Commit 3a604418 authored by alexandre's avatar alexandre
Browse files

Added pagination on the list of scores

parent 8a4a7ee6
......@@ -6,10 +6,19 @@ window.W = window.W || {};
(function(undefined) {
'use strict';
W.ScoreCollection = Backbone.Collection.extend({
W.ScoreCollection = Backbone.PageableCollection.extend({
url: '/api/scores/',
model: W.ScoreModel
model: W.ScoreModel,
// see <http://borodaalex.blogspot.be/2016/02/pagination-and-filtering-with.html>
parseState: function (resp, queryParams, state, options) {
return {totalRecords: resp.count};
},
parseRecords: function (resp, options) {
return resp.results;
}
});
......
......@@ -1304,6 +1304,39 @@ window.W = window.W || {};
});
W.PaginationView = Backbone.Marionette.View.extend({
template: '#pagination-template',
templateContext: function() {
return {
currentPage: this.collection.state.currentPage,
lastPage: this.collection.state.lastPage,
hasPreviousPage: this.collection.hasPreviousPage(),
hasNextPage: this.collection.hasNextPage()
}
},
triggers: {
'click .next-page': 'nextPage',
'click .previous-page': 'previousPage',
},
onNextPage: function(event) {
this.collection.getNextPage();
console.log(this.collection.state)
},
onPreviousPage: function(event) {
this.collection.getPreviousPage();
console.log(this.collection.state)
},
initialize: function (options) {
this.listenTo(this.collection, 'sync', this.render);
},
});
W.CreateView = Backbone.Marionette.View.extend({
template: '#create-template',
......@@ -1334,17 +1367,40 @@ window.W = window.W || {};
regions: {
list: '#list',
pagination : '#pagination',
create: '#create'
},
onRender: function () {
document.title = 'Notation W';
var scoreCollection = new W.ScoreCollection();
var scoreCollection = new W.ScoreCollection([], {
// All the `state` and `queryParams` key value pairs are merged with
// the defaults too.
state: {
pageSize: 25,
firstPage: 1,
currentPage: 1
},
queryParams: {
currentPage: "page",
pageSize: "page_size",
totalRecords: "count"
},
});
window.sc = scoreCollection;
var myListView = new W.ListView({
collection: scoreCollection
});
var myPaginationView = new W.PaginationView({
collection: scoreCollection
});
var myCreateView = new W.CreateView();
var that = this;
......@@ -1352,6 +1408,7 @@ window.W = window.W || {};
myListView.collection.fetch({
success: function () {
that.showChildView('list', myListView);
that.showChildView('pagination', myPaginationView);
that.showChildView('create', myCreateView);
}
});
......
!function(e){if("object"==typeof exports&&"function"==typeof require)module.exports=e(require("underscore"),require("backbone"));else if("function"==typeof define&&define.amd)define(["underscore","backbone"],e);else if("undefined"!=typeof _&&"undefined"!=typeof Backbone){var t=Backbone.PageableCollection,r=e(_,Backbone);Backbone.PageableCollection.noConflict=function(){return Backbone.PageableCollection=t,r}}}(function(e,t){"use strict";function r(t,r){if(!e.isNumber(t)||e.isNaN(t)||!e.isFinite(t)||~~t!==t)throw new TypeError("`"+r+"` must be a finite integer");return t}function s(e){for(var t,r,s,a,i={},n=decodeURIComponent,o=e.split("&"),l=0,c=o.length;l<c;l++)r=(t=o[l].split("="))[0],null==(s=t[1])&&(s=!0),r=n(r),s=n(s),a=i[r],d(a)?a.push(s):i[r]=a?[a,s]:s;return i}function a(e,t,r){var s=e._events[t];if(s&&s.length){var a=s[s.length-1],i=a.callback;a.callback=function(){try{i.apply(this,arguments),r()}catch(e){throw e}finally{a.callback=i}}}else r()}var i=e.extend,n=e.omit,o=e.clone,l=e.each,c=e.pick,u=e.includes,h=e.isEmpty,f=e.pairs||e.toPairs,g=e.invert,d=e.isArray,P=e.isFunction,m=e.isObject,p=e.keys,v=e.isUndefined,y=Math.ceil,k=Math.floor,b=Math.max,S=t.Collection.prototype,_=/[\s'"]/g,R=/[<>\s'"]/g,C=t.PageableCollection=t.Collection.extend({state:{firstPage:1,lastPage:null,currentPage:null,pageSize:25,totalPages:null,totalRecords:null,sortKey:null,order:-1},mode:"server",queryParams:{currentPage:"page",pageSize:"per_page",totalPages:"total_pages",totalRecords:"total_entries",sortKey:"sort_by",order:"order",directions:{"-1":"asc",1:"desc"}},constructor:function(e,t){S.constructor.apply(this,arguments),t=t||{};var r=this.mode=t.mode||this.mode||q.mode,s=i({},q.queryParams,this.queryParams,t.queryParams||{});s.directions=i({},q.queryParams.directions,this.queryParams.directions,s.directions),this.queryParams=s;var a=this.state=i({},q.state,this.state,t.state);a.currentPage=null==a.currentPage?a.firstPage:a.currentPage,d(e)||(e=e?[e]:[]),e=e.slice(),"server"==r||null!=a.totalRecords||h(e)||(a.totalRecords=this.length),this.switchMode(r,i({fetch:!1,resetState:!1,models:e},t));var n=t.comparator;if(a.sortKey&&!n&&this.setSorting(a.sortKey,a.order,t),"server"!=r){var l=this.fullCollection;n&&t.full&&(this.comparator=null,l.comparator=n),t.full&&l.sort(),h(e)||this.getPage(a.currentPage)}this._initState=o(this.state)},_makeFullCollection:function(e,r){var s,a,i,n=["url","model","sync","comparator"],o=this.constructor.prototype,l={};for(s=0,a=n.length;s<a;s++)v(o[i=n[s]])||(l[i]=o[i]);var c=new(t.Collection.extend(l))(e,r);for(s=0,a=n.length;s<a;s++)this[i=n[s]]!==o[i]&&(c[i]=this[i]);return c},_makeCollectionEventHandler:function(e,t){return function(r,s,n,c){var u=e._handlers;l(p(u),function(r){var s=u[r];e.off(r,s),t.off(r,s)});var h=o(e.state),f=h.firstPage,g=0===f?h.currentPage:h.currentPage-1,d=h.pageSize,P=g*d,m=P+d;if("add"==r){var k,b,S,c=c||{};if(n==t)(b=t.indexOf(s))>=P&&b<m&&(S=e,k=_=b-P);else{b=P+(k=e.indexOf(s)),S=t;var _=v(c.at)?b:c.at+P}if(c.onRemove||(++h.totalRecords,delete c.onRemove),e.state=e._checkState(h),S){S.add(s,i({},c,{at:_}));var R=k>=d?s:!v(c.at)&&_<m&&e.length>d?e.at(d):null;R&&a(n,r,function(){e.remove(R,{onAdd:!0})})}c.silent||e.trigger("pageable:state:change",e.state)}if("remove"==r){if(c.onAdd)delete c.onAdd;else{if(--h.totalRecords){var C=h.totalPages=y(h.totalRecords/d);h.lastPage=0===f?C-1:C||f,h.currentPage>C&&(h.currentPage=h.lastPage)}else h.totalRecords=null,h.totalPages=null;e.state=e._checkState(h);var q,x=c.index;n==e?((q=t.at(m))?a(e,r,function(){e.push(q,{onRemove:!0})}):!e.length&&h.totalRecords&&e.reset(t.models.slice(P-d,m-d),i({},c,{parse:!1})),t.remove(s)):x>=P&&x<m&&((q=t.at(m-1))&&a(e,r,function(){e.push(q,{onRemove:!0})}),e.remove(s),!e.length&&h.totalRecords&&e.reset(t.models.slice(P-d,m-d),i({},c,{parse:!1})))}c.silent||e.trigger("pageable:state:change",e.state)}if("reset"==r){if(c=n,(n=s)==e&&null==c.from&&null==c.to){var w=t.models.slice(0,P),z=t.models.slice(P+e.models.length);t.reset(w.concat(e.models).concat(z),c)}else n==t&&((h.totalRecords=t.models.length)||(h.totalRecords=null,h.totalPages=null),"client"==e.mode&&(m=(P=(g=0===(f=h.lastPage=h.currentPage=h.firstPage)?h.currentPage:h.currentPage-1)*d)+d),e.state=e._checkState(h),e.reset(t.models.slice(P,m),i({},c,{parse:!1})));c.silent||e.trigger("pageable:state:change",e.state)}"sort"==r&&(c=n,(n=s)===t&&e.reset(t.models.slice(P,m),i({},c,{parse:!1}))),l(p(u),function(r){var s=u[r];l([e,t],function(e){e.on(r,s);var t=e._events[r]||[];t.unshift(t.pop())})})}},_checkState:function(e){var t=this.mode,s=this.links,a=e.totalRecords,i=e.pageSize,n=e.currentPage,o=e.firstPage,l=e.totalPages;if(null!=a&&null!=i&&null!=n&&null!=o&&("infinite"!=t||s)){if(a=r(a,"totalRecords"),i=r(i,"pageSize"),n=r(n,"currentPage"),o=r(o,"firstPage"),i<1)throw new RangeError("`pageSize` must be >= 1");if(l=e.totalPages=y(a/i),o<0||o>1)throw new RangeError("`firstPage must be 0 or 1`");if(e.lastPage=0===o?b(0,l-1):l||o,"infinite"==t){if(!s[n])throw new RangeError("No link found for page "+n)}else if(n<o||l>0&&(o?n>l:n>=l))throw new RangeError("`currentPage` must be firstPage <= currentPage "+(o?"<":"<=")+" totalPages if "+o+"-based. Got "+n+".")}return e},setPageSize:function(e,t){e=r(e,"pageSize"),t=t||{first:!1};var s=this.state,a=y(s.totalRecords/e),o=a?b(s.firstPage,k(a*s.currentPage/s.totalPages)):s.firstPage;return s=this.state=this._checkState(i({},s,{pageSize:e,currentPage:t.first?s.firstPage:o,totalPages:a})),this.getPage(s.currentPage,n(t,["first"]))},switchMode:function(t,r){if(!u(["server","client","infinite"],t))throw new TypeError('`mode` must be one of "server", "client" or "infinite"');r=r||{fetch:!0,resetState:!0};var s=this.state=r.resetState?o(this._initState):this._checkState(i({},this.state));this.mode=t;var a,c=this,h=this.fullCollection,f=this._handlers=this._handlers||{};if("server"==t||h)"server"==t&&h&&(l(p(f),function(e){a=f[e],c.off(e,a),h.off(e,a)}),delete this._handlers,this._fullComparator=h.comparator,delete this.fullCollection);else{(h=this._makeFullCollection(r.models||[],r)).pageableCollection=this,this.fullCollection=h;var g=this._makeCollectionEventHandler(this,h);l(["add","remove","reset","sort"],function(t){f[t]=a=e.bind(g,{},t),c.on(t,a),h.on(t,a)}),h.comparator=this._fullComparator}if("infinite"==t)for(var d=this.links={},P=s.firstPage,m=y(s.totalRecords/s.pageSize),v=0===P?b(0,m-1):m||P,k=s.firstPage;k<=v;k++)d[k]=this.url;else this.links&&delete this.links;return r.silent||this.trigger("pageable:state:change",s),r.fetch?this.fetch(n(r,"fetch","resetState")):this},hasPreviousPage:function(){var e=this.state,t=e.currentPage;return"infinite"!=this.mode?t>e.firstPage:!!this.links[t-1]},hasNextPage:function(){var e=this.state,t=this.state.currentPage;return"infinite"!=this.mode?t<e.lastPage:!!this.links[t+1]},getFirstPage:function(e){return this.getPage("first",e)},getPreviousPage:function(e){return this.getPage("prev",e)},getNextPage:function(e){return this.getPage("next",e)},getLastPage:function(e){return this.getPage("last",e)},getPage:function(e,t){var s=this.mode,a=this.fullCollection;t=t||{fetch:!1};var o=this.state,l=o.firstPage,c=o.currentPage,u=o.lastPage,f=o.pageSize,g=e;switch(e){case"first":g=l;break;case"prev":g=c-1;break;case"next":g=c+1;break;case"last":g=u;break;default:g=r(e,"index")}this.state=this._checkState(i({},o,{currentPage:g})),t.silent||this.trigger("pageable:state:change",this.state),t.from=c,t.to=g;var d=(0===l?g:g-1)*f,P=a&&a.length?a.models.slice(d,d+f):[];return"client"!=s&&("infinite"!=s||h(P))||t.fetch?("infinite"==s&&(t.url=this.links[g]),this.fetch(n(t,"fetch"))):(this.reset(P,n(t,"fetch")),this)},getPageByOffset:function(e,t){if(e<0)throw new RangeError("`offset must be > 0`");e=r(e,"offset");var s=k(e/this.state.pageSize);return 0!==this.state.firstPage&&s++,s>this.state.lastPage&&(s=this.state.lastPage),this.getPage(s,t)},sync:function(e,r,s){var a=this;if("infinite"==a.mode){var n=s.success,o=a.state.currentPage;s.success=function(e,t,r){var l=a.links,c=a.parseLinks(e,i({xhr:r},s));c.first&&(l[a.state.firstPage]=c.first),c.prev&&(l[o-1]=c.prev),c.next&&(l[o+1]=c.next),n&&n(e,t,r)}}return(S.sync||t.sync).call(a,e,r,s)},parseLinks:function(e,t){var r={},s=t.xhr.getResponseHeader("Link");if(s){var a=["first","prev","next"];l(s.split(","),function(e){var t=e.split(";"),s=t[0].replace(R,""),i=t.slice(1);l(i,function(e){var t=e.split("="),i=t[0].replace(_,""),n=t[1].replace(_,"");"rel"==i&&u(a,n)&&(r[n]=s)})})}return r},parse:function(e,t){var r=this.parseState(e,o(this.queryParams),o(this.state),t);return r&&(this.state=this._checkState(i({},this.state,r)),(t||{}).silent||this.trigger("pageable:state:change",this.state)),this.parseRecords(e,t)},parseState:function(t,r,s,a){if(t&&2===t.length&&m(t[0])&&d(t[1])){var i=o(s),c=t[0];return l(f(n(r,"directions")),function(t){var r=t[0],s=t[1],a=c[s];v(a)||e.isNull(a)||(i[r]=c[s])}),c.order&&(i.order=1*g(r.directions)[c.order]),i}},parseRecords:function(e,t){return e&&2===e.length&&m(e[0])&&d(e[1])?e[1]:e},fetch:function(t){t=t||{};var r=this._checkState(this.state),a=this.mode;"infinite"!=a||t.url||(t.url=this.links[r.currentPage]);var o=t.data||{},u=t.url||this.url||"";P(u)&&(u=u.call(this));var h=u.indexOf("?");-1!=h&&(i(o,s(u.slice(h+1))),u=u.slice(0,h)),t.url=u,t.data=o;var g="client"==this.mode?c(this.queryParams,"sortKey"):n(c(this.queryParams,p(q.queryParams)),"order","directions","totalPages","totalRecords");l(g,function(t,s){t=P(t)?t.call(this):t,null!=r[s]&&null!=t&&e.isUndefined(o[t])&&(o[t]=r[s])},this);var m=P(this.queryParams.sortKey)?this.queryParams.sortKey.call(this):this.queryParams.sortKey,y=P(this.queryParams.order)?this.queryParams.order.call(this):this.queryParams.order;if(null!=m&&null!=r.sortKey&&null!=y&&null!=r.order)if(d(r.order)){o[y]=[];for(b=0;b<r.order.length;b++)o[y].push(this.queryParams.directions[r.order[b]])}else o[y]=this.queryParams.directions[r.order+""];for(var k=f(n(this.queryParams,p(q.queryParams))),b=0;b<k.length;b++){var _=k[b],R=_[1];null!=(R=P(R)?R.call(this):R)&&(o[_[0]]=R)}if("server"!=a){var C=this,x=this.fullCollection,w=t.success;return t.success=function(e,r,s){s=s||{},v(t.silent)?delete s.silent:s.silent=t.silent;var n=e.models;"client"==a?x.reset(n,s):(x.add(n,i({at:x.length},i(s,{parse:!1}))),C.trigger("reset",C,s)),w&&w(e,r,s)},S.fetch.call(this,i({},t,{silent:!0}))}return S.fetch.call(this,t)},_makeComparator:function(e,t,r){var s=this.state;if(e=e||s.sortKey,t=t||s.order,e&&t)return r||(r=function(e,t){return e.get(t)}),function(s,a){var i,n=r(s,e),o=r(a,e);return 1===t&&(i=n,n=o,o=i),n===o?0:n<o?-1:1}},setSorting:function(e,t,r){var s=this.state;s.sortKey=e,s.order=t=t||s.order;var a=this.fullCollection,n=!1,o=!1;e||(n=o=!0);var l=this.mode;r=i({side:"client"==l?l:"server",full:!0},r);var c=this._makeComparator(e,t,r.sortValue),u=r.full,h=r.side;return"client"==h?u?(a&&(a.comparator=c),n=!0):(this.comparator=c,o=!0):"server"!=h||u||(this.comparator=c),n&&(this.comparator=null),o&&a&&(a.comparator=null),this}}),q=C.prototype;return C});
\ No newline at end of file
......@@ -15,6 +15,10 @@
{% include "playground/underscore/score-list.mtpl" %}
</script>
<script id="pagination-template" type="text/template">
{% include "playground/underscore/pagination.mtpl" %}
</script>
<script id="create-template" type="text/template">
{% include "playground/underscore/create.mtpl" %}
</script>
......@@ -76,6 +80,7 @@
<script src="{% static 'playground/vendors/backbone.radio.min.js' %}"></script>
<script src="{% static 'playground/vendors/backbone.marionette.min.js' %}"></script>
<script src="{% static 'playground/vendors/backbone-relational.min.js' %}"></script>
<script src="{% static 'playground/vendors/backbone.paginator.min.js' %}"></script>
<script src="{% static 'playground/vendors/jquery-ui.min.js' %}"></script>
<script src="{% static 'playground/vendors/jquery.mjs.nestedSortable.js' %}"></script>
<script src="{% static 'playground/js/models.js' %}"></script>
......@@ -87,4 +92,4 @@
<script src="{% static 'playground/js/main.js' %}"></script>
</body>
</html>
\ No newline at end of file
</html>
<% if (hasPreviousPage) { %>
<span class="previous-page">Previous</span>
<% } %>
| page <%= currentPage %> de <%= lastPage %> |
<% if (hasNextPage) { %>
<span class="next-page">Next</span>
<% } %>
<div id="list"></div>
<div id="pagination"></div>
<div id="create"></div>
from django.views.generic.base import TemplateView
from rest_framework import viewsets
from rest_framework.pagination import PageNumberPagination
from rest_framework.parsers import FormParser, MultiPartParser
from .models import Attachment, Score
from .serializers import AttachmentSerializer, ScoreSerializer
......@@ -15,12 +16,19 @@ class AttachmentViewSet(viewsets.ModelViewSet):
serializer.save(attachment=self.request.data.get('attachment'))
class ScoreViewSetPagination(PageNumberPagination):
# page_size = 10
page_size_query_param = 'page_size'
# max_page_size = 10000
class ScoreViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows users to be viewed or edited.
"""
queryset = Score.objects.all()
serializer_class = ScoreSerializer
pagination_class = ScoreViewSetPagination
class ScoreView(TemplateView):
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment