2011-04-27 18:53:06 +02:00
/ * *
2013-10-31 15:51:19 +01:00
* EGroupware - Calendar - Javascript UI
2011-04-27 18:53:06 +02:00
*
* @ link http : //www.egroupware.org
* @ package calendar
2013-10-31 15:51:19 +01:00
* @ author Hadi Nategh < hn - AT - stylite . de >
2015-07-15 18:29:10 +02:00
* @ author Nathan Gray
2013-10-31 15:51:19 +01:00
* @ copyright ( c ) 2008 - 13 by Ralf Becker < RalfBecker - AT - outdoor - training . de >
2011-04-27 18:53:06 +02:00
* @ license http : //opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @ version $Id$
* /
2013-11-05 19:08:07 +01:00
/ * e g w : u s e s
2015-05-06 21:03:45 +02:00
/ e t e m p l a t e / j s / e t e m p l a t e 2 . j s ;
/ c a l e n d a r / j s / e t 2 _ w i d g e t _ t i m e g r i d . j s ;
2015-06-25 19:44:28 +02:00
/ c a l e n d a r / j s / e t 2 _ w i d g e t _ p l a n n e r . j s ;
2013-11-05 19:08:07 +01:00
* /
2011-04-27 18:53:06 +02:00
/ * *
2013-10-31 15:51:19 +01:00
* UI for calendar
*
2015-07-01 00:26:59 +02:00
* Calendar has multiple different views of the same data . All the templates
* for the different view are loaded at the start , then the view objects
2015-07-15 15:16:31 +02:00
* in app . classes . calendar . views are used to manage the different views .
2015-07-15 18:29:10 +02:00
* update _state ( ) is used to change the state between the different views , as
* well as adjust only a single part of the state while keeping the rest unchanged .
2015-07-01 00:26:59 +02:00
*
2015-07-15 18:29:10 +02:00
* The event widgets ( and the nextmatch ) get the data from egw . data , and they
* register update callbacks to automatically update when the data changes . This
* means that when we update something on the server , to update the UI we just need
* to send back the new data and if the event widget still exists it will update
* itself . See calendar _uiforms - > ajax _status ( ) .
*
* To reduce server calls , we also keep a map of day => event IDs . This allows
* us to quickly change views ( week to day , for example ) without requesting additional
* data from the server . We keep that map as long as only the date ( and a few
* others - see update _state ( ) ) changes . If user or any of the other filters are
* changed , we discard the daywise cache and ask the server for the filtered events .
2015-07-01 00:26:59 +02:00
*
2013-10-31 15:51:19 +01:00
* @ augments AppJS
2011-04-27 18:53:06 +02:00
* /
2013-11-04 21:54:23 +01:00
app . classes . calendar = AppJS . extend (
2011-04-27 18:53:06 +02:00
{
2013-10-31 15:51:19 +01:00
/ * *
* application name
* /
appname : 'calendar' ,
2013-11-05 19:08:07 +01:00
2015-06-10 23:51:28 +02:00
/ * *
* etemplate for the sidebox filters
* /
sidebox _et2 : null ,
/ * *
* Current internal state
2015-07-15 18:29:10 +02:00
*
* If you need to change state , you can pass just the fields to change to
* update _state ( ) .
2015-06-10 23:51:28 +02:00
* /
state : {
date : new Date ( ) ,
view : egw . preference ( 'defaultcalendar' , 'calendar' ) || 'day' ,
owner : egw . user ( 'account_id' ) ,
days : egw . preference ( 'days_in_weekview' , 'calendar' )
} ,
2015-09-07 19:13:20 +02:00
2015-09-09 22:59:23 +02:00
states _to _save : [ 'owner' , 'filter' , 'cat_id' , 'view' , 'sortby' , 'planner_days' ] ,
2015-09-14 22:47:25 +02:00
// If you are in one of these views and select a date in the sidebox, the view
// will change as needed to show the date. Other views will only change the
// date in the current view.
sidebox _changes _views : [ 'day' , 'week' , 'month' ] ,
2013-10-31 15:51:19 +01:00
/ * *
* Constructor
*
* @ memberOf app . calendar
* /
init : function ( )
2011-04-27 18:53:06 +02:00
{
2013-12-12 00:51:35 +01:00
// make calendar object available, even if not running in top window, as sidebox does
2015-06-15 23:38:03 +02:00
if ( window . top !== window && ! egw ( window ) . is _popup ( ) && window . top . app . calendar )
2013-12-12 00:51:35 +01:00
{
2015-06-15 23:38:03 +02:00
window . app . calendar = window . top . app . calendar ;
return ;
2013-12-12 00:51:35 +01:00
}
2014-08-26 18:29:12 +02:00
// call parent
this . _super . apply ( this , arguments ) ;
2015-06-25 19:44:28 +02:00
// Scroll
jQuery ( jQuery . proxy ( this . _scroll , this ) ) ;
2013-10-31 15:51:19 +01:00
} ,
/ * *
* Destructor
* /
destroy : function ( )
2011-04-27 18:53:06 +02:00
{
2013-10-31 15:51:19 +01:00
// call parent
this . _super . apply ( this , arguments ) ;
2013-12-12 00:51:35 +01:00
// remove top window reference
if ( window . top !== window && window . top . app . calendar === this )
{
2014-02-19 16:20:19 +01:00
delete window . top . app . calendar ;
2013-12-12 00:51:35 +01:00
}
2015-07-15 18:29:10 +02:00
jQuery ( 'body' ) . off ( '.calendar' ) ;
2013-10-31 15:51:19 +01:00
} ,
2011-04-27 18:53:06 +02:00
2013-10-31 15:51:19 +01:00
/ * *
* 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-02-19 16:20:19 +01:00
* @ param { etemplate2 } _et2 newly ready et2 object
* @ param { string } _name name of template
2013-10-31 15:51:19 +01:00
* /
2014-02-19 16:20:19 +01:00
et2 _ready : function ( _et2 , _name )
2013-10-31 15:51:19 +01:00
{
// call parent
this . _super . apply ( this , arguments ) ;
2014-02-12 18:36:20 +01:00
2015-07-15 18:29:10 +02:00
// Avoid many problems with home
if ( _et2 . app !== 'calendar' ) return ;
2015-09-07 19:13:20 +02:00
2014-02-12 18:36:20 +01:00
// Re-init sidebox, since it was probably initialized too soon
var sidebox = jQuery ( '#favorite_sidebox_' + this . appname ) ;
if ( sidebox . length == 0 && egw _getFramework ( ) != null )
{
var egw _fw = egw _getFramework ( ) ;
sidebox = $j ( '#favorite_sidebox_' + this . appname , egw _fw . sidemenuDiv ) ;
}
2013-10-31 15:51:19 +01:00
var content = this . et2 . getArrayMgr ( 'content' ) ;
2014-10-30 11:24:11 +01:00
2014-02-19 16:20:19 +01:00
switch ( _name )
2013-10-31 15:51:19 +01:00
{
2015-06-10 23:51:28 +02:00
case 'calendar.sidebox' :
this . sidebox _et2 = _et2 . widgetContainer ;
$j ( _et2 . DOMContainer ) . hide ( ) ;
this . _setup _sidebox _filters ( ) ;
2014-02-19 16:20:19 +01:00
break ;
2015-07-15 15:16:31 +02:00
2014-02-19 16:20:19 +01:00
case 'calendar.edit' :
if ( typeof content . data [ 'conflicts' ] == 'undefined' )
2014-01-24 16:50:17 +01:00
{
2014-02-19 16:20:19 +01:00
$j ( document . getElementById ( 'calendar-edit_calendar-delete_series' ) ) . hide ( ) ;
//Check if it's fallback from conflict window or it's from edit window
if ( content . data [ 'button_was' ] != 'freetime' )
{
this . set _enddate _visibility ( ) ;
this . check _recur _type ( ) ;
2014-10-30 11:24:11 +01:00
this . et2 . getWidgetById ( 'recur_exception' ) . set _disabled ( ! content . data . recur _exception ||
typeof content . data . recur _exception [ 0 ] == 'undefined' ) ;
2014-02-19 16:20:19 +01:00
}
else
{
this . freetime _search ( ) ;
}
//send Syncronus ajax request to the server to unlock the on close entry
//set onbeforeunload with json request to send request when the window gets close by X button
2015-08-31 12:49:58 +02:00
if ( content . data . lock _token )
{
window . onbeforeunload = function ( ) {
this . egw . json ( 'calendar.calendar_uiforms.ajax_unlock' ,
[ content . data . id , content . data . lock _token ] , null , true , null , null ) . sendRequest ( true ) ;
} ;
}
2014-01-24 16:50:17 +01:00
}
2014-05-27 17:02:56 +02:00
this . alarm _custom _date ( ) ;
2014-02-19 16:20:19 +01:00
break ;
case 'calendar.freetimesearch' :
2013-10-31 15:51:19 +01:00
this . set _enddate _visibility ( ) ;
2014-02-19 16:20:19 +01:00
break ;
2015-06-10 23:51:28 +02:00
case 'calendar.list' :
this . filter _change ( ) ;
2013-10-31 15:51:19 +01:00
}
2015-07-15 18:29:10 +02:00
// Record the templates for the views so we can switch between them
this . _et2 _view _init ( _et2 , _name ) ;
2013-10-31 15:51:19 +01:00
} ,
2014-08-21 14:43:14 +02:00
2014-06-25 17:39:58 +02:00
/ * *
* Observer method receives update notifications from all applications
*
* App is responsible for only reacting to "messages" it is interested in !
*
* @ 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 )
* @ param { object | null } _links app => array of ids of linked entries
* or null , if not triggered on server - side , which adds that info
* @ return { false | * } false to stop regular refresh , thought all observers are run
* /
observer : function ( _msg , _app , _id , _type , _msg _type , _links )
{
2014-06-26 14:39:20 +02:00
var do _refresh = false ;
switch ( _app )
2014-06-25 17:39:58 +02:00
{
2014-06-26 14:39:20 +02:00
case 'infolog' :
jQuery ( '.calendar_calDayTodos' )
. find ( 'a' )
. each ( function ( i , a ) {
var match = a . href . split ( /&info_id=/ ) ;
if ( match && typeof match [ 1 ] != "undefined" )
2014-06-25 17:39:58 +02:00
{
2014-06-26 14:39:20 +02:00
if ( match [ 1 ] == _id ) do _refresh = true ;
2014-06-25 17:39:58 +02:00
}
2014-06-26 14:39:20 +02:00
} ) ;
2014-08-21 15:31:10 +02:00
if ( jQuery ( 'div [id^="infolog' + _id + '"],div [id^="drag_infolog' + _id + '"]' ) . length > 0 ) do _refresh = true ;
2014-06-26 14:39:20 +02:00
switch ( _type )
{
case 'add' :
do _refresh = true ;
break ;
}
if ( do _refresh )
{
if ( typeof this . et2 != 'undefined' && this . et2 != null )
{
this . egw . refresh ( _msg , 'calendar' ) ;
}
else
{
2014-10-07 18:21:19 +02:00
var iframe = parent . jQuery ( parent . document ) . find ( '.egw_fw_content_browser_iframe' ) ;
var calTab = iframe . parentsUntil ( jQuery ( '.egw_fw_ui_tab_content' ) , '.egw_fw_ui_tab_content' ) ;
2014-10-30 11:24:11 +01:00
if ( ! calTab . is ( ':visible' ) )
2014-10-07 18:21:19 +02:00
{
2014-10-30 11:24:11 +01:00
// F.F can not handle to style correctly an iframe which is hidden (display:none), therefore we need to
2014-10-07 18:21:19 +02:00
// bind a handler to refresh the calendar views after it shows up
2014-11-27 18:37:18 +01:00
iframe . one ( 'show' , function ( ) { egw _refresh ( '' , 'calendar' ) ; } ) ;
2014-10-07 18:21:19 +02:00
}
else
2014-10-30 11:24:11 +01:00
{
2014-10-07 18:21:19 +02:00
//window.location.reload();
window . egw _refresh ( 'refreshing calendar' , 'calendar' ) ;
}
2014-06-25 17:39:58 +02:00
}
2014-06-26 14:39:20 +02:00
}
2015-07-15 18:29:10 +02:00
break ;
case 'calendar' :
2015-08-12 18:51:03 +02:00
if ( _id )
2015-07-15 18:29:10 +02:00
{
2015-08-12 18:51:03 +02:00
var event = egw . dataGetUIDdata ( 'calendar::' + _id ) ;
if ( event && event . data && event . data . date )
2015-07-15 18:29:10 +02:00
{
2015-08-12 18:51:03 +02:00
var new _cache _id = app . classes . calendar . _daywise _cache _id ( event . data . date , this . state . owner )
var daywise = egw . dataGetUIDdata ( new _cache _id ) ;
daywise = daywise ? daywise . data : [ ] ;
if ( _type === 'delete' )
{
daywise . splice ( daywise . indexOf ( _id ) , 1 ) ;
}
else if ( daywise . indexOf ( _id ) < 0 )
{
daywise . push ( _id ) ;
}
egw . dataStoreUID ( new _cache _id , daywise ) ;
}
}
else
{
// Full refresh, clear the caches
var daywise = egw . dataKnownUIDs ( app . classes . calendar . DAYWISE _CACHE _ID ) ;
for ( var i = 0 ; i < daywise . length ; i ++ )
{
egw . dataDeleteUID ( app . classes . calendar . DAYWISE _CACHE _ID + '::' + daywise [ i ] ) ;
2015-07-15 18:29:10 +02:00
}
2015-08-12 18:51:03 +02:00
var events = egw . dataKnownUIDs ( _app ) ;
for ( var i = 0 ; i < events . length ; i ++ )
2015-07-15 18:29:10 +02:00
{
2015-08-12 18:51:03 +02:00
egw . dataDeleteUID ( _app + '::' + events [ i ] ) ;
2015-07-15 18:29:10 +02:00
}
2015-08-12 18:51:03 +02:00
// Force redraw to default state
2015-08-12 19:42:22 +02:00
this . setState ( { } ) ;
2015-07-15 18:29:10 +02:00
}
break ;
2014-08-21 14:43:14 +02:00
}
2014-06-25 17:39:58 +02:00
} ,
2014-08-21 14:43:14 +02:00
2014-01-24 16:50:17 +01:00
/ * *
* Link hander for jDots template to just reload our iframe , instead of reloading whole admin app
*
* @ param { String } _url
* @ return { boolean | string } true , if linkHandler took care of link , false for default processing or url to navigate to
* /
linkHandler : function ( _url )
{
2015-08-12 00:30:50 +02:00
if ( _url . match ( 'menuaction=calendar\.calendar_uiviews\.' ) )
2014-01-24 16:50:17 +01:00
{
2015-08-12 00:30:50 +02:00
var view = _url . match ( /calendar_uiviews\.([^&?]+)/ ) ;
view = view && view . length > 1 ? view [ 1 ] : null ;
// Get query
var q = { } ;
_url . split ( '?' ) [ 1 ] . split ( '&' ) . forEach ( function ( i ) {
q [ i . split ( '=' ) [ 0 ] ] = i . split ( '=' ) [ 1 ] ;
} ) ;
delete q . ajax ;
delete q . menuaction ;
if ( ( ! view || view == 'index' ) && q . view ) view = q . view ;
if ( this . sidebox _et2 && typeof app . classes . calendar . views [ view ] == 'undefined' )
2015-06-15 23:38:03 +02:00
{
this . sidebox _et2 . getWidgetById ( 'iframe' ) . set _src ( _url ) ;
return true ;
}
2015-08-12 00:30:50 +02:00
// Known AJAX view
else if ( app . classes . calendar . views [ view ] )
2015-07-15 18:29:10 +02:00
{
2015-08-12 00:30:50 +02:00
if ( typeof app . classes . calendar . views [ view ] . etemplates [ 0 ] == 'string' )
{
return _url + '&ajax=true' ;
}
// Already loaded, we'll just apply any variables to our current state
var set = jQuery . extend ( { view : view } , q ) ;
this . update _state ( set ) ;
return true ;
2015-07-15 18:29:10 +02:00
}
2015-06-15 23:38:03 +02:00
}
2015-07-15 18:29:10 +02:00
else if ( _url . indexOf ( 'menuaction=calendar.calendar_' ) >= 0 )
2015-06-15 23:38:03 +02:00
{
2015-07-15 18:29:10 +02:00
var iframe = this . sidebox _et2 . getWidgetById ( 'iframe' ) ;
iframe . set _src ( _url ) ;
$j ( this . sidebox _et2 . parentNode ) . show ( ) ;
// Hide other views
for ( var _view in app . classes . calendar . views )
{
for ( var i = 0 ; i < app . classes . calendar . views [ _view ] . etemplates . length ; i ++ )
{
$j ( app . classes . calendar . views [ _view ] . etemplates [ i ] . DOMContainer ) . hide ( ) ;
}
}
this . state . view = '' ;
2015-06-15 23:38:03 +02:00
return true ;
2014-01-24 16:50:17 +01:00
}
// can not load our own index page, has to be done by framework
return false ;
} ,
2015-06-10 23:51:28 +02:00
/ * *
* Setup and handle sortable calendars .
*
* You can only sort calendars if there is more than one owner , and the calendars
* are not combined ( many owners , multi - week or month views )
* @ returns { undefined }
* /
_sortable : function ( ) {
2014-11-05 17:13:26 +01:00
// Calender current state
var state = this . getState ( ) ;
2015-06-10 23:51:28 +02:00
var sortable = jQuery ( '#calendar-view_view tbody' ) ;
2015-07-15 18:29:10 +02:00
if ( ! sortable . sortable ( 'instance' ) )
2014-11-05 17:13:26 +01:00
{
2015-06-10 23:51:28 +02:00
jQuery ( '#calendar-view_view tbody' ) . sortable ( {
2014-11-05 17:13:26 +01:00
cancel : "#divAppboxHeader, .calendar_calWeekNavHeader, .calendar_plannerHeader" ,
2015-06-10 23:51:28 +02:00
handle : '.calendar_calGridHeader' ,
//placeholder: "srotable_cal_wk_ph",
2014-11-05 17:13:26 +01:00
axis : "y" ,
revert : true ,
helper : "clone" ,
create : function ( )
{
var $sortItem = jQuery ( this ) ;
} ,
2015-07-22 01:45:38 +02:00
start : function ( event , ui )
2014-11-05 17:13:26 +01:00
{
2015-07-22 01:45:38 +02:00
$j ( '.calendar_calTimeGrid' , ui . helper ) . css ( 'position' , 'absolute' ) ;
2015-06-10 23:51:28 +02:00
// Put owners into row IDs
2015-08-12 00:30:50 +02:00
app . classes . calendar . views [ app . calendar . state . view ] . etemplates [ 0 ] . widgetContainer . iterateOver ( function ( widget ) {
2015-06-10 23:51:28 +02:00
widget . div . parents ( 'tr' ) . attr ( 'data-owner' , widget . options . owner ) ;
2015-07-15 15:16:31 +02:00
} , this , et2 _calendar _timegrid ) ;
2014-11-05 17:13:26 +01:00
} ,
stop : function ( )
{
} ,
update : function ( )
{
2015-08-12 00:30:50 +02:00
var state = app . calendar . getState ( ) ;
2014-11-05 17:13:26 +01:00
if ( state && typeof state . owner !== 'undefined' )
{
2015-06-10 23:51:28 +02:00
var sortedArr = sortable . sortable ( 'toArray' , { attribute : "data-owner" } ) ;
// Directly update, since there is no other changes needed,
// and we don't want the current sort order applied
app . calendar . state . owner = sortedArr ;
2014-11-05 17:13:26 +01:00
}
}
} ) ;
2015-06-10 23:51:28 +02:00
}
// Enable or disable
2015-07-15 18:29:10 +02:00
if ( ( state . view == 'day' || state . view == 'week' ) &&
2015-07-22 01:45:38 +02:00
state . owner . length > 1 && state . owner . length < egw . config ( 'calview_no_consolidate' , 'phpgwapi' ) )
2015-07-15 18:29:10 +02:00
{
sortable . sortable ( 'enable' )
. sortable ( "refresh" )
. disableSelection ( ) ;
var options = { } ;
switch ( state . view )
{
case "day" :
options = {
placeholder : "srotable_cal_day_ph" ,
axis : "x"
} ;
sortable . sortable ( 'option' , options ) ;
break ;
case "week" :
options = {
placeholder : "srotable_cal_wk_ph" ,
axis : "y"
} ;
sortable . sortable ( 'option' , options ) ;
break ;
}
2015-06-10 23:51:28 +02:00
}
else
{
2015-07-15 18:29:10 +02:00
sortable . sortable ( 'disable' ) ;
2015-06-10 23:51:28 +02:00
}
2013-12-13 19:18:56 +01:00
} ,
2014-01-30 19:24:24 +01:00
2015-06-25 19:44:28 +02:00
/ * *
* Bind scroll event
* When the user scrolls , we ' ll move enddate - startdate days
* /
_scroll : function ( ) {
2015-07-15 18:29:10 +02:00
// Bind only once, to the whole thing
jQuery ( 'body' ) . off ( '.calendar' )
//.on('wheel','.et2_container:#calendar-list,#calendar-sidebox)',
. on ( 'wheel.calendar' , '.et2_container .calendar_calTimeGrid, .et2_container .calendar_plannerWidget' ,
2015-06-25 19:44:28 +02:00
function ( e )
{
e . preventDefault ( ) ;
var direction = e . originalEvent . deltaY > 0 ? 1 : - 1 ;
var delta = 1 ;
var start = new Date ( app . calendar . state . date ) ;
var end = null ;
2015-08-05 23:24:07 +02:00
// Find the template
var id = $j ( this ) . closest ( '.et2_container' ) . attr ( 'id' ) ;
if ( ! id ) return ;
var template = etemplate2 . getById ( id ) ;
if ( ! template ) return ;
2015-06-25 19:44:28 +02:00
// Get the view to calculate
2015-07-01 00:26:59 +02:00
var view = app . classes . calendar . views [ app . calendar . state . view ] || false ;
2015-08-05 23:24:07 +02:00
if ( view && view . etemplates . indexOf ( template ) !== - 1 )
2015-06-25 19:44:28 +02:00
{
2015-07-22 01:45:38 +02:00
start = view . scroll ( direction * delta ) ;
2015-08-05 23:24:07 +02:00
app . calendar . update _state ( { date : app . calendar . date . toString ( start ) } ) ;
}
else
{
// Home - always 1 week
// TODO
return false ;
var widget = [ ] ;
var value = [ ] ;
template . widgetContainer . iterateOver ( function ( w ) {
if ( typeof w . set _start _date === 'function' && typeof w . set _value === 'function' )
{
widget . push ( w ) ;
}
} , this , et2 _valueWidget ) ;
for ( var i = 0 ; i < widget . length ; i ++ )
{
var state = template . widgetContainer . getParent ( ) . settings . favorite . state || { } ;
debugger ;
var start = new Date ( widget [ i ] . options . start _date || state . start ) ;
start . setUTCDate ( start . getUTCDate ( ) + ( 7 * direction * delta ) ) ;
var end = new Date ( widget [ i ] . options . end _date || state . end ) ;
end . setUTCDate ( end . getUTCDate ( ) + ( 7 * direction * delta ) ) ;
// Get data
value [ i ] = {
start _date : start ,
end _date : end
} ;
app . calendar . _need _data ( [ value [ i ] ] , state ) ;
widget [ i ] . set _value ( value [ i ] ) ;
}
2015-06-25 19:44:28 +02:00
}
return false ;
}
) ;
} ,
2014-01-30 17:48:49 +01:00
/ * *
* Function to help calendar resizable event , to fetch the right droppable cell
*
* @ param { int } _X position left of draggable element
* @ param { int } _Y position top of draggable element
*
* @ return { jquery object | boolean } return selected jquery if not return false
* /
resizeHelper : function ( _X , _Y )
{
2014-11-05 17:13:26 +01:00
var $drops = jQuery ( "div[id^='drop_']" ) ;
2014-01-30 17:48:49 +01:00
var top = Math . round ( _Y ) ;
var left = Math . round ( _X ) ;
2014-11-05 17:13:26 +01:00
for ( var i = 0 ; i < $drops . length ; i ++ )
2014-01-30 17:48:49 +01:00
{
2014-11-05 17:13:26 +01:00
if ( top >= Math . round ( $drops [ i ] . getBoundingClientRect ( ) . top )
&& top <= Math . round ( $drops [ i ] . getBoundingClientRect ( ) . bottom )
&& left >= Math . round ( $drops [ i ] . getBoundingClientRect ( ) . left )
&& left <= Math . round ( $drops [ i ] . getBoundingClientRect ( ) . right ) )
return $drops [ i ] ;
2014-01-30 17:48:49 +01:00
}
return false ;
} ,
2014-01-30 19:24:24 +01:00
2014-01-30 17:48:49 +01:00
/ * *
* Convert AM / PM dateTime format to 24 h
*
* @ param { string } _date dnd date format : dateTtime { am | pm } , eg . 121214 T1205 am
*
* @ return { string } 24 h format date
* /
cal _dnd _tZone _converter : function ( _date )
{
var date = _date ;
if ( _date != 'undefined' )
{
var tZone = _date . split ( 'T' ) [ 1 ] ;
if ( tZone . search ( 'am' ) > 0 )
{
tZone = tZone . replace ( ' am' , '' ) ;
var tAm = tZone . substr ( 0 , 2 ) ;
if ( tAm == '12' )
{
tZone = tZone . replace ( '12' , '00' ) ;
}
date = _date . split ( 'T' ) [ 0 ] + 'T' + tZone ;
}
if ( tZone . search ( 'pm' ) > 0 )
{
var pmTime = tZone . replace ( ' pm' , '' ) ;
var H = parseInt ( pmTime . substring ( 0 , 2 ) ) + 12 ;
pmTime = H . toString ( ) + pmTime . substr ( 2 , 2 ) ;
date = _date . split ( 'T' ) [ 0 ] + 'T' + pmTime ;
}
2013-12-13 19:18:56 +01:00
2014-01-30 17:48:49 +01:00
}
return date ;
} ,
2014-01-30 19:24:24 +01:00
2015-06-10 23:51:28 +02:00
/ * *
2015-07-15 15:16:31 +02:00
* Handler for changes generated by internal user interactions , like
2015-06-10 23:51:28 +02:00
* drag & drop inside calendar and resize .
2015-07-15 15:16:31 +02:00
*
2015-06-10 23:51:28 +02:00
* @ param { Event } event
* @ param { et2 _calendar _event } widget Widget for the event
* @ param { string } dialog _button - 'single' , 'series' , or 'exception' , based on the user ' s answer
* in the popup
* @ returns { undefined }
* /
event _change : function ( event , widget , dialog _button )
{
2015-08-24 19:28:19 +02:00
// Add loading spinner - not visible if the body / gradient is there though
widget . div . addClass ( 'loading' ) ;
2015-06-10 23:51:28 +02:00
egw ( ) . json (
'calendar.calendar_uiforms.ajax_moveEvent' ,
2015-08-24 19:28:19 +02:00
[ widget . options . value . id , widget . options . value . owner , widget . options . value . start , widget . options . value . owner , widget . options . value . duration ] ,
// Remove loading spinner
function ( ) { widget . div . removeClass ( 'loading' ) ; }
2015-07-03 19:56:36 +02:00
) . sendRequest ( true ) ;
2015-06-10 23:51:28 +02:00
} ,
2013-12-13 19:18:56 +01:00
/ * *
2014-08-21 13:20:37 +02:00
* This function tries to recognise the type of dropped event , and sends relative request to server accordingly
* - ATM we have three different requests :
* - 1. Event part of series
* - 2. Single Event ( Normall Cal Event )
* - 3. Integrated Infolog Event
2013-12-13 19:18:56 +01:00
*
* @ param { string } _id dragged event id
* @ param { array } _date array of date , hour , and minute of dropped cell
2013-12-16 19:10:08 +01:00
* @ param { string } _duration description
2014-08-21 13:20:37 +02:00
* @ param { string } _eventFlag Flag to distinguish whether the event is Whole Day , Series , or Single
* - S represents Series
2014-08-26 18:29:12 +02:00
* - WD represents Whole Day
2014-08-25 12:30:52 +02:00
* - WDS represents Whole Day Series ( recurrent whole day event )
2014-08-21 13:20:37 +02:00
* - '' represents Single
2013-12-13 19:18:56 +01:00
* /
2014-01-24 13:50:20 +01:00
dropEvent : function ( _id , _date , _duration , _eventFlag )
2013-12-13 19:18:56 +01:00
{
var eventId = _id . substring ( _id . lastIndexOf ( "drag_" ) + 5 , _id . lastIndexOf ( "_O" ) ) ;
var calOwner = _id . substring ( _id . lastIndexOf ( "_O" ) + 2 , _id . lastIndexOf ( "_C" ) ) ;
var eventOwner = _id . substring ( _id . lastIndexOf ( "_C" ) + 2 , _id . lastIndexOf ( "" ) ) ;
2014-01-30 17:48:49 +01:00
var date = this . cal _dnd _tZone _converter ( _date ) ;
2014-01-24 13:50:20 +01:00
if ( _eventFlag == 'S' )
{
et2 _dialog . show _dialog ( function ( _button _id )
2014-02-19 18:48:25 +01:00
{
if ( _button _id == et2 _dialog . OK _BUTTON )
{
2014-08-21 13:20:37 +02:00
egw ( ) . json ( 'calendar.calendar_uiforms.ajax_moveEvent' , [ eventId , calOwner , date , eventOwner , _duration ] ) . sendRequest ( ) ;
2014-02-19 18:48:25 +01:00
}
} , this . egw . lang ( "Do you really want to change the start of this series? If you do, the original series will be terminated as of today and a new series for the future reflecting your changes will be created." ) ,
this . egw . lang ( "This event is part of a series" ) , { } , et2 _dialog . BUTTONS _OK _CANCEL , et2 _dialog . WARNING _MESSAGE ) ;
2014-01-24 13:50:20 +01:00
}
else
{
2014-08-21 13:20:37 +02:00
//Get infologID if in case if it's an integrated infolog event
var infolog _id = eventId . split ( 'infolog' ) [ 1 ] ;
2014-08-21 15:31:10 +02:00
2014-08-21 13:20:37 +02:00
if ( infolog _id )
{
// If it is an integrated infolog event we need to edit infolog entry
egw ( ) . json ( 'stylite_infolog_calendar_integration::ajax_moveInfologEvent' , [ infolog _id , date , _duration ] ) . sendRequest ( ) ;
}
else
{
//Edit calendar event
egw ( ) . json ( 'calendar.calendar_uiforms.ajax_moveEvent' , [ eventId , calOwner , date , eventOwner , _duration ] ) . sendRequest ( ) ;
}
2014-01-24 13:50:20 +01:00
}
2013-12-13 19:18:56 +01:00
} ,
2014-01-30 19:24:24 +01:00
2013-10-31 15:51:19 +01:00
/ * *
* open the freetime search popup
*
2013-11-05 19:08:07 +01:00
* @ param { string } _link
2013-10-31 15:51:19 +01:00
* /
2013-11-05 19:08:07 +01:00
freetime _search _popup : function ( _link )
{
2013-10-31 15:51:19 +01:00
this . egw . open _link ( _link , 'ft_search' , '700x500' ) ;
2013-11-05 19:08:07 +01:00
} ,
2013-10-31 15:51:19 +01:00
/ * *
* send an ajax request to server to set the freetimesearch window content
*
* /
freetime _search : function ( )
2011-04-27 18:53:06 +02:00
{
2013-10-31 15:51:19 +01:00
var content = this . et2 . getArrayMgr ( 'content' ) . data ;
content [ 'start' ] = this . et2 . getWidgetById ( 'start' ) . get _value ( ) ;
content [ 'end' ] = this . et2 . getWidgetById ( 'end' ) . get _value ( ) ;
content [ 'duration' ] = this . et2 . getWidgetById ( 'duration' ) . get _value ( ) ;
var request = this . egw . json ( 'calendar.calendar_uiforms.ajax_freetimesearch' , [ content ] , null , null , null , null ) ;
request . sendRequest ( ) ;
} ,
/ * *
* Function for disabling the recur _data multiselect box
*
* /
check _recur _type : function ( )
2011-04-27 18:53:06 +02:00
{
2013-10-31 15:51:19 +01:00
var recurType = this . et2 . getWidgetById ( 'recur_type' ) ;
var recurData = this . et2 . getWidgetById ( 'recur_data' ) ;
2011-04-27 18:53:06 +02:00
2013-10-31 15:51:19 +01:00
if ( recurType && recurData )
2011-04-27 18:53:06 +02:00
{
2013-10-31 15:51:19 +01:00
recurData . set _disabled ( recurType . get _value ( ) != 2 ) ;
2011-04-27 18:53:06 +02:00
}
2013-10-31 15:51:19 +01:00
} ,
/ * *
* Show / Hide end date , for both edit and freetimesearch popups ,
* based on if "use end date" selected or not .
*
* /
set _enddate _visibility : function ( )
{
var duration = this . et2 . getWidgetById ( 'duration' ) ;
2014-11-14 10:37:49 +01:00
var start = this . et2 . getWidgetById ( 'start' ) ;
2013-10-31 15:51:19 +01:00
var end = this . et2 . getWidgetById ( 'end' ) ;
2014-11-14 10:37:49 +01:00
var content = this . et2 . getArrayMgr ( 'content' ) . data ;
2014-11-27 18:37:18 +01:00
2013-10-31 15:51:19 +01:00
if ( typeof duration != 'undefined' && typeof end != 'undefined' )
2011-04-27 18:53:06 +02:00
{
2013-10-31 15:51:19 +01:00
end . set _disabled ( duration . get _value ( ) !== '' ) ;
2014-11-14 10:37:49 +01:00
if ( ! end . disabled )
{
end . set _value ( start . get _value ( ) ) ;
if ( typeof content . duration != 'undefined' ) end . set _value ( "+" + content . duration ) ;
}
2011-04-27 18:53:06 +02:00
}
2013-10-31 15:51:19 +01:00
} ,
2013-01-09 22:38:18 +01:00
2013-10-31 15:51:19 +01:00
/ * *
* handles actions selectbox in calendar edit popup
*
2013-11-05 19:08:07 +01:00
* @ param { mixed } _event
2014-01-24 10:47:33 +01:00
* @ param { et2 _base _widget } widget "actions selectBox" in edit popup window
2013-10-31 15:51:19 +01:00
* /
2013-11-05 19:08:07 +01:00
actions _change : function ( _event , widget )
{
2013-10-31 15:51:19 +01:00
var event = this . et2 . getArrayMgr ( 'content' ) . data ;
if ( widget )
{
var id = this . et2 . getArrayMgr ( 'content' ) . data [ 'id' ] ;
switch ( widget . get _value ( ) )
{
case 'print' :
this . egw . open _link ( 'calendar.calendar_uiforms.edit&cal_id=' + id + '&print=1' , '_blank' , '700x700' ) ;
break ;
case 'mail' :
this . egw . json ( 'calendar.calendar_uiforms.ajax_custom_mail' , [ event , ! event [ 'id' ] , false ] , null , null , null , null ) . sendRequest ( ) ;
this . et2 . _inst . submit ( ) ;
break ;
case 'sendrequest' :
this . egw . json ( 'calendar.calendar_uiforms.ajax_custom_mail' , [ event , ! event [ 'id' ] , true ] , null , null , null , null ) . sendRequest ( ) ;
this . et2 . _inst . submit ( ) ;
break ;
case 'infolog' :
2014-07-21 11:38:35 +02:00
this . egw . open _link ( 'infolog.infolog_ui.edit&action=calendar&action_id=' + ( $j . isPlainObject ( event ) ? event [ 'id' ] : event ) , '_blank' , '700x600' , 'infolog' ) ;
2013-10-31 15:51:19 +01:00
this . et2 . _inst . submit ( ) ;
break ;
2014-02-10 13:45:57 +01:00
case 'ical' :
this . et2 . _inst . postSubmit ( ) ;
break ;
2013-10-31 15:51:19 +01:00
default :
this . et2 . _inst . submit ( ) ;
}
}
2013-11-05 19:08:07 +01:00
} ,
2013-10-31 15:51:19 +01:00
/ * *
* open mail compose popup window
*
2013-11-05 19:08:07 +01:00
* @ param { Array } vars
2013-10-31 15:51:19 +01:00
* @ todo need to provide right mail compose from server to custom _mail function
* /
2013-11-05 19:08:07 +01:00
custom _mail : function ( vars )
{
2014-01-29 19:47:49 +01:00
this . egw . open _link ( this . egw . link ( "/index.php" , vars ) , '_blank' , '700x700' ) ;
2013-11-05 19:08:07 +01:00
} ,
2014-08-21 14:43:14 +02:00
2013-10-31 15:51:19 +01:00
/ * *
* control delete _series popup visibility
*
2014-01-24 10:47:33 +01:00
* @ param { et2 _widget } widget
2013-11-05 19:08:07 +01:00
* @ param { Array } exceptions an array contains number of exception entries
2013-10-31 15:51:19 +01:00
*
* /
2014-01-23 11:27:18 +01:00
delete _btn : function ( widget , exceptions )
2013-11-05 19:08:07 +01:00
{
var content = this . et2 . getArrayMgr ( 'content' ) . data ;
2013-10-31 15:51:19 +01:00
2013-11-05 19:08:07 +01:00
if ( exceptions )
{
2014-06-16 18:49:45 +02:00
var buttons = [
{
button _id : 'keep' ,
statustext : 'All exceptions are converted into single events.' ,
text : 'Keep exceptions' ,
id : 'button[delete_keep_exceptions]' ,
image : 'keep' , "default" : true
} ,
{
button _id : 'delete' ,
statustext : 'The exceptions are deleted together with the series.' ,
text : 'Delete exceptions' ,
id : 'button[delete_exceptions]' ,
image : 'delete'
} ,
{
button _id : 'cancel' ,
text : 'Cancel' ,
id : 'dialog[cancel]' ,
image : 'cancel'
}
2014-08-21 14:43:14 +02:00
2014-06-16 18:49:45 +02:00
] ;
var self = this ;
et2 _dialog . show _dialog
(
function ( _button _id )
{
if ( _button _id != 'dialog[cancel]' )
{
self . et2 . _inst . submit ( _button _id ) ;
return true ;
}
else
{
return false ;
}
} ,
this . egw . lang ( "Do you want to keep the series exceptions in your calendar?" ) ,
this . egw . lang ( "This event is part of a series" ) , { } , buttons , et2 _dialog . WARNING _MESSAGE
) ;
2013-11-05 19:08:07 +01:00
}
else if ( content [ 'recur_type' ] !== 0 )
{
2014-01-23 11:27:18 +01:00
et2 _dialog . confirm ( widget , 'Delete this series of recuring events' , 'Delete Series' ) ;
2013-11-05 19:08:07 +01:00
}
else
{
2014-01-23 11:27:18 +01:00
et2 _dialog . confirm ( widget , 'Delete this event' , 'Delete' ) ;
2013-11-05 19:08:07 +01:00
}
} ,
2013-10-31 15:51:19 +01:00
/ * *
* print _participants _status ( egw , widget )
* Handle to apply changes from status in print popup
*
2013-11-05 19:08:07 +01:00
* @ param { mixed } _event
* @ param { et2 _base _widget } widget widget "status" in print popup window
2013-10-31 15:51:19 +01:00
*
* /
2013-11-05 19:08:07 +01:00
print _participants _status : function ( _event , widget )
{
2013-10-31 15:51:19 +01:00
if ( widget && window . opener )
{
//Parent popup window
var editPopWindow = window . opener ;
if ( editPopWindow )
{
//Update paretn popup window
editPopWindow . etemplate2 . getByApplication ( 'calendar' ) [ 0 ] . widgetContainer . getWidgetById ( widget . id ) . set _value ( widget . get _value ( ) ) ;
}
this . et2 . _inst . submit ( ) ;
editPopWindow . opener . egw _refresh ( 'status changed' , 'calendar' ) ;
}
else if ( widget )
{
window . egw _refresh ( this . egw . lang ( 'The original popup edit window is closed! You need to close the print window and reopen the entry again.' ) , 'calendar' ) ;
}
2013-11-05 19:08:07 +01:00
} ,
2013-10-31 15:51:19 +01:00
2015-03-12 17:24:55 +01:00
/ * *
* In edit popup , search for calendar participants .
* Resources need to have the start & duration ( etc . )
* passed along in the query .
*
* @ param { Object } request
* @ param { et2 _link _entry } widget
*
* @ returns { boolean } True to continue with the search
* /
edit _participant _search : function ( request , widget )
{
if ( widget . app _select . val ( ) == 'resources' )
{
// Resources search is expecting exec
var values = widget . getInstanceManager ( ) . getValues ( widget . getRoot ( ) ) ;
if ( typeof request . options != 'object' || request . options == null )
{
request . options = { } ;
}
request . options . exec = {
start : values . start ,
end : values . end ,
duration : values . duration ,
participants : values . participants ,
recur _type : values . recur _type ,
event _id : values . link _to . to _id , // cal_id, if available
show _conflict : ( egw . preference ( 'defaultresource_sel' , 'calendar' ) == 'resources_without_conflict' ) ? '0' : '1'
2015-03-12 17:50:47 +01:00
} ;
if ( values . whole _day )
{
request . options . exec . whole _date = true ;
2015-03-12 17:24:55 +01:00
}
}
return true ;
} ,
2015-07-15 15:16:31 +02:00
2013-10-31 15:51:19 +01:00
/ * *
* Handles to select freetime , and replace the selected one on Start ,
* and End date & time in edit calendar entry popup .
*
2013-11-05 19:08:07 +01:00
* @ param { mixed } _event
* @ param { et2 _base _widget } _widget widget "select button" in freetime search popup window
2013-10-31 15:51:19 +01:00
*
* /
2013-11-05 19:08:07 +01:00
freetime _select : function ( _event , _widget )
{
2013-10-31 15:51:19 +01:00
if ( _widget )
{
var content = this . et2 . _inst . widgetContainer . getArrayMgr ( 'content' ) . data ;
// Make the Id from selected button by checking the index
var selectedId = _widget . id . match ( /^select\[([0-9])\]$/i ) [ 1 ] ;
var sTime = this . et2 . getWidgetById ( selectedId + 'start' ) ;
//check the parent window is still open before to try to access it
2014-09-04 15:03:48 +02:00
if ( window . opener && sTime )
2013-10-31 15:51:19 +01:00
{
var editWindowObj = window . opener . etemplate2 . getByApplication ( 'calendar' ) [ 0 ] ;
if ( typeof editWindowObj != "undefined" )
{
var startTime = editWindowObj . widgetContainer . getWidgetById ( 'start' ) ;
var endTime = editWindowObj . widgetContainer . getWidgetById ( 'end' ) ;
if ( startTime && endTime )
{
2014-09-04 15:03:48 +02:00
startTime . set _value ( sTime . get _value ( ) ) ;
endTime . set _value ( sTime . get _value ( ) ) ;
endTime . set _value ( '+' + content [ 'duration' ] ) ;
2013-10-31 15:51:19 +01:00
}
}
}
else
{
alert ( this . egw . lang ( 'The original calendar edit popup is closed!' ) ) ;
}
}
2014-12-12 15:21:04 +01:00
egw ( window ) . close ( ) ;
2013-11-05 19:08:07 +01:00
} ,
2013-10-31 15:51:19 +01:00
/ * *
* show / hide the filter of nm list in calendar listview
*
* /
filter _change : function ( )
2013-01-09 22:45:55 +01:00
{
2014-02-19 16:20:19 +01:00
var filter = this . et2 ? this . et2 . getWidgetById ( 'filter' ) : null ;
var dates = this . et2 ? this . et2 . getWidgetById ( 'calendar.list.dates' ) : null ;
2013-10-31 15:51:19 +01:00
if ( filter && dates )
2013-01-09 22:45:55 +01:00
{
2013-10-31 15:51:19 +01:00
dates . set _disabled ( filter . value !== "custom" ) ;
2013-01-09 22:45:55 +01:00
}
2013-10-31 15:51:19 +01:00
} ,
2015-07-01 00:26:59 +02:00
/ * *
* Application links from non - list events
2015-07-15 15:16:31 +02:00
*
2015-07-01 00:26:59 +02:00
* @ param { egwAction } _action
* @ param { egwActionObject [ ] } _events
* /
action _open : function ( _action , _events )
{
var id = _events [ 0 ] . id . split ( '::' ) ;
if ( _action . data . open )
{
var open = JSON . parse ( _action . data . open ) || { } ;
var extra = open . extra || '' ;
extra = extra . replace ( /(\$|%24)app/ , id [ 0 ] ) . replace ( /(\$|%24)id/ , id [ 1 ] ) ;
this . egw . open ( open . id _data || '' , open . app , open . type , extra ) ;
}
else if ( _action . data . url )
{
var url = _action . data . url ;
url = url . replace ( /(\$|%24)app/ , id [ 0 ] ) . replace ( /(\$|%24)id/ , id [ 1 ] ) ;
this . egw . open _link ( url ) ;
}
} ,
2015-06-10 23:51:28 +02:00
/ * *
* Change status ( via AJAX )
*
* @ param { egwAction } _action
* @ param { egwActionObject } _events
* /
status : function ( _action , _events )
{
// Should be a single event, but we'll do it for all
for ( var i = 0 ; i < _events . length ; i ++ )
{
var event _widget = _events [ i ] . iface . getWidget ( ) || false ;
if ( ! event _widget ) continue ;
event _widget . recur _prompt ( jQuery . proxy ( function ( button _id , event _data ) {
switch ( button _id )
{
case 'exception' :
2015-07-01 00:26:59 +02:00
egw ( ) . json (
'calendar.calendar_uiforms.ajax_status' ,
[ event _data . app _id , egw . user ( 'account_id' ) , _action . data . id ]
) . sendRequest ( true ) ;
2015-06-10 23:51:28 +02:00
break ;
case 'series' :
case 'single' :
2015-07-01 00:26:59 +02:00
egw ( ) . json (
'calendar.calendar_uiforms.ajax_status' ,
[ event _data . id , egw . user ( 'account_id' ) , _action . data . id ]
) . sendRequest ( true ) ;
2015-06-10 23:51:28 +02:00
break ;
case 'cancel' :
default :
break ;
}
} , this ) ) ;
}
} ,
2013-10-31 15:51:19 +01:00
/ * *
* this function try to fix ids which are from integrated apps
*
2015-07-15 18:29:10 +02:00
* @ param { egwAction } _action
* @ param { egwActionObject [ ] } _senders
2013-10-31 15:51:19 +01:00
* /
cal _fix _app _id : function ( _action , _senders )
2013-01-09 22:38:18 +01:00
{
2013-10-31 15:51:19 +01:00
var app = 'calendar' ;
var id = _senders [ 0 ] . id ;
2013-11-04 11:23:08 +01:00
var matches = id . match ( /^(?:calendar::)?([0-9]+)(:([0-9]+))?$/ ) ;
2013-10-31 15:51:19 +01:00
if ( matches )
{
id = matches [ 1 ] ;
}
2014-01-24 10:47:33 +01:00
else
2013-10-31 15:51:19 +01:00
{
2014-01-24 10:47:33 +01:00
matches = id . match ( /^([a-z_-]+)([0-9]+)/i ) ;
if ( matches )
{
app = matches [ 1 ] ;
id = matches [ 2 ] ;
}
2013-10-31 15:51:19 +01:00
}
var backup _url = _action . data . url ;
2013-11-05 14:30:41 +01:00
_action . data . url = _action . data . url . replace ( /(\$|%24)id/ , id ) ;
_action . data . url = _action . data . url . replace ( /(\$|%24)app/ , app ) ;
2013-10-31 15:51:19 +01:00
2015-07-01 00:26:59 +02:00
nm _action ( _action , _senders , false , { ids : [ id ] } ) ;
2013-11-05 14:30:41 +01:00
2013-10-31 15:51:19 +01:00
_action . data . url = backup _url ; // restore url
} ,
/ * *
* Open calendar entry , taking into accout the calendar integration of other apps
*
* calendar _uilist : : get _rows sets var js _calendar _integration object
*
* @ param _action
* @ param _senders
*
* /
cal _open : function ( _action , _senders )
{
2015-07-01 00:26:59 +02:00
2015-08-11 17:35:54 +02:00
if ( _action . parent . data && _action . parent . data . nextmatch )
{
var js _integration _data = _action . parent . data . nextmatch . options . settings . js _integration _data || this . et2 . getArrayMgr ( 'content' ) . data . nm . js _integration _data ;
}
2013-10-31 15:51:19 +01:00
var id = _senders [ 0 ] . id ;
var matches = id . match ( /^(?:calendar::)?([0-9]+):([0-9]+)$/ ) ;
var backup = _action . data ;
if ( matches )
{
this . edit _series ( matches [ 1 ] , matches [ 2 ] ) ;
return ;
}
2014-01-24 10:47:33 +01:00
matches = id . match ( /^([a-z_-]+)([0-9]+)/i ) ;
2015-08-11 17:35:54 +02:00
if ( matches && js _integration _data )
2013-10-31 15:51:19 +01:00
{
var app = matches [ 1 ] ;
_action . data . url = window . egw _webserverUrl + '/index.php?' ;
var get _params = js _integration _data [ app ] . edit ;
get _params [ js _integration _data [ app ] . edit _id ] = matches [ 2 ] ;
for ( var name in get _params )
_action . data . url += name + "=" + encodeURIComponent ( get _params [ name ] ) + "&" ;
2013-01-09 22:38:18 +01:00
2014-01-24 10:47:33 +01:00
if ( js _integration _data [ app ] . edit _popup )
2013-10-31 15:51:19 +01:00
{
2014-01-24 10:47:33 +01:00
matches = js _integration _data [ app ] . edit _popup . match ( /^(.*)x(.*)$/ ) ;
if ( matches )
{
_action . data . width = matches [ 1 ] ;
_action . data . height = matches [ 2 ] ;
}
else
{
_action . data . nm _action = 'location' ;
}
2013-10-31 15:51:19 +01:00
}
}
egw . open ( id . replace ( /^calendar::/g , '' ) , 'calendar' , 'edit' ) ;
_action . data = backup ; // restore url, width, height, nm_action
} ,
2013-01-09 22:38:18 +01:00
2015-07-15 18:29:10 +02:00
/ * *
* Delete ( a single ) calendar entry over ajax .
*
* Used for the non - list views
*
* @ param { egwAction } _action
* @ param { egwActionObject } _events
* /
delete : function ( _action , _events )
{
// Should be a single event, but we'll do it for all
for ( var i = 0 ; i < _events . length ; i ++ )
{
var event _widget = _events [ i ] . iface . getWidget ( ) || false ;
if ( ! event _widget ) continue ;
event _widget . recur _prompt ( jQuery . proxy ( function ( button _id , event _data ) {
switch ( button _id )
{
case 'exception' :
egw ( ) . json (
'calendar.calendar_uiforms.ajax_delete' ,
[ event _data . app _id ]
) . sendRequest ( true ) ;
break ;
case 'series' :
case 'single' :
egw ( ) . json (
'calendar.calendar_uiforms.ajax_delete' ,
[ event _data . id ]
) . sendRequest ( true ) ;
break ;
case 'cancel' :
default :
break ;
}
} , this ) ) ;
}
} ,
2013-10-31 15:51:19 +01:00
/ * *
* Delete calendar entry , asking if you want to delete series or exception
*
2015-07-15 18:29:10 +02:00
* Used for nextmatch
2013-10-31 15:51:19 +01:00
*
* @ param _action
* @ param _senders
* /
cal _delete : function ( _action , _senders )
{
var backup = _action . data ;
var matches = false ;
2013-01-09 22:38:18 +01:00
2013-10-31 15:51:19 +01:00
// Loop so we ask if any of the selected entries is part of a series
for ( var i = 0 ; i < _senders . length ; i ++ )
2013-01-09 22:38:18 +01:00
{
2013-10-31 15:51:19 +01:00
var id = _senders [ i ] . id ;
if ( ! matches )
{
matches = id . match ( /^(?:calendar::)?([0-9]+):([0-9]+)$/ ) ;
}
}
if ( matches )
{
2014-06-17 11:44:15 +02:00
var popup = jQuery ( '#calendar-list_delete_popup' ) . get ( 0 ) ;
if ( typeof popup != 'undefined' )
2013-11-05 19:08:07 +01:00
{
2014-06-17 11:44:15 +02:00
// nm action - show popup
nm _open _popup ( _action , _senders ) ;
2014-08-21 14:43:14 +02:00
}
2013-01-09 22:38:18 +01:00
return ;
}
2013-10-31 15:51:19 +01:00
2013-11-05 17:02:21 +01:00
nm _action ( _action , _senders ) ;
2013-10-31 15:51:19 +01:00
} ,
2014-01-23 18:15:49 +01:00
/ * *
2014-01-24 16:50:17 +01:00
* Confirmation dialog for moving a series entry
2014-01-23 18:15:49 +01:00
*
2014-01-24 16:50:17 +01:00
* @ param { object } _DOM
* @ param { et2 _widget } _button button Save | Apply
2014-01-23 18:15:49 +01:00
* /
move _edit _series : function ( _DOM , _button )
{
var content = this . et2 . getArrayMgr ( 'content' ) . data ;
var start _date = this . et2 . getWidgetById ( 'start' ) . get _value ( ) ;
2014-09-10 12:24:40 +02:00
var whole _day = this . et2 . getWidgetById ( 'whole_day' ) ;
var is _whole _day = whole _day && whole _day . get _value ( ) == whole _day . options . selected _value ;
2014-01-23 18:15:49 +01:00
var button = _button ;
var that = this ;
2014-03-25 16:04:14 +01:00
if ( typeof content != 'undefined' && content . id != null &&
typeof content . recur _type != 'undefined' && content . recur _type != null && content . recur _type != 0
)
2014-01-23 18:15:49 +01:00
{
2014-09-10 12:24:40 +02:00
if ( content . start != start _date || content . whole _day != is _whole _day )
2014-01-23 18:15:49 +01:00
{
et2 _dialog . show _dialog ( function ( _button _id )
{
if ( _button _id == et2 _dialog . OK _BUTTON )
{
that . et2 . _inst . submit ( button ) ;
}
else
{
return false ;
}
} ,
this . egw . lang ( "Do you really want to change the start of this series? If you do, the original series will be terminated as of today and a new series for the future reflecting your changes will be created." ) ,
this . egw . lang ( "This event is part of a series" ) , { } , et2 _dialog . BUTTONS _OK _CANCEL , et2 _dialog . WARNING _MESSAGE ) ;
}
else
{
return true ;
}
}
else
{
return true ;
}
} ,
2013-10-31 15:51:19 +01:00
/ * *
* Create edit exception dialog for recurrence entries
*
2013-11-05 19:08:07 +01:00
* @ param { object } event
* @ param { string } id cal _id
* @ param { integer } date timestamp
2013-10-31 15:51:19 +01:00
* /
edit _series : function ( event , id , date )
{
// Coming from list, there is no event
if ( arguments . length == 2 )
{
date = id ;
id = event ;
event = null ;
}
2013-11-05 19:08:07 +01:00
var edit _id = id ;
var edit _date = date ;
2013-10-31 15:51:19 +01:00
var that = this ;
var buttons = [
{ text : this . egw . lang ( "Edit exception" ) , id : "exception" , class : "ui-priority-primary" , "default" : true } ,
{ text : this . egw . lang ( "Edit series" ) , id : "series" } ,
2013-11-05 19:08:07 +01:00
{ text : this . egw . lang ( "Cancel" ) , id : "cancel" }
2013-10-31 15:51:19 +01:00
] ;
2013-11-05 19:08:07 +01:00
et2 _dialog . show _dialog ( function ( _button _id )
2013-10-31 15:51:19 +01:00
{
2013-11-05 19:08:07 +01:00
switch ( _button _id )
2013-10-31 15:51:19 +01:00
{
case 'exception' :
2013-11-06 09:49:29 +01:00
that . egw . open ( edit _id , 'calendar' , 'edit' , '&date=' + edit _date + '&exception=1' ) ;
2013-10-31 15:51:19 +01:00
break ;
case 'series' :
2013-11-06 09:49:29 +01:00
that . egw . open ( edit _id , 'calendar' , 'edit' , '&date=' + edit _date ) ;
2013-10-31 15:51:19 +01:00
break ;
case 'cancel' :
default :
break ;
}
2013-11-05 19:08:07 +01:00
} , this . egw . lang ( "Do you want to edit this event as an exception or the whole series?" ) ,
this . egw . lang ( "This event is part of a series" ) , { } , buttons , et2 _dialog . WARNING _MESSAGE ) ;
2013-12-05 00:28:31 +01:00
} ,
2014-01-24 10:47:33 +01:00
/ * *
* Method to set state for JSON requests ( jdots ajax _exec or et2 submits can NOT use egw . js script tag )
*
* @ param { object } _state
* /
set _state : function ( _state )
{
if ( typeof _state == 'object' )
{
2015-06-10 23:51:28 +02:00
// If everything is loaded, handle the changes
if ( this . sidebox _et2 !== null )
{
this . update _state ( _state ) ;
}
else
{
// Things aren't loaded yet, just set it
this . state = _state ;
}
}
} ,
/ * *
* Change only part of the current state .
2015-07-15 15:16:31 +02:00
*
2015-06-10 23:51:28 +02:00
* The passed state options ( filters ) are merged with the current state , so
* this is the one that should be used for most calls , as setState ( ) requires
* the complete state .
2015-07-15 15:16:31 +02:00
*
2015-06-10 23:51:28 +02:00
* @ param { Object } _set New settings
* /
update _state : function ( _set )
{
2015-06-15 23:38:03 +02:00
// Make sure we're running in top window
if ( window !== window . top )
{
return window . top . app . calendar . update _state ( _set ) ;
}
2015-07-15 18:29:10 +02:00
if ( this . state _update _in _progress ) return ;
2015-06-10 23:51:28 +02:00
var changed = [ ] ;
var new _state = jQuery . extend ( { } , this . state ) ;
2015-07-15 18:29:10 +02:00
var cachable _changes = [ 'date' , 'view' , 'days' , 'planner_days' , 'sortby' ] ;
2015-07-01 00:26:59 +02:00
if ( typeof _set === 'object' )
2015-06-10 23:51:28 +02:00
{
for ( var s in _set )
{
2015-07-15 18:29:10 +02:00
if ( cachable _changes . indexOf ( s ) === - 1 )
{
// Expire daywise cache
2015-08-12 01:20:24 +02:00
var daywise = egw . dataKnownUIDs ( app . classes . calendar . DAYWISE _CACHE _ID ) ;
2015-07-15 18:29:10 +02:00
for ( var i = 0 ; i < daywise . length ; i ++ )
{
2015-08-12 01:20:24 +02:00
egw . dataDeleteUID ( app . classes . calendar . DAYWISE _CACHE _ID + '::' + daywise [ i ] ) ;
2015-07-15 18:29:10 +02:00
}
}
2015-06-10 23:51:28 +02:00
if ( new _state [ s ] !== _set [ s ] )
{
changed . push ( s + ': ' + new _state [ s ] + ' -> ' + _set [ s ] ) ;
new _state [ s ] = _set [ s ] ;
}
}
}
if ( changed . length && ! this . state _update _in _progress )
{
console . log ( 'Calendar state changed' , changed . join ( "\n" ) ) ;
// Log
this . egw . debug ( 'navigation' , 'Calendar state changed' , changed . join ( "\n" ) ) ;
this . setState ( { state : new _state } ) ;
2014-01-24 10:47:33 +01:00
}
} ,
2013-12-05 00:28:31 +01:00
/ * *
* Return state object defining current view
*
* Called by favorites to query current state .
*
* @ return { object } description
* /
getState : function ( )
{
2015-07-15 18:29:10 +02:00
var state = jQuery . extend ( { } , this . state ) ;
2013-12-06 22:26:55 +01:00
2014-01-24 10:47:33 +01:00
if ( ! state )
{
var egw _script _tag = document . getElementById ( 'egw_script_id' ) ;
state = egw _script _tag . getAttribute ( 'data-calendar-state' ) ;
state = state ? JSON . parse ( state ) : { } ;
}
2013-12-05 00:28:31 +01:00
2015-06-29 21:16:56 +02:00
// Make sure date is consitantly a string, in case it needs to be passed to server
2015-07-15 18:29:10 +02:00
if ( state . date && state . date . toJSON )
2015-06-29 21:16:56 +02:00
{
2015-07-15 18:29:10 +02:00
state . date = state . date . toJSON ( ) ;
2015-06-29 21:16:56 +02:00
}
2015-01-08 16:51:36 +01:00
// Don't store current user in state to allow admins to create favourites for all
// Should make no difference for normal users.
if ( state . owner == egw . user ( 'account_id' ) )
{
// 0 is always the current user, so if an admin creates a default favorite,
// it will work for other users too.
state . owner = 0 ;
}
2015-06-29 21:16:56 +02:00
// Don't store first and last
delete state . first ;
delete state . last ;
2015-07-15 15:16:31 +02:00
2013-12-06 22:26:55 +01:00
return state ;
2013-12-05 00:28:31 +01:00
} ,
/ * *
* Set a state previously returned by getState
*
* Called by favorites to set a state saved as favorite .
*
* @ param { object } state containing "name" attribute to be used as "favorite" GET parameter to a nextmatch
* /
setState : function ( state )
{
2013-12-06 19:24:29 +01:00
// State should be an object, not a string, but we'll parse
if ( typeof state == "string" )
{
if ( state . indexOf ( '{' ) != - 1 || state == 'null' )
{
state = JSON . parse ( state ) ;
}
}
2015-07-01 00:26:59 +02:00
if ( typeof state . state !== 'object' || ! state . state . view )
2015-06-10 23:51:28 +02:00
{
state . state = { view : 'week' } ;
}
if ( ! state . state . date )
{
state . state . date = new Date ( ) ;
}
2015-06-15 23:38:03 +02:00
// Hide other views
2015-07-01 00:26:59 +02:00
for ( var _view in app . classes . calendar . views )
2015-06-15 23:38:03 +02:00
{
2015-07-01 00:26:59 +02:00
if ( state . state . view != _view && app . classes . calendar . views [ _view ] )
2015-06-15 23:38:03 +02:00
{
2015-07-01 00:26:59 +02:00
for ( var i = 0 ; i < app . classes . calendar . views [ _view ] . etemplates . length ; i ++ )
2015-06-15 23:38:03 +02:00
{
2015-07-15 18:29:10 +02:00
if ( typeof app . classes . calendar . views [ _view ] . etemplates [ i ] !== 'string' )
{
$j ( app . classes . calendar . views [ _view ] . etemplates [ i ] . DOMContainer ) . hide ( ) ;
}
2015-06-15 23:38:03 +02:00
}
}
}
2015-06-29 21:16:56 +02:00
if ( this . sidebox _et2 )
{
$j ( this . sidebox _et2 . getInstanceManager ( ) . DOMContainer ) . hide ( ) ;
}
2015-07-15 15:16:31 +02:00
2015-06-10 23:51:28 +02:00
// Check for a supported client-side view
2015-07-01 00:26:59 +02:00
if ( app . classes . calendar . views [ state . state . view ] &&
2015-06-15 23:38:03 +02:00
// Check that the view is instanciated
2015-07-01 00:26:59 +02:00
typeof app . classes . calendar . views [ state . state . view ] . etemplates [ 0 ] !== 'string' && app . classes . calendar . views [ state . state . view ] . etemplates [ 0 ] . widgetContainer
2015-06-15 23:38:03 +02:00
)
2015-06-10 23:51:28 +02:00
{
// Doing an update - this includes the selected view, and the sidebox
// We set a flag to ignore changes from the sidebox which would
// cause infinite loops.
this . state _update _in _progress = true ;
2015-07-15 15:16:31 +02:00
2015-07-01 00:26:59 +02:00
var view = app . classes . calendar . views [ state . state . view ] ;
2015-06-10 23:51:28 +02:00
2015-07-15 18:29:10 +02:00
// Sanitize owner so it's always an array
2015-08-12 00:30:50 +02:00
if ( state . state . owner === null )
{
state . state . owner = undefined ;
}
2015-06-10 23:51:28 +02:00
switch ( typeof state . state . owner )
{
case 'undefined' :
2015-08-12 00:30:50 +02:00
state . state . owner = [ this . egw . user ( 'account_id' ) ] ;
2015-06-10 23:51:28 +02:00
break ;
case 'string' :
state . state . owner = state . state . owner . split ( ',' ) ;
break ;
case 'number' :
state . state . owner = [ state . state . owner ] ;
break ;
2015-07-15 18:29:10 +02:00
case 'object' :
// An array-like Object or an Array?
if ( ! state . state . owner . filter )
{
state . state . owner = jQuery . map ( state . state . owner , function ( owner ) { return owner ; } ) ;
}
2015-06-10 23:51:28 +02:00
}
// Keep sort order
if ( typeof this . state . owner === 'object' )
{
var owner = [ ] ;
this . state . owner . forEach ( function ( key ) {
var found = false ;
state . state . owner = state . state . owner . filter ( function ( item ) {
if ( ! found && item == key ) {
owner . push ( item ) ;
found = true ;
return false ;
} else
return true ;
} ) ;
} ) ;
// Add in any new owners
state . state . owner = owner . concat ( state . state . owner ) ;
}
2013-12-05 00:28:31 +01:00
2015-06-10 23:51:28 +02:00
// Show the correct number of grids
2015-06-25 19:44:28 +02:00
var grid _count = state . state . view === 'weekN' ? parseInt ( this . egw . preference ( 'multiple_weeks' , 'calendar' ) ) || 3 :
state . state . view === 'month' ? 0 : // Calculate based on weeks in the month
2015-06-10 23:51:28 +02:00
state . state . owner . length > ( this . egw . config ( 'calview_no_consolidate' , 'phpgwapi' ) || 5 ) ? 1 : state . state . owner . length ;
2015-07-01 00:26:59 +02:00
var grid = view . etemplates [ 0 ] . widgetContainer . getWidgetById ( 'view' ) ;
2015-06-10 23:51:28 +02:00
/ *
If the count is different , we need to have the correct number ( just remove all & re - create )
If the count is > 1 , it ' s either because there are multiple date spans ( weekN , month ) and we need the correct span
per row , or there are multiple owners and we need the correct owner per row .
* /
2015-06-25 19:44:28 +02:00
if ( grid && ( grid _count !== grid . _children . length || grid _count > 1 ) )
2015-06-10 23:51:28 +02:00
{
// Need to redo the number of grids
var value = [ ] ;
2015-07-01 00:26:59 +02:00
state . state . first = view . start _date ( state . state ) . toJSON ( ) ;
2015-06-25 19:44:28 +02:00
// We'll modify this one, so it needs to be a new object
var date = new Date ( state . state . first ) ;
2015-06-10 23:51:28 +02:00
// Determine the different end date
switch ( state . state . view )
{
case 'month' :
2015-07-01 00:26:59 +02:00
var end = state . state . last = view . end _date ( state . state ) ;
2015-06-10 23:51:28 +02:00
grid _count = Math . ceil ( ( end - date ) / ( 1000 * 60 * 60 * 24 ) / 7 ) ;
// fall through
case 'weekN' :
for ( var week = 0 ; week < grid _count ; week ++ )
{
var val = {
id : "" + date . getUTCFullYear ( ) + sprintf ( "%02d" , date . getUTCMonth ( ) ) + sprintf ( "%02d" , date . getUTCDate ( ) ) ,
start _date : new Date ( date ) ,
end _date : new Date ( date ) ,
owner : state . state . owner
} ;
val . end _date . setUTCHours ( 24 * 7 - 1 ) ;
value . push ( val ) ;
date . setUTCHours ( 24 * 7 ) ;
}
2015-07-15 18:29:10 +02:00
state . state . last = val . end _date ;
2015-06-10 23:51:28 +02:00
break ;
default :
2015-07-01 00:26:59 +02:00
var end = state . state . last = view . end _date ( state . state ) ;
2015-06-10 23:51:28 +02:00
for ( var owner = 0 ; owner < grid _count && owner < state . state . owner . length ; owner ++ )
{
value . push ( {
id : "" + date . getUTCFullYear ( ) + sprintf ( "%02d" , date . getUTCMonth ( ) ) + sprintf ( "%02d" , date . getUTCDate ( ) ) ,
start _date : date ,
end _date : end ,
2015-08-25 02:00:45 +02:00
owner : grid _count > 1 ? state . state . owner [ owner ] || 0 : state . state . owner
2015-06-10 23:51:28 +02:00
} ) ;
}
break ;
}
2015-07-15 18:29:10 +02:00
state . state . last = state . state . last . toJSON ( )
// If we have cached data for the timespan, pass it along
this . _need _data ( value , state . state ) ;
2015-06-25 19:44:28 +02:00
if ( grid )
2015-06-10 23:51:28 +02:00
{
2015-06-25 19:44:28 +02:00
grid . set _value (
2015-06-10 23:51:28 +02:00
{ content : value }
) ;
2015-08-06 19:12:34 +02:00
// Weekend needs to be done seperately
grid . iterateOver ( function ( widget ) {
if ( widget . set _show _weekend )
{
2015-08-12 18:37:02 +02:00
widget . set _show _weekend ( view . show _weekend ( state . state ) ) ;
2015-08-06 19:12:34 +02:00
}
} , this , et2 _valueWidget ) ;
2015-08-19 02:08:22 +02:00
// Granularity needs to be done seperately
grid . iterateOver ( function ( widget ) {
if ( widget . set _granularity )
{
widget . set _granularity ( view . granularity ( state . state ) ) ;
}
} , this , et2 _valueWidget ) ;
2015-06-10 23:51:28 +02:00
}
}
else
{
2015-06-25 19:44:28 +02:00
// Simple, easy case - just one widget for the selected time span.
2015-06-10 23:51:28 +02:00
// Update existing view's special attribute filters, defined in the view list
for ( var updater in view )
{
if ( typeof view [ updater ] === 'function' )
{
var value = view [ updater ] . call ( this , state . state ) ;
2015-07-01 00:26:59 +02:00
if ( updater === 'start_date' ) state . state . first = this . date . toString ( value ) ;
if ( updater === 'end_date' ) state . state . last = this . date . toString ( value ) ;
2015-06-10 23:51:28 +02:00
// Set value
for ( var i = 0 ; i < view . etemplates . length ; i ++ )
{
view . etemplates [ i ] . widgetContainer . iterateOver ( function ( widget ) {
2015-07-01 00:26:59 +02:00
if ( typeof widget [ 'set_' + updater ] === 'function' )
2015-06-10 23:51:28 +02:00
{
2015-07-01 00:26:59 +02:00
widget [ 'set_' + updater ] ( value ) ;
2015-06-10 23:51:28 +02:00
}
} , this , et2 _valueWidget ) ;
}
}
}
2015-07-15 18:29:10 +02:00
var value = [ { start _date : state . state . first , end _date : state . state . last } ] ;
this . _need _data ( value , state . state ) ;
2015-06-10 23:51:28 +02:00
}
2015-06-15 23:38:03 +02:00
// Include first & last dates in state, mostly for server side processing
2015-07-15 15:16:31 +02:00
if ( state . state . first && state . state . first . toJSON ) state . state . first = state . state . first . toJSON ( ) ;
if ( state . state . last && state . state . last . toJSON ) state . state . last = state . state . last . toJSON ( ) ;
2015-06-10 23:51:28 +02:00
// Show the templates for the current view
for ( var i = 0 ; i < view . etemplates . length ; i ++ )
{
$j ( view . etemplates [ i ] . DOMContainer ) . show ( ) ;
}
// Toggle todos
if ( state . state . view == 'day' )
{
2015-08-12 18:37:02 +02:00
if ( state . state . owner . length === 1 && ! isNaN ( state . state . owner ) && state . state . owner [ 0 ] > 0 )
2015-06-10 23:51:28 +02:00
{
view . etemplates [ 0 ] . widgetContainer . set _width ( "70%" ) ;
// TODO: Maybe some caching here
this . egw . jsonq ( 'calendar_uiviews::ajax_get_todos' , [ state . state . date , state . state . owner [ 0 ] ] , function ( data ) {
this . getWidgetById ( 'label' ) . set _value ( data . label || '' ) ;
2015-07-15 18:29:10 +02:00
this . getWidgetById ( 'todos' ) . set _value ( { content : data . todos || '' } ) ;
2015-07-15 15:16:31 +02:00
} , view . etemplates [ 1 ] . widgetContainer ) ;
2015-06-10 23:51:28 +02:00
}
2015-08-12 18:37:02 +02:00
else
{
$j ( view . etemplates [ 1 ] . DOMContainer ) . hide ( ) ;
view . etemplates [ 0 ] . widgetContainer . set _width ( "" ) ;
}
2015-06-10 23:51:28 +02:00
}
else
{
view . etemplates [ 0 ] . widgetContainer . set _width ( "" ) ;
}
this . state = jQuery . extend ( { } , state . state ) ;
2015-07-01 00:26:59 +02:00
var formatDate = new Date ( this . state . date ) ;
formatDate = new Date ( formatDate . valueOf ( ) + formatDate . getTimezoneOffset ( ) * 60 * 1000 ) ;
egw _app _header ( view . header ( state . state ) , 'calendar' ) ;
2015-07-15 15:16:31 +02:00
2015-07-15 18:29:10 +02:00
// List view (nextmatch) has slightly different fields
2015-06-10 23:51:28 +02:00
if ( state . state . view === 'listview' )
{
state . state . startdate = state . state . date ;
state . state . col _filter = { participant : state . state . owner } ;
2015-07-15 18:29:10 +02:00
// Pass status filter in as status filter, avoids conflicts with nm filter
state . state . status _filter = state . state . filter ;
delete state . state . filter ;
2015-09-07 19:13:20 +02:00
2015-07-01 00:26:59 +02:00
var nm = view . etemplates [ 0 ] . widgetContainer . getWidgetById ( 'nm' ) ;
2015-06-10 23:51:28 +02:00
nm . applyFilters ( state . state ) ;
}
/* Update re-orderable calendars */
this . _sortable ( ) ;
2015-07-15 15:16:31 +02:00
2015-06-10 23:51:28 +02:00
/* Update sidebox widgets to show current value*/
2015-07-15 18:29:10 +02:00
if ( this . sidebox _et2 )
{
this . sidebox _et2 . iterateOver ( function ( widget ) {
if ( widget . id == 'view' )
2015-06-10 23:51:28 +02:00
{
2015-07-15 18:29:10 +02:00
// View widget has a list of state settings, which require special handling
for ( var i = 0 ; i < widget . options . select _options . length ; i ++ )
2015-06-10 23:51:28 +02:00
{
2015-07-15 18:29:10 +02:00
var option _state = JSON . parse ( widget . options . select _options [ i ] . value ) || [ ] ;
var match = true ;
for ( var os _key in option _state )
{
2015-08-06 19:12:34 +02:00
// Sometimes an optional state variable is not yet defined (sortby, days, etc)
match = match && ( option _state [ os _key ] == this . state [ os _key ] || typeof this . state [ os _key ] == 'undefined' ) ;
2015-07-15 18:29:10 +02:00
}
if ( match )
{
widget . set _value ( widget . options . select _options [ i ] . value ) ;
return ;
}
2015-06-10 23:51:28 +02:00
}
}
2015-07-15 18:29:10 +02:00
else if ( typeof state . state [ widget . id ] !== 'undefined' && state . state [ widget . id ] != widget . getValue ( ) )
{
// Update widget. This may trigger an infinite loop of
// updates, so we do it after changing this.state and set a flag
widget . set _value ( state . state [ widget . id ] ) ;
}
} , this , et2 _valueWidget ) ;
}
2015-06-10 23:51:28 +02:00
2015-06-29 21:16:56 +02:00
// If current state matches a favorite, hightlight it
this . highlight _favorite ( ) ;
2015-06-10 23:51:28 +02:00
// Sidebox is updated, we can clear the flag
this . state _update _in _progress = false ;
2015-09-09 22:59:23 +02:00
// Update saved state in preferences
var save = { } ;
for ( var i = 0 ; i < this . states _to _save . length ; i ++ )
{
save [ this . states _to _save [ i ] ] = this . state [ this . states _to _save [ i ] ] ;
}
egw . set _preference ( 'calendar' , 'saved_states' , save ) ;
2015-06-10 23:51:28 +02:00
return ;
}
2013-12-05 00:28:31 +01:00
// old calendar state handling on server-side (incl. switching to and from listview)
var menuaction = 'calendar.calendar_uiviews.index' ;
2014-02-25 00:50:51 +01:00
if ( typeof state . state != 'undefined' && ( typeof state . state . view == 'undefined' || state . state . view == 'listview' ) )
2013-12-05 00:28:31 +01:00
{
2014-02-26 14:35:27 +01:00
if ( state . name )
{
// 'blank' is the special name for no filters, send that instead of the nice translated name
state . state . favorite = jQuery . isEmptyObject ( state ) || jQuery . isEmptyObject ( state . state || state . filter ) ? 'blank' : state . name . replace ( /[^A-Za-z0-9-_]/g , '_' ) ;
2014-02-28 11:51:33 +01:00
// set date for "No Filter" (blank) favorite to todays date
if ( state . state . favorite == 'blank' )
state . state . date = jQuery . datepicker . formatDate ( 'yymmdd' , new Date ) ;
2014-02-26 14:35:27 +01:00
}
menuaction = 'calendar.calendar_uilist.listview' ;
state . state . ajax = 'true' ;
2014-01-24 10:47:33 +01:00
// check if we already use et2 / are in listview
2014-01-30 19:24:24 +01:00
if ( this . et2 || etemplate2 && etemplate2 . getByApplication ( 'calendar' ) )
2014-01-24 10:47:33 +01:00
{
// current calendar-code can set regular calendar states only via a server-request :(
// --> check if we only need to set something which can be handeled by nm internally
// or we need a redirect
// ToDo: pass them via nm's get_rows call to server (eg. by passing state), so we dont need a redirect
var current _state = this . getState ( ) ;
var need _redirect = false ;
for ( var attr in current _state )
{
switch ( attr )
{
case 'cat_id' :
case 'owner' :
case 'filter' :
if ( state . state [ attr ] != current _state [ attr ] )
{
need _redirect = true ;
2014-02-26 14:35:27 +01:00
// reset of attributes managed on server-side
if ( state . state . favorite === 'blank' )
{
switch ( attr )
{
case 'cat_id' :
state . state . cat _id = 0 ;
break ;
case 'owner' :
state . state . owner = egw . user ( 'account_id' ) ;
break ;
case 'filter' :
state . state . filter = 'default' ;
break ;
}
}
2014-01-24 10:47:33 +01:00
break ;
}
break ;
2014-02-26 14:35:27 +01:00
case 'view' :
// "No filter" (blank) favorite: if not in listview --> stay in that view
if ( state . state . favorite === 'blank' && current _state . view != 'listview' )
{
menuaction = 'calendar.calendar_uiviews.index' ;
delete state . state . ajax ;
need _redirect = true ;
}
2014-01-24 10:47:33 +01:00
}
}
if ( ! need _redirect )
{
return this . _super . apply ( this , [ state ] ) ;
}
}
2013-12-05 00:28:31 +01:00
}
2014-01-30 17:55:02 +01:00
// setting internal state now, that linkHandler does not intercept switching from listview to any old view
2015-06-15 23:38:03 +02:00
this . state = jQuery . extend ( { } , state . state ) ;
2015-07-01 00:26:59 +02:00
if ( this . sidebox _et2 )
{
$j ( this . sidebox _et2 . getInstanceManager ( ) . DOMContainer ) . show ( ) ;
}
2014-01-30 17:55:02 +01:00
2013-12-12 00:51:35 +01:00
var query = jQuery . extend ( { menuaction : menuaction } , state . state || { } ) ;
2013-12-12 04:42:08 +01:00
2013-12-12 00:51:35 +01:00
// prepend an owner 0, to reset all owners and not just set given resource type
if ( typeof query . owner != 'undefined' )
2013-12-05 00:28:31 +01:00
{
2013-12-12 00:51:35 +01:00
query . owner = '0,' + query . owner ;
2013-12-05 00:28:31 +01:00
}
2013-12-12 00:51:35 +01:00
2013-12-12 04:42:08 +01:00
this . egw . open _link ( this . egw . link ( '/index.php' , query ) , 'calendar' ) ;
2013-12-12 00:51:35 +01:00
// Stop the normal bubbling if this is called on click
return false ;
2014-03-11 11:45:02 +01:00
} ,
2014-06-06 13:59:20 +02:00
2015-06-10 23:51:28 +02:00
/ * *
* Check to see if any of the selected is an event widget
* Used to separate grid actions from event actions
2015-07-15 15:16:31 +02:00
*
* @ param { egwAction } _action
* @ param { egwActioObject [ ] } _selected
2015-06-10 23:51:28 +02:00
* @ returns { boolean } Is any of the selected an event widget
* /
is _event : function ( _action , _selected )
{
var is _widget = false ;
for ( var i = 0 ; i < _selected . length ; i ++ )
{
if ( _selected [ i ] . iface . getWidget ( ) && _selected [ i ] . iface . getWidget ( ) . instanceOf ( et2 _calendar _event ) )
{
is _widget = true ;
}
2015-06-25 19:44:28 +02:00
// Also check classes, usually indicating permission
if ( _action . data && _action . data . enableClass )
{
2015-07-15 15:16:31 +02:00
is _widget = is _widget && ( $j ( _selected [ i ] . iface . getDOMNode ( ) ) . hasClass ( _action . data . enableClass ) ) ;
2015-06-25 19:44:28 +02:00
}
if ( _action . data && _action . data . disableClass )
{
2015-07-15 15:16:31 +02:00
is _widget = is _widget && ! ( $j ( _selected [ i ] . iface . getDOMNode ( ) ) . hasClass ( _action . data . disableClass ) ) ;
2015-06-25 19:44:28 +02:00
}
2015-06-10 23:51:28 +02:00
}
return is _widget ;
} ,
2014-05-27 17:02:56 +02:00
/ * *
* Enable / Disable custom Date - time for set Alarm
*
2014-06-06 13:59:20 +02:00
* @ param { egw object } _egw
2014-05-27 17:02:56 +02:00
* @ param { widget object } _widget new _alarm [ options ] selectbox
* /
alarm _custom _date : function ( _egw , _widget )
{
var alarm _date = this . et2 . getWidgetById ( 'new_alarm[date]' ) ;
var alarm _options = _widget || this . et2 . getWidgetById ( 'new_alarm[options]' ) ;
var start = this . et2 . getWidgetById ( 'start' ) ;
2014-06-06 13:59:20 +02:00
if ( alarm _date && alarm _options
2014-05-27 17:02:56 +02:00
&& start )
{
if ( alarm _options . get _value ( ) != '0' )
{
alarm _date . set _class ( 'calendar_alarm_date_display' ) ;
}
else
{
alarm _date . set _class ( '' ) ;
}
2014-09-23 15:49:22 +02:00
var startDate = typeof start . get _value != 'undefined' ? start . get _value ( ) : start . value ;
2014-05-27 17:02:56 +02:00
if ( startDate )
{
2014-08-21 14:43:14 +02:00
var date = new Date ( startDate ) ;
2014-08-21 15:31:10 +02:00
date . setTime ( date . getTime ( ) - 1000 * parseInt ( alarm _options . get _value ( ) ) ) ;
2014-05-27 17:02:56 +02:00
alarm _date . set _value ( date ) ;
}
}
2014-05-28 17:04:06 +02:00
} ,
2014-06-06 13:59:20 +02:00
2014-05-28 17:04:06 +02:00
/ * *
2014-06-06 13:59:20 +02:00
* Set alarm options based on WD / Regular event user preferences
2014-05-28 17:04:06 +02:00
* Gets fired by wholeday checkbox
2014-06-06 13:59:20 +02:00
*
* @ param { egw object } _egw
2014-05-28 17:04:06 +02:00
* @ param { widget object } _widget whole _day checkbox
* /
set _alarmOptions _WD : function ( _egw , _widget )
{
2014-06-06 13:59:20 +02:00
var alarm = this . et2 . getWidgetById ( 'alarm' ) ;
if ( ! alarm ) return ; // no default alarm
2014-06-05 18:07:59 +02:00
var content = this . et2 . getArrayMgr ( 'content' ) . data ;
var start = this . et2 . getWidgetById ( 'start' ) ;
var self = this ;
var time = alarm . cells [ 1 ] [ 0 ] . widget ;
var event = alarm . cells [ 1 ] [ 1 ] . widget ;
2014-05-28 17:04:06 +02:00
// Convert a seconds of time to a translated label
var _secs _to _label = function ( _secs )
{
var label = '' ;
if ( _secs <= 3600 )
{
label = self . egw . lang ( '%1 minutes' , _secs / 60 ) ;
}
else if ( _secs <= 86400 )
{
label = self . egw . lang ( '%1 hours' , _secs / 3600 ) ;
}
return label ;
2014-06-06 13:59:20 +02:00
} ;
if ( typeof content [ 'alarm' ] [ 1 ] [ 'default' ] == 'undefined' )
2014-05-28 17:04:06 +02:00
{
2014-06-06 13:59:20 +02:00
// user deleted alarm --> nothing to do
2014-05-28 17:04:06 +02:00
}
else
{
2014-06-06 13:59:20 +02:00
var def _alarm = this . egw . preference ( _widget . get _value ( ) === "true" ?
'default-alarm-wholeday' : 'default-alarm' , 'calendar' ) ;
if ( ! def _alarm && def _alarm !== 0 ) // no alarm
{
jQuery ( '#calendar-edit_alarm > tbody :nth-child(1)' ) . hide ( ) ;
}
else
{
jQuery ( '#calendar-edit_alarm > tbody :nth-child(1)' ) . show ( ) ;
2014-09-05 12:34:37 +02:00
start . set _hours ( 0 ) ;
start . set _minutes ( 0 ) ;
time . set _value ( start . get _value ( ) ) ;
time . set _value ( '-' + ( 60 * def _alarm ) ) ;
2014-06-06 13:59:20 +02:00
event . set _value ( _secs _to _label ( 60 * def _alarm ) ) ;
}
2014-05-28 17:04:06 +02:00
}
2015-06-10 23:51:28 +02:00
} ,
2015-07-15 18:29:10 +02:00
/ * *
* Take the date range ( s ) in the value and decide if we need to fetch data
* for the date ranges , or if they ' re already cached fill them in .
*
* @ param {
* /
_need _data : function ( value , state )
{
var need _data = false ;
// Determine if we're showing multiple owners seperate or consolidated
var seperate _owners = false ;
2015-08-25 02:00:45 +02:00
var last _owner = value . length ? value [ 0 ] . owner || 0 : 0 ;
2015-07-15 18:29:10 +02:00
for ( var i = 0 ; i < value . length && ! seperate _owners ; i ++ )
{
seperate _owners = seperate _owners || ( last _owner !== value [ i ] . owner )
}
for ( var i = 0 ; i < value . length ; i ++ )
{
var t = new Date ( value [ i ] . start _date ) ;
var end = new Date ( value [ i ] . end _date ) ;
do
{
// Cache is by date (and owner, if seperate)
var date = t . getUTCFullYear ( ) + sprintf ( '%02d' , t . getUTCMonth ( ) + 1 ) + sprintf ( '%02d' , t . getUTCDate ( ) ) ;
2015-08-06 19:12:34 +02:00
var cache _id = app . classes . calendar . _daywise _cache _id ( date , seperate _owners ? value [ i ] . owner : state . owner || false ) ;
2015-07-15 18:29:10 +02:00
if ( egw . dataHasUID ( cache _id ) )
{
var c = egw . dataGetUIDdata ( cache _id ) ;
if ( c . data && c . data !== null )
{
// There is data, pass it along now
value [ i ] [ date ] = [ ] ;
for ( var j = 0 ; j < c . data . length ; j ++ )
{
if ( egw . dataHasUID ( 'calendar::' + c . data [ j ] ) )
{
value [ i ] [ date ] . push ( egw . dataGetUIDdata ( 'calendar::' + c . data [ j ] ) . data ) ;
}
else
{
need _data = true ;
}
}
}
else
{
need _data = true ;
// Assume it's empty, if there is data it will be filled later
egw . dataStoreUID ( cache _id , [ ] ) ;
}
}
else
{
need _data = true ;
// Assume it's empty, if there is data it will be filled later
egw . dataStoreUID ( cache _id , [ ] ) ;
}
t . setUTCDate ( t . getUTCDate ( ) + 1 ) ;
}
while ( t < end ) ;
2015-09-07 19:13:20 +02:00
2015-07-15 18:29:10 +02:00
// Some data is missing for the current owner, go get it
if ( need _data && seperate _owners )
{
this . _fetch _data ( jQuery . extend ( { } , state , { owner : value [ i ] . owner } ) ) ;
}
}
// Some data was missing, go get it
if ( need _data && ! seperate _owners )
{
this . _fetch _data ( state ) ;
}
} ,
/ * *
* Use the egw . data system to get data from the calendar list for the
* selected time span .
*
* As long as the other filters are the same ( category , owner , status ) we
* cache the data .
2015-08-06 19:12:34 +02:00
*
* @ param { Object } state
* @ param { etemplate2 } [ instance ] If the full calendar app isn ' t loaded
* ( home app ) , pass a different instance to use it to get the data
2015-08-26 01:30:32 +02:00
* @ param { number } [ start ] Result offset . Internal use only
2015-07-15 18:29:10 +02:00
* /
2015-08-26 01:30:32 +02:00
_fetch _data : function ( state , instance , start )
2015-07-15 18:29:10 +02:00
{
2015-08-06 19:12:34 +02:00
if ( ! this . sidebox _et2 && ! instance ) return ;
2015-07-15 18:29:10 +02:00
2015-08-26 01:30:32 +02:00
if ( typeof start === 'undefined' )
{
start = 0 ;
}
var query = jQuery . extend ( { } , {
get _rows : 'calendar.calendar_uilist.get_rows' ,
row _id : 'row_id' ,
startdate : state . first || state . date ,
enddate : state . last ,
// Participant must be an array or it won't work
col _filter : { participant : ( typeof state . owner == 'string' || typeof state . owner == 'number' ? [ state . owner ] : state . owner ) } ,
filter : 'custom' , // Must be custom to get start & end dates
status _filter : state . filter ,
cat _id : state . cat _id ,
search : state . keywords
} ) ;
// Show ajax loader
framework . applications . calendar . sidemenuEntry . showAjaxLoader ( )
2015-07-15 18:29:10 +02:00
this . egw . dataFetch (
2015-08-06 19:12:34 +02:00
instance ? instance . etemplate _exec _id :
this . sidebox _et2 . getInstanceManager ( ) . etemplate _exec _id ,
2015-08-26 01:30:32 +02:00
{ start : start , num _rows : 200 } ,
query ,
2015-07-15 18:29:10 +02:00
this . id ,
function ( data ) {
console . log ( data ) ;
var updated _days = { } ;
for ( var i = 0 ; i < data . order . length && data . total ; i ++ )
{
var record = this . egw . dataGetUIDdata ( data . order [ i ] ) ;
if ( record && record . data )
{
if ( typeof updated _days [ record . data . date ] === 'undefined' )
{
updated _days [ record . data . date ] = [ ] ;
}
// Copy, to avoid unwanted changes by reference
updated _days [ record . data . date ] . push ( record . data . row _id ) ;
// Check for multi-day events listed once
// Date must stay a string or we might cause problems with nextmatch
var dates = {
start : typeof record . data . start === 'string' ? record . data . start : record . data . start . toJSON ( ) ,
end : typeof record . data . end === 'string' ? record . data . end : record . data . end . toJSON ( ) ,
} ;
if ( dates . start . substr ( 0 , 10 ) !== dates . end . substr ( 0 , 10 ) )
{
var end = new Date ( record . data . end ) ;
var t = new Date ( record . data . start ) ;
do
{
var expanded _date = '' + t . getUTCFullYear ( ) + sprintf ( '%02d' , t . getUTCMonth ( ) + 1 ) + sprintf ( '%02d' , t . getDate ( ) ) ;
if ( typeof ( updated _days [ expanded _date ] ) === 'undefined' )
{
updated _days [ expanded _date ] = [ ] ;
}
if ( record . data . date !== expanded _date )
{
// Copy, to avoid unwanted changes by reference
updated _days [ expanded _date ] . push ( record . data . row _id ) ;
}
t . setUTCDate ( t . getUTCDate ( ) + 1 ) ;
}
while ( end >= t )
}
}
}
for ( var day in updated _days )
{
2015-08-05 23:24:07 +02:00
this . egw . dataStoreUID ( app . classes . calendar . _daywise _cache _id ( day , state . owner ) , updated _days [ day ] ) ;
2015-07-15 18:29:10 +02:00
}
2015-09-07 19:13:20 +02:00
2015-08-26 01:30:32 +02:00
// More rows?
if ( data . order . length + start < data . total )
{
// Wait a bit, let UI do something.
window . setTimeout ( function ( ) {
app . calendar . _fetch _data ( state , instance , start + data . order . length ) ;
} , 100 ) ;
}
// Hide AJAX loader
framework . applications . calendar . sidemenuEntry . hideAjaxLoader ( ) ;
2015-07-15 18:29:10 +02:00
} , this , null
) ;
} ,
2015-06-10 23:51:28 +02:00
/ * *
* Some handy date calculations
* All take either a Date object or full date with timestamp ( Z )
* /
date : {
2015-07-01 00:26:59 +02:00
toString : function ( date )
{
// Ensure consistent formatting using UTC, avoids problems with comparison
// and timezones
if ( typeof date === 'string' ) date = new Date ( date ) ;
return date . getUTCFullYear ( ) + '-' +
sprintf ( "%02d" , date . getUTCMonth ( ) + 1 ) + '-' +
sprintf ( "%02d" , date . getUTCDate ( ) ) + 'T' +
sprintf ( "%02d" , date . getUTCHours ( ) ) + ':' +
sprintf ( "%02d" , date . getUTCMinutes ( ) ) + ':' +
sprintf ( "%02d" , date . getUTCSeconds ( ) ) + 'Z' ;
} ,
2015-09-07 19:13:20 +02:00
2015-08-19 02:08:22 +02:00
/ * *
* Formats one or two dates ( range ) as long date ( full monthname ) , optionaly with a time
*
* Take care of any timezone issues before you pass the dates in .
*
* @ param { Date } first first date
* @ param { Date } last = 0 last date for range , or false for a single date
* @ param { boolean } display _time = false should a time be displayed too
* @ param { boolean } display _day = false should a day - name prefix the date , eg . monday June 20 , 2006
* @ return string with formatted date
* /
long _date : function ( first , last , display _time , display _day )
{
if ( ! first ) return '' ;
if ( typeof first === 'string' )
{
first = new Date ( first ) ;
}
if ( typeof last == 'string' && last )
{
last = new Date ( last ) ;
}
if ( ! last || typeof last !== 'object' )
{
last = false ;
}
if ( ! display _time ) display _time = false ;
if ( ! display _day ) display _day = false ;
var range = '' ;
var datefmt = egw . preference ( 'dateformat' ) ;
var timefmt = egw . preference ( 'timeformat' ) == 12 ? 'h:i a' : 'H:i' ;
var month _before _day = datefmt [ 0 ] . toLowerCase ( ) == 'm' ||
datefmt [ 2 ] . toLowerCase ( ) == 'm' && datefmt [ 4 ] == 'd' ;
if ( display _day )
{
range = jQuery . datepicker . formatDate ( 'DD' , first ) + ( datefmt [ 0 ] != 'd' ? ' ' : ', ' ) ;
}
for ( var i = 0 ; i < 5 ; i += 2 )
{
switch ( datefmt [ i ] )
{
case 'd' :
range += first . getUTCDate ( ) + ( datefmt [ 1 ] == '.' ? '.' : '' ) ;
if ( last && ( first . getUTCMonth ( ) != last . getUTCMonth ( ) || first . getFullYear ( ) != last . getFullYear ( ) ) )
{
if ( ! month _before _day )
{
range += jQuery . datepicker . formatDate ( 'MM' , first ) ;
}
if ( first . getFullYear ( ) != last . getFullYear ( ) && datefmt [ 0 ] != 'Y' )
{
range += ( datefmt [ 0 ] != 'd' ? ', ' : ' ' ) . first . getFullYear ( ) ;
}
if ( display _time )
{
range += ' ' + jQuery . datepicker . formatDate ( dateTimeFormat ( timefmt ) , first ) ;
}
if ( ! last )
{
return range ;
}
range += ' - ' ;
if ( first . getFullYear ( ) != last . getFullYear ( ) && datefmt [ 0 ] == 'Y' )
{
range += last . getFullYear ( ) + ', ' ;
}
if ( month _before _day )
{
range += jQuery . datepicker . formatDate ( 'MM' , last ) ;
}
}
else
{
if ( display _time )
{
range += ' ' + jQuery . datepicker . formatDate ( dateTimeFormat ( timefmt ) , last ) ;
}
if ( last )
{
range += ' - ' ;
}
}
if ( last )
{
range += ' ' + last . getUTCDate ( ) + ( datefmt [ 1 ] == '.' ? '.' : '' ) ;
}
break ;
case 'm' :
case 'M' :
range += ' ' + jQuery . datepicker . formatDate ( 'MM' , month _before _day ? first : last ) + ' ' ;
break ;
case 'Y' :
if ( datefmt [ 0 ] != 'm' )
{
range += ' ' + ( datefmt [ 0 ] == 'Y' ? first . getFullYear ( ) + ( datefmt [ 2 ] == 'd' ? ', ' : ' ' ) : last . getFullYear ( ) + ' ' ) ;
}
break ;
}
}
if ( display _time && last )
{
range += ' ' + jQuery . datepicker . formatDate ( dateTimeFormat ( timefmt ) , last ) ;
}
if ( datefmt [ 4 ] == 'Y' && datefmt [ 0 ] == 'm' )
{
range += ', ' + last . getFullYear ( ) ;
}
return range ;
} ,
/ * *
* Calculate iso8601 week - number , which is defined for Monday as first day of week only
*
* We adjust the day , if user prefs want a different week - start - day
*
* @ param string | Date date
* @ return string
* /
week _number : function ( _date )
{
var d = new Date ( _date ) ;
var day = d . getUTCDay ( ) ;
// if week does not start Monday and date is Sunday --> add one day
if ( egw . preference ( 'weekdaystarts' , 'calendar' ) != 'Monday' && ! day )
{
d . setUTCDate ( d . getUTCDate ( ) + 1 ) ;
}
// if week does start Saturday and $time is Saturday --> add two days
else if ( egw . preference ( 'weekdaystarts' , 'calendar' ) == 'Saturday' && day == 6 )
{
d . setUTCDate ( d . getUTCDate ( ) + 2 ) ;
}
return jQuery . datepicker . iso8601Week ( new Date ( d . valueOf ( ) + d . getTimezoneOffset ( ) * 60 * 1000 ) ) ;
} ,
2015-06-10 23:51:28 +02:00
start _of _week : function ( date )
{
var d = new Date ( date ) ;
var day = d . getUTCDay ( ) ;
var diff = 0 ;
switch ( egw . preference ( 'weekdaystarts' , 'calendar' ) )
{
case 'Saturday' :
2015-08-19 02:08:22 +02:00
diff = day === 6 ? 0 : day === 0 ? - 1 : - ( day + 1 ) ;
2015-06-10 23:51:28 +02:00
break ;
case 'Monday' :
diff = day === 0 ? 1 : 1 - day ;
break ;
case 'Sunday' :
default :
diff = - day ;
}
2015-07-15 18:29:10 +02:00
d . setUTCDate ( d . getUTCDate ( ) + diff ) ;
2015-06-10 23:51:28 +02:00
return d ;
} ,
end _of _week : function ( date )
{
var d = app . calendar . date . start _of _week ( date ) ;
2015-07-15 18:29:10 +02:00
d . setUTCDate ( d . getUTCDate ( ) + 6 ) ;
2015-06-10 23:51:28 +02:00
return d ;
}
} ,
2015-08-12 00:30:50 +02:00
/ * *
* Initializes actions and handlers on sidebox ( delete )
* Extended from parent to automatically add change handlers for resource
* menu items .
*
* @ param { jQuery } sidebox jQuery of DOM node
* /
_init _sidebox : function ( sidebox )
{
if ( this . _super . apply ( this , arguments ) )
{
sidebox . parentsUntil ( '#calendar_sidebox_content' )
. find ( '.egw_fw_ui_category_content' ) . not ( sidebox . parent ( ) )
. on ( 'change.sidebox' , 'select:not(.et2_selectbox),input' , this , function ( event ) {
var state = { } ;
// Here we look for things like owner: ['r1,r2'] and change them
// to owner: ['r1','r2']
state [ this . name . replace ( '[]' , '' ) ] = $j ( this ) . val ( ) ;
2015-08-12 18:37:02 +02:00
$j ( 'option' , this ) . removeAttr ( 'selected' ) ;
2015-08-12 00:30:50 +02:00
for ( var key in state )
{
if ( state [ key ] && typeof state [ key ] . length !== 'undefined' )
{
for ( var sub _key in state [ key ] )
{
if ( typeof state [ key ] [ sub _key ] == 'string' && state [ key ] [ sub _key ] . indexOf ( ',' ) !== - 1 )
{
var explode _me = state [ key ] [ sub _key ] ;
delete state [ key ] [ sub _key ] ;
jQuery . extend ( state [ key ] , explode _me . split ( ',' ) ) ;
}
}
}
}
app . calendar . update _state ( state ) ;
} ) ;
}
} ,
2015-06-10 23:51:28 +02:00
/ * *
* The sidebox filters use some non - standard and not - exposed options . They
* are set up here .
*
* /
_setup _sidebox _filters : function ( )
{
// Further date customizations
var date = this . sidebox _et2 . getWidgetById ( 'date' ) ;
if ( date )
{
date . input _date . datepicker ( "option" , {
2015-09-07 19:13:20 +02:00
showButtonPanel : true ,
2015-08-24 19:28:19 +02:00
onChangeMonthYear : function ( year , month , inst )
{
// Switch to month view for that month
var date = new Date ( app . calendar . state . date ) ;
date . setUTCDate ( 1 ) ;
date . setFullYear ( year ) ;
date . setUTCMonth ( month - 1 ) ;
2015-09-14 22:47:25 +02:00
var state = { date : date } ;
if ( app . calendar . sidebox _changes _views . indexOf ( app . calendar . state . view ) >= 0 )
{
state . view = 'month' ;
}
else if ( app . calendar . state . view == 'planner' )
{
state . planner _days = 0 ;
state . last = false ;
}
app . calendar . update _state ( state ) ;
2015-08-24 19:28:19 +02:00
} ,
// Mark holidays
beforeShowDay : function ( date )
{
var holidays = et2 _calendar _daycol . get _holidays ( { day _class _holiday : function ( ) { } } , date . getFullYear ( ) ) ;
var day _holidays = holidays [ '' + date . getUTCFullYear ( ) +
sprintf ( "%02d" , date . getUTCMonth ( ) + 1 ) +
sprintf ( "%02d" , date . getUTCDate ( ) ) ] ;
var css _class = '' ;
var tooltip = '' ;
if ( typeof day _holidays !== 'undefined' && day _holidays . length )
{
for ( var i = 0 ; i < day _holidays . length ; i ++ )
{
if ( typeof day _holidays [ i ] [ 'birthyear' ] !== 'undefined' )
{
css _class += 'calendar_calBirthday ' ;
}
else
{
css _class += 'calendar_calHoliday ' ;
}
tooltip += day _holidays [ i ] [ 'name' ] + "\n" ;
}
}
return [ true , css _class , tooltip ] ;
}
2015-06-10 23:51:28 +02:00
} ) ;
2015-07-15 15:16:31 +02:00
2015-08-24 19:28:19 +02:00
// Clickable week numbers
date . input _date . on ( 'mouseenter' , '.ui-datepicker-week-col' , function ( ) {
$j ( this ) . siblings ( ) . find ( 'a' ) . addClass ( 'ui-state-hover' ) ;
} )
. on ( 'mouseleave' , '.ui-datepicker-week-col' , function ( ) {
$j ( this ) . siblings ( ) . find ( 'a' ) . removeClass ( 'ui-state-hover' ) ;
} )
. on ( 'click' , '.ui-datepicker-week-col' , function ( ) {
2015-09-14 22:47:25 +02:00
var view = app . calendar . state . view ;
2015-08-24 19:28:19 +02:00
// Fake a click event on the first day to get the updated date
$j ( this ) . next ( ) . click ( ) ;
2015-09-14 22:47:25 +02:00
// Set to week view, if in one of the views where we change view
if ( app . calendar . sidebox _changes _views . indexOf ( view ) >= 0 )
{
app . calendar . update _state ( { view : 'week' , date : date . getValue ( ) } ) ;
}
else if ( app . calendar . state . view == 'planner' )
{
// Clicked a week, show just a week
app . calendar . update _state ( { planner _days : 7 } ) ;
}
2015-08-24 19:28:19 +02:00
} ) ;
}
2015-07-01 00:26:59 +02:00
} ,
2015-09-07 19:13:20 +02:00
2015-07-15 18:29:10 +02:00
/ * *
* Record view templates so we can quickly switch between them .
2015-09-07 19:13:20 +02:00
*
2015-07-15 18:29:10 +02:00
* @ param { etemplate2 } _et2 etemplate2 template that was just loaded
* @ param { String } _name Name of the template
* /
_et2 _view _init : function ( _et2 , _name )
{
var hidden = typeof this . state . view !== 'undefined' ;
var all _loaded = true ;
2015-08-05 23:24:07 +02:00
// Avoid home portlets using our templates, and get them right
if ( _et2 . uniqueId . indexOf ( 'portlet' ) === 0 ) return ;
2015-09-07 19:13:20 +02:00
2015-07-15 18:29:10 +02:00
// Flag to make sure we don't hide non-view templates
var view _et2 = false ;
2015-09-07 19:13:20 +02:00
2015-07-15 18:29:10 +02:00
for ( var view in app . classes . calendar . views )
{
var index = app . classes . calendar . views [ view ] . etemplates . indexOf ( _name ) ;
if ( index > - 1 )
{
view _et2 = true ;
app . classes . calendar . views [ view ] . etemplates [ index ] = _et2 ;
// If a template disappears, we want to release it
$j ( _et2 . DOMContainer ) . one ( 'clear' , jQuery . proxy ( function ( ) {
this . view [ index ] = _name ;
2015-08-05 23:24:07 +02:00
} , jQuery . extend ( { } , { view : app . classes . calendar . views [ view ] , index : "" + index , name : _name } ) ) ) ;
2015-07-15 18:29:10 +02:00
if ( this . state . view === view )
{
hidden = false ;
}
}
app . classes . calendar . views [ view ] . etemplates . forEach ( function ( et ) { all _loaded = all _loaded && typeof et !== 'string' ; } ) ;
}
// Start hidden, except for current view
if ( view _et2 )
{
if ( hidden )
{
$j ( _et2 . DOMContainer ) . hide ( ) ;
}
if ( all _loaded )
{
this . setState ( { state : this . state } ) ;
}
}
} ,
2015-09-14 22:47:25 +02:00
/ * *
* Super class for the different views .
*
* Each separate view overrides what it needs
* /
2015-07-01 00:26:59 +02:00
View : {
// List of etemplates to show for this view
etemplates : [ 'calendar.view' ] ,
/ * *
* Translated label for header
* @ param { Object } state
* @ returns { string }
* /
header : function ( state ) {
var formatDate = new Date ( state . date ) ;
formatDate = new Date ( formatDate . valueOf ( ) + formatDate . getTimezoneOffset ( ) * 60 * 1000 ) ;
return date ( egw . preference ( 'dateformat' ) , formatDate ) ;
} ,
/ * *
* Get the start date for this view
* @ param { Object } state
* @ returns { Date }
* /
start _date : function ( state ) {
var d = state . date ? new Date ( state . date ) : new Date ( ) ;
d . setUTCHours ( 0 ) ;
d . setUTCMinutes ( 0 ) ;
d . setUTCSeconds ( 0 ) ;
d . setUTCMilliseconds ( 0 ) ;
return d ;
} ,
/ * *
* Get the end date for this view
* @ param { Object } state
* @ returns { Date }
* /
end _date : function ( state ) {
var d = state . date ? new Date ( state . date ) : new Date ( ) ;
d . setUTCHours ( 23 ) ;
d . setUTCMinutes ( 59 ) ;
d . setUTCSeconds ( 59 ) ;
d . setUTCMilliseconds ( 0 ) ;
return d ;
} ,
2015-07-22 01:45:38 +02:00
/ * *
* Get the owner for this view
*
* This is always the owner from the given state , we use a function
* to trigger setting the widget value .
*
* @ param { number [ ] | String } state . owner List of owner IDs , or a comma seperated list
* @ returns { number [ ] | String }
* /
2015-07-01 00:26:59 +02:00
owner : function ( state ) {
return state . owner || 0 ;
} ,
2015-07-22 01:45:38 +02:00
/ * *
* Should the view show the weekends
*
* @ returns { boolean } Current preference to show 5 or 7 days in weekview
* /
2015-07-01 00:26:59 +02:00
show _weekend : function ( state )
{
2015-08-06 19:12:34 +02:00
return state . days ? parseInt ( state . days ) === 7 : parseInt ( egw . preference ( 'days_in_weekview' , 'calendar' ) ) == 7 ;
2015-07-01 00:26:59 +02:00
} ,
2015-09-03 00:40:38 +02:00
/ * *
* How big or small are the displayed time chunks ?
* We automatically scale the user ' s preference based on how many rows / calendars are shown .
* /
2015-08-19 02:08:22 +02:00
granularity : function ( state ) {
2015-09-03 00:40:38 +02:00
return Math . min ( 240 , ( state . owner . length <= ( egw . config ( 'calview_no_consolidate' , 'phpgwapi' ) || 5 ) ? state . owner . length : 1 )
* ( parseInt ( egw . preference ( 'interval' , 'calendar' ) ) || 30 ) ) ;
2015-08-19 02:08:22 +02:00
} ,
2015-07-01 00:26:59 +02:00
extend : function ( sub )
{
return jQuery . extend ( { } , this , { _super : this } , sub ) ;
2015-07-22 01:45:38 +02:00
} ,
/ * *
* Determines the new date after scrolling . The default is 1 week .
*
* @ param { number } delta Integer for how many 'ticks' to move , positive for
* forward , negative for backward
* @ returns { Date }
* /
scroll : function ( delta )
{
var d = new Date ( app . calendar . state . date ) ;
d . setUTCDate ( d . getUTCDate ( ) + ( 7 * delta ) ) ;
return d ;
2015-07-01 00:26:59 +02:00
}
2014-06-06 13:59:20 +02:00
}
2013-10-31 15:51:19 +01:00
} ) ;
2015-07-01 00:26:59 +02:00
jQuery . extend ( app . classes . calendar , {
2015-08-05 23:24:07 +02:00
/ * *
* This is the data cache prefix for the daywise event index cache
* Daywise cache IDs look like : calendar _daywise : : 20150101 and
* contain a list of event IDs for that day ( or empty array )
* /
DAYWISE _CACHE _ID : 'calendar_daywise' ,
/ * *
* Create a cache ID for the daywise cache
*
* @ param { String | Date } date
* @ param { String | integer | String [ ] } owner
* @ returns { String } Cache ID
* /
_daywise _cache _id : function ( date , owner )
{
if ( typeof date === 'object' )
{
date = date . getUTCFullYear ( ) + sprintf ( '%02d' , date . getUTCMonth ( ) + 1 ) + sprintf ( '%02d' , date . getUTCDate ( ) ) ;
}
// If the owner is not set, 0, or the current user, don't bother adding it
2015-08-12 00:30:50 +02:00
var state _owner = app . calendar ? app . calendar . state . owner . toString ( ) || '' : '' ;
var _owner = ( owner && owner . toString ( ) != '0' && owner !== state _owner ) ? owner . toString ( ) : '' ;
2015-08-05 23:24:07 +02:00
if ( _owner == egw . user ( 'account_id' ) )
{
_owner = '' ;
}
return app . classes . calendar . DAYWISE _CACHE _ID + '::' + date + ( _owner ? '-' + _owner : '' ) ;
} ,
/ * *
* Etemplates and settings for the different views . Some ( day view )
* use more than one template , some use the same template as others ,
* most need different handling for their various attributes .
*
* Not using the standard Class . extend here because it hides the members ,
* and we want to be able to look inside them . This is done seperately instead
* of inside the normal object to allow access to the View object .
* /
2015-07-01 00:26:59 +02:00
views : {
day : app . classes . calendar . prototype . View . extend ( {
header : function ( state ) {
return egw . lang ( 'Day view' ) + ': ' + app . calendar . View . header . call ( this , state ) ;
} ,
etemplates : [ 'calendar.view' , 'calendar.todo' ] ,
start _date : function ( state ) {
var d = app . calendar . View . start _date . call ( this , state ) ;
state . date = app . calendar . date . toString ( d ) ;
return d ;
} ,
show _weekend : function ( state ) {
state . days = '1' ;
return app . calendar . View . show _weekend . call ( this , state ) ;
2015-07-22 01:45:38 +02:00
} ,
scroll : function ( delta )
{
var d = new Date ( app . calendar . state . date ) ;
d . setUTCDate ( d . getUTCDate ( ) + ( delta ) ) ;
return d ;
2015-07-01 00:26:59 +02:00
}
} ) ,
day4 : app . classes . calendar . prototype . View . extend ( {
header : function ( state ) {
return egw . lang ( 'Four days view' ) + ': ' + app . calendar . View . header . call ( this , state ) ;
} ,
end _date : function ( state ) {
var d = app . calendar . View . end _date . call ( this , state ) ;
state . days = '4' ;
d . setUTCHours ( 24 * 4 - 1 ) ;
d . setUTCMinutes ( 59 ) ;
d . setUTCSeconds ( 59 ) ;
d . setUTCMilliseconds ( 0 ) ;
return d ;
2015-08-19 02:08:22 +02:00
} ,
show _weekend : function ( state ) {
return true ;
2015-09-14 22:47:25 +02:00
} ,
scroll : function ( delta )
{
var d = new Date ( app . calendar . state . date ) ;
d . setUTCDate ( d . getUTCDate ( ) + ( 4 * delta ) ) ;
return d ;
2015-07-01 00:26:59 +02:00
}
} ) ,
week : app . classes . calendar . prototype . View . extend ( {
header : function ( state ) {
2015-08-19 02:08:22 +02:00
var formatDate = new Date ( state . first ) ;
return egw . lang ( 'Week view' ) + ': ' + egw . lang ( 'Week' ) + ' ' +
app . calendar . date . week _number ( state . first ) + ': ' +
app . calendar . date . long _date ( state . first , state . last )
2015-07-01 00:26:59 +02:00
} ,
start _date : function ( state ) {
2015-07-15 18:29:10 +02:00
return app . calendar . date . start _of _week ( app . calendar . View . start _date . call ( this , state ) ) ;
2015-07-01 00:26:59 +02:00
} ,
end _date : function ( state ) {
var d = app . calendar . date . start _of _week ( state . date || new Date ( ) ) ;
// Always 7 days, we just turn weekends on or off
d . setUTCHours ( 24 * 7 - 1 ) ;
d . setUTCMinutes ( 59 ) ;
d . setUTCSeconds ( 59 ) ;
d . setUTCMilliseconds ( 0 ) ;
state . days = '' + ( state . days >= 5 ? state . days : egw . preference ( 'days_in_weekview' , 'calendar' ) || 7 ) ;
return d ;
} ,
show _weekend : function ( state )
{
return parseInt ( state . days ) === 7 ;
}
} ) ,
weekN : app . classes . calendar . prototype . View . extend ( {
header : function ( state ) {
2015-08-19 02:08:22 +02:00
return egw . lang ( 'Week' ) + ' ' +
app . calendar . date . week _number ( state . first ) + ' - ' +
app . calendar . date . week _number ( state . last ) + ': ' +
app . calendar . date . long _date ( state . first , state . last )
2015-07-01 00:26:59 +02:00
} ,
start _date : function ( state ) {
return app . calendar . date . start _of _week ( state . date || new Date ( ) ) ;
} ,
end _date : function ( state ) {
state . days = '' + ( state . days >= 5 ? state . days : egw . preference ( 'days_in_weekview' , 'calendar' ) || 7 ) ;
var d = app . calendar . date . start _of _week ( state . date || new Date ( ) ) ;
// Always 7 days, we just turn weekends on or off
d . setUTCHours ( 24 * 7 - 1 ) ;
return d ;
2015-08-19 02:08:22 +02:00
} ,
granularity : function ( state ) {
2015-09-03 00:40:38 +02:00
return ( parseInt ( egw . preference ( 'multiple_weeks' , 'calendar' ) ) || 3 ) * app . calendar . View . granularity . call ( this , state ) ;
2015-07-15 15:16:31 +02:00
}
2015-07-01 00:26:59 +02:00
} ) ,
month : app . classes . calendar . prototype . View . extend ( {
header : function ( state )
{
var formatDate = new Date ( state . date ) ;
formatDate = new Date ( formatDate . valueOf ( ) + formatDate . getTimezoneOffset ( ) * 60 * 1000 ) ;
return egw . lang ( 'Month view' ) + ':' + egw . lang ( date ( 'F' , formatDate ) ) + ' ' + date ( 'Y' , formatDate ) ;
} ,
start _date : function ( state ) {
2015-07-15 15:16:31 +02:00
var d = app . calendar . View . start _date . call ( this , state ) ;
2015-07-01 00:26:59 +02:00
d . setUTCDate ( 1 ) ;
state . date = app . calendar . date . toString ( d ) ;
return app . calendar . date . start _of _week ( d ) ;
} ,
end _date : function ( state ) {
2015-07-15 15:16:31 +02:00
var d = app . calendar . View . end _date . call ( this , state ) ;
2015-07-01 00:26:59 +02:00
d = new Date ( d . getFullYear ( ) , d . getUTCMonth ( ) + 1 , 0 ) ;
var week _start = app . calendar . date . start _of _week ( d ) ;
if ( week _start < d ) week _start . setUTCHours ( 24 * 7 ) ;
week _start . setUTCHours ( week _start . getUTCHours ( ) - 1 ) ;
return week _start ;
2015-07-22 01:45:38 +02:00
} ,
2015-08-19 02:08:22 +02:00
granularity : function ( state ) {
return 120 ;
} ,
2015-07-22 01:45:38 +02:00
scroll : function ( delta )
{
var d = new Date ( app . calendar . state . date ) ;
d . setUTCMonth ( d . getUTCMonth ( ) + delta ) ;
return d ;
2015-07-15 15:16:31 +02:00
}
2015-07-01 00:26:59 +02:00
} ) ,
planner : app . classes . calendar . prototype . View . extend ( {
header : function ( state ) {
var startDate = new Date ( state . first ) ;
startDate = new Date ( startDate . valueOf ( ) + startDate . getTimezoneOffset ( ) * 60 * 1000 ) ;
var endDate = new Date ( state . last ) ;
endDate = new Date ( endDate . valueOf ( ) + endDate . getTimezoneOffset ( ) * 60 * 1000 ) ;
return egw . lang ( 'Planner view' ) + ': ' + date ( egw . preference ( 'dateformat' ) , startDate ) +
2015-08-11 17:35:54 +02:00
( startDate == endDate ? '' : ' - ' + date ( egw . preference ( 'dateformat' ) , endDate ) ) ;
2015-07-01 00:26:59 +02:00
} ,
etemplates : [ 'calendar.planner' ] ,
group _by : function ( state ) {
return state . cat _id ? state . cat _id : ( state . sortby ? state . sortby : 0 ) ;
} ,
start _date : function ( state ) {
var d = app . calendar . View . start _date . call ( this , state ) ;
if ( state . sortby && state . sortby === 'month' )
{
d . setUTCDate ( 1 ) ;
}
else if ( ! state . planner _days )
{
if ( d . getUTCDate ( ) < 15 )
{
d . setUTCDate ( 1 ) ;
return app . calendar . date . start _of _week ( d ) ;
}
else
{
return app . calendar . date . start _of _week ( d ) ;
}
}
return d ;
} ,
end _date : function ( state ) {
var d = app . calendar . View . end _date . call ( this , state ) ;
if ( state . sortby && state . sortby === 'month' )
{
d . setUTCDate ( 0 ) ;
d . setUTCFullYear ( d . getUTCFullYear ( ) + 1 ) ;
}
else if ( state . planner _days )
{
d . setUTCDate ( d . getUTCDate ( ) + parseInt ( state . planner _days ) - 1 ) ;
}
2015-08-06 19:12:34 +02:00
else if ( state . last )
2015-07-01 00:26:59 +02:00
{
2015-08-06 19:12:34 +02:00
d = new Date ( state . last ) ;
2015-07-01 00:26:59 +02:00
}
else if ( ! state . planner _days )
{
if ( d . getUTCDate ( ) < 15 )
{
d . setUTCDate ( 0 ) ;
d . setUTCMonth ( d . getUTCMonth ( ) + 1 ) ;
d = app . calendar . date . end _of _week ( d ) ;
}
else
{
d . setUTCMonth ( d . getUTCMonth ( ) + 1 ) ;
d = app . calendar . date . end _of _week ( d ) ;
}
}
return d ;
2015-08-06 19:12:34 +02:00
} ,
scroll : function ( delta )
{
2015-08-19 18:17:55 +02:00
var d = new Date ( app . calendar . state . date ) ;
// Yearly view, grouped by month - scroll 1 month
if ( app . calendar . state . sortby === 'month' )
{
d . setUTCMonth ( d . getUTCMonth ( ) + delta )
d . setUTCDate ( 1 ) ;
d . setUTCHours ( 0 ) ;
d . setUTCMinutes ( 0 ) ;
return d ;
}
2015-08-06 19:12:34 +02:00
// Need to set the day count, or auto date ranging takes over and
// makes things buggy
if ( app . calendar . state . first && app . calendar . state . last )
{
var diff = new Date ( app . calendar . state . last ) - new Date ( app . calendar . state . first ) ;
app . calendar . state . planner _days = Math . round ( diff / ( 1000 * 3600 * 24 ) ) ;
}
d . setUTCDate ( d . getUTCDate ( ) + ( app . calendar . state . planner _days * delta ) ) ;
if ( app . calendar . state . planner _days > 8 )
{
d = app . calendar . date . start _of _week ( d ) ;
}
return d ;
2015-07-01 00:26:59 +02:00
}
} ) ,
listview : app . classes . calendar . prototype . View . extend ( {
header : function ( ) { return egw . lang ( 'List view' ) ; } ,
etemplates : [ 'calendar.list' ]
} )
} }
) ;