backport stable branch 3.5
authorNicolas Chauvat <nicolas.chauvat@logilab.fr>
Wed, 26 Aug 2009 13:09:19 +0200
branch3.5
changeset 3019 bdb120240d75
parent 3005 a50d03e7014f (current diff)
parent 3015 0588e39f6743 (diff)
child 3022 238ad682bcb7
backport stable branch
web/data/cubicweb.formfilter.js
--- a/sobjects/notification.py	Wed Aug 26 09:08:44 2009 +0200
+++ b/sobjects/notification.py	Wed Aug 26 13:09:19 2009 +0200
@@ -76,9 +76,10 @@
         except RegistryException:
             return
         comment = entity.printable_value('comment', format='text/plain')
-        if comment:
-            comment = normalize_text(comment, 80,
-                                     rest=entity.comment_format=='text/rest')
+        # XXX don't try to wrap rest until we've a proper transformation (see
+        # #103822)
+        if comment and entity.comment_format != 'text/rest':
+            comment = normalize_text(comment, 80)
         RenderAndSendNotificationView(session, view=view, viewargs={
             'comment': comment, 'previous_state': entity.previous_state.name,
             'current_state': entity.new_state.name})
@@ -175,8 +176,12 @@
         entity = self.entity(self.row or 0, self.col or 0)
         content = entity.printable_value(self.content_attr, format='text/plain')
         if content:
-            contentformat = getattr(entity, self.content_attr + '_format', 'text/rest')
-            content = normalize_text(content, 80, rest=contentformat=='text/rest')
+            contentformat = getattr(entity, self.content_attr + '_format',
+                                    'text/rest')
+            # XXX don't try to wrap rest until we've a proper transformation (see
+            # #103822)
+            if contentformat != 'text/rest':
+                content = normalize_text(content, 80)
         return super(ContentAddedView, self).context(content=content, **kwargs)
 
     def subject(self):
--- a/view.py	Wed Aug 26 09:08:44 2009 +0200
+++ b/view.py	Wed Aug 26 13:09:19 2009 +0200
@@ -468,8 +468,10 @@
     __select__ = yes()
     property_defs = {}
 
+    # XXX huummm, much probably useless
+    htmlclass = 'mainRelated'
     def div_class(self):
-        return '%s %s' % (self.propval('htmlclass'), self.id)
-
+        return '%s %s' % (self.htmlclass, self.id)
+    # XXX a generic '%s%s' % (self.id, self.__registry__.capitalize()) would probably be nicer
     def div_id(self):
         return '%sComponent' % self.id
--- a/web/component.py	Wed Aug 26 09:08:44 2009 +0200
+++ b/web/component.py	Wed Aug 26 13:09:19 2009 +0200
@@ -8,6 +8,8 @@
 __docformat__ = "restructuredtext en"
 _ = unicode
 
+from simplejson import dumps
+
 from logilab.common.deprecation import class_renamed
 from logilab.mtconverter import xml_escape
 
@@ -45,8 +47,6 @@
                                         _('navcontenttop'), _('navcontentbottom')),
                             #vocabulary=(_('header'), _('incontext'), _('footer')),
                             help=_('context where this component should be displayed')),
-        _('htmlclass'):dict(type='String', default='mainRelated',
-                            help=_('html class of the component')),
     }
 
     context = 'navcontentbottom' # 'footer' | 'header' | 'incontext'
@@ -74,7 +74,8 @@
     page_link_templ = u'<span class="slice"><a href="%s" title="%s">%s</a></span>'
     selected_page_link_templ = u'<span class="selectedSlice"><a href="%s" title="%s">%s</a></span>'
     previous_page_link_templ = next_page_link_templ = page_link_templ
-    no_previous_page_link = no_next_page_link = u''
+    no_previous_page_link = u'&lt;&lt;'
+    no_next_page_link = u'&gt;&gt;'
 
     def __init__(self, req, rset, **kwargs):
         super(NavigationComponent, self).__init__(req, rset, **kwargs)
@@ -114,33 +115,40 @@
         if self.stop_param in params:
             del params[self.stop_param]
 
