[Zope-CVS] CVS: Products/CompositePage - __init__.py:1.1
composite.py:1.1 interfaces.py:1.1 rawfile.py:1.1 slot.py:1.1
tool.py:1.1 transformers.py:1.1
Shane Hathaway
shane at zope.com
Fri Sep 26 17:21:06 EDT 2003
Update of /cvs-repository/Products/CompositePage
In directory cvs.zope.org:/tmp/cvs-serv25375
Added Files:
__init__.py composite.py interfaces.py rawfile.py slot.py
tool.py transformers.py
Log Message:
Added the CompositePage product.
CompositePage is like the PageDesign product, but simplified, and now based
on PDLib, a Javascript drag and drop / context menu library.
=== Added File Products/CompositePage/__init__.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.
#
##############################################################################
"""CompositePage product initialization.
$Id: __init__.py,v 1.1 2003/09/26 21:21:05 shane Exp $
"""
import tool, composite, slot, transformers
def initialize(context):
tool.registerTransformer("common", transformers.CommonTransformer())
tool.registerTransformer("zmi", transformers.ZMITransformer())
context.registerClass(
tool.CompositeTool,
constructors=(tool.manage_addCompositeTool,),
icon="www/comptool.gif",
)
context.registerClass(
composite.Composite,
constructors=(composite.addCompositeForm,
composite.manage_addComposite,
),
icon="www/composite.gif",
)
context.registerClass(
slot.Slot,
constructors=(slot.addSlotForm,
slot.manage_addSlot,
slot.manage_generateSlots,
),
visibility=None,
)
=== Added File Products/CompositePage/composite.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.
#
##############################################################################
"""Composite class and supporting code.
$Id: composite.py,v 1.1 2003/09/26 21:21:05 shane Exp $
"""
import os
import re
import Globals
import Acquisition
from Acquisition import aq_base, aq_inner, aq_parent, aq_get
from OFS.Folder import Folder
from Products.PageTemplates.PageTemplateFile import PageTemplateFile
from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate
from AccessControl import ClassSecurityInfo
from AccessControl.ZopeGuards import guarded_getattr
from interfaces import ISlot, CompositeError
from slot import Slot
_www = os.path.join(os.path.dirname(__file__), "www")
class SlotGenerator (Acquisition.Explicit):
"""Automatically makes slots available to the template.
"""
def __getitem__(self, name):
composite = aq_parent(aq_inner(self))
slots = composite.filled_slots
try:
return slots[name]
except (KeyError, AttributeError):
# Generate a new slot.
s = Slot(name)
if composite._v_generating:
# Persist the slot immediately.
slots._setObject(s.getId(), s)
else:
# Persist automatically if the slot changes
jar = AddOnChangeJar(slots)
s._p_jar = jar
return s.__of__(slots)
class Composite(Folder):
"""An HTML fragment composed from a template and fragments.
"""
meta_type = "Composite"
security = ClassSecurityInfo()
manage_options = (
Folder.manage_options[:1]
+ ({"label": "Design", "action": "manage_designForm",},
{"label": "View", "action": "view",},)
+ Folder.manage_options[2:]
)
template_path = "template"
_v_editing = 0
_v_rendering = 0
_v_generating = 0
security.declarePublic("slots")
slots = SlotGenerator()
_properties = Folder._properties + (
{"id": "template_path", "mode": "w", "type": "string",
"label": "Path to template"},
)
def __init__(self):
f = SlotCollection()
f._setId("filled_slots")
self._setObject(f.getId(), f)
def getTemplate(self):
return self.restrictedTraverse(self.template_path)
def generateSlots(self):
"""Creates the slots defined by the template.
"""
self._v_generating = 1
try:
self()
finally:
self._v_generating = 0
def __call__(self):
"""Renders the composite.
"""
if self._v_rendering:
raise CompositeError("Circular composite reference")
self._v_rendering = 1
try:
template = self.getTemplate()
return template()
finally:
self._v_rendering = 0
view = __call__
index_html = None
def design(self, transformer="common"):
"""Renders the composite with editing features.
"""
tool = aq_get(self, "composite_tool", None, 1)
if tool is None:
raise CompositeError("No composite_tool found")
# Never cache a design view.
req = getattr(self, "REQUEST", None)
if req is not None:
req["RESPONSE"].setHeader("Cache-Control", "no-cache")
self._v_editing = 1
try:
text = self()
finally:
self._v_editing = 0
tf = guarded_getattr(tool.transformers, transformer)
return tf.transform(self, text)
def manage_designForm(self):
"""Renders the composite with editing and ZMI features.
"""
return self.design("zmi")
def isEditing(self):
return self._v_editing
Globals.InitializeClass(Composite)
class SlotCollection(Folder):
"""Collection of composite slots.
"""
meta_type = "Slot Collection"
def all_meta_types(self):
return Folder.all_meta_types(self, interfaces=(ISlot,))
class AddOnChangeJar:
"""Adds an object to a folder if the object changes.
"""
def __init__(self, parent):
self.parent = parent
def register(self, obj):
obj._p_jar = None
self.parent._setObject(obj.getId(), obj)
addCompositeForm = PageTemplateFile("addCompositeForm", _www)
def manage_addComposite(dispatcher, id, title="", create_sample=0,
REQUEST=None):
"""Adds a composite to a folder.
"""
ob = Composite()
ob._setId(id)
ob.title = string(title)
dispatcher._setObject(ob.getId(), ob)
if create_sample:
ob = dispatcher.this()._getOb(ob.getId())
f = open(os.path.join(_www, "sample_template.zpt"), "rt")
try:
text = f.read()
finally:
f.close()
pt = ZopePageTemplate(id="template", text=text,
content_type="text/html")
ob._setObject(pt.getId(), pt)
if REQUEST is not None:
return dispatcher.manage_main(dispatcher, REQUEST)
def string(s):
"""Ensures an object is either a string or a unicode.
"""
try:
return str(s)
except UnicodeEncodeError:
return unicode(s)
=== Added File Products/CompositePage/interfaces.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.
#
##############################################################################
"""Interfaces and exceptions in the CompositePage product.
$Id: interfaces.py,v 1.1 2003/09/26 21:21:05 shane Exp $
"""
from Interface import Interface
class ISlot(Interface):
"""A slot in a composite.
"""
class CompositeError(Exception):
"""An error in constructing a composite
"""
=== Added File Products/CompositePage/rawfile.py ===
##############################################################################
#
# Copyright (c) 2002 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.
#
##############################################################################
"""Binary data that is stored in a file.
$Id: rawfile.py,v 1.1 2003/09/26 21:21:05 shane Exp $
"""
import os
from os import stat
from time import time
import Acquisition
import Globals
from Globals import package_home
from App.Common import rfc1123_date
from DateTime import DateTime
class RawFile(Acquisition.Explicit):
"""Binary data stored in external files."""
def __init__(self, path, content_type, _prefix=None):
if _prefix is None:
_prefix = SOFTWARE_HOME
elif type(_prefix) is not type(''):
_prefix = package_home(_prefix)
path = os.path.join(_prefix, path)
self.path = path
if Globals.DevelopmentMode:
# In development mode, a shorter time is handy
max_age = 60 # One minute
else:
# A longer time reduces latency in production mode
max_age = 3600 # One hour
self.cch = 'public,max-age=%d' % max_age
file = open(path, 'rb')
data = file.read()
file.close()
self.content_type = content_type
self.__name__ = path.split('/')[-1]
self.lmt = float(stat(path)[8]) or time()
self.lmh = rfc1123_date(self.lmt)
def __call__(self, REQUEST=None, RESPONSE=None):
"""Default rendering"""
# HTTP If-Modified-Since header handling. This is duplicated
# from OFS.Image.Image - it really should be consolidated
# somewhere...
if RESPONSE is not None:
RESPONSE.setHeader('Content-Type', self.content_type)
RESPONSE.setHeader('Last-Modified', self.lmh)
RESPONSE.setHeader('Cache-Control', self.cch)
if REQUEST is not None:
header = REQUEST.get_header('If-Modified-Since', None)
if header is not None:
header = header.split(';')[0]
# Some proxies seem to send invalid date strings for this
# header. If the date string is not valid, we ignore it
# rather than raise an error to be generally consistent
# with common servers such as Apache (which can usually
# understand the screwy date string as a lucky side effect
# of the way they parse it).
try:
mod_since = long(DateTime(header).timeTime())
except:
mod_since = None
if mod_since is not None:
if getattr(self, 'lmt', None):
last_mod = long(self.lmt)
else:
last_mod = long(0)
if last_mod > 0 and last_mod <= mod_since:
RESPONSE.setStatus(304)
return ''
f = open(self.path, 'rb')
data = f.read()
f.close()
return data
index_html = None # Tells ZPublisher to use __call__
HEAD__roles__ = None
def HEAD(self, REQUEST, RESPONSE):
""" """
RESPONSE.setHeader('Content-Type', self.content_type)
RESPONSE.setHeader('Last-Modified', self.lmh)
return ''
=== Added File Products/CompositePage/slot.py ===
##############################################################################
#
# Copyright (c) 2002 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.
#
##############################################################################
"""Slot class and supporting code.
$Id: slot.py,v 1.1 2003/09/26 21:21:05 shane Exp $
"""
import os
import sys
from cgi import escape
from Acquisition import aq_base, aq_inner, aq_parent
from ZODB.POSException import ConflictError
from OFS.SimpleItem import SimpleItem
from OFS.OrderedFolder import OrderedFolder
from DocumentTemplate.DT_Util import safe_callable
from Products.PageTemplates.PageTemplateFile import PageTemplateFile
from interfaces import ISlot
_www = os.path.join(os.path.dirname(__file__), "www")
class NullElement(SimpleItem):
"""Temporary slot content
"""
meta_type = "Temporary Null Page Element"
def __init__(self, id):
self.id = id
class Slot (OrderedFolder):
"""A slot in a composite.
"""
meta_type = "Composite Slot"
__implements__ = ISlot, OrderedFolder.__implements__
null_element = NullElement("null_element")
def __init__(self, id):
self.id = id
def single(self):
"""Renders as a single-element slot."""
allow_add = (not self._objects)
return "".join(self.renderToList(allow_add))
def multiple(self):
return self.renderToList(1)
def reorder(self, name, new_index):
if name not in self.objectIds():
raise KeyError, name
objs = [info for info in self._objects if info['id'] != name]
objs.insert(new_index,
{'id': name, 'meta_type': getattr(self, name).meta_type})
self._objects = tuple(objs)
def nullify(self, name):
res = self[name]
objs = list(self._objects)
# Replace the item with a pointer to the null element.
for info in objs:
if info["id"] == name:
info["id"] = "null_element"
delattr(self, name)
return res
def pack(self):
objs = [info for info in self._objects if info["id"] != "null_element"]
self._objects = tuple(objs)
def renderToList(self, allow_add):
"""Renders the items to a list.
"""
res = []
composite = aq_parent(aq_inner(aq_parent(aq_inner(self))))
editing = composite.isEditing()
items = self.objectItems()
if editing:
mypath = escape('/'.join(self.getPhysicalPath()))
for index in range(len(items)):
name, obj = items[index]
if editing and allow_add:
tag = ('<div class="slot_target" target_path="%s" '
'target_index="%d"></div>' % (mypath, index))
res.append(tag)
try:
if safe_callable(obj):
text = obj()
else:
text = str(obj)
except ConflictError:
# Ugly ZODB requirement: don't catch ConflictErrors
raise
except:
t, v = sys.exc_info()[:2]
t = getattr(t, '__name__', t)
text = "<code>%s</code>" % (
escape(('%s: %s' % (t, v))[:80]))
if editing:
path = escape('/'.join(obj.getPhysicalPath()))
tag = '<div class="slot_element" source_path="%s">' % path
else:
# Output a <div> just to ensure that the element
# is rendered as an HTML block in both editing mode
# and rendering mode.
tag = "<div>"
res.append("%s\n%s\n</div>" % (tag, text))
if editing and allow_add:
index = len(items)
tag = ('<div class="slot_target" target_path="%s" '
'target_index="%d"></div>' % (mypath, index))
res.append(tag)
return res
addSlotForm = PageTemplateFile("addSlotForm", _www)
def manage_addSlot(dispatcher, id, REQUEST=None):
"""Adds a slot to a composite.
"""
ob = Slot(id)
dispatcher._setObject(ob.getId(), ob)
if REQUEST is not None:
return dispatcher.manage_main(dispatcher, REQUEST)
def manage_generateSlots(dispatcher, REQUEST=None):
"""Adds all slots requested by a template to a composite.
"""
dispatcher.this().generateSlots()
if REQUEST is not None:
return dispatcher.manage_main(dispatcher, REQUEST)
=== Added File Products/CompositePage/tool.py ===
##############################################################################
#
# Copyright (c) 2002 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.
#
##############################################################################
"""Composite tool.
$Id: tool.py,v 1.1 2003/09/26 21:21:05 shane Exp $
"""
import Globals
from Acquisition import aq_base, aq_parent, aq_inner
from OFS.SimpleItem import SimpleItem
from AccessControl import ClassSecurityInfo
from interfaces import ISlot, CompositeError
_transformers = {}
def registerTransformer(name, obj):
"""Registers a transformer for use with the composite tool.
"""
if _transformers.has_key(name):
raise RuntimeError("There is already a transformer named %s" % name)
obj._setId(name)
_transformers[name] = obj
class Transformers(SimpleItem):
"""Makes page transformers accessible through URL traversal.
"""
def __init__(self, id):
self._setId(id)
def __getattr__(self, name):
try:
return _transformers[name]
except KeyError:
raise AttributeError, name
class CompositeTool(SimpleItem):
"""Page composition helper tool.
"""
meta_type = "Composite Tool"
id = "composite_tool"
security = ClassSecurityInfo()
security.declarePublic("transformers")
transformers = Transformers("transformers")
security.declarePublic("moveElements")
def moveElements(self, source_paths, target_path, target_index):
"""Moves elements to a slot.
"""
target_index = int(target_index)
# Coerce the paths to sequences of path elements.
if hasattr(target_path, "split"):
target_path = target_path.split('/')
sources = []
for p in source_paths:
if hasattr(p, "split"):
p = p.split('/')
if p:
sources.append(p)
# Ignore descendants when an ancestor is already listed.
i = 1
sources.sort()
while i < len(sources):
prev = sources[i - 1]
if sources[i][:len(prev)] == prev:
del sources[i]
else:
i = i + 1
# Prevent parents from becoming their own descendants.
for source in sources:
if target_path[:len(source)] == source:
raise CompositeError(
"Can't make an object a descendant of itself")
# Gather the sources, replacing with nulls to avoid changing
# indexes while moving.
root = self.getPhysicalRoot()
orig_slots = {} # id(aq_base(slot)) -> slot
elements = []
try:
for source in sources:
slot = root.restrictedTraverse(source[:-1])
assert ISlot.isImplementedBy(slot), repr(slot)
slot_id = id(aq_base(slot))
if not orig_slots.has_key(slot_id):
orig_slots[slot_id] = slot
# validate(slot, "nullify")
element = slot.nullify(source[-1])
elements.append(element)
# Add the elements and reorder.
slot = root.restrictedTraverse(target_path)
assert ISlot.isImplementedBy(slot), repr(slot)
for element in elements:
# verifyObjectPaste(element, container=slot)
new_id = slot._get_id(element.getId())
element._setId(new_id)
slot._setObject(new_id, element)
slot.reorder(new_id, target_index)
target_index += 1
finally:
# Clear the nulls just added.
for slot in orig_slots.values():
slot.pack()
security.declarePublic("deleteElements")
def deleteElements(self, source_paths):
sources = []
for p in source_paths:
if hasattr(p, "split"):
p = p.split('/')
if p:
sources.append(p)
# Replace with nulls to avoid changing indexes while deleting.
orig_slots = {}
try:
for source in sources:
slot = self.restrictedTraverse(source[:-1])
assert ISlot.isImplementedBy(slot), repr(slot)
slot_id = id(aq_base(slot))
if not orig_slots.has_key(slot_id):
orig_slots[slot_id] = slot
# validate(slot, "nullify")
slot.nullify(source[-1])
finally:
# Clear the nulls just added.
for slot in orig_slots.values():
slot.pack()
security.declarePublic("moveAndDelete")
def moveAndDelete(self, move_source_paths="", move_target_path="",
move_target_index="", delete_source_paths="",
REQUEST=None):
"""Move and delete elements.
"""
if move_source_paths:
p = move_source_paths.split(':')
self.moveElements(p, move_target_path, int(move_target_index))
if delete_source_paths:
p = delete_source_paths.split(':')
self.deleteElements(p)
if REQUEST is not None:
# Return to the page the user was looking at.
REQUEST["RESPONSE"].redirect(REQUEST["HTTP_REFERER"])
Globals.InitializeClass(CompositeTool)
def manage_addCompositeTool(dispatcher, REQUEST=None):
"""Adds a composite tool to a folder.
"""
ob = CompositeTool()
dispatcher._setObject(ob.getId(), ob)
if REQUEST is not None:
return dispatcher.manage_main(dispatcher, REQUEST)
=== Added File Products/CompositePage/transformers.py ===
##############################################################################
#
# Copyright (c) 2002 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.
#
##############################################################################
"""Editable page transformation classes.
$Id: transformers.py,v 1.1 2003/09/26 21:21:05 shane Exp $
"""
import os
import re
import Globals
from Acquisition import aq_base, aq_inner, aq_parent
from OFS.SimpleItem import SimpleItem
from Products.PageTemplates.PageTemplateFile import PageTemplateFile
from AccessControl import ClassSecurityInfo
from rawfile import RawFile
_common = os.path.join(os.path.dirname(__file__), "common")
_zmi = os.path.join(os.path.dirname(__file__), "zmi")
start_of_head_search = re.compile("(<head[^>]*>)", re.IGNORECASE).search
start_of_body_search = re.compile("(<body[^>]*>)", re.IGNORECASE).search
end_of_body_search = re.compile("(</body[^>]*>)", re.IGNORECASE).search
DEFAULT_HTML_PAGE = """
<html>
<head>
<title>Composite Page</title>
</head>
<body>
%s
</body>
</html>
"""
class CommonTransformer (SimpleItem):
"""Basic page transformer.
Adds editing features to a rendered composite.
"""
security = ClassSecurityInfo()
security.declarePublic(
"pdlib_js", "design_js", "pdstyles_css", "designstyles_css",
"transform")
pdlib_js = RawFile("pdlib.js", "text/javascript", _common)
edit_js = RawFile("edit.js", "text/javascript", _common)
pdstyles_css = RawFile("pdstyles.css", "text/css", _common)
editstyles_css = RawFile("editstyles.css", "text/css", _common)
header_templates = (PageTemplateFile("header.pt", _common),)
top_templates = ()
bottom_templates = (PageTemplateFile("bottom.pt", _common),)
def transform(self, composite, text):
"""Adds scripts to a rendered composite.
"""
params = {
"tool": aq_parent(aq_inner(self)),
"transformer": self,
"composite": composite,
}
header = ""
top = ""
bottom = ""
for t in self.header_templates:
header += t.__of__(self)(**params)
for t in self.top_templates:
top += t.__of__(self)(**params)
for t in self.bottom_templates:
bottom += t.__of__(self)(**params)
match = start_of_head_search(text)
if match is None:
# Turn it into a page.
text = DEFAULT_HTML_PAGE % text
match = start_of_head_search(text)
if match is None:
raise CompositeError("Could not find header")
if header:
index = match.end(0)
text = "%s%s%s" % (text[:index], header, text[index:])
if top:
match = start_of_body_search(text)
if match is None:
raise CompositeError("No 'body' tag found")
index = match.end(0)
text = "%s%s%s" % (text[:index], top, text[index:])
if bottom:
match = end_of_body_search(text)
if match is None:
raise CompositeError("No 'body' end tag found")
m = match
while m is not None:
# Find the *last* occurrence of "</body>".
match = m
m = end_of_body_search(text, match.end(0))
index = match.start(0)
text = "%s%s%s" % (text[:index], bottom, text[index:])
return text
Globals.InitializeClass(CommonTransformer)
class ZMITransformer (CommonTransformer):
"""Zope management interface page transformer.
Adds editing features to a rendered composite.
"""
security = ClassSecurityInfo()
security.declarePublic("zmi_edit_js")
zmi_edit_js = RawFile("zmi_edit.js", "text/javascript", _zmi)
header_templates = CommonTransformer.header_templates + (
PageTemplateFile("header.pt", _zmi),)
top_templates = CommonTransformer.top_templates + (
PageTemplateFile("top.pt", _zmi),)
bottom_templates = (PageTemplateFile("bottom.pt", _zmi),
) + CommonTransformer.bottom_templates
def showElement(self, path, RESPONSE):
"""Redirects to the workspace for an element.
"""
root = self.getPhysicalRoot()
obj = root.restrictedTraverse(path)
RESPONSE.redirect(obj.absolute_url() + "/manage_workspace")
def showSlot(self, path, RESPONSE):
"""Redirects to (and possibly creates) the workspace for a slot.
"""
from composite import Composite
obj = self.getPhysicalRoot()
parts = path.split('/')
for name in parts:
obj = obj.restrictedTraverse(name)
try:
is_comp = isinstance(obj, Composite)
except TypeError:
is_comp = 0 # Python 2.1 bug
if is_comp:
obj.generateSlots()
RESPONSE.redirect(obj.absolute_url() + "/manage_workspace")
Globals.InitializeClass(ZMITransformer)
More information about the Zope-CVS
mailing list