[Checkins] SVN: CompositePage/trunk/ Moved the code into Products/CompositePage so we can turn this into an egg.

Shane Hathaway shane at hathawaymix.org
Sat Apr 30 15:15:39 EDT 2011


Log message for revision 121490:
  Moved the code into Products/CompositePage so we can turn this into an egg.
  

Changed:
  D   CompositePage/trunk/CHANGES.txt
  D   CompositePage/trunk/COPYRIGHT.txt
  D   CompositePage/trunk/LICENSE.txt
  A   CompositePage/trunk/Products/CompositePage/CHANGES.txt
  A   CompositePage/trunk/Products/CompositePage/COPYRIGHT.txt
  A   CompositePage/trunk/Products/CompositePage/LICENSE.txt
  A   CompositePage/trunk/Products/CompositePage/README.txt
  A   CompositePage/trunk/Products/CompositePage/__init__.py
  A   CompositePage/trunk/Products/CompositePage/cmf/
  A   CompositePage/trunk/Products/CompositePage/common/
  A   CompositePage/trunk/Products/CompositePage/composite.py
  A   CompositePage/trunk/Products/CompositePage/designuis.py
  A   CompositePage/trunk/Products/CompositePage/element.py
  A   CompositePage/trunk/Products/CompositePage/interfaces.py
  A   CompositePage/trunk/Products/CompositePage/manual/
  A   CompositePage/trunk/Products/CompositePage/perm_names.py
  A   CompositePage/trunk/Products/CompositePage/rawfile.py
  A   CompositePage/trunk/Products/CompositePage/slot.py
  A   CompositePage/trunk/Products/CompositePage/slotclass.py
  A   CompositePage/trunk/Products/CompositePage/slotexpr.py
  A   CompositePage/trunk/Products/CompositePage/tests/
  A   CompositePage/trunk/Products/CompositePage/tool.py
  A   CompositePage/trunk/Products/CompositePage/utils.py
  A   CompositePage/trunk/Products/CompositePage/version.txt
  A   CompositePage/trunk/Products/CompositePage/www/
  A   CompositePage/trunk/Products/CompositePage/zmi/
  D   CompositePage/trunk/README.txt
  D   CompositePage/trunk/__init__.py
  D   CompositePage/trunk/cmf/
  D   CompositePage/trunk/common/
  D   CompositePage/trunk/composite.py
  D   CompositePage/trunk/designuis.py
  D   CompositePage/trunk/element.py
  D   CompositePage/trunk/interfaces.py
  D   CompositePage/trunk/manual/
  D   CompositePage/trunk/perm_names.py
  D   CompositePage/trunk/rawfile.py
  D   CompositePage/trunk/slot.py
  D   CompositePage/trunk/slotclass.py
  D   CompositePage/trunk/slotexpr.py
  D   CompositePage/trunk/tests/
  D   CompositePage/trunk/tool.py
  D   CompositePage/trunk/utils.py
  D   CompositePage/trunk/version.txt
  D   CompositePage/trunk/www/
  D   CompositePage/trunk/zmi/

-=-
Deleted: CompositePage/trunk/CHANGES.txt
===================================================================
--- CompositePage/trunk/CHANGES.txt	2011-04-30 19:14:59 UTC (rev 121489)
+++ CompositePage/trunk/CHANGES.txt	2011-04-30 19:15:39 UTC (rev 121490)
@@ -1,40 +0,0 @@
-Next Release
-------------
-
-- Fixed test failures caused by 7 years of changes to Zope.  This mostly
-  involved simple modernization:
-
-    - Use zope.interface, zope.tales, and zope.pagetemplate rather than
-      their predecessors.
-
-    - Use absolute imports.
-
-    - Use Unicode where possible.
-
-- Let's stop swallowing errors that occur when rendering the template
-  to get the list of slots.  Error messages are friendlier than silent
-  breakage.
-
-- Slots now show the add element interface only at the top and bottom
-  of the slot, not between elements.  (Hmm, should this be configurable?)
-
-
-0.2 (2004-06-16)
-----------------
-
-- 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.
-
-- The clipboard now works.
-
-- You can now define slots in a template using "slot:" expressions.
-  This should make it easier to write templates.
-
-- The composite tool now checks copy/paste permissions before making
-  any changes.
-
-- Slots now have a __str__ method, making it easy to render them
-  directly.

Deleted: CompositePage/trunk/COPYRIGHT.txt
===================================================================
--- CompositePage/trunk/COPYRIGHT.txt	2011-04-30 19:14:59 UTC (rev 121489)
+++ CompositePage/trunk/COPYRIGHT.txt	2011-04-30 19:15:39 UTC (rev 121490)
@@ -1 +0,0 @@
-Zope Foundation and Contributors
\ No newline at end of file

Deleted: CompositePage/trunk/LICENSE.txt
===================================================================
--- CompositePage/trunk/LICENSE.txt	2011-04-30 19:14:59 UTC (rev 121489)
+++ CompositePage/trunk/LICENSE.txt	2011-04-30 19:15:39 UTC (rev 121490)
@@ -1,44 +0,0 @@
-Zope Public License (ZPL) Version 2.1
-
-A copyright notice accompanies this license document that identifies the
-copyright holders.
-
-This license has been certified as open source. It has also been designated as
-GPL compatible by the Free Software Foundation (FSF).
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions in source code must retain the accompanying copyright
-notice, this list of conditions, and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the accompanying copyright
-notice, this list of conditions, and the following disclaimer in the
-documentation and/or other materials provided with the distribution.
-
-3. Names of the copyright holders must not be used to endorse or promote
-products derived from this software without prior written permission from the
-copyright holders.
-
-4. The right to distribute this software or to use it for any purpose does not
-give you the right to use Servicemarks (sm) or Trademarks (tm) of the
-copyright
-holders. Use of them is covered by separate agreement with the copyright
-holders.
-
-5. If any files are modified, you must cause the modified files to carry
-prominent notices stating that you changed the files and the date of any
-change.
-
-Disclaimer
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED
-OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
-EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Copied: CompositePage/trunk/Products/CompositePage/CHANGES.txt (from rev 121488, CompositePage/trunk/CHANGES.txt)
===================================================================
--- CompositePage/trunk/Products/CompositePage/CHANGES.txt	                        (rev 0)
+++ CompositePage/trunk/Products/CompositePage/CHANGES.txt	2011-04-30 19:15:39 UTC (rev 121490)
@@ -0,0 +1,40 @@
+Next Release
+------------
+
+- Fixed test failures caused by 7 years of changes to Zope.  This mostly
+  involved simple modernization:
+
+    - Use zope.interface, zope.tales, and zope.pagetemplate rather than
+      their predecessors.
+
+    - Use absolute imports.
+
+    - Use Unicode where possible.
+
+- Let's stop swallowing errors that occur when rendering the template
+  to get the list of slots.  Error messages are friendlier than silent
+  breakage.
+
+- Slots now show the add element interface only at the top and bottom
+  of the slot, not between elements.  (Hmm, should this be configurable?)
+
+
+0.2 (2004-06-16)
+----------------
+
+- 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.
+
+- The clipboard now works.
+
+- You can now define slots in a template using "slot:" expressions.
+  This should make it easier to write templates.
+
+- The composite tool now checks copy/paste permissions before making
+  any changes.
+
+- Slots now have a __str__ method, making it easy to render them
+  directly.

Copied: CompositePage/trunk/Products/CompositePage/COPYRIGHT.txt (from rev 121488, CompositePage/trunk/COPYRIGHT.txt)
===================================================================
--- CompositePage/trunk/Products/CompositePage/COPYRIGHT.txt	                        (rev 0)
+++ CompositePage/trunk/Products/CompositePage/COPYRIGHT.txt	2011-04-30 19:15:39 UTC (rev 121490)
@@ -0,0 +1 @@
+Zope Foundation and Contributors
\ No newline at end of file

Copied: CompositePage/trunk/Products/CompositePage/LICENSE.txt (from rev 121488, CompositePage/trunk/LICENSE.txt)
===================================================================
--- CompositePage/trunk/Products/CompositePage/LICENSE.txt	                        (rev 0)
+++ CompositePage/trunk/Products/CompositePage/LICENSE.txt	2011-04-30 19:15:39 UTC (rev 121490)
@@ -0,0 +1,44 @@
+Zope Public License (ZPL) Version 2.1
+
+A copyright notice accompanies this license document that identifies the
+copyright holders.
+
+This license has been certified as open source. It has also been designated as
+GPL compatible by the Free Software Foundation (FSF).
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions in source code must retain the accompanying copyright
+notice, this list of conditions, and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the accompanying copyright
+notice, this list of conditions, and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+3. Names of the copyright holders must not be used to endorse or promote
+products derived from this software without prior written permission from the
+copyright holders.
+
+4. The right to distribute this software or to use it for any purpose does not
+give you the right to use Servicemarks (sm) or Trademarks (tm) of the
+copyright
+holders. Use of them is covered by separate agreement with the copyright
+holders.
+
+5. If any files are modified, you must cause the modified files to carry
+prominent notices stating that you changed the files and the date of any
+change.
+
+Disclaimer
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED
+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Copied: CompositePage/trunk/Products/CompositePage/README.txt (from rev 121488, CompositePage/trunk/README.txt)
===================================================================
--- CompositePage/trunk/Products/CompositePage/README.txt	                        (rev 0)
+++ CompositePage/trunk/Products/CompositePage/README.txt	2011-04-30 19:15:39 UTC (rev 121490)
@@ -0,0 +1,205 @@
+
+
+Contents
+========
+
+  - Introduction
+
+  - How to use CompositePage
+
+  - How to write a template
+
+  - How it works
+
+  - Adapting CompositePage to other applications
+
+  - Near-term directions
+
+
+
+Introduction
+============
+
+CompositePage is a new way to assemble pages for the World Wide Web.
+Through the use of Zope technology, browser-based drag and drop, and
+custom context menus, CompositePage makes it easy to visually combine
+page fragments into complete pages.
+
+CompositePage supercedes the PageDesign product and makes use of
+PDLib, a Javascript library.  CompositePage is designed for browsers
+that support the DOM (Document Object Model) and CSS (Cascading Style
+Sheets) level 2: Mozilla, Internet Explorer 5+, Opera, Konqueror, etc.
+Not all of these browsers have been tested, but it should be possible
+to solve most problems that occur.
+
+
+
+How to use CompositePage
+========================
+
+Follow these steps:
+
+- Install the CompositePage product in Zope by unpacking the archive
+into your Products directory.  I've tested only with a current Zope
+checkout, which is something like Zope 2.7.
+
+- Create a Composite Tool instance in a central location, possibly the
+root folder.
+
+- Create a Composite object.  On the creation form, there is a
+checkbox for creating a sample template.  Leave the checkbox checked.
+
+- Visit the Composite object and select the "Design" tab.  You should
+see a three-column layout with blue dotted lines in the places where
+you are allowed to insert content.
+
+- Click just beneath one of the blue lines.  A context menu will pop
+up.  Select "Add...".
+
+- You will be directed to a slot (a folderish object.)  In slots, you
+can add composite elements.  Add a composite element that points to a
+script.
+
+- Find the composite created earlier and select the "Design" tab
+again.  Your new object should now show up in the slot.
+
+- Move the object to a different slot using drag and drop.  When the
+mouse cursor is hovering over a permitted target (the blue dotted
+lines are targets), the target will be highlighted.  Let go and watch
+your object appear in the new place.
+
+- Right-click over your object and select "Delete" from the context
+menu.
+
+
+How to write a template
+=======================
+
+Templates can be any Zope object, but ZPTs (Zope Page Templates) are
+the most common.  A template designed for use with composites uses the
+'slots' attribute of the composite.  The 'slots' attribute is a
+mapping-like object.
+
+Here is a simple composite-aware page template::
+
+  <html>
+   <head>
+   </head>
+  <body>
+   <div tal:content="structure here/slots/center/single">
+   This will be replaced with one element from one slot.
+   </div>
+  </body>
+  </html>
+
+The expression 'here/slots/center/single' gets the 'slots' attribute
+of the composite, finds a slot named 'center', and calls the single()
+method of the slot, returning a string containing an HTML structure.
+
+The only place you have to name a slot is in the template.  If the
+template refers to a slot that does not yet exist, the composite will
+create and return an empty slot.  If you place something in that slot
+using the drag and drop interface, the composite will transparently
+add a new slot to the 'filled_slots' folder.  Note that Zope prevents
+you from storing slots with names that start with an underscore or
+that clash existing folder attributes.
+
+Templates use either the single() or the multiple() method of a slot.
+single() returns a string, while multiple() returns a list of strings.
+Use single() when you expect the slot to never contain more than one
+element.  Use multiple() to allow more than one element.  In either
+case, don't forget to use the ZPT 'structure' keyword, since the
+returned strings contain HTML that should not be escaped.
+
+
+
+How it works
+============
+
+Rendering:
+
+When you render (view) a composite, it calls its template.  When the
+template refers to a slot, the composite looks for the named slot in
+the filled_slots folder.  If it finds the slot, it returns it; if it
+doesn't find it, the composite creates a temporary empty slot.  Then
+the template calls either the single() or multiple() method and the
+slot renders and returns its contents.
+
+
+Rendering in edit mode:
+
+When requested, the composite calls upon a "UI" object to render its
+template and slots with edit mode turned on.  In edit mode, slots add
+'class', 'source_path', 'target_path', and 'target_index' attributes
+to HTML tags to mark movable objects and available drop targets.
+Slots add HTML markup for drop targets automatically.  When rendering
+using the single() method, slots provide a drop target only if the
+slot is empty.  When rendering using the multiple() method, slots
+insert drop targets between the elements and to the beginning and end
+of the slot.
+
+The UI object can use various mechanisms to make the page editable.
+Most UI objects use regular expressions to find the 'head' and 'body'
+tags.  Then the UI object inserts scripts, styles, and HTML elements.
+The result of the transformation is sent back to the browser.
+
+
+Drag and drop:
+
+At the bottom of a page rendered in edit mode is a call to the
+pd_setupPage() Javascript function.  pd_setupPage() searches all of
+the elements on the page, looking for elements with particular 'class'
+attributes.  When it finds a 'slot_element', a handler adds event
+listeners to that element that react when the user presses the mouse
+button in that element.  When pd_setupPage() finds a 'slot_target',
+another handler adds event listeners that react when the user drags
+into that element.
+
+If the user releases the mouse while dragging into a target, the
+Javascript code puts the appropriate source paths, target paths, and
+target indexes into a hidden form and submits that form to the
+composite tool in Zope.  The composite tool moves the elements then
+redirects the browser to the original page.  The browser loads the
+page in edit mode again and the moved element gets rendered in its new
+spot.
+
+
+Context menus:
+
+Like drag and drop, context menus depend on pd_setupPage().  When
+pd_setupPage() finds a 'slot_element', a handler adds a context menu
+listener to that element.  The context menu listener, when activated,
+positions and displays an otherwise invisible HTML element that looks
+just like a context menu.  Once displayed, the user is expected to
+either select an item from the context menu or click outside the
+context menu to make it disappear.  A similar process exists for
+'slot_target' elements, but a different invisible HTML element is
+used.
+
+Just before popping up a context menu, its contents are filtered using
+Javascript expressions.  Some actions are valid only when the user has
+selected at least one item, and other actions are valid only when
+exactly one item item is selected.  Filter expressions provide a way
+to express these constraints.
+
+
+
+Adapting CompositePage to other applications
+============================================
+
+CompositePage provides a default user interface that integrates with
+the Zope management interface, but mechanisms are provided for
+integrating with any user interface.  Look at design.py, the 'common'
+subdirectory, and the 'zmi' subdirectory for guidance.  Simple
+customizations probably do not require more code than ZMIUI.
+
+
+
+Near-term directions
+====================
+
+I would like CompositePage to work reliably with as many browsers as
+possible, but Mozilla 1.4 is the current reference browser.  Try it in
+your preferred browser.  If it acts strangely, try the same thing in
+Mozilla 1.4 and send an email describing the differences.
+

