work in progress: layout managememnt
git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@2891 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
7793462e9a
commit
97cea0f183
10 changed files with 161 additions and 86 deletions
|
@ -4,40 +4,52 @@ Layout Management
|
|||
|
||||
($Id$)
|
||||
|
||||
Let's start with some basic setup; the traversable adapter is needed for
|
||||
rendering the page templates.
|
||||
|
||||
>>> from zope import component
|
||||
>>> from zope.interface import Interface
|
||||
>>> from zope.traversing.adapters import DefaultTraversable
|
||||
>>> component.provideAdapter(DefaultTraversable, (Interface,))
|
||||
|
||||
For testing we define a simple content class.
|
||||
|
||||
>>> class Document(object):
|
||||
... text = ''
|
||||
|
||||
The layout management is controlled by a global utility, the layout
|
||||
manager.
|
||||
|
||||
>>> from cybertools.composer.layout.base import LayoutManager, LayoutInstance
|
||||
>>> from cybertools.composer.layout.interfaces import ILayout
|
||||
|
||||
>>> from cybertools.composer.layout.base import LayoutManager
|
||||
>>> manager = LayoutManager()
|
||||
>>> component.provideUtility(manager)
|
||||
|
||||
>>> from zope.traversing.adapters import DefaultTraversable
|
||||
>>> component.provideAdapter(DefaultTraversable, (Interface,))
|
||||
The layouts themselves are also specified as utilities.
|
||||
|
||||
>>> #from cybertools.composer.layout.browser.liquid.default import css
|
||||
>>> #component.provideUtility(css, ILayout, name='css')
|
||||
|
||||
>>> from cybertools.composer.layout.browser.liquid.default import body
|
||||
>>> component.provideUtility(body, ILayout, name='body.liquid')
|
||||
|
||||
>>> from cybertools.composer.layout.browser.default import footer
|
||||
>>> component.provideUtility(footer, ILayout, name='footer.default')
|
||||
|
||||
In addition we have to provide at least one layout instance adapter that
|
||||
connects a layout with the client object.
|
||||
|
||||
>>> component.provideAdapter(LayoutInstance, (object,))
|
||||
|
||||
|
||||
Browser Views
|
||||
=============
|
||||
|
||||
>>> from zope.app.pagetemplate import ViewPageTemplateFile
|
||||
>>> standardRenderers = ViewPageTemplateFile('browser/standard.pt').macros
|
||||
|
||||
>>> from cybertools.composer.layout.base import Layout
|
||||
>>> from cybertools.composer.layout.interfaces import ILayout
|
||||
|
||||
>>> #css = Layout('page.css', renderer=standardRenderers['css'])
|
||||
>>> # css = ResourceCollection('css', resourceRenderers['css'])
|
||||
>>> #component.provideUtility(css, ILayout, name='css')
|
||||
|
||||
>>> from cybertools.composer.layout.browser.liquid.default import BodyLayout
|
||||
>>> bodyLayout = BodyLayout()
|
||||
>>> component.provideUtility(bodyLayout, ILayout, name='body.liquid')
|
||||
|
||||
>>> footerLayout = Layout('body.footer', renderer=standardRenderers['footer'])
|
||||
>>> component.provideUtility(footerLayout, ILayout, name='footer.default')
|
||||
|
||||
>>> from cybertools.composer.layout.browser.view import Page
|
||||
>>> from zope.publisher.browser import TestRequest
|
||||
>>> page = Page(None, TestRequest())
|
||||
|
||||
>>> page = Page(Document(), TestRequest())
|
||||
|
||||
>>> page()
|
||||
u'<!DOCTYPE ...>...<html ...>...</html>...'
|
||||
|
|
|
@ -47,37 +47,35 @@ class LayoutManager(object):
|
|||
region.layouts.append(layout)
|
||||
return result
|
||||
|
||||
def getLayouts(self, key, **kw):
|
||||
def getLayouts(self, key, instance):
|
||||
region = self.regions.get(key)
|
||||
if region is None:
|
||||
return []
|
||||
# TODO: filter region.layouts
|
||||
return region.layouts
|
||||
result = []
|
||||
for layout in region.layouts:
|
||||
if self.check(layout, instance):
|
||||
result.append(layout)
|
||||
return result
|
||||
|
||||
def register(self, layout, regionName):
|
||||
region = self.regions.setdefault(regionName, Region(regionName))
|
||||
region.layouts.append(layout)
|
||||
def check(self, layout, instance):
|
||||
if instance is None or instance.checkLayout(layout):
|
||||
return True
|
||||
|
||||
|
||||
class Layout(Template):
|
||||
|
||||
implements(ILayout)
|
||||
|
||||
name = ''
|
||||
title = description = u''
|
||||
category = 'default'
|
||||
renderer = None
|
||||
regionName = None
|
||||
skin = 'default'
|
||||
|
||||
def __init__(self, regionName, **kw):
|
||||
def __init__(self, name, regionName, **kw):
|
||||
self.name = name
|
||||
self.regionName = regionName
|
||||
for k, v in kw.items():
|
||||
setattr(self, k, v)
|
||||
|
||||
def registerFor(self, regionName):
|
||||
manager = component.getUtility(ILayoutManager)
|
||||
manager.register(self, regionName)
|
||||
self.regionName = regionName
|
||||
|
||||
|
||||
class LayoutInstance(object):
|
||||
|
||||
|
@ -91,3 +89,7 @@ class LayoutInstance(object):
|
|||
@property
|
||||
def renderer(self):
|
||||
return self.template.renderer
|
||||
|
||||
def checkLayout(self, layout):
|
||||
return True
|
||||
|
||||
|
|
3
composer/layout/browser/default.pt
Normal file
3
composer/layout/browser/default.pt
Normal file
|
@ -0,0 +1,3 @@
|
|||
<div metal:define-macro="footer">
|
||||
Some footer text.
|
||||
</div>
|
|
@ -27,7 +27,8 @@ from zope.app.pagetemplate import ViewPageTemplateFile
|
|||
from cybertools.composer.layout.base import Layout
|
||||
|
||||
|
||||
standardRenderers = ViewPageTemplateFile('standard.pt').macros
|
||||
defaultRenderers = ViewPageTemplateFile('default.pt').macros
|
||||
|
||||
|
||||
footer = Layout('body.footer', renderer=standardRenderers['footer'])
|
||||
footer = Layout('footer.default', 'body.footer',
|
||||
renderer=defaultRenderers['footer'])
|
||||
|
|
|
@ -30,17 +30,8 @@ from zope.interface import implements
|
|||
from cybertools.composer.layout.base import Layout
|
||||
|
||||
|
||||
template = ViewPageTemplateFile('default.pt')
|
||||
defaultRenderers = ViewPageTemplateFile('default.pt').macros
|
||||
|
||||
|
||||
class BodyLayout(Layout):
|
||||
|
||||
regionName = 'page.body'
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@Lazy
|
||||
def renderer(self):
|
||||
return template.macros['body']
|
||||
body = Layout('body.liquid', 'page.body',
|
||||
renderer=defaultRenderers['body'])
|
||||
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
|
||||
<tal:css repeat="macro view/resources/css">
|
||||
<metal:css use-macro="macro" />
|
||||
<tal:css repeat="view view/layouts/css">
|
||||
<metal:css use-macro="view/renderer" />
|
||||
</tal:css>
|
||||
|
||||
<base href="." tal:attributes="href request/URL">
|
||||
|
|
|
@ -1,12 +1,7 @@
|
|||
<div metal:define-macro="footer">
|
||||
Some footer text.
|
||||
</div>
|
||||
|
||||
|
||||
<metal:css define-macro="css">
|
||||
<!--<style type="text/css" media="all"
|
||||
tal:attributes="media macro/media"
|
||||
tal:content="string:@import url(${resourceBase}${macro/resourceName});">
|
||||
tal:attributes="media view/media"
|
||||
tal:content="string:@import url(${view/page/resourceBase}${view/context/resourceName});">
|
||||
@import url(some.css);
|
||||
</style>-->
|
||||
</metal:css>
|
||||
|
|
34
composer/layout/browser/standard.py
Normal file
34
composer/layout/browser/standard.py
Normal file
|
@ -0,0 +1,34 @@
|
|||
#
|
||||
# Copyright (c) 2008 Helmut Merz helmutm@cy55.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
"""
|
||||
Default layouts.
|
||||
|
||||
$Id$
|
||||
"""
|
||||
|
||||
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||
|
||||
from cybertools.composer.layout.base import Layout
|
||||
|
||||
|
||||
standardRenderers = ViewPageTemplateFile('standard.pt').macros
|
||||
|
||||
|
||||
footer = Layout('footer.default', 'body.footer',
|
||||
renderer=standardRenderers['footer'])
|
|
@ -27,38 +27,56 @@ from zope.interface import Interface, implements
|
|||
from zope.cachedescriptors.property import Lazy
|
||||
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||
|
||||
from cybertools.composer.layout.base import Layout, LayoutInstance
|
||||
from cybertools.composer.layout.interfaces import ILayoutManager
|
||||
from cybertools.composer.layout.base import Layout
|
||||
from cybertools.composer.layout.interfaces import ILayoutManager, ILayoutInstance
|
||||
|
||||
|
||||
class BaseView(object):
|
||||
|
||||
template = ViewPageTemplateFile('base.pt')
|
||||
|
||||
def __init__(self, context, request, name=None):
|
||||
page = None
|
||||
parent = None
|
||||
skin = None
|
||||
|
||||
def __init__(self, context, request, **kw):
|
||||
self.context = self.__parent__ = context
|
||||
self.request = request
|
||||
if name is not None:
|
||||
self.name = name
|
||||
|
||||
def update(self):
|
||||
return True
|
||||
for k, v in kw.items():
|
||||
setattr(self, k, v)
|
||||
|
||||
def __call__(self):
|
||||
return self.template(self)
|
||||
|
||||
def update(self):
|
||||
return True
|
||||
|
||||
|
||||
class Page(BaseView):
|
||||
|
||||
macroName = 'page'
|
||||
|
||||
@Lazy
|
||||
def rootView(self):
|
||||
return self
|
||||
|
||||
def __call__(self):
|
||||
layout = Layout('page')
|
||||
layout.renderer = ViewPageTemplateFile('main.pt').macros['page']
|
||||
instance = LayoutInstance(self.context)
|
||||
layout = Layout('page', 'page')
|
||||
layout.renderer = ViewPageTemplateFile('main.pt').macros[self.macroName]
|
||||
instance = ILayoutInstance(self.context)
|
||||
instance.template = layout
|
||||
view = LayoutView(instance, self.request, name='page')
|
||||
view = LayoutView(instance, self.request, name='page',
|
||||
parent=self, page=self)
|
||||
view.body = view.layouts['body'][0]
|
||||
instance.view = view
|
||||
return view.template(view)
|
||||
|
||||
@Lazy
|
||||
def resourceBase(self):
|
||||
skinSetter = self.skin and ('/++skin++' + self.skin.__name__) or ''
|
||||
# TODO: put '/@@' etc after path to site instead of directly after URL0
|
||||
return self.request.URL[0] + skinSetter + '/@@/'
|
||||
|
||||
|
||||
class LayoutView(BaseView):
|
||||
|
||||
|
@ -83,9 +101,9 @@ class LayoutView(BaseView):
|
|||
def resources(self):
|
||||
return ViewResources(self)
|
||||
|
||||
def getLayoutsFor(self, key, **kw):
|
||||
def getLayoutsFor(self, key):
|
||||
manager = component.getUtility(ILayoutManager)
|
||||
return manager.getLayouts('.'.join((self.name, key)), **kw)
|
||||
return manager.getLayouts('.'.join((self.name, key)), self.context)
|
||||
|
||||
|
||||
# subview providers
|
||||
|
@ -99,10 +117,12 @@ class ViewLayouts(object):
|
|||
view = self.view
|
||||
subviews = []
|
||||
for layout in view.getLayoutsFor(key):
|
||||
instance = LayoutInstance(view.client)
|
||||
instance = ILayoutInstance(view.client)
|
||||
instance.template = layout
|
||||
instance.view = view
|
||||
subviews.append(LayoutView(instance, view.request, name=key))
|
||||
v = LayoutView(instance, view.request, name=key,
|
||||
parent=view, page=view.page)
|
||||
instance.view = v
|
||||
subviews.append(v)
|
||||
return subviews
|
||||
|
||||
|
||||
|
|
|
@ -37,17 +37,24 @@ class ILayoutManager(Interface):
|
|||
""" A utility that manages layouts and regions.
|
||||
"""
|
||||
|
||||
def register(layout, regionName):
|
||||
""" Register the layout given for the region specified.
|
||||
def getLayouts(regionName, instance):
|
||||
""" Return a sequence of layouts for the region given that are
|
||||
valid sub-layouts for the layout instance given.
|
||||
"""
|
||||
|
||||
def check(layout, instance):
|
||||
""" Return True if the layout given is a valid sub-layout
|
||||
for the instance given.
|
||||
"""
|
||||
|
||||
|
||||
|
||||
class ILayout(ITemplate):
|
||||
""" Represents an ordered sequence of layout elements.
|
||||
"""
|
||||
|
||||
name = schema.ASCIILine(
|
||||
title=_(u'Layout name'),
|
||||
title=_(u'Layout Name'),
|
||||
description=_(u'The internal name of the layout.'),
|
||||
required=True,)
|
||||
title = schema.TextLine(
|
||||
|
@ -63,13 +70,14 @@ class ILayout(ITemplate):
|
|||
description=_(u'The name of a layout category this layout '
|
||||
u'belongs to.'),
|
||||
required=False,)
|
||||
regionName = schema.ASCIILine(
|
||||
title=_(u'Region Name'),
|
||||
description=_(u'A dotted name that specifies the region '
|
||||
u'this layout should be used for.'),
|
||||
required=True,)
|
||||
|
||||
renderer = Attribute(u'An object responsible for rendering the layout.')
|
||||
|
||||
def registerFor(regionName):
|
||||
""" Register the layout for the region specified.
|
||||
"""
|
||||
|
||||
|
||||
class ILayoutComponent(IComponent):
|
||||
""" May be used for data entry or display.
|
||||
|
@ -77,11 +85,11 @@ class ILayoutComponent(IComponent):
|
|||
|
||||
name = schema.ASCIILine(
|
||||
title=_(u'Component name'),
|
||||
description=_(u'The internal name of the component'),
|
||||
description=_(u'The internal name of the component.'),
|
||||
required=True,)
|
||||
title = schema.TextLine(
|
||||
title=_(u'Title'),
|
||||
description=_(u'The title or label of the component'),
|
||||
description=_(u'The title or label of the component.'),
|
||||
required=True,)
|
||||
description = schema.Text(
|
||||
title=_(u'Description'),
|
||||
|
@ -100,16 +108,25 @@ class ILayoutInstance(IInstance):
|
|||
|
||||
renderer = Attribute(u'An object responsible for rendering the layout.')
|
||||
|
||||
def checkLayout(layout):
|
||||
""" Return True if the layout given is a valid sub-layout
|
||||
for this instance.
|
||||
"""
|
||||
|
||||
|
||||
class IRegion(Interface):
|
||||
""" A part of a layout "canvas" that may be filled with layout objects.
|
||||
"""
|
||||
|
||||
name = schema.ASCIILine(
|
||||
title=_(u'Region name'),
|
||||
description=_(u'The internal name of the region.'),
|
||||
required=True,)
|
||||
allowedLayoutCategories = schema.List(
|
||||
title=_(u'Allowed layout categories'),
|
||||
description=_(u'A collection of names of layout categories '
|
||||
u'to which layouts may belong that may be placed '
|
||||
u'in this region'),
|
||||
u'in this region.'),
|
||||
value_type=schema.ASCIILine(),
|
||||
required=False,)
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue