use new SchemaFactory for fine-grained control of field properties
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@2080 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
c2807ce730
commit
5fd6f75a60
6 changed files with 107 additions and 168 deletions
|
@ -580,14 +580,6 @@
|
|||
permission="zope.ManageContent"
|
||||
/>
|
||||
|
||||
<zope:view
|
||||
type="zope.publisher.interfaces.browser.IBrowserRequest"
|
||||
for="loops.interfaces.IFile"
|
||||
provides="zope.app.form.interfaces.IInputWidget"
|
||||
factory="loops.browser.form.UploadWidget"
|
||||
permission="zope.Public"
|
||||
/>
|
||||
|
||||
<!-- inner HTML views -->
|
||||
|
||||
<page
|
||||
|
|
188
browser/form.py
188
browser/form.py
|
@ -41,8 +41,8 @@ from zope.security.proxy import isinstance, removeSecurityProxy
|
|||
from cybertools.ajax import innerHtml
|
||||
from cybertools.browser.form import FormController
|
||||
from cybertools.composer.interfaces import IInstance
|
||||
from cybertools.composer.schema.interfaces import ISchemaFactory
|
||||
from cybertools.composer.schema.browser.common import schema_macros, schema_edit_macros
|
||||
from cybertools.composer.schema.util import getSchemaFromInterface
|
||||
from cybertools.typology.interfaces import IType, ITypeManager
|
||||
from loops.common import adapted
|
||||
from loops.concept import Concept, ResourceRelation
|
||||
|
@ -58,26 +58,6 @@ from loops.util import _
|
|||
from loops.versioning.interfaces import IVersionable
|
||||
|
||||
|
||||
# special widgets
|
||||
|
||||
class UploadWidget(FileWidget):
|
||||
|
||||
def _toFieldValue(self, input):
|
||||
# not used at the moment as the context object is updated
|
||||
# via EditObject.updateFields()
|
||||
fn = getattr(input, 'filename', '') # zope.publisher.browser.FileUpload
|
||||
self.request.form['filename'] = fn
|
||||
if input:
|
||||
self.request.form['_tempfilename'] = input.headers.get('_tempfilename')
|
||||
# f = self.context
|
||||
# f.extfiledata = tempfilename # provide for rename
|
||||
if fn:
|
||||
contentType = guess_content_type(fn)
|
||||
if contentType:
|
||||
request.form['form.contentType'] = contentType
|
||||
return super(UploadWidget, self)._toFieldValue(input)
|
||||
|
||||
|
||||
# forms
|
||||
|
||||
class ObjectForm(NodeView):
|
||||
|
@ -91,7 +71,13 @@ class ObjectForm(NodeView):
|
|||
def __init__(self, context, request):
|
||||
super(ObjectForm, self).__init__(context, request)
|
||||
|
||||
# cybertools.composer.schema support
|
||||
@Lazy
|
||||
def adapted(self):
|
||||
return adapted(self.context)
|
||||
|
||||
@Lazy
|
||||
def typeInterface(self):
|
||||
return IType(self.context).typeInterface or ITextDocument
|
||||
|
||||
@property
|
||||
def schemaMacros(self):
|
||||
|
@ -103,10 +89,13 @@ class ObjectForm(NodeView):
|
|||
|
||||
@Lazy
|
||||
def schema(self):
|
||||
return getSchemaFromInterface(self.typeInterface, manager=self)
|
||||
schemaFactory = component.getAdapter(self.adapted, ISchemaFactory)
|
||||
return schemaFactory(self.typeInterface, manager=self,
|
||||
request=self.request)
|
||||
|
||||
@Lazy
|
||||
def fields(self):
|
||||
return self.schema.fields
|
||||
fields = self.schema.fields
|
||||
fields.data.height = 10
|
||||
ifc = self.typeInterface
|
||||
|
@ -130,41 +119,12 @@ class ObjectForm(NodeView):
|
|||
def instance(self):
|
||||
return IInstance(adapted(self.context))
|
||||
|
||||
# zope.formlib support
|
||||
|
||||
@property
|
||||
def form_fields(self):
|
||||
ifc = self.typeInterface
|
||||
ff = FormFields(ifc)
|
||||
if ifc in widgetControllers:
|
||||
wc = widgetControllers[ifc](self.context, self.request)
|
||||
ff = wc.modifyFormFields(ff)
|
||||
return ff
|
||||
|
||||
def setUp(self):
|
||||
if self._isSetUp:
|
||||
return
|
||||
self.setUpWidgets()
|
||||
desc = self.widgets.get('description')
|
||||
if desc:
|
||||
desc.height = 2
|
||||
if self.typeInterface in widgetControllers:
|
||||
wc = widgetControllers[self.typeInterface](self.context, self.request)
|
||||
wc.modifyWidgetSetup(self.widgets)
|
||||
self._isSetUp = True
|
||||
|
||||
# general methods
|
||||
|
||||
def __call__(self):
|
||||
response = self.request.response
|
||||
response.setHeader('Expires', 'Sat, 1 Jan 2000 00:00:00 GMT')
|
||||
response.setHeader('Pragma', 'no-cache')
|
||||
return innerHtml(self)
|
||||
|
||||
@Lazy
|
||||
def typeInterface(self):
|
||||
return IType(self.context).typeInterface or ITextDocument
|
||||
|
||||
@Lazy
|
||||
def defaultPredicate(self):
|
||||
return self.loopsRoot.getConceptManager().getDefaultPredicate()
|
||||
|
@ -194,55 +154,6 @@ class ObjectForm(NodeView):
|
|||
for o in result])
|
||||
|
||||
|
||||
class WidgetController(object):
|
||||
|
||||
def __init__(self, context, request):
|
||||
self.context = context
|
||||
self.request = request
|
||||
|
||||
def modifySchemaFields(self, fields):
|
||||
pass
|
||||
|
||||
def modifyFormFields(self, formFields):
|
||||
return formFields
|
||||
|
||||
def modifyWidgetSetup(self, widgets):
|
||||
pass
|
||||
|
||||
|
||||
class NoteWidgetController(WidgetController):
|
||||
|
||||
def modifySchemaFields(self, fields):
|
||||
del fields['description']
|
||||
fields.data.height = 5
|
||||
|
||||
def modifyFormFields(self, formFields):
|
||||
return formFields.omit('description')
|
||||
|
||||
def modifyWidgetSetup(self, widgets):
|
||||
widgets['data'].height = 5
|
||||
|
||||
|
||||
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
|
||||
return formFields.omit('contentType')
|
||||
|
||||
|
||||
widgetControllers = {
|
||||
INote: NoteWidgetController,
|
||||
IFile: FileWidgetController,
|
||||
IExternalFile: FileWidgetController,
|
||||
}
|
||||
|
||||
|
||||
class EditObjectForm(ObjectForm, EditForm):
|
||||
|
||||
@property
|
||||
|
@ -275,13 +186,13 @@ class CreateObjectForm(ObjectForm, Form):
|
|||
form_action = 'create_resource'
|
||||
dialog_name = 'create'
|
||||
|
||||
# cybertools.composer.schema support
|
||||
@Lazy
|
||||
def adapted(self):
|
||||
return self.typeInterface(Resource())
|
||||
|
||||
@Lazy
|
||||
def instance(self):
|
||||
return IInstance(Concept())
|
||||
|
||||
# general methods
|
||||
return IInstance(Resource())
|
||||
|
||||
@Lazy
|
||||
def typeInterface(self):
|
||||
|
@ -307,13 +218,16 @@ class CreateObjectForm(ObjectForm, Form):
|
|||
class InnerForm(CreateObjectForm):
|
||||
|
||||
@property
|
||||
#def macro(self): return self.template.macros['fields']
|
||||
def macro(self): return self.schemaMacros['fields']
|
||||
|
||||
|
||||
# processing form input
|
||||
|
||||
class EditObject(FormController):
|
||||
""" Note that ``self.context`` of this adapter may be different from
|
||||
``self.object``, the object it acts upon, e.g. when this object
|
||||
is created during the update processing.
|
||||
"""
|
||||
|
||||
prefix = 'form.'
|
||||
conceptPrefix = 'assignments.'
|
||||
|
@ -321,9 +235,18 @@ class EditObject(FormController):
|
|||
old = None
|
||||
selected = None
|
||||
|
||||
@Lazy
|
||||
def adapted(self):
|
||||
return adapted(self.object)
|
||||
|
||||
@Lazy
|
||||
def typeInterface(self):
|
||||
return IType(self.object).typeInterface or ITextDocument
|
||||
|
||||
@Lazy
|
||||
def schema(self):
|
||||
return getSchemaFromInterface(self.typeInterface, manager=self)
|
||||
schemaFactory = component.getAdapter(self.adapted, ISchemaFactory)
|
||||
return schemaFactory(self.typeInterface)
|
||||
|
||||
@Lazy
|
||||
def fields(self):
|
||||
|
@ -331,12 +254,7 @@ class EditObject(FormController):
|
|||
|
||||
@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
|
||||
return component.getAdapter(self.adapted, IInstance, name='editor')
|
||||
|
||||
@Lazy
|
||||
def loopsRoot(self):
|
||||
|
@ -398,50 +316,6 @@ class EditObject(FormController):
|
|||
def fieldHandlers(self):
|
||||
return dict(fileupload=self.handleFileUpload)
|
||||
|
||||
def xupdateFields(self): # obsolete
|
||||
obj = self.object
|
||||
errors = {}
|
||||
form = self.request.form
|
||||
ti = IType(obj).typeInterface
|
||||
if ti is not None:
|
||||
adapted = ti(obj)
|
||||
else:
|
||||
adapted = obj
|
||||
for k in form.keys():
|
||||
# TODO: use self.view.form_fields or better: IInstance(adapted)
|
||||
if k.startswith(self.prefix):
|
||||
fn = k[len(self.prefix):]
|
||||
if fn in ('action', 'type', 'data.used') or fn.endswith('-empty-marker'):
|
||||
continue
|
||||
value = form[k]
|
||||
if fn.startswith(self.conceptPrefix) and value:
|
||||
self.collectConcepts(fn[len(self.conceptPrefix):], value)
|
||||
else:
|
||||
if not value and fn == 'data' and IFile.providedBy(adapted):
|
||||
# empty file data - don't change
|
||||
continue
|
||||
if isinstance(value, FileUpload):
|
||||
filename = getattr(value, 'filename', '')
|
||||
value = value.read()
|
||||
if filename:
|
||||
#self.request.form['filename'] = filename
|
||||
contentType = guess_content_type(filename, value[:100])
|
||||
if contentType:
|
||||
ct = contentType[0]
|
||||
self.request.form['form.contentType'] = ct
|
||||
adapted.contentType = ct
|
||||
adapted.localFilename = filename
|
||||
if fn == 'title' and not value:
|
||||
# TODO: provide general validation mechanism
|
||||
errors[fn] = 'Field %s must not be empty' % fn
|
||||
else:
|
||||
# TODO: provide unmarshalling depending on field type
|
||||
setattr(adapted, fn, value)
|
||||
if self.old or self.selected:
|
||||
self.assignConcepts(obj)
|
||||
notify(ObjectModifiedEvent(obj))
|
||||
return errors
|
||||
|
||||
def collectConcepts(self, fieldName, value):
|
||||
if self.old is None: self.old = []
|
||||
if self.selected is None: self.selected = []
|
||||
|
|
|
@ -392,7 +392,6 @@
|
|||
interface="zope.filerepresentation.interfaces.IFileFactory" />
|
||||
</class>
|
||||
|
||||
|
||||
<adapter factory="cybertools.composer.schema.instance.Instance" />
|
||||
<adapter factory="cybertools.composer.schema.instance.Editor"
|
||||
name="editor" />
|
||||
|
@ -402,6 +401,11 @@
|
|||
<adapter factory="cybertools.composer.schema.field.FileUploadFieldInstance"
|
||||
name="fileupload" />
|
||||
|
||||
<adapter factory="loops.schema.ResourceSchemaFactory" />
|
||||
<adapter factory="loops.schema.ResourceSchemaFactory"
|
||||
for="loops.interfaces.IResource" />
|
||||
<adapter factory="loops.schema.FileSchemaFactory" />
|
||||
<adapter factory="loops.schema.NoteSchemaFactory" />
|
||||
|
||||
<adapter factory="loops.setup.SetupManager" />
|
||||
<adapter factory="loops.external.NodesLoader" />
|
||||
|
|
|
@ -375,8 +375,8 @@ class TextDocumentAdapter(DocumentAdapter):
|
|||
""" A type adapter for providing text document functionality for resources.
|
||||
"""
|
||||
|
||||
implements(IDocument)
|
||||
_contextAttributes = list(IDocument) + list(IBaseResource)
|
||||
implements(ITextDocument)
|
||||
_contextAttributes = list(ITextDocument) + list(IBaseResource)
|
||||
|
||||
|
||||
class NoteAdapter(DocumentAdapter):
|
||||
|
|
62
schema.py
Normal file
62
schema.py
Normal file
|
@ -0,0 +1,62 @@
|
|||
#
|
||||
# Copyright (c) 2005 Helmut Merz helmutm@cy55.de
|
||||
#
|
||||
# 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
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
"""
|
||||
Specialized schema factories
|
||||
|
||||
$Id$
|
||||
"""
|
||||
|
||||
from zope.component import adapts
|
||||
|
||||
from cybertools.composer.schema.factory import SchemaFactory
|
||||
from loops.interfaces import IResourceAdapter, IFile, INote
|
||||
|
||||
|
||||
class ResourceSchemaFactory(SchemaFactory):
|
||||
|
||||
adapts(IResourceAdapter)
|
||||
|
||||
def __call__(self, interface, **kw):
|
||||
schema = super(ResourceSchemaFactory, self).__call__(interface, **kw)
|
||||
schema.fields.data.height = 10
|
||||
return schema
|
||||
|
||||
|
||||
class FileSchemaFactory(SchemaFactory):
|
||||
|
||||
adapts(IFile)
|
||||
|
||||
def __call__(self, interface, **kw):
|
||||
schema = super(FileSchemaFactory, self).__call__(interface, **kw)
|
||||
if 'request' in kw and kw['request'].principal.id != 'rootadmin':
|
||||
del schema.fields['contentType']
|
||||
return schema
|
||||
|
||||
|
||||
class NoteSchemaFactory(SchemaFactory):
|
||||
|
||||
adapts(INote)
|
||||
|
||||
def __call__(self, interface, **kw):
|
||||
schema = super(NoteSchemaFactory, self).__call__(interface, **kw)
|
||||
del schema.fields['description']
|
||||
schema.fields.data.height = 5
|
||||
return schema
|
||||
|
||||
|
|
@ -16,6 +16,7 @@ from zope.app.security.interfaces import IAuthentication
|
|||
from zope.dublincore.annotatableadapter import ZDCAnnotatableAdapter
|
||||
from zope.dublincore.interfaces import IZopeDublinCore
|
||||
|
||||
from cybertools.composer.schema.factory import SchemaFactory
|
||||
from cybertools.composer.schema.field import FieldInstance, NumberFieldInstance
|
||||
from cybertools.composer.schema.instance import Instance, Editor
|
||||
from cybertools.relation.tests import IntIdsStub
|
||||
|
@ -34,6 +35,7 @@ from loops.concept import Concept
|
|||
from loops.concept import IndexAttributes as ConceptIndexAttributes
|
||||
from loops.resource import Resource, FileAdapter
|
||||
from loops.resource import IndexAttributes as ResourceIndexAttributes
|
||||
from loops.schema import ResourceSchemaFactory, FileSchemaFactory, NoteSchemaFactory
|
||||
from loops.setup import SetupManager, addObject
|
||||
from loops.type import LoopsType, ConceptType, ResourceType, TypeConcept
|
||||
|
||||
|
@ -67,6 +69,11 @@ class TestSite(object):
|
|||
component.provideAdapter(FieldInstance)
|
||||
component.provideAdapter(NumberFieldInstance, name='number')
|
||||
|
||||
component.provideAdapter(SchemaFactory)
|
||||
component.provideAdapter(ResourceSchemaFactory)
|
||||
component.provideAdapter(FileSchemaFactory)
|
||||
component.provideAdapter(NoteSchemaFactory)
|
||||
|
||||
component.getSiteManager().registerHandler(invalidateRelations,
|
||||
(ILoopsObject, IObjectRemovedEvent))
|
||||
component.getSiteManager().registerHandler(removeRelation,
|
||||
|
|
Loading…
Add table
Reference in a new issue