{ "info": { "author": "Martin Aspeli, Laurence Rowe", "author_email": "optilude@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: Plone", "Framework :: Plone :: 4.3", "Framework :: Plone :: 5.0", "Framework :: Plone :: 5.1", "Framework :: Plone :: 5.2", "License :: OSI Approved :: GNU General Public License v2 (GPLv2)", "Programming Language :: Python", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Software Development :: Libraries :: Python Modules" ], "description": "======================\nIntroduction to Blocks\n======================\n\n.. image:: https://secure.travis-ci.org/plone/plone.app.blocks.png?branch=master\n :alt: Travis CI badge\n :target: http://travis-ci.org/plone/plone.app.blocks\n\n.. image:: https://coveralls.io/repos/plone/plone.app.blocks/badge.png?branch=master\n :alt: Coveralls badge\n :target: https://coveralls.io/r/plone/plone.app.blocks\n\nThis package implements the 'blocks' rendering model,\nby providing several transform stages that hook into ``plone.transformchain``.\n\nThe rendering stages are:\n\n``plone.app.blocks.parsexml`` (order 8000)\n Turns the response in a ``repoze.xmliter`` ``XMLSerializer`` object.\n This is then used by the subsequent stages.\n If the input is not HTML, the transformation is aborted.\n\n``plone.app.blocks.mergepanels`` (order 8100)\n Looks up the site layout and executes the panel merge algorithm.\n Sets a request variable ('plone.app.blocks.merged') to indicate that it has done its job.\n\n``plone.app.blocks.tiles`` (order 8500)\n Resolve tiles and place them directly into the merged layout.\n This is the fallback for views that do not opt into ``ITilePageRendered``.\n\n``plone.app.blocks.esirender`` (order 9900)\n Only executed if the request key ``plone.app.blocks.esi`` is set and its value is true,\n as would be the case if any ESI-rendered tiles are included and ESI rendering is enabled globally.\n This step will serialise the response down to a string and perform some substitution to make ESI rendering work.\n\n\nSite layouts\n============\n\nThe package also registers the ``sitelayout`` ``plone.resource`` resource type,\nallowing site layouts to be created easily as static HTML files served from resource directories.\nThe URL to a site layout is typically something like::\n\n /++sitelayout++my.layout/site.html\n\nSee ``plone.resource`` for more information about how to register resource directories.\nFor site layouts, the ``type`` of the resource directory is ``sitelayout``.\n\nIt is possible to provide a manifest file that gives a title, description and alternative default file for a site layout HTML file in a resource directory.\nTo create such a manifest, put a ``manifest.cfg`` file in the layout directory with the following structure:\n\n.. code-block:: ini\n\n [sitelayout]\n title = My layout title\n description = Some description\n file = some-html-file.html\n\n* All keys are optional.\n* The file defaults to ``site.html``.\n* Single manifest may contain multiple ``[sitelayout]`` sections.\n\nA vocabulary factory called ``plone.availableSiteLayouts`` is registered to allow lookup of all registered site layouts.\nThe terms in this vocabulary use the URL as a value,\nthe resource directory name as a token,\nand the title from the manifest (falling back on a sanitised version of the resource directory name) as the title.\n\nThe current default site layout can be identified by the ``plone.registry`` key ``plone.defaultSiteLayout``,\nwhich is set to ``None`` by default.\nTo always use the current site default, use:\n\n.. code-block:: html\n\n \n\nThe ``@@default-site-layout`` view will render the current default site layout.\n\n\nContent layouts\n===============\n\nThe package also registers the ``contentlayout`` ``plone.resource`` resource type,\nallowing shared content area layouts to be created easily as static HTML files served from resource directories.\nThe URL to a content layout is typically something like::\n\n /++contentlayout++my.layout/content.html\n\nSee ``plone.resource`` for more information about how to register resource directories.\nFor site layouts, the ``type`` of the resource directory is ``contentlayout``.\n\nIt is possible to provide a manifest file that gives a title, description and alternative default file for a site layout HTML file in a resource directory.\nTo create such a manifest, put a ``manifest.cfg`` file in the layout directory with the following structure:\n\n.. code-block:: ini\n\n [contentlayout]\n title = My layout title\n description = Some description\n file = some-html-file.html\n screenshot = mylayout.png\n for = Document,Folder\n permission = cmf.ModifyPortalContent\n\n* All keys are optional.\n* Value for key ``file`` defaults to ``content.html``.\n* Single manifest may contain multiple ``[contentlayout]`` sections.\n* Values for keys ``for`` and ``permission`` are only for advisory and may not\n be enforced.\n\nA vocabulary factory called ``plone.availableContentLayouts`` is registered to allow lookup of all registered content layouts.\nThe terms in this vocabulary use the URL as a value,\nthe resource directory name as a token,\nand the title from the manifest (falling back on a sanitised version of the resource directory name) as the title.\n\nThe default content layout can be identified by the ``plone.registry`` key ``plone.app.blocks.default_layout``,\nand the default content layout for some specific content type with key ``plone.app.blocks.default_layout.my_type``.\nThe default content layout is supported by the built-in ``layout_view`` browser view for content with ``ILayoutAware`` behavior.\n\n\nILayoutAware behavior\n=====================\n\nIt is possible for the default site layout to be overridden per section,\nby having parent objects provide or be adaptable to ``plone.app.blocks.layoutbehavior.ILayoutAware``.\nAs the module name implies, this interface can be used as a ``plone.behavior`` behavior,\nbut it can also be implemented directly or used as a standard adapter.\n\nThe ``ILayoutAware`` interface defines three properties:\n\n``content``\n which contains the body of the page to be rendered.\n``contentLayout``\n which contains the path to the selected static content layout,\n which is used instead of ``content`` when set.\n``pageSiteLayout``\n which contains the path to the site layout to be used for the given page.\n It can be ``None`` if the default is to be used.\n``sectionSiteLayout``\n which contains the path to the site layout to be used for pages *underneath* the given page (but not for the page itself).\n Again, it can be ``None`` if the default is to be used.\n\nTo make use of the page site layout, use the following:\n\n.. code-block:: html\n\n \n\nSee ``rendering.rst`` for detailed examples of how the processing is applied,\nand ``esi.rst`` for details about how Edge Side Includes can be supported.\n\nBlocks rendering in detail\n==========================\n\nThis doctest illustrates the blocks rendering process.\nAt a high level, it consists of the following steps:\n\n0. Obtain the content page, an HTML document.\n1. Look for a site layout link in the content page.\n\n This takes the form of an attribute on the html tag like ``
``.\n\n Usually, the site layout URL will refer to a resource in a resource directory of type ``sitelayout``,\n e.g. ``/++sitelayout++foo/site.html``,\n although the layout can be any URL.\n An absolute path like this will be adjusted so that it is always relative to the Plone site root.\n2. Resolve and obtain the site layout.\n\n This is another HTML document.\n3. Extract panels from the site layout.\n\n A panel is an element (usually a ````) in the layout page with a data-panel attribute,\n for example: ````.\n The attribute specifies an id which *may* be used in the content page.\n4. Merge panels.\n\n This is the process which applies the layout to the unstyled page.\n All panels in the layout page that have a matching element in the content page are replaced by the content page element.\n The rest of the content page is discarded.\n5. Resolve and obtain tiles.\n\n A tile is a placeholder element in the page which will be replaced by the contents of a document referenced by a URL.\n\n A tile is identified by a placeholder element with a ``data-tile`` attribute containing the tile URL.\n\n Note that at this point, panel merging has taken place,\n so if a panel in the content page contains tiles, they will be carried over into the merge page.\n Also note that it is possible to have tiles outside of panels - the two concepts are not directly related.\n\n The ``plone.tiles`` package provides a framework for writing tiles,\n although in reality a tile can be any HTML page.\n6. Place tiles into the page.\n\n The tile should resolve to a full HTML document.\n Any content found in the ``\n ...\n ... This is a demo tile with id %(name)s\n ...
\n ...\n ... Magic number: %(number)d; Form: %(form)s; Query string: %(queryString)s; URL: %(url)s\n ...
\n ... \n ... \"\"\" % dict(name=self.id, number=self.data['magicNumber'] or -1,\n ... form=sorted(self.request.form.items()), queryString=self.request['QUERY_STRING'], url=self.request.getURL())\n\nLet's add another tile, this time only a head part.\nThis could for example be a tile that only needs to insert some CSS.\n\n.. code-block:: python\n\n >>> class TestTileNoBody(Tile):\n ... __name__ = 'test.tile_nobody'\n ...\n ... def __call__(self):\n ... return \"\"\"\\\n ... \n ... \n ... \n ... \n ... \"\"\"\n\nWe register these views and tiles in the same way the ZCML handlers for ``\n This is a demo tile with id tile2\n
\n\n Magic number: 2; Form: [('magicNumber', 2)]; Query string: magicNumber:int=2; URL: http://nohost/plone/@@test.tile1/tile2\n
\n\n This is a demo tile with id tile3\n
\n\n Magic number: -1; Form: []; Query string: ; URL: http://nohost/plone/@@test.tile1/tile3\n
\n\n This is a demo tile with id tile2\n
\n\n Magic number: -1; Form: []; Query string: ; URL: http://nohost/plone/@@test.tile1/tile2\n
\n\n ... Non-ESI tile with query string %(queryString)s\n ...
\n ... \n ... \"\"\" % dict(name=self.id, queryString=self.request['QUERY_STRING'])\n\n >>> testTile2Type = TileType(\n ... name=u'test.tile2',\n ... title=u\"Test tile 2\",\n ... description=u\"A tile used for testing\",\n ... add_permission=\"cmf.ManagePortal\",\n ... view_permission=\"zope2.View\")\n\n >>> class SimpleESITile(ESITile):\n ... __name__ = 'test.tile3' # normally set by ZCML handler\n ...\n ... def render(self):\n ... return \"\"\"\\\n ... \n ... \n ... \n ... \n ... \n ...\n ... ESI tile with query string %(queryString)s\n ...
\n ... \n ... \"\"\" % dict(name=self.id, queryString=self.request['QUERY_STRING'])\n\n >>> testTile3Type = TileType(\n ... name=u'test.tile3',\n ... title=u\"Test tile 3\",\n ... description=u\"A tile used for testing\",\n ... add_permission=\"cmf.ManagePortal\",\n ... view_permission=\"zope2.View\")\n\nRegister these in the same way that the ZCML handlers would, more or less.\n\n.. code-block:: python\n\n >>> from AccessControl.security import protectClass\n >>> protectClass(NonESITile, 'zope2.View')\n >>> protectClass(SimpleESITile, 'zope2.View')\n\n >>> from App.class_init import InitializeClass\n >>> InitializeClass(NonESITile)\n >>> InitializeClass(SimpleESITile)\n\n >>> from zope.component import provideAdapter, provideUtility\n >>> from zope.interface import Interface\n >>> provideAdapter(NonESITile, (Interface, Interface,), Interface, u'test.tile2',)\n >>> provideUtility(testTile2Type, name=u'test.tile2')\n >>> provideAdapter(SimpleESITile, (Interface, Interface,), Interface, u'test.tile3',)\n >>> provideUtility(testTile3Type, name=u'test.tile3')\n\nWe will also register a simple layout and a simple page using these tiles.\n\n.. code-block:: python\n\n >>> layoutHTML = u\"\"\"\\\n ... \n ... \n ... \n ...\n Non-ESI tile with query string foo=bar\n
\n\n ESI tile with query string foo=bar\n
\n\n Non-ESI tile with query string\n
\n\n ESI tile with query string\n
\n \n \n\n Non-ESI tile with query string foo=bar\n
\n\n Non-ESI tile with query string\n
\n\n ESI tile with query string foo=bar\n
\n\n >>> browser.open(\"http://nohost/plone/@@test.tile3/tile2/@@esi-body?\")\n >>> print(browser.contents)\n\n ESI tile with query string\n
\n\n.. _plone.tiles: http://pypi.python.org/pypi/plone.tiles\n\nChangelog\n=========\n\n4.3.2 (2019-10-18)\n------------------\n\nBug fixes:\n\n- Catch errors on resolving tiles and return an error message instead of breaking the whole UI\n [MrTango]\n\n- Fix issue where layout aware tile data storage read cache was not purged when\n data was updated programmatically [fixes #75]\n [datakurre]\n\n- Fix issue where resolveResource would break when url html content param contains other ++-url's\n [MrTango]\n\n4.3.1 (2019-02-20)\n------------------\n\nBug fixes:\n\n- fix multidict feature for python 3\n [petschki]\n\n\n4.3.0 (2019-02-10)\n------------------\n\nBug fixes:\n\n- Enforce usage of plone.subrequest >= 1.7.0;\n this avoids ``TypeError`` on package upgrades (refs. `#62`` of the tile content will be merged into the ``
`` of the rendered content.\n The contents of the ``
`` of the tile content are put into the rendered document at the tile placeholder.\n\nRendering step-by-step\n----------------------\n\nLet us now illustrate the rendering process.\nWe'll need a few variables defined first:\n\n.. code-block:: python\n\n >>> from plone.testing.z2 import Browser\n >>> import transaction\n\n >>> app = layer['app']\n >>> portal = layer['portal']\n\n >>> browser = Browser(app)\n >>> browser.handleErrors = False\n\nCreating a site layout\n~~~~~~~~~~~~~~~~~~~~~~\n\nThe most common approach for managing site layouts is to use a resource registered using a ``plone.resource`` directory of type ``sitelayout``,\nand then use the ``@@default-site-layout`` view to reference the content.\nWe will illustrate this below, but it is important to realise that ``plone.app.blocks`` works by post-processing responses rendered by Zope.\nThe content and layout pages could just as easily be created by views of content objects, or even resources external to Zope/Plone.\n\nFirst, we will create a resource representing the site layout and its panels.\nThis includes some resources and other elements in the ``
``,\n```` tags which identify tile placeholders and panels,\nas well as content inside and outside panels.\nThe tiles in this case are managed by ``plone.tiles``, and are both of the same type.\n\n.. code-block:: python\n\n >>> layoutHTML = \"\"\"\\\n ... \n ... \n ...
\n ...
\n ... \n ... \n ...\n ... \n ...\n ... \n ... \n ...
contents are ignored, instead of being merged into the final page.\nThat is, only the ``@@esi-body`` view form `plone.tiles`_ is used by default.\n\nAn ESI link looks like this:\n\n.. code-block:: xml\n\n
\n ... \n ... \n ...