options.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. var L=$('#sList'),cur=null,C=$('.content');
  2. zip.workerScriptsPath='lib/zip.js/';
  3. initI18n();
  4. function split(t){return t.replace(/^\s+|\s+$/g,'').split(/\s*\n\s*/).filter(function(e){return e;});}
  5. function getName(d,n,def){
  6. d.title=n||'';
  7. d.innerHTML=n?n.replace(/&/g,'&amp;').replace(/</g,'&lt;'):(def||'<em>'+_('labelNoName')+'</em>');
  8. }
  9. // Main options
  10. function allowUpdate(n){return n.update&&(n.custom.updateURL||n.meta.updateURL);}
  11. function setIcon(n,d){
  12. d.src=cache[n.meta.icon]||'images/icon48.png';
  13. }
  14. function modifyItem(r){
  15. var o=map[r.id],d=o.div,n=o.obj;
  16. if(r.message) d.querySelector('.message').innerHTML=r.message;
  17. d.className=n.enabled?'':'disabled';
  18. var a=d.querySelector('.update');
  19. if(a) a.disabled=r.updating;
  20. a=d.querySelector('.name');
  21. getName(a,n.custom.name||n.meta.name);
  22. if(o=n.custom.homepage||n.meta.homepage) a.href=o;
  23. if(n.meta.author) d.querySelector('.author').innerText=_('labelAuthor')+n.meta.author;
  24. a=d.querySelector('.descrip');
  25. getName(a,n.meta.description||'','&nbsp;');
  26. setIcon(n,d.querySelector('.icon'));
  27. a=d.querySelector('.enable');
  28. a.innerHTML=n.enabled?_('buttonDisable'):_('buttonEnable');
  29. }
  30. function loadItem(o,r){
  31. var d=o.div,n=o.obj;if(!r) r={id:n.id};
  32. d.innerHTML='<img class=icon>'
  33. +'<a class="name ellipsis" target=_blank></a>'
  34. +'<span class=version>'+(n.meta.version?'v'+n.meta.version:'')+'</span>'
  35. +'<span class=author></span>'
  36. +'<div class=panelT>'
  37. +'<span class=move data=move>&equiv;</span>'
  38. +'</div>'
  39. +'<p class="descrip ellipsis"></p>'
  40. +'<div class=panelB>'
  41. +'<button data=edit>'+_('buttonEdit')+'</button> '
  42. +'<button data=enable class=enable></button> '
  43. +'<button data=remove>'+_('buttonRemove')+'</button> '
  44. +(allowUpdate(n)?'<button data=update class=update>'+_('anchorUpdate')+'</button> ':'')
  45. +'<span class=message></span>'
  46. +'</div>';
  47. modifyItem(r);
  48. }
  49. function addItem(o){
  50. o.div=document.createElement('div');
  51. loadItem(o);
  52. L.appendChild(o.div);
  53. }
  54. (function(){
  55. function getSource(e){
  56. var o=e.target,p,i;
  57. for(p=o;p&&p.parentNode!=L;p=p.parentNode);
  58. i=Array.prototype.indexOf.call(L.childNodes,p);
  59. return [i,p,o];
  60. }
  61. function moveItem(e){
  62. var m=getSource(e);if(m[0]<0) return;
  63. if(m[0]>=0&&m[0]!=t) {
  64. e=m;m=e[1];if(e[0]>t) m=m.nextSibling;
  65. L.insertBefore(o[1],m);
  66. t=e[0];
  67. }
  68. }
  69. function movedItem(e){
  70. if(!moving) return;moving=false;
  71. o[1].classList.remove('moving');
  72. L.onmousemove=L.onmouseup=null;L.onmousedown=startMove;
  73. if(o[0]!=t) {
  74. chrome.runtime.sendMessage({cmd:'Move',data:{id:ids[o[0]],offset:t-o[0]}});
  75. var s=t>o[0]?1:-1,i=o[0],x=ids[i];
  76. for(;i!=t;i+=s) ids[i]=ids[i+s];
  77. ids[t]=x;
  78. }
  79. }
  80. function startMove(e){
  81. o=getSource(e);t=o[0];
  82. if(o[2].getAttribute('data')=='move') {
  83. if(moving) return;moving=true;
  84. e.preventDefault();
  85. o[1].classList.add('moving');
  86. L.onmousedown=null;
  87. L.onmousemove=moveItem;
  88. L.onmouseup=movedItem;
  89. }
  90. }
  91. var maps={
  92. edit:function(i){
  93. E.cur=map[ids[i]];
  94. chrome.runtime.sendMessage({cmd:'GetScript',data:ids[i]},gotScript);
  95. },
  96. enable:function(i,p,o){
  97. var e=map[ids[i]].obj;
  98. chrome.runtime.sendMessage({cmd:'UpdateMeta',data:{id:e.id,enabled:!e.enabled?1:0}});
  99. },
  100. remove:function(i,p){
  101. chrome.runtime.sendMessage({cmd:'RemoveScript',data:ids[i]});
  102. delete map[ids.splice(i,1)[0]];
  103. L.removeChild(p);
  104. },
  105. update:function(i){
  106. chrome.runtime.sendMessage({cmd:'CheckUpdate',data:ids[i]});
  107. }
  108. },o,t,moving=false;
  109. L.onmousedown=startMove;
  110. L.onclick=function(e){
  111. var o=getSource(e),d=o[2].getAttribute('data'),f=maps[d];
  112. if(f) {
  113. e.preventDefault();
  114. f.apply(this,o);
  115. }
  116. };
  117. })();
  118. $('#bNew').onclick=function(){chrome.runtime.sendMessage({cmd:'NewScript'},function(o){
  119. E.cur=null;gotScript(o);
  120. });};
  121. $('#bUpdate').onclick=function(){chrome.runtime.sendMessage({cmd:'CheckUpdateAll'});};
  122. function switchTab(e){
  123. var t=e.target,i=t.id.slice(2),o=C.querySelector('#tab'+i);
  124. if(!o) return;
  125. if(cur) {
  126. if(cur.tab==o) return;
  127. cur.menu.classList.remove('selected');
  128. cur.tab.classList.add('hide');
  129. }
  130. cur={menu:t,tab:o};
  131. t.classList.add('selected');
  132. o.classList.remove('hide');
  133. switch(i) { // init
  134. case 'Settings':xLoad();break;
  135. }
  136. }
  137. $('.sidemenu').onclick=switchTab;
  138. switchTab({target:$('#smInstalled')});
  139. function confirmCancel(dirty){
  140. return !dirty||confirm(_('confirmNotSaved'));
  141. }
  142. // Advanced
  143. var H=$('#iImport'),S=$('#tSearch'),V=$('#bVacuum');
  144. $('#cUpdate').onchange=function(){chrome.runtime.sendMessage({cmd:'AutoUpdate',data:this.checked});};
  145. S.title=_('hintSearchLink');
  146. S.onchange=function(){chrome.runtime.sendMessage({cmd:'SetOption',data:{key:'search',value:S.value}});};
  147. $('#bDefSearch').onclick=function(){S.value=_('defaultSearch');S.onchange();};
  148. H.onchange=function(e){
  149. zip.createReader(new zip.BlobReader(e.target.files[0]),function(r){
  150. r.getEntries(function(e){
  151. function getFiles(){
  152. var i=e.shift();
  153. if(i) i.getData(writer,function(t){
  154. var c={code:t};
  155. if(vm.scripts&&(v=vm.scripts[i.filename.slice(0,-8)])) {
  156. delete v.id;c.more=v;
  157. }
  158. chrome.runtime.sendMessage({cmd:'ParseScript',data:c});
  159. count++;
  160. getFiles();
  161. }); else {
  162. alert(_('msgImported',[count]));
  163. location.reload();
  164. }
  165. }
  166. var i,vm={},writer=new zip.TextWriter(),count=0;
  167. for(i=0;i<e.length;i++) if(e[i].filename=='ViolentMonkey') break;
  168. if(i<e.length) e.splice(i,1)[0].getData(writer,function(t){
  169. try{
  170. vm=JSON.parse(t);
  171. }catch(e){
  172. vm={};
  173. console.log('Error parsing ViolentMonkey configuration.');
  174. }
  175. if(vm.values) for(z in vm.values) chrome.runtime.sendMessage({cmd:'SetValue',data:{uri:z,values:vm.values[z]}});
  176. if(vm.settings) for(z in vm.settings) chrome.runtime.sendMessage({cmd:'SetOption',data:{key:z,value:vm.settings[z],check:true}});
  177. getFiles();
  178. }); else getFiles();
  179. });
  180. },function(e){console.log(e);});
  181. };
  182. $('#bImport').onclick=function(){
  183. var e=document.createEvent('MouseEvent');
  184. e.initMouseEvent('click',true,true,window,0,0,0,0,0,false,false,false,false,0,null);
  185. H.dispatchEvent(e);
  186. };
  187. V.onclick=function(){
  188. this.disabled=true;
  189. this.innerHTML=_('buttonVacuuming');
  190. chrome.runtime.sendMessage({cmd:'Vacuum'});
  191. };
  192. V.title=_('hintVacuum');
  193. // Export
  194. var xL=$('#xList'),xE=$('#bExport'),xD=$('#cWithData');
  195. function xLoad() {
  196. xL.innerHTML='';xE.disabled=false;
  197. ids.forEach(function(i){
  198. var d=document.createElement('div'),n=map[i].obj;
  199. d.className='ellipsis';
  200. getName(d,n.custom.name||n.meta.name);
  201. xL.appendChild(d);
  202. });
  203. }
  204. xD.onchange=function(){chrome.runtime.sendMessage({cmd:'SetOption',data:{key:'withData',value:this.checked}});};
  205. xL.onclick=function(e){
  206. var t=e.target;
  207. if(t.parentNode!=this) return;
  208. t.classList.toggle('selected');
  209. };
  210. $('#bSelect').onclick=function(){
  211. var c=xL.childNodes,v,i;
  212. for(i=0;i<c.length;i++) if(!c[i].classList.contains('selected')) break;
  213. v=i<c.length;
  214. for(i=0;i<c.length;i++) if(v) c[i].classList.add('selected'); else c[i].classList.remove('selected');
  215. };
  216. function exported(o){
  217. function addFiles(){
  218. adding=true;
  219. if(!writer) { // create writer
  220. zip.createWriter(new zip.BlobWriter(),function(w){writer=w;addFiles();});
  221. return;
  222. }
  223. var i=files.shift();
  224. if(i) {
  225. if(i.name) { // add file
  226. writer.add(i.name,new zip.TextReader(i.content),addFiles);
  227. return;
  228. } else // finished
  229. writer.close(function(b){
  230. var u=URL.createObjectURL(b),e=document.createEvent('MouseEvent');
  231. e.initMouseEvent('click',true,true,window,0,0,0,0,0,false,false,false,false,0,null);
  232. xH.href=u;
  233. xH.download='scripts.zip';
  234. xH.dispatchEvent(e);
  235. writer=null;
  236. URL.revokeObjectURL(u);
  237. });
  238. }
  239. adding=false;
  240. }
  241. function addFile(o){
  242. files.push(o);
  243. if(!adding) addFiles();
  244. }
  245. var writer=null,files=[],adding=false,xH=$('#xHelper'),
  246. n,_n,names={},vm={scripts:{},settings:o.settings};
  247. if(xD.checked) vm.values={};
  248. o.scripts.forEach(function(c){
  249. var j=0;
  250. n=_n=c.custom.name||c.meta.name||'Noname';
  251. while(names[n]) n=_n+'_'+(++j);names[n]=1;
  252. addFile({name:n+'.user.js',content:c.code});
  253. vm.scripts[n]={id:c.id,custom:c.custom,enabled:c.enabled,update:c.update};
  254. if(xD.checked&&(n=o.values[c.uri])) vm.values[c.uri]=n;
  255. });
  256. addFile({name:'ViolentMonkey',content:JSON.stringify(vm)});
  257. addFile({}); // finish adding files
  258. }
  259. xE.onclick=function(e){
  260. e.preventDefault();
  261. this.disabled=true;
  262. var i,c=[];
  263. for(i=0;i<ids.length;i++)
  264. if(xL.childNodes[i].classList.contains('selected')) c.push(ids[i]);
  265. chrome.runtime.sendMessage({cmd:'ExportZip',data:{values:xD.checked,data:c}},exported);
  266. };
  267. // Script Editor
  268. var E=$('#wndEditor'),U=$('#eUpdate'),M=$('#eMeta'),
  269. mN=$('#mName'),mH=$('#mHomepage'),mR=$('#mRunAt'),
  270. mU=$('#mUpdateURL'),mD=$('#mDownloadURL'),
  271. mI=$('#mInclude'),mE=$('#mExclude'),mM=$('#mMatch'),
  272. cI=$('#cInclude'),cE=$('#cExclude'),cM=$('#cMatch'),
  273. eS=$('#eSave'),eSC=$('#eSaveClose'),T,sC=$('#sCustom');
  274. function markClean(){
  275. eS.disabled=eSC.disabled=true;
  276. }
  277. function mReset(){
  278. M.classList.add('hide');
  279. sC.innerHTML='&laquo;';
  280. var e=[],c=E.scr.custom;M.dirty=false;
  281. mN.value=c.name||'';
  282. mH.value=c.homepage||'';
  283. mU.value=c.updateURL||'';
  284. mD.value=c.downloadURL||'';
  285. switch(c['run-at']){
  286. case 'document-start':mR.value='start';break;
  287. case 'document-idle':mR.value='idle';break;
  288. case 'document-end':mR.value='end';break;
  289. default:mR.value='default';
  290. }
  291. cI.checked=c._include!=false;
  292. mI.value=(c.include||e).join('\n');
  293. cM.checked=c._match!=false;
  294. mM.value=(c.match||e).join('\n');
  295. cE.checked=c._exclude!=false;
  296. mE.value=(c.exclude||e).join('\n');
  297. }
  298. function gotScript(o){
  299. E.classList.remove('hide');
  300. E.scr=o;U.checked=o.update;
  301. T.setValueAndFocus(o.code);
  302. T.clearHistory();markClean();mReset();
  303. }
  304. function eSave(){
  305. if(M.dirty) {
  306. var c=E.scr.custom;
  307. c.name=mN.value;
  308. c.homepage=mH.value;
  309. c.updateURL=mU.value;
  310. c.downloadURL=mD.value;
  311. switch(mR.value){
  312. case 'start':c['run-at']='document-start';break;
  313. case 'idle':c['run-at']='document-idle';break;
  314. case 'end':c['run-at']='document-end';break;
  315. default:delete c['run-at'];
  316. }
  317. c._include=cI.checked;
  318. c.include=split(mI.value);
  319. c._match=cM.checked;
  320. c.match=split(mM.value);
  321. c._exclude=cE.checked;
  322. c.exclude=split(mE.value);
  323. }
  324. chrome.runtime.sendMessage({
  325. cmd:'ParseScript',
  326. data:{
  327. id:E.scr.id,
  328. code:T.getValue(),
  329. message:'',
  330. more:{
  331. custom:E.scr.custom,
  332. update:E.scr.update=U.checked
  333. }
  334. }
  335. });
  336. markClean();
  337. }
  338. function mClose(){M.classList.add('hide');}
  339. function eClose(){E.classList.add('hide');E.scr=null;}
  340. U.onchange=E.markDirty=function(){eS.disabled=eSC.disabled=false;};
  341. M.markDirty=function(){M.dirty=true;E.markDirty();};
  342. [mN,mH,mR,mU,mD,mI,mM,mE,cI,cM,cE].forEach(function(i){i.onchange=M.markDirty;});
  343. $('#bCustom').onclick=function(){
  344. var r=M.classList.toggle('hide');
  345. sC.innerHTML=r?'&laquo;':'&raquo;';
  346. };
  347. eS.onclick=eSave;
  348. eSC.onclick=function(){eSave();eClose();};
  349. E.close=$('#eClose').onclick=function(){if(confirmCancel(!eS.disabled)) eClose();};
  350. initEditor(function(o){T=o;},{save:eSave,exit:E.close,onchange:E.markDirty});
  351. // Load at last
  352. var ids,map,cache;
  353. function loadOptions(o){
  354. ids=[];map={};L.innerHTML='';
  355. cache=o.cache;
  356. o.scripts.forEach(function(i){
  357. ids.push(i.id);addItem(map[i.id]={obj:i});
  358. });
  359. $('#cUpdate').checked=o.settings.autoUpdate;
  360. S.value=o.settings.search;
  361. xD.checked=o.settings.withData;
  362. }
  363. function updateItem(r){
  364. if(!('id' in r)) return;
  365. var m=map[r.id];
  366. if(!m) map[r.id]=m={};
  367. if(r.obj) m.obj=r.obj;
  368. switch(r.status){
  369. case 0:loadItem(m,r);break;
  370. case 1:ids.push(r.id);addItem(m);break;
  371. default:modifyItem(r);
  372. }
  373. }
  374. chrome.runtime.sendMessage({cmd:'GetData'},loadOptions);
  375. chrome.runtime.onMessage.addListener(function(req,src){
  376. var maps={
  377. Vacuumed: function(){
  378. for(var i=0;i<ids.length;i++) map[ids[i]].obj.position=i+1;
  379. V.innerHTML=_('buttonVacuumed');
  380. },
  381. },f=maps[req.cmd];
  382. if(f) f(req.data,src);
  383. });
  384. var port=chrome.runtime.connect({name:'Options'});
  385. port.onMessage.addListener(updateItem);