changeset 3776:13241a4075e9 beta

Unified the paginators for pylons and YUI. - YUI based paginators now behave more like the ones generated with pylons - introduced new custom pylons paginator for customizations needed to unify both
author Marcin Kuzminski <marcin@python-works.com>
date Mon, 22 Apr 2013 14:11:40 +0200
parents 371898dc9a91
children 0b6982223baa
files rhodecode/controllers/admin/admin.py rhodecode/controllers/admin/notifications.py rhodecode/controllers/journal.py rhodecode/controllers/search.py rhodecode/lib/helpers.py rhodecode/public/css/style.css rhodecode/public/js/rhodecode.js rhodecode/templates/admin/repos/repos.html rhodecode/templates/admin/users/user_edit_my_account.html rhodecode/templates/index_base.html rhodecode/templates/journal/journal.html rhodecode/templates/journal/journal_data.html
diffstat 12 files changed, 449 insertions(+), 98 deletions(-) [+]
line wrap: on
line diff
--- a/rhodecode/controllers/admin/admin.py	Sun Apr 21 23:37:56 2013 +0200
+++ b/rhodecode/controllers/admin/admin.py	Mon Apr 22 14:11:40 2013 +0200
@@ -27,17 +27,17 @@
 
 from pylons import request, tmpl_context as c, url
 from sqlalchemy.orm import joinedload
-from webhelpers.paginate import Page
 from whoosh.qparser.default import QueryParser
+from whoosh.qparser.dateparse import DateParserPlugin
 from whoosh import query
 from sqlalchemy.sql.expression import or_, and_, func
 
+from rhodecode.model.db import UserLog, User
 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
 from rhodecode.lib.base import BaseController, render
-from rhodecode.model.db import UserLog, User
 from rhodecode.lib.utils2 import safe_int, remove_prefix, remove_suffix
 from rhodecode.lib.indexers import JOURNAL_SCHEMA
-from whoosh.qparser.dateparse import DateParserPlugin
+from rhodecode.lib.helpers import Page
 
 
 log = logging.getLogger(__name__)
--- a/rhodecode/controllers/admin/notifications.py	Sun Apr 21 23:37:56 2013 +0200
+++ b/rhodecode/controllers/admin/notifications.py	Mon Apr 22 14:11:40 2013 +0200
@@ -30,15 +30,13 @@
 from pylons import tmpl_context as c, url
 from pylons.controllers.util import redirect, abort
 
-from webhelpers.paginate import Page
-
+from rhodecode.model.db import Notification
+from rhodecode.model.notification import NotificationModel
+from rhodecode.model.meta import Session
+from rhodecode.lib.auth import LoginRequired, NotAnonymous
 from rhodecode.lib.base import BaseController, render
-from rhodecode.model.db import Notification
-
-from rhodecode.model.notification import NotificationModel
-from rhodecode.lib.auth import LoginRequired, NotAnonymous
 from rhodecode.lib import helpers as h
-from rhodecode.model.meta import Session
+from rhodecode.lib.helpers import Page
 from rhodecode.lib.utils2 import safe_int
 
 
--- a/rhodecode/controllers/journal.py	Sun Apr 21 23:37:56 2013 +0200
+++ b/rhodecode/controllers/journal.py	Mon Apr 22 14:11:40 2013 +0200
@@ -29,21 +29,21 @@
 from sqlalchemy.orm import joinedload
 from sqlalchemy.sql.expression import func
 
-from webhelpers.paginate import Page
 from webhelpers.feedgenerator import Atom1Feed, Rss201rev2Feed
 
 from webob.exc import HTTPBadRequest
 from pylons import request, tmpl_context as c, response, url
 from pylons.i18n.translation import _
 
+from rhodecode.controllers.admin.admin import _journal_filter
+from rhodecode.model.db import UserLog, UserFollowing, Repository, User
+from rhodecode.model.meta import Session
+from rhodecode.model.repo import RepoModel
 import rhodecode.lib.helpers as h
+from rhodecode.lib.helpers import Page
 from rhodecode.lib.auth import LoginRequired, NotAnonymous
 from rhodecode.lib.base import BaseController, render
-from rhodecode.model.db import UserLog, UserFollowing, Repository, User
-from rhodecode.model.meta import Session
 from rhodecode.lib.utils2 import safe_int, AttributeDict
