diff --git a/apps/files/css/detailsView.css b/apps/files/css/detailsView.css new file mode 100644 index 0000000000..783a8c9b0c --- /dev/null +++ b/apps/files/css/detailsView.css @@ -0,0 +1,22 @@ + + +#app-content-files .detailsView { + position: absolute; + width: 300px; + top: 44px; + bottom: 0; + right: 0; + background-color: white; + border: 1px solid black; +} + +#app-content-files .detailsView .thumbnail { + width: 32px; + height: 32px; + float: left; +} + +#app-content-files .detailsView .detailList { + float: left; +} + diff --git a/apps/files/index.php b/apps/files/index.php index 4f103f975c..1cb7c16ce6 100644 --- a/apps/files/index.php +++ b/apps/files/index.php @@ -50,6 +50,12 @@ OCP\Util::addscript('files', 'search'); \OCP\Util::addScript('files', 'tagsplugin'); \OCP\Util::addScript('files', 'favoritesplugin'); +\OCP\Util::addScript('files', 'detailfileinfoview'); +\OCP\Util::addScript('files', 'detailtabview'); +\OCP\Util::addScript('files', 'detailsview'); +\OCP\Util::addScript('files', 'mainfileinfodetailview'); +\OCP\Util::addStyle('files', 'detailsView'); + \OC_Util::addVendorScript('core', 'handlebars/handlebars'); OCP\App::setActiveNavigationEntry('files_index'); diff --git a/apps/files/js/detailfileinfoview.js b/apps/files/js/detailfileinfoview.js new file mode 100644 index 0000000000..9585f57f1e --- /dev/null +++ b/apps/files/js/detailfileinfoview.js @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2015 + * + * This file is licensed under the Affero General Public License version 3 + * or later. + * + * See the COPYING-README file. + * + */ + +(function() { + /** + * @class OCA.Files.DetailFileInfoView + * @classdesc + * + * Displays a block of details about the file info. + * + */ + var DetailFileInfoView = function() { + this.initialize(); + }; + /** + * @memberof OCA.Files + */ + DetailFileInfoView.prototype = { + /** + * jQuery element + */ + $el: null, + + _template: null, + + /** + * Currently displayed file info + * + * @type OCA.Files.FileInfo + */ + _fileInfo: null, + + /** + * Initialize the details view + */ + initialize: function() { + this.$el = $('
'); + }, + + /** + * Destroy / uninitialize this instance. + */ + destroy: function() { + if (this.$el) { + this.$el.remove(); + } + }, + + /** + * Renders this details view + * + * @abstract + */ + render: function() { + // to be implemented in subclass + }, + + /** + * Sets the file info to be displayed in the view + * + * @param {OCA.Files.FileInfo} fileInfo file info to set + */ + setFileInfo: function(fileInfo) { + this._fileInfo = fileInfo; + this.render(); + }, + + /** + * Returns the file info. + * + * @return {OCA.Files.FileInfo} file info + */ + getFileInfo: function() { + return this._fileInfo; + } + }; + + OCA.Files.DetailFileInfoView = DetailFileInfoView; +})(); + diff --git a/apps/files/js/detailsview.js b/apps/files/js/detailsview.js new file mode 100644 index 0000000000..a8abac5c68 --- /dev/null +++ b/apps/files/js/detailsview.js @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2015 + * + * This file is licensed under the Affero General Public License version 3 + * or later. + * + * See the COPYING-README file. + * + */ + +(function() { + + var TEMPLATE = + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
'; + + var TEMPLATE_TAB_HEADER = + '
{{label}}
'; + + /** + * @class OCA.Files.DetailsView + * @classdesc + * + * The details view show details about a selected file. + * + */ + var DetailsView = function() { + this.initialize(); + }; + /** + * @memberof OCA.Files + */ + DetailsView.prototype = { + + /** + * jQuery element + */ + $el: null, + + _template: null, + _templateTabHeader: null, + + /** + * Currently displayed file info + * + * @type OCA.Files.FileInfo + */ + _fileInfo: null, + + /** + * List of detail tab views + * + * @type Array + */ + _tabViews: [], + + /** + * List of detail file info views + * + * @type Array + */ + _detailFileInfoViews: [], + + /** + * Initialize the details view + */ + initialize: function() { + this.$el = $('
'); + this.fileInfo = null; + this._tabViews = []; + this._detailFileInfoViews = []; + }, + + /** + * Destroy / uninitialize this instance. + */ + destroy: function() { + if (this.$el) { + this.$el.remove(); + } + }, + + /** + * Renders this details view + */ + render: function() { + this.$el.empty(); + + if (!this._template) { + this._template = Handlebars.compile(TEMPLATE); + } + + if (!this._templateTabHeader) { + this._templateTabHeader = Handlebars.compile(TEMPLATE_TAB_HEADER); + } + + var $el = $(this._template()); + var $tabHeadsContainer = $el.find('.tabHeadsContainer'); + var $tabsContainer = $el.find('.tabContentsContainer'); + var $detailsContainer = $el.find('.detailFileInfoContainer'); + + // render tabs + _.each(this._tabs, function(tabView) { + tabView.render(); + // hidden by default + tabView.$el.addClass('hidden'); + $tabsContainer.append(tabView.$el); + + $tabHeadsContainer.append(this._templateTabHeader({label: tabView.getLabel()})); + }); + + // render details + _.each(this._detailFileInfoViews, function(detailView) { + detailView.render(); + $detailsContainer.append(detailView.$el); + }); + + // select first tab + $el.find('.tabContentsContainer:first').removeClass('hidden'); + + this.$el.append($el); + }, + + /** + * Sets the file info to be displayed in the view + * + * @param {OCA.Files.FileInfo} fileInfo file info to set + */ + setFileInfo: function(fileInfo) { + this._fileInfo = fileInfo; + + // notify all panels + _.each(this._tabs, function(tabView) { + tabView.setFileInfo(fileInfo); + }); + _.each(this._detailFileInfoViews, function(detailView) { + detailView.setFileInfo(fileInfo); + }); + }, + + /** + * Returns the file info. + * + * @return {OCA.Files.FileInfo} file info + */ + getFileInfo: function() { + return this._fileInfo; + }, + + /** + * Adds a tab in the tab view + * + * @param {OCA.Files.DetailTabView} tab view + */ + addTabView: function(tabView) { + this._tabViews.push(tabView); + }, + + /** + * Adds a detail view for file info. + * + * @param {OCA.Files.DetailFileInfoView} detail view + */ + addDetailView: function(detailView) { + this._detailFileInfoViews.push(detailView); + } + }; + + OCA.Files.DetailsView = DetailsView; +})(); + diff --git a/apps/files/js/detailtabview.js b/apps/files/js/detailtabview.js new file mode 100644 index 0000000000..f630099111 --- /dev/null +++ b/apps/files/js/detailtabview.js @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2015 + * + * This file is licensed under the Affero General Public License version 3 + * or later. + * + * See the COPYING-README file. + * + */ + +(function() { + + /** + * @class OCA.Files.DetailTabView + * @classdesc + * + * Base class for tab views to display file information. + * + */ + var DetailTabView = function() { + this.initialize(); + }; + + /** + * @memberof OCA.Files + */ + DetailTabView.prototype = { + /** + * jQuery element + */ + $el: null, + + /** + * Tab id + */ + _id: null, + + /** + * Tab label + */ + _label: null, + + _template: null, + + /** + * Currently displayed file info + * + * @type OCA.Files.FileInfo + */ + _fileInfo: null, + + /** + * Initialize the details view + */ + initialize: function() { + this.$el = $('
'); + }, + + /** + * Destroy / uninitialize this instance. + */ + destroy: function() { + if (this.$el) { + this.$el.remove(); + } + }, + + /** + * Returns the tab label + * + * @return {String} label + */ + getLabel: function() { + return 'Tab ' + this._id; + }, + + /** + * Renders this details view + * + * @abstract + */ + render: function() { + // to be implemented in subclass + }, + + /** + * Sets the file info to be displayed in the view + * + * @param {OCA.Files.FileInfo} fileInfo file info to set + */ + setFileInfo: function(fileInfo) { + this._fileInfo = fileInfo; + this.render(); + }, + + /** + * Returns the file info. + * + * @return {OCA.Files.FileInfo} file info + */ + getFileInfo: function() { + return this._fileInfo; + } + }; + + OCA.Files.DetailTabView = DetailTabView; +})(); + diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index a7d4e41d0e..cbf946974e 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -64,6 +64,11 @@ */ fileSummary: null, + /** + * @type OCA.Files.DetailsView + */ + _detailsView: null, + /** * Whether the file list was initialized already. * @type boolean @@ -262,6 +267,25 @@ this.fileActions.on('setDefault', this._onFileActionsUpdated); }, + /** + * Update the details view to display the given file + * + * @param {OCA.Files.FileInfo} fileInfo file info to display + */ + _updateDetailsView: function(fileInfo) { + if (!this._detailsView) { + this._detailsView = new OCA.Files.DetailsView(); + this.$el.append(this._detailsView.$el); + + this._detailsView.addDetailView(new OCA.Files.MainFileInfoDetailView()); + + this._detailsView.render(); + } + this._detailsView.setFileInfo(_.extend({ + path: this.getCurrentDirectory() + }, fileInfo)); + }, + /** * Event handler for when the window size changed */ @@ -350,6 +374,15 @@ this._selectFileEl($tr, !$checkbox.prop('checked')); this.updateSelectionSummary(); } else { + var currentIndex = $tr.index(); + var fileInfo = this.files[currentIndex]; + + this._updateDetailsView(fileInfo); + event.preventDefault(); + return; + + // FIXME: disabled for testing details view + var filename = $tr.attr('data-file'); var renaming = $tr.data('renaming'); if (!renaming) { diff --git a/apps/files/js/mainfileinfodetailview.js b/apps/files/js/mainfileinfodetailview.js new file mode 100644 index 0000000000..3f3705c258 --- /dev/null +++ b/apps/files/js/mainfileinfodetailview.js @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2015 + * + * This file is licensed under the Affero General Public License version 3 + * or later. + * + * See the COPYING-README file. + * + */ + +(function() { + var TEMPLATE = + '
' + + ''; + + /** + * @class OCA.Files.MainFileInfoDetailView + * @classdesc + * + * Displays main details about a file + * + */ + var MainFileInfoDetailView = function() { + this.initialize(); + }; + /** + * @memberof OCA.Files + */ + MainFileInfoDetailView.prototype = _.extend({}, OCA.Files.DetailFileInfoView.prototype, + /** @lends OCA.Files.MainFileInfoDetailView.prototype */ { + _template: null, + + /** + * Initialize the details view + */ + initialize: function() { + this.$el = $('
'); + }, + + /** + * Renders this details view + * + * @abstract + */ + render: function() { + this.$el.empty(); + + if (!this._template) { + this._template = Handlebars.compile(TEMPLATE); + } + + if (this._fileInfo) { + this.$el.append(this._template(this._fileInfo)); + var $iconDiv = this.$el.find('.thumbnail'); + // FIXME: use proper way, this is only for demo purposes + FileList.lazyLoadPreview({ + path: this._fileInfo.path + '/' + this._fileInfo.name, + mime: this._fileInfo.mimetype, + etag: this._fileInfo.etag, + callback: function(url) { + $iconDiv.css('background-image', 'url("' + url + '")'); + } + }); + } else { + // TODO: render placeholder text? + } + } + }); + + OCA.Files.MainFileInfoDetailView = MainFileInfoDetailView; +})(); +