You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 13 Next »

模板脚本绘制输出。通常这种输出是HTML。脚本用如FreeMarker或JSP这样的模板语言编写。脚本指导绘制者将内容放到页面的什么位置,并为类似标题和图片的内容提供占位符。

脚本语言和绘制器

Magnolia CMS为FreeMarker和JSP提供可立即使用的绘制器。您可以选择偏好的语言,甚至可以在相同的网站上混合使用,在一些模板里使用FreeMarker而另一些里用JSP。 

FreeMarker

在Magnolia里,我们更倾向于使用FreeMarker,因其灵活性,较清晰的语法,更好的错误报告机制,也因为它不依赖于文件系统。模板不需要导出到文件系统,这意味着您可以将它们存储在内容库中,并像其他资源一样获得,随意添加版本控制,以及添加定制的属性和元数据。

样例:绘制页面标题,如果没有标题则绘制名字。

<h3>${content.title!content.@name}</h3>

这是FreeMarker提供的一些好处:

  • 它是一种通用的模板语言,不束缚于Java环境。
  • 提供基本的指令,如[if][else]和[list]
  • 有一大套built-ins
  • 可以调用任何Java对象和返回对象的公共方法。
  • 不需要在请求/回复环境中绘制。
  • 提供直接获取节点对象(beans)的方法。
  • 可直接迭代任何扩展一个Java列表的内容集合。
  • 严格的null值处理导致稳定的模板。
  • 需要的话允许使用JSP标签库。

JSP

JSP代表JavaServer Pages,是Java Servlet技术的一个延伸,用于综合Java服务器端的程序和HTML。

样例:绘制页面标题,如果没有标题则绘制名字。

<h3>
<c:choose>
    <c:when test="${not empty content.title}">${content.title}</c:when>
    <c:otherwise>${content['@name']}</c:otherwise>
</c:choose>
</h3>

其他语言

您也可以使用另一模板语言。例如,有一些网站使用Apache Velocity。如果有您使用的语言可用的绘制器,很有可能可以将它合入Magnolia CMS。这就能够让您使用您熟悉的模板语言了。

绘制器配置

FreemarkerRendererJspRendererConfiguration应用的/modules/rendering/renderers/freemarker/jsp里配置。

节点名

modules

 

rendering

 

renderers

 

freemarker

 

contextAttributes

 

class

info.magnolia.rendering.renderer.FreemarkerRenderer

type

freemarker

jsp

 

contextAttributes

 

class

 info.magnolia.rendering.renderer.JspRenderer

type

 jsp

STK定义它自己的绘制器STKRenderer,在Configuration应用的/modules/standard-templating kit/rendering/renderers/stk里配置。

节点名

modules

 

standard-templating-kit

 

renderers

 

stk

 

contextAttributes

 

class

info.magnolia.module.templatingkit.renderers.STKRenderer

页面区域组件定义里的renderType属性定义使用的模板绘制器。对STK模板来说,类型是stk

加载脚本

系统可以从三个地方加载FreeMarker脚本,以下列顺序:

  1. 网络应用程序的文件系统。您可以将脚本文件放在/<CATALINA_HOME>/webapps/<contextPath>/templates文件夹。
  2. templates 工作区。模板需被使能才能被考虑进去。
  3. 网络应用程序的类路径(classpath)。这是STK模板默认存放的地方。最佳实践是在模块JAR里打包脚本。模块JAR在类路径里好让系统找得到它。

模板加载器

FreeMarker模板加载器在Configuration应用的/server/rendering/freemarker/jcr/webapp里配置:

需要的话您也可以写下您自己定制的模板加载器。

节点名

server

 

filters

 

IPConfig

 

i18n

 

security

 

rendering

 

freemarker

 

templateLoaders

 

jcr

 

class

info.magnolia.module.inplacetemplating.JcrRepoTemplateLoader

extension

.ftl

workspace

templates

