您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
Helper for client side customized pagination
当前为
此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.greasyfork.icu/scripts/424499/918391/Brazen%20Paginator.js
// ==UserScript== // @name Brazen Paginator // @namespace brazenvoid // @version 1.0.0 // @author brazenvoid // @license GPL-3.0-only // @description Helper for client side customized pagination // ==/UserScript== class BrazenPaginator { /** * @callback PaginatorAfterPaginationEventHandler * @param {BrazenPaginator} paginator */ /** * @callback PaginatorGetPageNoFromUrlHandler * @param {string} pageUrl * @param {BrazenPaginator} paginator */ /** * @callback PaginatorGetPageUrlFromPageNoHandler * @param {number} pageNo * @param {BrazenPaginator} paginator */ /** * @callback PaginatorGetPaginationElementForPageNoHandler * @param {number} pageNo * @param {BrazenPaginator} paginator */ /** * @param {JQuery} paginationWrapper * @param {JQuery.Selector} listSelector * @param {JQuery.Selector} itemClassesSelector * @param {string } lastPageUrl * @return {BrazenPaginator} */ static create (paginationWrapper, listSelector, itemClassesSelector, lastPageUrl) { return (new BrazenPaginator).configure(paginationWrapper, listSelector, itemClassesSelector, lastPageUrl) } /** * */ constructor () { /** * @type {number} * @private */ this._currentPageNo = 0 /** * @type {JQuery.Selector} * @private */ this._itemClassesSelector = '' /** * @type {number} * @private */ this._lastPageNo = 0 /** * @type {string} * @private */ this._lastPageUrl = '' /** * @type {JQuery.Selector} * @private */ this._listSelector = '' /** * @type {boolean} * @private */ this._pageConcatenated = false /** * @type {number} * @private */ this._paginatedPageNo = 0 /** * @type {JQuery} * @private */ this._paginationWrapper = null /** * @type {JQuery} * @private */ this._targetElement = null // Events and callbacks /** * @type {PaginatorAfterPaginationEventHandler} * @private */ this._onAfterPagination = null /** * @type {PaginatorGetPageNoFromUrlHandler} * @private */ this._onGetPageNoFromUrl = null /** * @type {PaginatorGetPageUrlFromPageNoHandler} * @private */ this._onGetPageUrlFromPageNo = null /** * @type {PaginatorGetPaginationElementForPageNoHandler} * @private */ this._onGetPaginationElementForPageNo = null } _conformUIToNewPaginatedState () { if (this._pageConcatenated) { this._pageConcatenated = false let currentPageElement = this.getPaginationElementForPageNo(this._currentPageNo) let newSubsequentPageNo = this._paginatedPageNo + 1 let newSubsequentPageNoUrl = this.getPageUrlFromPageNo(newSubsequentPageNo) // Mutate current page no element to show paginated page numbers currentPageElement.text(this._currentPageNo + '-' + this._paginatedPageNo) // Get next pages' pagination elements let currentNextPageElements = currentPageElement.nextAll() if (this._paginatedPageNo === this._lastPageNo) { // Delete all pagination elements if last page is paginated currentNextPageElements.remove() } else { // Determine whether the paginated page immediately precedes the last page if (newSubsequentPageNo !== this._lastPageNo) { // If not so, determine whether pagination element for the page following the paginated page exists let newSubsequentPageElement = this.getPaginationElementForPageNo(newSubsequentPageNo) if (!newSubsequentPageElement.length) { // If it does not exist then try getting the old next page no element let oldSubsequentPageElement = this.getPaginationElementForPageNo(this._currentPageNo + 1) if (oldSubsequentPageElement.length) { // If it does exist then mutate it for this purpose oldSubsequentPageElement.attr('href', newSubsequentPageNoUrl).text(newSubsequentPageNo) } else { // If even that does not exist, then clone the less desirable alternative; the last page element and mutate it to this use let lastPageElement = this.getPaginationElementForPageNo(this._lastPageNo) lastPageElement.clone().insertAfter(currentPageElement).attr('href', newSubsequentPageNoUrl).text(newSubsequentPageNo) } } // Remove any other pagination elements for already paginated pages currentNextPageElements.each((index, element) => { let paginationLink = $(element) let paginationLinkUrl = paginationLink.attr('href') if (paginationLinkUrl && this.getPageNoFromUrl(paginationLinkUrl) <= this._paginatedPageNo) { paginationLink.remove() } }) } } Utilities.callEventHandler(this._onAfterPagination, [this]) } } /** * @param {number} threshold * @param {number} limit * @private */ _loadAndParseNextPage (threshold, limit) { let lastPageHasNotBeenReached = this._paginatedPageNo < this._lastPageNo let paginationLimitHasNotBeenMet = limit > 0 && (this._paginatedPageNo - this._currentPageNo) < limit let compliantItemsAreLessThanTheThreshold = this._targetElement.find(this._itemClassesSelector + ':not(.noncompliant-item)').length < threshold if (lastPageHasNotBeenReached && paginationLimitHasNotBeenMet && compliantItemsAreLessThanTheThreshold) { this._sandbox.load(this.getPageUrlFromPageNo(++this._paginatedPageNo) + ' ' + this._listSelector, '', () => { this._pageConcatenated = true this._sandbox.find(this._itemClassesSelector).insertAfter(this._targetElement.find(this._itemClassesSelector + ':last')) this._sandbox.empty() }) } else { this._conformUIToNewPaginatedState() } } /** * @param {JQuery} paginationWrapper * @param {JQuery.Selector} listSelector * @param {JQuery.Selector} itemClassesSelector * @param {string } lastPageUrl * @return {BrazenPaginator} */ configure (paginationWrapper, listSelector, itemClassesSelector, lastPageUrl) { this._lastPageUrl = lastPageUrl this._listSelector = listSelector this._itemClassesSelector = itemClassesSelector this._paginationWrapper = paginationWrapper return this } getCurrentPageNo () { return this._currentPageNo } getLastPageNo () { return this._lastPageNo } getListSelector () { return this._listSelector } /** * @param {string} pageUrl * @return {number} */ getPageNoFromUrl (pageUrl) { return Utilities.callEventHandlerOrFail('onGetPageNoFromUrl', this._onGetPageNoFromUrl, [pageUrl, this]) } /** * @param {number} pageNo * @return {string} */ getPageUrlFromPageNo (pageNo) { return Utilities.callEventHandlerOrFail('onGetPageUrlFromPageNo', this._onGetPageUrlFromPageNo, [pageNo, this]) } /** * @param {number} pageNo * @return {JQuery} */ getPaginationElementForPageNo (pageNo) { return Utilities.callEventHandlerOrFail('onGetPaginationElementForPageNo', this._onGetPaginationElementForPageNo, [pageNo, this]) } getPaginatedPageNo () { return this._paginatedPageNo } getPaginationWrapper () { return this._paginationWrapper } initialize () { this._currentPageNo = this.getPageNoFromUrl(window.location.href) this._lastPageNo = this.getPageNoFromUrl(this._lastPageUrl) this._paginatedPageNo = this._currentPageNo this._sandbox = $('<div id="brazen-paginator-sandbox" hidden/>').appendTo('body') this._targetElement = $(this._listSelector + ':first') return this } /** * @param {PaginatorAfterPaginationEventHandler} handler * @return {this} */ onAfterPagination (handler) { this._onAfterPagination = handler return this } /** * @param {PaginatorGetPageNoFromUrlHandler} handler * @return {this} */ onGetPageNoFromUrl (handler) { this._onGetPageNoFromUrl = handler return this } /** * @param {PaginatorGetPageUrlFromPageNoHandler} handler * @return {this} */ onGetPageUrlFromPageNo (handler) { this._onGetPageUrlFromPageNo = handler return this } /** * @param {PaginatorGetPaginationElementForPageNoHandler} handler * @return {this} */ onGetPaginationElementForPageNo (handler) { this._onGetPaginationElementForPageNo = handler return this } run (threshold, limit) { if (this._paginationWrapper.length && threshold) { this._loadAndParseNextPage(threshold, limit) } return this } }