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 cr.define('print_preview', function() {
12 GRANTING_PERMISSION: 'GRANTING_PERMISSION',
18 * Utility class for bundling a promise object with it's resolver methods.
19 * @param {!Promise<!print_preview.Destination>} promise A promise returning
21 * @param {function(!print_preview.Destination)} resolve Function resolving
23 * @param {function()} reject Function for rejecting the promise.
24 * @constructor @struct
26 function PromiseResolver(promise, resolve, reject) {
27 /** @type {!Promise<!print_preview.Destination>} */
28 this.promise = promise;
29 /** @type {function(!print_preview.Destination)} */
30 this.resolve = resolve;
31 /** @type {function()} */
36 * Create a Promise and an associated PromiseResolver.
37 * @return {!PromiseResolver}
39 PromiseResolver.create = function() {
42 /** @type {!Promise<!print_preview.Destination>} */
43 var promise = new Promise(function(resolvePromise, rejectPromise) {
44 resolve = /** @type {function(!print_preview.Destination)}*/(
46 reject = /** @type {function()} */(rejectPromise);
49 return new PromiseResolver(promise, resolve, reject);
53 * Overlay used to resolve a provisional extension destination. The user is
54 * prompted to allow print preview to grant a USB device access to an
55 * extension associated with the destination. If user agrees destination
56 * resolvement is attempted (which includes granting the extension USB access
57 * and requesting destination description from the extension). The overlay is
58 * hidden when destination resolving is done.
60 * @param {!print_preview.DestinationStore} destinationStore The destination
61 * store containing the destination. Used as a proxy to native layer for
62 * resolving the destination.
63 * @param {!print_preview.Destination} destination The destination that has
66 * @extends {print_preview.Overlay}
68 function ProvisionalDestinationResolver(destinationStore, destination) {
69 print_preview.Overlay.call(this);
71 /** @private {!print_preview.DestinationStore} */
72 this.destinationStore_ = destinationStore;
73 /** @private {!print_preview.Destination} */
74 this.destination_ = destination;
76 /** @private {ResolverState} */
77 this.state_ = ResolverState.INITIAL;
80 * Promise resolver for promise returned by {@code this.run}.
81 * @private {?PromiseResolver}
83 this.promiseResolver_ = null;
87 * @param {!print_preview.DestinationStore} store
88 * @param {!print_preview.Destination} destination
89 * @return {?ProvisionalDestinationResolver}
91 ProvisionalDestinationResolver.create = function(store, destination) {
92 if (destination.provisionalType !=
93 print_preview.Destination.ProvisionalType.NEEDS_USB_PERMISSION) {
96 return new ProvisionalDestinationResolver(store, destination);
99 ProvisionalDestinationResolver.prototype = {
100 __proto__: print_preview.Overlay.prototype,
103 enterDocument: function() {
104 print_preview.Overlay.prototype.enterDocument.call(this);
107 this.getChildElement('.usb-permission-ok-button'),
109 this.startResolveDestination_.bind(this));
111 this.getChildElement('.cancel'),
113 this.cancel.bind(this));
116 this.destinationStore_,
117 print_preview.DestinationStore.EventType
118 .PROVISIONAL_DESTINATION_RESOLVED,
119 this.onDestinationResolved_.bind(this));
123 onSetVisibleInternal: function(visible) {
125 assert(this.state_ == ResolverState.INITIAL,
126 'Showing overlay while not in initial state.');
127 assert(!this.promiseResolver_, 'Promise resolver already set.');
128 this.setState_(ResolverState.ACTIVE);
129 this.promiseResolver_ = PromiseResolver.create();
130 this.getChildElement('.default').focus();
131 } else if (this.state_ != ResolverState.DONE) {
132 assert(this.state_ != ResolverState.INITIAL, 'Hiding in initial state');
133 this.setState_(ResolverState.DONE);
134 this.promiseResolver_.reject();
135 this.promiseResolver_ = null;
140 createDom: function() {
141 this.setElementInternal(this.cloneTemplateInternal(
142 'extension-usb-resolver'));
144 var extNameEl = this.getChildElement('.usb-permission-extension-name');
145 extNameEl.title = this.destination_.extensionName;
146 extNameEl.textContent = this.destination_.extensionName;
148 var extIconEl = this.getChildElement('.usb-permission-extension-icon');
149 extIconEl.style.backgroundImage = '-webkit-image-set(' +
150 'url(chrome://extension-icon/' +
151 this.destination_.extensionId + '/24/1) 1x,' +
152 'url(chrome://extension-icon/' +
153 this.destination_.extensionId + '/48/1) 2x)';
157 * Handler for click on OK button. It initiates destination resolving.
160 startResolveDestination_: function() {
161 assert(this.state_ == ResolverState.ACTIVE,
162 'Invalid state in request grant permission');
164 this.setState_(ResolverState.GRANTING_PERMISSION);
165 this.destinationStore_.resolveProvisionalDestination(this.destination_);
169 * Handler for PROVISIONAL_DESTINATION_RESOLVED event. It finalizes the
170 * resolver state once the destination associated with the resolver gets
172 * @param {Event} event
175 onDestinationResolved_: function(event) {
176 if (this.state_ == ResolverState.DONE)
179 if (event.provisionalId != this.destination_.id)
182 if (event.destination) {
183 this.setState_(ResolverState.DONE);
184 this.promiseResolver_.resolve(event.destination);
185 this.promiseResolver_ = null;
186 this.setIsVisible(false);
188 this.setState_(ResolverState.ERROR);
193 * Sets new resolver state and updates the UI accordingly.
194 * @param {ResolverState} state
197 setState_: function(state) {
198 if (this.state_ == state)
206 * Updates the resolver overlay UI to match the resolver state.
209 updateUI_: function() {
210 this.getChildElement('.usb-permission-ok-button').hidden =
211 this.state_ == ResolverState.ERROR;
212 this.getChildElement('.usb-permission-ok-button').disabled =
213 this.state_ != ResolverState.ACTIVE;
215 // If OK button is disabled, make sure Cancel button gets focus.
216 if (this.state_ != ResolverState.ACTIVE)
217 this.getChildElement('.cancel').focus();
219 this.getChildElement('.throbber-placeholder').classList.toggle(
221 this.state_ == ResolverState.GRANTING_PERMISSION);
223 this.getChildElement('.usb-permission-extension-desc').hidden =
224 this.state_ == ResolverState.ERROR;
226 this.getChildElement('.usb-permission-message').textContent =
227 this.state_ == ResolverState.ERROR ?
228 loadTimeData.getStringF('resolveExtensionUSBErrorMessage',
229 this.destination_.extensionName) :
230 loadTimeData.getString('resolveExtensionUSBPermissionMessage');
234 * Initiates and shows the resolver overlay.
235 * @param {!HTMLElement} parent The element that should parent the resolver
237 * @return {!Promise<!print_preview.Destination>} Promise that will be
238 * fulfilled when the destination resolving is finished.
240 run: function(parent) {
242 this.setIsVisible(true);
244 assert(this.promiseResolver_, 'Promise resolver not created.');
245 return this.promiseResolver_.promise;
250 ProvisionalDestinationResolver: ProvisionalDestinationResolver