[Zope-CVS] CVS: Products/CompositePage - render.py:1.1 CHANGES.txt:1.2 interfaces.py:1.5 slot.py:1.11 slotdef.py:1.3 tool.py:1.7 transformers.py:1.7

Shane Hathaway shane at zope.com
Sat Dec 27 17:57:14 EST 2003


Update of /cvs-repository/Products/CompositePage
In directory cvs.zope.org:/tmp/cvs-serv20150

Modified Files:
	CHANGES.txt interfaces.py slot.py slotdef.py tool.py 
	transformers.py 
Added Files:
	render.py 
Log Message:
Add inline views (with an inline view selector) and tidied here and there.


=== Added File Products/CompositePage/render.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.  All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Adapters to IRenderableInline.

$Id: render.py,v 1.1 2003/12/27 22:56:43 shane Exp $
"""

import Acquisition
from Acquisition import aq_base, aq_inner, aq_parent, aq_get
from AccessControl.SecurityInfo import ClassSecurityInfo
from DocumentTemplate.DT_Util import safe_callable
from Globals import InitializeClass
from OFS.SimpleItem import SimpleItem

from interfaces import IRenderableInline, IAnnotations
import perm_names

try:
    from Products.References.Proxy import proxyReference
except ImportError:
    def proxyReference(obj):
        return None


class SimpleItemAnnotations:
    __implements__ = IAnnotations
    
    def __init__(self, ob):
        self.ob = ob

    def getAnnotation(self, name):
        """Returns an annotation by name or None.

        Looks in the reference (if there is one), then in the context object.
        """
        ref = proxyReference(self.ob)
        if ref is not None:
            anns = getattr(ref, "_annotations", None)
            if anns and anns.has_key(name):
                return anns[name]
        anns = getattr(self.ob, "_annotations", None)
        if anns:
            return anns.get(name)
        return None

    def setAnnotation(self, name, value):
        """Sets an annotation by name.

        Changes the reference if there is one; otherwise, changes context.
        """
        ob = proxyReference(self.ob)
        if ob is None:
            ob = self.ob
        ob._p_changed = 1
        if getattr(ob, "_annotations", None) is None:
            ob._annotations = {}
        ob._annotations[name] = value


class SimpleItemInlineRenderer(Acquisition.Implicit):
    __implements__ = IRenderableInline

    security = ClassSecurityInfo()

    security.declareProtected(perm_names.view, "renderInline")
    def renderInline(self):
        """Returns a string rendering of this object.
        """
        ob = aq_parent(aq_inner(self))
        anns = adapt(ob, IAnnotations)
        name = anns.getAnnotation("inline_view")
        if not name:
            # Default to the first allowable inline view.
            names = self.listAllowableInlineViews()
            if names:
                name = names[0]
        if name != "call":
            view = ob.restrictedTraverse(name)
            return view()
        # Special view name "call" means to call the object.
        if safe_callable(ob):
            return ob()
        return str(ob)

    security.declareProtected(perm_names.view, "getInlineView")
    def getInlineView(self):
        """Returns the name of the inline view this object uses.
        """
        ob = aq_parent(aq_inner(self))
        anns = adapt(ob, IAnnotations)
        return anns.getAnnotation("inline_view")

    security.declareProtected(perm_names.change_composites, "setInlineView")
    def setInlineView(self, name):
        """Sets the inline view for this object.
        """
        name = str(name)
        ob = aq_parent(aq_inner(self))
        anns = adapt(ob, IAnnotations)
        anns.setAnnotation("inline_view", name)

    security.declareProtected(perm_names.change_composites,
                              "listAllowableInlineViews")
    def listAllowableInlineViews(self):
        """Returns a list of view names allowable for this object.
        """
        ob = aq_parent(aq_inner(self))
        if hasattr(aq_base(ob), "getTypeInfo"):
            ti = ob.getTypeInfo()
            if hasattr(aq_base(ti), "inline_views"):
                res = ti.inline_views
                if res:
                    return res
        tool = aq_get(self, "composite_tool", None, 1)
        if tool is not None:
            return tool.default_inline_views
        # No tool found, so no inline views are known.
        return ()

InitializeClass(SimpleItemInlineRenderer)


renderer_factory = SimpleItemInlineRenderer().__of__

def adapt(ob, iface):
    # This is a simple substitute for adapter lookup.
    if iface.isImplementedBy(ob):
        return ob
    if isinstance(ob, SimpleItem):
        if iface is IRenderableInline:
            return renderer_factory(ob)
        if iface is IAnnotations:
            return SimpleItemAnnotations(ob)
    raise LookupError("No adapter found")



=== Products/CompositePage/CHANGES.txt 1.1 => 1.2 ===
--- Products/CompositePage/CHANGES.txt:1.1	Wed Oct  8 10:51:12 2003
+++ Products/CompositePage/CHANGES.txt	Sat Dec 27 17:56:43 2003
@@ -1,6 +1,12 @@
 
 Next version after 0.1
 
+  - Changed the UI to use images for elements and targets.
+
+  - Added inline views.  You can now select templates to render objects.
+
+  - Context menus now have headers.
+
   - You can now define slots in a template using standard METAL syntax.
     This should make it easier to write templates.
 


=== Products/CompositePage/interfaces.py 1.4 => 1.5 ===
--- Products/CompositePage/interfaces.py:1.4	Sat Dec 27 13:40:19 2003
+++ Products/CompositePage/interfaces.py	Sat Dec 27 17:56:43 2003
@@ -70,19 +70,32 @@
     """Interface of objects that can be rendered inline (as page elements).
     """
 
-    def renderInline(self):
-        """Returns a string rendering of this object.
+    def renderInline():
+        """Returns a representation of this object as a string.
         """
 
