2011-08-25 15:35:53 +02:00
/ * *
2013-04-13 21:00:13 +02:00
* EGroupware eTemplate2 - dataview code
2011-08-25 15:35:53 +02:00
*
* @ license http : //opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @ package etemplate
* @ subpackage dataview
* @ link http : //www.egroupware.org
* @ author Andreas Stöckel
2012-03-23 13:20:57 +01:00
* @ copyright Stylite 2011 - 2012
2011-08-25 15:35:53 +02:00
* @ version $Id$
* /
2013-04-13 21:00:13 +02:00
"use strict" ;
2011-08-25 15:35:53 +02:00
/ * e g w : u s e s
jquery . jquery ;
et2 _core _common ;
2011-09-02 18:15:57 +02:00
2012-03-23 13:20:57 +01:00
et2 _dataview _model _columns ;
et2 _dataview _view _rowProvider ;
2011-09-02 18:15:57 +02:00
et2 _dataview _view _grid ;
2012-03-12 13:17:07 +01:00
et2 _dataview _view _resizeable ;
2011-08-25 15:35:53 +02:00
* /
/ * *
2012-03-23 13:20:57 +01:00
* The et2 _dataview class is the main class for displaying a dataview . The
* dataview class manages the creation of the outer html nodes ( like the table ,
* header , etc . ) and contains the root container : an instance of
* et2 _dataview _view _grid , which can be accessed using the "grid" property of
* this object .
2014-03-20 10:40:37 +01:00
*
2013-04-13 21:00:13 +02:00
* @ augments Class
2011-08-25 15:35:53 +02:00
* /
2012-03-23 13:20:57 +01:00
var et2 _dataview = Class . extend ( {
2011-08-25 15:35:53 +02:00
/ * *
* Constant which regulates the column padding .
* /
columnPadding : 2 ,
/ * *
* Some browser dependant variables which will be calculated on creation of
* the first gridContainer object .
* /
scrollbarWidth : false ,
headerBorderWidth : false ,
columnBorderWidth : false ,
2011-09-29 21:35:20 +02:00
/ * *
* Hooks to allow parent to keep up to date if things change
* /
onUpdateColumns : false ,
2011-10-04 23:45:54 +02:00
selectColumnsClick : false ,
2011-09-29 21:35:20 +02:00
2011-08-25 15:35:53 +02:00
/ * *
* Constructor for the grid container
2014-03-20 10:40:37 +01:00
*
* @ param { DOMElement } _parentNode is the DOM - Node into which the grid view will be inserted
* @ param { egw } _egw
2013-04-13 21:00:13 +02:00
* @ memberOf et2 _dataview
2011-08-25 15:35:53 +02:00
* /
2012-03-23 13:20:57 +01:00
init : function ( _parentNode , _egw ) {
2011-08-25 15:35:53 +02:00
2011-08-31 17:39:24 +02:00
// Copy the arguments
2011-08-25 15:35:53 +02:00
this . parentNode = $j ( _parentNode ) ;
2012-03-07 16:33:21 +01:00
this . egw = _egw ;
2011-08-25 15:35:53 +02:00
// Initialize some variables
this . columnNodes = [ ] ; // Array with the header containers
this . columns = [ ] ;
this . columnMgr = null ;
2011-09-05 16:35:28 +02:00
this . rowProvider = null ;
2011-08-25 15:35:53 +02:00
2011-08-31 17:39:24 +02:00
this . grid = null ;
2011-08-25 15:35:53 +02:00
this . width = 0 ;
this . height = 0 ;
2012-03-07 16:33:21 +01:00
this . uniqueId = "gridCont_" + this . egw . uid ( ) ;
2011-08-26 11:58:25 +02:00
2011-08-25 15:35:53 +02:00
// Build the base nodes
this . _createElements ( ) ;
// Read the browser dependant variables
this . _getDepVars ( ) ;
} ,
/ * *
* Destroys the object , removes all dom nodes and clears all references .
* /
destroy : function ( ) {
// Clear the columns
this . _clearHeader ( ) ;
2011-08-31 17:39:24 +02:00
// Free the grid
if ( this . grid )
{
this . grid . free ( ) ;
}
2011-09-05 16:35:28 +02:00
// Free the row provider
if ( this . rowProvider )
{
this . rowProvider . free ( ) ;
}
2011-08-25 15:35:53 +02:00
// Detatch the outer element
this . table . remove ( ) ;
} ,
2011-09-09 16:32:55 +02:00
/ * *
* Clears all data rows and reloads them
* /
clear : function ( ) {
if ( this . grid )
{
this . grid . clear ( ) ;
}
} ,
2011-08-25 15:35:53 +02:00
/ * *
* Returns the column container node for the given column index
*
* @ param _columnIdx the integer column index
* /
getHeaderContainerNode : function ( _columnIdx ) {
if ( typeof this . columnNodes [ _columnIdx ] != "undefined" )
{
return this . columnNodes [ _columnIdx ] . container [ 0 ] ;
}
return null ;
} ,
/ * *
* Sets the column descriptors and creates the column header according to it .
* The inner grid will be emptied if it has already been built .
* /
setColumns : function ( _columnData ) {
// Free all column objects which have been created till this moment
2011-08-26 11:58:25 +02:00
this . _clearHeader ( ) ;
2011-08-25 15:35:53 +02:00
2011-08-26 11:58:25 +02:00
// Copy the given column data
this . columnMgr = new et2 _dataview _columns ( _columnData ) ;
// Create the stylesheets
2011-08-31 17:39:24 +02:00
this . updateColumns ( ) ;
2011-08-25 15:35:53 +02:00
// Build the header row
this . _buildHeader ( ) ;
2011-08-31 17:39:24 +02:00
// Build the grid
this . _buildGrid ( ) ;
2011-08-25 15:35:53 +02:00
} ,
/ * *
* Resizes the grid
* /
resize : function ( _w , _h ) {
2013-10-09 16:05:05 +02:00
// Not fully initialized yet...
if ( ! this . columnMgr ) return ;
2014-03-20 10:40:37 +01:00
2011-08-25 15:35:53 +02:00
if ( this . width != _w )
{
this . width = _w ;
// Rebuild the column stylesheets
2011-08-26 11:58:25 +02:00
this . columnMgr . setTotalWidth ( _w - this . scrollbarWidth ) ;
2011-08-25 15:35:53 +02:00
this . _updateColumns ( ) ;
}
if ( this . height != _h )
{
2011-08-26 11:58:25 +02:00
this . height = _h ;
2011-08-31 17:39:24 +02:00
2011-08-25 15:35:53 +02:00
// Set the height of the grid.
2011-08-31 17:39:24 +02:00
if ( this . grid )
{
this . grid . setScrollHeight ( this . height -
this . headTr . outerHeight ( true ) ) ;
}
2011-08-25 15:35:53 +02:00
}
} ,
2011-08-26 11:58:25 +02:00
/ * *
* Returns the column manager object . You can use it to set the visibility
* of columns etc . Call "updateHeader" if you did any changes .
* /
getColumnMgr : function ( ) {
return this . columnMgr ;
} ,
/ * *
* Recalculates the stylesheets which determine the column visibility and
* width .
2014-03-20 10:40:37 +01:00
*
2011-10-04 23:45:54 +02:00
* @ param setDefault boolean Allow admins to save current settings as default for all users
2011-08-26 11:58:25 +02:00
* /
2011-10-04 23:45:54 +02:00
updateColumns : function ( setDefault ) {
2011-08-26 11:58:25 +02:00
if ( this . columnMgr )
{
this . _updateColumns ( ) ;
}
2011-09-29 21:35:20 +02:00
// Ability to notify parent / someone else
if ( this . onUpdateColumns )
{
2011-10-04 23:45:54 +02:00
this . onUpdateColumns ( setDefault ) ;
2011-09-29 21:35:20 +02:00
}
2011-08-26 11:58:25 +02:00
} ,
2011-08-25 15:35:53 +02:00
/* --- PRIVATE FUNCTIONS --- */
/* --- Code for building the grid container DOM-Tree elements ---- */
/ * *
* Builds the base DOM - Tree elements
* /
_createElements : function ( ) {
/ *
Structure :
< table class = "egwGridView_outer" >
< thead >
< tr > [ HEAD ] < / t r >
< / t h e a d >
< tbody >
< tr > [ GRID CONTAINER ] < / t r >
< / t b o d y >
< / t a b l e >
* /
this . containerTr = $j ( document . createElement ( "tr" ) ) ;
this . headTr = $j ( document . createElement ( "tr" ) ) ;
this . thead = $j ( document . createElement ( "thead" ) )
. append ( this . headTr ) ;
this . tbody = $j ( document . createElement ( "tbody" ) )
. append ( this . containerTr ) ;
this . table = $j ( document . createElement ( "table" ) )
. addClass ( "egwGridView_outer" )
. append ( this . thead , this . tbody )
. appendTo ( this . parentNode ) ;
} ,
/* --- Code for building the header row --- */
/ * *
* Clears the header row
* /
_clearHeader : function ( ) {
if ( this . columnMgr )
{
this . columnMgr . free ( ) ;
this . columnMgr = null ;
}
2015-09-23 01:43:20 +02:00
// Remove dynamic CSS,
for ( var i = 0 ; i < this . columns . length ; i ++ )
{
if ( this . columns [ i ] . tdClass )
{
this . egw . css ( '.' + this . columns [ i ] . tdClass ) ;
}
if ( this . columns [ i ] . divClass )
{
this . egw . css ( '.' + this . columns [ i ] . divClass ) ;
this . egw . css ( ".egwGridView_outer ." + this . columns [ i ] . divClass ) ;
this . egw . css ( ".egwGridView_grid ." + this . columns [ i ] . divClass ) ;
}
}
this . egw . css ( ".egwGridView_grid ." + this . uniqueId + "_div_fullRow" ) ;
this . egw . css ( ".egwGridView_outer ." + this . uniqueId + "_td_fullRow" ) ;
this . egw . css ( ".egwGridView_outer ." + this . uniqueId + "_spacer_fullRow" ) ;
2011-08-25 15:35:53 +02:00
// Reset the headerColumns array and empty the table row
this . columnNodes = [ ] ;
2011-08-26 11:58:25 +02:00
this . columns = [ ] ;
2011-08-25 15:35:53 +02:00
this . headTr . empty ( ) ;
} ,
2011-08-26 11:58:25 +02:00
/ * *
* Sets the column data which is retrieved by calling egwGridColumns . getColumnData .
* The columns will be updated .
* /
_updateColumns : function ( ) {
// Copy the columns data
this . columns = this . columnMgr . getColumnData ( ) ;
// Count the visible rows
var total _cnt = 0 ;
for ( var i = 0 ; i < this . columns . length ; i ++ )
{
if ( this . columns [ i ] . visible )
{
total _cnt ++ ;
}
}
// Set the grid column styles
var first = true ;
var vis _col = this . visibleColumnCount = 0 ;
var totalWidth = 0 ;
for ( var i = 0 ; i < this . columns . length ; i ++ )
{
var col = this . columns [ i ] ;
col . tdClass = this . uniqueId + "_td_" + col . id ;
col . divClass = this . uniqueId + "_div_" + col . id ;
if ( col . visible )
{
vis _col ++ ;
this . visibleColumnCount ++ ;
2011-08-31 17:39:24 +02:00
// Update the visibility of the column
2014-03-20 10:40:37 +01:00
this . egw . css ( "." + col . tdClass ,
"display: table-cell; " +
2011-08-26 11:58:25 +02:00
"!important;" ) ;
2014-03-20 10:40:37 +01:00
// Ugly browser dependant code - each browser seems to treat the
2011-08-26 11:58:25 +02:00
// right (collapsed) border of the row differently
2011-09-01 12:02:23 +02:00
var subBorder = 0 ;
var subHBorder = 0 ;
2013-07-18 17:26:41 +02:00
/ *
2011-08-26 11:58:25 +02:00
if ( $j . browser . mozilla )
{
var maj = $j . browser . version . split ( "." ) [ 0 ] ;
if ( maj < 2 ) {
2011-09-01 12:02:23 +02:00
subBorder = 1 ; // Versions <= FF 3.6
2011-08-26 11:58:25 +02:00
}
}
2011-09-01 12:02:23 +02:00
if ( $j . browser . webkit )
2011-08-26 11:58:25 +02:00
{
2011-09-01 12:02:23 +02:00
if ( ! first )
{
subBorder = 1 ;
}
subHBorder = 1 ;
2011-08-26 11:58:25 +02:00
}
if ( ( $j . browser . msie || $j . browser . opera ) && first )
{
2011-09-01 12:02:23 +02:00
subBorder = - 1 ;
2011-08-26 11:58:25 +02:00
}
2013-07-18 17:26:41 +02:00
* /
2011-08-26 11:58:25 +02:00
// Make the last columns one pixel smaller, to prevent a horizontal
// scrollbar from showing up
if ( vis _col == total _cnt )
{
2011-09-01 12:02:23 +02:00
subBorder += 1 ;
2011-08-26 11:58:25 +02:00
}
2011-08-31 17:39:24 +02:00
// Write the width of the header columns
2011-09-01 12:02:23 +02:00
var headerWidth = Math . max ( 0 , ( col . width - this . headerBorderWidth - subHBorder ) ) ;
2014-03-20 10:40:37 +01:00
this . egw . css ( ".egwGridView_outer ." + col . divClass ,
2011-08-31 17:39:24 +02:00
"width: " + headerWidth + "px;" ) ;
2011-08-26 11:58:25 +02:00
2011-09-01 12:02:23 +02:00
// Write the width of the body-columns
var columnWidth = Math . max ( 0 , ( col . width - this . columnBorderWidth - subBorder ) ) ;
2014-03-20 10:40:37 +01:00
this . egw . css ( ".egwGridView_grid ." + col . divClass ,
2011-09-01 12:02:23 +02:00
"width: " + columnWidth + "px;" ) ;
2011-08-26 11:58:25 +02:00
totalWidth += col . width ;
first = false ;
}
else
{
2012-03-07 16:33:21 +01:00
this . egw . css ( "." + col . tdClass , "display: none;" ) ;
2011-08-26 11:58:25 +02:00
}
}
// Add the full row and spacer class
2012-03-07 16:33:21 +01:00
this . egw . css ( ".egwGridView_grid ." + this . uniqueId + "_div_fullRow" ,
2012-03-23 13:20:57 +01:00
"width: " + ( totalWidth - this . columnBorderWidth - 2 ) + "px; border-right-width: 0 !important;" ) ;
this . egw . css ( ".egwGridView_outer ." + this . uniqueId + "_td_fullRow" ,
"border-right-width: 0 !important;" ) ;
2012-03-07 16:33:21 +01:00
this . egw . css ( ".egwGridView_outer ." + this . uniqueId + "_spacer_fullRow" ,
2011-08-26 11:58:25 +02:00
"width: " + ( totalWidth - 1 ) + "px; border-right-width: 0 !important;" ) ;
} ,
2011-08-25 15:35:53 +02:00
/ * *
* Builds the containers for the header row
* /
_buildHeader : function ( ) {
2011-09-30 00:57:42 +02:00
var self = this ;
var handler = function ( event ) {
2013-04-13 21:00:13 +02:00
} ;
2011-08-25 15:35:53 +02:00
for ( var i = 0 ; i < this . columns . length ; i ++ )
{
var col = this . columns [ i ] ;
// Create the column header and the container element
var cont = $j ( document . createElement ( "div" ) )
. addClass ( "innerContainer" )
. addClass ( col . divClass ) ;
2011-09-30 00:57:42 +02:00
2011-08-25 15:35:53 +02:00
var column = $j ( document . createElement ( "th" ) )
. addClass ( col . tdClass )
2012-05-07 20:43:38 +02:00
. attr ( "align" , "left" )
2011-08-25 15:35:53 +02:00
. append ( cont )
. appendTo ( this . headTr ) ;
2014-09-09 19:39:33 +02:00
if ( this . columnMgr && this . columnMgr . columns [ i ] )
{
column . addClass ( this . columnMgr . columns [ i ] . fixedWidth ? 'fixedWidth' : 'relativeWidth' ) ;
}
2011-08-25 15:35:53 +02:00
2013-02-06 17:32:18 +01:00
// make column resizable
var enc _column = self . columnMgr . getColumnById ( col . id ) ;
et2 _dataview _makeResizeable ( column , function ( _w ) {
2014-09-09 18:58:26 +02:00
// User wants the column to stay where they put it, even for relative
// width columns, so set it explicitly first and adjust other relative
// columns to match.
if ( this . relativeWidth )
{
// Set to selected width
this . set _width ( _w + "px" ) ;
self . columnMgr . updated = true ;
2014-10-08 00:59:55 +02:00
// Just triggers recalculation
self . columnMgr . getColumnWidth ( 0 ) ;
2014-09-09 18:58:26 +02:00
// Set relative widths to match
var relative = self . columnMgr . totalWidth - self . columnMgr . totalFixed + _w ;
this . set _width ( _w / relative ) ;
for ( var i = 0 ; i < self . columnMgr . columns . length ; i ++ )
{
var col = self . columnMgr . columns [ i ] ;
if ( col == this || col . fixedWidth ) continue ;
2014-10-08 19:10:58 +02:00
col . set _width ( self . columnMgr . columnWidths [ i ] / relative ) ;
2014-09-09 18:58:26 +02:00
}
2014-10-08 00:59:55 +02:00
// Triggers column change callback, which saves
self . updateColumns ( ) ;
2014-09-09 18:58:26 +02:00
}
else
{
this . set _width ( this . relativeWidth ? ( _w / self . columnMgr . totalWidth ) : _w + "px" ) ;
self . columnMgr . updated = true ;
self . updateColumns ( ) ;
}
2013-02-06 17:32:18 +01:00
} , enc _column ) ;
2011-09-30 00:57:42 +02:00
2011-08-25 15:35:53 +02:00
// Store both nodes in the columnNodes array
this . columnNodes . push ( {
"column" : column ,
"container" : cont
} ) ;
}
this . _buildSelectCol ( ) ;
} ,
/ * *
* Builds the select cols column
* /
_buildSelectCol : function ( ) {
// Build the "select columns" icon
this . selectColIcon = $j ( document . createElement ( "span" ) )
2013-08-20 10:03:46 +02:00
. addClass ( "selectcols" )
. css ( 'display' , 'inline-block' ) ; // otherwise $j('span.selectcols',this.dataview.headTr).show() set it to "inline" causing it to not show up because 0 height
2011-08-25 15:35:53 +02:00
// Build the option column
this . selectCol = $j ( document . createElement ( "th" ) )
. addClass ( "optcol" )
. append ( this . selectColIcon )
2011-10-04 23:45:54 +02:00
// Toggle display of option popup
2013-04-13 21:00:13 +02:00
. click ( this , function ( e ) { if ( e . data . selectColumnsClick ) e . data . selectColumnsClick ( e ) ; } )
2011-08-25 15:35:53 +02:00
. appendTo ( this . headTr ) ;
this . selectCol . css ( "width" , this . scrollbarWidth - this . selectCol . outerWidth ( )
+ this . selectCol . width ( ) + 1 ) ;
} ,
2011-08-31 17:39:24 +02:00
/ * *
* Builds the inner grid class
* /
_buildGrid : function ( ) {
// Create the collection of column ids
var colIds = new Array ( this . columns . length ) ;
for ( var i = 0 ; i < this . columns . length ; i ++ )
{
colIds [ i ] = this . columns [ i ] . id ;
}
2011-09-05 16:35:28 +02:00
// Create the row provider
if ( this . rowProvider )
{
this . rowProvider . free ( ) ;
}
this . rowProvider = new et2 _dataview _rowProvider ( this . uniqueId , colIds ) ;
2011-08-31 17:39:24 +02:00
// Create the grid class and pass "19" as the starting average row height
2012-03-30 13:43:39 +02:00
this . grid = new et2 _dataview _grid ( null , null , this . egw , this . rowProvider , 19 ) ;
2011-08-31 17:39:24 +02:00
// Insert the grid into the DOM-Tree
2012-03-23 13:20:57 +01:00
var tr = $j ( this . grid . _nodes [ 0 ] ) ;
this . containerTr . replaceWith ( tr ) ;
this . containerTr = tr ;
2011-08-31 17:39:24 +02:00
} ,
2011-08-25 15:35:53 +02:00
/* --- Code for calculating the browser/css depending widths --- */
/ * *
* Reads the browser dependant variables
* /
_getDepVars : function ( ) {
if ( this . scrollbarWidth === false )
{
// Clone the table and attach it to the outer body tag
var clone = this . table . clone ( ) ;
$j ( window . top . document . getElementsByTagName ( "body" ) [ 0 ] )
. append ( clone ) ;
// Read the scrollbar width
this . scrollbarWidth = this . constructor . prototype . scrollbarWidth =
this . _getScrollbarWidth ( clone ) ;
// Read the header border width
this . headerBorderWidth = this . constructor . prototype . headerBorderWidth =
this . _getHeaderBorderWidth ( clone ) ;
// Read the column border width
this . columnBorderWidth = this . constructor . prototype . columnBorderWidth =
this . _getColumnBorderWidth ( clone ) ;
// Remove the cloned DOM-Node again from the outer body
clone . remove ( ) ;
}
} ,
/ * *
* Reads the scrollbar width
* /
_getScrollbarWidth : function ( _table ) {
2014-03-20 10:40:37 +01:00
// Create a temporary td and two divs, which are inserted into the
2011-08-25 15:35:53 +02:00
// DOM-Tree. The outer div has a fixed size and "overflow" set to auto.
// When the second div is inserted, it will be forced to display a scrollbar.
var div _inner = $j ( document . createElement ( "div" ) )
. css ( "height" , "1000px" ) ;
var div _outer = $j ( document . createElement ( "div" ) )
. css ( "height" , "100px" )
. css ( "width" , "100px" )
. css ( "overflow" , "auto" )
. append ( div _inner ) ;
var td = $j ( document . createElement ( "td" ) )
. append ( div _outer ) ;
// Store the scrollbar width statically.
$j ( "tbody tr" , _table ) . append ( td ) ;
var width = Math . max ( 10 , div _outer . outerWidth ( ) - div _inner . outerWidth ( ) ) ;
// Remove the elements again
div _outer . remove ( ) ;
return width ;
} ,
/ * *
* Calculates the total width of the header column border
* /
_getHeaderBorderWidth : function ( _table ) {
// Create a temporary th which is appended to the outer thead row
var cont = $j ( document . createElement ( "div" ) )
. addClass ( "innerContainer" ) ;
var th = $j ( document . createElement ( "th" ) )
. append ( cont ) ;
// Insert the th into the document tree
$j ( "thead tr" , _table ) . append ( th ) ;
// Calculate the total border width
var width = th . outerWidth ( true ) - cont . width ( ) ;
// Remove the appended element again
th . remove ( ) ;
return width ;
} ,
/ * *
* Calculates the total width of the column border
* /
_getColumnBorderWidth : function ( _table ) {
// Create a temporary th which is appended to the outer thead row
var cont = $j ( document . createElement ( "div" ) )
. addClass ( "innerContainer" ) ;
var td = $j ( document . createElement ( "td" ) )
. append ( cont ) ;
// Insert the th into the document tree
$j ( "tbody tr" , _table ) . append ( td ) ;
// Calculate the total border width
_table . addClass ( "egwGridView_grid" ) ;
var width = td . outerWidth ( true ) - cont . width ( ) ;
// Remove the appended element again
td . remove ( ) ;
return width ;
}
} ) ;