diff --git a/browser/common.py b/browser/common.py index 7da8da5..dbf00c4 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..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 @@ -503,6 +507,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 +520,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 []): diff --git a/browser/concept_macros.pt b/browser/concept_macros.pt index 3734d46..1424dd4 100644 --- a/browser/concept_macros.pt +++ b/browser/concept_macros.pt @@ -27,10 +27,19 @@
-

+

Title + + +

+ tal:attributes="value request/version|nothing" /> +

Edit Information Object

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 @@ + + + + + + + + + +
    - Open for editing 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"> + + + + + + + + + + + - - - - - - +
    diff --git a/browser/skin/loopy/__init__.py b/browser/skin/loopy/__init__.py new file mode 100644 index 0000000..35f9581 --- /dev/null +++ b/browser/skin/loopy/__init__.py @@ -0,0 +1,4 @@ +# package loops.browser.skin.loopy +# +# variant of the Loopz skin with all portlets on the left +# \ No newline at end of file diff --git a/browser/skin/loopy/body.pt b/browser/skin/loopy/body.pt new file mode 100644 index 0000000..c17c3b6 --- /dev/null +++ b/browser/skin/loopy/body.pt @@ -0,0 +1,51 @@ + +
    + + + 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..ba7e06c --- /dev/null +++ b/browser/skin/loopy/loops.css @@ -0,0 +1,649 @@ +/* + + settings specific for view / node objects + +*/ + +/* general */ + +#content {width: 79%} +#menu {width: 20%;} +#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; + padding-top: 12px; +} + +.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; +} diff --git a/compound/book/browser.py b/compound/book/browser.py index f893be8..9117e95 100644 --- a/compound/book/browser.py +++ b/compound/book/browser.py @@ -24,6 +24,7 @@ from cgi import parse_qs from zope import interface, component from zope.app.pagetemplate import ViewPageTemplateFile from zope.cachedescriptors.property import Lazy +from zope.traversing.api import getName from cybertools.typology.interfaces import IType from loops.browser.lobo import standard @@ -52,8 +53,24 @@ class Base(object): class SectionView(Base, ConceptView): - pass + @Lazy + def macro(self): + return book_template.macros['section'] + @Lazy + def tabview(self): + if self.editable: + return 'index.html' + + def getCssClassForResource(self, r): + documentType = self.conceptManager['documenttype'] + for c in r.context.getConcepts([self.defaultPredicate]): + if c.conceptType == documentType: + return getName(c) + return 'textelement' + + +# layout parts - probably obsolete: class PageLayout(Base, standard.Layout): diff --git a/compound/book/loops_book_de.dmp b/compound/book/loops_book_de.dmp index ed3a62e..995d2cd 100644 --- a/compound/book/loops_book_de.dmp +++ b/compound/book/loops_book_de.dmp @@ -4,9 +4,9 @@ type(u'documenttype', u'Dokumentenart', options=u'qualifier:assign', # book types type(u'book', u'Buch', viewName=u'', typeInterface=u'', options=u'action.portlet:create_subtype,edit_concept') -type(u'page', u'Seite', viewName=u'page_layout', - typeInterface=u'loops.compound.book.interfaces.IPage', - options=u'action.portlet:edit_concept') +#type(u'page', u'Seite', viewName=u'page_layout', +# typeInterface=u'loops.compound.book.interfaces.IPage', +# options=u'action.portlet:edit_concept') type(u'section', u'Kapitel', viewName=u'section_view', typeInterface=u'', options=u'action.portlet:create_subtype,edit_concept') @@ -20,7 +20,7 @@ concept(u'issubtype', u'is Subtype', u'predicate', options=u'hide_children', # document types concept(u'keyquestions', u'Leitfragen', u'documenttype') -concept(u'maintext', u'Haupttext', u'documenttype') +concept(u'textelement', u'Textabschnitt', u'documenttype') concept(u'quote', u'Zitat', u'documenttype') concept(u'story', u'Geschichte', u'documenttype') concept(u'usecase', u'Fallbeispiel', u'documenttype') @@ -28,4 +28,4 @@ concept(u'usecase', u'Fallbeispiel', u'documenttype') # book structure child(u'book', u'section', u'issubtype', usePredicate=u'ispartof') child(u'section', u'section', u'issubtype', usePredicate=u'ispartof') -child(u'section', u'page', u'issubtype', usePredicate=u'ispartof') +#child(u'section', u'page', u'issubtype', usePredicate=u'ispartof') diff --git a/compound/book/view_macros.pt b/compound/book/view_macros.pt index e330154..ec1e68c 100644 --- a/compound/book/view_macros.pt +++ b/compound/book/view_macros.pt @@ -1,13 +1,44 @@ + + +
    +
    + + + + +
    +
    +
    + + + + +
    -
    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