web/views/editforms.py
branchtls-sprint
changeset 1091 b5e253c0dd13
child 1132 96752791c2b6
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/views/editforms.py	Thu Mar 12 16:29:00 2009 +0100
@@ -0,0 +1,170 @@
+"""Set of HTML automatic forms to create, delete, copy or edit a single entity
+or a list of entities of the same type
+
+:organization: Logilab
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
+"""
+__docformat__ = "restructuredtext en"
+
+from copy import copy
+
+from simplejson import dumps
+
+from logilab.mtconverter import html_escape
+from logilab.common.decorators import cached
+
+from cubicweb.selectors import (specified_etype_implements, implements,
+                                match_kwargs, match_form_params, one_line_rset,
+                                non_final_entity, accepts_etype_compat)
+from cubicweb.utils import make_uid
+from cubicweb.view import View, EntityView
+from cubicweb.common import tags
+from cubicweb.common.uilib import cut
+from cubicweb.web import INTERNAL_FIELD_VALUE, stdmsgs, eid_param
+from cubicweb.web.controller import NAV_FORM_PARAMETERS
+from cubicweb.web.form import MultipleFieldsForm, EntityFieldsForm, FormMixIn, FormRenderer
+from cubicweb.web.formfields import StringField,  RichTextField, guess_field
+from cubicweb.web.formwidgets import HiddenInput
+
+_ = unicode
+
+
+class DeleteConfForm(EntityView):
+    id = 'deleteconf'
+    title = _('delete')
+    domid = 'deleteconf'
+    onsubmit = None
+    # don't use navigation, all entities asked to be deleted should be displayed
+    # else we will only delete the displayed page
+    need_navigation = False
+    
+    def call(self):
+        """ask for confirmation before real deletion"""
+        req, w = self.req, self.w
+        _ = req._
+        w(u'<script type="text/javascript">updateMessage(\'%s\');</script>\n'
+          % _('this action is not reversible!'))
+        # XXX above message should have style of a warning
+        w(u'<h4>%s</h4>\n' % _('Do you want to delete the following element(s) ?'))
+        form = MultipleFieldsForm(req, domid='deleteconf', action=self.build_url('edit'),
+                                  onsubmit=self.onsubmit, copy_nav_params=True)
+        form.buttons.append(form.button_delete(label=stdmsgs.YES))
+        form.buttons.append(form.button_cancel(label=stdmsgs.NO))
+        done = set()
+        w(u'<ul>\n')
+        for i in xrange(self.rset.rowcount):
+            if self.rset[i][0] in done:
+                continue
+            done.add(self.rset[i][0])
+            entity = self.rset.get_entity(i, 0)
+            subform = EntityFieldsForm(req, set_error_url=False,
+                                       entity=entity)
+            form.form_add_subform(subform)
+            # don't use outofcontext view or any other that may contain inline edition form
+            w(u'<li>%s</li>' % tags.a(entity.view('textoutofcontext'),
+                                      href=entity.absolute_url()))
+        w(u'</ul>\n')
+        w(form.form_render())
+
+
+class ClickAndEditForm(FormMixIn, EntityView):
+    id = 'reledit'
+    __select__ = non_final_entity() & match_kwargs('rtype')
+
+    # FIXME editableField class could be toggleable from userprefs
+      
+    def cell_call(self, row, col, rtype=None, role='subject', reload=False):
+        entity = self.entity(row, col)
+        if getattr(entity, rtype) is None:
+            value = self.req._('not specified')
+        else:
+            value = entity.printable_value(rtype)
+        if not entity.has_perm('update'):
+            self.w(value)
+            return
+        self.req.add_js( ('cubicweb.ajax.js',) )
+        eid = entity.eid
+        edit_key = make_uid('%s-%s' % (rtype, eid))
+        divid = 'd%s' % edit_key
+        reload = dumps(reload)
+        buttons = [tags.input(klass="validateButton", type="submit", name="__action_apply",
+                              value=self.req._(stdmsgs.BUTTON_OK), tabindex=self.req.next_tabindex()),
+                   tags.input(klass="validateButton", type="button",
+                              value=self.req._(stdmsgs.BUTTON_CANCEL),
+                              onclick="cancelInlineEdit(%s,\'%s\',\'%s\')" % (eid, rtype, divid),
+                              tabindex=self.req.next_tabindex())]
+        form = self.vreg.select_object('forms', 'edition', self.req, self.rset, row=row, col=col,
+                                       entity=entity, domid='%s-form' % divid, action='#',
+                                       cssstyle='display: none', buttons=buttons,
+                                       onsubmit="return inlineValidateForm('%(divid)s-form', '%(rtype)s', '%(eid)s', '%(divid)s', %(reload)s);" % locals())
+        renderer = FormRenderer(display_label=False, display_help=False,
+                                display_fields=(rtype,), button_bar_class='buttonbar')
+        self.w(tags.div(value, klass='editableField', id=divid,
+                        ondblclick="showInlineEditionForm(%(eid)s, '%(rtype)s', '%(divid)s')" % locals()))
+        self.w(form.render(renderer=renderer))
+
+
+class AutomaticEntityForm(EntityFieldsForm):
+    id = 'edition'
+    needs_js = EntityFieldsForm.needs_js + ('cubicweb.ajax.js',)
+    
+    def __init__(self, *args, **kwargs):
+        super(AutomaticEntityForm, self).__init__(*args, **kwargs)
+        self.entity.complete()
+        for rschema, target in self.editable_attributes(entity):
+            field = guess_field(entity.__class__, entity.e_schema, rschema, target)
+            self.fields.append(field)
+            
+    def form_buttons(self):
+        return [self.button_ok(tabindex=self.req.next_tabindex()),
+                self.button_apply(tabindex=self.req.next_tabindex()),
+                self.button_cancel(tabindex=self.req.next_tabindex())]
+
+    def editable_attributes(self, entity):
+        # XXX both (add, delete) required for non final relations
+        return [(rschema, x) for rschema, _, x in entity.relations_by_category(('primary', 'secondary'), 'add')
+                if rschema != 'eid']
+    
+class _EditionForm(EntityView):
+    """primary entity edition form
+
+    When generating a new attribute_input, the editor will look for a method
+    named 'default_ATTRNAME' on the entity instance, where ATTRNAME is the
+    name of the attribute being edited. You may use this feature to compute
+    dynamic default values such as the 'tomorrow' date or the user's login
+    being connected
+    """    
+    id = 'edition'
+    __select__ = one_line_rset() & non_final_entity()
+
+    title = _('edition')
+    controller = 'edit'
+    skip_relations = FormMixIn.skip_relations.copy()
+
+    def cell_call(self, row, col, **kwargs):
+        self.req.add_js( ('cubicweb.ajax.js',) )
+        self.initialize_varmaker()
+        entity = self.complete_entity(row, col)
+
+    def initialize_varmaker(self):
+        varmaker = self.req.get_page_data('rql_varmaker')
+        if varmaker is None:
+            varmaker = self.req.varmaker
+            self.req.set_page_data('rql_varmaker', varmaker)
+        self.varmaker = varmaker
+        
+    def edit_form(self, entity, kwargs):
+        form = EntityFieldsForm(self.req, entity=entity)
+        for rschema, target in self.editable_attributes(entity):
+            field = guess_field(entity.__class__, entity.e_schema, rschema, target)
+            form.fields.append(field)
+        form.buttons.append(form.button_ok())
+        form.buttons.append(form.button_apply())
+        form.buttons.append(form.button_cancel())
+        self.w(form.form_render())
+
+    def editable_attributes(self, entity):
+        # XXX both (add, delete)
+        return [(rschema, x) for rschema, _, x in entity.relations_by_category(('primary', 'secondary'), 'add')
+                if rschema != 'eid']