2013-08-26 11:45:43 +02:00
/ * *
* EGroupware - Infolog - Javascript UI
*
* @ link http : //www.egroupware.org
* @ package infolog
* @ author Hadi Nategh < hn - AT - stylite . de >
* @ copyright ( c ) 2008 - 13 by Ralf Becker < RalfBecker - AT - outdoor - training . de >
* @ license http : //opensource.org/licenses/gpl-license.php GPL - GNU General Public License
2013-11-04 21:54:23 +01:00
* @ version $Id$
2013-08-26 11:45:43 +02:00
* /
/ * *
* UI for Infolog
*
* @ augments AppJS
* /
2013-11-04 21:54:23 +01:00
app . classes . infolog = AppJS . extend (
2013-08-26 11:45:43 +02:00
{
appname : 'infolog' ,
/ * *
* Constructor
*
* @ memberOf app . infolog
* /
init : function ( )
{
// call parent
this . _super . apply ( this , arguments ) ;
} ,
/ * *
* Destructor
* /
destroy : function ( )
{
// call parent
this . _super . apply ( this , arguments ) ;
} ,
/ * *
* This function is called when the etemplate2 object is loaded
* and ready . If you must store a reference to the et2 object ,
* make sure to clean it up in destroy ( ) .
*
2014-03-03 10:28:56 +01:00
* @ param { etemplate2 } _et2 newly ready object
* @ param { string } _name template name
2013-08-26 11:45:43 +02:00
* /
2014-03-03 10:28:56 +01:00
et2 _ready : function ( _et2 , _name )
2013-08-26 11:45:43 +02:00
{
// call parent
this . _super . apply ( this , arguments ) ;
2014-03-03 10:28:56 +01:00
switch ( _name )
2013-08-26 11:45:43 +02:00
{
2014-03-03 10:28:56 +01:00
case 'infolog.index' :
this . filter _change ( ) ;
2014-09-16 16:30:52 +02:00
// Show / hide descriptions according to details filter
var nm = this . et2 . getWidgetById ( 'nm' ) ;
var filter2 = nm . getWidgetById ( 'filter2' ) ;
this . show _details ( filter2 . value == 'all' , nm . getDOMNode ( nm ) ) ;
2014-03-03 10:28:56 +01:00
break ;
2014-05-20 12:51:37 +02:00
case 'infolog.edit.print' :
// Trigger print command if the infolog oppend for printing porpuse
2014-07-29 17:02:46 +02:00
this . infolog _print _preview _onload ( ) ;
2013-08-26 11:45:43 +02:00
}
} ,
/ * *
2014-05-22 17:29:14 +02:00
* Observer method receives update notifications from all applications
*
* InfoLog currently reacts to timesheet updates , as it might show time - sums .
* @ todo only trigger update , if times are shown
2013-08-26 11:45:43 +02:00
*
2014-05-22 17:29:14 +02:00
* @ param { string } _msg message ( already translated ) to show , eg . 'Entry deleted'
* @ param { string } _app application name
* @ param { ( string | number ) } _id id of entry to refresh or null
* @ param { string } _type either 'update' , 'edit' , 'delete' , 'add' or null
* - update : request just modified data from given rows . Sorting is not considered ,
* so if the sort field is changed , the row will not be moved .
* - edit : rows changed , but sorting may be affected . Requires full reload .
* - delete : just delete the given rows clientside ( no server interaction neccessary )
* - add : requires full reload for proper sorting
* @ param { string } _msg _type 'error' , 'warning' or 'success' ( default )
2014-05-26 16:01:18 +02:00
* @ param { object | null } _links app => array of ids of linked entries
* or null , if not triggered on server - side , which adds that info
2013-08-26 11:45:43 +02:00
* /
2014-05-26 16:01:18 +02:00
observer : function ( _msg , _app , _id , _type , _msg _type , _links )
2013-08-26 11:45:43 +02:00
{
2014-05-27 15:36:40 +02:00
if ( typeof _links != 'undefined' )
{
if ( typeof _links . infolog != 'undefined' )
2014-10-16 11:29:01 +02:00
{
2014-05-27 15:36:40 +02:00
switch ( _app )
{
case 'timesheet' :
var nm = this . et2 ? this . et2 . getWidgetById ( 'nm' ) : null ;
if ( nm ) nm . applyFilters ( ) ;
break ;
}
2014-05-26 16:01:18 +02:00
}
2014-06-26 14:39:20 +02:00
}
2015-02-17 17:22:08 +01:00
// Refresh handler for Addressbook CRM view
if ( _app == 'infolog' && this . et2 . _inst . app == 'addressbook' && this . et2 . _inst . name == 'infolog.index' )
{
this . et2 . _inst . refresh ( _msg , _app , _id , _type ) ;
}
// Refresh handler for infologs integrated in calendar
if ( _app == 'infolog' && _id && _type != 'delete' )
2014-06-26 14:39:20 +02:00
{
var info _type = egw . dataGetUIDdata ( _app + "::" + _id ) ? egw . dataGetUIDdata ( _app + "::" + _id ) . data . info _type : false ;
var cal _show = egw . preference ( 'cal_show' , 'infolog' ) || false ;
2014-10-16 11:29:01 +02:00
2014-06-26 14:39:20 +02:00
if ( info _type && cal _show )
{
var rex = RegExp ( info _type , 'gi' ) ;
if ( cal _show . match ( rex ) )
{
2014-10-16 11:29:01 +02:00
//Trigger refresh the whole calendar if the changed infolog entry is integrated one
2014-06-26 14:39:20 +02:00
if ( typeof app [ 'calendar' ] != 'undefined' ) app . calendar . egw . window . location . reload ( ) ;
2014-10-16 11:29:01 +02:00
}
2014-06-26 14:39:20 +02:00
}
}
2014-05-22 17:29:14 +02:00
} ,
2013-08-26 11:45:43 +02:00
2014-10-16 11:29:01 +02:00
/ * *
* Retrieve the current state of the application for future restoration
*
2014-10-16 17:59:10 +02:00
* Reimplemented to add action / action _id from content set by server
2014-10-16 11:29:01 +02:00
* when eg . viewing infologs linked to contacts .
*
* @ return { object } Application specific map representing the current state
* /
getState : function ( )
{
// call parent
var state = this . _super . apply ( this , arguments ) ;
2014-10-16 17:59:10 +02:00
var nm = this . et2 ? this . et2 . getArrayMgr ( 'content' ) . data . nm : { } ;
state . action = nm . action || null ;
state . action _id = nm . action _id || null ;
2014-10-16 11:29:01 +02:00
return state ;
} ,
2014-10-16 17:59:10 +02:00
/ * *
* Set the application ' s state to the given state .
*
* Reimplemented to also reset action / action _id .
*
* @ param { { name : string , state : object } | string } state Object ( or JSON string ) for a state .
* Only state is required , and its contents are application specific .
*
* @ return { boolean } false - Returns false to stop event propagation
* /
setState : function ( state )
{
2014-10-23 14:42:24 +02:00
// as we have to set state.state.action, we have to set all other
// for "No filter" favorite to work as expected
var to _set = { col _filter : null , filter : '' , filter2 : '' , cat _id : '' , search : '' , action : null } ;
for ( var name in to _set )
{
if ( typeof state . state [ name ] == 'undefined' ) state . state [ name ] = to _set [ name ] ;
}
2014-10-16 17:59:10 +02:00
return this . _super . apply ( this , arguments ) ;
} ,
2014-05-22 17:29:14 +02:00
/ * *
2014-08-25 19:29:42 +02:00
* Enable or disable the date filter
2014-05-22 17:29:14 +02:00
*
2014-08-25 19:29:42 +02:00
* If the filter is set to something that needs dates , we enable the
* header _left template . Otherwise , it is disabled .
2014-05-22 17:29:14 +02:00
* /
filter _change : function ( )
{
2013-08-26 11:45:43 +02:00
var filter = this . et2 . getWidgetById ( 'filter' ) ;
2014-03-06 23:12:50 +01:00
var nm = this . et2 . getWidgetById ( 'nm' ) ;
2014-08-25 19:29:42 +02:00
var dates = this . et2 . getWidgetById ( 'infolog.index.dates' ) ;
2014-03-06 23:12:50 +01:00
if ( nm && filter )
2013-08-26 11:45:43 +02:00
{
2014-03-06 23:12:50 +01:00
switch ( filter . getValue ( ) )
{
case 'bydate' :
case 'duedate' :
2014-08-25 19:29:42 +02:00
if ( filter && dates )
{
dates . set _disabled ( false ) ;
}
2014-03-06 23:12:50 +01:00
break ;
default :
2014-08-25 19:29:42 +02:00
if ( dates )
{
dates . set _disabled ( true ) ;
}
2014-03-06 23:12:50 +01:00
break ;
}
2013-08-26 11:45:43 +02:00
}
} ,
/ * *
* show or hide the details of rows by selecting the filter2 option
* either 'all' for details or 'no_description' for no details
*
2014-08-26 01:18:09 +02:00
* @ param { Event } event Change event
* @ param { et2 _nextmatch } nm The nextmatch widget that owns the filter
2013-08-26 11:45:43 +02:00
* /
2014-08-26 01:18:09 +02:00
filter2 _change : function ( event , nm )
2013-08-26 11:45:43 +02:00
{
2014-08-26 01:18:09 +02:00
var filter2 = nm . getWidgetById ( 'filter2' ) ;
2013-08-26 11:45:43 +02:00
if ( nm && filter2 )
{
// Show / hide descriptions
2014-09-01 21:20:05 +02:00
this . show _details ( filter2 . value == 'all' , nm . getDOMNode ( nm ) ) ;
2013-08-26 11:45:43 +02:00
2014-09-02 23:14:33 +02:00
// Store selection as implicit preference
egw . set _preference ( 'infolog' , nm . options . settings . columnselection _pref . replace ( '-details' , '' ) + '-details-pref' , filter2 . value ) ;
2013-08-26 11:45:43 +02:00
// Change preference location - widget is nextmatch
2014-08-26 01:18:09 +02:00
nm . options . settings . columnselection _pref = nm . options . settings . columnselection _pref . replace ( '-details' , '' ) + ( filter2 . value == 'all' ? '-details' : '' ) ;
2014-10-16 11:29:01 +02:00
2013-08-26 11:45:43 +02:00
// Load new preferences
2014-08-26 01:18:09 +02:00
var colData = nm . columns . slice ( ) ;
for ( var i = 0 ; i < nm . columns . length ; i ++ ) colData [ i ] . disabled = false ;
2013-08-26 11:45:43 +02:00
nm . _applyUserPreferences ( nm . columns , colData ) ;
2014-08-26 01:18:09 +02:00
// Now apply them to columns
2013-08-26 11:45:43 +02:00
for ( var i = 0 ; i < colData . length ; i ++ )
{
2014-08-26 01:18:09 +02:00
nm . dataview . getColumnMgr ( ) . columns [ i ] . set _width ( colData [ i ] . width ) ;
2013-08-26 11:45:43 +02:00
nm . dataview . getColumnMgr ( ) . columns [ i ] . set _visibility ( ! colData [ i ] . disabled ) ;
}
nm . dataview . getColumnMgr ( ) . updated = true ;
// Update page
nm . dataview . updateColumns ( ) ;
}
} ,
/ * *
* Show or hide details by changing the CSS class
*
2014-10-16 11:29:01 +02:00
* @ param { boolean } show
* @ param { DOMNode } dom _node
2013-08-26 11:45:43 +02:00
* /
2014-09-01 21:20:05 +02:00
show _details : function ( show , dom _node )
2013-08-26 11:45:43 +02:00
{
// Show / hide descriptions
2014-09-01 21:20:05 +02:00
egw . css ( ( dom _node && dom _node . id ? "#" + dom _node . id + ' ' : '' ) + ".et2_box.infoDes" , "display:" + ( show ? "block;" : "none;" ) ) ;
2013-08-26 11:45:43 +02:00
} ,
2013-09-19 14:52:50 +02:00
confirm _delete _2 : function ( _action , _senders )
{
var children = false ;
var child _button = jQuery ( '#delete_sub' ) . get ( 0 ) || jQuery ( '[id*="delete_sub"]' ) . get ( 0 ) ;
if ( child _button )
{
for ( var i = 0 ; i < _senders . length ; i ++ )
{
if ( $j ( _senders [ i ] . iface . node ) . hasClass ( 'infolog_rowHasSubs' ) )
{
children = true ;
break ;
}
}
child _button . style . display = children ? 'block' : 'none' ;
}
var callbackDeleteDialog = function ( button _id )
2014-03-03 10:28:56 +01:00
{
if ( button _id == et2 _dialog . YES _BUTTON )
{
2013-09-19 15:47:02 +02:00
2014-03-03 10:28:56 +01:00
}
} ;
2013-10-07 18:53:13 +02:00
var confirmDeleteDialog = et2 _dialog . show _dialog ( callbackDeleteDialog , this . egw . lang ( "Do you really want to DELETE this Rule" ) , this . egw . lang ( "Delete" ) , { } , et2 _dialog . BUTTONS _YES _NO _CANCEL , et2 _dialog . WARNING _MESSAGE ) ;
2013-09-19 14:52:50 +02:00
} ,
2013-08-26 11:45:43 +02:00
/ * *
* Confirm delete
* If entry has children , asks if you want to delete children too
*
* @ param _action
* @ param _senders
* /
2013-08-27 12:46:42 +02:00
confirm _delete : function ( _action , _senders )
2013-08-26 11:45:43 +02:00
{
var children = false ;
var child _button = jQuery ( '#delete_sub' ) . get ( 0 ) || jQuery ( '[id*="delete_sub"]' ) . get ( 0 ) ;
if ( child _button )
{
for ( var i = 0 ; i < _senders . length ; i ++ )
{
2014-04-28 22:25:40 +02:00
if ( $j ( _senders [ i ] . iface . getDOMNode ( ) ) . hasClass ( 'infolog_rowHasSubs' ) )
2013-08-26 11:45:43 +02:00
{
children = true ;
break ;
}
}
child _button . style . display = children ? 'block' : 'none' ;
}
nm _open _popup ( _action , _senders ) ;
} ,
/ * *
* Add email from addressbook
*
* @ param ab _id
* @ param info _cc
* /
2013-08-27 12:46:42 +02:00
add _email _from _ab : function ( ab _id , info _cc )
2013-08-26 11:45:43 +02:00
{
var ab = document . getElementById ( ab _id ) ;
if ( ! ab || ! ab . value )
{
jQuery ( "tr.hiddenRow" ) . css ( "display" , "table-row" ) ;
}
else
{
var cc = document . getElementById ( info _cc ) ;
for ( var i = 0 ; i < ab . options . length && ab . options [ i ] . value != ab . value ; ++ i ) ;
if ( i < ab . options . length )
{
cc . value += ( cc . value ? ', ' : '' ) + ab . options [ i ] . text . replace ( /^.* <(.*)>$/ , '$1' ) ;
ab . value = '' ;
ab . onchange ( ) ;
jQuery ( "tr.hiddenRow" ) . css ( "display" , "none" ) ;
}
}
return false ;
} ,
/ * *
* If one of info _status , info _percent or info _datecompleted changed -- > set others to reasonable values
*
2014-03-03 10:28:56 +01:00
* @ param { string } changed _id id of changed element
* @ param { string } status _id
* @ param { string } percent _id
* @ param { string } datecompleted _id
2013-08-26 11:45:43 +02:00
* /
2013-08-27 12:46:42 +02:00
status _changed : function ( changed _id , status _id , percent _id , datecompleted _id )
2013-08-26 11:45:43 +02:00
{
2014-01-10 15:25:41 +01:00
// Make sure this doesn't get executed while template is loading
2014-01-10 16:02:50 +01:00
if ( this . et2 == null || this . et2 . getInstanceManager ( ) == null ) return ;
2014-03-03 10:28:56 +01:00
2013-08-26 11:45:43 +02:00
var status = document . getElementById ( status _id ) ;
var percent = document . getElementById ( percent _id ) ;
var datecompleted = document . getElementById ( datecompleted _id + '[str]' ) ;
if ( ! datecompleted )
{
datecompleted = jQuery ( '#' + datecompleted _id + ' input' ) . get ( 0 ) ;
}
var completed ;
switch ( changed _id )
{
case status _id :
completed = status . value == 'done' || status . value == 'billed' ;
if ( completed || status . value == 'not-started' ||
( status . value == 'ongoing' ) != ( percent . value > 0 && percent . value < 100 ) )
{
percent . value = completed ? 100 : ( status . value == 'not-started' ? 0 : 10 ) ;
}
break ;
case percent _id :
completed = percent . value == 100 ;
if ( completed != ( status . value == 'done' || status . value == 'billed' ) ||
( status . value == 'not-started' ) != ( percent . value == 0 ) )
{
2015-03-09 20:26:38 +01:00
status . value = percent . value == 0 ? ( $j ( '[value="not-started"]' , status ) . length ? 'not-started' : 'ongoing' ) : ( percent . value == 100 ? 'done' : 'ongoing' ) ;
2013-08-26 11:45:43 +02:00
}
break ;
case datecompleted _id + '[str]' :
case datecompleted _id :
completed = datecompleted . value != '' ;
if ( completed != ( status . value == 'done' || status . value == 'billed' ) )
{
status . value = completed ? 'done' : 'not-started' ;
}
if ( completed != ( percent . value == 100 ) )
{
percent . value = completed ? 100 : 0 ;
}
break ;
}
if ( ! completed && datecompleted && datecompleted . value != '' )
{
datecompleted . value = '' ;
}
else if ( completed && datecompleted && datecompleted . value == '' )
{
// todo: set current date in correct format
}
} ,
/ * *
* handle "print" action from "Actions" selectbox in edit infolog window .
* check if the template is dirty then submit the template otherwise just open new window as print .
2013-08-27 12:46:42 +02:00
*
2013-08-26 11:45:43 +02:00
* /
2013-08-27 12:46:42 +02:00
edit _actions : function ( )
2013-08-26 11:45:43 +02:00
{
var widget = this . et2 . getWidgetById ( 'action' ) ;
var template = this . et2 . _inst ;
if ( template )
{
var id = template . widgetContainer . getArrayMgr ( 'content' ) . data [ 'info_id' ] ;
}
if ( widget )
{
switch ( widget . get _value ( ) )
{
case 'print' :
if ( template . isDirty ( ) )
{
template . submit ( ) ;
}
egw _open ( id , 'infolog' , 'edit' , { print : 1 } ) ;
break ;
default :
template . submit ( ) ;
}
}
} ,
2014-05-22 17:29:14 +02:00
2014-05-20 12:51:37 +02:00
/ * *
* Open infolog entry for printing
*
* @ param { aciton object } _action
* @ param { object } _selected
* /
infolog _menu _print : function ( _action , _selected )
{
var id = _selected [ 0 ] . id . replace ( /^infolog::/g , '' ) ;
egw _open ( id , 'infolog' , 'edit' , { print : 1 } ) ;
} ,
2014-05-22 17:29:14 +02:00
2014-07-29 17:02:46 +02:00
/ * *
* Trigger print ( ) onload window
* /
infolog _print _preview _onload : function ( )
{
var that = this ;
jQuery ( '#infolog-edit-print' ) . bind ( 'load' , function ( ) {
var isLoadingCompleted = true ;
jQuery ( '#infolog-edit-print' ) . bind ( "DOMSubtreeModified" , function ( event ) {
isLoadingCompleted = false ;
jQuery ( '#infolog-edit-print' ) . unbind ( "DOMSubtreeModified" ) ;
} ) ;
2014-10-16 11:29:01 +02:00
setTimeout ( function ( ) {
isLoadingCompleted = false ;
} , 1000 ) ;
2014-07-29 17:02:46 +02:00
var interval = setInterval ( function ( ) {
if ( ! isLoadingCompleted )
{
clearInterval ( interval ) ;
that . infolog _print _preview ( ) ;
}
} , 100 ) ;
} ) ;
} ,
2014-10-16 11:29:01 +02:00
2014-05-20 12:51:37 +02:00
/ * *
* Trigger print ( ) function to print the current window
* /
2014-07-29 17:02:46 +02:00
infolog _print _preview : function ( )
2014-05-20 12:51:37 +02:00
{
2014-07-29 17:02:46 +02:00
this . egw . message ( 'Printing...' ) ;
2014-05-20 12:51:37 +02:00
this . egw . window . print ( ) ;
} ,
2014-05-22 17:29:14 +02:00
2013-09-13 15:51:33 +02:00
/ * *
*
* /
add _link _sidemenu : function ( )
{
2013-09-25 11:20:32 +02:00
egw . open ( '' , 'infolog' , 'add' ) ;
2013-09-13 15:51:33 +02:00
} ,
2013-11-27 01:17:08 +01:00
/ * *
* Opens a new edit dialog with some extra url parameters pulled from
* standard locations . Done with a function instead of hardcoding so
* the values can be updated if user changes them in UI .
*
2013-11-28 18:34:28 +01:00
* @ param { et2 _widget } widget Originating / calling widget
2013-11-27 01:17:08 +01:00
* @ param _type string Type of infolog entry
* @ param _action string Special action for new infolog entry
* @ param _action _id string ID for special action
* /
2013-11-28 18:34:28 +01:00
add _with _extras : function ( widget , _type , _action , _action _id )
2013-11-27 01:17:08 +01:00
{
2013-11-28 18:34:28 +01:00
// We use widget.getRoot() instead of this.et2 for the case when the
// addressbook tab is viewing a contact + infolog list, there's 2 infolog
// etemplates
var nm = widget . getRoot ( ) . getWidgetById ( 'nm' ) ;
2013-11-27 01:17:08 +01:00
var nm _value = nm . getValue ( ) || { } ;
2013-11-28 18:34:28 +01:00
// It's important that all these keys are here, they override the link
// registry.
2014-12-11 18:59:29 +01:00
var action _id = nm _value . action _id ? nm _value . action _id : ( _action _id != '0' ? _action _id : "" ) || "" ;
if ( typeof action _id == "object" && typeof action _id . length == "undefined" )
{
// Need a real array here
action _id = jQuery . map ( action _id , function ( val ) { return val ; } ) ;
}
2013-11-27 01:17:08 +01:00
var extras = {
2013-11-28 18:34:28 +01:00
type : _type || nm _value . filter || "" ,
cat _id : nm _value . cat _id || "" ,
2014-12-11 18:59:29 +01:00
action : nm _value . action || _action || "" ,
// egw_link can handle arrays, but server is expecting CSV
action _id : typeof action _id . join != "undefined" ? action _id . join ( ',' ) : action _id
2013-11-27 01:17:08 +01:00
} ;
egw . open ( '' , 'infolog' , 'add' , extras ) ;
2015-01-05 15:28:35 +01:00
} ,
2015-02-13 19:03:59 +01:00
2015-01-05 15:28:35 +01:00
/ * *
* Get title in order to set it as document title
* @ returns { string }
* /
getWindowTitle : function ( )
{
var widget = this . et2 . getWidgetById ( 'info_subject' ) ;
if ( widget ) return widget . options . value ;
2015-02-13 19:03:59 +01:00
} ,
/ * *
* View parent entry with all children
*
* @ param { aciton object } _action
* @ param { object } _selected
* /
view _parent : function ( _action , _selected )
{
var data = egw . dataGetUIDdata ( _selected [ 0 ] . id ) ;
if ( data && data . data && data . data . info _id _parent )
{
egw . link _handler ( egw . link ( '/index.php' , {
menuaction : "infolog.infolog_ui.index" ,
action : "sp" ,
action _id : data . data . info _id _parent ,
ajax : "true"
} ) , "infolog" ) ;
}
} ,
/ * *
* Go to parent entry
*
* @ param { aciton object } _action
* @ param { object } _selected
* /
has _parent : function ( _action , _selected )
{
var data = egw . dataGetUIDdata ( _selected [ 0 ] . id ) ;
return data && data . data && data . data . info _id _parent > 0 ;
2013-11-27 01:17:08 +01:00
}
2013-08-26 11:45:43 +02:00
} ) ;