| /* |
| Copyright (c) 2004-2009, 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 |
| */ |
| |
| /* |
| This is a compiled version of Dojo, built for deployment and not for |
| development. To get an editable version, please visit: |
| |
| http://dojotoolkit.org |
| |
| for documentation and information on getting the source. |
| */ |
| |
| if(!dojo._hasResource["dijit._base.manager"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dijit._base.manager"] = true; |
| dojo.provide("dijit._base.manager"); |
| |
| dojo.declare("dijit.WidgetSet", null, { |
| // summary: |
| // A set of widgets indexed by id. A default instance of this class is |
| // available as `dijit.registry` |
| // |
| // example: |
| // Create a small list of widgets: |
| // | var ws = new dijit.WidgetSet(); |
| // | ws.add(dijit.byId("one")); |
| // | ws.add(dijit.byId("two")); |
| // | // destroy both: |
| // | ws.forEach(function(w){ w.destroy(); }); |
| // |
| // example: |
| // Using dijit.registry: |
| // | dijit.registry.forEach(function(w){ /* do something */ }); |
| |
| constructor: function(){ |
| this._hash = {}; |
| this.length = 0; |
| }, |
| |
| add: function(/*dijit._Widget*/ widget){ |
| // summary: |
| // Add a widget to this list. If a duplicate ID is detected, a error is thrown. |
| // |
| // widget: dijit._Widget |
| // Any dijit._Widget subclass. |
| if(this._hash[widget.id]){ |
| throw new Error("Tried to register widget with id==" + widget.id + " but that id is already registered"); |
| } |
| this._hash[widget.id] = widget; |
| this.length++; |
| }, |
| |
| remove: function(/*String*/ id){ |
| // summary: |
| // Remove a widget from this WidgetSet. Does not destroy the widget; simply |
| // removes the reference. |
| if(this._hash[id]){ |
| delete this._hash[id]; |
| this.length--; |
| } |
| }, |
| |
| forEach: function(/*Function*/ func, /* Object? */thisObj){ |
| // summary: |
| // Call specified function for each widget in this set. |
| // |
| // func: |
| // A callback function to run for each item. Is passed the widget, the index |
| // in the iteration, and the full hash, similar to `dojo.forEach`. |
| // |
| // thisObj: |
| // An optional scope parameter |
| // |
| // example: |
| // Using the default `dijit.registry` instance: |
| // | dijit.registry.forEach(function(widget){ |
| // | console.log(widget.declaredClass); |
| // | }); |
| // |
| // returns: |
| // Returns self, in order to allow for further chaining. |
| |
| thisObj = thisObj || dojo.global; |
| var i = 0, id; |
| for(id in this._hash){ |
| func.call(thisObj, this._hash[id], i++, this._hash); |
| } |
| return this; // dijit.WidgetSet |
| }, |
| |
| filter: function(/*Function*/ filter, /* Object? */thisObj){ |
| // summary: |
| // Filter down this WidgetSet to a smaller new WidgetSet |
| // Works the same as `dojo.filter` and `dojo.NodeList.filter` |
| // |
| // filter: |
| // Callback function to test truthiness. Is passed the widget |
| // reference and the pseudo-index in the object. |
| // |
| // thisObj: Object? |
| // Option scope to use for the filter function. |
| // |
| // example: |
| // Arbitrary: select the odd widgets in this list |
| // | dijit.registry.filter(function(w, i){ |
| // | return i % 2 == 0; |
| // | }).forEach(function(w){ /* odd ones */ }); |
| |
| thisObj = thisObj || dojo.global; |
| var res = new dijit.WidgetSet(), i = 0, id; |
| for(id in this._hash){ |
| var w = this._hash[id]; |
| if(filter.call(thisObj, w, i++, this._hash)){ |
| res.add(w); |
| } |
| } |
| return res; // dijit.WidgetSet |
| }, |
| |
| byId: function(/*String*/ id){ |
| // summary: |
| // Find a widget in this list by it's id. |
| // example: |
| // Test if an id is in a particular WidgetSet |
| // | var ws = new dijit.WidgetSet(); |
| // | ws.add(dijit.byId("bar")); |
| // | var t = ws.byId("bar") // returns a widget |
| // | var x = ws.byId("foo"); // returns undefined |
| |
| return this._hash[id]; // dijit._Widget |
| }, |
| |
| byClass: function(/*String*/ cls){ |
| // summary: |
| // Reduce this widgetset to a new WidgetSet of a particular `declaredClass` |
| // |
| // cls: String |
| // The Class to scan for. Full dot-notated string. |
| // |
| // example: |
| // Find all `dijit.TitlePane`s in a page: |
| // | dijit.registry.byClass("dijit.TitlePane").forEach(function(tp){ tp.close(); }); |
| |
| var res = new dijit.WidgetSet(), id, widget; |
| for(id in this._hash){ |
| widget = this._hash[id]; |
| if(widget.declaredClass == cls){ |
| res.add(widget); |
| } |
| } |
| return res; // dijit.WidgetSet |
| }, |
| |
| toArray: function(){ |
| // summary: |
| // Convert this WidgetSet into a true Array |
| // |
| // example: |
| // Work with the widget .domNodes in a real Array |
| // | dojo.map(dijit.registry.toArray(), function(w){ return w.domNode; }); |
| |
| var ar = []; |
| for(var id in this._hash){ |
| ar.push(this._hash[id]); |
| } |
| return ar; // dijit._Widget[] |
| }, |
| |
| map: function(/* Function */func, /* Object? */thisObj){ |
| // summary: |
| // Create a new Array from this WidgetSet, following the same rules as `dojo.map` |
| // example: |
| // | var nodes = dijit.registry.map(function(w){ return w.domNode; }); |
| // |
| // returns: |
| // A new array of the returned values. |
| return dojo.map(this.toArray(), func, thisObj); // Array |
| }, |
| |
| every: function(func, thisObj){ |
| // summary: |
| // A synthetic clone of `dojo.every` acting explictly on this WidgetSet |
| // |
| // func: Function |
| // A callback function run for every widget in this list. Exits loop |
| // when the first false return is encountered. |
| // |
| // thisObj: Object? |
| // Optional scope parameter to use for the callback |
| |
| thisObj = thisObj || dojo.global; |
| var x = 0, i; |
| for(i in this._hash){ |
| if(!func.call(thisObj, this._hash[i], x++, this._hash)){ |
| return false; // Boolean |
| } |
| } |
| return true; // Boolean |
| }, |
| |
| some: function(func, thisObj){ |
| // summary: |
| // A synthetic clone of `dojo.some` acting explictly on this WidgetSet |
| // |
| // func: Function |
| // A callback function run for every widget in this list. Exits loop |
| // when the first true return is encountered. |
| // |
| // thisObj: Object? |
| // Optional scope parameter to use for the callback |
| |
| thisObj = thisObj || dojo.global; |
| var x = 0, i; |
| for(i in this._hash){ |
| if(func.call(thisObj, this._hash[i], x++, this._hash)){ |
| return true; // Boolean |
| } |
| } |
| return false; // Boolean |
| } |
| |
| }); |
| |
| /*===== |
| dijit.registry = { |
| // summary: |
| // A list of widgets on a page. |
| // description: |
| // Is an instance of `dijit.WidgetSet` |
| }; |
| =====*/ |
| dijit.registry= new dijit.WidgetSet(); |
| |
| dijit._widgetTypeCtr = {}; |
| |
| dijit.getUniqueId = function(/*String*/widgetType){ |
| // summary: |
| // Generates a unique id for a given widgetType |
| |
| var id; |
| do{ |
| id = widgetType + "_" + |
| (widgetType in dijit._widgetTypeCtr ? |
| ++dijit._widgetTypeCtr[widgetType] : dijit._widgetTypeCtr[widgetType] = 0); |
| }while(dijit.byId(id)); |
| return dijit._scopeName == "dijit" ? id : dijit._scopeName + "_" + id; // String |
| }; |
| |
| dijit.findWidgets = function(/*DomNode*/ root){ |
| // summary: |
| // Search subtree under root returning widgets found. |
| // Doesn't search for nested widgets (ie, widgets inside other widgets). |
| |
| var outAry = []; |
| |
| function getChildrenHelper(root){ |
| for(var node = root.firstChild; node; node = node.nextSibling){ |
| if(node.nodeType == 1){ |
| var widgetId = node.getAttribute("widgetId"); |
| if(widgetId){ |
| var widget = dijit.byId(widgetId); |
| outAry.push(widget); |
| }else{ |
| getChildrenHelper(node); |
| } |
| } |
| } |
| } |
| |
| getChildrenHelper(root); |
| return outAry; |
| }; |
| |
| dijit._destroyAll = function(){ |
| // summary: |
| // Code to destroy all widgets and do other cleanup on page unload |
| |
| // Clean up focus manager lingering references to widgets and nodes |
| dijit._curFocus = null; |
| dijit._prevFocus = null; |
| dijit._activeStack = []; |
| |
| // Destroy all the widgets, top down |
| dojo.forEach(dijit.findWidgets(dojo.body()), function(widget){ |
| // Avoid double destroy of widgets like Menu that are attached to <body> |
| // even though they are logically children of other widgets. |
| if(!widget._destroyed){ |
| if(widget.destroyRecursive){ |
| widget.destroyRecursive(); |
| }else if(widget.destroy){ |
| widget.destroy(); |
| } |
| } |
| }); |
| }; |
| |
| if(dojo.isIE){ |
| // Only run _destroyAll() for IE because we think it's only necessary in that case, |
| // and because it causes problems on FF. See bug #3531 for details. |
| dojo.addOnWindowUnload(function(){ |
| dijit._destroyAll(); |
| }); |
| } |
| |
| dijit.byId = function(/*String|Widget*/id){ |
| // summary: |
| // Returns a widget by it's id, or if passed a widget, no-op (like dojo.byId()) |
| return typeof id == "string" ? dijit.registry._hash[id] : id; // dijit._Widget |
| }; |
| |
| dijit.byNode = function(/* DOMNode */ node){ |
| // summary: |
| // Returns the widget corresponding to the given DOMNode |
| return dijit.registry.byId(node.getAttribute("widgetId")); // dijit._Widget |
| }; |
| |
| dijit.getEnclosingWidget = function(/* DOMNode */ node){ |
| // summary: |
| // Returns the widget whose DOM tree contains the specified DOMNode, or null if |
| // the node is not contained within the DOM tree of any widget |
| while(node){ |
| var id = node.getAttribute && node.getAttribute("widgetId"); |
| if(id){ |
| return dijit.byId(id); |
| } |
| node = node.parentNode; |
| } |
| return null; |
| }; |
| |
| dijit._isElementShown = function(/*Element*/elem){ |
| var style = dojo.style(elem); |
| return (style.visibility != "hidden") |
| && (style.visibility != "collapsed") |
| && (style.display != "none") |
| && (dojo.attr(elem, "type") != "hidden"); |
| } |
| |
| dijit.isTabNavigable = function(/*Element*/elem){ |
| // summary: |
| // Tests if an element is tab-navigable |
| |
| // TODO: convert (and rename method) to return effectivite tabIndex; will save time in _getTabNavigable() |
| if(dojo.attr(elem, "disabled")){ |
| return false; |
| }else if(dojo.hasAttr(elem, "tabIndex")){ |
| // Explicit tab index setting |
| return dojo.attr(elem, "tabIndex") >= 0; // boolean |
| }else{ |
| // No explicit tabIndex setting, need to investigate node type |
| switch(elem.nodeName.toLowerCase()){ |
| case "a": |
| // An <a> w/out a tabindex is only navigable if it has an href |
| return dojo.hasAttr(elem, "href"); |
| case "area": |
| case "button": |
| case "input": |
| case "object": |
| case "select": |
| case "textarea": |
| // These are navigable by default |
| return true; |
| case "iframe": |
| // If it's an editor <iframe> then it's tab navigable. |
| if(dojo.isMoz){ |
| return elem.contentDocument.designMode == "on"; |
| }else if(dojo.isWebKit){ |
| var doc = elem.contentDocument, |
| body = doc && doc.body; |
| return body && body.contentEditable == 'true'; |
| }else{ |
| // contentWindow.document isn't accessible within IE7/8 |
| // if the iframe.src points to a foreign url and this |
| // page contains an element, that could get focus |
| try{ |
| doc = elem.contentWindow.document; |
| body = doc && doc.body; |
| return body && body.firstChild && body.firstChild.contentEditable == 'true'; |
| }catch(e){ |
| return false; |
| } |
| } |
| default: |
| return elem.contentEditable == 'true'; |
| } |
| } |
| }; |
| |
| dijit._getTabNavigable = function(/*DOMNode*/root){ |
| // summary: |
| // Finds descendants of the specified root node. |
| // |
| // description: |
| // Finds the following descendants of the specified root node: |
| // * the first tab-navigable element in document order |
| // without a tabIndex or with tabIndex="0" |
| // * the last tab-navigable element in document order |
| // without a tabIndex or with tabIndex="0" |
| // * the first element in document order with the lowest |
| // positive tabIndex value |
| // * the last element in document order with the highest |
| // positive tabIndex value |
| var first, last, lowest, lowestTabindex, highest, highestTabindex; |
| var walkTree = function(/*DOMNode*/parent){ |
| dojo.query("> *", parent).forEach(function(child){ |
| var isShown = dijit._isElementShown(child); |
| if(isShown && dijit.isTabNavigable(child)){ |
| var tabindex = dojo.attr(child, "tabIndex"); |
| if(!dojo.hasAttr(child, "tabIndex") || tabindex == 0){ |
| if(!first){ first = child; } |
| last = child; |
| }else if(tabindex > 0){ |
| if(!lowest || tabindex < lowestTabindex){ |
| lowestTabindex = tabindex; |
| lowest = child; |
| } |
| if(!highest || tabindex >= highestTabindex){ |
| highestTabindex = tabindex; |
| highest = child; |
| } |
| } |
| } |
| if(isShown && child.nodeName.toUpperCase() != 'SELECT'){ walkTree(child) } |
| }); |
| }; |
| if(dijit._isElementShown(root)){ walkTree(root) } |
| return { first: first, last: last, lowest: lowest, highest: highest }; |
| } |
| dijit.getFirstInTabbingOrder = function(/*String|DOMNode*/root){ |
| // summary: |
| // Finds the descendant of the specified root node |
| // that is first in the tabbing order |
| var elems = dijit._getTabNavigable(dojo.byId(root)); |
| return elems.lowest ? elems.lowest : elems.first; // DomNode |
| }; |
| |
| dijit.getLastInTabbingOrder = function(/*String|DOMNode*/root){ |
| // summary: |
| // Finds the descendant of the specified root node |
| // that is last in the tabbing order |
| var elems = dijit._getTabNavigable(dojo.byId(root)); |
| return elems.last ? elems.last : elems.highest; // DomNode |
| }; |
| |
| /*===== |
| dojo.mixin(dijit, { |
| // defaultDuration: Integer |
| // The default animation speed (in ms) to use for all Dijit |
| // transitional animations, unless otherwise specified |
| // on a per-instance basis. Defaults to 200, overrided by |
| // `djConfig.defaultDuration` |
| defaultDuration: 300 |
| }); |
| =====*/ |
| |
| dijit.defaultDuration = dojo.config["defaultDuration"] || 200; |
| |
| } |
| |
| if(!dojo._hasResource["dijit._base.focus"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dijit._base.focus"] = true; |
| dojo.provide("dijit._base.focus"); |
| |
| // for dijit.isTabNavigable() |
| |
| // summary: |
| // These functions are used to query or set the focus and selection. |
| // |
| // Also, they trace when widgets become activated/deactivated, |
| // so that the widget can fire _onFocus/_onBlur events. |
| // "Active" here means something similar to "focused", but |
| // "focus" isn't quite the right word because we keep track of |
| // a whole stack of "active" widgets. Example: ComboButton --> Menu --> |
| // MenuItem. The onBlur event for ComboButton doesn't fire due to focusing |
| // on the Menu or a MenuItem, since they are considered part of the |
| // ComboButton widget. It only happens when focus is shifted |
| // somewhere completely different. |
| |
| dojo.mixin(dijit, { |
| // _curFocus: DomNode |
| // Currently focused item on screen |
| _curFocus: null, |
| |
| // _prevFocus: DomNode |
| // Previously focused item on screen |
| _prevFocus: null, |
| |
| isCollapsed: function(){ |
| // summary: |
| // Returns true if there is no text selected |
| return dijit.getBookmark().isCollapsed; |
| }, |
| |
| getBookmark: function(){ |
| // summary: |
| // Retrieves a bookmark that can be used with moveToBookmark to return to the same range |
| var bm, rg, tg, sel = dojo.doc.selection, cf = dijit._curFocus; |
| |
| if(dojo.global.getSelection){ |
| //W3C Range API for selections. |
| sel = dojo.global.getSelection(); |
| if(sel){ |
| if(sel.isCollapsed){ |
| tg = cf? cf.tagName : ""; |
| if(tg){ |
| //Create a fake rangelike item to restore selections. |
| tg = tg.toLowerCase(); |
| if(tg == "textarea" || |
| (tg == "input" && (!cf.type || cf.type.toLowerCase() == "text"))){ |
| sel = { |
| start: cf.selectionStart, |
| end: cf.selectionEnd, |
| node: cf, |
| pRange: true |
| }; |
| return {isCollapsed: (sel.end <= sel.start), mark: sel}; //Object. |
| } |
| } |
| bm = {isCollapsed:true}; |
| }else{ |
| rg = sel.getRangeAt(0); |
| bm = {isCollapsed: false, mark: rg.cloneRange()}; |
| } |
| } |
| }else if(sel){ |
| // If the current focus was a input of some sort and no selection, don't bother saving |
| // a native bookmark. This is because it causes issues with dialog/page selection restore. |
| // So, we need to create psuedo bookmarks to work with. |
| tg = cf ? cf.tagName : ""; |
| tg = tg.toLowerCase(); |
| if(cf && tg && (tg == "button" || tg == "textarea" || tg == "input")){ |
| if(sel.type && sel.type.toLowerCase() == "none"){ |
| return { |
| isCollapsed: true, |
| mark: null |
| } |
| }else{ |
| rg = sel.createRange(); |
| return { |
| isCollapsed: rg.text && rg.text.length?false:true, |
| mark: { |
| range: rg, |
| pRange: true |
| } |
| }; |
| } |
| } |
| bm = {}; |
| |
| //'IE' way for selections. |
| try{ |
| // createRange() throws exception when dojo in iframe |
| //and nothing selected, see #9632 |
| rg = sel.createRange(); |
| bm.isCollapsed = !(sel.type == 'Text' ? rg.htmlText.length : rg.length); |
| }catch(e){ |
| bm.isCollapsed = true; |
| return bm; |
| } |
| if(sel.type.toUpperCase() == 'CONTROL'){ |
| if(rg.length){ |
| bm.mark=[]; |
| var i=0,len=rg.length; |
| while(i<len){ |
| bm.mark.push(rg.item(i++)); |
| } |
| }else{ |
| bm.isCollapsed = true; |
| bm.mark = null; |
| } |
| }else{ |
| bm.mark = rg.getBookmark(); |
| } |
| }else{ |
| console.warn("No idea how to store the current selection for this browser!"); |
| } |
| return bm; // Object |
| }, |
| |
| moveToBookmark: function(/*Object*/bookmark){ |
| // summary: |
| // Moves current selection to a bookmark |
| // bookmark: |
| // This should be a returned object from dijit.getBookmark() |
| |
| var _doc = dojo.doc, |
| mark = bookmark.mark; |
| if(mark){ |
| if(dojo.global.getSelection){ |
| //W3C Rangi API (FF, WebKit, Opera, etc) |
| var sel = dojo.global.getSelection(); |
| if(sel && sel.removeAllRanges){ |
| if(mark.pRange){ |
| var r = mark; |
| var n = r.node; |
| n.selectionStart = r.start; |
| n.selectionEnd = r.end; |
| }else{ |
| sel.removeAllRanges(); |
| sel.addRange(mark); |
| } |
| }else{ |
| console.warn("No idea how to restore selection for this browser!"); |
| } |
| }else if(_doc.selection && mark){ |
| //'IE' way. |
| var rg; |
| if(mark.pRange){ |
| rg = mark.range; |
| }else if(dojo.isArray(mark)){ |
| rg = _doc.body.createControlRange(); |
| //rg.addElement does not have call/apply method, so can not call it directly |
| //rg is not available in "range.addElement(item)", so can't use that either |
| dojo.forEach(mark, function(n){ |
| rg.addElement(n); |
| }); |
| }else{ |
| rg = _doc.body.createTextRange(); |
| rg.moveToBookmark(mark); |
| } |
| rg.select(); |
| } |
| } |
| }, |
| |
| getFocus: function(/*Widget?*/ menu, /*Window?*/ openedForWindow){ |
| // summary: |
| // Called as getFocus(), this returns an Object showing the current focus |
| // and selected text. |
| // |
| // Called as getFocus(widget), where widget is a (widget representing) a button |
| // that was just pressed, it returns where focus was before that button |
| // was pressed. (Pressing the button may have either shifted focus to the button, |
| // or removed focus altogether.) In this case the selected text is not returned, |
| // since it can't be accurately determined. |
| // |
| // menu: dijit._Widget or {domNode: DomNode} structure |
| // The button that was just pressed. If focus has disappeared or moved |
| // to this button, returns the previous focus. In this case the bookmark |
| // information is already lost, and null is returned. |
| // |
| // openedForWindow: |
| // iframe in which menu was opened |
| // |
| // returns: |
| // A handle to restore focus/selection, to be passed to `dijit.focus` |
| var node = !dijit._curFocus || (menu && dojo.isDescendant(dijit._curFocus, menu.domNode)) ? dijit._prevFocus : dijit._curFocus; |
| return { |
| node: node, |
| bookmark: (node == dijit._curFocus) && dojo.withGlobal(openedForWindow || dojo.global, dijit.getBookmark), |
| openedForWindow: openedForWindow |
| }; // Object |
| }, |
| |
| focus: function(/*Object || DomNode */ handle){ |
| // summary: |
| // Sets the focused node and the selection according to argument. |
| // To set focus to an iframe's content, pass in the iframe itself. |
| // handle: |
| // object returned by get(), or a DomNode |
| |
| if(!handle){ return; } |
| |
| var node = "node" in handle ? handle.node : handle, // because handle is either DomNode or a composite object |
| bookmark = handle.bookmark, |
| openedForWindow = handle.openedForWindow, |
| collapsed = bookmark ? bookmark.isCollapsed : false; |
| |
| // Set the focus |
| // Note that for iframe's we need to use the <iframe> to follow the parentNode chain, |
| // but we need to set focus to iframe.contentWindow |
| if(node){ |
| var focusNode = (node.tagName.toLowerCase() == "iframe") ? node.contentWindow : node; |
| if(focusNode && focusNode.focus){ |
| try{ |
| // Gecko throws sometimes if setting focus is impossible, |
| // node not displayed or something like that |
| focusNode.focus(); |
| }catch(e){/*quiet*/} |
| } |
| dijit._onFocusNode(node); |
| } |
| |
| // set the selection |
| // do not need to restore if current selection is not empty |
| // (use keyboard to select a menu item) or if previous selection was collapsed |
| // as it may cause focus shift (Esp in IE). |
| if(bookmark && dojo.withGlobal(openedForWindow || dojo.global, dijit.isCollapsed) && !collapsed){ |
| if(openedForWindow){ |
| openedForWindow.focus(); |
| } |
| try{ |
| dojo.withGlobal(openedForWindow || dojo.global, dijit.moveToBookmark, null, [bookmark]); |
| }catch(e2){ |
| /*squelch IE internal error, see http://trac.dojotoolkit.org/ticket/1984 */ |
| } |
| } |
| }, |
| |
| // _activeStack: dijit._Widget[] |
| // List of currently active widgets (focused widget and it's ancestors) |
| _activeStack: [], |
| |
| registerIframe: function(/*DomNode*/ iframe){ |
| // summary: |
| // Registers listeners on the specified iframe so that any click |
| // or focus event on that iframe (or anything in it) is reported |
| // as a focus/click event on the <iframe> itself. |
| // description: |
| // Currently only used by editor. |
| // returns: |
| // Handle to pass to unregisterIframe() |
| return dijit.registerWin(iframe.contentWindow, iframe); |
| }, |
| |
| unregisterIframe: function(/*Object*/ handle){ |
| // summary: |
| // Unregisters listeners on the specified iframe created by registerIframe. |
| // After calling be sure to delete or null out the handle itself. |
| // handle: |
| // Handle returned by registerIframe() |
| |
| dijit.unregisterWin(handle); |
| }, |
| |
| registerWin: function(/*Window?*/targetWindow, /*DomNode?*/ effectiveNode){ |
| // summary: |
| // Registers listeners on the specified window (either the main |
| // window or an iframe's window) to detect when the user has clicked somewhere |
| // or focused somewhere. |
| // description: |
| // Users should call registerIframe() instead of this method. |
| // targetWindow: |
| // If specified this is the window associated with the iframe, |
| // i.e. iframe.contentWindow. |
| // effectiveNode: |
| // If specified, report any focus events inside targetWindow as |
| // an event on effectiveNode, rather than on evt.target. |
| // returns: |
| // Handle to pass to unregisterWin() |
| |
| // TODO: make this function private in 2.0; Editor/users should call registerIframe(), |
| |
| var mousedownListener = function(evt){ |
| dijit._justMouseDowned = true; |
| setTimeout(function(){ dijit._justMouseDowned = false; }, 0); |
| dijit._onTouchNode(effectiveNode || evt.target || evt.srcElement, "mouse"); |
| }; |
| //dojo.connect(targetWindow, "onscroll", ???); |
| |
| // Listen for blur and focus events on targetWindow's document. |
| // IIRC, I'm using attachEvent() rather than dojo.connect() because focus/blur events don't bubble |
| // through dojo.connect(), and also maybe to catch the focus events early, before onfocus handlers |
| // fire. |
| // Connect to <html> (rather than document) on IE to avoid memory leaks, but document on other browsers because |
| // (at least for FF) the focus event doesn't fire on <html> or <body>. |
| var doc = dojo.isIE ? targetWindow.document.documentElement : targetWindow.document; |
| if(doc){ |
| if(dojo.isIE){ |
| doc.attachEvent('onmousedown', mousedownListener); |
| var activateListener = function(evt){ |
| // IE reports that nodes like <body> have gotten focus, even though they have tabIndex=-1, |
| // Should consider those more like a mouse-click than a focus.... |
| if(evt.srcElement.tagName.toLowerCase() != "#document" && |
| dijit.isTabNavigable(evt.srcElement)){ |
| dijit._onFocusNode(effectiveNode || evt.srcElement); |
| }else{ |
| dijit._onTouchNode(effectiveNode || evt.srcElement); |
| } |
| }; |
| doc.attachEvent('onactivate', activateListener); |
| var deactivateListener = function(evt){ |
| dijit._onBlurNode(effectiveNode || evt.srcElement); |
| }; |
| doc.attachEvent('ondeactivate', deactivateListener); |
| |
| return function(){ |
| doc.detachEvent('onmousedown', mousedownListener); |
| doc.detachEvent('onactivate', activateListener); |
| doc.detachEvent('ondeactivate', deactivateListener); |
| doc = null; // prevent memory leak (apparent circular reference via closure) |
| }; |
| }else{ |
| doc.addEventListener('mousedown', mousedownListener, true); |
| var focusListener = function(evt){ |
| dijit._onFocusNode(effectiveNode || evt.target); |
| }; |
| doc.addEventListener('focus', focusListener, true); |
| var blurListener = function(evt){ |
| dijit._onBlurNode(effectiveNode || evt.target); |
| }; |
| doc.addEventListener('blur', blurListener, true); |
| |
| return function(){ |
| doc.removeEventListener('mousedown', mousedownListener, true); |
| doc.removeEventListener('focus', focusListener, true); |
| doc.removeEventListener('blur', blurListener, true); |
| doc = null; // prevent memory leak (apparent circular reference via closure) |
| }; |
| } |
| } |
| }, |
| |
| unregisterWin: function(/*Handle*/ handle){ |
| // summary: |
| // Unregisters listeners on the specified window (either the main |
| // window or an iframe's window) according to handle returned from registerWin(). |
| // After calling be sure to delete or null out the handle itself. |
| |
| // Currently our handle is actually a function |
| handle && handle(); |
| }, |
| |
| _onBlurNode: function(/*DomNode*/ node){ |
| // summary: |
| // Called when focus leaves a node. |
| // Usually ignored, _unless_ it *isn't* follwed by touching another node, |
| // which indicates that we tabbed off the last field on the page, |
| // in which case every widget is marked inactive |
| dijit._prevFocus = dijit._curFocus; |
| dijit._curFocus = null; |
| |
| if(dijit._justMouseDowned){ |
| // the mouse down caused a new widget to be marked as active; this blur event |
| // is coming late, so ignore it. |
| return; |
| } |
| |
| // if the blur event isn't followed by a focus event then mark all widgets as inactive. |
| if(dijit._clearActiveWidgetsTimer){ |
| clearTimeout(dijit._clearActiveWidgetsTimer); |
| } |
| dijit._clearActiveWidgetsTimer = setTimeout(function(){ |
| delete dijit._clearActiveWidgetsTimer; |
| dijit._setStack([]); |
| dijit._prevFocus = null; |
| }, 100); |
| }, |
| |
| _onTouchNode: function(/*DomNode*/ node, /*String*/ by){ |
| // summary: |
| // Callback when node is focused or mouse-downed |
| // node: |
| // The node that was touched. |
| // by: |
| // "mouse" if the focus/touch was caused by a mouse down event |
| |
| // ignore the recent blurNode event |
| if(dijit._clearActiveWidgetsTimer){ |
| clearTimeout(dijit._clearActiveWidgetsTimer); |
| delete dijit._clearActiveWidgetsTimer; |
| } |
| |
| // compute stack of active widgets (ex: ComboButton --> Menu --> MenuItem) |
| var newStack=[]; |
| try{ |
| while(node){ |
| var popupParent = dojo.attr(node, "dijitPopupParent"); |
| if(popupParent){ |
| node=dijit.byId(popupParent).domNode; |
| }else if(node.tagName && node.tagName.toLowerCase() == "body"){ |
| // is this the root of the document or just the root of an iframe? |
| if(node === dojo.body()){ |
| // node is the root of the main document |
| break; |
| } |
| // otherwise, find the iframe this node refers to (can't access it via parentNode, |
| // need to do this trick instead). window.frameElement is supported in IE/FF/Webkit |
| node=dijit.getDocumentWindow(node.ownerDocument).frameElement; |
| }else{ |
| var id = node.getAttribute && node.getAttribute("widgetId"); |
| if(id){ |
| newStack.unshift(id); |
| } |
| node=node.parentNode; |
| } |
| } |
| }catch(e){ /* squelch */ } |
| |
| dijit._setStack(newStack, by); |
| }, |
| |
| _onFocusNode: function(/*DomNode*/ node){ |
| // summary: |
| // Callback when node is focused |
| |
| if(!node){ |
| return; |
| } |
| |
| if(node.nodeType == 9){ |
| // Ignore focus events on the document itself. This is here so that |
| // (for example) clicking the up/down arrows of a spinner |
| // (which don't get focus) won't cause that widget to blur. (FF issue) |
| return; |
| } |
| |
| dijit._onTouchNode(node); |
| |
| if(node == dijit._curFocus){ return; } |
| if(dijit._curFocus){ |
| dijit._prevFocus = dijit._curFocus; |
| } |
| dijit._curFocus = node; |
| dojo.publish("focusNode", [node]); |
| }, |
| |
| _setStack: function(/*String[]*/ newStack, /*String*/ by){ |
| // summary: |
| // The stack of active widgets has changed. Send out appropriate events and records new stack. |
| // newStack: |
| // array of widget id's, starting from the top (outermost) widget |
| // by: |
| // "mouse" if the focus/touch was caused by a mouse down event |
| |
| var oldStack = dijit._activeStack; |
| dijit._activeStack = newStack; |
| |
| // compare old stack to new stack to see how many elements they have in common |
| for(var nCommon=0; nCommon<Math.min(oldStack.length, newStack.length); nCommon++){ |
| if(oldStack[nCommon] != newStack[nCommon]){ |
| break; |
| } |
| } |
| |
| var widget; |
| // for all elements that have gone out of focus, send blur event |
| for(var i=oldStack.length-1; i>=nCommon; i--){ |
| widget = dijit.byId(oldStack[i]); |
| if(widget){ |
| widget._focused = false; |
| widget._hasBeenBlurred = true; |
| if(widget._onBlur){ |
| widget._onBlur(by); |
| } |
| if(widget._setStateClass){ |
| widget._setStateClass(); |
| } |
| dojo.publish("widgetBlur", [widget, by]); |
| } |
| } |
| |
| // for all element that have come into focus, send focus event |
| for(i=nCommon; i<newStack.length; i++){ |
| widget = dijit.byId(newStack[i]); |
| if(widget){ |
| widget._focused = true; |
| if(widget._onFocus){ |
| widget._onFocus(by); |
| } |
| if(widget._setStateClass){ |
| widget._setStateClass(); |
| } |
| dojo.publish("widgetFocus", [widget, by]); |
| } |
| } |
| } |
| }); |
| |
| // register top window and all the iframes it contains |
| dojo.addOnLoad(function(){ |
| var handle = dijit.registerWin(window); |
| if(dojo.isIE){ |
| dojo.addOnWindowUnload(function(){ |
| dijit.unregisterWin(handle); |
| handle = null; |
| }) |
| } |
| }); |
| |
| } |
| |
| if(!dojo._hasResource["dojo.AdapterRegistry"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojo.AdapterRegistry"] = true; |
| dojo.provide("dojo.AdapterRegistry"); |
| |
| dojo.AdapterRegistry = function(/*Boolean?*/ returnWrappers){ |
| // summary: |
| // A registry to make contextual calling/searching easier. |
| // description: |
| // Objects of this class keep list of arrays in the form [name, check, |
| // wrap, directReturn] that are used to determine what the contextual |
| // result of a set of checked arguments is. All check/wrap functions |
| // in this registry should be of the same arity. |
| // example: |
| // | // create a new registry |
| // | var reg = new dojo.AdapterRegistry(); |
| // | reg.register("handleString", |
| // | dojo.isString, |
| // | function(str){ |
| // | // do something with the string here |
| // | } |
| // | ); |
| // | reg.register("handleArr", |
| // | dojo.isArray, |
| // | function(arr){ |
| // | // do something with the array here |
| // | } |
| // | ); |
| // | |
| // | // now we can pass reg.match() *either* an array or a string and |
| // | // the value we pass will get handled by the right function |
| // | reg.match("someValue"); // will call the first function |
| // | reg.match(["someValue"]); // will call the second |
| |
| this.pairs = []; |
| this.returnWrappers = returnWrappers || false; // Boolean |
| } |
| |
| dojo.extend(dojo.AdapterRegistry, { |
| register: function(/*String*/ name, /*Function*/ check, /*Function*/ wrap, /*Boolean?*/ directReturn, /*Boolean?*/ override){ |
| // summary: |
| // register a check function to determine if the wrap function or |
| // object gets selected |
| // name: |
| // a way to identify this matcher. |
| // check: |
| // a function that arguments are passed to from the adapter's |
| // match() function. The check function should return true if the |
| // given arguments are appropriate for the wrap function. |
| // directReturn: |
| // If directReturn is true, the value passed in for wrap will be |
| // returned instead of being called. Alternately, the |
| // AdapterRegistry can be set globally to "return not call" using |
| // the returnWrappers property. Either way, this behavior allows |
| // the registry to act as a "search" function instead of a |
| // function interception library. |
| // override: |
| // If override is given and true, the check function will be given |
| // highest priority. Otherwise, it will be the lowest priority |
| // adapter. |
| this.pairs[((override) ? "unshift" : "push")]([name, check, wrap, directReturn]); |
| }, |
| |
| match: function(/* ... */){ |
| // summary: |
| // Find an adapter for the given arguments. If no suitable adapter |
| // is found, throws an exception. match() accepts any number of |
| // arguments, all of which are passed to all matching functions |
| // from the registered pairs. |
| for(var i = 0; i < this.pairs.length; i++){ |
| var pair = this.pairs[i]; |
| if(pair[1].apply(this, arguments)){ |
| if((pair[3])||(this.returnWrappers)){ |
| return pair[2]; |
| }else{ |
| return pair[2].apply(this, arguments); |
| } |
| } |
| } |
| throw new Error("No match found"); |
| }, |
| |
| unregister: function(name){ |
| // summary: Remove a named adapter from the registry |
| |
| // FIXME: this is kind of a dumb way to handle this. On a large |
| // registry this will be slow-ish and we can use the name as a lookup |
| // should we choose to trade memory for speed. |
| for(var i = 0; i < this.pairs.length; i++){ |
| var pair = this.pairs[i]; |
| if(pair[0] == name){ |
| this.pairs.splice(i, 1); |
| return true; |
| } |
| } |
| return false; |
| } |
| }); |
| |
| } |
| |
| if(!dojo._hasResource["dijit._base.place"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dijit._base.place"] = true; |
| dojo.provide("dijit._base.place"); |
| |
| |
| |
| // ported from dojo.html.util |
| |
| dijit.getViewport = function(){ |
| // summary: |
| // Returns the dimensions and scroll position of the viewable area of a browser window |
| |
| var scrollRoot = (dojo.doc.compatMode == 'BackCompat')? dojo.body() : dojo.doc.documentElement; |
| |
| // get scroll position |
| var scroll = dojo._docScroll(); // scrollRoot.scrollTop/Left should work |
| return { w: scrollRoot.clientWidth, h: scrollRoot.clientHeight, l: scroll.x, t: scroll.y }; |
| }; |
| |
| /*===== |
| dijit.__Position = function(){ |
| // x: Integer |
| // horizontal coordinate in pixels, relative to document body |
| // y: Integer |
| // vertical coordinate in pixels, relative to document body |
| |
| thix.x = x; |
| this.y = y; |
| } |
| =====*/ |
| |
| |
| dijit.placeOnScreen = function( |
| /* DomNode */ node, |
| /* dijit.__Position */ pos, |
| /* String[] */ corners, |
| /* dijit.__Position? */ padding){ |
| // summary: |
| // Positions one of the node's corners at specified position |
| // such that node is fully visible in viewport. |
| // description: |
| // NOTE: node is assumed to be absolutely or relatively positioned. |
| // pos: |
| // Object like {x: 10, y: 20} |
| // corners: |
| // Array of Strings representing order to try corners in, like ["TR", "BL"]. |
| // Possible values are: |
| // * "BL" - bottom left |
| // * "BR" - bottom right |
| // * "TL" - top left |
| // * "TR" - top right |
| // padding: |
| // set padding to put some buffer around the element you want to position. |
| // example: |
| // Try to place node's top right corner at (10,20). |
| // If that makes node go (partially) off screen, then try placing |
| // bottom left corner at (10,20). |
| // | placeOnScreen(node, {x: 10, y: 20}, ["TR", "BL"]) |
| |
| var choices = dojo.map(corners, function(corner){ |
| var c = { corner: corner, pos: {x:pos.x,y:pos.y} }; |
| if(padding){ |
| c.pos.x += corner.charAt(1) == 'L' ? padding.x : -padding.x; |
| c.pos.y += corner.charAt(0) == 'T' ? padding.y : -padding.y; |
| } |
| return c; |
| }); |
| |
| return dijit._place(node, choices); |
| } |
| |
| dijit._place = function(/*DomNode*/ node, /* Array */ choices, /* Function */ layoutNode){ |
| // summary: |
| // Given a list of spots to put node, put it at the first spot where it fits, |
| // of if it doesn't fit anywhere then the place with the least overflow |
| // choices: Array |
| // Array of elements like: {corner: 'TL', pos: {x: 10, y: 20} } |
| // Above example says to put the top-left corner of the node at (10,20) |
| // layoutNode: Function(node, aroundNodeCorner, nodeCorner) |
| // for things like tooltip, they are displayed differently (and have different dimensions) |
| // based on their orientation relative to the parent. This adjusts the popup based on orientation. |
| |
| // get {x: 10, y: 10, w: 100, h:100} type obj representing position of |
| // viewport over document |
| var view = dijit.getViewport(); |
| |
| // This won't work if the node is inside a <div style="position: relative">, |
| // so reattach it to dojo.doc.body. (Otherwise, the positioning will be wrong |
| // and also it might get cutoff) |
| if(!node.parentNode || String(node.parentNode.tagName).toLowerCase() != "body"){ |
| dojo.body().appendChild(node); |
| } |
| |
| var best = null; |
| dojo.some(choices, function(choice){ |
| var corner = choice.corner; |
| var pos = choice.pos; |
| |
| // configure node to be displayed in given position relative to button |
| // (need to do this in order to get an accurate size for the node, because |
| // a tooltips size changes based on position, due to triangle) |
| if(layoutNode){ |
| layoutNode(node, choice.aroundCorner, corner); |
| } |
| |
| // get node's size |
| var style = node.style; |
| var oldDisplay = style.display; |
| var oldVis = style.visibility; |
| style.visibility = "hidden"; |
| style.display = ""; |
| var mb = dojo.marginBox(node); |
| style.display = oldDisplay; |
| style.visibility = oldVis; |
| |
| // coordinates and size of node with specified corner placed at pos, |
| // and clipped by viewport |
| var startX = Math.max(view.l, corner.charAt(1) == 'L' ? pos.x : (pos.x - mb.w)), |
| startY = Math.max(view.t, corner.charAt(0) == 'T' ? pos.y : (pos.y - mb.h)), |
| endX = Math.min(view.l + view.w, corner.charAt(1) == 'L' ? (startX + mb.w) : pos.x), |
| endY = Math.min(view.t + view.h, corner.charAt(0) == 'T' ? (startY + mb.h) : pos.y), |
| width = endX - startX, |
| height = endY - startY, |
| overflow = (mb.w - width) + (mb.h - height); |
| |
| if(best == null || overflow < best.overflow){ |
| best = { |
| corner: corner, |
| aroundCorner: choice.aroundCorner, |
| x: startX, |
| y: startY, |
| w: width, |
| h: height, |
| overflow: overflow |
| }; |
| } |
| return !overflow; |
| }); |
| |
| node.style.left = best.x + "px"; |
| node.style.top = best.y + "px"; |
| if(best.overflow && layoutNode){ |
| layoutNode(node, best.aroundCorner, best.corner); |
| } |
| return best; |
| } |
| |
| dijit.placeOnScreenAroundNode = function( |
| /* DomNode */ node, |
| /* DomNode */ aroundNode, |
| /* Object */ aroundCorners, |
| /* Function? */ layoutNode){ |
| |
| // summary: |
| // Position node adjacent or kitty-corner to aroundNode |
| // such that it's fully visible in viewport. |
| // |
| // description: |
| // Place node such that corner of node touches a corner of |
| // aroundNode, and that node is fully visible. |
| // |
| // aroundCorners: |
| // Ordered list of pairs of corners to try matching up. |
| // Each pair of corners is represented as a key/value in the hash, |
| // where the key corresponds to the aroundNode's corner, and |
| // the value corresponds to the node's corner: |
| // |
| // | { aroundNodeCorner1: nodeCorner1, aroundNodeCorner2: nodeCorner2, ...} |
| // |
| // The following strings are used to represent the four corners: |
| // * "BL" - bottom left |
| // * "BR" - bottom right |
| // * "TL" - top left |
| // * "TR" - top right |
| // |
| // layoutNode: Function(node, aroundNodeCorner, nodeCorner) |
| // For things like tooltip, they are displayed differently (and have different dimensions) |
| // based on their orientation relative to the parent. This adjusts the popup based on orientation. |
| // |
| // example: |
| // | dijit.placeOnScreenAroundNode(node, aroundNode, {'BL':'TL', 'TR':'BR'}); |
| // This will try to position node such that node's top-left corner is at the same position |
| // as the bottom left corner of the aroundNode (ie, put node below |
| // aroundNode, with left edges aligned). If that fails it will try to put |
| // the bottom-right corner of node where the top right corner of aroundNode is |
| // (ie, put node above aroundNode, with right edges aligned) |
| // |
| |
| // get coordinates of aroundNode |
| aroundNode = dojo.byId(aroundNode); |
| var oldDisplay = aroundNode.style.display; |
| aroundNode.style.display=""; |
| // #3172: use the slightly tighter border box instead of marginBox |
| var aroundNodePos = dojo.position(aroundNode, true); |
| aroundNode.style.display=oldDisplay; |
| |
| // place the node around the calculated rectangle |
| return dijit._placeOnScreenAroundRect(node, |
| aroundNodePos.x, aroundNodePos.y, aroundNodePos.w, aroundNodePos.h, // rectangle |
| aroundCorners, layoutNode); |
| }; |
| |
| /*===== |
| dijit.__Rectangle = function(){ |
| // x: Integer |
| // horizontal offset in pixels, relative to document body |
| // y: Integer |
| // vertical offset in pixels, relative to document body |
| // width: Integer |
| // width in pixels |
| // height: Integer |
| // height in pixels |
| |
| this.x = x; |
| this.y = y; |
| this.width = width; |
| this.height = height; |
| } |
| =====*/ |
| |
| |
| dijit.placeOnScreenAroundRectangle = function( |
| /* DomNode */ node, |
| /* dijit.__Rectangle */ aroundRect, |
| /* Object */ aroundCorners, |
| /* Function */ layoutNode){ |
| |
| // summary: |
| // Like dijit.placeOnScreenAroundNode(), except that the "around" |
| // parameter is an arbitrary rectangle on the screen (x, y, width, height) |
| // instead of a dom node. |
| |
| return dijit._placeOnScreenAroundRect(node, |
| aroundRect.x, aroundRect.y, aroundRect.width, aroundRect.height, // rectangle |
| aroundCorners, layoutNode); |
| }; |
| |
| dijit._placeOnScreenAroundRect = function( |
| /* DomNode */ node, |
| /* Number */ x, |
| /* Number */ y, |
| /* Number */ width, |
| /* Number */ height, |
| /* Object */ aroundCorners, |
| /* Function */ layoutNode){ |
| |
| // summary: |
| // Like dijit.placeOnScreenAroundNode(), except it accepts coordinates |
| // of a rectangle to place node adjacent to. |
| |
| // TODO: combine with placeOnScreenAroundRectangle() |
| |
| // Generate list of possible positions for node |
| var choices = []; |
| for(var nodeCorner in aroundCorners){ |
| choices.push( { |
| aroundCorner: nodeCorner, |
| corner: aroundCorners[nodeCorner], |
| pos: { |
| x: x + (nodeCorner.charAt(1) == 'L' ? 0 : width), |
| y: y + (nodeCorner.charAt(0) == 'T' ? 0 : height) |
| } |
| }); |
| } |
| |
| return dijit._place(node, choices, layoutNode); |
| }; |
| |
| dijit.placementRegistry= new dojo.AdapterRegistry(); |
| dijit.placementRegistry.register("node", |
| function(n, x){ |
| return typeof x == "object" && |
| typeof x.offsetWidth != "undefined" && typeof x.offsetHeight != "undefined"; |
| }, |
| dijit.placeOnScreenAroundNode); |
| dijit.placementRegistry.register("rect", |
| function(n, x){ |
| return typeof x == "object" && |
| "x" in x && "y" in x && "width" in x && "height" in x; |
| }, |
| dijit.placeOnScreenAroundRectangle); |
| |
| dijit.placeOnScreenAroundElement = function( |
| /* DomNode */ node, |
| /* Object */ aroundElement, |
| /* Object */ aroundCorners, |
| /* Function */ layoutNode){ |
| |
| // summary: |
| // Like dijit.placeOnScreenAroundNode(), except it accepts an arbitrary object |
| // for the "around" argument and finds a proper processor to place a node. |
| |
| return dijit.placementRegistry.match.apply(dijit.placementRegistry, arguments); |
| }; |
| |
| dijit.getPopupAlignment = function(/*Array*/ position, /*Boolean*/ leftToRight){ |
| // summary: |
| // Transforms the passed array of preferred positions into a format suitable for passing as the aroundCorners argument to dijit.placeOnScreenAroundElement. |
| // |
| // position: String[] |
| // This variable controls the position of the drop down. |
| // It's an array of strings with the following values: |
| // |
| // * before: places drop down to the left of the target node/widget, or to the right in |
| // the case of RTL scripts like Hebrew and Arabic |
| // * after: places drop down to the right of the target node/widget, or to the left in |
| // the case of RTL scripts like Hebrew and Arabic |
| // * above: drop down goes above target node |
| // * below: drop down goes below target node |
| // |
| // The list is positions is tried, in order, until a position is found where the drop down fits |
| // within the viewport. |
| // |
| // leftToRight: Boolean |
| // Whether the popup will be displaying in leftToRight mode. |
| // |
| var align = {}; |
| dojo.forEach(position, function(pos){ |
| switch(pos){ |
| case "after": |
| align[leftToRight ? "BR" : "BL"] = leftToRight ? "BL" : "BR"; |
| break; |
| case "before": |
| align[leftToRight ? "BL" : "BR"] = leftToRight ? "BR" : "BL"; |
| break; |
| case "below": |
| // first try to align left borders, next try to align right borders (or reverse for RTL mode) |
| align[leftToRight ? "BL" : "BR"] = leftToRight ? "TL" : "TR"; |
| align[leftToRight ? "BR" : "BL"] = leftToRight ? "TR" : "TL"; |
| break; |
| case "above": |
| default: |
| // first try to align left borders, next try to align right borders (or reverse for RTL mode) |
| align[leftToRight ? "TL" : "TR"] = leftToRight ? "BL" : "BR"; |
| align[leftToRight ? "TR" : "TL"] = leftToRight ? "BR" : "BL"; |
| break; |
| } |
| }); |
| return align; |
| }; |
| dijit.getPopupAroundAlignment = function(/*Array*/ position, /*Boolean*/ leftToRight){ |
| // summary: |
| // Transforms the passed array of preferred positions into a format suitable for passing as the aroundCorners argument to dijit.placeOnScreenAroundElement. |
| // |
| // position: String[] |
| // This variable controls the position of the drop down. |
| // It's an array of strings with the following values: |
| // |
| // * before: places drop down to the left of the target node/widget, or to the right in |
| // the case of RTL scripts like Hebrew and Arabic |
| // * after: places drop down to the right of the target node/widget, or to the left in |
| // the case of RTL scripts like Hebrew and Arabic |
| // * above: drop down goes above target node |
| // * below: drop down goes below target node |
| // |
| // The list is positions is tried, in order, until a position is found where the drop down fits |
| // within the viewport. |
| // |
| // leftToRight: Boolean |
| // Whether the popup will be displaying in leftToRight mode. |
| // |
| var align = {}; |
| dojo.forEach(position, function(pos){ |
| switch(pos){ |
| case "after": |
| align[leftToRight ? "BR" : "BL"] = leftToRight ? "BL" : "BR"; |
| break; |
| case "before": |
| align[leftToRight ? "BL" : "BR"] = leftToRight ? "BR" : "BL"; |
| break; |
| case "below": |
| // first try to align left borders, next try to align right borders (or reverse for RTL mode) |
| align[leftToRight ? "BL" : "BR"] = leftToRight ? "TL" : "TR"; |
| align[leftToRight ? "BR" : "BL"] = leftToRight ? "TR" : "TL"; |
| break; |
| case "above": |
| default: |
| // first try to align left borders, next try to align right borders (or reverse for RTL mode) |
| align[leftToRight ? "TL" : "TR"] = leftToRight ? "BL" : "BR"; |
| align[leftToRight ? "TR" : "TL"] = leftToRight ? "BR" : "BL"; |
| break; |
| } |
| }); |
| return align; |
| }; |
| |
| } |
| |
| if(!dojo._hasResource["dijit._base.window"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dijit._base.window"] = true; |
| dojo.provide("dijit._base.window"); |
| |
| // TODO: remove this in 2.0, it's not used anymore, or at least not internally |
| |
| dijit.getDocumentWindow = function(doc){ |
| // summary: |
| // Get window object associated with document doc |
| |
| // In some IE versions (at least 6.0), document.parentWindow does not return a |
| // reference to the real window object (maybe a copy), so we must fix it as well |
| // We use IE specific execScript to attach the real window reference to |
| // document._parentWindow for later use |
| if(dojo.isIE && window !== document.parentWindow && !doc._parentWindow){ |
| /* |
| In IE 6, only the variable "window" can be used to connect events (others |
| may be only copies). |
| */ |
| doc.parentWindow.execScript("document._parentWindow = window;", "Javascript"); |
| //to prevent memory leak, unset it after use |
| //another possibility is to add an onUnload handler which seems overkill to me (liucougar) |
| var win = doc._parentWindow; |
| doc._parentWindow = null; |
| return win; // Window |
| } |
| |
| return doc._parentWindow || doc.parentWindow || doc.defaultView; // Window |
| } |
| |
| } |
| |
| if(!dojo._hasResource["dijit._base.popup"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dijit._base.popup"] = true; |
| dojo.provide("dijit._base.popup"); |
| |
| |
| |
| |
| |
| dijit.popup = new function(){ |
| // summary: |
| // This class is used to show/hide widgets as popups. |
| |
| var stack = [], |
| beginZIndex=1000, |
| idGen = 1; |
| |
| this.moveOffScreen = function(/*DomNode*/ node){ |
| // summary: |
| // Moves node offscreen without hiding it (so that all layout widgets included |
| // in this node can still layout properly) |
| // |
| // description: |
| // Attaches node to dojo.doc.body, and |
| // positions it off screen, but not display:none, so that |
| // the widget doesn't appear in the page flow and/or cause a blank |
| // area at the bottom of the viewport (making scrollbar longer), but |
| // initialization of contained widgets works correctly |
| |
| var s = node.style; |
| s.visibility = "hidden"; // so TAB key doesn't navigate to hidden popup |
| s.position = "absolute"; |
| s.top = "-9999px"; |
| if(s.display == "none"){ |
| s.display=""; |
| } |
| dojo.body().appendChild(node); |
| }; |
| |
| /*===== |
| dijit.popup.__OpenArgs = function(){ |
| // popup: Widget |
| // widget to display |
| // parent: Widget |
| // the button etc. that is displaying this popup |
| // around: DomNode |
| // DOM node (typically a button); place popup relative to this node. (Specify this *or* "x" and "y" parameters.) |
| // x: Integer |
| // Absolute horizontal position (in pixels) to place node at. (Specify this *or* "around" parameter.) |
| // y: Integer |
| // Absolute vertical position (in pixels) to place node at. (Specity this *or* "around" parameter.) |
| // orient: Object || String |
| // When the around parameter is specified, orient should be an |
| // ordered list of tuples of the form (around-node-corner, popup-node-corner). |
| // dijit.popup.open() tries to position the popup according to each tuple in the list, in order, |
| // until the popup appears fully within the viewport. |
| // |
| // The default value is {BL:'TL', TL:'BL'}, which represents a list of two tuples: |
| // 1. (BL, TL) |
| // 2. (TL, BL) |
| // where BL means "bottom left" and "TL" means "top left". |
| // So by default, it first tries putting the popup below the around node, left-aligning them, |
| // and then tries to put it above the around node, still left-aligning them. Note that the |
| // default is horizontally reversed when in RTL mode. |
| // |
| // When an (x,y) position is specified rather than an around node, orient is either |
| // "R" or "L". R (for right) means that it tries to put the popup to the right of the mouse, |
| // specifically positioning the popup's top-right corner at the mouse position, and if that doesn't |
| // fit in the viewport, then it tries, in order, the bottom-right corner, the top left corner, |
| // and the top-right corner. |
| // onCancel: Function |
| // callback when user has canceled the popup by |
| // 1. hitting ESC or |
| // 2. by using the popup widget's proprietary cancel mechanism (like a cancel button in a dialog); |
| // i.e. whenever popupWidget.onCancel() is called, args.onCancel is called |
| // onClose: Function |
| // callback whenever this popup is closed |
| // onExecute: Function |
| // callback when user "executed" on the popup/sub-popup by selecting a menu choice, etc. (top menu only) |
| // padding: dijit.__Position |
| // adding a buffer around the opening position. This is only useful when around is not set. |
| this.popup = popup; |
| this.parent = parent; |
| this.around = around; |
| this.x = x; |
| this.y = y; |
| this.orient = orient; |
| this.onCancel = onCancel; |
| this.onClose = onClose; |
| this.onExecute = onExecute; |
| this.padding = padding; |
| } |
| =====*/ |
| |
| // Compute the closest ancestor popup that's *not* a child of another popup. |
| // Ex: For a TooltipDialog with a button that spawns a tree of menus, find the popup of the button. |
| var getTopPopup = function(){ |
| for(var pi=stack.length-1; pi > 0 && stack[pi].parent === stack[pi-1].widget; pi--){ |
| /* do nothing, just trying to get right value for pi */ |
| } |
| return stack[pi]; |
| }; |
| |
| var wrappers=[]; |
| this.open = function(/*dijit.popup.__OpenArgs*/ args){ |
| // summary: |
| // Popup the widget at the specified position |
| // |
| // example: |
| // opening at the mouse position |
| // | dijit.popup.open({popup: menuWidget, x: evt.pageX, y: evt.pageY}); |
| // |
| // example: |
| // opening the widget as a dropdown |
| // | dijit.popup.open({parent: this, popup: menuWidget, around: this.domNode, onClose: function(){...}}); |
| // |
| // Note that whatever widget called dijit.popup.open() should also listen to its own _onBlur callback |
| // (fired from _base/focus.js) to know that focus has moved somewhere else and thus the popup should be closed. |
| |
| var widget = args.popup, |
| orient = args.orient || ( |
| dojo._isBodyLtr() ? |
| {'BL':'TL', 'BR':'TR', 'TL':'BL', 'TR':'BR'} : |
| {'BR':'TR', 'BL':'TL', 'TR':'BR', 'TL':'BL'} |
| ), |
| around = args.around, |
| id = (args.around && args.around.id) ? (args.around.id+"_dropdown") : ("popup_"+idGen++); |
| |
| // make wrapper div to hold widget and possibly hold iframe behind it. |
| // we can't attach the iframe as a child of the widget.domNode because |
| // widget.domNode might be a <table>, <ul>, etc. |
| |
| var wrapperobj = wrappers.pop(), wrapper, iframe; |
| if(!wrapperobj){ |
| wrapper = dojo.create("div",{ |
| "class":"dijitPopup" |
| }, dojo.body()); |
| dijit.setWaiRole(wrapper, "presentation"); |
| }else{ |
| // recycled a old wrapper, so that we don't need to reattach the iframe |
| // which is slow even if the iframe is empty, see #10167 |
| wrapper = wrapperobj[0]; |
| iframe = wrapperobj[1]; |
| } |
| |
| dojo.attr(wrapper,{ |
| id: id, |
| style:{ |
| zIndex: beginZIndex + stack.length, |
| visibility:"hidden", |
| // prevent transient scrollbar causing misalign (#5776), and initial flash in upper left (#10111) |
| top: "-9999px" |
| }, |
| dijitPopupParent: args.parent ? args.parent.id : "" |
| }); |
| |
| var s = widget.domNode.style; |
| s.display = ""; |
| s.visibility = ""; |
| s.position = ""; |
| s.top = "0px"; |
| wrapper.appendChild(widget.domNode); |
| |
| if(!iframe){ |
| iframe = new dijit.BackgroundIframe(wrapper); |
| }else{ |
| iframe.resize(wrapper) |
| } |
| |
| // position the wrapper node |
| var best = around ? |
| dijit.placeOnScreenAroundElement(wrapper, around, orient, widget.orient ? dojo.hitch(widget, "orient") : null) : |
| dijit.placeOnScreen(wrapper, args, orient == 'R' ? ['TR','BR','TL','BL'] : ['TL','BL','TR','BR'], args.padding); |
| |
| wrapper.style.visibility = "visible"; |
| // TODO: use effects to fade in wrapper |
| |
| var handlers = []; |
| |
| // provide default escape and tab key handling |
| // (this will work for any widget, not just menu) |
| handlers.push(dojo.connect(wrapper, "onkeypress", this, function(evt){ |
| if(evt.charOrCode == dojo.keys.ESCAPE && args.onCancel){ |
| dojo.stopEvent(evt); |
| args.onCancel(); |
| }else if(evt.charOrCode === dojo.keys.TAB){ |
| dojo.stopEvent(evt); |
| var topPopup = getTopPopup(); |
| if(topPopup && topPopup.onCancel){ |
| topPopup.onCancel(); |
| } |
| } |
| })); |
| |
| // watch for cancel/execute events on the popup and notify the caller |
| // (for a menu, "execute" means clicking an item) |
| if(widget.onCancel){ |
| handlers.push(dojo.connect(widget, "onCancel", args.onCancel)); |
| } |
| |
| handlers.push(dojo.connect(widget, widget.onExecute ? "onExecute" : "onChange", function(){ |
| var topPopup = getTopPopup(); |
| if(topPopup && topPopup.onExecute){ |
| topPopup.onExecute(); |
| } |
| })); |
| |
| stack.push({ |
| wrapper: wrapper, |
| iframe: iframe, |
| widget: widget, |
| parent: args.parent, |
| onExecute: args.onExecute, |
| onCancel: args.onCancel, |
| onClose: args.onClose, |
| handlers: handlers |
| }); |
| |
| if(widget.onOpen){ |
| // TODO: in 2.0 standardize onShow() (used by StackContainer) and onOpen() (used here) |
| widget.onOpen(best); |
| } |
| |
| return best; |
| }; |
| |
| this.close = function(/*dijit._Widget*/ popup){ |
| // summary: |
| // Close specified popup and any popups that it parented |
| |
| // Basically work backwards from the top of the stack closing popups |
| // until we hit the specified popup, but IIRC there was some issue where closing |
| // a popup would cause others to close too. Thus if we are trying to close B in [A,B,C] |
| // closing C might close B indirectly and then the while() condition will run where stack==[A]... |
| // so the while condition is constructed defensively. |
| while(dojo.some(stack, function(elem){return elem.widget == popup;})){ |
| var top = stack.pop(), |
| wrapper = top.wrapper, |
| iframe = top.iframe, |
| widget = top.widget, |
| onClose = top.onClose; |
| |
| if(widget.onClose){ |
| // TODO: in 2.0 standardize onHide() (used by StackContainer) and onClose() (used here) |
| widget.onClose(); |
| } |
| dojo.forEach(top.handlers, dojo.disconnect); |
| |
| // Move the widget offscreen, unless it has already been destroyed in above onClose() etc. |
| if(widget && widget.domNode){ |
| this.moveOffScreen(widget.domNode); |
| } |
| |
| // recycle the wrapper plus iframe, so we prevent reattaching iframe everytime an popup opens |
| // don't use moveOffScreen which would also reattach the wrapper to body, which causes reloading of iframe |
| wrapper.style.top = "-9999px"; |
| wrapper.style.visibility = "hidden"; |
| wrappers.push([wrapper,iframe]); |
| |
| if(onClose){ |
| onClose(); |
| } |
| } |
| }; |
| }(); |
| |
| dijit._frames = new function(){ |
| // summary: |
| // cache of iframes |
| var queue = []; |
| |
| this.pop = function(){ |
| var iframe; |
| if(queue.length){ |
| iframe = queue.pop(); |
| iframe.style.display=""; |
| }else{ |
| if(dojo.isIE){ |
| var burl = dojo.config["dojoBlankHtmlUrl"] || (dojo.moduleUrl("dojo", "resources/blank.html")+"") || "javascript:\"\""; |
| var html="<iframe src='" + burl + "'" |
| + " style='position: absolute; left: 0px; top: 0px;" |
| + "z-index: -1; filter:Alpha(Opacity=\"0\");'>"; |
| iframe = dojo.doc.createElement(html); |
| }else{ |
| iframe = dojo.create("iframe"); |
| iframe.src = 'javascript:""'; |
| iframe.className = "dijitBackgroundIframe"; |
| dojo.style(iframe, "opacity", 0.1); |
| } |
| iframe.tabIndex = -1; // Magic to prevent iframe from getting focus on tab keypress - as style didnt work. |
| } |
| return iframe; |
| }; |
| |
| this.push = function(iframe){ |
| iframe.style.display="none"; |
| queue.push(iframe); |
| } |
| }(); |
| |
| |
| dijit.BackgroundIframe = function(/* DomNode */node){ |
| // summary: |
| // For IE/FF z-index schenanigans. id attribute is required. |
| // |
| // description: |
| // new dijit.BackgroundIframe(node) |
| // Makes a background iframe as a child of node, that fills |
| // area (and position) of node |
| |
| if(!node.id){ throw new Error("no id"); } |
| if(dojo.isIE || dojo.isMoz){ |
| var iframe = dijit._frames.pop(); |
| node.appendChild(iframe); |
| if(dojo.isIE<7){ |
| this.resize(node); |
| this._conn = dojo.connect(node, 'onresize', this, function(){ |
| this.resize(node); |
| }); |
| }else{ |
| dojo.style(iframe, { |
| width: '100%', |
| height: '100%' |
| }); |
| } |
| this.iframe = iframe; |
| } |
| }; |
| |
| dojo.extend(dijit.BackgroundIframe, { |
| resize: function(node){ |
| // summary: |
| // resize the iframe so its the same size as node |
| // description: |
| // this function is a no-op in all browsers except |
| // IE6, which does not support 100% width/height |
| // of absolute positioned iframes |
| if(this.iframe && dojo.isIE<7){ |
| dojo.style(this.iframe, { |
| width: node.offsetWidth + 'px', |
| height: node.offsetHeight + 'px' |
| }); |
| } |
| }, |
| destroy: function(){ |
| // summary: |
| // destroy the iframe |
| if(this._conn){ |
| dojo.disconnect(this._conn); |
| this._conn = null; |
| } |
| if(this.iframe){ |
| dijit._frames.push(this.iframe); |
| delete this.iframe; |
| } |
| } |
| }); |
| |
| } |
| |
| if(!dojo._hasResource["dijit._base.scroll"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dijit._base.scroll"] = true; |
| dojo.provide("dijit._base.scroll"); |
| |
| dijit.scrollIntoView = function(/*DomNode*/ node, /*Object?*/ pos){ |
| // summary: |
| // Scroll the passed node into view, if it is not already. |
| |
| // don't rely on that node.scrollIntoView works just because the function is there |
| |
| try{ // catch unexpected/unrecreatable errors (#7808) since we can recover using a semi-acceptable native method |
| node = dojo.byId(node); |
| var doc = node.ownerDocument || dojo.doc, |
| body = doc.body || dojo.body(), |
| html = doc.documentElement || body.parentNode, |
| isIE = dojo.isIE, isWK = dojo.isWebKit; |
| // if an untested browser, then use the native method |
| if((!(dojo.isMoz || isIE || isWK) || node == body || node == html) && (typeof node.scrollIntoView != "undefined")){ |
| node.scrollIntoView(false); // short-circuit to native if possible |
| return; |
| } |
| var backCompat = doc.compatMode == 'BackCompat', |
| clientAreaRoot = backCompat? body : html, |
| scrollRoot = isWK ? body : clientAreaRoot, |
| rootWidth = clientAreaRoot.clientWidth, |
| rootHeight = clientAreaRoot.clientHeight, |
| rtl = !dojo._isBodyLtr(), |
| nodePos = pos || dojo.position(node), |
| el = node.parentNode, |
| isFixed = function(el){ |
| return ((isIE <= 6 || (isIE && backCompat))? false : (dojo.style(el, 'position').toLowerCase() == "fixed")); |
| }; |
| if(isFixed(node)){ return; } // nothing to do |
| while(el){ |
| if(el == body){ el = scrollRoot; } |
| var elPos = dojo.position(el), |
| fixedPos = isFixed(el); |
| with(elPos){ |
| if(el == scrollRoot){ |
| w = rootWidth, h = rootHeight; |
| if(scrollRoot == html && isIE && rtl){ x += scrollRoot.offsetWidth-w; } // IE workaround where scrollbar causes negative x |
| if(x < 0 || !isIE){ x = 0; } // IE can have values > 0 |
| if(y < 0 || !isIE){ y = 0; } |
| }else{ |
| var pb = dojo._getPadBorderExtents(el); |
| w -= pb.w; h -= pb.h; x += pb.l; y += pb.t; |
| } |
| with(el){ |
| if(el != scrollRoot){ // body, html sizes already have the scrollbar removed |
| var clientSize = clientWidth, |
| scrollBarSize = w - clientSize; |
| if(clientSize > 0 && scrollBarSize > 0){ |
| w = clientSize; |
| if(isIE && rtl){ x += scrollBarSize; } |
| } |
| clientSize = clientHeight; |
| scrollBarSize = h - clientSize; |
| if(clientSize > 0 && scrollBarSize > 0){ |
| h = clientSize; |
| } |
| } |
| if(fixedPos){ // bounded by viewport, not parents |
| if(y < 0){ |
| h += y, y = 0; |
| } |
| if(x < 0){ |
| w += x, x = 0; |
| } |
| if(y + h > rootHeight){ |
| h = rootHeight - y; |
| } |
| if(x + w > rootWidth){ |
| w = rootWidth - x; |
| } |
| } |
| // calculate overflow in all 4 directions |
| var l = nodePos.x - x, // beyond left: < 0 |
| t = nodePos.y - Math.max(y, 0), // beyond top: < 0 |
| r = l + nodePos.w - w, // beyond right: > 0 |
| bot = t + nodePos.h - h; // beyond bottom: > 0 |
| if(r * l > 0){ |
| var s = Math[l < 0? "max" : "min"](l, r); |
| nodePos.x += scrollLeft; |
| scrollLeft += (isIE >= 8 && !backCompat && rtl)? -s : s; |
| nodePos.x -= scrollLeft; |
| } |
| if(bot * t > 0){ |
| nodePos.y += scrollTop; |
| scrollTop += Math[t < 0? "max" : "min"](t, bot); |
| nodePos.y -= scrollTop; |
| } |
| } |
| } |
| el = (el != scrollRoot) && !fixedPos && el.parentNode; |
| } |
| }catch(error){ |
| console.error('scrollIntoView: ' + error); |
| node.scrollIntoView(false); |
| } |
| }; |
| |
| } |
| |
| if(!dojo._hasResource["dijit._base.sniff"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dijit._base.sniff"] = true; |
| // summary: |
| // Applies pre-set CSS classes to the top-level HTML node, based on: |
| // - browser (ex: dj_ie) |
| // - browser version (ex: dj_ie6) |
| // - box model (ex: dj_contentBox) |
| // - text direction (ex: dijitRtl) |
| // |
| // In addition, browser, browser version, and box model are |
| // combined with an RTL flag when browser text is RTL. ex: dj_ie-rtl. |
| // |
| // Simply doing a require on this module will |
| // establish this CSS. Modified version of Morris' CSS hack. |
| |
| dojo.provide("dijit._base.sniff"); |
| |
| (function(){ |
| |
| var d = dojo, |
| html = d.doc.documentElement, |
| ie = d.isIE, |
| opera = d.isOpera, |
| maj = Math.floor, |
| ff = d.isFF, |
| boxModel = d.boxModel.replace(/-/,''), |
| |
| classes = { |
| dj_ie: ie, |
| dj_ie6: maj(ie) == 6, |
| dj_ie7: maj(ie) == 7, |
| dj_ie8: maj(ie) == 8, |
| dj_iequirks: ie && d.isQuirks, |
| |
| // NOTE: Opera not supported by dijit |
| dj_opera: opera, |
| |
| dj_khtml: d.isKhtml, |
| |
| dj_webkit: d.isWebKit, |
| dj_safari: d.isSafari, |
| dj_chrome: d.isChrome, |
| |
| dj_gecko: d.isMozilla, |
| dj_ff3: maj(ff) == 3 |
| }; // no dojo unsupported browsers |
| |
| classes["dj_" + boxModel] = true; |
| |
| // apply browser, browser version, and box model class names |
| for(var p in classes){ |
| if(classes[p]){ |
| if(html.className){ |
| html.className += " " + p; |
| }else{ |
| html.className = p; |
| } |
| } |
| } |
| |
| // If RTL mode then add dijitRtl flag plus repeat existing classes |
| // with -rtl extension |
| // (unshift is to make this code run after <body> node is loaded but before parser runs) |
| dojo._loaders.unshift(function(){ |
| if(!dojo._isBodyLtr()){ |
| html.className += " dijitRtl"; |
| for(var p in classes){ |
| if(classes[p]){ |
| html.className += " " + p + "-rtl"; |
| } |
| } |
| } |
| }); |
| |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dijit._base.typematic"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dijit._base.typematic"] = true; |
| dojo.provide("dijit._base.typematic"); |
| |
| dijit.typematic = { |
| // summary: |
| // These functions are used to repetitively call a user specified callback |
| // method when a specific key or mouse click over a specific DOM node is |
| // held down for a specific amount of time. |
| // Only 1 such event is allowed to occur on the browser page at 1 time. |
| |
| _fireEventAndReload: function(){ |
| this._timer = null; |
| this._callback(++this._count, this._node, this._evt); |
| |
| // Schedule next event, reducing the timer a little bit each iteration, bottoming-out at 10 to avoid |
| // browser overload (particularly avoiding starving DOH robot so it never gets to send a mouseup) |
| this._currentTimeout = Math.max( |
| this._currentTimeout < 0 ? this._initialDelay : |
| (this._subsequentDelay > 1 ? this._subsequentDelay : Math.round(this._currentTimeout * this._subsequentDelay)), |
| 10); |
| this._timer = setTimeout(dojo.hitch(this, "_fireEventAndReload"), this._currentTimeout); |
| }, |
| |
| trigger: function(/*Event*/ evt, /* Object */ _this, /*DOMNode*/ node, /* Function */ callback, /* Object */ obj, /* Number */ subsequentDelay, /* Number */ initialDelay){ |
| // summary: |
| // Start a timed, repeating callback sequence. |
| // If already started, the function call is ignored. |
| // This method is not normally called by the user but can be |
| // when the normal listener code is insufficient. |
| // evt: |
| // key or mouse event object to pass to the user callback |
| // _this: |
| // pointer to the user's widget space. |
| // node: |
| // the DOM node object to pass the the callback function |
| // callback: |
| // function to call until the sequence is stopped called with 3 parameters: |
| // count: |
| // integer representing number of repeated calls (0..n) with -1 indicating the iteration has stopped |
| // node: |
| // the DOM node object passed in |
| // evt: |
| // key or mouse event object |
| // obj: |
| // user space object used to uniquely identify each typematic sequence |
| // subsequentDelay: |
| // if > 1, the number of milliseconds until the 3->n events occur |
| // or else the fractional time multiplier for the next event's delay, default=0.9 |
| // initialDelay: |
| // the number of milliseconds until the 2nd event occurs, default=500ms |
| if(obj != this._obj){ |
| this.stop(); |
| this._initialDelay = initialDelay || 500; |
| this._subsequentDelay = subsequentDelay || 0.90; |
| this._obj = obj; |
| this._evt = evt; |
| this._node = node; |
| this._currentTimeout = -1; |
| this._count = -1; |
| this._callback = dojo.hitch(_this, callback); |
| this._fireEventAndReload(); |
| } |
| }, |
| |
| stop: function(){ |
| // summary: |
| // Stop an ongoing timed, repeating callback sequence. |
| if(this._timer){ |
| clearTimeout(this._timer); |
| this._timer = null; |
| } |
| if(this._obj){ |
| this._callback(-1, this._node, this._evt); |
| this._obj = null; |
| } |
| }, |
| |
| addKeyListener: function(/*DOMNode*/ node, /*Object*/ keyObject, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay){ |
| // summary: |
| // Start listening for a specific typematic key. |
| // See also the trigger method for other parameters. |
| // keyObject: |
| // an object defining the key to listen for. |
| // charOrCode: |
| // the printable character (string) or keyCode (number) to listen for. |
| // keyCode: |
| // (deprecated - use charOrCode) the keyCode (number) to listen for (implies charCode = 0). |
| // charCode: |
| // (deprecated - use charOrCode) the charCode (number) to listen for. |
| // ctrlKey: |
| // desired ctrl key state to initiate the calback sequence: |
| // - pressed (true) |
| // - released (false) |
| // - either (unspecified) |
| // altKey: |
| // same as ctrlKey but for the alt key |
| // shiftKey: |
| // same as ctrlKey but for the shift key |
| // returns: |
| // an array of dojo.connect handles |
| if(keyObject.keyCode){ |
| keyObject.charOrCode = keyObject.keyCode; |
| dojo.deprecated("keyCode attribute parameter for dijit.typematic.addKeyListener is deprecated. Use charOrCode instead.", "", "2.0"); |
| }else if(keyObject.charCode){ |
| keyObject.charOrCode = String.fromCharCode(keyObject.charCode); |
| dojo.deprecated("charCode attribute parameter for dijit.typematic.addKeyListener is deprecated. Use charOrCode instead.", "", "2.0"); |
| } |
| return [ |
| dojo.connect(node, "onkeypress", this, function(evt){ |
| if(evt.charOrCode == keyObject.charOrCode && |
| (keyObject.ctrlKey === undefined || keyObject.ctrlKey == evt.ctrlKey) && |
| (keyObject.altKey === undefined || keyObject.altKey == evt.altKey) && |
| (keyObject.metaKey === undefined || keyObject.metaKey == (evt.metaKey || false)) && // IE doesn't even set metaKey |
| (keyObject.shiftKey === undefined || keyObject.shiftKey == evt.shiftKey)){ |
| dojo.stopEvent(evt); |
| dijit.typematic.trigger(keyObject, _this, node, callback, keyObject, subsequentDelay, initialDelay); |
| }else if(dijit.typematic._obj == keyObject){ |
| dijit.typematic.stop(); |
| } |
| }), |
| dojo.connect(node, "onkeyup", this, function(evt){ |
| if(dijit.typematic._obj == keyObject){ |
| dijit.typematic.stop(); |
| } |
| }) |
| ]; |
| }, |
| |
| addMouseListener: function(/*DOMNode*/ node, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay){ |
| // summary: |
| // Start listening for a typematic mouse click. |
| // See the trigger method for other parameters. |
| // returns: |
| // an array of dojo.connect handles |
| var dc = dojo.connect; |
| return [ |
| dc(node, "mousedown", this, function(evt){ |
| dojo.stopEvent(evt); |
| dijit.typematic.trigger(evt, _this, node, callback, node, subsequentDelay, initialDelay); |
| }), |
| dc(node, "mouseup", this, function(evt){ |
| dojo.stopEvent(evt); |
| dijit.typematic.stop(); |
| }), |
| dc(node, "mouseout", this, function(evt){ |
| dojo.stopEvent(evt); |
| dijit.typematic.stop(); |
| }), |
| dc(node, "mousemove", this, function(evt){ |
| dojo.stopEvent(evt); |
| }), |
| dc(node, "dblclick", this, function(evt){ |
| dojo.stopEvent(evt); |
| if(dojo.isIE){ |
| dijit.typematic.trigger(evt, _this, node, callback, node, subsequentDelay, initialDelay); |
| setTimeout(dojo.hitch(this, dijit.typematic.stop), 50); |
| } |
| }) |
| ]; |
| }, |
| |
| addListener: function(/*Node*/ mouseNode, /*Node*/ keyNode, /*Object*/ keyObject, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay){ |
| // summary: |
| // Start listening for a specific typematic key and mouseclick. |
| // This is a thin wrapper to addKeyListener and addMouseListener. |
| // See the addMouseListener and addKeyListener methods for other parameters. |
| // mouseNode: |
| // the DOM node object to listen on for mouse events. |
| // keyNode: |
| // the DOM node object to listen on for key events. |
| // returns: |
| // an array of dojo.connect handles |
| return this.addKeyListener(keyNode, keyObject, _this, callback, subsequentDelay, initialDelay).concat( |
| this.addMouseListener(mouseNode, _this, callback, subsequentDelay, initialDelay)); |
| } |
| }; |
| |
| } |
| |
| if(!dojo._hasResource["dijit._base.wai"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dijit._base.wai"] = true; |
| dojo.provide("dijit._base.wai"); |
| |
| dijit.wai = { |
| onload: function(){ |
| // summary: |
| // Detects if we are in high-contrast mode or not |
| |
| // This must be a named function and not an anonymous |
| // function, so that the widget parsing code can make sure it |
| // registers its onload function after this function. |
| // DO NOT USE "this" within this function. |
| |
| // create div for testing if high contrast mode is on or images are turned off |
| var div = dojo.create("div",{ |
| id: "a11yTestNode", |
| style:{ |
| cssText:'border: 1px solid;' |
| + 'border-color:red green;' |
| + 'position: absolute;' |
| + 'height: 5px;' |
| + 'top: -999px;' |
| + 'background-image: url("' + (dojo.config.blankGif || dojo.moduleUrl("dojo", "resources/blank.gif")) + '");' |
| } |
| }, dojo.body()); |
| |
| // test it |
| var cs = dojo.getComputedStyle(div); |
| if(cs){ |
| var bkImg = cs.backgroundImage; |
| var needsA11y = (cs.borderTopColor == cs.borderRightColor) || (bkImg != null && (bkImg == "none" || bkImg == "url(invalid-url:)" )); |
| dojo[needsA11y ? "addClass" : "removeClass"](dojo.body(), "dijit_a11y"); |
| if(dojo.isIE){ |
| div.outerHTML = ""; // prevent mixed-content warning, see http://support.microsoft.com/kb/925014 |
| }else{ |
| dojo.body().removeChild(div); |
| } |
| } |
| } |
| }; |
| |
| // Test if computer is in high contrast mode. |
| // Make sure the a11y test runs first, before widgets are instantiated. |
| if(dojo.isIE || dojo.isMoz){ // NOTE: checking in Safari messes things up |
| dojo._loaders.unshift(dijit.wai.onload); |
| } |
| |
| dojo.mixin(dijit, { |
| _XhtmlRoles: /banner|contentinfo|definition|main|navigation|search|note|secondary|seealso/, |
| |
| hasWaiRole: function(/*Element*/ elem, /*String*/ role){ |
| // summary: |
| // Determines if an element has a particular non-XHTML role. |
| // returns: |
| // True if elem has the specific non-XHTML role attribute and false if not. |
| // For backwards compatibility if role parameter not provided, |
| // returns true if has non XHTML role |
| var waiRole = this.getWaiRole(elem); |
| return role ? (waiRole.indexOf(role) > -1) : (waiRole.length > 0); |
| }, |
| |
| getWaiRole: function(/*Element*/ elem){ |
| // summary: |
| // Gets the non-XHTML role for an element (which should be a wai role). |
| // returns: |
| // The non-XHTML role of elem or an empty string if elem |
| // does not have a role. |
| return dojo.trim((dojo.attr(elem, "role") || "").replace(this._XhtmlRoles,"").replace("wairole:","")); |
| }, |
| |
| setWaiRole: function(/*Element*/ elem, /*String*/ role){ |
| // summary: |
| // Sets the role on an element. |
| // description: |
| // Replace existing role attribute with new role. |
| // If elem already has an XHTML role, append this role to XHTML role |
| // and remove other ARIA roles. |
| |
| var curRole = dojo.attr(elem, "role") || ""; |
| if(!this._XhtmlRoles.test(curRole)){ |
| dojo.attr(elem, "role", role); |
| }else{ |
| if((" "+ curRole +" ").indexOf(" " + role + " ") < 0){ |
| var clearXhtml = dojo.trim(curRole.replace(this._XhtmlRoles, "")); |
| var cleanRole = dojo.trim(curRole.replace(clearXhtml, "")); |
| dojo.attr(elem, "role", cleanRole + (cleanRole ? ' ' : '') + role); |
| } |
| } |
| }, |
| |
| removeWaiRole: function(/*Element*/ elem, /*String*/ role){ |
| // summary: |
| // Removes the specified non-XHTML role from an element. |
| // Removes role attribute if no specific role provided (for backwards compat.) |
| |
| var roleValue = dojo.attr(elem, "role"); |
| if(!roleValue){ return; } |
| if(role){ |
| var t = dojo.trim((" " + roleValue + " ").replace(" " + role + " ", " ")); |
| dojo.attr(elem, "role", t); |
| }else{ |
| elem.removeAttribute("role"); |
| } |
| }, |
| |
| hasWaiState: function(/*Element*/ elem, /*String*/ state){ |
| // summary: |
| // Determines if an element has a given state. |
| // description: |
| // Checks for an attribute called "aria-"+state. |
| // returns: |
| // true if elem has a value for the given state and |
| // false if it does not. |
| |
| return elem.hasAttribute ? elem.hasAttribute("aria-"+state) : !!elem.getAttribute("aria-"+state); |
| }, |
| |
| getWaiState: function(/*Element*/ elem, /*String*/ state){ |
| // summary: |
| // Gets the value of a state on an element. |
| // description: |
| // Checks for an attribute called "aria-"+state. |
| // returns: |
| // The value of the requested state on elem |
| // or an empty string if elem has no value for state. |
| |
| return elem.getAttribute("aria-"+state) || ""; |
| }, |
| |
| setWaiState: function(/*Element*/ elem, /*String*/ state, /*String*/ value){ |
| // summary: |
| // Sets a state on an element. |
| // description: |
| // Sets an attribute called "aria-"+state. |
| |
| elem.setAttribute("aria-"+state, value); |
| }, |
| |
| removeWaiState: function(/*Element*/ elem, /*String*/ state){ |
| // summary: |
| // Removes a state from an element. |
| // description: |
| // Sets an attribute called "aria-"+state. |
| |
| elem.removeAttribute("aria-"+state); |
| } |
| }); |
| |
| } |
| |
| if(!dojo._hasResource["dijit._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dijit._base"] = true; |
| dojo.provide("dijit._base"); |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| } |
| |
| if(!dojo._hasResource["dojo.date.stamp"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojo.date.stamp"] = true; |
| dojo.provide("dojo.date.stamp"); |
| |
| // Methods to convert dates to or from a wire (string) format using well-known conventions |
| |
| dojo.date.stamp.fromISOString = function(/*String*/formattedString, /*Number?*/defaultTime){ |
| // summary: |
| // Returns a Date object given a string formatted according to a subset of the ISO-8601 standard. |
| // |
| // description: |
| // Accepts a string formatted according to a profile of ISO8601 as defined by |
| // [RFC3339](http://www.ietf.org/rfc/rfc3339.txt), except that partial input is allowed. |
| // Can also process dates as specified [by the W3C](http://www.w3.org/TR/NOTE-datetime) |
| // The following combinations are valid: |
| // |
| // * dates only |
| // | * yyyy |
| // | * yyyy-MM |
| // | * yyyy-MM-dd |
| // * times only, with an optional time zone appended |
| // | * THH:mm |
| // | * THH:mm:ss |
| // | * THH:mm:ss.SSS |
| // * and "datetimes" which could be any combination of the above |
| // |
| // timezones may be specified as Z (for UTC) or +/- followed by a time expression HH:mm |
| // Assumes the local time zone if not specified. Does not validate. Improperly formatted |
| // input may return null. Arguments which are out of bounds will be handled |
| // by the Date constructor (e.g. January 32nd typically gets resolved to February 1st) |
| // Only years between 100 and 9999 are supported. |
| // |
| // formattedString: |
| // A string such as 2005-06-30T08:05:00-07:00 or 2005-06-30 or T08:05:00 |
| // |
| // defaultTime: |
| // Used for defaults for fields omitted in the formattedString. |
| // Uses 1970-01-01T00:00:00.0Z by default. |
| |
| if(!dojo.date.stamp._isoRegExp){ |
| dojo.date.stamp._isoRegExp = |
| //TODO: could be more restrictive and check for 00-59, etc. |
| /^(?:(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(.\d+)?)?((?:[+-](\d{2}):(\d{2}))|Z)?)?$/; |
| } |
| |
| var match = dojo.date.stamp._isoRegExp.exec(formattedString), |
| result = null; |
| |
| if(match){ |
| match.shift(); |
| if(match[1]){match[1]--;} // Javascript Date months are 0-based |
| if(match[6]){match[6] *= 1000;} // Javascript Date expects fractional seconds as milliseconds |
| |
| if(defaultTime){ |
| // mix in defaultTime. Relatively expensive, so use || operators for the fast path of defaultTime === 0 |
| defaultTime = new Date(defaultTime); |
| dojo.map(["FullYear", "Month", "Date", "Hours", "Minutes", "Seconds", "Milliseconds"], function(prop){ |
| return defaultTime["get" + prop](); |
| }).forEach(function(value, index){ |
| if(match[index] === undefined){ |
| match[index] = value; |
| } |
| }); |
| } |
| result = new Date(match[0]||1970, match[1]||0, match[2]||1, match[3]||0, match[4]||0, match[5]||0, match[6]||0); //TODO: UTC defaults |
| if(match[0] < 100){ |
| result.setFullYear(match[0] || 1970); |
| } |
| |
| var offset = 0, |
| zoneSign = match[7] && match[7].charAt(0); |
| if(zoneSign != 'Z'){ |
| offset = ((match[8] || 0) * 60) + (Number(match[9]) || 0); |
| if(zoneSign != '-'){ offset *= -1; } |
| } |
| if(zoneSign){ |
| offset -= result.getTimezoneOffset(); |
| } |
| if(offset){ |
| result.setTime(result.getTime() + offset * 60000); |
| } |
| } |
| |
| return result; // Date or null |
| } |
| |
| /*===== |
| dojo.date.stamp.__Options = function(){ |
| // selector: String |
| // "date" or "time" for partial formatting of the Date object. |
| // Both date and time will be formatted by default. |
| // zulu: Boolean |
| // if true, UTC/GMT is used for a timezone |
| // milliseconds: Boolean |
| // if true, output milliseconds |
| this.selector = selector; |
| this.zulu = zulu; |
| this.milliseconds = milliseconds; |
| } |
| =====*/ |
| |
| dojo.date.stamp.toISOString = function(/*Date*/dateObject, /*dojo.date.stamp.__Options?*/options){ |
| // summary: |
| // Format a Date object as a string according a subset of the ISO-8601 standard |
| // |
| // description: |
| // When options.selector is omitted, output follows [RFC3339](http://www.ietf.org/rfc/rfc3339.txt) |
| // The local time zone is included as an offset from GMT, except when selector=='time' (time without a date) |
| // Does not check bounds. Only years between 100 and 9999 are supported. |
| // |
| // dateObject: |
| // A Date object |
| |
| var _ = function(n){ return (n < 10) ? "0" + n : n; }; |
| options = options || {}; |
| var formattedDate = [], |
| getter = options.zulu ? "getUTC" : "get", |
| date = ""; |
| if(options.selector != "time"){ |
| var year = dateObject[getter+"FullYear"](); |
| date = ["0000".substr((year+"").length)+year, _(dateObject[getter+"Month"]()+1), _(dateObject[getter+"Date"]())].join('-'); |
| } |
| formattedDate.push(date); |
| if(options.selector != "date"){ |
| var time = [_(dateObject[getter+"Hours"]()), _(dateObject[getter+"Minutes"]()), _(dateObject[getter+"Seconds"]())].join(':'); |
| var millis = dateObject[getter+"Milliseconds"](); |
| if(options.milliseconds){ |
| time += "."+ (millis < 100 ? "0" : "") + _(millis); |
| } |
| if(options.zulu){ |
| time += "Z"; |
| }else if(options.selector != "time"){ |
| var timezoneOffset = dateObject.getTimezoneOffset(); |
| var absOffset = Math.abs(timezoneOffset); |
| time += (timezoneOffset > 0 ? "-" : "+") + |
| _(Math.floor(absOffset/60)) + ":" + _(absOffset%60); |
| } |
| formattedDate.push(time); |
| } |
| return formattedDate.join('T'); // String |
| } |
| |
| } |
| |
| if(!dojo._hasResource["dojo.parser"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojo.parser"] = true; |
| dojo.provide("dojo.parser"); |
| |
| |
| dojo.parser = new function(){ |
| // summary: The Dom/Widget parsing package |
| |
| var d = dojo; |
| this._attrName = d._scopeName + "Type"; |
| this._query = "[" + this._attrName + "]"; |
| |
| function val2type(/*Object*/ value){ |
| // summary: |
| // Returns name of type of given value. |
| |
| if(d.isString(value)){ return "string"; } |
| if(typeof value == "number"){ return "number"; } |
| if(typeof value == "boolean"){ return "boolean"; } |
| if(d.isFunction(value)){ return "function"; } |
| if(d.isArray(value)){ return "array"; } // typeof [] == "object" |
| if(value instanceof Date) { return "date"; } // assume timestamp |
| if(value instanceof d._Url){ return "url"; } |
| return "object"; |
| } |
| |
| function str2obj(/*String*/ value, /*String*/ type){ |
| // summary: |
| // Convert given string value to given type |
| switch(type){ |
| case "string": |
| return value; |
| case "number": |
| return value.length ? Number(value) : NaN; |
| case "boolean": |
| // for checked/disabled value might be "" or "checked". interpret as true. |
| return typeof value == "boolean" ? value : !(value.toLowerCase()=="false"); |
| case "function": |
| if(d.isFunction(value)){ |
| // IE gives us a function, even when we say something like onClick="foo" |
| // (in which case it gives us an invalid function "function(){ foo }"). |
| // Therefore, convert to string |
| value=value.toString(); |
| value=d.trim(value.substring(value.indexOf('{')+1, value.length-1)); |
| } |
| try{ |
| if(value.search(/[^\w\.]+/i) != -1){ |
| // The user has specified some text for a function like "return x+5" |
| return new Function(value); |
| }else{ |
| // The user has specified the name of a function like "myOnClick" |
| return d.getObject(value, false); |
| } |
| }catch(e){ return new Function(); } |
| case "array": |
| return value ? value.split(/\s*,\s*/) : []; |
| case "date": |
| switch(value){ |
| case "": return new Date(""); // the NaN of dates |
| case "now": return new Date(); // current date |
| default: return d.date.stamp.fromISOString(value); |
| } |
| case "url": |
| return d.baseUrl + value; |
| default: |
| return d.fromJson(value); |
| } |
| } |
| |
| var instanceClasses = { |
| // map from fully qualified name (like "dijit.Button") to structure like |
| // { cls: dijit.Button, params: {label: "string", disabled: "boolean"} } |
| }; |
| |
| // Widgets like BorderContainer add properties to _Widget via dojo.extend(). |
| // If BorderContainer is loaded after _Widget's parameter list has been cached, |
| // we need to refresh that parameter list (for _Widget and all widgets that extend _Widget). |
| dojo.connect(dojo, "extend", function(){ |
| instanceClasses = {}; |
| }); |
| |
| function getClassInfo(/*String*/ className){ |
| // className: |
| // fully qualified name (like "dijit.form.Button") |
| // returns: |
| // structure like |
| // { |
| // cls: dijit.Button, |
| // params: { label: "string", disabled: "boolean"} |
| // } |
| |
| if(!instanceClasses[className]){ |
| // get pointer to widget class |
| var cls = d.getObject(className); |
| if(!d.isFunction(cls)){ |
| throw new Error("Could not load class '" + className + |
| "'. Did you spell the name correctly and use a full path, like 'dijit.form.Button'?"); |
| } |
| var proto = cls.prototype; |
| |
| // get table of parameter names & types |
| var params = {}, dummyClass = {}; |
| for(var name in proto){ |
| if(name.charAt(0)=="_"){ continue; } // skip internal properties |
| if(name in dummyClass){ continue; } // skip "constructor" and "toString" |
| var defVal = proto[name]; |
| params[name]=val2type(defVal); |
| } |
| |
| instanceClasses[className] = { cls: cls, params: params }; |
| } |
| return instanceClasses[className]; |
| } |
| |
| this._functionFromScript = function(script){ |
| var preamble = ""; |
| var suffix = ""; |
| var argsStr = script.getAttribute("args"); |
| if(argsStr){ |
| d.forEach(argsStr.split(/\s*,\s*/), function(part, idx){ |
| preamble += "var "+part+" = arguments["+idx+"]; "; |
| }); |
| } |
| var withStr = script.getAttribute("with"); |
| if(withStr && withStr.length){ |
| d.forEach(withStr.split(/\s*,\s*/), function(part){ |
| preamble += "with("+part+"){"; |
| suffix += "}"; |
| }); |
| } |
| return new Function(preamble+script.innerHTML+suffix); |
| } |
| |
| this.instantiate = function(/* Array */nodes, /* Object? */mixin, /* Object? */args){ |
| // summary: |
| // Takes array of nodes, and turns them into class instances and |
| // potentially calls a layout method to allow them to connect with |
| // any children |
| // mixin: Object? |
| // An object that will be mixed in with each node in the array. |
| // Values in the mixin will override values in the node, if they |
| // exist. |
| // args: Object? |
| // An object used to hold kwArgs for instantiation. |
| // Only supports 'noStart' currently. |
| var thelist = [], dp = dojo.parser; |
| mixin = mixin||{}; |
| args = args||{}; |
| |
| d.forEach(nodes, function(node){ |
| if(!node){ return; } |
| var type = dp._attrName in mixin?mixin[dp._attrName]:node.getAttribute(dp._attrName); |
| if(!type || !type.length){ return; } |
| var clsInfo = getClassInfo(type), |
| clazz = clsInfo.cls, |
| ps = clazz._noScript || clazz.prototype._noScript; |
| |
| // read parameters (ie, attributes). |
| // clsInfo.params lists expected params like {"checked": "boolean", "n": "number"} |
| var params = {}, |
| attributes = node.attributes; |
| for(var name in clsInfo.params){ |
| var item = name in mixin?{value:mixin[name],specified:true}:attributes.getNamedItem(name); |
| if(!item || (!item.specified && (!dojo.isIE || name.toLowerCase()!="value"))){ continue; } |
| var value = item.value; |
| // Deal with IE quirks for 'class' and 'style' |
| switch(name){ |
| case "class": |
| value = "className" in mixin?mixin.className:node.className; |
| break; |
| case "style": |
| value = "style" in mixin?mixin.style:(node.style && node.style.cssText); // FIXME: Opera? |
| } |
| var _type = clsInfo.params[name]; |
| if(typeof value == "string"){ |
| params[name] = str2obj(value, _type); |
| }else{ |
| params[name] = value; |
| } |
| } |
| |
| // Process <script type="dojo/*"> script tags |
| // <script type="dojo/method" event="foo"> tags are added to params, and passed to |
| // the widget on instantiation. |
| // <script type="dojo/method"> tags (with no event) are executed after instantiation |
| // <script type="dojo/connect" event="foo"> tags are dojo.connected after instantiation |
| // note: dojo/* script tags cannot exist in self closing widgets, like <input /> |
| if(!ps){ |
| var connects = [], // functions to connect after instantiation |
| calls = []; // functions to call after instantiation |
| |
| d.query("> script[type^='dojo/']", node).orphan().forEach(function(script){ |
| var event = script.getAttribute("event"), |
| type = script.getAttribute("type"), |
| nf = d.parser._functionFromScript(script); |
| if(event){ |
| if(type == "dojo/connect"){ |
| connects.push({event: event, func: nf}); |
| }else{ |
| params[event] = nf; |
| } |
| }else{ |
| calls.push(nf); |
| } |
| }); |
| } |
| |
| var markupFactory = clazz.markupFactory || clazz.prototype && clazz.prototype.markupFactory; |
| // create the instance |
| var instance = markupFactory ? markupFactory(params, node, clazz) : new clazz(params, node); |
| thelist.push(instance); |
| |
| // map it to the JS namespace if that makes sense |
| var jsname = node.getAttribute("jsId"); |
| if(jsname){ |
| d.setObject(jsname, instance); |
| } |
| |
| // process connections and startup functions |
| if(!ps){ |
| d.forEach(connects, function(connect){ |
| d.connect(instance, connect.event, null, connect.func); |
| }); |
| d.forEach(calls, function(func){ |
| func.call(instance); |
| }); |
| } |
| }); |
| |
| // Call startup on each top level instance if it makes sense (as for |
| // widgets). Parent widgets will recursively call startup on their |
| // (non-top level) children |
| if(!mixin._started){ |
| d.forEach(thelist, function(instance){ |
| if( !args.noStart && instance && |
| instance.startup && |
| !instance._started && |
| (!instance.getParent || !instance.getParent()) |
| ){ |
| instance.startup(); |
| } |
| }); |
| } |
| return thelist; |
| }; |
| |
| this.parse = function(/*DomNode?*/ rootNode, /* Object? */ args){ |
| // summary: |
| // Scan the DOM for class instances, and instantiate them. |
| // |
| // description: |
| // Search specified node (or root node) recursively for class instances, |
| // and instantiate them Searches for |
| // dojoType="qualified.class.name" |
| // |
| // rootNode: DomNode? |
| // A default starting root node from which to start the parsing. Can be |
| // omitted, defaulting to the entire document. If omitted, the `args` |
| // object can be passed in this place. If the `args` object has a |
| // `rootNode` member, that is used. |
| // |
| // args: |
| // a kwArgs object passed along to instantiate() |
| // |
| // * noStart: Boolean? |
| // when set will prevent the parser from calling .startup() |
| // when locating the nodes. |
| // * rootNode: DomNode? |
| // identical to the function's `rootNode` argument, though |
| // allowed to be passed in via this `args object. |
| // |
| // example: |
| // Parse all widgets on a page: |
| // | dojo.parser.parse(); |
| // |
| // example: |
| // Parse all classes within the node with id="foo" |
| // | dojo.parser.parse(dojo.byId(foo)); |
| // |
| // example: |
| // Parse all classes in a page, but do not call .startup() on any |
| // child |
| // | dojo.parser.parse({ noStart: true }) |
| // |
| // example: |
| // Parse all classes in a node, but do not call .startup() |
| // | dojo.parser.parse(someNode, { noStart:true }); |
| // | // or |
| // | dojo.parser.parse({ noStart:true, rootNode: someNode }); |
| |
| // determine the root node based on the passed arguments. |
| var root; |
| if(!args && rootNode && rootNode.rootNode){ |
| args = rootNode; |
| root = args.rootNode; |
| }else{ |
| root = rootNode; |
| } |
| |
| var list = d.query(this._query, root); |
| // go build the object instances |
| return this.instantiate(list, null, args); // Array |
| |
| }; |
| }(); |
| |
| //Register the parser callback. It should be the first callback |
| //after the a11y test. |
| |
| (function(){ |
| var parseRunner = function(){ |
| if(dojo.config.parseOnLoad){ |
| dojo.parser.parse(); |
| } |
| }; |
| |
| // FIXME: need to clobber cross-dependency!! |
| if(dojo.exists("dijit.wai.onload") && (dijit.wai.onload === dojo._loaders[0])){ |
| dojo._loaders.splice(1, 0, parseRunner); |
| }else{ |
| dojo._loaders.unshift(parseRunner); |
| } |
| })(); |
| |
| } |
| |
| 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" ); |
| |
| |
| // This code is to assist deferring dojo.connect() calls in widgets (connecting to events on the widgets' |
| // DOM nodes) until someone actually needs to monitor that event. |
| dojo.connect(dojo, "_connect", |
| function(/*dijit._Widget*/ widget, /*String*/ event){ |
| if(widget && dojo.isFunction(widget._onConnect)){ |
| widget._onConnect(event); |
| } |
| }); |
| |
| dijit._connectOnUseEventHandler = function(/*Event*/ event){}; |
| |
| // Keep track of where the last keydown event was, to help avoid generating |
| // spurious ondijitclick events when: |
| // 1. focus is on a <button> or <a> |
| // 2. user presses then releases the ENTER key |
| // 3. onclick handler fires and shifts focus to another node, with an ondijitclick handler |
| // 4. onkeyup event fires, causing the ondijitclick handler to fire |
| dijit._lastKeyDownNode = null; |
| if(dojo.isIE){ |
| (function(){ |
| var keydownCallback = function(evt){ |
| dijit._lastKeyDownNode = evt.srcElement; |
| }; |
| dojo.doc.attachEvent('onkeydown', keydownCallback); |
| dojo.addOnWindowUnload(function(){ |
| dojo.doc.detachEvent('onkeydown', keydownCallback); |
| }); |
| })(); |
| }else{ |
| dojo.doc.addEventListener('keydown', function(evt){ |
| dijit._lastKeyDownNode = evt.target; |
| }, true); |
| } |
| |
| (function(){ |
| |
| var _attrReg = {}, // cached results from getSetterAttributes |
| getSetterAttributes = function(widget){ |
| // summary: |
| // Returns list of attributes with custom setters for specified widget |
| var dc = widget.declaredClass; |
| if(!_attrReg[dc]){ |
| var r = [], |
| attrs, |
| proto = widget.constructor.prototype; |
| for(var fxName in proto){ |
| if(dojo.isFunction(proto[fxName]) && (attrs = fxName.match(/^_set([a-zA-Z]*)Attr$/)) && attrs[1]){ |
| r.push(attrs[1].charAt(0).toLowerCase() + attrs[1].substr(1)); |
| } |
| } |
| _attrReg[dc] = r; |
| } |
| return _attrReg[dc] || []; // String[] |
| }; |
| |
| dojo.declare("dijit._Widget", null, { |
| // summary: |
| // Base class for all Dijit widgets. |
| |
| // id: [const] 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: [const] 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: [const] 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||Object |
| // HTML style attributes as cssText string or name/value hash |
| style: "", |
| |
| // title: String |
| // HTML title attribute. |
| // |
| // For form widgets this specifies a tooltip to display when hovering over |
| // the widget (just like the native HTML title attribute). |
| // |
| // For TitlePane or for when this widget is a child of a TabContainer, AccordionContainer, |
| // etc., it's used to specify the tab label, accordion pane title, etc. |
| title: "", |
| |
| // tooltip: String |
| // When this widget's title attribute is used to for a tab label, accordion pane title, etc., |
| // this specifies the tooltip to appear when the mouse is hovered over that text. |
| tooltip: "", |
| |
| // srcNodeRef: [readonly] DomNode |
| // pointer to original DOM node |
| srcNodeRef: null, |
| |
| // domNode: [readonly] DomNode |
| // This is our visible representation of the widget! Other DOM |
| // Nodes may by assigned to other properties, usually through the |
| // template system's dojoAttachPoint syntax, but the domNode |
| // property is the canonical "top level" node in widget UI. |
| domNode: null, |
| |
| // containerNode: [readonly] DomNode |
| // Designates where children of the source DOM node will be placed. |
| // "Children" in this case refers to both DOM nodes and widgets. |
| // For example, for myWidget: |
| // |
| // | <div dojoType=myWidget> |
| // | <b> here's a plain DOM node |
| // | <span dojoType=subWidget>and a widget</span> |
| // | <i> and another plain DOM node </i> |
| // | </div> |
| // |
| // containerNode would point to: |
| // |
| // | <b> here's a plain DOM node |
| // | <span dojoType=subWidget>and a widget</span> |
| // | <i> and another plain DOM node </i> |
| // |
| // In templated widgets, "containerNode" is set via a |
| // dojoAttachPoint assignment. |
| // |
| // containerNode must be defined for any widget that accepts innerHTML |
| // (like ContentPane or BorderContainer or even Button), and conversely |
| // is null for widgets that don't, like TextBox. |
| containerNode: null, |
| |
| /*===== |
| // _started: Boolean |
| // startup() has completed. |
| _started: false, |
| =====*/ |
| |
| // attributeMap: [protected] Object |
| // attributeMap sets up a "binding" between attributes (aka properties) |
| // of the widget and the widget's DOM. |
| // Changes to widget attributes listed in attributeMap will be |
| // reflected into the DOM. |
| // |
| // For example, calling attr('title', 'hello') |
| // on a TitlePane will automatically cause the TitlePane's DOM to update |
| // with the new title. |
| // |
| // attributeMap is a hash where the key is an attribute of the widget, |
| // and the value reflects a binding to a: |
| // |
| // - DOM node attribute |
| // | focus: {node: "focusNode", type: "attribute"} |
| // Maps this.focus to this.focusNode.focus |
| // |
| // - DOM node innerHTML |
| // | title: { node: "titleNode", type: "innerHTML" } |
| // Maps this.title to this.titleNode.innerHTML |
| // |
| // - DOM node innerText |
| // | title: { node: "titleNode", type: "innerText" } |
| // Maps this.title to this.titleNode.innerText |
| // |
| // - DOM node CSS class |
| // | myClass: { node: "domNode", type: "class" } |
| // Maps this.myClass to this.domNode.className |
| // |
| // If the value is an array, then each element in the array matches one of the |
| // formats of the above list. |
| // |
| // There are also some shorthands for backwards compatibility: |
| // - string --> { node: string, type: "attribute" }, for example: |
| // | "focusNode" ---> { node: "focusNode", type: "attribute" } |
| // - "" --> { node: "domNode", type: "attribute" } |
| attributeMap: {id:"", dir:"", lang:"", "class":"", style:"", title:""}, |
| |
| // _deferredConnects: [protected] Object |
| // attributeMap addendum for event handlers that should be connected only on first use |
| _deferredConnects: { |
| onClick: "", |
| onDblClick: "", |
| onKeyDown: "", |
| onKeyPress: "", |
| onKeyUp: "", |
| onMouseMove: "", |
| onMouseDown: "", |
| onMouseOut: "", |
| onMouseOver: "", |
| onMouseLeave: "", |
| onMouseEnter: "", |
| onMouseUp: "" |
| }, |
| |
| onClick: dijit._connectOnUseEventHandler, |
| /*===== |
| onClick: function(event){ |
| // summary: |
| // Connect to this function to receive notifications of mouse click events. |
| // event: |
| // mouse Event |
| // tags: |
| // callback |
| }, |
| =====*/ |
| onDblClick: dijit._connectOnUseEventHandler, |
| /*===== |
| onDblClick: function(event){ |
| // summary: |
| // Connect to this function to receive notifications of mouse double click events. |
| // event: |
| // mouse Event |
| // tags: |
| // callback |
| }, |
| =====*/ |
| onKeyDown: dijit._connectOnUseEventHandler, |
| /*===== |
| onKeyDown: function(event){ |
| // summary: |
| // Connect to this function to receive notifications of keys being pressed down. |
| // event: |
| // key Event |
| // tags: |
| // callback |
| }, |
| =====*/ |
| onKeyPress: dijit._connectOnUseEventHandler, |
| /*===== |
| onKeyPress: function(event){ |
| // summary: |
| // Connect to this function to receive notifications of printable keys being typed. |
| // event: |
| // key Event |
| // tags: |
| // callback |
| }, |
| =====*/ |
| onKeyUp: dijit._connectOnUseEventHandler, |
| /*===== |
| onKeyUp: function(event){ |
| // summary: |
| // Connect to this function to receive notifications of keys being released. |
| // event: |
| // key Event |
| // tags: |
| // callback |
| }, |
| =====*/ |
| onMouseDown: dijit._connectOnUseEventHandler, |
| /*===== |
| onMouseDown: function(event){ |
| // summary: |
| // Connect to this function to receive notifications of when the mouse button is pressed down. |
| // event: |
| // mouse Event |
| // tags: |
| // callback |
| }, |
| =====*/ |
| onMouseMove: dijit._connectOnUseEventHandler, |
| /*===== |
| onMouseMove: function(event){ |
| // summary: |
| // Connect to this function to receive notifications of when the mouse moves over nodes contained within this widget. |
| // event: |
| // mouse Event |
| // tags: |
| // callback |
| }, |
| =====*/ |
| onMouseOut: dijit._connectOnUseEventHandler, |
| /*===== |
| onMouseOut: function(event){ |
| // summary: |
| // Connect to this function to receive notifications of when the mouse moves off of nodes contained within this widget. |
| // event: |
| // mouse Event |
| // tags: |
| // callback |
| }, |
| =====*/ |
| onMouseOver: dijit._connectOnUseEventHandler, |
| /*===== |
| onMouseOver: function(event){ |
| // summary: |
| // Connect to this function to receive notifications of when the mouse moves onto nodes contained within this widget. |
| // event: |
| // mouse Event |
| // tags: |
| // callback |
| }, |
| =====*/ |
| onMouseLeave: dijit._connectOnUseEventHandler, |
| /*===== |
| onMouseLeave: function(event){ |
| // summary: |
| // Connect to this function to receive notifications of when the mouse moves off of this widget. |
| // event: |
| // mouse Event |
| // tags: |
| // callback |
| }, |
| =====*/ |
| onMouseEnter: dijit._connectOnUseEventHandler, |
| /*===== |
| onMouseEnter: function(event){ |
| // summary: |
| // Connect to this function to receive notifications of when the mouse moves onto this widget. |
| // event: |
| // mouse Event |
| // tags: |
| // callback |
| }, |
| =====*/ |
| onMouseUp: dijit._connectOnUseEventHandler, |
| /*===== |
| onMouseUp: function(event){ |
| // summary: |
| // Connect to this function to receive notifications of when the mouse button is released. |
| // event: |
| // mouse Event |
| // tags: |
| // callback |
| }, |
| =====*/ |
| |
| // Constants used in templates |
| |
| // _blankGif: [protected] String |
| // Path to a blank 1x1 image. |
| // Used by <img> nodes in templates that really get their image via CSS background-image. |
| _blankGif: (dojo.config.blankGif || dojo.moduleUrl("dojo", "resources/blank.gif")).toString(), |
| |
| //////////// INITIALIZATION METHODS /////////////////////////////////////// |
| |
| postscript: function(/*Object?*/params, /*DomNode|String*/srcNodeRef){ |
| // summary: |
| // Kicks off widget instantiation. See create() for details. |
| // tags: |
| // private |
| this.create(params, srcNodeRef); |
| }, |
| |
| create: function(/*Object?*/params, /*DomNode|String?*/srcNodeRef){ |
| // summary: |
| // Kick off the life-cycle of a widget |
| // params: |
| // Hash of initialization parameters for widget, including |
| // scalar values (like title, duration etc.) and functions, |
| // typically callbacks like onClick. |
| // srcNodeRef: |
| // If a srcNodeRef (DOM node) is specified: |
| // - use srcNodeRef.innerHTML as my contents |
| // - if this is a behavioral widget then apply behavior |
| // to that srcNodeRef |
| // - otherwise, replace srcNodeRef with my generated DOM |
| // tree |
| // description: |
| // Create calls a number of widget methods (postMixInProperties, buildRendering, postCreate, |
| // etc.), some of which of you'll want to override. See http://docs.dojocampus.org/dijit/_Widget |
| // for a discussion of the widget creation lifecycle. |
| // |
| // Of course, adventurous developers could override create entirely, but this should |
| // only be done as a last resort. |
| // tags: |
| // private |
| |
| // 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 = []; |
| |
| // For garbage collection. An array of handles returned by Widget.subscribe() |
| // The handle returned from Widget.subscribe() is the handle returned from dojo.subscribe() |
| this._subscribes = []; |
| |
| // To avoid double-connects, remove entries from _deferredConnects |
| // that have been setup manually by a subclass (ex, by dojoAttachEvent). |
| // If a subclass has redefined a callback (ex: onClick) then assume it's being |
| // connected to manually. |
| this._deferredConnects = dojo.clone(this._deferredConnects); |
| for(var attr in this.attributeMap){ |
| delete this._deferredConnects[attr]; // can't be in both attributeMap and _deferredConnects |
| } |
| for(attr in this._deferredConnects){ |
| if(this[attr] !== dijit._connectOnUseEventHandler){ |
| delete this._deferredConnects[attr]; // redefined, probably dojoAttachEvent exists |
| } |
| } |
| |
| //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(); |
| |
| if(this.domNode){ |
| // Copy attributes listed in attributeMap into the [newly created] DOM for the widget. |
| this._applyAttributes(); |
| |
| var source = this.srcNodeRef; |
| if(source && source.parentNode){ |
| source.parentNode.replaceChild(this.domNode, source); |
| } |
| |
| // If the developer has specified a handler as a widget parameter |
| // (ex: new Button({onClick: ...}) |
| // then naturally need to connect from DOM node to that handler immediately, |
| for(attr in this.params){ |
| this._onConnect(attr); |
| } |
| } |
| |
| 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; |
| } |
| |
| this._created = true; |
| }, |
| |
| _applyAttributes: function(){ |
| // summary: |
| // Step during widget creation to copy all widget attributes to the |
| // DOM as per attributeMap and _setXXXAttr functions. |
| // description: |
| // Skips over blank/false attribute values, unless they were explicitly specified |
| // as parameters to the widget, since those are the default anyway, |
| // and setting tabIndex="" is different than not setting tabIndex at all. |
| // |
| // It processes the attributes in the attribute map first, and then |
| // it goes through and processes the attributes for the _setXXXAttr |
| // functions that have been specified |
| // tags: |
| // private |
| var condAttrApply = function(attr, scope){ |
| if((scope.params && attr in scope.params) || scope[attr]){ |
| scope.attr(attr, scope[attr]); |
| } |
| }; |
| |
| // Do the attributes in attributeMap |
| for(var attr in this.attributeMap){ |
| condAttrApply(attr, this); |
| } |
| |
| // And also any attributes with custom setters |
| dojo.forEach(getSetterAttributes(this), function(a){ |
| if(!(a in this.attributeMap)){ |
| condAttrApply(a, this); |
| } |
| }, this); |
| }, |
| |
| 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. |
| // tags: |
| // protected |
| }, |
| |
| buildRendering: function(){ |
| // summary: |
| // Construct the UI for this widget, setting this.domNode |
| // description: |
| // Most widgets will mixin `dijit._Templated`, which implements this |
| // method. |
| // tags: |
| // protected |
| this.domNode = this.srcNodeRef || dojo.create('div'); |
| }, |
| |
| postCreate: function(){ |
| // summary: |
| // Processing after the DOM fragment is created |
| // description: |
| // Called after the DOM fragment has been created, but not necessarily |
| // added to the document. Do not include any operations which rely on |
| // node dimensions or placement. |
| // tags: |
| // protected |
| }, |
| |
| startup: function(){ |
| // summary: |
| // Processing after the DOM fragment is added to the document |
| // description: |
| // Called after a widget and its children have been created and added to the page, |
| // and all related widgets have finished their create() cycle, up through postCreate(). |
| // 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?*/ preserveDom){ |
| // summary: |
| // Destroy this widget and its descendants |
| // description: |
| // This is the generic "destructor" function that all widget users |
| // should call to cleanly discard with a widget. Once a widget is |
| // destroyed, it is removed from the manager object. |
| // preserveDom: |
| // If true, this method will leave the original DOM structure |
| // alone of descendant Widgets. Note: This will NOT work with |
| // dijit._Templated widgets. |
| |
| this._beingDestroyed = true; |
| this.destroyDescendants(preserveDom); |
| this.destroy(preserveDom); |
| }, |
| |
| destroy: function(/*Boolean*/ preserveDom){ |
| // summary: |
| // Destroy this widget, but not its descendants. |
| // This method will, however, destroy internal widgets such as those used within a template. |
| // preserveDom: Boolean |
| // If true, this method will leave the original DOM structure alone. |
| // Note: This will not yet work with _Templated widgets |
| |
| this._beingDestroyed = true; |
| this.uninitialize(); |
| var d = dojo, |
| dfe = d.forEach, |
| dun = d.unsubscribe; |
| dfe(this._connects, function(array){ |
| dfe(array, d.disconnect); |
| }); |
| dfe(this._subscribes, function(handle){ |
| dun(handle); |
| }); |
| |
| // destroy widgets created as part of template, etc. |
| dfe(this._supportingWidgets || [], function(w){ |
| if(w.destroyRecursive){ |
| w.destroyRecursive(); |
| }else if(w.destroy){ |
| w.destroy(); |
| } |
| }); |
| |
| this.destroyRendering(preserveDom); |
| dijit.registry.remove(this.id); |
| this._destroyed = true; |
| }, |
| |
| destroyRendering: function(/*Boolean?*/ preserveDom){ |
| // summary: |
| // Destroys the DOM nodes associated with this widget |
| // preserveDom: |
| // If true, this method will leave the original DOM structure alone |
| // during tear-down. Note: this will not work with _Templated |
| // widgets yet. |
| // tags: |
| // protected |
| |
| if(this.bgIframe){ |
| this.bgIframe.destroy(preserveDom); |
| delete this.bgIframe; |
| } |
| |
| if(this.domNode){ |
| if(preserveDom){ |
| dojo.removeAttr(this.domNode, "widgetId"); |
| }else{ |
| dojo.destroy(this.domNode); |
| } |
| delete this.domNode; |
| } |
| |
| if(this.srcNodeRef){ |
| if(!preserveDom){ |
| dojo.destroy(this.srcNodeRef); |
| } |
| delete this.srcNodeRef; |
| } |
| }, |
| |
| destroyDescendants: function(/*Boolean?*/ preserveDom){ |
| // summary: |
| // Recursively destroy the children of this widget and their |
| // descendants. |
| // preserveDom: |
| // If true, the preserveDom attribute is passed to all descendant |
| // widget's .destroy() method. Not for use with _Templated |
| // widgets. |
| |
| // get all direct descendants and destroy them recursively |
| dojo.forEach(this.getChildren(), function(widget){ |
| if(widget.destroyRecursive){ |
| widget.destroyRecursive(preserveDom); |
| } |
| }); |
| }, |
| |
| |
| uninitialize: function(){ |
| // summary: |
| // Stub function. Override to implement custom widget tear-down |
| // behavior. |
| // tags: |
| // protected |
| return false; |
| }, |
| |
| ////////////////// MISCELLANEOUS METHODS /////////////////// |
| |
| onFocus: function(){ |
| // summary: |
| // Called when the widget becomes "active" because |
| // it or a widget inside of it either has focus, or has recently |
| // been clicked. |
| // tags: |
| // callback |
| }, |
| |
| onBlur: function(){ |
| // summary: |
| // Called when the widget stops being "active" because |
| // focus moved to something outside of it, or the user |
| // clicked somewhere outside of it, or the widget was |
| // hidden. |
| // tags: |
| // callback |
| }, |
| |
| _onFocus: function(e){ |
| // summary: |
| // This is where widgets do processing for when they are active, |
| // such as changing CSS classes. See onFocus() for more details. |
| // tags: |
| // protected |
| this.onFocus(); |
| }, |
| |
| _onBlur: function(){ |
| // summary: |
| // This is where widgets do processing for when they stop being active, |
| // such as changing CSS classes. See onBlur() for more details. |
| // tags: |
| // protected |
| this.onBlur(); |
| }, |
| |
| _onConnect: function(/*String*/ event){ |
| // summary: |
| // Called when someone connects to one of my handlers. |
| // "Turn on" that handler if it isn't active yet. |
| // |
| // This is also called for every single initialization parameter |
| // so need to do nothing for parameters like "id". |
| // tags: |
| // private |
| if(event in this._deferredConnects){ |
| var mapNode = this[this._deferredConnects[event] || 'domNode']; |
| this.connect(mapNode, event.toLowerCase(), event); |
| delete this._deferredConnects[event]; |
| } |
| }, |
| |
| _setClassAttr: function(/*String*/ value){ |
| // summary: |
| // Custom setter for the CSS "class" attribute |
| // tags: |
| // protected |
| var mapNode = this[this.attributeMap["class"] || 'domNode']; |
| dojo.removeClass(mapNode, this["class"]) |
| this["class"] = value; |
| dojo.addClass(mapNode, value); |
| }, |
| |
| _setStyleAttr: function(/*String||Object*/ value){ |
| // summary: |
| // Sets the style attribut of the widget according to value, |
| // which is either a hash like {height: "5px", width: "3px"} |
| // or a plain string |
| // description: |
| // Determines which node to set the style on based on style setting |
| // in attributeMap. |
| // tags: |
| // protected |
| |
| var mapNode = this[this.attributeMap.style || 'domNode']; |
| |
| // Note: technically we should revert any style setting made in a previous call |
| // to his method, but that's difficult to keep track of. |
| |
| if(dojo.isObject(value)){ |
| dojo.style(mapNode, value); |
| }else{ |
| if(mapNode.style.cssText){ |
| mapNode.style.cssText += "; " + value; |
| }else{ |
| mapNode.style.cssText = value; |
| } |
| } |
| |
| this.style = value; |
| }, |
| |
| setAttribute: function(/*String*/ attr, /*anything*/ value){ |
| // summary: |
| // Deprecated. Use attr() instead. |
| // tags: |
| // deprecated |
| dojo.deprecated(this.declaredClass+"::setAttribute() is deprecated. Use attr() instead.", "", "2.0"); |
| this.attr(attr, value); |
| }, |
| |
| _attrToDom: function(/*String*/ attr, /*String*/ value){ |
| // summary: |
| // Reflect a widget attribute (title, tabIndex, duration etc.) to |
| // the widget DOM, as specified in attributeMap. |
| // |
| // description: |
| // Also sets this["attr"] to the new value. |
| // Note some attributes like "type" |
| // cannot be processed this way as they are not mutable. |
| // |
| // tags: |
| // private |
| |
| var commands = this.attributeMap[attr]; |
| dojo.forEach(dojo.isArray(commands) ? commands : [commands], function(command){ |
| |
| // Get target node and what we are doing to that node |
| var mapNode = this[command.node || command || "domNode"]; // DOM node |
| var type = command.type || "attribute"; // class, innerHTML, innerText, or attribute |
| |
| switch(type){ |
| case "attribute": |
| if(dojo.isFunction(value)){ // functions execute in the context of the widget |
| value = dojo.hitch(this, value); |
| } |
| |
| // Get the name of the DOM node attribute; usually it's the same |
| // as the name of the attribute in the widget (attr), but can be overridden. |
| // Also maps handler names to lowercase, like onSubmit --> onsubmit |
| var attrName = command.attribute ? command.attribute : |
| (/^on[A-Z][a-zA-Z]*$/.test(attr) ? attr.toLowerCase() : attr); |
| |
| dojo.attr(mapNode, attrName, value); |
| break; |
| case "innerText": |
| mapNode.innerHTML = ""; |
| mapNode.appendChild(dojo.doc.createTextNode(value)); |
| break; |
| case "innerHTML": |
| mapNode.innerHTML = value; |
| break; |
| case "class": |
| dojo.removeClass(mapNode, this[attr]); |
| dojo.addClass(mapNode, value); |
| break; |
| } |
| }, this); |
| this[attr] = value; |
| }, |
| |
| attr: function(/*String|Object*/name, /*Object?*/value){ |
| // summary: |
| // Set or get properties on a widget instance. |
| // name: |
| // The property to get or set. If an object is passed here and not |
| // a string, its keys are used as names of attributes to be set |
| // and the value of the object as values to set in the widget. |
| // value: |
| // Optional. If provided, attr() operates as a setter. If omitted, |
| // the current value of the named property is returned. |
| // description: |
| // Get or set named properties on a widget. If no value is |
| // provided, the current value of the attribute is returned, |
| // potentially via a getter method. If a value is provided, then |
| // the method acts as a setter, assigning the value to the name, |
| // potentially calling any explicitly provided setters to handle |
| // the operation. For instance, if the widget has properties "foo" |
| // and "bar" and a method named "_setFooAttr", calling: |
| // | myWidget.attr("foo", "Howdy!"); |
| // would be equivalent to calling: |
| // | widget._setFooAttr("Howdy!"); |
| // while calling: |
| // | myWidget.attr("bar", "Howdy!"); |
| // would be the same as writing: |
| // | widget.bar = "Howdy!"; |
| // It also tries to copy the changes to the widget's DOM according |
| // to settings in attributeMap (see description of `dijit._Widget.attributeMap` |
| // for details) |
| // For example, calling: |
| // | myTitlePane.attr("title", "Howdy!"); |
| // will do |
| // | myTitlePane.title = "Howdy!"; |
| // | myTitlePane.title.innerHTML = "Howdy!"; |
| // It works for DOM node attributes too. Calling |
| // | widget.attr("disabled", true) |
| // will set the disabled attribute on the widget's focusNode, |
| // among other housekeeping for a change in disabled state. |
| |
| // open questions: |
| // - how to handle build shortcut for attributes which want to map |
| // into DOM attributes? |
| // - what relationship should setAttribute()/attr() have to |
| // layout() calls? |
| var args = arguments.length; |
| if(args == 1 && !dojo.isString(name)){ |
| for(var x in name){ this.attr(x, name[x]); } |
| return this; |
| } |
| var names = this._getAttrNames(name); |
| if(args >= 2){ // setter |
| if(this[names.s]){ |
| // use the explicit setter |
| args = dojo._toArray(arguments, 1); |
| return this[names.s].apply(this, args) || this; |
| }else{ |
| // if param is specified as DOM node attribute, copy it |
| if(name in this.attributeMap){ |
| this._attrToDom(name, value); |
| } |
| |
| // FIXME: what about function assignments? Any way to connect() here? |
| this[name] = value; |
| } |
| return this; |
| }else{ // getter |
| return this[names.g] ? this[names.g]() : this[name]; |
| } |
| }, |
| |
| _attrPairNames: {}, // shared between all widgets |
| _getAttrNames: function(name){ |
| // summary: |
| // Helper function for Widget.attr(). |
| // Caches attribute name values so we don't do the string ops every time. |
| // tags: |
| // private |
| |
| var apn = this._attrPairNames; |
| if(apn[name]){ return apn[name]; } |
| var uc = name.charAt(0).toUpperCase() + name.substr(1); |
| return (apn[name] = { |
| n: name+"Node", |
| s: "_set"+uc+"Attr", |
| g: "_get"+uc+"Attr" |
| }); |
| }, |
| |
| toString: function(){ |
| // summary: |
| // Returns a string that represents the widget |
| // description: |
| // 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 reversible |
| // serialization. |
| return '[Widget ' + this.declaredClass + ', ' + (this.id || 'NO ID') + ']'; // String |
| }, |
| |
| getDescendants: function(){ |
| // summary: |
| // Returns all the widgets contained by this, i.e., all widgets underneath this.containerNode. |
| // This method should generally be avoided as it returns widgets declared in templates, which are |
| // supposed to be internal/hidden, but it's left here for back-compat reasons. |
| |
| return this.containerNode ? dojo.query('[widgetId]', this.containerNode).map(dijit.byNode) : []; // dijit._Widget[] |
| }, |
| |
| getChildren: function(){ |
| // summary: |
| // Returns all the widgets contained by this, i.e., all widgets underneath this.containerNode. |
| // Does not return nested widgets, nor widgets that are part of this widget's template. |
| return this.containerNode ? dijit.findWidgets(this.containerNode) : []; // dijit._Widget[] |
| }, |
| |
| // nodesWithKeyClick: [private] String[] |
| // List of nodes that correctly handle click events via native browser support, |
| // and don't need dijit's help |
| nodesWithKeyClick: ["input", "button"], |
| |
| connect: function( |
| /*Object|null*/ obj, |
| /*String|Function*/ event, |
| /*String|Function*/ method){ |
| // summary: |
| // Connects specified obj/event to specified method of this object |
| // and registers for disconnect() on widget destroy. |
| // description: |
| // Provide widget-specific analog to dojo.connect, except with the |
| // implicit use of this widget as the target object. |
| // This version of connect also provides a special "ondijitclick" |
| // event which triggers on a click or space or enter keyup |
| // returns: |
| // A handle that can be passed to `disconnect` in order to disconnect before |
| // the widget is destroyed. |
| // example: |
| // | var btn = new dijit.form.Button(); |
| // | // when foo.bar() is called, call the listener we're going to |
| // | // provide in the scope of btn |
| // | btn.connect(foo, "bar", function(){ |
| // | console.debug(this.toString()); |
| // | }); |
| // tags: |
| // protected |
| |
| var d = dojo, |
| dc = d._connect, |
| handles = []; |
| if(event == "ondijitclick"){ |
| // add key based click activation for unsupported nodes. |
| // do all processing onkey up to prevent spurious clicks |
| // for details see comments at top of this file where _lastKeyDownNode is defined |
| if(!this.nodesWithKeyClick[obj.tagName.toLowerCase()]){ |
| var m = d.hitch(this, method); |
| handles.push( |
| dc(obj, "onkeydown", this, function(e){ |
| //console.log(this.id + ": onkeydown, e.target = ", e.target, ", lastKeyDownNode was ", dijit._lastKeyDownNode, ", equality is ", (e.target === dijit._lastKeyDownNode)); |
| if((e.keyCode == d.keys.ENTER || e.keyCode == d.keys.SPACE) && |
| !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey){ |
| // needed on IE for when focus changes between keydown and keyup - otherwise dropdown menus do not work |
| dijit._lastKeyDownNode = e.target; |
| d.stopEvent(e); // stop event to prevent scrolling on space key in IE |
| } |
| }), |
| dc(obj, "onkeyup", this, function(e){ |
| //console.log(this.id + ": onkeyup, e.target = ", e.target, ", lastKeyDownNode was ", dijit._lastKeyDownNode, ", equality is ", (e.target === dijit._lastKeyDownNode)); |
| if( (e.keyCode == d.keys.ENTER || e.keyCode == d.keys.SPACE) && |
| e.target === dijit._lastKeyDownNode && |
| !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey){ |
| //need reset here or have problems in FF when focus returns to trigger element after closing popup/alert |
| dijit._lastKeyDownNode = null; |
| return m(e); |
| } |
| }) |
| ); |
| } |
| event = "onclick"; |
| } |
| handles.push(dc(obj, event, this, method)); |
| |
| this._connects.push(handles); |
| return handles; // _Widget.Handle |
| }, |
| |
| disconnect: function(/* _Widget.Handle */ handles){ |
| // summary: |
| // Disconnects handle created by `connect`. |
| // Also removes handle from this widget's list of connects. |
| // tags: |
| // protected |
| 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; |
| } |
| } |
| }, |
| |
| subscribe: function( |
| /*String*/ topic, |
| /*String|Function*/ method){ |
| // summary: |
| // Subscribes to the specified topic and calls the specified method |
| // of this object and registers for unsubscribe() on widget destroy. |
| // description: |
| // Provide widget-specific analog to dojo.subscribe, except with the |
| // implicit use of this widget as the target object. |
| // example: |
| // | var btn = new dijit.form.Button(); |
| // | // when /my/topic is published, this button changes its label to |
| // | // be the parameter of the topic. |
| // | btn.subscribe("/my/topic", function(v){ |
| // | this.attr("label", v); |
| // | }); |
| var d = dojo, |
| handle = d.subscribe(topic, this, method); |
| |
| // return handles for Any widget that may need them |
| this._subscribes.push(handle); |
| return handle; |
| }, |
| |
| unsubscribe: function(/*Object*/ handle){ |
| // summary: |
| // Unsubscribes handle created by this.subscribe. |
| // Also removes handle from this widget's list of subscriptions |
| for(var i=0; i<this._subscribes.length; i++){ |
| if(this._subscribes[i] == handle){ |
| dojo.unsubscribe(handle); |
| this._subscribes.splice(i, 1); |
| return; |
| } |
| } |
| }, |
| |
| isLeftToRight: function(){ |
| // summary: |
| // Checks the page for text direction |
| // tags: |
| // protected |
| return dojo._isBodyLtr(); //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"); |
| }, |
| |
| placeAt: function(/* String|DomNode|_Widget */reference, /* String?|Int? */position){ |
| // summary: |
| // Place this widget's domNode reference somewhere in the DOM based |
| // on standard dojo.place conventions, or passing a Widget reference that |
| // contains and addChild member. |
| // |
| // description: |
| // A convenience function provided in all _Widgets, providing a simple |
| // shorthand mechanism to put an existing (or newly created) Widget |
| // somewhere in the dom, and allow chaining. |
| // |
| // reference: |
| // The String id of a domNode, a domNode reference, or a reference to a Widget posessing |
| // an addChild method. |
| // |
| // position: |
| // If passed a string or domNode reference, the position argument |
| // accepts a string just as dojo.place does, one of: "first", "last", |
| // "before", or "after". |
| // |
| // If passed a _Widget reference, and that widget reference has an ".addChild" method, |
| // it will be called passing this widget instance into that method, supplying the optional |
| // position index passed. |
| // |
| // returns: |
| // dijit._Widget |
| // Provides a useful return of the newly created dijit._Widget instance so you |
| // can "chain" this function by instantiating, placing, then saving the return value |
| // to a variable. |
| // |
| // example: |
| // | // create a Button with no srcNodeRef, and place it in the body: |
| // | var button = new dijit.form.Button({ label:"click" }).placeAt(dojo.body()); |
| // | // now, 'button' is still the widget reference to the newly created button |
| // | dojo.connect(button, "onClick", function(e){ console.log('click'); }); |
| // |
| // example: |
| // | // create a button out of a node with id="src" and append it to id="wrapper": |
| // | var button = new dijit.form.Button({},"src").placeAt("wrapper"); |
| // |
| // example: |
| // | // place a new button as the first element of some div |
| // | var button = new dijit.form.Button({ label:"click" }).placeAt("wrapper","first"); |
| // |
| // example: |
| // | // create a contentpane and add it to a TabContainer |
| // | var tc = dijit.byId("myTabs"); |
| // | new dijit.layout.ContentPane({ href:"foo.html", title:"Wow!" }).placeAt(tc) |
| |
| if(reference.declaredClass && reference.addChild){ |
| reference.addChild(this, position); |
| }else{ |
| dojo.place(this.domNode, reference, position); |
| } |
| return this; |
| }, |
| |
| _onShow: function(){ |
| // summary: |
| // Internal method called when this widget is made visible. |
| // See `onShow` for details. |
| this.onShow(); |
| }, |
| |
| onShow: function(){ |
| // summary: |
| // Called when this widget becomes the selected pane in a |
| // `dijit.layout.TabContainer`, `dijit.layout.StackContainer`, |
| // `dijit.layout.AccordionContainer`, etc. |
| // |
| // Also called to indicate display of a `dijit.Dialog`, `dijit.TooltipDialog`, or `dijit.TitlePane`. |
| // tags: |
| // callback |
| }, |
| |
| onHide: function(){ |
| // summary: |
| // Called when another widget becomes the selected pane in a |
| // `dijit.layout.TabContainer`, `dijit.layout.StackContainer`, |
| // `dijit.layout.AccordionContainer`, etc. |
| // |
| // Also called to indicate hide of a `dijit.Dialog`, `dijit.TooltipDialog`, or `dijit.TitlePane`. |
| // tags: |
| // callback |
| } |
| }); |
| |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojo.string"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojo.string"] = true; |
| dojo.provide("dojo.string"); |
| |
| /*===== |
| dojo.string = { |
| // summary: String utilities for Dojo |
| }; |
| =====*/ |
| |
| dojo.string.rep = function(/*String*/str, /*Integer*/num){ |
| // summary: |
| // Efficiently replicate a string `n` times. |
| // str: |
| // the string to replicate |
| // num: |
| // number of times to replicate the string |
| |
| if(num <= 0 || !str){ return ""; } |
| |
| var buf = []; |
| for(;;){ |
| if(num & 1){ |
| buf.push(str); |
| } |
| if(!(num >>= 1)){ break; } |
| str += str; |
| } |
| return buf.join(""); // String |
| }; |
| |
| dojo.string.pad = function(/*String*/text, /*Integer*/size, /*String?*/ch, /*Boolean?*/end){ |
| // summary: |
| // Pad a string to guarantee that it is at least `size` length by |
| // filling with the character `ch` at either the start or end of the |
| // string. Pads at the start, by default. |
| // text: |
| // the string to pad |
| // size: |
| // length to provide padding |
| // ch: |
| // character to pad, defaults to '0' |
| // end: |
| // adds padding at the end if true, otherwise pads at start |
| // example: |
| // | // Fill the string to length 10 with "+" characters on the right. Yields "Dojo++++++". |
| // | dojo.string.pad("Dojo", 10, "+", true); |
| |
| if(!ch){ |
| ch = '0'; |
| } |
| var out = String(text), |
| pad = dojo.string.rep(ch, Math.ceil((size - out.length) / ch.length)); |
| return end ? out + pad : pad + out; // String |
| }; |
| |
| dojo.string.substitute = function( /*String*/ template, |
| /*Object|Array*/map, |
| /*Function?*/ transform, |
| /*Object?*/ thisObject){ |
| // summary: |
| // Performs parameterized substitutions on a string. Throws an |
| // exception if any parameter is unmatched. |
| // template: |
| // a string with expressions in the form `${key}` to be replaced or |
| // `${key:format}` which specifies a format function. keys are case-sensitive. |
| // map: |
| // hash to search for substitutions |
| // transform: |
| // a function to process all parameters before substitution takes |
| // place, e.g. mylib.encodeXML |
| // thisObject: |
| // where to look for optional format function; default to the global |
| // namespace |
| // example: |
| // Substitutes two expressions in a string from an Array or Object |
| // | // returns "File 'foo.html' is not found in directory '/temp'." |
| // | // by providing substitution data in an Array |
| // | dojo.string.substitute( |
| // | "File '${0}' is not found in directory '${1}'.", |
| // | ["foo.html","/temp"] |
| // | ); |
| // | |
| // | // also returns "File 'foo.html' is not found in directory '/temp'." |
| // | // but provides substitution data in an Object structure. Dotted |
| // | // notation may be used to traverse the structure. |
| // | dojo.string.substitute( |
| // | "File '${name}' is not found in directory '${info.dir}'.", |
| // | { name: "foo.html", info: { dir: "/temp" } } |
| // | ); |
| // example: |
| // Use a transform function to modify the values: |
| // | // returns "file 'foo.html' is not found in directory '/temp'." |
| // | dojo.string.substitute( |
| // | "${0} is not found in ${1}.", |
| // | ["foo.html","/temp"], |
| // | function(str){ |
| // | // try to figure out the type |
| // | var prefix = (str.charAt(0) == "/") ? "directory": "file"; |
| // | return prefix + " '" + str + "'"; |
| // | } |
| // | ); |
| // example: |
| // Use a formatter |
| // | // returns "thinger -- howdy" |
| // | dojo.string.substitute( |
| // | "${0:postfix}", ["thinger"], null, { |
| // | postfix: function(value, key){ |
| // | return value + " -- howdy"; |
| // | } |
| // | } |
| // | ); |
| |
| thisObject = thisObject || dojo.global; |
| transform = transform ? |
| dojo.hitch(thisObject, transform) : function(v){ return v; }; |
| |
| return template.replace(/\$\{([^\s\:\}]+)(?:\:([^\s\:\}]+))?\}/g, |
| function(match, key, format){ |
| var value = dojo.getObject(key, false, map); |
| if(format){ |
| value = dojo.getObject(format, false, thisObject).call(thisObject, value, key); |
| } |
| return transform(value, key).toString(); |
| }); // String |
| }; |
| |
| /*===== |
| dojo.string.trim = function(str){ |
| // summary: |
| // Trims whitespace from both sides of the string |
| // str: String |
| // String to be trimmed |
| // returns: String |
| // Returns the trimmed string |
| // description: |
| // This version of trim() was taken from [Steven Levithan's blog](http://blog.stevenlevithan.com/archives/faster-trim-javascript). |
| // The short yet performant version of this function is dojo.trim(), |
| // which is part of Dojo base. Uses String.prototype.trim instead, if available. |
| return ""; // String |
| } |
| =====*/ |
| |
| dojo.string.trim = String.prototype.trim ? |
| dojo.trim : // aliasing to the native function |
| function(str){ |
| str = str.replace(/^\s+/, ''); |
| for(var i = str.length - 1; i >= 0; i--){ |
| if(/\S/.test(str.charAt(i))){ |
| str = str.substring(0, i + 1); |
| break; |
| } |
| } |
| return str; |
| }; |
| |
| } |
| |
| if(!dojo._hasResource["dojo.cache"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojo.cache"] = true; |
| dojo.provide("dojo.cache"); |
| |
| /*===== |
| dojo.cache = { |
| // summary: |
| // A way to cache string content that is fetchable via `dojo.moduleUrl`. |
| }; |
| =====*/ |
| |
| (function(){ |
| var cache = {}; |
| dojo.cache = function(/*String||Object*/module, /*String*/url, /*String||Object?*/value){ |
| // summary: |
| // A getter and setter for storing the string content associated with the |
| // module and url arguments. |
| // description: |
| // module and url are used to call `dojo.moduleUrl()` to generate a module URL. |
| // If value is specified, the cache value for the moduleUrl will be set to |
| // that value. Otherwise, dojo.cache will fetch the moduleUrl and store it |
| // in its internal cache and return that cached value for the URL. To clear |
| // a cache value pass null for value. Since XMLHttpRequest (XHR) is used to fetch the |
| // the URL contents, only modules on the same domain of the page can use this capability. |
| // The build system can inline the cache values though, to allow for xdomain hosting. |
| // module: String||Object |
| // If a String, the module name to use for the base part of the URL, similar to module argument |
| // to `dojo.moduleUrl`. If an Object, something that has a .toString() method that |
| // generates a valid path for the cache item. For example, a dojo._Url object. |
| // url: String |
| // The rest of the path to append to the path derived from the module argument. If |
| // module is an object, then this second argument should be the "value" argument instead. |
| // value: String||Object? |
| // If a String, the value to use in the cache for the module/url combination. |
| // If an Object, it can have two properties: value and sanitize. The value property |
| // should be the value to use in the cache, and sanitize can be set to true or false, |
| // to indicate if XML declarations should be removed from the value and if the HTML |
| // inside a body tag in the value should be extracted as the real value. The value argument |
| // or the value property on the value argument are usually only used by the build system |
| // as it inlines cache content. |
| // example: |
| // To ask dojo.cache to fetch content and store it in the cache (the dojo["cache"] style |
| // of call is used to avoid an issue with the build system erroneously trying to intern |
| // this example. To get the build system to intern your dojo.cache calls, use the |
| // "dojo.cache" style of call): |
| // | //If template.html contains "<h1>Hello</h1>" that will be |
| // | //the value for the text variable. |
| // | var text = dojo["cache"]("my.module", "template.html"); |
| // example: |
| // To ask dojo.cache to fetch content and store it in the cache, and sanitize the input |
| // (the dojo["cache"] style of call is used to avoid an issue with the build system |
| // erroneously trying to intern this example. To get the build system to intern your |
| // dojo.cache calls, use the "dojo.cache" style of call): |
| // | //If template.html contains "<html><body><h1>Hello</h1></body></html>", the |
| // | //text variable will contain just "<h1>Hello</h1>". |
| // | var text = dojo["cache"]("my.module", "template.html", {sanitize: true}); |
| // example: |
| // Same example as previous, but demostrates how an object can be passed in as |
| // the first argument, then the value argument can then be the second argument. |
| // | //If template.html contains "<html><body><h1>Hello</h1></body></html>", the |
| // | //text variable will contain just "<h1>Hello</h1>". |
| // | var text = dojo["cache"](new dojo._Url("my/module/template.html"), {sanitize: true}); |
| |
| //Module could be a string, or an object that has a toString() method |
| //that will return a useful path. If it is an object, then the "url" argument |
| //will actually be the value argument. |
| if(typeof module == "string"){ |
| var pathObj = dojo.moduleUrl(module, url); |
| }else{ |
| pathObj = module; |
| value = url; |
| } |
| var key = pathObj.toString(); |
| |
| var val = value; |
| if(value !== undefined && !dojo.isString(value)){ |
| val = ("value" in value ? value.value : undefined); |
| } |
| |
| var sanitize = value && value.sanitize ? true : false; |
| |
| if(val || val === null){ |
| //We have a value, either clear or set the cache value. |
| if(val == null){ |
| delete cache[key]; |
| }else{ |
| val = cache[key] = sanitize ? dojo.cache._sanitize(val) : val; |
| } |
| }else{ |
| //Allow cache values to be empty strings. If key property does |
| //not exist, fetch it. |
| if(!(key in cache)){ |
| val = dojo._getText(key); |
| cache[key] = sanitize ? dojo.cache._sanitize(val) : val; |
| } |
| val = cache[key]; |
| } |
| return val; //String |
| }; |
| |
| dojo.cache._sanitize = function(/*String*/val){ |
| // summary: |
| // Strips <?xml ...?> declarations so that external SVG and XML |
| // documents can be added to a document without worry. Also, if the string |
| // is an HTML document, only the part inside the body tag is returned. |
| // description: |
| // Copied from dijit._Templated._sanitizeTemplateString. |
| if(val){ |
| val = val.replace(/^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, ""); |
| var matches = val.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im); |
| if(matches){ |
| val = matches[1]; |
| } |
| }else{ |
| val = ""; |
| } |
| return val; //String |
| }; |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dijit._Templated"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dijit._Templated"] = true; |
| dojo.provide("dijit._Templated"); |
| |
| |
| |
| |
| |
| |
| dojo.declare("dijit._Templated", |
| null, |
| { |
| // summary: |
| // Mixin for widgets that are instantiated from a template |
| |
| // templateString: [protected] String |
| // A string that represents the widget template. Pre-empts the |
| // templatePath. In builds that have their strings "interned", the |
| // templatePath is converted to an inline templateString, thereby |
| // preventing a synchronous network call. |
| // |
| // Use in conjunction with dojo.cache() to load from a file. |
| templateString: null, |
| |
| // templatePath: [protected deprecated] String |
| // Path to template (HTML file) for this widget relative to dojo.baseUrl. |
| // Deprecated: use templateString with dojo.cache() instead. |
| templatePath: null, |
| |
| // widgetsInTemplate: [protected] Boolean |
| // Should we parse the template to find widgets that might be |
| // declared in markup inside it? False by default. |
| widgetsInTemplate: false, |
| |
| // skipNodeCache: [protected] Boolean |
| // If using a cached widget template node poses issues for a |
| // particular widget class, it can set this property to ensure |
| // that its template is always re-built from a string |
| _skipNodeCache: false, |
| |
| // _earlyTemplatedStartup: Boolean |
| // A fallback to preserve the 1.0 - 1.3 behavior of children in |
| // templates having their startup called before the parent widget |
| // fires postCreate. Defaults to 'false', causing child widgets to |
| // have their .startup() called immediately before a parent widget |
| // .startup(), but always after the parent .postCreate(). Set to |
| // 'true' to re-enable to previous, arguably broken, behavior. |
| _earlyTemplatedStartup: false, |
| |
| // _attachPoints: [private] String[] |
| // List of widget attribute names associated with dojoAttachPoint=... in the |
| // template, ex: ["containerNode", "labelNode"] |
| /*===== |
| _attachPoints: [], |
| =====*/ |
| |
| constructor: function(){ |
| this._attachPoints = []; |
| }, |
| |
| _stringRepl: function(tmpl){ |
| // summary: |
| // Does substitution of ${foo} type properties in template string |
| // tags: |
| // private |
| var className = this.declaredClass, _this = this; |
| // Cache contains a string because we need to do property replacement |
| // do the property replacement |
| return dojo.string.substitute(tmpl, this, function(value, key){ |
| if(key.charAt(0) == '!'){ value = dojo.getObject(key.substr(1), false, _this); } |
| if(typeof value == "undefined"){ throw new Error(className+" template:"+key); } // a debugging aide |
| if(value == null){ return ""; } |
| |
| // Substitution keys beginning with ! will skip the transform step, |
| // in case a user wishes to insert unescaped markup, e.g. ${!foo} |
| return key.charAt(0) == "!" ? value : |
| // Safer substitution, see heading "Attribute values" in |
| // http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.3.2 |
| value.toString().replace(/"/g,"""); //TODO: add &? use encodeXML method? |
| }, this); |
| }, |
| |
| // method over-ride |
| buildRendering: function(){ |
| // summary: |
| // Construct the UI for this widget from a template, setting this.domNode. |
| // tags: |
| // protected |
| |
| // Lookup cached version of template, and download to cache if it |
| // isn't there already. Returns either a DomNode or a string, depending on |
| // whether or not the template contains ${foo} replacement parameters. |
| var cached = dijit._Templated.getCachedTemplate(this.templatePath, this.templateString, this._skipNodeCache); |
| |
| var node; |
| if(dojo.isString(cached)){ |
| node = dojo._toDom(this._stringRepl(cached)); |
| if(node.nodeType != 1){ |
| // Flag common problems such as templates with multiple top level nodes (nodeType == 11) |
| throw new Error("Invalid template: " + cached); |
| } |
| }else{ |
| // if it's a node, all we have to do is clone it |
| node = cached.cloneNode(true); |
| } |
| |
| this.domNode = node; |
| |
| // recurse through the node, looking for, and attaching to, our |
| // attachment points and events, which should be defined on the template node. |
| this._attachTemplateNodes(node); |
| |
| if(this.widgetsInTemplate){ |
| // Make sure dojoType is used for parsing widgets in template. |
| // The dojo.parser.query could be changed from multiversion support. |
| var parser = dojo.parser, qry, attr; |
| if(parser._query != "[dojoType]"){ |
| qry = parser._query; |
| attr = parser._attrName; |
| parser._query = "[dojoType]"; |
| parser._attrName = "dojoType"; |
| } |
| |
| // Store widgets that we need to start at a later point in time |
| var cw = (this._startupWidgets = dojo.parser.parse(node, { |
| noStart: !this._earlyTemplatedStartup |
| })); |
| |
| // Restore the query. |
| if(qry){ |
| parser._query = qry; |
| parser._attrName = attr; |
| } |
| |
| this._supportingWidgets = dijit.findWidgets(node); |
| |
| this._attachTemplateNodes(cw, function(n,p){ |
| return n[p]; |
| }); |
| } |
| |
| this._fillContent(this.srcNodeRef); |
| }, |
| |
| _fillContent: function(/*DomNode*/ source){ |
| // summary: |
| // Relocate source contents to templated container node. |
| // this.containerNode must be able to receive children, or exceptions will be thrown. |
| // tags: |
| // protected |
| var dest = this.containerNode; |
| if(source && dest){ |
| while(source.hasChildNodes()){ |
| dest.appendChild(source.firstChild); |
| } |
| } |
| }, |
| |
| _attachTemplateNodes: function(rootNode, getAttrFunc){ |
| // summary: |
| // Iterate through the template and attach functions and nodes accordingly. |
| // description: |
| // Map widget properties and functions to the handlers specified in |
| // the dom node and it's descendants. This function iterates over all |
| // nodes and looks for these properties: |
| // * dojoAttachPoint |
| // * dojoAttachEvent |
| // * waiRole |
| // * waiState |
| // rootNode: DomNode|Array[Widgets] |
| // the node to search for properties. All children will be searched. |
| // getAttrFunc: Function? |
| // a function which will be used to obtain property for a given |
| // DomNode/Widget |
| // tags: |
| // private |
| |
| getAttrFunc = getAttrFunc || function(n,p){ return n.getAttribute(p); }; |
| |
| var nodes = dojo.isArray(rootNode) ? rootNode : (rootNode.all || rootNode.getElementsByTagName("*")); |
| var x = dojo.isArray(rootNode) ? 0 : -1; |
| for(; x<nodes.length; x++){ |
| var baseNode = (x == -1) ? rootNode : nodes[x]; |
| if(this.widgetsInTemplate && getAttrFunc(baseNode, "dojoType")){ |
| continue; |
| } |
| // Process dojoAttachPoint |
| var attachPoint = getAttrFunc(baseNode, "dojoAttachPoint"); |
| if(attachPoint){ |
| var point, points = attachPoint.split(/\s*,\s*/); |
| while((point = points.shift())){ |
| if(dojo.isArray(this[point])){ |
| this[point].push(baseNode); |
| }else{ |
| this[point]=baseNode; |
| } |
| this._attachPoints.push(point); |
| } |
| } |
| |
| // Process dojoAttachEvent |
| var attachEvent = getAttrFunc(baseNode, "dojoAttachEvent"); |
| if(attachEvent){ |
| // NOTE: we want to support attributes that have the form |
| // "domEvent: nativeEvent; ..." |
| var event, events = attachEvent.split(/\s*,\s*/); |
| var trim = dojo.trim; |
| while((event = events.shift())){ |
| if(event){ |
| var thisFunc = null; |
| if(event.indexOf(":") != -1){ |
| // oh, if only JS had tuple assignment |
| var funcNameArr = event.split(":"); |
| event = trim(funcNameArr[0]); |
| thisFunc = trim(funcNameArr[1]); |
| }else{ |
| event = trim(event); |
| } |
| if(!thisFunc){ |
| thisFunc = event; |
| } |
| this.connect(baseNode, event, thisFunc); |
| } |
| } |
| } |
| |
| // waiRole, waiState |
| var role = getAttrFunc(baseNode, "waiRole"); |
| if(role){ |
| dijit.setWaiRole(baseNode, role); |
| } |
| var values = getAttrFunc(baseNode, "waiState"); |
| if(values){ |
| dojo.forEach(values.split(/\s*,\s*/), function(stateValue){ |
| if(stateValue.indexOf('-') != -1){ |
| var pair = stateValue.split('-'); |
| dijit.setWaiState(baseNode, pair[0], pair[1]); |
| } |
| }); |
| } |
| } |
| }, |
| |
| startup: function(){ |
| dojo.forEach(this._startupWidgets, function(w){ |
| if(w && !w._started && w.startup){ |
| w.startup(); |
| } |
| }); |
| this.inherited(arguments); |
| }, |
| |
| destroyRendering: function(){ |
| // Delete all attach points to prevent IE6 memory leaks. |
| dojo.forEach(this._attachPoints, function(point){ |
| delete this[point]; |
| }, this); |
| this._attachPoints = []; |
| |
| this.inherited(arguments); |
| } |
| } |
| ); |
| |
| // key is either templatePath or templateString; object is either string or DOM tree |
| dijit._Templated._templateCache = {}; |
| |
| dijit._Templated.getCachedTemplate = function(templatePath, templateString, alwaysUseString){ |
| // summary: |
| // Static method to get a template based on the templatePath or |
| // templateString key |
| // templatePath: String||dojo.uri.Uri |
| // The URL to get the template from. |
| // templateString: String? |
| // a string to use in lieu of fetching the template from a URL. Takes precedence |
| // over templatePath |
| // returns: Mixed |
| // Either string (if there are ${} variables that need to be replaced) or just |
| // a DOM tree (if the node can be cloned directly) |
| |
| // is it already cached? |
| var tmplts = dijit._Templated._templateCache; |
| var key = templateString || templatePath; |
| var cached = tmplts[key]; |
| if(cached){ |
| try{ |
| // if the cached value is an innerHTML string (no ownerDocument) or a DOM tree created within the current document, then use the current cached value |
| if(!cached.ownerDocument || cached.ownerDocument == dojo.doc){ |
| // string or node of the same document |
| return cached; |
| } |
| }catch(e){ /* squelch */ } // IE can throw an exception if cached.ownerDocument was reloaded |
| dojo.destroy(cached); |
| } |
| |
| // If necessary, load template string from template path |
| if(!templateString){ |
| templateString = dojo.cache(templatePath, {sanitize: true}); |
| } |
| templateString = dojo.string.trim(templateString); |
| |
| if(alwaysUseString || templateString.match(/\$\{([^\}]+)\}/g)){ |
| // there are variables in the template so all we can do is cache the string |
| return (tmplts[key] = templateString); //String |
| }else{ |
| // there are no variables in the template so we can cache the DOM tree |
| var node = dojo._toDom(templateString); |
| if(node.nodeType != 1){ |
| throw new Error("Invalid template: " + templateString); |
| } |
| return (tmplts[key] = node); //Node |
| } |
| }; |
| |
| if(dojo.isIE){ |
| dojo.addOnWindowUnload(function(){ |
| var cache = dijit._Templated._templateCache; |
| for(var key in cache){ |
| var value = cache[key]; |
| if(typeof value == "object"){ // value is either a string or a DOM node template |
| dojo.destroy(value); |
| } |
| delete cache[key]; |
| } |
| }); |
| } |
| |
| // These arguments can be specified for widgets which are used in templates. |
| // Since any widget can be specified as sub widgets in template, mix it |
| // into the base widget class. (This is a hack, but it's effective.) |
| dojo.extend(dijit._Widget,{ |
| dojoAttachEvent: "", |
| dojoAttachPoint: "", |
| waiRole: "", |
| waiState:"" |
| }); |
| |
| } |
| |
| if(!dojo._hasResource["dijit._Container"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dijit._Container"] = true; |
| dojo.provide("dijit._Container"); |
| |
| dojo.declare("dijit._Container", |
| null, |
| { |
| // summary: |
| // Mixin for widgets that contain a set of widget children. |
| // description: |
| // Use this mixin for widgets that needs to know about and |
| // keep track of their widget children. Suitable for widgets like BorderContainer |
| // and TabContainer which contain (only) a set of child widgets. |
| // |
| // It's not suitable for widgets like ContentPane |
| // which contains mixed HTML (plain DOM nodes in addition to widgets), |
| // and where contained widgets are not necessarily directly below |
| // this.containerNode. In that case calls like addChild(node, position) |
| // wouldn't make sense. |
| |
| // isContainer: [protected] Boolean |
| // Indicates that this widget acts as a "parent" to the descendant widgets. |
| // When the parent is started it will call startup() on the child widgets. |
| // See also `isLayoutContainer`. |
| isContainer: true, |
| |
| buildRendering: function(){ |
| this.inherited(arguments); |
| if(!this.containerNode){ |
| // all widgets with descendants must set containerNode |
| this.containerNode = this.domNode; |
| } |
| }, |
| |
| addChild: function(/*dijit._Widget*/ widget, /*int?*/ insertIndex){ |
| // summary: |
| // Makes the given widget a child of this widget. |
| // description: |
| // Inserts specified child widget's dom node as a child of this widget's |
| // container node, and possibly does other processing (such as layout). |
| |
| var refNode = this.containerNode; |
| if(insertIndex && typeof insertIndex == "number"){ |
| var children = this.getChildren(); |
| if(children && children.length >= insertIndex){ |
| refNode = children[insertIndex-1].domNode; |
| insertIndex = "after"; |
| } |
| } |
| dojo.place(widget.domNode, refNode, insertIndex); |
| |
| // If I've been started but the child widget hasn't been started, |
| // start it now. Make sure to do this after widget has been |
| // inserted into the DOM tree, so it can see that it's being controlled by me, |
| // so it doesn't try to size itself. |
| if(this._started && !widget._started){ |
| widget.startup(); |
| } |
| }, |
| |
| removeChild: function(/*Widget or int*/ widget){ |
| // summary: |
| // Removes the passed widget instance from this widget but does |
| // not destroy it. You can also pass in an integer indicating |
| // the index within the container to remove |
| |
| if(typeof widget == "number" && widget > 0){ |
| widget = this.getChildren()[widget]; |
| } |
| |
| if(widget && widget.domNode){ |
| var node = widget.domNode; |
| node.parentNode.removeChild(node); // detach but don't destroy |
| } |
| }, |
| |
| getChildren: function(){ |
| // summary: |
| // Returns array of children widgets. |
| // description: |
| // Returns the widgets that are directly under this.containerNode. |
| return dojo.query("> [widgetId]", this.containerNode).map(dijit.byNode); // Widget[] |
| }, |
| |
| hasChildren: function(){ |
| // summary: |
| // Returns true if widget has children, i.e. if this.containerNode contains something. |
| return dojo.query("> [widgetId]", this.containerNode).length > 0; // Boolean |
| }, |
| |
| destroyDescendants: function(/*Boolean*/ preserveDom){ |
| // summary: |
| // Destroys all the widgets inside this.containerNode, |
| // but not this widget itself |
| dojo.forEach(this.getChildren(), function(child){ child.destroyRecursive(preserveDom); }); |
| }, |
| |
| _getSiblingOfChild: function(/*dijit._Widget*/ child, /*int*/ dir){ |
| // summary: |
| // Get the next or previous widget sibling of child |
| // dir: |
| // if 1, get the next sibling |
| // if -1, get the previous sibling |
| // tags: |
| // private |
| var node = child.domNode, |
| which = (dir>0 ? "nextSibling" : "previousSibling"); |
| do{ |
| node = node[which]; |
| }while(node && (node.nodeType != 1 || !dijit.byNode(node))); |
| return node && dijit.byNode(node); // dijit._Widget |
| }, |
| |
| getIndexOfChild: function(/*dijit._Widget*/ child){ |
| // summary: |
| // Gets the index of the child in this container or -1 if not found |
| return dojo.indexOf(this.getChildren(), child); // int |
| }, |
| |
| startup: function(){ |
| // summary: |
| // Called after all the widgets have been instantiated and their |
| // dom nodes have been inserted somewhere under dojo.doc.body. |
| // |
| // Widgets should override this method to do any initialization |
| // dependent on other widgets existing, and then call |
| // this superclass method to finish things off. |
| // |
| // startup() in subclasses shouldn't do anything |
| // size related because the size of the widget hasn't been set yet. |
| |
| if(this._started){ return; } |
| |
| // Startup all children of this widget |
| dojo.forEach(this.getChildren(), function(child){ child.startup(); }); |
| |
| this.inherited(arguments); |
| } |
| } |
| ); |
| |
| } |
| |
| if(!dojo._hasResource["dijit._Contained"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dijit._Contained"] = true; |
| dojo.provide("dijit._Contained"); |
| |
| dojo.declare("dijit._Contained", |
| null, |
| { |
| // summary: |
| // Mixin for widgets that are children of a container widget |
| // |
| // example: |
| // | // make a basic custom widget that knows about it's parents |
| // | dojo.declare("my.customClass",[dijit._Widget,dijit._Contained],{}); |
| |
| getParent: function(){ |
| // summary: |
| // Returns the parent widget of this widget, assuming the parent |
| // specifies isContainer |
| var parent = dijit.getEnclosingWidget(this.domNode.parentNode); |
| return parent && parent.isContainer ? parent : null; |
| }, |
| |
| _getSibling: function(/*String*/ which){ |
| // summary: |
| // Returns next or previous sibling |
| // which: |
| // Either "next" or "previous" |
| // tags: |
| // private |
| var node = this.domNode; |
| do{ |
| node = node[which+"Sibling"]; |
| }while(node && node.nodeType != 1); |
| return node && dijit.byNode(node); // dijit._Widget |
| }, |
| |
| getPreviousSibling: function(){ |
| // summary: |
| // Returns null if this is the first child of the parent, |
| // otherwise returns the next element sibling to the "left". |
| |
| return this._getSibling("previous"); // dijit._Widget |
| }, |
| |
| getNextSibling: function(){ |
| // summary: |
| // Returns null if this is the last child of the parent, |
| // otherwise returns the next element sibling to the "right". |
| |
| return this._getSibling("next"); // dijit._Widget |
| }, |
| |
| getIndexInParent: function(){ |
| // summary: |
| // Returns the index of this widget within its container parent. |
| // It returns -1 if the parent does not exist, or if the parent |
| // is not a dijit._Container |
| |
| var p = this.getParent(); |
| if(!p || !p.getIndexOfChild){ |
| return -1; // int |
| } |
| return p.getIndexOfChild(this); // int |
| } |
| } |
| ); |
| |
| |
| } |
| |
| if(!dojo._hasResource["dijit.layout._LayoutWidget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dijit.layout._LayoutWidget"] = true; |
| dojo.provide("dijit.layout._LayoutWidget"); |
| |
| |
| |
| |
| |
| dojo.declare("dijit.layout._LayoutWidget", |
| [dijit._Widget, dijit._Container, dijit._Contained], |
| { |
| // summary: |
| // Base class for a _Container widget which is responsible for laying out its children. |
| // Widgets which mixin this code must define layout() to manage placement and sizing of the children. |
| |
| // baseClass: [protected extension] String |
| // This class name is applied to the widget's domNode |
| // and also may be used to generate names for sub nodes, |
| // for example dijitTabContainer-content. |
| baseClass: "dijitLayoutContainer", |
| |
| // isLayoutContainer: [protected] Boolean |
| // Indicates that this widget is going to call resize() on its |
| // children widgets, setting their size, when they become visible. |
| isLayoutContainer: true, |
| |
| postCreate: function(){ |
| dojo.addClass(this.domNode, "dijitContainer"); |
| dojo.addClass(this.domNode, this.baseClass); |
| |
| this.inherited(arguments); |
| }, |
| |
| startup: function(){ |
| // summary: |
| // Called after all the widgets have been instantiated and their |
| // dom nodes have been inserted somewhere under dojo.doc.body. |
| // |
| // Widgets should override this method to do any initialization |
| // dependent on other widgets existing, and then call |
| // this superclass method to finish things off. |
| // |
| // startup() in subclasses shouldn't do anything |
| // size related because the size of the widget hasn't been set yet. |
| |
| if(this._started){ return; } |
| |
| // Need to call inherited first - so that child widgets get started |
| // up correctly |
| this.inherited(arguments); |
| |
| // If I am a not being controlled by a parent layout widget... |
| var parent = this.getParent && this.getParent() |
| if(!(parent && parent.isLayoutContainer)){ |
| // Do recursive sizing and layout of all my descendants |
| // (passing in no argument to resize means that it has to glean the size itself) |
| this.resize(); |
| |
| // Since my parent isn't a layout container, and my style *may be* width=height=100% |
| // or something similar (either set directly or via a CSS class), |
| // monitor when my size changes so that I can re-layout. |
| // For browsers where I can't directly monitor when my size changes, |
| // monitor when the viewport changes size, which *may* indicate a size change for me. |
| this.connect(dojo.isIE ? this.domNode : dojo.global, 'onresize', function(){ |
| // Using function(){} closure to ensure no arguments to resize. |
| this.resize(); |
| }); |
| } |
| }, |
| |
| resize: function(changeSize, resultSize){ |
| // summary: |
| // Call this to resize a widget, or after its size has changed. |
| // description: |
| // Change size mode: |
| // When changeSize is specified, changes the marginBox of this widget |
| // and forces it to relayout its contents accordingly. |
| // changeSize may specify height, width, or both. |
| // |
| // If resultSize is specified it indicates the size the widget will |
| // become after changeSize has been applied. |
| // |
| // Notification mode: |
| // When changeSize is null, indicates that the caller has already changed |
| // the size of the widget, or perhaps it changed because the browser |
| // window was resized. Tells widget to relayout its contents accordingly. |
| // |
| // If resultSize is also specified it indicates the size the widget has |
| // become. |
| // |
| // In either mode, this method also: |
| // 1. Sets this._borderBox and this._contentBox to the new size of |
| // the widget. Queries the current domNode size if necessary. |
| // 2. Calls layout() to resize contents (and maybe adjust child widgets). |
| // |
| // changeSize: Object? |
| // Sets the widget to this margin-box size and position. |
| // May include any/all of the following properties: |
| // | {w: int, h: int, l: int, t: int} |
| // |
| // resultSize: Object? |
| // The margin-box size of this widget after applying changeSize (if |
| // changeSize is specified). If caller knows this size and |
| // passes it in, we don't need to query the browser to get the size. |
| // | {w: int, h: int} |
| |
| var node = this.domNode; |
| |
| // set margin box size, unless it wasn't specified, in which case use current size |
| if(changeSize){ |
| dojo.marginBox(node, changeSize); |
| |
| // set offset of the node |
| if(changeSize.t){ node.style.top = changeSize.t + "px"; } |
| if(changeSize.l){ node.style.left = changeSize.l + "px"; } |
| } |
| |
| // If either height or width wasn't specified by the user, then query node for it. |
| // But note that setting the margin box and then immediately querying dimensions may return |
| // inaccurate results, so try not to depend on it. |
| var mb = resultSize || {}; |
| dojo.mixin(mb, changeSize || {}); // changeSize overrides resultSize |
| if( !("h" in mb) || !("w" in mb) ){ |
| mb = dojo.mixin(dojo.marginBox(node), mb); // just use dojo.marginBox() to fill in missing values |
| } |
| |
| // Compute and save the size of my border box and content box |
| // (w/out calling dojo.contentBox() since that may fail if size was recently set) |
| var cs = dojo.getComputedStyle(node); |
| var me = dojo._getMarginExtents(node, cs); |
| var be = dojo._getBorderExtents(node, cs); |
| var bb = (this._borderBox = { |
| w: mb.w - (me.w + be.w), |
| h: mb.h - (me.h + be.h) |
| }); |
| var pe = dojo._getPadExtents(node, cs); |
| this._contentBox = { |
| l: dojo._toPixelValue(node, cs.paddingLeft), |
| t: dojo._toPixelValue(node, cs.paddingTop), |
| w: bb.w - pe.w, |
| h: bb.h - pe.h |
| }; |
| |
| // Callback for widget to adjust size of its children |
| this.layout(); |
| }, |
| |
| layout: function(){ |
| // summary: |
| // Widgets override this method to size and position their contents/children. |
| // When this is called this._contentBox is guaranteed to be set (see resize()). |
| // |
| // This is called after startup(), and also when the widget's size has been |
| // changed. |
| // tags: |
| // protected extension |
| }, |
| |
| _setupChild: function(/*dijit._Widget*/child){ |
| // summary: |
| // Common setup for initial children and children which are added after startup |
| // tags: |
| // protected extension |
| |
| dojo.addClass(child.domNode, this.baseClass+"-child"); |
| if(child.baseClass){ |
| dojo.addClass(child.domNode, this.baseClass+"-"+child.baseClass); |
| } |
| }, |
| |
| addChild: function(/*dijit._Widget*/ child, /*Integer?*/ insertIndex){ |
| // Overrides _Container.addChild() to call _setupChild() |
| this.inherited(arguments); |
| if(this._started){ |
| this._setupChild(child); |
| } |
| }, |
| |
| removeChild: function(/*dijit._Widget*/ child){ |
| // Overrides _Container.removeChild() to remove class added by _setupChild() |
| dojo.removeClass(child.domNode, this.baseClass+"-child"); |
| if(child.baseClass){ |
| dojo.removeClass(child.domNode, this.baseClass+"-"+child.baseClass); |
| } |
| this.inherited(arguments); |
| } |
| } |
| ); |
| |
| dijit.layout.marginBox2contentBox = function(/*DomNode*/ node, /*Object*/ mb){ |
| // summary: |
| // Given the margin-box size of a node, return its content box size. |
| // Functions like dojo.contentBox() but is more reliable since it doesn't have |
| // to wait for the browser to compute sizes. |
| var cs = dojo.getComputedStyle(node); |
| var me = dojo._getMarginExtents(node, cs); |
| var pb = dojo._getPadBorderExtents(node, cs); |
| return { |
| l: dojo._toPixelValue(node, cs.paddingLeft), |
| t: dojo._toPixelValue(node, cs.paddingTop), |
| w: mb.w - (me.w + pb.w), |
| h: mb.h - (me.h + pb.h) |
| }; |
| }; |
| |
| (function(){ |
| var capitalize = function(word){ |
| return word.substring(0,1).toUpperCase() + word.substring(1); |
| }; |
| |
| var size = function(widget, dim){ |
| // size the child |
| widget.resize ? widget.resize(dim) : dojo.marginBox(widget.domNode, dim); |
| |
| // record child's size, but favor our own numbers when we have them. |
| // the browser lies sometimes |
| dojo.mixin(widget, dojo.marginBox(widget.domNode)); |
| dojo.mixin(widget, dim); |
| }; |
| |
| dijit.layout.layoutChildren = function(/*DomNode*/ container, /*Object*/ dim, /*Object[]*/ children){ |
| // summary |
| // Layout a bunch of child dom nodes within a parent dom node |
| // container: |
| // parent node |
| // dim: |
| // {l, t, w, h} object specifying dimensions of container into which to place children |
| // children: |
| // an array like [ {domNode: foo, layoutAlign: "bottom" }, {domNode: bar, layoutAlign: "client"} ] |
| |
| // copy dim because we are going to modify it |
| dim = dojo.mixin({}, dim); |
| |
| dojo.addClass(container, "dijitLayoutContainer"); |
| |
| // Move "client" elements to the end of the array for layout. a11y dictates that the author |
| // needs to be able to put them in the document in tab-order, but this algorithm requires that |
| // client be last. |
| children = dojo.filter(children, function(item){ return item.layoutAlign != "client"; }) |
| .concat(dojo.filter(children, function(item){ return item.layoutAlign == "client"; })); |
| |
| // set positions/sizes |
| dojo.forEach(children, function(child){ |
| var elm = child.domNode, |
| pos = child.layoutAlign; |
| |
| // set elem to upper left corner of unused space; may move it later |
| var elmStyle = elm.style; |
| elmStyle.left = dim.l+"px"; |
| elmStyle.top = dim.t+"px"; |
| elmStyle.bottom = elmStyle.right = "auto"; |
| |
| dojo.addClass(elm, "dijitAlign" + capitalize(pos)); |
| |
| // set size && adjust record of remaining space. |
| // note that setting the width of a <div> may affect its height. |
| if(pos == "top" || pos == "bottom"){ |
| size(child, { w: dim.w }); |
| dim.h -= child.h; |
| if(pos == "top"){ |
| dim.t += child.h; |
| }else{ |
| elmStyle.top = dim.t + dim.h + "px"; |
| } |
| }else if(pos == "left" || pos == "right"){ |
| size(child, { h: dim.h }); |
| dim.w -= child.w; |
| if(pos == "left"){ |
| dim.l += child.w; |
| }else{ |
| elmStyle.left = dim.l + dim.w + "px"; |
| } |
| }else if(pos == "client"){ |
| size(child, dim); |
| } |
| }); |
| }; |
| |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dijit.form._FormWidget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dijit.form._FormWidget"] = true; |
| dojo.provide("dijit.form._FormWidget"); |
| |
| |
| |
| |
| dojo.declare("dijit.form._FormWidget", [dijit._Widget, dijit._Templated], |
| { |
| // summary: |
| // Base class for widgets corresponding to native HTML elements such as <checkbox> or <button>, |
| // which can be children of a <form> node or a `dijit.form.Form` widget. |
| // |
| // description: |
| // Represents a single HTML element. |
| // All these widgets should have these attributes just like native HTML input elements. |
| // You can set them during widget construction or afterwards, via `dijit._Widget.attr`. |
| // |
| // They also share some common methods. |
| |
| // baseClass: [protected] String |
| // Root CSS class of the widget (ex: dijitTextBox), used to add CSS classes of widget |
| // (ex: "dijitTextBox dijitTextBoxInvalid dijitTextBoxFocused dijitTextBoxInvalidFocused") |
| // See _setStateClass(). |
| baseClass: "", |
| |
| // name: String |
| // Name used when submitting form; same as "name" attribute or plain HTML elements |
| name: "", |
| |
| // alt: String |
| // Corresponds to the native HTML <input> element's attribute. |
| alt: "", |
| |
| // value: String |
| // Corresponds to the native HTML <input> element's attribute. |
| value: "", |
| |
| // type: String |
| // Corresponds to the native HTML <input> element's attribute. |
| type: "text", |
| |
| // tabIndex: Integer |
| // Order fields are traversed when user hits the tab key |
| tabIndex: "0", |
| |
| // disabled: Boolean |
| // Should this widget respond to user input? |
| // In markup, this is specified as "disabled='disabled'", or just "disabled". |
| disabled: false, |
| |
| // intermediateChanges: Boolean |
| // Fires onChange for each value change or only on demand |
| intermediateChanges: false, |
| |
| // scrollOnFocus: Boolean |
| // On focus, should this widget scroll into view? |
| scrollOnFocus: true, |
| |
| // These mixins assume that the focus node is an INPUT, as many but not all _FormWidgets are. |
| attributeMap: dojo.delegate(dijit._Widget.prototype.attributeMap, { |
| value: "focusNode", |
| id: "focusNode", |
| tabIndex: "focusNode", |
| alt: "focusNode", |
| title: "focusNode" |
| }), |
| |
| postMixInProperties: function(){ |
| // Setup name=foo string to be referenced from the template (but only if a name has been specified) |
| // Unfortunately we can't use attributeMap to set the name due to IE limitations, see #8660 |
| this.nameAttrSetting = this.name ? ("name='" + this.name + "'") : ""; |
| this.inherited(arguments); |
| }, |
| |
| _setDisabledAttr: function(/*Boolean*/ value){ |
| this.disabled = value; |
| dojo.attr(this.focusNode, 'disabled', value); |
| if(this.valueNode){ |
| dojo.attr(this.valueNode, 'disabled', value); |
| } |
| dijit.setWaiState(this.focusNode, "disabled", value); |
| |
| if(value){ |
| // reset those, because after the domNode is disabled, we can no longer receive |
| // mouse related events, see #4200 |
| this._hovering = false; |
| this._active = false; |
| // remove the tabIndex, especially for FF |
| this.focusNode.setAttribute('tabIndex', "-1"); |
| }else{ |
| this.focusNode.setAttribute('tabIndex', this.tabIndex); |
| } |
| this._setStateClass(); |
| }, |
| |
| setDisabled: function(/*Boolean*/ disabled){ |
| // summary: |
| // Deprecated. Use attr('disabled', ...) instead. |
| dojo.deprecated("setDisabled("+disabled+") is deprecated. Use attr('disabled',"+disabled+") instead.", "", "2.0"); |
| this.attr('disabled', disabled); |
| }, |
| |
| _onFocus: function(e){ |
| if(this.scrollOnFocus){ |
| dijit.scrollIntoView(this.domNode); |
| } |
| this.inherited(arguments); |
| }, |
| |
| _onMouse : function(/*Event*/ event){ |
| // summary: |
| // Sets _hovering, _active, and stateModifier properties depending on mouse state, |
| // then calls setStateClass() to set appropriate CSS classes for this.domNode. |
| // |
| // To get a different CSS class for hover, send onmouseover and onmouseout events to this method. |
| // To get a different CSS class while mouse button is depressed, send onmousedown to this method. |
| |
| var mouseNode = event.currentTarget; |
| if(mouseNode && mouseNode.getAttribute){ |
| this.stateModifier = mouseNode.getAttribute("stateModifier") || ""; |
| } |
| |
| if(!this.disabled){ |
| switch(event.type){ |
| case "mouseenter": |
| case "mouseover": |
| this._hovering = true; |
| this._active = this._mouseDown; |
| break; |
| |
| case "mouseout": |
| case "mouseleave": |
| this._hovering = false; |
| this._active = false; |
| break; |
| |
| case "mousedown" : |
| this._active = true; |
| this._mouseDown = true; |
| // set a global event to handle mouseup, so it fires properly |
| // even if the cursor leaves the button |
| var mouseUpConnector = this.connect(dojo.body(), "onmouseup", function(){ |
| // if user clicks on the button, even if the mouse is released outside of it, |
| // this button should get focus (which mimics native browser buttons) |
| if(this._mouseDown && this.isFocusable()){ |
| this.focus(); |
| } |
| this._active = false; |
| this._mouseDown = false; |
| this._setStateClass(); |
| this.disconnect(mouseUpConnector); |
| }); |
| break; |
| } |
| this._setStateClass(); |
| } |
| }, |
| |
| isFocusable: function(){ |
| // summary: |
| // Tells if this widget is focusable or not. Used internally by dijit. |
| // tags: |
| // protected |
| return !this.disabled && !this.readOnly && this.focusNode && (dojo.style(this.domNode, "display") != "none"); |
| }, |
| |
| focus: function(){ |
| // summary: |
| // Put focus on this widget |
| dijit.focus(this.focusNode); |
| }, |
| |
| _setStateClass: function(){ |
| // summary: |
| // Update the visual state of the widget by setting the css classes on this.domNode |
| // (or this.stateNode if defined) by combining this.baseClass with |
| // various suffixes that represent the current widget state(s). |
| // |
| // description: |
| // In the case where a widget has multiple |
| // states, it sets the class based on all possible |
| // combinations. For example, an invalid form widget that is being hovered |
| // will be "dijitInput dijitInputInvalid dijitInputHover dijitInputInvalidHover". |
| // |
| // For complex widgets with multiple regions, there can be various hover/active states, |
| // such as "Hover" or "CloseButtonHover" (for tab buttons). |
| // This is controlled by a stateModifier="CloseButton" attribute on the close button node. |
| // |
| // The widget may have one or more of the following states, determined |
| // by this.state, this.checked, this.valid, and this.selected: |
| // - Error - ValidationTextBox sets this.state to "Error" if the current input value is invalid |
| // - Checked - ex: a checkmark or a ToggleButton in a checked state, will have this.checked==true |
| // - Selected - ex: currently selected tab will have this.selected==true |
| // |
| // In addition, it may have one or more of the following states, |
| // based on this.disabled and flags set in _onMouse (this._active, this._hovering, this._focused): |
| // - Disabled - if the widget is disabled |
| // - Active - if the mouse (or space/enter key?) is being pressed down |
| // - Focused - if the widget has focus |
| // - Hover - if the mouse is over the widget |
| |
| // Compute new set of classes |
| var newStateClasses = this.baseClass.split(" "); |
| |
| function multiply(modifier){ |
| newStateClasses = newStateClasses.concat(dojo.map(newStateClasses, function(c){ return c+modifier; }), "dijit"+modifier); |
| } |
| |
| if(this.checked){ |
| multiply("Checked"); |
| } |
| if(this.state){ |
| multiply(this.state); |
| } |
| if(this.selected){ |
| multiply("Selected"); |
| } |
| |
| if(this.disabled){ |
| multiply("Disabled"); |
| }else if(this.readOnly){ |
| multiply("ReadOnly"); |
| }else if(this._active){ |
| multiply(this.stateModifier+"Active"); |
| }else{ |
| if(this._focused){ |
| multiply("Focused"); |
| } |
| if(this._hovering){ |
| multiply(this.stateModifier+"Hover"); |
| } |
| } |
| |
| // Remove old state classes and add new ones. |
| // For performance concerns we only write into domNode.className once. |
| var tn = this.stateNode || this.domNode, |
| classHash = {}; // set of all classes (state and otherwise) for node |
| |
| dojo.forEach(tn.className.split(" "), function(c){ classHash[c] = true; }); |
| |
| if("_stateClasses" in this){ |
| dojo.forEach(this._stateClasses, function(c){ delete classHash[c]; }); |
| } |
| |
| dojo.forEach(newStateClasses, function(c){ classHash[c] = true; }); |
| |
| var newClasses = []; |
| for(var c in classHash){ |
| newClasses.push(c); |
| } |
| tn.className = newClasses.join(" "); |
| |
| this._stateClasses = newStateClasses; |
| }, |
| |
| compare: function(/*anything*/val1, /*anything*/val2){ |
| // summary: |
| // Compare 2 values (as returned by attr('value') for this widget). |
| // tags: |
| // protected |
| if(typeof val1 == "number" && typeof val2 == "number"){ |
| return (isNaN(val1) && isNaN(val2)) ? 0 : val1 - val2; |
| }else if(val1 > val2){ |
| return 1; |
| }else if(val1 < val2){ |
| return -1; |
| }else{ |
| return 0; |
| } |
| }, |
| |
| onChange: function(newValue){ |
| // summary: |
| // Callback when this widget's value is changed. |
| // tags: |
| // callback |
| }, |
| |
| // _onChangeActive: [private] Boolean |
| // Indicates that changes to the value should call onChange() callback. |
| // This is false during widget initialization, to avoid calling onChange() |
| // when the initial value is set. |
| _onChangeActive: false, |
| |
| _handleOnChange: function(/*anything*/ newValue, /* Boolean? */ priorityChange){ |
| // summary: |
| // Called when the value of the widget is set. Calls onChange() if appropriate |
| // newValue: |
| // the new value |
| // priorityChange: |
| // For a slider, for example, dragging the slider is priorityChange==false, |
| // but on mouse up, it's priorityChange==true. If intermediateChanges==true, |
| // onChange is only called form priorityChange=true events. |
| // tags: |
| // private |
| this._lastValue = newValue; |
| if(this._lastValueReported == undefined && (priorityChange === null || !this._onChangeActive)){ |
| // this block executes not for a change, but during initialization, |
| // and is used to store away the original value (or for ToggleButton, the original checked state) |
| this._resetValue = this._lastValueReported = newValue; |
| } |
| if((this.intermediateChanges || priorityChange || priorityChange === undefined) && |
| ((typeof newValue != typeof this._lastValueReported) || |
| this.compare(newValue, this._lastValueReported) != 0)){ |
| this._lastValueReported = newValue; |
| if(this._onChangeActive){ |
| if(this._onChangeHandle){ |
| clearTimeout(this._onChangeHandle); |
| } |
| // setTimout allows hidden value processing to run and |
| // also the onChange handler can safely adjust focus, etc |
| this._onChangeHandle = setTimeout(dojo.hitch(this, |
| function(){ |
| this._onChangeHandle = null; |
| this.onChange(newValue); |
| }), 0); // try to collapse multiple onChange's fired faster than can be processed |
| } |
| } |
| }, |
| |
| create: function(){ |
| // Overrides _Widget.create() |
| this.inherited(arguments); |
| this._onChangeActive = true; |
| this._setStateClass(); |
| }, |
| |
| destroy: function(){ |
| if(this._onChangeHandle){ // destroy called before last onChange has fired |
| clearTimeout(this._onChangeHandle); |
| this.onChange(this._lastValueReported); |
| } |
| this.inherited(arguments); |
| }, |
| |
| setValue: function(/*String*/ value){ |
| // summary: |
| // Deprecated. Use attr('value', ...) instead. |
| dojo.deprecated("dijit.form._FormWidget:setValue("+value+") is deprecated. Use attr('value',"+value+") instead.", "", "2.0"); |
| this.attr('value', value); |
| }, |
| |
| getValue: function(){ |
| // summary: |
| // Deprecated. Use attr('value') instead. |
| dojo.deprecated(this.declaredClass+"::getValue() is deprecated. Use attr('value') instead.", "", "2.0"); |
| return this.attr('value'); |
| } |
| }); |
| |
| dojo.declare("dijit.form._FormValueWidget", dijit.form._FormWidget, |
| { |
| // summary: |
| // Base class for widgets corresponding to native HTML elements such as <input> or <select> that have user changeable values. |
| // description: |
| // Each _FormValueWidget represents a single input value, and has a (possibly hidden) <input> element, |
| // to which it serializes it's input value, so that form submission (either normal submission or via FormBind?) |
| // works as expected. |
| |
| // Don't attempt to mixin the 'type', 'name' attributes here programatically -- they must be declared |
| // directly in the template as read by the parser in order to function. IE is known to specifically |
| // require the 'name' attribute at element creation time. See #8484, #8660. |
| // TODO: unclear what that {value: ""} is for; FormWidget.attributeMap copies value to focusNode, |
| // so maybe {value: ""} is so the value *doesn't* get copied to focusNode? |
| // Seems like we really want value removed from attributeMap altogether |
| // (although there's no easy way to do that now) |
| |
| // readOnly: Boolean |
| // Should this widget respond to user input? |
| // In markup, this is specified as "readOnly". |
| // Similar to disabled except readOnly form values are submitted. |
| readOnly: false, |
| |
| attributeMap: dojo.delegate(dijit.form._FormWidget.prototype.attributeMap, { |
| value: "", |
| readOnly: "focusNode" |
| }), |
| |
| _setReadOnlyAttr: function(/*Boolean*/ value){ |
| this.readOnly = value; |
| dojo.attr(this.focusNode, 'readOnly', value); |
| dijit.setWaiState(this.focusNode, "readonly", value); |
| this._setStateClass(); |
| }, |
| |
| postCreate: function(){ |
| if(dojo.isIE){ // IE won't stop the event with keypress |
| this.connect(this.focusNode || this.domNode, "onkeydown", this._onKeyDown); |
| } |
| // Update our reset value if it hasn't yet been set (because this.attr |
| // is only called when there *is* a value |
| if(this._resetValue === undefined){ |
| this._resetValue = this.value; |
| } |
| }, |
| |
| _setValueAttr: function(/*anything*/ newValue, /*Boolean, optional*/ priorityChange){ |
| // summary: |
| // Hook so attr('value', value) works. |
| // description: |
| // Sets the value of the widget. |
| // If the value has changed, then fire onChange event, unless priorityChange |
| // is specified as null (or false?) |
| this.value = newValue; |
| this._handleOnChange(newValue, priorityChange); |
| }, |
| |
| _getValueAttr: function(){ |
| // summary: |
| // Hook so attr('value') works. |
| return this._lastValue; |
| }, |
| |
| undo: function(){ |
| // summary: |
| // Restore the value to the last value passed to onChange |
| this._setValueAttr(this._lastValueReported, false); |
| }, |
| |
| reset: function(){ |
| // summary: |
| // Reset the widget's value to what it was at initialization time |
| this._hasBeenBlurred = false; |
| this._setValueAttr(this._resetValue, true); |
| }, |
| |
| _onKeyDown: function(e){ |
| if(e.keyCode == dojo.keys.ESCAPE && !(e.ctrlKey || e.altKey || e.metaKey)){ |
| var te; |
| if(dojo.isIE){ |
| e.preventDefault(); // default behavior needs to be stopped here since keypress is too late |
| te = document.createEventObject(); |
| te.keyCode = dojo.keys.ESCAPE; |
| te.shiftKey = e.shiftKey; |
| e.srcElement.fireEvent('onkeypress', te); |
| } |
| } |
| }, |
| |
| _layoutHackIE7: function(){ |
| // summary: |
| // Work around table sizing bugs on IE7 by forcing redraw |
| |
| if(dojo.isIE == 7){ // fix IE7 layout bug when the widget is scrolled out of sight |
| var domNode = this.domNode; |
| var parent = domNode.parentNode; |
| var pingNode = domNode.firstChild || domNode; // target node most unlikely to have a custom filter |
| var origFilter = pingNode.style.filter; // save custom filter, most likely nothing |
| while(parent && parent.clientHeight == 0){ // search for parents that haven't rendered yet |
| parent._disconnectHandle = this.connect(parent, "onscroll", dojo.hitch(this, function(e){ |
| this.disconnect(parent._disconnectHandle); // only call once |
| parent.removeAttribute("_disconnectHandle"); // clean up DOM node |
| pingNode.style.filter = (new Date()).getMilliseconds(); // set to anything that's unique |
| setTimeout(function(){ pingNode.style.filter = origFilter }, 0); // restore custom filter, if any |
| })); |
| parent = parent.parentNode; |
| } |
| } |
| } |
| }); |
| |
| } |
| |
| if(!dojo._hasResource["dijit.dijit"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dijit.dijit"] = true; |
| dojo.provide("dijit.dijit"); |
| |
| /*===== |
| dijit.dijit = { |
| // summary: |
| // A roll-up for common dijit methods |
| // description: |
| // A rollup file for the build system including the core and common |
| // dijit files. |
| // |
| // example: |
| // | <script type="text/javascript" src="js/dojo/dijit/dijit.js"></script> |
| // |
| }; |
| =====*/ |
| |
| // All the stuff in _base (these are the function that are guaranteed available without an explicit dojo.require) |
| |
| |
| // And some other stuff that we tend to pull in all the time anyway |
| |
| |
| |
| |
| |
| |
| |
| } |
| |