Copied: CompositePage/trunk/Products/CompositePage/__init__.py (from rev 121488, CompositePage/trunk/__init__.py)
===================================================================
--- CompositePage/trunk/Products/CompositePage/__init__.py	                        (rev 0)
+++ CompositePage/trunk/Products/CompositePage/__init__.py	2011-04-30 19:15:39 UTC (rev 121490)
@@ -0,0 +1,72 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Foundation and Contributors.
+#
+# 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.7 2004/03/05 21:41:04 shane Exp $
+"""
+
+import tool, element, composite, slot, slotclass, designuis, interfaces
+import slotexpr
+
+slotexpr.registerSlotExprType()
+
+tool.registerUI("common", designuis.CommonUI())
+tool.registerUI("zmi", designuis.ZMIUI())
+tool.registerUI("cmf", designuis.CMFUI())
+tool.registerUI("manual", designuis.ManualUI())
+
+
+def initialize(context):
+
+    context.registerClass(
+        tool.CompositeTool,
+        constructors=(tool.manage_addCompositeTool,),
+        icon="www/comptool.gif",
+        )
+
+    context.registerClass(
+        element.CompositeElement,
+        constructors=(element.addElementForm,
+                      element.manage_addElement,
+                      ),
+        visibility=None,
+        icon="www/element.gif",
+        )
+
+    context.registerClass(
+        slotclass.SlotClass,
+        constructors=(slotclass.addSlotClassForm,
+                      slotclass.manage_addSlotClass,
+                      ),
+        interfaces=(interfaces.ISlotClass,),
+        visibility=None,
+        icon="www/slot.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,
+        icon="www/slot.gif",
+        )

Copied: CompositePage/trunk/Products/CompositePage/composite.py (from rev 121488, CompositePage/trunk/composite.py)
===================================================================
--- CompositePage/trunk/Products/CompositePage/composite.py	                        (rev 0)
+++ CompositePage/trunk/Products/CompositePage/composite.py	2011-04-30 19:15:39 UTC (rev 121490)
@@ -0,0 +1,367 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Foundation and Contributors.
+#
+# 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.24 2004/04/15 22:13:44 shane Exp $
+"""
+
+import os
+import re
+
+import Globals
+import Acquisition
+from Acquisition import aq_base
+from Acquisition import aq_inner
+from Acquisition import aq_parent
+from Acquisition import aq_get
+from OFS.Folder import Folder
+from OFS.SimpleItem import SimpleItem
+from Products.PageTemplates.PageTemplateFile import PageTemplateFile
+from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate
+from AccessControl import ClassSecurityInfo
+from AccessControl.ZopeGuards import guarded_getattr
+from zope.interface import implements
+
+from Products.CompositePage.interfaces import IComposite
+from Products.CompositePage.interfaces import ISlot
+from Products.CompositePage.interfaces import ISlotGenerator
+from Products.CompositePage.interfaces import CompositeError
+from Products.CompositePage.slot import Slot
+from Products.CompositePage.slot import getIconURL
+from Products.CompositePage.slot import formatException
+from Products.CompositePage.perm_names import view_perm
+from Products.CompositePage.perm_names import change_composites_perm
+
+_www = os.path.join(os.path.dirname(__file__), "www")
+
+
+class SlotGenerator(Acquisition.Explicit):
+    """Automatically makes slots available to the template.
+
+    Note: instances of this class are shared across threads.
+    """
+    _slot_class = Slot
+
+    def get(self, name, class_name=None, title=None):
+        """Returns a slot by name.
+
+        This is designed to be called in the middle of a page
+        template.  Assigns attributes (class_name and title) to the
+        slot at the same time.
+        """
+        name = str(name)
+        composite = aq_parent(aq_inner(self))
+        composite._usingSlot(name, class_name, title)
+        slots = composite.filled_slots
+        if slots.hasObject(name):
+            return slots[name]
+        else:
+            # Generate a new slot.
+            s = self._slot_class(name)
+            if composite.isEditing():
+                # Persist the slot.
+                slots._setObject(s.getId(), s)
+            # else don't persist the slot.
+            return s.__of__(slots)
+
+    __getitem__ = get
+
+
+class CompositeMixin:
+    """Base class for editable composite pages.
+
+    Composite pages are assemblies of templates and composite
+    elements.  This base class provides the nuts and bolts of a
+    composite editing interface.
+    """
+    implements(IComposite)
+    meta_type = "Composite"
+
+    security = ClassSecurityInfo()
+
+    manage_options = (
+        {"label": "Design", "action": "manage_designForm",},
+        {"label": "View", "action": "view",},
+        )
+
+    default_ui = "common"
+    template_path = "template"
+    _v_editing = 0
+    _v_rendering = 0
+    _v_slot_specs = None  # [{'name', 'class', 'title'}]
+
+    security.declarePublic("slots")
+    slots = SlotGenerator()
+
+    _properties = (
+        {"id": "template_path", "mode": "w", "type": "string",
+         "label": "Path to template"},
+        )
+
+    security.declareProtected(view_perm, "hasTemplate")
+    def hasTemplate(self):
+        if self.template_path:
+            return 1
+        return 0
+
+    security.declareProtected(view_perm, "getTemplate")
+    def getTemplate(self):
+        if not self.template_path:
+            raise CompositeError("No template set")
+        return self.restrictedTraverse(str(self.template_path))
+
+    security.declareProtected(change_composites_perm, "generateSlots")
+    def generateSlots(self):
+        """Creates the slots defined by the template.
+        """
+        self._v_editing = 1
+        try:
+            self()
+        finally:
+            self._v_editing = 0
+
+    security.declareProtected(view_perm, "__call__")
+    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(composite=self)
+        finally:
+            self._v_rendering = 0
+
+    view = __call__
+
+    index_html = None
+
+    security.declareProtected(change_composites_perm, "design")
+    def design(self, ui=None):
+        """Renders the composite with editing features.
+        """
+        # Never cache a design view.
+        req = getattr(self, "REQUEST", None)
+        if req is not None:
+            req["RESPONSE"].setHeader("Cache-Control", "no-cache")
+        ui_obj = self.getUI(ui)
+        self._v_editing = 1
+        try:
+            return ui_obj.render(self)
+        finally:
+            self._v_editing = 0
+
+    security.declareProtected(change_composites_perm, "manage_designForm")
+    def manage_designForm(self):
+        """Renders the composite with editing and ZMI features.
+        """
+        return self.design("zmi")
+
+    security.declareProtected(change_composites_perm, "getUI")
+    def getUI(self, ui=None):
+        """Returns a UI object.
+        """
+        if not ui:
+            ui = self.default_ui
+        tool = aq_get(self, "composite_tool", None, 1)
+        if tool is None:
+            raise CompositeError("No composite_tool found")
+        return guarded_getattr(tool.uis, ui)
+
+    def _usingSlot(self, name, class_name, title):
+        """Receives notification that the template is using a slot.
+
+        Even though slots are persisted, only the template knows
+        exactly what slots are in use.  This callback gives the
+        composite a chance to learn about the slots in use.  This is
+        designed for editing purposes, not rendering.
+        """
+        if self._v_slot_specs is not None:
+            # Record the slot spec.
+            self._v_slot_specs.append({
+                'name': name,
+                'class_name': class_name,
+                'title': title,
+                })
+
+    security.declareProtected(change_composites_perm, "getSlotSpecs")
+    def getSlotSpecs(self):
+        """Returns the slot specs within the template.
+
+        Returns [{'name', 'class_name', 'title'}].  May return duplicates.
+        """
+        self._v_editing = 1
+        self._v_slot_specs = []
+        try:
+            self()
+            slots = self._v_slot_specs
+            return slots
+        finally:
+            self._v_editing = 0
+            self._v_slot_specs = None
+
+    security.declareProtected(change_composites_perm, "getSlotClassName")
+    def getSlotClassName(self, slot_name):
+        """Returns the class_name of a slot.
+
+        Returns None if no class is defined for the slot.  Raises
+        KeyError if no such slot exists.
+        """
+        specs = self.getSlotSpecs()
+        for spec in specs:
+            if spec['name'] == slot_name:
+                return spec['class_name']
+        raise KeyError(slot_name)
+
+    security.declareProtected(change_composites_perm, "getManifest")
+    def getManifest(self):
+        """Returns a manifest of slot contents.
+
+        Designed for use by page templates that implement a manual
+        slotting user interface.
+        """
+        contents = []  # [{name, slot_info}]
+        seen = {}
+        specs = self.getSlotSpecs()
+        if hasattr(self, 'portal_url'):
+            icon_base_url = self.portal_url()
+        else:
+            request = getattr(self, 'REQUEST', None)
+            if request is not None:
+                icon_base_url = request['BASEPATH1']
+            else:
+                icon_base_url = ''
+        for spec in specs:
+            name = spec['name']
+            if seen.has_key(name):
+                # Don't show duplicate uses of a slot.
+                continue
+            seen[name] = 1
+            slot = self.slots[name]
+            elements = []
+            index = 0
+            slot_values = slot.objectValues()
+            for element in slot_values:
+                error = None
+                template = None
+                templates = ()
+                try:
+                    ob = element.dereference()
+                    template = element.queryInlineTemplate(spec['class_name'])
+                    templates = element.listAllowableInlineTemplates(
+                        spec['class_name'])
+                except:
+                    error = formatException(self, editing=1)
+                    ob = FailedElement().__of__(self)
+                icon = getIconURL(ob, icon_base_url)
+                available_templates = []
+                for name, t in templates:
+                    if hasattr(aq_base(t), 'title_or_id'):
+                        title = t.title_or_id()
+                    else:
+                        title = name
+                    available_templates.append({'id': name, 'title': title})
+                element_info = {
+                    'title': ob.title_or_id(),
+                    'icon': icon,
+                    'error': error,
+                    'source_path': '/'.join(element.getPhysicalPath()),
+                    'index': index,
+                    'next_index': index + 1,
+                    'can_move_up': (index > 0),
+                    'can_move_down': (index < len(slot_values) - 1),
+                    'template': template,
+                    'available_templates': available_templates,
+                    }
+                elements.append(element_info)
+                index += 1
+            slot_info = {
+                'name': name,
+                'title': spec['title'] or name,
+                'class_name': spec['class_name'],
+                'target_path': '/'.join(slot.getPhysicalPath()),
+                'elements': elements,
+                }
+            contents.append(slot_info)
+        return contents
+
+    security.declareProtected(view_perm, "isEditing")
+    def isEditing(self):
+        """Returns true if currently rendering in design mode.
+        """
+        return self._v_editing
+
+Globals.InitializeClass(CompositeMixin)
+
+
+class SlotCollection(Folder):
+    """Stored collection of composite slots.
+    """
+    meta_type = "Slot Collection"
+
+    def all_meta_types(self):
+        return Folder.all_meta_types(self, interfaces=(ISlot,))
+
+
+class Composite(CompositeMixin, Folder):
+    """An HTML fragment composed from a template and fragments.
+
+    Fragments are stored on a container called 'filled_slots'.
+    """
+
+    manage_options = (
+        Folder.manage_options[:1]
+        + CompositeMixin.manage_options
+        + Folder.manage_options[2:]
+        )
+
+    _properties = Folder._properties + CompositeMixin._properties
+
+    def __init__(self):
+        f = SlotCollection()
+        f._setId("filled_slots")
+        self._setObject(f.getId(), f)
+
+Globals.InitializeClass(Composite)
+
+
+class FailedElement(SimpleItem):
+    meta_type = "Failed Element"
+    icon = 'p_/broken'
+    id = 'error'
+    title = 'Error'
+
+
+addCompositeForm = PageTemplateFile("addCompositeForm.zpt", _www)
+
+def manage_addComposite(dispatcher, id, title="", create_sample="",
+                        REQUEST=None):
+    """Adds a composite to a folder.
+    """
+    ob = Composite()
+    ob._setId(id)
+    ob.title = unicode(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)

