--- a/web/uicfg.py Thu Apr 30 00:41:10 2009 +0200
+++ b/web/uicfg.py Thu Apr 30 00:41:52 2009 +0200
@@ -12,6 +12,48 @@
from cubicweb.rtags import RelationTags, RelationTagsSet
+# primary view configuration ##################################################
+
+# how to display a relation in primary view.
+# values a dict with the following keys:
+#
+# 'where', whose value may be one of:
+# * 'attributes', display in the attributes section
+# * 'relations', display in the relations section (below attributes)
+# * 'sideboxes', display in the side boxes (beside attributes)
+# if this key is missing, the relation won't be displayed at all.
+#
+# 'vid' is an optional view identifier
+#
+# 'label' is an optional label
+#
+# 'limit' is a boolean telling if the results should be limited according to
+# the configuration
+class RDisplayRelationTags(RelationTags):
+ def __init__(self):
+ super(RDisplayRelationTags, self).__init__()
+ self._counter = 0
+
+ def tag_relation(self, values, *args, **kwargs):
+ super(RDisplayRelationTags, self).tag_relation(values, *args, **kwargs)
+ if values:
+ values['order'] = self.get_timestamp()
+
+ def get_timestamp(self):
+ self._counter += 1
+ return self._counter
+
+rdisplay = RDisplayRelationTags()
+for rtype in ('eid', 'creation_date', 'modification_date',
+ 'is', 'is_instance_of', 'identity',
+ 'owned_by', 'created_by',
+ 'in_state', 'wf_info_for', 'require_permission',
+ 'from_entity', 'to_entity',
+ 'see_also'):
+ rdisplay.tag_relation({}, ('*', rtype, '*'), 'subject')
+ rdisplay.tag_relation({}, ('*', rtype, '*'), 'object')
+
+
# autoform.AutomaticEntityForm configuration ##################################
# relations'category (eg primary/secondary/generic/metadata/generated)
--- a/web/views/basecomponents.py Thu Apr 30 00:41:10 2009 +0200
+++ b/web/views/basecomponents.py Thu Apr 30 00:41:52 2009 +0200
@@ -16,7 +16,7 @@
from cubicweb.schema import display_name
from cubicweb.web.htmlwidgets import MenuWidget, PopupBoxMenu, BoxSeparator, BoxLink
-from cubicweb.web.component import Component, RelatedObjectsVComponent
+from cubicweb.web import uicfg, component
_ = unicode
@@ -25,7 +25,7 @@
help=_('display the component or not')),
}
-class RQLInputForm(Component):
+class RQLInputForm(component.Component):
"""build the rql input form, usually displayed in the header"""
id = 'rqlinput'
property_defs = VISIBLE_PROP_DEF
@@ -54,7 +54,7 @@
self.w(u'</form></div>')
-class ApplLogo(Component):
+class ApplLogo(component.Component):
"""build the application logo, usually displayed in the header"""
id = 'logo'
property_defs = VISIBLE_PROP_DEF
@@ -66,7 +66,7 @@
% (self.req.base_url(), self.req.external_resource('LOGO')))
-class ApplHelp(Component):
+class ApplHelp(component.Component):
"""build the help button, usually displayed in the header"""
id = 'help'
property_defs = VISIBLE_PROP_DEF
@@ -76,7 +76,7 @@
self.req._(u'help'),))
-class UserLink(Component):
+class UserLink(component.Component):
"""if the user is the anonymous user, build a link to login
else a link to the connected user object with a loggout link
"""
@@ -120,7 +120,7 @@
% (self.build_url('login'), self.req._('login')))
-class ApplicationMessage(Component):
+class ApplicationMessage(component.Component):
"""display application's messages given using the __message parameter
into a special div section
"""
@@ -141,7 +141,7 @@
self.w(u'</div>')
-class ApplicationName(Component):
+class ApplicationName(component.Component):
"""display the application name"""
id = 'appliname'
property_defs = VISIBLE_PROP_DEF
@@ -151,19 +151,22 @@
self.req.property_value('ui.site-title')))
-class SeeAlsoVComponent(RelatedObjectsVComponent):
+uicfg.rdisplay.tag_relation({}, ('*', 'see_also', '*'), 'subject')
+uicfg.rdisplay.tag_relation({}, ('*', 'see_also', '*'), 'object')
+
+class SeeAlsoVComponent(component.RelatedObjectsVComponent):
"""display any entity's see also"""
id = 'seealso'
context = 'navcontentbottom'
rtype = 'see_also'
- target = 'object'
+ role = 'subject'
order = 40
# register msg not generated since no entity use see_also in cubicweb itself
title = _('contentnavigation_seealso')
help = _('contentnavigation_seealso_description')
-class EtypeRestrictionComponent(Component):
+class EtypeRestrictionComponent(component.Component):
"""displays the list of entity types contained in the resultset
to be able to filter accordingly.
"""
--- a/web/views/baseviews.py Thu Apr 30 00:41:10 2009 +0200
+++ b/web/views/baseviews.py Thu Apr 30 00:41:52 2009 +0200
@@ -373,7 +373,6 @@
from cubicweb.web.views import boxes, xmlrss, primary
PrimaryView = class_moved(primary.PrimaryView)
-PRIMARY_SKIP_RELS = primary.PRIMARY_SKIP_RELS
SideBoxView = class_moved(boxes.SideBoxView)
XmlView = class_moved(xmlrss.XmlView)
XmlItemView = class_moved(xmlrss.XmlItemView)
--- a/web/views/cwuser.py Thu Apr 30 00:41:10 2009 +0200
+++ b/web/views/cwuser.py Thu Apr 30 00:41:52 2009 +0200
@@ -26,6 +26,8 @@
uicfg.rmode.tag_relation('link', ('*', 'owned_by', 'CWUser'), 'object')
uicfg.rmode.tag_relation('link', ('*', 'created_by', 'CWUser'), 'object')
uicfg.rmode.tag_relation('create', ('*', 'bookmarked_by', 'CWUser'), 'object')
+uicfg.rdisplay.tag_attribute({}, 'CWUser', 'firstname')
+uicfg.rdisplay.tag_attribute({}, 'CWUser', 'surname')
class UserPreferencesEntityAction(action.Action):
@@ -44,23 +46,9 @@
class CWUserPrimaryView(PrimaryView):
__select__ = implements('CWUser')
- skip_attrs = ('firstname', 'surname')
-
- def iter_relations(self, entity):
- # don't want to display user's entities
- for rschema, targetschemas, x in super(CWUserPrimaryView, self).iter_relations(entity):
- if x == 'object' and rschema.type in ('owned_by', 'for_user'):
- continue
- yield rschema, targetschemas, x
-
def content_title(self, entity):
return entity.name()
- def is_side_related(self, rschema, eschema):
- # XXX only bookmarked_by defined in cw...
- return rschema.type in ['interested_in', 'tags',
- 'todo_by', 'bookmarked_by']
-
class FoafView(EntityView):
id = 'foaf'
--- a/web/views/emailaddress.py Thu Apr 30 00:41:10 2009 +0200
+++ b/web/views/emailaddress.py Thu Apr 30 00:41:52 2009 +0200
@@ -20,7 +20,7 @@
self.skipeids = skipeids
super(EmailAddressPrimaryView, self).cell_call(row, col)
- def render_entity_attributes(self, entity, siderelations):
+ def render_entity_attributes(self, entity):
self.w(u'<h3>')
entity.view('oneline', w=self.w)
if not entity.canonical:
@@ -53,7 +53,7 @@
emailofstr = ', '.join(e.view('oneline') for e in emailof)
self.field(display_name(self.req, 'use_email', 'object'), emailofstr)
- def render_entity_relations(self, entity, siderelations):
+ def render_entity_relations(self, entity):
for i, email in enumerate(entity.related_emails(self.skipeids)):
self.w(u'<div class="%s">' % (i%2 and 'even' or 'odd'))
email.view('oneline', w=self.w, contexteid=entity.eid)
@@ -64,7 +64,8 @@
__select__ = implements('EmailAddress')
id = 'shortprimary'
title = None # hidden view
- def render_entity_attributes(self, entity, siderelations):
+
+ def render_entity_attributes(self, entity):
self.w(u'<h5>')
entity.view('oneline', w=self.w)
self.w(u'</h5>')
--- a/web/views/idownloadable.py Thu Apr 30 00:41:10 2009 +0200
+++ b/web/views/idownloadable.py Thu Apr 30 00:41:52 2009 +0200
@@ -94,19 +94,11 @@
self.w(u'<a href="%s">%s</a>' % (url, html_escape(title or entity.dc_title())))
-
class IDownloadablePrimaryView(baseviews.PrimaryView):
__select__ = implements(IDownloadable)
- # XXX File/Image attributes but this is not specified in the IDownloadable interface
- skip_attrs = baseviews.PrimaryView.skip_attrs + ('data', 'name')
- def render_entity_title(self, entity):
- self.w(u'<h1>%s %s</h1>'
- % (entity.dc_type().capitalize(),
- html_escape(entity.dc_title())))
-
- def render_entity_attributes(self, entity, siderelations):
- super(IDownloadablePrimaryView, self).render_entity_attributes(entity, siderelations)
+ def render_entity_attributes(self, entity):
+ super(IDownloadablePrimaryView, self).render_entity_attributes(entity)
self.w(u'<div class="content">')
contenttype = entity.download_content_type()
if contenttype.startswith('image/'):
@@ -123,10 +115,6 @@
self.w('<div class="error">%s</div>' % msg)
self.w(u'</div>')
- def is_side_related(self, rschema, eschema):
- """display all relations as side related"""
- return True
-
class IDownloadableLineView(baseviews.OneLineView):
__select__ = implements(IDownloadable)
--- a/web/views/primary.py Thu Apr 30 00:41:10 2009 +0200
+++ b/web/views/primary.py Thu Apr 30 00:41:52 2009 +0200
@@ -4,19 +4,18 @@
:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
"""
+__docformat__ = "restructuredtext en"
from warnings import warn
+from logilab.mtconverter import html_escape
+
from cubicweb import Unauthorized
from cubicweb.view import EntityView
+from cubicweb.web.uicfg import rdisplay
_ = unicode
-PRIMARY_SKIP_RELS = set(['is', 'is_instance_of', 'identity',
- 'owned_by', 'created_by',
- 'in_state', 'wf_info_for', 'require_permission',
- 'from_entity', 'to_entity',
- 'see_also'])
class PrimaryView(EntityView):
"""the full view of an non final entity"""
@@ -25,10 +24,44 @@
show_attr_label = True
show_rel_label = True
skip_none = True
- skip_attrs = ('eid', 'creation_date', 'modification_date')
- skip_rels = ()
+ rdisplay = rdisplay
main_related_section = True
+ @classmethod
+ def vreg_initialization_completed(cls):
+ """set default category tags for relations where it's not yet defined in
+ the category relation tags
+ """
+ for eschema in cls.schema.entities():
+ for rschema, tschemas, role in eschema.relation_definitions(True):
+ for tschema in tschemas:
+ if role == 'subject':
+ X, Y = eschema, tschema
+ card = rschema.rproperty(X, Y, 'cardinality')[0]
+ composed = rschema.rproperty(X, Y, 'composite') == 'object'
+ else:
+ X, Y = tschema, eschema
+ card = rschema.rproperty(X, Y, 'cardinality')[1]
+ composed = rschema.rproperty(X, Y, 'composite') == 'subject'
+ displayinfo = cls.rdisplay.get(rschema, role, X, Y)
+ if displayinfo is None:
+ if rschema.is_final():
+ if rschema.meta or tschema.type in ('Password', 'Bytes'):
+ where = None
+ else:
+ where = 'attributes'
+ elif card in '1+':
+ where = 'attributes'
+ elif composed:
+ where = 'relations'
+ else:
+ where = 'sideboxes'
+ displayinfo = {'where': where,
+ 'order': cls.rdisplay.get_timestamp()}
+ cls.rdisplay.tag_relation(displayinfo, (X, rschema, Y),
+ role)
+ displayinfo.setdefault('label', '%s_%s' % (rschema, role))
+
def html_headers(self):
"""return a list of html headers (eg something to be inserted between
<head> and </head> of the returned page
@@ -41,6 +74,7 @@
self.row = row
# XXX move render_entity implementation here
self.render_entity(self.complete_entity(row, col))
+ self.maxrelated = self.req.property_value('navigation.related-limit')
def render_entity(self, entity):
"""return html to display the given entity"""
@@ -48,8 +82,8 @@
self.render_entity_metadata(entity)
# entity's attributes and relations, excluding meta data
# if the entity isn't meta itself
- boxes = self._preinit_side_related(entity)
- if boxes:
+ boxes = self._prepare_side_boxes(entity)
+ if boxes or hasattr(self, 'render_side_related'):
self.w(u'<table width="100%"><tr><td width="75%">')
self.w(u'<div>')
self.w(u'<div class="mainInfo">')
@@ -69,16 +103,14 @@
'deprecated')
self.render_entity_relations(entity, [])
self.w(u'</div>')
- if boxes:
+ if boxes or hasattr(self, 'render_side_related'):
self.w(u'</td><td>')
# side boxes
self.w(u'<div class="primaryRight">')
- try:
- self.render_side_related(entity)
- except TypeError: # XXX bw compat
- warn('siderelations argument of render_entity_relations is '
- 'deprecated')
- self.render_entity_relations(entity, [])
+ if hasattr(self, 'render_side_related'):
+ warn('render_side_related is deprecated')
+ self.render_side_related(entity, [])
+ self.render_side_boxes(boxes)
self.w(u'</div>')
self.w(u'</td></tr></table>')
self.content_navigation_components('navcontentbottom')
@@ -97,29 +129,16 @@
comp.dispatch(w=self.w, view=self)
self.w(u'</div>')
- def iter_attributes(self, entity):
- for rschema, targetschema in entity.e_schema.attribute_definitions():
- if rschema.type in self.skip_attrs:
- continue
- yield rschema, targetschema
-
- def iter_relations(self, entity):
- skip = set(self.skip_rels)
- skip.update(PRIMARY_SKIP_RELS)
- for rschema, targetschemas, x in entity.e_schema.relation_definitions():
- if rschema.type in skip:
- continue
- yield rschema, targetschemas, x
-
def render_entity_title(self, entity):
title = self.content_title(entity) # deprecate content_title?
if title:
self.w(u'<h1><span class="etype">%s</span> %s</h1>'
% (entity.dc_type().capitalize(), title))
+
def content_title(self, entity):
- """default implementation return an empty string"""
- return u''
+ """default implementation return dc_title"""
+ return html_escape(entity.dc_title())
def render_entity_metadata(self, entity):
entity.view('metadata', w=self.w)
@@ -132,67 +151,39 @@
return u''
def render_entity_attributes(self, entity, siderelations=None):
- for rschema, targetschema in self.iter_attributes(entity):
- attr = rschema.type
- if targetschema.type in ('Password', 'Bytes'):
- continue
- try:
- wdg = entity.get_widget(attr)
- except Exception, ex:
- value = entity.printable_value(attr, entity[attr], targetschema.type)
+ for rschema, tschemas, role, displayinfo in self._iter_display(entity, 'attributes'):
+ vid = displayinfo.get('vid', 'reledit')
+ if rschema.is_final():
+ value = entity.view('reledit', rtype=rschema.type)
else:
- value = wdg.render(entity)
+ vid = displayinfo.get('vid', 'reledit')
+ rset = self._relation_rset(entity, rschema, role, displayinfo)
+ if rset:
+ value = self.view(rset, vid)
+ else:
+ value = None
if self.skip_none and (value is None or value == ''):
continue
- if rschema.meta:
- continue
- self._render_related_entities(entity, rschema, value)
-
- def _preinit_side_related(self, entity):
- self._sideboxes = []
- if hasattr(self, 'get_side_boxes_defs'):
- self._sideboxes = [(label, rset, 'sidebox') for label, rset in self.get_side_boxes_defs(entity)
- if rset]
- else:
- eschema = entity.e_schema
- maxrelated = self.req.property_value('navigation.related-limit')
- for rschema, targetschemas, role in self.iter_relations(entity):
- if self.is_side_related(rschema, eschema):
- try:
- related = entity.related(rschema.type, role, limit=maxrelated+1)
- except Unauthorized:
- continue
- if not related:
- continue
- label = display_name(self.req, rschema.type, role)
- self._sideboxes.append((label, related, 'autolimited'))
- self._contextboxes = list(self.vreg.possible_vobjects('boxes', self.req, self.rset,
- row=self.row, view=self,
- context='incontext'))
- return self._sideboxes or self._contextboxes
+ self._render_attribute(rschema, value)
def render_entity_relations(self, entity, siderelations=None):
- eschema = entity.e_schema
- for rschema, targetschemas, x in self.iter_relations(entity):
- if not self.is_side_related(rschema, eschema):
- try:
- related = entity.related(rschema.type, x, limit=maxrelated+1)
- except Unauthorized:
- continue
- self._render_related_entities(entity, rschema, related, x)
+ for rschema, tschemas, role, displayinfo in self._iter_display(entity, 'relations'):
+ rset = self._relation_rset(entity, rschema, role, displayinfo)
+ if rset:
+ self._render_relation(rset, displayinfo, 'autolimited',
+ self.show_rel_label)
-
- def render_side_related(self, entity, siderelations=None):
+ def render_side_boxes(self, boxes):
"""display side related relations:
non-meta in a first step, meta in a second step
"""
- if self._sideboxes:
- for label, rset, vid in self._sideboxes:
+ for box in boxes:
+ if isinstance(box, tuple):
+ label, rset, vid, _ = box
self.w(u'<div class="sideRelated">')
self.wview(vid, rset, title=label)
self.w(u'</div>')
- if self._contextboxes:
- for box in self._contextboxes:
+ else:
try:
box.dispatch(w=self.w, row=self.row)
except NotImplementedError:
@@ -200,28 +191,73 @@
# .call() and not cell_call()
box.dispatch(w=self.w)
- def is_side_related(self, rschema, eschema):
- return rschema.meta and \
- not rschema.schema_relation() == eschema.schema_entity()
+ def _prepare_side_boxes(self, entity):
+ sideboxes = []
+ for rschema, tschemas, role, displayinfo in self._iter_display(entity, 'sideboxes'):
+ rset = self._relation_rset(entity, rschema, role, displayinfo)
+ if not rset:
+ continue
+ label = display_name(self.req, rschema.type, role)
+ vid = displayinfo.get('vid', 'autolimited')
+ sideboxes.append((label, rset, vid, displayinfo.get('order')))
+ sideboxes = sorted(sideboxes, key=lambda x: x[-1])
+ sideboxes += list(self.vreg.possible_vobjects('boxes', self.req, self.rset,
+ row=self.row, view=self,
+ context='incontext'))
+ return sideboxes
- def _render_related_entities(self, entity, rschema, related,
- role='subject'):
+ def _iter_display(self, entity, where):
+ eschema = entity.e_schema
+ for rschema, tschemas, role in eschema.relation_definitions(True):
+ matchtschemas = []
+ for tschema in tschemas:
+ displayinfo = self.rdisplay.etype_get(eschema, rschema, role,
+ tschema)
+ assert displayinfo is not None, (str(rschema), role,
+ str(eschema), str(tschema))
+ if displayinfo.get('where') == where:
+ matchtschemas.append(tschema)
+ if matchtschemas:
+ # XXX pick the latest displayinfo
+ yield rschema, matchtschemas, role, displayinfo
+
+ def _relation_rset(self, entity, rschema, role, displayinfo):
+ try:
+ if displayinfo.get('limit'):
+ rset = entity.related(rschema.type, role,
+ limit=self.maxrelated+1)
+ else:
+ rset = entity.related(rschema.type, role)
+ except Unauthorized:
+ return
+ if 'filter' in displayinfo:
+ rset = displayinfo['filter'](rset)
+ return rset
+
+ def _render_relation(self, rset, displayinfo, defaultvid, showlabel):
+ self.w('<div class="section">')
+ if showlabel:
+ label = self.req._(displayinfo['label'])
+ self.w('<h4>%s</h4>' % label)
+ self.wview(displayinfo.get('vid', defaultvid), rset)
+ self.w('</div>')
+
+ def _render_attribute(self, rschema, value, role='subject'):
if rschema.is_final():
- value = related
show_label = self.show_attr_label
else:
- if not related:
- return
- value = self.view('autolimited', related)
+ show_label = self.show_rel_label
label = display_name(self.req, rschema.type, role)
self.field(label, value, show_label=show_label, tr=False)
class RelatedView(EntityView):
id = 'autolimited'
- def call(self):
+ def call(self, title=None, **kwargs):
# if not too many entities, show them all in a list
maxrelated = self.req.property_value('navigation.related-limit')
+ if title:
+ self.w(u'<div class="title"><span>%s</span></div>' % title)
if self.rset.rowcount <= maxrelated:
if self.rset.rowcount == 1:
self.wview('incontext', self.rset, row=0)
@@ -234,7 +270,7 @@
# else show links to display related entities
else:
rql = self.rset.printable_rql()
- self.rset.limit(maxself.rset)
+ self.rset.limit(maxrelated)
self.w(u'<div>')
self.wview('simplelist', self.rset)
self.w(u'[<a href="%s">%s</a>]' % (self.build_url(rql=rql),
--- a/web/views/schema.py Thu Apr 30 00:41:10 2009 +0200
+++ b/web/views/schema.py Thu Apr 30 00:41:52 2009 +0200
@@ -16,7 +16,7 @@
from cubicweb.view import EntityView, StartupView
from cubicweb.common.uilib import ureport_as_html
from cubicweb.web import uicfg, action
-from cubicweb.web.views import TmpFileViewMixin, baseviews
+from cubicweb.web.views import TmpFileViewMixin, primary, baseviews
uicfg.rcategories.tag_relation('primary', ('CWPermission', 'require_group', '*'), 'subject')
@@ -33,6 +33,11 @@
uicfg.rmode.tag_relation('link', ('*', 'from_entity', 'CWEType'), 'object')
uicfg.rmode.tag_relation('link', ('*', 'to_entity', 'CWEType'), 'object')
+for attr in ('name', 'meta', 'final'):
+ uicfg.rdisplay.tag_attribute({}, 'CWRType', attr)
+for attr in ('name', 'meta', 'final', 'symetric', 'inlined'):
+ uicfg.rdisplay.tag_attribute({}, 'CWRType', attr)
+
class ViewSchemaAction(action.Action):
id = 'schema'
@@ -48,25 +53,13 @@
# schema entity types views ###################################################
-class _SchemaEntityPrimaryView(baseviews.PrimaryView):
- show_attr_label = False
+class CWRDEFPrimaryView(primary.PrimaryView):
+ __select__ = implements('CWAttribute', 'CWRelation')
cache_max_age = 60*60*2 # stay in http cache for 2 hours by default
def content_title(self, entity):
return html_escape(entity.dc_long_title())
-class CWETypePrimaryView(_SchemaEntityPrimaryView):
- __select__ = implements('CWEType')
- skip_attrs = _SchemaEntityPrimaryView.skip_attrs + ('name', 'meta', 'final')
-
-class CWRTypePrimaryView(_SchemaEntityPrimaryView):
- __select__ = implements('CWRType')
- skip_attrs = _SchemaEntityPrimaryView.skip_attrs + ('name', 'meta', 'final',
- 'symetric', 'inlined')
-
-class ErdefPrimaryView(_SchemaEntityPrimaryView):
- __select__ = implements('CWAttribute', 'CWRelation')
- show_attr_label = True
class CWETypeOneLineView(baseviews.OneLineView):
__select__ = implements('CWEType')
@@ -82,13 +75,15 @@
# in memory schema views (yams class instances) ###############################
+SKIPPED_RELS = ('is', 'is_instance_of', 'identity', 'created_by', 'owned_by',
+ 'has_text',)
-class CWETypeSchemaView(CWETypePrimaryView):
+class CWETypeSchemaView(primary.PrimaryView):
id = 'eschema'
+ __select__ = implements('CWEType')
title = _('in memory entity schema')
main_related_section = False
- skip_rels = ('is', 'is_instance_of', 'identity', 'created_by', 'owned_by',
- 'has_text',)
+ skip_rels = SKIPPED_RELS
def render_entity_attributes(self, entity, siderelations):
super(CWETypeSchemaView, self).render_entity_attributes(entity, siderelations)
@@ -102,8 +97,9 @@
html_escape(self.req._('graphical schema for %s') % entity.name)))
-class CWRTypeSchemaView(CWRTypePrimaryView):
+class CWRTypeSchemaView(primary.PrimaryView):
id = 'eschema'
+ __select__ = implements('CWRType')
title = _('in memory relation schema')
main_related_section = False
@@ -198,8 +194,9 @@
class SchemaImageView(TmpFileViewMixin, StartupView):
id = 'schemagraph'
+
content_type = 'image/png'
- skip_rels = ('owned_by', 'created_by', 'identity', 'is', 'is_instance_of')
+ skip_rels = SKIPPED_RELS
def _generate(self, tmpfile):
"""display global schema information"""
skipmeta = not int(self.req.form.get('withmeta', 0))
@@ -209,9 +206,10 @@
class CWETypeSchemaImageView(TmpFileViewMixin, EntityView):
id = 'eschemagraph'
+ __select__ = implements('CWEType')
+
content_type = 'image/png'
- __select__ = implements('CWEType')
- skip_rels = ('owned_by', 'created_by', 'identity', 'is', 'is_instance_of')
+ skip_rels = SKIPPED_RELS
def _generate(self, tmpfile):
"""display schema information for an entity"""
--- a/web/widgets.py Thu Apr 30 00:41:10 2009 +0200
+++ b/web/widgets.py Thu Apr 30 00:41:52 2009 +0200
@@ -63,7 +63,7 @@
autoid = True
html_attributes = set(('id', 'class', 'tabindex', 'accesskey', 'onchange', 'onkeypress'))
cubicwebns_attributes = set()
-
+
def __init__(self, vreg, subjschema, rschema, objschema,
role='subject', description=None,
**kwattrs):
@@ -83,12 +83,12 @@
because widget instances are cached)
"""
# brute force copy (subclasses don't have the
- # same __init__ prototype)
+ # same __init__ prototype)
widget = self.__new__(self.__class__)
widget.__dict__ = dict(self.__dict__)
widget.attrs = dict(widget.attrs)
return widget
-
+
@staticmethod
def size_constraint_attrs(attrs, maxsize):
"""set html attributes in the attrs dict to consider maxsize"""
@@ -105,7 +105,7 @@
elif name in self.html_attributes:
attrs.append(u'%s="%s"' % (name, value))
return u' '.join(sorted(attrs))
-
+
def required(self, entity):
"""indicates if the widget needs a value to be filled in"""
card = self.rschema.cardinality(self.subjtype, self.objtype, self.role)
@@ -116,7 +116,7 @@
return self.rname
except AttributeError:
return eid_param(self.name, entity.eid)
-
+
def render_label(self, entity, label=None):
"""render widget's label"""
label = label or self.rschema.display_name(entity.req, self.role)
@@ -130,7 +130,7 @@
else:
label = u'<label%s>%s</label>' % (forattr, label)
return label
-
+
def render_error(self, entity):
"""return validation error for widget's field of the given entity, if
any
@@ -153,16 +153,16 @@
help.append(u'<span class="helper">(%s: %s)</span>'
% (req._('sample format'), example))
return u' '.join(help)
-
+
def render_example(self, req):
return u''
-
+
def render(self, entity):
"""render the widget for a simple view"""
if not entity.has_eid():
return u''
return entity.printable_value(self.name)
-
+
def edit_render(self, entity, tabindex=None,
includehelp=False, useid=None, **kwargs):
"""render the widget for edition"""
@@ -180,7 +180,7 @@
if includehelp:
output += self.render_help(entity)
return output
-
+
def _edit_render(self, entity):
"""do the actual job to render the widget for edition"""
raise NotImplementedError
@@ -196,7 +196,7 @@
elif entity.has_eid():
return [row[0] for row in entity.related(self.name, self.role)]
return ()
-
+
def current_value(self, entity):
return _value_from_values(self.current_values(entity))
@@ -213,13 +213,13 @@
if not isinstance(cdvalues, (list, tuple)):
cdvalues = (cdvalues,)
return cdvalues
-
+
def current_display_value(self, entity):
"""same as .current_value but consider values stored in session in case
of validation error
"""
return _value_from_values(self.current_display_values(entity))
-
+
def hidden_input(self, entity, qvalue):
"""return an hidden field which
1. indicates that a field is edited
@@ -258,7 +258,7 @@
def __init__(self, vreg, subjschema, rschema, objschema,
role='subject', **kwattrs):
InputWidget.__init__(self, vreg, subjschema, rschema, objschema,
- role='subject',
+ role='subject',
**kwattrs)
# disable access key
del self.attrs['accesskey']
@@ -270,18 +270,18 @@
def current_display_value(self, entity):
value = InputWidget.current_display_value(self, entity)
return value or INTERNAL_FIELD_VALUE
-
+
def render_label(self, entity, label=None):
"""render widget's label"""
return u''
-
+
def render_help(self, entity):
return u''
-
+
def hidden_input(self, entity, value):
"""no hidden input for hidden input"""
return ''
-
+
class EidWidget(HiddenWidget):
@@ -297,15 +297,15 @@
"""set html attributes in the attrs dict to consider maxsize"""
attrs['size'] = min(maxsize, 40)
attrs['maxlength'] = maxsize
-
-
+
+
class AutoCompletionWidget(StringWidget):
cubicwebns_attributes = (StringWidget.cubicwebns_attributes |
set(('accesskey', 'size', 'maxlength')))
attrs = ()
-
+
wdgtype = 'SuggestField'
-
+
def current_value(self, entity):
value = StringWidget.current_value(self, entity)
return value or INTERNAL_FIELD_VALUE
@@ -344,22 +344,22 @@
class StaticFileAutoCompletionWidget(AutoCompletionWidget):
wdgtype = 'StaticFileSuggestField'
-
+
def _get_url(self, entity):
return entity.req.datadir_url + entity.autocomplete_initfuncs[self.rschema]
class RestrictedAutoCompletionWidget(AutoCompletionWidget):
- wdgtype = 'RestrictedSuggestField'
+ wdgtype = 'RestrictedSuggestField'
-
+
class PasswordWidget(InputWidget):
input_type = 'password'
-
+
def required(self, entity):
if InputWidget.required(self, entity) and not entity.has_eid():
return True
return False
-
+
def current_values(self, entity):
# on existant entity, show password field has non empty (we don't have
# the actual value
@@ -374,10 +374,10 @@
html, self.input_type, name, name, entity.req.next_tabindex(),
entity.req._('confirm password'))
-
+
class TextWidget(Widget):
html_attributes = Widget.html_attributes | set(('rows', 'cols'))
-
+
@staticmethod
def size_constraint_attrs(attrs, maxsize):
"""set html attributes in the attrs dict to consider maxsize"""
@@ -385,12 +385,12 @@
attrs['cols'], attrs['rows'] = 60, 5
else:
attrs['cols'], attrs['rows'] = 80, 10
-
+
def render(self, entity):
if not entity.has_eid():
return u''
return entity.printable_value(self.name)
-
+
def _edit_render(self, entity, with_format=True):
req = entity.req
editor = self._edit_render_textarea(entity, with_format)
@@ -398,7 +398,7 @@
if isinstance(value, basestring):
value = html_escape(value)
return u'%s%s' % (self.hidden_input(entity, value), editor)
-
+
def _edit_render_textarea(self, entity, with_format):
self.attrs.setdefault('cols', 80)
self.attrs.setdefault('rows', 20)
@@ -426,8 +426,8 @@
fmtwdgstr = ''
return u'%s<br/><textarea onkeypress="autogrow(this)" name="%s" %s>%s</textarea>' % (
fmtwdgstr, self.rname, self.format_attrs(), dvalue)
-
-
+
+
class CheckBoxWidget(Widget):
html_attributes = Widget.html_attributes | set(('checked', ))
def _edit_render(self, entity):
@@ -460,7 +460,7 @@
u'<input type="radio" name="%s" value="" %s/>%s<br/>' % (self.rname, attrs2, entity.req._('no'))]
return '\n'.join(wdgs)
-
+
class FileWidget(Widget):
need_multipart = True
def _file_wdg(self, entity):
@@ -492,7 +492,7 @@
wdgs.append(u'<br/>')
wdgs.append(req._('currently attached file: %s' % entity.dc_title()))
return '\n'.join(wdgs)
-
+
def _edit_render(self, entity):
return self.hidden_input(entity, None) + self._file_wdg(entity)
@@ -510,7 +510,7 @@
'You can either submit a new file using the browse button above'
', or edit file content online with the widget below.')
return msg
-
+
def _edit_render(self, entity):
wdgs = [self._file_wdg(entity)]
if entity.attr_metadata(self.name, 'format') in ('text/plain', 'text/html', 'text/rest'):
@@ -534,7 +534,7 @@
class ComboBoxWidget(Widget):
html_attributes = Widget.html_attributes | set(('multiple', 'size'))
-
+
def __init__(self, vreg, subjschema, rschema, objschema,
multiple=False, **kwattrs):
super(ComboBoxWidget, self).__init__(vreg, subjschema, rschema, objschema,
@@ -545,10 +545,10 @@
self.attrs['size'] = '5'
# disable access key (dunno why but this is not allowed by xhtml 1.0)
del self.attrs['accesskey']
-
+
def vocabulary(self, entity):
raise NotImplementedError()
-
+
def form_value(self, entity, value, values):
if value in values:
flag = 'selected="selected"'
@@ -574,9 +574,9 @@
res.append(u'</select>')
return '\n'.join(res)
-
+
class StaticComboBoxWidget(ComboBoxWidget):
-
+
def __init__(self, vreg, subjschema, rschema, objschema,
vocabfunc, multiple=False, sort=False, **kwattrs):
super(StaticComboBoxWidget, self).__init__(vreg, subjschema, rschema, objschema,
@@ -591,11 +591,11 @@
if self.rschema.rproperty(self.subjtype, self.objtype, 'internationalizable'):
return zip((entity.req._(v) for v in choices), choices)
return zip(choices, choices)
-
+
class EntityLinkComboBoxWidget(ComboBoxWidget):
"""to be used be specific forms"""
-
+
def current_values(self, entity):
if entity.has_eid():
return [r[0] for r in entity.related(self.name, self.role)]
@@ -603,13 +603,13 @@
if hasattr(entity, defaultmeth):
return getattr(entity, defaultmeth)()
return ()
-
+
def vocabulary(self, entity):
return [('', INTERNAL_FIELD_VALUE)] + entity.vocabulary(self.rschema, self.role)
class RawDynamicComboBoxWidget(EntityLinkComboBoxWidget):
-
+
def vocabulary(self, entity, limit=None):
req = entity.req
# first see if its specified by __linkto form parameters
@@ -632,7 +632,7 @@
class DynamicComboBoxWidget(RawDynamicComboBoxWidget):
-
+
def vocabulary(self, entity, limit=None):
return sorted(super(DynamicComboBoxWidget, self).vocabulary(entity, limit))
@@ -669,11 +669,11 @@
kwattrs['size'] = 5
kwattrs['maxlength'] = 15
StringWidget.__init__(self, vreg, subjschema, rschema, objschema, **kwattrs)
-
+
def render_example(self, req):
return '23'
-
-
+
+
class FloatWidget(StringWidget):
def __init__(self, vreg, subjschema, rschema, objschema, **kwattrs):
kwattrs['size'] = 5
@@ -683,7 +683,7 @@
def render_example(self, req):
formatstr = req.property_value('ui.float-format')
return formatstr % 1.23
-
+
def current_values(self, entity):
values = entity.attribute_values(self.name)
if values:
@@ -702,7 +702,7 @@
kwattrs['size'] = 5
kwattrs['maxlength'] = 15
StringWidget.__init__(self, vreg, subjschema, rschema, objschema, **kwattrs)
-
+
def render_example(self, req):
return '345.0300'
@@ -724,7 +724,7 @@
daynames = [_(dname) for dname in cls.daynames]
req.html_headers.define_var('MONTHNAMES', monthnames)
req.html_headers.define_var('DAYNAMES', daynames)
-
+
def __init__(self, vreg, subjschema, rschema, objschema, **kwattrs):
kwattrs.setdefault('size', 10)
kwattrs.setdefault('maxlength', 10)
@@ -784,7 +784,7 @@
kwattrs['size'] = 16
kwattrs['maxlength'] = 16
DateWidget.__init__(self, vreg, subjschema, rschema, objschema, **kwattrs)
-
+
def render_example(self, req):
formatstr1 = req.property_value('ui.datetime-format')
formatstr2 = req.property_value('ui.date-format')
@@ -801,26 +801,26 @@
kwattrs['maxlength'] = 5
StringWidget.__init__(self, vreg, subjschema, rschema, objschema, **kwattrs)
-
+
class EmailWidget(StringWidget):
-
+
def render(self, entity):
email = getattr(entity, self.name)
if not email:
return u''
return u'<a href="mailto:%s">%s</a>' % (email, email)
-
+
class URLWidget(StringWidget):
-
+
def render(self, entity):
url = getattr(entity, self.name)
if not url:
return u''
url = html_escape(url)
return u'<a href="%s">%s</a>' % (url, url)
-
+
class EmbededURLWidget(StringWidget):
-
+
def render(self, entity):
url = getattr(entity, self.name)
if not url:
@@ -828,7 +828,7 @@
aurl = html_escape(entity.build_url('embed', url=url))
return u'<a href="%s">%s</a>' % (aurl, url)
-
+
def widget_factory(vreg, subjschema, rschema, objschema, role='subject',
**kwargs):
@@ -857,14 +857,14 @@
# factories to find the most adapated widget according to a type and other constraints
-
+
def _string_widget_factory(vreg, subjschema, rschema, objschema, wcls=None, **kwargs):
w = None
for c in rschema.rproperty(subjschema, objschema, 'constraints'):
if isinstance(c, StaticVocabularyConstraint):
# may have been set by a previous SizeConstraint but doesn't make sense
# here (even doesn't have the same meaning on a combobox actually)
- kwargs.pop('size', None)
+ kwargs.pop('size', None)
return (wcls or StaticComboBoxWidget)(vreg, subjschema, rschema, objschema,
vocabfunc=c.vocabulary, **kwargs)
if isinstance(c, SizeConstraint) and c.max is not None:
@@ -914,7 +914,7 @@
'String' : StringWidget,
'Time': TimeWidget,
}
-
+
# widgets registry
WIDGETS = {}
def register(widget_list):