,
// so reattach it to win.doc.body. (Otherwise, the positioning will be wrong
// and also it might get cutoff)
if(!node.parentNode || String(node.parentNode.tagName).toLowerCase() != "body"){
win.body(node.ownerDocument).appendChild(node);
}
var best = null;
array.some(choices, function(choice){
var corner = choice.corner;
var pos = choice.pos;
var overflow = 0;
// calculate amount of space available given specified position of node
var spaceAvailable = {
w: {
'L': view.l + view.w - pos.x,
'R': pos.x - view.l,
'M': view.w
}[corner.charAt(1)],
h: {
'T': view.t + view.h - pos.y,
'B': pos.y - view.t,
'M': view.h
}[corner.charAt(0)]
};
// Clear left/right position settings set earlier so they don't interfere with calculations,
// specifically when layoutNode() (a.k.a. Tooltip.orient()) measures natural width of Tooltip
var s = node.style;
s.left = s.right = "auto";
// 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 tooltip's size changes based on position, due to triangle)
if(layoutNode){
var res = layoutNode(node, choice.aroundCorner, corner, spaceAvailable, aroundNodeCoords);
overflow = typeof res == "undefined" ? 0 : res;
}
// get node's size
var style = node.style;
var oldDisplay = style.display;
var oldVis = style.visibility;
if(style.display == "none"){
style.visibility = "hidden";
style.display = "";
}
var bb = domGeometry.position(node);
style.display = oldDisplay;
style.visibility = oldVis;
// coordinates and size of node with specified corner placed at pos,
// and clipped by viewport
var
startXpos = {
'L': pos.x,
'R': pos.x - bb.w,
'M': Math.max(view.l, Math.min(view.l + view.w, pos.x + (bb.w >> 1)) - bb.w) // M orientation is more flexible
}[corner.charAt(1)],
startYpos = {
'T': pos.y,
'B': pos.y - bb.h,
'M': Math.max(view.t, Math.min(view.t + view.h, pos.y + (bb.h >> 1)) - bb.h)
}[corner.charAt(0)],
startX = Math.max(view.l, startXpos),
startY = Math.max(view.t, startYpos),
endX = Math.min(view.l + view.w, startXpos + bb.w),
endY = Math.min(view.t + view.h, startYpos + bb.h),
width = endX - startX,
height = endY - startY;
overflow += (bb.w - width) + (bb.h - height);
if(best == null || overflow < best.overflow){
best = {
corner: corner,
aroundCorner: choice.aroundCorner,
x: startX,
y: startY,
w: width,
h: height,
overflow: overflow,
spaceAvailable: spaceAvailable
};
}
return !overflow;
});
// In case the best position is not the last one we checked, need to call
// layoutNode() again.
if(best.overflow && layoutNode){
layoutNode(node, best.aroundCorner, best.corner, best.spaceAvailable, aroundNodeCoords);
}
// And then position the node. Do this last, after the layoutNode() above
// has sized the node, due to browser quirks when the viewport is scrolled
// (specifically that a Tooltip will shrink to fit as though the window was
// scrolled to the left).
var s = node.style;
s.top = best.y + "px";
s.left = best.x + "px";
s.right = "auto"; // needed for FF or else tooltip goes to far left
return best;
}
var place = {
// summary:
// Code to place a DOMNode relative to another DOMNode.
// Load using require(["dijit/place"], function(place){ ... }).
at: function(node, pos, corners, padding){
// summary:
// Positions one of the node's corners at specified position
// such that node is fully visible in viewport.
// description:
// NOTE: node is assumed to be absolutely or relatively positioned.
// node: DOMNode
// The node to position
// pos: dijit/place.__Position
// Object like {x: 10, y: 20}
// corners: String[]
// Array of Strings representing order to try corners in, like ["TR", "BL"].
// Possible values are:
//
// - "BL" - bottom left
// - "BR" - bottom right
// - "TL" - top left
// - "TR" - top right
// padding: dijit/place.__Position?
// optional param to set padding, to put some buffer around the element you want to position.
// example:
// Try to place node's top right corner at (10,20).
// If that makes node go (partially) off screen, then try placing
// bottom left corner at (10,20).
// | place(node, {x: 10, y: 20}, ["TR", "BL"])
var choices = array.map(corners, function(corner){
var c = { corner: corner, pos: {x:pos.x,y:pos.y} };
if(padding){
c.pos.x += corner.charAt(1) == 'L' ? padding.x : -padding.x;
c.pos.y += corner.charAt(0) == 'T' ? padding.y : -padding.y;
}
return c;
});
return _place(node, choices);
},
around: function(
/*DomNode*/ node,
/*DomNode|dijit/place.__Rectangle*/ anchor,
/*String[]*/ positions,
/*Boolean*/ leftToRight,
/*Function?*/ layoutNode){
// summary:
// Position node adjacent or kitty-corner to anchor
// 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.
// anchor:
// Either a DOMNode or a rectangle (object with x, y, width, height).
// positions:
// Ordered list of positions to try matching up.
//
// - before: places drop down to the left of the anchor node/widget, or to the right in the case
// of RTL scripts like Hebrew and Arabic; aligns either the top of the drop down
// with the top of the anchor, or the bottom of the drop down with bottom of the anchor.
// - after: places drop down to the right of the anchor node/widget, or to the left in the case
// of RTL scripts like Hebrew and Arabic; aligns either the top of the drop down
// with the top of the anchor, or the bottom of the drop down with bottom of the anchor.
// - before-centered: centers drop down to the left of the anchor node/widget, or to the right
// in the case of RTL scripts like Hebrew and Arabic
// - after-centered: centers drop down to the right of the anchor node/widget, or to the left
// in the case of RTL scripts like Hebrew and Arabic
// - above-centered: drop down is centered above anchor node
// - above: drop down goes above anchor node, left sides aligned
// - above-alt: drop down goes above anchor node, right sides aligned
// - below-centered: drop down is centered above anchor node
// - below: drop down goes below anchor node
// - below-alt: drop down goes below anchor node, right sides aligned
// 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.
// leftToRight:
// True if widget is LTR, false if widget is RTL. Affects the behavior of "above" and "below"
// positions slightly.
// example:
// | placeAroundNode(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)
//
// if around is a DOMNode (or DOMNode id), convert to coordinates
var aroundNodePos = (typeof anchor == "string" || "offsetWidth" in anchor || "ownerSVGElement" in anchor)
? domGeometry.position(anchor, true)
: anchor;
// Compute position and size of visible part of anchor (it may be partially hidden by ancestor nodes w/scrollbars)
if(anchor.parentNode){
// ignore nodes between position:relative and position:absolute
var sawPosAbsolute = domStyle.getComputedStyle(anchor).position == "absolute";
var parent = anchor.parentNode;
while(parent && parent.nodeType == 1 && parent.nodeName != "BODY"){ //ignoring the body will help performance
var parentPos = domGeometry.position(parent, true),
pcs = domStyle.getComputedStyle(parent);
if(/relative|absolute/.test(pcs.position)){
sawPosAbsolute = false;
}
if(!sawPosAbsolute && /hidden|auto|scroll/.test(pcs.overflow)){
var bottomYCoord = Math.min(aroundNodePos.y + aroundNodePos.h, parentPos.y + parentPos.h);
var rightXCoord = Math.min(aroundNodePos.x + aroundNodePos.w, parentPos.x + parentPos.w);
aroundNodePos.x = Math.max(aroundNodePos.x, parentPos.x);
aroundNodePos.y = Math.max(aroundNodePos.y, parentPos.y);
aroundNodePos.h = bottomYCoord - aroundNodePos.y;
aroundNodePos.w = rightXCoord - aroundNodePos.x;
}
if(pcs.position == "absolute"){
sawPosAbsolute = true;
}
parent = parent.parentNode;
}
}
var x = aroundNodePos.x,
y = aroundNodePos.y,
width = "w" in aroundNodePos ? aroundNodePos.w : (aroundNodePos.w = aroundNodePos.width),
height = "h" in aroundNodePos ? aroundNodePos.h : (kernel.deprecated("place.around: dijit/place.__Rectangle: { x:"+x+", y:"+y+", height:"+aroundNodePos.height+", width:"+width+" } has been deprecated. Please use { x:"+x+", y:"+y+", h:"+aroundNodePos.height+", w:"+width+" }", "", "2.0"), aroundNodePos.h = aroundNodePos.height);
// Convert positions arguments into choices argument for _place()
var choices = [];
function push(aroundCorner, corner){
choices.push({
aroundCorner: aroundCorner,
corner: corner,
pos: {
x: {
'L': x,
'R': x + width,
'M': x + (width >> 1)
}[aroundCorner.charAt(1)],
y: {
'T': y,
'B': y + height,
'M': y + (height >> 1)
}[aroundCorner.charAt(0)]
}
})
}
array.forEach(positions, function(pos){
var ltr = leftToRight;
switch(pos){
case "above-centered":
push("TM", "BM");
break;
case "below-centered":
push("BM", "TM");
break;
case "after-centered":
ltr = !ltr;
// fall through
case "before-centered":
push(ltr ? "ML" : "MR", ltr ? "MR" : "ML");
break;
case "after":
ltr = !ltr;
// fall through
case "before":
push(ltr ? "TL" : "TR", ltr ? "TR" : "TL");
push(ltr ? "BL" : "BR", ltr ? "BR" : "BL");
break;
case "below-alt":
ltr = !ltr;
// fall through
case "below":
// first try to align left borders, next try to align right borders (or reverse for RTL mode)
push(ltr ? "BL" : "BR", ltr ? "TL" : "TR");
push(ltr ? "BR" : "BL", ltr ? "TR" : "TL");
break;
case "above-alt":
ltr = !ltr;
// fall through
case "above":
// first try to align left borders, next try to align right borders (or reverse for RTL mode)
push(ltr ? "TL" : "TR", ltr ? "BL" : "BR");
push(ltr ? "TR" : "TL", ltr ? "BR" : "BL");
break;
default:
// To assist dijit/_base/place, accept arguments of type {aroundCorner: "BL", corner: "TL"}.
// Not meant to be used directly.
push(pos.aroundCorner, pos.corner);
}
});
var position = _place(node, choices, layoutNode, {w: width, h: height});
position.aroundNodePos = aroundNodePos;
return position;
}
};
/*=====
place.__Position = {
// x: Integer
// horizontal coordinate in pixels, relative to document body
// y: Integer
// vertical coordinate in pixels, relative to document body
};
place.__Rectangle = {
// x: Integer
// horizontal offset in pixels, relative to document body
// y: Integer
// vertical offset in pixels, relative to document body
// w: Integer
// width in pixels. Can also be specified as "width" for backwards-compatibility.
// h: Integer
// height in pixels. Can also be specified as "height" for backwards-compatibility.
};
=====*/
return dijit.place = place; // setting dijit.place for back-compat, remove for 2.0
});
},
'dijit/Viewport':function(){
define("dijit/Viewport", [
"dojo/Evented",
"dojo/on",
"dojo/ready",
"dojo/sniff",
"dojo/_base/window", // global
"dojo/window" // getBox()
], function(Evented, on, ready, has, win, winUtils){
// module:
// dijit/Viewport
/*=====
return {
// summary:
// Utility singleton to watch for viewport resizes, avoiding duplicate notifications
// which can lead to infinite loops.
// description:
// Usage: Viewport.on("resize", myCallback).
//
// myCallback() is called without arguments in case it's _WidgetBase.resize(),
// which would interpret the argument as the size to make the widget.
};
=====*/
var Viewport = new Evented();
var focusedNode;
ready(200, function(){
var oldBox = winUtils.getBox();
Viewport._rlh = on(win.global, "resize", function(){
var newBox = winUtils.getBox();
if(oldBox.h == newBox.h && oldBox.w == newBox.w){ return; }
oldBox = newBox;
Viewport.emit("resize");
});
// Also catch zoom changes on IE8, since they don't naturally generate resize events
if(has("ie") == 8){
var deviceXDPI = screen.deviceXDPI;
setInterval(function(){
if(screen.deviceXDPI != deviceXDPI){
deviceXDPI = screen.deviceXDPI;
Viewport.emit("resize");
}
}, 500);
}
// On iOS, keep track of the focused node so we can guess when the keyboard is/isn't being displayed.
if(has("ios")){
on(document, "focusin", function(evt){
focusedNode = evt.target;
});
on(document, "focusout", function(evt){
focusedNode = null;
});
}
});
Viewport.getEffectiveBox = function(/*Document*/ doc){
// summary:
// Get the size of the viewport, or on mobile devices, the part of the viewport not obscured by the
// virtual keyboard.
var box = winUtils.getBox(doc);
// Account for iOS virtual keyboard, if it's being shown. Unfortunately no direct way to check or measure.
var tag = focusedNode && focusedNode.tagName && focusedNode.tagName.toLowerCase();
if(has("ios") && focusedNode && !focusedNode.readOnly && (tag == "textarea" || (tag == "input" &&
/^(color|email|number|password|search|tel|text|url)$/.test(focusedNode.type)))){
// Box represents the size of the viewport. Some of the viewport is likely covered by the keyboard.
// Estimate height of visible viewport assuming viewport goes to bottom of screen, but is covered by keyboard.
box.h *= (orientation == 0 || orientation == 180 ? 0.66 : 0.40);
// Above measurement will be inaccurate if viewport was scrolled up so far that it ends before the bottom
// of the screen. In this case, keyboard isn't covering as much of the viewport as we thought.
// We know the visible size is at least the distance from the top of the viewport to the focused node.
var rect = focusedNode.getBoundingClientRect();
box.h = Math.max(box.h, rect.top + rect.height);
}
return box;
};
return Viewport;
});
},
'dojo/window':function(){
define(["./_base/lang", "./sniff", "./_base/window", "./dom", "./dom-geometry", "./dom-style", "./dom-construct"],
function(lang, has, baseWindow, dom, geom, style, domConstruct){
// feature detection
/* not needed but included here for future reference
has.add("rtl-innerVerticalScrollBar-on-left", function(win, doc){
var body = baseWindow.body(doc),
scrollable = domConstruct.create('div', {
style: {overflow:'scroll', overflowX:'hidden', direction:'rtl', visibility:'hidden', position:'absolute', left:'0', width:'64px', height:'64px'}
}, body, "last"),
center = domConstruct.create('center', {
style: {overflow:'hidden', direction:'ltr'}
}, scrollable, "last"),
inner = domConstruct.create('div', {
style: {overflow:'visible', display:'inline' }
}, center, "last");
inner.innerHTML=" ";
var midPoint = Math.max(inner.offsetLeft, geom.position(inner).x);
var ret = midPoint >= 32;
center.removeChild(inner);
scrollable.removeChild(center);
body.removeChild(scrollable);
return ret;
});
*/
has.add("rtl-adjust-position-for-verticalScrollBar", function(win, doc){
var body = baseWindow.body(doc),
scrollable = domConstruct.create('div', {
style: {overflow:'scroll', overflowX:'visible', direction:'rtl', visibility:'hidden', position:'absolute', left:'0', top:'0', width:'64px', height:'64px'}
}, body, "last"),
div = domConstruct.create('div', {
style: {overflow:'hidden', direction:'ltr'}
}, scrollable, "last"),
ret = geom.position(div).x != 0;
scrollable.removeChild(div);
body.removeChild(scrollable);
return ret;
});
has.add("position-fixed-support", function(win, doc){
// IE6, IE7+quirks, and some older mobile browsers don't support position:fixed
var body = baseWindow.body(doc),
outer = domConstruct.create('span', {
style: {visibility:'hidden', position:'fixed', left:'1px', top:'1px'}
}, body, "last"),
inner = domConstruct.create('span', {
style: {position:'fixed', left:'0', top:'0'}
}, outer, "last"),
ret = geom.position(inner).x != geom.position(outer).x;
outer.removeChild(inner);
body.removeChild(outer);
return ret;
});
// module:
// dojo/window
var window = {
// summary:
// TODOC
getBox: function(/*Document?*/ doc){
// summary:
// Returns the dimensions and scroll position of the viewable area of a browser window
doc = doc || baseWindow.doc;
var
scrollRoot = (doc.compatMode == 'BackCompat') ? baseWindow.body(doc) : doc.documentElement,
// get scroll position
scroll = geom.docScroll(doc), // scrollRoot.scrollTop/Left should work
w, h;
if(has("touch")){ // if(scrollbars not supported)
var uiWindow = window.get(doc); // use UI window, not dojo.global window
// on mobile, scrollRoot.clientHeight <= uiWindow.innerHeight <= scrollRoot.offsetHeight, return uiWindow.innerHeight
w = uiWindow.innerWidth || scrollRoot.clientWidth; // || scrollRoot.clientXXX probably never evaluated
h = uiWindow.innerHeight || scrollRoot.clientHeight;
}else{
// on desktops, scrollRoot.clientHeight <= scrollRoot.offsetHeight <= uiWindow.innerHeight, return scrollRoot.clientHeight
// uiWindow.innerWidth/Height includes the scrollbar and cannot be used
w = scrollRoot.clientWidth;
h = scrollRoot.clientHeight;
}
return {
l: scroll.x,
t: scroll.y,
w: w,
h: h
};
},
get: function(/*Document*/ doc){
// summary:
// Get window object associated with document doc.
// doc:
// The document to get the associated window for.
// 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(has("ie") && window !== document.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.defaultView; // Window
},
scrollIntoView: function(/*DomNode*/ node, /*Object?*/ pos){
// summary:
// Scroll the passed node into view using minimal movement, if it is not already.
// Don't rely on node.scrollIntoView working just because the function is there since
// it forces the node to the page's bottom or top (and left or right in IE) without consideration for the minimal movement.
// WebKit's node.scrollIntoViewIfNeeded doesn't work either for inner scrollbars in right-to-left mode
// and when there's a fixed position scrollable element
try{ // catch unexpected/unrecreatable errors (#7808) since we can recover using a semi-acceptable native method
node = dom.byId(node);
var doc = node.ownerDocument || baseWindow.doc, // TODO: why baseWindow.doc? Isn't node.ownerDocument always defined?
body = baseWindow.body(doc),
html = doc.documentElement || body.parentNode,
isIE = has("ie"),
isWK = has("webkit");
// if an untested browser, then use the native method
if(node == body || node == html){ return; }
if(!(has("mozilla") || isIE || isWK || has("opera") || has("trident")) && ("scrollIntoView" in node)){
node.scrollIntoView(false); // short-circuit to native if possible
return;
}
var backCompat = doc.compatMode == 'BackCompat',
rootWidth = Math.min(body.clientWidth || html.clientWidth, html.clientWidth || body.clientWidth),
rootHeight = Math.min(body.clientHeight || html.clientHeight, html.clientHeight || body.clientHeight),
scrollRoot = (isWK || backCompat) ? body : html,
nodePos = pos || geom.position(node),
el = node.parentNode,
isFixed = function(el){
return (isIE <= 6 || (isIE == 7 && backCompat))
? false
: (has("position-fixed-support") && (style.get(el, 'position').toLowerCase() == "fixed"));
},
self = this,
scrollElementBy = function(el, x, y){
if(el.tagName == "BODY" || el.tagName == "HTML"){
self.get(el.ownerDocument).scrollBy(x, y);
}else{
x && (el.scrollLeft += x);
y && (el.scrollTop += y);
}
};
if(isFixed(node)){ return; } // nothing to do
while(el){
if(el == body){ el = scrollRoot; }
var elPos = geom.position(el),
fixedPos = isFixed(el),
rtl = style.getComputedStyle(el).direction.toLowerCase() == "rtl";
if(el == scrollRoot){
elPos.w = rootWidth; elPos.h = rootHeight;
if(scrollRoot == html && (isIE || has("trident")) && rtl){
elPos.x += scrollRoot.offsetWidth-elPos.w;// IE workaround where scrollbar causes negative x
}
elPos.x = 0;
elPos.y = 0;
}else{
var pb = geom.getPadBorderExtents(el);
elPos.w -= pb.w; elPos.h -= pb.h; elPos.x += pb.l; elPos.y += pb.t;
var clientSize = el.clientWidth,
scrollBarSize = elPos.w - clientSize;
if(clientSize > 0 && scrollBarSize > 0){
if(rtl && has("rtl-adjust-position-for-verticalScrollBar")){
elPos.x += scrollBarSize;
}
elPos.w = clientSize;
}
clientSize = el.clientHeight;
scrollBarSize = elPos.h - clientSize;
if(clientSize > 0 && scrollBarSize > 0){
elPos.h = clientSize;
}
}
if(fixedPos){ // bounded by viewport, not parents
if(elPos.y < 0){
elPos.h += elPos.y; elPos.y = 0;
}
if(elPos.x < 0){
elPos.w += elPos.x; elPos.x = 0;
}
if(elPos.y + elPos.h > rootHeight){
elPos.h = rootHeight - elPos.y;
}
if(elPos.x + elPos.w > rootWidth){
elPos.w = rootWidth - elPos.x;
}
}
// calculate overflow in all 4 directions
var l = nodePos.x - elPos.x, // beyond left: < 0
// t = nodePos.y - Math.max(elPos.y, 0), // beyond top: < 0
t = nodePos.y - elPos.y, // beyond top: < 0
r = l + nodePos.w - elPos.w, // beyond right: > 0
bot = t + nodePos.h - elPos.h; // beyond bottom: > 0
var s, old;
if(r * l > 0 && (!!el.scrollLeft || el == scrollRoot || el.scrollWidth > el.offsetHeight)){
s = Math[l < 0? "max" : "min"](l, r);
if(rtl && ((isIE == 8 && !backCompat) || has("trident") >= 5)){ s = -s; }
old = el.scrollLeft;
scrollElementBy(el, s, 0);
s = el.scrollLeft - old;
nodePos.x -= s;
}
if(bot * t > 0 && (!!el.scrollTop || el == scrollRoot || el.scrollHeight > el.offsetHeight)){
s = Math.ceil(Math[t < 0? "max" : "min"](t, bot));
old = el.scrollTop;
scrollElementBy(el, 0, s);
s = el.scrollTop - old;
nodePos.y -= s;
}
el = (el != scrollRoot) && !fixedPos && el.parentNode;
}
}catch(error){
console.error('scrollIntoView: ' + error);
node.scrollIntoView(false);
}
}
};
1 && lang.setObject("dojo.window", window);
return window;
});
},
'dijit/_Widget':function(){
define("dijit/_Widget", [
"dojo/aspect", // aspect.around
"dojo/_base/config", // config.isDebug
"dojo/_base/connect", // connect.connect
"dojo/_base/declare", // declare
"dojo/has",
"dojo/_base/kernel", // kernel.deprecated
"dojo/_base/lang", // lang.hitch
"dojo/query",
"dojo/ready",
"./registry", // registry.byNode
"./_WidgetBase",
"./_OnDijitClickMixin",
"./_FocusMixin",
"dojo/uacss", // browser sniffing (included for back-compat; subclasses may be using)
"./hccss" // high contrast mode sniffing (included to set CSS classes on , module ret value unused)
], function(aspect, config, connect, declare, has, kernel, lang, query, ready,
registry, _WidgetBase, _OnDijitClickMixin, _FocusMixin){
// module:
// dijit/_Widget
function connectToDomNode(){
// summary:
// If user connects to a widget method === this function, then they will
// instead actually be connecting the equivalent event on this.domNode
}
// Trap dojo.connect() calls to connectToDomNode methods, and redirect to _Widget.on()
function aroundAdvice(originalConnect){
return function(obj, event, scope, method){
if(obj && typeof event == "string" && obj[event] == connectToDomNode){
return obj.on(event.substring(2).toLowerCase(), lang.hitch(scope, method));
}
return originalConnect.apply(connect, arguments);
};
}
aspect.around(connect, "connect", aroundAdvice);
if(kernel.connect){
aspect.around(kernel, "connect", aroundAdvice);
}
var _Widget = declare("dijit._Widget", [_WidgetBase, _OnDijitClickMixin, _FocusMixin], {
// summary:
// Old base class for widgets. New widgets should extend `dijit/_WidgetBase` instead
// description:
// Old Base class for Dijit widgets.
//
// Extends _WidgetBase, adding support for:
//
// - declaratively/programatically specifying widget initialization parameters like
// onMouseMove="foo" that call foo when this.domNode gets a mousemove event
// - ondijitclick:
// Support new data-dojo-attach-event="ondijitclick: ..." that is triggered by a mouse click or a SPACE/ENTER keypress
// - focus related functions:
// In particular, the onFocus()/onBlur() callbacks. Driven internally by
// dijit/_base/focus.js.
// - deprecated methods
// - onShow(), onHide(), onClose()
//
// Also, by loading code in dijit/_base, turns on:
//
// - browser sniffing (putting browser class like `dj_ie` on `` node)
// - high contrast mode sniffing (add `dijit_a11y` class to `` if machine is in high contrast mode)
////////////////// DEFERRED CONNECTS ///////////////////
onClick: connectToDomNode,
/*=====
onClick: function(event){
// summary:
// Connect to this function to receive notifications of mouse click events.
// event:
// mouse Event
// tags:
// callback
},
=====*/
onDblClick: connectToDomNode,
/*=====
onDblClick: function(event){
// summary:
// Connect to this function to receive notifications of mouse double click events.
// event:
// mouse Event
// tags:
// callback
},
=====*/
onKeyDown: connectToDomNode,
/*=====
onKeyDown: function(event){
// summary:
// Connect to this function to receive notifications of keys being pressed down.
// event:
// key Event
// tags:
// callback
},
=====*/
onKeyPress: connectToDomNode,
/*=====
onKeyPress: function(event){
// summary:
// Connect to this function to receive notifications of printable keys being typed.
// event:
// key Event
// tags:
// callback
},
=====*/
onKeyUp: connectToDomNode,
/*=====
onKeyUp: function(event){
// summary:
// Connect to this function to receive notifications of keys being released.
// event:
// key Event
// tags:
// callback
},
=====*/
onMouseDown: connectToDomNode,
/*=====
onMouseDown: function(event){
// summary:
// Connect to this function to receive notifications of when the mouse button is pressed down.
// event:
// mouse Event
// tags:
// callback
},
=====*/
onMouseMove: connectToDomNode,
/*=====
onMouseMove: function(event){
// summary:
// Connect to this function to receive notifications of when the mouse moves over nodes contained within this widget.
// event:
// mouse Event
// tags:
// callback
},
=====*/
onMouseOut: connectToDomNode,
/*=====
onMouseOut: function(event){
// summary:
// Connect to this function to receive notifications of when the mouse moves off of nodes contained within this widget.
// event:
// mouse Event
// tags:
// callback
},
=====*/
onMouseOver: connectToDomNode,
/*=====
onMouseOver: function(event){
// summary:
// Connect to this function to receive notifications of when the mouse moves onto nodes contained within this widget.
// event:
// mouse Event
// tags:
// callback
},
=====*/
onMouseLeave: connectToDomNode,
/*=====
onMouseLeave: function(event){
// summary:
// Connect to this function to receive notifications of when the mouse moves off of this widget.
// event:
// mouse Event
// tags:
// callback
},
=====*/
onMouseEnter: connectToDomNode,
/*=====
onMouseEnter: function(event){
// summary:
// Connect to this function to receive notifications of when the mouse moves onto this widget.
// event:
// mouse Event
// tags:
// callback
},
=====*/
onMouseUp: connectToDomNode,
/*=====
onMouseUp: function(event){
// summary:
// Connect to this function to receive notifications of when the mouse button is released.
// event:
// mouse Event
// tags:
// callback
},
=====*/
constructor: function(params /*===== ,srcNodeRef =====*/){
// summary:
// Create the widget.
// params: Object|null
// Hash of initialization parameters for widget, including scalar values (like title, duration etc.)
// and functions, typically callbacks like onClick.
// The hash can contain any of the widget's properties, excluding read-only properties.
// srcNodeRef: DOMNode|String?
// 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
// extract parameters like onMouseMove that should connect directly to this.domNode
this._toConnect = {};
for(var name in params){
if(this[name] === connectToDomNode){
this._toConnect[name.replace(/^on/, "").toLowerCase()] = params[name];
delete params[name];
}
}
},
postCreate: function(){
this.inherited(arguments);
// perform connection from this.domNode to user specified handlers (ex: onMouseMove)
for(var name in this._toConnect){
this.on(name, this._toConnect[name]);
}
delete this._toConnect;
},
on: function(/*String|Function*/ type, /*Function*/ func){
if(this[this._onMap(type)] === connectToDomNode){
// Use connect.connect() rather than on() to get handling for "onmouseenter" on non-IE,
// normalization of onkeypress/onkeydown to behave like firefox, etc.
// Also, need to specify context as "this" rather than the default context of the DOMNode
// Remove in 2.0.
return connect.connect(this.domNode, type.toLowerCase(), this, func);
}
return this.inherited(arguments);
},
_setFocusedAttr: function(val){
// Remove this method in 2.0 (or sooner), just here to set _focused == focused, for back compat
// (but since it's a private variable we aren't required to keep supporting it).
this._focused = val;
this._set("focused", val);
},
////////////////// DEPRECATED METHODS ///////////////////
setAttribute: function(/*String*/ attr, /*anything*/ value){
// summary:
// Deprecated. Use set() instead.
// tags:
// deprecated
kernel.deprecated(this.declaredClass+"::setAttribute(attr, value) is deprecated. Use set() instead.", "", "2.0");
this.set(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:
// This method is deprecated, use get() or set() directly.
// Print deprecation warning but only once per calling function
if(config.isDebug){
var alreadyCalledHash = arguments.callee._ach || (arguments.callee._ach = {}),
caller = (arguments.callee.caller || "unknown caller").toString();
if(!alreadyCalledHash[caller]){
kernel.deprecated(this.declaredClass + "::attr() is deprecated. Use get() or set() instead, called from " +
caller, "", "2.0");
alreadyCalledHash[caller] = true;
}
}
var args = arguments.length;
if(args >= 2 || typeof name === "object"){ // setter
return this.set.apply(this, arguments);
}else{ // getter
return this.get(name);
}
},
getDescendants: function(){
// summary:
// Returns all the widgets contained by this, i.e., all widgets underneath this.containerNode.
// This method should generally be avoided as it returns widgets declared in templates, which are
// supposed to be internal/hidden, but it's left here for back-compat reasons.
kernel.deprecated(this.declaredClass+"::getDescendants() is deprecated. Use getChildren() instead.", "", "2.0");
return this.containerNode ? query('[widgetId]', this.containerNode).map(registry.byNode) : []; // dijit/_WidgetBase[]
},
////////////////// MISCELLANEOUS METHODS ///////////////////
_onShow: function(){
// summary:
// Internal method called when this widget is made visible.
// See `onShow` for details.
this.onShow();
},
onShow: function(){
// summary:
// Called when this widget becomes the selected pane in a
// `dijit/layout/TabContainer`, `dijit/layout/StackContainer`,
// `dijit/layout/AccordionContainer`, etc.
//
// Also called to indicate display of a `dijit.Dialog`, `dijit.TooltipDialog`, or `dijit.TitlePane`.
// tags:
// callback
},
onHide: function(){
// summary:
// Called when another widget becomes the selected pane in a
// `dijit/layout/TabContainer`, `dijit/layout/StackContainer`,
// `dijit/layout/AccordionContainer`, etc.
//
// Also called to indicate hide of a `dijit.Dialog`, `dijit.TooltipDialog`, or `dijit.TitlePane`.
// tags:
// callback
},
onClose: function(){
// summary:
// Called when this widget is being displayed as a popup (ex: a Calendar popped
// up from a DateTextBox), and it is hidden.
// This is called from the dijit.popup code, and should not be called directly.
//
// Also used as a parameter for children of `dijit/layout/StackContainer` or subclasses.
// Callback if a user tries to close the child. Child will be closed if this function returns true.
// tags:
// extension
return true; // Boolean
}
});
// For back-compat, remove in 2.0.
if(has("dijit-legacy-requires")){
ready(0, function(){
var requires = ["dijit/_base"];
require(requires); // use indirection so modules not rolled into a build
});
}
return _Widget;
});
},
'dijit/_OnDijitClickMixin':function(){
define("dijit/_OnDijitClickMixin", [
"dojo/on",
"dojo/_base/array", // array.forEach
"dojo/keys", // keys.ENTER keys.SPACE
"dojo/_base/declare", // declare
"dojo/has", // has("dom-addeventlistener")
"dojo/_base/unload", // unload.addOnWindowUnload
"dojo/_base/window", // win.doc.addEventListener win.doc.attachEvent win.doc.detachEvent
"./a11yclick"
], function(on, array, keys, declare, has, unload, win, a11yclick){
// module:
// dijit/_OnDijitClickMixin
var ret = declare("dijit._OnDijitClickMixin", null, {
connect: function(
/*Object|null*/ obj,
/*String|Function*/ event,
/*String|Function*/ method){
// summary:
// Connects specified obj/event to specified method of this object
// and registers for disconnect() on widget destroy.
// description:
// Provide widget-specific analog to connect.connect, except with the
// implicit use of this widget as the target object.
// This version of connect also provides a special "ondijitclick"
// event which triggers on a click or space or enter keyup.
// Events connected with `this.connect` are disconnected upon
// destruction.
// returns:
// A handle that can be passed to `disconnect` in order to disconnect before
// the widget is destroyed.
// example:
// | var btn = new Button();
// | // when foo.bar() is called, call the listener we're going to
// | // provide in the scope of btn
// | btn.connect(foo, "bar", function(){
// | console.debug(this.toString());
// | });
// tags:
// protected
return this.inherited(arguments, [obj, event == "ondijitclick" ? a11yclick : event, method]);
}
});
ret.a11yclick = a11yclick; // back compat
return ret;
});
},
'dijit/a11yclick':function(){
define("dijit/a11yclick", [
"dojo/_base/array", // array.forEach
"dojo/_base/declare", // declare
"dojo/has", // has("dom-addeventlistener")
"dojo/keys", // keys.ENTER keys.SPACE
"dojo/on"
], function(array, declare, has, keys, on){
// module:
// dijit/a11yclick
function marked(/*DOMNode*/ node){
// Test if a node or its ancestor has been marked with the dojoClick property to indicate special processing
do{
if(node.dojoClick){ return true; }
}while(node = node.parentNode);
}
function clickKey(/*Event*/ e){
// Test if this keyboard event should be tracked as the start (if keyup) or end (if keydown) of a click event.
// Only track for nodes marked to be tracked, and not for buttons or inputs since they handle keyboard click
// natively.
return (e.keyCode === keys.ENTER || e.keyCode === keys.SPACE) &&
!e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey && !/input|button/i.test(e.target.nodeName) &&
marked(e.target);
}
var lastKeyDownNode;
on(document, "keydown", function(e){
//console.log(this.id + ": onkeydown, e.target = ", e.target, ", lastKeyDownNode was ", lastKeyDownNode, ", equality is ", (e.target === lastKeyDownNode));
if(clickKey(e)){
// needed on IE for when focus changes between keydown and keyup - otherwise dropdown menus do not work
lastKeyDownNode = e.target;
// Prevent viewport scrolling on space key in IE<9.
// (Reproducible on test_Button.html on any of the first dijit/form/Button examples)
e.preventDefault();
}
});
on(document, "keyup", function(e){
//console.log(this.id + ": onkeyup, e.target = ", e.target, ", lastKeyDownNode was ", lastKeyDownNode, ", equality is ", (e.target === lastKeyDownNode));
if(clickKey(e) && e.target == lastKeyDownNode){ // === breaks greasemonkey
//need reset here or have problems in FF when focus returns to trigger element after closing popup/alert
lastKeyDownNode = null;
on.emit(e.target, "click", {
cancelable: true,
bubbles: true
});
}
});
if(has("touch")){
// touchstart-->touchend will automatically generate a click event, but there are problems
// on iOS after focus has been programatically shifted (#14604, #14918), so setup a failsafe
// if click doesn't fire naturally.
var clickTimer;
on(document, "touchend", function(e){
var target = e.target;
if(marked(target)){
var naturalClickListener = on.once(target, "click", function(e){
// If browser generates a click naturally, clear the timer to fire a synthetic click event
if(clickTimer){
clearTimeout(clickTimer);
clickTimer = null;
}
});
if(clickTimer){
clearTimeout(clickTimer);
}
clickTimer = setTimeout(function(){
clickTimer = null;
naturalClickListener.remove();
on.emit(target, "click", {
cancelable: true,
bubbles: true
});
}, 600);
}
});
// TODO: if the touchstart and touchend were <100ms apart, and then there's another touchstart
// event <300ms after the touchend event, then clear the synthetic click timer, because user
// is doing a zoom. Alternately monitor screen.deviceXDPI (or something similar) to see if
// zoom level has changed.
}
return function(node, listener){
// summary:
// Custom a11yclick (a.k.a. ondijitclick) event
// which triggers on a mouse click, touch, or space/enter keyup.
node.dojoClick = true;
return on(node, "click", listener);
};
});
},
'dijit/_FocusMixin':function(){
define("dijit/_FocusMixin", [
"./focus",
"./_WidgetBase",
"dojo/_base/declare", // declare
"dojo/_base/lang" // lang.extend
], function(focus, _WidgetBase, declare, lang){
// module:
// dijit/_FocusMixin
// We don't know where _FocusMixin will occur in the inheritance chain, but we need the _onFocus()/_onBlur() below
// to be last in the inheritance chain, so mixin to _WidgetBase.
lang.extend(_WidgetBase, {
// focused: [readonly] Boolean
// This widget or a widget it contains has focus, or is "active" because
// it was recently clicked.
focused: false,
onFocus: function(){
// summary:
// Called when the widget becomes "active" because
// it or a widget inside of it either has focus, or has recently
// been clicked.
// tags:
// callback
},
onBlur: function(){
// summary:
// Called when the widget stops being "active" because
// focus moved to something outside of it, or the user
// clicked somewhere outside of it, or the widget was
// hidden.
// tags:
// callback
},
_onFocus: function(){
// summary:
// This is where widgets do processing for when they are active,
// such as changing CSS classes. See onFocus() for more details.
// tags:
// protected
this.onFocus();
},
_onBlur: function(){
// summary:
// This is where widgets do processing for when they stop being active,
// such as changing CSS classes. See onBlur() for more details.
// tags:
// protected
this.onBlur();
}
});
return declare("dijit._FocusMixin", null, {
// summary:
// Mixin to widget to provide _onFocus() and _onBlur() methods that
// fire when a widget or its descendants get/lose focus
// flag that I want _onFocus()/_onBlur() notifications from focus manager
_focusManager: focus
});
});
},
'dijit/focus':function(){
define("dijit/focus", [
"dojo/aspect",
"dojo/_base/declare", // declare
"dojo/dom", // domAttr.get dom.isDescendant
"dojo/dom-attr", // domAttr.get dom.isDescendant
"dojo/dom-construct", // connect to domConstruct.empty, domConstruct.destroy
"dojo/Evented",
"dojo/_base/lang", // lang.hitch
"dojo/on",
"dojo/ready",
"dojo/sniff", // has("ie")
"dojo/Stateful",
"dojo/_base/unload", // unload.addOnWindowUnload
"dojo/_base/window", // win.body
"dojo/window", // winUtils.get
"./a11y", // a11y.isTabNavigable
"./registry", // registry.byId
"./main" // to set dijit.focus
], function(aspect, declare, dom, domAttr, domConstruct, Evented, lang, on, ready, has, Stateful, unload, win, winUtils,
a11y, registry, dijit){
// module:
// dijit/focus
var lastFocusin;
var FocusManager = declare([Stateful, Evented], {
// summary:
// Tracks the currently focused node, and which widgets are currently "active".
// Access via require(["dijit/focus"], function(focus){ ... }).
//
// A widget is considered active if it or a descendant widget has focus,
// or if a non-focusable node of this widget or a descendant was recently clicked.
//
// Call focus.watch("curNode", callback) to track the current focused DOMNode,
// or focus.watch("activeStack", callback) to track the currently focused stack of widgets.
//
// Call focus.on("widget-blur", func) or focus.on("widget-focus", ...) to monitor when
// when widgets become active/inactive
//
// Finally, focus(node) will focus a node, suppressing errors if the node doesn't exist.
// curNode: DomNode
// Currently focused item on screen
curNode: null,
// activeStack: dijit/_WidgetBase[]
// List of currently active widgets (focused widget and it's ancestors)
activeStack: [],
constructor: function(){
// Don't leave curNode/prevNode pointing to bogus elements
var check = lang.hitch(this, function(node){
if(dom.isDescendant(this.curNode, node)){
this.set("curNode", null);
}
if(dom.isDescendant(this.prevNode, node)){
this.set("prevNode", null);
}
});
aspect.before(domConstruct, "empty", check);
aspect.before(domConstruct, "destroy", check);
},
registerIframe: function(/*DomNode*/ iframe){
// summary:
// Registers listeners on the specified iframe so that any click
// or focus event on that iframe (or anything in it) is reported
// as a focus/click event on the `