Dialog.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. if (!dojo._hasResource["dijit.Dialog"]) { // _hasResource checks added by
  2. // build. Do not use _hasResource
  3. // directly in your code.
  4. dojo._hasResource["dijit.Dialog"] = true;
  5. dojo.provide("dijit.Dialog");
  6. dojo.require("dojo.dnd.move");
  7. dojo.require("dojo.fx");
  8. dojo.require("dijit._Widget");
  9. dojo.require("dijit._Templated");
  10. dojo.require("dijit.layout.ContentPane");
  11. dojo.require("dijit.form.Form");
  12. dojo.declare("dijit.DialogUnderlay", [dijit._Widget, dijit._Templated], {
  13. // summary: the thing that grays out the screen behind the dialog
  14. // Template has two divs; outer div is used for fade-in/fade-out, and
  15. // also to hold background iframe.
  16. // Inner div has opacity specified in CSS file.
  17. templateString : "<div class=dijitDialogUnderlayWrapper id='${id}_underlay'><div class=dijitDialogUnderlay dojoAttachPoint='node'></div></div>",
  18. postCreate : function() {
  19. dojo.body().appendChild(this.domNode);
  20. this.bgIframe = new dijit.BackgroundIframe(this.domNode);
  21. },
  22. layout : function() {
  23. // summary
  24. // Sets the background to the size of the viewport (rather than the
  25. // size
  26. // of the document) since we need to cover the whole browser window,
  27. // even
  28. // if the document is only a few lines long.
  29. var viewport = dijit.getViewport();
  30. var is = this.node.style, os = this.domNode.style;
  31. os.top = viewport.t + "px";
  32. os.left = viewport.l + "px";
  33. is.width = viewport.w + "px";
  34. is.height = viewport.h + "px";
  35. // process twice since the scroll bar may have been removed
  36. // by the previous resizing
  37. var viewport2 = dijit.getViewport();
  38. if (viewport.w != viewport2.w) {
  39. is.width = viewport2.w + "px";
  40. }
  41. if (viewport.h != viewport2.h) {
  42. is.height = viewport2.h + "px";
  43. }
  44. },
  45. show : function() {
  46. this.domNode.style.display = "block";
  47. this.layout();
  48. if (this.bgIframe.iframe) {
  49. this.bgIframe.iframe.style.display = "block";
  50. }
  51. this._resizeHandler = this.connect(window, "onresize", "layout");
  52. },
  53. hide : function() {
  54. this.domNode.style.display = "none";
  55. if (this.bgIframe.iframe) {
  56. this.bgIframe.iframe.style.display = "none";
  57. }
  58. this.disconnect(this._resizeHandler);
  59. },
  60. uninitialize : function() {
  61. if (this.bgIframe) {
  62. this.bgIframe.destroy();
  63. }
  64. }
  65. });
  66. dojo.declare("dijit.Dialog", [dijit.layout.ContentPane, dijit._Templated,
  67. dijit.form._FormMixin], {
  68. // summary:
  69. // Pops up a modal dialog window, blocking access to the screen
  70. // and also graying out the screen Dialog is extended from
  71. // ContentPane so it supports all the same parameters (href,
  72. // etc.)
  73. templateString : null,
  74. templateString : "<div class=\"dijitDialog\">\n\t<div dojoAttachPoint=\"titleBar\" class=\"dijitDialogTitleBar\" tabindex=\"0\" waiRole=\"dialog\">\n\t<span dojoAttachPoint=\"titleNode\" class=\"dijitDialogTitle\">${title}</span>\n\t<span dojoAttachPoint=\"closeButtonNode\" class=\"dijitDialogCloseIcon\" dojoAttachEvent=\"onclick: hide\">\n\t\t<span dojoAttachPoint=\"closeText\" class=\"closeText\">x</span>\n\t</span>\n\t</div>\n\t\t<div dojoAttachPoint=\"containerNode\" class=\"dijitDialogPaneContent\"></div>\n\t<span dojoAttachPoint=\"tabEnd\" dojoAttachEvent=\"onfocus:_cycleFocus\" tabindex=\"0\"></span>\n</div>\n",
  75. // open: Boolean
  76. // is True or False depending on state of dialog
  77. open : false,
  78. // duration: Integer
  79. // The time in milliseconds it takes the dialog to fade in and
  80. // out
  81. duration : 400,
  82. _lastFocusItem : null,
  83. attributeMap : dojo.mixin(dojo
  84. .clone(dijit._Widget.prototype.attributeMap), {
  85. title : "titleBar"
  86. }),
  87. postCreate : function() {
  88. dojo.body().appendChild(this.domNode);
  89. this.inherited("postCreate", arguments);
  90. this.domNode.style.display = "none";
  91. this.connect(this, "onExecute", "hide");
  92. this.connect(this, "onCancel", "hide");
  93. },
  94. onLoad : function() {
  95. // summary:
  96. // when href is specified we need to reposition the dialog
  97. // after the data is loaded
  98. this._position();
  99. this.inherited("onLoad", arguments);
  100. },
  101. _setup : function() {
  102. // summary:
  103. // stuff we need to do before showing the Dialog for the
  104. // first
  105. // time (but we defer it until right beforehand, for
  106. // performance reasons)
  107. this._modalconnects = [];
  108. if (this.titleBar) {
  109. this._moveable = new dojo.dnd.Moveable(this.domNode, {
  110. handle : this.titleBar
  111. });
  112. }
  113. this._underlay = new dijit.DialogUnderlay();
  114. var node = this.domNode;
  115. this._fadeIn = dojo.fx.combine([dojo.fadeIn({
  116. node : node,
  117. duration : this.duration
  118. }), dojo.fadeIn({
  119. node : this._underlay.domNode,
  120. duration : this.duration,
  121. onBegin : dojo.hitch(
  122. this._underlay, "show")
  123. })]);
  124. this._fadeOut = dojo.fx.combine([dojo.fadeOut({
  125. node : node,
  126. duration : this.duration,
  127. onEnd : function() {
  128. node.style.display = "none";
  129. }
  130. }), dojo.fadeOut({
  131. node : this._underlay.domNode,
  132. duration : this.duration,
  133. onEnd : dojo.hitch(
  134. this._underlay, "hide")
  135. })]);
  136. },
  137. uninitialize : function() {
  138. if (this._underlay) {
  139. this._underlay.destroy();
  140. }
  141. },
  142. _position : function() {
  143. // summary: position modal dialog in center of screen
  144. if (dojo.hasClass(dojo.body(), "dojoMove")) {
  145. return;
  146. }
  147. var viewport = dijit.getViewport();
  148. var mb = dojo.marginBox(this.domNode);
  149. var style = this.domNode.style;
  150. style.left = Math.floor((viewport.l + (viewport.w - mb.w)
  151. / 2))
  152. + "px";
  153. style.top = Math.floor((viewport.t + (viewport.h - mb.h)
  154. / 2))
  155. + "px";
  156. },
  157. _findLastFocus : function(/* Event */evt) {
  158. // summary: called from onblur of dialog container to
  159. // determine the last focusable item
  160. this._lastFocused = evt.target;
  161. },
  162. _cycleFocus : function(/* Event */evt) {
  163. // summary: when tabEnd receives focus, advance focus around
  164. // to titleBar
  165. // on first focus to tabEnd, store the last focused item in
  166. // dialog
  167. if (!this._lastFocusItem) {
  168. this._lastFocusItem = this._lastFocused;
  169. }
  170. this.titleBar.focus();
  171. },
  172. _onKey : function(/* Event */evt) {
  173. if (evt.keyCode) {
  174. var node = evt.target;
  175. // see if we are shift-tabbing from titleBar
  176. if (node == this.titleBar && evt.shiftKey
  177. && evt.keyCode == dojo.keys.TAB) {
  178. if (this._lastFocusItem) {
  179. this._lastFocusItem.focus(); // send focus to
  180. // last item in
  181. // dialog if
  182. // known
  183. }
  184. dojo.stopEvent(evt);
  185. } else {
  186. // see if the key is for the dialog
  187. while (node) {
  188. if (node == this.domNode) {
  189. if (evt.keyCode == dojo.keys.ESCAPE) {
  190. this.hide();
  191. } else {
  192. return; // just let it go
  193. }
  194. }
  195. node = node.parentNode;
  196. }
  197. // this key is for the disabled document window
  198. if (evt.keyCode != dojo.keys.TAB) { // allow tabbing
  199. // into the
  200. // dialog for
  201. // a11y
  202. dojo.stopEvent(evt);
  203. // opera won't tab to a div
  204. } else if (!dojo.isOpera) {
  205. try {
  206. this.titleBar.focus();
  207. } catch (e) {/* squelch */
  208. }
  209. }
  210. }
  211. }
  212. },
  213. show : function() {
  214. // summary: display the dialog
  215. // first time we show the dialog, there's some
  216. // initialization stuff to do
  217. if (!this._alreadyInitialized) {
  218. this._setup();
  219. this._alreadyInitialized = true;
  220. }
  221. if (this._fadeOut.status() == "playing") {
  222. this._fadeOut.stop();
  223. }
  224. this._modalconnects.push(dojo.connect(window, "onscroll",
  225. this, "layout"));
  226. this._modalconnects.push(dojo.connect(
  227. document.documentElement, "onkeypress", this,
  228. "_onKey"));
  229. // IE doesn't bubble onblur events - use ondeactivate
  230. // instead
  231. var ev = typeof(document.ondeactivate) == "object"
  232. ? "ondeactivate"
  233. : "onblur";
  234. this._modalconnects.push(dojo.connect(this.containerNode,
  235. ev, this, "_findLastFocus"));
  236. dojo.style(this.domNode, "opacity", 0);
  237. this.domNode.style.display = "block";
  238. this.open = true;
  239. this._loadCheck(); // lazy load trigger
  240. this._position();
  241. this._fadeIn.play();
  242. this._savedFocus = dijit.getFocus(this);
  243. // set timeout to allow the browser to render dialog
  244. setTimeout(dojo.hitch(this, function() {
  245. dijit.focus(this.titleBar);
  246. }), 50);
  247. },
  248. hide : function() {
  249. // summary
  250. // Hide the dialog
  251. // if we haven't been initialized yet then we aren't showing
  252. // and we can just return
  253. if (!this._alreadyInitialized) {
  254. return;
  255. }
  256. if (this._fadeIn.status() == "playing") {
  257. this._fadeIn.stop();
  258. }
  259. this._fadeOut.play();
  260. if (this._scrollConnected) {
  261. this._scrollConnected = false;
  262. }
  263. dojo.forEach(this._modalconnects, dojo.disconnect);
  264. this._modalconnects = [];
  265. this.connect(this._fadeOut, "onEnd", dojo.hitch(this,
  266. function() {
  267. dijit.focus(this._savedFocus);
  268. }));
  269. this.open = false;
  270. },
  271. layout : function() {
  272. // summary: position the Dialog and the underlay
  273. if (this.domNode.style.display == "block") {
  274. this._underlay.layout();
  275. this._position();
  276. }
  277. }
  278. });
  279. dojo.declare("dijit.TooltipDialog", [dijit.layout.ContentPane,
  280. dijit._Templated, dijit.form._FormMixin], {
  281. // summary:
  282. // Pops up a dialog that appears like a Tooltip
  283. // title: String
  284. // Description of tooltip dialog (required for a11Y)
  285. title : "",
  286. _lastFocusItem : null,
  287. templateString : null,
  288. templateString : "<div class=\"dijitTooltipDialog\" >\n\t<div class=\"dijitTooltipContainer\">\n\t\t<div class =\"dijitTooltipContents dijitTooltipFocusNode\" dojoAttachPoint=\"containerNode\" tabindex=\"0\" waiRole=\"dialog\"></div>\n\t</div>\n\t<span dojoAttachPoint=\"tabEnd\" tabindex=\"0\" dojoAttachEvent=\"focus:_cycleFocus\"></span>\n\t<div class=\"dijitTooltipConnector\" ></div>\n</div>\n",
  289. postCreate : function() {
  290. this.inherited("postCreate", arguments);
  291. this.connect(this.containerNode, "onkeypress", "_onKey");
  292. // IE doesn't bubble onblur events - use ondeactivate
  293. // instead
  294. var ev = typeof(document.ondeactivate) == "object"
  295. ? "ondeactivate"
  296. : "onblur";
  297. this.connect(this.containerNode, ev, "_findLastFocus");
  298. this.containerNode.title = this.title;
  299. },
  300. orient : function(/* Object */corner) {
  301. // summary: configure widget to be displayed in given
  302. // position relative to the button
  303. this.domNode.className = "dijitTooltipDialog "
  304. + " dijitTooltipAB"
  305. + (corner.charAt(1) == 'L' ? "Left" : "Right")
  306. + " dijitTooltip"
  307. + (corner.charAt(0) == 'T' ? "Below" : "Above");
  308. },
  309. onOpen : function(/* Object */pos) {
  310. // summary: called when dialog is displayed
  311. this.orient(pos.corner);
  312. this._loadCheck(); // lazy load trigger
  313. this.containerNode.focus();
  314. },
  315. _onKey : function(/* Event */evt) {
  316. // summary: keep keyboard focus in dialog; close dialog on
  317. // escape key
  318. if (evt.keyCode == dojo.keys.ESCAPE) {
  319. this.onCancel();
  320. } else if (evt.target == this.containerNode && evt.shiftKey
  321. && evt.keyCode == dojo.keys.TAB) {
  322. if (this._lastFocusItem) {
  323. this._lastFocusItem.focus();
  324. }
  325. dojo.stopEvent(evt);
  326. } else if (evt.keyCode == dojo.keys.TAB) {
  327. // we want the browser's default tab handling to move
  328. // focus
  329. // but we don't want the tab to propagate upwards
  330. evt.stopPropagation();
  331. }
  332. },
  333. _findLastFocus : function(/* Event */evt) {
  334. // summary: called from onblur of dialog container to
  335. // determine the last focusable item
  336. this._lastFocused = evt.target;
  337. },
  338. _cycleFocus : function(/* Event */evt) {
  339. // summary: when tabEnd receives focus, advance focus around
  340. // to containerNode
  341. // on first focus to tabEnd, store the last focused item in
  342. // dialog
  343. if (!this._lastFocusItem) {
  344. this._lastFocusItem = this._lastFocused;
  345. }
  346. this.containerNode.focus();
  347. }
  348. });
  349. }