diff options
Diffstat (limited to 'includes/js/dijit/_Widget.js')
-rw-r--r-- | includes/js/dijit/_Widget.js | 407 |
1 files changed, 407 insertions, 0 deletions
diff --git a/includes/js/dijit/_Widget.js b/includes/js/dijit/_Widget.js new file mode 100644 index 0000000..361b6bf --- /dev/null +++ b/includes/js/dijit/_Widget.js @@ -0,0 +1,407 @@ +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<this._connects.length; i++){ + if(this._connects[i]==handles){ + dojo.forEach(handles, dojo.disconnect); + this._connects.splice(i, 1); + return; + } + } + }, + + isLeftToRight: function(){ + // summary: + // Checks the DOM to for the text direction for bi-directional support + // description: + // This method cannot be used during widget construction because the widget + // must first be connected to the DOM tree. Parent nodes are searched for the + // 'dir' attribute until one is found, otherwise left to right mode is assumed. + // See HTML spec, DIR attribute for more information. + + if(!("_ltr" in this)){ + this._ltr = dojo.getComputedStyle(this.domNode).direction != "rtl"; + } + return this._ltr; //Boolean + }, + + isFocusable: function(){ + // summary: + // Return true if this widget can currently be focused + // and false if not + return this.focus && (dojo.style(this.domNode, "display") != "none"); + } +}); + +} |