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
2021-06-07 17:33:53 +02:00
* @ link https : //www.egroupware.org
2011-08-25 15:35:53 +02:00
* @ author Andreas Stöckel
2021-06-07 17:33:53 +02:00
* @ copyright EGroupware GmbH 2011 - 2021
* /
2011-08-25 15:35:53 +02:00
/ * e g w : u s e s
2020-01-24 12:14:08 +01:00
/ v e n d o r / b o w e r - a s s e t / j q u e r y / d i s t / j q u e r y . j s ;
et2 _core _common ;
2011-09-02 18:15:57 +02:00
2020-01-24 12:14:08 +01:00
et2 _dataview _model _columns ;
et2 _dataview _view _grid ;
2020-01-31 21:07:27 +01:00
et2 _dataview _view _rowProvider ;
2020-01-24 12:14:08 +01:00
et2 _dataview _view _resizeable ;
2011-08-25 15:35:53 +02:00
* /
2021-06-07 17:33:53 +02:00
import { et2 _dataview _column , et2 _dataview _columns } from './et2_dataview_model_columns' ;
import { et2 _dataview _view _resizable } from "./et2_dataview_view_resizeable" ;
import { et2 _dataview _grid } from "./et2_dataview_view_grid" ;
import { et2 _dataview _rowProvider } from "./et2_dataview_view_rowProvider" ;
2021-06-10 15:40:49 +02:00
import { egw } from "../jsapi/egw_global" ;
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
* /
2021-06-07 17:33:53 +02:00
export class et2 _dataview {
2020-01-24 12:14:08 +01:00
/ * *
* Constructor for the grid container
*
* @ param { DOMElement } _parentNode is the DOM - Node into which the grid view will be inserted
* @ param { egw } _egw
* @ memberOf et2 _dataview
* /
2021-06-07 17:33:53 +02:00
constructor ( _parentNode , _egw ) {
2020-01-24 12:14:08 +01:00
// Copy the arguments
this . parentNode = jQuery ( _parentNode ) ;
this . egw = _egw ;
// Initialize some variables
this . columnNodes = [ ] ; // Array with the header containers
this . columns = [ ] ;
this . columnMgr = null ;
this . rowProvider = null ;
this . width = 0 ;
this . height = 0 ;
this . uniqueId = "gridCont_" + this . egw . uid ( ) ;
// Build the base nodes
this . _createElements ( ) ;
// Read the browser dependant variables
this . _getDepVars ( ) ;
}
/ * *
* Destroys the object , removes all dom nodes and clears all references .
* /
2021-06-07 17:33:53 +02:00
destroy ( ) {
2020-01-24 12:14:08 +01:00
// Clear the columns
this . _clearHeader ( ) ;
// Free the grid
if ( this . grid ) {
2020-01-31 21:07:27 +01:00
this . grid . destroy ( ) ;
2020-01-24 12:14:08 +01:00
}
// Free the row provider
if ( this . rowProvider ) {
2020-01-31 21:07:27 +01:00
this . rowProvider . destroy ( ) ;
2020-01-24 12:14:08 +01:00
}
// Detatch the outer element
this . table . remove ( ) ;
2021-06-07 17:33:53 +02:00
}
2020-01-24 12:14:08 +01:00
/ * *
* Clears all data rows and reloads them
* /
2021-06-07 17:33:53 +02:00
clear ( ) {
2020-01-24 12:14:08 +01:00
if ( this . grid ) {
this . grid . clear ( ) ;
}
2021-06-07 17:33:53 +02:00
}
2020-01-24 12:14:08 +01:00
/ * *
* Returns the column container node for the given column index
*
* @ param _columnIdx the integer column index
* /
2021-06-07 17:33:53 +02:00
getHeaderContainerNode ( _columnIdx ) {
2020-01-24 12:14:08 +01:00
if ( typeof this . columnNodes [ _columnIdx ] != "undefined" ) {
return this . columnNodes [ _columnIdx ] . container [ 0 ] ;
}
return null ;
2021-06-07 17:33:53 +02:00
}
2020-01-24 12:14:08 +01:00
/ * *
* Sets the column descriptors and creates the column header according to it .
* The inner grid will be emptied if it has already been built .
* /
2021-06-07 17:33:53 +02:00
setColumns ( _columnData ) {
2020-01-24 12:14:08 +01:00
// Free all column objects which have been created till this moment
this . _clearHeader ( ) ;
// Copy the given column data
2021-06-07 17:33:53 +02:00
this . columnMgr = new et2 _dataview _columns ( _columnData ) ;
2020-01-24 12:14:08 +01:00
// Create the stylesheets
this . updateColumns ( ) ;
// Build the header row
this . _buildHeader ( ) ;
// Build the grid
this . _buildGrid ( ) ;
2021-06-07 17:33:53 +02:00
}
2020-01-24 12:14:08 +01:00
/ * *
* Resizes the grid
* /
2021-06-07 17:33:53 +02:00
resize ( _w , _h ) {
2020-01-24 12:14:08 +01:00
// Not fully initialized yet...
if ( ! this . columnMgr )
return ;
if ( this . width != _w ) {
this . width = _w ;
// Take grid border width into account
_w -= ( this . table . outerWidth ( true ) - this . table . innerWidth ( ) ) ;
// Take grid header border's width into account. eg. category colors may add extra pixel into width
_w = _w - ( this . thead . find ( 'tr' ) . outerWidth ( ) - this . thead . find ( 'tr' ) . innerWidth ( ) ) ;
// Rebuild the column stylesheets
this . columnMgr . setTotalWidth ( _w - this . scrollbarWidth ) ;
this . _updateColumns ( ) ;
}
if ( this . height != _h ) {
this . height = _h ;
// Set the height of the grid.
if ( this . grid ) {
this . grid . setScrollHeight ( this . height -
this . headTr . outerHeight ( true ) ) ;
}
}
2021-06-07 17:33:53 +02:00
}
2020-01-24 12:14:08 +01:00
/ * *
* Returns the column manager object . You can use it to set the visibility
* of columns etc . Call "updateHeader" if you did any changes .
* /
2021-06-07 17:33:53 +02:00
getColumnMgr ( ) {
2020-01-24 12:14:08 +01:00
return this . columnMgr ;
2021-06-07 17:33:53 +02:00
}
2020-01-24 12:14:08 +01:00
/ * *
* Recalculates the stylesheets which determine the column visibility and
* width .
*
* @ param setDefault boolean Allow admins to save current settings as default for all users
* /
2021-06-07 17:33:53 +02:00
updateColumns ( setDefault = false ) {
2020-01-24 12:14:08 +01:00
if ( this . columnMgr ) {
this . _updateColumns ( ) ;
}
// Ability to notify parent / someone else
if ( this . onUpdateColumns ) {
this . onUpdateColumns ( setDefault ) ;
}
2021-06-07 17:33:53 +02:00
}
2020-01-24 12:14:08 +01:00
/* --- PRIVATE FUNCTIONS --- */
/* --- Code for building the grid container DOM-Tree elements ---- */
/ * *
* Builds the base DOM - Tree elements
* /
2021-06-07 17:33:53 +02:00
_createElements ( ) {
2020-01-24 12:14:08 +01:00
/ *
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 = jQuery ( document . createElement ( "tr" ) ) ;
this . headTr = jQuery ( document . createElement ( "tr" ) ) ;
this . thead = jQuery ( document . createElement ( "thead" ) )
. append ( this . headTr ) ;
this . tbody = jQuery ( document . createElement ( "tbody" ) )
. append ( this . containerTr ) ;
this . table = jQuery ( document . createElement ( "table" ) )
. addClass ( "egwGridView_outer" )
. append ( this . thead , this . tbody )
. appendTo ( this . parentNode ) ;
2021-06-07 17:33:53 +02:00
}
2020-01-24 12:14:08 +01:00
/* --- Code for building the header row --- */
/ * *
* Clears the header row
* /
2021-06-07 17:33:53 +02:00
_clearHeader ( ) {
2020-01-24 12:14:08 +01:00
if ( this . columnMgr ) {
2020-01-30 00:05:01 +01:00
this . columnMgr . destroy ( ) ;
2020-01-24 12:14:08 +01:00
this . columnMgr = null ;
}
// 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" ) ;
// Reset the headerColumns array and empty the table row
this . columnNodes = [ ] ;
this . columns = [ ] ;
this . headTr . empty ( ) ;
2021-06-07 17:33:53 +02:00
}
2020-01-24 12:14:08 +01:00
/ * *
* Sets the column data which is retrieved by calling egwGridColumns . getColumnData .
* The columns will be updated .
* /
2021-06-07 17:33:53 +02:00
_updateColumns ( ) {
2020-01-24 12:14:08 +01:00
// 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 ++ ;
// Update the visibility of the column
this . egw . css ( "." + col . tdClass , "display: table-cell; " +
"!important;" ) ;
// Ugly browser dependant code - each browser seems to treat the
// right (collapsed) border of the row differently
var subBorder = 0 ;
var subHBorder = 0 ;
/ *
if ( jQuery . browser . mozilla )
{
var maj = jQuery . browser . version . split ( "." ) [ 0 ] ;
if ( maj < 2 ) {
subBorder = 1 ; // Versions <= FF 3.6
}
}
if ( jQuery . browser . webkit )
{
if ( ! first )
{
subBorder = 1 ;
}
subHBorder = 1 ;
}
if ( ( jQuery . browser . msie || jQuery . browser . opera ) && first )
{
subBorder = - 1 ;
}
* /
// Make the last columns one pixel smaller, to prevent a horizontal
// scrollbar from showing up
if ( vis _col == total _cnt ) {
subBorder += 1 ;
}
// Write the width of the header columns
var headerWidth = Math . max ( 0 , ( col . width - this . headerBorderWidth - subHBorder ) ) ;
this . egw . css ( ".egwGridView_outer ." + col . divClass , "width: " + headerWidth + "px;" ) ;
// Write the width of the body-columns
var columnWidth = Math . max ( 0 , ( col . width - this . columnBorderWidth - subBorder ) ) ;
this . egw . css ( ".egwGridView_grid ." + col . divClass , "width: " + columnWidth + "px;" ) ;
totalWidth += col . width ;
first = false ;
}
else {
this . egw . css ( "." + col . tdClass , "display: none;" ) ;
}
}
// Add the full row and spacer class
this . egw . css ( ".egwGridView_grid ." + this . uniqueId + "_div_fullRow" , "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;" ) ;
this . egw . css ( ".egwGridView_outer ." + this . uniqueId + "_spacer_fullRow" , "width: " + ( totalWidth - 1 ) + "px; border-right-width: 0 !important;" ) ;
2021-06-07 17:33:53 +02:00
}
2020-01-24 12:14:08 +01:00
/ * *
* Builds the containers for the header row
* /
2021-06-07 17:33:53 +02:00
_buildHeader ( ) {
2020-01-24 12:14:08 +01:00
var self = this ;
var handler = function ( event ) {
} ;
for ( var i = 0 ; i < this . columns . length ; i ++ ) {
var col = this . columns [ i ] ;
// Create the column header and the container element
var cont = jQuery ( document . createElement ( "div" ) )
. addClass ( "innerContainer" )
. addClass ( col . divClass ) ;
var column = jQuery ( document . createElement ( "th" ) )
. addClass ( col . tdClass )
. attr ( "align" , "left" )
. append ( cont )
. appendTo ( this . headTr ) ;
2020-01-30 00:05:01 +01:00
if ( this . columnMgr && this . columnMgr . getColumnById ( i ) ) {
column . addClass ( this . columnMgr . getColumnById ( i ) . fixedWidth ? 'fixedWidth' : 'relativeWidth' ) ;
if ( this . columnMgr . getColumnById ( i ) . visibility === et2 _dataview _column . ET2 _COL _VISIBILITY _ALWAYS _NOSELECT ) {
2020-01-24 12:14:08 +01:00
column . addClass ( 'noResize' ) ;
}
}
// make column resizable
var enc _column = self . columnMgr . getColumnById ( col . id ) ;
if ( enc _column . visibility !== et2 _dataview _column . ET2 _COL _VISIBILITY _ALWAYS _NOSELECT ) {
2021-06-07 17:33:53 +02:00
et2 _dataview _view _resizable . makeResizeable ( column , function ( _w ) {
2020-01-24 12:14:08 +01: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" ) ;
2020-01-31 21:07:27 +01:00
self . columnMgr . updated ( ) ;
2020-01-24 12:14:08 +01:00
// Just triggers recalculation
self . columnMgr . getColumnWidth ( 0 ) ;
// Set relative widths to match
var relative = self . columnMgr . totalWidth - self . columnMgr . totalFixed + _w ;
this . set _width ( _w / relative ) ;
2020-01-31 21:07:27 +01:00
for ( var i = 0 ; i < self . columnMgr . columnCount ( ) ; i ++ ) {
2020-06-15 19:42:45 +02:00
var col = self . columnMgr . getColumnById ( 'col_' + i ) ;
if ( ! col || col == this || col . fixedWidth )
2020-01-24 12:14:08 +01:00
continue ;
2020-01-30 00:05:01 +01:00
col . set _width ( self . columnMgr . getColumnWidth ( i ) / relative ) ;
2020-01-24 12:14:08 +01:00
}
// Triggers column change callback, which saves
self . updateColumns ( ) ;
}
else {
this . set _width ( this . relativeWidth ? ( _w / self . columnMgr . totalWidth ) : _w + "px" ) ;
2020-01-31 21:07:27 +01:00
self . columnMgr . updated ( ) ;
2020-01-24 12:14:08 +01:00
self . updateColumns ( ) ;
}
} , enc _column ) ;
}
// Store both nodes in the columnNodes array
this . columnNodes . push ( {
"column" : column ,
"container" : cont
} ) ;
}
this . _buildSelectCol ( ) ;
2021-06-07 17:33:53 +02:00
}
2020-01-24 12:14:08 +01:00
/ * *
* Builds the select cols column
* /
2021-06-07 17:33:53 +02:00
_buildSelectCol ( ) {
2020-01-24 12:14:08 +01:00
// Build the "select columns" icon
this . selectColIcon = jQuery ( document . createElement ( "span" ) )
. addClass ( "selectcols" )
. css ( 'display' , 'inline-block' ) ; // otherwise jQuery('span.selectcols',this.dataview.headTr).show() set it to "inline" causing it to not show up because 0 height
// Build the option column
this . selectCol = jQuery ( document . createElement ( "th" ) )
. addClass ( "optcol" )
. append ( this . selectColIcon )
// Toggle display of option popup
. click ( this , function ( e ) { if ( e . data . selectColumnsClick )
e . data . selectColumnsClick ( e ) ; } )
. appendTo ( this . headTr ) ;
this . selectCol . css ( "width" , this . scrollbarWidth - this . selectCol . outerWidth ( )
+ this . selectCol . width ( ) + 1 ) ;
2021-06-07 17:33:53 +02:00
}
2020-01-24 12:14:08 +01:00
/ * *
* Builds the inner grid class
* /
2021-06-07 17:33:53 +02:00
_buildGrid ( ) {
2020-01-24 12:14:08 +01:00
// Create the collection of column ids
2020-03-11 17:56:51 +01:00
var colIds = [ ] ;
2020-01-24 12:14:08 +01:00
for ( var i = 0 ; i < this . columns . length ; i ++ ) {
2020-03-30 18:28:48 +02:00
if ( this . columns [ i ] . visible ) {
colIds [ i ] = this . columns [ i ] . id ;
}
}
2020-01-24 12:14:08 +01:00
// Create the row provider
if ( this . rowProvider ) {
2020-01-31 21:07:27 +01:00
this . rowProvider . destroy ( ) ;
2020-01-24 12:14:08 +01:00
}
2021-06-07 17:33:53 +02:00
this . rowProvider = new et2 _dataview _rowProvider ( this . uniqueId , colIds ) ;
2020-01-24 12:14:08 +01:00
// Create the grid class and pass "19" as the starting average row height
2021-06-07 17:33:53 +02:00
this . grid = new et2 _dataview _grid ( null , null , this . egw , this . rowProvider , 19 ) ;
2020-01-24 12:14:08 +01:00
// Insert the grid into the DOM-Tree
2020-01-31 21:07:27 +01:00
var tr = jQuery ( this . grid . getFirstNode ( ) ) ;
2020-01-24 12:14:08 +01:00
this . containerTr . replaceWith ( tr ) ;
this . containerTr = tr ;
2021-06-07 17:33:53 +02:00
}
2020-01-24 12:14:08 +01:00
/* --- Code for calculating the browser/css depending widths --- */
/ * *
* Reads the browser dependant variables
* /
2021-06-07 17:33:53 +02:00
_getDepVars ( ) {
2020-01-24 12:14:08 +01:00
if ( typeof this . scrollbarWidth === 'undefined' ) {
// Clone the table and attach it to the outer body tag
var clone = this . table . clone ( ) ;
2020-05-18 20:55:57 +02:00
jQuery ( egw . top . document . getElementsByTagName ( "body" ) [ 0 ] )
2020-01-24 12:14:08 +01:00
. 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 ( ) ;
}
2021-06-07 17:33:53 +02:00
}
2020-01-24 12:14:08 +01:00
/ * *
* Reads the scrollbar width
* /
2021-06-07 17:33:53 +02:00
_getScrollbarWidth ( _table ) {
2020-01-24 12:14:08 +01:00
// Create a temporary td and two divs, which are inserted into the
// 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 = jQuery ( document . createElement ( "div" ) )
. css ( "height" , "1000px" ) ;
var div _outer = jQuery ( document . createElement ( "div" ) )
. css ( "height" , "100px" )
. css ( "width" , "100px" )
. css ( "overflow" , "auto" )
. append ( div _inner ) ;
var td = jQuery ( document . createElement ( "td" ) )
. append ( div _outer ) ;
// Store the scrollbar width statically.
jQuery ( "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 ;
2021-06-07 17:33:53 +02:00
}
2020-01-24 12:14:08 +01:00
/ * *
* Calculates the total width of the header column border
* /
2021-06-07 17:33:53 +02:00
_getHeaderBorderWidth ( _table ) {
2020-01-24 12:14:08 +01:00
// Create a temporary th which is appended to the outer thead row
var cont = jQuery ( document . createElement ( "div" ) )
. addClass ( "innerContainer" ) ;
var th = jQuery ( document . createElement ( "th" ) )
. append ( cont ) ;
// Insert the th into the document tree
jQuery ( "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 ;
2021-06-07 17:33:53 +02:00
}
2020-01-24 12:14:08 +01:00
/ * *
* Calculates the total width of the column border
* /
2021-06-07 17:33:53 +02:00
_getColumnBorderWidth ( _table ) {
2020-01-24 12:14:08 +01:00
// Create a temporary th which is appended to the outer thead row
var cont = jQuery ( document . createElement ( "div" ) )
. addClass ( "innerContainer" ) ;
var td = jQuery ( document . createElement ( "td" ) )
. append ( cont ) ;
// Insert the th into the document tree
jQuery ( "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 ;
2021-06-07 17:33:53 +02:00
}
}
2020-01-24 12:14:08 +01:00
//# sourceMappingURL=et2_dataview.js.map