Merge pull request #350 from siikamiika/query-parser-html-templates
query parser html templates
This commit is contained in:
commit
9ffd0cb441
10
README.md
10
README.md
@ -27,7 +27,6 @@ Yomichan provides advanced features not available in other browser-based diction
|
|||||||
* [Flashcard Creation](https://foosoft.net/projects/yomichan/#flashcard-creation)
|
* [Flashcard Creation](https://foosoft.net/projects/yomichan/#flashcard-creation)
|
||||||
* [Keyboard Shortcuts](https://foosoft.net/projects/yomichan/#keyboard-shortcuts)
|
* [Keyboard Shortcuts](https://foosoft.net/projects/yomichan/#keyboard-shortcuts)
|
||||||
* [Development](https://foosoft.net/projects/yomichan/#development)
|
* [Development](https://foosoft.net/projects/yomichan/#development)
|
||||||
* [Templates](https://foosoft.net/projects/yomichan/#templates)
|
|
||||||
* [Dependencies](https://foosoft.net/projects/yomichan/#dependencies)
|
* [Dependencies](https://foosoft.net/projects/yomichan/#dependencies)
|
||||||
* [Frequently Asked Questions](https://foosoft.net/projects/yomichan/#frequently-asked-questions)
|
* [Frequently Asked Questions](https://foosoft.net/projects/yomichan/#frequently-asked-questions)
|
||||||
* [Screenshots](https://foosoft.net/projects/yomichan/#screenshots)
|
* [Screenshots](https://foosoft.net/projects/yomichan/#screenshots)
|
||||||
@ -241,15 +240,6 @@ following basic guidelines when creating pull requests:
|
|||||||
* Large pull requests without a clear scope will not be merged.
|
* Large pull requests without a clear scope will not be merged.
|
||||||
* Incomplete or non-standalone features will not be merged.
|
* Incomplete or non-standalone features will not be merged.
|
||||||
|
|
||||||
### Templates ###
|
|
||||||
|
|
||||||
Yomichan uses [Handlebars](https://handlebarsjs.com/) templates for user interface generation. The source templates are
|
|
||||||
found in the `tmpl` directory and the compiled version is stored in the `ext/bg/js/templates.js` file. If you modify the
|
|
||||||
source templates, you will need to also recompile them. If you are developing on Linux or Mac OS X, you can use the
|
|
||||||
included `build_tmpl.sh` and `build_tmpl_auto.sh` shell scripts to do this for you
|
|
||||||
([inotify-tools](https://github.com/rvoicilas/inotify-tools/wiki) required). Otherwise, simply execute `handlebars
|
|
||||||
tmpl/*.html -f ext/bg/js/templates.js` from the project's base directory to compile all the templates.
|
|
||||||
|
|
||||||
### Dependencies ###
|
### Dependencies ###
|
||||||
|
|
||||||
Yomichan uses several third-party libraries to function. Below are links to homepages, snapshots, and licenses of the exact
|
Yomichan uses several third-party libraries to function. Below are links to homepages, snapshots, and licenses of the exact
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
handlebars tmpl/*.html -f ext/bg/js/templates.js
|
|
@ -1,16 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
DIRECTORY_TO_OBSERVE="tmpl"
|
|
||||||
BUILD_SCRIPT="build_tmpl.sh"
|
|
||||||
|
|
||||||
function block_for_change {
|
|
||||||
inotifywait -e modify,move,create,delete $DIRECTORY_TO_OBSERVE
|
|
||||||
}
|
|
||||||
|
|
||||||
function build {
|
|
||||||
bash $BUILD_SCRIPT
|
|
||||||
}
|
|
||||||
|
|
||||||
build
|
|
||||||
while block_for_change; do
|
|
||||||
build
|
|
||||||
done
|
|
@ -37,7 +37,6 @@
|
|||||||
<script src="/bg/js/options.js"></script>
|
<script src="/bg/js/options.js"></script>
|
||||||
<script src="/bg/js/profile-conditions.js"></script>
|
<script src="/bg/js/profile-conditions.js"></script>
|
||||||
<script src="/bg/js/request.js"></script>
|
<script src="/bg/js/request.js"></script>
|
||||||
<script src="/bg/js/templates.js"></script>
|
|
||||||
<script src="/bg/js/translator.js"></script>
|
<script src="/bg/js/translator.js"></script>
|
||||||
<script src="/bg/js/util.js"></script>
|
<script src="/bg/js/util.js"></script>
|
||||||
<script src="/mixed/js/audio.js"></script>
|
<script src="/mixed/js/audio.js"></script>
|
||||||
|
@ -33,6 +33,10 @@ function apiClipboardGet() {
|
|||||||
return _apiInvoke('clipboardGet');
|
return _apiInvoke('clipboardGet');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function apiGetQueryParserTemplatesHtml() {
|
||||||
|
return _apiInvoke('getQueryParserTemplatesHtml');
|
||||||
|
}
|
||||||
|
|
||||||
function _apiInvoke(action, params={}) {
|
function _apiInvoke(action, params={}) {
|
||||||
const data = {action, params};
|
const data = {action, params};
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
@ -567,6 +567,11 @@ class Backend {
|
|||||||
return await requestText(url, 'GET');
|
return await requestText(url, 'GET');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async _onApiGetQueryParserTemplatesHtml() {
|
||||||
|
const url = chrome.runtime.getURL('/bg/query-parser-templates.html');
|
||||||
|
return await requestText(url, 'GET');
|
||||||
|
}
|
||||||
|
|
||||||
_onApiGetZoom(params, sender) {
|
_onApiGetZoom(params, sender) {
|
||||||
if (!sender || !sender.tab) {
|
if (!sender || !sender.tab) {
|
||||||
return Promise.reject(new Error('Invalid tab'));
|
return Promise.reject(new Error('Invalid tab'));
|
||||||
@ -854,6 +859,7 @@ Backend._messageHandlers = new Map([
|
|||||||
['getEnvironmentInfo', (self, ...args) => self._onApiGetEnvironmentInfo(...args)],
|
['getEnvironmentInfo', (self, ...args) => self._onApiGetEnvironmentInfo(...args)],
|
||||||
['clipboardGet', (self, ...args) => self._onApiClipboardGet(...args)],
|
['clipboardGet', (self, ...args) => self._onApiClipboardGet(...args)],
|
||||||
['getDisplayTemplatesHtml', (self, ...args) => self._onApiGetDisplayTemplatesHtml(...args)],
|
['getDisplayTemplatesHtml', (self, ...args) => self._onApiGetDisplayTemplatesHtml(...args)],
|
||||||
|
['getQueryParserTemplatesHtml', (self, ...args) => self._onApiGetQueryParserTemplatesHtml(...args)],
|
||||||
['getZoom', (self, ...args) => self._onApiGetZoom(...args)]
|
['getZoom', (self, ...args) => self._onApiGetZoom(...args)]
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
77
ext/bg/js/search-query-parser-generator.js
Normal file
77
ext/bg/js/search-query-parser-generator.js
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Alex Yatskov <alex@foosoft.net>
|
||||||
|
* Author: Alex Yatskov <alex@foosoft.net>
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
class QueryParserGenerator {
|
||||||
|
constructor() {
|
||||||
|
this._templateHandler = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async prepare() {
|
||||||
|
const html = await apiGetQueryParserTemplatesHtml();
|
||||||
|
this._templateHandler = new TemplateHandler(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
createParseResult(terms, preview=false) {
|
||||||
|
const fragment = document.createDocumentFragment();
|
||||||
|
for (const term of terms) {
|
||||||
|
const termContainer = this._templateHandler.instantiate(preview ? 'term-preview' : 'term');
|
||||||
|
for (const segment of term) {
|
||||||
|
if (!segment.text.trim()) { continue; }
|
||||||
|
if (!segment.reading || !segment.reading.trim()) {
|
||||||
|
termContainer.appendChild(this.createSegmentText(segment.text));
|
||||||
|
} else {
|
||||||
|
termContainer.appendChild(this.createSegment(segment));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fragment.appendChild(termContainer);
|
||||||
|
}
|
||||||
|
return fragment;
|
||||||
|
}
|
||||||
|
|
||||||
|
createSegment(segment) {
|
||||||
|
const segmentContainer = this._templateHandler.instantiate('segment');
|
||||||
|
const segmentTextContainer = segmentContainer.querySelector('.query-parser-segment-text');
|
||||||
|
const segmentReadingContainer = segmentContainer.querySelector('.query-parser-segment-reading');
|
||||||
|
segmentTextContainer.appendChild(this.createSegmentText(segment.text));
|
||||||
|
segmentReadingContainer.innerText = segment.reading;
|
||||||
|
return segmentContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
createSegmentText(text) {
|
||||||
|
const fragment = document.createDocumentFragment();
|
||||||
|
for (const chr of text) {
|
||||||
|
const charContainer = this._templateHandler.instantiate('char');
|
||||||
|
charContainer.innerText = chr;
|
||||||
|
fragment.appendChild(charContainer);
|
||||||
|
}
|
||||||
|
return fragment;
|
||||||
|
}
|
||||||
|
|
||||||
|
createParserSelect(parseResults, selectedParser) {
|
||||||
|
const selectContainer = this._templateHandler.instantiate('select');
|
||||||
|
for (const parseResult of parseResults) {
|
||||||
|
const optionContainer = this._templateHandler.instantiate('select-option');
|
||||||
|
optionContainer.value = parseResult.id;
|
||||||
|
optionContainer.innerText = parseResult.name;
|
||||||
|
optionContainer.defaultSelected = selectedParser === parseResult.id;
|
||||||
|
selectContainer.appendChild(optionContainer);
|
||||||
|
}
|
||||||
|
return selectContainer;
|
||||||
|
}
|
||||||
|
}
|
@ -19,14 +19,20 @@
|
|||||||
|
|
||||||
class QueryParser extends TextScanner {
|
class QueryParser extends TextScanner {
|
||||||
constructor(search) {
|
constructor(search) {
|
||||||
super(document.querySelector('#query-parser'), [], [], []);
|
super(document.querySelector('#query-parser-content'), [], [], []);
|
||||||
this.search = search;
|
this.search = search;
|
||||||
|
|
||||||
this.parseResults = [];
|
this.parseResults = [];
|
||||||
this.selectedParser = null;
|
this.selectedParser = null;
|
||||||
|
|
||||||
this.queryParser = document.querySelector('#query-parser');
|
this.queryParser = document.querySelector('#query-parser-content');
|
||||||
this.queryParserSelect = document.querySelector('#query-parser-select');
|
this.queryParserSelect = document.querySelector('#query-parser-select-container');
|
||||||
|
|
||||||
|
this.queryParserGenerator = new QueryParserGenerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
async prepare() {
|
||||||
|
await this.queryParserGenerator.prepare();
|
||||||
}
|
}
|
||||||
|
|
||||||
onError(error) {
|
onError(error) {
|
||||||
@ -64,7 +70,7 @@ class QueryParser extends TextScanner {
|
|||||||
const selectedParser = e.target.value;
|
const selectedParser = e.target.value;
|
||||||
this.selectedParser = selectedParser;
|
this.selectedParser = selectedParser;
|
||||||
apiOptionsSet({parsing: {selectedParser}}, this.search.getOptionsContext());
|
apiOptionsSet({parsing: {selectedParser}}, this.search.getOptionsContext());
|
||||||
this.renderParseResult(this.getParseResult());
|
this.renderParseResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
getMouseEventListeners() {
|
getMouseEventListeners() {
|
||||||
@ -113,13 +119,13 @@ class QueryParser extends TextScanner {
|
|||||||
async setText(text) {
|
async setText(text) {
|
||||||
this.search.setSpinnerVisible(true);
|
this.search.setSpinnerVisible(true);
|
||||||
|
|
||||||
await this.setPreview(text);
|
this.setPreview(text);
|
||||||
|
|
||||||
this.parseResults = await this.parseText(text);
|
this.parseResults = await this.parseText(text);
|
||||||
this.refreshSelectedParser();
|
this.refreshSelectedParser();
|
||||||
|
|
||||||
this.renderParserSelect();
|
this.renderParserSelect();
|
||||||
await this.renderParseResult();
|
this.renderParseResult();
|
||||||
|
|
||||||
this.search.setSpinnerVisible(false);
|
this.search.setSpinnerVisible(false);
|
||||||
}
|
}
|
||||||
@ -146,57 +152,29 @@ class QueryParser extends TextScanner {
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
async setPreview(text) {
|
setPreview(text) {
|
||||||
const previewTerms = [];
|
const previewTerms = [];
|
||||||
for (let i = 0, ii = text.length; i < ii; i += 2) {
|
for (let i = 0, ii = text.length; i < ii; i += 2) {
|
||||||
const tempText = text.substring(i, i + 2);
|
const tempText = text.substring(i, i + 2);
|
||||||
previewTerms.push([{text: tempText.split('')}]);
|
previewTerms.push([{text: tempText}]);
|
||||||
}
|
}
|
||||||
this.queryParser.innerHTML = await apiTemplateRender('query-parser.html', {
|
this.queryParser.textContent = '';
|
||||||
terms: previewTerms,
|
this.queryParser.appendChild(this.queryParserGenerator.createParseResult(previewTerms, true));
|
||||||
preview: true
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
renderParserSelect() {
|
renderParserSelect() {
|
||||||
this.queryParserSelect.innerHTML = '';
|
this.queryParserSelect.innerHTML = '';
|
||||||
if (this.parseResults.length > 1) {
|
if (this.parseResults.length > 1) {
|
||||||
const select = document.createElement('select');
|
const select = this.queryParserGenerator.createParserSelect(this.parseResults, this.selectedParser);
|
||||||
select.classList.add('form-control');
|
|
||||||
for (const parseResult of this.parseResults) {
|
|
||||||
const option = document.createElement('option');
|
|
||||||
option.value = parseResult.id;
|
|
||||||
option.innerText = parseResult.name;
|
|
||||||
option.defaultSelected = this.selectedParser === parseResult.id;
|
|
||||||
select.appendChild(option);
|
|
||||||
}
|
|
||||||
select.addEventListener('change', this.onParserChange.bind(this));
|
select.addEventListener('change', this.onParserChange.bind(this));
|
||||||
this.queryParserSelect.appendChild(select);
|
this.queryParserSelect.appendChild(select);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async renderParseResult() {
|
renderParseResult() {
|
||||||
const parseResult = this.getParseResult();
|
const parseResult = this.getParseResult();
|
||||||
if (!parseResult) {
|
this.queryParser.textContent = '';
|
||||||
this.queryParser.innerHTML = '';
|
if (!parseResult) { return; }
|
||||||
return;
|
this.queryParser.appendChild(this.queryParserGenerator.createParseResult(parseResult.parsedText));
|
||||||
}
|
|
||||||
|
|
||||||
this.queryParser.innerHTML = await apiTemplateRender(
|
|
||||||
'query-parser.html',
|
|
||||||
{terms: QueryParser.processParseResultForDisplay(parseResult.parsedText)}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static processParseResultForDisplay(result) {
|
|
||||||
return result.map((term) => {
|
|
||||||
return term.filter((part) => part.text.trim()).map((part) => {
|
|
||||||
return {
|
|
||||||
text: part.text.split(''),
|
|
||||||
reading: part.reading,
|
|
||||||
raw: !part.reading || !part.reading.trim()
|
|
||||||
};
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,8 @@ class DisplaySearch extends Display {
|
|||||||
try {
|
try {
|
||||||
await this.initialize();
|
await this.initialize();
|
||||||
|
|
||||||
|
await this.queryParser.prepare();
|
||||||
|
|
||||||
const {queryParams: {query='', mode=''}} = parseUrl(window.location.href);
|
const {queryParams: {query='', mode=''}} = parseUrl(window.location.href);
|
||||||
|
|
||||||
if (this.search !== null) {
|
if (this.search !== null) {
|
||||||
|
@ -1,55 +0,0 @@
|
|||||||
(function() {
|
|
||||||
var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
|
|
||||||
templates['query-parser.html'] = template({"1":function(container,depth0,helpers,partials,data) {
|
|
||||||
var stack1, alias1=depth0 != null ? depth0 : (container.nullContext || {});
|
|
||||||
|
|
||||||
return ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.preview : depth0),{"name":"if","hash":{},"fn":container.program(2, data, 0),"inverse":container.program(4, data, 0),"data":data})) != null ? stack1 : "")
|
|
||||||
+ ((stack1 = helpers.each.call(alias1,depth0,{"name":"each","hash":{},"fn":container.program(6, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
|
||||||
+ "</span>";
|
|
||||||
},"2":function(container,depth0,helpers,partials,data) {
|
|
||||||
return "<span class=\"query-parser-term-preview\">";
|
|
||||||
},"4":function(container,depth0,helpers,partials,data) {
|
|
||||||
return "<span class=\"query-parser-term\">";
|
|
||||||
},"6":function(container,depth0,helpers,partials,data) {
|
|
||||||
var stack1;
|
|
||||||
|
|
||||||
return ((stack1 = container.invokePartial(partials.part,depth0,{"name":"part","data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
|
|
||||||
},"8":function(container,depth0,helpers,partials,data) {
|
|
||||||
var stack1;
|
|
||||||
|
|
||||||
return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.raw : depth0),{"name":"if","hash":{},"fn":container.program(9, data, 0),"inverse":container.program(12, data, 0),"data":data})) != null ? stack1 : "");
|
|
||||||
},"9":function(container,depth0,helpers,partials,data) {
|
|
||||||
var stack1;
|
|
||||||
|
|
||||||
return ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.text : depth0),{"name":"each","hash":{},"fn":container.program(10, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
|
|
||||||
},"10":function(container,depth0,helpers,partials,data) {
|
|
||||||
return "<span class=\"query-parser-char\">"
|
|
||||||
+ container.escapeExpression(container.lambda(depth0, depth0))
|
|
||||||
+ "</span>";
|
|
||||||
},"12":function(container,depth0,helpers,partials,data) {
|
|
||||||
var stack1, helper, alias1=depth0 != null ? depth0 : (container.nullContext || {});
|
|
||||||
|
|
||||||
return "<ruby>"
|
|
||||||
+ ((stack1 = helpers.each.call(alias1,(depth0 != null ? depth0.text : depth0),{"name":"each","hash":{},"fn":container.program(10, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
|
||||||
+ "<rt>"
|
|
||||||
+ container.escapeExpression(((helper = (helper = helpers.reading || (depth0 != null ? depth0.reading : depth0)) != null ? helper : helpers.helperMissing),(typeof helper === "function" ? helper.call(alias1,{"name":"reading","hash":{},"data":data}) : helper)))
|
|
||||||
+ "</rt></ruby>";
|
|
||||||
},"14":function(container,depth0,helpers,partials,data,blockParams,depths) {
|
|
||||||
var stack1;
|
|
||||||
|
|
||||||
return ((stack1 = container.invokePartial(partials.term,depth0,{"name":"term","hash":{"preview":(depths[1] != null ? depths[1].preview : depths[1])},"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
|
|
||||||
},"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data,blockParams,depths) {
|
|
||||||
var stack1;
|
|
||||||
|
|
||||||
return ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.terms : depth0),{"name":"each","hash":{},"fn":container.program(14, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "");
|
|
||||||
},"main_d": function(fn, props, container, depth0, data, blockParams, depths) {
|
|
||||||
|
|
||||||
var decorators = container.decorators;
|
|
||||||
|
|
||||||
fn = decorators.inline(fn,props,container,{"name":"inline","hash":{},"fn":container.program(1, data, 0, blockParams, depths),"inverse":container.noop,"args":["term"],"data":data}) || fn;
|
|
||||||
fn = decorators.inline(fn,props,container,{"name":"inline","hash":{},"fn":container.program(8, data, 0, blockParams, depths),"inverse":container.noop,"args":["part"],"data":data}) || fn;
|
|
||||||
return fn;
|
|
||||||
}
|
|
||||||
|
|
||||||
,"useDecorators":true,"usePartial":true,"useData":true,"useDepths":true});
|
|
||||||
})();
|
|
11
ext/bg/query-parser-templates.html
Normal file
11
ext/bg/query-parser-templates.html
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<!DOCTYPE html><html><head></head><body>
|
||||||
|
|
||||||
|
<template id="term-template"><span class="query-parser-term" data-type="normal"></span></template>
|
||||||
|
<template id="term-preview-template"><span class="query-parser-term" data-type="preview"></span></template>
|
||||||
|
<template id="segment-template"><ruby class="query-parser-segment"><span class="query-parser-segment-text"></span><rt class="query-parser-segment-reading"></rt></ruby></template>
|
||||||
|
<template id="char-template"><span class="query-parser-char"></span></template>
|
||||||
|
|
||||||
|
<template id="select-template"><select class="query-parser-select form-control"></select></template>
|
||||||
|
<template id="select-option-template"><option class="query-parser-select-option"></option></template>
|
||||||
|
|
||||||
|
</body></html>
|
@ -48,8 +48,8 @@
|
|||||||
<div id="spinner" hidden><img src="/mixed/img/spinner.gif"></div>
|
<div id="spinner" hidden><img src="/mixed/img/spinner.gif"></div>
|
||||||
|
|
||||||
<div class="scan-disable">
|
<div class="scan-disable">
|
||||||
<div id="query-parser-select" class="input-group"></div>
|
<div id="query-parser-select-container" class="input-group"></div>
|
||||||
<div id="query-parser"></div>
|
<div id="query-parser-content"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
@ -78,7 +78,6 @@
|
|||||||
<script src="/bg/js/dictionary.js"></script>
|
<script src="/bg/js/dictionary.js"></script>
|
||||||
<script src="/bg/js/handlebars.js"></script>
|
<script src="/bg/js/handlebars.js"></script>
|
||||||
<script src="/bg/js/japanese.js"></script>
|
<script src="/bg/js/japanese.js"></script>
|
||||||
<script src="/bg/js/templates.js"></script>
|
|
||||||
<script src="/fg/js/document.js"></script>
|
<script src="/fg/js/document.js"></script>
|
||||||
<script src="/fg/js/source.js"></script>
|
<script src="/fg/js/source.js"></script>
|
||||||
<script src="/mixed/js/audio.js"></script>
|
<script src="/mixed/js/audio.js"></script>
|
||||||
@ -87,7 +86,9 @@
|
|||||||
<script src="/mixed/js/display-generator.js"></script>
|
<script src="/mixed/js/display-generator.js"></script>
|
||||||
<script src="/mixed/js/scroll.js"></script>
|
<script src="/mixed/js/scroll.js"></script>
|
||||||
<script src="/mixed/js/text-scanner.js"></script>
|
<script src="/mixed/js/text-scanner.js"></script>
|
||||||
|
<script src="/mixed/js/template-handler.js"></script>
|
||||||
|
|
||||||
|
<script src="/bg/js/search-query-parser-generator.js"></script>
|
||||||
<script src="/bg/js/search-query-parser.js"></script>
|
<script src="/bg/js/search-query-parser.js"></script>
|
||||||
<script src="/bg/js/clipboard-monitor.js"></script>
|
<script src="/bg/js/clipboard-monitor.js"></script>
|
||||||
<script src="/bg/js/search.js"></script>
|
<script src="/bg/js/search.js"></script>
|
||||||
|
@ -1097,7 +1097,6 @@
|
|||||||
<script src="/bg/js/options.js"></script>
|
<script src="/bg/js/options.js"></script>
|
||||||
<script src="/bg/js/page-exit-prevention.js"></script>
|
<script src="/bg/js/page-exit-prevention.js"></script>
|
||||||
<script src="/bg/js/profile-conditions.js"></script>
|
<script src="/bg/js/profile-conditions.js"></script>
|
||||||
<script src="/bg/js/templates.js"></script>
|
|
||||||
<script src="/bg/js/util.js"></script>
|
<script src="/bg/js/util.js"></script>
|
||||||
<script src="/mixed/js/audio.js"></script>
|
<script src="/mixed/js/audio.js"></script>
|
||||||
|
|
||||||
|
@ -127,12 +127,12 @@ html:root[data-yomichan-page=float] .navigation-header:not([hidden])~.navigation
|
|||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#query-parser {
|
#query-parser-content {
|
||||||
margin-top: 0.5em;
|
margin-top: 0.5em;
|
||||||
font-size: 2em;
|
font-size: 2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
#query-parser[data-term-spacing=true] .query-parser-term {
|
#query-parser-content[data-term-spacing=true] .query-parser-term {
|
||||||
margin-right: 0.2em;
|
margin-right: 0.2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,6 +105,10 @@ function apiGetDisplayTemplatesHtml() {
|
|||||||
return _apiInvoke('getDisplayTemplatesHtml');
|
return _apiInvoke('getDisplayTemplatesHtml');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function apiGetQueryParserTemplatesHtml() {
|
||||||
|
return _apiInvoke('getQueryParserTemplatesHtml');
|
||||||
|
}
|
||||||
|
|
||||||
function apiGetZoom() {
|
function apiGetZoom() {
|
||||||
return _apiInvoke('getZoom');
|
return _apiInvoke('getZoom');
|
||||||
}
|
}
|
||||||
|
47
ext/mixed/js/template-handler.js
Normal file
47
ext/mixed/js/template-handler.js
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Alex Yatskov <alex@foosoft.net>
|
||||||
|
* Author: Alex Yatskov <alex@foosoft.net>
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
class TemplateHandler {
|
||||||
|
constructor(html) {
|
||||||
|
this._templates = new Map();
|
||||||
|
|
||||||
|
const doc = new DOMParser().parseFromString(html, 'text/html');
|
||||||
|
for (const template of doc.querySelectorAll('template')) {
|
||||||
|
this._setTemplate(template);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_setTemplate(template) {
|
||||||
|
const idMatch = template.id.match(/^([a-z-]+)-template$/);
|
||||||
|
if (!idMatch) {
|
||||||
|
throw new Error(`Invalid template ID: ${template.id}`);
|
||||||
|
}
|
||||||
|
this._templates.set(idMatch[1], template);
|
||||||
|
}
|
||||||
|
|
||||||
|
instantiate(name) {
|
||||||
|
const template = this._templates.get(name);
|
||||||
|
return document.importNode(template.content.firstChild, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
instantiateFragment(name) {
|
||||||
|
const template = this._templates.get(name);
|
||||||
|
return document.importNode(template.content, true);
|
||||||
|
}
|
||||||
|
}
|
@ -1,27 +0,0 @@
|
|||||||
{{~#*inline "term"~}}
|
|
||||||
{{~#if preview~}}
|
|
||||||
<span class="query-parser-term-preview">
|
|
||||||
{{~else~}}
|
|
||||||
<span class="query-parser-term">
|
|
||||||
{{~/if~}}
|
|
||||||
{{~#each this~}}
|
|
||||||
{{> part }}
|
|
||||||
{{~/each~}}
|
|
||||||
</span>
|
|
||||||
{{~/inline~}}
|
|
||||||
|
|
||||||
{{~#*inline "part"~}}
|
|
||||||
{{~#if raw~}}
|
|
||||||
{{~#each text~}}
|
|
||||||
<span class="query-parser-char">{{this}}</span>
|
|
||||||
{{~/each~}}
|
|
||||||
{{~else~}}
|
|
||||||
<ruby>{{~#each text~}}
|
|
||||||
<span class="query-parser-char">{{this}}</span>
|
|
||||||
{{~/each~}}<rt>{{reading}}</rt></ruby>
|
|
||||||
{{~/if~}}
|
|
||||||
{{~/inline~}}
|
|
||||||
|
|
||||||
{{~#each terms~}}
|
|
||||||
{{> term preview=../preview }}
|
|
||||||
{{~/each~}}
|
|
Loading…
Reference in New Issue
Block a user