vendor/CMFonFive/1.3.0

changeset 0:b4f7f3010227 1.3.0

(none)
author lregebro
date Fri, 06 Jan 2006 15:24:54 +0000
parents
children 4f3d7d6b5fee
files CHANGES.txt COPYING.txt Extensions/install.py README.txt __init__.py configure.zcml fiveactionstool.py meta.zcml tests/__init__.py tests/products/CMFonFiveTest/__init__.py tests/products/CMFonFiveTest/cmfcontent.py tests/products/CMFonFiveTest/configure.zcml tests/products/CMFonFiveTest/interfaces.py tests/products/CMFonFiveTest/tests/__init__.py tests/products/CMFonFiveTest/tests/test_actionstool.py tests/products/CMFonFiveTest/www/cmfContentAdd.zpt tests/products/README.txt tool.gif version.txt www/document_edit.pt www/document_view.pt www/folder_contents.pt
diffstat 22 files changed, 1001 insertions(+), 0 deletions(-) [+]
line diff
     1.1 new file mode 100644
     1.2 --- /dev/null
     1.3 +++ b/CHANGES.txt
     1.4 @@ -0,0 +1,57 @@
     1.5 +CMFonFive Product Changelog
     1.6 +
     1.7 +  CMFonFive 1.3.0 (2006-01-05)
     1.8 +      
     1.9 +    - The five_template support was removed as it provided little extra
    1.10 +      functionality compared to the support that already exists in CMFDefault.
    1.11 +      Note that this will create some compatibility issues:
    1.12 +      
    1.13 +      1. The five_template is no longer configured for all interfaces, but 
    1.14 +         only for IDynamicType. If your class do not implement IDynamicType, 
    1.15 +         you can add a directlyProvides statement for the class in the 
    1.16 +         configure.zcml.
    1.17 +         
    1.18 +      2. The CMFDefault template does not include support for the "head"-slot.
    1.19 +      
    1.20 +      3. What CMFonFive calls css_clot, is by CMFDefault called style_slot.
    1.21 +
    1.22 +    - interfaces.py is no longer used and was removed.
    1.23 +    
    1.24 +    - The menuItem support is replaced by an implementation that supports
    1.25 +      Zope 3.2 (and therefore Zope 2.9). Zope 3.0 and Zope 2.8 is no longer
    1.26 +      supported.
    1.27 +
    1.28 +
    1.29 +  CMFonFive 1.2.1 (2006-01-02)
    1.30 +
    1.31 +    - Menu titles was converted to strings even if they were messageIDs.
    1.32 +
    1.33 +    - Spelling fixes.
    1.34 +
    1.35 +    - metadirectives.py is not used and was removed.
    1.36 +
    1.37 +  CMFonFive 1.2.0 (2005-07-22)
    1.38 +  
    1.39 +    - CMF 1.5.2 moves the interface bridging into CMF itself, so it it
    1.40 +      removed from CMFonFive.
    1.41 +  
    1.42 +  CMFonFive 1.1.0 (2005-06-19)
    1.43 +
    1.44 +    - A new ZCML directive has been added: cmf:menuItem. This works
    1.45 +      as browser:menuItem, except that the filter parameter will be
    1.46 +      evaluated as a Zope2 TALES statement instead of a Zope3 TALES
    1.47 +      statement. In practice, if you need filters on your menuItems,
    1.48 +      you will want to use this. 
    1.49 +      
    1.50 +    - The five_template has some errors giving templates double <html>-tags.
    1.51 +    
    1.52 +  CMFonFive 1.0.1 (2005-06-01)
    1.53 +
    1.54 +    - configure.zcml:  Provided an i18n translation domain, 'CMFonFive'.
    1.55 +
    1.56 +    - permissions.py:  Use newer permission imports from CMF 1.5,
    1.57 +      if available (fall back to 1.4 spellings).
    1.58 +
    1.59 +  CMFonFive 1.0.0 (2005-04-01)
    1.60 +
    1.61 +    - Initial release.
     2.1 new file mode 100644
     2.2 --- /dev/null
     2.3 +++ b/COPYING.txt
     2.4 @@ -0,0 +1,27 @@
     2.5 +Five is distributed under the provisions of the Zope Public License
     2.6 +(ZPL) v2.1.  See doc/ZopePublicLicense.txt for the license text.
     2.7 +
     2.8 +Copyright (C) 2005 Five Contributors. See CREDITS.txt for a list of
     2.9 +Five contributors.
    2.10 +
    2.11 +Five contains source code derived from:
    2.12 +
    2.13 +- Zope 3, copyright (C) 2001-2005 by Zope Corporation.  Code that
    2.14 +  falls under this copyright is prefixed with the following header:
    2.15 +
    2.16 +  Copyright (c) 2001-2004 Zope Corporation and Contributors.
    2.17 +  All Rights Reserved.
    2.18 +
    2.19 +  This software is subject to the provisions of the Zope Public
    2.20 +  License, Version 2.1 (ZPL).  A copy of the ZPL should accompany this
    2.21 +  distribution.  THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL
    2.22 +  EXPRESS OR IMPLIED WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT
    2.23 +  LIMITED TO, THE IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
    2.24 +  AGAINST INFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE.
    2.25 +
    2.26 +- metaclass.py is derived from PEAK, copyright (C) 1996-2004 by
    2.27 +  Phillip J. Eby and Tyler C. Sarna. PEAK may be used under the same
    2.28 +  terms as Zope.
    2.29 +
    2.30 +- TrustedExecutables. Dieter Mauer kindly allow licensing this under the
    2.31 +  ZPL 2.1.
    2.32 \ No newline at end of file
     3.1 new file mode 100644
     3.2 --- /dev/null
     3.3 +++ b/Extensions/install.py
     3.4 @@ -0,0 +1,110 @@
     3.5 +# (C) Copyright 2005 Nuxeo SARL <http://nuxeo.com>
     3.6 +# Author: Lennart Regebro <regebro@nuxeo.com>
     3.7 +#
     3.8 +# This program is free software; you can redistribute it and/or modify
     3.9 +# it under the terms of the GNU General Public License version 2 as published
    3.10 +# by the Free Software Foundation.
    3.11 +#
    3.12 +# This program is distributed in the hope that it will be useful,
    3.13 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    3.14 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    3.15 +# GNU General Public License for more details.
    3.16 +#
    3.17 +# You should have received a copy of the GNU General Public License
    3.18 +# along with this program; if not, write to the Free Software
    3.19 +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
    3.20 +# 02111-1307, USA.
    3.21 +#
    3.22 +# $Id: install.py 10227 2005-04-01 16:51:45Z regebro $
    3.23 +
    3.24 +from zLOG import LOG, INFO, DEBUG
    3.25 +from Products.CMFCore.utils import getToolByName, _marker
    3.26 +
    3.27 +log_ok_message = '...Already correctly installed'
    3.28 +
    3.29 +class CMFonFiveInstaller:
    3.30 +    """A simplified version of the installers from CPSInstaller"""
    3.31 +
    3.32 +    # Sure, it's overkill, but easier that writing things from scratch. /Lennart
    3.33 +   
    3.34 +    product_name = 'CMFonFive'
    3.35 +
    3.36 +    def __init__(self, context):
    3.37 +        """CMFInstaller initialization
    3.38 +
    3.39 +        product_name should be set as a class attribute when subclassing,
    3.40 +        but must be passed if you are not subclassing the installer.
    3.41 +
    3.42 +        is_main_installer should be se to 0 if this installer is called
    3.43 +        from another installer to prevent multiple reindexing of catalogs
    3.44 +        and similar actions that only needs to be done once.
    3.45 +        """
    3.46 +        self.context = context
    3.47 +        self.messages = []
    3.48 +        self.portal = context.portal_url.getPortalObject()
    3.49 +
    3.50 +    #
    3.51 +    # Logging
    3.52 +    #
    3.53 +    def log(self, message):
    3.54 +        self.messages.append(message)
    3.55 +        LOG(self.product_name, INFO, message)
    3.56 +
    3.57 +    def logOK(self):
    3.58 +        self.messages[-1] = self.messages[-1] + log_ok_message
    3.59 +        #self.log(log_ok_message)
    3.60 +
    3.61 +    def flush(self):
    3.62 +        log = '\n'.join(self.messages)
    3.63 +        self.messages = []
    3.64 +        return log
    3.65 +
    3.66 +    def logResult(self):
    3.67 +        if not self.isMainInstaller():
    3.68 +            return self.flush()
    3.69 +        # Wrap HTML around it if it's the main installer.
    3.70 +        return '''<html><head><title>%s</title></head>
    3.71 +            <body><pre>%s</pre></body></html>''' % (
    3.72 +            self.product_name, self.flush() )
    3.73 +    #
    3.74 +    # Other support methods
    3.75 +    #
    3.76 +    def portalHas(self, id):
    3.77 +        return id in self.portal.objectIds()
    3.78 +
    3.79 +    def getTool(self, id, default=_marker):
    3.80 +        """Gets the tool by id
    3.81 +        
    3.82 +        If No default is given, it will raise an error.
    3.83 +        """
    3.84 +        return getToolByName(self.portal, id, default)
    3.85 +    #
    3.86 +    # Methods to setup and manage actions
    3.87 +    #
    3.88 +    def verifyActionProvider(self, action_provider):
    3.89 +        self.log('Verifying action provider %s' % action_provider)
    3.90 +        atool = self.getTool('portal_actions')
    3.91 +        if action_provider in atool.listActionProviders():
    3.92 +            self.logOK()
    3.93 +        else:    
    3.94 +            atool.addActionProvider(action_provider)
    3.95 +            self.log(' Installed')
    3.96 +        
    3.97 +    def verifyTool(self, toolid, product, meta_type):
    3.98 +        self.log('Verifying tool %s' % toolid)
    3.99 +        if self.portalHas(toolid):
   3.100 +            tool = self.getTool(toolid)
   3.101 +            if tool.meta_type == meta_type:
   3.102 +                self.logOK()
   3.103 +                return
   3.104 +            self.log(' Deleting old %s tool' % tool.meta_type)
   3.105 +            self.portal.manage_delObjects([toolid])
   3.106 +        self.log(' Adding')
   3.107 +        self.portal.manage_addProduct[product].manage_addTool(meta_type)
   3.108 +
   3.109 +
   3.110 +def install(self):
   3.111 +    installer = CMFonFiveInstaller(self)
   3.112 +    installer.verifyTool('portal_fiveactions', 'CMFonFive', 'Five Actions Tool')
   3.113 +    installer.verifyActionProvider('portal_fiveactions')
   3.114 +    return installer.flush()
     4.1 new file mode 100644
     4.2 --- /dev/null
     4.3 +++ b/README.txt
     4.4 @@ -0,0 +1,105 @@
     4.5 +CMFonFive
     4.6 +=========
     4.7 +
     4.8 +CMFonFive is a product that provides integration between CMF and Five, 
     4.9 +making it possible to write Five products that run on CMF. 
    4.10 +
    4.11 +* http://www.zope.org/Products/CMF/
    4.12 +
    4.13 +* http://codespeak.net/z3/five/
    4.14 +
    4.15 +CMFonFive used to have three main parts, but two of these have now been 
    4.16 +integrated into CMF itself:
    4.17 +
    4.18 +* A set of interface definitions and bridges for many parts of CMF.
    4.19 +  This part has been moved to CMF itself in CMF 1.5.2.
    4.20 +
    4.21 +* A skin layer that provides integration between the Zope3 standard macros
    4.22 +  and the CMF main template. 
    4.23 +  This part has been moved to CMF itself in CMF 1.5.2.
    4.24 +
    4.25 +* A Five Actions Tool, that enables you to display the Zope 3 menuItems
    4.26 +  as CMF actions. Any menuItem registered will be accessible though the 
    4.27 +  portal_actions tool, where the menu the item was registered for will be
    4.28 +  used as the action category.
    4.29 +
    4.30 +Requirements
    4.31 +------------
    4.32 +
    4.33 +* Zope 2.7 or later.
    4.34 +
    4.35 +* If you use Zope 2.7 you also need Five 1.0 or 1.1.
    4.36 +
    4.37 +* CMF 1.4 or 1.5.
    4.38 +
    4.39 +
    4.40 +Download
    4.41 +--------
    4.42 +Which version you should download depends on the version of Zope and CMF.
    4.43 +Make sure you match these versions with your CMFonFive version! 
    4.44 +Note that there is no CMFonFive for CMF versions before 1.5.2 on Zope 2.9.
    4.45 +
    4.46 +* CMFonFive 1.3.0 (2006-01-05)
    4.47 +
    4.48 +  For CMF 1.5.2 and later, with Zope 2.9.
    4.49 +  
    4.50 +  http://codespeak.net/z3/cmfonfive/release/CMFonFive-1.3.0.tgz
    4.51 +
    4.52 +* CMFonFive 1.2.1 (2006-01-02) 
    4.53 +
    4.54 +  For CMF 1.5.2 and later, with Zope 2.8.
    4.55 +
    4.56 +  http://codespeak.net/z3/cmfonfive/release/CMFonFive-1.2.1.tgz
    4.57 +
    4.58 +* CMFonFive 1.1.1 (2006-01-02)
    4.59 +
    4.60 +  For CMF 1.4.0 to  1.5.1 with Zope 2.7 or 2.8.
    4.61 +
    4.62 +  http://codespeak.net/z3/cmfonfive/release/CMFonFive-1.1.1.tgz
    4.63 +
    4.64 +
    4.65 +Earlier versions
    4.66 +----------------
    4.67 +
    4.68 +These earlier versions are depracated, as later version have had bugs fixed.
    4.69 +
    4.70 +* CMFonFive 1.2.0 (2005-07-22)
    4.71 +
    4.72 +  Supports CMF 1.5.2 to 1.5.5.
    4.73 +
    4.74 +  http://codespeak.net/z3/cmfonfive/release/CMFonFive-1.2.0.tgz
    4.75 +
    4.76 +* CMFonFive 1.1.0 (2005-06-19)
    4.77 +
    4.78 +  Supports CMF 1.4, 1.5.0 and 1.5.1.
    4.79 +
    4.80 +  http://codespeak.net/z3/cmfonfive/release/CMFonFive-1.1.0.tgz
    4.81 +
    4.82 +* CMFonFive 1.0.1 (2005-06-01) 
    4.83 +
    4.84 +  Supports CMF 1.4, 1.5.0 and 1.5.1.
    4.85 +
    4.86 +  http://codespeak.net/z3/cmfonfive/release/CMFonFive-1.0.1.tgz
    4.87 +
    4.88 +* CMFonFive 1.0.0 (2005-04-01) 
    4.89 +
    4.90 +  Supports CMF 1.4 only.
    4.91 +
    4.92 +  http://codespeak.net/z3/cmfonfive/release/CMFonFive-1.0.0.tgz
    4.93 +
    4.94 +
    4.95 +Installation
    4.96 +------------
    4.97 +The interface support needs no installation. If you want the menuItem 
    4.98 +support, you simply create a Five Actions Tool in your CMF site, and set 
    4.99 +that tool up as an action provider in the portal_actions tool.
   4.100 +
   4.101 +CMFonFive has support for CMFQuickInstaller, so if you have that installed
   4.102 +you can use that to do the above installation.
   4.103 +
   4.104 +
   4.105 +Contributors
   4.106 +------------
   4.107 +* Tres Seaver (tseaver@zope.com)
   4.108 +
   4.109 +* Lennart Regebro (regebro@nuxeo.com)
     5.1 new file mode 100644
     5.2 --- /dev/null
     5.3 +++ b/__init__.py
     5.4 @@ -0,0 +1,22 @@
     5.5 +##############################################################################
     5.6 +#
     5.7 +# Copyright (c) 2005 CMFonFive Contributors. All rights reserved.
     5.8 +#
     5.9 +# This software is distributed under the terms of the Zope Public
    5.10 +# License (ZPL) v2.1. See COPYING.txt for more information.
    5.11 +#
    5.12 +###########################################################################
    5.13 +""" Bridge CMF to Five.
    5.14 +
    5.15 +$Id: __init__.py 21741 2006-01-06 15:08:14Z regebro $
    5.16 +"""
    5.17 +from Products.CMFCore.utils import ToolInit
    5.18 +import fiveactionstool
    5.19 +
    5.20 +def initialize(context):
    5.21 +
    5.22 +    ToolInit( 'Five Tools'
    5.23 +            , tools=(fiveactionstool.FiveActionsTool,)
    5.24 +            , product_name='CMFonFive'
    5.25 +            , icon='tool.gif'
    5.26 +            ).initialize( context )
     6.1 new file mode 100644
     6.2 --- /dev/null
     6.3 +++ b/configure.zcml
     6.4 @@ -0,0 +1,11 @@
     6.5 +<configure
     6.6 +  xmlns:browser="http://namespaces.zope.org/browser"
     6.7 +  >
     6.8 +
     6.9 +  <!-- Set up standard action categories as menus -->
    6.10 +  <browser:menu
    6.11 +    id="object"
    6.12 +    title="Object menu"
    6.13 +    />
    6.14 +
    6.15 +</configure>
     7.1 new file mode 100644
     7.2 --- /dev/null
     7.3 +++ b/fiveactionstool.py
     7.4 @@ -0,0 +1,90 @@
     7.5 +##############################################################################
     7.6 +#
     7.7 +# Copyright (c) 2005 CMFonFive Contributors. All rights reserved.
     7.8 +#
     7.9 +# This software is distributed under the terms of the Zope Public
    7.10 +# License (ZPL) v2.1. See COPYING.txt for more information.
    7.11 +#
    7.12 +###########################################################################
    7.13 +""" Five actions tool.
    7.14 +
    7.15 +$Id: fiveactionstool.py 21741 2006-01-06 15:08:14Z regebro $
    7.16 +"""
    7.17 +
    7.18 +from AccessControl import ClassSecurityInfo
    7.19 +from Acquisition import aq_base
    7.20 +from Globals import InitializeClass
    7.21 +from OFS.SimpleItem import SimpleItem
    7.22 +
    7.23 +from Products.CMFCore.ActionInformation import ActionInformation
    7.24 +from Products.CMFCore.ActionProviderBase import ActionProviderBase
    7.25 +from Products.CMFCore.Expression import Expression
    7.26 +from Products.CMFCore.utils import UniqueObject
    7.27 +
    7.28 +from zope.app import zapi
    7.29 +from zope.app.publisher.interfaces.browser import IBrowserMenu
    7.30 +from zope.app.publisher.browser.menu import getMenu
    7.31 +    
    7.32 +def _listMenuIds():
    7.33 +    return [id for id, utility in zapi.getUtilitiesFor(IBrowserMenu)]
    7.34 +
    7.35 +from Products.Five import security
    7.36 +import zope.thread
    7.37 +
    7.38 +class FiveActionsTool( UniqueObject, SimpleItem, ActionProviderBase ):
    7.39 +    """ Links content to discussions.
    7.40 +    """
    7.41 +
    7.42 +    __implements__ = (ActionProviderBase.__implements__)
    7.43 +
    7.44 +    id = 'portal_fiveactions'
    7.45 +    meta_type = 'Five Actions Tool'
    7.46 +
    7.47 +    security = ClassSecurityInfo()
    7.48 +
    7.49 +    def getReqestURL(self):
    7.50 +        return self.REQUEST.URL
    7.51 +
    7.52 +    security.declarePrivate('listActions')
    7.53 +    def listActions(self, info=None, object=None):
    7.54 +        """ List all the actions defined by a provider.
    7.55 +        """       
    7.56 +        # Necessary to make the Request look like a Zope3 request
    7.57 +        # XXX This can be removed when we no longer need Five 1.0 compatibility.
    7.58 +        #self.REQUEST.getURL = self.getReqestURL
    7.59 +        if object is None:
    7.60 +            object = info.content
    7.61 +        actions = []
    7.62 +
    7.63 +        for menu_id in _listMenuIds():
    7.64 +            for entry in getMenu(menu_id, object, self.REQUEST):
    7.65 +                # The action needs a unique name, so I'll build one
    7.66 +                # from the object_id and the action url. That is sure
    7.67 +                # to be unique.
    7.68 +                action = str(entry['action'])
    7.69 +                if object is None:
    7.70 +                    act_id = 'action_%s' % action
    7.71 +                else:
    7.72 +                    act_id = 'action_%s_%s' % (object.getId(), action)
    7.73 +                    
    7.74 +                if entry.get('filter') is None:
    7.75 +                    filter = None
    7.76 +                else:
    7.77 +                    filter = Expression(text=str(entry['filter']))
    7.78 +
    7.79 +                title = entry['title']
    7.80 +                # Having bits of unicode here can make rendering very confused.
    7.81 +                if isinstance(title, unicode):
    7.82 +                    title = str(title)
    7.83 +                act = ActionInformation(id=act_id,
    7.84 +                    title=title,
    7.85 +                    action=Expression(text='string:%s' % action),
    7.86 +                    condition=filter,
    7.87 +                    category=str(menu_id),
    7.88 +                    visible=1)
    7.89 +                actions.append(act)
    7.90 +                
    7.91 +        return tuple(actions)
    7.92 +
    7.93 +
    7.94 +InitializeClass( FiveActionsTool )
     8.1 new file mode 100644
     8.2 --- /dev/null
     8.3 +++ b/meta.zcml
     8.4 @@ -0,0 +1,34 @@
     8.5 +<configure
     8.6 +    xmlns="http://namespaces.zope.org/zope"
     8.7 +    xmlns:meta="http://namespaces.zope.org/meta">
     8.8 +
     8.9 +  <!-- meta:directives namespace="http://namespaces.zope.org/cmf">
    8.10 +
    8.11 +    <meta:directive
    8.12 +        name="menu"
    8.13 +        schema="zope.app.publisher.browser.metadirectives.IMenuDirective"
    8.14 +        handler="zope.app.publisher.browser.menumeta.menuDirective"
    8.15 +        />
    8.16 +
    8.17 +    <meta:directive
    8.18 +        name="menuItem"
    8.19 +        schema="zope.app.publisher.browser.menumeta.IMenuItemDirective"
    8.20 +        handler=".globalbrowsermenuservice.menuItemDirective"
    8.21 +        />
    8.22 +
    8.23 +    <meta:complexDirective
    8.24 +        name="menuItems"
    8.25 +        schema="zope.app.publisher.browser.menumeta.IMenuItemsDirective"
    8.26 +        handler=".globalbrowsermenuservice.menuItemsDirective"
    8.27 +        >
    8.28 +
    8.29 +      <meta:subdirective
    8.30 +          name="menuItem"
    8.31 +          schema="zope.app.publisher.browser.metadirectives.IMenuItemSubdirective"
    8.32 +          />
    8.33 +
    8.34 +    </meta:complexDirective>
    8.35 +
    8.36 +  </meta:directives /-->
    8.37 +
    8.38 +</configure>
     9.1 new file mode 100644
     9.2 --- /dev/null
     9.3 +++ b/tests/__init__.py
     9.4 @@ -0,0 +1,4 @@
     9.5 +""" Unit tests for CMFonFive.
     9.6 +
     9.7 +$Id: __init__.py 10227 2005-04-01 16:51:45Z regebro $
     9.8 +"""
    10.1 new file mode 100644
    10.2 --- /dev/null
    10.3 +++ b/tests/products/CMFonFiveTest/__init__.py
    10.4 @@ -0,0 +1,11 @@
    10.5 +import cmfcontent
    10.6 +
    10.7 +def initialize(context):
    10.8 +
    10.9 +    context.registerClass(
   10.10 +        cmfcontent.CMFContent,
   10.11 +        constructors = (cmfcontent.manage_addCMFContentForm,
   10.12 +                        cmfcontent.manage_addCMFContent),
   10.13 +        )
   10.14 +
   10.15 +
    11.1 new file mode 100644
    11.2 --- /dev/null
    11.3 +++ b/tests/products/CMFonFiveTest/cmfcontent.py
    11.4 @@ -0,0 +1,43 @@
    11.5 +from OFS.SimpleItem import SimpleItem
    11.6 +from Globals import InitializeClass
    11.7 +from AccessControl import ClassSecurityInfo
    11.8 +from Products.PageTemplates.PageTemplateFile import PageTemplateFile
    11.9 +from zope.interface import implements
   11.10 +from interfaces import ICMFContent
   11.11 +
   11.12 +class CMFContent(SimpleItem):
   11.13 +    implements(ICMFContent)
   11.14 +
   11.15 +    meta_type = 'CMFonFive Content'
   11.16 +    security = ClassSecurityInfo()
   11.17 +
   11.18 +    def __init__(self, id, title):
   11.19 +        self.id = id
   11.20 +        self.title = title
   11.21 +
   11.22 +    security.declarePublic('mymethod')
   11.23 +    def mymethod(self):
   11.24 +        return "Hello world"
   11.25 +
   11.26 +InitializeClass(CMFContent)
   11.27 +
   11.28 +
   11.29 +manage_addCMFContentForm = PageTemplateFile(
   11.30 +    "www/cmfContentAdd", globals(),
   11.31 +    __name__ = 'manage_addCmfContentForm')
   11.32 +
   11.33 +def manage_addCMFContent(self, id, title, REQUEST=None):
   11.34 +    """Add the simple content."""
   11.35 +    id = self._setObject(id, CMFContent(id, title))
   11.36 +
   11.37 +    if REQUEST is None:
   11.38 +        return
   11.39 +    try:
   11.40 +        u = self.DestinationURL()
   11.41 +    except:
   11.42 +        u = REQUEST['URL1']
   11.43 +    if REQUEST.has_key('submit_edit'):
   11.44 +        u = "%s/%s" % (u, urllib.quote(id))
   11.45 +    REQUEST.RESPONSE.redirect(u+'/manage_main')
   11.46 +
   11.47 +    return ''
    12.1 new file mode 100644
    12.2 --- /dev/null
    12.3 +++ b/tests/products/CMFonFiveTest/configure.zcml
    12.4 @@ -0,0 +1,34 @@
    12.5 +<configure xmlns="http://namespaces.zope.org/zope"
    12.6 +           xmlns:browser="http://namespaces.zope.org/browser"
    12.7 +           xmlns:five="http://namespaces.zope.org/five">
    12.8 +
    12.9 +  <five:traversable class=".cmfcontent.CMFContent" />
   12.10 +
   12.11 +  <!-- browser menu support -->
   12.12 +  <browser:menu
   12.13 +      id="folder"
   12.14 +      title="CMF menu" />
   12.15 +
   12.16 +  <browser:menuItem
   12.17 +      for=".interfaces.ICMFContent"
   12.18 +      menu="folder"
   12.19 +      title="Public Test Menu Item"
   12.20 +      action="public.html"
   12.21 +      description="This is a public test menu item"
   12.22 +      permission="zope.Public"
   12.23 +      />
   12.24 +
   12.25 +  <browser:menuItem
   12.26 +      for=".interfaces.ICMFContent"
   12.27 +      menu="folder"
   12.28 +      title="Protected Test Menu Item"
   12.29 +      action="protected.html"
   12.30 +      description="This is a protected test menu item"
   12.31 +      permission="zope2.ManageUsers"
   12.32 +      />
   12.33 +
   12.34 +  <five:implements class="ZPublisher.HTTPRequest.HTTPRequest"
   12.35 +    interface="zope.publisher.interfaces.browser.IDefaultBrowserLayer"
   12.36 +    />
   12.37 +
   12.38 +</configure>
    13.1 new file mode 100644
    13.2 --- /dev/null
    13.3 +++ b/tests/products/CMFonFiveTest/interfaces.py
    13.4 @@ -0,0 +1,5 @@
    13.5 +from zope.interface import Interface
    13.6 +
    13.7 +class ICMFContent(Interface):
    13.8 +    pass
    13.9 +
    14.1 new file mode 100644
    14.2 --- /dev/null
    14.3 +++ b/tests/products/CMFonFiveTest/tests/__init__.py
    14.4 @@ -0,0 +1,4 @@
    14.5 +""" Unit tests for CMFonFive.
    14.6 +
    14.7 +$Id$
    14.8 +"""
    15.1 new file mode 100644
    15.2 --- /dev/null
    15.3 +++ b/tests/products/CMFonFiveTest/tests/test_actionstool.py
    15.4 @@ -0,0 +1,52 @@
    15.5 +""" Unit tests for mapped interfaces.
    15.6 +
    15.7 +$Id$
    15.8 +"""
    15.9 +
   15.10 +import unittest
   15.11 +from Testing import ZopeTestCase
   15.12 +from Testing.ZopeTestCase.functional import Functional
   15.13 +from Products.CMFCore.utils import getToolByName
   15.14 +from Products.Five.traversable import newInteraction
   15.15 +
   15.16 +# we need to install test products *before* Five as Five
   15.17 +# looks up zcml files in the products it can find.
   15.18 +ZopeTestCase.installProduct('CMFonFiveTest')
   15.19 +ZopeTestCase.installProduct('CMFonFive')
   15.20 +ZopeTestCase.installProduct('Five')
   15.21 +
   15.22 +class ActionsToolTests(ZopeTestCase.ZopeTestCase):
   15.23 +
   15.24 +    def afterSetUp(self):
   15.25 +        self.folder.manage_addProduct['CMFonFive'].manage_addTool(
   15.26 +            'Five Actions Tool')
   15.27 +        self.login()
   15.28 +
   15.29 +    def test_ActionsToolDocument(self):
   15.30 +        tool = getToolByName(self.folder, 'portal_fiveactions')
   15.31 +        # The action created for the content should appear in the list
   15.32 +        # of actions for such content
   15.33 +        self.folder.manage_addProduct['CMFonFiveTest'].manage_addCMFContent(
   15.34 +            'content', 'Content Title')
   15.35 +        newInteraction()
   15.36 +        actions = tool.listActions(object=self.folder.content)
   15.37 +        action_names = [action.id for action in actions]
   15.38 +        self.failUnless('action_content_public.html' in action_names,
   15.39 +            'Expected menu item was not found in action list')
   15.40 +        # But not the protected action:
   15.41 +        self.failIf('action_content_protected.html' in action_names,
   15.42 +            'Protected menu item was found in action list')
   15.43 +        # And there should be no actions anywhere else:
   15.44 +        self.failUnlessEqual(list(tool.listActions(object=self.folder)), [])
   15.45 +
   15.46 +
   15.47 +def test_suite():
   15.48 +    suite = unittest.TestSuite()
   15.49 +    suite.addTest(unittest.makeSuite(ActionsToolTests))
   15.50 +    return suite
   15.51 +
   15.52 +
   15.53 +
   15.54 +
   15.55 +if __name__ == '__main__':
   15.56 +    unittest.main()
    16.1 new file mode 100644
    16.2 --- /dev/null
    16.3 +++ b/tests/products/CMFonFiveTest/www/cmfContentAdd.zpt
    16.4 @@ -0,0 +1,45 @@
    16.5 +<h1 tal:replace="structure here/manage_page_header">Header</h1>
    16.6 +
    16.7 +<h2 tal:define="form_title string:Add CMF Content"
    16.8 +    tal:replace="structure here/manage_form_title">Form Title</h2>
    16.9 +
   16.10 +<p class="form-help">
   16.11 +Add CMF Content
   16.12 +</p>
   16.13 +
   16.14 +<form action="manage_addCMFContent" method="post">
   16.15 +<table cellspacing="0" cellpadding="2" border="0">
   16.16 +  <tr>
   16.17 +    <td align="left" valign="top">
   16.18 +    <div class="form-label">
   16.19 +    Id
   16.20 +    </div>
   16.21 +    </td>
   16.22 +    <td align="left" valign="top">
   16.23 +    <input type="text" name="id" size="40" />
   16.24 +    </td>
   16.25 +  </tr>
   16.26 +  <tr>
   16.27 +    <td align="left" valign="top">
   16.28 +    <div class="form-label">
   16.29 +    Title
   16.30 +    </div>
   16.31 +    </td>
   16.32 +    <td align="left" valign="top">
   16.33 +    <input type="text" name="title" size="40" />
   16.34 +    </td>
   16.35 +  </tr>
   16.36 +  <tr>
   16.37 +    <td align="left" valign="top">
   16.38 +    </td>
   16.39 +    <td align="left" valign="top">
   16.40 +    <div class="form-element">
   16.41 +    <input class="form-element" type="submit" name="submit_add"
   16.42 +     value=" Add " />
   16.43 +    </div>
   16.44 +    </td>
   16.45 +  </tr>
   16.46 +</table>
   16.47 +</form>
   16.48 +
   16.49 +<h1 tal:replace="structure here/manage_page_footer">Footer</h1>
    17.1 new file mode 100644
    17.2 --- /dev/null
    17.3 +++ b/tests/products/README.txt
    17.4 @@ -0,0 +1,17 @@
    17.5 +This directory contains a product CMFonFiveTest, which is used to
    17.6 +do testing of CMFonFive. Mainly, it tests that the zcml statements
    17.7 +work, by having a small product that uses the zcml statements.
    17.8 +
    17.9 +Most other things can be tested in the main unit tests of CMFonFive.
   17.10 +
   17.11 +To use these tests, move or link) the CMFonFiveTest directory to
   17.12 +your Products directory:
   17.13 +
   17.14 +  cd <zope_dir>/Products
   17.15 +  ln -s CMFonFive/tests/products/CMFonFiveTest .
   17.16 +
   17.17 +Then run the unit tests as normal
   17.18 +
   17.19 +  cd <zope_dir>
   17.20 +  bin/zopectl test --dir Products/CMFonFiveTest
   17.21 +
    18.1 new file mode 100644
    18.2 index 0000000000000000000000000000000000000000..8aa90b53b65ee410b8a9be3819fcba223c936c4e
    18.3 GIT binary patch
    18.4 literal 166
    18.5 zc${<hbhEHb6krfwc+9}CY0HL=j*jye&gSIiPn<a6=+R>pRTa;lKc6*c#>$l|!@|OE
    18.6 z+_;gLl<4i_^&bor|MB@IrlcyAXO?6rxO@5rFev_HVdP@qXV75)0+6W;ERG*edamB8
    18.7 z5Tng@Gc-|#-=T@ALFE+FH0H}Z`3En&SC;VkC&SXpufZbA$LjKNlL8A@=P~XD7D8Nh
    18.8 Qa~U7Jeo%8GoQ1&}0ANHx<p2Nx
    18.9 
    19.1 new file mode 100644
    19.2 --- /dev/null
    19.3 +++ b/version.txt
    19.4 @@ -0,0 +1,1 @@
    19.5 +CMFonFive-1.2.0
    20.1 new file mode 100644
    20.2 --- /dev/null
    20.3 +++ b/www/document_edit.pt
    20.4 @@ -0,0 +1,77 @@
    20.5 +<tal:x tal:define="here nocall: here/context;">
    20.6 +<html xmlns:tal="http://xml.zope.org/namespaces/tal"
    20.7 +      xmlns:metal="http://xml.zope.org/namespaces/metal"
    20.8 +      metal:use-macro="here/main_template/macros/master"
    20.9 +>
   20.10 +<body>
   20.11 +<div metal:fill-slot="main" i18n:domain="cmf_default">
   20.12 +<div class="Desktop">
   20.13 +
   20.14 +<h2 i18n:translate="">Edit <span
   20.15 +    tal:replace="here/getId" i18n:name="objectid">My ID</span></h2>
   20.16 +
   20.17 +<form action="document_edit" method="post" enctype="multipart/form-data"
   20.18 +      tal:attributes="action string:${here/absolute_url}/document_edit"
   20.19 +>
   20.20 +
   20.21 + <input type="hidden" name="SafetyBelt" value=""
   20.22 +        tal:attributes="value here/SafetyBelt" />
   20.23 +
   20.24 +<table class="FormLayout">
   20.25 + <tr>
   20.26 +  <th i18n:translate="">Title</th>
   20.27 +  <td>
   20.28 +   <span tal:replace="here/Title">Title</span>
   20.29 +  </td>
   20.30 + </tr>
   20.31 + <tr>
   20.32 +  <th i18n:translate="">Description</th>
   20.33 +  <td>
   20.34 +   <span tal:replace="here/Description">Description</span>
   20.35 +  </td>
   20.36 + </tr>
   20.37 + <tr>
   20.38 +  <th i18n:translate="">Format</th>
   20.39 +  <td>
   20.40 +   <input type="radio" name="text_format" value="structured-text" id="cb_stx"
   20.41 +          tal:attributes="
   20.42 +                checked python:path('here/text_format')=='structured-text'" />
   20.43 +   <label for="cb_stx" i18n:translate="">structured-text</label>
   20.44 +   <input type="radio" name="text_format" value="plain" id="cb_plain"
   20.45 +          tal:attributes="checked python:path('here/text_format')=='plain'" />
   20.46 +   <label for="cb_plain" i18n:translate="">plain text</label>
   20.47 +   <input type="radio" name="text_format" value="html" id="cb_html"
   20.48 +          tal:attributes="checked python:path('here/text_format')=='html'" />
   20.49 +   <label for="cb_html" i18n:translate="">html</label>
   20.50 +  </td>
   20.51 + </tr>
   20.52 + <tr>
   20.53 +  <th i18n:translate="">Upload</th>
   20.54 +  <td>
   20.55 +   <input type="file" name="file" size="25" />
   20.56 +  </td>
   20.57 + </tr>
   20.58 + <tr>
   20.59 +  <th class="TextField" i18n:translate="">Edit</th>
   20.60 +  <td class="TextField">
   20.61 +   <textarea name="text:text" rows="20" cols="80" wrap="soft"
   20.62 +             tal:content="here/EditableBody"></textarea>
   20.63 +  </td>
   20.64 + </tr>
   20.65 + <tr>
   20.66 +  <td> <br /> </td>
   20.67 +  <td>
   20.68 +   <input type="submit" name="change" value="Change"
   20.69 +          i18n:attributes="value" />
   20.70 +   <input type="submit" name="change_and_view" value="Change and View"
   20.71 +          i18n:attributes="value" />
   20.72 +  </td>
   20.73 + </tr>
   20.74 +</table>
   20.75 +</form>
   20.76 +
   20.77 +</div>
   20.78 +</div>
   20.79 +</body>
   20.80 +</html>
   20.81 +</tal:x>
    21.1 new file mode 100644
    21.2 --- /dev/null
    21.3 +++ b/www/document_view.pt
    21.4 @@ -0,0 +1,37 @@
    21.5 +<tal:x tal:define="here nocall: here/context;">
    21.6 +<html xmlns:tal="http://xml.zope.org/namespaces/tal"
    21.7 +      xmlns:metal="http://xml.zope.org/namespaces/metal"
    21.8 +      metal:use-macro="here/main_template/macros/master">
    21.9 +  <metal:block fill-slot="base">
   21.10 +      <base href=""
   21.11 +            tal:attributes="href python: here.absolute_url() + '/'">
   21.12 +  </metal:block>
   21.13 +<body>
   21.14 +
   21.15 +<div metal:fill-slot="header">
   21.16 +
   21.17 +    <h1 id="DesktopTitle"
   21.18 +        tal:content="here/Title">Document Title</h1>
   21.19 +
   21.20 +    <div id="DesktopDescription" tal:content="here/Description">
   21.21 +        Document Description goes here.
   21.22 +    </div>
   21.23 +
   21.24 +    <div metal:use-macro="here/content_byline/macros/byline">By Me</div>
   21.25 +
   21.26 +</div>
   21.27 +
   21.28 +<div metal:fill-slot="main">
   21.29 +
   21.30 +<div tal:replace="structure here/CookedBody">Cooked Body</div>
   21.31 +
   21.32 +<div class="Discussion">
   21.33 +   <span tal:replace="structure here/viewThreadsAtBottom"
   21.34 +         tal:condition="here/viewThreadsAtBottom|nothing"></span>
   21.35 +</div>
   21.36 +
   21.37 +</div>
   21.38 +
   21.39 +</body>
   21.40 +</html>
   21.41 +</tal:x>
    22.1 new file mode 100644
    22.2 --- /dev/null
    22.3 +++ b/www/folder_contents.pt
    22.4 @@ -0,0 +1,215 @@
    22.5 +<tal:x tal:define="global here here/context;" />
    22.6 +<html xmlns:tal="http://xml.zope.org/namespaces/tal"
    22.7 +      xmlns:metal="http://xml.zope.org/namespaces/metal"
    22.8 +      metal:use-macro="here/context/main_template/macros/master"
    22.9 +>
   22.10 +<body>
   22.11 +<div metal:fill-slot="main"
   22.12 +     tal:define="m_tool here/portal_membership;
   22.13 +                 checkPerm nocall: m_tool/checkPermission;
   22.14 +                 list_here python:checkPerm('List folder contents', here);
   22.15 +                 list_parent python:checkPerm( 'List folder contents', here
   22.16 +                                             , 'aq_parent' );
   22.17 +                "
   22.18 +     i18n:domain="cmf_default"
   22.19 +>
   22.20 +<div tal:condition="not: list_here"
   22.21 +      tal:define="response request/RESPONSE;
   22.22 +                  url here/absolute_url;
   22.23 +                 "
   22.24 + >
   22.25 +  <span tal:define="redirect python: response.redirect( url )"></span>
   22.26 +</div>
   22.27 +
   22.28 +<!-- This is the desktop area -->
   22.29 +<div class="Desktop">
   22.30 +
   22.31 +<h1 i18n:translate="">Desktop</h1>
   22.32 +
   22.33 +<form action="" method="post"
   22.34 +      tal:attributes="action here/absolute_url">
   22.35 + <table class="FormLayout">
   22.36 +  <tr>
   22.37 +   <td valign="top">
   22.38 +    <table class="ContentsList">
   22.39 +     <!-- Navigate to parent -->
   22.40 +     <tbody tal:condition="list_parent">
   22.41 +      <tr valign="top"
   22.42 +          tal:define="upNav python: hasattr(here.aq_parent, 'portal_url');">
   22.43 +        <td colspan="3" align="left">
   22.44 +         <span tal:condition="upNav | nothing">
   22.45 +          <a href="../folder_contents"
   22.46 +          ><img src="" alt="[Link]" border="0"
   22.47 +                tal:attributes="src string:${here/portal_url}/UpFolder_icon.gif"
   22.48 +          /></a>
   22.49 +         </span>&nbsp;&nbsp;
   22.50 +         <span tal:condition="upNav">
   22.51 +          <span tal:omit-tag="" i18n:translate="">Up to</span>
   22.52 +          <a href="../folder_contents">Up</a>
   22.53 +         </span>
   22.54 +         <span tal:condition="python: not(upNav)">
   22.55 +           <span class="mild" i18n:translate="">Root</span>
   22.56 +         </span>
   22.57 +        </td>
   22.58 +      </tr>
   22.59 +     </tbody>
   22.60 +     <!-- This row holds the "two column list" -->
   22.61 +     <tr tal:define="global b_start string:0;
   22.62 +                     b_start request/b_start | b_start;
   22.63 +                     filterString python: request.get('folderfilter', '');
   22.64 +                     filter python: here.decodeFolderFilter(filterString);
   22.65 +                     items python: here.listFolderContents(
   22.66 +                                                contentFilter=filter);
   22.67 +                     Batch nocall: modules/ZTUtils/Batch;
   22.68 +                     global batch1 python:Batch( items, 20, int(b_start)
   22.69 +                                              , orphan=0);
   22.70 +                     global batch2 batch1/next;
   22.71 +                    "
   22.72 +     >
   22.73 +      <!-- First column, first half batch in 'batch1'. -->
   22.74 +      <td colspan="1" align="left" width="49%">
   22.75 +       <table>
   22.76 +        <tr valign="top" tal:repeat="item batch1">
   22.77 +         <td align="left" width="5" nowrap
   22.78 +             tal:define="folderish item/isPrincipiaFolderish;
   22.79 +                         portalish item/isPortalContent | nothing;
   22.80 +                         global methodID python:( folderish
   22.81 +                                              and 'folder_contents'
   22.82 +                                               or (portalish and 'view' or '')
   22.83 +                                                );
   22.84 +                         global icon item/getIcon | item/icon | nothing
   22.85 +                        ">
   22.86 +            <input type="checkbox" name="ids:list" value="" id=""
   22.87 +                   tal:attributes="value item/getId;
   22.88 +                                   id python: 'cb_' + item.getId()" />
   22.89 +         </td>
   22.90 +         <td>
   22.91 +          <span tal:condition="icon">
   22.92 +           <a href=""
   22.93 +              tal:attributes="href string:${item/absolute_url}/${methodID};
   22.94 +                             "
   22.95 +           ><img src="" alt="" border="0"
   22.96 +                 tal:attributes="src string:${here/portal_url}/${icon};
   22.97 +                                 alt item/Type|nothing;"
   22.98 +                 i18n:attributes="alt" /></a>
   22.99 +          </span>
  22.100 +         </td>
  22.101 +         <td>
  22.102 +          <a href=""
  22.103 +             tal:attributes="href string:${item/absolute_url}/${methodID};
  22.104 +                            "
  22.105 +          ><span tal:replace="item/getId">ID</span>
  22.106 +           <span tal:condition="item/Title"
  22.107 +                 tal:replace="string:(${item/Title})">(Title)</span></a>
  22.108 +         </td>
  22.109 +        </tr>
  22.110 +       </table>
  22.111 +      </td>
  22.112 +      <!-- Spacer column. -->
  22.113 +      <td width="2%">&nbsp;</td>
  22.114 +      <!-- Second column, second half batch in 'batch2'. -->
  22.115 +      <td colspan="1" width="49%">
  22.116 +       <table>
  22.117 +        <tr valign="top" tal:repeat="item batch2">
  22.118 +         <td align="left" width="5" nowrap
  22.119 +             tal:define="folderish item/isPrincipiaFolderish;
  22.120 +                         portalish item/isPortalContent | nothing;
  22.121 +                         global methodID python:( folderish
  22.122 +                                              and 'folder_contents'
  22.123 +                                               or (portalish and 'view' or '')
  22.124 +                                                );
  22.125 +                         global icon item/getIcon | item/icon | nothing
  22.126 +                        ">
  22.127 +            <input type="checkbox" name="ids:list" value="" id=""
  22.128 +                   tal:attributes="value item/getId;
  22.129 +                                   id python: 'cb_' + item.getId()" />
  22.130 +         </td>
  22.131 +         <td>
  22.132 +          <span tal:condition="icon">
  22.133 +           <a href=""
  22.134 +              tal:attributes="href string:${item/absolute_url}/${methodID};
  22.135 +                             "
  22.136 +           ><img src="" alt="" border="0"
  22.137 +                 tal:attributes="src string:${here/portal_url}/${icon};
  22.138 +                                 alt item/Type|nothing;"
  22.139 +                 i18n:attributes="alt" /></a>
  22.140 +          </span>
  22.141 +         </td>
  22.142 +         <td>
  22.143 +          <a href=""
  22.144 +             tal:attributes="href string:${item/absolute_url}/${methodID};
  22.145 +                            "
  22.146 +          ><span tal:replace="item/getId">ID</span>
  22.147 +           <span tal:condition="item/Title"
  22.148 +                 tal:replace="string:(${item/Title})">(Title)</span></a>
  22.149 +         </td>
  22.150 +        </tr>
  22.151 +       </table>
  22.152 +      </td>
  22.153 +
  22.154 +     </tr>
  22.155 +
  22.156 +     <tr>
  22.157 +      <td align="left">
  22.158 +       <span tal:define="p batch1/previous" tal:condition="p">
  22.159 +        <a href=""
  22.160 +           tal:attributes="
  22.161 +                href string:folder_contents?b_start=${p/previous/first}"
  22.162 +           i18n:translate=""
  22.163 +        >Previous Items</a>
  22.164 +       </span>
  22.165 +      </td>
  22.166 +      <td>&nbsp;</td>
  22.167 +      <td align="right">
  22.168 +       <span tal:define="n batch2/next | nothing" tal:condition="n">
  22.169 +        <a href=""
  22.170 +           tal:attributes="
  22.171 +                href string:folder_contents?b_start=${batch2/end}"
  22.172 +           i18n:translate=""
  22.173 +        >Next Items</a>
  22.174 +       </span>
  22.175 +      </td>
  22.176 +     </tr>
  22.177 +    <!-- end contentList -->
  22.178 +    </table>
  22.179 +
  22.180 +    <table border="0" cellspacing="0" cellpadding="2">
  22.181 +     <tr>
  22.182 +      <td align="left" valign="top" width="16"></td>
  22.183 +      <td align="left" valign="top">
  22.184 +      <span tal:condition="python: checkPerm('Add portal content', here)
  22.185 +                                   and here.allowedContentTypes()">
  22.186 +        <input type="submit" name="folder_factories:method" value="New..."
  22.187 +               i18n:attributes="value" />
  22.188 +      </span>
  22.189 +      <span tal:condition="python: checkPerm('View management screens', here)">
  22.190 +        <input type="submit" name="folder_rename_form:method" value="Rename"
  22.191 +               i18n:attributes="value" />
  22.192 +        <input type="submit" name="folder_cut:method" value="Cut"
  22.193 +               i18n:attributes="value" />
  22.194 +        <input type="submit" name="folder_copy:method" value="Copy"
  22.195 +               i18n:attributes="value" />
  22.196 +        <span tal:condition="here/cb_dataValid">
  22.197 +        <input type="submit" name="folder_paste:method" value="Paste"
  22.198 +               i18n:attributes="value" />
  22.199 +        </span>
  22.200 +      </span>
  22.201 +      <span tal:condition="python: checkPerm('Delete objects', here)">
  22.202 +        <input type="submit" name="folder_delete:method" value="Delete"
  22.203 +               i18n:attributes="value" />
  22.204 +      </span>
  22.205 +      </td>
  22.206 +     </tr>
  22.207 +    </table>
  22.208 +
  22.209 +   </td>
  22.210 +  </tr>
  22.211 + </table>
  22.212 +</form>
  22.213 +
  22.214 +<div tal:replace="structure here/folder_filter_form">Filter Form Here</div>
  22.215 +
  22.216 +</div>
  22.217 +</div>
  22.218 +</body>
  22.219 +</html>