Automatically look up Kanji when cannot find definitions.
Allow text scanning without holding Shift key (resolves #18).
This commit is contained in:
parent
1d573f4179
commit
1e9906c624
@ -46,15 +46,10 @@
|
|||||||
<li>Left-click on the <img src="../img/icon16.png" alt> icon to enable or disable Yomichan for the current browser instance.</li>
|
<li>Left-click on the <img src="../img/icon16.png" alt> icon to enable or disable Yomichan for the current browser instance.</li>
|
||||||
<li>Right-click on the <img src="../img/icon16.png" alt> icon and select <em>Options</em> to open the Yomichan options page.</li>
|
<li>Right-click on the <img src="../img/icon16.png" alt> icon and select <em>Options</em> to open the Yomichan options page.</li>
|
||||||
<li>Hold down <kbd>Shift</kbd> (or the middle mouse button) as you hover over text to see term definitions.</li>
|
<li>Hold down <kbd>Shift</kbd> (or the middle mouse button) as you hover over text to see term definitions.</li>
|
||||||
<li>Hold down <kbd>Ctrl</kbd> + <kbd>Shift</kbd> (or the middle mouse button) as you hover over text to see Kanji definitions.</li>
|
|
||||||
<li>Resize the definitions window by dragging the bottom-left corner inwards or outwards.</li>
|
<li>Resize the definitions window by dragging the bottom-left corner inwards or outwards.</li>
|
||||||
<li>Click on Kanji in the definition window to view additional information about that character.</li>
|
<li>Click on Kanji in the definition window to view additional information about that character.</li>
|
||||||
</ol>
|
</ol>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<p>よろしくね!</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="../lib/jquery-2.2.2.min.js"></script>
|
<script src="../lib/jquery-2.2.2.min.js"></script>
|
||||||
|
@ -39,51 +39,43 @@ function modelIdToFieldOptKey(id) {
|
|||||||
|
|
||||||
function modelIdToMarkers(id) {
|
function modelIdToMarkers(id) {
|
||||||
return {
|
return {
|
||||||
'anki-term-model': [
|
'anki-term-model': ['audio', 'exholdion', 'glossary', 'glossary-list', 'reading', 'sentence', 'tags', 'url'],
|
||||||
'audio',
|
'anki-kanji-model': ['character', 'glossary', 'glossary-list', 'kunyomi', 'onyomi', 'url'],
|
||||||
'expression',
|
|
||||||
'glossary',
|
|
||||||
'glossary-list',
|
|
||||||
'reading',
|
|
||||||
'sentence',
|
|
||||||
'tags',
|
|
||||||
'url'
|
|
||||||
],
|
|
||||||
'anki-kanji-model': [
|
|
||||||
'character',
|
|
||||||
'glossary',
|
|
||||||
'glossary-list',
|
|
||||||
'kunyomi',
|
|
||||||
'onyomi',
|
|
||||||
'url'
|
|
||||||
],
|
|
||||||
}[id];
|
}[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
function formToOptions(section) {
|
function getBasicOptions() {
|
||||||
return loadOptions().then(optsOld => {
|
return loadOptions().then(optsOld => {
|
||||||
const optsNew = $.extend({}, optsOld);
|
const optsNew = $.extend({}, optsOld);
|
||||||
|
|
||||||
switch (section) {
|
optsNew.activateOnStartup = $('#activate-on-startup').prop('checked');
|
||||||
case 'general':
|
optsNew.showAdvancedOptions = $('#show-advanced-options').prop('checked');
|
||||||
optsNew.scanLength = parseInt($('#scan-length').val(), 10);
|
optsNew.enableAudioPlayback = $('#enable-audio-playback').prop('checked');
|
||||||
optsNew.activateOnStartup = $('#activate-on-startup').prop('checked');
|
optsNew.enableAnkiConnect = $('#enable-anki-connect').prop('checked');
|
||||||
optsNew.selectMatchedText = $('#select-matched-text').prop('checked');
|
optsNew.holdShiftToScan = $('#hold-shift-to-scan').prop('checked');
|
||||||
optsNew.showAdvancedOptions = $('#show-advanced-options').prop('checked');
|
optsNew.selectMatchedText = $('#select-matched-text').prop('checked');
|
||||||
optsNew.enableAudioPlayback = $('#enable-audio-playback').prop('checked');
|
optsNew.scanDelay = parseInt($('#scan-delay').val(), 10);
|
||||||
optsNew.enableAnkiConnect = $('#enable-anki-connect').prop('checked');
|
optsNew.scanLength = parseInt($('#scan-length').val(), 10);
|
||||||
break;
|
|
||||||
case 'anki':
|
return {
|
||||||
optsNew.ankiCardTags = $('#anki-card-tags').val().split(/[,; ]+/);
|
optsNew: sanitizeOptions(optsNew),
|
||||||
optsNew.sentenceExtent = parseInt($('#sentence-extent').val(), 10);
|
optsOld: sanitizeOptions(optsOld)
|
||||||
optsNew.ankiTermDeck = $('#anki-term-deck').val();
|
};
|
||||||
optsNew.ankiTermModel = $('#anki-term-model').val();
|
});
|
||||||
optsNew.ankiTermFields = fieldsToDict($('#term .anki-field-value'));
|
}
|
||||||
optsNew.ankiKanjiDeck = $('#anki-kanji-deck').val();
|
|
||||||
optsNew.ankiKanjiModel = $('#anki-kanji-model').val();
|
function getAnkiOptions() {
|
||||||
optsNew.ankiKanjiFields = fieldsToDict($('#kanji .anki-field-value'));
|
return loadOptions().then(optsOld => {
|
||||||
break;
|
const optsNew = $.extend({}, optsOld);
|
||||||
}
|
|
||||||
|
optsNew.ankiCardTags = $('#anki-card-tags').val().split(/[,; ]+/);
|
||||||
|
optsNew.sentenceExtent = parseInt($('#sentence-extent').val(), 10);
|
||||||
|
optsNew.ankiTermDeck = $('#anki-term-deck').val();
|
||||||
|
optsNew.ankiTermModel = $('#anki-term-model').val();
|
||||||
|
optsNew.ankiTermFields = fieldsToDict($('#term .anki-field-value'));
|
||||||
|
optsNew.ankiKanjiDeck = $('#anki-kanji-deck').val();
|
||||||
|
optsNew.ankiKanjiModel = $('#anki-kanji-model').val();
|
||||||
|
optsNew.ankiKanjiFields = fieldsToDict($('#kanji .anki-field-value'));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
optsNew: sanitizeOptions(optsNew),
|
optsNew: sanitizeOptions(optsNew),
|
||||||
@ -182,12 +174,12 @@ function populateAnkiFields(element, opts) {
|
|||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
function onOptionsGeneralChanged(e) {
|
function onOptionsBasicChanged(e) {
|
||||||
if (!e.originalEvent && !e.isTrigger) {
|
if (!e.originalEvent && !e.isTrigger) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
formToOptions('general').then(({optsNew, optsOld}) => {
|
getBasicOptions().then(({optsNew, optsOld}) => {
|
||||||
saveOptions(optsNew).then(() => {
|
saveOptions(optsNew).then(() => {
|
||||||
yomichan().setOptions(optsNew);
|
yomichan().setOptions(optsNew);
|
||||||
if (!optsOld.enableAnkiConnect && optsNew.enableAnkiConnect) {
|
if (!optsOld.enableAnkiConnect && optsNew.enableAnkiConnect) {
|
||||||
@ -212,14 +204,14 @@ function onOptionsAnkiChanged(e) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
formToOptions('anki').then(({optsNew, optsOld}) => {
|
getAnkiOptions().then(({optsNew, optsOld}) => {
|
||||||
saveOptions(optsNew).then(() => yomichan().setOptions(optsNew));
|
saveOptions(optsNew).then(() => yomichan().setOptions(optsNew));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function onAnkiModelChanged(e) {
|
function onAnkiModelChanged(e) {
|
||||||
if (e.originalEvent) {
|
if (e.originalEvent) {
|
||||||
formToOptions('anki').then(({optsNew, optsOld}) => {
|
getAnkiOptions().then(({optsNew, optsOld}) => {
|
||||||
optsNew[modelIdToFieldOptKey($(this).id)] = {};
|
optsNew[modelIdToFieldOptKey($(this).id)] = {};
|
||||||
populateAnkiFields($(this), optsNew);
|
populateAnkiFields($(this), optsNew);
|
||||||
saveOptions(optsNew).then(() => yomichan().setOptions(optsNew));
|
saveOptions(optsNew).then(() => yomichan().setOptions(optsNew));
|
||||||
@ -230,16 +222,17 @@ function onAnkiModelChanged(e) {
|
|||||||
$(document).ready(() => {
|
$(document).ready(() => {
|
||||||
loadOptions().then(opts => {
|
loadOptions().then(opts => {
|
||||||
$('#activate-on-startup').prop('checked', opts.activateOnStartup);
|
$('#activate-on-startup').prop('checked', opts.activateOnStartup);
|
||||||
$('#select-matched-text').prop('checked', opts.selectMatchedText);
|
|
||||||
$('#enable-audio-playback').prop('checked', opts.enableAudioPlayback);
|
$('#enable-audio-playback').prop('checked', opts.enableAudioPlayback);
|
||||||
$('#enable-anki-connect').prop('checked', opts.enableAnkiConnect);
|
$('#enable-anki-connect').prop('checked', opts.enableAnkiConnect);
|
||||||
$('#show-advanced-options').prop('checked', opts.showAdvancedOptions);
|
$('#show-advanced-options').prop('checked', opts.showAdvancedOptions);
|
||||||
|
$('#hold-shift-to-scan').prop('checked', opts.holdShiftToScan);
|
||||||
|
$('#select-matched-text').prop('checked', opts.selectMatchedText);
|
||||||
|
$('#scan-delay').val(opts.scanDelay);
|
||||||
$('#scan-length').val(opts.scanLength);
|
$('#scan-length').val(opts.scanLength);
|
||||||
|
|
||||||
$('#anki-card-tags').val(opts.ankiCardTags.join(' '));
|
$('#anki-card-tags').val(opts.ankiCardTags.join(' '));
|
||||||
$('#sentence-extent').val(opts.sentenceExtent);
|
$('#sentence-extent').val(opts.sentenceExtent);
|
||||||
|
|
||||||
$('.options-general input').change(onOptionsGeneralChanged);
|
$('.options-basic input').change(onOptionsBasicChanged);
|
||||||
$('.options-anki input').change(onOptionsAnkiChanged);
|
$('.options-anki input').change(onOptionsAnkiChanged);
|
||||||
$('.anki-deck').change(onOptionsAnkiChanged);
|
$('.anki-deck').change(onOptionsAnkiChanged);
|
||||||
$('.anki-model').change(onAnkiModelChanged);
|
$('.anki-model').change(onAnkiModelChanged);
|
||||||
|
@ -20,12 +20,13 @@
|
|||||||
function sanitizeOptions(options) {
|
function sanitizeOptions(options) {
|
||||||
const defaults = {
|
const defaults = {
|
||||||
activateOnStartup: true,
|
activateOnStartup: true,
|
||||||
selectMatchedText: true,
|
|
||||||
enableAudioPlayback: true,
|
enableAudioPlayback: true,
|
||||||
enableAnkiConnect: false,
|
enableAnkiConnect: false,
|
||||||
showAdvancedOptions: false,
|
showAdvancedOptions: false,
|
||||||
|
selectMatchedText: true,
|
||||||
|
holdShiftToScan: true,
|
||||||
|
scanDelay: 15,
|
||||||
scanLength: 20,
|
scanLength: 20,
|
||||||
|
|
||||||
ankiCardTags: ['yomichan'],
|
ankiCardTags: ['yomichan'],
|
||||||
sentenceExtent: 200,
|
sentenceExtent: 200,
|
||||||
|
|
||||||
|
@ -135,7 +135,7 @@ class Translator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.all(promises).then(sets => this.processKanji(sets.reduce((a, b) => a.concat(b))));
|
return Promise.all(promises).then(sets => this.processKanji(sets.reduce((a, b) => a.concat(b), [])));
|
||||||
}
|
}
|
||||||
|
|
||||||
processTerm(groups, source, tags, rules, root) {
|
processTerm(groups, source, tags, rules, root) {
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="options-general">
|
<div class="options-basic">
|
||||||
<h3>General Options</h3>
|
<h3>General Options</h3>
|
||||||
|
|
||||||
<form class="form-horizontal">
|
<form class="form-horizontal">
|
||||||
@ -36,14 +36,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="col-sm-offset-2 col-sm-10">
|
|
||||||
<div class="checkbox">
|
|
||||||
<label class="control-label"><input type="checkbox" id="select-matched-text"> Select matched text</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-sm-offset-2 col-sm-10">
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
@ -67,23 +59,51 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="options-basic">
|
||||||
|
<h3>Scanning Options</h3>
|
||||||
|
|
||||||
|
<form class="form-horizontal">
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
|
<div class="checkbox">
|
||||||
|
<label class="control-label"><input type="checkbox" id="hold-shift-to-scan"> Hold <kbd>Shift</kbd> to scan</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
|
<div class="checkbox">
|
||||||
|
<label class="control-label"><input type="checkbox" id="select-matched-text"> Select matched text</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group options-advanced">
|
||||||
|
<label for="scan-delay" class="control-label col-sm-2">Scan delay</label>
|
||||||
|
<div class="col-sm-10"><input type="number" min="1" id="scan-delay" class="form-control"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group options-advanced">
|
<div class="form-group options-advanced">
|
||||||
<label for="scan-length" class="control-label col-sm-2">Scan length</label>
|
<label for="scan-length" class="control-label col-sm-2">Scan length</label>
|
||||||
<div class="col-sm-10"><input type="number" min="1" id="scan-length" class="form-control"></div>
|
<div class="col-sm-10"><input type="number" min="1" id="scan-length" class="form-control"></div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="options-anki">
|
<div class="options-anki">
|
||||||
<h3>Anki Options</h3>
|
<h3>Anki Options</h3>
|
||||||
|
|
||||||
<div class="alert alert-danger error-dlg error-dlg-connection">
|
<div class="alert alert-danger error-dlg error-dlg-connection">
|
||||||
<strong>Unable to connect</strong>: is the <a href="https://foosoft.net/projects/anki-connect">AnkiConnect</a> extension for <a href="http://ankisrs.net/">Anki</a> installed and running? This software is required for Anki-related features.
|
<strong>Unable to Connect</strong><br>
|
||||||
|
Is the <a href="https://foosoft.net/projects/anki-connect">AnkiConnect</a> extension for <a href="http://ankisrs.net/">Anki</a> installed and running? This software is required for Anki-related features.
|
||||||
</div>
|
</div>
|
||||||
<div class="alert alert-warning error-dlg error-dlg-version">
|
<div class="alert alert-warning error-dlg error-dlg-version">
|
||||||
<strong>Unsupported version</strong>: the installed version of the <a href="https://foosoft.net/projects/anki-connect">AnkiConnect</a> extension for <a href="http://ankisrs.net/">Anki</a> is not compatible with this release; please update it.
|
<strong>Unsupported Version</strong><br>
|
||||||
|
The installed version of the <a href="https://foosoft.net/projects/anki-connect">AnkiConnect</a> extension for <a href="http://ankisrs.net/">Anki</a> is not compatible with this release; please update it.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form class="form-horizontal options-anki-controls">
|
<form class="form-horizontal options-anki-controls">
|
||||||
@ -158,7 +178,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="text-align: right;">
|
<div style="text-align: right;">
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
class Driver {
|
class Driver {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.popup = new Popup();
|
this.popup = new Popup();
|
||||||
|
this.popupTimer = null;
|
||||||
this.audio = {};
|
this.audio = {};
|
||||||
this.lastMousePos = null;
|
this.lastMousePos = null;
|
||||||
this.lastTextSource = null;
|
this.lastTextSource = null;
|
||||||
@ -32,6 +33,7 @@ class Driver {
|
|||||||
|
|
||||||
chrome.runtime.onMessage.addListener(this.onBgMessage.bind(this));
|
chrome.runtime.onMessage.addListener(this.onBgMessage.bind(this));
|
||||||
window.addEventListener('message', this.onFrameMessage.bind(this));
|
window.addEventListener('message', this.onFrameMessage.bind(this));
|
||||||
|
window.addEventListener('mouseover', this.onMouseOver.bind(this));
|
||||||
window.addEventListener('mousedown', this.onMouseDown.bind(this));
|
window.addEventListener('mousedown', this.onMouseDown.bind(this));
|
||||||
window.addEventListener('mousemove', this.onMouseMove.bind(this));
|
window.addEventListener('mousemove', this.onMouseMove.bind(this));
|
||||||
window.addEventListener('keydown', this.onKeyDown.bind(this));
|
window.addEventListener('keydown', this.onKeyDown.bind(this));
|
||||||
@ -46,25 +48,58 @@ class Driver {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
popupTimerSet(callback) {
|
||||||
|
this.popupTimerClear();
|
||||||
|
this.popupTimer = window.setTimeout(callback, this.options.scanDelay);
|
||||||
|
}
|
||||||
|
|
||||||
|
popupTimerClear() {
|
||||||
|
if (this.popupTimer !== null) {
|
||||||
|
window.clearTimeout(this.popupTimer);
|
||||||
|
this.popupTimer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onKeyDown(e) {
|
onKeyDown(e) {
|
||||||
if (this.enabled && this.lastMousePos !== null && (e.keyCode === 16 || e.charCode === 16)) {
|
this.popupTimerClear();
|
||||||
this.searchAt(this.lastMousePos, e.ctrlKey ? 'kanji' : 'terms');
|
|
||||||
|
if (this.enabled && this.lastMousePos !== null && e.keyCode === 16 /* shift */) {
|
||||||
|
this.searchAt(this.lastMousePos, true);
|
||||||
} else {
|
} else {
|
||||||
this.hidePopup();
|
this.hidePopup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onMouseOver(e) {
|
||||||
|
if (e.target === this.popup.container && this.popuptimer !== null) {
|
||||||
|
this.popupTimerClear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onMouseMove(e) {
|
onMouseMove(e) {
|
||||||
|
this.popupTimerClear();
|
||||||
|
|
||||||
this.lastMousePos = {x: e.clientX, y: e.clientY};
|
this.lastMousePos = {x: e.clientX, y: e.clientY};
|
||||||
if (this.enabled && (e.shiftKey || e.which === 2)) {
|
if (!this.enabled) {
|
||||||
this.searchAt(this.lastMousePos, e.ctrlKey ? 'kanji' : 'terms');
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.options.holdShiftToScan && !e.shiftKey) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const searcher = () => this.searchAt(this.lastMousePos, false);
|
||||||
|
if (!this.popup.visible() || e.shiftKey || e.which === 2 /* mmb */) {
|
||||||
|
searcher();
|
||||||
|
} else {
|
||||||
|
this.popupTimerSet(searcher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMouseDown(e) {
|
onMouseDown(e) {
|
||||||
this.lastMousePos = {x: e.clientX, y: e.clientY};
|
this.lastMousePos = {x: e.clientX, y: e.clientY};
|
||||||
if (this.enabled && (e.shiftKey || e.which === 2)) {
|
if (this.enabled && (e.shiftKey || !this.options.holdShiftToScan || e.which === 2 /* mmb */)) {
|
||||||
this.searchAt(this.lastMousePos, e.ctrlKey ? 'kanji' : 'terms');
|
this.searchAt(this.lastMousePos, true);
|
||||||
} else {
|
} else {
|
||||||
this.hidePopup();
|
this.hidePopup();
|
||||||
}
|
}
|
||||||
@ -90,10 +125,10 @@ class Driver {
|
|||||||
textSource.setEndOffset(this.options.scanLength);
|
textSource.setEndOffset(this.options.scanLength);
|
||||||
|
|
||||||
this.pendingLookup = true;
|
this.pendingLookup = true;
|
||||||
findTerm(textSource.text()).then(({definitions, length}) => {
|
return findTerm(textSource.text()).then(({definitions, length}) => {
|
||||||
if (definitions.length === 0) {
|
if (definitions.length === 0) {
|
||||||
this.pendingLookup = false;
|
this.pendingLookup = false;
|
||||||
this.hidePopup();
|
return false;
|
||||||
} else {
|
} else {
|
||||||
textSource.setEndOffset(length);
|
textSource.setEndOffset(length);
|
||||||
|
|
||||||
@ -113,6 +148,8 @@ class Driver {
|
|||||||
if (states !== null) {
|
if (states !== null) {
|
||||||
states.forEach((state, index) => this.popup.invokeApi('setActionState', {index, state, sequence}));
|
states.forEach((state, index) => this.popup.invokeApi('setActionState', {index, state, sequence}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -122,10 +159,10 @@ class Driver {
|
|||||||
textSource.setEndOffset(1);
|
textSource.setEndOffset(1);
|
||||||
|
|
||||||
this.pendingLookup = true;
|
this.pendingLookup = true;
|
||||||
findKanji(textSource.text()).then(definitions => {
|
return findKanji(textSource.text()).then(definitions => {
|
||||||
if (definitions.length === 0) {
|
if (definitions.length === 0) {
|
||||||
this.pendingLookup = false;
|
this.pendingLookup = false;
|
||||||
this.hidePopup();
|
return false;
|
||||||
} else {
|
} else {
|
||||||
definitions.forEach(definition => definition.url = window.location.href);
|
definitions.forEach(definition => definition.url = window.location.href);
|
||||||
|
|
||||||
@ -139,34 +176,40 @@ class Driver {
|
|||||||
if (states !== null) {
|
if (states !== null) {
|
||||||
states.forEach((state, index) => this.popup.invokeApi('setActionState', {index, state, sequence}));
|
states.forEach((state, index) => this.popup.invokeApi('setActionState', {index, state, sequence}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
searchAt(point, mode) {
|
searchAt(point, hideNotFound) {
|
||||||
if (this.pendingLookup) {
|
if (this.pendingLookup) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const textSource = textSourceFromPoint(point);
|
const textSource = textSourceFromPoint(point);
|
||||||
if (textSource === null || !textSource.containsPoint(point)) {
|
if (textSource === null || !textSource.containsPoint(point)) {
|
||||||
this.hidePopup();
|
if (hideNotFound) {
|
||||||
|
this.hidePopup();
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.lastTextSource !== null && this.lastTextSource.equals(textSource)) {
|
if (this.lastTextSource !== null && this.lastTextSource.equals(textSource)) {
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (mode) {
|
this.searchTerms(textSource).then(found => {
|
||||||
case 'terms':
|
if (!found) {
|
||||||
this.searchTerms(textSource);
|
this.searchKanji(textSource).then(found => {
|
||||||
break;
|
if (!found && hideNotFound) {
|
||||||
case 'kanji':
|
this.hidePopup();
|
||||||
this.searchKanji(textSource);
|
}
|
||||||
break;
|
});
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
showPopup(textSource, content) {
|
showPopup(textSource, content) {
|
||||||
|
@ -19,16 +19,16 @@
|
|||||||
|
|
||||||
class Popup {
|
class Popup {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.popup = null;
|
this.container = null;
|
||||||
this.offset = 10;
|
this.offset = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
showAt(pos, content) {
|
showAt(pos, content) {
|
||||||
this.inject();
|
this.inject();
|
||||||
|
|
||||||
this.popup.style.left = pos.x + 'px';
|
this.container.style.left = pos.x + 'px';
|
||||||
this.popup.style.top = pos.y + 'px';
|
this.container.style.top = pos.y + 'px';
|
||||||
this.popup.style.visibility = 'visible';
|
this.container.style.visibility = 'visible';
|
||||||
|
|
||||||
this.setContent(content);
|
this.setContent(content);
|
||||||
}
|
}
|
||||||
@ -36,58 +36,58 @@ class Popup {
|
|||||||
showNextTo(elementRect, content) {
|
showNextTo(elementRect, content) {
|
||||||
this.inject();
|
this.inject();
|
||||||
|
|
||||||
const popupRect = this.popup.getBoundingClientRect();
|
const containerRect = this.container.getBoundingClientRect();
|
||||||
|
|
||||||
let posX = elementRect.left;
|
let posX = elementRect.left;
|
||||||
if (posX + popupRect.width >= window.innerWidth) {
|
if (posX + containerRect.width >= window.innerWidth) {
|
||||||
posX = window.innerWidth - popupRect.width;
|
posX = window.innerWidth - containerRect.width;
|
||||||
}
|
}
|
||||||
|
|
||||||
let posY = elementRect.bottom + this.offset;
|
let posY = elementRect.bottom + this.offset;
|
||||||
if (posY + popupRect.height >= window.innerHeight) {
|
if (posY + containerRect.height >= window.innerHeight) {
|
||||||
posY = elementRect.top - popupRect.height - this.offset;
|
posY = elementRect.top - containerRect.height - this.offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.showAt({x: posX, y: posY}, content);
|
this.showAt({x: posX, y: posY}, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
visible() {
|
visible() {
|
||||||
return this.popup !== null && this.popup.style.visibility !== 'hidden';
|
return this.container !== null && this.container.style.visibility !== 'hidden';
|
||||||
}
|
}
|
||||||
|
|
||||||
hide() {
|
hide() {
|
||||||
if (this.popup !== null) {
|
if (this.container !== null) {
|
||||||
this.popup.style.visibility = 'hidden';
|
this.container.style.visibility = 'hidden';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setContent(content) {
|
setContent(content) {
|
||||||
if (this.popup === null) {
|
if (this.container === null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const doc = this.popup.contentDocument;
|
const doc = this.container.contentDocument;
|
||||||
doc.open();
|
doc.open();
|
||||||
doc.write(content);
|
doc.write(content);
|
||||||
doc.close();
|
doc.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
invokeApi(action, params) {
|
invokeApi(action, params) {
|
||||||
if (this.popup !== null) {
|
if (this.container !== null) {
|
||||||
this.popup.contentWindow.postMessage({action, params}, '*');
|
this.container.contentWindow.postMessage({action, params}, '*');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inject() {
|
inject() {
|
||||||
if (this.popup !== null) {
|
if (this.container !== null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.popup = document.createElement('iframe');
|
this.container = document.createElement('iframe');
|
||||||
this.popup.id = 'yomichan-popup';
|
this.container.id = 'yomichan-popup';
|
||||||
this.popup.addEventListener('mousedown', e => e.stopPropagation());
|
this.container.addEventListener('mousedown', e => e.stopPropagation());
|
||||||
this.popup.addEventListener('scroll', e => e.stopPropagation());
|
this.container.addEventListener('scroll', e => e.stopPropagation());
|
||||||
|
|
||||||
document.body.appendChild(this.popup);
|
document.body.appendChild(this.container);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user