diff options
Diffstat (limited to 'ext')
| -rw-r--r-- | ext/bg/js/settings/generic-setting-controller.js | 177 | ||||
| -rw-r--r-- | ext/bg/js/settings/settings-controller.js | 4 | ||||
| -rw-r--r-- | ext/bg/settings.html | 134 | 
3 files changed, 94 insertions, 221 deletions
| diff --git a/ext/bg/js/settings/generic-setting-controller.js b/ext/bg/js/settings/generic-setting-controller.js index d7d40c5d..aa3118e5 100644 --- a/ext/bg/js/settings/generic-setting-controller.js +++ b/ext/bg/js/settings/generic-setting-controller.js @@ -16,182 +16,47 @@   */  /* globals + * DOMSettingsBinder   * utilBackgroundIsolate   */  class GenericSettingController {      constructor(settingsController) {          this._settingsController = settingsController; +        this._settingsBinder = null;      }      async prepare() { -        $('input, select, textarea').not('.anki-model').not('.ignore-form-changes *').change(this._onFormOptionsChanged.bind(this)); +        this._settingsBinder = new DOMSettingsBinder({ +            getOptionsContext: () => this._settingsController.getOptionsContext(), +            source: this._settingsController.source, +            transforms: [ +                ['setDocumentAttribute', this._setDocumentAttribute.bind(this)], +                ['splitTags', this._splitTags.bind(this)], +                ['joinTags', this._joinTags.bind(this)] +            ] +        }); +        this._settingsBinder.observe(document.body);          this._settingsController.on('optionsChanged', this._onOptionsChanged.bind(this)); - -        const options = await this._settingsController.getOptions(); -        this._onOptionsChanged({options});      }      // Private -    _onOptionsChanged({options}) { -        $('#enable').prop('checked', options.general.enable); -        $('#show-usage-guide').prop('checked', options.general.showGuide); -        $('#compact-tags').prop('checked', options.general.compactTags); -        $('#compact-glossaries').prop('checked', options.general.compactGlossaries); -        $('#result-output-mode').val(options.general.resultOutputMode); -        $('#show-debug-info').prop('checked', options.general.debugInfo); -        $('#show-advanced-options').prop('checked', options.general.showAdvanced); -        $('#max-displayed-results').val(options.general.maxResults); -        $('#popup-display-mode').val(options.general.popupDisplayMode); -        $('#popup-horizontal-text-position').val(options.general.popupHorizontalTextPosition); -        $('#popup-vertical-text-position').val(options.general.popupVerticalTextPosition); -        $('#popup-width').val(options.general.popupWidth); -        $('#popup-height').val(options.general.popupHeight); -        $('#popup-horizontal-offset').val(options.general.popupHorizontalOffset); -        $('#popup-vertical-offset').val(options.general.popupVerticalOffset); -        $('#popup-horizontal-offset2').val(options.general.popupHorizontalOffset2); -        $('#popup-vertical-offset2').val(options.general.popupVerticalOffset2); -        $('#popup-scaling-factor').val(options.general.popupScalingFactor); -        $('#popup-scale-relative-to-page-zoom').prop('checked', options.general.popupScaleRelativeToPageZoom); -        $('#popup-scale-relative-to-visual-viewport').prop('checked', options.general.popupScaleRelativeToVisualViewport); -        $('#show-pitch-accent-downstep-notation').prop('checked', options.general.showPitchAccentDownstepNotation); -        $('#show-pitch-accent-position-notation').prop('checked', options.general.showPitchAccentPositionNotation); -        $('#show-pitch-accent-graph').prop('checked', options.general.showPitchAccentGraph); -        $('#show-iframe-popups-in-root-frame').prop('checked', options.general.showIframePopupsInRootFrame); -        $('#popup-theme').val(options.general.popupTheme); -        $('#popup-outer-theme').val(options.general.popupOuterTheme); -        $('#custom-popup-css').val(options.general.customPopupCss); -        $('#custom-popup-outer-css').val(options.general.customPopupOuterCss); - -        $('#audio-playback-enabled').prop('checked', options.audio.enabled); -        $('#auto-play-audio').prop('checked', options.audio.autoPlay); -        $('#audio-playback-volume').val(options.audio.volume); -        $('#audio-custom-source').val(options.audio.customSourceUrl); -        $('#text-to-speech-voice').val(options.audio.textToSpeechVoice).attr('data-value', options.audio.textToSpeechVoice); - -        $('#middle-mouse-button-scan').prop('checked', options.scanning.middleMouse); -        $('#touch-input-enabled').prop('checked', options.scanning.touchInputEnabled); -        $('#select-matched-text').prop('checked', options.scanning.selectText); -        $('#search-alphanumeric').prop('checked', options.scanning.alphanumeric); -        $('#auto-hide-results').prop('checked', options.scanning.autoHideResults); -        $('#deep-dom-scan').prop('checked', options.scanning.deepDomScan); -        $('#enable-search-within-first-popup').prop('checked', options.scanning.enablePopupSearch); -        $('#enable-scanning-of-popup-expressions').prop('checked', options.scanning.enableOnPopupExpressions); -        $('#enable-scanning-on-search-page').prop('checked', options.scanning.enableOnSearchPage); -        $('#enable-search-tags').prop('checked', options.scanning.enableSearchTags); -        $('#scan-delay').val(options.scanning.delay); -        $('#scan-length').val(options.scanning.length); -        $('#scan-modifier-key').val(options.scanning.modifier); -        $('#popup-nesting-max-depth').val(options.scanning.popupNestingMaxDepth); - -        $('#translation-convert-half-width-characters').val(options.translation.convertHalfWidthCharacters); -        $('#translation-convert-numeric-characters').val(options.translation.convertNumericCharacters); -        $('#translation-convert-alphabetic-characters').val(options.translation.convertAlphabeticCharacters); -        $('#translation-convert-hiragana-to-katakana').val(options.translation.convertHiraganaToKatakana); -        $('#translation-convert-katakana-to-hiragana').val(options.translation.convertKatakanaToHiragana); -        $('#translation-collapse-emphatic-sequences').val(options.translation.collapseEmphaticSequences); - -        $('#parsing-scan-enable').prop('checked', options.parsing.enableScanningParser); -        $('#parsing-mecab-enable').prop('checked', options.parsing.enableMecabParser); -        $('#parsing-term-spacing').prop('checked', options.parsing.termSpacing); -        $('#parsing-reading-mode').val(options.parsing.readingMode); - -        $('#anki-enable').prop('checked', options.anki.enable); -        $('#card-tags').val(options.anki.tags.join(' ')); -        $('#sentence-detection-extent').val(options.anki.sentenceExt); -        $('#interface-server').val(options.anki.server); -        $('#duplicate-scope').val(options.anki.duplicateScope); -        $('#screenshot-format').val(options.anki.screenshot.format); -        $('#screenshot-quality').val(options.anki.screenshot.quality); - -        this._formUpdateVisibility(options); +    _onOptionsChanged() { +        this._settingsBinder.refresh();      } -    _formRead(options) { -        options.general.enable = $('#enable').prop('checked'); -        options.general.showGuide = $('#show-usage-guide').prop('checked'); -        options.general.compactTags = $('#compact-tags').prop('checked'); -        options.general.compactGlossaries = $('#compact-glossaries').prop('checked'); -        options.general.resultOutputMode = $('#result-output-mode').val(); -        options.general.debugInfo = $('#show-debug-info').prop('checked'); -        options.general.showAdvanced = $('#show-advanced-options').prop('checked'); -        options.general.maxResults = parseInt($('#max-displayed-results').val(), 10); -        options.general.popupDisplayMode = $('#popup-display-mode').val(); -        options.general.popupHorizontalTextPosition = $('#popup-horizontal-text-position').val(); -        options.general.popupVerticalTextPosition = $('#popup-vertical-text-position').val(); -        options.general.popupWidth = parseInt($('#popup-width').val(), 10); -        options.general.popupHeight = parseInt($('#popup-height').val(), 10); -        options.general.popupHorizontalOffset = parseInt($('#popup-horizontal-offset').val(), 0); -        options.general.popupVerticalOffset = parseInt($('#popup-vertical-offset').val(), 10); -        options.general.popupHorizontalOffset2 = parseInt($('#popup-horizontal-offset2').val(), 0); -        options.general.popupVerticalOffset2 = parseInt($('#popup-vertical-offset2').val(), 10); -        options.general.popupScalingFactor = parseFloat($('#popup-scaling-factor').val()); -        options.general.popupScaleRelativeToPageZoom = $('#popup-scale-relative-to-page-zoom').prop('checked'); -        options.general.popupScaleRelativeToVisualViewport = $('#popup-scale-relative-to-visual-viewport').prop('checked'); -        options.general.showPitchAccentDownstepNotation = $('#show-pitch-accent-downstep-notation').prop('checked'); -        options.general.showPitchAccentPositionNotation = $('#show-pitch-accent-position-notation').prop('checked'); -        options.general.showPitchAccentGraph = $('#show-pitch-accent-graph').prop('checked'); -        options.general.showIframePopupsInRootFrame = $('#show-iframe-popups-in-root-frame').prop('checked'); -        options.general.popupTheme = $('#popup-theme').val(); -        options.general.popupOuterTheme = $('#popup-outer-theme').val(); -        options.general.customPopupCss = $('#custom-popup-css').val(); -        options.general.customPopupOuterCss = $('#custom-popup-outer-css').val(); - -        options.audio.enabled = $('#audio-playback-enabled').prop('checked'); -        options.audio.autoPlay = $('#auto-play-audio').prop('checked'); -        options.audio.volume = parseFloat($('#audio-playback-volume').val()); -        options.audio.customSourceUrl = $('#audio-custom-source').val(); -        options.audio.textToSpeechVoice = $('#text-to-speech-voice').val(); - -        options.scanning.middleMouse = $('#middle-mouse-button-scan').prop('checked'); -        options.scanning.touchInputEnabled = $('#touch-input-enabled').prop('checked'); -        options.scanning.selectText = $('#select-matched-text').prop('checked'); -        options.scanning.alphanumeric = $('#search-alphanumeric').prop('checked'); -        options.scanning.autoHideResults = $('#auto-hide-results').prop('checked'); -        options.scanning.deepDomScan = $('#deep-dom-scan').prop('checked'); -        options.scanning.enablePopupSearch = $('#enable-search-within-first-popup').prop('checked'); -        options.scanning.enableOnPopupExpressions = $('#enable-scanning-of-popup-expressions').prop('checked'); -        options.scanning.enableOnSearchPage = $('#enable-scanning-on-search-page').prop('checked'); -        options.scanning.enableSearchTags = $('#enable-search-tags').prop('checked'); -        options.scanning.delay = parseInt($('#scan-delay').val(), 10); -        options.scanning.length = parseInt($('#scan-length').val(), 10); -        options.scanning.modifier = $('#scan-modifier-key').val(); -        options.scanning.popupNestingMaxDepth = parseInt($('#popup-nesting-max-depth').val(), 10); - -        options.translation.convertHalfWidthCharacters = $('#translation-convert-half-width-characters').val(); -        options.translation.convertNumericCharacters = $('#translation-convert-numeric-characters').val(); -        options.translation.convertAlphabeticCharacters = $('#translation-convert-alphabetic-characters').val(); -        options.translation.convertHiraganaToKatakana = $('#translation-convert-hiragana-to-katakana').val(); -        options.translation.convertKatakanaToHiragana = $('#translation-convert-katakana-to-hiragana').val(); -        options.translation.collapseEmphaticSequences = $('#translation-collapse-emphatic-sequences').val(); - -        options.parsing.enableScanningParser = $('#parsing-scan-enable').prop('checked'); -        options.parsing.enableMecabParser = $('#parsing-mecab-enable').prop('checked'); -        options.parsing.termSpacing = $('#parsing-term-spacing').prop('checked'); -        options.parsing.readingMode = $('#parsing-reading-mode').val(); - -        options.anki.enable = $('#anki-enable').prop('checked'); -        options.anki.tags = utilBackgroundIsolate($('#card-tags').val().split(/[,; ]+/)); -        options.anki.sentenceExt = parseInt($('#sentence-detection-extent').val(), 10); -        options.anki.server = $('#interface-server').val(); -        options.anki.duplicateScope = $('#duplicate-scope').val(); -        options.anki.screenshot.format = $('#screenshot-format').val(); -        options.anki.screenshot.quality = parseInt($('#screenshot-quality').val(), 10); +    _setDocumentAttribute(value, metadata, element) { +        document.documentElement.setAttribute(element.dataset.documentAttribute, `${value}`); +        return value;      } -    async _onFormOptionsChanged() { -        const options = await this._settingsController.getOptionsMutable(); -        this._formRead(options); -        this._formUpdateVisibility(options); -        await this._settingsController.save(); +    _splitTags(value) { +        return `${value}`.split(/[,; ]+/).filter((v) => !!v);      } -    _formUpdateVisibility(options) { -        document.documentElement.dataset.optionsAnkiEnable = `${!!options.anki.enable}`; -        document.documentElement.dataset.optionsGeneralDebugInfo = `${!!options.general.debugInfo}`; -        document.documentElement.dataset.optionsGeneralShowAdvanced = `${!!options.general.showAdvanced}`; -        document.documentElement.dataset.optionsGeneralResultOutputMode = `${options.general.resultOutputMode}`; +    _joinTags(value) { +        return value.join(' ');      }  } diff --git a/ext/bg/js/settings/settings-controller.js b/ext/bg/js/settings/settings-controller.js index 0d7abaa9..9224aedf 100644 --- a/ext/bg/js/settings/settings-controller.js +++ b/ext/bg/js/settings/settings-controller.js @@ -28,6 +28,10 @@ class SettingsController extends EventDispatcher {          this._source = yomichan.generateId(16);      } +    get source() { +        return this._source; +    } +      get profileIndex() {          return this._profileIndex;      } diff --git a/ext/bg/settings.html b/ext/bg/settings.html index bab62519..1baeeced 100644 --- a/ext/bg/settings.html +++ b/ext/bg/settings.html @@ -135,7 +135,7 @@                  <h3>General Options</h3>                  <div class="checkbox"> -                    <label><input type="checkbox" id="enable"> Enable content scanning</label> +                    <label><input type="checkbox" id="enable" data-setting="general.enable"> Enable content scanning</label>                  </div>                  <div class="checkbox ignore-form-changes" data-hide-for-browser="firefox-mobile"> @@ -143,52 +143,52 @@                  </div>                  <div class="checkbox"> -                    <label><input type="checkbox" id="show-usage-guide"> Show usage guide on startup</label> +                    <label><input type="checkbox" id="show-usage-guide" data-setting="general.showGuide"> Show usage guide on startup</label>                  </div>                  <div class="checkbox"> -                    <label><input type="checkbox" id="compact-tags"> Compact tags</label> +                    <label><input type="checkbox" id="compact-tags" data-setting="general.compactTags"> Compact tags</label>                  </div>                  <div class="checkbox"> -                    <label><input type="checkbox" id="compact-glossaries"> Compact glossaries</label> +                    <label><input type="checkbox" id="compact-glossaries" data-setting="general.compactGlossaries"> Compact glossaries</label>                  </div>                  <div class="checkbox"> -                    <label><input type="checkbox" id="show-advanced-options"> Show advanced options</label> +                    <label><input type="checkbox" id="show-advanced-options" data-setting="general.showAdvanced" data-transform-pre="setDocumentAttribute" data-transform-post="setDocumentAttribute" data-document-attribute="data-options-general-show-advanced"> Show advanced options</label>                  </div>                  <div class="checkbox options-advanced"> -                    <label><input type="checkbox" id="popup-scale-relative-to-page-zoom"> Change popup size relative to page zoom level</label> +                    <label><input type="checkbox" id="popup-scale-relative-to-page-zoom" data-setting="general.popupScaleRelativeToPageZoom"> Change popup size relative to page zoom level</label>                  </div>                  <div class="checkbox options-advanced"> -                    <label><input type="checkbox" id="popup-scale-relative-to-visual-viewport"> Change popup size relative to page viewport</label> +                    <label><input type="checkbox" id="popup-scale-relative-to-visual-viewport" data-setting="general.popupScaleRelativeToVisualViewport"> Change popup size relative to page viewport</label>                  </div>                  <div class="checkbox options-advanced"> -                    <label><input type="checkbox" id="show-pitch-accent-downstep-notation"> Show downstep notation for pitch accents</label> +                    <label><input type="checkbox" id="show-pitch-accent-downstep-notation" data-setting="general.showPitchAccentDownstepNotation"> Show downstep notation for pitch accents</label>                  </div>                  <div class="checkbox options-position"> -                    <label><input type="checkbox" id="show-pitch-accent-position-notation"> Show position notation for pitch accents</label> +                    <label><input type="checkbox" id="show-pitch-accent-position-notation" data-setting="general.showPitchAccentPositionNotation"> Show position notation for pitch accents</label>                  </div>                  <div class="checkbox options-advanced"> -                    <label><input type="checkbox" id="show-pitch-accent-graph"> Show graph for pitch accents</label> +                    <label><input type="checkbox" id="show-pitch-accent-graph" data-setting="general.showPitchAccentGraph"> Show graph for pitch accents</label>                  </div>                  <div class="checkbox options-advanced"> -                    <label><input type="checkbox" id="show-iframe-popups-in-root-frame"> Show iframe popups in root frame</label> +                    <label><input type="checkbox" id="show-iframe-popups-in-root-frame" data-setting="general.showIframePopupsInRootFrame"> Show iframe popups in root frame</label>                  </div>                  <div class="checkbox options-advanced"> -                    <label><input type="checkbox" id="show-debug-info"> Show debug information</label> +                    <label><input type="checkbox" id="show-debug-info" data-setting="general.debugInfo" data-transform-pre="setDocumentAttribute" data-transform-post="setDocumentAttribute" data-document-attribute="data-options-general-debug-info"> Show debug information</label>                  </div>                  <div class="form-group">                      <label for="result-output-mode">Result grouping</label> -                    <select class="form-control" id="result-output-mode"> +                    <select class="form-control" id="result-output-mode" data-setting="general.resultOutputMode" data-transform-pre="setDocumentAttribute" data-transform-post="setDocumentAttribute" data-document-attribute="data-options-general-result-output-mode">                          <option value="group">Group results by term-reading pairs</option>                          <option value="merge">Group results by main dictionary entry</option>                          <option value="split">Split definitions to their own results</option> @@ -197,7 +197,7 @@                  <div class="form-group">                      <label for="popup-display-mode">Popup display mode</label> -                    <select class="form-control" id="popup-display-mode"> +                    <select class="form-control" id="popup-display-mode" data-setting="general.popupDisplayMode">                          <option value="default">Default</option>                          <option value="full-width">Full width</option>                      </select> @@ -205,26 +205,26 @@                  <div class="form-group">                      <label for="popup-scaling-factor">Popup size multiplier</label> -                    <input type="number" min="0" id="popup-scaling-factor" class="form-control"> +                    <input type="number" min="0" id="popup-scaling-factor" data-setting="general.popupScalingFactor" class="form-control">                  </div>                  <div class="form-group options-advanced">                      <label for="max-displayed-results">Maximum displayed results</label> -                    <input type="number" min="1" id="max-displayed-results" class="form-control"> +                    <input type="number" min="1" id="max-displayed-results" class="form-control" data-setting="general.maxResults">                  </div>                  <div class="form-group">                      <div class="row">                          <div class="col-xs-6">                              <label for="popup-horizontal-text-position">Popup position for horizontal text</label> -                            <select class="form-control" id="popup-horizontal-text-position"> +                            <select class="form-control" id="popup-horizontal-text-position" data-setting="general.popupHorizontalTextPosition">                                  <option value="below">Below text</option>                                  <option value="above">Above text</option>                              </select>                          </div>                          <div class="col-xs-6">                              <label for="popup-vertical-text-position">Popup position for vertical text</label> -                            <select class="form-control" id="popup-vertical-text-position"> +                            <select class="form-control" id="popup-vertical-text-position" data-setting="general.popupVerticalTextPosition">                                  <option value="default">Same as for horizontal text</option>                                  <option value="before">Before text reading direction</option>                                  <option value="after">After text reading direction</option> @@ -239,11 +239,11 @@                      <div class="row">                          <div class="col-xs-6">                              <label for="popup-width">Popup width <span class="label-light">(in pixels)</span></label> -                            <input type="number" min="1" id="popup-width" class="form-control"> +                            <input type="number" min="1" id="popup-width" class="form-control" data-setting="general.popupWidth">                          </div>                          <div class="col-xs-6">                              <label for="popup-height">Popup height <span class="label-light">(in pixels)</span></label> -                            <input type="number" min="1" id="popup-height" class="form-control"> +                            <input type="number" min="1" id="popup-height" class="form-control" data-setting="general.popupHeight">                          </div>                      </div>                  </div> @@ -252,11 +252,11 @@                      <div class="row">                          <div class="col-xs-6">                              <label for="popup-horizontal-offset">Horizontal popup offset <span class="label-light">(in pixels)</span></label> -                            <input type="number" min="0" id="popup-horizontal-offset" class="form-control"> +                            <input type="number" min="0" id="popup-horizontal-offset" class="form-control" data-setting="general.popupHorizontalOffset">                          </div>                          <div class="col-xs-6">                              <label for="popup-vertical-offset">Vertical popup offset <span class="label-light">(in pixels)</span></label> -                            <input type="number" min="0" id="popup-vertical-offset" class="form-control"> +                            <input type="number" min="0" id="popup-vertical-offset" class="form-control" data-setting="general.popupVerticalOffset">                          </div>                      </div>                  </div> @@ -265,11 +265,11 @@                      <div class="row">                          <div class="col-xs-6">                              <label for="popup-horizontal-offset2">Horizontal popup offset for vertical text <span class="label-light">(in pixels)</span></label> -                            <input type="number" min="0" id="popup-horizontal-offset2" class="form-control"> +                            <input type="number" min="0" id="popup-horizontal-offset2" class="form-control" data-setting="general.popupHorizontalOffset2">                          </div>                          <div class="col-xs-6">                              <label for="popup-vertical-offset2">Vertical popup offset for vertical text <span class="label-light">(in pixels)</span></label> -                            <input type="number" min="0" id="popup-vertical-offset2" class="form-control"> +                            <input type="number" min="0" id="popup-vertical-offset2" class="form-control" data-setting="general.popupVerticalOffset2">                          </div>                      </div>                  </div> @@ -278,14 +278,14 @@                      <div class="row">                          <div class="col-xs-6">                              <label for="popup-theme">Popup theme</label> -                            <select class="form-control" id="popup-theme"> +                            <select class="form-control" id="popup-theme" data-setting="general.popupTheme">                                  <option value="default">Light</option>                                  <option value="dark">Dark</option>                              </select>                          </div>                          <div class="col-xs-6">                              <label for="popup-outer-theme">Popup shadow theme</label> -                            <select class="form-control" id="popup-outer-theme"> +                            <select class="form-control" id="popup-outer-theme" data-setting="general.popupOuterTheme">                                  <option value="auto">Auto-detect</option>                                  <option value="default">Light</option>                                  <option value="dark">Dark</option> @@ -298,11 +298,11 @@                      <div class="row">                          <div class="col-xs-6">                              <label for="custom-popup-css">Custom popup CSS</label> -                            <div><textarea autocomplete="off" spellcheck="false" wrap="soft" id="custom-popup-css" class="form-control"></textarea></div> +                            <div><textarea autocomplete="off" spellcheck="false" wrap="soft" id="custom-popup-css" class="form-control" data-setting="general.customPopupCss"></textarea></div>                          </div>                          <div class="col-xs-6">                              <label for="custom-popup-outer-css">Custom popup outer CSS</label> -                            <div><textarea autocomplete="off" spellcheck="false" wrap="soft" id="custom-popup-outer-css" class="form-control" placeholder="iframe.yomichan-float { /*styles*/ }"></textarea></div> +                            <div><textarea autocomplete="off" spellcheck="false" wrap="soft" id="custom-popup-outer-css" class="form-control" data-setting="general.customPopupOuterCss" placeholder="iframe.yomichan-float { /*styles*/ }"></textarea></div>                          </div>                      </div>                  </div> @@ -324,22 +324,22 @@                  <h3>Audio Options</h3>                  <div class="checkbox"> -                    <label><input type="checkbox" id="audio-playback-enabled"> Enable audio playback in search results</label> +                    <label><input type="checkbox" id="audio-playback-enabled" data-setting="audio.enabled"> Enable audio playback in search results</label>                  </div>                  <div class="checkbox"> -                    <label><input type="checkbox" id="auto-play-audio"> Play audio automatically</label> +                    <label><input type="checkbox" id="auto-play-audio" data-setting="audio.autoPlay"> Play audio automatically</label>                  </div>                  <div class="form-group">                      <label for="audio-playback-volume">Audio playback volume <span class="label-light">(percent)</span></label> -                    <input type="number" min="0" max="100" id="audio-playback-volume" class="form-control"> +                    <input type="number" min="0" max="100" id="audio-playback-volume" class="form-control" data-setting="audio.volume">                  </div>                  <div class="form-group" id="text-to-speech-voice-container" hidden>                      <label for="text-to-speech-voice">Text-to-speech voice</label>                      <div class="input-group"> -                        <select class="form-control" id="text-to-speech-voice"></select> +                        <select class="form-control" id="text-to-speech-voice" data-setting="audio.textToSpeechVoice"></select>                          <div class="input-group-btn">                              <button class="btn btn-default" id="text-to-speech-voice-test" title="Test voice" data-speech-text="よみちゃん"><span class="glyphicon glyphicon-volume-up"></span></button>                          </div> @@ -348,7 +348,7 @@                  <div class="form-group options-advanced">                      <label for="audio-custom-source">Custom audio source <span class="label-light">(URL)</span></label> -                    <input type="text" id="audio-custom-source" class="form-control" placeholder="Example: http://localhost/audio.mp3?expression={expression}&reading={reading}"> +                    <input type="text" id="audio-custom-source" class="form-control" data-setting="audio.customSourceUrl" placeholder="Example: http://localhost/audio.mp3?expression={expression}&reading={reading}">                  </div>                  <div class="form-group ignore-form-changes"> @@ -377,42 +377,42 @@                  <h3>Scanning Options</h3>                  <div class="checkbox"> -                    <label><input type="checkbox" id="middle-mouse-button-scan"> Middle mouse button scans</label> +                    <label><input type="checkbox" id="middle-mouse-button-scan" data-setting="scanning.middleMouse"> Middle mouse button scans</label>                  </div>                  <div class="checkbox"> -                    <label><input type="checkbox" id="touch-input-enabled"> Touch input enabled</label> +                    <label><input type="checkbox" id="touch-input-enabled" data-setting="scanning.touchInputEnabled"> Touch input enabled</label>                  </div>                  <div class="checkbox"> -                    <label><input type="checkbox" id="select-matched-text"> Select matched text</label> +                    <label><input type="checkbox" id="select-matched-text" data-setting="scanning.selectText"> Select matched text</label>                  </div>                  <div class="checkbox"> -                    <label><input type="checkbox" id="search-alphanumeric"> Search alphanumeric text</label> +                    <label><input type="checkbox" id="search-alphanumeric" data-setting="scanning.alphanumeric"> Search alphanumeric text</label>                  </div>                  <div class="checkbox"> -                    <label><input type="checkbox" id="auto-hide-results"> Automatically hide results</label> +                    <label><input type="checkbox" id="auto-hide-results" data-setting="scanning.autoHideResults"> Automatically hide results</label>                  </div>                  <div class="checkbox options-advanced"> -                    <label><input type="checkbox" id="deep-dom-scan"> Deep DOM scan</label> +                    <label><input type="checkbox" id="deep-dom-scan" data-setting="scanning.deepDomScan"> Deep DOM scan</label>                  </div>                  <div class="form-group options-advanced">                      <label for="scan-delay">Scan delay <span class="label-light">(in milliseconds)</span></label> -                    <input type="number" min="0" id="scan-delay" class="form-control"> +                    <input type="number" min="0" id="scan-delay" class="form-control" data-setting="scanning.delay">                  </div>                  <div class="form-group options-advanced">                      <label for="scan-length">Scan length <span class="label-light">(in characters)</span></label> -                    <input type="number" min="1" step="1" id="scan-length" class="form-control"> +                    <input type="number" min="1" step="1" id="scan-length" class="form-control" data-setting="scanning.length">                  </div>                  <div class="form-group">                      <label for="scan-modifier-key">Scan modifier key</label> -                    <select class="form-control" id="scan-modifier-key"></select> +                    <select class="form-control" id="scan-modifier-key" data-setting="scanning.modifier"></select>                  </div>              </div> @@ -447,7 +447,7 @@                  <div class="form-group">                      <label for="translation-convert-half-width-characters">Convert half width characters to full width <span class="label-light">(ヨミチャン → ヨミチャン)</span></label> -                    <select class="form-control" id="translation-convert-half-width-characters"> +                    <select class="form-control" id="translation-convert-half-width-characters" data-setting="translation.convertHalfWidthCharacters">                          <option value="false">Disabled</option>                          <option value="true">Enabled</option>                          <option value="variant">Use both variants</option> @@ -456,7 +456,7 @@                  <div class="form-group">                      <label for="translation-convert-numeric-characters">Convert numeric characters to full width <span class="label-light">(1234 → 1234)</span></label> -                    <select class="form-control" id="translation-convert-numeric-characters"> +                    <select class="form-control" id="translation-convert-numeric-characters" data-setting="translation.convertNumericCharacters">                          <option value="false">Disabled</option>                          <option value="true">Enabled</option>                          <option value="variant">Use both variants</option> @@ -465,7 +465,7 @@                  <div class="form-group">                      <label for="translation-convert-alphabetic-characters">Convert alphabetic characters to hiragana <span class="label-light">(yomichan → よみちゃん)</span></label> -                    <select class="form-control" id="translation-convert-alphabetic-characters"> +                    <select class="form-control" id="translation-convert-alphabetic-characters" data-setting="translation.convertAlphabeticCharacters">                          <option value="false">Disabled</option>                          <option value="true">Enabled</option>                          <option value="variant">Use both variants</option> @@ -474,7 +474,7 @@                  <div class="form-group">                      <label for="translation-convert-hiragana-to-katakana">Convert hiragana to katakana <span class="label-light">(よみちゃん → ヨミチャン)</span></label> -                    <select class="form-control" id="translation-convert-hiragana-to-katakana"> +                    <select class="form-control" id="translation-convert-hiragana-to-katakana" data-setting="translation.convertHiraganaToKatakana">                          <option value="false">Disabled</option>                          <option value="true">Enabled</option>                          <option value="variant">Use both variants</option> @@ -483,7 +483,7 @@                  <div class="form-group">                      <label for="translation-convert-katakana-to-hiragana">Convert katakana to hiragana <span class="label-light">(ヨミチャン → よみちゃん)</span></label> -                    <select class="form-control" id="translation-convert-katakana-to-hiragana"> +                    <select class="form-control" id="translation-convert-katakana-to-hiragana" data-setting="translation.convertKatakanaToHiragana">                          <option value="false">Disabled</option>                          <option value="true">Enabled</option>                          <option value="variant">Use both variants</option> @@ -492,7 +492,7 @@                  <div class="form-group">                      <label for="translation-collapse-emphatic-sequences">Collapse emphatic character sequences <span class="label-light">(すっっごーーい → すっごーい / すごい)</span></label> -                    <select class="form-control" id="translation-collapse-emphatic-sequences"> +                    <select class="form-control" id="translation-collapse-emphatic-sequences" data-setting="translation.collapseEmphaticSequences">                          <option value="false">Disabled</option>                          <option value="true">Collapse into single character</option>                          <option value="full">Remove all characters</option> @@ -509,24 +509,24 @@                  </p>                  <div class="checkbox"> -                    <label><input type="checkbox" id="enable-search-within-first-popup"> Enable search when clicking glossary entries and tags</label> +                    <label><input type="checkbox" id="enable-search-within-first-popup" data-setting="scanning.enablePopupSearch"> Enable search when clicking glossary entries and tags</label>                  </div>                  <div class="checkbox"> -                    <label><input type="checkbox" id="enable-scanning-on-search-page"> Enable scanning on search page</label> +                    <label><input type="checkbox" id="enable-scanning-on-search-page" data-setting="scanning.enableOnSearchPage"> Enable scanning on search page</label>                  </div>                  <div class="checkbox"> -                    <label><input type="checkbox" id="enable-scanning-of-popup-expressions"> Enable scanning of expressions in search results</label> +                    <label><input type="checkbox" id="enable-scanning-of-popup-expressions" data-setting="scanning.enableOnPopupExpressions"> Enable scanning of expressions in search results</label>                  </div>                  <div class="checkbox"> -                    <label><input type="checkbox" id="enable-search-tags"> Enable clickable and scannable tags for searching expressions and their readings</label> +                    <label><input type="checkbox" id="enable-search-tags" data-setting="scanning.enableSearchTags"> Enable clickable and scannable tags for searching expressions and their readings</label>                  </div>                  <div class="form-group">                      <label for="popup-nesting-max-depth">Maximum number of additional popups</label> -                    <input type="number" min="0" step="1" id="popup-nesting-max-depth" class="form-control"> +                    <input type="number" min="0" step="1" id="popup-nesting-max-depth" class="form-control" data-setting="scanning.popupNestingMaxDepth">                  </div>              </div> @@ -551,20 +551,20 @@                  </p>                  <div class="checkbox"> -                    <label><input type="checkbox" id="parsing-scan-enable"> Enable text parsing using installed dictionaries</label> +                    <label><input type="checkbox" id="parsing-scan-enable" data-setting="parsing.enableScanningParser"> Enable text parsing using installed dictionaries</label>                  </div>                  <div class="checkbox"> -                    <label><input type="checkbox" id="parsing-mecab-enable"> Enable text parsing using MeCab</label> +                    <label><input type="checkbox" id="parsing-mecab-enable" data-setting="parsing.enableMecabParser"> Enable text parsing using MeCab</label>                  </div>                  <div class="checkbox"> -                    <label><input type="checkbox" id="parsing-term-spacing"> Enable small spaces between parsed words</label> +                    <label><input type="checkbox" id="parsing-term-spacing" data-setting="parsing.termSpacing"> Enable small spaces between parsed words</label>                  </div>                  <div class="form-group">                      <label for="parsing-reading-mode">Reading mode</label> -                    <select class="form-control" id="parsing-reading-mode"> +                    <select class="form-control" id="parsing-reading-mode" data-setting="parsing.readingMode">                          <option value="hiragana">ひらがな</option>                          <option value="katakana">カタカナ</option>                          <option value="romaji">Romaji</option> @@ -621,7 +621,7 @@                  </div>                  <div class="checkbox"> -                    <label><input type="checkbox" id="database-enable-prefix-wildcard-searches"> Enable prefix wildcard searches</label> +                    <label><input type="checkbox" id="database-enable-prefix-wildcard-searches" data-setting="global.database.prefixWildcardsSupported" data-scope="global"> Enable prefix wildcard searches</label>                      <p class="help-block">                          This option only applies to newly imported dictionaries.                          Enabling this option will also cause dictionary data to take up slightly more storage space. @@ -781,7 +781,7 @@                  </p>                  <div class="checkbox"> -                    <label><input type="checkbox" id="anki-enable"> Enable Anki integration</label> +                    <label><input type="checkbox" id="anki-enable" data-setting="anki.enable"  data-transform-pre="setDocumentAttribute" data-transform-post="setDocumentAttribute" data-document-attribute="data-options-anki-enable"> Enable Anki integration</label>                  </div>                  <div id="anki-general"> @@ -804,22 +804,22 @@                      <div class="form-group">                          <label for="card-tags">Card tags <span class="label-light">(comma or space separated)</span></label> -                        <input type="text" id="card-tags" class="form-control"> +                        <input type="text" id="card-tags" class="form-control" data-setting="anki.tags" data-transform-pre="splitTags" data-transform-post="joinTags">                      </div>                      <div class="form-group options-advanced">                          <label for="sentence-detection-extent">Sentence detection extent <span class="label-light">(in characters)</span></label> -                        <input type="number" min="1" step="1" id="sentence-detection-extent" class="form-control"> +                        <input type="number" min="1" step="1" id="sentence-detection-extent" class="form-control" data-setting="anki.sentenceExt">                      </div>                      <div class="form-group options-advanced">                          <label for="interface-server">Interface server <span class="label-light">(Default: http://127.0.0.1:8765)</span></label> -                        <input type="text" id="interface-server" class="form-control"> +                        <input type="text" id="interface-server" class="form-control" data-setting="anki.server">                      </div>                      <div class="form-group options-advanced">                          <label for="duplicate-scope">Duplicate scope</label> -                        <select class="form-control" id="duplicate-scope"> +                        <select class="form-control" id="duplicate-scope" data-setting="anki.duplicateScope">                              <option value="collection">Collection</option>                              <option value="deck">Deck</option>                          </select> @@ -827,7 +827,7 @@                      <div class="form-group options-advanced">                          <label for="screenshot-format">Screenshot format</label> -                        <select class="form-control" id="screenshot-format"> +                        <select class="form-control" id="screenshot-format" data-setting="anki.screenshot.format">                              <option value="png">PNG</option>                              <option value="jpeg">JPEG</option>                          </select> @@ -835,7 +835,7 @@                      <div class="form-group options-advanced">                          <label for="screenshot-quality">Screenshot quality <span class="label-light">(JPEG only)</span></label> -                        <input type="number" min="0" max="100" step="1" id="screenshot-quality" class="form-control"> +                        <input type="number" min="0" max="100" step="1" id="screenshot-quality" class="form-control" data-setting="anki.screenshot.quality">                      </div>                      <div id="anki-format"> @@ -1144,11 +1144,15 @@          <script src="/bg/js/settings/clipboard-popups-controller.js"></script>          <script src="/bg/js/settings/conditions-ui.js"></script>          <script src="/bg/js/settings/dictionaries.js"></script> +        <script src="/bg/js/settings/dom-settings-binder.js"></script>          <script src="/bg/js/settings/generic-setting-controller.js"></script>          <script src="/bg/js/settings/popup-preview.js"></script>          <script src="/bg/js/settings/profiles.js"></script>          <script src="/bg/js/settings/settings-controller.js"></script>          <script src="/bg/js/settings/storage.js"></script> +        <script src="/mixed/js/object-property-accessor.js"></script> +        <script src="/mixed/js/task-accumulator.js"></script> +        <script src="/mixed/js/dom-data-binder.js"></script>          <script src="/bg/js/settings/main.js"></script>      </body> |