diff --git a/src/config.js b/src/config.js index 49f9c485..3a6e976f 100644 --- a/src/config.js +++ b/src/config.js @@ -1,6 +1,6 @@ const CONFIG_KEY = 'ytaf-configuration'; -export const configOptions = new Map([ +const configOptions = new Map([ ['enableAdBlock', { default: true, desc: 'Enable ad blocking' }], ['enableSponsorBlock', { default: true, desc: 'Enable SponsorBlock' }], [ @@ -40,6 +40,15 @@ const defaultConfig = (() => { return ret; })(); +/** @type {Record} as const */ +const configFrags = (() => { + let ret = {}; + for (const k of configOptions.keys()) { + ret[k] = new DocumentFragment(); + } + return ret; +})(); + function loadStoredConfig() { const storage = window.localStorage.getItem(CONFIG_KEY); @@ -63,7 +72,7 @@ function configExists(key) { return configOptions.has(key); } -export function getConfigDesc(key) { +export function configGetDesc(key) { if (!configExists(key)) { throw new Error('tried to get desc for unknown config key: ' + key); } @@ -95,7 +104,38 @@ export function configWrite(key, value) { throw new Error('tried to write unknown config key: ' + key); } - console.info('Setting key', key, 'to', value); + const oldValue = + localConfig[key] !== undefined ? localConfig[key] : defaultConfig[key]; + + console.info('Changing key', key, 'from', oldValue, 'to', value); localConfig[key] = value; window.localStorage[CONFIG_KEY] = JSON.stringify(localConfig); + + configFrags[key].dispatchEvent( + new CustomEvent('ytafConfigChange', { + detail: { key, newValue: value, oldValue } + }) + ); +} + +/** + * Add a listener for changes in the value of a specified config option + * @param {string} key Config option to monitor + * @param {(evt: Event) => void} callback Function to be called on change + */ +export function configAddChangeListener(key, callback) { + const frag = configFrags[key]; + + frag.addEventListener('ytafConfigChange', callback); +} + +/** + * Remove a listener for changes in the value of a specified config option + * @param {string} key Config option to monitor + * @param {(evt: Event) => void} callback Function to be called on change + */ +export function configRemoveChangeListener(key, callback) { + const frag = configFrags[key]; + + frag.removeEventListener('ytafConfigChange', callback); } diff --git a/src/ui.js b/src/ui.js index 16dcf4cc..94e5ba01 100644 --- a/src/ui.js +++ b/src/ui.js @@ -1,7 +1,7 @@ /*global navigate*/ import './spatial-navigation-polyfill.js'; import './ui.css'; -import { configRead, configWrite, getConfigDesc } from './config.js'; +import { configRead, configWrite, configGetDesc } from './config.js'; // We handle key events ourselves. window.__spatialNavigation__.keyMode = 'NONE'; @@ -41,14 +41,22 @@ function createConfigCheckbox(key) { const elmInput = document.createElement('input'); elmInput.type = 'checkbox'; elmInput.checked = configRead(key); - elmInput.addEventListener('change', (evt) => { + + /** @type {(evt: Event) => void} */ + const changeHandler = (evt) => { configWrite(key, evt.target.checked); + }; + + elmInput.addEventListener('change', changeHandler); + + configAddChangeListener(key, (evt) => { + elmInput.checked = evt.detail.newValue; }); const elmLabel = document.createElement('label'); elmLabel.appendChild(elmInput); // Use non-breaking space (U+00A0) - elmLabel.appendChild(document.createTextNode('\u00A0' + getConfigDesc(key))); + elmLabel.appendChild(document.createTextNode('\u00A0' + configGetDesc(key))); return elmLabel; }