source: Dev/trunk/src/client/dojox/form/manager/_NodeMixin.js

Last change on this file was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

File size: 9.7 KB
Line 
1define([
2        "dojo/_base/lang",
3        "dojo/_base/array",
4        "dojo/on",
5        "dojo/dom",
6        "dojo/dom-attr",
7        "dojo/query",
8        "./_Mixin",
9        "dijit/form/_FormWidget",
10        "dijit/_base/manager",
11        "dojo/_base/declare"
12], function(lang, array, on, dom, domAttr, query, _Mixin, _FormWidget, manager, declare){
13        var fm = lang.getObject("dojox.form.manager", true),
14                aa = fm.actionAdapter,
15                keys = fm._keys,
16
17                ce = fm.changeEvent = function(node){
18                        // summary:
19                        //              Function that returns a valid "onchange" event for a given form node.
20                        // node: Node
21                        //              Form node.
22
23                        var eventName = "click";
24                        switch(node.tagName.toLowerCase()){
25                                case "textarea":
26                                        eventName = "keyup";
27                                        break;
28                                case "select":
29                                        eventName = "change";
30                                        break;
31                                case "input":
32                                        switch(node.type.toLowerCase()){
33                                                case "text":
34                                                case "password":
35                                                        eventName = "keyup";
36                                                        break;
37                                        }
38                                        break;
39                                // button, input/button, input/checkbox, input/radio,
40                                // input/file, input/image, input/submit, input/reset
41                                // use "onclick" (the default)
42                        }
43                        return eventName;       // String
44                },
45
46                registerNode = function(node, groupNode){
47                        var name = domAttr.get(node, "name");
48                        groupNode = groupNode || this.domNode;
49                        if(name && !(name in this.formWidgets)){
50                                // verify that it is not part of any widget
51                                for(var n = node; n && n !== groupNode; n = n.parentNode){
52                                        if(domAttr.get(n, "widgetId") && manager.byNode(n).isInstanceOf(_FormWidget)){
53                                                // this is a child of some widget --- bail out
54                                                return null;
55                                        }
56                                }
57                                // register the node
58                                if(node.tagName.toLowerCase() == "input" && node.type.toLowerCase() == "radio"){
59                                        var a = this.formNodes[name];
60                                        a = a && a.node;
61                                        if(a && lang.isArray(a)){
62                                                a.push(node);
63                                        }else{
64                                                this.formNodes[name] = {node: [node], connections: []};
65                                        }
66                                }else{
67                                        this.formNodes[name] = {node: node, connections: []};
68                                }
69                        }else{
70                                name = null;
71                        }
72                        return name;
73                },
74
75                getObserversFromNode = function(name){
76                        var observers = {};
77                        aa(function(_, n){
78                                var o = domAttr.get(n, "data-dojo-observer") || domAttr.get(n, "observer");
79                                if(o && typeof o == "string"){
80                                        array.forEach(o.split(","), function(o){
81                                                o = lang.trim(o);
82                                                if(o && lang.isFunction(this[o])){
83                                                        observers[o] = 1;
84                                                }
85                                        }, this);
86                                }
87                        }).call(this, null, this.formNodes[name].node);
88                        return keys(observers);
89                },
90
91                connectNode = function(name, observers){
92                        var t = this.formNodes[name], c = t.connections;
93                        if(c.length){
94                                array.forEach(c, function(item){ item.remove(); });
95                                c = t.connections = [];
96                        }
97                        aa(function(_, n){
98                                // the next line is a crude workaround for Button that fires onClick instead of onChange
99                                var eventName = ce(n);
100                                array.forEach(observers, function(o){
101                                        c.push(on(n, eventName, lang.hitch(this, function(evt){
102                                                if(this.watching){
103                                                        this[o](this.formNodeValue(name), name, n, evt);
104                                                }
105                                        })));
106                                }, this);
107                        }).call(this, null, t.node);
108                };
109
110        return declare("dojox.form.manager._NodeMixin", null, {
111                // summary:
112                //              Mixin to orchestrate dynamic forms (works with DOM nodes).
113                // description:
114                //              This mixin provides a foundation for an enhanced form
115                //              functionality: unified access to individual form elements,
116                //              unified "change" event processing, and general event
117                //              processing. It complements dojox/form/manager/_Mixin
118                //              extending the functionality to DOM nodes.
119
120                destroy: function(){
121                        // summary:
122                        //              Called when the widget is being destroyed
123
124                        for(var name in this.formNodes){
125                                array.forEach(this.formNodes[name].connections, function(item){
126                                        item.remove();
127                                });
128                        }
129                        this.formNodes = {};
130
131                        this.inherited(arguments);
132                },
133
134                // register/unregister widgets and nodes
135
136                registerNode: function(node){
137                        // summary:
138                        //              Register a node with the form manager
139                        // node: String|Node
140                        //              A node, or its id
141                        // returns: Object
142                        //              Returns self
143                        if(typeof node == "string"){
144                                node = dom.byId(node);
145                        }
146                        var name = registerNode.call(this, node);
147                        if(name){
148                                connectNode.call(this, name, getObserversFromNode.call(this, name));
149                        }
150                        return this;
151                },
152
153                unregisterNode: function(name){
154                        // summary:
155                        //              Removes the node by name from internal tables unregistering
156                        //              connected observers
157                        // name: String
158                        //              Name of the to unregister
159                        // returns: Object
160                        //              Returns self
161                        if(name in this.formNodes){
162                                array.forEach(this.formNodes[name].connections, function(item){
163                                        item.remove();
164                                });
165                                delete this.formNodes[name];
166                        }
167                        return this;
168                },
169
170                registerNodeDescendants: function(node){
171                        // summary:
172                        //              Register node's descendants (form nodes) with the form manager
173                        // node: String|Node
174                        //              A widget, or its widgetId, or its DOM node
175                        // returns: Object
176                        //              Returns self
177
178                        if(typeof node == "string"){
179                                node = dom.byId(node);
180                        }
181
182                        query("input, select, textarea, button", node).
183                                map(function(n){
184                                        return registerNode.call(this, n, node);
185                                }, this).
186                                forEach(function(name){
187                                        if(name){
188                                                connectNode.call(this, name, getObserversFromNode.call(this, name));
189                                        }
190                                }, this);
191
192                        return this;
193                },
194
195                unregisterNodeDescendants: function(node){
196                        // summary:
197                        //              Unregister node's descendants (form nodes) with the form manager
198                        // node: String|Node
199                        //              A widget, or its widgetId, or its DOM node
200                        // returns: Object
201                        //              Returns self
202
203                        if(typeof node == "string"){
204                                node = dom.byId(node);
205                        }
206
207                        query("input, select, textarea, button", node).
208                                map(function(n){ return domAttr.get(node, "name") || null; }).
209                                forEach(function(name){
210                                        if(name){
211                                                this.unregisterNode(name);
212                                        }
213                                }, this);
214
215                        return this;
216                },
217
218                // value accessors
219
220                formNodeValue: function(elem, value){
221                        // summary:
222                        //              Set or get a form element by name.
223                        // elem: String|Node|Array
224                        //              Form element's name, DOM node, or array or radio nodes.
225                        // value: Object?
226                        //              Optional. The value to set.
227                        // returns: Object
228                        //              For a getter it returns the value, for a setter it returns
229                        //              self. If the elem is not valid, null will be returned.
230
231                        var isSetter = arguments.length == 2 && value !== undefined, result;
232
233                        if(typeof elem == "string"){
234                                elem = this.formNodes[elem];
235                                if(elem){
236                                        elem = elem.node;
237                                }
238                        }
239
240                        if(!elem){
241                                return null;    // Object
242                        }
243
244                        if(lang.isArray(elem)){
245                                // input/radio array
246                                if(isSetter){
247                                        array.forEach(elem, function(node){
248                                                node.checked = "";
249                                        });
250                                        array.forEach(elem, function(node){
251                                                node.checked = node.value === value ? "checked" : "";
252                                        });
253                                        return this;    // self
254                                }
255                                // getter
256                                array.some(elem, function(node){
257                                        if(node.checked){
258                                                result = node;
259                                                return true;
260                                        }
261                                        return false;
262                                });
263                                return result ? result.value : "";      // String
264                        }
265                        // all other elements
266                        switch(elem.tagName.toLowerCase()){
267                                case "select":
268                                        if(elem.multiple){
269                                                // multiple is allowed
270                                                if(isSetter){
271                                                        if(lang.isArray(value)){
272                                                                var dict = {};
273                                                                array.forEach(value, function(v){
274                                                                        dict[v] = 1;
275                                                                });
276                                                                query("> option", elem).forEach(function(opt){
277                                                                        opt.selected = opt.value in dict;
278                                                                });
279                                                                return this;    // self
280                                                        }
281                                                        // singular property
282                                                        query("> option", elem).forEach(function(opt){
283                                                                opt.selected = opt.value === value;
284                                                        });
285                                                        return this;    // self
286                                                }
287                                                // getter
288                                                result = query("> option", elem).filter(function(opt){
289                                                        return opt.selected;
290                                                }).map(function(opt){
291                                                        return opt.value;
292                                                });
293                                                return result.length == 1 ? result[0] : result; // Object
294                                        }
295                                        // singular
296                                        if(isSetter){
297                                                query("> option", elem).forEach(function(opt){
298                                                        opt.selected = opt.value === value;
299                                                });
300                                                return this;    // self
301                                        }
302                                        // getter
303                                        return elem.value || ""; // String
304                                case "button":
305                                        if(isSetter){
306                                                elem.innerHTML = "" + value;
307                                                return this;
308                                        }
309                                        // getter
310                                        return elem.innerHTML;
311                                case "input":
312                                        if(elem.type.toLowerCase() == "checkbox"){
313                                                // input/checkbox element
314                                                if(isSetter){
315                                                        elem.checked = value ? "checked" : "";
316                                                        return this;
317                                                }
318                                                // getter
319                                                return Boolean(elem.checked);
320                                        }
321                        }
322                        // the rest of inputs
323                        if(isSetter){
324                                elem.value = "" + value;
325                                return this;
326                        }
327                        // getter
328                        return elem.value;
329                },
330
331                // inspectors
332
333                inspectFormNodes: function(inspector, state, defaultValue){
334                        // summary:
335                        //              Run an inspector function on controlled form elements returning a result object.
336                        // inspector: Function
337                        //              A function to be called on a form element. Takes three arguments: a name, a node or
338                        //              an array of nodes, and a supplied value. Runs in the context of the form manager.
339                        //              Returns a value that will be collected and returned as a state.
340                        // state: Object?
341                        //              Optional. If a name-value dictionary --- only listed names will be processed.
342                        //              If an array, all names in the array will be processed with defaultValue.
343                        //              If omitted or null, all form elements will be processed with defaultValue.
344                        // defaultValue: Object?
345                        //              Optional. The default state (true, if omitted).
346
347                        var name, result = {};
348
349                        if(state){
350                                if(lang.isArray(state)){
351                                        array.forEach(state, function(name){
352                                                if(name in this.formNodes){
353                                                        result[name] = inspector.call(this, name, this.formNodes[name].node, defaultValue);
354                                                }
355                                        }, this);
356                                }else{
357                                        for(name in state){
358                                                if(name in this.formNodes){
359                                                        result[name] = inspector.call(this, name, this.formNodes[name].node, state[name]);
360                                                }
361                                        }
362                                }
363                        }else{
364                                for(name in this.formNodes){
365                                        result[name] = inspector.call(this, name, this.formNodes[name].node, defaultValue);
366                                }
367                        }
368
369                        return result;  // Object
370                }
371        });
372});
Note: See TracBrowser for help on using the repository browser.