background.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617
  1. var db,port=null,pos=0;
  2. function initDb(callback) {
  3. var request=indexedDB.open('Violentmonkey',1);
  4. request.onsuccess=function(e){db=request.result;if(callback) callback();};
  5. request.onerror=function(e){console.log('IndexedDB error: '+e.target.error.message);};
  6. request.onupgradeneeded=function(e){
  7. var r=e.currentTarget.result,o;
  8. // scripts: id uri custom meta enabled update code position
  9. o=r.createObjectStore('scripts',{keyPath:'id',autoIncrement:true});
  10. o.createIndex('uri','uri',{unique:true});
  11. o.createIndex('update','update',{unique:false});
  12. o.createIndex('position','position',{unique:false}); // should be unique at last
  13. // require: uri code
  14. o=r.createObjectStore('require',{keyPath:'uri'});
  15. // cache: uri data
  16. o=r.createObjectStore('cache',{keyPath:'uri'});
  17. // values: uri values
  18. o=r.createObjectStore('values',{keyPath:'uri'});
  19. };
  20. }
  21. function getNameURI(i) {
  22. var ns=i.meta.namespace||'',n=i.meta.name||'',k=escape(ns)+':'+escape(n)+':';
  23. if(!ns&&!n) k+=i.id;
  24. return k;
  25. }
  26. function getMeta(j){return {id:j.id,custom:j.custom,meta:j.meta,enabled:j.enabled,update:j.update};}
  27. function parseMeta(d){
  28. var o=-1,meta={include:[],exclude:[],match:[],require:[],resource:[],resources:{}};
  29. d.replace(/(?:^|\n)\/\/\s*([@=]\S+)(.*)/g,function(m,k,v){
  30. if(o<0&&k=='==UserScript==') o=1;
  31. else if(k=='==/UserScript==') o=0;
  32. if(o==1&&k[0]=='@') k=k.slice(1); else return;
  33. v=v.replace(/^\s+|\s+$/g,'');
  34. if(meta[k]&&meta[k].push) meta[k].push(v); // multiple values allowed
  35. else if(!(k in meta)) meta[k]=v; // only first value will be stored
  36. });
  37. meta.resource.forEach(function(i){
  38. o=i.match(/^(\w+)\s+(.*)/);
  39. if(o) meta.resources[o[1]]=o[2];
  40. });
  41. delete meta.resource;
  42. return meta;
  43. }
  44. function newScript() {
  45. var r={
  46. custom: {},
  47. enabled: 1,
  48. update: 1,
  49. code: '// ==UserScript==\n// @name New Script\n// ==/UserScript==\n'
  50. };
  51. r.meta=parseMeta(r.code);
  52. return r;
  53. }
  54. function removeScript(i,src,callback) {
  55. var o=db.transaction('scripts','readwrite').objectStore('scripts');
  56. o.delete(i);
  57. if(callback) callback();
  58. }
  59. function saveScript(i,src,callback) {
  60. var o=db.transaction('scripts','readwrite').objectStore('scripts');
  61. i.enabled=i.enabled?1:0;
  62. i.update=i.update?1:0;
  63. if(!i.position) i.position=++pos;
  64. if(callback) callback();
  65. return o.put(i);
  66. }
  67. function vacuum(o,src,callback) {
  68. var ids=[],cc={},rq={},vl={},w=0,p=0;
  69. function init(){
  70. var o=db.transaction('scripts').objectStore('scripts');
  71. o.index('position').openCursor().onsuccess=function(e){
  72. var r=e.target.result,v,i;
  73. if(r) {
  74. v=r.value;ids.push(v.id);
  75. v.meta.require.forEach(function(i){rq[i]=1;});
  76. for(i in v.meta.resources) cc[v.meta.resources[i]]=1;
  77. if(v.meta.icon) cc[v.meta.icon]=1;vl[v.uri]=1;
  78. r.continue();
  79. } else vacuumPosition();
  80. };
  81. }
  82. function vacuumPosition(){
  83. var i=ids.shift();
  84. if(i) {
  85. var o=db.transaction('scripts','readwrite').objectStore('scripts');
  86. o.get(i).onsuccess=function(e){
  87. var r=e.target.result;r.position=++p;
  88. o.put(r).onsuccess=vacuumPosition;
  89. };
  90. } else {
  91. pos=p;
  92. vacuumDB('require',rq);
  93. vacuumDB('cache',cc);
  94. vacuumDB('values',vl);
  95. }
  96. }
  97. function vacuumDB(dbName,dic){
  98. w++;
  99. var o=db.transaction(dbName,'readwrite').objectStore(dbName);
  100. o.openCursor().onsuccess=function(e){
  101. var r=e.target.result,v;
  102. if(r) {
  103. v=r.value;
  104. if(!dic[v.uri]) o.delete(v.uri);
  105. else dic[v.uri]++; // stored
  106. r.continue();
  107. } else finish();
  108. };
  109. }
  110. function finish(){
  111. if(!--w) {
  112. var i;
  113. for(i in rq) if(rq[i]==1) fetchRequire(i);
  114. for(i in cc) if(cc[i]==1) fetchCache(i);
  115. chrome.tabs.sendMessage(src.tab.id,{cmd:'Vacuumed'});
  116. }
  117. }
  118. init();
  119. if(callback) callback();
  120. }
  121. function move(data,src,callback){
  122. var o=db.transaction('scripts','readwrite').objectStore('scripts');
  123. o.get(data.id).onsuccess=function(e){
  124. var r=e.target.result,k,s,x=r.position;
  125. if(data.offset<0) {
  126. k=IDBKeyRange.upperBound(x,true);
  127. s='prev';
  128. data.offset=-data.offset;
  129. } else {
  130. k=IDBKeyRange.lowerBound(x,true);
  131. s='next';
  132. }
  133. o.index('position').openCursor(k,s).onsuccess=function(e){
  134. var p=e.target.result,v;
  135. if(p) {
  136. data.offset--;
  137. v=p.value;v.position=x;o.put(v);x=p.key;
  138. if(data.offset) p.continue();
  139. else {r.position=x;o.put(r);}
  140. }
  141. };
  142. };
  143. if(callback) callback();
  144. }
  145. function str2RE(s){return s.replace(/(\.|\?|\/)/g,'\\$1').replace(/\*/g,'.*?');}
  146. function autoReg(s, w) {
  147. if(!w&&s[0]=='/'&&s.slice(-1)=='/') return RegExp(s.slice(1,-1));
  148. return RegExp('^'+str2RE(s)+'$');
  149. }
  150. var match_reg=/(.*?):\/\/([^\/]*)\/(.*)/;
  151. function matchTest(s,u) {
  152. var m=s.match(match_reg);
  153. if(!m) return false;
  154. if(m[1]=='*') {
  155. if(u[1]!='http'&&u[1]!='https') return false;
  156. } else if(m[1]!=u[1]) return false;
  157. if(m[2]!='*') {
  158. if(m[2].slice(0,2)=='*.') {
  159. if(u[2]!=m[2].slice(2)&&u[2].slice(1-m[2].length)!=m[2].slice(1)) return false;
  160. } else if(m[2]!=u[2]) return false;
  161. }
  162. if(!autoReg(m[3],1).test(u[3])) return false;
  163. return true;
  164. }
  165. function testURL(url,e) {
  166. var f=true,i,inc=[],exc=[],mat=[],u=url.match(match_reg);
  167. if(e.custom._match!=false&&e.meta.match) mat=mat.concat(e.meta.match);
  168. if(e.custom.match) mat=mat.concat(e.custom.match);
  169. if(e.custom._include!=false&&e.meta.include) inc=inc.concat(e.meta.include);
  170. if(e.custom.include) inc=inc.concat(e.custom.include);
  171. if(e.custom._exclude!=false&&e.meta.exclude) exc=exc.concat(e.meta.exclude);
  172. if(e.custom.exclude) exc=exc.concat(e.custom.exclude);
  173. if(mat.length) {
  174. for(i=0;i<mat.length;i++) if(f=matchTest(mat[i],u)) break;
  175. } else for(i=0;i<inc.length;i++) if(f=autoReg(inc[i]).test(url)) break;
  176. if(f) for(i=0;i<exc.length;i++) if(!(f=!autoReg(exc[i]).test(url))) break;
  177. return f;
  178. }
  179. function getScript(id,src,callback) { // for user edit
  180. var o=db.transaction('scripts').objectStore('scripts');
  181. o.get(id).onsuccess=function(e){
  182. var r=e.target.result,v;
  183. if(r) {
  184. v=getMeta(r);
  185. v.code=r.code;
  186. if(callback) callback(v);
  187. }
  188. };
  189. }
  190. function getMetas(ids,src,callback) { // for popup menu
  191. var o=db.transaction('scripts').objectStore('scripts'),data=[],id;
  192. function getOne(){
  193. var id=ids.shift();
  194. if(id) o.get(id).onsuccess=function(e){
  195. var r=e.target.result;
  196. if(r) data.push(getMeta(r));
  197. getOne();
  198. }; else callback(data);
  199. }
  200. getOne();
  201. }
  202. function getCacheB64(ids,src,callback) {
  203. var o=db.transaction('cache').objectStore('cache'),data={};
  204. function loop(){
  205. var i=ids.pop();
  206. if(i) o.get(i).onsuccess=function(e){
  207. var r=e.target.result,b,u;
  208. if(r) {
  209. if(typeof r.data=='string') data[i]=r.data;
  210. else
  211. // XXX: old data, update it
  212. setTimeout(function(){fetchCache(i)},1);
  213. }
  214. loop();
  215. }; else callback(data);
  216. }
  217. loop();
  218. }
  219. function getInjected(url,src,callback) { // for injected
  220. function getScripts(){
  221. var o=db.transaction('scripts').objectStore('scripts'),n=0,require={};
  222. o.index('position').openCursor().onsuccess=function(e){
  223. var i,r=e.target.result,v;
  224. if(r) {
  225. v=r.value;
  226. if(testURL(url,v)) {
  227. data.scripts.push(v);if(v.enabled) n++;
  228. values.push(v.uri);
  229. v.meta.require.forEach(function(i){require[i]=1;});
  230. for(i in v.meta.resources) cache[v.meta.resources[i]]=1;
  231. }
  232. r.continue();
  233. } else {
  234. if(n) {
  235. chrome.browserAction.setBadgeBackgroundColor({color:'#808',tabId:src.tab.id});
  236. chrome.browserAction.setBadgeText({text:n.toString(),tabId:src.tab.id});
  237. }
  238. getRequire(Object.getOwnPropertyNames(require));
  239. }
  240. };
  241. }
  242. function getRequire(require){
  243. function loop(){
  244. var i=require.pop();
  245. if(i) o.get(i).onsuccess=function(e){
  246. var r=e.target.result;
  247. if(r) data.require[i]=r.code;
  248. loop();
  249. }; else getCache();
  250. }
  251. var o=db.transaction('require').objectStore('require');
  252. loop();
  253. }
  254. function getCache(){
  255. getCacheB64(Object.getOwnPropertyNames(cache),src,function(o){
  256. data.cache=o;
  257. getValues();
  258. });
  259. }
  260. function getValues(){
  261. function loop(){
  262. var i=values.pop();
  263. if(i) o.get(i).onsuccess=function(e){
  264. var r=e.target.result;
  265. if(r) data.values[i]=r.values;
  266. loop();
  267. }; else finish();
  268. }
  269. var o=db.transaction('values').objectStore('values');
  270. loop();
  271. }
  272. function finish(){callback(data);}
  273. var data={scripts:[],values:{},require:{}},cache={},values=[];
  274. if(data.isApplied=settings.isApplied) getScripts(); else finish();
  275. }
  276. function fetchURL(url, cb, type, headers) {
  277. var req=new XMLHttpRequest(),i;
  278. req.open('GET', url, true);
  279. if(type) req.responseType = type;
  280. if(headers) for(i in headers)
  281. req.setRequestHeader(i,headers[i]);
  282. if(cb) req.onloadend = cb;
  283. req.send();
  284. }
  285. var u_cache={},u_require={};
  286. function saveCache(url,data,callback) {
  287. var o=db.transaction('cache','readwrite').objectStore('cache');
  288. o.put({uri:url,data:data}).onsuccess=callback;
  289. }
  290. function fetchCache(url) {
  291. if(u_cache[url]) return;
  292. u_cache[url]=1;
  293. fetchURL(url, function() {
  294. if (this.status!=200) return;
  295. //saveCache(url,this.response,function(){delete u_cache[url];});
  296. var r=new FileReader();
  297. r.onload=function(e){
  298. saveCache(url,window.btoa(r.result),function(){delete u_cache[url];});
  299. };
  300. r.readAsBinaryString(this.response);
  301. }, 'blob');
  302. }
  303. function saveRequire(url,data,callback) {
  304. var o=db.transaction('require','readwrite').objectStore('require');
  305. o.put({uri:url,code:data}).onsuccess=callback;
  306. }
  307. function fetchRequire(url) {
  308. if(u_require[url]) return;
  309. u_require[url]=1;
  310. fetchURL(url, function(){
  311. if(this.status==200) saveRequire(url,this.responseText,function(){delete u_require[url];});
  312. });
  313. }
  314. function updateItem(r){
  315. if(port) try{
  316. port.postMessage(r);
  317. }catch(e){
  318. port=null;
  319. console.log(e);
  320. }
  321. }
  322. function queryScript(id,meta,callback){
  323. var o=db.transaction('scripts').objectStore('scripts');
  324. function queryMeta() {
  325. var uri=getNameURI({id:'',meta:meta});
  326. if(uri!='::') o.index('uri').get(uri).onsuccess=function(e){
  327. var r=e.target.result;
  328. if(r) callback(r); else callback(newScript());
  329. }; else callback(newScript());
  330. }
  331. function queryId() {
  332. if(id) o.get(id).onsuccess=function(e){
  333. var r=e.target.result;
  334. if(r) callback(r); else queryMeta();
  335. }; else queryMeta();
  336. }
  337. queryId();
  338. }
  339. function parseScript(o,src,callback) {
  340. var i,r={status:0,message:'message' in o?o.message:_('msgUpdated')};
  341. function finish(){
  342. if(src) chrome.tabs.sendMessage(src.tab.id,{cmd:'ShowMessage',data:r});
  343. updateItem(r);
  344. }
  345. if(o.status&&o.status!=200||o.code=='') { // net error
  346. r.status=-1;r.message=_('msgErrorFetchingScript');finish();
  347. } else { // store script
  348. var meta=parseMeta(o.code);
  349. queryScript(o.id,meta,function(c){
  350. if(!c.id){r.status=1;r.message=_('msgInstalled');}
  351. if(o.more) for(i in o.more) if(i in c) c[i]=o.more[i]; // for import and user edit
  352. c.meta=meta;c.code=o.code;c.uri=getNameURI(c);
  353. if(o.from&&!c.meta.homepageURL&&!c.custom.homepageURL&&!/^(file|data):/.test(o.from)) c.custom.homepageURL=o.from;
  354. if(o.url&&!/^(file|data):/.test(o.url)) c.custom.lastInstallURL=o.url;
  355. saveScript(c,src).onsuccess=function(e){
  356. r.id=c.id=e.target.result;r.obj=getMeta(c);finish();
  357. };
  358. });
  359. meta.require.forEach(function(u){ // @require
  360. var c=o.require&&o.require[u];
  361. if(c) saveRequire(u,c); else fetchRequire(u);
  362. });
  363. for(d in meta.resources) { // @resource
  364. var u=meta.resources[d],c=o.resources&&o.resources[u];
  365. if(c) saveCache(u,c); else fetchCache(u);
  366. }
  367. if(meta.icon) fetchCache(meta.icon); // @icon
  368. }
  369. if(callback) callback();
  370. }
  371. function canUpdate(o,n){
  372. o=(o||'').split('.');
  373. n=(n||'').split('.');
  374. var r=/(\d*)([a-z]*)(\d*)([a-z]*)/i;
  375. while(o.length&&n.length){
  376. var vo=o.shift().match(r),vn=n.shift().match(r);
  377. vo.shift();vn.shift();
  378. vo[0]=parseInt(vo[0]||0,10);
  379. vo[2]=parseInt(vo[2]||0,10);
  380. vn[0]=parseInt(vn[0]||0,10);
  381. vn[2]=parseInt(vn[2]||0,10);
  382. while(vo.length&&vn.length){
  383. var eo=vo.shift(),en=vn.shift();
  384. if(eo!=en) return eo<en;
  385. }
  386. }
  387. return n.length;
  388. }
  389. function setValue(data,src,callback){
  390. var o=db.transaction('values','readwrite').objectStore('values');
  391. o.put({uri:data.uri,values:data.values});
  392. if(callback) callback(); // it seems that CALLBACK does not work with READWRITE transaction
  393. }
  394. function getOption(k,src,callback){
  395. var v=localStorage.getItem(k)||'';
  396. try{
  397. v=JSON.parse(v);
  398. }catch(e){
  399. return false;
  400. }
  401. settings[k]=v;
  402. if(callback) callback(v);
  403. return true;
  404. }
  405. function setOption(o,src,callback){
  406. if(!o.check||(o.key in settings)) {
  407. localStorage.setItem(o.key,JSON.stringify(o.value));
  408. settings[o.key]=o.value;
  409. }
  410. if(callback) callback(o.value);
  411. }
  412. function initSettings(){
  413. function init(k,v){
  414. if(!getOption(k)) setOption({key:k,value:v});
  415. }
  416. init('isApplied',true);
  417. init('autoUpdate',true);
  418. init('lastUpdate',0);
  419. init('withData',true);
  420. init('closeAfterInstall',false);
  421. init('search',_('defaultSearch'));
  422. }
  423. function updateMeta(d,src,callback) {
  424. var o=db.transaction('scripts','readwrite').objectStore('scripts');
  425. o.get(d.id).onsuccess=function(e){
  426. var r=e.target.result,i;
  427. if(!r) return;
  428. for(i in d) if(i in r) r[i]=d[i];
  429. o.put(r).onsuccess=function(e){ // store script without another transaction
  430. updateItem({id:d.id,obj:getMeta(r),status:0});
  431. };
  432. };
  433. if(callback) callback();
  434. }
  435. var _update={};
  436. function checkUpdateO(o) {
  437. if(_update[o.id]) return;_update[o.id]=1;
  438. function finish(){delete _update[o.id];}
  439. var r={id:o.id,updating:1,status:2};
  440. function update() {
  441. if(du) {
  442. r.message=_('msgUpdating');
  443. fetchURL(du,function(){
  444. parseScript({
  445. id: o.id,
  446. status: this.status,
  447. code: this.responseText
  448. });
  449. });
  450. } else r.message='<span class=new>'+_('msgNewVersion')+'</span>';
  451. updateItem(r);finish();
  452. }
  453. var du=o.custom.downloadURL||o.meta.downloadURL||o.custom.lastInstallURL,
  454. u=o.custom.updateURL||o.meta.updateURL||du;
  455. if(u) {
  456. r.message=_('msgCheckingForUpdate');updateItem(r);
  457. fetchURL(u,function() {
  458. r.message=_('msgErrorFetchingUpdateInfo');
  459. if(this.status==200) try {
  460. var m=parseMeta(this.responseText);
  461. if(canUpdate(o.meta.version,m.version)) return update();
  462. r.message=_('msgNoUpdate');
  463. } catch(e){}
  464. delete r.updating;
  465. updateItem(r);finish();
  466. },null,{Accept:'text/x-userscript-meta'});
  467. } else finish();
  468. }
  469. function checkUpdate(id,src,callback) {
  470. var o=db.transaction('scripts').objectStore('scripts');
  471. o.get(id).onsuccess=function(e){
  472. var r=e.target.result;
  473. if(r) checkUpdateO(r);
  474. if(callback) callback();
  475. };
  476. }
  477. function checkUpdateAll(e,src,callback) {
  478. setOption({key:'lastUpdate',value:Date.now()});
  479. var o=db.transaction('scripts').objectStore('scripts');
  480. o.index('update').openCursor(1).onsuccess=function(e){
  481. var r=e.target.result;
  482. if(!r) {
  483. if(callback) callback();
  484. return;
  485. }
  486. checkUpdateO(r.value);
  487. r.continue();
  488. };
  489. }
  490. var checking=false;
  491. function autoCheck() {
  492. function check() {
  493. if(settings.autoUpdate) {
  494. if(Date.now()-settings.lastUpdate>=864e5) checkUpdateAll();
  495. setTimeout(check,36e5);
  496. } else checking=false;
  497. }
  498. if(!checking) {checking=true;check();}
  499. }
  500. function autoUpdate(o,src,callback){
  501. o=!!o;
  502. setOption({key:'autoUpdate',value:o},src,autoCheck);
  503. if(callback) callback(o);
  504. }
  505. function getData(d,src,callback) {
  506. function getScripts(){
  507. var o=db.transaction('scripts').objectStore('scripts');
  508. o.index('position').openCursor().onsuccess=function(e){
  509. var r=e.target.result,v;
  510. if(r) {
  511. v=r.value;
  512. if(v.meta.icon) cache[v.meta.icon]=1;
  513. data.scripts.push(getMeta(v));
  514. r.continue();
  515. } else getCache();
  516. };
  517. function getCache(){
  518. getCacheB64(Object.getOwnPropertyNames(cache),src,function(o){
  519. for(var i in o) o[i]='data:image/png;base64,'+o[i];
  520. data.cache=o;
  521. callback(data);
  522. });
  523. }
  524. }
  525. var data={settings:settings,scripts:[]},cache={};
  526. getScripts();
  527. }
  528. function exportZip(z,src,callback){
  529. function getScripts(){
  530. function loop(){
  531. var i=z.data.shift();
  532. if(i) o.get(i).onsuccess=function(e){
  533. var r=e.target.result;
  534. if(r) {
  535. d.scripts.push(r);
  536. if(z.values) values.push(r.uri);
  537. }
  538. loop();
  539. }; else getValues();
  540. }
  541. var o=db.transaction('scripts').objectStore('scripts');
  542. loop();
  543. }
  544. function getValues(){
  545. function loop(){
  546. var i=values.shift();
  547. if(i) o.get(i).onsuccess=function(e){
  548. var r=e.target.result;
  549. if(r) d.values[i]=r.values;
  550. loop();
  551. }; else finish();
  552. }
  553. if(z.values) {
  554. var o=db.transaction('values').objectStore('values');
  555. d.values={};loop();
  556. } else finish();
  557. }
  558. function finish(){callback(d);}
  559. var d={scripts:[],settings:settings},values=[];
  560. getScripts();
  561. }
  562. chrome.runtime.onConnect.addListener(function(p){
  563. port=p;
  564. p.onDisconnect.addListener(function(){port=null;});
  565. });
  566. chrome.runtime.onMessage.addListener(function(req,src,callback) {
  567. var maps={
  568. NewScript:function(o,src,callback){callback(newScript());},
  569. RemoveScript: removeScript,
  570. GetData: getData,
  571. GetInjected: getInjected,
  572. CheckUpdate: checkUpdate,
  573. CheckUpdateAll: checkUpdateAll,
  574. SaveScript: saveScript,
  575. UpdateMeta: updateMeta,
  576. SetValue: setValue,
  577. GetOption: getOption,
  578. SetOption: setOption,
  579. ExportZip: exportZip,
  580. ParseScript: parseScript,
  581. GetScript: getScript, // for user edit
  582. GetMetas: getMetas, // for popup menu
  583. AutoUpdate: autoUpdate,
  584. Vacuum: vacuum,
  585. Move: move,
  586. ParseMeta: function(o,src,callback){callback(parseMeta(o));},
  587. },f=maps[req.cmd];
  588. if(f) f(req.data,src,callback);
  589. return true;
  590. });
  591. var settings={};
  592. initSettings();
  593. initDb(function(){
  594. var o=db.transaction('scripts').objectStore('scripts');
  595. o.index('position').openCursor(null,'prev').onsuccess=function(e){
  596. var r=e.target.result;pos=r.key;
  597. };
  598. chrome.browserAction.setIcon({path:'images/icon19'+(settings.isApplied?'':'w')+'.png'});
  599. setTimeout(autoCheck,2e4);
  600. });
  601. chrome.webRequest.onBeforeRequest.addListener(function(o){
  602. if(/\.user\.js([\?#]|$)/.test(o.url)) {
  603. var x=new XMLHttpRequest();
  604. x.open('GET',o.url,false);
  605. x.send();
  606. if((!x.status||x.status==200)&&/^\s*[^<]/.test(x.responseText)) {
  607. if(o.tabId<0) chrome.tabs.create({url:chrome.extension.getURL('/confirm.html')+'?url='+encodeURIComponent(o.url)});
  608. else chrome.tabs.get(o.tabId,function(t){
  609. chrome.tabs.create({url:chrome.extension.getURL('/confirm.html')+'?url='+encodeURIComponent(o.url)+'&from='+encodeURIComponent(t.url)});
  610. });
  611. return {redirectUrl:'javascript:history.back()'};
  612. }
  613. }
  614. },{
  615. urls:['*://*/*','file://*/*'],types:['main_frame']
  616. },['blocking']);