2006-01-30

JavaScriptでDebugScreenを表示する

デモ、IEかFirefox
http://la.ma.la/misc/js/debugscreen/

IEとFirefoxではwindow.onerrorを設定するとJavaScript全体のエラーを補足できます。さらに返値をtrueにすると標準のエラーダイアログを抑制できます。

簡単なサンプルはこんな感じ。
window.onerror = function(mes,file,num){
    alert([
        "file    : " + file,
        "line    : " + num,
        "message : " + mes
    ].join("\n"));
    return true;
}

あまり細かい情報を取得できるわけではないので、例外処理に使ったりはできないのですが、エラーメッセージを親切にしたりできるかもしれません。

そんなわけで、ファイル名と行番号わかるなら自分自身をXMLHttpRequestで受信してエラー行付近を切り出したりできるんじゃないかと思って適当に作ってみた。arguments.callee.callerを使うと関数の呼び出し元がわかるんだけどwindow.onerrorの呼び出し元がIEじゃないとわからないようだった。

あんまり役に立たないような気もするんだけどCatalystとかSledgeとかCGI::ApplicationとかでDebugScreenがブームになってたので作ってみた。遅いけど。

JavaScriptでDebugScreen、その2

更新しました。ライブラリ化と適当にドキュメントを書いた。
http://la.ma.la/misc/js/debugscreen/

実際に使ってみたりしながら改良中。プラグイン方式で任意のオブジェクトを表示できるようにしてみました。
関数を登録すると実行結果を返すので複雑なこともできます。サーバーにエラー投げるとかも、まあ、できるけど、本番環境でやるのはおすすめできない。

あとは、強制的にスコープを保存する方法を思いついたのでローカル変数の内容をダンプしたりできるようにしようかな、と、考えている。
var saveVars = "window.__args__ = arguments;(" + function(){
    window.recall = function(expr){
        if(expr == "arguments") return window.__args__;
        return eval("(" + expr + ")");
    }
} + ")()";

function test(){
    eval(saveVars); // 環境保存
    var test = "aiueo";
};
function hoge(){ return test(1,2,3) }
hoge();

alert(recall("test")); // aiueo
alert(recall("arguments")[0]); // 1
alert(recall("arguments").callee) // function test(){ ... }
alert(recall("arguments").callee.caller) // null

evalを使って「evalで任意の変数を取り出すクロージャ」を定義し、環境を無理やり外に引っ張り出しています。関数の呼び出しが終わった後でローカル変数を呼び戻す。適当な語彙が思い浮かばなかったので、とりあえずrecallで。

argumentsを保持してやれば呼び出し元を辿れるかな、と考えていたのだけれど、最後のは上手くいかない。どうやら関数の呼び出しが終わるとFunction#callerプロパティは破棄されてしまうようだ。

IE限定でarguments.caller.calleeだと上手くいったりする。arguments.callerは関数の呼び出し元のargumentsオブジェクトを参照する。Firefoxでは既に廃止されているようだ。

ここら辺はECMA非準拠で環境依存が大きいのだけど、組み込めるようだったら組み込みたい。

2006-01-24

はてなに入っ

Wiki小話に行くついで、渋谷で暇だったのではてなに遊びにいった。
しなもん日記のRSSを全文配信にしてくれと言うのを忘れた。

2006-01-20

Firefoxでの開発を高速化する自動リロードスクリプト

以前にも書いたとおり萌ディタとSleipnirAPIを駆使して、htmlその他ソースファイルをいじると保存のタイミングに合わせてSleipnirのアクティブタブがリロードされるようになっているわけなのですが、近頃Firefox1.5をメインに使うようになってしまったのでFirefoxでも上手く動くようにしようという話。

もちろん自動リロード機能を提供する拡張があるのは知ってるんだけど、編集のタイミングと関係なく1秒ごとにリロードさせたらせわしなくて仕方ない。あくまで保存のタイミングに合わせてブラウザを更新したい。

最初は萌ディタからFirefoxにコマンドラインでブックマークレットを渡すというのをやってみたのだけれど、どうにも手元の環境では上手く動かない。新しいタブでブックマークレットを開いてしまったりする。WSHでFirefoxにフォーカスを合わせてF5を送るとかもやってみたんだけど萌ディタにフォーカスを戻す方法がわからない。

そんなわけなのでエディタに依存せず、完全にブラウザの側で何とかすることにした。
XMLHttpRequestで自分自身を取得してファイルの内容に変更があったら表示を更新するようにする。
// 今開いてるページに変更があったらリロード
setInterval(function(){
    var self = arguments.callee;
    var req = new XMLHttpRequest;
    req.open("GET",location.href,true);
    req.onload = function(){
        (self.old && req.responseText != self.old) && location.reload(true);
        self.old = req.responseText;
    };
    req.send(null);
},1000);

これだと、自分自身のファイルしか見ていないので外部CSSなんかを変更したときにリロードされない。そこで(全部見張るようにしても良いんだろうけど)トリガーとなるファイルを手動で指定できるブックマークレットにしてみた。スタイルシートをいじっているときはstyle.cssなど指定すればスタイルシートの更新に合わせてページが再描画される。

このページで起動されると困るのでローカルファイル専用。
ブックマークレット : AutoReload

で、いちいち実行するのが面倒くさいのでGreasemonkeyスクリプトにしてみた。
ローカルファイルの場合、ファイルの更新を検知して自動で再表示するようになる。
http://la.ma.la/misc/userjs/AutoReload.user.js

User Script Commands から更新を検出するファイルとタイマーの周期を設定できるようにした。デフォルトは今見ているファイルと1000ミリ秒。