webapp

 

class

 info.magnolia.freemarker.loaders.LazyWebappTemplateLoader

JSP脚本只能存在于文件系统中,因为它们在被绘制前需要服务器预编译。JSP脚本在模块安装或更新时被解压到文件系统。

编辑脚本

最佳实践
最佳实践是将脚本存储在您的项目模块里,这样脚本可以被存储在一个版本控制系统,并且自动成为一个可控的软件开发周期的一部分。您可以在文件系统里用您喜爱的支持语法高亮及其他特性的编辑器来编辑。

开发时,在内容库里编辑脚本有时候很有用。这种方法只对FreeMarker脚本有效。如果您将脚本导入templates工作区,它们就会在STK > Templates里可见可用。所有的STK脚本都遵循这个模式。您可以从以上的加载顺序看出,在templates工作区里的脚本会覆写从类路径里加载的脚本。一旦被添加或修改,则需要选中Enable template复选框来强迫Magnolia CMS从内容库中加载模板。

 

在内容库里编辑模板脚本对评估,制造原型,或较小的项目比较理想。然后,长期来说这不利于维护。不要在生产环境中这样做。我们强烈建议您在一个版本控制系统中存储脚本,并将它们打包进一个项目模块。

 

参考模板样例 > 编辑模板脚本里更多信息。

STK脚本

STK模板脚本在网络应用程序的类路径中。其副本在STK > Templates里就可以编辑。STK脚本是用FreeMarker写的。

脚本存储在/templating-kit文件夹的子文件夹里:

  • components包含按照组件类型分类的组件模板。
  • pages包含main页面脚本,区域脚本在子文件夹里。

此结构遵循模板原型结构。在模板原型里引用的区域模板都被存在/global文件夹里。

main脚本

main是主页面脚本(Git)。它是理解这个系统的一个好起点。它在编写实例上使用@cms.init指令初始化页面编辑器,也包含了设置bodyClassbodyID的逻辑。

main脚本使用@cms.area指令来调用区域绘制它们自身。它使用#include指令绘制导航main脚本用三个DIV元件包装区域,建立了一个可调的页面网格

区域脚本

参考STK区域里关于STK区域脚本的描述。

指令

