二十四画生的Blog


        ——开始学习Orchard框架
posts - 125, comments - 1456, trackbacks - 46, articles - 8
  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理

公告

理解Orchard中的placement.info文件

Posted on 2011-08-02 11:51 二十四画生 阅读(...) 评论(...) 编辑 收藏
(本文内容适用于Orchard v1.1版本)

 

    在Orchard等CMS系统中,内容可由任意多个部分组成。例如,一个博客文章是由:路由和标题(Routable part),文本内容(Body part),标签(Tags part),评论(Comment part)和其他一些通用的部件(Common and PublishLater)组成。为了获得一个模板来呈现这样的对象,你可以明确的访问每一部分的内容并呈现它们。这是一种实现方式,但是这却不能很好的处理一些CMS中经常出现的一些不可预知的修改。如果管理员下载了一个评分模块,并将这个评分部件(rating part)加入到了博客文章中。如果显示界面是明确定义整个博客文章项的,你就需要对模板做出修改,明确呈现新增加的部件。
 

所谓明确的呈现一个内容,是指在代码中直接用类似以下的代码来实现。

例如显示一个博客就可以用:
@Display(Model.RoutableTitle)
@Display(Model.Body)
@Display(Model.Tags)
@Display(Model.Comments)
如果要加一个评分部件,就需要修改这个模板,改为:
@Display(Model.RoutableTitle)
@Display(Model.Body)
@Display(Model.Tags)
@Display(Model.Rating)
@Display(Model.Comments)
这样每增加一个功能都需要修改相应的模板,如果这样做就很不方便了。
 

    在Orchard中,我们并不需要这样去修改。添加一个新的部件,我们完全不用修改任何代码就可以正确显示。这种功能能够得以实现是由于在Orchard实现了“呈现”(由模板或形状的方法去执行)和“放置”(通过placement.info文件来实现)的分离。这样,部件不仅可以指定其默认的呈现方式,还可以在主题中进行重写。并且部件的显示位置和区域也可以通过在主题中添加新的placement.info文件来进行重写。

 

    要理解“呈现”和“放置”分离,首先我们要再讲一下Orchard中内容的组织方式。在Orchard中所有的数据都是内容(Content),这些内容都是不同类型的数据(Content Type),不同类型的数据都是由不同的内容部件(Content Part)构成。一个类型由那些部件组成,可以在后台进行定制。所谓的“呈现”和“放置”分离是指:每一个部件都有自己的呈现方式和对应的呈现模板。每一个部件都只考虑自己的呈现,不用管其他的部件。当呈现一个内容的时候通过各部件“放置”文件中的定义,按顺序在不同的区域显示相应的部件然后合并为一个完整内容显示。

 

    在进一步介绍placement.info文件之前,还需要先介绍另外一个东西——Content.cshtml(内容项模板)。首先在Orchard中的内容项都需要通过此模板来显示,无论什么样的内容都会调用此模板。当然此模板同样可以在主题中进行重写,这里就拿默认的内容项模板为例:(文件位置:~\Core\Contents\Views\Content.cshtml)

<article class="content-item @contentTypeClassName">
    <header>
        @Display(Model.Header)
        @if (Model.Meta != null)
        {
        <div class="metadata">
            @Display(Model.Meta)
        </div>
        }
    </header>
    @Display(Model.Content)
    @if (Model.Footer != null)
    {
    <footer>
        @Display(Model.Footer)
    </footer>
    }
</article>
此模板定义了四个区域:Header、Meta、Content、Footer。那么一个内容中的各个部件如何在这个模板中呈现,如:那些部件需要呈现在Header里面,那些部件需要呈现在Content里面,呈现在Content里面的位置顺序又是怎样的。这些都需要一个放置文件来处理,这个文件就是placement.info。

placement.info文件

通过上面描述,我们已经可以知道placement.info文件的作用以及此文件存在的必要性了。如果你看一下Orchard中的文件,你会发现大多数的模块和主题都有一个placement.info文件在它们的根目录下。这是一个xml文件,用于定义相应的布局在内容项中的呈现位置。下面的文件显示了一个放置文件的例子。(具体来说,它来自于Orchard.Tags的placement.info文件)
<Placement>
    <Place Parts_Tags_Edit="Content:7"/>
    <Match DisplayType="Detail">
        <Place Parts_Tags_ShowTags="Header:after.7"/>
    </Match>
    <Match DisplayType="Summary">
        <Place Parts_Tags_ShowTags="Header:after.7"/>
    </Match>
