[Zope-CVS] CVS: Products/PageDesign - ReferencedElement.py:1.2 utils.py:1.2 IIndexedSlot.py:1.2 IPageElement.py:1.2 ISlotProvider.py:1.2 PageDesign.py:1.3 RawFile.py:1.2 Slot.py:1.2 SlotElementClipboardSource.py:1.2 SlotElementClipboardTarget.py:1.2 SlotElementTraverser.py:1.2 SlotProvider.py:1.2 zopetop_design.zexp:1.2
Shane Hathaway
shane@cvs.zope.org
Mon, 12 Aug 2002 10:39:59 -0400
Update of /cvs-repository/Products/PageDesign
In directory cvs.zope.org:/tmp/cvs-serv8780
Modified Files:
IIndexedSlot.py IPageElement.py ISlotProvider.py PageDesign.py
RawFile.py Slot.py SlotElementClipboardSource.py
SlotElementClipboardTarget.py SlotElementTraverser.py
SlotProvider.py zopetop_design.zexp
Added Files:
ReferencedElement.py utils.py
Log Message:
Merged page-redesign-branch. This is almost ready to try out.
=== Products/PageDesign/ReferencedElement.py 1.1 => 1.2 ===
--- /dev/null Mon Aug 12 10:39:59 2002
+++ Products/PageDesign/ReferencedElement.py Mon Aug 12 10:39:29 2002
@@ -0,0 +1,95 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+
+import Acquisition
+from Acquisition import aq_base, aq_get, aq_inner, aq_parent
+from Persistence import Persistent
+from OFS.Traversable import Traversable
+from OFS.Application import Application
+
+from IPageElement import IPageElement
+
+
+class ReferencedElement (Persistent, Acquisition.Explicit, Traversable):
+
+ __implements__ = IPageElement
+
+ def __init__(self, ob):
+ self._path = ob.getPhysicalPath()
+
+ def _deref(self):
+ root = self.getPhysicalRoot()
+ return root.restrictedTraverse(self._path)
+
+ def render(self, design, editable, index):
+ """Returns a string.
+ """
+ ob = self._deref()
+ if getattr(aq_base(ob), 'isDocTemp', 0):
+ # DTML
+ s = ob(self, aq_get(self, 'REQUEST'),
+ editable=editable, index=index)
+ elif hasattr(ob, '__call__'):
+ # Other kinds of callable objects
+ s = ob(editable=editable, index=index)
+ else:
+ s = str(ob)
+ return s
+
+ def getIconURL(self):
+ """Returns an URL to an icon for this element if available.
+ """
+ ob = self._deref()
+ icon = None
+ if hasattr(aq_base(ob), 'getIcon'):
+ icon = ob.getIcon()
+ elif hasattr(aq_base(ob), 'icon'):
+ icon = ob.icon
+ if icon:
+ return '/' + icon
+ else:
+ return ''
+
+ def getTitle(self):
+ """Returns the title of this element.
+ """
+ ob = self._deref()
+ # It's altogether silly to have to look at four attributes. :-)
+ if hasattr(aq_base(ob), 'Title'):
+ s = ob.Title()
+ else:
+ s = getattr(ob, 'title', '')
+ if s:
+ return str(s)
+ if hasattr(aq_base(ob), 'getId'):
+ return ob.getId()
+ return str(ob.id)
+
+ def getEditURL(self):
+ """Returns the URL for editing this element.
+
+ Returns None or a blank string if it is not editable.
+ """
+ if hasattr(Application, 'externalEdit_'):
+ ob = self._deref()
+ folder = aq_parent(aq_inner(ob))
+ if hasattr(aq_base(ob), 'getId'):
+ id = ob.getId()
+ else:
+ id = str(ob.id)
+
+ url = '%s/externalEdit_/%s' % (folder.absolute_url(), id)
+ return url
+ return None
+
=== Products/PageDesign/utils.py 1.1 => 1.2 ===
--- /dev/null Mon Aug 12 10:39:59 2002
+++ Products/PageDesign/utils.py Mon Aug 12 10:39:29 2002
@@ -0,0 +1,28 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+
+import os
+
+import Globals
+import OFS
+
+def registerIcon(product_id, icon_filepath):
+ dir, name = os.path.split(icon_filepath)
+ icon = Globals.ImageFile(name, dir)
+ icon.__roles__ = None # Public.
+ if not hasattr(OFS.misc_.misc_, product_id):
+ setattr(OFS.misc_.misc_, product_id, OFS.misc_.Misc_(product_id, {}))
+ getattr(OFS.misc_.misc_, product_id)[name] = icon
+ return 'misc_/%s/%s' % (product_id, name)
+
=== Products/PageDesign/IIndexedSlot.py 1.1 => 1.2 ===
--- Products/PageDesign/IIndexedSlot.py:1.1 Sat Aug 3 15:46:10 2002
+++ Products/PageDesign/IIndexedSlot.py Mon Aug 12 10:39:29 2002
@@ -18,15 +18,33 @@
class IIndexedSlot(ISlot):
def getElementCount():
- """
+ """Returns the number of elements currently in the slot.
"""
def getElement(index):
+ """Returns the IPageElement at the specified index.
"""
+
+ def track(index):
+ """Returns an insertion point tracker.
+
+ The insertion point will be updated as items are added or
+ removed from this slot, ensuring that elements are later inserted
+ where the user expected.
"""
- def insertBefore(before_element, elements):
+ def untrack(ipt):
+ """Disconnects an insertion point tracker, returning its index.
"""
+
+ def insertElements(index, elements):
+ """Inserts IPageElements at the specified index.
+
+ If index is an insertion point tracker (as returned by track()),
+ the tracker will be disconnected and its current value will be
+ used as the index.
+
+ If index is None, the elements will be appended to the end.
"""
def remove(element):
=== Products/PageDesign/IPageElement.py 1.1 => 1.2 ===
--- Products/PageDesign/IPageElement.py:1.1 Sat Aug 3 15:46:10 2002
+++ Products/PageDesign/IPageElement.py Mon Aug 12 10:39:29 2002
@@ -24,6 +24,10 @@
"""Returns the title of this element.
"""
+ def getIconURL():
+ """Returns the URL to an icon for this element if any.
+ """
+
def getEditURL():
"""Returns the URL for editing this element.
=== Products/PageDesign/ISlotProvider.py 1.1 => 1.2 ===
--- Products/PageDesign/ISlotProvider.py:1.1 Sat Aug 3 15:46:10 2002
+++ Products/PageDesign/ISlotProvider.py Mon Aug 12 10:39:29 2002
@@ -23,10 +23,8 @@
The slot might be created on the fly and not stored.
"""
- def _makeSlot(name):
- """Creates a slot if it doesn't exist.
-
- Returns the slot object.
+ def _persistSlot(slot):
+ """Ensures the slot is linked into the database.
"""
def _isEditable():
=== Products/PageDesign/PageDesign.py 1.2 => 1.3 === (550/650 lines abridged)
--- Products/PageDesign/PageDesign.py:1.2 Mon Jul 1 14:27:31 2002
+++ Products/PageDesign/PageDesign.py Mon Aug 12 10:39:29 2002
@@ -24,23 +24,27 @@
import Globals
import Acquisition
from Acquisition import aq_base, aq_inner, aq_parent
-from AccessControl import ClassSecurityInfo
+from AccessControl import ClassSecurityInfo, getSecurityManager
from AccessControl.Permissions import view
+from AccessControl.ZopeGuards import guarded_getattr
from Interface import Base as Interface
from ZODB import Persistent
from ZODB.PersistentMapping import PersistentMapping
from OFS.SimpleItem import SimpleItem
from OFS.PropertyManager import PropertyManager
from Products.PageTemplates.PageTemplateFile import PageTemplateFile
+from Globals import ImageFile
from RawFile import RawFile
+from SlotProvider import SlotProvider
+from ReferencedElement import ReferencedElement
+from ISlotProvider import ISlotProvider
+from IClipboardSource import IClipboardSource
+from IClipboardTarget import IClipboardTarget
# Permission name
change_page_designs = 'Change Page Designs'
-# Constant until the right policy can be chosen.
-INDEPENDENT_TARGETS = 1
-
_www = os.path.join(os.path.dirname(__file__), 'www')
@@ -52,308 +56,259 @@
"""Error in page design"""
-class AreaRenderer:
-
- security = ClassSecurityInfo()
- security.setDefaultAccess('allow')
-
- def __init__(self, design, editable, layered_areas):
- self._design = design
- self._editable = editable
- # layered_areas is not None when a page design uses another page
- # design as its template.
- self._layered_areas = layered_areas
-
[-=- -=- -=- 550 lines omitted -=- -=- -=-]
+ setattr(PageDesignBase, img_name + '_icon', im)
+
+
class PageDesign(PageDesignBase, SimpleItem, PropertyManager):
meta_type = 'Page Design'
@@ -422,33 +394,20 @@
manage_options = (PageDesignBase.manage_options +
SimpleItem.manage_options)
- _properties = ({'id': 'title', 'type': 'string', 'mode': 'w'},
- {'id': 'template_id', 'type': 'string', 'mode': 'w'},)
- template_id = None
- title = ''
-
- security.declareProtected(change_page_designs, 'listAvailableElementIds')
- def listAvailableElementIds(self):
- # This implementation uses a simple ID.
- return aq_parent(aq_inner(self)).objectIds()
-
- security.declareProtected(change_page_designs, 'getElement')
- def getElement(self, element_id):
- return aq_parent(aq_inner(self))[element_id]
-
- security.declareProtected(change_page_designs, 'getTemplate')
- def getTemplate(self):
- id = self.template_id
- if not id:
- raise DesignError, 'Template not set'
- return getattr(aq_parent(aq_inner(self)), id)
+ _properties = (
+ {'id': 'title', 'type': 'string', 'mode': 'w'},
+ {'id': 'template_id', 'type': 'string', 'mode': 'w'},
+ )
security.declareProtected(change_page_designs, 'manage_propertiesForm')
- def manage_propertiesForm(self, *args, **kw):
+ def manage_propertiesForm(self, client=None, REQUEST=None,
+ manage_tabs_message=None):
"""Object properties form
"""
- return self.manage_areas(*args, **kw)
-
+ if REQUEST is not None:
+ REQUEST['RESPONSE'].redirect(
+ self.absolute_url() + '/manage_main?manage_tabs_message=' +
+ manage_tabs_message)
Globals.InitializeClass(PageDesign)
=== Products/PageDesign/RawFile.py 1.1.1.1 => 1.2 ===
--- Products/PageDesign/RawFile.py:1.1.1.1 Sat Jun 8 12:09:34 2002
+++ Products/PageDesign/RawFile.py Mon Aug 12 10:39:29 2002
@@ -51,48 +51,48 @@
self.lmh = rfc1123_date(self.lmt)
- def index_html(self, REQUEST, RESPONSE):
+ 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...
- RESPONSE.setHeader('Content-Type', self.content_type)
- RESPONSE.setHeader('Last-Modified', self.lmh)
- RESPONSE.setHeader('Cache-Control', self.cch)
- 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 ''
+ 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 ''
-
- def __len__(self):
- # This is bogus and needed because of the way Python tests truth.
- return 1
=== Products/PageDesign/Slot.py 1.1 => 1.2 ===
--- Products/PageDesign/Slot.py:1.1 Sat Aug 3 15:46:10 2002
+++ Products/PageDesign/Slot.py Mon Aug 12 10:39:29 2002
@@ -11,32 +11,80 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
+"""Slots containing one or more page elements.
+$Id$
+"""
+
+import os
+import sys
+from cgi import escape
from Persistence import Persistent
import Acquisition
from Acquisition import aq_inner, aq_parent
+import Globals
+from AccessControl import ClassSecurityInfo
from OFS.Traversable import Traversable
from IIndexedSlot import IIndexedSlot
from IPageElement import IPageElement
+from SlotElementClipboardSource import SlotElementClipboardSource
from SlotElementClipboardTarget \
import SlotElementClipboardTarget, SlotElementClipboardLastTarget
+from SlotElementTraverser import SlotElementTraverser
+import utils
+
+_www = os.path.join(os.path.dirname(__file__), 'www')
+
+
+target_icon = '/' + utils.registerIcon(
+ 'PageDesign', os.path.join(_www, 'element_add.gif'))
class Slot (Persistent, Acquisition.Explicit, Traversable):
- """Slot in a page design.
+ """Slot in a page design that can contain either 1 element or a sequence.
+
+ When a template uses the 'single()' method, which returns a string,
+ the slot provides a UI for adding only one page element.
+
+ When a template uses the 'multiple()' method, which returns a list,
+ the slot provides a UI for adding multiple page elements. This allows
+ the template to have some control over the layout of multiple elements.
+
+ Slots designed using multiple() but later rendered with single() will
+ get all elements concatenated together in a string.
"""
__implements__ = IIndexedSlot
- # Traversal helpers.
- elementSources = SlotElementTraverser('elementSources',
- SlotElementClipboardSource)
- elementTargets = SlotElementTraverser('elementTargets',
- SlotElementClipboardTarget)
- lastElementTarget = SlotElementClipboardLastTarget
+ security = ClassSecurityInfo()
+
+ # Clipboard traversal helpers.
+ security.declarePublic('elementSources', 'elementTargets',
+ 'lastElementTarget')
+ elementSources = SlotElementTraverser(
+ 'elementSources', SlotElementClipboardSource)
+ elementTargets = SlotElementTraverser(
+ 'elementTargets', SlotElementClipboardTarget)
+ lastElementTarget = SlotElementClipboardLastTarget()
+
+
+ target_html = '''<div class="design-target" align="center"
+ id="%(clipboard_path)s"><a href="#"
+ onclick="addElementDialog('%(clipboard_path)s'); return false;"><img
+ src="%(target_icon)s" border="0"
+ alt="Add element to slot: %(slot_name)s"
+ title="Add element to slot: %(slot_name)s" /></a></div>'''
+
+ element_html = '''<div class="design-element" id="%(clipboard_path)s">
+ <table class="design-element-titlebar" width="100%%"><tr>
+ <td align="left">%(titlebar)s</td>
+ <td align="right">%(controls)s</td>
+ </tr></table>
+ <div class="design-element-body">%(text)s</div></div>'''
+ _trackers = ()
def __init__(self, id):
self.id = id
@@ -47,6 +95,34 @@
return self.id
+ def renderTargetHTML(self, **kw):
+ kw['target_icon'] = target_icon
+ return self.target_html % kw
+
+
+ def renderSourceHTML(self, element, **kw):
+ c = []
+ for name in ('moveup', 'movedown', 'remove'):
+ url = kw.get(name + '_url')
+ if url:
+ # TODO: use server-wide icons
+ c.append('<a href="%s"><img src="%s_icon" border="0" /></a>'
+ % (url, name))
+ icon_tag = edit_tag = ''
+ icon_url = element.getIconURL()
+ if icon_url:
+ icon_tag = '<img border="0" src="%s" /> ' % icon_url
+ edit_url = element.getEditURL()
+ if edit_url:
+ edit_tag = (' <a href="%s"><img border="0" src="edit_icon" /></a>'
+ % edit_url)
+
+ kw['titlebar'] = icon_tag + escape(kw['title']) + edit_tag
+ kw['controls'] = '\n'.join(c)
+ return self.element_html % kw
+
+
+ security.declarePublic('single')
def single(self):
"""Renders as a single-element slot."""
allow_add = (not self.contents)
@@ -61,6 +137,7 @@
return ''.join(res)
+ security.declarePublic('multiple')
def multiple(self):
"""Renders as a multiple-element slot."""
res = self.renderToList(1)
@@ -83,34 +160,61 @@
res = []
phys_path = '/'.join(self.getPhysicalPath())
- for index in range(len(self.contents)):
+ clen = len(self.contents)
+ for index in range(clen):
e = self.contents[index].__of__(self)
if editable and allow_add:
path = '%s/elementTargets/%d' % (phys_path, index)
- res.append(self.target_html % {
- 'slot_name': self.id,
- 'slot_index': index,
- 'path': path,
- })
+ res.append(self.renderTargetHTML(
+ clipboard_path=path,
+ slot_name=self.id,
+ slot_index=index,
+ ))
+
+ try:
+ text = e.render(design, editable, index)
+ except:
+ # Show the exception.
+ text = "<i>%s</i>" % (
+ escape(('%s: %s' % (sys.exc_info()[:2]))[:80]))
- text = e.render(design=design, editable=editable, index=index)
if editable:
+ design_url = design.absolute_url()
path = '%s/elementSources/%d' % (phys_path, index)
- text = self.element_html % {
- 'title': e.getTitle(),
- 'path': path,
- 'edit_url': e.getEditURL(),
- 'text': text,
- }
+ move_up_url = move_down_url = ''
+ if index > 0:
+ # Can move up.
+ move_up_url = (
+ '%s/moveElement?source_path=%s'
+ '&target_path=%s/elementTargets/%d' % (
+ design_url, path, phys_path, index - 1))
+ if index < (clen - 1):
+ # Can move down.
+ move_down_url = (
+ '%s/moveElement?source_path=%s'
+ '&target_path=%s/elementTargets/%d' % (
+ design_url, path, phys_path, index + 2))
+ remove_url = '%s/removeElement?source_path=%s' % (
+ design_url, path)
+
+ text = self.renderSourceHTML(
+ element=e,
+ clipboard_path=path,
+ title=e.getTitle(),
+ text=text,
+ moveup_url=move_up_url,
+ movedown_url=move_down_url,
+ remove_url=remove_url,
+ )
res.append(text)
if editable and allow_add:
path = '%s/lastElementTarget' % phys_path
- res.append(self.target_html % {
- 'slot_name': self.id,
- 'slot_index': -1,
- 'path': path,
- })
+ res.append(self.renderTargetHTML(
+ clipboard_path=path,
+ slot_name=self.id,
+ slot_index=-1,
+ ))
return res
@@ -121,24 +225,65 @@
def getElement(self, index):
return self.contents[index]
- def insertBefore(self, before_element, elements):
+ def beforeChange(self):
+ aq_parent(aq_inner(self))._persistSlot(self)
+
+ def track(self, index):
+ self.beforeChange()
+ ipt = InsertionPointTracker(index)
+ self._trackers = self._trackers + (ipt,)
+ return ipt
+
+ def untrack(self, ipt):
+ self.beforeChange()
+ ipts = list(self._trackers)
+ ipts.remove(ipt)
+ self._trackers = tuple(ipts)
+ return ipt.index
+
+ def insertElements(self, index, elements):
# Verify none of the elements are already inserted.
# An element can only be in one place at a time.
+ if isinstance(index, InsertionPointTracker):
+ index = self.untrack(index)
for e in elements:
if not IPageElement.isImplementedBy(e):
raise ValueError, 'Not a page element'
if e in self.contents:
raise ValueError, 'Already inserted'
- if before_element is None:
+ self.beforeChange()
+ if index is None:
# append.
self.contents = self.contents + tuple(elements)
else:
- index = list(self.contents).index(before_element)
self.contents = (self.contents[:index] + tuple(elements)
+ self.contents[index:])
+ for ipt in self._trackers:
+ ipt.afterInsert(index, len(elements))
def remove(self, element):
+ self.beforeChange()
lst = list(self.contents)
- lst.remove(element)
+ index = lst.index(element)
+ del lst[index]
self.contents = tuple(lst)
+ for ipt in self._trackers:
+ ipt.afterRemove(index, 1)
+
+Globals.InitializeClass(Slot)
+
+
+
+class InsertionPointTracker:
+
+ def __init__(self, index):
+ self.index = index
+
+ def afterInsert(self, index, count):
+ if self.index >= index:
+ self.index += count
+
+ def afterRemove(self, index, count):
+ if self.index > index:
+ self.index -= count
=== Products/PageDesign/SlotElementClipboardSource.py 1.1 => 1.2 ===
--- Products/PageDesign/SlotElementClipboardSource.py:1.1 Sat Aug 3 15:46:10 2002
+++ Products/PageDesign/SlotElementClipboardSource.py Mon Aug 12 10:39:29 2002
@@ -14,25 +14,37 @@
import Acquisition
+import Globals
from Acquisition import aq_base, aq_inner, aq_parent
+from AccessControl import ClassSecurityInfo
from IClipboardSource import IClipboardSource
from IIndexedSlot import IIndexedSlot
+from IPageElement import IPageElement
+
+# Permission name
+change_page_designs = 'Change Page Designs'
class SlotElementClipboardSource (Acquisition.Explicit):
__implements__ = IClipboardSource
- def __init__(self, index):
+ security = ClassSecurityInfo()
+
+ def init(self, index):
index = int(index)
slot = aq_parent(aq_inner(self))
- assert IIndexedSlot.isImplementedBy(slot)
- self.element = slot.getElement(index)
+ assert IIndexedSlot.isImplementedBy(slot), `slot`
+ element = aq_base(slot.getElement(index))
+ assert IPageElement.isImplementedBy(element), `element`
+ self.element = aq_base(element)
+ return self
+ security.declareProtected(change_page_designs, 'cut')
def cut(self):
slot = aq_parent(aq_inner(self))
- assert IIndexedSlot.isImplementedBy(slot)
element = aq_base(self.element)
slot.remove(element)
return element
+Globals.InitializeClass(SlotElementClipboardSource)
=== Products/PageDesign/SlotElementClipboardTarget.py 1.1 => 1.2 ===
--- Products/PageDesign/SlotElementClipboardTarget.py:1.1 Sat Aug 3 15:46:10 2002
+++ Products/PageDesign/SlotElementClipboardTarget.py Mon Aug 12 10:39:29 2002
@@ -13,29 +13,52 @@
##############################################################################
import Acquisition
+import Globals
from Acquisition import aq_base, aq_inner, aq_parent
+from AccessControl import ClassSecurityInfo
from IClipboardTarget import IClipboardTarget
+from IIndexedSlot import IIndexedSlot
+
+# Permission name
+change_page_designs = 'Change Page Designs'
class SlotElementClipboardTarget (Acquisition.Explicit):
__implements__ = IClipboardTarget
- def __init__(self, index):
+ __roles__ = None # ugh
+
+ security = ClassSecurityInfo()
+
+ def init(self, index):
index = int(index)
slot = aq_parent(aq_inner(self))
- self.before_element = slot.getElement(index)
+ assert IIndexedSlot.isImplementedBy(slot), `slot`
+ self.ipt = slot.track(index)
+ return self
+ security.declareProtected(change_page_designs, 'paste')
def paste(self, elements):
slot = aq_parent(aq_inner(self))
- slot.insertBefore(aq_base(self.before_element), elements)
+ slot.insertElements(self.ipt, elements)
+
+Globals.InitializeClass(SlotElementClipboardTarget)
class SlotElementClipboardLastTarget (Acquisition.Explicit):
__implements__ = IClipboardTarget
+ __roles__ = None # ugh
+
+ security = ClassSecurityInfo()
+
+ security.declareProtected(change_page_designs, 'paste')
def paste(self, elements):
slot = aq_parent(aq_inner(self))
- slot.insertBefore(None, elements)
+ assert IIndexedSlot.isImplementedBy(slot), `slot`
+ slot.insertElements(None, elements)
+
+Globals.InitializeClass(SlotElementClipboardLastTarget)
=== Products/PageDesign/SlotElementTraverser.py 1.1 => 1.2 ===
--- Products/PageDesign/SlotElementTraverser.py:1.1 Sat Aug 3 15:46:10 2002
+++ Products/PageDesign/SlotElementTraverser.py Mon Aug 12 10:39:29 2002
@@ -12,18 +12,30 @@
#
##############################################################################
+import Acquisition
+from Acquisition import aq_inner, aq_parent
+import Globals
+from AccessControl import ClassSecurityInfo
from OFS.Traversable import Traversable
class SlotElementTraverser (Acquisition.Explicit, Traversable):
+ security = ClassSecurityInfo()
+ security.setDefaultAccess('allow')
+
+ __roles__ = None
+
def __init__(self, id, item_factory):
self.id = id
- self.item_factory = item_factory
+ self._item_factory = item_factory
def getId(self):
return self.id
def __getitem__(self, name):
- return self.item_factory(name).__of__(self)
+ slot = aq_parent(aq_inner(self))
+ return self._item_factory().__of__(slot).init(name)
+
+Globals.InitializeClass(SlotElementTraverser)
=== Products/PageDesign/SlotProvider.py 1.1 => 1.2 ===
--- Products/PageDesign/SlotProvider.py:1.1 Sat Aug 3 15:46:10 2002
+++ Products/PageDesign/SlotProvider.py Mon Aug 12 10:39:29 2002
@@ -13,9 +13,14 @@
##############################################################################
import Acquisition
+from Acquisition import aq_base
+import Globals
from AccessControl import ClassSecurityInfo
from OFS.Traversable import Traversable
+from ISlotProvider import ISlotProvider
+from Slot import Slot
+
class SlotProvider (Acquisition.Explicit, Traversable):
@@ -33,21 +38,23 @@
def getId(self):
return self.id
- def _makeSlot(self, name):
- self.__getitem__(name, 1)
+ def _persistSlot(self, slot):
+ slots = self.aq_parent._slots
+ name = slot.getId()
+ if not slots.has_key(name):
+ slots[name] = aq_base(slot)
- def __getitem__(self, name, add=0):
+ def __getitem__(self, name):
slots = self.aq_parent._slots
slot = slots.get(name)
if slot is None:
- slot = Slot()
- if add:
- slots[name] = slot
+ slot = Slot(name)
return slot.__of__(self)
def _isEditable(self):
return self._editable
- def _getLayeredProvider():
+ def _getLayeredProvider(self):
return self._layered_provider
+Globals.InitializeClass(SlotProvider)
=== Products/PageDesign/zopetop_design.zexp 1.1 => 1.2 ===