Brazen Framework - Configuration Manager

Configuration management for the Brazen user scripts framework

此腳本不應該直接安裝,它是一個供其他腳本使用的函式庫。欲使用本函式庫,請在腳本 metadata 寫上: // @require https://update.greasyfork.org/scripts/418665/1847371/Brazen%20Framework%20-%20Configuration%20Manager.js

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

作者
brazenvoid
版本
2.3.0
建立日期
2020-12-15
更新日期
2026-06-10
尺寸
20.7 KB
授權條款
GPL-3.0-only

Brazen Framework — Configuration Manager (developer guide)

Typed settings schema, localStorage persistence, cross-tab sync, backup/restore, and DOM factories bound to View Layer widgets.

Greasy Fork: Configuration Manager · Requires: Utilities, View Layer · Used by: Framework core


Constructor

new BrazenConfigurationManager(scriptPrefix, uiGenerator, tagSelectorGenerator)
Parameter Role
scriptPrefix Prefix for localStorage keys
uiGenerator BrazenViewLayer instance
tagSelectorGenerator (tag: string) => string — used by addTagRulesetField / _optimizeTagRuleset

Framework exposes this as this._configurationManager. Register fields in the subclass constructor; call initialize() during init() before UI build.


Field keys

Display name strings (e.g. 'Tag Blacklist') are normalized to kebab-case keys via Utilities.toKebabCase (tag-blacklist). Use the same display name in createElement, getValue, and getField.


Field types and registration

Constant add* method Stored value type UI
CONFIG_TYPE_FLAG addFlagField(name, helpText) boolean Checkbox
CONFIG_TYPE_TEXT addTextField(name, helpText, defaultValue?) string Text input; empty → defaultValue on read
CONFIG_TYPE_NUMBER addNumberField(name, min, max, helpText) number Number input
CONFIG_TYPE_COLOR addColorField(name, helpText) color string Color input
CONFIG_TYPE_RANGE addRangeField(name, min, max, helpText) { minimum, maximum } Two number inputs
CONFIG_TYPE_SELECT addSelectField(name, pairs, helpText) option value See known limitation in spec
CONFIG_TYPE_CHECKBOXES_GROUP addCheckboxesGroup(name, pairs, helpText) string[] of checked data-values Checkbox group
CONFIG_TYPE_RADIOS_GROUP addRadiosGroup(name, pairs, helpText) selected data-value Radio group
CONFIG_TYPE_RULESET addRulesetField(name, rows, helpText, onTranslate?, onFormat?, onOptimize?, sortRules?) string[] lines Textarea
CONFIG_TYPE_BOOKMARKS addBookmarksField(name, helpText, handlers) array (not persisted) Bookmarks panel

All add* methods return this (fluent).

Ruleset pipeline

On Apply/Save (setFromUserInterface):

  1. Split textarea by REGEX_LINE_BREAK; trim empty lines.
  2. Optional sortRules: true — locale-aware sort.
  3. onTranslateFromUI(values) — normalize (optional).
  4. Deduplicate individual rules (case-sensitive; first occurrence kept). Refreshes the textarea when duplicates are removed.
  5. onOptimize(values) — store result in field.optimized (filters read this at runtime).

On interface refresh (updateUserInterface):

  • onFormatForUI(value) → join with \n for textarea display.

addTagRulesetField(key, useSelectors, rows, helpText?, formatter?, sortRules?) wraps addRulesetField with default onOptimize_optimizeTagRuleset.

Tag rule syntax (one rule per line):

  • & — AND (all tags in segment must match)
  • | — OR within a segment
  • // — comment suffix (ignored after split)

Optimized output: array of arrays (each inner array = one conjunctive rule). Sorted shortest-first.


addBookmarksField

addBookmarksField('Bookmarks', 'Add pages you visit often.', {
  load: () => /* array from GM_setValue */,
  showAddButton: true,
  pageMatch: { getCurrentUrl, normalizeUrl, onMatchChange, watchSelectors, isActive },
  onAdd, onSort, onRemove(id), onNavigate(url),
})
Behaviour Detail
persist false — excluded from localStorage backup object
widget BrazenBookmarksPanel from createBookmarksPanel
setFromUserInterface No-op
updateUserInterface Calls handlers.load() then widget.render(value)

DOM binding: createElement

this._configurationManager.createElement('My Setting')  // display name

Invokes the field's createElement() which:

  1. Builds View Layer DOM.
  2. Stores jQuery reference on field.element.
  3. Returns the mountable node (input group or section).

Fields without createElement called remain memory-only until mounted.

Each field implements:

Callback When
createElement() First mount
setFromUserInterface() Apply/Save — read DOM → field.value (+ ruleset optimize)
updateUserInterface() Load/reset/tab switch — write field.value → DOM

Reading values

this._configurationManager.getValue('My Setting')
this._configurationManager.getField('My Setting')       // ConfigurationField | null
this._configurationManager.getFieldOrFail('My Setting') // throws if missing
this._configurationManager.hasField('My Setting')

ConfigurationField properties: title, type, element, value, optimized?, helpText, minimum, maximum, options, persist, widget, ruleset callbacks.


Persistence

Store Key Content
Settings {scriptPrefix}settings JSON object: kebab keys → values (skips persist: false)
Sync id {scriptPrefix}settings-id { id: number } — bumps on save

initialize()

  1. Creates both LocalStore instances.
  2. _syncLocalStore() — merge disk into fields; rulesets run onOptimize.
  3. onChange on settings store → updateInterface().
  4. visibilitychange — if tab visible and id changed, re-sync + onExternalConfigurationChange.

Save / apply / restore

Method Behaviour
update() All mounted fields: setFromUserInterface() (rulesets: trim → optional sort → onTranslateFromUI → dedupe rules case-sensitively → onOptimize)
save() update() → write store → bump sync id
revertChanges() Re-read store into fields + updateInterface()
updateInterface() All mounted fields: updateUserInterface()

Framework button wiring:

  • Applyupdate() + re-run compliance (no disk).
  • Save — apply + save().
  • ResetrevertChanges() + compliance.

Backup format

backup() downloads {scriptPrefix}backup.json:

{
  "tag-blacklist": ["rule1", "rule2"],
  "pagination-threshold": 20,
  "id": 123456789
}

restore(response)fetch/Response with JSON body; restores values + sync id; alerts success/failure.

Not included: GM_setValue data (bookmarks, download ledger) unless stored in a persisted config field.

Cross-tab sync

onExternalConfigurationChange(handler)(manager) => void when another tab saved. Framework registers compliance re-run.


Validation helper

generateValidationCallback(configKey) → default enable checks:

Type Active when
flag / radios / select truthy value
checkboxes length > 0
number value > 0
range `minimum > 0 \
ruleset / text length > 0

Used by framework _addItemComplianceFilter when no custom validate callback is supplied.


Integration checklist

  1. Register all fields before init() builds UI.
  2. Use stable English labels — they appear in the panel and backup JSON keys.
  3. Mount with createElement inside tab panels.
  4. Pair enable flags with filters (addFlagField + ruleset).
  5. Document keys stored outside backup (persist: false, GM_setValue).
  6. Set #bv-ui userScript reference if tabs need updateInterface from custom widgets.

Next in stack: Item Attributes Resolver (before Framework core).