]> git.pond.sub.org Git - eow/blob - static/dojo-release-1.1.1/dijit/_base/popup.js
add Dojo 1.1.1
[eow] / static / dojo-release-1.1.1 / dijit / _base / popup.js
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");
4
5 dojo.require("dijit._base.focus");
6 dojo.require("dijit._base.place");
7 dojo.require("dijit._base.window");
8
9 dijit.popup = new function(){
10         // summary:
11         //              This class is used to show/hide widgets as popups.
12         //
13
14         var stack = [],
15                 beginZIndex=1000,
16                 idGen = 1;
17
18         this.prepare = function(/*DomNode*/ node){
19                 // summary:
20                 //              Prepares a node to be used as a popup
21                 //
22                 // description:
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
28         
29                 dojo.body().appendChild(node);
30                 var s = node.style;
31                 if(s.display == "none"){
32                         s.display="";
33                 }
34                 s.visibility = "hidden";        // not needed for hiding, but used as flag that node is off-screen
35                 s.position = "absolute";
36                 s.top = "-9999px";
37         };
38
39         this.open = function(/*Object*/ args){
40                 // summary:
41                 //              Popup the widget at the specified position
42                 //
43                 // args: Object
44                 //              popup: Widget
45                 //                      widget to display,
46                 //              parent: Widget
47                 //                      the button etc. that is displaying this popup
48                 //              around: DomNode
49                 //                      DOM node (typically a button); place popup relative to this node
50                 //              orient: Object
51                 //                      structure specifying possible positions of popup relative to "around" node
52                 //              onCancel: Function
53                 //                      callback when user has canceled the popup by
54                 //                              1. hitting ESC or
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
57                 //              onClose: Function
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)
61                 //
62                 // examples:
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(){...}  });
67                 //
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.
70
71                 var widget = args.popup,
72                         orient = args.orient || {'BL':'TL', 'TL':'BL'},
73                         around = args.around,
74                         id = (args.around && args.around.id) ? (args.around.id+"_dropdown") : ("popup_"+idGen++);
75
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");
81                 wrapper.id = id;
82                 wrapper.className="dijitPopup";
83                 wrapper.style.zIndex = beginZIndex + stack.length;
84                 wrapper.style.visibility = "hidden";
85                 if(args.parent){
86                         wrapper.dijitPopupParent=args.parent.id;
87                 }
88                 dojo.body().appendChild(wrapper);
89
90                 var s = widget.domNode.style;
91                 s.display = "";
92                 s.visibility = "";
93                 s.position = "";
94                 wrapper.appendChild(widget.domNode);
95
96                 var iframe = new dijit.BackgroundIframe(wrapper);
97
98                 // position the wrapper node
99                 var best = around ?
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']);
102
103                 wrapper.style.visibility = "visible";
104                 // TODO: use effects to fade in wrapper
105
106                 var handlers = [];
107
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 */
113                         }
114                         return stack[pi];
115                 }
116
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){
121                                 dojo.stopEvent(evt);
122                                 args.onCancel();
123                         }else if(evt.keyCode == dojo.keys.TAB){
124                                 dojo.stopEvent(evt);
125                                 var topPopup = getTopPopup();
126                                 if(topPopup && topPopup.onCancel){
127                                         topPopup.onCancel();
128                                 }
129                         }
130                 }));
131
132                 // watch for cancel/execute events on the popup and notify the caller
133                 // (for a menu, "execute" means clicking an item)
134                 if(widget.onCancel){
135                         handlers.push(dojo.connect(widget, "onCancel", null, args.onCancel));
136                 }
137
138                 handlers.push(dojo.connect(widget, widget.onExecute ? "onExecute" : "onChange", null, function(){
139                         var topPopup = getTopPopup();
140                         if(topPopup && topPopup.onExecute){
141                                 topPopup.onExecute();
142                         }
143                 }));
144
145                 stack.push({
146                         wrapper: wrapper,
147                         iframe: iframe,
148                         widget: widget,
149                         parent: args.parent,
150                         onExecute: args.onExecute,
151                         onCancel: args.onCancel,
152                         onClose: args.onClose,
153                         handlers: handlers
154                 });
155
156                 if(widget.onOpen){
157                         widget.onOpen(best);
158                 }
159
160                 return best;
161         };
162
163         this.close = function(/*Widget*/ popup){
164                 // summary:
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,
169                                 iframe = top.iframe,
170                                 widget = top.widget,
171                                 onClose = top.onClose;
172         
173                         if(widget.onClose){
174                                 widget.onClose();
175                         }
176                         dojo.forEach(top.handlers, dojo.disconnect);
177         
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; }
180                         
181                         this.prepare(widget.domNode);
182
183                         iframe.destroy();
184                         dojo._destroyElement(wrapper);
185         
186                         if(onClose){
187                                 onClose();
188                         }
189                 }
190         };
191 }();
192
193 dijit._frames = new function(){
194         // summary: cache of iframes
195         var queue = [];
196
197         this.pop = function(){
198                 var iframe;
199                 if(queue.length){
200                         iframe = queue.pop();
201                         iframe.style.display="";
202                 }else{
203                         if(dojo.isIE){
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);
208                         }else{
209                                 iframe = dojo.doc.createElement("iframe");
210                                 iframe.src = 'javascript:""';
211                                 iframe.className = "dijitBackgroundIframe";
212                         }
213                         iframe.tabIndex = -1; // Magic to prevent iframe from getting focus on tab keypress - as style didnt work.
214                         dojo.body().appendChild(iframe);
215                 }
216                 return iframe;
217         };
218
219         this.push = function(iframe){
220                 iframe.style.display="";
221                 if(dojo.isIE){
222                         iframe.style.removeExpression("width");
223                         iframe.style.removeExpression("height");
224                 }
225                 queue.push(iframe);
226         }
227 }();
228
229 // fill the queue
230 if(dojo.isIE && dojo.isIE < 7){
231         dojo.addOnLoad(function(){
232                 var f = dijit._frames;
233                 dojo.forEach([f.pop()], f.push);
234         });
235 }
236
237
238 dijit.BackgroundIframe = function(/* DomNode */node){
239         //      summary:
240         //              For IE z-index schenanigans. id attribute is required.
241         //
242         //      description:
243         //              new dijit.BackgroundIframe(node)
244         //                      Makes a background iframe as a child of node, that fills
245         //                      area (and position) of node
246
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);
251                 if(dojo.isIE){
252                         iframe.style.setExpression("width", dojo._scopeName + ".doc.getElementById('" + node.id + "').offsetWidth");
253                         iframe.style.setExpression("height", dojo._scopeName + ".doc.getElementById('" + node.id + "').offsetHeight");
254                 }
255                 this.iframe = iframe;
256         }
257 };
258
259 dojo.extend(dijit.BackgroundIframe, {
260         destroy: function(){
261                 //      summary: destroy the iframe
262                 if(this.iframe){
263                         dijit._frames.push(this.iframe);
264                         delete this.iframe;
265                 }
266         }
267 });
268
269 }