blob: 0a63ffe0ad7966b7bd4d7a3d40be46bd5d84e483 [file] [log] [blame]
// 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;
// }));