background.js 18 KB

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