| OLD | NEW |
| (Empty) | |
| 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. |
| 4 |
| 5 cr.define('print_preview', function() { |
| 6 'use strict'; |
| 7 |
| 8 /** @enum {string} */ |
| 9 var ResolverState = { |
| 10 INITIAL: 'INITIAL', |
| 11 ACTIVE: 'ACTIVE', |
| 12 GRANTING_PERMISSION: 'GRANTING_PERMISSION', |
| 13 ERROR: 'ERROR', |
| 14 DONE: 'DONE' |
| 15 }; |
| 16 |
| 17 /** |
| 18 * Utility class for bundling a promise object with it's resolver methods. |
| 19 * @param {!Promise<!print_preview.Destination>} promise A promise returning |
| 20 * a destination. |
| 21 * @param {function(!print_preview.Destination)} resolve Function resolving |
| 22 * the promise. |
| 23 * @param {function()} reject Function for rejecting the promise. |
| 24 * @constructor @struct |
| 25 */ |
| 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()} */ |
| 32 this.reject = reject; |
| 33 } |
| 34 |
| 35 /** |
| 36 * Create a Promise and an associated PromiseResolver. |
| 37 * @return {!PromiseResolver} |
| 38 */ |
| 39 PromiseResolver.create = function() { |
| 40 var reject = null; |
| 41 var resolve = null; |
| 42 /** @type {!Promise<!print_preview.Destination>} */ |
| 43 var promise = new Promise(function(resolvePromise, rejectPromise) { |
| 44 resolve = /** @type {function(!print_preview.Destination)}*/( |
| 45 resolvePromise); |
| 46 reject = /** @type {function()} */(rejectPromise); |
| 47 }); |
| 48 |
| 49 return new PromiseResolver(promise, resolve, reject); |
| 50 }; |
| 51 |
| 52 /** |
| 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. |
| 59 * |
| 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 |
| 64 * to be resolved. |
| 65 * @constructor |
| 66 * @extends {print_preview.Overlay} |
| 67 */ |
| 68 function ProvisionalDestinationResolver(destinationStore, destination) { |
| 69 print_preview.Overlay.call(this); |
| 70 |
| 71 /** @private {!print_preview.DestinationStore} */ |
| 72 this.destinationStore_ = destinationStore; |
| 73 /** @private {!print_preview.Destination} */ |
| 74 this.destination_ = destination; |
| 75 |
| 76 /** @private {ResolverState} */ |
| 77 this.state_ = ResolverState.INITIAL; |
| 78 |
| 79 /** |
| 80 * Promise resolver for promise returned by {@code this.run}. |
| 81 * @private {?PromiseResolver} |
| 82 */ |
| 83 this.promiseResolver_ = null; |
| 84 } |
| 85 |
| 86 /** |
| 87 * @param {!print_preview.DestinationStore} store |
| 88 * @param {!print_preview.Destination} destination |
| 89 * @return {?ProvisionalDestinationResolver} |
| 90 */ |
| 91 ProvisionalDestinationResolver.create = function(store, destination) { |
| 92 if (destination.provisionalType != |
| 93 print_preview.Destination.ProvisionalType.NEEDS_USB_PERMISSION) { |
| 94 return null; |
| 95 } |
| 96 return new ProvisionalDestinationResolver(store, destination); |
| 97 }; |
| 98 |
| 99 ProvisionalDestinationResolver.prototype = { |
| 100 __proto__: print_preview.Overlay.prototype, |
| 101 |
| 102 /** @override */ |
| 103 enterDocument: function() { |
| 104 print_preview.Overlay.prototype.enterDocument.call(this); |
| 105 |
| 106 this.tracker.add( |
| 107 this.getChildElement('.usb-permission-ok-button'), |
| 108 'click', |
| 109 this.startResolveDestination_.bind(this)); |
| 110 this.tracker.add( |
| 111 this.getChildElement('.cancel'), |
| 112 'click', |
| 113 this.cancel.bind(this)); |
| 114 |
| 115 this.tracker.add( |
| 116 this.destinationStore_, |
| 117 print_preview.DestinationStore.EventType |
| 118 .PROVISIONAL_DESTINATION_RESOLVED, |
| 119 this.onDestinationResolved_.bind(this)); |
| 120 }, |
| 121 |
| 122 /** @override */ |
| 123 onSetVisibleInternal: function(visible) { |
| 124 if (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; |
| 136 } |
| 137 }, |
| 138 |
| 139 /** @override */ |
| 140 createDom: function() { |
| 141 this.setElementInternal(this.cloneTemplateInternal( |
| 142 'extension-usb-resolver')); |
| 143 |
| 144 var extNameEl = this.getChildElement('.usb-permission-extension-name'); |
| 145 extNameEl.title = this.destination_.extensionName; |
| 146 extNameEl.textContent = this.destination_.extensionName; |
| 147 |
| 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)'; |
| 154 }, |
| 155 |
| 156 /** |
| 157 * Handler for click on OK button. It initiates destination resolving. |
| 158 * @private |
| 159 */ |
| 160 startResolveDestination_: function() { |
| 161 assert(this.state_ == ResolverState.ACTIVE, |
| 162 'Invalid state in request grant permission'); |
| 163 |
| 164 this.setState_(ResolverState.GRANTING_PERMISSION); |
| 165 this.destinationStore_.resolveProvisionalDestination(this.destination_); |
| 166 }, |
| 167 |
| 168 /** |
| 169 * Handler for PROVISIONAL_DESTINATION_RESOLVED event. It finalizes the |
| 170 * resolver state once the destination associated with the resolver gets |
| 171 * resolved. |
| 172 * @param {Event} event |
| 173 * @private |
| 174 */ |
| 175 onDestinationResolved_: function(event) { |
| 176 if (this.state_ == ResolverState.DONE) |
| 177 return; |
| 178 |
| 179 if (event.provisionalId != this.destination_.id) |
| 180 return; |
| 181 |
| 182 if (event.destination) { |
| 183 this.setState_(ResolverState.DONE); |
| 184 this.promiseResolver_.resolve(event.destination); |
| 185 this.promiseResolver_ = null; |
| 186 this.setIsVisible(false); |
| 187 } else { |
| 188 this.setState_(ResolverState.ERROR); |
| 189 } |
| 190 }, |
| 191 |
| 192 /** |
| 193 * Sets new resolver state and updates the UI accordingly. |
| 194 * @param {ResolverState} state |
| 195 * @private |
| 196 */ |
| 197 setState_: function(state) { |
| 198 if (this.state_ == state) |
| 199 return; |
| 200 |
| 201 this.state_ = state; |
| 202 this.updateUI_(); |
| 203 }, |
| 204 |
| 205 /** |
| 206 * Updates the resolver overlay UI to match the resolver state. |
| 207 * @private |
| 208 */ |
| 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; |
| 214 |
| 215 // If OK button is disabled, make sure Cancel button gets focus. |
| 216 if (this.state_ != ResolverState.ACTIVE) |
| 217 this.getChildElement('.cancel').focus(); |
| 218 |
| 219 this.getChildElement('.throbber-placeholder').classList.toggle( |
| 220 'throbber', |
| 221 this.state_ == ResolverState.GRANTING_PERMISSION); |
| 222 |
| 223 this.getChildElement('.usb-permission-extension-desc').hidden = |
| 224 this.state_ == ResolverState.ERROR; |
| 225 |
| 226 this.getChildElement('.usb-permission-message').textContent = |
| 227 this.state_ == ResolverState.ERROR ? |
| 228 loadTimeData.getStringF('resolveExtensionUSBErrorMessage', |
| 229 this.destination_.extensionName) : |
| 230 loadTimeData.getString('resolveExtensionUSBPermissionMessage'); |
| 231 }, |
| 232 |
| 233 /** |
| 234 * Initiates and shows the resolver overlay. |
| 235 * @param {!HTMLElement} parent The element that should parent the resolver |
| 236 * UI. |
| 237 * @return {!Promise<!print_preview.Destination>} Promise that will be |
| 238 * fulfilled when the destination resolving is finished. |
| 239 */ |
| 240 run: function(parent) { |
| 241 this.render(parent); |
| 242 this.setIsVisible(true); |
| 243 |
| 244 assert(this.promiseResolver_, 'Promise resolver not created.'); |
| 245 return this.promiseResolver_.promise; |
| 246 } |
| 247 }; |
| 248 |
| 249 return { |
| 250 ProvisionalDestinationResolver: ProvisionalDestinationResolver |
| 251 }; |
| 252 }); |
| OLD | NEW |