You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@labs.apache.org by si...@apache.org on 2009/01/12 16:59:54 UTC
svn commit: r733824 [2/2] - in
/labs/magma/trunk/website-dojo-textareas/src/main: dojo-profile/
java/org/apache/magma/dojo/ resources/dojo-1.2.0/
resources/dojo-1.2.0/magma/ resources/dojo-1.2.0/magma/nls/
Added: labs/magma/trunk/website-dojo-textareas/src/main/resources/dojo-1.2.0/magma/textareaFieldsCustom.js.uncompressed.js
URL: http://svn.apache.org/viewvc/labs/magma/trunk/website-dojo-textareas/src/main/resources/dojo-1.2.0/magma/textareaFieldsCustom.js.uncompressed.js?rev=733824&view=auto
==============================================================================
--- labs/magma/trunk/website-dojo-textareas/src/main/resources/dojo-1.2.0/magma/textareaFieldsCustom.js.uncompressed.js (added)
+++ labs/magma/trunk/website-dojo-textareas/src/main/resources/dojo-1.2.0/magma/textareaFieldsCustom.js.uncompressed.js Mon Jan 12 07:59:45 2009
@@ -0,0 +1,18865 @@
+/*
+ Copyright (c) 2004-2008, The Dojo Foundation All Rights Reserved.
+ Available via Academic Free License >= 2.1 OR the modified BSD license.
+ see: http://dojotoolkit.org/license for details
+*/
+
+/*
+ This is a compiled version of Dojo, built for deployment and not for
+ development. To get an editable version, please visit:
+
+ http://dojotoolkit.org
+
+ for documentation and information on getting the source.
+*/
+
+if(!dojo._hasResource["dijit._base.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 _document = dojo.doc;
+ if(_document.selection){ // IE
+ var s=_document.selection;
+ if(s.type=='Text'){
+ return !s.createRange().htmlText.length; // Boolean
+ }else{ //Control range
+ return !s.createRange().length; // Boolean
+ }
+ }else{
+ var _window = dojo.global;
+ 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();
+ //range.addElement does not have call/apply method, so can not call it directly
+ //range is not available in "range.addElement(item)", so can't use that either
+ dojo.forEach(bookmark, function(n){
+ range.addElement(n);
+ });
+ }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 doc = targetWindow.document;
+ if(doc){
+ if(dojo.isIE){
+ doc.attachEvent('onactivate', function(evt){
+ if(evt.srcElement.tagName.toLowerCase() != "#document"){
+ dijit._onFocusNode(evt.srcElement);
+ }
+ });
+ doc.attachEvent('ondeactivate', function(evt){
+ dijit._onBlurNode(evt.srcElement);
+ });
+ }else{
+ doc.addEventListener('focus', function(evt){
+ dijit._onFocusNode(evt.target);
+ }, true);
+ doc.addEventListener('blur', function(evt){
+ dijit._onBlurNode(evt.target);
+ }, true);
+ }
+ }
+ doc = 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){
+ return;
+ }
+
+ if(node.nodeName && node.nodeName.toLowerCase() == "body"){
+ // Ignore focus events on main document <body>. This is specifically here
+ // so that clicking the up/down arrows of a spinner (which don't get focus)
+ // won't cause that widget to blur. (IIRC, IE issue)
+ return;
+ }
+
+ if(node.nodeType == 9){
+ // We focused on (the body of) the document itself, either the main document
+ // or an iframe
+ var iframe = dijit.getDocumentWindow(node).frameElement;
+ if(!iframe){
+ // Ignore focus events on main document. This is specifically here
+ // so that clicking the up/down arrows of a spinner (which don't get focus)
+ // won't cause that widget to blur.
+ return;
+ }
+
+ node = iframe;
+ }
+
+ 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.addOnWindowUnload(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")
+ && (dojo.attr(elem, "type") != "hidden");
+}
+
+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 && child.nodeName.toUpperCase() != 'SELECT'){ walkTree(child) }
+ });
+ };
+ if(dijit._isElementShown(root)){ walkTree(root) }
+ return { first: first, last: last, lowest: lowest, highest: highest };
+}
+dijit.getFirstInTabbingOrder = function(/*String|DOMNode*/root){
+ // summary:
+ // Finds the descendant of the specified root node
+ // that is first in the tabbing order
+ var elems = dijit._getTabNavigable(dojo.byId(root));
+ return elems.lowest ? elems.lowest : elems.first; // 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
+};
+
+// dijit.defaultDuration
+// Default duration for wipe and fade animations within dijits
+dijit.defaultDuration = dojo.config["defaultDuration"] || 200;
+
+}
+
+if(!dojo._hasResource["dojo.AdapterRegistry"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo.AdapterRegistry"] = true;
+dojo.provide("dojo.AdapterRegistry");
+
+dojo.AdapterRegistry = function(/*Boolean?*/ returnWrappers){
+ // summary:
+ // A registry to make contextual calling/searching easier.
+ // description:
+ // Objects of this class keep list of arrays in the form [name, check,
+ // wrap, directReturn] that are used to determine what the contextual
+ // result of a set of checked arguments is. All check/wrap functions
+ // in this registry should be of the same arity.
+ // example:
+ // | // create a new registry
+ // | var reg = new dojo.AdapterRegistry();
+ // | reg.register("handleString",
+ // | dojo.isString,
+ // | function(str){
+ // | // do something with the string here
+ // | }
+ // | );
+ // | reg.register("handleArr",
+ // | dojo.isArray,
+ // | function(arr){
+ // | // do something with the array here
+ // | }
+ // | );
+ // |
+ // | // now we can pass reg.match() *either* an array or a string and
+ // | // the value we pass will get handled by the right function
+ // | reg.match("someValue"); // will call the first function
+ // | reg.match(["someValue"]); // will call the second
+
+ this.pairs = [];
+ this.returnWrappers = returnWrappers || false; // Boolean
+}
+
+dojo.extend(dojo.AdapterRegistry, {
+ register: function(/*String*/ name, /*Function*/ check, /*Function*/ wrap, /*Boolean?*/ directReturn, /*Boolean?*/ override){
+ // summary:
+ // register a check function to determine if the wrap function or
+ // object gets selected
+ // name:
+ // a way to identify this matcher.
+ // check:
+ // a function that arguments are passed to from the adapter's
+ // match() function. The check function should return true if the
+ // given arguments are appropriate for the wrap function.
+ // directReturn:
+ // If directReturn is true, the value passed in for wrap will be
+ // returned instead of being called. Alternately, the
+ // AdapterRegistry can be set globally to "return not call" using
+ // the returnWrappers property. Either way, this behavior allows
+ // the registry to act as a "search" function instead of a
+ // function interception library.
+ // override:
+ // If override is given and true, the check function will be given
+ // highest priority. Otherwise, it will be the lowest priority
+ // adapter.
+ this.pairs[((override) ? "unshift" : "push")]([name, check, wrap, directReturn]);
+ },
+
+ match: function(/* ... */){
+ // summary:
+ // Find an adapter for the given arguments. If no suitable adapter
+ // is found, throws an exception. match() accepts any number of
+ // arguments, all of which are passed to all matching functions
+ // from the registered pairs.
+ for(var i = 0; i < this.pairs.length; i++){
+ var pair = this.pairs[i];
+ if(pair[1].apply(this, arguments)){
+ if((pair[3])||(this.returnWrappers)){
+ return pair[2];
+ }else{
+ return pair[2].apply(this, arguments);
+ }
+ }
+ }
+ throw new Error("No match found");
+ },
+
+ unregister: function(name){
+ // summary: Remove a named adapter from the registry
+
+ // FIXME: this is kind of a dumb way to handle this. On a large
+ // registry this will be slow-ish and we can use the name as a lookup
+ // should we choose to trade memory for speed.
+ for(var i = 0; i < this.pairs.length; i++){
+ var pair = this.pairs[i];
+ if(pair[0] == name){
+ this.pairs.splice(i, 1);
+ return true;
+ }
+ }
+ return false;
+ }
+});
+
+}
+
+if(!dojo._hasResource["dijit._base.place"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._base.place"] = true;
+dojo.provide("dijit._base.place");
+
+
+
+// ported from dojo.html.util
+
+dijit.getViewport = function(){
+ // summary
+ // Returns the dimensions and scroll position of the viewable area of a browser window
+
+ var _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.__Position = function(){
+ // x: Integer
+ // horizontal coordinate in pixels, relative to document body
+ // y: Integer
+ // vertical coordinate in pixels, relative to document body
+
+ thix.x = x;
+ this.y = y;
+}
+=====*/
+
+
+dijit.placeOnScreen = function(
+ /* DomNode */ node,
+ /* dijit.__Position */ pos,
+ /* String[] */ corners,
+ /* boolean? */ tryOnly){
+ // summary:
+ // Positions one of the node's corners at specified position
+ // such that node is fully visible in viewport.
+ // description:
+ // NOTE: node is assumed to be absolutely or relatively positioned.
+ // pos:
+ // Object like {x: 10, y: 20}
+ // corners:
+ // Array of Strings representing order to try corners in, like ["TR", "BL"].
+ // Possible values are:
+ // * "BL" - bottom left
+ // * "BR" - bottom right
+ // * "TL" - top left
+ // * "TR" - top right
+ // example:
+ // Try to place node's top right corner at (10,20).
+ // If that makes node go (partially) off screen, then try placing
+ // bottom left corner at (10,20).
+ // | placeOnScreen(node, {x: 10, y: 20}, ["TR", "BL"])
+
+ var choices = dojo.map(corners, function(corner){ 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.placeOnScreenAroundNode = function(
+ /* DomNode */ node,
+ /* DomNode */ aroundNode,
+ /* Object */ aroundCorners,
+ /* Function? */ layoutNode){
+
+ // summary:
+ // Position node adjacent or kitty-corner to aroundNode
+ // such that it's fully visible in viewport.
+ //
+ // description:
+ // Place node such that corner of node touches a corner of
+ // aroundNode, and that node is fully visible.
+ //
+ // aroundCorners:
+ // Ordered list of pairs of corners to try matching up.
+ // Each pair of corners is represented as a key/value in the hash,
+ // where the key corresponds to the aroundNode's corner, and
+ // the value corresponds to the node's corner:
+ //
+ // | { aroundNodeCorner1: nodeCorner1, aroundNodeCorner2: nodeCorner2, ...}
+ //
+ // The following strings are used to represent the four corners:
+ // * "BL" - bottom left
+ // * "BR" - bottom right
+ // * "TL" - top left
+ // * "TR" - top right
+ //
+ // layoutNode: Function(node, aroundNodeCorner, nodeCorner)
+ // For things like tooltip, they are displayed differently (and have different dimensions)
+ // based on their orientation relative to the parent. This adjusts the popup based on orientation.
+ //
+ // example:
+ // | dijit.placeOnScreenAroundNode(node, aroundNode, {'BL':'TL', 'TR':'BR'});
+ // This will try to position node such that node's top-left corner is at the same position
+ // as the bottom left corner of the aroundNode (ie, put node below
+ // aroundNode, with left edges aligned). If that fails it will try to put
+ // the bottom-right corner of node where the top right corner of aroundNode is
+ // (ie, put node above aroundNode, with right edges aligned)
+ //
+
+ // get coordinates of aroundNode
+ aroundNode = dojo.byId(aroundNode);
+ var oldDisplay = aroundNode.style.display;
+ aroundNode.style.display="";
+ // #3172: use the slightly tighter border box instead of marginBox
+ var aroundNodeW = aroundNode.offsetWidth; //mb.w;
+ var aroundNodeH = aroundNode.offsetHeight; //mb.h;
+ var aroundNodePos = dojo.coords(aroundNode, true);
+ aroundNode.style.display=oldDisplay;
+
+ // place the node around the calculated rectangle
+ return dijit._placeOnScreenAroundRect(node,
+ aroundNodePos.x, aroundNodePos.y, aroundNodeW, aroundNodeH, // rectangle
+ aroundCorners, layoutNode);
+};
+
+/*=====
+dijit.__Rectangle = function(){
+ // x: Integer
+ // horizontal offset in pixels, relative to document body
+ // y: Integer
+ // vertical offset in pixels, relative to document body
+ // width: Integer
+ // width in pixels
+ // height: Integer
+ // height in pixels
+
+ thix.x = x;
+ this.y = y;
+ thix.width = width;
+ this.height = height;
+}
+=====*/
+
+
+dijit.placeOnScreenAroundRectangle = function(
+ /* DomNode */ node,
+ /* dijit.__Rectangle */ aroundRect,
+ /* Object */ aroundCorners,
+ /* Function */ layoutNode){
+
+ // summary:
+ // Like dijit.placeOnScreenAroundNode(), except that the "around"
+ // parameter is an arbitrary rectangle on the screen (x, y, width, height)
+ // instead of a dom node.
+
+ return dijit._placeOnScreenAroundRect(node,
+ aroundRect.x, aroundRect.y, aroundRect.width, aroundRect.height, // rectangle
+ aroundCorners, layoutNode);
+};
+
+dijit._placeOnScreenAroundRect = function(
+ /* DomNode */ node,
+ /* Number */ x,
+ /* Number */ y,
+ /* Number */ width,
+ /* Number */ height,
+ /* Object */ aroundCorners,
+ /* Function */ layoutNode){
+
+ // summary:
+ // Like dijit.placeOnScreenAroundNode(), except it accepts coordinates
+ // of a rectangle to place node adjacent to.
+
+ // TODO: combine with placeOnScreenAroundRectangle()
+
+ // Generate list of possible positions for node
+ var choices = [];
+ for(var nodeCorner in aroundCorners){
+ choices.push( {
+ aroundCorner: nodeCorner,
+ corner: aroundCorners[nodeCorner],
+ pos: {
+ x: x + (nodeCorner.charAt(1) == 'L' ? 0 : width),
+ y: y + (nodeCorner.charAt(0) == 'T' ? 0 : height)
+ }
+ });
+ }
+
+ return dijit._place(node, choices, layoutNode);
+};
+
+dijit.placementRegistry = new dojo.AdapterRegistry();
+dijit.placementRegistry.register("node",
+ function(n, x){
+ return typeof x == "object" &&
+ typeof x.offsetWidth != "undefined" && typeof x.offsetHeight != "undefined";
+ },
+ dijit.placeOnScreenAroundNode);
+dijit.placementRegistry.register("rect",
+ function(n, x){
+ return typeof x == "object" &&
+ "x" in x && "y" in x && "width" in x && "height" in x;
+ },
+ dijit.placeOnScreenAroundRectangle);
+
+dijit.placeOnScreenAroundElement = function(
+ /* DomNode */ node,
+ /* Object */ aroundElement,
+ /* Object */ aroundCorners,
+ /* Function */ layoutNode){
+
+ // summary:
+ // Like dijit.placeOnScreenAroundNode(), except it accepts an arbitrary object
+ // for the "around" argument and finds a proper processor to place a node.
+
+ return dijit.placementRegistry.match.apply(dijit.placementRegistry, arguments);
+};
+
+}
+
+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
+
+ // In some IE versions (at least 6.0), document.parentWindow does not return a
+ // reference to the real window object (maybe a copy), so we must fix it as well
+ // We use IE specific execScript to attach the real window reference to
+ // document._parentWindow for later use
+ if(dojo.isIE && window !== document.parentWindow && !doc._parentWindow){
+ /*
+ In IE 6, only the variable "window" can be used to connect events (others
+ may be only copies).
+ */
+ doc.parentWindow.execScript("document._parentWindow = window;", "Javascript");
+ //to prevent memory leak, unset it after use
+ //another possibility is to add an onUnload handler which seems overkill to me (liucougar)
+ var win = doc._parentWindow;
+ doc._parentWindow = null;
+ return win; // Window
+ }
+
+ return doc._parentWindow || doc.parentWindow || doc.defaultView; // Window
+}
+
+}
+
+if(!dojo._hasResource["dijit._base.popup"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._base.popup"] = true;
+dojo.provide("dijit._base.popup");
+
+
+
+
+
+dijit.popup = new function(){
+ // summary:
+ // This class is used to show/hide widgets as popups.
+ //
+
+ var stack = [],
+ beginZIndex=1000,
+ idGen = 1;
+
+ this.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.left = wrapper.style.top = "0px"; // prevent transient scrollbar causing misalign (#5776)
+ 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.charOrCode == dojo.keys.ESCAPE && args.onCancel){
+ dojo.stopEvent(evt);
+ args.onCancel();
+ }else if(evt.charOrCode === dojo.keys.TAB){
+ dojo.stopEvent(evt);
+ var topPopup = getTopPopup();
+ if(topPopup && topPopup.onCancel){
+ topPopup.onCancel();
+ }
+ }
+ }));
+
+ // watch for cancel/execute events on the popup and notify the caller
+ // (for a menu, "execute" means clicking an item)
+ if(widget.onCancel){
+ handlers.push(dojo.connect(widget, "onCancel", 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 burl = dojo.config["dojoBlankHtmlUrl"] || (dojo.moduleUrl("dojo", "resources/blank.html")+"") || "javascript:\"\"";
+ var html="<iframe src='" + burl + "'"
+ + " style='position: absolute; left: 0px; top: 0px;"
+ + "z-index: -1; filter:Alpha(Opacity=\"0\");'>";
+ iframe = dojo.doc.createElement(html);
+ }else{
+ iframe = dojo.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 < 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
+ // 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
+
+ node = dojo.byId(node);
+ var body = node.ownerDocument.body;
+ var html = body.parentNode;
+ if(dojo.isFF == 2 || node == body || node == html){ // FF2 is perfect, too bad FF3 is not
+ node.scrollIntoView(false); // short-circuit to native if possible
+ return;
+ }
+ var rtl = !dojo._isBodyLtr();
+ var strict = dojo.doc.compatMode != 'BackCompat'; // not the same as !dojo.isQuirks
+ var scrollRoot = (strict && !dojo.isSafari)? html : body;
+
+ function addPseudoAttrs(element){
+ var parent = element.parentNode;
+ var offsetParent = element.offsetParent;
+ if(offsetParent == null){ // process only 1 of BODY/HTML
+ element = scrollRoot;
+ offsetParent = html;
+ parent = null;
+ }
+ // all the V/H object members below are to reuse code for both directions
+ element._offsetParent = (offsetParent == body)? scrollRoot : offsetParent;
+ element._parent = (parent == body)? scrollRoot : parent;
+ element._start = { H:element.offsetLeft, V:element.offsetTop };
+ element._scroll = { H:element.scrollLeft, V:element.scrollTop };
+ element._renderedSize = { H: element.offsetWidth, V: element.offsetHeight };
+ var bp = dojo._getBorderExtents(element);
+ element._borderStart = { H:bp.l, V:bp.t };
+ element._borderSize = { H:bp.w, V:bp.h };
+ element._clientSize = (element._offsetParent == html && dojo.isSafari && strict)? { H:html.clientWidth, V:html.clientHeight } : { H:element.clientWidth, V:element.clientHeight };
+ element._scrollBarSize = { V: null, H: null };
+ for(var dir in element._scrollBarSize){ // for both x and y directions
+ var scrollBar = element._renderedSize[dir] - element._clientSize[dir] - element._borderSize[dir];
+ element._scrollBarSize[dir] = (element._clientSize[dir] > 0 && scrollBar >= 15 && scrollBar <= 17)? scrollBar : 0; // sanity check
+ }
+ element._isScrollable = { V: null, H: null };
+ for(dir in element._isScrollable){ // for both x and y directions
+ var otherDir = dir=="H"? "V" : "H";
+ element._isScrollable[dir] = element == scrollRoot || element._scroll[dir] || element._scrollBarSize[otherDir];
+ }
+ }
+
+ var parent = node;
+ while(parent != null){
+ addPseudoAttrs(parent);
+ var next = parent._parent;
+ if(next){
+ next._child = parent;
+ }
+ parent = next;
+ }
+ for(var dir in scrollRoot._renderedSize){ scrollRoot._renderedSize[dir] = Math.min(scrollRoot._clientSize[dir], scrollRoot._renderedSize[dir]); }
+ var element = node;
+ while(element != scrollRoot){
+ parent = element._parent;
+ if(parent.tagName == "TD"){
+ var table = parent._parent._parent._parent; // point to TABLE
+ if(table._offsetParent == element._offsetParent && parent._offsetParent != element._offsetParent){
+ parent = table; // child of TD has the same offsetParent as TABLE, so skip TD, TR, and TBODY (ie. verticalslider)
+ }
+ }
+ // check if this node and its parent share the same offsetParent
+ var startIsRelative = element == scrollRoot || (parent._offsetParent != element._offsetParent);
+
+ for(dir in element._start){ // for both x and y directions
+ var otherDir = dir=="H"? "V" : "H";
+ if(rtl && dir=="H" && (dojo.isSafari || dojo.isIE) && parent._clientSize.H > 0){ // scroll starts on the right
+ var delta = parent.scrollWidth - parent._clientSize.H;
+ if(delta > 0){ parent._scroll.H -= delta; } // match FF3 which has cool negative scrollLeft values
+ }
+ if(dojo.isIE && parent._offsetParent.tagName == "TABLE"){ // make it consistent with Safari and FF3 and exclude the starting TABLE border of TABLE children
+ parent._start[dir] -= parent._offsetParent._borderStart[dir];
+ parent._borderStart[dir] = parent._borderSize[dir] = 0;
+ }
+ if(parent._clientSize[dir] == 0){ // TABLE on Safari3/FF3, and TBODY on IE6/7
+ parent._renderedSize[dir] = parent._clientSize[dir] = parent._child._clientSize[dir];
+ if(rtl && dir=="H"){ parent._start[dir] -= parent._renderedSize[dir]; }
+ }else{
+ parent._renderedSize[dir] -= parent._borderSize[dir] + parent._scrollBarSize[dir];
+ }
+ parent._start[dir] += parent._borderStart[dir];
+
+ // underflow = visible gap between parent and this node taking scrolling into account
+ // if negative, part of the node is obscured by the parent's beginning and should be scrolled to become visible
+ var underflow = element._start[dir] - (startIsRelative? 0 : parent._start[dir]) - parent._scroll[dir];
+ // if positive, number of pixels obscured by the parent's end
+ var overflow = underflow + element._renderedSize[dir] - parent._renderedSize[dir];
+ var scrollAmount, scrollAttr = (dir=="H")? "scrollLeft" : "scrollTop";
+ // see if we should scroll forward or backward
+ var reverse = (dir=="H" && rtl); // flip everything
+ var underflowScroll = reverse? -overflow : underflow;
+ var overflowScroll = reverse? -underflow : overflow;
+ if(underflowScroll <= 0){
+ scrollAmount = underflowScroll;
+ }else if(overflowScroll <= 0){
+ scrollAmount = 0;
+ }else if(underflowScroll < overflowScroll){
+ scrollAmount = underflowScroll;
+ }else{
+ scrollAmount = overflowScroll;
+ }
+ var scrolledAmount = 0;
+ if(scrollAmount != 0){
+ var oldScroll = parent[scrollAttr];
+ parent[scrollAttr] += reverse? -scrollAmount : scrollAmount; // actually perform the scroll
+ scrolledAmount = parent[scrollAttr] - oldScroll; // in case the scroll failed
+ underflow -= scrolledAmount;
+ overflowScroll -= reverse? -scrolledAmount : scrolledAmount;
+ }
+ parent._renderedSize[dir] = element._renderedSize[dir] + parent._scrollBarSize[dir] -
+ // check for isScrollable since a nonscrolling parent could be smaller than the child but the child is fully visible
+ ((parent._isScrollable[dir] && overflowScroll > 0)? overflowScroll : 0); // only show portion of the parent
+ parent._start[dir] += (underflow >= 0 || !parent._isScrollable[dir])? underflow : 0;
+ }
+ element = parent; // now see if the parent needs to be scrolled as well
+ }
+};
+
+}
+
+if(!dojo._hasResource["dijit._base.sniff"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._base.sniff"] = true;
+// summary:
+// Applies pre-set CSS classes to the top-level HTML node, based on:
+// - browser (ex: dj_ie)
+// - browser version (ex: dj_ie6)
+// - box model (ex: dj_contentBox)
+// - text direction (ex: dijitRtl)
+//
+// In addition, browser, browser version, and box model are
+// combined with an RTL flag when browser text is RTL. ex: dj_ie-rtl.
+//
+// Simply doing a require on this module will
+// establish this CSS. Modified version of Morris' CSS hack.
+
+dojo.provide("dijit._base.sniff");
+
+(function(){
+ var d = dojo;
+ var ie = d.isIE;
+ var opera = d.isOpera;
+ var maj = Math.floor;
+ var ff = d.isFF;
+ var boxModel = d.boxModel.replace(/-/,'');
+ 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,
+ dj_ff3: maj(ff) == 3
+ }; // no dojo unsupported browsers
+ classes["dj_" + boxModel] = true;
+
+ var html = dojo.doc.documentElement;
+
+ // apply browser, browser version, and box model class names
+ for(var p in classes){
+ if(classes[p]){
+ if(html.className){
+ html.className += " " + p;
+ }else{
+ html.className = p;
+ }
+ }
+ }
+
+ // If RTL mode then add dijitRtl flag plus repeat existing classes
+ // with -rtl extension
+ // (unshift is to make this code run after <body> node is loaded but before parser runs)
+ dojo._loaders.unshift(function(){
+ if(!dojo._isBodyLtr()){
+ html.className += " dijitRtl";
+ for(var p in classes){
+ if(classes[p]){
+ html.className += " " + p+"-rtl";
+ }
+ }
+ }
+ });
+})();
+
+}
+
+if(!dojo._hasResource["dijit._base.typematic"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._base.typematic"] = true;
+dojo.provide("dijit._base.typematic");
+
+dijit.typematic = {
+ // summary:
+ // These functions are used to repetitively call a user specified callback
+ // method when a specific key or mouse click over a specific DOM node is
+ // held down for a specific amount of time.
+ // Only 1 such event is allowed to occur on the browser page at 1 time.
+
+ _fireEventAndReload: function(){
+ this._timer = null;
+ this._callback(++this._count, this._node, this._evt);
+ 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.
+ // charOrCode: the printable character (string) or keyCode (number) to listen for.
+ // keyCode: (deprecated - use charOrCode) the keyCode (number) to listen for (implies charCode = 0).
+ // charCode: (deprecated - use charOrCode) the charCode (number) to listen for.
+ // ctrlKey: desired ctrl key state to initiate the calback sequence:
+ // pressed (true)
+ // released (false)
+ // either (unspecified)
+ // altKey: same as ctrlKey but for the alt key
+ // shiftKey: same as ctrlKey but for the shift key
+ // See the trigger method for other parameters.
+ // Returns an array of dojo.connect handles
+ if(keyObject.keyCode){
+ keyObject.charOrCode = keyObject.keyCode;
+ dojo.deprecated("keyCode attribute parameter for dijit.typematic.addKeyListener is deprecated. Use charOrCode instead.", "", "2.0");
+ }else if(keyObject.charCode){
+ keyObject.charOrCode = String.fromCharCode(keyObject.charCode);
+ dojo.deprecated("charCode attribute parameter for dijit.typematic.addKeyListener is deprecated. Use charOrCode instead.", "", "2.0");
+ }
+ return [
+ dojo.connect(node, "onkeypress", this, function(evt){
+ if(evt.charOrCode == keyObject.charOrCode &&
+ (keyObject.ctrlKey === undefined || keyObject.ctrlKey == evt.ctrlKey) &&
+ (keyObject.altKey === undefined || keyObject.altKey == evt.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.config.blankGif || 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");
+ if(dojo.isIE){
+ div.outerHTML = ""; // prevent mixed-content warning, see http://support.microsoft.com/kb/925014
+ }else{
+ dojo.body().removeChild(div);
+ }
+ }
+ }
+};
+
+// Test if computer is in high contrast mode.
+// Make sure the a11y test runs first, before widgets are instantiated.
+if(dojo.isIE || dojo.isMoz){ // NOTE: checking in Safari messes things up
+ dojo._loaders.unshift(dijit.wai.onload);
+}
+
+dojo.mixin(dijit,
+{
+ _XhtmlRoles: /banner|contentinfo|definition|main|navigation|search|note|secondary|seealso/,
+
+ hasWaiRole: function(/*Element*/ elem, /*String*/ role){
+ // summary: Determines if an element has a particular non-XHTML role.
+ // returns: true if elem has the specific non-XHTML role attribute and false if not.
+ // for backwards compatibility if role parameter not provided,
+ // returns true if has non XHTML role
+ var waiRole = this.getWaiRole(elem);
+ if (role){
+ return (waiRole.indexOf(role) > -1);
+ }else{
+ return (waiRole.length >0);
+ }
+ },
+
+ getWaiRole: function(/*Element*/ elem){
+ // summary: Gets the non-XHTML role for an element (which should be a wai role).
+ // returns:
+ // The non-XHTML role of elem or an empty string if elem
+ // does not have a role.
+ return dojo.trim((dojo.attr(elem, "role") || "").replace(this._XhtmlRoles,"").replace("wairole:",""));
+ },
+
+ setWaiRole: function(/*Element*/ elem, /*String*/ role){
+ // summary: Sets the role on an element.
+ // description:
+ // in other than FF2 replace existing role attribute with new role
+ // FF3 supports XHTML and ARIA roles so
+ // If elem already has an XHTML role, append this role to XHTML role
+ // and remove other ARIA roles
+ // On Firefox 2 and below, "wairole:" is
+ // prepended to the provided role value.
+
+ var curRole = (theRole = dojo.attr(elem, "role")) ? theRole : "";
+ if (dojo.isFF<3 || !this._XhtmlRoles.test(curRole)){
+ dojo.attr(elem, "role", dojo.isFF<3 ? "wairole:" + role : role);
+ }else{
+ if((" "+ curRole +" ").indexOf(" " + role + " ") < 0){
+ var clearXhtml = dojo.trim(curRole.replace(this._XhtmlRoles, ""));
+ var cleanRole = dojo.trim(curRole.replace(clearXhtml, ""));
+ dojo.attr(elem, "role", cleanRole + (cleanRole ? ' ' : '') + role);
+ }
+ }
+ },
+
+ removeWaiRole: function(/*Element*/ elem, /*String*/ role){
+ // summary: Removes the specified non-XHTML role from an element.
+ // removes role attribute if no specific role provided (for backwards compat.)
+
+ var roleValue = dojo.attr(elem, "role");
+ if (!roleValue){ return; }
+ if(role){
+ var searchRole = dojo.isFF < 3 ? "wairole:" + role : role;
+ var t = dojo.trim((" " + roleValue + " ").replace(" " + searchRole + " ", " "));
+ dojo.attr(elem, "role", t);
+ }else{
+ elem.removeAttribute("role");
+ }
+ },
+
+ hasWaiState: function(/*Element*/ elem, /*String*/ state){
+ // summary: Determines if an element has a given state.
+ // description:
+ // 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 < 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 < 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 < 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 < 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");
+
+
+
+
+
+
+
+
+
+
+
+}
+
+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.connect(dojo, "connect",
+ function(/*Widget*/ widget, /*String*/ event){
+ if(widget && dojo.isFunction(widget._onConnect)){
+ widget._onConnect(event);
+ }
+ });
+
+dijit._connectOnUseEventHandler = function(/*Event*/ event){};
+
+(function(){
+
+var _attrReg = {};
+var getAttrReg = function(dc){
+ if(!_attrReg[dc]){
+ var r = [];
+ var attrs;
+ var proto = dojo.getObject(dc).prototype;
+ for(var fxName in proto){
+ if(dojo.isFunction(proto[fxName]) && (attrs = fxName.match(/^_set([a-zA-Z]*)Attr$/)) && attrs[1]){
+ r.push(attrs[1].charAt(0).toLowerCase() + attrs[1].substr(1));
+ }
+ }
+ _attrReg[dc] = r;
+ }
+ return _attrReg[dc]||[];
+}
+
+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 dojoAttachPoint syntax, but the domNode
+ // property is the canonical "top level" node in widget UI.
+ domNode: null,
+
+ // containerNode: DomNode
+ // Designates where children of the source dom node will be placed.
+ // "Children" in this case refers to both dom nodes and widgets.
+ // For example, for myWidget:
+ //
+ // | <div dojoType=myWidget>
+ // | <b> here's a plain dom node
+ // | <span dojoType=subWidget>and a widget</span>
+ // | <i> and another plain dom node </i>
+ // | </div>
+ //
+ // containerNode would point to:
+ //
+ // | <b> here's a plain dom node
+ // | <span dojoType=subWidget>and a widget</span>
+ // | <i> and another plain dom node </i>
+ //
+ // In templated widgets, "containerNode" is set via a
+ // dojoAttachPoint assignment.
+ //
+ // containerNode must be defined for any widget that accepts innerHTML
+ // (like ContentPane or BorderContainer or even Button), and conversely
+ // is null for widgets that don't, like TextBox.
+ containerNode: null,
+
+ // attributeMap: Object
+ // attributeMap sets up a "binding" between attributes (aka properties)
+ // of the widget and the widget's DOM.
+ // Changes to widget attributes listed in attributeMap will be
+ // reflected into the DOM.
+ //
+ // For example, calling attr('title', 'hello')
+ // on a TitlePane will automatically cause the TitlePane's DOM to update
+ // with the new title.
+ //
+ // attributeMap is a hash where the key is an attribute of the widget,
+ // and the value reflects a binding to a:
+ //
+ // - DOM node attribute
+ // | focus: {node: "focusNode", type: "attribute"}
+ // Maps this.focus to this.focusNode.focus
+ //
+ // - DOM node innerHTML
+ // | title: { node: "titleNode", type: "innerHTML" }
+ // Maps this.title to this.titleNode.innerHTML
+ //
+ // - DOM node CSS class
+ // | myClass: { node: "domNode", type: "class" }
+ // Maps this.myClass to this.domNode.className
+ //
+ // If the value is an array, then each element in the array matches one of the
+ // formats of the above list.
+ //
+ // There are also some shorthands for backwards compatibility:
+ // - string --> { node: string, type: "attribute" }, for example:
+ // | "focusNode" ---> { node: "focusNode", type: "attribute" }
+ // - "" --> { node: "domNode", type: "attribute" }
+ attributeMap: {id:"", dir:"", lang:"", "class":"", style:"", title:""},
+
+ // _deferredConnects: Object
+ // attributeMap addendum for event handlers that should be connected only on first use
+ _deferredConnects: {
+ onClick: "",
+ onDblClick: "",
+ onKeyDown: "",
+ onKeyPress: "",
+ onKeyUp: "",
+ onMouseMove: "",
+ onMouseDown: "",
+ onMouseOut: "",
+ onMouseOver: "",
+ onMouseLeave: "",
+ onMouseEnter: "",
+ onMouseUp: ""},
+
+ onClick: dijit._connectOnUseEventHandler,
+ /*=====
+ onClick: function(event){
+ // summary:
+ // Connect to this function to receive notifications of mouse click events.
+ // event: mouse Event
+ },
+ =====*/
+ onDblClick: dijit._connectOnUseEventHandler,
+ /*=====
+ onDblClick: function(event){
+ // summary:
+ // Connect to this function to receive notifications of mouse double click events.
+ // event: mouse Event
+ },
+ =====*/
+ onKeyDown: dijit._connectOnUseEventHandler,
+ /*=====
+ onKeyDown: function(event){
+ // summary:
+ // Connect to this function to receive notifications of keys being pressed down.
+ // event: key Event
+ },
+ =====*/
+ onKeyPress: dijit._connectOnUseEventHandler,
+ /*=====
+ onKeyPress: function(event){
+ // summary:
+ // Connect to this function to receive notifications of printable keys being typed.
+ // event: key Event
+ },
+ =====*/
+ onKeyUp: dijit._connectOnUseEventHandler,
+ /*=====
+ onKeyUp: function(event){
+ // summary:
+ // Connect to this function to receive notifications of keys being released.
+ // event: key Event
+ },
+ =====*/
+ onMouseDown: dijit._connectOnUseEventHandler,
+ /*=====
+ onMouseDown: function(event){
+ // summary:
+ // Connect to this function to receive notifications of when the mouse button is pressed down.
+ // event: mouse Event
+ },
+ =====*/
+ onMouseMove: dijit._connectOnUseEventHandler,
+ /*=====
+ onMouseMove: function(event){
+ // summary:
+ // Connect to this function to receive notifications of when the mouse moves over nodes contained within this widget.
+ // event: mouse Event
+ },
+ =====*/
+ onMouseOut: dijit._connectOnUseEventHandler,
+ /*=====
+ onMouseOut: function(event){
+ // summary:
+ // Connect to this function to receive notifications of when the mouse moves off of nodes contained within this widget.
+ // event: mouse Event
+ },
+ =====*/
+ onMouseOver: dijit._connectOnUseEventHandler,
+ /*=====
+ onMouseOver: function(event){
+ // summary:
+ // Connect to this function to receive notifications of when the mouse moves onto nodes contained within this widget.
+ // event: mouse Event
+ },
+ =====*/
+ onMouseLeave: dijit._connectOnUseEventHandler,
+ /*=====
+ onMouseLeave: function(event){
+ // summary:
+ // Connect to this function to receive notifications of when the mouse moves off of this widget.
+ // event: mouse Event
+ },
+ =====*/
+ onMouseEnter: dijit._connectOnUseEventHandler,
+ /*=====
+ onMouseEnter: function(event){
+ // summary:
+ // Connect to this function to receive notifications of when the mouse moves onto this widget.
+ // event: mouse Event
+ },
+ =====*/
+ onMouseUp: dijit._connectOnUseEventHandler,
+ /*=====
+ onMouseUp: function(event){
+ // summary:
+ // Connect to this function to receive notifications of when the mouse button is released.
+ // event: mouse Event
+ },
+ =====*/
+
+ // Constants used in templates
+ _blankGif: (dojo.config.blankGif || dojo.moduleUrl("dojo", "resources/blank.gif")),
+
+ //////////// INITIALIZATION METHODS ///////////////////////////////////////
+
+ postscript: function(/*Object?*/params, /*DomNode|String*/srcNodeRef){
+ // summary: kicks off widget instantiation, see create() for details.
+ this.create(params, srcNodeRef);
+ },
+
+ create: function(/*Object?*/params, /*DomNode|String?*/srcNodeRef){
+ // summary:
+ // Kick off the life-cycle of a widget
+ // params:
+ // Hash of initialization parameters for widget, including
+ // scalar values (like title, duration etc.) and functions,
+ // typically callbacks like onClick.
+ // srcNodeRef:
+ // If a srcNodeRef (dom node) is specified:
+ // - use srcNodeRef.innerHTML as my contents
+ // - if this is a behavioral widget then apply behavior
+ // to that srcNodeRef
+ // - otherwise, replace srcNodeRef with my generated DOM
+ // tree
+ // description:
+ // 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 = [];
+
+ // To avoid double-connects, remove entries from _deferredConnects
+ // that have been setup manually by a subclass (ex, by dojoAttachEvent).
+ // If a subclass has redefined a callback (ex: onClick) then assume it's being
+ // connected to manually.
+ this._deferredConnects = dojo.clone(this._deferredConnects);
+ for(var attr in this.attributeMap){
+ delete this._deferredConnects[attr]; // can't be in both attributeMap and _deferredConnects
+ }
+ for(attr in this._deferredConnects){
+ if(this[attr] !== dijit._connectOnUseEventHandler){
+ delete this._deferredConnects[attr]; // redefined, probably dojoAttachEvent exists
+ }
+ }
+
+ //mixin our passed parameters
+ if(this.srcNodeRef && (typeof this.srcNodeRef.id == "string")){ this.id = this.srcNodeRef.id; }
+ if(params){
+ this.params = params;
+ dojo.mixin(this,params);
+ }
+ this.postMixInProperties();
+
+ // generate an id for the widget if one wasn't specified
+ // (be sure to do this before buildRendering() because that function might
+ // expect the id to be there.)
+ if(!this.id){
+ this.id = dijit.getUniqueId(this.declaredClass.replace(/\./g,"_"));
+ }
+ dijit.registry.add(this);
+
+ this.buildRendering();
+
+ if(this.domNode){
+ // Copy attributes listed in attributeMap into the [newly created] DOM for the widget.
+ this._applyAttributes();
+
+ // If the developer has specified a handler as a widget parameter
+ // (ex: new Button({onClick: ...})
+ // then naturally need to connect from dom node to that handler immediately,
+ for(attr in this.params){
+ this._onConnect(attr);
+ }
+ }
+
+ if(this.domNode){
+ this.domNode.setAttribute("widgetId", this.id);
+ }
+ this.postCreate();
+
+ // If srcNodeRef has been processed and removed from the DOM (e.g. TemplatedWidget) then delete it to allow GC.
+ if(this.srcNodeRef && !this.srcNodeRef.parentNode){
+ delete this.srcNodeRef;
+ }
+
+ this._created = true;
+ },
+
+ _applyAttributes: function(){
+ // summary:
+ // Step during widget creation to copy all widget attributes to the
+ // DOM as per attributeMap and _setXXXAttr functions.
+ // description:
+ // Skips over blank/false attribute values, unless they were explicitly specified
+ // as parameters to the widget, since those are the default anyway,
+ // and setting tabIndex="" is different than not setting tabIndex at all.
+ //
+ // It processes the attributes in the attribute map first, ant then
+ // it goes through and processes the attributes for the _setXXXAttr
+ // functions that have been specified
+ var condAttrApply = function(attr, scope){
+ if( (scope.params && attr in scope.params) || scope[attr]){
+ scope.attr(attr, scope[attr]);
+ }
+ };
+ for(var attr in this.attributeMap){
+ condAttrApply(attr, this);
+ }
+ dojo.forEach(getAttrReg(this.declaredClass), function(a){
+ if(!(a in this.attributeMap)){
+ condAttrApply(a, this);
+ }
+ }, this);
+ },
+
+ postMixInProperties: function(){
+ // summary:
+ // Called after the parameters to the widget have been read-in,
+ // but before the widget template is instantiated. Especially
+ // useful to set properties that are referenced in the widget
+ // template.
+ },
+
+ buildRendering: function(){
+ // summary:
+ // Construct the UI for this widget, setting this.domNode. Most
+ // widgets will mixin dijit._Templated, which implements 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?*/ preserveDom){
+ // 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.
+ // preserveDom:
+ // If true, this method will leave the original Dom structure
+ // alone of descendant Widgets. Note: This will NOT work with
+ // dijit._Templated widgets.
+ //
+ this.destroyDescendants(preserveDom);
+ this.destroy(preserveDom);
+ },
+
+ destroy: function(/*Boolean*/ preserveDom){
+ // summary:
+ // Destroy this widget, but not its descendants.
+ // Will, however, destroy internal widgets such as those used within a template.
+ // preserveDom: Boolean
+ // If true, this method will leave the original Dom structure alone.
+ // Note: This will not yet work with _Templated widgets
+
+ this.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){
+ if(w.destroy){
+ w.destroy();
+ }
+ });
+
+ this.destroyRendering(preserveDom);
+ dijit.registry.remove(this.id);
+ },
+
+ destroyRendering: function(/*Boolean?*/ preserveDom){
+ // summary:
+ // Destroys the DOM nodes associated with this widget
+ // preserveDom:
+ // If true, this method will leave the original Dom structure alone
+ // during tear-down. Note: this will not work with _Templated
+ // widgets yet.
+
+ if(this.bgIframe){
+ this.bgIframe.destroy(preserveDom);
+ delete this.bgIframe;
+ }
+
+ if(this.domNode){
+ if(!preserveDom){
+ dojo._destroyElement(this.domNode);
+ }
+ delete this.domNode;
+ }
+
+ if(this.srcNodeRef){
+ if(!preserveDom){
+ dojo._destroyElement(this.srcNodeRef);
+ }
+ delete this.srcNodeRef;
+ }
+ },
+
+ destroyDescendants: function(/*Boolean?*/ preserveDom){
+ // summary:
+ // Recursively destroy the children of this widget and their
+ // descendants.
+ // preserveDom:
+ // If true, the preserveDom attribute is passed to all descendant
+ // widget's .destroy() method. Not for use with _Templated
+ // widgets.
+
+ // TODO: should I destroy in the reverse order, to go bottom up?
+ dojo.forEach(this.getDescendants(), function(widget){
+ if(widget.destroy){
+ widget.destroy(preserveDom);
+ }
+ });
+ },
+
+
+ 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();
+ },
+
+ _onConnect: function(/*String*/ event){
+ // summary:
+ // Called when someone connects to one of my handlers.
+ // "Turn on" that handler if it isn't active yet.
+ if(event in this._deferredConnects){
+ var mapNode = this[this._deferredConnects[event]||'domNode'];
+ this.connect(mapNode, event.toLowerCase(), this[event]);
+ delete this._deferredConnects[event];
+ }
+ },
+
+ _setClassAttr: function(/*String*/ value){
+ var mapNode = this[this.attributeMap["class"]||'domNode'];
+ dojo.removeClass(mapNode, this["class"])
+ this["class"] = value;
+ dojo.addClass(mapNode, value);
+ },
+
+ _setStyleAttr: function(/*String*/ value){
+ var mapNode = this[this.attributeMap["style"]||'domNode'];
+ if(mapNode.style.cssText){
+ // TODO: remove old value
+ mapNode.style.cssText += "; " + value; // FIXME: Opera
+ }else{
+ mapNode.style.cssText = value;
+ }
+ this["style"] = value;
+ },
+
+ setAttribute: function(/*String*/ attr, /*anything*/ value){
+ dojo.deprecated(this.declaredClass+"::setAttribute() is deprecated. Use attr() instead.", "", "2.0");
+ this.attr(attr, value);
+ },
+
+ _attrToDom: function(/*String*/ attr, /*String*/ value){
+ // summary:
+ // Reflect a widget attribute (title, tabIndex, duration etc.) to
+ // the widget DOM, as specified in attributeMap.
+ //
+ // description:
+ // Also sets this["attr"] to the new value.
+ // Note some attributes like "type"
+ // cannot be processed this way as they are not mutable.
+
+ var commands = this.attributeMap[attr];
+ dojo.forEach( dojo.isArray(commands) ? commands : [commands], function(command){
+
+ // Get target node and what we are doing to that node
+ var mapNode = this[command.node || command || "domNode"]; // DOM node
+ var type = command.type || "attribute"; // class, innerHTML, or attribute
+
+ switch(type){
+ case "attribute":
+ if(dojo.isFunction(value)){ // functions execute in the context of the widget
+ value = dojo.hitch(this, value);
+ }
+ if(/^on[A-Z][a-zA-Z]*$/.test(attr)){ // eg. onSubmit needs to be onsubmit
+ attr = attr.toLowerCase();
+ }
+ dojo.attr(mapNode, attr, value);
+ break;
+ case "innerHTML":
+ mapNode.innerHTML = value;
+ break;
+ case "class":
+ dojo.removeClass(mapNode, this[attr]);
+ dojo.addClass(mapNode, value);
+ break;
+ }
+ }, this);
+ this[attr] = value;
+ },
+
+ attr: function(/*String|Object*/name, /*Object?*/value){
+ // summary:
+ // Set or get properties on a widget instance.
+ // name:
+ // The property to get or set. If an object is passed here and not
+ // a string, its keys are used as names of attributes to be set
+ // and the value of the object as values to set in the widget.
+ // value:
+ // Optional. If provided, attr() operates as a setter. If omitted,
+ // the current value of the named property is returned.
+ // description:
+ // Get or set named properties on a widget. If no value is
+ // provided, the current value of the attribute is returned,
+ // potentially via a getter method. If a value is provided, then
+ // the method acts as a setter, assigning the value to the name,
+ // potentially calling any explicitly provided setters to handle
+ // the operation. For instance, if the widget has properties "foo"
+ // and "bar" and a method named "_setFooAttr", calling:
+ // | myWidget.attr("foo", "Howdy!");
+ // would be equivalent to calling:
+ // | widget._setFooAttr("Howdy!");
+ // while calling:
+ // | myWidget.attr("bar", "Howdy!");
+ // would be the same as writing:
+ // | widget.bar = "Howdy!";
+ // It also tries to copy the changes to the widget's DOM according
+ // to settings in attributeMap (see description of attributeMap
+ // for details)
+ // For example, calling:
+ // | myTitlePane.attr("title", "Howdy!");
+ // will do
+ // | myTitlePane.title = "Howdy!";
+ // | myTitlePane.title.innerHTML = "Howdy!";
+ // It works for dom node attributes too. Calling
+ // | widget.attr("disabled", true)
+ // will set the disabled attribute on the widget's focusNode,
+ // among other housekeeping for a change in disabled state.
+
+ // open questions:
+ // - how to handle build shortcut for attributes which want to map
+ // into DOM attributes?
+ // - what relationship should setAttribute()/attr() have to
+ // layout() calls?
+ var args = arguments.length;
+ if(args == 1 && !dojo.isString(name)){
+ for(var x in name){ this.attr(x, name[x]); }
+ return this;
+ }
+ var names = this._getAttrNames(name);
+ if(args == 2){ // setter
+ if(this[names.s]){
+ // use the explicit setter
+ return this[names.s](value) || this;
+ }else{
+ // if param is specified as DOM node attribute, copy it
+ if(name in this.attributeMap){
+ this._attrToDom(name, value);
+ }
+
+ // FIXME: what about function assignments? Any way to connect() here?
+ this[name] = value;
+ }
+ return this;
+ }else{ // getter
+ if(this[names.g]){
+ return this[names.g]();
+ }else{
+ return this[name];
+ }
+ }
+ },
+
+ _attrPairNames: {}, // shared between all widgets
+ _getAttrNames: function(name){
+ // summary: helper function for Widget.attr()
+ // cache attribute name values so we don't do the string ops every time
+ var apn = this._attrPairNames;
+ if(apn[name]){ return apn[name]; }
+ var uc = name.charAt(0).toUpperCase() + name.substr(1);
+ return apn[name] = {
+ n: name+"Node",
+ s: "_set"+uc+"Attr",
+ g: "_get"+uc+"Attr"
+ };
+ },
+
+ toString: function(){
+ // summary:
+ // returns a string that represents the widget. 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.
+ // description:
[... 16274 lines stripped ...]
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@labs.apache.org
For additional commands, e-mail: commits-help@labs.apache.org