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
2021-06-07 17:33:53 +02:00
* @ link https : //www.egroupware.org
2012-05-24 17:45:29 +02:00
* @ author Nathan Gray
* @ copyright 2012 Nathan Gray
* /
2021-06-07 17:33:53 +02:00
import { et2 _createWidget , et2 _register _widget , et2 _registry } from "./et2_core_widget" ;
import { ClassWithAttributes } from "./et2_core_inheritance" ;
import { et2 _valueWidget } from "./et2_core_valueWidget" ;
import { et2 _dataview } from "./et2_dataview" ;
import { et2 _dataview _column } from "./et2_dataview_model_columns" ;
import { et2 _dataview _controller } from "./et2_dataview_controller" ;
import { et2 _diff } from "./et2_widget_diff" ;
import { et2 _IDetachedDOM } from "./et2_core_interfaces" ;
import { et2 _dynheight } from "./et2_widget_dynheight" ;
import { et2 _selectbox } from "./et2_widget_selectbox" ;
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
* /
2021-06-07 17:33:53 +02:00
export class et2 _historylog extends et2 _valueWidget {
2020-02-11 23:37:33 +01:00
/ * *
* Constructor
*
* @ memberOf et2 _historylog
* /
2021-06-07 17:33:53 +02:00
constructor ( _parent , _attrs , _child ) {
super ( _parent , _attrs , ClassWithAttributes . extendAttributes ( et2 _historylog . _attributes , _child || { } ) ) ;
this . div = jQuery ( document . createElement ( "div" ) )
2020-02-11 23:37:33 +01:00
. addClass ( "et2_historylog" ) ;
2021-06-07 17:33:53 +02:00
this . innerDiv = jQuery ( document . createElement ( "div" ) )
. appendTo ( this . div ) ;
2020-02-11 23:37:33 +01:00
}
2021-06-07 17:33:53 +02:00
set _status _id ( _new _id ) {
2020-02-11 23:37:33 +01:00
this . options . status _id = _new _id ;
2021-06-07 17:33:53 +02:00
}
doLoadingFinished ( ) {
super . doLoadingFinished ( ) ;
2020-02-11 23:37:33 +01:00
// Find the tab
2021-06-07 17:33:53 +02:00
let tab = this . get _tab _info ( ) ;
2020-02-11 23:37:33 +01:00
if ( tab ) {
// Bind the action to when the tab is selected
2021-06-07 17:33:53 +02:00
const handler = function ( e ) {
2020-02-11 23:37:33 +01:00
e . data . div . unbind ( "click.history" ) ;
// 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 : tab . flagDiv } , function ( e ) {
if ( e . data . history && e . data . history . dynheight ) {
e . data . history . dynheight . update ( function ( _w , _h ) {
e . data . history . dataview . resize ( _w , _h ) ;
} ) ;
}
} ) ;
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 ) ;
} ) ;
}
}
} ;
tab . flagDiv . bind ( "click.history" , { "history" : this , div : tab . flagDiv } , handler ) ;
// Display if history tab is selected
if ( tab . contentDiv . is ( ':visible' ) && typeof this . dataview == 'undefined' ) {
tab . flagDiv . trigger ( "click.history" ) ;
}
}
else {
this . finishInit ( ) ;
}
return true ;
2021-06-07 17:33:53 +02:00
}
_createNamespace ( ) {
2020-02-11 23:37:33 +01:00
return true ;
2021-06-07 17:33:53 +02:00
}
2020-02-11 23:37:33 +01:00
/ * *
* Finish initialization which was skipped until tab was selected
* /
2021-06-07 17:33:53 +02:00
finishInit ( ) {
2020-02-11 23:37:33 +01:00
// No point with no ID
if ( ! this . options . value || ! this . options . value . id ) {
return ;
}
this . _filters = {
record _id : this . options . value . id ,
appname : this . options . value . app ,
get _rows : this . options . get _rows
} ;
// 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" ) ;
}
// Create the dynheight component which dynamically scales the inner
// container.
this . div . parentsUntil ( '.et2_tabs' ) . height ( '100%' ) ;
2021-06-07 17:33:53 +02:00
const parent = this . get _tab _info ( ) ;
2020-02-11 23:37:33 +01:00
this . dynheight = new et2 _dynheight ( parent ? parent . contentDiv : this . div . parent ( ) , this . innerDiv , 250 ) ;
// Create the outer grid container
2021-06-07 17:33:53 +02:00
this . dataview = new et2 _dataview ( this . innerDiv , this . egw ( ) ) ;
const dataview _columns = [ ] ;
let _columns = typeof this . options . columns === "string" ?
2020-02-11 23:37:33 +01:00
this . options . columns . split ( ',' ) : this . options . columns ;
for ( var i = 0 ; i < et2 _historylog . columns . length ; i ++ ) {
dataview _columns [ i ] = {
"id" : et2 _historylog . columns [ i ] . id ,
"caption" : et2 _historylog . columns [ i ] . caption ,
"width" : et2 _historylog . columns [ i ] . width ,
"visibility" : _columns . indexOf ( et2 _historylog . columns [ i ] . id ) < 0 ?
2021-06-07 17:33:53 +02:00
et2 _dataview _column . ET2 _COL _VISIBILITY _INVISIBLE : et2 _dataview _column . ET2 _COL _VISIBILITY _VISIBLE
2020-02-11 23:37:33 +01:00
} ;
}
this . dataview . setColumns ( dataview _columns ) ;
// Create widgets for columns that stay the same, and set up varying widgets
this . createWidgets ( ) ;
// Create the gridview controller
2021-06-07 17:33:53 +02:00
const linkCallback = function ( ) {
2020-02-12 23:18:10 +01:00
} ;
2021-06-07 17:33:53 +02:00
this . controller = new et2 _dataview _controller ( null , this . dataview . grid ) ;
2020-02-11 23:37:33 +01:00
this . controller . setContext ( this ) ;
this . controller . setDataProvider ( this ) ;
this . controller . setLinkCallback ( linkCallback ) ;
this . controller . setRowCallback ( this . rowCallback ) ;
this . controller . setActionObjectManager ( null ) ;
2021-06-07 17:33:53 +02:00
const total = typeof this . options . value . total !== "undefined" ?
2020-02-11 23:37:33 +01:00
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 ( ) ;
}
// Write something inside the column headers
for ( var i = 0 ; i < et2 _historylog . columns . length ; i ++ ) {
jQuery ( this . dataview . getHeaderContainerNode ( i ) ) . text ( et2 _historylog . columns [ i ] . caption ) ;
}
// Register a resize callback
jQuery ( window ) . on ( 'resize.' + this . options . value . app + this . options . value . id , function ( ) {
2020-09-11 21:11:52 +02:00
if ( this && typeof this . dynheight != 'undefined' )
this . dynheight . update ( function ( _w , _h ) {
this . dataview . resize ( _w , _h ) ;
} . bind ( this ) ) ;
} . bind ( this ) ) ;
2021-06-07 17:33:53 +02:00
}
2020-02-11 23:37:33 +01:00
/ * *
* Destroys all
* /
2021-06-07 17:33:53 +02:00
destroy ( ) {
2020-02-11 23:37:33 +01:00
// Unbind, if bound
if ( this . options . value && ! this . options . value . id ) {
jQuery ( window ) . off ( '.' + this . options . value . app + this . options . value . id ) ;
}
// Free the widgets
2021-06-07 17:33:53 +02:00
for ( let i = 0 ; i < et2 _historylog . columns . length ; i ++ ) {
2020-02-11 23:37:33 +01:00
if ( et2 _historylog . columns [ i ] . widget )
et2 _historylog . columns [ i ] . widget . destroy ( ) ;
}
2021-06-07 17:33:53 +02:00
for ( let key in this . fields ) {
2020-02-11 23:37:33 +01:00
this . fields [ key ] . widget . destroy ( ) ;
}
// Free the grid components
if ( this . dataview )
this . dataview . destroy ( ) ;
if ( this . controller )
this . controller . destroy ( ) ;
if ( this . dynheight )
2020-02-12 22:49:22 +01:00
this . dynheight . destroy ( ) ;
2021-06-07 17:33:53 +02:00
super . destroy ( ) ;
}
2020-02-11 23:37:33 +01:00
/ * *
* Create all needed widgets for new / o l d v a l u e s
* /
2021-06-07 17:33:53 +02:00
createWidgets ( ) {
2020-02-11 23:37:33 +01:00
// Constant widgets - first 3 columns
2021-06-07 17:33:53 +02:00
for ( let i = 0 ; i < et2 _historylog . columns . length ; i ++ ) {
if ( et2 _historylog . columns [ i ] . widget _type ) {
2020-02-11 23:37:33 +01:00
// Status ID is allowed to be remapped to something else. Only affects the widget ID though
2021-06-07 17:33:53 +02:00
var attrs = { 'readonly' : true , 'id' : ( i == et2 _historylog . FIELD ? this . options . status _id : et2 _historylog . columns [ i ] . id ) } ;
et2 _historylog . columns [ i ] . widget = et2 _createWidget ( et2 _historylog . columns [ i ] . widget _type , attrs , this ) ;
et2 _historylog . columns [ i ] . widget . transformAttributes ( attrs ) ;
et2 _historylog . columns [ i ] . nodes = jQuery ( et2 _historylog . columns [ i ] . widget . getDetachedNodes ( ) ) ;
2020-02-11 23:37:33 +01:00
}
}
// Add in handling for links
if ( typeof this . options . value [ 'status-widgets' ] [ '~link~' ] == 'undefined' ) {
et2 _historylog . columns [ et2 _historylog . FIELD ] . widget . optionValues [ '~link~' ] = this . egw ( ) . lang ( 'link' ) ;
this . options . value [ 'status-widgets' ] [ '~link~' ] = 'link' ;
}
// Add in handling for files
if ( typeof this . options . value [ 'status-widgets' ] [ '~file~' ] == 'undefined' ) {
et2 _historylog . columns [ et2 _historylog . FIELD ] . widget . optionValues [ '~file~' ] = this . egw ( ) . lang ( 'File' ) ;
this . options . value [ 'status-widgets' ] [ '~file~' ] = 'vfs' ;
}
// Add in handling for user-agent & action
if ( typeof this . options . value [ 'status-widgets' ] [ 'user_agent_action' ] == 'undefined' ) {
et2 _historylog . columns [ et2 _historylog . FIELD ] . widget . optionValues [ 'user_agent_action' ] = this . egw ( ) . lang ( 'User-agent & action' ) ;
}
// Per-field widgets - new value & old value
this . fields = { } ;
2021-06-07 17:33:53 +02:00
let labels = et2 _historylog . columns [ et2 _historylog . FIELD ] . widget . optionValues ;
2020-02-11 23:37:33 +01:00
// Custom fields - Need to create one that's all read-only for proper display
2021-06-07 17:33:53 +02:00
let cf _widget = et2 _createWidget ( 'customfields' , { 'readonly' : true } , this ) ;
2020-02-11 23:37:33 +01:00
cf _widget . loadFields ( ) ;
// Override this or it may damage the real values
cf _widget . getValue = function ( ) { return null ; } ;
2021-06-07 17:33:53 +02:00
for ( let key in cf _widget . widgets ) {
2020-02-11 23:37:33 +01:00
// Add label
2021-06-07 17:33:53 +02:00
labels [ cf _widget . prefix + key ] = cf _widget . options . customfields [ key ] . label ;
2020-02-11 23:37:33 +01:00
// If it doesn't support detached nodes, just treat it as text
2021-06-07 17:33:53 +02:00
if ( cf _widget . widgets [ key ] . getDetachedNodes ) {
var nodes = cf _widget . widgets [ key ] . getDetachedNodes ( ) ;
2020-02-11 23:37:33 +01:00
for ( var i = 0 ; i < nodes . length ; i ++ ) {
if ( nodes [ i ] == null )
nodes . splice ( i , 1 ) ;
}
// Save to use for each row
2021-06-07 17:33:53 +02:00
this . fields [ cf _widget . prefix + key ] = {
attrs : cf _widget . widgets [ key ] . options ,
widget : cf _widget . widgets [ key ] ,
2020-02-11 23:37:33 +01:00
nodes : jQuery ( nodes )
} ;
}
}
// Add all cf labels
et2 _historylog . columns [ et2 _historylog . FIELD ] . widget . set _select _options ( labels ) ;
// From app
for ( var key in this . options . value [ 'status-widgets' ] ) {
2021-06-07 17:33:53 +02:00
let attrs = jQuery . extend ( { 'readonly' : true , 'id' : key } , this . getArrayMgr ( 'modifications' ) . getEntry ( key ) ) ;
const field = attrs . type || this . options . value [ 'status-widgets' ] [ key ] ;
const options = null ;
const widget = this . _create _widget ( key , field , attrs , options ) ;
2020-02-11 23:37:33 +01:00
if ( widget === null ) {
continue ;
}
if ( widget . instanceOf ( et2 _selectbox ) )
widget . options . multiple = true ;
2021-06-07 17:33:53 +02:00
widget . transformAttributes ( attrs ) ;
2020-02-11 23:37:33 +01:00
// Save to use for each row
2021-06-07 17:33:53 +02:00
let nodes = widget . _children . length ? [ ] : jQuery ( widget . getDetachedNodes ( ) ) ;
for ( let i = 0 ; i < widget . _children . length ; i ++ ) {
2020-02-12 23:18:10 +01:00
// @ts-ignore
2021-06-07 17:33:53 +02:00
nodes . push ( jQuery ( widget . _children [ i ] . getDetachedNodes ( ) ) ) ;
2020-02-11 23:37:33 +01:00
}
this . fields [ key ] = {
2021-06-07 17:33:53 +02:00
attrs : attrs ,
2020-02-11 23:37:33 +01:00
widget : widget ,
2021-06-07 17:33:53 +02:00
nodes : nodes
2020-02-11 23:37:33 +01:00
} ;
}
// Widget for text diffs
2021-06-07 17:33:53 +02:00
const diff = et2 _createWidget ( 'diff' , { } , this ) ;
2020-02-11 23:37:33 +01:00
this . diff = {
2020-02-12 22:49:22 +01:00
// @ts-ignore
2020-02-11 23:37:33 +01:00
widget : diff ,
nodes : jQuery ( diff . getDetachedNodes ( ) )
} ;
2021-06-07 17:33:53 +02:00
}
_create _widget ( key , field , attrs , options ) {
let widget = null ;
2020-02-11 23:37:33 +01:00
// If field has multiple parts (is object) and isn't an obvious select box
if ( typeof field === 'object' ) {
// Check for multi-part statuses needing multiple widgets
2021-06-07 17:33:53 +02:00
let need _box = false ; //!this.getArrayMgr('sel_options').getEntry(key);
for ( let j in field ) {
2020-02-11 23:37:33 +01:00
// Require widget to be a widget, to avoid invalid widgets
// (and template, which is a widget and an infolog todo status)
if ( et2 _registry [ field [ j ] ] && [ 'template' ] . indexOf ( field [ j ] ) < 0 ) // && (et2_registry[field[j]].prototype.instanceOf(et2_valueWidget))
{
need _box = true ;
break ;
}
}
if ( need _box ) {
// Multi-part value needs multiple widgets
widget = et2 _createWidget ( 'vbox' , attrs , this ) ;
for ( var i in field ) {
2021-06-07 17:33:53 +02:00
let type = field [ i ] ;
const child _attrs = jQuery . extend ( { } , attrs ) ;
2020-02-11 23:37:33 +01:00
if ( typeof type === 'object' ) {
child _attrs [ 'select_options' ] = field [ i ] ;
type = 'select' ;
}
else {
delete child _attrs [ 'select_options' ] ;
}
child _attrs . id = i ;
2021-06-07 17:33:53 +02:00
const child = this . _create _widget ( i , type , child _attrs , options ) ;
2020-02-11 23:37:33 +01:00
widget . addChild ( child ) ;
child . transformAttributes ( child _attrs ) ;
}
}
else {
attrs [ 'select_options' ] = field ;
}
}
// Check for options after the type, ex: link-entry:infolog
else if ( field . indexOf ( ':' ) > 0 ) {
var options = field . split ( ':' ) ;
field = options . shift ( ) ;
}
if ( widget === null ) {
widget = et2 _createWidget ( typeof field === 'string' ? field : 'select' , attrs , this ) ;
}
if ( ! widget . instanceOf ( et2 _IDetachedDOM ) ) {
this . egw ( ) . debug ( "warn" , this , "Invalid widget " + field + " for " + key + ". Status widgets must implement et2_IDetachedDOM." ) ;
return null ;
}
// Parse / set legacy options
if ( options ) {
2021-06-07 17:33:53 +02:00
const mgr = this . getArrayMgr ( "content" ) ;
let legacy = widget . constructor . legacyOptions || [ ] ;
for ( let i = 0 ; i < options . length && i < legacy . length ; i ++ ) {
2020-02-11 23:37:33 +01:00
// Not set
2021-06-07 17:33:53 +02:00
if ( options [ i ] === "" )
2020-02-11 23:37:33 +01:00
continue ;
2021-06-07 17:33:53 +02:00
const attr = widget . attributes [ legacy [ i ] ] ;
let attrValue = options [ i ] ;
2020-02-11 23:37:33 +01:00
// 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 ) ;
}
2021-06-07 17:33:53 +02:00
attrs [ legacy [ i ] ] = attrValue ;
if ( typeof widget [ 'set_' + legacy [ i ] ] === 'function' ) {
widget [ 'set_' + legacy [ i ] ] . call ( widget , attrValue ) ;
2020-02-11 23:37:33 +01:00
}
else {
2021-06-07 17:33:53 +02:00
widget . options [ legacy [ i ] ] = attrValue ;
2020-02-11 23:37:33 +01:00
}
}
}
return widget ;
2021-06-07 17:33:53 +02:00
}
getDOMNode ( _sender ) {
2020-02-11 23:37:33 +01:00
if ( _sender == this ) {
return this . div [ 0 ] ;
}
2021-06-07 17:33:53 +02:00
for ( let i = 0 ; i < et2 _historylog . columns . length ; i ++ ) {
2020-02-11 23:37:33 +01:00
if ( _sender == et2 _historylog . columns [ i ] . widget ) {
return this . dataview . getHeaderContainerNode ( i ) ;
}
}
return null ;
2021-06-07 17:33:53 +02:00
}
dataFetch ( _queriedRange , _callback , _context ) {
2020-02-11 23:37:33 +01:00
// Skip getting data if there's no ID
if ( ! this . value . id )
return ;
// Set num_rows to fetch via nextmatch
if ( this . options . value [ 'num_rows' ] )
_queriedRange [ 'num_rows' ] = this . options . value [ 'num_rows' ] ;
2021-06-07 17:33:53 +02:00
const historylog = this ;
2020-02-11 23:37:33 +01:00
// Pass the fetch call to the API
this . egw ( ) . dataFetch ( this . getInstanceManager ( ) . etemplate _exec _id , _queriedRange , this . _filters , this . id , function ( _response ) {
_callback . call ( this , _response ) ;
} , _context , [ ] ) ;
2021-06-07 17:33:53 +02:00
}
2020-02-11 23:37:33 +01:00
// Needed by interface
2021-06-07 17:33:53 +02:00
dataRegisterUID ( _uid , _callback , _context ) {
2020-02-11 23:37:33 +01:00
this . egw ( ) . dataRegisterUID ( _uid , _callback , _context , this . getInstanceManager ( ) . etemplate _exec _id , this . id ) ;
2021-06-07 17:33:53 +02:00
}
dataUnregisterUID ( _uid , _callback , _context ) {
2020-02-11 23:37:33 +01:00
// Needed by interface
2021-06-07 17:33:53 +02:00
}
2020-02-11 23:37:33 +01:00
/ * *
* 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 .
*
* @ param { type } _data
* @ param { type } _row
* @ param { type } _idx
* @ param { type } _entry
* /
2021-06-07 17:33:53 +02:00
rowCallback ( _data , _row , _idx , _entry ) {
let tr = _row . getDOMNode ( ) ;
2020-02-11 23:37:33 +01:00
jQuery ( tr ) . attr ( "valign" , "top" ) ;
2021-06-07 17:33:53 +02:00
let row = this . dataview . rowProvider . getPrototype ( "default" ) ;
let self = this ;
2020-02-11 23:37:33 +01:00
jQuery ( "div" , row ) . each ( function ( i ) {
2021-06-07 17:33:53 +02:00
let nodes = [ ] ;
let widget = et2 _historylog . columns [ i ] . widget ;
let value = _data [ et2 _historylog . columns [ i ] . id ] ;
2020-02-11 23:37:33 +01:00
if ( et2 _historylog . OWNER === i && _data [ 'share_email' ] ) {
// Show share email instead of owner
widget = undefined ;
value = _data [ 'share_email' ] ;
}
// Get widget from list, unless it needs a diff widget
2020-06-16 18:58:03 +02:00
if ( ( typeof widget == 'undefined' || widget == null ) && typeof self . fields [ _data . status ] != 'undefined' && ( i < et2 _historylog . NEW _VALUE ||
2020-02-11 23:37:33 +01:00
i >= et2 _historylog . NEW _VALUE && ( self . fields [ _data . status ] . nodes || ! self . _needsDiffWidget ( _data [ 'status' ] , _data [ et2 _historylog . columns [ et2 _historylog . OLD _VALUE ] . id ] ) ) ) ) {
widget = self . fields [ _data . status ] . widget ;
if ( ! widget . _children . length ) {
nodes = self . fields [ _data . status ] . nodes . clone ( ) ;
}
for ( var j = 0 ; j < widget . _children . length ; j ++ ) {
2020-02-12 23:18:10 +01:00
// @ts-ignore
2020-02-11 23:37:33 +01:00
nodes . push ( self . fields [ _data . status ] . nodes [ j ] . clone ( ) ) ;
2021-06-07 17:33:53 +02:00
if ( widget . _children [ j ] . instanceOf ( et2 _diff ) ) {
2020-02-11 23:37:33 +01:00
self . _spanValueColumns ( jQuery ( this ) ) ;
}
}
}
else if ( widget ) {
nodes = et2 _historylog . columns [ i ] . nodes . clone ( ) ;
}
else if ( (
// Already parsed & cached
typeof _data [ et2 _historylog . columns [ et2 _historylog . NEW _VALUE ] . id ] == "object" &&
typeof _data [ et2 _historylog . columns [ et2 _historylog . NEW _VALUE ] . id ] != "undefined" &&
_data [ et2 _historylog . columns [ et2 _historylog . NEW _VALUE ] . id ] !== null ) || // typeof null === 'object'
// Large old value
self . _needsDiffWidget ( _data [ 'status' ] , _data [ et2 _historylog . columns [ et2 _historylog . OLD _VALUE ] . id ] ) ||
// Large new value
self . _needsDiffWidget ( _data [ 'status' ] , _data [ et2 _historylog . columns [ et2 _historylog . NEW _VALUE ] . id ] ) ) {
// Large text value - span both columns, and show a nice diff
2021-06-07 17:33:53 +02:00
let jthis = jQuery ( this ) ;
2020-02-11 23:37:33 +01:00
if ( i === et2 _historylog . NEW _VALUE ) {
// Diff widget
widget = self . diff . widget ;
nodes = self . diff . nodes . clone ( ) ;
if ( widget )
widget . setDetachedAttributes ( nodes , {
value : value ,
label : jthis . parents ( "td" ) . prev ( ) . text ( )
} ) ;
self . _spanValueColumns ( jthis ) ;
}
}
else {
// No widget fallback - display actual value
nodes = jQuery ( '<span>' ) . text ( value === null ? '' : value ) ;
}
if ( widget ) {
if ( widget . _children . length ) {
// Multi-part values
2021-06-07 17:33:53 +02:00
const box = jQuery ( widget . getDOMNode ( ) ) . clone ( ) ;
2020-02-11 23:37:33 +01:00
for ( var j = 0 ; j < widget . _children . length ; j ++ ) {
2021-06-07 17:33:53 +02:00
const id = widget . _children [ j ] . id ;
const widget _value = value ? value [ id ] || "" : "" ;
2020-02-11 23:37:33 +01:00
widget . _children [ j ] . setDetachedAttributes ( nodes [ j ] , { value : widget _value } ) ;
box . append ( nodes [ j ] ) ;
}
nodes = box ;
}
else {
widget . setDetachedAttributes ( nodes , { value : value } ) ;
}
}
jQuery ( this ) . append ( nodes ) ;
} ) ;
jQuery ( tr ) . append ( row . children ( ) ) ;
return tr ;
2021-06-07 17:33:53 +02:00
}
2020-02-11 23:37:33 +01:00
/ * *
* How to tell if the row needs a diff widget or not
*
* @ param { string } columnName
* @ param { string } value
* @ returns { Boolean }
* /
2021-06-07 17:33:53 +02:00
_needsDiffWidget ( columnName , value ) {
2020-02-11 23:37:33 +01:00
if ( typeof value !== "string" && value ) {
this . egw ( ) . debug ( "warn" , "Crazy diff value" , value ) ;
return false ;
}
return value === '***diff***' ;
2021-06-07 17:33:53 +02:00
}
2020-02-11 23:37:33 +01:00
/ * *
* Make a single row ' s new value cell span across both new value and old value
* columns . Used for diff widget .
*
* @ param { jQuery } row jQuery wrapped row node
* /
2021-06-07 17:33:53 +02:00
_spanValueColumns ( row ) {
2020-02-11 23:37:33 +01:00
// Stretch column 4
row . parents ( "td" ) . attr ( "colspan" , 2 )
. css ( "border-right" , "none" ) ;
row . css ( "width" , ( this . dataview . getColumnMgr ( ) . getColumnWidth ( et2 _historylog . NEW _VALUE ) +
this . dataview . getColumnMgr ( ) . getColumnWidth ( et2 _historylog . OLD _VALUE ) - 10 ) + 'px' ) ;
// Skip column 5
row . parents ( "td" ) . next ( ) . remove ( ) ;
2021-06-07 17:33:53 +02:00
}
resize ( _height ) {
2020-02-11 23:37:33 +01:00
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 ) {
// 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 ;
this . div . height ( this . div . height ( ) + _height ) ;
// trigger the history registered resize
// in order to update the height with new value
this . div . trigger ( 'resize.' + this . options . value . app + this . options . value . id ) ;
}
}
if ( this . dynheight ) {
this . dynheight . update ( ) ;
}
// Resize diff widgets to match new space
if ( this . dataview ) {
2021-06-07 17:33:53 +02:00
const columns = this . dataview . getColumnMgr ( ) ;
2020-02-12 22:49:22 +01:00
jQuery ( '.et2_diff' , this . div ) . closest ( '.innerContainer' )
. width ( columns . getColumnWidth ( et2 _historylog . NEW _VALUE ) + columns . getColumnWidth ( et2 _historylog . OLD _VALUE ) ) ;
2020-02-11 23:37:33 +01:00
}
2021-06-07 17:33:53 +02:00
}
}
et2 _historylog . _attributes = {
"value" : {
"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"
} ,
"status_id" : {
"name" : "status_id" ,
"type" : "string" ,
"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. "
} ,
"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"
} ,
"get_rows" : {
"name" : "get_rows" ,
"type" : "string" ,
"default" : "EGroupware\\Api\\Storage\\History::get_rows" ,
"description" : "Method to get rows"
}
} ;
et2 _historylog . legacyOptions = [ "status_id" ] ;
et2 _historylog . columns = [
{ 'id' : 'user_ts' , caption : 'Date' , 'width' : '120px' , widget _type : 'date-time' , widget : null , nodes : null } ,
{ 'id' : 'owner' , caption : 'User' , 'width' : '150px' , widget _type : 'select-account' , widget : null , nodes : null } ,
{ 'id' : 'status' , caption : 'Changed' , 'width' : '120px' , widget _type : 'select' , widget : null , nodes : null } ,
{ 'id' : 'new_value' , caption : 'New Value' , 'width' : '50%' , widget : null , nodes : null } ,
{ 'id' : 'old_value' , caption : 'Old Value' , 'width' : '50%' , widget : null , nodes : null }
] ;
et2 _historylog . TIMESTAMP = 0 ;
et2 _historylog . OWNER = 1 ;
et2 _historylog . FIELD = 2 ;
et2 _historylog . NEW _VALUE = 3 ;
et2 _historylog . OLD _VALUE = 4 ;
et2 _register _widget ( et2 _historylog , [ 'historylog' ] ) ;
2020-02-11 23:37:33 +01:00
//# sourceMappingURL=et2_widget_historylog.js.map