//>>built define("dojox/form/manager/_NodeMixin", [ "dojo/_base/lang", "dojo/_base/array", "dojo/_base/connect", "dojo/dom", "dojo/dom-attr", "dojo/query", "./_Mixin", "dijit/form/_FormWidget", "dijit/_base/manager", "dojo/_base/declare" ], function(lang, array, connect, dom, domAttr, query, _Mixin, _FormWidget, manager, declare){ var fm = lang.getObject("dojox.form.manager", true), aa = fm.actionAdapter, keys = fm._keys, ce = fm.changeEvent = function(node){ // summary: // Function that returns a valid "onchange" event for a given form node. // node: Node: // Form node. var eventName = "onclick"; switch(node.tagName.toLowerCase()){ case "textarea": eventName = "onkeyup"; break; case "select": eventName = "onchange"; break; case "input": switch(node.type.toLowerCase()){ case "text": case "password": eventName = "onkeyup"; break; } break; // button, input/button, input/checkbox, input/radio, // input/file, input/image, input/submit, input/reset // use "onclick" (the default) } return eventName; // String }, registerNode = function(node, groupNode){ var name = domAttr.get(node, "name"); groupNode = groupNode || this.domNode; if(name && !(name in this.formWidgets)){ // verify that it is not part of any widget for(var n = node; n && n !== groupNode; n = n.parentNode){ if(domAttr.get(n, "widgetId") && manager.byNode(n).isInstanceOf(_FormWidget)){ // this is a child of some widget --- bail out return null; } } // register the node if(node.tagName.toLowerCase() == "input" && node.type.toLowerCase() == "radio"){ var a = this.formNodes[name]; a = a && a.node; if(a && lang.isArray(a)){ a.push(node); }else{ this.formNodes[name] = {node: [node], connections: []}; } }else{ this.formNodes[name] = {node: node, connections: []}; } }else{ name = null; } return name; }, getObserversFromNode = function(name){ var observers = {}; aa(function(_, n){ var o = domAttr.get(n, "observer"); if(o && typeof o == "string"){ array.forEach(o.split(","), function(o){ o = lang.trim(o); if(o && lang.isFunction(this[o])){ observers[o] = 1; } }, this); } }).call(this, null, this.formNodes[name].node); return keys(observers); }, connectNode = function(name, observers){ var t = this.formNodes[name], c = t.connections; if(c.length){ array.forEach(c, connect.disconnect); c = t.connections = []; } aa(function(_, n){ // the next line is a crude workaround for Button that fires onClick instead of onChange var eventName = ce(n); array.forEach(observers, function(o){ c.push(connect.connect(n, eventName, this, function(evt){ if(this.watching){ this[o](this.formNodeValue(name), name, n, evt); } })); }, this); }).call(this, null, t.node); }; return declare("dojox.form.manager._NodeMixin", null, { // summary: // Mixin to orchestrate dynamic forms (works with DOM nodes). // description: // This mixin provideas a foundation for an enhanced form // functionality: unified access to individual form elements, // unified "onchange" event processing, and general event // processing. It complements dojox.form.manager._Mixin // extending the functionality to DOM nodes. destroy: function(){ // summary: // Called when the widget is being destroyed for(var name in this.formNodes){ array.forEach(this.formNodes[name].connections, connect.disconnect); } this.formNodes = {}; this.inherited(arguments); }, // register/unregister widgets and nodes registerNode: function(node){ // summary: // Register a node with the form manager // node: String|Node: // A node, or its id // returns: Object: // Returns self if(typeof node == "string"){ node = dom.byId(node); } var name = registerNode.call(this, node); if(name){ connectNode.call(this, name, getObserversFromNode.call(this, name)); } return this; }, unregisterNode: function(name){ // summary: // Removes the node by name from internal tables unregistering // connected observers // name: String: // Name of the to unregister // returns: Object: // Returns self if(name in this.formNodes){ array.forEach(this.formNodes[name].connections, this.disconnect, this); delete this.formNodes[name]; } return this; }, registerNodeDescendants: function(node){ // summary: // Register node's descendants (form nodes) with the form manager // node: String|Node: // A widget, or its widgetId, or its DOM node // returns: Object: // Returns self if(typeof node == "string"){ node = dom.byId(node); } query("input, select, textarea, button", node). map(function(n){ return registerNode.call(this, n, node); }, this). forEach(function(name){ if(name){ connectNode.call(this, name, getObserversFromNode.call(this, name)); } }, this); return this; }, unregisterNodeDescendants: function(node){ // summary: // Unregister node's descendants (form nodes) with the form manager // node: String|Node: // A widget, or its widgetId, or its DOM node // returns: Object: // Returns self if(typeof node == "string"){ node = dom.byId(node); } query("input, select, textarea, button", node). map(function(n){ return domAttr.get(node, "name") || null; }). forEach(function(name){ if(name){ this.unregisterNode(name); } }, this); return this; }, // value accessors formNodeValue: function(elem, value){ // summary: // Set or get a form element by name. // elem: String|Node|Array: // Form element's name, DOM node, or array or radio nodes. // value: Object?: // Optional. The value to set. // returns: Object: // For a getter it returns the value, for a setter it returns // self. If the elem is not valid, null will be returned. var isSetter = arguments.length == 2 && value !== undefined, result; if(typeof elem == "string"){ elem = this.formNodes[elem]; if(elem){ elem = elem.node; } } if(!elem){ return null; // Object } if(lang.isArray(elem)){ // input/radio array if(isSetter){ array.forEach(elem, function(node){ node.checked = ""; }); array.forEach(elem, function(node){ node.checked = node.value === value ? "checked" : ""; }); return this; // self } // getter array.some(elem, function(node){ if(node.checked){ result = node; return true; } return false; }); return result ? result.value : ""; // String } // all other elements switch(elem.tagName.toLowerCase()){ case "select": if(elem.multiple){ // multiple is allowed if(isSetter){ if(lang.isArray(value)){ var dict = {}; array.forEach(value, function(v){ dict[v] = 1; }); query("> option", elem).forEach(function(opt){ opt.selected = opt.value in dict; }); return this; // self } // singular property query("> option", elem).forEach(function(opt){ opt.selected = opt.value === value; }); return this; // self } // getter var result = query("> option", elem).filter(function(opt){ return opt.selected; }).map(function(opt){ return opt.value; }); return result.length == 1 ? result[0] : result; // Object } // singular if(isSetter){ query("> option", elem).forEach(function(opt){ opt.selected = opt.value === value; }); return this; // self } // getter return elem.value || ""; // String case "button": if(isSetter){ elem.innerHTML = "" + value; return this; } // getter return elem.innerHTML; case "input": if(elem.type.toLowerCase() == "checkbox"){ // input/checkbox element if(isSetter){ elem.checked = value ? "checked" : ""; return this; } // getter return Boolean(elem.checked); } } // the rest of inputs if(isSetter){ elem.value = "" + value; return this; } // getter return elem.value; }, // inspectors inspectFormNodes: function(inspector, state, defaultValue){ // summary: // Run an inspector function on controlled form elements returning a result object. // inspector: Function: // A function to be called on a form element. Takes three arguments: a name, a node or // an array of nodes, and a supplied value. Runs in the context of the form manager. // Returns a value that will be collected and returned as a state. // state: Object?: // Optional. If a name-value dictionary --- only listed names will be processed. // If an array, all names in the array will be processed with defaultValue. // If omitted or null, all form elements will be processed with defaultValue. // defaultValue: Object?: // Optional. The default state (true, if omitted). var name, result = {}; if(state){ if(lang.isArray(state)){ array.forEach(state, function(name){ if(name in this.formNodes){ result[name] = inspector.call(this, name, this.formNodes[name].node, defaultValue); } }, this); }else{ for(name in state){ if(name in this.formNodes){ result[name] = inspector.call(this, name, this.formNodes[name].node, state[name]); } } } }else{ for(name in this.formNodes){ result[name] = inspector.call(this, name, this.formNodes[name].node, defaultValue); } } return result; // Object } }); });