+    def page_url(self, path, params, start, stop):
+        params = merge_dicts(params, {self.start_param : start,
+                                      self.stop_param : stop,})
+        if path == 'json':
+            rql = params.pop('rql', self.rset.printable_rql())
+            # latest 'true' used for 'swap' mode
+            url = 'javascript: replacePageChunk(%s, %s, %s, %s, true)' % (
+                dumps(params.get('divid', 'paginated-content')),
+                dumps(rql), dumps(params.pop('vid', None)), dumps(params))
+        else:
+            url = self.build_url(path, **params)
+        return url
+
     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 = xml_escape(url)
+        url = xml_escape(self.page_url(path, params, start, stop))
         if start == self.starting_from:
             return self.selected_page_link_templ % (url, content, content)
         return self.page_link_templ % (url, content, content)
 
-    def previous_link(self, params, content='&lt;&lt;', title=_('previous_results')):
+    def previous_link(self, path, params, content='&lt;&lt;', title=_('previous_results')):
         start = self.starting_from
         if not start :
             return self.no_previous_page_link
         start = max(0, start - self.page_size)
         stop = start + self.page_size - 1
-        url = self.build_url(**merge_dicts(params, {self.start_param : start,
-                                                    self.stop_param : stop,}))
-        url = xml_escape(url)
+        url = xml_escape(self.page_url(path, params, start, stop))
         return self.previous_page_link_templ % (url, title, content)
 
-    def next_link(self, params, content='&gt;&gt;', title=_('next_results')):
+    def next_link(self, path, params, content='&gt;&gt;', title=_('next_results')):
         start = self.starting_from + self.page_size
         if start >= self.total:
             return self.no_next_page_link
         stop = start + self.page_size - 1
-        url = self.build_url(**merge_dicts(params, {self.start_param : start,
-                                                    self.stop_param : stop,}))
-        url = xml_escape(url)
+        url = xml_escape(self.page_url(path, params, start, stop))
         return self.next_page_link_templ % (url, title, content)
 
 
--- a/web/data/cubicweb.ajax.js	Wed Aug 26 09:08:44 2009 +0200
+++ b/web/data/cubicweb.ajax.js	Wed Aug 26 13:09:19 2009 +0200
@@ -66,7 +66,16 @@
     jQuery(CubicWeb).trigger('ajax-loaded');
 }
 
-// cubicweb loadxhtml plugin to make jquery handle xhtml response
+/* cubicweb loadxhtml plugin to make jquery handle xhtml response
+ *
+ * fetches `url` and replaces this's content with the result
+ *
+ * @param mode how the replacement should be done (default is 'replace')
+ *  Possible values are :
+ *    - 'replace' to replace the node's content with the generated HTML
+ *    - 'swap' to replace the node itself with the generated HTML
+ *    - 'append' to append the generated HTML to the node's content
+ */
 jQuery.fn.loadxhtml = function(url, data, reqtype, mode) {
     var ajax = null;
     if (reqtype == 'post') {
@@ -323,7 +332,7 @@
     }
 }
 