</Placement>
这个文件说明了什么?首先,这个Tags部件有两种形状Parts_Tags_Edit和Parts_Tags_ShowTags。Parts_Tags_Edit是编辑画面用到的形状,Parts_Tags_ShowTags是显示画面用到的形状。在显示画面中用到Parts_Tags_ShowTags时,又有两种显示方式:详细显示呈现方式和摘要显示呈现方式。其次,通过这个文件我们可以知道在编辑画面显示的时候,标签部件需要呈现在内容项的Content区域里面,位置序号为7。在显示画面显示的时候标签部件需要呈现在内容项的Header区域里面且位置靠后,在同为靠后显示时的序号为7。标签模块就通过这个文件,缺省定义了标签部件的显示位置。以后只要有内容用到标签部件,就会根据这个放置文件的定义自动安排标签部件的显示位置,而不用我们在代码中去指定了。

如果大家还没弄明白,那么再举例说明一下,例如:现在显示一篇博客文章,包含四个部件:标题、标签、内容、评论。这四个部件的placement.info文件定义如下: 

<Place Parts_RoutableTitle="Header:5"/>
<Place Parts_Tags_ShowTags="Header:after.7"/>
<Place Parts_Common_Body="Content:1"/>
<Place Parts_Comments="Content:10" />
那么呈现出来的Html就会是:
<article>
    <header>
        <首先显示标题内容,因为标题是显示在Header区域的,位置序号为5,但没有比它靠前的了>
        <然后显示标签,应为标签也是显示在Header区域的,不过显示位置定义为靠后>
    </header>
        <这里显示文章内容,因为文章内容是显示在Content区域的,位置序号为1>
        <这里显示文章评论,因为文章评论是显示在Content区域的,位置序号为10,所以显示在文章内容后面>
    <footer>
    </footer>
</article>
 

通过以上的例子和描述,我相信大家对placement.info文件已经有了一些了解,下面就进一步的讲述如何来写一个placement.info文件。

 

范围(Scope)

放置文件的作用范围为内容项。这意味着,你可以用它来重新排列显示任意一个内容项(博客文章、页面,评论,自定义项,部件等),但不一定是任意形状(Shape)。如果一个形状不是由内容部件所处理的,就不需要你提供放置文件了。例如:默认主题中定义的Branding,这个就是一个形状,但是不需要内容部件去处理,当然也用不到放置文件了。

 

Placement节点

Placement节点必须为placement.info文件的根节点。这就相当于一个简单容器,表明该节点下的内容就是放置文件要定义的东西了。
 

Place 节点

Place 节点是placement.info文件中主要的节点。它可以有任意数量的属性,但基于可读性的要求,建议每一个Place节点只定义一个形状的位置情况。多个形状的位置情况可以用多个Place节点来定义。一行一个,这样即清楚又明白。每一个Place节点的属性,都是对应一个形状名称(如:Parts_Tags_ShowTags),此属性的值就是这个形状的位置定义。至于一个模块都有哪些形状需要定义显示位置,我可以查看相应模块的驱动器代码。在返回ContentShape时,需要指定一个shapeType,这个shapeType就是形状的名称。更简单的方式是使用Orchard提供的一个设计工具模块,来查看各种内容对应的形状名称。关于这个工具的介绍可以查看《Customizing Orchard using Designer Helper Tools》。
 

Place节点的属性名称可以是任意一个形状的名称(但不是它的替换名称,如:一个部件可以有详情显示模式,摘要显示模式等,要分别定义同一个形状在不同显示模式下的显示位置需要用Match节点,这个下文会讲到)。但是在显示某些字段的时候也有一些特殊情况,放置文件也可针对这些特殊情况进行扩展。例如:下面的放置文件将会禁止名为“Occupation”的字段显示。(注意此例的属性值是短横表示隐藏的意思,但是并不代表这种特殊扩展的写法就只适用于隐藏,属性值也可以是定位的功能,如="Header:1")

<Place Fields_Common_Text-Occupation="-"/>
  
字段开发人员请注意实现上述功能需要在字段的驱动器中返回ContentShape时,传递一个可以区分不同字段的标记(differentiator)。这样就可以实现在形状名称后面加短横线和字段名称来定位某一一特定的字段了。具体做法可查看TextField字段驱动器中返回ContentShape时的写法。

  

