web/views/editforms.py
branchtls-sprint
changeset 1091 b5e253c0dd13
child 1132 96752791c2b6
equal deleted inserted replaced
1090:a99dc223c583 1091:b5e253c0dd13
       
     1 """Set of HTML automatic forms to create, delete, copy or edit a single entity
       
     2 or a list of entities of the same type
       
     3 
       
     4 :organization: Logilab
       
     5 :copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
       
     6 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
       
     7 """
       
     8 __docformat__ = "restructuredtext en"
       
     9 
       
    10 from copy import copy
       
    11 
       
    12 from simplejson import dumps
       
    13 
       
    14 from logilab.mtconverter import html_escape
       
    15 from logilab.common.decorators import cached
       
    16 
       
    17 from cubicweb.selectors import (specified_etype_implements, implements,
       
    18                                 match_kwargs, match_form_params, one_line_rset,
       
    19                                 non_final_entity, accepts_etype_compat)
       
    20 from cubicweb.utils import make_uid
       
    21 from cubicweb.view import View, EntityView
       
    22 from cubicweb.common import tags
       
    23 from cubicweb.common.uilib import cut
       
    24 from cubicweb.web import INTERNAL_FIELD_VALUE, stdmsgs, eid_param
       
    25 from cubicweb.web.controller import NAV_FORM_PARAMETERS
       
    26 from cubicweb.web.form import MultipleFieldsForm, EntityFieldsForm, FormMixIn, FormRenderer
       
    27 from cubicweb.web.formfields import StringField,  RichTextField, guess_field
       
    28 from cubicweb.web.formwidgets import HiddenInput
       
    29 
       
    30 _ = unicode
       
    31 
       
    32 
       
    33 class DeleteConfForm(EntityView):
       
    34     id = 'deleteconf'
       
    35     title = _('delete')
       
    36     domid = 'deleteconf'
       
    37     onsubmit = None
       
    38     # don't use navigation, all entities asked to be deleted should be displayed
       
    39     # else we will only delete the displayed page
       
    40     need_navigation = False
       
    41     
       
    42     def call(self):
       
    43         """ask for confirmation before real deletion"""
       
    44         req, w = self.req, self.w
       
    45         _ = req._
       
    46         w(u'<script type="text/javascript">updateMessage(\'%s\');</script>\n'
       
    47           % _('this action is not reversible!'))
       
    48         # XXX above message should have style of a warning
       
    49         w(u'<h4>%s</h4>\n' % _('Do you want to delete the following element(s) ?'))
       
    50         form = MultipleFieldsForm(req, domid='deleteconf', action=self.build_url('edit'),
       
    51                                   onsubmit=self.onsubmit, copy_nav_params=True)
       
    52         form.buttons.append(form.button_delete(label=stdmsgs.YES))
       
    53         form.buttons.append(form.button_cancel(label=stdmsgs.NO))
       
    54         done = set()
       
    55         w(u'<ul>\n')
       
    56         for i in xrange(self.rset.rowcount):
       
    57             if self.rset[i][0] in done:
       
    58                 continue
       
    59             done.add(self.rset[i][0])
       
    60             entity = self.rset.get_entity(i, 0)
       
    61             subform = EntityFieldsForm(req, set_error_url=False,
       
    62                                        entity=entity)
       
    63             form.form_add_subform(subform)
       
    64             # don't use outofcontext view or any other that may contain inline edition form
       
    65             w(u'<li>%s</li>' % tags.a(entity.view('textoutofcontext'),
       
    66                                       href=entity.absolute_url()))
       
    67         w(u'</ul>\n')
       
    68         w(form.form_render())
       
    69 
       
    70 
       
    71 class ClickAndEditForm(FormMixIn, EntityView):
       
    72     id = 'reledit'
       
    73     __select__ = non_final_entity() & match_kwargs('rtype')
       
    74 
       
    75     # FIXME editableField class could be toggleable from userprefs
       
    76       
       
    77     def cell_call(self, row, col, rtype=None, role='subject', reload=False):
       
    78         entity = self.entity(row, col)
       
    79         if getattr(entity, rtype) is None:
       
    80             value = self.req._('not specified')
       
    81         else:
       
    82             value = entity.printable_value(rtype)
       
    83         if not entity.has_perm('update'):
       
    84             self.w(value)
       
    85             return
       
    86         self.req.add_js( ('cubicweb.ajax.js',) )
       
    87         eid = entity.eid
       
    88         edit_key = make_uid('%s-%s' % (rtype, eid))
       
    89         divid = 'd%s' % edit_key
       
    90         reload = dumps(reload)
       
    91         buttons = [tags.input(klass="validateButton", type="submit", name="__action_apply",
       
    92                               value=self.req._(stdmsgs.BUTTON_OK), tabindex=self.req.next_tabindex()),
       
    93                    tags.input(klass="validateButton", type="button",
       
    94                               value=self.req._(stdmsgs.BUTTON_CANCEL),
       
    95                               onclick="cancelInlineEdit(%s,\'%s\',\'%s\')" % (eid, rtype, divid),
       
    96                               tabindex=self.req.next_tabindex())]
       
    97         form = self.vreg.select_object('forms', 'edition', self.req, self.rset, row=row, col=col,
       
    98                                        entity=entity, domid='%s-form' % divid, action='#',
       
    99                                        cssstyle='display: none', buttons=buttons,
       
   100                                        onsubmit="return inlineValidateForm('%(divid)s-form', '%(rtype)s', '%(eid)s', '%(divid)s', %(reload)s);" % locals())
       
   101         renderer = FormRenderer(display_label=False, display_help=False,
       
   102                                 display_fields=(rtype,), button_bar_class='buttonbar')
       
   103         self.w(tags.div(value, klass='editableField', id=divid,
       
   104                         ondblclick="showInlineEditionForm(%(eid)s, '%(rtype)s', '%(divid)s')" % locals()))
       
   105         self.w(form.render(renderer=renderer))
       
   106 
       
   107 
       
   108 class AutomaticEntityForm(EntityFieldsForm):
       
   109     id = 'edition'
       
   110     needs_js = EntityFieldsForm.needs_js + ('cubicweb.ajax.js',)
       
   111     
       
   112     def __init__(self, *args, **kwargs):
       
   113         super(AutomaticEntityForm, self).__init__(*args, **kwargs)
       
   114         self.entity.complete()
       
   115         for rschema, target in self.editable_attributes(entity):
       
   116             field = guess_field(entity.__class__, entity.e_schema, rschema, target)
       
   117             self.fields.append(field)
       
   118             
       
   119     def form_buttons(self):
       
   120         return [self.button_ok(tabindex=self.req.next_tabindex()),
       
   121                 self.button_apply(tabindex=self.req.next_tabindex()),
       
   122                 self.button_cancel(tabindex=self.req.next_tabindex())]
       
   123 
       
   124     def editable_attributes(self, entity):
       
   125         # XXX both (add, delete) required for non final relations
       
   126         return [(rschema, x) for rschema, _, x in entity.relations_by_category(('primary', 'secondary'), 'add')
       
   127                 if rschema != 'eid']
       
   128     
       
   129 class _EditionForm(EntityView):
       
   130     """primary entity edition form
       
   131 
       
   132     When generating a new attribute_input, the editor will look for a method
       
   133     named 'default_ATTRNAME' on the entity instance, where ATTRNAME is the
       
   134     name of the attribute being edited. You may use this feature to compute
       
   135     dynamic default values such as the 'tomorrow' date or the user's login
       
   136     being connected
       
   137     """    
       
   138     id = 'edition'
       
   139     __select__ = one_line_rset() & non_final_entity()
       
   140 
       
   141     title = _('edition')
       
   142     controller = 'edit'
       
   143     skip_relations = FormMixIn.skip_relations.copy()
       
   144 
       
   145     def cell_call(self, row, col, **kwargs):
       
   146         self.req.add_js( ('cubicweb.ajax.js',) )
       
   147         self.initialize_varmaker()
       
   148         entity = self.complete_entity(row, col)
       
   149 
       
   150     def initialize_varmaker(self):
       
   151         varmaker = self.req.get_page_data('rql_varmaker')
       
   152         if varmaker is None:
       
   153             varmaker = self.req.varmaker
       
   154             self.req.set_page_data('rql_varmaker', varmaker)
       
   155         self.varmaker = varmaker
       
   156         
       
   157     def edit_form(self, entity, kwargs):
       
   158         form = EntityFieldsForm(self.req, entity=entity)
       
   159         for rschema, target in self.editable_attributes(entity):
       
   160             field = guess_field(entity.__class__, entity.e_schema, rschema, target)
       
   161             form.fields.append(field)
       
   162         form.buttons.append(form.button_ok())
       
   163         form.buttons.append(form.button_apply())
       
   164         form.buttons.append(form.button_cancel())
       
   165         self.w(form.form_render())
       
   166 
       
   167     def editable_attributes(self, entity):
       
   168         # XXX both (add, delete)
       
   169         return [(rschema, x) for rschema, _, x in entity.relations_by_category(('primary', 'secondary'), 'add')
       
   170                 if rschema != 'eid']