--- a/web/views/eproperties.py Wed Apr 08 20:37:55 2009 +0200
+++ b/web/views/eproperties.py Wed Apr 08 20:38:34 2009 +0200
@@ -10,18 +10,19 @@
from logilab.common.decorators import cached
+from cubicweb import UnknownProperty
from cubicweb.selectors import (one_line_rset, none_rset, implements,
- match_user_groups)
+ match_user_groups, entity_implements)
from cubicweb.utils import UStringIO
from cubicweb.view import StartupView
from cubicweb.web import INTERNAL_FIELD_VALUE, eid_param
from cubicweb.web.views import baseviews
-from cubicweb.web.form import FormMixIn
+from cubicweb.web import stdmsgs
+from cubicweb.web.form import FormMixIn, CompositeForm, EntityFieldsForm
+from cubicweb.web.formfields import FIELDS, StringField
+from cubicweb.web.formwidgets import Select, Button, SubmitButton
from cubicweb.web.views.editforms import AutomaticEntityForm
-AutomaticEntityForm.rwidgets.set_rtag('PropertyKeyWidget', 'pkey', 'subject', 'EProperty')
-AutomaticEntityForm.rwidgets.set_rtag('PropertyValueWidget', 'value', 'subject', 'EProperty')
-
_ = unicode
# some string we want to be internationalizable for nicer display of eproperty
@@ -33,10 +34,6 @@
_('components')
_('contentnavigation')
-class EPropertyPrimaryView(baseviews.PrimaryView):
- __select__ = implements('EProperty')
- skip_none = False
-
def make_togglable_link(nodeid, label, cookiename):
"""builds a HTML link that switches the visibility & remembers it"""
@@ -47,9 +44,15 @@
def css_class(someclass):
return someclass and 'class="%s"' % someclass or ''
+
+class EPropertyPrimaryView(baseviews.PrimaryView):
+ __select__ = implements('EProperty')
+ skip_none = False
+
+
class SystemEPropertiesForm(FormMixIn, StartupView):
id = 'systemepropertiesform'
- __select__ = none_rset & match_user_groups('managers')
+ __select__ = none_rset() & match_user_groups('managers')
title = _('site configuration')
controller = 'edit'
@@ -66,6 +69,7 @@
return str('%s_property_%s' % (self.config.appid, somestr))
def _group_status(self, group, default=u'hidden'):
+ """return css class name 'hidden' (collapsed), or '' (open)"""
cookies = self.req.get_cookie()
cookiename = self._cookie_name(group)
cookie = cookies.get(cookiename)
@@ -97,19 +101,17 @@
mainopts.setdefault(parts[0], []).append(key)
# precompute form to consume error message
for group, keys in mainopts.items():
- mainopts[group] = self.form(keys, False)
+ mainopts[group] = self.form(keys, True)
for group, objects in groupedopts.items():
for oid, keys in objects.items():
groupedopts[group][oid] = self.form(keys, True)
-
w = self.w
req = self.req
_ = req._
w(u'<h1>%s</h1>\n' % _(self.title))
- w(self.error_message())
for label, group, form in sorted((_(g), g, f)
for g, f in mainopts.iteritems()):
- status = css_class(self._group_status(group)) #'hidden' (collapsed), or '' (open) ?
+ status = css_class(self._group_status(group))
w(u'<h2 class="propertiesform">%s</h2>\n' %
(make_togglable_link('fieldset_' + group, label,
self._cookie_name(group))))
@@ -139,7 +141,8 @@
@property
@cached
def eprops_rset(self):
- return self.req.execute('Any P,K,V WHERE P is EProperty, P pkey K, P value V, NOT P for_user U')
+ return self.req.execute('Any P,K,V WHERE P is EProperty, P pkey K, '
+ 'P value V, NOT P for_user U')
@property
def defined_keys(self):
@@ -155,65 +158,38 @@
else:
entity = self.vreg.etype_class('EProperty')(self.req, None, None)
entity.eid = self.req.varmaker.next()
+ entity['pkey'] = key
entity['value'] = self.vreg.property_value(key)
return entity
def form(self, keys, splitlabel=False):
- stream = UStringIO()
- w = stream.write
- w(u'<form action="%s" method="post">\n' % self.build_url())
- w(u'<fieldset>\n')
- w(u'<input type="hidden" name="__errorurl" value="%s"/>\n'
- % html_escape(self.req.url()))
- w(u'<input type="hidden" name="__form_id" value="%s"/>\n' % self.id)
+ buttons = [SubmitButton(),
+ Button(stdmsgs.BUTTON_CANCEL, cwaction='cancel')]
+ form = CompositeForm(self.req, domid=None, action=self.build_url(),
+ form_buttons=buttons,
+ submitmsg=self.req._('changes applied'))
path = self.req.relative_path()
if '?' in path:
path, params = path.split('?', 1)
- w(u'<input type="hidden" name="__redirectparams" value="%s"/>\n'
- % html_escape(params))
- w(u'<input type="hidden" name="__redirectpath" value="%s"/>\n' % path)
- #w(u'<input type="hidden" name="__redirectrql" value=""/>\n')
- w(u'<input type="hidden" name="__message" value="%s"/>\n'
- % self.req._('changes applied'))
- w(u'<table><tr><td>\n')
+ form.form_add_hidden('__redirectparams', params)
+ form.form_add_hidden('__redirectpath', path)
+ for key in keys:
+ self.form_row(form, key, splitlabel)
+ return form.form_render()
- w(u'<table>\n')
- for key in keys:
- w(u'<tr>\n')
- self.form_row(w, key, splitlabel)
- w(u'</tr>\n')
- w(u'</table>\n')
- w(u'</td></tr><tr><td>\n')
- w(self.button_ok())
- w(self.button_cancel())
- w(u'</td></tr></table>\n')
- w(u'</fieldset>\n')
- w(u'</form>\n')
- return stream.getvalue()
-
- def form_row(self, w, key, splitlabel):
+ def form_row(self, form, key, splitlabel):
entity = self.entity_for_key(key)
if splitlabel:
- w(u'<td class="label">%s</td>' % self.req._(key.split('.')[-1]))
+ label = key.split('.')[-1]
else:
- w(u'<td class="label">%s</td>' % self.req._(key))
- wdg = self.vreg.property_value_widget(key, req=self.req)
- error = wdg.render_error(entity)
- w(u'<td class="%s">' % (error and 'error' or ''))
- w(error)
- self.form_row_hiddens(w, entity, key)
- w(wdg.edit_render(entity))
- w(u'</td>\n')
- w(u'<td>%s</td>' % wdg.render_help(entity))
- return entity
-
- def form_row_hiddens(self, w, entity, key):
- eid = entity.eid
- w(u'<input type="hidden" name="eid" value="%s"/>' % eid)
- w(u'<input type="hidden" name="%s" value="EProperty"/>' % eid_param('__type', eid))
- w(u'<input type="hidden" name="%s" value="%s"/>' % (eid_param('pkey', eid), key))
- w(u'<input type="hidden" name="%s" value="%s"/>' % (eid_param('edits-pkey', eid), ''))
-
+ label = key
+ subform = EntityFieldsForm(self.req, entity=entity, set_error_url=False)
+ subform.append_field(PropertyValueField(name='value', label=label,
+ eidparam=True))
+ subform.vreg = self.vreg
+ subform.form_add_hidden('pkey', key, eidparam=True)
+ form.form_add_subform(subform)
+ return subform
def is_user_prefs(cls, req, rset, row=None, col=0, **kwargs):
@@ -225,8 +201,8 @@
__select__ = (
# we don't want guests to be able to come here
match_user_groups('users', 'managers') &
- (none_rset | ((one_line_rset() & is_user_prefs) &
- (one_line_rset() & match_user_groups('managers'))))
+ (none_rset() | ((one_line_rset() & is_user_prefs) &
+ (one_line_rset() & match_user_groups('managers'))))
)
title = _('preferences')
@@ -243,14 +219,106 @@
return self.req.execute('Any P,K,V WHERE P is EProperty, P pkey K, P value V,'
'P for_user U, U eid %(x)s', {'x': self.user.eid})
- def form_row_hiddens(self, w, entity, key):
- super(EPropertiesForm, self).form_row_hiddens(w, entity, key)
+ def form_row(self, form, key, splitlabel):
+ subform = super(EPropertiesForm, self).form_row(form, key, splitlabel)
# if user is in the managers group and the property is being created,
# we have to set for_user explicitly
- if not entity.has_eid() and self.user.matching_groups('managers'):
- eid = entity.eid
- w(u'<input type="hidden" name="%s" value="%s"/>'
- % (eid_param('edits-for_user', eid), INTERNAL_FIELD_VALUE))
- w(u'<input type="hidden" name="%s" value="%s"/>'
- % (eid_param('for_user', eid), self.user.eid))
+ if not subform.edited_entity.has_eid() and self.user.matching_groups('managers'):
+ subform.form_add_hidden('for_user', self.user.eid, eidparam=True)
+
+
+# eproperty entity edition ####################################################
+
+class PropertyKeyField(StringField):
+ """specific field for EProperty.pkey to set the value widget according to
+ the selected key
+ """
+ widget = Select
+
+ def render(self, form, renderer):
+ wdg = self.get_widget(form)
+ wdg.attrs['tabindex'] = form.req.next_tabindex()
+ wdg.attrs['onchange'] = "javascript:setPropValueWidget('%s', %s)" % (
+ form.edited_entity.eid, form.req.next_tabindex())
+ return wdg.render(form, self)
+
+ def vocabulary(self, form):
+ entity = form.edited_entity
+ _ = form.req._
+ if entity.has_eid():
+ return [(_(entity.pkey), entity.pkey)]
+ # key beginning with 'system.' should usually not be edited by hand
+ choices = entity.vreg.user_property_keys()
+ return sorted(zip((_(v) for v in choices), choices))
+
+
+class PropertyValueField(StringField):
+ """specific field for EProperty.value which will be different according to
+ the selected key type and vocabulary information
+ """
+ def render(self, form, renderer=None, tabindex=None):
+ if not (form.edited_entity.has_eid() or 'pkey' in form.edited_entity):
+ # no key set yet, just include an empty div which will be filled
+ # on key selection
+ # empty span as well elsehtml validation fail (label is refering to
+ # this id)
+ domid = form.context[self]['id']
+ return u'<div id="div:%s"><span id="%s"/></div>' % (domid, domid)
+ wdg = self.get_widget(form)
+ if tabindex is not None:
+ wdg.attrs['tabindex'] = tabindex
+ return wdg.render(form, self)
+ def form_init(self, form):
+ entity = form.edited_entity
+ try:
+ pdef = form.vreg.property_info(entity.pkey)
+ except UnknownProperty, ex:
+ self.warning('%s (you should probably delete that property '
+ 'from the database)', ex)
+ msg = form.req._('you should probably delete that property')
+ self.widget = NotEditableWidget(entity.printable_value('value'),
+ '%s (%s)' % (msg, ex))
+ if entity.pkey.startswith('system.'):
+ msg = form.req._('value associated to this key is not editable '
+ 'manually')
+ self.widget = NotEditableWidget(entity.printable_value('value'), msg)
+ # XXX race condition when used from EPropertyForm, should not rely on
+ # instance attributes
+ self.initial = pdef['default']
+ self.help = pdef['help']
+ vocab = pdef['vocabulary']
+ if vocab is not None:
+ if callable(vocab):
+ # list() just in case its a generator function
+ self.choices = list(vocab(form.req))
+ else:
+ self.choices = vocab
+ wdg = Select()
+ else:
+ wdg = FIELDS[pdef['type']].widget()
+ if pdef['type'] == 'Boolean':
+ self.choices = [(form.req._('yes'), '1'), (form.req._('no'), '')]
+ elif pdef['type'] in ('Float', 'Int'):
+ wdg.attrs.setdefault('size', 3)
+ self.widget = wdg
+
+
+class NotEditableWidget(object):
+ def __init__(self, value, msg=None):
+ self.value = value
+ self.msg = msg
+
+ def render(self, form, field):
+ domid = form.context[field]['id']
+ value = '<span class="value" id="%s">%s</span>' % (domid, self.value)
+ if self.msg:
+ value + '<div class="helper">%s</div>' % self.msg
+ return value
+
+
+class EPropertyForm(AutomaticEntityForm):
+ __select__ = entity_implements('EProperty')
+ pkey = PropertyKeyField(eidparam=True)
+ value = PropertyValueField(eidparam=True)
+