From 4d7940e8e4ceb0b90439fc9726339f796ee23940 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Fri, 8 Nov 2019 22:08:11 -0500 Subject: Optimize dictFieldFormat --- ext/mixed/js/extension.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'ext/mixed') diff --git a/ext/mixed/js/extension.js b/ext/mixed/js/extension.js index 54862e19..12ed9c1f 100644 --- a/ext/mixed/js/extension.js +++ b/ext/mixed/js/extension.js @@ -133,3 +133,18 @@ function promiseTimeout(delay, resolveValue) { return promise; } + +function stringReplaceAsync(str, regex, replacer) { + let match; + let index = 0; + const parts = []; + while ((match = regex.exec(str)) !== null) { + parts.push(str.substring(index, match.index), replacer(...match, match.index, str)); + index = regex.lastIndex; + } + if (parts.length === 0) { + return Promise.resolve(str); + } + parts.push(str.substring(index)); + return Promise.all(parts).then(v => v.join('')); +} -- cgit v1.2.3 From 4ac41283880fdbdf9bf0b82e255004a300d62e8b Mon Sep 17 00:00:00 2001 From: siikamiika Date: Sun, 10 Nov 2019 03:15:55 +0200 Subject: search page checkbox styling Change checkboxes to color-inverting icons --- ext/bg/search.html | 14 +++++--------- ext/mixed/css/display-dark.css | 6 ++++++ ext/mixed/css/display-default.css | 6 ++++++ ext/mixed/css/display.css | 16 ++++++++++++++++ 4 files changed, 33 insertions(+), 9 deletions(-) (limited to 'ext/mixed') diff --git a/ext/bg/search.html b/ext/bg/search.html index c7f97712..54c5fb6c 100644 --- a/ext/bg/search.html +++ b/ext/bg/search.html @@ -25,18 +25,14 @@

Search your installed dictionaries by entering a Japanese expression into the field below.