-/*
+/* XXX deprecates?
  * fetches `url` and replaces `nodeid`'s content with the result
  * @param replacemode how the replacement should be done (default is 'replace')
  *  Possible values are :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/data/cubicweb.facets.js	Wed Aug 26 13:09:19 2009 +0200
@@ -0,0 +1,227 @@
+/*
+ *  :organization: Logilab
+ *  :copyright: 2003-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+ *  :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
+ */
+
+CubicWeb.require('htmlhelpers.js');
+CubicWeb.require('ajax.js');
+
+//============= filter form functions ========================================//
+function copyParam(origparams, newparams, param) {
+    var index = findValue(origparams[0], param);
+    if (index > -1) {
+	newparams[param] = origparams[1][index];
+    }
+}
+
+function facetFormContent(form) {
+    var names = [];
+    var values = [];
+    jQuery(form).find('.facet').each(function () {
+        var facetName = jQuery(this).find('.facetTitle').attr('cubicweb:facetName');
+        var facetValues = jQuery(this).find('.facetValueSelected').each(function(x) {
+  	    names.push(facetName);
+  	    values.push(this.getAttribute('cubicweb:value'));
+        });
+    });
+    jQuery(form).find('input').each(function () {
+        names.push(this.name);
+        values.push(this.value);
+    });
+    jQuery(form).find('select option[selected]').each(function () {
+	names.push(this.parentNode.name);
+	values.push(this.value);
+    });
+    return [names, values];
+}
+
+function buildRQL(divid, vid, paginate, vidargs) {
+    jQuery(CubicWeb).trigger('facets-content-loading', [divid, vid, paginate, vidargs]);
+    var form = getNode(divid+'Form');
+    var zipped = facetFormContent(form);
+    zipped[0].push('facetargs');
+    zipped[1].push(vidargs);
+    var d = asyncRemoteExec('filter_build_rql', zipped[0], zipped[1]);
+    d.addCallback(function(result) {
+	var rql = result[0];
+	var $bkLink = jQuery('#facetBkLink');
+	if ($bkLink.length) {
+	    var bkUrl = $bkLink.attr('cubicweb:target') + '&path=view?rql=' + rql;
+	    if (vid) {
+		bkUrl += '&vid=' + vid;
+	    }
+	    $bkLink.attr('href', bkUrl);
+	}
+	var toupdate = result[1];
+	var extraparams = vidargs;
+	var displayactions = jQuery('#' + divid).attr('cubicweb:displayactions');
+	if (displayactions) { extraparams['displayactions'] = displayactions; }
+	if (paginate) { extraparams['paginate'] = '1'; }
+	// copy some parameters
+	// XXX cleanup vid/divid mess
+	// if vid argument is specified , the one specified in form params will
+	// be overriden by replacePageChunk
+	copyParam(zipped, extraparams, 'vid');
+	extraparams['divid'] = divid;
+	copyParam(zipped, extraparams, 'divid');
+	copyParam(zipped, extraparams, 'subvid');
+	// paginate used to know if the filter box is acting, in which case we
+	// want to reload action box to match current selection (we don't want
+	// this from a table filter)
+	replacePageChunk(divid, rql, vid, extraparams, true, function() {
+	  jQuery(CubicWeb).trigger('facets-content-loaded', [divid, rql, vid, extraparams]);
+	});
+	if (paginate) {
+	    // FIXME the edit box might not be displayed in which case we don't
+	    // know where to put the potential new one, just skip this case
+	    // for now
+	    if (jQuery('#edit_box').length) {
+		reloadComponent('edit_box', rql, 'boxes', 'edit_box');
+	    }
+	    if (jQuery('#breadcrumbs').length) {
+		reloadComponent('breadcrumbs', rql, 'components', 'breadcrumbs');
+	    }
+	}
+	var d = asyncRemoteExec('filter_select_content', toupdate, rql);
+	d.addCallback(function(updateMap) {
+	    for (facetId in updateMap) {
+		var values = updateMap[facetId];
+		jqNode(facetId).find('.facetCheckBox').each(function () {
+		    var value = this.getAttribute('cubicweb:value');
+		    if (!values.contains(value)) {
+			if (!jQuery(this).hasClass('facetValueDisabled')) {
+			    jQuery(this).addClass('facetValueDisabled');
+			}
+		    } else {
+			if (jQuery(this).hasClass('facetValueDisabled')) {
+			    jQuery(this).removeClass('facetValueDisabled');
+			}
+		    }
+		});
+	    }
+	});
+    });
+}
+
+
+var SELECTED_IMG = baseuri()+"data/black-check.png";
+var UNSELECTED_IMG = baseuri()+"data/no-check-no-border.png";
+var UNSELECTED_BORDER_IMG = baseuri()+"data/black-uncheck.png";
+
+function initFacetBoxEvents(root) {
+    // facetargs : (divid, vid, paginate, extraargs)
+    root = root || document;
+    jQuery(root).find('form').each(function () {
+	var form = jQuery(this);
+	// NOTE: don't evaluate facetargs here but in callbacks since its value
+	//       may changes and we must send its value when the callback is
+	//       called, not when the page is initialized
+	var facetargs = form.attr('cubicweb:facetargs');
+	if (facetargs !== undefined) {
+	    form.submit(function() {
+	        buildRQL.apply(null, evalJSON(form.attr('cubicweb:facetargs')));
+	        return false;
+	    });
+	    form.find('div.facet').each(function() {
+		var facet = jQuery(this);
+		facet.find('div.facetCheckBox').each(function (i) {
+		    this.setAttribute('cubicweb:idx', i);
+		});
+		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'));
+			// 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');
+			if (lastSelected.length) {
+			    lastSelected.after(this);
+			} else {
+			    var parent = this.parentNode;
+			    jQuery(parent).prepend(this);
+			}
+			jQuery(this).addClass('facetValueSelected');
+			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}, '');
+		});
+		facet.find('select.facetOperator').change(function() {
+		    var nbselected = facet.find('div.facetValueSelected').length;
+		    if (nbselected >= 2) {
+			buildRQL.apply(null, evalJSON(form.attr('cubicweb:facetargs')));
+		    }
+		});
+		facet.find('div.facetTitle').click(function() {
+		  facet.find('div.facetBody').toggleClass('hidden').toggleClass('opened');
+		  jQuery(this).toggleClass('opened');
+		   });
+
+	    });
+	}
+    });
+}
+
+// trigger this function on document ready event if you provide some kind of
+// persistent search (eg crih)
+function reorderFacetsItems(root){
+    root = root || document;
+    jQuery(root).find('form').each(function () {
+	var form = jQuery(this);
+	if (form.attr('cubicweb:facetargs')) {
+	    form.find('div.facet').each(function() {
+		var facet = jQuery(this);
+		var lastSelected = null;
+		facet.find('div.facetCheckBox').each(function (i) {
+		    var $this = jQuery(this);
+		    if ($this.hasClass('facetValueSelected')) {
+			if (lastSelected) {
+			    lastSelected.after(this);
+			} else {
+			    var parent = this.parentNode;
+			    jQuery(parent).prepend(this);
+			}
+			lastSelected = $this;
+		    }
+		});
+	    });
+	}
+    });
+}
+
+// we need to differenciate cases where initFacetBoxEvents is called
+// with one argument or without any argument. If we use `initFacetBoxEvents`
+// as the direct callback on the jQuery.ready event, jQuery will pass some argument
+// of his, so we use this small anonymous function instead.
+jQuery(document).ready(function() {initFacetBoxEvents();});
+
+CubicWeb.provide('facets.js');
--- a/web/data/cubicweb.formfilter.js	Wed Aug 26 09:08:44 2009 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,223 +0,0 @@
-/*
- *  :organization: Logilab
- *  :copyright: 2003-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
- *  :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
- */
-
-CubicWeb.require('htmlhelpers.js');
-CubicWeb.require('ajax.js');
-
-//============= filter form functions ========================================//
-function copyParam(origparams, newparams, param) {
-    var index = findValue(origparams[0], param);
-    if (index > -1) {
-	newparams[param] = origparams[1][index];
-    }
-}
-
-function facetFormContent(form) {
-    var names = [];
-    var values = [];
-    jQuery(form).find('.facet').each(function () {
-        var facetName = jQuery(this).find('.facetTitle').attr('cubicweb:facetName');
-        var facetValues = jQuery(this).find('.facetValueSelected').each(function(x) {
-  	    names.push(facetName);
-  	    values.push(this.getAttribute('cubicweb:value'));
-        });
-    });
-    jQuery(form).find('input').each(function () {
-        names.push(this.name);
-        values.push(this.value);
-    });
-    jQuery(form).find('select option[selected]').each(function () {
-	names.push(this.parentNode.name);
-	values.push(this.value);
-    });
-    return [names, values];
-}
-
-function buildRQL(divid, vid, paginate, vidargs) {
-    jQuery(CubicWeb).trigger('facets-content-loading', [divid, vid, paginate, vidargs]);
-    var form = getNode(divid+'Form');
-    var zipped = facetFormContent(form);
-    zipped[0].push('facetargs');
-    zipped[1].push(vidargs);
-    var d = asyncRemoteExec('filter_build_rql', zipped[0], zipped[1]);
-    d.addCallback(function(result) {
-	var rql = result[0];
-	var $bkLink = jQuery('#facetBkLink');
-	if ($bkLink.length) {
-	    var bkUrl = $bkLink.attr('cubicweb:target') + '&path=view?rql=' + rql;
-	    if (vid) {
-		bkUrl += '&vid=' + vid;
-	    }
-	    $bkLink.attr('href', bkUrl);
-	}
-	var toupdate = result[1];
-	var extraparams = vidargs;
-	var displayactions = jQuery('#' + divid).attr('cubicweb:displayactions');
-	if (displayactions) { extraparams['displayactions'] = displayactions; }
-	if (paginate) { extraparams['paginate'] = '1'; }
-	// copy some parameters
-	// XXX cleanup vid/divid mess
-	// if vid argument is specified , the one specified in form params will
-	// be overriden by replacePageChunk
-	copyParam(zipped, extraparams, 'vid');
-	extraparams['divid'] = divid;
-	copyParam(zipped, extraparams, 'divid');
-	copyParam(zipped, extraparams, 'subvid');
-	// paginate used to know if the filter box is acting, in which case we
-	// want to reload action box to match current selection
-	replacePageChunk(divid, rql, vid, extraparams, true, function() {
-	  jQuery(CubicWeb).trigger('facets-content-loaded', [divid, rql, vid, extraparams]);
-	});
-	if (paginate) {
-	    // FIXME the edit box might not be displayed in which case we don't
-	    // know where to put the potential new one, just skip this case
-	    // for now
-	    if (jQuery('#edit_box').length) {
-		reloadComponent('edit_box', rql, 'boxes', 'edit_box');
-	    }
-	}
-	var d = asyncRemoteExec('filter_select_content', toupdate, rql);
-	d.addCallback(function(updateMap) {
-	    for (facetId in updateMap) {
-		var values = updateMap[facetId];
-		jqNode(facetId).find('.facetCheckBox').each(function () {
-		    var value = this.getAttribute('cubicweb:value');
-		    if (!values.contains(value)) {
-			if (!jQuery(this).hasClass('facetValueDisabled')) {
-			    jQuery(this).addClass('facetValueDisabled');
-			}
-		    } else {
-			if (jQuery(this).hasClass('facetValueDisabled')) {
-			    jQuery(this).removeClass('facetValueDisabled');
-			}
-		    }
-		});
-	    }
-	});
-    });
-}
-
-
-var SELECTED_IMG = baseuri()+"data/black-check.png";
-var UNSELECTED_IMG = baseuri()+"data/no-check-no-border.png";
-var UNSELECTED_BORDER_IMG = baseuri()+"data/black-uncheck.png";
-
-function initFacetBoxEvents(root) {
-    // facetargs : (divid, vid, paginate, extraargs)
-    root = root || document;
-    jQuery(root).find('form').each(function () {
-	var form = jQuery(this);
-	// NOTE: don't evaluate facetargs here but in callbacks since its value
-	//       may changes and we must send its value when the callback is
-	//       called, not when the page is initialized
-	var facetargs = form.attr('cubicweb:facetargs');
-	if (facetargs !== undefined) {
-	    form.submit(function() {
-	        buildRQL.apply(null, evalJSON(form.attr('cubicweb:facetargs')));
-	        return false;
-	    });
-	    form.find('div.facet').each(function() {
-		var facet = jQuery(this);
-		facet.find('div.facetCheckBox').each(function (i) {
-		    this.setAttribute('cubicweb:idx', i);
-		});
-		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'));
-			// 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');
-			if (lastSelected.length) {
-			    lastSelected.after(this);
-			} else {
-			    var parent = this.parentNode;
-			    jQuery(parent).prepend(this);
-			}
-			jQuery(this).addClass('facetValueSelected');
-			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}, '');
-		});
-		facet.find('select.facetOperator').change(function() {
-		    var nbselected = facet.find('div.facetValueSelected').length;
-		    if (nbselected >= 2) {
-			buildRQL.apply(null, evalJSON(form.attr('cubicweb:facetargs')));
-		    }
-		});
-		facet.find('div.facetTitle').click(function() {
-		  facet.find('div.facetBody').toggleClass('hidden').toggleClass('opened');
-		  jQuery(this).toggleClass('opened');
-		   });
-
-	    });
-	}
-    });
-}
-
-// trigger this function on document ready event if you provide some kind of
-// persistent search (eg crih)
-function reorderFacetsItems(root){
-    root = root || document;
-    jQuery(root).find('form').each(function () {
-	var form = jQuery(this);
-	if (form.attr('cubicweb:facetargs')) {
-	    form.find('div.facet').each(function() {
-		var facet = jQuery(this);
-		var lastSelected = null;
-		facet.find('div.facetCheckBox').each(function (i) {
-		    var $this = jQuery(this);
-		    if ($this.hasClass('facetValueSelected')) {
-			if (lastSelected) {
-			    lastSelected.after(this);
-			} else {
-			    var parent = this.parentNode;
-			    jQuery(parent).prepend(this);
-			}
-			lastSelected = $this;
-		    }
-		});
-	    });
-	}
-    });
-}
-
-// we need to differenciate cases where initFacetBoxEvents is called
-// with one argument or without any argument. If we use `initFacetBoxEvents`
-// as the direct callback on the jQuery.ready event, jQuery will pass some argument
-// of his, so we use this small anonymous function instead.
-jQuery(document).ready(function() {initFacetBoxEvents();});
-
-CubicWeb.provide('formfilter.js');
--- a/web/views/facets.py	Wed Aug 26 09:08:44 2009 +0200
+++ b/web/views/facets.py	Wed Aug 26 13:09:19 2009 +0200
@@ -40,7 +40,7 @@
     roundcorners = True
 
     needs_css = 'cubicweb.facets.css'
