turn all the stuff used to handle 'generic relations' in forms into proper
field / widget.
-> regroup code from web.request, web.controller, web.views.autoform, web.views.formrenderers,
web.views.editcontroller (!) into GenericRelationsField, GenericRelationsWidget in the editviews
module (together with the UnrelatedDiv view).
So:
* almost everything in one place
* no more specific behaviour in the form renderer
* almost no custom behaviour in autoform (simply add the field when it think it should)
Also, the form renderer now display field's value with colspan=2 when field.label is None.
--- a/web/controller.py Wed Jan 20 08:43:41 2010 +0100
+++ b/web/controller.py Wed Jan 20 10:06:12 2010 +0100
@@ -35,19 +35,6 @@
params[navparam] = form[redirectparam]
return params
-def parse_relations_descr(rdescr):
- """parse a string describing some relations, in the form
- subjeids:rtype:objeids
- where subjeids and objeids are eids separeted by a underscore
-
- return an iterator on (subject eid, relation type, object eid) found
- """
- for rstr in rdescr:
- subjs, rtype, objs = rstr.split(':')
- for subj in subjs.split('_'):
- for obj in objs.split('_'):
- yield typed_eid(subj), rtype, typed_eid(obj)
-
def append_url_params(url, params):
"""append raw parameters to the url. Given parameters, if any, are expected
to be already url-quoted.
@@ -137,22 +124,6 @@
else:
self._cw.set_message(self._cw._('entity deleted'))
- def delete_relations(self, rdefs):
- """delete relations from the repository"""
- # FIXME convert to using the syntax subject:relation:eids
- execute = self._cw.execute
- for subj, rtype, obj in rdefs:
- rql = 'DELETE X %s Y where X eid %%(x)s, Y eid %%(y)s' % rtype
- execute(rql, {'x': subj, 'y': obj}, ('x', 'y'))
- self._cw.set_message(self._cw._('relations deleted'))
-
- def insert_relations(self, rdefs):
- """insert relations into the repository"""
- execute = self._cw.execute
- for subj, rtype, obj in rdefs:
- rql = 'SET X %s Y where X eid %%(x)s, Y eid %%(y)s' % rtype
- execute(rql, {'x': subj, 'y': obj}, ('x', 'y'))
-
def reset(self):
"""reset form parameters and redirect to a view determinated by given
--- a/web/request.py Wed Jan 20 08:43:41 2010 +0100
+++ b/web/request.py Wed Jan 20 10:06:12 2010 +0100
@@ -386,37 +386,7 @@
raise RequestError(self._('missing parameters for entity %s') % eid)
return params
- def get_pending_operations(self, entity, relname, role):
- operations = {'insert' : [], 'delete' : []}
- for optype in ('insert', 'delete'):
- data = self.get_session_data('pending_%s' % optype) or ()
- for eidfrom, rel, eidto in data:
- if relname == rel:
- if role == 'subject' and entity.eid == eidfrom:
- operations[optype].append(eidto)
- if role == 'object' and entity.eid == eidto:
- operations[optype].append(eidfrom)
- return operations
-
- def get_pending_inserts(self, eid=None):
- """shortcut to access req's pending_insert entry
-
- This is where are stored relations being added while editing
- an entity. This used to be stored in a temporary cookie.
- """
- pending = self.get_session_data('pending_insert') or ()
- return ['%s:%s:%s' % (subj, rel, obj) for subj, rel, obj in pending
- if eid is None or eid in (subj, obj)]
-
- def get_pending_deletes(self, eid=None):
- """shortcut to access req's pending_delete entry
-
- This is where are stored relations being removed while editing
- an entity. This used to be stored in a temporary cookie.
- """
- pending = self.get_session_data('pending_delete') or ()
- return ['%s:%s:%s' % (subj, rel, obj) for subj, rel, obj in pending
- if eid is None or eid in (subj, obj)]
+ # XXX this should go to the GenericRelationsField. missing edition cancel protocol.
def remove_pending_operations(self):
"""shortcut to clear req's pending_{delete,insert} entries
--- a/web/views/autoform.py Wed Jan 20 08:43:41 2010 +0100
+++ b/web/views/autoform.py Wed Jan 20 10:06:12 2010 +0100
@@ -9,12 +9,12 @@
__docformat__ = "restructuredtext en"
_ = unicode
-from logilab.common.decorators import cached
+from logilab.common.decorators import cached, iclassmethod
from cubicweb import typed_eid
from cubicweb.web import stdmsgs, uicfg
from cubicweb.web import form, formwidgets as fwdgs
-from cubicweb.web.views import forms, editforms
+from cubicweb.web.views import forms, editforms, editviews
_afs = uicfg.autoform_section
@@ -44,6 +44,31 @@
# which relations should be edited
display_fields = None
+ def _generic_relations_field(self):
+ try:
+ srels_by_cat = self.srelations_by_category('generic', 'add', strict=True)
+ warn('[3.6] %s: srelations_by_category is deprecated, use uicfg or '
+ 'override editable_relations instead' % classid(form),
+ DeprecationWarning)
+ except AttributeError:
+ srels_by_cat = self.editable_relations()
+ if not srels_by_cat:
+ raise form.FieldNotFound('_cw_generic_field')
+ return editviews.GenericRelationsField(self.editable_relations())
+
+ @iclassmethod
+ def field_by_name(cls_or_self, name, role=None, eschema=None):
+ """return field with the given name and role. If field is not explicitly
+ defined for the form but `eclass` is specified, guess_field will be
+ called.
+ """
+ try:
+ return super(AutomaticEntityForm, cls_or_self).field_by_name(name, role, eschema)
+ except form.FieldNotFound:
+ if name == '_cw_generic_field' and not isinstance(cls_or_self, type):
+ return cls_or_self._generic_relations_field()
+ raise
+
# base automatic entity form methods #######################################
def __init__(self, *args, **kwargs):
@@ -64,6 +89,12 @@
except form.FieldNotFound:
# meta attribute such as <attr>_format
continue
+ if self.formtype == 'main' and entity.has_eid():
+ try:
+ self.fields.append(self.field_by_name('_cw_generic_field'))
+ except form.FieldNotFound:
+ # no editable relation
+ pass
self.maxrelitems = self._cw.property_value('navigation.related-limit')
self.force_display = bool(self._cw.form.get('__force_display'))
fnum = len(self.fields)
@@ -163,63 +194,6 @@
# generic relations modifier ###############################################
- def relations_table(self):
- """yiels 3-tuples (rtype, target, related_list)
- where <related_list> itself a list of :
- - node_id (will be the entity element's DOM id)
- - appropriate javascript's togglePendingDelete() function call
- - status 'pendingdelete' or ''
- - oneline view of related entity
- """
- entity = self.edited_entity
- pending_deletes = self._cw.get_pending_deletes(entity.eid)
- for label, rschema, role in self.editable_relations():
- relatedrset = entity.related(rschema, role, limit=self.related_limit)
- if rschema.has_perm(self._cw, 'delete'):
- toggleable_rel_link_func = editforms.toggleable_relation_link
- else:
- toggleable_rel_link_func = lambda x, y, z: u''
- related = []
- for row in xrange(relatedrset.rowcount):
- nodeid = editforms.relation_id(entity.eid, rschema, role,
- relatedrset[row][0])
- if nodeid in pending_deletes:
- status = u'pendingDelete'
- label = '+'
- else:
- status = u''
- label = 'x'
- dellink = toggleable_rel_link_func(entity.eid, nodeid, label)
- eview = self._cw.view('oneline', relatedrset, row=row)
- related.append((nodeid, dellink, status, eview))
- yield (rschema, role, related)
-
- def restore_pending_inserts(self, cell=False):
- """used to restore edition page as it was before clicking on
- 'search for <some entity type>'
- """
- eid = self.edited_entity.eid
- cell = cell and "div_insert_" or "tr"
- pending_inserts = set(self._cw.get_pending_inserts(eid))
- for pendingid in pending_inserts:
- eidfrom, rtype, eidto = pendingid.split(':')
- if typed_eid(eidfrom) == eid: # subject
- label = display_name(self._cw, rtype, 'subject',
- self.edited_entity.__regid__)
- reid = eidto
- else:
- label = display_name(self._cw, rtype, 'object',
- self.edited_entity.__regid__)
- reid = eidfrom
- jscall = "javascript: cancelPendingInsert('%s', '%s', null, %s);" \
- % (pendingid, cell, eid)
- rset = self._cw.eid_rset(reid)
- eview = self._cw.view('text', rset, row=0)
- # XXX find a clean way to handle baskets
- if rset.description[0][0] == 'Basket':
- eview = '%s (%s)' % (eview, display_name(self._cw, 'Basket'))
- yield rtype, pendingid, jscall, label, reid, eview
-
# inlined forms support ####################################################
@cached
--- a/web/views/editcontroller.py Wed Jan 20 08:43:41 2010 +0100
+++ b/web/views/editcontroller.py Wed Jan 20 10:06:12 2010 +0100
@@ -13,7 +13,7 @@
from cubicweb import Binary, ValidationError, typed_eid
from cubicweb.web import INTERNAL_FIELD_VALUE, RequestError, NothingToEdit, ProcessFormError
-from cubicweb.web.controller import parse_relations_descr
+from cubicweb.web.views.editviews import delete_relations, insert_relations
from cubicweb.web.views.basecontrollers import ViewController
@@ -73,8 +73,6 @@
# no specific action, generic edition
self._to_create = req.data['eidmap'] = {}
self._pending_fields = req.data['pendingfields'] = set()
- todelete = self._cw.get_pending_deletes()
- toinsert = self._cw.get_pending_inserts()
try:
methodname = req.form.pop('__method', None)
for eid in req.edited_eids():
@@ -88,7 +86,7 @@
except (RequestError, NothingToEdit), ex:
if '__linkto' in req.form and 'eid' in req.form:
self.execute_linkto()
- elif not ('__delete' in req.form or '__insert' in req.form or todelete or toinsert):
+ elif not ('__delete' in req.form or '__insert' in req.form):
raise ValidationError(None, {None: unicode(ex)})
# handle relations in newly created entities
if self._pending_fields:
@@ -99,13 +97,15 @@
self._cw.execute(*querydef)
# XXX this processes *all* pending operations of *all* entities
if req.form.has_key('__delete'):
- todelete += req.list_form_param('__delete', req.form, pop=True)
- if todelete:
- self.delete_relations(parse_relations_descr(todelete))
+ todelete = req.list_form_param('__delete', req.form, pop=True)
+ if todelete:
+ delete_relations(self._cw, todelete)
if req.form.has_key('__insert'):
+ warn('[3.6] stop using __insert, support will be removed',
+ DeprecationWarning)
toinsert = req.list_form_param('__insert', req.form, pop=True)
- if toinsert:
- self.insert_relations(parse_relations_descr(toinsert))
+ if toinsert:
+ insert_relations(self._cw, toinsert)
self._cw.remove_pending_operations()
if self.errors:
errors = dict((f.name, unicode(ex)) for f, ex in self.errors)
@@ -171,13 +171,11 @@
if is_main_entity:
self.notify_edited(entity)
if formparams.has_key('__delete'):
+ # XXX deprecate?
todelete = self._cw.list_form_param('__delete', formparams, pop=True)
- self.delete_relations(parse_relations_descr(todelete))
+ delete_relations(self._cw, todelete)
if formparams.has_key('__cloned_eid'):
entity.copy_relations(typed_eid(formparams['__cloned_eid']))
- if formparams.has_key('__insert'):
- toinsert = self._cw.list_form_param('__insert', formparams, pop=True)
- self.insert_relations(parse_relations_descr(toinsert))
if is_main_entity: # only execute linkto for the main entity
self.execute_linkto(entity.eid)
return eid
--- a/web/views/editforms.py Wed Jan 20 08:43:41 2010 +0100
+++ b/web/views/editforms.py Wed Jan 20 10:06:12 2010 +0100
@@ -30,21 +30,6 @@
_pvdc = uicfg.primaryview_display_ctrl
-def relation_id(eid, rtype, role, reid):
- """return an identifier for a relation between two entities"""
- if role == 'subject':
- return u'%s:%s:%s' % (eid, rtype, reid)
- return u'%s:%s:%s' % (reid, rtype, eid)
-
-def toggleable_relation_link(eid, nodeid, label='x'):
- """return javascript snippet to delete/undelete a relation between two
- entities
- """
- js = u"javascript: togglePendingDelete('%s', %s);" % (
- nodeid, xml_escape(dumps(eid)))
- return u'[<a class="handle" href="%s" id="handle%s">%s</a>]' % (
- js, nodeid, label)
-
class DeleteConfForm(forms.CompositeForm):
__regid__ = 'deleteconf'
--- a/web/views/editviews.py Wed Jan 20 08:43:41 2010 +0100
+++ b/web/views/editviews.py Wed Jan 20 10:06:12 2010 +0100
@@ -13,14 +13,29 @@
from logilab.common.decorators import cached
from logilab.mtconverter import xml_escape
-from cubicweb import typed_eid
+from cubicweb import typed_eid, uilib
+from cubicweb.schema import display_name
from cubicweb.view import EntityView
from cubicweb.selectors import (one_line_rset, non_final_entity,
match_search_state, match_form_params)
-from cubicweb.uilib import cut
-from cubicweb.web.views import linksearch_select_url
-from cubicweb.web.views.editforms import relation_id
-from cubicweb.web.views.baseviews import FinalView
+from cubicweb.web import formwidgets as fw, formfields as ff
+from cubicweb.web.views import baseviews, linksearch_select_url
+
+
+def relation_id(eid, rtype, role, reid):
+ """return an identifier for a relation between two entities"""
+ if role == 'subject':
+ return u'%s:%s:%s' % (eid, rtype, reid)
+ return u'%s:%s:%s' % (reid, rtype, eid)
+
+def toggleable_relation_link(eid, nodeid, label='x'):
+ """return javascript snippet to delete/undelete a relation between two
+ entities
+ """
+ js = u"javascript: togglePendingDelete('%s', %s);" % (
+ nodeid, xml_escape(dumps(eid)))
+ return u'[<a class="handle" href="%s" id="handle%s">%s</a>]' % (
+ js, nodeid, label)
class SearchForAssociationView(EntityView):
@@ -73,6 +88,195 @@
entity.view('outofcontext', w=self.w)
+def get_pending_inserts(req, eid=None):
+ """shortcut to access req's pending_insert entry
+
+ This is where are stored relations being added while editing
+ an entity. This used to be stored in a temporary cookie.
+ """
+ pending = req.get_session_data('pending_insert') or ()
+ return ['%s:%s:%s' % (subj, rel, obj) for subj, rel, obj in pending
+ if eid is None or eid in (subj, obj)]
+
+def get_pending_deletes(req, eid=None):
+ """shortcut to access req's pending_delete entry
+
+ This is where are stored relations being removed while editing
+ an entity. This used to be stored in a temporary cookie.
+ """
+ pending = req.get_session_data('pending_delete') or ()
+ return ['%s:%s:%s' % (subj, rel, obj) for subj, rel, obj in pending
+ if eid is None or eid in (subj, obj)]
+
+def parse_relations_descr(rdescr):
+ """parse a string describing some relations, in the form
+ subjeids:rtype:objeids
+ where subjeids and objeids are eids separeted by a underscore
+
+ return an iterator on (subject eid, relation type, object eid) found
+ """
+ for rstr in rdescr:
+ subjs, rtype, objs = rstr.split(':')
+ for subj in subjs.split('_'):
+ for obj in objs.split('_'):
+ yield typed_eid(subj), rtype, typed_eid(obj)
+
+def delete_relations(req, rdefs):
+ """delete relations from the repository"""
+ # FIXME convert to using the syntax subject:relation:eids
+ execute = req.execute
+ for subj, rtype, obj in parse_relations_descr(rdefs):
+ rql = 'DELETE X %s Y where X eid %%(x)s, Y eid %%(y)s' % rtype
+ execute(rql, {'x': subj, 'y': obj}, ('x', 'y'))
+ req.set_message(req._('relations deleted'))
+
+def insert_relations(req, rdefs):
+ """insert relations into the repository"""
+ execute = req.execute
+ for subj, rtype, obj in parse_relations_descr(rdefs):
+ rql = 'SET X %s Y where X eid %%(x)s, Y eid %%(y)s' % rtype
+ execute(rql, {'x': subj, 'y': obj}, ('x', 'y'))
+
+
+
+class GenericRelationsWidget(fw.FieldWidget):
+
+ def render(self, form, field, renderer):
+ stream = []
+ w = stream.append
+ req = form._cw
+ _ = req._
+ __ = _
+ label = u'%s :' % __('This %s' % form.edited_entity.e_schema).capitalize()
+ eid = form.edited_entity.eid
+ w(u'<fieldset class="subentity">')
+ w(u'<legend class="iformTitle">%s</legend>' % label)
+ w(u'<table id="relatedEntities">')
+ for rschema, role, related in field.relations_table(form):
+ # already linked entities
+ if related:
+ w(u'<tr><th class="labelCol">%s</th>' % rschema.display_name(req, role))
+ w(u'<td>')
+ w(u'<ul>')
+ for viewparams in related:
+ w(u'<li class="invisible">%s<div id="span%s" class="%s">%s</div></li>'
+ % (viewparams[1], viewparams[0], viewparams[2], viewparams[3]))
+ if not form.force_display and form.maxrelitems < len(related):
+ link = (u'<span class="invisible">'
+ '[<a href="javascript: window.location.href+=\'&__force_display=1\'">%s</a>]'
+ '</span>' % self._cw._('view all'))
+ w(u'<li class="invisible">%s</li>' % link)
+ w(u'</ul>')
+ w(u'</td>')
+ w(u'</tr>')
+ pendings = list(field.restore_pending_inserts(form))
+ if not pendings:
+ w(u'<tr><th> </th><td> </td></tr>')
+ else:
+ for row in pendings:
+ # soon to be linked to entities
+ w(u'<tr id="tr%s">' % row[1])
+ w(u'<th>%s</th>' % row[3])
+ w(u'<td>')
+ w(u'<a class="handle" title="%s" href="%s">[x]</a>' %
+ (_('cancel this insert'), row[2]))
+ w(u'<a id="a%s" class="editionPending" href="%s">%s</a>'
+ % (row[1], row[4], xml_escape(row[5])))
+ w(u'</td>')
+ w(u'</tr>')
+ w(u'<tr id="relationSelectorRow_%s" class="separator">' % eid)
+ w(u'<th class="labelCol">')
+ w(u'<select id="relationSelector_%s" tabindex="%s" '
+ 'onchange="javascript:showMatchingSelect(this.options[this.selectedIndex].value,%s);">'
+ % (eid, req.next_tabindex(), xml_escape(dumps(eid))))
+ w(u'<option value="">%s</option>' % _('select a relation'))
+ for i18nrtype, rschema, role in field.relations:
+ # more entities to link to
+ w(u'<option value="%s_%s">%s</option>' % (rschema, role, i18nrtype))
+ w(u'</select>')
+ w(u'</th>')
+ w(u'<td id="unrelatedDivs_%s"></td>' % eid)
+ w(u'</tr>')
+ w(u'</table>')
+ w(u'</fieldset>')
+ return '\n'.join(stream)
+
+
+class GenericRelationsField(ff.Field):
+ widget = GenericRelationsWidget
+
+ def __init__(self, relations, name='_cw_generic_field', **kwargs):
+ assert relations
+ kwargs['eidparam'] = True
+ super(GenericRelationsField, self).__init__(name, **kwargs)
+ self.relations = relations
+ self.label = None
+
+ def process_posted(self, form):
+ todelete = get_pending_deletes(form._cw)
+ if todelete:
+ delete_relations(form._cw, todelete)
+ toinsert = get_pending_inserts(form._cw)
+ if toinsert:
+ insert_relations(form._cw, toinsert)
+ return ()
+
+ def relations_table(self, form):
+ """yiels 3-tuples (rtype, role, related_list)
+ where <related_list> itself a list of :
+ - node_id (will be the entity element's DOM id)
+ - appropriate javascript's togglePendingDelete() function call
+ - status 'pendingdelete' or ''
+ - oneline view of related entity
+ """
+ entity = form.edited_entity
+ pending_deletes = get_pending_deletes(form._cw, entity.eid)
+ for label, rschema, role in self.relations:
+ related = []
+ if entity.has_eid():
+ rset = entity.related(rschema, role, limit=form.related_limit)
+ if rschema.has_perm(form._cw, 'delete'):
+ toggleable_rel_link_func = toggleable_relation_link
+ else:
+ toggleable_rel_link_func = lambda x, y, z: u''
+ for row in xrange(rset.rowcount):
+ nodeid = relation_id(entity.eid, rschema, role,
+ rset[row][0])
+ if nodeid in pending_deletes:
+ status, label = u'pendingDelete', '+'
+ else:
+ status, label = u'', 'x'
+ dellink = toggleable_rel_link_func(entity.eid, nodeid, label)
+ eview = form._cw.view('oneline', rset, row=row)
+ related.append((nodeid, dellink, status, eview))
+ yield (rschema, role, related)
+
+ def restore_pending_inserts(self, form):
+ """used to restore edition page as it was before clicking on
+ 'search for <some entity type>'
+ """
+ entity = form.edited_entity
+ pending_inserts = set(get_pending_inserts(form._cw, form.edited_entity.eid))
+ for pendingid in pending_inserts:
+ eidfrom, rtype, eidto = pendingid.split(':')
+ if typed_eid(eidfrom) == entity.eid: # subject
+ label = display_name(form._cw, rtype, 'subject',
+ entity.__regid__)
+ reid = eidto
+ else:
+ label = display_name(form._cw, rtype, 'object',
+ entity.__regid__)
+ reid = eidfrom
+ jscall = "javascript: cancelPendingInsert('%s', 'tr', null, %s);" \
+ % (pendingid, entity.eid)
+ rset = form._cw.eid_rset(reid)
+ eview = form._cw.view('text', rset, row=0)
+ # XXX find a clean way to handle baskets
+ if rset.description[0][0] == 'Basket':
+ eview = '%s (%s)' % (eview, display_name(form._cw, 'Basket'))
+ yield rtype, pendingid, jscall, label, reid, eview
+
+
class UnrelatedDivs(EntityView):
__regid__ = 'unrelateddivs'
__select__ = match_form_params('relation')
@@ -97,7 +301,7 @@
else:
targettypes = rschema.subjects(entity.e_schema)
etypes = '/'.join(sorted(etype.display_name(self._cw) for etype in targettypes))
- etypes = cut(etypes, self._cw.property_value('navigation.short-line-size'))
+ etypes = uilib.cut(etypes, self._cw.property_value('navigation.short-line-size'))
options.append('<option>%s %s</option>' % (self._cw._('select a'), etypes))
options += self._get_select_options(entity, rschema, target)
options += self._get_search_options(entity, rschema, target, targettypes)
@@ -117,15 +321,16 @@
def _get_select_options(self, entity, rschema, target):
"""add options to search among all entities of each possible type"""
options = []
- pending_inserts = self._cw.get_pending_inserts(entity.eid)
+ pending_inserts = get_pending_inserts(self._cw, entity.eid)
rtype = rschema.type
form = self._cw.vreg['forms'].select('edition', self._cw, entity=entity)
field = form.field_by_name(rschema, target, entity.e_schema)
limit = self._cw.property_value('navigation.combobox-limit')
for eview, reid in field.choices(form, limit): # XXX expect 'limit' arg on choices
if reid is None:
- options.append('<option class="separator">-- %s --</option>'
- % xml_escape(eview))
+ if eview: # skip blank value
+ options.append('<option class="separator">-- %s --</option>'
+ % xml_escape(eview))
else:
optionid = relation_id(entity.eid, rtype, target, reid)
if optionid not in pending_inserts:
@@ -193,7 +398,7 @@
self.wview('textoutofcontext', self.cw_rset, row=row, col=col)
-class EditableFinalView(FinalView):
+class EditableFinalView(baseviews.FinalView):
"""same as FinalView but enables inplace-edition when possible"""
__regid__ = 'editable-final'
--- a/web/views/formrenderers.py Wed Jan 20 08:43:41 2010 +0100
+++ b/web/views/formrenderers.py Wed Jan 20 10:06:12 2010 +0100
@@ -205,14 +205,15 @@
w(u'<table class="%s">' % self.table_class)
for field in fields:
w(u'<tr class="%s_%s_row">' % (field.name, field.role))
- if self.display_label:
+ if self.display_label and field.label is not None:
w(u'<th class="labelCol">%s</th>' % self.render_label(form, field))
+ w('<td')
+ if field.label is None:
+ w(' colspan="2"')
error = form.field_error(field)
if error:
- w(u'<td class="error">')
- self.render_error(w, error)
- else:
- w(u'<td>')
+ w(u' class="error"')
+ w(u'>')
w(field.render(form, self))
if self.display_help:
w(self.render_help(form, field))
@@ -392,72 +393,6 @@
</table>""" % tuple(button.render(form) for button in form.form_buttons))
else:
super(EntityFormRenderer, self).render_buttons(w, form)
-
- def relations_form(self, w, form):
- try:
- srels_by_cat = form.srelations_by_category('generic', 'add', strict=True)
- warn('[3.6] %s: srelations_by_category is deprecated, override '
- 'editable_relations instead' % classid(form), DeprecationWarning)
- except AttributeError:
- srels_by_cat = form.editable_relations()
- if not srels_by_cat:
- return u''
- req = self._cw
- _ = req._
- __ = _
- label = u'%s :' % __('This %s' % form.edited_entity.e_schema).capitalize()
- eid = form.edited_entity.eid
- w(u'<fieldset class="subentity">')
- w(u'<legend class="iformTitle">%s</legend>' % label)
- w(u'<table id="relatedEntities">')
- for rschema, target, related in form.relations_table():
- # already linked entities
- if related:
- w(u'<tr><th class="labelCol">%s</th>' % rschema.display_name(req, target))
- w(u'<td>')
- w(u'<ul>')
- for viewparams in related:
- w(u'<li class="invisible">%s<div id="span%s" class="%s">%s</div></li>'
- % (viewparams[1], viewparams[0], viewparams[2], viewparams[3]))
- if not form.force_display and form.maxrelitems < len(related):
- link = (u'<span class="invisible">'
- '[<a href="javascript: window.location.href+=\'&__force_display=1\'">%s</a>]'
- '</span>' % self._cw._('view all'))
- w(u'<li class="invisible">%s</li>' % link)
- w(u'</ul>')
- w(u'</td>')
- w(u'</tr>')
- pendings = list(form.restore_pending_inserts())
- if not pendings:
- w(u'<tr><th> </th><td> </td></tr>')
- else:
- for row in pendings:
- # soon to be linked to entities
- w(u'<tr id="tr%s">' % row[1])
- w(u'<th>%s</th>' % row[3])
- w(u'<td>')
- w(u'<a class="handle" title="%s" href="%s">[x]</a>' %
- (_('cancel this insert'), row[2]))
- w(u'<a id="a%s" class="editionPending" href="%s">%s</a>'
- % (row[1], row[4], xml_escape(row[5])))
- w(u'</td>')
- w(u'</tr>')
- w(u'<tr id="relationSelectorRow_%s" class="separator">' % eid)
- w(u'<th class="labelCol">')
- w(u'<select id="relationSelector_%s" tabindex="%s" '
- 'onchange="javascript:showMatchingSelect(this.options[this.selectedIndex].value,%s);">'
- % (eid, req.next_tabindex(), xml_escape(dumps(eid))))
- w(u'<option value="">%s</option>' % _('select a relation'))
- for i18nrtype, rschema, target in srels_by_cat:
- # more entities to link to
- w(u'<option value="%s_%s">%s</option>' % (rschema, target, i18nrtype))
- w(u'</select>')
- w(u'</th>')
- w(u'<td id="unrelatedDivs_%s"></td>' % eid)
- w(u'</tr>')
- w(u'</table>')
- w(u'</fieldset>')
-
# NOTE: should_* and display_* method extracted and moved to the form to
# ease overriding