168 lines
5.4 KiB
JavaScript
168 lines
5.4 KiB
JavaScript
const FIRST_BUTTON_CLASS = 'erp-pagination-first';
|
|
const LAST_BUTTON_CLASS = 'erp-pagination-last';
|
|
const JUMP_BUTTON_CLASS = 'erp-pagination-jump';
|
|
const DEFAULT_PAGE_SIZE = 10;
|
|
const DEFAULT_PAGE_SIZES = [10, 20, 50, 100];
|
|
const PAGE_KEY_PATTERN = /(^page$|Page$|^page[A-Z])/;
|
|
|
|
const toNumber = value => {
|
|
const number = Number(value);
|
|
return Number.isFinite(number) ? number : 0;
|
|
};
|
|
|
|
const getNativeInputValueSetter = input => {
|
|
const prototype = Object.getPrototypeOf(input);
|
|
const descriptor = Object.getOwnPropertyDescriptor(prototype, 'value');
|
|
return descriptor && descriptor.set;
|
|
};
|
|
|
|
const setInputValue = (input, value) => {
|
|
const setter = getNativeInputValueSetter(input);
|
|
if (setter) {
|
|
setter.call(input, value);
|
|
} else {
|
|
input.value = value;
|
|
}
|
|
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
};
|
|
|
|
const getPaginationState = pagination => {
|
|
const active = pagination.querySelector('.el-pager li.is-active');
|
|
const jumpInput = pagination.querySelector('.el-pagination__editor input');
|
|
const currentPage = toNumber(
|
|
active && active.textContent ? active.textContent.trim() : jumpInput?.value
|
|
);
|
|
const pageCount = toNumber(jumpInput?.getAttribute('max'));
|
|
return {
|
|
currentPage: currentPage || 1,
|
|
pageCount: pageCount || 1,
|
|
jumpInput,
|
|
};
|
|
};
|
|
|
|
const changePage = (pagination, page) => {
|
|
const { currentPage, pageCount, jumpInput } = getPaginationState(pagination);
|
|
const targetPage = Math.min(Math.max(toNumber(page), 1), pageCount);
|
|
if (!targetPage || targetPage === currentPage) return;
|
|
|
|
const targetPager = Array.from(pagination.querySelectorAll('.el-pager li.number')).find(
|
|
item => toNumber(item.textContent && item.textContent.trim()) === targetPage
|
|
);
|
|
if (targetPager) {
|
|
targetPager.click();
|
|
return;
|
|
}
|
|
|
|
if (jumpInput) {
|
|
setInputValue(jumpInput, targetPage);
|
|
jumpInput.dispatchEvent(new Event('change', { bubbles: true }));
|
|
jumpInput.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }));
|
|
}
|
|
};
|
|
|
|
const createPaginationButton = (className, text, onClick) => {
|
|
const button = document.createElement('button');
|
|
button.type = 'button';
|
|
button.className = `erp-pagination-button ${className}`;
|
|
button.textContent = text;
|
|
button.addEventListener('click', onClick);
|
|
return button;
|
|
};
|
|
|
|
const setButtonDisabled = (button, disabled) => {
|
|
if (!button || button.disabled === disabled) return;
|
|
button.disabled = disabled;
|
|
};
|
|
|
|
const isPageConfig = value =>
|
|
value &&
|
|
typeof value === 'object' &&
|
|
('pageSize' in value || 'currentPage' in value || 'total' in value);
|
|
|
|
const normalizePageConfig = page => {
|
|
if (!isPageConfig(page)) return;
|
|
page.pageSize = DEFAULT_PAGE_SIZES.includes(toNumber(page.pageSize))
|
|
? toNumber(page.pageSize)
|
|
: DEFAULT_PAGE_SIZE;
|
|
page.pageSizes = DEFAULT_PAGE_SIZES;
|
|
};
|
|
|
|
const normalizeComponentPageConfigs = pagination => {
|
|
let component = pagination.__vueParentComponent;
|
|
while (component) {
|
|
[component.data, component.setupState].forEach(state => {
|
|
if (!state) return;
|
|
Object.keys(state)
|
|
.filter(key => PAGE_KEY_PATTERN.test(key))
|
|
.forEach(key => normalizePageConfig(state[key]));
|
|
});
|
|
component = component.parent;
|
|
}
|
|
};
|
|
|
|
const updatePaginationButtons = pagination => {
|
|
const { currentPage, pageCount, jumpInput } = getPaginationState(pagination);
|
|
const firstButton = pagination.querySelector(`.${FIRST_BUTTON_CLASS}`);
|
|
const lastButton = pagination.querySelector(`.${LAST_BUTTON_CLASS}`);
|
|
const jumpButton = pagination.querySelector(`.${JUMP_BUTTON_CLASS}`);
|
|
|
|
setButtonDisabled(firstButton, currentPage <= 1);
|
|
setButtonDisabled(lastButton, currentPage >= pageCount);
|
|
setButtonDisabled(jumpButton, !jumpInput || jumpInput.disabled);
|
|
};
|
|
|
|
const enhancePagination = pagination => {
|
|
const prevButton = pagination.querySelector('.btn-prev');
|
|
const nextButton = pagination.querySelector('.btn-next');
|
|
const jumpWrapper = pagination.querySelector('.el-pagination__jump');
|
|
|
|
normalizeComponentPageConfigs(pagination);
|
|
|
|
if (prevButton && !pagination.querySelector(`.${FIRST_BUTTON_CLASS}`)) {
|
|
const firstButton = createPaginationButton(FIRST_BUTTON_CLASS, '首页', () => {
|
|
changePage(pagination, 1);
|
|
});
|
|
prevButton.before(firstButton);
|
|
}
|
|
|
|
if (nextButton && !pagination.querySelector(`.${LAST_BUTTON_CLASS}`)) {
|
|
const lastButton = createPaginationButton(LAST_BUTTON_CLASS, '尾页', () => {
|
|
const { pageCount } = getPaginationState(pagination);
|
|
changePage(pagination, pageCount);
|
|
});
|
|
nextButton.after(lastButton);
|
|
}
|
|
|
|
if (jumpWrapper && !pagination.querySelector(`.${JUMP_BUTTON_CLASS}`)) {
|
|
const jumpButton = createPaginationButton(JUMP_BUTTON_CLASS, '跳转', () => {
|
|
const { jumpInput } = getPaginationState(pagination);
|
|
if (!jumpInput) return;
|
|
changePage(pagination, jumpInput.value);
|
|
});
|
|
jumpWrapper.after(jumpButton);
|
|
}
|
|
|
|
updatePaginationButtons(pagination);
|
|
};
|
|
|
|
const enhanceAllPaginations = () => {
|
|
document.querySelectorAll('.el-pagination').forEach(enhancePagination);
|
|
};
|
|
|
|
export const setupPaginationEnhancer = () => {
|
|
if (typeof window === 'undefined' || typeof document === 'undefined') return;
|
|
|
|
const scheduleEnhance = () => {
|
|
window.requestAnimationFrame(enhanceAllPaginations);
|
|
};
|
|
|
|
scheduleEnhance();
|
|
const observer = new MutationObserver(scheduleEnhance);
|
|
observer.observe(document.body, {
|
|
attributes: true,
|
|
attributeFilter: ['class', 'disabled'],
|
|
childList: true,
|
|
subtree: true,
|
|
});
|
|
};
|