Search query offset value (#1968)
* Add type property to TextSource* classes * Use type property rather than instanceof * Expose a sentence offset value * Use offset added to URL * Improve fallback sentence for Anki note context
This commit is contained in:
parent
b784e5b11a
commit
b0f6c41f5d
@ -18,7 +18,6 @@
|
|||||||
/* global
|
/* global
|
||||||
* DocumentUtil
|
* DocumentUtil
|
||||||
* TextScanner
|
* TextScanner
|
||||||
* TextSourceElement
|
|
||||||
* TextSourceRange
|
* TextSourceRange
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -536,7 +535,7 @@ class Frontend {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (textSource instanceof TextSourceElement && textSource.fullContent !== query) {
|
if (textSource.type === 'element' && textSource.fullContent !== query) {
|
||||||
details.params.full = textSource.fullContent;
|
details.params.full = textSource.fullContent;
|
||||||
details.params['full-visible'] = 'true';
|
details.params['full-visible'] = 'true';
|
||||||
}
|
}
|
||||||
|
@ -216,8 +216,8 @@ class DisplayAnki {
|
|||||||
if (typeof url !== 'string') {
|
if (typeof url !== 'string') {
|
||||||
url = window.location.href;
|
url = window.location.href;
|
||||||
}
|
}
|
||||||
const {query, fullQuery} = this._display;
|
const {query, fullQuery, queryOffset} = this._display;
|
||||||
sentence = this._getValidSentenceData(sentence, query);
|
sentence = this._getValidSentenceData(sentence, fullQuery, queryOffset);
|
||||||
return {
|
return {
|
||||||
url,
|
url,
|
||||||
sentence,
|
sentence,
|
||||||
@ -565,11 +565,11 @@ class DisplayAnki {
|
|||||||
return isTerms ? ['term-kanji', 'term-kana'] : ['kanji'];
|
return isTerms ? ['term-kanji', 'term-kana'] : ['kanji'];
|
||||||
}
|
}
|
||||||
|
|
||||||
_getValidSentenceData(sentence, fallback) {
|
_getValidSentenceData(sentence, fallback, fallbackOffset) {
|
||||||
let {text, offset} = (isObject(sentence) ? sentence : {});
|
let {text, offset} = (isObject(sentence) ? sentence : {});
|
||||||
if (typeof text !== 'string') {
|
if (typeof text !== 'string') {
|
||||||
text = fallback;
|
text = fallback;
|
||||||
offset = 0;
|
offset = fallbackOffset;
|
||||||
} else {
|
} else {
|
||||||
if (typeof offset !== 'number') { offset = 0; }
|
if (typeof offset !== 'number') { offset = 0; }
|
||||||
}
|
}
|
||||||
|
@ -73,6 +73,7 @@ class Display extends EventDispatcher {
|
|||||||
this._titleMaxLength = 1000;
|
this._titleMaxLength = 1000;
|
||||||
this._query = '';
|
this._query = '';
|
||||||
this._fullQuery = '';
|
this._fullQuery = '';
|
||||||
|
this._queryOffset = 0;
|
||||||
this._documentUtil = new DocumentUtil();
|
this._documentUtil = new DocumentUtil();
|
||||||
this._progressIndicator = document.querySelector('#progress-indicator');
|
this._progressIndicator = document.querySelector('#progress-indicator');
|
||||||
this._progressIndicatorTimer = null;
|
this._progressIndicatorTimer = null;
|
||||||
@ -208,6 +209,10 @@ class Display extends EventDispatcher {
|
|||||||
return this._fullQuery;
|
return this._fullQuery;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get queryOffset() {
|
||||||
|
return this._queryOffset;
|
||||||
|
}
|
||||||
|
|
||||||
get frameVisible() {
|
get frameVisible() {
|
||||||
return this._frameVisible;
|
return this._frameVisible;
|
||||||
}
|
}
|
||||||
@ -432,7 +437,7 @@ class Display extends EventDispatcher {
|
|||||||
const details = {
|
const details = {
|
||||||
focus: false,
|
focus: false,
|
||||||
historyMode: 'clear',
|
historyMode: 'clear',
|
||||||
params: this._createSearchParams(type, query, false),
|
params: this._createSearchParams(type, query, false, this._queryOffset),
|
||||||
state,
|
state,
|
||||||
content: {
|
content: {
|
||||||
dictionaryEntries: null,
|
dictionaryEntries: null,
|
||||||
@ -598,9 +603,14 @@ class Display extends EventDispatcher {
|
|||||||
const isTerms = (type === 'terms');
|
const isTerms = (type === 'terms');
|
||||||
let queryFull = urlSearchParams.get('full');
|
let queryFull = urlSearchParams.get('full');
|
||||||
queryFull = (queryFull !== null ? queryFull : query);
|
queryFull = (queryFull !== null ? queryFull : query);
|
||||||
|
let queryOffset = urlSearchParams.get('offset');
|
||||||
|
if (queryOffset !== null) {
|
||||||
|
queryOffset = Number.parseInt(queryOffset, 10);
|
||||||
|
if (!Number.isFinite(queryOffset)) { queryOffset = null; }
|
||||||
|
}
|
||||||
const wildcardsEnabled = (urlSearchParams.get('wildcards') !== 'off');
|
const wildcardsEnabled = (urlSearchParams.get('wildcards') !== 'off');
|
||||||
const lookup = (urlSearchParams.get('lookup') !== 'false');
|
const lookup = (urlSearchParams.get('lookup') !== 'false');
|
||||||
await this._setContentTermsOrKanji(token, isTerms, query, queryFull, lookup, wildcardsEnabled, eventArgs);
|
await this._setContentTermsOrKanji(token, isTerms, query, queryFull, queryOffset, lookup, wildcardsEnabled, eventArgs);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'unloaded':
|
case 'unloaded':
|
||||||
@ -633,7 +643,7 @@ class Display extends EventDispatcher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_onQueryParserSearch({type, dictionaryEntries, sentence, inputInfo: {eventType}, textSource, optionsContext}) {
|
_onQueryParserSearch({type, dictionaryEntries, sentence, inputInfo: {eventType}, textSource, optionsContext, sentenceOffset}) {
|
||||||
const query = textSource.text();
|
const query = textSource.text();
|
||||||
const historyState = this._history.state;
|
const historyState = this._history.state;
|
||||||
const historyMode = (
|
const historyMode = (
|
||||||
@ -644,7 +654,7 @@ class Display extends EventDispatcher {
|
|||||||
const details = {
|
const details = {
|
||||||
focus: false,
|
focus: false,
|
||||||
historyMode,
|
historyMode,
|
||||||
params: this._createSearchParams(type, query, false),
|
params: this._createSearchParams(type, query, false, sentenceOffset),
|
||||||
state: {
|
state: {
|
||||||
sentence,
|
sentence,
|
||||||
optionsContext,
|
optionsContext,
|
||||||
@ -724,7 +734,7 @@ class Display extends EventDispatcher {
|
|||||||
const details = {
|
const details = {
|
||||||
focus: false,
|
focus: false,
|
||||||
historyMode: 'new',
|
historyMode: 'new',
|
||||||
params: this._createSearchParams('kanji', query, false),
|
params: this._createSearchParams('kanji', query, false, null),
|
||||||
state: {
|
state: {
|
||||||
focusEntry: 0,
|
focusEntry: 0,
|
||||||
optionsContext,
|
optionsContext,
|
||||||
@ -887,7 +897,7 @@ class Display extends EventDispatcher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async _setContentTermsOrKanji(token, isTerms, query, queryFull, lookup, wildcardsEnabled, eventArgs) {
|
async _setContentTermsOrKanji(token, isTerms, query, queryFull, queryOffset, lookup, wildcardsEnabled, eventArgs) {
|
||||||
let {state, content} = this._history;
|
let {state, content} = this._history;
|
||||||
let changeHistory = false;
|
let changeHistory = false;
|
||||||
if (!isObject(content)) {
|
if (!isObject(content)) {
|
||||||
@ -912,7 +922,11 @@ class Display extends EventDispatcher {
|
|||||||
changeHistory = true;
|
changeHistory = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._setFullQuery(queryFull);
|
if (queryOffset !== null) {
|
||||||
|
queryOffset = Math.max(0, Math.min(queryFull.length - query.length, queryOffset));
|
||||||
|
}
|
||||||
|
|
||||||
|
this._setFullQuery(queryFull, queryOffset);
|
||||||
this._setTitleText(query);
|
this._setTitleText(query);
|
||||||
|
|
||||||
let {dictionaryEntries} = content;
|
let {dictionaryEntries} = content;
|
||||||
@ -1015,13 +1029,13 @@ class Display extends EventDispatcher {
|
|||||||
this._updateNavigation(false, false);
|
this._updateNavigation(false, false);
|
||||||
this._setNoContentVisible(false);
|
this._setNoContentVisible(false);
|
||||||
this._setTitleText('');
|
this._setTitleText('');
|
||||||
this._setFullQuery('');
|
this._setFullQuery('', 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
_clearContent() {
|
_clearContent() {
|
||||||
this._container.textContent = '';
|
this._container.textContent = '';
|
||||||
this._setTitleText('');
|
this._setTitleText('');
|
||||||
this._setFullQuery('');
|
this._setFullQuery('', 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
_setNoContentVisible(visible) {
|
_setNoContentVisible(visible) {
|
||||||
@ -1032,8 +1046,9 @@ class Display extends EventDispatcher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_setFullQuery(text) {
|
_setFullQuery(text, offset) {
|
||||||
this._fullQuery = text;
|
this._fullQuery = text;
|
||||||
|
this._queryOffset = offset;
|
||||||
this._updateQueryParser();
|
this._updateQueryParser();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1200,12 +1215,17 @@ class Display extends EventDispatcher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_createSearchParams(type, query, wildcards) {
|
_createSearchParams(type, query, wildcards, sentenceOffset) {
|
||||||
const params = {};
|
const params = {};
|
||||||
if (query.length < this._fullQuery.length) {
|
const fullQuery = this._fullQuery;
|
||||||
params.full = this._fullQuery;
|
const includeFull = (query.length < fullQuery.length);
|
||||||
|
if (includeFull) {
|
||||||
|
params.full = fullQuery;
|
||||||
}
|
}
|
||||||
params.query = query;
|
params.query = query;
|
||||||
|
if (includeFull && sentenceOffset !== null) {
|
||||||
|
params.offset = `${sentenceOffset}`;
|
||||||
|
}
|
||||||
if (typeof type === 'string') {
|
if (typeof type === 'string') {
|
||||||
params.type = type;
|
params.type = type;
|
||||||
}
|
}
|
||||||
|
@ -117,6 +117,8 @@ class QueryParser extends EventDispatcher {
|
|||||||
}
|
}
|
||||||
if (e.type === null) { return; }
|
if (e.type === null) { return; }
|
||||||
|
|
||||||
|
e.sentenceOffset = this._getSentenceOffset(e.textSource);
|
||||||
|
|
||||||
this.trigger('searched', e);
|
this.trigger('searched', e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,29 +210,33 @@ class QueryParser extends EventDispatcher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_createParseResult(data) {
|
_createParseResult(data) {
|
||||||
|
let offset = 0;
|
||||||
const fragment = document.createDocumentFragment();
|
const fragment = document.createDocumentFragment();
|
||||||
for (const term of data) {
|
for (const term of data) {
|
||||||
const termNode = document.createElement('span');
|
const termNode = document.createElement('span');
|
||||||
termNode.className = 'query-parser-term';
|
termNode.className = 'query-parser-term';
|
||||||
|
termNode.dataset.offset = `${offset}`;
|
||||||
for (const {text, reading} of term) {
|
for (const {text, reading} of term) {
|
||||||
if (reading.length === 0) {
|
if (reading.length === 0) {
|
||||||
termNode.appendChild(document.createTextNode(text));
|
termNode.appendChild(document.createTextNode(text));
|
||||||
} else {
|
} else {
|
||||||
const reading2 = this._convertReading(text, reading);
|
const reading2 = this._convertReading(text, reading);
|
||||||
termNode.appendChild(this._createSegment(text, reading2));
|
termNode.appendChild(this._createSegment(text, reading2, offset));
|
||||||
}
|
}
|
||||||
|
offset += text.length;
|
||||||
}
|
}
|
||||||
fragment.appendChild(termNode);
|
fragment.appendChild(termNode);
|
||||||
}
|
}
|
||||||
return fragment;
|
return fragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
_createSegment(text, reading) {
|
_createSegment(text, reading, offset) {
|
||||||
const segmentNode = document.createElement('ruby');
|
const segmentNode = document.createElement('ruby');
|
||||||
segmentNode.className = 'query-parser-segment';
|
segmentNode.className = 'query-parser-segment';
|
||||||
|
|
||||||
const textNode = document.createElement('span');
|
const textNode = document.createElement('span');
|
||||||
textNode.className = 'query-parser-segment-text';
|
textNode.className = 'query-parser-segment-text';
|
||||||
|
textNode.dataset.offset = `${offset}`;
|
||||||
|
|
||||||
const readingNode = document.createElement('rt');
|
const readingNode = document.createElement('rt');
|
||||||
readingNode.className = 'query-parser-segment-reading';
|
readingNode.className = 'query-parser-segment-reading';
|
||||||
@ -265,4 +271,30 @@ class QueryParser extends EventDispatcher {
|
|||||||
return reading;
|
return reading;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_getSentenceOffset(textSource) {
|
||||||
|
if (textSource.type === 'range') {
|
||||||
|
const {range} = textSource;
|
||||||
|
const node = this._getParentElement(range.startContainer);
|
||||||
|
if (node !== null) {
|
||||||
|
const {offset} = node.dataset;
|
||||||
|
if (typeof offset === 'string') {
|
||||||
|
const value = Number.parseInt(offset, 10);
|
||||||
|
if (Number.isFinite(value)) {
|
||||||
|
return Math.max(0, value) + range.startOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_getParentElement(node) {
|
||||||
|
const {ELEMENT_NODE} = Node;
|
||||||
|
while (true) {
|
||||||
|
node = node.parentNode;
|
||||||
|
if (node === null) { return null; }
|
||||||
|
if (node.nodeType === ELEMENT_NODE) { return node; }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,10 @@ class TextSourceElement {
|
|||||||
this._content = this._fullContent.substring(this._startOffset, this._endOffset);
|
this._content = this._fullContent.substring(this._startOffset, this._endOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get type() {
|
||||||
|
return 'element';
|
||||||
|
}
|
||||||
|
|
||||||
get element() {
|
get element() {
|
||||||
return this._element;
|
return this._element;
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,10 @@ class TextSourceRange {
|
|||||||
this._imposterSourceElement = imposterSourceElement;
|
this._imposterSourceElement = imposterSourceElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get type() {
|
||||||
|
return 'range';
|
||||||
|
}
|
||||||
|
|
||||||
get range() {
|
get range() {
|
||||||
return this._range;
|
return this._range;
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
|
|
||||||
/* global
|
/* global
|
||||||
* DocumentUtil
|
* DocumentUtil
|
||||||
* TextSourceElement
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class TextScanner extends EventDispatcher {
|
class TextScanner extends EventDispatcher {
|
||||||
@ -345,7 +344,7 @@ class TextScanner extends EventDispatcher {
|
|||||||
if (result !== null) {
|
if (result !== null) {
|
||||||
({dictionaryEntries, sentence, type} = result);
|
({dictionaryEntries, sentence, type} = result);
|
||||||
valid = true;
|
valid = true;
|
||||||
} else if (textSource instanceof TextSourceElement && await this._hasJapanese(textSource.fullContent)) {
|
} else if (textSource !== null && textSource.type === 'element' && await this._hasJapanese(textSource.fullContent)) {
|
||||||
dictionaryEntries = [];
|
dictionaryEntries = [];
|
||||||
sentence = {sentence: '', offset: 0};
|
sentence = {sentence: '', offset: 0};
|
||||||
type = 'terms';
|
type = 'terms';
|
||||||
|
Loading…
Reference in New Issue
Block a user