关键的模板特性以指令(directives形式在Magnolia CMS标签库里可用。指令输入很快,但会绘制复杂的输出。

标准FreeMarker指令

这里有一些最有用的FreeMarker指令及其样例代码:

if, else和elseif

支持常用运算符(&&, ||, !, ==, !=, >, <, >=, <=)。

布尔测试:

[#if content.header?has_content]
   <h1>${content.header}</h1>
[#else]
   DO_SOMETHING_ELSE
[/#if]
值比较:
[#if content.imageLocation == "top"]
   …
[/#if]
替换值:
[#if content.date?has_content]
   ${content.date?time?string.short}
[#elseif content.endDate?has_content]
   ${content.endDate?time?string.short}
[#else]
   No date is set!
[/#if]

list

可在任何Java集的扩展集合里进行迭代。

[#list model.getSomeList() as elem]
   <li>${elem.title!}</li>
[/#list] 

assign

assign允许您定义变量。任何非空对象都能被传递给变量。

[#assign title = content.title!content.@name]
[#assign hasDate = content.date?has_content]
[#assign dateShort = content.date?time?string.short]
[#assign events = model.events]
[#assign stringgy = "Some direct string data"]

include

include指令包含一个FreeMarker模板脚本。

[#include "/templating-kit/templates/content/myScript.ftl"]

宏指令使您复用FreeMarker代码片段。参考Templating Kit > Templates /templating-kit/components/macros里STK使用的例子。

[#macro test foo bar="Bar" baaz=-1]
    Test text, and the params: ${foo}, ${bar}, ${baaz}
[/#macro]
[@test foo="a" bar="b" baaz=5*5-2/]
[@test foo="a" bar="b"/]
[@test foo="a" baaz=5*5-2/]
[@test foo="a"/]

定制Magnolia指令

Magnolia CMS提供一下定制指令:

对FreeMarker来说,这些指令都是由Directives类来完成的。此类可在Configuration应用的modules/rendering/renderers/freemarker/contextAttributes/cms/componentClass里配置。

对JSP,指令是由Templating JSP模块提供。

指令的语法随模板语言而略有不同。FreeMarker指令中,标准指令以“#”字符开头,而定制指令则以“@”符号开头。所有Magnolia cms标签库中的指令都以“@”开头,紧接着是标签库的名字,如cms,其次是一个点符号,宏的名字,以及任何参数。在JSP里限制的字符则不同。

语法:

[@<tag library>.<macro> <parameter>=<value> /]

FreeMarker示例:绘制一个组件

[@cms.component content=component /]

JSP示例:绘制一个组件

<cms:component content="${component}"/>

cms:init

InitElement Java类嵌入了在编写实例上编辑页面所需的JavaScript和CSS。输出在HTML页面的head元件里。

示例:

[@cms.init /]

cms:area

cms:area指令AreaDirective)绘制一个area以及里面的任何组件。编辑者可在区域内添加组件。可用的组件在区域定义里配置。

示例:

[@cms.area name="main"/]

该指令通过区域名字引用区域。区域名为包含区域定义的内容节点,如mainfooterstage

页面上的结果是一个区域栏,一个开始标记和一个结束标记。区域定义里title属性值在此区域栏里绘制。当编辑者点击New Component框的添加图标时,组件就添加到区域里了。

如果区域定义包含一个templateScript属性,那么由被引用的脚本绘制区域。如果没给定脚本,以下缺省脚本则会被使用:

区域类型为single

[@cms.component content=component /]

区域类型为list

[#list components as component]
   [@cms.component content=component /]
[/#list]

cms:component

cms:component指令(ComponentDirective)绘制组件content属性(attribute)定义组件编辑的内容。该标签符通常被用在list指令里来依次通过地图里的组件。

要绘制的内容,或对于可编辑组件可能的编辑,都是通过content属性(attribute)来传递。在编写实例上,指令绘制一个组件工具栏。组件定义里的title属性值在工具栏中绘制。

属性(Attribute)描述缺省值
editable定义编辑图标是否应被显示,主要对继承的内容有用。cmsfn.isFromCurrentPage()
template要用到的组件定义名。节点里定义的模板。

示例:

[#list components as component ]
   [@cms.component content=component /]
[/#list]

常用指令属性

下列属性可用任何指令传递,它们定义指令创建的元件应该工作在什么内容上。The following attributes can be passed with any directive. They define which content the element created by the directive should work on.

属性(Attribute)描述缺省值
content一个节点或是内容地图。 
workspace指定路径时用到的工作区。与当前内容相同
path工作区中的路径。 

content属性

content属性(attribute)告诉脚本它应该在哪个内容节点上操作。脚本通常在“当前”内容节点上执行。对于一个页面级脚本,当前节点为该页面,而对于一个区域级脚本,当前节点就是该区域,同样,对于一个组件级脚本,当前节点就是该组件。然后,也有一些您想要脚本在一个不同的内容节点上执行的情况,这就是content属性变得方便实用的时候。

例如,intro区域没有它自己的内容,它也不包含任何组件,因为它是noComponent类型的。这个区域在页面内容上操作,编辑和绘制页面标题及摘要。我们通过使用内容属性来实现这些。

main.ftl脚本里,我们告诉main区域:“你应该在当前内容节点上执行,它是一个页面,因为我是一个页面级脚本。”

<div id="wrapper-3">
    [@cms.area name="platform"/]
    [@cms.area name="main" content=content/]
    [@cms.area name="extras"/]
</div>

mainArea 区域脚本里,我们再次传递相同的信息给intro区域:“你应该在当前内容节点上执行,它(仍然)是一个页面。”

<div id="main" role="main">
    [@cms.area name="breadcrumb" content=content/]
    [@cms.area name="intro" content=content/]
    [@cms.area name="opener"/]
    [@cms.area name="content"/]
</div><!-- end main -->

现在由intro区域编辑页面内容。尽管intro区域在页面上位于main区域的DIV元件里,标题和摘要实际上属于页面,它们是页面的属性,而不是区域的。所以将这些属性存放在内容结构里的页面节点下是有道理的。

workspace属性

workspace属性告知指令内容在magnolia JCR库的哪个工作区。这几乎一直是website工作区,如果当前内容在website工作区里,则自动默认指向website。

指令绘制示例

这是一个关于指令在页面上如何绘制的例子。

  1. main脚本包含一个cms.init指令,嵌入了编写实例上所需的CSS和JavaScript。
  2. cms.area指令调用即将绘制的区域。该指令通过名字来辨别区域,在此例中为extras。如果该区域有子区域,您需要一个分开的脚本来调用要绘制的子区域。然后,如果该区域只包含组件,那么您不需要区域脚本。
  3. 页面的脚注同样使用cms.area指令来绘制。该区域不含子区域,只有组件。

添加您自己的指令

您可以添加自己的指令。以下步骤使您类中的Java方法和功能对模板脚本可用:

  1. 像通常一样写作和编译您的Java类。
  2. 拷贝这个类文件到您的Magnolia网络应用的WEB-INF/classes文件夹。
  3. 转到Configuration应用/modules/rendering/renderers/freemarker/contextAttributes
  4. /contextAttributes下,创建一个内容节点,如myClass。用您类的用途命名它。
  5. myClass里,创建两个数据节点:
    • componentClass,设置其值为您放在WEB-INF/classes里的类的完全相称类名。
    • name,设置其值为myClass

这就让您能够使用${myClass.myMethod()} FreeMarker句法,从模板获得myClass里所有的静态方法。

模板功能

TemplatingFunctions includes useful methods that you can use in your templates. The methods are exposed as cmsfn. The decode method that removes escaping of HTML on properties is is an example and the snippet below shows its use in the stkTextImage component script.

[#if content.text?has_content]
   ${cmsfn.decode(content).text}
[/#if]

DamTemplatingFunctions provides direct access to Assets and defines useful methods. The methods are exposed as damfn. See DAM templating for more information. For example:

[#assign asset = damfn.getAssetForId(content.link)][#assign assetMap = damfn.getAssetMapForAssetId(content.link)]

STKTemplatingFunctions makes additional methods available for use in STK templates. The methods are exposed as stkfn. The snippet below from the promos component script contains the abbreviateString example.

[#assign text = stkfn.abbreviateString(text, 80)]

The templating functions classes are configured for each renderer in the Configuration app > /<module>/rendering/renderers/<renderer>/contextAttributes/<tag library>. Note that the <tag library> content node and the value of the name data node matches the syntax used to expose the methods in scripts.

 

 

Node nameValue

modules

 

rendering

 

renderers

 

freemarker

 

contextAttributes

 

cms

 

cmsfn

 

componentClass

info.magnolia.templating.functions.TemplatingFunctions

name

cmsfn

class

info.magnolia.rendering.renderer.FreemarkerRenderer

type

freemarker

jsp

 

listeners

 

version

5.0.2

standard-templating-kit

 

renderers

 

stk

 

contextAttributes

 

cms

 

cmsfn

 

stkfn

 

componentClass

info.magnolia.module.templatingkit.functions.STKTemplatingFunctions

name

stkfn

damfn

 

class

info.magnolia.module.templatingkit.renderers.STKRenderer

 

 

Freemarker built-ins

FreeMarker provides a powerful set of built-ins. These are used for basic manipulation of data and no Java code is necessary. Built-ins are used with a preceding ? character. For example ?exists checks if a value/object exists and ?has_content checks if a value/object is empty and exists.

Strings

Most Java String are implemented and can be used directly in Freemarker. Examples: substringuncap_firstcapitalizedate, time, datetimeends_withhtmlindex_oflast_index_oflengthlower_caseupper_casecontainsreplacestarts_withtrim.

Booleans

String (when used with a boolean value) converts a boolean to a string. You can use it in two ways:

  • foo?string converts the boolean to string using the default strings to represent true and false values.
  • foo?string("yes", "no") returns the first parameter "yes" if the boolean is true, otherwise the second parameter "no".

Dates

There are various built-ins for dates with formating capabilities. For example:

[#assign microFormatDate = content.date?string("yyyy-MM-dd") + "T" + ontent.date?string("hh:mm:ss")]

Expert

There are various expert built-ins. The most commonly used are:

has_content determines if HTML is rendered to avoid empty HTML tags.

[#if content.author?has_content]
 <p>
  <cite>${content.author}</cite>
 </p>
[/#if]

eval evaluates the passed Freemarker code.

[#assign indexString = ('"'+(ctx.indexString!)+'"')?eval]

Java objects

These rendering context objects are set in AbstractRenderer and its child classes,

content: the current content node.

${content.header!}

model: The example code below corresponds to getNavigation() method of the model class.

${model.navigation!}

def: The current page, area or component definition object.

${def.headingLevel!}

ctx: See WebContext.

${ctx.user.name!}

state: See AggregationState.

${state.locale!}

Checking for null

Null checks stabilize your templates. Freemarker throws an exception if null is encountered. There are two options:

Use the ! character to provide default values. The content after ! is executed.

This code tries to assign title from content, if not it falls back to the content node's name.

<meta name="keywords" content="${content.keywords!content.title!content.@name}" />

You can also specify the value.

[#if content.keywordsEnabled!false]
     <meta name="keywords" content="${content.keywords!"These are some keywords"}" />
[/#if]

Or use the ?has_content built-in. The example renders the header in h1 tags if a value exists.

[#if content.header?has_content]
     <h1>${content.header}</h1>
[/#if]

Templating examples

Here are the most common Freemarker examples for use in your template scripts:

[#-- Accessing content --]
The value of "someProperty": ${content.someProperty}
Accessing a child node: ${content.childNode}
Accessing the child node collection: ${content?children}
Accessing the parent node: ${content?parent}
[#-- Special content properties --]
The content object is an instance of ContentMap and the following attributes are available:
The current node name: ${content.@name}
The current node path: ${content.@path}
The current node id: ${content.@id}
The current node depth: ${content.@depth}
The current node node type: ${content.@nodeType}

[#-- MetaData --]
The creation date: ${content.metaData.creationDate}
Metadata.modificationDate: ${content.metaData.modificationDate!" 
This node has never been modified."}

[#-- Component definition --]
The current component definition: ${def.name}
A component definition property: ${def.style}

[#-- Context: ctx --]
A request parmeter: ${ctx.myParam}
The current user name ${ctx.user.name} 
The current locale ${ctx.locale}

[#-- TemplatingFunctions: cmsfn--]
Create a link to a page: ${cmsfn.link(content)}
Create a binary link: ${cmsfn.link(content.image)}

[#-- Status based rendering --]
This is ${cmsfn.authorInstance?string('indeed', 'not')} an author instance.
This is ${cmsfn.editMode?string('indeed', 'not')} the edit mode.
This is ${cmsfn.previewMode?string('indeed', 'not')} the preview mode.

[#-- The Model executed before the paragraph rendering: model --]
The parent model: {model.parent}
The result of the execute method: ${actionResult}

[#-- AggregationState: state --]
Entry point of the rendering: ${state.mainContent}
Current content node: ${state.currentContent}

References

Useful links to get started with Freemarker:

  • No labels