diff --git a/etemplate/js/et2_dataview_controller.js b/etemplate/js/et2_dataview_controller.js index 4fc141f40d..8eacb1a646 100644 --- a/etemplate/js/et2_dataview_controller.js +++ b/etemplate/js/et2_dataview_controller.js @@ -352,7 +352,7 @@ var et2_dataview_controller = Class.extend({ if (!_entry.row) { createdRow = true; - _entry.row = new et2_dataview_row(this._grid); + _entry.row = this._createRow(ctx); _entry.row.setDestroyCallback(this._destroyCallback, ctx); } @@ -388,6 +388,17 @@ var et2_dataview_controller = Class.extend({ return this.hasData; }, + + /** + * Create a new row. + * + * @param {type} ctx + * @returns {et2_dataview_container} + */ + _createRow: function(ctx) { + return new et2_dataview_row(this._grid); + }, + /** * Function which gets called by the grid when data is requested. * diff --git a/etemplate/js/et2_dataview_view_tile.js b/etemplate/js/et2_dataview_view_tile.js new file mode 100644 index 0000000000..57fbf278c2 --- /dev/null +++ b/etemplate/js/et2_dataview_view_tile.js @@ -0,0 +1,106 @@ +/** + * EGroupware eTemplate2 - dataview code + * + * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License + * @package etemplate + * @subpackage dataview + * @link http://www.egroupware.org + * @author Nathan Gray + * @copyright Nathan Gray 2014 + * @version $Id: et2_dataview_view_container_1.js 46338 2014-03-20 09:40:37Z ralfbecker $ + */ + +"use strict"; + +/*egw:uses + jquery.jquery; + et2_dataview_interfaces; +*/ + +/** + * Displays tiles or thumbnails (squares) instead of full rows. + * + * It's important that the template specifies a fixed width and height (via CSS) + * so that the rows and columns work out properly. + * + * @augments et2_dataview_container + */ +var et2_dataview_tile = et2_dataview_row.extend([], +{ + columns: 4, + + /** + * Creates the row container. Use the "setRow" function to load the actual + * row content. + * + * @param _parent is the row parent container. + * @memberOf et2_dataview_row + */ + init: function(_parent) { + // Call the inherited constructor + this._super(_parent); + + // Make sure the needed class is there to get the CSS + this.tr.addClass('tile'); + }, + + makeExpandable: function (_expandable, _callback, _context) { + // Nope. It mostly works, it's just weird. + }, + + getAvgHeightData: function() { + var res = { + "avgHeight": this.getHeight() / this.columns, + "avgCount": this.columns + }; + return res; + }, + + /** + * Returns the height for the tile. + * + * This is where we do the magic. If a new row should start, we return the proper + * height. If this should be another tile in the same row, we say it has 0 height. + * @returns {Number} + */ + getHeight: function() { + if(this._index % this.columns == 0) + { + return this._super(); + } + else + { + return 0; + } + }, + + /** + * Broadcasts an invalidation through the container tree. Marks the own + * height as invalid. + */ + invalidate: function() { + if(this._inTree && this.tr) + { + var template_width = $j('.innerContainer',this.tr).children().outerWidth(true); + if(template_width) + { + + this.tr.css('width', template_width + (this.tr.outerWidth(true) - this.tr.width())); + } + } + this._recalculate_columns(); + this._super(); + }, + + /** + * Recalculate how many columns we can fit in a row. + * While browser takes care of the actual layout, we need this for proper + * pagination. + */ + _recalculate_columns: function() { + if(this._inTree && this.tr && this.tr.parent()) + { + this.columns = parseInt(this.tr.parent().innerWidth() / this.tr.outerWidth(true)); + } + } +}); diff --git a/etemplate/js/et2_extension_nextmatch.js b/etemplate/js/et2_extension_nextmatch.js index 4d79656bcd..c48d2a9769 100644 --- a/etemplate/js/et2_extension_nextmatch.js +++ b/etemplate/js/et2_extension_nextmatch.js @@ -138,6 +138,10 @@ var et2_nextmatch = et2_DOMWidget.extend([et2_IResizeable, et2_IInput], createNamespace: true, columns: [], + + // Current view, either row or tile. We store it here as controllers are + // recreated when the template changes. + view: 'row', /** * Constructor @@ -1109,6 +1113,9 @@ var et2_nextmatch = et2_DOMWidget.extend([et2_IResizeable, et2_IInput], } this.controller.setPrefix(this.options.settings.dataStorePrefix); + // Set the view + this.controller._view = this.view; + // Load the initial order /*this.controller.loadInitialOrder(this._getInitialOrder( this.options.settings.rows, this.options.settings.row_id @@ -1651,6 +1658,26 @@ var et2_nextmatch = et2_DOMWidget.extend([et2_IResizeable, et2_IInput], } }, + /** + * Switch view between row and tile. + * This should be followed by a call to change the template to match, which + * will cause a reload of the grid using the new settings. + * + * @param {type} view + */ + set_view: function(view) + { + // Restrict to the only 2 accepted values + if(view == 'tile') + { + this.view = 'tile'; + } + else + { + this.view = 'row'; + } + }, + /** * Set a different / additional handler for dropped files. * diff --git a/etemplate/js/et2_extension_nextmatch_controller.js b/etemplate/js/et2_extension_nextmatch_controller.js index 94bddfc98a..98075d90fa 100644 --- a/etemplate/js/et2_extension_nextmatch_controller.js +++ b/etemplate/js/et2_extension_nextmatch_controller.js @@ -19,6 +19,7 @@ et2_dataview_view_row; et2_dataview_controller; et2_dataview_interfaces; + et2_dataview_view_tile; et2_extension_nextmatch_actions; // Contains nm_action @@ -30,6 +31,10 @@ */ var et2_nextmatch_controller = et2_dataview_controller.extend(et2_IDataProvider, { + // Display constants + VIEW_ROW: 'row', + VIEW_TILE: 'tile', + /** * Initializes the nextmatch controller. * @@ -94,6 +99,8 @@ var et2_nextmatch_controller = et2_dataview_controller.extend(et2_IDataProvider, // dataUnregisterUID this.dataUnregisterUID = _egw.dataUnregisterUID; + // Default to rows + this._view = et2_nextmatch_controller.prototype.VIEW_ROW; }, destroy: function () { @@ -190,6 +197,34 @@ var et2_nextmatch_controller = et2_dataview_controller.extend(et2_IDataProvider, /** -- PRIVATE FUNCTIONS -- **/ + /** + * Create a new row, either normal or tiled + * + * @param {type} ctx + * @returns {et2_dataview_container} + */ + _createRow: function(ctx) { + switch(this._view) + { + case et2_nextmatch_controller.prototype.VIEW_TILE: + var row = new et2_dataview_tile(this._grid); + // Try to overcome chrome rendering issue where float is not + // applied properly, leading to incomplete rows + window.setTimeout(function() { + if(!row.tr) return; + row.tr.css('float','none'); + window.setTimeout(function() { + if(!row.tr) return; + row.tr.css('float','left'); + },50); + },100); + return row; + case et2_nextmatch_controller.prototype.VIEW_ROW: + default: + return new et2_dataview_row(this._grid); + } + }, + /** * Initializes the action and the object manager. */ diff --git a/etemplate/templates/default/etemplate2.css b/etemplate/templates/default/etemplate2.css index 0b038393ab..f87233b0ca 100644 --- a/etemplate/templates/default/etemplate2.css +++ b/etemplate/templates/default/etemplate2.css @@ -1147,6 +1147,18 @@ div.message.floating { margin-right: -11px; } /* End of hierarchy */ + +/* Nextmatch tiled view */ +.et2_nextmatch .egwGridView_grid tr.tile { + display: inline-block; + width: 240px; + float: left; + padding: 2px; +} +.et2_nextmatch .egwGridView_grid tr.tile > td > div > *:first-child { + text-align: center; +} + /* Mangled link-to widget inside a nextmatch - used for DnD uploads */ .et2_nextmatch * .et2_link_to { position: fixed; diff --git a/filemanager/js/app.js b/filemanager/js/app.js index 75c62ba248..801120af17 100644 --- a/filemanager/js/app.js +++ b/filemanager/js/app.js @@ -606,6 +606,42 @@ app.classes.filemanager = AppJS.extend( this.path_widget[etemplate_name].set_value(_dir); }, + /** + * Toggle view between tiles and rows + * + * @param {string} [view] - Specify what to change the view to. Either 'tile' or 'row'. + * @param {et2_widget} [button_widget] - The widget that's calling + */ + change_view: function(view, button_widget) + { + var nm = this.et2.getWidgetById('nm'); + if(!nm) + { + egw.debug('warn', 'Could not find nextmatch to change view'); + + return; + } + + if(button_widget && button_widget.instanceOf(et2_button)) + { + // Switch view based on button icon, since controller can get re-created + if(typeof view != 'string') + { + view = button_widget.options.image.replace('list_',''); + } + + // Toggle button icon to the other view + button_widget.set_image("list_"+(view == nm.controller.VIEW_ROW ? nm.controller.VIEW_TILE : nm.controller.VIEW_ROW)); + + button_widget.set_label(view == nm.controller.VIEW_ROW ? this.egw.lang("Tile view") : this.egw.lang('List view')); + } + + nm.set_view(view); + + // Change template to match + this.et2.getWidgetById('nm').set_template(view == nm.controller.VIEW_ROW ? 'filemanager.index.rows' : 'filemanager.tile'); + }, + /** * Open/active an item * diff --git a/filemanager/templates/default/app.css b/filemanager/templates/default/app.css index 5f9b30d101..ce3d69e691 100644 --- a/filemanager/templates/default/app.css +++ b/filemanager/templates/default/app.css @@ -64,6 +64,32 @@ div.filemanager_navigation > label > input { max-height: none; } +/** + * Tile view +table.egwGridView_grid .tile .file_tile { + height: 150px; +} + */ +.egwGridView_grid .tile span.iconOverlayContainer { + display: block; + max-width: 140px; +} +table.egwGridView_grid .tile .file_tile img.vfsMimeIcon { + height: auto; + width: auto; + max-height: 120px; + display:block; + margin: 0 auto; +} +.egwGridView_grid tr.tile:hover .innerContainer { + overflow: visible; +} +.egwGridView_grid tr.tile:hover .file_tile > :not(.iconOverlayContainer) { + position: relative; + z-index:90; + background-color: white; +} + /** * Select file dialog */ diff --git a/filemanager/templates/default/images/list_row.png b/filemanager/templates/default/images/list_row.png new file mode 100644 index 0000000000..189c68cae3 Binary files /dev/null and b/filemanager/templates/default/images/list_row.png differ diff --git a/filemanager/templates/default/images/list_tile.png b/filemanager/templates/default/images/list_tile.png new file mode 100644 index 0000000000..d3963f5e91 Binary files /dev/null and b/filemanager/templates/default/images/list_tile.png differ diff --git a/filemanager/templates/default/index.xet b/filemanager/templates/default/index.xet index b383990f78..7b8282d254 100644 --- a/filemanager/templates/default/index.xet +++ b/filemanager/templates/default/index.xet @@ -50,6 +50,7 @@