123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495 |
- /*
- Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved.
- Available via Academic Free License >= 2.1 OR the modified BSD license.
- see: http://dojotoolkit.org/license for details
- */
- if(!dojo._hasResource["dojox.form.manager._Mixin"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
- dojo._hasResource["dojox.form.manager._Mixin"] = true;
- dojo.provide("dojox.form.manager._Mixin");
- dojo.require("dijit._Widget");
- (function(){
- var fm = dojox.form.manager,
- aa = fm.actionAdapter = function(action){
- // summary:
- // Adapter that automates application of actions to arrays.
- // action: Function:
- // Function that takes three parameters: a name, an object
- // (usually node or widget), and a value. This action will
- // be applied to all elements of array.
- return function(name, elems, value){
- if(dojo.isArray(elems)){
- dojo.forEach(elems, function(elem){
- action.call(this, name, elem, value);
- }, this);
- }else{
- action.apply(this, arguments);
- }
- };
- },
- ia = fm.inspectorAdapter = function(inspector){
- // summary:
- // Adapter that applies an inspector only to the first item of the array.
- // inspector: Function:
- // Function that takes three parameters: a name, an object
- // (usually node or widget), and a value.
- return function(name, elem, value){
- return inspector.call(this, name, dojo.isArray(elem) ? elem[0] : elem, value);
- };
- },
- skipNames = {domNode: 1, containerNode: 1, srcNodeRef: 1, bgIframe: 1},
- keys = fm._keys = function(o){
- // similar to dojox.lang.functional.keys
- var list = [], key;
- for(key in o){
- if(o.hasOwnProperty(key)){
- list.push(key);
- }
- }
- return list;
- },
- registerWidget = function(widget){
- var name = widget.get("name");
- if(name && widget instanceof dijit.form._FormWidget){
- if(name in this.formWidgets){
- var a = this.formWidgets[name].widget;
- if(dojo.isArray(a)){
- a.push(widget);
- }else{
- this.formWidgets[name].widget = [a, widget];
- }
- }else{
- this.formWidgets[name] = {widget: widget, connections: []};
- }
- }else{
- name = null;
- }
- return name;
- },
- getObserversFromWidget = function(name){
- var observers = {};
- aa(function(_, w){
- var o = w.get("observer");
- if(o && typeof o == "string"){
- dojo.forEach(o.split(","), function(o){
- o = dojo.trim(o);
- if(o && dojo.isFunction(this[o])){
- observers[o] = 1;
- }
- }, this);
- }
- }).call(this, null, this.formWidgets[name].widget);
- return keys(observers);
- },
- connectWidget = function(name, observers){
- var t = this.formWidgets[name], w = t.widget, c = t.connections;
- if(c.length){
- dojo.forEach(c, dojo.disconnect);
- c = t.connections = [];
- }
- if(dojo.isArray(w)){
- // radio buttons
- dojo.forEach(w, function(w){
- dojo.forEach(observers, function(o){
- c.push(dojo.connect(w, "onChange", this, function(evt){
- // TODO: for some reason for radio button widgets
- // w.checked != w.focusNode.checked when value changes.
- // We test the underlying value to be 100% sure.
- if(this.watching && dojo.attr(w.focusNode, "checked")){
- this[o](w.get("value"), name, w, evt);
- }
- }));
- }, this);
- }, this);
- }else{
- // the rest
- // the next line is a crude workaround for dijit.form.Button that fires onClick instead of onChange
- var eventName = w.declaredClass == "dijit.form.Button" ?
- "onClick" : "onChange";
- dojo.forEach(observers, function(o){
- c.push(dojo.connect(w, eventName, this, function(evt){
- if(this.watching){
- this[o](w.get("value"), name, w, evt);
- }
- }));
- }, this);
- }
- };
- dojo.declare("dojox.form.manager._Mixin", null, {
- // summary:
- // Mixin to orchestrate dynamic forms.
- // description:
- // This mixin provideas a foundation for an enhanced form
- // functionality: unified access to individual form elements,
- // unified "onchange" event processing, general event
- // processing, I/O orchestration, and common form-related
- // functionality. See additional mixins in dojox.form.manager
- // namespace.
- watching: true,
- startup: function(){
- // summary:
- // Called after all the widgets have been instantiated and their
- // dom nodes have been inserted somewhere under dojo.doc.body.
- if(this._started){ return; }
- this.formWidgets = {};
- this.formNodes = {};
- this.registerWidgetDescendants(this);
- this.inherited(arguments);
- },
- destroy: function(){
- // summary:
- // Called when the widget is being destroyed
- for(var name in this.formWidgets){
- dojo.forEach(this.formWidgets[name].connections, dojo.disconnect);
- }
- this.formWidgets = {};
- this.inherited(arguments);
- },
- // register/unregister widgets and nodes
- registerWidget: function(widget){
- // summary:
- // Register a widget with the form manager
- // widget: String|Node|dijit.form._FormWidget:
- // A widget, or its widgetId, or its DOM node
- // returns: Object:
- // Returns self
- if(typeof widget == "string"){
- widget = dijit.byId(widget);
- }else if(widget.tagName && widget.cloneNode){
- widget = dijit.byNode(widget);
- }
- var name = registerWidget.call(this, widget);
- if(name){
- connectWidget.call(this, name, getObserversFromWidget.call(this, name));
- }
- return this;
- },
- unregisterWidget: function(name){
- // summary:
- // Removes the widget by name from internal tables unregistering
- // connected observers
- // name: String:
- // Name of the to unregister
- // returns: Object:
- // Returns self
- if(name in this.formWidgets){
- dojo.forEach(this.formWidgets[name].connections, this.disconnect, this);
- delete this.formWidgets[name];
- }
- return this;
- },
- registerWidgetDescendants: function(widget){
- // summary:
- // Register widget's descendants with the form manager
- // widget: String|Node|dijit._Widget:
- // A widget, or its widgetId, or its DOM node
- // returns: Object:
- // Returns self
- // convert to widget, if required
- if(typeof widget == "string"){
- widget = dijit.byId(widget);
- }else if(widget.tagName && widget.cloneNode){
- widget = dijit.byNode(widget);
- }
- // build the map of widgets
- var widgets = dojo.map(widget.getDescendants(), registerWidget, this);
- // process observers for widgets
- dojo.forEach(widgets, function(name){
- if(name){
- connectWidget.call(this, name, getObserversFromWidget.call(this, name));
- }
- }, this);
- // do the same with nodes, if available
- return this.registerNodeDescendants ?
- this.registerNodeDescendants(widget.domNode) : this;
- },
- unregisterWidgetDescendants: function(widget){
- // summary:
- // Unregister widget's descendants with the form manager
- // widget: String|Node|dijit._Widget:
- // A widget, or its widgetId, or its DOM node
- // returns: Object:
- // Returns self
- // convert to widget, if required
- if(typeof widget == "string"){
- widget = dijit.byId(widget);
- }else if(widget.tagName && widget.cloneNode){
- widget = dijit.byNode(widget);
- }
- // unregister widgets by names
- dojo.forEach(
- dojo.map(
- widget.getDescendants(),
- function(w){
- return w instanceof dijit.form._FormWidget && w.get("name") || null;
- }
- ),
- function(name){
- if(name){
- this.unregisterNode(name);
- }
- },
- this
- );
- // do the same with nodes, if available
- return this.unregisterNodeDescendants ?
- this.unregisterNodeDescendants(widget.domNode) : this;
- },
- // value accessors
- formWidgetValue: function(elem, value){
- // summary:
- // Set or get a form widget by name.
- // elem: String|Object|Array:
- // Form element's name, widget object, or array or radio widgets.
- // 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.formWidgets[elem];
- if(elem){
- elem = elem.widget;
- }
- }
- if(!elem){
- return null; // Object
- }
- if(dojo.isArray(elem)){
- // input/radio array of widgets
- if(isSetter){
- dojo.forEach(elem, function(widget){
- widget.set("checked", false, !this.watching);
- }, this);
- dojo.forEach(elem, function(widget){
- widget.set("checked", widget.value === value, !this.watching);
- }, this);
- return this; // self
- }
- // getter
- dojo.some(elem, function(widget){
- // TODO: for some reason for radio button widgets
- // w.checked != w.focusNode.checked when value changes.
- // We test the underlying value to be 100% sure.
- if(dojo.attr(widget.focusNode, "checked")){
- //if(widget.get("checked")){
- result = widget;
- return true;
- }
- return false;
- });
- return result ? result.get("value") : ""; // String
- }
- // checkbox widget is a special case :-(
- if(elem.declaredClass == "dijit.form.CheckBox"){
- if(isSetter){
- elem.set("value", Boolean(value), !this.watching);
- return this; // self
- }
- return Boolean(elem.get("value")); // Object
- }
- // all other elements
- if(isSetter){
- elem.set("value", value, !this.watching);
- return this; // self
- }
- return elem.get("value"); // Object
- },
- formPointValue: function(elem, value){
- // summary:
- // Set or get a node context by name (using dojoAttachPoint).
- // elem: String|Object|Array:
- // A node.
- // 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.
- if(elem && typeof elem == "string"){
- elem = this[elem];
- }
- if(!elem || !elem.tagName || !elem.cloneNode){
- return null; // Object
- }
- if(!dojo.hasClass(elem, "dojoFormValue")){
- // accessing the value of the attached point not marked with CSS class 'dojoFormValue'
- return null;
- }
- if(arguments.length == 2 && value !== undefined){
- // setter
- elem.innerHTML = value;
- return this; // self
- }
- // getter
- return elem.innerHTML; // String
- },
- // inspectors
- inspectFormWidgets: function(inspector, state, defaultValue){
- // summary:
- // Run an inspector function on controlled widgets returning a result object.
- // inspector: Function:
- // A function to be called on a widget. Takes three arguments: a name, a widget object
- // or an array of widget objects, 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 widgets will be processed with defaultValue.
- // defaultValue: Object?:
- // Optional. The default state (true, if omitted).
- var name, result = {};
- if(state){
- if(dojo.isArray(state)){
- dojo.forEach(state, function(name){
- if(name in this.formWidgets){
- result[name] = inspector.call(this, name, this.formWidgets[name].widget, defaultValue);
- }
- }, this);
- }else{
- for(name in state){
- if(name in this.formWidgets){
- result[name] = inspector.call(this, name, this.formWidgets[name].widget, state[name]);
- }
- }
- }
- }else{
- for(name in this.formWidgets){
- result[name] = inspector.call(this, name, this.formWidgets[name].widget, defaultValue);
- }
- }
- return result; // Object
- },
- inspectAttachedPoints: function(inspector, state, defaultValue){
- // summary:
- // Run an inspector function on "dojoAttachPoint" nodes returning a result object.
- // inspector: Function:
- // A function to be called on a node. 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 attached point nodes will be processed with defaultValue.
- // defaultValue: Object?:
- // Optional. The default state (true, if omitted).
- var name, result = {};
- if(state){
- if(dojo.isArray(state)){
- dojo.forEach(state, function(name){
- var elem = this[name];
- if(elem && elem.tagName && elem.cloneNode){
- result[name] = inspector.call(this, name, elem, defaultValue);
- }
- }, this);
- }else{
- for(name in state){
- var elem = this[name];
- if(elem && elem.tagName && elem.cloneNode){
- result[name] = inspector.call(this, name, elem, state[name]);
- }
- }
- }
- }else{
- for(name in this){
- if(!(name in skipNames)){
- var elem = this[name];
- if(elem && elem.tagName && elem.cloneNode){
- result[name] = inspector.call(this, name, elem, defaultValue);
- }
- }
- }
- }
- return result; // Object
- },
- inspect: function(inspector, state, defaultValue){
- // summary:
- // Run an inspector function on controlled elements returning a result object.
- // inspector: Function:
- // A function to be called on a widget, form element, and an attached node.
- // Takes three arguments: a name, a node (domNode in the case of widget) or
- // an array of such objects, 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 controlled elements will be processed with defaultValue.
- // defaultValue: Object?:
- // Optional. The default state (true, if omitted).
- var result = this.inspectFormWidgets(function(name, widget, value){
- if(dojo.isArray(widget)){
- return inspector.call(this, name, dojo.map(widget, function(w){ return w.domNode; }), value);
- }
- return inspector.call(this, name, widget.domNode, value);
- }, state, defaultValue);
- if(this.inspectFormNodes){
- dojo.mixin(result, this.inspectFormNodes(inspector, state, defaultValue));
- }
- return dojo.mixin(result, this.inspectAttachedPoints(inspector, state, defaultValue)); // Object
- }
- });
- })();
- // These arguments can be specified for widgets which are used in forms.
- // Since any widget can be specified as sub widgets, mix it into the base
- // widget class. (This is a hack, but it's effective.)
- dojo.extend(dijit._Widget, {
- observer: ""
- });
- }
|