* Tile view for filemanager

This commit is contained in:
Nathan Gray 2014-12-31 17:55:06 +00:00
parent eb0a91d3fe
commit 33a0d1154a
14 changed files with 310 additions and 1 deletions

View File

@ -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.
*

View File

@ -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));
}
}
});

View File

@ -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.
*

View File

@ -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.
*/

View File

@ -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;

View File

@ -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
*

View File

@ -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
*/

Binary file not shown.

After

Width:  |  Height:  |  Size: 317 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

View File

@ -50,6 +50,7 @@
<vfs-name label="Path" id="path" onchange="if(widget.getValue() == '') { app.filemanager.change_dir('~');} return true;" size="80" class="address"/>
<hbox id="buttons">
<button label="Go to" id="button[go]" image="key_enter"/>
<buttononly label="Tile view" id="button[change_view]" onclick="app.filemanager.change_view" options="list_tile"/>
<image id="tarp" src="buttonseparator"/>
<buttononly statustext="Rename, change permissions or ownership" label="Edit settings" id="button[edit]" onclick="app.filemanager.editprefs();" options="edit"/>
<buttononly label="Create directory" id="button[createdir]" onclick="app.filemanager.createdir();" options="button_createdir,createdir_disabled"/>

View File

@ -0,0 +1,30 @@
<?xml version="1.0"?>
<!-- $Id$ -->
<overlay>
<!--
This is used as a tiled template for nextmatch. Note only 1 column, and
the vbox has both width and height explicitly defined. These are for the vbox,
and any spacing between should be done using its margins.
Also important is the tile class on the row, to get the proper display and
the column width="100%" to take the whole width
-->
<template id="filemanager.tile" template="" lang="" group="0" version="1.9.001">
<grid width="100%">
<columns>
<column width="100%"/>
</columns>
<rows>
<row class="th">
<nextmatch-header/>
</row>
<row class="tile $row_cont[class]">
<vbox class="file_tile" width="150px" height="150px">
<vfs-mime align="center" id="$row"/>
<vfs-name id="${row}[name]" no_lang="1" readonly="true"/>
<description id="${row}[comment]"/>
</vbox>
</row>
</rows>
</grid>
</template>
</overlay>

View File

@ -94,6 +94,31 @@ div.filemanager_navigation > label > input {
text-overflow: ellipsis;
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
*/

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 996 B