bootstrap-table-pipeline.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? factory(require('core-js/modules/es.array.concat.js'), require('core-js/modules/es.array.slice.js'), require('core-js/modules/es.object.assign.js'), require('core-js/modules/es.parse-int.js'), require('jquery')) :
  3. typeof define === 'function' && define.amd ? define(['core-js/modules/es.array.concat.js', 'core-js/modules/es.array.slice.js', 'core-js/modules/es.object.assign.js', 'core-js/modules/es.parse-int.js', 'jquery'], factory) :
  4. (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(null, null, null, null, global.jQuery));
  5. })(this, (function (es_array_concat_js, es_array_slice_js, es_object_assign_js, es_parseInt_js, $) { 'use strict';
  6. function _assertThisInitialized(e) {
  7. if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
  8. return e;
  9. }
  10. function _callSuper(t, o, e) {
  11. return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e));
  12. }
  13. function _classCallCheck(a, n) {
  14. if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function");
  15. }
  16. function _defineProperties(e, r) {
  17. for (var t = 0; t < r.length; t++) {
  18. var o = r[t];
  19. o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o);
  20. }
  21. }
  22. function _createClass(e, r, t) {
  23. return r && _defineProperties(e.prototype, r), Object.defineProperty(e, "prototype", {
  24. writable: !1
  25. }), e;
  26. }
  27. function _defineProperty(e, r, t) {
  28. return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
  29. value: t,
  30. enumerable: !0,
  31. configurable: !0,
  32. writable: !0
  33. }) : e[r] = t, e;
  34. }
  35. function _get() {
  36. return _get = "undefined" != typeof Reflect && Reflect.get ? Reflect.get.bind() : function (e, t, r) {
  37. var p = _superPropBase(e, t);
  38. if (p) {
  39. var n = Object.getOwnPropertyDescriptor(p, t);
  40. return n.get ? n.get.call(arguments.length < 3 ? e : r) : n.value;
  41. }
  42. }, _get.apply(null, arguments);
  43. }
  44. function _getPrototypeOf(t) {
  45. return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) {
  46. return t.__proto__ || Object.getPrototypeOf(t);
  47. }, _getPrototypeOf(t);
  48. }
  49. function _inherits(t, e) {
  50. if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function");
  51. t.prototype = Object.create(e && e.prototype, {
  52. constructor: {
  53. value: t,
  54. writable: !0,
  55. configurable: !0
  56. }
  57. }), Object.defineProperty(t, "prototype", {
  58. writable: !1
  59. }), e && _setPrototypeOf(t, e);
  60. }
  61. function _isNativeReflectConstruct() {
  62. try {
  63. var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
  64. } catch (t) {}
  65. return (_isNativeReflectConstruct = function () {
  66. return !!t;
  67. })();
  68. }
  69. function ownKeys(e, r) {
  70. var t = Object.keys(e);
  71. if (Object.getOwnPropertySymbols) {
  72. var o = Object.getOwnPropertySymbols(e);
  73. r && (o = o.filter(function (r) {
  74. return Object.getOwnPropertyDescriptor(e, r).enumerable;
  75. })), t.push.apply(t, o);
  76. }
  77. return t;
  78. }
  79. function _objectSpread2(e) {
  80. for (var r = 1; r < arguments.length; r++) {
  81. var t = null != arguments[r] ? arguments[r] : {};
  82. r % 2 ? ownKeys(Object(t), !0).forEach(function (r) {
  83. _defineProperty(e, r, t[r]);
  84. }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) {
  85. Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));
  86. });
  87. }
  88. return e;
  89. }
  90. function _possibleConstructorReturn(t, e) {
  91. if (e && ("object" == typeof e || "function" == typeof e)) return e;
  92. if (void 0 !== e) throw new TypeError("Derived constructors may only return object or undefined");
  93. return _assertThisInitialized(t);
  94. }
  95. function _setPrototypeOf(t, e) {
  96. return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) {
  97. return t.__proto__ = e, t;
  98. }, _setPrototypeOf(t, e);
  99. }
  100. function _superPropBase(t, o) {
  101. for (; !{}.hasOwnProperty.call(t, o) && null !== (t = _getPrototypeOf(t)););
  102. return t;
  103. }
  104. function _toPrimitive(t, r) {
  105. if ("object" != typeof t || !t) return t;
  106. var e = t[Symbol.toPrimitive];
  107. if (void 0 !== e) {
  108. var i = e.call(t, r );
  109. if ("object" != typeof i) return i;
  110. throw new TypeError("@@toPrimitive must return a primitive value.");
  111. }
  112. return (String )(t);
  113. }
  114. function _toPropertyKey(t) {
  115. var i = _toPrimitive(t, "string");
  116. return "symbol" == typeof i ? i : i + "";
  117. }
  118. /**
  119. * @author doug-the-guy
  120. * @update zhixin wen <wenzhixin2010@gmail.com>
  121. *
  122. * Bootstrap Table Pipeline
  123. * -----------------------
  124. *
  125. * This plugin enables client side data caching for server side requests which will
  126. * eliminate the need to issue a new request every page change. This will allow
  127. * for a performance balance for a large data set between returning all data at once
  128. * (client side paging) and a new server side request (server side paging).
  129. *
  130. * There are two new options:
  131. * - usePipeline: enables this feature
  132. * - pipelineSize: the size of each cache window
  133. *
  134. * The size of the pipeline must be evenly divisible by the current page size. This is
  135. * assured by rounding up to the nearest evenly divisible value. For example, if
  136. * the pipeline size is 4990 and the current page size is 25, then pipeline size will
  137. * be dynamically set to 5000.
  138. *
  139. * The cache windows are computed based on the pipeline size and the total number of rows
  140. * returned by the server side query. For example, with pipeline size 500 and total rows
  141. * 1300, the cache windows will be:
  142. *
  143. * [{'lower': 0, 'upper': 499}, {'lower': 500, 'upper': 999}, {'lower': 1000, 'upper': 1499}]
  144. *
  145. * Using the limit (i.e. the pipelineSize) and offset parameters, the server side request
  146. * **MUST** return only the data in the requested cache window **AND** the total number of rows.
  147. * To wit, the server side code must use the offset and limit parameters to prepare the response
  148. * data.
  149. *
  150. * On a page change, the new offset is checked if it is within the current cache window. If so,
  151. * the requested page data is returned from the cached data set. Otherwise, a new server side
  152. * request will be issued for the new cache window.
  153. *
  154. * The current cached data is only invalidated on these events:
  155. * * sorting
  156. * * searching
  157. * * page size change
  158. * * page change moves into a new cache window
  159. *
  160. * There are two new events:
  161. * - cached-data-hit.bs.table: issued when cached data is used on a page change
  162. * - cached-data-reset.bs.table: issued when the cached data is invalidated and a
  163. * new server side request is issued
  164. *
  165. **/
  166. var Utils = $.fn.bootstrapTable.utils;
  167. Object.assign($.fn.bootstrapTable.defaults, {
  168. usePipeline: false,
  169. pipelineSize: 1000,
  170. // eslint-disable-next-line no-unused-vars
  171. onCachedDataHit: function onCachedDataHit(data) {
  172. return false;
  173. },
  174. // eslint-disable-next-line no-unused-vars
  175. onCachedDataReset: function onCachedDataReset(data) {
  176. return false;
  177. }
  178. });
  179. Object.assign($.fn.bootstrapTable.events, {
  180. 'cached-data-hit.bs.table': 'onCachedDataHit',
  181. 'cached-data-reset.bs.table': 'onCachedDataReset'
  182. });
  183. $.BootstrapTable = /*#__PURE__*/function (_$$BootstrapTable) {
  184. function _class() {
  185. _classCallCheck(this, _class);
  186. return _callSuper(this, _class, arguments);
  187. }
  188. _inherits(_class, _$$BootstrapTable);
  189. return _createClass(_class, [{
  190. key: "init",
  191. value:
  192. // needs to be called before initServer
  193. function init() {
  194. var _get2;
  195. if (this.options.usePipeline) {
  196. this.initPipeline();
  197. }
  198. for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
  199. args[_key] = arguments[_key];
  200. }
  201. (_get2 = _get(_getPrototypeOf(_class.prototype), "init", this)).call.apply(_get2, [this].concat(args));
  202. }
  203. }, {
  204. key: "initPipeline",
  205. value: function initPipeline() {
  206. this.cacheRequestJSON = {};
  207. this.cacheWindows = [];
  208. this.currWindow = 0;
  209. this.resetCache = true;
  210. }
  211. // force a cache reset on search
  212. }, {
  213. key: "onSearch",
  214. value: function onSearch() {
  215. var _get3;
  216. if (this.options.usePipeline) {
  217. this.resetCache = true;
  218. }
  219. for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
  220. args[_key2] = arguments[_key2];
  221. }
  222. (_get3 = _get(_getPrototypeOf(_class.prototype), "onSearch", this)).call.apply(_get3, [this].concat(args));
  223. }
  224. // force a cache reset on sort
  225. }, {
  226. key: "onSort",
  227. value: function onSort() {
  228. var _get4;
  229. if (this.options.usePipeline) {
  230. this.resetCache = true;
  231. }
  232. for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
  233. args[_key3] = arguments[_key3];
  234. }
  235. (_get4 = _get(_getPrototypeOf(_class.prototype), "onSort", this)).call.apply(_get4, [this].concat(args));
  236. }
  237. // rebuild cache window on page size change
  238. }, {
  239. key: "onPageListChange",
  240. value: function onPageListChange(event) {
  241. var target = $(event.currentTarget);
  242. var newPageSize = parseInt(target.text(), 10);
  243. this.options.pipelineSize = this.calculatePipelineSize(this.options.pipelineSize, newPageSize);
  244. this.resetCache = true;
  245. _get(_getPrototypeOf(_class.prototype), "onPageListChange", this).call(this, event);
  246. }
  247. // calculate pipeline size by rounding up to
  248. // the nearest value evenly divisible by the pageSize
  249. }, {
  250. key: "calculatePipelineSize",
  251. value: function calculatePipelineSize(pipelineSize, pageSize) {
  252. if (pageSize === 0) {
  253. return 0;
  254. }
  255. return Math.ceil(pipelineSize / pageSize) * pageSize;
  256. }
  257. // set cache windows based on the total number of rows returned
  258. // by server side request and the pipelineSize
  259. }, {
  260. key: "setCacheWindows",
  261. value: function setCacheWindows() {
  262. this.cacheWindows = [];
  263. for (var i = 0; i <= this.options.totalRows / this.options.pipelineSize; i++) {
  264. var lower = i * this.options.pipelineSize;
  265. this.cacheWindows[i] = {
  266. lower: lower,
  267. upper: lower + this.options.pipelineSize - 1
  268. };
  269. }
  270. }
  271. // set the current cache window index, based on where the current offset falls
  272. }, {
  273. key: "setCurrWindow",
  274. value: function setCurrWindow(offset) {
  275. this.currWindow = 0;
  276. for (var i = 0; i < this.cacheWindows.length; i++) {
  277. if (this.cacheWindows[i].lower <= offset && offset <= this.cacheWindows[i].upper) {
  278. this.currWindow = i;
  279. break;
  280. }
  281. }
  282. }
  283. // draw rows from the cache using offset and limit
  284. }, {
  285. key: "drawFromCache",
  286. value: function drawFromCache(offset, limit) {
  287. var res = Utils.extend(true, {}, this.cacheRequestJSON);
  288. var drawStart = offset - this.cacheWindows[this.currWindow].lower;
  289. var drawEnd = drawStart + limit;
  290. res.rows = res.rows.slice(drawStart, drawEnd);
  291. return res;
  292. }
  293. /*
  294. * determine if requested data is in cache (on paging) or if
  295. * a new ajax request needs to be issued (sorting, searching, paging
  296. * moving outside of cached data, page size change)
  297. * initial version of this extension will entirely override base initServer
  298. */
  299. }, {
  300. key: "initServer",
  301. value: function initServer(silent, query, url) {
  302. var _this = this;
  303. if (!this.options.usePipeline) {
  304. return _get(_getPrototypeOf(_class.prototype), "initServer", this).call(this, silent, query, url);
  305. }
  306. var useAjax = true;
  307. var params = {};
  308. if (this.options.queryParamsType === 'limit' && this.options.pagination && this.options.sidePagination === 'server') {
  309. // same as parent initServer: params.offset
  310. params.offset = this.options.pageSize === this.options.formatAllRows() ? 0 : this.options.pageSize * (this.options.pageNumber - 1);
  311. params.limit = this.options.pageSize;
  312. // if cacheWindows is empty, this is the initial request
  313. if (!this.cacheWindows.length) {
  314. useAjax = true;
  315. params.drawOffset = params.offset;
  316. // cache exists: determine if the page request is entirely within the current cached window
  317. } else {
  318. var w = this.cacheWindows[this.currWindow];
  319. // case 1: reset cache but stay within current window (e.g. column sort)
  320. // case 2: move outside of the current window (e.g. search or paging)
  321. // since each cache window is aligned with the current page size
  322. // checking if params.offset is outside the current window is sufficient.
  323. // need to re-query for preceding or succeeding cache window
  324. // also handle case
  325. if (this.resetCache || params.offset < w.lower || params.offset > w.upper) {
  326. useAjax = true;
  327. this.setCurrWindow(params.offset);
  328. // store the relative offset for drawing the page data afterwards
  329. params.drawOffset = params.offset;
  330. // now set params.offset to the lower bound of the new cache window
  331. // the server will return that whole cache window
  332. params.offset = this.cacheWindows[this.currWindow].lower;
  333. // within current cache window
  334. } else {
  335. useAjax = false;
  336. }
  337. }
  338. }
  339. // force an ajax call - this is on search, sort or page size change
  340. if (this.resetCache) {
  341. useAjax = true;
  342. this.resetCache = false;
  343. }
  344. if (useAjax) {
  345. // in this scenario limit is used on the server to get the cache window
  346. // and drawLimit is used to get the page data afterwards
  347. params.drawLimit = params.limit;
  348. params.limit = this.options.pipelineSize;
  349. }
  350. // cached results can be used
  351. if (!useAjax) {
  352. var res = this.drawFromCache(params.offset, params.limit);
  353. this.load(res);
  354. this.trigger('load-success', res);
  355. this.trigger('cached-data-hit', res);
  356. return;
  357. }
  358. if (!this.pipelineResponseHandler) {
  359. this.pipelineResponseHandler = this.options.responseHandler;
  360. this.options.responseHandler = function (_res, jqXHR) {
  361. var res = Utils.calculateObjectValue(_this.options, _this.pipelineResponseHandler, [_res, jqXHR], _res);
  362. // store entire request in cache
  363. _this.cacheRequestJSON = Utils.extend(true, {}, res);
  364. // this gets set in load() also but needs to be set before
  365. // setting cacheWindows
  366. _this.options.totalRows = res[_this.options.totalField];
  367. // if this is a search, potentially less results will be returned
  368. // so cache windows need to be rebuilt. Otherwise it
  369. // will come out the same
  370. _this.setCacheWindows();
  371. // just load data for the page
  372. res = _this.drawFromCache(params.drawOffset, params.drawLimit);
  373. _this.trigger('cached-data-reset', res);
  374. return res;
  375. };
  376. }
  377. return _get(_getPrototypeOf(_class.prototype), "initServer", this).call(this, silent, _objectSpread2(_objectSpread2({}, query), params), url);
  378. }
  379. }, {
  380. key: "destroy",
  381. value: function destroy() {
  382. var _get5;
  383. this.options.responseHandler = this.pipelineResponseHandler;
  384. this.pipelineResponseHandler = null;
  385. for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {
  386. args[_key4] = arguments[_key4];
  387. }
  388. (_get5 = _get(_getPrototypeOf(_class.prototype), "destroy", this)).call.apply(_get5, [this].concat(args));
  389. }
  390. }]);
  391. }($.BootstrapTable);
  392. }));