-    needs_js = ('cubicweb.ajax.js', 'cubicweb.formfilter.js')
+    needs_js = ('cubicweb.ajax.js', 'cubicweb.facets.js')
 
     bk_linkbox_template = u'<div class="facetTitle">%s</div>'
 
--- a/web/views/ibreadcrumbs.py	Wed Aug 26 09:08:44 2009 +0200
+++ b/web/views/ibreadcrumbs.py	Wed Aug 26 13:09:19 2009 +0200
@@ -10,50 +10,55 @@
 
 from logilab.mtconverter import xml_escape
 
+from cubicweb.interfaces import IBreadCrumbs
+from cubicweb.selectors import (one_line_rset, implements, one_etype_rset,
+                                two_lines_rset, any_rset)
+from cubicweb.view import EntityView, Component
 # don't use AnyEntity since this may cause bug with isinstance() due to reloading
-from cubicweb.interfaces import IBreadCrumbs
-from cubicweb.selectors import match_context_prop, one_line_rset, implements
 from cubicweb.entity import Entity
-from cubicweb.view import EntityView
 from cubicweb.common.uilib import cut
-from cubicweb.web.component import EntityVComponent
 
 
 def bc_title(entity):
     textsize = entity.req.property_value('navigation.short-line-size')
     return xml_escape(cut(entity.dc_title(), textsize))
 
