Metadata-Version: 1.0
Name: dolmen.app.viewselector
Version: 0.2.1
Summary: Dolmen Layout/View Selector
Home-page: http://tracker.trollfot.org/
Author: Souheil Chelfouh
Author-email: souheil@chelfouh.com
License: GPL
Download-URL: http://pypi.python.org/pypi/dolmen.app.viewselector
Description: 
        
        The package ``dolmen.app.viewselector`` is an extension for `Dolmen`
        applications, allowing a basic management of alternative views.
        
        
        About
        =====
        
        In a CMS, it's often very useful to be able to design and provide several
        views for a single item. These views can be relevant, according to a given
        context and situation. `dolmen.app.viewselector` allows you to define a
        view as being an "alternate" option to render a given context. A menu then
        provides you the machinery to select the most relevant view for your
        usecase.
        
        
        A quick overview
        ================
        
        To know that a component can provide alternative views, we need to
        explicitly specify it. An interface defines the "selector" capability::
        
          >>> from dolmen.app.viewselector import IViewSelector
          >>> list(IViewSelector)
          ['selected_view']
        
          >>> IViewSelector['selected_view']
          <...TextLine...>
        
        The IViewSelector interface defines a single field, known as
        'selected_view'. The field value is merely the name of the Page
        component currently used::
        
          >>> IViewSelector['selected_view'].default
          u'base_view'
        
        Out of the box, the default value is set to 'base_view'.
        
        
        Defining the content
        ====================
        
        To demonstrate the alternative views, we first need a context that is
        aware of the views selection::
        
          >>> from zope.location import Location
          >>> from zope.interface import implements
        
          >>> class Bear(Location):
          ...  implements(IViewSelector)
          ...  selected_view = u"sleeping"
        
        We defined the default view to the view named "sleeping".
        
        
        Defining alternate views
        ========================
        
        The alternative views are 'pages' (see ``megrok.layout`` and
        ``dolmen.app.layout``) that are registered onto a dedicated menu.
        To define an alternative view, we inherit from the ``AlternativeView``
        base class::
        
          >>> import grokcore.view as grok
          >>> from grokcore.component import testing
          >>> from dolmen.app.viewselector import AlternativeView
        
          >>> class Sleeping(AlternativeView):
          ...   grok.context(Bear)
          ...   grok.title("Sleeping bear")
          ...
          ...   def render(self):
          ...     return u"RRrrr..."
        
          >>> testing.grok_component('sleeping', Sleeping)
          True
        
        The "sleeping" view that we defined as a default value for our IViewSelector
        is now defined and registered. Let's register 2 other views, to populate
        the menu and provide a "realistic" usecase::
        
          >>> class PolarFur(AlternativeView):
          ...   grok.context(Bear)
          ...   grok.title("Polar bear")
          ...
          ...   def render(self):
          ...     return u"I'm white !"
        
          >>> testing.grok_component('polar', PolarFur)
          True
        
          >>> class SpringFur(AlternativeView):
          ...   grok.context(Bear)
          ...   grok.title("Spring bear")
          ...   grok.require("dolmen.content.Edit")
          ...
          ...   def render(self):
          ...     return u"I'm brown !"
        
          >>> testing.grok_component('spring', SpringFur)
          True
        
        
        Default dynamic index
        =====================
        
        In order to render the selected view, another view is used. We may call it a 
        "routing" view, as it's used to lookup and render the desired component.
        
        We first need to instance the two needed components, the content and
        the request ::
        
          >>> from zope.publisher.browser import TestRequest
        
          >>> herman = Bear()
          >>> request = TestRequest()
        
        The content provides IViewSelector, the interface for which the "routing"
        view is registered::
        
          >>> IViewSelector.providedBy(herman)
          True
        
        The "routing" view is by convention called "index" and can be looked up
        as a basic view::
        
          >>> from zope.component import getMultiAdapter
          >>> index = getMultiAdapter((herman, request), name="index")
          >>> index
          <dolmen.app.viewselector.select.SelectedView...>
        
        This view, when rendered, will look up and render the view named as the
        `selected_view` attribute, registered for the same content and request::
        
          >>> herman.selected_view
          u'sleeping'
        
          >>> index.render()
          u'RRrrr...'
        
        If we set a different value for the `selected_view` attribute, the looked up
        view changes accordingly::
          
          >>> herman.selected_view = u"polarfur"
          >>> index.render()
          u"I'm white !"
        
          >>> herman.selected_view = u"springfur"
          >>> index.render()
          u"I'm brown !"
        
        If the view doesn't exist, a base message is returned::
        
          >>> herman.selected_view = u"nothing"
          >>> index.render()
          u'The selected view is not a valid IPage component.'
        
        
        Applying the view via the User interface
        ========================================
        
        The selected view can be chosen from a list of available alternative view.
        This choice is made via a menu, for which the views are registered.
        
        Menu
        ----
        
        Let's render the menu, to have a look at its structure.
        Before we can get a functional menu, which requires a located content, we need
        to persist our content in a functional site::
        
          >>> from zope.component.hooks import getSite
          >>> site = getSite()
        
          >>> herman = site['herman'] = herman
          >>> herman.__name__
          u'herman'
        
        The content located, we can instanciate the menu. The menu is handled by
        ``megrok.menu`` and is a ``zope.browsermenu.IBrowserMenu`` component.
        
        A viewlet is registered in order to render this menu is a conventional way::
        
          >>> baseview = Sleeping(herman, request)
        
          >>> from dolmen.app.layout.master import AboveBody
          >>> from dolmen.app.viewselector.select import SelectableViews
        
          >>> manager = AboveBody(herman, request, baseview)
          >>> menu = SelectableViews(herman, request, baseview, manager)
        
        The alternate views do use a security declaration and therefore, we need to
        login as a particular user, to test the rendering. Here, the `SpringFur`
        view requires the `dolmen.content.Edit` permission.
        
        Let's login as a used that doesn't have this permission granted::
        
          >>> login('zope.user')
        
        When rendering the menu, the `SpringFur` component will, therefore,
        be omitted::
        
          >>> menu.update()
          >>> print menu.render()
          <dl id="selectable-views" class="additional-actions">
            <dt>Content display</dt>
            <dd>
              <ul class="menu">
                <li class="entry">
            	  <a href="http://127.0.0.1/herman/viewselector?name=sleeping"
                     title="Sleeping bear">Sleeping bear</a>
             	</li>
               	<li class="entry">
            	  <a href="http://127.0.0.1/herman/viewselector?name=polarfur"
                     title="Polar bear">Polar bear</a>
        	</li>
              </ul>
            </dd>
          </dl>
        
          >>> logout()
        
        If we now log in with a user with the right permission granted, we see
        that the component is correctly included::
        
          >>> login('zope.mgr')
          >>> menu.update()
          >>> print menu.render()
          <dl id="selectable-views" class="additional-actions">
            <dt>Content display</dt>
            <dd>
              <ul class="menu">
                <li class="entry">
            	  <a href="http://127.0.0.1/herman/viewselector?name=sleeping"
                     title="Sleeping bear">Sleeping bear</a>
             	</li>
               	<li class="entry">
            	  <a href="http://127.0.0.1/herman/viewselector?name=polarfur"
                     title="Polar bear">Polar bear</a>
        	</li>
            	<li class="entry">
            	  <a href="http://127.0.0.1/herman/viewselector?name=springfur"
                     title="Spring bear">Spring bear</a>
            	</li>
              </ul>
            </dd>
          </dl>
        
          >>> logout()
        
        
        Apply
        -----
        
        The menu above exposes the view 'viewselector', registered for a 
        IViewSelector content. This view is the component that effectively
        changes the `selected_view` attribute to the clicked value.
        
        Let's simulate a click to test that view. The current value of the 
        `selected_view` attribute is inconsistant::
        
          >>> herman.selected_view
          u'nothing'
        
        We want it changed to something existing, like the `PolarFur` view::
        
          >>> request = TestRequest(form={'name': u'polarfur'})
          >>> handler = getMultiAdapter((herman, request), name="viewselector")
          >>> handler
          <dolmen.app.viewselector.select.ApplyView ...>
        
        Logged in as an admin user, we can apply the selected view::
        
          >>> login('zope.mgr', request)
          >>> handler()
          'http://127.0.0.1/herman'
        
        The view redirects you to the base view of the content. The value is
        now changed::
        
          >>> herman.selected_view
          u'polarfur'
        
        Changes
        =======
        
        0.2.1 (2010-05-31)
        ------------------
        
         - Fixed the egg dist, by removing the zip-safe flag.
        
        0.2 (2010-03-26)
        ----------------
        
         - Fixed missing MANIFEST.
        
        
        0.1 (2010-03-25)
        ----------------
        
         - Initial release.
        
Keywords: Grok Zope3 CMS Dolmen
Platform: Any
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Web Environment
Classifier: Framework :: Zope3
Classifier: Intended Audience :: Other Audience
Classifier: License :: OSI Approved :: GNU General Public License (GPL)
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
