if(!dojo._hasResource["dijit._Widget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["dijit._Widget"] = true; dojo.provide("dijit._Widget"); dojo.require( "dijit._base" ); dojo.declare("dijit._Widget", null, { // summary: // The foundation of dijit widgets. // // id: String // a unique, opaque ID string that can be assigned by users or by the // system. If the developer passes an ID which is known not to be // unique, the specified ID is ignored and the system-generated ID is // used instead. id: "", // lang: String // Rarely used. Overrides the default Dojo locale used to render this widget, // as defined by the [HTML LANG](http://www.w3.org/TR/html401/struct/dirlang.html#adef-lang) attribute. // Value must be among the list of locales specified during by the Dojo bootstrap, // formatted according to [RFC 3066](http://www.ietf.org/rfc/rfc3066.txt) (like en-us). lang: "", // dir: String // Unsupported by Dijit, but here for completeness. Dijit only supports setting text direction on the // entire document. // Bi-directional support, as defined by the [HTML DIR](http://www.w3.org/TR/html401/struct/dirlang.html#adef-dir) // attribute. Either left-to-right "ltr" or right-to-left "rtl". dir: "", // class: String // HTML class attribute "class": "", // style: String // HTML style attribute style: "", // title: String // HTML title attribute title: "", // srcNodeRef: DomNode // pointer to original dom node srcNodeRef: null, // domNode: DomNode // this is our visible representation of the widget! Other DOM // Nodes may by assigned to other properties, usually through the // template system's dojoAttachPonit syntax, but the domNode // property is the canonical "top level" node in widget UI. domNode: null, // attributeMap: Object // A map of attributes and attachpoints -- typically standard HTML attributes -- to set // on the widget's dom, at the "domNode" attach point, by default. // Other node references can be specified as properties of 'this' attributeMap: {id:"", dir:"", lang:"", "class":"", style:"", title:""}, // TODO: add on* handlers? //////////// INITIALIZATION METHODS /////////////////////////////////////// //TODOC: params and srcNodeRef need docs. Is srcNodeRef optional? //TODOC: summary needed for postscript postscript: function(/*Object?*/params, /*DomNode|String*/srcNodeRef){ this.create(params, srcNodeRef); }, create: function(/*Object?*/params, /*DomNode|String*/srcNodeRef){ // summary: // Kick off the life-cycle of a widget // description: // To understand the process by which widgets are instantiated, it // is critical to understand what other methods create calls and // which of them you'll want to override. Of course, adventurous // developers could override create entirely, but this should // only be done as a last resort. // // Below is a list of the methods that are called, in the order // they are fired, along with notes about what they do and if/when // you should over-ride them in your widget: // // * postMixInProperties: // | * a stub function that you can over-ride to modify // variables that may have been naively assigned by // mixInProperties // * widget is added to manager object here // * buildRendering: // | * Subclasses use this method to handle all UI initialization // Sets this.domNode. Templated widgets do this automatically // and otherwise it just uses the source dom node. // * postCreate: // | * a stub function that you can over-ride to modify take // actions once the widget has been placed in the UI // store pointer to original dom tree this.srcNodeRef = dojo.byId(srcNodeRef); // For garbage collection. An array of handles returned by Widget.connect() // Each handle returned from Widget.connect() is an array of handles from dojo.connect() this._connects=[]; // _attaches: String[] // names of all our dojoAttachPoint variables this._attaches=[]; //mixin our passed parameters if(this.srcNodeRef && (typeof this.srcNodeRef.id == "string")){ this.id = this.srcNodeRef.id; } if(params){ this.params = params; dojo.mixin(this,params); } this.postMixInProperties(); // generate an id for the widget if one wasn't specified // (be sure to do this before buildRendering() because that function might // expect the id to be there. if(!this.id){ this.id=dijit.getUniqueId(this.declaredClass.replace(/\./g,"_")); } dijit.registry.add(this); this.buildRendering(); // Copy attributes listed in attributeMap into the [newly created] DOM for the widget. // The placement of these attributes is according to the property mapping in attributeMap. // Note special handling for 'style' and 'class' attributes which are lists and can // have elements from both old and new structures, and some attributes like "type" // cannot be processed this way as they are not mutable. if(this.domNode){ for(var attr in this.attributeMap){ var value = this[attr]; if(typeof value != "object" && ((value !== "" && value !== false) || (params && params[attr]))){ this.setAttribute(attr, value); } } } if(this.domNode){ this.domNode.setAttribute("widgetId", this.id); } this.postCreate(); // If srcNodeRef has been processed and removed from the DOM (e.g. TemplatedWidget) then delete it to allow GC. if(this.srcNodeRef && !this.srcNodeRef.parentNode){ delete this.srcNodeRef; } }, postMixInProperties: function(){ // summary // Called after the parameters to the widget have been read-in, // but before the widget template is instantiated. // Especially useful to set properties that are referenced in the widget template. }, buildRendering: function(){ // summary: // Construct the UI for this widget, setting this.domNode. // Most widgets will mixin TemplatedWidget, which overrides this method. this.domNode = this.srcNodeRef || dojo.doc.createElement('div'); }, postCreate: function(){ // summary: // Called after a widget's dom has been setup }, startup: function(){ // summary: // Called after a widget's children, and other widgets on the page, have been created. // Provides an opportunity to manipulate any children before they are displayed. // This is useful for composite widgets that need to control or layout sub-widgets. // Many layout widgets can use this as a wiring phase. this._started = true; }, //////////// DESTROY FUNCTIONS //////////////////////////////// destroyRecursive: function(/*Boolean*/ finalize){ // summary: // Destroy this widget and it's descendants. This is the generic // "destructor" function that all widget users should call to // cleanly discard with a widget. Once a widget is destroyed, it's // removed from the manager object. // finalize: Boolean // is this function being called part of global environment // tear-down? this.destroyDescendants(); this.destroy(); }, destroy: function(/*Boolean*/ finalize){ // summary: // Destroy this widget, but not its descendants // finalize: Boolean // is this function being called part of global environment // tear-down? this.uninitialize(); dojo.forEach(this._connects, function(array){ dojo.forEach(array, dojo.disconnect); }); // destroy widgets created as part of template, etc. dojo.forEach(this._supportingWidgets || [], function(w){ w.destroy(); }); this.destroyRendering(finalize); dijit.registry.remove(this.id); }, destroyRendering: function(/*Boolean*/ finalize){ // summary: // Destroys the DOM nodes associated with this widget // finalize: Boolean // is this function being called part of global environment // tear-down? if(this.bgIframe){ this.bgIframe.destroy(); delete this.bgIframe; } if(this.domNode){ dojo._destroyElement(this.domNode); delete this.domNode; } if(this.srcNodeRef){ dojo._destroyElement(this.srcNodeRef); delete this.srcNodeRef; } }, destroyDescendants: function(){ // summary: // Recursively destroy the children of this widget and their // descendants. // TODO: should I destroy in the reverse order, to go bottom up? dojo.forEach(this.getDescendants(), function(widget){ widget.destroy(); }); }, uninitialize: function(){ // summary: // stub function. Override to implement custom widget tear-down // behavior. return false; }, ////////////////// MISCELLANEOUS METHODS /////////////////// onFocus: function(){ // summary: // stub function. Override or connect to this method to receive // notifications for when the widget moves into focus. }, onBlur: function(){ // summary: // stub function. Override or connect to this method to receive // notifications for when the widget moves out of focus. }, _onFocus: function(e){ this.onFocus(); }, _onBlur: function(){ this.onBlur(); }, setAttribute: function(/*String*/ attr, /*anything*/ value){ // summary // Set native HTML attributes reflected in the widget, // such as readOnly, disabled, and maxLength in TextBox widgets. // description // In general, a widget's "value" is controlled via setValue()/getValue(), // rather than this method. The exception is for widgets where the // end user can't adjust the value, such as Button and CheckBox; // in the unusual case that you want to change the value attribute of // those widgets, use setAttribute(). var mapNode = this[this.attributeMap[attr]||'domNode']; this[attr] = value; switch(attr){ case "class": dojo.addClass(mapNode, value); break; case "style": if(mapNode.style.cssText){ mapNode.style.cssText += "; " + value;// FIXME: Opera }else{ mapNode.style.cssText = value; } break; default: if(/^on[A-Z]/.test(attr)){ // eg. onSubmit needs to be onsubmit attr = attr.toLowerCase(); } if(typeof value == "function"){ // functions execute in the context of the widget value = dojo.hitch(this, value); } dojo.attr(mapNode, attr, value); } }, toString: function(){ // summary: // returns a string that represents the widget. When a widget is // cast to a string, this method will be used to generate the // output. Currently, it does not implement any sort of reversable // serialization. return '[Widget ' + this.declaredClass + ', ' + (this.id || 'NO ID') + ']'; // String }, getDescendants: function(){ // summary: // Returns all the widgets that contained by this, i.e., all widgets underneath this.containerNode. if(this.containerNode){ var list= dojo.query('[widgetId]', this.containerNode); return list.map(dijit.byNode); // Array }else{ return []; } }, //TODOC nodesWithKeyClick: ["input", "button"], connect: function( /*Object|null*/ obj, /*String*/ event, /*String|Function*/ method){ // summary: // Connects specified obj/event to specified method of this object // and registers for disconnect() on widget destroy. // Special event: "ondijitclick" triggers on a click or enter-down or space-up // Similar to dojo.connect() but takes three arguments rather than four. var handles =[]; if(event == "ondijitclick"){ // add key based click activation for unsupported nodes. if(!this.nodesWithKeyClick[obj.nodeName]){ handles.push(dojo.connect(obj, "onkeydown", this, function(e){ if(e.keyCode == dojo.keys.ENTER){ return (dojo.isString(method))? this[method](e) : method.call(this, e); }else if(e.keyCode == dojo.keys.SPACE){ // stop space down as it causes IE to scroll // the browser window dojo.stopEvent(e); } })); handles.push(dojo.connect(obj, "onkeyup", this, function(e){ if(e.keyCode == dojo.keys.SPACE){ return dojo.isString(method) ? this[method](e) : method.call(this, e); } })); } event = "onclick"; } handles.push(dojo.connect(obj, event, this, method)); // return handles for FormElement and ComboBox this._connects.push(handles); return handles; }, disconnect: function(/*Object*/ handles){ // summary: // Disconnects handle created by this.connect. // Also removes handle from this widget's list of connects for(var i=0; i