work in progress: provide target listings and views on nodes, possibly via concepts
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1125 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
072318ea06
commit
f15f2e94e3
8 changed files with 59 additions and 171 deletions
|
@ -31,7 +31,6 @@ from zope.security.proxy import removeSecurityProxy
|
||||||
|
|
||||||
from cybertools.typology.interfaces import IType
|
from cybertools.typology.interfaces import IType
|
||||||
from loops import util
|
from loops import util
|
||||||
from loops.target import getTargetTypes
|
|
||||||
|
|
||||||
class BaseView(object):
|
class BaseView(object):
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,6 @@ from zope.security.proxy import removeSecurityProxy
|
||||||
from cybertools.typology.interfaces import ITypeManager
|
from cybertools.typology.interfaces import ITypeManager
|
||||||
from loops.interfaces import IConcept
|
from loops.interfaces import IConcept
|
||||||
from loops.concept import Concept, ConceptTypeSourceList, PredicateSourceList
|
from loops.concept import Concept, ConceptTypeSourceList, PredicateSourceList
|
||||||
from loops.target import getTargetTypes
|
|
||||||
from loops.browser.common import BaseView, LoopsTerms
|
from loops.browser.common import BaseView, LoopsTerms
|
||||||
from loops import util
|
from loops import util
|
||||||
|
|
||||||
|
|
|
@ -24,8 +24,16 @@
|
||||||
|
|
||||||
<metal:body fill-slot="body">
|
<metal:body fill-slot="body">
|
||||||
<tal:content define="item view/page;
|
<tal:content define="item view/page;
|
||||||
level level|python: 1">
|
level level|python: 1;
|
||||||
<metal:block use-macro="views/node_macros/content" />
|
target request/annotations/loops.view/target | nothing">
|
||||||
|
<tal:content condition="not:target">
|
||||||
|
<metal:block use-macro="views/node_macros/content" />
|
||||||
|
</tal:content>
|
||||||
|
<tal:target condition="target">
|
||||||
|
<div>
|
||||||
|
Here comes the real target... <span tal:replace="target/title" />
|
||||||
|
</div>
|
||||||
|
</tal:target>
|
||||||
</tal:content>
|
</tal:content>
|
||||||
</metal:body>
|
</metal:body>
|
||||||
|
|
||||||
|
|
|
@ -26,9 +26,7 @@ from zope.cachedescriptors.property import Lazy
|
||||||
from zope.app import zapi
|
from zope.app import zapi
|
||||||
from zope.app.catalog.interfaces import ICatalog
|
from zope.app.catalog.interfaces import ICatalog
|
||||||
from zope.app.container.browser.contents import JustContents
|
from zope.app.container.browser.contents import JustContents
|
||||||
from zope.app.dublincore.interfaces import ICMFDublinCore
|
|
||||||
from zope.app.event.objectevent import ObjectCreatedEvent
|
from zope.app.event.objectevent import ObjectCreatedEvent
|
||||||
#import zope.configuration.name
|
|
||||||
from zope.dottedname.resolve import resolve
|
from zope.dottedname.resolve import resolve
|
||||||
from zope.event import notify
|
from zope.event import notify
|
||||||
from zope.proxy import removeAllProxies
|
from zope.proxy import removeAllProxies
|
||||||
|
@ -36,32 +34,19 @@ from zope.security import canAccess, canWrite
|
||||||
from zope.security.proxy import removeSecurityProxy
|
from zope.security.proxy import removeSecurityProxy
|
||||||
|
|
||||||
from cybertools.typology.interfaces import ITypeManager
|
from cybertools.typology.interfaces import ITypeManager
|
||||||
from loops.interfaces import IConcept, IDocument, IMediaAsset
|
from loops.interfaces import IConcept, IResource, IDocument, IMediaAsset
|
||||||
from loops.resource import MediaAsset
|
from loops.resource import MediaAsset
|
||||||
from loops.target import getTargetTypes, getTargetTypesForSearch
|
|
||||||
from loops import util
|
from loops import util
|
||||||
from loops.browser.common import BaseView
|
from loops.browser.common import BaseView
|
||||||
from loops.browser.concept import ConceptView
|
from loops.browser.concept import ConceptView
|
||||||
|
|
||||||
|
|
||||||
class NodeView(object):
|
class NodeView(BaseView):
|
||||||
|
|
||||||
def __init__(self, context, request):
|
|
||||||
self.context = context
|
|
||||||
self.request = request
|
|
||||||
|
|
||||||
@Lazy
|
|
||||||
def title(self):
|
|
||||||
return self.context.title
|
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def nodeType(self):
|
def nodeType(self):
|
||||||
return self.context.nodeType
|
return self.context.nodeType
|
||||||
|
|
||||||
@Lazy
|
|
||||||
def url(self):
|
|
||||||
return zapi.absoluteURL(self.context, self.request)
|
|
||||||
|
|
||||||
def render(self, text=None):
|
def render(self, text=None):
|
||||||
if text is None:
|
if text is None:
|
||||||
text = self.context.body
|
text = self.context.body
|
||||||
|
@ -74,19 +59,19 @@ class NodeView(object):
|
||||||
return view.render()
|
return view.render()
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def modified(self):
|
def targetObject(self):
|
||||||
""" get date/time of last modification
|
return self.context.target
|
||||||
"""
|
|
||||||
dc = ICMFDublinCore(self.context)
|
|
||||||
d = dc.modified or dc.created
|
|
||||||
return d and d.strftime('%Y-%m-%d %H:%M') or ''
|
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def target(self):
|
def target(self):
|
||||||
return self.context.target
|
obj = self.targetObject
|
||||||
|
if obj is not None:
|
||||||
|
if IConcept.providedBy(obj):
|
||||||
|
return ConceptView(obj, self.request)
|
||||||
|
return BaseView(obj, self.request)
|
||||||
|
|
||||||
def renderTarget(self):
|
def renderTarget(self):
|
||||||
target = self.target
|
target = self.targetObject
|
||||||
if target is not None:
|
if target is not None:
|
||||||
targetView = zapi.getMultiAdapter((target, self.request),
|
targetView = zapi.getMultiAdapter((target, self.request),
|
||||||
name=zapi.getDefaultViewName(target, self.request))
|
name=zapi.getDefaultViewName(target, self.request))
|
||||||
|
@ -94,7 +79,7 @@ class NodeView(object):
|
||||||
return u''
|
return u''
|
||||||
|
|
||||||
def renderTargetBody(self):
|
def renderTargetBody(self):
|
||||||
target = self.target
|
target = self.targetObject
|
||||||
if target is not None:
|
if target is not None:
|
||||||
targetView = zapi.getMultiAdapter((target, self.request))
|
targetView = zapi.getMultiAdapter((target, self.request))
|
||||||
return targetView.render()
|
return targetView.render()
|
||||||
|
@ -115,7 +100,7 @@ class NodeView(object):
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def bodyMacro(self):
|
def bodyMacro(self):
|
||||||
target = self.target
|
target = self.targetObject
|
||||||
if target is None or IDocument.providedBy(target):
|
if target is None or IDocument.providedBy(target):
|
||||||
return 'textbody'
|
return 'textbody'
|
||||||
if IConcept.providedBy(target): # TODO...
|
if IConcept.providedBy(target): # TODO...
|
||||||
|
@ -140,8 +125,17 @@ class NodeView(object):
|
||||||
def selected(self, item):
|
def selected(self, item):
|
||||||
return item.context == self.context
|
return item.context == self.context
|
||||||
|
|
||||||
|
# view @@target - probably obsolete, replace by view.NodeTraverser
|
||||||
|
def renderTarget(self):
|
||||||
|
target = self.target
|
||||||
|
if target is not None:
|
||||||
|
targetView = zapi.getMultiAdapter((target, self.request),
|
||||||
|
name=zapi.getDefaultViewName(target, self.request))
|
||||||
|
return targetView()
|
||||||
|
return u''
|
||||||
|
|
||||||
class ConfigureView(BaseView):
|
|
||||||
|
class ConfigureView(NodeView):
|
||||||
""" An editing view for configuring a node, optionally creating
|
""" An editing view for configuring a node, optionally creating
|
||||||
a target object.
|
a target object.
|
||||||
"""
|
"""
|
||||||
|
@ -151,19 +145,6 @@ class ConfigureView(BaseView):
|
||||||
self.context = removeSecurityProxy(context)
|
self.context = removeSecurityProxy(context)
|
||||||
self.request = request
|
self.request = request
|
||||||
|
|
||||||
@Lazy
|
|
||||||
def loopsRoot(self):
|
|
||||||
return self.context.getLoopsRoot()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def target(self):
|
|
||||||
target = self.context.target
|
|
||||||
if target is not None:
|
|
||||||
if IConcept.providedBy(target):
|
|
||||||
return ConceptView(target, self.request)
|
|
||||||
return BaseView(target, self.request)
|
|
||||||
return None
|
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
request = self.request
|
request = self.request
|
||||||
action = request.get('action')
|
action = request.get('action')
|
||||||
|
@ -249,8 +230,4 @@ class ConfigureView(BaseView):
|
||||||
if o == self.context.target:
|
if o == self.context.target:
|
||||||
continue
|
continue
|
||||||
yield BaseView(o, request)
|
yield BaseView(o, request)
|
||||||
#if IConcept.providedBy(o):
|
|
||||||
# yield ConceptView(o, request)
|
|
||||||
#else:
|
|
||||||
# yield BaseView(o, request)
|
|
||||||
|
|
||||||
|
|
|
@ -35,15 +35,19 @@
|
||||||
|
|
||||||
|
|
||||||
<metal:body define-macro="conceptbody">
|
<metal:body define-macro="conceptbody">
|
||||||
<tal:body define="body item/body">
|
<tal:body define="body item/body;
|
||||||
|
target item/target;">
|
||||||
<div class="content-1"
|
<div class="content-1"
|
||||||
tal:define="onclick string:openEditWindow('${item/url}/@@configure.html')"
|
tal:define="onclick string:openEditWindow('${item/url}/@@configure.html')"
|
||||||
tal:attributes="class string:content-$level;
|
tal:attributes="class string:content-$level;
|
||||||
ondblclick python: item.editable and onclick or ''">
|
ondblclick python: item.editable and onclick or ''">
|
||||||
|
<span tal:content="structure body">Node Body</span>
|
||||||
|
</div>
|
||||||
|
<div tal:repeat="resource target/resources">
|
||||||
<a href="#"
|
<a href="#"
|
||||||
tal:omit-tag=""
|
tal:attributes="href
|
||||||
tal:attributes="href item/target/@@absolute_url"
|
string:${item/url}/.target${repeat/resource/number}/@@node.html"
|
||||||
tal:content="structure body">The body</a>
|
tal:content="resource/title">Resource Title</a>
|
||||||
</div>
|
</div>
|
||||||
</tal:body>
|
</tal:body>
|
||||||
</metal:body>
|
</metal:body>
|
||||||
|
@ -56,7 +60,7 @@
|
||||||
tal:attributes="class string:content-$level;
|
tal:attributes="class string:content-$level;
|
||||||
ondblclick python: item.editable and onclick or ''">
|
ondblclick python: item.editable and onclick or ''">
|
||||||
<a href="#"
|
<a href="#"
|
||||||
tal:attributes="href string:${item/url}/target"
|
tal:attributes="href string:${item/url}/@@target"
|
||||||
tal:content="structure body">The body</a>
|
tal:content="structure body">The body</a>
|
||||||
</div>
|
</div>
|
||||||
</tal:body>
|
</tal:body>
|
||||||
|
@ -70,7 +74,7 @@
|
||||||
tal:attributes="class string:content-$level;
|
tal:attributes="class string:content-$level;
|
||||||
ondblclick python: item.editable and onclick or ''">
|
ondblclick python: item.editable and onclick or ''">
|
||||||
<img src="target"
|
<img src="target"
|
||||||
tal:attributes="src string:${item/url}/target" />
|
tal:attributes="src string:${item/url}/@@target" />
|
||||||
</div>
|
</div>
|
||||||
<div class="content-1"
|
<div class="content-1"
|
||||||
tal:condition="body"
|
tal:condition="body"
|
||||||
|
|
|
@ -244,9 +244,6 @@
|
||||||
<adapter factory="loops.external.NodesExporter" />
|
<adapter factory="loops.external.NodesExporter" />
|
||||||
<adapter factory="loops.external.NodesImporter" />
|
<adapter factory="loops.external.NodesImporter" />
|
||||||
|
|
||||||
<adapter factory=".view.NodeConfigAdapter"
|
|
||||||
permission="zope.ManageContent" />
|
|
||||||
|
|
||||||
<adapter factory="loops.target.DocumentProxy"
|
<adapter factory="loops.target.DocumentProxy"
|
||||||
permission="zope.ManageContent" />
|
permission="zope.ManageContent" />
|
||||||
<adapter factory="loops.target.MediaAssetProxy"
|
<adapter factory="loops.target.MediaAssetProxy"
|
||||||
|
@ -264,11 +261,6 @@
|
||||||
name="loops.PredicateSource"
|
name="loops.PredicateSource"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!--<vocabulary
|
|
||||||
factory="loops.target.TargetSourceList"
|
|
||||||
name="loops.targetSource"
|
|
||||||
/>-->
|
|
||||||
|
|
||||||
<!-- Register various browser related components, including all views -->
|
<!-- Register various browser related components, including all views -->
|
||||||
<include package=".browser" />
|
<include package=".browser" />
|
||||||
|
|
||||||
|
|
66
target.py
66
target.py
|
@ -55,11 +55,14 @@ class ConceptProxy(object):
|
||||||
def setTitle(self, title): self.target.title = title
|
def setTitle(self, title): self.target.title = title
|
||||||
title = property(getTitle, setTitle)
|
title = property(getTitle, setTitle)
|
||||||
|
|
||||||
def getChildren(self, relationships=None):
|
def getChildren(self, predicates=None):
|
||||||
return self.target.getChildren(relationships)
|
return self.target.getChildren(predicates)
|
||||||
|
|
||||||
def getParents(self, relationships=None):
|
def getParents(self, predicates=None):
|
||||||
return self.target.getParents(relationships)
|
return self.target.getParents(predicates)
|
||||||
|
|
||||||
|
def getResources(self, predicates=None):
|
||||||
|
return self.target.getResources(predicates)
|
||||||
|
|
||||||
|
|
||||||
class ResourceProxy(object):
|
class ResourceProxy(object):
|
||||||
|
@ -103,58 +106,3 @@ class MediaAssetProxy(ResourceProxy):
|
||||||
def getData(self): return self.target.data
|
def getData(self): return self.target.data
|
||||||
data = property(getData, setData)
|
data = property(getData, setData)
|
||||||
|
|
||||||
|
|
||||||
# source classes for target vocabularies
|
|
||||||
|
|
||||||
class TargetSourceList(object):
|
|
||||||
|
|
||||||
implements(schema.interfaces.IIterableSource)
|
|
||||||
|
|
||||||
def __init__(self, context):
|
|
||||||
#self.context = context
|
|
||||||
self.context = removeSecurityProxy(context)
|
|
||||||
root = self.context.getLoopsRoot()
|
|
||||||
self.resources = root.getResourceManager()
|
|
||||||
# concepts will only be included when we have some really
|
|
||||||
# queryable source with a corresponding user interface:
|
|
||||||
#self.concepts = root.getConceptManager()
|
|
||||||
self.concepts = {}
|
|
||||||
|
|
||||||
def __iter__(self):
|
|
||||||
for obj in self.resources.values():
|
|
||||||
yield obj
|
|
||||||
for obj in self.concepts.values():
|
|
||||||
yield obj
|
|
||||||
#return iter(list(self.resources.values()) + list(self.concepts.values()))
|
|
||||||
|
|
||||||
def __len__(self):
|
|
||||||
return len(self.resources) + len(self.concepts)
|
|
||||||
|
|
||||||
|
|
||||||
class QueryableTargetSource(object):
|
|
||||||
|
|
||||||
implements(schema.interfaces.ISource)
|
|
||||||
|
|
||||||
def __init__(self, context):
|
|
||||||
self.context = context
|
|
||||||
root = self.context.getLoopsRoot()
|
|
||||||
self.resources = root.getResourceManager()
|
|
||||||
self.concepts = root.getConceptManager()
|
|
||||||
|
|
||||||
def __contains__(self, value):
|
|
||||||
return value in self.resources.values() or value in self.concepts.values()
|
|
||||||
|
|
||||||
|
|
||||||
def getTargetTypes():
|
|
||||||
return (('loops.concept.Concept', _(u'Concept')),
|
|
||||||
('loops.resource.Document', _(u'Document')),
|
|
||||||
('loops.resource.MediaAsset', _(u'Media Asset')),
|
|
||||||
)
|
|
||||||
|
|
||||||
def getTargetTypesForSearch():
|
|
||||||
# TODO: provide full list of concept types
|
|
||||||
return (('loops:concept:*', _(u'Any Concept')),
|
|
||||||
('loops:resource:Document', _(u'Document')),
|
|
||||||
('loops:resource:MediaAsset', _(u'Media Asset')),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
59
view.py
59
view.py
|
@ -42,6 +42,7 @@ from interfaces import IView, INode, INodeConfigSchema
|
||||||
from interfaces import IViewManager, INodeContained
|
from interfaces import IViewManager, INodeContained
|
||||||
from interfaces import ILoopsContained
|
from interfaces import ILoopsContained
|
||||||
from interfaces import ITargetRelation
|
from interfaces import ITargetRelation
|
||||||
|
from interfaces import IConcept
|
||||||
|
|
||||||
|
|
||||||
class View(object):
|
class View(object):
|
||||||
|
@ -167,54 +168,14 @@ class NodeTraverser(ItemTraverser):
|
||||||
def publishTraverse(self, request, name):
|
def publishTraverse(self, request, name):
|
||||||
if name == '.loops':
|
if name == '.loops':
|
||||||
return self.context.getLoopsRoot()
|
return self.context.getLoopsRoot()
|
||||||
|
if name.startswith('.target'):
|
||||||
|
target = self.context.target
|
||||||
|
if len(name) > len('.target') and IConcept.providedBy(target):
|
||||||
|
idx = int(name[len('.target'):]) - 1
|
||||||
|
target = target.getResources()[idx]
|
||||||
|
viewAnnotations = request.annotations.get('loops.view', {})
|
||||||
|
viewAnnotations['target'] = target
|
||||||
|
request.annotations['loops.view'] = viewAnnotations
|
||||||
|
return self.context
|
||||||
return super(NodeTraverser, self).publishTraverse(request, name)
|
return super(NodeTraverser, self).publishTraverse(request, name)
|
||||||
|
|
||||||
|
|
||||||
class NodeConfigAdapter(object):
|
|
||||||
|
|
||||||
def __init__(self, context):
|
|
||||||
self.context = removeSecurityProxy(context)
|
|
||||||
self._targetType = None
|
|
||||||
|
|
||||||
implements(INodeConfigSchema)
|
|
||||||
adapts(INode)
|
|
||||||
|
|
||||||
# provide access to fields of the Node class:
|
|
||||||
|
|
||||||
def getTitle(self): return self.context.title
|
|
||||||
def setTitle(self, title): self.context.title = title
|
|
||||||
title = property(getTitle, setTitle)
|
|
||||||
|
|
||||||
def getDescription(self): return self.context.description
|
|
||||||
def setDescription(self, description): self.context.description = description
|
|
||||||
description = property(getDescription, setDescription)
|
|
||||||
|
|
||||||
def getNodeType(self): return self.context.nodeType
|
|
||||||
def setNodeType(self, nodeType): self.context.nodeType = nodeType
|
|
||||||
nodeType = property(getNodeType, setNodeType)
|
|
||||||
|
|
||||||
def getTarget(self): return self.context.target
|
|
||||||
def setTarget(self, target): self.context.target = target
|
|
||||||
target = property(getTarget, setTarget)
|
|
||||||
|
|
||||||
# the real config stuff:
|
|
||||||
|
|
||||||
@Lazy
|
|
||||||
def loopsRoot(self): return self.context.getLoopsRoot()
|
|
||||||
|
|
||||||
def getTargetUri(self):return ''
|
|
||||||
def setTargetUri(self, uri): pass
|
|
||||||
targetUri = property(getTargetUri, setTargetUri)
|
|
||||||
|
|
||||||
def getTargetType(self):
|
|
||||||
target = self.target
|
|
||||||
if target:
|
|
||||||
return '%s.%s' % (target.__module__, target.__class__.__name__)
|
|
||||||
return None
|
|
||||||
def setTargetType(self, tt): pass
|
|
||||||
targetType = property(getTargetType, setTargetType)
|
|
||||||
|
|
||||||
def getCreateTarget(self): return False
|
|
||||||
def setCreateTarget(self, value): pass
|
|
||||||
createTarget = property(getCreateTarget, setCreateTarget)
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue