2020-02-27 21:37:36 +01:00
"use strict" ;
2015-05-06 21:03:45 +02:00
/ *
* Egroupware Calendar event widget
* @ license http : //opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @ package etemplate
* @ subpackage api
* @ link http : //www.egroupware.org
* @ author Nathan Gray
* @ version $Id$
* /
2020-02-27 21:37:36 +01:00
var _ _extends = ( this && this . _ _extends ) || ( function ( ) {
var extendStatics = function ( d , b ) {
extendStatics = Object . setPrototypeOf ||
( { _ _proto _ _ : [ ] } instanceof Array && function ( d , b ) { d . _ _proto _ _ = b ; } ) ||
function ( d , b ) { for ( var p in b ) if ( b . hasOwnProperty ( p ) ) d [ p ] = b [ p ] ; } ;
return extendStatics ( d , b ) ;
} ;
return function ( d , b ) {
extendStatics ( d , b ) ;
function _ _ ( ) { this . constructor = d ; }
d . prototype = b === null ? Object . create ( b ) : ( _ _ . prototype = b . prototype , new _ _ ( ) ) ;
} ;
} ) ( ) ;
Object . defineProperty ( exports , "__esModule" , { value : true } ) ;
2015-05-06 21:03:45 +02:00
/ * e g w : u s e s
2020-02-27 21:37:36 +01:00
/ e t e m p l a t e / j s / e t 2 _ c o r e _ v a l u e W i d g e t ;
2015-05-06 21:03:45 +02:00
* /
2020-02-27 21:37:36 +01:00
var et2 _core _widget _1 = require ( "../../api/js/etemplate/et2_core_widget" ) ;
var et2 _core _valueWidget _1 = require ( "../../api/js/etemplate/et2_core_valueWidget" ) ;
var et2 _core _inheritance _1 = require ( "../../api/js/etemplate/et2_core_inheritance" ) ;
var et2 _core _DOMWidget _1 = require ( "../../api/js/etemplate/et2_core_DOMWidget" ) ;
var et2 _widget _daycol _1 = require ( "./et2_widget_daycol" ) ;
var et2 _widget _planner _row _1 = require ( "./et2_widget_planner_row" ) ;
2015-05-06 21:03:45 +02:00
/ * *
2016-01-13 23:07:09 +01:00
* Class for a single event , displayed in either the timegrid or planner view
*
* It is possible to directly provide all information directly , but calendar
* uses egw . data for caching , so ID is all that is needed .
*
* Note that there are several pieces of information that have 'ID' in them :
* - row _id - used by both et2 _calendar _event and the nextmatch to uniquely
* identify a particular entry or entry ocurrence
* - id - Recurring events may have their recurrence as a timestamp after their ID ,
* such as '194:1453318200' , or not . It ' s usually ( always ? ) the same as row ID .
* - app _id - the ID according to the source application . For calendar , this
* is the same as ID ( but always with the recurrence ) , for other apps this is
* usually just an integer . With app _id and app , you should be able to call
* egw . open ( ) and get the specific entry .
* - Events from other apps will have their app name prepended to their ID , such
* as 'infolog123' , so app _id and id will be different for these events
* - Cache ID is the same as other apps , and looks like 'calendar::<row_id>'
* - The DOM ID for the containing div is event _ < row _id >
*
* Events are expected to be added to either et2 _calendar _daycol or
* et2 _calendar _planner _row rather than either et2 _calendar _timegrid or
* et2 _calendar _planner directly .
2015-05-06 21:03:45 +02:00
*
2015-06-10 23:51:28 +02:00
* /
2020-02-27 21:37:36 +01:00
var et2 _calendar _event = /** @class */ ( function ( _super ) {
_ _extends ( et2 _calendar _event , _super ) ;
/ * *
* Constructor
* /
function et2 _calendar _event ( _parent , _attrs , _child ) {
var _this =
// Call the inherited constructor
_super . call ( this , _parent , _attrs , et2 _core _inheritance _1 . ClassWithAttributes . extendAttributes ( et2 _calendar _event . _attributes , _child || { } ) ) || this ;
_this . _need _actions _linked = false ;
var event = _this ;
// Main container
_this . div = jQuery ( document . createElement ( "div" ) )
. addClass ( "calendar_calEvent" )
. addClass ( _this . options . class )
. css ( 'width' , _this . options . width )
. on ( 'mouseenter' , function ( ) {
// Bind actions on first mouseover for faster creation
if ( event . _need _actions _linked ) {
event . _copy _parent _actions ( ) ;
}
// Tooltip
if ( ! event . _tooltipElem ) {
event . options . statustext _html = true ;
event . set _statustext ( event . _tooltip ( ) ) ;
if ( event . statustext ) {
return event . div . trigger ( 'mouseenter' ) ;
}
}
// Hacky to remove egw's tooltip border and let the mouse in
window . setTimeout ( function ( ) {
jQuery ( 'body .egw_tooltip' )
. css ( 'border' , 'none' )
. on ( 'mouseenter' , function ( ) {
event . div . off ( 'mouseleave.tooltip' ) ;
jQuery ( 'body.egw_tooltip' ) . remove ( ) ;
jQuery ( 'body' ) . append ( this ) ;
jQuery ( this ) . stop ( true ) . fadeTo ( 400 , 1 )
. on ( 'mouseleave' , function ( ) {
jQuery ( this ) . fadeOut ( '400' , function ( ) {
jQuery ( this ) . remove ( ) ;
// Set up to work again
event . set _statustext ( event . _tooltip ( ) ) ;
} ) ;
} ) ;
} ) ;
} , 105 ) ;
} ) ;
_this . title = jQuery ( document . createElement ( 'div' ) )
. addClass ( "calendar_calEventHeader" )
. appendTo ( _this . div ) ;
_this . body = jQuery ( document . createElement ( 'div' ) )
. addClass ( "calendar_calEventBody" )
. appendTo ( _this . div ) ;
_this . icons = jQuery ( document . createElement ( 'div' ) )
. addClass ( "calendar_calEventIcons" )
. appendTo ( _this . title ) ;
_this . setDOMNode ( _this . div [ 0 ] ) ;
return _this ;
}
et2 _calendar _event . prototype . doLoadingFinished = function ( ) {
_super . prototype . doLoadingFinished . call ( this ) ;
// Already know what is needed to hook to cache
if ( this . options . value && this . options . value . row _id ) {
egw . dataRegisterUID ( 'calendar::' + this . options . value . row _id , this . _UID _callback , this , this . getInstanceManager ( ) . execId , this . id ) ;
}
return true ;
} ;
et2 _calendar _event . prototype . destroy = function ( ) {
_super . prototype . destroy . call ( this ) ;
if ( this . _actionObject ) {
this . _actionObject . remove ( ) ;
this . _actionObject = null ;
}
this . div . off ( ) ;
this . title . remove ( ) ;
this . title = null ;
this . body . remove ( ) ;
this . body = null ;
this . icons = null ;
this . div . remove ( ) ;
this . div = null ;
jQuery ( 'body.egw_tooltip' ) . remove ( ) ;
// Unregister, or we'll continue to be notified...
if ( this . options . value ) {
var old _app _id = this . options . value . row _id ;
egw . dataUnregisterUID ( 'calendar::' + old _app _id , null , this ) ;
}
} ;
et2 _calendar _event . prototype . set _value = function ( _value ) {
// Un-register for updates
if ( this . options . value ) {
var old _id = this . options . value . row _id ;
if ( ! _value || ! _value . row _id || old _id !== _value . row _id ) {
egw . dataUnregisterUID ( 'calendar::' + old _id , null , this ) ;
}
}
this . options . value = _value ;
// Register for updates
var id = this . options . value . row _id ;
if ( ! old _id || old _id !== id ) {
egw . dataRegisterUID ( 'calendar::' + id , this . _UID _callback , this , this . getInstanceManager ( ) . execId , this . id ) ;
}
if ( _value && ! egw . dataHasUID ( 'calendar::' + id ) ) {
egw . dataStoreUID ( 'calendar::' + id , _value ) ;
}
} ;
/ * *
* Callback for changes in cached data
* /
et2 _calendar _event . prototype . _UID _callback = function ( event ) {
2020-03-30 18:28:48 +02:00
// Copy to avoid changes, which may cause nm problems
var value = event === null ? null : jQuery . extend ( { } , event ) ;
var parent = this . getParent ( ) ;
var parent _owner = parent . getDOMNode ( parent ) . dataset [ 'owner' ] || parent . getParent ( ) . options . owner ;
2020-05-19 17:02:03 +02:00
if ( parent _owner . indexOf ( ',' ) >= 0 ) {
2020-04-20 20:00:42 +02:00
parent _owner = parent _owner . split ( ',' ) ;
}
2020-03-30 18:28:48 +02:00
// Make sure id is a string, check values
if ( value ) {
this . _values _check ( value ) ;
}
// Check for changing days in the grid view
if ( ! this . _sameday _check ( value ) || ! this . _status _check ( value , app . calendar . getState ( ) . status _filter , parent _owner ) ) {
// May need to update parent to remove out-of-view events
parent . removeChild ( this ) ;
if ( event === null && parent && parent . instanceOf ( et2 _widget _daycol _1 . et2 _calendar _daycol ) ) {
parent . _out _of _view ( ) ;
}
// This should now cease to exist, as new events have been created
this . destroy ( ) ;
return ;
}
// Copy to avoid changes, which may cause nm problems
this . options . value = jQuery . extend ( { } , value ) ;
if ( this . getParent ( ) . options . date ) {
this . options . value . date = this . getParent ( ) . options . date ;
}
// Let parent position - could also be et2_calendar_planner_row
this . getParent ( ) . position _event ( this ) ;
// Parent may remove this if the date isn't the same
if ( this . getParent ( ) ) {
this . _update ( ) ;
2020-02-27 21:37:36 +01:00
}
} ;
/ * *
* Draw the event
* /
et2 _calendar _event . prototype . _update = function ( ) {
// Update to reflect new information
var event = this . options . value ;
var id = event . row _id ? event . row _id : event . id + ( event . recur _type ? ':' + event . recur _date : '' ) ;
var formatted _start = event . start . toJSON ( ) ;
this . set _id ( 'event_' + id ) ;
if ( this . _actionObject ) {
this . _actionObject . id = 'calendar::' + id ;
}
this . _need _actions _linked = ! this . options . readonly ;
// Make sure category stuff is there
// Fake it to use the cache / call - if already there, these will return
// immediately.
var im = this . getInstanceManager ( ) ;
et2 _selectbox . cat _options ( {
_type : 'select-cat' ,
getInstanceManager : function ( ) { return im ; }
} , { application : event . app || 'calendar' } ) ;
// Need cleaning? (DnD helper removes content)
// @ts-ignore
if ( ! this . div . has ( this . title ) . length ) {
this . div
. empty ( )
. append ( this . title )
. append ( this . body ) ;
}
if ( ! this . getParent ( ) . options . readonly && ! this . options . readonly && this . div . droppable ( 'instance' ) ) {
this . div
// Let timegrid always get the drag
. droppable ( 'option' , 'greedy' , false ) ;
}
// DOM nodes
this . div
// Set full day flag
. attr ( 'data-full_day' , event . whole _day )
// Put everything we need for basic interaction here, so it's available immediately
. attr ( 'data-id' , event . id )
. attr ( 'data-app' , event . app || 'calendar' )
. attr ( 'data-app_id' , event . app _id )
. attr ( 'data-start' , formatted _start )
. attr ( 'data-owner' , event . owner )
. attr ( 'data-recur_type' , event . recur _type )
. attr ( 'data-resize' , event . whole _day ? 'WD' : '' + ( event . recur _type ? 'S' : '' ) )
. attr ( 'data-priority' , event . priority )
// Remove any category classes
. removeClass ( function ( index , css ) {
return ( css . match ( /(^|\s)cat_\S+/g ) || [ ] ) . join ( ' ' ) ;
} )
// Remove any status classes
. removeClass ( function ( index , css ) {
return ( css . match ( /calendar_calEvent\S+/g ) || [ ] ) . join ( ' ' ) ;
} )
. removeClass ( 'calendar_calEventSmall' )
. addClass ( event . class )
. toggleClass ( 'calendar_calEventPrivate' , typeof event . private !== 'undefined' && event . private ) ;
this . options . class = event . class ;
var status _class = this . _status _class ( ) ;
// Add category classes, if real categories are set
if ( event . category && event . category != '0' ) {
var cats = event . category . split ( ',' ) ;
for ( var i = 0 ; i < cats . length ; i ++ ) {
this . div . addClass ( 'cat_' + cats [ i ] ) ;
}
}
this . div . toggleClass ( 'calendar_calEventUnknown' , event . participants [ egw . user ( 'account_id' ) ] ? event . participants [ egw . user ( 'account_id' ) ] [ 0 ] === 'U' : false ) ;
this . div . addClass ( status _class ) ;
this . body . toggleClass ( 'calendar_calEventBodySmall' , event . whole _day _on _top || false ) ;
// Header
var title = ! event . is _private ? egw . htmlspecialchars ( event [ 'title' ] ) : egw . lang ( 'private' ) ;
this . title
. html ( '<span class="calendar_calTimespan">' + this . _get _timespan ( event ) + '<br /></span>' )
. append ( '<span class="calendar_calEventTitle">' + title + '</span>' ) ;
// Colors - don't make them transparent if there is no color
// @ts-ignore
if ( jQuery . Color ( "rgba(0,0,0,0)" ) . toRgbaString ( ) != jQuery . Color ( this . div , 'background-color' ) . toRgbaString ( ) ) {
// Most statuses use colored borders
this . div . css ( 'border-color' , this . div . css ( 'background-color' ) ) ;
}
this . icons . appendTo ( this . title )
. html ( this . _icons ( ) . join ( '' ) ) ;
// Body
if ( event . whole _day _on _top ) {
this . body . html ( title ) ;
}
else {
// @ts-ignore
var start _time = jQuery . datepicker . formatTime ( egw . preference ( "timeformat" ) === "12" ? "h:mmtt" : "HH:mm" , {
hour : event . start _m / 60 ,
minute : event . start _m % 60 ,
seconds : 0 ,
timezone : 0
} , { "ampm" : ( egw . preference ( "timeformat" ) === "12" ) } ) . trim ( ) ;
this . body
. html ( '<span class="calendar_calEventTitle">' + title + '</span>' )
. append ( '<span class="calendar_calTimespan">' + start _time + '</span>' ) ;
if ( this . options . value . description . trim ( ) ) {
this . body
. append ( '<p>' + egw . htmlspecialchars ( this . options . value . description ) + '</p>' ) ;
}
}
// Clear tooltip for regeneration
this . set _statustext ( '' ) ;
// Height specific section
// This can take an unreasonable amount of time if parent is hidden
if ( jQuery ( this . getParent ( ) . getDOMNode ( this ) ) . is ( ':visible' ) ) {
this . _small _size ( ) ;
}
} ;
/ * *
* Calculate display variants for when event is too short for full display
*
* Display is based on the number of visible lines , calculated off the header
* height :
* 1 - show just the event title , with ellipsis
* 2 - Show timespan and title , with ellipsis
* > 4 - Show description as well , truncated to fit
* /
et2 _calendar _event . prototype . _small _size = function ( ) {
if ( this . options . value . whole _day _on _top )
return ;
// Skip for planner view, it's always small
if ( this . getParent ( ) && this . getParent ( ) . instanceOf ( et2 _widget _planner _row _1 . et2 _calendar _planner _row ) )
return ;
// Pre-calculation reset
this . div . removeClass ( 'calendar_calEventSmall' ) ;
this . body . css ( 'height' , 'auto' ) ;
var line _height = parseFloat ( this . div . css ( 'line-height' ) ) ;
var visible _lines = Math . floor ( this . div . innerHeight ( ) / line _height ) ;
if ( ! this . title . height ( ) ) {
// Handle sizing while hidden, such as when calendar is not the active tab
visible _lines = Math . floor ( egw . getHiddenDimensions ( this . div ) . h / egw . getHiddenDimensions ( this . title ) . h ) ;
}
visible _lines = Math . max ( 1 , visible _lines ) ;
if ( this . getParent ( ) && this . getParent ( ) . instanceOf ( et2 _widget _daycol _1 . et2 _calendar _daycol ) ) {
this . div . toggleClass ( 'calendar_calEventSmall' , visible _lines < 4 ) ;
this . div
. attr ( 'data-visible_lines' , visible _lines ) ;
}
else if ( this . getParent ( ) && this . getParent ( ) . instanceOf ( et2 _widget _planner _row _1 . et2 _calendar _planner _row ) ) {
// Less than 8 hours is small
this . div . toggleClass ( 'calendar_calEventSmall' , this . options . value . end . valueOf ( ) - this . options . value . start . valueOf ( ) < 28800000 ) ;
}
if ( this . body . height ( ) > this . div . height ( ) - this . title . height ( ) && visible _lines >= 4 ) {
this . body . css ( 'height' , Math . floor ( ( visible _lines - 1 ) * line _height - this . title . height ( ) ) + 'px' ) ;
}
else {
this . body . css ( 'height' , '' ) ;
}
} ;
/ * *
* Examines the participants & returns CSS classname for status
*
* @ returns { String }
* /
et2 _calendar _event . prototype . _status _class = function ( ) {
var status _class = 'calendar_calEventAllAccepted' ;
for ( var id in this . options . value . participants ) {
var status _1 = this . options . value . participants [ id ] ;
status _1 = et2 _calendar _event . split _status ( status _1 ) ;
switch ( status _1 ) {
case 'A' :
case '' : // app without status
break ;
case 'U' :
status _class = 'calendar_calEventSomeUnknown' ;
return status _class ; // break for
default :
status _class = 'calendar_calEventAllAnswered' ;
break ;
}
}
return status _class ;
} ;
/ * *
* Create tooltip shown on hover
*
* @ return { String }
* /
et2 _calendar _event . prototype . _tooltip = function ( ) {
if ( ! this . div || ! this . options . value || ! this . options . value . app _id )
return '' ;
var border = this . div . css ( 'borderTopColor' ) ;
var bg _color = this . div . css ( 'background-color' ) ;
var header _color = this . title . css ( 'color' ) ;
var timespan = this . _get _timespan ( this . options . value ) ;
var parent = this . getParent ( ) instanceof et2 _widget _daycol _1 . et2 _calendar _daycol ? this . getParent ( ) : this . getParent ( ) ;
parent . date _helper . set _value ( this . options . value . start . valueOf ? new Date ( this . options . value . start ) : this . options . value . start ) ;
var start = parent . date _helper . input _date . val ( ) ;
parent . date _helper . set _value ( this . options . value . end . valueOf ? new Date ( this . options . value . end ) : this . options . value . end ) ;
var end = parent . date _helper . input _date . val ( ) ;
var times = ! this . options . value . multiday ?
'<span class="calendar_calEventLabel">' + this . egw ( ) . lang ( 'Time' ) + '</span>:' + timespan :
'<span class="calendar_calEventLabel">' + this . egw ( ) . lang ( 'Start' ) + '</span>:' + start + ' ' +
'<span class="calendar_calEventLabel">' + this . egw ( ) . lang ( 'End' ) + '</span>:' + end ;
var cat _label = '' ;
if ( this . options . value . category ) {
var cat = et2 _createWidget ( 'select-cat' , { 'readonly' : true } , this ) ;
cat . set _value ( this . options . value . category ) ;
var cat _label _1 = this . options . value . category . indexOf ( ',' ) <= 0 ? cat . span . text ( ) : [ ] ;
if ( typeof cat _label _1 != 'string' ) {
cat . span . children ( ) . each ( function ( ) {
cat _label _1 . push ( jQuery ( this ) . text ( ) ) ;
} ) ;
cat _label _1 = cat _label _1 . join ( ', ' ) ;
}
cat . destroy ( ) ;
}
2020-04-24 18:54:08 +02:00
// Location + Videoconference
var location = '' ;
if ( this . options . value . location || this . options . value [ '##videoconference' ] ) {
location += '<p><span class="calendar_calEventLabel">' + this . egw ( ) . lang ( 'Location' ) + '</span>:' +
egw . htmlspecialchars ( this . options . value . location ) ;
if ( this . options . value [ '##videoconference' ] ) {
// Click handler is set in _bind_videoconference()
location += ( this . options . value . location . trim ( ) ? '<br />' : '' ) +
2020-05-06 22:07:01 +02:00
'<span data-videoconference="' + this . options . value [ '##videoconference' ] + '">' + this . egw ( ) . lang ( 'Video conference' ) +
2020-04-24 18:54:08 +02:00
'<img src="' + this . egw ( ) . image ( 'videoconference' , 'calendar' ) + '"/></span>' ;
this . _bind _videoconference ( ) ;
}
location += '</p>' ;
}
// Participants
2020-02-27 21:37:36 +01:00
var participants = '' ;
if ( this . options . value . participant _types [ '' ] ) {
participants += this . options . value . participant _types [ '' ] . join ( "<br />" ) ;
}
for ( var type _name in this . options . value . participant _types ) {
if ( type _name ) {
participants += '</p><p><span class="calendar_calEventLabel">' + type _name + '</span>:<br />' ;
participants += this . options . value . participant _types [ type _name ] . join ( "<br />" ) ;
}
}
return '<div class="calendar_calEventTooltip ' + this . _status _class ( ) + ' ' + this . options . class +
'" style="border-color: ' + border + '; background-color: ' + bg _color + ';">' +
'<div class="calendar_calEventHeaderSmall">' +
'<font style="color:' + header _color + '">' + timespan + '</font>' +
this . icons [ 0 ] . outerHTML +
'</div>' +
'<div class="calendar_calEventBody">' +
'<p style="margin: 0px;">' +
'<span class="calendar_calEventTitle">' + egw . htmlspecialchars ( this . options . value . title ) + '</span><br>' +
egw . htmlspecialchars ( this . options . value . description ) + '</p>' +
'<p style="margin: 2px 0px;">' + times + '</p>' +
2020-04-24 18:54:08 +02:00
location +
2020-02-27 21:37:36 +01:00
( cat _label ? '<p><span class="calendar_calEventLabel">' + this . egw ( ) . lang ( 'Category' ) + '</span>:' + cat _label + '</p>' : '' ) +
'<p><span class="calendar_calEventLabel">' + this . egw ( ) . lang ( 'Participants' ) + '</span>:<br />' +
participants + '</p>' + this . _participant _summary ( this . options . value . participants ) +
'</div>' +
'</div>' ;
} ;
/ * *
* Generate participant summary line
*
* @ returns { String }
* /
et2 _calendar _event . prototype . _participant _summary = function ( participants ) {
if ( Object . keys ( this . options . value . participants ) . length < 2 ) {
return '' ;
}
var participant _status = { A : 0 , R : 0 , T : 0 , U : 0 , D : 0 } ;
var status _label = { A : 'accepted' , R : 'rejected' , T : 'tentative' , U : 'unknown' , D : 'delegated' } ;
var participant _summary = Object . keys ( this . options . value . participants ) . length + ' ' + this . egw ( ) . lang ( 'Participants' ) + ': ' ;
var status _totals = [ ] ;
for ( var id in this . options . value . participants ) {
var status = this . options . value . participants [ id ] . substr ( 0 , 1 ) ;
participant _status [ status ] ++ ;
}
for ( var status _2 in participant _status ) {
if ( participant _status [ status _2 ] > 0 ) {
status _totals . push ( participant _status [ status _2 ] + ' ' + this . egw ( ) . lang ( status _label [ status _2 ] ) ) ;
}
}
return participant _summary + status _totals . join ( ', ' ) ;
} ;
/ * *
* Get actual icons from list
* /
et2 _calendar _event . prototype . _icons = function ( ) {
var icons = [ ] ;
if ( this . options . value . is _private ) {
// Hide everything
icons . push ( '<img src="' + this . egw ( ) . image ( 'private' , 'calendar' ) + '"/>' ) ;
}
else {
if ( this . options . value . app !== 'calendar' ) {
icons . push ( '<img src="' + this . egw ( ) . image ( 'navbar' , this . options . value . app ) + '" title="' + this . egw ( ) . lang ( this . options . value . app ) + '"/>' ) ;
}
if ( this . options . value . priority == 3 ) {
icons . push ( '<img src="' + this . egw ( ) . image ( 'high' , 'calendar' ) + '" title="' + this . egw ( ) . lang ( 'high priority' ) + '"/>' ) ;
}
if ( this . options . value . public == '0' ) {
// Show private flag
icons . push ( '<img src="' + this . egw ( ) . image ( 'private' , 'calendar' ) + '"/>' ) ;
}
if ( this . options . value [ 'recur_type' ] ) {
icons . push ( '<img src="' + this . egw ( ) . image ( 'recur' , 'calendar' ) + '" title="' + this . egw ( ) . lang ( 'recurring event' ) + '"/>' ) ;
}
// icons for single user, multiple users or group(s) and resources
var single = '<img src="' + this . egw ( ) . image ( 'single' , 'calendar' ) + '" title="' + '"/>' ;
var multiple = '<img src="' + this . egw ( ) . image ( 'users' , 'calendar' ) + '" title="' + '"/>' ;
for ( var uid in this . options . value [ 'participants' ] ) {
// @ts-ignore
if ( Object . keys ( this . options . value . participants ) . length == 1 && ! isNaN ( uid ) ) {
icons . push ( single ) ;
break ;
}
// @ts-ignore
if ( ! isNaN ( uid ) && icons . indexOf ( multiple ) === - 1 ) {
icons . push ( multiple ) ;
}
/ *
* TODO : resource icons
elseif ( ! isset ( $icons [ $uid [ 0 ] ] ) && isset ( $this - > bo - > resources [ $uid [ 0 ] ] ) && isset ( $this - > bo - > resources [ $uid [ 0 ] ] [ 'icon' ] ) )
{
$icons [ $uid [ 0 ] ] = html : : image ( $this - > bo - > resources [ $uid [ 0 ] ] [ 'app' ] ,
( $this - > bo - > resources [ $uid [ 0 ] ] [ 'icon' ] ? $this - > bo - > resources [ $uid [ 0 ] ] [ 'icon' ] : 'navbar' ) ,
lang ( $this - > bo - > resources [ $uid [ 0 ] ] [ 'app' ] ) ,
'width="16px" height="16px"' ) ;
}
* /
}
if ( this . options . value . alarm && ! jQuery . isEmptyObject ( this . options . value . alarm ) && ! this . options . value . is _private ) {
icons . push ( '<img src="' + this . egw ( ) . image ( 'alarm' , 'calendar' ) + '" title="' + this . egw ( ) . lang ( 'alarm' ) + '"/>' ) ;
}
if ( this . options . value . participants [ egw . user ( 'account_id' ) ] && this . options . value . participants [ egw . user ( 'account_id' ) ] [ 0 ] == 'U' ) {
icons . push ( '<img src="' + this . egw ( ) . image ( 'needs-action' , 'calendar' ) + '" title="' + this . egw ( ) . lang ( 'Needs action' ) + '"/>' ) ;
}
2020-04-23 22:57:19 +02:00
if ( this . options . value [ "##videoconference" ] ) {
2020-05-06 22:07:01 +02:00
icons . push ( '<img src="' + this . egw ( ) . image ( 'videoconference' , 'calendar' ) + '" title="' + this . egw ( ) . lang ( 'video conference' ) + '"/>' ) ;
2020-04-23 22:57:19 +02:00
}
2020-02-27 21:37:36 +01:00
}
// Always include non-blocking, regardless of privacy
if ( this . options . value . non _blocking ) {
icons . push ( '<img src="' + this . egw ( ) . image ( 'nonblocking' , 'calendar' ) + '" title="' + this . egw ( ) . lang ( 'non blocking' ) + '"/>' ) ;
}
return icons ;
} ;
2020-04-24 18:54:08 +02:00
/ * *
* Bind the click handler for opening the video conference
*
* Tooltips are placed in the DOM directly in the body , managed by egw .
* /
et2 _calendar _event . prototype . _bind _videoconference = function ( ) {
var vc _event = 'click.calendar_videoconference' ;
jQuery ( 'body' ) . off ( vc _event )
. on ( vc _event , '[data-videoconference]' , function ( event ) {
app . calendar . joinVideoConference ( this . dataset . videoconference ) ;
} ) ;
} ;
2020-02-27 21:37:36 +01:00
/ * *
* Get a text representation of the timespan of the event . Either start
* - end , or 'all day'
*
* @ param { Object } event Event to get the timespan for
* @ param { number } event . start _m Event start , in minutes from midnight
* @ param { number } event . end _m Event end , in minutes from midnight
*
* @ return { string } Timespan
* /
et2 _calendar _event . prototype . _get _timespan = function ( event ) {
var timespan = '' ;
if ( event [ 'start_m' ] === 0 && event [ 'end_m' ] >= 24 * 60 - 1 ) {
if ( event [ 'end_m' ] > 24 * 60 ) {
// @ts-ignore
timespan = jQuery . datepicker . formatTime ( egw . preference ( "timeformat" ) === "12" ? "h:mmtt" : "HH:mm" , {
hour : event . start _m / 60 ,
minute : event . start _m % 60 ,
seconds : 0 ,
timezone : 0
} , { "ampm" : ( egw . preference ( "timeformat" ) === "12" ) }
// @ts-ignore
) . trim ( ) + ' - ' + jQuery . datepicker . formatTime ( egw . preference ( "timeformat" ) === "12" ? "h:mmtt" : "HH:mm" , {
hour : event . end _m / 60 ,
minute : event . end _m % 60 ,
seconds : 0 ,
timezone : 0
} , { "ampm" : ( egw . preference ( "timeformat" ) === "12" ) } ) . trim ( ) ;
}
else {
timespan = this . egw ( ) . lang ( 'Whole day' ) ;
}
}
else {
var duration = event . multiday ?
( event . end - event . start ) / 60000 :
( event . end _m - event . start _m ) ;
duration = Math . floor ( duration / 60 ) + this . egw ( ) . lang ( 'h' ) + ( duration % 60 ? duration % 60 : '' ) ;
// @ts-ignore
timespan = jQuery . datepicker . formatTime ( egw . preference ( "timeformat" ) === "12" ? "h:mmtt" : "HH:mm" , {
hour : event . start _m / 60 ,
minute : event . start _m % 60 ,
seconds : 0 ,
timezone : 0
} , { "ampm" : ( egw . preference ( "timeformat" ) === "12" ) } ) . trim ( ) ;
// @ts-ignore
timespan += ' - ' + jQuery . datepicker . formatTime ( egw . preference ( "timeformat" ) === "12" ? "h:mmtt" : "HH:mm" , {
hour : event . end _m / 60 ,
minute : event . end _m % 60 ,
seconds : 0 ,
timezone : 0
} , { "ampm" : ( egw . preference ( "timeformat" ) === "12" ) } ) . trim ( ) ;
timespan += ': ' + duration ;
}
return timespan ;
} ;
/ * *
* Make sure event data has all proper values , and format them as expected
* @ param { Object } event
* /
et2 _calendar _event . prototype . _values _check = function ( event ) {
// Make sure ID is a string
if ( event . id ) {
event . id = '' + event . id ;
}
// Parent might be a daycol or a planner_row
var parent = this . getParent ( ) ;
// Use dates as objects
if ( typeof event . start !== 'object' ) {
parent . date _helper . set _value ( event . start ) ;
event . start = new Date ( parent . date _helper . getValue ( ) ) ;
}
if ( typeof event . end !== 'object' ) {
parent . date _helper . set _value ( event . end ) ;
event . end = new Date ( parent . date _helper . getValue ( ) ) ;
}
// We need minutes for durations
if ( typeof event . start _m === 'undefined' ) {
event . start _m = event . start . getUTCHours ( ) * 60 + event . start . getUTCMinutes ( ) ;
event . end _m = event . end . getUTCHours ( ) * 60 + event . end . getUTCMinutes ( ) ;
}
if ( typeof event . multiday === 'undefined' ) {
event . multiday = ( event . start . getUTCFullYear ( ) !== event . end . getUTCFullYear ( ) ||
event . start . getUTCMonth ( ) !== event . end . getUTCMonth ( ) ||
event . start . getUTCDate ( ) != event . end . getUTCDate ( ) ) ;
}
if ( ! event . start . getUTCHours ( ) && ! event . start . getUTCMinutes ( ) && event . end . getUTCHours ( ) == 23 && event . end . getUTCMinutes ( ) == 59 ) {
event . whole _day _on _top = ( event . non _blocking && event . non _blocking != '0' ) ;
}
} ;
/ * *
* Check to see if the provided event information is for the same date as
* what we ' re currently expecting , and that it has not been changed .
*
* If the date has changed , we adjust the associated daywise caches to move
* the event ' s ID to where it should be . This check allows us to be more
* directly reliant on the data cache , and less on any other control logic
* elsewhere first .
*
* @ param { Object } event Map of event data from cache
* @ param { string } event . date For non - recurring , single day events , this is
* the date the event is on .
* @ param { string } event . start Start of the event ( used for multi - day events )
* @ param { string } event . end End of the event ( used for multi - day events )
*
* @ return { Boolean } Provided event data is for the same date
* /
et2 _calendar _event . prototype . _sameday _check = function ( event ) {
// Event somehow got orphaned, or deleted
if ( ! this . getParent ( ) || event === null ) {
return false ;
}
// Also check participants against owner
var owner _match = et2 _calendar _event . owner _check ( event , this . getParent ( ) ) ;
// Simple, same day
if ( owner _match && this . options . value . date && event . date == this . options . value . date ) {
return true ;
}
// Multi-day non-recurring event spans days - date does not match
var event _start = new Date ( event . start ) ;
var event _end = new Date ( event . end ) ;
var parent = this . getParent ( ) ;
if ( owner _match && ( parent instanceof et2 _widget _daycol _1 . et2 _calendar _daycol ) && parent . getDate ( ) >= event _start && parent . getDate ( ) <= event _end ) {
return true ;
}
// Delete all old actions
if ( this . _actionObject ) {
this . _actionObject . clear ( ) ;
this . _actionObject . unregisterActions ( ) ;
this . _actionObject = null ;
}
// Update daywise caches
2020-03-30 18:28:48 +02:00
var new _cache _id = CalendarApp . _daywise _cache _id ( event . date , this . getParent ( ) . options . owner ) ;
var new _daywise = egw . dataGetUIDdata ( new _cache _id ) ;
new _daywise = new _daywise && new _daywise . data ? new _daywise . data : [ ] ;
var old _cache _id = '' ;
if ( this . options . value && this . options . value . date ) {
old _cache _id = CalendarApp . _daywise _cache _id ( this . options . value . date , parent . options . owner ) ;
}
if ( new _cache _id != old _cache _id ) {
var old _daywise = egw . dataGetUIDdata ( old _cache _id ) ;
old _daywise = old _daywise && old _daywise . data ? old _daywise . data : [ ] ;
old _daywise . splice ( old _daywise . indexOf ( this . options . value . row _id ) , 1 ) ;
egw . dataStoreUID ( old _cache _id , old _daywise ) ;
if ( new _daywise . indexOf ( event . row _id ) < 0 ) {
new _daywise . push ( event . row _id ) ;
}
if ( egw . dataHasUID ( new _cache _id ) ) {
egw . dataStoreUID ( new _cache _id , new _daywise ) ;
}
}
return false ;
} ;
/ * *
* Check that the event passes the given status filter .
* Status filter is set in the sidebox and used when fetching several events , but if user changes their status
* for an event , it may no longer match and have to be removed .
*
* @ param event
* @ param filter
2020-04-23 22:15:08 +02:00
* @ param owner The owner of the target / parent , not the event owner
2020-03-30 18:28:48 +02:00
* @ private
* /
et2 _calendar _event . prototype . _status _check = function ( event , filter , owner ) {
2020-04-23 22:15:08 +02:00
var _a ;
2020-03-30 18:28:48 +02:00
if ( ! owner || ! event ) {
return false ;
}
// If we're doing a bunch, just one passing is enough
if ( typeof owner !== "string" ) {
var pass = false ;
for ( var j = 0 ; j < owner . length && pass == false ; j ++ ) {
pass = pass || this . _status _check ( event , filter , owner [ j ] ) ;
}
return pass ;
}
// Show also events just owned by selected user
2020-03-31 18:14:41 +02:00
// Group members can be owner too, those get handled when we check group memberships below
if ( filter == 'owner' && owner == event . owner ) {
return true ;
2020-03-30 18:28:48 +02:00
}
// Get the relevant participant
var participant = event . participants [ owner ] ;
// If filter says don't look in groups, skip it all
if ( ! participant && filter === 'no-enum-groups' ) {
return false ;
}
// Couldn't find the current owner in the participant list, check groups & resources
if ( ! participant ) {
var options = null ;
if ( app . calendar && app . calendar . sidebox _et2 && app . calendar . sidebox _et2 . getWidgetById ( 'owner' ) ) {
options = app . calendar . sidebox _et2 . getWidgetById ( 'owner' ) . taglist . getSelection ( ) ;
}
if ( ( isNaN ( parseInt ( owner ) ) || parseInt ( owner ) < 0 ) && options && typeof options . find == "function" ) {
var resource = options . find ( function ( element ) {
2020-05-06 19:00:47 +02:00
return element . id == owner ;
2020-03-30 18:28:48 +02:00
} ) || { } ;
2020-05-06 19:00:47 +02:00
var matching _participant = typeof resource . resources == "undefined" ?
resource : ( _a = resource ) === null || _a === void 0 ? void 0 : _a . resources . filter ( function ( id ) { return typeof event . participants [ id ] != "undefined" ; } ) ;
2020-04-23 22:15:08 +02:00
if ( matching _participant . length > 0 ) {
2020-03-30 18:28:48 +02:00
return this . _status _check ( event , filter , matching _participant ) ;
}
2020-05-06 19:31:54 +02:00
else if ( filter == 'owner' && resource && resource . resources && resource . resources . indexOf ( event . owner ) ) {
2020-04-23 22:15:08 +02:00
// owner param was a group but event is owned by someone in that group
return true ;
}
2020-03-30 18:28:48 +02:00
}
}
var status = et2 _calendar _event . split _status ( participant ) ;
switch ( filter ) {
default :
case 'all' :
return true ;
case 'default' : // Show all status, but rejected
return status !== 'R' ;
case 'accepted' : //Show only accepted events
return status === 'A' ;
case 'unknown' : // Show only invitations, not yet accepted or rejected
return status === 'U' ;
case 'tentative' : // Show only tentative accepted events
return status === 'T' ;
case 'delegated' : // Show only delegated events
return status === 'D' ;
case 'rejected' : // Show only rejected events
return status === 'R' ;
// Handled above
//case 'owner': // Show also events just owned by selected user
case 'hideprivate' : // Show all events, as if they were private
// handled server-side
return true ;
case 'showonlypublic' : // Show only events flagged as public, -not checked as private
return event . public == '1' ;
// Handled above
// case 'no-enum-groups': // Do not include events of group members
case 'not-unknown' : // Show all status, but unknown
return status !== 'U' ;
case 'deleted' : // Show events that have been deleted
return event . deleted ;
}
} ;
et2 _calendar _event . prototype . attachToDOM = function ( ) {
var result = _super . prototype . attachToDOM . call ( this ) ;
// Remove the binding for the click handler, unless there's something
// custom here.
if ( ! this . onclick ) {
jQuery ( this . node ) . off ( "click" ) ;
}
return result ;
} ;
/ * *
* Click handler calling custom handler set via onclick attribute to this . onclick .
* All other handling is done by the timegrid widget .
*
* @ param { Event } _ev
* @ returns { boolean }
* /
et2 _calendar _event . prototype . click = function ( _ev ) {
var result = true ;
if ( typeof this . onclick == 'function' ) {
2020-02-27 21:37:36 +01:00
// Make sure function gets a reference to the widget, splice it in as 2. argument if not
var args = Array . prototype . slice . call ( arguments ) ;
if ( args . indexOf ( this ) == - 1 )
args . splice ( 1 , 0 , this ) ;
result = this . onclick . apply ( this , args ) ;
}
return result ;
} ;
/ * *
* Show the recur prompt for this event
*
* Calls et2 _calendar _event . recur _prompt with this event ' s value .
*
* @ param { et2 _calendar _event ~ prompt _callback } callback
* @ param { Object } [ extra _data ]
* /
et2 _calendar _event . prototype . recur _prompt = function ( callback , extra _data ) {
et2 _calendar _event . recur _prompt ( this . options . value , callback , extra _data ) ;
} ;
/ * *
* Show the series split prompt for this event
*
* Calls et2 _calendar _event . series _split _prompt with this event ' s value .
*
* @ param { et2 _calendar _event ~ prompt _callback } callback
* /
et2 _calendar _event . prototype . series _split _prompt = function ( callback ) {
et2 _calendar _event . series _split _prompt ( this . options . value , this . options . value . recur _date , callback ) ;
} ;
/ * *
* Copy the actions set on the parent , apply them to self
*
* This can take a while to do , so we try to do it only when needed - on mouseover
* /
et2 _calendar _event . prototype . _copy _parent _actions = function ( ) {
// Copy actions set in parent
if ( ! this . options . readonly && ! this . getParent ( ) . options . readonly ) {
var action _parent = this ;
while ( action _parent != null && ! action _parent . options . actions &&
! ( action _parent instanceof et2 _container ) ) {
action _parent = action _parent . getParent ( ) ;
}
try {
this . _link _actions ( action _parent . options . actions || { } ) ;
this . _need _actions _linked = false ;
}
catch ( e ) {
// something went wrong, but keep quiet about it
}
}
} ;
/ * *
* Link the actions to the DOM nodes / widget bits .
*
* @ param { object } actions { ID : { attributes . . } + } map of egw action information
* /
et2 _calendar _event . prototype . _link _actions = function ( actions ) {
if ( ! this . _actionObject ) {
// Get the top level element - timegrid or so
var objectManager = this . getParent ( ) . _actionObject || this . getParent ( ) . getParent ( ) . _actionObject ||
egw _getAppObjectManager ( true ) . getObjectById ( this . getParent ( ) . getParent ( ) . getParent ( ) . id ) || egw _getAppObjectManager ( true ) ;
this . _actionObject = objectManager . getObjectById ( 'calendar::' + this . options . value . row _id ) ;
}
if ( this . _actionObject == null ) {
// Add a new container to the object manager which will hold the widget
// objects
this . _actionObject = objectManager . insertObject ( false , new egwActionObject ( 'calendar::' + this . options . value . row _id , objectManager , et2 _calendar _event . et2 _event _action _object _impl ( this , this . getDOMNode ( ) ) , this . _actionManager || objectManager . manager . getActionById ( 'calendar::' + this . options . value . row _id ) || objectManager . manager ) ) ;
}
else {
this . _actionObject . setAOI ( et2 _calendar _event . et2 _event _action _object _impl ( this , this . getDOMNode ( this ) ) ) ;
}
// Delete all old objects
this . _actionObject . clear ( ) ;
this . _actionObject . unregisterActions ( ) ;
// Go over the widget & add links - this is where we decide which actions are
// 'allowed' for this widget at this time
var action _links = this . _get _action _links ( actions ) ;
action _links . push ( 'egw_link_drag' ) ;
action _links . push ( 'egw_link_drop' ) ;
if ( this . _actionObject . parent . getActionLink ( 'invite' ) ) {
action _links . push ( 'invite' ) ;
}
this . _actionObject . updateActionLinks ( action _links ) ;
} ;
/ * *
* Code for implementing et2 _IDetachedDOM
*
* @ param { array } _attrs array to add further attributes to
* /
et2 _calendar _event . prototype . getDetachedAttributes = function ( _attrs ) {
} ;
et2 _calendar _event . prototype . getDetachedNodes = function ( ) {
return [ this . getDOMNode ( ) ] ;
} ;
et2 _calendar _event . prototype . setDetachedAttributes = function ( _nodes , _values ) {
} ;
// Static class stuff
/ * *
* Check event owner against a parent object
*
* As an event is edited , its participants may change . Also , as the state
* changes we may change which events are displayed and show the same event
* in several places for different users . Here we check the event participants
* against an owner value ( which may be an array ) to see if the event should be
* displayed or included .
*
* @ param { Object } event - Event information
* @ param { et2 _widget _daycol | et2 _widget _planner _row } parent - potential parent object
* that has an owner option
* @ param { boolean } [ owner _too ] - Include the event owner in consideration , or only
* event participants
*
* @ return { boolean } Should the event be displayed
* /
et2 _calendar _event . owner _check = function ( event , parent , owner _too ) {
var owner _match = true ;
if ( typeof owner _too === 'undefined' && app . calendar . state . status _filter ) {
owner _too = app . calendar . state . status _filter === 'owner' ;
}
var options = null ;
if ( app . calendar && app . calendar . sidebox _et2 && app . calendar . sidebox _et2 . getWidgetById ( 'owner' ) ) {
options = app . calendar . sidebox _et2 . getWidgetById ( 'owner' ) . taglist . getSelection ( ) ;
}
else {
options = parent . getArrayMgr ( "sel_options" ) . getRoot ( ) . getEntry ( 'owner' ) ;
}
if ( event . participants && typeof parent . options . owner != 'undefined' && parent . options . owner . length > 0 ) {
var parent _owner = jQuery . extend ( [ ] , typeof parent . options . owner !== 'object' ?
[ parent . options . owner ] :
parent . options . owner ) ;
owner _match = false ;
var length _1 = parent _owner . length ;
for ( var i = 0 ; i < length _1 ; i ++ ) {
// Handle groups & grouped resources like mailing lists, they won't match so
// we need the list - pull it from sidebox owner
if ( ( isNaN ( parent _owner [ i ] ) || parent _owner [ i ] < 0 ) && options && typeof options . find == "function" ) {
var resource = options . find ( function ( element ) { return element . id == parent _owner [ i ] ; } ) || { } ;
if ( resource && resource . resources ) {
parent _owner . splice ( i , 1 ) ;
2020-04-20 20:00:42 +02:00
i -- ;
2020-02-27 21:37:36 +01:00
parent _owner = parent _owner . concat ( resource . resources ) ;
}
}
}
var participants _1 = jQuery . extend ( [ ] , Object . keys ( event . participants ) ) ;
var _loop _1 = function ( ) {
var id = participants _1 [ i ] ;
// Expand group invitations
if ( parseInt ( id ) < 0 ) {
if ( options && options . find && ( resource = options . find ( function ( element ) { return element . id === id ; } ) ) && resource . resources ) {
participants _1 = participants _1 . concat ( resource . resources ) ;
}
else {
// Add in groups, if we can get them (this is asynchronous)
egw . accountData ( id , 'account_id' , true , function ( members ) {
participants _1 = participants _1 . concat ( Object . keys ( members ) ) ;
} , this _1 ) ;
}
}
if ( parent . options . owner == id ||
parent _owner . indexOf &&
parent _owner . indexOf ( id ) >= 0 ) {
owner _match = true ;
return "break" ;
}
} ;
var this _1 = this , resource ;
for ( var i = 0 ; i < participants _1 . length ; i ++ ) {
var state _1 = _loop _1 ( ) ;
if ( state _1 === "break" )
break ;
}
}
if ( owner _too && ! owner _match ) {
owner _match = ( parent . options . owner == event . owner ||
parent _owner . indexOf &&
parent _owner . indexOf ( event . owner ) >= 0 ) ;
}
return owner _match ;
} ;
/ * *
* @ callback et2 _calendar _event ~ prompt _callback
* @ param { string } button _id - One of ok , exception , series , single or cancel
* depending on which buttons are on the prompt
* @ param { Object } event _data - Event information - whatever you passed in to
* the prompt .
* /
/ * *
* Recur prompt
* If the event is recurring , asks the user if they want to edit the event as
* an exception , or change the whole series . Then the callback is called .
*
* If callback is not provided , egw . open ( ) will be used to open an edit dialog .
*
* If you call this on a single ( non - recurring ) event , the callback will be
* executed immediately , with the passed button _id as 'single' .
*
* @ param { Object } event _data - Event information
* @ param { string } event _data . id - Unique ID for the event , possibly with a
* timestamp
* @ param { string | Date } event _data . start - Start date / time for the event
* @ param { number } event _data . recur _type - Recur type , or 0 for a non - recurring event
* @ param { et2 _calendar _event ~ prompt _callback } [ callback ] - Callback is
* called with the button ( exception , series , single or cancel ) and the event
* data .
* @ param { Object } [ extra _data ] - Additional data passed to the callback , used
* as extra parameters for default callback
*
* @ augments { et2 _calendar _event }
* /
et2 _calendar _event . recur _prompt = function ( event _data , callback , extra _data ) {
var egw ;
var edit _id = event _data . app _id ;
var edit _date = event _data . start ;
// seems window.opener somehow in certain conditions could be from different origin
// we try to catch the exception and in this case retrieve the egw object from current window.
try {
egw = this . egw ? ( typeof this . egw == 'function' ? this . egw ( ) : this . egw ) : window . opener && typeof window . opener . egw != 'undefined' ? window . opener . egw ( 'calendar' ) : window . egw ( 'calendar' ) ;
}
catch ( e ) {
egw = window . egw ( 'calendar' ) ;
}
var that = this ;
var extra _params = extra _data && typeof extra _data == 'object' ? extra _data : { } ;
extra _params . date = edit _date . toJSON ? edit _date . toJSON ( ) : edit _date ;
if ( typeof callback != 'function' ) {
callback = function ( _button _id ) {
switch ( _button _id ) {
case 'exception' :
extra _params . exception = '1' ;
egw . open ( edit _id , event _data . app || 'calendar' , 'edit' , extra _params ) ;
break ;
case 'series' :
case 'single' :
egw . open ( edit _id , event _data . app || 'calendar' , 'edit' , extra _params ) ;
break ;
case 'cancel' :
default :
break ;
}
} ;
}
if ( parseInt ( event _data . recur _type ) ) {
var buttons = [
{ text : egw . lang ( "Edit exception" ) , id : "exception" , class : "ui-priority-primary" , "default" : true } ,
{ text : egw . lang ( "Edit series" ) , id : "series" } ,
{ text : egw . lang ( "Cancel" ) , id : "cancel" }
] ;
et2 _dialog . show _dialog ( function ( button _id ) { callback . call ( that , button _id , event _data ) ; } , ( ! event _data . is _private ? event _data [ 'title' ] : egw . lang ( 'private' ) ) + "\n" +
egw . lang ( "Do you want to edit this event as an exception or the whole series?" ) , egw . lang ( "This event is part of a series" ) , { } , buttons , et2 _dialog . QUESTION _MESSAGE ) ;
}
else {
callback . call ( this , 'single' , event _data ) ;
}
} ;
/ * *
* Split series prompt
*
* If the event is recurring and the user adjusts the time or duration , we may need
* to split the series , ending the current one and creating a new one with the changes .
* This prompts the user if they really want to do that .
*
* There is no default callback , and nothing happens if you call this on a
* single ( non - recurring ) event
*
* @ param { Object } event _data - Event information
* @ param { string } event _data . id - Unique ID for the event , possibly with a timestamp
* @ param { string | Date } instance _date - The date of the edited instance of the event
* @ param { et2 _calendar _event ~ prompt _callback } callback - Callback is
* called with the button ( ok or cancel ) and the event data .
* @ augments { et2 _calendar _event }
* /
et2 _calendar _event . series _split _prompt = function ( event _data , instance _date , callback ) {
var egw ;
// seems window.opener somehow in certian conditions could be from different origin
// we try to catch the exception and in this case retrieve the egw object from current window.
try {
egw = this . egw ? ( typeof this . egw == 'function' ? this . egw ( ) : this . egw ) : window . opener && typeof window . opener . egw != 'undefined' ? window . opener . egw ( 'calendar' ) : window . egw ( 'calendar' ) ;
}
catch ( e ) {
egw = window . egw ( 'calendar' ) ;
}
var that = this ;
if ( typeof instance _date == 'string' ) {
instance _date = new Date ( instance _date ) ;
}
// Check for modifying a series that started before today
var tempDate = new Date ( ) ;
var today = new Date ( tempDate . getFullYear ( ) , tempDate . getMonth ( ) , tempDate . getDate ( ) , tempDate . getHours ( ) , - tempDate . getTimezoneOffset ( ) , tempDate . getSeconds ( ) ) ;
var termination _date = instance _date < today ? egw . lang ( 'today' ) : date ( egw . preference ( 'dateformat' ) , instance _date ) ;
if ( parseInt ( event _data . recur _type ) ) {
et2 _dialog . show _dialog ( function ( button _id ) { callback . call ( that , button _id , event _data ) ; } , ( ! event _data . is _private ? event _data [ 'title' ] : egw . lang ( 'private' ) ) + "\n" +
egw . lang ( "Do you really want to change the start of this series? If you do, the original series will be terminated as of %1 and a new series for the future reflecting your changes will be created." , termination _date ) , egw . lang ( "This event is part of a series" ) , { } , et2 _dialog . BUTTONS _OK _CANCEL , et2 _dialog . WARNING _MESSAGE ) ;
}
} ;
et2 _calendar _event . drag _helper = function ( event , ui ) {
ui . helper . width ( ui . width ( ) ) ;
} ;
/ * *
* splits the combined status , quantity and role
*
* @ param { string } status - combined value , O : status letter : U , T , A , R
* @ param { int } [ quantity ] - quantity
* @ param { string } [ role ]
* @ return string status U , T , A or R , same as $status parameter on return
* /
et2 _calendar _event . split _status = function ( status , quantity , role ) {
quantity = 1 ;
role = 'REQ-PARTICIPANT' ;
//error_log(__METHOD__.__LINE__.array2string($status));
var matches = null ;
if ( typeof status === 'string' && status . length > 1 ) {
matches = status . match ( /^.([0-9]*)(.*)$/gi ) ;
}
if ( matches ) {
if ( parseInt ( matches [ 1 ] ) > 0 )
quantity = parseInt ( matches [ 1 ] ) ;
if ( matches [ 2 ] )
role = matches [ 2 ] ;
status = status [ 0 ] ;
}
else if ( status === true ) {
status = 'U' ;
}
return status ;
} ;
/ * *
* The egw _action system requires an egwActionObjectInterface Interface implementation
* to tie actions to DOM nodes . I ' m not sure if we need this .
*
* The class extension is different than the widgets
*
* @ param { et2 _DOMWidget } widget
* @ param { Object } node
*
* /
et2 _calendar _event . et2 _event _action _object _impl = function ( widget , node ) {
var aoi = new et2 _core _DOMWidget _1 . et2 _action _object _impl ( widget , node ) . getAOI ( ) ;
// _outerCall may be used to determine, whether the state change has been
// evoked from the outside and the stateChangeCallback has to be called
// or not.
aoi . doSetState = function ( _state , _outerCall ) {
} ;
return aoi ;
} ;
et2 _calendar _event . _attributes = {
"value" : {
type : "any" ,
default : et2 _no _init
} ,
"onclick" : {
"description" : "JS code which is executed when the element is clicked. " +
"If no handler is provided, or the handler returns true and the event is not read-only, the " +
"event will be opened according to calendar settings."
}
} ;
return et2 _calendar _event ;
} ( et2 _core _valueWidget _1 . et2 _valueWidget ) ) ;
exports . et2 _calendar _event = et2 _calendar _event ;
et2 _core _widget _1 . et2 _register _widget ( et2 _calendar _event , [ "calendar-event" ] ) ;
//# sourceMappingURL=et2_widget_event.js.map