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() {
10 * The main ActionChoice object.
11 * @param {HTMLElement} dom Container.
12 * @param {FileSystem} filesystem Local file system.
13 * @param {Object} params Parameters.
16 function ActionChoice(dom
, filesystem
, params
) {
17 this.filesystem_
= filesystem
;
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));
27 this.loadSource_(params
.source
);
30 ActionChoice
.prototype = { __proto__
: cr
.EventTarget
.prototype };
33 * The number of previews shown.
35 ActionChoice
.PREVIEW_COUNT
= 3;
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
);
61 onFilesystem(opt_filesystem
);
63 chrome
.fileBrowserPrivate
.requestLocalFileSystem(onFilesystem
);
69 * One-time initialization of dom elements.
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();
93 * Checks whether Drive is reachable.
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
)) {
113 this.volumeManager_
.mountGData(onMounted
, function() {});
118 * Load the source contents.
119 * @param {string} source Path to source.
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];
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.
143 this.recordAction_('view-files-auto');
147 if (mediaFiles
.length
< ActionChoice
.PREVIEW_COUNT
) {
148 this.counter_
.textContent
= loadTimeData
.getStringF(
149 'ACTION_CHOICE_COUNTER_NO_MEDIA', results
.length
);
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
);
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',
167 this.dom_
.querySelector('.loading-text').textContent
=
168 loadTimeData
.getString('ACTION_CHOICE_LOADING_' +
169 deviceType
.toUpperCase());
171 util
.traverseTree(entry
, onTraversed
, 0 /* infinite depth */,
175 this.sourceEntry_
= null;
176 metrics
.startInterval('PhotoImport.Scan');
177 util
.resolvePath(this.filesystem_
.root
, source
, onEntry
, function() {
178 this.recordAction_('error');
184 * Renders a preview for a media entry.
185 * @param {Array.<FileEntry>} entries The entries.
186 * @param {number} count Remaining count.
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');
199 var onSuccess = function() {
200 this.previews_
.appendChild(box
);
204 this.renderPreview_(entries
, count
);
208 var onError = function() {
209 if (entries
.length
== 0) {
210 // Append one image with generic thumbnail.
211 this.previews_
.appendChild(box
);
214 this.renderPreview_(entries
, count
);
218 this.metadataCache_
.get(entry
, 'thumbnail|filesystem',
220 new ThumbnailLoader(entry
.toURL(), metadata
).
221 load(box
, true /* fill, not fit */, onSuccess
, onError
, onError
);
229 ActionChoice
.prototype.close_ = function() {
234 * Keydown event handler.
235 * @param {Event} e The event.
238 ActionChoice
.prototype.onKeyDown_ = function(e
) {
239 switch (util
.getKeyModifiers(e
) + e
.keyCode
) {
244 this.recordAction_('close');
251 * Called when OK button clicked.
252 * @param {Event} event The event object.
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
;
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
) {
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');
282 * Called when some device is unmounted.
283 * @param {Event} event Event object.
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.
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
});
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.
313 ActionChoice
.prototype.recordAction_ = function(action
) {
314 metrics
.recordEnum('PhotoImport.Action', action
,
315 ['import-photos-to-drive',
318 'watch-single-video',