diff --git a/browser/liquid/liquid4.css b/browser/liquid/liquid4.css index 74b690c..7a3d071 100644 --- a/browser/liquid/liquid4.css +++ b/browser/liquid/liquid4.css @@ -22,14 +22,14 @@ body { #header,#footer {width:100%} #menu,#content,#sub-section {float:left} #menu {width:20%} -#content {width:60%} -#sub-section {width:19.9%} +#content {width:67%} +#sub-section {width:12.9%} #footer {clear:left} /* more general stuff */ .box { - margin: 12px 15px 8px 10px; + margin: 12px 12px 8px 10px; border-left: none; } diff --git a/container/DEPENDENCIES.cfg b/container/DEPENDENCIES.cfg new file mode 100644 index 0000000..a309abd --- /dev/null +++ b/container/DEPENDENCIES.cfg @@ -0,0 +1,4 @@ +zope.app +zope.component +zope.interface +persistent diff --git a/container/README.txt b/container/README.txt new file mode 100644 index 0000000..3892541 --- /dev/null +++ b/container/README.txt @@ -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() diff --git a/container/SETUP.cfg b/container/SETUP.cfg new file mode 100644 index 0000000..2e893b1 --- /dev/null +++ b/container/SETUP.cfg @@ -0,0 +1,5 @@ +# Tell zpkg how to install the ZCML slugs. + + + cybertools.container-*.zcml + diff --git a/container/__init__.py b/container/__init__.py new file mode 100644 index 0000000..4bc90fb --- /dev/null +++ b/container/__init__.py @@ -0,0 +1,4 @@ +""" +$Id$ +""" + diff --git a/container/configure.zcml b/container/configure.zcml new file mode 100644 index 0000000..d97817e --- /dev/null +++ b/container/configure.zcml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + diff --git a/container/contents.pt b/container/contents.pt new file mode 100644 index 0000000..505f090 --- /dev/null +++ b/container/contents.pt @@ -0,0 +1,216 @@ + + +
+
+ + + + +
+ + + + +
+ Error message +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 NameTitleSizeCreatedModified
+ + + + foo   + +      +      + +    
+ +
+ + + + + + + +
+
+ + + +
+
+ +
+ + + + + +
+ +
+ +
+ + +
+ +
+
+
+ + + + +
+ +
+ + diff --git a/container/cybertools.container-configure.zcml b/container/cybertools.container-configure.zcml new file mode 100644 index 0000000..b9894b5 --- /dev/null +++ b/container/cybertools.container-configure.zcml @@ -0,0 +1 @@ + diff --git a/container/interfaces.py b/container/interfaces.py new file mode 100644 index 0000000..a21e778 --- /dev/null +++ b/container/interfaces.py @@ -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 + + diff --git a/container/ordered.py b/container/ordered.py new file mode 100644 index 0000000..6144d70 --- /dev/null +++ b/container/ordered.py @@ -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 + diff --git a/container/tests.py b/container/tests.py new file mode 100755 index 0000000..7956cd4 --- /dev/null +++ b/container/tests.py @@ -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')