script.aculo.us の InPlaceEditor で submitOnBlur だと Safari が落ちる
script.aculo.us の InPlaceEditor を試している。
設定でカスタマイズできる部分がけっこうある割に、必要なものがなかったりして(特にコールバック系)微妙に使いづらいんだが、Safari だと不意にクラッシュする、という問題もあったり。
色々調べてみると、どうやら submitOnBlur を設定して、フォーカスリング(テキストフィールドのフォーカス時に、フィールドの周囲に出る青い線)をクリックするとお亡くなりになるらしい。
まあ、普通に Safari のバグだと思うんだが、onblur の処理を適当に遅延させると大丈夫なようなので、ticket:3717 にパッチを送っておいた。
JavaScript でコードを色づけしてくれるライブラリ google-code-prettify
Ruby のコードを色づけしてくれる Syntax を試しているうちに、このブログでもコードの色づけ(いわゆるシンタックス・ハイライト。はてなダイアリーのスーパー pre 記法みたいなやつね)をやってみたくなった。
誰でも普段は、エディタで色づけされたコードを見慣れてるわけで、やっぱり黒べったりは読みづらいといえば読みづらい。
JavaScript によるコード色づけ
ただ、このブログは WordPress で動作している。
WordPress といえば、あれか ... PHP か。なので、Ruby の Syntax ライブラリは使えない。それに、そもそも Syntax は Ruby の字句解析ライブラリとしての用途に重きを置いているためか、デフォルトで対応している言語が少ない(Ruby と XML, YAML だけ)。そのへんの不満もある。
色々迷った末(五分くらい)、JavaScript によるコード色づけを試してみることにした(WordPress のプラグインはですね、種類が多すぎて比較する気にもなれませんでした)。
問題はどのライブラリを使うか。検索してみると、Google Code にいくつか見つかった。
syntaxhighlighter は対応言語は申し分ないのだが、ちょっとオーバースペック気味だ。行番号表示やクリップボードへのコピーとかは、とりあえずいらないだろう。
一方の google-code-prettify はシンプルでいい感じ。早速、試してみることにする。
google-code-prettify
使い方は README を読めば問題ないと思う。このブログでは prototype.js を使って、こんなふうに組み込んだ。
<script src="http://metareal.org/javascripts/prototype.js" type="text/javascript" charset="utf-8"></script>
<script src="http://metareal.org/javascripts/prettify.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript" charset="utf-8">
Event.observe(window, 'load', function() {
prettyPrint();
});
</script>
この通り、HTML も色づけしてくれる。HTML に埋め込んだ JavaScript も認識されてるのはすごいな。しかも、コード部分の指定は pre 要素か code 要素の class 属性に prettyprint を指定するだけ。シンプル。
おまけ: Ruby コードの色づけ
ちなみに、Ruby コードの色づけはどうだろう。
冒頭にあげた Syntax のコードで試してみよう。
syntax-1.0.0/lib/syntax/convertors/abstract.rb
require 'syntax'
module Syntax
module Convertors
# The abstract ancestor class for all convertors. It implements a few
# convenience methods to provide a common interface for all convertors.
class Abstract
# A reference to the tokenizer used by this convertor.
attr_reader :tokenizer
# A convenience method for instantiating a new convertor for a
# specific syntax.
def self.for_syntax( syntax )
new( Syntax.load( syntax ) )
end
# Creates a new convertor that uses the given tokenizer.
def initialize( tokenizer )
@tokenizer = tokenizer
end
end
end
end
十分だな。シンボルは色づけされてないようだけど、インスタンス変数は認識されている。
Google の検索履歴を記録する JavaScript を読んでみた
Google 検索履歴では、検索クエリーの履歴だけではなく、検索結果で実際にどのページをクリックしたか、も記録している。
検索結果ページのソースコードを読んでみると、履歴の保存は JavaScript で行われているようだ。
改行やインデントを加えて読みやすくしたソースコードを基に、履歴を保存する処理や興味深い部分を紹介する。
検索クエリーの保存
if (document.images) {
new Image().src="/url?sa=Q&client=safari&rls=ja-jp&q=...";
}
まずは冒頭。新しい Image を生成することで http://www.google.com/url/ にアクセスさせている。
URL から推測するに検索クエリーを保存しているのだろう。
クリックされたページの URL を保存
クリックされたページの URL を保存する処理は、各リンクの onmousedown に JavaScript を仕込むことで実現している。
<a href="..." class=l onmousedown="return asq(event,this,'','','res','1','&sig2=...')">
リンクをクリックすると asq 関数が実行されたのち、ページに遷移する、というわけだ。
asq 関数の実装
では、asq 関数はどのような実装になっているのだろう。それなりに長いので些末な部分は削除したソースは以下の通り。
window.asq = function(d,a,f,g,k,l,m) {
if (window.XMLHttpRequest) {
var c = window.encodeURIComponent ? encodeURIComponent : escape;
var h = "", i = "";
var b = new XMLHttpRequest;
var e = d.altKey || d.metaKey;
b.open(
"GET",
"/url?&url="+c(a.href.replace(/#.*/,"")).replace(/\+/g,"%2B")+"&ei=..."+m,
true);
if (!e) {
b.onreadystatechange = function() {
if (b.readyState == 4) {
clearTimeout(j);
a.dispatchEvent(d)
}
};
var j = setTimeout(function() {
b.abort();
a.dispatchEvent(d)
},
2000);
}
b.send(null);
return e
}
return true
};
XMLHttpRequest を使って、クリックされたページの URL を非同期送信している。強調した部分では、setTimeout でタイムアウト処理をしているようだ。
IE 6 以下の場合は?
見ての通り、asq 関数の実装は XMLHttpRequest オブジェクトがあるかどうかに依存している。
では、XMLHttpRequest オブジェクトではなく、ActiveXObject 経由で非同期通信を行う IE 6 などではどうするのだろう?
実は IE 6 などでアクセスすると、asq 関数ではなく、clk 関数というものが定義されるようになっている。この関数では検索クエリーの保存と同じように、Image オブジェクトによるアクセスが行われている。
JSON はみんなが思ってるほど安全ではない
del.icio.us 経由で今日読んだ記事。
- JSON is not as safe as people think it is - Joe Walker's Blog
- http://getahead.org/blog/joe/2007/03/05/ json_is_not_as_safe_as_people_think_it_is.html
script による CSRF と JavaScript のハック的手法を組み合わせることで、たとえログイン必須にしている JSON データであっても盗まれるかもしれない、という話。
たとえば、
<script type='text/javascript' src='http://example.com/jsonservice'></script>
という script で JSON を読み込めたとする。
このままだと読み込んだ JSON のデータが評価されるだけで、どんなコードも実行されないのでそれほど問題にはならない (評価された JSON のデータはどんな変数にも代入されてないので参照できない)。
しかし、元記事に紹介されている方法で、たとえば Array のコンストラクタを再定義してやると、JSON が評価されるときに 任意のコード(どこかにデータを送信するなど)を実行できてしまう。
Firefox の <canvas> 要素バグ
Firefox の <canvas> 要素で width, height 属性を指定せず、スタイルシートで width, height を指定すると、JavaScript での描画で座標がおかしくなる。Firefox 2.0.0.1 で確認。
width, height 属性を指定すれば大丈夫。