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) ... print item.url, view.selected(item)
http://127.0.0.1/loops/views/m1/m11 True http://127.0.0.1/loops/views/m1/m11 True
Node Schema Adapters 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.
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.interfaces import INodeConfigSchema
>>> from loops.view import NodeConfigAdapter >>> from loops.view import NodeConfigAdapter
>>> ztapi.provideAdapter(INode, INodeConfigSchema, NodeConfigAdapter) >>> ztapi.provideAdapter(INode, INodeConfigSchema, NodeConfigAdapter)
>>> nodeConfig = INodeConfigSchema(m111) >>> nodeConfig = INodeConfigSchema(m111)
>>> nodeConfig.targetUri
'.loops/concepts/cc2'
>>> nodeConfig.title = u'New title for m111' >>> nodeConfig.title = u'New title for m111'
>>> nodeConfig.title >>> nodeConfig.title
u'New title for m111' u'New title for m111'
@ -293,9 +293,43 @@ an existing one or create a new one.
>>> nodeConfig.target = doc1 >>> nodeConfig.target = doc1
>>> m111.target is doc1 >>> m111.target is doc1
True True
>>> m111 in doc1.getClients()
True
The targetUri and targetType fields are only relevant when creating
a new target object:
>>> nodeConfig.targetUri
''
>>> nodeConfig.targetType >>> nodeConfig.targetType
'loops.resource.Document' '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 True
There is a special edit view class that can be used to configure a node 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): def getLoopsRoot(self):
return self return self
def getConceptManager(self):
return self['concepts']
def getResourceManager(self):
return self['resources']
def getViewManager(self): def getViewManager(self):
return self['views'] return self['views']

View file

@ -32,7 +32,7 @@ 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
from loops.interfaces import IDocument, IMediaAsset from loops.interfaces import IConcept, IDocument, IMediaAsset
from loops.resource import MediaAsset from loops.resource import MediaAsset
class NodeView(object): class NodeView(object):
@ -97,7 +97,9 @@ class NodeView(object):
target = self.target target = self.target
if target is None or IDocument.providedBy(target): if target is None or IDocument.providedBy(target):
return 'textbody' 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 'imagebody'
return 'filebody' return 'filebody'
@ -138,20 +140,23 @@ class ConfigureBaseView(object):
def checkCreateTarget(self): def checkCreateTarget(self):
form = self.request.form form = self.request.form
if form.get('field.createTarget', False): if form.get('field.createTarget', False):
root = self.loopsRoot
type = self.request.form.get('field.targetType', type = self.request.form.get('field.targetType',
'loops.resource.MediaAsset') 'loops.resource.MediaAsset')
factory = resolve(type) factory = resolve(type)
uri = self.request.form.get('field.targetUri', None) uri = self.request.form.get('field.targetUri', None)
if uri: if uri:
path = uri.split('/') path = uri.split('/')
# TODO: check for .loops prefix
containerName = path[-2] containerName = path[-2]
name = path[-1] name = path[-1]
container = root[containerName]
else: else:
containerName = 'resource' in type and 'resources' or 'concepts' container = ('.resource.' in type and root.getResourceManager()
viewManagerPath = zapi.getPath(self.context.getViewManager()) or root.getConceptManager())
viewManagerPath = zapi.getPath(root.getViewManager())
name = zapi.getPath(self.context)[len(viewManagerPath)+1:] name = zapi.getPath(self.context)[len(viewManagerPath)+1:]
name = name.replace('/', '.') name = name.replace('/', '.')
container = self.loopsRoot[containerName]
# check for duplicates: # check for duplicates:
num = 1 num = 1
basename = name basename = name
@ -161,9 +166,8 @@ class ConfigureBaseView(object):
# create target: # create target:
container[name] = factory() container[name] = factory()
target = container[name] 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) targetUri = self.loopsRoot.getLoopsUri(target)
#form['field.targetUri'] = targetUri
form['field.target'] = targetUri form['field.target'] = targetUri
return target return target

View file

