diff options
| -rw-r--r-- | ext/bg/js/api.js | 17 | ||||
| -rw-r--r-- | ext/bg/js/backend.js | 19 | ||||
| -rw-r--r-- | ext/bg/js/options.js | 138 | ||||
| -rw-r--r-- | ext/bg/settings.html | 79 | ||||
| -rw-r--r-- | ext/fg/js/api.js | 4 | ||||
| -rw-r--r-- | ext/fg/js/frontend.js | 2 | 
6 files changed, 145 insertions, 114 deletions
| diff --git a/ext/bg/js/api.js b/ext/bg/js/api.js index b8ef4362..9839aef5 100644 --- a/ext/bg/js/api.js +++ b/ext/bg/js/api.js @@ -17,16 +17,16 @@   */ -async function apiOptionsSet(options) { -    utilBackend().onOptionsUpdated(options); +function apiOptionsGetSync() { +    return utilBackend().options;  }  async function apiOptionsGet() { -    return utilBackend().options; +    return apiOptionsGetSync();  }  async function apiTermsFind(text) { -    const options = utilBackend().options; +    const options = apiOptionsGetSync();      const translator = utilBackend().translator;      const searcher = { @@ -48,13 +48,13 @@ async function apiTermsFind(text) {  }  async function apiKanjiFind(text) { -    const options = utilBackend().options; +    const options = apiOptionsGetSync();      const definitions = await utilBackend().translator.findKanji(text, dictEnabledSet(options));      return definitions.slice(0, options.general.maxResults);  }  async function apiDefinitionAdd(definition, mode, context) { -    const options = utilBackend().options; +    const options = apiOptionsGetSync();      if (mode !== 'kanji') {          await audioInject( @@ -83,7 +83,7 @@ async function apiDefinitionsAddable(definitions, modes) {          const notes = [];          for (const definition of definitions) {              for (const mode of modes) { -                const note = await dictNoteFormat(definition, mode, utilBackend().options); +                const note = await dictNoteFormat(definition, mode, apiOptionsGetSync());                  notes.push(note);              }          } @@ -131,10 +131,9 @@ async function apiCommandExec(command) {          },          toggle: async () => { -            const options = utilBackend().options; +            const options = apiOptionsGetSync();              options.general.enable = !options.general.enable;              await optionsSave(options); -            await apiOptionsSet(options);          }      }; diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index 39fd4288..b3e737da 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -28,7 +28,7 @@ class Backend {      async prepare() {          await this.translator.prepare(); -        await apiOptionsSet(await optionsLoad()); +        this.onOptionsUpdated(await optionsLoad());          if (chrome.commands !== null && typeof chrome.commands === 'object') {              chrome.commands.onCommand.addListener(this.onCommand.bind(this)); @@ -41,7 +41,8 @@ class Backend {      }      onOptionsUpdated(options) { -        this.options = utilIsolate(options); +        options = utilIsolate(options); +        this.options = options;          if (!options.general.enable) {              this.setExtensionBadgeBackgroundColor('#555555'); @@ -53,16 +54,12 @@ class Backend {              this.setExtensionBadgeText('');          } -        if (options.anki.enable) { -            this.anki = new AnkiConnect(options.anki.server); -        } else { -            this.anki = new AnkiNull(); -        } +        this.anki = options.anki.enable ? new AnkiConnect(options.anki.server) : new AnkiNull();          const callback = () => this.checkLastError(chrome.runtime.lastError);          chrome.tabs.query({}, tabs => {              for (const tab of tabs) { -                chrome.tabs.sendMessage(tab.id, {action: 'optionsSet', params: options}, callback); +                chrome.tabs.sendMessage(tab.id, {action: 'optionsSet', params: {options}}, callback);              }          });      } @@ -85,10 +82,6 @@ class Backend {                  forward(apiOptionsGet(), callback);              }, -            optionsSet: ({options, callback}) => { -                forward(apiOptionsSet(options), callback); -            }, -              kanjiFind: ({text, callback}) => {                  forward(apiKanjiFind(text), callback);              }, @@ -148,7 +141,7 @@ class Backend {              chrome.browserAction.setBadgeBackgroundColor({color});          }      } -     +      setExtensionBadgeText(text) {          if (typeof chrome.browserAction.setBadgeText === 'function') {              chrome.browserAction.setBadgeText({text}); diff --git a/ext/bg/js/options.js b/ext/bg/js/options.js index df95aae9..69c662e6 100644 --- a/ext/bg/js/options.js +++ b/ext/bg/js/options.js @@ -17,6 +17,57 @@   */ +function optionsApplyUpdates(options, updates) { +    const targetVersion = updates.length; +    const currentVersion = options.version; +    if (typeof currentVersion === 'number' && Number.isFinite(currentVersion)) { +        for (let i = Math.max(0, Math.floor(currentVersion)); i < targetVersion; ++i) { +            const update = updates[i]; +            if (update !== null) { +                update(options); +            } +        } +    } + +    options.version = targetVersion; +    return options; +} + +const optionsVersionUpdates = [ +    null, +    null, +    null, +    null, +    (options) => { +        options.general.audioSource = options.general.audioPlayback ? 'jpod101' : 'disabled'; +    }, +    (options) => { +        options.general.showGuide = false; +    }, +    (options) => { +        options.scanning.modifier = options.scanning.requireShift ? 'shift' : 'none'; +    }, +    (options) => { +        const fieldTemplatesDefault = profileCreateDefaultFieldTemplates(); +        options.general.resultOutputMode = options.general.groupResults ? 'group' : 'split'; +        options.anki.fieldTemplates = ( +            (utilStringHashCode(options.anki.fieldTemplates) !== -805327496) ? +            `{{#if merge}}${fieldTemplatesDefault}{{else}}${options.anki.fieldTemplates}{{/if}}` : +            fieldTemplatesDefault +        ); +    }, +    (options) => { +        if (utilStringHashCode(options.anki.fieldTemplates) === 1285806040) { +            options.anki.fieldTemplates = profileCreateDefaultFieldTemplates(); +        } +    }, +    (options) => { +        if (utilStringHashCode(options.anki.fieldTemplates) === -250091611) { +            options.anki.fieldTemplates = profileCreateDefaultFieldTemplates(); +        } +    } +]; +  function optionsFieldTemplates() {      return `  {{#*inline "glossary-single"}} @@ -183,8 +234,8 @@ function optionsFieldTemplates() {  `.trim();  } -function optionsSetDefaults(options) { -    const defaults = { +function optionsCreateDefaults() { +    return {          general: {              enable: true,              audioSource: 'jpod101', @@ -238,6 +289,10 @@ function optionsSetDefaults(options) {              fieldTemplates: optionsFieldTemplates()          }      }; +} + +function optionsSetDefaults(options) { +    const defaults = optionsCreateDefaults();      const combine = (target, source) => {          for (const key in source) { @@ -258,70 +313,29 @@ function optionsSetDefaults(options) {  }  function optionsVersion(options) { -    const fixups = [ -        () => {}, -        () => {}, -        () => {}, -        () => {}, -        () => { -            if (options.general.audioPlayback) { -                options.general.audioSource = 'jpod101'; -            } else { -                options.general.audioSource = 'disabled'; -            } -        }, -        () => { -            options.general.showGuide = false; -        }, -        () => { -            if (options.scanning.requireShift) { -                options.scanning.modifier = 'shift'; -            } else { -                options.scanning.modifier = 'none'; -            } -        }, -        () => { -            if (options.general.groupResults) { -                options.general.resultOutputMode = 'group'; -            } else { -                options.general.resultOutputMode = 'split'; -            } -            if (utilStringHashCode(options.anki.fieldTemplates) !== -805327496) { -                options.anki.fieldTemplates = `{{#if merge}}${optionsFieldTemplates()}{{else}}${options.anki.fieldTemplates}{{/if}}`; -            } else { -                options.anki.fieldTemplates = optionsFieldTemplates(); -            } -        }, -        () => { -            if (utilStringHashCode(options.anki.fieldTemplates) === 1285806040) { -                options.anki.fieldTemplates = optionsFieldTemplates(); -            } -        }, -        () => { -            if (utilStringHashCode(options.anki.fieldTemplates) === -250091611) { -                options.anki.fieldTemplates = optionsFieldTemplates(); -            } -        } -    ]; -      optionsSetDefaults(options); -    if (!options.hasOwnProperty('version')) { -        options.version = fixups.length; -    } - -    while (options.version < fixups.length) { -        fixups[options.version++](); -    } - -    return options; +    return optionsApplyUpdates(options, optionsVersionUpdates);  }  function optionsLoad() {      return new Promise((resolve, reject) => { -        chrome.storage.local.get(null, store => resolve(store.options)); +        chrome.storage.local.get(['options'], store => { +            const error = chrome.runtime.lastError; +            if (error) { +                reject(error); +            } else { +                resolve(store.options); +            } +        });      }).then(optionsStr => { -        return optionsStr ? JSON.parse(optionsStr) : {}; -    }).catch(error => { +        if (typeof optionsStr === 'string') { +            const options = JSON.parse(optionsStr); +            if (typeof options === 'object' && options !== null && !Array.isArray(options)) { +                return options; +            } +        } +        return {}; +    }).catch(() => {          return {};      }).then(options => {          return optionsVersion(options); @@ -329,9 +343,9 @@ function optionsLoad() {  }  function optionsSave(options) { -    return new Promise((resolve, reject) => { +    return new Promise((resolve) => {          chrome.storage.local.set({options: JSON.stringify(options)}, resolve);      }).then(() => { -        apiOptionsSet(options); +        utilBackend().onOptionsUpdated(options);      });  } diff --git a/ext/bg/settings.html b/ext/bg/settings.html index 85b7ee5f..ddda8303 100644 --- a/ext/bg/settings.html +++ b/ext/bg/settings.html @@ -30,6 +30,10 @@                  padding-bottom: 1em;              } +            .label-light { +                font-weight: normal; +            } +              #custom-popup-css {                  width: 100%;                  min-height: 34px; @@ -49,6 +53,16 @@              [data-browser=firefox-mobile] [data-show-for-browser~=firefox-mobile] {                  display: initial;              } + +            @media screen and (max-width: 740px) { +                .col-xs-6 { +                    float: none; +                    width: 100%; +                } +                .col-xs-6+.col-xs-6 { +                    margin-top: 15px; +                } +            }          </style>      </head>      <body> @@ -107,6 +121,16 @@                      </select>                  </div> +                <div class="form-group options-advanced"> +                    <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"> +                </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"> +                </div> +                  <div class="form-group">                      <div class="row">                          <div class="col-xs-6"> @@ -130,36 +154,41 @@                  </div>                  <div class="form-group options-advanced"> -                    <label for="audio-playback-volume">Audio playback volume (percent)</label> -                    <input type="number" min="0" max="100" id="audio-playback-volume" 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"> -                </div> - -                <div class="form-group options-advanced"> -                    <label>Popup size (width × height, in pixels)</label>                      <div class="row"> -                        <div class="col-xs-6"><input type="number" min="1" id="popup-width" class="form-control"></div> -                        <div class="col-xs-6"><input type="number" min="1" id="popup-height" class="form-control"></div> +                        <div class="col-xs-6"> +                            <label for="popup-display-mode">Popup width <span class="label-light">(in pixels)</span></label> +                            <input type="number" min="1" id="popup-width" class="form-control"> +                        </div> +                        <div class="col-xs-6"> +                            <label for="popup-display-mode">Popup height <span class="label-light">(in pixels)</span></label> +                            <input type="number" min="1" id="popup-height" class="form-control"> +                        </div>                      </div>                  </div>                  <div class="form-group options-advanced"> -                    <label>Popup offset (horizontal, vertical; in pixels)</label>                      <div class="row"> -                        <div class="col-xs-6"><input type="number" min="0" id="popup-horizontal-offset" class="form-control"></div> -                        <div class="col-xs-6"><input type="number" min="0" id="popup-vertical-offset" class="form-control"></div> +                        <div class="col-xs-6"> +                            <label for="popup-display-mode">Horizontal popup offset <span class="label-light">(in pixels)</span></label> +                            <input type="number" min="0" id="popup-horizontal-offset" class="form-control"> +                        </div> +                        <div class="col-xs-6"> +                            <label for="popup-display-mode">Vertical popup offset <span class="label-light">(in pixels)</span></label> +                            <input type="number" min="0" id="popup-vertical-offset" class="form-control"> +                        </div>                      </div>                  </div>                  <div class="form-group options-advanced"> -                    <label>Popup offset for vertical text (horizontal, vertical; in pixels)</label>                      <div class="row"> -                        <div class="col-xs-6"><input type="number" min="0" id="popup-horizontal-offset2" class="form-control"></div> -                        <div class="col-xs-6"><input type="number" min="0" id="popup-vertical-offset2" class="form-control"></div> +                        <div class="col-xs-6"> +                            <label for="popup-display-mode">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"> +                        </div> +                        <div class="col-xs-6"> +                            <label for="popup-display-mode">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"> +                        </div>                      </div>                  </div> @@ -205,12 +234,12 @@                  </div>                  <div class="form-group options-advanced"> -                    <label for="scan-delay">Scan delay (in milliseconds)</label> +                    <label for="scan-delay">Scan delay <span class="label-light">(in milliseconds)</span></label>                      <input type="number" min="1" id="scan-delay" class="form-control">                  </div>                  <div class="form-group options-advanced"> -                    <label for="scan-length">Scan length (in characters)</label> +                    <label for="scan-length">Scan length <span class="label-light">(in characters)</span></label>                      <input type="number" min="1" id="scan-length" class="form-control">                  </div> @@ -326,12 +355,12 @@                  <div id="anki-general">                      <div class="form-group"> -                        <label for="card-tags">Card tags (comma or space separated)</label> +                        <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">                      </div>                      <div class="form-group options-advanced"> -                        <label for="sentence-detection-extent">Sentence detection extent (in characters)</label> +                        <label for="sentence-detection-extent">Sentence detection extent <span class="label-light">(in characters)</span></label>                          <input type="number" min="1" id="sentence-detection-extent" class="form-control">                      </div> @@ -349,7 +378,7 @@                      </div>                      <div class="form-group options-advanced"> -                        <label for="screenshot-quality">Screenshot quality (JPEG only)</label> +                        <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">                      </div> @@ -413,7 +442,7 @@                                  their Anki cards. If you encounter problems with your changes you can always <a href="#" id="field-templates-reset">reset to default</a>                                  template settings.                              </p> -                            <textarea class="form-control" rows="10" id="field-templates"></textarea> +                            <textarea autocomplete="off" spellcheck="false" wrap="soft" class="form-control" rows="10" id="field-templates"></textarea>                          </div>                      </div>                  </div> diff --git a/ext/fg/js/api.js b/ext/fg/js/api.js index 6bcb0dbb..aa3b2629 100644 --- a/ext/fg/js/api.js +++ b/ext/fg/js/api.js @@ -17,10 +17,6 @@   */ -function apiOptionsSet(options) { -    return utilInvoke('optionsSet', {options}); -} -  function apiOptionsGet() {      return utilInvoke('optionsGet');  } diff --git a/ext/fg/js/frontend.js b/ext/fg/js/frontend.js index 079a7ef2..52620933 100644 --- a/ext/fg/js/frontend.js +++ b/ext/fg/js/frontend.js @@ -261,7 +261,7 @@ class Frontend {      onBgMessage({action, params}, sender, callback) {          const handlers = { -            optionsSet: options => { +            optionsSet: ({options}) => {                  this.options = options;                  if (!this.options.enable) {                      this.searchClear(); |