{ "info": { "author": "Ross Patterson", "author_email": "me@rpatterson.net", "bugtrack_url": null, "classifiers": [ "Programming Language :: Python", "Topic :: Software Development :: Libraries :: Python Modules" ], "description": ".. -*-doctest-*-\n\n=================\nContent Templates\n=================\n\nThe `collective.contemplate\n`_ package allows\nsite administrators to designate content items as the template from\nwhich new items of that type will be created.\n\nWhen creating content from a template, the initial edit form is\nrendered and validation performed on the template after changing the\nowner of the template to the current user within a\ntransaction.savepoint() which is rolled back after rendering. As a\nresult, portal_factory is not involved and indexing occurs only on the\nfinal copy of the template. This may result in performance gains\nthough this has not been tested.\n\nWhile designed to be Archetypes agnostic, only an Archetypes\nimplementation is currently provided. Templates may currently be\ndesignated using Archetype UIDs for the global templates or references\nfor the context specific templates.\n\nA reserved_id property can also be set on type information objects in\nportal_types. If set and an object with that ID already exists in the\ncontainer, then the type is not allowed to be added.\n\n.. contents:: Table of Contents\n\nInstallation\n============\n\nTo use collective.contemplate for the Plone content types, include the\ncollective.contemplate configure.zcml in your instance and install\n\"Content Templates\" in the \"Add-on Products\" control panel, or in the\nZMI through portal_setup. This will replace the Plone content type\ninformation with template versions.\n\nTo install for other content types, register a template add form for\nthe content type and use the TemplateDynamicViewTypeInfo meta_type for\nthe content type information.\n\nIn the ZCML for the browser views::\n\n \n\nNote that the \"foo.AddFoo\" permission must be registered and the name\n\"addFoo\" must be the same as your content type constructor. If you're\nusing Archetypes, then the constructor may auto-generated by prefixing\n\"add\" to the content class name.\n\nIn the GenericSetup profile types.xml file::\n\n \n\nIn the GenericSetup profile types/Foo.xml file::\n\n \n \n\nUsage\n=====\n\nThis package is currently incomplete until a UI for designating\ntemplates is included. In the mean time, you may set the global\ntemplates in the ZMI or context specific templates using the\nreferences GenericSetup import handler provided by collective.gsqi.\n\nYou can use a given content item as the global template by setting the\nglobal_uid property of the content type information under portal_types\nin the ZMI. Set global_uid to the Archetypes UID of the template.\n\nYou can use a content item as the template in the context of a\nspecific folder by setting a reference from the folder to the item\nwith the relationship of \"contemplate.${type_info/getId}\" where\n\"${type_info/getId}\" is the id of the content type. \n\nA reserved id can be set using the reserved_id property of the content\ntype information under portal_types in the ZMI.\n\nContext Templates\n=================\n\nOpen a browser and log in as a user who is allowed to administer\ntemplates.\n\n >>> from Products.Five.testbrowser import Browser\n >>> from Products.PloneTestCase import ptc\n >>> owner_browser = Browser()\n >>> owner_browser.handleErrors = False\n >>> owner_browser.open(portal.absolute_url())\n >>> owner_browser.getLink('Log in').click()\n >>> owner_browser.getControl(\n ... 'Login Name').value = ptc.portal_owner\n >>> owner_browser.getControl(\n ... 'Password').value = ptc.default_password\n >>> owner_browser.getControl('Log in').click()\n\nBefore we've added a template, adding content proceeds as before with\nfields empty.\n\n >>> owner_browser.open(portal.Members.absolute_url())\n >>> owner_browser.getLink(url='/+/addATDocument').click()\n >>> owner_browser.url\n 'http://nohost/plone/Members/portal_factory/Document/document.../edit'\n >>> owner_browser.getControl('Title').value\n ''\n >>> owner_browser.getControl('Description').value\n ''\n\nFinish creating the page to use as a template.\n\n >>> owner_browser.getControl('Title').value = 'Foo Template Title'\n >>> owner_browser.getControl(\n ... 'Description').value = 'Foo Template Description'\n >>> owner_browser.getControl('Save').click()\n >>> print owner_browser.contents\n <...\n ...Changes saved...\n ...Foo Template Title...\n ...Foo Template Description...\n\nMake sure the template is visible to users that will use it as a\ntemplate.\n\n >>> self.loginAsPortalOwner()\n >>> portal.portal_workflow.doActionFor(\n ... portal.Members['foo-template-title'], 'publish')\n >>> self.logout()\n\nA user with rights to administer templates may designate the page as a\ntemplate for the Page content type in that folder and below using\n\"Make template\" in the actions menu.\n\n >>> portal.Members.addReference(\n ... portal.Members['foo-template-title'],\n ... relationship='contemplate.Document')\n \n\nOpen another browser and log in as a normal user.\n\n >>> from Products.Five.testbrowser import Browser\n >>> from Products.PloneTestCase import ptc\n >>> contributor_browser = Browser()\n >>> contributor_browser.handleErrors = False\n >>> contributor_browser.open(portal.absolute_url())\n >>> contributor_browser.getLink('Log in').click()\n >>> contributor_browser.getControl(\n ... 'Login Name').value = ptc.default_user\n >>> contributor_browser.getControl(\n ... 'Password').value = ptc.default_password\n >>> contributor_browser.getControl('Log in').click()\n\nOnce a template has been designated, adding an item of the same\ncontent type in that folder or below will use the template.\n\n >>> contributor_browser.open(folder.absolute_url())\n >>> contributor_browser.getLink(url='/+/addATDocument').click()\n >>> contributor_browser.getControl('Title').value\n 'Foo Template Title'\n >>> contributor_browser.getControl('Description').value\n 'Foo Template Description'\n\nThe edit page will be rendered and validated against the template\nwithout copying or otherwise instantiating new content.\n\n >>> contributor_browser.getControl('Title').value = ''\n >>> contributor_browser.getControl('Save').click()\n >>> print contributor_browser.contents\n <...\n ...Please correct the indicated errors...\n ...Title is required...\n >>> contributor_browser.url\n 'http://nohost/plone/Members/test_user_1_/+/addATDocument'\n >>> portal.Members.contentValues()\n [,\n ]\n >>> folder.contentValues()\n []\n\nSuccessfully saving the form will copy the template and modify it with\nthe submitted form data.\n\n >>> contributor_browser.getControl('Title').value = 'Foo Page Title'\n >>> contributor_browser.getControl('Save').click()\n >>> contributor_browser.url\n 'http://nohost/plone/Members/test_user_1_/foo-page-title'\n >>> print contributor_browser.contents\n <...\n ...Changes saved...\n Foo Page Title...\n Foo Template Description...\n >>> portal.Members.contentValues()\n [,\n ]\n >>> folder.contentValues()\n []\n\nThe content added from the template behaves as other content and is\neditable by the owner.\n\n >>> contributor_browser.getLink('Edit')\n \n\nA user without rights to administer templates may not designate\ncontent as a template.\n\n >>> contributor_browser.getLink('Make template')\n Traceback (most recent call last):\n LinkNotFoundError\n\nThe template's permissions and field values have not been changed.\n\n >>> owner_browser.open(\n ... portal.Members['foo-template-title'].absolute_url())\n >>> print owner_browser.contents\n <...\n ...Foo Template Title...\n ...Foo Template Description...\n\n >>> contributor_browser.open(\n ... portal.Members['foo-template-title'].absolute_url())\n >>> contributor_browser.getLink('Edit')\n Traceback (most recent call last):\n LinkNotFoundError\n\nThe template for a given content type may be replaced using the \"Make\ntemplate\" action on the new template.\n\n >>> portal.Members.deleteReference(\n ... portal.Members['foo-template-title'],\n ... relationship='contemplate.Document')\n >>> portal.Members.addReference(\n ... folder['foo-page-title'],\n ... relationship='contemplate.Document')\n \n\n >>> contributor_browser.open(folder.absolute_url())\n >>> contributor_browser.getLink(url='/+/addATDocument').click()\n >>> contributor_browser.getControl('Title').value\n 'Foo Page Title'\n\nThe template may also be removed using the \"Remove template\" action on\nthe template based add form.\n\n >>> portal.Members.deleteReference(\n ... folder['foo-page-title'],\n ... relationship='contemplate.Document')\n\n >>> contributor_browser.open(folder.absolute_url())\n >>> contributor_browser.getLink(url='/+/addATDocument').click()\n >>> contributor_browser.url\n 'http://nohost/plone/Members/test_user_1_/portal_factory/Document/document.../edit'\n >>> contributor_browser.getControl('Title').value\n ''\n >>> contributor_browser.getControl('Description').value\n ''\n\nGlobal Templates\n================\n\nA template can be designated as the global template for a given portal\ntype. To do so set, the \"Global Template UID\" property of the type\ninfo in the portal_types tool to the UID of the template object.\n\nCreate an event as the template.\n\n >>> self.loginAsPortalOwner()\n >>> foo_event = portal[portal.invokeFactory(\n ... type_name='Event', id='event-template-title',\n ... title='Event Template Title',\n ... description='Event template description')]\n\nSet the type info property to the UID for the event template.\n\n >>> portal.portal_types.Event.manage_changeProperties(\n ... global_uid=foo_event.UID())\n\nNow when an event is added through the browser, it will be created\nfrom the template.\n\n >>> contributor_browser.open(folder.absolute_url())\n >>> contributor_browser.getLink(url='/+/addATEvent').click()\n >>> contributor_browser.getControl('Title').value\n 'Event Template Title'\n >>> contributor_browser.getControl('Description').value\n 'Event template description'\n\nReserved IDs\n============\n\nA reserved_id property can also be set on type information objects in\nportal_types. If set and an object with that ID already exists in the\ncontainer, then the type is not allowed to be added.\n\n >>> self.login()\n >>> folder.allowedContentTypes()\n [,\n ,\n ,\n ,\n ,\n ,\n ,\n ]\n >>> portal.portal_types.Document.reserved_id = 'foo-page-title'\n >>> folder.allowedContentTypes()\n [,\n ,\n ,\n ,\n ,\n ,\n ]\n\nChangelog\n=========\n\n0.1 - Unreleased\n----------------\n\n* Initial release\n\n\nTODO\n====\n\n* Add UI to the types control for selecting a global template\n\n* Add UI to folders for specifying context templates\n\n >>> owner_browser.getLink('Make template').click()\n >>> print owner_browser.contents\n <...\n ...Item designated as the template...\n\n >>> owner_browser.open(folder['foo-page-title'].absolute_url())\n >>> owner_browser.getLink('Make template').click()\n >>> print owner_browser.contents\n <...\n ...Item designated as the template...\n\n >>> owner_browser.open(folder.absolute_url())\n >>> owner_browser.getLink(url='/+/addATDocument').click()\n >>> owner_browser.getLink('Remove template').click()\n >>> print owner_browser.contents\n <...\n ...Item removed as the template...\n >>> contributor_browser.url\n 'http://nohost/plone/Members/foo-template-title'\n\n* Further avoid redundant indexing\n\n Implement manage_pasteObjects and manage_renameObject, such that no\n indexing is performed and leave indexing to the edit form handling.\n\n This might cause problems with programmatic use. Look at\n experimental.contentcreation.", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "http://pypi.python.org/pypi/collective.contemplate", "keywords": "", "license": "GPL", "maintainer": null, "maintainer_email": null, "name": "collective.contemplate", "package_url": "https://pypi.org/project/collective.contemplate/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/collective.contemplate/", "project_urls": { "Download": "UNKNOWN", "Homepage": "http://pypi.python.org/pypi/collective.contemplate" }, "release_url": "https://pypi.org/project/collective.contemplate/0.1/", "requires_dist": null, "requires_python": null, "summary": "Add content from existing content templates", "version": "0.1" }, "last_serial": 845318, "releases": { "0.1": [ { "comment_text": "", "digests": { "md5": "2fcdde526d2cd0515f62277a67f2201b", "sha256": "5985cea5ed6067a464387c6ec68949c5ffc7a1dcc0bbbf0a9122388bc676c66c" }, "downloads": -1, "filename": "collective.contemplate-0.1.tar.gz", "has_sig": false, "md5_digest": "2fcdde526d2cd0515f62277a67f2201b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 19278, "upload_time": "2009-08-24T00:12:10", "url": "https://files.pythonhosted.org/packages/d8/6c/7b4eb24c1406ca594d7a1ea2308df70e52df1ef3136b5ab390665d35049b/collective.contemplate-0.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "2fcdde526d2cd0515f62277a67f2201b", "sha256": "5985cea5ed6067a464387c6ec68949c5ffc7a1dcc0bbbf0a9122388bc676c66c" }, "downloads": -1, "filename": "collective.contemplate-0.1.tar.gz", "has_sig": false, "md5_digest": "2fcdde526d2cd0515f62277a67f2201b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 19278, "upload_time": "2009-08-24T00:12:10", "url": "https://files.pythonhosted.org/packages/d8/6c/7b4eb24c1406ca594d7a1ea2308df70e52df1ef3136b5ab390665d35049b/collective.contemplate-0.1.tar.gz" } ] }