Configuration management for the Brazen user scripts framework
Hindi dapat direktang i-install ang script na ito. Ito ay isang library para sa iba pang mga script na isasama sa meta directive. // @require https://update.greasyfork.org/scripts/418665/1872288/Brazen%20Framework%20-%20Configuration%20Manager.js
Typed settings schema, pluggable storage drivers (localStorage + Tampermonkey GM), 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
new BrazenConfigurationManager(scriptPrefix, uiGenerator, tagSelectorGenerator)
| Parameter | Role |
|---|---|
scriptPrefix |
Prefix for storage keys (per driver) |
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.
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.
| 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, options?) |
array (self-managed on gm) |
Bookmarks panel |
CONFIG_TYPE_LEDGER |
addLedgerField(name, options?) |
self-managed id set (not in aggregate blob) | No UI — GM-backed duplicate ledger |
All add* methods return this (fluent). Chain attachStorage('local'|'gm') after any add*Field to assign a non-default driver (default: local).
On Apply/Save (setFromUserInterface):
REGEX_LINE_BREAK; trim empty lines.sortRules: true — locale-aware sort.onTranslateFromUI(values) — normalize (optional).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.
Every ruleset field exposes methods for programmatic add/remove without going through the textarea. Callers get the field via getField(name) and invoke these directly; side effects (save(), compliance refresh, UI refresh elsewhere) remain the caller's responsibility.
| Method | Role |
|---|---|
onMatchRule(storedRule, target) |
Optional matcher callback; default is strict equality (storedRule === target) |
setRules(lines) |
Canonical write: onTranslateFromUI → optional sortRules → value → onOptimize → updateUserInterface |
findRuleIndex(target) |
Index of first matching rule, or -1 |
hasRule(target) |
Membership test via onMatchRule |
addRule(rule, target?) |
Upsert: remove matches for target (defaults to rule), append rule, then setRules |
removeRule(target) |
Drop all matches, then setRules |
toggleRule(rule, target?) |
Add or remove via hasRule |
clearRules() |
setRules([]) |
setRules does not deduplicate (preserves programmatic edits); setFromUserInterface (Apply/Save) still deduplicates via _deduplicateRulesetRules.
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.
addBookmarksFieldaddBookmarksField('Bookmarks', 'Add pages you visit often.', {
storageKey: 'myscript-bookmarks', // default: {scriptPrefix}bookmarks
storage: 'gm', // default
normalizeBookmarks: (stored) => /* sanitize array */,
showAddButton: true,
pageMatch: { getCurrentUrl, normalizeUrl, onMatchChange, watchSelectors, isActive },
onAdd, onSort, onRemove(id), onNavigate(url),
getRowActions(bookmark), // optional → HTMLElement[] | JQuery[]
})
| Behaviour | Detail |
|---|---|
persist |
false — not in aggregate blob; dedicated GM key via GmStorageDriver |
storage |
'gm' by default |
| Field API | reload(), save(), serializeForBackup(), applyFromBackup() (replace on restore) |
widget |
BrazenBookmarksPanel from createBookmarksPanel |
setFromUserInterface |
No-op — mutations call field.save() from site handlers |
updateUserInterface |
reload() then widget.render(value) |
createElementthis._configurationManager.createElement('My Setting') // display name
Invokes the field's createElement() which:
field.element.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 |
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.
Each field has a storage driver key (local by default). Simple fields persist in a per-driver aggregate blob; self-managed types (persist: false, e.g. ledger, bookmarks) use driver primitives directly and participate in backup v2 when they implement serializeForBackup.
| Store | Driver | Key | Content |
|---|---|---|---|
| Settings | local |
{scriptPrefix}settings |
JSON object: kebab keys → values (skips persist: false) |
| Sync id | local |
{scriptPrefix}settings-id |
{ id: number } — bumps on save |
| Settings | gm |
{scriptPrefix}settings |
Same shape in GM namespace (lazy; only when a field uses gm) |
| Sync id | gm |
{scriptPrefix}settings-id |
Same in GM namespace |
initialize()local driver stores (LocalStore)._syncDriverStores('local') — merge disk into fields; rulesets run onOptimize.onChange on settings store → updateInterface().visibilitychange — if tab visible and local id changed, re-sync + onExternalConfigurationChange.| 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:
update() + re-run compliance (no disk).save().revertChanges() + compliance.backup() downloads {scriptPrefix}backup.json:
{
"version": 2,
"id": 123456789,
"drivers": {
"local": {
"tag-blacklist": ["rule1", "rule2"],
"pagination-threshold": 20
},
"gm": {
"download-ledger": { "postIds": ["123", "456"] },
"bookmarks": [{ "id": "…", "label": "…", "tags": "…", "url": "…" }]
}
}
}
Legacy flat backups (no version / drivers) still import as local values.
restore(response) — fetch/Response with JSON body; each field's applyFromBackup handles semantics (ledger merges ids; bookmarks replace list); restores values + sync id; alerts success/failure. Legacy v1 backups without a bookmarks key leave local bookmarks untouched.
onExternalConfigurationChange(handler) — (manager) => void when another tab saved. Framework registers compliance re-run.
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.
init() builds UI.createElement inside tab panels.addFlagField + ruleset).addLedgerField, addBookmarksField) use dedicated driver keys — no ad-hoc GM_setValue in apps.#bv-ui userScript reference if tabs need updateInterface from custom widgets.Next in stack: Item Attributes Resolver (before Framework core).