1 // Copyright 2015 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.
5 /** @suppress {duplicate} */
6 var remoting
= remoting
|| {};
13 * A helper class for implementing dialogs with an input field using
16 * @param {remoting.AppMode} mode
17 * @param {HTMLElement} formElement
18 * @param {HTMLElement} inputField
19 * @param {HTMLElement} cancelButton
23 remoting
.InputDialog = function(mode
, formElement
, inputField
, cancelButton
) {
27 this.formElement_
= formElement
;
29 this.cancelButton_
= cancelButton
;
31 this.inputField_
= inputField
;
32 /** @private {base.Deferred} */
33 this.deferred_
= null;
34 /** @private {base.Disposables} */
35 this.eventHooks_
= null;
39 * @return {Promise<string>} Promise that resolves with the value of the
40 * inputField or rejects with |remoting.Error.CANCELLED| if the user clicks
41 * on the cancel button.
43 remoting
.InputDialog
.prototype.show = function() {
44 var onCancel
= this.createFormEventHandler_(this.onCancel_
.bind(this));
45 var onOk
= this.createFormEventHandler_(this.onSubmit_
.bind(this));
47 this.eventHooks_
= new base
.Disposables(
48 new base
.DomEventHook(this.formElement_
, 'submit', onOk
, false),
49 new base
.DomEventHook(this.cancelButton_
, 'click', onCancel
, false));
50 console
.assert(this.deferred_
=== null, 'No deferred Promise found.');
51 this.deferred_
= new base
.Deferred();
52 remoting
.setMode(this.appMode_
);
53 return this.deferred_
.promise();
56 /** @return {HTMLElement} */
57 remoting
.InputDialog
.prototype.inputField = function() {
58 return this.inputField_
;
62 remoting
.InputDialog
.prototype.onSubmit_ = function() {
63 this.deferred_
.resolve(this.inputField_
.value
);
67 remoting
.InputDialog
.prototype.onCancel_ = function() {
68 this.deferred_
.reject(new remoting
.Error(remoting
.Error
.Tag
.CANCELLED
));
72 * @param {function():void} handler
76 remoting
.InputDialog
.prototype.createFormEventHandler_ = function(handler
) {
78 return function (/** Event */ e
) {
79 // Prevents form submission from reloading the v1 app.
82 // Set the focus away from the password field. This has to be done
83 // before the password field gets hidden, to work around a Blink
84 // clipboard-handling bug - http://crbug.com/281523.
85 that
.cancelButton_
.focus();
87 base
.dispose(that
.eventHooks_
);
88 that
.eventHooks_
= null;
89 that
.deferred_
= null;
94 * A helper class for implementing MessageDialog with a primary and
95 * and secondary button using remoting.setMode().
97 * @param {remoting.AppMode} mode
98 * @param {HTMLElement} primaryButton
99 * @param {HTMLElement=} opt_secondaryButton
102 * @implements {base.Disposable}
104 remoting
.MessageDialog = function(mode
, primaryButton
, opt_secondaryButton
) {
105 /** @private @const */
107 /** @private @const */
108 this.primaryButton_
= primaryButton
;
109 /** @private @const */
110 this.secondaryButton_
= opt_secondaryButton
;
111 /** @private {base.Deferred} */
112 this.deferred_
= null;
113 /** @private {base.Disposables} */
114 this.eventHooks_
= null;
118 * @return {Promise<remoting.MessageDialog.Result>} Promise that resolves with
119 * the button clicked.
121 remoting
.MessageDialog
.prototype.show = function() {
122 console
.assert(this.eventHooks_
=== null, 'Duplicate show() invocation.');
123 this.eventHooks_
= new base
.Disposables(new base
.DomEventHook(
124 this.primaryButton_
, 'click',
125 this.onClicked_
.bind(this, remoting
.MessageDialog
.Result
.PRIMARY
),
128 if (this.secondaryButton_
) {
129 this.eventHooks_
.add(new base
.DomEventHook(
130 this.secondaryButton_
, 'click',
131 this.onClicked_
.bind(this, remoting
.MessageDialog
.Result
.SECONDARY
),
135 console
.assert(this.deferred_
=== null, 'No deferred Promise found.');
136 this.deferred_
= new base
.Deferred();
137 remoting
.setMode(this.mode_
);
138 return this.deferred_
.promise();
141 remoting
.MessageDialog
.prototype.dispose = function() {
142 base
.dispose(this.eventHooks_
);
143 this.eventHooks_
= null;
144 if (this.deferred_
) {
145 this.deferred_
.reject(new remoting
.Error(remoting
.Error
.Tag
.CANCELLED
));
147 this.deferred_
= null;
151 * @param {remoting.MessageDialog.Result} result
155 remoting
.MessageDialog
.prototype.onClicked_ = function(result
) {
156 this.deferred_
.resolve(result
);
157 this.deferred_
= null;
164 * A promise-based dialog implementation using the <dialog> element.
166 * @param {remoting.Html5ModalDialog.Params} params
169 * @implements {remoting.WindowShape.ClientUI}
170 * @implements {base.Disposable}
172 remoting
.Html5ModalDialog = function(params
) {
174 this.dialog_
= params
.dialog
;
176 /** @private {base.Disposables} */
177 this.eventHooks_
= new base
.Disposables(
178 new base
.DomEventHook(
179 this.dialog_
, 'cancel', this.onCancel_
.bind(this), false),
180 new base
.DomEventHook(
181 params
.primaryButton
, 'click',
182 this.close
.bind(this, remoting
.MessageDialog
.Result
.PRIMARY
), false)
185 if (params
.secondaryButton
) {
186 this.eventHooks_
.add(new base
.DomEventHook(
187 params
.secondaryButton
, 'click',
188 this.close
.bind(this, remoting
.MessageDialog
.Result
.SECONDARY
), false));
192 this.closeOnEscape_
= Boolean(params
.closeOnEscape
);
195 this.windowShape_
= params
.windowShape
;
197 /** @private {base.Deferred} */
198 this.deferred_
= null;
201 remoting
.Html5ModalDialog
.prototype.dispose = function() {
202 if (this.dialog_
.open
) {
203 this.close(remoting
.MessageDialog
.Result
.CANCEL
);
205 base
.dispose(this.eventHooks_
);
206 this.eventHookes_
= null;
210 * @return {Promise<remoting.MessageDialog.Result>} Promise that resolves with
211 * the button clicked.
213 remoting
.Html5ModalDialog
.prototype.show = function() {
214 console
.assert(this.deferred_
=== null, 'No deferred Promise found.');
215 this.deferred_
= new base
.Deferred();
216 this.dialog_
.showModal();
217 if (this.windowShape_
) {
218 this.windowShape_
.registerClientUI(this);
219 this.windowShape_
.centerToDesktop(this.dialog_
);
221 return this.deferred_
.promise();
224 /** @param {Event} e */
225 remoting
.Html5ModalDialog
.prototype.onCancel_ = function(e
) {
227 if (this.closeOnEscape_
) {
228 this.close(remoting
.MessageDialog
.Result
.CANCEL
);
233 * @param {remoting.MessageDialog.Result} result
235 remoting
.Html5ModalDialog
.prototype.close = function(result
) {
236 if (!this.dialog_
.open
) {
239 this.dialog_
.close();
240 this.deferred_
.resolve(result
);
241 this.deferred_
= null;
242 if (this.windowShape_
) {
243 this.windowShape_
.unregisterClientUI(this);
247 remoting
.Html5ModalDialog
.prototype.addToRegion = function(rects
) {
248 var rect
= /** @type {ClientRect} */(this.dialog_
.getBoundingClientRect());
250 // If the dialog is repositioned by setting the left and top, it takes a while
251 // for getBoundingClientRect() to update the rectangle.
252 var left
= this.dialog_
.style
.left
;
253 var top
= this.dialog_
.style
.top
;
256 left
: (left
=== '') ? rect
.left
: parseInt(left
, 10),
257 top
: (top
=== '') ? rect
.top
: parseInt(top
, 10),
265 * @param {Function} cancelCallback The callback to invoke when the user clicks
266 * on the cancel button.
269 remoting
.ConnectingDialog = function(cancelCallback
) {
271 this.dialog_
= new remoting
.MessageDialog(
272 remoting
.AppMode
.CLIENT_CONNECTING
,
273 document
.getElementById('cancel-connect-button'));
275 this.onCancel_
= cancelCallback
;
278 remoting
.ConnectingDialog
.prototype.show = function() {
280 this.dialog_
.show().then(function() {
281 remoting
.setMode(remoting
.AppMode
.HOME
);
283 // The promise rejects when the dialog is hidden. Don't report that as error.
284 }).catch(remoting
.Error
.handler(base
.doNothing
));
287 remoting
.ConnectingDialog
.prototype.hide = function() {
288 this.dialog_
.dispose();
292 * A factory object for the modal dialogs. The factory will be stubbed out in
293 * unit test to avoid UI dependencies on remoting.setMode().
297 remoting
.ModalDialogFactory = function() {};
300 * @param {Function} cancelCallback
301 * @return {remoting.ConnectingDialog}
303 remoting
.ModalDialogFactory
.prototype.createConnectingDialog
=
304 function(cancelCallback
) {
305 return new remoting
.ConnectingDialog(cancelCallback
);
309 * @param {remoting.Html5ModalDialog.Params} params
310 * @return {remoting.Html5ModalDialog}
312 remoting
.ModalDialogFactory
.prototype.createHtml5ModalDialog
=
314 return new remoting
.Html5ModalDialog(params
);
318 * @param {remoting.AppMode} mode
319 * @param {HTMLElement} primaryButton
320 * @param {HTMLElement=} opt_secondaryButton
321 * @return {remoting.MessageDialog}
323 remoting
.ModalDialogFactory
.prototype.createMessageDialog
=
324 function(mode
, primaryButton
, opt_secondaryButton
) {
325 return new remoting
.MessageDialog(mode
, primaryButton
, opt_secondaryButton
);
329 * @param {remoting.AppMode} mode
330 * @param {HTMLElement} formElement
331 * @param {HTMLElement} inputField
332 * @param {HTMLElement} cancelButton
333 * @return {remoting.InputDialog}
335 remoting
.ModalDialogFactory
.prototype.createInputDialog
=
336 function(mode
, formElement
, inputField
, cancelButton
) {
337 return new remoting
.InputDialog(mode
, formElement
, inputField
, cancelButton
);
340 /** @type {remoting.ModalDialogFactory} */
341 remoting
.modalDialogFactory
= new remoting
.ModalDialogFactory();
346 * Define the enum at the end of file as JSCompile doesn't understand enums that
347 * are defined within an IIFE (Immediately Invoked Function Expression).
350 remoting
.MessageDialog
.Result
= {
353 CANCEL
: 2 // User presses the escape button.
357 * Parameters for the remoting.Html5ModalDialog constructor. Unless otherwise
358 * noted, all parameters are optional.
360 * dialog: (required) The HTML dialog element.
362 * primaryButton: (required) The HTML element of the primary button.
364 * secondaryButton: The HTML element of the secondary button.
366 * closeOnEscape: Whether the user can dismiss the dialog by pressing the escape
367 * key. Default to false.
370 * dialog: HTMLDialogElement,
371 * primaryButton:HTMLElement,
372 * secondaryButton:(HTMLElement|undefined),
373 * closeOnEscape:(boolean|undefined),
374 * windowShape:(remoting.WindowShape|undefined)
377 remoting
.Html5ModalDialog
.Params
;