2012-05-24 17:45:29 +02:00
/ * *
2013-04-13 21:00:13 +02:00
* EGroupware eTemplate2 - JS History log
2012-05-24 17:45:29 +02:00
*
* @ license http : //opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @ package etemplate
* @ subpackage api
* @ link http : //www.egroupware.org
* @ author Nathan Gray
* @ copyright 2012 Nathan Gray
* /
/ * e g w : u s e s
2019-03-19 11:11:38 +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 ;
/ v e n d o r / b o w e r - a s s e t / j q u e r y - u i / j q u e r y - u i . j s ;
et2 _core _valueWidget ;
2012-05-24 17:45:29 +02:00
// Include the grid classes
2019-03-19 11:11:38 +01:00
et2 _dataview ;
2012-05-24 17:45:29 +02:00
* /
/ * *
* eTemplate history log widget displays a list of changes to the current record .
2014-01-21 15:39:51 +01:00
* The widget is encapsulated , and only needs the record ' s ID , and a map of
2012-05-24 19:53:23 +02:00
* fields : widgets for display .
*
* It defers its initialization until the tab that it ' s on is selected , to avoid
* wasting time if the user never looks at it .
2014-01-21 15:39:51 +01:00
*
2013-04-13 21:00:13 +02:00
* @ augments et2 _valueWidget
2012-05-24 17:45:29 +02:00
* /
2016-02-29 21:40:43 +01:00
var et2 _historylog = ( function ( ) { "use strict" ; return et2 _valueWidget . extend ( [ et2 _IDataProvider , et2 _IResizeable ] ,
2013-04-13 21:00:13 +02:00
{
2014-08-27 19:13:38 +02:00
createNamespace : true ,
2012-07-24 01:54:16 +02:00
attributes : {
"value" : {
2013-06-17 23:22:32 +02:00
"name" : "Value" ,
"type" : "any" ,
"description" : "Object {app: ..., id: ..., status-widgets: {}} where status-widgets is a map of fields to widgets used to display those fields"
2012-07-25 22:56:05 +02:00
} ,
"status_id" : {
2013-06-17 23:22:32 +02:00
"name" : "status_id" ,
2012-07-25 22:56:05 +02:00
"type" : "string" ,
2013-06-17 23:22:32 +02:00
"default" : "status" ,
"description" : "The history widget is traditionally named 'status'. If you name another widget in the same template 'status', you can use this attribute to re-name the history widget. "
2019-03-18 21:42:29 +01:00
} ,
"columns" : {
"name" : "columns" ,
"type" : "string" ,
"default" : "user_ts,owner,status,new_value,old_value" ,
"description" : "Columns to display. Default is user_ts,owner,status,new_value,old_value"
2012-07-24 01:54:16 +02:00
}
} ,
2012-07-25 22:56:05 +02:00
legacyOptions : [ "status_id" ] ,
2012-05-24 17:45:29 +02:00
columns : [
2012-05-30 20:54:23 +02:00
{ 'id' : 'user_ts' , caption : 'Date' , 'width' : '120px' , widget _type : 'date-time' } ,
2012-05-24 17:45:29 +02:00
{ 'id' : 'owner' , caption : 'User' , 'width' : '150px' , widget _type : 'select-account' } ,
{ 'id' : 'status' , caption : 'Changed' , 'width' : '120px' , widget _type : 'select' } ,
2014-08-27 19:13:38 +02:00
{ 'id' : 'new_value' , caption : 'New Value' , 'width' : '50%' } ,
{ 'id' : 'old_value' , caption : 'Old Value' , 'width' : '50%' }
2012-05-24 17:45:29 +02:00
] ,
2012-05-30 20:47:32 +02:00
TIMESTAMP : 0 , OWNER : 1 , FIELD : 2 , NEW _VALUE : 3 , OLD _VALUE : 4 ,
2014-01-21 15:39:51 +01:00
2013-04-13 21:00:13 +02:00
/ * *
* Constructor
2014-01-21 15:39:51 +01:00
*
2013-04-13 21:00:13 +02:00
* @ memberOf et2 _historylog
* /
2012-05-24 17:45:29 +02:00
init : function ( ) {
this . _super . apply ( this , arguments ) ;
2016-06-02 16:51:15 +02:00
this . div = jQuery ( document . createElement ( "div" ) )
2012-05-24 17:45:29 +02:00
. addClass ( "et2_historylog" ) ;
2016-06-02 16:51:15 +02:00
this . innerDiv = jQuery ( document . createElement ( "div" ) )
2012-05-24 17:45:29 +02:00
. appendTo ( this . div ) ;
} ,
2012-07-25 22:56:05 +02:00
set _status _id : function ( _new _id ) {
this . options . status _id = _new _id ;
} ,
2012-05-24 17:45:29 +02:00
doLoadingFinished : function ( ) {
this . _super . apply ( this , arguments ) ;
2012-05-24 19:53:23 +02:00
2012-05-24 17:45:29 +02:00
// Find the tab widget, if there is one
var tabs = this ;
do {
tabs = tabs . _parent ;
} while ( tabs != this . getRoot ( ) && tabs . _type != 'tabbox' ) ;
if ( tabs != this . getRoot ( ) )
{
// Find the tab index
for ( var i = 0 ; i < tabs . tabData . length ; i ++ )
{
// Find the tab
if ( tabs . tabData [ i ] . contentDiv . has ( this . div ) . length )
{
// Bind the action to when the tab is selected
var handler = function ( e ) {
e . data . div . unbind ( "click.history" ) ;
2015-05-13 17:01:30 +02:00
// Bind on click tap, because we need to update history size
// after a rezise happend and history log was not the active tab
e . data . div . bind ( "click.history" , { "history" : e . data . history , div : tabs . tabData [ i ] . flagDiv } , function ( e ) {
2019-03-21 21:39:39 +01:00
if ( e . data . history && e . data . history . dynheight )
2015-05-13 17:01:30 +02:00
{
2019-03-21 21:39:39 +01:00
e . data . history . dynheight . update ( function ( _w , _h )
{
e . data . history . dataview . resize ( _w , _h ) ;
} ) ;
}
2015-05-13 17:01:30 +02:00
} ) ;
2016-02-29 21:40:43 +01:00
2019-03-28 18:10:59 +01:00
if ( typeof e . data . history . dataview == "undefined" )
{
e . data . history . finishInit ( ) ;
if ( e . data . history . dynheight )
{
e . data . history . dynheight . update ( function ( _w , _h ) {
e . data . history . dataview . resize ( _w , _h ) ;
} ) ;
}
}
2012-05-24 17:45:29 +02:00
} ;
tabs . tabData [ i ] . flagDiv . bind ( "click.history" , { "history" : this , div : tabs . tabData [ i ] . flagDiv } , handler ) ;
2014-06-16 17:17:30 +02:00
// Display if history tab is selected
2015-05-21 12:38:04 +02:00
if ( i == tabs . get _active _tab ( ) && typeof this . dataview == 'undefined' )
2014-06-16 17:17:30 +02:00
{
tabs . tabData [ i ] . flagDiv . trigger ( "click.history" ) ;
}
2012-05-24 17:45:29 +02:00
break ;
}
}
}
else
{
this . finishInit ( ) ;
}
} ,
2012-05-24 19:53:23 +02:00
/ * *
* Finish initialization which was skipped until tab was selected
* /
2012-05-24 17:45:29 +02:00
finishInit : function ( ) {
2013-07-20 19:20:55 +02:00
// No point with no ID
if ( ! this . options . value || ! this . options . value . id )
{
return ;
}
2012-06-13 17:13:49 +02:00
this . _filters = {
record _id : this . options . value . id ,
appname : this . options . value . app ,
2016-10-12 17:48:09 +02:00
get _rows : 'EGroupware\\Api\\Storage\\History::get_rows'
2012-06-13 17:13:49 +02:00
} ;
2019-03-19 18:00:46 +01:00
// Warn if status_id is the same as history id, that causes overlap and missing labels
if ( this . options . status _id === this . id )
{
this . egw ( ) . debug ( "warn" , "status_id attribute should not be the same as historylog ID" ) ;
}
var _columns = typeof this . options . columns === "string" ?
this . options . columns . split ( ',' ) : this . options . columns ;
2012-05-24 17:45:29 +02:00
// Create the dynheight component which dynamically scales the inner
// container.
2013-11-28 19:43:44 +01:00
this . dynheight = new et2 _dynheight ( this . div . parent ( ) ,
2012-05-24 17:45:29 +02:00
this . innerDiv , 250
) ;
// Create the outer grid container
this . dataview = new et2 _dataview ( this . innerDiv , this . egw ( ) ) ;
2012-07-25 22:56:05 +02:00
var dataview _columns = [ ] ;
2019-03-19 18:00:46 +01:00
var _columns = typeof this . options . columns === "string" ?
this . options . columns . split ( ',' ) : this . options . columns ;
2012-07-25 22:56:05 +02:00
for ( var i = 0 ; i < this . columns . length ; i ++ )
{
2019-03-18 21:42:29 +01:00
dataview _columns [ i ] = {
"id" : this . columns [ i ] . id ,
"caption" : this . columns [ i ] . caption ,
"width" : this . columns [ i ] . width ,
2019-03-19 18:00:46 +01:00
"visibility" : _columns . indexOf ( this . columns [ i ] . id ) < 0 ?
2019-03-18 21:42:29 +01:00
ET2 _COL _VISIBILITY _INVISIBLE : ET2 _COL _VISIBILITY _VISIBLE
} ;
2012-07-25 22:56:05 +02:00
}
this . dataview . setColumns ( dataview _columns ) ;
2012-05-24 17:45:29 +02:00
// Create widgets for columns that stay the same, and set up varying widgets
this . createWidgets ( ) ;
// Create the gridview controller
var linkCallback = function ( ) { } ;
this . controller = new et2 _dataview _controller ( null , this . dataview . grid ,
this , this . rowCallback , linkCallback , this ,
null
) ;
2019-03-18 21:42:29 +01:00
var total = typeof this . options . value . total !== "undefined" ?
this . options . value . total : 0 ;
// This triggers an invalidate, which updates the grid
this . dataview . grid . setTotalCount ( total ) ;
// Insert any data sent from server, so invalidate finds data already
if ( this . options . value . rows && this . options . value . num _rows )
{
this . controller . loadInitialData (
this . options . value . dataStorePrefix ,
this . options . value . row _id ,
this . options . value . rows
) ;
// Remove, to prevent duplication
delete this . options . value . rows ;
// This triggers an invalidate, which updates the grid
this . dataview . grid . setTotalCount ( total ) ;
}
else
{
// Trigger the initial update
this . controller . update ( ) ;
}
2012-05-24 17:45:29 +02:00
// Write something inside the column headers
for ( var i = 0 ; i < this . columns . length ; i ++ )
{
2016-06-02 16:51:15 +02:00
jQuery ( this . dataview . getHeaderContainerNode ( i ) ) . text ( this . columns [ i ] . caption ) ;
2012-05-24 17:45:29 +02:00
}
// Register a resize callback
var self = this ;
2016-06-02 16:51:15 +02:00
jQuery ( window ) . on ( 'resize.' + this . options . value . app + this . options . value . id , function ( ) {
2015-05-21 12:38:04 +02:00
if ( self && typeof self . dynheight != 'undefined' ) self . dynheight . update ( function ( _w , _h ) {
2012-05-24 17:45:29 +02:00
self . dataview . resize ( _w , _h ) ;
} ) ;
} ) ;
} ,
/ * *
2014-01-21 15:39:51 +01:00
* Destroys all
2012-05-24 17:45:29 +02:00
* /
destroy : function ( ) {
2014-01-13 16:03:15 +01:00
// Unbind, if bound
if ( this . options . value && ! this . options . value . id )
{
2016-06-02 16:51:15 +02:00
jQuery ( window ) . off ( '.' + this . options . value . app + this . options . value . id ) ;
2014-01-13 16:03:15 +01:00
}
2014-01-21 15:39:51 +01:00
2012-05-24 17:45:29 +02:00
// Free the widgets
for ( var i = 0 ; i < this . columns . length ; i ++ )
{
if ( this . columns [ i ] . widget ) this . columns [ i ] . widget . destroy ( ) ;
}
for ( var key in this . fields )
{
this . fields [ key ] . widget . destroy ( ) ;
}
2012-05-30 01:05:26 +02:00
if ( this . diff ) this . diff . widget . destroy ( ) ;
2014-01-21 15:39:51 +01:00
2012-05-24 17:45:29 +02:00
// Free the grid components
2012-05-30 01:05:26 +02:00
if ( this . dataview ) this . dataview . free ( ) ;
if ( this . rowProvider ) this . rowProvider . free ( ) ;
if ( this . controller ) this . controller . free ( ) ;
if ( this . dynheight ) this . dynheight . free ( ) ;
2012-05-24 17:45:29 +02:00
this . _super . apply ( this , arguments ) ;
} ,
2012-07-09 21:04:32 +02:00
/ * *
* Create all needed widgets for new / o l d v a l u e s
* /
2012-05-24 17:45:29 +02:00
createWidgets : function ( ) {
// Constant widgets - first 3 columns
for ( var i = 0 ; i < this . columns . length ; i ++ )
{
if ( this . columns [ i ] . widget _type )
{
2012-07-25 22:56:05 +02:00
// Status ID is allowed to be remapped to something else. Only affects the widget ID though
var attrs = { 'readonly' : true , 'id' : ( i == this . FIELD ? this . options . status _id : this . columns [ i ] . id ) } ;
2012-05-24 17:45:29 +02:00
this . columns [ i ] . widget = et2 _createWidget ( this . columns [ i ] . widget _type , attrs , this ) ;
this . columns [ i ] . widget . transformAttributes ( attrs ) ;
2016-06-02 16:51:15 +02:00
this . columns [ i ] . nodes = jQuery ( this . columns [ i ] . widget . getDetachedNodes ( ) ) ;
2012-05-24 17:45:29 +02:00
}
}
2012-05-24 19:53:23 +02:00
// Add in handling for links
if ( typeof this . options . value [ 'status-widgets' ] [ '~link~' ] == 'undefined' )
{
2012-06-27 22:32:45 +02:00
this . columns [ this . FIELD ] . widget . optionValues [ '~link~' ] = this . egw ( ) . lang ( 'link' ) ;
2012-05-24 19:53:23 +02:00
this . options . value [ 'status-widgets' ] [ '~link~' ] = 'link' ;
}
2012-06-27 22:32:45 +02:00
// Add in handling for files
if ( typeof this . options . value [ 'status-widgets' ] [ '~file~' ] == 'undefined' )
{
this . columns [ this . FIELD ] . widget . optionValues [ '~file~' ] = this . egw ( ) . lang ( 'File' ) ;
this . options . value [ 'status-widgets' ] [ '~file~' ] = 'vfs' ;
}
2013-07-11 15:09:23 +02:00
// Add in handling for user-agent & action
if ( typeof this . options . value [ 'status-widgets' ] [ 'user_agent_action' ] == 'undefined' )
{
this . columns [ this . FIELD ] . widget . optionValues [ 'user_agent_action' ] = this . egw ( ) . lang ( 'User-agent & action' ) ;
}
2012-05-24 17:45:29 +02:00
// Per-field widgets - new value & old value
this . fields = { } ;
2012-05-30 20:47:32 +02:00
2012-07-25 22:56:05 +02:00
var labels = this . columns [ this . FIELD ] . widget . optionValues ;
2012-06-19 22:27:27 +02:00
// Custom fields - Need to create one that's all read-only for proper display
var cf _widget = et2 _createWidget ( 'customfields' , { 'readonly' : true } , this ) ;
cf _widget . loadFields ( ) ;
2012-06-19 23:49:58 +02:00
// Override this or it may damage the real values
cf _widget . getValue = function ( ) { return null ; } ;
2012-05-30 20:47:32 +02:00
for ( var key in cf _widget . widgets )
{
// Add label
labels [ cf _widget . prefix + key ] = cf _widget . options . customfields [ key ] . label ;
// If it doesn't support detached nodes, just treat it as text
if ( cf _widget . widgets [ key ] . getDetachedNodes )
{
var nodes = cf _widget . widgets [ key ] . getDetachedNodes ( ) ;
for ( var i = 0 ; i < nodes . length ; i ++ )
{
if ( nodes [ i ] == null ) nodes . splice ( i , 1 ) ;
}
2014-01-21 15:39:51 +01:00
2012-07-09 21:04:32 +02:00
// Save to use for each row
2012-05-30 20:47:32 +02:00
this . fields [ cf _widget . prefix + key ] = {
attrs : cf _widget . widgets [ key ] . options ,
widget : cf _widget . widgets [ key ] ,
nodes : jQuery ( nodes )
} ;
}
}
// Add all cf labels
this . columns [ this . FIELD ] . widget . set _select _options ( labels ) ;
// From app
2012-05-24 17:45:29 +02:00
for ( var key in this . options . value [ 'status-widgets' ] )
{
2019-03-20 20:58:11 +01:00
var attrs = jQuery . extend ( { 'readonly' : true , 'id' : key } , this . getArrayMgr ( 'modifications' ) . getEntry ( key ) ) ;
var field = attrs . type || this . options . value [ 'status-widgets' ] [ key ] ;
2012-07-09 18:57:19 +02:00
var options = null ;
2015-04-01 21:35:35 +02:00
var widget = null ;
2012-07-09 18:57:19 +02:00
if ( typeof field == 'object' )
{
2015-04-08 22:49:36 +02:00
// Check for multi-part statuses needing multiple widgets
2015-04-01 21:35:35 +02:00
var need _box = false ;
for ( var j in field )
{
2015-04-08 22:49:36 +02:00
// Require widget to be a valueWidget, to avoid invalid widgets
// (and template, which is a widget and an infolog todo status)
if ( et2 _registry [ field [ j ] ] && et2 _registry [ field [ j ] ] . prototype . instanceOf ( et2 _valueWidget ) )
2015-04-01 21:35:35 +02:00
{
need _box = true ;
break ;
}
}
if ( need _box )
{
// Multi-part value needs multiple widgets
widget = et2 _createWidget ( 'vbox' , attrs , this ) ;
for ( var i in field )
{
if ( typeof field [ i ] == 'object' )
{
attrs [ 'select_options' ] = field [ i ] ;
}
else
{
delete attrs [ 'select_options' ] ;
}
2019-03-19 22:59:31 +01:00
attrs . id = i ;
2015-04-01 21:35:35 +02:00
var child = et2 _createWidget ( typeof field [ i ] == 'string' ? field [ i ] : 'select' , attrs , widget ) ;
child . transformAttributes ( attrs ) ;
}
}
else
{
attrs [ 'select_options' ] = field ;
}
2012-07-09 18:57:19 +02:00
}
2012-07-09 21:04:32 +02:00
// Check for options after the type, ex: link-entry:infolog
2012-07-09 18:57:19 +02:00
else if ( field . indexOf ( ':' ) > 0 )
{
var options = field . split ( ':' ) ;
field = options . shift ( ) ;
}
2014-01-21 15:39:51 +01:00
2015-04-01 21:35:35 +02:00
if ( widget == null )
{
widget = et2 _createWidget ( typeof field == 'string' ? field : 'select' , attrs , this ) ;
}
2012-07-09 21:04:32 +02:00
2019-03-19 18:00:46 +01:00
if ( ! widget . instanceOf ( et2 _IDetachedDOM ) )
{
this . egw ( ) . debug ( "warn" , this , "Invalid widget " + field + " for " + key + ". Status widgets must implement et2_IDetachedDOM." ) ;
continue ;
}
2012-07-09 21:04:32 +02:00
// Parse / set legacy options
2012-07-09 18:57:19 +02:00
if ( options )
{
var mgr = this . getArrayMgr ( "content" ) ;
for ( var i = 0 ; i < options . length && i < widget . legacyOptions . length ; i ++ )
{
// Not set
if ( options [ i ] == "" ) continue ;
2012-07-09 21:04:32 +02:00
2012-07-09 18:57:19 +02:00
var attr = widget . attributes [ widget . legacyOptions [ i ] ] ;
var attrValue = options [ i ] ;
// If the attribute is marked as boolean, parse the
// expression as bool expression.
if ( attr . type == "boolean" )
{
attrValue = mgr . parseBoolExpression ( attrValue ) ;
}
else
{
attrValue = mgr . expandName ( attrValue ) ;
}
attrs [ widget . legacyOptions [ i ] ] = attrValue ;
if ( typeof widget [ 'set_' + widget . legacyOptions [ i ] ] == 'function' )
{
widget [ 'set_' + widget . legacyOptions [ i ] ] . call ( widget , attrValue ) ;
}
else
{
widget . options [ widget . legacyOptions [ i ] ] = attrValue ;
}
}
}
2012-07-05 21:59:42 +02:00
if ( widget . instanceOf ( et2 _selectbox ) ) widget . options . multiple = true ;
2012-05-24 17:45:29 +02:00
widget . transformAttributes ( attrs ) ;
2012-07-09 21:04:32 +02:00
// Save to use for each row
2015-04-01 21:35:35 +02:00
var nodes = widget . _children . length ? [ ] : jQuery ( widget . getDetachedNodes ( ) ) ;
for ( var i = 0 ; i < widget . _children . length ; i ++ )
{
nodes . push ( jQuery ( widget . _children [ i ] . getDetachedNodes ( ) ) ) ;
}
2012-05-24 17:45:29 +02:00
this . fields [ key ] = {
attrs : attrs ,
widget : widget ,
2015-04-01 21:35:35 +02:00
nodes : nodes
2012-05-24 17:45:29 +02:00
} ;
}
// Widget for text diffs
var diff = et2 _createWidget ( 'diff' , { } , this ) ;
this . diff = {
widget : diff ,
nodes : jQuery ( diff . getDetachedNodes ( ) )
} ;
} ,
getDOMNode : function ( _sender ) {
2015-04-01 21:35:35 +02:00
if ( _sender == this )
{
return this . div [ 0 ] ;
}
for ( var i = 0 ; i < this . columns . length ; i ++ )
{
if ( _sender == this . columns [ i ] . widget )
{
return this . dataview . getHeaderContainerNode ( i ) ;
}
}
2012-05-24 17:45:29 +02:00
return null ;
} ,
dataFetch : function ( _queriedRange , _callback , _context ) {
2013-07-17 11:36:38 +02:00
// Skip getting data if there's no ID
if ( ! this . value . id ) return ;
2014-01-21 15:39:51 +01:00
2017-12-01 12:04:31 +01:00
// Set num_rows to fetch via nextmatch
if ( this . options . value [ 'num_rows' ] )
_queriedRange [ 'num_rows' ] = this . options . value [ 'num_rows' ] ;
2012-05-24 17:45:29 +02:00
// Pass the fetch call to the API
2013-07-17 11:36:38 +02:00
this . egw ( ) . dataFetch (
2012-05-24 17:45:29 +02:00
this . getInstanceManager ( ) . etemplate _exec _id ,
_queriedRange ,
this . _filters ,
this . id ,
_callback ,
2014-10-06 22:10:07 +02:00
_context ,
[ ]
2012-05-24 17:45:29 +02:00
) ;
} ,
// Needed by interface
dataRegisterUID : function ( _uid , _callback , _context ) {
this . egw ( ) . dataRegisterUID ( _uid , _callback , _context , this . getInstanceManager ( ) . etemplate _exec _id ,
this . id ) ;
} ,
dataUnregisterUID : function ( _uid , _callback , _context ) {
// Needed by interface
} ,
/ * *
* The row callback gets called by the gridview controller whenever
* the actual DOM - Nodes for a node with the given data have to be
* created .
2016-02-29 21:40:43 +01:00
*
* @ param { type } _data
* @ param { type } _row
* @ param { type } _idx
* @ param { type } _entry
2012-05-24 17:45:29 +02:00
* /
rowCallback : function ( _data , _row , _idx , _entry ) {
var tr = _row . getDOMNode ( ) ;
jQuery ( tr ) . attr ( "valign" , "top" ) ;
var row = this . dataview . rowProvider . getPrototype ( "default" ) ;
var self = this ;
2016-06-02 16:51:15 +02:00
jQuery ( "div" , row ) . each ( function ( i ) {
2012-05-24 17:45:29 +02:00
var nodes = [ ] ;
var widget = self . columns [ i ] . widget ;
2018-06-06 23:51:46 +02:00
var value = _data [ self . columns [ i ] . id ] ;
if ( self . OWNER === i && _data [ 'share_email' ] )
{
// Show share email instead of owner
widget = undefined ;
value = _data [ 'share_email' ] ;
}
2019-02-28 23:15:26 +01:00
// Get widget from list, unless it needs a diff widget
2019-03-01 18:30:53 +01:00
if ( typeof widget == 'undefined' && typeof self . fields [ _data . status ] != 'undefined' && ( i < self . NEW _VALUE ||
i >= self . NEW _VALUE && ! self . _needsDiffWidget ( _data [ 'status' ] , _data [ self . columns [ self . OLD _VALUE ] . id ] ) ) )
2012-05-24 17:45:29 +02:00
{
widget = self . fields [ _data . status ] . widget ;
2015-04-01 21:35:35 +02:00
if ( ! widget . _children . length )
{
nodes = self . fields [ _data . status ] . nodes . clone ( ) ;
}
for ( var j = 0 ; j < widget . _children . length ; j ++ )
{
nodes . push ( self . fields [ _data . status ] . nodes [ j ] . clone ( ) ) ;
}
2012-05-24 17:45:29 +02:00
}
else if ( widget )
{
nodes = self . columns [ i ] . nodes . clone ( ) ;
}
2014-08-27 19:13:38 +02:00
else if ( (
// Already parsed & cached
typeof _data [ self . columns [ self . NEW _VALUE ] . id ] == "object" &&
2019-03-19 11:11:38 +01:00
typeof _data [ self . columns [ self . NEW _VALUE ] . id ] != "undefined" &&
_data [ self . columns [ self . NEW _VALUE ] . id ] !== null ) || // typeof null === 'object'
2014-08-27 19:13:38 +02:00
// Large old value
self . _needsDiffWidget ( _data [ 'status' ] , _data [ self . columns [ self . OLD _VALUE ] . id ] ) ||
// Large new value
2012-06-26 01:38:26 +02:00
self . _needsDiffWidget ( _data [ 'status' ] , _data [ self . columns [ self . NEW _VALUE ] . id ] ) )
2012-05-24 17:45:29 +02:00
{
2012-05-24 19:53:23 +02:00
// Large text value - span both columns, and show a nice diff
2012-05-24 17:45:29 +02:00
var jthis = jQuery ( this ) ;
2019-02-27 17:05:07 +01:00
if ( i === self . NEW _VALUE )
2012-05-24 17:45:29 +02:00
{
2012-06-05 17:48:57 +02:00
// Diff widget
2012-05-24 17:45:29 +02:00
widget = self . diff . widget ;
nodes = self . diff . nodes . clone ( ) ;
// Skip column 4
jthis . parents ( "td" ) . attr ( "colspan" , 2 )
. css ( "border-right" , "none" ) ;
2012-06-26 01:38:26 +02:00
jthis . css ( "width" , ( self . dataview . columnMgr . columnWidths [ i ] + self . dataview . columnMgr . columnWidths [ i + 1 ] - 10 ) + 'px' ) ;
2012-05-24 17:45:29 +02:00
if ( widget ) widget . setDetachedAttributes ( nodes , {
2018-06-06 23:51:46 +02:00
value : value ,
2012-05-24 17:45:29 +02:00
label : jthis . parents ( "td" ) . prev ( ) . text ( )
} ) ;
2012-06-26 01:38:26 +02:00
2012-05-24 17:45:29 +02:00
// Skip column 4
2012-06-26 01:38:26 +02:00
jthis . parents ( "td" ) . next ( ) . remove ( ) ;
2012-05-24 17:45:29 +02:00
}
}
else
{
2012-05-24 19:53:23 +02:00
// No widget fallback - display actual value
2019-03-19 11:11:38 +01:00
nodes = jQuery ( '<span>' ) . text ( value === null ? '' : value ) ;
2012-05-24 17:45:29 +02:00
}
2015-04-01 21:35:35 +02:00
if ( widget )
{
if ( widget . _children . length )
{
// Multi-part values
2016-06-02 16:51:15 +02:00
var box = jQuery ( widget . getDOMNode ( ) ) . clone ( ) ;
2015-04-01 21:35:35 +02:00
for ( var j = 0 ; j < widget . _children . length ; j ++ )
{
2019-03-19 22:59:31 +01:00
var id = widget . _children [ j ] . id ;
2019-03-20 17:29:58 +01:00
var widget _value = value ? value [ id ] || "" : "" ;
widget . _children [ j ] . setDetachedAttributes ( nodes [ j ] , { value : widget _value } ) ;
2015-04-01 21:35:35 +02:00
box . append ( nodes [ j ] ) ;
}
nodes = box ;
}
else
{
2018-06-06 23:51:46 +02:00
widget . setDetachedAttributes ( nodes , { value : value } ) ;
2015-04-01 21:35:35 +02:00
}
}
2016-06-02 16:51:15 +02:00
jQuery ( this ) . append ( nodes ) ;
2012-05-24 17:45:29 +02:00
} ) ;
2016-06-02 16:51:15 +02:00
jQuery ( tr ) . append ( row . children ( ) ) ;
2012-05-24 17:45:29 +02:00
return tr ;
} ,
/ * *
* How to tell if the row needs a diff widget or not
2016-02-29 21:40:43 +01:00
*
* @ param { string } columnName
* @ param { string } value
* @ returns { Boolean }
2012-05-24 17:45:29 +02:00
* /
_needsDiffWidget : function ( columnName , value ) {
2019-03-20 17:29:58 +01:00
if ( typeof value !== "string" && value )
2012-06-26 01:38:26 +02:00
{
2014-01-21 15:39:51 +01:00
this . egw ( ) . debug ( "warn" , "Crazy diff value" , value ) ;
2012-06-26 01:38:26 +02:00
return false ;
}
2019-03-19 11:11:38 +01:00
return value === '***diff***' ;
2012-05-24 17:45:29 +02:00
} ,
2015-02-25 17:30:49 +01:00
resize : function ( _height )
{
if ( typeof this . options != 'undefined' && _height
&& typeof this . options . resize _ratio != 'undefined' )
{
// apply the ratio
_height = ( this . options . resize _ratio != '' ) ? _height * this . options . resize _ratio : _height ;
if ( _height != 0 )
{
2015-05-13 17:01:30 +02:00
// 250px is the default value for history widget
// if it's not loaded yet and window is resized
// then add the default height with excess_height
if ( this . div . height ( ) == 0 ) _height += 250 ;
2015-02-25 17:30:49 +01:00
this . div . height ( this . div . height ( ) + _height ) ;
2016-02-29 21:40:43 +01:00
2015-05-13 17:01:30 +02:00
// trigger the history registered resize
// in order to update the height with new value
2015-05-21 12:40:04 +02:00
this . div . trigger ( 'resize.' + this . options . value . app + this . options . value . id ) ;
2015-02-25 17:30:49 +01:00
}
}
2019-02-28 23:15:26 +01:00
// Resize diff widgets to match new space
if ( this . dataview )
{
var columns = this . dataview . getColumnMgr ( ) . columnWidths ;
2019-03-01 18:53:40 +01:00
jQuery ( '.et2_diff' , this . div ) . parent ( ) . width ( columns [ this . NEW _VALUE ] + columns [ this . OLD _VALUE ] ) ;
2019-02-28 23:15:26 +01:00
}
2015-02-25 17:30:49 +01:00
}
2016-02-29 21:40:43 +01:00
} ) ; } ) . call ( this ) ;
2012-05-24 17:45:29 +02:00
et2 _register _widget ( et2 _historylog , [ 'historylog' ] ) ;