provide implementation for relation set and relation field types

git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@3184 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2009-01-27 16:35:05 +00:00
parent 87cb629f1c
commit 40b8182f06
9 changed files with 118 additions and 31 deletions

View file

@ -603,16 +603,14 @@
for="loops.browser.node.NodeView for="loops.browser.node.NodeView
zope.publisher.interfaces.browser.IBrowserRequest" zope.publisher.interfaces.browser.IBrowserRequest"
factory="loops.browser.form.CreateConcept" factory="loops.browser.form.CreateConcept"
permission="zope.ManageContent" permission="zope.ManageContent" />
/>
<zope:adapter <zope:adapter
name="edit_concept" name="edit_concept"
for="loops.browser.node.NodeView for="loops.browser.node.NodeView
zope.publisher.interfaces.browser.IBrowserRequest" zope.publisher.interfaces.browser.IBrowserRequest"
factory="loops.browser.form.EditConcept" factory="loops.browser.form.EditConcept"
permission="zope.ManageContent" permission="zope.ManageContent" />
/>
<!-- inner HTML views --> <!-- inner HTML views -->

View file

@ -1,5 +1,5 @@
# #
# Copyright (c) 2008 Helmut Merz helmutm@cy55.de # Copyright (c) 2009 Helmut Merz helmutm@cy55.de
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
@ -115,6 +115,7 @@ class ObjectForm(NodeView):
renderers['input_html'] = self.template.macros['input_html'] renderers['input_html'] = self.template.macros['input_html']
renderers['input_grid'] = grid_macros.macros['input_grid'] renderers['input_grid'] = grid_macros.macros['input_grid']
renderers['input_relationset'] = relation_macros.macros['input_relationset'] renderers['input_relationset'] = relation_macros.macros['input_relationset']
renderers['input_relation'] = relation_macros.macros['input_relation']
return renderers return renderers
@Lazy @Lazy
@ -397,8 +398,7 @@ class CreateConceptPage(CreateConceptForm):
@Lazy @Lazy
def nextUrl(self): def nextUrl(self):
#return self.nodeView.getUrlForTarget(self.context) return self.getUrlForTarget(self.virtualTargetObject)
return self.getUrlForTarget(self.context)
class InnerForm(CreateObjectForm): class InnerForm(CreateObjectForm):

View file

@ -189,8 +189,6 @@
</metal:assignments> </metal:assignments>
<metal:versioning define-macro="versioning" <metal:versioning define-macro="versioning"
tal:define="versionInfo view/versionInfo" tal:define="versionInfo view/versionInfo"
tal:condition="versionInfo"> tal:condition="versionInfo">

View file

@ -147,11 +147,26 @@ function addRelation(fieldName) {
valuesNode = dojo.byId(fieldName + '_values'); valuesNode = dojo.byId(fieldName + '_values');
widget = dijit.byId(fieldName + '_search'); widget = dijit.byId(fieldName + '_search');
token = widget.getValue(); token = widget.getValue();
if (token) {
title = widget.getDisplayedValue(); title = widget.getDisplayedValue();
ih = '<input type="checkbox" name="' + name + ':list" value="' + token + '" checked> <span>' + title + '</span>'; ih = '<div><input type="checkbox" name="' + fieldName + ':list" value="' + token + '" checked> <span>' + title + '</span></div>';
newNode = document.createElement('div'); newNode = document.createElement('div');
newNode.innerHTML = ih; newNode.innerHTML = ih;
valuesNode.appendChild(newNode); valuesNode.appendChild(newNode);
}
}
function setRelation(fieldName) {
valuesNode = dojo.byId(fieldName + '_values');
widget = dijit.byId(fieldName + '_search');
token = widget.getValue();
if (token) {
title = widget.getDisplayedValue();
ih = '<div><input type="checkbox" name="' + fieldName + '" value="' + token + '" checked> <span>' + title + '</span></div>';
newNode = document.createElement('div');
newNode.innerHTML = ih;
valuesNode.replaceChild(newNode, valuesNode.firstChild);
}
} }
function validate() { function validate() {

View file

@ -387,6 +387,16 @@ class RelationSetProperty(object):
return self return self
return self.factory(inst, self.predicateName) return self.factory(inst, self.predicateName)
def __set__(self, inst, value):
rs = self.factory(inst, self.predicateName)
current = list(rs)
for c in current:
if c not in value:
rs.remove(c)
for v in value:
if v not in current:
rs.add(v)
class ParentRelationSetProperty(RelationSetProperty): class ParentRelationSetProperty(RelationSetProperty):

View file

@ -345,6 +345,8 @@
name="grid" /> name="grid" />
<adapter factory="loops.schema.field.RelationSetFieldInstance" <adapter factory="loops.schema.field.RelationSetFieldInstance"
name="relationset" /> name="relationset" />
<adapter factory="loops.schema.field.RelationFieldInstance"
name="relation" />
<adapter factory="cybertools.composer.schema.factory.SchemaFactory" /> <adapter factory="cybertools.composer.schema.factory.SchemaFactory" />
<adapter factory="loops.schema.factory.ResourceSchemaFactory" /> <adapter factory="loops.schema.factory.ResourceSchemaFactory" />

View file

@ -24,13 +24,13 @@ $Id$
from zope.component import adapts from zope.component import adapts
from zope.interface import Attribute, implements from zope.interface import Attribute, implements
from zope.schema import Choice, List from zope.schema import Field, List
from zope.schema.interfaces import IChoice, IList from zope.schema.interfaces import IField, IList
from cybertools.composer.schema.interfaces import FieldType from cybertools.composer.schema.interfaces import FieldType
class IRelation(IChoice): class IRelation(IField):
""" An object addressed via a single relation. """ An object addressed via a single relation.
""" """
@ -50,11 +50,14 @@ class IRelationSet(IList):
'targets for the relations.') 'targets for the relations.')
class Relation(Choice): class Relation(Field):
implements(IRelation) implements(IRelation)
__typeInfo__ = ('relation',) __typeInfo__ = ('relation',
FieldType('relation', 'relation',
u'A field representing a related object.',
instanceName='relation'))
def __init__(self, *args, **kw): def __init__(self, *args, **kw):
self.target_types = kw.pop('target_types') self.target_types = kw.pop('target_types')

