From 96c6c4ad1ae8dd784ba4d90546ae3bf7ce1861f6 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Sat, 20 Aug 2016 22:03:16 -0700 Subject: [PATCH 01/51] Adding dexie --- ext/bg/background.html | 1 + ext/lib/dexie.min.js | 3 +++ 2 files changed, 4 insertions(+) create mode 100644 ext/lib/dexie.min.js diff --git a/ext/bg/background.html b/ext/bg/background.html index c35e917d..e68c665b 100644 --- a/ext/bg/background.html +++ b/ext/bg/background.html @@ -2,6 +2,7 @@ + diff --git a/ext/lib/dexie.min.js b/ext/lib/dexie.min.js new file mode 100644 index 00000000..8b87e378 --- /dev/null +++ b/ext/lib/dexie.min.js @@ -0,0 +1,3 @@ +!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){In=n,An=t}function t(){if(En)try{throw t.arguments,new Error}catch(n){return n}return new Error}function e(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(An).map(function(n){return"\n"+n}).join("")):""}function r(){}function i(n){return n}function o(n,t){return null==n||n===i?t:function(e){return t(n(e))}}function u(n,t){return function(){n.apply(this,arguments),t.apply(this,arguments)}}function a(n,t){return n===r?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?u(r,this.onsuccess):r),i&&(this.onerror=this.onerror?u(i,this.onerror):i),void 0!==o?o:e}}function c(n,t){return n===r?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?u(e,this.onsuccess):e),r&&(this.onerror=this.onerror?u(r,this.onerror):r)}}function s(n,t){return n===r?t:function(e){var r=n.apply(this,arguments);h(e,r);var i=this.onsuccess,o=this.onerror;this.onsuccess=null,this.onerror=null;var a=t.apply(this,arguments);return i&&(this.onsuccess=this.onsuccess?u(i,this.onsuccess):i),o&&(this.onerror=this.onerror?u(o,this.onerror):o),void 0===r?void 0===a?void 0:a:h(r,a)}}function f(n,t){return n===r?t:function(){return t.apply(this,arguments)===!1?!1:n.apply(this,arguments)}}function l(n,t){return n===r?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 h(n,t){return"object"!=typeof t?n:(Cn(t).forEach(function(e){n[e]=t[e]}),n)}function d(n,t){return Dn.call(n,t)}function p(n,t){"function"==typeof t&&(t=t(Pn(n))),Cn(t).forEach(function(e){v(n,e,t[e])})}function v(n,t,e,r){Object.defineProperty(n,t,h(e&&d(e,"get")&&"function"==typeof e.get?{get:e.get,set:e.set,configurable:!0}:{value:e,configurable:!0,writable:!0},r))}function y(n){return{from:function(t){return n.prototype=Object.create(t.prototype),v(n.prototype,"constructor",n),{extend:p.bind(null,n.prototype)}}}}function m(n,t){var e,r=Sn(n,t);return r||(e=Pn(n))&&m(e,t)}function g(n,t,e){return Tn.call(n,t,e)}function b(n,t){return t(n)}function _(n){var t=setTimeout(n,1e3);clearTimeout(t)}function w(n){if(!n)throw new Ln.Internal("Assertion failed")}function k(n){jn.setImmediate?setImmediate(n):setTimeout(n,0)}function x(n,t){return n.reduce(function(n,e,r){var i=t(e,r);return i&&(n[i[0]]=i[1]),n},{})}function I(n,t){return function(){try{n.apply(this,arguments)}catch(e){t(e)}}}function A(n,t,e){try{n.apply(null,e)}catch(r){t&&t(r)}}function E(n,t){var e=U.reject(n);return t?e.uncaught(t):e}function C(n,t){if(d(n,t))return n[t];if(!t)return n;if("string"!=typeof t){for(var e=[],r=0,i=t.length;i>r;++r){var o=C(n,t[r]);e.push(o)}return e}var u=t.indexOf(".");if(-1!==u){var a=n[t.substr(0,u)];return void 0===a?void 0:C(a,t.substr(u+1))}}function O(n,t,e){if(n&&void 0!==t&&!("isFrozen"in Object&&Object.isFrozen(n)))if("string"!=typeof t&&"length"in t){w("string"!=typeof e&&"length"in e);for(var r=0,i=t.length;i>r;++r)O(n,t[r],e[r])}else{var o=t.indexOf(".");if(-1!==o){var u=t.substr(0,o),a=t.substr(o+1);if(""===a)void 0===e?delete n[u]:n[u]=e;else{var c=n[u];c||(c=n[u]={}),O(c,a,e)}}else void 0===e?delete n[t]:n[t]=e}}function j(n,t){"string"==typeof t?O(n,t,void 0):"length"in t&&[].map.call(t,function(t){O(n,t,void 0)})}function P(n){var t={};for(var e in n)d(n,e)&&(t[e]=n[e]);return t}function D(n){if(!n||"object"!=typeof n)return n;var t;if(On(n)){t=[];for(var e=0,r=n.length;r>e;++e)t.push(D(n[e]))}else if(n instanceof Date)t=new Date,t.setTime(n.getTime());else{t=n.constructor?Object.create(n.constructor.prototype):{};for(var i in n)d(n,i)&&(t[i]=D(n[i]))}return t}function S(n,t,e,r){return e=e||{},r=r||"",Cn(n).forEach(function(i){if(d(t,i)){var o=n[i],u=t[i];"object"==typeof o&&"object"==typeof u&&o&&u&&o.constructor===u.constructor?S(o,u,e,r+i+"."):o!==u&&(e[r+i]=t[i])}else e[r+i]=void 0}),Cn(t).forEach(function(i){d(n,i)||(e[r+i]=t[i])}),e}function T(n){var t,e,r,i;if(1===arguments.length){if(On(n))return n.slice();if(this===Mn&&"string"==typeof n)return[n];if(i=Bn(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){return Nn.apply([],n)}function B(n,e){this._e=t(),this.name=n,this.message=e}function M(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 N(n,e,r,i){this._e=t(),this.failures=e,this.failedKeys=i,this.successCount=r}function q(n,e){this._e=t(),this.name="BulkError",this.failures=e,this.message=M(n,e)}function F(n,t){if(!n||n instanceof B||n instanceof TypeError||n instanceof SyntaxError||!n.name||!Wn[n.name])return n;var e=new Wn[n.name](t||n.message,n);return"stack"in n&&v(e,"stack",{get:function(){return this.inner.stack}}),e}function R(n){function t(n,t,i){if("object"==typeof n)return e(n);t||(t=f),i||(i=r);var a={subscribers:[],fire:i,subscribe:function(n){-1===a.subscribers.indexOf(n)&&(a.subscribers.push(n),a.fire=t(a.fire,n))},unsubscribe:function(n){a.subscribers=a.subscribers.filter(function(t){return t!==n}),a.fire=a.subscribers.reduce(t,i)}};return o[n]=u[n]=a,a}function e(n){Cn(n).forEach(function(e){var r=n[e];if(On(r))t(e,n[e][0],n[e][1]);else{if("asap"!==r)throw new Ln.InvalidArgument("Invalid event config");var o=t(e,i,function(){for(var n=arguments.length,t=new Array(n);n--;)t[n]=arguments[n];o.subscribers.forEach(function(n){k(function(){n.apply(null,t)})})})}})}var o={},u=function(t,e){if(e){for(var r=arguments.length,i=new Array(r-1);--r;)i[r-1]=arguments[r];return o[t].subscribe.apply(null,i),n}return"string"==typeof t?o[t]:void 0};u.addEventType=t;for(var a=1,c=arguments.length;c>a;++a)t(arguments[a]);return u}function U(n){if("object"!=typeof this)throw new TypeError("Promises must be constructed via new");this._listeners=[],this.onuncatched=r,this._lib=!1;var e=this._PSD=ut;if(In&&(this._stackHolder=t(),this._prev=null,this._numPrev=0,Q(this,rt)),"function"!=typeof n){if(n!==Gn)throw new TypeError("Not a function");return this._state=arguments[1],this._value=arguments[2],void(this._state===!1&&L(this,this._value))}this._state=null,this._value=null,++e.ref,V(this,n)}function z(n,t,e,r){this.onFulfilled="function"==typeof n?n:null,this.onRejected="function"==typeof t?t:null,this.resolve=e,this.reject=r,this.psd=ut}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&&$();t&&"function"==typeof t.then?V(n,function(n,e){t instanceof U?t._then(n,e):t.then(n,e)}):(n._state=!0,n._value=t,W(n)),e&&X()}},L.bind(null,n))}catch(e){L(n,e)}}function L(n,t){if(et.push(t),null===n._state){var e=n._lib&&$();t=it(t),n._state=!1,n._value=t,In&&null!==t&&"object"==typeof t&&!t._promise&&A(function(){var e=m(t,"stack");t._promise=n,v(t,"stack",{get:function(){return Yn?e&&(e.get?e.get.apply(t):e.value):n.stack}})}),tn(n),W(n),e&&X()}}function W(n){var t=n._listeners;n._listeners=[];for(var e=0,r=t.length;r>e;++e)H(n,t[e]);var i=n._PSD;--i.ref||i.finalize(),0===ct&&(++ct,Xn(function(){0===--ct&&Z()},[]))}function H(n,t){if(null===n._state)return void n._listeners.push(t);var e=n._state?t.onFulfilled:t.onRejected;if(null===e)return(n._state?t.resolve:t.reject)(n._value);var r=t.psd;++r.ref,++ct,Xn(G,[e,n,t])}function G(n,t,e){var r=ut,i=e.psd;try{i!==r&&(ut=i),rt=t;var o,u=t._value;t._state?o=n(u):(et.length&&(et=[]),o=n(u),-1===et.indexOf(u)&&en(t)),e.resolve(o)}catch(a){e.reject(a)}finally{i!==r&&(ut=r),rt=null,0===--ct&&Z(),--i.ref||i.finalize()}}function J(n,t,r){if(t.length===r)return t;var i="";if(n._state===!1){var o,u,a=n._value;null!=a?(o=a.name||"Error",u=a.message||a,i=e(a,0)):(o=a,u=""),t.push(o+(u?": "+u:"")+i)}return In&&(i=e(n._stackHolder,2),i&&-1===t.indexOf(i)&&t.push(i),n._prev&&J(n._prev,t,r)),t}function Q(n,t){var e=t?t._numPrev+1:0;Jn>e&&(n._prev=t,n._numPrev=e)}function Y(){$()&&X()}function $(){var n=Zn;return Zn=!1,nt=!1,n}function X(){var n,t,e;do for(;at.length>0;)for(n=at,at=[],e=n.length,t=0;e>t;++t){var r=n[t];r[0].apply(null,r[1])}while(at.length>0);Zn=!0,nt=!0}function Z(){var n=tt;tt=[],n.forEach(function(n){n._PSD.onunhandled.call(null,n._value,n)});for(var t=st.slice(0),e=t.length;e;)t[--e]()}function nn(n){function t(){n(),st.splice(st.indexOf(t),1)}st.push(t),++ct,Xn(function(){0===--ct&&Z()},[])}function tn(n){tt.some(function(t){return t._value===n._value})||tt.push(n)}function en(n){for(var t=tt.length;t;)if(tt[--t]._value===n._value)return void tt.splice(t,1)}function rn(n){console.warn("Unhandled rejection: "+(n.stack||n))}function on(n){return new U(Gn,!1,n)}function un(n,t){var e=ut;return function(){var r=$(),i=ut;try{return i!==e&&(ut=e),n.apply(this,arguments)}catch(o){t&&t(o)}finally{i!==e&&(ut=i),r&&X()}}}function an(n,t,e,r){var i=ut,o=Object.create(i);o.parent=i,o.ref=0,o.global=!1,++i.ref,o.finalize=function(){--this.parent.ref||this.parent.finalize()};var u=cn(o,n,t,e,r);return 0===o.ref&&o.finalize(),u}function cn(n,t,e,r,i){var o=ut;try{return n!==o&&(ut=n),t(e,r,i)}finally{n!==o&&(ut=o)}}function sn(n,t){var e;try{e=t.onuncatched(n)}catch(r){}if(e!==!1)try{U.on.error.fire(n,t)}catch(r){}}function fn(n,e){function u(){et.on("versionchange",function(n){n.newVersion>0?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=Hn,i=n._cfg.dbschema;Tn(r,e),Tn(i,e),Hn=et._dbSchema=i;var o=j(r,i);return o.add.forEach(function(n){B(e,n[0],n[1].primKey,n[1].indexes)}),o.change.forEach(function(n){if(n.recreate)throw new Ln.Upgrade("Not yet support for changing primary key");var t=e.objectStore(n.name);n.add.forEach(function(n){z(t,n)}),n.change.forEach(function(n){t.deleteIndex(n.name),z(t,n)}),n.del.forEach(function(n){t.deleteIndex(n)})}),n._cfg.contentUpgrade?(u=!0,U.follow(function(){n._cfg.contentUpgrade(t)})):void 0}),i.push(function(t){if(u&&!mt){var e=n._cfg.dbschema;F(e,t)}})}),r().then(function(){M(Hn,e)})}function j(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 B(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){z(i,n)}),i}function M(n,t){Cn(n).forEach(function(e){t.db.objectStoreNames.contains(e)||B(t,e,n[e].primKey,n[e].indexes)})}function F(n,t){for(var e=0;er;++r){s={onsuccess:null,onerror:null};var u=e[r];i.call(s,u[0],u[1],t);var h=n["delete"](u[0]);h._hookCtx=s,h.onerror=f,r===c?h.onsuccess=pn(o):h.onsuccess=l}},function(n){throw s.onerror&&s.onerror(n),n})}else for(var h=0;a>h;++h){var d=n["delete"](e[h]);d.onerror=un(vn(u)),h===c&&(d.onsuccess=un(function(){return o()}))}}).uncaught(V)}function Q(n,t,e,r){var i=this;this.db=et,this.mode=n,this.storeNames=t,this.idbtrans=null,this.on=R(this,"complete","error","abort"),this.parent=r||null,this.active=!0,this._tables=null,this._reculock=0,this._blockedFuncs=[],this._psd=null,this._dbschema=e,this._resolve=null,this._reject=null,this._completion=new U(function(n,t){i._resolve=n,i._reject=t}).uncaught(V),this._completion.then(function(){i.on.complete.fire()},function(n){return i.on.error.fire(n),i.parent?i.parent._reject(n):i.active&&i.idbtrans&&i.idbtrans.abort(),i.active=!1,E(n)})}function Y(n,t,e){this._ctx={table:n,index:":id"===t?null:t,collClass:n._collClass,or:e}}function $(n,t){var e=null,r=null;if(t)try{e=t()}catch(i){r=i}var o=n._ctx,u=o.table;this._ctx={table:u,index:o.index,isPrimKey:!o.index||u.schema.primKey.keyPath&&o.index===u.schema.primKey.name,range:e,keysOnly:!1,dir:"next",unique:"",algorithm:null,filter:null,replayFilter:null,justLimit:!0,isMatch:null,offset:0,limit:1/0,error:r,or:o.or,valueMapper:u.hook.reading.fire}}function X(n,t){return!(n.filter||n.algorithm||n.or)&&(t?n.justLimit:!n.replayFilter)}function Z(){$.apply(this,arguments)}function nn(n,t){return n._cfg.version-t._cfg.version}function tn(n,t,e,r){t.forEach(function(t){var i=et._tableFactory(e,r[t]);n.forEach(function(n){t in n||(n[t]=i)})})}function en(n){n.forEach(function(n){for(var t in n)n[t]instanceof W&&delete n[t]})}function rn(n,t,e,r,i,o){var u=o?function(n,t,r){return e(o(n),t,r)}:e,a=un(u,i);n.onerror||(n.onerror=vn(i)),t?n.onsuccess=I(function(){var e=n.result;if(e){var o=function(){e["continue"]()};t(e,function(n){o=n},r,i)&&a(e.value,e,function(n){o=n}),o()}else r()},i):n.onsuccess=I(function(){var t=n.result;if(t){var e=function(){t["continue"]()};a(t.value,t,function(n){e=n}),e()}else r()},i)}function on(n){var t=[];return n.split(",").forEach(function(n){n=n.trim();var e=n.replace(/([&*]|\+\+)/g,""),r=/^\[/.test(e)?e.match(/^\[(.*)\]$/)[1].split("+"):e;t.push(new _n(e,r||null,/\&/.test(n),/\*/.test(n),/\+\+/.test(n),On(r),/\./.test(n)))}),t}function cn(n,t){return Vn.cmp(n,t)}function sn(n,t){return cn(n,t)<0?n:t}function ln(n,t){return cn(n,t)>0?n:t}function An(n,t){return Vn.cmp(n,t)}function En(n,t){return Vn.cmp(t,n)}function jn(n,t){return t>n?-1:n===t?0:1}function Pn(n,t){return n>t?-1:n===t?0:1}function Dn(n,t){return n?t?function(){return n.apply(this,arguments)&&t.apply(this,arguments)}:n:t}function Sn(){if(et.verno=Yn.version/10,et._dbSchema=Hn={},Jn=g(Yn.objectStoreNames,0),0!==Jn.length){var n=Yn.transaction(kn(Jn),"readonly");Jn.forEach(function(t){for(var e=n.objectStore(t),r=e.keyPath,i=r&&"string"==typeof r&&-1!==r.indexOf("."),o=new _n(r,r||"",!1,!1,!!e.autoIncrement,r&&"string"!=typeof r,i),u=[],a=0;a0&&(ot=!1),!Vn)throw new Ln.MissingAPI("indexedDB API not found. If using IE10+, make sure to run your code on a server URL (not locally). If using old Safari versions, make sure to include indexedDB polyfill.");var i=ot?Vn.open(n):Vn.open(n,Math.round(10*et.verno));if(!i)throw new Ln.MissingAPI("IndexedDB API not available");i.onerror=un(vn(e)),i.onblocked=un(Kn),i.onupgradeneeded=un(function(t){if(r=i.transaction,ot&&!et._allowEmptyDB){i.onerror=mn,r.abort(),i.result.close();var o=Vn.deleteDatabase(n);o.onsuccess=o.onerror=un(function(){e(new Ln.NoSuchDatabase("Database "+n+" doesnt exist"))})}else{r.onerror=un(vn(e));var u=t.oldVersion>Math.pow(2,62)?0:t.oldVersion;m(u/10,r,e,i)}},e),i.onsuccess=un(function(){if(r=null,Yn=i.result,vt.push(et),ot)Sn();else if(Yn.objectStoreNames.length>0)try{Tn(Hn,Yn.transaction(kn(Yn.objectStoreNames),nt))}catch(e){}Yn.onversionchange=un(function(n){et._vcFired=!0,et.on("versionchange").fire(n)}),at||gn(function(t){return-1===t.indexOf(n)?t.push(n):void 0}),t()},e)})]).then(function(){return fn.vip(et.on.ready.fire)}).then(function(){return Xn=!1,et})["catch"](function(n){try{r&&r.abort()}catch(t){}return Xn=!1,et.close(),$n=n,E($n,V)})["finally"](function(){Zn=!0,e()})},this.close=function(){var n=vt.indexOf(et);if(n>=0&&vt.splice(n,1),Yn){try{Yn.close()}catch(t){}Yn=null}zn=!1,$n=new Ln.DatabaseClosed,Xn&&Nn($n),rt=new U(function(n){Bn=n}),it=new U(function(n,t){Nn=t})},this["delete"]=function(){var t=arguments.length>0;return new U(function(e,r){function i(){et.close();var t=Vn.deleteDatabase(n);t.onsuccess=un(function(){at||gn(function(t){var e=t.indexOf(n);return e>=0?t.splice(e,1):void 0}),e()}),t.onerror=un(vn(r)),t.onblocked=Kn}if(t)throw new Ln.InvalidArgument("Arguments not allowed in db.delete()");Xn?rt.then(i):i()}).uncaught(V)},this.backendDB=function(){return Yn},this.isOpen=function(){return null!==Yn},this.hasFailed=function(){return null!==$n},this.dynamicallyOpened=function(){return ot},this.name=n,v(this,"tables",{get:function(){return Cn(Qn).map(function(n){return Qn[n]})}}),this.on=R(this,"error","populate","blocked","versionchange",{ready:[l,r]}),this.on.ready.subscribe=b(this.on.ready.subscribe,function(n){return function(t,e){fn.vip(function(){n(t),e||n(function r(){et.on.ready.unsubscribe(t),et.on.ready.unsubscribe(r)})})}}),_t(function(){et.on("populate").fire(et._createTransaction(tt,Jn,Hn)),et.on("error").fire(new Error)}),this.transaction=function(n,t,e){function r(t){var r=ut;t(U.resolve().then(function(){return an(function(){ut.transless=ut.transless||r;var t=et._createTransaction(n,s,Hn,a);ut.trans=t,a?t.idbtrans=a.idbtrans:t.create();var i=s.map(function(n){return t.tables[n]});i.push(t);var o;return U.follow(function(){if(o=e.apply(t,i))if("function"==typeof o.next&&"function"==typeof o["throw"])o=bn(o);else if("function"==typeof o.then&&!d(o,"_PSD"))throw new Ln.IncompatiblePromise("Incompatible Promise returned from transaction scope (read more at http://tinyurl.com/znyqjqc). Transaction scope: "+e.toString())}).uncaught(V).then(function(){return a&&t._resolve(),t._completion}).then(function(){return o})["catch"](function(n){return t._reject(n),E(n)})})}))}var i=arguments.length;if(2>i)throw new Ln.InvalidArgument("Too few arguments");for(var o=new Array(i-1);--i;)o[i-1]=arguments[i];e=o.pop();var u=K(o),a=ut.trans;a&&a.db===et&&-1===n.indexOf("!")||(a=null);var c=-1!==n.indexOf("?");n=n.replace("!","").replace("?","");try{var s=u.map(function(n){var t=n instanceof W?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==nt)n=nt;else{if("rw"!=n&&n!=tt)throw new Ln.InvalidArgument("Invalid transaction mode: "+n);n=tt}if(a){if(a.mode===nt&&n===tt){if(!c)throw new Ln.SubTransaction("Cannot enter a sub-transaction with READWRITE mode when parent transaction is READONLY");a=null}a&&s.forEach(function(n){if(!d(a.tables,n)){if(!c)throw new Ln.SubTransaction("Table "+n+" not included in parent transaction.");a=null}})}}catch(f){return a?a._promise(null,function(n,t){t(f)}):E(f,V)}return a?a._promise(n,r,"lock"):et._whenReady(r)},this.table=function(n){if(wt&&ot)return new H(n);if(!d(Qn,n))throw new Ln.InvalidTable("Table "+n+" does not exist");return Qn[n]},p(W.prototype,{_trans:function(n,t,e){var r=ut.trans;return r&&r.db===et?r._promise(n,t,e):L(n,[this.name],t)},_idbstore:function(n,t,e){function r(n,e,r){t(n,e,r.idbtrans.objectStore(o),r)}if(wt)return new U(t);var i=ut.trans,o=this.name;return i&&i.db===et?i._promise(n,r,e):L(n,[this.name],r)},get:function(n,t){var e=this;return this._idbstore(nt,function(t,r,i){wt&&t(e.schema.instanceTemplate);var o=i.get(n);o.onerror=vn(r),o.onsuccess=function(){t(e.hook.reading.fire(o.result))}}).then(t)},where:function(n){return new Y(this,n)},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 this._collClass(new Y(this,n))},toCollection:function(){return new this._collClass(new Y(this))},mapToClass:function(n,t){this.schema.mappedClass=n;var e=Object.create(n.prototype);t&&hn(e,t),this.schema.instanceTemplate=e;var r=function(t){if(!t)return t;var e=Object.create(n.prototype);for(var r in t)d(t,r)&&(e[r]=t[r]);return e};return this.schema.readHook&&this.hook.reading.unsubscribe(this.schema.readHook),this.schema.readHook=r,this.hook("reading",r),n},defineClass:function(n){return this.mapToClass(fn.defineClass(n),n)}}),y(H).from(W).extend({bulkDelete:function(n){return this.hook.deleting.fire===r?this._idbstore(tt,function(t,e,i,o){t(J(i,o,n,!1,r))}):this.where(":id").anyOf(n)["delete"]().then(function(){})},bulkPut:function(n,t){var e=this;return this._idbstore(tt,function(i,o,u){if(!u.keyPath&&!e.schema.primKey.auto&&!t)throw new Ln.InvalidArgument("bulkPut() with non-inbound keys requires keys array in second argument");if(u.keyPath&&t)throw new Ln.InvalidArgument("bulkPut(): keys argument invalid on tables with inbound keys");if(t&&t.length!==n.length)throw new Ln.InvalidArgument("Arguments objects and keys must have the same length");if(0===n.length)return i();var a,c,s=function(n){0===f.length?i(n):o(new q(e.name+".bulkPut(): "+f.length+" of "+l+" operations failed",f))},f=[],l=n.length,h=e;if(e.hook.creating.fire===r&&e.hook.updating.fire===r){c=G(f);for(var d=0,p=n.length;p>d;++d)a=t?u.put(n[d],t[d]):u.put(n[d]),a.onerror=c;a.onerror=G(f,s),a.onsuccess=dn(s)}else{var v=t||u.keyPath&&n.map(function(n){return C(n,u.keyPath)}),y=v&&x(v,function(t,e){return null!=t&&[t,n[e]]}),m=v?h.where(":id").anyOf(v.filter(function(n){return null!=n})).modify(function(){this.value=y[this.primKey],y[this.primKey]=null})["catch"](N,function(n){f=n.failures}).then(function(){for(var e=[],r=t&&[],i=v.length-1;i>=0;--i){var o=v[i];(null==o||y[o])&&(e.push(n[i]),t&&r.push(o),null!=o&&(y[o]=null))}return e.reverse(),t&&r.reverse(),h.bulkAdd(e,r)}).then(function(n){var t=v[v.length-1];return null!=t?t:n}):h.bulkAdd(n);m.then(s)["catch"](q,function(n){f=f.concat(n.failures),s()})["catch"](o)}},"locked")},bulkAdd:function(n,t){var e=this,i=this.hook.creating.fire;return this._idbstore(tt,function(o,u,a,c){function s(n){0===d.length?o(n):u(new q(e.name+".bulkAdd(): "+d.length+" of "+p+" operations failed",d))}if(!a.keyPath&&!e.schema.primKey.auto&&!t)throw new Ln.InvalidArgument("bulkAdd() with non-inbound keys requires keys array in second argument");if(a.keyPath&&t)throw new Ln.InvalidArgument("bulkAdd(): keys argument invalid on tables with inbound keys");if(t&&t.length!==n.length)throw new Ln.InvalidArgument("Arguments objects and keys must have the same length");if(0===n.length)return o();var f,l,h,d=[],p=n.length;if(i!==r){var v,y=a.keyPath;l=G(d,null,!0),h=pn(null),A(function(){for(var e=0,r=n.length;r>e;++e){v={onerror:null,onsuccess:null};var o=t&&t[e],u=n[e],s=t?o:y?C(u,y):void 0,d=i.call(v,s,u,c);null==s&&null!=d&&(y?(u=D(u),O(u,y,d)):o=d),f=null!=o?a.add(u,o):a.add(u),f._hookCtx=v,r-1>e&&(f.onerror=l,v.onsuccess&&(f.onsuccess=h))}},function(n){throw v.onerror&&v.onerror(n),n}),f.onerror=G(d,s,!0),f.onsuccess=pn(s)}else{l=G(d);for(var m=0,g=n.length;g>m;++m)f=t?a.add(n[m],t[m]):a.add(n[m]),f.onerror=l;f.onerror=G(d,s),f.onsuccess=dn(s)}})},add:function(n,t){var e=this.hook.creating.fire;return this._idbstore(tt,function(i,o,u,a){var c={onsuccess:null,onerror:null};if(e!==r){var s=null!=t?t:u.keyPath?C(n,u.keyPath):void 0,f=e.call(c,s,n,a);null==s&&null!=f&&(u.keyPath?O(n,u.keyPath,f):t=f)}try{var l=null!=t?u.add(n,t):u.add(n);l._hookCtx=c,l.onerror=yn(o),l.onsuccess=pn(function(t){var e=u.keyPath;e&&O(n,e,t),i(t)})}catch(h){throw c.onerror&&c.onerror(h),h}})},put:function(n,t){var e=this,i=this.hook.creating.fire,o=this.hook.updating.fire;return i!==r||o!==r?this._trans(tt,function(r,i,o){var u=void 0!==t?t:e.schema.primKey.keyPath&&C(n,e.schema.primKey.keyPath);null==u?o.tables[e.name].add(n).then(r,i):(o._lock(),n=D(n),o.tables[e.name].where(":id").equals(u).modify(function(){this.value=n}).then(function(r){return 0===r?o.tables[e.name].add(n,t):u})["finally"](function(){o._unlock()}).then(r,i))}):this._idbstore(tt,function(e,r,i){var o=void 0!==t?i.put(n,t):i.put(n);o.onerror=vn(r),o.onsuccess=function(t){var r=i.keyPath;r&&O(n,r,t.target.result),e(o.result)}})},"delete":function(n){return this.hook.deleting.subscribers.length?this.where(":id").equals(n)["delete"]():this._idbstore(tt,function(t,e,r){var i=r["delete"](n);i.onerror=vn(e),i.onsuccess=function(){t(i.result)}})},clear:function(){return this.hook.deleting.subscribers.length?this.toCollection()["delete"]():this._idbstore(tt,function(n,t,e){var r=e.clear();r.onerror=vn(t),r.onsuccess=function(){n(r.result)}})},update:function(n,t){if("object"!=typeof t||On(t))throw new Ln.InvalidArgument("Modifications must be an object.");if("object"!=typeof n||On(n))return this.where(":id").equals(n).modify(t);Cn(t).forEach(function(e){O(n,e,t[e])});var e=C(n,this.schema.primKey.keyPath);return void 0===e?E(new Ln.InvalidArgument("Given object does not contain its primary key"),V):this.where(":id").equals(e).modify(t)}}),p(Q.prototype,{_lock:function(){return w(!ut.global),++this._reculock,1!==this._reculock||ut.global||(ut.lockOwnerFor=this),this},_unlock:function(){if(w(!ut.global),0===--this._reculock)for(ut.global||(ut.lockOwnerFor=null);this._blockedFuncs.length>0&&!this._locked();){var n=this._blockedFuncs.shift();try{n()}catch(t){}}return this},_locked:function(){return this._reculock&&ut.lockOwnerFor!==this},create:function(n){var t=this;if(w(!this.idbtrans),!n&&!Yn)switch($n&&$n.name){case"DatabaseClosedError":throw new Ln.DatabaseClosed($n);case"MissingAPIError":throw new Ln.MissingAPI($n.message,$n);default:throw new Ln.OpenFailed($n)}if(!this.active)throw new Ln.TransactionInactive;return w(null===this._completion._state),n=this.idbtrans=n||Yn.transaction(kn(this.storeNames),this.mode),n.onerror=un(function(e){mn(e),t._reject(n.error)}),n.onabort=un(function(n){mn(n),t.active&&t._reject(new Ln.Abort),t.active=!1,t.on("abort").fire(n)}),n.oncomplete=un(function(){t.active=!1,t._resolve()}),this},_promise:function(n,t,e){var r=this;return an(function(){var i;return r._locked()?i=new U(function(i,o){r._blockedFuncs.push(function(){r._promise(n,t,e).then(i,o)})}):(i=r.active?new U(function(i,o){if(n===tt&&r.mode!==tt)throw new Ln.ReadOnly("Transaction is readonly");!r.idbtrans&&n&&r.create(),e&&r._lock(),t(i,o,r)}):E(new Ln.TransactionInactive),r.active&&e&&i["finally"](function(){r._unlock()})),i._lib=!0,i.uncaught(V)})},abort:function(){this.active&&this._reject(new Ln.Abort),this.active=!1},tables:{get:function(){return this._tables?this._tables:this._tables=x(this.storeNames,function(n){return[n,Qn[n]]})}},complete:function(n){return this.on("complete",n)},error:function(n){return this.on("error",n)},table:function(n){if(-1===this.storeNames.indexOf(n))throw new Ln.InvalidTable("Table "+n+" not in transaction");return Qn[n]}}),p(Y.prototype,function(){function n(n,t,e){var r=n instanceof Y?new n._ctx.collClass(n):n;return r._ctx.error=e?new e(t):new TypeError(t), +r}function t(n){return new n._ctx.collClass(n,function(){return Wn.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;u>c;++c){var s=t[c];if(s!==r[c])return i(n[c],e[c])<0?n.substr(0,c)+e[c]+e.substr(c+1):i(n[c],r[c])<0?n.substr(0,c)+r[c]+e.substr(c+1):a>=0?n.substr(0,a)+t[a]+e.substr(a+1):null;i(n[c],s)<0&&(a=c)}return ua?null:n.substr(0,a)+r[a]+e.substr(a+1)}function o(t,o,u,a){function c(n){s=e(n),f=r(n),l="next"===n?jn:Pn;var t=u.map(function(n){return{lower:f(n),upper:s(n)}}).sort(function(n,t){return l(n.lower,t.lower)});h=t.map(function(n){return n.upper}),d=t.map(function(n){return n.lower}),p=n,v="next"===n?"":a}var s,f,l,h,d,p,v,y=u.length;if(!u.every(function(n){return"string"==typeof n}))return n(t,pt);c("next");var m=new t._ctx.collClass(t,function(){return Wn.bound(h[0],d[y-1]+a)});m._ondirectionchange=function(n){c(n)};var g=0;return m._addAlgorithm(function(n,t,e){var r=n.key;if("string"!=typeof r)return!1;var u=f(r);if(o(u,d,g))return!0;for(var a=null,c=g;y>c;++c){var s=i(r,u,h[c],d[c],l,p);null===s&&null===a?g=c+1:(null===a||l(a,s)>0)&&(a=s)}return t(null!==a?function(){n["continue"](a+v)}:e),!1}),m}return{between:function(e,r,i,o){i=i!==!1,o=o===!0;try{return cn(e,r)>0||0===cn(e,r)&&(i||o)&&(!i||!o)?t(this):new this._ctx.collClass(this,function(){return Wn.bound(e,r,!i,!o)})}catch(u){return n(this,dt)}},equals:function(n){return new this._ctx.collClass(this,function(){return Wn.only(n)})},above:function(n){return new this._ctx.collClass(this,function(){return Wn.lowerBound(n,!0)})},aboveOrEqual:function(n){return new this._ctx.collClass(this,function(){return Wn.lowerBound(n)})},below:function(n){return new this._ctx.collClass(this,function(){return Wn.upperBound(n,!0)})},belowOrEqual:function(n){return new this._ctx.collClass(this,function(){return Wn.upperBound(n)})},startsWith:function(t){return"string"!=typeof t?n(this,pt):this.between(t,t+lt,!0,!0)},startsWithIgnoreCase:function(n){return""===n?this.startsWith(n):o(this,function(n,t){return 0===n.indexOf(t[0])},[n],lt)},equalsIgnoreCase:function(n){return o(this,function(n,t){return n===t[0]},[n],"")},anyOfIgnoreCase:function(){var n=T.apply(Mn,arguments);return 0===n.length?t(this):o(this,function(n,t){return-1!==t.indexOf(n)},n,"")},startsWithAnyOfIgnoreCase:function(){var n=T.apply(Mn,arguments);return 0===n.length?t(this):o(this,function(n,t){return t.some(function(t){return 0===n.indexOf(t)})},n,lt)},anyOf:function(){var e=T.apply(Mn,arguments),r=An;try{e.sort(r)}catch(i){return n(this,dt)}if(0===e.length)return t(this);var o=new this._ctx.collClass(this,function(){return Wn.bound(e[0],e[e.length-1])});o._ondirectionchange=function(n){r="next"===n?An:En,e.sort(r)};var u=0;return o._addAlgorithm(function(n,t,i){for(var o=n.key;r(o,e[u])>0;)if(++u,u===e.length)return t(i),!1;return 0===r(o,e[u])?!0:(t(function(){n["continue"](e[u])}),!1)}),o},notEqual:function(n){return this.inAnyRange([[-(1/0),n],[n,ht]],{includeLowers:!1,includeUppers:!1})},noneOf:function(){var t=T.apply(Mn,arguments);if(0===t.length)return new this._ctx.collClass(this);try{t.sort(An)}catch(e){return n(this,dt)}var r=t.reduce(function(n,t){return n?n.concat([[n[n.length-1][1],t]]):[[-(1/0),t]]},null);return r.push([t[t.length-1],ht]),this.inAnyRange(r,{includeLowers:!1,includeUppers:!1})},inAnyRange:function(e,r){function i(n,t){for(var e=0,r=n.length;r>e;++e){var i=n[e];if(cn(t[0],i[1])<0&&cn(t[1],i[0])>0){i[0]=sn(i[0],t[0]),i[1]=ln(i[1],t[1]);break}}return e===r&&n.push(t),n}function o(n,t){return l(n[0],t[0])}function u(n){return!p(n)&&!v(n)}var a=this._ctx;if(0===e.length)return t(this);if(!e.every(function(n){return void 0!==n[0]&&void 0!==n[1]&&An(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",Ln.InvalidArgument);var c,s=!r||r.includeLowers!==!1,f=r&&r.includeUppers===!0,l=An;try{c=e.reduce(i,[]),c.sort(o)}catch(h){return n(this,dt)}var d=0,p=f?function(n){return An(n,c[d][1])>0}:function(n){return An(n,c[d][1])>=0},v=s?function(n){return En(n,c[d][0])>0}:function(n){return En(n,c[d][0])>=0},y=p,m=new a.collClass(this,function(){return Wn.bound(c[0][0],c[c.length-1][1],!s,!f)});return m._ondirectionchange=function(n){"next"===n?(y=p,l=An):(y=v,l=En),c.sort(o)},m._addAlgorithm(function(n,t,e){for(var r=n.key;y(r);)if(++d,d===c.length)return t(e),!1;return u(r)?!0:0===cn(r,c[d][1])||0===cn(r,c[d][0])?!1:(t(function(){l===An?n["continue"](c[d][0]):n["continue"](c[d][1])}),!1)}),m},startsWithAnyOf:function(){var e=T.apply(Mn,arguments);return e.every(function(n){return"string"==typeof n})?0===e.length?t(this):this.inAnyRange(e.map(function(n){return[n,n+lt]})):n(this,"startsWithAnyOf() only works with strings")}}}),p($.prototype,function(){function n(n,t){n.filter=Dn(n.filter,t)}function t(n,t,e){var r=n.replayFilter;n.replayFilter=r?function(){return Dn(r(),t())}:t,n.justLimit=e&&!r}function e(n,t){n.isMatch=Dn(n.isMatch,t)}function r(n,t){if(n.isPrimKey)return t;var e=n.table.schema.idxByName[n.index];if(!e)throw new Ln.Schema("KeyPath "+n.index+" on object store "+t.name+" is not indexed");return t.index(e.name)}function o(n,t){var e=r(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 u(n,t,e,r,i){var u=n.replayFilter?Dn(n.filter,n.replayFilter()):n.filter;n.or?function(){function a(){2===++f&&e()}function c(n,e,i){if(!u||u(e,i,a,r)){var o=e.primaryKey.toString();d(s,o)||(s[o]=!0,t(n,e,i))}}var s={},f=0;n.or._iterate(c,a,r,i),rn(o(n,i),n.algorithm,c,a,r,!n.keysOnly&&n.valueMapper)}():rn(o(n,i),Dn(n.algorithm,u),t,e,r,!n.keysOnly&&n.valueMapper)}function a(n){return n.table.schema.instanceTemplate}return{_read:function(n,t){var e=this._ctx;return e.error?e.table._trans(null,function(n,t){t(e.error)}):e.table._idbstore(nt,n).then(t)},_write:function(n){var t=this._ctx;return t.error?t.table._trans(null,function(n,e){e(t.error)}):t.table._idbstore(tt,n,"locked")},_addAlgorithm:function(n){var t=this._ctx;t.algorithm=Dn(t.algorithm,n)},_iterate:function(n,t,e,r){return u(this._ctx,n,t,e,r)},clone:function(n){var t=Object.create(this.constructor.prototype),e=Object.create(this._ctx);return n&&h(e,n),t._ctx=e,t},raw:function(){return this._ctx.valueMapper=null,this},each:function(n){var t=this._ctx;if(wt){var e=a(t),r=t.table.schema.primKey.keyPath,i=C(e,t.index?t.table.schema.idxByName[t.index].keyPath:r),o=C(e,r);n(e,{key:i,primaryKey:o})}return this._read(function(e,r,i){u(t,n,e,r,i)})},count:function(n){if(wt)return U.resolve(0).then(n);var t=this._ctx;if(X(t,!0))return this._read(function(n,e,i){var o=r(t,i),u=t.range?o.count(t.range):o.count();u.onerror=vn(e),u.onsuccess=function(e){n(Math.min(e.target.result,t.limit))}},n);var e=0;return this._read(function(n,r,i){u(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 i>r?-a:r>i?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,o){if(wt&&n([a(t)]),qn&&"next"===t.dir&&X(t,!0)&&t.limit>0){var c=t.table.hook.reading.fire,s=r(t,o),f=t.limit<1/0?s.getAll(t.range,t.limit):s.getAll(t.range);f.onerror=vn(e),f.onsuccess=c===i?dn(n):un(dn(function(t){n(t.map(c))}))}else{var l=[];u(t,function(n){l.push(n)},function(){n(l)},e,o)}},n)},offset:function(n){var e=this._ctx;return 0>=n?this:(e.offset+=n,X(e)?t(e,function(){var t=n;return function(n,e){return 0===t?!0:1===t?(--t,!1):(e(function(){n.advance(t),t=0}),!1)}}):t(e,function(){var t=n;return function(){return--t<0}}),this)},limit:function(n){return this._ctx.limit=Math.min(this._ctx.limit,n),t(this._ctx,function(){var t=n;return function(n,e,r){return--t<=0&&e(r),t>=0}},!0),this},until:function(t,e){var r=this._ctx;return wt&&t(a(r)),n(this._ctx,function(n,r,i){return t(n.value)?(r(i),e):!0}),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(t){return wt&&t(a(this._ctx)),n(this._ctx,function(n){return t(n.value)}),e(this._ctx,t),this},and:function(n){return this.filter(n)},or:function(n){return new Y(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(qn&&"next"===t.dir&&X(t,!0)&&t.limit>0)return this._read(function(n,e,i){var o=r(t,i),u=t.limit<1/0?o.getAllKeys(t.range,t.limit):o.getAllKeys(t.range);u.onerror=vn(e),u.onsuccess=dn(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 t=this._ctx,e=t.index&&t.table.schema.idxByName[t.index];if(!e||!e.multi)return this;var r={};return n(this._ctx,function(n){var t=n.primaryKey.toString(),e=d(r,t);return r[t]=!0,!e}),this}}}),y(Z).from($).extend({modify:function(n){var t=this,e=this._ctx,i=e.table.hook,o=i.updating.fire,u=i.deleting.fire;return wt&&"function"==typeof n&&n.call({value:e.table.schema.instanceTemplate},e.table.schema.instanceTemplate),this._write(function(e,i,a,c){function s(n,t){function e(n){return w.push(n),k.push(r.primKey),l(),!0}x=t.primaryKey;var r={primKey:t.primaryKey,value:n,onsuccess:null,onerror:null};if(p.call(r,n,r)!==!1){var i=!d(r,"value");++g,A(function(){var n=i?t["delete"]():t.update(r.value);n._hookCtx=r,n.onerror=yn(e),n.onsuccess=pn(function(){++b,l()})},e)}else r.onsuccess&&r.onsuccess(r.value)}function f(n){return n&&(w.push(n),k.push(x)),i(new N("Error modifying one or more objects",w,b,k))}function l(){_&&b+w.length===g&&(w.length>0?f():e(b))}var p;if("function"==typeof n)p=o===r&&u===r?n:function(t){var e=D(t);if(n.call(this,t,this)===!1)return!1;if(d(this,"value")){var r=S(e,this.value),i=o.call(this,r,this.primKey,e,c);i&&(t=this.value,Cn(i).forEach(function(n){O(t,n,i[n])}))}else u.call(this,this.primKey,t,c)};else if(o===r){var v=Cn(n),y=v.length;p=function(t){for(var e=!1,r=0;y>r;++r){var i=v[r],o=n[i];C(t,i)!==o&&(O(t,i,o),e=!0)}return e}}else{var m=n;n=P(m),p=function(t){var e=!1,r=o.call(this,n,this.primKey,D(t),c);return r&&h(n,r),Cn(n).forEach(function(r){var i=n[r];C(t,r)!==i&&(O(t,r,i),e=!0)}),r&&(n=P(m)),e}}var g=0,b=0,_=!1,w=[],k=[],x=null;t.clone().raw()._iterate(s,function(){_=!0,l()},f,a)})},"delete":function(){var n=this,t=this._ctx,e=t.range,i=t.table.hook.deleting.fire,o=i!==r;if(!o&&X(t)&&(t.isPrimKey&&!gt||!e))return this._write(function(n,t,r){var i=vn(t),o=e?r.count(e):r.count();o.onerror=i,o.onsuccess=function(){var u=o.result;A(function(){var t=e?r["delete"](e):r.clear();t.onerror=i,t.onsuccess=function(){return n(u)}},function(n){return t(n)})}});var u=o?2e3:1e4;return this._write(function(e,r,a,c){var s=0,f=n.clone({keysOnly:!t.isMatch&&!o}).distinct().limit(u).raw(),l=[],h=function(){return f.each(o?function(n,t){l.push([t.primaryKey,t.value])}:function(n,t){l.push(t.primaryKey)}).then(function(){return o?l.sort(function(n,t){return An(n[0],t[0])}):l.sort(An),J(a,c,l,o,i)}).then(function(){var n=l.length;return s+=n,l=[],u>n?s:h()})};e(h())})}}),h(this,{Collection:$,Table:W,Transaction:Q,Version:f,WhereClause:Y,WriteableCollection:Z,WriteableTable:H}),u(),Un.forEach(function(n){n(et)})}function ln(n){if("function"==typeof n)return new n;if(On(n))return[ln(n[0])];if(n&&"object"==typeof n){var t={};return hn(t,n),t}return n}function hn(n,t){return Cn(t).forEach(function(e){var r=ln(t[e]);n[e]=r}),n}function dn(n){return function(t){n(t.target.result)}}function pn(n){return un(function(t){var e=t.target,r=e.result,i=e._hookCtx,o=i&&i.onsuccess;o&&o(r),n&&n(r)},n)}function vn(n){return function(t){return mn(t),n(t.target.error),!1}}function yn(n){return un(function(t){var e=t.target,r=e.error,i=e._hookCtx,o=i&&i.onerror;return o&&o(r),mn(t),n(r),!1})}function mn(n){n.stopPropagation&&n.stopPropagation(),n.preventDefault&&n.preventDefault()}function gn(n){var t,e=fn.dependencies.localStorage;if(!e)return n([]);try{t=JSON.parse(e.getItem("Dexie.DatabaseNames")||"[]")}catch(r){t=[]}n(t)&&e.setItem("Dexie.DatabaseNames",JSON.stringify(t))}function bn(n){function t(n){return function(t){var e=n(t),r=e.value;return e.done?r:r&&"function"==typeof r.then?r.then(i,o):On(r)?U.all(r).then(i,o):i(r)}}var e=function(t){return n.next(t)},r=function(t){return n["throw"](t)},i=t(e),o=t(r);return t(e)()}function _n(n,t,e,r,i,o,u){this.name=n,this.keyPath=t,this.unique=e,this.multi=r,this.auto=i,this.compound=o,this.dotted=u;var a="string"==typeof t?t:t&&"["+[].join.call(t,"+")+"]";this.src=(e?"&":"")+(r?"*":"")+(i?"++":"")+a}function wn(n,t,e,r){this.name=n,this.primKey=t||new _n,this.indexes=e||[new _n],this.instanceTemplate=r,this.mappedClass=null,this.idxByName=x(e,function(n){return[n.name,n]})}function kn(n){return 1===n.length?n[0]:n}function xn(n){var t=n&&(n.getDatabaseNames||n.webkitGetDatabaseNames);return t&&t.bind(n)}var In="undefined"!=typeof location&&/^(http|https):\/\/(localhost|127\.0\.0\.1)/.test(location.href),An=function(){return!0},En=!new Error("").stack,Cn=Object.keys,On=Array.isArray,jn="undefined"!=typeof self?self:"undefined"!=typeof window?window:global,Pn=Object.getPrototypeOf,Dn={}.hasOwnProperty,Sn=Object.getOwnPropertyDescriptor,Tn=[].slice,Kn="undefined"!=typeof Symbol&&Symbol.iterator,Bn=Kn?function(n){var t;return null!=n&&(t=n[Kn])&&t.apply(n)}:function(){return null},Mn={},Nn=[].concat,qn=["Modify","Bulk","OpenFailed","VersionChange","Schema","Upgrade","InvalidTable","MissingAPI","NoSuchDatabase","InvalidArgument","SubTransaction","Unsupported","Internal","DatabaseClosed","IncompatiblePromise"],Fn=["Unknown","Constraint","Data","TransactionInactive","ReadOnly","Version","NotFound","InvalidState","InvalidAccess","Abort","Timeout","QuotaExceeded","Syntax","DataClone"],Rn=qn.concat(Fn),Un={VersionChanged:"Database version changed by other database connection",DatabaseClosed:"Database has been closed",Abort:"Transaction aborted",TransactionInactive:"Transaction has already completed or failed"};y(B).from(Error).extend({stack:{get:function(){return this._stack||(this._stack=this.name+": "+this.message+e(this._e,2))}},toString:function(){return this.name+": "+this.message}}),y(N).from(B),y(q).from(B);var zn=Rn.reduce(function(n,t){return n[t]=t+"Error",n},{}),Vn=B,Ln=Rn.reduce(function(n,e){function r(n,r){this._e=t(),this.name=i,n?"string"==typeof n?(this.message=n,this.inner=r||null):"object"==typeof n&&(this.message=n.name+" "+n.message,this.inner=n):(this.message=Un[e]||i,this.inner=null)}var i=e+"Error";return y(r).from(Vn),n[e]=r,n},{});Ln.Syntax=SyntaxError,Ln.Type=TypeError,Ln.Range=RangeError;var Wn=Fn.reduce(function(n,t){return n[t+"Error"]=Ln[t],n},{}),Hn=Rn.reduce(function(n,t){return-1===["Syntax","Type","Range"].indexOf(t)&&(n[t+"Error"]=Ln[t]),n},{});Hn.ModifyError=N,Hn.DexieError=B,Hn.BulkError=q;var Gn={},Jn=100,Qn=20,Yn=!1,$n="undefined"==typeof setImmediate?function(){setTimeout(Y,0)}:setImmediate.bind(null,Y),Xn=function(n,t){at.push([n,t]),nt&&($n(),nt=!1)},Zn=!0,nt=!0,tt=[],et=[],rt=null,it=i,ot={global:!0,ref:0,unhandleds:[],onunhandled:sn,finalize:function(){this.unhandleds.forEach(function(n){try{sn(n[0],n[1])}catch(t){}})}},ut=ot,at=[],ct=0,st=[];p(U.prototype,{then:function(n,t){var e=this,r=new U(function(r,i){H(e,new z(n,t,r,i))});return In&&(!this._prev||null===this._state)&&Q(r,this),r},_then:function(n,t){H(this,new z(null,null,n,t))},"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):on(n)}):this.then(null,function(n){return n&&n.name===t?e(n):on(n)})},"finally":function(n){return this.then(function(t){return n(),t},function(t){return n(),on(t)})},uncaught:function(n){var t=this;return this.onuncatched=f(this.onuncatched,n),this._state===!1&&-1===tt.indexOf(this)&&tt.some(function(n,e,r){return n._value===t._value&&(r[e]=t)}),this},stack:{get:function(){if(this._stack)return this._stack;try{Yn=!0;var n=J(this,[],Qn),t=n.join("\nFrom previous: ");return null!==this._state&&(this._stack=t),t}finally{Yn=!1}}}}),p(U,{all:function(){var n=T.apply(null,arguments);return new U(function(t,e){0===n.length&&t([]);var r=n.length;n.forEach(function(i,o){return U.resolve(i).then(function(e){n[o]=e,--r||t(n)},e)})})},resolve:function(n){return n&&"function"==typeof n.then?n:new U(Gn,!0,n)},reject:on,race:function(){var n=T.apply(null,arguments);return new U(function(t,e){n.map(function(n){return U.resolve(n).then(t,e)})})},PSD:{get:function(){return ut},set:function(n){return ut=n}},newPSD:an,usePSD:cn,scheduler:{get:function(){return Xn},set:function(n){Xn=n}},rejectionMapper:{get:function(){return it},set:function(n){it=n}},follow:function(n){return new U(function(t,e){return an(function(t,e){var r=ut;r.unhandleds=[],r.onunhandled=e,r.finalize=u(function(){var n=this;nn(function(){0===n.unhandleds.length?t():e(n.unhandleds[0])})},r.finalize),n()},t,e)})},on:R(null,{error:[f,rn]})}),_(function(){Xn=function(n,t){setTimeout(function(){n.apply(null,t)},0)}});var ft="1.4.1",lt=String.fromCharCode(65535),ht=function(){try{return IDBKeyRange.only([[]]),[[]]}catch(n){return lt}}(),dt="Invalid key provided. Keys must be of type string, number, Date or Array.",pt="String expected.",vt=[],yt="undefined"!=typeof navigator&&/(MSIE|Trident|Edge)/.test(navigator.userAgent),mt=yt,gt=yt,bt=function(n){return!/(dexie\.js|dexie\.min\.js)/.test(n)};n(In,bt);var _t=function(){},wt=!1,kt=jn.idbModules&&jn.idbModules.shimIndexedDB?jn.idbModules:{};return p(fn,Hn),p(fn,{"delete":function(n){var t=new fn(n),e=t["delete"]();return e.onblocked=function(n){return t.on("blocked",n),this},e},exists:function(n){return new fn(n).open().then(function(n){return n.close(),!0})["catch"](fn.NoSuchDatabaseError,function(){return!1})},getDatabaseNames:function(n){return new U(function(n,t){var e=xn(indexedDB);if(e){var r=e();r.onsuccess=function(t){n(g(t.target.result,0))},r.onerror=vn(t)}else gn(function(t){return n(t),!1})}).then(n)},defineClass:function(n){function t(t){t?h(this,t):wt&&hn(this,n)}return t},applyStructure:hn,ignoreTransaction:function(n){return ut.trans?cn(ut.transless,n):n()},vip:function(n){return an(function(){return ut.letThrough=!0,n()})},async:function(n){return function(){try{var t=bn(n.apply(this,arguments));return t&&"function"==typeof t.then?t:U.resolve(t)}catch(e){return E(e)}}},spawn:function(n,t,e){try{var r=bn(n.apply(e,t||[]));return r&&"function"==typeof r.then?r:U.resolve(r)}catch(i){return E(i)}},currentTransaction:{get:function(){return ut.trans||null}},Promise:U,debug:{get:function(){return In},set:function(t){n(t,"dexie"===t?function(){return!0}:bt)}},derive:y,extend:h,props:p,override:b,Events:R,events:R,getByKeyPath:C,setByKeyPath:O,delByKeyPath:j,shallowClone:P,deepClone:D,getObjectDiff:S,asap:k,maxKey:ht,addons:[],connections:vt,MultiModifyError:Ln.Modify,errnames:zn,IndexSpec:_n,TableSchema:wn,dependencies:{indexedDB:kt.shimIndexedDB||jn.indexedDB||jn.mozIndexedDB||jn.webkitIndexedDB||jn.msIndexedDB,IDBKeyRange:kt.IDBKeyRange||jn.IDBKeyRange||jn.webkitIDBKeyRange},semVer:ft,version:ft.split(".").map(function(n){return parseInt(n)}).reduce(function(n,t,e){return n+t/Math.pow(10,2*e)}),fakeAutoComplete:_t,"default":fn}),A(function(){fn.dependencies.localStorage=null!=("undefined"!=typeof chrome&&null!==chrome?chrome.storage:void 0)?null:jn.localStorage}),U.rejectionMapper=F,_(function(){fn.fakeAutoComplete=_t=_,fn.fake=wt=!0}),fn}); +//# sourceMappingURL=dist/dexie.min.js.map \ No newline at end of file From 67f906ab24acb80a8ffbad29ff8ddda5fc570cf0 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Sun, 21 Aug 2016 13:32:36 -0700 Subject: [PATCH 02/51] Import stubs --- ext/bg/js/dictionary.js | 20 ++++++++++++++---- ext/bg/js/translator.js | 47 +++++++++++++++++++---------------------- 2 files changed, 38 insertions(+), 29 deletions(-) diff --git a/ext/bg/js/dictionary.js b/ext/bg/js/dictionary.js index a6438523..082d1479 100644 --- a/ext/bg/js/dictionary.js +++ b/ext/bg/js/dictionary.js @@ -21,20 +21,32 @@ class Dictionary { constructor() { this.termDicts = {}; this.kanjiDicts = {}; + this.db = new Dexie('dict'); + this.dbVer = 1; } - addTermDict(name, dict) { + loadDb() { + return this.db.open().then((db) => { + if (db.verno !== this.dbVer) { + Promise.reject('db version mismatch'); + } + + return db.verno; + }); + } + + importTermDict(name, dict) { this.termDicts[name] = dict; } - addKanjiDict(name, dict) { + importKanjiDict(name, dict) { this.kanjiDicts[name] = dict; } findTerm(term) { let results = []; - for (let name in this.termDicts) { + for (const name in this.termDicts) { const dict = this.termDicts[name]; if (!(term in dict.i)) { continue; @@ -62,7 +74,7 @@ class Dictionary { findKanji(kanji) { const results = []; - for (let name in this.kanjiDicts) { + for (const name in this.kanjiDicts) { const def = this.kanjiDicts[name].c[kanji]; if (def) { const [k, o, t, ...g] = def; diff --git a/ext/bg/js/translator.js b/ext/bg/js/translator.js index fd414847..f373fe83 100644 --- a/ext/bg/js/translator.js +++ b/ext/bg/js/translator.js @@ -31,31 +31,28 @@ class Translator { return; } - Translator.loadData('bg/data/rules.json') - .then((response) => { - this.deinflector.setRules(JSON.parse(response)); - return Translator.loadData('bg/data/tags.json'); - }) - .then((response) => { - this.tagMeta = JSON.parse(response); - return Translator.loadData('bg/data/edict.json'); - }) - .then((response) => { - this.dictionary.addTermDict('edict', JSON.parse(response)); - return Translator.loadData('bg/data/kanjidic.json'); - }) - .then((response) => { - this.dictionary.addKanjiDict('kanjidic', JSON.parse(response)); - return loadEnamDict ? Translator.loadData('bg/data/enamdict.json') : Promise.resolve(null); - }) - .then((response) => { - if (response !== null) { - this.dictionary.addTermDict('enamdict', JSON.parse(response)); - } - - this.loaded = true; - callback(); - }); + Translator.loadData('bg/data/rules.json').then((response) => { + this.deinflector.setRules(JSON.parse(response)); + return Translator.loadData('bg/data/tags.json'); + }).then((response) => { + this.tagMeta = JSON.parse(response); + return this.dictionary.loadDb(); + }).then(() => { + this.loaded = true; + callback(); + }).catch(() => { + return Translator.loadData('bg/data/edict.json'); + }).then((response) => { + this.dictionary.importTermDict('edict', JSON.parse(response)); + return Translator.loadData('bg/data/enamdict.json'); + }).then((response) => { + this.dictionary.importTermDict('enamdict', JSON.parse(response)); + return Translator.loadData('bg/data/kanjidic.json'); + }).then((response) => { + this.dictionary.importKanjiDict('kanjidic', JSON.parse(response)); + this.loaded = true; + callback(); + }); } findTerm(text) { From a062b25178dd8d916a8cdf87cffa36b5365ab021 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Sun, 21 Aug 2016 19:51:12 -0700 Subject: [PATCH 03/51] Work on DB integration --- ext/bg/js/dictionary.js | 101 ++++++++++++++++++++++------------------ ext/bg/js/translator.js | 7 +-- 2 files changed, 59 insertions(+), 49 deletions(-) diff --git a/ext/bg/js/dictionary.js b/ext/bg/js/dictionary.js index 082d1479..7b885db2 100644 --- a/ext/bg/js/dictionary.js +++ b/ext/bg/js/dictionary.js @@ -19,10 +19,9 @@ class Dictionary { constructor() { - this.termDicts = {}; - this.kanjiDicts = {}; this.db = new Dexie('dict'); this.dbVer = 1; + this.entities = null; } loadDb() { @@ -35,59 +34,69 @@ class Dictionary { }); } - importTermDict(name, dict) { - this.termDicts[name] = dict; + initDb() { + this.entities = {}; + return this.db.version(this.dbVer).stores({ + terms: 'expression, reading', + entities: 'name', + kanji: 'character', + }); } - importKanjiDict(name, dict) { - this.kanjiDicts[name] = dict; - } - - findTerm(term) { - let results = []; - - for (const name in this.termDicts) { - const dict = this.termDicts[name]; - if (!(term in dict.i)) { - continue; + importTermDict(dict) { + this.entities = {}; + return this.db.terms.bulkAdd(dict.d, 'expression, reading, tags, glossary').then(() => { + for (const [key, value] of dict.e) { + this.entities[key] = value; } - const indices = dict.i[term].split(' ').map(Number); - results = results.concat( - indices.map(index => { - const [e, r, t, ...g] = dict.d[index]; - return { - expression: e, - reading: r, - tags: t.split(' '), - glossary: g, - entities: dict.e, - id: index - }; - }) - ); + return this.db.entities.bulkAdd(dict.e, 'name, value'); + }); + } + + importKanjiDict(dict) { + return this.db.kanji.bulkAdd(dict.d, 'character, onyomi, kunyomi, tags, glossary'); + } + + fetchEntities() { + if (this.entities !== null) { + return Promise.resolve(this.entities); } - return results; + this.entities = {}; + return this.db.entities.each((row) => { + this.entities[row.name] = row.value; + }).then(() => { + return Promise.resolve(this.entities); + }); + } + + findterm(term) { + const results = []; + return this.db.terms.where('expression').equals(term).or('reading').equals(term).each((row) => { + results.push({ + expression: row.expression, + reading: row.reading, + tags: row.tags.split(' '), + glossary: row.glossary, + entities: this.entities, + id: results.length + }); + }).then(() => { + Promise.resolve(results); + }); } findKanji(kanji) { const results = []; - - for (const name in this.kanjiDicts) { - const def = this.kanjiDicts[name].c[kanji]; - if (def) { - const [k, o, t, ...g] = def; - results.push({ - character: kanji, - kunyomi: k.split(' '), - onyomi: o.split(' '), - tags: t.split(' '), - glossary: g - }); - } - } - - return results; + return this.db.kanji.where('character').equals(kanji).each((row) => { + results.push({ + character: row.character, + onyomi: row.onyomi.split(' '), + kunyomi: row.kunyomi.split(' '), + tags: row.tags.split(' '), + glossary: row.glossary + }); + }); } } diff --git a/ext/bg/js/translator.js b/ext/bg/js/translator.js index f373fe83..9fd1ab59 100644 --- a/ext/bg/js/translator.js +++ b/ext/bg/js/translator.js @@ -41,15 +41,16 @@ class Translator { this.loaded = true; callback(); }).catch(() => { + this.dictionary.initDb(); return Translator.loadData('bg/data/edict.json'); }).then((response) => { - this.dictionary.importTermDict('edict', JSON.parse(response)); + this.dictionary.importTermDict(JSON.parse(response)); return Translator.loadData('bg/data/enamdict.json'); }).then((response) => { - this.dictionary.importTermDict('enamdict', JSON.parse(response)); + this.dictionary.importTermDict(JSON.parse(response)); return Translator.loadData('bg/data/kanjidic.json'); }).then((response) => { - this.dictionary.importKanjiDict('kanjidic', JSON.parse(response)); + this.dictionary.importKanjiDict(JSON.parse(response)); this.loaded = true; callback(); }); From 9621a0cd4b8ea395b78418d2aca210183394f4a4 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Mon, 22 Aug 2016 08:48:19 -0700 Subject: [PATCH 04/51] WIP --- ext/bg/js/dictionary.js | 75 ++++++++++++++++++++++------------------- ext/bg/js/translator.js | 24 +++++++------ 2 files changed, 55 insertions(+), 44 deletions(-) diff --git a/ext/bg/js/dictionary.js b/ext/bg/js/dictionary.js index 7b885db2..a3793cd6 100644 --- a/ext/bg/js/dictionary.js +++ b/ext/bg/js/dictionary.js @@ -19,43 +19,48 @@ class Dictionary { constructor() { - this.db = new Dexie('dict'); - this.dbVer = 1; + this.db = null; this.entities = null; } loadDb() { - return this.db.open().then((db) => { - if (db.verno !== this.dbVer) { - Promise.reject('db version mismatch'); - } + this.db = null; + this.entities = null; - return db.verno; + return new Dexie('dict').open().then((db) => { + this.db = db; }); } - initDb() { - this.entities = {}; - return this.db.version(this.dbVer).stores({ - terms: 'expression, reading', - entities: 'name', - kanji: 'character', + resetDb() { + this.db = null; + this.entities = null; + + return new Dexie('dict').delete().then(() => { + return Promise.resolve(new Dexie('dict')); + }).then((db) => { + this.db = db; + return this.db.version(1).stores({ + terms: '++id, e, r', + entities: 'n', + kanji: 'c' + }); }); } importTermDict(dict) { - this.entities = {}; - return this.db.terms.bulkAdd(dict.d, 'expression, reading, tags, glossary').then(() => { - for (const [key, value] of dict.e) { - this.entities[key] = value; + return this.db.terms.bulkAdd(dict.d).then(() => { + this.entities = {}; + for (const name in dict.e) { + this.entities[name] = dict.e[name]; } - return this.db.entities.bulkAdd(dict.e, 'name, value'); + return this.db.entities.bulkAdd(dict.e); }); } importKanjiDict(dict) { - return this.db.kanji.bulkAdd(dict.d, 'character, onyomi, kunyomi, tags, glossary'); + return this.db.kanji.bulkAdd(dict.d); } fetchEntities() { @@ -63,9 +68,11 @@ class Dictionary { return Promise.resolve(this.entities); } - this.entities = {}; - return this.db.entities.each((row) => { - this.entities[row.name] = row.value; + return this.db.entities.toArray((rows) => { + this.entities = {}; + for (const row of rows) { + this.entities[row.name] = row.value; + } }).then(() => { return Promise.resolve(this.entities); }); @@ -73,14 +80,14 @@ class Dictionary { findterm(term) { const results = []; - return this.db.terms.where('expression').equals(term).or('reading').equals(term).each((row) => { + return this.db.terms.where('e').equals(term).or('r').equals(term).each((row) => { results.push({ - expression: row.expression, - reading: row.reading, - tags: row.tags.split(' '), - glossary: row.glossary, + expression: row.e, + reading: row.r, + tags: row.t.split(' '), + glossary: row.g, entities: this.entities, - id: results.length + id: results.id }); }).then(() => { Promise.resolve(results); @@ -89,13 +96,13 @@ class Dictionary { findKanji(kanji) { const results = []; - return this.db.kanji.where('character').equals(kanji).each((row) => { + return this.db.kanji.where('c').equals(kanji).each((row) => { results.push({ - character: row.character, - onyomi: row.onyomi.split(' '), - kunyomi: row.kunyomi.split(' '), - tags: row.tags.split(' '), - glossary: row.glossary + character: row.c, + onyomi: row.o.split(' '), + kunyomi: row.k.split(' '), + tags: row.t.split(' '), + glossary: row.m }); }); } diff --git a/ext/bg/js/translator.js b/ext/bg/js/translator.js index 9fd1ab59..75f91055 100644 --- a/ext/bg/js/translator.js +++ b/ext/bg/js/translator.js @@ -41,16 +41,20 @@ class Translator { this.loaded = true; callback(); }).catch(() => { - this.dictionary.initDb(); - return Translator.loadData('bg/data/edict.json'); - }).then((response) => { - this.dictionary.importTermDict(JSON.parse(response)); - return Translator.loadData('bg/data/enamdict.json'); - }).then((response) => { - this.dictionary.importTermDict(JSON.parse(response)); - return Translator.loadData('bg/data/kanjidic.json'); - }).then((response) => { - this.dictionary.importKanjiDict(JSON.parse(response)); + return this.dictionary.resetDb().then(() => { + return Translator.loadData('bg/data/edict.json'); + }).then((response) => { + return this.dictionary.importTermDict(JSON.parse(response)); + }).then(() => { + return Translator.loadData('bg/data/enamdict.json'); + }).then((response) => { + return this.dictionary.importTermDict(JSON.parse(response)); + }).then(() => { + return Translator.loadData('bg/data/kanjidic.json'); + }).then((response) => { + return this.dictionary.importKanjiDict(JSON.parse(response)); + }); + }).then(() => { this.loaded = true; callback(); }); From f106b64876c975237e8c8bb51518ab53d2a9d2fc Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Tue, 23 Aug 2016 20:33:04 -0700 Subject: [PATCH 05/51] WIP --- ext/bg/js/dictionary.js | 117 ++++++++++++++++++++++++++++------------ ext/bg/js/translator.js | 31 +++++------ 2 files changed, 97 insertions(+), 51 deletions(-) diff --git a/ext/bg/js/dictionary.js b/ext/bg/js/dictionary.js index a3793cd6..dd46064a 100644 --- a/ext/bg/js/dictionary.js +++ b/ext/bg/js/dictionary.js @@ -23,40 +23,26 @@ class Dictionary { this.entities = null; } + existsDb() { + return Dexie.exists('dict'); + } + loadDb() { this.db = null; this.entities = null; - return new Dexie('dict').open().then((db) => { - this.db = db; - }); + return this.initDb().open(); } - resetDb() { - this.db = null; - this.entities = null; - - return new Dexie('dict').delete().then(() => { - return Promise.resolve(new Dexie('dict')); - }).then((db) => { - this.db = db; - return this.db.version(1).stores({ - terms: '++id, e, r', - entities: 'n', - kanji: 'c' - }); + initDb() { + this.db = new Dexie('dict'); + this.db.version(1).stores({ + terms: '++id,expression,reading', + entities: '++id,name', + kanji: '++id,character' }); - } - importTermDict(dict) { - return this.db.terms.bulkAdd(dict.d).then(() => { - this.entities = {}; - for (const name in dict.e) { - this.entities[name] = dict.e[name]; - } - - return this.db.entities.bulkAdd(dict.e); - }); + return this.db; } importKanjiDict(dict) { @@ -78,19 +64,19 @@ class Dictionary { }); } - findterm(term) { + findTerm(term) { const results = []; - return this.db.terms.where('e').equals(term).or('r').equals(term).each((row) => { + return this.db.terms.where('expression').equals(term).or('reading').equals(term).each((row) => { results.push({ - expression: row.e, - reading: row.r, - tags: row.t.split(' '), - glossary: row.g, + expression: row.expression, + reading: row.reading, + tags: row.tags.split(' '), + glossary: row.glossary, entities: this.entities, - id: results.id + id: row.id }); }).then(() => { - Promise.resolve(results); + return Promise.resolve(results); }); } @@ -106,4 +92,67 @@ class Dictionary { }); }); } + + // importTermDict(dict) { + // return this.db.terms.bulkAdd(dict.d).then(() => { + // this.entities = {}; + // for (const name in dict.e) { + // this.entities[name] = dict.e[name]; + // } + + // return this.db.entities.bulkAdd(dict.e); + // }); + // } + + importTermDict(indexUrl) { + return Dictionary.loadJson(indexUrl).then((index) => { + const entities = []; + for (const [name, value] of index.ents) { + entities.push({name, value}); + } + + return this.db.entities.bulkAdd(entities).then(() => { + if (this.entities === null) { + this.entities = {}; + } + + for (const entity of entities) { + this.entities[entity.name] = entity.value; + } + }).then(() => { + const loaders = []; + const indexDir = indexUrl.slice(0, indexUrl.lastIndexOf('/')); + + for (let i = 0; i < index.refs; ++i) { + const refUrl = `${indexDir}/ref_${i}.json`; + loaders.push( + Dictionary.loadJson(refUrl).then((refs) => { + const rows = []; + for (const [e, r, t, ...g] of refs) { + rows.push({ + 'expression': e, + 'reading': r, + 'tags': t, + 'glossary': g + }); + } + + return this.db.terms.bulkAdd(rows); + }) + ); + } + + return Promise.all(loaders); + }); + }); + } + + static loadJson(url) { + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest(); + xhr.addEventListener('load', () => resolve(JSON.parse(xhr.responseText))); + xhr.open('GET', chrome.extension.getURL(url), true); + xhr.send(); + }); + } } diff --git a/ext/bg/js/translator.js b/ext/bg/js/translator.js index 75f91055..f9ac1d56 100644 --- a/ext/bg/js/translator.js +++ b/ext/bg/js/translator.js @@ -36,27 +36,24 @@ class Translator { return Translator.loadData('bg/data/tags.json'); }).then((response) => { this.tagMeta = JSON.parse(response); - return this.dictionary.loadDb(); + return this.dictionary.existsDb(); + }).then((exists) => { + if (exists) { + return this.dictionary.loadDb(); + } else { + this.dictionary.initDb(); + return Promise.all([ + this.dictionary.importTermDict('bg/data/edict/index.json'), + this.dictionary.importTermDict('bg/data/enamdict/index.json') + ]); + } }).then(() => { this.loaded = true; callback(); - }).catch(() => { - return this.dictionary.resetDb().then(() => { - return Translator.loadData('bg/data/edict.json'); - }).then((response) => { - return this.dictionary.importTermDict(JSON.parse(response)); - }).then(() => { - return Translator.loadData('bg/data/enamdict.json'); - }).then((response) => { - return this.dictionary.importTermDict(JSON.parse(response)); - }).then(() => { - return Translator.loadData('bg/data/kanjidic.json'); - }).then((response) => { - return this.dictionary.importKanjiDict(JSON.parse(response)); + + this.dictionary.findTerm('猫').then((result) => { + console.log(result); }); - }).then(() => { - this.loaded = true; - callback(); }); } From 6366d9bd8e5758d631e5bba14b2c892e0b27c474 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Tue, 23 Aug 2016 20:53:11 -0700 Subject: [PATCH 06/51] WIP --- ext/bg/js/dictionary.js | 28 ++++++++++++++-------------- ext/bg/js/translator.js | 20 ++++++++++---------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/ext/bg/js/dictionary.js b/ext/bg/js/dictionary.js index dd46064a..44e97752 100644 --- a/ext/bg/js/dictionary.js +++ b/ext/bg/js/dictionary.js @@ -38,8 +38,8 @@ class Dictionary { this.db = new Dexie('dict'); this.db.version(1).stores({ terms: '++id,expression,reading', - entities: '++id,name', - kanji: '++id,character' + entities: '++,name', + kanji: '++,character' }); return this.db; @@ -125,24 +125,24 @@ class Dictionary { for (let i = 0; i < index.refs; ++i) { const refUrl = `${indexDir}/ref_${i}.json`; - loaders.push( - Dictionary.loadJson(refUrl).then((refs) => { + loaders.push(() => { + return Dictionary.loadJson(refUrl).then((refs) => { const rows = []; - for (const [e, r, t, ...g] of refs) { - rows.push({ - 'expression': e, - 'reading': r, - 'tags': t, - 'glossary': g - }); + for (const [expression, reading, tags, ...glossary] of refs) { + rows.push({expression, reading, tags, glossary}); } return this.db.terms.bulkAdd(rows); - }) - ); + }); + }); } - return Promise.all(loaders); + let chain = Promise.resolve(); + for (const loader of loaders) { + chain = chain.then(loader); + } + + return chain; }); }); } diff --git a/ext/bg/js/translator.js b/ext/bg/js/translator.js index f9ac1d56..8af0e31b 100644 --- a/ext/bg/js/translator.js +++ b/ext/bg/js/translator.js @@ -31,11 +31,11 @@ class Translator { return; } - Translator.loadData('bg/data/rules.json').then((response) => { - this.deinflector.setRules(JSON.parse(response)); - return Translator.loadData('bg/data/tags.json'); - }).then((response) => { - this.tagMeta = JSON.parse(response); + Translator.loadJson('bg/data/rules.json').then((rules) => { + this.deinflector.setRules(rules); + return Translator.loadJson('bg/data/tags.json'); + }).then((tagMeta) => { + this.tagMeta = tagMeta; return this.dictionary.existsDb(); }).then((exists) => { if (exists) { @@ -48,12 +48,12 @@ class Translator { ]); } }).then(() => { - this.loaded = true; - callback(); - this.dictionary.findTerm('猫').then((result) => { console.log(result); }); + + this.loaded = true; + callback(); }); } @@ -246,10 +246,10 @@ class Translator { return code >= 0x4e00 && code < 0x9fb0 || code >= 0x3400 && code < 0x4dc0; } - static loadData(url) { + static loadJson(url) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); - xhr.addEventListener('load', () => resolve(xhr.responseText)); + xhr.addEventListener('load', () => resolve(JSON.parse(xhr.responseText))); xhr.open('GET', chrome.extension.getURL(url), true); xhr.send(); }); From 8b5f74f99bdbaeb1b7c72614f2a71abfc72be479 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Tue, 23 Aug 2016 22:22:09 -0700 Subject: [PATCH 07/51] WIP --- ext/bg/js/dictionary.js | 83 ++++++++++++++++++++++++----------------- 1 file changed, 48 insertions(+), 35 deletions(-) diff --git a/ext/bg/js/dictionary.js b/ext/bg/js/dictionary.js index 44e97752..8f04c458 100644 --- a/ext/bg/js/dictionary.js +++ b/ext/bg/js/dictionary.js @@ -27,13 +27,6 @@ class Dictionary { return Dexie.exists('dict'); } - loadDb() { - this.db = null; - this.entities = null; - - return this.initDb().open(); - } - initDb() { this.db = new Dexie('dict'); this.db.version(1).stores({ @@ -45,23 +38,11 @@ class Dictionary { return this.db; } - importKanjiDict(dict) { - return this.db.kanji.bulkAdd(dict.d); - } + loadDb() { + this.db = null; + this.entities = null; - fetchEntities() { - if (this.entities !== null) { - return Promise.resolve(this.entities); - } - - return this.db.entities.toArray((rows) => { - this.entities = {}; - for (const row of rows) { - this.entities[row.name] = row.value; - } - }).then(() => { - return Promise.resolve(this.entities); - }); + return this.initDb().open(); } findTerm(term) { @@ -93,18 +74,24 @@ class Dictionary { }); } - // importTermDict(dict) { - // return this.db.terms.bulkAdd(dict.d).then(() => { - // this.entities = {}; - // for (const name in dict.e) { - // this.entities[name] = dict.e[name]; - // } + getEntities() { + if (this.entities !== null) { + return Promise.resolve(this.entities); + } - // return this.db.entities.bulkAdd(dict.e); - // }); - // } + return this.db.entities.toArray((rows) => { + this.entities = {}; + for (const row of rows) { + this.entities[row.name] = row.value; + } + }).then(() => { + return Promise.resolve(this.entities); + }); + } importTermDict(indexUrl) { + const indexDir = indexUrl.slice(0, indexUrl.lastIndexOf('/')); + return Dictionary.loadJson(indexUrl).then((index) => { const entities = []; for (const [name, value] of index.ents) { @@ -121,9 +108,7 @@ class Dictionary { } }).then(() => { const loaders = []; - const indexDir = indexUrl.slice(0, indexUrl.lastIndexOf('/')); - - for (let i = 0; i < index.refs; ++i) { + for (let i = 0; i <= index.refs; ++i) { const refUrl = `${indexDir}/ref_${i}.json`; loaders.push(() => { return Dictionary.loadJson(refUrl).then((refs) => { @@ -147,6 +132,34 @@ class Dictionary { }); } + importKanjiDict(indexUrl) { + const indexDir = indexUrl.slice(0, indexUrl.lastIndexOf('/')); + + return Dictionary.loadJson(indexUrl).then((index) => { + const loaders = []; + for (let i = 0; i <= index.refs; ++i) { + const refUrl = `${indexDir}/ref_${i}.json`; + loaders.push(() => { + return Dictionary.loadJson(refUrl).then((refs) => { + const rows = []; + for (const [character, onyomi, kunyomi, tags, ...glossary] of refs) { + rows.push({character, onyomi, kunyomi, tags, glossary}); + } + + return this.db.kanji.bulkAdd(rows); + }); + }); + } + + let chain = Promise.resolve(); + for (const loader of loaders) { + chain = chain.then(loader); + } + + return chain; + }); + } + static loadJson(url) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); From b2d9b613ad3a673abb20033808877962545644d4 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Tue, 23 Aug 2016 22:28:37 -0700 Subject: [PATCH 08/51] Cleanup --- ext/bg/background.html | 1 + ext/bg/js/dictionary.js | 17 ++++------------- ext/bg/js/translator.js | 18 ++---------------- ext/bg/js/util.js | 33 +++++++++++++++++++++++++++++++++ ext/bg/js/yomichan.js | 2 +- 5 files changed, 41 insertions(+), 30 deletions(-) create mode 100644 ext/bg/js/util.js diff --git a/ext/bg/background.html b/ext/bg/background.html index e68c665b..c490df81 100644 --- a/ext/bg/background.html +++ b/ext/bg/background.html @@ -4,6 +4,7 @@ + diff --git a/ext/bg/js/dictionary.js b/ext/bg/js/dictionary.js index 8f04c458..3fceef65 100644 --- a/ext/bg/js/dictionary.js +++ b/ext/bg/js/dictionary.js @@ -92,7 +92,7 @@ class Dictionary { importTermDict(indexUrl) { const indexDir = indexUrl.slice(0, indexUrl.lastIndexOf('/')); - return Dictionary.loadJson(indexUrl).then((index) => { + return loadJson(indexUrl).then((index) => { const entities = []; for (const [name, value] of index.ents) { entities.push({name, value}); @@ -111,7 +111,7 @@ class Dictionary { for (let i = 0; i <= index.refs; ++i) { const refUrl = `${indexDir}/ref_${i}.json`; loaders.push(() => { - return Dictionary.loadJson(refUrl).then((refs) => { + return loadJson(refUrl).then((refs) => { const rows = []; for (const [expression, reading, tags, ...glossary] of refs) { rows.push({expression, reading, tags, glossary}); @@ -135,12 +135,12 @@ class Dictionary { importKanjiDict(indexUrl) { const indexDir = indexUrl.slice(0, indexUrl.lastIndexOf('/')); - return Dictionary.loadJson(indexUrl).then((index) => { + return loadJson(indexUrl).then((index) => { const loaders = []; for (let i = 0; i <= index.refs; ++i) { const refUrl = `${indexDir}/ref_${i}.json`; loaders.push(() => { - return Dictionary.loadJson(refUrl).then((refs) => { + return loadJson(refUrl).then((refs) => { const rows = []; for (const [character, onyomi, kunyomi, tags, ...glossary] of refs) { rows.push({character, onyomi, kunyomi, tags, glossary}); @@ -159,13 +159,4 @@ class Dictionary { return chain; }); } - - static loadJson(url) { - return new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest(); - xhr.addEventListener('load', () => resolve(JSON.parse(xhr.responseText))); - xhr.open('GET', chrome.extension.getURL(url), true); - xhr.send(); - }); - } } diff --git a/ext/bg/js/translator.js b/ext/bg/js/translator.js index 8af0e31b..30045378 100644 --- a/ext/bg/js/translator.js +++ b/ext/bg/js/translator.js @@ -31,9 +31,9 @@ class Translator { return; } - Translator.loadJson('bg/data/rules.json').then((rules) => { + loadJson('bg/data/rules.json').then((rules) => { this.deinflector.setRules(rules); - return Translator.loadJson('bg/data/tags.json'); + return loadJson('bg/data/tags.json'); }).then((tagMeta) => { this.tagMeta = tagMeta; return this.dictionary.existsDb(); @@ -240,18 +240,4 @@ class Translator { return 0; }); } - - static isKanji(c) { - const code = c.charCodeAt(0); - return code >= 0x4e00 && code < 0x9fb0 || code >= 0x3400 && code < 0x4dc0; - } - - static loadJson(url) { - return new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest(); - xhr.addEventListener('load', () => resolve(JSON.parse(xhr.responseText))); - xhr.open('GET', chrome.extension.getURL(url), true); - xhr.send(); - }); - } } diff --git a/ext/bg/js/util.js b/ext/bg/js/util.js new file mode 100644 index 00000000..97906eda --- /dev/null +++ b/ext/bg/js/util.js @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2016 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 . + */ + + +function loadJson(url) { + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest(); + xhr.addEventListener('load', () => resolve(JSON.parse(xhr.responseText))); + xhr.open('GET', chrome.extension.getURL(url), true); + xhr.send(); + }); +} + +function isKanji(c) { + const code = c.charCodeAt(0); + return code >= 0x4e00 && code < 0x9fb0 || code >= 0x3400 && code < 0x4dc0; +} + diff --git a/ext/bg/js/yomichan.js b/ext/bg/js/yomichan.js index fd9b84d3..716c622a 100644 --- a/ext/bg/js/yomichan.js +++ b/ext/bg/js/yomichan.js @@ -23,7 +23,7 @@ class Yomichan { Handlebars.registerHelper('kanjiLinks', function(options) { let result = ''; for (const c of options.fn(this)) { - if (Translator.isKanji(c)) { + if (isKanji(c)) { result += Handlebars.templates['kanji-link.html']({kanji: c}).trim(); } else { result += c; From 4bebe9215999e9983e47e3fc9a1e7d6d94d0a3bb Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Wed, 24 Aug 2016 09:14:23 -0700 Subject: [PATCH 09/51] WIP --- .gitattributes | 4 +++- ext/bg/js/dictionary.js | 18 +++++++++--------- ext/bg/js/translator.js | 1 + 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/.gitattributes b/.gitattributes index c575774d..c891610e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,5 @@ -util/data/*dic* filter=lfs diff=lfs merge=lfs -text ext/bg/data/*dic* filter=lfs diff=lfs merge=lfs -text +ext/bg/data/edict/*.json filter=lfs diff=lfs merge=lfs -text +ext/bg/data/enamdict/*.json filter=lfs diff=lfs merge=lfs -text +ext/bg/data/kanjidic/*.json filter=lfs diff=lfs merge=lfs -text *.ttf filter=lfs diff=lfs merge=lfs -text diff --git a/ext/bg/js/dictionary.js b/ext/bg/js/dictionary.js index 3fceef65..4baa41c8 100644 --- a/ext/bg/js/dictionary.js +++ b/ext/bg/js/dictionary.js @@ -108,12 +108,12 @@ class Dictionary { } }).then(() => { const loaders = []; - for (let i = 0; i <= index.refs; ++i) { - const refUrl = `${indexDir}/ref_${i}.json`; + for (let i = 1; i <= index.banks; ++i) { + const bankUrl = `${indexDir}/bank_${i}.json`; loaders.push(() => { - return loadJson(refUrl).then((refs) => { + return loadJson(bankUrl).then((defs) => { const rows = []; - for (const [expression, reading, tags, ...glossary] of refs) { + for (const [expression, reading, tags, ...glossary] of defs) { rows.push({expression, reading, tags, glossary}); } @@ -137,13 +137,13 @@ class Dictionary { return loadJson(indexUrl).then((index) => { const loaders = []; - for (let i = 0; i <= index.refs; ++i) { - const refUrl = `${indexDir}/ref_${i}.json`; + for (let i = 1; i <= index.banks; ++i) { + const bankUrl = `${indexDir}/bank_${i}.json`; loaders.push(() => { - return loadJson(refUrl).then((refs) => { + return loadJson(bankUrl).then((defs) => { const rows = []; - for (const [character, onyomi, kunyomi, tags, ...glossary] of refs) { - rows.push({character, onyomi, kunyomi, tags, glossary}); + for (const [character, onyomi, kunyomi, tags, ...meanings] of defs) { + rows.push({character, onyomi, kunyomi, tags, meanings}); } return this.db.kanji.bulkAdd(rows); diff --git a/ext/bg/js/translator.js b/ext/bg/js/translator.js index 30045378..d1a92d08 100644 --- a/ext/bg/js/translator.js +++ b/ext/bg/js/translator.js @@ -43,6 +43,7 @@ class Translator { } else { this.dictionary.initDb(); return Promise.all([ + this.dictionary.importKanjiDict('bg/data/kanjidic/index.json'), this.dictionary.importTermDict('bg/data/edict/index.json'), this.dictionary.importTermDict('bg/data/enamdict/index.json') ]); From a5440348b5e3aac04ad24e8fdfb947a04a5c210f Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Wed, 24 Aug 2016 09:16:02 -0700 Subject: [PATCH 10/51] . --- .gitattributes | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitattributes b/.gitattributes index c891610e..74ed3a99 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,4 +1,3 @@ -ext/bg/data/*dic* filter=lfs diff=lfs merge=lfs -text ext/bg/data/edict/*.json filter=lfs diff=lfs merge=lfs -text ext/bg/data/enamdict/*.json filter=lfs diff=lfs merge=lfs -text ext/bg/data/kanjidic/*.json filter=lfs diff=lfs merge=lfs -text From 1483dd4f09d4087bb13b270083a316f8bc64b34b Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Wed, 24 Aug 2016 09:23:56 -0700 Subject: [PATCH 11/51] Updating README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5eb26c61..07d7de63 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,8 @@ Store](https://chrome.google.com/webstore/detail/yomichan/ogmnaimimemjmbakcfefmn helpful and appreciate the time that was spent developing it, I would kindly ask that you leave a positive review. Your support and feedback encourages continued development of this tool. +[![Chrome web store](https://foosoft.net/projects/yomichan-chrome/img/store.png)](https://chrome.google.com/webstore/detail/yomichan/ogmnaimimemjmbakcfefmnahgdfhfami) + ## Usage ## Yomichan can be used as a standalone extension, or in conjunction with [Anki](http://ankisrs.net) via @@ -52,7 +54,7 @@ Yomichan can be used as a standalone extension, or in conjunction with [Anki](ht ### Anki Integration ### -1. Open the *Install Add-on* dialog by the selecting *Tools* > *Add-ons* > *Browse & Install* in Anki. +1. Open the *Install Add-on* dialog by selecting *Tools* > *Add-ons* > *Browse & Install* in Anki. 2. Input *2055492159* into the text box labeled *Code* and press the *OK* button to proceed. 3. Restart Anki when prompted to do so in order to complete the installation of AnkiConnect. 4. In Chrome, open the Yomichan options page by right-clicking the ![](https://foosoft.net/projects/yomichan-chrome/img/logo.png) icon and selecting *Options*. From 9462bc397b45aef0034f5ef8d11294125198581b Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Sun, 28 Aug 2016 21:02:51 -0700 Subject: [PATCH 12/51] Cleanup --- ext/bg/js/dictionary.js | 11 ++--------- ext/bg/js/translator.js | 16 ++++++++-------- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/ext/bg/js/dictionary.js b/ext/bg/js/dictionary.js index 4baa41c8..b7b7039c 100644 --- a/ext/bg/js/dictionary.js +++ b/ext/bg/js/dictionary.js @@ -28,21 +28,14 @@ class Dictionary { } initDb() { + this.entities = null; + this.db = new Dexie('dict'); this.db.version(1).stores({ terms: '++id,expression,reading', entities: '++,name', kanji: '++,character' }); - - return this.db; - } - - loadDb() { - this.db = null; - this.entities = null; - - return this.initDb().open(); } findTerm(term) { diff --git a/ext/bg/js/translator.js b/ext/bg/js/translator.js index d1a92d08..f7dfae13 100644 --- a/ext/bg/js/translator.js +++ b/ext/bg/js/translator.js @@ -38,16 +38,16 @@ class Translator { this.tagMeta = tagMeta; return this.dictionary.existsDb(); }).then((exists) => { + this.dictionary.initDb(); if (exists) { - return this.dictionary.loadDb(); - } else { - this.dictionary.initDb(); - return Promise.all([ - this.dictionary.importKanjiDict('bg/data/kanjidic/index.json'), - this.dictionary.importTermDict('bg/data/edict/index.json'), - this.dictionary.importTermDict('bg/data/enamdict/index.json') - ]); + return Promise.resolve(); } + + return Promise.all([ + this.dictionary.importKanjiDict('bg/data/kanjidic/index.json'), + this.dictionary.importTermDict('bg/data/edict/index.json'), + this.dictionary.importTermDict('bg/data/enamdict/index.json') + ]); }).then(() => { this.dictionary.findTerm('猫').then((result) => { console.log(result); From c55ba3b2be267d9dc616bda1a293d136c63cd639 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Mon, 29 Aug 2016 19:51:37 -0700 Subject: [PATCH 13/51] WIP --- ext/bg/js/dictionary.js | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/ext/bg/js/dictionary.js b/ext/bg/js/dictionary.js index b7b7039c..7cfa58a8 100644 --- a/ext/bg/js/dictionary.js +++ b/ext/bg/js/dictionary.js @@ -19,8 +19,8 @@ class Dictionary { constructor() { - this.db = null; this.entities = null; + this.db = new Dexie('dict'); } existsDb() { @@ -29,8 +29,6 @@ class Dictionary { initDb() { this.entities = null; - - this.db = new Dexie('dict'); this.db.version(1).stores({ terms: '++id,expression,reading', entities: '++,name', @@ -46,11 +44,16 @@ class Dictionary { reading: row.reading, tags: row.tags.split(' '), glossary: row.glossary, - entities: this.entities, id: row.id }); }).then(() => { - return Promise.resolve(results); + return this.getEntities(); + }).then((entities) => { + for (const result of results) { + result.entities = entities; + } + + return results; }); } @@ -67,9 +70,9 @@ class Dictionary { }); } - getEntities() { + getEntities(tags) { if (this.entities !== null) { - return Promise.resolve(this.entities); + return this.entities; } return this.db.entities.toArray((rows) => { @@ -77,8 +80,8 @@ class Dictionary { for (const row of rows) { this.entities[row.name] = row.value; } - }).then(() => { - return Promise.resolve(this.entities); + + return this.entities; }); } From 133abb6f585bee94fcdee23689779042e3ccfd65 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Mon, 29 Aug 2016 20:27:04 -0700 Subject: [PATCH 14/51] . --- ext/bg/js/translator.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/ext/bg/js/translator.js b/ext/bg/js/translator.js index f7dfae13..5768c3d6 100644 --- a/ext/bg/js/translator.js +++ b/ext/bg/js/translator.js @@ -31,13 +31,13 @@ class Translator { return; } - loadJson('bg/data/rules.json').then((rules) => { + loadJson('bg/data/rules.json').then(rules => { this.deinflector.setRules(rules); return loadJson('bg/data/tags.json'); - }).then((tagMeta) => { + }).then(tagMeta => { this.tagMeta = tagMeta; return this.dictionary.existsDb(); - }).then((exists) => { + }).then(exists => { this.dictionary.initDb(); if (exists) { return Promise.resolve(); @@ -49,10 +49,6 @@ class Translator { this.dictionary.importTermDict('bg/data/enamdict/index.json') ]); }).then(() => { - this.dictionary.findTerm('猫').then((result) => { - console.log(result); - }); - this.loaded = true; callback(); }); From 05ac93128539cf4be5417a50728329c3ae070580 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Sat, 10 Sep 2016 18:57:00 -0700 Subject: [PATCH 15/51] Work on deinflector --- ext/bg/js/deinflector.js | 54 +++++++++++++++++++++++----------------- ext/bg/js/translator.js | 8 +++--- 2 files changed, 35 insertions(+), 27 deletions(-) diff --git a/ext/bg/js/deinflector.js b/ext/bg/js/deinflector.js index 0eabd0f3..2d567e6b 100644 --- a/ext/bg/js/deinflector.js +++ b/ext/bg/js/deinflector.js @@ -26,26 +26,30 @@ class Deinflection { } validate(validator) { - for (const tags of validator(this.term)) { - if (this.tags.length === 0) { - return true; - } - - for (const tag of this.tags) { - if (tags.indexOf(tag) !== -1) { + return validator(this.term).then(tagSets => { + for (const tags of tagSets) { + if (this.tags.length === 0) { return true; } - } - } - return false; + for (const tag of this.tags) { + if (tags.indexOf(tag) !== -1) { + return true; + } + } + } + + return false; + }); } deinflect(validator, rules) { - if (this.validate(validator)) { - const child = new Deinflection(this.term, this.tags); - this.children.push(child); - } + const promises = [ + this.validate(validator).then(valid => { + const child = new Deinflection(this.term, this.tags); + this.children.push(child); + }) + ]; for (const rule in rules) { for (const variant of rules[rule]) { @@ -63,13 +67,19 @@ class Deinflection { const term = this.term.slice(0, -variant.ki.length) + variant.ko; const child = new Deinflection(term, variant.to, rule); - if (child.deinflect(validator, rules)) { - this.children.push(child); - } + promises.push( + child.deinflect(validator, rules).then(valid => { + if (valid) { + this.children.push(child); + } + } + )); } } - return this.children.length > 0; + return Promise.all(promises).then(() => { + return this.children.length > 0; + }); } gather() { @@ -105,10 +115,8 @@ class Deinflector { deinflect(term, validator) { const node = new Deinflection(term); - if (node.deinflect(validator, this.rules)) { - return node.gather(); - } - - return null; + return node.deinflect(validator, this.rules).then(success => { + return success ? node.gather() : null; + }); } } diff --git a/ext/bg/js/translator.js b/ext/bg/js/translator.js index 5768c3d6..8938162a 100644 --- a/ext/bg/js/translator.js +++ b/ext/bg/js/translator.js @@ -59,12 +59,12 @@ class Translator { for (let i = text.length; i > 0; --i) { const term = text.slice(0, i); const dfs = this.deinflector.deinflect(term, t => { - const tags = []; + const tagSets = []; for (const d of this.dictionary.findTerm(t)) { - tags.push(d.tags); + tagSets.push(d.tags); } - return tags; + return tagSets; }); if (dfs === null) { @@ -114,7 +114,7 @@ class Translator { length = Math.max(length, result.source.length); } - return {definitions: definitions, length: length}; + return {definitions, length}; } findKanji(text) { From fa391bd5d366ec06d816905abde6ca0a1d4d7791 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Sat, 10 Sep 2016 19:36:28 -0700 Subject: [PATCH 16/51] WIP --- ext/bg/js/translator.js | 188 ++++++++++++++++++++-------------------- 1 file changed, 95 insertions(+), 93 deletions(-) diff --git a/ext/bg/js/translator.js b/ext/bg/js/translator.js index 8938162a..dcc2e5ac 100644 --- a/ext/bg/js/translator.js +++ b/ext/bg/js/translator.js @@ -54,67 +54,67 @@ class Translator { }); } - findTerm(text) { + findTermGroups(text) { const groups = {}; + const promises = []; + for (let i = text.length; i > 0; --i) { - const term = text.slice(0, i); - const dfs = this.deinflector.deinflect(term, t => { - const tagSets = []; - for (const d of this.dictionary.findTerm(t)) { - tagSets.push(d.tags); + promises.append( + this.deinflector.deinflect(text.slice(0, i), term => { + return this.dictionary.findTerm(term).then(definitions => definitions.map(def => def.tags)); + }).then(inflects => { + for (const inflect of inflects || []) { + this.processTerm(groups, df.source, df.tags, df.rules, df.root); + } + }) + ); + } + + return Promise.all(promises).then(Promise.resolve(groups)); + } + + findTerm(text) { + return this.findTermGroups(text).then(groups => { + let definitions = []; + for (const key in groups) { + definitions.push(groups[key]); + } + + definitions = definitions.sort((v1, v2) => { + const sl1 = v1.source.length; + const sl2 = v2.source.length; + if (sl1 > sl2) { + return -1; + } else if (sl1 < sl2) { + return 1; } - return tagSets; + const s1 = v1.score; + const s2 = v2.score; + if (s1 > s2) { + return -1; + } else if (s1 < s2) { + return 1; + } + + const rl1 = v1.rules.length; + const rl2 = v2.rules.length; + if (rl1 < rl2) { + return -1; + } else if (rl1 > rl2) { + return 1; + } + + return v2.expression.localeCompare(v1.expression); }); - if (dfs === null) { - continue; + let length = 0; + for (const result of definitions) { + length = Math.max(length, result.source.length); } - for (const df of dfs) { - this.processTerm(groups, df.source, df.tags, df.rules, df.root); - } - } - - let definitions = []; - for (const key in groups) { - definitions.push(groups[key]); - } - - definitions = definitions.sort((v1, v2) => { - const sl1 = v1.source.length; - const sl2 = v2.source.length; - if (sl1 > sl2) { - return -1; - } else if (sl1 < sl2) { - return 1; - } - - const s1 = v1.score; - const s2 = v2.score; - if (s1 > s2) { - return -1; - } else if (s1 < s2) { - return 1; - } - - const rl1 = v1.rules.length; - const rl2 = v2.rules.length; - if (rl1 < rl2) { - return -1; - } else if (rl1 > rl2) { - return 1; - } - - return v2.expression.localeCompare(v1.expression); + return {definitions, length}; }); - - let length = 0; - for (const result of definitions) { - length = Math.max(length, result.source.length); - } - - return {definitions, length}; } findKanji(text) { @@ -132,52 +132,54 @@ class Translator { } processTerm(groups, source, tags, rules, root) { - for (const entry of this.dictionary.findTerm(root)) { - if (entry.id in groups) { - continue; - } - - let matched = tags.length === 0; - for (const tag of tags) { - if (entry.tags.indexOf(tag) !== -1) { - matched = true; - break; + return this.dictionary.findTerm(root).then(definitions => { + for (const definition of definitions) { + if (definition.id in groups) { + continue; } - } - if (!matched) { - continue; - } + let matched = tags.length === 0; + for (const tag of tags) { + if (definition.tags.indexOf(tag) !== -1) { + matched = true; + break; + } + } - const tagItems = []; - for (const tag of entry.tags) { - const tagItem = { - name: tag, - class: 'default', - order: Number.MAX_SAFE_INTEGER, - score: 0, - desc: entry.entities[tag] || '', + if (!matched) { + continue; + } + + const tagItems = []; + for (const tag of definition.tags) { + const tagItem = { + name: tag, + class: 'default', + order: Number.MAX_SAFE_INTEGER, + score: 0, + desc: definition.entities[tag] || '', + }; + + this.applyTagMeta(tagItem); + tagItems.push(tagItem); + } + + let score = 0; + for (const tagItem of tagItems) { + score += tagItem.score; + } + + groups[definition.id] = { + score, + source, + rules, + expression: definition.expression, + reading: definition.reading, + glossary: definition.glossary, + tags: Translator.sortTags(tagItems) }; - - this.applyTagMeta(tagItem); - tagItems.push(tagItem); } - - let score = 0; - for (const tagItem of tagItems) { - score += tagItem.score; - } - - groups[entry.id] = { - score, - source, - rules, - expression: entry.expression, - reading: entry.reading, - glossary: entry.glossary, - tags: Translator.sortTags(tagItems) - }; - } + }); } processKanji(entries) { From 47ef617eb4d951233d43c8da6e13a8bd2e40a863 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Sat, 10 Sep 2016 19:40:56 -0700 Subject: [PATCH 17/51] Cleanup --- ext/bg/js/dictionary.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/ext/bg/js/dictionary.js b/ext/bg/js/dictionary.js index 7cfa58a8..624fe15e 100644 --- a/ext/bg/js/dictionary.js +++ b/ext/bg/js/dictionary.js @@ -38,7 +38,7 @@ class Dictionary { findTerm(term) { const results = []; - return this.db.terms.where('expression').equals(term).or('reading').equals(term).each((row) => { + return this.db.terms.where('expression').equals(term).or('reading').equals(term).each(row => { results.push({ expression: row.expression, reading: row.reading, @@ -48,7 +48,7 @@ class Dictionary { }); }).then(() => { return this.getEntities(); - }).then((entities) => { + }).then(entities => { for (const result of results) { result.entities = entities; } @@ -59,7 +59,7 @@ class Dictionary { findKanji(kanji) { const results = []; - return this.db.kanji.where('c').equals(kanji).each((row) => { + return this.db.kanji.where('c').equals(kanji).each(row => { results.push({ character: row.c, onyomi: row.o.split(' '), @@ -75,7 +75,7 @@ class Dictionary { return this.entities; } - return this.db.entities.toArray((rows) => { + return this.db.entities.toArray(rows => { this.entities = {}; for (const row of rows) { this.entities[row.name] = row.value; @@ -88,7 +88,7 @@ class Dictionary { importTermDict(indexUrl) { const indexDir = indexUrl.slice(0, indexUrl.lastIndexOf('/')); - return loadJson(indexUrl).then((index) => { + return loadJson(indexUrl).then(index => { const entities = []; for (const [name, value] of index.ents) { entities.push({name, value}); @@ -107,9 +107,9 @@ class Dictionary { for (let i = 1; i <= index.banks; ++i) { const bankUrl = `${indexDir}/bank_${i}.json`; loaders.push(() => { - return loadJson(bankUrl).then((defs) => { + return loadJson(bankUrl).then(definitions => { const rows = []; - for (const [expression, reading, tags, ...glossary] of defs) { + for (const [expression, reading, tags, ...glossary] of definitions) { rows.push({expression, reading, tags, glossary}); } @@ -131,14 +131,14 @@ class Dictionary { importKanjiDict(indexUrl) { const indexDir = indexUrl.slice(0, indexUrl.lastIndexOf('/')); - return loadJson(indexUrl).then((index) => { + return loadJson(indexUrl).then(index => { const loaders = []; for (let i = 1; i <= index.banks; ++i) { const bankUrl = `${indexDir}/bank_${i}.json`; loaders.push(() => { - return loadJson(bankUrl).then((defs) => { + return loadJson(bankUrl).then(definitions => { const rows = []; - for (const [character, onyomi, kunyomi, tags, ...meanings] of defs) { + for (const [character, onyomi, kunyomi, tags, ...meanings] of definitions) { rows.push({character, onyomi, kunyomi, tags, meanings}); } From 058739988302513c8496e569cf3a4fd1eb5920b4 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Sat, 10 Sep 2016 19:44:54 -0700 Subject: [PATCH 18/51] WIP --- ext/bg/js/deinflector.js | 2 +- ext/bg/js/translator.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/bg/js/deinflector.js b/ext/bg/js/deinflector.js index 2d567e6b..4cdc9a3d 100644 --- a/ext/bg/js/deinflector.js +++ b/ext/bg/js/deinflector.js @@ -116,7 +116,7 @@ class Deinflector { deinflect(term, validator) { const node = new Deinflection(term); return node.deinflect(validator, this.rules).then(success => { - return success ? node.gather() : null; + return success ? node.gather() : []; }); } } diff --git a/ext/bg/js/translator.js b/ext/bg/js/translator.js index dcc2e5ac..ccf1876f 100644 --- a/ext/bg/js/translator.js +++ b/ext/bg/js/translator.js @@ -63,7 +63,7 @@ class Translator { this.deinflector.deinflect(text.slice(0, i), term => { return this.dictionary.findTerm(term).then(definitions => definitions.map(def => def.tags)); }).then(inflects => { - for (const inflect of inflects || []) { + for (const inflect of inflects) { this.processTerm(groups, df.source, df.tags, df.rules, df.root); } }) From 3ec57d5bf658c247835fc933c2c41ea4e5ea52f6 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Sat, 10 Sep 2016 22:25:16 -0700 Subject: [PATCH 19/51] Fixes --- ext/bg/js/translator.js | 10 ++++++++-- ext/bg/js/yomichan.js | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/ext/bg/js/translator.js b/ext/bg/js/translator.js index ccf1876f..6c028c5c 100644 --- a/ext/bg/js/translator.js +++ b/ext/bg/js/translator.js @@ -59,12 +59,18 @@ class Translator { const promises = []; for (let i = text.length; i > 0; --i) { - promises.append( + promises.push( this.deinflector.deinflect(text.slice(0, i), term => { return this.dictionary.findTerm(term).then(definitions => definitions.map(def => def.tags)); }).then(inflects => { for (const inflect of inflects) { - this.processTerm(groups, df.source, df.tags, df.rules, df.root); + this.processTerm( + groups, + inflect.source, + inflect.tags, + inflect.rules, + inflect.root + ); } }) ); diff --git a/ext/bg/js/yomichan.js b/ext/bg/js/yomichan.js index 716c622a..557f8780 100644 --- a/ext/bg/js/yomichan.js +++ b/ext/bg/js/yomichan.js @@ -297,7 +297,7 @@ class Yomichan { } api_findTerm({text, callback}) { - callback(this.translator.findTerm(text)); + this.translator.findTerm(text).then((result) => callback(result)); } api_getDeckNames({callback}) { From 64d6b8761d512ca608e1d1aedc14bebd3581283f Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Sat, 10 Sep 2016 22:35:31 -0700 Subject: [PATCH 20/51] WIP --- ext/bg/js/translator.js | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/ext/bg/js/translator.js b/ext/bg/js/translator.js index 6c028c5c..9987f820 100644 --- a/ext/bg/js/translator.js +++ b/ext/bg/js/translator.js @@ -56,27 +56,24 @@ class Translator { findTermGroups(text) { const groups = {}; - const promises = []; + const deinflectPromises = []; for (let i = text.length; i > 0; --i) { - promises.push( + deinflectPromises.push( this.deinflector.deinflect(text.slice(0, i), term => { - return this.dictionary.findTerm(term).then(definitions => definitions.map(def => def.tags)); + return this.dictionary.findTerm(term).then(definitions => definitions.map(definition => definition.tags)); }).then(inflects => { + const processPromises = []; for (const inflect of inflects) { - this.processTerm( - groups, - inflect.source, - inflect.tags, - inflect.rules, - inflect.root - ); + processPromises.push(this.processTerm(groups, inflect.source, inflect.tags, inflect.rules, inflect.root)); } + + return Promise.all(processPromises); }) ); } - return Promise.all(promises).then(Promise.resolve(groups)); + return Promise.all(deinflectPromises).then(Promise.resolve(groups)); } findTerm(text) { From 1ac14cd633b3a99a3dd8ec8d0ec29158077b3798 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Sat, 10 Sep 2016 22:51:04 -0700 Subject: [PATCH 21/51] WIP --- ext/bg/js/translator.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/bg/js/translator.js b/ext/bg/js/translator.js index 9987f820..9b7b4bf5 100644 --- a/ext/bg/js/translator.js +++ b/ext/bg/js/translator.js @@ -73,7 +73,7 @@ class Translator { ); } - return Promise.all(deinflectPromises).then(Promise.resolve(groups)); + return Promise.all(deinflectPromises).then(() => groups); } findTerm(text) { From d5ea03171ea997d6734e6d31197c7f233fff7084 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Sun, 11 Sep 2016 12:29:18 -0700 Subject: [PATCH 22/51] Working with IndexDb --- ext/bg/js/deinflector.js | 12 +++++------- ext/bg/js/dictionary.js | 14 +++++++------- ext/bg/js/translator.js | 35 ++++++++++++++++++++++------------- ext/bg/js/yomichan.js | 18 +++++++++--------- 4 files changed, 43 insertions(+), 36 deletions(-) diff --git a/ext/bg/js/deinflector.js b/ext/bg/js/deinflector.js index 4cdc9a3d..e5b1efe5 100644 --- a/ext/bg/js/deinflector.js +++ b/ext/bg/js/deinflector.js @@ -26,14 +26,14 @@ class Deinflection { } validate(validator) { - return validator(this.term).then(tagSets => { - for (const tags of tagSets) { + return validator(this.term).then(sets => { + for (const tags of sets) { if (this.tags.length === 0) { return true; } for (const tag of this.tags) { - if (tags.indexOf(tag) !== -1) { + if (tags.includes(tag)) { return true; } } @@ -55,7 +55,7 @@ class Deinflection { for (const variant of rules[rule]) { let allowed = this.tags.length === 0; for (const tag of this.tags) { - if (variant.ti.indexOf(tag) !== -1) { + if (variant.ti.includes(tag)) { allowed = true; break; } @@ -115,8 +115,6 @@ class Deinflector { deinflect(term, validator) { const node = new Deinflection(term); - return node.deinflect(validator, this.rules).then(success => { - return success ? node.gather() : []; - }); + return node.deinflect(validator, this.rules).then(success => success ? node.gather() : []); } } diff --git a/ext/bg/js/dictionary.js b/ext/bg/js/dictionary.js index 624fe15e..0c5e4c4a 100644 --- a/ext/bg/js/dictionary.js +++ b/ext/bg/js/dictionary.js @@ -59,15 +59,15 @@ class Dictionary { findKanji(kanji) { const results = []; - return this.db.kanji.where('c').equals(kanji).each(row => { + return this.db.kanji.where('character').equals(kanji).each(row => { results.push({ - character: row.c, - onyomi: row.o.split(' '), - kunyomi: row.k.split(' '), - tags: row.t.split(' '), - glossary: row.m + character: row.character, + onyomi: row.onyomi.split(' '), + kunyomi: row.kunyomi.split(' '), + tags: row.tags.split(' '), + glossary: row.meanings }); - }); + }).then(() => results); } getEntities(tags) { diff --git a/ext/bg/js/translator.js b/ext/bg/js/translator.js index 9b7b4bf5..6b08f485 100644 --- a/ext/bg/js/translator.js +++ b/ext/bg/js/translator.js @@ -55,17 +55,23 @@ class Translator { } findTermGroups(text) { - const groups = {}; - + const deinflectGroups = {}; const deinflectPromises = []; + for (let i = text.length; i > 0; --i) { deinflectPromises.push( this.deinflector.deinflect(text.slice(0, i), term => { return this.dictionary.findTerm(term).then(definitions => definitions.map(definition => definition.tags)); - }).then(inflects => { + }).then(deinflects => { const processPromises = []; - for (const inflect of inflects) { - processPromises.push(this.processTerm(groups, inflect.source, inflect.tags, inflect.rules, inflect.root)); + for (const deinflect of deinflects) { + processPromises.push(this.processTerm( + deinflectGroups, + deinflect.source, + deinflect.tags, + deinflect.rules, + deinflect.root + )); } return Promise.all(processPromises); @@ -73,14 +79,14 @@ class Translator { ); } - return Promise.all(deinflectPromises).then(() => groups); + return Promise.all(deinflectPromises).then(() => deinflectGroups); } findTerm(text) { - return this.findTermGroups(text).then(groups => { + return this.findTermGroups(text).then(deinflectGroups => { let definitions = []; - for (const key in groups) { - definitions.push(groups[key]); + for (const key in deinflectGroups) { + definitions.push(deinflectGroups[key]); } definitions = definitions.sort((v1, v2) => { @@ -121,17 +127,20 @@ class Translator { } findKanji(text) { - let definitions = []; const processed = {}; + const promises = []; for (const c of text) { if (!processed[c]) { - definitions = definitions.concat(this.dictionary.findKanji(c)); + promises.push(this.dictionary.findKanji(c).then((definitions) => definitions)); processed[c] = true; } } - return this.processKanji(definitions); + return Promise.all(promises).then((sets) => { + const definitions = sets.reduce((a, b) => a.concat(b)); + return this.processKanji(definitions); + }); } processTerm(groups, source, tags, rules, root) { @@ -143,7 +152,7 @@ class Translator { let matched = tags.length === 0; for (const tag of tags) { - if (definition.tags.indexOf(tag) !== -1) { + if (definition.tags.includes(tag)) { matched = true; break; } diff --git a/ext/bg/js/yomichan.js b/ext/bg/js/yomichan.js index 557f8780..11f348bf 100644 --- a/ext/bg/js/yomichan.js +++ b/ext/bg/js/yomichan.js @@ -41,10 +41,10 @@ class Yomichan { chrome.runtime.onInstalled.addListener(this.onInstalled.bind(this)); chrome.runtime.onMessage.addListener(this.onMessage.bind(this)); chrome.browserAction.onClicked.addListener(this.onBrowserAction.bind(this)); - chrome.tabs.onCreated.addListener((tab) => this.onTabReady(tab.id)); + chrome.tabs.onCreated.addListener(tab => this.onTabReady(tab.id)); chrome.tabs.onUpdated.addListener(this.onTabReady.bind(this)); - loadOptions((opts) => { + loadOptions(opts => { this.setOptions(opts); if (this.options.activateOnStartup) { this.setState('loading'); @@ -118,7 +118,7 @@ class Yomichan { } tabInvokeAll(action, params) { - chrome.tabs.query({}, (tabs) => { + chrome.tabs.query({}, tabs => { for (const tab of tabs) { this.tabInvoke(tab.id, action, params); } @@ -133,7 +133,7 @@ class Yomichan { if (this.ankiConnectVer === this.getApiVersion()) { this.ankiInvoke(action, params, pool, callback); } else { - this.api_getVersion({callback: (version) => { + this.api_getVersion({callback: version => { if (version === this.getApiVersion()) { this.ankiConnectVer = version; this.ankiInvoke(action, params, pool, callback); @@ -209,7 +209,7 @@ class Yomichan { break; case 'tags': if (definition.tags) { - value = definition.tags.map((t) => t.name); + value = definition.tags.map(t => t.name); } break; } @@ -244,7 +244,7 @@ class Yomichan { }; for (const name in fields) { - if (fields[name].indexOf('{audio}') !== -1) { + if (fields[name].includes('{audio}')) { audio.fields.push(name); } } @@ -274,7 +274,7 @@ class Yomichan { } } - this.ankiInvokeSafe('canAddNotes', {notes}, 'notes', (results) => { + this.ankiInvokeSafe('canAddNotes', {notes}, 'notes', results => { const states = []; if (results !== null) { @@ -293,11 +293,11 @@ class Yomichan { } api_findKanji({text, callback}) { - callback(this.translator.findKanji(text)); + this.translator.findKanji(text).then(result => callback(result)); } api_findTerm({text, callback}) { - this.translator.findTerm(text).then((result) => callback(result)); + this.translator.findTerm(text).then(result => callback(result)); } api_getDeckNames({callback}) { From 8eb43c93d920fb6d940cba2c1f46a9876d9087e9 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Sun, 11 Sep 2016 12:40:45 -0700 Subject: [PATCH 23/51] Cleanup --- ext/bg/js/translator.js | 40 ++++++++++++++-------------------------- ext/bg/js/yomichan.js | 2 +- 2 files changed, 15 insertions(+), 27 deletions(-) diff --git a/ext/bg/js/translator.js b/ext/bg/js/translator.js index 6b08f485..e18d5a3b 100644 --- a/ext/bg/js/translator.js +++ b/ext/bg/js/translator.js @@ -25,13 +25,12 @@ class Translator { this.deinflector = new Deinflector(); } - loadData({loadEnamDict=true}, callback) { + loadData() { if (this.loaded) { - callback(); - return; + return Promise.resolve(); } - loadJson('bg/data/rules.json').then(rules => { + return loadJson('bg/data/rules.json').then(rules => { this.deinflector.setRules(rules); return loadJson('bg/data/tags.json'); }).then(tagMeta => { @@ -39,18 +38,15 @@ class Translator { return this.dictionary.existsDb(); }).then(exists => { this.dictionary.initDb(); - if (exists) { - return Promise.resolve(); + if (!exists) { + return Promise.all([ + this.dictionary.importKanjiDict('bg/data/kanjidic/index.json'), + this.dictionary.importTermDict('bg/data/edict/index.json'), + this.dictionary.importTermDict('bg/data/enamdict/index.json') + ]); } - - return Promise.all([ - this.dictionary.importKanjiDict('bg/data/kanjidic/index.json'), - this.dictionary.importTermDict('bg/data/edict/index.json'), - this.dictionary.importTermDict('bg/data/enamdict/index.json') - ]); }).then(() => { this.loaded = true; - callback(); }); } @@ -194,12 +190,10 @@ class Translator { }); } - processKanji(entries) { - const results = []; - - for (const entry of entries) { + processKanji(definitions) { + for (const definition of definitions) { const tagItems = []; - for (const tag of entry.tags) { + for (const tag of definition.tags) { const tagItem = { name: tag, class: 'default', @@ -211,16 +205,10 @@ class Translator { tagItems.push(tagItem); } - results.push({ - character: entry.character, - kunyomi: entry.kunyomi, - onyomi: entry.onyomi, - glossary: entry.glossary, - tags: Translator.sortTags(tagItems) - }); + definition.tags = Translator.sortTags(tagItems); } - return results; + return definitions; } applyTagMeta(tag) { diff --git a/ext/bg/js/yomichan.js b/ext/bg/js/yomichan.js index 11f348bf..d9d4234d 100644 --- a/ext/bg/js/yomichan.js +++ b/ext/bg/js/yomichan.js @@ -101,7 +101,7 @@ class Yomichan { break; case 'loading': chrome.browserAction.setBadgeText({text: '...'}); - this.translator.loadData({loadEnamDict: this.options.loadEnamDict}, () => this.setState('enabled')); + this.translator.loadData().then(() => this.setState('enabled')); break; } From 94dccfd875bf0ef1ec0d732b548b94a5811491f3 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Sun, 11 Sep 2016 12:48:53 -0700 Subject: [PATCH 24/51] WIP --- ext/bg/js/translator.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ext/bg/js/translator.js b/ext/bg/js/translator.js index e18d5a3b..b8cad6de 100644 --- a/ext/bg/js/translator.js +++ b/ext/bg/js/translator.js @@ -133,10 +133,7 @@ class Translator { } } - return Promise.all(promises).then((sets) => { - const definitions = sets.reduce((a, b) => a.concat(b)); - return this.processKanji(definitions); - }); + return Promise.all(promises).then(sets => this.processKanji(sets.reduce((a, b) => a.concat(b)))); } processTerm(groups, source, tags, rules, root) { From 6183864f164a44bcb24e98ad2150ac9aafe371d3 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Sun, 11 Sep 2016 19:47:40 -0700 Subject: [PATCH 25/51] Cleanup --- ext/fg/js/client.js | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/ext/fg/js/client.js b/ext/fg/js/client.js index 628d5b30..ebfb1090 100644 --- a/ext/fg/js/client.js +++ b/ext/fg/js/client.js @@ -23,6 +23,7 @@ class Client { this.audio = {}; this.lastMousePos = null; this.lastTextSource = null; + this.pendingLookup = false; this.activateKey = 16; this.activateBtn = 2; this.enabled = false; @@ -36,8 +37,8 @@ class Client { window.addEventListener('mousedown', this.onMouseDown.bind(this)); window.addEventListener('mousemove', this.onMouseMove.bind(this)); window.addEventListener('keydown', this.onKeyDown.bind(this)); - window.addEventListener('scroll', (e) => this.hidePopup()); - window.addEventListener('resize', (e) => this.hidePopup()); + window.addEventListener('scroll', e => this.hidePopup()); + window.addEventListener('resize', e => this.hidePopup()); } onKeyDown(e) { @@ -89,11 +90,16 @@ class Client { return; } + if (this.pendingLookup) { + return; + } + textSource.setEndOffset(this.options.scanLength); let defs = []; let seq = -1; + this.pendingLookup = true; bgFindTerm(textSource.text()) .then(({definitions, length}) => { if (length === 0) { @@ -103,7 +109,7 @@ class Client { textSource.setEndOffset(length); const sentence = Client.extractSentence(textSource, this.options.sentenceExtent); - definitions.forEach((definition) => { + definitions.forEach(definition => { definition.url = window.location.href; definition.sentence = sentence; }); @@ -113,17 +119,21 @@ class Client { return bgRenderText({definitions, root: this.fgRoot, options: this.options, sequence: seq}, 'term-list.html'); }) - .then((content) => { + .then(content => { this.definitions = defs; this.showPopup(textSource, content); return bgCanAddDefinitions(defs, ['term_kanji', 'term_kana']); }) - .then((states) => { + .then(states => { + this.pendingLookup = false; if (states !== null) { states.forEach((state, index) => this.popup.sendMessage('setActionState', {index, state, sequence: seq})); } - }, () => this.hidePopup()); + }, () => { + this.pendingLookup = false; + this.hidePopup(); + }); } showPopup(textSource, content) { @@ -159,7 +169,7 @@ class Client { api_addNote({index, mode}) { const state = {[mode]: false}; - bgAddDefinition(this.definitions[index], mode).then((success) => { + bgAddDefinition(this.definitions[index], mode).then(success => { if (success) { this.popup.sendMessage('setActionState', {index, state, sequence: this.sequence}); } else { @@ -192,21 +202,21 @@ class Client { let seq = -1; bgFindKanji(kanji) - .then((definitions) => { - definitions.forEach((definition) => definition.url = window.location.href); + .then(definitions => { + definitions.forEach(definition => definition.url = window.location.href); defs = definitions; seq = ++this.sequence; return bgRenderText({definitions, root: this.fgRoot, options: this.options, sequence: seq}, 'kanji-list.html'); }) - .then((content) => { + .then(content => { this.definitions = defs; this.popup.setContent(content, defs); return bgCanAddDefinitions(defs, ['kanji']); }) - .then((states) => { + .then(states => { if (states !== null) { states.forEach((state, index) => this.popup.sendMessage('setActionState', {index, state, sequence: seq})); } @@ -217,7 +227,7 @@ class Client { const element = document.elementFromPoint(point.x, point.y); if (element !== null) { const names = ['IMG', 'INPUT', 'BUTTON', 'TEXTAREA']; - if (names.indexOf(element.nodeName) !== -1) { + if (names.includes(element.nodeName)) { return new TextSourceElement(element); } } @@ -246,7 +256,7 @@ class Client { for (let i = position; i >= startPos; --i) { const c = content[i]; - if (quoteStack.length === 0 && (terminators.indexOf(c) !== -1 || c in quotesFwd)) { + if (quoteStack.length === 0 && (terminators.includes(c) || c in quotesFwd)) { startPos = i + 1; break; } @@ -265,7 +275,7 @@ class Client { const c = content[i]; if (quoteStack.length === 0) { - if (terminators.indexOf(c) !== -1) { + if (terminators.includes(c)) { endPos = i + 1; break; } From 8f776cf759c0572904afbed5fc168883e8d3324f Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Sun, 11 Sep 2016 20:18:34 -0700 Subject: [PATCH 26/51] Cleanup --- ext/fg/js/client.js | 92 ++++++++++++++++++--------------------------- 1 file changed, 37 insertions(+), 55 deletions(-) diff --git a/ext/fg/js/client.js b/ext/fg/js/client.js index ebfb1090..8f9fdc08 100644 --- a/ext/fg/js/client.js +++ b/ext/fg/js/client.js @@ -24,8 +24,6 @@ class Client { this.lastMousePos = null; this.lastTextSource = null; this.pendingLookup = false; - this.activateKey = 16; - this.activateBtn = 2; this.enabled = false; this.options = {}; this.definitions = null; @@ -42,21 +40,21 @@ class Client { } onKeyDown(e) { - if (this.enabled && this.lastMousePos !== null && (e.keyCode === this.activateKey || e.charCode === this.activateKey)) { + if (this.enabled && this.lastMousePos !== null && (e.keyCode === 16 || e.charCode === 16)) { this.searchAt(this.lastMousePos); } } onMouseMove(e) { this.lastMousePos = {x: e.clientX, y: e.clientY}; - if (this.enabled && (e.shiftKey || e.which === this.activateBtn)) { + if (this.enabled && (e.shiftKey || e.which === 2)) { this.searchAt(this.lastMousePos); } } onMouseDown(e) { this.lastMousePos = {x: e.clientX, y: e.clientY}; - if (this.enabled && (e.shiftKey || e.which === this.activateBtn)) { + if (this.enabled && (e.shiftKey || e.which === 2)) { this.searchAt(this.lastMousePos); } else { this.hidePopup(); @@ -80,6 +78,10 @@ class Client { } searchAt(point) { + if (this.pendingLookup) { + return; + } + const textSource = Client.textSourceFromPoint(point); if (textSource === null || !textSource.containsPoint(point)) { this.hidePopup(); @@ -90,22 +92,13 @@ class Client { return; } - if (this.pendingLookup) { - return; - } - textSource.setEndOffset(this.options.scanLength); - let defs = []; - let seq = -1; - this.pendingLookup = true; - bgFindTerm(textSource.text()) - .then(({definitions, length}) => { - if (length === 0) { - return Promise.reject(); - } - + bgFindTerm(textSource.text()).then(({definitions, length}) => { + if (length === 0) { + this.hidePopup(); + } else { textSource.setEndOffset(length); const sentence = Client.extractSentence(textSource, this.options.sentenceExtent); @@ -114,26 +107,18 @@ class Client { definition.sentence = sentence; }); - defs = definitions; - seq = ++this.sequence; - - return bgRenderText({definitions, root: this.fgRoot, options: this.options, sequence: seq}, 'term-list.html'); - }) - .then(content => { - this.definitions = defs; - this.showPopup(textSource, content); - - return bgCanAddDefinitions(defs, ['term_kanji', 'term_kana']); - }) - .then(states => { - this.pendingLookup = false; - if (states !== null) { - states.forEach((state, index) => this.popup.sendMessage('setActionState', {index, state, sequence: seq})); - } - }, () => { - this.pendingLookup = false; - this.hidePopup(); - }); + const sequence = ++this.sequence; + return bgRenderText({definitions, sequence, root: this.fgRoot, options: this.options}, 'term-list.html').then((content) => { + this.definitions = definitions; + this.showPopup(textSource, content); + return bgCanAddDefinitions(definitions, ['term_kanji', 'term_kana']); + }).then(states => { + if (states !== null) { + states.forEach((state, index) => this.popup.sendMessage('setActionState', {index, state, sequence })); + } + }); + } + }).then(() => this.pendingLookup = false); } showPopup(textSource, content) { @@ -201,26 +186,23 @@ class Client { let defs = []; let seq = -1; - bgFindKanji(kanji) - .then(definitions => { - definitions.forEach(definition => definition.url = window.location.href); + bgFindKanji(kanji).then(definitions => { + definitions.forEach(definition => definition.url = window.location.href); - defs = definitions; - seq = ++this.sequence; + defs = definitions; + seq = ++this.sequence; - return bgRenderText({definitions, root: this.fgRoot, options: this.options, sequence: seq}, 'kanji-list.html'); - }) - .then(content => { - this.definitions = defs; - this.popup.setContent(content, defs); + return bgRenderText({definitions, root: this.fgRoot, options: this.options, sequence: seq}, 'kanji-list.html'); + }).then(content => { + this.definitions = defs; + this.popup.setContent(content, defs); - return bgCanAddDefinitions(defs, ['kanji']); - }) - .then(states => { - if (states !== null) { - states.forEach((state, index) => this.popup.sendMessage('setActionState', {index, state, sequence: seq})); - } - }); + return bgCanAddDefinitions(defs, ['kanji']); + }).then(states => { + if (states !== null) { + states.forEach((state, index) => this.popup.sendMessage('setActionState', {index, state, sequence: seq})); + } + }); } static textSourceFromPoint(point) { From f653195aed4fe1ce12b771cb1e5de06d9e6f0253 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Sun, 11 Sep 2016 20:35:53 -0700 Subject: [PATCH 27/51] Cleanup --- ext/fg/js/client.js | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/ext/fg/js/client.js b/ext/fg/js/client.js index 8f9fdc08..266e4b5a 100644 --- a/ext/fg/js/client.js +++ b/ext/fg/js/client.js @@ -183,25 +183,19 @@ class Client { } api_displayKanji(kanji) { - let defs = []; - let seq = -1; - bgFindKanji(kanji).then(definitions => { definitions.forEach(definition => definition.url = window.location.href); - defs = definitions; - seq = ++this.sequence; - - return bgRenderText({definitions, root: this.fgRoot, options: this.options, sequence: seq}, 'kanji-list.html'); - }).then(content => { - this.definitions = defs; - this.popup.setContent(content, defs); - - return bgCanAddDefinitions(defs, ['kanji']); - }).then(states => { - if (states !== null) { - states.forEach((state, index) => this.popup.sendMessage('setActionState', {index, state, sequence: seq})); - } + const sequence = ++this.sequence; + return bgRenderText({definitions, sequence, root: this.fgRoot, options: this.options}, 'kanji-list.html').then(content => { + this.definitions = definitions; + this.popup.setContent(content, definitions); + return bgCanAddDefinitions(definitions, ['kanji']); + }).then(states => { + if (states !== null) { + states.forEach((state, index) => this.popup.sendMessage('setActionState', {index, state, sequence})); + } + }); }); } From fa446f540a3a93d51c457da661d61976bdd5cbdf Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Sun, 11 Sep 2016 20:41:41 -0700 Subject: [PATCH 28/51] WIP --- ext/fg/js/client.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ext/fg/js/client.js b/ext/fg/js/client.js index 266e4b5a..9a0ad25a 100644 --- a/ext/fg/js/client.js +++ b/ext/fg/js/client.js @@ -97,6 +97,7 @@ class Client { this.pendingLookup = true; bgFindTerm(textSource.text()).then(({definitions, length}) => { if (length === 0) { + this.pendingLookup = false; this.hidePopup(); } else { textSource.setEndOffset(length); @@ -108,8 +109,9 @@ class Client { }); const sequence = ++this.sequence; - return bgRenderText({definitions, sequence, root: this.fgRoot, options: this.options}, 'term-list.html').then((content) => { + return bgRenderText({definitions, sequence, root: this.fgRoot, options: this.options}, 'term-list.html').then(content => { this.definitions = definitions; + this.pendingLookup = false; this.showPopup(textSource, content); return bgCanAddDefinitions(definitions, ['term_kanji', 'term_kana']); }).then(states => { @@ -118,7 +120,7 @@ class Client { } }); } - }).then(() => this.pendingLookup = false); + }); } showPopup(textSource, content) { From f4314497e401e94ccd2ff88358b5720c73074612 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Sun, 11 Sep 2016 20:59:42 -0700 Subject: [PATCH 29/51] Cleanup --- ext/fg/js/api.js | 42 ---------------- ext/fg/js/client.js | 90 ++++------------------------------ ext/fg/js/frame.js | 6 +-- ext/fg/js/popup.js | 4 +- ext/fg/js/util.js | 114 ++++++++++++++++++++++++++++++++++++++++++++ ext/manifest.json | 2 +- 6 files changed, 129 insertions(+), 129 deletions(-) delete mode 100644 ext/fg/js/api.js create mode 100644 ext/fg/js/util.js diff --git a/ext/fg/js/api.js b/ext/fg/js/api.js deleted file mode 100644 index 643d0360..00000000 --- a/ext/fg/js/api.js +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2016 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 . - */ - - -function bgSendMessage(action, params) { - return new Promise((resolve, reject) => chrome.runtime.sendMessage({action, params}, resolve)); -} - -function bgFindTerm(text) { - return bgSendMessage('findTerm', {text}); -} - -function bgFindKanji(text) { - return bgSendMessage('findKanji', {text}); -} - -function bgRenderText(data, template) { - return bgSendMessage('renderText', {data, template}); -} - -function bgCanAddDefinitions(definitions, modes) { - return bgSendMessage('canAddDefinitions', {definitions, modes}); -} - -function bgAddDefinition(definition, mode) { - return bgSendMessage('addDefinition', {definition, mode}); -} diff --git a/ext/fg/js/client.js b/ext/fg/js/client.js index 9a0ad25a..daeabf99 100644 --- a/ext/fg/js/client.js +++ b/ext/fg/js/client.js @@ -82,7 +82,7 @@ class Client { return; } - const textSource = Client.textSourceFromPoint(point); + const textSource = textSourceFromPoint(point); if (textSource === null || !textSource.containsPoint(point)) { this.hidePopup(); return; @@ -95,25 +95,25 @@ class Client { textSource.setEndOffset(this.options.scanLength); this.pendingLookup = true; - bgFindTerm(textSource.text()).then(({definitions, length}) => { + findTerm(textSource.text()).then(({definitions, length}) => { if (length === 0) { this.pendingLookup = false; this.hidePopup(); } else { textSource.setEndOffset(length); - const sentence = Client.extractSentence(textSource, this.options.sentenceExtent); + const sentence = extractSentence(textSource, this.options.sentenceExtent); definitions.forEach(definition => { definition.url = window.location.href; definition.sentence = sentence; }); const sequence = ++this.sequence; - return bgRenderText({definitions, sequence, root: this.fgRoot, options: this.options}, 'term-list.html').then(content => { + return renderText({definitions, sequence, root: this.fgRoot, options: this.options}, 'term-list.html').then(content => { this.definitions = definitions; this.pendingLookup = false; this.showPopup(textSource, content); - return bgCanAddDefinitions(definitions, ['term_kanji', 'term_kana']); + return canAddDefinitions(definitions, ['term_kanji', 'term_kana']); }).then(states => { if (states !== null) { states.forEach((state, index) => this.popup.sendMessage('setActionState', {index, state, sequence })); @@ -156,7 +156,7 @@ class Client { api_addNote({index, mode}) { const state = {[mode]: false}; - bgAddDefinition(this.definitions[index], mode).then(success => { + addDefinition(this.definitions[index], mode).then(success => { if (success) { this.popup.sendMessage('setActionState', {index, state, sequence: this.sequence}); } else { @@ -185,14 +185,14 @@ class Client { } api_displayKanji(kanji) { - bgFindKanji(kanji).then(definitions => { + findKanji(kanji).then(definitions => { definitions.forEach(definition => definition.url = window.location.href); const sequence = ++this.sequence; - return bgRenderText({definitions, sequence, root: this.fgRoot, options: this.options}, 'kanji-list.html').then(content => { + return renderText({definitions, sequence, root: this.fgRoot, options: this.options}, 'kanji-list.html').then(content => { this.definitions = definitions; this.popup.setContent(content, definitions); - return bgCanAddDefinitions(definitions, ['kanji']); + return canAddDefinitions(definitions, ['kanji']); }).then(states => { if (states !== null) { states.forEach((state, index) => this.popup.sendMessage('setActionState', {index, state, sequence})); @@ -200,78 +200,6 @@ class Client { }); }); } - - static textSourceFromPoint(point) { - const element = document.elementFromPoint(point.x, point.y); - if (element !== null) { - const names = ['IMG', 'INPUT', 'BUTTON', 'TEXTAREA']; - if (names.includes(element.nodeName)) { - return new TextSourceElement(element); - } - } - - const range = document.caretRangeFromPoint(point.x, point.y); - if (range !== null) { - return new TextSourceRange(range); - } - - return null; - } - - static extractSentence(source, extent) { - const quotesFwd = {'「': '」', '『': '』', "'": "'", '"': '"'}; - const quotesBwd = {'」': '「', '』': '『', "'": "'", '"': '"'}; - const terminators = '…。..??!!'; - - const sourceLocal = source.clone(); - const position = sourceLocal.setStartOffset(extent); - sourceLocal.setEndOffset(position + extent); - const content = sourceLocal.text(); - - let quoteStack = []; - - let startPos = 0; - for (let i = position; i >= startPos; --i) { - const c = content[i]; - - if (quoteStack.length === 0 && (terminators.includes(c) || c in quotesFwd)) { - startPos = i + 1; - break; - } - - if (quoteStack.length > 0 && c === quoteStack[0]) { - quoteStack.pop(); - } else if (c in quotesBwd) { - quoteStack = [quotesBwd[c]].concat(quoteStack); - } - } - - quoteStack = []; - - let endPos = content.length; - for (let i = position; i < endPos; ++i) { - const c = content[i]; - - if (quoteStack.length === 0) { - if (terminators.includes(c)) { - endPos = i + 1; - break; - } - else if (c in quotesBwd) { - endPos = i; - break; - } - } - - if (quoteStack.length > 0 && c === quoteStack[0]) { - quoteStack.pop(); - } else if (c in quotesFwd) { - quoteStack = [quotesFwd[c]].concat(quoteStack); - } - } - - return content.substring(startPos, endPos).trim(); - } } window.yomiClient = new Client(); diff --git a/ext/fg/js/frame.js b/ext/fg/js/frame.js index 8f3d3877..30cb7c73 100644 --- a/ext/fg/js/frame.js +++ b/ext/fg/js/frame.js @@ -19,7 +19,7 @@ function registerKanjiLinks() { for (const link of Array.from(document.getElementsByClassName('kanji-link'))) { - link.addEventListener('click', (e) => { + link.addEventListener('click', e => { e.preventDefault(); window.parent.postMessage({action: 'displayKanji', params: e.target.innerHTML}, '*'); }); @@ -28,7 +28,7 @@ function registerKanjiLinks() { function registerAddNoteLinks() { for (const link of Array.from(document.getElementsByClassName('action-add-note'))) { - link.addEventListener('click', (e) => { + link.addEventListener('click', e => { e.preventDefault(); const ds = e.currentTarget.dataset; window.parent.postMessage({action: 'addNote', params: {index: ds.index, mode: ds.mode}}, '*'); @@ -38,7 +38,7 @@ function registerAddNoteLinks() { function registerAudioLinks() { for (const link of Array.from(document.getElementsByClassName('action-play-audio'))) { - link.addEventListener('click', (e) => { + link.addEventListener('click', e => { e.preventDefault(); const ds = e.currentTarget.dataset; window.parent.postMessage({action: 'playAudio', params: ds.index}, '*'); diff --git a/ext/fg/js/popup.js b/ext/fg/js/popup.js index a0eb725c..930df18d 100644 --- a/ext/fg/js/popup.js +++ b/ext/fg/js/popup.js @@ -81,8 +81,8 @@ class Popup { this.popup = document.createElement('iframe'); this.popup.id = 'yomichan-popup'; - this.popup.addEventListener('mousedown', (e) => e.stopPropagation()); - this.popup.addEventListener('scroll', (e) => e.stopPropagation()); + this.popup.addEventListener('mousedown', e => e.stopPropagation()); + this.popup.addEventListener('scroll', e => e.stopPropagation()); document.body.appendChild(this.popup); } diff --git a/ext/fg/js/util.js b/ext/fg/js/util.js new file mode 100644 index 00000000..176765fc --- /dev/null +++ b/ext/fg/js/util.js @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2016 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 . + */ + + +function sendMessage(action, params) { + return new Promise((resolve, reject) => chrome.runtime.sendMessage({action, params}, resolve)); +} + +function findTerm(text) { + return sendMessage('findTerm', {text}); +} + +function findKanji(text) { + return sendMessage('findKanji', {text}); +} + +function renderText(data, template) { + return sendMessage('renderText', {data, template}); +} + +function canAddDefinitions(definitions, modes) { + return sendMessage('canAddDefinitions', {definitions, modes}); +} + +function addDefinition(definition, mode) { + return sendMessage('addDefinition', {definition, mode}); +} + +function textSourceFromPoint(point) { + const element = document.elementFromPoint(point.x, point.y); + if (element !== null) { + const names = ['IMG', 'INPUT', 'BUTTON', 'TEXTAREA']; + if (names.includes(element.nodeName)) { + return new TextSourceElement(element); + } + } + + const range = document.caretRangeFromPoint(point.x, point.y); + if (range !== null) { + return new TextSourceRange(range); + } + + return null; +} + +function extractSentence(source, extent) { + const quotesFwd = {'「': '」', '『': '』', "'": "'", '"': '"'}; + const quotesBwd = {'」': '「', '』': '『', "'": "'", '"': '"'}; + const terminators = '…。..??!!'; + + const sourceLocal = source.clone(); + const position = sourceLocal.setStartOffset(extent); + sourceLocal.setEndOffset(position + extent); + const content = sourceLocal.text(); + + let quoteStack = []; + + let startPos = 0; + for (let i = position; i >= startPos; --i) { + const c = content[i]; + + if (quoteStack.length === 0 && (terminators.includes(c) || c in quotesFwd)) { + startPos = i + 1; + break; + } + + if (quoteStack.length > 0 && c === quoteStack[0]) { + quoteStack.pop(); + } else if (c in quotesBwd) { + quoteStack = [quotesBwd[c]].concat(quoteStack); + } + } + + quoteStack = []; + + let endPos = content.length; + for (let i = position; i < endPos; ++i) { + const c = content[i]; + + if (quoteStack.length === 0) { + if (terminators.includes(c)) { + endPos = i + 1; + break; + } + else if (c in quotesBwd) { + endPos = i; + break; + } + } + + if (quoteStack.length > 0 && c === quoteStack[0]) { + quoteStack.pop(); + } else if (c in quotesFwd) { + quoteStack = [quotesFwd[c]].concat(quoteStack); + } + } + + return content.substring(startPos, endPos).trim(); +} diff --git a/ext/manifest.json b/ext/manifest.json index 080f6f4f..c3864e10 100644 --- a/ext/manifest.json +++ b/ext/manifest.json @@ -15,7 +15,7 @@ "fg/js/source-range.js", "fg/js/source-element.js", "fg/js/popup.js", - "fg/js/api.js", + "fg/js/util.js", "fg/js/client.js" ], "css": ["fg/css/client.css"] From 4241b4f8595813b966371a02f5b2f35d7997b1e2 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Sun, 11 Sep 2016 22:47:08 -0700 Subject: [PATCH 30/51] WIP --- ext/bg/js/dictionary.js | 48 ++++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/ext/bg/js/dictionary.js b/ext/bg/js/dictionary.js index 0c5e4c4a..20a94f8f 100644 --- a/ext/bg/js/dictionary.js +++ b/ext/bg/js/dictionary.js @@ -19,24 +19,34 @@ class Dictionary { constructor() { + this.db = null; this.entities = null; + } + + initDb() { this.db = new Dexie('dict'); + this.db.version(1).stores({ + terms: '++id,expression,reading', + entities: '++,name', + kanji: '++,character' + }); + + this.entities = null; + } + + deleteDb() { + return this.db === null ? Promise.resolve() : this.db.delete(); } existsDb() { return Dexie.exists('dict'); } - initDb() { - this.entities = null; - this.db.version(1).stores({ - terms: '++id,expression,reading', - entities: '++,name', - kanji: '++,character' - }); - } - findTerm(term) { + if (this.db === null) { + return Promise.reject('database not initialized'); + } + const results = []; return this.db.terms.where('expression').equals(term).or('reading').equals(term).each(row => { results.push({ @@ -58,6 +68,10 @@ class Dictionary { } findKanji(kanji) { + if (this.db === null) { + return Promise.reject('database not initialized'); + } + const results = []; return this.db.kanji.where('character').equals(kanji).each(row => { results.push({ @@ -71,8 +85,12 @@ class Dictionary { } getEntities(tags) { + if (this.db === null) { + return Promise.reject('database not initialized'); + } + if (this.entities !== null) { - return this.entities; + return Promise.resolve(this.entities); } return this.db.entities.toArray(rows => { @@ -86,8 +104,11 @@ class Dictionary { } importTermDict(indexUrl) { - const indexDir = indexUrl.slice(0, indexUrl.lastIndexOf('/')); + if (this.db === null) { + return Promise.reject('database not initialized'); + } + const indexDir = indexUrl.slice(0, indexUrl.lastIndexOf('/')); return loadJson(indexUrl).then(index => { const entities = []; for (const [name, value] of index.ents) { @@ -129,8 +150,11 @@ class Dictionary { } importKanjiDict(indexUrl) { - const indexDir = indexUrl.slice(0, indexUrl.lastIndexOf('/')); + if (this.db === null) { + return Promise.reject('database not initialized'); + } + const indexDir = indexUrl.slice(0, indexUrl.lastIndexOf('/')); return loadJson(indexUrl).then(index => { const loaders = []; for (let i = 1; i <= index.banks; ++i) { From 540d0e239c9b7dc5bee8a3e53bcf6ec0767ee80b Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Mon, 12 Sep 2016 22:14:58 -0700 Subject: [PATCH 31/51] Cleanup --- ext/bg/js/util.js | 13 +++++++++++++ ext/bg/js/yomichan.js | 13 +------------ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/ext/bg/js/util.js b/ext/bg/js/util.js index 97906eda..5583502d 100644 --- a/ext/bg/js/util.js +++ b/ext/bg/js/util.js @@ -17,6 +17,19 @@ */ +function kanjiLinks(options) { + let result = ''; + for (const c of options.fn(this)) { + if (isKanji(c)) { + result += Handlebars.templates['kanji-link.html']({kanji: c}).trim(); + } else { + result += c; + } + } + + return result; +} + function loadJson(url) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); diff --git a/ext/bg/js/yomichan.js b/ext/bg/js/yomichan.js index d9d4234d..26b28138 100644 --- a/ext/bg/js/yomichan.js +++ b/ext/bg/js/yomichan.js @@ -20,18 +20,7 @@ class Yomichan { constructor() { Handlebars.partials = Handlebars.templates; - Handlebars.registerHelper('kanjiLinks', function(options) { - let result = ''; - for (const c of options.fn(this)) { - if (isKanji(c)) { - result += Handlebars.templates['kanji-link.html']({kanji: c}).trim(); - } else { - result += c; - } - } - - return result; - }); + Handlebars.registerHelper('kanjiLinks', kanjiLinks); this.translator = new Translator(); this.asyncPools = {}; From cd4f16c096746d13502dc7b258dfe16c97344ba1 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Tue, 13 Sep 2016 13:38:37 -0700 Subject: [PATCH 32/51] Options cleanup --- ext/bg/js/options-form.js | 27 +++++++++++++++------------ ext/bg/js/options.js | 8 ++++---- ext/bg/js/yomichan.js | 2 +- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/ext/bg/js/options-form.js b/ext/bg/js/options-form.js index 3dab0a87..a1ecccda 100644 --- a/ext/bg/js/options-form.js +++ b/ext/bg/js/options-form.js @@ -60,8 +60,8 @@ function modelIdToMarkers(id) { }[id]; } -function formToOptions(section, callback) { - loadOptions((optsOld) => { +function formToOptions(section) { + return loadOptions().then(optsOld => { const optsNew = $.extend({}, optsOld); switch (section) { @@ -86,7 +86,10 @@ function formToOptions(section, callback) { break; } - callback(sanitizeOptions(optsNew), sanitizeOptions(optsOld)); + return { + optsNew: sanitizeOptions(optsNew), + optsOld: sanitizeOptions(optsOld) + }; }); } @@ -185,8 +188,8 @@ function onOptionsGeneralChanged(e) { return; } - formToOptions('general', (optsNew, optsOld) => { - saveOptions(optsNew, () => { + formToOptions('general').then(({optsNew, optsOld}) => { + saveOptions(optsNew).then(() => { yomichan().setOptions(optsNew); if (!optsOld.enableAnkiConnect && optsNew.enableAnkiConnect) { updateAnkiStatus(); @@ -210,23 +213,23 @@ function onOptionsAnkiChanged(e) { return; } - formToOptions('anki', (opts) => { - saveOptions(opts, () => yomichan().setOptions(opts)); + formToOptions('anki').then(({optsNew, optsOld}) => { + saveOptions(optsNew).then(() => yomichan().setOptions(optsNew)); }); } function onAnkiModelChanged(e) { if (e.originalEvent) { - formToOptions('anki', (opts) => { - opts[modelIdToFieldOptKey($(this).id)] = {}; - populateAnkiFields($(this), opts); - saveOptions(opts, () => yomichan().setOptions(opts)); + formToOptions('anki').then(({optsNew, optsOld}) => { + optsNew[modelIdToFieldOptKey($(this).id)] = {}; + populateAnkiFields($(this), optsNew); + saveOptions(optsNew).then(() => yomichan().setOptions(optsNew)); }); } } $(document).ready(() => { - loadOptions((opts) => { + loadOptions().then(opts => { $('#scan-length').val(opts.scanLength); $('#activate-on-startup').prop('checked', opts.activateOnStartup); $('#load-enamdict').prop('checked', opts.loadEnamDict); diff --git a/ext/bg/js/options.js b/ext/bg/js/options.js index 831bb817..4c726730 100644 --- a/ext/bg/js/options.js +++ b/ext/bg/js/options.js @@ -45,10 +45,10 @@ function sanitizeOptions(options) { return options; } -function loadOptions(callback) { - chrome.storage.sync.get(null, (items) => callback(sanitizeOptions(items))); +function loadOptions() { + return new Promise((resolve, reject) => chrome.storage.sync.get(null, resolve)); } -function saveOptions(opts, callback) { - chrome.storage.sync.set(sanitizeOptions(opts), callback); +function saveOptions(opts) { + return new Promise((resolve, reject) => chrome.storage.sync.set(sanitizeOptions(opts), resolve)); } diff --git a/ext/bg/js/yomichan.js b/ext/bg/js/yomichan.js index 26b28138..10a42f47 100644 --- a/ext/bg/js/yomichan.js +++ b/ext/bg/js/yomichan.js @@ -33,7 +33,7 @@ class Yomichan { chrome.tabs.onCreated.addListener(tab => this.onTabReady(tab.id)); chrome.tabs.onUpdated.addListener(this.onTabReady.bind(this)); - loadOptions(opts => { + loadOptions().then(opts => { this.setOptions(opts); if (this.options.activateOnStartup) { this.setState('loading'); From 0e89d0e7e68d58407480e0e40e80c2f00f3c2f66 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Tue, 13 Sep 2016 15:59:18 -0700 Subject: [PATCH 33/51] Database stuff --- ext/bg/js/dictionary.js | 41 ++++++++++++++++++++++++++++++++++------- ext/bg/js/translator.js | 5 ++--- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/ext/bg/js/dictionary.js b/ext/bg/js/dictionary.js index 20a94f8f..936dc3c1 100644 --- a/ext/bg/js/dictionary.js +++ b/ext/bg/js/dictionary.js @@ -20,26 +20,53 @@ class Dictionary { constructor() { this.db = null; + this.dbVer = 1; this.entities = null; } initDb() { + if (this.db !== null) { + return Promise.reject('database already initialized'); + } + this.db = new Dexie('dict'); this.db.version(1).stores({ terms: '++id,expression,reading', entities: '++,name', - kanji: '++,character' + kanji: '++,character', + meta: 'name,value', }); - - this.entities = null; } - deleteDb() { - return this.db === null ? Promise.resolve() : this.db.delete(); + prepareDb() { + this.initDb(); + + return this.db.meta.get('version').then(row => { + return row ? row.value : 0; + }).catch(() => { + return 0; + }).then(version => { + if (this.dbVer === version) { + return true; + } + + const db = this.db; + this.db.close(); + this.db = null; + + return db.delete().then(() => { + this.initDb(); + return false; + }); + }); } - existsDb() { - return Dexie.exists('dict'); + sealDb() { + if (this.db === null) { + return Promise.reject('database not initialized'); + } + + return this.db.meta.put({name: 'version', value: this.dbVer}); } findTerm(term) { diff --git a/ext/bg/js/translator.js b/ext/bg/js/translator.js index b8cad6de..2cc97e1c 100644 --- a/ext/bg/js/translator.js +++ b/ext/bg/js/translator.js @@ -35,15 +35,14 @@ class Translator { return loadJson('bg/data/tags.json'); }).then(tagMeta => { this.tagMeta = tagMeta; - return this.dictionary.existsDb(); + return this.dictionary.prepareDb(); }).then(exists => { - this.dictionary.initDb(); if (!exists) { return Promise.all([ this.dictionary.importKanjiDict('bg/data/kanjidic/index.json'), this.dictionary.importTermDict('bg/data/edict/index.json'), this.dictionary.importTermDict('bg/data/enamdict/index.json') - ]); + ]).then(() => this.dictionary.sealDb()); } }).then(() => { this.loaded = true; From 17366e521afe2dd3b32f2068db43f972ce89b36f Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Tue, 13 Sep 2016 20:36:13 -0700 Subject: [PATCH 34/51] Progress callback for dictionary loading --- ext/bg/js/dictionary.js | 16 ++++++++++++---- ext/bg/js/translator.js | 38 +++++++++++++++++++++++++++++++------- 2 files changed, 43 insertions(+), 11 deletions(-) diff --git a/ext/bg/js/dictionary.js b/ext/bg/js/dictionary.js index 936dc3c1..2bd39344 100644 --- a/ext/bg/js/dictionary.js +++ b/ext/bg/js/dictionary.js @@ -130,7 +130,7 @@ class Dictionary { }); } - importTermDict(indexUrl) { + importTermDict(indexUrl, callback) { if (this.db === null) { return Promise.reject('database not initialized'); } @@ -161,7 +161,11 @@ class Dictionary { rows.push({expression, reading, tags, glossary}); } - return this.db.terms.bulkAdd(rows); + return this.db.terms.bulkAdd(rows).then(() => { + if (callback) { + callback(i, index.banks); + } + }); }); }); } @@ -176,7 +180,7 @@ class Dictionary { }); } - importKanjiDict(indexUrl) { + importKanjiDict(indexUrl, callback) { if (this.db === null) { return Promise.reject('database not initialized'); } @@ -193,7 +197,11 @@ class Dictionary { rows.push({character, onyomi, kunyomi, tags, meanings}); } - return this.db.kanji.bulkAdd(rows); + return this.db.kanji.bulkAdd(rows).then(() => { + if (callback) { + callback(i, index.banks); + } + }); }); }); } diff --git a/ext/bg/js/translator.js b/ext/bg/js/translator.js index 2cc97e1c..1dc0dca1 100644 --- a/ext/bg/js/translator.js +++ b/ext/bg/js/translator.js @@ -25,7 +25,7 @@ class Translator { this.deinflector = new Deinflector(); } - loadData() { + loadData(callback) { if (this.loaded) { return Promise.resolve(); } @@ -37,13 +37,37 @@ class Translator { this.tagMeta = tagMeta; return this.dictionary.prepareDb(); }).then(exists => { - if (!exists) { - return Promise.all([ - this.dictionary.importKanjiDict('bg/data/kanjidic/index.json'), - this.dictionary.importTermDict('bg/data/edict/index.json'), - this.dictionary.importTermDict('bg/data/enamdict/index.json') - ]).then(() => this.dictionary.sealDb()); + if (exists) { + return; } + + if (callback) { + callback({state: 'begin', progress: 0}); + } + + let banksLoaded = 0; + let banksTotal = 0; + + const bankCallback = (loaded, total) => { + banksLoaded += loaded; + banksTotal += total; + + if (callback) { + callback({state: 'update', progress: Math.ceil(100 * banksLoaded / banksTotal)}); + } + }; + + return Promise.all([ + this.dictionary.importTermDict('bg/data/edict/index.json', bankCallback), + this.dictionary.importTermDict('bg/data/enamdict/index.json', bankCallback), + this.dictionary.importKanjiDict('bg/data/kanjidic/index.json', bankCallback), + ]).then(() => { + return this.dictionary.sealDb(); + }).then(() => { + if (callback) { + callback({state: 'end', progress: 100}); + } + }); }).then(() => { this.loaded = true; }); From ff3896ed01024e612f9a80fb898f84afac98fc6b Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Tue, 13 Sep 2016 22:43:16 -0700 Subject: [PATCH 35/51] Fix progress counting --- ext/bg/js/dictionary.js | 4 ++-- ext/bg/js/translator.js | 19 +++++++++++++------ ext/bg/js/yomichan.js | 6 +++++- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/ext/bg/js/dictionary.js b/ext/bg/js/dictionary.js index 2bd39344..738535bb 100644 --- a/ext/bg/js/dictionary.js +++ b/ext/bg/js/dictionary.js @@ -163,7 +163,7 @@ class Dictionary { return this.db.terms.bulkAdd(rows).then(() => { if (callback) { - callback(i, index.banks); + callback(indexUrl, i, index.banks); } }); }); @@ -199,7 +199,7 @@ class Dictionary { return this.db.kanji.bulkAdd(rows).then(() => { if (callback) { - callback(i, index.banks); + callback(indexUrl, i, index.banks); } }); }); diff --git a/ext/bg/js/translator.js b/ext/bg/js/translator.js index 1dc0dca1..6827b5bc 100644 --- a/ext/bg/js/translator.js +++ b/ext/bg/js/translator.js @@ -45,14 +45,21 @@ class Translator { callback({state: 'begin', progress: 0}); } - let banksLoaded = 0; - let banksTotal = 0; + const banks = {}; + const bankCallback = (indexUrl, loaded, total) => { + banks[indexUrl] = {loaded: loaded, total: total}; + if (Object.keys(banks).length !== 3) { + return; + } - const bankCallback = (loaded, total) => { - banksLoaded += loaded; - banksTotal += total; + let banksLoaded = 0; + let banksTotal = 0; + for (const url in banks) { + banksLoaded += banks[url].loaded; + banksTotal += banks[url].total; + } - if (callback) { + if (callback && banksTotal > 0) { callback({state: 'update', progress: Math.ceil(100 * banksLoaded / banksTotal)}); } }; diff --git a/ext/bg/js/yomichan.js b/ext/bg/js/yomichan.js index 10a42f47..c9f53253 100644 --- a/ext/bg/js/yomichan.js +++ b/ext/bg/js/yomichan.js @@ -47,6 +47,10 @@ class Yomichan { } } + onImport({state, progress}) { + console.log(`${state}: ${progress}`); + } + onMessage(request, sender, callback) { const {action, params} = request, method = this['api_' + action]; @@ -90,7 +94,7 @@ class Yomichan { break; case 'loading': chrome.browserAction.setBadgeText({text: '...'}); - this.translator.loadData().then(() => this.setState('enabled')); + this.translator.loadData(this.onImport.bind(this)).then(() => this.setState('enabled')); break; } From b9d53f8427dde34900799295287c634a68d00687 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Wed, 14 Sep 2016 20:08:49 -0700 Subject: [PATCH 36/51] Progress update --- ext/bg/js/dictionary.js | 4 ++-- ext/bg/js/translator.js | 19 ++++++++----------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/ext/bg/js/dictionary.js b/ext/bg/js/dictionary.js index 738535bb..4562c821 100644 --- a/ext/bg/js/dictionary.js +++ b/ext/bg/js/dictionary.js @@ -163,7 +163,7 @@ class Dictionary { return this.db.terms.bulkAdd(rows).then(() => { if (callback) { - callback(indexUrl, i, index.banks); + callback(i, index.banks, indexUrl); } }); }); @@ -199,7 +199,7 @@ class Dictionary { return this.db.kanji.bulkAdd(rows).then(() => { if (callback) { - callback(indexUrl, i, index.banks); + callback(i, index.banks, indexUrl); } }); }); diff --git a/ext/bg/js/translator.js b/ext/bg/js/translator.js index 6827b5bc..2331bde7 100644 --- a/ext/bg/js/translator.js +++ b/ext/bg/js/translator.js @@ -46,21 +46,18 @@ class Translator { } const banks = {}; - const bankCallback = (indexUrl, loaded, total) => { - banks[indexUrl] = {loaded: loaded, total: total}; - if (Object.keys(banks).length !== 3) { - return; - } + const bankCallback = (loaded, total, indexUrl) => { + banks[indexUrl] = {loaded, total}; - let banksLoaded = 0; - let banksTotal = 0; + let percent = 0.0; for (const url in banks) { - banksLoaded += banks[url].loaded; - banksTotal += banks[url].total; + percent += banks[url].loaded / banks[url].total; } - if (callback && banksTotal > 0) { - callback({state: 'update', progress: Math.ceil(100 * banksLoaded / banksTotal)}); + percent /= 3; + + if (callback) { + callback({state: 'update', progress: Math.ceil(100 * percent)}); } }; From ce49a126cf156d6886e664f80417a2b65ff118ba Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Wed, 14 Sep 2016 21:08:51 -0700 Subject: [PATCH 37/51] Progress bar --- ext/bg/import.html | 25 +++++++++++++++++++++++++ ext/bg/js/import.js | 23 +++++++++++++++++++++++ ext/bg/js/yomichan.js | 13 ++++++++++++- 3 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 ext/bg/import.html create mode 100644 ext/bg/js/import.js diff --git a/ext/bg/import.html b/ext/bg/import.html new file mode 100644 index 00000000..47483c25 --- /dev/null +++ b/ext/bg/import.html @@ -0,0 +1,25 @@ + + + + + Yomichan Dictionary Import + + + + +
+ + +

Importing dictionary data, this can take a while...

+ +
+
+
+
+ + + + + diff --git a/ext/bg/js/import.js b/ext/bg/js/import.js new file mode 100644 index 00000000..905b4580 --- /dev/null +++ b/ext/bg/js/import.js @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2016 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 . + */ + + +chrome.runtime.onMessage.addListener(({state, progress}, sender, callback) => { + $('.progress-bar').css('width', progress + '%'); + callback(); +}); diff --git a/ext/bg/js/yomichan.js b/ext/bg/js/yomichan.js index c9f53253..bec34691 100644 --- a/ext/bg/js/yomichan.js +++ b/ext/bg/js/yomichan.js @@ -23,6 +23,7 @@ class Yomichan { Handlebars.registerHelper('kanjiLinks', kanjiLinks); this.translator = new Translator(); + this.importTabId = null; this.asyncPools = {}; this.ankiConnectVer = 0; this.setState('disabled'); @@ -48,7 +49,17 @@ class Yomichan { } onImport({state, progress}) { - console.log(`${state}: ${progress}`); + if (state === 'begin') { + chrome.tabs.create({url: chrome.extension.getURL('bg/import.html')}, tab => this.importTabId = tab.id); + } + + if (this.importTabId !== null) { + chrome.tabs.sendMessage(this.importTabId, {state, progress}, () => null); + } + + if (state === 'end') { + this.importTabId = null; + } } onMessage(request, sender, callback) { From 07a1f94806756d96344b52fd185c2bdc0495edf6 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Wed, 14 Sep 2016 21:14:34 -0700 Subject: [PATCH 38/51] Updating icons --- ext/img/icon128.png | Bin 274 -> 594 bytes ext/img/icon16.png | Bin 107 -> 129 bytes ext/img/icon19.png | Bin 111 -> 135 bytes ext/img/icon38.png | Bin 137 -> 196 bytes ext/img/icon48.png | Bin 147 -> 223 bytes 5 files changed, 0 insertions(+), 0 deletions(-) diff --git a/ext/img/icon128.png b/ext/img/icon128.png index d22e3c88d791f6ca6b17284358e1937307314721..c3e5ae647b3f04ef1d6049aa9520b3b840da496a 100644 GIT binary patch literal 594 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7xzrV3PE7aSW-r_4baTpOz!T@rVD{ zUHekD{xeh7Va^p9Hr?$THXTWxa3k4SSzTe{wB&?`Hr$6FFFcYm^XI-4uEmNsZ{F`a zz2NrK|LZ3EOzxQ+qqdX7d7I}ZzfC?y{+oWiFI=T8c&!2`du)yTOl2|znjH~}yHg1)l z|C~h$yZSc|EE|b4>he>|M)kUydBPn~XQ5fU;qZg`!X2U@(K_9R-pq_^%ltQ)@t=+Q z?m6w*!pPHhC-2ypWZzSdRIM}DO<)2lr}Bp4)kzJ0-r}Q*Tnt%;{=2YLz#> z_PW|_YwN8#o)j;sEErP%$-P}i(0Fp_-5IstzaKf06>v7x{^xa1yC?PC>me~WZMG}h mp1sj!<~|~!5O})!xvX~)z3s?#K!JzBG5FVi z{pI-_B8v*2>4|Qu64)dLRK&nw5E~+%l6Kxr+3nrukNn?+92gh{92i&x7#LZg%pJ}p zwL5;r#n+~nGoeW#sRGIDxDg$D!L+{ml-*g*-A$Nk%~Jesa2BvCHZX7~Ffeg6Ffb`# oFwZ3W{YZb-66=Vm1ngc0Uc35j5_^P#&&PuJp00i_>zopr0I2yup8x;= diff --git a/ext/img/icon16.png b/ext/img/icon16.png index 4670bda041a2ea2588bc89c4ea5856fd5178575d..10dab78a507ea18483a3aa5e82b0d90c88381862 100644 GIT binary patch delta 110 zcmd09WSk(G!N$PAApiM)B9QX%ba4!^IGvo3kkFByknqD_tuMXB=meXN!Lk4UXFM}7 zG7_4SoU}k7;VaV_w;8%W7>?>KxWTZe(Zh$KpY72CUYDT53XM#EIT@N}Yqzhl`d17z Olfl!~&t;ucLK6V)WGU$Y delta 88 zcmZo<%$^__#KgeBFkxbb8IUsaba4#PIG>!bz%-#H;Q#;s?t-Z)M^sO^tn3AGj3sy{ oBwD@YiVJY#?Rk>Eak-aXL9+fqg(X!HrMCMmjgh) uVXTL*^~vieo3t4w%Gyh9Q#Q`Y8=0(0E|0qppR71*p$x{C>?v9um@ z?kl314gK%BVgmaOSogYU4R&jI)k=X0Os;&nQshc0NlFr!z$^qNSIU(F8{6xd zf@CO{l>o|EIJ^6O#;kl_(wcuI%AxqAgp7nZ@UbZWR_;Q_b~>3|Qh4kVB^^u0zNiFf ZZ~%kS7&NiB_a^`V002ovPDHLkV1j!(GN%9l diff --git a/ext/img/icon48.png b/ext/img/icon48.png index 403bb60e36f4e4be29cbae0b59517867191f929d..da76135b8e5fe0bdc79a7602b3ddf018548a6b16 100644 GIT binary patch delta 206 zcmV;<05SiQ0p9_T8Gi-<00374`G)`i0H#SqK~!ko?b^K!gD@0D;bX!EEReO>i7p+> zz-CTEekC`F1i8w2k}D+iKAvT6VR+OCEI|G7wQRk<)D+P8`a;bFityx;{a=L|7!=#!GL@3(U(1L6?xs}3KJCkHoW3~(*OVf07*qo IM6N<$g3^0fT>t<8 delta 129 zcmV-{0Dk}90h0lc8F~T$007uvZqNV#09r{zK~z}7?bcBS05J>z(WdtPSI! zZ$3*HjWA;X*h|!>%=|DP(K|j*`yoPvHeA_)dO`I}tc(yLLYE6YKl7u#UaX9e{E#1n j2oaJW@`Df|0B7?8FV`4E5MnWy00000NkvXXu0mjfrOq*c From 0eb54e24c6c290d8aa2df1e5f6c52ae35e35ca1a Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Wed, 14 Sep 2016 22:34:05 -0700 Subject: [PATCH 39/51] Deleting dead options --- ext/bg/js/options-form.js | 18 ++++++++---------- ext/bg/js/options.js | 1 - ext/bg/options.html | 19 +++++-------------- ext/fg/js/frame.js | 27 ++++++++++++--------------- 4 files changed, 25 insertions(+), 40 deletions(-) diff --git a/ext/bg/js/options-form.js b/ext/bg/js/options-form.js index a1ecccda..f7d4279f 100644 --- a/ext/bg/js/options-form.js +++ b/ext/bg/js/options-form.js @@ -68,7 +68,6 @@ function formToOptions(section) { case 'general': optsNew.scanLength = parseInt($('#scan-length').val(), 10); optsNew.activateOnStartup = $('#activate-on-startup').prop('checked'); - optsNew.loadEnamDict = $('#load-enamdict').prop('checked'); optsNew.selectMatchedText = $('#select-matched-text').prop('checked'); optsNew.showAdvancedOptions = $('#show-advanced-options').prop('checked'); optsNew.enableAudioPlayback = $('#enable-audio-playback').prop('checked'); @@ -98,9 +97,9 @@ function populateAnkiDeckAndModel(opts) { const ankiDeck = $('.anki-deck'); ankiDeck.find('option').remove(); - yomi.api_getDeckNames({callback: (names) => { + yomi.api_getDeckNames({callback: names => { if (names !== null) { - names.forEach((name) => ankiDeck.append($('