UNPKG

tabulator-tables

Version:

Interactive table generation JavaScript library

739 lines (557 loc) 18.6 kB
var Page = function(table){ this.table = table; //hold Tabulator object this.mode = "local"; this.progressiveLoad = false; this.size = 0; this.page = 1; this.count = 5; this.max = 1; this.displayIndex = 0; //index in display pipeline this.initialLoad = true; this.pageSizes = []; this.dataReceivedNames = {}; this.dataSentNames = {}; this.createElements(); }; Page.prototype.createElements = function(){ var button; this.element = document.createElement("span"); this.element.classList.add("tabulator-paginator"); this.pagesElement = document.createElement("span"); this.pagesElement.classList.add("tabulator-pages"); button = document.createElement("button"); button.classList.add("tabulator-page"); button.setAttribute("type", "button"); button.setAttribute("role", "button"); button.setAttribute("aria-label", ""); button.setAttribute("title", ""); this.firstBut = button.cloneNode(true); this.firstBut.setAttribute("data-page", "first"); this.prevBut = button.cloneNode(true); this.prevBut.setAttribute("data-page", "prev"); this.nextBut = button.cloneNode(true); this.nextBut.setAttribute("data-page", "next"); this.lastBut = button.cloneNode(true); this.lastBut.setAttribute("data-page", "last"); if(this.table.options.paginationSizeSelector){ this.pageSizeSelect = document.createElement("select"); this.pageSizeSelect.classList.add("tabulator-page-size"); } }; Page.prototype.generatePageSizeSelectList = function(){ var pageSizes = []; if(this.pageSizeSelect){ if(Array.isArray(this.table.options.paginationSizeSelector)){ pageSizes = this.table.options.paginationSizeSelector; this.pageSizes = pageSizes; if(this.pageSizes.indexOf(this.size) == -1){ pageSizes.unshift(this.size); } }else{ if(this.pageSizes.indexOf(this.size) == -1){ pageSizes = []; for (let i = 1; i < 5; i++){ pageSizes.push(this.size * i); } this.pageSizes = pageSizes; }else{ pageSizes = this.pageSizes; } } while(this.pageSizeSelect.firstChild) this.pageSizeSelect.removeChild(this.pageSizeSelect.firstChild); pageSizes.forEach((item) => { var itemEl = document.createElement("option"); itemEl.value = item; if(item === true){ this.table.modules.localize.bind("pagination|all", function(value){ itemEl.innerHTML = value; }); }else{ itemEl.innerHTML = item; } this.pageSizeSelect.appendChild(itemEl); }); this.pageSizeSelect.value = this.size; } }; //setup pageination Page.prototype.initialize = function(hidden){ var self = this, pageSelectLabel, testElRow, testElCell; //update param names this.dataSentNames = Object.assign({}, this.paginationDataSentNames); this.dataSentNames = Object.assign(this.dataSentNames, this.table.options.paginationDataSent); this.dataReceivedNames = Object.assign({}, this.paginationDataReceivedNames); this.dataReceivedNames = Object.assign(this.dataReceivedNames, this.table.options.paginationDataReceived); //build pagination element //bind localizations self.table.modules.localize.bind("pagination|first", function(value){ self.firstBut.innerHTML = value; }); self.table.modules.localize.bind("pagination|first_title", function(value){ self.firstBut.setAttribute("aria-label", value); self.firstBut.setAttribute("title", value); }); self.table.modules.localize.bind("pagination|prev", function(value){ self.prevBut.innerHTML = value; }); self.table.modules.localize.bind("pagination|prev_title", function(value){ self.prevBut.setAttribute("aria-label", value); self.prevBut.setAttribute("title", value); }); self.table.modules.localize.bind("pagination|next", function(value){ self.nextBut.innerHTML = value; }); self.table.modules.localize.bind("pagination|next_title", function(value){ self.nextBut.setAttribute("aria-label", value); self.nextBut.setAttribute("title", value); }); self.table.modules.localize.bind("pagination|last", function(value){ self.lastBut.innerHTML = value; }); self.table.modules.localize.bind("pagination|last_title", function(value){ self.lastBut.setAttribute("aria-label", value); self.lastBut.setAttribute("title", value); }); //click bindings self.firstBut.addEventListener("click", function(){ self.setPage(1).then(()=>{}).catch(()=>{}); }); self.prevBut.addEventListener("click", function(){ self.previousPage().then(()=>{}).catch(()=>{}); }); self.nextBut.addEventListener("click", function(){ self.nextPage().then(()=>{}).catch(()=>{}); }); self.lastBut.addEventListener("click", function(){ self.setPage(self.max).then(()=>{}).catch(()=>{}); }); if(self.table.options.paginationElement){ self.element = self.table.options.paginationElement; } if(this.pageSizeSelect){ pageSelectLabel = document.createElement("label"); self.table.modules.localize.bind("pagination|page_size", function(value){ self.pageSizeSelect.setAttribute("aria-label", value); self.pageSizeSelect.setAttribute("title", value); pageSelectLabel.innerHTML = value; }); self.element.appendChild(pageSelectLabel); self.element.appendChild(self.pageSizeSelect); self.pageSizeSelect.addEventListener("change", function(e){ self.setPageSize(self.pageSizeSelect.value == "true" ? true : self.pageSizeSelect.value); self.setPage(1).then(()=>{}).catch(()=>{}); }); } //append to DOM self.element.appendChild(self.firstBut); self.element.appendChild(self.prevBut); self.element.appendChild(self.pagesElement); self.element.appendChild(self.nextBut); self.element.appendChild(self.lastBut); if(!self.table.options.paginationElement && !hidden){ self.table.footerManager.append(self.element, self); } //set default values self.mode = self.table.options.pagination; if(self.table.options.paginationSize){ self.size = self.table.options.paginationSize; }else{ testElRow = document.createElement("div"); testElRow.classList.add("tabulator-row"); testElRow.style.visibility = hidden; testElCell = document.createElement("div"); testElCell.classList.add("tabulator-cell"); testElCell.innerHTML = "Page Row Test"; testElRow.appendChild(testElCell); self.table.rowManager.getTableElement().appendChild(testElRow); self.size = Math.floor(self.table.rowManager.getElement().clientHeight / testElRow.offsetHeight); self.table.rowManager.getTableElement().removeChild(testElRow); } // self.page = self.table.options.paginationInitialPage || 1; self.count = self.table.options.paginationButtonCount; self.generatePageSizeSelectList(); }; Page.prototype.initializeProgressive = function(mode){ this.initialize(true); this.mode = "progressive_" + mode; this.progressiveLoad = true; }; Page.prototype.setDisplayIndex = function(index){ this.displayIndex = index; }; Page.prototype.getDisplayIndex = function(){ return this.displayIndex; }; //calculate maximum page from number of rows Page.prototype.setMaxRows = function(rowCount){ if(!rowCount){ this.max = 1; }else{ this.max = this.size === true ? 1 : Math.ceil(rowCount/this.size); } if(this.page > this.max){ this.page = this.max; } }; //reset to first page without triggering action Page.prototype.reset = function(force, columnsChanged){ if(this.mode == "local" || force){ this.page = 1; } if(columnsChanged){ this.initialLoad = true; } return true; }; //set the maxmum page Page.prototype.setMaxPage = function(max){ max = parseInt(max); this.max = max || 1; if(this.page > this.max){ this.page = this.max; this.trigger(); } }; //set current page number Page.prototype.setPage = function(page){ var self = this; switch(page){ case "first": return this.setPage(1); break; case "prev": return this.previousPage(); break; case "next": return this.nextPage(); break; case "last": return this.setPage(this.max); break; } return new Promise((resolve, reject)=>{ page = parseInt(page); if((page > 0 && page <= this.max) || this.mode !== "local"){ this.page = page; this.trigger() .then(()=>{ resolve(); }) .catch(()=>{ reject(); }); if(self.table.options.persistence && self.table.modExists("persistence", true) && self.table.modules.persistence.config.page){ self.table.modules.persistence.save("page"); } }else{ console.warn("Pagination Error - Requested page is out of range of 1 - " + this.max + ":", page); reject(); } }); }; Page.prototype.setPageToRow = function(row){ return new Promise((resolve, reject)=>{ var rows = this.table.rowManager.getDisplayRows(this.displayIndex - 1); var index = rows.indexOf(row); if(index > -1){ var page = this.size === true ? 1 : Math.ceil((index + 1) / this.size); this.setPage(page) .then(()=>{ resolve(); }) .catch(()=>{ reject(); }); }else{ console.warn("Pagination Error - Requested row is not visible"); reject(); } }); }; Page.prototype.setPageSize = function(size){ if(size !== true){ size = parseInt(size); } if(size > 0){ this.size = size; } if(this.pageSizeSelect){ // this.pageSizeSelect.value = size; this.generatePageSizeSelectList(); } if(this.table.options.persistence && this.table.modExists("persistence", true) && this.table.modules.persistence.config.page){ this.table.modules.persistence.save("page"); } }; //setup the pagination buttons Page.prototype._setPageButtons = function(){ var self = this; let leftSize = Math.floor((this.count-1) / 2); let rightSize = Math.ceil((this.count-1) / 2); let min = this.max - this.page + leftSize + 1 < this.count ? this.max-this.count+1: Math.max(this.page-leftSize,1); let max = this.page <= rightSize? Math.min(this.count, this.max) :Math.min(this.page+rightSize, this.max); while(self.pagesElement.firstChild) self.pagesElement.removeChild(self.pagesElement.firstChild); if(self.page == 1){ self.firstBut.disabled = true; self.prevBut.disabled = true; }else{ self.firstBut.disabled = false; self.prevBut.disabled = false; } if(self.page == self.max){ self.lastBut.disabled = true; self.nextBut.disabled = true; }else{ self.lastBut.disabled = false; self.nextBut.disabled = false; } for(let i = min; i <= max; i++){ if(i>0 && i <= self.max){ self.pagesElement.appendChild(self._generatePageButton(i)); } } this.footerRedraw(); }; Page.prototype._generatePageButton = function(page){ var self = this, button = document.createElement("button"); button.classList.add("tabulator-page"); if(page == self.page){ button.classList.add("active"); } button.setAttribute("type", "button"); button.setAttribute("role", "button"); self.table.modules.localize.bind("pagination|page_title", function(value){ button.setAttribute("aria-label", value + " " + page); button.setAttribute("title", value + " " + page); }); button.setAttribute("data-page", page); button.textContent = page; button.addEventListener("click", function(e){ self.setPage(page).then(()=>{}).catch(()=>{}); }); return button; }; //previous page Page.prototype.previousPage = function(){ return new Promise((resolve, reject)=>{ if(this.page > 1){ this.page--; this.trigger() .then(()=>{ resolve(); }) .catch(()=>{ reject(); }); if(this.table.options.persistence && this.table.modExists("persistence", true) && this.table.modules.persistence.config.page){ this.table.modules.persistence.save("page"); } }else{ console.warn("Pagination Error - Previous page would be less than page 1:", 0); reject() } }); }; //next page Page.prototype.nextPage = function(){ return new Promise((resolve, reject)=>{ if(this.page < this.max){ this.page++; this.trigger() .then(()=>{ resolve(); }) .catch(()=>{ reject(); }); if(this.table.options.persistence && this.table.modExists("persistence", true) && this.table.modules.persistence.config.page){ this.table.modules.persistence.save("page"); } }else{ if(!this.progressiveLoad){ console.warn("Pagination Error - Next page would be greater than maximum page of " + this.max + ":", this.max + 1); } reject(); } }); }; //return current page number Page.prototype.getPage = function(){ return this.page; }; //return max page number Page.prototype.getPageMax = function(){ return this.max; }; Page.prototype.getPageSize = function(size){ return this.size; }; Page.prototype.getMode = function(){ return this.mode; }; //return appropriate rows for current page Page.prototype.getRows = function(data){ var output, start, end; if(this.mode == "local"){ output = []; if(this.size === true){ start = 0; end = data.length; }else{ start = this.size * (this.page - 1); end = start + parseInt(this.size); } this._setPageButtons(); for(let i = start; i < end; i++){ if(data[i]){ output.push(data[i]); } } return output; }else{ this._setPageButtons(); return data.slice(0); } }; Page.prototype.trigger = function(){ var left; return new Promise((resolve, reject)=>{ switch(this.mode){ case "local": left = this.table.rowManager.scrollLeft; this.table.rowManager.refreshActiveData("page"); this.table.rowManager.scrollHorizontal(left); this.table.options.pageLoaded.call(this.table, this.getPage()); resolve(); break; case "remote": case "progressive_load": case "progressive_scroll": this.table.modules.ajax.blockActiveRequest(); this._getRemotePage() .then(()=>{ resolve(); }) .catch(()=>{ reject(); }); break; default: console.warn("Pagination Error - no such pagination mode:", this.mode); reject(); } }); }; Page.prototype._getRemotePage = function(){ var self = this, oldParams, pageParams; return new Promise((resolve, reject)=>{ if(!self.table.modExists("ajax", true)){ reject() } //record old params and restore after request has been made oldParams = Tabulator.prototype.helpers.deepClone(self.table.modules.ajax.getParams() || {}); pageParams = self.table.modules.ajax.getParams(); //configure request params pageParams[this.dataSentNames.page] = self.page; //set page size if defined if(this.size){ pageParams[this.dataSentNames.size] = this.size; } //set sort data if defined if(this.table.options.ajaxSorting && this.table.modExists("sort")){ let sorters = self.table.modules.sort.getSort(); sorters.forEach(function(item){ delete item.column; }); pageParams[this.dataSentNames.sorters] = sorters; } //set filter data if defined if(this.table.options.ajaxFiltering && this.table.modExists("filter")){ let filters = self.table.modules.filter.getFilters(true, true); pageParams[this.dataSentNames.filters] = filters; } self.table.modules.ajax.setParams(pageParams); self.table.modules.ajax.sendRequest(this.progressiveLoad) .then((data)=>{ self._parseRemoteData(data); resolve(); }) .catch((e)=>{reject()}); self.table.modules.ajax.setParams(oldParams); }); }; Page.prototype._parseRemoteData = function(data){ var self = this, left, data, margin; if(typeof data[this.dataReceivedNames.last_page] === "undefined"){ console.warn("Remote Pagination Error - Server response missing '" + this.dataReceivedNames.last_page + "' property"); } if(data[this.dataReceivedNames.data]){ this.max = parseInt(data[this.dataReceivedNames.last_page]) || 1; if(this.progressiveLoad){ switch(this.mode){ case "progressive_load": if(this.page == 1){ this.table.rowManager.setData(data[this.dataReceivedNames.data], false, this.initialLoad && this.page == 1) }else{ this.table.rowManager.addRows(data[this.dataReceivedNames.data]); } if(this.page < this.max){ setTimeout(function(){ self.nextPage().then(()=>{}).catch(()=>{}); }, self.table.options.ajaxProgressiveLoadDelay); } break; case "progressive_scroll": data = this.table.rowManager.getData().concat(data[this.dataReceivedNames.data]); this.table.rowManager.setData(data, true, this.initialLoad && this.page == 1); margin = this.table.options.ajaxProgressiveLoadScrollMargin || (this.table.rowManager.element.clientHeight * 2); if(self.table.rowManager.element.scrollHeight <= (self.table.rowManager.element.clientHeight + margin)){ self.nextPage().then(()=>{}).catch(()=>{}); } break; } }else{ left = this.table.rowManager.scrollLeft; this.table.rowManager.setData(data[this.dataReceivedNames.data], false, this.initialLoad && this.page == 1); this.table.rowManager.scrollHorizontal(left); this.table.columnManager.scrollHorizontal(left); this.table.options.pageLoaded.call(this.table, this.getPage()); } this.initialLoad = false; }else{ console.warn("Remote Pagination Error - Server response missing '" + this.dataReceivedNames.data + "' property"); } }; //handle the footer element being redrawn Page.prototype.footerRedraw = function(){ var footer = this.table.footerManager.element; if((Math.ceil(footer.clientWidth) - footer.scrollWidth) < 0){ this.pagesElement.style.display = 'none'; }else{ this.pagesElement.style.display = ''; if((Math.ceil(footer.clientWidth) - footer.scrollWidth) < 0){ this.pagesElement.style.display = 'none'; } } }; //set the paramter names for pagination requests Page.prototype.paginationDataSentNames = { "page":"page", "size":"size", "sorters":"sorters", // "sort_dir":"sort_dir", "filters":"filters", // "filter_value":"filter_value", // "filter_type":"filter_type", }; //set the property names for pagination responses Page.prototype.paginationDataReceivedNames = { "current_page":"current_page", "last_page":"last_page", "data":"data", }; Tabulator.prototype.registerModule("page", Page);