-from rhodecode.controllers.admin.admin import _journal_filter
-from rhodecode.model.repo import RepoModel
 from rhodecode.lib.compat import json
 
 log = logging.getLogger(__name__)
--- a/rhodecode/controllers/search.py	Sun Apr 21 23:37:56 2013 +0200
+++ b/rhodecode/controllers/search.py	Mon Apr 22 14:11:40 2013 +0200
@@ -28,20 +28,18 @@
 from pylons.i18n.translation import _
 from pylons import request, config, tmpl_context as c
 
+from whoosh.index import open_dir, EmptyIndexError
+from whoosh.qparser import QueryParser, QueryParserError
+from whoosh.query import Phrase, Wildcard, Term, Prefix
+from webhelpers.util import update_params
+
 from rhodecode.lib.auth import LoginRequired
 from rhodecode.lib.base import BaseRepoController, render
 from rhodecode.lib.indexers import CHGSETS_SCHEMA, SCHEMA, CHGSET_IDX_NAME, \
     IDX_NAME, WhooshResultWrapper
-
-from webhelpers.paginate import Page
-from webhelpers.util import update_params
-
-from whoosh.index import open_dir, EmptyIndexError
-from whoosh.qparser import QueryParser, QueryParserError
-from whoosh.query import Phrase, Wildcard, Term, Prefix
 from rhodecode.model.repo import RepoModel
 from rhodecode.lib.utils2 import safe_str, safe_int
-
+from rhodecode.lib.helpers import Page
 
 log = logging.getLogger(__name__)
 
--- a/rhodecode/lib/helpers.py	Sun Apr 21 23:37:56 2013 +0200
+++ b/rhodecode/lib/helpers.py	Mon Apr 22 14:11:40 2013 +0200
@@ -36,7 +36,7 @@
     convert_misc_entities, lchop, plural, rchop, remove_formatting, \
     replace_whitespace, urlify, truncate, wrap_paragraphs
 from webhelpers.date import time_ago_in_words
-from webhelpers.paginate import Page
+from webhelpers.paginate import Page as _Page
 from webhelpers.html.tags import _set_input_attrs, _set_id_attr, \
     convert_boolean_attrs, NotGiven, _make_safe_id_component
 
@@ -809,6 +809,143 @@
     return gravatar_url
 
 
