StackGenVis: Alignment of Data, Algorithms, and Models for Stacking Ensemble Learning Using Performance Metrics
https://doi.org/10.1109/TVCG.2020.3030352
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
673 lines
21 KiB
673 lines
21 KiB
import KeyCodes from '../utils/key-codes';
|
|
import range from '../utils/range';
|
|
import { isVisible, isDisabled, selectAll, getAttr } from '../utils/dom';
|
|
import { isFunction, isNull } from '../utils/inspect';
|
|
import { toInteger } from '../utils/number';
|
|
import { toString } from '../utils/string';
|
|
import { warn } from '../utils/warn';
|
|
import normalizeSlotMixin from '../mixins/normalize-slot';
|
|
import { BLink } from '../components/link/link'; // Common props, computed, data, render function, and methods
|
|
// for `<b-pagination>` and `<b-pagination-nav>`
|
|
// --- Constants ---
|
|
// Threshold of limit size when we start/stop showing ellipsis
|
|
|
|
var ELLIPSIS_THRESHOLD = 3; // Default # of buttons limit
|
|
|
|
var DEFAULT_LIMIT = 5; // --- Helper methods ---
|
|
// Make an array of N to N+X
|
|
|
|
var makePageArray = function makePageArray(startNumber, numberOfPages) {
|
|
return range(numberOfPages).map(function (val, i) {
|
|
return {
|
|
number: startNumber + i,
|
|
classes: null
|
|
};
|
|
});
|
|
}; // Sanitize the provided limit value (converting to a number)
|
|
|
|
|
|
var sanitizeLimit = function sanitizeLimit(val) {
|
|
var limit = toInteger(val) || 1;
|
|
return limit < 1 ? DEFAULT_LIMIT : limit;
|
|
}; // Sanitize the provided current page number (converting to a number)
|
|
|
|
|
|
var sanitizeCurrentPage = function sanitizeCurrentPage(val, numberOfPages) {
|
|
var page = toInteger(val) || 1;
|
|
return page > numberOfPages ? numberOfPages : page < 1 ? 1 : page;
|
|
}; // Links don't normally respond to SPACE, so we add that
|
|
// functionality via this handler
|
|
|
|
|
|
var onSpaceKey = function onSpaceKey(evt) {
|
|
if (evt.keyCode === KeyCodes.SPACE) {
|
|
evt.preventDefault(); // Stop page from scrolling
|
|
|
|
evt.stopImmediatePropagation();
|
|
evt.stopPropagation(); // Trigger the click event on the link
|
|
|
|
evt.currentTarget.click();
|
|
return false;
|
|
}
|
|
}; // --- Props ---
|
|
|
|
|
|
export var props = {
|
|
disabled: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
value: {
|
|
type: [Number, String],
|
|
default: null,
|
|
validator: function validator(value)
|
|
/* istanbul ignore next */
|
|
{
|
|
var number = toInteger(value);
|
|
|
|
if (!isNull(value) && (isNaN(number) || number < 1)) {
|
|
warn('"v-model" value must be a number greater than "0"', 'BPagination');
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
},
|
|
limit: {
|
|
type: [Number, String],
|
|
default: DEFAULT_LIMIT,
|
|
validator: function validator(value)
|
|
/* istanbul ignore next */
|
|
{
|
|
var number = toInteger(value);
|
|
|
|
if (isNaN(number) || number < 1) {
|
|
warn('Prop "limit" must be a number greater than "0"', 'BPagination');
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
},
|
|
align: {
|
|
type: String,
|
|
default: 'left'
|
|
},
|
|
pills: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
hideGotoEndButtons: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
ariaLabel: {
|
|
type: String,
|
|
default: 'Pagination'
|
|
},
|
|
labelFirstPage: {
|
|
type: String,
|
|
default: 'Go to first page'
|
|
},
|
|
firstText: {
|
|
type: String,
|
|
default: "\xAB" // '«'
|
|
|
|
},
|
|
firstNumber: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
firstClass: {
|
|
type: [String, Array, Object],
|
|
default: null
|
|
},
|
|
labelPrevPage: {
|
|
type: String,
|
|
default: 'Go to previous page'
|
|
},
|
|
prevText: {
|
|
type: String,
|
|
default: "\u2039" // '‹'
|
|
|
|
},
|
|
prevClass: {
|
|
type: [String, Array, Object],
|
|
default: null
|
|
},
|
|
labelNextPage: {
|
|
type: String,
|
|
default: 'Go to next page'
|
|
},
|
|
nextText: {
|
|
type: String,
|
|
default: "\u203A" // '›'
|
|
|
|
},
|
|
nextClass: {
|
|
type: [String, Array, Object],
|
|
default: null
|
|
},
|
|
labelLastPage: {
|
|
type: String,
|
|
default: 'Go to last page'
|
|
},
|
|
lastText: {
|
|
type: String,
|
|
default: "\xBB" // '»'
|
|
|
|
},
|
|
lastNumber: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
lastClass: {
|
|
type: [String, Array, Object],
|
|
default: null
|
|
},
|
|
labelPage: {
|
|
type: [String, Function],
|
|
default: 'Go to page'
|
|
},
|
|
pageClass: {
|
|
type: [String, Array, Object],
|
|
default: null
|
|
},
|
|
hideEllipsis: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
ellipsisText: {
|
|
type: String,
|
|
default: "\u2026" // '…'
|
|
|
|
},
|
|
ellipsisClass: {
|
|
type: [String, Array, Object],
|
|
default: null
|
|
}
|
|
}; // @vue/component
|
|
|
|
export default {
|
|
mixins: [normalizeSlotMixin],
|
|
model: {
|
|
prop: 'value',
|
|
event: 'input'
|
|
},
|
|
props: props,
|
|
data: function data() {
|
|
var curr = toInteger(this.value);
|
|
return {
|
|
// -1 signifies no page initially selected
|
|
currentPage: curr > 0 ? curr : -1,
|
|
localNumberOfPages: 1,
|
|
localLimit: DEFAULT_LIMIT
|
|
};
|
|
},
|
|
computed: {
|
|
btnSize: function btnSize() {
|
|
return this.size ? "pagination-".concat(this.size) : '';
|
|
},
|
|
alignment: function alignment() {
|
|
var align = this.align;
|
|
|
|
if (align === 'center') {
|
|
return 'justify-content-center';
|
|
} else if (align === 'end' || align === 'right') {
|
|
return 'justify-content-end';
|
|
} else if (align === 'fill') {
|
|
// The page-items will also have 'flex-fill' added
|
|
// We add text centering to make the button appearance better in fill mode
|
|
return 'text-center';
|
|
}
|
|
|
|
return '';
|
|
},
|
|
styleClass: function styleClass() {
|
|
return this.pills ? 'b-pagination-pills' : '';
|
|
},
|
|
computedCurrentPage: function computedCurrentPage() {
|
|
return sanitizeCurrentPage(this.currentPage, this.localNumberOfPages);
|
|
},
|
|
paginationParams: function paginationParams() {
|
|
// Determine if we should show the the ellipsis
|
|
var limit = this.localLimit;
|
|
var numberOfPages = this.localNumberOfPages;
|
|
var currentPage = this.computedCurrentPage;
|
|
var hideEllipsis = this.hideEllipsis;
|
|
var firstNumber = this.firstNumber;
|
|
var lastNumber = this.lastNumber;
|
|
var showFirstDots = false;
|
|
var showLastDots = false;
|
|
var numberOfLinks = limit;
|
|
var startNumber = 1;
|
|
|
|
if (numberOfPages <= limit) {
|
|
// Special case: Less pages available than the limit of displayed pages
|
|
numberOfLinks = numberOfPages;
|
|
} else if (currentPage < limit - 1 && limit > ELLIPSIS_THRESHOLD) {
|
|
if (!hideEllipsis || lastNumber) {
|
|
showLastDots = true;
|
|
numberOfLinks = limit - (firstNumber ? 0 : 1);
|
|
}
|
|
|
|
numberOfLinks = Math.min(numberOfLinks, limit);
|
|
} else if (numberOfPages - currentPage + 2 < limit && limit > ELLIPSIS_THRESHOLD) {
|
|
if (!hideEllipsis || firstNumber) {
|
|
showFirstDots = true;
|
|
numberOfLinks = limit - (lastNumber ? 0 : 1);
|
|
}
|
|
|
|
startNumber = numberOfPages - numberOfLinks + 1;
|
|
} else {
|
|
// We are somewhere in the middle of the page list
|
|
if (limit > ELLIPSIS_THRESHOLD) {
|
|
numberOfLinks = limit - 2;
|
|
showFirstDots = !!(!hideEllipsis || firstNumber);
|
|
showLastDots = !!(!hideEllipsis || lastNumber);
|
|
}
|
|
|
|
startNumber = currentPage - Math.floor(numberOfLinks / 2);
|
|
} // Sanity checks
|
|
|
|
/* istanbul ignore if */
|
|
|
|
|
|
if (startNumber < 1) {
|
|
startNumber = 1;
|
|
showFirstDots = false;
|
|
} else if (startNumber > numberOfPages - numberOfLinks) {
|
|
startNumber = numberOfPages - numberOfLinks + 1;
|
|
showLastDots = false;
|
|
}
|
|
|
|
if (showFirstDots && firstNumber && startNumber < 4) {
|
|
numberOfLinks = numberOfLinks + 2;
|
|
startNumber = 1;
|
|
showFirstDots = false;
|
|
}
|
|
|
|
var lastPageNumber = startNumber + numberOfLinks - 1;
|
|
|
|
if (showLastDots && lastNumber && lastPageNumber > numberOfPages - 3) {
|
|
numberOfLinks = numberOfLinks + (lastPageNumber === numberOfPages - 2 ? 2 : 3);
|
|
showLastDots = false;
|
|
} // Special handling for lower limits (where ellipsis are never shown)
|
|
|
|
|
|
if (limit <= ELLIPSIS_THRESHOLD) {
|
|
if (firstNumber && startNumber === 1) {
|
|
numberOfLinks = Math.min(numberOfLinks + 1, numberOfPages, limit + 1);
|
|
} else if (lastNumber && numberOfPages === startNumber + numberOfLinks - 1) {
|
|
startNumber = Math.max(startNumber - 1, 1);
|
|
numberOfLinks = Math.min(numberOfPages - startNumber + 1, numberOfPages, limit + 1);
|
|
}
|
|
}
|
|
|
|
numberOfLinks = Math.min(numberOfLinks, numberOfPages - startNumber + 1);
|
|
return {
|
|
showFirstDots: showFirstDots,
|
|
showLastDots: showLastDots,
|
|
numberOfLinks: numberOfLinks,
|
|
startNumber: startNumber
|
|
};
|
|
},
|
|
pageList: function pageList() {
|
|
// Generates the pageList array
|
|
var _this$paginationParam = this.paginationParams,
|
|
numberOfLinks = _this$paginationParam.numberOfLinks,
|
|
startNumber = _this$paginationParam.startNumber;
|
|
var currentPage = this.computedCurrentPage; // Generate list of page numbers
|
|
|
|
var pages = makePageArray(startNumber, numberOfLinks); // We limit to a total of 3 page buttons on XS screens
|
|
// So add classes to page links to hide them for XS breakpoint
|
|
// Note: Ellipsis will also be hidden on XS screens
|
|
// TODO: Make this visual limit configurable based on breakpoint(s)
|
|
|
|
if (pages.length > 3) {
|
|
var idx = currentPage - startNumber; // THe following is a bootstrap-vue custom utility class
|
|
|
|
var classes = 'bv-d-xs-down-none';
|
|
|
|
if (idx === 0) {
|
|
// Keep leftmost 3 buttons visible when current page is first page
|
|
for (var i = 3; i < pages.length; i++) {
|
|
pages[i].classes = classes;
|
|
}
|
|
} else if (idx === pages.length - 1) {
|
|
// Keep rightmost 3 buttons visible when current page is last page
|
|
for (var _i = 0; _i < pages.length - 3; _i++) {
|
|
pages[_i].classes = classes;
|
|
}
|
|
} else {
|
|
// Hide all except current page, current page - 1 and current page + 1
|
|
for (var _i2 = 0; _i2 < idx - 1; _i2++) {
|
|
// hide some left button(s)
|
|
pages[_i2].classes = classes;
|
|
}
|
|
|
|
for (var _i3 = pages.length - 1; _i3 > idx + 1; _i3--) {
|
|
// hide some right button(s)
|
|
pages[_i3].classes = classes;
|
|
}
|
|
}
|
|
}
|
|
|
|
return pages;
|
|
}
|
|
},
|
|
watch: {
|
|
value: function value(newValue, oldValue) {
|
|
if (newValue !== oldValue) {
|
|
this.currentPage = sanitizeCurrentPage(newValue, this.localNumberOfPages);
|
|
}
|
|
},
|
|
currentPage: function currentPage(newValue, oldValue) {
|
|
if (newValue !== oldValue) {
|
|
// Emit null if no page selected
|
|
this.$emit('input', newValue > 0 ? newValue : null);
|
|
}
|
|
},
|
|
limit: function limit(newValue, oldValue) {
|
|
if (newValue !== oldValue) {
|
|
this.localLimit = sanitizeLimit(newValue);
|
|
}
|
|
}
|
|
},
|
|
created: function created() {
|
|
var _this = this;
|
|
|
|
// Set our default values in data
|
|
this.localLimit = sanitizeLimit(this.limit);
|
|
this.$nextTick(function () {
|
|
// Sanity check
|
|
_this.currentPage = _this.currentPage > _this.localNumberOfPages ? _this.localNumberOfPages : _this.currentPage;
|
|
});
|
|
},
|
|
methods: {
|
|
handleKeyNav: function handleKeyNav(evt) {
|
|
var keyCode = evt.keyCode,
|
|
shiftKey = evt.shiftKey;
|
|
|
|
if (keyCode === KeyCodes.LEFT || keyCode === KeyCodes.UP) {
|
|
evt.preventDefault();
|
|
shiftKey ? this.focusFirst() : this.focusPrev();
|
|
} else if (keyCode === KeyCodes.RIGHT || keyCode === KeyCodes.DOWN) {
|
|
evt.preventDefault();
|
|
shiftKey ? this.focusLast() : this.focusNext();
|
|
}
|
|
},
|
|
getButtons: function getButtons() {
|
|
// Return only buttons that are visible
|
|
return selectAll('a.page-link', this.$el).filter(function (btn) {
|
|
return isVisible(btn);
|
|
});
|
|
},
|
|
setBtnFocus: function setBtnFocus(btn) {
|
|
btn.focus();
|
|
},
|
|
focusCurrent: function focusCurrent() {
|
|
var _this2 = this;
|
|
|
|
// We do this in `$nextTick()` to ensure buttons have finished rendering
|
|
this.$nextTick(function () {
|
|
var btn = _this2.getButtons().find(function (el) {
|
|
return toInteger(getAttr(el, 'aria-posinset')) === _this2.computedCurrentPage;
|
|
});
|
|
|
|
if (btn && btn.focus) {
|
|
_this2.setBtnFocus(btn);
|
|
} else {
|
|
// Fallback if current page is not in button list
|
|
_this2.focusFirst();
|
|
}
|
|
});
|
|
},
|
|
focusFirst: function focusFirst() {
|
|
var _this3 = this;
|
|
|
|
// We do this in `$nextTick()` to ensure buttons have finished rendering
|
|
this.$nextTick(function () {
|
|
var btn = _this3.getButtons().find(function (el) {
|
|
return !isDisabled(el);
|
|
});
|
|
|
|
if (btn && btn.focus && btn !== document.activeElement) {
|
|
_this3.setBtnFocus(btn);
|
|
}
|
|
});
|
|
},
|
|
focusLast: function focusLast() {
|
|
var _this4 = this;
|
|
|
|
// We do this in `$nextTick()` to ensure buttons have finished rendering
|
|
this.$nextTick(function () {
|
|
var btn = _this4.getButtons().reverse().find(function (el) {
|
|
return !isDisabled(el);
|
|
});
|
|
|
|
if (btn && btn.focus && btn !== document.activeElement) {
|
|
_this4.setBtnFocus(btn);
|
|
}
|
|
});
|
|
},
|
|
focusPrev: function focusPrev() {
|
|
var _this5 = this;
|
|
|
|
// We do this in `$nextTick()` to ensure buttons have finished rendering
|
|
this.$nextTick(function () {
|
|
var buttons = _this5.getButtons();
|
|
|
|
var idx = buttons.indexOf(document.activeElement);
|
|
|
|
if (idx > 0 && !isDisabled(buttons[idx - 1]) && buttons[idx - 1].focus) {
|
|
_this5.setBtnFocus(buttons[idx - 1]);
|
|
}
|
|
});
|
|
},
|
|
focusNext: function focusNext() {
|
|
var _this6 = this;
|
|
|
|
// We do this in `$nextTick()` to ensure buttons have finished rendering
|
|
this.$nextTick(function () {
|
|
var buttons = _this6.getButtons();
|
|
|
|
var idx = buttons.indexOf(document.activeElement);
|
|
var cnt = buttons.length - 1;
|
|
|
|
if (idx < cnt && !isDisabled(buttons[idx + 1]) && buttons[idx + 1].focus) {
|
|
_this6.setBtnFocus(buttons[idx + 1]);
|
|
}
|
|
});
|
|
}
|
|
},
|
|
render: function render(h) {
|
|
var _this7 = this;
|
|
|
|
var buttons = [];
|
|
var numberOfPages = this.localNumberOfPages;
|
|
var pageNumbers = this.pageList.map(function (p) {
|
|
return p.number;
|
|
});
|
|
var disabled = this.disabled;
|
|
var _this$paginationParam2 = this.paginationParams,
|
|
showFirstDots = _this$paginationParam2.showFirstDots,
|
|
showLastDots = _this$paginationParam2.showLastDots;
|
|
var currentPage = this.computedCurrentPage;
|
|
var fill = this.align === 'fill'; // Helper function and flag
|
|
|
|
var isActivePage = function isActivePage(pageNum) {
|
|
return pageNum === currentPage;
|
|
};
|
|
|
|
var noCurrentPage = this.currentPage < 1; // Factory function for prev/next/first/last buttons
|
|
|
|
var makeEndBtn = function makeEndBtn(linkTo, ariaLabel, btnSlot, btnText, btnClass, pageTest, key) {
|
|
var isDisabled = disabled || isActivePage(pageTest) || noCurrentPage || linkTo < 1 || linkTo > numberOfPages;
|
|
var pageNum = linkTo < 1 ? 1 : linkTo > numberOfPages ? numberOfPages : linkTo;
|
|
var scope = {
|
|
disabled: isDisabled,
|
|
page: pageNum,
|
|
index: pageNum - 1
|
|
};
|
|
var btnContent = _this7.normalizeSlot(btnSlot, scope) || toString(btnText) || h();
|
|
var inner = h(isDisabled ? 'span' : BLink, {
|
|
staticClass: 'page-link',
|
|
props: isDisabled ? {} : _this7.linkProps(linkTo),
|
|
attrs: {
|
|
role: 'menuitem',
|
|
tabindex: isDisabled ? null : '-1',
|
|
'aria-label': ariaLabel,
|
|
'aria-controls': _this7.ariaControls || null,
|
|
'aria-disabled': isDisabled ? 'true' : null
|
|
},
|
|
on: isDisabled ? {} : {
|
|
click: function click(evt) {
|
|
_this7.onClick(linkTo, evt);
|
|
},
|
|
keydown: onSpaceKey
|
|
}
|
|
}, [btnContent]);
|
|
return h('li', {
|
|
key: key,
|
|
staticClass: 'page-item',
|
|
class: [{
|
|
disabled: isDisabled,
|
|
'flex-fill': fill
|
|
}, btnClass],
|
|
attrs: {
|
|
role: 'presentation',
|
|
'aria-hidden': isDisabled ? 'true' : null
|
|
}
|
|
}, [inner]);
|
|
}; // Ellipsis factory
|
|
|
|
|
|
var makeEllipsis = function makeEllipsis(isLast) {
|
|
return h('li', {
|
|
key: "ellipsis-".concat(isLast ? 'last' : 'first'),
|
|
staticClass: 'page-item',
|
|
class: ['disabled', 'bv-d-xs-down-none', fill ? 'flex-fill' : '', _this7.ellipsisClass],
|
|
attrs: {
|
|
role: 'separator'
|
|
}
|
|
}, [h('span', {
|
|
staticClass: 'page-link'
|
|
}, [_this7.normalizeSlot('ellipsis-text') || toString(_this7.ellipsisText) || h()])]);
|
|
}; // Page button factory
|
|
|
|
|
|
var makePageButton = function makePageButton(page, idx) {
|
|
var active = isActivePage(page.number) && !noCurrentPage; // Active page will have tabindex of 0, or if no current page and first page button
|
|
|
|
var tabIndex = disabled ? null : active || noCurrentPage && idx === 0 ? '0' : '-1';
|
|
var attrs = {
|
|
role: 'menuitemradio',
|
|
'aria-disabled': disabled ? 'true' : null,
|
|
'aria-controls': _this7.ariaControls || null,
|
|
'aria-label': isFunction(_this7.labelPage) ? _this7.labelPage(page.number) : "".concat(_this7.labelPage, " ").concat(page.number),
|
|
'aria-checked': active ? 'true' : 'false',
|
|
'aria-posinset': page.number,
|
|
'aria-setsize': numberOfPages,
|
|
// ARIA "roving tabindex" method
|
|
tabindex: tabIndex
|
|
};
|
|
var btnContent = toString(_this7.makePage(page.number));
|
|
var scope = {
|
|
page: page.number,
|
|
index: page.number - 1,
|
|
content: btnContent,
|
|
active: active,
|
|
disabled: disabled
|
|
};
|
|
var inner = h(disabled ? 'span' : BLink, {
|
|
props: disabled ? {} : _this7.linkProps(page.number),
|
|
staticClass: 'page-link',
|
|
attrs: attrs,
|
|
on: disabled ? {} : {
|
|
click: function click(evt) {
|
|
_this7.onClick(page.number, evt);
|
|
},
|
|
keydown: onSpaceKey
|
|
}
|
|
}, [_this7.normalizeSlot('page', scope) || btnContent]);
|
|
return h('li', {
|
|
key: "page-".concat(page.number),
|
|
staticClass: 'page-item',
|
|
class: [{
|
|
disabled: disabled,
|
|
active: active,
|
|
'flex-fill': fill
|
|
}, page.classes, _this7.pageClass],
|
|
attrs: {
|
|
role: 'presentation'
|
|
}
|
|
}, [inner]);
|
|
}; // Goto first page button
|
|
// Don't render button when `hideGotoEndButtons` or `firstNumber` is set
|
|
|
|
|
|
var $firstPageBtn = h();
|
|
|
|
if (!this.firstNumber && !this.hideGotoEndButtons) {
|
|
$firstPageBtn = makeEndBtn(1, this.labelFirstPage, 'first-text', this.firstText, this.firstClass, 1, 'pagination-goto-first');
|
|
}
|
|
|
|
buttons.push($firstPageBtn); // Goto previous page button
|
|
|
|
buttons.push(makeEndBtn(currentPage - 1, this.labelPrevPage, 'prev-text', this.prevText, this.prevClass, 1, 'pagination-goto-prev')); // Show first (1) button?
|
|
|
|
buttons.push(this.firstNumber && pageNumbers[0] !== 1 ? makePageButton({
|
|
number: 1
|
|
}, 0) : h()); // First ellipsis
|
|
|
|
buttons.push(showFirstDots ? makeEllipsis(false) : h()); // Individual page links
|
|
|
|
this.pageList.forEach(function (page, idx) {
|
|
var offset = showFirstDots && _this7.firstNumber && pageNumbers[0] !== 1 ? 1 : 0;
|
|
buttons.push(makePageButton(page, idx + offset));
|
|
}); // Last ellipsis
|
|
|
|
buttons.push(showLastDots ? makeEllipsis(true) : h()); // Show last page button?
|
|
|
|
buttons.push(this.lastNumber && pageNumbers[pageNumbers.length - 1] !== numberOfPages ? makePageButton({
|
|
number: numberOfPages
|
|
}, -1) : h()); // Goto next page button
|
|
|
|
buttons.push(makeEndBtn(currentPage + 1, this.labelNextPage, 'next-text', this.nextText, this.nextClass, numberOfPages, 'pagination-goto-next')); // Goto last page button
|
|
// Don't render button when `hideGotoEndButtons` or `lastNumber` is set
|
|
|
|
var $lastPageBtn = h();
|
|
|
|
if (!this.lastNumber && !this.hideGotoEndButtons) {
|
|
$lastPageBtn = makeEndBtn(numberOfPages, this.labelLastPage, 'last-text', this.lastText, this.lastClass, numberOfPages, 'pagination-goto-last');
|
|
}
|
|
|
|
buttons.push($lastPageBtn); // Assemble the pagination buttons
|
|
|
|
var $pagination = h('ul', {
|
|
ref: 'ul',
|
|
staticClass: 'pagination',
|
|
class: ['b-pagination', this.btnSize, this.alignment, this.styleClass],
|
|
attrs: {
|
|
role: 'menubar',
|
|
'aria-disabled': disabled ? 'true' : 'false',
|
|
'aria-label': this.ariaLabel || null
|
|
},
|
|
on: {
|
|
keydown: this.handleKeyNav
|
|
}
|
|
}, buttons); // If we are `<b-pagination-nav>`, wrap in `<nav>` wrapper
|
|
|
|
if (this.isNav) {
|
|
return h('nav', {
|
|
attrs: {
|
|
'aria-disabled': disabled ? 'true' : null,
|
|
'aria-hidden': disabled ? 'true' : 'false'
|
|
}
|
|
}, [$pagination]);
|
|
}
|
|
|
|
return $pagination;
|
|
}
|
|
}; |