work in progress: preparing dojo dialog forms for implementing validation
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1965 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
4ccf4d033c
commit
4d645cc695
4 changed files with 68 additions and 16 deletions
|
@ -43,7 +43,7 @@ from cybertools.browser.form import FormController
|
||||||
from cybertools.typology.interfaces import IType, ITypeManager
|
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, ITextDocument
|
||||||
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.query import ConceptQuery
|
||||||
|
@ -80,10 +80,14 @@ class ObjectForm(NodeView):
|
||||||
|
|
||||||
template = ViewPageTemplateFile('form_macros.pt')
|
template = ViewPageTemplateFile('form_macros.pt')
|
||||||
|
|
||||||
|
_isSetUp = False
|
||||||
|
|
||||||
def __init__(self, context, request):
|
def __init__(self, context, request):
|
||||||
super(ObjectForm, self).__init__(context, request)
|
super(ObjectForm, self).__init__(context, request)
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
if self._isSetUp:
|
||||||
|
return
|
||||||
self.setUpWidgets()
|
self.setUpWidgets()
|
||||||
desc = self.widgets.get('description')
|
desc = self.widgets.get('description')
|
||||||
if desc:
|
if desc:
|
||||||
|
@ -91,6 +95,7 @@ class ObjectForm(NodeView):
|
||||||
if self.typeInterface in widgetControllers:
|
if self.typeInterface in widgetControllers:
|
||||||
wc = widgetControllers[self.typeInterface](self.context, self.request)
|
wc = widgetControllers[self.typeInterface](self.context, self.request)
|
||||||
wc.modifyWidgetSetup(self.widgets)
|
wc.modifyWidgetSetup(self.widgets)
|
||||||
|
self._isSetUp = True
|
||||||
|
|
||||||
def __call__(self):
|
def __call__(self):
|
||||||
response = self.request.response
|
response = self.request.response
|
||||||
|
@ -175,6 +180,7 @@ class EditObjectForm(ObjectForm, EditForm):
|
||||||
|
|
||||||
def __init__(self, context, request):
|
def __init__(self, context, request):
|
||||||
super(EditObjectForm, self).__init__(context, request)
|
super(EditObjectForm, self).__init__(context, request)
|
||||||
|
self.url = self.url # keep virtual target URL
|
||||||
self.context = self.virtualTargetObject
|
self.context = self.virtualTargetObject
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
|
@ -213,7 +219,8 @@ class CreateObjectForm(ObjectForm, Form):
|
||||||
t = self.loopsRoot.loopsTraverse(typeToken)
|
t = self.loopsRoot.loopsTraverse(typeToken)
|
||||||
ifc = removeSecurityProxy(ITypeConcept(t).typeInterface)
|
ifc = removeSecurityProxy(ITypeConcept(t).typeInterface)
|
||||||
else:
|
else:
|
||||||
ifc = INote
|
#ifc = INote
|
||||||
|
ifc = ITextDocument
|
||||||
self.typeInterface = ifc
|
self.typeInterface = ifc
|
||||||
ff = FormFields(ifc)
|
ff = FormFields(ifc)
|
||||||
#ff['data'].custom_widget = UploadWidget
|
#ff['data'].custom_widget = UploadWidget
|
||||||
|
@ -256,16 +263,21 @@ 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
|
||||||
self.updateFields(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.request.response.redirect(self.view.virtualTargetUrl + '?version=this')
|
self.request.response.redirect(self.view.virtualTargetUrl + '?version=this')
|
||||||
return False
|
return False
|
||||||
#return True
|
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def loopsRoot(self):
|
def loopsRoot(self):
|
||||||
return self.view.loopsRoot
|
return self.view.loopsRoot
|
||||||
|
|
||||||
def updateFields(self, obj):
|
def updateFields(self, obj):
|
||||||
|
errors = {}
|
||||||
form = self.request.form
|
form = self.request.form
|
||||||
ti = IType(obj).typeInterface
|
ti = IType(obj).typeInterface
|
||||||
if ti is not None:
|
if ti is not None:
|
||||||
|
@ -273,6 +285,7 @@ class EditObject(FormController):
|
||||||
else:
|
else:
|
||||||
adapted = obj
|
adapted = obj
|
||||||
for k in form.keys():
|
for k in form.keys():
|
||||||
|
# TODO: use self.view.form_fields
|
||||||
if k.startswith(self.prefix):
|
if k.startswith(self.prefix):
|
||||||
fn = k[len(self.prefix):]
|
fn = k[len(self.prefix):]
|
||||||
if fn in ('action', 'type', 'data.used') or fn.endswith('-empty-marker'):
|
if fn in ('action', 'type', 'data.used') or fn.endswith('-empty-marker'):
|
||||||
|
@ -295,10 +308,16 @@ class EditObject(FormController):
|
||||||
self.request.form['form.contentType'] = ct
|
self.request.form['form.contentType'] = ct
|
||||||
adapted.contentType = ct
|
adapted.contentType = ct
|
||||||
adapted.localFilename = filename
|
adapted.localFilename = filename
|
||||||
setattr(adapted, fn, value)
|
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:
|
if self.old or self.selected:
|
||||||
self.assignConcepts(obj)
|
self.assignConcepts(obj)
|
||||||
notify(ObjectModifiedEvent(obj))
|
notify(ObjectModifiedEvent(obj))
|
||||||
|
return errors
|
||||||
|
|
||||||
def collectConcepts(self, fieldName, value):
|
def collectConcepts(self, fieldName, value):
|
||||||
if self.old is None: self.old = []
|
if self.old is None: self.old = []
|
||||||
|
@ -361,5 +380,4 @@ class CreateObject(EditObject):
|
||||||
self.updateFields(obj)
|
self.updateFields(obj)
|
||||||
self.request.response.redirect(self.view.virtualTargetUrl)
|
self.request.response.redirect(self.view.virtualTargetUrl)
|
||||||
return False
|
return False
|
||||||
#return True
|
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
$Id$ -->
|
$Id$ -->
|
||||||
|
|
||||||
<metal:block define-macro="edit" i18n:domain="loops">
|
<metal:block define-macro="edit" i18n:domain="loops">
|
||||||
<form method="post" enctype="multipart/form-data">
|
<form method="post" enctype="multipart/form-data" id="dialog_form">
|
||||||
<input type="hidden" name="form.action" value="edit"
|
<input type="hidden" name="form.action" value="edit"
|
||||||
tal:attributes="value view/form_action" />
|
tal:attributes="value view/form_action" />
|
||||||
<input type="hidden" name="version"
|
<input type="hidden" name="version"
|
||||||
|
@ -55,7 +55,7 @@
|
||||||
tal:attributes="value type/token;
|
tal:attributes="value type/token;
|
||||||
selected python:
|
selected python:
|
||||||
type.token == (request.get('form.type')
|
type.token == (request.get('form.type')
|
||||||
or '.loops/concepts/note')">
|
or '.loops/concepts/textdocument')">
|
||||||
Note
|
Note
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
|
@ -81,8 +81,11 @@
|
||||||
</metal:block>
|
</metal:block>
|
||||||
|
|
||||||
|
|
||||||
<metal:fields define-macro="fields">
|
<metal:fields define-macro="fields"
|
||||||
<tal:block tal:define="dummy view/setUp">
|
tal:define="show view/update">
|
||||||
|
<tal:show condition="show">
|
||||||
|
<div id="form_fields"
|
||||||
|
tal:define="dummy view/setUp">
|
||||||
<table width="100%">
|
<table width="100%">
|
||||||
<tr tal:repeat="widget view/widgets">
|
<tr tal:repeat="widget view/widgets">
|
||||||
<td class="label" width="10%"
|
<td class="label" width="10%"
|
||||||
|
@ -104,7 +107,8 @@
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</tal:block>
|
</div>
|
||||||
|
</tal:show>
|
||||||
</metal:fields>
|
</metal:fields>
|
||||||
|
|
||||||
|
|
||||||
|
@ -205,8 +209,12 @@
|
||||||
<tr metal:define-macro="buttons" i18n:domain="">
|
<tr metal:define-macro="buttons" i18n:domain="">
|
||||||
<td colspan="5"
|
<td colspan="5"
|
||||||
tal:define="dlgName view/dialog_name">
|
tal:define="dlgName view/dialog_name">
|
||||||
<input type="submit" value="Save" onClick="dlg.hide()" class="submit"
|
<input value="Save" type="submit"
|
||||||
i18n:attributes="value"
|
i18n:attributes="value"
|
||||||
|
xtal:attributes="onClick
|
||||||
|
string:return submitReplacingOrReloading(
|
||||||
|
'form_fields', 'dialog_form',
|
||||||
|
'${view/virtualTargetUrl}/@@inner_form.html')"
|
||||||
tal:attributes="onClick string:dialogs['$dlgName'].hide()">
|
tal:attributes="onClick string:dialogs['$dlgName'].hide()">
|
||||||
<input type="button" value="Cancel" onClick="dlg.hide();"
|
<input type="button" value="Cancel" onClick="dlg.hide();"
|
||||||
i18n:attributes="value"
|
i18n:attributes="value"
|
||||||
|
|
|
@ -28,6 +28,28 @@ function submitReplacing(targetId, formId, actionUrl) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function submitReplacingOrReloading(targetId, formId, actionUrl) {
|
||||||
|
node = dojo.byId(targetId);
|
||||||
|
var args = {
|
||||||
|
url: actionUrl,
|
||||||
|
formNode: dojo.byId(formId),
|
||||||
|
method: 'post',
|
||||||
|
mimetype: "text/html"
|
||||||
|
};
|
||||||
|
args.load = function (t, d, e) {
|
||||||
|
if (d.length < 10) {
|
||||||
|
document.location.reload(false);
|
||||||
|
} else {
|
||||||
|
while (node.firstChild) {
|
||||||
|
dojo.dom.destroyNode(node.firstChild);
|
||||||
|
}
|
||||||
|
node.innerHTML = d;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
dojo.io.bind(args);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
function inlineEdit(id, saveUrl) {
|
function inlineEdit(id, saveUrl) {
|
||||||
var iconNode = dojo.byId('inlineedit_icon');
|
var iconNode = dojo.byId('inlineedit_icon');
|
||||||
iconNode.style.visibility = 'hidden';
|
iconNode.style.visibility = 'hidden';
|
||||||
|
|
|
@ -220,18 +220,22 @@
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a href="#" i18n:translate=""
|
<a href="create_object.html" i18n:translate=""
|
||||||
onclick="objectDialog('create', 'create_object.html'); return false;"
|
onclick="objectDialog('create', 'create_object.html'); return false;"
|
||||||
tal:attributes="onclick string:objectDialog('create', '$url/create_object.html');; return false;;">
|
tal:attributes="onClick
|
||||||
|
string:objectDialog('create', '$url/create_object.html');;
|
||||||
|
return false;;">
|
||||||
Create Resource...
|
Create Resource...
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div tal:condition="view/hasEditableTarget">
|
<div tal:condition="view/hasEditableTarget">
|
||||||
<a href="#" i18n:translate=""
|
<a href="edit_object.html" i18n:translate=""
|
||||||
onclick="objectDialog('edit', 'edit_object.html'); return false;"
|
onclick="objectDialog('edit', 'edit_object.html'); return false;"
|
||||||
tal:define="version request/version|nothing;
|
tal:define="version request/version|nothing;
|
||||||
versionPar python: version and '?version=' + version or ''"
|
versionPar python: version and '?version=' + version or ''"
|
||||||
tal:attributes="onclick string:objectDialog('edit', '$url/edit_object.html$versionPar');; return false;;">
|
tal:attributes="onClick
|
||||||
|
string:objectDialog('edit', '$url/edit_object.html$versionPar');;
|
||||||
|
return false;;">
|
||||||
Edit Resource...
|
Edit Resource...
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Add table
Reference in a new issue