+class Page(_Page):
+    """
+    Custom pager to match rendering style with YUI paginator
+    """
+
+    def _get_pos(self, cur_page, max_page, items):
+        edge = (items / 2) + 1
+        if (cur_page <= edge):
+            radius = max(items / 2, items - cur_page)
+        elif (max_page - cur_page) < edge:
+            radius = (items - 1) - (max_page - cur_page)
+        else:
+            radius = items / 2
+
+        left = max(1, (cur_page - (radius)))
+        right = min(max_page, cur_page + (radius))
+        return left, cur_page, right
+
+    def _range(self, regexp_match):
+        """
+        Return range of linked pages (e.g. '1 2 [3] 4 5 6 7 8').
+
+        Arguments:
+
+        regexp_match
+            A "re" (regular expressions) match object containing the
+            radius of linked pages around the current page in
+            regexp_match.group(1) as a string
+
+        This function is supposed to be called as a callable in
+        re.sub.
+
+        """
+        radius = int(regexp_match.group(1))
+
+        # Compute the first and last page number within the radius
+        # e.g. '1 .. 5 6 [7] 8 9 .. 12'
+        # -> leftmost_page  = 5
+        # -> rightmost_page = 9
+        leftmost_page, _cur, rightmost_page = self._get_pos(self.page,
+                                                            self.last_page,
+                                                            (radius * 2) + 1)
+        nav_items = []
+
+        # Create a link to the first page (unless we are on the first page
+        # or there would be no need to insert '..' spacers)
+        if self.page != self.first_page and self.first_page < leftmost_page:
+            nav_items.append(self._pagerlink(self.first_page, self.first_page))
+
+        # Insert dots if there are pages between the first page
+        # and the currently displayed page range
+        if leftmost_page - self.first_page > 1:
+            # Wrap in a SPAN tag if nolink_attr is set
+            text = '..'
+            if self.dotdot_attr:
+                text = HTML.span(c=text, **self.dotdot_attr)
+            nav_items.append(text)
+
+        for thispage in xrange(leftmost_page, rightmost_page + 1):
+            # Hilight the current page number and do not use a link
+            if thispage == self.page:
+                text = '%s' % (thispage,)
+                # Wrap in a SPAN tag if nolink_attr is set
+                if self.curpage_attr:
+                    text = HTML.span(c=text, **self.curpage_attr)
+                nav_items.append(text)
+            # Otherwise create just a link to that page
+            else:
+                text = '%s' % (thispage,)
+                nav_items.append(self._pagerlink(thispage, text))
+
+        # Insert dots if there are pages between the displayed
+        # page numbers and the end of the page range
+        if self.last_page - rightmost_page > 1:
+            text = '..'
+            # Wrap in a SPAN tag if nolink_attr is set
+            if self.dotdot_attr:
+                text = HTML.span(c=text, **self.dotdot_attr)
+            nav_items.append(text)
+
+        # Create a link to the very last page (unless we are on the last
+        # page or there would be no need to insert '..' spacers)
+        if self.page != self.last_page and rightmost_page < self.last_page:
+            nav_items.append(self._pagerlink(self.last_page, self.last_page))
+
+        return self.separator.join(nav_items)
+
+    def pager(self, format='~2~', page_param='page', partial_param='partial',
+        show_if_single_page=False, separator=' ', onclick=None,
+        symbol_first='<<', symbol_last='>>',
+        symbol_previous='<', symbol_next='>',
+        link_attr={'class': 'pager_link'},
+        curpage_attr={'class': 'pager_curpage'},
+        dotdot_attr={'class': 'pager_dotdot'}, **kwargs):
+
+        self.curpage_attr = curpage_attr
+        self.separator = separator
+        self.pager_kwargs = kwargs
+        self.page_param = page_param
+        self.partial_param = partial_param
+        self.onclick = onclick
+        self.link_attr = link_attr
+        self.dotdot_attr = dotdot_attr
+
+        # Don't show navigator if there is no more than one page
+        if self.page_count == 0 or (self.page_count == 1 and not show_if_single_page):
+            return ''
+
+        from string import Template
+        # Replace ~...~ in token format by range of pages
+        result = re.sub(r'~(\d+)~', self._range, format)
+
+        # Interpolate '%' variables
+        result = Template(result).safe_substitute({
+            'first_page': self.first_page,
+            'last_page': self.last_page,
+            'page': self.page,
+            'page_count': self.page_count,
+            'items_per_page': self.items_per_page,
+            'first_item': self.first_item,
+            'last_item': self.last_item,
+            'item_count': self.item_count,
+            'link_first': self.page > self.first_page and \
+                    self._pagerlink(self.first_page, symbol_first) or '',
+            'link_last': self.page < self.last_page and \
+                    self._pagerlink(self.last_page, symbol_last) or '',
+            'link_previous': self.previous_page and \
+                    self._pagerlink(self.previous_page, symbol_previous) \
+                    or HTML.span(symbol_previous, class_="yui-pg-previous"),
+            'link_next': self.next_page and \
+                    self._pagerlink(self.next_page, symbol_next) \
+                    or HTML.span(symbol_next, class_="yui-pg-next")
+        })
+
+        return literal(result)
+
+
 #==============================================================================
 # REPO PAGER, PAGER FOR REPOSITORY
 #==============================================================================
--- a/rhodecode/public/css/style.css	Sun Apr 21 23:37:56 2013 +0200
+++ b/rhodecode/public/css/style.css	Mon Apr 22 14:11:40 2013 +0200
@@ -1591,7 +1591,7 @@
     border-radius: 4px 0px 0px 4px;
 }
 
-#content div.box div.pagination-wh > :last-child{
+#content div.box div.pagination-wh > :last-child {
     border-radius: 0px 4px 4px 0px;
     border-right: 1px solid #cfcfcf;
 }
--- a/rhodecode/public/js/rhodecode.js	Sun Apr 21 23:37:56 2013 +0200
+++ b/rhodecode/public/js/rhodecode.js	Mon Apr 22 14:11:40 2013 +0200
@@ -2207,6 +2207,289 @@
 }
 
 
