If you benefit from web2py hope you feel encouraged to pay it forward by contributing back to society in whatever form you choose!

Just put this code in the model:

class Scroller(object):

    def __init__(self, dbset, paginate=5, pages=5, container=None, content=None, contents=None,
        prev=None, next=None, first=None, last=None,
    **kw):
        """
        container (function):
        content (function):
        """
        self.paginate = paginate
        self.pages = pages if (pages==0 or pages%2>0) else pages+1
        self.prev = prev if not prev is None else SPAN("-", **{"aria-hidden": "true"})
        self.next = next if not next is None else SPAN("+", **{"aria-hidden": "true"})
        self.first = first if not first is None else SPAN(XML("«"), **{"aria-hidden": "true"})
        self.last = last if not last is None else SPAN(XML("»"), **{"aria-hidden": "true"})
        self.container = container
        self.content = content # DEPRECATED! Use contents instead
        self.contents = contents
        self.dbset = dbset
        self.pars = kw

    def _getlimits(self, tot, current_page=0):
        """ Returns current query limits """
        if tot>0:
            start = range(0, tot, self.paginate)[current_page]
            end = min(start+self.paginate, tot)
        else:
            start = 0
            end = 0

        return start, end

    def _container(self, *nodes):
        if self.container is None:
            return DIV(*nodes)
        else:
            return self.container(*nodes)

    def _contents(self, rows):
        if self.contents is None:
            return (BEAUTIFY(row) for row in rows)
        else:
            return self.contents(rows)

    def _content(self, row, n=0):
        """ DEPRECATED! Use contents instead """
        if self.content is None:
            return BEAUTIFY(row)
        else:
            return self.content(row, n)

    def progress(self, tot, current_page=0):
        """ """
        if tot>0:
            start, end = self._getlimits(tot, current_page)
            return DIV(T("Results from "), start+1, " to ", end, " of ", tot, _class="btn")
        else:
            return T("No results")


    def paginator(self, tot, current_page=0):
        """ Web ref: http://getbootstrap.com/components/#disabled-and-active-states """

        total_pages = (tot/self.paginate)
        if tot%self.paginate>0:
            total_pages += 1

        def _first():
            url = URL(args=request.args, vars=dict(page=0))
            return LI(A(self.first, _href=url, cid=request.cid))

        def _last():
            url = URL(args=request.args, vars=dict(page=total_pages-1))
            return LI(A(self.last, _href=url, cid=request.cid))

        def _prev():
            vars = {}
            if current_page == 0:
                vars["_class"] = "disabled"
                url = "#"
                return LI(A(self.prev), **vars)
            else:
                url = URL(args=request.args, vars=dict(page=current_page-1))
                return LI(A(self.prev, _href=url, cid=request.cid, **{"_aria-label": "Previous"}), **vars)

        def _next():
            vars = {}
            disabled = current_page >= tot/self.paginate
            if disabled:
                vars["_class"] = "disabled"
                url = "#"
                return LI(A(self.next), **vars)
            else:
                url = URL(args=request.args, vars=dict(page=current_page+1))
                return LI(A(self.next, _href=url, cid=request.cid, **{"_aria-label": "Next"}), **vars)

        def _li(page):
            vars = {}
            if page == current_page:
                vars["_class"] = "active"
                url = "#"
                contents = (page+1, SPAN("(current)", _class="sr-only"))
            else:
                url = URL(args=request.args, vars=dict(page=page))
                contents = (page+1,)
            return LI(A(*contents, _href=url, cid=request.cid), **vars)

        def _dots():
            return LI(A(XML("…"), _href="#", **{"_aria-label": "..."}), _class="disabled")

        elements = []

        start, end = self._getlimits(tot, current_page)

        complete_range = range(0, tot, self.paginate)

        if total_pages > self.pages and current_page >= self.pages:
            elements.append(_dots())

        if current_page < self.pages:
            _from = 0
            _to = min(self.pages, (tot/self.paginate))
        elif current_page>total_pages-self.pages:
            _from = total_pages-self.pages
            _to = total_pages
        else:
            _from = current_page-self.pages/2
            _to = current_page+1+self.pages/2

        if total_pages>self.pages and _from>self.pages:
            elements.append(_dots())

        for n,i in enumerate(complete_range[_from:_to]):
            elements.append(_li(_from+n))

        if total_pages>self.pages and _to < total_pages:
            elements.append(_dots())

        elements.insert(0, _prev())
        elements.insert(0, _first())
        elements.append(_next())
        elements.append(_last())

        return SPAN(TAG.nav(UL(*elements, _class="pagination pagination-sm")))

    def __call__(self):
        current_page = int(request.vars.page or 0)
        tot = self.dbset.count()
        start, end = self._getlimits(tot, current_page)
        self.pars["limitby"] = (start, end,)
        rows = self.dbset.select(**self.pars)
        paginator = self.paginator(tot, current_page)

        return DIV(
            DIV(
                DIV(self.progress(tot, current_page), _class="col-md-9"),
                DIV(paginator, _class="col-md-3"),
                _class="web2py_paginator row"),
#             DIV(self._container(*[self._content(row, n) for n,row in enumerate(rows)]), _class="web2py_table"),
            DIV(self._container(*self._contents(rows)), _class="web2py_table"),
            DIV(
                DIV(self.progress(tot, current_page), _class="col-md-9"),
                DIV(paginator, _class="col-md-3"),
                _class="web2py_paginator row"),
        _class="web2py_grid")

Now use it in a controller/view with something like:

{{=Scroller(dbset)()}}

Look the __init__ options for possible customizations

Related slices

Comments (0)


Hosting graciously provided by:
Python Anywhere