1/* DOKUWIKI:include_once fullcalendar-3.10.5/moment.js */
2/* DOKUWIKI:include_once fullcalendar-3.10.5/fullcalendar.js */
3/* DOKUWIKI:include_once fullcalendar-3.10.5/locale/de.js */
4/* DOKUWIKI:include_once fullcalendar-3.10.5/locale/en.js */
5/* DOKUWIKI:include_once fullcalendar-3.10.5/locale/fr.js */
6/* DOKUWIKI:include_once fullcalendar-3.10.5/locale/nl.js */
7/* DOKUWIKI:include_once fullcalendar-3.10.5/locale/ru.js */
8/* DOKUWIKI:include_once datetimepicker-2.4.5/jquery.datetimepicker.js */
9/* DOKUWIKI:include_once jstz.js */
10
11/**
12 * Initialize the DAVCal script, attaching some event handlers and triggering
13 * the initial load of the fullcalendar JS
14 */
15jQuery(function() {
16    // Redefine functions for using moment.js with datetimepicker
17
18    Date.parseDate = function( input, format ){
19      return moment(input,format).toDate();
20    };
21    Date.prototype.dateFormat = function( format ){
22      return moment(this).format(format);
23    };
24
25    // Attach to event links
26    var calendarpage = jQuery('#fullCalendar').data('calendarpage');
27    if(!calendarpage) return;
28    dw_davcal__modals.page = calendarpage;
29
30    jQuery('div.fullCalendarSettings a').each(function() {
31        var $link = jQuery(this);
32        var href = $link.attr('href');
33        if (!href) return;
34
35        $link.click(
36            function(e) {
37                dw_davcal__modals.showSettingsDialog();
38                e.preventDefault();
39                return '';
40            }
41        );
42        }
43    );
44
45    // First, retrieve the current settings.
46    // Upon success, initialize fullcalendar.
47    var postArray = { };
48    jQuery.post(
49        DOKU_BASE + 'lib/exe/ajax.php',
50        {
51            call: 'plugin_davcal',
52            id: dw_davcal__modals.page,
53            page: dw_davcal__modals.page,
54            action: 'getSettings',
55            params: postArray,
56            sectok: JSINFO.plugin.davcal['sectok']
57        },
58        function(data)
59        {
60            var result = data['result'];
61            if(result === true)
62            {
63                dw_davcal__modals.settings = data['settings'];
64                var tz = false;
65                if(data['settings']['timezone'] !== '')
66                    tz = data['settings']['timezone'];
67                // Force-overwrite thhe timezone setting if requested
68                if(data['settings']['meta']['forcetimezone'] !== 'no')
69                    tz = data['settings']['meta']['forcetimezone'];
70                var fcOptions = {
71                    dayClick: function(date, jsEvent, view) {
72                        dw_davcal__modals.showEditEventDialog(date, false);
73                    },
74                    eventClick: function(calEvent, jsEvent, view) {
75                        dw_davcal__modals.showEditEventDialog(calEvent, true);
76                    },
77                    events: {
78                        url: DOKU_BASE + 'lib/exe/ajax.php',
79                        type: 'POST',
80                        data: {
81                            call: 'plugin_davcal',
82                            action: 'getEvents',
83                            id: dw_davcal__modals.page,
84                            page: dw_davcal__modals.page,
85                            sectok: JSINFO.plugin.davcal['sectok']
86                        },
87                        error: function() {
88                            dw_davcal__modals.msg = LANG.plugins.davcal['error_retrieving_data'];
89                            dw_davcal__modals.showDialog(false);
90                        }
91                    },
92                    header: {
93                        left: 'title',
94                        center: 'today prev,next',
95                        right: 'month,agendaWeek,agendaDay,listWeek'
96                    },
97                    locale: JSINFO.plugin.davcal['language'],
98                    weekNumbers: (data['settings']['weeknumbers'] == 1) ? true : false,
99                    timezone: tz,
100                    weekends: (data['settings']['workweek'] == 1) ? false : true,
101                    firstDay: (data['settings']['monday'] == 1) ? 1 : 0,
102                    defaultView: data['settings']['meta']['view'],
103                };
104                var timeformat = data['settings']['timeformat'];
105                // Force-overwrite the user's timezone setting if requested by the calendar
106                if(data['settings']['meta']['forcetimeformat'] !== 'no')
107                    timeformat = data['settings']['meta']['forcetimeformat'];
108                if(timeformat !== 'lang')
109                {
110                    // If the time format is language-based, we don't need to pass
111                    // the timeFormat option to fullCalendar
112                    if(timeformat == '24h')
113                    {
114                        fcOptions.timeFormat = 'H:mm';
115                    }
116                    if(timeformat == '12h')
117                    {
118                        fcOptions.timeFormat = 'h:mmt';
119                    }
120                }
121                for (var key in data['settings']['meta']['fcoptions'])
122                {
123                    if(!data['settings']['meta']['fcoptions'].hasOwnProperty(key)) continue;
124
125                    var val = data['settings']['meta']['fcoptions'][key];
126                    fcOptions[key] = val;
127                }
128                var detectedTz = jstz.determine().name();
129                dw_davcal__modals.detectedTz = detectedTz;
130                // The current TZ value holds either the uers's selection or
131                // the force timezone value
132                dw_davcal__modals.currentTz = (tz === false) ? '' : tz;
133                // Initialize the davcal popup
134                var res = jQuery('#fullCalendar').fullCalendar(fcOptions);
135            }
136        }
137    );
138});
139
140/**
141 * This holds all modal windows that DAVCal uses.
142 */
143var dw_davcal__modals = {
144    $editEventDialog: null,
145    $dialog: null,
146    $settingsDialog: null,
147    $inputDialog: null,
148    msg: null,
149    completeCb: null,
150    action: null,
151    uid: null,
152    settings: null,
153    page: null,
154    detectedTz: null,
155    currentTz: null,
156
157    /**
158     * Show the settings dialog
159     */
160    // FIXME: Hide URLs for multi-calendar
161    showSettingsDialog : function() {
162        if(dw_davcal__modals.$settingsDialog)
163            return;
164
165        // Dialog buttons are language-dependent and defined here.
166        // Attach event handlers for save and cancel.
167        var dialogButtons = {};
168        if(!JSINFO.plugin.davcal['disable_settings'])
169        {
170            dialogButtons[LANG.plugins.davcal['save']] = function() {
171                var postArray = { };
172                jQuery("input[class=dw_davcal__settings], select[class=dw_davcal__settings]").each(function() {
173                  if(jQuery(this).attr('type') == 'checkbox')
174                  {
175                      postArray[jQuery(this).prop('name')] = jQuery(this).prop('checked') ? 1 : 0;
176                  }
177                  else
178                  {
179                      postArray[jQuery(this).prop('name')] = jQuery(this).val();
180                  }
181                });
182                jQuery('#dw_davcal__ajaxsettings').html('<img src="'+DOKU_BASE+'lib/images/throbber.gif" alt="" width="16" height="16" />');
183                jQuery.post(
184                    DOKU_BASE + 'lib/exe/ajax.php',
185                    {
186                        call: 'plugin_davcal',
187                        id: dw_davcal__modals.page,
188                        page: dw_davcal__modals.page,
189                        action: 'saveSettings',
190                        params: postArray,
191                        sectok: JSINFO.plugin.davcal['sectok']
192                    },
193                    function(data)
194                    {
195                        var result = data['result'];
196                        var html = data['html'];
197                        jQuery('#dw_davcal__ajaxsettings').html(html);
198                        if(result === true)
199                        {
200                            location.reload();
201                        }
202                    }
203                );
204            };
205        }
206        dialogButtons[LANG.plugins.davcal['cancel']] = function () {
207            dw_davcal__modals.hideSettingsDialog();
208        };
209
210        var settingsHtml = '<div><table>';
211
212        if(JSINFO.plugin.davcal['disable_settings'] && JSINFO.plugin.davcal['disable_sync'] && JSINFO.plugin.davcal['disable_ics'])
213        {
214            settingsHtml += LANG.plugins.davcal['nothing_to_show'];
215        }
216
217        if(!JSINFO.plugin.davcal['disable_settings'])
218        {
219            settingsHtml += '<tr><td>' + LANG.plugins.davcal['timezone'] + '</td><td><select name="timezone" id="dw_davcal__settings_timezone" class="dw_davcal__settings"></select></td></tr>' +
220            '<tr><td>' + LANG.plugins.davcal['timeformat'] + '</td><td><select name="timeformat" id="dw_davcal__settings_timeformat" class="dw_davcal__settings"></select></td></tr>' +
221            '<tr><td>' + LANG.plugins.davcal['weeknumbers'] + '</td><td><input type="checkbox" name="weeknumbers" id="dw_davcal__settings_weeknumbers" class="dw_davcal__settings"></td></tr>' +
222            '<tr><td>' + LANG.plugins.davcal['only_workweek'] + '</td><td><input type="checkbox" name="workweek" id="dw_davcal__settings_workweek" class="dw_davcal__settings"></td></tr>' +
223            '<tr><td>' + LANG.plugins.davcal['start_monday'] + '</td><td><input type="checkbox" name="monday" id="dw_davcal__settings_monday" class="dw_davcal__settings"></td></tr>';
224         }
225
226         if(!JSINFO.plugin.davcal['disable_sync'])
227         {
228             settingsHtml += '<tr id="dw_davcal__settings_syncurl"><td>' + LANG.plugins.davcal['sync_url'] + '</td><td><input type="text" name="syncurl" readonly="readonly" id="dw_davcal__settings_syncurl_edit" class="dw_davcal__text" value="' + dw_davcal__modals.settings['syncurl'] + '"></td></tr>';
229             settingsHtml += '<tr id="dw_davcal__settings_principalurl"><td>' + LANG.plugins.davcal['sync_ical'] + '</td><td><input type="text" name="principalurl" readonly="readonly" id="dw_davcal__settings_principalurl_edit" class="dw_davcal__text" value="' + dw_davcal__modals.settings['principalurl'] + '"></td></tr>';
230         }
231
232         if(!JSINFO.plugin.davcal['disable_ics'])
233         {
234             settingsHtml += '<tr id="dw_davcal__settings_privateurl"><td>' + LANG.plugins.davcal['private_url'] + '</td><td><input type="text" name="privateurl" readonly="readonly" id="dw_davcal__settings_privateurl_edit" class="dw_davcal__text" value="' + dw_davcal__modals.settings['privateurl'] + '"></td></tr>';
235         }
236
237         settingsHtml += '</table>' +
238            '</div>' +
239            '<div id="dw_davcal__ajaxsettings"></div>';
240
241        dw_davcal__modals.$settingsDialog = jQuery(document.createElement('div'))
242       .dialog({
243           autoOpen: false,
244           draggable: true,
245           // fix for dragging: http://stackoverflow.com/questions/17247486/jquery-ui-dialog-dragging-issues
246           drag: function(event, ui) {
247               var fixPix = jQuery(document).scrollTop();
248               iObj = ui.position;
249               iObj.top = iObj.top - fixPix;
250               jQuery(this).closest(".ui-dialog").css("top", iObj.top + "px");
251           },
252           title: LANG.plugins.davcal['settings'],
253           resizable: true,
254           buttons: dialogButtons,
255       })
256       .html(
257           settingsHtml
258            )
259       .parent()
260       .attr('id','dw_davcal__settings')
261       .show()
262       .appendTo('.dokuwiki:first');
263
264       jQuery('#dw_davcal__settings').position({
265           my: "center",
266           at: "center",
267           of: window
268       });
269
270       // Initialize current settings
271
272        if(!JSINFO.plugin.davcal['disable_settings'])
273        {
274            var $tzdropdown = jQuery('#dw_davcal__settings_timezone');
275            jQuery('#fullCalendarTimezoneList option').each(function() {
276                jQuery('<option />', {value: jQuery(this).val(),
277                        text: jQuery(this).text()}).appendTo($tzdropdown);
278            });
279
280            var $tfdropdown = jQuery('#dw_davcal__settings_timeformat');
281            jQuery('<option />', {value: 'lang', text: LANG.plugins.davcal['language_specific']}).appendTo($tfdropdown);
282            jQuery('<option />', {value: '24h', text: '24h'}).appendTo($tfdropdown);
283            jQuery('<option />', {value: '12h', text: '12h'}).appendTo($tfdropdown);
284
285            if(!JSINFO.plugin.davcal['disable_sync'])
286            {
287                jQuery('#dw_davcal__settings_syncurl_edit').on('click', function() {
288                    jQuery(this).select();
289                });
290                jQuery('#dw_davcal__settings_principalurl_edit').on('click', function() {
291                    jQuery(this).select();
292                });
293            }
294
295            if(!JSINFO.plugin.davcal['disable_ics'])
296            {
297                jQuery('#dw_davcal__settings_privateurl_edit').on('click', function() {
298                    jQuery(this).select();
299                });
300            }
301
302            if(dw_davcal__modals.settings)
303            {
304                if(dw_davcal__modals.settings['timeformat'] !== '')
305                    jQuery('#dw_davcal__settings_timeformat').val(dw_davcal__modals.settings['timeformat']);
306                if(dw_davcal__modals.settings['timezone'] !== '')
307                    jQuery('#dw_davcal__settings_timezone').val(dw_davcal__modals.settings['timezone']);
308                if(dw_davcal__modals.settings['weeknumbers'] == 1)
309                    jQuery('#dw_davcal__settings_weeknumbers').prop('checked', true);
310                else
311                    jQuery('#dw_davcal__settings_weeknumbers').prop('checked', false);
312
313                if(dw_davcal__modals.settings['workweek'] == 1)
314                    jQuery('#dw_davcal__settings_workweek').prop('checked', true);
315                else
316                    jQuery('#dw_davcal__settings_workweek').prop('checked', false);
317
318                if(dw_davcal__modals.settings['monday'] == 1)
319                    jQuery('#dw_davcal__settings_monday').prop('checked', true);
320                else
321                    jQuery('#dw_davcal__settings_monday').prop('checked', false);
322                if(dw_davcal__modals.settings['meta']['forcetimezone'] !== 'no')
323                    jQuery('#dw_davcal__settings_timezone').prop('disabled', true);
324                if(dw_davcal__modals.settings['meta']['forcetimeformat'] !== 'no')
325                    jQuery('#dw_davcal__settings_timeformat').prop('disabled', true);
326            }
327        }
328
329        // attach event handlers
330        jQuery('#dw_davcal__settings .ui-dialog-titlebar-close').click(function(){
331          dw_davcal__modals.hideSettingsDialog();
332        });
333    },
334
335    /**
336     * Sanity-check our events.
337     *
338     * @return boolean false on failure, otherwise true
339     */
340    checkEvents : function() {
341        // Retrieve dates
342        var allDay = jQuery('#dw_davcal__allday_edit').prop('checked');
343        var startDate = moment(jQuery('#dw_davcal__eventfrom_edit').val(), 'YYYY-MM-DD');
344        var endDate = moment(jQuery('#dw_davcal__eventto_edit').val(), 'YYYY-MM-DD');
345
346        // Do the checking
347        if(!allDay)
348        {
349            var startTime = moment.duration(jQuery('#dw_davcal__eventfromtime_edit').val());
350            var endTime = moment.duration(jQuery('#dw_davcal__eventtotime_edit').val());
351            startDate.add(startTime);
352            endDate.add(endTime);
353        }
354        if(!startDate.isValid())
355        {
356            dw_davcal__modals.msg = LANG.plugins.davcal['start_date_invalid'];
357            dw_davcal__modals.showDialog(false);
358            return false;
359        }
360        if(!endDate.isValid())
361        {
362            dw_davcal__modals.msg = LANG.plugins.davcal['end_date_invalid'];
363            dw_davcal__modals.showDialog(false);
364            return false;
365        }
366        if(endDate.isBefore(startDate))
367        {
368            dw_davcal__modals.msg = LANG.plugins.davcal['end_date_before_start_date'];
369            dw_davcal__modals.showDialog(false);
370            return false;
371        }
372        if(!allDay && endDate.isSame(startDate))
373        {
374            dw_davcal__modals.msg = LANG.plugins.davcal['end_date_is_same_as_start_date'];
375            dw_davcal__modals.showDialog(false);
376            return false;
377        }
378        return true;
379    },
380
381    /**
382     * Show the edit event dialog, which is also used to create new events
383     * @param {Object} event The event to create, that is the date or the calEvent
384     * @param {Object} edit  Whether we edit (true) or create a new event (false)
385     */
386    showEditEventDialog : function(event, edit) {
387        if(dw_davcal__modals.$editEventDialog)
388            return;
389
390        var readonly = true;
391        for(var i=0; i<dw_davcal__modals.settings['calids'].length; i++)
392        {
393            if(edit)
394            {
395                // Use the specific calendar setting if we edit an event
396                if(event.page == dw_davcal__modals.settings['calids'][i]['page'])
397                  readonly = !dw_davcal__modals.settings['calids'][i]['write'];
398            }
399            else
400            {
401                // If there is at least one writable calendar,
402                // we set readonly to false
403                if(dw_davcal__modals.settings['calids'][i]['write'])
404                  readonly = false;
405            }
406        }
407
408        var title = '';
409        var dialogButtons = {};
410        var calEvent = [];
411        var recurringWarning = '';
412        // Buttons are dependent on edit or create
413        // Several possibilities:
414        //
415        // 1) Somebody tries to edit, it is not recurring and not readonly -> show
416        // 2) Somebody tries to edit, it is recurring and not readonly -> message
417        // 3) Somebody tries to edit, it is readonly -> message
418        // 4) Somebody tries to create and it is readonly -> message
419        // 5) Somebody tries to create -> show
420        if(edit && (event.recurring != true) && (readonly === false))
421        {
422            calEvent = event;
423            title = LANG.plugins.davcal['edit_event'];
424            dialogButtons[LANG.plugins.davcal['edit']] = function() {
425                if(!dw_davcal__modals.checkEvents())
426                  return;
427                var postArray = { };
428                var attachArr = new Array();
429                var pageid = calEvent.page;
430
431                jQuery('.dw_davcal__editevent_attachment_link').each(function() {
432                    var attachment = jQuery(this).attr('href');
433                    if(attachment != undefined)
434                    {
435                        attachArr.push(attachment);
436                    }
437                });
438                postArray['attachments'] = attachArr;
439                jQuery("input.dw_davcal__editevent, textarea.dw_davcal__editevent").each(function() {
440                  if(jQuery(this).attr('type') == 'checkbox')
441                  {
442                      postArray[jQuery(this).prop('name')] = jQuery(this).prop('checked') ? 1 : 0;
443                  }
444                  else
445                  {
446                      postArray[jQuery(this).prop('name')] = jQuery(this).val();
447                  }
448                });
449                jQuery('#dw_davcal__ajaxedit').html('<img src="'+DOKU_BASE+'lib/images/throbber.gif" alt="" width="16" height="16" />');
450                jQuery.post(
451                    DOKU_BASE + 'lib/exe/ajax.php',
452                    {
453                        call: 'plugin_davcal',
454                        id: pageid,
455                        page: dw_davcal__modals.page,
456                        action: 'editEvent',
457                        params: postArray,
458                        sectok: JSINFO.plugin.davcal['sectok']
459                    },
460                    function(data)
461                    {
462                        var result = data['result'];
463                        var html = data['html'];
464                        jQuery('#dw_davcal__ajaxedit').html(html);
465                        if(result === true)
466                        {
467                            jQuery('#fullCalendar').fullCalendar('refetchEvents');
468                            dw_davcal__modals.hideEditEventDialog();
469                        }
470                    }
471                );
472            };
473            dialogButtons[LANG.plugins.davcal['delete']] = function() {
474                dw_davcal__modals.action = 'deleteEvent';
475                dw_davcal__modals.msg = LANG.plugins.davcal['really_delete_this_event'];
476                dw_davcal__modals.completeCb = function(data) {
477                    var result = data['result'];
478                    var html = data['html'];
479                    jQuery('#dw_davcal__ajaxedit').html(html);
480                    if(result === true)
481                    {
482                        jQuery('#fullCalendar').fullCalendar('refetchEvents');
483                        dw_davcal__modals.hideEditEventDialog();
484                    }
485                };
486                dw_davcal__modals.showDialog(true);
487            };
488        }
489        else if(edit && (event.recurring == true) && (readonly === false))
490        {
491            calEvent = event;
492            title = LANG.plugins.davcal['edit_event'];
493            recurringWarning = LANG.plugins.davcal['recurring_cant_edit'];
494        }
495        else if(edit && (readonly === true))
496        {
497            calEvent = event;
498            title = LANG.plugins.davcal['edit_event'];
499            recurringWarning = LANG.plugins.davcal['no_permission'];
500        }
501        else if(readonly === true)
502        {
503            calEvent.start = event;
504            calEvent.end = moment(event);
505            calEvent.start.hour(12);
506            calEvent.start.minute(0);
507            calEvent.end.hour(13);
508            calEvent.end.minute(0);
509            calEvent.allDay = false;
510            calEvent.recurring = false;
511            calEvent.title = '';
512            calEvent.description = '';
513            calEvent.id = '0';
514            calEvent.location = '';
515            calEvent.page = dw_davcal__modals.page;
516            title = LANG.plugins.davcal['create_new_event'];
517            recurringWarning = LANG.plugins.davcal['no_permission'];
518        }
519        else
520        {
521            calEvent.start = event;
522            calEvent.end = moment(event);
523            calEvent.start.hour(12);
524            calEvent.start.minute(0);
525            calEvent.end.hour(13);
526            calEvent.end.minute(0);
527            calEvent.allDay = false;
528            calEvent.recurring = false;
529            calEvent.title = '';
530            calEvent.description = '';
531            calEvent.location = '';
532            calEvent.id = '0';
533            calEvent.page = dw_davcal__modals.settings['calids'][0]['page'];
534            title = LANG.plugins.davcal['create_new_event'];
535            dialogButtons[LANG.plugins.davcal['create']] = function() {
536                if(!dw_davcal__modals.checkEvents())
537                  return;
538
539                var postArray = { };
540                var attachArr = new Array();
541                var pageid = jQuery("#dw_davcal__editevent_calendar option:selected").val();
542                jQuery("input.dw_davcal__editevent, textarea.dw_davcal__editevent").each(function() {
543                  if(jQuery(this).attr('type') == 'checkbox')
544                  {
545                      postArray[jQuery(this).prop('name')] = jQuery(this).prop('checked') ? 1 : 0;
546                  }
547                  else
548                  {
549                      postArray[jQuery(this).prop('name')] = jQuery(this).val();
550                  }
551                });
552                jQuery('.dw_davcal__editevent_attachment_link').each(function() {
553                    var attachment = jQuery(this).attr('href');
554                    if(attachment != undefined)
555                    {
556                        attachArr.push(attachment);
557                    }
558                });
559                postArray['attachments'] = attachArr;
560                jQuery('#dw_davcal__ajaxedit').html('<img src="'+DOKU_BASE+'lib/images/throbber.gif" alt="" width="16" height="16" />');
561                jQuery.post(
562                    DOKU_BASE + 'lib/exe/ajax.php',
563                    {
564                        call: 'plugin_davcal',
565                        id: pageid,
566                        page: dw_davcal__modals.page,
567                        action: 'newEvent',
568                        params: postArray,
569                        sectok: JSINFO.plugin.davcal['sectok']
570                    },
571                    function(data)
572                    {
573                        var result = data['result'];
574                        var html = data['html'];
575                        jQuery('#dw_davcal__ajaxedit').html(html);
576                        if(result === true)
577                        {
578                            jQuery('#fullCalendar').fullCalendar('refetchEvents');
579                            dw_davcal__modals.hideEditEventDialog();
580                        }
581                    }
582                );
583            };
584        }
585        dialogButtons[LANG.plugins.davcal['cancel']] = function() {
586            dw_davcal__modals.hideEditEventDialog();
587        };
588        dw_davcal__modals.uid = calEvent.id;
589        dw_davcal__modals.$editEventDialog = jQuery(document.createElement('div'))
590       .dialog({
591           autoOpen: false,
592           draggable: true,
593           // fix for dragging: http://stackoverflow.com/questions/17247486/jquery-ui-dialog-dragging-issues
594           drag: function(event, ui) {
595               var fixPix = jQuery(document).scrollTop();
596               iObj = ui.position;
597               iObj.top = iObj.top - fixPix;
598               jQuery(this).closest(".ui-dialog").css("top", iObj.top + "px");
599           },
600           title: title,
601           resizable: true,
602           buttons: dialogButtons,
603       })
604       .html(
605            '<div><table>' +
606            '<tr><td>' + LANG.plugins.davcal['calendar'] + '</td><td><select id="dw_davcal__editevent_calendar"></select></td></tr>' +
607            '<tr><td>' + LANG.plugins.davcal['title'] + '</td><td><input type="text" id="dw_davcal__eventname_edit" name="eventname" class="dw_davcal__editevent"></td></tr>' +
608            '<tr><td>' + LANG.plugins.davcal['description'] + '</td><td><textarea name="eventdescription" id="dw_davcal__eventdescription_edit" class="dw_davcal__editevent dw_davcal__text"></textarea></td></tr>' +
609            '<tr><td>' + LANG.plugins.davcal['location'] + '</td><td><input type="text" id="dw_davcal__eventlocation_edit" name="eventlocation" class="dw_davcal__editevent"></td></tr>' +
610            '<tr><td>' + LANG.plugins.davcal['from'] + '</td><td><input type="text" name="eventfrom" id="dw_davcal__eventfrom_edit" class="dw_davcal__editevent dw_davcal__date"><input type="text" name="eventfromtime" id="dw_davcal__eventfromtime_edit" class="dw_davcal__editevent dw_davcal__time"></td></tr>' +
611            '<tr><td>' + LANG.plugins.davcal['to'] + '</td><td><input type="text" name="eventto" id="dw_davcal__eventto_edit" class="dw_davcal__editevent dw_davcal__date"><input type="text" name="eventtotime" id="dw_davcal__eventtotime_edit" class="dw_davcal__editevent dw_davcal__time"></td></tr>' +
612            '<tr><td colspan="2"><input type="checkbox" name="allday" id="dw_davcal__allday_edit" class="dw_davcal__editevent">' + LANG.plugins.davcal['allday'] + '</td></tr>' +
613            '<tr><td>' + LANG.plugins.davcal['attachments'] + '</td><td><table id="dw_davcal__editevent_attachments"><tbody><tr><td><input type="text" id="dw_davcal__editevent_attachment" value="http://"></td><td><a href="#" id="dw_davcal__editevent_attach">' + LANG.plugins.davcal['add_attachment'] + '</a></td></tr></tbody></table></td></tr>' +
614            '</table>' +
615            recurringWarning +
616            '<input type="hidden" name="uid" id="dw_davcal__uid_edit" class="dw_davcal__editevent">' +
617            '<input type="hidden" name="detectedtz" id="dw_davcal__tz_edit" class="dw_davcal__editevent">' +
618            '<input type="hidden" name="currenttz" id="dw_davcal__currenttz_edit" class="dw_davcal__editevent">' +
619            '</div>' +
620            '<div id="dw_davcal__ajaxedit"></div>'
621            )
622       .parent()
623       .attr('id','dw_davcal__edit')
624       .show()
625       .appendTo('.dokuwiki:first');
626
627       jQuery('#dw_davcal__edit').position({
628           my: "center",
629           at: "center",
630           of: window
631       });
632
633       // Populate calendar dropdown
634       var $dropdown = jQuery("#dw_davcal__editevent_calendar");
635       for(var i=0; i<dw_davcal__modals.settings['calids'].length; i++)
636       {
637           var sel = '';
638           // When creating an event, do not show read-only calendars
639           if(!edit && (dw_davcal__modals.settings['calids'][i]['write'] === false))
640             continue;
641           if(calEvent.page == dw_davcal__modals.settings['calids'][i]['page'])
642             sel = ' selected="selected"';
643           $dropdown.append('<option value="' + dw_davcal__modals.settings['calids'][i]['page'] + '"' + sel + '>' + dw_davcal__modals.settings['calids'][i]['name'] + '</option>');
644       }
645       if(edit || (dw_davcal__modals.settings['calids'].length < 1))
646       {
647           $dropdown.prop('disabled', true);
648       }
649
650       // Set up existing/predefined values
651       jQuery('#dw_davcal__tz_edit').val(dw_davcal__modals.detectedTz);
652       jQuery('#dw_davcal__currenttz_edit').val(dw_davcal__modals.currentTz);
653       jQuery('#dw_davcal__uid_edit').val(calEvent.id);
654       jQuery('#dw_davcal__eventname_edit').val(calEvent.title);
655       jQuery('#dw_davcal__eventlocation_edit').val(calEvent.location);
656       jQuery('#dw_davcal__eventfrom_edit').val(calEvent.start.format('YYYY-MM-DD'));
657       jQuery('#dw_davcal__eventfromtime_edit').val(calEvent.start.format('HH:mm'));
658       jQuery('#dw_davcal__eventdescription_edit').val(calEvent.description);
659       if(calEvent.attachments && (calEvent.attachments !== null))
660       {
661           for(var i=0; i<calEvent.attachments.length; i++)
662           {
663               var url = calEvent.attachments[i];
664               var row = '<tr><td><a href="' + url + '" class="dw_davcal__editevent_attachment_link">' + url + '</a></td><td><a class="deleteLink" href="#">' + LANG.plugins.davcal['delete'] + '</a></td></tr>';
665               jQuery('#dw_davcal__editevent_attachments > tbody:last').append(row);
666
667           }
668       }
669       dw_davcal__modals.attachAttachmentDeleteHandlers();
670       jQuery('#dw_davcal__editevent_attach').on("click", function(e)
671       {
672           e.preventDefault();
673           var url = jQuery('#dw_davcal__editevent_attachment').val();
674           if(url == '')
675             return false;
676           jQuery('#dw_davcal__editevent_attachment').val('http://');
677           var row = '<tr><td><a href="' + url + '" class="dw_davcal__editevent_attachment_link">' + url + '</a></td><td><a class="deleteLink" href="#">' + LANG.plugins.davcal['delete'] + '</a></td></tr>';
678           jQuery('#dw_davcal__editevent_attachments > tbody:last').append(row);
679           dw_davcal__modals.attachAttachmentDeleteHandlers();
680           return false;
681       });
682       if(calEvent.allDay && (calEvent.end === null))
683       {
684           jQuery('#dw_davcal__eventto_edit').val(calEvent.start.format('YYYY-MM-DD'));
685           jQuery('#dw_davcal__eventtotime_edit').val(calEvent.start.format('HH:mm'));
686       }
687       else if(calEvent.allDay)
688       {
689           endEvent = moment(calEvent.end);
690           endEvent.subtract(1, 'days');
691           jQuery('#dw_davcal__eventto_edit').val(endEvent.format('YYYY-MM-DD'));
692           jQuery('#dw_davcal__eventotime_edit').val(endEvent.format('HH:mm'));
693       }
694       else
695       {
696           jQuery('#dw_davcal__eventto_edit').val(calEvent.end.format('YYYY-MM-DD'));
697           jQuery('#dw_davcal__eventtotime_edit').val(calEvent.end.format('HH:mm'));
698       }
699       jQuery('#dw_davcal__allday_edit').prop('checked', calEvent.allDay);
700
701        // attach event handlers
702        jQuery('#dw_davcal__edit .ui-dialog-titlebar-close').click(function(){
703          dw_davcal__modals.hideEditEventDialog();
704        });
705        jQuery('#dw_davcal__eventfrom_edit').datetimepicker({format:'YYYY-MM-DD',
706                                                      formatDate:'YYYY-MM-DD',
707                                                      datepicker: true,
708                                                      timepicker: false,
709                                                      lang: JSINFO.plugin.davcal['language'],
710                                                      });
711        jQuery('#dw_davcal__eventfromtime_edit').datetimepicker({format:'HH:mm',
712                                                      formatTime:'HH:mm',
713                                                      datepicker: false,
714                                                      timepicker: true,
715                                                      lang: JSINFO.plugin.davcal['language'],
716                                                      step: 15});
717        jQuery('#dw_davcal__eventto_edit').datetimepicker({format:'YYYY-MM-DD',
718                                                      formatDate:'YYYY-MM-DD',
719                                                      datepicker: true,
720                                                      timepicker: false,
721                                                      lang: JSINFO.plugin.davcal['language'],
722                                                      });
723        jQuery('#dw_davcal__eventtotime_edit').datetimepicker({format:'HH:mm',
724                                                      formatTime:'HH:mm',
725                                                      datepicker: false,
726                                                      timepicker: true,
727                                                      lang: JSINFO.plugin.davcal['language'],
728                                                      step:15});
729        jQuery('#dw_davcal__allday_edit').change(function() {
730            if(jQuery(this).is(":checked"))
731            {
732                jQuery('#dw_davcal__eventfromtime_edit').prop('readonly', true);
733                jQuery('#dw_davcal__eventtotime_edit').prop('readonly', true);
734            }
735            else
736            {
737                jQuery('#dw_davcal__eventfromtime_edit').prop('readonly', false);
738                jQuery('#dw_davcal__eventtotime_edit').prop('readonly', false);
739            }
740        });
741        jQuery('#dw_davcal__allday_edit').change();
742    },
743
744    /**
745     * Attach handles to delete the attachments to all 'delete' links
746     */
747    attachAttachmentDeleteHandlers: function()
748    {
749       jQuery("#dw_davcal__editevent_attachments .deleteLink").on("click", function(e)
750       {
751            e.preventDefault();
752            var tr = jQuery(this).closest('tr');
753            tr.css("background-color", "#FF3700");
754            tr.fadeOut(400, function()
755            {
756                tr.remove();
757            });
758            return false;
759       });
760    },
761
762    /**
763     * Show an info/confirmation dialog
764     * @param {Object} confirm Whether a confirmation dialog (true) or an info dialog (false) is requested
765     */
766    showDialog : function(confirm)
767    {
768        if(dw_davcal__modals.$confirmDialog)
769            return;
770        var dialogButtons = {};
771        var title = '';
772        if(confirm)
773        {
774            title = LANG.plugins.davcal['confirmation'];
775            var pageid = jQuery("#dw_davcal__editevent_calendar option:selected").val();
776            dialogButtons[LANG.plugins.davcal['yes']] =  function() {
777                            jQuery.post(
778                                DOKU_BASE + 'lib/exe/ajax.php',
779                                {
780                                    call: 'plugin_davcal',
781                                    id: pageid,
782                                    page: dw_davcal__modals.page,
783                                    action: dw_davcal__modals.action,
784                                    params: {
785                                        uid: dw_davcal__modals.uid
786                                    },
787                                    sectok: JSINFO.plugin.davcal['sectok']
788                                },
789                                function(data)
790                                {
791                                    dw_davcal__modals.completeCb(data);
792                                }
793                            );
794                            dw_davcal__modals.hideDialog();
795                    };
796            dialogButtons[LANG.plugins.davcal['cancel']] = function() {
797                            dw_davcal__modals.hideDialog();
798                    };
799        }
800        else
801        {
802            title = LANG.plugins.davcal['info'];
803            dialogButtons[LANG.plugins.davcal['ok']] = function() {
804                 dw_davcal__modals.hideDialog();
805            };
806        }
807        dw_davcal__modals.$dialog = jQuery(document.createElement('div'))
808            .dialog({
809                autoOpen: false,
810                draggable: true,
811                //fix for dragging: http://stackoverflow.com/questions/17247486/jquery-ui-dialog-dragging-issues
812                drag: function(event, ui) {
813                    var fixPix = jQuery(document).scrollTop();
814                    iObj = ui.position;
815                    iObj.top = iObj.top - fixPix;
816                    jQuery(this).closest(".ui-dialog").css("top", iObj.top + "px");
817                },
818                title: title,
819                resizable: true,
820                buttons: dialogButtons,
821            })
822            .html(
823                '<div>' + dw_davcal__modals.msg + '</div>'
824            )
825            .parent()
826            .attr('id','dw_davcal__confirm')
827            .show()
828            .appendTo('.dokuwiki:first');
829
830            jQuery('#dw_davcal__confirm').position({
831                my: "center",
832                at: "center",
833                of: window
834            });
835                 // attach event handlers
836            jQuery('#dw_davcal__confirm .ui-dialog-titlebar-close').click(function(){
837                dw_davcal__modals.hideDialog();
838            });
839    },
840
841    /**
842     * Hide the edit event dialog
843     */
844    hideEditEventDialog : function() {
845        dw_davcal__modals.$editEventDialog.empty();
846        dw_davcal__modals.$editEventDialog.remove();
847        dw_davcal__modals.$editEventDialog = null;
848    },
849
850    /**
851     * Hide the confirm/info dialog
852     */
853    hideDialog: function() {
854        dw_davcal__modals.$dialog.empty();
855        dw_davcal__modals.$dialog.remove();
856        dw_davcal__modals.$dialog = null;
857    },
858
859    /**
860     * Hide the settings dialog
861     */
862    hideSettingsDialog: function() {
863        dw_davcal__modals.$settingsDialog.empty();
864        dw_davcal__modals.$settingsDialog.remove();
865        dw_davcal__modals.$settingsDialog = null;
866    }
867};
868