provide external editor usage for files, e.g. word documents
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1589 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
ab28635ff2
commit
24fb20d78a
9 changed files with 164 additions and 35 deletions
52
README.txt
52
README.txt
|
@ -564,18 +564,6 @@ cybertools.relation package.)
|
||||||
>>> IMediaAssetView.providedBy(m111)
|
>>> IMediaAssetView.providedBy(m111)
|
||||||
False
|
False
|
||||||
|
|
||||||
Views Related to Virtual Targets
|
|
||||||
--------------------------------
|
|
||||||
|
|
||||||
From a node usually any object in the concept or resource space can
|
|
||||||
be accessed as a `virtual target`. This is done by putting ".targetNNN"
|
|
||||||
at the end of the URL, with NNN being the unique id of the concept
|
|
||||||
or resource.
|
|
||||||
|
|
||||||
>>> from loops.view import NodeTraverser
|
|
||||||
>>> from zope.publisher.interfaces.browser import IBrowserPublisher
|
|
||||||
>>> component.provideAdapter(NodeTraverser, provides=IBrowserPublisher)
|
|
||||||
|
|
||||||
Ordering Nodes
|
Ordering Nodes
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
@ -605,8 +593,8 @@ to the bottom, and to the top.
|
||||||
['m111', 'm114', 'm112', 'm113']
|
['m111', 'm114', 'm112', 'm113']
|
||||||
|
|
||||||
|
|
||||||
End-user Forms
|
End-user Forms and Special Views
|
||||||
==============
|
================================
|
||||||
|
|
||||||
The browser.form and related modules provide additional support for forms
|
The browser.form and related modules provide additional support for forms
|
||||||
that are shown in the end-user interface.
|
that are shown in the end-user interface.
|
||||||
|
@ -670,7 +658,7 @@ and possibly critcal cases:
|
||||||
>>> nc.chooseName(u'A very very loooooong title', None)
|
>>> nc.chooseName(u'A very very loooooong title', None)
|
||||||
u'a_title'
|
u'a_title'
|
||||||
|
|
||||||
Editing an object
|
Editing an Object
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
>>> from loops.browser.form import EditObjectForm, EditObject
|
>>> from loops.browser.form import EditObjectForm, EditObject
|
||||||
|
@ -685,6 +673,40 @@ Editing an object
|
||||||
>>> resources['test_note'].title
|
>>> resources['test_note'].title
|
||||||
u'Test Note - changed'
|
u'Test Note - changed'
|
||||||
|
|
||||||
|
Virtual Targets
|
||||||
|
---------------
|
||||||
|
|
||||||
|
From a node usually any object in the concept or resource space can
|
||||||
|
be accessed as a `virtual target`. This is done by putting ".targetNNN"
|
||||||
|
at the end of the URL, with NNN being the unique id of the concept
|
||||||
|
or resource.
|
||||||
|
|
||||||
|
>>> from loops.view import NodeTraverser
|
||||||
|
|
||||||
|
>>> magic = '.target' + util.getUidForObject(note)
|
||||||
|
>>> url = 'http://127.0.0.1/loops/views/m1/m11/m111/' + magic + '/@@node.html'
|
||||||
|
>>> #request = TestRequest(environ=dict(SERVER_URL=url))
|
||||||
|
>>> request = TestRequest()
|
||||||
|
>>> NodeTraverser(m111, request).publishTraverse(request, magic)
|
||||||
|
<loops.view.Node object ...>
|
||||||
|
>>> view = NodeView(m111, request)
|
||||||
|
>>> view.virtualTargetObject
|
||||||
|
<loops.resource.Resource object ...>
|
||||||
|
|
||||||
|
A virtual target may be edited in the same way like directly assigned targets,
|
||||||
|
see above, "Editing an Object". In addition, target objects may be viewed
|
||||||
|
and edited in special ways, depending on the target object's type.
|
||||||
|
|
||||||
|
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/.target16'
|
||||||
|
|
||||||
|
|
||||||
Import/Export
|
Import/Export
|
||||||
=============
|
=============
|
||||||
|
|
|
@ -23,10 +23,11 @@ $Id$
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from zope.app import zapi
|
from zope.app import zapi
|
||||||
from zope.dublincore.interfaces import IZopeDublinCore
|
from zope import component
|
||||||
from zope.app.form.browser.interfaces import ITerms
|
from zope.app.form.browser.interfaces import ITerms
|
||||||
from zope.cachedescriptors.property import Lazy
|
from zope.cachedescriptors.property import Lazy
|
||||||
from zope.dottedname.resolve import resolve
|
from zope.dottedname.resolve import resolve
|
||||||
|
from zope.dublincore.interfaces import IZopeDublinCore
|
||||||
from zope.formlib import form
|
from zope.formlib import form
|
||||||
from zope.formlib.form import FormFields
|
from zope.formlib.form import FormFields
|
||||||
from zope.formlib.namedtemplate import NamedTemplate
|
from zope.formlib.namedtemplate import NamedTemplate
|
||||||
|
@ -38,6 +39,7 @@ from zope import schema
|
||||||
from zope.schema.vocabulary import SimpleTerm
|
from zope.schema.vocabulary import SimpleTerm
|
||||||
from zope.security import canAccess, canWrite
|
from zope.security import canAccess, canWrite
|
||||||
from zope.security.proxy import removeSecurityProxy
|
from zope.security.proxy import removeSecurityProxy
|
||||||
|
from zope.traversing.browser import absoluteURL
|
||||||
|
|
||||||
from cybertools.browser.view import GenericView
|
from cybertools.browser.view import GenericView
|
||||||
from cybertools.relation.interfaces import IRelationRegistry
|
from cybertools.relation.interfaces import IRelationRegistry
|
||||||
|
@ -78,7 +80,7 @@ class EditForm(form.EditForm):
|
||||||
def deleteObjectAction(self):
|
def deleteObjectAction(self):
|
||||||
return None # better not to show the edit button at the moment
|
return None # better not to show the edit button at the moment
|
||||||
parent = zapi.getParent(self.context)
|
parent = zapi.getParent(self.context)
|
||||||
parentUrl = zapi.absoluteURL(parent, self.request)
|
parentUrl = absoluteURL(parent, self.request)
|
||||||
return parentUrl + '/contents.html'
|
return parentUrl + '/contents.html'
|
||||||
|
|
||||||
|
|
||||||
|
@ -93,7 +95,7 @@ class BaseView(GenericView):
|
||||||
def setSkin(self, skinName):
|
def setSkin(self, skinName):
|
||||||
skin = None
|
skin = None
|
||||||
if skinName and IView.providedBy(self.context):
|
if skinName and IView.providedBy(self.context):
|
||||||
skin = zapi.queryUtility(IBrowserSkinType, skinName)
|
skin = component.queryUtility(IBrowserSkinType, skinName)
|
||||||
if skin:
|
if skin:
|
||||||
applySkin(self.request, skin)
|
applySkin(self.request, skin)
|
||||||
self.skin = skin
|
self.skin = skin
|
||||||
|
@ -112,7 +114,7 @@ class BaseView(GenericView):
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def url(self):
|
def url(self):
|
||||||
return zapi.absoluteURL(self.context, self.request)
|
return absoluteURL(self.context, self.request)
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def view(self):
|
def view(self):
|
||||||
|
@ -164,7 +166,7 @@ class BaseView(GenericView):
|
||||||
def typeUrl(self):
|
def typeUrl(self):
|
||||||
provider = self.typeProvider
|
provider = self.typeProvider
|
||||||
if provider is not None:
|
if provider is not None:
|
||||||
return zapi.absoluteURL(provider, self.request)
|
return absoluteURL(provider, self.request)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def viewIterator(self, objs):
|
def viewIterator(self, objs):
|
||||||
|
@ -206,6 +208,12 @@ class BaseView(GenericView):
|
||||||
def editable(self):
|
def editable(self):
|
||||||
return canWrite(self.context, 'title')
|
return canWrite(self.context, 'title')
|
||||||
|
|
||||||
|
def getActions(self, category):
|
||||||
|
""" Return a list of actions that provide the view and edit actions
|
||||||
|
available for the context object.
|
||||||
|
"""
|
||||||
|
return []
|
||||||
|
|
||||||
def openEditWindow(self, viewName='edit.html'):
|
def openEditWindow(self, viewName='edit.html'):
|
||||||
if self.editable:
|
if self.editable:
|
||||||
return "openEditWindow('%s/@@%s')" % (self.url, viewName)
|
return "openEditWindow('%s/@@%s')" % (self.url, viewName)
|
||||||
|
@ -234,6 +242,20 @@ class BaseView(GenericView):
|
||||||
cm.register('js', 'dojo.js', resourceName='ajax.dojo/dojo.js')
|
cm.register('js', 'dojo.js', resourceName='ajax.dojo/dojo.js')
|
||||||
|
|
||||||
|
|
||||||
|
# actions
|
||||||
|
|
||||||
|
class Action(object):
|
||||||
|
|
||||||
|
def __init__(self, renderer, url, **kw):
|
||||||
|
self.renderer = renderer
|
||||||
|
self.url = url
|
||||||
|
self.__dict__.update(kw)
|
||||||
|
#for k in kw:
|
||||||
|
# setattr(self, k, kw[k])
|
||||||
|
|
||||||
|
|
||||||
|
# vocabulary stuff
|
||||||
|
|
||||||
class LoopsTerms(object):
|
class LoopsTerms(object):
|
||||||
""" Provide the ITerms interface, e.g. for usage in selection
|
""" Provide the ITerms interface, e.g. for usage in selection
|
||||||
lists.
|
lists.
|
||||||
|
|
|
@ -557,6 +557,14 @@
|
||||||
permission="zope.View"
|
permission="zope.View"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<page
|
||||||
|
name="external_edit"
|
||||||
|
for="loops.interfaces.INode"
|
||||||
|
class="loops.browser.node.NodeView"
|
||||||
|
attribute="externalEdit"
|
||||||
|
permission="zope.ManageContent">
|
||||||
|
</page>
|
||||||
|
|
||||||
<!-- forms (end-user view) -->
|
<!-- forms (end-user view) -->
|
||||||
|
|
||||||
<page
|
<page
|
||||||
|
@ -653,7 +661,7 @@
|
||||||
|
|
||||||
<zope:view factory="loops.view.NodeTraverser"
|
<zope:view factory="loops.view.NodeTraverser"
|
||||||
for="loops.interfaces.INode"
|
for="loops.interfaces.INode"
|
||||||
type="zope.publisher.interfaces.browser.IBrowserRequest"
|
type="zope.publisher.interfaces.http.IHTTPRequest"
|
||||||
provides="zope.publisher.interfaces.browser.IBrowserPublisher"
|
provides="zope.publisher.interfaces.browser.IBrowserPublisher"
|
||||||
allowed_interface="zope.publisher.interfaces.browser.IBrowserPublisher"
|
allowed_interface="zope.publisher.interfaces.browser.IBrowserPublisher"
|
||||||
permission="zope.Public" />
|
permission="zope.Public" />
|
||||||
|
|
|
@ -37,6 +37,7 @@ from zope.lifecycleevent import ObjectCreatedEvent, ObjectModifiedEvent
|
||||||
from zope.lifecycleevent import Attributes
|
from zope.lifecycleevent import Attributes
|
||||||
from zope.formlib.form import Form, FormFields
|
from zope.formlib.form import Form, FormFields
|
||||||
from zope.formlib.namedtemplate import NamedTemplate
|
from zope.formlib.namedtemplate import NamedTemplate
|
||||||
|
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||||
from zope.proxy import removeAllProxies
|
from zope.proxy import removeAllProxies
|
||||||
from zope.security import canAccess, canWrite
|
from zope.security import canAccess, canWrite
|
||||||
from zope.security.proxy import removeSecurityProxy
|
from zope.security.proxy import removeSecurityProxy
|
||||||
|
@ -45,6 +46,7 @@ from cybertools.ajax import innerHtml
|
||||||
from cybertools.browser import configurator
|
from cybertools.browser import configurator
|
||||||
from cybertools.browser.view import GenericView
|
from cybertools.browser.view import GenericView
|
||||||
from cybertools.typology.interfaces import IType, ITypeManager
|
from cybertools.typology.interfaces import IType, ITypeManager
|
||||||
|
from cybertools.xedit.browser import ExternalEditorView
|
||||||
from loops.interfaces import IConcept, IResource, IDocument, IMediaAsset, INode
|
from loops.interfaces import IConcept, IResource, IDocument, IMediaAsset, INode
|
||||||
from loops.interfaces import IViewConfiguratorSchema
|
from loops.interfaces import IViewConfiguratorSchema
|
||||||
from loops.resource import MediaAsset
|
from loops.resource import MediaAsset
|
||||||
|
@ -54,6 +56,9 @@ from loops.browser.common import BaseView
|
||||||
from loops.browser.concept import ConceptView
|
from loops.browser.concept import ConceptView
|
||||||
|
|
||||||
|
|
||||||
|
node_macros = ViewPageTemplateFile('node_macros.pt')
|
||||||
|
|
||||||
|
|
||||||
class NodeView(BaseView):
|
class NodeView(BaseView):
|
||||||
|
|
||||||
_itemNum = 0
|
_itemNum = 0
|
||||||
|
@ -171,7 +176,8 @@ class NodeView(BaseView):
|
||||||
# TODO: replace by something like: return self.target.macroName
|
# TODO: replace by something like: return self.target.macroName
|
||||||
target = self.targetObject
|
target = self.targetObject
|
||||||
if (target is None or IDocument.providedBy(target)
|
if (target is None or IDocument.providedBy(target)
|
||||||
or (IResource.providedBy(target) and target.contentType.startswith('text/'))):
|
or (IResource.providedBy(target) and
|
||||||
|
target.contentType.startswith('text/'))):
|
||||||
return 'textbody'
|
return 'textbody'
|
||||||
if IConcept.providedBy(target):
|
if IConcept.providedBy(target):
|
||||||
return 'conceptbody'
|
return 'conceptbody'
|
||||||
|
@ -183,6 +189,8 @@ class NodeView(BaseView):
|
||||||
def editable(self):
|
def editable(self):
|
||||||
return canWrite(self.context, 'body')
|
return canWrite(self.context, 'body')
|
||||||
|
|
||||||
|
# menu stuff
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def menuObject(self):
|
def menuObject(self):
|
||||||
return self.context.getMenu()
|
return self.context.getMenu()
|
||||||
|
@ -244,6 +252,8 @@ class NodeView(BaseView):
|
||||||
def active(self, item):
|
def active(self, item):
|
||||||
return item.context == self.context or item.context in self.parents
|
return item.context == self.context or item.context in self.parents
|
||||||
|
|
||||||
|
# virtual target support
|
||||||
|
|
||||||
def targetDefaultView(self):
|
def targetDefaultView(self):
|
||||||
target = self.virtualTargetObject
|
target = self.virtualTargetObject
|
||||||
if target is not None:
|
if target is not None:
|
||||||
|
@ -297,6 +307,14 @@ class NodeView(BaseView):
|
||||||
if target is not None:
|
if target is not None:
|
||||||
return BaseView(target, self.request).url
|
return BaseView(target, self.request).url
|
||||||
|
|
||||||
|
# target viewing and editing support
|
||||||
|
|
||||||
|
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?
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def hasEditableTarget(self):
|
def hasEditableTarget(self):
|
||||||
return IResource.providedBy(self.virtualTargetObject)
|
return IResource.providedBy(self.virtualTargetObject)
|
||||||
|
@ -313,6 +331,20 @@ class NodeView(BaseView):
|
||||||
cm.register('js-execute', jsCall, jsCall=jsCall)
|
cm.register('js-execute', jsCall, jsCall=jsCall)
|
||||||
return 'return inlineEdit("%s", "%s/inline_save")' % (id, self.virtualTargetUrl)
|
return 'return inlineEdit("%s", "%s/inline_save")' % (id, self.virtualTargetUrl)
|
||||||
|
|
||||||
|
def externalEdit(self):
|
||||||
|
target = self.virtualTargetObject
|
||||||
|
if target is None:
|
||||||
|
target = self.context
|
||||||
|
url = self.url
|
||||||
|
else:
|
||||||
|
ti = IType(target).typeInterface
|
||||||
|
if ti is not None:
|
||||||
|
target = ti(target)
|
||||||
|
url = self.virtualTargetUrl
|
||||||
|
return ExternalEditorView(target, self.request).load(url=url)
|
||||||
|
|
||||||
|
# helper methods
|
||||||
|
|
||||||
def registerDojoDialog(self):
|
def registerDojoDialog(self):
|
||||||
self.registerDojo()
|
self.registerDojo()
|
||||||
cm = self.controller.macros
|
cm = self.controller.macros
|
||||||
|
|
|
@ -243,6 +243,15 @@
|
||||||
|
|
||||||
<!-- edit and other links -->
|
<!-- edit and other links -->
|
||||||
|
|
||||||
|
<metal:xedit define-macro="external_edit"
|
||||||
|
tal:define="url action/url">
|
||||||
|
<a href="#" title="Edit with External Editor"
|
||||||
|
tal:attributes="href string:$url/external_edit"
|
||||||
|
><img src="edit.gif" alt="External Editor"
|
||||||
|
tal:attributes="src context/++resource++edit.gif" /></a>
|
||||||
|
</metal:xedit>
|
||||||
|
|
||||||
|
|
||||||
<metal:editlink define-macro="editlink">
|
<metal:editlink define-macro="editlink">
|
||||||
<a target="zmi"
|
<a target="zmi"
|
||||||
tal:define="url string:${item/url}/@@edit.html'"
|
tal:define="url string:${item/url}/@@edit.html'"
|
||||||
|
|
|
@ -37,9 +37,9 @@ from zope.security.proxy import removeSecurityProxy
|
||||||
|
|
||||||
from cybertools.typology.interfaces import IType
|
from cybertools.typology.interfaces import IType
|
||||||
from loops.interfaces import IBaseResource, IDocument, IMediaAsset
|
from loops.interfaces import IBaseResource, IDocument, IMediaAsset
|
||||||
from loops.browser.common import EditForm, BaseView
|
from loops.browser.common import EditForm, BaseView, Action
|
||||||
from loops.browser.concept import ConceptRelationView, ConceptConfigureView
|
from loops.browser.concept import ConceptRelationView, ConceptConfigureView
|
||||||
from loops.browser.node import NodeView
|
from loops.browser.node import NodeView, node_macros
|
||||||
from loops.interfaces import ITypeConcept
|
from loops.interfaces import ITypeConcept
|
||||||
from loops.browser.util import html_quote
|
from loops.browser.util import html_quote
|
||||||
|
|
||||||
|
@ -113,16 +113,30 @@ class ResourceView(BaseView):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def show(self):
|
def show(self):
|
||||||
|
""" show means: "download"..."""
|
||||||
context = self.context
|
context = self.context
|
||||||
|
ti = IType(context).typeInterface
|
||||||
|
if ti is not None:
|
||||||
|
context = ti(context)
|
||||||
data = context.data
|
data = context.data
|
||||||
response = self.request.response
|
response = self.request.response
|
||||||
response.setHeader('Content-Type', context.contentType)
|
response.setHeader('Content-Type', context.contentType)
|
||||||
response.setHeader('Content-Length', len(data))
|
response.setHeader('Content-Length', len(data))
|
||||||
if not context.contentType.startswith('image/'):
|
if not context.contentType.startswith('image/'):
|
||||||
response.setHeader('Content-Disposition',
|
response.setHeader('Content-Disposition',
|
||||||
'attachment; filename=%s' % zapi.getName(context))
|
'attachment; filename=%s' % zapi.getName(self.context))
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
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
|
||||||
|
else:
|
||||||
|
url = self.url
|
||||||
|
return [Action(renderer, url)]
|
||||||
|
|
||||||
def concepts(self):
|
def concepts(self):
|
||||||
for r in self.context.getConceptRelations():
|
for r in self.context.getConceptRelations():
|
||||||
yield ConceptRelationView(r, self.request)
|
yield ConceptRelationView(r, self.request)
|
||||||
|
|
|
@ -39,10 +39,19 @@
|
||||||
<metal:block define-macro="download">
|
<metal:block define-macro="download">
|
||||||
<div tal:attributes="ondblclick python: item.openEditWindow('edit.html')">
|
<div tal:attributes="ondblclick python: item.openEditWindow('edit.html')">
|
||||||
<h3 tal:content="item/title">Title</h3>
|
<h3 tal:content="item/title">Title</h3>
|
||||||
<a href="#"
|
<p>
|
||||||
tal:attributes="href string:${view/url}/.target${view/targetId}/view">
|
<a href="#"
|
||||||
Download '<span tal:replace="item/title" />'
|
tal:attributes="href string:${view/url}/.target${view/targetId}/view">
|
||||||
</a>
|
Download
|
||||||
|
</a>
|
||||||
|
<tal:xedit condition="view/xeditable"> |
|
||||||
|
<a href="#" title="Edit with External Editor"
|
||||||
|
tal:define="url string:${view/url}/.target${view/targetId}"
|
||||||
|
tal:attributes="href string:$url/external_edit">
|
||||||
|
Open for editing
|
||||||
|
</a>
|
||||||
|
</tal:xedit>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</metal:block>
|
</metal:block>
|
||||||
|
|
||||||
|
|
11
resource.py
11
resource.py
|
@ -286,8 +286,15 @@ class DocumentWriteFileAdapter(object):
|
||||||
|
|
||||||
def write(self, data):
|
def write(self, data):
|
||||||
# TODO: use typeInterface...
|
# TODO: use typeInterface...
|
||||||
ITextDocument(self.context).data = unicode(data.replace('\r', ''), 'UTF-8')
|
ti = IType(self.context).typeInterface
|
||||||
notify(ObjectModifiedEvent(self.context, Attributes(IDocument, 'data')))
|
context = ti is None and self.context or ti(self.context)
|
||||||
|
if ITextDocument.providedBy(context):
|
||||||
|
context.data = unicode(data.replace('\r', ''), 'UTF-8')
|
||||||
|
else:
|
||||||
|
# TODO: make use of tmpfile when using external files
|
||||||
|
context.data = data
|
||||||
|
#ITextDocument(self.context).data = unicode(data.replace('\r', ''), 'UTF-8')
|
||||||
|
notify(ObjectModifiedEvent(self.context, Attributes(IResource, 'data')))
|
||||||
|
|
||||||
|
|
||||||
class DocumentReadFileAdapter(object):
|
class DocumentReadFileAdapter(object):
|
||||||
|
|
14
view.py
14
view.py
|
@ -202,9 +202,15 @@ class NodeTraverser(ItemTraverser):
|
||||||
else:
|
else:
|
||||||
target = self.context.target
|
target = self.context.target
|
||||||
if target is not None:
|
if target is not None:
|
||||||
viewAnnotations = request.annotations.get('loops.view', {})
|
# remember self.context in request
|
||||||
viewAnnotations['target'] = target
|
viewAnnotations = request.annotations.setdefault('loops.view', {})
|
||||||
request.annotations['loops.view'] = viewAnnotations
|
viewAnnotations['node'] = self.context
|
||||||
return self.context
|
if request.method == 'PUT':
|
||||||
|
# we have to use the target object directly
|
||||||
|
return target
|
||||||
|
else:
|
||||||
|
# we'll use the target object in the node's context
|
||||||
|
viewAnnotations['target'] = target
|
||||||
|
return self.context
|
||||||
return super(NodeTraverser, self).publishTraverse(request, name)
|
return super(NodeTraverser, self).publishTraverse(request, name)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue