work in progress: action/link management for portlets and icon bars
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@2184 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
4b239e150a
commit
9fa0cc512c
11 changed files with 194 additions and 39 deletions
51
README.txt
51
README.txt
|
@ -561,6 +561,48 @@ cybertools.relation package.)
|
|||
>>> IMediaAssetView.providedBy(m111)
|
||||
False
|
||||
|
||||
Target views
|
||||
------------
|
||||
|
||||
We can directly retrieve a target's view by using the NodeView's
|
||||
``targetObjectView`` property. If the target is a concept we get a ConceptView
|
||||
that provides methods e.g. for retrieving the concept's relations.
|
||||
These are again wrapped as views, i.e. as instances of the
|
||||
ConceptRelationView class.
|
||||
|
||||
>>> from loops.interfaces import IConcept
|
||||
>>> component.provideAdapter(ConceptView, (IConcept, IBrowserRequest), Interface)
|
||||
|
||||
>>> m112.target = cc1
|
||||
>>> view = NodeView(m112, TestRequest())
|
||||
>>> childRels = list(view.targetObjectView.children())
|
||||
>>> childRels[0]
|
||||
<loops.browser.concept.ConceptRelationView object ...>
|
||||
|
||||
A fairly useful method for providing links to target objects of a node
|
||||
is ``NodeView.getUrlForTarget()`` that expects a ConceptView, ResourceView,
|
||||
or ConceptRelationView as its argument.
|
||||
|
||||
>>> view.getUrlForTarget(childRels[0])
|
||||
'http://127.0.0.1/loops/views/m1/m11/m112/.target39'
|
||||
|
||||
Actions
|
||||
-------
|
||||
|
||||
>>> from cybertools.browser.liquid.controller import Controller
|
||||
>>> request = TestRequest()
|
||||
>>> view = NodeView(m112, request)
|
||||
>>> view.controller = Controller(view, request)
|
||||
>>> view.setupController()
|
||||
|
||||
>>> actions = view.getActions('portlet')
|
||||
>>> len(actions)
|
||||
1
|
||||
|
||||
Clean-up:
|
||||
|
||||
>>> m112.target = None
|
||||
|
||||
Ordering Nodes
|
||||
--------------
|
||||
|
||||
|
@ -761,11 +803,10 @@ In order to provide suitable links for viewing or editing a target you may
|
|||
ask a view which view and edit actions it supports. We directly use the
|
||||
target object's view here:
|
||||
|
||||
>>> view.virtualTarget.getActions()
|
||||
[<loops.browser.common.Action object ...>]
|
||||
>>> action = view.virtualTarget.getActions()[0]
|
||||
>>> action.url
|
||||
'http://127.0.0.1/loops/views/m1/m11/m111/.target23'
|
||||
>>> actions = view.virtualTarget.getActions('object', page=view)
|
||||
>>> #actions[0].url
|
||||
|
||||
'http://127.0.0.1/loops/views/m1/m11/m111/.target23'
|
||||
|
||||
|
||||
Collecting Information about Parents
|
||||
|
|
66
browser/action.py
Normal file
66
browser/action.py
Normal file
|
@ -0,0 +1,66 @@
|
|||
#
|
||||
# Copyright (c) 2007 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
|
||||
#
|
||||
|
||||
"""
|
||||
Base classes (sort of views) for action portlet items.
|
||||
|
||||
$Id$
|
||||
"""
|
||||
|
||||
from zope import component
|
||||
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||
from zope.cachedescriptors.property import Lazy
|
||||
|
||||
action_macros = ViewPageTemplateFile('action_macros.pt')
|
||||
|
||||
|
||||
class Action(object):
|
||||
|
||||
template = action_macros
|
||||
macroName = 'action'
|
||||
condition = True
|
||||
permission = None
|
||||
url = '.'
|
||||
targetWindow = ''
|
||||
title = ''
|
||||
description = ''
|
||||
icon = ''
|
||||
cssClass = ''
|
||||
onClick = ''
|
||||
innerHtmlId = ''
|
||||
|
||||
def __init__(self, view, **kw):
|
||||
self.view = view
|
||||
for k, v in kw.items():
|
||||
setattr(self, k, v)
|
||||
|
||||
@Lazy
|
||||
def macro(self):
|
||||
return self.template.macros[self.macroName]
|
||||
|
||||
@Lazy
|
||||
def url(self):
|
||||
return self.view.url
|
||||
|
||||
|
||||
class TargetAction(object):
|
||||
|
||||
@Lazy
|
||||
def url(self):
|
||||
return self.view.virtualTargetUrl
|
||||
|
23
browser/action_macros.pt
Normal file
23
browser/action_macros.pt
Normal file
|
@ -0,0 +1,23 @@
|
|||
<!-- action macros -->
|
||||
|
||||
<metal:action define-macro="action">
|
||||
<div tal:condition="action/condition">
|
||||
<a href="#" target="target_window" title="Description text"
|
||||
i18n:attributes="title"
|
||||
tal:attributes="href action/url;
|
||||
target action/targetWindow;
|
||||
title action/description;
|
||||
onClick action/onClick;"><img
|
||||
src="#" alt="icon"
|
||||
tal:condition="action/icon"
|
||||
tal:attributes="src action/icon;
|
||||
alt action/description" /><span
|
||||
i18n:translate=""
|
||||
tal:condition="action/title"
|
||||
tal:content="action/title">Action Title</span>
|
||||
</a>
|
||||
</div>
|
||||
<span id="inner.Id"
|
||||
tal:condition="action/innerHtmlId"
|
||||
tal:attributes="id action/innerHtmlId"></span>
|
||||
</metal:action>
|
|
@ -97,6 +97,8 @@ class EditForm(form.EditForm):
|
|||
|
||||
class BaseView(GenericView):
|
||||
|
||||
actions = {} # default only, don't update
|
||||
|
||||
def __init__(self, context, request):
|
||||
super(BaseView, self).__init__(context, request)
|
||||
# TODO: get rid of removeSecurityProxy() call
|
||||
|
@ -329,11 +331,14 @@ class BaseView(GenericView):
|
|||
def editable(self):
|
||||
return canWrite(self.context, 'title')
|
||||
|
||||
def getActions(self, category):
|
||||
def getActions(self, category='object', page=None):
|
||||
""" Return a list of actions that provide the view and edit actions
|
||||
available for the context object.
|
||||
"""
|
||||
return []
|
||||
actions = []
|
||||
if category in self.actions:
|
||||
actions.extend(self.actions[category](self, page=page))
|
||||
return actions
|
||||
|
||||
def openEditWindow(self, viewName='edit.html'):
|
||||
if self.editable:
|
||||
|
|
|
@ -46,7 +46,7 @@ from cybertools.typology.interfaces import IType, ITypeManager
|
|||
from loops.interfaces import IConcept
|
||||
from loops.interfaces import ITypeConcept
|
||||
from loops.concept import Concept, ConceptTypeSourceList, PredicateSourceList
|
||||
from loops.browser.common import EditForm, BaseView, LoopsTerms
|
||||
from loops.browser.common import EditForm, BaseView, LoopsTerms, conceptMacrosTemplate
|
||||
from loops import util
|
||||
from loops.util import _
|
||||
from loops.versioning.util import getVersion
|
||||
|
@ -75,12 +75,16 @@ class ConceptEditForm(EditForm):
|
|||
|
||||
class ConceptView(BaseView):
|
||||
|
||||
template = NamedTemplate('loops.concept_macros')
|
||||
template = ViewPageTemplateFile('concept_macros.pt')
|
||||
|
||||
@Lazy
|
||||
def macro(self):
|
||||
return self.template.macros['conceptdata']
|
||||
|
||||
@Lazy
|
||||
def conceptMacros(self):
|
||||
return conceptMacrosTemplate.macros
|
||||
|
||||
def __init__(self, context, request):
|
||||
super(ConceptView, self).__init__(context, request)
|
||||
cont = self.controller
|
||||
|
|
|
@ -394,13 +394,15 @@ class CreateObject(EditObject):
|
|||
name = name.rsplit('\\', 1)[-1]
|
||||
else:
|
||||
name = None
|
||||
# TODO: validate fields
|
||||
name = INameChooser(container).chooseName(name, obj)
|
||||
container[name] = obj
|
||||
tc = form.get('form.type') or '.loops/concepts/note'
|
||||
obj.resourceType = self.loopsRoot.loopsTraverse(tc)
|
||||
notify(ObjectCreatedEvent(obj))
|
||||
self.object = obj
|
||||
self.updateFields()
|
||||
self.request.response.redirect(self.view.virtualTargetUrl)
|
||||
self.updateFields() # TODO: suppress validation
|
||||
#self.request.response.redirect(self.view.virtualTargetUrl)
|
||||
self.request.response.redirect(self.view.request.URL)
|
||||
return False
|
||||
|
||||
|
|
|
@ -51,6 +51,7 @@ from loops.interfaces import IViewConfiguratorSchema
|
|||
from loops.resource import MediaAsset
|
||||
from loops import util
|
||||
from loops.util import _
|
||||
from loops.browser.action import Action, TargetAction
|
||||
from loops.browser.common import BaseView
|
||||
from loops.browser.concept import ConceptView
|
||||
from loops.versioning.util import getVersion
|
||||
|
@ -162,11 +163,6 @@ class NodeView(BaseView):
|
|||
basicView._viewName = self.context.viewName
|
||||
return basicView.view
|
||||
|
||||
#@Lazy
|
||||
#def target(self):
|
||||
# # obsolete and confusing - TODO: remove...
|
||||
# return self.targetObjectView
|
||||
|
||||
@Lazy
|
||||
def targetUrl(self):
|
||||
t = self.targetObjectView
|
||||
|
@ -334,11 +330,31 @@ class NodeView(BaseView):
|
|||
|
||||
# target viewing and editing support
|
||||
|
||||
def getUrlForTarget(self, target):
|
||||
""" Return URL of given target view given as .targetXXX URL.
|
||||
"""
|
||||
return '%s/.target%s' % (self.url, target.uniqueId)
|
||||
|
||||
def getActions(self, category='object'):
|
||||
#target = self.virtualTarget
|
||||
#if target is not None:
|
||||
# return target.getActions(category)
|
||||
return [] # TODO: what about editing the node itself?
|
||||
actions = []
|
||||
self.registerDojo()
|
||||
if category in self.actions:
|
||||
actions.extend(self.actions[category](self))
|
||||
target = self.virtualTarget
|
||||
if target is not None:
|
||||
actions.extend(target.getActions(category, page=self))
|
||||
return actions
|
||||
|
||||
def getPortletActions(self):
|
||||
actions = []
|
||||
actions.append(Action(self,
|
||||
targetWindow='loops_cme',
|
||||
title='Edit Concept Map',
|
||||
description='Open concept map editor in new window',
|
||||
url=self.conceptMapEditorUrl))
|
||||
return actions
|
||||
|
||||
actions = dict(portlet=getPortletActions)
|
||||
|
||||
@Lazy
|
||||
def hasEditableTarget(self):
|
||||
|
|
|
@ -208,17 +208,11 @@
|
|||
|
||||
|
||||
<metal:actions define-macro="actions">
|
||||
<tal:actions repeat="action python:view.getActions('portlet')">
|
||||
<metal:action use-macro="action/macro" />
|
||||
</tal:actions>
|
||||
<tal:actions define="dummy view/registerDojo;
|
||||
url view/virtualTargetUrl">
|
||||
<div tal:define="cmUrl view/conceptMapEditorUrl"
|
||||
tal:condition="url">
|
||||
<a href="#" target="loops_cme" i18n:translate=""
|
||||
i18n:attributes="title"
|
||||
title="Open concept map editor in new window"
|
||||
tal:attributes="href cmUrl">
|
||||
Edit Concept Map
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
<a href="create_object.html" i18n:translate=""
|
||||
onclick="objectDialog('create', 'create_object.html'); return false;"
|
||||
|
|
|
@ -41,7 +41,8 @@ from zope.traversing.api import getName, getParent
|
|||
|
||||
from cybertools.typology.interfaces import IType
|
||||
from cybertools.xedit.browser import ExternalEditorView, fromUnicode
|
||||
from loops.browser.common import EditForm, BaseView, Action
|
||||
from loops.browser.action import Action, TargetAction
|
||||
from loops.browser.common import EditForm, BaseView
|
||||
from loops.browser.concept import ConceptRelationView, ConceptConfigureView
|
||||
from loops.browser.node import NodeView, node_macros
|
||||
from loops.browser.util import html_quote
|
||||
|
@ -181,15 +182,15 @@ class ResourceView(BaseView):
|
|||
ct = self.context.contentType
|
||||
return ct.startswith('image/') or ct == 'application/pdf'
|
||||
|
||||
def getActions(self, category='object'):
|
||||
renderer = node_macros.macros['external_edit']
|
||||
node = self.request.annotations.get('loops.view', {}).get('node')
|
||||
if node is not None:
|
||||
nodeView = NodeView(node, self.request)
|
||||
url = nodeView.virtualTargetUrl
|
||||
def getObjectActions(self, page=None):
|
||||
actions = []
|
||||
if page is None:
|
||||
factory, view = Action, self
|
||||
else:
|
||||
url = self.url
|
||||
return [Action(renderer, url)]
|
||||
factory, view = TargetAction, page
|
||||
#if self.xeditable:
|
||||
# actions.append(factory(self, page=view,))
|
||||
return actions
|
||||
|
||||
def concepts(self):
|
||||
for r in self.context.getConceptRelations():
|
||||
|
|
Binary file not shown.
|
@ -3,7 +3,7 @@ msgstr ""
|
|||
|
||||
"Project-Id-Version: $Id$\n"
|
||||
"POT-Creation-Date: 2007-05-22 12:00 CET\n"
|
||||
"PO-Revision-Date: 2007-05-23 12:00 CET\n"
|
||||
"PO-Revision-Date: 2007-11-18 12:00 CET\n"
|
||||
"Last-Translator: Helmut Merz <helmutm@cy55.de>\n"
|
||||
"Language-Team: loops developers <helmutm@cy55.de>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
|
@ -194,6 +194,9 @@ msgstr "major"
|
|||
msgid "minor"
|
||||
msgstr "minor"
|
||||
|
||||
msgid "see"
|
||||
msgstr "siehe"
|
||||
|
||||
msgid "Change Password"
|
||||
msgstr "Passwort ändern"
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue