PageRenderTime 56ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/public/js/lib/backbone.paginator.js

https://bitbucket.org/AnuSekar/btree_pos
JavaScript | 1398 lines | 670 code | 152 blank | 576 comment | 258 complexity | fdb6602658ab4134a7acd29e84468506 MD5 | raw file
Possible License(s): Apache-2.0, BSD-3-Clause, MIT, MPL-2.0-no-copyleft-exception, GPL-2.0, GPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. backbone.paginator
  3. http://github.com/backbone-paginator/backbone.paginator
  4. Copyright (c) 2016 Jimmy Yuen Ho Wong and contributors
  5. @module
  6. @license MIT
  7. */
  8. (function (factory) {
  9. // CommonJS
  10. if (typeof exports == "object" && typeof require == "function") {
  11. module.exports = factory(require("underscore"), require("backbone"));
  12. }
  13. // AMD
  14. else if (typeof define == "function" && define.amd) {
  15. define(["underscore", "backbone"], factory);
  16. }
  17. // Browser
  18. else if (typeof _ !== "undefined" && typeof Backbone !== "undefined") {
  19. var oldPageableCollection = Backbone.PageableCollection;
  20. var PageableCollection = factory(_, Backbone);
  21. /**
  22. __BROWSER ONLY__
  23. If you already have an object named `PageableCollection` attached to the
  24. `Backbone` module, you can use this to return a local reference to this
  25. PageableCollection class and reset the name PageableCollection to its
  26. previous definition.
  27. // The left hand side gives you a reference to this
  28. // PageableCollection implementation, the right hand side
  29. // resets PageableCollection to your other PageableCollection.
  30. var PageableCollection = PageableCollection.noConflict();
  31. @static
  32. @return {PageableCollection}
  33. */
  34. Backbone.PageableCollection.noConflict = function () {
  35. Backbone.PageableCollection = oldPageableCollection;
  36. return PageableCollection;
  37. };
  38. }
  39. }(function (_, Backbone) {
  40. "use strict";
  41. var _extend = _.extend;
  42. var _omit = _.omit;
  43. var _clone = _.clone;
  44. var _each = _.each;
  45. var _pick = _.pick;
  46. var _contains = _.includes;
  47. var _isEmpty = _.isEmpty;
  48. var _pairs = _.pairs || _.toPairs;
  49. var _invert = _.invert;
  50. var _isArray = _.isArray;
  51. var _isFunction = _.isFunction;
  52. var _isObject = _.isObject;
  53. var _keys = _.keys;
  54. var _isUndefined = _.isUndefined;
  55. var ceil = Math.ceil;
  56. var floor = Math.floor;
  57. var max = Math.max;
  58. var BBColProto = Backbone.Collection.prototype;
  59. function finiteInt (val, name) {
  60. if (!_.isNumber(val) || _.isNaN(val) || !_.isFinite(val) || ~~val !== val) {
  61. throw new TypeError("`" + name + "` must be a finite integer");
  62. }
  63. return val;
  64. }
  65. function queryStringToParams (qs) {
  66. var kvp, k, v, ls, params = {}, decode = decodeURIComponent;
  67. var kvps = qs.split("&");
  68. for (var i = 0, l = kvps.length; i < l; i++) {
  69. var param = kvps[i];
  70. kvp = param.split("="), k = kvp[0], v = kvp[1];
  71. if (v == null) v = true;
  72. k = decode(k), v = decode(v), ls = params[k];
  73. if (_isArray(ls)) ls.push(v);
  74. else if (ls) params[k] = [ls, v];
  75. else params[k] = v;
  76. }
  77. return params;
  78. }
  79. // hack to make sure the whatever event handlers for this event is run
  80. // before func is, and the event handlers that func will trigger.
  81. function runOnceAtLastHandler (col, event, func) {
  82. var eventHandlers = col._events[event];
  83. if (eventHandlers && eventHandlers.length) {
  84. var lastHandler = eventHandlers[eventHandlers.length - 1];
  85. var oldCallback = lastHandler.callback;
  86. lastHandler.callback = function () {
  87. try {
  88. oldCallback.apply(this, arguments);
  89. func();
  90. }
  91. catch (e) {
  92. throw e;
  93. }
  94. finally {
  95. lastHandler.callback = oldCallback;
  96. }
  97. };
  98. }
  99. else func();
  100. }
  101. var PARAM_TRIM_RE = /[\s'"]/g;
  102. var URL_TRIM_RE = /[<>\s'"]/g;
  103. /**
  104. * State change event. Fired when PageableCollection#state gets updated
  105. *
  106. * @event pageable:state:change
  107. * @type {object} The PageableCollection#state object of this
  108. * PageableCollection instance
  109. */
  110. /**
  111. Drop-in replacement for Backbone.Collection. Supports server-side and
  112. client-side pagination and sorting. Client-side mode also support fully
  113. multi-directional synchronization of changes between pages.
  114. @class PageableCollection
  115. @extends Backbone.Collection
  116. */
  117. var PageableCollection = Backbone.PageableCollection = Backbone.Collection.extend({
  118. /**
  119. The container object to store all pagination states.
  120. You can override the default state by extending this class or specifying
  121. them in an `options` hash to the constructor.
  122. @property {number} firstPage = 1 - The first page index. Set to 0 if
  123. your server API uses 0-based indices. You should only override this value
  124. during extension, initialization or reset by the server after
  125. fetching. This value should be read only at other times.
  126. @property {number} lastPage = null - The last page index. This value
  127. is __read only__ and it's calculated based on whether `firstPage` is 0 or
  128. 1, during bootstrapping, fetching and resetting. Please don't change this
  129. value under any circumstances.
  130. @property {number} currentPage = null - The current page index. You
  131. should only override this value during extension, initialization or reset
  132. by the server after fetching. This value should be read only at other
  133. times. Can be a 0-based or 1-based index, depending on whether
  134. `firstPage` is 0 or 1. If left as default, it will be set to `firstPage`
  135. on initialization.
  136. @property {number} pageSize = 25 - How many records to show per
  137. page. This value is __read only__ after initialization, if you want to
  138. change the page size after initialization, you must call
  139. PageableCollection#setPageSize.
  140. @property {number} totalPages = null - How many pages there are. This
  141. value is __read only__ and it is calculated from `totalRecords`.
  142. @property {number} totalRecords = null - How many records there
  143. are. This value is __required__ under server mode. This value is optional
  144. for client mode as the number will be the same as the number of models
  145. during bootstrapping and during fetching, either supplied by the server
  146. in the metadata, or calculated from the size of the response.
  147. @property {string} sortKey = null - The model attribute to use for
  148. sorting.
  149. @property {number} order = -1 - The order to use for sorting. Specify
  150. -1 for ascending order or 1 for descending order. If 0, no client side
  151. sorting will be done and the order query parameter will not be sent to
  152. the server during a fetch.
  153. */
  154. state: {
  155. firstPage: 1,
  156. lastPage: null,
  157. currentPage: null,
  158. pageSize: 25,
  159. totalPages: null,
  160. totalRecords: null,
  161. sortKey: null,
  162. order: -1,
  163. type:null
  164. },
  165. /**
  166. @property {string} mode = "server" The mode of operations for this
  167. collection. `"server"` paginates on the server-side, `"client"` paginates
  168. on the client-side and `"infinite"` paginates on the server-side for APIs
  169. that do not support `totalRecords`.
  170. */
  171. mode: "server",
  172. /**
  173. A translation map to convert PageableCollection state attributes
  174. to the query parameters accepted by your server API.
  175. You can override the default state by extending this class or specifying
  176. them in `options.queryParams` object hash to the constructor.
  177. @property {string|function():string} currentPage = "page"
  178. @property {string|function():string} pageSize = "per_page"
  179. @property {string|function():string} totalPages = "total_pages"
  180. @property {string|function():string} totalRecords = "total_entries"
  181. @property {string|function():string} sortKey = "sort_by"
  182. @property {string|function():string} order = "order"
  183. @property {Object} directions = {"-1": "asc", "1": "desc"} - A map for
  184. translating a PageableCollection#state.order constant to the ones your
  185. server API accepts.
  186. */
  187. queryParams: {
  188. currentPage: "page",
  189. pageSize: "per_page",
  190. totalPages: "total_pages",
  191. totalRecords: "total_entries",
  192. sortKey: "sort_by",
  193. order: "order",
  194. directions: {
  195. "-1": "asc",
  196. "1": "desc"
  197. }
  198. },
  199. /**
  200. Given a list of models or model attributues, bootstraps the full
  201. collection in client mode or infinite mode, or just the page you want in
  202. server mode.
  203. If you want to initialize a collection to a different state than the
  204. default, you can specify them in `options.state`. Any state parameters
  205. supplied will be merged with the default. If you want to change the
  206. default mapping from PageableCollection#state keys to your server API's
  207. query parameter names, you can specifiy an object hash in
  208. `option.queryParams`. Likewise, any mapping provided will be merged with
  209. the default. Lastly, all Backbone.Collection constructor options are also
  210. accepted.
  211. See:
  212. - PageableCollection#state
  213. - PageableCollection#queryParams
  214. - [Backbone.Collection#initialize](http://backbonejs.org/#Collection-constructor)
  215. @constructor
  216. @property {Backbone.Collection} fullCollection - __CLIENT MODE ONLY__
  217. This collection is the internal storage for the bootstrapped or fetched
  218. models. You can use this if you want to operate on all the pages.
  219. @param {Array.<Object>} models
  220. @param {Object} options
  221. @param {function(*, *): number} options.comparator - If specified, this
  222. comparator is set to the current page under server mode, or the
  223. PageableCollection#fullCollection otherwise.
  224. @param {boolean} options.full 0 If `false` and either a
  225. `options.comparator` or `sortKey` is defined, the comparator is attached
  226. to the current page. Default is `true` under client or infinite mode and
  227. the comparator will be attached to the PageableCollection#fullCollection.
  228. @param {Object} options.state - The state attributes overriding the defaults.
  229. @param {string} options.state.sortKey - The model attribute to use for
  230. sorting. If specified instead of `options.comparator`, a comparator will
  231. be automatically created using this value, and optionally a sorting order
  232. specified in `options.state.order`. The comparator is then attached to
  233. the new collection instance.
  234. @param {number} options.state.order - The order to use for sorting. Specify
  235. -1 for ascending order and 1 for descending order.
  236. @param {Object} options.queryParam
  237. */
  238. constructor: function (models, options) {
  239. BBColProto.constructor.apply(this, arguments);
  240. options = options || {};
  241. var mode = this.mode = options.mode || this.mode || PageableProto.mode;
  242. var queryParams = _extend({}, PageableProto.queryParams, this.queryParams,
  243. options.queryParams || {});
  244. queryParams.directions = _extend({},
  245. PageableProto.queryParams.directions,
  246. this.queryParams.directions,
  247. queryParams.directions);
  248. this.queryParams = queryParams;
  249. var state = this.state = _extend({}, PageableProto.state, this.state,
  250. options.state);
  251. state.currentPage = state.currentPage == null ?
  252. state.firstPage :
  253. state.currentPage;
  254. if (!_isArray(models)) models = models ? [models] : [];
  255. models = models.slice();
  256. if (mode != "server" && state.totalRecords == null && !_isEmpty(models)) {
  257. // Can't use models.length naively here because Backbone.Collection will
  258. // dedupe by `idAttribute`
  259. state.totalRecords = this.length;
  260. }
  261. this.switchMode(mode, _extend({fetch: false,
  262. resetState: false,
  263. models: models}, options));
  264. var comparator = options.comparator;
  265. if (state.sortKey && !comparator) {
  266. this.setSorting(state.sortKey, state.order, options);
  267. }
  268. if (mode != "server") {
  269. var fullCollection = this.fullCollection;
  270. if (comparator && options.full) {
  271. this.comparator = null;
  272. fullCollection.comparator = comparator;
  273. }
  274. if (options.full) fullCollection.sort();
  275. // make sure the models in the current page and full collection have the
  276. // same references
  277. if (!_isEmpty(models)) {
  278. this.getPage(state.currentPage);
  279. }
  280. }
  281. this._initState = _clone(this.state);
  282. },
  283. /**
  284. Makes a Backbone.Collection that contains all the pages.
  285. @private
  286. @param {Array.<Object|Backbone.Model>} models
  287. @param {Object} options Options for Backbone.Collection constructor.
  288. @return {Backbone.Collection}
  289. */
  290. _makeFullCollection: function (models, options) {
  291. var properties = ["url", "model", "sync", "comparator"];
  292. var thisProto = this.constructor.prototype;
  293. var i, length, prop;
  294. var proto = {};
  295. for (i = 0, length = properties.length; i < length; i++) {
  296. prop = properties[i];
  297. if (!_isUndefined(thisProto[prop])) {
  298. proto[prop] = thisProto[prop];
  299. }
  300. }
  301. var fullCollection = new (Backbone.Collection.extend(proto))(models, options);
  302. for (i = 0, length = properties.length; i < length; i++) {
  303. prop = properties[i];
  304. if (this[prop] !== thisProto[prop]) {
  305. fullCollection[prop] = this[prop];
  306. }
  307. }
  308. return fullCollection;
  309. },
  310. /**
  311. Factory method that returns a Backbone event handler that responses to
  312. the `add`, `remove`, `reset`, and the `sort` events. The returned event
  313. handler will synchronize the current page collection and the full
  314. collection's models.
  315. @private
  316. @fires PageableCollection#pageable:state:change when handling an
  317. `add`, `remove`, or `reset` event
  318. @param {PageableCollection} pageCol
  319. @param {Backbone.Collection} fullCol
  320. @return {function(string, Backbone.Model, Backbone.Collection, Object)}
  321. Collection event handler
  322. */
  323. _makeCollectionEventHandler: function (pageCol, fullCol) {
  324. return function collectionEventHandler (event, model, collection, options) {
  325. var handlers = pageCol._handlers;
  326. _each(_keys(handlers), function (event) {
  327. var handler = handlers[event];
  328. pageCol.off(event, handler);
  329. fullCol.off(event, handler);
  330. });
  331. var state = _clone(pageCol.state);
  332. var firstPage = state.firstPage;
  333. var currentPage = firstPage === 0 ?
  334. state.currentPage :
  335. state.currentPage - 1;
  336. var pageSize = state.pageSize;
  337. var pageStart = currentPage * pageSize, pageEnd = pageStart + pageSize;
  338. if (event == "add") {
  339. var pageIndex, fullIndex, addAt, colToAdd, options = options || {};
  340. if (collection == fullCol) {
  341. fullIndex = fullCol.indexOf(model);
  342. if (fullIndex >= pageStart && fullIndex < pageEnd) {
  343. colToAdd = pageCol;
  344. pageIndex = addAt = fullIndex - pageStart;
  345. }
  346. }
  347. else {
  348. pageIndex = pageCol.indexOf(model);
  349. fullIndex = pageStart + pageIndex;
  350. colToAdd = fullCol;
  351. var addAt = !_isUndefined(options.at) ?
  352. options.at + pageStart :
  353. fullIndex;
  354. }
  355. if (!options.onRemove) {
  356. ++state.totalRecords;
  357. delete options.onRemove;
  358. }
  359. pageCol.state = pageCol._checkState(state);
  360. if (colToAdd) {
  361. colToAdd.add(model, _extend({}, options, {at: addAt}));
  362. var modelToRemove = pageIndex >= pageSize ?
  363. model :
  364. !_isUndefined(options.at) && addAt < pageEnd && pageCol.length > pageSize ?
  365. pageCol.at(pageSize) :
  366. null;
  367. if (modelToRemove) {
  368. runOnceAtLastHandler(collection, event, function () {
  369. pageCol.remove(modelToRemove, {onAdd: true});
  370. });
  371. }
  372. }
  373. if (!options.silent) pageCol.trigger("pageable:state:change", pageCol.state);
  374. }
  375. // remove the model from the other collection as well
  376. if (event == "remove") {
  377. if (!options.onAdd) {
  378. // decrement totalRecords and update totalPages and lastPage
  379. if (!--state.totalRecords) {
  380. state.totalRecords = null;
  381. state.totalPages = null;
  382. }
  383. else {
  384. var totalPages = state.totalPages = ceil(state.totalRecords / pageSize);
  385. state.lastPage = firstPage === 0 ? totalPages - 1 : totalPages || firstPage;
  386. if (state.currentPage > totalPages) state.currentPage = state.lastPage;
  387. }
  388. pageCol.state = pageCol._checkState(state);
  389. var nextModel, removedIndex = options.index;
  390. if (collection == pageCol) {
  391. if (nextModel = fullCol.at(pageEnd)) {
  392. runOnceAtLastHandler(pageCol, event, function () {
  393. pageCol.push(nextModel, {onRemove: true});
  394. });
  395. }
  396. else if (!pageCol.length && state.totalRecords) {
  397. pageCol.reset(fullCol.models.slice(pageStart - pageSize, pageEnd - pageSize),
  398. _extend({}, options, {parse: false}));
  399. }
  400. fullCol.remove(model);
  401. }
  402. else if (removedIndex >= pageStart && removedIndex < pageEnd) {
  403. if (nextModel = fullCol.at(pageEnd - 1)) {
  404. runOnceAtLastHandler(pageCol, event, function () {
  405. pageCol.push(nextModel, {onRemove: true});
  406. });
  407. }
  408. pageCol.remove(model);
  409. if (!pageCol.length && state.totalRecords) {
  410. pageCol.reset(fullCol.models.slice(pageStart - pageSize, pageEnd - pageSize),
  411. _extend({}, options, {parse: false}));
  412. }
  413. }
  414. }
  415. else delete options.onAdd;
  416. if (!options.silent) pageCol.trigger("pageable:state:change", pageCol.state);
  417. }
  418. if (event == "reset") {
  419. options = collection;
  420. collection = model;
  421. // Reset that's not a result of getPage
  422. if (collection == pageCol && options.from == null &&
  423. options.to == null) {
  424. var head = fullCol.models.slice(0, pageStart);
  425. var tail = fullCol.models.slice(pageStart + pageCol.models.length);
  426. fullCol.reset(head.concat(pageCol.models).concat(tail), options);
  427. }
  428. else if (collection == fullCol) {
  429. if (!(state.totalRecords = fullCol.models.length)) {
  430. state.totalRecords = null;
  431. state.totalPages = null;
  432. }
  433. if (pageCol.mode == "client") {
  434. firstPage = state.lastPage = state.currentPage = state.firstPage;
  435. currentPage = firstPage === 0 ? state.currentPage : state.currentPage - 1;
  436. pageStart = currentPage * pageSize;
  437. pageEnd = pageStart + pageSize;
  438. }
  439. pageCol.state = pageCol._checkState(state);
  440. pageCol.reset(fullCol.models.slice(pageStart, pageEnd),
  441. _extend({}, options, {parse: false}));
  442. }
  443. if (!options.silent) pageCol.trigger("pageable:state:change", pageCol.state);
  444. }
  445. if (event == "sort") {
  446. options = collection;
  447. collection = model;
  448. if (collection === fullCol) {
  449. pageCol.reset(fullCol.models.slice(pageStart, pageEnd),
  450. _extend({}, options, {parse: false}));
  451. }
  452. }
  453. _each(_keys(handlers), function (event) {
  454. var handler = handlers[event];
  455. _each([pageCol, fullCol], function (col) {
  456. col.on(event, handler);
  457. var callbacks = col._events[event] || [];
  458. callbacks.unshift(callbacks.pop());
  459. });
  460. });
  461. };
  462. },
  463. /**
  464. Sanity check this collection's pagination states. Only perform checks
  465. when all the required pagination state values are defined and not null.
  466. If `totalPages` is undefined or null, it is set to `totalRecords` /
  467. `pageSize`. `lastPage` is set according to whether `firstPage` is 0 or 1
  468. when no error occurs.
  469. @private
  470. @param {Object} state
  471. @throws {TypeError} If `totalRecords`, `pageSize`, `currentPage` or
  472. `firstPage` is not a finite integer.
  473. @throws {RangeError} If `pageSize`, `currentPage` or `firstPage` is out
  474. of bounds.
  475. @return {Object} Returns the `state` object if no error was found.
  476. */
  477. _checkState: function (state) {
  478. var mode = this.mode;
  479. var links = this.links;
  480. var totalRecords = state.totalRecords;
  481. var pageSize = state.pageSize;
  482. var currentPage = state.currentPage;
  483. var firstPage = state.firstPage;
  484. var totalPages = state.totalPages;
  485. if (totalRecords != null && pageSize != null && currentPage != null &&
  486. firstPage != null && (mode == "infinite" ? links : true)) {
  487. totalRecords = finiteInt(totalRecords, "totalRecords");
  488. pageSize = finiteInt(pageSize, "pageSize");
  489. currentPage = finiteInt(currentPage, "currentPage");
  490. firstPage = finiteInt(firstPage, "firstPage");
  491. if (pageSize < 1) {
  492. throw new RangeError("`pageSize` must be >= 1");
  493. }
  494. totalPages = state.totalPages = ceil(totalRecords / pageSize);
  495. if (firstPage < 0 || firstPage > 1) {
  496. throw new RangeError("`firstPage must be 0 or 1`");
  497. }
  498. state.lastPage = firstPage === 0 ? max(0, totalPages - 1) : totalPages || firstPage;
  499. if (mode == "infinite") {
  500. if (!links[currentPage]) {
  501. throw new RangeError("No link found for page " + currentPage);
  502. }
  503. }
  504. else if (currentPage < firstPage ||
  505. (totalPages > 0 &&
  506. (firstPage ? currentPage > totalPages : currentPage >= totalPages))) {
  507. throw new RangeError("`currentPage` must be firstPage <= currentPage " +
  508. (firstPage ? "<" : "<=") +
  509. " totalPages if " + firstPage + "-based. Got " +
  510. currentPage + ".");
  511. }
  512. }
  513. return state;
  514. },
  515. /**
  516. Change the page size of this collection.
  517. Under most if not all circumstances, you should call this method to
  518. change the page size of a pageable collection because it will keep the
  519. pagination state sane. By default, the method will recalculate the
  520. current page number to one that will retain the current page's models
  521. when increasing the page size. When decreasing the page size, this method
  522. will retain the last models to the current page that will fit into the
  523. smaller page size.
  524. If `options.first` is true, changing the page size will also reset the
  525. current page back to the first page instead of trying to be smart.
  526. For server mode operations, changing the page size will trigger a
  527. PageableCollection#fetch and subsequently a `reset` event.
  528. For client mode operations, changing the page size will `reset` the
  529. current page by recalculating the current page boundary on the client
  530. side.
  531. If `options.fetch` is true, a fetch can be forced if the collection is in
  532. client mode.
  533. @param {number} pageSize - The new page size to set to PageableCollection#state.
  534. @param {Object} options - {@link PageableCollection#fetch} options.
  535. @param {boolean} options.first = false 0 Reset the current page number to
  536. the first page if `true`.
  537. @param {boolean} options.fetch - If `true`, force a fetch in client mode.
  538. @throws {TypeError} If `pageSize` is not a finite integer.
  539. @throws {RangeError} If `pageSize` is less than 1.
  540. @chainable
  541. @return {XMLHttpRequest|PageableCollection} The XMLHttpRequest
  542. from fetch or this.
  543. */
  544. setPageSize: function (pageSize, options) {
  545. pageSize = finiteInt(pageSize, "pageSize");
  546. options = options || {first: false};
  547. var state = this.state;
  548. var totalPages = ceil(state.totalRecords / pageSize);
  549. var currentPage = totalPages ?
  550. max(state.firstPage, floor(totalPages * state.currentPage / state.totalPages)) :
  551. state.firstPage;
  552. state = this.state = this._checkState(_extend({}, state, {
  553. pageSize: pageSize,
  554. currentPage: options.first ? state.firstPage : currentPage,
  555. totalPages: totalPages
  556. }));
  557. return this.getPage(state.currentPage, _omit(options, ["first"]));
  558. },
  559. /**
  560. Switching between client, server and infinite mode.
  561. If switching from client to server mode, the #fullCollection is emptied
  562. first and then deleted and a fetch is immediately issued for the current
  563. page from the server. Pass `false` to `options.fetch` to skip fetching.
  564. If switching to infinite mode, and if `options.models` is given for an
  565. array of models,PageableCollection#links will be populated with a URL per
  566. page, using the default URL for this collection.
  567. If switching from server to client mode, all of the pages are immediately
  568. refetched. If you have too many pages, you can pass `false` to
  569. `options.fetch` to skip fetching.
  570. If switching to any mode from infinite mode, thePageableCollection#links
  571. will be deleted.
  572. @fires PageableCollection#pageable:state:change
  573. @param {"server"|"client"|"infinite"} mode - The mode to switch to.
  574. @param {Object} options
  575. @param {boolean} options.fetch = true - If `false`, no fetching is done.
  576. @param {boolean} options.resetState = true - If 'false', the state is not
  577. reset, but checked for sanity instead.
  578. @chainable
  579. @return {XMLHttpRequest|PageableCollection} The XMLHttpRequest
  580. from fetch or this if `options.fetch` is `false`.
  581. */
  582. switchMode: function (mode, options) {
  583. if (!_contains(["server", "client", "infinite"], mode)) {
  584. throw new TypeError('`mode` must be one of "server", "client" or "infinite"');
  585. }
  586. options = options || {fetch: true, resetState: true};
  587. var state = this.state = options.resetState ?
  588. _clone(this._initState) :
  589. this._checkState(_extend({}, this.state));
  590. this.mode = mode;
  591. var self = this;
  592. var fullCollection = this.fullCollection;
  593. var handlers = this._handlers = this._handlers || {}, handler;
  594. if (mode != "server" && !fullCollection) {
  595. fullCollection = this._makeFullCollection(options.models || [], options);
  596. fullCollection.pageableCollection = this;
  597. this.fullCollection = fullCollection;
  598. var allHandler = this._makeCollectionEventHandler(this, fullCollection);
  599. _each(["add", "remove", "reset", "sort"], function (event) {
  600. handlers[event] = handler = _.bind(allHandler, {}, event);
  601. self.on(event, handler);
  602. fullCollection.on(event, handler);
  603. });
  604. fullCollection.comparator = this._fullComparator;
  605. }
  606. else if (mode == "server" && fullCollection) {
  607. _each(_keys(handlers), function (event) {
  608. handler = handlers[event];
  609. self.off(event, handler);
  610. fullCollection.off(event, handler);
  611. });
  612. delete this._handlers;
  613. this._fullComparator = fullCollection.comparator;
  614. delete this.fullCollection;
  615. }
  616. if (mode == "infinite") {
  617. var links = this.links = {};
  618. var firstPage = state.firstPage;
  619. var totalPages = ceil(state.totalRecords / state.pageSize);
  620. var lastPage = firstPage === 0 ? max(0, totalPages - 1) : totalPages || firstPage;
  621. for (var i = state.firstPage; i <= lastPage; i++) {
  622. links[i] = this.url;
  623. }
  624. }
  625. else if (this.links) delete this.links;
  626. if (!options.silent) this.trigger("pageable:state:change", state);
  627. return options.fetch ?
  628. this.fetch(_omit(options, "fetch", "resetState")) :
  629. this;
  630. },
  631. /**
  632. @return {boolean} `true` if this collection can page backward, `false`
  633. otherwise.
  634. */
  635. hasPreviousPage: function () {
  636. var state = this.state;
  637. var currentPage = state.currentPage;
  638. if (this.mode != "infinite") return currentPage > state.firstPage;
  639. return !!this.links[currentPage - 1];
  640. },
  641. /**
  642. @return {boolean} `true` if this collection can page forward, `false`
  643. otherwise.
  644. */
  645. hasNextPage: function () {
  646. var state = this.state;
  647. var currentPage = this.state.currentPage;
  648. if (this.mode != "infinite") return currentPage < state.lastPage;
  649. return !!this.links[currentPage + 1];
  650. },
  651. /**
  652. Fetch the first page in server mode, or reset the current page of this
  653. collection to the first page in client or infinite mode.
  654. @param {Object} options {@linkPageableCollection#getPage} options.
  655. @chainable
  656. @return {XMLHttpRequest|PageableCollection} The XMLHttpRequest
  657. from fetch or this.
  658. */
  659. getFirstPage: function (options) {
  660. return this.getPage("first", options);
  661. },
  662. /**
  663. Fetch the previous page in server mode, or reset the current page of this
  664. collection to the previous page in client or infinite mode.
  665. @param {Object} options {@linkPageableCollection#getPage} options.
  666. @chainable
  667. @return {XMLHttpRequest|PageableCollection} The XMLHttpRequest
  668. from fetch or this.
  669. */
  670. getPreviousPage: function (options) {
  671. return this.getPage("prev", options);
  672. },
  673. /**
  674. Fetch the next page in server mode, or reset the current page of this
  675. collection to the next page in client mode.
  676. @param {Object} options {@linkPageableCollection#getPage} options.
  677. @chainable
  678. @return {XMLHttpRequest|PageableCollection} The XMLHttpRequest
  679. from fetch or this.
  680. */
  681. getNextPage: function (options) {
  682. return this.getPage("next", options);
  683. },
  684. /**
  685. Fetch the last page in server mode, or reset the current page of this
  686. collection to the last page in client mode.
  687. @param {Object} options {@linkPageableCollection#getPage} options.
  688. @chainable
  689. @return {XMLHttpRequest|PageableCollection} The XMLHttpRequest
  690. from fetch or this.
  691. */
  692. getLastPage: function (options) {
  693. return this.getPage("last", options);
  694. },
  695. /**
  696. Given a page index, set PageableCollection#state.currentPage to that
  697. index. If this collection is in server mode, fetch the page using the
  698. updated state, otherwise, reset the current page of this collection to
  699. the page specified by `index` in client mode. If `options.fetch` is true,
  700. a fetch can be forced in client mode before resetting the current
  701. page. Under infinite mode, if the index is less than the current page, a
  702. reset is done as in client mode. If the index is greater than the current
  703. page number, a fetch is made with the results **appended**
  704. toPageableCollection#fullCollection. The current page will then be reset
  705. after fetching.
  706. @fires PageableCollection#pageable:state:change
  707. @param {number|string} index - The page index to go to, or the page name to
  708. look up fromPageableCollection#links in infinite mode.
  709. @param {Object} options - {@linkPageableCollection#fetch} options or
  710. [reset](http://backbonejs.org/#Collection-reset) options for client mode
  711. when `options.fetch` is `false`.
  712. @param {boolean} options.fetch = false - If true, force a
  713. {@linkPageableCollection#fetch} in client mode.
  714. @throws {TypeError} If `index` is not a finite integer under server or
  715. client mode, or does not yield a URL fromPageableCollection#links under
  716. infinite mode.
  717. @throws {RangeError} If `index` is out of bounds.
  718. @chainable
  719. @return {XMLHttpRequest|PageableCollection} The XMLHttpRequest
  720. from fetch or this.
  721. */
  722. getPage: function (index, options) {
  723. var mode = this.mode, fullCollection = this.fullCollection;
  724. options = options || {fetch: false};
  725. var state = this.state,
  726. firstPage = state.firstPage,
  727. currentPage = state.currentPage,
  728. lastPage = state.lastPage,
  729. pageSize = state.pageSize;
  730. var pageNum = index;
  731. switch (index) {
  732. case "first": pageNum = firstPage; break;
  733. case "prev": pageNum = currentPage - 1; break;
  734. case "next": pageNum = currentPage + 1; break;
  735. case "last": pageNum = lastPage; break;
  736. default: pageNum = finiteInt(index, "index");
  737. }
  738. this.state = this._checkState(_extend({}, state, {currentPage: pageNum}));
  739. if (!options.silent) this.trigger("pageable:state:change", this.state);
  740. options.from = currentPage, options.to = pageNum;
  741. var pageStart = (firstPage === 0 ? pageNum : pageNum - 1) * pageSize;
  742. var pageModels = fullCollection && fullCollection.length ?
  743. fullCollection.models.slice(pageStart, pageStart + pageSize) :
  744. [];
  745. if ((mode == "client" || (mode == "infinite" && !_isEmpty(pageModels))) &&
  746. !options.fetch) {
  747. this.reset(pageModels, _omit(options, "fetch"));
  748. return this;
  749. }
  750. if (mode == "infinite") options.url = this.links[pageNum];
  751. console.log(options);
  752. return this.fetch(_omit(options, "fetch"));
  753. },
  754. /**
  755. Fetch the page for the provided item offset in server mode, or reset the
  756. current page of this collection to the page for the provided item offset
  757. in client mode.
  758. @param {number} offset
  759. @param {Object} options {@linkPageableCollection#getPage} options.
  760. @chainable
  761. @return {XMLHttpRequest|PageableCollection} The XMLHttpRequest
  762. from fetch or this.
  763. */
  764. getPageByOffset: function (offset, options) {
  765. if (offset < 0) {
  766. throw new RangeError("`offset must be > 0`");
  767. }
  768. offset = finiteInt(offset, "offset");
  769. var page = floor(offset / this.state.pageSize);
  770. if (this.state.firstPage !== 0) page++;
  771. if (page > this.state.lastPage) page = this.state.lastPage;
  772. return this.getPage(page, options);
  773. },
  774. /**
  775. Overidden to make `getPage` compatible with Zepto.
  776. @param {string} method
  777. @param {Backbone.Model|Backbone.Collection} model
  778. @param {Object} options
  779. @return {XMLHttpRequest}
  780. */
  781. sync: function (method, model, options) {
  782. var self = this;
  783. if (self.mode == "infinite") {
  784. var success = options.success;
  785. var currentPage = self.state.currentPage;
  786. options.success = function (resp, status, xhr) {
  787. var links = self.links;
  788. var newLinks = self.parseLinks(resp, _extend({xhr: xhr}, options));
  789. if (newLinks.first) links[self.state.firstPage] = newLinks.first;
  790. if (newLinks.prev) links[currentPage - 1] = newLinks.prev;
  791. if (newLinks.next) links[currentPage + 1] = newLinks.next;
  792. if (success) success(resp, status, xhr);
  793. };
  794. }
  795. return (BBColProto.sync || Backbone.sync).call(self, method, model, options);
  796. },
  797. /**
  798. Parse pagination links from the server response. Only valid under
  799. infinite mode.
  800. Given a response body and a XMLHttpRequest object, extract pagination
  801. links from them for infinite paging.
  802. This default implementation parses the RFC 5988 `Link` header and extract
  803. 3 links from it - `first`, `prev`, `next`. Any subclasses overriding this
  804. method __must__ return an object hash having only the keys
  805. above. However, simply returning a `next` link or an empty hash if there
  806. are no more links should be enough for most implementations.
  807. @param {*} resp The deserialized response body.
  808. @param {Object} options
  809. @param {XMLHttpRequest} options.xhr - The XMLHttpRequest object for this
  810. response.
  811. @return {Object}
  812. */
  813. parseLinks: function (resp, options) {
  814. var links = {};
  815. var linkHeader = options.xhr.getResponseHeader("Link");
  816. if (linkHeader) {
  817. var relations = ["first", "prev", "next"];
  818. _each(linkHeader.split(","), function (linkValue) {
  819. var linkParts = linkValue.split(";");
  820. var url = linkParts[0].replace(URL_TRIM_RE, "");
  821. var params = linkParts.slice(1);
  822. _each(params, function (param) {
  823. var paramParts = param.split("=");
  824. var key = paramParts[0].replace(PARAM_TRIM_RE, "");
  825. var value = paramParts[1].replace(PARAM_TRIM_RE, "");
  826. if (key == "rel" && _contains(relations, value)) links[value] = url;
  827. });
  828. });
  829. }
  830. return links;
  831. },
  832. /**
  833. Parse server response data.
  834. This default implementation assumes the response data is in one of two
  835. structures:
  836. [
  837. {}, // Your new pagination state
  838. [{}, ...] // An array of JSON objects
  839. ]
  840. Or,
  841. [{}] // An array of JSON objects
  842. The first structure is the preferred form because the pagination states
  843. may have been updated on the server side, sending them down again allows
  844. this collection to update its states. If the response has a pagination
  845. state object, it is checked for errors.
  846. The second structure is the
  847. [Backbone.Collection#parse](http://backbonejs.org/#Collection-parse)
  848. default.
  849. **Note:** this method has been further simplified since 1.1.7. While
  850. existingPageableCollection#parse implementations will continue to work,
  851. new code is encouraged to overridePageableCollection#parseState
  852. andPageableCollection#parseRecords instead.
  853. @fires PageableCollection#pageable:state:change
  854. @param {Object} resp The deserialized response data from the server.
  855. @param {Object} options The options for the ajax request
  856. @return {Array.<Object>} An array of model objects
  857. */
  858. parse: function (resp, options) {
  859. var newState = this.parseState(resp, _clone(this.queryParams), _clone(this.state), options);
  860. if (newState) {
  861. this.state = this._checkState(_extend({}, this.state, newState));
  862. if (!(options || {}).silent) this.trigger("pageable:state:change", this.state);
  863. }
  864. return this.parseRecords(resp, options);
  865. },
  866. /**
  867. Parse server response for server pagination state updates. Not applicable
  868. under infinite mode.
  869. This default implementation first checks whether the response has any
  870. state object as documented inPageableCollection#parse. If it exists, a
  871. state object is returned by mapping the server state keys to this
  872. pageable collection instance's query parameter keys using `queryParams`.
  873. It is __NOT__ neccessary to return a full state object complete with all
  874. the mappings defined inPageableCollection#queryParams. Any state object
  875. resulted is merged with a copy of the current pageable collection state
  876. and checked for sanity before actually updating. Most of the time, simply
  877. providing a new `totalRecords` value is enough to trigger a full
  878. pagination state recalculation.
  879. parseState: function (resp, queryParams, state, options) {
  880. return {totalRecords: resp.total_entries};
  881. }
  882. If you want to use header fields use:
  883. parseState: function (resp, queryParams, state, options) {
  884. return {totalRecords: options.xhr.getResponseHeader("X-total")};
  885. }
  886. This method __MUST__ return a new state object instead of directly
  887. modifying the PageableCollection#state object. The behavior of directly
  888. modifying PageableCollection#state is undefined.
  889. @param {Object} resp - The deserialized response data from the server.
  890. @param {Object} queryParams - A copy of PageableCollection#queryParams.
  891. @param {Object} state - A copy of PageableCollection#state.
  892. @param {Object} options - The options passed through from
  893. `parse`. (backbone >= 0.9.10 only)
  894. @return {Object} A new (partial) state object.
  895. */
  896. parseState: function (resp, queryParams, state, options) {
  897. if (resp && resp.length === 2 && _isObject(resp[0]) && _isArray(resp[1])) {
  898. var newState = _clone(state);
  899. var serverState = resp[0];
  900. _each(_pairs(_omit(queryParams, "directions")), function (kvp) {
  901. var k = kvp[0], v = kvp[1];
  902. var serverVal = serverState[v];
  903. if (!_isUndefined(serverVal) && !_.isNull(serverVal)) newState[k] = serverState[v];
  904. });
  905. if (serverState.order) {
  906. newState.order = _invert(queryParams.directions)[serverState.order] * 1;
  907. }
  908. return newState;
  909. }
  910. },
  911. /**
  912. Parse server response for an array of model objects.
  913. This default implementation first checks whether the response has any
  914. state object as documented inPageableCollection#parse. If it exists, the
  915. array of model objects is assumed to be the second element, otherwise the
  916. entire response is returned directly.
  917. @param {Object} resp - The deserialized response data from the server.
  918. @param {Object} options - The options passed through from the
  919. `parse`. (backbone >= 0.9.10 only)
  920. @return {Array.<Object>} An array of model objects
  921. */
  922. parseRecords: function (resp, options) {
  923. if (resp && resp.length === 2 && _isObject(resp[0]) && _isArray(resp[1])) {
  924. return resp[1];
  925. }
  926. return resp;
  927. },
  928. /**
  929. Fetch a page from the server in server mode, or all the pages in client
  930. mode. Under infinite mode, the current page is refetched by default and
  931. then reset.
  932. The query string is constructed by translating the current pagination
  933. state to your server API query parameter
  934. usingPageableCollection#queryParams. The current page will reset after
  935. fetch.
  936. @param {Object} options - Accepts all
  937. [Backbone.Collection#fetch](http://backbonejs.org/#Collection-fetch)
  938. options.
  939. @return {XMLHttpRequest}
  940. */
  941. fetch: function (options) {
  942. options = options || {};
  943. var state = this._checkState(this.state);
  944. var mode = this.mode;
  945. if (mode == "infinite" && !options.url) {
  946. options.url = this.links[state.currentPage];
  947. }
  948. console.log(options);
  949. console.log(appRouter.dateval);
  950. var data = options.data || {};
  951. if(appRouter.paginationtype == 'report' ){
  952. data.type = appRouter.dateval.type;
  953. data.reporttype = appRouter.dateval.reporttype;
  954. data.transtype = appRouter.dateval.transtype;
  955. data.reporttype = appRouter.dateval.reporttype;
  956. if(appRouter.dateval.discountrate != null || appRouter.dateval.discountrate != "" || appRouter.dateval.discountrate != undefined){
  957. data.discountrate = appRouter.dateval.discountrate;
  958. }
  959. if(appRouter.dateval.personid != null || appRouter.dateval.personid != "" || appRouter.dateval.personid != undefined){
  960. data.personid = appRouter.dateval.personid;
  961. }
  962. }
  963. // dedup query params
  964. var url = options.url || this.url || "";
  965. if (_isFunction(url)) url = url.call(this);
  966. var qsi = url.indexOf("?");
  967. if (qsi != -1) {
  968. _extend(data, queryStringToParams(url.slice(qsi + 1)));
  969. url = url.slice(0, qsi);
  970. }
  971. options.url = url;
  972. options.data = data;
  973. // pick the appropriate query param keys to map according to the mode
  974. var queryParams = this.mode == "client" ?
  975. _pick(this.queryParams, "sortKey") :
  976. _omit(_pick(this.queryParams, _keys(PageableProto.queryParams)),
  977. "order", "directions", "totalPages", "totalRecords");
  978. // map the query params to the data object used by the underlying ajax lib
  979. // to construct the query string
  980. _each(queryParams, function (v, k) {
  981. v = _isFunction(v) ? v.call(this) : v;
  982. if (state[k] != null && v != null && _.isUndefined(data[v])) {
  983. data[v] = state[k];
  984. }
  985. }, this);
  986. var sortKey = _isFunction(this.queryParams.sortKey) ?
  987. this.queryParams.sortKey.call(this) :
  988. this.queryParams.sortKey;
  989. var order = _isFunction(this.queryParams.order) ?
  990. this.queryParams.order.call(this) :
  991. this.queryParams.order;
  992. if (sortKey != null && state.sortKey != null &&
  993. order != null && state.order != null) {
  994. if (_isArray(state.order)) {
  995. data[order] = [];
  996. for (var i = 0; i < state.order.length; i++) {
  997. data[order].push(this.queryParams.directions[state.order[i]]);
  998. }
  999. }
  1000. else {
  1001. data[order] = this.queryParams.directions[state.order + ""];
  1002. }
  1003. }
  1004. // map extra query parameters
  1005. var extraKvps = _pairs(_omit(this.queryParams,
  1006. _keys(PageableProto.queryParams)));
  1007. for (var i = 0; i < extraKvps.length; i++) {
  1008. var kvp = extraKvps[i];
  1009. var v = kvp[1];
  1010. v = _isFunction(v) ? v.call(this) : v;
  1011. if (v != null) data[kvp[0]] = v;
  1012. }
  1013. if (mode != "server") {
  1014. var self = this, fullCol = this.fullCollection;
  1015. var success = options.success;
  1016. options.success = function (col, resp, opts) {
  1017. // make sure the caller's intent is obeyed
  1018. opts = opts || {};
  1019. if (_isUndefined(options.silent)) delete opts.silent;
  1020. else opts.silent = options.silent;
  1021. var models = col.models;
  1022. if (mode == "client") fullCol.reset(models, opts);
  1023. else {
  1024. fullCol.add(models, _extend({at: fullCol.length},
  1025. _extend(opts, {parse: false})));
  1026. self.trigger("reset", self, opts);
  1027. }
  1028. if (success) success(col, resp, opts);
  1029. };
  1030. // silent the first reset from backbone
  1031. return BBColProto.fetch.call(this, _extend({}, options, {silent: true}));
  1032. }
  1033. return BBColProto.fetch.call(this, options);
  1034. },
  1035. /**
  1036. Convenient method for making a `comparator` sorted by a model attribute
  1037. identified by `sortKey` and ordered by `order`.
  1038. Like a Backbone.Collection, a PageableCollection will maintain the
  1039. __current page__ in sorted order on the client side if a `comparator` is
  1040. attached to it. If the collection is in client mode, you can attach a
  1041. comparator toPageableCollection#fullCollection to have all the pages
  1042. reflect the global sorting order by specifying an option `full` to
  1043. `true`. You __must__ call `sort` manually
  1044. orPageableCollection#fullCollection.sort after calling this method to
  1045. force a resort.
  1046. While you can use this method to sort the current page in server mode,
  1047. the sorting order may not reflect the global sorting order due to the
  1048. additions or removals of the records on the server since the last
  1049. fetch. If you want the most updated page in a global sorting order, it is
  1050. recommended that you set PageableCollection#state.sortKey and optionally
  1051. PageableCollection#state.order, and then callPageableCollection#fetch.
  1052. @protected
  1053. @param {string} sortKey = this.state.sortKey - See `state.sortKey`.
  1054. @param {number} order = this.state.order - See `state.order`.
  1055. @param {(function(Backbone.Model, string): Object) | string} sortValue -
  1056. See PageableCollection#setSorting.
  1057. @return {function(Backbone.Model, string): number}
  1058. See [Backbone.Collection.comparator](http://backbonejs.org/#Collection-comparator).
  1059. */
  1060. _makeComparator: function (sortKey, order, sortValue) {
  1061. var state = this.state;
  1062. sortKey = sortKey || state.sortKey;
  1063. order = order || state.order;
  1064. if (!sortKey || !order) return;
  1065. if (!sortValue) {
  1066. sortValue = function (model, attr) {
  1067. return model.get(attr);
  1068. };
  1069. }
  1070. return function (left, right) {
  1071. var l = sortValue(left, sortKey), r = sortValue(right, sortKey), t;
  1072. if (order === 1) t = l, l = r, r = t;
  1073. if (l === r) return 0;
  1074. else if (l < r) return -1;
  1075. return 1;
  1076. };
  1077. },
  1078. /**
  1079. Adjusts the sorting for this pageable collection.
  1080. Given a `sortKey` and an `order`, sets `state.sortKey` and
  1081. `state.order`. A comparator can be applied on the client side to sort in
  1082. the order defined if `options.side` is `"client"`. By default the
  1083. comparator is applied to thePageableCollection#fullCollection. Set
  1084. `options.full` to `false` to apply a comparator to the current page under
  1085. any mode. Setting `sortKey` to `null` removes the comparator from both
  1086. the current page and the full collection.
  1087. If a `sortValue` function is given, it will be passed the `(model,
  1088. sortKey)` arguments and is used to extract a value from the model during
  1089. comparison sorts. If `sortValue` is not given, `model.get(sortKey)` is
  1090. used for sorting.
  1091. @chainable
  1092. @param {string} sortKey - See `state.sortKey`.
  1093. @param {number} order=thiā€¦

Large files files are truncated, but you can click here to view the full file