Automatic installer lang files (20110214)
[moodle.git] / lib / form / form.js
blob42b9316ae2aba830725526596845fa48d270d347
1 /**
2  * This file contains JS functionality required by mforms and is included automatically
3  * when required.
4  */
6 // Namespace for the form bits and bobs
7 M.form = M.form || {};
9 /**
10  * Initialises the show advanced functionality and events.
11  * This should only ever happen ONCE per page.
12  *
13  * @param {YUI} Y
14  * @param {object} config
15  */
16 M.form.initShowAdvanced = function(Y, config) {
17     if (M.form.showAdvanced) {
18         return M.form.showAdvanced;
19     }
20     var showAdvanced = function(config) {
21         showAdvanced.superclass.constructor.apply(this, arguments);
22     };
23     showAdvanced.prototype = {
24         _advButtons : [],
25         _advAreas : [],
26         _stateInput : null,
27         initializer : function() {
28             this._advAreas = Y.all('form .advanced');
29             this._advButtons = Y.all('.showadvancedbtn');
30             if (this._advButtons.size() > 0) {
31                 this._stateInput = new Y.NodeList(document.getElementsByName('mform_showadvanced_last'));
32                 this._advButtons.on('click', this.switchState, this);
33             }
34         },
35         /**
36          * Toggles between showing advanced items and hiding them.
37          * Should be fired by an event.
38          */
39         switchState : function(e) {
40             e.preventDefault();
41             if (this._stateInput.get('value')=='1') {
42                 this._stateInput.set('value', '0');
43                 this._advButtons.setAttribute('value', M.str.form.showadvanced);
44                 this._advAreas.addClass('hide');
45             } else {
46                 this._stateInput.set('value', '1');
47                 this._advButtons.setAttribute('value', M.str.form.hideadvanced);
48                 this._advAreas.removeClass('hide');
49             }
50         }
51     };
52     // Extend it with the YUI widget fw.
53     Y.extend(showAdvanced, Y.Base, showAdvanced.prototype, {
54         NAME : 'mform-showAdvanced'
55     });
56     M.form.showAdvanced = new showAdvanced(config);
57     return M.form.showAdvanced;
60 /**
61  * Initialises a manager for a forms dependencies.
62  * This should happen once per form.
63  */
64 M.form.initFormDependencies = function(Y, formid, dependencies) {
66     // If the dependencies isn't an array or object we don't want to
67     // know about it
68     if (!Y.Lang.isArray(dependencies) && !Y.Lang.isObject(dependencies)) {
69         return false;
70     }
72     /**
73      * Fixes an issue with YUI's processing method of form.elements property
74      * in Internet Explorer.
75      *     http://yuilibrary.com/projects/yui3/ticket/2528030
76      */
77     Y.Node.ATTRS.elements = {
78         getter: function() {
79             return Y.all(new Y.Array(this._node.elements, 0, true));
80         }
81     };
83     // Define the dependency manager if it hasn't already been defined.
84     M.form.dependencyManager = M.form.dependencyManager || (function(){
85         var dependencyManager = function(config) {
86             dependencyManager.superclass.constructor.apply(this, arguments);
87         };
88         dependencyManager.prototype = {
89             _form : null,
90             _depElements : [],
91             _nameCollections : [],
92             initializer : function(config) {
93                 var i = 0, nodeName;
94                 this._form = Y.one('#'+formid);
95                 for (i in dependencies) {
96                     this._depElements[i] = this.elementsByName(i);
97                     if (this._depElements[i].size() == 0) {
98                         continue;
99                     }
100                     this._depElements[i].each(function(node){
101                         nodeName = node.get('nodeName').toUpperCase();
102                         if (nodeName == 'INPUT') {
103                             if (node.getAttribute('type').match(/^(button|submit|radio|checkbox)$/)) {
104                                 node.on('click', this.checkDependencies, this);
105                             } else {
106                                 node.on('blur', this.checkDependencies, this);
107                             }
108                             node.on('change', this.checkDependencies, this);
109                         } else if (nodeName == 'SELECT') {
110                             node.on('change', this.checkDependencies, this);
111                         } else {
112                             node.on('click', this.checkDependencies, this);
113                             node.on('blur', this.checkDependencies, this);
114                             node.on('change', this.checkDependencies, this);
115                         }
116                     }, this);
117                 }
118                 this._form.get('elements').each(function(input){
119                     if (input.getAttribute('type')=='reset') {
120                         input.on('click', function(){
121                             this._form.reset();
122                             this.checkDependencies();
123                         }, this);
124                     }
125                 }, this);
127                 return this.checkDependencies(null);
128             },
129             /**
130              * Gets all elements in the form by thier name and returns
131              * a YUI NodeList
132              * @return Y.NodeList
133              */
134             elementsByName : function(name) {
135                 if (!this._nameCollections[name]) {
136                     var elements = [];
137                     this._form.get('elements').each(function(){
138                         if (this.getAttribute('name') == name) {
139                             elements.push(this);
140                         }
141                     });
142                     this._nameCollections[name] = new Y.NodeList(elements);
143                 }
144                 return this._nameCollections[name];
145             },
146             /**
147              * Checks the dependencies the form has an makes any changes to the
148              * form that are required.
149              *
150              * Changes are made by functions title _dependency_{dependencytype}
151              * and more can easily be introduced by defining further functions.
152              */
153             checkDependencies : function(e) {
154                 var tolock = [],
155                     tohide = [],
156                     dependon, condition, value,
157                     lock, hide, checkfunction, result;
158                 for (dependon in dependencies) {
159                     if (this._depElements[dependon].size() == 0) {
160                         continue;
161                     }
162                     for (condition in dependencies[dependon]) {
163                         for (value in dependencies[dependon][condition]) {
164                             lock = false;
165                             hide = false;
166                             checkfunction = '_dependency_'+condition;
167                             if (Y.Lang.isFunction(this[checkfunction])) {
168                                 result = this[checkfunction].apply(this, [this._depElements[dependon], value, e]);
169                             } else {
170                                 result = this._dependency_default(this._depElements[dependon], value, e);
171                             }
172                             lock = result.lock || false;
173                             hide = result.hide || false;
174                             for (var ei in dependencies[dependon][condition][value]) {
175                                 var eltolock = dependencies[dependon][condition][value][ei];
176                                 if (hide) {
177                                     tohide[eltolock] = true;
178                                 }
179                                 if (tolock[eltolock] != null) {
180                                     tolock[eltolock] = lock || tolock[eltolock];
181                                 } else {
182                                     tolock[eltolock] = lock;
183                                 }
184                             }
185                         }
186                     }
187                 }
188                 for (var el in tolock) {
189                     this._disableElement(el, tolock[el]);
190                     if (tohide.propertyIsEnumerable(el)) {
191                         this._hideElement(el, tohide[el]);
192                     }
193                 }
194                 return true;
195             },
196             /**
197              * Disabled all form elements with the given name
198              */
199             _disableElement : function(name, disabled) {
200                 var els = this.elementsByName(name);
201                 els.each(function(){
202                     if (disabled) {
203                         this.setAttribute('disabled', 'disabled');
204                     } else {
205                         this.removeAttribute('disabled');
206                     }
207                 })
208             },
209             /**
210              * Hides all elements with the given name.
211              */
212             _hideElement : function(name, hidden) {
213                 var els = this.elementsByName(name);
214                 els.each(function(){
215                     var e = els.ancestor('.fitem');
216                     if (e) {
217                         e.setStyles({
218                             display : (hidden)?'none':''
219                         })
220                     }
221                 });
222             },
223             _dependency_notchecked : function(elements, value) {
224                 var lock = false;
225                 elements.each(function(){
226                     if (this.getAttribute('type').toLowerCase()=='radio' && this.get('value') != value) {
227                         return;
228                     }
229                     lock = lock || !Y.Node.getDOMNode(this).checked;
230                 });
231                 return {
232                     lock : lock,
233                     hide : false
234                 }
235             },
236             _dependency_checked : function(elements, value) {
237                 var lock = false;
238                 elements.each(function(){
239                     if (this.getAttribute('type').toLowerCase()=='radio' && this.get('value') != value) {
240                         return;
241                     }
242                     lock = lock || Y.Node.getDOMNode(this).checked;
243                 });
244                 return {
245                     lock : lock,
246                     hide : false
247                 }
248             },
249             _dependency_noitemselected : function(elements, value) {
250                 var lock = false;
251                 elements.each(function(){
252                     lock = lock || this.get('selectedIndex') == -1;
253                 });
254                 return {
255                     lock : lock,
256                     hide : false
257                 }
258             },
259             _dependency_eq : function(elements, value) {
260                 var lock = false;
261                 elements.each(function(){
262                     if (this.getAttribute('type').toLowerCase()=='radio' && !Y.Node.getDOMNode(this).checked) {
263                         return;
264                     } else if (this.getAttribute('type').toLowerCase() == 'checkbox' && !Y.Node.getDOMNode(this).checked) {
265                         return;
266                     }
267                     lock = lock || this.get('value') == value;
268                 });
269                 return {
270                     lock : lock,
271                     hide : false
272                 }
273             },
274             _dependency_hide : function(elements, value) {
275                 return {
276                     lock : false,
277                     hide : true
278                 }
279             },
280             _dependency_default : function(elements, value, ev) {
281                 var lock = false;
282                 elements.each(function(){
283                     if (this.getAttribute('type').toLowerCase()=='radio' && !Y.Node.getDOMNode(this).checked) {
284                         return;
285                     } else if (this.getAttribute('type').toLowerCase() == 'checkbox' && !Y.Node.getDOMNode(this).checked) {
286                         return;
287                     }
288                     lock = lock || this.get('value') != value;
289                 });
290                 return {
291                     lock : lock,
292                     hide : false
293                 }
294             }
295         };
296         Y.extend(dependencyManager, Y.Base, dependencyManager.prototype, {
297             NAME : 'mform-dependency-manager'
298         });
300         return dependencyManager;
301     })();
303     return new M.form.dependencyManager();