From 99ade04957316f867ec180c5706fa9eb669f37c0 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Fri, 22 Jun 2012 14:15:33 +0200 Subject: [PATCH 1/7] provide view for book section that shows all contained resources --- browser/concept_macros.pt | 11 ++++++++++- browser/resource.py | 18 +++++++++--------- compound/book/browser.py | 19 ++++++++++++++++++- compound/book/loops_book_de.dmp | 10 +++++----- compound/book/view_macros.pt | 13 ++++++++++++- 5 files changed, 54 insertions(+), 17 deletions(-) diff --git a/browser/concept_macros.pt b/browser/concept_macros.pt index 40e0b0f..30a0114 100644 --- a/browser/concept_macros.pt +++ b/browser/concept_macros.pt @@ -27,10 +27,19 @@
-

+

Title + + +

+ + +

+
+
+ + + + +
-
From 9c9a504feac039819b2d4adf100d337337303dd0 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Mon, 25 Jun 2012 09:37:59 +0200 Subject: [PATCH 2/7] allow editing of resources via pop-up dialog directly from list; use in section view of book --- browser/form.py | 5 ++++- browser/form_macros.pt | 4 +++- browser/resource_macros.pt | 4 ++-- compound/book/view_macros.pt | 20 ++++++++++++++++++++ 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/browser/form.py b/browser/form.py index e7ac588..aa59167 100644 --- a/browser/form.py +++ b/browser/form.py @@ -500,6 +500,9 @@ class EditObject(FormController, I18NView): @Lazy def target(self): + targetUid = self.request.form.get('targetUid') + if targetUid: + return self.view.getObjectForUid(targetUid) return self.view.virtualTargetObject or self.context @Lazy @@ -694,7 +697,7 @@ class CreateObject(EditObject): obj.setType(self.loopsRoot.loopsTraverse(tc)) notify(ObjectCreatedEvent(obj)) #notify(ObjectAddedEvent(obj)) - self.object = obj + self.object = self.view.object = obj formState = self.updateFields() # TODO: suppress validation self.view.formState = formState # TODO: error handling diff --git a/browser/form_macros.pt b/browser/form_macros.pt index eeec0bd..47f56b1 100644 --- a/browser/form_macros.pt +++ b/browser/form_macros.pt @@ -19,7 +19,9 @@ + tal:attributes="value request/version|nothing" /> +

Edit Information Object