-    def getInlineView(self):
+    def getInlineView():
         """Returns the name of the inline view this object uses.
         """
 
-    def setInlineView(self, view):
+    def setInlineView(view):
         """Sets the inline view for this object.
         """
 
     def listAllowableInlineViews():
-        """Returns a list of view names allowable for this object.
+        """Returns a list of inline view names allowable for this object.
+        """
+
+
+class IAnnotations(Interface):
+    """Collection of annotations for an object.
+    """
+
+    def getAnnotation(name):
+        """Returns an annotation by name.
+        """
+
+    def setAnnotation(name, value):
+        """Sets an annotation by name.
         """
 


=== Products/CompositePage/slot.py 1.10 => 1.11 ===
--- Products/CompositePage/slot.py:1.10	Sat Dec 27 13:40:19 2003
+++ Products/CompositePage/slot.py	Sat Dec 27 17:56:43 2003
@@ -25,11 +25,14 @@
 from Acquisition import aq_base, aq_inner, aq_parent
 from ZODB.POSException import ConflictError
 from OFS.SimpleItem import SimpleItem
-from DocumentTemplate.DT_Util import safe_callable
 from Products.PageTemplates.PageTemplateFile import PageTemplateFile
 from AccessControl import ClassSecurityInfo
 from zLOG import LOG, ERROR
 
+from interfaces import IRenderableInline
+from render import adapt
+
+
 try:
     # Use OrderedFolder if it's available.
     from OFS.OrderedFolder import OrderedFolder
@@ -43,16 +46,16 @@
 _www = os.path.join(os.path.dirname(__file__), "www")
 
 
-TARGET_TAG = '''<div class="slot_target" title="Slot: %s [%d]"
+target_tag = '''<div class="slot_target" title="Slot: %s [%d]"
 target_path="%s" target_index="%d"></div>'''
 
-EDIT_TAG = '''<div class="slot_element" source_path="%s" icon="%s" title="%s">
+edit_tag = '''<div class="slot_element" source_path="%s" icon="%s" title="%s">
 %s
 </div>'''
 
 # VIEW_TAG includes a <div> just to ensure that the element is
 # rendered as an HTML block in both editing mode and view mode.
-VIEW_TAG = '''<div>
+view_tag = '''<div>
 %s
 </div>'''
 
@@ -142,16 +145,11 @@
             name, obj = items[index]
 
             if editing and allow_add:
-                tag = TARGET_TAG % (myid, index, mypath, index)
-                res.append(tag)
+                res.append(target_tag % (myid, index, mypath, index))
 
             try:
-                if hasattr(aq_base(obj), "render_inline"):
-                    text = obj.render_inline()
-                elif safe_callable(obj):
-                    text = obj()
-                else:
-                    text = str(obj)
+                o = adapt(obj, IRenderableInline)
+                text = o.renderInline()
             except ConflictError:
                 # Ugly ZODB requirement: don't catch ConflictErrors
                 raise
@@ -186,15 +184,14 @@
 
                 title = obj.title_and_id()
                 path = escape('/'.join(obj.getPhysicalPath()))
-                res.append(EDIT_TAG % (path,
+                res.append(edit_tag % (path,
                                        escape(icon), escape(title), text))
             else:
-                res.append(VIEW_TAG % text)
+                res.append(view_tag % text)
 
         if editing and allow_add:
             index = len(items)
-            tag = TARGET_TAG % (myid, index, mypath, index)
-            res.append(tag)
+            res.append(target_tag % (myid, index, mypath, index))
 
         return res
 
@@ -218,4 +215,3 @@
     dispatcher.this().generateSlots()
     if REQUEST is not None:
         return dispatcher.manage_main(dispatcher, REQUEST)
-    


=== Products/CompositePage/slotdef.py 1.2 => 1.3 ===
--- Products/CompositePage/slotdef.py:1.2	Sat Dec 27 13:40:19 2003
+++ Products/CompositePage/slotdef.py	Sat Dec 27 17:56:43 2003
@@ -34,7 +34,6 @@
     __implements__ = ISlotDefinition
     meta_type = "Composite Slot Definition"
     find_script = ""
-    inline_views = ()
 
     manage_options = (PropertyManager.manage_options
                       + SimpleItem.manage_options)
@@ -42,8 +41,6 @@
     _properties = (
         {'id': 'find_script', 'mode': 'w', 'type': 'string',
          'label': 'Script that finds available elements',},
-        {'id': 'inline_views', 'mode': 'w', 'type': 'lines',
-         'label': 'Allowable inline view names',},
         )
 
     def findAvailableElements(self, slot):


=== Products/CompositePage/tool.py 1.6 => 1.7 ===
--- Products/CompositePage/tool.py:1.6	Sat Dec 27 13:40:19 2003
+++ Products/CompositePage/tool.py	Sat Dec 27 17:56:43 2003
@@ -23,7 +23,9 @@
 from AccessControl import ClassSecurityInfo
 from AccessControl.ZopeGuards import guarded_getattr
 
-from interfaces import ISlot, ISlotDefinition, CompositeError
+from interfaces import ISlot, ISlotDefinition, IRenderableInline
+from interfaces import CompositeError
+from render import adapt
 
 
 _transformers = {}
@@ -74,6 +76,13 @@
     security.declarePublic("transformers")
     transformers = Transformers("transformers")
 
+    _properties = Folder._properties + (
+        {'id': 'default_inline_views', 'mode': 'w', 'type': 'lines',
+         'label': 'Default inline view names',},
+        )
+
+    default_inline_views = ()
+
     _check_security = 1  # Turned off in unit tests
 
     def __init__(self):
@@ -203,6 +212,11 @@
         if REQUEST is not None:
             # Return to the page the user was looking at.
             REQUEST["RESPONSE"].redirect(REQUEST["HTTP_REFERER"])
+
+
+    security.declarePublic("getRendererFor")
+    def getRendererFor(self, ob):
+        return adapt(ob, IRenderableInline)
 
 Globals.InitializeClass(CompositeTool)
 


=== Products/CompositePage/transformers.py 1.6 => 1.7 ===
--- Products/CompositePage/transformers.py:1.6	Mon Dec 22 15:21:14 2003
+++ Products/CompositePage/transformers.py	Sat Dec 27 17:56:43 2003
@@ -37,7 +37,7 @@
 start_of_body_search = re.compile("(<body[^>]*>)", re.IGNORECASE).search
 end_of_body_search = re.compile("(</body[^>]*>)", re.IGNORECASE).search
 
-DEFAULT_HTML_PAGE = """
+default_html_page = """
 <html>
 <head>
 <title>Composite Page</title>
@@ -48,6 +48,16 @@
 </html>
 """
 
