이 스크립트는 직접 설치하는 용도가 아닙니다. 다른 스크립트에서 메타 지시문 // @require https://update.sleazyfork.org/scripts/416105/869333/Brazen%20Base%20Search%20Enhancer.js
을(를) 사용하여 포함하는 라이브러리입니다.
줄 바꿈
// ==UserScript==
// @name Brazen Base Search Enhancer
// @namespace brazen
// @version 1.0.0
// @author brazenvoid
// @license GPL-3.0-only
// @description Base class for search enhancement scripts
// @require https://greasyfork.org/scripts/375557-base-resource/code/Base%20Resource.js?version=869326
// ==/UserScript==
class BrazenBaseSearchEnhancer
{
static initialize ()
{
BrazenBaseSearchEnhancer.throwOverrideError()
//return (new XNXXSearchFilters).init()
}
static throwOverrideError ()
{
throw new Error('override this method')
}
/**
* @param {Object} options
* @param {string} options.scriptPrefix
* @param {string[]} options.itemClasses
* @param {Object} options.paginator
* @param {boolean} options.paginator.enable
* @param {string} options.paginator.listSelector
* @param {string} options.paginator.lastPageUrl
* @param {Function} options.paginator.getPageNo
* @param {Function} options.paginator.getPageUrl
* @param {Function} options.paginator.afterPagination
* @param {Object} options.configDefaults
* @param {boolean} options.configDefaults.disableItemComplianceValidation
* @param {number} options.configDefaults.paginationLimit
* @param {number} options.configDefaults.paginationThreshold
* @param {boolean} options.configDefaults.showUIAlways
*/
constructor (options)
{
options.configDefaults.disableItemComplianceValidation = false
options.configDefaults.paginationLimit = 0
options.configDefaults.paginationThreshold = 0
options.configDefaults.showUIAlways = false
/**
* Array of item compliance filters ordered in intended sequence of execution
* @type {Function[]}
* @protected
*/
this._complianceFilters = []
/**
* @type {string[]}
* @protected
*/
this._itemClasses = Array.isArray(options.itemClasses) ? options.itemClasses : [options.itemClasses]
/**
* @type {string}
* @protected
*/
this._itemClassesSelector = '.' + this._itemClasses.join(',.')
/**
* Operations to perform after script initialization
* @type {Function}
* @protected
*/
this._onAfterInitialization = null
/**
* Operations to perform after UI generation
* @type {Function}
* @protected
*/
this._onAfterUIBuild = null
/**
* Operations to perform before compliance validation. This callback can also be used to skip compliance validation by returning false.
* @type {null}
* @protected
*/
this._onBeforeCompliance = null
/**
* Operations to perform before UI generation
* @type {Function}
* @protected
*/
this._onBeforeUIBuild = null
/**
* Operations to perform after compliance checks, the first time a item is retrieved
* @type {Function}
* @protected
*/
this._onFirstHitAfterCompliance = null
/**
* Operations to perform before compliance checks, the first time a item is retrieved
* @type {Function}
* @protected
*/
this._onFirstHitBeforeCompliance = null
/**
* Get item lists from the page
* @type {Function}
* @protected
*/
this._onGetItemLists = null
/**
* Logic to hide a non-compliant item
* @type {Function}
* @protected
*/
this._onItemHide = (item) => item.hide(100)
/**
* Logic to show compliant item
* @type {Function}
* @protected
*/
this._onItemShow = (item) => item.show(100)
/**
* Retrieve settings from UI and update settings object
* @type {Function}
* @private
*/
this._onSettingsApply = null
/**
* Settings to update in the UI or elsewhere when settings store is updated
* @type {Function}
* @protected
*/
this._onSettingsStoreUpdate = null
/**
* Must return the generated settings section node
* @type {Function}
* @protected
*/
this._onUIBuild = null
/**
* Validate initiating initialization.
* Can be used to stop script init on specific pages or vice versa
* @type {Function}
* @protected
*/
this._onValidateInit = () => true
/**
* Pagination manager
* @type {{lastPageUrl: string, listSelector: string, paginatedPageNo: number, enable: boolean, lastPageNo: number, getPageNo: Function, getPageUrl: Function,
* currentPageNo: number, afterPagination: Function, targetElement: null|JQuery}}
* @private
*/
this._paginator = {
enable: options.paginator.enable,
targetElement: null,
currentPageNo: 0,
lastPageNo: 0,
lastPageUrl: options.paginator.lastPageUrl,
listSelector: options.paginator.listSelector,
paginatedPageNo: 0,
afterPagination: options.paginator.afterPagination,
getPageNo: options.paginator.getPageNo,
getPageUrl: options.paginator.getPageUrl,
}
/**
* @type {string}
* @private
*/
this._scriptPrefix = options.scriptPrefix
/**
* Local storage store with defaults
* @type {LocalStore}
* @protected
*/
this._settingsStore = new LocalStore(this._scriptPrefix + 'settings', options.configDefaults)
/**
* @type {Object}
* @protected
*/
this._settings = this._settingsStore.retrieve().get()
/**
* @type {StatisticsRecorder}
* @protected
*/
this._statistics = new StatisticsRecorder(this._scriptPrefix)
/**
* @type {BrazenUIGenerator}
* @protected
*/
this._uiGen = new BrazenUIGenerator(this._settings.showUIAlways, this._scriptPrefix)
/**
* @type {Validator}
* @protected
*/
this._validator = (new Validator(this._statistics))
}
/**
* @param {Function} eventHandler
* @param {*} parameters
* @return {*}
* @private
*/
_callEventHandler (eventHandler, ...parameters)
{
if (eventHandler) {
return eventHandler(...parameters)
}
return null
}
/**
* Filters items as per settings
* @param {JQuery} itemsList
* @param {boolean} fromObserver
* @protected
*/
_complyItemsList (itemsList, fromObserver = false)
{
let items = fromObserver ? itemsList.filter(this._itemClassesSelector) : itemsList.find(this._itemClassesSelector)
items.each((index, element) => {
let item = $(element)
if (typeof element['scriptProcessedOnce'] === 'undefined') {
element.scriptProcessedOnce = false
this._callEventHandler(this._onFirstHitBeforeCompliance, item)
}
this._validateItemCompliance(item)
if (!element['scriptProcessedOnce']) {
this._callEventHandler(this._onFirstHitAfterCompliance, item)
element.scriptProcessedOnce = true
}
this._statistics.updateUI()
})
this._validatePaginationThreshold()
}
/**
* @protected
*/
_createSettingsFormActions ()
{
return this._uiGen.createSettingsFormActions(this._settingsStore, () => {
this._callEventHandler(this._onSettingsApply)
this._statistics.reset()
for (let itemsList of this._callEventHandler(this._onGetItemLists)) {
this._complyItemsList(itemsList)
}
})
}
/**
* @param {JQuery|null} UISection
* @private
*/
_embedUI (UISection)
{
if (UISection) {
this._uiGen.constructor.appendToBody(UISection)
this._uiGen.constructor.appendToBody(this._uiGen.createSettingsShowButton('', UISection, () => {
if (!this._settings.showUIAlways) {
UISection.hide()
}
}))
this._callEventHandler(this._onSettingsStoreUpdate)
}
}
/**
* @param {Object} sanitizationRules
* @return {string}
* @protected
*/
_transformSanitizationRulesToText (sanitizationRules)
{
let sanitizationRulesText = []
for (let substitute in sanitizationRules) {
sanitizationRulesText.push(substitute + '=' + sanitizationRules[substitute].join(','))
}
return sanitizationRulesText.join('\n')
}
/**
* @param {string[]} strings
* @protected
*/
_trimAndKeepNonEmptyStrings (strings)
{
let nonEmptyStrings = []
for (let string of strings) {
string = string.trim()
if (string !== '') {
nonEmptyStrings.push(string)
}
}
return nonEmptyStrings
}
/**
* @param {string[]} sanitizationRules
* @protected
*/
_validateAndSetSanitizationRules (sanitizationRules)
{
if (sanitizationRules.length) {
let fragments, validatedTargetWords
this._settings.sanitize = {}
for (let sanitizationRule of sanitizationRules) {
if (sanitizationRule.includes('=')) {
fragments = sanitizationRule.split('=')
if (fragments[0] === '') {
fragments[0] = ' '
}
validatedTargetWords = this._trimAndKeepNonEmptyStrings(fragments[1].split(','))
if (validatedTargetWords.length) {
this._settings.sanitize[fragments[0]] = validatedTargetWords
}
}
}
}
}
/**
* @param {JQuery} item
* @protected
*/
_validateItemCompliance (item)
{
let itemComplies = true
if (!this._settings.disableItemComplianceValidation && this._callEventHandler(this._onBeforeCompliance, item) !== false) {
for (let complianceFilter of this._complianceFilters) {
if (!complianceFilter(item)) {
itemComplies = false
break
}
}
}
itemComplies ? this._callEventHandler(this._onItemShow, item) : this._callEventHandler(this._onItemHide, item)
}
_validatePaginationThreshold ()
{
if (this._paginator.enable &&
this._settings.paginationThreshold &&
(this._settings.paginationLimit <= 0 || (this._paginator.paginatedPageNo - this._paginator.currentPageNo <= this._settings.paginationLimit)) &&
this._paginator.paginatedPageNo < this._paginator.lastPageNo
) {
let compliantItems = this._paginator.targetElement.find(this._itemClassesSelector + ':visible')
if (compliantItems.length < this._settings.paginationThreshold) {
let nextPageUrl = this._paginator.getPageUrl(++this._paginator.paginatedPageNo)
let sandbox = $('<div id="brazen-sandbox" hidden/>')
sandbox.appendTo('body')
sandbox.load(nextPageUrl + ' ' + this._paginator.listSelector, '', () => {
sandbox.find(this._itemClassesSelector).insertAfter(this._paginator.targetElement.find(this._itemClassesSelector + ':last'))
sandbox.remove()
this._paginator.afterPagination(this._paginator)
})
}
}
}
/**
* Initialize the script and do basic UI removals
*/
init ()
{
try {
if (this._callEventHandler(this._onValidateInit)) {
if (this._paginator.enable) {
this._paginator.targetElement = $(this._paginator.listSelector + ':first')
this._paginator.currentPageNo = this._paginator.getPageNo(window.location.href)
this._paginator.lastPageNo = this._paginator.getPageNo(this._paginator.lastPageUrl)
this._paginator.paginatedPageNo = this._paginator.currentPageNo
}
this._callEventHandler(this._onBeforeUIBuild)
this._embedUI(this._callEventHandler(this._onUIBuild))
this._callEventHandler(this._onAfterUIBuild)
for (let itemsList of this._callEventHandler(this._onGetItemLists)) {
ChildObserver.create().onNodesAdded((itemsAdded) => this._complyItemsList($(itemsAdded), true).observe(itemsList))
this._complyItemsList(itemsList)
}
this._uiGen.updateStatus('Initial run completed.')
this._callEventHandler(this._onAfterInitialization)
this._settingsStore.onChange(() => this._callEventHandler(this._onSettingsStoreUpdate))
}
} catch (error) {
console.error(this._scriptPrefix + 'script encountered an error: ' + error)
}
}
}