後は萌ディタで保存するたびに
perl -e "open(FH,'>c:/lastmod');print FH time;"

こんなワンライナーが走るようにしておいた。Greasemonkeyの側では「file:///c:/lastmod」を見張らせる。サーバー上で開発する場合はlocalhost/lastmodなんかに適宜変えるようにすれば良いだろう。

----
ちなみに。

GM_xmlhttpRequestは他ドメインは読めるがローカルファイルは読めない。ローカルファイルからでも読めない。Greasemonkey0.6.4ではXMLHttpRequestが使えなくなっているため、代わりにunsafeWindow.XMLHttpRequestを使った。この場合、同一ドメイン、及び、ローカルファイルからローカルファイルへのアクセスができる。

2006-01-16

2006-01-10

Firefoxでテキストをクリップボードにコピーする方法

動作デモ
http://la.ma.la/misc/js/setclipboard_for_firefox.html

Firefox1.5 + FlashPlayer8.5で動作確認してます。Opera8.5では動いたがOpera9では動作せず。Safariは知らない。FlashPlayerのバージョンによっても何か違うのかもしれない。

元ネタ
http://a-h.parfe.jp/einfach/archives/2005/0706043145.html

IEではデフォルト設定でブラウザからクリップボードの読み書きができる、というのは割と有名な話ですが、Flashを使うとIE以外でもクリップボードにテキストをコピーすることができます。上書きのみで読み込みはできないようなので多少は安心です。(クリップボードが勝手に置き換わってしまう、という悪戯はできる)

で、このFlashを使ったクリップボード操作に使っているsetClipboard.swfというファイルは103bytesと大変小さいのですが、swfファイルをサーバーに設置するのが面倒くさいという人向けにdataスキームを使って単体で動くようにしよう、という話。

dataスキームというのは「data:なんとか」という形式のURIでファイル自体を表すことができます。Firefoxのブックマークにfaviconを埋め込んだり、CSSに直接画像を埋め込んだり、Greasemonkeyに画像を埋め込んだり、ブラウザ上でアイコン作成したりするのに使われています。

data URIを作成するには
Perlスクリプト、バイナリファイルも変換できる
http://software.hixie.ch/utilities/cgi/data/data

副産物、クライアントサイドで動くもの、テキストのみ
http://la.ma.la/misc/js/data.html

を使います。

----
で、最初にとりあえずローカルで動くものができたのだけどサーバーにアップしたら動かない。どうもFlashの側でインターネットゾーンとdataスキームでのセキュリティ上の区分があるようで、多分dataスキームはローカルファイルとして扱われているような気がする。

実験1 : setClipboard.swfをdataスキームに変換したもの、ローカルに保存すれば動く
http://la.ma.la/misc/js/setClipboard.html

実験2 : 同じ階層にsetClipboard.swfを設置、当然動く
http://la.ma.la/misc/js/setClipboard2.html

実験3 : 外部ドメインにsetClipboard.swfを設置
http://la.ma.la/misc/js/setClipboard3.html

実験3が成功したので、どっかしら適当なサーバーにsetClipboard.swfを置いておけばブックマークレットからも使える、ということにはなるのだけど、適当なサーバーにリファラが残るのがイヤだなあ、と思ったので何とかして単体ファイルで動かせるようにしたものが、これ。
ファイル単体で完結して動く。
http://la.ma.la/misc/js/setclipboard_for_firefox.html

「表示するとクリップボードを指定文字列で上書きするHTMLファイル」をdataスキームを使って動的生成し、それをIFRAMEに読み込む、という回りくどい方法を取っています。

dataスキーム動的生成に使ってるutf16to8とbase64encodeは高度なJavaScript技集から。
http://www.onicos.com/staff/iz/amuse/javascript/expert/

これでGreasemonkeyでクリップボードにコピーとか作れますね。最初の目的はGreasemonkeyでTSS Clipborad Player自動演奏でした。飽きたのであとはまかせた。

----
追記: 2005-01-10

Firefoxではbase64が組み込み関数(btoa,atob)で使えるようなのでFirefox専用で短くしてみた。わずか27行。Greasemonkey組み込みなど、ご自由にどうぞ。
http://la.ma.la/misc/js/setclipboard.txt

Wikipedia日本語版全文検索AutoPagerを作った

Hyper Estraierを使ったWikipedia日本語版全文検索が大変素晴らしいのでGoogleAutoPagerの移植。

Firefox1.5とGreasemonkey0.6.4で動作確認してます。
http://la.ma.la/misc/userjs/estseekautopager.user.js

ついでに色々と直してます。ローディングのエフェクトを入れたり、全体的に変なテクニックを駆使したり。

- 無名関数を再帰処理させる。
- GreasemonkeyからDOMParserを使う
- valueOfメソッドをいじって残りスクロール量を返すオブジェクトを作る

あたりは何かの参考になるかもしれません。

2006-01-01

全てのウェブサイトを正月対応にするGreasemonkeyスクリプト

さっき思いついたので作ってみた。
http://la.ma.la/misc/userjs/akeome.user.js

新年早々ネット巡回しているとcron仕込んで新年ぴったりに新年画像に差し替えているようなサイトをちらほら見かけたりしますが、な
んの変化も見られない冠婚葬祭を重視しないサイトが非常に多くてガッカリそんなアナタに朗報このGreasemonkeyスクリプトを使えばどんなウェブサイトでもお正月ムードに変更してくれます。

とかなんとか。

mixiとか見るといい感じになると思います。
今年もよろしくお願いします。