跳转到主要内容

从现有内容模板添加内容

项目描述

collective.contemplate软件包允许站点管理员将内容项指定为创建该类型新项的模板。

从模板创建内容时,将在事务.savepoint()中更改模板所有者到当前用户后渲染初始编辑表单并进行模板验证。之后回滚渲染。因此,portal_factory未参与其中,索引仅发生在模板的最终副本上。这可能会带来性能提升,尽管这尚未经过测试。

虽然设计时无Archetypes依赖,但目前只提供了Archetypes实现。模板目前可以使用全局模板的Archetype UIDs或上下文特定模板的引用来指定。

在portal_types中的类型信息对象上还可以设置保留_id属性。如果设置,并且容器中已存在具有该ID的对象,则不允许添加该类型。

安装

要为Plone内容类型使用collective.contemplate,请将collective.contemplate configure.zcml配置文件包含到您的实例中,并在“附加产品”控制面板或通过portal_setup在ZMI中安装“内容模板”。这将用模板版本替换Plone内容类型信息。

要为其他内容类型安装,为该内容类型注册一个模板添加表单,并使用TemplateDynamicViewTypeInfo元类型来处理内容类型信息。

在browser views的ZCML中

<contemplate:formControllerPage
     name="addFoo"
     type_name="Foo"
     for="zope.app.container.interfaces.IAdding"
     permission="foo.AddFoo" />

注意,“foo.AddFoo”权限必须已注册,并且“addFoo”名称必须与您的内容类型构造函数相同。如果您使用Archetypes,则构造函数可能通过在内容类名称前添加“add”来自动生成。

在GenericSetup配置文件的types.xml文件中

<object name="Foo" meta_type="TemplateDynamicViewTypeInfo "/>

在GenericSetup配置文件的types/Foo.xml文件中

<?xml version="1.0"?>
<object name="Foo"
   meta_type="TemplateDynamicViewTypeInfo">

使用方法

该包目前不完整,直到包含指定模板的UI。在此期间,您可以在ZMI中设置全局模板,或使用collective.gsqi提供的references GenericSetup导入处理程序在上下文中使用特定模板。

您可以通过在ZMI的portal_types下的内容类型信息中设置global_uid属性,将给定内容项用作全局模板。将global_uid设置为模板的Archetypes UID。

您可以通过设置从文件夹到项目的引用来将内容项作为特定文件夹上下文中的模板,其中引用关系为“contemplate.${type_info/getId}”,其中“${type_info/getId}”是内容类型的id。

可以使用ZMI中portal_types下的内容类型信息的reserved_id属性设置保留ID。

上下文模板

打开浏览器并登录为有权限管理模板的用户。

>>> from Products.Five.testbrowser import Browser
>>> from Products.PloneTestCase import ptc
>>> owner_browser = Browser()
>>> owner_browser.handleErrors = False
>>> owner_browser.open(portal.absolute_url())
>>> owner_browser.getLink('Log in').click()
>>> owner_browser.getControl(
...     'Login Name').value = ptc.portal_owner
>>> owner_browser.getControl(
...     'Password').value = ptc.default_password
>>> owner_browser.getControl('Log in').click()

在我们添加模板之前,添加内容的流程与之前相同,字段为空。

>>> owner_browser.open(portal.Members.absolute_url())
>>> owner_browser.getLink(url='/+/addATDocument').click()
>>> owner_browser.url
'http://nohost/plone/Members/portal_factory/Document/document.../edit'
>>> owner_browser.getControl('Title').value
''
>>> owner_browser.getControl('Description').value
''

完成创建用作模板的页面。

>>> owner_browser.getControl('Title').value = 'Foo Template Title'
>>> owner_browser.getControl(
...     'Description').value = 'Foo Template Description'
>>> owner_browser.getControl('Save').click()
>>> print owner_browser.contents
<...
...Changes saved...
...Foo Template Title...
...Foo Template Description...

确保模板对将使用它的用户可见。

>>> self.loginAsPortalOwner()
>>> portal.portal_workflow.doActionFor(
...     portal.Members['foo-template-title'], 'publish')
>>> self.logout()

