diff options
Diffstat (limited to 'ext/bg/js')
| -rw-r--r-- | ext/bg/js/backend.js | 114 | ||||
| -rw-r--r-- | ext/bg/js/japanese.js | 40 | ||||
| -rw-r--r-- | ext/bg/js/options.js | 3 | ||||
| -rw-r--r-- | ext/bg/js/search.js | 2 | ||||
| -rw-r--r-- | ext/bg/js/settings/main.js | 2 | ||||
| -rw-r--r-- | ext/bg/js/translator.js | 17 | 
6 files changed, 119 insertions, 59 deletions
diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index 4a36be57..eb1f3e7b 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -75,33 +75,33 @@ class Backend {          this.messageToken = yomichan.generateId(16);          this._messageHandlers = new Map([ -            ['yomichanCoreReady', this._onApiYomichanCoreReady.bind(this)], -            ['optionsSchemaGet', this._onApiOptionsSchemaGet.bind(this)], -            ['optionsGet', this._onApiOptionsGet.bind(this)], -            ['optionsGetFull', this._onApiOptionsGetFull.bind(this)], -            ['optionsSet', this._onApiOptionsSet.bind(this)], -            ['optionsSave', this._onApiOptionsSave.bind(this)], -            ['kanjiFind', this._onApiKanjiFind.bind(this)], -            ['termsFind', this._onApiTermsFind.bind(this)], -            ['textParse', this._onApiTextParse.bind(this)], -            ['textParseMecab', this._onApiTextParseMecab.bind(this)], -            ['definitionAdd', this._onApiDefinitionAdd.bind(this)], -            ['definitionsAddable', this._onApiDefinitionsAddable.bind(this)], -            ['noteView', this._onApiNoteView.bind(this)], -            ['templateRender', this._onApiTemplateRender.bind(this)], -            ['commandExec', this._onApiCommandExec.bind(this)], -            ['audioGetUri', this._onApiAudioGetUri.bind(this)], -            ['screenshotGet', this._onApiScreenshotGet.bind(this)], -            ['forward', this._onApiForward.bind(this)], -            ['frameInformationGet', this._onApiFrameInformationGet.bind(this)], -            ['injectStylesheet', this._onApiInjectStylesheet.bind(this)], -            ['getEnvironmentInfo', this._onApiGetEnvironmentInfo.bind(this)], -            ['clipboardGet', this._onApiClipboardGet.bind(this)], -            ['getDisplayTemplatesHtml', this._onApiGetDisplayTemplatesHtml.bind(this)], -            ['getQueryParserTemplatesHtml', this._onApiGetQueryParserTemplatesHtml.bind(this)], -            ['getZoom', this._onApiGetZoom.bind(this)], -            ['getMessageToken', this._onApiGetMessageToken.bind(this)], -            ['getDefaultAnkiFieldTemplates', this._onApiGetDefaultAnkiFieldTemplates.bind(this)] +            ['yomichanCoreReady', {handler: this._onApiYomichanCoreReady.bind(this), async: false}], +            ['optionsSchemaGet', {handler: this._onApiOptionsSchemaGet.bind(this), async: false}], +            ['optionsGet', {handler: this._onApiOptionsGet.bind(this), async: false}], +            ['optionsGetFull', {handler: this._onApiOptionsGetFull.bind(this), async: false}], +            ['optionsSet', {handler: this._onApiOptionsSet.bind(this), async: true}], +            ['optionsSave', {handler: this._onApiOptionsSave.bind(this), async: true}], +            ['kanjiFind', {handler: this._onApiKanjiFind.bind(this), async: true}], +            ['termsFind', {handler: this._onApiTermsFind.bind(this), async: true}], +            ['textParse', {handler: this._onApiTextParse.bind(this), async: true}], +            ['textParseMecab', {handler: this._onApiTextParseMecab.bind(this), async: true}], +            ['definitionAdd', {handler: this._onApiDefinitionAdd.bind(this), async: true}], +            ['definitionsAddable', {handler: this._onApiDefinitionsAddable.bind(this), async: true}], +            ['noteView', {handler: this._onApiNoteView.bind(this), async: true}], +            ['templateRender', {handler: this._onApiTemplateRender.bind(this), async: true}], +            ['commandExec', {handler: this._onApiCommandExec.bind(this), async: false}], +            ['audioGetUri', {handler: this._onApiAudioGetUri.bind(this), async: true}], +            ['screenshotGet', {handler: this._onApiScreenshotGet.bind(this), async: true}], +            ['broadcastTab', {handler: this._onApiBroadcastTab.bind(this), async: false}], +            ['frameInformationGet', {handler: this._onApiFrameInformationGet.bind(this), async: true}], +            ['injectStylesheet', {handler: this._onApiInjectStylesheet.bind(this), async: true}], +            ['getEnvironmentInfo', {handler: this._onApiGetEnvironmentInfo.bind(this), async: true}], +            ['clipboardGet', {handler: this._onApiClipboardGet.bind(this), async: true}], +            ['getDisplayTemplatesHtml', {handler: this._onApiGetDisplayTemplatesHtml.bind(this), async: true}], +            ['getQueryParserTemplatesHtml', {handler: this._onApiGetQueryParserTemplatesHtml.bind(this), async: true}], +            ['getZoom', {handler: this._onApiGetZoom.bind(this), async: true}], +            ['getMessageToken', {handler: this._onApiGetMessageToken.bind(this), async: false}], +            ['getDefaultAnkiFieldTemplates', {handler: this._onApiGetDefaultAnkiFieldTemplates.bind(this), async: false}]          ]);          this._commandHandlers = new Map([ @@ -165,16 +165,23 @@ class Backend {      }      onMessage({action, params}, sender, callback) { -        const handler = this._messageHandlers.get(action); -        if (typeof handler !== 'function') { return false; } +        const messageHandler = this._messageHandlers.get(action); +        if (typeof messageHandler === 'undefined') { return false; } + +        const {handler, async} = messageHandler;          try { -            const promise = handler(params, sender); -            promise.then( -                (result) => callback({result}), -                (error) => callback({error: errorToJson(error)}) -            ); -            return true; +            const promiseOrResult = handler(params, sender); +            if (async) { +                promiseOrResult.then( +                    (result) => callback({result}), +                    (error) => callback({error: errorToJson(error)}) +                ); +                return true; +            } else { +                callback({result: promiseOrResult}); +                return false; +            }          } catch (error) {              callback({error: errorToJson(error)});              return false; @@ -311,27 +318,26 @@ class Backend {      _onApiYomichanCoreReady(_params, sender) {          // tab ID isn't set in background (e.g. browser_action) +        const callback = () => this.checkLastError(chrome.runtime.lastError); +        const data = {action: 'backendPrepared'};          if (typeof sender.tab === 'undefined') { -            const callback = () => this.checkLastError(chrome.runtime.lastError); -            chrome.runtime.sendMessage({action: 'backendPrepared'}, callback); -            return Promise.resolve(); +            chrome.runtime.sendMessage(data, callback); +            return false; +        } else { +            chrome.tabs.sendMessage(sender.tab.id, data, callback); +            return true;          } - -        const tabId = sender.tab.id; -        return new Promise((resolve) => { -            chrome.tabs.sendMessage(tabId, {action: 'backendPrepared'}, resolve); -        });      } -    async _onApiOptionsSchemaGet() { +    _onApiOptionsSchemaGet() {          return this.getOptionsSchema();      } -    async _onApiOptionsGet({optionsContext}) { +    _onApiOptionsGet({optionsContext}) {          return this.getOptions(optionsContext);      } -    async _onApiOptionsGetFull() { +    _onApiOptionsGetFull() {          return this.getFullOptions();      } @@ -538,7 +544,7 @@ class Backend {          return this._renderTemplate(template, data);      } -    async _onApiCommandExec({command, params}) { +    _onApiCommandExec({command, params}) {          return this._runCommand(command, params);      } @@ -558,15 +564,15 @@ class Backend {          });      } -    _onApiForward({action, params}, sender) { +    _onApiBroadcastTab({action, params}, sender) {          if (!(sender && sender.tab)) { -            return Promise.resolve(); +            return false;          }          const tabId = sender.tab.id; -        return new Promise((resolve) => { -            chrome.tabs.sendMessage(tabId, {action, params}, (response) => resolve(response)); -        }); +        const callback = () => this.checkLastError(chrome.runtime.lastError); +        chrome.tabs.sendMessage(tabId, {action, params}, callback); +        return true;      }      _onApiFrameInformationGet(params, sender) { @@ -689,11 +695,11 @@ class Backend {          });      } -    async _onApiGetMessageToken() { +    _onApiGetMessageToken() {          return this.messageToken;      } -    async _onApiGetDefaultAnkiFieldTemplates() { +    _onApiGetDefaultAnkiFieldTemplates() {          return this.defaultAnkiFieldTemplates;      } diff --git a/ext/bg/js/japanese.js b/ext/bg/js/japanese.js index 5c49cca7..5fef27a7 100644 --- a/ext/bg/js/japanese.js +++ b/ext/bg/js/japanese.js @@ -82,6 +82,9 @@      const ITERATION_MARK_CODE_POINT = 0x3005; +    const HIRAGANA_SMALL_TSU_CODE_POINT = 0x3063; +    const KATAKANA_SMALL_TSU_CODE_POINT = 0x30c3; +    const KANA_PROLONGED_SOUND_MARK_CODE_POINT = 0x30fc;      // Existing functions @@ -372,6 +375,40 @@      } +    // Miscellaneous + +    function collapseEmphaticSequences(text, fullCollapse, sourceMap=null) { +        let result = ''; +        let collapseCodePoint = -1; +        const hasSourceMap = (sourceMap !== null); +        for (const char of text) { +            const c = char.codePointAt(0); +            if ( +                c === HIRAGANA_SMALL_TSU_CODE_POINT || +                c === KATAKANA_SMALL_TSU_CODE_POINT || +                c === KANA_PROLONGED_SOUND_MARK_CODE_POINT +            ) { +                if (collapseCodePoint !== c) { +                    collapseCodePoint = c; +                    if (!fullCollapse) { +                        result += char; +                        continue; +                    } +                } +            } else { +                collapseCodePoint = -1; +                result += char; +                continue; +            } + +            if (hasSourceMap) { +                sourceMap.combine(Math.max(0, result.length - 1), 1); +            } +        } +        return result; +    } + +      // Exports      Object.assign(jp, { @@ -383,6 +420,7 @@          convertHalfWidthKanaToFullWidth,          convertAlphabeticToKana,          distributeFurigana, -        distributeFuriganaInflected +        distributeFuriganaInflected, +        collapseEmphaticSequences      });  })(); diff --git a/ext/bg/js/options.js b/ext/bg/js/options.js index 20df2a68..f3e5f60d 100644 --- a/ext/bg/js/options.js +++ b/ext/bg/js/options.js @@ -170,7 +170,8 @@ function profileOptionsCreateDefaults() {              convertNumericCharacters: 'false',              convertAlphabeticCharacters: 'false',              convertHiraganaToKatakana: 'false', -            convertKatakanaToHiragana: 'variant' +            convertKatakanaToHiragana: 'variant', +            collapseEmphaticSequences: 'false'          },          dictionaries: {}, diff --git a/ext/bg/js/search.js b/ext/bg/js/search.js index 2ba3e468..871c576b 100644 --- a/ext/bg/js/search.js +++ b/ext/bg/js/search.js @@ -208,7 +208,7 @@ class DisplaySearch extends Display {      onCopy() {          // ignore copy from search page -        this.clipboardMonitor.setPreviousText(document.getSelection().toString().trim()); +        this.clipboardMonitor.setPreviousText(window.getSelection().toString().trim());      }      onExternalSearchUpdate({text}) { diff --git a/ext/bg/js/settings/main.js b/ext/bg/js/settings/main.js index 8fd94562..308e92eb 100644 --- a/ext/bg/js/settings/main.js +++ b/ext/bg/js/settings/main.js @@ -118,6 +118,7 @@ async function formRead(options) {      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'); @@ -199,6 +200,7 @@ async function formWrite(options) {      $('#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); diff --git a/ext/bg/js/translator.js b/ext/bg/js/translator.js index e4441384..aaa1a0ec 100644 --- a/ext/bg/js/translator.js +++ b/ext/bg/js/translator.js @@ -347,17 +347,27 @@ class Translator {      getAllDeinflections(text, options) {          const translationOptions = options.translation; +        const collapseEmphaticOptions = [[false, false]]; +        switch (translationOptions.collapseEmphaticSequences) { +            case 'true': +                collapseEmphaticOptions.push([true, false]); +                break; +            case 'full': +                collapseEmphaticOptions.push([true, false], [true, true]); +                break; +        }          const textOptionVariantArray = [              Translator.getTextOptionEntryVariants(translationOptions.convertHalfWidthCharacters),              Translator.getTextOptionEntryVariants(translationOptions.convertNumericCharacters),              Translator.getTextOptionEntryVariants(translationOptions.convertAlphabeticCharacters),              Translator.getTextOptionEntryVariants(translationOptions.convertHiraganaToKatakana), -            Translator.getTextOptionEntryVariants(translationOptions.convertKatakanaToHiragana) +            Translator.getTextOptionEntryVariants(translationOptions.convertKatakanaToHiragana), +            collapseEmphaticOptions          ];          const deinflections = [];          const used = new Set(); -        for (const [halfWidth, numeric, alphabetic, katakana, hiragana] of Translator.getArrayVariants(textOptionVariantArray)) { +        for (const [halfWidth, numeric, alphabetic, katakana, hiragana, [collapseEmphatic, collapseEmphaticFull]] of Translator.getArrayVariants(textOptionVariantArray)) {              let text2 = text;              const sourceMap = new TextSourceMap(text2);              if (halfWidth) { @@ -375,6 +385,9 @@ class Translator {              if (hiragana) {                  text2 = jp.convertKatakanaToHiragana(text2);              } +            if (collapseEmphatic) { +                text2 = jp.collapseEmphaticSequences(text2, collapseEmphaticFull, sourceMap); +            }              for (let i = text2.length; i > 0; --i) {                  const text2Substring = text2.substring(0, i);  |