-
+
- + + - + +
diff --git a/ext/mixed/css/display-dark.css b/ext/mixed/css/display-dark.css index 34a0ccd1..681d248c 100644 --- a/ext/mixed/css/display-dark.css +++ b/ext/mixed/css/display-dark.css @@ -48,3 +48,9 @@ hr { border-top-color: #2f2f2f; } .expression-rare, .expression-rare .kanji-link { color: #666666; } + +.icon-checkbox:checked + label { + /* invert colors */ + background-color: #d4d4d4; + color: #1e1e1e; +} diff --git a/ext/mixed/css/display-default.css b/ext/mixed/css/display-default.css index 176c5387..add0a9c8 100644 --- a/ext/mixed/css/display-default.css +++ b/ext/mixed/css/display-default.css @@ -48,3 +48,9 @@ hr { border-top-color: #eeeeee; } .expression-rare, .expression-rare .kanji-link { color: #999999; } + +.icon-checkbox:checked + label { + /* invert colors */ + background-color: #333333; + color: #ffffff; +} diff --git a/ext/mixed/css/display.css b/ext/mixed/css/display.css index 7793ddeb..7ee6f5ac 100644 --- a/ext/mixed/css/display.css +++ b/ext/mixed/css/display.css @@ -73,6 +73,22 @@ ol, ul { } +/* + * Search page + */ + +.icon-checkbox { + display: none; +} + +.icon-checkbox + label { + cursor: pointer; + font-size: 22px; + padding: 2px; + user-select: none; +} + + /* * Entries */ -- cgit v1.2.3 From fd17a0fccd54229bf071899be96dbdab3cd12f02 Mon Sep 17 00:00:00 2001 From: sabs Date: Sat, 9 Nov 2019 13:51:53 -0800 Subject: Remove Download check when resolving Audio data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is a bug (seemingly unreported) in Yomichan where an Anki card will not contain any audio if the JapanesePod101 audio source trumps a secondary audio source (e.g. JapanesePod101-alternate) where the jpod101 source can't find the word requested. For example, そして has an audio entry in the alternate source but not the standard source. (Alternatively, there may be a bug in the jpod101 audioUrlBuilder, because I've only noticed this problem with hiragana-only expressions. JPod101 may not host those on the same url scheme any more. I'm not sure how to fix that, though, and the bug I'm addressing here does still persist). The reason this happens is that audioGetFromUrl uses downloaded audio to effectively check for a 404 (by examining the audio duration), but that check doesn't happen when an Anki card is being created (i.e. "download" is set, which I've changed to "willDownload" here). This change removes that check, but retains the will-download intent information to prevent attempts to download tts data, which AnkiConnect cannot do. I've also added a short explanation as to why the download check happens where it does. I think the unused audio object will get garbage collected since it's not referenced again, but I've explicitly unset it as well. --- ext/mixed/js/audio.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'ext/mixed') diff --git a/ext/mixed/js/audio.js b/ext/mixed/js/audio.js index cf8b8d24..8198f5ec 100644 --- a/ext/mixed/js/audio.js +++ b/ext/mixed/js/audio.js @@ -88,19 +88,15 @@ class TextToSpeechAudio { } -function audioGetFromUrl(url, download) { +function audioGetFromUrl(url, willDownload) { const tts = TextToSpeechAudio.createFromUri(url); if (tts !== null) { - if (download) { - throw new Error('Download not supported for text-to-speech'); + if (willDownload) { + throw new Error('AnkiConnect does not support downloading text-to-speech audio.'); } return Promise.resolve(tts); } - if (download) { - return Promise.resolve(null); - } - return new Promise((resolve, reject) => { const audio = new Audio(url); audio.addEventListener('loadeddata', () => { @@ -115,7 +111,7 @@ function audioGetFromUrl(url, download) { }); } -async function audioGetFromSources(expression, sources, optionsContext, download, cache=null) { +async function audioGetFromSources(expression, sources, optionsContext, willDownload, cache=null) { const key = `${expression.expression}:${expression.reading}`; if (cache !== null && cache.hasOwnProperty(expression)) { return cache[key]; @@ -129,7 +125,11 @@ async function audioGetFromSources(expression, sources, optionsContext, download } try { - const audio = await audioGetFromUrl(url, download); + const audio = await audioGetFromUrl(url, willDownload); + if (willDownload) { + // AnkiConnect handles downloading URLs into cards + audio = null + } const result = {audio, url, source}; if (cache !== null) { cache[key] = result; -- cgit v1.2.3 From 6f530304693534bfac41dfbe77cbbd9c79387617 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sun, 10 Nov 2019 12:25:28 -0500 Subject: Use for of loop instead of forEach --- ext/mixed/js/display.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'ext/mixed') diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index 6d992897..df887fb0 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -279,9 +279,9 @@ class Display { } addEventListeners(selector, type, listener, options) { - this.container.querySelectorAll(selector).forEach((node) => { + for (const node of this.container.querySelectorAll(selector)) { Display.addEventListener(this.eventListeners, node, type, listener, options); - }); + } } setContent(type, details) { -- cgit v1.2.3 From 75883ed885961e2252f972e4ce7e9a26ede5cabe Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sun, 3 Nov 2019 16:18:43 -0500 Subject: Remove dexie --- README.md | 1 - ext/bg/background.html | 1 - ext/bg/legal.html | 1 - ext/mixed/lib/dexie.min.js | 3 --- 4 files changed, 6 deletions(-) delete mode 100644 ext/mixed/lib/dexie.min.js (limited to 'ext/mixed') diff --git a/README.md b/README.md index 01c890cb..0efb313d 100644 --- a/README.md +++ b/README.md @@ -257,7 +257,6 @@ versions packaged. * Bootstrap: [homepage](https://getbootstrap.com/) - [snapshot](https://github.com/twbs/bootstrap/releases/download/v3.3.7/bootstrap-3.3.7-dist.zip) - [license](https://github.com/twbs/bootstrap/blob/v3.3.7/LICENSE) * Bootstrap Toggle: [homepage](https://www.bootstraptoggle.com/) - [snapshot](https://github.com/minhur/bootstrap-toggle/archive/b76c094.zip) - [license](https://github.com/minhur/bootstrap-toggle/blob/2.2.0/LICENSE) -* Dexie: [homepage](https://dexie.org/) - [snapshot](https://github.com/dfahlander/Dexie.js/archive/v2.0.0-beta.10.zip) - [license](https://github.com/dfahlander/Dexie.js/blob/v2.0.0-beta.10/LICENSE) * Handlebars: [homepage](https://handlebarsjs.com/) - [snapshot](http://builds.handlebarsjs.com.s3.amazonaws.com/handlebars.min-714a4c4.js) - [license](https://github.com/wycats/handlebars.js/blob/v4.0.6/LICENSE) * jQuery: [homepage](https://blog.jquery.com/) - [snapshot](https://code.jquery.com/jquery-3.2.1.min.js) - [license](https://github.com/jquery/jquery/blob/3.2.1/LICENSE.txt) * JSZip: [homepage](https://stuk.github.io/jszip/) - [snapshot](https://raw.githubusercontent.com/Stuk/jszip/de7f52fbcba485737bef7923a83f0fad92d9f5bc/dist/jszip.min.js) - [license](https://github.com/Stuk/jszip/blob/v3.1.3/LICENSE.markdown) diff --git a/ext/bg/background.html b/ext/bg/background.html index 3ab68639..bbfbd1e1 100644 --- a/ext/bg/background.html +++ b/ext/bg/background.html @@ -14,7 +14,6 @@
- diff --git a/ext/bg/legal.html b/ext/bg/legal.html index 30927da6..377d25ba 100644 --- a/ext/bg/legal.html +++ b/ext/bg/legal.html @@ -42,7 +42,6 @@ and are used in conformance with the Group's Bootstrap v3.3.7
  • Bootstrap Toggle v2.2.0
  • -
  • Dexie v2.0.0-beta.10
  • Handlebars v4.0.6
  • jQuery v3.2.1
  • JSZip v3.1.3
  • diff --git a/ext/mixed/lib/dexie.min.js b/ext/mixed/lib/dexie.min.js deleted file mode 100644 index 81676ce2..00000000 --- a/ext/mixed/lib/dexie.min.js +++ /dev/null @@ -1,3 +0,0 @@ -!function(n,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):n.Dexie=t()}(this,function(){"use strict";function n(n,t){return"object"!=typeof t?n:(Cn(t).forEach(function(e){n[e]=t[e]}),n)}function t(n,t){return Fn.call(n,t)}function e(n,t){"function"==typeof t&&(t=t(Bn(n))),Cn(t).forEach(function(e){r(n,e,t[e])})}function r(e,r,i,o){Mn(e,r,n(i&&t(i,"get")&&"function"==typeof i.get?{get:i.get,set:i.set,configurable:!0}:{value:i,configurable:!0,writable:!0},o))}function i(n){return{from:function(t){return n.prototype=Object.create(t.prototype),r(n.prototype,"constructor",n),{extend:e.bind(null,n.prototype)}}}}function o(n,t){var e,r=Nn(n,t);return r||(e=Bn(n))&&o(e,t)}function u(n,t,e){return qn.call(n,t,e)}function a(n,t){return t(n)}function c(n){var t=setTimeout(n,1e3);clearTimeout(t)}function s(n){if(!n)throw new Error("Assertion Failed")}function f(n){Kn.setImmediate?setImmediate(n):setTimeout(n,0)}function l(n,t){return n.reduce(function(n,e,r){var i=t(e,r);return i&&(n[i[0]]=i[1]),n},{})}function h(n,t){return function(){try{n.apply(this,arguments)}catch(n){t(n)}}}function d(n,t,e){try{n.apply(null,e)}catch(n){t&&t(n)}}function v(n,e){if(t(n,e))return n[e];if(!e)return n;if("string"!=typeof e){for(var r=[],i=0,o=e.length;i=0)e=n;else{e=n.constructor?Object.create(n.constructor.prototype):{};for(var o in n)t(n,o)&&(e[o]=b(n[o]))}return e}function w(n,e,r,i){return r=r||{},i=i||"",Cn(n).forEach(function(o){if(t(e,o)){var u=n[o],a=e[o];"object"==typeof u&&"object"==typeof a&&u&&a&&u.constructor===a.constructor?w(u,a,r,i+o+"."):u!==a&&(r[i+o]=e[o])}else r[i+o]=void 0}),Cn(e).forEach(function(o){t(n,o)||(r[i+o]=e[o])}),r}function _(n){var t,e,r,i;if(1===arguments.length){if(Tn(n))return n.slice();if(this===Ln&&"string"==typeof n)return[n];if(i=zn(n)){for(e=[];r=i.next(),!r.done;)e.push(r.value);return e}if(null==n)return[n];if(t=n.length,"number"==typeof t){for(e=new Array(t);t--;)e[t]=n[t];return e}return[n]}for(t=arguments.length,e=new Array(t);t--;)e[t]=arguments[t];return e}function k(n,t){Wn=n,Qn=t}function x(){if(Hn)try{throw x.arguments,new Error}catch(n){return n}return new Error}function j(n,t){var e=n.stack;return e?(t=t||0,0===e.indexOf(n.name)&&(t+=(n.name+n.message).split("\n").length),e.split("\n").slice(t).filter(Qn).map(function(n){return"\n"+n}).join("")):""}function E(n,t){return function(){return console.warn(n+" is deprecated. See https://github.com/dfahlander/Dexie.js/wiki/Deprecations. "+j(x(),1)),t.apply(this,arguments)}}function P(n,t){this._e=x(),this.name=n,this.message=t}function A(n,t){return n+". Errors: "+t.map(function(n){return n.toString()}).filter(function(n,t,e){return e.indexOf(n)===t}).join("\n")}function O(n,t,e,r){this._e=x(),this.failures=t,this.failedKeys=r,this.successCount=e}function S(n,t){this._e=x(),this.name="BulkError",this.failures=t,this.message=A(n,t)}function I(n,t){if(!n||n instanceof P||n instanceof TypeError||n instanceof SyntaxError||!n.name||!tt[n.name])return n;var e=new tt[n.name](t||n.message,n);return"stack"in n&&r(e,"stack",{get:function(){return this.inner.stack}}),e}function D(){}function C(n){return n}function T(n,t){return null==n||n===C?t:function(e){return t(n(e))}}function K(n,t){return function(){n.apply(this,arguments),t.apply(this,arguments)}}function B(n,t){return n===D?t:function(){var e=n.apply(this,arguments);void 0!==e&&(arguments[0]=e);var r=this.onsuccess,i=this.onerror;this.onsuccess=null,this.onerror=null;var o=t.apply(this,arguments);return r&&(this.onsuccess=this.onsuccess?K(r,this.onsuccess):r),i&&(this.onerror=this.onerror?K(i,this.onerror):i),void 0!==o?o:e}}function F(n,t){return n===D?t:function(){n.apply(this,arguments);var e=this.onsuccess,r=this.onerror;this.onsuccess=this.onerror=null,t.apply(this,arguments),e&&(this.onsuccess=this.onsuccess?K(e,this.onsuccess):e),r&&(this.onerror=this.onerror?K(r,this.onerror):r)}}function M(t,e){return t===D?e:function(r){var i=t.apply(this,arguments);n(r,i);var o=this.onsuccess,u=this.onerror;this.onsuccess=null,this.onerror=null;var a=e.apply(this,arguments);return o&&(this.onsuccess=this.onsuccess?K(o,this.onsuccess):o),u&&(this.onerror=this.onerror?K(u,this.onerror):u),void 0===i?void 0===a?void 0:a:n(i,a)}}function N(n,t){return n===D?t:function(){return t.apply(this,arguments)!==!1&&n.apply(this,arguments)}}function q(n,t){return n===D?t:function(){var e=n.apply(this,arguments);if(e&&"function"==typeof e.then){for(var r=this,i=arguments.length,o=new Array(i);i--;)o[i]=arguments[i];return e.then(function(){return t.apply(r,o)})}return t.apply(this,arguments)}}function R(n){if("object"!=typeof this)throw new TypeError("Promises must be constructed via new");this._listeners=[],this.onuncatched=D,this._lib=!1;var t=this._PSD=Et;if(Wn&&(this._stackHolder=x(),this._prev=null,this._numPrev=0),"function"!=typeof n){if(n!==rt)throw new TypeError("Not a function");return this._state=arguments[1],this._value=arguments[2],void(this._state===!1&&z(this,this._value))}this._state=null,this._value=null,++t.ref,V(this,n)}function U(n,t,e,r,i){this.onFulfilled="function"==typeof n?n:null,this.onRejected="function"==typeof t?t:null,this.resolve=e,this.reject=r,this.psd=i}function V(n,t){try{t(function(t){if(null===n._state){if(t===n)throw new TypeError("A promise cannot be resolved with itself.");var e=n._lib&&Y();t&&"function"==typeof t.then?V(n,function(n,e){t instanceof R?t._then(n,e):t.then(n,e)}):(n._state=!0,n._value=t,L(n)),e&&$()}},z.bind(null,n))}catch(t){z(n,t)}}function z(n,t){if(_t.push(t),null===n._state){var e=n._lib&&Y();t=xt(t),n._state=!1,n._value=t,Wn&&null!==t&&"object"==typeof t&&!t._promise&&d(function(){var e=o(t,"stack");t._promise=n,r(t,"stack",{get:function(){return pt?e&&(e.get?e.get.apply(t):e.value):n.stack}})}),nn(n),L(n),e&&$()}}function L(n){var t=n._listeners;n._listeners=[];for(var e=0,r=t.length;e0;)for(n=Pt,Pt=[],e=n.length,t=0;t0);gt=!0,bt=!0}function X(){var n=wt;wt=[],n.forEach(function(n){n._PSD.onunhandled.call(null,n._value,n)});for(var t=Ot.slice(0),e=t.length;e;)t[--e]()}function Z(n){function t(){n(),Ot.splice(Ot.indexOf(t),1)}Ot.push(t),++At,mt(function(){0===--At&&X()},[])}function nn(n){wt.some(function(t){return t._value===n._value})||wt.push(n)}function tn(n){for(var t=wt.length;t;)if(wt[--t]._value===n._value)return void wt.splice(t,1)}function en(n){return new R(rt,!1,n)}function rn(n,t){var e=Et;return function(){var r=Y(),i=Et;try{return ln(e,!0),n.apply(this,arguments)}catch(n){t&&t(n)}finally{ln(i,!1),r&&$()}}}function on(t,e,r,i){var o=Et,u=Object.create(o);u.parent=o,u.ref=0,u.global=!1,u.id=++Bt;var a=jt.env;u.env=vt?{Promise:R,all:R.all,race:R.race,resolve:R.resolve,reject:R.reject,nthen:yn(a.nthen,u),gthen:yn(a.gthen,u)}:{},e&&n(u,e),++o.ref,u.finalize=function(){--this.parent.ref||this.parent.finalize()};var c=dn(u,t,r,i);return 0===u.ref&&u.finalize(),c}function un(){return It.id||(It.id=++Dt),++It.awaits,It.echoes+=ut,It.id}function an(n){!It.awaits||n&&n!==It.id||(0===--It.awaits&&(It.id=0),It.echoes=It.awaits*ut)}function cn(n){return It.echoes&&n&&n.constructor===ht?(un(),n.then(function(n){return an(),n},function(n){return an(),Nt(n)})):n}function sn(n){++Kt,It.echoes&&0!==--It.echoes||(It.echoes=It.id=0),Ct.push(Et),ln(n,!0)}function fn(){var n=Ct[Ct.length-1];Ct.pop(),ln(n,!1)}function ln(n,t){var e=Et;if((t?!It.echoes||Tt++&&n===Et:!Tt||--Tt&&n===Et)||vn(t?sn.bind(null,n):fn),n!==Et&&(Et=n,e===jt&&(jt.env=hn()),vt)){var r=jt.env.Promise,i=n.env;st.then=i.nthen,r.prototype.then=i.gthen,(e.global||n.global)&&(Kn.Promise=i.Promise,r.all=i.all,r.race=i.race,r.resolve=i.resolve,r.reject=i.reject)}}function hn(){var n=Kn.Promise;return vt?{Promise:n,all:n.all,race:n.race,resolve:n.resolve,reject:n.reject,nthen:st.then,gthen:n.prototype.then}:{}}function dn(n,t,e,r,i){var o=Et;try{return ln(n,!0),t(e,r,i)}finally{ln(o,!1)}}function vn(n){lt.call(ct,n)}function pn(n,t,e){return"function"!=typeof n?n:function(){var r=Et;e&&un(),ln(t,!0);try{return n.apply(this,arguments)}finally{ln(r,!1)}}}function yn(n,t){return function(e,r){return n.call(this,pn(e,t,!1),pn(r,t,!1))}}function mn(t,e){var r;try{r=e.onuncatched(t)}catch(n){}if(r!==!1)try{var i,o={promise:e,reason:t};if(Kn.document&&document.createEvent?(i=document.createEvent("Event"),i.initEvent(Ft,!0,!0),n(i,o)):Kn.CustomEvent&&(i=new CustomEvent(Ft,{detail:o}),n(i,o)),i&&Kn.dispatchEvent&&(dispatchEvent(i),!Kn.PromiseRejectionEvent&&Kn.onunhandledrejection))try{Kn.onunhandledrejection(i)}catch(n){}i.defaultPrevented||console.warn("Unhandled rejection: "+(t.stack||t))}catch(n){}}function gn(n){function t(n,t,o){if("object"==typeof n)return e(n);t||(t=N),o||(o=D);var u={subscribers:[],fire:o,subscribe:function(n){u.subscribers.indexOf(n)===-1&&(u.subscribers.push(n),u.fire=t(u.fire,n))},unsubscribe:function(n){u.subscribers=u.subscribers.filter(function(t){return t!==n}),u.fire=u.subscribers.reduce(t,o)}};return r[n]=i[n]=u,u}function e(n){Cn(n).forEach(function(e){var r=n[e];if(Tn(r))t(e,n[e][0],n[e][1]);else{if("asap"!==r)throw new nt.InvalidArgument("Invalid event config");var i=t(e,C,function(){for(var n=arguments.length,t=new Array(n);n--;)t[n]=arguments[n];i.subscribers.forEach(function(n){f(function(){n.apply(null,t)})})})}})}var r={},i=function(t,e){if(e){for(var i=arguments.length,o=new Array(i-1);--i;)o[i-1]=arguments[i];return r[t].subscribe.apply(null,o),n}if("string"==typeof t)return r[t]};i.addEventType=t;for(var o=1,u=arguments.length;o0?console.warn("Another connection wants to upgrade database '"+et.name+"'. Closing db now to resume the upgrade."):console.warn("Another connection wants to delete database '"+et.name+"'. Closing db now to resume the delete request."),et.close()}),et.on("blocked",function(n){!n.newVersion||n.newVersionn});return a.forEach(function(n){i.push(function(){var r=Vn,i=n._cfg.dbschema;yn(r,e),yn(i,e),Vn=et._dbSchema=i;var o=P(r,i);if(o.add.forEach(function(n){A(e,n[0],n[1].primKey,n[1].indexes)}),o.change.forEach(function(n){if(n.recreate)throw new nt.Upgrade("Not yet support for changing primary key");var t=e.objectStore(n.name);n.add.forEach(function(n){N(t,n)}),n.change.forEach(function(n){t.deleteIndex(n.name),N(t,n)}),n.del.forEach(function(n){t.deleteIndex(n)})}),n._cfg.contentUpgrade)return u=!0,R.follow(function(){n._cfg.contentUpgrade(t)})}),i.push(function(t){if(!u||!Ht){var e=n._cfg.dbschema;K(e,t)}})}),r().then(function(){I(Vn,e)})}function P(n,t){var e={del:[],add:[],change:[]};for(var r in n)t[r]||e.del.push(r);for(r in t){var i=n[r],o=t[r];if(i){var u={name:r,def:o,recreate:!1,del:[],add:[],change:[]};if(i.primKey.src!==o.primKey.src)u.recreate=!0,e.change.push(u);else{var a=i.idxByName,c=o.idxByName;for(var s in a)c[s]||u.del.push(s);for(s in c){var f=a[s],l=c[s];f?f.src!==l.src&&u.change.push(l):u.add.push(l)}(u.del.length>0||u.add.length>0||u.change.length>0)&&e.change.push(u)}}else e.add.push([r,o])}return e}function A(n,t,e,r){var i=n.db.createObjectStore(t,e.keyPath?{keyPath:e.keyPath,autoIncrement:e.auto}:{autoIncrement:e.auto});return r.forEach(function(n){N(i,n)}),i}function I(n,t){Cn(n).forEach(function(e){t.db.objectStoreNames.contains(e)||A(t,e,n[e].primKey,n[e].indexes)})}function K(n,t){for(var e=0;e0?n:t}function sn(n,t){return Rn.cmp(n,t)}function fn(n,t){return Rn.cmp(t,n)}function ln(n,t){return nt?-1:n===t?0:1}function vn(n,t){return n?t?function(){return n.apply(this,arguments)&&t.apply(this,arguments)}:n:t}function pn(){if(et.verno=Gn.version/10,et._dbSchema=Vn={},Qn=u(Gn.objectStoreNames,0),0!==Qn.length){var n=Gn.transaction(In(Qn),"readonly");Qn.forEach(function(t){for(var e=n.objectStore(t),r=e.keyPath,i=r&&"string"==typeof r&&r.indexOf(".")!==-1,o=new On(r,r||"",!1,!1,!!e.autoIncrement,r&&"string"!=typeof r,i),u=[],a=0;aMath.pow(2,62)?0:n.oldVersion;k(u/10,t,e,r)}},e),r.onsuccess=rn(function(){if(t=null,Gn=r.result,Wt.push(et),ot)pn();else if(Gn.objectStoreNames.length>0)try{yn(Vn,Gn.transaction(In(Gn.objectStoreNames),Zn))}catch(n){}Gn.onversionchange=rn(function(n){et._vcFired=!0,et.on("versionchange").fire(n)}),ut||"__dbnames"===i||Mt.dbnames.put({name:i}).catch(D),n()},e)})]).then(function(){return $n=[],R.resolve(bn.vip(et.on.ready.fire)).then(function n(){if($n.length>0){var t=$n.reduce(q,D);return $n=[],R.resolve(bn.vip(t)).then(n)}})}).finally(function(){$n=null}).then(function(){return Yn=!1,et}).catch(function(n){try{t&&t.abort()}catch(n){}return Yn=!1,et.close(),Jn=n,Nt(Jn)}).finally(function(){Xn=!0,n()})},this.close=function(){var n=Wt.indexOf(et);if(n>=0&&Wt.splice(n,1),Gn){try{Gn.close()}catch(n){}Gn=null}qn=!1,Jn=new nt.DatabaseClosed,Yn&&Kn(Jn),rt=new R(function(n){wn=n}),it=new R(function(n,t){Kn=t})},this.delete=function(){var n=arguments.length>0;return new R(function(t,e){function r(){et.close();var n=Rn.deleteDatabase(i);n.onsuccess=rn(function(){ut||Mt.dbnames.delete(i).catch(D),t()}),n.onerror=xn(e),n.onblocked=mn}if(n)throw new nt.InvalidArgument("Arguments not allowed in db.delete()");Yn?rt.then(r):r()})},this.backendDB=function(){return Gn},this.isOpen=function(){return null!==Gn},this.hasBeenClosed=function(){return Jn&&Jn instanceof nt.DatabaseClosed},this.hasFailed=function(){return null!==Jn},this.dynamicallyOpened=function(){return ot},this.name=i,e(this,{tables:{get:function(){return Cn(Hn).map(function(n){return Hn[n]})}}}),this.on=gn(this,"populate","blocked","versionchange",{ready:[q,D]}),this.on.ready.subscribe=a(this.on.ready.subscribe,function(n){return function(t,e){bn.vip(function(){Xn?(Jn||R.resolve().then(t),e&&n(t)):$n?($n.push(t),e&&n(t)):(n(t),e||n(function n(){et.on.ready.unsubscribe(t),et.on.ready.unsubscribe(n)}))})}}),Yt(function(){et.on("populate").fire(et._createTransaction(tt,Qn,Vn))}),this.transaction=function(){var n=V.apply(this,arguments);return this._transaction.apply(this,n)},this._transaction=function(n,t,e){function r(){return R.resolve().then(function(){var t=Et.transless||Et,r=et._createTransaction(n,u,Vn,i),o={trans:r,transless:t};i?r.idbtrans=i.idbtrans:r.create(),e.constructor===dt&&un();var a,c=R.follow(function(){if(a=e.call(r,r))if(a.constructor===ht){var n=an.bind(null,null);a.then(n,n)}else"function"==typeof a.next&&"function"==typeof a.throw&&(a=An(a))},o);return(a&&"function"==typeof a.then?R.resolve(a).then(function(n){return r.active?n:Nt(new nt.PrematureCommit("Transaction committed too early. See http://bit.ly/2eVASrf"))}):c.then(function(){return a})).then(function(n){return i&&r._resolve(),r._completion.then(function(){return n})}).catch(function(n){return r._reject(n),Nt(n)})})}var i=Et.trans;i&&i.db===et&&n.indexOf("!")===-1||(i=null);var o=n.indexOf("?")!==-1;n=n.replace("!","").replace("?","");try{var u=t.map(function(n){var t=n instanceof z?n.name:n;if("string"!=typeof t)throw new TypeError("Invalid table argument to Dexie.transaction(). Only Table or String are allowed");return t});if("r"==n||n==Zn)n=Zn;else{if("rw"!=n&&n!=tt)throw new nt.InvalidArgument("Invalid transaction mode: "+n);n=tt}if(i){if(i.mode===Zn&&n===tt){if(!o)throw new nt.SubTransaction("Cannot enter a sub-transaction with READWRITE mode when parent transaction is READONLY");i=null}i&&u.forEach(function(n){if(i&&i.storeNames.indexOf(n)===-1){if(!o)throw new nt.SubTransaction("Table "+n+" not included in parent transaction.");i=null}}),o&&i&&!i.active&&(i=null)}}catch(n){return i?i._promise(null,function(t,e){e(n)}):Nt(n)}return i?i._promise(n,r,"lock"):Et.trans?dn(Et.transless,function(){return et._whenReady(r)}):et._whenReady(r)},this.table=function(n){if($t&&ot)return new z(n);if(!t(Hn,n))throw new nt.InvalidTable("Table "+n+" does not exist");return Hn[n]},e(z.prototype,{_trans:function(n,t,e){var r=this._tx||Et.trans;return r&&r.db===et?r===Et.trans?r._promise(n,t,e):on(function(){return r._promise(n,t,e)},{trans:r,transless:Et.transless||Et}):U(n,[this.name],t)},_idbstore:function(n,t,e){function r(n,e,r){if(r.storeNames.indexOf(i)===-1)throw new nt.NotFound("Table"+i+" not part of transaction");return t(n,e,r.idbtrans.objectStore(i),r)}if($t)return new R(t);var i=this.name;return this._trans(n,r,e)},get:function(n,t){if(n&&n.constructor===Object)return this.where(n).first(t);var e=this;return this._idbstore(Zn,function(t,r,i){$t&&t(e.schema.instanceTemplate);var o=i.get(n);o.onerror=xn(r),o.onsuccess=rn(function(){t(e.hook.reading.fire(o.result))},r)}).then(t)},where:function(n){if("string"==typeof n)return new H(this,n);if(Tn(n))return new H(this,"["+n.join("+")+"]");var t=Cn(n);if(1===t.length)return this.where(t[0]).equals(n[t[0]]);var e=this.schema.indexes.concat(this.schema.primKey).filter(function(n){return n.compound&&t.every(function(t){return n.keyPath.indexOf(t)>=0})&&n.keyPath.every(function(n){return t.indexOf(n)>=0})})[0];if(e&&Ut!==Rt)return this.where(e.name).equals(e.keyPath.map(function(t){return n[t]}));e||console.warn("The query "+JSON.stringify(n)+" on "+this.name+" would benefit of a "+("compound index ["+t.join("+")+"]"));var r=this.schema.idxByName,i=t.reduce(function(t,e){return[t[0]||r[e],t[0]||!r[e]?vn(t[1],function(t){return""+v(t,e)==""+n[e]}):t[1]]},[null,null]),o=i[0];return o?this.where(o.name).equals(n[o.keyPath]).filter(i[1]):e?this.filter(i[1]):this.where(t).equals("")},count:function(n){return this.toCollection().count(n)},offset:function(n){return this.toCollection().offset(n)},limit:function(n){return this.toCollection().limit(n)},reverse:function(){return this.toCollection().reverse()},filter:function(n){return this.toCollection().and(n)},each:function(n){return this.toCollection().each(n)},toArray:function(n){return this.toCollection().toArray(n)},orderBy:function(n){return new G(new H(this,Tn(n)?"["+n.join("+")+"]":n))},toCollection:function(){return new G(new H(this))},mapToClass:function(n,e){this.schema.mappedClass=n;var r=Object.create(n.prototype);e&&_n(r,e),this.schema.instanceTemplate=r;var i=function(e){if(!e)return e;var r=Object.create(n.prototype);for(var i in e)if(t(e,i))try{r[i]=e[i]}catch(n){}return r};return this.schema.readHook&&this.hook.reading.unsubscribe(this.schema.readHook),this.schema.readHook=i,this.hook("reading",i),n},defineClass:function(n){return this.mapToClass(bn.defineClass(n),n)},bulkDelete:function(n){return this.hook.deleting.fire===D?this._idbstore(tt,function(t,e,r,i){t(W(r,i,n,!1,D))}):this.where(":id").anyOf(n).delete().then(function(){})},bulkPut:function(n,t){var e=this;return this._idbstore(tt,function(r,i,o){if(!o.keyPath&&!e.schema.primKey.auto&&!t)throw new nt.InvalidArgument("bulkPut() with non-inbound keys requires keys array in second argument");if(o.keyPath&&t)throw new nt.InvalidArgument("bulkPut(): keys argument invalid on tables with inbound keys");if(t&&t.length!==n.length)throw new nt.InvalidArgument("Arguments objects and keys must have the same length");if(0===n.length)return r();var u,a,c=function(n){0===s.length?r(n):i(new S(e.name+".bulkPut(): "+s.length+" of "+f+" operations failed",s))},s=[],f=n.length,h=e;if(e.hook.creating.fire===D&&e.hook.updating.fire===D){a=L(s);for(var d=0,p=n.length;d=0;--i){var o=y[i];(null==o||m[o])&&(e.push(n[i]),t&&r.push(o),null!=o&&(m[o]=null))}return e.reverse(),t&&r.reverse(),h.bulkAdd(e,r)}).then(function(n){var t=y[y.length-1];return null!=t?t:n}):h.bulkAdd(n);g.then(c).catch(S,function(n){s=s.concat(n.failures),c()}).catch(i)}},"locked")},bulkAdd:function(n,t){var e=this,r=this.hook.creating.fire;return this._idbstore(tt,function(i,o,u,a){function c(n){0===h.length?i(n):o(new S(e.name+".bulkAdd(): "+h.length+" of "+y+" operations failed",h))}if(!u.keyPath&&!e.schema.primKey.auto&&!t)throw new nt.InvalidArgument("bulkAdd() with non-inbound keys requires keys array in second argument");if(u.keyPath&&t)throw new nt.InvalidArgument("bulkAdd(): keys argument invalid on tables with inbound keys");if(t&&t.length!==n.length)throw new nt.InvalidArgument("Arguments objects and keys must have the same length");if(0===n.length)return i();var s,f,l,h=[],y=n.length;if(r!==D){var m,g=u.keyPath;f=L(h,null,!0),l=kn(null),d(function(){for(var e=0,i=n.length;e0&&!this._locked();){var n=this._blockedFuncs.shift();try{dn(n[1],n[0])}catch(n){}}return this},_locked:function(){return this._reculock&&Et.lockOwnerFor!==this},create:function(n){var t=this;if(!this.mode)return this;if(s(!this.idbtrans),!n&&!Gn)switch(Jn&&Jn.name){case"DatabaseClosedError":throw new nt.DatabaseClosed(Jn);case"MissingAPIError":throw new nt.MissingAPI(Jn.message,Jn);default:throw new nt.OpenFailed(Jn)}if(!this.active)throw new nt.TransactionInactive;return s(null===this._completion._state),n=this.idbtrans=n||Gn.transaction(In(this.storeNames),this.mode),n.onerror=rn(function(e){Pn(e),t._reject(n.error)}),n.onabort=rn(function(n){Pn(n),t.active&&t._reject(new nt.Abort),t.active=!1,t.on("abort").fire(n)}),n.oncomplete=rn(function(){t.active=!1,t._resolve()}),this},_promise:function(n,t,e){var r=this;if(n===tt&&this.mode!==tt)return Nt(new nt.ReadOnly("Transaction is readonly"));if(!this.active)return Nt(new nt.TransactionInactive);if(this._locked())return new R(function(i,o){r._blockedFuncs.push([function(){r._promise(n,t,e).then(i,o)},Et])});if(e)return on(function(){var n=new R(function(n,e){r._lock();var i=t(n,e,r);i&&i.then&&i.then(n,e)});return n.finally(function(){return r._unlock()}),n._lib=!0,n});var i=new R(function(n,e){var i=t(n,e,r);i&&i.then&&i.then(n,e)});return i._lib=!0,i},_root:function(){return this.parent?this.parent._root():this},waitFor:function(n){var t=this._root();if(n=R.resolve(n),t._waitingFor)t._waitingFor=t._waitingFor.then(function(){return n});else{t._waitingFor=n,t._waitingQueue=[];var e=t.idbtrans.objectStore(t.storeNames[0]);!function n(){for(++t._spinCount;t._waitingQueue.length;)t._waitingQueue.shift()();t._waitingFor&&(e.get(-(1/0)).onsuccess=n)}()}var r=t._waitingFor;return new R(function(e,i){n.then(function(n){return t._waitingQueue.push(rn(e.bind(null,n)))},function(n){return t._waitingQueue.push(rn(i.bind(null,n)))}).finally(function(){t._waitingFor===r&&(t._waitingFor=null)})})},abort:function(){this.active&&this._reject(new nt.Abort),this.active=!1},tables:{get:E("Transaction.tables",function(){return Hn})},table:function(n){var t=et.table(n);return new z(n,t.schema,this)}}),e(H.prototype,function(){function n(n,t,e){var r=n instanceof H?new G(n):n;return r._ctx.error=e?new e(t):new TypeError(t),r}function t(n){return new G(n,function(){return Un.only("")}).limit(0)}function e(n){return"next"===n?function(n){return n.toUpperCase()}:function(n){return n.toLowerCase()}}function r(n){return"next"===n?function(n){return n.toLowerCase()}:function(n){return n.toUpperCase()}}function i(n,t,e,r,i,o){for(var u=Math.min(n.length,r.length),a=-1,c=0;c=0?n.substr(0,a)+t[a]+e.substr(a+1):null;i(n[c],s)<0&&(a=c)}return u0)&&(a=s)}return t(null!==a?function(){n.continue(a+p)}:e),!1}),m}return{between:function(e,r,i,o){i=i!==!1,o=o===!0;try{return tn(e,r)>0||0===tn(e,r)&&(i||o)&&(!i||!o)?t(this):new G(this,function(){return Un.bound(e,r,!i,!o)})}catch(t){return n(this,zt)}},equals:function(n){return new G(this,function(){return Un.only(n)})},above:function(n){return new G(this,function(){return Un.lowerBound(n,!0)})},aboveOrEqual:function(n){return new G(this,function(){return Un.lowerBound(n)})},below:function(n){return new G(this,function(){return Un.upperBound(n,!0)})},belowOrEqual:function(n){return new G(this,function(){return Un.upperBound(n)})},startsWith:function(t){return"string"!=typeof t?n(this,Lt):this.between(t,t+Rt,!0,!0)},startsWithIgnoreCase:function(n){return""===n?this.startsWith(n):o(this,function(n,t){return 0===n.indexOf(t[0])},[n],Rt)},equalsIgnoreCase:function(n){return o(this,function(n,t){return n===t[0]},[n],"")},anyOfIgnoreCase:function(){var n=_.apply(Ln,arguments);return 0===n.length?t(this):o(this,function(n,t){return t.indexOf(n)!==-1},n,"")},startsWithAnyOfIgnoreCase:function(){var n=_.apply(Ln,arguments);return 0===n.length?t(this):o(this,function(n,t){return t.some(function(t){return 0===n.indexOf(t)})},n,Rt)},anyOf:function(){var e=_.apply(Ln,arguments),r=sn;try{e.sort(r)}catch(t){return n(this,zt)}if(0===e.length)return t(this);var i=new G(this,function(){return Un.bound(e[0],e[e.length-1])});i._ondirectionchange=function(n){r="next"===n?sn:fn,e.sort(r)};var o=0;return i._addAlgorithm(function(n,t,i){for(var u=n.key;r(u,e[o])>0;)if(++o,o===e.length)return t(i),!1;return 0===r(u,e[o])||(t(function(){n.continue(e[o])}),!1)}),i},notEqual:function(n){return this.inAnyRange([[Vt,n],[n,Ut]],{includeLowers:!1,includeUppers:!1})},noneOf:function(){var t=_.apply(Ln,arguments);if(0===t.length)return new G(this);try{t.sort(sn)}catch(t){return n(this,zt)}var e=t.reduce(function(n,t){return n?n.concat([[n[n.length-1][1],t]]):[[Vt,t]]},null);return e.push([t[t.length-1],Ut]),this.inAnyRange(e,{includeLowers:!1,includeUppers:!1})},inAnyRange:function(e,r){function i(n,t){for(var e=0,r=n.length;e0){i[0]=en(i[0],t[0]),i[1]=cn(i[1],t[1]);break}}return e===r&&n.push(t),n}function o(n,t){return f(n[0],t[0])}function u(n){return!h(n)&&!d(n)}if(0===e.length)return t(this);if(!e.every(function(n){return void 0!==n[0]&&void 0!==n[1]&&sn(n[0],n[1])<=0}))return n(this,"First argument to inAnyRange() must be an Array of two-value Arrays [lower,upper] where upper must not be lower than lower",nt.InvalidArgument);var a,c=!r||r.includeLowers!==!1,s=r&&r.includeUppers===!0,f=sn;try{a=e.reduce(i,[]),a.sort(o)}catch(t){return n(this,zt)}var l=0,h=s?function(n){return sn(n,a[l][1])>0}:function(n){return sn(n,a[l][1])>=0},d=c?function(n){return fn(n,a[l][0])>0}:function(n){return fn(n,a[l][0])>=0},v=h,p=new G(this,function(){return Un.bound(a[0][0],a[a.length-1][1],!c,!s)});return p._ondirectionchange=function(n){"next"===n?(v=h,f=sn):(v=d,f=fn),a.sort(o)},p._addAlgorithm(function(n,t,e){for(var r=n.key;v(r);)if(++l,l===a.length)return t(e),!1;return!!u(r)||0!==tn(r,a[l][1])&&0!==tn(r,a[l][0])&&(t(function(){f===sn?n.continue(a[l][0]):n.continue(a[l][1])}),!1)}),p},startsWithAnyOf:function(){var e=_.apply(Ln,arguments);return e.every(function(n){return"string"==typeof n})?0===e.length?t(this):this.inAnyRange(e.map(function(n){return[n,n+Rt]})):n(this,"startsWithAnyOf() only works with strings")}}}),e(G.prototype,function(){function e(n,t){n.filter=vn(n.filter,t)}function r(n,t,e){var r=n.replayFilter;n.replayFilter=r?function(){return vn(r(),t())}:t,n.justLimit=e&&!r}function i(n,t){n.isMatch=vn(n.isMatch,t)}function o(n,t){if(n.isPrimKey)return t;var e=n.table.schema.idxByName[n.index];if(!e)throw new nt.Schema("KeyPath "+n.index+" on object store "+t.name+" is not indexed");return t.index(e.name)}function u(n,t){var e=o(n,t);return n.keysOnly&&"openKeyCursor"in e?e.openKeyCursor(n.range||null,n.dir+n.unique):e.openCursor(n.range||null,n.dir+n.unique)}function a(n,e,r,i,o){var a=n.replayFilter?vn(n.filter,n.replayFilter()):n.filter;n.or?function(){function c(){2===++l&&r()}function s(n,r,o){if(!a||a(r,o,c,i)){var u=r.primaryKey.toString();t(f,u)||(f[u]=!0,e(n,r,o))}}var f={},l=0;n.or._iterate(s,c,i,o),Z(u(n,o),n.algorithm,s,c,i,!n.keysOnly&&n.valueMapper)}():Z(u(n,o),vn(n.algorithm,a),e,r,i,!n.keysOnly&&n.valueMapper)}function c(n){return n.table.schema.instanceTemplate}return{_read:function(n,t){var e=this._ctx;return e.error?e.table._trans(null,Nt.bind(null,e.error)):e.table._idbstore(Zn,n).then(t)},_write:function(n){var t=this._ctx;return t.error?t.table._trans(null,Nt.bind(null,t.error)):t.table._idbstore(tt,n,"locked")},_addAlgorithm:function(n){var t=this._ctx;t.algorithm=vn(t.algorithm,n)},_iterate:function(n,t,e,r){return a(this._ctx,n,t,e,r)},clone:function(t){var e=Object.create(this.constructor.prototype),r=Object.create(this._ctx);return t&&n(r,t),e._ctx=r,e},raw:function(){return this._ctx.valueMapper=null,this},each:function(n){var t=this._ctx;if($t){var e=c(t),r=t.table.schema.primKey.keyPath,i=v(e,t.index?t.table.schema.idxByName[t.index].keyPath:r),o=v(e,r);n(e,{key:i,primaryKey:o})}return this._read(function(e,r,i){a(t,n,e,r,i)})},count:function(n){if($t)return R.resolve(0).then(n);var t=this._ctx;if(J(t,!0))return this._read(function(n,e,r){var i=o(t,r),u=t.range?i.count(t.range):i.count();u.onerror=xn(e),u.onsuccess=function(e){n(Math.min(e.target.result,t.limit))}},n);var e=0;return this._read(function(n,r,i){a(t,function(){return++e,!1},function(){n(e)},r,i)},n)},sortBy:function(n,t){function e(n,t){return t?e(n[i[t]],t-1):n[o]}function r(n,t){var r=e(n,u),i=e(t,u);return ri?a:0}var i=n.split(".").reverse(),o=i[0],u=i.length-1,a="next"===this._ctx.dir?1:-1;return this.toArray(function(n){return n.sort(r)}).then(t)},toArray:function(n){var t=this._ctx;return this._read(function(n,e,r){if($t&&n([c(t)]),Bn&&"next"===t.dir&&J(t,!0)&&t.limit>0){var i=t.table.hook.reading.fire,u=o(t,r),s=t.limit<1/0?u.getAll(t.range,t.limit):u.getAll(t.range);s.onerror=xn(e),s.onsuccess=jn(i===C?n:function(t){try{n(t.map(i))}catch(n){e(n)}})}else{var f=[];a(t,function(n){f.push(n)},function(){n(f)},e,r)}},n)},offset:function(n){var t=this._ctx;return n<=0?this:(t.offset+=n,J(t)?r(t,function(){var t=n;return function(n,e){return 0===t||(1===t?(--t,!1):(e(function(){n.advance(t),t=0}),!1))}}):r(t,function(){var t=n;return function(){return--t<0}}),this)},limit:function(n){return this._ctx.limit=Math.min(this._ctx.limit,n),r(this._ctx,function(){var t=n;return function(n,e,r){return--t<=0&&e(r),t>=0}},!0),this},until:function(n,t){var r=this._ctx;return $t&&n(c(r)),e(this._ctx,function(e,r,i){return!n(e.value)||(r(i),t)}),this},first:function(n){return this.limit(1).toArray(function(n){return n[0]}).then(n)},last:function(n){return this.reverse().first(n)},filter:function(n){return $t&&n(c(this._ctx)),e(this._ctx,function(t){return n(t.value)}),i(this._ctx,n),this},and:function(n){return this.filter(n)},or:function(n){return new H(this._ctx.table,n,this)},reverse:function(){return this._ctx.dir="prev"===this._ctx.dir?"next":"prev",this._ondirectionchange&&this._ondirectionchange(this._ctx.dir),this},desc:function(){return this.reverse()},eachKey:function(n){var t=this._ctx;return t.keysOnly=!t.isMatch,this.each(function(t,e){n(e.key,e)})},eachUniqueKey:function(n){return this._ctx.unique="unique",this.eachKey(n)},eachPrimaryKey:function(n){var t=this._ctx;return t.keysOnly=!t.isMatch,this.each(function(t,e){n(e.primaryKey,e)})},keys:function(n){var t=this._ctx;t.keysOnly=!t.isMatch;var e=[];return this.each(function(n,t){e.push(t.key)}).then(function(){return e}).then(n)},primaryKeys:function(n){var t=this._ctx;if(Bn&&"next"===t.dir&&J(t,!0)&&t.limit>0)return this._read(function(n,e,r){var i=o(t,r),u=t.limit<1/0?i.getAllKeys(t.range,t.limit):i.getAllKeys(t.range);u.onerror=xn(e),u.onsuccess=jn(n)}).then(n);t.keysOnly=!t.isMatch;var e=[];return this.each(function(n,t){e.push(t.primaryKey)}).then(function(){return e}).then(n)},uniqueKeys:function(n){return this._ctx.unique="unique",this.keys(n)},firstKey:function(n){return this.limit(1).keys(function(n){return n[0]}).then(n)},lastKey:function(n){return this.reverse().firstKey(n)},distinct:function(){var n=this._ctx,r=n.index&&n.table.schema.idxByName[n.index];if(!r||!r.multi)return this;var i={};return e(this._ctx,function(n){var e=n.primaryKey.toString(),r=t(i,e);return i[e]=!0,!r}),this},modify:function(e){var r=this,i=this._ctx,o=i.table.hook,u=o.updating.fire,a=o.deleting.fire;return $t&&"function"==typeof e&&e.call({value:i.table.schema.instanceTemplate},i.table.schema.instanceTemplate),this._write(function(i,o,c,s){function f(n,e){function r(n){return P.push(n),A.push(i.primKey),h(),!0}S=e.primaryKey;var i={primKey:e.primaryKey,value:n,onsuccess:null,onerror:null};if(y.call(i,n,i)!==!1){var o=!t(i,"value");++x,d(function(){var n=o?e.delete():e.update(i.value);n._hookCtx=i,n.onerror=En(r),n.onsuccess=kn(function(){++j,h()})},r)}else i.onsuccess&&i.onsuccess(i.value)}function l(n){return n&&(P.push(n),A.push(S)),o(new O("Error modifying one or more objects",P,j,A))}function h(){E&&j+P.length===x&&(P.length>0?l():i(j))}var y;if("function"==typeof e)y=u===D&&a===D?e:function(n){var r=b(n);if(e.call(this,n,this)===!1)return!1;if(t(this,"value")){var i=w(r,this.value),o=u.call(this,i,this.primKey,r,s);o&&(n=this.value,Cn(o).forEach(function(t){p(n,t,o[t])}))}else a.call(this,this.primKey,n,s)};else if(u===D){var g=Cn(e),_=g.length;y=function(n){for(var t=!1,r=0;r<_;++r){var i=g[r],o=e[i];v(n,i)!==o&&(p(n,i,o),t=!0)}return t}}else{var k=e;e=m(k),y=function(t){var r=!1,i=u.call(this,e,this.primKey,b(t),s);return i&&n(e,i),Cn(e).forEach(function(n){var i=e[n];v(t,n)!==i&&(p(t,n,i),r=!0)}),i&&(e=m(k)),r}}var x=0,j=0,E=!1,P=[],A=[],S=null;r.clone().raw()._iterate(f,function(){E=!0,h()},l,c)})},delete:function(){var n=this,t=this._ctx,e=t.range,r=t.table.hook.deleting.fire,i=r!==D;if(!i&&J(t)&&(t.isPrimKey&&!Gt||!e))return this._write(function(n,t,r){var i=xn(t),o=e?r.count(e):r.count();o.onerror=i,o.onsuccess=function(){var u=o.result;d(function(){var t=e?r.delete(e):r.clear();t.onerror=i,t.onsuccess=function(){return n(u)}},function(n){return t(n)})}});var o=i?2e3:1e4;return this._write(function(e,u,a,c){var s=0,f=n.clone({keysOnly:!t.isMatch&&!i}).distinct().limit(o).raw(),l=[],h=function(){return f.each(i?function(n,t){l.push([t.primaryKey,t.value])}:function(n,t){l.push(t.primaryKey)}).then(function(){return i?l.sort(function(n,t){return sn(n[0],t[0])}):l.sort(sn),W(a,c,l,i,r)}).then(function(){var n=l.length;return s+=n,l=[],n{},p=F();return [p,Object.getPrototypeOf(p),Promise.resolve(),F.constructor];")()}catch(t){var n=Kn.Promise;return n?[n.resolve(),n.prototype,n.resolve()]:[]}}(),ct=at[0],st=at[1],ft=at[2],lt=st&&st.then,ht=ct&&ct.constructor,dt=at[3],vt=!!ft,pt=!1,yt=ft?function(){ft.then(J)}:Kn.setImmediate?setImmediate.bind(null,J):Kn.MutationObserver?function(){var n=document.createElement("div");new MutationObserver(function(){J(),n=null}).observe(n,{attributes:!0}),n.setAttribute("i","1")}:function(){setTimeout(J,0)},mt=function(n,t){Pt.push([n,t]),bt&&(yt(),bt=!1)},gt=!0,bt=!0,wt=[],_t=[],kt=null,xt=C,jt={id:"global",global:!0,ref:0,unhandleds:[],onunhandled:mn,pgp:!1,env:{},finalize:function(){this.unhandleds.forEach(function(n){try{mn(n[0],n[1])}catch(n){}})}},Et=jt,Pt=[],At=0,Ot=[],St={get:function(){function n(n,r){var i=this,o=!t.global&&(t!==Et||e!==Kt);o&&an();var u=new R(function(e,u){W(i,new U(pn(n,t,o),pn(r,t,o),e,u,t))});return Wn&&G(u,this),u}var t=Et,e=Kt;return n.prototype=rt,n},set:function(n){r(this,"then",n&&n.prototype===rt?St:{get:function(){return n},set:St.set})}};e(R.prototype,{then:St,_then:function(n,t){W(this,new U(null,null,n,t,Et))},catch:function(n){if(1===arguments.length)return this.then(null,n);var t=arguments[0],e=arguments[1];return"function"==typeof t?this.then(null,function(n){return n instanceof t?e(n):en(n)}):this.then(null,function(n){return n&&n.name===t?e(n):en(n)})},finally:function(n){return this.then(function(t){return n(),t},function(t){return n(),en(t)})},stack:{get:function(){if(this._stack)return this._stack;try{pt=!0;var n=H(this,[],ot),t=n.join("\nFrom previous: ");return null!==this._state&&(this._stack=t),t}finally{pt=!1}}},timeout:function(n,t){var e=this;return n<1/0?new R(function(r,i){var o=setTimeout(function(){return i(new nt.Timeout(t))},n);e.then(r,i).finally(clearTimeout.bind(null,o))}):this}}),"undefined"!=typeof Symbol&&Symbol.toStringTag&&r(R.prototype,Symbol.toStringTag,"Promise"),jt.env=hn(),e(R,{all:function(){var n=_.apply(null,arguments).map(cn);return new R(function(t,e){0===n.length&&t([]);var r=n.length;n.forEach(function(i,o){return R.resolve(i).then(function(e){n[o]=e,--r||t(n)},e)})})},resolve:function(n){if(n instanceof R)return n;if(n&&"function"==typeof n.then)return new R(function(t,e){n.then(t,e)});var t=new R(rt,!0,n);return G(t,kt),t},reject:en,race:function(){var n=_.apply(null,arguments).map(cn);return new R(function(t,e){n.map(function(n){return R.resolve(n).then(t,e)})})},PSD:{get:function(){return Et},set:function(n){return Et=n}},newPSD:on,usePSD:dn,scheduler:{get:function(){return mt},set:function(n){mt=n}},rejectionMapper:{get:function(){return xt},set:function(n){xt=n}},follow:function(n,t){return new R(function(e,r){return on(function(t,e){var r=Et;r.unhandleds=[],r.onunhandled=e,r.finalize=K(function(){var n=this;Z(function(){0===n.unhandleds.length?t():e(n.unhandleds[0])})},r.finalize),n()},t,e,r)})}});var It={awaits:0,echoes:0,id:0},Dt=0,Ct=[],Tt=0,Kt=0,Bt=0,Ft="unhandledrejection";c(function(){mt=function(n,t){setTimeout(function(){n.apply(null,t)},0)}});var Mt,Nt=R.reject,qt="2.0.0-beta.10",Rt=String.fromCharCode(65535),Ut=function(){try{return IDBKeyRange.only([[]]),[[]]}catch(n){return Rt}}(),Vt=-(1/0),zt="Invalid key provided. Keys must be of type string, number, Date or Array.",Lt="String expected.",Wt=[],Qt="undefined"!=typeof navigator&&/(MSIE|Trident|Edge)/.test(navigator.userAgent),Ht=Qt,Gt=Qt,Jt=function(n){return!/(dexie\.js|dexie\.min\.js)/.test(n)};k(Wn,Jt);var Yt=function(){},$t=!1,Xt=Kn.idbModules&&Kn.idbModules.shimIndexedDB?Kn.idbModules:{};return e(bn,et),e(bn,{delete:function(n){var t=new bn(n),e=t.delete();return e.onblocked=function(n){return t.on("blocked",n),this},e},exists:function(n){return new bn(n).open().then(function(n){return n.close(),!0}).catch(bn.NoSuchDatabaseError,function(){return!1})},getDatabaseNames:function(n){var t=Dn(bn.dependencies.indexedDB);return t?new R(function(n,e){var r=t();r.onsuccess=function(t){n(u(t.target.result,0))},r.onerror=xn(e)}).then(n):Mt.dbnames.toCollection().primaryKeys(n)},defineClass:function(t){function e(e){e?n(this,e):$t&&_n(this,t)}return e},applyStructure:_n,ignoreTransaction:function(n){return Et.trans?dn(Et.transless,n):n()},vip:function(n){return on(function(){return Et.letThrough=!0,n()})},async:function(n){return function(){try{var t=An(n.apply(this,arguments));return t&&"function"==typeof t.then?t:R.resolve(t)}catch(n){return Nt(n)}}},spawn:function(n,t,e){try{var r=An(n.apply(e,t||[]));return r&&"function"==typeof r.then?r:R.resolve(r)}catch(n){return Nt(n)}},currentTransaction:{get:function(){return Et.trans||null}},waitFor:function(n,t){var e=R.resolve("function"==typeof n?bn.ignoreTransaction(n):n).timeout(t||6e4);return Et.trans?Et.trans.waitFor(e):e},Promise:R,debug:{get:function(){return Wn},set:function(n){k(n,"dexie"===n?function(){return!0}:Jt)}},derive:i,extend:n,props:e,override:a,Events:gn,getByKeyPath:v,setByKeyPath:p,delByKeyPath:y,shallowClone:m,deepClone:b,getObjectDiff:w,asap:f,maxKey:Ut,minKey:Vt,addons:[],connections:Wt,MultiModifyError:nt.Modify,errnames:Xn,IndexSpec:On,TableSchema:Sn,dependencies:{indexedDB:Xt.shimIndexedDB||Kn.indexedDB||Kn.mozIndexedDB||Kn.webkitIndexedDB||Kn.msIndexedDB,IDBKeyRange:Xt.IDBKeyRange||Kn.IDBKeyRange||Kn.webkitIDBKeyRange},semVer:qt,version:qt.split(".").map(function(n){return parseInt(n)}).reduce(function(n,t,e){return n+t/Math.pow(10,2*e)}),fakeAutoComplete:Yt,default:bn,Dexie:bn}),R.rejectionMapper=I,c(function(){bn.fakeAutoComplete=Yt=c,bn.fake=$t=!0}),Mt=new bn("__dbnames"),Mt.version(1).stores({dbnames:"name"}),function(){var n="Dexie.DatabaseNames";if(void 0!==typeof localStorage&&void 0!==Kn.document)try{JSON.parse(localStorage.getItem(n)||"[]").forEach(function(n){return Mt.dbnames.put({name:n}).catch(D)}),localStorage.removeItem(n)}catch(n){}}(),bn}); -//# sourceMappingURL=dist/dexie.min.js.map \ No newline at end of file -- cgit v1.2.3 From d6cdd693c87ffd999cb770172629a256c0b7dde1 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sun, 10 Nov 2019 13:55:37 -0500 Subject: Fix several warnings about name conflicts --- ext/bg/js/settings.js | 12 ++++++------ ext/mixed/js/display.js | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'ext/mixed') diff --git a/ext/bg/js/settings.js b/ext/bg/js/settings.js index 9d95e358..129d5f10 100644 --- a/ext/bg/js/settings.js +++ b/ext/bg/js/settings.js @@ -188,8 +188,8 @@ async function onFormOptionsChanged(e) { await ankiDeckAndModelPopulate(options); ankiErrorShow(); } - } catch (e) { - ankiErrorShow(e); + } catch (error) { + ankiErrorShow(error); } finally { ankiSpinnerShow(false); } @@ -602,8 +602,8 @@ async function onAnkiModelChanged(e) { ankiSpinnerShow(true); await ankiFieldsPopulate(element, options); ankiErrorShow(); - } catch (e) { - ankiErrorShow(e); + } catch (error) { + ankiErrorShow(error); } finally { ankiSpinnerShow(false); } @@ -627,8 +627,8 @@ async function onAnkiFieldTemplatesResetConfirm(e) { $('#field-templates').val(fieldTemplates); onAnkiTemplatesValidateCompile(); await settingsSaveOptions(); - } catch (e) { - ankiErrorShow(e); + } catch (error) { + ankiErrorShow(error); } } diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index df887fb0..5a824561 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -77,8 +77,8 @@ class Display { const definitions = await apiKanjiFind(link.textContent, this.getOptionsContext()); this.setContentKanji(definitions, context); - } catch (e) { - this.onError(e); + } catch (error) { + this.onError(error); } } @@ -140,8 +140,8 @@ class Display { } this.setContentTerms(definitions, context); - } catch (e) { - this.onError(e); + } catch (error) { + this.onError(error); } } -- cgit v1.2.3 From dad685dba42961697c78a26078c0d5a2e0750e8c Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sun, 10 Nov 2019 13:56:06 -0500 Subject: Fix overwriting const value --- ext/mixed/js/audio.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'ext/mixed') diff --git a/ext/mixed/js/audio.js b/ext/mixed/js/audio.js index 8198f5ec..ff50dee1 100644 --- a/ext/mixed/js/audio.js +++ b/ext/mixed/js/audio.js @@ -125,10 +125,10 @@ async function audioGetFromSources(expression, sources, optionsContext, willDown } try { - const audio = await audioGetFromUrl(url, willDownload); + let audio = await audioGetFromUrl(url, willDownload); if (willDownload) { // AnkiConnect handles downloading URLs into cards - audio = null + audio = null; } const result = {audio, url, source}; if (cache !== null) { -- cgit v1.2.3 From d9b44040751846d6b0bbf5fcf6ea4152f6ce9bcc Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sun, 10 Nov 2019 14:00:44 -0500 Subject: Create functions for the cases of isMouseButton jshint was showing a warning that there was no break statement after the first case, which there doesn't need to be. The most straightforward way to fix this without using the unclear // jshint ignore:line is to just have two functions. This change also updates invocations of isMouseButton to use the exact case function, as this will remove the need to check the case of mosueEvent.type. This was done because onMouseMove is invoked at a high frequency. --- ext/fg/js/frontend.js | 40 ++++++++++++++++++++++++++-------------- ext/mixed/js/display.js | 4 ++-- 2 files changed, 28 insertions(+), 16 deletions(-) (limited to 'ext/mixed') diff --git a/ext/fg/js/frontend.js b/ext/fg/js/frontend.js index e67008df..7c62b51b 100644 --- a/ext/fg/js/frontend.js +++ b/ext/fg/js/frontend.js @@ -80,7 +80,7 @@ class Frontend { onMouseMove(e) { this.popupTimerClear(); - if (this.pendingLookup || Frontend.isMouseButton('primary', e)) { + if (this.pendingLookup || Frontend.isMouseButtonDown('primary', e)) { return; } @@ -88,7 +88,7 @@ class Frontend { const scanningModifier = scanningOptions.modifier; if (!( Frontend.isScanningModifierPressed(scanningModifier, e) || - (scanningOptions.middleMouse && Frontend.isMouseButton('auxiliary', e)) + (scanningOptions.middleMouse && Frontend.isMouseButtonDown('auxiliary', e)) )) { return; } @@ -504,18 +504,30 @@ class Frontend { switch (mouseEvent.type) { case 'mouseup': case 'mousedown': - case 'click': switch (button) { - case 'primary': return mouseEvent.button === 0; - case 'secondary': return mouseEvent.button === 2; - case 'auxiliary': return mouseEvent.button === 1; - default: return false; - } - default: switch (button) { - case 'primary': return (mouseEvent.buttons & 0x1) !== 0x0; - case 'secondary': return (mouseEvent.buttons & 0x2) !== 0x0; - case 'auxiliary': return (mouseEvent.buttons & 0x4) !== 0x0; - default: return false; - } + case 'click': + return Frontend.isMouseButtonPressed(button, mouseEvent); + default: + return Frontend.isMouseButtonDown(button, mouseEvent); + } + } + + static isMouseButtonPressed(button, mouseEvent) { + const mouseEventButton = mouseEvent.button; + switch (button) { + case 'primary': return mouseEventButton === 0; + case 'secondary': return mouseEventButton === 2; + case 'auxiliary': return mouseEventButton === 1; + default: return false; + } + } + + static isMouseButtonDown(button, mouseEvent) { + const mouseEventButtons = mouseEvent.buttons; + switch (button) { + case 'primary': return (mouseEventButtons & 0x1) !== 0x0; + case 'secondary': return (mouseEventButtons & 0x2) !== 0x0; + case 'auxiliary': return (mouseEventButtons & 0x4) !== 0x0; + default: return false; } } } diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index 5a824561..801011df 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -83,7 +83,7 @@ class Display { } onGlossaryMouseDown(e) { - if (Frontend.isMouseButton('primary', e)) { + if (Frontend.isMouseButtonPressed('primary', e)) { this.clickScanPrevent = false; } } @@ -93,7 +93,7 @@ class Display { } onGlossaryMouseUp(e) { - if (!this.clickScanPrevent && Frontend.isMouseButton('primary', e)) { + if (!this.clickScanPrevent && Frontend.isMouseButtonPressed('primary', e)) { this.onTermLookup(e); } } -- cgit v1.2.3 From 3a225c3f916d435e04fb30afa731c30c4309fc7f Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Mon, 4 Nov 2019 20:43:40 -0500 Subject: Add details field to apiTermsFind --- ext/bg/js/api.js | 4 ++-- ext/bg/js/backend.js | 2 +- ext/bg/js/search.js | 2 +- ext/bg/js/translator.js | 22 +++++++++++----------- ext/fg/js/api.js | 4 ++-- ext/fg/js/frontend.js | 2 +- ext/mixed/js/display.js | 2 +- 7 files changed, 19 insertions(+), 19 deletions(-) (limited to 'ext/mixed') diff --git a/ext/bg/js/api.js b/ext/bg/js/api.js index c50db76f..df73aa2a 100644 --- a/ext/bg/js/api.js +++ b/ext/bg/js/api.js @@ -72,9 +72,9 @@ async function apiOptionsSave(source) { backend.onOptionsUpdated(source); } -async function apiTermsFind(text, optionsContext) { +async function apiTermsFind(text, details, optionsContext) { const options = await apiOptionsGet(optionsContext); - const [definitions, length] = await utilBackend().translator.findTerms(text, options); + const [definitions, length] = await utilBackend().translator.findTerms(text, details, options); definitions.splice(options.general.maxResults); return {length, definitions}; } diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index 71393467..efad153a 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -179,7 +179,7 @@ Backend.messageHandlers = { optionsGet: ({optionsContext}) => apiOptionsGet(optionsContext), optionsSet: ({changedOptions, optionsContext, source}) => apiOptionsSet(changedOptions, optionsContext, source), kanjiFind: ({text, optionsContext}) => apiKanjiFind(text, optionsContext), - termsFind: ({text, optionsContext}) => apiTermsFind(text, optionsContext), + termsFind: ({text, details, optionsContext}) => apiTermsFind(text, details, optionsContext), definitionAdd: ({definition, mode, context, optionsContext}) => apiDefinitionAdd(definition, mode, context, optionsContext), definitionsAddable: ({definitions, modes, optionsContext}) => apiDefinitionsAddable(definitions, modes, optionsContext), noteView: ({noteId}) => apiNoteView(noteId), diff --git a/ext/bg/js/search.js b/ext/bg/js/search.js index ad579918..abd40640 100644 --- a/ext/bg/js/search.js +++ b/ext/bg/js/search.js @@ -207,7 +207,7 @@ class DisplaySearch extends Display { this.setIntroVisible(!valid, animate); this.updateSearchButton(); if (valid) { - const {definitions} = await apiTermsFind(query, this.optionsContext); + const {definitions} = await apiTermsFind(query, {}, this.optionsContext); this.setContentTerms(definitions, { focus: false, sentence: null, diff --git a/ext/bg/js/translator.js b/ext/bg/js/translator.js index 1cdd79db..dac53f93 100644 --- a/ext/bg/js/translator.js +++ b/ext/bg/js/translator.js @@ -141,23 +141,23 @@ class Translator { return result; } - async findTerms(text, options) { + async findTerms(text, details, options) { switch (options.general.resultOutputMode) { case 'group': - return await this.findTermsGrouped(text, options); + return await this.findTermsGrouped(text, details, options); case 'merge': - return await this.findTermsMerged(text, options); + return await this.findTermsMerged(text, details, options); case 'split': - return await this.findTermsSplit(text, options); + return await this.findTermsSplit(text, details, options); default: return [[], 0]; } } - async findTermsGrouped(text, options) { + async findTermsGrouped(text, details, options) { const dictionaries = dictEnabledSet(options); const titles = Object.keys(dictionaries); - const [definitions, length] = await this.findTermsInternal(text, dictionaries, options.scanning.alphanumeric); + const [definitions, length] = await this.findTermsInternal(text, dictionaries, options.scanning.alphanumeric, details); const definitionsGrouped = dictTermsGroup(definitions, dictionaries); await this.buildTermFrequencies(definitionsGrouped, titles); @@ -171,11 +171,11 @@ class Translator { return [definitionsGrouped, length]; } - async findTermsMerged(text, options) { + async findTermsMerged(text, details, options) { const dictionaries = dictEnabledSet(options); const secondarySearchTitles = Object.keys(options.dictionaries).filter(dict => options.dictionaries[dict].allowSecondarySearches); const titles = Object.keys(dictionaries); - const [definitions, length] = await this.findTermsInternal(text, dictionaries, options.scanning.alphanumeric); + const [definitions, length] = await this.findTermsInternal(text, dictionaries, options.scanning.alphanumeric, details); const {sequencedDefinitions, defaultDefinitions} = await this.getSequencedDefinitions(definitions, options.general.mainDictionary); const definitionsMerged = []; const mergedByTermIndices = new Set(); @@ -209,17 +209,17 @@ class Translator { return [dictTermsSort(definitionsMerged), length]; } - async findTermsSplit(text, options) { + async findTermsSplit(text, details, options) { const dictionaries = dictEnabledSet(options); const titles = Object.keys(dictionaries); - const [definitions, length] = await this.findTermsInternal(text, dictionaries, options.scanning.alphanumeric); + const [definitions, length] = await this.findTermsInternal(text, dictionaries, options.scanning.alphanumeric, details); await this.buildTermFrequencies(definitions, titles); return [definitions, length]; } - async findTermsInternal(text, dictionaries, alphanumeric) { + async findTermsInternal(text, dictionaries, alphanumeric, details) { if (!alphanumeric && text.length > 0) { const c = text[0]; if (!jpIsKana(c) && !jpIsKanji(c)) { diff --git a/ext/fg/js/api.js b/ext/fg/js/api.js index 54818702..945ba076 100644 --- a/ext/fg/js/api.js +++ b/ext/fg/js/api.js @@ -25,8 +25,8 @@ function apiOptionsSet(changedOptions, optionsContext, source) { return utilInvoke('optionsSet', {changedOptions, optionsContext, source}); } -function apiTermsFind(text, optionsContext) { - return utilInvoke('termsFind', {text, optionsContext}); +function apiTermsFind(text, details, optionsContext) { + return utilInvoke('termsFind', {text, details, optionsContext}); } function apiKanjiFind(text, optionsContext) { diff --git a/ext/fg/js/frontend.js b/ext/fg/js/frontend.js index 7c62b51b..6002dfcb 100644 --- a/ext/fg/js/frontend.js +++ b/ext/fg/js/frontend.js @@ -413,7 +413,7 @@ class Frontend { const searchText = textSource.text(); if (searchText.length === 0) { return null; } - const {definitions, length} = await apiTermsFind(searchText, this.getOptionsContext()); + const {definitions, length} = await apiTermsFind(searchText, {}, this.getOptionsContext()); if (definitions.length === 0) { return null; } textSource.setEndOffset(length); diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index 801011df..8ad3ee1b 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -112,7 +112,7 @@ class Display { try { textSource.setEndOffset(this.options.scanning.length); - ({definitions, length} = await apiTermsFind(textSource.text(), this.getOptionsContext())); + ({definitions, length} = await apiTermsFind(textSource.text(), {}, this.getOptionsContext())); if (definitions.length === 0) { return false; } -- cgit v1.2.3 From 29c38b06b2fd700e7dbf49013ad91d473e65e812 Mon Sep 17 00:00:00 2001 From: siikamiika Date: Wed, 13 Nov 2019 13:51:47 +0200 Subject: only paste Japanese text from clipboard --- ext/bg/js/search.js | 2 +- ext/mixed/js/japanese.js | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'ext/mixed') diff --git a/ext/bg/js/search.js b/ext/bg/js/search.js index ad579918..6f512604 100644 --- a/ext/bg/js/search.js +++ b/ext/bg/js/search.js @@ -248,7 +248,7 @@ class DisplaySearch extends Display { } else if (IS_FIREFOX === false) { curText = (await apiClipboardGet()).trim(); } - if (curText && (curText !== this.clipboardPrevText)) { + if (curText && (curText !== this.clipboardPrevText) && jpIsJapaneseText(curText)) { if (this.isWanakanaEnabled()) { this.query.value = window.wanakana.toKana(curText); } else { diff --git a/ext/mixed/js/japanese.js b/ext/mixed/js/japanese.js index 9f401da7..d24f56a6 100644 --- a/ext/mixed/js/japanese.js +++ b/ext/mixed/js/japanese.js @@ -26,6 +26,15 @@ function jpIsKana(c) { return wanakana.isKana(c); } +function jpIsJapaneseText(text) { + for (const c of text) { + if (jpIsKanji(c) || jpIsKana(c)) { + return true; + } + } + return false; +} + function jpKatakanaToHiragana(text) { let result = ''; for (const c of text) { -- cgit v1.2.3 From f63e8e4be0e7bdb1a2e45e349bf667ea7ca4adab Mon Sep 17 00:00:00 2001 From: siikamiika Date: Tue, 29 Oct 2019 23:49:36 +0200 Subject: add simple query parser --- ext/bg/js/search-query-parser.js | 44 ++++++++++++++++++++++++++++++++++++++++ ext/bg/js/search.js | 24 ++++++++++++++-------- ext/bg/search.html | 3 +++ ext/mixed/css/display.css | 9 ++++++++ ext/mixed/js/display.js | 2 ++ 5 files changed, 74 insertions(+), 8 deletions(-) create mode 100644 ext/bg/js/search-query-parser.js (limited to 'ext/mixed') diff --git a/ext/bg/js/search-query-parser.js b/ext/bg/js/search-query-parser.js new file mode 100644 index 00000000..debe53b4 --- /dev/null +++ b/ext/bg/js/search-query-parser.js @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2019 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 . + */ + + +class QueryParser { + constructor(search) { + this.search = search; + + this.queryParser = document.querySelector('#query-parser'); + + // TODO also enable for mouseover scanning + this.queryParser.addEventListener('click', (e) => this.onTermLookup(e)); + } + + onError(error) { + logError(error, false); + } + + async onTermLookup(e) { + const {textSource} = await this.search.onTermLookup(e, {isQueryParser: true}); + if (textSource) { + textSource.select(); + } + } + + setText(text) { + this.queryParser.innerText = text; + } +} diff --git a/ext/bg/js/search.js b/ext/bg/js/search.js index 56316217..20d0c58c 100644 --- a/ext/bg/js/search.js +++ b/ext/bg/js/search.js @@ -32,6 +32,8 @@ class DisplaySearch extends Display { url: window.location.href }; + this.queryParser = new QueryParser(this); + this.search = document.querySelector('#search'); this.query = document.querySelector('#query'); this.intro = document.querySelector('#intro'); @@ -72,11 +74,11 @@ class DisplaySearch extends Display { const query = DisplaySearch.getSearchQueryFromLocation(window.location.href) || ''; if (e.target.checked) { window.wanakana.bind(this.query); - this.query.value = window.wanakana.toKana(query); + this.setQuery(window.wanakana.toKana(query)); apiOptionsSet({general: {enableWanakana: true}}, this.getOptionsContext()); } else { window.wanakana.unbind(this.query); - this.query.value = query; + this.setQuery(query); apiOptionsSet({general: {enableWanakana: false}}, this.getOptionsContext()); } this.onSearchQueryUpdated(this.query.value, false); @@ -86,9 +88,9 @@ class DisplaySearch extends Display { const query = DisplaySearch.getSearchQueryFromLocation(window.location.href); if (query !== null) { if (this.isWanakanaEnabled()) { - this.query.value = window.wanakana.toKana(query); + this.setQuery(window.wanakana.toKana(query)); } else { - this.query.value = query; + this.setQuery(query); } this.onSearchQueryUpdated(this.query.value, false); } @@ -159,6 +161,7 @@ class DisplaySearch extends Display { e.preventDefault(); const query = this.query.value; + this.queryParser.setText(query); const queryString = query.length > 0 ? `?query=${encodeURIComponent(query)}` : ''; window.history.pushState(null, '', `${window.location.pathname}${queryString}`); this.onSearchQueryUpdated(query, true); @@ -168,9 +171,9 @@ class DisplaySearch extends Display { const query = DisplaySearch.getSearchQueryFromLocation(window.location.href) || ''; if (this.query !== null) { if (this.isWanakanaEnabled()) { - this.query.value = window.wanakana.toKana(query); + this.setQuery(window.wanakana.toKana(query)); } else { - this.query.value = query; + this.setQuery(query); } } @@ -258,9 +261,9 @@ class DisplaySearch extends Display { } if (curText && (curText !== this.clipboardPrevText) && jpIsJapaneseText(curText)) { if (this.isWanakanaEnabled()) { - this.query.value = window.wanakana.toKana(curText); + this.setQuery(window.wanakana.toKana(curText)); } else { - this.query.value = curText; + this.setQuery(curText); } const queryString = curText.length > 0 ? `?query=${encodeURIComponent(curText)}` : ''; @@ -287,6 +290,11 @@ class DisplaySearch extends Display { return this.optionsContext; } + setQuery(query) { + this.query.value = query; + this.queryParser.setText(query); + } + setIntroVisible(visible, animate) { if (this.introVisible === visible) { return; diff --git a/ext/bg/search.html b/ext/bg/search.html index 54c5fb6c..48e7dbf5 100644 --- a/ext/bg/search.html +++ b/ext/bg/search.html @@ -47,6 +47,8 @@
    +
    +
    @@ -67,6 +69,7 @@ + diff --git a/ext/mixed/css/display.css b/ext/mixed/css/display.css index 7ee6f5ac..5e5213ff 100644 --- a/ext/mixed/css/display.css +++ b/ext/mixed/css/display.css @@ -88,6 +88,15 @@ ol, ul { user-select: none; } +#query-parser { + margin-top: 10px; + font-size: 24px; +} + +.highlight { + background-color: lightblue; +} + /* * Entries diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index 8ad3ee1b..07a851f5 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -140,6 +140,8 @@ class Display { } this.setContentTerms(definitions, context); + + return {textSource}; } catch (error) { this.onError(error); } -- cgit v1.2.3 From c35a05cd62d43ff435c022a353de55510b020277 Mon Sep 17 00:00:00 2001 From: siikamiika Date: Wed, 30 Oct 2019 03:58:24 +0200 Subject: add kana to text --- ext/bg/js/api.js | 37 +++++++++++++++ ext/bg/js/backend.js | 1 + ext/bg/js/search-query-parser.js | 97 ++++++++++++++++++++++++++++++++++++---- ext/fg/js/api.js | 4 ++ ext/mixed/css/display.css | 4 ++ ext/mixed/js/display.js | 78 +++++++++++++++++++++----------- 6 files changed, 188 insertions(+), 33 deletions(-) (limited to 'ext/mixed') diff --git a/ext/bg/js/api.js b/ext/bg/js/api.js index df73aa2a..064903ca 100644 --- a/ext/bg/js/api.js +++ b/ext/bg/js/api.js @@ -79,6 +79,43 @@ async function apiTermsFind(text, details, optionsContext) { 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) { const options = await apiOptionsGet(optionsContext); const definitions = await utilBackend().translator.findKanji(text, options); diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index efad153a..d0e404f2 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -180,6 +180,7 @@ Backend.messageHandlers = { optionsSet: ({changedOptions, optionsContext, source}) => apiOptionsSet(changedOptions, optionsContext, source), kanjiFind: ({text, optionsContext}) => apiKanjiFind(text, 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), definitionsAddable: ({definitions, modes, optionsContext}) => apiDefinitionsAddable(definitions, modes, optionsContext), noteView: ({noteId}) => apiNoteView(noteId), diff --git a/ext/bg/js/search-query-parser.js b/ext/bg/js/search-query-parser.js index debe53b4..c3a3900b 100644 --- a/ext/bg/js/search-query-parser.js +++ b/ext/bg/js/search-query-parser.js @@ -23,22 +23,103 @@ class QueryParser { this.queryParser = document.querySelector('#query-parser'); - // TODO also enable for mouseover scanning - this.queryParser.addEventListener('click', (e) => this.onTermLookup(e)); + this.queryParser.addEventListener('click', (e) => this.onClick(e)); + this.queryParser.addEventListener('mousemove', (e) => this.onMouseMove(e)); } onError(error) { logError(error, false); } - async onTermLookup(e) { - const {textSource} = await this.search.onTermLookup(e, {isQueryParser: true}); - if (textSource) { - textSource.select(); + onClick(e) { + this.onTermLookup(e, {disableScroll: true, selectText: true}); + } + + 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); } - setText(text) { - this.queryParser.innerText = text; + 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); + } + } + + popupTimerClear() { + 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; + } } } diff --git a/ext/fg/js/api.js b/ext/fg/js/api.js index 945ba076..cc1e0e90 100644 --- a/ext/fg/js/api.js +++ b/ext/fg/js/api.js @@ -29,6 +29,10 @@ function apiTermsFind(text, details, optionsContext) { return utilInvoke('termsFind', {text, details, optionsContext}); } +function apiTextParse(text, optionsContext) { + return utilInvoke('textParse', {text, optionsContext}); +} + function apiKanjiFind(text, optionsContext) { return utilInvoke('kanjiFind', {text, optionsContext}); } diff --git a/ext/mixed/css/display.css b/ext/mixed/css/display.css index 5e5213ff..81109fc6 100644 --- a/ext/mixed/css/display.css +++ b/ext/mixed/css/display.css @@ -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 */ diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index 07a851f5..82385bf9 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -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 { e.preventDefault(); - const clickedElement = e.target; const textSource = docRangeFromPoint(e.clientX, e.clientY, this.options); if (textSource === null) { return false; } - let definitions, length, sentence; + let definitions, length; try { textSource.setEndOffset(this.options.scanning.length); @@ -118,30 +163,11 @@ class Display { } textSource.setEndOffset(length); - - sentence = docSentenceExtract(textSource, this.options.anki.sentenceExt); } finally { textSource.cleanup(); } - this.windowScroll.toY(0); - 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}; + return {textSource, definitions}; } catch (error) { this.onError(error); } @@ -338,8 +364,10 @@ class Display { const content = await apiTemplateRender('terms.html', params); this.container.innerHTML = content; - const {index, scroll} = context || {}; - this.entryScrollIntoView(index || 0, scroll); + const {index, scroll, disableScroll} = context || {}; + if (!disableScroll) { + this.entryScrollIntoView(index || 0, scroll); + } if (options.audio.enabled && options.audio.autoPlay) { this.autoPlayAudio(); -- cgit v1.2.3 From 530b95895bb8a807cbaea6a324323c49152c16ab Mon Sep 17 00:00:00 2001 From: siikamiika Date: Wed, 30 Oct 2019 12:06:25 +0200 Subject: remove unused css --- ext/mixed/css/display.css | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'ext/mixed') diff --git a/ext/mixed/css/display.css b/ext/mixed/css/display.css index 81109fc6..65b8b466 100644 --- a/ext/mixed/css/display.css +++ b/ext/mixed/css/display.css @@ -73,10 +73,6 @@ ol, ul { } -html:root[data-yomichan-page=search] body { - min-height: 101vh; /* always show scroll bar to avoid scanning problems */ -} - /* * Search page */ @@ -97,8 +93,13 @@ html:root[data-yomichan-page=search] body { font-size: 24px; } -.highlight { - background-color: lightblue; +html:root[data-yomichan-page=search] body { + min-height: 101vh; /* always show scroll bar to avoid scanning problems */ +} + +#query-parser { + margin-top: 10px; + font-size: 24px; } -- cgit v1.2.3 From 408aa73cced09e1d4fd00cfd193d7f3bcb18b689 Mon Sep 17 00:00:00 2001 From: siikamiika Date: Wed, 30 Oct 2019 13:09:11 +0200 Subject: fix default params for term clicking --- ext/mixed/js/display.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ext/mixed') diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index 82385bf9..4c698ecf 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -98,7 +98,7 @@ class Display { } } - async onTermLookup(e, {disableScroll, selectText, disableHistory}) { + async onTermLookup(e, {disableScroll, selectText, disableHistory}={}) { const termLookupResults = await this.termLookup(e); if (!termLookupResults) { return false; -- cgit v1.2.3 From 3881457e4ed3f9c7833ac21a5e7fc44c2ba00b0f Mon Sep 17 00:00:00 2001 From: siikamiika Date: Thu, 31 Oct 2019 23:56:44 +0200 Subject: use handlebars templates for query parser --- ext/bg/js/api.js | 12 +++++----- ext/bg/js/search-query-parser.js | 40 ++++++++++++++------------------- ext/bg/js/templates.js | 48 ++++++++++++++++++++++++++++++++++++++++ ext/mixed/css/display.css | 9 ++++---- tmpl/query-parser.html | 23 +++++++++++++++++++ 5 files changed, 99 insertions(+), 33 deletions(-) create mode 100644 tmpl/query-parser.html (limited to 'ext/mixed') diff --git a/ext/bg/js/api.js b/ext/bg/js/api.js index dbbe7368..7c9a72a7 100644 --- a/ext/bg/js/api.js +++ b/ext/bg/js/api.js @@ -85,6 +85,7 @@ async function apiTextParse(text, optionsContext) { const results = []; while (text) { + const term = []; let [definitions, sourceLength] = await translator.findTerms(text, {}, options); if (definitions.length > 0) { definitions = dictTermsSort(definitions); @@ -98,22 +99,23 @@ async function apiTextParse(text, optionsContext) { } const offset = source.length - stemLength; - for (const result of jpDistributeFurigana( + for (const {text, furigana} 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) + reading.slice(0, offset === 0 ? reading.length : reading.length - expression.length + stemLength) )) { - results.push(result); + term.push({text, reading: furigana || ''}); } if (stemLength !== source.length) { - results.push({text: source.slice(stemLength)}); + term.push({text: source.slice(stemLength)}); } text = text.slice(source.length); } else { - results.push({text: text[0]}); + term.push({text: text[0]}); text = text.slice(1); } + results.push(term); } return results; } diff --git a/ext/bg/js/search-query-parser.js b/ext/bg/js/search-query-parser.js index 9bea6508..8a7db69a 100644 --- a/ext/bg/js/search-query-parser.js +++ b/ext/bg/js/search-query-parser.js @@ -59,39 +59,33 @@ class QueryParser { } async setText(text) { - this.queryParser.innerHTML = ''; this.search.setSpinnerVisible(true); + const previewTerms = []; let previewText = text; while (previewText) { const tempText = previewText.slice(0, 2); + previewTerms.push([{text: tempText}]); previewText = previewText.slice(2); - - const tempRuby = document.createElement('ruby'); - const tempFurigana = document.createElement('rt'); - tempRuby.appendChild(document.createTextNode(tempText)); - tempRuby.appendChild(tempFurigana); - this.queryParser.appendChild(tempRuby); } + this.queryParser.innerHTML = await apiTemplateRender('query-parser.html', { + terms: previewTerms, + preview: true + }); + const results = await apiTextParse(text, this.search.getOptionsContext()); - const textContainer = document.createElement('div'); - for (const {text, furigana} of results) { - const rubyElement = document.createElement('ruby'); - const furiganaElement = document.createElement('rt'); - if (furigana) { - furiganaElement.innerText = furigana; - rubyElement.appendChild(document.createTextNode(text)); - rubyElement.appendChild(furiganaElement); - } else { - rubyElement.appendChild(document.createTextNode(text)); - rubyElement.appendChild(furiganaElement); - } - textContainer.appendChild(rubyElement); - } - this.queryParser.innerHTML = ''; - this.queryParser.appendChild(textContainer); + const content = await apiTemplateRender('query-parser.html', { + terms: results.map((term) => { + return term.map((part) => { + part.raw = !part.text.trim() && (!part.reading || !part.reading.trim()); + return part; + }); + }) + }); + + this.queryParser.innerHTML = content; this.search.setSpinnerVisible(false); } diff --git a/ext/bg/js/templates.js b/ext/bg/js/templates.js index 823b9e6f..cc233d49 100644 --- a/ext/bg/js/templates.js +++ b/ext/bg/js/templates.js @@ -162,6 +162,54 @@ templates['kanji.html'] = template({"1":function(container,depth0,helpers,partia return fn; } +,"useDecorators":true,"usePartial":true,"useData":true,"useDepths":true}); +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 : "") + + ""; +},"2":function(container,depth0,helpers,partials,data) { + return ""; +},"4":function(container,depth0,helpers,partials,data) { + return ""; +},"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(11, data, 0),"data":data})) != null ? stack1 : ""); +},"9":function(container,depth0,helpers,partials,data) { + var helper; + + return container.escapeExpression(((helper = (helper = helpers.text || (depth0 != null ? depth0.text : depth0)) != null ? helper : helpers.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"text","hash":{},"data":data}) : helper))); +},"11":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.text || (depth0 != null ? depth0.text : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"text","hash":{},"data":data}) : helper))) + + "" + + alias4(((helper = (helper = helpers.reading || (depth0 != null ? depth0.reading : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"reading","hash":{},"data":data}) : helper))) + + ""; +},"13":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(13, 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}); templates['terms.html'] = template({"1":function(container,depth0,helpers,partials,data) { var stack1, helper, options, alias1=depth0 != null ? depth0 : (container.nullContext || {}), buffer = diff --git a/ext/mixed/css/display.css b/ext/mixed/css/display.css index 65b8b466..d24aa58c 100644 --- a/ext/mixed/css/display.css +++ b/ext/mixed/css/display.css @@ -93,13 +93,12 @@ ol, ul { font-size: 24px; } -html:root[data-yomichan-page=search] body { - min-height: 101vh; /* always show scroll bar to avoid scanning problems */ +.query-parser-term { + margin-right: 5px; } -#query-parser { - margin-top: 10px; - font-size: 24px; +html:root[data-yomichan-page=search] body { + min-height: 101vh; /* always show scroll bar to avoid scanning problems */ } diff --git a/tmpl/query-parser.html b/tmpl/query-parser.html new file mode 100644 index 00000000..818650e6 --- /dev/null +++ b/tmpl/query-parser.html @@ -0,0 +1,23 @@ +{{~#*inline "term"~}} +{{~#if preview~}} + +{{~else~}} + +{{~/if~}} +{{~#each this~}} +{{> part }} +{{~/each~}} + +{{~/inline~}} + +{{~#*inline "part"~}} +{{~#if raw~}} +{{text}} +{{~else~}} +{{text}}{{reading}} +{{~/if~}} +{{~/inline~}} + +{{~#each terms~}} +{{> term preview=../preview }} +{{~/each~}} -- cgit v1.2.3 From 41020289ab68ef22a0691a9f268a79d6a706df6b Mon Sep 17 00:00:00 2001 From: siikamiika Date: Sun, 3 Nov 2019 05:08:57 +0200 Subject: add mecab support --- ext/bg/background.html | 1 + ext/bg/js/api.js | 48 ++++++++++++++++++------------ ext/bg/js/backend.js | 2 ++ ext/bg/js/mecab.js | 63 ++++++++++++++++++++++++++++++++++++++++ ext/bg/js/search-query-parser.js | 3 +- ext/fg/js/api.js | 4 +++ ext/manifest.json | 3 +- ext/mixed/js/japanese.js | 35 ++++++++++++++++++++-- 8 files changed, 136 insertions(+), 23 deletions(-) create mode 100644 ext/bg/js/mecab.js (limited to 'ext/mixed') diff --git a/ext/bg/background.html b/ext/bg/background.html index bbfbd1e1..6e6e7c26 100644 --- a/ext/bg/background.html +++ b/ext/bg/background.html @@ -21,6 +21,7 @@ + diff --git a/ext/bg/js/api.js b/ext/bg/js/api.js index 7c9a72a7..2ab01af3 100644 --- a/ext/bg/js/api.js +++ b/ext/bg/js/api.js @@ -91,25 +91,10 @@ async function apiTextParse(text, optionsContext) { definitions = dictTermsSort(definitions); const {expression, reading} = definitions[0]; const source = text.slice(0, sourceLength); - - let stemLength = 0; - const shortest = Math.min(source.length, expression.length); - while (stemLength < shortest && source[stemLength] === expression[stemLength]) { - ++stemLength; - } - const offset = source.length - stemLength; - - for (const {text, furigana} of jpDistributeFurigana( - source.slice(0, offset === 0 ? source.length : source.length - offset), - reading.slice(0, offset === 0 ? reading.length : reading.length - expression.length + stemLength) - )) { - term.push({text, reading: furigana || ''}); - } - - if (stemLength !== source.length) { - term.push({text: source.slice(stemLength)}); + for (const {text, furigana} of jpDistributeFuriganaInflected(expression, reading, source)) { + // can't use 'furigana' in templates + term.push({text, reading: furigana}); } - text = text.slice(source.length); } else { term.push({text: text[0]}); @@ -120,6 +105,33 @@ async function apiTextParse(text, optionsContext) { return results; } +async function apiTextParseMecab(text, optionsContext) { + const options = await apiOptionsGet(optionsContext); + const mecab = utilBackend().mecab; + + const results = []; + for (const parsedLine of await mecab.parseText(text)) { + for (const {expression, reading, source} of parsedLine) { + const term = []; + if (expression && reading) { + for (const {text, furigana} of jpDistributeFuriganaInflected( + expression, + jpKatakanaToHiragana(reading), + source + )) { + // can't use 'furigana' in templates + term.push({text, reading: furigana}); + } + } else { + term.push({text: source}); + } + results.push(term); + } + results.push([{text: '\n'}]); + } + return results; +} + async function apiKanjiFind(text, optionsContext) { const options = await apiOptionsGet(optionsContext); const definitions = await utilBackend().translator.findKanji(text, options); diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index d0e404f2..e97f32b5 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -21,6 +21,7 @@ class Backend { constructor() { this.translator = new Translator(); this.anki = new AnkiNull(); + this.mecab = new Mecab(); this.options = null; this.optionsContext = { depth: 0, @@ -181,6 +182,7 @@ Backend.messageHandlers = { kanjiFind: ({text, optionsContext}) => apiKanjiFind(text, optionsContext), termsFind: ({text, details, optionsContext}) => apiTermsFind(text, details, optionsContext), textParse: ({text, optionsContext}) => apiTextParse(text, optionsContext), + textParseMecab: ({text, optionsContext}) => apiTextParseMecab(text, optionsContext), definitionAdd: ({definition, mode, context, optionsContext}) => apiDefinitionAdd(definition, mode, context, optionsContext), definitionsAddable: ({definitions, modes, optionsContext}) => apiDefinitionsAddable(definitions, modes, optionsContext), noteView: ({noteId}) => apiNoteView(noteId), diff --git a/ext/bg/js/mecab.js b/ext/bg/js/mecab.js new file mode 100644 index 00000000..dc46ded2 --- /dev/null +++ b/ext/bg/js/mecab.js @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2019 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 . + */ + + +class Mecab { + constructor() { + this.listeners = {}; + this.sequence = 0; + this.startListener(); + } + + async parseText(text) { + return await this.invoke('parse_text', {text}); + } + + startListener() { + this.port = chrome.runtime.connectNative('mecab'); + this.port.onMessage.addListener((message) => { + const {sequence, data} = message; + const {callback, timer} = this.listeners[sequence] || {}; + if (timer) { + clearTimeout(timer); + delete this.listeners[sequence]; + callback(data); + } + }); + } + + invoke(action, params) { + return new Promise((resolve, reject) => { + const sequence = this.sequence++; + + this.listeners[sequence] = { + callback: (data) => { + resolve(data); + }, + timer: setTimeout(() => { + delete this.listeners[sequence]; + reject(`Mecab invoke timed out in ${Mecab.timeout} ms`); + }, 1000) + } + + this.port.postMessage({action, params, sequence}); + }); + } +} + +Mecab.timeout = 1000; diff --git a/ext/bg/js/search-query-parser.js b/ext/bg/js/search-query-parser.js index 8a7db69a..0c74e550 100644 --- a/ext/bg/js/search-query-parser.js +++ b/ext/bg/js/search-query-parser.js @@ -74,7 +74,8 @@ class QueryParser { preview: true }); - const results = await apiTextParse(text, this.search.getOptionsContext()); + // const results = await apiTextParse(text, this.search.getOptionsContext()); + const results = await apiTextParseMecab(text, this.search.getOptionsContext()); const content = await apiTemplateRender('query-parser.html', { terms: results.map((term) => { diff --git a/ext/fg/js/api.js b/ext/fg/js/api.js index cc1e0e90..92330d9c 100644 --- a/ext/fg/js/api.js +++ b/ext/fg/js/api.js @@ -33,6 +33,10 @@ function apiTextParse(text, optionsContext) { return utilInvoke('textParse', {text, optionsContext}); } +function apiTextParseMecab(text, optionsContext) { + return utilInvoke('textParseMecab', {text, optionsContext}); +} + function apiKanjiFind(text, optionsContext) { return utilInvoke('kanjiFind', {text, optionsContext}); } diff --git a/ext/manifest.json b/ext/manifest.json index fabceafd..4d75cd54 100644 --- a/ext/manifest.json +++ b/ext/manifest.json @@ -42,7 +42,8 @@ "", "storage", "clipboardWrite", - "unlimitedStorage" + "unlimitedStorage", + "nativeMessaging" ], "optional_permissions": [ "clipboardRead" diff --git a/ext/mixed/js/japanese.js b/ext/mixed/js/japanese.js index d24f56a6..78c419b2 100644 --- a/ext/mixed/js/japanese.js +++ b/ext/mixed/js/japanese.js @@ -61,12 +61,11 @@ function jpDistributeFurigana(expression, reading) { const group = groups[0]; if (group.mode === 'kana') { - if (reading.startsWith(group.text)) { - const readingUsed = reading.substring(0, group.text.length); + if (jpKatakanaToHiragana(reading).startsWith(jpKatakanaToHiragana(group.text))) { const readingLeft = reading.substring(group.text.length); const segs = segmentize(readingLeft, groups.splice(1)); if (segs) { - return [{text: readingUsed}].concat(segs); + return [{text: group.text}].concat(segs); } } } else { @@ -95,3 +94,33 @@ function jpDistributeFurigana(expression, reading) { return segmentize(reading, groups) || fallback; } + +function jpDistributeFuriganaInflected(expression, reading, source) { + const output = []; + + let stemLength = 0; + const shortest = Math.min(source.length, expression.length); + const sourceHiragana = jpKatakanaToHiragana(source); + const expressionHiragana = jpKatakanaToHiragana(expression); + while ( + stemLength < shortest && + // sometimes an expression can use a kanji that's different from the source + (!jpIsKana(source[stemLength]) || (sourceHiragana[stemLength] === expressionHiragana[stemLength])) + ) { + ++stemLength; + } + const offset = source.length - stemLength; + + for (const segment of jpDistributeFurigana( + source.slice(0, offset === 0 ? source.length : source.length - offset), + reading.slice(0, offset === 0 ? reading.length : reading.length - expression.length + stemLength) + )) { + output.push(segment); + } + + if (stemLength !== source.length) { + output.push({text: source.slice(stemLength)}); + } + + return output; +} -- cgit v1.2.3 From 17003189888694da51d840dcf0464355bb342a4c Mon Sep 17 00:00:00 2001 From: siikamiika Date: Tue, 5 Nov 2019 02:43:04 +0200 Subject: remove unneeded feature Unidic actually has a field for the base form of the input --- ext/mixed/js/japanese.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'ext/mixed') diff --git a/ext/mixed/js/japanese.js b/ext/mixed/js/japanese.js index 78c419b2..1201e524 100644 --- a/ext/mixed/js/japanese.js +++ b/ext/mixed/js/japanese.js @@ -102,11 +102,7 @@ function jpDistributeFuriganaInflected(expression, reading, source) { const shortest = Math.min(source.length, expression.length); const sourceHiragana = jpKatakanaToHiragana(source); const expressionHiragana = jpKatakanaToHiragana(expression); - while ( - stemLength < shortest && - // sometimes an expression can use a kanji that's different from the source - (!jpIsKana(source[stemLength]) || (sourceHiragana[stemLength] === expressionHiragana[stemLength])) - ) { + while (stemLength < shortest && sourceHiragana[stemLength] === expressionHiragana[stemLength]) { ++stemLength; } const offset = source.length - stemLength; -- cgit v1.2.3 From 84f30113e4b8b750525b5e67a2a6bfa68da666ff Mon Sep 17 00:00:00 2001 From: siikamiika Date: Mon, 11 Nov 2019 21:58:04 +0200 Subject: give names to complex slices --- ext/mixed/js/japanese.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'ext/mixed') diff --git a/ext/mixed/js/japanese.js b/ext/mixed/js/japanese.js index 1201e524..e2d7a090 100644 --- a/ext/mixed/js/japanese.js +++ b/ext/mixed/js/japanese.js @@ -107,10 +107,11 @@ function jpDistributeFuriganaInflected(expression, reading, source) { } const offset = source.length - stemLength; - for (const segment of jpDistributeFurigana( - source.slice(0, offset === 0 ? source.length : source.length - offset), - reading.slice(0, offset === 0 ? reading.length : reading.length - expression.length + stemLength) - )) { + const stemExpression = source.slice(0, source.length - offset); + const stemReading = reading.slice( + 0, offset === 0 ? reading.length : reading.length - expression.length + stemLength + ); + for (const segment of jpDistributeFurigana(stemExpression, stemReading)) { output.push(segment); } -- cgit v1.2.3 From 0d6e0edc31d4ceac58b886e238b77f0143a5c3ec Mon Sep 17 00:00:00 2001 From: siikamiika Date: Wed, 13 Nov 2019 12:05:39 +0200 Subject: remove height hack and use overflow-y: scroll --- ext/mixed/css/display.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ext/mixed') diff --git a/ext/mixed/css/display.css b/ext/mixed/css/display.css index d24aa58c..ba2fadb7 100644 --- a/ext/mixed/css/display.css +++ b/ext/mixed/css/display.css @@ -98,7 +98,7 @@ ol, ul { } html:root[data-yomichan-page=search] body { - min-height: 101vh; /* always show scroll bar to avoid scanning problems */ + overflow-y: scroll; /* always show scroll bar to avoid scanning problems */ } -- cgit v1.2.3 From cc8221c6ea686521261e2ac562d3d5a6d0b9913a Mon Sep 17 00:00:00 2001 From: siikamiika Date: Wed, 13 Nov 2019 20:24:11 +0200 Subject: add reading modes --- ext/bg/js/api.js | 14 ++++++++------ ext/bg/js/options.js | 3 ++- ext/bg/js/settings.js | 2 ++ ext/bg/settings.html | 9 +++++++++ ext/mixed/js/japanese.js | 37 +++++++++++++++++++++++++++++++++++++ 5 files changed, 58 insertions(+), 7 deletions(-) (limited to 'ext/mixed') diff --git a/ext/bg/js/api.js b/ext/bg/js/api.js index bc9dfba1..228447c3 100644 --- a/ext/bg/js/api.js +++ b/ext/bg/js/api.js @@ -92,12 +92,13 @@ async function apiTextParse(text, optionsContext) { const {expression, reading} = definitions[0]; const source = text.slice(0, sourceLength); for (const {text, furigana} of jpDistributeFuriganaInflected(expression, reading, source)) { - // can't use 'furigana' in templates - term.push({text, reading: furigana}); + const reading = jpConvertReading(text, furigana, options.parsing.readingMode); + term.push({text, reading}); } text = text.slice(source.length); } else { - term.push({text: text[0]}); + const reading = jpConvertReading(text[0], null, options.parsing.readingMode); + term.push({text: text[0], reading}); text = text.slice(1); } results.push(term); @@ -122,11 +123,12 @@ async function apiTextParseMecab(text, optionsContext) { jpKatakanaToHiragana(reading), source )) { - // can't use 'furigana' in templates - term.push({text, reading: furigana}); + const reading = jpConvertReading(text, furigana, options.parsing.readingMode); + term.push({text, reading}); } } else { - term.push({text: source}); + const reading = jpConvertReading(source, null, options.parsing.readingMode); + term.push({text: source, reading}); } result.push(term); } diff --git a/ext/bg/js/options.js b/ext/bg/js/options.js index 053fb13d..b9bf85f3 100644 --- a/ext/bg/js/options.js +++ b/ext/bg/js/options.js @@ -314,7 +314,8 @@ function profileOptionsCreateDefaults() { parsing: { enableScanningParser: true, enableMecabParser: false, - selectedParser: null + selectedParser: null, + readingMode: 'hiragana' }, anki: { diff --git a/ext/bg/js/settings.js b/ext/bg/js/settings.js index f4fe032a..ab267c32 100644 --- a/ext/bg/js/settings.js +++ b/ext/bg/js/settings.js @@ -66,6 +66,7 @@ async function formRead(options) { options.parsing.enableScanningParser = $('#parsing-scan-enable').prop('checked'); options.parsing.enableMecabParser = $('#parsing-mecab-enable').prop('checked'); + options.parsing.readingMode = $('#parsing-reading-mode').val(); const optionsAnkiEnableOld = options.anki.enable; options.anki.enable = $('#anki-enable').prop('checked'); @@ -131,6 +132,7 @@ async function formWrite(options) { $('#parsing-scan-enable').prop('checked', options.parsing.enableScanningParser); $('#parsing-mecab-enable').prop('checked', options.parsing.enableMecabParser); + $('#parsing-reading-mode').val(options.parsing.readingMode); $('#anki-enable').prop('checked', options.anki.enable); $('#card-tags').val(options.anki.tags.join(' ')); diff --git a/ext/bg/settings.html b/ext/bg/settings.html index 08b9b6c1..0badb817 100644 --- a/ext/bg/settings.html +++ b/ext/bg/settings.html @@ -437,6 +437,15 @@
    + +
    + + +
    diff --git a/ext/mixed/js/japanese.js b/ext/mixed/js/japanese.js index e2d7a090..a7cd0452 100644 --- a/ext/mixed/js/japanese.js +++ b/ext/mixed/js/japanese.js @@ -48,6 +48,43 @@ function jpKatakanaToHiragana(text) { return result; } +function jpHiraganaToKatakana(text) { + let result = ''; + for (const c of text) { + if (wanakana.isHiragana(c)) { + result += wanakana.toKatakana(c); + } else { + result += c; + } + } + + return result; +} + +function jpToRomaji(text) { + return wanakana.toRomaji(text); +} + +function jpConvertReading(expressionFragment, readingFragment, readingMode) { + switch (readingMode) { + case 'hiragana': + return jpKatakanaToHiragana(readingFragment || ''); + case 'katakana': + return jpHiraganaToKatakana(readingFragment || ''); + case 'romaji': + if (readingFragment) { + return jpToRomaji(readingFragment); + } else { + if (jpIsKana(expressionFragment)) { + return jpToRomaji(expressionFragment); + } + } + return readingFragment; + default: + return readingFragment; + } +} + function jpDistributeFurigana(expression, reading) { const fallback = [{furigana: reading, text: expression}]; if (!reading) { -- cgit v1.2.3 From cf18e3b42e0fa171b9ec9af4c534a962d347e155 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sun, 24 Nov 2019 11:02:52 -0500 Subject: Replace string.substr and string.slice with string.substring Improves semantic clarity, and it's recommended to not use substr. --- ext/bg/js/audio.js | 2 +- ext/bg/js/deinflector.js | 2 +- ext/bg/js/search.js | 2 +- ext/bg/js/translator.js | 20 ++++++++++---------- ext/fg/js/popup.js | 2 +- ext/mixed/js/audio.js | 2 +- 6 files changed, 15 insertions(+), 15 deletions(-) (limited to 'ext/mixed') diff --git a/ext/bg/js/audio.js b/ext/bg/js/audio.js index 3efcce46..cd42a158 100644 --- a/ext/bg/js/audio.js +++ b/ext/bg/js/audio.js @@ -128,7 +128,7 @@ function audioUrlNormalize(url, baseUrl, basePath) { if (url[0] === '/') { if (url.length >= 2 && url[1] === '/') { // Begins with "//" - url = baseUrl.substr(0, baseUrl.indexOf(':') + 1) + url; + url = baseUrl.substring(0, baseUrl.indexOf(':') + 1) + url; } else { // Begins with "/" url = baseUrl + url; diff --git a/ext/bg/js/deinflector.js b/ext/bg/js/deinflector.js index ce4b2961..e2fb7461 100644 --- a/ext/bg/js/deinflector.js +++ b/ext/bg/js/deinflector.js @@ -44,7 +44,7 @@ class Deinflector { results.push({ source, - term: term.slice(0, -kanaIn.length) + kanaOut, + term: term.substring(0, term.length - kanaIn.length) + kanaOut, rules: rulesOut, definitions: [], reasons: [reason, ...reasons] diff --git a/ext/bg/js/search.js b/ext/bg/js/search.js index 56316217..ec5a5972 100644 --- a/ext/bg/js/search.js +++ b/ext/bg/js/search.js @@ -207,7 +207,7 @@ class DisplaySearch extends Display { const match = /[\*\uff0a]+$/.exec(query); if (match !== null) { details.wildcard = true; - query = query.substr(0, query.length - match[0].length); + query = query.substring(0, query.length - match[0].length); } const valid = (query.length > 0); diff --git a/ext/bg/js/translator.js b/ext/bg/js/translator.js index 583d6e31..e27cbdff 100644 --- a/ext/bg/js/translator.js +++ b/ext/bg/js/translator.js @@ -327,22 +327,22 @@ class Translator { const deinflections = []; for (let i = text.length; i > 0; --i) { - const textSlice = text.slice(0, i); - deinflections.push(...this.deinflector.deinflect(textSlice)); + const textSubstring = text.substring(0, i); + deinflections.push(...this.deinflector.deinflect(textSubstring)); } return deinflections; } - getDeinflections2(text, text2) { + getDeinflections2(text1, text2) { const deinflections = []; - for (let i = text.length; i > 0; --i) { - const textSlice = text.slice(0, i); - const text2Slice = text2.slice(0, i); - deinflections.push(...this.deinflector.deinflect(textSlice)); - if (textSlice !== text2Slice) { - deinflections.push(...this.deinflector.deinflect(text2Slice)); + for (let i = text1.length; i > 0; --i) { + const text1Substring = text1.substring(0, i); + const text2Substring = text2.substring(0, i); + deinflections.push(...this.deinflector.deinflect(text1Substring)); + if (text1Substring !== text2Substring) { + deinflections.push(...this.deinflector.deinflect(text2Substring)); } } @@ -516,6 +516,6 @@ class Translator { static getNameBase(name) { const pos = name.indexOf(':'); - return (pos >= 0 ? name.substr(0, pos) : name); + return (pos >= 0 ? name.substring(0, pos) : name); } } diff --git a/ext/fg/js/popup.js b/ext/fg/js/popup.js index 1f9317e0..ac96f9e8 100644 --- a/ext/fg/js/popup.js +++ b/ext/fg/js/popup.js @@ -391,7 +391,7 @@ class Popup { static isOnExtensionPage() { try { const url = chrome.runtime.getURL('/'); - return window.location.href.substr(0, url.length) === url; + return window.location.href.substring(0, url.length) === url; } catch (e) { // NOP } diff --git a/ext/mixed/js/audio.js b/ext/mixed/js/audio.js index ff50dee1..4e9d04fa 100644 --- a/ext/mixed/js/audio.js +++ b/ext/mixed/js/audio.js @@ -75,7 +75,7 @@ class TextToSpeechAudio { for (const group of m[1].split('&')) { const sep = group.indexOf('='); if (sep < 0) { continue; } - searchParameters[decodeURIComponent(group.substr(0, sep))] = decodeURIComponent(group.substr(sep + 1)); + searchParameters[decodeURIComponent(group.substring(0, sep))] = decodeURIComponent(group.substring(sep + 1)); } if (!searchParameters.text) { return null; } -- cgit v1.2.3 From 10b33dbd20d33b7497f500c11ad343399fc338a9 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sun, 24 Nov 2019 11:42:27 -0500 Subject: Optimize toggle on the context popup window Remove bootstrap-toggle dependency --- README.md | 1 - ext/bg/context.html | 65 +++++++++++++++++++++- ext/bg/js/context.js | 19 ++++--- ext/bg/legal.html | 1 - .../lib/bootstrap-toggle/bootstrap-toggle.min.css | 28 ---------- .../lib/bootstrap-toggle/bootstrap-toggle.min.js | 9 --- 6 files changed, 74 insertions(+), 49 deletions(-) delete mode 100644 ext/mixed/lib/bootstrap-toggle/bootstrap-toggle.min.css delete mode 100644 ext/mixed/lib/bootstrap-toggle/bootstrap-toggle.min.js (limited to 'ext/mixed') diff --git a/README.md b/README.md index 0efb313d..c8af8295 100644 --- a/README.md +++ b/README.md @@ -256,7 +256,6 @@ Yomichan uses several third-party libraries to function. Below are links to home versions packaged. * Bootstrap: [homepage](https://getbootstrap.com/) - [snapshot](https://github.com/twbs/bootstrap/releases/download/v3.3.7/bootstrap-3.3.7-dist.zip) - [license](https://github.com/twbs/bootstrap/blob/v3.3.7/LICENSE) -* Bootstrap Toggle: [homepage](https://www.bootstraptoggle.com/) - [snapshot](https://github.com/minhur/bootstrap-toggle/archive/b76c094.zip) - [license](https://github.com/minhur/bootstrap-toggle/blob/2.2.0/LICENSE) * Handlebars: [homepage](https://handlebarsjs.com/) - [snapshot](http://builds.handlebarsjs.com.s3.amazonaws.com/handlebars.min-714a4c4.js) - [license](https://github.com/wycats/handlebars.js/blob/v4.0.6/LICENSE) * jQuery: [homepage](https://blog.jquery.com/) - [snapshot](https://code.jquery.com/jquery-3.2.1.min.js) - [license](https://github.com/jquery/jquery/blob/3.2.1/LICENSE.txt) * JSZip: [homepage](https://stuk.github.io/jszip/) - [snapshot](https://raw.githubusercontent.com/Stuk/jszip/de7f52fbcba485737bef7923a83f0fad92d9f5bc/dist/jszip.min.js) - [license](https://github.com/Stuk/jszip/blob/v3.1.3/LICENSE.markdown) diff --git a/ext/bg/context.html b/ext/bg/context.html index 7e08dddd..52645022 100644 --- a/ext/bg/context.html +++ b/ext/bg/context.html @@ -11,7 +11,6 @@ -
    - +
    @@ -119,7 +179,6 @@
    - diff --git a/ext/bg/js/context.js b/ext/bg/js/context.js index 3fb27f0d..5bd6ada4 100644 --- a/ext/bg/js/context.js +++ b/ext/bg/js/context.js @@ -64,13 +64,18 @@ $(document).ready(utilAsync(() => { url: window.location.href }; apiOptionsGet(optionsContext).then(options => { - const toggle = $('#enable-search'); - toggle.prop('checked', options.general.enable).change(); - toggle.bootstrapToggle(); - toggle.change(() => apiCommandExec('toggle')); + const toggle = document.querySelector('#enable-search'); + toggle.checked = options.general.enable; + toggle.addEventListener('change', () => apiCommandExec('toggle'), false); - const toggle2 = $('#enable-search2'); - toggle2.prop('checked', options.general.enable).change(); - toggle2.change(() => apiCommandExec('toggle')); + const toggle2 = document.querySelector('#enable-search2'); + toggle2.checked = options.general.enable; + toggle2.addEventListener('change', () => apiCommandExec('toggle'), false); + + setTimeout(() => { + for (const n of document.querySelectorAll('.toggle-group')) { + n.classList.add('toggle-group-animated'); + } + }, 10); }); })); diff --git a/ext/bg/legal.html b/ext/bg/legal.html index 377d25ba..3047ab3e 100644 --- a/ext/bg/legal.html +++ b/ext/bg/legal.html @@ -41,7 +41,6 @@ and are used in conformance with the Group's Bootstrap v3.3.7 -
  • Bootstrap Toggle v2.2.0
  • Handlebars v4.0.6
  • jQuery v3.2.1
  • JSZip v3.1.3
  • diff --git a/ext/mixed/lib/bootstrap-toggle/bootstrap-toggle.min.css b/ext/mixed/lib/bootstrap-toggle/bootstrap-toggle.min.css deleted file mode 100644 index 0d42ed09..00000000 --- a/ext/mixed/lib/bootstrap-toggle/bootstrap-toggle.min.css +++ /dev/null @@ -1,28 +0,0 @@ -/*! ======================================================================== - * Bootstrap Toggle: bootstrap-toggle.css v2.2.0 - * http://www.bootstraptoggle.com - * ======================================================================== - * Copyright 2014 Min Hur, The New York Times Company - * Licensed under MIT - * ======================================================================== */ -.checkbox label .toggle,.checkbox-inline .toggle{margin-left:-20px;margin-right:5px} -.toggle{position:relative;overflow:hidden} -.toggle input[type=checkbox]{display:none} -.toggle-group{position:absolute;width:200%;top:0;bottom:0;left:0;transition:left .35s;-webkit-transition:left .35s;-moz-user-select:none;-webkit-user-select:none} -.toggle.off .toggle-group{left:-100%} -.toggle-on{position:absolute;top:0;bottom:0;left:0;right:50%;margin:0;border:0;border-radius:0} -.toggle-off{position:absolute;top:0;bottom:0;left:50%;right:0;margin:0;border:0;border-radius:0} -.toggle-handle{position:relative;margin:0 auto;padding-top:0;padding-bottom:0;height:100%;width:0;border-width:0 1px} -.toggle.btn{min-width:59px;min-height:34px} -.toggle-on.btn{padding-right:24px} -.toggle-off.btn{padding-left:24px} -.toggle.btn-lg{min-width:79px;min-height:45px} -.toggle-on.btn-lg{padding-right:31px} -.toggle-off.btn-lg{padding-left:31px} -.toggle-handle.btn-lg{width:40px} -.toggle.btn-sm{min-width:50px;min-height:30px} -.toggle-on.btn-sm{padding-right:20px} -.toggle-off.btn-sm{padding-left:20px} -.toggle.btn-xs{min-width:35px;min-height:22px} -.toggle-on.btn-xs{padding-right:12px} -.toggle-off.btn-xs{padding-left:12px} \ No newline at end of file diff --git a/ext/mixed/lib/bootstrap-toggle/bootstrap-toggle.min.js b/ext/mixed/lib/bootstrap-toggle/bootstrap-toggle.min.js deleted file mode 100644 index 37113200..00000000 --- a/ext/mixed/lib/bootstrap-toggle/bootstrap-toggle.min.js +++ /dev/null @@ -1,9 +0,0 @@ -/*! ======================================================================== - * Bootstrap Toggle: bootstrap-toggle.js v2.2.0 - * http://www.bootstraptoggle.com - * ======================================================================== - * Copyright 2014 Min Hur, The New York Times Company - * Licensed under MIT - * ======================================================================== */ -+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.toggle"),f="object"==typeof b&&b;e||d.data("bs.toggle",e=new c(this,f)),"string"==typeof b&&e[b]&&e[b]()})}var c=function(b,c){this.$element=a(b),this.options=a.extend({},this.defaults(),c),this.render()};c.VERSION="2.2.0",c.DEFAULTS={on:"On",off:"Off",onstyle:"primary",offstyle:"default",size:"normal",style:"",width:null,height:null},c.prototype.defaults=function(){return{on:this.$element.attr("data-on")||c.DEFAULTS.on,off:this.$element.attr("data-off")||c.DEFAULTS.off,onstyle:this.$element.attr("data-onstyle")||c.DEFAULTS.onstyle,offstyle:this.$element.attr("data-offstyle")||c.DEFAULTS.offstyle,size:this.$element.attr("data-size")||c.DEFAULTS.size,style:this.$element.attr("data-style")||c.DEFAULTS.style,width:this.$element.attr("data-width")||c.DEFAULTS.width,height:this.$element.attr("data-height")||c.DEFAULTS.height}},c.prototype.render=function(){this._onstyle="btn-"+this.options.onstyle,this._offstyle="btn-"+this.options.offstyle;var b="large"===this.options.size?"btn-lg":"small"===this.options.size?"btn-sm":"mini"===this.options.size?"btn-xs":"",c=a('
    - + diff --git a/ext/bg/search.html b/ext/bg/search.html index e819ebe6..16074022 100644 --- a/ext/bg/search.html +++ b/ext/bg/search.html @@ -60,7 +60,7 @@ - + diff --git a/ext/bg/settings-popup-preview.html b/ext/bg/settings-popup-preview.html index d27a9a33..574b6707 100644 --- a/ext/bg/settings-popup-preview.html +++ b/ext/bg/settings-popup-preview.html @@ -117,7 +117,7 @@
    - + diff --git a/ext/bg/settings.html b/ext/bg/settings.html index 262386e9..b2af3759 100644 --- a/ext/bg/settings.html +++ b/ext/bg/settings.html @@ -864,7 +864,7 @@ - + diff --git a/ext/fg/float.html b/ext/fg/float.html index 73118917..e04c1402 100644 --- a/ext/fg/float.html +++ b/ext/fg/float.html @@ -31,7 +31,7 @@ - + diff --git a/ext/manifest.json b/ext/manifest.json index 43a887cd..69ee0c4f 100644 --- a/ext/manifest.json +++ b/ext/manifest.json @@ -18,7 +18,7 @@ "content_scripts": [{ "matches": ["http://*/*", "https://*/*", "file://*/*"], "js": [ - "mixed/js/extension.js", + "mixed/js/core.js", "fg/js/api.js", "fg/js/document.js", "fg/js/frontend-api-receiver.js", diff --git a/ext/mixed/js/core.js b/ext/mixed/js/core.js new file mode 100644 index 00000000..12ed9c1f --- /dev/null +++ b/ext/mixed/js/core.js @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2019 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 . + */ + + +// toIterable is required on Edge for cross-window origin objects. +function toIterable(value) { + if (typeof Symbol !== 'undefined' && typeof value[Symbol.iterator] !== 'undefined') { + return value; + } + + if (value !== null && typeof value === 'object') { + const length = value.length; + if (typeof length === 'number' && Number.isFinite(length)) { + const array = []; + for (let i = 0; i < length; ++i) { + array.push(value[i]); + } + return array; + } + } + + throw new Error('Could not convert to iterable'); +} + +function extensionHasChrome() { + try { + return typeof chrome === 'object' && chrome !== null; + } catch (e) { + return false; + } +} + +function extensionHasBrowser() { + try { + return typeof browser === 'object' && browser !== null; + } catch (e) { + return false; + } +} + +function errorToJson(error) { + return { + name: error.name, + message: error.message, + stack: error.stack + }; +} + +function jsonToError(jsonError) { + const error = new Error(jsonError.message); + error.name = jsonError.name; + error.stack = jsonError.stack; + return error; +} + +function logError(error, alert) { + const manifest = chrome.runtime.getManifest(); + let errorMessage = `${manifest.name} v${manifest.version} has encountered an error.\n`; + errorMessage += `Originating URL: ${window.location.href}\n`; + + const errorString = `${error.toString ? error.toString() : error}`; + const stack = `${error.stack}`.trimRight(); + errorMessage += (!stack.startsWith(errorString) ? `${errorString}\n${stack}` : `${stack}`); + + errorMessage += '\n\nIssues can be reported at https://github.com/FooSoft/yomichan/issues'; + + console.error(errorMessage); + + if (alert) { + window.alert(`${errorString}\n\nCheck the developer console for more details.`); + } +} + +const EXTENSION_IS_BROWSER_EDGE = ( + extensionHasBrowser() && + (!extensionHasChrome() || (typeof chrome.runtime === 'undefined' && typeof browser.runtime !== 'undefined')) +); + +if (EXTENSION_IS_BROWSER_EDGE) { + // Edge does not have chrome defined. + chrome = browser; +} + +function promiseTimeout(delay, resolveValue) { + if (delay <= 0) { + return Promise.resolve(resolveValue); + } + + let timer = null; + let promiseResolve = null; + let promiseReject = null; + + const complete = (callback, value) => { + if (callback === null) { return; } + if (timer !== null) { + window.clearTimeout(timer); + timer = null; + } + promiseResolve = null; + promiseReject = null; + callback(value); + }; + + const resolve = (value) => complete(promiseResolve, value); + const reject = (value) => complete(promiseReject, value); + + const promise = new Promise((resolve, reject) => { + promiseResolve = resolve; + promiseReject = reject; + }); + timer = window.setTimeout(() => { + timer = null; + resolve(resolveValue); + }, delay); + + promise.resolve = resolve; + promise.reject = reject; + + return promise; +} + +function stringReplaceAsync(str, regex, replacer) { + let match; + let index = 0; + const parts = []; + while ((match = regex.exec(str)) !== null) { + parts.push(str.substring(index, match.index), replacer(...match, match.index, str)); + index = regex.lastIndex; + } + if (parts.length === 0) { + return Promise.resolve(str); + } + parts.push(str.substring(index)); + return Promise.all(parts).then(v => v.join('')); +} diff --git a/ext/mixed/js/extension.js b/ext/mixed/js/extension.js deleted file mode 100644 index 12ed9c1f..00000000 --- a/ext/mixed/js/extension.js +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (C) 2019 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 . - */ - - -// toIterable is required on Edge for cross-window origin objects. -function toIterable(value) { - if (typeof Symbol !== 'undefined' && typeof value[Symbol.iterator] !== 'undefined') { - return value; - } - - if (value !== null && typeof value === 'object') { - const length = value.length; - if (typeof length === 'number' && Number.isFinite(length)) { - const array = []; - for (let i = 0; i < length; ++i) { - array.push(value[i]); - } - return array; - } - } - - throw new Error('Could not convert to iterable'); -} - -function extensionHasChrome() { - try { - return typeof chrome === 'object' && chrome !== null; - } catch (e) { - return false; - } -} - -function extensionHasBrowser() { - try { - return typeof browser === 'object' && browser !== null; - } catch (e) { - return false; - } -} - -function errorToJson(error) { - return { - name: error.name, - message: error.message, - stack: error.stack - }; -} - -function jsonToError(jsonError) { - const error = new Error(jsonError.message); - error.name = jsonError.name; - error.stack = jsonError.stack; - return error; -} - -function logError(error, alert) { - const manifest = chrome.runtime.getManifest(); - let errorMessage = `${manifest.name} v${manifest.version} has encountered an error.\n`; - errorMessage += `Originating URL: ${window.location.href}\n`; - - const errorString = `${error.toString ? error.toString() : error}`; - const stack = `${error.stack}`.trimRight(); - errorMessage += (!stack.startsWith(errorString) ? `${errorString}\n${stack}` : `${stack}`); - - errorMessage += '\n\nIssues can be reported at https://github.com/FooSoft/yomichan/issues'; - - console.error(errorMessage); - - if (alert) { - window.alert(`${errorString}\n\nCheck the developer console for more details.`); - } -} - -const EXTENSION_IS_BROWSER_EDGE = ( - extensionHasBrowser() && - (!extensionHasChrome() || (typeof chrome.runtime === 'undefined' && typeof browser.runtime !== 'undefined')) -); - -if (EXTENSION_IS_BROWSER_EDGE) { - // Edge does not have chrome defined. - chrome = browser; -} - -function promiseTimeout(delay, resolveValue) { - if (delay <= 0) { - return Promise.resolve(resolveValue); - } - - let timer = null; - let promiseResolve = null; - let promiseReject = null; - - const complete = (callback, value) => { - if (callback === null) { return; } - if (timer !== null) { - window.clearTimeout(timer); - timer = null; - } - promiseResolve = null; - promiseReject = null; - callback(value); - }; - - const resolve = (value) => complete(promiseResolve, value); - const reject = (value) => complete(promiseReject, value); - - const promise = new Promise((resolve, reject) => { - promiseResolve = resolve; - promiseReject = reject; - }); - timer = window.setTimeout(() => { - timer = null; - resolve(resolveValue); - }, delay); - - promise.resolve = resolve; - promise.reject = reject; - - return promise; -} - -function stringReplaceAsync(str, regex, replacer) { - let match; - let index = 0; - const parts = []; - while ((match = regex.exec(str)) !== null) { - parts.push(str.substring(index, match.index), replacer(...match, match.index, str)); - index = regex.lastIndex; - } - if (parts.length === 0) { - return Promise.resolve(str); - } - parts.push(str.substring(index)); - return Promise.all(parts).then(v => v.join('')); -} -- cgit v1.2.3 From 099847729c471c3ff6e8c28673114eae81c6a4f4 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Tue, 26 Nov 2019 17:33:09 -0500 Subject: utilIsObject => isObject, move to core.js --- ext/bg/js/options.js | 4 ++-- ext/bg/js/util.js | 4 ---- ext/mixed/js/core.js | 4 ++++ 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'ext/mixed') diff --git a/ext/bg/js/options.js b/ext/bg/js/options.js index b9bf85f3..63d88789 100644 --- a/ext/bg/js/options.js +++ b/ext/bg/js/options.js @@ -389,7 +389,7 @@ function optionsUpdateVersion(options, defaultProfileOptions) { // Remove invalid const profiles = options.profiles; for (let i = profiles.length - 1; i >= 0; --i) { - if (!utilIsObject(profiles[i])) { + if (!isObject(profiles[i])) { profiles.splice(i, 1); } } @@ -440,7 +440,7 @@ function optionsLoad() { }).then(optionsStr => { if (typeof optionsStr === 'string') { const options = JSON.parse(optionsStr); - if (utilIsObject(options)) { + if (isObject(options)) { return options; } } diff --git a/ext/bg/js/util.js b/ext/bg/js/util.js index b9e602b3..c21fd68c 100644 --- a/ext/bg/js/util.js +++ b/ext/bg/js/util.js @@ -111,7 +111,3 @@ function utilReadFile(file) { reader.readAsBinaryString(file); }); } - -function utilIsObject(value) { - return typeof value === 'object' && value !== null && !Array.isArray(value); -} diff --git a/ext/mixed/js/core.js b/ext/mixed/js/core.js index 12ed9c1f..513d6211 100644 --- a/ext/mixed/js/core.js +++ b/ext/mixed/js/core.js @@ -148,3 +148,7 @@ function stringReplaceAsync(str, regex, replacer) { parts.push(str.substring(index)); return Promise.all(parts).then(v => v.join('')); } + +function isObject(value) { + return typeof value === 'object' && value !== null && !Array.isArray(value); +} -- cgit v1.2.3 From 50604b25e659661a10b9b1a2e268e25447746456 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Tue, 26 Nov 2019 17:38:05 -0500 Subject: Organize core.js --- ext/mixed/js/core.js | 83 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 51 insertions(+), 32 deletions(-) (limited to 'ext/mixed') diff --git a/ext/mixed/js/core.js b/ext/mixed/js/core.js index 513d6211..8a8a2368 100644 --- a/ext/mixed/js/core.js +++ b/ext/mixed/js/core.js @@ -17,27 +17,11 @@ */ -// toIterable is required on Edge for cross-window origin objects. -function toIterable(value) { - if (typeof Symbol !== 'undefined' && typeof value[Symbol.iterator] !== 'undefined') { - return value; - } - - if (value !== null && typeof value === 'object') { - const length = value.length; - if (typeof length === 'number' && Number.isFinite(length)) { - const array = []; - for (let i = 0; i < length; ++i) { - array.push(value[i]); - } - return array; - } - } - - throw new Error('Could not convert to iterable'); -} +/* + * Extension information + */ -function extensionHasChrome() { +function _extensionHasChrome() { try { return typeof chrome === 'object' && chrome !== null; } catch (e) { @@ -45,7 +29,7 @@ function extensionHasChrome() { } } -function extensionHasBrowser() { +function _extensionHasBrowser() { try { return typeof browser === 'object' && browser !== null; } catch (e) { @@ -53,6 +37,21 @@ function extensionHasBrowser() { } } +const EXTENSION_IS_BROWSER_EDGE = ( + _extensionHasBrowser() && + (!_extensionHasChrome() || (typeof chrome.runtime === 'undefined' && typeof browser.runtime !== 'undefined')) +); + +if (EXTENSION_IS_BROWSER_EDGE) { + // Edge does not have chrome defined. + chrome = browser; +} + + +/* + * Error handling + */ + function errorToJson(error) { return { name: error.name, @@ -86,16 +85,40 @@ function logError(error, alert) { } } -const EXTENSION_IS_BROWSER_EDGE = ( - extensionHasBrowser() && - (!extensionHasChrome() || (typeof chrome.runtime === 'undefined' && typeof browser.runtime !== 'undefined')) -); -if (EXTENSION_IS_BROWSER_EDGE) { - // Edge does not have chrome defined. - chrome = browser; +/* + * Common helpers + */ + +function isObject(value) { + return typeof value === 'object' && value !== null && !Array.isArray(value); } +// toIterable is required on Edge for cross-window origin objects. +function toIterable(value) { + if (typeof Symbol !== 'undefined' && typeof value[Symbol.iterator] !== 'undefined') { + return value; + } + + if (value !== null && typeof value === 'object') { + const length = value.length; + if (typeof length === 'number' && Number.isFinite(length)) { + const array = []; + for (let i = 0; i < length; ++i) { + array.push(value[i]); + } + return array; + } + } + + throw new Error('Could not convert to iterable'); +} + + +/* + * Async utilities + */ + function promiseTimeout(delay, resolveValue) { if (delay <= 0) { return Promise.resolve(resolveValue); @@ -148,7 +171,3 @@ function stringReplaceAsync(str, regex, replacer) { parts.push(str.substring(index)); return Promise.all(parts).then(v => v.join('')); } - -function isObject(value) { - return typeof value === 'object' && value !== null && !Array.isArray(value); -} -- cgit v1.2.3 From c2ff25b0ec2fdb8764a5e9994c1e37bfed7f05c6 Mon Sep 17 00:00:00 2001 From: siikamiika Date: Wed, 27 Nov 2019 01:20:04 +0200 Subject: use fallback for ambiguous furigana fixes #281, fixes #94 --- ext/mixed/js/japanese.js | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'ext/mixed') diff --git a/ext/mixed/js/japanese.js b/ext/mixed/js/japanese.js index a7cd0452..8b841b2e 100644 --- a/ext/mixed/js/japanese.js +++ b/ext/mixed/js/japanese.js @@ -91,8 +91,9 @@ function jpDistributeFurigana(expression, reading) { return fallback; } + let isAmbiguous = false; const segmentize = (reading, groups) => { - if (groups.length === 0) { + if (groups.length === 0 || isAmbiguous) { return []; } @@ -106,14 +107,25 @@ function jpDistributeFurigana(expression, reading) { } } } else { + let foundSegments = null; for (let i = reading.length; i >= group.text.length; --i) { const readingUsed = reading.substring(0, i); const readingLeft = reading.substring(i); const segs = segmentize(readingLeft, groups.slice(1)); if (segs) { - return [{text: group.text, furigana: readingUsed}].concat(segs); + if (foundSegments !== null) { + // more than one way to segmentize the tail, mark as ambiguous + isAmbiguous = true; + return null; + } + foundSegments = [{text: group.text, furigana: readingUsed}].concat(segs); + } + // there is only one way to segmentize the last non-kana group + if (groups.length === 1) { + break; } } + return foundSegments; } }; @@ -129,7 +141,11 @@ function jpDistributeFurigana(expression, reading) { } } - return segmentize(reading, groups) || fallback; + const segments = segmentize(reading, groups); + if (segments && !isAmbiguous) { + return segments; + } + return fallback; } function jpDistributeFuriganaInflected(expression, reading, source) { -- cgit v1.2.3 From 96aad50340b4d0374979ac981cd1c481cc8dcd94 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Tue, 26 Nov 2019 18:47:16 -0500 Subject: Create DOM utility file --- ext/bg/background.html | 1 + ext/bg/context.html | 1 + ext/bg/search.html | 1 + ext/bg/settings-popup-preview.html | 2 ++ ext/bg/settings.html | 1 + ext/fg/float.html | 1 + ext/fg/js/document.js | 19 ++-------------- ext/fg/js/frontend.js | 14 +----------- ext/manifest.json | 1 + ext/mixed/js/dom.js | 46 ++++++++++++++++++++++++++++++++++++++ 10 files changed, 57 insertions(+), 30 deletions(-) create mode 100644 ext/mixed/js/dom.js (limited to 'ext/mixed') diff --git a/ext/bg/background.html b/ext/bg/background.html index 3b337e18..5a6970c3 100644 --- a/ext/bg/background.html +++ b/ext/bg/background.html @@ -19,6 +19,7 @@ + diff --git a/ext/bg/context.html b/ext/bg/context.html index 52ca255d..eda09a68 100644 --- a/ext/bg/context.html +++ b/ext/bg/context.html @@ -179,6 +179,7 @@ + diff --git a/ext/bg/search.html b/ext/bg/search.html index 16074022..ef24af89 100644 --- a/ext/bg/search.html +++ b/ext/bg/search.html @@ -61,6 +61,7 @@ + diff --git a/ext/bg/settings-popup-preview.html b/ext/bg/settings-popup-preview.html index 574b6707..9ca59e44 100644 --- a/ext/bg/settings-popup-preview.html +++ b/ext/bg/settings-popup-preview.html @@ -118,6 +118,8 @@ + + diff --git a/ext/bg/settings.html b/ext/bg/settings.html index b2af3759..908c618c 100644 --- a/ext/bg/settings.html +++ b/ext/bg/settings.html @@ -865,6 +865,7 @@ + diff --git a/ext/fg/float.html b/ext/fg/float.html index e04c1402..38439c79 100644 --- a/ext/fg/float.html +++ b/ext/fg/float.html @@ -32,6 +32,7 @@ + diff --git a/ext/fg/js/document.js b/ext/fg/js/document.js index 8161c85a..3dd12a40 100644 --- a/ext/fg/js/document.js +++ b/ext/fg/js/document.js @@ -223,7 +223,7 @@ function isPointInRange(x, y, range) { const {node, offset, content} = TextSourceRange.seekForward(range.endContainer, range.endOffset, 1); range.setEnd(node, offset); - if (!isWhitespace(content) && isPointInAnyRect(x, y, range.getClientRects())) { + if (!isWhitespace(content) && DOM.isPointInAnyRect(x, y, range.getClientRects())) { return true; } } finally { @@ -234,7 +234,7 @@ function isPointInRange(x, y, range) { const {node, offset, content} = TextSourceRange.seekBackward(range.startContainer, range.startOffset, 1); range.setStart(node, offset); - if (!isWhitespace(content) && isPointInAnyRect(x, y, range.getClientRects())) { + if (!isWhitespace(content) && DOM.isPointInAnyRect(x, y, range.getClientRects())) { // This purposefully leaves the starting offset as modified and sets the range length to 0. range.setEnd(node, offset); return true; @@ -248,21 +248,6 @@ function isWhitespace(string) { return string.trim().length === 0; } -function isPointInAnyRect(x, y, rects) { - for (const rect of rects) { - if (isPointInRect(x, y, rect)) { - return true; - } - } - return false; -} - -function isPointInRect(x, y, rect) { - return ( - x >= rect.left && x < rect.right && - y >= rect.top && y < rect.bottom); -} - const caretRangeFromPoint = (() => { if (typeof document.caretRangeFromPoint === 'function') { // Chrome, Edge diff --git a/ext/fg/js/frontend.js b/ext/fg/js/frontend.js index 6002dfcb..81c159db 100644 --- a/ext/fg/js/frontend.js +++ b/ext/fg/js/frontend.js @@ -159,7 +159,7 @@ class Frontend { this.preventNextClick = false; const primaryTouch = e.changedTouches[0]; - if (Frontend.selectionContainsPoint(window.getSelection(), primaryTouch.clientX, primaryTouch.clientY)) { + if (DOM.isPointInSelection(primaryTouch.clientX, primaryTouch.clientY, window.getSelection())) { return; } @@ -456,18 +456,6 @@ class Frontend { return -1; } - static selectionContainsPoint(selection, x, y) { - for (let i = 0; i < selection.rangeCount; ++i) { - const range = selection.getRangeAt(i); - for (const rect of range.getClientRects()) { - if (x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom) { - return true; - } - } - } - return false; - } - setTextSourceScanLength(textSource, length) { textSource.setEndOffset(length); if (this.ignoreNodes === null || !textSource.range) { diff --git a/ext/manifest.json b/ext/manifest.json index 69ee0c4f..dc670633 100644 --- a/ext/manifest.json +++ b/ext/manifest.json @@ -19,6 +19,7 @@ "matches": ["http://*/*", "https://*/*", "file://*/*"], "js": [ "mixed/js/core.js", + "mixed/js/dom.js", "fg/js/api.js", "fg/js/document.js", "fg/js/frontend-api-receiver.js", diff --git a/ext/mixed/js/dom.js b/ext/mixed/js/dom.js new file mode 100644 index 00000000..4525dace --- /dev/null +++ b/ext/mixed/js/dom.js @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2019 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 . + */ + + +class DOM { + static isPointInRect(x, y, rect) { + return ( + x >= rect.left && x < rect.right && + y >= rect.top && y < rect.bottom + ); + } + + static isPointInAnyRect(x, y, rects) { + for (const rect of rects) { + if (DOM.isPointInRect(x, y, rect)) { + return true; + } + } + return false; + } + + static isPointInSelection(x, y, selection) { + for (let i = 0; i < selection.rangeCount; ++i) { + const range = selection.getRangeAt(i); + if (DOM.isPointInAnyRect(x, y, range.getClientRects())) { + return true; + } + } + return false; + } +} -- cgit v1.2.3 From 4110a848f5107c697e09c014d3488360fc8219ef Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Tue, 26 Nov 2019 18:52:05 -0500 Subject: Move additional utility functions to DOM --- ext/bg/js/search-query-parser.js | 8 ++++---- ext/fg/js/frontend.js | 35 ++--------------------------------- ext/mixed/js/display.js | 4 ++-- ext/mixed/js/dom.js | 20 ++++++++++++++++++++ 4 files changed, 28 insertions(+), 39 deletions(-) (limited to 'ext/mixed') diff --git a/ext/bg/js/search-query-parser.js b/ext/bg/js/search-query-parser.js index 42e53989..1a43347c 100644 --- a/ext/bg/js/search-query-parser.js +++ b/ext/bg/js/search-query-parser.js @@ -38,7 +38,7 @@ class QueryParser { } onMouseDown(e) { - if (Frontend.isMouseButton('primary', e)) { + if (DOM.isMouseButtonPressed(e, 'primary')) { this.clickScanPrevent = false; } } @@ -47,7 +47,7 @@ class QueryParser { if ( this.search.options.scanning.clickGlossary && !this.clickScanPrevent && - Frontend.isMouseButton('primary', e) + DOM.isMouseButtonPressed(e, 'primary') ) { const selectText = this.search.options.scanning.selectText; this.onTermLookup(e, {disableScroll: true, selectText}); @@ -55,7 +55,7 @@ class QueryParser { } onMouseMove(e) { - if (this.pendingLookup || Frontend.isMouseButton('primary', e)) { + if (this.pendingLookup || DOM.isMouseButtonDown(e, 'primary')) { return; } @@ -63,7 +63,7 @@ class QueryParser { const scanningModifier = scanningOptions.modifier; if (!( Frontend.isScanningModifierPressed(scanningModifier, e) || - (scanningOptions.middleMouse && Frontend.isMouseButton('auxiliary', e)) + (scanningOptions.middleMouse && DOM.isMouseButtonDown(e, 'auxiliary')) )) { return; } diff --git a/ext/fg/js/frontend.js b/ext/fg/js/frontend.js index 81c159db..ee653d78 100644 --- a/ext/fg/js/frontend.js +++ b/ext/fg/js/frontend.js @@ -80,7 +80,7 @@ class Frontend { onMouseMove(e) { this.popupTimerClear(); - if (this.pendingLookup || Frontend.isMouseButtonDown('primary', e)) { + if (this.pendingLookup || DOM.isMouseButtonDown(e, 'primary')) { return; } @@ -88,7 +88,7 @@ class Frontend { const scanningModifier = scanningOptions.modifier; if (!( Frontend.isScanningModifierPressed(scanningModifier, e) || - (scanningOptions.middleMouse && Frontend.isMouseButtonDown('auxiliary', e)) + (scanningOptions.middleMouse && DOM.isMouseButtonDown(e, 'auxiliary')) )) { return; } @@ -487,37 +487,6 @@ class Frontend { default: return false; } } - - static isMouseButton(button, mouseEvent) { - switch (mouseEvent.type) { - case 'mouseup': - case 'mousedown': - case 'click': - return Frontend.isMouseButtonPressed(button, mouseEvent); - default: - return Frontend.isMouseButtonDown(button, mouseEvent); - } - } - - static isMouseButtonPressed(button, mouseEvent) { - const mouseEventButton = mouseEvent.button; - switch (button) { - case 'primary': return mouseEventButton === 0; - case 'secondary': return mouseEventButton === 2; - case 'auxiliary': return mouseEventButton === 1; - default: return false; - } - } - - static isMouseButtonDown(button, mouseEvent) { - const mouseEventButtons = mouseEvent.buttons; - switch (button) { - case 'primary': return (mouseEventButtons & 0x1) !== 0x0; - case 'secondary': return (mouseEventButtons & 0x2) !== 0x0; - case 'auxiliary': return (mouseEventButtons & 0x4) !== 0x0; - default: return false; - } - } } Frontend.windowMessageHandlers = { diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index cbf8efb7..854418f4 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -85,7 +85,7 @@ class Display { } onGlossaryMouseDown(e) { - if (Frontend.isMouseButtonPressed('primary', e)) { + if (DOM.isMouseButtonPressed(e, 'primary')) { this.clickScanPrevent = false; } } @@ -95,7 +95,7 @@ class Display { } onGlossaryMouseUp(e) { - if (!this.clickScanPrevent && Frontend.isMouseButtonPressed('primary', e)) { + if (!this.clickScanPrevent && DOM.isMouseButtonPressed(e, 'primary')) { this.onTermLookup(e); } } diff --git a/ext/mixed/js/dom.js b/ext/mixed/js/dom.js index 4525dace..4e4d49e3 100644 --- a/ext/mixed/js/dom.js +++ b/ext/mixed/js/dom.js @@ -43,4 +43,24 @@ class DOM { } return false; } + + static isMouseButtonPressed(mouseEvent, button) { + const mouseEventButton = mouseEvent.button; + switch (button) { + case 'primary': return mouseEventButton === 0; + case 'secondary': return mouseEventButton === 2; + case 'auxiliary': return mouseEventButton === 1; + default: return false; + } + } + + static isMouseButtonDown(mouseEvent, button) { + const mouseEventButtons = mouseEvent.buttons; + switch (button) { + case 'primary': return (mouseEventButtons & 0x1) !== 0x0; + case 'secondary': return (mouseEventButtons & 0x2) !== 0x0; + case 'auxiliary': return (mouseEventButtons & 0x4) !== 0x0; + default: return false; + } + } } -- cgit v1.2.3 From 0aed27b66d9c496e4cd57ef95d982c4e634a8666 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Mon, 25 Nov 2019 14:19:18 -0500 Subject: Replace hasOwnProperty with simplified hasOwn function --- ext/bg/js/api.js | 4 ++-- ext/bg/js/audio.js | 6 +++--- ext/bg/js/backend.js | 2 +- ext/bg/js/conditions-ui.js | 20 ++++++++++---------- ext/bg/js/conditions.js | 30 +++++++++++++++--------------- ext/bg/js/database.js | 2 +- ext/bg/js/dictionary.js | 4 ++-- ext/bg/js/mecab.js | 2 +- ext/bg/js/options.js | 2 +- ext/bg/js/search.js | 2 +- ext/bg/js/settings-dictionaries.js | 4 ++-- ext/bg/js/settings-popup-preview.js | 2 +- ext/bg/js/translator.js | 12 ++++++------ ext/fg/js/float.js | 4 ++-- ext/fg/js/frontend-api-receiver.js | 2 +- ext/fg/js/frontend-api-sender.js | 6 +++--- ext/fg/js/frontend.js | 4 ++-- ext/fg/js/popup-proxy-host.js | 4 ++-- ext/mixed/js/audio.js | 2 +- ext/mixed/js/core.js | 4 ++++ ext/mixed/js/display.js | 4 ++-- 21 files changed, 63 insertions(+), 59 deletions(-) (limited to 'ext/mixed') diff --git a/ext/bg/js/api.js b/ext/bg/js/api.js index 766fb0ed..12257e92 100644 --- a/ext/bg/js/api.js +++ b/ext/bg/js/api.js @@ -45,7 +45,7 @@ async function apiOptionsSet(changedOptions, optionsContext, source) { function modifyOption(path, value, options) { let pivot = options; for (const key of path.slice(0, -1)) { - if (!pivot.hasOwnProperty(key)) { + if (!hasOwn(pivot, key)) { return false; } pivot = pivot[key]; @@ -236,7 +236,7 @@ async function apiTemplateRender(template, data, dynamic) { async function apiCommandExec(command, params) { const handlers = apiCommandExec.handlers; - if (handlers.hasOwnProperty(command)) { + if (hasOwn(handlers, command)) { const handler = handlers[command]; handler(params); } diff --git a/ext/bg/js/audio.js b/ext/bg/js/audio.js index cd42a158..9bbbf902 100644 --- a/ext/bg/js/audio.js +++ b/ext/bg/js/audio.js @@ -107,12 +107,12 @@ const audioUrlBuilders = { 'custom': async (definition, optionsContext) => { const options = await apiOptionsGet(optionsContext); const customSourceUrl = options.audio.customSourceUrl; - return customSourceUrl.replace(/\{([^\}]*)\}/g, (m0, m1) => (definition.hasOwnProperty(m1) ? `${definition[m1]}` : m0)); + return customSourceUrl.replace(/\{([^\}]*)\}/g, (m0, m1) => (hasOwn(definition, m1) ? `${definition[m1]}` : m0)); } }; async function audioGetUrl(definition, mode, optionsContext, download) { - if (audioUrlBuilders.hasOwnProperty(mode)) { + if (hasOwn(audioUrlBuilders, mode)) { const handler = audioUrlBuilders[mode]; try { return await handler(definition, optionsContext, download); @@ -171,7 +171,7 @@ async function audioInject(definition, fields, sources, optionsContext) { try { let audioSourceDefinition = definition; - if (definition.hasOwnProperty('expressions')) { + if (hasOwn(definition, 'expressions')) { audioSourceDefinition = definition.expressions[0]; } diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index 45db9660..4190116b 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -73,7 +73,7 @@ class Backend { onMessage({action, params}, sender, callback) { const handlers = Backend.messageHandlers; - if (handlers.hasOwnProperty(action)) { + if (hasOwn(handlers, action)) { const handler = handlers[action]; const promise = handler(params, sender); promise.then( diff --git a/ext/bg/js/conditions-ui.js b/ext/bg/js/conditions-ui.js index 43c6dc08..cc9db087 100644 --- a/ext/bg/js/conditions-ui.js +++ b/ext/bg/js/conditions-ui.js @@ -84,7 +84,7 @@ ConditionsUI.Container = class Container { createDefaultCondition(type) { let operator = ''; let value = ''; - if (this.conditionDescriptors.hasOwnProperty(type)) { + if (hasOwn(this.conditionDescriptors, type)) { const conditionDescriptor = this.conditionDescriptors[type]; operator = conditionDescriptor.defaultOperator; ({value} = this.getOperatorDefaultValue(type, operator)); @@ -96,15 +96,15 @@ ConditionsUI.Container = class Container { } getOperatorDefaultValue(type, operator) { - if (this.conditionDescriptors.hasOwnProperty(type)) { + if (hasOwn(this.conditionDescriptors, type)) { const conditionDescriptor = this.conditionDescriptors[type]; - if (conditionDescriptor.operators.hasOwnProperty(operator)) { + if (hasOwn(conditionDescriptor.operators, operator)) { const operatorDescriptor = conditionDescriptor.operators[operator]; - if (operatorDescriptor.hasOwnProperty('defaultValue')) { + if (hasOwn(operatorDescriptor, 'defaultValue')) { return {value: operatorDescriptor.defaultValue, fromOperator: true}; } } - if (conditionDescriptor.hasOwnProperty('defaultValue')) { + if (hasOwn(conditionDescriptor, 'defaultValue')) { return {value: conditionDescriptor.defaultValue, fromOperator: false}; } } @@ -219,7 +219,7 @@ ConditionsUI.Condition = class Condition { optionGroup.empty(); const type = this.condition.type; - if (conditionDescriptors.hasOwnProperty(type)) { + if (hasOwn(conditionDescriptors, type)) { const conditionDescriptor = conditionDescriptors[type]; const operators = conditionDescriptor.operators; for (const operatorName of Object.keys(operators)) { @@ -240,23 +240,23 @@ ConditionsUI.Condition = class Condition { }; const objects = []; - if (conditionDescriptors.hasOwnProperty(type)) { + if (hasOwn(conditionDescriptors, type)) { const conditionDescriptor = conditionDescriptors[type]; objects.push(conditionDescriptor); - if (conditionDescriptor.operators.hasOwnProperty(operator)) { + if (hasOwn(conditionDescriptor.operators, operator)) { const operatorDescriptor = conditionDescriptor.operators[operator]; objects.push(operatorDescriptor); } } for (const object of objects) { - if (object.hasOwnProperty('placeholder')) { + if (hasOwn(object, 'placeholder')) { props.placeholder = object.placeholder; } if (object.type === 'number') { props.type = 'number'; for (const prop of ['step', 'min', 'max']) { - if (object.hasOwnProperty(prop)) { + if (hasOwn(object, prop)) { props[prop] = object[prop]; } } diff --git a/ext/bg/js/conditions.js b/ext/bg/js/conditions.js index ed4b14f5..c0f0f301 100644 --- a/ext/bg/js/conditions.js +++ b/ext/bg/js/conditions.js @@ -18,14 +18,14 @@ function conditionsValidateOptionValue(object, value) { - if (object.hasOwnProperty('validate') && !object.validate(value)) { + if (hasOwn(object, 'validate') && !object.validate(value)) { throw new Error('Invalid value for condition'); } - if (object.hasOwnProperty('transform')) { + if (hasOwn(object, 'transform')) { value = object.transform(value); - if (object.hasOwnProperty('validateTransformed') && !object.validateTransformed(value)) { + if (hasOwn(object, 'validateTransformed') && !object.validateTransformed(value)) { throw new Error('Invalid value for condition'); } } @@ -34,12 +34,12 @@ function conditionsValidateOptionValue(object, value) { } function conditionsNormalizeOptionValue(descriptors, type, operator, optionValue) { - if (!descriptors.hasOwnProperty(type)) { + if (!hasOwn(descriptors, type)) { throw new Error('Invalid type'); } const conditionDescriptor = descriptors[type]; - if (!conditionDescriptor.operators.hasOwnProperty(operator)) { + if (!hasOwn(conditionDescriptor.operators, operator)) { throw new Error('Invalid operator'); } @@ -48,28 +48,28 @@ function conditionsNormalizeOptionValue(descriptors, type, operator, optionValue let transformedValue = conditionsValidateOptionValue(conditionDescriptor, optionValue); transformedValue = conditionsValidateOptionValue(operatorDescriptor, transformedValue); - if (operatorDescriptor.hasOwnProperty('transformReverse')) { + if (hasOwn(operatorDescriptor, 'transformReverse')) { transformedValue = operatorDescriptor.transformReverse(transformedValue); } return transformedValue; } function conditionsTestValueThrowing(descriptors, type, operator, optionValue, value) { - if (!descriptors.hasOwnProperty(type)) { + if (!hasOwn(descriptors, type)) { throw new Error('Invalid type'); } const conditionDescriptor = descriptors[type]; - if (!conditionDescriptor.operators.hasOwnProperty(operator)) { + if (!hasOwn(conditionDescriptor.operators, operator)) { throw new Error('Invalid operator'); } const operatorDescriptor = conditionDescriptor.operators[operator]; - if (operatorDescriptor.hasOwnProperty('transform')) { - if (operatorDescriptor.hasOwnProperty('transformCache')) { + if (hasOwn(operatorDescriptor, 'transform')) { + if (hasOwn(operatorDescriptor, 'transformCache')) { const key = `${optionValue}`; const transformCache = operatorDescriptor.transformCache; - if (transformCache.hasOwnProperty(key)) { + if (hasOwn(transformCache, key)) { optionValue = transformCache[key]; } else { optionValue = operatorDescriptor.transform(optionValue); @@ -93,23 +93,23 @@ function conditionsTestValue(descriptors, type, operator, optionValue, value) { function conditionsClearCaches(descriptors) { for (const type in descriptors) { - if (!descriptors.hasOwnProperty(type)) { + if (!hasOwn(descriptors, type)) { continue; } const conditionDescriptor = descriptors[type]; - if (conditionDescriptor.hasOwnProperty('transformCache')) { + if (hasOwn(conditionDescriptor, 'transformCache')) { conditionDescriptor.transformCache = {}; } const operatorDescriptors = conditionDescriptor.operators; for (const operator in operatorDescriptors) { - if (!operatorDescriptors.hasOwnProperty(operator)) { + if (!hasOwn(operatorDescriptors, operator)) { continue; } const operatorDescriptor = operatorDescriptors[operator]; - if (operatorDescriptor.hasOwnProperty('transformCache')) { + if (hasOwn(operatorDescriptor, 'transformCache')) { operatorDescriptor.transformCache = {}; } } diff --git a/ext/bg/js/database.js b/ext/bg/js/database.js index 9b560f78..c53c9f77 100644 --- a/ext/bg/js/database.js +++ b/ext/bg/js/database.js @@ -137,7 +137,7 @@ class Database { const visited = {}; const results = []; const processRow = (row, index) => { - if (titles.includes(row.dictionary) && !visited.hasOwnProperty(row.id)) { + if (titles.includes(row.dictionary) && !hasOwn(visited, row.id)) { visited[row.id] = true; results.push(Database.createTerm(row, index)); } diff --git a/ext/bg/js/dictionary.js b/ext/bg/js/dictionary.js index 9aa0af9c..affce9e9 100644 --- a/ext/bg/js/dictionary.js +++ b/ext/bg/js/dictionary.js @@ -81,7 +81,7 @@ function dictTermsUndupe(definitions) { const definitionGroups = {}; for (const definition of definitions) { const definitionExisting = definitionGroups[definition.id]; - if (!definitionGroups.hasOwnProperty(definition.id) || definition.expression.length > definitionExisting.expression.length) { + if (!hasOwn(definitionGroups, definition.id) || definition.expression.length > definitionExisting.expression.length) { definitionGroups[definition.id] = definition; } } @@ -131,7 +131,7 @@ function dictTermsGroup(definitions, dictionaries) { } const keyString = key.toString(); - if (groups.hasOwnProperty(keyString)) { + if (hasOwn(groups, keyString)) { groups[keyString].push(definition); } else { groups[keyString] = [definition]; diff --git a/ext/bg/js/mecab.js b/ext/bg/js/mecab.js index 246f8bba..297432e2 100644 --- a/ext/bg/js/mecab.js +++ b/ext/bg/js/mecab.js @@ -60,7 +60,7 @@ class Mecab { } onNativeMessage({sequence, data}) { - if (this.listeners.hasOwnProperty(sequence)) { + if (hasOwn(this.listeners, sequence)) { const {callback, timer} = this.listeners[sequence]; clearTimeout(timer); callback(data); diff --git a/ext/bg/js/options.js b/ext/bg/js/options.js index 63d88789..358a6b45 100644 --- a/ext/bg/js/options.js +++ b/ext/bg/js/options.js @@ -336,7 +336,7 @@ function profileOptionsSetDefaults(options) { const combine = (target, source) => { for (const key in source) { - if (!target.hasOwnProperty(key)) { + if (!hasOwn(target, key)) { target[key] = source[key]; } } diff --git a/ext/bg/js/search.js b/ext/bg/js/search.js index 0922d938..16cbfbbd 100644 --- a/ext/bg/js/search.js +++ b/ext/bg/js/search.js @@ -234,7 +234,7 @@ class DisplaySearch extends Display { onRuntimeMessage({action, params}, sender, callback) { const handlers = DisplaySearch.runtimeMessageHandlers; - if (handlers.hasOwnProperty(action)) { + if (hasOwn(handlers, action)) { const handler = handlers[action]; const result = handler(this, params); callback(result); diff --git a/ext/bg/js/settings-dictionaries.js b/ext/bg/js/settings-dictionaries.js index ebd380ac..177379b0 100644 --- a/ext/bg/js/settings-dictionaries.js +++ b/ext/bg/js/settings-dictionaries.js @@ -81,7 +81,7 @@ class SettingsDictionaryListUI { let changed = false; let optionsDictionary; const optionsDictionaries = this.optionsDictionaries; - if (optionsDictionaries.hasOwnProperty(title)) { + if (hasOwn(optionsDictionaries, title)) { optionsDictionary = optionsDictionaries[title]; } else { optionsDictionary = SettingsDictionaryListUI.createDictionaryOptions(); @@ -466,7 +466,7 @@ function dictionaryErrorsShow(errors) { for (let e of errors) { console.error(e); e = dictionaryErrorToString(e); - uniqueErrors[e] = uniqueErrors.hasOwnProperty(e) ? uniqueErrors[e] + 1 : 1; + uniqueErrors[e] = hasOwn(uniqueErrors, e) ? uniqueErrors[e] + 1 : 1; } for (const e in uniqueErrors) { diff --git a/ext/bg/js/settings-popup-preview.js b/ext/bg/js/settings-popup-preview.js index 7d641c46..49409968 100644 --- a/ext/bg/js/settings-popup-preview.js +++ b/ext/bg/js/settings-popup-preview.js @@ -106,7 +106,7 @@ class SettingsPopupPreview { onMessage(e) { const {action, params} = e.data; const handlers = SettingsPopupPreview.messageHandlers; - if (handlers.hasOwnProperty(action)) { + if (hasOwn(handlers, action)) { const handler = handlers[action]; handler(this, params); } diff --git a/ext/bg/js/translator.js b/ext/bg/js/translator.js index e27cbdff..0a0ce663 100644 --- a/ext/bg/js/translator.js +++ b/ext/bg/js/translator.js @@ -297,7 +297,7 @@ class Translator { for (const deinflection of deinflections) { const term = deinflection.term; let deinflectionArray; - if (uniqueDeinflectionsMap.hasOwnProperty(term)) { + if (hasOwn(uniqueDeinflectionsMap, term)) { deinflectionArray = uniqueDeinflectionsMap[term]; } else { deinflectionArray = []; @@ -355,7 +355,7 @@ class Translator { const kanjiUnique = {}; const kanjiList = []; for (const c of text) { - if (!kanjiUnique.hasOwnProperty(c)) { + if (!hasOwn(kanjiUnique, c)) { kanjiList.push(c); kanjiUnique[c] = true; } @@ -417,7 +417,7 @@ class Translator { const expression = term.expression; term.frequencies = []; - if (termsUniqueMap.hasOwnProperty(expression)) { + if (hasOwn(termsUniqueMap, expression)) { termsUniqueMap[expression].push(term); } else { const termList = [term]; @@ -464,7 +464,7 @@ class Translator { const category = meta.category; const group = ( - stats.hasOwnProperty(category) ? + hasOwn(stats, category) ? stats[category] : (stats[category] = []) ); @@ -484,7 +484,7 @@ class Translator { async getTagMetaList(names, title) { const tagMetaList = []; const cache = ( - this.tagCache.hasOwnProperty(title) ? + hasOwn(this.tagCache, title) ? this.tagCache[title] : (this.tagCache[title] = {}) ); @@ -492,7 +492,7 @@ class Translator { for (const name of names) { const base = Translator.getNameBase(name); - if (cache.hasOwnProperty(base)) { + if (hasOwn(cache, base)) { tagMetaList.push(cache[base]); } else { const tagMeta = await this.database.findTagForTitle(base, title); diff --git a/ext/fg/js/float.js b/ext/fg/js/float.js index 089c9422..ae54be00 100644 --- a/ext/fg/js/float.js +++ b/ext/fg/js/float.js @@ -49,7 +49,7 @@ class DisplayFloat extends Display { onMessage(e) { const {action, params} = e.data; const handlers = DisplayFloat.messageHandlers; - if (handlers.hasOwnProperty(action)) { + if (hasOwn(handlers, action)) { const handler = handlers[action]; handler(this, params); } @@ -58,7 +58,7 @@ class DisplayFloat extends Display { onKeyDown(e) { const key = Display.getKeyFromEvent(e); const handlers = DisplayFloat.onKeyDownHandlers; - if (handlers.hasOwnProperty(key)) { + if (hasOwn(handlers, key)) { const handler = handlers[key]; if (handler(this, e)) { e.preventDefault(); diff --git a/ext/fg/js/frontend-api-receiver.js b/ext/fg/js/frontend-api-receiver.js index fbfb3ab0..bde14646 100644 --- a/ext/fg/js/frontend-api-receiver.js +++ b/ext/fg/js/frontend-api-receiver.js @@ -34,7 +34,7 @@ class FrontendApiReceiver { onMessage(port, {id, action, params, target, senderId}) { if ( target !== this.source || - !this.handlers.hasOwnProperty(action) + !hasOwn(this.handlers, action) ) { return; } diff --git a/ext/fg/js/frontend-api-sender.js b/ext/fg/js/frontend-api-sender.js index c6eeaeb2..af998a8f 100644 --- a/ext/fg/js/frontend-api-sender.js +++ b/ext/fg/js/frontend-api-sender.js @@ -78,7 +78,7 @@ class FrontendApiSender { } onAck(id) { - if (!this.callbacks.hasOwnProperty(id)) { + if (!hasOwn(this.callbacks, id)) { console.warn(`ID ${id} not found for ack`); return; } @@ -95,7 +95,7 @@ class FrontendApiSender { } onResult(id, data) { - if (!this.callbacks.hasOwnProperty(id)) { + if (!hasOwn(this.callbacks, id)) { console.warn(`ID ${id} not found`); return; } @@ -118,7 +118,7 @@ class FrontendApiSender { } onError(id, reason) { - if (!this.callbacks.hasOwnProperty(id)) { return; } + if (!hasOwn(this.callbacks, id)) { return; } const info = this.callbacks[id]; delete this.callbacks[id]; info.timer = null; diff --git a/ext/fg/js/frontend.js b/ext/fg/js/frontend.js index ee653d78..16302e82 100644 --- a/ext/fg/js/frontend.js +++ b/ext/fg/js/frontend.js @@ -237,7 +237,7 @@ class Frontend { onWindowMessage(e) { const action = e.data; const handlers = Frontend.windowMessageHandlers; - if (handlers.hasOwnProperty(action)) { + if (hasOwn(handlers, action)) { const handler = handlers[action]; handler(this); } @@ -245,7 +245,7 @@ class Frontend { onRuntimeMessage({action, params}, sender, callback) { const handlers = Frontend.runtimeMessageHandlers; - if (handlers.hasOwnProperty(action)) { + if (hasOwn(handlers, action)) { const handler = handlers[action]; const result = handler(this, params); callback(result); diff --git a/ext/fg/js/popup-proxy-host.js b/ext/fg/js/popup-proxy-host.js index d8dec4df..b2f18b97 100644 --- a/ext/fg/js/popup-proxy-host.js +++ b/ext/fg/js/popup-proxy-host.js @@ -50,7 +50,7 @@ class PopupProxyHost { } createPopup(parentId, depth) { - const parent = (typeof parentId === 'string' && this.popups.hasOwnProperty(parentId) ? this.popups[parentId] : null); + const parent = (typeof parentId === 'string' && hasOwn(this.popups, parentId) ? this.popups[parentId] : null); const id = `${this.nextId}`; if (parent !== null) { depth = parent.depth + 1; @@ -70,7 +70,7 @@ class PopupProxyHost { } getPopup(id) { - if (!this.popups.hasOwnProperty(id)) { + if (!hasOwn(this.popups, id)) { throw new Error('Invalid popup ID'); } diff --git a/ext/mixed/js/audio.js b/ext/mixed/js/audio.js index 4e9d04fa..7d5ffedd 100644 --- a/ext/mixed/js/audio.js +++ b/ext/mixed/js/audio.js @@ -113,7 +113,7 @@ function audioGetFromUrl(url, willDownload) { async function audioGetFromSources(expression, sources, optionsContext, willDownload, cache=null) { const key = `${expression.expression}:${expression.reading}`; - if (cache !== null && cache.hasOwnProperty(expression)) { + if (cache !== null && hasOwn(cache, expression)) { return cache[key]; } diff --git a/ext/mixed/js/core.js b/ext/mixed/js/core.js index 8a8a2368..d82b9b4b 100644 --- a/ext/mixed/js/core.js +++ b/ext/mixed/js/core.js @@ -94,6 +94,10 @@ function isObject(value) { return typeof value === 'object' && value !== null && !Array.isArray(value); } +function hasOwn(object, property) { + return Object.prototype.hasOwnProperty.call(object, property); +} + // toIterable is required on Edge for cross-window origin objects. function toIterable(value) { if (typeof Symbol !== 'undefined' && typeof value[Symbol.iterator] !== 'undefined') { diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index 854418f4..ce43b22c 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -194,7 +194,7 @@ class Display { onKeyDown(e) { const key = Display.getKeyFromEvent(e); const handlers = Display.onKeyDownHandlers; - if (handlers.hasOwnProperty(key)) { + if (hasOwn(handlers, key)) { const handler = handlers[key]; if (handler(this, e)) { e.preventDefault(); @@ -216,7 +216,7 @@ class Display { onRuntimeMessage({action, params}, sender, callback) { const handlers = Display.runtimeMessageHandlers; - if (handlers.hasOwnProperty(action)) { + if (hasOwn(handlers, action)) { const handler = handlers[action]; const result = handler(this, params); callback(result); -- cgit v1.2.3 From 943350a1f66b3576e98c58539cbff277b0069977 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Mon, 25 Nov 2019 14:21:19 -0500 Subject: Use single quotes --- ext/bg/js/search.js | 2 +- ext/fg/js/popup.js | 2 +- ext/fg/js/source.js | 4 ++-- ext/mixed/js/display.js | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'ext/mixed') diff --git a/ext/bg/js/search.js b/ext/bg/js/search.js index 16cbfbbd..ae76c23b 100644 --- a/ext/bg/js/search.js +++ b/ext/bg/js/search.js @@ -324,7 +324,7 @@ class DisplaySearch extends Display { this.intro.style.transition = ''; this.intro.style.height = ''; const size = this.intro.getBoundingClientRect(); - this.intro.style.height = `0px`; + this.intro.style.height = '0px'; this.intro.style.transition = `height ${duration}s ease-in-out 0s`; window.getComputedStyle(this.intro).getPropertyValue('height'); // Commits height so next line can start animation this.intro.style.height = `${size.height}px`; diff --git a/ext/fg/js/popup.js b/ext/fg/js/popup.js index ac96f9e8..df784029 100644 --- a/ext/fg/js/popup.js +++ b/ext/fg/js/popup.js @@ -401,7 +401,7 @@ class Popup { if (Popup.outerStylesheet === null) { if (!css) { return; } Popup.outerStylesheet = document.createElement('style'); - Popup.outerStylesheet.id = "yomichan-popup-outer-stylesheet"; + Popup.outerStylesheet.id = 'yomichan-popup-outer-stylesheet'; } const outerStylesheet = Popup.outerStylesheet; diff --git a/ext/fg/js/source.js b/ext/fg/js/source.js index 5be521fa..886093d7 100644 --- a/ext/fg/js/source.js +++ b/ext/fg/js/source.js @@ -99,9 +99,9 @@ class TextSourceRange { static getRubyElement(node) { node = TextSourceRange.getParentElement(node); - if (node !== null && node.nodeName.toUpperCase() === "RT") { + if (node !== null && node.nodeName.toUpperCase() === 'RT') { node = node.parentNode; - return (node !== null && node.nodeName.toUpperCase() === "RUBY") ? node : null; + return (node !== null && node.nodeName.toUpperCase() === 'RUBY') ? node : null; } return null; } diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index ce43b22c..b454bf59 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -574,7 +574,7 @@ class Display { if (button !== null) { let titleDefault = button.dataset.titleDefault; if (!titleDefault) { - titleDefault = button.title || ""; + titleDefault = button.title || ''; button.dataset.titleDefault = titleDefault; } button.title = `${titleDefault}\n${info}`; -- cgit v1.2.3 From 527595f79bf97bc2d17cb821c8bb6b4e8b6776f9 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Mon, 25 Nov 2019 14:25:11 -0500 Subject: Remove unnecessary escapes from regex literals --- ext/bg/js/audio.js | 4 ++-- ext/bg/js/dictionary.js | 2 +- ext/bg/js/search.js | 4 ++-- ext/fg/js/document.js | 2 +- ext/fg/js/popup.js | 2 +- ext/mixed/js/audio.js | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) (limited to 'ext/mixed') diff --git a/ext/bg/js/audio.js b/ext/bg/js/audio.js index 9bbbf902..dc0ba5eb 100644 --- a/ext/bg/js/audio.js +++ b/ext/bg/js/audio.js @@ -107,7 +107,7 @@ const audioUrlBuilders = { 'custom': async (definition, optionsContext) => { const options = await apiOptionsGet(optionsContext); const customSourceUrl = options.audio.customSourceUrl; - return customSourceUrl.replace(/\{([^\}]*)\}/g, (m0, m1) => (hasOwn(definition, m1) ? `${definition[m1]}` : m0)); + return customSourceUrl.replace(/\{([^}]*)\}/g, (m0, m1) => (hasOwn(definition, m1) ? `${definition[m1]}` : m0)); } }; @@ -133,7 +133,7 @@ function audioUrlNormalize(url, baseUrl, basePath) { // Begins with "/" url = baseUrl + url; } - } else if (!/^[a-z][a-z0-9\+\-\.]*:/i.test(url)) { + } else if (!/^[a-z][a-z0-9\-+.]*:/i.test(url)) { // No URI scheme => relative path url = baseUrl + basePath + url; } diff --git a/ext/bg/js/dictionary.js b/ext/bg/js/dictionary.js index affce9e9..409bed85 100644 --- a/ext/bg/js/dictionary.js +++ b/ext/bg/js/dictionary.js @@ -322,7 +322,7 @@ async function dictFieldFormat(field, definition, mode, options, exceptions) { compactGlossaries: options.general.compactGlossaries }; const markers = dictFieldFormat.markers; - const pattern = /\{([\w\-]+)\}/g; + const pattern = /\{([\w-]+)\}/g; return await stringReplaceAsync(field, pattern, async (g0, marker) => { if (!markers.has(marker)) { return g0; diff --git a/ext/bg/js/search.js b/ext/bg/js/search.js index ae76c23b..552b7a59 100644 --- a/ext/bg/js/search.js +++ b/ext/bg/js/search.js @@ -207,7 +207,7 @@ class DisplaySearch extends Display { async onSearchQueryUpdated(query, animate) { try { const details = {}; - const match = /[\*\uff0a]+$/.exec(query); + const match = /[*\uff0a]+$/.exec(query); if (match !== null) { details.wildcard = true; query = query.substring(0, query.length - match[0].length); @@ -356,7 +356,7 @@ class DisplaySearch extends Display { } static getSearchQueryFromLocation(url) { - let match = /^[^\?#]*\?(?:[^&#]*&)?query=([^&#]*)/.exec(url); + let match = /^[^?#]*\?(?:[^&#]*&)?query=([^&#]*)/.exec(url); return match !== null ? decodeURIComponent(match[1]) : null; } } diff --git a/ext/fg/js/document.js b/ext/fg/js/document.js index 3dd12a40..10dea7df 100644 --- a/ext/fg/js/document.js +++ b/ext/fg/js/document.js @@ -17,7 +17,7 @@ */ -const REGEX_TRANSPARENT_COLOR = /rgba\s*\([^\)]*,\s*0(?:\.0+)?\s*\)/; +const REGEX_TRANSPARENT_COLOR = /rgba\s*\([^)]*,\s*0(?:\.0+)?\s*\)/; function docSetImposterStyle(style, propertyName, value) { style.setProperty(propertyName, value, 'important'); diff --git a/ext/fg/js/popup.js b/ext/fg/js/popup.js index df784029..c40e5d60 100644 --- a/ext/fg/js/popup.js +++ b/ext/fg/js/popup.js @@ -303,7 +303,7 @@ class Popup { } static getColorInfo(cssColor) { - const m = /^\s*rgba?\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([\d\.]+)\s*)?\)\s*$/.exec(cssColor); + const m = /^\s*rgba?\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([\d.]+)\s*)?\)\s*$/.exec(cssColor); if (m === null) { return null; } const m4 = m[4]; diff --git a/ext/mixed/js/audio.js b/ext/mixed/js/audio.js index 7d5ffedd..35f283a4 100644 --- a/ext/mixed/js/audio.js +++ b/ext/mixed/js/audio.js @@ -68,7 +68,7 @@ class TextToSpeechAudio { } static createFromUri(ttsUri) { - const m = /^tts:[^#\?]*\?([^#]*)/.exec(ttsUri); + const m = /^tts:[^#?]*\?([^#]*)/.exec(ttsUri); if (m === null) { return null; } const searchParameters = {}; -- cgit v1.2.3 From acb70f126cd87234b442fd599061f1b7539c846b Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Mon, 25 Nov 2019 14:35:53 -0500 Subject: Update unused arguments --- ext/bg/js/anki.js | 10 +++++----- ext/bg/js/backend.js | 2 +- ext/bg/js/search.js | 4 ++-- ext/fg/js/api.js | 2 +- ext/fg/js/frontend.js | 4 ++-- ext/fg/js/source.js | 2 +- ext/mixed/js/display.js | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) (limited to 'ext/mixed') diff --git a/ext/bg/js/anki.js b/ext/bg/js/anki.js index 9f851f13..ac45784b 100644 --- a/ext/bg/js/anki.js +++ b/ext/bg/js/anki.js @@ -108,11 +108,11 @@ class AnkiConnect { */ class AnkiNull { - async addNote(note) { + async addNote() { return null; } - async canAddNotes(notes) { + async canAddNotes() { return []; } @@ -124,15 +124,15 @@ class AnkiNull { return []; } - async getModelFieldNames(modelName) { + async getModelFieldNames() { return []; } - async guiBrowse(query) { + async guiBrowse() { return []; } - async findNoteIds(notes) { + async findNoteIds() { return []; } } diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index 4190116b..73df7cf5 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -177,7 +177,7 @@ class Backend { } } - checkLastError(e) { + checkLastError() { // NOP } } diff --git a/ext/bg/js/search.js b/ext/bg/js/search.js index e5cdf272..a98d7a9a 100644 --- a/ext/bg/js/search.js +++ b/ext/bg/js/search.js @@ -167,7 +167,7 @@ class DisplaySearch extends Display { this.onSearchQueryUpdated(query, true); } - onPopState(e) { + onPopState() { const query = DisplaySearch.getSearchQueryFromLocation(window.location.href) || ''; if (this.query !== null) { if (this.isWanakanaEnabled()) { @@ -245,7 +245,7 @@ class DisplaySearch extends Display { initClipboardMonitor() { // ignore copy from search page - window.addEventListener('copy', (e) => { + window.addEventListener('copy', () => { this.clipboardPrevText = document.getSelection().toString().trim(); }); } diff --git a/ext/fg/js/api.js b/ext/fg/js/api.js index f881b23d..0e100b59 100644 --- a/ext/fg/js/api.js +++ b/ext/fg/js/api.js @@ -113,6 +113,6 @@ function _apiInvoke(action, params={}) { }); } -function _apiCheckLastError(e) { +function _apiCheckLastError() { // NOP } diff --git a/ext/fg/js/frontend.js b/ext/fg/js/frontend.js index 8297f54d..bcdfd152 100644 --- a/ext/fg/js/frontend.js +++ b/ext/fg/js/frontend.js @@ -122,7 +122,7 @@ class Frontend { } } - onMouseOut(e) { + onMouseOut() { this.popupTimerClear(); } @@ -135,7 +135,7 @@ class Frontend { } } - onAuxClick(e) { + onAuxClick() { this.preventNextContextMenu = false; } diff --git a/ext/fg/js/source.js b/ext/fg/js/source.js index e6b991c4..a84feed4 100644 --- a/ext/fg/js/source.js +++ b/ext/fg/js/source.js @@ -375,7 +375,7 @@ class TextSourceElement { return this.content.length; } - setStartOffset(length) { + setStartOffset() { return 0; } diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index b454bf59..2396805a 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -42,7 +42,7 @@ class Display { this.setInteractive(true); } - onError(error) { + onError(_error) { throw new Error('Override me'); } @@ -90,7 +90,7 @@ class Display { } } - onGlossaryMouseMove(e) { + onGlossaryMouseMove() { this.clickScanPrevent = true; } -- cgit v1.2.3 From 5a1046bc906a74ca39906a52acc62fc702a658f2 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Tue, 26 Nov 2019 22:01:54 -0500 Subject: Update arrow-parens to always --- .eslintrc.json | 2 +- ext/bg/js/anki.js | 2 +- ext/bg/js/api.js | 2 +- ext/bg/js/backend-api-forwarder.js | 4 ++-- ext/bg/js/backend.js | 6 +++--- ext/bg/js/context.js | 2 +- ext/bg/js/database.js | 22 +++++++++++----------- ext/bg/js/dictionary.js | 10 +++++----- ext/bg/js/options.js | 6 +++--- ext/bg/js/profile-conditions.js | 2 +- ext/bg/js/request.js | 2 +- ext/bg/js/search-query-parser.js | 4 ++-- ext/bg/js/settings-dictionaries.js | 10 +++++----- ext/bg/js/settings-profiles.js | 2 +- ext/bg/js/settings.js | 8 ++++---- ext/bg/js/translator.js | 8 ++++---- ext/bg/js/util.js | 4 ++-- ext/fg/js/frontend-api-receiver.js | 4 ++-- ext/fg/js/popup.js | 4 ++-- ext/mixed/js/core.js | 2 +- 20 files changed, 53 insertions(+), 53 deletions(-) (limited to 'ext/mixed') diff --git a/.eslintrc.json b/.eslintrc.json index fce4b884..0e3b939a 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -8,7 +8,7 @@ "/ext/bg/js/templates.js" ], "rules": { - "arrow-parens": ["error", "as-needed"], + "arrow-parens": ["error", "always"], "comma-dangle": ["error", "never"], "curly": ["error", "all"], "dot-notation": "error", diff --git a/ext/bg/js/anki.js b/ext/bg/js/anki.js index ac45784b..17b93620 100644 --- a/ext/bg/js/anki.js +++ b/ext/bg/js/anki.js @@ -74,7 +74,7 @@ class AnkiConnect { async findNoteIds(notes) { await this.checkVersion(); - const actions = notes.map(note => ({ + const actions = notes.map((note) => ({ action: 'findNotes', params: { query: `deck:"${AnkiConnect.escapeQuery(note.deckName)}" ${AnkiConnect.fieldsToQuery(note.fields)}` diff --git a/ext/bg/js/api.js b/ext/bg/js/api.js index d5256acb..b489b8d2 100644 --- a/ext/bg/js/api.js +++ b/ext/bg/js/api.js @@ -207,7 +207,7 @@ async function apiDefinitionsAddable(definitions, modes, optionsContext) { } if (cannotAdd.length > 0) { - const noteIdsArray = await anki.findNoteIds(cannotAdd.map(e => e[0])); + const noteIdsArray = await anki.findNoteIds(cannotAdd.map((e) => e[0])); for (let i = 0, ii = Math.min(cannotAdd.length, noteIdsArray.length); i < ii; ++i) { const noteIds = noteIdsArray[i]; if (noteIds.length > 0) { diff --git a/ext/bg/js/backend-api-forwarder.js b/ext/bg/js/backend-api-forwarder.js index 979afd16..db4d30b9 100644 --- a/ext/bg/js/backend-api-forwarder.js +++ b/ext/bg/js/backend-api-forwarder.js @@ -37,8 +37,8 @@ class BackendApiForwarder { const forwardPort = chrome.tabs.connect(tabId, {name: 'frontend-api-receiver'}); - port.onMessage.addListener(message => forwardPort.postMessage(message)); - forwardPort.onMessage.addListener(message => port.postMessage(message)); + port.onMessage.addListener((message) => forwardPort.postMessage(message)); + forwardPort.onMessage.addListener((message) => port.postMessage(message)); port.onDisconnect.addListener(() => forwardPort.disconnect()); forwardPort.onDisconnect.addListener(() => port.disconnect()); } diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index 73df7cf5..d9f9b586 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -60,7 +60,7 @@ class Backend { this.applyOptions(); const callback = () => this.checkLastError(chrome.runtime.lastError); - chrome.tabs.query({}, tabs => { + chrome.tabs.query({}, (tabs) => { for (const tab of tabs) { chrome.tabs.sendMessage(tab.id, {action: 'optionsUpdate', params: {source}}, callback); } @@ -77,8 +77,8 @@ class Backend { const handler = handlers[action]; const promise = handler(params, sender); promise.then( - result => callback({result}), - error => callback({error: errorToJson(error)}) + (result) => callback({result}), + (error) => callback({error: errorToJson(error)}) ); } diff --git a/ext/bg/js/context.js b/ext/bg/js/context.js index b288a79a..38a82636 100644 --- a/ext/bg/js/context.js +++ b/ext/bg/js/context.js @@ -63,7 +63,7 @@ window.addEventListener('DOMContentLoaded', () => { depth: 0, url: window.location.href }; - apiOptionsGet(optionsContext).then(options => { + apiOptionsGet(optionsContext).then((options) => { const toggle = document.querySelector('#enable-search'); toggle.checked = options.general.enable; toggle.addEventListener('change', () => apiCommandExec('toggle'), false); diff --git a/ext/bg/js/database.js b/ext/bg/js/database.js index c53c9f77..a20d5f15 100644 --- a/ext/bg/js/database.js +++ b/ext/bg/js/database.js @@ -257,7 +257,7 @@ class Database { const dbTerms = dbTransaction.objectStore('tagMeta'); const dbIndex = dbTerms.index('name'); const only = IDBKeyRange.only(name); - await Database.getAll(dbIndex, only, null, row => { + await Database.getAll(dbIndex, only, null, (row) => { if (title === row.dictionary) { result = row; } @@ -273,7 +273,7 @@ class Database { const dbTransaction = this.db.transaction(['dictionaries'], 'readonly'); const dbDictionaries = dbTransaction.objectStore('dictionaries'); - await Database.getAll(dbDictionaries, null, null, info => results.push(info)); + await Database.getAll(dbDictionaries, null, null, (info) => results.push(info)); return results; } @@ -308,7 +308,7 @@ class Database { counts.push(null); const index = i; const query2 = IDBKeyRange.only(dictionaryNames[i]); - const countPromise = Database.getCounts(targets, query2).then(v => counts[index] = v); + const countPromise = Database.getCounts(targets, query2).then((v) => counts[index] = v); countPromises.push(countPromise); } await Promise.all(countPromises); @@ -346,7 +346,7 @@ class Database { } }; - const indexDataLoaded = async summary => { + const indexDataLoaded = async (summary) => { if (summary.version > 3) { throw new Error('Unsupported dictionary version'); } @@ -522,13 +522,13 @@ class Database { await indexDataLoaded(summary); - const buildTermBankName = index => `term_bank_${index + 1}.json`; - const buildTermMetaBankName = index => `term_meta_bank_${index + 1}.json`; - const buildKanjiBankName = index => `kanji_bank_${index + 1}.json`; - const buildKanjiMetaBankName = index => `kanji_meta_bank_${index + 1}.json`; - const buildTagBankName = index => `tag_bank_${index + 1}.json`; + const buildTermBankName = (index) => `term_bank_${index + 1}.json`; + const buildTermMetaBankName = (index) => `term_meta_bank_${index + 1}.json`; + const buildKanjiBankName = (index) => `kanji_bank_${index + 1}.json`; + const buildKanjiMetaBankName = (index) => `kanji_meta_bank_${index + 1}.json`; + const buildTagBankName = (index) => `tag_bank_${index + 1}.json`; - const countBanks = namer => { + const countBanks = (namer) => { let count = 0; while (zip.files[namer(count)]) { ++count; @@ -657,7 +657,7 @@ class Database { const counts = {}; for (const [objectStoreName, index] of targets) { const n = objectStoreName; - const countPromise = Database.getCount(index, query).then(count => counts[n] = count); + const countPromise = Database.getCount(index, query).then((count) => counts[n] = count); countPromises.push(countPromise); } return Promise.all(countPromises).then(() => counts); diff --git a/ext/bg/js/dictionary.js b/ext/bg/js/dictionary.js index 409bed85..0b35e32e 100644 --- a/ext/bg/js/dictionary.js +++ b/ext/bg/js/dictionary.js @@ -99,8 +99,8 @@ function dictTermsCompressTags(definitions) { let lastPartOfSpeech = ''; for (const definition of definitions) { - const dictionary = JSON.stringify(definition.definitionTags.filter(tag => tag.category === 'dictionary').map(tag => tag.name).sort()); - const partOfSpeech = JSON.stringify(definition.definitionTags.filter(tag => tag.category === 'partOfSpeech').map(tag => tag.name).sort()); + const dictionary = JSON.stringify(definition.definitionTags.filter((tag) => tag.category === 'dictionary').map((tag) => tag.name).sort()); + const partOfSpeech = JSON.stringify(definition.definitionTags.filter((tag) => tag.category === 'partOfSpeech').map((tag) => tag.name).sort()); const filterOutCategories = []; @@ -117,7 +117,7 @@ function dictTermsCompressTags(definitions) { lastPartOfSpeech = partOfSpeech; } - definition.definitionTags = definition.definitionTags.filter(tag => !filterOutCategories.includes(tag.category)); + definition.definitionTags = definition.definitionTags.filter((tag) => !filterOutCategories.includes(tag.category)); } } @@ -231,7 +231,7 @@ function dictTermsMergeByGloss(result, definitions, appendTo, mergedIndices) { result.reading.add(definition.reading); for (const tag of definition.definitionTags) { - if (!definitionsByGloss[gloss].definitionTags.find(existingTag => existingTag.name === tag.name)) { + if (!definitionsByGloss[gloss].definitionTags.find((existingTag) => existingTag.name === tag.name)) { definitionsByGloss[gloss].definitionTags.push(tag); } } @@ -246,7 +246,7 @@ function dictTermsMergeByGloss(result, definitions, appendTo, mergedIndices) { } for (const tag of definition.termTags) { - if (!result.expressions.get(definition.expression).get(definition.reading).find(existingTag => existingTag.name === tag.name)) { + if (!result.expressions.get(definition.expression).get(definition.reading).find((existingTag) => existingTag.name === tag.name)) { result.expressions.get(definition.expression).get(definition.reading).push(tag); } } diff --git a/ext/bg/js/options.js b/ext/bg/js/options.js index 358a6b45..e53a8a13 100644 --- a/ext/bg/js/options.js +++ b/ext/bg/js/options.js @@ -429,7 +429,7 @@ function optionsUpdateVersion(options, defaultProfileOptions) { function optionsLoad() { return new Promise((resolve, reject) => { - chrome.storage.local.get(['options'], store => { + chrome.storage.local.get(['options'], (store) => { const error = chrome.runtime.lastError; if (error) { reject(new Error(error)); @@ -437,7 +437,7 @@ function optionsLoad() { resolve(store.options); } }); - }).then(optionsStr => { + }).then((optionsStr) => { if (typeof optionsStr === 'string') { const options = JSON.parse(optionsStr); if (isObject(options)) { @@ -447,7 +447,7 @@ function optionsLoad() { return {}; }).catch(() => { return {}; - }).then(options => { + }).then((options) => { return ( Array.isArray(options.profiles) ? optionsUpdateVersion(options, {}) : diff --git a/ext/bg/js/profile-conditions.js b/ext/bg/js/profile-conditions.js index 8272e5dd..ebc6680a 100644 --- a/ext/bg/js/profile-conditions.js +++ b/ext/bg/js/profile-conditions.js @@ -86,7 +86,7 @@ const profileConditionsDescriptor = { placeholder: 'Comma separated list of domains', defaultValue: 'example.com', transformCache: {}, - transform: (optionValue) => optionValue.split(/[,;\s]+/).map(v => v.trim().toLowerCase()).filter(v => v.length > 0), + transform: (optionValue) => optionValue.split(/[,;\s]+/).map((v) => v.trim().toLowerCase()).filter((v) => v.length > 0), transformReverse: (transformedOptionValue) => transformedOptionValue.join(', '), validateTransformed: (transformedOptionValue) => (transformedOptionValue.length > 0), test: ({url}, transformedOptionValue) => _profileConditionTestDomainList(url, transformedOptionValue) diff --git a/ext/bg/js/request.js b/ext/bg/js/request.js index 3afc1506..7d73d49b 100644 --- a/ext/bg/js/request.js +++ b/ext/bg/js/request.js @@ -29,7 +29,7 @@ function requestJson(url, action, params) { } else { xhr.send(); } - }).then(responseText => { + }).then((responseText) => { try { return JSON.parse(responseText); } diff --git a/ext/bg/js/search-query-parser.js b/ext/bg/js/search-query-parser.js index 74ef32d8..c7222212 100644 --- a/ext/bg/js/search-query-parser.js +++ b/ext/bg/js/search-query-parser.js @@ -107,7 +107,7 @@ class QueryParser { } getParseResult() { - return this.parseResults.find(r => r.id === this.selectedParser); + return this.parseResults.find((r) => r.id === this.selectedParser); } async setText(text) { @@ -216,7 +216,7 @@ class QueryParser { static processParseResultForDisplay(result) { return result.map((term) => { - return term.filter(part => part.text.trim()).map((part) => { + return term.filter((part) => part.text.trim()).map((part) => { return { text: Array.from(part.text), reading: part.reading, diff --git a/ext/bg/js/settings-dictionaries.js b/ext/bg/js/settings-dictionaries.js index 177379b0..065a8abc 100644 --- a/ext/bg/js/settings-dictionaries.js +++ b/ext/bg/js/settings-dictionaries.js @@ -62,8 +62,8 @@ class SettingsDictionaryListUI { this.updateDictionaryOrder(); - const titles = this.dictionaryEntries.map(e => e.dictionaryInfo.title); - const removeKeys = Object.keys(this.optionsDictionaries).filter(key => titles.indexOf(key) < 0); + const titles = this.dictionaryEntries.map((e) => e.dictionaryInfo.title); + const removeKeys = Object.keys(this.optionsDictionaries).filter((key) => titles.indexOf(key) < 0); if (removeKeys.length > 0) { for (const key of toIterable(removeKeys)) { delete this.optionsDictionaries[key]; @@ -161,7 +161,7 @@ class SettingsDictionaryListUI { delete n.dataset.dict; $(n).modal('hide'); - const index = this.dictionaryEntries.findIndex(e => e.dictionaryInfo.title === title); + const index = this.dictionaryEntries.findIndex((e) => e.dictionaryInfo.title === title); if (index >= 0) { this.dictionaryEntries[index].deleteDictionary(); } @@ -377,7 +377,7 @@ async function onDatabaseUpdated(options) { updateMainDictionarySelect(options, dictionaries); - const {counts, total} = await utilDatabaseGetDictionaryCounts(dictionaries.map(v => v.title), true); + const {counts, total} = await utilDatabaseGetDictionaryCounts(dictionaries.map((v) => v.title), true); dictionaryUI.setCounts(counts, total); } catch (e) { dictionaryErrorsShow([e]); @@ -564,7 +564,7 @@ async function onDictionaryImport(e) { dictionaryErrorsShow(null); dictionarySpinnerShow(true); - const setProgress = percent => dictProgress.find('.progress-bar').css('width', `${percent}%`); + const setProgress = (percent) => dictProgress.find('.progress-bar').css('width', `${percent}%`); const updateProgress = (total, current) => { setProgress(current / total * 100.0); if (storageEstimate.mostRecent !== null && !storageUpdateStats.isUpdating) { diff --git a/ext/bg/js/settings-profiles.js b/ext/bg/js/settings-profiles.js index 9532e3eb..8c218e97 100644 --- a/ext/bg/js/settings-profiles.js +++ b/ext/bg/js/settings-profiles.js @@ -147,7 +147,7 @@ function profileOptionsCreateCopyName(name, profiles, maxUniqueAttempts) { let i = 0; while (true) { const newName = `${prefix}${space}${index}${suffix}`; - if (i++ >= maxUniqueAttempts || profiles.findIndex(profile => profile.name === newName) < 0) { + if (i++ >= maxUniqueAttempts || profiles.findIndex((profile) => profile.name === newName) < 0) { return newName; } if (typeof index !== 'number') { diff --git a/ext/bg/js/settings.js b/ext/bg/js/settings.js index 48026794..abe6f389 100644 --- a/ext/bg/js/settings.js +++ b/ext/bg/js/settings.js @@ -18,7 +18,7 @@ async function getOptionsArray() { const optionsFull = await apiOptionsGetFull(); - return optionsFull.profiles.map(profile => profile.options); + return optionsFull.profiles.map((profile) => profile.options); } async function formRead(options) { @@ -484,12 +484,12 @@ async function ankiDeckAndModelPopulate(options) { const deckNames = await utilAnkiGetDeckNames(); const ankiDeck = $('.anki-deck'); ankiDeck.find('option').remove(); - deckNames.sort().forEach(name => ankiDeck.append($('