Basic setup for node schema adapters (+ some minor improvements)
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1022 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
f30caa3c14
commit
ee7a84b6d5
11 changed files with 197 additions and 20 deletions
24
README.txt
24
README.txt
|
@ -236,9 +236,10 @@ view class's target attribute:
|
|||
>>> m111.target is cc2
|
||||
True
|
||||
|
||||
Node views
|
||||
Node Views
|
||||
----------
|
||||
|
||||
>>> from loops.interfaces import INode
|
||||
>>> from loops.browser.node import NodeView
|
||||
>>> view = NodeView(m11, TestRequest())
|
||||
|
||||
|
@ -254,7 +255,26 @@ Node views
|
|||
... print item.url, view.selected(item)
|
||||
http://127.0.0.1/loops/views/m1/m11 True
|
||||
|
||||
|
||||
Node Schema Adapters
|
||||
--------------------
|
||||
|
||||
When creating or editing (more precisely: 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 (with specifying the target's type),
|
||||
and give an URI that will be used to identify the target. (Internally
|
||||
the reference to the target will be stored as a relation so that the
|
||||
target may be moved or renamed without any problems.)
|
||||
|
||||
>>> from loops.interfaces import INodeConfigSchema
|
||||
>>> from loops.view import NodeConfigAdapter
|
||||
>>> ztapi.provideAdapter(INode, INodeConfigSchema, NodeConfigAdapter)
|
||||
>>> nodeConfig = INodeConfigSchema(m111)
|
||||
|
||||
It is also possible to edit a target's attributes directly in an
|
||||
edit form provided by the node:
|
||||
|
||||
>>> from loops.target import DocumentProxy, MediaAssetProxy
|
||||
|
||||
Ordering Nodes
|
||||
--------------
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# -*- coding: UTF-8 -*-
|
||||
# -*- Mode: Python; py-indent-offset: 4 -*-
|
||||
#
|
||||
# Copyright (c) 2005 Helmut Merz helmutm@cy55.de
|
||||
# Copyright (c) 2006 Helmut Merz helmutm@cy55.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
@ -31,3 +31,6 @@ class Loops(Folder):
|
|||
|
||||
implements(ILoops)
|
||||
|
||||
def getLoopsRoot(self):
|
||||
return self
|
||||
|
||||
|
|
|
@ -218,6 +218,13 @@
|
|||
permission="zope.ManageContent"
|
||||
menu="zmi_views" title="Edit"
|
||||
/>
|
||||
|
||||
<!-- suppress the upload menu item: -->
|
||||
<menuItem
|
||||
for="loops.interfaces.IMediaAsset"
|
||||
menu="zmi_views" action="upload.html" title="Upload"
|
||||
filter="nothing"
|
||||
/>
|
||||
|
||||
<!-- view manager -->
|
||||
|
||||
|
|
|
@ -46,3 +46,12 @@
|
|||
font-size: 90%
|
||||
}
|
||||
|
||||
.flow-left {
|
||||
float: left;
|
||||
}
|
||||
|
||||
div.image {
|
||||
margin-top: 10px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,6 @@ from zope.proxy import removeAllProxies
|
|||
from zope.security import canAccess, canWrite
|
||||
from zope.security.proxy import removeSecurityProxy
|
||||
|
||||
from loops.interfaces import IConcept
|
||||
|
||||
class NodeView(object):
|
||||
|
||||
|
@ -57,6 +56,10 @@ class NodeView(object):
|
|||
d = dc.modified or dc.created
|
||||
return d and d.strftime('%Y-%m-%d %H:%M') or ''
|
||||
|
||||
@Lazy
|
||||
def target(self):
|
||||
return self.context.target
|
||||
|
||||
@Lazy
|
||||
def page(self):
|
||||
page = self.context.getPage()
|
||||
|
|
|
@ -62,6 +62,9 @@ class Concept(Contained, Persistent):
|
|||
def __init__(self, title=u''):
|
||||
self.title = title
|
||||
|
||||
def getLoopsRoot(self):
|
||||
return zapi.getParent(self).getLoopsRoot()
|
||||
|
||||
# concept relations
|
||||
|
||||
def getSubConcepts(self, relationships=None):
|
||||
|
@ -122,3 +125,6 @@ class ConceptManager(BTreeContainer):
|
|||
|
||||
implements(IConceptManager, ILoopsContained)
|
||||
|
||||
def getLoopsRoot(self):
|
||||
return zapi.getParent(self)
|
||||
|
||||
|
|
|
@ -209,16 +209,17 @@
|
|||
|
||||
</content>
|
||||
|
||||
<!-- adapters for export/import -->
|
||||
<!-- adapters -->
|
||||
|
||||
<adapter factory="loops.external.NodesLoader" />
|
||||
|
||||
<adapter factory="loops.external.NodesExporter" />
|
||||
|
||||
<adapter factory="loops.external.NodesImporter" />
|
||||
|
||||
<!-- traversal adapter -->
|
||||
|
||||
<adapter factory="loops.view.NodeConfigAdapter" />
|
||||
|
||||
<adapter factory="loops.target.DocumentProxy" />
|
||||
<adapter factory="loops.target.MediaAssetProxy" />
|
||||
|
||||
<view factory="loops.view.NodeTraverser"
|
||||
for="loops.interfaces.INode"
|
||||
type="zope.publisher.interfaces.browser.IBrowserRequest"
|
||||
|
|
|
@ -33,9 +33,19 @@ from zope.app.folder.interfaces import IFolder
|
|||
_ = MessageFactory('loops')
|
||||
|
||||
|
||||
# common top-level
|
||||
|
||||
class ILoopsObject(Interface):
|
||||
""" Common top-level interface.
|
||||
"""
|
||||
|
||||
def getLoopsRoot():
|
||||
""" Return the loops root object.
|
||||
"""
|
||||
|
||||
# concept interfaces
|
||||
|
||||
class IConcept(Interface):
|
||||
class IConcept(ILoopsObject):
|
||||
""" The concept is the central element of the loops framework.
|
||||
|
||||
A concept is related to other concepts, may have resources
|
||||
|
@ -89,7 +99,7 @@ class IConcept(Interface):
|
|||
"""
|
||||
|
||||
|
||||
class IConceptManager(IContainer):
|
||||
class IConceptManager(ILoopsObject, IContainer):
|
||||
""" A manager/container for concepts.
|
||||
"""
|
||||
contains(IConcept)
|
||||
|
@ -101,7 +111,7 @@ class IConceptManagerContained(Interface):
|
|||
|
||||
# resource interfaces
|
||||
|
||||
class IResource(Interface):
|
||||
class IResource(ILoopsObject):
|
||||
""" A resource is an atomic information element that is made
|
||||
available via a view or a concept.
|
||||
"""
|
||||
|
@ -158,7 +168,7 @@ class IMediaAsset(IResource, IBaseAsset):
|
|||
required=False)
|
||||
|
||||
|
||||
class IResourceManager(IContainer):
|
||||
class IResourceManager(ILoopsObject, IContainer):
|
||||
""" A manager/container for resources.
|
||||
"""
|
||||
contains(IResource)
|
||||
|
@ -170,7 +180,7 @@ class IResourceManagerContained(Interface):
|
|||
|
||||
# view interfaces
|
||||
|
||||
class IView(Interface):
|
||||
class IView(ILoopsObject):
|
||||
""" A view is a user interface component that provides access to one
|
||||
or more concepts, resources, or other views.
|
||||
"""
|
||||
|
@ -261,7 +271,7 @@ class INode(IView, IBaseNode):
|
|||
"""
|
||||
|
||||
|
||||
class IViewManager(IBaseNode):
|
||||
class IViewManager(ILoopsObject, IBaseNode):
|
||||
""" A manager/container for views.
|
||||
"""
|
||||
contains(IView)
|
||||
|
@ -271,9 +281,38 @@ class INodeContained(Interface):
|
|||
containers(INode, IViewManager)
|
||||
|
||||
|
||||
# schemas to be used by forms on view/node objects
|
||||
|
||||
class ITargetProperties(Interface):
|
||||
""" Fields used for specifying a view's or node's target.
|
||||
"""
|
||||
|
||||
targetType = schema.Choice(
|
||||
title=_(u'Target Type'),
|
||||
description=_(u'Type of the target'),
|
||||
values=('', 'resource.Document', 'resource.MediaAsset'),
|
||||
default='',
|
||||
required=False)
|
||||
|
||||
targetUri = schema.TextLine(
|
||||
title=_(u'Target URI'),
|
||||
description=_(u'An URI being a unique reference to the target'),
|
||||
required=False)
|
||||
|
||||
|
||||
class INodeConfigSchema(INode, ITargetProperties):
|
||||
""" All fields that may be shown in the node add form.
|
||||
"""
|
||||
|
||||
createTarget = schema.Bool(
|
||||
title=_(u'Create Target'),
|
||||
description=_(u'Should a new target object be created?'),
|
||||
required=False)
|
||||
|
||||
|
||||
# the loops top-level container
|
||||
|
||||
class ILoops(IFolder):
|
||||
class ILoops(ILoopsObject, IFolder):
|
||||
""" The top-level object of a loops site.
|
||||
"""
|
||||
contains(IConceptManager, IResourceManager, IViewManager)
|
||||
|
|
|
@ -52,6 +52,9 @@ class Resource(Contained, Persistent):
|
|||
def getContentType(self): return self._contentType
|
||||
contentType = property(getContentType, setContentType)
|
||||
|
||||
def getLoopsRoot(self):
|
||||
return zapi.getParent(self).getLoopsRoot()
|
||||
|
||||
def getClients(self, relationships=None):
|
||||
rels = getRelations(second=self, relationships=relationships)
|
||||
return [r.first for r in rels]
|
||||
|
@ -99,4 +102,7 @@ class ResourceManager(BTreeContainer):
|
|||
|
||||
implements(IResourceManager, ILoopsContained)
|
||||
|
||||
def getLoopsRoot(self):
|
||||
return zapi.getParent(self)
|
||||
|
||||
|
||||
|
|
73
target.py
Normal file
73
target.py
Normal file
|
@ -0,0 +1,73 @@
|
|||
#
|
||||
# Copyright (c) 2006 Helmut Merz helmutm@cy55.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
"""
|
||||
Adapter classes (proxies, in fact), for providing access to concepts and
|
||||
resources e.g. from forms that are called on view/node objects.
|
||||
|
||||
$Id$
|
||||
"""
|
||||
|
||||
from zope.app import zapi
|
||||
from zope.cachedescriptors.property import Lazy
|
||||
from zope.component import adapts
|
||||
from zope.interface import implements
|
||||
|
||||
from loops.interfaces import IResource, IDocument, IMediaAsset
|
||||
from loops.interfaces import IView
|
||||
|
||||
|
||||
class ResourceProxy(object):
|
||||
|
||||
adapts(IView)
|
||||
|
||||
def getTitle(self): return self.target.title
|
||||
def setTitle(self, title): self.title = title
|
||||
title = property(getTitle, setTitle)
|
||||
|
||||
def setContentType(self, contentType):
|
||||
self.target._contentType = contentType
|
||||
def getContentType(self): return self.target.contentType
|
||||
contentType = property(getContentType, setContentType)
|
||||
|
||||
def __init__(self, context):
|
||||
self.context = context
|
||||
|
||||
@Lazy
|
||||
def target(self):
|
||||
return self.context.target
|
||||
|
||||
|
||||
class DocumentProxy(ResourceProxy):
|
||||
|
||||
implements(IDocument)
|
||||
|
||||
def setData(self, data): self.target.data = data
|
||||
def getData(self): return self.target.data
|
||||
data = property(getData, setData)
|
||||
|
||||
|
||||
class MediaAssetProxy(ResourceProxy):
|
||||
|
||||
implements(IMediaAsset)
|
||||
|
||||
def setData(self, data): self.target.data = data
|
||||
def getData(self): return self.target.data
|
||||
data = property(getData, setData)
|
||||
|
||||
|
18
view.py
18
view.py
|
@ -34,7 +34,7 @@ from persistent import Persistent
|
|||
from cybertools.relation import DyadicRelation
|
||||
from cybertools.relation.registry import IRelationsRegistry, getRelations
|
||||
|
||||
from interfaces import IView, INode
|
||||
from interfaces import IView, INode, INodeConfigSchema
|
||||
from interfaces import IViewManager, INodeContained
|
||||
from interfaces import ILoopsContained
|
||||
from util import moveByDelta
|
||||
|
@ -81,6 +81,9 @@ class View(object):
|
|||
self.description = description
|
||||
super(View, self).__init__()
|
||||
|
||||
def getLoopsRoot(self):
|
||||
return zapi.getParent(self).getLoopsRoot()
|
||||
|
||||
|
||||
class Node(View, OrderedContainer):
|
||||
|
||||
|
@ -98,9 +101,6 @@ class Node(View, OrderedContainer):
|
|||
|
||||
contentType = u'zope.source.rest'
|
||||
|
||||
def getLoopsRoot(self):
|
||||
return zapi.getParent(self).getLoopsRoot()
|
||||
|
||||
def getParentNode(self, nodeTypes=None):
|
||||
parent = zapi.getParent(self)
|
||||
while INode.providedBy(parent):
|
||||
|
@ -148,6 +148,7 @@ class TargetRelation(DyadicRelation):
|
|||
""" A relation between a view and another object.
|
||||
"""
|
||||
|
||||
# adapters
|
||||
|
||||
class NodeTraverser(ItemTraverser):
|
||||
|
||||
|
@ -159,3 +160,12 @@ class NodeTraverser(ItemTraverser):
|
|||
return self.context.getLoopsRoot()
|
||||
return super(NodeTraverser, self).publishTraverse(request, name)
|
||||
|
||||
|
||||
class NodeConfigAdapter(object):
|
||||
|
||||
def __init__(self, context):
|
||||
self.context = context
|
||||
|
||||
implements(INodeConfigSchema)
|
||||
adapts(INode)
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue