tabulator-tables
Version:
Interactive table generation JavaScript library
730 lines (562 loc) • 18.7 kB
JavaScript
/* Tabulator v4.9.3 (c) Oliver Folkerd */
var Page = function Page(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 _this = this;
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 (var 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(function (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(function () {}).catch(function () {});
});
self.prevBut.addEventListener("click", function () {
self.previousPage().then(function () {}).catch(function () {});
});
self.nextBut.addEventListener("click", function () {
self.nextPage().then(function () {}).catch(function () {});
});
self.lastBut.addEventListener("click", function () {
self.setPage(self.max).then(function () {}).catch(function () {});
});
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(function () {}).catch(function () {});
});
}
//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 _this2 = this;
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(function (resolve, reject) {
page = parseInt(page);
if (page > 0 && page <= _this2.max || _this2.mode !== "local") {
_this2.page = page;
_this2.trigger().then(function () {
resolve();
}).catch(function () {
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 - " + _this2.max + ":", page);
reject();
}
});
};
Page.prototype.setPageToRow = function (row) {
var _this3 = this;
return new Promise(function (resolve, reject) {
var rows = _this3.table.rowManager.getDisplayRows(_this3.displayIndex - 1);
var index = rows.indexOf(row);
if (index > -1) {
var page = _this3.size === true ? 1 : Math.ceil((index + 1) / _this3.size);
_this3.setPage(page).then(function () {
resolve();
}).catch(function () {
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;
var leftSize = Math.floor((this.count - 1) / 2);
var rightSize = Math.ceil((this.count - 1) / 2);
var min = this.max - this.page + leftSize + 1 < this.count ? this.max - this.count + 1 : Math.max(this.page - leftSize, 1);
var 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 (var 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(function () {}).catch(function () {});
});
return button;
};
//previous page
Page.prototype.previousPage = function () {
var _this4 = this;
return new Promise(function (resolve, reject) {
if (_this4.page > 1) {
_this4.page--;
_this4.trigger().then(function () {
resolve();
}).catch(function () {
reject();
});
if (_this4.table.options.persistence && _this4.table.modExists("persistence", true) && _this4.table.modules.persistence.config.page) {
_this4.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 () {
var _this5 = this;
return new Promise(function (resolve, reject) {
if (_this5.page < _this5.max) {
_this5.page++;
_this5.trigger().then(function () {
resolve();
}).catch(function () {
reject();
});
if (_this5.table.options.persistence && _this5.table.modExists("persistence", true) && _this5.table.modules.persistence.config.page) {
_this5.table.modules.persistence.save("page");
}
} else {
if (!_this5.progressiveLoad) {
console.warn("Pagination Error - Next page would be greater than maximum page of " + _this5.max + ":", _this5.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 (var 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 _this6 = this;
var left;
return new Promise(function (resolve, reject) {
switch (_this6.mode) {
case "local":
left = _this6.table.rowManager.scrollLeft;
_this6.table.rowManager.refreshActiveData("page");
_this6.table.rowManager.scrollHorizontal(left);
_this6.table.options.pageLoaded.call(_this6.table, _this6.getPage());
resolve();
break;
case "remote":
case "progressive_load":
case "progressive_scroll":
_this6.table.modules.ajax.blockActiveRequest();
_this6._getRemotePage().then(function () {
resolve();
}).catch(function () {
reject();
});
break;
default:
console.warn("Pagination Error - no such pagination mode:", _this6.mode);
reject();
}
});
};
Page.prototype._getRemotePage = function () {
var _this7 = this;
var self = this,
oldParams,
pageParams;
return new Promise(function (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[_this7.dataSentNames.page] = self.page;
//set page size if defined
if (_this7.size) {
pageParams[_this7.dataSentNames.size] = _this7.size;
}
//set sort data if defined
if (_this7.table.options.ajaxSorting && _this7.table.modExists("sort")) {
var sorters = self.table.modules.sort.getSort();
sorters.forEach(function (item) {
delete item.column;
});
pageParams[_this7.dataSentNames.sorters] = sorters;
}
//set filter data if defined
if (_this7.table.options.ajaxFiltering && _this7.table.modExists("filter")) {
var filters = self.table.modules.filter.getFilters(true, true);
pageParams[_this7.dataSentNames.filters] = filters;
}
self.table.modules.ajax.setParams(pageParams);
self.table.modules.ajax.sendRequest(_this7.progressiveLoad).then(function (data) {
self._parseRemoteData(data);
resolve();
}).catch(function (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(function () {}).catch(function () {});
}, 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(function () {}).catch(function () {});
}
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);