1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5'use strict';
6
7/** @suppress {duplicate} */
8var remoting = remoting || {};
9
10/**
11 * Create a new message window.
12 *
13 * @param {Object} options Message window create options
14 * @constructor
15 */
16remoting.MessageWindow = function(options) {
17  var title = /** @type {string} */ (options.title);
18  var message = /** @type {string} */ (options.message);
19  var okButtonLabel = /** @type {string} */ (options.buttonLabel);
20  var cancelButtonLabel = /** @type {string} */ (options.cancelButtonLabel);
21  var onResult = /** @type {function(number):void} */(options.onResult);
22  /** @type {number} */
23  var duration = 0;
24  if (/** @type {number?} */(options.duration)) {
25    duration = /** @type {number} */(options.duration);
26  }
27  /** @type {string} */
28  var infobox = '';
29  if (/** @type {string?} */(options.infobox)) {
30    infobox = /** @type {string} */(options.infobox);
31  }
32  var onTimeout = /** @type {?function():void} */ (options.onTimeout);
33
34  /** @type {number} */
35  this.id_ = remoting.MessageWindowManager.addMessageWindow(this);
36
37  /** @type {?function(number):void} */
38  this.onResult_ = onResult;
39
40  /** @type {Window} */
41  this.window_ = null;
42
43  /** @type {number} */
44  this.timer_ = 0;
45
46  /** @type {Array.<function():void>} */
47  this.pendingWindowOperations_ = [];
48
49  /**
50   * Callback to call when the timeout expires.
51   * @type {?function():void}
52   */
53  this.onTimeout_ = onTimeout;
54
55  var message_struct = {
56    command: 'show',
57    id: this.id_,
58    title: title,
59    message: message,
60    infobox: infobox,
61    buttonLabel: okButtonLabel,
62    cancelButtonLabel: cancelButtonLabel,
63    showSpinner: (duration != 0)
64  };
65
66  var windowAttributes = {
67    bounds: {
68      width: 400,
69      height: 100
70    },
71    resizable: false
72  };
73
74  /** @type {remoting.MessageWindow} */
75  var that = this;
76
77  /** @param {AppWindow} appWindow */
78  var onCreate = function(appWindow) {
79    that.setWindow_(/** @type {Window} */(appWindow.contentWindow));
80    var onLoad = function() {
81      appWindow.contentWindow.postMessage(message_struct, '*');
82    };
83    appWindow.contentWindow.addEventListener('load', onLoad, false);
84  };
85
86  chrome.app.window.create('message_window.html', windowAttributes, onCreate);
87
88  if (duration != 0) {
89    this.timer_ = window.setTimeout(this.onTimeoutHandler_.bind(this),
90                                    duration);
91  }
92};
93
94/**
95 * Called when the timer runs out. This in turn calls the window's
96 * timeout handler (if any).
97 */
98remoting.MessageWindow.prototype.onTimeoutHandler_ = function() {
99  this.close();
100  if (this.onTimeout_) {
101    this.onTimeout_();
102  }
103};
104
105/**
106 * Update the message being shown in the window. This should only be called
107 * after the window has been shown.
108 *
109 * @param {string} message The message.
110 */
111remoting.MessageWindow.prototype.updateMessage = function(message) {
112  if (!this.window_) {
113    this.pendingWindowOperations_.push(this.updateMessage.bind(this, message));
114    return;
115  }
116
117  var message_struct = {
118    command: 'update_message',
119    message: message
120  };
121  this.window_.postMessage(message_struct, '*');
122};
123
124/**
125 * Close the message box and unregister it with the window manager.
126 */
127remoting.MessageWindow.prototype.close = function() {
128  if (!this.window_) {
129    this.pendingWindowOperations_.push(this.close.bind(this));
130    return;
131  }
132
133  if (this.timer_) {
134    window.clearTimeout(this.timer_);
135  }
136  this.timer_ = 0;
137
138  // Unregister the window with the window manager.
139  // After this call, events sent to this window will no longer trigger the
140  // onResult callback.
141  remoting.MessageWindowManager.deleteMessageWindow(this.id_);
142  this.window_.close();
143  this.window_ = null;
144};
145
146/**
147 * Dispatch a message box result to the registered callback.
148 *
149 * @param {number} result The dialog result.
150 */
151remoting.MessageWindow.prototype.handleResult = function(result) {
152  if (this.onResult_) {
153    this.onResult_(result);
154  }
155}
156
157/**
158 * Set the window handle and run any pending operations that require it.
159 *
160 * @param {Window} window
161 * @private
162 */
163remoting.MessageWindow.prototype.setWindow_ = function(window) {
164  base.debug.assert(this.window_ == null);
165  this.window_ = window;
166  for (var i = 0; i < this.pendingWindowOperations_.length; ++i) {
167    var pendingOperation = this.pendingWindowOperations_[i];
168    pendingOperation();
169  }
170  this.pendingWindowOperations_ = [];
171};
172
173/**
174 * Static method to create and show a confirm message box.
175 *
176 * @param {string} title The title of the message box.
177 * @param {string} message The message.
178 * @param {string} okButtonLabel The text for the primary button.
179 * @param {string} cancelButtonLabel The text for the secondary button.
180 * @param {function(number):void} onResult The callback to invoke when the
181 *     user closes the message window.
182 * @return {remoting.MessageWindow}
183 */
184remoting.MessageWindow.showConfirmWindow = function(
185    title, message, okButtonLabel, cancelButtonLabel, onResult) {
186  var options = {
187    title: title,
188    message: message,
189    buttonLabel: okButtonLabel,
190    cancelButtonLabel: cancelButtonLabel,
191    onResult: onResult
192  };
193  return new remoting.MessageWindow(options);
194};
195
196/**
197 * Static method to create and show a simple message box.
198 *
199 * @param {string} title The title of the message box.
200 * @param {string} message The message.
201 * @param {string} buttonLabel The text for the primary button.
202 * @param {function(number):void} onResult The callback to invoke when the
203 *     user closes the message window.
204 * @return {remoting.MessageWindow}
205 */
206remoting.MessageWindow.showMessageWindow = function(
207    title, message, buttonLabel, onResult) {
208  var options = {
209    title: title,
210    message: message,
211    buttonLabel: buttonLabel,
212    onResult: onResult
213  };
214  return new remoting.MessageWindow(options);
215};
216
217/**
218 * Static method to create and show an error message box with an "OK" button.
219 * The app will close when the user dismisses the message window.
220 *
221 * @param {string} title The title of the message box.
222 * @param {string} message The message.
223 * @return {remoting.MessageWindow}
224 */
225remoting.MessageWindow.showErrorMessage = function(title, message) {
226  var options = {
227    title: title,
228    message: message,
229    buttonLabel: chrome.i18n.getMessage(/**i18n-content*/'OK'),
230    onResult: remoting.MessageWindow.quitApp
231  };
232  return new remoting.MessageWindow(options);
233};
234
235/**
236 * Static method to create and show a timed message box.
237 *
238 * @param {string} title The title of the message box.
239 * @param {string} message The message.
240 * @param {string} infobox Additional information to be displayed in an infobox,
241 *     or the empty string if there is no additional information.
242 * @param {string} buttonLabel The text for the primary button.
243 * @param {function(number):void} onResult The callback to invoke when the
244 *     user closes the message window.
245 * @param {number} duration Time for wait before calling onTime
246 * @param {?function():void} onTimeout Callback function.
247 * @return {remoting.MessageWindow}
248 */
249remoting.MessageWindow.showTimedMessageWindow = function(
250    title, message, infobox, buttonLabel, onResult, duration, onTimeout) {
251  var options = {
252    title: title,
253    message: message,
254    infobox: infobox,
255    buttonLabel: buttonLabel,
256    onResult: onResult,
257    duration: duration,
258    onTimeout: onTimeout
259  };
260  return new remoting.MessageWindow(options);
261};
262
263/**
264 * Cancel the current connection and close all app windows.
265 *
266 * @param {number} result The dialog result.
267 */
268remoting.MessageWindow.quitApp = function(result) {
269  remoting.MessageWindowManager.closeAllMessageWindows();
270  window.close();
271};
272