Copied: CompositePage/trunk/Products/CompositePage/designuis.py (from rev 121488, CompositePage/trunk/designuis.py)
===================================================================
--- CompositePage/trunk/Products/CompositePage/designuis.py	                        (rev 0)
+++ CompositePage/trunk/Products/CompositePage/designuis.py	2011-04-30 19:15:39 UTC (rev 121490)
@@ -0,0 +1,345 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Foundation 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.
+# 
+##############################################################################
+"""Page design UI classes.
+
+$Id: designuis.py,v 1.10 2004/04/06 16:50:25 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 AccessControl.ZopeGuards import guarded_getattr
+
+from Products.CompositePage.rawfile import RawFile
+from Products.CompositePage.rawfile import InterpolatedFile
+from Products.CompositePage.interfaces import ICompositeElement
+
+
+_common = os.path.join(os.path.dirname(__file__), "common")
+_zmi = os.path.join(os.path.dirname(__file__), "zmi")
+_cmf = os.path.join(os.path.dirname(__file__), "cmf")
+_manual = os.path.join(os.path.dirname(__file__), "manual")
+
+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>
+"""
+
+close_dialog_html = '''<html>
+<script type="text/javascript">
+if (window.opener)
+  window.opener.location.reload();
+window.close();
+</script>
+</html>
+'''
+
+class CommonUI(SimpleItem):
+    """Basic page design UI.
+
+    Adds editing features to a rendered composite.
+    """
+
+    security = ClassSecurityInfo()
+
+    security.declarePublic(
+        "pdlib_js", "design_js", "pdstyles_css", "designstyles_css")
+    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 = InterpolatedFile("editstyles.css", "text/css", _common)
+    target_image = RawFile("target.gif", "image/gif", _common)
+    target_image_hover = RawFile("target_hover.gif", "image/gif", _common)
+    target_image_active = RawFile("target_active.gif", "image/gif", _common)
+    element_image = RawFile("element.gif", "image/gif", _common)
+
+    header_templates = (PageTemplateFile("header.pt", _common),)
+    top_templates = ()
+    bottom_templates = (PageTemplateFile("bottom.pt", _common),)
+
+    changeTemplateForm = PageTemplateFile("changeTemplateForm.pt", _common)
+
+    workspace_view_name = "view"  # To be overridden
+
+    security.declarePublic("getFragments")
+    def getFragments(self, composite):
+        """Returns the fragments to be inserted in design mode.
+        """
+        params = {
+            "tool": aq_parent(aq_inner(aq_parent(aq_inner(self)))),
+            "ui": 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)
+        return {"header": header, "top": top, "bottom": bottom}
+
+
+    security.declarePrivate("render")
+    def render(self, composite):
+        """Renders a composite, adding scripts and styles.
+        """
+        text = composite()
+        fragments = self.getFragments(composite)
+        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 fragments['header']:
+            index = match.end(0)
+            text = "%s%s%s" % (text[:index], fragments['header'], text[index:])
+        if fragments['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], fragments['top'], text[index:])
+        if fragments['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], fragments['bottom'], text[index:])
+        return text
+
+
+    security.declarePublic("showElement")
+    def showElement(self, path, RESPONSE):
+        """Redirects to the workspace for an element.
+        """
+        root = self.getPhysicalRoot()
+        obj = root.restrictedTraverse(path)
+        if ICompositeElement.providedBy(obj):
+            obj = obj.dereference()
+        RESPONSE.redirect("%s/%s" % (
+            obj.absolute_url(), self.workspace_view_name))
+
+
+    security.declarePublic("previewElement")
+    def previewElement(self, path, RESPONSE):
+        """Redirects to the preview for an element.
+        """
+        root = self.getPhysicalRoot()
+        obj = root.restrictedTraverse(path)
+        if ICompositeElement.providedBy(obj):
+            obj = obj.dereference()
+        RESPONSE.redirect(obj.absolute_url())
+
+
+    security.declarePublic("showSlot")
+    def showSlot(self, path, RESPONSE):
+        """Redirects to (and possibly creates) the workspace for a slot.
+        """
+        from composite import Composite
+
+        obj = self.getPhysicalRoot()
+        parts = str(path).split('/')
+        for name in parts:
+            obj = obj.restrictedTraverse(name)
+            if IComposite.providedBy(obj):
+                gen = guarded_getattr(obj, "generateSlots")
+                gen()
+        RESPONSE.redirect("%s/%s" % (
+            obj.absolute_url(), self.workspace_view_name))
+
+
+    security.declarePublic("getTemplateChangeInfo")
+    def getTemplateChangeInfo(self, paths):
+        """Returns information for changing the template applied to objects.
+        """
+        root = self.getPhysicalRoot()
+        tool = aq_parent(aq_inner(self))
+        obs = []
+        all_choices = None  # {template -> 1}
+        current = None
+        for path in str(paths).split(':'):
+            ob = root.unrestrictedTraverse(path)
+            obs.append(ob)
+            if not ICompositeElement.providedBy(ob):
+                raise ValueError("Not a composite element: %s" % path)
+            m = guarded_getattr(ob, "queryInlineTemplate")
+            template = m()
+            if current is None:
+                current = template
+            elif current and current != template:
+                # The current template isn't the same for all of the elements,
+                # so there is no common current template.  Spell this condition
+                # using a non-string value.
+                current = 0
+            m = guarded_getattr(ob, "listAllowableInlineTemplates")
+            templates = m()
+            d = {}
+            for name, template in templates:
+                d[name] = template
+            if all_choices is None:
+                all_choices = d
+            else:
+                for template in all_choices.keys():
+                    if not d.has_key(template):
+                        del all_choices[template]
+        return {
+            "obs": obs,
+            "templates": all_choices,
+            "current_template": current,
+            }
+
+
+    security.declarePublic("changeTemplate")
+    def changeTemplate(self, paths, template, reload=0, close=1, REQUEST=None):
+        """Changes the template for objects.
+        """
+        info = self.getTemplateChangeInfo(paths)
+        if template not in info["templates"]:
+            raise KeyError("Template %s is not among the choices" % template)
+        tool = aq_parent(aq_inner(self))
+        for ob in info["obs"]:
+            assert ICompositeElement.providedBy(ob)
+            m = guarded_getattr(ob, "setInlineTemplate")
+            m(template)
+        if REQUEST is not None:
+            if reload:
+                REQUEST["RESPONSE"].redirect(REQUEST["HTTP_REFERER"])
+            elif close:
+                return close_dialog_html
+
+Globals.InitializeClass(CommonUI)
+
+
+
+class ZMIUI (CommonUI):
+    """Page design UI meant to fit the Zope management interface.
+
+    Adds editing features to a rendered composite.
+    """
+    security = ClassSecurityInfo()
+
+    workspace_view_name = "manage_workspace"
+
+    security.declarePublic("zmi_edit_js")
+    zmi_edit_js = RawFile("zmi_edit.js", "text/javascript", _zmi)
+
+    header_templates = CommonUI.header_templates + (
+        PageTemplateFile("header.pt", _zmi),)
+    top_templates = CommonUI.top_templates + (
+        PageTemplateFile("top.pt", _zmi),)
+    bottom_templates = (PageTemplateFile("bottom.pt", _zmi),
+                        ) + CommonUI.bottom_templates
+
+Globals.InitializeClass(ZMIUI)
+
+
+
+class CMFUI (CommonUI):
+    """Page design UI meant to fit CMF.
+
+    Adds CMF-specific scripts and styles to a page.
+    """
+    security = ClassSecurityInfo()
+
+    workspace_view_name = "view"
+
+    security.declarePublic("cmf_edit_js")
+    cmf_edit_js = RawFile("cmf_edit.js", "text/javascript", _cmf)
+
+    header_templates = CommonUI.header_templates + (
+        PageTemplateFile("header.pt", _cmf),)
+    bottom_templates = (PageTemplateFile("bottom.pt", _cmf),
+                        ) + CommonUI.bottom_templates
+
+Globals.InitializeClass(CMFUI)
+
+
+
+class ManualUI (CommonUI):
+    """Non-WYSIWYG page design UI.
+    """
+    security = ClassSecurityInfo()
+
+    body = PageTemplateFile("body.pt", _manual)
+    manual_styles_css = InterpolatedFile(
+        "manual_styles.css", "text/css", _manual)
+    header_templates = (PageTemplateFile("header.pt", _manual),)
+    bottom_templates = CommonUI.bottom_templates + (
+        PageTemplateFile("bottom.pt", _manual),)
+    manual_js = RawFile("manual.js", "text/javascript", _manual)
+    add_icon = RawFile("add.gif", "image/gif", _manual)
+    add_rollover = RawFile("add_rollover.gif", "image/gif", _manual)
+    remove_icon = RawFile("remove.gif", "image/gif", _manual)
+    remove_rollover = RawFile("remove_rollover.gif", "image/gif", _manual)
+    cut_icon = RawFile("cut.gif", "image/gif", _manual)
+    cut_rollover = RawFile("cut_rollover.gif", "image/gif", _manual)
+    copy_icon = RawFile("copy.gif", "image/gif", _manual)
+    copy_rollover = RawFile("copy_rollover.gif", "image/gif", _manual)
+    paste_icon = RawFile("paste.gif", "image/gif", _manual)
+    paste_rollover = RawFile("paste_rollover.gif", "image/gif", _manual)
+
+    security.declarePublic("renderBody")
+    def renderBody(self, composite):
+        """Renders the slotting interface for a composite.
+
+        Returns an HTML fragment without the required scripts and
+        styles.
+        """
+        manifest = composite.getManifest()
+        pt = self.body.__of__(composite)
+        return pt(ui=self, manifest=manifest)
+
+    security.declarePublic("render")
+    def render(self, composite):
+        """Renders a ZMI slotting interface for a composite.
+
+        Returns a full HTML page with scripts and styles.
+        """
+        fragments = self.getFragments(composite)
+        body = self.renderBody(composite)
+        res = []
+        res.append(composite.manage_page_header())
+        res.append(composite.manage_tabs())
+        res.append(fragments["header"])
+        res.append(fragments["top"])
+        res.append(body)
+        res.append(fragments["bottom"])
+        res.append(composite.manage_page_footer())
+        return '\n'.join(res)
+
+Globals.InitializeClass(ManualUI)

Copied: CompositePage/trunk/Products/CompositePage/element.py (from rev 121488, CompositePage/trunk/element.py)
===================================================================
--- CompositePage/trunk/Products/CompositePage/element.py	                        (rev 0)
+++ CompositePage/trunk/Products/CompositePage/element.py	2011-04-30 19:15:39 UTC (rev 121490)
@@ -0,0 +1,116 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Foundation and Contributors.
+#
+# 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 element.
+
+$Id: element.py,v 1.5 2004/04/14 16:15:29 sidnei Exp $
+"""
+
+import os
+
+import Globals
+from AccessControl.SecurityInfo import ClassSecurityInfo
+from Acquisition import aq_get
+from OFS.SimpleItem import SimpleItem
+from OFS.PropertyManager import PropertyManager
+from Products.PageTemplates.PageTemplateFile import PageTemplateFile
+from DocumentTemplate.DT_Util import safe_callable
+
+from zope.interface import implements
+
+from Products.CompositePage.interfaces import ICompositeElement
+
+_www = os.path.join(os.path.dirname(__file__), "www")
+
+
+class CompositeElement(SimpleItem, PropertyManager):
+    """A simple path-based reference to an object and a template.
+
+    You can render it and choose which template to apply for rendering.
+    """
+    implements(ICompositeElement)
+    meta_type = "Composite Element"
+    security = ClassSecurityInfo()
+    manage_options = PropertyManager.manage_options + SimpleItem.manage_options
+
+    _properties = (
+        {'id': 'path', 'type': 'string', 'mode': 'w',},
+        {'id': 'template_name', 'type': 'string', 'mode': 'w',},
+        )
+
+    template_name = ''
+
+    def __init__(self, id, obj):
+        self.id = id
+        self.path = '/'.join(obj.getPhysicalPath())
+
+    def dereference(self):
+        """Returns the object referenced by this composite element.
+        """
+        return self.restrictedTraverse(self.path)
+
+    def renderInline(self):
+        """Returns a representation of this object as a string.
+        """
+        obj = self.dereference()
+        name = self.template_name
+        if not name:
+            # Default to the first allowable inline template.
+            names = self.listAllowableInlineTemplates()
+            if names:
+                name = names[0]
+        if name and name != "call":
+            template = obj.restrictedTraverse(str(name))
+            return template()
+        # Special template name "call" means to call the object.
+        if safe_callable(obj):
+            return obj()
+        return unicode(obj)
+
+    def queryInlineTemplate(self, slot_class_name=None):
+        """Returns the name of the inline template this object uses.
+        """
+        return self.template_name
+
+    def setInlineTemplate(self, template):
+        """Sets the inline template for this object.
+        """
+        self.template_name = str(template)
+
+    def listAllowableInlineTemplates(self, slot_class_name=None):
+        """Returns a list of inline template names allowable for this object.
+        """
+        tool = aq_get(self, "composite_tool", None, 1)
+        if tool is not None:
+            res = []
+            for name in tool.default_inline_templates:
+                template = obj.restrictedTraverse(str(name))
+                res.append((name, template))
+            return res
+        # No tool found, so no inline templates are known.
+        return ()
+
+Globals.InitializeClass(CompositeElement)
+
+
+addElementForm = PageTemplateFile("addElementForm.zpt", _www)
+
+def manage_addElement(dispatcher, id, path, template_name=None, REQUEST=None):
+    """Adds an element to a slot.
+    """
+    target = dispatcher.restrictedTraverse(path)
+    ob = CompositeElement(str(id), target)
+    if template_name:
+        ob.template_name = str(template_name)
+    dispatcher._setObject(ob.getId(), ob)
+    if REQUEST is not None:
+        return dispatcher.manage_main(dispatcher, REQUEST)

Copied: CompositePage/trunk/Products/CompositePage/interfaces.py (from rev 121488, CompositePage/trunk/interfaces.py)
===================================================================
--- CompositePage/trunk/Products/CompositePage/interfaces.py	                        (rev 0)
+++ CompositePage/trunk/Products/CompositePage/interfaces.py	2011-04-30 19:15:39 UTC (rev 121490)
@@ -0,0 +1,127 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Foundation and Contributors.
+#
+# 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.14 2004/04/15 22:13:44 shane Exp $
+"""
+
+from zope.interface import Attribute
+from zope.interface import Interface
+
+
+class CompositeError(Exception):
+    """An error in constructing a composite
+    """
+
+
+class IComposite(Interface):
+    """An object whose rendering is composed of a layout and elements.
+    """
+    slots = Attribute("An ISlotGenerator.")
+
+    def __call__():
+        """Renders the composite as a string.
+        """
+
+
+class ISlotGenerator(Interface):
+
+    def get(name, class_name=None, title=None):
+        """Returns a slot, creating it if it does not yet exist.
+
+        The 'class_name' and 'title' arguments allow the caller to
+        specify a slot class and title.  Both are used for composite
+        design purposes, not rendering.
+        """
+
+    def __getitem__(name):
+        """Returns a slot, creating it if it does not yet exist.
+        """
+
+
+class ISlot(Interface):
+    """A slot in a composite.
+    """
+
+    def single():
+        """Renders to a string as a single-element slot.
+        """
+
+    def multiple():
+        """Renders to a sequence of strings as a multiple-element slot.
+        """
+
+    def reorder(name, new_index):
+        """Moves an item to a new index.
+        """
+
+    def nullify(name):
+        """Removes an item from the slot, returning the old item.
+
+        Leaves a null element in its place.  The null element ensures
+        that other items temporarily keep their index within the slot.
+        """
+
+    def pack():
+        """Removes all null elements from the slot.
+        """
+
+
+class ISlotClass(Interface):
+    """Parameters and constraints for a slot.
+    """
+
+    # inline_templates is an attribute listing allowed template names.  If
+    # this list is not empty, it is intersected with the inline templates
+    # provided by the object type to determine what templates are
+    # available.  If this list is empty, all inline templates provided by
+    # the object type are available.
+
+    def findAvailableElements():
+        """Returns a list of elements available for this slot.
+
+        Generally returns catalog results.
+        """
+
+
+class ICompositeElement(Interface):
+    """Interface of objects that can be part of a composite.
+    """
+
+    def renderInline():
+        """Returns a representation of this object as a string.
+        """
+
+    def queryInlineTemplate(slot_class_name=None):
+        """Returns the name of the inline template this object uses.
+
+        Returns None if none has been chosen and there is no default.
+
+        The slot_class_name may be provided as an optimization.
+        """
+
+    def setInlineTemplate(template):
+        """Sets the inline template for this object.
+        """
+
+    def listAllowableInlineTemplates(slot_class_name=None):
+        """Returns a list of templates allowable for this object.
+
+        Returns a list of (template_name, template_object).
+
+        The slot_class_name may be provided as an optimization.
+        """
+
+    def dereference():
+        """Returns the object to be rendered.
+        """

Copied: CompositePage/trunk/Products/CompositePage/perm_names.py (from rev 121488, CompositePage/trunk/perm_names.py)
===================================================================
--- CompositePage/trunk/Products/CompositePage/perm_names.py	                        (rev 0)
+++ CompositePage/trunk/Products/CompositePage/perm_names.py	2011-04-30 19:15:39 UTC (rev 121490)
@@ -0,0 +1,21 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Foundation 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.
+# 
+##############################################################################
+"""Names of permissions used by CompositePage.
+
+$Id: perm_names.py,v 1.1 2003/10/01 18:59:31 shane Exp $
+"""
+
+change_composites_perm = "Change Composites"
+view_perm = "View"
+

Copied: CompositePage/trunk/Products/CompositePage/rawfile.py (from rev 121488, CompositePage/trunk/rawfile.py)
===================================================================
--- CompositePage/trunk/Products/CompositePage/rawfile.py	                        (rev 0)
+++ CompositePage/trunk/Products/CompositePage/rawfile.py	2011-04-30 19:15:39 UTC (rev 121490)
@@ -0,0 +1,115 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Foundation 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.3 2004/04/03 16:35:32 shane Exp $
+"""
+
+import os
+from os import stat
+from time import time
+
+import Acquisition
+from Acquisition import aq_inner, aq_parent
+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
+        self.cch = 'public, max-age=3600'  # One hour
+
+        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()
+        data = self.interp(data)
+        return data
+
+    def interp(self, data):
+        """Hook point for subclasses that modify the file content.
+        """
+        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 ''
+
+
+class InterpolatedFile(RawFile):
+    """Text data, stored in a file, with %(xxx)s interpolation.
+    """
+
+    def interp(self, data):
+        parent_url = aq_parent(aq_inner(self)).absolute_url()
+        d = {
+            "parent_url": parent_url,
+            }
+        return data % d
+

Copied: CompositePage/trunk/Products/CompositePage/slot.py (from rev 121488, CompositePage/trunk/slot.py)
===================================================================
--- CompositePage/trunk/Products/CompositePage/slot.py	                        (rev 0)
+++ CompositePage/trunk/Products/CompositePage/slot.py	2011-04-30 19:15:39 UTC (rev 121490)
@@ -0,0 +1,271 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Foundation 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.21 2004/04/26 09:30:25 gotcha Exp $
+"""
+
+import os
+import sys
+from cgi import escape
+
+import Globals
+from Acquisition import aq_base
+from Acquisition import aq_inner
+from Acquisition import aq_parent
+from Acquisition import aq_get
+from ZODB.POSException import ConflictError
+from OFS.SimpleItem import SimpleItem
+from Products.PageTemplates.PageTemplateFile import PageTemplateFile
+from AccessControl import ClassSecurityInfo
+from zLOG import LOG, ERROR
+from zope.interface import implements
+
+from Products.CompositePage.interfaces import ICompositeElement
+from Products.CompositePage.interfaces import ISlot
+from Products.CompositePage.perm_names import view_perm
+from Products.CompositePage.perm_names import change_composites_perm
+
+
+try:
+    # Use OrderedFolder if it's available.
+    from OFS.OrderedFolder import OrderedFolder
+except ImportError:
+    # Fall back to normal folders, which happen to retain order anyway.
+    from OFS.Folder import Folder as OrderedFolder
+
+_www = os.path.join(os.path.dirname(__file__), "www")
+
+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">
+<div class="slot_element_body">%s</div>
+</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>
+%s
+</div>'''
+
+# error_tag lets the user click on the 'log' link even if the
+# container normally stops clicks.
+error_tag = '''<span class="slot_error">%s
+(<a href="%s" onmousedown="document.location=this.href">log</a>)</span>'''
+
+
+class NullElement(SimpleItem):
+    """Empty placeholder for slot content
+    """
+    meta_type = "Temporary Empty Slot Content"
+
+    def __init__(self, id):
+        self.id = id
+
+
+class Slot(OrderedFolder):
+    """A slot in a composite.
+    """
+    implements(ISlot)
+    meta_type = "Composite Slot"
+
+    security = ClassSecurityInfo()
+
+    null_element = NullElement("null_element")
+
+
+    def __init__(self, id):
+        self.id = id
+
+    def all_meta_types(self):
+        return OrderedFolder.all_meta_types(
+            self, interfaces=(ICompositeElement,))
+
+    security.declareProtected(view_perm, "single")
+    def single(self):
+        """Renders as a single-element slot.
+
+        Attempts to prevent the user from adding multiple elements
+        by not providing insertion points when the slot already
+        contains elements.
+        """
+        allow_add = (not self._objects)
+        return "".join(self.renderToList(allow_add))
+
+    security.declareProtected(view_perm, "multiple")
+    def multiple(self):
+        """Renders as a list containing multiple elements.
+        """
+        return self.renderToList(1)
+
+    def __str__(self):
+        """Renders as a string containing multiple elements.
+        """
+        return "".join(self.renderToList(1))
+
+    __unicode__ = __str__
+
+    security.declareProtected(change_composites_perm, "reorder")
+    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)
+
+    security.declareProtected(change_composites_perm, "nullify")
+    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
+
+    security.declareProtected(change_composites_perm, "nullify")
+    def pack(self):
+        objs = [info for info in self._objects if info["id"] != "null_element"]
+        self._objects = tuple(objs)
+
+    security.declareProtected(view_perm, "renderToList")
+    def renderToList(self, allow_add):
+        """Renders the items to a list.
+        """
+        res = ['<div class="slot_header"></div>']
+        composite = aq_parent(aq_inner(aq_parent(aq_inner(self))))
+        editing = composite.isEditing()
+        items = self.objectItems()
+        if editing:
+            mypath = escape('/'.join(self.getPhysicalPath()))
+            myid = self.getId()
+            if hasattr(self, 'portal_url'):
+                icon_base_url = self.portal_url()
+            else:
+                request = getattr(self, 'REQUEST', None)
+                if request is not None:
+                    icon_base_url = request['BASEPATH1']
+                else:
+                    icon_base_url = '/'
+
+        if editing and allow_add:
+            res.append(self._render_add_target(myid, 0, mypath))
+
+        for index in range(len(items)):
+            name, obj = items[index]
+
+            try:
+                assert ICompositeElement.providedBy(obj), (
+                    "Not a composite element: %s" % repr(obj))
+                text = obj.renderInline()
+            except ConflictError:
+                # Ugly ZODB requirement: don't catch ConflictErrors
+                raise
+            except:
+                text = formatException(self, editing)
+
+
+            if editing:
+                res.append(self._render_editing(obj, text, icon_base_url))
+            else:
+                res.append(view_tag % text)
+            
+            if editing and allow_add:
+                res.append(self._render_add_target(myid, index+1, mypath, obj.getId()))
+
+        return res
+
+    def _render_editing(self, obj, text, icon_base_url):
+        o2 = obj.dereference()
+        icon = getIconURL(o2, icon_base_url)
+        title = o2.title_and_id()
+        path = escape('/'.join(obj.getPhysicalPath()))
+        return edit_tag % (path,
+                               escape(icon), escape(title), text)
+
+    def _render_add_target(self, slot_id, index, path, obj_id=''):
+         return target_tag % (slot_id, index, path, index)
+         
+Globals.InitializeClass(Slot)
+
+
+def getIconURL(obj, icon_base_url):
+    base = aq_base(obj)
+    if hasattr(base, 'getIcon'):
+        icon = obj.getIcon()
+    elif hasattr(base, 'icon'):
+        icon = obj.icon
+    else:
+        icon = ""
+    if icon and '://' not in icon:
+        if not icon.startswith('/'):
+            icon = '/' + icon
+        icon = icon_base_url + icon
+    return icon
+
+
+def formatException(context, editing):
+    """Returns an HTML-ified error message.
+
+    If not editing, the message includes no details.
+    """
+    exc_info = sys.exc_info()
+    try:
+        if editing:
+            # Show editors the real error
+            t, v = exc_info[:2]
+            t = getattr(t, '__name__', t)
+            msg = "An error occurred. %s" % (
+                escape(('%s: %s' % (t, v))[:80]))
+        else:
+            # Show viewers a simplified error.
+            msg = ("An error occurred while generating "
+                    "this part of the page.")
+        try:
+            log = aq_get(context, '__error_log__', None, 1)
+            raising = getattr(log, 'raising', None)
+        except AttributeError:
+            raising = None
+
+        if raising is not None:
+            error_log_url = raising(exc_info)
+            return error_tag % (msg, error_log_url)
+        else:
+            LOG("Composite", ERROR, "Error in a page element",
+                error=exc_info)
+            return msg
+    finally:
+        del exc_info
+
+
+addSlotForm = PageTemplateFile("addSlotForm.zpt", _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)

Copied: CompositePage/trunk/Products/CompositePage/slotclass.py (from rev 121488, CompositePage/trunk/slotclass.py)
===================================================================
--- CompositePage/trunk/Products/CompositePage/slotclass.py	                        (rev 0)
+++ CompositePage/trunk/Products/CompositePage/slotclass.py	2011-04-30 19:15:39 UTC (rev 121490)
@@ -0,0 +1,66 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Foundation 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 classes.
+
+$Id: slotclass.py,v 1.1 2004/03/02 20:41:44 shane Exp $
+"""
+
+import os
+
+from Acquisition import aq_inner, aq_parent
+from OFS.SimpleItem import SimpleItem
+from OFS.PropertyManager import PropertyManager
+from Products.PageTemplates.PageTemplateFile import PageTemplateFile
+from zope.interface import implements
+
+from Products.CompositePage.interfaces import ISlotClass
+
+
+_www = os.path.join(os.path.dirname(__file__), "www")
+
+
+class SlotClass(SimpleItem, PropertyManager):
+    """Parameters and constraints for a slot.
+    """
+    implements(ISlotClass)
+    meta_type = "Composite Slot Class"
+    find_script = ""
+
+    manage_options = (PropertyManager.manage_options
+                      + SimpleItem.manage_options)
+
+    _properties = (
+        {'id': 'find_script', 'mode': 'w', 'type': 'string',
+         'label': 'Script that finds available elements',},
+        )
+
+    def findAvailableElements(self, slot):
+        if not self.find_script:
+            return None
+        tool = aq_parent(aq_inner(aq_parent(aq_inner(self))))
+        s = tool.restrictedTraverse(self.find_script)
+        return s(slot)
+
+
+addSlotClassForm = PageTemplateFile("addSlotClassForm.zpt", _www)
+
+def manage_addSlotClass(dispatcher, id, REQUEST=None):
+    """Adds a slot class to a composite tool.
+    """
+    ob = SlotClass()
+    ob._setId(id)
+    dispatcher._setObject(ob.getId(), ob)
+    if REQUEST is not None:
+        return dispatcher.manage_main(dispatcher, REQUEST)
+

Copied: CompositePage/trunk/Products/CompositePage/slotexpr.py (from rev 121488, CompositePage/trunk/slotexpr.py)
===================================================================
--- CompositePage/trunk/Products/CompositePage/slotexpr.py	                        (rev 0)
+++ CompositePage/trunk/Products/CompositePage/slotexpr.py	2011-04-30 19:15:39 UTC (rev 121490)
@@ -0,0 +1,105 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Foundation and Contributors.
+#
+# This software is subject to the provisions of the Zope Visible Source 
+# License, Version 1.0 (ZVSL).  A copy of the ZVSL 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
+#
+##############################################################################
+"""Support for 'slot:' expression type in ZPT.
+
+$Id: slotexpr.py,v 1.5 2004/05/03 16:02:40 sidnei Exp $
+"""
+
+import logging
+import re
+
+from zope.tales.tales import CompilerError
+
+from Products.CompositePage.interfaces import IComposite
+
+name_re = re.compile("\s*([a-zA-Z][a-zA-Z0-9_]*)")
+class_name_re = re.compile("\s*[(]([a-zA-Z][a-zA-Z0-9_]*)[)]")
+title_re = re.compile("\s*[']([^']+)[']")
+
+log = logging.getLogger(__name__)
+
+
+class SlotExpr(object):
+    """Slot expression type.
+
+    Provides a concise syntax for specifying composite slots in
+    ZPT.  An example slot expression, in context of ZPT:
+
+    <div tal:replace="slot: slot_name(class_name) 'Title'" />
+    """
+
+    def __init__(self, name, expr, engine):
+        self._s = s = expr.strip()
+        mo = name_re.match(s)
+        if mo is None:
+            raise CompilerError('Invalid slot expression "%s"' % s)
+        self._name = mo.group(1)
+        s = s[mo.end():]
+        mo = class_name_re.match(s)
+        if mo is not None:
+            self._class_name = mo.group(1)
+            s = s[mo.end():]
+        else:
+            self._class_name = None
+        mo = title_re.match(s)
+        if mo is not None:
+            self._title = mo.group(1)
+            s = s[mo.end():]
+        else:
+            self._title = None
+        if s.strip():
+            # Can't interpret some of the expression
+            raise CompilerError(
+                'Slot expression syntax error near %s' % repr(s))
+
+    def __call__(self, econtext):
+        context = econtext.contexts.get('options')
+        if context is None:
+            raise RuntimeError("Could not find options")
+        composite = context.get('composite')
+        if IComposite.providedBy(composite):
+            slot = composite.slots.get(
+                self._name, self._class_name, self._title)
+            # Render the slot
+            return unicode(slot)
+        else:
+            # Show the default content
+            return econtext.getDefault()
+
+    def __repr__(self):
+        return '<SlotExpr %s>' % repr(self._s)
+
+
+def registerSlotExprType():
+    # Register the 'slot:' expression type.
+
+    # Register with Products.PageTemplates.
+    try:
+        from Products.PageTemplates.Expressions import getEngine
+    except ImportError:
+        log.exception("Unable to register the slot expression type")
+    else:
+        engine = getEngine()
+        if not engine.getTypes().has_key('slot'):
+            engine.registerType('slot', SlotExpr)
+
+    # Register with zope.tales.
+    try:
+        from zope.tales.engine import Engine
+    except ImportError:
+        log.exception("Unable to register the slot expression type")
+    else:
+        if not Engine.getTypes().has_key('slot'):
+            Engine.registerType('slot', SlotExpr)

Copied: CompositePage/trunk/Products/CompositePage/tool.py (from rev 121488, CompositePage/trunk/tool.py)
===================================================================
--- CompositePage/trunk/Products/CompositePage/tool.py	                        (rev 0)
+++ CompositePage/trunk/Products/CompositePage/tool.py	2011-04-30 19:15:39 UTC (rev 121490)
@@ -0,0 +1,260 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Foundation 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.11 2004/03/02 20:41:44 shane Exp $
+"""
+
+import Globals
+from Acquisition import aq_base, aq_parent, aq_inner
+from OFS.SimpleItem import SimpleItem
+from OFS.Folder import Folder
+from OFS.CopySupport import _cb_encode, _cb_decode, cookie_path
+from AccessControl import ClassSecurityInfo
+from AccessControl.ZopeGuards import guarded_getattr
+
+from Products.CompositePage.interfaces import ICompositeElement
+from Products.CompositePage.interfaces import ISlot
+from Products.CompositePage.interfaces import ISlotClass
+from Products.CompositePage.interfaces import CompositeError
+from Products.CompositePage.element import CompositeElement
+from Products.CompositePage.utils import copyOf
+
+
+_uis = {}
+
+def registerUI(name, obj):
+    """Registers a page design UI for use with the composite tool.
+    """
+    if _uis.has_key(name):
+        raise RuntimeError("There is already a UI named %s" % name)
+    obj._setId(name)
+    _uis[name] = obj
+
+
+
+class DesignUIs(SimpleItem):
+    """The container of design user interface objects.
+
+    Makes page design UIs accessible through URL traversal.
+    """
+
+    def __init__(self, id):
+        self._setId(id)
+
+    def __getattr__(self, name):
+        try:
+            return _uis[name]
+        except KeyError:
+            raise AttributeError, name
+
+
+class SlotClassFolder(Folder):
+    """Container of slot classes.
+    """
+    meta_type = "Slot Class Folder"
+
+    def all_meta_types(self):
+        return Folder.all_meta_types(self, interfaces=(ISlotClass,))
+
+
+class CompositeTool(Folder):
+    """Page composition helper tool.
+    """
+    meta_type = "Composite Tool"
+    id = "composite_tool"
+
+    security = ClassSecurityInfo()
+
+    security.declarePublic("uis")
+    uis = DesignUIs("uis")
+
+    _properties = Folder._properties + (
+        {'id': 'default_inline_templates', 'mode': 'w', 'type': 'lines',
+         'label': 'Default inline template names',},
+        )
+
+    default_inline_templates = ()
+
+    _check_security = 1  # Turned off in unit tests
+
+    def __init__(self):
+        scf = SlotClassFolder()
+        scf._setId("slot_classes")
+        self._setObject(scf.id, scf)
+        self._reserved_names = ('slot_classes',)
+
+    security.declarePublic("moveElements")
+    def moveElements(self, source_paths, target_path, target_index, copy=0):
+        """Moves or copies 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, checking interfaces and security before
+        # making any changes.
+        root = self.getPhysicalRoot()
+        elements = []
+        target = root.restrictedTraverse(target_path)
+        assert ISlot.providedBy(target), repr(target)
+        for source in sources:
+            slot = root.restrictedTraverse(source[:-1])
+            assert ISlot.providedBy(slot), repr(slot)
+            element = slot.restrictedTraverse(source[-1])
+            elements.append(element)
+            if self._check_security:
+                target._verifyObjectPaste(element)
+
+        changed_slots = {}  # id(aq_base(slot)) -> slot
+        try:
+            if not copy:
+                # Replace items with nulls to avoid changing indexes
+                # while moving.
+                for source in sources:
+                    slot = root.restrictedTraverse(source[:-1])
+                    slot_id = id(aq_base(slot))
+                    if not changed_slots.has_key(slot_id):
+                        changed_slots[slot_id] = slot
+                    # Check security
+                    nullify = guarded_getattr(slot, "nullify")
+                    nullify(source[-1])
+
+            # Add the elements and reorder.
+            for element in elements:
+
+                if not ICompositeElement.providedBy(element):
+                    # Make a composite element wrapper.
+                    element = CompositeElement(element.getId(), element)
+
+                element = aq_base(element)
+                new_id = target._get_id(element.getId())
+                if copy:
+                    element = copyOf(element)
+                element._setId(new_id)
+                target._setObject(new_id, element)
+                # Check security
+                reorder = guarded_getattr(target, "reorder")
+                reorder(new_id, target_index)
+                target_index += 1
+        finally:
+            # Clear the nulls just added.
+            for slot in changed_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.providedBy(slot), repr(slot)
+                slot_id = id(aq_base(slot))
+                if not orig_slots.has_key(slot_id):
+                    orig_slots[slot_id] = slot
+                nullify = guarded_getattr(slot, "nullify")  # Check security
+                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/or 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"])
+
+
+    security.declarePublic("useClipboard")
+    def useClipboard(self, func, REQUEST,
+                     source_paths=None, target_path=None, target_index=None):
+        """Clipboard interaction.
+        """
+        resp = REQUEST['RESPONSE']
+        if func in ("cut", "copy"):
+            assert source_paths
+            items = []  # list of path tuples
+            cut = (func == 'cut')
+            for p in str(source_paths).split(':'):
+                items.append(p.split('/'))
+            data = _cb_encode((cut, items))
+            resp.setCookie('__cp', data, path=cookie_path(REQUEST))
+        elif func == 'paste':
+            assert target_path
+            assert target_index
+            assert REQUEST is not None
+            data = REQUEST['__cp']
+            cut, items = _cb_decode(data)
+            self.moveElements(
+                items, target_path, int(target_index), not cut)
+            resp.expireCookie('__cp', path=cookie_path(REQUEST))
+        else:
+            raise ValueError("Clipboard function %s unknown" % func)
+        resp.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)
+

Copied: CompositePage/trunk/Products/CompositePage/utils.py (from rev 121488, CompositePage/trunk/utils.py)
===================================================================
--- CompositePage/trunk/Products/CompositePage/utils.py	                        (rev 0)
+++ CompositePage/trunk/Products/CompositePage/utils.py	2011-04-30 19:15:39 UTC (rev 121490)
@@ -0,0 +1,70 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Foundation 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.
+#
+##############################################################################
+"""Utilities for handling ZODB objects.
+
+(Copied from the Ape product.)
+
+$Id: utils.py,v 1.1 2003/12/28 04:32:47 shane Exp $
+"""
+
+from cStringIO import StringIO
+from cPickle import Pickler, Unpickler
+
+
+def copyOf(source):
+    """Copies a ZODB object, loading subobjects as needed.
+
+    Re-ghostifies objects along the way to save memory.
+    """
+    former_ghosts = []
+    zclass_refs = {}
+
+    def persistent_id(ob, former_ghosts=former_ghosts,
+                      zclass_refs=zclass_refs):
+        if getattr(ob, '_p_changed', 0) is None:
+            # Load temporarily.
+            former_ghosts.append(ob)
+            ob._p_changed = 0
+        if hasattr(ob, '__bases__'):
+            m = getattr(ob, '__module__', None)
+            if (m is not None
+                and isinstance(m, basestring)
+                and m.startswith('*')):
+                n = getattr(ob, '__name__', None)
+                if n is not None:
+                    # Pickling a ZClass instance.  Store the reference to
+                    # the ZClass class separately, so that the pickler
+                    # and unpickler don't trip over the apparently
+                    # missing module.
+                    ref = (m, n)
+                    zclass_refs[ref] = ob
+                    return ref
+        return None
+
+    def persistent_load(ref, zclass_refs=zclass_refs):
+        return zclass_refs[ref]
+
+    stream = StringIO()
+    p = Pickler(stream, 1)
+    p.persistent_id = persistent_id
+    p.dump(source)
+    if former_ghosts:
+        for g in former_ghosts:
+            del g._p_changed
+        del former_ghosts[:]
+    stream.seek(0)
+    u = Unpickler(stream)
+    u.persistent_load = persistent_load
+    return u.load()
+

Copied: CompositePage/trunk/Products/CompositePage/version.txt (from rev 121488, CompositePage/trunk/version.txt)
===================================================================
--- CompositePage/trunk/Products/CompositePage/version.txt	                        (rev 0)
+++ CompositePage/trunk/Products/CompositePage/version.txt	2011-04-30 19:15:39 UTC (rev 121490)
@@ -0,0 +1 @@
+CompositePage-0.2

Deleted: CompositePage/trunk/README.txt
===================================================================
--- CompositePage/trunk/README.txt	2011-04-30 19:14:59 UTC (rev 121489)
+++ CompositePage/trunk/README.txt	2011-04-30 19:15:39 UTC (rev 121490)
@@ -1,205 +0,0 @@
-
-
-Contents
-========
-
-  - Introduction
-
-  - How to use CompositePage
-
-  - How to write a template
-
-  - How it works
-
-  - Adapting CompositePage to other applications
-
-  - Near-term directions
-
-
-
-Introduction
-============
-
-CompositePage is a new way to assemble pages for the World Wide Web.
-Through the use of Zope technology, browser-based drag and drop, and
-custom context menus, CompositePage makes it easy to visually combine
-page fragments into complete pages.
-
-CompositePage supercedes the PageDesign product and makes use of
-PDLib, a Javascript library.  CompositePage is designed for browsers
-that support the DOM (Document Object Model) and CSS (Cascading Style
-Sheets) level 2: Mozilla, Internet Explorer 5+, Opera, Konqueror, etc.
-Not all of these browsers have been tested, but it should be possible
-to solve most problems that occur.
-
-
-
-How to use CompositePage
-========================
-
-Follow these steps:
-
-- Install the CompositePage product in Zope by unpacking the archive
-into your Products directory.  I've tested only with a current Zope
-checkout, which is something like Zope 2.7.
-
-- Create a Composite Tool instance in a central location, possibly the
-root folder.
-
-- Create a Composite object.  On the creation form, there is a
-checkbox for creating a sample template.  Leave the checkbox checked.
-
-- Visit the Composite object and select the "Design" tab.  You should
-see a three-column layout with blue dotted lines in the places where
-you are allowed to insert content.
-
-- Click just beneath one of the blue lines.  A context menu will pop
-up.  Select "Add...".
-
-- You will be directed to a slot (a folderish object.)  In slots, you
-can add composite elements.  Add a composite element that points to a
-script.
-
-- Find the composite created earlier and select the "Design" tab
-again.  Your new object should now show up in the slot.
-
-- Move the object to a different slot using drag and drop.  When the
-mouse cursor is hovering over a permitted target (the blue dotted
-lines are targets), the target will be highlighted.  Let go and watch
-your object appear in the new place.
-
-- Right-click over your object and select "Delete" from the context
-menu.
-
-
-How to write a template
-=======================
-
-Templates can be any Zope object, but ZPTs (Zope Page Templates) are
-the most common.  A template designed for use with composites uses the
-'slots' attribute of the composite.  The 'slots' attribute is a
-mapping-like object.
-
-Here is a simple composite-aware page template::
-
-  <html>
-   <head>
-   </head>
-  <body>
-   <div tal:content="structure here/slots/center/single">
-   This will be replaced with one element from one slot.
-   </div>
-  </body>
-  </html>
-
-The expression 'here/slots/center/single' gets the 'slots' attribute
-of the composite, finds a slot named 'center', and calls the single()
-method of the slot, returning a string containing an HTML structure.
-
-The only place you have to name a slot is in the template.  If the
-template refers to a slot that does not yet exist, the composite will
-create and return an empty slot.  If you place something in that slot
-using the drag and drop interface, the composite will transparently
-add a new slot to the 'filled_slots' folder.  Note that Zope prevents
-you from storing slots with names that start with an underscore or
-that clash existing folder attributes.
-
-Templates use either the single() or the multiple() method of a slot.
-single() returns a string, while multiple() returns a list of strings.
-Use single() when you expect the slot to never contain more than one
-element.  Use multiple() to allow more than one element.  In either
-case, don't forget to use the ZPT 'structure' keyword, since the
-returned strings contain HTML that should not be escaped.
-
-
-
-How it works
-============
-
-Rendering:
-
-When you render (view) a composite, it calls its template.  When the
-template refers to a slot, the composite looks for the named slot in
-the filled_slots folder.  If it finds the slot, it returns it; if it
-doesn't find it, the composite creates a temporary empty slot.  Then
-the template calls either the single() or multiple() method and the
-slot renders and returns its contents.
-
-
-Rendering in edit mode:
-
-When requested, the composite calls upon a "UI" object to render its
-template and slots with edit mode turned on.  In edit mode, slots add
-'class', 'source_path', 'target_path', and 'target_index' attributes
-to HTML tags to mark movable objects and available drop targets.
-Slots add HTML markup for drop targets automatically.  When rendering
-using the single() method, slots provide a drop target only if the
-slot is empty.  When rendering using the multiple() method, slots
-insert drop targets between the elements and to the beginning and end
-of the slot.
-
-The UI object can use various mechanisms to make the page editable.
-Most UI objects use regular expressions to find the 'head' and 'body'
-tags.  Then the UI object inserts scripts, styles, and HTML elements.
-The result of the transformation is sent back to the browser.
-
-
-Drag and drop:
-
-At the bottom of a page rendered in edit mode is a call to the
-pd_setupPage() Javascript function.  pd_setupPage() searches all of
-the elements on the page, looking for elements with particular 'class'
-attributes.  When it finds a 'slot_element', a handler adds event
-listeners to that element that react when the user presses the mouse
-button in that element.  When pd_setupPage() finds a 'slot_target',
-another handler adds event listeners that react when the user drags
-into that element.
-
-If the user releases the mouse while dragging into a target, the
-Javascript code puts the appropriate source paths, target paths, and
-target indexes into a hidden form and submits that form to the
-composite tool in Zope.  The composite tool moves the elements then
-redirects the browser to the original page.  The browser loads the
-page in edit mode again and the moved element gets rendered in its new
-spot.
-
-
-Context menus:
-
-Like drag and drop, context menus depend on pd_setupPage().  When
-pd_setupPage() finds a 'slot_element', a handler adds a context menu
-listener to that element.  The context menu listener, when activated,
-positions and displays an otherwise invisible HTML element that looks
-just like a context menu.  Once displayed, the user is expected to
-either select an item from the context menu or click outside the
-context menu to make it disappear.  A similar process exists for
-'slot_target' elements, but a different invisible HTML element is
-used.
-
-Just before popping up a context menu, its contents are filtered using
-Javascript expressions.  Some actions are valid only when the user has
-selected at least one item, and other actions are valid only when
-exactly one item item is selected.  Filter expressions provide a way
-to express these constraints.
-
-
-
-Adapting CompositePage to other applications
-============================================
-
-CompositePage provides a default user interface that integrates with
-the Zope management interface, but mechanisms are provided for
-integrating with any user interface.  Look at design.py, the 'common'
-subdirectory, and the 'zmi' subdirectory for guidance.  Simple
-customizations probably do not require more code than ZMIUI.
-
-
-
-Near-term directions
-====================
-
-I would like CompositePage to work reliably with as many browsers as
-possible, but Mozilla 1.4 is the current reference browser.  Try it in
-your preferred browser.  If it acts strangely, try the same thing in
-Mozilla 1.4 and send an email describing the differences.
-

Deleted: CompositePage/trunk/__init__.py
===================================================================
--- CompositePage/trunk/__init__.py	2011-04-30 19:14:59 UTC (rev 121489)
+++ CompositePage/trunk/__init__.py	2011-04-30 19:15:39 UTC (rev 121490)
@@ -1,72 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2003 Zope Foundation and Contributors.
-#
-# 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.7 2004/03/05 21:41:04 shane Exp $
-"""
-
-import tool, element, composite, slot, slotclass, designuis, interfaces
-import slotexpr
-
-slotexpr.registerSlotExprType()
-
-tool.registerUI("common", designuis.CommonUI())
-tool.registerUI("zmi", designuis.ZMIUI())
-tool.registerUI("cmf", designuis.CMFUI())
-tool.registerUI("manual", designuis.ManualUI())
-
-
-def initialize(context):
-
-    context.registerClass(
-        tool.CompositeTool,
-        constructors=(tool.manage_addCompositeTool,),
-        icon="www/comptool.gif",
-        )
-
-    context.registerClass(
-        element.CompositeElement,
-        constructors=(element.addElementForm,
-                      element.manage_addElement,
-                      ),
-        visibility=None,
-        icon="www/element.gif",
-        )
-
-    context.registerClass(
-        slotclass.SlotClass,
-        constructors=(slotclass.addSlotClassForm,
-                      slotclass.manage_addSlotClass,
-                      ),
-        interfaces=(interfaces.ISlotClass,),
-        visibility=None,
-        icon="www/slot.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,
-        icon="www/slot.gif",
-        )

Deleted: CompositePage/trunk/composite.py
===================================================================
--- CompositePage/trunk/composite.py	2011-04-30 19:14:59 UTC (rev 121489)
+++ CompositePage/trunk/composite.py	2011-04-30 19:15:39 UTC (rev 121490)
@@ -1,367 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2003 Zope Foundation and Contributors.
-#
-# 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.24 2004/04/15 22:13:44 shane Exp $
-"""
-
-import os
-import re
-
-import Globals
-import Acquisition
-from Acquisition import aq_base
-from Acquisition import aq_inner
-from Acquisition import aq_parent
-from Acquisition import aq_get
-from OFS.Folder import Folder
-from OFS.SimpleItem import SimpleItem
-from Products.PageTemplates.PageTemplateFile import PageTemplateFile
-from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate
-from AccessControl import ClassSecurityInfo
-from AccessControl.ZopeGuards import guarded_getattr
-from zope.interface import implements
-
-from Products.CompositePage.interfaces import IComposite
-from Products.CompositePage.interfaces import ISlot
-from Products.CompositePage.interfaces import ISlotGenerator
-from Products.CompositePage.interfaces import CompositeError
-from Products.CompositePage.slot import Slot
-from Products.CompositePage.slot import getIconURL
-from Products.CompositePage.slot import formatException
-from Products.CompositePage.perm_names import view_perm
-from Products.CompositePage.perm_names import change_composites_perm
-
-_www = os.path.join(os.path.dirname(__file__), "www")
-
-
-class SlotGenerator(Acquisition.Explicit):
-    """Automatically makes slots available to the template.
-
-    Note: instances of this class are shared across threads.
-    """
-    _slot_class = Slot
-
-    def get(self, name, class_name=None, title=None):
-        """Returns a slot by name.
-
-        This is designed to be called in the middle of a page
-        template.  Assigns attributes (class_name and title) to the
-        slot at the same time.
-        """
-        name = str(name)
-        composite = aq_parent(aq_inner(self))
-        composite._usingSlot(name, class_name, title)
-        slots = composite.filled_slots
-        if slots.hasObject(name):
-            return slots[name]
-        else:
-            # Generate a new slot.
-            s = self._slot_class(name)
-            if composite.isEditing():
-                # Persist the slot.
-                slots._setObject(s.getId(), s)
-            # else don't persist the slot.
-            return s.__of__(slots)
-
-    __getitem__ = get
-
-
-class CompositeMixin:
-    """Base class for editable composite pages.
-
-    Composite pages are assemblies of templates and composite
-    elements.  This base class provides the nuts and bolts of a
-    composite editing interface.
-    """
-    implements(IComposite)
-    meta_type = "Composite"
-
-    security = ClassSecurityInfo()
-
-    manage_options = (
-        {"label": "Design", "action": "manage_designForm",},
-        {"label": "View", "action": "view",},
-        )
-
-    default_ui = "common"
-    template_path = "template"
-    _v_editing = 0
-    _v_rendering = 0
-    _v_slot_specs = None  # [{'name', 'class', 'title'}]
-
-    security.declarePublic("slots")
-    slots = SlotGenerator()
-
-    _properties = (
-        {"id": "template_path", "mode": "w", "type": "string",
-         "label": "Path to template"},
-        )
-
-    security.declareProtected(view_perm, "hasTemplate")
-    def hasTemplate(self):
-        if self.template_path:
-            return 1
-        return 0
-
-    security.declareProtected(view_perm, "getTemplate")
-    def getTemplate(self):
-        if not self.template_path:
-            raise CompositeError("No template set")
-        return self.restrictedTraverse(str(self.template_path))
-
-    security.declareProtected(change_composites_perm, "generateSlots")
-    def generateSlots(self):
-        """Creates the slots defined by the template.
-        """
-        self._v_editing = 1
-        try:
-            self()
-        finally:
-            self._v_editing = 0
-
-    security.declareProtected(view_perm, "__call__")
-    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(composite=self)
-        finally:
-            self._v_rendering = 0
-
-    view = __call__
-
-    index_html = None
-
-    security.declareProtected(change_composites_perm, "design")
-    def design(self, ui=None):
-        """Renders the composite with editing features.
-        """
-        # Never cache a design view.
-        req = getattr(self, "REQUEST", None)
-        if req is not None:
-            req["RESPONSE"].setHeader("Cache-Control", "no-cache")
-        ui_obj = self.getUI(ui)
-        self._v_editing = 1
-        try:
-            return ui_obj.render(self)
-        finally:
-            self._v_editing = 0
-
-    security.declareProtected(change_composites_perm, "manage_designForm")
-    def manage_designForm(self):
-        """Renders the composite with editing and ZMI features.
-        """
-        return self.design("zmi")
-
-    security.declareProtected(change_composites_perm, "getUI")
-    def getUI(self, ui=None):
-        """Returns a UI object.
-        """
-        if not ui:
-            ui = self.default_ui
-        tool = aq_get(self, "composite_tool", None, 1)
-        if tool is None:
-            raise CompositeError("No composite_tool found")
-        return guarded_getattr(tool.uis, ui)
-
-    def _usingSlot(self, name, class_name, title):
-        """Receives notification that the template is using a slot.
-
-        Even though slots are persisted, only the template knows
-        exactly what slots are in use.  This callback gives the
-        composite a chance to learn about the slots in use.  This is
-        designed for editing purposes, not rendering.
-        """
-        if self._v_slot_specs is not None:
-            # Record the slot spec.
-            self._v_slot_specs.append({
-                'name': name,
-                'class_name': class_name,
-                'title': title,
-                })
-
-    security.declareProtected(change_composites_perm, "getSlotSpecs")
-    def getSlotSpecs(self):
-        """Returns the slot specs within the template.
-
-        Returns [{'name', 'class_name', 'title'}].  May return duplicates.
-        """
-        self._v_editing = 1
-        self._v_slot_specs = []
-        try:
-            self()
-            slots = self._v_slot_specs
-            return slots
-        finally:
-            self._v_editing = 0
-            self._v_slot_specs = None
-
-    security.declareProtected(change_composites_perm, "getSlotClassName")
-    def getSlotClassName(self, slot_name):
-        """Returns the class_name of a slot.
-
-        Returns None if no class is defined for the slot.  Raises
-        KeyError if no such slot exists.
-        """
-        specs = self.getSlotSpecs()
-        for spec in specs:
-            if spec['name'] == slot_name:
-                return spec['class_name']
-        raise KeyError(slot_name)
-
-    security.declareProtected(change_composites_perm, "getManifest")
-    def getManifest(self):
-        """Returns a manifest of slot contents.
-
-        Designed for use by page templates that implement a manual
-        slotting user interface.
-        """
-        contents = []  # [{name, slot_info}]
-        seen = {}
-        specs = self.getSlotSpecs()
-        if hasattr(self, 'portal_url'):
-            icon_base_url = self.portal_url()
-        else:
-            request = getattr(self, 'REQUEST', None)
-            if request is not None:
-                icon_base_url = request['BASEPATH1']
-            else:
-                icon_base_url = ''
-        for spec in specs:
-            name = spec['name']
-            if seen.has_key(name):
-                # Don't show duplicate uses of a slot.
-                continue
-            seen[name] = 1
-            slot = self.slots[name]
-            elements = []
-            index = 0
-            slot_values = slot.objectValues()
-            for element in slot_values:
-                error = None
-                template = None
-                templates = ()
-                try:
-                    ob = element.dereference()
-                    template = element.queryInlineTemplate(spec['class_name'])
-                    templates = element.listAllowableInlineTemplates(
-                        spec['class_name'])
-                except:
-                    error = formatException(self, editing=1)
-                    ob = FailedElement().__of__(self)
-                icon = getIconURL(ob, icon_base_url)
-                available_templates = []
-                for name, t in templates:
-                    if hasattr(aq_base(t), 'title_or_id'):
-                        title = t.title_or_id()
-                    else:
-                        title = name
-                    available_templates.append({'id': name, 'title': title})
-                element_info = {
-                    'title': ob.title_or_id(),
-                    'icon': icon,
-                    'error': error,
-                    'source_path': '/'.join(element.getPhysicalPath()),
-                    'index': index,
-                    'next_index': index + 1,
-                    'can_move_up': (index > 0),
-                    'can_move_down': (index < len(slot_values) - 1),
-                    'template': template,
-                    'available_templates': available_templates,
-                    }
-                elements.append(element_info)
-                index += 1
-            slot_info = {
-                'name': name,
-                'title': spec['title'] or name,
-                'class_name': spec['class_name'],
-                'target_path': '/'.join(slot.getPhysicalPath()),
-                'elements': elements,
-                }
-            contents.append(slot_info)
-        return contents
-
-    security.declareProtected(view_perm, "isEditing")
-    def isEditing(self):
-        """Returns true if currently rendering in design mode.
-        """
-        return self._v_editing
-
-Globals.InitializeClass(CompositeMixin)
-
-
-class SlotCollection(Folder):
-    """Stored collection of composite slots.
-    """
-    meta_type = "Slot Collection"
-
-    def all_meta_types(self):
-        return Folder.all_meta_types(self, interfaces=(ISlot,))
-
-
-class Composite(CompositeMixin, Folder):
-    """An HTML fragment composed from a template and fragments.
-
-    Fragments are stored on a container called 'filled_slots'.
-    """
-
-    manage_options = (
-        Folder.manage_options[:1]
-        + CompositeMixin.manage_options
-        + Folder.manage_options[2:]
-        )
-
-    _properties = Folder._properties + CompositeMixin._properties
-
-    def __init__(self):
-        f = SlotCollection()
-        f._setId("filled_slots")
-        self._setObject(f.getId(), f)
-
-Globals.InitializeClass(Composite)
-
-
-class FailedElement(SimpleItem):
-    meta_type = "Failed Element"
-    icon = 'p_/broken'
-    id = 'error'
-    title = 'Error'
-
-
-addCompositeForm = PageTemplateFile("addCompositeForm.zpt", _www)
-
-def manage_addComposite(dispatcher, id, title="", create_sample="",
-                        REQUEST=None):
-    """Adds a composite to a folder.
-    """
-    ob = Composite()
-    ob._setId(id)
-    ob.title = unicode(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)

Deleted: CompositePage/trunk/designuis.py
===================================================================
--- CompositePage/trunk/designuis.py	2011-04-30 19:14:59 UTC (rev 121489)
+++ CompositePage/trunk/designuis.py	2011-04-30 19:15:39 UTC (rev 121490)
@@ -1,345 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2002 Zope Foundation 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.
-# 
-##############################################################################
-"""Page design UI classes.
-
-$Id: designuis.py,v 1.10 2004/04/06 16:50:25 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 AccessControl.ZopeGuards import guarded_getattr
-
-from Products.CompositePage.rawfile import RawFile
-from Products.CompositePage.rawfile import InterpolatedFile
-from Products.CompositePage.interfaces import ICompositeElement
-
-
-_common = os.path.join(os.path.dirname(__file__), "common")
-_zmi = os.path.join(os.path.dirname(__file__), "zmi")
-_cmf = os.path.join(os.path.dirname(__file__), "cmf")
-_manual = os.path.join(os.path.dirname(__file__), "manual")
-
-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>
-"""
-
-close_dialog_html = '''<html>
-<script type="text/javascript">
-if (window.opener)
-  window.opener.location.reload();
-window.close();
-</script>
-</html>
-'''
-
-class CommonUI(SimpleItem):
-    """Basic page design UI.
-
-    Adds editing features to a rendered composite.
-    """
-
-    security = ClassSecurityInfo()
-
-    security.declarePublic(
-        "pdlib_js", "design_js", "pdstyles_css", "designstyles_css")
-    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 = InterpolatedFile("editstyles.css", "text/css", _common)
-    target_image = RawFile("target.gif", "image/gif", _common)
-    target_image_hover = RawFile("target_hover.gif", "image/gif", _common)
-    target_image_active = RawFile("target_active.gif", "image/gif", _common)
-    element_image = RawFile("element.gif", "image/gif", _common)
-
-    header_templates = (PageTemplateFile("header.pt", _common),)
-    top_templates = ()
-    bottom_templates = (PageTemplateFile("bottom.pt", _common),)
-
-    changeTemplateForm = PageTemplateFile("changeTemplateForm.pt", _common)
-
-    workspace_view_name = "view"  # To be overridden
-
-    security.declarePublic("getFragments")
-    def getFragments(self, composite):
-        """Returns the fragments to be inserted in design mode.
-        """
-        params = {
-            "tool": aq_parent(aq_inner(aq_parent(aq_inner(self)))),
-            "ui": 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)
-        return {"header": header, "top": top, "bottom": bottom}
-
-
-    security.declarePrivate("render")
-    def render(self, composite):
-        """Renders a composite, adding scripts and styles.
-        """
-        text = composite()
-        fragments = self.getFragments(composite)
-        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 fragments['header']:
-            index = match.end(0)
-            text = "%s%s%s" % (text[:index], fragments['header'], text[index:])
-        if fragments['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], fragments['top'], text[index:])
-        if fragments['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], fragments['bottom'], text[index:])
-        return text
-
-
-    security.declarePublic("showElement")
-    def showElement(self, path, RESPONSE):
-        """Redirects to the workspace for an element.
-        """
-        root = self.getPhysicalRoot()
-        obj = root.restrictedTraverse(path)
-        if ICompositeElement.providedBy(obj):
-            obj = obj.dereference()
-        RESPONSE.redirect("%s/%s" % (
-            obj.absolute_url(), self.workspace_view_name))
-
-
-    security.declarePublic("previewElement")
-    def previewElement(self, path, RESPONSE):
-        """Redirects to the preview for an element.
-        """
-        root = self.getPhysicalRoot()
-        obj = root.restrictedTraverse(path)
-        if ICompositeElement.providedBy(obj):
-            obj = obj.dereference()
-        RESPONSE.redirect(obj.absolute_url())
-
-
-    security.declarePublic("showSlot")
-    def showSlot(self, path, RESPONSE):
-        """Redirects to (and possibly creates) the workspace for a slot.
-        """
-        from composite import Composite
-
-        obj = self.getPhysicalRoot()
-        parts = str(path).split('/')
-        for name in parts:
-            obj = obj.restrictedTraverse(name)
-            if IComposite.providedBy(obj):
-                gen = guarded_getattr(obj, "generateSlots")
-                gen()
-        RESPONSE.redirect("%s/%s" % (
-            obj.absolute_url(), self.workspace_view_name))
-
-
-    security.declarePublic("getTemplateChangeInfo")
-    def getTemplateChangeInfo(self, paths):
-        """Returns information for changing the template applied to objects.
-        """
-        root = self.getPhysicalRoot()
-        tool = aq_parent(aq_inner(self))
-        obs = []
-        all_choices = None  # {template -> 1}
-        current = None
-        for path in str(paths).split(':'):
-            ob = root.unrestrictedTraverse(path)
-            obs.append(ob)
-            if not ICompositeElement.providedBy(ob):
-                raise ValueError("Not a composite element: %s" % path)
-            m = guarded_getattr(ob, "queryInlineTemplate")
-            template = m()
-            if current is None:
-                current = template
-            elif current and current != template:
-                # The current template isn't the same for all of the elements,
-                # so there is no common current template.  Spell this condition
-                # using a non-string value.
-                current = 0
-            m = guarded_getattr(ob, "listAllowableInlineTemplates")
-            templates = m()
-            d = {}
-            for name, template in templates:
-                d[name] = template
-            if all_choices is None:
-                all_choices = d
-            else:
-                for template in all_choices.keys():
-                    if not d.has_key(template):
-                        del all_choices[template]
-        return {
-            "obs": obs,
-            "templates": all_choices,
-            "current_template": current,
-            }
-
-
-    security.declarePublic("changeTemplate")
-    def changeTemplate(self, paths, template, reload=0, close=1, REQUEST=None):
-        """Changes the template for objects.
-        """
-        info = self.getTemplateChangeInfo(paths)
-        if template not in info["templates"]:
-            raise KeyError("Template %s is not among the choices" % template)
-        tool = aq_parent(aq_inner(self))
-        for ob in info["obs"]:
-            assert ICompositeElement.providedBy(ob)
-            m = guarded_getattr(ob, "setInlineTemplate")
-            m(template)
-        if REQUEST is not None:
-            if reload:
-                REQUEST["RESPONSE"].redirect(REQUEST["HTTP_REFERER"])
-            elif close:
-                return close_dialog_html
-
-Globals.InitializeClass(CommonUI)
-
-
-
-class ZMIUI (CommonUI):
-    """Page design UI meant to fit the Zope management interface.
-
-    Adds editing features to a rendered composite.
-    """
-    security = ClassSecurityInfo()
-
-    workspace_view_name = "manage_workspace"
-
-    security.declarePublic("zmi_edit_js")
-    zmi_edit_js = RawFile("zmi_edit.js", "text/javascript", _zmi)
-
-    header_templates = CommonUI.header_templates + (
-        PageTemplateFile("header.pt", _zmi),)
-    top_templates = CommonUI.top_templates + (
-        PageTemplateFile("top.pt", _zmi),)
-    bottom_templates = (PageTemplateFile("bottom.pt", _zmi),
-                        ) + CommonUI.bottom_templates
-
-Globals.InitializeClass(ZMIUI)
-
-
-
-class CMFUI (CommonUI):
-    """Page design UI meant to fit CMF.
-
-    Adds CMF-specific scripts and styles to a page.
-    """
-    security = ClassSecurityInfo()
-
-    workspace_view_name = "view"
-
-    security.declarePublic("cmf_edit_js")
-    cmf_edit_js = RawFile("cmf_edit.js", "text/javascript", _cmf)
-
-    header_templates = CommonUI.header_templates + (
-        PageTemplateFile("header.pt", _cmf),)
-    bottom_templates = (PageTemplateFile("bottom.pt", _cmf),
-                        ) + CommonUI.bottom_templates
-
-Globals.InitializeClass(CMFUI)
-
-
-
-class ManualUI (CommonUI):
-    """Non-WYSIWYG page design UI.
-    """
-    security = ClassSecurityInfo()
-
-    body = PageTemplateFile("body.pt", _manual)
-    manual_styles_css = InterpolatedFile(
-        "manual_styles.css", "text/css", _manual)
-    header_templates = (PageTemplateFile("header.pt", _manual),)
-    bottom_templates = CommonUI.bottom_templates + (
-        PageTemplateFile("bottom.pt", _manual),)
-    manual_js = RawFile("manual.js", "text/javascript", _manual)
-    add_icon = RawFile("add.gif", "image/gif", _manual)
-    add_rollover = RawFile("add_rollover.gif", "image/gif", _manual)
-    remove_icon = RawFile("remove.gif", "image/gif", _manual)
-    remove_rollover = RawFile("remove_rollover.gif", "image/gif", _manual)
-    cut_icon = RawFile("cut.gif", "image/gif", _manual)
-    cut_rollover = RawFile("cut_rollover.gif", "image/gif", _manual)
-    copy_icon = RawFile("copy.gif", "image/gif", _manual)
-    copy_rollover = RawFile("copy_rollover.gif", "image/gif", _manual)
-    paste_icon = RawFile("paste.gif", "image/gif", _manual)
-    paste_rollover = RawFile("paste_rollover.gif", "image/gif", _manual)
-
-    security.declarePublic("renderBody")
-    def renderBody(self, composite):
-        """Renders the slotting interface for a composite.
-
-        Returns an HTML fragment without the required scripts and
-        styles.
-        """
-        manifest = composite.getManifest()
-        pt = self.body.__of__(composite)
-        return pt(ui=self, manifest=manifest)
-
-    security.declarePublic("render")
-    def render(self, composite):
-        """Renders a ZMI slotting interface for a composite.
-
-        Returns a full HTML page with scripts and styles.
-        """
-        fragments = self.getFragments(composite)
-        body = self.renderBody(composite)
-        res = []
-        res.append(composite.manage_page_header())
-        res.append(composite.manage_tabs())
-        res.append(fragments["header"])
-        res.append(fragments["top"])
-        res.append(body)
-        res.append(fragments["bottom"])
-        res.append(composite.manage_page_footer())
-        return '\n'.join(res)
-
-Globals.InitializeClass(ManualUI)

Deleted: CompositePage/trunk/element.py
===================================================================
--- CompositePage/trunk/element.py	2011-04-30 19:14:59 UTC (rev 121489)
+++ CompositePage/trunk/element.py	2011-04-30 19:15:39 UTC (rev 121490)
@@ -1,116 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2003 Zope Foundation and Contributors.
-#
-# 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 element.
-
-$Id: element.py,v 1.5 2004/04/14 16:15:29 sidnei Exp $
-"""
-
-import os
-
-import Globals
-from AccessControl.SecurityInfo import ClassSecurityInfo
-from Acquisition import aq_get
-from OFS.SimpleItem import SimpleItem
-from OFS.PropertyManager import PropertyManager
-from Products.PageTemplates.PageTemplateFile import PageTemplateFile
-from DocumentTemplate.DT_Util import safe_callable
-
-from zope.interface import implements
-
-from Products.CompositePage.interfaces import ICompositeElement
-
-_www = os.path.join(os.path.dirname(__file__), "www")
-
-
-class CompositeElement(SimpleItem, PropertyManager):
-    """A simple path-based reference to an object and a template.
-
-    You can render it and choose which template to apply for rendering.
-    """
-    implements(ICompositeElement)
-    meta_type = "Composite Element"
-    security = ClassSecurityInfo()
-    manage_options = PropertyManager.manage_options + SimpleItem.manage_options
-
-    _properties = (
-        {'id': 'path', 'type': 'string', 'mode': 'w',},
-        {'id': 'template_name', 'type': 'string', 'mode': 'w',},
-        )
-
-    template_name = ''
-
-    def __init__(self, id, obj):
-        self.id = id
-        self.path = '/'.join(obj.getPhysicalPath())
-
-    def dereference(self):
-        """Returns the object referenced by this composite element.
-        """
-        return self.restrictedTraverse(self.path)
-
-    def renderInline(self):
-        """Returns a representation of this object as a string.
-        """
-        obj = self.dereference()
-        name = self.template_name
-        if not name:
-            # Default to the first allowable inline template.
-            names = self.listAllowableInlineTemplates()
-            if names:
-                name = names[0]
-        if name and name != "call":
-            template = obj.restrictedTraverse(str(name))
-            return template()
-        # Special template name "call" means to call the object.
-        if safe_callable(obj):
-            return obj()
-        return unicode(obj)
-
-    def queryInlineTemplate(self, slot_class_name=None):
-        """Returns the name of the inline template this object uses.
-        """
-        return self.template_name
-
-    def setInlineTemplate(self, template):
-        """Sets the inline template for this object.
-        """
-        self.template_name = str(template)
-
-    def listAllowableInlineTemplates(self, slot_class_name=None):
-        """Returns a list of inline template names allowable for this object.
-        """
-        tool = aq_get(self, "composite_tool", None, 1)
-        if tool is not None:
-            res = []
-            for name in tool.default_inline_templates:
-                template = obj.restrictedTraverse(str(name))
-                res.append((name, template))
-            return res
-        # No tool found, so no inline templates are known.
-        return ()
-
-Globals.InitializeClass(CompositeElement)
-
-
-addElementForm = PageTemplateFile("addElementForm.zpt", _www)
-
-def manage_addElement(dispatcher, id, path, template_name=None, REQUEST=None):
-    """Adds an element to a slot.
-    """
-    target = dispatcher.restrictedTraverse(path)
-    ob = CompositeElement(str(id), target)
-    if template_name:
-        ob.template_name = str(template_name)
-    dispatcher._setObject(ob.getId(), ob)
-    if REQUEST is not None:
-        return dispatcher.manage_main(dispatcher, REQUEST)

Deleted: CompositePage/trunk/interfaces.py
===================================================================
--- CompositePage/trunk/interfaces.py	2011-04-30 19:14:59 UTC (rev 121489)
+++ CompositePage/trunk/interfaces.py	2011-04-30 19:15:39 UTC (rev 121490)
@@ -1,127 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2003 Zope Foundation and Contributors.
-#
-# 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.14 2004/04/15 22:13:44 shane Exp $
-"""
-
-from zope.interface import Attribute
-from zope.interface import Interface
-
-
-class CompositeError(Exception):
-    """An error in constructing a composite
-    """
-
-
-class IComposite(Interface):
-    """An object whose rendering is composed of a layout and elements.
-    """
-    slots = Attribute("An ISlotGenerator.")
-
-    def __call__():
-        """Renders the composite as a string.
-        """
-
-
-class ISlotGenerator(Interface):
-
-    def get(name, class_name=None, title=None):
-        """Returns a slot, creating it if it does not yet exist.
-
-        The 'class_name' and 'title' arguments allow the caller to
-        specify a slot class and title.  Both are used for composite
-        design purposes, not rendering.
-        """
-
-    def __getitem__(name):
-        """Returns a slot, creating it if it does not yet exist.
-        """
-
-
-class ISlot(Interface):
-    """A slot in a composite.
-    """
-
-    def single():
-        """Renders to a string as a single-element slot.
-        """
-
-    def multiple():
-        """Renders to a sequence of strings as a multiple-element slot.
-        """
-
-    def reorder(name, new_index):
-        """Moves an item to a new index.
-        """
-
-    def nullify(name):
-        """Removes an item from the slot, returning the old item.
-
-        Leaves a null element in its place.  The null element ensures
-        that other items temporarily keep their index within the slot.
-        """
-
-    def pack():
-        """Removes all null elements from the slot.
-        """
-
-
-class ISlotClass(Interface):
-    """Parameters and constraints for a slot.
-    """
-
-    # inline_templates is an attribute listing allowed template names.  If
-    # this list is not empty, it is intersected with the inline templates
-    # provided by the object type to determine what templates are
-    # available.  If this list is empty, all inline templates provided by
-    # the object type are available.
-
-    def findAvailableElements():
-        """Returns a list of elements available for this slot.
-
-        Generally returns catalog results.
-        """
-
-
-class ICompositeElement(Interface):
-    """Interface of objects that can be part of a composite.
-    """
-
-    def renderInline():
-        """Returns a representation of this object as a string.
-        """
-
-    def queryInlineTemplate(slot_class_name=None):
-        """Returns the name of the inline template this object uses.
-
-        Returns None if none has been chosen and there is no default.
-
-        The slot_class_name may be provided as an optimization.
-        """
-
-    def setInlineTemplate(template):
-        """Sets the inline template for this object.
-        """
-
-    def listAllowableInlineTemplates(slot_class_name=None):
-        """Returns a list of templates allowable for this object.
-
-        Returns a list of (template_name, template_object).
-
-        The slot_class_name may be provided as an optimization.
-        """
-
-    def dereference():
-        """Returns the object to be rendered.
-        """

Deleted: CompositePage/trunk/perm_names.py
===================================================================
--- CompositePage/trunk/perm_names.py	2011-04-30 19:14:59 UTC (rev 121489)
+++ CompositePage/trunk/perm_names.py	2011-04-30 19:15:39 UTC (rev 121490)
@@ -1,21 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2003 Zope Foundation 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.
-# 
-##############################################################################
-"""Names of permissions used by CompositePage.
-
-$Id: perm_names.py,v 1.1 2003/10/01 18:59:31 shane Exp $
-"""
-
-change_composites_perm = "Change Composites"
-view_perm = "View"
-

Deleted: CompositePage/trunk/rawfile.py
===================================================================
--- CompositePage/trunk/rawfile.py	2011-04-30 19:14:59 UTC (rev 121489)
+++ CompositePage/trunk/rawfile.py	2011-04-30 19:15:39 UTC (rev 121490)
@@ -1,115 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2002 Zope Foundation 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.3 2004/04/03 16:35:32 shane Exp $
-"""
-
-import os
-from os import stat
-from time import time
-
-import Acquisition
-from Acquisition import aq_inner, aq_parent
-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
-        self.cch = 'public, max-age=3600'  # One hour
-
-        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()
-        data = self.interp(data)
-        return data
-
-    def interp(self, data):
-        """Hook point for subclasses that modify the file content.
-        """
-        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 ''
-
-
-class InterpolatedFile(RawFile):
-    """Text data, stored in a file, with %(xxx)s interpolation.
-    """
-
-    def interp(self, data):
-        parent_url = aq_parent(aq_inner(self)).absolute_url()
-        d = {
-            "parent_url": parent_url,
-            }
-        return data % d
-

Deleted: CompositePage/trunk/slot.py
===================================================================
--- CompositePage/trunk/slot.py	2011-04-30 19:14:59 UTC (rev 121489)
+++ CompositePage/trunk/slot.py	2011-04-30 19:15:39 UTC (rev 121490)
@@ -1,271 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2002 Zope Foundation 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.21 2004/04/26 09:30:25 gotcha Exp $
-"""
-
-import os
-import sys
-from cgi import escape
-
-import Globals
-from Acquisition import aq_base
-from Acquisition import aq_inner
-from Acquisition import aq_parent
-from Acquisition import aq_get
-from ZODB.POSException import ConflictError
-from OFS.SimpleItem import SimpleItem
-from Products.PageTemplates.PageTemplateFile import PageTemplateFile
-from AccessControl import ClassSecurityInfo
-from zLOG import LOG, ERROR
-from zope.interface import implements
-
-from Products.CompositePage.interfaces import ICompositeElement
-from Products.CompositePage.interfaces import ISlot
-from Products.CompositePage.perm_names import view_perm
-from Products.CompositePage.perm_names import change_composites_perm
-
-
-try:
-    # Use OrderedFolder if it's available.
-    from OFS.OrderedFolder import OrderedFolder
-except ImportError:
-    # Fall back to normal folders, which happen to retain order anyway.
-    from OFS.Folder import Folder as OrderedFolder
-
-_www = os.path.join(os.path.dirname(__file__), "www")
-
-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">
-<div class="slot_element_body">%s</div>
-</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>
-%s
-</div>'''
-
-# error_tag lets the user click on the 'log' link even if the
-# container normally stops clicks.
-error_tag = '''<span class="slot_error">%s
-(<a href="%s" onmousedown="document.location=this.href">log</a>)</span>'''
-
-
-class NullElement(SimpleItem):
-    """Empty placeholder for slot content
-    """
-    meta_type = "Temporary Empty Slot Content"
-
-    def __init__(self, id):
-        self.id = id
-
-
-class Slot(OrderedFolder):
-    """A slot in a composite.
-    """
-    implements(ISlot)
-    meta_type = "Composite Slot"
-
-    security = ClassSecurityInfo()
-
-    null_element = NullElement("null_element")
-
-
-    def __init__(self, id):
-        self.id = id
-
-    def all_meta_types(self):
-        return OrderedFolder.all_meta_types(
-            self, interfaces=(ICompositeElement,))
-
-    security.declareProtected(view_perm, "single")
-    def single(self):
-        """Renders as a single-element slot.
-
-        Attempts to prevent the user from adding multiple elements
-        by not providing insertion points when the slot already
-        contains elements.
-        """
-        allow_add = (not self._objects)
-        return "".join(self.renderToList(allow_add))
-
-    security.declareProtected(view_perm, "multiple")
-    def multiple(self):
-        """Renders as a list containing multiple elements.
-        """
-        return self.renderToList(1)
-
-    def __str__(self):
-        """Renders as a string containing multiple elements.
-        """
-        return "".join(self.renderToList(1))
-
-    __unicode__ = __str__
-
-    security.declareProtected(change_composites_perm, "reorder")
-    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)
-
-    security.declareProtected(change_composites_perm, "nullify")
-    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
-
-    security.declareProtected(change_composites_perm, "nullify")
-    def pack(self):
-        objs = [info for info in self._objects if info["id"] != "null_element"]
-        self._objects = tuple(objs)
-
-    security.declareProtected(view_perm, "renderToList")
-    def renderToList(self, allow_add):
-        """Renders the items to a list.
-        """
-        res = ['<div class="slot_header"></div>']
-        composite = aq_parent(aq_inner(aq_parent(aq_inner(self))))
-        editing = composite.isEditing()
-        items = self.objectItems()
-        if editing:
-            mypath = escape('/'.join(self.getPhysicalPath()))
-            myid = self.getId()
-            if hasattr(self, 'portal_url'):
-                icon_base_url = self.portal_url()
-            else:
-                request = getattr(self, 'REQUEST', None)
-                if request is not None:
-                    icon_base_url = request['BASEPATH1']
-                else:
-                    icon_base_url = '/'
-
-        if editing and allow_add:
-            res.append(self._render_add_target(myid, 0, mypath))
-
-        for index in range(len(items)):
-            name, obj = items[index]
-
-            try:
-                assert ICompositeElement.providedBy(obj), (
-                    "Not a composite element: %s" % repr(obj))
-                text = obj.renderInline()
-            except ConflictError:
-                # Ugly ZODB requirement: don't catch ConflictErrors
-                raise
-            except:
-                text = formatException(self, editing)
-
-
-            if editing:
-                res.append(self._render_editing(obj, text, icon_base_url))
-            else:
-                res.append(view_tag % text)
-            
-            if editing and allow_add:
-                res.append(self._render_add_target(myid, index+1, mypath, obj.getId()))
-
-        return res
-
-    def _render_editing(self, obj, text, icon_base_url):
-        o2 = obj.dereference()
-        icon = getIconURL(o2, icon_base_url)
-        title = o2.title_and_id()
-        path = escape('/'.join(obj.getPhysicalPath()))
-        return edit_tag % (path,
-                               escape(icon), escape(title), text)
-
-    def _render_add_target(self, slot_id, index, path, obj_id=''):
-         return target_tag % (slot_id, index, path, index)
-         
-Globals.InitializeClass(Slot)
-
-
-def getIconURL(obj, icon_base_url):
-    base = aq_base(obj)
-    if hasattr(base, 'getIcon'):
-        icon = obj.getIcon()
-    elif hasattr(base, 'icon'):
-        icon = obj.icon
-    else:
-        icon = ""
-    if icon and '://' not in icon:
-        if not icon.startswith('/'):
-            icon = '/' + icon
-        icon = icon_base_url + icon
-    return icon
-
-
-def formatException(context, editing):
-    """Returns an HTML-ified error message.
-
-    If not editing, the message includes no details.
-    """
-    exc_info = sys.exc_info()
-    try:
-        if editing:
-            # Show editors the real error
-            t, v = exc_info[:2]
-            t = getattr(t, '__name__', t)
-            msg = "An error occurred. %s" % (
-                escape(('%s: %s' % (t, v))[:80]))
-        else:
-            # Show viewers a simplified error.
-            msg = ("An error occurred while generating "
-                    "this part of the page.")
-        try:
-            log = aq_get(context, '__error_log__', None, 1)
-            raising = getattr(log, 'raising', None)
-        except AttributeError:
-            raising = None
-
-        if raising is not None:
-            error_log_url = raising(exc_info)
-            return error_tag % (msg, error_log_url)
-        else:
-            LOG("Composite", ERROR, "Error in a page element",
-                error=exc_info)
-            return msg
-    finally:
-        del exc_info
-
-
-addSlotForm = PageTemplateFile("addSlotForm.zpt", _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)

Deleted: CompositePage/trunk/slotclass.py
===================================================================
--- CompositePage/trunk/slotclass.py	2011-04-30 19:14:59 UTC (rev 121489)
+++ CompositePage/trunk/slotclass.py	2011-04-30 19:15:39 UTC (rev 121490)
@@ -1,66 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2002 Zope Foundation 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 classes.
-
-$Id: slotclass.py,v 1.1 2004/03/02 20:41:44 shane Exp $
-"""
-
-import os
-
-from Acquisition import aq_inner, aq_parent
-from OFS.SimpleItem import SimpleItem
-from OFS.PropertyManager import PropertyManager
-from Products.PageTemplates.PageTemplateFile import PageTemplateFile
-from zope.interface import implements
-
-from Products.CompositePage.interfaces import ISlotClass
-
-
-_www = os.path.join(os.path.dirname(__file__), "www")
-
-
-class SlotClass(SimpleItem, PropertyManager):
-    """Parameters and constraints for a slot.
-    """
-    implements(ISlotClass)
-    meta_type = "Composite Slot Class"
-    find_script = ""
-
-    manage_options = (PropertyManager.manage_options
-                      + SimpleItem.manage_options)
-
-    _properties = (
-        {'id': 'find_script', 'mode': 'w', 'type': 'string',
-         'label': 'Script that finds available elements',},
-        )
-
-    def findAvailableElements(self, slot):
-        if not self.find_script:
-            return None
-        tool = aq_parent(aq_inner(aq_parent(aq_inner(self))))
-        s = tool.restrictedTraverse(self.find_script)
-        return s(slot)
-
-
-addSlotClassForm = PageTemplateFile("addSlotClassForm.zpt", _www)
-
-def manage_addSlotClass(dispatcher, id, REQUEST=None):
-    """Adds a slot class to a composite tool.
-    """
-    ob = SlotClass()
-    ob._setId(id)
-    dispatcher._setObject(ob.getId(), ob)
-    if REQUEST is not None:
-        return dispatcher.manage_main(dispatcher, REQUEST)
-

Deleted: CompositePage/trunk/slotexpr.py
===================================================================
--- CompositePage/trunk/slotexpr.py	2011-04-30 19:14:59 UTC (rev 121489)
+++ CompositePage/trunk/slotexpr.py	2011-04-30 19:15:39 UTC (rev 121490)
@@ -1,105 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2003 Zope Foundation and Contributors.
-#
-# This software is subject to the provisions of the Zope Visible Source 
-# License, Version 1.0 (ZVSL).  A copy of the ZVSL 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
-#
-##############################################################################
-"""Support for 'slot:' expression type in ZPT.
-
-$Id: slotexpr.py,v 1.5 2004/05/03 16:02:40 sidnei Exp $
-"""
-
-import logging
-import re
-
-from zope.tales.tales import CompilerError
-
-from Products.CompositePage.interfaces import IComposite
-
-name_re = re.compile("\s*([a-zA-Z][a-zA-Z0-9_]*)")
-class_name_re = re.compile("\s*[(]([a-zA-Z][a-zA-Z0-9_]*)[)]")
-title_re = re.compile("\s*[']([^']+)[']")
-
-log = logging.getLogger(__name__)
-
-
-class SlotExpr(object):
-    """Slot expression type.
-
-    Provides a concise syntax for specifying composite slots in
-    ZPT.  An example slot expression, in context of ZPT:
-
-    <div tal:replace="slot: slot_name(class_name) 'Title'" />
-    """
-
-    def __init__(self, name, expr, engine):
-        self._s = s = expr.strip()
-        mo = name_re.match(s)
-        if mo is None:
-            raise CompilerError('Invalid slot expression "%s"' % s)
-        self._name = mo.group(1)
-        s = s[mo.end():]
-        mo = class_name_re.match(s)
-        if mo is not None:
-            self._class_name = mo.group(1)
-            s = s[mo.end():]
-        else:
-            self._class_name = None
-        mo = title_re.match(s)
-        if mo is not None:
-            self._title = mo.group(1)
-            s = s[mo.end():]
-        else:
-            self._title = None
-        if s.strip():
-            # Can't interpret some of the expression
-            raise CompilerError(
-                'Slot expression syntax error near %s' % repr(s))
-
-    def __call__(self, econtext):
-        context = econtext.contexts.get('options')
-        if context is None:
-            raise RuntimeError("Could not find options")
-        composite = context.get('composite')
-        if IComposite.providedBy(composite):
-            slot = composite.slots.get(
-                self._name, self._class_name, self._title)
-            # Render the slot
-            return unicode(slot)
-        else:
-            # Show the default content
-            return econtext.getDefault()
-
-    def __repr__(self):
-        return '<SlotExpr %s>' % repr(self._s)
-
-
-def registerSlotExprType():
-    # Register the 'slot:' expression type.
-
-    # Register with Products.PageTemplates.
-    try:
-        from Products.PageTemplates.Expressions import getEngine
-    except ImportError:
-        log.exception("Unable to register the slot expression type")
-    else:
-        engine = getEngine()
-        if not engine.getTypes().has_key('slot'):
-            engine.registerType('slot', SlotExpr)
-
-    # Register with zope.tales.
-    try:
-        from zope.tales.engine import Engine
-    except ImportError:
-        log.exception("Unable to register the slot expression type")
-    else:
-        if not Engine.getTypes().has_key('slot'):
-            Engine.registerType('slot', SlotExpr)

Deleted: CompositePage/trunk/tool.py
===================================================================
--- CompositePage/trunk/tool.py	2011-04-30 19:14:59 UTC (rev 121489)
+++ CompositePage/trunk/tool.py	2011-04-30 19:15:39 UTC (rev 121490)
@@ -1,260 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2002 Zope Foundation 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.11 2004/03/02 20:41:44 shane Exp $
-"""
-
-import Globals
-from Acquisition import aq_base, aq_parent, aq_inner
-from OFS.SimpleItem import SimpleItem
-from OFS.Folder import Folder
-from OFS.CopySupport import _cb_encode, _cb_decode, cookie_path
-from AccessControl import ClassSecurityInfo
-from AccessControl.ZopeGuards import guarded_getattr
-
-from Products.CompositePage.interfaces import ICompositeElement
-from Products.CompositePage.interfaces import ISlot
-from Products.CompositePage.interfaces import ISlotClass
-from Products.CompositePage.interfaces import CompositeError
-from Products.CompositePage.element import CompositeElement
-from Products.CompositePage.utils import copyOf
-
-
-_uis = {}
-
-def registerUI(name, obj):
-    """Registers a page design UI for use with the composite tool.
-    """
-    if _uis.has_key(name):
-        raise RuntimeError("There is already a UI named %s" % name)
-    obj._setId(name)
-    _uis[name] = obj
-
-
-
-class DesignUIs(SimpleItem):
-    """The container of design user interface objects.
-
-    Makes page design UIs accessible through URL traversal.
-    """
-
-    def __init__(self, id):
-        self._setId(id)
-
-    def __getattr__(self, name):
-        try:
-            return _uis[name]
-        except KeyError:
-            raise AttributeError, name
-
-
-class SlotClassFolder(Folder):
-    """Container of slot classes.
-    """
-    meta_type = "Slot Class Folder"
-
-    def all_meta_types(self):
-        return Folder.all_meta_types(self, interfaces=(ISlotClass,))
-
-
-class CompositeTool(Folder):
-    """Page composition helper tool.
-    """
-    meta_type = "Composite Tool"
-    id = "composite_tool"
-
-    security = ClassSecurityInfo()
-
-    security.declarePublic("uis")
-    uis = DesignUIs("uis")
-
-    _properties = Folder._properties + (
-        {'id': 'default_inline_templates', 'mode': 'w', 'type': 'lines',
-         'label': 'Default inline template names',},
-        )
-
-    default_inline_templates = ()
-
-    _check_security = 1  # Turned off in unit tests
-
-    def __init__(self):
-        scf = SlotClassFolder()
-        scf._setId("slot_classes")
-        self._setObject(scf.id, scf)
-        self._reserved_names = ('slot_classes',)
-
-    security.declarePublic("moveElements")
-    def moveElements(self, source_paths, target_path, target_index, copy=0):
-        """Moves or copies 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, checking interfaces and security before
-        # making any changes.
-        root = self.getPhysicalRoot()
-        elements = []
-        target = root.restrictedTraverse(target_path)
-        assert ISlot.providedBy(target), repr(target)
-        for source in sources:
-            slot = root.restrictedTraverse(source[:-1])
-            assert ISlot.providedBy(slot), repr(slot)
-            element = slot.restrictedTraverse(source[-1])
-            elements.append(element)
-            if self._check_security:
-                target._verifyObjectPaste(element)
-
-        changed_slots = {}  # id(aq_base(slot)) -> slot
-        try:
-            if not copy:
-                # Replace items with nulls to avoid changing indexes
-                # while moving.
-                for source in sources:
-                    slot = root.restrictedTraverse(source[:-1])
-                    slot_id = id(aq_base(slot))
-                    if not changed_slots.has_key(slot_id):
-                        changed_slots[slot_id] = slot
-                    # Check security
-                    nullify = guarded_getattr(slot, "nullify")
-                    nullify(source[-1])
-
-            # Add the elements and reorder.
-            for element in elements:
-
-                if not ICompositeElement.providedBy(element):
-                    # Make a composite element wrapper.
-                    element = CompositeElement(element.getId(), element)
-
-                element = aq_base(element)
-                new_id = target._get_id(element.getId())
-                if copy:
-                    element = copyOf(element)
-                element._setId(new_id)
-                target._setObject(new_id, element)
-                # Check security
-                reorder = guarded_getattr(target, "reorder")
-                reorder(new_id, target_index)
-                target_index += 1
-        finally:
-            # Clear the nulls just added.
-            for slot in changed_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.providedBy(slot), repr(slot)
-                slot_id = id(aq_base(slot))
-                if not orig_slots.has_key(slot_id):
-                    orig_slots[slot_id] = slot
-                nullify = guarded_getattr(slot, "nullify")  # Check security
-                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/or 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"])
-
-
-    security.declarePublic("useClipboard")
-    def useClipboard(self, func, REQUEST,
-                     source_paths=None, target_path=None, target_index=None):
-        """Clipboard interaction.
-        """
-        resp = REQUEST['RESPONSE']
-        if func in ("cut", "copy"):
-            assert source_paths
-            items = []  # list of path tuples
-            cut = (func == 'cut')
-            for p in str(source_paths).split(':'):
-                items.append(p.split('/'))
-            data = _cb_encode((cut, items))
-            resp.setCookie('__cp', data, path=cookie_path(REQUEST))
-        elif func == 'paste':
-            assert target_path
-            assert target_index
-            assert REQUEST is not None
-            data = REQUEST['__cp']
-            cut, items = _cb_decode(data)
-            self.moveElements(
-                items, target_path, int(target_index), not cut)
-            resp.expireCookie('__cp', path=cookie_path(REQUEST))
-        else:
-            raise ValueError("Clipboard function %s unknown" % func)
-        resp.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)
-

Deleted: CompositePage/trunk/utils.py
===================================================================
--- CompositePage/trunk/utils.py	2011-04-30 19:14:59 UTC (rev 121489)
+++ CompositePage/trunk/utils.py	2011-04-30 19:15:39 UTC (rev 121490)
@@ -1,70 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2003 Zope Foundation 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.
-#
-##############################################################################
-"""Utilities for handling ZODB objects.
-
-(Copied from the Ape product.)
-
-$Id: utils.py,v 1.1 2003/12/28 04:32:47 shane Exp $
-"""
-
-from cStringIO import StringIO
-from cPickle import Pickler, Unpickler
-
-
-def copyOf(source):
-    """Copies a ZODB object, loading subobjects as needed.
-
-    Re-ghostifies objects along the way to save memory.
-    """
-    former_ghosts = []
-    zclass_refs = {}
-
-    def persistent_id(ob, former_ghosts=former_ghosts,
-                      zclass_refs=zclass_refs):
-        if getattr(ob, '_p_changed', 0) is None:
-            # Load temporarily.
-            former_ghosts.append(ob)
-            ob._p_changed = 0
-        if hasattr(ob, '__bases__'):
-            m = getattr(ob, '__module__', None)
-            if (m is not None
-                and isinstance(m, basestring)
-                and m.startswith('*')):
-                n = getattr(ob, '__name__', None)
-                if n is not None:
-                    # Pickling a ZClass instance.  Store the reference to
-                    # the ZClass class separately, so that the pickler
-                    # and unpickler don't trip over the apparently
-                    # missing module.
-                    ref = (m, n)
-                    zclass_refs[ref] = ob
-                    return ref
-        return None
-
-    def persistent_load(ref, zclass_refs=zclass_refs):
-        return zclass_refs[ref]
-
-    stream = StringIO()
-    p = Pickler(stream, 1)
-    p.persistent_id = persistent_id
-    p.dump(source)
-    if former_ghosts:
-        for g in former_ghosts:
-            del g._p_changed
-        del former_ghosts[:]
-    stream.seek(0)
-    u = Unpickler(stream)
-    u.persistent_load = persistent_load
-    return u.load()
-

Deleted: CompositePage/trunk/version.txt
===================================================================
--- CompositePage/trunk/version.txt	2011-04-30 19:14:59 UTC (rev 121489)
+++ CompositePage/trunk/version.txt	2011-04-30 19:15:39 UTC (rev 121490)
@@ -1 +0,0 @@
-CompositePage-0.2



More information about the checkins mailing list