[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