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']
|
||||
|
||||
>>> component.provideAdapter(NameChooser)
|
||||
>>> request = TestRequest(form={'form.title': u'Test Note',
|
||||
>>> request = TestRequest(form={'title': u'Test Note',
|
||||
... 'form.type': u'.loops/concepts/note'})
|
||||
>>> view = NodeView(m112, request)
|
||||
>>> cont = CreateObject(view, request)
|
||||
|
@ -668,7 +668,7 @@ created object:
|
|||
>>> from loops import util
|
||||
>>> topicUid = util.getUidForObject(topic)
|
||||
>>> 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.assignments.selected':
|
||||
... [':'.join((topicUid, predicateUid))]})
|
||||
|
@ -711,19 +711,21 @@ The new technique uses the ``fields`` and ``data`` attributes...
|
|||
>>> for f in view.fields:
|
||||
... print f.name, f.fieldType, f.required, f.vocabulary
|
||||
title textline True None
|
||||
description textarea False None
|
||||
data textarea False None
|
||||
contentType dropdown True <...SimpleVocabulary object...>
|
||||
linkUrl textline False None
|
||||
|
||||
>>> view.data
|
||||
{'linkUrl': None, 'contentType': u'', 'data': '', 'description': '',
|
||||
{'linkUrl': None, 'contentType': u'', 'data': '',
|
||||
'title': u'Test Note'}
|
||||
|
||||
The object is changed via a FormController adapter created for
|
||||
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)
|
||||
>>> cont = EditObject(view, request)
|
||||
>>> 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.typology.interfaces import IType, ITypeManager
|
||||
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 IFile, IExternalFile, INote, ITextDocument
|
||||
from loops.browser.node import NodeView
|
||||
|
@ -107,7 +107,13 @@ class ObjectForm(NodeView):
|
|||
|
||||
@Lazy
|
||||
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
|
||||
def data(self):
|
||||
|
@ -130,7 +136,7 @@ class ObjectForm(NodeView):
|
|||
def form_fields(self):
|
||||
ifc = self.typeInterface
|
||||
ff = FormFields(ifc)
|
||||
if self.typeInterface in widgetControllers:
|
||||
if ifc in widgetControllers:
|
||||
wc = widgetControllers[ifc](self.context, self.request)
|
||||
ff = wc.modifyFormFields(ff)
|
||||
return ff
|
||||
|
@ -194,6 +200,9 @@ class WidgetController(object):
|
|||
self.context = context
|
||||
self.request = request
|
||||
|
||||
def modifySchemaFields(self, fields):
|
||||
pass
|
||||
|
||||
def modifyFormFields(self, formFields):
|
||||
return formFields
|
||||
|
||||
|
@ -203,6 +212,10 @@ class WidgetController(object):
|
|||
|
||||
class NoteWidgetController(WidgetController):
|
||||
|
||||
def modifySchemaFields(self, fields):
|
||||
del fields['description']
|
||||
fields.data.height = 5
|
||||
|
||||
def modifyFormFields(self, formFields):
|
||||
return formFields.omit('description')
|
||||
|
||||
|
@ -212,6 +225,11 @@ class NoteWidgetController(WidgetController):
|
|||
|
||||
class FileWidgetController(WidgetController):
|
||||
|
||||
def modifySchemaFields(self, fields):
|
||||
if self.request.principal.id != 'rootadmin':
|
||||
del fields['contentType']
|
||||
|
||||
|
||||
def modifyFormFields(self, formFields):
|
||||
if self.request.principal.id == 'rootadmin':
|
||||
return formFields
|
||||
|
@ -289,7 +307,8 @@ class CreateObjectForm(ObjectForm, Form):
|
|||
class InnerForm(CreateObjectForm):
|
||||
|
||||
@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
|
||||
|
@ -302,6 +321,27 @@ class EditObject(FormController):
|
|||
old = 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):
|
||||
# create new version if necessary
|
||||
target = self.view.virtualTargetObject
|
||||
|
@ -310,20 +350,56 @@ class EditObject(FormController):
|
|||
# make sure new version is used by the view
|
||||
self.view.virtualTargetObject = obj
|
||||
self.request.annotations['loops.view']['target'] = obj
|
||||
errors = self.updateFields(obj)
|
||||
if errors:
|
||||
self.view.setUp()
|
||||
for fieldName, message in errors.items():
|
||||
self.view.widgets[fieldName].error = message
|
||||
return True
|
||||
self.object = obj
|
||||
formState = self.updateFields()
|
||||
# TODO: error handling
|
||||
#errors = self.updateFields()
|
||||
#if errors:
|
||||
# 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')
|
||||
return False
|
||||
|
||||
@Lazy
|
||||
def loopsRoot(self):
|
||||
return self.view.loopsRoot
|
||||
def updateFields(self):
|
||||
obj = self.object
|
||||
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 = {}
|
||||
form = self.request.form
|
||||
ti = IType(obj).typeInterface
|
||||
|
@ -407,11 +483,11 @@ class CreateObject(EditObject):
|
|||
def update(self):
|
||||
form = self.request.form
|
||||
container = self.loopsRoot.getResourceManager()
|
||||
title = form.get('form.title')
|
||||
title = form.get('title')
|
||||
if not title:
|
||||
raise BadRequest('Title field is empty')
|
||||
obj = Resource(title)
|
||||
data = form.get('form.data')
|
||||
data = form.get('data')
|
||||
if data and isinstance(data, FileUpload):
|
||||
name = getattr(data, 'filename', None)
|
||||
# strip path from IE uploads:
|
||||
|
@ -424,7 +500,8 @@ class CreateObject(EditObject):
|
|||
tc = form.get('form.type') or '.loops/concepts/note'
|
||||
obj.resourceType = self.loopsRoot.loopsTraverse(tc)
|
||||
notify(ObjectCreatedEvent(obj))
|
||||
self.updateFields(obj)
|
||||
self.object = obj
|
||||
self.updateFields()
|
||||
self.request.response.redirect(self.view.virtualTargetUrl)
|
||||
return False
|
||||
|
||||
|
|
|
@ -14,10 +14,10 @@
|
|||
</span>
|
||||
</th></tr></tbody>
|
||||
|
||||
<tbody><tr><td colspan="5">
|
||||
<tbody><tr><td colspan="5" style="padding-right: 15px">
|
||||
<div id="form.fields">
|
||||
<metal:fields use-macro="view/template/macros/fields" />
|
||||
<!--<metal:fields use-macro="view/schemaMacros/fields" />-->
|
||||
<!--<metal:fields use-macro="view/template/macros/fields" />-->
|
||||
<metal:fields use-macro="view/schemaMacros/fields" />
|
||||
</div>
|
||||
</td></tr></tbody>
|
||||
|
||||
|
@ -64,7 +64,8 @@
|
|||
|
||||
<tbody><tr><td colspan="5">
|
||||
<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>
|
||||
</td></tr></tbody>
|
||||
|
||||
|
|
|
@ -399,6 +399,8 @@
|
|||
<adapter factory="cybertools.composer.schema.field.FieldInstance" />
|
||||
<adapter factory="cybertools.composer.schema.field.NumberFieldInstance"
|
||||
name="number" />
|
||||
<adapter factory="cybertools.composer.schema.field.FileUploadFieldInstance"
|
||||
name="fileupload" />
|
||||
|
||||
|
||||
<adapter factory="loops.setup.SetupManager" />
|
||||
|
|
Loading…
Add table
Reference in a new issue