Updated drag and drop thumbnails.
[chromium-blink-merge.git] / chrome / browser / resources / file_manager / js / action_choice.js
blobc3cc446faf5c7d50c7a40151ef01c894ed1b86b3
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.
5 document.addEventListener('DOMContentLoaded', function() {
6 ActionChoice.load();
7 });
9 /**
10 * The main ActionChoice object.
11 * @param {HTMLElement} dom Container.
12 * @param {FileSystem} filesystem Local file system.
13 * @param {Object} params Parameters.
14 * @constructor
16 function ActionChoice(dom, filesystem, params) {
17 this.filesystem_ = filesystem;
18 this.dom_ = dom;
19 this.document_ = this.dom_.ownerDocument;
20 this.metadataCache_ = params.metadataCache;
21 this.volumeManager_ = new VolumeManager();
22 this.volumeManager_.addEventListener('externally-unmounted',
23 this.onDeviceUnmounted_.bind(this));
25 this.initDom_();
26 this.checkDrive_();
27 this.loadSource_(params.source);
30 ActionChoice.prototype = { __proto__: cr.EventTarget.prototype };
32 /**
33 * The number of previews shown.
35 ActionChoice.PREVIEW_COUNT = 3;
37 /**
38 * Loads app in the document body.
39 * @param {FileSystem=} opt_filesystem Local file system.
40 * @param {Object} opt_params Parameters.
42 ActionChoice.load = function(opt_filesystem, opt_params) {
43 ImageUtil.metrics = metrics;
45 var hash = location.hash ? decodeURI(location.hash.substr(1)) : '';
46 var params = opt_params || {};
47 if (!params.source) params.source = hash;
48 if (!params.metadataCache) params.metadataCache = MetadataCache.createFull();
50 function onFilesystem(filesystem) {
51 var dom = document.querySelector('.action-choice');
52 ActionChoice.instance = new ActionChoice(dom, filesystem, params);
55 chrome.fileBrowserPrivate.getStrings(function(strings) {
56 loadTimeData.data = strings;
58 i18nTemplate.process(document, loadTimeData);
60 if (opt_filesystem) {
61 onFilesystem(opt_filesystem);
62 } else {
63 chrome.fileBrowserPrivate.requestLocalFileSystem(onFilesystem);
65 });
68 /**
69 * One-time initialization of dom elements.
70 * @private
72 ActionChoice.prototype.initDom_ = function() {
73 this.previews_ = this.document_.querySelector('.previews');
74 this.counter_ = this.document_.querySelector('.counter');
76 this.document_.querySelector('button.ok').addEventListener('click',
77 this.onOk_.bind(this));
79 var choices = this.document_.querySelectorAll('.choices div');
80 for (var index = 0; index < choices.length; index++) {
81 choices[index].addEventListener('dblclick', this.onOk_.bind(this));
84 this.document_.addEventListener('keydown', this.onKeyDown_.bind(this));
86 metrics.startInterval('PhotoImport.Load');
87 this.dom_.setAttribute('loading', '');
89 this.document_.querySelectorAll('.choices input')[0].focus();
92 /**
93 * Checks whether Drive is reachable.
94 * @private
96 ActionChoice.prototype.checkDrive_ = function() {
97 var driveLabel = this.dom_.querySelector('label[for=import-photos-to-drive]');
98 var driveChoice = this.dom_.querySelector('#import-photos-to-drive');
99 var driveDiv = driveChoice.parentNode;
100 driveChoice.disabled = true;
101 driveDiv.setAttribute('disabled', '');
103 var onMounted = function() {
104 driveChoice.disabled = false;
105 driveDiv.removeAttribute('disabled');
106 driveLabel.textContent =
107 loadTimeData.getString('ACTION_CHOICE_PHOTOS_DRIVE');
110 if (this.volumeManager_.isMounted(RootDirectory.GDATA)) {
111 onMounted();
112 } else {
113 this.volumeManager_.mountGData(onMounted, function() {});
118 * Load the source contents.
119 * @param {string} source Path to source.
120 * @private
122 ActionChoice.prototype.loadSource_ = function(source) {
123 var onTraversed = function(results) {
124 metrics.recordInterval('PhotoImport.Scan');
125 var videos = results.filter(FileType.isVideo);
126 var videoLabel = this.dom_.querySelector('label[for=watch-single-video]');
127 if (videos.length == 1) {
128 videoLabel.textContent = loadTimeData.getStringF(
129 'ACTION_CHOICE_WATCH_SINGLE_VIDEO', videos[0].name);
130 this.singleVideo_ = videos[0];
131 } else {
132 videoLabel.parentNode.style.display = 'none';
135 var mediaFiles = results.filter(FileType.isImageOrVideo);
136 if (mediaFiles.length == 0) {
137 this.dom_.querySelector('#import-photos-to-drive').parentNode.
138 style.display = 'none';
140 // If we have no media files, the only choice is view files. So, don't
141 // confuse user with a single choice, and just open file manager.
142 this.viewFiles_();
143 this.recordAction_('view-files-auto');
144 this.close_();
147 if (mediaFiles.length < ActionChoice.PREVIEW_COUNT) {
148 this.counter_.textContent = loadTimeData.getStringF(
149 'ACTION_CHOICE_COUNTER_NO_MEDIA', results.length);
150 } else {
151 this.counter_.textContent = loadTimeData.getStringF(
152 'ACTION_CHOICE_COUNTER', mediaFiles.length);
154 var previews = mediaFiles.length ? mediaFiles : results;
155 var previewsCount = Math.min(ActionChoice.PREVIEW_COUNT, previews.length);
156 this.renderPreview_(previews, previewsCount);
157 }.bind(this);
159 var onEntry = function(entry) {
160 this.sourceEntry_ = entry;
161 this.document_.querySelector('title').textContent = entry.name;
163 var deviceType = this.volumeManager_.getDeviceType(entry.fullPath);
164 if (deviceType != 'sd') deviceType = 'usb';
165 this.dom_.querySelector('.device-type').setAttribute('device-type',
166 deviceType);
167 this.dom_.querySelector('.loading-text').textContent =
168 loadTimeData.getString('ACTION_CHOICE_LOADING_' +
169 deviceType.toUpperCase());
171 util.traverseTree(entry, onTraversed, 0 /* infinite depth */,
172 FileType.isVisible);
173 }.bind(this);
175 this.sourceEntry_ = null;
176 metrics.startInterval('PhotoImport.Scan');
177 util.resolvePath(this.filesystem_.root, source, onEntry, function() {
178 this.recordAction_('error');
179 this.close_();
180 }.bind(this));
184 * Renders a preview for a media entry.
185 * @param {Array.<FileEntry>} entries The entries.
186 * @param {number} count Remaining count.
187 * @private
189 ActionChoice.prototype.renderPreview_ = function(entries, count) {
190 var entry = entries.shift();
191 var box = this.document_.createElement('div');
192 box.className = 'img-container';
194 var done = function() {
195 this.dom_.removeAttribute('loading');
196 metrics.recordInterval('PhotoImport.Load');
197 }.bind(this);
199 var onSuccess = function() {
200 this.previews_.appendChild(box);
201 if (--count == 0) {
202 done();
203 } else {
204 this.renderPreview_(entries, count);
206 }.bind(this);
208 var onError = function() {
209 if (entries.length == 0) {
210 // Append one image with generic thumbnail.
211 this.previews_.appendChild(box);
212 done();
213 } else {
214 this.renderPreview_(entries, count);
216 }.bind(this);
218 this.metadataCache_.get(entry, 'thumbnail|filesystem',
219 function(metadata) {
220 new ThumbnailLoader(entry.toURL(), metadata).
221 load(box, true /* fill, not fit */, onSuccess, onError, onError);
226 * Closes the window.
227 * @private
229 ActionChoice.prototype.close_ = function() {
230 window.close();
234 * Keydown event handler.
235 * @param {Event} e The event.
236 * @private
238 ActionChoice.prototype.onKeyDown_ = function(e) {
239 switch (util.getKeyModifiers(e) + e.keyCode) {
240 case '13':
241 this.onOk_();
242 return;
243 case '27':
244 this.recordAction_('close');
245 this.close_();
246 return;
251 * Called when OK button clicked.
252 * @param {Event} event The event object.
253 * @private
255 ActionChoice.prototype.onOk_ = function(event) {
256 // Check for click on the disabled choice.
257 var input = event.currentTarget.querySelector('input');
258 if (input && input.disabled) return;
260 if (this.document_.querySelector('#import-photos-to-drive').checked) {
261 var url = util.platform.getURL('photo_import.html') +
262 '#' + this.sourceEntry_.fullPath;
263 var width = 728;
264 var height = 656;
265 var top = Math.round((window.screen.availHeight - height) / 2);
266 var left = Math.round((window.screen.availWidth - width) / 2);
267 util.platform.createWindow(url,
268 {height: height, width: width, left: left, top: top});
269 this.recordAction_('import-photos-to-drive');
270 } else if (this.document_.querySelector('#view-files').checked) {
271 this.viewFiles_();
272 this.recordAction_('view-files');
273 } else if (this.document_.querySelector('#watch-single-video').checked) {
274 chrome.fileBrowserPrivate.viewFiles([this.singleVideo_.toURL()], 'watch',
275 function(success) {});
276 this.recordAction_('watch-single-video');
278 this.close_();
282 * Called when some device is unmounted.
283 * @param {Event} event Event object.
284 * @private
286 ActionChoice.prototype.onDeviceUnmounted_ = function(event) {
287 if (this.sourceEntry_ && event.mountPath == this.sourceEntry_.fullPath) {
288 util.platform.closeWindow();
293 * Perform the 'view files' action.
294 * @private
296 ActionChoice.prototype.viewFiles_ = function() {
297 var path = this.sourceEntry_.fullPath;
298 if (util.platform.v2()) {
299 chrome.runtime.getBackgroundPage(function(bg) {
300 bg.launchFileManager({defaultPath: path});
302 } else {
303 var url = util.platform.getURL('main.html') + '#' + path;
304 util.platform.createWindow(url);
309 * Records an action chosen.
310 * @param {string} action Action name.
311 * @private
313 ActionChoice.prototype.recordAction_ = function(action) {
314 metrics.recordEnum('PhotoImport.Action', action,
315 ['import-photos-to-drive',
316 'view-files',
317 'view-files-auto',
318 'watch-single-video',
319 'error',
320 'close']);