有权限管理模板的用户可以使用操作菜单中的“制作模板”将该页面指定为该文件夹及以下页面的Page内容类型的模板。

>>> portal.Members.addReference(
...     portal.Members['foo-template-title'],
...     relationship='contemplate.Document')
<Reference sid:... tid:... rel:contemplate.Document>

打开另一个浏览器并以普通用户登录。

>>> from Products.Five.testbrowser import Browser
>>> from Products.PloneTestCase import ptc
>>> contributor_browser = Browser()
>>> contributor_browser.handleErrors = False
>>> contributor_browser.open(portal.absolute_url())
>>> contributor_browser.getLink('Log in').click()
>>> contributor_browser.getControl(
...     'Login Name').value = ptc.default_user
>>> contributor_browser.getControl(
...     'Password').value = ptc.default_password
>>> contributor_browser.getControl('Log in').click()

一旦指定了模板,在该文件夹或以下添加与同一内容类型的项目将使用该模板。

>>> contributor_browser.open(folder.absolute_url())
>>> contributor_browser.getLink(url='/+/addATDocument').click()
>>> contributor_browser.getControl('Title').value
'Foo Template Title'
>>> contributor_browser.getControl('Description').value
'Foo Template Description'

编辑页面将根据模板渲染并验证,而不复制或实例化新内容。

>>> contributor_browser.getControl('Title').value = ''
>>> contributor_browser.getControl('Save').click()
>>> print contributor_browser.contents
<...
...Please correct the indicated errors...
...Title is required...
>>> contributor_browser.url
'http://nohost/plone/Members/test_user_1_/+/addATDocument'
>>> portal.Members.contentValues()
[<ATDocument at /plone/Members/foo-template-title>,
 <ATFolder at /plone/Members/test_user_1_>]
>>> folder.contentValues()
[]

成功保存表单将复制模板并使用提交的表单数据修改它。

>>> contributor_browser.getControl('Title').value = 'Foo Page Title'
>>> contributor_browser.getControl('Save').click()
>>> contributor_browser.url
'http://nohost/plone/Members/test_user_1_/foo-page-title'
>>> print contributor_browser.contents
<...
...Changes saved...
Foo Page Title...
Foo Template Description...
>>> portal.Members.contentValues()
[<ATDocument at /plone/Members/foo-template-title>,
 <ATFolder at /plone/Members/test_user_1_>]
>>> folder.contentValues()
[<ATDocument at /plone/Members/test_user_1_/foo-page-title>]

从模板添加的内容的行为与其他内容相同,可以被所有者编辑。

>>> contributor_browser.getLink('Edit')
<Link text='Edit' url='http://nohost/plone/Members/test_user_1_/foo-page-title/edit'>

没有权限管理模板的用户不能将内容指定为模板。

>>> contributor_browser.getLink('Make template')
Traceback (most recent call last):
LinkNotFoundError

模板的权限和字段值没有更改。

>>> owner_browser.open(
...     portal.Members['foo-template-title'].absolute_url())
>>> print owner_browser.contents
<...
...Foo Template Title...
...Foo Template Description...
>>> contributor_browser.open(
...     portal.Members['foo-template-title'].absolute_url())
>>> contributor_browser.getLink('Edit')
Traceback (most recent call last):
LinkNotFoundError

可以使用新模板上的“制作模板”操作替换给定内容类型的模板。

>>> portal.Members.deleteReference(
...     portal.Members['foo-template-title'],
...     relationship='contemplate.Document')
>>> portal.Members.addReference(
...     folder['foo-page-title'],
...     relationship='contemplate.Document')
<Reference sid:... tid:... rel:contemplate.Document>
>>> contributor_browser.open(folder.absolute_url())
>>> contributor_browser.getLink(url='/+/addATDocument').click()
>>> contributor_browser.getControl('Title').value
'Foo Page Title'

也可以使用模板添加表单上的“删除模板”操作删除模板。

