--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/views/cwproperties.py Tue Apr 28 16:21:54 2009 +0200
@@ -0,0 +1,329 @@
+"""Specific views for CWProperty
+
+:organization: Logilab
+:copyright: 2007-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
+"""
+__docformat__ = "restructuredtext en"
+
+from logilab.mtconverter import html_escape
+
+from logilab.common.decorators import cached
+
+from cubicweb import UnknownProperty
+from cubicweb.selectors import (one_line_rset, none_rset, implements,
+ match_user_groups, entity_implements)
+from cubicweb.utils import UStringIO
+from cubicweb.view import StartupView
+from cubicweb.web import INTERNAL_FIELD_VALUE, eid_param, uicfg
+from cubicweb.web.views import baseviews
+from cubicweb.web import stdmsgs
+from cubicweb.web.form import CompositeForm, EntityFieldsForm, FormViewMixIn
+from cubicweb.web.formfields import FIELDS, StringField
+from cubicweb.web.formwidgets import Select, Button, SubmitButton
+
+_ = unicode
+
+# some string we want to be internationalizable for nicer display of eproperty
+# groups
+_('navigation')
+_('ui')
+_('actions')
+_('boxes')
+_('components')
+_('contentnavigation')
+
+
+def make_togglable_link(nodeid, label, cookiename):
+ """builds a HTML link that switches the visibility & remembers it"""
+ action = u"javascript: toggle_and_remember_visibility('%s', '%s')" % \
+ (nodeid, cookiename)
+ return u'<a href="%s">%s</a>' % (action, label)
+
+def css_class(someclass):
+ return someclass and 'class="%s"' % someclass or ''
+
+
+class CWPropertyPrimaryView(baseviews.PrimaryView):
+ __select__ = implements('CWProperty')
+ skip_none = False
+
+
+class SystemEPropertiesForm(FormViewMixIn, StartupView):
+ id = 'systemepropertiesform'
+ __select__ = none_rset() & match_user_groups('managers')
+
+ title = _('site configuration')
+ category = 'startupview'
+
+ def linkable(self):
+ return True
+
+ def url(self):
+ """return the url associated with this view. We can omit rql here"""
+ return self.build_url('view', vid=self.id)
+
+ def _cookie_name(self, somestr):
+ 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)
+ if cookie is None:
+ cookies[cookiename] = default
+ self.req.set_cookie(cookies, cookiename, maxage=None)
+ status = default
+ else:
+ status = cookie.value
+ return status
+
+ def call(self, **kwargs):
+ """The default view representing the application's index"""
+ self.req.add_js('cubicweb.preferences.js')
+ self.req.add_css('cubicweb.preferences.css')
+ vreg = self.vreg
+ values = self.defined_keys
+ groupedopts = {}
+ mainopts = {}
+ # "self.id=='systemepropertiesform'" to skip site wide properties on
+ # user's preference but not site's configuration
+ for key in vreg.user_property_keys(self.id=='systemepropertiesform'):
+ parts = key.split('.')
+ if parts[0] in vreg:
+ # appobject configuration
+ reg, oid, propid = parts
+ groupedopts.setdefault(reg, {}).setdefault(oid, []).append(key)
+ else:
+ mainopts.setdefault(parts[0], []).append(key)
+ # precompute form to consume error message
+ for group, keys in mainopts.items():
+ 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))
+ # we don't want this in each sub-forms
+ w(u'<div id="progress">%s</div>' % self.req._('validating...'))
+ for label, group, form in sorted((_(g), g, f)
+ for g, f in mainopts.iteritems()):
+ 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))))
+ w(u'<div id="fieldset_%s" %s>' % (group, status))
+ w(form)
+ w(u'</div>')
+ for label, group, objects in sorted((_(g), g, o)
+ for g, o in groupedopts.iteritems()):
+ 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))))
+ w(u'<div id="fieldset_%s" %s>' % (group, status))
+ for label, oid, form in sorted((self.req.__('%s_%s' % (group, o)), o, f)
+ for o, f in objects.iteritems()):
+ w(u'<fieldset class="subentity">')
+ w(u'<legend class="componentTitle">%s</legend>\n' % label)
+ docmsgid = '%s_%s_description' % (group, oid)
+ doc = _(docmsgid)
+ if doc != docmsgid:
+ w(u'<p class="description">%s</p>' % html_escape(doc))
+ w(form)
+ w(u'</fieldset>')
+ w(u'</div>')
+
+ @property
+ @cached
+ def eprops_rset(self):
+ return self.req.execute('Any P,K,V WHERE P is CWProperty, P pkey K, '
+ 'P value V, NOT P for_user U')
+
+ @property
+ def defined_keys(self):
+ values = {}
+ for i, entity in enumerate(self.eprops_rset.entities()):
+ values[entity.pkey] = i
+ return values
+
+ def entity_for_key(self, key):
+ values = self.defined_keys
+ if key in values:
+ entity = self.eprops_rset.get_entity(values[key], 0)
+ else:
+ entity = self.vreg.etype_class('CWProperty')(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):
+ 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)
+ 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(display_progress_div=False)
+
+ def form_row(self, form, key, splitlabel):
+ entity = self.entity_for_key(key)
+ if splitlabel:
+ label = key.split('.')[-1]
+ else:
+ 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):
+ return req.user.eid == rset[row or 0][col]
+
+
+class EPropertiesForm(SystemEPropertiesForm):
+ id = 'epropertiesform'
+ __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'))))
+ )
+
+ title = _('preferences')
+
+ @property
+ def user(self):
+ if self.rset is None:
+ return self.req.user
+ return self.rset.get_entity(self.row or 0, self.col or 0)
+
+ @property
+ @cached
+ def eprops_rset(self):
+ return self.req.execute('Any P,K,V WHERE P is CWProperty, P pkey K, P value V,'
+ 'P for_user U, U eid %(x)s', {'x': self.user.eid})
+
+ 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 subform.edited_entity.has_eid() and self.user.matching_groups('managers'):
+ subform.form_add_hidden('for_user', self.user.eid, eidparam=True)
+
+
+# eproperty form objects ######################################################
+
+class PlaceHolderWidget(object):
+
+ def render(self, form, field):
+ domid = form.context[field]['id']
+ # empty span as well else html validation fail (label is refering to
+ # this id)
+ return '<div id="div:%s"><span id="%s">%s</span></div>' % (
+ domid, domid, form.req._('select a key first'))
+
+
+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 PropertyKeyField(StringField):
+ """specific field for CWProperty.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 [(u'', u'')] + sorted(zip((_(v) for v in choices), choices))
+
+
+class PropertyValueField(StringField):
+ """specific field for CWProperty.value which will be different according to
+ the selected key type and vocabulary information
+ """
+ widget = PlaceHolderWidget
+
+ def render(self, form, renderer=None, tabindex=None):
+ 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
+ if not (entity.has_eid() or 'pkey' in entity):
+ # no key set yet, just include an empty div which will be filled
+ # on key selection
+ return
+ 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 CWPropertyForm, 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
+
+uicfg.rfields.set_rtag(PropertyKeyField, 'pkey', 'subject', 'CWProperty')
+uicfg.rfields.set_rtag(PropertyValueField, 'value', 'subject', 'CWProperty')
+
--- a/web/views/eproperties.py Tue Apr 28 16:21:32 2009 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,329 +0,0 @@
-"""Specific views for CWProperty
-
-:organization: Logilab
-:copyright: 2007-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
-:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
-"""
-__docformat__ = "restructuredtext en"
-
-from logilab.mtconverter import html_escape
-
-from logilab.common.decorators import cached
-
-from cubicweb import UnknownProperty
-from cubicweb.selectors import (one_line_rset, none_rset, implements,
- match_user_groups, entity_implements)
-from cubicweb.utils import UStringIO
-from cubicweb.view import StartupView
-from cubicweb.web import INTERNAL_FIELD_VALUE, eid_param, uicfg
-from cubicweb.web.views import baseviews
-from cubicweb.web import stdmsgs
-from cubicweb.web.form import CompositeForm, EntityFieldsForm, FormViewMixIn
-from cubicweb.web.formfields import FIELDS, StringField
-from cubicweb.web.formwidgets import Select, Button, SubmitButton
-
-_ = unicode
-
-# some string we want to be internationalizable for nicer display of eproperty
-# groups
-_('navigation')
-_('ui')
-_('actions')
-_('boxes')
-_('components')
-_('contentnavigation')
-
-
-def make_togglable_link(nodeid, label, cookiename):
- """builds a HTML link that switches the visibility & remembers it"""
- action = u"javascript: toggle_and_remember_visibility('%s', '%s')" % \
- (nodeid, cookiename)
- return u'<a href="%s">%s</a>' % (action, label)
-
-def css_class(someclass):
- return someclass and 'class="%s"' % someclass or ''
-
-
-class CWPropertyPrimaryView(baseviews.PrimaryView):
- __select__ = implements('CWProperty')
- skip_none = False
-
-
-class SystemEPropertiesForm(FormViewMixIn, StartupView):
- id = 'systemepropertiesform'
- __select__ = none_rset() & match_user_groups('managers')
-
- title = _('site configuration')
- category = 'startupview'
-
- def linkable(self):
- return True
-
- def url(self):
- """return the url associated with this view. We can omit rql here"""
- return self.build_url('view', vid=self.id)
-
- def _cookie_name(self, somestr):
- 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)
- if cookie is None:
- cookies[cookiename] = default
- self.req.set_cookie(cookies, cookiename, maxage=None)
- status = default
- else:
- status = cookie.value
- return status
-
- def call(self, **kwargs):
- """The default view representing the application's index"""
- self.req.add_js('cubicweb.preferences.js')
- self.req.add_css('cubicweb.preferences.css')
- vreg = self.vreg
- values = self.defined_keys
- groupedopts = {}
- mainopts = {}
- # "self.id=='systemepropertiesform'" to skip site wide properties on
- # user's preference but not site's configuration
- for key in vreg.user_property_keys(self.id=='systemepropertiesform'):
- parts = key.split('.')
- if parts[0] in vreg:
- # appobject configuration
- reg, oid, propid = parts
- groupedopts.setdefault(reg, {}).setdefault(oid, []).append(key)
- else:
- mainopts.setdefault(parts[0], []).append(key)
- # precompute form to consume error message
- for group, keys in mainopts.items():
- 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))
- # we don't want this in each sub-forms
- w(u'<div id="progress">%s</div>' % self.req._('validating...'))
- for label, group, form in sorted((_(g), g, f)
- for g, f in mainopts.iteritems()):
- 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))))
- w(u'<div id="fieldset_%s" %s>' % (group, status))
- w(form)
- w(u'</div>')
- for label, group, objects in sorted((_(g), g, o)
- for g, o in groupedopts.iteritems()):
- 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))))
- w(u'<div id="fieldset_%s" %s>' % (group, status))
- for label, oid, form in sorted((self.req.__('%s_%s' % (group, o)), o, f)
- for o, f in objects.iteritems()):
- w(u'<fieldset class="subentity">')
- w(u'<legend class="componentTitle">%s</legend>\n' % label)
- docmsgid = '%s_%s_description' % (group, oid)
- doc = _(docmsgid)
- if doc != docmsgid:
- w(u'<p class="description">%s</p>' % html_escape(doc))
- w(form)
- w(u'</fieldset>')
- w(u'</div>')
-
- @property
- @cached
- def eprops_rset(self):
- return self.req.execute('Any P,K,V WHERE P is CWProperty, P pkey K, '
- 'P value V, NOT P for_user U')
-
- @property
- def defined_keys(self):
- values = {}
- for i, entity in enumerate(self.eprops_rset.entities()):
- values[entity.pkey] = i
- return values
-
- def entity_for_key(self, key):
- values = self.defined_keys
- if key in values:
- entity = self.eprops_rset.get_entity(values[key], 0)
- else:
- entity = self.vreg.etype_class('CWProperty')(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):
- 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)
- 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(display_progress_div=False)
-
- def form_row(self, form, key, splitlabel):
- entity = self.entity_for_key(key)
- if splitlabel:
- label = key.split('.')[-1]
- else:
- 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):
- return req.user.eid == rset[row or 0][col]
-
-
-class EPropertiesForm(SystemEPropertiesForm):
- id = 'epropertiesform'
- __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'))))
- )
-
- title = _('preferences')
-
- @property
- def user(self):
- if self.rset is None:
- return self.req.user
- return self.rset.get_entity(self.row or 0, self.col or 0)
-
- @property
- @cached
- def eprops_rset(self):
- return self.req.execute('Any P,K,V WHERE P is CWProperty, P pkey K, P value V,'
- 'P for_user U, U eid %(x)s', {'x': self.user.eid})
-
- 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 subform.edited_entity.has_eid() and self.user.matching_groups('managers'):
- subform.form_add_hidden('for_user', self.user.eid, eidparam=True)
-
-
-# eproperty form objects ######################################################
-
-class PlaceHolderWidget(object):
-
- def render(self, form, field):
- domid = form.context[field]['id']
- # empty span as well else html validation fail (label is refering to
- # this id)
- return '<div id="div:%s"><span id="%s">%s</span></div>' % (
- domid, domid, form.req._('select a key first'))
-
-
-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 PropertyKeyField(StringField):
- """specific field for CWProperty.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 [(u'', u'')] + sorted(zip((_(v) for v in choices), choices))
-
-
-class PropertyValueField(StringField):
- """specific field for CWProperty.value which will be different according to
- the selected key type and vocabulary information
- """
- widget = PlaceHolderWidget
-
- def render(self, form, renderer=None, tabindex=None):
- 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
- if not (entity.has_eid() or 'pkey' in entity):
- # no key set yet, just include an empty div which will be filled
- # on key selection
- return
- 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 CWPropertyForm, 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
-
-uicfg.rfields.set_rtag(PropertyKeyField, 'pkey', 'subject', 'CWProperty')
-uicfg.rfields.set_rtag(PropertyValueField, 'value', 'subject', 'CWProperty')
-