+# XXX only provides the component version
 
-class BreadCrumbEntityVComponent(EntityVComponent):
+class BreadCrumbEntityVComponent(Component):
     id = 'breadcrumbs'
-    # register msg not generated since no entity implements IPrevNext in cubicweb itself
+    __select__ = one_line_rset() & implements(IBreadCrumbs)
+
+    property_defs = {
+        _('visible'):  dict(type='Boolean', default=True,
+                            help=_('display the component or not')),
+        }
     title = _('contentnavigation_breadcrumbs')
     help = _('contentnavigation_breadcrumbs_description')
-    __select__ = (one_line_rset() & match_context_prop() & implements(IBreadCrumbs))
-    context = 'navtop'
-    order = 5
-    visible = False
     separator = u'&#160;&gt;&#160;'
 
     def call(self, view=None, first_separator=True):
         entity = self.entity(0)
         path = entity.breadcrumbs(view)
         if path:
-            self.w(u'<span class="pathbar">')
+            self.w(u'<span id="breadcrumbs" class="pathbar">')
             if first_separator:
                 self.w(self.separator)
-            root = path.pop(0)
-            if isinstance(root, Entity):
-                self.w(u'<a href="%s">%s</a>' % (self.req.build_url(root.id),
-                                                 root.dc_type('plural')))
-                self.w(self.separator)
-            self.wpath_part(root, entity, not path)
-            for i, parent in enumerate(path):
-                self.w(self.separator)
-                self.w(u"\n")
-                self.wpath_part(parent, entity, i == len(path) - 1)
+            self.render_breadcrumbs(entity, path)
             self.w(u'</span>')
 
