From b8df9896e643c772253749a335b2abf0daa7a282 Mon Sep 17 00:00:00 2001 From: siikamiika Date: Thu, 1 Aug 2019 02:20:09 +0300 Subject: [PATCH 01/11] allow looking up terms from within terms resolves #167, resolves #139, resolves #75, resolves #151 --- ext/fg/float.html | 2 ++ ext/fg/js/float.js | 35 +++++++++++++++++++++++++++++++++++ ext/mixed/js/display.js | 1 + 3 files changed, 38 insertions(+) diff --git a/ext/fg/float.html b/ext/fg/float.html index fed7eeab..07f2d58b 100644 --- a/ext/fg/float.html +++ b/ext/fg/float.html @@ -36,6 +36,8 @@ + + diff --git a/ext/fg/js/float.js b/ext/fg/js/float.js index 1deb61a9..65ed89a1 100644 --- a/ext/fg/js/float.js +++ b/ext/fg/js/float.js @@ -123,6 +123,41 @@ class DisplayFloat extends Display { parent.appendChild(this.styleNode); } } + + async onTermLookup(e) { + try { + e.preventDefault(); + + const clickedElement = $(e.target); + const textSource = docRangeFromPoint({x: e.clientX, y: e.clientY}); + textSource.setEndOffset(this.options.scanning.length); + + const {definitions, length} = await apiTermsFind(textSource.text()); + if (definitions.length === 0) { + return false; + } + + textSource.setEndOffset(length); + + const sentence = docSentenceExtract(textSource, this.options.anki.sentenceExt); + + const context = { + source: { + definitions: this.definitions, + index: Display.entryIndexFind(clickedElement) + } + }; + + if (this.context) { + context.sentence = sentence; + context.url = this.context.url; + } + + this.termsShow(definitions, this.options, context); + } catch (e) { + this.onError(e); + } + } } window.yomichan_display = new DisplayFloat(); diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index 43eb93c1..364d67d8 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -265,6 +265,7 @@ class Display { $('.action-view-note').click(this.onNoteView.bind(this)); $('.action-play-audio').click(this.onAudioPlay.bind(this)); $('.kanji-link').click(this.onKanjiLookup.bind(this)); + $('.glossary li').click(this.onTermLookup.bind(this)); await this.adderButtonUpdate(['term-kanji', 'term-kana'], sequence); } catch (e) { From e500a647a2518e9090529522b0dd6dd84d26aefe Mon Sep 17 00:00:00 2001 From: siikamiika Date: Thu, 1 Aug 2019 20:41:06 +0300 Subject: [PATCH 02/11] fix term lookup for terms with one gloss only --- ext/mixed/js/display.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index 364d67d8..dc6f5798 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -265,7 +265,7 @@ class Display { $('.action-view-note').click(this.onNoteView.bind(this)); $('.action-play-audio').click(this.onAudioPlay.bind(this)); $('.kanji-link').click(this.onKanjiLookup.bind(this)); - $('.glossary li').click(this.onTermLookup.bind(this)); + $('.glossary-item').click(this.onTermLookup.bind(this)); await this.adderButtonUpdate(['term-kanji', 'term-kana'], sequence); } catch (e) { From 04f4607922e84d93ca8a05708802fb6bbd61f359 Mon Sep 17 00:00:00 2001 From: siikamiika Date: Fri, 2 Aug 2019 00:04:39 +0300 Subject: [PATCH 03/11] use ES6 import and export --- ext/bg/js/search.js | 1 + ext/bg/search.html | 3 +- ext/fg/float.html | 5 +- ext/fg/js/document.module.js | 177 +++++++++++++++++++++++++ ext/fg/js/float.js | 36 +----- ext/fg/js/source.module.js | 244 +++++++++++++++++++++++++++++++++++ ext/mixed/js/display.js | 39 ++++++ 7 files changed, 464 insertions(+), 41 deletions(-) create mode 100644 ext/fg/js/document.module.js create mode 100644 ext/fg/js/source.module.js diff --git a/ext/bg/js/search.js b/ext/bg/js/search.js index 40bf2019..911b5566 100644 --- a/ext/bg/js/search.js +++ b/ext/bg/js/search.js @@ -16,6 +16,7 @@ * along with this program. If not, see . */ +import {Display} from '../../mixed/js/display.js'; class DisplaySearch extends Display { constructor() { diff --git a/ext/bg/search.html b/ext/bg/search.html index 0d6c7cad..09b761cc 100644 --- a/ext/bg/search.html +++ b/ext/bg/search.html @@ -43,9 +43,8 @@ - - + diff --git a/ext/fg/float.html b/ext/fg/float.html index 07f2d58b..4860753a 100644 --- a/ext/fg/float.html +++ b/ext/fg/float.html @@ -36,10 +36,7 @@ - - - - + diff --git a/ext/fg/js/document.module.js b/ext/fg/js/document.module.js new file mode 100644 index 00000000..d86aff33 --- /dev/null +++ b/ext/fg/js/document.module.js @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2016-2017 Alex Yatskov + * Author: Alex Yatskov + * + * 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 . + */ + +import {TextSourceRange, TextSourceElement} from './source.module.js'; + +export function docOffsetCalc(element) { + const scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop; + const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft; + + const clientTop = document.documentElement.clientTop || document.body.clientTop || 0; + const clientLeft = document.documentElement.clientLeft || document.body.clientLeft || 0; + + const rect = element.getBoundingClientRect(); + const top = Math.round(rect.top + scrollTop - clientTop); + const left = Math.round(rect.left + scrollLeft - clientLeft); + + return {top, left}; +} + +export function docImposterCreate(element) { + const styleProps = window.getComputedStyle(element); + const stylePairs = []; + for (const key of styleProps) { + stylePairs.push(`${key}: ${styleProps[key]};`); + } + + const offset = docOffsetCalc(element); + const imposter = document.createElement('div'); + imposter.className = 'yomichan-imposter'; + imposter.innerText = element.value; + imposter.style.cssText = stylePairs.join('\n'); + imposter.style.position = 'absolute'; + imposter.style.top = `${offset.top}px`; + imposter.style.left = `${offset.left}px`; + imposter.style.opacity = 0; + imposter.style.zIndex = 2147483646; + if (element.nodeName === 'TEXTAREA' && styleProps.overflow === 'visible') { + imposter.style.overflow = 'auto'; + } + + document.body.appendChild(imposter); + imposter.scrollTop = element.scrollTop; + imposter.scrollLeft = element.scrollLeft; + + return imposter; +} + +export function docImposterDestroy() { + for (const element of document.getElementsByClassName('yomichan-imposter')) { + element.parentNode.removeChild(element); + } +} + +export function docRangeFromPoint(point) { + const element = document.elementFromPoint(point.x, point.y); + let imposter = null; + if (element) { + if (element.nodeName === 'IMG' || element.nodeName === 'BUTTON') { + return new TextSourceElement(element); + } else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') { + imposter = docImposterCreate(element); + } + } + + if (!document.caretRangeFromPoint) { + document.caretRangeFromPoint = (x, y) => { + const position = document.caretPositionFromPoint(x,y); + if (position && position.offsetNode && position.offsetNode.nodeType === Node.TEXT_NODE) { + const range = document.createRange(); + range.setStart(position.offsetNode, position.offset); + range.setEnd(position.offsetNode, position.offset); + return range; + } + return null; + }; + } + + const range = document.caretRangeFromPoint(point.x, point.y); + if (range === null) { + return; + } + + if(imposter !== null) imposter.style.zIndex = -2147483646; + + const rects = range.getClientRects(); + for (const rect of rects) { + if (point.y <= rect.bottom + 2) { + return new TextSourceRange(range); + } + } +} + +export function docSentenceExtract(source, extent) { + const quotesFwd = {'「': '」', '『': '』', "'": "'", '"': '"'}; + const quotesBwd = {'」': '「', '』': '『', "'": "'", '"': '"'}; + const terminators = '…。..??!!'; + + const sourceLocal = source.clone(); + const position = sourceLocal.setStartOffset(extent); + sourceLocal.setEndOffset(position + extent); + const content = sourceLocal.text(); + + let quoteStack = []; + + let startPos = 0; + for (let i = position; i >= startPos; --i) { + const c = content[i]; + + if (c === '\n') { + startPos = i + 1; + break; + } + + if (quoteStack.length === 0 && (terminators.includes(c) || c in quotesFwd)) { + startPos = i + 1; + break; + } + + if (quoteStack.length > 0 && c === quoteStack[0]) { + quoteStack.pop(); + } else if (c in quotesBwd) { + quoteStack = [quotesBwd[c]].concat(quoteStack); + } + } + + quoteStack = []; + + let endPos = content.length; + for (let i = position; i <= endPos; ++i) { + const c = content[i]; + + if (c === '\n') { + endPos = i + 1; + break; + } + + if (quoteStack.length === 0) { + if (terminators.includes(c)) { + endPos = i + 1; + break; + } + else if (c in quotesBwd) { + endPos = i; + break; + } + } + + if (quoteStack.length > 0 && c === quoteStack[0]) { + quoteStack.pop(); + } else if (c in quotesFwd) { + quoteStack = [quotesFwd[c]].concat(quoteStack); + } + } + + const text = content.substring(startPos, endPos); + const padding = text.length - text.replace(/^\s+/, '').length; + + return { + text: text.trim(), + offset: position - startPos - padding + }; +} diff --git a/ext/fg/js/float.js b/ext/fg/js/float.js index 65ed89a1..9301135b 100644 --- a/ext/fg/js/float.js +++ b/ext/fg/js/float.js @@ -16,6 +16,7 @@ * along with this program. If not, see . */ +import {Display} from '../../mixed/js/display.js'; class DisplayFloat extends Display { constructor() { @@ -123,41 +124,6 @@ class DisplayFloat extends Display { parent.appendChild(this.styleNode); } } - - async onTermLookup(e) { - try { - e.preventDefault(); - - const clickedElement = $(e.target); - const textSource = docRangeFromPoint({x: e.clientX, y: e.clientY}); - textSource.setEndOffset(this.options.scanning.length); - - const {definitions, length} = await apiTermsFind(textSource.text()); - if (definitions.length === 0) { - return false; - } - - textSource.setEndOffset(length); - - const sentence = docSentenceExtract(textSource, this.options.anki.sentenceExt); - - const context = { - source: { - definitions: this.definitions, - index: Display.entryIndexFind(clickedElement) - } - }; - - if (this.context) { - context.sentence = sentence; - context.url = this.context.url; - } - - this.termsShow(definitions, this.options, context); - } catch (e) { - this.onError(e); - } - } } window.yomichan_display = new DisplayFloat(); diff --git a/ext/fg/js/source.module.js b/ext/fg/js/source.module.js new file mode 100644 index 00000000..ed9263c5 --- /dev/null +++ b/ext/fg/js/source.module.js @@ -0,0 +1,244 @@ +/* + * Copyright (C) 2016-2017 Alex Yatskov + * Author: Alex Yatskov + * + * 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 . + */ + + +/* + * TextSourceRange + */ + +export class TextSourceRange { + constructor(range, content='') { + this.range = range; + this.content = content; + } + + clone() { + return new TextSourceRange(this.range.cloneRange(), this.content); + } + + text() { + return this.content; + } + + setEndOffset(length) { + const state = TextSourceRange.seekForward(this.range.startContainer, this.range.startOffset, length); + this.range.setEnd(state.node, state.offset); + this.content = state.content; + return length - state.remainder; + } + + setStartOffset(length) { + const state = TextSourceRange.seekBackward(this.range.startContainer, this.range.startOffset, length); + this.range.setStart(state.node, state.offset); + this.content = state.content; + return length - state.remainder; + } + + containsPoint(point) { + const rect = this.getPaddedRect(); + return point.x >= rect.left && point.x <= rect.right; + } + + getRect() { + return this.range.getBoundingClientRect(); + } + + getPaddedRect() { + const range = this.range.cloneRange(); + const startOffset = range.startOffset; + const endOffset = range.endOffset; + const node = range.startContainer; + + range.setStart(node, Math.max(0, startOffset - 1)); + range.setEnd(node, Math.min(node.length, endOffset + 1)); + + return range.getBoundingClientRect(); + } + + select() { + const selection = window.getSelection(); + selection.removeAllRanges(); + selection.addRange(this.range); + } + + deselect() { + const selection = window.getSelection(); + selection.removeAllRanges(); + } + + equals(other) { + return other && other.range && other.range.compareBoundaryPoints(Range.START_TO_START, this.range) === 0; + } + + static shouldEnter(node) { + if (node.nodeType !== 1) { + return false; + } + + const skip = ['RT', 'SCRIPT', 'STYLE']; + if (skip.includes(node.nodeName)) { + return false; + } + + const style = window.getComputedStyle(node); + const hidden = + style.visibility === 'hidden' || + style.display === 'none' || + parseFloat(style.fontSize) === 0; + + return !hidden; + } + + static seekForward(node, offset, length) { + const state = {node, offset, remainder: length, content: ''}; + if (!TextSourceRange.seekForwardHelper(node, state)) { + return state; + } + + for (let current = node; current !== null; current = current.parentElement) { + for (let sibling = current.nextSibling; sibling !== null; sibling = sibling.nextSibling) { + if (!TextSourceRange.seekForwardHelper(sibling, state)) { + return state; + } + } + } + + return state; + } + + static seekForwardHelper(node, state) { + if (node.nodeType === 3 && node.parentElement && TextSourceRange.shouldEnter(node.parentElement)) { + const offset = state.node === node ? state.offset : 0; + const remaining = node.length - offset; + const consumed = Math.min(remaining, state.remainder); + state.content = state.content + node.nodeValue.substring(offset, offset + consumed); + state.node = node; + state.offset = offset + consumed; + state.remainder -= consumed; + } else if (TextSourceRange.shouldEnter(node)) { + for (let i = 0; i < node.childNodes.length; ++i) { + if (!TextSourceRange.seekForwardHelper(node.childNodes[i], state)) { + break; + } + } + } + + return state.remainder > 0; + } + + static seekBackward(node, offset, length) { + const state = {node, offset, remainder: length, content: ''}; + if (!TextSourceRange.seekBackwardHelper(node, state)) { + return state; + } + + for (let current = node; current !== null; current = current.parentElement) { + for (let sibling = current.previousSibling; sibling !== null; sibling = sibling.previousSibling) { + if (!TextSourceRange.seekBackwardHelper(sibling, state)) { + return state; + } + } + } + + return state; + } + + static seekBackwardHelper(node, state) { + if (node.nodeType === 3 && node.parentElement && TextSourceRange.shouldEnter(node.parentElement)) { + const offset = state.node === node ? state.offset : node.length; + const remaining = offset; + const consumed = Math.min(remaining, state.remainder); + state.content = node.nodeValue.substring(offset - consumed, offset) + state.content; + state.node = node; + state.offset = offset - consumed; + state.remainder -= consumed; + } else if (TextSourceRange.shouldEnter(node)) { + for (let i = node.childNodes.length - 1; i >= 0; --i) { + if (!TextSourceRange.seekBackwardHelper(node.childNodes[i], state)) { + break; + } + } + } + + return state.remainder > 0; + } +} + + +/* + * TextSourceElement + */ + +export class TextSourceElement { + constructor(element, content='') { + this.element = element; + this.content = content; + } + + clone() { + return new TextSourceElement(this.element, this.content); + } + + text() { + return this.content; + } + + setEndOffset(length) { + switch (this.element.nodeName) { + case 'BUTTON': + this.content = this.element.innerHTML; + break; + case 'IMG': + this.content = this.element.getAttribute('alt'); + break; + default: + this.content = this.element.value; + break; + } + + this.content = this.content || ''; + this.content = this.content.substring(0, length); + + return this.content.length; + } + + setStartOffset(length) { + return 0; + } + + containsPoint(point) { + const rect = this.getRect(); + return point.x >= rect.left && point.x <= rect.right; + } + + getRect() { + return this.element.getBoundingClientRect(); + } + + select() { + // NOP + } + + deselect() { + // NOP + } + + equals(other) { + return other && other.element === this.element && other.content === this.content; + } +} diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index dc6f5798..5d259936 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -17,6 +17,8 @@ */ +import {docRangeFromPoint, docSentenceExtract} from '../../fg/js/document.module.js'; + class Display { constructor(spinner, container) { this.spinner = spinner; @@ -69,6 +71,41 @@ class Display { } } + async onTermLookup(e) { + try { + e.preventDefault(); + + const clickedElement = $(e.target); + const textSource = docRangeFromPoint({x: e.clientX, y: e.clientY}); + textSource.setEndOffset(this.options.scanning.length); + + const {definitions, length} = await apiTermsFind(textSource.text()); + if (definitions.length === 0) { + return false; + } + + textSource.setEndOffset(length); + + const sentence = docSentenceExtract(textSource, this.options.anki.sentenceExt); + + const context = { + source: { + definitions: this.definitions, + index: Display.entryIndexFind(clickedElement) + } + }; + + if (this.context) { + context.sentence = sentence; + context.url = this.context.url; + } + + this.termsShow(definitions, this.options, context); + } catch (e) { + this.onError(e); + } + } + onAudioPlay(e) { e.preventDefault(); const link = $(e.currentTarget); @@ -460,3 +497,5 @@ class Display { return $('.entry').eq(index).find('.action-view-note'); } } + +export {Display}; From 52f9a8f736d02785e9171047e4533d4a0a9f4bde Mon Sep 17 00:00:00 2001 From: siikamiika Date: Sat, 3 Aug 2019 11:52:56 +0300 Subject: [PATCH 04/11] update supported browser versions for ES6 modules --- ext/manifest.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/manifest.json b/ext/manifest.json index 83900ed3..e7d57d04 100644 --- a/ext/manifest.json +++ b/ext/manifest.json @@ -25,7 +25,7 @@ "css": ["fg/css/client.css"], "all_frames": true }], - "minimum_chrome_version": "57.0.0.0", + "minimum_chrome_version": "61.0.0.0", "options_page": "bg/settings.html", "options_ui": { "page": "bg/settings.html", @@ -55,7 +55,7 @@ "applications": { "gecko": { "id": "alex.testing@foosoft.net", - "strict_min_version": "52.0" + "strict_min_version": "60.0" } } } From a343fa589e7ba05740cc11b3b2a8f86817f3a460 Mon Sep 17 00:00:00 2001 From: siikamiika Date: Sat, 3 Aug 2019 14:56:45 +0300 Subject: [PATCH 05/11] Revert "update supported browser versions for ES6 modules" This reverts commit 52f9a8f736d02785e9171047e4533d4a0a9f4bde. --- ext/manifest.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/manifest.json b/ext/manifest.json index e7d57d04..83900ed3 100644 --- a/ext/manifest.json +++ b/ext/manifest.json @@ -25,7 +25,7 @@ "css": ["fg/css/client.css"], "all_frames": true }], - "minimum_chrome_version": "61.0.0.0", + "minimum_chrome_version": "57.0.0.0", "options_page": "bg/settings.html", "options_ui": { "page": "bg/settings.html", @@ -55,7 +55,7 @@ "applications": { "gecko": { "id": "alex.testing@foosoft.net", - "strict_min_version": "60.0" + "strict_min_version": "52.0" } } } From 0ee6d05cb15a8bc94f120c2896e7537fd969aaed Mon Sep 17 00:00:00 2001 From: siikamiika Date: Sat, 3 Aug 2019 14:57:17 +0300 Subject: [PATCH 06/11] Revert "use ES6 import and export" This reverts commit 04f4607922e84d93ca8a05708802fb6bbd61f359. --- ext/bg/js/search.js | 1 - ext/bg/search.html | 3 +- ext/fg/float.html | 5 +- ext/fg/js/document.module.js | 177 ------------------------- ext/fg/js/float.js | 36 +++++- ext/fg/js/source.module.js | 244 ----------------------------------- ext/mixed/js/display.js | 39 ------ 7 files changed, 41 insertions(+), 464 deletions(-) delete mode 100644 ext/fg/js/document.module.js delete mode 100644 ext/fg/js/source.module.js diff --git a/ext/bg/js/search.js b/ext/bg/js/search.js index 911b5566..40bf2019 100644 --- a/ext/bg/js/search.js +++ b/ext/bg/js/search.js @@ -16,7 +16,6 @@ * along with this program. If not, see . */ -import {Display} from '../../mixed/js/display.js'; class DisplaySearch extends Display { constructor() { diff --git a/ext/bg/search.html b/ext/bg/search.html index 09b761cc..0d6c7cad 100644 --- a/ext/bg/search.html +++ b/ext/bg/search.html @@ -43,8 +43,9 @@ + - + diff --git a/ext/fg/float.html b/ext/fg/float.html index 4860753a..07f2d58b 100644 --- a/ext/fg/float.html +++ b/ext/fg/float.html @@ -36,7 +36,10 @@ + + + - + diff --git a/ext/fg/js/document.module.js b/ext/fg/js/document.module.js deleted file mode 100644 index d86aff33..00000000 --- a/ext/fg/js/document.module.js +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (C) 2016-2017 Alex Yatskov - * Author: Alex Yatskov - * - * 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 . - */ - -import {TextSourceRange, TextSourceElement} from './source.module.js'; - -export function docOffsetCalc(element) { - const scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop; - const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft; - - const clientTop = document.documentElement.clientTop || document.body.clientTop || 0; - const clientLeft = document.documentElement.clientLeft || document.body.clientLeft || 0; - - const rect = element.getBoundingClientRect(); - const top = Math.round(rect.top + scrollTop - clientTop); - const left = Math.round(rect.left + scrollLeft - clientLeft); - - return {top, left}; -} - -export function docImposterCreate(element) { - const styleProps = window.getComputedStyle(element); - const stylePairs = []; - for (const key of styleProps) { - stylePairs.push(`${key}: ${styleProps[key]};`); - } - - const offset = docOffsetCalc(element); - const imposter = document.createElement('div'); - imposter.className = 'yomichan-imposter'; - imposter.innerText = element.value; - imposter.style.cssText = stylePairs.join('\n'); - imposter.style.position = 'absolute'; - imposter.style.top = `${offset.top}px`; - imposter.style.left = `${offset.left}px`; - imposter.style.opacity = 0; - imposter.style.zIndex = 2147483646; - if (element.nodeName === 'TEXTAREA' && styleProps.overflow === 'visible') { - imposter.style.overflow = 'auto'; - } - - document.body.appendChild(imposter); - imposter.scrollTop = element.scrollTop; - imposter.scrollLeft = element.scrollLeft; - - return imposter; -} - -export function docImposterDestroy() { - for (const element of document.getElementsByClassName('yomichan-imposter')) { - element.parentNode.removeChild(element); - } -} - -export function docRangeFromPoint(point) { - const element = document.elementFromPoint(point.x, point.y); - let imposter = null; - if (element) { - if (element.nodeName === 'IMG' || element.nodeName === 'BUTTON') { - return new TextSourceElement(element); - } else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') { - imposter = docImposterCreate(element); - } - } - - if (!document.caretRangeFromPoint) { - document.caretRangeFromPoint = (x, y) => { - const position = document.caretPositionFromPoint(x,y); - if (position && position.offsetNode && position.offsetNode.nodeType === Node.TEXT_NODE) { - const range = document.createRange(); - range.setStart(position.offsetNode, position.offset); - range.setEnd(position.offsetNode, position.offset); - return range; - } - return null; - }; - } - - const range = document.caretRangeFromPoint(point.x, point.y); - if (range === null) { - return; - } - - if(imposter !== null) imposter.style.zIndex = -2147483646; - - const rects = range.getClientRects(); - for (const rect of rects) { - if (point.y <= rect.bottom + 2) { - return new TextSourceRange(range); - } - } -} - -export function docSentenceExtract(source, extent) { - const quotesFwd = {'「': '」', '『': '』', "'": "'", '"': '"'}; - const quotesBwd = {'」': '「', '』': '『', "'": "'", '"': '"'}; - const terminators = '…。..??!!'; - - const sourceLocal = source.clone(); - const position = sourceLocal.setStartOffset(extent); - sourceLocal.setEndOffset(position + extent); - const content = sourceLocal.text(); - - let quoteStack = []; - - let startPos = 0; - for (let i = position; i >= startPos; --i) { - const c = content[i]; - - if (c === '\n') { - startPos = i + 1; - break; - } - - if (quoteStack.length === 0 && (terminators.includes(c) || c in quotesFwd)) { - startPos = i + 1; - break; - } - - if (quoteStack.length > 0 && c === quoteStack[0]) { - quoteStack.pop(); - } else if (c in quotesBwd) { - quoteStack = [quotesBwd[c]].concat(quoteStack); - } - } - - quoteStack = []; - - let endPos = content.length; - for (let i = position; i <= endPos; ++i) { - const c = content[i]; - - if (c === '\n') { - endPos = i + 1; - break; - } - - if (quoteStack.length === 0) { - if (terminators.includes(c)) { - endPos = i + 1; - break; - } - else if (c in quotesBwd) { - endPos = i; - break; - } - } - - if (quoteStack.length > 0 && c === quoteStack[0]) { - quoteStack.pop(); - } else if (c in quotesFwd) { - quoteStack = [quotesFwd[c]].concat(quoteStack); - } - } - - const text = content.substring(startPos, endPos); - const padding = text.length - text.replace(/^\s+/, '').length; - - return { - text: text.trim(), - offset: position - startPos - padding - }; -} diff --git a/ext/fg/js/float.js b/ext/fg/js/float.js index 9301135b..65ed89a1 100644 --- a/ext/fg/js/float.js +++ b/ext/fg/js/float.js @@ -16,7 +16,6 @@ * along with this program. If not, see . */ -import {Display} from '../../mixed/js/display.js'; class DisplayFloat extends Display { constructor() { @@ -124,6 +123,41 @@ class DisplayFloat extends Display { parent.appendChild(this.styleNode); } } + + async onTermLookup(e) { + try { + e.preventDefault(); + + const clickedElement = $(e.target); + const textSource = docRangeFromPoint({x: e.clientX, y: e.clientY}); + textSource.setEndOffset(this.options.scanning.length); + + const {definitions, length} = await apiTermsFind(textSource.text()); + if (definitions.length === 0) { + return false; + } + + textSource.setEndOffset(length); + + const sentence = docSentenceExtract(textSource, this.options.anki.sentenceExt); + + const context = { + source: { + definitions: this.definitions, + index: Display.entryIndexFind(clickedElement) + } + }; + + if (this.context) { + context.sentence = sentence; + context.url = this.context.url; + } + + this.termsShow(definitions, this.options, context); + } catch (e) { + this.onError(e); + } + } } window.yomichan_display = new DisplayFloat(); diff --git a/ext/fg/js/source.module.js b/ext/fg/js/source.module.js deleted file mode 100644 index ed9263c5..00000000 --- a/ext/fg/js/source.module.js +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Copyright (C) 2016-2017 Alex Yatskov - * Author: Alex Yatskov - * - * 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 . - */ - - -/* - * TextSourceRange - */ - -export class TextSourceRange { - constructor(range, content='') { - this.range = range; - this.content = content; - } - - clone() { - return new TextSourceRange(this.range.cloneRange(), this.content); - } - - text() { - return this.content; - } - - setEndOffset(length) { - const state = TextSourceRange.seekForward(this.range.startContainer, this.range.startOffset, length); - this.range.setEnd(state.node, state.offset); - this.content = state.content; - return length - state.remainder; - } - - setStartOffset(length) { - const state = TextSourceRange.seekBackward(this.range.startContainer, this.range.startOffset, length); - this.range.setStart(state.node, state.offset); - this.content = state.content; - return length - state.remainder; - } - - containsPoint(point) { - const rect = this.getPaddedRect(); - return point.x >= rect.left && point.x <= rect.right; - } - - getRect() { - return this.range.getBoundingClientRect(); - } - - getPaddedRect() { - const range = this.range.cloneRange(); - const startOffset = range.startOffset; - const endOffset = range.endOffset; - const node = range.startContainer; - - range.setStart(node, Math.max(0, startOffset - 1)); - range.setEnd(node, Math.min(node.length, endOffset + 1)); - - return range.getBoundingClientRect(); - } - - select() { - const selection = window.getSelection(); - selection.removeAllRanges(); - selection.addRange(this.range); - } - - deselect() { - const selection = window.getSelection(); - selection.removeAllRanges(); - } - - equals(other) { - return other && other.range && other.range.compareBoundaryPoints(Range.START_TO_START, this.range) === 0; - } - - static shouldEnter(node) { - if (node.nodeType !== 1) { - return false; - } - - const skip = ['RT', 'SCRIPT', 'STYLE']; - if (skip.includes(node.nodeName)) { - return false; - } - - const style = window.getComputedStyle(node); - const hidden = - style.visibility === 'hidden' || - style.display === 'none' || - parseFloat(style.fontSize) === 0; - - return !hidden; - } - - static seekForward(node, offset, length) { - const state = {node, offset, remainder: length, content: ''}; - if (!TextSourceRange.seekForwardHelper(node, state)) { - return state; - } - - for (let current = node; current !== null; current = current.parentElement) { - for (let sibling = current.nextSibling; sibling !== null; sibling = sibling.nextSibling) { - if (!TextSourceRange.seekForwardHelper(sibling, state)) { - return state; - } - } - } - - return state; - } - - static seekForwardHelper(node, state) { - if (node.nodeType === 3 && node.parentElement && TextSourceRange.shouldEnter(node.parentElement)) { - const offset = state.node === node ? state.offset : 0; - const remaining = node.length - offset; - const consumed = Math.min(remaining, state.remainder); - state.content = state.content + node.nodeValue.substring(offset, offset + consumed); - state.node = node; - state.offset = offset + consumed; - state.remainder -= consumed; - } else if (TextSourceRange.shouldEnter(node)) { - for (let i = 0; i < node.childNodes.length; ++i) { - if (!TextSourceRange.seekForwardHelper(node.childNodes[i], state)) { - break; - } - } - } - - return state.remainder > 0; - } - - static seekBackward(node, offset, length) { - const state = {node, offset, remainder: length, content: ''}; - if (!TextSourceRange.seekBackwardHelper(node, state)) { - return state; - } - - for (let current = node; current !== null; current = current.parentElement) { - for (let sibling = current.previousSibling; sibling !== null; sibling = sibling.previousSibling) { - if (!TextSourceRange.seekBackwardHelper(sibling, state)) { - return state; - } - } - } - - return state; - } - - static seekBackwardHelper(node, state) { - if (node.nodeType === 3 && node.parentElement && TextSourceRange.shouldEnter(node.parentElement)) { - const offset = state.node === node ? state.offset : node.length; - const remaining = offset; - const consumed = Math.min(remaining, state.remainder); - state.content = node.nodeValue.substring(offset - consumed, offset) + state.content; - state.node = node; - state.offset = offset - consumed; - state.remainder -= consumed; - } else if (TextSourceRange.shouldEnter(node)) { - for (let i = node.childNodes.length - 1; i >= 0; --i) { - if (!TextSourceRange.seekBackwardHelper(node.childNodes[i], state)) { - break; - } - } - } - - return state.remainder > 0; - } -} - - -/* - * TextSourceElement - */ - -export class TextSourceElement { - constructor(element, content='') { - this.element = element; - this.content = content; - } - - clone() { - return new TextSourceElement(this.element, this.content); - } - - text() { - return this.content; - } - - setEndOffset(length) { - switch (this.element.nodeName) { - case 'BUTTON': - this.content = this.element.innerHTML; - break; - case 'IMG': - this.content = this.element.getAttribute('alt'); - break; - default: - this.content = this.element.value; - break; - } - - this.content = this.content || ''; - this.content = this.content.substring(0, length); - - return this.content.length; - } - - setStartOffset(length) { - return 0; - } - - containsPoint(point) { - const rect = this.getRect(); - return point.x >= rect.left && point.x <= rect.right; - } - - getRect() { - return this.element.getBoundingClientRect(); - } - - select() { - // NOP - } - - deselect() { - // NOP - } - - equals(other) { - return other && other.element === this.element && other.content === this.content; - } -} diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index 5d259936..dc6f5798 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -17,8 +17,6 @@ */ -import {docRangeFromPoint, docSentenceExtract} from '../../fg/js/document.module.js'; - class Display { constructor(spinner, container) { this.spinner = spinner; @@ -71,41 +69,6 @@ class Display { } } - async onTermLookup(e) { - try { - e.preventDefault(); - - const clickedElement = $(e.target); - const textSource = docRangeFromPoint({x: e.clientX, y: e.clientY}); - textSource.setEndOffset(this.options.scanning.length); - - const {definitions, length} = await apiTermsFind(textSource.text()); - if (definitions.length === 0) { - return false; - } - - textSource.setEndOffset(length); - - const sentence = docSentenceExtract(textSource, this.options.anki.sentenceExt); - - const context = { - source: { - definitions: this.definitions, - index: Display.entryIndexFind(clickedElement) - } - }; - - if (this.context) { - context.sentence = sentence; - context.url = this.context.url; - } - - this.termsShow(definitions, this.options, context); - } catch (e) { - this.onError(e); - } - } - onAudioPlay(e) { e.preventDefault(); const link = $(e.currentTarget); @@ -497,5 +460,3 @@ class Display { return $('.entry').eq(index).find('.action-view-note'); } } - -export {Display}; From afc771de9fd34a7b16a6bbf8bcdc85dd758d7836 Mon Sep 17 00:00:00 2001 From: siikamiika Date: Sat, 3 Aug 2019 15:06:28 +0300 Subject: [PATCH 07/11] inject doc functions as dependencies --- ext/bg/js/search.js | 2 ++ ext/fg/js/float.js | 37 ++----------------------------------- ext/mixed/js/display.js | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 35 deletions(-) diff --git a/ext/bg/js/search.js b/ext/bg/js/search.js index 40bf2019..f08f22da 100644 --- a/ext/bg/js/search.js +++ b/ext/bg/js/search.js @@ -25,6 +25,8 @@ class DisplaySearch extends Display { this.query = $('#query').on('input', this.onSearchInput.bind(this)); this.intro = $('#intro'); + this.dependencies = {...this.dependencies, ...{docRangeFromPoint, docSentenceExtract}}; + window.wanakana.bind(this.query.get(0)); } diff --git a/ext/fg/js/float.js b/ext/fg/js/float.js index 65ed89a1..090839a1 100644 --- a/ext/fg/js/float.js +++ b/ext/fg/js/float.js @@ -23,6 +23,8 @@ class DisplayFloat extends Display { this.autoPlayAudioTimer = null; this.styleNode = null; + this.dependencies = {...this.dependencies, ...{docRangeFromPoint, docSentenceExtract}}; + $(window).on('message', utilAsync(this.onMessage.bind(this))); } @@ -123,41 +125,6 @@ class DisplayFloat extends Display { parent.appendChild(this.styleNode); } } - - async onTermLookup(e) { - try { - e.preventDefault(); - - const clickedElement = $(e.target); - const textSource = docRangeFromPoint({x: e.clientX, y: e.clientY}); - textSource.setEndOffset(this.options.scanning.length); - - const {definitions, length} = await apiTermsFind(textSource.text()); - if (definitions.length === 0) { - return false; - } - - textSource.setEndOffset(length); - - const sentence = docSentenceExtract(textSource, this.options.anki.sentenceExt); - - const context = { - source: { - definitions: this.definitions, - index: Display.entryIndexFind(clickedElement) - } - }; - - if (this.context) { - context.sentence = sentence; - context.url = this.context.url; - } - - this.termsShow(definitions, this.options, context); - } catch (e) { - this.onError(e); - } - } } window.yomichan_display = new DisplayFloat(); diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index dc6f5798..0067d457 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -28,6 +28,8 @@ class Display { this.index = 0; this.audioCache = {}; + this.dependencies = {}; + $(document).keydown(this.onKeyDown.bind(this)); $(document).on('wheel', this.onWheel.bind(this)); } @@ -69,6 +71,43 @@ class Display { } } + async onTermLookup(e) { + try { + e.preventDefault(); + + const {docRangeFromPoint, docSentenceExtract} = this.dependencies; + + const clickedElement = $(e.target); + const textSource = docRangeFromPoint({x: e.clientX, y: e.clientY}); + textSource.setEndOffset(this.options.scanning.length); + + const {definitions, length} = await apiTermsFind(textSource.text()); + if (definitions.length === 0) { + return false; + } + + textSource.setEndOffset(length); + + const sentence = docSentenceExtract(textSource, this.options.anki.sentenceExt); + + const context = { + source: { + definitions: this.definitions, + index: Display.entryIndexFind(clickedElement) + } + }; + + if (this.context) { + context.sentence = sentence; + context.url = this.context.url; + } + + this.termsShow(definitions, this.options, context); + } catch (e) { + this.onError(e); + } + } + onAudioPlay(e) { e.preventDefault(); const link = $(e.currentTarget); From 1a37342aa0168c931898f6eefa94690b1fc30d2d Mon Sep 17 00:00:00 2001 From: siikamiika Date: Sat, 3 Aug 2019 15:09:51 +0300 Subject: [PATCH 08/11] add doc scripts to search too --- ext/bg/search.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ext/bg/search.html b/ext/bg/search.html index 0d6c7cad..ce156578 100644 --- a/ext/bg/search.html +++ b/ext/bg/search.html @@ -43,6 +43,8 @@ + + From ec1441434f35ad7ac2d1feb4eae1cee12bf00609 Mon Sep 17 00:00:00 2001 From: siikamiika Date: Sat, 3 Aug 2019 15:50:49 +0300 Subject: [PATCH 09/11] allow multi level context --- ext/mixed/js/display.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index 0067d457..9a178a1f 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -62,6 +62,7 @@ class Display { if (this.context) { context.sentence = this.context.sentence; context.url = this.context.url; + context.source.source = this.context.source; } const kanjiDefs = await apiKanjiFind(link.text()); @@ -100,6 +101,7 @@ class Display { if (this.context) { context.sentence = sentence; context.url = this.context.url; + context.source.source = this.context.source; } this.termsShow(definitions, this.options, context); @@ -405,7 +407,8 @@ class Display { const context = { url: this.context.source.url, sentence: this.context.source.sentence, - index: this.context.source.index + index: this.context.source.index, + source: this.context.source.source }; this.termsShow(this.context.source.definitions, this.options, context); From 683bb5b620759c71297ca6d8fe24aa8c3ff56a18 Mon Sep 17 00:00:00 2001 From: siikamiika Date: Sat, 3 Aug 2019 19:46:54 +0300 Subject: [PATCH 10/11] scroll back to exact position in source term view --- ext/mixed/js/display.js | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index 9a178a1f..650372d3 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -55,7 +55,8 @@ class Display { const context = { source: { definitions: this.definitions, - index: Display.entryIndexFind(link) + index: Display.entryIndexFind(link), + scroll: $('html,body').scrollTop() } }; @@ -94,7 +95,8 @@ class Display { const context = { source: { definitions: this.definitions, - index: Display.entryIndexFind(clickedElement) + index: Display.entryIndexFind(clickedElement), + scroll: $('html,body').scrollTop() } }; @@ -155,42 +157,42 @@ class Display { 33: /* page up */ () => { if (e.altKey) { - this.entryScrollIntoView(this.index - 3, true); + this.entryScrollIntoView(this.index - 3, null, true); return true; } }, 34: /* page down */ () => { if (e.altKey) { - this.entryScrollIntoView(this.index + 3, true); + this.entryScrollIntoView(this.index + 3, null, true); return true; } }, 35: /* end */ () => { if (e.altKey) { - this.entryScrollIntoView(this.definitions.length - 1, true); + this.entryScrollIntoView(this.definitions.length - 1, null, true); return true; } }, 36: /* home */ () => { if (e.altKey) { - this.entryScrollIntoView(0, true); + this.entryScrollIntoView(0, null, true); return true; } }, 38: /* up */ () => { if (e.altKey) { - this.entryScrollIntoView(this.index - 1, true); + this.entryScrollIntoView(this.index - 1, null, true); return true; } }, 40: /* down */ () => { if (e.altKey) { - this.entryScrollIntoView(this.index + 1, true); + this.entryScrollIntoView(this.index + 1, null, true); return true; } }, @@ -251,10 +253,10 @@ class Display { const handler = () => { if (event.altKey) { if (event.deltaY < 0) { // scroll up - this.entryScrollIntoView(this.index - 1, true); + this.entryScrollIntoView(this.index - 1, null, true); return true; } else if (event.deltaY > 0) { // scroll down - this.entryScrollIntoView(this.index + 1, true); + this.entryScrollIntoView(this.index + 1, null, true); return true; } } @@ -296,7 +298,8 @@ class Display { const content = await apiTemplateRender('terms.html', params); this.container.html(content); - this.entryScrollIntoView(context && context.index || 0); + const {index, scroll} = context || {}; + this.entryScrollIntoView(index || 0, scroll); if (this.options.general.autoPlayAudio && this.options.general.audioSource !== 'disabled') { this.autoPlayAudio(); @@ -342,7 +345,8 @@ class Display { const content = await apiTemplateRender('kanji.html', params); this.container.html(content); - this.entryScrollIntoView(context && context.index || 0); + const {index, scroll} = context || {}; + this.entryScrollIntoView(index || 0, scroll); $('.action-add-note').click(this.onNoteAdd.bind(this)); $('.action-view-note').click(this.onNoteView.bind(this)); @@ -383,7 +387,7 @@ class Display { } } - entryScrollIntoView(index, smooth) { + entryScrollIntoView(index, scroll, smooth) { index = Math.min(index, this.definitions.length - 1); index = Math.max(index, 0); @@ -391,7 +395,13 @@ class Display { const container = $('html,body').stop(); const entry = $('.entry').eq(index); - const target = index === 0 ? 0 : entry.offset().top; + let target; + + if (scroll) { + target = scroll; + } else { + target = index === 0 ? 0 : entry.offset().top; + } if (smooth) { container.animate({scrollTop: target}, 200); @@ -408,6 +418,7 @@ class Display { url: this.context.source.url, sentence: this.context.source.sentence, index: this.context.source.index, + scroll: this.context.source.scroll, source: this.context.source.source }; From 3b07a9000cbf715098b6e368c39ee9175cd5f04f Mon Sep 17 00:00:00 2001 From: siikamiika Date: Sat, 3 Aug 2019 19:54:01 +0300 Subject: [PATCH 11/11] add source term button to terms --- ext/bg/js/templates.js | 117 ++++++++++++++++++++-------------------- ext/mixed/js/display.js | 2 + tmpl/terms.html | 5 +- 3 files changed, 66 insertions(+), 58 deletions(-) diff --git a/ext/bg/js/templates.js b/ext/bg/js/templates.js index 43acd28d..e12d1bf3 100644 --- a/ext/bg/js/templates.js +++ b/ext/bg/js/templates.js @@ -289,16 +289,17 @@ templates['terms.html'] = template({"1":function(container,depth0,helpers,partia return "
\n
\n" + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.addable : depth0),{"name":"if","hash":{},"fn":container.program(23, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "") + ((stack1 = helpers.unless.call(alias1,(depth0 != null ? depth0.merged : depth0),{"name":"unless","hash":{},"fn":container.program(25, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.source : depth0),{"name":"if","hash":{},"fn":container.program(28, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "") + " \n
\n\n" - + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.merged : depth0),{"name":"if","hash":{},"fn":container.program(28, data, 0, blockParams, depths),"inverse":container.program(43, data, 0, blockParams, depths),"data":data})) != null ? stack1 : "") + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.merged : depth0),{"name":"if","hash":{},"fn":container.program(30, data, 0, blockParams, depths),"inverse":container.program(45, data, 0, blockParams, depths),"data":data})) != null ? stack1 : "") + "\n" - + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.reasons : depth0),{"name":"if","hash":{},"fn":container.program(47, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.reasons : depth0),{"name":"if","hash":{},"fn":container.program(49, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "") + "\n" - + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.frequencies : depth0),{"name":"if","hash":{},"fn":container.program(51, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.frequencies : depth0),{"name":"if","hash":{},"fn":container.program(53, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "") + "\n
\n" - + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.grouped : depth0),{"name":"if","hash":{},"fn":container.program(54, data, 0, blockParams, depths),"inverse":container.program(60, data, 0, blockParams, depths),"data":data})) != null ? stack1 : "") + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.grouped : depth0),{"name":"if","hash":{},"fn":container.program(56, data, 0, blockParams, depths),"inverse":container.program(62, data, 0, blockParams, depths),"data":data})) != null ? stack1 : "") + "
\n\n" - + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.debug : depth0),{"name":"if","hash":{},"fn":container.program(63, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.debug : depth0),{"name":"if","hash":{},"fn":container.program(65, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "") + "
\n"; },"23":function(container,depth0,helpers,partials,data) { return " \n \n \n"; @@ -308,45 +309,47 @@ templates['terms.html'] = template({"1":function(container,depth0,helpers,partia return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.playback : depth0),{"name":"if","hash":{},"fn":container.program(26, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : ""); },"26":function(container,depth0,helpers,partials,data) { return " \n"; -},"28":function(container,depth0,helpers,partials,data,blockParams,depths) { +},"28":function(container,depth0,helpers,partials,data) { + return " \n"; +},"30":function(container,depth0,helpers,partials,data,blockParams,depths) { var stack1; - return ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.expressions : depth0),{"name":"each","hash":{},"fn":container.program(29, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : ""); -},"29":function(container,depth0,helpers,partials,data,blockParams,depths) { + return ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.expressions : depth0),{"name":"each","hash":{},"fn":container.program(31, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : ""); +},"31":function(container,depth0,helpers,partials,data,blockParams,depths) { var stack1, helper, options, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", buffer = "
"; - stack1 = ((helper = (helper = helpers.kanjiLinks || (depth0 != null ? depth0.kanjiLinks : depth0)) != null ? helper : alias2),(options={"name":"kanjiLinks","hash":{},"fn":container.program(30, data, 0, blockParams, depths),"inverse":container.noop,"data":data}),(typeof helper === alias3 ? helper.call(alias1,options) : helper)); + stack1 = ((helper = (helper = helpers.kanjiLinks || (depth0 != null ? depth0.kanjiLinks : depth0)) != null ? helper : alias2),(options={"name":"kanjiLinks","hash":{},"fn":container.program(32, data, 0, blockParams, depths),"inverse":container.noop,"data":data}),(typeof helper === alias3 ? helper.call(alias1,options) : helper)); if (!helpers.kanjiLinks) { stack1 = helpers.blockHelperMissing.call(depth0,stack1,options)} if (stack1 != null) { buffer += stack1; } return buffer + "
" - + ((stack1 = helpers["if"].call(alias1,(depths[1] != null ? depths[1].playback : depths[1]),{"name":"if","hash":{},"fn":container.program(33, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "") - + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.termTags : depth0),{"name":"if","hash":{},"fn":container.program(35, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "") - + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.frequencies : depth0),{"name":"if","hash":{},"fn":container.program(38, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers["if"].call(alias1,(depths[1] != null ? depths[1].playback : depths[1]),{"name":"if","hash":{},"fn":container.program(35, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.termTags : depth0),{"name":"if","hash":{},"fn":container.program(37, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.frequencies : depth0),{"name":"if","hash":{},"fn":container.program(40, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "") + "
"; -},"30":function(container,depth0,helpers,partials,data) { +},"32":function(container,depth0,helpers,partials,data) { var stack1, helper, options; - stack1 = ((helper = (helper = helpers.furigana || (depth0 != null ? depth0.furigana : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"furigana","hash":{},"fn":container.program(31, data, 0),"inverse":container.noop,"data":data}),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),options) : helper)); + stack1 = ((helper = (helper = helpers.furigana || (depth0 != null ? depth0.furigana : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"furigana","hash":{},"fn":container.program(33, data, 0),"inverse":container.noop,"data":data}),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),options) : helper)); if (!helpers.furigana) { stack1 = helpers.blockHelperMissing.call(depth0,stack1,options)} if (stack1 != null) { return stack1; } else { return ''; } -},"31":function(container,depth0,helpers,partials,data) { +},"33":function(container,depth0,helpers,partials,data) { var stack1; return ((stack1 = container.lambda(depth0, depth0)) != null ? stack1 : ""); -},"33":function(container,depth0,helpers,partials,data) { - return ""; },"35":function(container,depth0,helpers,partials,data) { + return ""; +},"37":function(container,depth0,helpers,partials,data) { var stack1; return "
" - + ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.termTags : depth0),{"name":"each","hash":{},"fn":container.program(36, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.termTags : depth0),{"name":"each","hash":{},"fn":container.program(38, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + "
"; -},"36":function(container,depth0,helpers,partials,data) { +},"38":function(container,depth0,helpers,partials,data) { var helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression; return " " + alias4(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"name","hash":{},"data":data}) : helper))) + "\n"; -},"38":function(container,depth0,helpers,partials,data) { +},"40":function(container,depth0,helpers,partials,data) { var stack1; return "
" - + ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.frequencies : depth0),{"name":"each","hash":{},"fn":container.program(39, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.frequencies : depth0),{"name":"each","hash":{},"fn":container.program(41, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + "
"; -},"39":function(container,depth0,helpers,partials,data) { +},"41":function(container,depth0,helpers,partials,data) { var helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression; return " " @@ -370,23 +373,23 @@ templates['terms.html'] = template({"1":function(container,depth0,helpers,partia + ":" + alias4(((helper = (helper = helpers.frequency || (depth0 != null ? depth0.frequency : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"frequency","hash":{},"data":data}) : helper))) + "\n"; -},"41":function(container,depth0,helpers,partials,data) { - return "invisible"; },"43":function(container,depth0,helpers,partials,data) { + return "invisible"; +},"45":function(container,depth0,helpers,partials,data) { var stack1, helper, options, alias1=depth0 != null ? depth0 : (container.nullContext || {}), buffer = "
"; - stack1 = ((helper = (helper = helpers.kanjiLinks || (depth0 != null ? depth0.kanjiLinks : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"kanjiLinks","hash":{},"fn":container.program(30, data, 0),"inverse":container.noop,"data":data}),(typeof helper === "function" ? helper.call(alias1,options) : helper)); + stack1 = ((helper = (helper = helpers.kanjiLinks || (depth0 != null ? depth0.kanjiLinks : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"kanjiLinks","hash":{},"fn":container.program(32, data, 0),"inverse":container.noop,"data":data}),(typeof helper === "function" ? helper.call(alias1,options) : helper)); if (!helpers.kanjiLinks) { stack1 = helpers.blockHelperMissing.call(depth0,stack1,options)} if (stack1 != null) { buffer += stack1; } return buffer + "
\n" - + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.termTags : depth0),{"name":"if","hash":{},"fn":container.program(44, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : ""); -},"44":function(container,depth0,helpers,partials,data) { + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.termTags : depth0),{"name":"if","hash":{},"fn":container.program(46, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : ""); +},"46":function(container,depth0,helpers,partials,data) { var stack1; return "
\n" - + ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.termTags : depth0),{"name":"each","hash":{},"fn":container.program(45, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.termTags : depth0),{"name":"each","hash":{},"fn":container.program(47, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + "
\n"; -},"45":function(container,depth0,helpers,partials,data) { +},"47":function(container,depth0,helpers,partials,data) { var helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression; return " " + alias4(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"name","hash":{},"data":data}) : helper))) + "\n"; -},"47":function(container,depth0,helpers,partials,data) { +},"49":function(container,depth0,helpers,partials,data) { var stack1; return "
\n" - + ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.reasons : depth0),{"name":"each","hash":{},"fn":container.program(48, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.reasons : depth0),{"name":"each","hash":{},"fn":container.program(50, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + "
\n"; -},"48":function(container,depth0,helpers,partials,data) { +},"50":function(container,depth0,helpers,partials,data) { var stack1; return " " + container.escapeExpression(container.lambda(depth0, depth0)) + " " - + ((stack1 = helpers.unless.call(depth0 != null ? depth0 : (container.nullContext || {}),(data && data.last),{"name":"unless","hash":{},"fn":container.program(49, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers.unless.call(depth0 != null ? depth0 : (container.nullContext || {}),(data && data.last),{"name":"unless","hash":{},"fn":container.program(51, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + "\n"; -},"49":function(container,depth0,helpers,partials,data) { - return "«"; },"51":function(container,depth0,helpers,partials,data) { + return "«"; +},"53":function(container,depth0,helpers,partials,data) { var stack1; return "
\n" - + ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.frequencies : depth0),{"name":"each","hash":{},"fn":container.program(52, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.frequencies : depth0),{"name":"each","hash":{},"fn":container.program(54, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + "
\n"; -},"52":function(container,depth0,helpers,partials,data) { +},"54":function(container,depth0,helpers,partials,data) { var helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression; return " " @@ -426,61 +429,61 @@ templates['terms.html'] = template({"1":function(container,depth0,helpers,partia + ":" + alias4(((helper = (helper = helpers.frequency || (depth0 != null ? depth0.frequency : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"frequency","hash":{},"data":data}) : helper))) + "\n"; -},"54":function(container,depth0,helpers,partials,data,blockParams,depths) { +},"56":function(container,depth0,helpers,partials,data,blockParams,depths) { var stack1; - return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.definitions : depth0)) != null ? stack1["1"] : stack1),{"name":"if","hash":{},"fn":container.program(55, data, 0, blockParams, depths),"inverse":container.program(58, data, 0, blockParams, depths),"data":data})) != null ? stack1 : ""); -},"55":function(container,depth0,helpers,partials,data,blockParams,depths) { + return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.definitions : depth0)) != null ? stack1["1"] : stack1),{"name":"if","hash":{},"fn":container.program(57, data, 0, blockParams, depths),"inverse":container.program(60, data, 0, blockParams, depths),"data":data})) != null ? stack1 : ""); +},"57":function(container,depth0,helpers,partials,data,blockParams,depths) { var stack1; return "
    \n" - + ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.definitions : depth0),{"name":"each","hash":{},"fn":container.program(56, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.definitions : depth0),{"name":"each","hash":{},"fn":container.program(58, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "") + "
\n"; -},"56":function(container,depth0,helpers,partials,data,blockParams,depths) { +},"58":function(container,depth0,helpers,partials,data,blockParams,depths) { var stack1; return "
  • " + ((stack1 = container.invokePartial(partials.definition,depth0,{"name":"definition","hash":{"compactGlossaries":(depths[1] != null ? depths[1].compactGlossaries : depths[1])},"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "") + "
  • \n"; -},"58":function(container,depth0,helpers,partials,data) { +},"60":function(container,depth0,helpers,partials,data) { var stack1; return ((stack1 = container.invokePartial(partials.definition,((stack1 = (depth0 != null ? depth0.definitions : depth0)) != null ? stack1["0"] : stack1),{"name":"definition","hash":{"compactGlossaries":(depth0 != null ? depth0.compactGlossaries : depth0)},"data":data,"indent":" ","helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : ""); -},"60":function(container,depth0,helpers,partials,data,blockParams,depths) { +},"62":function(container,depth0,helpers,partials,data,blockParams,depths) { var stack1; - return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.merged : depth0),{"name":"if","hash":{},"fn":container.program(54, data, 0, blockParams, depths),"inverse":container.program(61, data, 0, blockParams, depths),"data":data})) != null ? stack1 : ""); -},"61":function(container,depth0,helpers,partials,data) { + return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.merged : depth0),{"name":"if","hash":{},"fn":container.program(56, data, 0, blockParams, depths),"inverse":container.program(63, data, 0, blockParams, depths),"data":data})) != null ? stack1 : ""); +},"63":function(container,depth0,helpers,partials,data) { var stack1; return ((stack1 = container.invokePartial(partials.definition,depth0,{"name":"definition","hash":{"compactGlossaries":(depth0 != null ? depth0.compactGlossaries : depth0)},"data":data,"indent":" ","helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "") + " "; -},"63":function(container,depth0,helpers,partials,data) { +},"65":function(container,depth0,helpers,partials,data) { var stack1, helper, options, buffer = "
    ";
    -  stack1 = ((helper = (helper = helpers.dumpObject || (depth0 != null ? depth0.dumpObject : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"dumpObject","hash":{},"fn":container.program(31, data, 0),"inverse":container.noop,"data":data}),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),options) : helper));
    +  stack1 = ((helper = (helper = helpers.dumpObject || (depth0 != null ? depth0.dumpObject : depth0)) != null ? helper : helpers.helperMissing),(options={"name":"dumpObject","hash":{},"fn":container.program(33, data, 0),"inverse":container.noop,"data":data}),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),options) : helper));
       if (!helpers.dumpObject) { stack1 = helpers.blockHelperMissing.call(depth0,stack1,options)}
       if (stack1 != null) { buffer += stack1; }
       return buffer + "
    \n"; -},"65":function(container,depth0,helpers,partials,data,blockParams,depths) { +},"67":function(container,depth0,helpers,partials,data,blockParams,depths) { var stack1; - return ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.definitions : depth0),{"name":"each","hash":{},"fn":container.program(66, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : ""); -},"66":function(container,depth0,helpers,partials,data,blockParams,depths) { + return ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.definitions : depth0),{"name":"each","hash":{},"fn":container.program(68, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : ""); +},"68":function(container,depth0,helpers,partials,data,blockParams,depths) { var stack1; - return ((stack1 = helpers.unless.call(depth0 != null ? depth0 : (container.nullContext || {}),(data && data.first),{"name":"unless","hash":{},"fn":container.program(67, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "") + return ((stack1 = helpers.unless.call(depth0 != null ? depth0 : (container.nullContext || {}),(data && data.first),{"name":"unless","hash":{},"fn":container.program(69, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "") + "\n" - + ((stack1 = container.invokePartial(partials.term,depth0,{"name":"term","hash":{"compactGlossaries":(depths[1] != null ? depths[1].compactGlossaries : depths[1]),"playback":(depths[1] != null ? depths[1].playback : depths[1]),"addable":(depths[1] != null ? depths[1].addable : depths[1]),"merged":(depths[1] != null ? depths[1].merged : depths[1]),"grouped":(depths[1] != null ? depths[1].grouped : depths[1]),"debug":(depths[1] != null ? depths[1].debug : depths[1])},"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : ""); -},"67":function(container,depth0,helpers,partials,data) { - return "
    "; + + ((stack1 = container.invokePartial(partials.term,depth0,{"name":"term","hash":{"source":(depths[1] != null ? depths[1].source : depths[1]),"compactGlossaries":(depths[1] != null ? depths[1].compactGlossaries : depths[1]),"playback":(depths[1] != null ? depths[1].playback : depths[1]),"addable":(depths[1] != null ? depths[1].addable : depths[1]),"merged":(depths[1] != null ? depths[1].merged : depths[1]),"grouped":(depths[1] != null ? depths[1].grouped : depths[1]),"debug":(depths[1] != null ? depths[1].debug : depths[1])},"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : ""); },"69":function(container,depth0,helpers,partials,data) { + return "
    "; +},"71":function(container,depth0,helpers,partials,data) { return "

    No results found.

    \n"; },"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data,blockParams,depths) { var stack1; return "\n\n" - + ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.definitions : depth0),{"name":"if","hash":{},"fn":container.program(65, data, 0, blockParams, depths),"inverse":container.program(69, data, 0, blockParams, depths),"data":data})) != null ? stack1 : ""); + + ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.definitions : depth0),{"name":"if","hash":{},"fn":container.program(67, data, 0, blockParams, depths),"inverse":container.program(71, data, 0, blockParams, depths),"data":data})) != null ? stack1 : ""); },"main_d": function(fn, props, container, depth0, data, blockParams, depths) { var decorators = container.decorators; diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index 650372d3..3bb78fe1 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -278,6 +278,7 @@ class Display { const sequence = ++this.sequence; const params = { definitions, + source: context && context.source, addable: options.anki.enable, grouped: options.general.resultOutputMode === 'group', merged: options.general.resultOutputMode === 'merge', @@ -309,6 +310,7 @@ class Display { $('.action-view-note').click(this.onNoteView.bind(this)); $('.action-play-audio').click(this.onAudioPlay.bind(this)); $('.kanji-link').click(this.onKanjiLookup.bind(this)); + $('.source-term').click(this.onSourceTermView.bind(this)); $('.glossary-item').click(this.onTermLookup.bind(this)); await this.adderButtonUpdate(['term-kanji', 'term-kana'], sequence); diff --git a/tmpl/terms.html b/tmpl/terms.html index e01fc8d5..b9e5e0ad 100644 --- a/tmpl/terms.html +++ b/tmpl/terms.html @@ -39,6 +39,9 @@ {{/if}} {{/unless}} + {{#if source}} + + {{/if}} @@ -126,7 +129,7 @@ {{#if definitions}} {{#each definitions}} {{#unless @first}}
    {{/unless}} -{{> term debug=../debug grouped=../grouped merged=../merged addable=../addable playback=../playback compactGlossaries=../compactGlossaries}} +{{> term debug=../debug grouped=../grouped merged=../merged addable=../addable playback=../playback compactGlossaries=../compactGlossaries source=../source}} {{/each}} {{else}}

    No results found.