1 if(!dojo._hasResource["dijit._base.popup"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2 dojo._hasResource["dijit._base.popup"] = true;
3 dojo.provide("dijit._base.popup");
5 dojo.require("dijit._base.focus");
6 dojo.require("dijit._base.place");
7 dojo.require("dijit._base.window");
9 dijit.popup = new function(){
11 // This class is used to show/hide widgets as popups.
18 this.prepare = function(/*DomNode*/ node){
20 // Prepares a node to be used as a popup
23 // Attaches node to dojo.doc.body, and
24 // positions it off screen, but not display:none, so that
25 // the widget doesn't appear in the page flow and/or cause a blank
26 // area at the bottom of the viewport (making scrollbar longer), but
27 // initialization of contained widgets works correctly
29 dojo.body().appendChild(node);
31 if(s.display == "none"){
34 s.visibility = "hidden"; // not needed for hiding, but used as flag that node is off-screen
35 s.position = "absolute";
39 this.open = function(/*Object*/ args){
41 // Popup the widget at the specified position
47 // the button etc. that is displaying this popup
49 // DOM node (typically a button); place popup relative to this node
51 // structure specifying possible positions of popup relative to "around" node
53 // callback when user has canceled the popup by
55 // 2. by using the popup widget's proprietary cancel mechanism (like a cancel button in a dialog);
56 // ie: whenever popupWidget.onCancel() is called, args.onCancel is called
58 // callback whenever this popup is closed
59 // onExecute: Function
60 // callback when user "executed" on the popup/sub-popup by selecting a menu choice, etc. (top menu only)
63 // 1. opening at the mouse position
64 // dijit.popup.open({popup: menuWidget, x: evt.pageX, y: evt.pageY});
65 // 2. opening the widget as a dropdown
66 // dijit.popup.open({parent: this, popup: menuWidget, around: this.domNode, onClose: function(){...} });
68 // Note that whatever widget called dijit.popup.open() should also listen to it's own _onBlur callback
69 // (fired from _base/focus.js) to know that focus has moved somewhere else and thus the popup should be closed.
71 var widget = args.popup,
72 orient = args.orient || {'BL':'TL', 'TL':'BL'},
74 id = (args.around && args.around.id) ? (args.around.id+"_dropdown") : ("popup_"+idGen++);
76 // make wrapper div to hold widget and possibly hold iframe behind it.
77 // we can't attach the iframe as a child of the widget.domNode because
78 // widget.domNode might be a <table>, <ul>, etc.
79 var wrapper = dojo.doc.createElement("div");
80 dijit.setWaiRole(wrapper, "presentation");
82 wrapper.className="dijitPopup";
83 wrapper.style.zIndex = beginZIndex + stack.length;
84 wrapper.style.visibility = "hidden";
86 wrapper.dijitPopupParent=args.parent.id;
88 dojo.body().appendChild(wrapper);
90 var s = widget.domNode.style;
94 wrapper.appendChild(widget.domNode);
96 var iframe = new dijit.BackgroundIframe(wrapper);
98 // position the wrapper node
100 dijit.placeOnScreenAroundElement(wrapper, around, orient, widget.orient ? dojo.hitch(widget, "orient") : null) :
101 dijit.placeOnScreen(wrapper, args, orient == 'R' ? ['TR','BR','TL','BL'] : ['TL','BL','TR','BR']);
103 wrapper.style.visibility = "visible";
104 // TODO: use effects to fade in wrapper
108 // Compute the closest ancestor popup that's *not* a child of another popup.
109 // Ex: For a TooltipDialog with a button that spawns a tree of menus, find the popup of the button.
110 var getTopPopup = function(){
111 for(var pi=stack.length-1; pi > 0 && stack[pi].parent === stack[pi-1].widget; pi--){
112 /* do nothing, just trying to get right value for pi */
117 // provide default escape and tab key handling
118 // (this will work for any widget, not just menu)
119 handlers.push(dojo.connect(wrapper, "onkeypress", this, function(evt){
120 if(evt.keyCode == dojo.keys.ESCAPE && args.onCancel){
123 }else if(evt.keyCode == dojo.keys.TAB){
125 var topPopup = getTopPopup();
126 if(topPopup && topPopup.onCancel){
132 // watch for cancel/execute events on the popup and notify the caller
133 // (for a menu, "execute" means clicking an item)
135 handlers.push(dojo.connect(widget, "onCancel", null, args.onCancel));
138 handlers.push(dojo.connect(widget, widget.onExecute ? "onExecute" : "onChange", null, function(){
139 var topPopup = getTopPopup();
140 if(topPopup && topPopup.onExecute){
141 topPopup.onExecute();
150 onExecute: args.onExecute,
151 onCancel: args.onCancel,
152 onClose: args.onClose,
163 this.close = function(/*Widget*/ popup){
165 // Close specified popup and any popups that it parented
166 while(dojo.some(stack, function(elem){return elem.widget == popup;})){
167 var top = stack.pop(),
168 wrapper = top.wrapper,
171 onClose = top.onClose;
176 dojo.forEach(top.handlers, dojo.disconnect);
178 // #2685: check if the widget still has a domNode so ContentPane can change its URL without getting an error
179 if(!widget||!widget.domNode){ return; }
181 this.prepare(widget.domNode);
184 dojo._destroyElement(wrapper);
193 dijit._frames = new function(){
194 // summary: cache of iframes
197 this.pop = function(){
200 iframe = queue.pop();
201 iframe.style.display="";
204 var html="<iframe src='javascript:\"\"'"
205 + " style='position: absolute; left: 0px; top: 0px;"
206 + "z-index: -1; filter:Alpha(Opacity=\"0\");'>";
207 iframe = dojo.doc.createElement(html);
209 iframe = dojo.doc.createElement("iframe");
210 iframe.src = 'javascript:""';
211 iframe.className = "dijitBackgroundIframe";
213 iframe.tabIndex = -1; // Magic to prevent iframe from getting focus on tab keypress - as style didnt work.
214 dojo.body().appendChild(iframe);
219 this.push = function(iframe){
220 iframe.style.display="";
222 iframe.style.removeExpression("width");
223 iframe.style.removeExpression("height");
230 if(dojo.isIE && dojo.isIE < 7){
231 dojo.addOnLoad(function(){
232 var f = dijit._frames;
233 dojo.forEach([f.pop()], f.push);
238 dijit.BackgroundIframe = function(/* DomNode */node){
240 // For IE z-index schenanigans. id attribute is required.
243 // new dijit.BackgroundIframe(node)
244 // Makes a background iframe as a child of node, that fills
245 // area (and position) of node
247 if(!node.id){ throw new Error("no id"); }
248 if((dojo.isIE && dojo.isIE < 7) || (dojo.isFF && dojo.isFF < 3 && dojo.hasClass(dojo.body(), "dijit_a11y"))){
249 var iframe = dijit._frames.pop();
250 node.appendChild(iframe);
252 iframe.style.setExpression("width", dojo._scopeName + ".doc.getElementById('" + node.id + "').offsetWidth");
253 iframe.style.setExpression("height", dojo._scopeName + ".doc.getElementById('" + node.id + "').offsetHeight");
255 this.iframe = iframe;
259 dojo.extend(dijit.BackgroundIframe, {
261 // summary: destroy the iframe
263 dijit._frames.push(this.iframe);