+close_dialog_html = '''
+<html>
+<script type="text/javascript">
+if (window.opener)
+  window.opener.location.reload();
+window.close();
+</script>
+</html>
+'''
+
 
 class CommonTransformer (SimpleItem):
     """Basic page transformer.
@@ -74,6 +84,8 @@
     top_templates = ()
     bottom_templates = (PageTemplateFile("bottom.pt", _common),)
 
+    changeViewForm = PageTemplateFile("changeViewForm.pt", _common)
+
     workspace_view_name = ""  # To be overridden
 
     security.declarePublic("transform")
@@ -98,7 +110,7 @@
         match = start_of_head_search(text)
         if match is None:
             # Turn it into a page.
-            text = DEFAULT_HTML_PAGE % text
+            text = default_html_page % text
             match = start_of_head_search(text)
             if match is None:
                 raise CompositeError("Could not find header")
@@ -155,6 +167,60 @@
                 gen()
         RESPONSE.redirect("%s/%s" % (
             obj.absolute_url(), self.workspace_view_name))
+
+
+    security.declarePublic("getViewChangeInfo")
+    def getViewChangeInfo(self, paths):
+        """Returns information for changing the view applied to objects.
+        """
+        root = self.getPhysicalRoot()
+        tool = aq_parent(aq_inner(self))
+        obs = []
+        all_choices = None  # {view -> 1}
+        current = None
+        for path in paths.split(':'):
+            ob = root.restrictedTraverse(path)
+            obs.append(ob)
+            renderer = tool.getRendererFor(ob)
+            m = guarded_getattr(renderer, "getInlineView")
+            view = m()
+            if current is None:
+                current = view
+            elif current and current != view:
+                # The current view isn't the same for all of the elements,
+                # so there is no common current view.  Spell this condition
+                # using a non-string value.
+                current = 0
+            m = guarded_getattr(renderer, "listAllowableInlineViews")
+            views = m()
+            d = {}
+            for view in views:
+                d[view] = 1
+            if all_choices is None:
+                all_choices = d
+            else:
+                for view in all_choices.keys():
+                    if not d.has_key(view):
+                        del all_choices[view]
+        views = all_choices.keys()
+        views.sort()
+        return {"obs": obs, "views": views, "current_view": current}
+
+
+    security.declarePublic("changeView")
+    def changeView(self, paths, view, REQUEST=None):
+        """Changes the view for objects.
+        """
+        info = self.getViewChangeInfo(paths)
+        if view not in info["views"]:
+            raise KeyError("View %s is not among the choices" % view)
+        tool = aq_parent(aq_inner(self))
+        for ob in info["obs"]:
+            renderer = tool.getRendererFor(ob)
+            m = guarded_getattr(renderer, "setInlineView")
+            m(view)
+        if REQUEST is not None:
+            return close_dialog_html
 
 Globals.InitializeClass(CommonTransformer)
 




More information about the Zope-CVS mailing list