UNPKG

@gitlab/ui

Version:
387 lines (345 loc) 12.3 kB
import range from 'lodash/range'; import isFunction from 'lodash/isFunction'; import debounce from 'lodash/debounce'; import GlLink from '../link/link'; import GlIcon from '../icon/icon'; import Breakpoints, { breakpoints } from '../../../utils/breakpoints'; import { isIntGreaterThan } from '../../../utils/number_utils'; import { sizeOptions, alignOptions, resizeDebounceTime } from '../../../utils/constants'; import __vue_normalize__ from 'vue-runtime-helpers/dist/normalize-component.js'; function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; } var isIntGreaterThanZero = isIntGreaterThan(0); var pageRange = function pageRange(from, to) { return range(from, to + 1, 1); }; var script = { name: 'Pagination', components: { GlLink: GlLink, GlIcon: GlIcon }, model: { prop: 'value', event: 'input' }, props: { value: { type: Number, required: false, default: 1, validator: isIntGreaterThanZero }, perPage: { type: Number, required: false, default: 20, validator: isIntGreaterThanZero }, totalItems: { type: Number, required: false, default: 0 }, limits: { type: Object, required: false, default: function _default() { return { xs: 0, sm: 3, md: 9, default: 9 }; }, validator: function validator(value) { var missingSizes = Object.keys(breakpoints).filter(function (size) { return !value[size]; }).length; return missingSizes === 0 ? true : value.default; } }, linkGen: { type: Function, required: false, default: null }, prevPage: { type: Number, required: false, default: null }, prevText: { type: String, required: false, default: 'Prev' }, nextPage: { type: Number, required: false, default: null }, nextText: { type: String, required: false, default: 'Next' }, ellipsisText: { type: String, required: false, default: '…' }, labelFirstPage: { type: String, default: 'Go to first page' }, labelPrevPage: { type: String, default: 'Go to previous page' }, labelNextPage: { type: String, default: 'Go to next page' }, labelLastPage: { type: String, default: 'Go to last page' }, labelPage: { type: Function, default: function _default(page) { return "Go to page ".concat(page); } }, size: { type: String, required: false, default: null, validator: function validator(value) { return Object.keys(sizeOptions).includes(value); } }, align: { type: String, required: false, default: alignOptions.left, validator: function validator(value) { return Object.keys(alignOptions).includes(value); } }, disabled: { type: Boolean, required: false, default: false } }, data: function data() { return { breakpoint: Breakpoints.getBreakpointSize(), // If total pages count is below or equal to minTotalPagesToCollapse, collapsing is disabled minTotalPagesToCollapse: 4 }; }, computed: { isVisible: function isVisible() { return this.totalPages > 1 || this.isCompactPagination; }, isLinkBased: function isLinkBased() { return isFunction(this.linkGen); }, paginationLimit: function paginationLimit() { return typeof this.limits[this.breakpoint] !== 'undefined' ? this.limits[this.breakpoint] : this.limits.default; }, maxAdjacentPages: function maxAdjacentPages() { return Math.max(Math.ceil((this.paginationLimit - 1) / 2), 0); }, totalPages: function totalPages() { return Math.ceil(this.totalItems / this.perPage); }, isFillAlign: function isFillAlign() { return this.align === alignOptions.fill; }, wrapperClasses: function wrapperClasses() { var classes = []; if (this.align === alignOptions.center) { classes.push('justify-content-center'); } if (this.align === alignOptions.right) { classes.push('justify-content-end'); } if (this.isFillAlign) { classes.push('text-center'); } if (this.size) { classes.push("pagination-".concat(this.size)); } if (Object.keys(this.$slots).length > 0) { classes.push('custom-rendering'); } return classes; }, shouldCollapseLeftSide: function shouldCollapseLeftSide() { var diff = this.value - this.maxAdjacentPages; // Magic 3: prevents collapsing a single page on the left side return diff >= this.maxAdjacentPages && diff > 3 && this.totalPages > this.minTotalPagesToCollapse; }, shouldCollapseRightSide: function shouldCollapseRightSide() { // Magic 2: prevents collapsing a single page on the right side var diff = this.totalPages - 2 - this.value; return diff > this.maxAdjacentPages && this.totalPages > this.minTotalPagesToCollapse; }, visibleItems: function visibleItems() { var _this = this; var items = []; if (!this.isCompactPagination) { var firstPage = this.shouldCollapseLeftSide ? this.value - this.maxAdjacentPages : 1; // If we're on last page, show at least one page to the left firstPage = Math.min(firstPage, this.totalPages - 1); var lastPage = this.shouldCollapseRightSide ? this.value + this.maxAdjacentPages : this.totalPages; // If we're on first page, show at least one page to the right lastPage = Math.max(lastPage, 2); // Default numbered items items = pageRange(firstPage, lastPage).map(function (page) { return _this.getPageItem(page); }); if (this.shouldCollapseLeftSide) { items.splice(0, 0, this.getPageItem(1, this.labelFirstPage), this.getEllipsisItem('left')); } if (this.shouldCollapseRightSide) { items.push(this.getEllipsisItem('right'), this.getPageItem(this.totalPages, this.labelLastPage)); } } return items; }, isCompactPagination: function isCompactPagination() { return Boolean(!this.totalItems && (this.prevPage || this.nextPage)); }, prevPageIsDisabled: function prevPageIsDisabled() { return this.pageIsDisabled(this.value - 1); }, nextPageIsDisabled: function nextPageIsDisabled() { return this.pageIsDisabled(this.value + 1); } }, created: function created() { window.addEventListener('resize', debounce(this.setBreakpoint, resizeDebounceTime)); }, beforeDestroy: function beforeDestroy() { window.removeEventListener('resize', debounce(this.setBreakpoint, resizeDebounceTime)); }, methods: { setBreakpoint: function setBreakpoint() { this.breakpoint = Breakpoints.getBreakpointSize(); }, pageIsDisabled: function pageIsDisabled(page) { return this.disabled || page < 1 || this.isCompactPagination && page > this.value && !this.nextPage || !this.isCompactPagination && page > this.totalPages; }, getPageItem: function getPageItem(page) { var _this2 = this; var label = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; var commonAttrs = { 'aria-label': label || this.labelPage(page), href: '#', class: [] }; var isActivePage = page === this.value; var isDisabled = this.pageIsDisabled(page); var attrs = _objectSpread({}, commonAttrs); var listeners = {}; if (isActivePage) { attrs.class.push('active', 'btn-primary'); } // Disable previous and/or next buttons if needed if (this.isLinkBased) { attrs.href = this.linkGen(page); } else { listeners.click = function (e) { e.preventDefault(); _this2.$emit('input', page); }; } return { content: page, component: isDisabled ? 'span' : GlLink, disabled: isDisabled, key: "page_".concat(page), slot: 'page-number', slotData: { page: page, active: isActivePage, disabled: isDisabled }, attrs: attrs, listeners: listeners }; }, getEllipsisItem: function getEllipsisItem(side) { return { content: this.ellipsisText, key: "ellipsis_".concat(side), slot: "ellipsis-".concat(side), component: 'span', disabled: true }; } } }; /* script */ const __vue_script__ = script; /* template */ var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return (_vm.isVisible)?_c('ul',{staticClass:"pagination gl-pagination text-nowrap",class:_vm.wrapperClasses,attrs:{"role":"navigation","aria-label":"Pagination"}},[_c('li',{staticClass:"page-item",class:{ disabled: _vm.prevPageIsDisabled, 'flex-fill': _vm.isFillAlign, }},[_c(_vm.prevPageIsDisabled ? 'span' : 'a',{tag:"component",staticClass:"page-link prev-page-item",attrs:{"aria-disabled":_vm.prevPageIsDisabled,"aria-label":_vm.labelPrevPage || _vm.labelPage(_vm.value - 1),"href":_vm.isLinkBased ? _vm.linkGen(_vm.value - 1) : '#'},on:{"click":function($event){$event.preventDefault();return _vm.$emit('input', _vm.value - 1)}}},[_vm._t("previous",[_c('gl-icon',{attrs:{"name":"chevron-left"}}),_vm._v(" "),_c('span',[_vm._v(_vm._s(_vm.prevText))])],null,{ page: _vm.value - 1, disabled: _vm.prevPageIsDisabled })],2)],1),_vm._v(" "),_vm._l((_vm.visibleItems),function(item){return _c('li',{key:item.key,staticClass:"page-item",class:{ disabled: item.disabled, 'flex-fill': _vm.isFillAlign, }},[_c(item.component,_vm._g(_vm._b({tag:"component",staticClass:"page-link",attrs:{"size":_vm.size,"aria-disabled":item.disabled}},'component',item.attrs,false),item.listeners),[_vm._t(item.slot,[_vm._v(_vm._s(item.content))],null,item.slotData)],2)],1)}),_vm._v(" "),_c('li',{staticClass:"page-item",class:{ disabled: _vm.nextPageIsDisabled, 'flex-fill': _vm.isFillAlign, }},[_c(_vm.nextPageIsDisabled ? 'span' : 'a',{tag:"component",staticClass:"page-link next-page-item",attrs:{"aria-disabled":_vm.nextPageIsDisabled,"aria-label":_vm.labelNextPage || _vm.labelPage(_vm.value + 1),"href":_vm.isLinkBased ? _vm.linkGen(_vm.value + 1) : '#'},on:{"click":function($event){$event.preventDefault();return _vm.$emit('input', _vm.value + 1)}}},[_vm._t("next",[_c('span',[_vm._v(_vm._s(_vm.nextText))]),_vm._v(" "),_c('gl-icon',{attrs:{"name":"chevron-right"}})],null,{ page: _vm.value + 1, disabled: _vm.nextPageIsDisabled })],2)],1)],2):_vm._e()}; var __vue_staticRenderFns__ = []; /* style */ const __vue_inject_styles__ = undefined; /* scoped */ const __vue_scope_id__ = undefined; /* module identifier */ const __vue_module_identifier__ = undefined; /* functional template */ const __vue_is_functional_template__ = false; /* style inject */ /* style inject SSR */ /* style inject shadow dom */ const __vue_component__ = __vue_normalize__( { render: __vue_render__, staticRenderFns: __vue_staticRenderFns__ }, __vue_inject_styles__, __vue_script__, __vue_scope_id__, __vue_is_functional_template__, __vue_module_identifier__, false, undefined, undefined, undefined ); export default __vue_component__;