Back to index

plone3  3.1.7
edit.py
Go to the documentation of this file.
00001 from xml.sax.saxutils import unescape
00002 
00003 from zope.component import getMultiAdapter
00004 from zope.event import notify
00005 
00006 from zope import lifecycleevent
00007 from zope.app.form.interfaces import IDisplayWidget
00008 from zope.formlib import form as formlib
00009 
00010 from kss.core import kssaction
00011 from plone.app.kss.plonekssview import PloneKSSView
00012 
00013 from Acquisition import aq_inner
00014 from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
00015 
00016 from plone.locking.interfaces import ILockable
00017 
00018 from plone.app.form.kss.validation import validate_and_issue_message
00019 
00020 class FormlibInlineEdit(PloneKSSView):
00021     """KSS actions for formlib form inline editing
00022     """
00023 
00024     form_template = ViewPageTemplateFile('inline_edit_wrapper.pt')
00025 
00026     @kssaction
00027     def begin(self, formname, fieldname, structure='false'):
00028         """Begin inline editing - find the widget for the given field name
00029         in the given form (looked up as a view on the context), then hide the
00030         block with the id '${fieldname}-display' and display an edit form in
00031         its place. If 'structure' is 'true' (a string), then the inline 
00032         editable field will eventually permit HTML input to be rendered
00033         unescaped.
00034         """
00035         context = aq_inner(self.context)
00036         request = aq_inner(self.request)
00037         
00038         form = getMultiAdapter((context, request), name=formname)
00039         form = form.__of__(context)
00040         
00041         if fieldname.startswith(form.prefix):
00042             fieldname = fieldname[len(form.prefix)+1:]
00043             
00044         formlib_field = form.form_fields[fieldname]
00045         widgets = formlib.setUpEditWidgets((formlib_field,), form.prefix, 
00046             context, request, ignore_request=True)
00047             
00048         widget = widgets[fieldname]
00049         
00050         display_id = '%s-display' % fieldname
00051         form_id = '%s-form' % fieldname
00052         
00053         ksscore = self.getCommandSet('core')
00054         zopecommands = self.getCommandSet('zope')
00055         plonecommands = self.getCommandSet('plone')
00056         
00057         # lock the context (or issue warning)
00058         locking = ILockable(context, None)
00059         if locking:
00060             if not locking.can_safely_unlock():
00061                 selector = ksscore.getHtmlIdSelector('plone-lock-status')
00062                 zopecommands.refreshViewlet(selector, 'plone.abovecontent', 'plone.lockinfo')
00063                 plonecommands.refreshContentMenu()
00064                 return
00065             else: # we are locking the content
00066                 locking.lock()
00067         
00068         plonecommands.issuePortalMessage('')
00069         
00070         # hide the existing display field
00071         display_selector = ksscore.getHtmlIdSelector(display_id)
00072         ksscore.addClass(display_selector, 'hiddenStructure')
00073         
00074         # show the form
00075         form_html = self.form_template(widget=widget,
00076                                        form_id=form_id,
00077                                        fieldname=fieldname,
00078                                        structure=structure)
00079 
00080         ksscore.insertHTMLAfter(display_selector, form_html)
00081         
00082         # XXX: Focus on the input field?
00083         
00084     @kssaction
00085     def cancel(self, fieldname):
00086         """Cancel the inline editing taking place for the given field, by
00087         removing the inline editing form and unhiding the block with id
00088         '${fieldname}-display'.
00089         """
00090         context = aq_inner(self.context)
00091         
00092         display_id = '%s-display' % fieldname
00093         form_id = '%s-form' % fieldname
00094         
00095         ksscore = self.getCommandSet('core')
00096         
00097         # unlock the context if it was locked before
00098         locking = ILockable(context, None)
00099         if locking and locking.can_safely_unlock():
00100             locking.unlock()
00101 
00102         # show the existing display field
00103         ksscore.removeClass(ksscore.getHtmlIdSelector(display_id), 'hiddenStructure')
00104         
00105         # hide the form
00106         ksscore.deleteNode(ksscore.getHtmlIdSelector(form_id))
00107         
00108     @kssaction
00109     def save(self, formname, fieldname, structure='false'):
00110         """Attempt to save the given field in the given form which is being
00111         inline-edited. If there is a validation error, the error will be
00112         highlighted. If not, the value will be saved, and the inline editing
00113         form removed. Before the form is re-displayed, the contents of the
00114         element with id '${fieldname}-display' will be updated with the new
00115         field value.
00116         """
00117         
00118         context = aq_inner(self.context)
00119         request = aq_inner(self.request)
00120         
00121         structure = (structure == 'true')
00122         
00123         form = getMultiAdapter((context, request), name=formname)
00124         form = form.__of__(context)
00125         
00126         raw_fieldname = fieldname
00127         if fieldname.startswith(form.prefix):
00128             raw_fieldname = fieldname[len(form.prefix)+1:]
00129             full_fieldname = fieldname
00130         else:
00131             full_fieldname = "%s.%s" % (form.prefix, raw_fieldname)
00132             
00133         formlib_field = form.form_fields[raw_fieldname]
00134         widgets = formlib.setUpEditWidgets((formlib_field,), form.prefix, 
00135             context, request, ignore_request=False)
00136             
00137         widget = widgets[raw_fieldname]
00138         
00139         # validate and issue a message if there's an error
00140         
00141         ksscore = self.getCommandSet('core')
00142         error = validate_and_issue_message(ksscore, widget, full_fieldname)
00143 
00144         if not error:
00145         
00146             field_value = request.form.get('%s.%s' % (form.prefix, raw_fieldname))
00147             data = { raw_fieldname : field_value }
00148         
00149             # update value
00150             changed = formlib.applyChanges(context, (formlib_field,), data)
00151             if changed:
00152                 
00153                 # send modified events if something actually changed
00154                 field = widget.context
00155                 adapter = field.interface(context)
00156                 
00157                 descriptor = lifecycleevent.Attributes(field.interface, raw_fieldname)
00158                 notify(lifecycleevent.ObjectModifiedEvent(context, descriptor))
00159                 
00160                 # update the rendered value
00161                 display_widget = getMultiAdapter((formlib_field.field, request), IDisplayWidget)
00162                 display_widget.setRenderedValue(field.get(adapter))
00163                 output = display_widget()
00164                 
00165                 if structure:
00166                     output = unescape(output)
00167                 
00168                 display_id = '%s-display' % fieldname
00169                 ksscore.replaceInnerHTML(ksscore.getHtmlIdSelector(display_id), output)
00170         
00171             # unlock and remove the field
00172             self.cancel(fieldname)