summaryrefslogtreecommitdiff
path: root/includes/js/dijit/_Widget.js
diff options
context:
space:
mode:
Diffstat (limited to 'includes/js/dijit/_Widget.js')
-rw-r--r--includes/js/dijit/_Widget.js407
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");
+ }
+});
+
+}