>>> portal.Members.deleteReference(
...     folder['foo-page-title'],
...     relationship='contemplate.Document')
>>> contributor_browser.open(folder.absolute_url())
>>> contributor_browser.getLink(url='/+/addATDocument').click()
>>> contributor_browser.url
'http://nohost/plone/Members/test_user_1_/portal_factory/Document/document.../edit'
>>> contributor_browser.getControl('Title').value
''
>>> contributor_browser.getControl('Description').value
''

全局模板

可以将模板指定为给定门户类型的全局模板。为此,将portal_types工具中类型信息的“全局模板UID”属性设置为模板对象的UID。

创建一个作为模板的事件。

>>> self.loginAsPortalOwner()
>>> foo_event = portal[portal.invokeFactory(
...     type_name='Event', id='event-template-title',
...     title='Event Template Title',
...     description='Event template description')]

将类型信息属性设置为事件模板的UID。

>>> portal.portal_types.Event.manage_changeProperties(
...     global_uid=foo_event.UID())

现在,当通过浏览器添加事件时,它将根据模板创建。

>>> contributor_browser.open(folder.absolute_url())
>>> contributor_browser.getLink(url='/+/addATEvent').click()
>>> contributor_browser.getControl('Title').value
'Event Template Title'
>>> contributor_browser.getControl('Description').value
'Event template description'

保留ID

在portal_types中的类型信息对象上还可以设置保留_id属性。如果设置,并且容器中已存在具有该ID的对象,则不允许添加该类型。

>>> self.login()
>>> folder.allowedContentTypes()
[<TemplateDynamicViewTypeInfo at /plone/portal_types/Document>,
 <TemplateDynamicViewTypeInfo at /plone/portal_types/Event>,
 <TemplateDynamicViewTypeInfo at /plone/portal_types/Favorite>,
 <TemplateDynamicViewTypeInfo at /plone/portal_types/File>,
 <TemplateDynamicViewTypeInfo at /plone/portal_types/Folder>,
 <TemplateDynamicViewTypeInfo at /plone/portal_types/Image>,
 <TemplateDynamicViewTypeInfo at /plone/portal_types/Link>,
 <TemplateDynamicViewTypeInfo at /plone/portal_types/News Item>]
>>> portal.portal_types.Document.reserved_id = 'foo-page-title'
>>> folder.allowedContentTypes()
[<TemplateDynamicViewTypeInfo at /plone/portal_types/Event>,
 <TemplateDynamicViewTypeInfo at /plone/portal_types/Favorite>,
 <TemplateDynamicViewTypeInfo at /plone/portal_types/File>,
 <TemplateDynamicViewTypeInfo at /plone/portal_types/Folder>,
 <TemplateDynamicViewTypeInfo at /plone/portal_types/Image>,
 <TemplateDynamicViewTypeInfo at /plone/portal_types/Link>,
 <TemplateDynamicViewTypeInfo at /plone/portal_types/News Item>]

变更日志

0.1 - 未发布

  • 初始发布

待办事项

  • 添加到类型控制中的UI以选择全局模板

  • 添加到文件夹中的UI以指定上下文模板

    >>> owner_browser.getLink('Make template').click()
    >>> print owner_browser.contents
    <...
    ...Item designated as the template...
    
    >>> owner_browser.open(folder['foo-page-title'].absolute_url())
    >>> owner_browser.getLink('Make template').click()
    >>> print owner_browser.contents
    <...
    ...Item designated as the template...
    
    >>> owner_browser.open(folder.absolute_url())
    >>> owner_browser.getLink(url='/+/addATDocument').click()
    >>> owner_browser.getLink('Remove template').click()
    >>> print owner_browser.contents
    <...
    ...Item removed as the template...
    >>> contributor_browser.url
    'http://nohost/plone/Members/foo-template-title'
    
  • 进一步避免重复索引

    实现manage_pasteObjects和manage_renameObject,这样就不进行索引,并将索引留给编辑表单处理。

    这可能会导致程序化使用时出现问题。查看experimental.contentcreation。

项目详情


下载文件

下载适用于您平台的文件。如果您不确定选择哪一个,请了解有关安装包的更多信息。

源分发

collective.contemplate-0.1.tar.gz (19.3 kB 查看哈希值)

上传时间

支持