Index: ui/file_manager/file_manager/foreground/js/ui/single_file_details.js |
diff --git a/ui/file_manager/file_manager/foreground/js/ui/single_file_details.js b/ui/file_manager/file_manager/foreground/js/ui/single_file_details.js |
index 5329e1c3325c27da73d146a9bf5a3ee79ed93d01..6a191a82962f9be7d8da695988d0172de115febe 100644 |
--- a/ui/file_manager/file_manager/foreground/js/ui/single_file_details.js |
+++ b/ui/file_manager/file_manager/foreground/js/ui/single_file_details.js |
@@ -20,111 +20,299 @@ function SingleFileDetailsPanel() { |
SingleFileDetailsPanel.prototype = { |
__proto__: HTMLDivElement.prototype, |
onFileSelectionChanged: function(entry) { |
+ this.setFileName_(entry); |
+ this.setGenericThumbnail_(entry); |
+ this.loadMetadata_(entry); |
+ }, |
+ |
+ /** |
+ * Display filename for the filename. |
+ * @param {!FileEntry} entry |
+ * @private |
+ */ |
+ setFileName_: function(entry) { |
+ this.filenameIcon_.setAttribute('file-type-icon', FileType.getIcon(entry)); |
this.filename_.textContent = entry.name; |
- } |
-}; |
+ }, |
-/** |
- * Decorates an HTML element to be a SingleFileDetailsList. |
- * @param {!HTMLDivElement} self The grid to decorate. |
- * @param {!MetadataModel} metadataModel File system metadata. |
- */ |
-SingleFileDetailsPanel.decorate = function(self, metadataModel) { |
- self.__proto__ = SingleFileDetailsPanel.prototype; |
- self.metadataModel = metadataModel; |
/** |
- * Data model of detail infos. |
- * @private {!SingleFileDetailsDataModel} |
- * @const |
+ * Display generic thumbnail for the entry. |
+ * @param {!FileEntry} entry |
+ * @private |
*/ |
- self.model_ = new SingleFileDetailsDataModel(); |
- self.filename_ = assertInstanceof(queryRequiredElement('.filename', self), |
- HTMLDivElement); |
- var list = queryRequiredElement('.details-list', self); |
- SingleFileDetailsList.decorate(list, metadataModel); |
- self.list_ = assertInstanceof(list, SingleFileDetailsList); |
- self.list_.dataModel = self.model_; |
- self.list_.autoExpands = true; |
-}; |
+ setGenericThumbnail_: function(entry) { |
+ if (entry.isDirectory) { |
+ this.thumbnail_.setAttribute('generic-thumbnail', 'folder'); |
+ } else { |
+ var mediaType = FileType.getMediaType(entry); |
+ this.thumbnail_.setAttribute('generic-thumbnail', mediaType); |
+ } |
+ }, |
-/** |
- * SingleFileDetailsList constructor. |
- * |
- * Represents grid for the details list for a single file in Files app. |
- * @constructor |
- * @extends {cr.ui.List} |
- */ |
-function SingleFileDetailsList() { |
- throw new Error('Use SingleFileDetailsList.decorate'); |
-} |
+ /** |
+ * Load metadata for the entry. |
+ * @param {!FileEntry} entry |
+ * @private |
+ */ |
+ loadMetadata_: function(entry) { |
+ this.ticket_++; |
+ var ticket = this.ticket_; |
+ this.thumbnail_.innerHTML = ''; |
+ this.preview_ = null; |
+ this.thumbnail_.classList.toggle('loaded', false); |
+ this.metadataModel_.get([entry], SingleFileDetailsPanel.LOADING_ITEMS) |
+ .then(this.onMetadataLoaded_.bind(this, ticket, entry)); |
+ }, |
-/** |
- * Inherits from cr.ui.List. |
- */ |
-SingleFileDetailsList.prototype = { |
- __proto__: cr.ui.List.prototype, |
- onFileSelectionChanged: function(entry) { |
- console.log(entry); |
- } |
-}; |
+ /** |
+ * Called when a metadata is fetched. |
+ * @param {number} ticket Ticket number. |
+ * @param {!FileEntry} entry |
+ * @param {!Array<!MetadataItem>} items metadata items |
+ * @private |
+ */ |
+ onMetadataLoaded_: function(ticket, entry, items) { |
+ if (this.ticket_ !== ticket) { |
+ return; |
+ } |
+ var item = items[0]; |
+ this.setPreview_(ticket, entry, item); |
+ this.setDetails_(entry, item); |
+ }, |
-/** |
- * Decorates an HTML element to be a SingleFileDetailsList. |
- * @param {!Element} self The grid to decorate. |
- * @param {!MetadataModel} metadataModel File system metadata. |
- */ |
-SingleFileDetailsList.decorate = function(self, metadataModel) { |
- cr.ui.Grid.decorate(self); |
- self.__proto__ = SingleFileDetailsList.prototype; |
- self.metadataModel_ = metadataModel; |
+ /** |
+ * Display preview for the file entry. |
+ * @param {number} ticket Ticket number. |
+ * @param {!FileEntry} entry |
+ * @param {!MetadataItem} item metadata |
+ * @private |
+ */ |
+ setPreview_: function(ticket, entry, item) { |
+ var type = FileType.getType(entry); |
+ var thumbnailUrl = item.thumbnailUrl || item.croppedThumbnailUrl; |
+ if (type.type === 'image') { |
+ if (item.externalFileUrl) { |
+ // it's in Google Drive. Use ImageLoader. |
+ if (item.thumbnailUrl) { |
+ this.loadThumbnailFromDrive_(item.thumbnailUrl, |
+ function (result) { |
+ if (ticket !== this.ticket_) { |
+ return; |
+ } |
+ if (result.status !== 'success') { |
+ return; |
+ } |
+ var url = result.data; |
+ var img = document.createElement('img'); |
+ this.thumbnail_.appendChild(img); |
+ img.src = url; |
+ this.thumbnail_.classList.toggle('loaded', true); |
+ }.bind(this)); |
+ } |
+ } else { |
+ var img = document.createElement('img'); |
+ this.thumbnail_.appendChild(img); |
+ img.src = thumbnailUrl || entry.toURL(); |
+ this.thumbnail_.classList.toggle('loaded', true); |
+ } |
+ } else if (type.type === 'video') { |
+ var video = document.createElement('video'); |
+ video.controls = true; |
+ this.thumbnail_.appendChild(video); |
+ this.thumbnail_.classList.toggle('loaded', true); |
+ video.src = entry.toURL(); |
+ if (item.externalFileUrl) { |
+ // it's in google drive. |
+ if (item.thumbnailUrl) { |
+ this.loadThumbnailFromDrive_(item.thumbnailUrl, |
+ function (result) { |
+ if (ticket !== this.ticket_) { |
+ return; |
+ } |
+ if (result.status !== 'success') { |
+ return; |
+ } |
+ video.poster = result.data; |
+ }.bind(this)); |
+ } |
+ }else if (thumbnailUrl) { |
+ video.poster = thumbnailUrl; |
+ } |
+ this.preview_ = video; |
+ } else if (type.type === 'audio') { |
+ if (item.externalFileUrl) { |
+ // it's in google drive. |
+ if (item.thumbnailUrl) { |
+ this.loadThumbnailFromDrive_(item.thumbnailUrl, |
+ function (result) { |
+ if (ticket !== this.ticket_) { |
+ return; |
+ } |
+ if (result.status !== 'success') { |
+ return; |
+ } |
+ var url = result.data; |
+ var img = document.createElement('img'); |
+ this.thumbnail_.appendChild(img); |
+ img.src = url; |
+ this.thumbnail_.classList.toggle('loaded', true); |
+ }.bind(this)); |
+ } |
+ } else { |
+ this.loadContentMetadata_(entry, function(entry, items) { |
+ if (ticket !== this.ticket_) { |
+ return; |
+ } |
+ var item = items[0]; |
+ if (!item.contentThumbnailUrl) { |
+ return; |
+ } |
+ var img = document.createElement('img'); |
+ this.thumbnail_.appendChild(img); |
+ img.src = item.externalFileUrl; |
+ this.thumbnail_.classList.toggle('loaded', true); |
+ }.bind(this)); |
+ } |
+ var audio = document.createElement('audio'); |
+ audio.controls = true; |
+ this.thumbnail_.appendChild(audio); |
+ audio.src = entry.toURL(); |
+ this.preview_ = audio; |
+ } |
+ }, |
- self.scrollBar_ = new ScrollBar(); |
- self.scrollBar_.initialize(self.parentElement, self); |
+ /** |
+ * Load content metadata |
+ * @param {!FileEntry} entry |
+ * @param {function(!FileEntry, !Array<!MetadataItem>)} callback |
+ * @private |
+ */ |
+ loadContentMetadata_: function(entry, callback) { |
+ this.metadataModel_.get([entry], SingleFileDetailsPanel.CONTENT_ITEMS) |
+ .then(callback.bind(null, entry)); |
+ }, |
+ |
+ /** |
+ * Load thumbnails from Drive. |
+ * @param {string} url Thumbnail url |
+ * @param {function({status: string, data:string, width:number, |
+ * height:number})} callback |
+ * @private |
+ */ |
+ loadThumbnailFromDrive_: function (url, callback) { |
+ ImageLoaderClient.getInstance().load(url, callback); |
+ }, |
- self.itemConstructor = function(entry) { |
- var item = self.ownerDocument.createElement('li'); |
- SingleFileDetailsList.Item.decorate( |
- item, |
- entry, |
- /** @type {FileGrid} */ (self)); |
- return item; |
- }; |
+ /** |
+ * Display detailed information from metadata item. |
+ * @param {!FileEntry} entry |
+ * @param {!MetadataItem} item metadata |
+ * @private |
+ */ |
+ setDetails_: function(entry, item) { |
+ var elem; |
+ // Modification Time |
+ elem = queryRequiredElement('.modification-time', this.list_); |
+ if (item.modificationTime) { |
+ elem.classList.toggle('available', true); |
+ queryRequiredElement('.content', elem).textContent = |
+ this.formatter_.formatModDate(item.modificationTime); |
+ } else { |
+ elem.classList.toggle('available', false); |
+ } |
+ // Filesize |
+ elem = queryRequiredElement('.file-size', this.list_); |
+ if (item.size) { |
+ elem.classList.toggle('available', true); |
+ queryRequiredElement('.content', elem).textContent = |
+ this.formatter_.formatSize(item.size, item.hosted); |
+ } else { |
+ elem.classList.toggle('available', false); |
+ } |
+ // TODO(ryoh): Display more and more details... |
+ }, |
+ /** |
+ * Called when visibility of this panel is changed. |
+ * @param {boolean} visibility True if the details panel is visible. |
+ */ |
+ onVisibilityChanged: function(visibility) { |
+ if (!visibility) { |
+ if (this.preview_) { |
+ this.preview_.pause(); |
+ } |
+ } |
+ } |
}; |
/** |
- * Item for the Grid View. |
- * @constructor |
- * @extends {cr.ui.ListItem} |
+ * Metadata items to display in details panel. |
+ * @const |
*/ |
-SingleFileDetailsList.Item = function() { |
- throw new Error(); |
-}; |
+SingleFileDetailsPanel.LOADING_ITEMS = [ |
+ 'availableOffline', |
+ 'availableWhenMetered', |
+ 'croppedThumbnailUrl', |
+ 'customIconUrl', |
+ 'dirty', |
+ 'externalFileUrl', |
+ 'hosted', |
+ 'imageHeight', |
+ 'imageRotation', |
+ 'imageWidth', |
+ 'mediaArtist', |
+ 'mediaMimeType', |
+ 'mediaTitle', |
+ 'modificationTime', |
+ 'pinned', |
+ 'present', |
+ 'shared', |
+ 'sharedWithMe', |
+ 'size', |
+ 'thumbnailUrl' |
+]; |
/** |
- * Inherits from cr.ui.DetailsItem. |
+ * Metadata items to display content metadatas in details panel. |
+ * @const |
*/ |
-SingleFileDetailsList.Item.prototype.__proto__ = cr.ui.ListItem.prototype; |
+SingleFileDetailsPanel.CONTENT_ITEMS = [ |
+ 'contentThumbnailUrl' |
+]; |
/** |
- * @param {Element} li List item element. |
- * @param {!Entry} entry File entry. |
- * @param {FileGrid} grid Owner. |
+ * Decorates an HTML element to be a SingleFileDetailsList. |
+ * @param {!HTMLDivElement} self The grid to decorate. |
+ * @param {!MetadataModel} metadataModel File system metadata. |
*/ |
-SingleFileDetailsList.Item.decorate = function(li, entry, grid) { |
- li.__proto__ = SingleFileDetailsList.Item.prototype; |
+SingleFileDetailsPanel.decorate = function(self, metadataModel) { |
+ self.__proto__ = SingleFileDetailsPanel.prototype; |
+ self.metadataModel_ = metadataModel; |
+ self.formatter_ = new FileMetadataFormatter(); |
+ self.filename_ = assertInstanceof(queryRequiredElement('.filename', self), |
+ HTMLDivElement); |
+ self.filenameIcon_ = assertInstanceof( |
+ queryRequiredElement('.filename-icon', self), HTMLDivElement); |
+ self.thumbnail_ = assertInstanceof( |
+ queryRequiredElement('.thumbnail', self), HTMLDivElement); |
+ self.list_ = queryRequiredElement('.details-list', self); |
+ /** |
+ * Preview element. Video or Audio element. |
+ * @private {HTMLMediaElement} |
+ */ |
+ self.preview_ = null; |
+ /** |
+ * A ticket to display metadata. |
+ * It strictly increases as the user selects files. |
+ * Only the task that has the latest ticket can update the view. |
+ * @private {number} |
+ */ |
+ self.ticket_ = 0; |
}; |
/** |
- * Data model for details panel. |
- * |
- * @constructor |
- * @extends {cr.ui.ArrayDataModel} |
+ * Sets date and time format. |
+ * @param {boolean} use12hourClock True if 12 hours clock, False if 24 hours. |
*/ |
-function SingleFileDetailsDataModel() { |
- cr.ui.ArrayDataModel.call(this, []); |
-} |
- |
-SingleFileDetailsDataModel.prototype = { |
- __proto__: cr.ui.ArrayDataModel.prototype, |
- |
+SingleFileDetailsPanel.prototype.setDateTimeFormat = function(use12hourClock) { |
+ this.formatter_.setDateTimeFormat(use12hourClock); |
}; |