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:
helmutm 2006-02-06 15:14:04 +00:00
parent 4bbf9d4df9
commit 48f580ca31
10 changed files with 89 additions and 57 deletions

View file

@ -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

View file

@ -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']

View file

@ -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

View file

@ -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>

View file

@ -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)

View file

@ -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):

View file

@ -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)

View file

@ -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]

View file

@ -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
View file

@ -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