otsdaq_utilities  v2_05_02_indev
page.js
1 var Page = function(table){
2 
3  this.table = table; //hold Tabulator object
4 
5  this.mode = "local";
6  this.progressiveLoad = false;
7 
8  this.size = 0;
9  this.page = 1;
10  this.count = 5;
11  this.max = 1;
12 
13  this.displayIndex = 0; //index in display pipeline
14 
15  this.pageSizes = [];
16 
17  this.createElements();
18 };
19 
20 Page.prototype.createElements = function(){
21 
22  var button;
23 
24  this.element = document.createElement("span");
25  this.element.classList.add("tabulator-paginator");
26 
27  this.pagesElement = document.createElement("span");
28  this.pagesElement.classList.add("tabulator-pages");
29 
30  button = document.createElement("button");
31  button.classList.add("tabulator-page");
32  button.setAttribute("type", "button");
33  button.setAttribute("role", "button");
34  button.setAttribute("aria-label", "");
35  button.setAttribute("title", "");
36 
37  this.firstBut = button.cloneNode(true);
38  this.firstBut.setAttribute("data-page", "first");
39 
40  this.prevBut = button.cloneNode(true);
41  this.prevBut.setAttribute("data-page", "prev");
42 
43  this.nextBut = button.cloneNode(true);
44  this.nextBut.setAttribute("data-page", "next");
45 
46  this.lastBut = button.cloneNode(true);
47  this.lastBut.setAttribute("data-page", "last");
48 
49  if(this.table.options.paginationSizeSelector){
50  this.pageSizeSelect = document.createElement("select");
51  this.pageSizeSelect.classList.add("tabulator-page-size");
52  }
53 
54 };
55 
56 Page.prototype.generatePageSizeSelectList = function(){
57  var pageSizes = [];
58 
59  if(this.pageSizeSelect){
60 
61  if(Array.isArray(this.table.options.paginationSizeSelector)){
62  pageSizes = this.table.options.paginationSizeSelector;
63  this.pageSizes = pageSizes;
64 
65  if(this.pageSizes.indexOf(this.size) == -1){
66  pageSizes.unshift(this.size);
67  }
68  }else{
69 
70  if(this.pageSizes.indexOf(this.size) == -1){
71  pageSizes = [];
72 
73  for (let i = 1; i < 5; i++){
74  pageSizes.push(this.size * i);
75  }
76 
77  this.pageSizes = pageSizes;
78  }else{
79  pageSizes = this.pageSizes;
80  }
81  }
82 
83  while(this.pageSizeSelect.firstChild) this.pageSizeSelect.removeChild(this.pageSizeSelect.firstChild);
84 
85  pageSizes.forEach((item) => {
86  var itemEl = document.createElement("option");
87  itemEl.value = item;
88  itemEl.innerHTML = item;
89 
90  this.pageSizeSelect.appendChild(itemEl);
91  });
92 
93  this.pageSizeSelect.value = this.size;
94  }
95 };
96 
97 //setup pageination
98 Page.prototype.initialize = function(hidden){
99  var self = this,
100  pageSelectLabel;
101 
102  //update param names
103  for(let key in self.table.options.paginationDataSent){
104  self.paginationDataSentNames[key] = self.table.options.paginationDataSent[key];
105  }
106 
107  for(let key in self.table.options.paginationDataReceived){
108  self.paginationDataReceivedNames[key] = self.table.options.paginationDataReceived[key];
109  }
110 
111  //build pagination element
112 
113  //bind localizations
114  self.table.modules.localize.bind("pagination|first", function(value){
115  self.firstBut.innerHTML = value;
116  });
117 
118  self.table.modules.localize.bind("pagination|first_title", function(value){
119  self.firstBut.setAttribute("aria-label", value);
120  self.firstBut.setAttribute("title", value);
121  });
122 
123  self.table.modules.localize.bind("pagination|prev", function(value){
124  self.prevBut.innerHTML = value;
125  });
126 
127  self.table.modules.localize.bind("pagination|prev_title", function(value){
128  self.prevBut.setAttribute("aria-label", value);
129  self.prevBut.setAttribute("title", value);
130  });
131 
132  self.table.modules.localize.bind("pagination|next", function(value){
133  self.nextBut.innerHTML = value;
134  });
135 
136  self.table.modules.localize.bind("pagination|next_title", function(value){
137  self.nextBut.setAttribute("aria-label", value);
138  self.nextBut.setAttribute("title", value);
139  });
140 
141  self.table.modules.localize.bind("pagination|last", function(value){
142  self.lastBut.innerHTML = value;
143  });
144 
145  self.table.modules.localize.bind("pagination|last_title", function(value){
146  self.lastBut.setAttribute("aria-label", value);
147  self.lastBut.setAttribute("title", value);
148  });
149 
150  //click bindings
151  self.firstBut.addEventListener("click", function(){
152  self.setPage(1);
153  });
154 
155  self.prevBut.addEventListener("click", function(){
156  self.previousPage();
157  });
158 
159  self.nextBut.addEventListener("click", function(){
160  self.nextPage().then(()=>{}).catch(()=>{});
161  });
162 
163  self.lastBut.addEventListener("click", function(){
164  self.setPage(self.max);
165  });
166 
167  if(self.table.options.paginationElement){
168  self.element = self.table.options.paginationElement;
169  }
170 
171  if(this.pageSizeSelect){
172  pageSelectLabel = document.createElement("label");
173 
174  self.table.modules.localize.bind("pagination|page_size", function(value){
175  self.pageSizeSelect.setAttribute("aria-label", value);
176  self.pageSizeSelect.setAttribute("title", value);
177  pageSelectLabel.innerHTML = value;
178  });
179 
180  self.element.appendChild(pageSelectLabel);
181  self.element.appendChild(self.pageSizeSelect);
182 
183  self.pageSizeSelect.addEventListener("change", function(e){
184  self.setPageSize(self.pageSizeSelect.value)
185  self.setPage(1).then(()=>{}).catch(()=>{});
186  });
187  }
188 
189  //append to DOM
190  self.element.appendChild(self.firstBut);
191  self.element.appendChild(self.prevBut);
192  self.element.appendChild(self.pagesElement);
193  self.element.appendChild(self.nextBut);
194  self.element.appendChild(self.lastBut);
195 
196  if(!self.table.options.paginationElement && !hidden){
197  self.table.footerManager.append(self.element, self);
198  }
199 
200  //set default values
201  self.mode = self.table.options.pagination;
202 
203  self.size = self.table.options.paginationSize || Math.floor(self.table.rowManager.getElement().clientHeight / 24);
204  // self.page = self.table.options.paginationInitialPage || 1;
205  self.count = self.table.options.paginationButtonCount;
206 
207  self.generatePageSizeSelectList();
208 };
209 
210 Page.prototype.initializeProgressive = function(mode){
211  this.initialize(true);
212  this.mode = "progressive_" + mode;
213  this.progressiveLoad = true;
214 };
215 
216 Page.prototype.setDisplayIndex = function(index){
217  this.displayIndex = index;
218 };
219 
220 Page.prototype.getDisplayIndex = function(){
221  return this.displayIndex;
222 };
223 
224 
225 //calculate maximum page from number of rows
226 Page.prototype.setMaxRows = function(rowCount){
227  if(!rowCount){
228  this.max = 1;
229  }else{
230  this.max = Math.ceil(rowCount/this.size);
231  }
232 
233  if(this.page > this.max){
234  this.page = this.max;
235  }
236 };
237 
238 //reset to first page without triggering action
239 Page.prototype.reset = function(force){
240  if(this.mode == "local" || force){
241  this.page = 1;
242  }
243  return true;
244 };
245 
246 //set the maxmum page
247 Page.prototype.setMaxPage = function(max){
248 
249  max = parseInt(max);
250 
251  this.max = max || 1;
252 
253  if(this.page > this.max){
254  this.page = this.max;
255  this.trigger();
256  }
257 };
258 
259 //set current page number
260 Page.prototype.setPage = function(page){
261  var self = this;
262 
263  return new Promise((resolve, reject)=>{
264 
265  page = parseInt(page);
266 
267  if(page > 0 && page <= this.max){
268  this.page = page;
269  this.trigger()
270  .then(()=>{
271  resolve();
272  })
273  .catch(()=>{
274  reject();
275  });
276 
277  if(self.table.options.persistence && self.table.modExists("persistence", true) && self.table.modules.persistence.config.page){
278  self.table.modules.persistence.save("page");
279  }
280 
281  }else{
282  console.warn("Pagination Error - Requested page is out of range of 1 - " + this.max + ":", page);
283  reject();
284  }
285  });
286 };
287 
288 Page.prototype.setPageToRow = function(row){
289 
290  return new Promise((resolve, reject)=>{
291 
292  var rows = this.table.rowManager.getDisplayRows(this.displayIndex - 1);
293  var index = rows.indexOf(row);
294 
295  if(index > -1){
296  var page = Math.ceil((index + 1) / this.size);
297 
298  this.setPage(page)
299  .then(()=>{
300  resolve();
301  })
302  .catch(()=>{
303  reject();
304  });
305  }else{
306  console.warn("Pagination Error - Requested row is not visible");
307  reject();
308  }
309  });
310 };
311 
312 
313 Page.prototype.setPageSize = function(size){
314  size = parseInt(size);
315 
316  if(size > 0){
317  this.size = size;
318  }
319 
320  if(this.pageSizeSelect){
321  // this.pageSizeSelect.value = size;
322  this.generatePageSizeSelectList();
323  }
324 
325  if(this.table.options.persistence && this.table.modExists("persistence", true) && this.table.modules.persistence.config.page){
326  this.table.modules.persistence.save("page");
327  }
328 };
329 
330 
331 //setup the pagination buttons
332 Page.prototype._setPageButtons = function(){
333  var self = this;
334 
335  let leftSize = Math.floor((this.count-1) / 2);
336  let rightSize = Math.ceil((this.count-1) / 2);
337  let min = this.max - this.page + leftSize + 1 < this.count ? this.max-this.count+1: Math.max(this.page-leftSize,1);
338  let max = this.page <= rightSize? Math.min(this.count, this.max) :Math.min(this.page+rightSize, this.max);
339 
340  while(self.pagesElement.firstChild) self.pagesElement.removeChild(self.pagesElement.firstChild);
341 
342  if(self.page == 1){
343  self.firstBut.disabled = true;
344  self.prevBut.disabled = true;
345  }else{
346  self.firstBut.disabled = false;
347  self.prevBut.disabled = false;
348  }
349 
350  if(self.page == self.max){
351  self.lastBut.disabled = true;
352  self.nextBut.disabled = true;
353  }else{
354  self.lastBut.disabled = false;
355  self.nextBut.disabled = false;
356  }
357 
358  for(let i = min; i <= max; i++){
359  if(i>0 && i <= self.max){
360  self.pagesElement.appendChild(self._generatePageButton(i));
361  }
362  }
363 
364  this.footerRedraw();
365 };
366 
367 Page.prototype._generatePageButton = function(page){
368  var self = this,
369  button = document.createElement("button");
370 
371  button.classList.add("tabulator-page");
372  if(page == self.page){
373  button.classList.add("active");
374  }
375 
376  button.setAttribute("type", "button");
377  button.setAttribute("role", "button");
378  button.setAttribute("aria-label", "Show Page " + page);
379  button.setAttribute("title", "Show Page " + page);
380  button.setAttribute("data-page", page);
381  button.textContent = page;
382 
383  button.addEventListener("click", function(e){
384  self.setPage(page);
385  });
386 
387  return button;
388 };
389 
390 //previous page
391 Page.prototype.previousPage = function(){
392  return new Promise((resolve, reject)=>{
393  if(this.page > 1){
394  this.page--;
395  this.trigger()
396  .then(()=>{
397  resolve();
398  })
399  .catch(()=>{
400  reject();
401  });
402  }else{
403  console.warn("Pagination Error - Previous page would be less than page 1:", 0);
404  reject()
405  }
406  });
407 };
408 
409 //next page
410 Page.prototype.nextPage = function(){
411  return new Promise((resolve, reject)=>{
412  if(this.page < this.max){
413  this.page++;
414  this.trigger()
415  .then(()=>{
416  resolve();
417  })
418  .catch(()=>{
419  reject();
420  });
421  }else{
422  if(!this.progressiveLoad){
423  console.warn("Pagination Error - Next page would be greater than maximum page of " + this.max + ":", this.max + 1);
424  }
425  reject();
426  }
427  });
428 };
429 
430 //return current page number
431 Page.prototype.getPage = function(){
432  return this.page;
433 };
434 
435 //return max page number
436 Page.prototype.getPageMax = function(){
437  return this.max;
438 };
439 
440 Page.prototype.getPageSize = function(size){
441  return this.size;
442 };
443 
444 Page.prototype.getMode = function(){
445  return this.mode;
446 };
447 
448 //return appropriate rows for current page
449 Page.prototype.getRows = function(data){
450  var output, start, end;
451 
452  if(this.mode == "local"){
453  output = [];
454  start = this.size * (this.page - 1);
455  end = start + parseInt(this.size);
456 
457  this._setPageButtons();
458 
459  for(let i = start; i < end; i++){
460  if(data[i]){
461  output.push(data[i]);
462  }
463  }
464 
465  return output;
466  }else{
467 
468  this._setPageButtons();
469 
470  return data.slice(0);
471  }
472 };
473 
474 Page.prototype.trigger = function(){
475  var left;
476 
477  return new Promise((resolve, reject)=>{
478 
479  switch(this.mode){
480  case "local":
481  left = this.table.rowManager.scrollLeft;
482 
483  this.table.rowManager.refreshActiveData("page");
484  this.table.rowManager.scrollHorizontal(left);
485 
486  this.table.options.pageLoaded.call(this.table, this.getPage());
487  resolve();
488  break;
489 
490  case "remote":
491  case "progressive_load":
492  case "progressive_scroll":
493  this.table.modules.ajax.blockActiveRequest();
494  this._getRemotePage()
495  .then(()=>{
496  resolve();
497  })
498  .catch(()=>{
499  reject();
500  });
501  break;
502 
503  default:
504  console.warn("Pagination Error - no such pagination mode:", this.mode);
505  reject();
506  }
507  });
508 };
509 
510 Page.prototype._getRemotePage = function(){
511  var self = this,
512  oldParams, pageParams;
513 
514 
515  return new Promise((resolve, reject)=>{
516 
517  if(!self.table.modExists("ajax", true)){
518  reject()
519  }
520 
521  //record old params and restore after request has been made
522  oldParams = Tabulator.prototype.helpers.deepClone(self.table.modules.ajax.getParams() || {});
523  pageParams = self.table.modules.ajax.getParams();
524 
525  //configure request params
526  pageParams[this.paginationDataSentNames.page] = self.page;
527 
528  //set page size if defined
529  if(this.size){
530  pageParams[this.paginationDataSentNames.size] = this.size;
531  }
532 
533  //set sort data if defined
534  if(this.table.options.ajaxSorting && this.table.modExists("sort")){
535  let sorters = self.table.modules.sort.getSort();
536 
537  sorters.forEach(function(item){
538  delete item.column;
539  });
540 
541  pageParams[this.paginationDataSentNames.sorters] = sorters;
542  }
543 
544  //set filter data if defined
545  if(this.table.options.ajaxFiltering && this.table.modExists("filter")){
546  let filters = self.table.modules.filter.getFilters(true, true);
547  pageParams[this.paginationDataSentNames.filters] = filters;
548  }
549 
550  self.table.modules.ajax.setParams(pageParams);
551 
552  self.table.modules.ajax.sendRequest(this.progressiveLoad)
553  .then((data)=>{
554  self._parseRemoteData(data);
555  resolve();
556  })
557  .catch((e)=>{reject()});
558 
559  self.table.modules.ajax.setParams(oldParams);
560  });
561 };
562 
563 
564 
565 Page.prototype._parseRemoteData = function(data){
566  var self = this,
567  left, data, margin;
568 
569  if(typeof data[this.paginationDataReceivedNames.last_page] === "undefined"){
570  console.warn("Remote Pagination Error - Server response missing '" + this.paginationDataReceivedNames.last_page + "' property");
571  }
572 
573  if(data[this.paginationDataReceivedNames.data]){
574  this.max = parseInt(data[this.paginationDataReceivedNames.last_page]) || 1;
575 
576  if(this.progressiveLoad){
577  switch(this.mode){
578  case "progressive_load":
579  this.table.rowManager.addRows(data[this.paginationDataReceivedNames.data]);
580  if(this.page < this.max){
581  setTimeout(function(){
582  self.nextPage().then(()=>{}).catch(()=>{});
583  }, self.table.options.ajaxProgressiveLoadDelay);
584  }
585  break;
586 
587  case "progressive_scroll":
588  data = this.table.rowManager.getData().concat(data[this.paginationDataReceivedNames.data]);
589 
590  this.table.rowManager.setData(data, true);
591 
592  margin = this.table.options.ajaxProgressiveLoadScrollMargin || (this.table.rowManager.element.clientHeight * 2);
593 
594  if(self.table.rowManager.element.scrollHeight <= (self.table.rowManager.element.clientHeight + margin)){
595  self.nextPage().then(()=>{}).catch(()=>{});
596  }
597  break;
598  }
599  }else{
600  left = this.table.rowManager.scrollLeft;
601 
602  this.table.rowManager.setData(data[this.paginationDataReceivedNames.data]);
603 
604  this.table.rowManager.scrollHorizontal(left);
605 
606  this.table.columnManager.scrollHorizontal(left);
607 
608  this.table.options.pageLoaded.call(this.table, this.getPage());
609  }
610 
611  }else{
612  console.warn("Remote Pagination Error - Server response missing '" + this.paginationDataReceivedNames.data + "' property");
613  }
614 
615 };
616 
617 
618 
619 
620 //handle the footer element being redrawn
621 Page.prototype.footerRedraw = function(){
622  var footer = this.table.footerManager.element;
623 
624  if((Math.ceil(footer.clientWidth) - footer.scrollWidth) < 0){
625  this.pagesElement.style.display = 'none';
626  }else{
627  this.pagesElement.style.display = '';
628 
629  if((Math.ceil(footer.clientWidth) - footer.scrollWidth) < 0){
630  this.pagesElement.style.display = 'none';
631  }
632  }
633 };
634 
635 //set the paramter names for pagination requests
636 Page.prototype.paginationDataSentNames = {
637  "page":"page",
638  "size":"size",
639  "sorters":"sorters",
640  // "sort_dir":"sort_dir",
641  "filters":"filters",
642  // "filter_value":"filter_value",
643  // "filter_type":"filter_type",
644 };
645 
646 //set the property names for pagination responses
647 Page.prototype.paginationDataReceivedNames = {
648  "current_page":"current_page",
649  "last_page":"last_page",
650  "data":"data",
651 };
652 
653 Tabulator.prototype.registerModule("page", Page);