assets/js/plugins/cloudant.pagingcollection.js (120 lines of code) (raw):

// Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. import _ from 'lodash'; import $ from 'jquery'; import Backbone from "backbone"; import app from '../../../app/app'; //PagingCollection //---------------- // A PagingCollection knows how to build appropriate requests to the // CouchDB-like server and how to fetch. The Collection will always contain a // single page of documents. export const PagingCollection = Backbone.Collection.extend({ // initialize parameters and page size constructor: function() { Backbone.Collection.apply(this, arguments); this.configure.apply(this, arguments); }, configure: function(collections, options) { var querystring = _.result(this, "url").split("?")[1] || ""; this.paging = _.defaults((options.paging || {}), { defaultParams: _.defaults({}, options.params, this._parseQueryString(querystring)), hasNext: false, hasPrevious: false, params: {}, pageSize: 20, direction: undefined }); this.paging.params = _.clone(this.paging.defaultParams); this.updateUrlQuery(this.paging.defaultParams); }, calculateParams: function(currentParams, skipIncrement, limitIncrement) { var params = _.clone(currentParams); params.skip = (parseInt(currentParams.skip, 10) || 0) + skipIncrement; // guard against hard limits if (this.paging.defaultParams.limit) { params.limit = Math.min(this.paging.defaultParams.limit, params.limit); } // request an extra row so we know that there are more results params.limit = limitIncrement + 1; // prevent illegal skip values params.skip = Math.max(params.skip, 0); return params; }, pageSizeReset: function(pageSize, opts) { var options = _.defaults((opts || {}), {fetch: true}); this.paging.direction = undefined; this.paging.pageSize = pageSize; this.paging.params = this.paging.defaultParams; this.paging.params.limit = pageSize; this.updateUrlQuery(this.paging.params); if (options.fetch) { return this.fetch(); } }, _parseQueryString: function(uri) { var queryString = decodeURI(uri).split(/&/); return _.reduce(queryString, function (parsedQuery, item) { var nameValue = item.split(/=/); if (nameValue.length === 2) { parsedQuery[nameValue[0]] = nameValue[1]; } return parsedQuery; }, {}); }, _iterate: function(offset, opts) { var options = _.defaults((opts || {}), {fetch: true}); this.paging.params = this.calculateParams(this.paging.params, offset, this.paging.pageSize); // Fetch the next page of documents this.updateUrlQuery(this.paging.params); if (options.fetch) { return this.fetch({reset: true}); } }, // `next` is called with the number of items for the next page. // It returns the fetch promise. next: function(options) { this.paging.direction = "next"; return this._iterate(this.paging.pageSize, options); }, // `previous` is called with the number of items for the previous page. // It returns the fetch promise. previous: function(options) { this.paging.direction = "previous"; return this._iterate(0 - this.paging.pageSize, options); }, shouldStringify: function (val) { try { JSON.parse(val); return false; } catch (e) { return true; } }, // Encodes the parameters so that couchdb will understand them // and then sets the url with the new url. updateUrlQuery: function (params) { var url = _.result(this, "url").split("?")[0]; _.each(['startkey', 'endkey', 'key'], (key) => { if (_.has(params, key) && this.shouldStringify(params[key])) { params[key] = JSON.stringify(params[key]); } }); this.url = url + '?' + app.utils.queryParams(params); }, fetch: function () { // if this is a fetch for the first time, fetch one extra to see if there is a next if (!this.paging.direction && this.paging.params.limit > 0) { this.paging.direction = 'fetch'; this.paging.params.limit = this.paging.params.limit + 1; this.updateUrlQuery(this.paging.params); } return Backbone.Collection.prototype.fetch.apply(this, arguments); }, parse: function (resp) { var rows = resp.rows; this.paging.hasNext = this.paging.hasPrevious = false; this.viewMeta = { total_rows: resp.total_rows, offset: resp.offset, update_seq: resp.update_seq }; if (this.paging.params.skip > 0) { this.paging.hasPrevious = true; } if (rows.length === this.paging.pageSize + 1) { this.paging.hasNext = true; // remove the next page marker result rows.pop(); this.viewMeta.total_rows = this.viewMeta.total_rows - 1; } return rows; }, hasNext: function() { return this.paging.hasNext; }, hasPrevious: function() { return this.paging.hasPrevious; } }); export default PagingCollection; // if (exports) { // // Overload the Backbone.ajax method, this allows PagingCollection to be able to // // work in node.js // exports.setAjax = function (ajax) { // Backbone.ajax = ajax; // }; // exports.PagingCollection = PagingCollection; // } // return PagingCollection; // }));