provide preset concept lists (via type option qualifier:assign) for create and edit dialog
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1616 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
d44b721a89
commit
483a730c6c
3 changed files with 80 additions and 5 deletions
41
README.txt
41
README.txt
|
@ -608,6 +608,45 @@ Creating an object
|
||||||
>>> from loops.browser.form import CreateObjectForm, CreateObject
|
>>> from loops.browser.form import CreateObjectForm, CreateObject
|
||||||
>>> form = CreateObjectForm(m112, TestRequest())
|
>>> form = CreateObjectForm(m112, TestRequest())
|
||||||
|
|
||||||
|
The form provides a set of data entry fields derived from the interface
|
||||||
|
associated with the new object's resource (or concept) type.
|
||||||
|
|
||||||
|
In addition it allows to assign concepts as parents to the object. Beside
|
||||||
|
an integrated free search for concepts to assign there may be a list of
|
||||||
|
preset concepts, e.g. depending on the target of the current node:
|
||||||
|
|
||||||
|
>>> form.assignments
|
||||||
|
()
|
||||||
|
>>> m112.target = cc1
|
||||||
|
>>> form = CreateObjectForm(m112, TestRequest())
|
||||||
|
>>> form.assignments
|
||||||
|
(<...ConceptRelationView object ...>,)
|
||||||
|
|
||||||
|
There also may be preset concept types that directly provide lists of
|
||||||
|
concepts to select from.
|
||||||
|
|
||||||
|
To show this let's start with a new type, the customer type.
|
||||||
|
|
||||||
|
>>> customer = concepts['customer'] = Concept('Customer')
|
||||||
|
>>> customer.conceptType = concepts.getTypeConcept()
|
||||||
|
>>> from loops.type import ConceptType, TypeConcept
|
||||||
|
>>> custType = TypeConcept(customer)
|
||||||
|
>>> custType.options
|
||||||
|
[]
|
||||||
|
>>> cust1 = concepts['cust1'] = Concept(u'Zope Corporation')
|
||||||
|
>>> cust2 = concepts['cust2'] = Concept(u'cyberconcepts')
|
||||||
|
>>> for c in (cust1, cust2): c.conceptType = customer
|
||||||
|
>>> custType.options = ('qualifier:assign',)
|
||||||
|
>>> ConceptType(cust1).qualifiers
|
||||||
|
('concept', 'assign')
|
||||||
|
|
||||||
|
>>> form = CreateObjectForm(m112, TestRequest())
|
||||||
|
>>> form.presetTypesForAssignment
|
||||||
|
[{'token': 'loops:concept:customer', 'title': 'Customer'}]
|
||||||
|
|
||||||
|
OK, so much about the form - now we want to create a new object based
|
||||||
|
on data provided in this form:
|
||||||
|
|
||||||
>>> from loops.interfaces import INote, ITypeConcept
|
>>> from loops.interfaces import INote, ITypeConcept
|
||||||
>>> from loops.type import TypeConcept
|
>>> from loops.type import TypeConcept
|
||||||
>>> from loops.resource import NoteAdapter
|
>>> from loops.resource import NoteAdapter
|
||||||
|
@ -708,7 +747,7 @@ target object's view here:
|
||||||
[<loops.browser.common.Action object ...>]
|
[<loops.browser.common.Action object ...>]
|
||||||
>>> action = view.virtualTarget.getActions()[0]
|
>>> action = view.virtualTarget.getActions()[0]
|
||||||
>>> action.url
|
>>> action.url
|
||||||
'http://127.0.0.1/loops/views/m1/m11/m111/.target16'
|
'http://127.0.0.1/loops/views/m1/m11/m111/.target19'
|
||||||
|
|
||||||
|
|
||||||
Import/Export
|
Import/Export
|
||||||
|
|
|
@ -40,12 +40,13 @@ from zope.security.proxy import isinstance
|
||||||
|
|
||||||
from cybertools.ajax import innerHtml
|
from cybertools.ajax import innerHtml
|
||||||
from cybertools.browser.form import FormController
|
from cybertools.browser.form import FormController
|
||||||
from cybertools.typology.interfaces import IType
|
from cybertools.typology.interfaces import IType, ITypeManager
|
||||||
from loops.concept import ResourceRelation
|
from loops.concept import ResourceRelation
|
||||||
from loops.interfaces import IConcept, IResourceManager, IDocument
|
from loops.interfaces import IConcept, IResourceManager, IDocument
|
||||||
from loops.interfaces import IFile, IExternalFile, INote
|
from loops.interfaces import IFile, IExternalFile, INote
|
||||||
from loops.browser.node import NodeView
|
from loops.browser.node import NodeView
|
||||||
from loops.browser.concept import ConceptRelationView
|
from loops.browser.concept import ConceptRelationView
|
||||||
|
from loops.query import ConceptQuery
|
||||||
from loops.resource import Resource
|
from loops.resource import Resource
|
||||||
from loops.type import ITypeConcept
|
from loops.type import ITypeConcept
|
||||||
from loops import util
|
from loops import util
|
||||||
|
@ -98,8 +99,27 @@ class ObjectForm(NodeView):
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def defaultPredicate(self):
|
def defaultPredicate(self):
|
||||||
return util.getUidForObject(
|
return self.loopsRoot.getConceptManager().getDefaultPredicate()
|
||||||
self.loopsRoot.getConceptManager().getDefaultPredicate())
|
|
||||||
|
@Lazy
|
||||||
|
def typeManager(self):
|
||||||
|
return ITypeManager(self.context)
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def presetTypesForAssignment(self):
|
||||||
|
types = list(self.typeManager.listTypes(include=('assign',)))
|
||||||
|
assigned = [r.context.conceptType for r in self.assignments]
|
||||||
|
types = [t for t in types if t.typeProvider not in assigned]
|
||||||
|
return [dict(title=t.title, token=t.tokenForSearch) for t in types]
|
||||||
|
|
||||||
|
def conceptsForType(self, token):
|
||||||
|
noSelection = dict(token='none', title=u'not selected')
|
||||||
|
result = sorted(ConceptQuery(self).query(type=token), key=lambda x: x.title)
|
||||||
|
predicateUid = util.getUidForObject(self.defaultPredicate)
|
||||||
|
return ([noSelection] +
|
||||||
|
[dict(title=o.title,
|
||||||
|
token='%s:%s' % (util.getUidForObject(o), predicateUid))
|
||||||
|
for o in result])
|
||||||
|
|
||||||
|
|
||||||
class WidgetController(object):
|
class WidgetController(object):
|
||||||
|
@ -241,6 +261,9 @@ class EditObject(FormController):
|
||||||
if fn.startswith(self.conceptPrefix) and value:
|
if fn.startswith(self.conceptPrefix) and value:
|
||||||
self.collectConcepts(fn[len(self.conceptPrefix):], value)
|
self.collectConcepts(fn[len(self.conceptPrefix):], value)
|
||||||
else:
|
else:
|
||||||
|
if not value and fn == 'data' and IFile.providedBy(adapted):
|
||||||
|
# empty file data - don' change
|
||||||
|
continue
|
||||||
if isinstance(value, FileUpload):
|
if isinstance(value, FileUpload):
|
||||||
filename = getattr(value, 'filename', '')
|
filename = getattr(value, 'filename', '')
|
||||||
value = value.read()
|
value = value.read()
|
||||||
|
@ -273,7 +296,7 @@ class EditObject(FormController):
|
||||||
predicate = util.getObjectForUid(p)
|
predicate = util.getObjectForUid(p)
|
||||||
obj.deassignConcept(concept, [predicate])
|
obj.deassignConcept(concept, [predicate])
|
||||||
for v in self.selected:
|
for v in self.selected:
|
||||||
if v not in self.old:
|
if v != 'none' and v not in self.old:
|
||||||
c, p = v.split(':')
|
c, p = v.split(':')
|
||||||
concept = util.getObjectForUid(c)
|
concept = util.getObjectForUid(c)
|
||||||
predicate = util.getObjectForUid(p)
|
predicate = util.getObjectForUid(p)
|
||||||
|
|
|
@ -105,6 +105,19 @@
|
||||||
|
|
||||||
<metal:assignments define-macro="assignments">
|
<metal:assignments define-macro="assignments">
|
||||||
<tbody id="form.assignments">
|
<tbody id="form.assignments">
|
||||||
|
<tr tal:repeat="type view/presetTypesForAssignment">
|
||||||
|
<td><span i18n:translate="">Type: </span></td>
|
||||||
|
<td><b tal:content="type/title" /></td>
|
||||||
|
<td><span i18n:translate="">Select value: </span></td>
|
||||||
|
<td colspan="2">
|
||||||
|
<select name="form.assignments.selected:list">
|
||||||
|
<tal:concepts repeat="concept python: view.conceptsForType(type['token'])">
|
||||||
|
<option tal:attributes="value concept/token"
|
||||||
|
tal:content="concept/title">Zope Corp</option>
|
||||||
|
</tal:concepts>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr tal:repeat="relation view/assignments">
|
<tr tal:repeat="relation view/assignments">
|
||||||
<td colspan="5">
|
<td colspan="5">
|
||||||
<input type="hidden" name="form.assignments.old:list"
|
<input type="hidden" name="form.assignments.old:list"
|
||||||
|
|
Loading…
Add table
Reference in a new issue