use composer.schema for form/dialog handling
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@2065 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
effa162a32
commit
46a1638edd
4 changed files with 108 additions and 26 deletions
12
README.txt
12
README.txt
|
@ -651,7 +651,7 @@ on data provided in this form:
|
||||||
>>> note_tc = concepts['note']
|
>>> note_tc = concepts['note']
|
||||||
|
|
||||||
>>> component.provideAdapter(NameChooser)
|
>>> component.provideAdapter(NameChooser)
|
||||||
>>> request = TestRequest(form={'form.title': u'Test Note',
|
>>> request = TestRequest(form={'title': u'Test Note',
|
||||||
... 'form.type': u'.loops/concepts/note'})
|
... 'form.type': u'.loops/concepts/note'})
|
||||||
>>> view = NodeView(m112, request)
|
>>> view = NodeView(m112, request)
|
||||||
>>> cont = CreateObject(view, request)
|
>>> cont = CreateObject(view, request)
|
||||||
|
@ -668,7 +668,7 @@ created object:
|
||||||
>>> from loops import util
|
>>> from loops import util
|
||||||
>>> topicUid = util.getUidForObject(topic)
|
>>> topicUid = util.getUidForObject(topic)
|
||||||
>>> predicateUid = util.getUidForObject(concepts.getDefaultPredicate())
|
>>> predicateUid = util.getUidForObject(concepts.getDefaultPredicate())
|
||||||
>>> request = TestRequest(form={'form.title': u'Test Note',
|
>>> request = TestRequest(form={'title': u'Test Note',
|
||||||
... 'form.type': u'.loops/concepts/note',
|
... 'form.type': u'.loops/concepts/note',
|
||||||
... 'form.assignments.selected':
|
... 'form.assignments.selected':
|
||||||
... [':'.join((topicUid, predicateUid))]})
|
... [':'.join((topicUid, predicateUid))]})
|
||||||
|
@ -711,19 +711,21 @@ The new technique uses the ``fields`` and ``data`` attributes...
|
||||||
>>> for f in view.fields:
|
>>> for f in view.fields:
|
||||||
... print f.name, f.fieldType, f.required, f.vocabulary
|
... print f.name, f.fieldType, f.required, f.vocabulary
|
||||||
title textline True None
|
title textline True None
|
||||||
description textarea False None
|
|
||||||
data textarea False None
|
data textarea False None
|
||||||
contentType dropdown True <...SimpleVocabulary object...>
|
contentType dropdown True <...SimpleVocabulary object...>
|
||||||
linkUrl textline False None
|
linkUrl textline False None
|
||||||
|
|
||||||
>>> view.data
|
>>> view.data
|
||||||
{'linkUrl': None, 'contentType': u'', 'data': '', 'description': '',
|
{'linkUrl': None, 'contentType': u'', 'data': '',
|
||||||
'title': u'Test Note'}
|
'title': u'Test Note'}
|
||||||
|
|
||||||
The object is changed via a FormController adapter created for
|
The object is changed via a FormController adapter created for
|
||||||
a NodeView.
|
a NodeView.
|
||||||
|
|
||||||
>>> request = TestRequest(form={'form.title': u'Test Note - changed'})
|
>>> form = dict(
|
||||||
|
... title=u'Test Note - changed',
|
||||||
|
... contentType=u'text/plain',)
|
||||||
|
>>> request = TestRequest(form=form)
|
||||||
>>> view = NodeView(m112, request)
|
>>> view = NodeView(m112, request)
|
||||||
>>> cont = EditObject(view, request)
|
>>> cont = EditObject(view, request)
|
||||||
>>> cont.update()
|
>>> cont.update()
|
||||||
|
|
111
browser/form.py
111
browser/form.py
|
@ -45,7 +45,7 @@ from cybertools.composer.schema.browser.common import schema_macros, schema_edit
|
||||||
from cybertools.composer.schema.util import getSchemaFromInterface
|
from cybertools.composer.schema.util import getSchemaFromInterface
|
||||||
from cybertools.typology.interfaces import IType, ITypeManager
|
from cybertools.typology.interfaces import IType, ITypeManager
|
||||||
from loops.common import adapted
|
from loops.common import adapted
|
||||||
from loops.concept import ResourceRelation
|
from loops.concept import Concept, ResourceRelation
|
||||||
from loops.interfaces import IConcept, IResourceManager, IDocument
|
from loops.interfaces import IConcept, IResourceManager, IDocument
|
||||||
from loops.interfaces import IFile, IExternalFile, INote, ITextDocument
|
from loops.interfaces import IFile, IExternalFile, INote, ITextDocument
|
||||||
from loops.browser.node import NodeView
|
from loops.browser.node import NodeView
|
||||||
|
@ -107,7 +107,13 @@ class ObjectForm(NodeView):
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def fields(self):
|
def fields(self):
|
||||||
return self.schema.fields
|
fields = self.schema.fields
|
||||||
|
fields.data.height = 10
|
||||||
|
ifc = self.typeInterface
|
||||||
|
if ifc in widgetControllers:
|
||||||
|
wc = widgetControllers[ifc](self.context, self.request)
|
||||||
|
wc.modifySchemaFields(fields)
|
||||||
|
return fields
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def data(self):
|
def data(self):
|
||||||
|
@ -130,7 +136,7 @@ class ObjectForm(NodeView):
|
||||||
def form_fields(self):
|
def form_fields(self):
|
||||||
ifc = self.typeInterface
|
ifc = self.typeInterface
|
||||||
ff = FormFields(ifc)
|
ff = FormFields(ifc)
|
||||||
if self.typeInterface in widgetControllers:
|
if ifc in widgetControllers:
|
||||||
wc = widgetControllers[ifc](self.context, self.request)
|
wc = widgetControllers[ifc](self.context, self.request)
|
||||||
ff = wc.modifyFormFields(ff)
|
ff = wc.modifyFormFields(ff)
|
||||||
return ff
|
return ff
|
||||||
|
@ -194,6 +200,9 @@ class WidgetController(object):
|
||||||
self.context = context
|
self.context = context
|
||||||
self.request = request
|
self.request = request
|
||||||
|
|
||||||
|
def modifySchemaFields(self, fields):
|
||||||
|
pass
|
||||||
|
|
||||||
def modifyFormFields(self, formFields):
|
def modifyFormFields(self, formFields):
|
||||||
return formFields
|
return formFields
|
||||||
|
|
||||||
|
@ -203,6 +212,10 @@ class WidgetController(object):
|
||||||
|
|
||||||
class NoteWidgetController(WidgetController):
|
class NoteWidgetController(WidgetController):
|
||||||
|
|
||||||
|
def modifySchemaFields(self, fields):
|
||||||
|
del fields['description']
|
||||||
|
fields.data.height = 5
|
||||||
|
|
||||||
def modifyFormFields(self, formFields):
|
def modifyFormFields(self, formFields):
|
||||||
return formFields.omit('description')
|
return formFields.omit('description')
|
||||||
|
|
||||||
|
@ -212,6 +225,11 @@ class NoteWidgetController(WidgetController):
|
||||||
|
|
||||||
class FileWidgetController(WidgetController):
|
class FileWidgetController(WidgetController):
|
||||||
|
|
||||||
|
def modifySchemaFields(self, fields):
|
||||||
|
if self.request.principal.id != 'rootadmin':
|
||||||
|
del fields['contentType']
|
||||||
|
|
||||||
|
|
||||||
def modifyFormFields(self, formFields):
|
def modifyFormFields(self, formFields):
|
||||||
if self.request.principal.id == 'rootadmin':
|
if self.request.principal.id == 'rootadmin':
|
||||||
return formFields
|
return formFields
|
||||||
|
@ -289,7 +307,8 @@ class CreateObjectForm(ObjectForm, Form):
|
||||||
class InnerForm(CreateObjectForm):
|
class InnerForm(CreateObjectForm):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def macro(self): return self.template.macros['fields']
|
#def macro(self): return self.template.macros['fields']
|
||||||
|
def macro(self): return self.schemaMacros['fields']
|
||||||
|
|
||||||
|
|
||||||
# processing form input
|
# processing form input
|
||||||
|
@ -302,6 +321,27 @@ class EditObject(FormController):
|
||||||
old = None
|
old = None
|
||||||
selected = None
|
selected = None
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def schema(self):
|
||||||
|
return getSchemaFromInterface(self.typeInterface, manager=self)
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def fields(self):
|
||||||
|
return self.schema.fields
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def instance(self):
|
||||||
|
return component.getAdapter(adapted(self.object), IInstance, name='editor')
|
||||||
|
#return IInstance(adapted(self.object), name='editor')
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def typeInterface(self):
|
||||||
|
return IType(self.object).typeInterface or ITextDocument
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def loopsRoot(self):
|
||||||
|
return self.view.loopsRoot
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
# create new version if necessary
|
# create new version if necessary
|
||||||
target = self.view.virtualTargetObject
|
target = self.view.virtualTargetObject
|
||||||
|
@ -310,20 +350,56 @@ class EditObject(FormController):
|
||||||
# make sure new version is used by the view
|
# make sure new version is used by the view
|
||||||
self.view.virtualTargetObject = obj
|
self.view.virtualTargetObject = obj
|
||||||
self.request.annotations['loops.view']['target'] = obj
|
self.request.annotations['loops.view']['target'] = obj
|
||||||
errors = self.updateFields(obj)
|
self.object = obj
|
||||||
if errors:
|
formState = self.updateFields()
|
||||||
self.view.setUp()
|
# TODO: error handling
|
||||||
for fieldName, message in errors.items():
|
#errors = self.updateFields()
|
||||||
self.view.widgets[fieldName].error = message
|
#if errors:
|
||||||
return True
|
# self.view.setUp()
|
||||||
|
# for fieldName, message in errors.items():
|
||||||
|
# self.view.widgets[fieldName].error = message
|
||||||
|
# return True
|
||||||
self.request.response.redirect(self.view.virtualTargetUrl + '?version=this')
|
self.request.response.redirect(self.view.virtualTargetUrl + '?version=this')
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@Lazy
|
def updateFields(self):
|
||||||
def loopsRoot(self):
|
obj = self.object
|
||||||
return self.view.loopsRoot
|
form = self.request.form
|
||||||
|
instance = self.instance
|
||||||
|
instance.template = self.schema
|
||||||
|
formState = instance.applyTemplate(data=form, fieldHandlers=self.fieldHandlers)
|
||||||
|
for k in form.keys():
|
||||||
|
if k.startswith(self.prefix):
|
||||||
|
fn = k[len(self.prefix):]
|
||||||
|
value = form[k]
|
||||||
|
if fn.startswith(self.conceptPrefix) and value:
|
||||||
|
self.collectConcepts(fn[len(self.conceptPrefix):], value)
|
||||||
|
if self.old or self.selected:
|
||||||
|
self.assignConcepts(obj)
|
||||||
|
notify(ObjectModifiedEvent(obj))
|
||||||
|
return formState
|
||||||
|
|
||||||
def updateFields(self, obj):
|
def handleFileUpload(self, context, value, fieldInstance, formState):
|
||||||
|
""" Special handler for fileupload fields;
|
||||||
|
value is a FileUpload instance.
|
||||||
|
"""
|
||||||
|
filename = getattr(value, 'filename', '')
|
||||||
|
if filename: # ignore if no filename present - no file uploaded
|
||||||
|
value = value.read()
|
||||||
|
contentType = guess_content_type(filename, value[:100])
|
||||||
|
if contentType:
|
||||||
|
ct = contentType[0]
|
||||||
|
self.request.form['form.contentType'] = ct
|
||||||
|
context.contentType = ct
|
||||||
|
setattr(context, fieldInstance.name, value)
|
||||||
|
context.localFilename = filename
|
||||||
|
|
||||||
|
@property
|
||||||
|
def fieldHandlers(self):
|
||||||
|
return dict(fileupload=self.handleFileUpload)
|
||||||
|
|
||||||
|
def xupdateFields(self): # obsolete
|
||||||
|
obj = self.object
|
||||||
errors = {}
|
errors = {}
|
||||||
form = self.request.form
|
form = self.request.form
|
||||||
ti = IType(obj).typeInterface
|
ti = IType(obj).typeInterface
|
||||||
|
@ -407,11 +483,11 @@ class CreateObject(EditObject):
|
||||||
def update(self):
|
def update(self):
|
||||||
form = self.request.form
|
form = self.request.form
|
||||||
container = self.loopsRoot.getResourceManager()
|
container = self.loopsRoot.getResourceManager()
|
||||||
title = form.get('form.title')
|
title = form.get('title')
|
||||||
if not title:
|
if not title:
|
||||||
raise BadRequest('Title field is empty')
|
raise BadRequest('Title field is empty')
|
||||||
obj = Resource(title)
|
obj = Resource(title)
|
||||||
data = form.get('form.data')
|
data = form.get('data')
|
||||||
if data and isinstance(data, FileUpload):
|
if data and isinstance(data, FileUpload):
|
||||||
name = getattr(data, 'filename', None)
|
name = getattr(data, 'filename', None)
|
||||||
# strip path from IE uploads:
|
# strip path from IE uploads:
|
||||||
|
@ -424,7 +500,8 @@ class CreateObject(EditObject):
|
||||||
tc = form.get('form.type') or '.loops/concepts/note'
|
tc = form.get('form.type') or '.loops/concepts/note'
|
||||||
obj.resourceType = self.loopsRoot.loopsTraverse(tc)
|
obj.resourceType = self.loopsRoot.loopsTraverse(tc)
|
||||||
notify(ObjectCreatedEvent(obj))
|
notify(ObjectCreatedEvent(obj))
|
||||||
self.updateFields(obj)
|
self.object = obj
|
||||||
|
self.updateFields()
|
||||||
self.request.response.redirect(self.view.virtualTargetUrl)
|
self.request.response.redirect(self.view.virtualTargetUrl)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
|
@ -14,10 +14,10 @@
|
||||||
</span>
|
</span>
|
||||||
</th></tr></tbody>
|
</th></tr></tbody>
|
||||||
|
|
||||||
<tbody><tr><td colspan="5">
|
<tbody><tr><td colspan="5" style="padding-right: 15px">
|
||||||
<div id="form.fields">
|
<div id="form.fields">
|
||||||
<metal:fields use-macro="view/template/macros/fields" />
|
<!--<metal:fields use-macro="view/template/macros/fields" />-->
|
||||||
<!--<metal:fields use-macro="view/schemaMacros/fields" />-->
|
<metal:fields use-macro="view/schemaMacros/fields" />
|
||||||
</div>
|
</div>
|
||||||
</td></tr></tbody>
|
</td></tr></tbody>
|
||||||
|
|
||||||
|
@ -64,7 +64,8 @@
|
||||||
|
|
||||||
<tbody><tr><td colspan="5">
|
<tbody><tr><td colspan="5">
|
||||||
<div id="form.fields">
|
<div id="form.fields">
|
||||||
<metal:fields use-macro="view/template/macros/fields" />
|
<!--<metal:fields use-macro="view/template/macros/fields" />-->
|
||||||
|
<metal:fields use-macro="view/schemaMacros/fields" />
|
||||||
</div>
|
</div>
|
||||||
</td></tr></tbody>
|
</td></tr></tbody>
|
||||||
|
|
||||||
|
|
|
@ -399,6 +399,8 @@
|
||||||
<adapter factory="cybertools.composer.schema.field.FieldInstance" />
|
<adapter factory="cybertools.composer.schema.field.FieldInstance" />
|
||||||
<adapter factory="cybertools.composer.schema.field.NumberFieldInstance"
|
<adapter factory="cybertools.composer.schema.field.NumberFieldInstance"
|
||||||
name="number" />
|
name="number" />
|
||||||
|
<adapter factory="cybertools.composer.schema.field.FileUploadFieldInstance"
|
||||||
|
name="fileupload" />
|
||||||
|
|
||||||
|
|
||||||
<adapter factory="loops.setup.SetupManager" />
|
<adapter factory="loops.setup.SetupManager" />
|
||||||
|
|
Loading…
Add table
Reference in a new issue