merge and fix cubicwebSortValueExtraction pb which disappeared when tablesorter.js has been updated
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pylintext.py Fri Oct 14 09:21:45 2011 +0200
@@ -0,0 +1,41 @@
+"""https://pastebin.logilab.fr/show/860/"""
+
+from logilab.astng import MANAGER, nodes, scoped_nodes
+
+def turn_function_to_class(node):
+ """turn a Function node into a Class node (in-place)"""
+ node.__class__ = scoped_nodes.Class
+ node.bases = ()
+ # remove return nodes so that we don't get warned about 'return outside
+ # function' by pylint
+ for rnode in node.nodes_of_class(nodes.Return):
+ rnode.parent.body.remove(rnode)
+ # that seems to be enough :)
+
+
+def cubicweb_transform(module):
+ # handle objectify_selector decorator. Only look at module level functions,
+ # should be enough
+ for assnodes in module.locals.values():
+ for node in assnodes:
+ if isinstance(node, scoped_nodes.Function) and node.decorators:
+ for decorator in node.decorators.nodes:
+ for infered in decorator.infer():
+ if infered.name == 'objectify_selector':
+ turn_function_to_class(node)
+ break
+ else:
+ continue
+ break
+ # add yams base types into 'yams.buildobjs', astng doesn't grasp globals()
+ # magic in there
+ if module.name == 'yams.buildobjs':
+ from yams import BASE_TYPES
+ for etype in BASE_TYPES:
+ module.locals[etype] = [scoped_nodes.Class(etype, None)]
+
+MANAGER.register_transformer(cubicweb_transform)
+
+def register(linter):
+ """called when loaded by pylint --load-plugins, nothing to do here"""
+
--- a/server/migractions.py Fri Oct 14 08:51:24 2011 +0200
+++ b/server/migractions.py Fri Oct 14 09:21:45 2011 +0200
@@ -1554,14 +1554,15 @@
rschema = self.repo.schema.rschema(attr)
oldtype = rschema.objects(etype)[0]
rdefeid = rschema.rdef(etype, oldtype).eid
+ allownull = rschema.rdef(etype, oldtype).cardinality[0] != '1'
sql = ("UPDATE cw_CWAttribute "
"SET cw_to_entity=(SELECT cw_eid FROM cw_CWEType WHERE cw_name='%s')"
"WHERE cw_eid=%s") % (newtype, rdefeid)
self.sqlexec(sql, ask_confirm=False)
dbhelper = self.repo.system_source.dbhelper
sqltype = dbhelper.TYPE_MAPPING[newtype]
- sql = 'ALTER TABLE cw_%s ALTER COLUMN cw_%s TYPE %s' % (etype, attr, sqltype)
- self.sqlexec(sql, ask_confirm=False)
+ cursor = self.session.cnxset[self.repo.system_source.uri]
+ dbhelper.change_col_type(cursor, 'cw_%s' % etype, 'cw_%s' % attr, sqltype, allownull)
if commit:
self.commit()
--- a/view.py Fri Oct 14 08:51:24 2011 +0200
+++ b/view.py Fri Oct 14 09:21:45 2011 +0200
@@ -23,6 +23,7 @@
import types, new
from cStringIO import StringIO
from warnings import warn
+from functools import partial
from logilab.common.deprecation import deprecated
from logilab.mtconverter import xml_escape
@@ -451,25 +452,54 @@
category = _('anyrsetview')
def columns_labels(self, mainindex=0, tr=True):
+ """compute the label of the rset colums
+
+ The logic is based on :meth:`~rql.stmts.Union.get_description`.
+
+ :param mainindex: The index of the main variable. This is an hint to get
+ more accurate label for various situation
+ :type mainindex: int
+
+ :param tr: Should the label be translated ?
+ :type tr: boolean
+ """
if tr:
- translate = lambda val, req=self._cw: display_name(req, val)
+ translate = partial(display_name, self._cw)
else:
translate = lambda val: val
# XXX [0] because of missing Union support
- rqlstdescr = self.cw_rset.syntax_tree().get_description(mainindex,
- translate)[0]
+ rql_syntax_tree = self.cw_rset.syntax_tree()
+ rqlstdescr = rql_syntax_tree.get_description(mainindex)[0]
labels = []
for colidx, label in enumerate(rqlstdescr):
- try:
- label = getattr(self, 'label_column_%s' % colidx)()
- except AttributeError:
- # compute column header
- if label == 'Any': # find a better label
- label = ','.join(translate(et)
- for et in self.cw_rset.column_types(colidx))
- labels.append(label)
+ labels.append(self.column_label(colidx, label, translate))
return labels
+ def column_label(self, colidx, default, translate_func=None):
+ """return the label of a specified columns index
+
+ Overwrite me if you need to compute specific label.
+
+ :param colidx: The index of the column the call computes a label for.
+ :type colidx: int
+
+ :param default: Default value. If ``"Any"`` the default value will be
+ recomputed as coma separated list for all possible
+ etypes name.
+ :type colidx: string
+
+ :param translate_func: A function used to translate name.
+ :type colidx: function
+ """
+ label = default
+ if label == 'Any':
+ etypes = self.cw_rset.column_types(colidx)
+ if translate_func is not None:
+ etypes = map(translate_func, etypes)
+ label = ','.join(etypes)
+ return label
+
+
# concrete template base classes ##############################################
--- a/web/data/cubicweb.ajax.js Fri Oct 14 08:51:24 2011 +0200
+++ b/web/data/cubicweb.ajax.js Fri Oct 14 09:21:45 2011 +0200
@@ -257,10 +257,6 @@
}
function _postAjaxLoad(node) {
- // find sortable tables if there are some
- if (typeof(Sortable) != 'undefined') {
- Sortable.sortTables(node);
- }
// find textareas and wrap them if there are some
if (typeof(FCKeditor) != 'undefined') {
buildWysiwygEditors();
--- a/web/data/cubicweb.js Fri Oct 14 08:51:24 2011 +0200
+++ b/web/data/cubicweb.js Fri Oct 14 09:21:45 2011 +0200
@@ -82,6 +82,15 @@
}
return src;
}
+
+
+ sortValueExtraction: function (node) {
+ var sortvalue = jQuery(node).attr('cubicweb:sortvalue');
+ if (sortvalue === undefined) {
+ return '';
+ }
+ return sortvalue;
+}
});
--- a/web/facet.py Fri Oct 14 08:51:24 2011 +0200
+++ b/web/facet.py Fri Oct 14 09:21:45 2011 +0200
@@ -90,6 +90,31 @@
## rqlst manipulation functions used by facets ################################
def init_facets(rset, select, mainvar=None):
+ """Alters in place the <select> for filtering and returns related data.
+
+ Calls :func:`prepare_select` to prepare the syntaxtree for selection and
+ :func:`get_filtered_variable` that selects the variable to be filtered and
+ drops several parts of the select tree. See each function docstring for
+ details.
+
+ :param rset: ResultSet we init facet for.
+ :type rset: :class:`~cubicweb.rset.ResultSet`
+
+ :param select: Select statement to be *altered* to support filtering.
+ :type select: :class:`~rql.stmts.Select` from the ``rset`` parameters.
+
+ :param mainvar: Name of the variable we want to filter with facets.
+ :type mainvar: string
+
+ :rtype: (filtered_variable, baserql) tuple.
+ :return filtered_variable: A rql class:`~rql.node.VariableRef`
+ instance as returned by
+ :func:`get_filtered_variable`.
+
+ :return baserql: A string containing the rql before
+ :func:`prepare_select` but after
+ :func:`get_filtered_variable`.
+ """
rset.req.vreg.rqlhelper.annotate(select)
filtered_variable = get_filtered_variable(select, mainvar)
baserql = select.as_string(kwargs=rset.args) # before call to prepare_select
--- a/web/views/actions.py Fri Oct 14 08:51:24 2011 +0200
+++ b/web/views/actions.py Fri Oct 14 09:21:45 2011 +0200
@@ -147,7 +147,7 @@
class ModifyAction(action.Action):
__regid__ = 'edit'
__select__ = (action.Action.__select__
- & one_line_rset() & has_editable_relation('add'))
+ & one_line_rset() & has_editable_relation())
title = _('modify')
category = 'mainactions'
--- a/web/views/cwsources.py Fri Oct 14 08:51:24 2011 +0200
+++ b/web/views/cwsources.py Fri Oct 14 09:21:45 2011 +0200
@@ -39,7 +39,6 @@
_abaa.tag_object_of(('CWSourceSchemaConfig', 'cw_host_config_of', '*'), False)
_afs = uicfg.autoform_section
-_afs.tag_attribute(('CWSource', 'synchronizing'), 'main', 'hidden')
_afs.tag_object_of(('*', 'cw_for_source', 'CWSource'), 'main', 'hidden')
_affk = uicfg.autoform_field_kwargs
--- a/web/views/facets.py Fri Oct 14 08:51:24 2011 +0200
+++ b/web/views/facets.py Fri Oct 14 09:21:45 2011 +0200
@@ -27,6 +27,7 @@
match_context_prop, yes, relation_possible)
from cubicweb.utils import json_dumps
from cubicweb.web import component, facet as facetbase
+from cubicweb.rqlrewrite import add_types_restriction
def facets(req, rset, context, mainvar=None):
"""return the base rql and a list of widgets for facets applying to the
@@ -65,6 +66,17 @@
if len(origqlst.children) != 1:
req.debug('facette disabled on union request %s', origqlst)
return None, ()
+
+ # Add type restriction to rql. This allow the get_type() method to return
+ # useful value on variable extracted from a select statement.
+ #
+ # This is done on origqlst to ensure all rql related objects are properly
+ # enriched when handled by a Facet:
+ # - the rset.syntax_tree() during selection
+ # - the select during selection
+ # - the select during filtering
+
+ add_types_restriction(req.vreg.schema, origqlst.children[0])
rqlst = origqlst.copy()
select = rqlst.children[0]
filtered_variable, baserql = facetbase.init_facets(rset, select, mainvar)
@@ -175,6 +187,20 @@
hiddens['mainvar'] = mainvar
filter_hiddens(w, baserql, wdgs, **hiddens)
self.layout_widgets(w, self.sorted_widgets(wdgs))
+
+ # <Enter> is supposed to submit the form only if there is a single
+ # input:text field. However most browsers will submit the form
+ # on <Enter> anyway if there is an input:submit field.
+ #
+ # see: http://www.w3.org/MarkUp/html-spec/html-spec_8.html#SEC8.2
+ #
+ # Firefox 7.0.1 does not submit form on <Enter> if there is more than a
+ # input:text field and not input:submit but does it if there is an
+ # input:submit.
+ #
+ # IE 6 or Firefox 2 behave the same way.
+ w(u'<input type="submit" class="hidden" />')
+ #
w(u'</fieldset>\n')
w(u'</form>\n')
--- a/web/views/tableview.py Fri Oct 14 08:51:24 2011 +0200
+++ b/web/views/tableview.py Fri Oct 14 09:21:45 2011 +0200
@@ -24,7 +24,7 @@
from cubicweb import NoSelectableObject, tags
from cubicweb.selectors import nonempty_rset
-from cubicweb.utils import make_uid, json_dumps
+from cubicweb.utils import make_uid, js_dumps, JSString
from cubicweb.view import EntityView, AnyRsetView
from cubicweb.uilib import toggle_action, limitsize, htmlescape
from cubicweb.web import jsonize, component, facet
@@ -45,6 +45,11 @@
table_widget_class = TableWidget
table_column_class = TableColumn
+ tablesorter_settings = {
+ 'textExtraction': JSString('cw.sortValueExtraction'),
+ 'selectorHeaders: "thead tr:first th"' # only plug on the first row
+ }
+
def form_filter(self, divid, displaycols, displayactions, displayfilter,
paginate, hidden=True):
try:
@@ -84,6 +89,15 @@
displaycols = range(len(self.cw_rset.syntax_tree().children[0].selection))
return displaycols
+ def _setup_tablesorter(self, divid):
+ req = self._cw
+ req.add_js('jquery.tablesorter.js')
+ req.add_onload('''$(document).ready(function() {
+ $("#%s table.listing").tablesorter(%s);
+});''' % (divid, js_dumps(self.tablesorter_settings)))
+ req.add_css(('cubicweb.tablesorter.css', 'cubicweb.tableview.css'))
+
+
def call(self, title=None, subvid=None, displayfilter=None, headers=None,
displaycols=None, displayactions=None, actions=(), divid=None,
cellvids=None, cellattrs=None, mainindex=None,
@@ -98,12 +112,8 @@
:param displayactions: if True, display action menu
"""
req = self._cw
- req.add_js('jquery.tablesorter.js')
- req.add_onload('jQuery("table.listing").tablesorter({'
- 'textExtraction: cubicwebSortValueExtraction,' # use our own function
- 'selectorHeaders: "thead tr:first th"' # only plug on the first row
- '});')
- req.add_css(('cubicweb.tablesorter.css', 'cubicweb.tableview.css'))
+ divid = divid or req.form.get('divid') or 'rs%s' % make_uid(id(self.cw_rset))
+ self._setup_tablesorter(divid)
# compute label first since the filter form may remove some necessary
# information from the rql syntax tree
if mainindex is None:
@@ -112,7 +122,6 @@
hidden = True
if not subvid and 'subvid' in req.form:
subvid = req.form.pop('subvid')
- divid = divid or req.form.get('divid') or 'rs%s' % make_uid(id(self.cw_rset))
actions = list(actions)
if mainindex is None:
displayfilter, displayactions = False, False