devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
569 lines (568 loc) • 24.2 kB
JavaScript
/**
* DevExtreme (ui/pager.js)
* Version: 18.1.3
* Build date: Tue May 15 2018
*
* Copyright (c) 2012 - 2018 Developer Express Inc. ALL RIGHTS RESERVED
* Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
*/
"use strict";
var $ = require("../core/renderer"),
eventsEngine = require("../events/core/events_engine"),
Class = require("../core/class"),
stringUtils = require("../core/utils/string"),
registerComponent = require("../core/component_registrator"),
commonUtils = require("../core/utils/common"),
each = require("../core/utils/iterator").each,
typeUtils = require("../core/utils/type"),
extend = require("../core/utils/extend").extend,
clickEvent = require("../events/click"),
messageLocalization = require("../localization/message"),
Widget = require("./widget/ui.widget"),
SelectBox = require("./select_box"),
NumberBox = require("./number_box"),
eventUtils = require("../events/utils");
var PAGES_LIMITER = 4,
PAGER_CLASS = "dx-pager",
PAGER_PAGE_CLASS = "dx-page",
PAGER_PAGES_CLASS = "dx-pages",
LIGHT_MODE_CLASS = "dx-light-mode",
LIGHT_PAGES_CLASS = "dx-light-pages",
PAGER_PAGE_INDEX_CLASS = "dx-page-index",
PAGER_PAGES_COUNT_CLASS = "dx-pages-count",
PAGER_SELECTION_CLASS = "dx-selection",
PAGER_PAGE_SEPARATOR_CLASS = "dx-separator",
PAGER_PAGE_SIZES_CLASS = "dx-page-sizes",
PAGER_PAGE_SIZE_CLASS = "dx-page-size",
PAGER_NAVIGATE_BUTTON = "dx-navigate-button",
PAGER_PREV_BUTTON_CLASS = "dx-prev-button",
PAGER_NEXT_BUTTON_CLASS = "dx-next-button",
PAGER_INFO_CLASS = "dx-info",
PAGER_INFO_TEXT_CLASS = "dx-info-text",
PAGER_BUTTON_DISABLE_CLASS = "dx-button-disable";
var Page = Class.inherit({
ctor: function(value, index) {
var that = this;
that.index = index;
that._$page = $("<div>").text(value).addClass(PAGER_PAGE_CLASS)
},
value: function(_value) {
var that = this;
if (typeUtils.isDefined(_value)) {
that._$page.text(_value)
} else {
var text = that._$page.text();
if (typeUtils.isNumeric(text)) {
return parseInt(text)
} else {
return text
}
}
},
element: function() {
return this._$page
},
select: function(value) {
this._$page.toggleClass(PAGER_SELECTION_CLASS, value)
},
render: function(rootElement, rtlEnabled) {
rtlEnabled ? this._$page.prependTo(rootElement) : this._$page.appendTo(rootElement)
}
});
var Pager = Widget.inherit({
_getDefaultOptions: function() {
return extend(this.callBase(), {
visible: true,
pagesNavigatorVisible: "auto",
pageIndex: 1,
maxPagesCount: 10,
pageCount: 10,
totalCount: 0,
pageSize: 5,
showPageSizes: true,
pageSizes: [5, 10],
hasKnownLastPage: true,
showNavigationButtons: false,
showInfo: false,
infoText: messageLocalization.getFormatter("dxPager-infoText"),
pagesCountText: messageLocalization.getFormatter("dxPager-pagesCountText"),
rtlEnabled: false,
lightModeEnabled: false,
pageIndexChanged: commonUtils.noop,
pageSizeChanged: commonUtils.noop
})
},
_toggleVisibility: function(value) {
var $element = this.$element();
if ($element) {
$element.css("display", value ? "" : "none")
}
},
_getPages: function(currentPage, count) {
var firstValue, i, pages = [],
showMoreButton = !this.option("hasKnownLastPage");
if (count > 0 || showMoreButton) {
if (count <= this.option("maxPagesCount")) {
for (i = 1; i <= count; i++) {
pages.push(new Page(i, i - 1))
}
if (showMoreButton) {
pages.push(new Page(">", i - 1))
}
} else {
pages.push(new Page(1, 0));
firstValue = currentPage ? currentPage.value() - currentPage.index : 1;
for (i = 1; i <= PAGES_LIMITER; i++) {
pages.push(new Page(firstValue + i, i))
}
pages.push(new Page(count, PAGES_LIMITER + 1));
if (showMoreButton) {
pages.push(new Page(">", PAGES_LIMITER + 1))
}
}
}
return pages
},
_getPageByValue: function(value) {
var page, i, that = this;
for (i = 0; i < that._pages.length; i++) {
page = that._pages[i];
if (page.value() === value) {
return page
}
}
},
_processSelectedPage: function(maxPagesCount, pageIndex, pageCount) {
var selectedPageIndex, that = this,
isPageIndexValid = false;
if (that._pages) {
each(that._pages, function(key, page) {
if (pageIndex === page.value()) {
isPageIndexValid = true
}
});
if (!isPageIndexValid) {
that.selectedPage = null
}
}
if (typeUtils.isDefined(that.selectedPage)) {
if (pageIndex === pageCount && pageCount > maxPagesCount && that.selectedPage.index !== PAGES_LIMITER + 1) {
that.selectedPage.index = PAGES_LIMITER + 1
}
} else {
if (pageIndex > PAGES_LIMITER && pageIndex < pageCount) {
selectedPageIndex = pageCount - PAGES_LIMITER < pageIndex ? PAGES_LIMITER - (pageCount - pageIndex) + 1 : 2;
that.selectedPage = new Page(pageIndex, selectedPageIndex)
}
}
},
_selectPageByValue: function(value) {
var i, prevPage, nextPage, morePage, that = this,
page = that._getPageByValue(value),
pages = that._pages,
pagesLength = pages.length;
if (!typeUtils.isDefined(page)) {
return
}
prevPage = that._pages[page.index - 1];
nextPage = that._pages[page.index + 1];
if (nextPage && ">" === nextPage.value()) {
morePage = nextPage;
nextPage = void 0;
pagesLength--;
pages.pop()
}
if (that.selectedPage) {
that.selectedPage.select(false)
}
page.select(true);
that.selectedPage = page;
if (nextPage && nextPage.value() - value > 1) {
if (0 !== page.index) {
prevPage.value(value + 1);
that._pages.splice(page.index, 1);
that._pages.splice(page.index - 1, 0, page);
that._pages[page.index].index = page.index;
page.index = page.index - 1;
for (i = page.index - 1; i > 0; i--) {
that._pages[i].value(that._pages[i + 1].value() - 1)
}
} else {
for (i = 0; i < pagesLength - 1; i++) {
that._pages[i].value(i + 1)
}
}
}
if (prevPage && value - prevPage.value() > 1) {
if (page.index !== pagesLength - 1) {
nextPage.value(value - 1);
that._pages.splice(page.index, 1);
that._pages.splice(page.index + 1, 0, page);
that._pages[page.index].index = page.index;
page.index = page.index + 1;
for (i = page.index + 1; i < pagesLength - 1; i++) {
that._pages[i].value(that._pages[i - 1].value() + 1)
}
} else {
for (i = 1; i <= pagesLength - 2; i++) {
that._pages[pagesLength - 1 - i].value(that._pages[pagesLength - 1].value() - i)
}
}
}
if (morePage) {
pages.push(morePage)
}
},
_nextPage: function(direction) {
var pageIndex = this.option("pageIndex"),
pageCount = this.option("pageCount");
if (typeUtils.isDefined(pageIndex)) {
pageIndex = "next" === direction ? ++pageIndex : --pageIndex;
if (pageIndex > 0 && pageIndex <= pageCount) {
this.option("pageIndex", pageIndex)
}
}
},
_renderPages: function(pages) {
var $separator, page, that = this,
pagesLength = pages.length,
clickPagesIndexAction = that._createAction(function(args) {
var e = args.event,
pageNumber = $(e.target).text(),
pageIndex = ">" === pageNumber ? that.option("pageCount") + 1 : Number(pageNumber);
that.option("pageIndex", pageIndex)
});
if (pagesLength > 1) {
that._pageClickHandler = function(e) {
clickPagesIndexAction({
event: e
})
};
eventsEngine.on(that._$pagesChooser, eventUtils.addNamespace(clickEvent.name, that.Name + "Pages"), "." + PAGER_PAGE_CLASS, that._pageClickHandler)
}
for (var i = 0; i < pagesLength; i++) {
page = pages[i];
page.render(that._$pagesChooser, that.option("rtlEnabled"));
that.setAria({
role: "button",
label: "Page " + page.value()
}, page.element());
if (pages[i + 1] && pages[i + 1].value() - page.value() > 1) {
$separator = $("<div>").text(". . .").addClass(PAGER_PAGE_SEPARATOR_CLASS);
that.option("rtlEnabled") ? $separator.prependTo(that._$pagesChooser) : $separator.appendTo(that._$pagesChooser)
}
}
},
_calculateLightPagesWidth: function($pageIndex, pageCount) {
return Number($pageIndex.css("minWidth").replace("px", "")) + 10 * pageCount.toString().length
},
_renderLightPages: function() {
var $pageCount, $pageIndex, that = this,
pageCount = this.option("pageCount"),
pageIndex = this.option("pageIndex"),
clickAction = that._createAction(function() {
that.option("pageIndex", pageCount)
}),
pagesCountText = this.option("pagesCountText");
var $container = $("<div>").addClass(LIGHT_PAGES_CLASS).appendTo(this._$pagesChooser);
$pageIndex = $("<div>").addClass(PAGER_PAGE_INDEX_CLASS).appendTo($container);
that._pageIndexEditor = that._createComponent($pageIndex, NumberBox, {
value: pageIndex,
min: 1,
max: pageCount,
width: that._calculateLightPagesWidth($pageIndex, pageCount),
onValueChanged: function(e) {
that.option("pageIndex", e.value)
}
});
$("<span>").text(pagesCountText).addClass(PAGER_INFO_TEXT_CLASS + " " + PAGER_INFO_CLASS).appendTo($container);
$pageCount = $("<span>").addClass(PAGER_PAGES_COUNT_CLASS).text(pageCount);
eventsEngine.on($pageCount, eventUtils.addNamespace(clickEvent.name, that.Name + "PagesCount"), function(e) {
clickAction({
event: e
})
});
$pageCount.appendTo($container);
that.setAria({
role: "button",
label: "Navigates to the last page"
}, $pageCount)
},
_renderPagesChooser: function() {
var that = this,
lightModeEnabled = that.option("lightModeEnabled"),
pagesNavigatorVisible = that.option("pagesNavigatorVisible"),
$element = that.$element();
that._$pagesChooser && that._$pagesChooser.remove();
if (!pagesNavigatorVisible) {
return
}
if (that._pages && 0 === that._pages.length) {
that.selectedPage = null;
return
}
that._$pagesChooser = $("<div>").addClass(PAGER_PAGES_CLASS).appendTo($element);
if ("auto" === pagesNavigatorVisible) {
that._$pagesChooser.css("visibility", 1 === that.option("pageCount") ? "hidden" : "")
}
if (!lightModeEnabled) {
that._renderInfo()
}
that._renderNavigateButton("prev");
if (lightModeEnabled) {
that._renderLightPages()
} else {
that._renderPages(that._pages)
}
that._renderNavigateButton("next");
that._updatePagesChooserWidth()
},
_renderPageSizes: function() {
var i, pageSizeValue, $pageSize, that = this,
pageSizes = that.option("pageSizes"),
pagesSizesLength = pageSizes && pageSizes.length,
currentPageSize = that.option("pageSize"),
clickPagesSizeAction = that._createAction(function(args) {
var e = args.event;
pageSizeValue = parseInt($(e.target).text());
that.option("pageSize", pageSizeValue)
});
eventsEngine.on(that._$pagesSizeChooser, eventUtils.addNamespace(clickEvent.name, that.Name + "PageSize"), "." + PAGER_PAGE_SIZE_CLASS, function(e) {
clickPagesSizeAction({
event: e
})
});
for (i = 0; i < pagesSizesLength; i++) {
$pageSize = $("<div>").text(pageSizes[i]).addClass(PAGER_PAGE_SIZE_CLASS);
that.setAria({
role: "button",
label: "Display " + pageSizes[i] + " items on page"
}, $pageSize);
if (currentPageSize === pageSizes[i]) {
$pageSize.addClass(PAGER_SELECTION_CLASS)
}
that._$pagesSizeChooser.append($pageSize)
}
},
_calculateLightPageSizesWidth: function(pageSizes) {
return Number(this._$pagesSizeChooser.css("minWidth").replace("px", "")) + 10 * Math.max.apply(Math, pageSizes).toString().length
},
_renderLightPageSizes: function() {
var $editor, that = this,
pageSizes = that.option("pageSizes");
$editor = $("<div>").appendTo(that._$pagesSizeChooser);
that._pageSizeEditor = that._createComponent($editor, SelectBox, {
dataSource: pageSizes,
value: that.option("pageSize"),
onSelectionChanged: function(e) {
that.option("pageSize", e.selectedItem)
},
width: that._calculateLightPageSizesWidth(pageSizes)
})
},
_renderPagesSizeChooser: function() {
var that = this,
pageSizes = that.option("pageSizes"),
showPageSizes = that.option("showPageSizes"),
pagesSizesLength = pageSizes && pageSizes.length,
$element = that.$element();
that._$pagesSizeChooser && that._$pagesSizeChooser.remove();
if (!showPageSizes || !pagesSizesLength) {
return
}
that._$pagesSizeChooser = $("<div>").addClass(PAGER_PAGE_SIZES_CLASS).appendTo($element);
if (that.option("lightModeEnabled")) {
that._renderLightPageSizes()
} else {
that._renderPageSizes()
}
that._pagesSizeChooserWidth = that._$pagesSizeChooser.width()
},
_renderInfo: function() {
var infoText = this.option("infoText");
if (this.option("showInfo") && typeUtils.isDefined(infoText)) {
this._$info = $("<div>").css("display", this._isInfoHide ? "none" : "").addClass(PAGER_INFO_CLASS).text(stringUtils.format(infoText, this.selectedPage && this.selectedPage.value(), this.option("pageCount"), this.option("totalCount"))).appendTo(this._$pagesChooser);
if (!this._isInfoHide) {
this._infoWidth = this._$info.outerWidth(true)
}
}
},
_renderNavigateButton: function(direction) {
var $button, that = this,
clickAction = that._createAction(function() {
that._nextPage(direction)
});
if (that.option("showNavigationButtons") || that.option("lightModeEnabled")) {
$button = $("<div>").addClass(PAGER_NAVIGATE_BUTTON);
eventsEngine.on($button, eventUtils.addNamespace(clickEvent.name, that.Name + "Pages"), function(e) {
clickAction({
event: e
})
});
that.setAria({
role: "button",
label: "prev" === direction ? "Previous page" : " Next page"
}, $button);
if (that.option("rtlEnabled")) {
$button.addClass("prev" === direction ? PAGER_NEXT_BUTTON_CLASS : PAGER_PREV_BUTTON_CLASS);
$button.prependTo(this._$pagesChooser)
} else {
$button.addClass("prev" === direction ? PAGER_PREV_BUTTON_CLASS : PAGER_NEXT_BUTTON_CLASS);
$button.appendTo(this._$pagesChooser)
}
}
},
_renderContentImpl: function() {
this.$element().toggleClass(LIGHT_MODE_CLASS, this.option("lightModeEnabled"));
this._toggleVisibility(this.option("visible"));
this._updatePageSizes(true);
this._updatePages(true)
},
_initMarkup: function() {
var $element = this.$element();
$element.addClass(PAGER_CLASS);
var $pageSize = $("<div>").addClass(PAGER_PAGE_CLASS);
this._$pagesChooser = $("<div>").addClass(PAGER_PAGES_CLASS).append($pageSize).appendTo($element)
},
_render: function() {
this.option().lightModeEnabled = false;
this.callBase();
this._updateLightMode()
},
_updatePageSizes: function(forceRender) {
var lightModeEnabled = this.option("lightModeEnabled"),
pageSize = this.option("pageSize"),
pageSizes = this.option("pageSizes");
if (lightModeEnabled) {
this._pageSizeEditor && this._pageSizeEditor.option({
value: pageSize,
dataSource: pageSizes,
width: this._calculateLightPageSizesWidth(pageSizes)
})
}
if (!lightModeEnabled || forceRender) {
this._renderPagesSizeChooser()
}
},
_updatePages: function(forceRender) {
var pageCount = this.option("pageCount"),
pageIndex = this.option("pageIndex"),
lightModeEnabled = this.option("lightModeEnabled");
if (!lightModeEnabled) {
this._processSelectedPage(this.option("maxPagesCount"), pageIndex, pageCount);
this._pages = this._getPages(this.selectedPage, pageCount);
this._selectPageByValue(pageIndex)
} else {
this._pageIndexEditor && this._pageIndexEditor.option({
value: pageIndex,
width: this._calculateLightPagesWidth(this._pageIndexEditor.$element(), pageCount)
})
}
if (!lightModeEnabled || forceRender) {
this._renderPagesChooser()
}
this._updateButtonsState(pageIndex)
},
_isPageIndexInvalid: function(direction, pageIndex) {
var isNextDirection = "next" === direction,
rtlEnabled = this.option("rtlEnabled");
if (rtlEnabled && isNextDirection || !rtlEnabled && !isNextDirection) {
return pageIndex <= 1
}
return pageIndex >= this.option("pageCount")
},
_updateButtonsState: function(pageIndex) {
var nextButton = this.$element().find("." + PAGER_NEXT_BUTTON_CLASS),
prevButton = this.$element().find("." + PAGER_PREV_BUTTON_CLASS);
nextButton.toggleClass(PAGER_BUTTON_DISABLE_CLASS, this._isPageIndexInvalid("next", pageIndex));
prevButton.toggleClass(PAGER_BUTTON_DISABLE_CLASS, this._isPageIndexInvalid("prev", pageIndex))
},
_optionChanged: function(args) {
switch (args.name) {
case "visible":
this._toggleVisibility(args.value);
break;
case "pageIndex":
var pageIndexChanged = this.option("pageIndexChanged");
if (pageIndexChanged) {
pageIndexChanged(args.value)
}
this._updatePages();
break;
case "maxPagesCount":
case "pageCount":
case "totalCount":
case "hasKnownLastPage":
case "pagesNavigatorVisible":
case "showNavigationButtons":
this._updatePages();
break;
case "pageSize":
var pageSizeChanged = this.option("pageSizeChanged");
if (pageSizeChanged) {
pageSizeChanged(args.value)
}
this._updatePageSizes();
break;
case "pageSizes":
this._updatePageSizes();
break;
case "lightModeEnabled":
this._renderContentImpl();
!args.value && this._updateLightMode();
break;
default:
this._invalidate()
}
},
_clean: function() {
this._$pagesChooser && eventsEngine.off(this._$pagesChooser, eventUtils.addNamespace(clickEvent.name, this.Name + "Pages"), "." + PAGER_PAGE_CLASS, this._pageClickHandler);
this.callBase()
},
_getMinPagerWidth: function() {
var pagesChooserWidth = typeUtils.isDefined(this._pagesChooserWidth) ? this._pagesChooserWidth : 0,
pagesSizeChooserWidth = typeUtils.isDefined(this._pagesSizeChooserWidth) ? this._pagesSizeChooserWidth : 0;
return pagesChooserWidth + pagesSizeChooserWidth
},
_updatePagesChooserWidth: commonUtils.deferUpdater(function() {
var lastPageWidth = this._pages && this._pages.length > 0 ? this._pages[this._pages.length - 1]._$page.width() : 0;
this._pagesChooserWidth = this._$pagesChooser.width() + lastPageWidth
}),
_updateLightMode: commonUtils.deferUpdater(function() {
var that = this,
width = this.$element().width(),
infoWidth = typeUtils.isDefined(this._infoWidth) ? this._infoWidth : 0;
commonUtils.deferRender(function() {
if (that._isInfoHide && width > that._getMinPagerWidth() + infoWidth) {
that._$info.show();
that._updatePagesChooserWidth();
that._isInfoHide = false
}
if (!that._isInfoHide && width > that._getMinPagerWidth() - infoWidth && width < that._getMinPagerWidth()) {
that._$info.hide();
that._updatePagesChooserWidth();
that._isInfoHide = true
}
commonUtils.deferUpdate(function() {
commonUtils.deferRender(function() {
if (that.option("lightModeEnabled") && width > that._previousWidth) {
that.option("lightModeEnabled", false)
} else {
if (width < that._getMinPagerWidth()) {
that.option("lightModeEnabled", true)
}
}
that._previousWidth = width
})
})
})
}),
_dimensionChanged: function() {
this._updateLightMode()
},
getHeight: function() {
return this.option("visible") ? this.$element().outerHeight() : 0
}
});
module.exports = Pager;
registerComponent("dxPager", Pager);