diff options
Diffstat (limited to 'includes/js/dijit/_base/popup.js')
-rw-r--r-- | includes/js/dijit/_base/popup.js | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/includes/js/dijit/_base/popup.js b/includes/js/dijit/_base/popup.js new file mode 100644 index 0000000..6cb4dfc --- /dev/null +++ b/includes/js/dijit/_base/popup.js @@ -0,0 +1,269 @@ +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.prepare = function(/*DomNode*/ node){ + // summary: + // Prepares a node to be used as a popup + // + // description: + // Attaches node to dojo.doc.body, and + // positions it off screen, but not display:none, so that + // the widget doesn't appear in the page flow and/or cause a blank + // area at the bottom of the viewport (making scrollbar longer), but + // initialization of contained widgets works correctly + + dojo.body().appendChild(node); + var s = node.style; + if(s.display == "none"){ + s.display=""; + } + s.visibility = "hidden"; // not needed for hiding, but used as flag that node is off-screen + s.position = "absolute"; + s.top = "-9999px"; + }; + + this.open = function(/*Object*/ args){ + // summary: + // Popup the widget at the specified position + // + // args: Object + // popup: Widget + // widget to display, + // parent: Widget + // the button etc. that is displaying this popup + // around: DomNode + // DOM node (typically a button); place popup relative to this node + // orient: Object + // structure specifying possible positions of popup relative to "around" node + // onCancel: Function + // callback when user has canceled the popup by + // 1. hitting ESC or + // 2. by using the popup widget's proprietary cancel mechanism (like a cancel button in a dialog); + // ie: whenever popupWidget.onCancel() is called, args.onCancel is called + // onClose: Function + // callback whenever this popup is closed + // onExecute: Function + // callback when user "executed" on the popup/sub-popup by selecting a menu choice, etc. (top menu only) + // + // examples: + // 1. opening at the mouse position + // dijit.popup.open({popup: menuWidget, x: evt.pageX, y: evt.pageY}); + // 2. opening the widget as a dropdown + // dijit.popup.open({parent: this, popup: menuWidget, around: this.domNode, onClose: function(){...} }); + // + // Note that whatever widget called dijit.popup.open() should also listen to it's own _onBlur callback + // (fired from _base/focus.js) to know that focus has moved somewhere else and thus the popup should be closed. + + var widget = args.popup, + orient = args.orient || {'BL':'TL', 'TL':'BL'}, + around = args.around, + id = (args.around && args.around.id) ? (args.around.id+"_dropdown") : ("popup_"+idGen++); + + // make wrapper div to hold widget and possibly hold iframe behind it. + // we can't attach the iframe as a child of the widget.domNode because + // widget.domNode might be a <table>, <ul>, etc. + var wrapper = dojo.doc.createElement("div"); + dijit.setWaiRole(wrapper, "presentation"); + wrapper.id = id; + wrapper.className="dijitPopup"; + wrapper.style.zIndex = beginZIndex + stack.length; + wrapper.style.visibility = "hidden"; + if(args.parent){ + wrapper.dijitPopupParent=args.parent.id; + } + dojo.body().appendChild(wrapper); + + var s = widget.domNode.style; + s.display = ""; + s.visibility = ""; + s.position = ""; + wrapper.appendChild(widget.domNode); + + var iframe = new dijit.BackgroundIframe(wrapper); + + // position the wrapper node + var best = around ? + dijit.placeOnScreenAroundElement(wrapper, around, orient, widget.orient ? dojo.hitch(widget, "orient") : null) : + dijit.placeOnScreen(wrapper, args, orient == 'R' ? ['TR','BR','TL','BL'] : ['TL','BL','TR','BR']); + + wrapper.style.visibility = "visible"; + // TODO: use effects to fade in wrapper + + var handlers = []; + + // Compute the closest ancestor popup that's *not* a child of another popup. + // Ex: For a TooltipDialog with a button that spawns a tree of menus, find the popup of the button. + var getTopPopup = function(){ + for(var pi=stack.length-1; pi > 0 && stack[pi].parent === stack[pi-1].widget; pi--){ + /* do nothing, just trying to get right value for pi */ + } + return stack[pi]; + } + + // provide default escape and tab key handling + // (this will work for any widget, not just menu) + handlers.push(dojo.connect(wrapper, "onkeypress", this, function(evt){ + if(evt.keyCode == dojo.keys.ESCAPE && args.onCancel){ + dojo.stopEvent(evt); + args.onCancel(); + }else if(evt.keyCode == dojo.keys.TAB){ + dojo.stopEvent(evt); + var topPopup = getTopPopup(); + if(topPopup && topPopup.onCancel){ + topPopup.onCancel(); + } + } + })); + + // watch for cancel/execute events on the popup and notify the caller + // (for a menu, "execute" means clicking an item) + if(widget.onCancel){ + handlers.push(dojo.connect(widget, "onCancel", null, args.onCancel)); + } + + handlers.push(dojo.connect(widget, widget.onExecute ? "onExecute" : "onChange", null, function(){ + var topPopup = getTopPopup(); + if(topPopup && topPopup.onExecute){ + topPopup.onExecute(); + } + })); + + stack.push({ + wrapper: wrapper, + iframe: iframe, + widget: widget, + parent: args.parent, + onExecute: args.onExecute, + onCancel: args.onCancel, + onClose: args.onClose, + handlers: handlers + }); + + if(widget.onOpen){ + widget.onOpen(best); + } + + return best; + }; + + this.close = function(/*Widget*/ popup){ + // summary: + // Close specified popup and any popups that it parented + while(dojo.some(stack, function(elem){return elem.widget == popup;})){ + var top = stack.pop(), + wrapper = top.wrapper, + iframe = top.iframe, + widget = top.widget, + onClose = top.onClose; + + if(widget.onClose){ + widget.onClose(); + } + dojo.forEach(top.handlers, dojo.disconnect); + + // #2685: check if the widget still has a domNode so ContentPane can change its URL without getting an error + if(!widget||!widget.domNode){ return; } + + this.prepare(widget.domNode); + + iframe.destroy(); + dojo._destroyElement(wrapper); + + if(onClose){ + onClose(); + } + } + }; +}(); + +dijit._frames = new function(){ + // summary: cache of iframes + var queue = []; + + this.pop = function(){ + var iframe; + if(queue.length){ + iframe = queue.pop(); + iframe.style.display=""; + }else{ + if(dojo.isIE){ + var html="<iframe src='javascript:\"\"'" + + " style='position: absolute; left: 0px; top: 0px;" + + "z-index: -1; filter:Alpha(Opacity=\"0\");'>"; + iframe = dojo.doc.createElement(html); + }else{ + iframe = dojo.doc.createElement("iframe"); + iframe.src = 'javascript:""'; + iframe.className = "dijitBackgroundIframe"; + } + iframe.tabIndex = -1; // Magic to prevent iframe from getting focus on tab keypress - as style didnt work. + dojo.body().appendChild(iframe); + } + return iframe; + }; + + this.push = function(iframe){ + iframe.style.display=""; + if(dojo.isIE){ + iframe.style.removeExpression("width"); + iframe.style.removeExpression("height"); + } + queue.push(iframe); + } +}(); + +// fill the queue +if(dojo.isIE && dojo.isIE < 7){ + dojo.addOnLoad(function(){ + var f = dijit._frames; + dojo.forEach([f.pop()], f.push); + }); +} + + +dijit.BackgroundIframe = function(/* DomNode */node){ + // summary: + // For IE z-index schenanigans. id attribute is required. + // + // description: + // new dijit.BackgroundIframe(node) + // Makes a background iframe as a child of node, that fills + // area (and position) of node + + if(!node.id){ throw new Error("no id"); } + if((dojo.isIE && dojo.isIE < 7) || (dojo.isFF && dojo.isFF < 3 && dojo.hasClass(dojo.body(), "dijit_a11y"))){ + var iframe = dijit._frames.pop(); + node.appendChild(iframe); + if(dojo.isIE){ + iframe.style.setExpression("width", dojo._scopeName + ".doc.getElementById('" + node.id + "').offsetWidth"); + iframe.style.setExpression("height", dojo._scopeName + ".doc.getElementById('" + node.id + "').offsetHeight"); + } + this.iframe = iframe; + } +}; + +dojo.extend(dijit.BackgroundIframe, { + destroy: function(){ + // summary: destroy the iframe + if(this.iframe){ + dijit._frames.push(this.iframe); + delete this.iframe; + } + } +}); + +} |