From 10c6434de97ce3cdc81e9233422ce284f8a59336 Mon Sep 17 00:00:00 2001 From: helmutm Date: Sun, 26 Mar 2006 16:43:43 +0000 Subject: [PATCH] View controller now basically functional, with macro registries for CSS and JS resources git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@1146 fd906abe-77d9-0310-91a1-e0d9ade77398 --- browser/README.txt | 85 +++++++++++++++++++++++ browser/base_macros.pt | 15 ++++ browser/configure.zcml | 3 +- browser/controller.py | 51 ++++++++++++-- browser/ftests.py | 2 +- browser/{liquid.txt => liquid/README.txt} | 2 +- browser/liquid/configure.zcml | 16 +++-- browser/liquid/controller.py | 45 ++++++++++++ browser/liquid/view_macros.pt | 44 +++++------- browser/tests.py | 5 +- 10 files changed, 225 insertions(+), 43 deletions(-) create mode 100644 browser/base_macros.pt rename browser/{liquid.txt => liquid/README.txt} (92%) create mode 100644 browser/liquid/controller.py diff --git a/browser/README.txt b/browser/README.txt index b99d1ec..d97648b 100644 --- a/browser/README.txt +++ b/browser/README.txt @@ -6,3 +6,88 @@ We first set up a test and working environment: >>> from zope.app import zapi >>> from zope.app.testing import ztapi +The View Controller +------------------- + +There is a special view class that does not directly adapt to a real context +(i.e. typically a content) object but to a view instead. Thus it can provide +additional functionality e.g. for templates without the view being aware +of it. + +This view controller (or controller view) is typically provided by the +Controller class. Let's use the Controller sub-class from the Liquid skin +because this already provides some predefined stuff: + + >>> from cybertools.browser.liquid.controller import Controller + +Before creating a controller we have to set up a context object and +a view: + + >>> class SomeObject(object): pass + >>> obj = SomeObject() + >>> class View(object): + ... def __init__(self, context, request): + ... self.context = context + ... self.request = request + >>> from zope.publisher.browser import TestRequest + >>> request = TestRequest() + >>> view = View(obj, request) + + >>> controller = Controller(view, request) + >>> controller.view is view + True + >>> controller.context is obj + True + >>> controller.request is request + True + +The controller registers itself with the view: + + >>> view.controller is controller + True + +The resourceBase attribute gives a base URL to which one can simply append +the name of a resource. + + >>> controller.resourceBase + 'http://127.0.0.1/@@/' + +If necessary, a ++skin++xxx path element is provided +with the resourceBase to care for proper skin setting. This will work only +(and is only necessary) when the skin is set programmatically + + >>> class DummySkin(object): pass + >>> skin = DummySkin; skin.__name__ = 'dummy' + +Note that we make heavy use of Lazy attributes, so we have to get a new +controller object to get an updated setting: + + >>> controller = Controller(view, request) + >>> controller.skin = skin + >>> controller.resourceBase + 'http://127.0.0.1/++skin++dummy/@@/' + +The controller may be used as a provider for content elements using +ZPT macros: + + >>> cssMacros = controller.macros['css'] + >>> len(cssMacros) + 4 + >>> m1 = cssMacros[0] + >>> print m1.name, m1.media, m1.resourceName + css all zope3_tablelayout.css + +Calling a macro provided by Controller.macros[] returns the real ZPT macro: + + >>> m1() + [...base_macros.pt...css...] + +The pre-set collection of macros for a certain slot may be extended: + + >>> controller.macros.register('css', resourceName='node.css', media='all') + >>> len(controller.macros['css']) + 5 + >>> m5 = cssMacros[4] + >>> print m5.name, m5.media, m5.resourceName + css all node.css + diff --git a/browser/base_macros.pt b/browser/base_macros.pt new file mode 100644 index 0000000..3e33b80 --- /dev/null +++ b/browser/base_macros.pt @@ -0,0 +1,15 @@ + + + + + + + + + diff --git a/browser/configure.zcml b/browser/configure.zcml index 2ec65cf..6f9c0ff 100644 --- a/browser/configure.zcml +++ b/browser/configure.zcml @@ -6,7 +6,8 @@ i18n_domain="zope" > - diff --git a/browser/controller.py b/browser/controller.py index 2bca433..ba842c6 100644 --- a/browser/controller.py +++ b/browser/controller.py @@ -23,24 +23,63 @@ $Id$ """ from zope.app import zapi +from zope.app.pagetemplate import ViewPageTemplateFile from zope.cachedescriptors.property import Lazy class Controller(object): + def __init__(self, context, request): + self.view = context # the controller is adapted to a view + self.context = context.context + self.request = request + self.skin = None # may be overwritten by the view + context.controller = self # notify the view + @Lazy def macros(self): return Macros(self) + @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 Macros(object): + +class Macros(dict): + + # TODO: move to namedTemplate + standardTemplate = ViewPageTemplateFile('base_macros.pt') def __init__(self, controller): self.controller = controller - self.context = controller.context - self.request = controller.request + + def register(self, slot, template=None, name=None, position=None, **kw): + if template is None: + template = self.standardTemplate + if name is None: + name = slot + macro = Macro(template, name, **kw) + if slot not in self: + self[slot] = [] + if position is None: + self[slot].append(macro) + else: + self[slot].insert(position, macro) + +class Macro(object): + + def __init__(self, template, name, **kw): + self.template = template + self.name = name + for k in kw: + setattr(self, k, kw[k]) @Lazy - def css(self): - return 'Here comes the CSS stuff...' - + def macro(self): + return self.template.macros[self.name] + + def __call__(self): + return self.macro + diff --git a/browser/ftests.py b/browser/ftests.py index 8b54f89..6aaa6f2 100755 --- a/browser/ftests.py +++ b/browser/ftests.py @@ -7,7 +7,7 @@ from zope.app.testing.functional import FunctionalDocFileSuite def test_suite(): flags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS - browser = FunctionalDocFileSuite('liquid.txt', optionflags=flags) + browser = FunctionalDocFileSuite('liquid/README.txt', optionflags=flags) return unittest.TestSuite((browser,)) if __name__ == '__main__': diff --git a/browser/liquid.txt b/browser/liquid/README.txt similarity index 92% rename from browser/liquid.txt rename to browser/liquid/README.txt index db04b70..5343faa 100644 --- a/browser/liquid.txt +++ b/browser/liquid/README.txt @@ -11,7 +11,7 @@ We first set up a test and working environment: >>> browser = Browser() >>> browser.addHeader('Authorization', 'Basic mgr:mgrpw') -We can now open a page using the CyberView skin: +We can now open a page using the Liquid skin: >>> browser.addHeader('Accept-Language', 'en-US') >>> browser.open('http://localhost/++skin++Liquid') diff --git a/browser/liquid/configure.zcml b/browser/liquid/configure.zcml index 8186869..8cebc26 100644 --- a/browser/liquid/configure.zcml +++ b/browser/liquid/configure.zcml @@ -22,13 +22,15 @@ permission="zope.View" layer="liquid" /> - + - - - + + + diff --git a/browser/liquid/controller.py b/browser/liquid/controller.py new file mode 100644 index 0000000..9c24a3b --- /dev/null +++ b/browser/liquid/controller.py @@ -0,0 +1,45 @@ +# +# Copyright (c) 2006 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 +# + +""" +View controller for the Liquid skin. + +$Id$ +""" + +from cybertools.browser.controller import Controller as BaseController + + +class Controller(BaseController): + + def __init__(self, context, request): + super(Controller, self).__init__(context, request) + self.setupCss() + self.setupJs() + + def setupCss(self): + macros = self.macros + params = [('zope3_tablelayout.css', 'all'), + ('base.css', 'screen'), + ('custom.css', 'all'), ('print.css', 'print')] + for param in params: + macros.register('css', resourceName=param[0], media=param[1]) + + def setupJs(self): + #self.macros['js'] = [] + self.macros.register('js', resourceName='zope3.js') diff --git a/browser/liquid/view_macros.pt b/browser/liquid/view_macros.pt index 08b27c5..e7b9618 100644 --- a/browser/liquid/view_macros.pt +++ b/browser/liquid/view_macros.pt @@ -1,46 +1,39 @@ + tal:define="controller nocall:view/@@controller; + resourceBase controller/resourceBase"> + + Powered by Zope 3 - + + + + + + - + + + - - - - + - diff --git a/browser/tests.py b/browser/tests.py index d6b5e76..576547e 100755 --- a/browser/tests.py +++ b/browser/tests.py @@ -1,6 +1,6 @@ # $Id$ -import unittest +import unittest, doctest from zope.testing.doctestunit import DocFileSuite from zope.app.testing import ztapi from zope.interface.verify import verifyClass @@ -8,8 +8,9 @@ from zope.app import zapi def test_suite(): + flags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS return unittest.TestSuite(( - DocFileSuite('README.txt'), + DocFileSuite('README.txt', optionflags=flags), )) if __name__ == '__main__':