--- a/common/uilib.py Wed Jul 15 09:45:13 2009 +0200
+++ b/common/uilib.py Thu Jul 16 13:30:13 2009 +0200
@@ -15,7 +15,7 @@
from urllib import quote as urlquote
from StringIO import StringIO
-from logilab.mtconverter import html_escape, html_unescape
+from logilab.mtconverter import xml_escape, html_unescape
from cubicweb.utils import ustrftime
@@ -66,7 +66,7 @@
except ImportError:
def rest_publish(entity, data):
"""default behaviour if docutils was not found"""
- return html_escape(data)
+ return xml_escape(data)
TAG_PROG = re.compile(r'</?.*?>', re.U)
def remove_html_tags(text):
@@ -108,7 +108,7 @@
if len(text_nohtml) <= length:
return text
# else if un-tagged text is too long, cut it
- return html_escape(text_nohtml[:length] + u'...')
+ return xml_escape(text_nohtml[:length] + u'...')
fallback_safe_cut = safe_cut
@@ -220,15 +220,15 @@
attrs['class'] = attrs.pop('klass')
except KeyError:
pass
- value += u' ' + u' '.join(u'%s="%s"' % (attr, html_escape(unicode(value)))
+ value += u' ' + u' '.join(u'%s="%s"' % (attr, xml_escape(unicode(value)))
for attr, value in sorted(attrs.items())
if value is not None)
if content:
if escapecontent:
- content = html_escape(unicode(content))
+ content = xml_escape(unicode(content))
value += u'>%s</%s>' % (content, tag)
else:
- value += u'/>'
+ value += u'></%s>' % tag
return value
def tooltipize(text, tooltip, url=None):
@@ -406,9 +406,9 @@
strings.append(body)
strings.append(u'</div>')
if title:
- strings.append(u'<h1 class="error">%s</h1>'% html_escape(title))
+ strings.append(u'<h1 class="error">%s</h1>'% xml_escape(title))
try:
- strings.append(u'<p class="error">%s</p>' % html_escape(str(exception)).replace("\n","<br />"))
+ strings.append(u'<p class="error">%s</p>' % xml_escape(str(exception)).replace("\n","<br />"))
except UnicodeError:
pass
strings.append(u'<div class="error_traceback">')
@@ -416,9 +416,9 @@
strings.append(u'<b>File</b> <b class="file">%s</b>, <b>line</b> '
u'<b class="line">%s</b>, <b>function</b> '
u'<b class="function">%s</b>:<br/>'%(
- html_escape(stackentry[0]), stackentry[1], html_escape(stackentry[2])))
+ xml_escape(stackentry[0]), stackentry[1], xml_escape(stackentry[2])))
if stackentry[3]:
- string = html_escape(stackentry[3]).decode('utf-8', 'replace')
+ string = xml_escape(stackentry[3]).decode('utf-8', 'replace')
strings.append(u' %s<br/>\n' % (string))
# add locals info for each entry
try:
@@ -426,7 +426,7 @@
html_info = []
chars = 0
for name, value in local_context.iteritems():
- value = html_escape(repr(value))
+ value = xml_escape(repr(value))
info = u'<span class="name">%s</span>=%s, ' % (name, value)
line_length = len(name) + len(value)
chars += line_length
@@ -491,5 +491,5 @@
def newfunc(*args, **kwargs):
ret = function(*args, **kwargs)
assert isinstance(ret, basestring)
- return html_escape(ret)
+ return xml_escape(ret)
return newfunc
--- a/cwconfig.py Wed Jul 15 09:45:13 2009 +0200
+++ b/cwconfig.py Thu Jul 16 13:30:13 2009 +0200
@@ -571,7 +571,7 @@
}),
('sender-addr',
{'type' : 'string',
- 'default': 'devel@logilab.fr',
+ 'default': 'cubicweb@mydomain.com',
'help': 'email address used as HELO address for outgoing emails from \
the repository',
'group': 'email', 'inputlevel': 1,
--- a/doc/book/en/development/datamodel/define-workflows.rst Wed Jul 15 09:45:13 2009 +0200
+++ b/doc/book/en/development/datamodel/define-workflows.rst Thu Jul 16 13:30:13 2009 +0200
@@ -118,7 +118,7 @@
* `%(seid)s`, the object's current state eid
-.. image:: images/lax-book.03-transitions-view.en.png
+.. image:: ../../images/lax-book.03-transitions-view.en.png
You can notice that in the action box of a BlogEntry, the state
is now listed as well as the possible transitions defined by the workflow.
--- a/entity.py Wed Jul 15 09:45:13 2009 +0200
+++ b/entity.py Thu Jul 16 13:30:13 2009 +0200
@@ -13,7 +13,7 @@
from logilab.common.compat import all
from logilab.common.decorators import cached
from logilab.common.deprecation import obsolete
-from logilab.mtconverter import TransformData, TransformError, html_escape
+from logilab.mtconverter import TransformData, TransformError, xml_escape
from rql.utils import rqlvar_maker
@@ -463,7 +463,7 @@
return u''
value = printable_value(self.req, attrtype, value, props, displaytime)
if format == 'text/html':
- value = html_escape(value)
+ value = xml_escape(value)
return value
def mtc_transform(self, data, format, target_format, encoding,
@@ -666,6 +666,7 @@
self.critical("can't get value for attribute %s of entity with eid %s",
name, self.eid)
if self.e_schema.destination(name) == 'String':
+ # XXX (syt) imo emtpy string is better
self[name] = value = self.req._('unaccessible')
else:
self[name] = value = None
--- a/ext/html4zope.py Wed Jul 15 09:45:13 2009 +0200
+++ b/ext/html4zope.py Thu Jul 16 13:30:13 2009 +0200
@@ -24,7 +24,7 @@
__docformat__ = 'reStructuredText'
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
from docutils import nodes
from docutils.writers.html4css1 import Writer as CSS1Writer
@@ -154,7 +154,7 @@
error = u'System Message: %s%s/%s%s (%s %s)%s</p>\n' % (
a_start, node['type'], node['level'], a_end,
self.encode(node['source']), line, backref_text)
- self.body.append(u'<div class="system-message"><b>ReST / HTML errors:</b>%s</div>' % html_escape(error))
+ self.body.append(u'<div class="system-message"><b>ReST / HTML errors:</b>%s</div>' % xml_escape(error))
def depart_system_message(self, node):
pass
--- a/ext/rest.py Wed Jul 15 09:45:13 2009 +0200
+++ b/ext/rest.py Thu Jul 16 13:30:13 2009 +0200
@@ -29,7 +29,7 @@
from docutils.parsers.rst import Parser, states, directives
from docutils.parsers.rst.roles import register_canonical_role, set_classes
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import ESC_UCAR_TABLE, ESC_CAR_TABLE, xml_escape
from cubicweb.ext.html4zope import Writer
@@ -207,8 +207,12 @@
req = context.req
if isinstance(data, unicode):
encoding = 'unicode'
+ # remove unprintable characters unauthorized in xml
+ data = data.translate(ESC_UCAR_TABLE)
else:
encoding = req.encoding
+ # remove unprintable characters unauthorized in xml
+ data = data.translate(ESC_CAR_TABLE)
settings = {'input_encoding': encoding, 'output_encoding': 'unicode',
'warning_stream': StringIO(), 'context': context,
# dunno what's the max, severe is 4, and we never want a crash
@@ -232,5 +236,5 @@
LOGGER.exception('error while publishing ReST text')
if not isinstance(data, unicode):
data = unicode(data, encoding, 'replace')
- return html_escape(req._('error while publishing ReST text')
+ return xml_escape(req._('error while publishing ReST text')
+ '\n\n' + data)
--- a/goa/appobjects/components.py Wed Jul 15 09:45:13 2009 +0200
+++ b/goa/appobjects/components.py Thu Jul 16 13:30:13 2009 +0200
@@ -7,7 +7,7 @@
"""
__docformat__ = "restructuredtext en"
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
from cubicweb import typed_eid
from cubicweb.selectors import one_line_rset, match_search_state, accept
@@ -74,7 +74,7 @@
label = display_name(req, etype, 'plural')
view = self.vreg.select('views', 'list', req, req.etype_rset(etype))
url = view.url()
- etypelink = u' <a href="%s">%s</a>' % (html_escape(url), label)
+ etypelink = u' <a href="%s">%s</a>' % (xml_escape(url), label)
yield (label, etypelink, self.add_entity_link(eschema, req))
ManageView.entity_types = entity_types_no_count
--- a/goa/appobjects/dbmgmt.py Wed Jul 15 09:45:13 2009 +0200
+++ b/goa/appobjects/dbmgmt.py Thu Jul 16 13:30:13 2009 +0200
@@ -12,7 +12,7 @@
from pickle import loads, dumps
from logilab.common.decorators import cached
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
from cubicweb.selectors import none_rset, match_user_groups
from cubicweb.common.view import StartupView
@@ -54,7 +54,7 @@
break
values.append('__session=%s' % cookie['__session'].value)
self.w(u"<p>pass this flag to the client: --cookie='%s'</p>"
- % html_escape('; '.join(values)))
+ % xml_escape('; '.join(values)))
@@ -148,7 +148,7 @@
% cpath)
self.w(u'<div>click <a href="%s?vid=contentclear">here</a> to '
'<b>delete all datastore content</b> so process can be '
- 'reinitialized</div>' % html_escape(self.req.base_url()))
+ 'reinitialized</div>' % xml_escape(self.req.base_url()))
Put(status)
@property
@@ -159,11 +159,11 @@
repo=self.config.repository())
def msg(self, msg):
- self.w(u'<div class="message">%s</div>' % html_escape(msg))
+ self.w(u'<div class="message">%s</div>' % xml_escape(msg))
def redirect(self, msg):
raise Redirect(self.req.build_url('', msg))
def continue_link(self):
- self.w(u'<a href="%s">continue</a><br/>' % html_escape(self.req.url()))
+ self.w(u'<a href="%s">continue</a><br/>' % xml_escape(self.req.url()))
class ContentClear(StartupView):
--- a/i18n/en.po Wed Jul 15 09:45:13 2009 +0200
+++ b/i18n/en.po Thu Jul 16 13:30:13 2009 +0200
@@ -160,6 +160,9 @@
"can also display a <a href=\"%s\">complete schema with meta-data</a>.</div>"
msgstr ""
+msgid "<no value>"
+msgstr ""
+
msgid "?*"
msgstr "0..1 0..n"
@@ -1147,6 +1150,9 @@
msgid "click on the box to cancel the deletion"
msgstr ""
+msgid "click to edit this field"
+msgstr ""
+
msgid "comment"
msgstr ""
@@ -1721,12 +1727,6 @@
msgid "facets_cwfinal-facet_description"
msgstr ""
-msgid "facets_cwmeta-facet"
-msgstr ""
-
-msgid "facets_cwmeta-facet_description"
-msgstr ""
-
msgid "facets_etype-facet"
msgstr "\"entity type\" facet"
@@ -2259,9 +2259,6 @@
msgid "not selected"
msgstr ""
-msgid "not specified"
-msgstr ""
-
msgid "not the initial state for this entity"
msgstr ""
@@ -2946,6 +2943,12 @@
msgid "view workflow"
msgstr ""
+msgid "view_index"
+msgstr "index"
+
+msgid "view_manage"
+msgstr "site management"
+
msgid "views"
msgstr ""
--- a/i18n/fr.po Wed Jul 15 09:45:13 2009 +0200
+++ b/i18n/fr.po Thu Jul 16 13:30:13 2009 +0200
@@ -164,8 +164,11 @@
"<div>This schema of the data model <em>excludes</em> the meta-data, but you "
"can also display a <a href=\"%s\">complete schema with meta-data</a>.</div>"
msgstr ""
-"<div>Ce schéma du modèle de données <em>exclue</em> les méta-données, mais vous "
-"pouvez afficher un <a href=\"%s\">schéma complet</a>.</div>"
+"<div>Ce schéma du modèle de données <em>exclue</em> les méta-données, mais "
+"vous pouvez afficher un <a href=\"%s\">schéma complet</a>.</div>"
+
+msgid "<no value>"
+msgstr "<non spécifié>"
msgid "?*"
msgstr "0..1 0..n"
@@ -633,9 +636,10 @@
"invalidate the cache (typically in hooks). Also, checkout the AppRsetObject."
"get_cache() method."
msgstr ""
-"une simple entité de cache, caractérisées par un nom et une date de validité. L'application "
-"est responsable de la mise à jour de la date quand il est nécessaire d'invalider le cache (typiquement dans les crochets). "
-"Voir aussi la méthode get_cache() sur la classe AppRsetObject."
+"une simple entité de cache, caractérisées par un nom et une date de "
+"validité. L'application est responsable de la mise à jour de la date quand "
+"il est nécessaire d'invalider le cache (typiquement dans les crochets). Voir "
+"aussi la méthode get_cache() sur la classe AppRsetObject."
msgid "about this site"
msgstr "à propos de ce site"
@@ -1039,7 +1043,8 @@
msgstr "signets"
msgid "bookmarks are used to have user's specific internal links"
-msgstr "les signets sont utilisés pour gérer des liens internes par utilisateur"
+msgstr ""
+"les signets sont utilisés pour gérer des liens internes par utilisateur"
msgid "boxes"
msgstr "boîtes"
@@ -1178,7 +1183,10 @@
msgstr "cliquez ici pour voir l'entité créée"
msgid "click on the box to cancel the deletion"
-msgstr "cliquer dans la zone d'édition pour annuler la suppression"
+msgstr "cliquez dans la zone d'édition pour annuler la suppression"
+
+msgid "click to edit this field"
+msgstr "cliquez pour éditer ce champ"
msgid "comment"
msgstr "commentaire"
@@ -1800,12 +1808,6 @@
msgid "facets_cwfinal-facet_description"
msgstr ""
-msgid "facets_cwmeta-facet"
-msgstr ""
-
-msgid "facets_cwmeta-facet_description"
-msgstr ""
-
msgid "facets_etype-facet"
msgstr "facette \"est de type\""
@@ -2360,9 +2362,6 @@
msgid "not selected"
msgstr "non sélectionné"
-msgid "not specified"
-msgstr "non spécifié"
-
msgid "not the initial state for this entity"
msgstr "n'est pas l'état initial pour cette entité"
@@ -3069,6 +3068,12 @@
msgid "view workflow"
msgstr "voir les états possibles"
+msgid "view_index"
+msgstr "accueil"
+
+msgid "view_manage"
+msgstr "gestion du site"
+
msgid "views"
msgstr "vues"
@@ -3252,6 +3257,9 @@
#~ msgid "no associated epermissions"
#~ msgstr "aucune permission spécifique n'est définie"
+#~ msgid "not specified"
+#~ msgstr "non spécifié"
+
#~ msgid "owned by"
#~ msgstr "appartient à"
--- a/rset.py Wed Jul 15 09:45:13 2009 +0200
+++ b/rset.py Thu Jul 16 13:30:13 2009 +0200
@@ -538,10 +538,12 @@
for i, term in enumerate(rqlst.selection):
if i == index:
continue
- try:
- # XXX rewritten const
- var = term.variable
- except AttributeError:
+ # XXX rewritten const
+ # use iget_nodes for (hack) case where we have things like MAX(V)
+ for vref in term.iget_nodes(nodes.VariableRef):
+ var = vref.variable
+ break
+ else:
continue
#varname = var.name
for ref in var.references():
--- a/rtags.py Wed Jul 15 09:45:13 2009 +0200
+++ b/rtags.py Thu Jul 16 13:30:13 2009 +0200
@@ -101,6 +101,7 @@
'%r is not an allowed tag (should be in %s)' % (
tag, self._allowed_values)
self._tagdefs[(rtype, tagged, stype, otype)] = tag
+ return tag
# rtag runtime api ########################################################
@@ -123,15 +124,19 @@
class RelationTagsSet(RelationTags):
- """This class associates a set of tags to each key."""
+ """This class associates a set of tags to each key.
+ """
+ tag_container_cls = set
def tag_relation(self, key, tag):
stype, rtype, otype, tagged = [str(k) for k in key]
- rtags = self._tagdefs.setdefault((rtype, tagged, stype, otype), set())
+ rtags = self._tagdefs.setdefault((rtype, tagged, stype, otype),
+ self.tag_container_cls())
rtags.add(tag)
+ return rtags
def get(self, stype, rtype, otype, tagged):
- rtags = set()
+ rtags = self.tag_container_cls()
for key in self._get_keys(stype, rtype, otype, tagged):
try:
rtags.update(self._tagdefs[key])
@@ -140,6 +145,31 @@
return rtags
+class RelationTagsDict(RelationTagsSet):
+ """This class associates a set of tags to each key."""
+ tag_container_cls = dict
+
+ def tag_relation(self, key, tag):
+ stype, rtype, otype, tagged = [str(k) for k in key]
+ try:
+ rtags = self._tagdefs[(rtype, tagged, stype, otype)]
+ rtags.update(tag)
+ return rtags
+ except KeyError:
+ self._tagdefs[(rtype, tagged, stype, otype)] = tag
+ return tag
+
+ def setdefault(self, key, tagkey, tagvalue):
+ stype, rtype, otype, tagged = [str(k) for k in key]
+ try:
+ rtags = self._tagdefs[(rtype, tagged, stype, otype)]
+ rtags.setdefault(tagkey, tagvalue)
+ return rtags
+ except KeyError:
+ self._tagdefs[(rtype, tagged, stype, otype)] = {tagkey: tagvalue}
+ return self._tagdefs[(rtype, tagged, stype, otype)]
+
+
class RelationTagsBool(RelationTags):
_allowed_values = frozenset((True, False))
--- a/selectors.py Wed Jul 15 09:45:13 2009 +0200
+++ b/selectors.py Thu Jul 16 13:30:13 2009 +0200
@@ -79,7 +79,7 @@
ret = selector(cls, *args, **kwargs)
if TRACED_OIDS == 'all' or oid in TRACED_OIDS:
#SELECTOR_LOGGER.warning('selector %s returned %s for %s', selname, ret, cls)
- print 'selector %s returned %s for %s' % (selname, ret, vobj)
+ print '%s -> %s for %s' % (selname, ret, vobj)
return ret
traced.__name__ = selector.__name__
return traced
--- a/server/__init__.py Wed Jul 15 09:45:13 2009 +0200
+++ b/server/__init__.py Thu Jul 16 13:30:13 2009 +0200
@@ -50,8 +50,7 @@
driver = source['db-driver']
sqlcnx = repo.system_source.get_connection()
sqlcursor = sqlcnx.cursor()
- def execute(sql, args=None):
- repo.system_source.doexec(sqlcursor, sql, args)
+ execute = sqlcursor.execute
if drop:
dropsql = sqldropschema(schema, driver)
try:
--- a/server/hooksmanager.py Wed Jul 15 09:45:13 2009 +0200
+++ b/server/hooksmanager.py Thu Jul 16 13:30:13 2009 +0200
@@ -216,7 +216,14 @@
cls.warning('%s hook has been disabled', cls)
return
done = set()
+ assert isinstance(cls.events, (tuple, list)), \
+ '%s: events is expected to be a tuple, not %s' % (
+ cls, type(cls.events))
for event in cls.events:
+ if event == 'server_startup':
+ assert not cls.accepts or cls.accepts == ('Any',), \
+ '%s doesnt make sense on server_startup' % cls.accepts
+ cls.accepts = ('Any',)
for ertype in cls.accepts:
if (event, ertype) in done:
continue
--- a/server/rqlannotation.py Wed Jul 15 09:45:13 2009 +0200
+++ b/server/rqlannotation.py Thu Jul 16 13:30:13 2009 +0200
@@ -22,7 +22,7 @@
has_text_query = False
need_distinct = rqlst.distinct
for rel in rqlst.iget_nodes(Relation):
- if getrschema(rel.r_type).symetric:
+ if getrschema(rel.r_type).symetric and not rel.neged(strict=True):
for vref in rel.iget_nodes(VariableRef):
stinfo = vref.variable.stinfo
if not stinfo['constnode'] and stinfo['selected']:
--- a/server/session.py Wed Jul 15 09:45:13 2009 +0200
+++ b/server/session.py Thu Jul 16 13:30:13 2009 +0200
@@ -88,9 +88,7 @@
"""return a sql cursor on the system database"""
if not sql.split(None, 1)[0].upper() == 'SELECT':
self.mode = 'write'
- cursor = self.pool['system']
- self.pool.source('system').doexec(cursor, sql, args)
- return cursor
+ return self.pool.source('system').doexec(self, sql, args)
def set_language(self, language):
"""i18n configuration for translation"""
@@ -137,24 +135,27 @@
raise Exception('try to set pool on a closed session')
if self.pool is None:
# get pool first to avoid race-condition
- self._threaddata.pool = self.repo._get_pool()
+ self._threaddata.pool = pool = self.repo._get_pool()
try:
- self._threaddata.pool.pool_set()
+ pool.pool_set()
except:
self._threaddata.pool = None
- self.repo._free_pool(self.pool)
+ self.repo._free_pool(pool)
raise
self._threads_in_transaction.add(threading.currentThread())
return self._threaddata.pool
def reset_pool(self):
- """the session has no longer using its pool, at least for some time"""
+ """the session is no longer using its pool, at least for some time"""
# pool may be none if no operation has been done since last commit
# or rollback
if self.pool is not None and self.mode == 'read':
# even in read mode, we must release the current transaction
pool = self.pool
- self._threads_in_transaction.remove(threading.currentThread())
+ try:
+ self._threads_in_transaction.remove(threading.currentThread())
+ except KeyError:
+ pass
pool.pool_reset()
self._threaddata.pool = None
# free pool once everything is done to avoid race-condition
--- a/server/sources/extlite.py Wed Jul 15 09:45:13 2009 +0200
+++ b/server/sources/extlite.py Thu Jul 16 13:30:13 2009 +0200
@@ -174,9 +174,7 @@
if server.DEBUG:
print self.uri, 'SOURCE RQL', union.as_string()
args = self.sqladapter.merge_args(args, query_args)
- cursor = session.pool[self.uri]
- self.doexec(cursor, sql, args)
- res = self.sqladapter.process_result(cursor)
+ res = self.sqladapter.process_result(self.doexec(session, sql, args))
if server.DEBUG:
print '------>', res
return res
@@ -190,7 +188,7 @@
"""
attrs = self.sqladapter.preprocess_entity(entity)
sql = self.sqladapter.sqlgen.insert(SQL_PREFIX + str(entity.e_schema), attrs)
- self.doexec(session.pool[self.uri], sql, attrs)
+ self.doexec(session, sql, attrs)
def add_entity(self, session, entity):
"""add a new entity to the source"""
@@ -207,7 +205,7 @@
attrs = self.sqladapter.preprocess_entity(entity)
sql = self.sqladapter.sqlgen.update(SQL_PREFIX + str(entity.e_schema),
attrs, [SQL_PREFIX + 'eid'])
- self.doexec(session.pool[self.uri], sql, attrs)
+ self.doexec(session, sql, attrs)
def update_entity(self, session, entity):
"""update an entity in the source"""
@@ -222,7 +220,7 @@
"""
attrs = {SQL_PREFIX + 'eid': eid}
sql = self.sqladapter.sqlgen.delete(SQL_PREFIX + etype, attrs)
- self.doexec(session.pool[self.uri], sql, attrs)
+ self.doexec(session, sql, attrs)
def local_add_relation(self, session, subject, rtype, object):
"""add a relation to the source
@@ -233,7 +231,7 @@
"""
attrs = {'eid_from': subject, 'eid_to': object}
sql = self.sqladapter.sqlgen.insert('%s_relation' % rtype, attrs)
- self.doexec(session.pool[self.uri], sql, attrs)
+ self.doexec(session, sql, attrs)
def add_relation(self, session, subject, rtype, object):
"""add a relation to the source"""
@@ -252,21 +250,25 @@
else:
attrs = {'eid_from': subject, 'eid_to': object}
sql = self.sqladapter.sqlgen.delete('%s_relation' % rtype, attrs)
- self.doexec(session.pool[self.uri], sql, attrs)
+ self.doexec(session, sql, attrs)
- def doexec(self, cursor, query, args=None):
+ def doexec(self, session, query, args=None):
"""Execute a query.
it's a function just so that it shows up in profiling
"""
- #t1 = time()
if server.DEBUG:
print 'exec', query, args
- #import sys
- #sys.stdout.flush()
- # str(query) to avoid error if it's an unicode string
+ cursor = session.pool[self.uri]
try:
+ # str(query) to avoid error if it's an unicode string
cursor.execute(str(query), args)
except Exception, ex:
self.critical("sql: %r\n args: %s\ndbms message: %r",
query, args, ex.args[0])
+ try:
+ session.pool.connection(self.uri).rollback()
+ self.critical('transaction has been rollbacked')
+ except:
+ pass
raise
+ return cursor
--- a/server/sources/native.py Wed Jul 15 09:45:13 2009 +0200
+++ b/server/sources/native.py Thu Jul 16 13:30:13 2009 +0200
@@ -31,6 +31,7 @@
from cubicweb.server.sources.rql2sql import SQLGenerator
+ATTR_MAP = {}
NONSYSTEM_ETYPES = set()
NONSYSTEM_RELATIONS = set()
@@ -90,6 +91,7 @@
class NativeSQLSource(SQLAdapterMixIn, AbstractSource):
"""adapter for source using the native cubicweb schema (see below)
"""
+ sqlgen_class = SQLGenerator
# need default value on class since migration doesn't call init method
has_deleted_entitites_table = True
@@ -141,8 +143,8 @@
AbstractSource.__init__(self, repo, appschema, source_config,
*args, **kwargs)
# sql generator
- self._rql_sqlgen = SQLGenerator(appschema, self.dbhelper,
- self.encoding)
+ self._rql_sqlgen = self.sqlgen_class(appschema, self.dbhelper,
+ self.encoding, ATTR_MAP.copy())
# full text index helper
self.indexer = get_indexer(self.dbdriver, self.encoding)
# advanced functionality helper
@@ -185,9 +187,7 @@
def sqlexec(self, session, sql, args=None):
"""execute the query and return its result"""
- cursor = session.pool[self.uri]
- self.doexec(cursor, sql, args)
- return self.process_result(cursor)
+ return self.process_result(self.doexec(session, sql, args))
def init_creating(self):
pool = self.repo._get_pool()
@@ -211,6 +211,9 @@
pool.pool_reset()
self.repo._free_pool(pool)
+ def map_attribute(self, etype, attr, cb):
+ self._rql_sqlgen.attr_map['%s.%s' % (etype, attr)] = cb
+
# ISource interface #######################################################
def compile_rql(self, rql):
@@ -305,17 +308,15 @@
sql, query_args = self._rql_sqlgen.generate(union, args, varmap)
self._cache[cachekey] = sql, query_args
args = self.merge_args(args, query_args)
- cursor = session.pool[self.uri]
assert isinstance(sql, basestring), repr(sql)
try:
- self.doexec(cursor, sql, args)
+ cursor = self.doexec(session, sql, args)
except (self.dbapi_module.OperationalError,
self.dbapi_module.InterfaceError):
# FIXME: better detection of deconnection pb
self.info("request failed '%s' ... retry with a new cursor", sql)
session.pool.reconnect(self)
- cursor = session.pool[self.uri]
- self.doexec(cursor, sql, args)
+ cursor = self.doexec(session, sql, args)
res = self.process_result(cursor)
if server.DEBUG:
print '------>', res
@@ -337,8 +338,7 @@
# generate sql queries if we are able to do so
sql, query_args = self._rql_sqlgen.generate(union, args, varmap)
query = 'INSERT INTO %s %s' % (table, sql.encode(self.encoding))
- self.doexec(session.pool[self.uri], query,
- self.merge_args(args, query_args))
+ self.doexec(session, query, self.merge_args(args, query_args))
else:
super(NativeSQLSource, self).flying_insert(table, session, union,
args, varmap)
@@ -358,15 +358,14 @@
cell = self.binary(cell.getvalue())
kwargs[str(index)] = cell
kwargs_list.append(kwargs)
- self.doexecmany(session.pool[self.uri], query, kwargs_list)
+ self.doexecmany(session, query, kwargs_list)
def clean_temp_data(self, session, temptables):
"""remove temporary data, usually associated to temporary tables"""
if temptables:
- cursor = session.pool[self.uri]
for table in temptables:
try:
- self.doexec(cursor,'DROP TABLE %s' % table)
+ self.doexec(session,'DROP TABLE %s' % table)
except:
pass
try:
@@ -378,25 +377,25 @@
"""add a new entity to the source"""
attrs = self.preprocess_entity(entity)
sql = self.sqlgen.insert(SQL_PREFIX + str(entity.e_schema), attrs)
- self.doexec(session.pool[self.uri], sql, attrs)
+ self.doexec(session, sql, attrs)
def update_entity(self, session, entity):
"""replace an entity in the source"""
attrs = self.preprocess_entity(entity)
sql = self.sqlgen.update(SQL_PREFIX + str(entity.e_schema), attrs, [SQL_PREFIX + 'eid'])
- self.doexec(session.pool[self.uri], sql, attrs)
+ self.doexec(session, sql, attrs)
def delete_entity(self, session, etype, eid):
"""delete an entity from the source"""
attrs = {SQL_PREFIX + 'eid': eid}
sql = self.sqlgen.delete(SQL_PREFIX + etype, attrs)
- self.doexec(session.pool[self.uri], sql, attrs)
+ self.doexec(session, sql, attrs)
def add_relation(self, session, subject, rtype, object):
"""add a relation to the source"""
attrs = {'eid_from': subject, 'eid_to': object}
sql = self.sqlgen.insert('%s_relation' % rtype, attrs)
- self.doexec(session.pool[self.uri], sql, attrs)
+ self.doexec(session, sql, attrs)
def delete_relation(self, session, subject, rtype, object):
"""delete a relation from the source"""
@@ -410,39 +409,47 @@
else:
attrs = {'eid_from': subject, 'eid_to': object}
sql = self.sqlgen.delete('%s_relation' % rtype, attrs)
- self.doexec(session.pool[self.uri], sql, attrs)
+ self.doexec(session, sql, attrs)
- def doexec(self, cursor, query, args=None):
+ def doexec(self, session, query, args=None):
"""Execute a query.
it's a function just so that it shows up in profiling
"""
- #t1 = time()
if server.DEBUG:
print 'exec', query, args
- #import sys
- #sys.stdout.flush()
- # str(query) to avoid error if it's an unicode string
+ cursor = session.pool[self.uri]
try:
+ # str(query) to avoid error if it's an unicode string
cursor.execute(str(query), args)
except Exception, ex:
self.critical("sql: %r\n args: %s\ndbms message: %r",
query, args, ex.args[0])
+ try:
+ session.pool.connection(self.uri).rollback()
+ self.critical('transaction has been rollbacked')
+ except:
+ pass
raise
+ return cursor
- def doexecmany(self, cursor, query, args):
+ def doexecmany(self, session, query, args):
"""Execute a query.
it's a function just so that it shows up in profiling
"""
- #t1 = time()
if server.DEBUG:
print 'execmany', query, 'with', len(args), 'arguments'
- #import sys
- #sys.stdout.flush()
- # str(query) to avoid error if it's an unicode string
+ cursor = session.pool[self.uri]
try:
+ # str(query) to avoid error if it's an unicode string
cursor.executemany(str(query), args)
- except:
- self.critical("sql many: %r\n args: %s", query, args)
+ except Exception, ex:
+ self.critical("sql many: %r\n args: %s\ndbms message: %r",
+ query, args, ex.args[0])
+ try:
+ session.pool.connection(self.uri).rollback()
+ self.critical('transaction has been rollbacked')
+ except:
+ pass
raise
# short cut to method requiring advanced db helper usage ##################
@@ -498,14 +505,13 @@
# running with an ldap source, and table will be deleted manually any way
# on commit
sql = self.dbhelper.sql_temporary_table(table, schema, False)
- self.doexec(session.pool[self.uri], sql)
+ self.doexec(session, sql)
def create_eid(self, session):
self._eid_creation_lock.acquire()
try:
- cursor = session.pool[self.uri]
for sql in self.dbhelper.sqls_increment_sequence('entities_id_seq'):
- self.doexec(cursor, sql)
+ cursor = self.doexec(session, sql)
return cursor.fetchone()[0]
finally:
self._eid_creation_lock.release()
--- a/server/sources/rql2sql.py Wed Jul 15 09:45:13 2009 +0200
+++ b/server/sources/rql2sql.py Thu Jul 16 13:30:13 2009 +0200
@@ -303,7 +303,7 @@
protected by a lock
"""
- def __init__(self, schema, dbms_helper, dbencoding='UTF-8'):
+ def __init__(self, schema, dbms_helper, dbencoding='UTF-8', attrmap=None):
self.schema = schema
self.dbms_helper = dbms_helper
self.dbencoding = dbencoding
@@ -313,6 +313,9 @@
if not self.dbms_helper.union_parentheses_support:
self.union_sql = self.noparen_union_sql
self._lock = threading.Lock()
+ if attrmap is None:
+ attrmap = {}
+ self.attr_map = attrmap
def generate(self, union, args=None, varmap=None):
"""return SQL queries and a variable dictionnary from a RQL syntax tree
@@ -853,27 +856,30 @@
relation.r_type)
return '%s%s' % (lhssql, relation.children[1].accept(self, contextrels))
- def _visit_attribute_relation(self, relation):
+ def _visit_attribute_relation(self, rel):
"""generate SQL for an attribute relation"""
- lhs, rhs = relation.get_parts()
+ lhs, rhs = rel.get_parts()
rhssql = rhs.accept(self)
table = self._var_table(lhs.variable)
if table is None:
- assert relation.r_type == 'eid'
+ assert rel.r_type == 'eid'
lhssql = lhs.accept(self)
else:
try:
- lhssql = self._varmap['%s.%s' % (lhs.name, relation.r_type)]
+ lhssql = self._varmap['%s.%s' % (lhs.name, rel.r_type)]
except KeyError:
- if relation.r_type == 'eid':
+ mapkey = '%s.%s' % (self._state.solution[lhs.name], rel.r_type)
+ if mapkey in self.attr_map:
+ lhssql = self.attr_map[mapkey](self, lhs.variable, rel)
+ elif rel.r_type == 'eid':
lhssql = lhs.variable._q_sql
else:
- lhssql = '%s.%s%s' % (table, SQL_PREFIX, relation.r_type)
+ lhssql = '%s.%s%s' % (table, SQL_PREFIX, rel.r_type)
try:
- if relation._q_needcast == 'TODAY':
+ if rel._q_needcast == 'TODAY':
sql = 'DATE(%s)%s' % (lhssql, rhssql)
# XXX which cast function should be used
- #elif relation._q_needcast == 'NOW':
+ #elif rel._q_needcast == 'NOW':
# sql = 'TIMESTAMP(%s)%s' % (lhssql, rhssql)
else:
sql = '%s%s' % (lhssql, rhssql)
@@ -884,15 +890,15 @@
else:
return sql
- def _visit_has_text_relation(self, relation):
+ def _visit_has_text_relation(self, rel):
"""generate SQL for a has_text relation"""
- lhs, rhs = relation.get_parts()
+ lhs, rhs = rel.get_parts()
const = rhs.children[0]
- alias = self._fti_table(relation)
+ alias = self._fti_table(rel)
jointo = lhs.accept(self)
restriction = ''
lhsvar = lhs.variable
- me_is_principal = lhsvar.stinfo.get('principal') is relation
+ me_is_principal = lhsvar.stinfo.get('principal') is rel
if me_is_principal:
if not lhsvar.stinfo['typerels']:
# the variable is using the fti table, no join needed
@@ -908,8 +914,8 @@
else:
etypes = ','.join("'%s'" % etype for etype in lhsvar.stinfo['possibletypes'])
restriction = " AND %s.type IN (%s)" % (ealias, etypes)
- if isinstance(relation.parent, Not):
- self._state.done.add(relation.parent)
+ if isinstance(rel.parent, Not):
+ self._state.done.add(rel.parent)
not_ = True
else:
not_ = False
@@ -1117,6 +1123,9 @@
if isinstance(linkedvar, ColumnAlias):
raise BadRQLQuery('variable %s should be selected by the subquery'
% variable.name)
+ mapkey = '%s.%s' % (self._state.solution[linkedvar.name], rel.r_type)
+ if mapkey in self.attr_map:
+ return self.attr_map[mapkey](self, linkedvar, rel)
try:
sql = self._varmap['%s.%s' % (linkedvar.name, rel.r_type)]
except KeyError:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/server/test/data/schema.py Thu Jul 16 13:30:13 2009 +0200
@@ -0,0 +1,207 @@
+"""
+
+:organization: Logilab
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.
+:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
+:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
+"""
+from cubicweb.schema import format_constraint
+
+class Affaire(WorkflowableEntityType):
+ permissions = {
+ 'read': ('managers',
+ ERQLExpression('X owned_by U'), ERQLExpression('X concerne S?, S owned_by U')),
+ 'add': ('managers', ERQLExpression('X concerne S, S owned_by U')),
+ 'update': ('managers', 'owners', ERQLExpression('X in_state S, S name in ("pitetre", "en cours")')),
+ 'delete': ('managers', 'owners', ERQLExpression('X concerne S, S owned_by U')),
+ }
+
+ ref = String(fulltextindexed=True, indexed=True,
+ constraints=[SizeConstraint(16)])
+ sujet = String(fulltextindexed=True,
+ constraints=[SizeConstraint(256)])
+ descr_format = String(meta=True, internationalizable=True,
+ default='text/rest', constraints=[format_constraint])
+ descr = String(fulltextindexed=True,
+ description=_('more detailed description'))
+
+ duration = Int()
+ invoiced = Int()
+
+ depends_on = SubjectRelation('Affaire')
+ require_permission = SubjectRelation('CWPermission')
+ concerne = SubjectRelation(('Societe', 'Note'))
+ todo_by = SubjectRelation('Personne')
+ documented_by = SubjectRelation('Card')
+
+
+class Societe(EntityType):
+ permissions = {
+ 'read': ('managers', 'users', 'guests'),
+ 'update': ('managers', 'owners', ERQLExpression('U login L, X nom L')),
+ 'delete': ('managers', 'owners', ERQLExpression('U login L, X nom L')),
+ 'add': ('managers', 'users',)
+ }
+
+ nom = String(maxsize=64, fulltextindexed=True)
+ web = String(maxsize=128)
+ type = String(maxsize=128) # attribute in common with Note
+ tel = Int()
+ fax = Int()
+ rncs = String(maxsize=128)
+ ad1 = String(maxsize=128)
+ ad2 = String(maxsize=128)
+ ad3 = String(maxsize=128)
+ cp = String(maxsize=12)
+ ville= String(maxsize=32)
+
+
+class Division(Societe):
+ __specializes_schema__ = True
+
+class SubDivision(Division):
+ __specializes_schema__ = True
+ travaille_subdivision = ObjectRelation('Personne')
+
+_euser = import_schema('base').CWUser
+_euser.__relations__[0].fulltextindexed = True
+
+class Note(EntityType):
+ date = String(maxsize=10)
+ type = String(maxsize=6)
+ para = String(maxsize=512)
+
+ migrated_from = SubjectRelation('Note')
+ attachment = SubjectRelation(('File', 'Image'))
+ inline1 = SubjectRelation('Affaire', inlined=True)
+ todo_by = SubjectRelation('CWUser')
+
+class Personne(EntityType):
+ nom = String(fulltextindexed=True, required=True, maxsize=64)
+ prenom = String(fulltextindexed=True, maxsize=64)
+ sexe = String(maxsize=1, default='M')
+ promo = String(vocabulary=('bon','pasbon'))
+ titre = String(fulltextindexed=True, maxsize=128)
+ adel = String(maxsize=128)
+ ass = String(maxsize=128)
+ web = String(maxsize=128)
+ tel = Int()
+ fax = Int()
+ datenaiss = Datetime()
+ test = Boolean()
+ description = String()
+ firstname = String(fulltextindexed=True, maxsize=64)
+
+ travaille = SubjectRelation('Societe')
+ concerne = SubjectRelation('Affaire')
+ connait = SubjectRelation('Personne')
+ inline2 = SubjectRelation('Affaire', inlined=True)
+ comments = ObjectRelation('Comment')
+
+
+class fiche(RelationType):
+ inlined = True
+ subject = 'Personne'
+ object = 'Card'
+ cardinality = '??'
+
+class multisource_inlined_rel(RelationType):
+ inlined = True
+ cardinality = '?*'
+ subject = ('Card', 'Note')
+ object = ('Affaire', 'Note')
+
+class ecrit_par(RelationType):
+ inlined = True
+
+class connait(RelationType):
+ symetric = True
+
+class concerne(RelationType):
+ permissions = {
+ 'read': ('managers', 'users', 'guests'),
+ 'add': ('managers', RRQLExpression('U has_update_permission S')),
+ 'delete': ('managers', RRQLExpression('O owned_by U')),
+ }
+
+class travaille(RelationType):
+ permissions = {
+ 'read': ('managers', 'users', 'guests'),
+ 'add': ('managers', RRQLExpression('U has_update_permission S')),
+ 'delete': ('managers', RRQLExpression('O owned_by U')),
+ }
+
+class para(AttributeRelationType):
+ permissions = {
+ 'read': ('managers', 'users', 'guests'),
+ 'add': ('managers', ERQLExpression('X in_state S, S name "todo"')),
+ 'delete': ('managers', ERQLExpression('X in_state S, S name "todo"')),
+ }
+
+class test(AttributeRelationType):
+ permissions = {'read': ('managers', 'users', 'guests'),
+ 'delete': ('managers',),
+ 'add': ('managers',)}
+
+
+class in_state(RelationDefinition):
+ subject = 'Note'
+ object = 'State'
+ cardinality = '1*'
+ constraints=[RQLConstraint('S is ET, O state_of ET')]
+
+class wf_info_for(RelationDefinition):
+ subject = 'TrInfo'
+ object = 'Note'
+ cardinality = '1*'
+
+class multisource_rel(RelationDefinition):
+ subject = ('Card', 'Note')
+ object = 'Note'
+
+class multisource_crossed_rel(RelationDefinition):
+ subject = ('Card', 'Note')
+ object = 'Note'
+
+
+class see_also(RelationDefinition):
+ subject = ('Bookmark', 'Note')
+ object = ('Bookmark', 'Note')
+
+class evaluee(RelationDefinition):
+ subject = ('Personne', 'CWUser', 'Societe')
+ object = ('Note')
+
+class ecrit_par_1(RelationDefinition):
+ name = 'ecrit_par'
+ subject = 'Note'
+ object ='Personne'
+ constraints = [RQLConstraint('E concerns P, X version_of P')]
+
+class ecrit_par_2(RelationDefinition):
+ name = 'ecrit_par'
+ subject = 'Note'
+ object ='CWUser'
+
+class see_also(RelationDefinition):
+ subject = object = 'Folder'
+
+
+class copain(RelationDefinition):
+ subject = object = 'CWUser'
+
+class tags(RelationDefinition):
+ subject = 'Tag'
+ object = ('CWUser', 'CWGroup', 'State', 'Note', 'Card', 'Affaire')
+
+class filed_under(RelationDefinition):
+ subject = ('Note', 'Affaire')
+ object = 'Folder'
+
+class require_permission(RelationDefinition):
+ subject = ('Card', 'Note')
+ object = 'CWPermission'
+
+class require_state(RelationDefinition):
+ subject = 'CWPermission'
+ object = 'State'
--- a/server/test/data/schema/Affaire.py Wed Jul 15 09:45:13 2009 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-"""
-
-:organization: Logilab
-:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.
-:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
-:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
-"""
-from cubicweb.schema import format_constraint
-
-class Affaire(WorkflowableEntityType):
- permissions = {
- 'read': ('managers',
- ERQLExpression('X owned_by U'), ERQLExpression('X concerne S?, S owned_by U')),
- 'add': ('managers', ERQLExpression('X concerne S, S owned_by U')),
- 'update': ('managers', 'owners', ERQLExpression('X in_state S, S name in ("pitetre", "en cours")')),
- 'delete': ('managers', 'owners', ERQLExpression('X concerne S, S owned_by U')),
- }
-
- ref = String(fulltextindexed=True, indexed=True,
- constraints=[SizeConstraint(16)])
- sujet = String(fulltextindexed=True,
- constraints=[SizeConstraint(256)])
- descr_format = String(meta=True, internationalizable=True,
- default='text/rest', constraints=[format_constraint])
- descr = String(fulltextindexed=True,
- description=_('more detailed description'))
-
- duration = Int()
- invoiced = Int()
-
- depends_on = SubjectRelation('Affaire')
- require_permission = SubjectRelation('CWPermission')
-
-class concerne(RelationType):
- permissions = {
- 'read': ('managers', 'users', 'guests'),
- 'add': ('managers', RRQLExpression('U has_update_permission S')),
- 'delete': ('managers', RRQLExpression('O owned_by U')),
- }
-
-
--- a/server/test/data/schema/Note.sql Wed Jul 15 09:45:13 2009 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-date varchar(10)
-type char(6)
-para varchar(512)
--- a/server/test/data/schema/Personne.sql Wed Jul 15 09:45:13 2009 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-nom ivarchar(64) NOT NULL
-prenom ivarchar(64)
-sexe char(1) DEFAULT 'M'
-promo choice('bon','pasbon')
-titre ivarchar(128)
-adel varchar(128)
-ass varchar(128)
-web varchar(128)
-tel integer
-fax integer
-datenaiss datetime
-test boolean
-description text
-firstname ivarchar(64)
--- a/server/test/data/schema/Societe.py Wed Jul 15 09:45:13 2009 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-"""
-
-:organization: Logilab
-:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.
-:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
-:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
-"""
-class Societe(EntityType):
- permissions = {
- 'read': ('managers', 'users', 'guests'),
- 'update': ('managers', 'owners', ERQLExpression('U login L, X nom L')),
- 'delete': ('managers', 'owners', ERQLExpression('U login L, X nom L')),
- 'add': ('managers', 'users',)
- }
-
- nom = String(maxsize=64, fulltextindexed=True)
- web = String(maxsize=128)
- type = String(maxsize=128) # attribute in common with Note
- tel = Int()
- fax = Int()
- rncs = String(maxsize=128)
- ad1 = String(maxsize=128)
- ad2 = String(maxsize=128)
- ad3 = String(maxsize=128)
- cp = String(maxsize=12)
- ville= String(maxsize=32)
-
-
-class travaille(RelationType):
- permissions = {
- 'read': ('managers', 'users', 'guests'),
- 'add': ('managers', RRQLExpression('U has_update_permission S')),
- 'delete': ('managers', RRQLExpression('O owned_by U')),
- }
-
-
-class Division(Societe):
- __specializes_schema__ = True
-
-class SubDivision(Division):
- __specializes_schema__ = True
- travaille_subdivision = ObjectRelation('Personne')
--- a/server/test/data/schema/custom.py Wed Jul 15 09:45:13 2009 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-"""
-
-:organization: Logilab
-:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.
-:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
-:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
-"""
-
-
-class test(AttributeRelationType):
- permissions = {'read': ('managers', 'users', 'guests'),
- 'delete': ('managers',),
- 'add': ('managers',)}
-
-class fiche(RelationType):
- inlined = True
- subject = 'Personne'
- object = 'Card'
- cardinality = '??'
-
-class multisource_rel(RelationDefinition):
- subject = ('Card', 'Note')
- object = 'Note'
-
-class multisource_crossed_rel(RelationDefinition):
- subject = ('Card', 'Note')
- object = 'Note'
-
-class multisource_inlined_rel(RelationType):
- inlined = True
- cardinality = '?*'
- subject = ('Card', 'Note')
- object = ('Affaire', 'Note')
-
-
-class see_also(RelationDefinition):
- subject = ('Bookmark', 'Note')
- object = ('Bookmark', 'Note')
-
-_euser = import_schema('base').CWUser
-_euser.__relations__[0].fulltextindexed = True
--- a/server/test/data/schema/note.py Wed Jul 15 09:45:13 2009 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-"""
-
-:organization: Logilab
-:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.
-:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
-:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
-"""
-
-class para(AttributeRelationType):
- permissions = {
- 'read': ('managers', 'users', 'guests'),
- 'add': ('managers', ERQLExpression('X in_state S, S name "todo"')),
- 'delete': ('managers', ERQLExpression('X in_state S, S name "todo"')),
- }
-
-class in_state(RelationDefinition):
- subject = 'Note'
- object = 'State'
- cardinality = '1*'
- constraints=[RQLConstraint('S is ET, O state_of ET')]
-
-class wf_info_for(RelationDefinition):
- subject = 'TrInfo'
- object = 'Note'
- cardinality = '1*'
--- a/server/test/data/schema/relations.rel Wed Jul 15 09:45:13 2009 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-Personne travaille Societe
-Personne evaluee Note
-CWUser evaluee Note
-Societe evaluee Note
-Personne concerne Affaire
-Affaire concerne Societe
-Affaire concerne Note
-
-Note ecrit_par Personne inline CONSTRAINT E concerns P, X version_of P
-Note ecrit_par CWUser inline CONSTRAINT
-Personne connait Personne symetric
-
-# not inlined intentionaly
-Comment comments Personne
-
-Note inline1 Affaire inline
-Personne inline2 Affaire inline
-
-Note todo_by CWUser
-Affaire todo_by Personne
-
-Folder see_also Folder
-
-
-Affaire documented_by Card
-
-CWUser copain CWUser
-
-Tag tags CWUser
-Tag tags CWGroup
-Tag tags State
-Tag tags Note
-Tag tags Card
-Tag tags Affaire
-
-Note filed_under Folder
-Affaire filed_under Folder
-
-Card require_permission CWPermission
-Note require_permission CWPermission
-Personne require_permission CWPermission
-
-CWPermission require_state State
-
-Note migrated_from Note
-
-Note attachment File
-Note attachment Image
--- a/server/test/unittest_rql2sql.py Wed Jul 15 09:45:13 2009 +0200
+++ b/server/test/unittest_rql2sql.py Thu Jul 16 13:30:13 2009 +0200
@@ -1436,6 +1436,22 @@
'''SELECT COUNT(1)
WHERE EXISTS(SELECT 1 FROM owned_by_relation AS rel_owned_by0, cw_Affaire AS P WHERE rel_owned_by0.eid_from=P.cw_eid AND rel_owned_by0.eid_to=1 UNION SELECT 1 FROM owned_by_relation AS rel_owned_by1, cw_Note AS P WHERE rel_owned_by1.eid_from=P.cw_eid AND rel_owned_by1.eid_to=1)''')
+ def test_attr_map(self):
+ def generate_ref(gen, linkedvar, rel):
+ linkedvar.accept(gen)
+ return 'VERSION_DATA(%s)' % linkedvar._q_sql
+ self.o.attr_map['Affaire.ref'] = generate_ref
+ try:
+ self._check('Any R WHERE X ref R',
+ '''SELECT VERSION_DATA(X.cw_eid)
+FROM cw_Affaire AS X''')
+ self._check('Any X WHERE X ref 1',
+ '''SELECT X.cw_eid
+FROM cw_Affaire AS X
+WHERE VERSION_DATA(X.cw_eid)=1''')
+ finally:
+ self.o.attr_map.clear()
+
class SqliteSQLGeneratorTC(PostgresSQLGeneratorTC):
--- a/skeleton/__pkginfo__.py.tmpl Wed Jul 15 09:45:13 2009 +0200
+++ b/skeleton/__pkginfo__.py.tmpl Thu Jul 16 13:30:13 2009 +0200
@@ -34,21 +34,16 @@
and not fname.endswith('~')
and not isdir(join(dirpath, fname))]
-try:
- data_files = [
- # common files
- [THIS_CUBE_DIR, [fname for fname in glob('*.py') if fname != 'setup.py']],
- ]
- # check for possible extended cube layout
- for dirname in ('entities', 'views', 'sobjects', 'hooks', 'schema', 'data', 'i18n', 'migration'):
- if isdir(dirname):
- data_files.append([join(THIS_CUBE_DIR, dirname), listdir(dirname)])
- # Note: here, you'll need to add subdirectories if you want
- # them to be included in the debian package
-except OSError:
- if exists(dirname(__file__)):
- raise
- # we are in an installed directory
+data_files = [
+ # common files
+ [THIS_CUBE_DIR, [fname for fname in glob('*.py') if fname != 'setup.py']],
+ ]
+# check for possible extended cube layout
+for dirname in ('entities', 'views', 'sobjects', 'hooks', 'schema', 'data', 'i18n', 'migration'):
+ if isdir(dirname):
+ data_files.append([join(THIS_CUBE_DIR, dirname), listdir(dirname)])
+# Note: here, you'll need to add subdirectories if you want
+# them to be included in the debian package
cube_eid = None # <=== FIXME if you need direct bug-subscription
--- a/test/unittest_rtags.py Wed Jul 15 09:45:13 2009 +0200
+++ b/test/unittest_rtags.py Thu Jul 16 13:30:13 2009 +0200
@@ -6,7 +6,7 @@
:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
"""
from logilab.common.testlib import TestCase, unittest_main
-from cubicweb.rtags import RelationTags, RelationTagsSet
+from cubicweb.rtags import RelationTags, RelationTagsSet, RelationTagsDict
class RelationTagsTC(TestCase):
@@ -53,12 +53,30 @@
rtags.tag_subject_of(('*', 'travaille', '*'), 'secondary')
self.assertEquals(rtags.get('Societe', 'travaille', '*', 'subject'),
set(('primary', 'secondary')))
- self.assertEquals(rtags.get('Societe', 'travaille', '*', 'subject'),
- set(('primary', 'secondary')))
self.assertEquals(rtags.get('Note', 'travaille', '*', 'subject'),
set(('secondary',)))
self.assertEquals(rtags.get('Note', 'tags', "*", 'subject'),
set())
+ def test_rtagdict_expansion(self):
+ rtags = RelationTagsDict()
+ rtags.tag_subject_of(('Societe', 'travaille', '*'),
+ {'key1': 'val1', 'key2': 'val1'})
+ rtags.tag_subject_of(('*', 'travaille', '*'),
+ {'key1': 'val0', 'key3': 'val0'})
+ rtags.tag_subject_of(('Societe', 'travaille', '*'),
+ {'key2': 'val2'})
+ self.assertEquals(rtags.get('Societe', 'travaille', '*', 'subject'),
+ {'key1': 'val1', 'key2': 'val2', 'key3': 'val0'})
+ self.assertEquals(rtags.get('Note', 'travaille', '*', 'subject'),
+ {'key1': 'val0', 'key3': 'val0'})
+ self.assertEquals(rtags.get('Note', 'tags', "*", 'subject'),
+ {})
+
+ rtags.setdefault(('Societe', 'travaille', '*', 'subject'), 'key1', 'val4')
+ rtags.setdefault(('Societe', 'travaille', '*', 'subject'), 'key4', 'val4')
+ self.assertEquals(rtags.get('Societe', 'travaille', '*', 'subject'),
+ {'key1': 'val1', 'key2': 'val2', 'key3': 'val0', 'key4': 'val4'})
+
if __name__ == '__main__':
unittest_main()
--- a/utils.py Wed Jul 15 09:45:13 2009 +0200
+++ b/utils.py Thu Jul 16 13:30:13 2009 +0200
@@ -326,4 +326,18 @@
"""
# XXX deprecated, no more necessary
+def get_schema_property(eschema, rschema, role, property):
+ # XXX use entity.e_schema.role_rproperty(role, rschema, property, tschemas[0]) once yams > 0.23.0 is out
+ if role == 'subject':
+ targetschema = rschema.objects(eschema)[0]
+ return rschema.rproperty(eschema, targetschema, property)
+ targetschema = rschema.subjects(eschema)[0]
+ return rschema.rproperty(targetschema, eschema, property)
+def compute_cardinality(eschema, rschema, role):
+ if role == 'subject':
+ targetschema = rschema.objects(eschema)[0]
+ return rschema.rproperty(eschema, targetschema, 'cardinality')[0]
+ targetschema = rschema.subjects(eschema)[0]
+ return rschema.rproperty(targetschema, eschema, 'cardinality')[1]
+
--- a/view.py Wed Jul 15 09:45:13 2009 +0200
+++ b/view.py Thu Jul 16 13:30:13 2009 +0200
@@ -12,7 +12,7 @@
from cStringIO import StringIO
from logilab.common.deprecation import obsolete
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
from cubicweb import NotAnEntity
from cubicweb.selectors import yes, non_final_entity, nonempty_rset, none_rset
@@ -219,7 +219,7 @@
def wdata(self, data):
"""simple helper that escapes `data` and writes into `self.w`"""
- self.w(html_escape(data))
+ self.w(xml_escape(data))
def html_headers(self):
"""return a list of html headers (eg something to be inserted between
@@ -440,10 +440,10 @@
def cb(*args):
_cb(*args)
cbname = self.req.register_onetime_callback(cb, *args)
- return self.build_js(cbname, html_escape(msg or ''))
+ return self.build_js(cbname, xml_escape(msg or ''))
def build_update_js_call(self, cbname, msg):
- rql = html_escape(self.rset.printable_rql())
+ rql = xml_escape(self.rset.printable_rql())
return "javascript:userCallbackThenUpdateUI('%s', '%s', '%s', '%s', '%s', '%s')" % (
cbname, self.id, rql, msg, self.__registry__, self.div_id())
--- a/vregistry.py Wed Jul 15 09:45:13 2009 +0200
+++ b/vregistry.py Thu Jul 16 13:30:13 2009 +0200
@@ -1,10 +1,10 @@
"""
-* the vregistry handle various type of objects interacting
- together. The vregistry handle registration of dynamically loaded
- objects and provide a convenient api access to those objects
+* the vregistry handles various types of objects interacting
+ together. The vregistry handles registration of dynamically loaded
+ objects and provides a convenient api to access those objects
according to a context
-* to interact with the vregistry, object should inherit from the
+* to interact with the vregistry, objects should inherit from the
VObject abstract class
* the selection procedure has been generalized by delegating to a
--- a/web/box.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/box.py Thu Jul 16 13:30:13 2009 +0200
@@ -8,7 +8,7 @@
__docformat__ = "restructuredtext en"
_ = unicode
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
from cubicweb import Unauthorized, role as get_role, target as get_target
from cubicweb.selectors import (one_line_rset, primary_view,
@@ -74,7 +74,7 @@
.format_actions method
"""
if escape:
- title = html_escape(title)
+ title = xml_escape(title)
return self.box_action(self._action(title, path, **kwargs))
def _action(self, title, path, **kwargs):
--- a/web/component.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/component.py Thu Jul 16 13:30:13 2009 +0200
@@ -9,7 +9,7 @@
_ = unicode
from logilab.common.deprecation import class_renamed
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
from cubicweb import role
from cubicweb.utils import merge_dicts
@@ -117,7 +117,7 @@
def page_link(self, path, params, start, stop, content):
url = self.build_url(path, **merge_dicts(params, {self.start_param : start,
self.stop_param : stop,}))
- url = html_escape(url)
+ url = xml_escape(url)
if start == self.starting_from:
return self.selected_page_link_templ % (url, content, content)
return self.page_link_templ % (url, content, content)
@@ -130,7 +130,7 @@
stop = start + self.page_size - 1
url = self.build_url(**merge_dicts(params, {self.start_param : start,
self.stop_param : stop,}))
- url = html_escape(url)
+ url = xml_escape(url)
return self.previous_page_link_templ % (url, title, content)
def next_link(self, params, content='>>', title=_('next_results')):
@@ -140,7 +140,7 @@
stop = start + self.page_size - 1
url = self.build_url(**merge_dicts(params, {self.start_param : start,
self.stop_param : stop,}))
- url = html_escape(url)
+ url = xml_escape(url)
return self.next_page_link_templ % (url, title, content)
--- a/web/controller.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/controller.py Thu Jul 16 13:30:13 2009 +0200
@@ -184,11 +184,9 @@
elif '__redirectpath' in self.req.form:
# if redirect path was explicitly specified in the form, use it
path = self.req.form['__redirectpath']
- if self._edited_entity:
- msg = newparams.get('__message', '')
- msg += ' (<a href="%s">%s</a>)' % (
- self._edited_entity.absolute_url(),
- self.req._('click here to see created entity'))
+ if self._edited_entity and path != self._edited_entity.rest_path():
+ # XXX may be here on modification? if yes the message should be
+ # modified where __createdpath is detected (cw.web.request)
newparams['__createdpath'] = self._edited_entity.rest_path()
elif self._after_deletion_path:
# else it should have been set during form processing
--- a/web/data/cubicweb.ajax.js Wed Jul 15 09:45:13 2009 +0200
+++ b/web/data/cubicweb.ajax.js Thu Jul 16 13:30:13 2009 +0200
@@ -59,8 +59,8 @@
if (typeof buildWidgets != 'undefined') {
buildWidgets(node);
}
- if (typeof roundedCornersOnLoad != 'undefined') {
- roundedCornersOnLoad();
+ if (typeof roundedCorners != 'undefined') {
+ roundedCorners(node);
}
loadDynamicFragments(node);
jQuery(CubicWeb).trigger('ajax-loaded');
@@ -231,6 +231,7 @@
// make sure the component is visible
removeElementClass(node, "hidden");
swapDOM(node, domnode);
+ postAjaxLoad(domnode);
}
});
d.addCallback(resetCursor);
--- a/web/data/cubicweb.edition.js Wed Jul 15 09:45:13 2009 +0200
+++ b/web/data/cubicweb.edition.js Thu Jul 16 13:30:13 2009 +0200
@@ -348,11 +348,11 @@
// Success
if (result[0]) {
if (onsuccess) {
- return onsuccess(result[1], formid);
+ onsuccess(result[1], formid);
} else {
document.location.href = result[1];
- return ;
}
+ return;
}
unfreezeFormButtons(formid);
// Failures
@@ -362,7 +362,7 @@
if ( !isArrayLike(descr) || descr.length != 2 ) {
log('got strange error :', descr);
updateMessage(descr);
- return ;
+ return;
}
_displayValidationerrors(formid, descr[0], descr[1]);
updateMessage(_("please correct errors below"));
@@ -370,7 +370,7 @@
if (onfailure){
onfailure(formid);
}
- return false;
+ return;
}
@@ -422,7 +422,7 @@
});
}
-$(document).ready(setFormsTarget);
+jQuery(document).ready(setFormsTarget);
/*
@@ -454,9 +454,9 @@
* @param eid : the eid of the entity being edited
* @param reload: boolean to reload page if true (when changing URL dependant data)
*/
-function inlineValidateAttributeForm(formid, rtype, eid, divid, reload, default_value) {
+function inlineValidateAttributeForm(rtype, eid, divid, reload, default_value) {
try {
- var form = getNode(formid);
+ var form = getNode(divid+'-form');
if (typeof FCKeditorAPI != "undefined") {
for ( var name in FCKeditorAPI.__Instances ) {
var oEditor = FCKeditorAPI.__Instances[name] ;
@@ -473,7 +473,7 @@
return false;
}
d.addCallback(function (result, req) {
- handleFormValidationResponse(formid, noop, noop, result);
+ handleFormValidationResponse(divid+'-form', noop, noop, result);
if (reload) {
document.location.href = result[1];
} else {
@@ -486,7 +486,7 @@
// hide global error messages
jQuery('div.errorMessage').remove();
jQuery('#appMsg').hide();
- cancelInlineEdit(eid, rtype, divid);
+ hideInlineEdit(eid, rtype, divid);
}
}
return false;
@@ -494,30 +494,29 @@
return false;
}
-function inlineValidateRelationForm(formid, rtype, role, eid, divid, vid, default_value) {
+function inlineValidateRelationForm(rtype, role, eid, divid, reload, vid,
+ default_value, lzone) {
try {
- var form = getNode(formid);
+ var form = getNode(divid+'-form');
var relname = rtype + ':' + eid;
var newtarget = jQuery('[name=' + relname + ']').val();
var zipped = formContents(form);
- var d = asyncRemoteExec('edit_relation', 'apply', zipped[0], zipped[1], rtype, role,
- eid, vid, default_value);
+ var d = asyncRemoteExec('validate_form', 'apply', zipped[0], zipped[1]);
} catch (ex) {
log('got exception', ex);
return false;
}
d.addCallback(function (result, req) {
- handleFormValidationResponse(formid, noop, noop, result);
- var fieldview = getNode(divid);
- fieldview.innerHTML = result[2];
- // switch inline form off only if no error
- if (result[0]) {
- // hide global error messages
- jQuery('div.errorMessage').remove();
- jQuery('#appMsg').hide();
- var inputname = 'edit' + role[0] + '-' + relname;
- jQuery('input[name=' + inputname + ']').val(newtarget);
- cancelInlineEdit(eid, rtype, divid);
+ handleFormValidationResponse(divid+'-form', noop, noop, result);
+ if (reload) {
+ document.location.href = result[1];
+ } else {
+ if (result[0]) {
+ var d = asyncRemoteExec('reledit_form', eid, rtype, role, lzone);
+ d.addCallback(function (result) {
+ jQuery('#'+divid+'-reledit').replaceWith(result);
+ });
+ }
}
return false;
});
@@ -528,12 +527,12 @@
/**** inline edition ****/
function showInlineEditionForm(eid, rtype, divid) {
jQuery('#' + divid).hide();
- jQuery('#' + divid + '-form').show();
+ jQuery('#' + divid+'-form').show();
}
-function cancelInlineEdit(eid, rtype, divid) {
+function hideInlineEdit(eid, rtype, divid) {
jQuery('#' + divid).show();
- jQuery('#' + divid + '-form').hide();
+ jQuery('#' + divid+'-form').hide();
}
CubicWeb.provide('edition.js');
--- a/web/data/cubicweb.formfilter.js Wed Jul 15 09:45:13 2009 +0200
+++ b/web/data/cubicweb.formfilter.js Thu Jul 16 13:30:13 2009 +0200
@@ -126,27 +126,35 @@
});
facet.find('div.facetCheckBox').click(function () {
var $this = jQuery(this);
+ if ($this.hasClass('facetValueDisabled')){
+ return
+ }
if ($this.hasClass('facetValueSelected')) {
$this.removeClass('facetValueSelected');
$this.find('img').each(function (i){
if (this.getAttribute('cubicweb:unselimg')){
this.setAttribute('src', UNSELECTED_BORDER_IMG);
+ this.setAttribute('alt', (_('not selected')));
}
else{
this.setAttribute('src', UNSELECTED_IMG);
+ this.setAttribute('alt', (_('not selected')));
}
});
var index = parseInt($this.attr('cubicweb:idx'));
- var shift = jQuery.grep(facet.find('.facetValueSelected'), function (n) {
- var nindex = parseInt(n.getAttribute('cubicweb:idx'));
- return nindex > index;
- }).length;
- index += shift;
- var parent = this.parentNode;
- var $insertAfter = jQuery(parent).find('.facetCheckBox:nth('+index+')');
- if ( ! ($insertAfter.length == 1 && index == 0) ) {
- // only rearrange element if necessary
- $insertAfter.after(this);
+ // we dont need to move the element when cubicweb:idx == 0
+ if (index > 0){
+ var shift = jQuery.grep(facet.find('.facetValueSelected'), function (n) {
+ var nindex = parseInt(n.getAttribute('cubicweb:idx'));
+ return nindex > index;
+ }).length;
+ index += shift;
+ var parent = this.parentNode;
+ var $insertAfter = jQuery(parent).find('.facetCheckBox:nth('+index+')');
+ if ( ! ($insertAfter.length == 1 && shift == 0) ) {
+ // only rearrange element if necessary
+ $insertAfter.after(this);
+ }
}
} else {
var lastSelected = facet.find('.facetValueSelected:last');
@@ -157,7 +165,8 @@
jQuery(parent).prepend(this);
}
jQuery(this).addClass('facetValueSelected');
- jQuery(this).find('img').attr('src', SELECTED_IMG);
+ var $img = jQuery(this).find('img');
+ $img.attr('src', SELECTED_IMG).attr('alt', (_('selected')));
}
buildRQL.apply(null, evalJSON(form.attr('cubicweb:facetargs')));
facet.find('.facetBody').animate({scrollTop: 0}, '');
--- a/web/data/cubicweb.htmlhelpers.js Wed Jul 15 09:45:13 2009 +0200
+++ b/web/data/cubicweb.htmlhelpers.js Thu Jul 16 13:30:13 2009 +0200
@@ -1,4 +1,5 @@
CubicWeb.require('python.js');
+CubicWeb.require('jquery.corner.js');
/* returns the document's baseURI. (baseuri() uses document.baseURI if
* available and inspects the <base> tag manually otherwise.)
@@ -15,6 +16,7 @@
return '';
}
+// XXX this is used exactly ONCE in web/views/massmailing.py
function insertText(text, areaId) {
var textarea = jQuery('#' + areaId);
if (document.selection) { // IE
@@ -39,6 +41,7 @@
}
/* taken from dojo toolkit */
+// XXX this looks unused
function setCaretPos(element, start, end){
if(!end){ end = element.value.length; } // NOTE: Strange - should be able to put caret at start of text?
// Mozilla
@@ -71,30 +74,30 @@
}
}
+
+// XXX this looks unused
function setProgressMessage(label) {
var body = document.getElementsByTagName('body')[0];
body.appendChild(DIV({id: 'progress'}, label));
jQuery('#progress').show();
}
+// XXX this looks unused
function resetProgressMessage() {
var body = document.getElementsByTagName('body')[0];
jQuery('#progress').hide();
}
-/* set body's cursor to 'progress'
- */
+/* set body's cursor to 'progress' */
function setProgressCursor() {
var body = document.getElementsByTagName('body')[0];
body.style.cursor = 'progress';
}
-/*
- * reset body's cursor to default (mouse cursor). The main
+/* reset body's cursor to default (mouse cursor). The main
* purpose of this function is to be used as a callback in the
- * deferreds' callbacks chain.
- */
+ * deferreds' callbacks chain. */
function resetCursor(result) {
var body = document.getElementsByTagName('body')[0];
body.style.cursor = 'default';
@@ -137,7 +140,7 @@
*/
function firstSelected(selectNode) {
var selection = filter(attrgetter('selected'), selectNode.options);
- return (selection.length>0) ? getNodeAttribute(selection[0], 'value'):null;
+ return (selection.length > 0) ? getNodeAttribute(selection[0], 'value'):null;
}
/* toggle visibility of an element by its id
@@ -148,22 +151,12 @@
/* toggles visibility of login popup div */
+// XXX used exactly ONCE
function popupLoginBox() {
toggleVisibility('popupLoginBox');
jQuery('#__login:visible').focus();
}
-/*
- * return true (resp. false) if <element> (resp. doesn't) matches <properties>
- */
-function elementMatches(properties, element) {
- for (prop in properties) {
- if (getNodeAttribute(element, prop) != properties[prop]) {
- return false;
- }
- }
- return true;
-}
/* returns the list of elements in the document matching the tag name
* and the properties provided
@@ -174,9 +167,13 @@
* list() function)
*/
function getElementsMatching(tagName, properties, /* optional */ parent) {
- var filterfunc = partial(elementMatches, properties);
parent = parent || document;
- return filter(filterfunc, parent.getElementsByTagName(tagName));
+ return filter(function elementMatches(element) {
+ for (prop in properties) {
+ if (getNodeAttribute(element, prop) != properties[prop]) {
+ return false;}}
+ return true;},
+ parent.getElementsByTagName(tagName));
}
/*
@@ -196,9 +193,8 @@
forEach(filter(filterfunc, elements), function(cb) {cb.checked=checked;});
}
-/*
- * centers an HTML element on the screen
- */
+/* centers an HTML element on the screen */
+// XXX looks unused
function centerElement(obj){
var vpDim = getViewportDimensions();
var elemDim = getElementDimensions(obj);
@@ -227,15 +223,9 @@
function isTextNode(domNode) { return domNode.nodeType == 3; }
function isElementNode(domNode) { return domNode.nodeType == 1; }
+// XXX this looks unused
function changeLinkText(link, newText) {
jQuery(link).text(newText);
-// for (var i=0; i<link.childNodes.length; i++) {
-// var node = link.childNodes[i];
-// if (isTextNode(node)) {
-// swapDOM(node, document.createTextNode(newText));
-// break;
-// }
-// }
}
@@ -247,19 +237,29 @@
}
}
+// XXX this looks unused
function limitTextAreaSize(textarea, size) {
var $area = jQuery(textarea);
$area.val($area.val().slice(0, size));
}
//============= page loading events ==========================================//
-function roundedCornersOnLoad() {
- jQuery('div.sideBoxBody').corner('bottom 6px');
- jQuery('div.boxTitle, div.boxPrefTitle, div.sideBoxTitle, th.month').corner('top 6px');
+
+CubicWeb.rounded = [
+ ['div.sideBoxBody', 'bottom 6px'],
+ ['div.boxTitle, div.boxPrefTitle, div.sideBoxTitle, th.month', 'top 6px']
+ ];
+
+
+
+function roundedCorners(node) {
+ node = jQuery(node);
+ for(var r=0; r < CubicWeb.rounded.length; r++) {
+ node.find(CubicWeb.rounded[r][0]).corner(CubicWeb.rounded[r][1]);
+ }
}
-jQuery(document).ready(roundedCornersOnLoad);
-
+jQuery(document).ready(function () {roundedCorners(this.body)});
CubicWeb.provide('htmlhelpers.js');
--- a/web/data/cubicweb.python.js Wed Jul 15 09:45:13 2009 +0200
+++ b/web/data/cubicweb.python.js Thu Jul 16 13:30:13 2009 +0200
@@ -15,12 +15,12 @@
return true;
}
return false;
-}
+};
Date.prototype.add = function(days) {
- var res = new Date()
- res.setTime(this.getTime() + (days * ONE_DAY))
- return res
+ var res = new Date();
+ res.setTime(this.getTime() + (days * ONE_DAY));
+ return res;
};
Date.prototype.sub = function(days) {
@@ -29,14 +29,14 @@
Date.prototype.iadd = function(days) {
// in-place add
- this.setTime(this.getTime() + (days * ONE_DAY))
+ this.setTime(this.getTime() + (days * ONE_DAY));
// avoid strange rounding problems !!
this.setHours(12);
};
Date.prototype.isub = function(days) {
// in-place sub
- this.setTime(this.getTime() - (days * ONE_DAY))
+ this.setTime(this.getTime() - (days * ONE_DAY));
};
/*
@@ -170,14 +170,14 @@
*/
String.prototype.startsWith = function(prefix) {
return this.indexOf(prefix) == 0;
-}
+};
/* python-like endsWith method for js strings */
String.prototype.endsWith = function(suffix) {
var startPos = this.length - suffix.length;
if (startPos < 0) { return false; }
return this.lastIndexOf(suffix, startPos) == startPos;
-}
+};
/* python-like strip method for js strings */
String.prototype.strip = function() {
@@ -187,12 +187,12 @@
/* py-equiv: string in list */
String.prototype.in_ = function(values) {
return findValue(values, this) != -1;
-}
+};
/* py-equiv: str.join(list) */
String.prototype.join = function(args) {
return args.join(this);
-}
+};
/* python-like list builtin
* transforms an iterable in a js sequence
--- a/web/facet.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/facet.py Thu Jul 16 13:30:13 2009 +0200
@@ -12,7 +12,7 @@
from copy import deepcopy
from datetime import date, datetime, timedelta
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
from logilab.common.graph import has_path
from logilab.common.decorators import cached
@@ -21,6 +21,7 @@
from rql import parse, nodes
from cubicweb import Unauthorized, typed_eid
+from cubicweb.schema import display_name
from cubicweb.utils import datetime2ticks, make_uid, ustrftime
from cubicweb.selectors import match_context_prop, partial_relation_possible
from cubicweb.appobject import AppRsetObject
@@ -70,7 +71,7 @@
def filter_hiddens(w, **kwargs):
for key, val in kwargs.items():
w(u'<input type="hidden" name="%s" value="%s" />' % (
- key, html_escape(val)))
+ key, xml_escape(val)))
def _may_be_removed(rel, schema, mainvar):
@@ -586,11 +587,11 @@
self.items.append(item)
def _render(self):
- title = html_escape(self.facet.title)
- facetid = html_escape(self.facet.id)
+ title = xml_escape(self.facet.title)
+ facetid = xml_escape(self.facet.id)
self.w(u'<div id="%s" class="facet">\n' % facetid)
self.w(u'<div class="facetTitle" cubicweb:facetName="%s">%s</div>\n' %
- (html_escape(facetid), title))
+ (xml_escape(facetid), title))
if self.facet.support_and():
_ = self.facet.req._
self.w(u'''<select name="%s" class="radio facetOperator" title="%s">
@@ -616,8 +617,8 @@
self.value = None
def _render(self):
- title = html_escape(self.facet.title)
- facetid = html_escape(self.facet.id)
+ title = xml_escape(self.facet.title)
+ facetid = xml_escape(self.facet.id)
self.w(u'<div id="%s" class="facet">\n' % facetid)
self.w(u'<div class="facetTitle" cubicweb:facetName="%s">%s</div>\n' %
(facetid, title))
@@ -660,7 +661,7 @@
facet.req.add_js('ui.slider.js')
facet.req.add_css('ui.all.css')
sliderid = make_uid('the slider')
- facetid = html_escape(self.facet.id)
+ facetid = xml_escape(self.facet.id)
facet.req.html_headers.add_onload(self.onload % {
'sliderid': sliderid,
'facetid': facetid,
@@ -668,7 +669,7 @@
'maxvalue': self.maxvalue,
'formatter': self.formatter,
})
- title = html_escape(self.facet.title)
+ title = xml_escape(self.facet.title)
self.w(u'<div id="%s" class="facet">\n' % facetid)
self.w(u'<div class="facetTitle" cubicweb:facetName="%s">%s</div>\n' %
(facetid, title))
@@ -720,9 +721,9 @@
imgsrc = self.req.datadir_url + self.unselected_img
imgalt = self.req._('not selected')
self.w(u'<div class="facetValue facetCheckBox%s" cubicweb:value="%s">\n'
- % (cssclass, html_escape(unicode(self.value))))
+ % (cssclass, xml_escape(unicode(self.value))))
self.w(u'<img src="%s" alt="%s"/> ' % (imgsrc, imgalt))
- self.w(u'<a href="javascript: {}">%s</a>' % html_escape(self.label))
+ self.w(u'<a href="javascript: {}">%s</a>' % xml_escape(self.label))
self.w(u'</div>')
class CheckBoxFacetWidget(HTMLWidget):
@@ -736,8 +737,8 @@
self.selected = selected
def _render(self):
- title = html_escape(self.facet.title)
- facetid = html_escape(self.facet.id)
+ title = xml_escape(self.facet.title)
+ facetid = xml_escape(self.facet.id)
self.w(u'<div id="%s" class="facet">\n' % facetid)
if self.selected:
cssclass = ' facetValueSelected'
@@ -748,7 +749,7 @@
imgsrc = self.req.datadir_url + self.unselected_img
imgalt = self.req._('not selected')
self.w(u'<div class="facetValue facetCheckBox%s" cubicweb:value="%s">\n'
- % (cssclass, html_escape(unicode(self.value))))
+ % (cssclass, xml_escape(unicode(self.value))))
self.w(u'<div class="facetCheckBoxWidget">')
self.w(u'<img src="%s" alt="%s" cubicweb:unselimg="true" /> ' % (imgsrc, imgalt))
self.w(u'<label class="facetTitle" cubicweb:facetName="%s"><a href="javascript: {}">%s</a></label>' % (facetid, title))
--- a/web/formfields.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/formfields.py Thu Jul 16 13:30:13 2009 +0200
@@ -10,11 +10,11 @@
from warnings import warn
from datetime import datetime
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
from yams.constraints import SizeConstraint, StaticVocabularyConstraint
from cubicweb.schema import FormatConstraint
-from cubicweb.utils import ustrftime
+from cubicweb.utils import ustrftime, compute_cardinality
from cubicweb.common import tags, uilib
from cubicweb.web import INTERNAL_FIELD_VALUE
from cubicweb.web.formwidgets import (
@@ -203,9 +203,17 @@
widget = Select()
elif self.max_length and self.max_length < 257:
widget = TextInput()
+
super(StringField, self).init_widget(widget)
if isinstance(self.widget, TextArea):
self.init_text_area(self.widget)
+ elif isinstance(self.widget, TextInput):
+ self.init_text_input(self.widget)
+
+ def init_text_input(self, widget):
+ if self.max_length:
+ widget.attrs.setdefault('size', min(45, self.max_length))
+ widget.attrs.setdefault('maxlength', self.max_length)
def init_text_area(self, widget):
if self.max_length < 513:
@@ -219,6 +227,9 @@
super(RichTextField, self).__init__(**kwargs)
self.format_field = format_field
+ def init_text_area(self, widget):
+ pass
+
def get_widget(self, form):
if self.widget is None:
if self.use_fckeditor(form):
@@ -300,9 +311,9 @@
if self.format_field or self.encoding_field:
divid = '%s-advanced' % form.context[self]['name']
wdgs.append(u'<a href="%s" title="%s"><img src="%s" alt="%s"/></a>' %
- (html_escape(uilib.toggle_action(divid)),
+ (xml_escape(uilib.toggle_action(divid)),
form.req._('show advanced fields'),
- html_escape(form.req.build_url('data/puce_down.png')),
+ xml_escape(form.req.build_url('data/puce_down.png')),
form.req._('show advanced fields')))
wdgs.append(u'<div id="%s" class="hidden">' % divid)
if self.format_field:
@@ -460,7 +471,7 @@
fieldclass = None
if role == 'subject':
targetschema = rschema.objects(eschema)[0]
- card = rschema.rproperty(eschema, targetschema, 'cardinality')[0]
+ card = compute_cardinality(eschema, rschema, role)
help = rschema.rproperty(eschema, targetschema, 'description')
if rschema.is_final():
if rschema.rproperty(eschema, targetschema, 'internationalizable'):
@@ -470,7 +481,7 @@
kwargs.setdefault('initial', get_default)
else:
targetschema = rschema.subjects(eschema)[0]
- card = rschema.rproperty(targetschema, eschema, 'cardinality')[1]
+ card = compute_cardinality(eschema, rschema, role)
help = rschema.rproperty(targetschema, eschema, 'description')
kwargs['required'] = card in '1+'
kwargs['name'] = rschema.type
--- a/web/formwidgets.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/formwidgets.py Thu Jul 16 13:30:13 2009 +0200
@@ -146,17 +146,22 @@
class TextArea(FieldWidget):
"""<textarea>"""
+
def render(self, form, field):
name, values, attrs = self._render_attrs(form, field)
attrs.setdefault('onkeyup', 'autogrow(this)')
- attrs.setdefault('cols', 80)
- attrs.setdefault('rows', 20)
if not values:
value = u''
elif len(values) == 1:
value = values[0]
else:
raise ValueError('a textarea is not supposed to be multivalued')
+ lines = value.splitlines()
+ linecount = len(lines)
+ for line in lines:
+ linecount += len(line) / 80
+ attrs.setdefault('cols', 80)
+ attrs.setdefault('rows', min(15, linecount + 2))
return tags.textarea(value, name=name, **attrs)
--- a/web/htmlwidgets.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/htmlwidgets.py Thu Jul 16 13:30:13 2009 +0200
@@ -9,7 +9,7 @@
:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
"""
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
from cubicweb.utils import UStringIO
from cubicweb.common.uilib import toggle_action
@@ -81,7 +81,7 @@
self.w(u'<div class="%s">' % self._class)
if self.title:
if self.escape:
- title = '<span>%s</span>' % html_escape(self.title)
+ title = '<span>%s</span>' % xml_escape(self.title)
else:
title = '<span>%s</span>' % self.title
self.w(u'<div class="%s">%s</div>' % (self.title_class, title))
@@ -204,7 +204,7 @@
def __init__(self, href, label, _class='', title='', ident='', escape=False):
self.href = href
if escape:
- self.label = html_escape(label)
+ self.label = xml_escape(label)
else:
self.label = label
self._class = _class or ''
@@ -213,7 +213,7 @@
def _render(self):
link = u'<a href="%s" title="%s">%s</a>' % (
- html_escape(self.href), html_escape(self.title), self.label)
+ xml_escape(self.href), xml_escape(self.title), self.label)
if self.ident:
self.w(u'<li id="%s" class="%s">%s</li>\n' % (self.ident, self._class, link))
else:
--- a/web/request.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/request.py Thu Jul 16 13:30:13 2009 +0200
@@ -20,7 +20,7 @@
from logilab.common.decorators import cached
from logilab.common.deprecation import obsolete
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
from cubicweb.dbapi import DBAPIRequest
from cubicweb.common.mail import header
@@ -153,7 +153,8 @@
else:
self.form[k] = v
# special key for created entity, added in controller's reset method
- if '__createdpath' in params:
+ # if no message set, we don't want this neither
+ if '__createdpath' in params and self.message:
self.message += ' (<a href="%s">%s</a>)' % (
self.build_url(params.pop('__createdpath')),
self._('click here to see created entity'))
@@ -505,7 +506,7 @@
url = self.build_url('view', rql=rql, vid=vid, __notemplate=1,
**extraparams)
return "javascript: loadxhtml('%s', '%s', '%s')" % (
- nodeid, html_escape(url), replacemode)
+ nodeid, xml_escape(url), replacemode)
# urls/path management ####################################################
--- a/web/test/unittest_form.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/test/unittest_form.py Thu Jul 16 13:30:13 2009 +0200
@@ -156,12 +156,12 @@
<option value="text/html">text/html</option>
<option value="text/plain">text/plain</option>
<option selected="selected" value="text/rest">text/rest</option>
-</select><textarea cols="60" id="description:%(eid)s" name="description:%(eid)s" onkeyup="autogrow(this)" rows="5" tabindex="1"/>''')
+</select><textarea cols="80" id="description:%(eid)s" name="description:%(eid)s" onkeyup="autogrow(this)" rows="2" tabindex="1"></textarea>''')
def test_richtextfield_2(self):
self.req.use_fckeditor = lambda: True
- self._test_richtextfield('<input name="description_format:%(eid)s" style="display: block" type="hidden" value="text/rest"/><textarea cols="80" cubicweb:type="wysiwyg" id="description:%(eid)s" name="description:%(eid)s" onkeyup="autogrow(this)" rows="20" tabindex="0"/>')
+ self._test_richtextfield('<input name="description_format:%(eid)s" style="display: block" type="hidden" value="text/rest"></input><textarea cols="80" cubicweb:type="wysiwyg" id="description:%(eid)s" name="description:%(eid)s" onkeyup="autogrow(this)" rows="2" tabindex="0"></textarea>')
def test_filefield(self):
@@ -172,14 +172,14 @@
data=Binary('new widgets system'))
form = FFForm(self.req, redirect_path='perdu.com', entity=file)
self.assertTextEquals(self._render_entity_field('data', form),
- '''<input id="data:%(eid)s" name="data:%(eid)s" tabindex="0" type="file" value=""/>
+ '''<input id="data:%(eid)s" name="data:%(eid)s" tabindex="0" type="file" value=""></input>
<a href="javascript: toggleVisibility('data:%(eid)s-advanced')" title="show advanced fields"><img src="http://testing.fr/cubicweb/data/puce_down.png" alt="show advanced fields"/></a>
<div id="data:%(eid)s-advanced" class="hidden">
-<label for="data_format:%(eid)s">data_format</label><input id="data_format:%(eid)s" name="data_format:%(eid)s" tabindex="1" type="text" value="text/plain"/><br/>
-<label for="data_encoding:%(eid)s">data_encoding</label><input id="data_encoding:%(eid)s" name="data_encoding:%(eid)s" tabindex="2" type="text" value="UTF-8"/><br/>
+<label for="data_format:%(eid)s">data_format</label><input id="data_format:%(eid)s" maxlength="50" name="data_format:%(eid)s" size="45" tabindex="1" type="text" value="text/plain"></input><br/>
+<label for="data_encoding:%(eid)s">data_encoding</label><input id="data_encoding:%(eid)s" maxlength="20" name="data_encoding:%(eid)s" size="20" tabindex="2" type="text" value="UTF-8"></input><br/>
</div>
<br/>
-<input name="data:%(eid)s__detach" type="checkbox"/>
+<input name="data:%(eid)s__detach" type="checkbox"></input>
detach attached file
''' % {'eid': file.eid})
@@ -196,17 +196,17 @@
data=Binary('new widgets system'))
form = EFFForm(self.req, redirect_path='perdu.com', entity=file)
self.assertTextEquals(self._render_entity_field('data', form),
- '''<input id="data:%(eid)s" name="data:%(eid)s" tabindex="0" type="file" value=""/>
+ '''<input id="data:%(eid)s" name="data:%(eid)s" tabindex="0" type="file" value=""></input>
<a href="javascript: toggleVisibility('data:%(eid)s-advanced')" title="show advanced fields"><img src="http://testing.fr/cubicweb/data/puce_down.png" alt="show advanced fields"/></a>
<div id="data:%(eid)s-advanced" class="hidden">
-<label for="data_format:%(eid)s">data_format</label><input id="data_format:%(eid)s" name="data_format:%(eid)s" tabindex="1" type="text" value="text/plain"/><br/>
-<label for="data_encoding:%(eid)s">data_encoding</label><input id="data_encoding:%(eid)s" name="data_encoding:%(eid)s" tabindex="2" type="text" value="UTF-8"/><br/>
+<label for="data_format:%(eid)s">data_format</label><input id="data_format:%(eid)s" maxlength="50" name="data_format:%(eid)s" size="45" tabindex="1" type="text" value="text/plain"></input><br/>
+<label for="data_encoding:%(eid)s">data_encoding</label><input id="data_encoding:%(eid)s" maxlength="20" name="data_encoding:%(eid)s" size="20" tabindex="2" type="text" value="UTF-8"></input><br/>
</div>
<br/>
-<input name="data:%(eid)s__detach" type="checkbox"/>
+<input name="data:%(eid)s__detach" type="checkbox"></input>
detach attached file
<p><b>You can either submit a new file using the browse button above, or choose to remove already uploaded file by checking the "detach attached file" check-box, or edit file content online with the widget below.</b></p>
-<textarea cols="80" name="data:%(eid)s" onkeyup="autogrow(this)" rows="20" tabindex="3">new widgets system</textarea>''' % {'eid': file.eid})
+<textarea cols="80" name="data:%(eid)s" onkeyup="autogrow(this)" rows="3" tabindex="3">new widgets system</textarea>''' % {'eid': file.eid})
def test_passwordfield(self):
@@ -214,9 +214,9 @@
upassword = StringField(widget=PasswordInput)
form = PFForm(self.req, redirect_path='perdu.com', entity=self.entity)
self.assertTextEquals(self._render_entity_field('upassword', form),
- '''<input id="upassword:%(eid)s" name="upassword:%(eid)s" tabindex="0" type="password" value="__cubicweb_internal_field__"/>
+ '''<input id="upassword:%(eid)s" name="upassword:%(eid)s" tabindex="0" type="password" value="__cubicweb_internal_field__"></input>
<br/>
-<input name="upassword-confirm:%(eid)s" tabindex="0" type="password" value="__cubicweb_internal_field__"/>
+<input name="upassword-confirm:%(eid)s" tabindex="0" type="password" value="__cubicweb_internal_field__"></input>
<span class="emphasis">confirm password</span>''' % {'eid': self.entity.eid})
--- a/web/test/unittest_views_baseviews.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/test/unittest_views_baseviews.py Thu Jul 16 13:30:13 2009 +0200
@@ -102,6 +102,7 @@
# self.assertAlmostEquals(value, rset.rows[0][3].seconds)
def test_sortvalue_with_display_col(self):
+ self.skip('XXX there is no column_labels on rset')
e, rset, view = self._prepare_entity()
labels = rset.column_labels()
table = TableWidget(view)
--- a/web/uicfg.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/uicfg.py Thu Jul 16 13:30:13 2009 +0200
@@ -68,7 +68,8 @@
__docformat__ = "restructuredtext en"
from cubicweb import neg_role
-from cubicweb.rtags import RelationTags, RelationTagsBool, RelationTagsSet
+from cubicweb.rtags import (RelationTags, RelationTagsBool,
+ RelationTagsSet, RelationTagsDict)
from cubicweb.web import formwidgets
@@ -118,14 +119,13 @@
primaryview_section.tag_attribute(('CWRType', attr), 'hidden')
-class DisplayCtrlRelationTags(RelationTags):
+class DisplayCtrlRelationTags(RelationTagsDict):
def __init__(self, *args, **kwargs):
super(DisplayCtrlRelationTags, self).__init__(*args, **kwargs)
self._counter = 0
def tag_relation(self, key, tag):
- assert isinstance(tag, dict)
- super(DisplayCtrlRelationTags, self).tag_relation(key, tag)
+ tag = super(DisplayCtrlRelationTags, self).tag_relation(key, tag)
self._counter += 1
tag.setdefault('order', self._counter)
@@ -152,11 +152,8 @@
else:
sschema = '*'
label = '%s_%s' % (rschema, role)
- displayinfo = rtag.get(sschema, rschema, oschema, role)
- if displayinfo is None:
- displayinfo = {}
- rtag.tag_relation((sschema, rschema, oschema, role), displayinfo)
- displayinfo.setdefault('label', label)
+ rtag.setdefault((sschema, rschema, oschema, role), 'label', label)
+ rtag.setdefault((sschema, rschema, oschema, role), 'order', rtag._counter)
primaryview_display_ctrl = DisplayCtrlRelationTags('primaryview_display_ctrl',
init_primaryview_display_ctrl)
@@ -243,7 +240,7 @@
autoform_field = RelationTags('autoform_field')
# relations'field explicit kwargs (given to field's __init__)
-autoform_field_kwargs = RelationTags()
+autoform_field_kwargs = RelationTagsDict()
autoform_field_kwargs.tag_attribute(('RQLExpression', 'expression'),
{'widget': formwidgets.TextInput})
autoform_field_kwargs.tag_attribute(('Bookmark', 'path'),
--- a/web/views/basecomponents.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/views/basecomponents.py Thu Jul 16 13:30:13 2009 +0200
@@ -11,11 +11,12 @@
__docformat__ = "restructuredtext en"
_ = unicode
+from logilab.mtconverter import xml_escape
from rql import parse
from cubicweb.selectors import yes, two_etypes_rset, match_form_params
from cubicweb.schema import display_name
-from cubicweb.common.uilib import html_escape, toggle_action
+from cubicweb.common.uilib import toggle_action
from cubicweb.web import component
from cubicweb.web.htmlwidgets import (MenuWidget, PopupBoxMenu, BoxSeparator,
BoxLink)
@@ -47,7 +48,7 @@
<input type="submit" value="" class="rqlsubmit" tabindex="%s" />
</fieldset>
''' % (not self.propval('visible') and 'hidden' or '',
- self.build_url('view'), html_escape(rql), req._('full text or RQL query'), req.next_tabindex(),
+ self.build_url('view'), xml_escape(rql), req._('full text or RQL query'), req.next_tabindex(),
req.next_tabindex()))
if self.req.search_state[0] != 'normal':
self.w(u'<input type="hidden" name="__mode" value="%s"/>'
@@ -202,7 +203,7 @@
url = self.build_url(rql=newrql, __restrrql=restrrql,
__restrtype=etype, __restrtypes=','.join(restrtypes))
html.append(u'<span><a href="%s">%s</a></span>' % (
- html_escape(url), elabel))
+ xml_escape(url), elabel))
rqlst.recover()
if on_etype:
url = self.build_url(rql=restrrql)
--- a/web/views/basecontrollers.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/views/basecontrollers.py Thu Jul 16 13:30:13 2009 +0200
@@ -15,7 +15,7 @@
import simplejson
from logilab.common.decorators import cached
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
from cubicweb import NoSelectableObject, ValidationError, ObjectNotFound, typed_eid
from cubicweb.utils import strptime
@@ -394,27 +394,16 @@
rset = self.req.execute('Any X,N WHERE X eid %%(x)s, X %s N' % rtype,
{'x': eid}, 'x')
entity = rset.get_entity(0, 0)
- value = entity.printable_value(rtype)
- return (success, args, value or default)
+ value = entity.printable_value(rtype) or default
+ return (success, args, value)
else:
return (success, args, None)
@jsonize
- def js_edit_relation(self, action, names, values,
- rtype, role, eid, vid, default):
- success, args = self.validate_form(action, names, values)
- if success:
- entity = self.req.eid_rset(eid).get_entity(0, 0)
- rset = entity.related(rtype, role)
- if rset:
- output = self.view(vid, rset)
- if vid == 'textoutofcontext':
- output = html_escape(output)
- else:
- output = default
- return (success, args, output)
- else:
- return (success, args, None)
+ def js_reledit_form(self, eid, rtype, role, lzone):
+ entity = self.req.eid_rset(eid).get_entity(0, 0)
+ return entity.view('reledit', rtype=rtype, role=role,
+ landing_zone=lzone)
@jsonize
def js_i18n(self, msgids):
--- a/web/views/baseforms.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/views/baseforms.py Thu Jul 16 13:30:13 2009 +0200
@@ -12,7 +12,7 @@
from simplejson import dumps
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
from logilab.common.decorators import cached
from cubicweb.selectors import (specified_etype_implements, accepts_etype_compat,
@@ -148,7 +148,7 @@
output = []
for name, value, iid in self._hiddens:
if isinstance(value, basestring):
- value = html_escape(value)
+ value = xml_escape(value)
if iid:
output.append(u'<input id="%s" type="hidden" name="%s" value="%s" />'
% (iid, name, value))
@@ -249,14 +249,14 @@
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], html_escape(row[5])))
+ % (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'<span>%s</span>' % _('add relation'))
w(u'<select id="relationSelector_%s" tabindex="%s" onchange="javascript:showMatchingSelect(this.options[this.selectedIndex].value,%s);">'
- % (eid, req.next_tabindex(), html_escape(dumps(eid))))
+ % (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
@@ -551,10 +551,10 @@
ctx = {'action' : self.build_url('edit'),
'error': self.error_message(),
'progress': _('validating...'),
- 'url': html_escape(req.url()),
+ 'url': xml_escape(req.url()),
'formid': self.id,
- 'redirectvid': html_escape(form.get('__redirectvid', 'list')),
- 'redirectrql': html_escape(form.get('__redirectrql', self.rset.printable_rql())),
+ 'redirectvid': xml_escape(form.get('__redirectvid', 'list')),
+ 'redirectrql': xml_escape(form.get('__redirectrql', self.rset.printable_rql())),
'attrheaders': u'\n'.join(attrheaders),
'lines': u'\n'.join(self.edit_form(ent) for ent in self.rset.entities()),
'okvalue': _('button_ok').capitalize(),
@@ -583,7 +583,7 @@
wdg = entity.get_widget
wdgfactories = [wdg(rschema, x) for rschema, _, x in entity.relations_by_category('primary', 'add')
if rschema.type != 'eid'] # XXX both (add, delete)
- seid = html_escape(dumps(eid))
+ seid = xml_escape(dumps(eid))
for wobj in wdgfactories:
if isinstance(wobj, ComboBoxWidget):
wobj.attrs['onchange'] = "setCheckboxesState2('eid', %s, 'checked')" % seid
--- a/web/views/basetemplates.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/views/basetemplates.py Thu Jul 16 13:30:13 2009 +0200
@@ -8,7 +8,7 @@
"""
__docformat__ = "restructuredtext en"
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
from cubicweb.vregistry import objectify_selector
from cubicweb.selectors import match_kwargs
@@ -31,14 +31,14 @@
def template_header(self, content_type, view=None, page_title='', additional_headers=()):
w = self.whead
# explictly close the <base> tag to avoid IE 6 bugs while browsing DOM
- w(u'<base href="%s"></base>' % html_escape(self.req.base_url()))
+ w(u'<base href="%s"></base>' % xml_escape(self.req.base_url()))
w(u'<meta http-equiv="content-type" content="%s; charset=%s"/>\n'
% (content_type, self.req.encoding))
w(NOINDEX)
w(NOFOLLOW)
w(u'\n'.join(additional_headers) + u'\n')
self.wview('htmlheader', rset=self.rset)
- w(u'<title>%s</title>\n' % html_escape(page_title))
+ w(u'<title>%s</title>\n' % xml_escape(page_title))
class LogInTemplate(LogInOutTemplate):
@@ -60,7 +60,7 @@
if self.config['anonymous-user']:
indexurl = self.build_url('view', vid='index', __message=msg)
w(u'<p><a href="%s">%s</a><p>' % (
- html_escape(indexurl),
+ xml_escape(indexurl),
self.req._('go back to the index page')))
@objectify_selector
@@ -110,7 +110,7 @@
w(u'<div id="pageContent">\n')
vtitle = self.req.form.get('vtitle')
if vtitle:
- w(u'<h1 class="vtitle">%s</h1>\n' % html_escape(vtitle))
+ w(u'<h1 class="vtitle">%s</h1>\n' % xml_escape(vtitle))
# display entity type restriction component
etypefilter = self.vreg.select_vobject('components', 'etypenavigation',
self.req, rset=self.rset)
@@ -137,13 +137,13 @@
w = self.whead
lang = self.req.lang
self.write_doctype()
- w(u'<base href="%s" />' % html_escape(self.req.base_url()))
+ w(u'<base href="%s" />' % xml_escape(self.req.base_url()))
w(u'<meta http-equiv="content-type" content="%s; charset=%s"/>\n'
% (content_type, self.req.encoding))
w(u'\n'.join(additional_headers) + u'\n')
self.wview('htmlheader', rset=self.rset)
if page_title:
- w(u'<title>%s</title>\n' % html_escape(page_title))
+ w(u'<title>%s</title>\n' % xml_escape(page_title))
def template_body_header(self, view):
w = self.w
@@ -212,7 +212,7 @@
% (content_type, self.req.encoding))
w(u'\n'.join(additional_headers))
self.wview('htmlheader', rset=self.rset)
- w(u'<title>%s</title>\n' % html_escape(page_title))
+ w(u'<title>%s</title>\n' % xml_escape(page_title))
self.w(u'<body>\n')
def template_footer(self, view=None):
@@ -234,7 +234,7 @@
whead(u'\n'.join(additional_headers) + u'\n')
self.wview('htmlheader', rset=self.rset)
w = self.w
- w(u'<title>%s</title>\n' % html_escape(page_title))
+ w(u'<title>%s</title>\n' % xml_escape(page_title))
w(u'<body>\n')
w(u'<div id="page">')
w(u'<table width="100%" height="100%" border="0"><tr>\n')
@@ -252,7 +252,7 @@
w(u'<div id="pageContent">\n')
vtitle = self.req.form.get('vtitle')
if vtitle:
- w(u'<h1 class="vtitle">%s</h1>' % html_escape(vtitle))
+ w(u'<h1 class="vtitle">%s</h1>' % xml_escape(vtitle))
def topleft_header(self):
logo = self.vreg.select_vobject('components', 'logo', self.req,
@@ -301,7 +301,7 @@
self.req, rset=self.rset)
if urlgetter is not None:
self.whead(u'<link rel="alternate" type="application/rss+xml" title="RSS feed" href="%s"/>\n'
- % html_escape(urlgetter.feed_url()))
+ % xml_escape(urlgetter.feed_url()))
def pageid(self):
req = self.req
@@ -462,7 +462,7 @@
def login_form(self, id):
_ = self.req._
self.w(u'<form method="post" action="%s" id="login_form">\n'
- % html_escape(login_form_url(self.config, self.req)))
+ % xml_escape(login_form_url(self.config, self.req)))
self.w(u'<table>\n')
self.w(u'<tr>\n')
msg = (self.config['allow-email-login'] and _('login or email')) or _('login')
--- a/web/views/baseviews.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/views/baseviews.py Thu Jul 16 13:30:13 2009 +0200
@@ -17,7 +17,7 @@
from rql import nodes
-from logilab.mtconverter import TransformError, html_escape, xml_escape
+from logilab.mtconverter import TransformError, xml_escape, xml_escape
from cubicweb import NoSelectableObject
from cubicweb.selectors import yes, empty_rset
@@ -121,8 +121,8 @@
"""the one line view for an entity: linked text view
"""
entity = self.entity(row, col)
- self.w(u'<a href="%s">' % html_escape(entity.absolute_url()))
- self.w(html_escape(self.view('text', self.rset, row=row, col=col)))
+ self.w(u'<a href="%s">' % xml_escape(entity.absolute_url()))
+ self.w(xml_escape(self.view('text', self.rset, row=row, col=col)))
self.w(u'</a>')
@@ -205,8 +205,8 @@
entity = self.entity(row, col)
desc = cut(entity.dc_description(), 50)
self.w(u'<a href="%s" title="%s">' % (
- html_escape(entity.absolute_url()), html_escape(desc)))
- self.w(html_escape(self.view('textincontext', self.rset,
+ xml_escape(entity.absolute_url()), xml_escape(desc)))
+ self.w(xml_escape(self.view('textincontext', self.rset,
row=row, col=col)))
self.w(u'</a>')
@@ -218,8 +218,8 @@
entity = self.entity(row, col)
desc = cut(entity.dc_description(), 50)
self.w(u'<a href="%s" title="%s">' % (
- html_escape(entity.absolute_url()), html_escape(desc)))
- self.w(html_escape(self.view('textoutofcontext', self.rset,
+ xml_escape(entity.absolute_url()), xml_escape(desc)))
+ self.w(xml_escape(self.view('textoutofcontext', self.rset,
row=row, col=col)))
self.w(u'</a>')
--- a/web/views/bookmark.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/views/bookmark.py Thu Jul 16 13:30:13 2009 +0200
@@ -7,7 +7,7 @@
"""
__docformat__ = "restructuredtext en"
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
from cubicweb import Unauthorized
from cubicweb.selectors import implements
@@ -35,12 +35,12 @@
entity = self.complete_entity(row, col)
self.w(u' ')
self.w(u"<span class='title'><b>")
- self.w(u"%s : %s" % (self.req._('Bookmark'), html_escape(entity.title)))
+ self.w(u"%s : %s" % (self.req._('Bookmark'), xml_escape(entity.title)))
self.w(u"</b></span>")
self.w(u'<br/><br/><div class="content"><a href="%s">' % (
- html_escape(entity.actual_url())))
+ xml_escape(entity.actual_url())))
self.w(u'</a>')
- self.w(u'<p>%s%s</p>' % (self.req._('Used by:'), ', '.join(html_escape(u.name())
+ self.w(u'<p>%s%s</p>' % (self.req._('Used by:'), ', '.join(xml_escape(u.name())
for u in entity.bookmarked_by)))
self.w(u'</div>')
@@ -75,8 +75,8 @@
else:
dlink = None
for bookmark in rset.entities():
- label = '<a href="%s">%s</a>' % (html_escape(bookmark.action_url()),
- html_escape(bookmark.title))
+ label = '<a href="%s">%s</a>' % (xml_escape(bookmark.action_url()),
+ xml_escape(bookmark.title))
if candelete:
dlink = u'[<a href="javascript:removeBookmark(%s)" title="%s">-</a>]' % (
bookmark.eid, _('delete this bookmark'))
--- a/web/views/boxes.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/views/boxes.py Thu Jul 16 13:30:13 2009 +0200
@@ -16,7 +16,7 @@
__docformat__ = "restructuredtext en"
_ = unicode
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
from cubicweb.selectors import match_user_groups, non_final_entity
from cubicweb.view import EntityView
@@ -191,7 +191,7 @@
else:
rql = ''
form = self.formdef % (req.build_url('view'), req.next_tabindex(),
- html_escape(rql), req.next_tabindex())
+ xml_escape(rql), req.next_tabindex())
title = u"""<span onclick="javascript: toggleVisibility('rqlinput')">%s</span>""" % req._(self.title)
box = BoxWidget(title, self.id, _class="searchBoxFrame", islist=False, escape=False)
box.append(BoxHtml(form))
--- a/web/views/calendar.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/views/calendar.py Thu Jul 16 13:30:13 2009 +0200
@@ -10,7 +10,7 @@
from datetime import datetime, date, timedelta
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
from cubicweb.interfaces import ICalendarable
from cubicweb.selectors import implements
@@ -82,7 +82,7 @@
for i in range(len(self.rset.rows)):
task = self.complete_entity(i)
self.w(u'<div class="vevent">')
- self.w(u'<h3 class="summary">%s</h3>' % html_escape(task.dc_title()))
+ self.w(u'<h3 class="summary">%s</h3>' % xml_escape(task.dc_title()))
self.w(u'<div class="description">%s</div>'
% task.dc_description(format='text/html'))
if task.start:
@@ -244,8 +244,8 @@
prevlink, nextlink = self._prevnext_links(curdate) # XXX
self.w(u'<tr><th><a href="%s"><<</a></th><th colspan="5">%s %s</th>'
u'<th><a href="%s">>></a></th></tr>' %
- (html_escape(prevlink), self.req._(curdate.strftime('%B').lower()),
- curdate.year, html_escape(nextlink)))
+ (xml_escape(prevlink), self.req._(curdate.strftime('%B').lower()),
+ curdate.year, xml_escape(nextlink)))
# output header
self.w(u'<tr><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th></tr>' %
@@ -292,7 +292,7 @@
__redirectparams=self.req.build_url_params(year=curdate.year, month=curmonth),
__redirectvid=self.id
)
- self.w(u'<div class="cmd"><a href="%s">%s</a></div>' % (html_escape(url), self.req._(u'add')))
+ self.w(u'<div class="cmd"><a href="%s">%s</a></div>' % (xml_escape(url), self.req._(u'add')))
self.w(u' ')
self.w(u'</div>')
self.w(u'<div class="cellContent">')
@@ -307,7 +307,7 @@
__redirectvid=self.id
)
- self.w(u'<div class="tooltip" ondblclick="stopPropagation(event); window.location.assign(\'%s\'); return false;">' % html_escape(url))
+ self.w(u'<div class="tooltip" ondblclick="stopPropagation(event); window.location.assign(\'%s\'); return false;">' % xml_escape(url))
task.view('tooltip', w=self.w )
self.w(u'</div>')
else:
@@ -388,9 +388,9 @@
self.w(u'<tr><th class="transparent"></th>')
self.w(u'<th><a href="%s"><<</a></th><th colspan="5">%s %s %s</th>'
u'<th><a href="%s">>></a></th></tr>' %
- (html_escape(prevlink), first_day_of_week.year,
+ (xml_escape(prevlink), first_day_of_week.year,
self.req._(u'week'), first_day_of_week.isocalendar()[1],
- html_escape(nextlink)))
+ xml_escape(nextlink)))
# output header
self.w(u'<tr>')
@@ -429,7 +429,7 @@
__redirectvid=self.id
)
extra = ' ondblclick="addCalendarItem(event, hmin=8, hmax=20, year=%s, month=%s, day=%s, duration=2, baseurl=\'%s\')"' % (
- wdate.year, wdate.month, wdate.day, html_escape(url))
+ wdate.year, wdate.month, wdate.day, xml_escape(url))
else:
extra = ""
self.w(u'<div class="columndiv"%s>'% extra)
@@ -501,7 +501,7 @@
__redirectvid=self.id
)
- self.w(u'<div class="tooltip" ondblclick="stopPropagation(event); window.location.assign(\'%s\'); return false;">' % html_escape(url))
+ self.w(u'<div class="tooltip" ondblclick="stopPropagation(event); window.location.assign(\'%s\'); return false;">' % xml_escape(url))
task.view('tooltip', w=self.w)
self.w(u'</div>')
if task.start is None:
--- a/web/views/cwproperties.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/views/cwproperties.py Thu Jul 16 13:30:13 2009 +0200
@@ -8,7 +8,7 @@
__docformat__ = "restructuredtext en"
_ = unicode
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
from logilab.common.decorators import cached
@@ -154,7 +154,7 @@
docmsgid = '%s_%s_description' % (group, oid)
doc = _(docmsgid)
if doc != docmsgid:
- w(u'<div class="helper">%s</div>' % html_escape(doc).capitalize())
+ w(u'<div class="helper">%s</div>' % xml_escape(doc).capitalize())
w(u'</div>')
w(u'<fieldset id="field_%(oid)s_%(group)s" class="%(group)s preferences hidden">'
% {'oid':oid, 'group':group})
--- a/web/views/cwuser.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/views/cwuser.py Thu Jul 16 13:30:13 2009 +0200
@@ -7,7 +7,7 @@
"""
__docformat__ = "restructuredtext en"
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
from cubicweb.selectors import one_line_rset, implements, match_user_groups
from cubicweb.view import EntityView
@@ -52,14 +52,14 @@
<foaf:primaryTopic rdf:resource="%s"/>
</foaf:PersonalProfileDocument>''' % (entity.absolute_url(), entity.absolute_url()))
self.w(u'<foaf:Person rdf:ID="%s">\n' % entity.eid)
- self.w(u'<foaf:name>%s</foaf:name>\n' % html_escape(entity.dc_long_title()))
+ self.w(u'<foaf:name>%s</foaf:name>\n' % xml_escape(entity.dc_long_title()))
if entity.surname:
self.w(u'<foaf:family_name>%s</foaf:family_name>\n'
- % html_escape(entity.surname))
+ % xml_escape(entity.surname))
if entity.firstname:
self.w(u'<foaf:givenname>%s</foaf:givenname>\n'
- % html_escape(entity.firstname))
+ % xml_escape(entity.firstname))
emailaddr = entity.get_email()
if emailaddr:
- self.w(u'<foaf:mbox>%s</foaf:mbox>\n' % html_escape(emailaddr))
+ self.w(u'<foaf:mbox>%s</foaf:mbox>\n' % xml_escape(emailaddr))
self.w(u'</foaf:Person>\n')
--- a/web/views/debug.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/views/debug.py Thu Jul 16 13:30:13 2009 +0200
@@ -10,7 +10,7 @@
from time import strftime, localtime
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
from cubicweb.selectors import none_rset, match_user_groups
from cubicweb.view import StartupView
@@ -21,7 +21,7 @@
w(u'<ul>')
for key in sorted(dict):
w(u'<li><span class="label">%s</span>: <span>%s</span></li>' % (
- html_escape(str(key)), html_escape(repr(dict[key]))))
+ xml_escape(str(key)), xml_escape(repr(dict[key]))))
w(u'</ul>')
@@ -38,7 +38,7 @@
if sessions:
w(u'<ul>')
for sid, session in sessions:
- w(u'<li>%s (last usage: %s)<br/>' % (html_escape(str(session)),
+ w(u'<li>%s (last usage: %s)<br/>' % (xml_escape(str(session)),
strftime('%Y-%m-%d %H:%M:%S',
localtime(session.timestamp))))
dict_to_html(w, session.data)
--- a/web/views/editforms.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/views/editforms.py Thu Jul 16 13:30:13 2009 +0200
@@ -13,17 +13,17 @@
from simplejson import dumps
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
from cubicweb.selectors import (match_kwargs, one_line_rset, non_final_entity,
specified_etype_implements, yes)
-from cubicweb.utils import make_uid
+from cubicweb.utils import make_uid, compute_cardinality, get_schema_property
from cubicweb.view import EntityView
from cubicweb.common import tags
-from cubicweb.web import INTERNAL_FIELD_VALUE, stdmsgs, eid_param
+from cubicweb.web import INTERNAL_FIELD_VALUE, stdmsgs, eid_param, uicfg
from cubicweb.web.form import FormViewMixIn
-from cubicweb.web.formfields import RelationField
-from cubicweb.web.formwidgets import Button, SubmitButton, ResetButton, Select
+from cubicweb.web.formfields import guess_field
+from cubicweb.web.formwidgets import Button, SubmitButton, ResetButton
from cubicweb.web.views import forms
@@ -38,7 +38,7 @@
entities
"""
js = u"javascript: togglePendingDelete('%s', %s);" % (
- nodeid, html_escape(dumps(eid)))
+ nodeid, xml_escape(dumps(eid)))
return u'[<a class="handle" href="%s" id="handle%s">%s</a>]' % (
js, nodeid, label)
@@ -90,91 +90,127 @@
# FIXME editableField class could be toggleable from userprefs
- onsubmit = ("return inlineValidateAttributeForm('%(divid)s-form', '%(rtype)s', "
- "'%(eid)s', '%(divid)s', %(reload)s, '%(default)s');")
- ondblclick = "showInlineEditionForm(%(eid)s, '%(rtype)s', '%(divid)s')"
+ _onclick = u"showInlineEditionForm(%(eid)s, '%(rtype)s', '%(divid)s')"
+ _defaultlandingzone = u'<img title="%(msg)s" src="data/file.gif" alt="%(msg)s"/>'
+ _landingzonemsg = _('click to edit this field')
+ # default relation vids according to cardinality
+ _one_rvid = 'incontext'
+ _many_rvid = 'csv'
+
+ def _compute_best_vid(self, entity, rtype, role):
+ if compute_cardinality(entity.e_schema,
+ entity.schema.rschema(rtype),
+ role) in '+*':
+ return self._many_rvid
+ return self._one_rvid
+
+ def _build_landing_zone(self, lzone):
+ return lzone or self._defaultlandingzone % {'msg' : self.req._(self._landingzonemsg)}
- def cell_call(self, row, col, rtype=None, role='subject', reload=False,
- vid='textoutofcontext', default=None):
- """display field to edit entity's `rtype` relation on double-click"""
- rschema = self.schema.rschema(rtype)
+ def _build_renderer(self, entity, rtype, role):
+ return self.vreg.select_object('formrenderers', 'base', self.req,
+ entity=entity,
+ display_label=False, display_help=False,
+ display_fields=[(rtype, role)],
+ table_class='', button_bar_class='buttonbar',
+ display_progress_div=False)
+
+ def cell_call(self, row, col, rtype=None, role='subject',
+ reload=False, # controls reloading the whole page after change
+ rvid=None, # vid to be applied to other side of rtype
+ default=None, # default value
+ landing_zone=None # prepend value with a separate html element to click onto
+ # (esp. needed when values are links)
+ ):
+ """display field to edit entity's `rtype` relation on click"""
+ assert rtype
+ assert role in ('subject', 'object')
+ if default is None:
+ default = xml_escape(self.req._('<no value>'))
entity = self.entity(row, col)
- if not default:
- default = self.req._('not specified')
+ rschema = entity.schema.rschema(rtype)
+ # compute value, checking perms, build form
if rschema.is_final():
- value = entity.printable_value(rtype)
+ value = entity.printable_value(rtype) or default
if not entity.has_perm('update'):
self.w(value)
return
- else:
- rset = entity.related(rtype, role)
- # XXX html_escape but that depends of the actual vid
- value = html_escape(self.view(vid, rset, 'null') or default)
- # XXX consider local roles ?
- if role == 'subject'and not rschema.has_perm(self.req, 'add',
- fromeid=entity.eid):
- self.w(value)
- return
- elif role == 'object'and not rschema.has_perm(self.req, 'add',
- toeid=entity.eid):
- self.w(value)
- return
- if not value.strip():
- value = default
- if rschema.is_final():
- form = self._build_attribute_form(entity, value, rtype, role,
- reload, row, col, default)
+ self._attribute_form(entity, value, rtype, role, reload,
+ row, col, default, landing_zone)
else:
- form = self._build_relation_form(entity, value, rtype, role,
- row, col, vid, default)
- renderer = self.vreg.select('formrenderers', 'base', self.req,
- entity=entity,
- display_label=False, display_help=False,
- display_fields=[(rtype, role)],
- table_class='', button_bar_class='buttonbar',
- display_progress_div=False)
- self.w(form.form_render(renderer=renderer))
+ dispctrl = uicfg.primaryview_display_ctrl.etype_get(entity.e_schema,
+ rtype, role)
+ vid = dispctrl.get('vid', 'reledit')
+ if vid != 'reledit': # reledit explicitly disabled
+ self.wview(vid, entity.related(rtype, role))
+ return
+ if rvid is None:
+ rvid = self._compute_best_vid(entity, rtype, role)
+ rset = entity.related(rtype, role)
+ candidate = self.view(rvid, rset, 'null')
+ value = candidate or default
+ if role == 'subject' and not rschema.has_perm(self.req, 'add',
+ fromeid=entity.eid):
+ return self.w(value)
+ elif role == 'object' and not rschema.has_perm(self.req, 'add',
+ toeid=entity.eid):
+ return self.w(value)
+ elif get_schema_property(entity.e_schema, rschema,
+ role, 'composite') == role:
+ self.warning('reledit cannot be applied : (... %s %s [composite])'
+ % (rtype, entity.e_schema))
+ return self.w(value)
+ self._relation_form(entity, value, rtype, role, reload, row, col,
+ rvid, default, landing_zone)
- def _build_relation_form(self, entity, value, rtype, role, row, col, vid, default):
- entity = self.entity(row, col)
+
+ def _relation_form(self, entity, value, rtype, role, row, col, reload, rvid, default, lzone):
+ lzone = self._build_landing_zone(lzone)
+ value = lzone + value
divid = 'd%s' % make_uid('%s-%s' % (rtype, entity.eid))
- event_data = {'divid' : divid, 'eid' : entity.eid, 'rtype' : rtype, 'vid' : vid,
- 'default' : default, 'role' : role}
- onsubmit = ("return inlineValidateRelationForm('%(divid)s-form', '%(rtype)s', "
- "'%(role)s', '%(eid)s', '%(divid)s', '%(vid)s', '%(default)s');"
+ event_data = {'divid' : divid, 'eid' : entity.eid, 'rtype' : rtype, 'vid' : rvid,
+ 'reload' : reload, 'default' : default, 'role' : role,
+ 'lzone' : lzone}
+ onsubmit = ("return inlineValidateRelationForm('%(rtype)s', '%(role)s', '%(eid)s', "
+ "'%(divid)s', %(reload)s, '%(vid)s', '%(default)s', '%(lzone)s');"
% event_data)
- cancelclick = "cancelInlineEdit(%s,\'%s\',\'%s\')" % (
+ cancelclick = "hideInlineEdit(%s,\'%s\',\'%s\')" % (
entity.eid, rtype, divid)
- form = self.vreg.select('forms', 'base', self.req, entity=entity,
- domid='%s-form' % divid, cssstyle='display: none',
- onsubmit=onsubmit, action='#',
- form_buttons=[SubmitButton(),
- Button(stdmsgs.BUTTON_CANCEL,
- onclick=cancelclick)])
- form.append_field(RelationField(name=rtype, role=role, sort=True,
- widget=Select(),
- label=u' '))
+ form = self.vreg.select_object('forms', 'base', self.req, entity=entity,
+ domid='%s-form' % divid, cssstyle='display: none',
+ onsubmit=onsubmit, action='#',
+ form_buttons=[SubmitButton(),
+ Button(stdmsgs.BUTTON_CANCEL,
+ onclick=cancelclick)])
+ field = guess_field(entity.e_schema, entity.schema.rschema(rtype), role)
+ form.append_field(field)
+ self.w(u'<div id="%s-reledit" class="field">' % divid)
self.w(tags.div(value, klass='editableField', id=divid,
- ondblclick=self.ondblclick % event_data))
- return form
+ onclick=self._onclick % event_data))
+ renderer = self._build_renderer(entity, rtype, role)
+ self.w(form.form_render(renderer=renderer))
+ self.w(u'</div>')
- def _build_attribute_form(self, entity, value, rtype, role, reload, row, col, default):
+ def _attribute_form(self, entity, value, rtype, role, reload, row, col, default, lzone):
eid = entity.eid
divid = 'd%s' % make_uid('%s-%s' % (rtype, eid))
event_data = {'divid' : divid, 'eid' : eid, 'rtype' : rtype,
- 'reload' : dumps(reload), 'default' : default}
+ 'reload' : dumps(reload), 'default' : default, 'lzone' : lzone}
+ onsubmit = ("return inlineValidateAttributeForm('%(rtype)s', '%(eid)s', '%(divid)s', "
+ "%(reload)s, '%(default)s', '%(lzone)s');")
buttons = [SubmitButton(stdmsgs.BUTTON_OK),
Button(stdmsgs.BUTTON_CANCEL,
- onclick="cancelInlineEdit(%s,\'%s\',\'%s\')" % (
+ onclick="hideInlineEdit(%s,\'%s\',\'%s\')" % (
eid, rtype, divid))]
- form = self.vreg.select('forms', 'edition', self.req, rset=self.rset,
- row=row, col=col, form_buttons=buttons,
- domid='%s-form' % divid, action='#',
- cssstyle='display: none',
- onsubmit=self.onsubmit % event_data)
+ form = self.vreg.select_object('forms', 'edition', self.req, self.rset,
+ row=row, col=col, form_buttons=buttons,
+ domid='%s-form' % divid, action='#',
+ cssstyle='display: none',
+ onsubmit=onsubmit % event_data)
self.w(tags.div(value, klass='editableField', id=divid,
- ondblclick=self.ondblclick % event_data))
- return form
+ onclick=self._onclick % event_data))
+ renderer = self._build_renderer(entity, rtype, role)
+ self.w(form.form_render(renderer=renderer))
class EditionFormView(FormViewMixIn, EntityView):
--- a/web/views/editviews.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/views/editviews.py Thu Jul 16 13:30:13 2009 +0200
@@ -11,7 +11,7 @@
from simplejson import dumps
from logilab.common.decorators import cached
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
from cubicweb import typed_eid
from cubicweb.view import EntityView
@@ -64,10 +64,10 @@
erset = entity.as_rset()
if self.req.match_search_state(erset):
self.w(u'<a href="%s" title="%s">%s</a> <a href="%s" title="%s">[...]</a>' % (
- html_escape(linksearch_select_url(self.req, erset)),
+ xml_escape(linksearch_select_url(self.req, erset)),
self.req._('select this entity'),
- html_escape(entity.view('textoutofcontext')),
- html_escape(entity.absolute_url(vid='primary')),
+ xml_escape(entity.view('textoutofcontext')),
+ xml_escape(entity.absolute_url(vid='primary')),
self.req._('view detail for this entity')))
else:
entity.view('outofcontext', w=self.w)
@@ -111,7 +111,7 @@
</select>
</div>
""" % (hidden and 'hidden' or '', divid, selectid,
- html_escape(dumps(entity.eid)), is_cell and 'true' or 'null', relname,
+ xml_escape(dumps(entity.eid)), is_cell and 'true' or 'null', relname,
'\n'.join(options))
def _get_select_options(self, entity, rschema, target):
@@ -126,13 +126,13 @@
for eview, reid in form.form_field_vocabulary(field, limit):
if reid is None:
options.append('<option class="separator">-- %s --</option>'
- % html_escape(eview))
+ % xml_escape(eview))
else:
optionid = relation_id(eid, rtype, target, reid)
if optionid not in pending_inserts:
# prefix option's id with letters to make valid XHTML wise
options.append('<option id="id%s" value="%s">%s</option>' %
- (optionid, reid, html_escape(eview)))
+ (optionid, reid, xml_escape(eview)))
return options
def _get_search_options(self, entity, rschema, target, targettypes):
@@ -145,7 +145,7 @@
__mode=mode)
options.append((eschema.display_name(self.req),
'<option value="%s">%s %s</option>' % (
- html_escape(url), _('Search for'), eschema.display_name(self.req))))
+ xml_escape(url), _('Search for'), eschema.display_name(self.req))))
return [o for l, o in sorted(options)]
def _get_basket_options(self, entity, rschema, target, targettypes):
@@ -156,7 +156,7 @@
target, targettypes):
optionid = relation_id(entity.eid, rtype, target, basketeid)
options.append('<option id="%s" value="%s">%s %s</option>' % (
- optionid, basketeid, _('link to each item in'), html_escape(basketname)))
+ optionid, basketeid, _('link to each item in'), xml_escape(basketname)))
return options
def _get_basket_links(self, ueid, target, targettypes):
--- a/web/views/emailaddress.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/views/emailaddress.py Thu Jul 16 13:30:13 2009 +0200
@@ -7,8 +7,9 @@
"""
__docformat__ = "restructuredtext en"
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
+from cubicweb.schema import display_name
from cubicweb.selectors import implements
from cubicweb.common import Unauthorized
from cubicweb.web.views import baseviews, primary
@@ -79,9 +80,9 @@
if entity.reverse_primary_email:
self.w(u'<b>')
if entity.alias:
- self.w(u'%s <' % html_escape(entity.alias))
- self.w('<a href="%s">%s</a>' % (html_escape(entity.absolute_url()),
- html_escape(entity.display_address())))
+ self.w(u'%s <' % xml_escape(entity.alias))
+ self.w('<a href="%s">%s</a>' % (xml_escape(entity.absolute_url()),
+ xml_escape(entity.display_address())))
if entity.alias:
self.w(u'>\n')
if entity.reverse_primary_email:
@@ -108,8 +109,8 @@
mailto = "mailto:%s <%s>" % (alias, entity.display_address())
else:
mailto = "mailto:%s" % entity.display_address()
- self.w(u'<a href="%s">%s</a>' % (html_escape(mailto),
- html_escape(entity.display_address())))
+ self.w(u'<a href="%s">%s</a>' % (xml_escape(mailto),
+ xml_escape(entity.display_address())))
if entity.reverse_primary_email:
self.w(u'</b>')
--- a/web/views/facets.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/views/facets.py Thu Jul 16 13:30:13 2009 +0200
@@ -9,14 +9,15 @@
from simplejson import dumps
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
from cubicweb.vregistry import objectify_selector
from cubicweb.selectors import (non_final_entity, two_lines_rset,
match_context_prop, yes, relation_possible)
from cubicweb.web.box import BoxTemplate
from cubicweb.web.facet import (AbstractFacet, FacetStringWidget, RelationFacet,
- prepare_facets_rqlst, filter_hiddens)
+ prepare_facets_rqlst, filter_hiddens, _cleanup_rqlst,
+ _prepare_vocabulary_rqlst)
@objectify_selector
def contextview_selector(cls, req, rset=None, row=None, col=None, view=None,
@@ -41,7 +42,7 @@
needs_css = 'cubicweb.facets.css'
needs_js = ('cubicweb.ajax.js', 'cubicweb.formfilter.js')
- bkLinkBox_template = u'<div class="facetTitle">%s</div>'
+ bk_linkbox_template = u'<div class="facetTitle">%s</div>'
def facetargs(self):
"""this method returns the list of extra arguments that should
@@ -82,10 +83,11 @@
widgets.append(wdg)
if not widgets:
return
- self.displayBookmarkLink(rset)
+ if self.bk_linkbox_template:
+ self.display_bookmark_link(rset)
w = self.w
w(u'<form method="post" id="%sForm" cubicweb:facetargs="%s" action="">' % (
- divid, html_escape(dumps([divid, vid, paginate, self.facetargs()]))))
+ divid, xml_escape(dumps([divid, vid, paginate, self.facetargs()]))))
w(u'<fieldset>')
hiddens = {'facets': ','.join(wdg.facet.id for wdg in widgets),
'baserql': baserql}
@@ -101,7 +103,7 @@
import cubicweb
cubicweb.info('after facets with rql: %s' % repr(rqlst))
- def displayBookmarkLink(self, rset):
+ def display_bookmark_link(self, rset):
eschema = self.schema.eschema('Bookmark')
if eschema.has_perm(self.req, 'add'):
bk_path = 'view?rql=%s' % rset.printable_rql()
@@ -110,10 +112,10 @@
bk_add_url = self.build_url('add/Bookmark', path=bk_path, title=bk_title, __linkto=linkto)
bk_base_url = self.build_url('add/Bookmark', title=bk_title, __linkto=linkto)
bk_link = u'<a cubicweb:target="%s" id="facetBkLink" href="%s">%s</a>' % (
- html_escape(bk_base_url),
- html_escape(bk_add_url),
+ xml_escape(bk_base_url),
+ xml_escape(bk_add_url),
self.req._('bookmark this search'))
- self.w(self.bkLinkBox_template % bk_link)
+ self.w(self.bk_linkbox_template % bk_link)
def get_facets(self, rset, mainvar):
return self.vreg.possible_vobjects('facets', self.req, rset=rset,
@@ -162,6 +164,21 @@
return
self.rqlst.add_type_restriction(self.filtered_variable, value)
+ def possible_values(self):
+ """return a list of possible values (as string since it's used to
+ compare to a form value in javascript) for this facet
+ """
+ rqlst = self.rqlst
+ rqlst.save_state()
+ try:
+ _cleanup_rqlst(rqlst, self.filtered_variable)
+ etype_var = _prepare_vocabulary_rqlst(rqlst, self.filtered_variable, self.rtype, self.role)
+ attrvar = rqlst.make_variable()
+ rqlst.add_selected(attrvar)
+ rqlst.add_relation(etype_var, 'name', attrvar)
+ return [etype for _, etype in self.rqlexec(rqlst.as_string())]
+ finally:
+ rqlst.recover()
class HasTextFacet(AbstractFacet):
__select__ = relation_possible('has_text', 'subject') & match_context_prop()
--- a/web/views/formrenderers.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/views/formrenderers.py Thu Jul 16 13:30:13 2009 +0200
@@ -8,7 +8,7 @@
__docformat__ = "restructuredtext en"
from logilab.common import dictattr
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
from simplejson import dumps
@@ -144,17 +144,17 @@
else:
action = form.action
tag = ('<form action="%s" method="post" enctype="%s"' % (
- html_escape(action or '#'), enctype))
+ xml_escape(action or '#'), enctype))
if form.domid:
tag += ' id="%s"' % form.domid
if form.onsubmit:
- tag += ' onsubmit="%s"' % html_escape(form.onsubmit % dictattr(form))
+ tag += ' onsubmit="%s"' % xml_escape(form.onsubmit % dictattr(form))
if form.cssstyle:
- tag += ' style="%s"' % html_escape(form.cssstyle)
+ tag += ' style="%s"' % xml_escape(form.cssstyle)
if form.cssclass:
- tag += ' class="%s"' % html_escape(form.cssclass)
+ tag += ' class="%s"' % xml_escape(form.cssclass)
if form.cwtarget:
- tag += ' cubicweb:target="%s"' % html_escape(form.cwtarget)
+ tag += ' cubicweb:target="%s"' % xml_escape(form.cwtarget)
return tag + '>'
def display_field(self, form, field):
@@ -298,7 +298,7 @@
entity = form.edited_entity
values = form.form_previous_values
qeid = eid_param('eid', entity.eid)
- cbsetstate = "setCheckboxesState2('eid', %s, 'checked')" % html_escape(dumps(entity.eid))
+ cbsetstate = "setCheckboxesState2('eid', %s, 'checked')" % xml_escape(dumps(entity.eid))
w(u'<tr class="%s">' % (entity.row % 2 and u'even' or u'odd'))
# XXX turn this into a widget used on the eid field
w(u'<td>%s</td>' % checkbox('eid', entity.eid, checked=qeid in values))
@@ -411,7 +411,7 @@
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], html_escape(row[5])))
+ % (row[1], row[4], xml_escape(row[5])))
w(u'</td>')
w(u'</tr>')
w(u'<tr id="relationSelectorRow_%s" class="separator">' % eid)
@@ -419,7 +419,7 @@
w(u'<span>%s</span>' % _('add relation'))
w(u'<select id="relationSelector_%s" tabindex="%s" '
'onchange="javascript:showMatchingSelect(this.options[this.selectedIndex].value,%s);">'
- % (eid, req.next_tabindex(), html_escape(dumps(eid))))
+ % (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
--- a/web/views/ibreadcrumbs.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/views/ibreadcrumbs.py Thu Jul 16 13:30:13 2009 +0200
@@ -8,7 +8,7 @@
__docformat__ = "restructuredtext en"
_ = unicode
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
# don't use AnyEntity since this may cause bug with isinstance() due to reloading
from cubicweb.interfaces import IBreadCrumbs
@@ -21,7 +21,7 @@
def bc_title(entity):
textsize = entity.req.property_value('navigation.short-line-size')
- return html_escape(cut(entity.dc_title(), textsize))
+ return xml_escape(cut(entity.dc_title(), textsize))
class BreadCrumbEntityVComponent(EntityVComponent):
@@ -64,7 +64,7 @@
url, title = part
textsize = self.req.property_value('navigation.short-line-size')
self.w(u'<a href="%s">%s</a>' % (
- html_escape(url), html_escape(cut(title, textsize))))
+ xml_escape(url), xml_escape(cut(title, textsize))))
else:
textsize = self.req.property_value('navigation.short-line-size')
self.w(cut(unicode(part), textsize))
@@ -81,6 +81,6 @@
def cell_call(self, row, col):
entity = self.entity(row, col)
- desc = html_escape(cut(entity.dc_description(), 50))
+ desc = xml_escape(cut(entity.dc_description(), 50))
self.w(u'<a href="%s" title="%s">%s</a>' % (
- html_escape(entity.absolute_url()), desc, bc_title(entity)))
+ xml_escape(entity.absolute_url()), desc, bc_title(entity)))
--- a/web/views/idownloadable.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/views/idownloadable.py Thu Jul 16 13:30:13 2009 +0200
@@ -8,7 +8,7 @@
__docformat__ = "restructuredtext en"
_ = unicode
-from logilab.mtconverter import BINARY_ENCODINGS, TransformError, html_escape
+from logilab.mtconverter import BINARY_ENCODINGS, TransformError, xml_escape
from cubicweb.view import EntityView
from cubicweb.selectors import (one_line_rset, score_entity,
@@ -31,12 +31,12 @@
if title is None:
title = req._('download')
w(u'<div class="sideBoxTitle downloadBoxTitle"><span>%s</span></div>'
- % html_escape(title))
+ % xml_escape(title))
w(u'<div class="sideBox downloadBox"><div class="sideBoxBody">')
w(u'<a href="%s"><img src="%s" alt="%s"/> %s</a>'
- % (html_escape(entity.download_url()),
+ % (xml_escape(entity.download_url()),
req.external_resource('DOWNLOAD_ICON'),
- _('download icon'), html_escape(label or entity.dc_title())))
+ _('download icon'), xml_escape(label or entity.dc_title())))
w(u'</div>')
w(u'</div>\n</div>\n')
@@ -92,8 +92,8 @@
def cell_call(self, row, col, title=None, **kwargs):
entity = self.entity(row, col)
- url = html_escape(entity.download_url())
- self.w(u'<a href="%s">%s</a>' % (url, html_escape(title or entity.dc_title())))
+ url = xml_escape(entity.download_url())
+ self.w(u'<a href="%s">%s</a>' % (url, xml_escape(title or entity.dc_title())))
class IDownloadablePrimaryView(primary.PrimaryView):
@@ -124,9 +124,9 @@
def cell_call(self, row, col, title=None, **kwargs):
"""the secondary view is a link to download the file"""
entity = self.entity(row, col)
- url = html_escape(entity.absolute_url())
- name = html_escape(title or entity.download_file_name())
- durl = html_escape(entity.download_url())
+ url = xml_escape(entity.absolute_url())
+ name = xml_escape(title or entity.download_file_name())
+ durl = xml_escape(entity.download_url())
self.w(u'<a href="%s">%s</a> [<a href="%s">%s</a>]' %
(url, name, durl, self.req._('download')))
@@ -147,6 +147,6 @@
def cell_call(self, row, col):
entity = self.entity(row, col)
#if entity.data_format.startswith('image/'):
- self.w(u'<img src="%s" alt="%s"/>' % (html_escape(entity.download_url()),
- html_escape(entity.download_file_name())))
+ self.w(u'<img src="%s" alt="%s"/>' % (xml_escape(entity.download_url()),
+ xml_escape(entity.download_file_name())))
--- a/web/views/iprogress.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/views/iprogress.py Thu Jul 16 13:30:13 2009 +0200
@@ -8,7 +8,7 @@
__docformat__ = "restructuredtext en"
_ = unicode
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
from cubicweb.selectors import implements
from cubicweb.interfaces import IProgress, IMileStone
@@ -99,7 +99,7 @@
colname = meth(ecls)
else:
colname = _(column)
- self.w(u'<th>%s</th>' % html_escape(colname))
+ self.w(u'<th>%s</th>' % xml_escape(colname))
self.w(u'</tr></thead>\n')
@@ -117,7 +117,7 @@
def build_state_cell(self, entity):
"""``state`` column cell renderer"""
- return html_escape(self.req._(entity.state))
+ return xml_escape(self.req._(entity.state))
def build_eta_date_cell(self, entity):
"""``eta_date`` column cell renderer"""
--- a/web/views/isioc.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/views/isioc.py Thu Jul 16 13:30:13 2009 +0200
@@ -7,7 +7,7 @@
"""
__docformat__ = "restructuredtext en"
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
from cubicweb.view import EntityView
from cubicweb.selectors import implements
@@ -45,11 +45,11 @@
def cell_call(self, row, col):
entity = self.complete_entity(row, col)
- sioct = html_escape(entity.isioc_type())
+ sioct = xml_escape(entity.isioc_type())
self.w(u'<sioc:%s rdf:about="%s">\n'
- % (sioct, html_escape(entity.absolute_url())))
+ % (sioct, xml_escape(entity.absolute_url())))
self.w(u'<dcterms:title>%s</dcterms:title>'
- % html_escape(entity.dc_title()))
+ % xml_escape(entity.dc_title()))
self.w(u'<dcterms:created>%s</dcterms:created>'
% entity.creation_date)
self.w(u'<dcterms:modified>%s</dcterms:modified>'
@@ -66,25 +66,25 @@
def cell_call(self, row, col):
entity = self.complete_entity(row, col)
- sioct = html_escape(entity.isioc_type())
+ sioct = xml_escape(entity.isioc_type())
self.w(u'<sioc:%s rdf:about="%s">\n'
- % (sioct, html_escape(entity.absolute_url())))
+ % (sioct, xml_escape(entity.absolute_url())))
self.w(u'<dcterms:title>%s</dcterms:title>'
- % html_escape(entity.dc_title()))
+ % xml_escape(entity.dc_title()))
self.w(u'<dcterms:created>%s</dcterms:created>'
% entity.creation_date)
self.w(u'<dcterms:modified>%s</dcterms:modified>'
% entity.modification_date)
if entity.content:
self.w(u'<sioc:content>%s</sioc:content>'''
- % html_escape(entity.isioc_content()))
+ % xml_escape(entity.isioc_content()))
if entity.related('entry_of'):
self.w(u'<sioc:has_container rdf:resource="%s"/>\n'
- % html_escape(entity.isioc_container().absolute_url()))
+ % xml_escape(entity.isioc_container().absolute_url()))
if entity.creator:
self.w(u'<sioc:has_creator>\n')
self.w(u'<sioc:User rdf:about="%s">\n'
- % html_escape(entity.creator.absolute_url()))
+ % xml_escape(entity.creator.absolute_url()))
self.w(entity.creator.view('foaf'))
self.w(u'</sioc:User>\n')
self.w(u'</sioc:has_creator>\n')
--- a/web/views/management.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/views/management.py Thu Jul 16 13:30:13 2009 +0200
@@ -9,7 +9,7 @@
__docformat__ = "restructuredtext en"
_ = unicode
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
from cubicweb.selectors import yes, none_rset, match_user_groups, authenticated_user
from cubicweb.view import AnyRsetView, StartupView, EntityView
@@ -84,8 +84,8 @@
_ = self.req._
w(u'<h1><span class="etype">%s</span> <a href="%s">%s</a></h1>'
% (entity.dc_type().capitalize(),
- html_escape(entity.absolute_url()),
- html_escape(entity.dc_title())))
+ xml_escape(entity.absolute_url()),
+ xml_escape(entity.dc_title())))
# first show permissions defined by the schema
self.w('<h2>%s</h2>' % _('schema\'s permissions definitions'))
self.schema_definition(entity.e_schema)
@@ -140,7 +140,7 @@
# and this will replace %s by %25s
delurl += '&__delete=%s:require_permission:%%s' % entity.eid
dellinktempl = u'[<a href="%s" title="%s">-</a>] ' % (
- html_escape(delurl), _('delete this permission'))
+ xml_escape(delurl), _('delete this permission'))
else:
dellinktempl = None
w(u'<table class="schemaInfo">')
@@ -215,14 +215,14 @@
if excinfo is not None and self.config['print-traceback']:
if exclass is None:
w(u'<div class="tb">%s</div>'
- % html_escape(ex).replace("\n","<br />"))
+ % xml_escape(ex).replace("\n","<br />"))
else:
w(u'<div class="tb">%s: %s</div>'
- % (exclass, html_escape(ex).replace("\n","<br />")))
+ % (exclass, xml_escape(ex).replace("\n","<br />")))
w(u'<hr />')
w(u'<div class="tb">%s</div>' % html_traceback(excinfo, ex, ''))
else:
- w(u'<div class="tb">%s</div>' % (html_escape(ex).replace("\n","<br />")))
+ w(u'<div class="tb">%s</div>' % (xml_escape(ex).replace("\n","<br />")))
# if excinfo is not None, it's probably not a bug
if excinfo is None:
return
@@ -269,7 +269,7 @@
return unicode(repr(ex), encoding, 'replace')
def text_error_description(ex, excinfo, req, eversion, cubes):
- binfo = rest_traceback(excinfo, html_escape(ex))
+ binfo = rest_traceback(excinfo, xml_escape(ex))
binfo += u'\n\n:URL: %s\n' % req.url()
if not '__bugreporting' in req.form:
binfo += u'\n:form params:\n'
@@ -319,7 +319,7 @@
self.w(u'<table border="1">')
for attr in env.keys():
self.w(u'<tr><th align="left">%s</th><td>%s</td></tr>'
- % (attr, html_escape(env[attr])))
+ % (attr, xml_escape(env[attr])))
self.w(u'</table>')
self.w(u'<h3>%s</h3>' % _('Request'))
self.w(u'<table border="1">')
@@ -328,7 +328,7 @@
'search_state', 'the_request', 'unparsed_uri', 'uri'):
val = getattr(req, attr)
self.w(u'<tr><th align="left">%s</th><td>%s</td></tr>'
- % (attr, html_escape(val)))
+ % (attr, xml_escape(val)))
self.w(u'</table>')
server = req.server
self.w(u'<h3>%s</h3>' % _('Server'))
@@ -338,6 +338,6 @@
if attr.startswith('_') or callable(val):
continue
self.w(u'<tr><th align="left">%s</th><td>%s</td></tr>'
- % (attr, html_escape(val)))
+ % (attr, xml_escape(val)))
self.w(u'</table>')
--- a/web/views/navigation.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/views/navigation.py Thu Jul 16 13:30:13 2009 +0200
@@ -10,7 +10,7 @@
from rql.nodes import VariableRef, Constant
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
from logilab.common.deprecation import obsolete
from cubicweb.interfaces import IPrevNext
@@ -136,7 +136,7 @@
def format_link_content(self, startstr, stopstr):
text = u'%s - %s' % (startstr.lower()[:self.nb_chars],
stopstr.lower()[:self.nb_chars])
- return html_escape(text)
+ return xml_escape(text)
def write_links(self, params, blocklist):
self.w(u'<div class="pagination">')
@@ -159,7 +159,7 @@
nav.clean_params(params)
# make a link to see them all
if show_all_option:
- url = html_escape(self.build_url(__force_display=1, **params))
+ url = xml_escape(self.build_url(__force_display=1, **params))
w(u'<p><a href="%s">%s</a></p>\n'
% (url, req._('show %s results') % len(rset)))
rset.limit(offset=start, limit=stop-start, inplace=True)
@@ -198,24 +198,24 @@
self.w(self.previous_link(previous, textsize))
self.w(u'</div>')
self.req.html_headers.add_raw('<link rel="prev" href="%s" />'
- % html_escape(previous.absolute_url()))
+ % xml_escape(previous.absolute_url()))
if next:
self.w(u'<div class="nextEntity right">')
self.w(self.next_link(next, textsize))
self.w(u'</div>')
self.req.html_headers.add_raw('<link rel="next" href="%s" />'
- % html_escape(next.absolute_url()))
+ % xml_escape(next.absolute_url()))
self.w(u'</div>')
self.w(u'<div class="clear"></div>')
def previous_link(self, previous, textsize):
return u'<a href="%s" title="%s"><< %s</a>' % (
- html_escape(previous.absolute_url()),
+ xml_escape(previous.absolute_url()),
self.req._('i18nprevnext_previous'),
- html_escape(cut(previous.dc_title(), textsize)))
+ xml_escape(cut(previous.dc_title(), textsize)))
def next_link(self, next, textsize):
return u'<a href="%s" title="%s">%s >></a>' % (
- html_escape(next.absolute_url()),
+ xml_escape(next.absolute_url()),
self.req._('i18nprevnext_next'),
- html_escape(cut(next.dc_title(), textsize)))
+ xml_escape(cut(next.dc_title(), textsize)))
--- a/web/views/old_calendar.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/views/old_calendar.py Thu Jul 16 13:30:13 2009 +0200
@@ -8,7 +8,7 @@
from datetime import date, time, timedelta
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
from cubicweb.interfaces import ICalendarViews
from cubicweb.utils import ONEDAY, ONEWEEK, date_range, first_day, last_day, previous_month, next_month, days_in_month
@@ -46,13 +46,13 @@
next2 = next_month(date, bigshift)
rql = self.rset.printable_rql()
return self.NAV_HEADER % (
- html_escape(self.build_url(rql=rql, vid=self.id, year=prev2.year,
+ xml_escape(self.build_url(rql=rql, vid=self.id, year=prev2.year,
month=prev2.month)),
- html_escape(self.build_url(rql=rql, vid=self.id, year=prev1.year,
+ xml_escape(self.build_url(rql=rql, vid=self.id, year=prev1.year,
month=prev1.month)),
- html_escape(self.build_url(rql=rql, vid=self.id, year=next1.year,
+ xml_escape(self.build_url(rql=rql, vid=self.id, year=next1.year,
month=next1.month)),
- html_escape(self.build_url(rql=rql, vid=self.id, year=next2.year,
+ xml_escape(self.build_url(rql=rql, vid=self.id, year=next2.year,
month=next2.month)))
@@ -91,7 +91,7 @@
rows.append(u'<tr>%s%s</tr>' % (WEEKNUM_CELL % day.isocalendar()[1], ''.join(current_row)))
url = self.build_url(rql=rql, vid='calendarmonth',
year=first_day.year, month=first_day.month)
- monthlink = u'<a href="%s">%s</a>' % (html_escape(url), umonth)
+ monthlink = u'<a href="%s">%s</a>' % (xml_escape(url), umonth)
return CALENDAR(self.req) % (monthlink, '\n'.join(rows))
def _mk_schedule(self, begin, end, itemvid='calendaritem'):
@@ -203,7 +203,7 @@
umonth = u'%s %s' % (self.format_date(cur_month, '%B'), cur_month.year)
url = self.build_url(rql=rql, vid=self.id,
year=cur_month.year, month=cur_month.month)
- self.w(u'<th colspan="2"><a href="%s">%s</a></th>' % (html_escape(url),
+ self.w(u'<th colspan="2"><a href="%s">%s</a></th>' % (xml_escape(url),
umonth))
self.w(u'</tr>')
_ = self.req._
@@ -272,7 +272,7 @@
umonth = self.format_date(monday, '%B %Y')
url = self.build_url(rql=rql, vid='calendarmonth',
year=monday.year, month=monday.month)
- monthlink = '<a href="%s">%s</a>' % (html_escape(url), umonth)
+ monthlink = '<a href="%s">%s</a>' % (xml_escape(url), umonth)
self.w(u'<tr><th colspan="3">%s %s (%s)</th></tr>' \
% (_('week'), monday.isocalendar()[1], monthlink))
for day in date_range(monday, sunday):
@@ -295,10 +295,10 @@
next2 = date + ONEWEEK * bigshift
rql = self.rset.printable_rql()
return self.NAV_HEADER % (
- html_escape(self.build_url(rql=rql, vid=self.id, year=prev2.year, week=prev2.isocalendar()[1])),
- html_escape(self.build_url(rql=rql, vid=self.id, year=prev1.year, week=prev1.isocalendar()[1])),
- html_escape(self.build_url(rql=rql, vid=self.id, year=next1.year, week=next1.isocalendar()[1])),
- html_escape(self.build_url(rql=rql, vid=self.id, year=next2.year, week=next2.isocalendar()[1])))
+ xml_escape(self.build_url(rql=rql, vid=self.id, year=prev2.year, week=prev2.isocalendar()[1])),
+ xml_escape(self.build_url(rql=rql, vid=self.id, year=prev1.year, week=prev1.isocalendar()[1])),
+ xml_escape(self.build_url(rql=rql, vid=self.id, year=next1.year, week=next1.isocalendar()[1])),
+ xml_escape(self.build_url(rql=rql, vid=self.id, year=next2.year, week=next2.isocalendar()[1])))
@@ -326,7 +326,7 @@
if day.weekday() == 6:
url = self.build_url(rql=rql, vid='ampmcalendarweek',
year=day.year, week=day.isocalendar()[1])
- weeklink = '<a href="%s">%s</a>' % (html_escape(url),
+ weeklink = '<a href="%s">%s</a>' % (xml_escape(url),
day.isocalendar()[1])
current_row.append(WEEKNUM_CELL % weeklink)
rows.append(current_row)
@@ -334,7 +334,7 @@
current_row.extend([(NO_CELL, NO_CELL, NO_CELL)] * (6-day.weekday()))
url = self.build_url(rql=rql, vid='ampmcalendarweek',
year=day.year, week=day.isocalendar()[1])
- weeklink = '<a href="%s">%s</a>' % (html_escape(url), day.isocalendar()[1])
+ weeklink = '<a href="%s">%s</a>' % (xml_escape(url), day.isocalendar()[1])
current_row.append(WEEKNUM_CELL % weeklink)
rows.append(current_row)
# build two rows for each week: am & pm
@@ -350,7 +350,7 @@
# tigh everything together
url = self.build_url(rql=rql, vid='ampmcalendarmonth',
year=first_day.year, month=first_day.month)
- monthlink = '<a href="%s">%s</a>' % (html_escape(url), umonth)
+ monthlink = '<a href="%s">%s</a>' % (xml_escape(url), umonth)
return CALENDAR(self.req) % (monthlink, '\n'.join(formatted_rows))
@@ -367,7 +367,7 @@
umonth = u'%s %s' % (self.format_date(cur_month, '%B'), cur_month.year)
url = self.build_url(rql=rql, vid=self.id,
year=cur_month.year, month=cur_month.month)
- self.w(u'<th colspan="3"><a href="%s">%s</a></th>' % (html_escape(url),
+ self.w(u'<th colspan="3"><a href="%s">%s</a></th>' % (xml_escape(url),
umonth))
self.w(u'</tr>')
_ = self.req._
@@ -417,7 +417,7 @@
if day.weekday() == 6:
url = self.build_url(rql=rql, vid='ampmcalendarweek',
year=day.year, week=day.isocalendar()[1])
- weeklink = '<a href="%s">%s</a>' % (html_escape(url),
+ weeklink = '<a href="%s">%s</a>' % (xml_escape(url),
day.isocalendar()[1])
current_row.append(WEEKNUM_CELL % weeklink)
rows.append(current_row)
@@ -425,7 +425,7 @@
current_row.extend([(NO_CELL, NO_CELL, NO_CELL)] * (6-day.weekday()))
url = self.build_url(rql=rql, vid='ampmcalendarweek',
year=day.year, week=day.isocalendar()[1])
- weeklink = '<a href="%s">%s</a>' % (html_escape(url),
+ weeklink = '<a href="%s">%s</a>' % (xml_escape(url),
day.isocalendar()[1])
current_row.append(WEEKNUM_CELL % weeklink)
rows.append(current_row)
@@ -442,7 +442,7 @@
# tigh everything together
url = self.build_url(rql=rql, vid='ampmcalendarmonth',
year=first_day.year, month=first_day.month)
- monthlink = '<a href="%s">%s</a>' % (html_escape(url),
+ monthlink = '<a href="%s">%s</a>' % (xml_escape(url),
umonth)
return CALENDAR(self.req) % (monthlink, '\n'.join(formatted_rows))
@@ -461,7 +461,7 @@
umonth = self.format_date(monday, '%B %Y')
url = self.build_url(rql=rql, vid='ampmcalendarmonth',
year=monday.year, month=monday.month)
- monthlink = '<a href="%s">%s</a>' % (html_escape(url), umonth)
+ monthlink = '<a href="%s">%s</a>' % (xml_escape(url), umonth)
w(u'<tr>%s</tr>' % (
WEEK_TITLE % (_('week'), monday.isocalendar()[1], monthlink)))
w(u'<tr><th>%s</th><th> </th></tr>'% _(u'Date'))
--- a/web/views/plots.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/views/plots.py Thu Jul 16 13:30:13 2009 +0200
@@ -13,7 +13,7 @@
from simplejson import dumps
from logilab.common import flatten
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
from cubicweb.utils import make_uid, UStringIO, datetime2ticks
from cubicweb.vregistry import objectify_selector
@@ -167,7 +167,7 @@
piechart.size(width, height)
if self.title:
piechart.title(self.title)
- self.w(u'<img src="%s" />' % html_escape(piechart.url))
+ self.w(u'<img src="%s" />' % xml_escape(piechart.url))
class PieChartView(baseviews.AnyRsetView):
id = 'piechart'
--- a/web/views/primary.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/views/primary.py Thu Jul 16 13:30:13 2009 +0200
@@ -10,7 +10,7 @@
from warnings import warn
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
from cubicweb import Unauthorized
from cubicweb.view import EntityView
@@ -100,7 +100,7 @@
def render_entity_title(self, entity):
"""default implementation return dc_title"""
- title = html_escape(entity.dc_title())
+ title = xml_escape(entity.dc_title())
if title:
self.w(u'<h1><span class="etype">%s</span> %s</h1>'
% (entity.dc_type().capitalize(), title))
@@ -117,19 +117,7 @@
def render_entity_attributes(self, entity, siderelations=None):
for rschema, tschemas, role, dispctrl in self._section_def(entity, 'attributes'):
- # don't use reledit as default vid for composite relation
- if rschema.is_final():
- defaultvid = 'reledit'
- # XXX use entity.e_schema.role_rproperty(role, rschema, 'composite', tschemas[0]) once yams > 0.23.0 is out
- elif role == 'subject' and \
- rschema.rproperty(entity.e_schema, tschemas[0], 'composite'):
- defaultvid = 'csv'
- elif role == 'object' and \
- rschema.rproperty(tschemas[0], entity.e_schema, 'composite'):
- defaultvid = 'csv'
- else:
- defaultvid = 'reledit'
- vid = dispctrl.get('vid', defaultvid)
+ vid = dispctrl.get('vid', 'reledit')
if rschema.is_final() or vid == 'reledit':
value = entity.view(vid, rtype=rschema.type, role=role)
else:
--- a/web/views/schema.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/views/schema.py Thu Jul 16 13:30:13 2009 +0200
@@ -7,7 +7,9 @@
"""
__docformat__ = "restructuredtext en"
-from logilab.mtconverter import html_escape
+from itertools import cycle
+
+from logilab.mtconverter import xml_escape
from yams import schema2dot as s2d
from cubicweb.selectors import implements, yes
@@ -47,7 +49,7 @@
def render_entity_title(self, entity):
self.w(u'<h1><span class="etype">%s</span> %s</h1>'
% (entity.dc_type().capitalize(),
- html_escape(entity.dc_long_title())))
+ xml_escape(entity.dc_long_title())))
# CWEType ######################################################################
@@ -123,8 +125,8 @@
entity = self.entity(row, col)
url = entity.absolute_url(vid='schemagraph')
self.w(u'<img src="%s" alt="%s"/>' % (
- html_escape(url),
- html_escape(self.req._('graphical schema for %s') % entity.name)))
+ xml_escape(url),
+ xml_escape(self.req._('graphical schema for %s') % entity.name)))
class CWETypeSPermView(EntityView):
id = 'cwetype-schema-permissions'
@@ -161,8 +163,8 @@
entity = self.entity(row, col)
if entity.reverse_state_of:
self.w(u'<img src="%s" alt="%s"/>' % (
- html_escape(entity.absolute_url(vid='ewfgraph')),
- html_escape(self.req._('graphical workflow for %s') % entity.name)))
+ xml_escape(entity.absolute_url(vid='ewfgraph')),
+ xml_escape(self.req._('graphical workflow for %s') % entity.name)))
else:
self.w(u'<p>%s</p>' % _('There is no workflow defined for this entity.'))
--- a/web/views/startup.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/views/startup.py Thu Jul 16 13:30:13 2009 +0200
@@ -74,7 +74,7 @@
else:
href = req.build_url('view', vid='creation', etype='Card', wikiid='index')
label = self.req._('create an index page')
- self.w(u'<br/><a href="%s">%s</a>\n' % (html_escape(href), label))
+ self.w(u'<br/><a href="%s">%s</a>\n' % (xml_escape(href), label))
def folders(self):
self.w(u'<h4>%s</h4>\n' % self.req._('Browse by category'))
@@ -89,7 +89,7 @@
if v.category != 'startupview' or v.id in ('index', 'tree', 'manage'):
continue
self.w('<p><a href="%s">%s</a></p>' % (
- html_escape(v.url()), html_escape(self.req._(v.title).capitalize())))
+ xml_escape(v.url()), xml_escape(self.req._(v.title).capitalize())))
def entities(self):
schema = self.schema
@@ -144,7 +144,7 @@
else:
url = self.build_url('view', rql='%s X' % etype)
etypelink = u' <a href="%s">%s</a> (%d)' % (
- html_escape(url), label, nb)
+ xml_escape(url), label, nb)
yield (label, etypelink, self.add_entity_link(eschema, req))
def add_entity_link(self, eschema, req):
@@ -152,13 +152,13 @@
if not eschema.has_perm(req, 'add'):
return u''
return u'[<a href="%s" title="%s">+</a>]' % (
- html_escape(self.create_url(eschema.type)),
+ xml_escape(self.create_url(eschema.type)),
self.req.__('add a %s' % eschema))
class IndexView(ManageView):
id = 'index'
- title = _('index')
+ title = _('view_index')
def display_folders(self):
return 'Folder' in self.schema and self.req.execute('Any COUNT(X) WHERE X is Folder')[0][0]
@@ -184,9 +184,9 @@
self.w(_(u'<div>This schema of the data model <em>excludes</em> the '
u'meta-data, but you can also display a <a href="%s">complete '
u'schema with meta-data</a>.</div>')
- % html_escape(self.build_url('view', vid='schemagraph', skipmeta=0)))
+ % xml_escape(self.build_url('view', vid='schemagraph', withmeta=1)))
self.w(u'<img src="%s" alt="%s"/>\n' % (
- html_escape(self.req.build_url('view', vid='schemagraph', skipmeta=1)),
+ xml_escape(self.req.build_url('view', vid='schemagraph', skipmeta=1)),
self.req._("graphical representation of the application'schema")))
@@ -228,15 +228,15 @@
self.w(u'<h2 class="schema">%s</h2>' % _('index').capitalize())
self.w(u'<h4>%s</h4>' % _('Entities').capitalize())
ents = []
- for eschema in entities:
- url = html_escape(self.build_url('schema', **formparams))
+ for eschema in sorted(entities):
+ url = xml_escape(self.build_url('schema', **formparams))
ents.append(u'<a class="grey" href="%s#%s">%s</a> (%s)' % (
url, eschema.type, eschema.type, _(eschema.type)))
self.w(u', '.join(ents))
self.w(u'<h4>%s</h4>' % (_('relations').capitalize()))
rels = []
- for rschema in relations:
- url = html_escape(self.build_url('schema', **formparams))
+ for rschema in sorted(relations):
+ url = xml_escape(self.build_url('schema', **formparams))
rels.append(u'<a class="grey" href="%s#%s">%s</a> (%s), ' % (
url , rschema.type, rschema.type, _(rschema.type)))
self.w(u', '.join(ents))
@@ -254,7 +254,7 @@
for eschema in entities:
self.w(u'<a id="%s" href="%s"/>' % (eschema.type, eschema.type))
self.w(u'<h3 class="schema">%s (%s) ' % (eschema.type, _(eschema.type)))
- url = html_escape(self.build_url('schema', **formparams) + '#index')
+ url = xml_escape(self.build_url('schema', **formparams) + '#index')
self.w(u'<a href="%s"><img src="%s" alt="%s"/></a>' % (
url, self.req.external_resource('UP_ICON'), _('up')))
self.w(u'</h3>')
@@ -281,7 +281,7 @@
for rschema in relations:
self.w(u'<a id="%s" href="%s"/>' % (rschema.type, rschema.type))
self.w(u'<h3 class="schema">%s (%s) ' % (rschema.type, _(rschema.type)))
- url = html_escape(self.build_url('schema', **formparams) + '#index')
+ url = xml_escape(self.build_url('schema', **formparams) + '#index')
self.w(u'<a href="%s"><img src="%s" alt="%s"/></a>' % (
url, self.req.external_resource('UP_ICON'), _('up')))
self.w(u'</h3>')
--- a/web/views/tableview.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/views/tableview.py Thu Jul 16 13:30:13 2009 +0200
@@ -10,7 +10,7 @@
from simplejson import dumps
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
from cubicweb.selectors import nonempty_rset, match_form_params
from cubicweb.utils import make_uid
@@ -55,7 +55,7 @@
# drop False / None values from vidargs
vidargs = dict((k, v) for k, v in vidargs.iteritems() if v)
self.w(u'<form method="post" cubicweb:facetargs="%s" action="">' %
- html_escape(dumps([divid, 'table', False, vidargs])))
+ xml_escape(dumps([divid, 'table', False, vidargs])))
self.w(u'<fieldset id="%sForm" class="%s">' % (divid, hidden and 'hidden' or ''))
self.w(u'<input type="hidden" name="divid" value="%s" />' % divid)
filter_hiddens(self.w, facets=','.join(wdg.facet.id for wdg in fwidgets), baserql=baserql)
@@ -178,7 +178,7 @@
box = MenuWidget('', 'tableActionsBox', _class='', islist=False)
label = '<img src="%s" alt="%s"/>' % (
self.req.datadir_url + 'liveclipboard-icon.png',
- html_escape(self.req._('action(s) on this selection')))
+ xml_escape(self.req._('action(s) on this selection')))
menu = PopupBoxMenu(label, isitem=False, link_class='actionsBox',
ident='%sActions' % divid)
box.append(menu)
--- a/web/views/tabs.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/views/tabs.py Thu Jul 16 13:30:13 2009 +0200
@@ -8,7 +8,7 @@
__docformat__ = "restructuredtext en"
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
from cubicweb import NoSelectableObject, role
from cubicweb.selectors import partial_has_related_entities
@@ -47,7 +47,7 @@
elif rset:
urlparams['rql'] = rset.printable_rql()
w(u'<div id="lazy-%s" cubicweb:loadurl="%s">' % (
- vid, html_escape(self.build_url('json', **urlparams))))
+ vid, xml_escape(self.build_url('json', **urlparams))))
if show_spinbox:
w(u'<img src="data/loading.gif" id="%s-hole" alt="%s"/>'
% (vid, self.req._('loading')))
--- a/web/views/timeline.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/views/timeline.py Thu Jul 16 13:30:13 2009 +0200
@@ -11,7 +11,7 @@
import simplejson
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
from cubicweb.interfaces import ICalendarable
from cubicweb.selectors import implements
@@ -68,7 +68,7 @@
if start is None and stop is None:
return None
event_data = {'start': start.strftime(self.date_fmt),
- 'title': html_escape(entity.dc_title()),
+ 'title': xml_escape(entity.dc_title()),
'description': entity.dc_description(format='text/html'),
'link': entity.absolute_url(),
}
@@ -95,7 +95,7 @@
additional = u''
self.w(u'<div class="widget" cubicweb:wdgtype="%s" '
u'cubicweb:loadtype="auto" cubicweb:loadurl="%s" %s >' %
- (self.widget_class, html_escape(loadurl),
+ (self.widget_class, xml_escape(loadurl),
additional))
self.w(u'</div>')
--- a/web/views/timetable.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/views/timetable.py Thu Jul 16 13:30:13 2009 +0200
@@ -6,7 +6,7 @@
:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
"""
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
from cubicweb.interfaces import ITimetableViews
from cubicweb.selectors import implements
@@ -190,7 +190,7 @@
if value:
task_descr, first_row = value
if first_row:
- url = html_escape(task_descr.task.absolute_url(vid="edition"))
+ url = xml_escape(task_descr.task.absolute_url(vid="edition"))
self.w(u'<td rowspan="%d" class="%s %s" onclick="document.location=\'%s\'"> <div>' % (
task_descr.lines, task_descr.color, filled_klasses[kj], url))
task_descr.task.view('tooltip', w=self.w)
--- a/web/views/treeview.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/views/treeview.py Thu Jul 16 13:30:13 2009 +0200
@@ -8,7 +8,7 @@
__docformat__ = "restructuredtext en"
from logilab.common.decorators import monkeypatch
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
from cubicweb.utils import make_uid
from cubicweb.interfaces import ITree
@@ -39,7 +39,7 @@
self.w(u'</ul>')
if initial_load and not self.req.form.get('fname'):
self.req.add_css('jquery.treeview.css')
- self.req.add_js(('cubicweb.ajax.js', 'jquery.treeview.js'))
+ self.req.add_js(('cubicweb.ajax.js', 'cubicweb.widgets.js', 'jquery.treeview.js'))
self.req.html_headers.add_onload(u"""
jQuery("#tree-%s").treeview({toggle: toggleTree, prerendered: true});""" % treeid)
@@ -113,7 +113,7 @@
w(u'<li class="%s">' % u' '.join(liclasses))
else:
rql = entity.children_rql() % {'x': entity.eid}
- url = html_escape(self.build_url('json', rql=rql, vid=parentvid,
+ url = xml_escape(self.build_url('json', rql=rql, vid=parentvid,
pageid=self.req.pageid,
treeid=treeid,
fname='view',
--- a/web/views/workflow.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/views/workflow.py Thu Jul 16 13:30:13 2009 +0200
@@ -11,7 +11,7 @@
__docformat__ = "restructuredtext en"
_ = unicode
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
from logilab.common.graph import escape, GraphGenerator, DotBackend
from cubicweb import Unauthorized, view
@@ -118,7 +118,7 @@
__select__ = implements('State')
def cell_call(self, row, col):
- self.w(html_escape(self.view('textincontext', self.rset,
+ self.w(xml_escape(self.view('textincontext', self.rset,
row=row, col=col)))
@@ -145,8 +145,8 @@
self.w(u'<h1>%s</h1>' % (self.req._('workflow for %s')
% display_name(self.req, entity.name)))
self.w(u'<img src="%s" alt="%s"/>' % (
- html_escape(entity.absolute_url(vid='ewfgraph')),
- html_escape(self.req._('graphical workflow for %s') % entity.name)))
+ xml_escape(entity.absolute_url(vid='ewfgraph')),
+ xml_escape(self.req._('graphical workflow for %s') % entity.name)))
class WorkflowDotPropsHandler(object):
--- a/web/views/xbel.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/views/xbel.py Thu Jul 16 13:30:13 2009 +0200
@@ -8,7 +8,7 @@
__docformat__ = "restructuredtext en"
_ = unicode
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
from cubicweb.selectors import implements
from cubicweb.view import EntityView
@@ -42,8 +42,8 @@
def cell_call(self, row, col):
entity = self.complete_entity(row, col)
- self.w(u'<bookmark href="%s">' % html_escape(self.url(entity)))
- self.w(u' <title>%s</title>' % html_escape(entity.dc_title()))
+ self.w(u'<bookmark href="%s">' % xml_escape(self.url(entity)))
+ self.w(u' <title>%s</title>' % xml_escape(entity.dc_title()))
self.w(u'</bookmark>')
def url(self, entity):
--- a/web/widgets.py Wed Jul 15 09:45:13 2009 +0200
+++ b/web/widgets.py Thu Jul 16 13:30:13 2009 +0200
@@ -12,7 +12,7 @@
from datetime import datetime
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import xml_escape
from yams.constraints import SizeConstraint, StaticVocabularyConstraint
@@ -247,9 +247,9 @@
value = self.current_value(entity)
dvalue = self.current_display_value(entity)
if isinstance(value, basestring):
- value = html_escape(value)
+ value = xml_escape(value)
if isinstance(dvalue, basestring):
- dvalue = html_escape(dvalue)
+ dvalue = xml_escape(dvalue)
return u'%s<input type="%s" name="%s" value="%s" %s/>' % (
self.hidden_input(entity, value), self.input_type,
self.rname, dvalue, self.format_attrs())
@@ -323,9 +323,9 @@
value = self.current_value(entity)
dvalue = self.current_display_value(entity)
if isinstance(value, basestring):
- value = html_escape(value)
+ value = xml_escape(value)
if isinstance(dvalue, basestring):
- dvalue = html_escape(dvalue)
+ dvalue = xml_escape(dvalue)
iid = self.attrs.pop('id')
if self.required(entity):
cssclass = u' required'
@@ -337,7 +337,7 @@
'iid': iid,
'hidden': self.hidden_input(entity, value),
'wdgtype': self.wdgtype,
- 'url': html_escape(dataurl),
+ 'url': xml_escape(dataurl),
'tabindex': self.attrs.pop('tabindex'),
'value': dvalue,
'attrs': self.format_attrs(),
@@ -398,7 +398,7 @@
editor = self._edit_render_textarea(entity, with_format)
value = self.current_value(entity)
if isinstance(value, basestring):
- value = html_escape(value)
+ value = xml_escape(value)
return u'%s%s' % (self.hidden_input(entity, value), editor)
def _edit_render_textarea(self, entity, with_format):
@@ -406,7 +406,7 @@
self.attrs.setdefault('rows', 20)
dvalue = self.current_display_value(entity)
if isinstance(dvalue, basestring):
- dvalue = html_escape(dvalue)
+ dvalue = xml_escape(dvalue)
if entity.use_fckeditor(self.name):
entity.req.fckeditor_config()
if with_format:
@@ -472,9 +472,9 @@
or entity.e_schema.has_metadata(self.name, 'encoding')):
divid = '%s-%s-advanced' % (self.name, entity.eid)
wdgs.append(u'<a href="%s" title="%s"><img src="%s" alt="%s"/></a>' %
- (html_escape(toggle_action(divid)),
+ (xml_escape(toggle_action(divid)),
req._('show advanced fields'),
- html_escape(req.build_url('data/puce_down.png')),
+ xml_escape(req.build_url('data/puce_down.png')),
req._('show advanced fields')))
wdgs.append(u'<div id="%s" class="hidden">' % divid)
for extraattr in ('_format', '_encoding'):
@@ -572,7 +572,7 @@
res.append(u'<optgroup label="%s"/>' % (label or ''))
else:
value, flag = self.form_value(entity, value, dvalues)
- res.append(u'<option value="%s" %s>%s</option>' % (value, flag, html_escape(label)))
+ res.append(u'<option value="%s" %s>%s</option>' % (value, flag, xml_escape(label)))
res.append(u'</select>')
return '\n'.join(res)
@@ -658,7 +658,7 @@
res.append(u'<optgroup label="%s"/>' % (label or ''))
else:
value, flag = self.form_value(entity, value, dvalues)
- res.append(u'<option value="%s" %s>%s</option>' % (value, flag, html_escape(label)))
+ res.append(u'<option value="%s" %s>%s</option>' % (value, flag, xml_escape(label)))
res.append(u'</select>')
res.append(u'<div id="newvalue">')
res.append(u'<input type="text" id="newopt" />')
@@ -819,7 +819,7 @@
url = getattr(entity, self.name)
if not url:
return u''
- url = html_escape(url)
+ url = xml_escape(url)
return u'<a href="%s">%s</a>' % (url, url)
class EmbededURLWidget(StringWidget):
@@ -828,7 +828,7 @@
url = getattr(entity, self.name)
if not url:
return u''
- aurl = html_escape(entity.build_url('embed', url=url))
+ aurl = xml_escape(entity.build_url('embed', url=url))
return u'<a href="%s">%s</a>' % (aurl, url)