OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * CWSWidgetContainer contains a Chrome Web Store widget that displays list of | 6 * CWSWidgetContainer contains a Chrome Web Store widget that displays list of |
7 * apps that satisfy certain constraints (e.g. fileHandler apps that can handle | 7 * apps that satisfy certain constraints (e.g. fileHandler apps that can handle |
8 * files with specific file extension or MIME type) and enables the user to | 8 * files with specific file extension or MIME type) and enables the user to |
9 * install apps directly from it. | 9 * install apps directly from it. |
10 * CWSWidgetContainer implements client side of the widget, which handles | 10 * CWSWidgetContainer implements client side of the widget, which handles |
(...skipping 29 matching lines...) Expand all Loading... |
40 */ | 40 */ |
41 var CWS_WIDGET_ORIGIN = 'https://clients5.google.com'; | 41 var CWS_WIDGET_ORIGIN = 'https://clients5.google.com'; |
42 | 42 |
43 /** | 43 /** |
44 * Creates the widget container element in DOM tree. | 44 * Creates the widget container element in DOM tree. |
45 * | 45 * |
46 * @param {!HTMLDocument} document The document to contain this container. | 46 * @param {!HTMLDocument} document The document to contain this container. |
47 * @param {!HTMLElement} parentNode Node to be parent for this container. | 47 * @param {!HTMLElement} parentNode Node to be parent for this container. |
48 * @param {!CWSWidgetContainer.PlatformDelegate} delegate Delegate for accessing | 48 * @param {!CWSWidgetContainer.PlatformDelegate} delegate Delegate for accessing |
49 * Chrome platform APIs. | 49 * Chrome platform APIs. |
50 * @param {!SuggestAppDialogState} state Static state of suggest app dialog. | 50 * @param {!{ |
| 51 * overrideCwsContainerUrlForTest: (string|undefined), |
| 52 * overrideCwsContainerOriginForTest: (string|undefined) |
| 53 * }} params Overrides for container params. |
51 * @constructor | 54 * @constructor |
52 */ | 55 */ |
53 function CWSWidgetContainer(document, parentNode, delegate, state) { | 56 function CWSWidgetContainer(document, parentNode, delegate, params) { |
54 /** @private {!CWSWidgetContainer.PlatformDelegate} */ | 57 /** @private {!CWSWidgetContainer.PlatformDelegate} */ |
55 this.delegate_ = delegate; | 58 this.delegate_ = delegate; |
56 | 59 |
57 /** @private {!CWSWidgetContainer.MetricsRecorder} */ | 60 /** @private {!CWSWidgetContainer.MetricsRecorder} */ |
58 this.metricsRecorder_ = | 61 this.metricsRecorder_ = |
59 new CWSWidgetContainer.MetricsRecorder(delegate.metricsImpl); | 62 new CWSWidgetContainer.MetricsRecorder(delegate.metricsImpl); |
60 | 63 |
61 /** | 64 /** |
62 * The document that will contain the container. | 65 * The document that will contain the container. |
63 * @const {!HTMLDocument} | 66 * @const {!HTMLDocument} |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
101 buttons.classList.add('cws-widget-buttons'); | 104 buttons.classList.add('cws-widget-buttons'); |
102 parentNode.appendChild(buttons); | 105 parentNode.appendChild(buttons); |
103 | 106 |
104 /** | 107 /** |
105 * Button that opens the Webstore URL. | 108 * Button that opens the Webstore URL. |
106 * @const {!Element} | 109 * @const {!Element} |
107 * @private | 110 * @private |
108 */ | 111 */ |
109 this.webstoreButton_ = document.createElement('div'); | 112 this.webstoreButton_ = document.createElement('div'); |
110 this.webstoreButton_.hidden = true; | 113 this.webstoreButton_.hidden = true; |
111 this.webstoreButton_.classList.add('cws-widget-webstore-button'); | |
112 this.webstoreButton_.setAttribute('role', 'button'); | 114 this.webstoreButton_.setAttribute('role', 'button'); |
113 this.webstoreButton_.tabIndex = 0; | 115 this.webstoreButton_.tabIndex = 0; |
114 | 116 |
115 /** | 117 /** |
116 * Icon for the Webstore button. | 118 * Icon for the Webstore button. |
117 * @type {!Element} | 119 * @type {!Element} |
118 */ | 120 */ |
119 var webstoreButtonIcon = this.document_.createElement('span'); | 121 var webstoreButtonIcon = this.document_.createElement('span'); |
120 webstoreButtonIcon.classList.add('cws-widget-webstore-button-icon'); | 122 webstoreButtonIcon.classList.add('cws-widget-webstore-button-icon'); |
121 this.webstoreButton_.appendChild(webstoreButtonIcon); | 123 this.webstoreButton_.appendChild(webstoreButtonIcon); |
(...skipping 19 matching lines...) Expand all Loading... |
141 * @type {?WebView} | 143 * @type {?WebView} |
142 * @private | 144 * @private |
143 */ | 145 */ |
144 this.webview_ = null; | 146 this.webview_ = null; |
145 | 147 |
146 /** | 148 /** |
147 * The Chrome Web Store widget URL. | 149 * The Chrome Web Store widget URL. |
148 * @const {string} | 150 * @const {string} |
149 * @private | 151 * @private |
150 */ | 152 */ |
151 this.widgetUrl_ = state.overrideCwsContainerUrlForTest || CWS_WIDGET_URL; | 153 this.widgetUrl_ = params.overrideCwsContainerUrlForTest || CWS_WIDGET_URL; |
152 | 154 |
153 /** | 155 /** |
154 * The Chrome Web Store widget origin. | 156 * The Chrome Web Store widget origin. |
155 * @const {string} | 157 * @const {string} |
156 * @private | 158 * @private |
157 */ | 159 */ |
158 this.widgetOrigin_ = state.overrideCwsContainerOriginForTest || | 160 this.widgetOrigin_ = params.overrideCwsContainerOriginForTest || |
159 CWS_WIDGET_ORIGIN; | 161 CWS_WIDGET_ORIGIN; |
160 | 162 |
161 /** | 163 /** |
162 * Map of options for the widget. | 164 * Map of options for the widget. |
163 * @type {?Object.<string, *>} | 165 * @type {?Object.<string, *>} |
164 * @private | 166 * @private |
165 */ | 167 */ |
166 this.options_ = null; | 168 this.options_ = null; |
167 | 169 |
168 /** | 170 /** |
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
382 }.bind(this)); | 384 }.bind(this)); |
383 }.bind(this)); | 385 }.bind(this)); |
384 }; | 386 }; |
385 | 387 |
386 /** | 388 /** |
387 * Initializes and starts loading the Chrome Web Store widget webview. | 389 * Initializes and starts loading the Chrome Web Store widget webview. |
388 * Must not be called before {@code this.ready()} is resolved. | 390 * Must not be called before {@code this.ready()} is resolved. |
389 * | 391 * |
390 * @param {!Object<string, *>} options Map of options for the dialog. | 392 * @param {!Object<string, *>} options Map of options for the dialog. |
391 * @param {?string} webStoreUrl Url for more results. Null if not supported. | 393 * @param {?string} webStoreUrl Url for more results. Null if not supported. |
392 * @return {Promise.<CWSWidgetContainer.ResolveReason>} Resolved when app | 394 * @return {!Promise.<CWSWidgetContainer.ResolveReason>} Resolved when app |
393 * installation is done, or the installation is cancelled. | 395 * installation is done, or the installation is cancelled. |
394 */ | 396 */ |
395 CWSWidgetContainer.prototype.start = function(options, webStoreUrl) { | 397 CWSWidgetContainer.prototype.start = function(options, webStoreUrl) { |
396 return new Promise(function(resolve, reject) { | 398 return new Promise(function(resolve, reject) { |
397 if (this.state_ !== CWSWidgetContainer.State.ACCESS_TOKEN_READY) { | 399 if (this.state_ !== CWSWidgetContainer.State.ACCESS_TOKEN_READY) { |
398 this.state_ = CWSWidgetContainer.State.INITIALIZE_FAILED_CLOSING; | 400 this.state_ = CWSWidgetContainer.State.INITIALIZE_FAILED_CLOSING; |
399 reject('Invalid state in |start|.'); | 401 reject('Invalid state in |start|.'); |
400 return; | 402 return; |
401 } | 403 } |
402 | 404 |
403 if (!this.accessToken_) { | 405 if (!this.accessToken_) { |
404 this.state_ = CWSWidgetContainer.State.INITIALIZE_FAILED_CLOSING; | 406 this.state_ = CWSWidgetContainer.State.INITIALIZE_FAILED_CLOSING; |
405 reject('No access token.'); | 407 reject('No access token.'); |
406 return; | 408 return; |
407 } | 409 } |
408 | 410 |
409 this.resolveStart_ = resolve; | 411 this.resolveStart_ = resolve; |
410 | 412 |
411 this.state_ = CWSWidgetContainer.State.INITIALIZING; | 413 this.state_ = CWSWidgetContainer.State.INITIALIZING; |
412 | 414 |
413 this.webStoreUrl_ = webStoreUrl; | 415 this.webStoreUrl_ = webStoreUrl; |
414 this.options_ = options; | 416 this.options_ = options; |
415 | 417 |
416 this.webstoreButton_.hidden = (webStoreUrl === null); | 418 this.webstoreButton_.hidden = !webStoreUrl; |
| 419 this.webstoreButton_.classList.toggle('cws-widget-webstore-button', |
| 420 !!webStoreUrl); |
417 | 421 |
418 this.webview_ = | 422 this.webview_ = |
419 /** @type {!WebView} */(this.document_.createElement('webview')); | 423 /** @type {!WebView} */(this.document_.createElement('webview')); |
420 this.webview_.id = 'cws-widget'; | 424 this.webview_.id = 'cws-widget'; |
421 this.webview_.partition = 'persist:cwswidgets'; | 425 this.webview_.partition = 'persist:cwswidgets'; |
422 this.webview_.style.width = WEBVIEW_WIDTH + 'px'; | 426 this.webview_.style.width = WEBVIEW_WIDTH + 'px'; |
423 this.webview_.style.height = WEBVIEW_HEIGHT + 'px'; | 427 this.webview_.style.height = WEBVIEW_HEIGHT + 'px'; |
424 this.webview_.request.onBeforeSendHeaders.addListener( | 428 this.webview_.request.onBeforeSendHeaders.addListener( |
425 this.authorizeRequest_.bind(this), | 429 this.authorizeRequest_.bind(this), |
426 /** @type {!RequestFilter}*/ ({urls: [this.widgetOrigin_ + '/*']}), | 430 /** @type {!RequestFilter}*/ ({urls: [this.widgetOrigin_ + '/*']}), |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
462 /** | 466 /** |
463 * Called when the 'See more...' button is activated. It opens | 467 * Called when the 'See more...' button is activated. It opens |
464 * {@code this.webstoreUrl_}. | 468 * {@code this.webstoreUrl_}. |
465 * @param {Event} e The event that activated the link. Either mouse click or | 469 * @param {Event} e The event that activated the link. Either mouse click or |
466 * key down event. | 470 * key down event. |
467 * @private | 471 * @private |
468 */ | 472 */ |
469 CWSWidgetContainer.prototype.onWebstoreLinkActivated_ = function(e) { | 473 CWSWidgetContainer.prototype.onWebstoreLinkActivated_ = function(e) { |
470 if (!this.webStoreUrl_) | 474 if (!this.webStoreUrl_) |
471 return; | 475 return; |
472 util.visitURL(this.webStoreUrl_); | 476 window.open(this.webStoreUrl_); |
473 this.state_ = CWSWidgetContainer.State.OPENING_WEBSTORE_CLOSING; | 477 this.state_ = CWSWidgetContainer.State.OPENING_WEBSTORE_CLOSING; |
474 this.reportDone_(); | 478 this.reportDone_(); |
475 }; | 479 }; |
476 | 480 |
477 /** | 481 /** |
478 * Key down event handler for webstore button element. If the key is enter, it | 482 * Key down event handler for webstore button element. If the key is enter, it |
479 * activates the button. | 483 * activates the button. |
480 * @param {Event} e The event | 484 * @param {Event} e The event |
481 * @private | 485 * @private |
482 */ | 486 */ |
(...skipping 446 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
929 this.metricsImpl_.recordUserAction('SuggestApps.ShowDialog'); | 933 this.metricsImpl_.recordUserAction('SuggestApps.ShowDialog'); |
930 }; | 934 }; |
931 | 935 |
932 CWSWidgetContainer.MetricsRecorder.prototype.startLoad = function() { | 936 CWSWidgetContainer.MetricsRecorder.prototype.startLoad = function() { |
933 this.metricsImpl_.startInterval('SuggestApps.LoadTime'); | 937 this.metricsImpl_.startInterval('SuggestApps.LoadTime'); |
934 }; | 938 }; |
935 | 939 |
936 CWSWidgetContainer.MetricsRecorder.prototype.finishLoad = function() { | 940 CWSWidgetContainer.MetricsRecorder.prototype.finishLoad = function() { |
937 this.metricsImpl_.recordInterval('SuggestApps.LoadTime'); | 941 this.metricsImpl_.recordInterval('SuggestApps.LoadTime'); |
938 }; | 942 }; |
OLD | NEW |