لا ينبغي أن لا يتم تثبيت هذا السكريت مباشرة. هو مكتبة لسكبتات لتشمل مع التوجيه الفوقية // @require https://update.sleazyfork.org/scripts/416105/1114720/Brazen%20Base%20Search%20Enhancer.js
// ==UserScript==
// @name Brazen Base Search Enhancer
// @namespace brazenvoid
// @version 3.2.1
// @author brazenvoid
// @license GPL-3.0-only
// @description Base class for search enhancement scripts
// ==/UserScript==
// Selectors
const SELECTOR_BUTTON_DISABLE_FILTERS = 'brazen-disable-filters'
const SELECTOR_BUTTON_SUBSCRIPTION_LOADER = 'brazen-subscriptions-loader'
const SELECTOR_BUTTON_SYNC = '#brazen-sync'
const SELECTOR_INPUT_RESTORE_CONFIG = '#brazen-restore-settings'
// Preset filter configuration keys
const CONFIG_PAGINATOR_LIMIT = 'Pagination Limit'
const CONFIG_PAGINATOR_THRESHOLD = 'Pagination Threshold'
const FILTER_DURATION_RANGE = 'Duration'
const FILTER_PERCENTAGE_RATING_RANGE = 'Rating'
const FILTER_SUBSCRIBED_VIDEOS = 'Hide Subscribed Videos'
const FILTER_TEXT_BLACKLIST = 'Blacklist'
const FILTER_TEXT_SEARCH = 'Search'
const FILTER_TEXT_SANITIZATION = 'Text Sanitization Rules'
const FILTER_TEXT_WHITELIST = 'Whitelist'
const FILTER_UNRATED = 'Unrated'
const FILTER_VIEWED_VIDEOS = 'Hide Browsed Videos'
// const FILTER_WATCHED_VIDEOS = 'Hide Watched Videos'
const STORE_SUBSCRIPTIONS = 'Account Subscriptions'
// const STORE_VIEWED_ADDRESSES = 'Viewed Addresses Store'
// const STORE_WATCHED_ADDRESSES = 'Watched Addresses Store'
const UI_MARK_WATCHED_VIDEOS = 'Mark Watched Videos'
// Item preset attributes
const ITEM_ATTRIBUTE_DURATION = 'presetDurationRange'
const ITEM_ATTRIBUTE_NAME = 'presetName'
const ITEM_ATTRIBUTE_RATING = 'presetPercentageRating'
const ITEM_ATTRIBUTE_USER = 'username'
const ITEM_PROCESSED_ONCE = 'scriptItemProcessedOnce'
// Configuration
const OPTION_ALWAYS_SHOW_SETTINGS_PANE = 'Always Show Settings Pane'
const OPTION_DISABLE_COMPLIANCE_VALIDATION = 'Disable All Filters'
class BrazenItemAttributesResolver
{
/**
* @callback ItemAttributesResolverCallback
* @param {JQuery} item
* @return {*}
*/
/**
* @param {JQuery.Selector} itemPageLinkSelector
* @param {JQuery.Selector} itemPageDeepAnalysisSelector
*/
constructor(itemPageLinkSelector, itemPageDeepAnalysisSelector)
{
/**
* @type {{}}
* @private
*/
this._attributes = {}
/**
* @type {{}}
* @private
*/
this._deepAttributes = {}
/**
* @type {boolean}
* @private
*/
this._hasDeepAttributes = false
/**
* @type {JQuery.Selector}
* @protected
*/
this._itemPageLinkSelector = itemPageLinkSelector
/**
* @type {JQuery.Selector}
* @protected
*/
this._itemPageDeepAnalysisSelector = itemPageDeepAnalysisSelector
/**
* @type {JQuery<HTMLElement> | jQuery | HTMLElement}
* @private
*/
this._sandbox = $('<div id="brazen-item-attributes-resolver-sandbox" hidden/>').appendTo('body')
}
/**
* @param {string} attributeName
* @returns {string}
* @private
*/
_generateAttributeName(attributeName)
{
return 'scriptItemAttribute' + attributeName[0].toUpperCase() + attributeName.slice(1)
}
/**
* @param {string} name
* @param {ItemAttributesResolverCallback} resolutionCallback
* @returns {this}
*/
addAttribute(name, resolutionCallback)
{
this._attributes[name] = resolutionCallback
return this
}
/**
* @param {string} name
* @param {ItemAttributesResolverCallback} resolutionCallback
* @returns {this}
*/
addDeepAttribute(name, resolutionCallback)
{
this._deepAttributes[name] = resolutionCallback
this._hasDeepAttributes = true
return this
}
/**
* @param {JQuery} item
* @param {string} attributeName
* @returns {*}
*/
getAttribute(item, attributeName)
{
return item[0][this._generateAttributeName(attributeName)]
}
/**
* @param {JQuery} item
* @param {Function|null} afterResolutionCallback
*/
resolveAttributes(item, afterResolutionCallback = null)
{
let element = item[0]
for (const attributeName in this._attributes) {
element[this._generateAttributeName(attributeName)] = this._attributes[attributeName](item)
}
if (this._hasDeepAttributes) {
this._sandbox.load(item.find(this._itemPageLinkSelector).attr('href') + ' ' + this._itemPageDeepAnalysisSelector, () => {
for (const attributeName in this._deepAttributes) {
element[this._generateAttributeName(attributeName)] = this._deepAttributes[attributeName](this._sandbox)
}
this._sandbox.empty()
})
}
}
}
class BrazenBaseSearchEnhancer
{
/**
* @typedef {{configKey: string, validate: SearchEnhancerFilterValidationCallback, comply: SearchEnhancerFilterComplianceCallback}} ComplianceFilter
*/
/**
* @callback SearchEnhancerFilterValidationCallback
* @param {*} configValues
* @return boolean
*/
/**
* @callback SearchEnhancerFilterComplianceCallback
* @param {JQuery} item
* @param {*} configValues
* @return {*}
*/
/**
* @callback SubscriptionsFilterExclusionsCallback
* @return {boolean}
*/
/**
* @return BrazenBaseSearchEnhancer
*/
static initialize()
{
BrazenBaseSearchEnhancer.throwOverrideError()
}
static throwOverrideError()
{
throw new Error('Method must be overridden.')
}
/**
* @param {Object} configuration
* @param {Object} configuration.about
* @param {string} configuration.about.name
* @param {string} configuration.about.link
* @param {string} configuration.about.version
* @param {string} configuration.about.released
* @param {boolean} configuration.isUserLoggedIn
* @param {JQuery.Selector} configuration.itemPageDeepAnalysisSelector
* @param {JQuery.Selector} configuration.itemPageLinkSelector
* @param {string} configuration.itemSelectors
*/
constructor(configuration)
{
/**
* Array of item compliance filters ordered in intended sequence of execution
* @type {ComplianceFilter[]}
* @private
*/
this._complianceFilters = []
/**
* @type {boolean}
* @private
*/
this._isUserLoggedIn = configuration.isUserLoggedIn
/**
* @type {string}
* @private
*/
this._itemClassesSelector = configuration.itemSelectors
/**
* Pagination manager
* @type BrazenPaginator|null
* @private
*/
this._paginator = null
/**
* @type {BrazenItemAttributesResolver}
* @protected
*/
this._itemAttributesResolver = new BrazenItemAttributesResolver(configuration.itemPageLinkSelector, configuration.itemPageDeepAnalysisSelector)
/**
* @type {{name: string, link: string, version: string, released: string}}
* @private
*/
this._scriptBrandingInformation = configuration.about
/**
* @type {BrazenSubscriptionsLoader}
* @protected
*/
this._subscriptionsLoader = new BrazenSubscriptionsLoader(
(status) => this._subscriptionsLoaderButton.text(status),
(subscriptions) => {
this._configurationManager.getField(STORE_SUBSCRIPTIONS).value = subscriptions.length ? '"' + subscriptions.join('""') + '"' : ''
this._configurationManager.save()
BrazenUIGenerator.addTransientChangeToButton(
this._subscriptionsLoaderButton, 'btn-secondary', 'btn-success', 'Load Subscriptions', 'Subscriptions Loaded!')
})
/**
* @type {JQuery}
* @protected
*/
this._subscriptionsLoaderButton = null
/**
* @type {JQuery<HTMLElement> | jQuery | HTMLElement}
* @protected
*/
this._syncConfigButton = null
/**
* @type {BrazenUIGenerator}
* @protected
*/
this._uiGen = new BrazenUIGenerator(configuration.about.name)
/**
* Local storage store with defaults
* @type {BrazenConfigurationManager}
* @protected
*/
this._configurationManager = BrazenConfigurationManager.create(this._uiGen)
.addFlagField(OPTION_DISABLE_COMPLIANCE_VALIDATION, 'Disables all search filters.')
.addFlagField(OPTION_ALWAYS_SHOW_SETTINGS_PANE, 'Always show configuration interface.')
.onExternalConfigurationChange(() => this._syncConfigButton.prop('disable', false))
// Events
/**
* 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}
* @param {JQuery} item
* @protected
*/
this._onFirstHitAfterCompliance = null
/**
* Operations to perform before compliance checks, the first time a item is retrieved
* @type {Function}
* @param {JQuery} item
* @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}
* @param {JQuery} item
* @protected
*/
this._onItemHide = (item) => item.addClass('noncompliant-item').hide()
/**
* Logic to show compliant item
* @type {Function}
* @param {JQuery} item
* @protected
*/
this._onItemShow = (item) => item.removeClass('noncompliant-item').show()
/**
* Must be used to compose the UI
* @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
}
/**
* @param {JQuery} button
* @private
*/
_onGlobalDisableClick(button)
{
if (button.hasClass('btn-danger')) {
this._configurationManager.getField(OPTION_DISABLE_COMPLIANCE_VALIDATION).value = true
button.removeClass('btn-danger').addClass('btn-success').text('Enable Filters')
} else {
this._configurationManager.getField(OPTION_DISABLE_COMPLIANCE_VALIDATION).value = false
button.removeClass('btn-success').addClass('btn-danger').text('Disable Filters')
}
this._validateCompliance()
}
/**
* @private
*/
_buildNativeUI()
{
// Shortcuts Menu
// -- Add sync config button
this._syncConfigButton = this._uiGen
.createShortcutButton('Sync Config', 'warning', () => this._onResetConfig())
.attr('id', SELECTOR_BUTTON_SYNC.slice(1))
.prop('disabled', true)
// -- Add global disable button
let globalDisable = this._configurationManager.getField(OPTION_DISABLE_COMPLIANCE_VALIDATION)
if (globalDisable.value) {
this._uiGen.createShortcutButton('Enable Filters', 'success', (button) => this._onGlobalDisableClick(button))
} else {
this._uiGen.createShortcutButton('Disable Filters', 'danger', (button) => this._onGlobalDisableClick(button))
}
// Accordion Tabs
// -- Add about tab
this._uiGen.createAccordionTab('About', [
this._uiGen.createFormLabelGroup(
'Name', `<a href="${this._scriptBrandingInformation.link}" target="_blank">${this._scriptBrandingInformation.name}</a>`),
this._uiGen.createFormLabelGroup(
'Version', this._scriptBrandingInformation.version),
this._uiGen.createFormLabelGroup(
'Release Date', this._scriptBrandingInformation.released),
this._uiGen.createFormLabelGroup(
'Author', '<a href="https://greasyfork.org/en/users/220654-brazenvoid" target="_blank">Brazenvoid</a>'),
this._uiGen.createFormLabelGroup(
'Support', '<a href="https://www.patreon.com/brazen_scripts" target="_blank">Patreon</a>'),
])
// Actions Menu
// -- Add Apply Config Button
this._uiGen.createActionsButton('Apply', 'warning', () => {
this._configurationManager.update()
this._validateCompliance()
})
// -- Add Save Config Button
this._uiGen.createActionsButton('Save', 'success', () => {
this._configurationManager.save()
this._validateCompliance()
})
// -- Add Reset Config Button
this._uiGen.createActionsButton('Reset', 'danger', () => this._onResetConfig())
}
/**
* @param item
* @private
*/
_complyItem(item)
{
let globalDisableState = this._configurationManager.getValue(OPTION_DISABLE_COMPLIANCE_VALIDATION)
let globalBeforeComplianceValidation = Utilities.callEventHandler(this._onBeforeCompliance, [item], true)
let itemComplies = true
if (!globalDisableState && globalBeforeComplianceValidation && this._validateItemWhiteList(item)) {
let configField
for (let complianceFilter of this._complianceFilters) {
configField = this._configurationManager.getFieldOrFail(complianceFilter.configKey)
if (complianceFilter.validate(this._configurationManager.getValue(configField))) {
itemComplies = complianceFilter.comply(item, this._configurationManager.getValue(configField))
if (!itemComplies) {
this._configurationManager.trackState(configField)
break
}
}
}
}
itemComplies ? Utilities.callEventHandler(this._onItemShow, [item]) : Utilities.callEventHandler(this._onItemHide, [item])
item.css('opacity', 'unset')
}
/**
* @param {string} configKey
* @param {SearchEnhancerFilterValidationCallback|null} validationCallback
* @param {SearchEnhancerFilterComplianceCallback} complianceCallback
* @protected
*/
_addItemComplexComplianceFilter(configKey, validationCallback, complianceCallback)
{
this._addItemComplianceFilter(configKey, complianceCallback, validationCallback)
}
/**
* @param {string} configKey
* @param {SearchEnhancerFilterComplianceCallback|string} action
* @param {SearchEnhancerFilterValidationCallback|null} validationCallback
* @protected
*/
_addItemComplianceFilter(configKey, action, validationCallback = null)
{
let configType = this._configurationManager.getField(configKey).type
if (typeof action === 'string') {
let attributeName = action
switch (configType) {
case CONFIG_TYPE_FLAG:
action = (item) => this.getItemAttribute(item, attributeName)
break
case CONFIG_TYPE_RANGE:
action = (item, range) => Validator.isInRange(this.getItemAttribute(item, attributeName), range.minimum, range.maximum)
break
default:
throw new Error('Associated config type requires explicit action callback definition.')
}
}
if (validationCallback === null) {
switch (configType) {
case CONFIG_TYPE_FLAG:
case CONFIG_TYPE_RADIOS_GROUP:
case CONFIG_TYPE_SELECT:
validationCallback = (value) => value
break
case CONFIG_TYPE_CHECKBOXES_GROUP:
validationCallback = (valueKeys) => valueKeys.length
break
case CONFIG_TYPE_NUMBER:
validationCallback = (value) => value > 0
break
case CONFIG_TYPE_RANGE:
validationCallback = (range) => range.minimum > 0 || range.maximum > 0
break
case CONFIG_TYPE_RULESET:
validationCallback = (rules) => rules.length
break
case CONFIG_TYPE_TEXT:
validationCallback = (value) => value.length
break
default:
throw new Error('Associated config type requires explicit validation callback definition.')
}
}
this._complianceFilters.push({
configKey: configKey,
validate: validationCallback,
comply: action,
})
}
/**
* @param {string} helpText
* @protected
*/
_addItemBlacklistFilter(helpText)
{
this._configurationManager
.addRulesetField(FILTER_TEXT_BLACKLIST, helpText)
.onOptimize = (rules) => Utilities.buildWholeWordMatchingRegex(rules) ?? ''
this._addItemComplexComplianceFilter(
FILTER_TEXT_BLACKLIST,
(value) => value.length,
(item, value) => this.getItemAttribute(item, ITEM_ATTRIBUTE_NAME).match(value) === null,
)
}
/**
* @param {string|null} helpText
* @protected
*/
_addItemDurationRangeFilter(helpText = null)
{
this._configurationManager.addRangeField(FILTER_DURATION_RANGE, 'seconds', 0, 100000, helpText ?? 'Filter items by duration.')
this._addItemComplianceFilter(FILTER_DURATION_RANGE, (item, range) => {
let duration = this.getItemAttribute(item, ITEM_ATTRIBUTE_DURATION)
return duration > 0 ? Validator.isInRange(duration, range.minimum, range.maximum) : duration === -1
})
}
/**
* @param {string|null} helpText
* @param {string|null} unratedHelpText
* @protected
*/
_addItemPercentageRatingRangeFilter(helpText = null, unratedHelpText = null)
{
this._configurationManager.addRangeField(FILTER_PERCENTAGE_RATING_RANGE, '%', 0, 100000, helpText ?? 'Filter items by percentage rating.')
.addFlagField(FILTER_UNRATED, unratedHelpText ?? 'Hide items with zero or no rating.')
this._addItemComplianceFilter(FILTER_PERCENTAGE_RATING_RANGE, (item, range) => {
let rating = this.getItemAttribute(item, ITEM_ATTRIBUTE_RATING)
return rating === 0 ? !this._configurationManager.getValue(FILTER_UNRATED) : Validator.isInRange(rating, range.minimum, range.maximum)
})
}
/**
* @param {string} helpText
* @protected
*/
_addItemTextSanitizationFilter(helpText)
{
let field = this._configurationManager.addRulesetField(FILTER_TEXT_SANITIZATION, helpText, false)
field.onTranslateFromUI = (rules) => {
let sanitizationRules = {}, fragments, validatedTargetWords
for (let sanitizationRule of rules) {
if (sanitizationRule.includes('=')) {
fragments = sanitizationRule.split('=')
if (fragments[0] === '') {
fragments[0] = ' '
}
validatedTargetWords = Utilities.trimAndKeepNonEmptyStrings(fragments[1].split(','))
if (validatedTargetWords.length) {
sanitizationRules[fragments[0]] = validatedTargetWords
}
}
}
return sanitizationRules
}
field.onFormatForUI = (rules) => {
let sanitizationRulesText = []
for (let substitute in rules) {
sanitizationRulesText.push(substitute + '=' + rules[substitute].join(','))
}
return sanitizationRulesText
}
field.onOptimize = (rules) => {
let optimizedRules = {}
for (const substitute in rules) {
optimizedRules[substitute] = Utilities.buildWholeWordMatchingRegex(rules[substitute])
}
return optimizedRules
}
}
/**
* @param {string|null} helpText
* @protected
*/
_addItemTextSearchFilter(helpText = null)
{
this._configurationManager.addTextField(FILTER_TEXT_SEARCH, helpText ?? 'Show videos with these comma separated words in their names.')
this._addItemComplianceFilter(FILTER_TEXT_SEARCH, (item, value) => this.getItemAttribute(item, ITEM_ATTRIBUTE_NAME).includes(value))
}
// /**
// * @protected
// */
// _addItemCustomWatchedFilters ()
// {
// this._configurationManager.
// addFlagField(FILTER_VIEWED_VIDEOS, 'Tracks and hides all items present on opened pages on next page load. Should be purged regularly.').
// addFlagField(FILTER_WATCHED_VIDEOS, 'Tracks and hides 3,000 recent seen items.').
// addTextField(STORE_VIEWED_ADDRESSES, '').
// addTextField(STORE_WATCHED_ADDRESSES, '')
// }
/**
* @param {string} helpText
* @protected
*/
_addItemWhitelistFilter(helpText)
{
this._configurationManager
.addRulesetField(FILTER_TEXT_WHITELIST, helpText)
.onOptimize = (rules) => Utilities.buildWholeWordMatchingRegex(rules)
}
_addPaginationConfiguration()
{
this._configurationManager
.addNumberField(CONFIG_PAGINATOR_LIMIT, 'pages', 1, 50, 'Limit paginator to concatenate the specified number of maximum pages.')
.addNumberField(CONFIG_PAGINATOR_THRESHOLD, 'results', 1, 1000, 'Make paginator ensure the specified number of minimum results.')
}
/**
* @param {SubscriptionsFilterExclusionsCallback} exclusionsCallback Add page exclusions here
* @return {BrazenSubscriptionsLoader}
* @protected
*/
_addSubscriptionsFilter(exclusionsCallback)
{
this._configurationManager
.addFlagField(FILTER_SUBSCRIBED_VIDEOS, 'Hide videos from subscribed channels.')
.addTextField(STORE_SUBSCRIPTIONS, 'Recorded subscription accounts.')
this._addItemComplexComplianceFilter(
FILTER_SUBSCRIBED_VIDEOS,
(value) => value && this._isUserLoggedIn && exclusionsCallback(),
(item) => {
let username = this.getItemAttribute(item, ITEM_ATTRIBUTE_USER)
return username === false ?
true : !(new RegExp('"([^"]*' + username + '[^"]*)"')).test(this._configurationManager.getValue(STORE_SUBSCRIPTIONS))
})
return this._subscriptionsLoader
}
/**
* 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.css('opacity', 0.5).each((index, element) => {
let item = $(element)
// First run processing
if (typeof element[ITEM_PROCESSED_ONCE] === 'undefined') {
element[ITEM_PROCESSED_ONCE] = false
this._itemAttributesResolver.resolveAttributes(item)
Utilities.callEventHandler(this._onFirstHitBeforeCompliance, [item])
}
// Compliance filtering
this._complyItem(item)
// After first run processing
if (!element[ITEM_PROCESSED_ONCE]) {
Utilities.callEventHandler(this._onFirstHitAfterCompliance, [item])
element[ITEM_PROCESSED_ONCE] = true
}
})
this._configurationManager.updateTrackersInterface()
}
/**
* @protected
* @return {JQuery}
*/
_createPaginationTab()
{
return this._uiGen.createAccordionTab('Pagination', [
this._configurationManager.createElement(CONFIG_PAGINATOR_THRESHOLD),
this._configurationManager.createElement(CONFIG_PAGINATOR_LIMIT),
])
}
/**
* @protected
* @return {JQuery}
*/
_createSettingsBackupRestoreTab()
{
let inputControl = $(`<input id="${SELECTOR_INPUT_RESTORE_CONFIG}" class="form-control" type="text">`)
return this._uiGen.createAccordionTab('Backup & Restore', [
this._uiGen.createFormHelpText(
this._uiGen.createFormGroup(
this._uiGen
.createButton('Backup Configuration', 'secondary', (button) => this._onBackupSettings(button))
.addClass('btn-block'),
),
null,
'Backup settings to the clipboard.',
),
this._uiGen.createFormHelpText(this._uiGen.createFormGroup(inputControl), inputControl, 'Paste backed up configuration.'),
this._uiGen.createFormHelpText(
this._uiGen.createFormGroup(
this._uiGen
.createButton('Restore Configuration', 'danger', (button) => this._onRestoreSettings(button))
.addClass('btn-block'),
),
null,
'Restore backup settings.',
),
])
}
/**
* @protected
* @return {JQuery}
*/
_createSubscriptionLoaderTab()
{
this._subscriptionsLoaderButton = this._uiGen.createButton('Load Subscriptions', 'secondary', (button) => {
if (this._isUserLoggedIn) {
this._subscriptionsLoaderButton.removeClass('btn-secondary').addClass('btn-warning')
this._subscriptionsLoader.run()
} else {
BrazenUIGenerator.addTransientChangeToButton(
button, 'btn-secondary', 'btn-danger', 'Load Subscriptions', 'Please login before proceeding.')
}
}).attr('id', SELECTOR_BUTTON_SUBSCRIPTION_LOADER)
return this._uiGen.createFormHelpText(
this._uiGen.createFormGroup(this._subscriptionsLoaderButton), null, 'Makes a copy of your subscriptions in cache for related filters.')
}
/**
* @param {JQuery} button
* @private
*/
_onBackupSettings(button)
{
navigator.clipboard
.writeText(this._configurationManager.backup())
.then(() => BrazenUIGenerator.addTransientChangeToButton(
button, 'btn-secondary', 'btn-success', 'Backup Configuration', 'Config Copied To Clipboard!'))
.catch(() => button.removeClass('btn-secondary').addClass('btn-danger').text('Error!'))
}
/**
* @private
*/
_onResetConfig()
{
this._configurationManager.revertChanges()
this._validateCompliance()
}
/**
* @param {JQuery} button
* @return {boolean}
* @private
*/
_onRestoreSettings(button)
{
let settings = $('#' + SELECTOR_INPUT_RESTORE_CONFIG).val().trim()
if (!settings) {
BrazenUIGenerator.addTransientContentChangeToButton(button, 'Restore Configuration', 'No Configuration Found!')
} else {
try {
this._configurationManager.restore(settings)
BrazenUIGenerator.addTransientChangeToButton(
button, 'btn-danger', 'btn-success', 'Restore Configuration', 'Configuration Restored!')
this._validateCompliance()
} catch (e) {
button.text('Error!')
return false
}
}
return true
}
/**
* @protected
*/
_setupUI()
{
this.constructor.throwOverrideError()
}
/**
* @protected
*/
_setupAttributes()
{
this.constructor.throwOverrideError()
}
/**
* @protected
*/
_setupCompliance()
{
this.constructor.throwOverrideError()
}
/**
* @protected
*/
_setupConfiguration()
{
this.constructor.throwOverrideError()
}
/**
* @protected
*/
_setupComplianceFilters()
{
this.constructor.throwOverrideError()
}
/**
* @param {boolean} firstRun
* @protected
*/
_validateCompliance(firstRun = false)
{
let itemLists = Utilities.callEventHandler(this._onGetItemLists)
if (!firstRun) {
this._configurationManager.resetTrackers()
itemLists.each((index, itemsList) => {
this._complyItemsList($(itemsList))
})
} else {
itemLists.each((index, itemList) => {
let itemListObject = $(itemList)
if (this._paginator && itemListObject.is(this._paginator.getListSelector())) {
ChildObserver.create().onNodesAdded((itemsAdded) => {
this._complyItemsList($(itemsAdded), true)
this._paginator.run(this._configurationManager.getValue(CONFIG_PAGINATOR_THRESHOLD),
this._configurationManager.getValue(CONFIG_PAGINATOR_LIMIT))
}).observe(itemList)
} else {
ChildObserver.create().onNodesAdded((itemsAdded) => this._complyItemsList($(itemsAdded), true)).observe(itemList)
}
this._complyItemsList(itemListObject)
})
}
if (this._paginator) {
this._paginator.run(this._configurationManager.getValue(CONFIG_PAGINATOR_THRESHOLD), this._configurationManager.getValue(CONFIG_PAGINATOR_LIMIT))
}
}
/**
* @param {JQuery} item
* @return {boolean}
* @protected
*/
_validateItemWhiteList(item)
{
let field = this._configurationManager.getField(FILTER_TEXT_WHITELIST)
if (field) {
let validationResult = field.value.length ? Validator.regexMatches(this.getItemAttribute(item, ITEM_ATTRIBUTE_NAME), field.optimized) : true
if (!validationResult) {
this._configurationManager.trackState(field)
}
return validationResult
}
return true
}
/**
* @param {JQuery} item
* @param {string} attributeName
* @returns {*}
*/
getItemAttribute(item, attributeName)
{
return this._itemAttributesResolver.getAttribute(item, attributeName)
}
/**
* Initialize the script and do basic UI removals
*/
initialize()
{
if (Utilities.callEventHandler(this._onValidateInit)) {
this._setupConfiguration()
this._configurationManager.initialize(this._scriptBrandingInformation.name)
this._setupAttributes()
this._setupCompliance()
this._setupComplianceFilters()
this._setupUI()
// Paginator
if (this._paginator) {
this._paginator.initialize()
}
// UI generation
Utilities.callEventHandler(this._onBeforeUIBuild)
Utilities.callEventHandler(this._onUIBuild)
this._buildNativeUI()
this._uiGen.initialize()
Utilities.callEventHandler(this._onAfterUIBuild)
this._configurationManager.updateInterface()
// First run
this._validateCompliance(true)
Utilities.callEventHandler(this._onAfterInitialization)
}
}
/**
* @returns {boolean}
*/
isUserLoggedIn()
{
return this._isUserLoggedIn
}
}