Refactored ordered container stuff out of loops package and put into cybertools.container
git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@1035 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
e577086b0e
commit
0be4751c55
11 changed files with 437 additions and 3 deletions
|
@ -22,14 +22,14 @@ body {
|
||||||
#header,#footer {width:100%}
|
#header,#footer {width:100%}
|
||||||
#menu,#content,#sub-section {float:left}
|
#menu,#content,#sub-section {float:left}
|
||||||
#menu {width:20%}
|
#menu {width:20%}
|
||||||
#content {width:60%}
|
#content {width:67%}
|
||||||
#sub-section {width:19.9%}
|
#sub-section {width:12.9%}
|
||||||
#footer {clear:left}
|
#footer {clear:left}
|
||||||
|
|
||||||
/* more general stuff */
|
/* more general stuff */
|
||||||
|
|
||||||
.box {
|
.box {
|
||||||
margin: 12px 15px 8px 10px;
|
margin: 12px 12px 8px 10px;
|
||||||
border-left: none;
|
border-left: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
4
container/DEPENDENCIES.cfg
Normal file
4
container/DEPENDENCIES.cfg
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
zope.app
|
||||||
|
zope.component
|
||||||
|
zope.interface
|
||||||
|
persistent
|
48
container/README.txt
Normal file
48
container/README.txt
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
Ordered Containers
|
||||||
|
==================
|
||||||
|
|
||||||
|
($Id$)
|
||||||
|
|
||||||
|
>>> from zope.app.testing.setup import placefulSetUp, placefulTearDown
|
||||||
|
>>> site = placefulSetUp(True)
|
||||||
|
>>> from zope.interface import implements
|
||||||
|
|
||||||
|
Let's add an ordered container and place some objects in it:
|
||||||
|
|
||||||
|
>>> from zope.app.container.interfaces import IOrderedContainer
|
||||||
|
>>> import zope.app.container.ordered
|
||||||
|
>>> class OrderedContainer(zope.app.container.ordered.OrderedContainer):
|
||||||
|
... implements(IOrderedContainer)
|
||||||
|
|
||||||
|
>>> c1 = OrderedContainer()
|
||||||
|
>>> site['c1'] = c1
|
||||||
|
>>> c1['sub1'] = OrderedContainer()
|
||||||
|
>>> c1['sub2'] = OrderedContainer()
|
||||||
|
>>> c1['sub3'] = OrderedContainer()
|
||||||
|
>>> c1['sub4'] = OrderedContainer()
|
||||||
|
>>> c1.keys()
|
||||||
|
['sub1', 'sub2', 'sub3', 'sub4']
|
||||||
|
|
||||||
|
A special management view provides methods for moving objects down, up,
|
||||||
|
to the bottom, and to the top
|
||||||
|
|
||||||
|
>>> from cybertools.container.ordered import OrderedContainerView
|
||||||
|
>>> from zope.publisher.browser import TestRequest
|
||||||
|
>>> view = OrderedContainerView(c1, TestRequest())
|
||||||
|
>>> view.moveToBottom(('sub3',))
|
||||||
|
>>> c1.keys()
|
||||||
|
['sub1', 'sub2', 'sub4', 'sub3']
|
||||||
|
>>> view.moveUp(('sub4',), 1)
|
||||||
|
>>> c1.keys()
|
||||||
|
['sub1', 'sub4', 'sub2', 'sub3']
|
||||||
|
>>> view.moveToTop(('sub2',))
|
||||||
|
>>> c1.keys()
|
||||||
|
['sub2', 'sub1', 'sub4', 'sub3']
|
||||||
|
>>> view.moveDown(('sub2',), 2)
|
||||||
|
>>> c1.keys()
|
||||||
|
['sub1', 'sub4', 'sub2', 'sub3']
|
||||||
|
|
||||||
|
The end...
|
||||||
|
==========
|
||||||
|
|
||||||
|
>>> placefulTearDown()
|
5
container/SETUP.cfg
Normal file
5
container/SETUP.cfg
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# Tell zpkg how to install the ZCML slugs.
|
||||||
|
|
||||||
|
<data-files zopeskel/etc/package-includes>
|
||||||
|
cybertools.container-*.zcml
|
||||||
|
</data-files>
|
4
container/__init__.py
Normal file
4
container/__init__.py
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
"""
|
||||||
|
$Id$
|
||||||
|
"""
|
||||||
|
|
21
container/configure.zcml
Normal file
21
container/configure.zcml
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<!-- $Id$ -->
|
||||||
|
|
||||||
|
<configure
|
||||||
|
xmlns="http://namespaces.zope.org/browser"
|
||||||
|
xmlns:zope="http://namespaces.zope.org/zope"
|
||||||
|
i18n_domain="zope">
|
||||||
|
|
||||||
|
<pages
|
||||||
|
for="zope.app.container.interfaces.IOrderedContainer"
|
||||||
|
class=".ordered.OrderedContainerView"
|
||||||
|
permission="zope.ManageContent">
|
||||||
|
<page name="contents.html" template="contents.pt"
|
||||||
|
menu="zmi_views" title="Contents"
|
||||||
|
/>
|
||||||
|
<page name="move_down" attribute="moveDown" />
|
||||||
|
<page name="move_up" attribute="moveUp" />
|
||||||
|
<page name="move_bottom" attribute="moveToBottom" />
|
||||||
|
<page name="move_top" attribute="moveToTop" />
|
||||||
|
</pages>
|
||||||
|
|
||||||
|
</configure>
|
216
container/contents.pt
Normal file
216
container/contents.pt
Normal file
|
@ -0,0 +1,216 @@
|
||||||
|
<html metal:use-macro="context/@@standard_macros/view"
|
||||||
|
i18n:domain="zope">
|
||||||
|
<body>
|
||||||
|
<div metal:fill-slot="body">
|
||||||
|
<div metal:define-macro="contents">
|
||||||
|
|
||||||
|
<tal:checkmove define="isMoveAction view/checkMoveAction">
|
||||||
|
|
||||||
|
<tal:showlisting condition="not:isMoveAction">
|
||||||
|
<form name="containerContentsForm" method="post" action="."
|
||||||
|
tal:attributes="action request/URL"
|
||||||
|
tal:define="container_contents view/listContentInfo">
|
||||||
|
|
||||||
|
<input type="hidden" name="type_name" value=""
|
||||||
|
tal:attributes="value request/type_name"
|
||||||
|
tal:condition="request/type_name|nothing"
|
||||||
|
/>
|
||||||
|
<input type="hidden" name="retitle_id" value=""
|
||||||
|
tal:attributes="value request/retitle_id"
|
||||||
|
tal:condition="request/retitle_id|nothing"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div class="page_error"
|
||||||
|
tal:condition="view/error"
|
||||||
|
tal:content="view/error"
|
||||||
|
i18n:translate="">
|
||||||
|
Error message
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table id="sortable" class="listing" summary="Content listing"
|
||||||
|
i18n:attributes="summary">
|
||||||
|
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th> </th>
|
||||||
|
<th i18n:translate="">Name</th>
|
||||||
|
<th i18n:translate="">Title</th>
|
||||||
|
<th i18n:translate="">Size</th>
|
||||||
|
<th i18n:translate="">Created</th>
|
||||||
|
<th i18n:translate="">Modified</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
<metal:block tal:condition="view/hasAdding">
|
||||||
|
<tr tal:define="names_required context/@@+/nameAllowed"
|
||||||
|
tal:condition="python:names_required and request.has_key('type_name')">
|
||||||
|
<td></td>
|
||||||
|
<td><input name="new_value" id="focusid" value="" /></td>
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
</metal:block>
|
||||||
|
|
||||||
|
<metal:block tal:define="supportsRename view/supportsRename"
|
||||||
|
tal:repeat="item container_contents">
|
||||||
|
<tr tal:define="oddrow repeat/item/odd; url item/url;
|
||||||
|
id_quoted item/id/url:quote"
|
||||||
|
tal:attributes="class python:oddrow and 'even' or 'odd'" >
|
||||||
|
<td>
|
||||||
|
<input type="checkbox" class="noborder" name="ids:list" id="#"
|
||||||
|
value="#"
|
||||||
|
tal:attributes="value item/id;
|
||||||
|
id item/cb_id;
|
||||||
|
checked request/ids_checked|nothing;"/>
|
||||||
|
</td>
|
||||||
|
<td><a href="#"
|
||||||
|
tal:attributes="href
|
||||||
|
string:${url}/@@SelectedManagementView.html"
|
||||||
|
tal:content="structure item/icon|default">
|
||||||
|
</a
|
||||||
|
><span tal:condition="item/rename"
|
||||||
|
><input name="new_value:list"
|
||||||
|
tal:attributes="value item/id"
|
||||||
|
/><input type="hidden" name="rename_ids:list" value=""
|
||||||
|
tal:attributes="value item/rename"
|
||||||
|
/></span
|
||||||
|
><span tal:condition="not:item/rename">
|
||||||
|
<a href="#"
|
||||||
|
tal:attributes="href
|
||||||
|
string:${url}/@@SelectedManagementView.html"
|
||||||
|
tal:content="item/id"
|
||||||
|
i18n:translate=""
|
||||||
|
>foo</a
|
||||||
|
><a href="#"
|
||||||
|
tal:attributes="href
|
||||||
|
string:${request/URL}?rename_ids:list=${id_quoted}"
|
||||||
|
tal:condition="supportsRename"
|
||||||
|
> </a
|
||||||
|
></span
|
||||||
|
></td>
|
||||||
|
<td>
|
||||||
|
<input name="new_value" id="focusid"
|
||||||
|
tal:attributes="value item/title|nothing"
|
||||||
|
tal:condition="item/retitle"
|
||||||
|
/>
|
||||||
|
<a href="#"
|
||||||
|
tal:attributes="href
|
||||||
|
string:${request/URL}?retitle_id=${id_quoted}"
|
||||||
|
tal:condition="item/retitleable"
|
||||||
|
tal:content="item/title|default"
|
||||||
|
i18n:translate=""
|
||||||
|
> </a>
|
||||||
|
<span
|
||||||
|
tal:condition="item/plaintitle"
|
||||||
|
tal:content="item/title|default"
|
||||||
|
i18n:translate=""
|
||||||
|
> </span>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td><span tal:content="item/size/sizeForDisplay|nothing"
|
||||||
|
i18n:translate="">
|
||||||
|
</span></td>
|
||||||
|
<td><span tal:define="created item/created|default"
|
||||||
|
tal:content="created"
|
||||||
|
i18n:translate=""> </span></td>
|
||||||
|
<td><span tal:define="modified item/modified|default"
|
||||||
|
tal:content="modified"
|
||||||
|
i18n:translate=""> </span></td>
|
||||||
|
</tr>
|
||||||
|
</metal:block>
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div tal:condition="view/normalButtons">
|
||||||
|
|
||||||
|
<input type="submit" name="container_rename_button" value="Rename"
|
||||||
|
i18n:attributes="value container-rename-button"
|
||||||
|
tal:condition="view/supportsRename"
|
||||||
|
/>
|
||||||
|
<input type="submit" name="container_cut_button" value="Cut"
|
||||||
|
i18n:attributes="value container-cut-button"
|
||||||
|
tal:condition="view/supportsCut"
|
||||||
|
/>
|
||||||
|
<input type="submit" name="container_copy_button" value="Copy"
|
||||||
|
i18n:attributes="value container-copy-button"
|
||||||
|
tal:condition="view/supportsCopy"
|
||||||
|
/>
|
||||||
|
<input type="submit" name="container_paste_button" value="Paste"
|
||||||
|
tal:condition="view/hasClipboardContents"
|
||||||
|
i18n:attributes="value container-paste-button"
|
||||||
|
/>
|
||||||
|
<input type="submit" name="container_delete_button" value="Delete"
|
||||||
|
i18n:attributes="value container-delete-button"
|
||||||
|
tal:condition="view/supportsDelete"
|
||||||
|
i18n:domain="zope"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div tal:condition="view/hasAdding" tal:omit-tag="">
|
||||||
|
<div tal:omit-tag=""
|
||||||
|
tal:define="adding nocall:context/@@+;
|
||||||
|
addingInfo adding/addingInfo;
|
||||||
|
has_custom_add_view adding/hasCustomAddView;
|
||||||
|
names_required adding/nameAllowed"
|
||||||
|
tal:condition="adding/isSingleMenuItem">
|
||||||
|
<input type="submit" name="container_add_button" value="Add"
|
||||||
|
i18n:attributes="value add-button"
|
||||||
|
i18n:domain="zope"
|
||||||
|
/>
|
||||||
|
<input type="text" name="single_new_value" id="focusid"
|
||||||
|
tal:condition="python:names_required and not has_custom_add_view"
|
||||||
|
i18n:domain="zope"
|
||||||
|
/>
|
||||||
|
<input type="hidden" name="single_type_name"
|
||||||
|
value=""
|
||||||
|
tal:attributes="value python:addingInfo[0]['action']"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div tal:condition="view/orderable">
|
||||||
|
<input type="submit" name="move_top" value="Top"
|
||||||
|
i18n:attributes="value container-movetop-button"
|
||||||
|
i18n:domain="zope" />
|
||||||
|
<input type="submit" name="move_up" value="Up"
|
||||||
|
i18n:attributes="value container-moveup-button"
|
||||||
|
i18n:domain="zope" />
|
||||||
|
<input type="text" size="2" name="delta" value="1" />
|
||||||
|
<input type="submit" name="move_down" value="Down"
|
||||||
|
i18n:attributes="value container-moveup-button"
|
||||||
|
i18n:domain="zope" />
|
||||||
|
<input type="submit" name="move_bottom" value="Bottom"
|
||||||
|
i18n:attributes="value container-movebottom-button"
|
||||||
|
i18n:domain="zope" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div tal:condition="view/specialButtons">
|
||||||
|
<input type="submit" value="Apply"
|
||||||
|
i18n:attributes="value container-apply-button"
|
||||||
|
/>
|
||||||
|
<input type="submit" name="container_cancel_button" value="Cancel"
|
||||||
|
i18n:attributes="value container-cancel-button"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</tal:showlisting>
|
||||||
|
</tal:checkmove>
|
||||||
|
|
||||||
|
|
||||||
|
<script type="text/javascript"><!--
|
||||||
|
if (document.containerContentsForm.new_value)
|
||||||
|
document.containerContentsForm.new_value.focus();
|
||||||
|
//-->
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
1
container/cybertools.container-configure.zcml
Normal file
1
container/cybertools.container-configure.zcml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<include package="cybertools.container" />
|
27
container/interfaces.py
Normal file
27
container/interfaces.py
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#
|
||||||
|
# Copyright (c) 2006 Helmut Merz helmutm@cy55.de
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
interface definitions for ordered containers.
|
||||||
|
|
||||||
|
$Id$
|
||||||
|
"""
|
||||||
|
|
||||||
|
from zope.interface import Interface, Attribute
|
||||||
|
|
||||||
|
|
95
container/ordered.py
Normal file
95
container/ordered.py
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
#
|
||||||
|
# Copyright (c) 2006 Helmut Merz helmutm@cy55.de
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
Ordered container implementation.
|
||||||
|
|
||||||
|
$Id$
|
||||||
|
"""
|
||||||
|
|
||||||
|
from zope.app import zapi
|
||||||
|
from zope.app.container.ordered import OrderedContainer as BaseOrderedContainer
|
||||||
|
from zope.cachedescriptors.property import Lazy
|
||||||
|
from zope.app.container.browser.contents import JustContents
|
||||||
|
|
||||||
|
|
||||||
|
class OrderedContainerView(JustContents):
|
||||||
|
""" A view providing the necessary methods for moving sub-objects
|
||||||
|
within an ordered container.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def url(self):
|
||||||
|
return zapi.absoluteURL(self.context, self.request)
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def orderable(self):
|
||||||
|
return len(self.context) > 1
|
||||||
|
|
||||||
|
def checkMoveAction(self):
|
||||||
|
request = self.request
|
||||||
|
for var in request:
|
||||||
|
if var.startswith('move_'):
|
||||||
|
params = []
|
||||||
|
if 'delta' in request:
|
||||||
|
params.append('delta=' + request['delta'])
|
||||||
|
if 'ids' in request:
|
||||||
|
for id in request['ids']:
|
||||||
|
params.append('ids:list=' + id)
|
||||||
|
request.response.redirect('%s/%s?%s'
|
||||||
|
% (self.url, var, '&'.join(params)))
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def moveDown(self, ids=[], delta=1):
|
||||||
|
self.context.updateOrder(
|
||||||
|
moveByDelta(self.context.keys(), ids, int(delta)))
|
||||||
|
self.request.response.redirect(self.url + '/contents.html')
|
||||||
|
|
||||||
|
def moveUp(self, ids=[], delta=1):
|
||||||
|
self.context.updateOrder(
|
||||||
|
moveByDelta(self.context.keys(), ids, -int(delta)))
|
||||||
|
self.request.response.redirect(self.url + '/contents.html')
|
||||||
|
|
||||||
|
def moveToBottom(self, ids=[]):
|
||||||
|
self.context.updateOrder(
|
||||||
|
moveByDelta(self.context.keys(), ids, len(self.context)))
|
||||||
|
self.request.response.redirect(self.url + '/contents.html')
|
||||||
|
|
||||||
|
def moveToTop(self, ids=[]):
|
||||||
|
self.context.updateOrder(
|
||||||
|
moveByDelta(self.context.keys(), ids, -len(self.context)))
|
||||||
|
self.request.response.redirect(self.url + '/contents.html')
|
||||||
|
|
||||||
|
|
||||||
|
def moveByDelta(objs, toMove, delta):
|
||||||
|
""" Return the list given by objs resorted in a way that the elements
|
||||||
|
of toMove (which must be in the objs list) have been moved by delta.
|
||||||
|
"""
|
||||||
|
result = [obj for obj in objs if obj not in toMove]
|
||||||
|
if delta < 0:
|
||||||
|
objs = list(reversed(objs))
|
||||||
|
result.reverse()
|
||||||
|
toMove = sorted(toMove, lambda x,y: cmp(objs.index(x), objs.index(y)))
|
||||||
|
for element in toMove:
|
||||||
|
newPos = min(len(result), objs.index(element) + abs(delta))
|
||||||
|
result.insert(newPos, element)
|
||||||
|
if delta < 0:
|
||||||
|
result.reverse()
|
||||||
|
return result
|
||||||
|
|
13
container/tests.py
Executable file
13
container/tests.py
Executable file
|
@ -0,0 +1,13 @@
|
||||||
|
# $Id$
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
from zope.testing.doctestunit import DocFileSuite
|
||||||
|
|
||||||
|
|
||||||
|
def test_suite():
|
||||||
|
return unittest.TestSuite((
|
||||||
|
DocFileSuite('README.txt'),
|
||||||
|
))
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main(defaultTest='test_suite')
|
Loading…
Add table
Reference in a new issue