View file

@ -28,9 +28,10 @@ from zope.interface import implements
from zope.app.pagetemplate import ViewPageTemplateFile from zope.app.pagetemplate import ViewPageTemplateFile
from zope.cachedescriptors.property import Lazy from zope.cachedescriptors.property import Lazy
import zope.schema import zope.schema
from zope.traversing.api import getName
from cybertools.composer.schema.factory import createField from cybertools.composer.schema.factory import createField
from cybertools.composer.schema.field import ListFieldInstance from cybertools.composer.schema.field import FieldInstance, ListFieldInstance
from cybertools.composer.schema.interfaces import IField, IFieldInstance from cybertools.composer.schema.interfaces import IField, IFieldInstance
from cybertools.composer.schema.interfaces import fieldTypes, undefined from cybertools.composer.schema.interfaces import fieldTypes, undefined
from cybertools.util.format import toStr, toUnicode from cybertools.util.format import toStr, toUnicode
@ -41,17 +42,7 @@ from loops import util
relation_macros = ViewPageTemplateFile('relation_macros.pt') relation_macros = ViewPageTemplateFile('relation_macros.pt')
class RelationSetFieldInstance(ListFieldInstance): class BaseRelationFieldInstance(object):
def marshall(self, value):
return [dict(title=v.title, uid=util.getUidForObject(v.context))
for v in value]
def display(self, value):
return value
def unmarshall(self, value):
return value
@Lazy @Lazy
def typesParams(self): def typesParams(self):
@ -62,3 +53,40 @@ class RelationSetFieldInstance(ListFieldInstance):
if result: if result:
return '?' + '&'.join(result) return '?' + '&'.join(result)
return '' return ''
def getPresetTargets(self, view):
if view.adapted.__is_dummy__:
# only for object in creation
target = view.virtualTargetObject
if getName(target.conceptType) in self.context.target_types:
return [dict(title=target.title, uid=util.getUidForObject(target))]
return []
class RelationSetFieldInstance(ListFieldInstance, BaseRelationFieldInstance):
def marshall(self, value):
return [dict(title=v.title, uid=util.getUidForObject(v.context))
for v in value]
def display(self, value):
return ' | '.join([v.title for v in value])
def unmarshall(self, value):
return [util.getObjectForUid(v) for v in value]
class RelationFieldInstance(FieldInstance, BaseRelationFieldInstance):
def marshall(self, value):
if value:
return dict(title=value.title, uid=util.getUidForObject(value))
def display(self, value):
if value:
return value.title
return u''
def unmarshall(self, value):
return util.getObjectForUid(value)

View file

@ -17,6 +17,13 @@
value obj/uid" /> value obj/uid" />
<span tal:content="obj/title" /> <span tal:content="obj/title" />
</div> </div>
<div tal:repeat="obj python:
fieldInstance.getPresetTargets(view)">
<input type="checkbox" checked
tal:attributes="name string:$name:list;
value obj/uid" />
<span tal:content="obj/title" />
</div>
</div> </div>
<input dojoType="dijit.form.FilteringSelect" <input dojoType="dijit.form.FilteringSelect"
autoComplete="False" labelAttr="label" autoComplete="False" labelAttr="label"
@ -27,5 +34,31 @@
</metal:textline> </metal:textline>
<metal:textline define-macro="input_relation"
tal:define="fieldInstance field/getFieldInstance;
types fieldInstance/typesParams">
<div dojoType="dojox.data.QueryReadStore" jsId="conceptSearch"
tal:attributes="url string:listConceptsForComboBox.js$types;
jsId string:${name}_search_store" >
</div>
<div tal:define="obj data/?name"
tal:attributes="id string:${name}_values"><div>
<tal:block tal:condition="obj">
<input type="checkbox" checked
tal:attributes="name string:$name;
value obj/uid" />
<span tal:content="obj/title" />
</tal:block>
</div>
</div>
<input dojoType="dijit.form.FilteringSelect"
autoComplete="False" labelAttr="label"
tal:attributes="store string:${name}_search_store;
name string:${name}_search;
id string:${name}_search;
onChange string:setRelation('$name')" />
</metal:textline>
</body> </body>
</html> </html>