From ac603d54a3a53bec2881199756f3dd6a1aa44057 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sat, 11 Apr 2020 14:23:49 -0400 Subject: Add support for displaying images --- ext/bg/search.html | 1 + 1 file changed, 1 insertion(+) (limited to 'ext/bg/search.html') diff --git a/ext/bg/search.html b/ext/bg/search.html index eacc1893..fe88e264 100644 --- a/ext/bg/search.html +++ b/ext/bg/search.html @@ -85,6 +85,7 @@ + -- cgit v1.2.3 From 4d3d5d9ccb1c8ffbac0be0dc348790b34f68a564 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sun, 19 Apr 2020 14:28:07 -0400 Subject: Rename search-frontend.js to search-main.js Also move DisplaySearch creation into the main() function. --- ext/bg/js/search-frontend.js | 79 ----------------------------------------- ext/bg/js/search-main.js | 83 ++++++++++++++++++++++++++++++++++++++++++++ ext/bg/js/search.js | 8 ----- ext/bg/search.html | 3 +- 4 files changed, 85 insertions(+), 88 deletions(-) delete mode 100644 ext/bg/js/search-frontend.js create mode 100644 ext/bg/js/search-main.js (limited to 'ext/bg/search.html') diff --git a/ext/bg/js/search-frontend.js b/ext/bg/js/search-frontend.js deleted file mode 100644 index bda46a98..00000000 --- a/ext/bg/js/search-frontend.js +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2019-2020 Yomichan Authors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/* global - * apiOptionsGet - */ - -function injectSearchFrontend() { - const scriptSrcs = [ - '/mixed/js/text-scanner.js', - '/fg/js/frontend-api-receiver.js', - '/fg/js/frame-offset-forwarder.js', - '/fg/js/popup.js', - '/fg/js/popup-proxy-host.js', - '/fg/js/frontend.js', - '/fg/js/content-script-main.js' - ]; - for (const src of scriptSrcs) { - const node = document.querySelector(`script[src='${src}']`); - if (node !== null) { continue; } - - const script = document.createElement('script'); - script.async = false; - script.src = src; - document.body.appendChild(script); - } - - const styleSrcs = [ - '/fg/css/client.css' - ]; - for (const src of styleSrcs) { - const style = document.createElement('link'); - style.rel = 'stylesheet'; - style.type = 'text/css'; - style.href = src; - document.head.appendChild(style); - } -} - -async function main() { - await yomichan.prepare(); - - let optionsApplied = false; - - const applyOptions = async () => { - const optionsContext = { - depth: 0, - url: window.location.href - }; - const options = await apiOptionsGet(optionsContext); - if (!options.scanning.enableOnSearchPage || optionsApplied) { return; } - optionsApplied = true; - - window.frontendInitializationData = {depth: 1, proxy: false, isSearchPage: true}; - injectSearchFrontend(); - - yomichan.off('optionsUpdated', applyOptions); - }; - - yomichan.on('optionsUpdated', applyOptions); - - await applyOptions(); -} - -main(); diff --git a/ext/bg/js/search-main.js b/ext/bg/js/search-main.js new file mode 100644 index 00000000..91c39222 --- /dev/null +++ b/ext/bg/js/search-main.js @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2019-2020 Yomichan Authors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* global + * DisplaySearch + * apiOptionsGet + */ + +function injectSearchFrontend() { + const scriptSrcs = [ + '/mixed/js/text-scanner.js', + '/fg/js/frontend-api-receiver.js', + '/fg/js/frame-offset-forwarder.js', + '/fg/js/popup.js', + '/fg/js/popup-proxy-host.js', + '/fg/js/frontend.js', + '/fg/js/content-script-main.js' + ]; + for (const src of scriptSrcs) { + const node = document.querySelector(`script[src='${src}']`); + if (node !== null) { continue; } + + const script = document.createElement('script'); + script.async = false; + script.src = src; + document.body.appendChild(script); + } + + const styleSrcs = [ + '/fg/css/client.css' + ]; + for (const src of styleSrcs) { + const style = document.createElement('link'); + style.rel = 'stylesheet'; + style.type = 'text/css'; + style.href = src; + document.head.appendChild(style); + } +} + +async function main() { + await yomichan.prepare(); + + const displaySearch = new DisplaySearch(); + await displaySearch.prepare(); + + let optionsApplied = false; + + const applyOptions = async () => { + const optionsContext = { + depth: 0, + url: window.location.href + }; + const options = await apiOptionsGet(optionsContext); + if (!options.scanning.enableOnSearchPage || optionsApplied) { return; } + optionsApplied = true; + + window.frontendInitializationData = {depth: 1, proxy: false, isSearchPage: true}; + injectSearchFrontend(); + + yomichan.off('optionsUpdated', applyOptions); + }; + + yomichan.on('optionsUpdated', applyOptions); + + await applyOptions(); +} + +main(); diff --git a/ext/bg/js/search.js b/ext/bg/js/search.js index 871c576b..266cccc8 100644 --- a/ext/bg/js/search.js +++ b/ext/bg/js/search.js @@ -72,12 +72,6 @@ class DisplaySearch extends Display { ]); } - static create() { - const instance = new DisplaySearch(); - instance.prepare(); - return instance; - } - async prepare() { try { await super.prepare(); @@ -376,5 +370,3 @@ class DisplaySearch extends Display { } } } - -DisplaySearch.instance = DisplaySearch.create(); diff --git a/ext/bg/search.html b/ext/bg/search.html index fe88e264..9a824776 100644 --- a/ext/bg/search.html +++ b/ext/bg/search.html @@ -94,6 +94,7 @@ - + + -- cgit v1.2.3 From 4e0fc76fe1d4bf38cfbef370fcc55331108e0e0a Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sun, 26 Apr 2020 16:56:14 -0400 Subject: Add Yomichan icon SVG (#478) * Create Yomichan icon SVG and 32x32 PNG * Update icons * Add 32x32 icon definition to HTML pages --- ext/bg/background.html | 1 + ext/bg/context.html | 1 + ext/bg/guide.html | 3 ++- ext/bg/legal.html | 1 + ext/bg/search.html | 1 + ext/bg/settings-popup-preview.html | 1 + ext/bg/settings.html | 1 + ext/fg/float.html | 1 + ext/manifest.json | 21 ++++++++++++++-- ext/mixed/img/icon32.png | Bin 0 -> 288 bytes ext/mixed/img/yomichan-icon.svg | 5 ++++ resources/icons.svg | 49 +++++++++++++++++++++++++++++-------- 12 files changed, 72 insertions(+), 13 deletions(-) create mode 100644 ext/mixed/img/icon32.png create mode 100644 ext/mixed/img/yomichan-icon.svg (limited to 'ext/bg/search.html') diff --git a/ext/bg/background.html b/ext/bg/background.html index 3446d9ce..ee5a1f32 100644 --- a/ext/bg/background.html +++ b/ext/bg/background.html @@ -6,6 +6,7 @@ Background + diff --git a/ext/bg/context.html b/ext/bg/context.html index 394869b1..93012d70 100644 --- a/ext/bg/context.html +++ b/ext/bg/context.html @@ -5,6 +5,7 @@ + diff --git a/ext/bg/guide.html b/ext/bg/guide.html index ff9c71ee..cde520d1 100644 --- a/ext/bg/guide.html +++ b/ext/bg/guide.html @@ -6,6 +6,7 @@ Welcome to Yomichan! + @@ -25,7 +26,7 @@

    -
  1. Click on the icon in the browser toolbar to open the Yomichan actions dialog.
  2. +
  3. Click on the icon in the browser toolbar to open the Yomichan actions dialog.
  4. Click on the monkey wrench icon in the middle to open the options page.
  5. Import the dictionaries you wish to use for term and Kanji searches.
  6. Hold down Shift key or the middle mouse button as you move your mouse over text to display definitions.
  7. diff --git a/ext/bg/legal.html b/ext/bg/legal.html index 78acf79a..1ee9a28c 100644 --- a/ext/bg/legal.html +++ b/ext/bg/legal.html @@ -6,6 +6,7 @@ Yomichan Legal + diff --git a/ext/bg/search.html b/ext/bg/search.html index 9a824776..8ed6c838 100644 --- a/ext/bg/search.html +++ b/ext/bg/search.html @@ -6,6 +6,7 @@ Yomichan Search + diff --git a/ext/bg/settings-popup-preview.html b/ext/bg/settings-popup-preview.html index 66475b7c..a332fb22 100644 --- a/ext/bg/settings-popup-preview.html +++ b/ext/bg/settings-popup-preview.html @@ -6,6 +6,7 @@ Yomichan Popup Preview + diff --git a/ext/bg/settings.html b/ext/bg/settings.html index 96c1db82..f0236193 100644 --- a/ext/bg/settings.html +++ b/ext/bg/settings.html @@ -6,6 +6,7 @@ Yomichan Options + diff --git a/ext/fg/float.html b/ext/fg/float.html index 07c3c9e6..deb9e9d2 100644 --- a/ext/fg/float.html +++ b/ext/fg/float.html @@ -6,6 +6,7 @@ + diff --git a/ext/manifest.json b/ext/manifest.json index 4f35b03c..3cb634f0 100644 --- a/ext/manifest.json +++ b/ext/manifest.json @@ -4,9 +4,26 @@ "version": "20.4.18.0", "description": "Japanese dictionary with Anki integration", - "icons": {"16": "mixed/img/icon16.png", "48": "mixed/img/icon48.png", "128": "mixed/img/icon128.png"}, + "icons": { + "16": "mixed/img/icon16.png", + "19": "mixed/img/icon19.png", + "32": "mixed/img/icon32.png", + "38": "mixed/img/icon38.png", + "48": "mixed/img/icon48.png", + "64": "mixed/img/icon48.png", + "128": "mixed/img/icon128.png" + }, "browser_action": { - "default_icon": {"19": "mixed/img/icon19.png", "38": "mixed/img/icon38.png"}, + "default_icon": { + "16": "mixed/img/icon16.png", + "19": "mixed/img/icon19.png", + "32": "mixed/img/icon32.png", + "38": "mixed/img/icon38.png", + "48": "mixed/img/icon48.png", + "64": "mixed/img/icon48.png", + "128": "mixed/img/icon128.png" + }, + "default_title": "Yomichan", "default_popup": "bg/context.html" }, diff --git a/ext/mixed/img/icon32.png b/ext/mixed/img/icon32.png new file mode 100644 index 00000000..05f2f064 Binary files /dev/null and b/ext/mixed/img/icon32.png differ diff --git a/ext/mixed/img/yomichan-icon.svg b/ext/mixed/img/yomichan-icon.svg new file mode 100644 index 00000000..f15ab0aa --- /dev/null +++ b/ext/mixed/img/yomichan-icon.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/resources/icons.svg b/resources/icons.svg index 4bc46c02..f096947b 100644 --- a/resources/icons.svg +++ b/resources/icons.svg @@ -15,10 +15,11 @@ viewBox="0 0 16 16" version="1.1" id="svg8" - inkscape:version="0.92.3 (2405546, 2018-03-11)" + inkscape:version="0.92.4 (5da689c313, 2019-01-14)" sodipodi:docname="icons.svg" - inkscape:export-xdpi="96" - inkscape:export-ydpi="96"> + inkscape:export-xdpi="192" + inkscape:export-ydpi="192" + inkscape:export-filename="../ext/mixed/img/icon32.png"> image/svg+xml - + @@ -520,7 +521,7 @@ style="image-rendering:optimizeSpeed" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0 U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJvSURBVDjLpZPrS5NhGIf9W7YvBYOkhlko qCklWChv2WyKik7blnNris72bi6dus0DLZ0TDxW1odtopDs4D8MDZuLU0kXq61CijSIIasOvv94V TUfLiB74fXngup7nvrnvJABJ/5PfLnTTdcwOj4RsdYmo5glBWP6iOtzwvIKSWstI0Wgx80SBblpK tE9KQs/We7EaWoT/8wbWP61gMmCH0lMDvokT4j25TiQU/ITFkek9Ow6+7WH2gwsmahCPdwyw75uw 9HEO2gUZSkfyI9zBPCJOoJ2SMmg46N61YO/rNoa39Xi41oFuXysMfh36/Fp0b7bAfWAH6RGi0Hgl WNCbzYgJaFjRv6zGuy+b9It96N3SQvNKiV9HvSaDfFEIxXItnPs23BzJQd6DDEVM0OKsoVwBG/1V MzpXVWhbkUM2K4oJBDYuGmbKIJ0qxsAbHfRLzbjcnUbFBIpx/qH3vQv9b3U03IQ/HfFkERTzfFj8 w8jSpR7GBE123uFEYAzaDRIqX/2JAtJbDat/COkd7CNBva2cMvq0MGxp0PRSCPF8BXjWG3FgNHc9 XPT71Ojy3sMFdfJRCeKxEsVtKwFHwALZfCUk3tIfNR8XiJwc1LmL4dg141JPKtj3WUdNFJqLGFVP C4OkR4BxajTWsChY64wmCnMxsWPCHcutKBxMVp5mxA1S+aMComToaqTRUQknLTH62kHOVEE+VQnj ahscNCy0cMBWsSI0TCQcZc5ALkEYckL5A5noWSBhfm2AecMAjbcRWV0pUTh0HE64TNf0mczcnnQy u/MilaFJCae1nw2fbz1DnVOxyGTlKeZft/Ff8x1BRssfACjTwQAAAABJRU5ErkJggg== " id="image4539" - x="4.7683716e-007" + x="4.7683716e-07" y="292.76669" /> + + + + + + + + -- cgit v1.2.3 From 887d769786f2909dbd74e3465cef3551b780a49b Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sun, 26 Apr 2020 16:56:34 -0400 Subject: Use dynamicLoader for main (#481) * Update style of search-main and float-main to have better parity * Use dynamicLoader to inject scripts and CSS --- ext/bg/js/search-main.js | 41 +++++++++++------------------------------ ext/bg/search.html | 1 + ext/fg/float.html | 1 + ext/fg/js/float-main.js | 30 ++++++++---------------------- 4 files changed, 21 insertions(+), 52 deletions(-) (limited to 'ext/bg/search.html') diff --git a/ext/bg/js/search-main.js b/ext/bg/js/search-main.js index 5e4d7a20..1075d46e 100644 --- a/ext/bg/js/search-main.js +++ b/ext/bg/js/search-main.js @@ -19,10 +19,14 @@ * DisplaySearch * apiForwardLogsToBackend * apiOptionsGet + * dynamicLoader */ -function injectSearchFrontend() { - const scriptSrcs = [ +async function injectSearchFrontend() { + dynamicLoader.loadStyles([ + '/fg/css/client.css' + ]); + await dynamicLoader.loadScripts([ '/mixed/js/text-scanner.js', '/fg/js/frontend-api-receiver.js', '/fg/js/frame-offset-forwarder.js', @@ -30,27 +34,7 @@ function injectSearchFrontend() { '/fg/js/popup-proxy-host.js', '/fg/js/frontend.js', '/fg/js/content-script-main.js' - ]; - for (const src of scriptSrcs) { - const node = document.querySelector(`script[src='${src}']`); - if (node !== null) { continue; } - - const script = document.createElement('script'); - script.async = false; - script.src = src; - document.body.appendChild(script); - } - - const styleSrcs = [ - '/fg/css/client.css' - ]; - for (const src of styleSrcs) { - const style = document.createElement('link'); - style.rel = 'stylesheet'; - style.type = 'text/css'; - style.href = src; - document.head.appendChild(style); - } + ]); } (async () => { @@ -63,18 +47,15 @@ function injectSearchFrontend() { let optionsApplied = false; const applyOptions = async () => { - const optionsContext = { - depth: 0, - url: window.location.href - }; + const optionsContext = {depth: 0, url: window.location.href}; const options = await apiOptionsGet(optionsContext); if (!options.scanning.enableOnSearchPage || optionsApplied) { return; } + optionsApplied = true; + yomichan.off('optionsUpdated', applyOptions); window.frontendInitializationData = {depth: 1, proxy: false, isSearchPage: true}; - injectSearchFrontend(); - - yomichan.off('optionsUpdated', applyOptions); + await injectSearchFrontend(); }; yomichan.on('optionsUpdated', applyOptions); diff --git a/ext/bg/search.html b/ext/bg/search.html index 8ed6c838..52915b76 100644 --- a/ext/bg/search.html +++ b/ext/bg/search.html @@ -86,6 +86,7 @@ + diff --git a/ext/fg/float.html b/ext/fg/float.html index deb9e9d2..6f37de52 100644 --- a/ext/fg/float.html +++ b/ext/fg/float.html @@ -52,6 +52,7 @@ + diff --git a/ext/fg/js/float-main.js b/ext/fg/js/float-main.js index 5ef4b07c..e7e50a54 100644 --- a/ext/fg/js/float-main.js +++ b/ext/fg/js/float-main.js @@ -19,23 +19,18 @@ * DisplayFloat * apiForwardLogsToBackend * apiOptionsGet + * dynamicLoader */ -function injectPopupNested() { - const scriptSrcs = [ +async function injectPopupNested() { + await dynamicLoader.loadScripts([ '/mixed/js/text-scanner.js', '/fg/js/frontend-api-sender.js', '/fg/js/popup.js', '/fg/js/popup-proxy.js', '/fg/js/frontend.js', '/fg/js/content-script-main.js' - ]; - for (const src of scriptSrcs) { - const script = document.createElement('script'); - script.async = false; - script.src = src; - document.body.appendChild(script); - } + ]); } async function popupNestedInitialize(id, depth, parentFrameId, url) { @@ -44,23 +39,14 @@ async function popupNestedInitialize(id, depth, parentFrameId, url) { const applyOptions = async () => { const optionsContext = {depth, url}; const options = await apiOptionsGet(optionsContext); - const popupNestingMaxDepth = options.scanning.popupNestingMaxDepth; - - const maxPopupDepthExceeded = !( - typeof popupNestingMaxDepth === 'number' && - typeof depth === 'number' && - depth < popupNestingMaxDepth - ); - if (maxPopupDepthExceeded || optionsApplied) { - return; - } + const maxPopupDepthExceeded = !(typeof depth === 'number' && depth < options.scanning.popupNestingMaxDepth); + if (maxPopupDepthExceeded || optionsApplied) { return; } optionsApplied = true; + yomichan.off('optionsUpdated', applyOptions); window.frontendInitializationData = {id, depth, parentFrameId, url, proxy: true}; - injectPopupNested(); - - yomichan.off('optionsUpdated', applyOptions); + await injectPopupNested(); }; yomichan.on('optionsUpdated', applyOptions); -- cgit v1.2.3 From f361139d744e58a6c33841cee227d13d1970bb98 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Wed, 6 May 2020 19:37:36 -0400 Subject: Japanese util refactor (#510) * Convert mixed japanese.js to utility class * Copy functions from bg/js/japanese.js into mixed/js/japanese.js * Remove bg/js/japanese.js * Make wanakana dependency optional * Update tests --- ext/bg/background.html | 1 - ext/bg/js/japanese.js | 426 --------------------------------------- ext/bg/search.html | 1 - ext/bg/settings.html | 1 - ext/mixed/js/japanese.js | 507 ++++++++++++++++++++++++++++++++++++++++++----- test/test-japanese.js | 3 +- 6 files changed, 453 insertions(+), 486 deletions(-) delete mode 100644 ext/bg/js/japanese.js (limited to 'ext/bg/search.html') diff --git a/ext/bg/background.html b/ext/bg/background.html index 9c740adf..7cb76ec3 100644 --- a/ext/bg/background.html +++ b/ext/bg/background.html @@ -36,7 +36,6 @@ - diff --git a/ext/bg/js/japanese.js b/ext/bg/js/japanese.js deleted file mode 100644 index ac81acb5..00000000 --- a/ext/bg/js/japanese.js +++ /dev/null @@ -1,426 +0,0 @@ -/* - * Copyright (C) 2016-2020 Yomichan Authors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/* global - * jp - * wanakana - */ - -(() => { - const HALFWIDTH_KATAKANA_MAPPING = new Map([ - ['ヲ', 'ヲヺ-'], - ['ァ', 'ァ--'], - ['ィ', 'ィ--'], - ['ゥ', 'ゥ--'], - ['ェ', 'ェ--'], - ['ォ', 'ォ--'], - ['ャ', 'ャ--'], - ['ュ', 'ュ--'], - ['ョ', 'ョ--'], - ['ッ', 'ッ--'], - ['ー', 'ー--'], - ['ア', 'ア--'], - ['イ', 'イ--'], - ['ウ', 'ウヴ-'], - ['エ', 'エ--'], - ['オ', 'オ--'], - ['カ', 'カガ-'], - ['キ', 'キギ-'], - ['ク', 'クグ-'], - ['ケ', 'ケゲ-'], - ['コ', 'コゴ-'], - ['サ', 'サザ-'], - ['シ', 'シジ-'], - ['ス', 'スズ-'], - ['セ', 'セゼ-'], - ['ソ', 'ソゾ-'], - ['タ', 'タダ-'], - ['チ', 'チヂ-'], - ['ツ', 'ツヅ-'], - ['テ', 'テデ-'], - ['ト', 'トド-'], - ['ナ', 'ナ--'], - ['ニ', 'ニ--'], - ['ヌ', 'ヌ--'], - ['ネ', 'ネ--'], - ['ノ', 'ノ--'], - ['ハ', 'ハバパ'], - ['ヒ', 'ヒビピ'], - ['フ', 'フブプ'], - ['ヘ', 'ヘベペ'], - ['ホ', 'ホボポ'], - ['マ', 'マ--'], - ['ミ', 'ミ--'], - ['ム', 'ム--'], - ['メ', 'メ--'], - ['モ', 'モ--'], - ['ヤ', 'ヤ--'], - ['ユ', 'ユ--'], - ['ヨ', 'ヨ--'], - ['ラ', 'ラ--'], - ['リ', 'リ--'], - ['ル', 'ル--'], - ['レ', 'レ--'], - ['ロ', 'ロ--'], - ['ワ', 'ワ--'], - ['ン', 'ン--'] - ]); - - 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 - - const isCodePointKanji = jp.isCodePointKanji; - const isStringEntirelyKana = jp.isStringEntirelyKana; - - - // Conversion functions - - function convertKatakanaToHiragana(text) { - let result = ''; - for (const c of text) { - if (wanakana.isKatakana(c)) { - result += wanakana.toHiragana(c); - } else { - result += c; - } - } - - return result; - } - - function convertHiraganaToKatakana(text) { - let result = ''; - for (const c of text) { - if (wanakana.isHiragana(c)) { - result += wanakana.toKatakana(c); - } else { - result += c; - } - } - - return result; - } - - function convertToRomaji(text) { - return wanakana.toRomaji(text); - } - - function convertReading(expression, reading, readingMode) { - switch (readingMode) { - case 'hiragana': - return convertKatakanaToHiragana(reading); - case 'katakana': - return convertHiraganaToKatakana(reading); - case 'romaji': - if (reading) { - return convertToRomaji(reading); - } else { - if (isStringEntirelyKana(expression)) { - return convertToRomaji(expression); - } - } - return reading; - case 'none': - return ''; - default: - return reading; - } - } - - function convertNumericToFullWidth(text) { - let result = ''; - for (const char of text) { - let c = char.codePointAt(0); - if (c >= 0x30 && c <= 0x39) { // ['0', '9'] - c += 0xff10 - 0x30; // 0xff10 = '0' full width - result += String.fromCodePoint(c); - } else { - result += char; - } - } - return result; - } - - function convertHalfWidthKanaToFullWidth(text, sourceMap=null) { - let result = ''; - - // This function is safe to use charCodeAt instead of codePointAt, since all - // the relevant characters are represented with a single UTF-16 character code. - for (let i = 0, ii = text.length; i < ii; ++i) { - const c = text[i]; - const mapping = HALFWIDTH_KATAKANA_MAPPING.get(c); - if (typeof mapping !== 'string') { - result += c; - continue; - } - - let index = 0; - switch (text.charCodeAt(i + 1)) { - case 0xff9e: // dakuten - index = 1; - break; - case 0xff9f: // handakuten - index = 2; - break; - } - - let c2 = mapping[index]; - if (index > 0) { - if (c2 === '-') { // invalid - index = 0; - c2 = mapping[0]; - } else { - ++i; - } - } - - if (sourceMap !== null && index > 0) { - sourceMap.combine(result.length, 1); - } - result += c2; - } - - return result; - } - - function convertAlphabeticToKana(text, sourceMap=null) { - let part = ''; - let result = ''; - - for (const char of text) { - // Note: 0x61 is the character code for 'a' - let c = char.codePointAt(0); - if (c >= 0x41 && c <= 0x5a) { // ['A', 'Z'] - c += (0x61 - 0x41); - } else if (c >= 0x61 && c <= 0x7a) { // ['a', 'z'] - // NOP; c += (0x61 - 0x61); - } else if (c >= 0xff21 && c <= 0xff3a) { // ['A', 'Z'] fullwidth - c += (0x61 - 0xff21); - } else if (c >= 0xff41 && c <= 0xff5a) { // ['a', 'z'] fullwidth - c += (0x61 - 0xff41); - } else if (c === 0x2d || c === 0xff0d) { // '-' or fullwidth dash - c = 0x2d; // '-' - } else { - if (part.length > 0) { - result += convertAlphabeticPartToKana(part, sourceMap, result.length); - part = ''; - } - result += char; - continue; - } - part += String.fromCodePoint(c); - } - - if (part.length > 0) { - result += convertAlphabeticPartToKana(part, sourceMap, result.length); - } - return result; - } - - function convertAlphabeticPartToKana(text, sourceMap, sourceMapStart) { - const result = wanakana.toHiragana(text); - - // Generate source mapping - if (sourceMap !== null) { - let i = 0; - let resultPos = 0; - const ii = text.length; - while (i < ii) { - // Find smallest matching substring - let iNext = i + 1; - let resultPosNext = result.length; - while (iNext < ii) { - const t = wanakana.toHiragana(text.substring(0, iNext)); - if (t === result.substring(0, t.length)) { - resultPosNext = t.length; - break; - } - ++iNext; - } - - // Merge characters - const removals = iNext - i - 1; - if (removals > 0) { - sourceMap.combine(sourceMapStart, removals); - } - ++sourceMapStart; - - // Empty elements - const additions = resultPosNext - resultPos - 1; - for (let j = 0; j < additions; ++j) { - sourceMap.insert(sourceMapStart, 0); - ++sourceMapStart; - } - - i = iNext; - resultPos = resultPosNext; - } - } - - return result; - } - - - // Furigana distribution - - function distributeFurigana(expression, reading) { - const fallback = [{furigana: reading, text: expression}]; - if (!reading) { - return fallback; - } - - let isAmbiguous = false; - const segmentize = (reading2, groups) => { - if (groups.length === 0 || isAmbiguous) { - return []; - } - - const group = groups[0]; - if (group.mode === 'kana') { - if (convertKatakanaToHiragana(reading2).startsWith(convertKatakanaToHiragana(group.text))) { - const readingLeft = reading2.substring(group.text.length); - const segs = segmentize(readingLeft, groups.splice(1)); - if (segs) { - return [{text: group.text, furigana: ''}].concat(segs); - } - } - } else { - let foundSegments = null; - for (let i = reading2.length; i >= group.text.length; --i) { - const readingUsed = reading2.substring(0, i); - const readingLeft = reading2.substring(i); - const segs = segmentize(readingLeft, groups.slice(1)); - if (segs) { - if (foundSegments !== null) { - // more than one way to segmentize the tail, mark as ambiguous - isAmbiguous = true; - return null; - } - foundSegments = [{text: group.text, furigana: readingUsed}].concat(segs); - } - // there is only one way to segmentize the last non-kana group - if (groups.length === 1) { - break; - } - } - return foundSegments; - } - }; - - const groups = []; - let modePrev = null; - for (const c of expression) { - const codePoint = c.codePointAt(0); - const modeCurr = isCodePointKanji(codePoint) || codePoint === ITERATION_MARK_CODE_POINT ? 'kanji' : 'kana'; - if (modeCurr === modePrev) { - groups[groups.length - 1].text += c; - } else { - groups.push({mode: modeCurr, text: c}); - modePrev = modeCurr; - } - } - - const segments = segmentize(reading, groups); - if (segments && !isAmbiguous) { - return segments; - } - return fallback; - } - - function distributeFuriganaInflected(expression, reading, source) { - const output = []; - - let stemLength = 0; - const shortest = Math.min(source.length, expression.length); - const sourceHiragana = convertKatakanaToHiragana(source); - const expressionHiragana = convertKatakanaToHiragana(expression); - while (stemLength < shortest && sourceHiragana[stemLength] === expressionHiragana[stemLength]) { - ++stemLength; - } - const offset = source.length - stemLength; - - const stemExpression = source.substring(0, source.length - offset); - const stemReading = reading.substring( - 0, - offset === 0 ? reading.length : reading.length - expression.length + stemLength - ); - for (const segment of distributeFurigana(stemExpression, stemReading)) { - output.push(segment); - } - - if (stemLength !== source.length) { - output.push({text: source.substring(stemLength), furigana: ''}); - } - - return output; - } - - - // 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, { - convertKatakanaToHiragana, - convertHiraganaToKatakana, - convertToRomaji, - convertReading, - convertNumericToFullWidth, - convertHalfWidthKanaToFullWidth, - convertAlphabeticToKana, - distributeFurigana, - distributeFuriganaInflected, - collapseEmphaticSequences - }); -})(); diff --git a/ext/bg/search.html b/ext/bg/search.html index 52915b76..a30b1d60 100644 --- a/ext/bg/search.html +++ b/ext/bg/search.html @@ -79,7 +79,6 @@ - diff --git a/ext/bg/settings.html b/ext/bg/settings.html index b8477e46..a0981687 100644 --- a/ext/bg/settings.html +++ b/ext/bg/settings.html @@ -1139,7 +1139,6 @@ - diff --git a/ext/mixed/js/japanese.js b/ext/mixed/js/japanese.js index ced486dd..801dec84 100644 --- a/ext/mixed/js/japanese.js +++ b/ext/mixed/js/japanese.js @@ -16,6 +16,11 @@ */ const jp = (() => { + 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; + const HIRAGANA_RANGE = [0x3040, 0x309f]; const KATAKANA_RANGE = [0x30a0, 0x30ff]; const KANA_RANGES = [HIRAGANA_RANGE, KATAKANA_RANGE]; @@ -65,20 +70,65 @@ const jp = (() => { const SMALL_KANA_SET = new Set(Array.from('ぁぃぅぇぉゃゅょゎァィゥェォャュョヮ')); + const HALFWIDTH_KATAKANA_MAPPING = new Map([ + ['ヲ', 'ヲヺ-'], + ['ァ', 'ァ--'], + ['ィ', 'ィ--'], + ['ゥ', 'ゥ--'], + ['ェ', 'ェ--'], + ['ォ', 'ォ--'], + ['ャ', 'ャ--'], + ['ュ', 'ュ--'], + ['ョ', 'ョ--'], + ['ッ', 'ッ--'], + ['ー', 'ー--'], + ['ア', 'ア--'], + ['イ', 'イ--'], + ['ウ', 'ウヴ-'], + ['エ', 'エ--'], + ['オ', 'オ--'], + ['カ', 'カガ-'], + ['キ', 'キギ-'], + ['ク', 'クグ-'], + ['ケ', 'ケゲ-'], + ['コ', 'コゴ-'], + ['サ', 'サザ-'], + ['シ', 'シジ-'], + ['ス', 'スズ-'], + ['セ', 'セゼ-'], + ['ソ', 'ソゾ-'], + ['タ', 'タダ-'], + ['チ', 'チヂ-'], + ['ツ', 'ツヅ-'], + ['テ', 'テデ-'], + ['ト', 'トド-'], + ['ナ', 'ナ--'], + ['ニ', 'ニ--'], + ['ヌ', 'ヌ--'], + ['ネ', 'ネ--'], + ['ノ', 'ノ--'], + ['ハ', 'ハバパ'], + ['ヒ', 'ヒビピ'], + ['フ', 'フブプ'], + ['ヘ', 'ヘベペ'], + ['ホ', 'ホボポ'], + ['マ', 'マ--'], + ['ミ', 'ミ--'], + ['ム', 'ム--'], + ['メ', 'メ--'], + ['モ', 'モ--'], + ['ヤ', 'ヤ--'], + ['ユ', 'ユ--'], + ['ヨ', 'ヨ--'], + ['ラ', 'ラ--'], + ['リ', 'リ--'], + ['ル', 'ル--'], + ['レ', 'レ--'], + ['ロ', 'ロ--'], + ['ワ', 'ワ--'], + ['ン', 'ン--'] + ]); - // Character code testing functions - - function isCodePointKanji(codePoint) { - return isCodePointInRanges(codePoint, CJK_UNIFIED_IDEOGRAPHS_RANGES); - } - - function isCodePointKana(codePoint) { - return isCodePointInRanges(codePoint, KANA_RANGES); - } - - function isCodePointJapanese(codePoint) { - return isCodePointInRanges(codePoint, JAPANESE_RANGES); - } function isCodePointInRanges(codePoint, ranges) { for (const [min, max] of ranges) { @@ -89,63 +139,410 @@ const jp = (() => { return false; } + function getWanakana() { + try { + if (typeof wanakana !== 'undefined') { + // eslint-disable-next-line no-undef + return wanakana; + } + } catch (e) { + // NOP + } + return null; + } + - // String testing functions + class JapaneseUtil { + constructor(wanakana=null) { + this._wanakana = wanakana; + } - function isStringEntirelyKana(str) { - if (str.length === 0) { return false; } - for (const c of str) { - if (!isCodePointKana(c.codePointAt(0))) { - return false; + // Character code testing functions + + isCodePointKanji(codePoint) { + return isCodePointInRanges(codePoint, CJK_UNIFIED_IDEOGRAPHS_RANGES); + } + + isCodePointKana(codePoint) { + return isCodePointInRanges(codePoint, KANA_RANGES); + } + + isCodePointJapanese(codePoint) { + return isCodePointInRanges(codePoint, JAPANESE_RANGES); + } + + // String testing functions + + isStringEntirelyKana(str) { + if (str.length === 0) { return false; } + for (const c of str) { + if (!isCodePointInRanges(c.codePointAt(0), KANA_RANGES)) { + return false; + } } + return true; } - return true; - } - function isStringPartiallyJapanese(str) { - if (str.length === 0) { return false; } - for (const c of str) { - if (isCodePointJapanese(c.codePointAt(0))) { - return true; + isStringPartiallyJapanese(str) { + if (str.length === 0) { return false; } + for (const c of str) { + if (isCodePointInRanges(c.codePointAt(0), JAPANESE_RANGES)) { + return true; + } } + return false; } - return false; - } + // Mora functions - // Mora functions + isMoraPitchHigh(moraIndex, pitchAccentPosition) { + switch (pitchAccentPosition) { + case 0: return (moraIndex > 0); + case 1: return (moraIndex < 1); + default: return (moraIndex > 0 && moraIndex < pitchAccentPosition); + } + } - function isMoraPitchHigh(moraIndex, pitchAccentPosition) { - switch (pitchAccentPosition) { - case 0: return (moraIndex > 0); - case 1: return (moraIndex < 1); - default: return (moraIndex > 0 && moraIndex < pitchAccentPosition); + getKanaMorae(text) { + const morae = []; + let i; + for (const c of text) { + if (SMALL_KANA_SET.has(c) && (i = morae.length) > 0) { + morae[i - 1] += c; + } else { + morae.push(c); + } + } + return morae; } - } - function getKanaMorae(text) { - const morae = []; - let i; - for (const c of text) { - if (SMALL_KANA_SET.has(c) && (i = morae.length) > 0) { - morae[i - 1] += c; - } else { - morae.push(c); + // Conversion functions + + convertKatakanaToHiragana(text) { + const wanakana = this._getWanakana(); + let result = ''; + for (const c of text) { + if (wanakana.isKatakana(c)) { + result += wanakana.toHiragana(c); + } else { + result += c; + } } + + return result; } - return morae; - } + convertHiraganaToKatakana(text) { + const wanakana = this._getWanakana(); + let result = ''; + for (const c of text) { + if (wanakana.isHiragana(c)) { + result += wanakana.toKatakana(c); + } else { + result += c; + } + } + + return result; + } + + convertToRomaji(text) { + const wanakana = this._getWanakana(); + return wanakana.toRomaji(text); + } + + convertReading(expression, reading, readingMode) { + switch (readingMode) { + case 'hiragana': + return this.convertKatakanaToHiragana(reading); + case 'katakana': + return this.convertHiraganaToKatakana(reading); + case 'romaji': + if (reading) { + return this.convertToRomaji(reading); + } else { + if (this.isStringEntirelyKana(expression)) { + return this.convertToRomaji(expression); + } + } + return reading; + case 'none': + return ''; + default: + return reading; + } + } + + convertNumericToFullWidth(text) { + let result = ''; + for (const char of text) { + let c = char.codePointAt(0); + if (c >= 0x30 && c <= 0x39) { // ['0', '9'] + c += 0xff10 - 0x30; // 0xff10 = '0' full width + result += String.fromCodePoint(c); + } else { + result += char; + } + } + return result; + } + + convertHalfWidthKanaToFullWidth(text, sourceMap=null) { + let result = ''; + + // This function is safe to use charCodeAt instead of codePointAt, since all + // the relevant characters are represented with a single UTF-16 character code. + for (let i = 0, ii = text.length; i < ii; ++i) { + const c = text[i]; + const mapping = HALFWIDTH_KATAKANA_MAPPING.get(c); + if (typeof mapping !== 'string') { + result += c; + continue; + } + + let index = 0; + switch (text.charCodeAt(i + 1)) { + case 0xff9e: // dakuten + index = 1; + break; + case 0xff9f: // handakuten + index = 2; + break; + } + + let c2 = mapping[index]; + if (index > 0) { + if (c2 === '-') { // invalid + index = 0; + c2 = mapping[0]; + } else { + ++i; + } + } + + if (sourceMap !== null && index > 0) { + sourceMap.combine(result.length, 1); + } + result += c2; + } + + return result; + } + + convertAlphabeticToKana(text, sourceMap=null) { + let part = ''; + let result = ''; + + for (const char of text) { + // Note: 0x61 is the character code for 'a' + let c = char.codePointAt(0); + if (c >= 0x41 && c <= 0x5a) { // ['A', 'Z'] + c += (0x61 - 0x41); + } else if (c >= 0x61 && c <= 0x7a) { // ['a', 'z'] + // NOP; c += (0x61 - 0x61); + } else if (c >= 0xff21 && c <= 0xff3a) { // ['A', 'Z'] fullwidth + c += (0x61 - 0xff21); + } else if (c >= 0xff41 && c <= 0xff5a) { // ['a', 'z'] fullwidth + c += (0x61 - 0xff41); + } else if (c === 0x2d || c === 0xff0d) { // '-' or fullwidth dash + c = 0x2d; // '-' + } else { + if (part.length > 0) { + result += this._convertAlphabeticPartToKana(part, sourceMap, result.length); + part = ''; + } + result += char; + continue; + } + part += String.fromCodePoint(c); + } + + if (part.length > 0) { + result += this._convertAlphabeticPartToKana(part, sourceMap, result.length); + } + return result; + } + + // Furigana distribution + + distributeFurigana(expression, reading) { + const fallback = [{furigana: reading, text: expression}]; + if (!reading) { + return fallback; + } + + let isAmbiguous = false; + const segmentize = (reading2, groups) => { + if (groups.length === 0 || isAmbiguous) { + return []; + } + + const group = groups[0]; + if (group.mode === 'kana') { + if (this.convertKatakanaToHiragana(reading2).startsWith(this.convertKatakanaToHiragana(group.text))) { + const readingLeft = reading2.substring(group.text.length); + const segs = segmentize(readingLeft, groups.splice(1)); + if (segs) { + return [{text: group.text, furigana: ''}].concat(segs); + } + } + } else { + let foundSegments = null; + for (let i = reading2.length; i >= group.text.length; --i) { + const readingUsed = reading2.substring(0, i); + const readingLeft = reading2.substring(i); + const segs = segmentize(readingLeft, groups.slice(1)); + if (segs) { + if (foundSegments !== null) { + // more than one way to segmentize the tail, mark as ambiguous + isAmbiguous = true; + return null; + } + foundSegments = [{text: group.text, furigana: readingUsed}].concat(segs); + } + // there is only one way to segmentize the last non-kana group + if (groups.length === 1) { + break; + } + } + return foundSegments; + } + }; + + const groups = []; + let modePrev = null; + for (const c of expression) { + const codePoint = c.codePointAt(0); + const modeCurr = this.isCodePointKanji(codePoint) || codePoint === ITERATION_MARK_CODE_POINT ? 'kanji' : 'kana'; + if (modeCurr === modePrev) { + groups[groups.length - 1].text += c; + } else { + groups.push({mode: modeCurr, text: c}); + modePrev = modeCurr; + } + } + + const segments = segmentize(reading, groups); + if (segments && !isAmbiguous) { + return segments; + } + return fallback; + } + + distributeFuriganaInflected(expression, reading, source) { + const output = []; + + let stemLength = 0; + const shortest = Math.min(source.length, expression.length); + const sourceHiragana = this.convertKatakanaToHiragana(source); + const expressionHiragana = this.convertKatakanaToHiragana(expression); + while (stemLength < shortest && sourceHiragana[stemLength] === expressionHiragana[stemLength]) { + ++stemLength; + } + const offset = source.length - stemLength; + + const stemExpression = source.substring(0, source.length - offset); + const stemReading = reading.substring( + 0, + offset === 0 ? reading.length : reading.length - expression.length + stemLength + ); + for (const segment of this.distributeFurigana(stemExpression, stemReading)) { + output.push(segment); + } + + if (stemLength !== source.length) { + output.push({text: source.substring(stemLength), furigana: ''}); + } + + return output; + } + + // Miscellaneous + + 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; + } + + // Private + + _getWanakana() { + const wanakana = this._wanakana; + if (wanakana === null) { throw new Error('Functions which use WanaKana are not supported in this context'); } + return wanakana; + } + + _convertAlphabeticPartToKana(text, sourceMap, sourceMapStart) { + const wanakana = this._getWanakana(); + const result = wanakana.toHiragana(text); + + // Generate source mapping + if (sourceMap !== null) { + let i = 0; + let resultPos = 0; + const ii = text.length; + while (i < ii) { + // Find smallest matching substring + let iNext = i + 1; + let resultPosNext = result.length; + while (iNext < ii) { + const t = wanakana.toHiragana(text.substring(0, iNext)); + if (t === result.substring(0, t.length)) { + resultPosNext = t.length; + break; + } + ++iNext; + } + + // Merge characters + const removals = iNext - i - 1; + if (removals > 0) { + sourceMap.combine(sourceMapStart, removals); + } + ++sourceMapStart; + + // Empty elements + const additions = resultPosNext - resultPos - 1; + for (let j = 0; j < additions; ++j) { + sourceMap.insert(sourceMapStart, 0); + ++sourceMapStart; + } + + i = iNext; + resultPos = resultPosNext; + } + } + + return result; + } + } - // Exports - return { - isCodePointKanji, - isCodePointKana, - isCodePointJapanese, - isStringEntirelyKana, - isStringPartiallyJapanese, - isMoraPitchHigh, - getKanaMorae - }; + return new JapaneseUtil(getWanakana()); })(); diff --git a/test/test-japanese.js b/test/test-japanese.js index 321861d5..39004128 100644 --- a/test/test-japanese.js +++ b/test/test-japanese.js @@ -22,8 +22,7 @@ const vm = new VM(); vm.execute([ 'mixed/lib/wanakana.min.js', 'mixed/js/japanese.js', - 'bg/js/text-source-map.js', - 'bg/js/japanese.js' + 'bg/js/text-source-map.js' ]); const jp = vm.get('jp'); const TextSourceMap = vm.get('TextSourceMap'); -- cgit v1.2.3 From 9742d5662bde1340a12c343599cc962e2b175803 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sun, 10 May 2020 14:07:25 -0400 Subject: Use CSS variables for themes (#528) * Update formatting * Merge default tag color with category-less tags * Use CSS variables for colors * Add dark theme colors * Move color variables into display.css * Remove old stylesheets * Update headings * Bump minimum Firefox version to support CSS var() * Revert popular kanji text color --- ext/bg/search.html | 2 - ext/fg/float.html | 2 - ext/manifest.json | 2 +- ext/mixed/css/display-dark.css | 103 --------------------- ext/mixed/css/display-default.css | 103 --------------------- ext/mixed/css/display.css | 184 ++++++++++++++++++++++++++++++++++---- ext/mixed/js/display.js | 6 -- 7 files changed, 167 insertions(+), 235 deletions(-) delete mode 100644 ext/mixed/css/display-dark.css delete mode 100644 ext/mixed/css/display-default.css (limited to 'ext/bg/search.html') diff --git a/ext/bg/search.html b/ext/bg/search.html index a30b1d60..f3f156d8 100644 --- a/ext/bg/search.html +++ b/ext/bg/search.html @@ -14,8 +14,6 @@ - -
    diff --git a/ext/fg/float.html b/ext/fg/float.html index 6f37de52..89952524 100644 --- a/ext/fg/float.html +++ b/ext/fg/float.html @@ -12,8 +12,6 @@ - - diff --git a/ext/manifest.json b/ext/manifest.json index 80823fc4..865fe3f3 100644 --- a/ext/manifest.json +++ b/ext/manifest.json @@ -88,7 +88,7 @@ "applications": { "gecko": { "id": "alex@foosoft.net", - "strict_min_version": "53.0" + "strict_min_version": "55.0" } } } diff --git a/ext/mixed/css/display-dark.css b/ext/mixed/css/display-dark.css deleted file mode 100644 index acfa2782..00000000 --- a/ext/mixed/css/display-dark.css +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2019-2020 Yomichan Authors - * - * This program is free software: you can redistribute it and/or modify - * it under the entrys of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -body { background-color: #1e1e1e; color: #d4d4d4; } - -h2 { border-bottom-color: #2f2f2f; } - -.navigation-header { - background-color: #1e1e1e; - border-bottom-color: #2f2f2f; -} - -.entry+.entry { border-top-color: #2f2f2f; } - -.kanji-glyph-data>tbody>tr>* { border-top-color: #3f3f3f; } - -.tag { color: #e1e1e1; } -.tag[data-category=default] { background-color: #69696e; } -.tag[data-category=name] { background-color: #489148; } -.tag[data-category=expression] { background-color: #b07f39; } -.tag[data-category=popular] { background-color: #025caa; } -.tag[data-category=frequent] { background-color: #4490a7; } -.tag[data-category=archaism] { background-color: #b04340; } -.tag[data-category=dictionary] { background-color: #9057ad; } -.tag[data-category=frequency] { background-color: #489148; } -.tag[data-category=partOfSpeech] { background-color: #565656; } -.tag[data-category=search] { background-color: #69696e; } -.tag[data-category=pitch-accent-dictionary] { background-color: #6640be; } - -.term-reasons { color: #888888; } - -.term-expression>.term-expression-text .kanji-link { - border-bottom-color: #888888; - color: #cccccc; -} - -.term-expression[data-frequency=popular]>.term-expression-text, -.term-expression[data-frequency=popular]>.term-expression-text .kanji-link { - color: #0275d8; -} - -.term-expression[data-frequency=rare]>.term-expression-text, -.term-expression[data-frequency=rare]>.term-expression-text .kanji-link { - color: #666666; -} - -.term-definition-list, -.term-pitch-accent-group-list, -.term-pitch-accent-disambiguation-list, -.kanji-glossary-list { - color: #888888; -} - -.term-glossary, -.term-pitch-accent, -.kanji-glossary { - color: #d4d4d4; -} - -.icon-checkbox:checked + label { - /* invert colors */ - background-color: #d4d4d4; - color: #1e1e1e; -} - -.term-pitch-accent-container { border-bottom-color: #2f2f2f; } - -.term-pitch-accent-character:before { border-color: #ffffff; } - -.term-pitch-accent-graph-line, -.term-pitch-accent-graph-line-tail, -#term-pitch-accent-graph-dot, -#term-pitch-accent-graph-dot-downstep, -#term-pitch-accent-graph-triangle { - stroke: #ffffff; -} - -#term-pitch-accent-graph-dot, -#term-pitch-accent-graph-dot-downstep>circle:last-of-type { - fill: #ffffff; -} - -.term-glossary-image-container { - background-color: #2f2f2f; -} -.term-glossary-image-container-overlay { - color: #888888; -} diff --git a/ext/mixed/css/display-default.css b/ext/mixed/css/display-default.css deleted file mode 100644 index 70f81eb6..00000000 --- a/ext/mixed/css/display-default.css +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2019-2020 Yomichan Authors - * - * This program is free software: you can redistribute it and/or modify - * it under the entrys of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -body { background-color: #ffffff; color: #333333; } - -h2 { border-bottom-color: #eeeeee; } - -.navigation-header { - background-color: #ffffff; - border-bottom-color: #eeeeee; -} - -.entry+.entry { border-top-color: #eeeeee; } - -.kanji-glyph-data>tbody>tr>* { border-top-color: #dddddd; } - -.tag { color: #ffffff; } -.tag[data-category=default] { background-color: #8a8a91; } -.tag[data-category=name] { background-color: #5cb85c; } -.tag[data-category=expression] { background-color: #f0ad4e; } -.tag[data-category=popular] { background-color: #0275d8; } -.tag[data-category=frequent] { background-color: #5bc0de; } -.tag[data-category=archaism] { background-color: #d9534f; } -.tag[data-category=dictionary] { background-color: #aa66cc; } -.tag[data-category=frequency] { background-color: #5cb85c; } -.tag[data-category=partOfSpeech] { background-color: #565656; } -.tag[data-category=search] { background-color: #8a8a91; } -.tag[data-category=pitch-accent-dictionary] { background-color: #6640be; } - -.term-reasons { color: #777777; } - -.term-expression>.term-expression-text .kanji-link { - border-bottom-color: #777777; - color: #333333; -} - -.term-expression[data-frequency=popular]>.term-expression-text, -.term-expression[data-frequency=popular]>.term-expression-text .kanji-link { - color: #0275d8; -} - -.term-expression[data-frequency=rare]>.term-expression-text, -.term-expression[data-frequency=rare]>.term-expression-text .kanji-link { - color: #999999; -} - -.term-definition-list, -.term-pitch-accent-group-list, -.term-pitch-accent-disambiguation-list, -.kanji-glossary-list { - color: #777777; -} - -.term-glossary, -.term-pitch-accent, -.kanji-glossary { - color: #000000; -} - -.icon-checkbox:checked + label { - /* invert colors */ - background-color: #333333; - color: #ffffff; -} - -.term-pitch-accent-container { border-bottom-color: #eeeeee; } - -.term-pitch-accent-character:before { border-color: #000000; } - -.term-pitch-accent-graph-line, -.term-pitch-accent-graph-line-tail, -#term-pitch-accent-graph-dot, -#term-pitch-accent-graph-dot-downstep, -#term-pitch-accent-graph-triangle { - stroke: #000000; -} - -#term-pitch-accent-graph-dot, -#term-pitch-accent-graph-dot-downstep>circle:last-of-type { - fill: #000000; -} - -.term-glossary-image-container { - background-color: #eeeeee; -} -.term-glossary-image-container-overlay { - color: #777777; -} diff --git a/ext/mixed/css/display.css b/ext/mixed/css/display.css index 4f43af6f..8b567173 100644 --- a/ext/mixed/css/display.css +++ b/ext/mixed/css/display.css @@ -15,6 +15,72 @@ * along with this program. If not, see . */ +/* + * Variables + */ + +:root { + --background-color: #ffffff; + --glossary-image-background-color: #eeeeee; + + --dark-text-color: #000000; + --default-text-color: #333333; + --light-text-color: #777777; + --very-light-text-color: #999999; + + --light-border-color: #eeeeee; + --medium-border-color: #dddddd; + --dark-border-color: #777777; + + --popuplar-kanji-text-color: #0275d8; + + --pitch-accent-annotation-color: #000000; + + --tag-text-color: #ffffff; + --tag-default-background-color: #8a8a91; + --tag-name-background-color: #5cb85c; + --tag-expression-background-color: #f0ad4e; + --tag-popular-background-color: #0275d8; + --tag-frequent-background-color: #5bc0de; + --tag-archaism-background-color: #d9534f; + --tag-dictionary-background-color: #aa66cc; + --tag-frequency-background-color: #5cb85c; + --tag-part-of-speech-background-color: #565656; + --tag-search-background-color: #8a8a91; + --tag-pitch-accent-dictionary-background-color: #6640be; +} + +:root[data-yomichan-theme=dark] { + --background-color: #1e1e1e; + --glossary-image-background-color: #2f2f2f; + + --dark-text-color: #d8d8d8; + --default-text-color: #d4d4d4; + --light-text-color: #888888; + --very-light-text-color: #666666; + + --light-border-color: #2f2f2f; + --medium-border-color: #3f3f3f; + --dark-border-color: #888888; + + --popuplar-kanji-text-color: #0275d8; + + --pitch-accent-annotation-color: #ffffff; + + --tag-text-color: #e1e1e1; + --tag-default-background-color: #69696e; + --tag-name-background-color: #489148; + --tag-expression-background-color: #b07f39; + --tag-popular-background-color: #025caa; + --tag-frequent-background-color: #4490a7; + --tag-archaism-background-color: #b04340; + --tag-dictionary-background-color: #9057ad; + --tag-frequency-background-color: #489148; + --tag-part-of-speech-background-color: #565656; + --tag-search-background-color: #69696e; + --tag-pitch-accent-dictionary-background-color: #6640be; +} + /* * Fonts @@ -25,6 +91,7 @@ src: url('/mixed/ttf/kanji-stroke-orders.ttf'); } + /* * General */ @@ -45,6 +112,8 @@ body { border: 0; padding: 0; overflow-y: scroll; /* always show scroll bar */ + background-color: var(--background-color); + color: var(--default-text-color); } ol, ul { @@ -68,10 +137,10 @@ h2 { font-size: 1.25em; font-weight: normal; margin: 0.25em 0 0; - border-bottom-width: 0.05714285714285714em; /* 14px * 1.25em => 1px */ - border-bottom-style: solid; + border-bottom: 0.05714285714285714em solid var(--light-border-color); /* 14px * 1.25em => 1px */ } + /* * Navigation */ @@ -83,8 +152,8 @@ h2 { height: 2.1em; box-sizing: border-box; padding: 0.25em 0.5em; - border-bottom-width: 0.07142857em; /* 14px => 1px */ - border-bottom-style: solid; + border-bottom: 0.07142857em solid var(--light-border-color); /* 14px => 1px */ + background-color: var(--background-color); z-index: 10; } @@ -131,6 +200,12 @@ h2 { user-select: none; } +.icon-checkbox:checked+label { + /* Invert colors */ + background-color: var(--default-text-color); + color: var(--background-color); +} + #query-parser-content { margin-top: 0.5em; font-size: 2em; @@ -206,11 +281,21 @@ button.action-button { } .term-expression .kanji-link { - border-bottom-width: 0.03571428em; /* 28px => 1px */ - border-bottom-style: dashed; + border-bottom: 0.03571428em dashed var(--dark-border-color); /* 28px => 1px */ + color: var(--default-text-color); text-decoration: none; } +.term-expression[data-frequency=popular]>.term-expression-text, +.term-expression[data-frequency=popular]>.term-expression-text .kanji-link { + color: var(--popuplar-kanji-text-color); +} + +.term-expression[data-frequency=rare]>.term-expression-text, +.term-expression[data-frequency=rare]>.term-expression-text .kanji-link { + color: var(--very-light-text-color); +} + .entry:not(.entry-current) .current { display: none; } @@ -225,6 +310,48 @@ button.action-button { white-space: nowrap; vertical-align: baseline; border-radius: 0.25em; + color: var(--tag-text-color); + background-color: var(--tag-default-background-color); +} + +.tag[data-category=name] { + background-color: var(--tag-name-background-color); +} + +.tag[data-category=expression] { + background-color: var(--tag-expression-background-color); +} + +.tag[data-category=popular] { + background-color: var(--tag-popular-background-color); +} + +.tag[data-category=frequent] { + background-color: var(--tag-frequent-background-color); +} + +.tag[data-category=archaism] { + background-color: var(--tag-archaism-background-color); +} + +.tag[data-category=dictionary] { + background-color: var(--tag-dictionary-background-color); +} + +.tag[data-category=frequency] { + background-color: var(--tag-frequency-background-color); +} + +.tag[data-category=partOfSpeech] { + background-color: var(--tag-part-of-speech-background-color); +} + +.tag[data-category=search] { + background-color: var(--tag-search-background-color); +} + +.tag[data-category=pitch-accent-dictionary] { + background-color: var(--tag-pitch-accent-dictionary-background-color); } .tag-inner { @@ -249,8 +376,7 @@ button.action-button { } .entry+.entry { - border-top-width: 0.07142857em; /* 14px => 1px */ - border-top-style: solid; + border-top: 0.07142857em solid var(--light-border-color); /* 14px => 1px */ } .entry[data-type=term][data-expression-multi=true] .actions>.action-play-audio { @@ -259,6 +385,7 @@ button.action-button { .term-reasons { display: inline-block; + color: var(--light-text-color); } .term-reasons>.term-reason+.term-reason-separator+.term-reason:before { @@ -346,6 +473,7 @@ button.action-button { margin: 0; padding: 0; list-style-type: none; + color: var(--light-text-color); } .term-definition-list:not([data-count="0"]):not([data-count="1"]) { @@ -364,6 +492,10 @@ button.action-button { list-style-type: circle; } +.term-glossary { + color: var(--dark-text-color); +} + .term-definition-disambiguation-list[data-count="0"] { display: none; } @@ -445,8 +577,7 @@ button.action-button { } .term-pitch-accent-container { - border-bottom-width: 0.05714285714285714em; /* 14px * 1.25em => 1px */ - border-bottom-style: solid; + border-bottom: 0.05714285714285714em solid var(--light-border-color); /* 14px * 1.25em => 1px */ padding-bottom: 0.25em; margin-bottom: 0.25em; } @@ -455,6 +586,7 @@ button.action-button { margin: 0; padding: 0; list-style-type: none; + color: var(--light-text-color); } .term-pitch-accent-group-list:not([data-count="0"]):not([data-count="1"]) { @@ -478,6 +610,7 @@ button.action-button { .term-pitch-accent { display: inline; line-height: 1.5em; + color: var(--dark-text-color); } .term-pitch-accent-list:not([data-count="0"]):not([data-count="1"])>.term-pitch-accent { @@ -490,6 +623,7 @@ button.action-button { .term-pitch-accent-disambiguation-list { padding-right: 0.25em; + color: var(--light-text-color); } .term-pitch-accent-disambiguation-list:before { @@ -522,6 +656,9 @@ button.action-button { display: inline-block; position: relative; } +.term-pitch-accent-character:before { + border-color: var(--pitch-accent-annotation-color); +} .term-pitch-accent-character[data-pitch='high']:before { content: ""; display: block; @@ -586,31 +723,36 @@ button.action-button { .term-pitch-accent-graph-line, .term-pitch-accent-graph-line-tail { fill: none; - stroke: #000000; + stroke: var(--pitch-accent-annotation-color); stroke-width: 5; } .term-pitch-accent-graph-line-tail { stroke-dasharray: 5 5; } #term-pitch-accent-graph-dot { - fill: #000000; - stroke: #000000; + fill: var(--pitch-accent-annotation-color); + stroke: var(--pitch-accent-annotation-color); stroke-width: 5; } #term-pitch-accent-graph-dot-downstep { fill: none; - stroke: #000000; + stroke: var(--pitch-accent-annotation-color); stroke-width: 5; } #term-pitch-accent-graph-dot-downstep>circle:last-of-type { - fill: #000000; + fill: var(--pitch-accent-annotation-color); } #term-pitch-accent-graph-triangle { fill: none; - stroke: #000000; + stroke: var(--pitch-accent-annotation-color); stroke-width: 5; } + +/* + * Glossary images + */ + .term-glossary-image-container { display: inline-block; white-space: nowrap; @@ -620,6 +762,7 @@ button.action-button { line-height: 0; font-size: 0.07142857em; /* 14px => 1px */ overflow: hidden; + background-color: var(--glossary-image-background-color); } .term-glossary-image-link { @@ -642,6 +785,7 @@ button.action-button { display: table; table-layout: fixed; white-space: normal; + color: var(--light-text-color); } .term-glossary-item[data-has-image=true][data-image-load-state=load-error] .term-glossary-image-container-overlay:after { @@ -746,8 +890,7 @@ button.action-button { } .kanji-glyph-data>tbody>tr>* { - border-top-width: 0.07142857em; /* 14px => 1px */ - border-top-style: solid; + border-top: 0.07142857em solid var(--medium-border-color); /* 14px => 1px */ text-align: left; vertical-align: top; padding: 0.36em; @@ -783,9 +926,14 @@ button.action-button { margin: 0; padding: 0; list-style-type: none; + color: var(--light-text-color); } .kanji-glossary-list:not([data-count="0"]):not([data-count="1"]) { padding-left: 1.4em; list-style-type: decimal; } + +.kanji-glossary { + color: var(--dark-text-color); +} diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index 783af7d8..2e59b4ff 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -399,12 +399,6 @@ class Display { updateTheme(themeName) { document.documentElement.dataset.yomichanTheme = themeName; - - const stylesheets = document.querySelectorAll('link[data-yomichan-theme-name]'); - for (const stylesheet of stylesheets) { - const match = (stylesheet.dataset.yomichanThemeName === themeName); - stylesheet.rel = (match ? 'stylesheet' : 'stylesheet alternate'); - } } setCustomCss(css) { -- cgit v1.2.3