+    def render_breadcrumbs(self, contextentity, path):
+        root = path.pop(0)
+        if isinstance(root, Entity):
+            self.w(u'<a href="%s">%s</a>' % (self.req.build_url(root.id),
+                                             root.dc_type('plural')))
+            self.w(self.separator)
+        self.wpath_part(root, contextentity, not path)
+        for i, parent in enumerate(path):
+            self.w(self.separator)
+            self.w(u"\n")
+            self.wpath_part(parent, contextentity, i == len(path) - 1)
+
     def wpath_part(self, part, contextentity, last=False):
         if isinstance(part, Entity):
             if last and part.eid == contextentity.eid:
@@ -70,10 +75,28 @@
             self.w(cut(unicode(part), textsize))
 
 
-class BreadCrumbComponent(BreadCrumbEntityVComponent):
-    __registry__ = 'components'
-    __select__ = (one_line_rset() & implements(IBreadCrumbs))
-    visible = True
+class BreadCrumbETypeVComponent(BreadCrumbEntityVComponent):
+    __select__ = two_lines_rset() & one_etype_rset() & implements(IBreadCrumbs)
+
+    def render_breadcrumbs(self, contextentity, path):
+        # XXX hack: only display etype name or first non entity path part
+        root = path.pop(0)
+        if isinstance(root, Entity):
+            self.w(u'<a href="%s">%s</a>' % (self.req.build_url(root.id),
+                                             root.dc_type('plural')))
+        else:
+            self.wpath_part(root, entity, not path)
+
+
+class BreadCrumbAnyRSetVComponent(BreadCrumbEntityVComponent):
+    __select__ = any_rset()
+
+    def call(self, view=None, first_separator=True):
+        self.w(u'<span id="breadcrumbs" class="pathbar">')
+        if first_separator:
+            self.w(self.separator)
+        self.w(self.req._('search'))
+        self.w(u'</span>')
 
 
 class BreadCrumbView(EntityView):
