More on assigning targets to views/nodes via a vocabulary, including doc tests
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1055 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
4bbf9d4df9
commit
48f580ca31
10 changed files with 89 additions and 57 deletions
52
README.txt
52
README.txt
|
@ -271,20 +271,20 @@ Node Views
|
|||
... print item.url, view.selected(item)
|
||||
http://127.0.0.1/loops/views/m1/m11 True
|
||||
|
||||
Node Schema Adapters
|
||||
--------------------
|
||||
|
||||
When configuring a node you may
|
||||
specify what you want to do with respect to the node's target: associate
|
||||
an existing one or create a new one.
|
||||
Node Configuration
|
||||
------------------
|
||||
|
||||
When configuring a node you may specify what you want to do with respect
|
||||
to the node's target: associate an existing one or create a new one.
|
||||
These options are provided via the INodeConfigSchema that is provided
|
||||
by a NodeConfigAdapter; in addition the attributes of the node (like the
|
||||
title) may be changed via the NodeConfigAdapter.
|
||||
|
||||
>>> from loops.interfaces import INodeConfigSchema
|
||||
>>> from loops.view import NodeConfigAdapter
|
||||
>>> ztapi.provideAdapter(INode, INodeConfigSchema, NodeConfigAdapter)
|
||||
>>> nodeConfig = INodeConfigSchema(m111)
|
||||
|
||||
>>> nodeConfig.targetUri
|
||||
'.loops/concepts/cc2'
|
||||
>>> nodeConfig.title = u'New title for m111'
|
||||
>>> nodeConfig.title
|
||||
u'New title for m111'
|
||||
|
@ -293,9 +293,43 @@ an existing one or create a new one.
|
|||
>>> nodeConfig.target = doc1
|
||||
>>> m111.target is doc1
|
||||
True
|
||||
>>> m111 in doc1.getClients()
|
||||
True
|
||||
|
||||
The targetUri and targetType fields are only relevant when creating
|
||||
a new target object:
|
||||
|
||||
>>> nodeConfig.targetUri
|
||||
''
|
||||
>>> nodeConfig.targetType
|
||||
'loops.resource.Document'
|
||||
>>> m111 in doc1.getClients()
|
||||
|
||||
The node configuration form provides a target assignment field using
|
||||
a vocabulary (source) for selecting the target. (In a future version this form
|
||||
will be extended by a widget that lets you search for potential target
|
||||
objects.) The source is basically a source list:
|
||||
|
||||
>>> from loops.target import TargetSourceList
|
||||
>>> source = TargetSourceList(m111)
|
||||
>>> len(source)
|
||||
3
|
||||
>>> sorted([zapi.getName(s) for s in source])
|
||||
[u'cc1', u'cc2', u'doc1']
|
||||
|
||||
The form then uses a sort of browser view providing the ITerms interface
|
||||
based on this source list:
|
||||
|
||||
>>> from loops.browser.target import TargetTerms
|
||||
>>> terms = TargetTerms(source, TestRequest())
|
||||
>>> term = terms.getTerm(doc1)
|
||||
>>> term.token, term.title, term.value
|
||||
('.loops/resources/doc1', u'Zope Info', <loops.resource.Document...>)
|
||||
|
||||
>>> term = terms.getTerm(cc1)
|
||||
>>> term.token, term.title, term.value
|
||||
('.loops/concepts/cc1', u'cc1', <loops.concept.Concept...>)
|
||||
|
||||
>>> terms.getValue('.loops/concepts/cc1') is cc1
|
||||
True
|
||||
|
||||
There is a special edit view class that can be used to configure a node
|
||||
|
|
|
@ -37,6 +37,12 @@ class Loops(Folder):
|
|||
def getLoopsRoot(self):
|
||||
return self
|
||||
|
||||
def getConceptManager(self):
|
||||
return self['concepts']
|
||||
|
||||
def getResourceManager(self):
|
||||
return self['resources']
|
||||
|
||||
def getViewManager(self):
|
||||
return self['views']
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ from zope.proxy import removeAllProxies
|
|||
from zope.security import canAccess, canWrite
|
||||
from zope.security.proxy import removeSecurityProxy
|
||||
|
||||
from loops.interfaces import IDocument, IMediaAsset
|
||||
from loops.interfaces import IConcept, IDocument, IMediaAsset
|
||||
from loops.resource import MediaAsset
|
||||
|
||||
class NodeView(object):
|
||||
|
@ -97,7 +97,9 @@ class NodeView(object):
|
|||
target = self.target
|
||||
if target is None or IDocument.providedBy(target):
|
||||
return 'textbody'
|
||||
if target.contentType.startswith('image/'):
|
||||
if IConcept.providedBy(target): # TODO...
|
||||
return 'filebody'
|
||||
if IMediaAsset.providedBy(target) and target.contentType.startswith('image/'):
|
||||
return 'imagebody'
|
||||
return 'filebody'
|
||||
|
||||
|
@ -138,20 +140,23 @@ class ConfigureBaseView(object):
|
|||
def checkCreateTarget(self):
|
||||
form = self.request.form
|
||||
if form.get('field.createTarget', False):
|
||||
root = self.loopsRoot
|
||||
type = self.request.form.get('field.targetType',
|
||||
'loops.resource.MediaAsset')
|
||||
factory = resolve(type)
|
||||
uri = self.request.form.get('field.targetUri', None)
|
||||
if uri:
|
||||
path = uri.split('/')
|
||||
# TODO: check for .loops prefix
|
||||
containerName = path[-2]
|
||||
name = path[-1]
|
||||
container = root[containerName]
|
||||
else:
|
||||
containerName = 'resource' in type and 'resources' or 'concepts'
|
||||
viewManagerPath = zapi.getPath(self.context.getViewManager())
|
||||
container = ('.resource.' in type and root.getResourceManager()
|
||||
or root.getConceptManager())
|
||||
viewManagerPath = zapi.getPath(root.getViewManager())
|
||||
name = zapi.getPath(self.context)[len(viewManagerPath)+1:]
|
||||
name = name.replace('/', '.')
|
||||
container = self.loopsRoot[containerName]
|
||||
# check for duplicates:
|
||||
num = 1
|
||||
basename = name
|
||||
|
@ -161,9 +166,8 @@ class ConfigureBaseView(object):
|
|||
# create target:
|
||||
container[name] = factory()
|
||||
target = container[name]
|
||||
# set possibly new targetUri in request for further processing:
|
||||
# set possibly new target uri in request for further processing:
|
||||
targetUri = self.loopsRoot.getLoopsUri(target)
|
||||
#form['field.targetUri'] = targetUri
|
||||
form['field.target'] = targetUri
|
||||
return target
|
||||
|
||||
|
|
|
@ -22,12 +22,12 @@
|
|||
The body
|
||||
</div>
|
||||
<div class="content-1"
|
||||
tal:define="target view/target;
|
||||
tal:define="target item/target;
|
||||
onclick string:openEditWindow('${item/url}/@@edit_target.html')"
|
||||
tal:condition="target"
|
||||
tal:attributes="class string:content-$level;
|
||||
ondblclick python: item.editable and onclick or ''"
|
||||
tal:content="structure view/renderTargetBody">
|
||||
tal:content="structure item/renderTargetBody">
|
||||
The body
|
||||
</div>
|
||||
</tal:body>
|
||||
|
|
|
@ -45,7 +45,8 @@ class TargetTerms(object):
|
|||
|
||||
def getTerm(self, value):
|
||||
token = self.loopsRoot.getLoopsUri(value)
|
||||
return SimpleTerm(value, token, value.title)
|
||||
title = value.title or zapi.getName(value)
|
||||
return SimpleTerm(value, token, title)
|
||||
|
||||
def getValue(self, token):
|
||||
return self.loopsRoot.loopsTraverse(token)
|
||||
|
|
|
@ -67,9 +67,6 @@ class Concept(Contained, Persistent):
|
|||
def getLoopsRoot(self):
|
||||
return zapi.getParent(self).getLoopsRoot()
|
||||
|
||||
def getViewManager(self):
|
||||
return self.getLoopsRoot().getViewManager()
|
||||
|
||||
# concept relations
|
||||
|
||||
def getSubConcepts(self, relationships=None):
|
||||
|
|
|
@ -46,13 +46,9 @@ class ILoopsObject(Interface):
|
|||
""" Return the loops root object.
|
||||
"""
|
||||
|
||||
def getViewManager():
|
||||
""" Return the (default) view manager.
|
||||
"""
|
||||
|
||||
|
||||
class IPotentialTarget(Interface):
|
||||
""" For objects that may be used as target objects for view objects.
|
||||
""" For objects that may be used as target objects for views/nodes.
|
||||
"""
|
||||
|
||||
proxyInterface = Attribute('An interface allowing an object to be '
|
||||
|
@ -381,9 +377,22 @@ class ILoops(ILoopsObject, IFolder):
|
|||
"""
|
||||
|
||||
def loopsTraverse(uri):
|
||||
""" Retrieve object specified by the loops uri given.
|
||||
""" Retrieve object specified by the loops uri (starting with
|
||||
'.loops/') given.
|
||||
"""
|
||||
|
||||
def getConceptManager():
|
||||
""" Return the (default) concept manager.
|
||||
"""
|
||||
|
||||
def getResourceManager():
|
||||
""" Return the (default) resource manager.
|
||||
"""
|
||||
|
||||
def getViewManager():
|
||||
""" Return the (default) view manager.
|
||||
"""
|
||||
|
||||
|
||||
class ILoopsContained(Interface):
|
||||
containers(ILoops)
|
||||
|
|
|
@ -57,9 +57,6 @@ class Resource(Contained, Persistent):
|
|||
def getLoopsRoot(self):
|
||||
return zapi.getParent(self).getLoopsRoot()
|
||||
|
||||
def getViewManager(self):
|
||||
return self.getLoopsRoot().getViewManager()
|
||||
|
||||
def getClients(self, relationships=None):
|
||||
rels = getRelations(second=self, relationships=relationships)
|
||||
return [r.first for r in rels]
|
||||
|
|
11
target.py
11
target.py
|
@ -109,12 +109,15 @@ class TargetSourceList(object):
|
|||
|
||||
def __init__(self, context):
|
||||
self.context = removeSecurityProxy(context)
|
||||
self.resources = self.context.getLoopsRoot()['resources']
|
||||
root = self.context.getLoopsRoot()
|
||||
self.resources = root.getResourceManager()
|
||||
self.concepts = root.getConceptManager()
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self.resources.values())
|
||||
return iter(list(self.resources.values()) + list(self.concepts.values()))
|
||||
|
||||
def __len__():
|
||||
return len(self.resources)
|
||||
def __len__(self):
|
||||
return len(self.resources) + len(self.concepts)
|
||||
|
||||
|
||||
|
25
view.py
25
view.py
|
@ -91,9 +91,6 @@ class View(object):
|
|||
def getLoopsRoot(self):
|
||||
return zapi.getParent(self).getLoopsRoot()
|
||||
|
||||
def getViewManager(self):
|
||||
return zapi.getParent(self).getViewManager()
|
||||
|
||||
|
||||
class Node(View, OrderedContainer):
|
||||
|
||||
|
@ -204,23 +201,8 @@ class NodeConfigAdapter(object):
|
|||
@Lazy
|
||||
def loopsRoot(self): return self.context.getLoopsRoot()
|
||||
|
||||
def getTargetUri(self):
|
||||
target = self.target
|
||||
if target is not None:
|
||||
return self.loopsRoot.getLoopsUri(target)
|
||||
else:
|
||||
return ''
|
||||
|
||||
def setTargetUri(self, uri):
|
||||
return # ignore - only relevant for target creation
|
||||
if uri:
|
||||
names = uri.split('/')
|
||||
if names[0] == '.loops':
|
||||
path = '/'.join(names[1:])
|
||||
self.context.target = zapi.traverse(self.loopsRoot, path)
|
||||
else:
|
||||
self.context.target = None
|
||||
|
||||
def getTargetUri(self):return ''
|
||||
def setTargetUri(self, uri): pass
|
||||
targetUri = property(getTargetUri, setTargetUri)
|
||||
|
||||
def getTargetType(self):
|
||||
|
@ -228,8 +210,7 @@ class NodeConfigAdapter(object):
|
|||
if target:
|
||||
return '%s.%s' % (target.__module__, target.__class__.__name__)
|
||||
return None
|
||||
def setTargetType(self, tt):
|
||||
pass # only used whe a new target object is created
|
||||
def setTargetType(self, tt): pass
|
||||
targetType = property(getTargetType, setTargetType)
|
||||
|
||||
def getCreateTarget(self): return False
|
||||
|
|
Loading…
Add table
Reference in a new issue