--- a/cwvreg.py Wed Apr 08 20:37:55 2009 +0200
+++ b/cwvreg.py Wed Apr 08 20:38:34 2009 +0200
@@ -339,37 +339,6 @@
self.warning('%s (you should probably delete that property '
'from the database)', ex)
-
- def property_value_widget(self, propkey, req=None, **attrs):
- """return widget according to key's type / vocab"""
- from cubicweb.web.widgets import StaticComboBoxWidget, widget_factory
- if req is None:
- tr = unicode
- else:
- tr = req._
- try:
- pdef = self.property_info(propkey)
- except UnknownProperty, ex:
- self.warning('%s (you should probably delete that property '
- 'from the database)', ex)
- return widget_factory(self, 'EProperty', self.schema['value'], 'String',
- description=u'', **attrs)
- req.form['value'] = pdef['default'] # XXX hack to pass the default value
- vocab = pdef['vocabulary']
- if vocab is not None:
- if callable(vocab):
- # list() just in case its a generator function
- vocabfunc = lambda **kwargs: list(vocab(propkey, req))
- else:
- vocabfunc = lambda **kwargs: vocab
- w = StaticComboBoxWidget(self, 'EProperty', self.schema['value'], 'String',
- vocabfunc=vocabfunc, description=tr(pdef['help']),
- **attrs)
- else:
- w = widget_factory(self, 'EProperty', self.schema['value'], pdef['type'],
- description=tr(pdef['help']), **attrs)
- return w
-
def parse(self, session, rql, args=None):
rqlst = self.rqlhelper.parse(rql)
def type_from_eid(eid, session=session):
--- a/web/views/basecontrollers.py Wed Apr 08 20:37:55 2009 +0200
+++ b/web/views/basecontrollers.py Wed Apr 08 20:38:34 2009 +0200
@@ -21,6 +21,7 @@
from cubicweb.view import STRICT_DOCTYPE, CW_XHTML_EXTENSIONS
from cubicweb.common.mail import format_mail
from cubicweb.web import ExplicitLogin, Redirect, RemoteCallFailed
+from cubicweb.web.formrenderers import FormRenderer
from cubicweb.web.controller import Controller
from cubicweb.web.views import vid_from_rset
try:
@@ -387,11 +388,15 @@
def js_prop_widget(self, propkey, varname, tabindex=None):
"""specific method for EProperty handling"""
- w = self.vreg.property_value_widget(propkey, req=self.req)
entity = self.vreg.etype_class('EProperty')(self.req, None, None)
entity.eid = varname
- self.req.form['value'] = self.vreg.property_info(propkey)['default']
- return w.edit_render(entity, tabindex, includehelp=True)
+ entity['pkey'] = propkey
+ entity['value'] = self.vreg.property_info(propkey)['default']
+ form = self.vreg.select_object('forms', 'edition', entity=entity)
+ vfield = form.field_by_name('value')
+ renderer = FormRenderer()
+ return (vfield.render(form, renderer, tabindex=tabindex)
+ + renderer.render_help(form, vfield))
def js_component(self, compid, rql, registry='components', extraargs=None):
if rql:
@@ -432,12 +437,11 @@
self.req.cancel_edition(errorurl)
@check_pageid
- def js_inline_creation_form(self, peid, ptype, ttype, rtype, role):
+ def js_inline_creation_form(self, peid, ttype, rtype, role):
view = self.vreg.select_view('inline-creation', self.req, None,
- etype=ttype, ptype=ptype, peid=peid,
- rtype=rtype, role=role)
- source = view.dispatch(etype=ttype, ptype=ptype, peid=peid, rtype=rtype,
- role=role)
+ etype=ttype, peid=peid, rtype=rtype,
+ role=role)
+ source = view.dispatch(etype=ttype, peid=peid, rtype=rtype, role=role)
return self._set_content_type(view, source)
def js_remove_pending_insert(self, (eidfrom, rel, eidto)):
--- 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)
+
--- a/web/widgets.py Wed Apr 08 20:37:55 2009 +0200
+++ b/web/widgets.py Wed Apr 08 20:38:34 2009 +0200
@@ -828,59 +828,6 @@
aurl = html_escape(entity.build_url('embed', url=url))
return u'<a href="%s">%s</a>' % (aurl, url)
-
-
-class PropertyKeyWidget(ComboBoxWidget):
- """specific widget for EProperty.pkey field to set the value widget according to
- the selected key
- """
-
- def _edit_render(self, entity):
- entity.req.add_js( ('cubicweb.ajax.js', 'cubicweb.edition.js') )
- vtabindex = self.attrs.get('tabindex', 0) + 1
- self.attrs['onchange'] = "javascript:setPropValueWidget('%s', %s)" % (
- entity.eid, vtabindex)
- # limit size
- if not entity.has_eid():
- self.attrs['size'] = 10
- else:
- self.attrs['size'] = 1
- return super(PropertyKeyWidget, self)._edit_render(entity)
-
- def vocabulary(self, entity):
- _ = entity.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 PropertyValueWidget(Widget):
- """specific widget for EProperty.value field which will be different according to
- the selected key type and vocabulary information
- """
-
- def render_help(self, entity):
- return u''
-
- def render(self, entity):
- assert entity.has_eid()
- w = self.vreg.property_value_widget(entity.pkey, req=entity.req, **self.attrs)
- return w.render(entity)
-
- def _edit_render(self, entity):
- if not entity.has_eid():
- # no key set yet, just include an empty div which will be filled
- # on key selection
- # empty span as well else html validation fail (label is refering to this id)
- return u'<div id="div:%s"><span id="%s"/></div>' % (self.rname, self.attrs.get('id'))
- w = self.vreg.property_value_widget(entity.pkey, req=entity.req, **self.attrs)
- if entity.pkey.startswith('system.'):
- value = '<span class="value" id="%s">%s</span>' % (self.attrs.get('id'), w.render(entity))
- msg = entity.req._('value associated to this key is not editable manually')
- return value + '<div>%s</div>' % msg
- return w.edit_render(entity, self.attrs.get('tabindex'), includehelp=True)
def widget_factory(vreg, subjschema, rschema, objschema, role='subject',