diff --git a/browser/resource_macros.pt b/browser/resource_macros.pt index 2a8b9fb..406e519 100644 --- a/browser/resource_macros.pt +++ b/browser/resource_macros.pt @@ -83,8 +83,8 @@ - Open for editing diff --git a/compound/book/view_macros.pt b/compound/book/view_macros.pt index 3ded0de..ec1e68c 100644 --- a/compound/book/view_macros.pt +++ b/compound/book/view_macros.pt @@ -4,6 +4,26 @@
+
From edf058fec2c6efe75064b400f9c3aeefe0b7c82c Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Wed, 27 Jun 2012 10:59:39 +0200 Subject: [PATCH 3/7] allow simple specification of portlet actions via view class --- browser/common.py | 1 + browser/concept.py | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/browser/common.py b/browser/common.py index 507cab4..997a179 100644 --- a/browser/common.py +++ b/browser/common.py @@ -130,6 +130,7 @@ class EditForm(form.EditForm): class BaseView(GenericView, I18NView): actions = {} + portlet_actions = [] icon = None modeName = 'view' isToplevel = False diff --git a/browser/concept.py b/browser/concept.py index 0c1fe97..b616952 100644 --- a/browser/concept.py +++ b/browser/concept.py @@ -503,6 +503,12 @@ class ConceptView(BaseView): acts.extend(self.actions[category](self, page, target)) return acts + def getPortletActions(self, page=None, target=None): + if self.portlet_actions: + return actions.get('portlet', self.portlet_actions, + view=self, page=page, target=target) + return [] + def getObjectActions(self, page=None, target=None): acts = ['info'] if self.globalOptions('organize.allowSendEmail'): @@ -510,7 +516,7 @@ class ConceptView(BaseView): acts.extend('state.' + st.statesDefinition for st in self.states) return actions.get('object', acts, view=self, page=page, target=target) - actions = dict(object=getObjectActions) + actions = dict(object=getObjectActions, portlet=getPortletActions) def checkAction(self, name, category, target): if name in (self.typeOptions('hide_action.' + category) or []): From 81dd7b4cf68eb574af36dffa2e1ef4fb6838ecbe Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Sat, 30 Jun 2012 20:39:26 +0200 Subject: [PATCH 4/7] new 'Loopy' skin, a liquid skin with all portlets on the left-hand side --- browser/skin/__init__.py | 4 + browser/skin/configure.zcml | 22 ++ browser/skin/loopy/__init__.py | 4 + browser/skin/loopy/body.pt | 41 +++ browser/skin/loopy/browser.py | 29 ++ browser/skin/loopy/custom.css | 33 ++ browser/skin/loopy/loops.css | 648 +++++++++++++++++++++++++++++++++ 7 files changed, 781 insertions(+) create mode 100644 browser/skin/loopy/__init__.py create mode 100644 browser/skin/loopy/body.pt create mode 100644 browser/skin/loopy/browser.py create mode 100644 browser/skin/loopy/custom.css create mode 100644 browser/skin/loopy/loops.css diff --git a/browser/skin/__init__.py b/browser/skin/__init__.py index 438a06a..0babeb0 100644 --- a/browser/skin/__init__.py +++ b/browser/skin/__init__.py @@ -6,6 +6,10 @@ from cybertools.browser.liquid import Liquid from cybertools.browser.blue import Blue +class Loopy(Liquid): + """ The Loopy (neutral enduser) skin with all portlets on the + left-hand side """ + class Loopz(Liquid): """ The Loopz (neutral enduser) skin """ diff --git a/browser/skin/configure.zcml b/browser/skin/configure.zcml index 09ffedb..98972d0 100644 --- a/browser/skin/configure.zcml +++ b/browser/skin/configure.zcml @@ -5,6 +5,28 @@ xmlns="http://namespaces.zope.org/browser" i18n_domain="loops"> + + + + + + + + + + + +
+ + + loops Site + + + + + + + + + + + + + + + + +
+ For quick creation of notes/links bookmark this link: + Create loops Note +
+ Powered by + loops · + Zope 3 · + Python · + Dojo. +
+ + +
+ diff --git a/browser/skin/loopy/browser.py b/browser/skin/loopy/browser.py new file mode 100644 index 0000000..e43439d --- /dev/null +++ b/browser/skin/loopy/browser.py @@ -0,0 +1,29 @@ +# +# Copyright (c) 2012 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 +# + +""" +Dummy view class for providing the body template. +""" + +from cybertools.browser.view import UnboundTemplateFile + + +class View(object): + + bodyTemplate = UnboundTemplateFile('body.pt') + diff --git a/browser/skin/loopy/custom.css b/browser/skin/loopy/custom.css new file mode 100644 index 0000000..c451dfc --- /dev/null +++ b/browser/skin/loopy/custom.css @@ -0,0 +1,33 @@ +/* + custom.css + +*/ + +body { + color: #242424; +} + +a { + text-decoration: none; + color: #344080; + background-color: transparent; +} + +#global { + border-bottom: 1px solid #d0d0d0; + margin-bottom: 2px; + padding: 2px 0 20px 5px; +} + +.language-switch { + position: absolute; + left: 83%; + top: 42px; +} + +.page-actions { + position: absolute; + right: 25px; + top: 42px; +} + diff --git a/browser/skin/loopy/loops.css b/browser/skin/loopy/loops.css new file mode 100644 index 0000000..41bedf0 --- /dev/null +++ b/browser/skin/loopy/loops.css @@ -0,0 +1,648 @@ +/* + + settings specific for view / node objects + +*/ + +/* general */ + +#content {width: 82%} +#menu {width: 17%;} +#sub-section {width: 0} + + +h1, h2, h3, h4, h5, h6 { + margin-bottom: 0.4em; + border-bottom: None; +} + +a[href]:hover { + text-decoration: none; + color: #803000; +} + +pre { + font-size: 100%; + background-color: #f4f4f4; + overflow: scroll; + max-height: 35em; +} + +ol, ul, p { + margin-top: 0.4em; + margin-bottom: 0.5em; +} + +ol li, ul li { + line-height: 1.5em; +} + +blockquote ul { + margin: 0; +} + +textarea { + font-size: 100%; +} + +table { + border-collapse: collapse; +} + +/* class-specific */ + +.breadcrumbs td { + padding-left: 0; +} + +.description { + font-style: italic; + /* margin-top: 0.5em;*/ + margin-bottom: 0.3em; +} + +.fields td { + vertical-align: top; +} + +.dialog div.heading { + font-weight: bold; + font-size: 140%; + margin: 0.5em 0 0.3em 0; +} + +.dialog label { + display: block; + font-weight: bold; + margin-top: 0.5em; +} + +.dialog div.buttons { + margin-top: 0.5em; +} + +tr.even td { + background-color: transparent; +} + +tr.odd td { + background-color: none; +} + +table.listing { + margin: 1px; + /*margin-top: 0.5em; */ + margin-bottom: 1em; + border: none; +} + +table.listing th { + color: #000040; + padding: 0 2px 0 2px; + border: none; + border-bottom: 1px solid lightgrey; + background-color: white; +} + +table.listing td { + padding: 2px 2px 2px 2px; + white-space: normal; + vertical-align: middle; + border: none; + border-bottom: 1px dotted #dddddd; +} + +fieldset.box table.listing td { + padding: 0 1px 0 1px; +} + +table.listing .number { + text-align: right; +} + +table.listing .center { + text-align: center; +} + +table.listing .nowrap { + white-space: nowrap; +} + +table.listing tr.even { + background-color: white; +} + +table.listing td.checkbox { + text-align: center; + width: 10px; + padding-left: 2px; + padding-right: 2px; +} + +table.listing td.headline { + font-weight: bold; + border: 1px solid lightgrey; +} + +table.listing-details td { + white-space: normal; + border: 1px solid lightgrey; +} + +table.listing-details tr.heading td { + border: none; +} + +table.listing-details tr.heading td h3 { + font-weight: bold; + border: none; +} + +table.listing th span.ascending { + background-image: url(/++resource++cybertools.icons/arrowdown.gif); + background-position: right; + background-repeat: no-repeat; +} + +table.listing th span.descending { + background-image: url(/++resource++cybertools.icons/arrowup.gif); + background-position: right; + background-repeat: no-repeat; +} + +table.records input, table.records textarea { + border: none; + padding: 0; + margin: 0; + width: auto; +} + +table.records th { + background-color: #fefefe; +} + +table.records th, table.records td { + padding: 0; + margin: 0; + border: 1px solid lightgrey; +} + +table.report td { + vertical-align: top; +} + +dl.docutils dt { + font-weight: bold; + margin-top: 0.3em; +} + +dl.docutils dd { + margin-left: 2em; +} + +dl.docutils dd ul li { + margin-left: -1em; +} + +fieldset.box { + margin: 1em 0 0.5em 0; + padding: 0.5em; + border: 1px solid #ccc; +} + +fieldset.box td { + padding: 0.2em 0.2em 0.2em 0; +} + +#body { + margin-left: 5px; +} + +.top-actions { + position: absolute; + right: 2em; + top: 1em; +} + +.quicksearch { + position: absolute; + right: 2em; + top: 0.8em; +} + +.quicksearch input { + font-size: 80%; +} + +.language-switch { + position: absolute; + right: 2em; + top: 2.4em; +} + +.page-actions { + position: absolute; + right: 2em; + top: 3.8em; +} + +.top image { + margin-top: -1px; +} + +.content-1 h1, h1 { + font-size: 180%; + font-weight: bold; + color: #444; + padding-top: 0.6em; +} + +.content-2 h1, .content-1 h2, h2 { + font-size: 160%; + font-weight: bold; + color: #444; + padding-top: 0.5em; +} + +.content-3 h1, .content-2 h2, .content-1 h3, h3 { + font-size: 140%; + font-weight: bold; + color: #444; + padding-top: 0.4em; +} + +.content-4 h1, .content-3 h2, .content-2 h3, .content-1 h4, h4 { + font-size: 130%; + font-weight: normal; + padding-top: 0.3em; +} + +.content-5 h1, .content-4 h2, .content-3 h3, content-2 h4, h5 { + font-size: 120%; + /* border: none; */ + padding-top: 0.2em; +} + +.box { + padding: 0; + padding-top: 0; + border-left: 1px solid #ccc; + border-right: 1px solid #ccc; +} + +div.box { + margin: 15px 15px 0 15px; + /*border-top: 1px solid #ccc;*/ + /*border-bottom: 1px solid #ccc;*/ +} + +div.box h4 { + font: 110% Verdana, Tahoma, Arial, Helvetica, sans-serif; + color: #000040; + border: none; + border-top: 1px solid #ccc; + border-bottom: 1px solid #ccc; + padding: 4px; + padding-top: 1px; + padding-bottom: 3px; + background-color: #eee; + height: auto; + margin-bottom: 0; +} + +.box h1, .box h2, .box h3 { + border-bottom: None; +} + +.box div.body div.even { + background-color: #f8f8f8; +} + +.box div.body div { + padding: 0.2em 0.2em 0.2em 0.3em; +} + +div.action { + border-top: 1px solid #eeeeee; +} + +div.menu-1, div.menu-2 { + border-top: 1px solid #eeeeee; + font-weight: bold; +} + +.box div.body div.menu-3 { + border-top: none; + padding: 0.1em 0 0.2em 1.5em; +} + +.box div.body div.menu-4 { + padding-left: 3em; + font-size: 90% +} + +.delete-item a[href] { + color: #ff7777; + font-weight: bold; + text-decoration: none; +} + +.subcolumn { + display: inline; + float: left; +} + +.footer { + text-align: center; + border-top: 1px solid #ccc; + border-bottom: none; + margin-top: 12px; + padding-top: 6px; +} + +.object-actions { + float: right; + margin: 0; +} + +.object-actions { + padding: 1.5em 0 0 0; +} + +.content-2 .object-actions { + padding: 1em 0 0 0; +} + +.listing .object-actions { + float: none; + padding: 0; + text-align: center; +} + +.icon-action { + display: inline; +} + +.flow-left { + float: left; + padding: 0.4em 0.8em 0.8em 0; +} + +.flow-right { + float: right; + padding: 0.4em 0.8em 0.8em 0; +} + +div.image { + margin-top: 10px; + margin-right: 5px; +} + +img.selected { + border: 2px solid #d6dcf6; +} + +img.notselected { + border: 2px solid #eff8ff; +} + +.navlink { + font-size: 130%; + margin-bottom: 1em; +} + +.navlink a { + font-weight: bold; + text-decoration: underline; +} + +.subtitle { + font-size: 140%; + font-weight: bold; + margin: 1em 0 0.5em 0; +} + +.button { + margin: 1em 0 1em 0; +} + +.button a:link, .button a:visited { + padding: 2px 4px 2px 4px; + background-color: #e8e8e8; + text-decoration: None; + color: Black; + border-width: 2px; + border-style: solid; + border-color: #f4f4f4 #989898 #989898 #f4f4f4; +} + +.button a:active { + border-color: #989898 #f4f4f4 #f4f4f4 #989898; +} + +.itemViews { + border-bottom-width: 2px; +} + +.dialog .headline { + font-size: 140%; + font-weight: bold; + padding: 1em 0 1em 0; +} + +.error { + background-color: #ffbb00; + padding: 4px; + margin-bottom: 4px; +} + +.error-heading { + margin-bottom: 8px; + font-weight: bold; +} + +.message { + font-weight: bold; + background-color: #c3d9ff; + padding: 4px; + margin-bottom: 4px; +} + +.header-1 { + font-size: 120%; + font-weight: bold; +} + +.center { + text-align: center; +} + +.right { + text-align: right; +} + +/* view modes (tabs) */ + +ul.view-modes { + padding: 0 0 0 2em; + margin: 0.7em 0 0 0; + white-space: nowrap; + list-style-type: none; + border-bottom: #ccc 1px solid; + background-color: transparent; +} + +ul.view-modes li { + display: inline +} + +ul.view-modes li a { + padding: 0.15em 1.25em 0.15em 1.25em; + margin: 0 0.5em 0 0; + text-decoration: none; + border: #ccc 1px solid; + background-color: transparent; +} + +ul.view-modes li.active a { + border-bottom: #eee 1px solid; + background-color: #eee; +} + +ul.view-modes li.inactive a:hover { + background-color: #f8f8f8; +} + +/* comments */ + +div.comment { + padding: 0.5em; + background-color: #eeeeff; + border: 1px solid #aaaaff; +} + +.comment h3 { + margin-top: 0; +} + +.comment .info { + font-style: italic; + padding-top: 3px; + padding-bottom: 0; +} + +/* search stuff */ + +.searchForm input.button, input.submit { + padding: 2px; +} + +/* blog */ + +.blog .description { + font-size: 90%; + color: #666666; +} + +.blogpost .description { + font-size: 90%; + color: #666666; + padding-top: 0.4em; +} + +.blog .info, .blogpost .info { + font-style: italic; + font-size: 90%; + color: #666666; + padding-top: 0.4em; +} + +/* microart */ + +.micropart { + background-color: #f7f7f7; + padding: 0 5px 0 5px; + margin: 5px 0 5px 0; +} + +.micropart h3,h4,h5 { + font-weight: bold; + margin-bottom: 0.2em; + border-bottom: none; +} + +/* calendar, work items */ + +.today { + color: #444488; + font-weight: bold; +} + +.calendar td.arrows { + font-size: 130%; +} + +.calendar td.week_number { + color: grey; +} + +.calendar td.day { + width: 12%; +} + +.calendar td.today { + border: 1px solid red; + font-weight: normal; +} + +.calendar .has_events { + font-weight: bold; + background-color: #eeeeff; +} + +/* dojo stuff */ + +.dijitDialog { + background-color: #aaaaaa; + border: 1px solid #999; + padding: 5px; +} + +.dijitDialogPaneContent { + background-color: #aaaaaa; +} + +.dijitDialog th { + font-size: 120%; + font-weight: bold; + text-align: center; + padding: 0 5px 8px 5px; +} + +.dijitDialog td { + padding: 2px; +} + +.dijitDialog .headline { + font-weight: bold; +} + +.dijitDialog input.text { + width: 100%; + margin-right: 10px; +} + +.dijitDialog input.submit { + font-weight: bold; +} + +.dijitDialogUnderlay { + background-color: Lightgrey; +} + +div.RichTextEditable { + border-top: 2px solid grey; + border-left: 2px solid grey; + border-right: 2px solid #eeeeee; + border-bottom: 2px solid #eeeeee; +} From 90362949a6a82ef1b7502755854b84742d9bda03 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Sun, 1 Jul 2012 13:09:18 +0200 Subject: [PATCH 5/7] improvements of Loopy skin; centralize definition of breadcrumbs macro --- browser/node_macros.pt | 21 +++++++++++++++++++++ browser/skin/lobo/body.pt | 18 +----------------- browser/skin/loopy/body.pt | 10 ++++++++++ browser/skin/loopy/loops.css | 5 +++-- 4 files changed, 35 insertions(+), 19 deletions(-) diff --git a/browser/node_macros.pt b/browser/node_macros.pt index 72472e9..7f65b19 100644 --- a/browser/node_macros.pt +++ b/browser/node_macros.pt @@ -240,6 +240,27 @@ + + + + + + + + + +
    - - - - - - +
    diff --git a/browser/skin/loopy/body.pt b/browser/skin/loopy/body.pt index e344189..c17c3b6 100644 --- a/browser/skin/loopy/body.pt +++ b/browser/skin/loopy/body.pt @@ -9,6 +9,16 @@ tal:attributes="src string:${resourceBase}logo.png" /> + + + + + + + + + + diff --git a/browser/skin/loopy/loops.css b/browser/skin/loopy/loops.css index 41bedf0..ba7e06c 100644 --- a/browser/skin/loopy/loops.css +++ b/browser/skin/loopy/loops.css @@ -6,8 +6,8 @@ /* general */ -#content {width: 82%} -#menu {width: 17%;} +#content {width: 79%} +#menu {width: 20%;} #sub-section {width: 0} @@ -53,6 +53,7 @@ table { .breadcrumbs td { padding-left: 0; + padding-top: 12px; } .description { From 670ebf95f18e5dd2760c541e98e71bce924f8d29 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Mon, 2 Jul 2012 08:46:56 +0200 Subject: [PATCH 6/7] meeting minutes: fix listing of tasks, access to task for work item listing --- organize/work/report.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/organize/work/report.py b/organize/work/report.py index deb8865..937bf65 100644 --- a/organize/work/report.py +++ b/organize/work/report.py @@ -219,7 +219,7 @@ class WorkReportInstance(ReportInstance): def getAllSubtasks(self, concept): result = [] - for c in concept.getChildren(): + for c in concept.getChildren([self.view.defaultPredicate]): if c.conceptType in self.taskTypes: result.append(c) result.extend(self.getAllSubtasks(c)) @@ -227,7 +227,8 @@ class WorkReportInstance(ReportInstance): def selectWorkItems(self, task, parts): # TODO: take states from parts - kw = dict(task=util.getUidForObject(task), state=self.states) + kw = dict(task=util.getUidForObject(baseObject(task)), + state=self.states) if 'userName' in parts: kw['userName'] = parts['userName'].comparisonValue wi = self.workItems From 8c1a5d6b47a66c4c7af5ed70adebc279b4ba69de Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Mon, 2 Jul 2012 12:00:06 +0200 Subject: [PATCH 7/7] allow overriding of title shown on breadcrumbs --- browser/concept.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/browser/concept.py b/browser/concept.py index b616952..e795ade 100644 --- a/browser/concept.py +++ b/browser/concept.py @@ -243,9 +243,13 @@ class ConceptView(BaseView): if self.breadcrumbsParent is not None: data.extend(self.breadcrumbsParent.breadcrumbs()) if self.context != self.nodeView.targetObject: - data.append(dict(label=self.title, url=self.targetUrl)) + data.append(dict(label=self.breadcrumbsTitle, url=self.targetUrl)) return data + @Lazy + def breadcrumbsTitle(self): + return self.title + @Lazy def breadcrumbsParent(self): return None