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

Side by Side Diff: chrome/browser/resources/file_manager/js/file_tasks.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) 2012 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 * This object encapsulates everything related to tasks execution.
9 *
10 * @param {FileManager} fileManager FileManager instance.
11 * @param {Object=} opt_params File manager load parameters.
12 * @constructor
13 */
14 function FileTasks(fileManager, opt_params) {
15 this.fileManager_ = fileManager;
16 this.params_ = opt_params;
17 this.tasks_ = null;
18 this.defaultTask_ = null;
19
20 /**
21 * List of invocations to be called once tasks are available.
22 *
23 * @private
24 * @type {Array.<Object>}
25 */
26 this.pendingInvocations_ = [];
27 }
28
29 /**
30 * Location of the FAQ about the file actions.
31 *
32 * @const
33 * @type {string}
34 */
35 FileTasks.NO_ACTION_FOR_FILE_URL = 'http://support.google.com/chromeos/bin/' +
36 'answer.py?answer=1700055&topic=29026&ctx=topic';
37
38 /**
39 * Location of the Chrome Web Store.
40 *
41 * @const
42 * @type {string}
43 */
44 FileTasks.CHROME_WEB_STORE_URL = 'https://chrome.google.com/webstore';
45
46 /**
47 * Base URL of apps list in the Chrome Web Store. This constant is used in
48 * FileTasks.createWebStoreLink().
49 *
50 * @const
51 * @type {string}
52 */
53 FileTasks.WEB_STORE_HANDLER_BASE_URL =
54 'https://chrome.google.com/webstore/category/collection/file_handlers';
55
56 /**
57 * Returns URL of the Chrome Web Store which show apps supporting the given
58 * file-extension and mime-type.
59 *
60 * @param {string} extension Extension of the file.
61 * @param {string} mimeType Mime type of the file.
62 * @return {string} URL
63 */
64 FileTasks.createWebStoreLink = function(extension, mimeType) {
65 if (!extension)
66 return FileTasks.CHROME_WEB_STORE_URL;
67
68 var url = FileTasks.WEB_STORE_HANDLER_BASE_URL;
69 url += '?_fe=' + extension.toLowerCase().replace(/[^\w]/g, '');
70
71 // If a mime is given, add it into the URL.
72 if (mimeType)
73 url += '&_fmt=' + mimeType.replace(/[^-\w\/]/g, '');
74 return url;
75 };
76
77 /**
78 * Complete the initialization.
79 *
80 * @param {Array.<string>} urls List of file urls.
81 * @param {Array.<string>=} opt_mimeTypes List of MIME types for each
82 * of the files.
83 */
84 FileTasks.prototype.init = function(urls, opt_mimeTypes) {
85 this.urls_ = urls;
86 if (urls.length > 0)
87 chrome.fileBrowserPrivate.getFileTasks(urls, opt_mimeTypes || [],
88 this.onTasks_.bind(this));
89 };
90
91 /**
92 * Returns amount of tasks.
93 *
94 * @return {number} amount of tasks.
95 */
96 FileTasks.prototype.size = function() {
97 return (this.tasks_ && this.tasks_.length) || 0;
98 };
99
100 /**
101 * Callback when tasks found.
102 *
103 * @param {Array.<Object>} tasks The tasks.
104 * @private
105 */
106 FileTasks.prototype.onTasks_ = function(tasks) {
107 this.processTasks_(tasks);
108 for (var index = 0; index < this.pendingInvocations_.length; index++) {
109 var name = this.pendingInvocations_[index][0];
110 var args = this.pendingInvocations_[index][1];
111 this[name].apply(this, args);
112 }
113 this.pendingInvocations_ = [];
114 };
115
116 /**
117 * The list of known extensions to record UMA.
118 * Note: Because the data is recorded by the index, so new item shouldn't be
119 * inserted.
120 *
121 * @const
122 * @type {Array.<string>}
123 * @private
124 */
125 FileTasks.knownExtensions_ = [
126 'other', '.3ga', '.3gp', '.aac', '.alac', '.asf', '.avi', '.bmp', '.csv',
127 '.doc', '.docx', '.flac', '.gif', '.jpeg', '.jpg', '.log', '.m3u', '.m3u8',
128 '.m4a', '.m4v', '.mid', '.mkv', '.mov', '.mp3', '.mp4', '.mpg', '.odf',
129 '.odp', '.ods', '.odt', '.oga', '.ogg', '.ogv', '.pdf', '.png', '.ppt',
130 '.pptx', '.ra', '.ram', '.rar', '.rm', '.rtf', '.wav', '.webm', '.webp',
131 '.wma', '.wmv', '.xls', '.xlsx',
132 ];
133
134 /**
135 * Records trial of opening file grouped by extensions.
136 *
137 * @param {Array.<string>} urls The path to be opened.
138 * @private
139 */
140 FileTasks.recordViewingFileTypeUMA_ = function(urls) {
141 for (var i = 0; i < urls.length; i++) {
142 var url = urls[i];
143 var extension = FileType.getExtension(url).toLowerCase();
144 if (FileTasks.knownExtensions_.indexOf(extension) < 0) {
145 extension = 'other';
146 }
147 metrics.recordEnum(
148 'ViewingFileType', extension, FileTasks.knownExtensions_);
149 }
150 };
151
152 /**
153 * Returns true if the taskId is for an internal task.
154 *
155 * @param {string} taskId Task identifier.
156 * @return {boolean} True if the task ID is for an internal task.
157 * @private
158 */
159 FileTasks.isInternalTask_ = function(taskId) {
160 var taskParts = taskId.split('|');
161 var appId = taskParts[0];
162 var taskType = taskParts[1];
163 var actionId = taskParts[2];
164 // The action IDs here should match ones used in executeInternalTask_().
165 return (appId == chrome.runtime.id &&
166 taskType == 'file' &&
167 (actionId == 'play' ||
168 actionId == 'watch' ||
169 actionId == 'mount-archive' ||
170 actionId == 'format-device' ||
171 actionId == 'gallery'));
172 };
173
174 /**
175 * Processes internal tasks.
176 *
177 * @param {Array.<Object>} tasks The tasks.
178 * @private
179 */
180 FileTasks.prototype.processTasks_ = function(tasks) {
181 this.tasks_ = [];
182 var id = chrome.runtime.id;
183 var isOnDrive = false;
184 for (var index = 0; index < this.urls_.length; ++index) {
185 if (FileType.isOnDrive(this.urls_[index])) {
186 isOnDrive = true;
187 break;
188 }
189 }
190
191 for (var i = 0; i < tasks.length; i++) {
192 var task = tasks[i];
193 var taskParts = task.taskId.split('|');
194
195 // Skip internal Files.app's handlers.
196 if (taskParts[0] == id && (taskParts[2] == 'auto-open' ||
197 taskParts[2] == 'select' || taskParts[2] == 'open')) {
198 continue;
199 }
200
201 // Tweak images, titles of internal tasks.
202 if (taskParts[0] == id && taskParts[1] == 'file') {
203 if (taskParts[2] == 'play') {
204 // TODO(serya): This hack needed until task.iconUrl is working
205 // (see GetFileTasksFileBrowserFunction::RunImpl).
206 task.iconType = 'audio';
207 task.title = loadTimeData.getString('ACTION_LISTEN');
208 } else if (taskParts[2] == 'mount-archive') {
209 task.iconType = 'archive';
210 task.title = loadTimeData.getString('MOUNT_ARCHIVE');
211 } else if (taskParts[2] == 'gallery') {
212 task.iconType = 'image';
213 task.title = loadTimeData.getString('ACTION_OPEN');
214 } else if (taskParts[2] == 'watch') {
215 task.iconType = 'video';
216 task.title = loadTimeData.getString('ACTION_WATCH');
217 } else if (taskParts[2] == 'open-hosted-generic') {
218 if (this.urls_.length > 1)
219 task.iconType = 'generic';
220 else // Use specific icon.
221 task.iconType = FileType.getIcon(this.urls_[0]);
222 task.title = loadTimeData.getString('ACTION_OPEN');
223 } else if (taskParts[2] == 'open-hosted-gdoc') {
224 task.iconType = 'gdoc';
225 task.title = loadTimeData.getString('ACTION_OPEN_GDOC');
226 } else if (taskParts[2] == 'open-hosted-gsheet') {
227 task.iconType = 'gsheet';
228 task.title = loadTimeData.getString('ACTION_OPEN_GSHEET');
229 } else if (taskParts[2] == 'open-hosted-gslides') {
230 task.iconType = 'gslides';
231 task.title = loadTimeData.getString('ACTION_OPEN_GSLIDES');
232 } else if (taskParts[2] == 'view-swf') {
233 // Do not render this task if disabled.
234 if (!loadTimeData.getBoolean('SWF_VIEW_ENABLED'))
235 continue;
236 task.iconType = 'generic';
237 task.title = loadTimeData.getString('ACTION_VIEW');
238 } else if (taskParts[2] == 'view-pdf') {
239 // Do not render this task if disabled.
240 if (!loadTimeData.getBoolean('PDF_VIEW_ENABLED'))
241 continue;
242 task.iconType = 'pdf';
243 task.title = loadTimeData.getString('ACTION_VIEW');
244 } else if (taskParts[2] == 'view-in-browser') {
245 task.iconType = 'generic';
246 task.title = loadTimeData.getString('ACTION_VIEW');
247 }
248 }
249
250 if (!task.iconType && taskParts[1] == 'web-intent') {
251 task.iconType = 'generic';
252 }
253
254 this.tasks_.push(task);
255 if (this.defaultTask_ == null && task.isDefault) {
256 this.defaultTask_ = task;
257 }
258 }
259 if (!this.defaultTask_ && this.tasks_.length > 0) {
260 // If we haven't picked a default task yet, then just pick the first one.
261 // This is not the preferred way we want to pick this, but better this than
262 // no default at all if the C++ code didn't set one.
263 this.defaultTask_ = this.tasks_[0];
264 }
265 };
266
267 /**
268 * Executes default task.
269 *
270 * @param {function(boolean, Array.<string>)=} opt_callback Called when the
271 * default task is executed, or the error is occurred.
272 * @private
273 */
274 FileTasks.prototype.executeDefault_ = function(opt_callback) {
275 var urls = this.urls_;
276 FileTasks.recordViewingFileTypeUMA_(urls);
277 this.executeDefaultInternal_(urls, opt_callback);
278 };
279
280 /**
281 * Executes default task.
282 *
283 * @param {Array.<string>} urls Urls to execute.
284 * @param {function(boolean, Array.<string>)=} opt_callback Called when the
285 * default task is executed, or the error is occurred.
286 * @private
287 */
288 FileTasks.prototype.executeDefaultInternal_ = function(urls, opt_callback) {
289 var callback = opt_callback || function(arg1, arg2) {};
290
291 if (this.defaultTask_ != null) {
292 this.executeInternal_(this.defaultTask_.taskId, urls);
293 callback(true, urls);
294 return;
295 }
296
297 // We don't have tasks, so try to show a file in a browser tab.
298 // We only do that for single selection to avoid confusion.
299 if (urls.length != 1)
300 return;
301
302 var onViewFiles = function(success) {
303 callback(success, urls);
304 }.bind(this);
305
306 this.checkAvailability_(function() {
307 util.viewFilesInBrowser(urls, onViewFiles);
308 }.bind(this));
309 };
310
311 /**
312 * Executes a single task.
313 *
314 * @param {string} taskId Task identifier.
315 * @param {Array.<string>=} opt_urls Urls to execute on instead of |this.urls_|.
316 * @private
317 */
318 FileTasks.prototype.execute_ = function(taskId, opt_urls) {
319 var urls = opt_urls || this.urls_;
320 FileTasks.recordViewingFileTypeUMA_(urls);
321 this.executeInternal_(taskId, urls);
322 };
323
324 /**
325 * The core implementation to execute a single task.
326 *
327 * @param {string} taskId Task identifier.
328 * @param {Array.<string>} urls Urls to execute.
329 * @private
330 */
331 FileTasks.prototype.executeInternal_ = function(taskId, urls) {
332 this.checkAvailability_(function() {
333 if (FileTasks.isInternalTask_(taskId)) {
334 var taskParts = taskId.split('|');
335 this.executeInternalTask_(taskParts[2], urls);
336 } else {
337 chrome.fileBrowserPrivate.executeTask(taskId, urls);
338 }
339 }.bind(this));
340 };
341
342 /**
343 * Checks whether the remote files are available right now.
344 *
345 * @param {function} callback The callback.
346 * @private
347 */
348 FileTasks.prototype.checkAvailability_ = function(callback) {
349 var areAll = function(props, name) {
350 var isOne = function(e) {
351 // If got no properties, we safely assume that item is unavailable.
352 return e && e[name];
353 };
354 return props.filter(isOne).length == props.length;
355 };
356
357 var fm = this.fileManager_;
358 var urls = this.urls_;
359
360 if (fm.isOnDrive() && fm.isDriveOffline()) {
361 fm.metadataCache_.get(urls, 'drive', function(props) {
362 if (areAll(props, 'availableOffline')) {
363 callback();
364 return;
365 }
366
367 fm.alert.showHtml(
368 loadTimeData.getString('OFFLINE_HEADER'),
369 props[0].hosted ?
370 loadTimeData.getStringF(
371 urls.length == 1 ?
372 'HOSTED_OFFLINE_MESSAGE' :
373 'HOSTED_OFFLINE_MESSAGE_PLURAL') :
374 loadTimeData.getStringF(
375 urls.length == 1 ?
376 'OFFLINE_MESSAGE' :
377 'OFFLINE_MESSAGE_PLURAL',
378 loadTimeData.getString('OFFLINE_COLUMN_LABEL')));
379 });
380 return;
381 }
382
383 if (fm.isOnDrive() && fm.isDriveOnMeteredConnection()) {
384 fm.metadataCache_.get(urls, 'drive', function(driveProps) {
385 if (areAll(driveProps, 'availableWhenMetered')) {
386 callback();
387 return;
388 }
389
390 fm.metadataCache_.get(urls, 'filesystem', function(fileProps) {
391 var sizeToDownload = 0;
392 for (var i = 0; i != urls.length; i++) {
393 if (!driveProps[i].availableWhenMetered)
394 sizeToDownload += fileProps[i].size;
395 }
396 fm.confirm.show(
397 loadTimeData.getStringF(
398 urls.length == 1 ?
399 'CONFIRM_MOBILE_DATA_USE' :
400 'CONFIRM_MOBILE_DATA_USE_PLURAL',
401 util.bytesToString(sizeToDownload)),
402 callback);
403 });
404 });
405 return;
406 }
407
408 callback();
409 };
410
411 /**
412 * Executes an internal task.
413 *
414 * @param {string} id The short task id.
415 * @param {Array.<string>} urls The urls to execute on.
416 * @private
417 */
418 FileTasks.prototype.executeInternalTask_ = function(id, urls) {
419 var fm = this.fileManager_;
420
421 if (id == 'play') {
422 var position = 0;
423 if (urls.length == 1) {
424 // If just a single audio file is selected pass along every audio file
425 // in the directory.
426 var selectedUrl = urls[0];
427 urls = fm.getAllUrlsInCurrentDirectory().filter(FileType.isAudio);
428 position = urls.indexOf(selectedUrl);
429 }
430 fm.backgroundPage.launchAudioPlayer({ items: urls, position: position });
431 return;
432 }
433
434 if (id == 'watch') {
435 console.assert(urls.length == 1, 'Cannot open multiple videos');
436 fm.backgroundPage.launchVideoPlayer(urls[0]);
437 return;
438 }
439
440 if (id == 'mount-archive') {
441 this.mountArchivesInternal_(urls);
442 return;
443 }
444
445 if (id == 'format-device') {
446 fm.confirm.show(loadTimeData.getString('FORMATTING_WARNING'), function() {
447 chrome.fileBrowserPrivate.formatDevice(urls[0]);
448 });
449 return;
450 }
451
452 if (id == 'gallery') {
453 this.openGalleryInternal_(urls);
454 return;
455 }
456
457 console.error('Unexpected action ID: ' + id);
458 };
459
460 /**
461 * Mounts archives.
462 *
463 * @param {Array.<string>} urls Mount file urls list.
464 */
465 FileTasks.prototype.mountArchives = function(urls) {
466 FileTasks.recordViewingFileTypeUMA_(urls);
467 this.mountArchivesInternal_(urls);
468 };
469
470 /**
471 * The core implementation of mounts archives.
472 *
473 * @param {Array.<string>} urls Mount file urls list.
474 * @private
475 */
476 FileTasks.prototype.mountArchivesInternal_ = function(urls) {
477 var fm = this.fileManager_;
478
479 var tracker = fm.directoryModel_.createDirectoryChangeTracker();
480 tracker.start();
481
482 fm.resolveSelectResults_(urls, function(urls) {
483 for (var index = 0; index < urls.length; ++index) {
484 fm.volumeManager_.mountArchive(urls[index], function(mountPath) {
485 tracker.stop();
486 if (!tracker.hasChanged)
487 fm.directoryModel_.changeDirectory(mountPath);
488 }, function(url, error) {
489 var path = util.extractFilePath(url);
490 tracker.stop();
491 var namePos = path.lastIndexOf('/');
492 fm.alert.show(strf('ARCHIVE_MOUNT_FAILED',
493 path.substr(namePos + 1), error));
494 }.bind(null, urls[index]));
495 }
496 });
497 };
498
499 /**
500 * Open the Gallery.
501 *
502 * @param {Array.<string>} urls List of selected urls.
503 */
504 FileTasks.prototype.openGallery = function(urls) {
505 FileTasks.recordViewingFileTypeUMA_(urls);
506 this.openGalleryInternal_(urls);
507 };
508
509 /**
510 * The core implementation to open the Gallery.
511 *
512 * @param {Array.<string>} urls List of selected urls.
513 * @private
514 */
515 FileTasks.prototype.openGalleryInternal_ = function(urls) {
516 var fm = this.fileManager_;
517
518 var allUrls =
519 fm.getAllUrlsInCurrentDirectory().filter(FileType.isImageOrVideo);
520
521 var galleryFrame = fm.document_.createElement('iframe');
522 galleryFrame.className = 'overlay-pane';
523 galleryFrame.scrolling = 'no';
524 galleryFrame.setAttribute('webkitallowfullscreen', true);
525
526 if (this.params_ && this.params_.gallery) {
527 // Remove the Gallery state from the location, we do not need it any more.
528 util.updateAppState(null /* keep path */, '' /* remove search. */);
529 }
530
531 var savedAppState = window.appState;
532 var savedTitle = document.title;
533
534 // Push a temporary state which will be replaced every time the selection
535 // changes in the Gallery and popped when the Gallery is closed.
536 util.updateAppState();
537
538 var onBack = function(selectedUrls) {
539 fm.directoryModel_.selectUrls(selectedUrls);
540 fm.closeFilePopup_(); // Will call Gallery.unload.
541 window.appState = savedAppState;
542 util.saveAppState();
543 document.title = savedTitle;
544 };
545
546 var onClose = function() {
547 fm.onClose();
548 };
549
550 var onMaximize = function() {
551 fm.onMaximize();
552 };
553
554 galleryFrame.onload = function() {
555 galleryFrame.contentWindow.ImageUtil.metrics = metrics;
556
557 // TODO(haruki): isOnReadonlyDirectory() only checks the permission for the
558 // root. We should check more granular permission to know whether the file
559 // is writable or not.
560 var readonly = fm.isOnReadonlyDirectory();
561 var currentDir = fm.getCurrentDirectoryEntry();
562 var downloadsVolume =
563 fm.volumeManager_.getVolumeInfo(RootDirectory.DOWNLOADS);
564 var downloadsDir = downloadsVolume && downloadsVolume.root;
565 var readonlyDirName = null;
566 if (readonly && currentDir) {
567 var rootPath = PathUtil.getRootPath(currentDir.fullPath);
568 readonlyDirName = fm.isOnDrive() ?
569 PathUtil.getRootLabel(rootPath) :
570 PathUtil.basename(rootPath);
571 }
572
573 var context = {
574 // We show the root label in readonly warning (e.g. archive name).
575 readonlyDirName: readonlyDirName,
576 curDirEntry: currentDir,
577 saveDirEntry: readonly ? downloadsDir : null,
578 searchResults: fm.directoryModel_.isSearching(),
579 metadataCache: fm.metadataCache_,
580 pageState: this.params_,
581 appWindow: chrome.app.window.current(),
582 onBack: onBack,
583 onClose: onClose,
584 onMaximize: onMaximize,
585 displayStringFunction: strf
586 };
587 galleryFrame.contentWindow.Gallery.open(
588 context, fm.volumeManager_, allUrls, urls);
589 }.bind(this);
590
591 galleryFrame.src = 'gallery.html';
592 fm.openFilePopup_(galleryFrame, fm.updateTitle_.bind(fm));
593 };
594
595 /**
596 * Displays the list of tasks in a task picker combobutton.
597 *
598 * @param {cr.ui.ComboButton} combobutton The task picker element.
599 * @private
600 */
601 FileTasks.prototype.display_ = function(combobutton) {
602 if (this.tasks_.length == 0) {
603 combobutton.hidden = true;
604 return;
605 }
606
607 combobutton.clear();
608 combobutton.hidden = false;
609 combobutton.defaultItem = this.createCombobuttonItem_(this.defaultTask_);
610
611 var items = this.createItems_();
612
613 if (items.length > 1) {
614 var defaultIdx = 0;
615
616 for (var j = 0; j < items.length; j++) {
617 combobutton.addDropDownItem(items[j]);
618 if (items[j].task.taskId == this.defaultTask_.taskId)
619 defaultIdx = j;
620 }
621
622 combobutton.addSeparator();
623 var changeDefaultMenuItem = combobutton.addDropDownItem({
624 label: loadTimeData.getString('CHANGE_DEFAULT_MENU_ITEM')
625 });
626 changeDefaultMenuItem.classList.add('change-default');
627 }
628 };
629
630 /**
631 * Creates sorted array of available task descriptions such as title and icon.
632 *
633 * @return {Array} created array can be used to feed combobox, menus and so on.
634 * @private
635 */
636 FileTasks.prototype.createItems_ = function() {
637 var items = [];
638 var title = this.defaultTask_.title + ' ' +
639 loadTimeData.getString('DEFAULT_ACTION_LABEL');
640 items.push(this.createCombobuttonItem_(this.defaultTask_, title, true));
641
642 for (var index = 0; index < this.tasks_.length; index++) {
643 var task = this.tasks_[index];
644 if (task != this.defaultTask_)
645 items.push(this.createCombobuttonItem_(task));
646 }
647
648 items.sort(function(a, b) {
649 return a.label.localeCompare(b.label);
650 });
651
652 return items;
653 };
654
655 /**
656 * Updates context menu with default item.
657 * @private
658 */
659
660 FileTasks.prototype.updateMenuItem_ = function() {
661 this.fileManager_.updateContextMenuActionItems(this.defaultTask_,
662 this.tasks_.length > 1);
663 };
664
665 /**
666 * Creates combobutton item based on task.
667 *
668 * @param {Object} task Task to convert.
669 * @param {string=} opt_title Title.
670 * @param {boolean=} opt_bold Make a menu item bold.
671 * @return {Object} Item appendable to combobutton drop-down list.
672 * @private
673 */
674 FileTasks.prototype.createCombobuttonItem_ = function(task, opt_title,
675 opt_bold) {
676 return {
677 label: opt_title || task.title,
678 iconUrl: task.iconUrl,
679 iconType: task.iconType,
680 task: task,
681 bold: opt_bold || false
682 };
683 };
684
685
686 /**
687 * Decorates a FileTasks method, so it will be actually executed after the tasks
688 * are available.
689 * This decorator expects an implementation called |method + '_'|.
690 *
691 * @param {string} method The method name.
692 */
693 FileTasks.decorate = function(method) {
694 var privateMethod = method + '_';
695 FileTasks.prototype[method] = function() {
696 if (this.tasks_) {
697 this[privateMethod].apply(this, arguments);
698 } else {
699 this.pendingInvocations_.push([privateMethod, arguments]);
700 }
701 return this;
702 };
703 };
704
705 /**
706 * Shows modal action picker dialog with currently available list of tasks.
707 *
708 * @param {DefaultActionDialog} actionDialog Action dialog to show and update.
709 * @param {string} title Title to use.
710 * @param {string} message Message to use.
711 * @param {function(Object)} onSuccess Callback to pass selected task.
712 */
713 FileTasks.prototype.showTaskPicker = function(actionDialog, title, message,
714 onSuccess) {
715 var items = this.createItems_();
716
717 var defaultIdx = 0;
718 for (var j = 0; j < items.length; j++) {
719 if (items[j].task.taskId == this.defaultTask_.taskId)
720 defaultIdx = j;
721 }
722
723 actionDialog.show(
724 title,
725 message,
726 items, defaultIdx,
727 function(item) {
728 onSuccess(item.task);
729 });
730 };
731
732 FileTasks.decorate('display');
733 FileTasks.decorate('updateMenuItem');
734 FileTasks.decorate('execute');
735 FileTasks.decorate('executeDefault');
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698