2011-08-25 15:35:53 +02:00
/ * *
* eGroupWare eTemplate2 - JS Nextmatch object
*
* @ license http : //opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @ package etemplate
* @ subpackage api
* @ link http : //www.egroupware.org
* @ author Andreas Stöckel
* @ copyright Stylite 2011
* @ version $Id$
* /
"use strict" ;
/ * e g w : u s e s
jquery . jquery ;
et2 _widget ;
et2 _core _interfaces ;
et2 _core _DOMWidget ;
et2 _widget _template ;
et2 _widget _grid ;
et2 _widget _selectbox ;
2011-08-25 17:54:15 +02:00
et2 _extension _nextmatch _dynheight ;
2011-09-02 18:15:57 +02:00
et2 _dataview _view _gridContainer ;
et2 _dataview _model _dataProvider ;
2011-09-09 11:57:59 +02:00
et2 _dataview _model _columns ;
2011-08-25 15:35:53 +02:00
* /
/ * *
* Interface all special nextmatch header elements have to implement .
* /
var et2 _INextmatchHeader = new Interface ( {
/ * *
* The 'setNextmatch' function is called by the parent nextmatch widget
* and tells the nextmatch header widgets which widget they should direct
* their 'sort' , 'search' or 'filter' calls to .
* /
setNextmatch : function ( _nextmatch ) { }
} ) ;
var et2 _INextmatchSortable = new Interface ( {
setSortmode : function ( _mode ) { }
} ) ;
/ * *
* Class which implements the "nextmatch" XET - Tag
* /
2011-08-25 17:54:15 +02:00
var et2 _nextmatch = et2 _DOMWidget . extend ( et2 _IResizeable , {
2011-08-25 15:35:53 +02:00
attributes : {
"template" : {
"name" : "Template" ,
"type" : "string" ,
"description" : "The id of the template which contains the grid layout."
}
} ,
legacyOptions : [ "template" ] ,
init : function ( ) {
this . _super . apply ( this , arguments ) ;
this . div = $j ( document . createElement ( "div" ) )
. addClass ( "et2_nextmatch" ) ;
2011-08-25 17:54:15 +02:00
// Create the dynheight component which dynamically scales the inner
// container.
this . dynheight = new et2 _dynheight ( null , this . div , 150 ) ;
2011-08-31 17:39:24 +02:00
// Create the data provider which cares about streaming the row data
// efficiently to the rows
2011-09-08 20:36:09 +02:00
this . dataProvider = new et2 _dataview _dataProvider ( this , 100 ) ;
2011-08-31 17:39:24 +02:00
2011-08-25 15:35:53 +02:00
// Create the outer grid container
2011-08-31 17:39:24 +02:00
this . dataviewContainer = new et2 _dataview _gridContainer ( this . div ,
this . dataProvider ) ;
2011-08-25 15:35:53 +02:00
this . activeFilters = { } ;
} ,
2011-08-26 11:58:25 +02:00
/ * *
* Destroys all
* /
2011-08-25 15:35:53 +02:00
destroy : function ( ) {
this . dataviewContainer . free ( ) ;
2011-08-31 17:39:24 +02:00
this . dataProvider . free ( ) ;
2011-08-25 17:54:15 +02:00
this . dynheight . free ( ) ;
2011-08-25 15:35:53 +02:00
this . _super . apply ( this , arguments ) ;
} ,
2011-08-26 11:58:25 +02:00
/ * *
* Implements the et2 _IResizeable interface - lets the dynheight manager
* update the width and height and then update the dataview container .
* /
2011-08-25 17:54:15 +02:00
resize : function ( ) {
2011-08-26 11:58:25 +02:00
this . dynheight . update ( function ( _w , _h ) {
this . dataviewContainer . resize ( _w , _h ) ;
} , this ) ;
2011-08-25 17:54:15 +02:00
} ,
2011-09-08 20:36:09 +02:00
/ * *
* Get Rows callback
* /
getRows : function ( _fetchList , _callback , _context ) {
console . log ( "Nextmatch will fetch " , _fetchList ) ;
// Create the entries:
var entries = { } ;
for ( var i = 0 ; i < _fetchList . length ; i ++ )
{
var start = _fetchList [ i ] . startIdx ;
for ( var j = 0 ; j < _fetchList [ i ] . count ; j ++ )
{
entries [ start + j ] =
{ "info_id" : "5" , "info_type" : "email" , "info_from" : "tracker" , "info_addr" : "tracker" , "info_subject" : "InfoLog grid view: problem with Opera; 'permission denied' while saving" , "info_des" : "<snip>" , "info_owner" : "5" , "info_responsible" : [ ] , "info_access" : "public" , "info_cat" : "0" , "info_datemodified" : 1307112528 , "info_startdate" : 1306503000 , "info_enddate" : "0" , "info_id_parent" : "0" , "info_planned_time" : "0" , "info_replanned_time" : "0" , "info_used_time" : "0" , "info_status" : "done" , "info_confirm" : "not" , "info_modifier" : "5" , "info_link_id" : 0 , "info_priority" : "1" , "pl_id" : "0" , "info_price" : null , "info_percent" : "100%" , "info_datecompleted" : 1307112528 , "info_location" : "" , "info_custom_from" : 1 , "info_uid" : "infolog-5-18d12c7bf195f6b9d602e1fa5cde28f1" , "info_cc" : "" , "caldav_name" : "5.ics" , "info_etag" : "0" , "info_created" : 1307112528 , "info_creator" : "5" , "links" : [ ] , "info_anz_subs" : 0 , "sub_class" : "normal_done" , "info_link" : { "title" : "tracker" } , "class" : "rowNoClose rowNoCloseAll " , "info_type_label" : "E-Mail" , "info_status_label" : "done" , "info_number" : "5" }
}
}
_callback . call ( _context , entries ) ;
} ,
2011-08-25 15:35:53 +02:00
/ * *
* Sorts the nextmatch widget by the given ID .
*
* @ param _id is the id of the data entry which should be sorted .
* @ param _asc if true , the elements are sorted ascending , otherwise
* descending . If not set , the sort direction will be determined
* automatically .
* /
sortBy : function ( _id , _asc ) {
// Create the "sort" entry in the active filters if it did not exist
// yet.
if ( typeof this . activeFilters [ "sort" ] == "undefined" )
{
this . activeFilters [ "sort" ] = {
"id" : null ,
"asc" : true
} ;
}
// Determine the sort direction automatically if it is not set
if ( typeof _asc == "undefined" )
{
if ( this . activeFilters [ "sort" ] . id == _id )
{
_asc = ! this . activeFilters [ "sort" ] . asc ;
}
}
// Update the entry in the activeFilters object
this . activeFilters [ "sort" ] = {
"id" : _id ,
"asc" : _asc
}
// Set the sortmode display
this . iterateOver ( function ( _widget ) {
_widget . setSortmode ( ( _widget . id == _id ) ? ( _asc ? "asc" : "desc" ) : "none" ) ;
} , this , et2 _INextmatchSortable ) ;
et2 _debug ( "info" , "Sorting nextmatch by '" + _id + "' in direction '" +
( _asc ? "asc" : "desc" ) + "'" ) ;
} ,
2011-08-26 11:58:25 +02:00
/ * *
* Removes the sort entry from the active filters object and thus returns to
* the natural sort order .
* /
2011-08-25 15:35:53 +02:00
resetSort : function ( ) {
// Check whether the nextmatch widget is currently sorted
if ( typeof this . activeFilters [ "sort" ] != "undefined" )
{
// Reset the sortmode
this . iterateOver ( function ( _widget ) {
_widget . setSortmode ( "none" ) ;
} , this , et2 _INextmatchSortable ) ;
2011-08-26 11:58:25 +02:00
// Delete the "sort" filter entry
2011-08-25 15:35:53 +02:00
delete ( this . activeFilters [ "sort" ] ) ;
this . applyFilters ( ) ;
}
} ,
applyFilters : function ( ) {
et2 _debug ( "info" , "Changing nextmatch filters to " , this . activeFilters ) ;
} ,
/ * *
* Generates the column name for the given column widget
* /
2011-08-26 11:58:25 +02:00
_genColumnCaption : function ( _widget ) {
2011-08-25 15:35:53 +02:00
var result = null ;
_widget . iterateOver ( function ( _widget ) {
if ( ! result )
{
result = _widget . options . label ;
}
else
{
result += ", " + _widget . options . label ;
}
} , this , et2 _INextmatchHeader ) ;
return result ;
} ,
2011-08-26 11:58:25 +02:00
_parseHeaderRow : function ( _row , _colData ) {
2011-08-25 15:35:53 +02:00
// Go over the header row and create the column entries
this . columns = new Array ( _row . length ) ;
2011-08-26 11:58:25 +02:00
var columnData = new Array ( _row . length ) ;
2011-08-25 15:35:53 +02:00
for ( var x = 0 ; x < _row . length ; x ++ )
{
this . columns [ x ] = {
2011-08-26 11:58:25 +02:00
"widget" : _row [ x ] . widget
} ;
columnData [ x ] = {
"id" : "col_" + x ,
"caption" : this . _genColumnCaption ( _row [ x ] . widget ) ,
"visibility" : _colData [ x ] . disabled ?
ET2 _COL _VISIBILITY _INVISIBLE : ET2 _COL _VISIBILITY _VISIBLE ,
"width" : _colData [ x ] . width
} ;
2011-08-25 15:35:53 +02:00
// Append the widget to this container
this . addChild ( _row [ x ] . widget ) ;
}
2011-08-26 11:58:25 +02:00
// Create the column manager and update the grid container
this . dataviewContainer . setColumns ( columnData ) ;
2011-08-25 15:35:53 +02:00
} ,
2011-09-05 16:35:28 +02:00
_parseDataRow : function ( _row , _colData ) {
var columnWidgets = new Array ( this . columns . length ) ;
for ( var x = 0 ; x < columnWidgets . length ; x ++ )
{
if ( typeof _row [ x ] != "undefined" && _row [ x ] . widget )
{
columnWidgets [ x ] = _row [ x ] . widget ;
// Append the widget to this container
this . addChild ( _row [ x ] . widget ) ;
}
else
{
columnWidgets [ x ] = _row [ x ] . widget ;
}
}
this . dataviewContainer . rowProvider . setDataRowTemplate ( columnWidgets , this ) ;
} ,
2011-08-25 15:35:53 +02:00
_parseGrid : function ( _grid ) {
// Search the rows for a header-row - if one is found, parse it
for ( var y = 0 ; y < _grid . rowData . length ; y ++ )
{
if ( _grid . rowData [ y ] [ "class" ] == "th" )
{
2011-08-26 11:58:25 +02:00
this . _parseHeaderRow ( _grid . cells [ y ] , _grid . colData ) ;
2011-08-25 15:35:53 +02:00
}
2011-09-05 16:35:28 +02:00
else
{
this . _parseDataRow ( _grid . cells [ y ] , _grid . colData ) ;
}
2011-08-25 15:35:53 +02:00
}
} ,
/ * *
* When the template attribute is set , the nextmatch widget tries to load
* that template and to fetch the grid which is inside of it . It then calls
* /
set _template : function ( _value ) {
if ( ! this . template )
{
// Load the template
var template = et2 _createWidget ( "template" , { "id" : _value } , this ) ;
if ( ! template . proxiedTemplate )
{
et2 _debug ( "error" , "Error while loading definition template for" +
"nextmatch widget." ) ;
return ;
}
// Fetch the grid element and parse it
var definitionGrid = template . proxiedTemplate . getChildren ( ) [ 0 ] ;
if ( definitionGrid && definitionGrid instanceof et2 _grid )
{
this . _parseGrid ( definitionGrid ) ;
}
else
{
et2 _debug ( "error" , "Nextmatch widget expects a grid to be the " +
"first child of the defined template." ) ;
return ;
}
// Free the template again
template . free ( ) ;
// Call the "setNextmatch" function of all registered
// INextmatchHeader widgets.
this . iterateOver ( function ( _node ) {
_node . setNextmatch ( this ) ;
} , this , et2 _INextmatchHeader ) ;
}
} ,
getDOMNode : function ( _sender ) {
if ( _sender == this )
{
return this . div [ 0 ] ;
}
for ( var i = 0 ; i < this . columns . length ; i ++ )
{
if ( _sender == this . columns [ i ] . widget )
{
return this . dataviewContainer . getHeaderContainerNode ( i ) ;
}
}
return null ;
}
} ) ;
et2 _register _widget ( et2 _nextmatch , [ "nextmatch" ] ) ;
/ * *
* Classes for the nextmatch sortheaders etc .
* /
var et2 _nextmatch _header = et2 _baseWidget . extend ( et2 _INextmatchHeader , {
attributes : {
"label" : {
"name" : "Caption" ,
"type" : "string" ,
"description" : "Caption for the nextmatch header" ,
"translate" : true
}
} ,
init : function ( ) {
this . _super . apply ( this , arguments ) ;
this . labelNode = $j ( document . createElement ( "span" ) ) ;
this . nextmatch = null ;
this . setDOMNode ( this . labelNode [ 0 ] ) ;
} ,
destroy : function ( ) {
this . _super . apply ( this , arguments ) ;
} ,
/ * *
* Set nextmatch is the function which has to be implemented for the
* et2 _INextmatchHeader interface .
* /
setNextmatch : function ( _nextmatch ) {
this . nextmatch = _nextmatch ;
} ,
set _label : function ( _value ) {
this . label = _value ;
this . labelNode . text ( _value ) ;
}
} ) ;
et2 _register _widget ( et2 _nextmatch _header , [ 'nextmatch-header' ,
2011-08-25 17:54:15 +02:00
'nextmatch-customfilter' , 'nextmatch-customfields' ] ) ;
2011-08-25 15:35:53 +02:00
var et2 _nextmatch _sortheader = et2 _nextmatch _header . extend ( et2 _INextmatchSortable , {
init : function ( ) {
this . _super . apply ( this , arguments ) ;
this . sortmode = "none" ;
this . labelNode . addClass ( "nextmatch_sortheader none" ) ;
} ,
click : function ( ) {
if ( this . nextmatch && this . _super . apply ( this , arguments ) )
{
this . nextmatch . sortBy ( this . id ) ;
return true ;
}
return false ;
} ,
/ * *
* Function which implements the et2 _INextmatchSortable function .
* /
setSortmode : function ( _mode ) {
// Remove the last sortmode class and add the new one
this . labelNode . removeClass ( this . sortmode )
. addClass ( _mode ) ;
this . sortmode = _mode ;
}
} ) ;
et2 _register _widget ( et2 _nextmatch _sortheader , [ 'nextmatch-sortheader' ] ) ;
var et2 _nextmatch _filterheader = et2 _selectbox . extend ( et2 _INextmatchHeader , {
/ * *
* Set nextmatch is the function which has to be implemented for the
* et2 _INextmatchHeader interface .
* /
setNextmatch : function ( _nextmatch ) {
this . nextmatch = _nextmatch ;
}
} ) ;
2011-08-25 17:54:15 +02:00
et2 _register _widget ( et2 _nextmatch _filterheader , [ 'nextmatch-filterheader' ,
'nextmatch-accountfilter' ] ) ;
2011-08-25 15:35:53 +02:00