いきなり後ろ向きなエントリーでちょっと恐縮なのです(汗)
趣味の範囲を超えて『仕事』でMooToolsを使用していると、ブラウザの対応範囲の問題というモノには常に悩まされます。
具体的には、一番困るのが「古いブラウザにも対応して欲しい」というモノ。
それはなんとか説得できたとして、次に来るのが「じゃあ、せめて非対応ブラウザでエラーが出ないようにして欲しい」。
そこで、非対応ブラウザでエラーが出ないようにするMooToolsの微カスタマイズをお教えします。
と言っても、元のソースもロジックも触らず、ちょっとだけ書き加えるだけです。
0. MooToolsをダウンロード
まずは、MooToolsの準備。
サイトから、download を選択し、必要なオプションを選択してダウンロードします。
『Choose the Components you need』は、もちろん必要なモノだけでOKです。初めてでよく分からないという人は、全てにチェックを入れてしまえばOK。その際、下から順にチェックを入れると簡単です。コンポーネントの依存性がある場合、必要なコンポーネントにも自動的にチェックが入りますので。
ここで、ポイントは『Choose compression type』オプション。
クリックするとラジオボタン(のようにデザインされたオプション群)が表示されますが、一番上の「JavaScript Packer」を選択します(何もしていなければデフォルトで選択されていると思います)。
これを選択する理由は、「後の作業が一番分かりやすいから」。
以降、この「JavaScript Packer」オプションでダウンロードされたモノとして続けます。
0-1. MooTools1.2b1の場合
2007/11/22 現在、MooToolsの最新ベータ版 ver.1.2b1 が公開されています。
そちらのダウンロードページを見ると、『Choose compression type』オプションにまだ「JavaScript Packer」が用意されていません。
1.2b1 でかつPackerで圧縮されたモノを使用したい場合は、ご自分でDean Edwards Packerのサイトで圧縮してみてください。
ただし自己責任でお願いします。
1. .jsファイルの編集
(「JavaScript Packer」オプションでダウンロードした場合、).jsファイルをテキストエディタで開くと、中身はおおざっぱに以下のようになっています。
1: //MooTools, My Object Oriented Javascript Tools. Copyright (c) 2006-2007 Valerio Proietti, <http://mad4milk.net>, MIT Style License.
2:
3: eval(function(p,a,c,k,e,d){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};...(長いので以下省略)
1行目はライセンス表示、2行目は空行、3行目は、MooToolsのすべての(選択された)コンポーネントのコードを圧縮した長い1行(eval()1文)になっています。
この3行目の前と、3行目の後(=ファイルの最後尾)に、それぞれ以下の内容を挿入します。
if((window.ActiveXObject)||(document.childNodes&&!document.all&&!navigator.taintEnabled)||(document.getBoxObjectFor!=null)||window.opera)/*@cc_on @if (@_win32 && @_jscript_version > 5.5) @*/
//@end
つまり全体として、以下のようになります。
1: //MooTools, My Object Oriented Javascript Tools. Copyright (c) 2006-2007 Valerio Proietti, <http://mad4milk.net>, MIT Style License.
2:
3: if((window.ActiveXObject)||(document.childNodes&&!document.all&&!navigator.taintEnabled)||(document.getBoxObjectFor!=null)||window.opera)/*@cc_on @if (@_win32 && @_jscript_version > 5.5) @*/
4: eval(function(p,a,c,k,e,d){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};...(長いので以下省略)
5: //@end
これで終わりです。
MooTools非対応ブラウザでは、MooToolsは一切機能しません。
この.jsファイルを使用すればOK、というワケです。
2. 非対応ブラウザでエラーを出さないスクリプト記述
上記のように加工した.jsファイルを使用すると、MooToolsを使用している前提で記述したスクリプトは、そのままだと非対応ブラウザだとエラーになってしまいます。(対応ブラウザなら問題ありません。)
そこで、エラーを出さないようにするためにもう一工夫。
MooToolsを使用したい箇所を、以下のようなif文ブロックで括ります。
if (window.MooTools) {
// MooToolsの機能を利用したスクリプトの記述
}
これは、MooToolsが有効ならば、グローバルな変数(≒window オブジェクトに設定されたプロパティ)にMooToolsというオブジェクトが設定されるからです。
それが有効かどうかで、MooToolsが使えるかどうかを判別する、と言うわけです。
3. おまけ:技術情報
念のため、.jsファイル内に追記した記述がどのような意味なのかを簡単に解説。
これは実は、MooTools(v1.1x)内のブラウザ判別ルーチンをほぼそのまま拝借しているだけです。
興味のない方は読み飛ばしてください。
3行目のifの条件節は、「||」(論理和)で4つに別れます。
最初が「IEかどうか」、2番目が「Safari(およびそれと同じWebKitを利用したブラウザ)かどうか」、3番目が「Firefox、Netscape等のGeckoエンジンを利用したブラウザかどうか」、4番目は「Operaかどうか」(まんま)です。
2番目の「WebKitかどうか」についてのみ詳細。その中が更に「&&」で3つに別れます。
最初は「document.childNodes」が有効か(=DOMが有効か)。これはほとんどのモダンブラウザなら有効です。
一つ飛ばして3番目は、「navigator.taintEnabled が無効か」。
navigator.taintEnabled() というのは、「ユーザーに非通知でデータ送信が可能かどうか(データテイント機能の使用有無)を返すメソッド」です。「何それ?」て思われた方、ご安心ください。Netscape Navigator 3.x の時代の、古い古ーい仕様で、データテイント機能は現在使われておりません。多くのブラウザは、ただfalseを返すだけです。
ただしSafari(WebKit)では、このメソッドそのものを定義していません。よって「!navigator.taintEnabled が true」=「navigator.taintEnabled()が定義されていない」=「Safari(WebKit)」という判別になるのです。
じゃぁ2番目の「!document.all」は何なのか、というと。分かる方は分かると思いますが、「document.all」はIE固有のプロパティです。つまりこれはIEを除外するための記述です。(実際にはOperaも除外されてしまいますけれど)。
なぜこれが必要なのかというと、どうやらIEでは、後ろに「()」をつけない「navigator.taintEnabled」を記述すると「オブジェクトまたはプロパティは存在しません」というエラーになってしまうようなのです。それを避けるための記述、ということですね。
ただその前に「window.ActiveXObject」でIEかどうかは判別できているはずなので、やっぱりここでは要らないような気もしますけれど、一応、念のため付加してあります。
ifの条件節の後に続くコメントは、IE固有の「条件付きコンパイル」の記述です。
そういう前提で眺めてみれば大体分かると思いますので、さらっと。ここでは、「WindowsでかつIE5.5より上のバージョン(=WinIE6以上)」を判定しています。つまりWinIE5.5以下やmacIEを排除しています。
ちなみにファイル最後尾に追記した「//@end」は、この条件付きコンパイル内の「@if」に対応する「if文(ブロック)の終わり」を表しています。
4. 応用・発展性
今回は、私が実際に仕事で(必要に迫られて)書いたものですが、同じような記述を応用すれば、MooTools以外のJavaScriptライブラリ使用時にも流用・転用できると思います。
またMooToolsでも、理由があってPacker圧縮したものを使用できない(あるいはPackerが信用できない)という場合でも、ちょっと書き方を変えれば利用できるはずです。
例えば、追記する記述中の、3行目の最後尾(条件付きコンパイルコメントの終わりの「*/」の後)に「{」を、最終行の「//@end」の前に「}」を付ける↓
if((window.ActiveXObject)||(document.childNodes&&!document.all&&!navigator.taintEnabled)||(document.getBoxObjectFor!=null)||window.opera)/*@cc_on @if (@_win32 && @_jscript_version > 5.5) @*/{
}//@end
これだけで、他の多くのパターン(特にPackerを使用できない/したくない場合)に応用できるはずです。
(ただし実験していないので、何か問題が起きても私は保証できかねますm(_ _)m)