diff --git a/README.txt b/README.txt
index 7323476..c869943 100755
--- a/README.txt
+++ b/README.txt
@@ -232,8 +232,16 @@ Targets
-------
We can associate a node with a concept or directly with a resource via the
-view class's target attribute:
+view class's target attribute. (We also have to supply a subscriber to
+IRelationInvalidatedEvent to make sure associated actions will be carried
+out - this is usually done through ZCML.)
+ >>> from loops.util import removeTargetRelation
+ >>> from loops.interfaces import ITargetRelation
+ >>> from cybertools.relation.interfaces import IRelationInvalidatedEvent
+ >>> ztapi.subscribe([ITargetRelation, IRelationInvalidatedEvent], None,
+ ... removeTargetRelation)
+
>>> m111.target = cc1
>>> m111.target is cc1
True
@@ -351,6 +359,22 @@ edit form provided by the node:
>>> resources['ma07'].title
u'Set via proxy'
+If the target object is removed from its container all references
+to it are removed as well. (To make this work we have to handle
+the IObjectRemovedEvent; this is usually done via ZCML in the
+cybertools.relation package.)
+
+ >>> from zope.app.container.interfaces import IObjectRemovedEvent
+ >>> from zope.interface import Interface
+ >>> from cybertools.relation.registry import invalidateRelations
+ >>> ztapi.subscribe([Interface, IObjectRemovedEvent], None,
+ ... invalidateRelations)
+
+ >>> del resources['ma07']
+ >>> m111.target
+ >>> IMediaAssetView.providedBy(m111)
+ False
+
Ordering Nodes
--------------
diff --git a/browser/configure.zcml b/browser/configure.zcml
index b91c17c..7e4a2f6 100644
--- a/browser/configure.zcml
+++ b/browser/configure.zcml
@@ -251,6 +251,13 @@
add="zope.ManageContent"
/>
+
+
+ menu="zmi_views" title="Edit Node">
diff --git a/configure.zcml b/configure.zcml
index 4e69e35..e20a883 100644
--- a/configure.zcml
+++ b/configure.zcml
@@ -5,7 +5,15 @@
i18n_domain="zope"
>
-
+
+
+
+
+
diff --git a/interfaces.py b/interfaces.py
index 8fb8075..5f99c7c 100644
--- a/interfaces.py
+++ b/interfaces.py
@@ -29,11 +29,12 @@ from zope.app.container.constraints import contains, containers
from zope.app.container.interfaces import IContainer, IOrderedContainer
from zope.app.file.interfaces import IImage as IBaseAsset
from zope.app.folder.interfaces import IFolder
+from cybertools.relation.interfaces import IRelation
_ = MessageFactory('loops')
-# common top-level
+# common interfaces
class ILoopsObject(Interface):
""" Common top-level interface.
@@ -56,6 +57,7 @@ class IPotentialTarget(Interface):
'used as a target for a view/node (and '
'typically specifying the corresponding schema')
+
# concept interfaces
class IConcept(ILoopsObject, IPotentialTarget):
@@ -335,6 +337,12 @@ class INodeConfigSchema(INode, ITargetProperties):
required=False)
+class ITargetRelation(IRelation):
+ """ (Marker) interfaces for relations pointing to a target
+ of a view or node.
+ """
+
+
# the loops top-level container
class ILoops(ILoopsObject, IFolder):
@@ -350,4 +358,3 @@ class ILoops(ILoopsObject, IFolder):
class ILoopsContained(Interface):
containers(ILoops)
-
\ No newline at end of file
diff --git a/util.py b/util.py
index 8ea2d27..a72ed06 100644
--- a/util.py
+++ b/util.py
@@ -22,9 +22,21 @@ Utility functions.
$Id$
"""
+from zope.interface import directlyProvides, directlyProvidedBy
+from view import TargetRelation
+
+
+def removeTargetRelation(context, event):
+ """ Handles IRelationInvalidatedEvent by doing some cleanup work.
+ """
+ targetIfc = context.second.proxyInterface
+ if targetIfc:
+ directlyProvides(context.first, directlyProvidedBy(context) - targetIfc)
+
+
def nl2br(text):
if not text: return text
if '\n' in text: # Unix or DOS line endings
return '
\n'.join(x.replace('\r', '') for x in text.split('\n'))
- else: # gracefully handle Mac line endigns
+ else: # gracefully handle Mac line endings
return '
\n'.join(text.split('\r'))
diff --git a/view.py b/view.py
index d6b23bc..5c4714c 100644
--- a/view.py
+++ b/view.py
@@ -40,6 +40,7 @@ from cybertools.relation.registry import IRelationsRegistry, getRelations
from interfaces import IView, INode, INodeConfigSchema
from interfaces import IViewManager, INodeContained
from interfaces import ILoopsContained
+from interfaces import ITargetRelation
class View(object):
@@ -74,8 +75,6 @@ class View(object):
return
else:
registry.unregister(oldRel)
- oldTargetSchema = oldRel.second.proxyInterface
- directlyProvides(self, directlyProvidedBy(self) - oldTargetSchema)
if target:
targetSchema = target.proxyInterface
@@ -157,8 +156,10 @@ class ViewManager(OrderedContainer):
class TargetRelation(DyadicRelation):
- """ A relation between a view and another object.
+ """ A relation between a view and its target.
"""
+ implements(ITargetRelation)
+
# adapters