diff options
Diffstat (limited to 'includes/js/dijit/dijit.js.uncompressed.js')
-rw-r--r-- | includes/js/dijit/dijit.js.uncompressed.js | 3641 |
1 files changed, 3641 insertions, 0 deletions
diff --git a/includes/js/dijit/dijit.js.uncompressed.js b/includes/js/dijit/dijit.js.uncompressed.js new file mode 100644 index 0000000..0d91587 --- /dev/null +++ b/includes/js/dijit/dijit.js.uncompressed.js @@ -0,0 +1,3641 @@ +/* + Copyright (c) 2004-2008, The Dojo Foundation + All Rights Reserved. + + Licensed under the Academic Free License version 2.1 or above OR the + modified BSD license. For more information on Dojo licensing, see: + + http://dojotoolkit.org/book/dojo-book-0-9/introduction/licensing +*/ + +/* + 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.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"); + +// summary: +// These functions are used to query or set the focus and selection. +// +// Also, they trace when widgets become actived/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: tests whether the current selection is empty + var _window = dojo.global; + var _document = dojo.doc; + if(_document.selection){ // IE + return !_document.selection.createRange().text; // Boolean + }else{ + var selection = _window.getSelection(); + if(dojo.isString(selection)){ // Safari + return !selection; // Boolean + }else{ // Mozilla/W3 + return selection.isCollapsed || !selection.toString(); // Boolean + } + } + }, + + getBookmark: function(){ + // summary: Retrieves a bookmark that can be used with moveToBookmark to return to the same range + var bookmark, selection = dojo.doc.selection; + if(selection){ // IE + var range = selection.createRange(); + if(selection.type.toUpperCase()=='CONTROL'){ + if(range.length){ + bookmark=[]; + var i=0,len=range.length; + while(i<len){ + bookmark.push(range.item(i++)); + } + }else{ + bookmark=null; + } + }else{ + bookmark = range.getBookmark(); + } + }else{ + if(window.getSelection){ + selection = dojo.global.getSelection(); + if(selection){ + range = selection.getRangeAt(0); + bookmark = range.cloneRange(); + } + }else{ + console.warn("No idea how to store the current selection for this browser!"); + } + } + return bookmark; // Array + }, + + moveToBookmark: function(/*Object*/bookmark){ + // summary: Moves current selection to a bookmark + // bookmark: This should be a returned object from dojo.html.selection.getBookmark() + var _document = dojo.doc; + if(_document.selection){ // IE + var range; + if(dojo.isArray(bookmark)){ + range = _document.body.createControlRange(); + dojo.forEach(bookmark, "range.addElement(item)"); //range.addElement does not have call/apply method, so can not call it directly + }else{ + range = _document.selection.createRange(); + range.moveToBookmark(bookmark); + } + range.select(); + }else{ //Moz/W3C + var selection = dojo.global.getSelection && dojo.global.getSelection(); + if(selection && selection.removeAllRanges){ + selection.removeAllRanges(); + selection.addRange(bookmark); + }else{ + console.warn("No idea how to restore selection for this browser!"); + } + } + }, + + getFocus: function(/*Widget?*/menu, /*Window?*/openedForWindow){ + // summary: + // Returns the current focus and selection. + // Called when a popup appears (either a top level menu or a dialog), + // or when a toolbar/menubar receives focus + // + // menu: + // The menu that's being opened + // + // openedForWindow: + // iframe in which menu was opened + // + // returns: + // A handle to restore focus/selection + + return { + // Node to return focus to + node: menu && dojo.isDescendant(dijit._curFocus, menu.domNode) ? dijit._prevFocus : dijit._curFocus, + + // Previously selected text + bookmark: + !dojo.withGlobal(openedForWindow||dojo.global, dijit.isCollapsed) ? + dojo.withGlobal(openedForWindow||dojo.global, dijit.getBookmark) : + null, + + 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; + + // 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) + if(bookmark && dojo.withGlobal(openedForWindow||dojo.global, dijit.isCollapsed)){ + if(openedForWindow){ + openedForWindow.focus(); + } + try{ + dojo.withGlobal(openedForWindow||dojo.global, dijit.moveToBookmark, null, [bookmark]); + }catch(e){ + /*squelch IE internal error, see http://trac.dojotoolkit.org/ticket/1984 */ + } + } + }, + + // _activeStack: Array + // List of currently active widgets (focused widget and it's ancestors) + _activeStack: [], + + registerWin: function(/*Window?*/targetWindow){ + // summary: + // Registers listeners on the specified window (either the main + // window or an iframe) to detect when the user has clicked somewhere. + // Anyone that creates an iframe should call this function. + + if(!targetWindow){ + targetWindow = window; + } + + dojo.connect(targetWindow.document, "onmousedown", function(evt){ + dijit._justMouseDowned = true; + setTimeout(function(){ dijit._justMouseDowned = false; }, 0); + dijit._onTouchNode(evt.target||evt.srcElement); + }); + //dojo.connect(targetWindow, "onscroll", ???); + + // Listen for blur and focus events on targetWindow's body + var body = targetWindow.document.body || targetWindow.document.getElementsByTagName("body")[0]; + if(body){ + if(dojo.isIE){ + body.attachEvent('onactivate', function(evt){ + if(evt.srcElement.tagName.toLowerCase() != "body"){ + dijit._onFocusNode(evt.srcElement); + } + }); + body.attachEvent('ondeactivate', function(evt){ dijit._onBlurNode(evt.srcElement); }); + }else{ + body.addEventListener('focus', function(evt){ dijit._onFocusNode(evt.target); }, true); + body.addEventListener('blur', function(evt){ dijit._onBlurNode(evt.target); }, true); + } + } + body = null; // prevent memory leak (apparent circular reference via closure) + }, + + _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){ + // summary: + // Callback when node is focused or mouse-downed + + // 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){ + if(node.dijitPopupParent){ + node=dijit.byId(node.dijitPopupParent).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); + }, + + _onFocusNode: function(/*DomNode*/ node){ + // summary + // Callback when node is focused + if(node && node.tagName && node.tagName.toLowerCase() == "body"){ + 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(newStack){ + // summary + // The stack of active widgets has changed. Send out appropriate events and record new stack + + 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; + } + } + + // for all elements that have gone out of focus, send blur event + for(var i=oldStack.length-1; i>=nCommon; i--){ + var widget = dijit.byId(oldStack[i]); + if(widget){ + widget._focused = false; + widget._hasBeenBlurred = true; + if(widget._onBlur){ + widget._onBlur(); + } + if (widget._setStateClass){ + widget._setStateClass(); + } + dojo.publish("widgetBlur", [widget]); + } + } + + // 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(); + } + if (widget._setStateClass){ + widget._setStateClass(); + } + dojo.publish("widgetFocus", [widget]); + } + } + } +}); + +// register top window and all the iframes it contains +dojo.addOnLoad(dijit.registerWin); + +} + +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 + + constructor: function(){ + this._hash={}; + }, + + add: function(/*Widget*/ widget){ + 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; + }, + + remove: function(/*String*/ id){ + delete this._hash[id]; + }, + + forEach: function(/*Function*/ func){ + for(var id in this._hash){ + func(this._hash[id]); + } + }, + + filter: function(/*Function*/ filter){ + var res = new dijit.WidgetSet(); + this.forEach(function(widget){ + if(filter(widget)){ res.add(widget); } + }); + return res; // dijit.WidgetSet + }, + + byId: function(/*String*/ id){ + return this._hash[id]; + }, + + byClass: function(/*String*/ cls){ + return this.filter(function(widget){ return widget.declaredClass==cls; }); // dijit.WidgetSet + } + }); + +/*===== +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 id; // String +}; + + +if(dojo.isIE){ + // Only run this 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.addOnUnload(function(){ + dijit.registry.forEach(function(widget){ widget.destroy(); }); + }); +} + +dijit.byId = function(/*String|Widget*/id){ + // summary: + // Returns a widget by its id, or if passed a widget, no-op (like dojo.byId()) + return (dojo.isString(id)) ? dijit.registry.byId(id) : id; // Widget +}; + +dijit.byNode = function(/* DOMNode */ node){ + // summary: + // Returns the widget as referenced by node + return dijit.registry.byId(node.getAttribute("widgetId")); // Widget +}; + +dijit.getEnclosingWidget = function(/* DOMNode */ node){ + // summary: + // Returns the widget whose dom tree contains node or null if + // the node is not contained within the dom tree of any widget + while(node){ + if(node.getAttribute && node.getAttribute("widgetId")){ + return dijit.registry.byId(node.getAttribute("widgetId")); + } + node = node.parentNode; + } + return null; +}; + +// elements that are tab-navigable if they have no tabindex value set +// (except for "a", which must have an href attribute) +dijit._tabElements = { + area: true, + button: true, + input: true, + object: true, + select: true, + textarea: true +}; + +dijit._isElementShown = function(/*Element*/elem){ + var style = dojo.style(elem); + return (style.visibility != "hidden") + && (style.visibility != "collapsed") + && (style.display != "none"); +} + +dijit.isTabNavigable = function(/*Element*/elem){ + // summary: + // Tests if an element is tab-navigable + if(dojo.hasAttr(elem, "disabled")){ return false; } + var hasTabindex = dojo.hasAttr(elem, "tabindex"); + var tabindex = dojo.attr(elem, "tabindex"); + if(hasTabindex && tabindex >= 0) { + return true; // boolean + } + var name = elem.nodeName.toLowerCase(); + if(((name == "a" && dojo.hasAttr(elem, "href")) + || dijit._tabElements[name]) + && (!hasTabindex || tabindex >= 0)){ + return true; // boolean + } + return false; // boolean +}; + +dijit._getTabNavigable = function(/*DOMNode*/root){ + // summary: + // 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){ 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; // Element +}; + +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; // Element +}; + +} + +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 _window = dojo.global; + var _document = dojo.doc; + + // get viewport size + var w = 0, h = 0; + var de = _document.documentElement; + var dew = de.clientWidth, deh = de.clientHeight; + if(dojo.isMozilla){ + // mozilla + // _window.innerHeight includes the height taken by the scroll bar + // clientHeight is ideal but has DTD issues: + // #4539: FF reverses the roles of body.clientHeight/Width and documentElement.clientHeight/Width based on the DTD! + // check DTD to see whether body or documentElement returns the viewport dimensions using this algorithm: + var minw, minh, maxw, maxh; + var dbw = _document.body.clientWidth; + if(dbw > dew){ + minw = dew; + maxw = dbw; + }else{ + maxw = dew; + minw = dbw; + } + var dbh = _document.body.clientHeight; + if(dbh > deh){ + minh = deh; + maxh = dbh; + }else{ + maxh = deh; + minh = dbh; + } + w = (maxw > _window.innerWidth) ? minw : maxw; + h = (maxh > _window.innerHeight) ? minh : maxh; + }else if(!dojo.isOpera && _window.innerWidth){ + //in opera9, dojo.body().clientWidth should be used, instead + //of window.innerWidth/document.documentElement.clientWidth + //so we have to check whether it is opera + w = _window.innerWidth; + h = _window.innerHeight; + }else if(dojo.isIE && de && deh){ + w = dew; + h = deh; + }else if(dojo.body().clientWidth){ + // IE5, Opera + w = dojo.body().clientWidth; + h = dojo.body().clientHeight; + } + + // get scroll position + var scroll = dojo._docScroll(); + + return { w: w, h: h, l: scroll.x, t: scroll.y }; // object +}; + +dijit.placeOnScreen = function( + /* DomNode */ node, + /* Object */ pos, + /* Object */ corners, + /* boolean? */ tryOnly){ + // summary: + // Keeps 'node' in the visible area of the screen while trying to + // place closest to pos.x, pos.y. The input coordinates are + // expected to be the desired document position. + // + // Set which corner(s) you want to bind to, such as + // + // placeOnScreen(node, {x: 10, y: 20}, ["TR", "BL"]) + // + // The desired x/y will be treated as the topleft(TL)/topright(TR) or + // BottomLeft(BL)/BottomRight(BR) corner of the node. Each corner is tested + // and if a perfect match is found, it will be used. Otherwise, it goes through + // all of the specified corners, and choose the most appropriate one. + // + // NOTE: node is assumed to be absolutely or relatively positioned. + + var choices = dojo.map(corners, function(corner){ return { corner: corner, pos: pos }; }); + + 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 = (corner.charAt(1) == 'L' ? pos.x : Math.max(view.l, pos.x - mb.w)), + startY = (corner.charAt(0) == 'T' ? pos.y : Math.max(view.t, pos.y - mb.h)), + endX = (corner.charAt(1) == 'L' ? Math.min(view.l + view.w, startX + mb.w) : pos.x), + endY = (corner.charAt(0) == 'T' ? Math.min(view.t + view.h, 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.placeOnScreenAroundElement = function( + /* DomNode */ node, + /* DomNode */ aroundNode, + /* Object */ aroundCorners, + /* Function */ layoutNode){ + + // summary + // Like placeOnScreen, except it accepts aroundNode instead of x,y + // and attempts to place node around it. Uses margin box dimensions. + // + // aroundCorners + // specify Which corner of aroundNode should be + // used to place the node => which corner(s) of node to use (see the + // corners parameter in dijit.placeOnScreen) + // e.g. {'TL': 'BL', 'BL': 'TL'} + // + // 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 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 aroundNodeW = aroundNode.offsetWidth; //mb.w; + var aroundNodeH = aroundNode.offsetHeight; //mb.h; + var aroundNodePos = dojo.coords(aroundNode, true); + aroundNode.style.display=oldDisplay; + + // Generate list of possible positions for node + var choices = []; + for(var nodeCorner in aroundCorners){ + choices.push( { + aroundCorner: nodeCorner, + corner: aroundCorners[nodeCorner], + pos: { + x: aroundNodePos.x + (nodeCorner.charAt(1) == 'L' ? 0 : aroundNodeW), + y: aroundNodePos.y + (nodeCorner.charAt(0) == 'T' ? 0 : aroundNodeH) + } + }); + } + + return dijit._place(node, choices, layoutNode); +} + +} + +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"); + +dijit.getDocumentWindow = function(doc){ + // summary + // Get window object associated with document doc + + // With Safari, there is not way to retrieve the window from the document, so we must fix it. + if(dojo.isSafari && !doc._parentWindow){ + /* + This is a Safari specific function that fix the reference to the parent + window from the document object. + TODO: #5711: should the use of document below reference dojo.doc instead + in case they're not the same? + */ + var fix=function(win){ + win.document._parentWindow=win; + for(var i=0; i<win.frames.length; i++){ + fix(win.frames[i]); + } + } + fix(window.top); + } + + //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 + //TODO: #5711: should the use of document below reference dojo.doc instead in case they're not the same? + 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.prepare = function(/*DomNode*/ node){ + // summary: + // Prepares a node to be used as a popup + // + // 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 + + dojo.body().appendChild(node); + var s = node.style; + if(s.display == "none"){ + s.display=""; + } + s.visibility = "hidden"; // not needed for hiding, but used as flag that node is off-screen + s.position = "absolute"; + s.top = "-9999px"; + }; + + this.open = function(/*Object*/ args){ + // summary: + // Popup the widget at the specified position + // + // args: Object + // 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 + // orient: Object + // structure specifying possible positions of popup relative to "around" node + // 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); + // ie: 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) + // + // examples: + // 1. opening at the mouse position + // dijit.popup.open({popup: menuWidget, x: evt.pageX, y: evt.pageY}); + // 2. 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 it's 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 || {'BL':'TL', '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 wrapper = dojo.doc.createElement("div"); + dijit.setWaiRole(wrapper, "presentation"); + wrapper.id = id; + wrapper.className="dijitPopup"; + wrapper.style.zIndex = beginZIndex + stack.length; + wrapper.style.visibility = "hidden"; + if(args.parent){ + wrapper.dijitPopupParent=args.parent.id; + } + dojo.body().appendChild(wrapper); + + var s = widget.domNode.style; + s.display = ""; + s.visibility = ""; + s.position = ""; + wrapper.appendChild(widget.domNode); + + var iframe = new dijit.BackgroundIframe(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']); + + wrapper.style.visibility = "visible"; + // TODO: use effects to fade in wrapper + + var handlers = []; + + // 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]; + } + + // 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.keyCode == dojo.keys.ESCAPE && args.onCancel){ + dojo.stopEvent(evt); + args.onCancel(); + }else if(evt.keyCode == 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", null, args.onCancel)); + } + + handlers.push(dojo.connect(widget, widget.onExecute ? "onExecute" : "onChange", null, 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){ + widget.onOpen(best); + } + + return best; + }; + + this.close = function(/*Widget*/ popup){ + // summary: + // Close specified popup and any popups that it parented + 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){ + widget.onClose(); + } + dojo.forEach(top.handlers, dojo.disconnect); + + // #2685: check if the widget still has a domNode so ContentPane can change its URL without getting an error + if(!widget||!widget.domNode){ return; } + + this.prepare(widget.domNode); + + iframe.destroy(); + dojo._destroyElement(wrapper); + + 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 html="<iframe src='javascript:\"\"'" + + " style='position: absolute; left: 0px; top: 0px;" + + "z-index: -1; filter:Alpha(Opacity=\"0\");'>"; + iframe = dojo.doc.createElement(html); + }else{ + iframe = dojo.doc.createElement("iframe"); + iframe.src = 'javascript:""'; + iframe.className = "dijitBackgroundIframe"; + } + iframe.tabIndex = -1; // Magic to prevent iframe from getting focus on tab keypress - as style didnt work. + dojo.body().appendChild(iframe); + } + return iframe; + }; + + this.push = function(iframe){ + iframe.style.display=""; + if(dojo.isIE){ + iframe.style.removeExpression("width"); + iframe.style.removeExpression("height"); + } + queue.push(iframe); + } +}(); + +// fill the queue +if(dojo.isIE && dojo.isIE < 7){ + dojo.addOnLoad(function(){ + var f = dijit._frames; + dojo.forEach([f.pop()], f.push); + }); +} + + +dijit.BackgroundIframe = function(/* DomNode */node){ + // summary: + // For IE 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.isIE < 7) || (dojo.isFF && dojo.isFF < 3 && dojo.hasClass(dojo.body(), "dijit_a11y"))){ + var iframe = dijit._frames.pop(); + node.appendChild(iframe); + if(dojo.isIE){ + iframe.style.setExpression("width", dojo._scopeName + ".doc.getElementById('" + node.id + "').offsetWidth"); + iframe.style.setExpression("height", dojo._scopeName + ".doc.getElementById('" + node.id + "').offsetHeight"); + } + this.iframe = iframe; + } +}; + +dojo.extend(dijit.BackgroundIframe, { + destroy: function(){ + // summary: destroy the iframe + 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){ + // summary + // Scroll the passed node into view, if it is not. + + // don't rely on that node.scrollIntoView works just because the function is there + // it doesnt work in Konqueror or Opera even though the function is there and probably + // not safari either + // native scrollIntoView() causes FF3's whole window to scroll if there is no scroll bar + // on the immediate parent + // dont like browser sniffs implementations but sometimes you have to use it + // #6146: IE scrollIntoView is broken + // It's not enough just to scroll the menu node into view if + // node.scrollIntoView hides part of the parent's scrollbar, + // so just manage the parent scrollbar ourselves + var parent = node.parentNode; + var parentBottom = parent.scrollTop + dojo.marginBox(parent).h; //PORT was getBorderBox + var nodeBottom = node.offsetTop + dojo.marginBox(node).h; + if(parentBottom < nodeBottom){ + parent.scrollTop += (nodeBottom - parentBottom); + }else if(parent.scrollTop > node.offsetTop){ + parent.scrollTop -= (parent.scrollTop - node.offsetTop); + } +}; + +} + +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; +dojo.provide("dijit._base.sniff"); + +// ported from dojo.html.applyBrowserClass (style.js) + +// summary: +// Applies pre-set class names based on browser & version to the +// top-level HTML node. Simply doing a require on this module will +// establish this CSS. Modified version of Morris' CSS hack. +(function(){ + var d = dojo; + var ie = d.isIE; + var opera = d.isOpera; + var maj = Math.floor; + var ff = d.isFF; + var classes = { + dj_ie: ie, +// dj_ie55: ie == 5.5, + dj_ie6: maj(ie) == 6, + dj_ie7: maj(ie) == 7, + dj_iequirks: ie && d.isQuirks, +// NOTE: Opera not supported by dijit + dj_opera: opera, + dj_opera8: maj(opera) == 8, + dj_opera9: maj(opera) == 9, + dj_khtml: d.isKhtml, + dj_safari: d.isSafari, + dj_gecko: d.isMozilla, + dj_ff2: maj(ff) == 2 + }; // no dojo unsupported browsers + + for(var p in classes){ + if(classes[p]){ + var html = dojo.doc.documentElement; //TODO browser-specific DOM magic needed? + if(html.className){ + html.className += " " + p; + }else{ + html.className = p; + } + } + } +})(); + +} + +if(!dojo._hasResource["dijit._base.bidi"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dijit._base.bidi"] = true; +dojo.provide("dijit._base.bidi"); + +// summary: applies a class to the top of the document for right-to-left stylesheet rules + +dojo.addOnLoad(function(){ + if(!dojo._isBodyLtr()){ + dojo.addClass(dojo.body(), "dijitRtl"); + } +}); + +} + +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); + this._currentTimeout = (this._currentTimeout < 0) ? this._initialDelay : ((this._subsequentDelay > 1) ? this._subsequentDelay : Math.round(this._currentTimeout * this._subsequentDelay)); + 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. + // Parameters: + // 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. + // keyObject: an object defining the key to listen for. + // key: (mandatory) the keyCode (number) or character (string) 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 + // See the trigger method for other parameters. + // Returns an array of dojo.connect handles + return [ + dojo.connect(node, "onkeypress", this, function(evt){ + if(evt.keyCode == keyObject.keyCode && (!keyObject.charCode || keyObject.charCode == evt.charCode) && + (keyObject.ctrlKey === undefined || keyObject.ctrlKey == evt.ctrlKey) && + (keyObject.altKey === undefined || keyObject.altKey == evt.ctrlKey) && + (keyObject.shiftKey === undefined || keyObject.shiftKey == evt.ctrlKey)){ + 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. + // mouseNode: the DOM node object to listen on for mouse events. + // keyNode: the DOM node object to listen on for key events. + // See the addMouseListener and addKeyListener methods for other parameters. + // 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.doc.createElement("div"); + div.id = "a11yTestNode"; + div.style.cssText = 'border: 1px solid;' + + 'border-color:red green;' + + 'position: absolute;' + + 'height: 5px;' + + 'top: -999px;' + + 'background-image: url("' + dojo.moduleUrl("dojo", "resources/blank.gif") + '");'; + dojo.body().appendChild(div); + + // 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"); + 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, +{ + hasWaiRole: function(/*Element*/ elem){ + // summary: Determines if an element has a role. + // returns: true if elem has a role attribute and false if not. + return elem.hasAttribute ? elem.hasAttribute("role") : !!elem.getAttribute("role"); + }, + + getWaiRole: function(/*Element*/ elem){ + // summary: Gets the role for an element. + // returns: + // The role of elem or an empty string if elem + // does not have a role. + var value = elem.getAttribute("role"); + if(value){ + var prefixEnd = value.indexOf(":"); + return prefixEnd == -1 ? value : value.substring(prefixEnd+1); + }else{ + return ""; + } + }, + + setWaiRole: function(/*Element*/ elem, /*String*/ role){ + // summary: Sets the role on an element. + // description: + // On Firefox 2 and below, "wairole:" is + // prepended to the provided role value. + elem.setAttribute("role", (dojo.isFF && dojo.isFF < 3) ? "wairole:" + role : role); + }, + + removeWaiRole: function(/*Element*/ elem){ + // summary: Removes the role from an element. + elem.removeAttribute("role"); + }, + + hasWaiState: function(/*Element*/ elem, /*String*/ state){ + // summary: Determines if an element has a given state. + // description: + // On Firefox 2 and below, we check for an attribute in namespace + // "http://www.w3.org/2005/07/aaa" with a name of the given state. + // On all other browsers, we check for an attribute + // called "aria-"+state. + // returns: + // true if elem has a value for the given state and + // false if it does not. + if(dojo.isFF && dojo.isFF < 3){ + return elem.hasAttributeNS("http://www.w3.org/2005/07/aaa", state); + }else{ + 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: + // On Firefox 2 and below, we check for an attribute in namespace + // "http://www.w3.org/2005/07/aaa" with a name of the given state. + // On all other browsers, we check 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. + if(dojo.isFF && dojo.isFF < 3){ + return elem.getAttributeNS("http://www.w3.org/2005/07/aaa", state); + }else{ + var value = elem.getAttribute("aria-"+state); + return value ? value : ""; + } + }, + + setWaiState: function(/*Element*/ elem, /*String*/ state, /*String*/ value){ + // summary: Sets a state on an element. + // description: + // On Firefox 2 and below, we set an attribute in namespace + // "http://www.w3.org/2005/07/aaa" with a name of the given state. + // On all other browsers, we set an attribute called + // "aria-"+state. + if(dojo.isFF && dojo.isFF < 3){ + elem.setAttributeNS("http://www.w3.org/2005/07/aaa", + "aaa:"+state, value); + }else{ + elem.setAttribute("aria-"+state, value); + } + }, + + removeWaiState: function(/*Element*/ elem, /*String*/ state){ + // summary: Removes a state from an element. + // description: + // On Firefox 2 and below, we remove the attribute in namespace + // "http://www.w3.org/2005/07/aaa" with a name of the given state. + // On all other browsers, we remove the attribute called + // "aria-"+state. + if(dojo.isFF && dojo.isFF < 3){ + elem.removeAttributeNS("http://www.w3.org/2005/07/aaa", state); + }else{ + 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"); + + + + + + + + + + + + +// FIXME: Find a better way of solving this bug! +if(dojo.isSafari){ + // Ugly-ass hack to solve bug #5626 for 1.1; basically force Safari to re-layout. + // Note that we can't reliably use dojo.addOnLoad here because this bug is basically + // a timing / race condition; so instead we use window.onload. + dojo.connect(window, "load", function(){ + window.resizeBy(1,0); + setTimeout(function(){ window.resizeBy(-1,0); }, 10); + }); +} + +} + +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); + var 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); +// result.setFullYear(match[0]||1970); // for year < 100 + + var offset = 0; + var 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 = []; + var getter = options.zulu ? "getUTC" : "get"; + var 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; + var dtName = d._scopeName + "Type"; + var qry = "[" + dtName + "]"; + + 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){ + // TODO: "this" here won't work + value = d.parser._nameAnonFunc(new Function(value), this); + } + return d.getObject(value, false); + }catch(e){ return new Function(); } + case "array": + return 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"} } + }; + + function getClassInfo(/*String*/ className){ + // className: + // fully qualified name (like "dijit.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={}; + for(var name in proto){ + if(name.charAt(0)=="_"){ continue; } // skip internal properties + 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){ + // 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 + var thelist = []; + d.forEach(nodes, function(node){ + if(!node){ return; } + var type = node.getAttribute(dtName); + if((!type)||(!type.length)){ return; } + var clsInfo = getClassInfo(type); + var clazz = clsInfo.cls; + var ps = clazz._noScript||clazz.prototype._noScript; + + // read parameters (ie, attributes). + // clsInfo.params lists expected params like {"checked": "boolean", "n": "number"} + var params = {}; + var attributes = node.attributes; + for(var name in clsInfo.params){ + var item = 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 = node.className; + break; + case "style": + value = node.style && node.style.cssText; // FIXME: Opera? + } + var _type = clsInfo.params[name]; + params[name] = str2obj(value, _type); + } + + // 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"]; + if(!markupFactory && clazz["prototype"]){ + markupFactory = 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 + d.forEach(thelist, function(instance){ + if( instance && + instance.startup && + !instance._started && + (!instance.getParent || !instance.getParent()) + ){ + instance.startup(); + } + }); + return thelist; + }; + + this.parse = function(/*DomNode?*/ rootNode){ + // summary: + // Search specified node (or root node) recursively for class instances, + // and instantiate them Searches for + // dojoType="qualified.class.name" + var list = d.query(qry, rootNode); + // go build the object instances + var instances = this.instantiate(list); + return instances; + }; +}(); + +//Register the parser callback. It should be the first callback +//after the a11y test. + +(function(){ + var parseRunner = function(){ + if(dojo.config["parseOnLoad"] == true){ + 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); + } +})(); + +//TODO: ported from 0.4.x Dojo. Can we reduce this? +dojo.parser._anonCtr = 0; +dojo.parser._anon = {}; // why is this property required? +dojo.parser._nameAnonFunc = function(/*Function*/anonFuncPtr, /*Object*/thisObj){ + // summary: + // Creates a reference to anonFuncPtr in thisObj with a completely + // unique name. The new name is returned as a String. + var jpn = "$joinpoint"; + var nso = (thisObj|| dojo.parser._anon); + if(dojo.isIE){ + var cn = anonFuncPtr["__dojoNameCache"]; + if(cn && nso[cn] === anonFuncPtr){ + return anonFuncPtr["__dojoNameCache"]; + } + } + var ret = "__"+dojo.parser._anonCtr++; + while(typeof nso[ret] != "undefined"){ + ret = "__"+dojo.parser._anonCtr++; + } + nso[ret] = anonFuncPtr; + return ret; // String +} + +} + +if(!dojo._hasResource["dijit._Widget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dijit._Widget"] = true; +dojo.provide("dijit._Widget"); + +dojo.require( "dijit._base" ); + +dojo.declare("dijit._Widget", null, { + // summary: + // The foundation of dijit widgets. + // + // id: String + // a unique, opaque ID string that can be assigned by users or by the + // system. If the developer passes an ID which is known not to be + // unique, the specified ID is ignored and the system-generated ID is + // used instead. + id: "", + + // lang: String + // Rarely used. Overrides the default Dojo locale used to render this widget, + // as defined by the [HTML LANG](http://www.w3.org/TR/html401/struct/dirlang.html#adef-lang) attribute. + // Value must be among the list of locales specified during by the Dojo bootstrap, + // formatted according to [RFC 3066](http://www.ietf.org/rfc/rfc3066.txt) (like en-us). + lang: "", + + // dir: String + // Unsupported by Dijit, but here for completeness. Dijit only supports setting text direction on the + // entire document. + // Bi-directional support, as defined by the [HTML DIR](http://www.w3.org/TR/html401/struct/dirlang.html#adef-dir) + // attribute. Either left-to-right "ltr" or right-to-left "rtl". + dir: "", + + // class: String + // HTML class attribute + "class": "", + + // style: String + // HTML style attribute + style: "", + + // title: String + // HTML title attribute + title: "", + + // srcNodeRef: DomNode + // pointer to original dom node + srcNodeRef: null, + + // domNode: DomNode + // this is our visible representation of the widget! Other DOM + // Nodes may by assigned to other properties, usually through the + // template system's dojoAttachPonit syntax, but the domNode + // property is the canonical "top level" node in widget UI. + domNode: null, + + // attributeMap: Object + // A map of attributes and attachpoints -- typically standard HTML attributes -- to set + // on the widget's dom, at the "domNode" attach point, by default. + // Other node references can be specified as properties of 'this' + attributeMap: {id:"", dir:"", lang:"", "class":"", style:"", title:""}, // TODO: add on* handlers? + + //////////// INITIALIZATION METHODS /////////////////////////////////////// +//TODOC: params and srcNodeRef need docs. Is srcNodeRef optional? +//TODOC: summary needed for postscript + postscript: function(/*Object?*/params, /*DomNode|String*/srcNodeRef){ + this.create(params, srcNodeRef); + }, + + create: function(/*Object?*/params, /*DomNode|String*/srcNodeRef){ + // summary: + // Kick off the life-cycle of a widget + // description: + // To understand the process by which widgets are instantiated, it + // is critical to understand what other methods create calls and + // which of them you'll want to override. Of course, adventurous + // developers could override create entirely, but this should + // only be done as a last resort. + // + // Below is a list of the methods that are called, in the order + // they are fired, along with notes about what they do and if/when + // you should over-ride them in your widget: + // + // * postMixInProperties: + // | * a stub function that you can over-ride to modify + // variables that may have been naively assigned by + // mixInProperties + // * widget is added to manager object here + // * buildRendering: + // | * Subclasses use this method to handle all UI initialization + // Sets this.domNode. Templated widgets do this automatically + // and otherwise it just uses the source dom node. + // * postCreate: + // | * a stub function that you can over-ride to modify take + // actions once the widget has been placed in the UI + + // store pointer to original dom tree + this.srcNodeRef = dojo.byId(srcNodeRef); + + // For garbage collection. An array of handles returned by Widget.connect() + // Each handle returned from Widget.connect() is an array of handles from dojo.connect() + this._connects=[]; + + // _attaches: String[] + // names of all our dojoAttachPoint variables + this._attaches=[]; + + //mixin our passed parameters + if(this.srcNodeRef && (typeof this.srcNodeRef.id == "string")){ this.id = this.srcNodeRef.id; } + if(params){ + this.params = params; + dojo.mixin(this,params); + } + this.postMixInProperties(); + + // generate an id for the widget if one wasn't specified + // (be sure to do this before buildRendering() because that function might + // expect the id to be there. + if(!this.id){ + this.id=dijit.getUniqueId(this.declaredClass.replace(/\./g,"_")); + } + dijit.registry.add(this); + + this.buildRendering(); + + // Copy attributes listed in attributeMap into the [newly created] DOM for the widget. + // The placement of these attributes is according to the property mapping in attributeMap. + // Note special handling for 'style' and 'class' attributes which are lists and can + // have elements from both old and new structures, and some attributes like "type" + // cannot be processed this way as they are not mutable. + if(this.domNode){ + for(var attr in this.attributeMap){ + var value = this[attr]; + if(typeof value != "object" && ((value !== "" && value !== false) || (params && params[attr]))){ + this.setAttribute(attr, value); + } + } + } + + if(this.domNode){ + this.domNode.setAttribute("widgetId", this.id); + } + this.postCreate(); + + // If srcNodeRef has been processed and removed from the DOM (e.g. TemplatedWidget) then delete it to allow GC. + if(this.srcNodeRef && !this.srcNodeRef.parentNode){ + delete this.srcNodeRef; + } + }, + + postMixInProperties: function(){ + // summary + // Called after the parameters to the widget have been read-in, + // but before the widget template is instantiated. + // Especially useful to set properties that are referenced in the widget template. + }, + + buildRendering: function(){ + // summary: + // Construct the UI for this widget, setting this.domNode. + // Most widgets will mixin TemplatedWidget, which overrides this method. + this.domNode = this.srcNodeRef || dojo.doc.createElement('div'); + }, + + postCreate: function(){ + // summary: + // Called after a widget's dom has been setup + }, + + startup: function(){ + // summary: + // Called after a widget's children, and other widgets on the page, have been created. + // Provides an opportunity to manipulate any children before they are displayed. + // This is useful for composite widgets that need to control or layout sub-widgets. + // Many layout widgets can use this as a wiring phase. + this._started = true; + }, + + //////////// DESTROY FUNCTIONS //////////////////////////////// + + destroyRecursive: function(/*Boolean*/ finalize){ + // summary: + // Destroy this widget and it's descendants. This is the generic + // "destructor" function that all widget users should call to + // cleanly discard with a widget. Once a widget is destroyed, it's + // removed from the manager object. + // finalize: Boolean + // is this function being called part of global environment + // tear-down? + + this.destroyDescendants(); + this.destroy(); + }, + + destroy: function(/*Boolean*/ finalize){ + // summary: + // Destroy this widget, but not its descendants + // finalize: Boolean + // is this function being called part of global environment + // tear-down? + + this.uninitialize(); + dojo.forEach(this._connects, function(array){ + dojo.forEach(array, dojo.disconnect); + }); + + // destroy widgets created as part of template, etc. + dojo.forEach(this._supportingWidgets || [], function(w){ w.destroy(); }); + + this.destroyRendering(finalize); + dijit.registry.remove(this.id); + }, + + destroyRendering: function(/*Boolean*/ finalize){ + // summary: + // Destroys the DOM nodes associated with this widget + // finalize: Boolean + // is this function being called part of global environment + // tear-down? + + if(this.bgIframe){ + this.bgIframe.destroy(); + delete this.bgIframe; + } + + if(this.domNode){ + dojo._destroyElement(this.domNode); + delete this.domNode; + } + + if(this.srcNodeRef){ + dojo._destroyElement(this.srcNodeRef); + delete this.srcNodeRef; + } + }, + + destroyDescendants: function(){ + // summary: + // Recursively destroy the children of this widget and their + // descendants. + + // TODO: should I destroy in the reverse order, to go bottom up? + dojo.forEach(this.getDescendants(), function(widget){ widget.destroy(); }); + }, + + uninitialize: function(){ + // summary: + // stub function. Override to implement custom widget tear-down + // behavior. + return false; + }, + + ////////////////// MISCELLANEOUS METHODS /////////////////// + + onFocus: function(){ + // summary: + // stub function. Override or connect to this method to receive + // notifications for when the widget moves into focus. + }, + + onBlur: function(){ + // summary: + // stub function. Override or connect to this method to receive + // notifications for when the widget moves out of focus. + }, + + _onFocus: function(e){ + this.onFocus(); + }, + + _onBlur: function(){ + this.onBlur(); + }, + + setAttribute: function(/*String*/ attr, /*anything*/ value){ + // summary + // Set native HTML attributes reflected in the widget, + // such as readOnly, disabled, and maxLength in TextBox widgets. + // description + // In general, a widget's "value" is controlled via setValue()/getValue(), + // rather than this method. The exception is for widgets where the + // end user can't adjust the value, such as Button and CheckBox; + // in the unusual case that you want to change the value attribute of + // those widgets, use setAttribute(). + var mapNode = this[this.attributeMap[attr]||'domNode']; + this[attr] = value; + switch(attr){ + case "class": + dojo.addClass(mapNode, value); + break; + case "style": + if(mapNode.style.cssText){ + mapNode.style.cssText += "; " + value;// FIXME: Opera + }else{ + mapNode.style.cssText = value; + } + break; + default: + if(/^on[A-Z]/.test(attr)){ // eg. onSubmit needs to be onsubmit + attr = attr.toLowerCase(); + } + if(typeof value == "function"){ // functions execute in the context of the widget + value = dojo.hitch(this, value); + } + dojo.attr(mapNode, attr, value); + } + }, + + toString: function(){ + // summary: + // returns a string that represents the widget. When a widget is + // cast to a string, this method will be used to generate the + // output. Currently, it does not implement any sort of reversable + // serialization. + return '[Widget ' + this.declaredClass + ', ' + (this.id || 'NO ID') + ']'; // String + }, + + getDescendants: function(){ + // summary: + // Returns all the widgets that contained by this, i.e., all widgets underneath this.containerNode. + if(this.containerNode){ + var list= dojo.query('[widgetId]', this.containerNode); + return list.map(dijit.byNode); // Array + }else{ + return []; + } + }, + +//TODOC + nodesWithKeyClick: ["input", "button"], + + connect: function( + /*Object|null*/ obj, + /*String*/ event, + /*String|Function*/ method){ + // summary: + // Connects specified obj/event to specified method of this object + // and registers for disconnect() on widget destroy. + // Special event: "ondijitclick" triggers on a click or enter-down or space-up + // Similar to dojo.connect() but takes three arguments rather than four. + var handles =[]; + if(event == "ondijitclick"){ + // add key based click activation for unsupported nodes. + if(!this.nodesWithKeyClick[obj.nodeName]){ + handles.push(dojo.connect(obj, "onkeydown", this, + function(e){ + if(e.keyCode == dojo.keys.ENTER){ + return (dojo.isString(method))? + this[method](e) : method.call(this, e); + }else if(e.keyCode == dojo.keys.SPACE){ + // stop space down as it causes IE to scroll + // the browser window + dojo.stopEvent(e); + } + })); + handles.push(dojo.connect(obj, "onkeyup", this, + function(e){ + if(e.keyCode == dojo.keys.SPACE){ + return dojo.isString(method) ? + this[method](e) : method.call(this, e); + } + })); + } + event = "onclick"; + } + handles.push(dojo.connect(obj, event, this, method)); + + // return handles for FormElement and ComboBox + this._connects.push(handles); + return handles; + }, + + disconnect: function(/*Object*/ handles){ + // summary: + // Disconnects handle created by this.connect. + // Also removes handle from this widget's list of connects + for(var i=0; i<this._connects.length; i++){ + if(this._connects[i]==handles){ + dojo.forEach(handles, dojo.disconnect); + this._connects.splice(i, 1); + return; + } + } + }, + + isLeftToRight: function(){ + // summary: + // Checks the DOM to for the text direction for bi-directional support + // description: + // This method cannot be used during widget construction because the widget + // must first be connected to the DOM tree. Parent nodes are searched for the + // 'dir' attribute until one is found, otherwise left to right mode is assumed. + // See HTML spec, DIR attribute for more information. + + if(!("_ltr" in this)){ + this._ltr = dojo.getComputedStyle(this.domNode).direction != "rtl"; + } + return this._ltr; //Boolean + }, + + isFocusable: function(){ + // summary: + // Return true if this widget can currently be focused + // and false if not + return this.focus && (dojo.style(this.domNode, "display") != "none"); + } +}); + +} + +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.pad = function(/*String*/text, /*int*/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 + + var out = String(text); + if(!ch){ + ch = '0'; + } + while(out.length < size){ + if(end){ + out += ch; + }else{ + out = ch + out; + } + } + return 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. + // description: + // For example, + // | dojo.string.substitute("File '${0}' is not found in directory '${1}'.",["foo.html","/temp"]); + // | dojo.string.substitute("File '${name}' is not found in directory '${info.dir}'.", + // | {name: "foo.html", info: {dir: "/temp"}}); + // both return + // | "File 'foo.html' is not found in directory '/temp'." + // template: + // a string with expressions in the form `${key}` to be replaced or + // `${key:format}` which specifies a format function. + // map: hash to search for substitutions + // transform: + // a function to process all parameters before substitution takes + // place, e.g. dojo.string.encodeXML + // thisObject: + // where to look for optional format function; default to the global + // namespace + + 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)(value);} + if(transform){ value = transform(value, key); } + return value.toString(); + }); // string +}; + +dojo.string.trim = function(/*String*/ str){ + // summary: trims whitespaces from both sides of the 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. + 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; // 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 + // + // templateNode: DomNode + // a node that represents the widget template. Pre-empts both templateString and templatePath. + templateNode: null, + + // templateString: 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. + templateString: null, + + // templatePath: String + // Path to template (HTML file) for this widget relative to dojo.baseUrl + templatePath: null, + + // widgetsInTemplate: Boolean + // should we parse the template to find widgets that might be + // declared in markup inside it? false by default. + widgetsInTemplate: false, + + // containerNode: DomNode + // holds child elements. "containerNode" is generally set via a + // dojoAttachPoint assignment and it designates where children of + // the src dom node will be placed + containerNode: null, + + // skipNodeCache: 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, + + _stringRepl: function(tmpl){ + 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 = _this[key.substr(1)]; } + if(typeof value == "undefined"){ throw new Error(className+" template:"+key); } // a debugging aide + if(!value){ 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. + + // 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 = dijit._Templated._createNodesFromText(this._stringRepl(cached))[0]; + }else{ + // if it's a node, all we have to do is clone it + node = cached.cloneNode(true); + } + + // recurse through the node, looking for, and attaching to, our + // attachment points which should be defined on the template node. + this._attachTemplateNodes(node); + + var source = this.srcNodeRef; + if(source && source.parentNode){ + source.parentNode.replaceChild(node, source); + } + + this.domNode = node; + if(this.widgetsInTemplate){ + var cw = this._supportingWidgets = dojo.parser.parse(node); + this._attachTemplateNodes(cw, function(n,p){ + return n[p]; + }); + } + + this._fillContent(source); + }, + + _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 + 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 + + 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; + } + } + } + + // 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]); + } + }); + } + + } + } + } +); + +// 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 + // The URL to get the template from. dojo.uri.Uri is often passed as well. + // 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){ + return cached; + } + + // If necessary, load template string from template path + if(!templateString){ + templateString = dijit._Templated._sanitizeTemplateString(dojo._getText(templatePath)); + } + + 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 + return (tmplts[key] = dijit._Templated._createNodesFromText(templateString)[0]); //Node + } +}; + +dijit._Templated._sanitizeTemplateString = function(/*String*/tString){ + // 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. + if(tString){ + tString = tString.replace(/^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, ""); + var matches = tString.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im); + if(matches){ + tString = matches[1]; + } + }else{ + tString = ""; + } + return tString; //String +}; + + +if(dojo.isIE){ + dojo.addOnUnload(function(){ + var cache = dijit._Templated._templateCache; + for(var key in cache){ + var value = cache[key]; + if(!isNaN(value.nodeType)){ // isNode equivalent + dojo._destroyElement(value); + } + delete cache[key]; + } + }); +} + +(function(){ + var tagMap = { + cell: {re: /^<t[dh][\s\r\n>]/i, pre: "<table><tbody><tr>", post: "</tr></tbody></table>"}, + row: {re: /^<tr[\s\r\n>]/i, pre: "<table><tbody>", post: "</tbody></table>"}, + section: {re: /^<(thead|tbody|tfoot)[\s\r\n>]/i, pre: "<table>", post: "</table>"} + }; + + // dummy container node used temporarily to hold nodes being created + var tn; + + dijit._Templated._createNodesFromText = function(/*String*/text){ + // summary: + // Attempts to create a set of nodes based on the structure of the passed text. + + if(!tn){ + tn = dojo.doc.createElement("div"); + tn.style.display="none"; + dojo.body().appendChild(tn); + } + var tableType = "none"; + var rtext = text.replace(/^\s+/, ""); + for(var type in tagMap){ + var map = tagMap[type]; + if(map.re.test(rtext)){ + tableType = type; + text = map.pre + text + map.post; + break; + } + } + + tn.innerHTML = text; + if(tn.normalize){ + tn.normalize(); + } + + var tag = { cell: "tr", row: "tbody", section: "table" }[tableType]; + var _parent = (typeof tag != "undefined") ? + tn.getElementsByTagName(tag)[0] : + tn; + + var nodes = []; + while(_parent.firstChild){ + nodes.push(_parent.removeChild(_parent.firstChild)); + } + tn.innerHTML=""; + return nodes; // Array + } +})(); + +// 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._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 + // implements dijit._Container + for(var p=this.domNode.parentNode; p; p=p.parentNode){ + var id = p.getAttribute && p.getAttribute("widgetId"); + if(id){ + var parent = dijit.byId(id); + return parent.isContainer ? parent : null; + } + } + return null; + }, + + _getSibling: function(which){ + var node = this.domNode; + do{ + node = node[which+"Sibling"]; + }while(node && node.nodeType != 1); + if(!node){ return null; } // null + var id = node.getAttribute("widgetId"); + return dijit.byId(id); + }, + + 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"); // Mixed + }, + + 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"); // Mixed + } + } +); + +dojo.declare("dijit._Container", + null, + { + // summary: + // Mixin for widgets that contain a list of children. + // description: + // Use this mixin when the widget needs to know about and + // keep track of it's widget children. Widgets like SplitContainer + // and TabContainer. + + isContainer: true, + + addChild: function(/*Widget*/ widget, /*int?*/ insertIndex){ + // summary: + // Process the given child widget, inserting it's dom node as + // a child of our dom node + + if(insertIndex === undefined){ + insertIndex = "last"; + } + var refNode = this.containerNode || this.domNode; + if(insertIndex && typeof insertIndex == "number"){ + var children = dojo.query("> [widgetid]", refNode); + if(children && children.length >= insertIndex){ + refNode = children[insertIndex-1]; 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*/ widget){ + // summary: + // Removes the passed widget instance from this widget but does + // not destroy it + var node = widget.domNode; + node.parentNode.removeChild(node); // detach but don't destroy + }, + + _nextElement: function(node){ + do{ + node = node.nextSibling; + }while(node && node.nodeType != 1); + return node; + }, + + _firstElement: function(node){ + node = node.firstChild; + if(node && node.nodeType != 1){ + node = this._nextElement(node); + } + return node; + }, + + getChildren: function(){ + // summary: + // Returns array of children widgets + return dojo.query("> [widgetId]", this.containerNode || this.domNode).map(dijit.byNode); // Array + }, + + hasChildren: function(){ + // summary: + // Returns true if widget has children + var cn = this.containerNode || this.domNode; + return !!this._firstElement(cn); // Boolean + }, + + _getSiblingOfChild: function(/*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 + var node = child.domNode; + var which = (dir>0 ? "nextSibling" : "previousSibling"); + do{ + node = node[which]; + }while(node && (node.nodeType != 1 || !dijit.byNode(node))); + return node ? dijit.byNode(node) : null; + } + } +); + +dojo.declare("dijit._KeyNavContainer", + [dijit._Container], + { + + // summary: A _Container with keyboard navigation of its children. + // decscription: + // To use this mixin, call connectKeyNavHandlers() in + // postCreate() and call startupKeyNavChildren() in startup(). + // It provides normalized keyboard and focusing code for Container + // widgets. +/*===== + // focusedChild: Widget + // The currently focused child widget, or null if there isn't one + focusedChild: null, +=====*/ + + _keyNavCodes: {}, + + connectKeyNavHandlers: function(/*Array*/ prevKeyCodes, /*Array*/ nextKeyCodes){ + // summary: + // Call in postCreate() to attach the keyboard handlers + // to the container. + // preKeyCodes: Array + // Key codes for navigating to the previous child. + // nextKeyCodes: Array + // Key codes for navigating to the next child. + + var keyCodes = this._keyNavCodes = {}; + var prev = dojo.hitch(this, this.focusPrev); + var next = dojo.hitch(this, this.focusNext); + dojo.forEach(prevKeyCodes, function(code){ keyCodes[code] = prev }); + dojo.forEach(nextKeyCodes, function(code){ keyCodes[code] = next }); + this.connect(this.domNode, "onkeypress", "_onContainerKeypress"); + this.connect(this.domNode, "onfocus", "_onContainerFocus"); + }, + + startupKeyNavChildren: function(){ + // summary: + // Call in startup() to set child tabindexes to -1 + dojo.forEach(this.getChildren(), dojo.hitch(this, "_startupChild")); + }, + + addChild: function(/*Widget*/ widget, /*int?*/ insertIndex){ + // summary: Add a child to our _Container + dijit._KeyNavContainer.superclass.addChild.apply(this, arguments); + this._startupChild(widget); + }, + + focus: function(){ + // summary: Default focus() implementation: focus the first child. + this.focusFirstChild(); + }, + + focusFirstChild: function(){ + // summary: Focus the first focusable child in the container. + this.focusChild(this._getFirstFocusableChild()); + }, + + focusNext: function(){ + // summary: Focus the next widget or focal node (for widgets + // with multiple focal nodes) within this container. + if(this.focusedChild && this.focusedChild.hasNextFocalNode + && this.focusedChild.hasNextFocalNode()){ + this.focusedChild.focusNext(); + return; + } + var child = this._getNextFocusableChild(this.focusedChild, 1); + if(child.getFocalNodes){ + this.focusChild(child, child.getFocalNodes()[0]); + }else{ + this.focusChild(child); + } + }, + + focusPrev: function(){ + // summary: Focus the previous widget or focal node (for widgets + // with multiple focal nodes) within this container. + if(this.focusedChild && this.focusedChild.hasPrevFocalNode + && this.focusedChild.hasPrevFocalNode()){ + this.focusedChild.focusPrev(); + return; + } + var child = this._getNextFocusableChild(this.focusedChild, -1); + if(child.getFocalNodes){ + var nodes = child.getFocalNodes(); + this.focusChild(child, nodes[nodes.length-1]); + }else{ + this.focusChild(child); + } + }, + + focusChild: function(/*Widget*/ widget, /*Node?*/ node){ + // summary: Focus widget. Optionally focus 'node' within widget. + if(widget){ + if(this.focusedChild && widget !== this.focusedChild){ + this._onChildBlur(this.focusedChild); + } + this.focusedChild = widget; + if(node && widget.focusFocalNode){ + widget.focusFocalNode(node); + }else{ + widget.focus(); + } + } + }, + + _startupChild: function(/*Widget*/ widget){ + // summary: + // Set tabindex="-1" on focusable widgets so that we + // can focus them programmatically and by clicking. + // Connect focus and blur handlers. + if(widget.getFocalNodes){ + dojo.forEach(widget.getFocalNodes(), function(node){ + dojo.attr(node, "tabindex", -1); + this._connectNode(node); + }, this); + }else{ + var node = widget.focusNode || widget.domNode; + if(widget.isFocusable()){ + dojo.attr(node, "tabindex", -1); + } + this._connectNode(node); + } + }, + + _connectNode: function(/*Element*/ node){ + this.connect(node, "onfocus", "_onNodeFocus"); + this.connect(node, "onblur", "_onNodeBlur"); + }, + + _onContainerFocus: function(evt){ + // focus bubbles on Firefox, + // so just make sure that focus has really gone to the container + if(evt.target === this.domNode){ + this.focusFirstChild(); + } + }, + + _onContainerKeypress: function(evt){ + if(evt.ctrlKey || evt.altKey){ return; } + var func = this._keyNavCodes[evt.keyCode]; + if(func){ + func(); + dojo.stopEvent(evt); + } + }, + + _onNodeFocus: function(evt){ + // while focus is on a child, + // take the container out of the tab order so that + // we can shift-tab to the element before the container + dojo.attr(this.domNode, "tabindex", -1); + // record the child that has been focused + var widget = dijit.getEnclosingWidget(evt.target); + if(widget && widget.isFocusable()){ + this.focusedChild = widget; + } + dojo.stopEvent(evt); + }, + + _onNodeBlur: function(evt){ + // when focus leaves a child, + // reinstate the container's tabindex + if(this.tabIndex){ + dojo.attr(this.domNode, "tabindex", this.tabIndex); + } + dojo.stopEvent(evt); + }, + + _onChildBlur: function(/*Widget*/ widget){ + // summary: + // Called when focus leaves a child widget to go + // to a sibling widget. + }, + + _getFirstFocusableChild: function(){ + return this._getNextFocusableChild(null, 1); + }, + + _getNextFocusableChild: function(child, dir){ + if(child){ + child = this._getSiblingOfChild(child, dir); + } + var children = this.getChildren(); + for(var i=0; i < children.length; i++){ + if(!child){ + child = children[(dir>0) ? 0 : (children.length-1)]; + } + if(child.isFocusable()){ + return child; + } + child = this._getSiblingOfChild(child, dir); + } + // no focusable child found + return null; + } + } +); + +} + +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 + // Mixin for widgets that contain a list of children like SplitContainer. + // Widgets which mixin this code must define layout() to lay out the children + + isLayoutContainer: true, + + postCreate: function(){ + dojo.addClass(this.domNode, "dijitContainer"); + }, + + 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; } + + dojo.forEach(this.getChildren(), function(child){ child.startup(); }); + + // If I am a top level widget + if(!this.getParent || !this.getParent()){ + // 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 is width=height=100% (or something similar), + // then I need to watch when the window resizes, and size myself accordingly + // (passing in no argument to resize means that it has to glean the size itself) + this.connect(window, 'onresize', function(){this.resize();}); + } + + this.inherited(arguments); + }, + + resize: function(args){ + // summary: + // Explicitly set this widget's size (in pixels), + // and then call layout() to resize contents (and maybe adjust child widgets) + // + // args: Object? + // {w: int, h: int, l: int, t: int} + + var node = this.domNode; + + // set margin box size, unless it wasn't specified, in which case use current size + if(args){ + dojo.marginBox(node, args); + + // set offset of the node + if(args.t){ node.style.top = args.t + "px"; } + if(args.l){ node.style.left = args.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 = dojo.mixin(dojo.marginBox(node), args||{}); + +// console.log(this, ": setting size to ", mb); + + // Save the size of my content box. + this._contentBox = dijit.layout.marginBox2contentBox(node, mb); + + // Callback for widget to adjust size of it's children + this.layout(); + }, + + layout: function(){ + // summary + // Widgets override this method to size & 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. + } + } +); + +dijit.layout.marginBox2contentBox = function(/*DomNode*/ node, /*Object*/ mb){ + // summary: + // Given the margin-box size of a node, return it's 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 it's 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: + _FormWidget's correspond to native HTML elements such as <checkbox> or <button>. + Each _FormWidget 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. + + They also share some common methods. + */ + + // baseClass: 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, + + // 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, + + // intermediateChanges: Boolean + // Fires onChange for each value change or only on demand + intermediateChanges: false, + + // These mixins assume that the focus node is an INPUT, as many but not all _FormWidgets are. + // 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. + attributeMap: dojo.mixin(dojo.clone(dijit._Widget.prototype.attributeMap), + {value:"focusNode", disabled:"focusNode", readOnly:"focusNode", id:"focusNode", tabIndex:"focusNode", alt:"focusNode"}), + + setAttribute: function(/*String*/ attr, /*anything*/ value){ + this.inherited(arguments); + switch(attr){ + case "disabled": + var tabIndexNode = this[this.attributeMap['tabIndex']||'domNode']; + 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 + tabIndexNode.removeAttribute('tabIndex'); + }else{ + tabIndexNode.setAttribute('tabIndex', this.tabIndex); + } + dijit.setWaiState(this[this.attributeMap['disabled']||'domNode'], "disabled", value); + this._setStateClass(); + } + }, + + setDisabled: function(/*Boolean*/ disabled){ + // summary: + // Set disabled state of widget (Deprecated). + dojo.deprecated("setDisabled("+disabled+") is deprecated. Use setAttribute('disabled',"+disabled+") instead.", "", "2.0"); + this.setAttribute('disabled', disabled); + }, + + + _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(){ + this._active = false; + this._mouseDown = false; + this._setStateClass(); + this.disconnect(mouseUpConnector); + }); + if(this.isFocusable()){ this.focus(); } + break; + } + this._setStateClass(); + } + }, + + isFocusable: function(){ + return !this.disabled && !this.readOnly && this.focusNode && (dojo.style(this.domNode, "display") != "none"); + }, + + focus: function(){ + setTimeout(dojo.hitch(this, dijit.focus, this.focusNode), 0); // cannot call focus() from an event handler directly + }, + + _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). + // + // 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 + + // Get original (non state related, non baseClass related) class specified in template + if(!("staticClass" in this)){ + this.staticClass = (this.stateNode||this.domNode).className; + } + + // Compute new set of classes + var classes = [ this.baseClass ]; + + function multiply(modifier){ + classes=classes.concat(dojo.map(classes, 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"); + } + } + + (this.stateNode || this.domNode).className = this.staticClass + " " + classes.join(" "); + }, + + onChange: function(newValue){ + // summary: callback when value is changed + }, + + _onChangeMonitor: 'value', + _onChangeActive: false, + + _handleOnChange: function(/*anything*/ newValue, /*Boolean, optional*/ priorityChange){ + // summary: set the value of the widget. + this._lastValue = newValue; + if(this._lastValueReported == undefined && (priorityChange === null || !this._onChangeActive)){ + this._resetValue = this._lastValueReported = newValue; + } + if((this.intermediateChanges || priorityChange || priorityChange === undefined) && + ((newValue && newValue.toString)?newValue.toString():newValue) !== ((this._lastValueReported && this._lastValueReported.toString)?this._lastValueReported.toString():this._lastValueReported)){ + this._lastValueReported = newValue; + if(this._onChangeActive){ this.onChange(newValue); } + } + }, + + reset: function(){ + this._hasBeenBlurred = false; + if(this.setValue && !this._getValueDeprecated){ + this.setValue(this._resetValue, true); + }else if(this._onChangeMonitor){ + this.setAttribute(this._onChangeMonitor, (this._resetValue !== undefined && this._resetValue !== null)? this._resetValue : ''); + } + }, + + create: function(){ + this.inherited(arguments); + this._onChangeActive = true; + this._setStateClass(); + }, + + destroy: function(){ + if(this._layoutHackHandle){ + clearTimeout(this._layoutHackHandle); + } + this.inherited(arguments); + }, + + setValue: function(/*String*/ value){ + dojo.deprecated("dijit.form._FormWidget:setValue("+value+") is deprecated. Use setAttribute('value',"+value+") instead.", "", "2.0"); + this.setAttribute('value', value); + }, + + _getValueDeprecated: true, // Form uses this, remove when getValue is removed + getValue: function(){ + dojo.deprecated("dijit.form._FormWidget:getValue() is deprecated. Use widget.value instead.", "", "2.0"); + return this.value; + }, + + _layoutHack: function(){ + // summary: work around table sizing bugs on FF2 by forcing redraw + if(dojo.isFF == 2){ + var node=this.domNode; + var old = node.style.opacity; + node.style.opacity = "0.999"; + this._layoutHackHandle = setTimeout(dojo.hitch(this, function(){ + this._layoutHackHandle = null; + node.style.opacity = old; + }), 0); + } + } +}); + +dojo.declare("dijit.form._FormValueWidget", dijit.form._FormWidget, +{ + /* + Summary: + _FormValueWidget's correspond to native HTML elements such as <input> or <select> that have user changeable values. + Each _ValueWidget represents a single input value, and has a (possibly hidden) <input> element, + to which it serializes its input value, so that form submission (either normal submission or via FormBind?) + works as expected. + */ + + attributeMap: dojo.mixin(dojo.clone(dijit.form._FormWidget.prototype.attributeMap), + {value:""}), + + postCreate: function(){ + this.setValue(this.value, null); + }, + + setValue: function(/*anything*/ newValue, /*Boolean, optional*/ priorityChange){ + // summary: set the value of the widget. + this.value = newValue; + this._handleOnChange(newValue, priorityChange); + }, + + _getValueDeprecated: false, // remove when _FormWidget:getValue is removed + getValue: function(){ + // summary: get the value of the widget. + return this._lastValue; + }, + + undo: function(){ + // summary: restore the value to the last value passed to onChange + this.setValue(this._lastValueReported, false); + }, + + _valueChanged: function(){ + var v = this.getValue(); + var lv = this._lastValueReported; + // Equality comparison of objects such as dates are done by reference so + // two distinct objects are != even if they have the same data. So use + // toStrings in case the values are objects. + return ((v !== null && (v !== undefined) && v.toString)?v.toString():'') !== ((lv !== null && (lv !== undefined) && lv.toString)?lv.toString():''); + }, + + _onKeyPress: function(e){ + if(e.keyCode == dojo.keys.ESCAPE && !e.shiftKey && !e.ctrlKey && !e.altKey){ + if(this._valueChanged()){ + this.undo(); + dojo.stopEvent(e); + return false; + } + } + return true; + } +}); + +} + +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 + + + + + + + +} + |