Blame | Last modification | View Log | RSS feed
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");
dojo.require("dijit._base.focus");
dojo.require("dijit._base.place");
dojo.require("dijit._base.window");
dijit.popup = new function(){
// summary:
// This class is used to show/hide widgets as popups.
//
var stack = [],
beginZIndex=1000,
idGen = 1;
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");
wrapper.id = id;
wrapper.className="dijitPopup";
wrapper.style.zIndex = beginZIndex + stack.length;
wrapper.style.visibility = "hidden";
if(args.parent){
wrapper.dijitPopupParent=args.parent.id;
}
dojo.body().appendChild(wrapper);
widget.domNode.style.display="";
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.
function getTopPopup(){
for(var pi=stack.length-1; pi > 0 && stack[pi].parent === stack[pi-1].widget; pi--);
return stack[pi];
}
// provide default escape and tab key handling
// (this will work for any widget, not just menu)
handlers.push(dojo.connect(wrapper, "onkeypress", this, function(evt){
if(evt.keyCode == dojo.keys.ESCAPE && args.onCancel){
args.onCancel();
}else if(evt.keyCode == dojo.keys.TAB){
dojo.stopEvent(evt);
var topPopup = getTopPopup();
if(topPopup && topPopup.onCancel){
topPopup.onCancel();
}
}
}));
// watch for cancel/execute events on the popup and notify the caller
// (for a menu, "execute" means clicking an item)
if(widget.onCancel){
handlers.push(dojo.connect(widget, "onCancel", null, args.onCancel));
}
handlers.push(dojo.connect(widget, widget.onExecute ? "onExecute" : "onChange", null, function(){
var topPopup = getTopPopup();
if(topPopup && topPopup.onExecute){
topPopup.onExecute();
}
}));
stack.push({
wrapper: wrapper,
iframe: iframe,
widget: widget,
parent: args.parent,
onExecute: args.onExecute,
onCancel: args.onCancel,
onClose: args.onClose,
handlers: handlers
});
if(widget.onOpen){
widget.onOpen(best);
}
return best;
};
this.close = function(/*Widget*/ popup){
// summary:
// Close specified popup and any popups that it parented
while(dojo.some(stack, function(elem){return elem.widget == popup;})){
var top = stack.pop(),
wrapper = top.wrapper,
iframe = top.iframe,
widget = top.widget,
onClose = top.onClose;
if(widget.onClose){
widget.onClose();
}
dojo.forEach(top.handlers, dojo.disconnect);
// #2685: check if the widget still has a domNode so ContentPane can change its URL without getting an error
if(!widget||!widget.domNode){ return; }
dojo.style(widget.domNode, "display", "none");
dojo.body().appendChild(widget.domNode);
iframe.destroy();
dojo._destroyElement(wrapper);
if(onClose){
onClose();
}
}
};
}();
dijit._frames = new function(){
// summary: cache of iframes
var queue = [];
this.pop = function(){
var iframe;
if(queue.length){
iframe = queue.pop();
iframe.style.display="";
}else{
if(dojo.isIE){
var html="<iframe src='javascript:\"\"'"
+ " style='position: absolute; left: 0px; top: 0px;"
+ "z-index: -1; filter:Alpha(Opacity=\"0\");'>";
iframe = dojo.doc.createElement(html);
}else{
var iframe = dojo.doc.createElement("iframe");
iframe.src = 'javascript:""';
iframe.className = "dijitBackgroundIframe";
}
iframe.tabIndex = -1; // Magic to prevent iframe from getting focus on tab keypress - as style didnt work.
dojo.body().appendChild(iframe);
}
return iframe;
};
this.push = function(iframe){
iframe.style.display="";
if(dojo.isIE){
iframe.style.removeExpression("width");
iframe.style.removeExpression("height");
}
queue.push(iframe);
}
}();
// fill the queue
if(dojo.isIE && dojo.isIE < 7){
dojo.addOnLoad(function(){
var f = dijit._frames;
dojo.forEach([f.pop()], f.push);
});
}
dijit.BackgroundIframe = function(/* DomNode */node){
// summary:
// For IE z-index schenanigans. id attribute is required.
//
// description:
// new dijit.BackgroundIframe(node)
// Makes a background iframe as a child of node, that fills
// area (and position) of node
if(!node.id){ throw new Error("no id"); }
if((dojo.isIE && dojo.isIE < 7) || (dojo.isFF && dojo.isFF < 3 && dojo.hasClass(dojo.body(), "dijit_a11y"))){
var iframe = dijit._frames.pop();
node.appendChild(iframe);
if(dojo.isIE){
iframe.style.setExpression("width", "document.getElementById('" + node.id + "').offsetWidth");
iframe.style.setExpression("height", "document.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;
}
}
});
}