您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Helper methods to generate a control panel UI for scripts
当前为
此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.sleazyfork.org/scripts/416104/870040/Brazen%20UI%20Generator.js
// ==UserScript== // @name Brazen UI Generator // @namespace brazen // @version 1.0.1 // @author brazenvoid // @license GPL-3.0-only // @description Helper methods to generate a control panel UI for scripts // @require https://greasyfork.org/scripts/375557-base-resource/code/Base%20Resource.js?version=869326 // @grant GM_addStyle // ==/UserScript== /** * @function GM_addStyle * @param {string} style */ GM_addStyle( `@keyframes fadeEffect{from{opacity:0}to{opacity:1}}button.form-button{padding:0 5px;width:100%}button.show-settings{background-color:#ffa31a;border:0;color:#000;font-size:.7rem;height:90vh;left:0;margin:0;padding:0;position:fixed;top:5vh;width:.1vw;writing-mode:sideways-lr;z-index:999}button.tab-button{background-color:inherit;border:1px solid #000;border-bottom:0;border-top-left-radius:3px;border-top-right-radius:3px;cursor:pointer;float:left;outline:none;padding:5px 10px;transition:.3s}button.tab-button:hover{background-color:#fff}button.tab-button.active{background-color:#fff;display:block}div.form-actions{text-align:center}div.form-actions button.form-button{padding:0 15px;width:auto}div.form-actions-wrapper{display:inline-flex}div.form-actions-wrapper > div.form-group + *{margin-left:15px}div.form-group{align-items:center;display:flex;min-height:20px;padding:4px 0}div.form-group.form-range-input-group > input{padding:0 5px;width:75px}div.form-group.form-range-input-group > input + input{margin-left:5px}div.form-section{text-align:center}div.form-section button + button{margin-left:5px}div.form-section label.title{display:block;height:20px;width:100%}div.form-section button.form-button{width:auto}div.tab-panel{animation:fadeEffect 1s;border:1px solid #000;display:none;padding:5px 10px}div.tab-panel.active{display:block}div.tabs-nav{overflow:hidden}div.tabs-section{margin-bottom:5px}hr{margin:3px}input.form-input{text-align:center}input.form-input.check-radio-input{margin-right:5px}input.form-input.regular-input{width:100px}label.form-label{flex-grow:1}label.form-stat-label{padding:2px 0}section.form-section{color:#000;font-size:12px;font-weight:700;position:fixed;left:0;padding:5px 10px;z-index:1000}select.form-dropdown{float:right;height:18px;text-align:center;width:100px}textarea.form-input{display:block;height:auto;position:relative;width:98%}`) class BrazenUIGenerator { /** * @param {JQuery} nodes */ static appendToBody (nodes) { $('body').append(nodes) } /** * @param {boolean} showUI * @param {string} selectorPrefix */ constructor (showUI, selectorPrefix) { /** * @type {*} * @private */ this._buttonBackroundColor = null /** * @type {JQuery} * @private */ this._section = null /** * @type {SelectorGenerator} * @private */ this._selectorGenerator = new SelectorGenerator(selectorPrefix) /** * @type {string} * @private */ this._selectorPrefix = selectorPrefix /** * @type {boolean} * @private */ this._showUI = showUI /** * @type {JQuery} * @private */ this._statusLine = null /** * @type {string} * @private */ this._statusText = '' } /** * @param {JQuery} node * @param {string} text * @return {this} * @private */ _addHelpTextOnHover (node, text) { node.on('mouseover', () => this.updateStatus(text, true)) node.on('mouseout', () => this.resetStatus()) } /** * @return {JQuery} */ createBreakSeparator () { return $('<br/>') } /** * @param {JQuery|JQuery[]} children * @return {JQuery} */ createFormActions (children) { return $('<div class="form-actions"/>').append($('<div class="form-actions-wrapper"/>').append(children)) } /** * @param {string} caption * @param {JQuery.EventHandler} onClick * @param {string} hoverHelp * @return {JQuery} */ createFormButton (caption, onClick, hoverHelp = '') { let button = $('<button class="form-button">'). css('backgroundColor', this._buttonBackroundColor ?? 'revert'). text(caption). on('click', onClick) if (hoverHelp !== '') { this._addHelpTextOnHover(button, hoverHelp) } return button } /** * @return {JQuery} */ createFormGroup () { return $('<div class="form-group"/>') } /** * @param {string} id * @param {Array} keyValuePairs * @param {boolean} multiple * * @return {JQuery} */ createFormGroupDropdown (id, keyValuePairs, multiple = false) { let dropdown = $('<select>'). attr('id'.id). addClass(multiple ? 'form-dropdown-multiple' : 'form-dropdown'). prop('multiple', multiple) for (let i = 0; i < keyValuePairs.length; i++) { dropdown.append( $('<option>'). val(keyValuePairs[i][0]). text(keyValuePairs[i][1]). prop('selected', multiple ? false : (i === 0)), ) } return dropdown } /** * @param {string} id * @param {string} type * * @return {JQuery} */ createFormGroupInput (id, type) { let inputFormGroup = $('<input class="form-input">').attr('id', id).attr('type', type) switch (type) { case 'number': case 'text': inputFormGroup.addClass('regular-input') break case 'radio': case 'checkbox': inputFormGroup.addClass('check-radio-input') break } return inputFormGroup } /** * @param {string} label * @param {string} inputID * @param {string} inputType * @return {JQuery} */ createFormGroupLabel (label, inputID = '', inputType = '') { let labelFormGroup = $('<label class="form-label">').attr('for', inputID).text(label) if (inputType !== '') { switch (inputType) { case 'number': case 'text': labelFormGroup.addClass('regular-input') labelFormGroup.text(labelFormGroup.text() + ': ') break case 'radio': case 'checkbox': labelFormGroup.addClass('check-radio-input') break } } return labelFormGroup } /** * @param {string} statisticType * @return {JQuery} */ createFormGroupStatLabel (statisticType) { return $('<label class="form-stat-label">'). attr('id', this._selectorGenerator.getStatLabelSelector(statisticType)). text('0') } /** * @param {string} label * @param {string} inputType * @param {string} hoverHelp * @return {JQuery} */ createFormInputGroup (label, inputType = 'text', hoverHelp = '') { let inputID = this._selectorGenerator.getSettingsInputSelector(label) let divFormInputGroup = this.createFormGroup().append([ this.createFormGroupLabel(label, inputID, inputType), this.createFormGroupInput(inputID, inputType), ]) if (hoverHelp !== '') { this._addHelpTextOnHover(divFormInputGroup, hoverHelp) } return divFormInputGroup } /** * @param {string} label * @param {string} inputsType * * @return {JQuery} */ createFormRangeInputGroup (label, inputsType = 'text') { let divFormInputGroup = this.createFormGroup().append([ this.createFormGroupLabel(label, '', inputsType), this.createFormGroupInput(this._selectorGenerator.getSettingsRangeInputSelector(label, true), inputsType), this.createFormGroupInput(this._selectorGenerator.getSettingsRangeInputSelector(label, false), inputsType), ]) return divFormInputGroup.addClass('form-range-input-group') } /** * @param {string} title * @return {JQuery} */ createFormSection (title = '') { let sectionDiv = $('<div class="form-section">') if (title !== '') { sectionDiv.append($('<label class="title">').text(title)) } return sectionDiv } /** * @param {string} caption * @param {string} tooltip * @param {JQuery.EventHandler} onClick * @param {string} hoverHelp * @return {JQuery} */ createFormSectionButton (caption, tooltip, onClick, hoverHelp = '') { return this.createFormButton(caption, onClick, hoverHelp).attr('title', tooltip) } /** * @param {string} label * @param {int} rows * @param {string} hoverHelp * @return {JQuery} */ createFormTextAreaGroup (label, rows, hoverHelp = '') { let group = this.createFormGroup().append([ this.createFormGroupLabel(label).css('textAlign', 'center'), $('<textarea class="form-input">'). attr('id', this._selectorGenerator.getSettingsInputSelector(label)). attr('rows', rows), ]) if (hoverHelp !== '') { this._addHelpTextOnHover(group, hoverHelp) } return group } /** * @return {JQuery} */ createSection () { this._section = $('<section class="form-section">') return this._section } /** * @return {JQuery} */ createSeparator () { return $('<hr/>') } /** * @param {LocalStore} localStore * @param {JQuery.EventHandler} onClick * @return {JQuery} */ createSettingsFormActions (localStore, onClick) { return this.createFormSection().append([ this.createFormActions([ this.createFormButton('Apply', onClick, 'Filter items as per the settings in the dialog.'), this.createFormButton('Reset', (event) => { localStore.retrieve() onClick(event) }, 'Restore and apply saved configuration.'), ]), ]) } /** * @param {string} label * @param {Array} keyValuePairs * @param {boolean} multiple * * @return {JQuery} */ createSettingsDropDownFormGroup (label, keyValuePairs, multiple = false) { let dropdownID = this._selectorGenerator.getSettingsInputSelector(label) let optionsSelector = '#' + dropdownID + ' option' if (multiple) { return this.createFormSection(label).append([ this.createFormGroup().append([ this.createFormGroupDropdown(dropdownID, keyValuePairs, multiple), ]), this.createFormActions([ this.createFormButton( 'Select All', () => { $(optionsSelector).each((index, element) => { $(element).prop('selected', true) }) }, 'Select all options.', ), this.createFormButton( 'Deselect All', () => { $(optionsSelector).each((index, element) => { $(element).prop('selected', false) }) }, 'Deselect all options.', ), ]), ]) } return this.createFormGroup().append([ this.createFormGroupLabel(label, dropdownID, 'text'), this.createFormGroupDropdown(dropdownID, keyValuePairs, multiple), ]) } /** * @return {JQuery} */ createSettingsHideButton () { return this.createFormButton('<< Hide', () => this._section.style.display = 'none') } /** * @param {string} caption * @param {JQuery} settingsSection * @param {JQuery.EventHandler|null} onMouseLeave * * @return {JQuery} */ createSettingsShowButton (caption, settingsSection, onMouseLeave = null) { return $('<button class="show-settings">'). text(caption). on('click', () => settingsSection.toggle(500)). on('mouseleave', onMouseLeave ? () => onMouseLeave() : () => settingsSection.hide(500)) } /** * @param {string} statisticsType * @param {string} label * @return {JQuery} */ createStatisticsFormGroup (statisticsType, label = '') { return this.createFormGroup().append([ this.createFormGroupLabel((label === '' ? statisticsType : label) + ' Filter'), this.createFormGroupStatLabel(statisticsType), ]) } /** * @return {JQuery} */ createStatisticsTotalsGroup () { return this.createFormGroup().append([ this.createFormGroupLabel('Total'), this.createFormGroupStatLabel('Total'), ]) } /** * @return {JQuery} */ createStatusSection () { this._statusLine = this.createFormGroupLabel('Status').attr('id', this._selectorGenerator.getSelector('status')) return this.createFormSection().append(this._statusLine) } /** * @param {LocalStore} localStore * @return {JQuery} */ createStoreFormSection (localStore) { return this.createFormSection('Cached Configuration').append([ this.createFormActions([ this.createFormSectionButton( 'Update', 'Save UI settings in store', () => localStore.save(), 'Saves applied settings.', ), this.createFormSectionButton( 'Purge', 'Purge store', () => localStore.delete(), 'Removes saved settings. Settings will then be sourced from the defaults defined in the script.', ), ]), ]) } /** * @param {string} tabName * @param {boolean} isFirst * @return {JQuery} */ createTabButton (tabName, isFirst) { let tabButton = $('<button class="tab-button">'). text(tabName). on('click', (event) => { let button = $(event.currentTarget) button.parents('.tabs-section:first').find('.tab-button,.tab-panel').removeClass('active') button.addClass('active') console.log(button.text()) console.log(Utilities.toKebabCase(button.text())) console.log('#' + Utilities.toKebabCase(button.text())) $('#' + Utilities.toKebabCase(button.text())).addClass('active') }) if (isFirst) { tabButton.addClass('active') } return tabButton } /** * @param {string} tabName * @param {boolean} isFirst * @return {JQuery} */ createTabPanel (tabName, isFirst = false) { let tabPanel = $('<div class="tab-panel">').attr('id', Utilities.toKebabCase(tabName)) if (isFirst) { tabPanel.addClass('active') } return tabPanel } /** * @param {string[]} tabNames * @param {JQuery[]} tabPanels * @return {JQuery} */ createTabsSection (tabNames, tabPanels) { let tabButtons = [] for (let i = 0; i < tabNames.length; i++) { tabButtons.push(this.createTabButton(tabNames[i], i === 0)) } let nav = $('<div class="tabs-nav">').append(tabButtons) return $('<div class="tabs-section">').append(nav).append(...tabPanels) } /** * @return {JQuery} */ getSelectedSection () { return this._section } /** * @param {string} label * @return {JQuery} */ getSettingsInput (label) { return $(this._selectorGenerator.getSettingsInputSelector(label)) } /** * @param {string} label * @return {number} */ getSettingsInputNumberValue (label) { return parseInt(this.getSettingsInput(label).val()) } /** * @param {string} label * @return {string|string[]|boolean} */ getSettingsInputValue (label) { let input = this.getSettingsInput(label) if (input.attr('type') === 'checkbox') { return input.prop('checked') } return input.val() } /** * @param {string} label * @param {boolean} getMinInput * @return {JQuery} */ getSettingsRangeInput (label, getMinInput) { return $(this._selectorGenerator.getSettingsRangeInputSelector(label, getMinInput)) } /** * @param {string} label * @param {boolean} getMinInputValue * @return {number} */ getSettingsRangeInputValue (label, getMinInputValue) { return parseInt(this.getSettingsRangeInput(label, getMinInputValue).val()) } resetStatus () { this._statusLine.text(this._statusText) } /** * @param {string} label * @param {*} value */ setSettingsInputValue (label, value) { let input = this.getSettingsInput(label) if (input.attr('type') === 'checkbox') { input.prop('checked', value) } else { input.val(value) } } /** * @param {string} label * @param {number} lowerBound * @param {number} upperBound */ setSettingsRangeInputValue (label, lowerBound, upperBound) { this.getSettingsRangeInput(label, true).val(lowerBound) this.getSettingsRangeInput(label, false).val(upperBound) } /** * @param {string} status * @param {boolean} transient */ updateStatus (status, transient = false) { if (!transient) { this._statusText = status } this._statusLine.text(status) } }