Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(52)

Side by Side Diff: chrome/browser/resources/file_manager/js/suggest_apps_dialog.js

Issue 39123003: [Files.app] Split the JavaScript files into subdirectories: common, background, and foreground (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fixed test failure. Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2013 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 /**
8 * SuggestAppsDialog contains a list box to select an app to be opened the file
9 * with. This dialog should be used as action picker for file operations.
10 */
11
12 /**
13 * The width of the widget (in pixel).
14 * @type {number}
15 * @const
16 */
17 var WEBVIEW_WIDTH = 735;
18 /**
19 * The height of the widget (in pixel).
20 * @type {number}
21 * @const
22 */
23 var WEBVIEW_HEIGHT = 480;
24
25 /**
26 * The URL of the widget.
27 * @type {string}
28 * @const
29 */
30 var CWS_WIDGET_URL =
31 'https://clients5.google.com/webstore/wall/cros-widget-container';
32 /**
33 * The origin of the widget.
34 * @type {string}
35 * @const
36 */
37 var CWS_WIDGET_ORIGIN = 'https://clients5.google.com';
38
39 /**
40 * Creates dialog in DOM tree.
41 *
42 * @param {HTMLElement} parentNode Node to be parent for this dialog.
43 * @param {Object} state Static state of suggest app dialog.
44 * @constructor
45 * @extends {FileManagerDialogBase}
46 */
47 function SuggestAppsDialog(parentNode, state) {
48 FileManagerDialogBase.call(this, parentNode);
49
50 this.frame_.id = 'suggest-app-dialog';
51
52 this.spinner_ = this.document_.createElement('div');
53 this.spinner_.className = 'spinner';
54
55 this.spinnerWrapper_ = this.document_.createElement('div');
56 this.spinnerWrapper_.className = 'spinner-container';
57 this.spinnerWrapper_.style.width = WEBVIEW_WIDTH + 'px';
58 this.spinnerWrapper_.style.height = WEBVIEW_HEIGHT + 'px';
59 this.spinnerWrapper_.appendChild(this.spinner_);
60 this.frame_.insertBefore(this.spinnerWrapper_, this.text_.nextSibling);
61
62 this.webviewContainer_ = this.document_.createElement('div');
63 this.webviewContainer_.id = 'webview-container';
64 this.webviewContainer_.style.width = WEBVIEW_WIDTH + 'px';
65 this.webviewContainer_.style.height = WEBVIEW_HEIGHT + 'px';
66 this.frame_.insertBefore(this.webviewContainer_, this.text_.nextSibling);
67
68 this.buttons_ = this.document_.createElement('div');
69 this.buttons_.id = 'buttons';
70 this.frame_.appendChild(this.buttons_);
71
72 this.webstoreButton_ = this.document_.createElement('div');
73 this.webstoreButton_.id = 'webstore-button';
74 this.webstoreButton_.innerHTML = str('SUGGEST_DIALOG_LINK_TO_WEBSTORE');
75 this.webstoreButton_.addEventListener(
76 'click', this.onWebstoreLinkClicked_.bind(this));
77 this.buttons_.appendChild(this.webstoreButton_);
78
79 this.initialFocusElement_ = this.webviewContainer_;
80
81 this.webview_ = null;
82 this.accessToken_ = null;
83 this.widgetUrl_ =
84 state.overrideCwsContainerUrlForTest || CWS_WIDGET_URL;
85 this.widgetOrigin_ =
86 state.overrideCwsContainerOriginForTest || CWS_WIDGET_ORIGIN;
87
88 this.extension_ = null;
89 this.mime_ = null;
90 this.installingItemId_ = null;
91 this.state_ = SuggestAppsDialog.State.UNINITIALIZED;
92
93 this.initializationTask_ = new AsyncUtil.Group();
94 this.initializationTask_.add(this.retrieveAuthorizeToken_.bind(this));
95 this.initializationTask_.run();
96 }
97
98 SuggestAppsDialog.prototype = {
99 __proto__: FileManagerDialogBase.prototype
100 };
101
102 /**
103 * @enum {string}
104 * @const
105 */
106 SuggestAppsDialog.State = {
107 UNINITIALIZED: 'SuggestAppsDialog.State.UNINITIALIZED',
108 INITIALIZING: 'SuggestAppsDialog.State.INITIALIZING',
109 INITIALIZE_FAILED_CLOSING:
110 'SuggestAppsDialog.State.INITIALIZE_FAILED_CLOSING',
111 INITIALIZED: 'SuggestAppsDialog.State.INITIALIZED',
112 INSTALLING: 'SuggestAppsDialog.State.INSTALLING',
113 INSTALLED_CLOSING: 'SuggestAppsDialog.State.INSTALLED_CLOSING',
114 CANCELED_CLOSING: 'SuggestAppsDialog.State.CANCELED_CLOSING'
115 };
116 Object.freeze(SuggestAppsDialog.State);
117
118 /**
119 * @enum {string}
120 * @const
121 */
122 SuggestAppsDialog.Result = {
123 // Install is done. The install app should be opened.
124 INSTALL_SUCCESSFUL: 'SuggestAppsDialog.Result.INSTALL_SUCCESSFUL',
125 // User cancelled the suggest app dialog. No message should be shown.
126 USER_CANCELL: 'SuggestAppsDialog.Result.USER_CANCELL',
127 // Failed to load the widget. Error message should be shown.
128 FAILED: 'SuggestAppsDialog.Result.FAILED'
129 };
130 Object.freeze(SuggestAppsDialog.Result);
131
132 /**
133 * @override
134 */
135 SuggestAppsDialog.prototype.onInputFocus = function() {
136 this.webviewContainer_.select();
137 };
138
139 /**
140 * Injects headers into the passed request.
141 *
142 * @param {Event} e Request event.
143 * @return {{requestHeaders: HttpHeaders}} Modified headers.
144 * @private
145 */
146 SuggestAppsDialog.prototype.authorizeRequest_ = function(e) {
147 e.requestHeaders.push({
148 name: 'Authorization',
149 value: 'Bearer ' + this.accessToken_
150 });
151 return {requestHeaders: e.requestHeaders};
152 };
153
154 /**
155 * Retrieves the authorize token. This method should be called in
156 * initialization of the dialog.
157 *
158 * @param {function()} callback Called when the token is retrieved.
159 * @private
160 */
161 SuggestAppsDialog.prototype.retrieveAuthorizeToken_ = function(callback) {
162 if (window.IN_TEST) {
163 // In test, use a dummy string as token. This must be a non-empty string.
164 this.accessToken_ = 'DUMMY_ACCESS_TOKEN_FOR_TEST';
165 }
166
167 if (this.accessToken_) {
168 callback();
169 return;
170 }
171
172 // Fetch or update the access token.
173 chrome.fileBrowserPrivate.requestWebStoreAccessToken(
174 function(accessToken) {
175 // In case of error, this.accessToken_ will be set to null.
176 this.accessToken_ = accessToken;
177 callback();
178 }.bind(this));
179 };
180
181 /**
182 * Shows dialog.
183 *
184 * @param {string} extension Extension of the file.
185 * @param {string} mime Mime of the file.
186 * @param {function(boolean)} onDialogClosed Called when the dialog is closed.
187 * The argument is the result of installation: true if an app is installed,
188 * false otherwise.
189 */
190 SuggestAppsDialog.prototype.show = function(extension, mime, onDialogClosed) {
191 if (this.state_ != SuggestAppsDialog.State.UNINITIALIZED) {
192 console.error('Invalid state.');
193 return;
194 }
195
196 this.extension_ = extension;
197 this.mimeType_ = mime;
198 this.onDialogClosed_ = onDialogClosed;
199 this.state_ = SuggestAppsDialog.State.INITIALIZING;
200
201 // Makes it sure that the initialization is completed.
202 this.initializationTask_.run(function() {
203 if (!this.accessToken_) {
204 this.state_ = SuggestAppsDialog.State.INITIALIZE_FAILED_CLOSING;
205 this.onHide_();
206 return;
207 }
208
209 var title = str('SUGGEST_DIALOG_TITLE');
210
211 var show =
212 FileManagerDialogBase.prototype.showTitleOnlyDialog.call(this, title);
213 if (!show) {
214 console.error('SuggestAppsDialog can\'t be shown');
215 this.state_ = SuggestAppsDialog.State.UNINITIALIZED;
216 this.onHide();
217 return;
218 }
219
220 this.webviewContainer_.innerHTML =
221 '<webview id="cws-widget" partition="persist:cwswidgets"></webview>';
222
223 this.webview_ = this.container_.querySelector('#cws-widget');
224 this.webview_.style.width = WEBVIEW_WIDTH + 'px';
225 this.webview_.style.height = WEBVIEW_HEIGHT + 'px';
226 this.webview_.request.onBeforeSendHeaders.addListener(
227 this.authorizeRequest_.bind(this),
228 {urls: [this.widgetOrigin_ + '/*']},
229 ['blocking', 'requestHeaders']);
230 this.webview_.addEventListener('newwindow', function(event) {
231 // Discard the window object and reopen in an external window.
232 event.window.discard();
233 util.visitURL(event.targetUrl);
234 event.preventDefault();
235 });
236
237 this.frame_.classList.add('show-spinner');
238
239 this.webviewClient_ = new CWSContainerClient(
240 this.webview_,
241 extension, mime,
242 WEBVIEW_WIDTH, WEBVIEW_HEIGHT,
243 this.widgetUrl_, this.widgetOrigin_);
244 this.webviewClient_.addEventListener(CWSContainerClient.Events.LOADED,
245 this.onWidgetLoaded_.bind(this));
246 this.webviewClient_.addEventListener(CWSContainerClient.Events.LOAD_FAILED,
247 this.onWidgetLoadFailed_.bind(this));
248 this.webviewClient_.addEventListener(
249 CWSContainerClient.Events.REQUEST_INSTALL,
250 this.onInstallRequest_.bind(this));
251 this.webviewClient_.load();
252 }.bind(this));
253 };
254
255 /**
256 * Called when the 'See more...' link is clicked to be navigated to Webstore.
257 * @param {Event} e Event.
258 * @private
259 */
260 SuggestAppsDialog.prototype.onWebstoreLinkClicked_ = function(e) {
261 var webStoreUrl =
262 FileTasks.createWebStoreLink(this.extension_, this.mimeType_);
263 chrome.windows.create({url: webStoreUrl});
264 this.hide();
265 };
266
267 /**
268 * Called when the widget is loaded successfully.
269 * @param {Event} event Event.
270 * @private
271 */
272 SuggestAppsDialog.prototype.onWidgetLoaded_ = function(event) {
273 this.frame_.classList.remove('show-spinner');
274 this.state_ = SuggestAppsDialog.State.INITIALIZED;
275
276 this.webview_.focus();
277 };
278
279 /**
280 * Called when the widget is failed to load.
281 * @param {Event} event Event.
282 * @private
283 */
284 SuggestAppsDialog.prototype.onWidgetLoadFailed_ = function(event) {
285 this.frame_.classList.remove('show-spinner');
286 this.state_ = SuggestAppsDialog.State.INITIALIZE_FAILED_CLOSING;
287
288 this.hide();
289 };
290
291 /**
292 * Called when the connection status is changed.
293 * @param {util.DriveConnectionType} connectionType Current connection type.
294 */
295 SuggestAppsDialog.prototype.onDriveConnectionChanged =
296 function(connectionType) {
297 if (this.state_ !== SuggestAppsDialog.State.UNINITIALIZED &&
298 connectionType === util.DriveConnectionType.OFFLINE) {
299 this.state_ = SuggestAppsDialog.State.INITIALIZE_FAILED_CLOSING;
300 this.hide();
301 }
302 };
303
304 /**
305 * Called when receiving the install request from the webview client.
306 * @param {Event} e Event.
307 * @private
308 */
309 SuggestAppsDialog.prototype.onInstallRequest_ = function(e) {
310 var itemId = e.itemId;
311 this.installingItemId_ = itemId;
312
313 this.appInstaller_ = new AppInstaller(itemId);
314 this.appInstaller_.install(this.onInstallCompleted_.bind(this));
315
316 this.frame_.classList.add('show-spinner');
317 this.state_ = SuggestAppsDialog.State.INSTALLING;
318 };
319
320 /**
321 * Called when the installation is completed from the app installer.
322 * @param {AppInstaller.Result} result Result of the installation.
323 * @param {string} error Detail of the error.
324 * @private
325 */
326 SuggestAppsDialog.prototype.onInstallCompleted_ = function(result, error) {
327 var success = (result === AppInstaller.Result.SUCCESS);
328
329 this.frame_.classList.remove('show-spinner');
330 this.state_ = success ?
331 SuggestAppsDialog.State.INSTALLED_CLOSING :
332 SuggestAppsDialog.State.INITIALIZED; // Back to normal state.
333 this.webviewClient_.onInstallCompleted(success, this.installingItemId_);
334 this.installingItemId_ = null;
335
336 switch (result) {
337 case AppInstaller.Result.SUCCESS:
338 this.hide();
339 break;
340 case AppInstaller.Result.CANCELLED:
341 // User cancelled the installation. Do nothing.
342 break;
343 case AppInstaller.Result.ERROR:
344 fileManager.error.show(str('SUGGEST_DIALOG_INSTALLATION_FAILED'));
345 break;
346 }
347 };
348
349 /**
350 * @override
351 */
352 SuggestAppsDialog.prototype.hide = function(opt_originalOnHide) {
353 switch (this.state_) {
354 case SuggestAppsDialog.State.INSTALLING:
355 // Install is being aborted. Send the failure result.
356 // Cancels the install.
357 if (this.webviewClient_)
358 this.webviewClient_.onInstallCompleted(false, this.installingItemId_);
359 this.installingItemId_ = null;
360
361 // Assumes closing the dialog as canceling the install.
362 this.state_ = SuggestAppsDialog.State.CANCELED_CLOSING;
363 break;
364 case SuggestAppsDialog.State.INSTALLED_CLOSING:
365 case SuggestAppsDialog.State.INITIALIZE_FAILED_CLOSING:
366 // Do nothing.
367 break;
368 case SuggestAppsDialog.State.INITIALIZED:
369 this.state_ = SuggestAppsDialog.State.CANCELED_CLOSING;
370 break;
371 default:
372 this.state_ = SuggestAppsDialog.State.CANCELED_CLOSING;
373 console.error('Invalid state.');
374 }
375
376 if (this.webviewClient_) {
377 this.webviewClient_.dispose();
378 this.webviewClient_ = null;
379 }
380
381 this.webviewContainer_.innerHTML = '';
382 this.extension_ = null;
383 this.mime_ = null;
384
385 FileManagerDialogBase.prototype.hide.call(
386 this,
387 this.onHide_.bind(this, opt_originalOnHide));
388 };
389
390 /**
391 * @param {function()=} opt_originalOnHide Original onHide function passed to
392 * SuggestAppsDialog.hide().
393 * @private
394 */
395 SuggestAppsDialog.prototype.onHide_ = function(opt_originalOnHide) {
396 // Calls the callback after the dialog hides.
397 if (opt_originalOnHide)
398 opt_originalOnHide();
399
400 var result;
401 switch (this.state_) {
402 case SuggestAppsDialog.State.INSTALLED_CLOSING:
403 result = SuggestAppsDialog.Result.INSTALL_SUCCESSFUL;
404 break;
405 case SuggestAppsDialog.State.INITIALIZE_FAILED_CLOSING:
406 result = SuggestAppsDialog.Result.FAILED;
407 break;
408 case SuggestAppsDialog.State.CANCELED_CLOSING:
409 result = SuggestAppsDialog.Result.USER_CANCELL;
410 break;
411 default:
412 result = SuggestAppsDialog.Result.USER_CANCELL;
413 console.error('Invalid state.');
414 }
415 this.state_ = SuggestAppsDialog.State.UNINITIALIZED;
416
417 this.onDialogClosed_(result);
418 };
OLDNEW
« no previous file with comments | « chrome/browser/resources/file_manager/js/share_dialog.js ('k') | chrome/browser/resources/file_manager/js/test_util.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698