Helper methods to generate a control panel UI for scripts
Version vom
Dieses Skript sollte nicht direkt installiert werden. Es handelt sich hier um eine Bibliothek für andere Skripte, welche über folgenden Befehl in den Metadaten eines Skriptes eingebunden wird // @require https://update.sleazyfork.org/scripts/416104/877457/Brazen%20UI%20Generator.js
// ==UserScript==
// @name Brazen UI Generator
// @namespace brazen
// @version 1.1.0
// @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}}.bg-brand{background-color:#ffa31a}.border-primary{border:1px solid #000}.font-primary{color:#000}button.form-button{padding:0 5px;width:100%}button.show-settings{border:0;font-size:.7rem;height:90vh;left:0;margin:0;padding:0;position:fixed;top:5vh;width:.2vw;writing-mode:sideways-lr;z-index:999}button.tab-button{background-color:inherit;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-stat-group{padding:2px 0}div.form-group.form-textarea-group{align-items:unset;display:block}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 > label.title{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;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{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 {string} selectorPrefix
*/
constructor (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 {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, hoverHelp)
{
let inputID = this._selectorGenerator.getSettingsInputSelector(label)
let divFormInputGroup = this.createFormGroup().append([
this.createFormGroupLabel(label, inputID, inputType),
this.createFormGroupInput(inputID, inputType),
])
this._addHelpTextOnHover(divFormInputGroup, hoverHelp)
return divFormInputGroup
}
/**
* @param {string} label
* @param {string} inputsType
* @param {number} minimum
* @param {number} maximum
* @param {string} hoverHelp
* @return {JQuery}
*/
createFormRangeInputGroup (label, inputsType, minimum, maximum, hoverHelp)
{
let divFormInputGroup = this.createFormGroup().append([
this.createFormGroupLabel(label, '', inputsType),
this.createFormGroupInput(this._selectorGenerator.getSettingsRangeInputSelector(label, true), inputsType).
attr('min', minimum).
attr('max', maximum),
this.createFormGroupInput(this._selectorGenerator.getSettingsRangeInputSelector(label, false), inputsType).
attr('min', minimum).
attr('max', maximum),
])
this._addHelpTextOnHover(divFormInputGroup, hoverHelp)
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().addClass('form-textarea-group').append([
this.createFormGroupLabel(label),
$('<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 font-primary">')
return this._section
}
/**
* @return {JQuery}
*/
createSeparator ()
{
return $('<hr/>')
}
/**
* @param {string} label
* @param {Array} keyValuePairs
* @param {string} hoverHelp
*
* @return {JQuery}
*/
createDropDownFormGroup (label, keyValuePairs, hoverHelp)
{
let dropdownID = this._selectorGenerator.getSettingsInputSelector(label)
// let optionsSelector = '#' + dropdownID + ' option'
let group = this.createFormGroup().append([
this.createFormGroupLabel(label, dropdownID, 'text'),
this.createFormGroupDropdown(dropdownID, keyValuePairs),
])
// 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.',
// ),
// ]),
// ])
// }
if (hoverHelp !== '') {
this._addHelpTextOnHover(group, hoverHelp)
}
return group
}
/**
* @return {JQuery}
*/
createSettingsHideButton ()
{
return this.createFormButton('<< Hide', () => this._section.style.display = 'none')
}
/**
* @return {JQuery}
*/
createSettingsSection ()
{
return this.createSection().attr('id', 'settings-wrapper').hide()
}
/**
* @param {string} caption
* @param {JQuery} settingsSection
*
* @return {JQuery}
*/
createSettingsShowButton (caption, settingsSection)
{
return $('<button class="show-settings bg-brand font-primary">').
text(caption).
on('click', () => settingsSection.toggle(300)).
on('mouseover', () => settingsSection.show(300))
}
/**
* @param {string} statisticsType
* @param {string} label
* @return {JQuery}
*/
createStatisticsFormGroup (statisticsType, label = '')
{
return this.createFormGroup().addClass('form-stat-group').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 {string} tabName
* @param {boolean} isFirst
* @return {JQuery}
*/
createTabButton (tabName, isFirst)
{
let tabButton = $('<button class="tab-button border-primary">').
text(tabName).
on('click', (event) => {
let button = $(event.currentTarget)
button.parents('.tabs-section:first').find('.tab-button,.tab-panel').removeClass('active')
button.addClass('active')
$('#' + 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 border-primary">').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
}
resetStatus ()
{
this._statusLine.text(this._statusText)
}
/**
* @param {string} status
* @param {boolean} transient
*/
updateStatus (status, transient = false)
{
if (!transient) {
this._statusText = status
}
this._statusLine.text(status)
}
}