Place节点的属性值是由区域名称+冒号+定位标记组成。区域名称通常为:Header、 Meta、 Content或Footer,这些区域是在内容项模板(Content.cshtml)中定义的。如果你重写了内容项模板,那么这些区域的名称就是你重新模板的中定义的哪些区域名称。定位标记可以是一个单独的数字(1、2、3、10、20等)也可以是多层级的用点分割的数字组合(1.2、1.52.3等)。在排列同一区域的多个部件位置时,将按照这些序号的大小顺序,由小到大顺序排列。对于多层级的数字组合定位,先按第一个数字进行排列,然后按第二个数字排列,以此类推。例如:1在2.4.5前面,2.4.5在2.10前面。

 

在定位标记中,你还可以使用一些限定符来进行标记,如:before和after。使用限定符来定义的部分要前于或后于用数字来定位部分。例如:Content: before就要排在Content:1前面,Header:after就要排在Header:10后面。这种定位标记的限定符,同样可以用于用点分隔的层级组合中。判定规则还是按每一层级逐一比较,用限定符的要前于或后于用数字的。

 

在多层级比较时,如果有一些的定位层级有3层,有一些只有2层。那么按已有层对比排序后,少一层那个部分默认排在最前面。例如:1.2就要排在1.2.1前面,也要排在1.2.before前面。

 

在Orchard v1.1版本中还新增了几个新的功能:指定形状的替换名称、指定形状的包装和重命名形状名称的功能。如果你希望在主题中为博客文章的标签部件写一个单独的模板,你可以用指定形状的替换名称功能,在博客文章的类型下将标签显示的形状名称替换为一个特殊名称,这样就可以方便的为这一特例来指定模板了。如在placement.info文件中添加以下代码:
<Match ContentType="BlogPost">
  <Place Parts_Tags_ShowTags="Header:after;Alternate=Parts_Tags_ShowTags_BlogPost"/>
</Match>
然后就可以在主题Views目录中新增一个Parts/Tags.ShowTags.BlogPost.cshtml文件来自定义博客文章中的标签显示。
 

同样,你也可以为某一形状提供一个包装(Header:after;Wrapper=Wrapper_GreenDiv)或者从命名一个形状的名称(Header:after;Shape=IPreferToCallThoseStickersForSomeReason)。

 

指定包装和指定替换名称的功能好像差不多,也是可以单独在主题目录中为某一种形状的特殊情况指定一个新的模板。而且我感觉这两个新增功能都无大用,因为模板的替换规则已经针对各种特殊情况都可以创建不同名称的特定模板来重写原有模板的功能。比如上面所说的关于博客文章中标签的显示。其实我也可以在主题Views目录中新增一个Tags.ShowTags-BlogPost.cshtml模板来达到同样的效果。可能指定包装和指定替换名称有更灵活的应用情况,如果以后有遇到我再来补充。至于重命名形状名称,则可以将部件中显示的某一特定形状用一个其他的形状来替换。具体能做什么用现在还想不出来,也等到以后再补充吧。

 

Match节点

Match节点可以定义Place节点定义的应用范围。Match节点有以下属性可以使用:
DisplayType:显示类型。表明该Match节点下的Place节点的位置定义适用于某种显示模式的情况。显示模式包括:Detail、Summary等。
ContentType:内容类型。表明该Match节点下的Place节点的位置定义适用于某种指定的类型。如:可指定博客文章中各部件的位置情况。
Path:路径。表明该Match节点下的Place节点的位置定义适用于某种指定的路径。如:Path="/About",表示在About页面中相应部件的位置定义可以使用这个Match节点下Place节点中的定义。也可以使用一些通配符来指定,如:Path="/MyBlog/*"表示在此路径下的所有页面上的相应部件都可以使用这个Match节点下Place节点中的定义。例如:/Myblog 和 /MyBlog/FirstPost都适用。这个属性是Orchard1.1特有的属性。
 

重写位置文件

所有模块(有显示要求的)都需要定义一个缺省的放置文件。这个放置文件需要包含这个模块中所有的可显示部件的位置定义,这个文件需要命名为placement.info且要放在相应模块的根目录下。缺省的放置文件,可以在任意一个主题中进行重写。通过重写相应的显示部分的位置定义,每一个主题都可以有一套属于自己的模块放置定义。

参考文档