[navigation] when there are to much results, use a <select> based page navigation stable
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Tue, 01 Jun 2010 12:19:01 +0200
branchstable
changeset 5615 cfa9a776d99a
parent 5614 37b31a7b8e74
child 5616 859225caf375
[navigation] when there are to much results, use a <select> based page navigation
selectors.py
web/views/navigation.py
--- a/selectors.py	Tue Jun 01 12:16:56 2010 +0200
+++ b/selectors.py	Tue Jun 01 12:19:01 2010 +0200
@@ -623,28 +623,35 @@
         return rset and self.match_expected(len(rset.rows[0])) or 0
 
 
-@objectify_selector
-@lltrace
-def paginated_rset(cls, req, rset=None, **kwargs):
-    """Return 1 for result set with more rows than a page size.
+class paginated_rset(Selector):
+    """Return 1 or more for result set with more rows than one or more page
+    size.  You can specify expected number of pages to the initializer (default
+    to one), and you'll get that number of pages as score if the result set is
+    big enough.
 
     Page size is searched in (respecting order):
     * a `page_size` argument
     * a `page_size` form parameters
     * the :ref:`navigation.page-size` property
     """
-    if rset is None:
-        return 0
-    page_size = kwargs.get('page_size')
-    if page_size is None:
-        page_size = req.form.get('page_size')
+    def __init__(self, nbpages=1):
+        assert nbpages > 0
+        self.nbpages = nbpages
+
+    @lltrace
+    def __call__(self, cls, req, rset=None, **kwargs):
+        if rset is None:
+            return 0
+        page_size = kwargs.get('page_size')
         if page_size is None:
-            page_size = req.property_value('navigation.page-size')
-        else:
-            page_size = int(page_size)
-    if rset.rowcount <= page_size:
-        return 0
-    return 1
+            page_size = req.form.get('page_size')
+            if page_size is None:
+                page_size = req.property_value('navigation.page-size')
+            else:
+                page_size = int(page_size)
+        if rset.rowcount <= (page_size*self.nbpages):
+            return 0
+        return self.nbpages
 
 
 @objectify_selector
--- a/web/views/navigation.py	Tue Jun 01 12:16:56 2010 +0200
+++ b/web/views/navigation.py	Tue Jun 01 12:19:01 2010 +0200
@@ -15,9 +15,8 @@
 #
 # You should have received a copy of the GNU Lesser General Public License along
 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
-"""navigation components definition for CubicWeb web client
+"""navigation components definition for CubicWeb web client"""
 
-"""
 __docformat__ = "restructuredtext en"
 _ = unicode
 
@@ -38,29 +37,52 @@
 
     def call(self):
         """displays a resultset by page"""
-        w = self.w
-        req = self._cw
+        params = dict(self._cw.form)
+        self.clean_params(params)
+        basepath = self._cw.relative_path(includeparams=False)
+        self.w(u'<div class="pagination">')
+        self.w(u'%s&#160;' % self.previous_link(basepath, params))
+        self.w(u'[&#160;%s&#160;]' %
+               u'&#160;| '.join(self.iter_page_links(basepath, params)))
+        self.w(u'&#160;%s' % self.next_link(basepath, params))
+        self.w(u'</div>')
+
+    def index_display(self, start, stop):
+        return u'%s - %s' % (start+1, stop+1)
+
+    def iter_page_links(self, basepath, params):
         rset = self.cw_rset
         page_size = self.page_size
         start = 0
-        blocklist = []
-        params = dict(req.form)
-        self.clean_params(params)
-        basepath = req.relative_path(includeparams=False)
         while start < rset.rowcount:
             stop = min(start + page_size - 1, rset.rowcount - 1)
-            blocklist.append(self.page_link(basepath, params, start, stop,
-                                            self.index_display(start, stop)))
+            yield self.page_link(basepath, params, start, stop,
+                                 self.index_display(start, stop))
             start = stop + 1
+
+
+class PageNavigationSelect(PageNavigation):
+    """displays a resultset by page as PageNavigationSelect but in a <select>,
+    better when there are a lot of results.
+    """
+    __select__ = paginated_rset(4)
+
+    page_link_templ = u'<option value="%s" title="%s">%s</option>'
+    selected_page_link_templ = u'<option value="%s" selected="selected" title="%s">%s</option>'
+    def call(self):
+        params = dict(self._cw.form)
+        self.clean_params(params)
+        basepath = self._cw.relative_path(includeparams=False)
+        w = self.w
         w(u'<div class="pagination">')
         w(u'%s&#160;' % self.previous_link(basepath, params))
-        w(u'[&#160;%s&#160;]' % u'&#160;| '.join(blocklist))
+        w(u'<select onchange="javascript: document.location=this.options[this.selectedIndex].value">')
+        for option in self.iter_page_links(basepath, params):
+            w(option)
+        w(u'</select>')
         w(u'&#160;%s' % self.next_link(basepath, params))
         w(u'</div>')
 
-    def index_display(self, start, stop):
-        return u'%s - %s' % (start+1, stop+1)
-
 
 class SortedNavigation(NavigationComponent):
     """sorted navigation apply if navigation is needed (according to page size)