prototype.jsを読み解く

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

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

Form.Element.Methods オブジェクト

2737: Form.Element.Methods = {
2738:   serialize: function(element) {
2739:     element = $(element);
2740:     if (!element.disabled && element.name) {
2741:       var value = element.getValue();
2742:       if (value != undefined) {
2743:         var pair = {};
2744:         pair[element.name] = value;
2745:         return Hash.toQueryString(pair);
2746:       }
2747:     }
2748:     return '';
2749:   },
2750: 

2737行目からはForm.Element.Methodsです。

まずはserialize()です。単一要素の保持している値を,name=valueの形式の文字列として返します。

disabledプロパティが偽で,nameプロパティが設定されていて,値がundefinedでなければハッシュオブジェクトを作成しHash.toQueryString()で返します。

2751:   getValue: function(element) {
2752:     element = $(element);
2753:     var method = element.tagName.toLowerCase();
2754:     return Form.Element.Serializers[method](element);
2755:   },
2756: 

2751行目からはgetValue()です。

Form.Element.Serializersにタグ名ごとのハンドラが入っているので,それを呼び出して返り値を返しています。

2757:   clear: function(element) {
2758:     $(element).value = '';
2759:     return element;
2760:   },
2761: 

2757行目からはclear()です。

単にvalueプロパティに空文字列を設定しているだけです。そのため,<input type="text">や<textarea>で使われることが前提です。

2762:   present: function(element) {
2763:     return $(element).value != '';
2764:   },
2765: 

2762行目からはpresent()です。

valueプロパティが空文字でなければ真を返します。

2766:   activate: function(element) {
2767:     element = $(element);
2768:     try {
2769:       element.focus();
2770:       if (element.select && (element.tagName.toLowerCase() != 'input' ||
2771:         !['button', 'reset', 'submit'].include(element.type)))
2772:         element.select();
2773:     } catch (e) {}
2774:     return element;
2775:   },
2776: 

2766行目からはactivate()です。

まずfocus()を呼んで,その後selectプロパティが存在し,タグが<textarea>, <select>か,<input>のtypeがtext, password, hidden, radio, checkbox ならselect()メソッドを呼んでいます。

IEでは要素がdisplay:noneやvisibility:hiddenの場合に,focus()を呼ぶと例外が発生してしまいます。それを避けるために try {} で括って例外を無視するようにしています。

2777:   disable: function(element) {
2778:     element = $(element);
2779:     element.blur();
2780:     element.disabled = true;
2781:     return element;
2782:   },
2783: 

2777行目からはdisable()です。

要素のblur()メソッドを呼んでフォーカスを外し,disabledプロパティにtrueを設定して無効化しています。

2784:   enable: function(element) {
2785:     element = $(element);
2786:     element.disabled = false;
2787:     return element;
2788:   }
2789: }
2790: 
2791: /*--------------------------------------------------------------------------*/
2792: 

2784行目からはenable()です。

こちらはdisabledプロパティにtrueを設定しているだけで,フォーカスは操作しません。

2793: var Field = Form.Element;
2794: var $F = Form.Element.Methods.getValue;
2795: 
2796: /*--------------------------------------------------------------------------*/
2797: 

2793行目ではForm.Elementの別名としてFieldを作っています。今のところ他の場所ではこれは使われていないようです。

また,2794行目ではForm.Element.Methods.getValue()の別名として$F()関数を定義しています。

Form.Element.Serializers オブジェクト

2798: Form.Element.Serializers = {
2799:   input: function(element) {
2800:     switch (element.type.toLowerCase()) {
2801:       case 'checkbox':
2802:       case 'radio':
2803:         return Form.Element.Serializers.inputSelector(element);
2804:       default:
2805:         return Form.Element.Serializers.textarea(element);
2806:     }
2807:   },
2808: 

Form.Element.Serializersには,要素に対応したハンドラであるinput, textarea, selectプロパティと,それらから呼び出されるヘルパ関数からなっています。

2799行目からはinputハンドラです。

type別に処理を分けていて,checkbox, radioの場合はinputSelector()関数を,それ以外は単にvalueを取得するtextareaハンドラを呼び出しています。

2809:   inputSelector: function(element) {
2810:     return element.checked ? element.value : null;
2811:   },
2812: 
2813:   textarea: function(element) {
2814:     return element.value;
2815:   },
2816: 

inputSelector()では,checkedプロパティが真ならvalueプロパティの値を,そうでなければnullを返します。

textareaハンドラでは,<textarea>タグと<input>タグの一部を担当します。<textarea>でもvalueプロパティで値を取得できるので,それをそのまま返しています。

2817:   select: function(element) {
2818:     return this[element.type == 'select-one' ?
2819:       'selectOne' : 'selectMany'](element);
2820:   },
2821: 
2822:   selectOne: function(element) {
2823:     var index = element.selectedIndex;
2824:     return index >= 0 ? this.optionValue(element.options[index]) : null;
2825:   },
2826: 
2827:   selectMany: function(element) {
2828:     var values, length = element.length;
2829:     if (!length) return null;
2830: 
2831:     for (var i = 0, values = []; i < length; i++) {
2832:       var opt = element.options[i];
2833:       if (opt.selected) values.push(this.optionValue(opt));
2834:     }
2835:     return values;
2836:   },
2837: 
2838:   optionValue: function(opt) {
2839:     // extend element because hasAttribute may not be native
2840:     return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
2841:   }
2842: }
2843: 
2844: /*--------------------------------------------------------------------------*/
2845: 

2817行目からはselectハンドラです。<select>タグのtypeが'select-one'かどうかによって後述するselectOne(), selectMany()関数を使い分けています。例えばXHTMLで <select multiple="multiple"> と記述されている場合,ここではselectMany()関数が使われます。

selectOne()関数ではselectedIndexプロパティに選択されている<option>タグのインデックス値が入っているので,後述するoptionValue()関数を使って値を取得します。

selectMany()関数では,optionsプロパティを使ってすべての<option>タグを調べ,selectedプロパティが真のものを配列に集めて返します。

optionValue()関数 では,<option>タグにvalue属性があればその値を,無ければ<option>タグの内側の文字列が値となるのでそれをtextプロパティから取り出して返します。

著者プロフィール

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

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