+
+
+var YUI_paginator = function(links_per_page, containers){
+    // my custom paginator
+    (function () {
+
+        var Paginator = YAHOO.widget.Paginator,
+            l         = YAHOO.lang,
+            setId     = YAHOO.util.Dom.generateId;
+
+        Paginator.ui.MyFirstPageLink = function (p) {
+            this.paginator = p;
+
+            p.subscribe('recordOffsetChange',this.update,this,true);
+            p.subscribe('rowsPerPageChange',this.update,this,true);
+            p.subscribe('totalRecordsChange',this.update,this,true);
+            p.subscribe('destroy',this.destroy,this,true);
+
+            // TODO: make this work
+            p.subscribe('firstPageLinkLabelChange',this.update,this,true);
+            p.subscribe('firstPageLinkClassChange',this.update,this,true);
+        };
+
+        Paginator.ui.MyFirstPageLink.init = function (p) {
+            p.setAttributeConfig('firstPageLinkLabel', {
+                value : 1,
+                validator : l.isString
+            });
+            p.setAttributeConfig('firstPageLinkClass', {
+                value : 'yui-pg-first',
+                validator : l.isString
+            });
+            p.setAttributeConfig('firstPageLinkTitle', {
+                value : 'First Page',
+                validator : l.isString
+            });
+        };
+
+        // Instance members and methods
+        Paginator.ui.MyFirstPageLink.prototype = {
+            current   : null,
+            leftmost_page: null,
+            rightmost_page: null,
+            link      : null,
+            span      : null,
+            dotdot    : null,
+            getPos    : function(cur_page, max_page, items){
+                var edge = parseInt(items / 2) + 1;
+                if (cur_page <= edge){
+                    var radius = Math.max(parseInt(items / 2), items - cur_page);
+                }
+                else if ((max_page - cur_page) < edge) {
+                    var radius = (items - 1) - (max_page - cur_page);
+                }
+                else{
+                    var radius = parseInt(items / 2);
+                }
+
+                var left = Math.max(1, (cur_page - (radius)))
+                var right = Math.min(max_page, cur_page + (radius))
+                return [left, cur_page, right]
+            },
+            render : function (id_base) {
+                var p      = this.paginator,
+                    c      = p.get('firstPageLinkClass'),
+                    label  = p.get('firstPageLinkLabel'),
+                    title  = p.get('firstPageLinkTitle');
+
+                this.link     = document.createElement('a');
+                this.span     = document.createElement();
+
+                var _pos = this.getPos(p.getCurrentPage(), p.getTotalPages(), 5);
+                this.leftmost_page = _pos[0];
+                this.rightmost_page = _pos[2];
+
+                setId(this.link, id_base + '-first-link');
+                this.link.href      = '#';
+                this.link.className = c;
+                this.link.innerHTML = label;
+                this.link.title     = title;
+                YAHOO.util.Event.on(this.link,'click',this.onClick,this,true);
+
+                setId(this.span, id_base + '-first-span');
+                this.span.className = c;
+                this.span.innerHTML = label;
+
+                this.current = p.getCurrentPage() > 1 ? this.link : this.span;
+                return this.current;
+            },
+            update : function (e) {
+                var p      = this.paginator;
+                var _pos   = this.getPos(p.getCurrentPage(), p.getTotalPages(), 5);
+                this.leftmost_page = _pos[0];
+                this.rightmost_page = _pos[2];
+
+                if (e && e.prevValue === e.newValue) {
+                    return;
+                }
+
+                var par = this.current ? this.current.parentNode : null;
+                if (this.leftmost_page > 1) {
+                    if (par && this.current === this.span) {
+                        par.replaceChild(this.link,this.current);
+                        this.current = this.link;
+                    }
+                } else {
+                    if (par && this.current === this.link) {
+                        par.replaceChild(this.span,this.current);
+                        this.current = this.span;
+                    }
+                }
+            },
+            destroy : function () {
+                YAHOO.util.Event.purgeElement(this.link);
+                this.current.parentNode.removeChild(this.current);
+                this.link = this.span = null;
+            },
+            onClick : function (e) {
+                YAHOO.util.Event.stopEvent(e);
+                this.paginator.setPage(1);
+            }
+        };
+
+        })();
+    (function () {
+
+        var Paginator = YAHOO.widget.Paginator,
+            l         = YAHOO.lang,
+            setId     = YAHOO.util.Dom.generateId;
+
+        Paginator.ui.MyLastPageLink = function (p) {
+            this.paginator = p;
+
+            p.subscribe('recordOffsetChange',this.update,this,true);
+            p.subscribe('rowsPerPageChange',this.update,this,true);
+            p.subscribe('totalRecordsChange',this.update,this,true);
+            p.subscribe('destroy',this.destroy,this,true);
+
+            // TODO: make this work
+            p.subscribe('lastPageLinkLabelChange',this.update,this,true);
+            p.subscribe('lastPageLinkClassChange', this.update,this,true);
+        };
+
+        Paginator.ui.MyLastPageLink.init = function (p) {
+            p.setAttributeConfig('lastPageLinkLabel', {
+                value : -1,
+                validator : l.isString
+            });
+            p.setAttributeConfig('lastPageLinkClass', {
+                value : 'yui-pg-last',
+                validator : l.isString
+            });
+            p.setAttributeConfig('lastPageLinkTitle', {
+                value : 'Last Page',
+                validator : l.isString
+            });
+
+        };
+
+        Paginator.ui.MyLastPageLink.prototype = {
+
+            current   : null,
+            leftmost_page: null,
+            rightmost_page: null,
+            link      : null,
+            span      : null,
+            dotdot    : null,
+            na        : null,
+            getPos    : function(cur_page, max_page, items){
+                var edge = parseInt(items / 2) + 1;
+                if (cur_page <= edge){
+                    var radius = Math.max(parseInt(items / 2), items - cur_page);
+                }
+                else if ((max_page - cur_page) < edge) {
+                    var radius = (items - 1) - (max_page - cur_page);
+                }
+                else{
+                    var radius = parseInt(items / 2);
+                }
+
+                var left = Math.max(1, (cur_page - (radius)))
+                var right = Math.min(max_page, cur_page + (radius))
+                return [left, cur_page, right]
+            },
+            render : function (id_base) {
+                var p      = this.paginator,
+                    c      = p.get('lastPageLinkClass'),
+                    label  = p.get('lastPageLinkLabel'),
+                    last   = p.getTotalPages(),
+                    title  = p.get('lastPageLinkTitle');
+
+                var _pos = this.getPos(p.getCurrentPage(), p.getTotalPages(), 5);
+                this.leftmost_page = _pos[0];
+                this.rightmost_page = _pos[2];
+
+                this.link = document.createElement('a');
+                this.span = document.createElement();
+                this.na   = this.span.cloneNode(false);
+
+                setId(this.link, id_base + '-last-link');
+                this.link.href      = '#';
+                this.link.className = c;
+                this.link.innerHTML = label;
+                this.link.title     = title;
+                YAHOO.util.Event.on(this.link,'click',this.onClick,this,true);
+
+                setId(this.span, id_base + '-last-span');
+                this.span.className = c;
+                this.span.innerHTML = label;
+
+                setId(this.na, id_base + '-last-na');
+
+                if (this.rightmost_page < p.getTotalPages()){
+                    this.current = this.link;
+                }
+                else{
+                    this.current = this.span;
+                }
+
+                this.current.innerHTML = p.getTotalPages();
+                return this.current;
+            },
+
+            update : function (e) {
+                var p      = this.paginator;
+
+                var _pos = this.getPos(p.getCurrentPage(), p.getTotalPages(), 5);
+                this.leftmost_page = _pos[0];
+                this.rightmost_page = _pos[2];
+
+                if (e && e.prevValue === e.newValue) {
+                    return;
+                }
+
+                var par   = this.current ? this.current.parentNode : null,
+                    after = this.link;
+                if (par) {
+
+                    // only show the last page if the rightmost one is
+                    // lower, so we don't have doubled entries at the end
+                    if (!(this.rightmost_page < p.getTotalPages())){
+                        after = this.span
+                    }
+
+                    if (this.current !== after) {
+                        par.replaceChild(after,this.current);
+                        this.current = after;
+                    }
+                }
+                this.current.innerHTML = this.paginator.getTotalPages();
+
+            },
+            destroy : function () {
+                YAHOO.util.Event.purgeElement(this.link);
+                this.current.parentNode.removeChild(this.current);
+                this.link = this.span = null;
+            },
+            onClick : function (e) {
+                YAHOO.util.Event.stopEvent(e);
+                this.paginator.setPage(this.paginator.getTotalPages());
+            }
+        };
+
+        })();
+
+    var pagi = new YAHOO.widget.Paginator({
+        rowsPerPage: links_per_page,
+        alwaysVisible: false,
+        template : "{PreviousPageLink} {MyFirstPageLink} {PageLinks} {MyLastPageLink} {NextPageLink}",
+        pageLinks: 5,
+        containerClass: 'pagination-wh',
+        currentPageClass: 'pager_curpage',
+        pageLinkClass: 'pager_link',
+        nextPageLinkLabel: '&gt;',
+        previousPageLinkLabel: '&lt;',
+        containers:containers
+    })
+
+    return pagi
+}
+
+
+
 // global hooks after DOM is loaded
 
 YUE.onDOMReady(function(){
--- a/rhodecode/templates/admin/repos/repos.html	Sun Apr 21 23:37:56 2013 +0200
+++ b/rhodecode/templates/admin/repos/repos.html	Mon Apr 22 14:11:40 2013 +0200
@@ -79,20 +79,7 @@
 
   var myDataTable = new YAHOO.widget.DataTable("repos_list_wrap", myColumnDefs, myDataSource,{
     sortedBy:{key:"name",dir:"asc"},
-    paginator: new YAHOO.widget.Paginator({
-        rowsPerPage: 25,
-        alwaysVisible: false,
-        template : "{PreviousPageLink} {FirstPageLink} {PageLinks} {LastPageLink} {NextPageLink}",
-        pageLinks: 5,
-        containerClass: 'pagination-wh',
-        currentPageClass: 'pager_curpage',
-        pageLinkClass: 'pager_link',
-        nextPageLinkLabel: '&gt;',
-        previousPageLinkLabel: '&lt;',
-        firstPageLinkLabel: '&lt;&lt;',
-        lastPageLinkLabel: '&gt;&gt;',
-        containers:['user-paginator']
-    }),
+    paginator: YUI_paginator(25, ['user-paginator']),
 
     MSG_SORTASC:"${_('Click to sort ascending')}",
     MSG_SORTDESC:"${_('Click to sort descending')}",
--- a/rhodecode/templates/admin/users/user_edit_my_account.html	Sun Apr 21 23:37:56 2013 +0200
+++ b/rhodecode/templates/admin/users/user_edit_my_account.html	Mon Apr 22 14:11:40 2013 +0200
@@ -178,20 +178,7 @@
 
       var myDataTable = new YAHOO.widget.DataTable("repos_list_wrap", myColumnDefs, myDataSource,{
         sortedBy:{key:"name",dir:"asc"},
-        paginator: new YAHOO.widget.Paginator({
-            rowsPerPage: 50,
-            alwaysVisible: false,
-            template : "{PreviousPageLink} {FirstPageLink} {PageLinks} {LastPageLink} {NextPageLink}",
-            pageLinks: 5,
-            containerClass: 'pagination-wh',
-            currentPageClass: 'pager_curpage',
-            pageLinkClass: 'pager_link',
-            nextPageLinkLabel: '&gt;',
-            previousPageLinkLabel: '&lt;',
-            firstPageLinkLabel: '&lt;&lt;',
-            lastPageLinkLabel: '&gt;&gt;',
-            containers:['user-paginator']
-        }),
+        paginator: YUI_paginator(50, ['user-paginator']),
 
         MSG_SORTASC:"${_('Click to sort ascending')}",
         MSG_SORTDESC:"${_('Click to sort descending')}",
--- a/rhodecode/templates/index_base.html	Sun Apr 21 23:37:56 2013 +0200
+++ b/rhodecode/templates/index_base.html	Mon Apr 22 14:11:40 2013 +0200
@@ -131,20 +131,7 @@
 
         var myDataTable = new YAHOO.widget.DataTable("repos_list_wrap", myColumnDefs, myDataSource,{
           sortedBy:{key:"name",dir:"asc"},
-          paginator: new YAHOO.widget.Paginator({
-              rowsPerPage: ${c.visual.dashboard_items},
-              alwaysVisible: false,
-              template : "{PreviousPageLink} {FirstPageLink} {PageLinks} {LastPageLink} {NextPageLink}",
-              pageLinks: 5,
-              containerClass: 'pagination-wh',
-              currentPageClass: 'pager_curpage',
-              pageLinkClass: 'pager_link',
-              nextPageLinkLabel: '&gt;',
-              previousPageLinkLabel: '&lt;',
-              firstPageLinkLabel: '&lt;&lt;',
-              lastPageLinkLabel: '&gt;&gt;',
-              containers:['user-paginator']
-          }),
+          paginator: YUI_paginator(${c.visual.dashboard_items},['user-paginator']),
 
           MSG_SORTASC:"${_('Click to sort ascending')}",
           MSG_SORTDESC:"${_('Click to sort descending')}",
--- a/rhodecode/templates/journal/journal.html	Sun Apr 21 23:37:56 2013 +0200
+++ b/rhodecode/templates/journal/journal.html	Mon Apr 22 14:11:40 2013 +0200
@@ -199,20 +199,7 @@
 
         var myDataTable = new YAHOO.widget.DataTable("watched_repos_list_wrap", myColumnDefs, myDataSource,{
           sortedBy:{key:"name",dir:"asc"},
-          paginator: new YAHOO.widget.Paginator({
-              rowsPerPage: 25,
-              alwaysVisible: false,
-              template : "{PreviousPageLink} {FirstPageLink} {PageLinks} {LastPageLink} {NextPageLink}",
-              pageLinks: 5,
-              containerClass: 'pagination-wh',
-              currentPageClass: 'pager_curpage',
-              pageLinkClass: 'pager_link',
-              nextPageLinkLabel: '&gt;',
-              previousPageLinkLabel: '&lt;',
-              firstPageLinkLabel: '&lt;&lt;',
-              lastPageLinkLabel: '&gt;&gt;',
-              containers:['watched-user-paginator']
-          }),
+          paginator: YUI_paginator(25, ['watched-user-paginator']),
 
           MSG_SORTASC:"${_('Click to sort ascending')}",
           MSG_SORTDESC:"${_('Click to sort descending')}",
@@ -302,20 +289,7 @@
 
         var myDataTable = new YAHOO.widget.DataTable("repos_list_wrap", myColumnDefs, myDataSource,{
           sortedBy:{key:"name",dir:"asc"},
-          paginator: new YAHOO.widget.Paginator({
-              rowsPerPage: 25,
-              alwaysVisible: false,
-              template : "{PreviousPageLink} {FirstPageLink} {PageLinks} {LastPageLink} {NextPageLink}",
-              pageLinks: 5,
-              containerClass: 'pagination-wh',
-              currentPageClass: 'pager_curpage',
-              pageLinkClass: 'pager_link',
-              nextPageLinkLabel: '&gt;',
-              previousPageLinkLabel: '&lt;',
-              firstPageLinkLabel: '&lt;&lt;',
-              lastPageLinkLabel: '&gt;&gt;',
-              containers:['user-paginator']
-          }),
+          paginator: YUI_paginator(25, ['user-paginator']),
 
           MSG_SORTASC:"${_('Click to sort ascending')}",
           MSG_SORTDESC:"${_('Click to sort descending')}",
--- a/rhodecode/templates/journal/journal_data.html	Sun Apr 21 23:37:56 2013 +0200
+++ b/rhodecode/templates/journal/journal_data.html	Mon Apr 22 14:11:40 2013 +0200
@@ -34,9 +34,9 @@
             </div>
         %endfor
     %endfor
-  
+
   <div class="pagination-wh pagination-left" style="padding: 0px 0px 0px 10px;">
-  ${c.journal_pager.pager('$link_previous ~2~ $link_next')}  
+  ${c.journal_pager.pager('$link_previous ~2~ $link_next')}
   </div>
     <script type="text/javascript">
     YUE.onDOMReady(function(){
@@ -49,7 +49,7 @@
             YUE.preventDefault(e);
         },'.pager_link');
     });
-    </script>  
+    </script>
 %else:
   <div style="padding:5px 0px 10px 10px;">
       ${_('No entries yet')}