prototype.jsを読み解く

第9回 Prototypeライブラリ(2621~2845行目)

この記事を読むのに必要な時間:およそ 7 分

Prototype 1.6.0とscript.aculo.us 1.8.0

script.aculo.us 1.8.0がアナウンスされ,Prototypeも1.6.0のタグが打たれたようです。

新機能の部分が枯れるまではまだしばらくは1.5.1.1でいいとは思いますが,Prototypeに依存するライブラリも徐々に1.6.0に移行していくと思われるので,早いうちから慣れておいたほうがよいかもしれません。

では,今回は少なめですが,主にForm関係のクラスたちを見ていきます。

$$() 関数

2621: function $$() {
2622:   return Selector.findChildElements(document, $A(arguments));
2623: }

2621行目からは$$()関数です。

先ほどのSelector.findChildElements()をdocumentトップから検索するようにしたショートカット関数となっています。

Form オブジェクト

2624: var Form = {
2625:   reset: function(form) {
2626:     $(form).reset();
2627:     return form;
2628:   },
2629: 

2624行目からはFormオブジェクトです。reset(), serializeElements()しか定義されていませんが,Element.addMethods()でObject.extend(Form, Form.Methods)されているので,最終的にはForm.Methodsのメソッドも持つことになります。

2625行目からのreset()は,ブラウザ側のHTMLFormElementインターフェイスのreset()を呼んでいるだけです。

2630:   serializeElements: function(elements, getHash) {
2631:     var data = elements.inject({}, function(result, element) {
2632:       if (!element.disabled && element.name) {
2633:         var key = element.name, value = $(element).getValue();
2634:         if (value != null) {
2635:                 if (key in result) {
2636:             if (result[key].constructor != Array) result[key] = [result[key]];
2637:             result[key].push(value);
2638:           }
2639:           else result[key] = value;
2640:         }
2641:       }
2642:       return result;
2643:     });
2644: 
2645:     return getHash ? data : Hash.toQueryString(data);
2646:   }
2647: };
2648: 

2630行目からはserializeElements() です。

渡された要素の配列を,Array.inject({})を使ってループ処理します。そのイテレータ関数内では,disabledプロパティが偽で,nameプロパティがセットされているものだけが対象になっています。また,同じnameを持つ要素が複数出てきた場合は,値を配列として格納するようになっています。

各フォーム要素の値を得るにはgetValue() (定義は Form.Element.Methods.getValue())を用いています。

最後に,getHashフラグが真ならハッシュのまま,そうでなければtoQueryString()して文字列形式で返しています。

Form.Methods オブジェクト

2649: Form.Methods = {
2650:   serialize: function(form, getHash) {
2651:     return Form.serializeElements(Form.getElements(form), getHash);
2652:   },
2653: 

2649行目からはForm.Methodsオブジェクトです。結局FormにObject.extend()するので,なぜわざわざ分割しているのかは不明です。

2650行目からはserialize()です。これは次のgetElements()を使って指定されたフォーム以下の入力要素の一覧を取得し,それを先ほどのForm.serializeElements()に渡しています。

2654:   getElements: function(form) {
2655:     return $A($(form).getElementsByTagName('*')).inject([],
2656:       function(elements, child) {
2657:         if (Form.Element.Serializers[child.tagName.toLowerCase()])
2658:           elements.push(Element.extend(child));
2659:         return elements;
2660:       }
2661:     );
2662:   },
2663: 

2654行目からはgetElements()です。

フォーム要素を渡すと,それ以下でgetElementsByTagName('*')で全タグを取得し,Form.Element.Serializersにシリアライズ用ハンドラが存在するなら対応している要素とみなして返り値用の配列にpush()します。具体的には<input>, <textarea>, <select>に対応しています。

2664:   getInputs: function(form, typeName, name) {
2665:     form = $(form);
2666:     var inputs = form.getElementsByTagName('input');
2667: 
2668:     if (!typeName && !name) return $A(inputs).map(Element.extend);
2669: 
2670:     for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
2671:       var input = inputs[i];
2672:       if ((typeName && input.type != typeName) || (name && input.name != name))
2673:         continue;
2674:       matchingInputs.push(Element.extend(input));
2675:     }
2676: 
2677:     return matchingInputs;
2678:   },
2679: 

2664行目からはgetInputs()です。

typeNameに'radio'などと指定して限定したり,さらにnameを指定して絞り込んだりできます。

typeName, nameの両方とも指定されていなければ,指定されているフォーム要素以下の<input>タグすべてを返します。

そうでなければ,取得した<input>タグをループして,typeName, nameの指定に沿ったものを集めてそれだけを返しています。

著者プロフィール

栗山淳(くりやまじゅん)

S2ファクトリー株式会社株式会社イメージソース所属。
本業はWeb制作会社の裏方。得意分野はFreeBSDやPerlのはずだが,必要に迫られるとHTML/CSSやJavaScriptも書く。

コメント

コメントの記入