]> git.donarmstrong.com Git - dactyl.git/blob - common/tests/functional/shared-modules/modal-dialog.js
Initial import of 1.0~b6
[dactyl.git] / common / tests / functional / shared-modules / modal-dialog.js
1 /* ***** BEGIN LICENSE BLOCK *****
2  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3  *
4  * The contents of this file are subject to the Mozilla Public License Version
5  * 1.1 (the "License"); you may not use this file except in compliance with
6  * the License. You may obtain a copy of the License at
7  * http://www.mozilla.org/MPL/
8  *
9  * Software distributed under the License is distributed on an "AS IS" basis,
10  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11  * for the specific language governing rights and limitations under the
12  * License.
13  *
14  * The Original Code is MozMill Test code.
15  *
16  * The Initial Developer of the Original Code is Mozilla Foundation.
17  * Portions created by the Initial Developer are Copyright (C) 2009
18  * the Initial Developer. All Rights Reserved.
19  *
20  * Contributor(s):
21  *   Clint Talbert <ctalbert@mozilla.com>
22  *   Henrik Skupin <hskupin@mozilla.com>
23  *
24  * Alternatively, the contents of this file may be used under the terms of
25  * either the GNU General Public License Version 2 or later (the "GPL"), or
26  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27  * in which case the provisions of the GPL or the LGPL are applicable instead
28  * of those above. If you wish to allow use of your version of this file only
29  * under the terms of either the GPL or the LGPL, and not to allow others to
30  * use your version of this file under the terms of the MPL, indicate your
31  * decision by deleting the provisions above and replace them with the notice
32  * and other provisions required by the GPL or the LGPL. If you do not delete
33  * the provisions above, a recipient may use your version of this file under
34  * the terms of any one of the MPL, the GPL or the LGPL.
35  *
36  * ***** END LICENSE BLOCK ***** */
37
38 // Include required modules
39 var domUtils = require("dom-utils");
40
41 const TIMEOUT_MODAL_DIALOG = 5000;
42 const DELAY_CHECK = 100;
43
44 /**
45  * Observer object to find the modal dialog spawned by a controller
46  *
47  * @constructor
48  * @class Observer used to find a modal dialog
49  *
50  * @param {object} aOpener
51  *        Window which is the opener of the modal dialog
52  * @param {function} aCallback
53  *        The callback handler to use to interact with the modal dialog
54  */
55 function mdObserver(aOpener, aCallback) {
56   this._opener = aOpener;
57   this._callback = aCallback;
58   this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
59 }
60
61 mdObserver.prototype = {
62
63   /**
64    * Set our default values for our internal properties
65    */
66   _opener : null,
67   _callback: null,
68   _timer: null,
69   exception: null,
70   finished: false,
71
72   /**
73    * Check if the modal dialog has been opened
74    *
75    * @returns {object} The modal dialog window found, or null.
76    */
77   findWindow : function mdObserver_findWindow() {
78     // If a window has been opened from content, it has to be unwrapped.
79     var window = domUtils.unwrapNode(mozmill.wm.getMostRecentWindow(''));
80
81     // Get the WebBrowserChrome and check if it's a modal window
82     var chrome = window.QueryInterface(Ci.nsIInterfaceRequestor).
83                  getInterface(Ci.nsIWebNavigation).
84                  QueryInterface(Ci.nsIDocShellTreeItem).
85                  treeOwner.
86                  QueryInterface(Ci.nsIInterfaceRequestor).
87                  getInterface(Ci.nsIWebBrowserChrome);
88     if (!chrome.isWindowModal()) {
89       return null;
90     }
91
92     // Opening a modal dialog from a modal dialog would fail, if we wouldn't
93     // check for the opener of the modal dialog
94     var found = false;
95     if (window.opener) {
96       // XXX Bug 614757 - an already unwrapped node returns a wrapped node
97       var opener = domUtils.unwrapNode(window.opener);
98       found = (mozmill.utils.getChromeWindow(opener) == this._opener);
99     }
100     else {
101       // Also note that it could happen that dialogs don't have an opener
102       // (i.e. clear recent history). In such a case make sure that the most
103       // recent window is not the passed in reference opener
104       found = (window != this._opener);
105     }
106
107     return (found ? window : null);
108   },
109
110   /**
111    * Called by the timer in the given interval to check if the modal dialog has
112    * been opened. Once it has been found the callback gets executed
113    *
114    * @param {object} aSubject Not used.
115    * @param {string} aTopic Not used.
116    * @param {string} aData Not used.
117    */
118   observe : function mdObserver_observe(aSubject, aTopic, aData) {
119     // Once the window has been found and loaded we can execute the callback
120     var window = this.findWindow();
121     if (window && ("documentLoaded" in window)) {
122       try {
123         this._callback(new mozmill.controller.MozMillController(window));
124       }
125       catch (ex) {
126         // Store the exception, so it can be forwarded if a modal dialog has
127         // been opened by another modal dialog
128         this.exception = ex;
129       }
130
131       if (window) {
132         window.close();
133       }
134
135       this.finished = true;
136       this.stop();
137     }
138     else {
139       // otherwise try again in a bit
140       this._timer.init(this, DELAY_CHECK, Ci.nsITimer.TYPE_ONE_SHOT);
141     }
142   },
143
144   /**
145    * Stop the timer which checks for new modal dialogs
146    */
147   stop : function mdObserver_stop() {
148     delete this._timer;
149   }
150 };
151
152
153 /**
154  * Creates a new instance of modalDialog.
155  *
156  * @constructor
157  * @class Handler for modal dialogs
158  *
159  * @param {object} aWindow [optional - default: null]
160  *        Window which is the opener of the modal dialog
161  */
162 function modalDialog(aWindow) {
163   this._window = aWindow || null;
164 }
165
166 modalDialog.prototype = {
167
168   /**
169    * Simply checks if the modal dialog has been processed
170    *
171    * @returns {boolean} True, if the dialog has been processed
172    */
173   get finished() {
174     return (!this._observer || this._observer.finished);
175   },
176
177   /**
178    * Start timer to wait for the modal dialog.
179    *
180    * @param {function} aCallback
181    *        The callback handler to use to interact with the modal dialog
182    */
183   start : function modalDialog_start(aCallback) {
184     if (!aCallback)
185       throw new Error(arguments.callee.name + ": Callback not specified.");
186
187     this._observer = new mdObserver(this._window, aCallback);
188
189     this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
190     this._timer.init(this._observer, DELAY_CHECK, Ci.nsITimer.TYPE_ONE_SHOT);
191   },
192
193   /**
194    * Stop the timer which checks for new modal dialogs
195    */
196   stop : function modalDialog_stop() {
197     delete this._timer;
198
199     if (this._observer) {
200       this._observer.stop();
201       this._observer = null;
202     }
203   },
204
205   /**
206    * Wait until the modal dialog has been processed.
207    *
208    * @param {Number} aTimeout (optional - default 5s)
209    *        Duration to wait
210    */
211   waitForDialog : function modalDialog_waitForDialog(aTimeout) {
212     var timeout = aTimeout || TIMEOUT_MODAL_DIALOG;
213
214     if (!this._observer) {
215       return;
216     }
217
218     try {
219       mozmill.utils.waitFor(function () {
220         return this.finished;
221       }, "Modal dialog has been found and processed", timeout, undefined, this);
222
223       // Forward the raised exception so we can detect failures in modal dialogs
224       if (this._observer.exception) {
225         throw this._observer.exception;
226       }
227     }
228     finally {
229       this.stop();
230     }
231   }
232 }
233
234
235 // Export of classes
236 exports.modalDialog = modalDialog;