@ -22,12 +22,12 @@
The body The body
</div> </div>
<div class="content-1" <div class="content-1"
tal:define="target view/target; tal:define="target item/target;
onclick string:openEditWindow('${item/url}/@@edit_target.html')" onclick string:openEditWindow('${item/url}/@@edit_target.html')"
tal:condition="target" tal:condition="target"
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 ''"
tal:content="structure view/renderTargetBody"> tal:content="structure item/renderTargetBody">
The body The body
</div> </div>
</tal:body> </tal:body>

View file

@ -45,7 +45,8 @@ class TargetTerms(object):
def getTerm(self, value): def getTerm(self, value):
token = self.loopsRoot.getLoopsUri(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): def getValue(self, token):
return self.loopsRoot.loopsTraverse(token) return self.loopsRoot.loopsTraverse(token)

View file

@ -67,9 +67,6 @@ class Concept(Contained, Persistent):
def getLoopsRoot(self): def getLoopsRoot(self):
return zapi.getParent(self).getLoopsRoot() return zapi.getParent(self).getLoopsRoot()
def getViewManager(self):
return self.getLoopsRoot().getViewManager()
# concept relations # concept relations
def getSubConcepts(self, relationships=None): def getSubConcepts(self, relationships=None):

View file

@ -46,13 +46,9 @@ class ILoopsObject(Interface):
""" Return the loops root object. """ Return the loops root object.
""" """
def getViewManager():
""" Return the (default) view manager.
"""
class IPotentialTarget(Interface): 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 ' proxyInterface = Attribute('An interface allowing an object to be '
@ -381,9 +377,22 @@ class ILoops(ILoopsObject, IFolder):
""" """
def loopsTraverse(uri): 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): class ILoopsContained(Interface):
containers(ILoops) containers(ILoops)

View file

@ -57,9 +57,6 @@ class Resource(Contained, Persistent):
def getLoopsRoot(self): def getLoopsRoot(self):
return zapi.getParent(self).getLoopsRoot() return zapi.getParent(self).getLoopsRoot()
def getViewManager(self):
return self.getLoopsRoot().getViewManager()
def getClients(self, relationships=None): def getClients(self, relationships=None):
rels = getRelations(second=self, relationships=relationships) rels = getRelations(second=self, relationships=relationships)
return [r.first for r in rels] return [r.first for r in rels]

View file

@ -109,12 +109,15 @@ class TargetSourceList(object):
def __init__(self, context): def __init__(self, context):
self.context = removeSecurityProxy(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): def __iter__(self):
return iter(self.resources.values()) return iter(list(self.resources.values()) + list(self.concepts.values()))
def __len__(): def __len__(self):
return len(self.resources) return len(self.resources) + len(self.concepts)

25
view.py
View file

@ -91,9 +91,6 @@ class View(object):
def getLoopsRoot(self): def getLoopsRoot(self):
return zapi.getParent(self).getLoopsRoot() return zapi.getParent(self).getLoopsRoot()
def getViewManager(self):
return zapi.getParent(self).getViewManager()
class Node(View, OrderedContainer): class Node(View, OrderedContainer):
@ -204,23 +201,8 @@ class NodeConfigAdapter(object):
@Lazy @Lazy
def loopsRoot(self): return self.context.getLoopsRoot() def loopsRoot(self): return self.context.getLoopsRoot()
def getTargetUri(self): def getTargetUri(self):return ''
target = self.target def setTargetUri(self, uri): pass
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
targetUri = property(getTargetUri, setTargetUri) targetUri = property(getTargetUri, setTargetUri)
def getTargetType(self): def getTargetType(self):
@ -228,8 +210,7 @@ class NodeConfigAdapter(object):
if target: if target:
return '%s.%s' % (target.__module__, target.__class__.__name__) return '%s.%s' % (target.__module__, target.__class__.__name__)
return None return None
def setTargetType(self, tt): def setTargetType(self, tt): pass
pass # only used whe a new target object is created
targetType = property(getTargetType, setTargetType) targetType = property(getTargetType, setTargetType)
def getCreateTarget(self): return False def getCreateTarget(self): return False