久々の投稿。
最近、社内でもブラウザで動くシステムが増えてきている。 でも、使い勝手が悪い、クロスブラウザが考慮されてない、など、 もの申したいことも度々。
そんな時、まず最初に 『それ、BookmarkletとかUserScriptでなんとかなるんじゃない?』 と考えてしまうほど、UserScript厨化が進行している。
まぁ、実際できるんだから、いいじゃん。
で、実際UserScriptを書くときは、 Chromeの拡張機能で、UserScript実行環境でありエディタでもあるTampermonkeyを使っている。
これでデバッグ用コードを書いて動作検証した後に、 GoogleのClosure Compilerでコード圧縮してから配布/公開、 というのが、最近の基本的な流れ。
で、作業がルーチン化すると、人間どうしても、 その作業を全自動/半自動化したくなるもので。
今回は、今までTampermonkeyで書いてたコードをclosurecompilerにコピペして圧縮してたルーチン作業を、 Tampermonkeyから直接実行できるようにしてみた。 これはBookmarkletで。 ホントは、UserScriptで圧縮用ボタンでも追加したかったが、 さすがに「chrome-extension://」で始まる画面でUserScriptは実行できないらしいので
以下、コード。
<![CDATA[ (function(){ var mask; var compile=function(js_code){ var metas=js_code.match(/\/\/ ==UserScript==[\w\W]*\/\/ ==\/UserScript==\n/g); var xhr=new XMLHttpRequest(); xhr.open("POST", "http://closure-compiler.appspot.com/compile"); xhr.onreadystatechange=function(){ if (xhr.readyState==4&&xhr.status==200){ var textarea=mask.getElementsByTagName("textarea")[0]; textarea.innerHTML=(metas!=null?metas[0]+"\n":"")+JSON.parse(this.responseText).compiledCode; mask.getElementsByTagName("div")[1].style.display="inline"; mask.getElementsByTagName("input")[0].onclick=function(){ d.body.removeChild(mask); }; textarea.focus(); textarea.select(); } }; xhr.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded;charset=UTF-8'); var encoded=encodeURIComponent(js_code); xhr.send("compilation_level=SIMPLE_OPTIMIZATIONS&output_info=compiled_code&output_info=warnings&output_info=errors&output_info=statistics&compilation_level=SIMPLE_OPTIMIZATIONS&warning_level=default&output_format=json&output_info=compiled_code&js_code="+encoded); } var d=document; try{ mask=d.createElement("div"); mask.innerHTML='<div style="width: 100%; height: 100%; position: fixed; left: 0px; top: 0px; opacity: 0.7; background-color: black;"><div style="width: 80%; height: 80%; position: fixed; top: 0px; right: 0px; bottom: 0px; left: 0px; margin: auto;display:none" align="right"><textarea style="font-size:12px;width: 100%; height: 100%;background-color: white;" readonly=""><input type="button" value="閉じる">'; mask.id="mask"; mask.style.cssText="width:100%;height:100%;position:fixed;left:0;top:0;z-index:9999;"; d.body.appendChild(mask); if(location.href.indexOf('chrome-extension://dhdgffkkebhmkfjojejmpbldmpobfkfo/')==0) { var at=(function(){var tabs=d.getElementsByClassName("tv_content");for(var i=0;i<tabs.length;i++){if(tabs[i].id.indexOf("_details_c")>=0&&tabs[i].style.display!="none")return tabs[i]}return null;})(); var a=at.getElementsByClassName("CodeMirror-scroll")[0]; var b=$(at.getElementsByClassName("CodeMirror-editor")[0]); var c=0,cl=0; var allsrc=[]; var pos=a.scrollTop; if(pos==0)a.scrollTop=1; var onscroll=function(){ var s=at.getElementsByClassName("CodeMirror-scroll")[0].innerText; var lines=s.match(/(?:\n|^)[1-9]{1}\d*/g); if(cl==parseInt(lines[lines.length-1])){ a.removeEventListener("scroll",onscroll); a.scrollTop=pos; compile(allsrc.join('\n')) return; } cl=parseInt(lines[lines.length-1]); c=a.scrollTop; var m=0; var n=at.getElementsByClassName("CodeMirror-scroll")[0].innerText.replace( /(?:\n|^)([1-9]\d*)\n([^\n]*)/g, function(a,b,c){ if(m==0)m=parseInt(b); return "@"+b+","+c+""; }); var src=n.split(/\@[1-9]\d*,/); src.forEach(function(e,i,a){ if(allsrc[i+m-1]==null)allsrc[i+m-1]=e; }); var before=a.scrollTop; a.scrollTop+=b.height(); var after=a.scrollTop; if(before==after)onscroll(); } a.addEventListener("scroll", onscroll); if(a.scrollTop==0)onscroll(); else a.scrollTop=0; } }catch(e){ if((mask=d.getElementById("mask"))!=null){ d.body.removeChild(mask); } } })();]]>
前半は、Closure Compilerに投げる関数の宣言で、 これはREST APIがあるので、XMLHttpRequestでPOSTするだけ。
Tampermonkey固有のコードは30行目付近から。 面倒だったのは、Tampermonkeyのエディタから、表示中のソースコードを取得する部分。
どうもこのエディタ、どこかの要素に全てのソースコードを保持してる訳ではなく、 表示されている部分と前後±αしか保持してなく、 残りはスクロールする度にロードされていた。
なので、上記のコードでは、一旦一番上までスクロールして、 自動でスクロールしながら、上の行から順番に配列に確保し、 最後にArray.joinで(改行コードを挟みながら)連結している。
ソースコードが出来上がれば、後はClosure Compilerに投げるだけ。
このコード自体をClosure Compilerで圧縮して、 Bookmarkletとして使っている。
一応(何がなんだかわからない)圧縮版も。 <![CDATA[javascript:(function(){var c,m=function(b){var h=b.match(/\/\/ ==UserScript==[\w\W]*\/\/ ==\/UserScript==\n/g),a=new XMLHttpRequest;a.open("POST","http://closure-compiler.appspot.com/compile");a.onreadystatechange=function(){if(4==a.readyState&&200==a.status){var b=c.getElementsByTagName("textarea")[0];b.innerHTML=(null!=h?h[0]+"\n":"")+JSON.parse(this.responseText).compiledCode;c.getElementsByTagName("div")[1].style.display="inline";c.getElementsByTagName("input")[0].onclick=function(){d.body.removeChild(c)}; b.focus();b.select()}};a.setRequestHeader("Content-Type","application/x-www-form-urlencoded;charset=UTF-8");b=encodeURIComponent(b);a.send("compilation_level=SIMPLE_OPTIMIZATIONS&output_info=compiled_code&output_info=warnings&output_info=errors&output_info=statistics&compilation_level=SIMPLE_OPTIMIZATIONS&warning_level=default&output_format=json&output_info=compiled_code&js_code="+b)},d=document;try{if(c=d.createElement("div"),c.innerHTML='<div style="width: 100%; height: 100%; position: fixed; left: 0px; top: 0px; opacity: 0.7; background-color: black;"><div style="width: 80%; height: 80%; position: fixed; top: 0px; right: 0px; bottom: 0px; left: 0px; margin: auto;display:none" align="right"><textarea style="font-size:12px;width: 100%; height: 100%;background-color: white;" readonly=""><input type="button" value="\u9589\u3058\u308b">', c.id="mask",c.style.cssText="width:100%;height:100%;position:fixed;left:0;top:0;z-index:9999;",d.body.appendChild(c),0==location.href.indexOf("chrome-extension://dhdgffkkebhmkfjojejmpbldmpobfkfo/")){var e=function(){for(var b=d.getElementsByClassName("tv_content"),a=0;a<b.length;a++)if(0<=b[a].id.indexOf("_details_c")&&"none"!=b[a].style.display)return b[a];return null}(),a=e.getElementsByClassName("CodeMirror-scroll")[0],n=$(e.getElementsByClassName("CodeMirror-editor")[0]),k=0,g=[],l=a.scrollTop; 0==l&&(a.scrollTop=1);var f=function(){var b=e.getElementsByClassName("CodeMirror-scroll")[0].innerText.match(/(?:\n|^)[1-9]{1}\d*/g);if(k==parseInt(b[b.length-1]))a.removeEventListener("scroll",f),a.scrollTop=l,m(g.join("\n"));else{k=parseInt(b[b.length-1]);var c=0;e.getElementsByClassName("CodeMirror-scroll")[0].innerText.replace(/(?:\n|^)([1-9]\d*)\n([^\n]*)/g,function(a,b,d){0==c&&(c=parseInt(b));return"@"+b+","+d+""}).split(/\@[1-9]\d*,/).forEach(function(a,b,d){null==g[b+c-1]&&(g[b+c-1]=a)}); b=a.scrollTop;a.scrollTop+=n.height();b==a.scrollTop&&f()}};a.addEventListener("scroll",f);0==a.scrollTop?f():a.scrollTop=0}}catch(p){null!=(c=d.getElementById("mask"))&&d.body.removeChild(c)}})();]]>












