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