Sleazy Fork is available in English.

Brazen UI Generator

Helper methods to generate a control panel UI for scripts

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/1498249/Brazen%20UI%20Generator.js

  1. // ==UserScript==
  2. // @name Brazen UI Generator
  3. // @namespace brazenvoid
  4. // @version 2.1.0
  5. // @author brazenvoid
  6. // @license GPL-3.0-only
  7. // @description Helper methods to generate a control panel UI for scripts
  8. // @grant GM_addStyle
  9. // ==/UserScript==
  10.  
  11. /**
  12. * @function GM_addStyle
  13. * @param {string} style
  14. */
  15. GM_addStyle(
  16. `@keyframes brazen-fade{from{opacity:0}to{opacity:1}}#restore-settings.bv-input{margin-bottom:1rem}#settings-wrapper{bottom:5vh;overflow:auto;resize:horizontal;top:5vh;z-index:1001}.show-settings.bv-section{top:5vh;box-shadow:0 0 20px white;padding:8px;border-radius:5px;border:2px solid white}.bv-actions{display:inline-flex;justify-content:center;padding:0 0.25rem;text-align:center}.bv-actions .bv-button{width:auto}.bv-bg-colour{background-color:#4f535b}.bv-border-primary{border:1px solid black}.bv-break{margin:0.5rem 0}.bv-button{background-color:revert;padding:0.5rem 1rem;width:100%}.bv-flex-column{flex-direction:column}.bv-font-primary{color:white}.bv-font-secondary{color:black}.bv-group{align-items:center;display:flex;min-height:20px}.bv-group + .bv-group{margin-top:1rem}.bv-group.bv-range-group,.bv-group.bv-text-group{align-items:center}.bv-group.bv-range-group > input{width:75px}.bv-group.bv-range-group > input + input{margin-left:5px}.bv-group.bv-textarea-group{align-items:start;flex-direction:column;overflow:hidden}.bv-group.bv-textarea-group > textarea.bv-input{margin-top:0.5rem;resize:vertical;width:100%}input.bv-input,select.bv-input,textarea.bv-input{box-sizing:border-box;margin:0;padding:0.5rem}.bv-input.bv-checkbox-radio{margin-right:5px;scale:2}.bv-input.bv-text{width:100%}.bv-label{flex-grow:1;text-align:start}.bv-label.bv-text + .bv-input.bv-text{width:40%}.bv-section{display:flex;flex-direction:column;font-family:"roboto";font-size:1rem;font-weight:normal;left:0;padding:1rem;position:fixed;z-index:1000}.bv-section > div + div{margin-top:1rem}.bv-section hr{border:1px solid white;margin:1rem 0}.bv-section button + button{margin-left:0.25rem}.bv-section .bv-title{display:block;height:20px;margin-bottom:1rem;text-align:center;width:100%}.bv-show-settings{border:0;font-size:0.7rem;height:90vh;left:0;margin:0;padding:0;position:fixed;top:5vh;width:0.2vw;writing-mode:sideways-lr;z-index:999}.bv-show-settings .bv-title{display:block;height:20px;width:100%}.bv-tab-button{background-color:inherit;border-bottom:0;border-top-left-radius:3px;border-top-right-radius:3px;cursor:pointer;outline:none;padding:0.5rem 0.75rem;transition:0.3s}.bv-tab-button.bv-active,.bv-tab-button:hover{color:black;background-color:white}.bv-tab-panel{animation:brazen-fade 1s;display:none;flex-direction:column;padding:1rem}.bv-tab-panel.bv-active{display:flex}.bv-tabs-nav{display:flex;flex-wrap:wrap;overflow:hidden}`)
  17.  
  18. class BrazenUIGenerator
  19. {
  20. /**
  21. * @param {JQuery} nodes
  22. */
  23. static appendToBody(nodes)
  24. {
  25. $('body').append(nodes)
  26. }
  27.  
  28. /**
  29. * @param {string} selectorPrefix
  30. */
  31. constructor(selectorPrefix)
  32. {
  33. /**
  34. * @type {JQuery}
  35. * @private
  36. */
  37. this._section = null
  38.  
  39. /**
  40. * @type {SelectorGenerator}
  41. * @private
  42. */
  43. this._selectorGenerator = new SelectorGenerator(selectorPrefix)
  44.  
  45. /**
  46. * @type {string}
  47. * @private
  48. */
  49. this._selectorPrefix = selectorPrefix
  50.  
  51. /**
  52. * @type {JQuery}
  53. * @private
  54. */
  55. this._statusLine = null
  56.  
  57. /**
  58. * @type {string}
  59. * @private
  60. */
  61. this._statusText = ''
  62. }
  63.  
  64. /**
  65. * @param {JQuery} node
  66. * @param {string} text
  67. * @return {JQuery}
  68. * @private
  69. */
  70. _addHelpTextOnHover(node, text)
  71. {
  72. if (text !== '') {
  73. node.on('mouseover', () => this.updateStatus(text, true))
  74. node.on('mouseout', () => this.resetStatus())
  75. }
  76. return node
  77. }
  78.  
  79. /**
  80. * @return {JQuery}
  81. */
  82. createBreakSeparator()
  83. {
  84. return $('<br class="bv-break"/>')
  85. }
  86.  
  87. /**
  88. * @return {JQuery}
  89. */
  90. createContainer()
  91. {
  92. this._section = $('<section class="bv-section bv-font-primary">')
  93. return this._section
  94. }
  95.  
  96. /**
  97. * @param {JQuery|JQuery[]} children
  98. * @param {string} wrapperClasses
  99. * @return {JQuery}
  100. */
  101. createFormActions(children, wrapperClasses = '')
  102. {
  103. return $('<div class="bv-actions"/>').addClass(wrapperClasses).append(children)
  104. }
  105.  
  106. /**
  107. * @param {string} caption
  108. * @param {JQuery.EventHandler} onClick
  109. * @param {string} hoverHelp
  110. * @return {JQuery}
  111. */
  112. createFormButton(caption, hoverHelp, onClick)
  113. {
  114. let button = $('<button class="bv-button">').text(caption).on('click', onClick)
  115. return this._addHelpTextOnHover(button, hoverHelp)
  116. }
  117.  
  118. createFormCheckBoxesGroupSection(label, keyValuePairs, hoverHelp)
  119. {
  120. let section = this.createFormSection(label).addClass('bv-checkboxes-group')
  121. for (const element of keyValuePairs) {
  122. section.append(
  123. this.createFormGroup().append([
  124. this.createFormGroupLabel(element[0], 'checkbox'),
  125. this.createFormGroupInput('checkbox').attr('data-value', element[1]),
  126. ]),
  127. )
  128. }
  129. return this._addHelpTextOnHover(section, hoverHelp)
  130. }
  131.  
  132. /**
  133. * @return {JQuery}
  134. */
  135. createFormGroup()
  136. {
  137. return $('<div class="bv-group"/>')
  138. }
  139.  
  140. /**
  141. * @param {string} id
  142. * @param {Array} keyValuePairs
  143. *
  144. * @return {JQuery}
  145. */
  146. createFormGroupDropdown(id, keyValuePairs)
  147. {
  148. let dropdown = $('<select>').attr('id', id).addClass('bv-input')
  149.  
  150. for (let i = 0; i < keyValuePairs.length; i++) {
  151. dropdown.append($('<option>').attr('value', keyValuePairs[i][0]).text(keyValuePairs[i][1]).prop('selected', (i === 0)))
  152. }
  153. return dropdown
  154. }
  155.  
  156. /**
  157. * @param {string} type
  158. *
  159. * @return {JQuery}
  160. */
  161. createFormGroupInput(type)
  162. {
  163. let input = $('<input class="bv-input">').attr('type', type)
  164. switch (type) {
  165. case 'number':
  166. case 'text':
  167. input.addClass('bv-text')
  168. break
  169.  
  170. case 'radio':
  171. case 'checkbox':
  172. input.addClass('bv-checkbox-radio')
  173. break
  174. }
  175. return input
  176. }
  177.  
  178. /**
  179. * @param {string} label
  180. * @param {string} inputType
  181. * @return {JQuery}
  182. */
  183. createFormGroupLabel(label, inputType = '')
  184. {
  185. let labelFormGroup = $('<label class="bv-label">').text(label)
  186. if (inputType !== '') {
  187. switch (inputType) {
  188. case 'number':
  189. case 'text':
  190. labelFormGroup.addClass('bv-text')
  191. labelFormGroup.text(labelFormGroup.text() + ': ')
  192. break
  193. case 'radio':
  194. case 'checkbox':
  195. labelFormGroup.addClass('bv-checkbox-radio')
  196. break
  197. }
  198. }
  199. return labelFormGroup
  200. }
  201.  
  202. /**
  203. * @param {string} statisticType
  204. * @return {JQuery}
  205. */
  206. createFormGroupStatLabel(statisticType)
  207. {
  208. return $('<label class="bv-stat-label">').attr('id', this._selectorGenerator.getStatLabelSelector(statisticType)).text('0')
  209. }
  210.  
  211. /**
  212. * @param {string} label
  213. * @param {string} inputType
  214. * @param {string} hoverHelp
  215. * @return {JQuery}
  216. */
  217. createFormInputGroup(label, inputType, hoverHelp = '')
  218. {
  219. return this._addHelpTextOnHover(
  220. this.createFormGroup().append([
  221. this.createFormGroupLabel(label, inputType),
  222. this.createFormGroupInput(inputType),
  223. ]),
  224. hoverHelp,
  225. )
  226. }
  227.  
  228. createFormRadiosGroupSection(label, keyValuePairs, hoverHelp)
  229. {
  230. let section = this.createFormSection(label).addClass('bv-radios-group')
  231. for (let i = 0; i < keyValuePairs.length; i++) {
  232. section.append(
  233. this.createFormGroup().append([
  234. this.createFormGroupLabel(keyValuePairs[i][0], 'radio'),
  235. this.createFormGroupInput('radio').prop('checked', i === 0).attr('data-value', keyValuePairs[i][1]).on('change', (event) => {
  236. $(event.currentTarget).parents('.bv-radios-group').first().find('input').each((index, element) => {
  237. if (!element.isSameNode(event.currentTarget)) {
  238. $(element).prop('checked', false)
  239. }
  240. })
  241. }),
  242. ]),
  243. )
  244. }
  245. return this._addHelpTextOnHover(section, hoverHelp)
  246. }
  247.  
  248. /**
  249. * @param {string} label
  250. * @param {string} inputsType
  251. * @param {number} minimum
  252. * @param {number} maximum
  253. * @param {string} hoverHelp
  254. * @return {JQuery}
  255. */
  256. createFormRangeInputGroup(label, inputsType, minimum, maximum, hoverHelp)
  257. {
  258. return this._addHelpTextOnHover(
  259. this.createFormGroup().addClass('bv-range-group').append([
  260. this.createFormGroupLabel(label, inputsType),
  261. this.createFormGroupInput(inputsType).attr('min', minimum).attr('max', maximum),
  262. this.createFormGroupInput(inputsType).attr('min', minimum).attr('max', maximum),
  263. ]),
  264. hoverHelp,
  265. )
  266. }
  267.  
  268. /**
  269. * @param {string} title
  270. * @return {JQuery}
  271. */
  272. createFormSection(title = '')
  273. {
  274. return $('<div>').append($('<label class="bv-title">').text(title))
  275. }
  276.  
  277. /**
  278. * @param {string} label
  279. * @param {int} rows
  280. * @param {string} hoverHelp
  281. * @return {JQuery}
  282. */
  283. createFormTextAreaGroup(label, rows, hoverHelp = '')
  284. {
  285. return this._addHelpTextOnHover(
  286. this.createFormGroup().addClass('bv-textarea-group').append([
  287. this.createFormGroupLabel(label),
  288. $('<textarea class="bv-input" spellcheck="false">').attr('rows', rows),
  289. ]),
  290. hoverHelp,
  291. )
  292. }
  293.  
  294. /**
  295. * @return {JQuery}
  296. */
  297. createSeparator()
  298. {
  299. return $('<hr/>')
  300. }
  301.  
  302. /**
  303. * @return {JQuery}
  304. */
  305. createSettingsHideButton()
  306. {
  307. return this.createFormButton('<< Hide', '', () => this._section.css('display', 'none'))
  308. }
  309.  
  310. /**
  311. * @return {JQuery}
  312. */
  313. createSettingsSection()
  314. {
  315. return this.createContainer().attr('id', 'settings-wrapper').addClass('bv-bg-colour bv-border-primary').hide()
  316. }
  317.  
  318. /**
  319. * @param {string} caption
  320. * @param {JQuery} settingsSection
  321. *
  322. * @return {JQuery}
  323. */
  324. createSettingsShowButton(caption, settingsSection)
  325. {
  326. return $('<button class="show-settings bv-section bv-bg-colour">').text(caption).on('click', () => settingsSection.slideDown(300))
  327. }
  328.  
  329. /**
  330. * @param {string} statisticsType
  331. * @param {string} label
  332. * @return {JQuery}
  333. */
  334. createStatisticsFormGroup(statisticsType, label = '')
  335. {
  336. return this.createFormGroup().addClass('bv-stat-group').append([
  337. this.createFormGroupLabel((label === '' ? statisticsType : label) + ' Filter'),
  338. this.createFormGroupStatLabel(statisticsType),
  339. ])
  340. }
  341.  
  342. /**
  343. * @return {JQuery}
  344. */
  345. createStatisticsTotalsGroup()
  346. {
  347. return this.createFormGroup().append([
  348. this.createFormGroupLabel('Total'),
  349. this.createFormGroupStatLabel('Total'),
  350. ])
  351. }
  352.  
  353. /**
  354. * @return {JQuery}
  355. */
  356. createStatusSection()
  357. {
  358. this._statusLine = this.createFormGroupLabel('Status').attr('id', this._selectorGenerator.getSelector('status'))
  359. return this._statusLine
  360. }
  361.  
  362. /**
  363. * @param {string} tabName
  364. * @param {boolean} isFirst
  365. * @return {JQuery}
  366. */
  367. createTabButton(tabName, isFirst)
  368. {
  369. let tabButton = $('<button class="bv-tab-button bv-border-primary">').
  370. text(tabName).
  371. on('click', (event) => {
  372.  
  373. let button = $(event.currentTarget)
  374. let tabSection = button.parents('.bv-tabs-section:first')
  375.  
  376. tabSection.find('.bv-tab-button').removeClass('bv-active bv-font-secondary').addClass('bv-font-primary')
  377.  
  378. tabSection.find('.bv-tab-panel').removeClass('bv-active')
  379.  
  380. button.removeClass('bv-font-primary').addClass('bv-active bv-font-secondary')
  381.  
  382. $('#' + Utilities.toKebabCase(button.text())).addClass('bv-active')
  383. }).
  384. on('mouseenter', (event) => $(event.currentTarget).addClass('bv-font-secondary')).
  385. on('mouseleave', (event) => $(event.currentTarget).removeClass('bv-font-secondary'))
  386.  
  387. return isFirst ? tabButton.addClass('bv-active bv-font-secondary') : tabButton.addClass('bv-font-primary')
  388. }
  389.  
  390. /**
  391. * @param {string} tabName
  392. * @param {boolean} isFirst
  393. * @return {JQuery}
  394. */
  395. createTabPanel(tabName, isFirst = false)
  396. {
  397. let tabPanel = $('<div class="bv-tab-panel bv-border-primary">').attr('id', Utilities.toKebabCase(tabName))
  398. if (isFirst) {
  399. tabPanel.addClass('bv-active')
  400. }
  401. return tabPanel
  402. }
  403.  
  404. /**
  405. * @param {string[]} tabNames
  406. * @param {JQuery[]} tabPanels
  407. * @return {JQuery}
  408. */
  409. createTabsSection(tabNames, tabPanels)
  410. {
  411. let tabButtons = []
  412. for (let i = 0; i < tabNames.length; i++) {
  413. tabButtons.push(this.createTabButton(tabNames[i], i === 0))
  414. }
  415. let nav = $('<div class="bv-tabs-nav">').append(tabButtons)
  416. return $('<div class="bv-tabs-section">').append(nav).append(...tabPanels)
  417. }
  418.  
  419. /**
  420. * @param {string} title
  421. * @return {JQuery}
  422. */
  423. createTitle(title)
  424. {
  425. return $('<label class="bv-title">' + title + '</label>')
  426. }
  427.  
  428. /**
  429. * @return {JQuery}
  430. */
  431. getSelectedSection()
  432. {
  433. return this._section
  434. }
  435.  
  436. resetStatus()
  437. {
  438. this._statusLine.text(this._statusText)
  439. }
  440.  
  441. /**
  442. * @param {string} status
  443. * @param {boolean} transient
  444. */
  445. updateStatus(status, transient = false)
  446. {
  447. if (!transient) {
  448. this._statusText = status
  449. }
  450. this._statusLine.text(status)
  451. }
  452. }