--- a/web/views/navigation.py	Wed Aug 26 09:08:44 2009 +0200
+++ b/web/views/navigation.py	Wed Aug 26 13:09:19 2009 +0200
@@ -40,9 +40,9 @@
                                             self.index_display(start, stop)))
             start = stop + 1
         w(u'<div class="pagination">')
-        w(u'%s&#160;' % self.previous_link(params))
+        w(u'%s&#160;' % self.previous_link(basepath, params))
         w(u'[&#160;%s&#160;]' % u'&#160;| '.join(blocklist))
-        w(u'&#160;%s' % self.next_link(params))
+        w(u'&#160;%s' % self.next_link(basepath, params))
         w(u'</div>')
 
     def index_display(self, start, stop):
@@ -131,18 +131,18 @@
             cell = self.format_link_content(index_display(start), index_display(stop))
             blocklist.append(self.page_link(basepath, params, start, stop, cell))
             start = stop + 1
-        self.write_links(params, blocklist)
+        self.write_links(basepath, params, blocklist)
 
     def format_link_content(self, startstr, stopstr):
         text = u'%s - %s' % (startstr.lower()[:self.nb_chars],
                              stopstr.lower()[:self.nb_chars])
         return xml_escape(text)
 
-    def write_links(self, params, blocklist):
+    def write_links(self, basepath, params, blocklist):
         self.w(u'<div class="pagination">')
-        self.w(u'%s&#160;' % self.previous_link(params))
+        self.w(u'%s&#160;' % self.previous_link(basepath, params))
         self.w(u'[&#160;%s&#160;]' % u'&#160;| '.join(blocklist))
-        self.w(u'&#160;%s' % self.next_link(params))
+        self.w(u'&#160;%s' % self.next_link(basepath, params))
         self.w(u'</div>')
 
 
--- a/web/views/tableview.py	Wed Aug 26 09:08:44 2009 +0200
+++ b/web/views/tableview.py	Wed Aug 26 13:09:19 2009 +0200
@@ -51,7 +51,7 @@
         """display a form to filter table's content. This should only
         occurs when a context eid is given
         """
-        self.req.add_js( ('cubicweb.ajax.js', 'cubicweb.formfilter.js'))
+        self.req.add_js( ('cubicweb.ajax.js', 'cubicweb.facets.js'))
         # 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="">' %
@@ -129,8 +129,7 @@
         # replace the inner div, so don't regenerate everything under the if
         # below
         if not fromformfilter:
-            div_class = 'section'
-            self.w(u'<div class="%s">' % div_class)
+            self.w(u'<div class="section">')
             if not title and 'title' in req.form:
                 title = req.form['title']
             if title: