add kana to text
This commit is contained in:
parent
f63e8e4be0
commit
c35a05cd62
@ -79,6 +79,43 @@ async function apiTermsFind(text, details, optionsContext) {
|
|||||||
return {length, definitions};
|
return {length, definitions};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function apiTextParse(text, optionsContext) {
|
||||||
|
const options = await apiOptionsGet(optionsContext);
|
||||||
|
const translator = utilBackend().translator;
|
||||||
|
|
||||||
|
const results = [];
|
||||||
|
while (text) {
|
||||||
|
let [definitions, length] = await translator.findTerms(text, {}, options);
|
||||||
|
if (definitions.length > 0) {
|
||||||
|
definitions = dictTermsSort(definitions);
|
||||||
|
const {expression, source, reading} = definitions[0];
|
||||||
|
|
||||||
|
let stemLength = source.length;
|
||||||
|
while (source[stemLength - 1] !== expression[stemLength - 1]) {
|
||||||
|
--stemLength;
|
||||||
|
}
|
||||||
|
const offset = source.length - stemLength;
|
||||||
|
|
||||||
|
for (const result of jpDistributeFurigana(
|
||||||
|
source.slice(0, offset === 0 ? source.length : source.length - offset),
|
||||||
|
reading.slice(0, offset === 0 ? reading.length : source.length + (reading.length - expression.length) - offset)
|
||||||
|
)) {
|
||||||
|
results.push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stemLength !== source.length) {
|
||||||
|
results.push({text: source.slice(stemLength)});
|
||||||
|
}
|
||||||
|
|
||||||
|
text = text.slice(source.length);
|
||||||
|
} else {
|
||||||
|
results.push({text: text[0]});
|
||||||
|
text = text.slice(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
async function apiKanjiFind(text, optionsContext) {
|
async function apiKanjiFind(text, optionsContext) {
|
||||||
const options = await apiOptionsGet(optionsContext);
|
const options = await apiOptionsGet(optionsContext);
|
||||||
const definitions = await utilBackend().translator.findKanji(text, options);
|
const definitions = await utilBackend().translator.findKanji(text, options);
|
||||||
|
@ -180,6 +180,7 @@ Backend.messageHandlers = {
|
|||||||
optionsSet: ({changedOptions, optionsContext, source}) => apiOptionsSet(changedOptions, optionsContext, source),
|
optionsSet: ({changedOptions, optionsContext, source}) => apiOptionsSet(changedOptions, optionsContext, source),
|
||||||
kanjiFind: ({text, optionsContext}) => apiKanjiFind(text, optionsContext),
|
kanjiFind: ({text, optionsContext}) => apiKanjiFind(text, optionsContext),
|
||||||
termsFind: ({text, details, optionsContext}) => apiTermsFind(text, details, optionsContext),
|
termsFind: ({text, details, optionsContext}) => apiTermsFind(text, details, optionsContext),
|
||||||
|
textParse: ({text, optionsContext}) => apiTextParse(text, optionsContext),
|
||||||
definitionAdd: ({definition, mode, context, optionsContext}) => apiDefinitionAdd(definition, mode, context, optionsContext),
|
definitionAdd: ({definition, mode, context, optionsContext}) => apiDefinitionAdd(definition, mode, context, optionsContext),
|
||||||
definitionsAddable: ({definitions, modes, optionsContext}) => apiDefinitionsAddable(definitions, modes, optionsContext),
|
definitionsAddable: ({definitions, modes, optionsContext}) => apiDefinitionsAddable(definitions, modes, optionsContext),
|
||||||
noteView: ({noteId}) => apiNoteView(noteId),
|
noteView: ({noteId}) => apiNoteView(noteId),
|
||||||
|
@ -23,22 +23,103 @@ class QueryParser {
|
|||||||
|
|
||||||
this.queryParser = document.querySelector('#query-parser');
|
this.queryParser = document.querySelector('#query-parser');
|
||||||
|
|
||||||
// TODO also enable for mouseover scanning
|
this.queryParser.addEventListener('click', (e) => this.onClick(e));
|
||||||
this.queryParser.addEventListener('click', (e) => this.onTermLookup(e));
|
this.queryParser.addEventListener('mousemove', (e) => this.onMouseMove(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
onError(error) {
|
onError(error) {
|
||||||
logError(error, false);
|
logError(error, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
async onTermLookup(e) {
|
onClick(e) {
|
||||||
const {textSource} = await this.search.onTermLookup(e, {isQueryParser: true});
|
this.onTermLookup(e, {disableScroll: true, selectText: true});
|
||||||
if (textSource) {
|
}
|
||||||
textSource.select();
|
|
||||||
|
async onMouseMove(e) {
|
||||||
|
if (
|
||||||
|
(e.buttons & 0x1) !== 0x0 // Left mouse button
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const scanningOptions = this.search.options.scanning;
|
||||||
|
const scanningModifier = scanningOptions.modifier;
|
||||||
|
if (!(
|
||||||
|
QueryParser.isScanningModifierPressed(scanningModifier, e) ||
|
||||||
|
(scanningOptions.middleMouse && (e.buttons & 0x4) !== 0x0) // Middle mouse button
|
||||||
|
)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.onTermLookup(e, {disableScroll: true, selectText: true, disableHistory: true})
|
||||||
|
}
|
||||||
|
|
||||||
|
onTermLookup(e, params) {
|
||||||
|
this.search.onTermLookup(e, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
async setText(text) {
|
||||||
|
this.search.setSpinnerVisible(true);
|
||||||
|
|
||||||
|
const results = await apiTextParse(text, this.search.getOptionsContext());
|
||||||
|
|
||||||
|
const tempContainer = document.createElement('div');
|
||||||
|
for (const {text, furigana} of results) {
|
||||||
|
if (furigana) {
|
||||||
|
const rubyElement = document.createElement('ruby');
|
||||||
|
const furiganaElement = document.createElement('rt');
|
||||||
|
furiganaElement.innerText = furigana;
|
||||||
|
rubyElement.appendChild(document.createTextNode(text));
|
||||||
|
rubyElement.appendChild(furiganaElement);
|
||||||
|
tempContainer.appendChild(rubyElement);
|
||||||
|
} else {
|
||||||
|
tempContainer.appendChild(document.createTextNode(text));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.queryParser.innerHTML = '';
|
||||||
|
this.queryParser.appendChild(tempContainer);
|
||||||
|
|
||||||
|
this.search.setSpinnerVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
async parseText(text) {
|
||||||
|
const results = [];
|
||||||
|
while (text) {
|
||||||
|
const {definitions, length} = await apiTermsFind(text, {}, this.search.getOptionsContext());
|
||||||
|
if (length) {
|
||||||
|
results.push(definitions);
|
||||||
|
text = text.slice(length);
|
||||||
|
} else {
|
||||||
|
results.push(text[0]);
|
||||||
|
text = text.slice(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
popupTimerSet(callback) {
|
||||||
|
const delay = this.options.scanning.delay;
|
||||||
|
if (delay > 0) {
|
||||||
|
this.popupTimer = window.setTimeout(callback, delay);
|
||||||
|
} else {
|
||||||
|
Promise.resolve().then(callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setText(text) {
|
popupTimerClear() {
|
||||||
this.queryParser.innerText = text;
|
if (this.popupTimer !== null) {
|
||||||
|
window.clearTimeout(this.popupTimer);
|
||||||
|
this.popupTimer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static isScanningModifierPressed(scanningModifier, mouseEvent) {
|
||||||
|
switch (scanningModifier) {
|
||||||
|
case 'alt': return mouseEvent.altKey;
|
||||||
|
case 'ctrl': return mouseEvent.ctrlKey;
|
||||||
|
case 'shift': return mouseEvent.shiftKey;
|
||||||
|
case 'none': return true;
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,10 @@ function apiTermsFind(text, details, optionsContext) {
|
|||||||
return utilInvoke('termsFind', {text, details, optionsContext});
|
return utilInvoke('termsFind', {text, details, optionsContext});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function apiTextParse(text, optionsContext) {
|
||||||
|
return utilInvoke('textParse', {text, optionsContext});
|
||||||
|
}
|
||||||
|
|
||||||
function apiKanjiFind(text, optionsContext) {
|
function apiKanjiFind(text, optionsContext) {
|
||||||
return utilInvoke('kanjiFind', {text, optionsContext});
|
return utilInvoke('kanjiFind', {text, optionsContext});
|
||||||
}
|
}
|
||||||
|
@ -73,6 +73,10 @@ ol, ul {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
html:root[data-yomichan-page=search] body {
|
||||||
|
min-height: 101vh; /* always show scroll bar to avoid scanning problems */
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Search page
|
* Search page
|
||||||
*/
|
*/
|
||||||
|
@ -98,17 +98,62 @@ class Display {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async onTermLookup(e) {
|
async onTermLookup(e, {disableScroll, selectText, disableHistory}) {
|
||||||
|
const termLookupResults = await this.termLookup(e);
|
||||||
|
if (!termLookupResults) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const {textSource, definitions} = termLookupResults;
|
||||||
|
|
||||||
|
const scannedElement = e.target;
|
||||||
|
const sentence = docSentenceExtract(textSource, this.options.anki.sentenceExt);
|
||||||
|
|
||||||
|
if (!disableScroll) {
|
||||||
|
this.windowScroll.toY(0);
|
||||||
|
}
|
||||||
|
let context;
|
||||||
|
if (disableHistory) {
|
||||||
|
const {url, source} = this.context || {};
|
||||||
|
context = {sentence, url, source, disableScroll};
|
||||||
|
} else {
|
||||||
|
context = {
|
||||||
|
disableScroll,
|
||||||
|
source: {
|
||||||
|
definitions: this.definitions,
|
||||||
|
index: this.entryIndexFind(scannedElement),
|
||||||
|
scroll: this.windowScroll.y
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (this.context) {
|
||||||
|
context.sentence = sentence;
|
||||||
|
context.url = this.context.url;
|
||||||
|
context.source.source = this.context.source;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setContentTerms(definitions, context);
|
||||||
|
|
||||||
|
if (selectText) {
|
||||||
|
textSource.select();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.onError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async termLookup(e) {
|
||||||
try {
|
try {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
const clickedElement = e.target;
|
|
||||||
const textSource = docRangeFromPoint(e.clientX, e.clientY, this.options);
|
const textSource = docRangeFromPoint(e.clientX, e.clientY, this.options);
|
||||||
if (textSource === null) {
|
if (textSource === null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let definitions, length, sentence;
|
let definitions, length;
|
||||||
try {
|
try {
|
||||||
textSource.setEndOffset(this.options.scanning.length);
|
textSource.setEndOffset(this.options.scanning.length);
|
||||||
|
|
||||||
@ -118,30 +163,11 @@ class Display {
|
|||||||
}
|
}
|
||||||
|
|
||||||
textSource.setEndOffset(length);
|
textSource.setEndOffset(length);
|
||||||
|
|
||||||
sentence = docSentenceExtract(textSource, this.options.anki.sentenceExt);
|
|
||||||
} finally {
|
} finally {
|
||||||
textSource.cleanup();
|
textSource.cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.windowScroll.toY(0);
|
return {textSource, definitions};
|
||||||
const context = {
|
|
||||||
source: {
|
|
||||||
definitions: this.definitions,
|
|
||||||
index: this.entryIndexFind(clickedElement),
|
|
||||||
scroll: this.windowScroll.y
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (this.context) {
|
|
||||||
context.sentence = sentence;
|
|
||||||
context.url = this.context.url;
|
|
||||||
context.source.source = this.context.source;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setContentTerms(definitions, context);
|
|
||||||
|
|
||||||
return {textSource};
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.onError(error);
|
this.onError(error);
|
||||||
}
|
}
|
||||||
@ -338,8 +364,10 @@ class Display {
|
|||||||
|
|
||||||
const content = await apiTemplateRender('terms.html', params);
|
const content = await apiTemplateRender('terms.html', params);
|
||||||
this.container.innerHTML = content;
|
this.container.innerHTML = content;
|
||||||
const {index, scroll} = context || {};
|
const {index, scroll, disableScroll} = context || {};
|
||||||
this.entryScrollIntoView(index || 0, scroll);
|
if (!disableScroll) {
|
||||||
|
this.entryScrollIntoView(index || 0, scroll);
|
||||||
|
}
|
||||||
|
|
||||||
if (options.audio.enabled && options.audio.autoPlay) {
|
if (options.audio.enabled && options.audio.autoPlay) {
|
||||||
this.autoPlayAudio();
|
this.autoPlayAudio();
|
||||||
|
Loading…
Reference in New Issue
Block a user