From 4d5a7f43076bd2dcc5dcc4a7b279d25e5e65cff9 Mon Sep 17 00:00:00 2001 From: Thomas Date: Fri, 23 Sep 2011 14:07:40 +0200 Subject: [PATCH] Add feature to create events from mails (#403) --- plugins/calendar/calendar.php | 138 +++++++++++++++--- plugins/calendar/calendar_base.js | 62 ++++++++ plugins/calendar/calendar_ui.js | 17 ++- plugins/calendar/lib/calendar_ui.php | 29 +++- plugins/calendar/localization/de_CH.inc | 1 + plugins/calendar/localization/de_DE.inc | 1 + plugins/calendar/localization/en_US.inc | 1 + plugins/calendar/skins/default/calendar.css | 5 +- .../skins/default/images/calendars.gif | Bin 1767 -> 1928 bytes .../skins/default/images/calendars.png | Bin 1849 -> 2103 bytes .../skins/default/templates/calendar.html | 104 +------------ .../skins/default/templates/eventedit.html | 103 +++++++++++++ 12 files changed, 327 insertions(+), 134 deletions(-) create mode 100644 plugins/calendar/skins/default/templates/eventedit.html diff --git a/plugins/calendar/calendar.php b/plugins/calendar/calendar.php index 20ca8828..a79db6ca 100644 --- a/plugins/calendar/calendar.php +++ b/plugins/calendar/calendar.php @@ -135,6 +135,9 @@ class calendar extends rcube_plugin $this->register_action('randomdata', array($this, 'generate_randomdata')); $this->register_action('print', array($this,'print_view')); $this->register_action('mailimportevent', array($this, 'mail_import_event')); + $this->register_action('mailtoevent', array($this, 'mail_message2event')); + $this->register_action('inlineui', array($this, 'get_inline_ui')); + $this->register_action('check-recent', array($this, 'check_recent')); // remove undo information... if ($undo = $_SESSION['calendar_event_undo']) { @@ -158,6 +161,19 @@ class calendar extends rcube_plugin $this->add_hook('message_load', array($this, 'mail_message_load')); $this->add_hook('template_object_messagebody', array($this, 'mail_messagebody_html')); } + + // add 'Create event' item to message menu + if ($this->api->output->type == 'html') { + $this->api->add_content(html::tag('li', null, + $this->api->output->button(array( + 'command' => 'calendar-create-from-mail', + 'label' => 'calendar.createfrommail', + 'type' => 'link', + 'classact' => 'calendarlink active', + 'class' => 'calendarlink', + ))), + 'messagemenu'); + } } // add hook to display alarms @@ -227,27 +243,7 @@ class calendar extends rcube_plugin // Add JS files to the page header $this->ui->addJS(); - $this->register_handler('plugin.calendar_css', array($this->ui, 'calendar_css')); - $this->register_handler('plugin.calendar_list', array($this->ui, 'calendar_list')); - $this->register_handler('plugin.calendar_select', array($this->ui, 'calendar_select')); - $this->register_handler('plugin.category_select', array($this->ui, 'category_select')); - $this->register_handler('plugin.freebusy_select', array($this->ui, 'freebusy_select')); - $this->register_handler('plugin.priority_select', array($this->ui, 'priority_select')); - $this->register_handler('plugin.sensitivity_select', array($this->ui, 'sensitivity_select')); - $this->register_handler('plugin.alarm_select', array($this->ui, 'alarm_select')); - $this->register_handler('plugin.snooze_select', array($this->ui, 'snooze_select')); - $this->register_handler('plugin.recurrence_form', array($this->ui, 'recurrence_form')); - $this->register_handler('plugin.attachments_form', array($this->ui, 'attachments_form')); - $this->register_handler('plugin.attachments_list', array($this->ui, 'attachments_list')); - $this->register_handler('plugin.attendees_list', array($this->ui, 'attendees_list')); - $this->register_handler('plugin.attendees_form', array($this->ui, 'attendees_form')); - $this->register_handler('plugin.attendees_freebusy_table', array($this->ui, 'attendees_freebusy_table')); - $this->register_handler('plugin.edit_attendees_notify', array($this->ui, 'edit_attendees_notify')); - $this->register_handler('plugin.edit_recurring_warning', array($this->ui, 'recurring_event_warning')); - $this->register_handler('plugin.event_rsvp_buttons', array($this->ui, 'event_rsvp_buttons')); - $this->register_handler('plugin.angenda_options', array($this->ui, 'angenda_options')); - $this->register_handler('plugin.searchform', array($this->rc->output, 'search_form')); // use generic method from rcube_template - + $this->ui->init_templates(); $this->rc->output->add_label('low','normal','high','delete','cancel','uploading','noemailwarning'); // initialize attendees autocompletion @@ -798,6 +794,15 @@ class calendar extends rcube_plugin } } + /** + * Handler for check-recent requests which are accidentally sent to calendar taks + */ + function check_recent() + { + // NOP + $this->rc->output->send(); + } + /** * Construct the ics file for exporting events to iCalendar format; */ @@ -1230,7 +1235,7 @@ class calendar extends rcube_plugin $calendar = get_input_value('calendar', RCUBE_INPUT_GPC); $uploadid = get_input_value('_uploadid', RCUBE_INPUT_GPC); - $eventid = $calendar.':'.$event; + $eventid = 'cal:'.$event; if (!is_array($_SESSION['event_session']) || $_SESSION['event_session']['id'] != $eventid) { $_SESSION['event_session'] = array(); @@ -1442,7 +1447,7 @@ class calendar extends rcube_plugin */ private function prepare_event(&$event, $action) { - $eventid = $event['calendar'].':'.$event['id']; + $eventid = 'cal:'.$event['id']; $attachments = array(); if (is_array($_SESSION['event_session']) && $_SESSION['event_session']['id'] == $eventid) { @@ -1456,7 +1461,7 @@ class calendar extends rcube_plugin } $event['attachments'] = $attachments; - + // check for organizer in attendees if ($event['attendees']) { $emails = $this->get_user_emails(); @@ -1487,6 +1492,7 @@ class calendar extends rcube_plugin private function cleanup_event(&$event) { // remove temp. attachment files + $eventid = 'cal:'.$event['id']; if (!empty($_SESSION['event_session']) && ($eventid = $_SESSION['event_session']['id'])) { $this->rc->plugins->exec_hook('attachments_cleanup', array('group' => $eventid)); unset($_SESSION['event_session']); @@ -1697,6 +1703,29 @@ class calendar extends rcube_plugin $this->rc->output->send("calendar.print"); } + /** + * + */ + public function get_inline_ui() + { + foreach (array('save','cancel','savingdata') as $label) + $texts['calendar.'.$label] = $this->gettext($label); + + $texts['calendar.new_event'] = $this->gettext('createfrommail'); + + $this->ui->init_templates(); + $this->ui->calendar_list(); # set env['calendars'] + echo $this->api->output->parse('calendar.eventedit', false, false); + echo html::tag('script', array('type' => 'text/javascript'), + "rcmail.set_env('calendars', " . json_encode($this->api->output->env['calendars']) . ");\n". + "rcmail.set_env('deleteicon', '" . $this->api->output->env['deleteicon'] . "');\n". + "rcmail.set_env('cancelicon', '" . $this->api->output->env['cancelicon'] . "');\n". + "rcmail.set_env('loadingicon', '" . $this->api->output->env['loadingicon'] . "');\n". + "rcmail.add_label(" . json_encode($texts) . ");\n" + ); + exit; + } + /** * Compare two event objects and return differing properties * @@ -2078,6 +2107,67 @@ class calendar extends rcube_plugin } + /** + * Read email message and return contents for a new event based on that message + */ + public function mail_message2event() + { + $uid = get_input_value('_uid', RCUBE_INPUT_POST); + $mbox = get_input_value('_mbox', RCUBE_INPUT_POST); + $event = array(); + + // establish imap connection + $this->rc->imap_connect(); + $this->rc->imap->set_mailbox($mbox); + $message = new rcube_message($uid); + + if ($message->headers) { + $event['title'] = trim($message->subject); + $event['description'] = trim($message->first_text_part()); + + // copy mail attachments to event + if ($message->attachments) { + $eventid = 'cal:'; + if (!is_array($_SESSION['event_session']) || $_SESSION['event_session']['id'] != $eventid) { + $_SESSION['event_session'] = array(); + $_SESSION['event_session']['id'] = $eventid; + $_SESSION['event_session']['attachments'] = array(); + } + + foreach ((array)$message->attachments as $part) { + $attachment = array( + 'data' => $this->rc->imap->get_message_part($uid, $part->mime_id, $part), + 'size' => $part->size, + 'name' => $part->filename, + 'mimetype' => $part->mimetype, + 'group' => $eventid, + ); + + $attachment = $this->rc->plugins->exec_hook('attachment_save', $attachment); + + if ($attachment['status'] && !$attachment['abort']) { + $id = $attachment['id']; + + // store new attachment in session + unset($attachment['status'], $attachment['abort'], $attachment['data']); + $_SESSION['event_session']['attachments'][$id] = $attachment; + + $attachment['id'] = 'rcmfile' . $attachment['id']; # add prefix to consider it 'new' + $event['attachments'][] = $attachment; + } + } + } + + $this->rc->output->command('plugin.mail2event_dialog', $event); + } + else { + $this->rc->output->command('display_message', $this->gettext('messageopenerror'), 'error'); + } + + $this->rc->output->send(); + } + + /** * Checks if specified message part is a vcalendar data * diff --git a/plugins/calendar/calendar_base.js b/plugins/calendar/calendar_base.js index eec2dbe5..1767faa6 100644 --- a/plugins/calendar/calendar_base.js +++ b/plugins/calendar/calendar_base.js @@ -18,6 +18,8 @@ function rcube_calendar(settings) { // member vars + this.ui; + this.ui_loaded = false; this.settings = settings; this.alarm_ids = []; this.alarm_dialog = null; @@ -156,6 +158,49 @@ function rcube_calendar(settings) this.dismiss_link = null; }; + // create new event from current mail message + this.create_from_mail = function() + { + var uid; + if ((uid = rcmail.get_single_uid())) { + // load calendar UI (scripts and edit dialog template) + if (!this.ui_loaded) { + $.when( + $.getScript('./plugins/calendar/calendar_ui.js'), + $.get(rcmail.url('calendar/inlineui'), function(html){ $(document.body).append(html); }, 'html') + ).then(function() { + // register attachments form + rcmail.gui_object('attachmentlist', 'attachmentlist'); + + // disable attendees feature (autocompletion and stuff is not initialized) + for (var c in rcmail.env.calendars) + rcmail.env.calendars[c].attendees = false; + + me.ui_loaded = true; + me.ui = new rcube_calendar_ui(me.settings); + me.create_from_mail(); // start over + }); + return; + } + else { + // get message contents for event dialog + var lock = rcmail.set_busy(true, 'loading'); + rcmail.http_post('calendar/mailtoevent', { + '_mbox': rcmail.env.mailbox, + '_uid': uid + }, lock); + } + } + }; + + // callback function triggered from server with contents for the new event + this.mail2event_dialog = function(event) + { + if (event.title) { + this.ui.add_event(event); + rcmail.message_list.blur(); + } + }; } // static methods @@ -222,6 +267,23 @@ window.rcmail && rcmail.addEventListener('init', function(evt) { $('#'+p.action+'-'+p.id).show(); }); + + // register create-from-mail command to message_commands array + if (rcmail.env.task == 'mail') { + // place link above 'view source' + $('#messagemenu a.calendarlink').parent().insertBefore($('#messagemenu a.sourcelink').parent()); + + rcmail.register_command('calendar-create-from-mail', function() { cal.create_from_mail() }); + rcmail.addEventListener('plugin.mail2event_dialog', function(p){ cal.mail2event_dialog(p) }); + rcmail.addEventListener('plugin.unlock_saving', function(p){ rcmail.set_busy(false, null, cal.ui.saving_lock); }); + + if (rcmail.env.action != 'show') { + rcmail.env.message_commands.push('calendar-create-from-mail'); + rcmail.add_element($('')); + } + else + rcmail.enable_command('calendar-create-from-mail', true); + } } rcmail.addEventListener('plugin.ping_url', function(p){ diff --git a/plugins/calendar/calendar_ui.js b/plugins/calendar/calendar_ui.js index 72c89bce..c2598944 100644 --- a/plugins/calendar/calendar_ui.js +++ b/plugins/calendar/calendar_ui.js @@ -723,6 +723,10 @@ function rcube_calendar_ui(settings) // activate the first tab $('#eventtabs').tabs('select', 0); + + // hack: set task to 'calendar' to make all dialog actions work correctly + var comm_path_before = rcmail.env.comm_path; + rcmail.env.comm_path = comm_path_before.replace(/_task=[a-z]+/, '_task=calendar'); var editform = $("#eventedit"); @@ -738,6 +742,7 @@ function rcube_calendar_ui(settings) rcmail.ksearch_blur(); rcmail.ksearch_destroy(); freebusy_data = {}; + rcmail.env.comm_path = comm_path_before; // restore comm_path }, buttons: buttons, minWidth: 500, @@ -1494,7 +1499,7 @@ function rcube_calendar_ui(settings) var update_event = function(action, data) { me.saving_lock = rcmail.set_busy(true, 'calendar.savingdata'); - rcmail.http_post('event', { action:action, e:data }); + rcmail.http_post('calendar/event', { action:action, e:data }); // render event temporarily into the calendar if ((data.start && data.end) || data.id) { @@ -1771,15 +1776,17 @@ function rcube_calendar_ui(settings) }; // public method to bring up the new event dialog - this.add_event = function() { + this.add_event = function(templ) { if (this.selected_calendar) { var now = new Date(); - var date = fc.fullCalendar('getDate') || now; + var date = fc.fullCalendar('getDate'); + if (typeof date != 'Date') + date = now; date.setHours(now.getHours()+1); date.setMinutes(0); var end = new Date(date.getTime()); end.setHours(date.getHours()+1); - event_edit_dialog('new', { start:date, end:end, allDay:false, calendar:this.selected_calendar }); + event_edit_dialog('new', $.extend({ start:date, end:end, allDay:false, calendar:this.selected_calendar }, templ || {})); } }; @@ -2391,7 +2398,7 @@ function rcube_calendar_ui(settings) }, beforeShowDay: function(date) { var view = fc.fullCalendar('getView'); - var active = date.getTime() >= view.visStart.getTime() && date.getTime() < view.visEnd.getTime(); + var active = view.visStart && date.getTime() >= view.visStart.getTime() && date.getTime() < view.visEnd.getTime(); return [ true, (active ? 'ui-datepicker-activerange ui-datepicker-active-' + view.name : ''), '']; } })) // set event handler for clicks on calendar week cell of the datepicker widget diff --git a/plugins/calendar/lib/calendar_ui.php b/plugins/calendar/lib/calendar_ui.php index 62cf0b4d..c5ed6774 100644 --- a/plugins/calendar/lib/calendar_ui.php +++ b/plugins/calendar/lib/calendar_ui.php @@ -63,7 +63,34 @@ class calendar_ui $this->ready = true; } - + + /** + * Register handler methods for the template engine + */ + public function init_templates() + { + $this->cal->register_handler('plugin.calendar_css', array($this, 'calendar_css')); + $this->cal->register_handler('plugin.calendar_list', array($this, 'calendar_list')); + $this->cal->register_handler('plugin.calendar_select', array($this, 'calendar_select')); + $this->cal->register_handler('plugin.category_select', array($this, 'category_select')); + $this->cal->register_handler('plugin.freebusy_select', array($this, 'freebusy_select')); + $this->cal->register_handler('plugin.priority_select', array($this, 'priority_select')); + $this->cal->register_handler('plugin.sensitivity_select', array($this, 'sensitivity_select')); + $this->cal->register_handler('plugin.alarm_select', array($this, 'alarm_select')); + $this->cal->register_handler('plugin.snooze_select', array($this, 'snooze_select')); + $this->cal->register_handler('plugin.recurrence_form', array($this, 'recurrence_form')); + $this->cal->register_handler('plugin.attachments_form', array($this, 'attachments_form')); + $this->cal->register_handler('plugin.attachments_list', array($this, 'attachments_list')); + $this->cal->register_handler('plugin.attendees_list', array($this, 'attendees_list')); + $this->cal->register_handler('plugin.attendees_form', array($this, 'attendees_form')); + $this->cal->register_handler('plugin.attendees_freebusy_table', array($this, 'attendees_freebusy_table')); + $this->cal->register_handler('plugin.edit_attendees_notify', array($this, 'edit_attendees_notify')); + $this->cal->register_handler('plugin.edit_recurring_warning', array($this, 'recurring_event_warning')); + $this->cal->register_handler('plugin.event_rsvp_buttons', array($this, 'event_rsvp_buttons')); + $this->cal->register_handler('plugin.angenda_options', array($this, 'angenda_options')); + $this->cal->register_handler('plugin.searchform', array($this->rc->output, 'search_form')); // use generic method from rcube_template + } + /** * Adds CSS stylesheets to the page header */ diff --git a/plugins/calendar/localization/de_CH.inc b/plugins/calendar/localization/de_CH.inc index 208db617..ad97c098 100644 --- a/plugins/calendar/localization/de_CH.inc +++ b/plugins/calendar/localization/de_CH.inc @@ -67,6 +67,7 @@ $labels['searchlaterdates'] = 'Spätere Termine suchen »'; $labels['andnmore'] = '$nr weitere...'; $labels['showmore'] = 'Mehr anzeigen...'; $labels['togglerole'] = 'Klick zum Ändern der Rolle'; +$labels['createfrommail'] = 'Als Termin speichern'; // agenda view $labels['listrange'] = 'Angezeigter Bereich:'; diff --git a/plugins/calendar/localization/de_DE.inc b/plugins/calendar/localization/de_DE.inc index 6aa5bfbe..e1452d63 100644 --- a/plugins/calendar/localization/de_DE.inc +++ b/plugins/calendar/localization/de_DE.inc @@ -67,6 +67,7 @@ $labels['searchlaterdates'] = 'Spätere Termine suchen »'; $labels['andnmore'] = '$nr weitere...'; $labels['showmore'] = 'Mehr anzeigen...'; $labels['togglerole'] = 'Klick zum Ändern der Rolle'; +$labels['createfrommail'] = 'Als Termin speichern'; // agenda view $labels['listrange'] = 'Angezeigter Bereich:'; diff --git a/plugins/calendar/localization/en_US.inc b/plugins/calendar/localization/en_US.inc index 29458a1e..ce0bfe0d 100644 --- a/plugins/calendar/localization/en_US.inc +++ b/plugins/calendar/localization/en_US.inc @@ -67,6 +67,7 @@ $labels['searchlaterdates'] = 'Search for later events »'; $labels['andnmore'] = '$nr more...'; $labels['showmore'] = 'Show more...'; $labels['togglerole'] = 'Click to toggle role'; +$labels['createfrommail'] = 'Save as event'; // agenda view $labels['listrange'] = 'Range to display:'; diff --git a/plugins/calendar/skins/default/calendar.css b/plugins/calendar/skins/default/calendar.css index d8497fcf..2c0c7978 100644 --- a/plugins/calendar/skins/default/calendar.css +++ b/plugins/calendar/skins/default/calendar.css @@ -1162,9 +1162,12 @@ fieldset #calendarcategories div { margin-bottom: 0.3em; } - /* Invitation UI in mail */ +#messagemenu li a.calendarlink { + background: url(images/calendars.png) 7px -109px no-repeat; +} + div.calendar-invitebox { min-height: 20px; margin: 5px 8px; diff --git a/plugins/calendar/skins/default/images/calendars.gif b/plugins/calendar/skins/default/images/calendars.gif index 353140952b29390dc915d40a5a8771c099f98f28..cf12ebdf8469fe1250f7e84a0a703d7a9e4f891c 100644 GIT binary patch literal 1928 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 J*u5wq06RFjSoHt^ diff --git a/plugins/calendar/skins/default/images/calendars.png b/plugins/calendar/skins/default/images/calendars.png index 76005d7fbae57d38ec57333b9f6d6a097500ab55..feb394519ce22c008adffb10aeb412dc6ddc1acd 100644 GIT binary patch delta 2067 zcmV+u2<-Q{4!01H7Ycp|1^@s6Ee(-Nks&942iZwPK~#9!?3jB{RM#EHzjycUgGC;@ zO9BfOVuIQ%#iRwQVswCv@P{Lo8D-i@rasz?sTpIMk*ecB6~S?$NoHD@blPU}M;j;O z5E^yzB2{8uU@M{!RtBsnFCi?;^4j;_+uymniyI2dR%T*5vxhl*Irp63@BYr~bHDe0 zaH1$;F-eBSrhjo9`YG2@rnH*!c6Mdu0e_yWj@d9i|^DmS>d~QH*z+%~+b4h!xA0 zNd|qLozNvD%s6-=BSXq8v9`=cDy;P7GOr+rZm&12%-S*=X3P6mf!ssk2wpGhKKKCr zLqmv-iNUUI+oVc%uaEBide<)B+{@)4J9+Rrkb49HE^<&@RD?a-w_|8{SSkm9?%8d& znKEk&zk@&oJd42P@!(EhAKtF3!}_&rrE(xm(ZJ1=eGy3GCu0soe*|u7kZdrZZ0}yY z|MACCIglr476SjXw#-Hha=-_=!14%9Au|Y+_Z>JOmDx4W1<@ZpZ>N>0raARe7tCZ> zQ(FtIR*RA?TcpM;RUbPx(-n4qPf2Y>j#D|9gF#VDPUE;3InN`J*1@sL$_4iiYfG+U zm@OL!gPqn=wpxAqzuAONvSGH|1Lwhmcffyoltxe3D_!%j7Z<7+(|^byv8?>zU8>-kEp!x3|{p7RqQGv>U>s}@l(2g7Xt`0PpSoG zh(yK`k!T%MaE(Xge-;K&VpiyMg2RS89yyX_9_X|&SgJ8#m8@8DU?L*j+`k{`r%u6G zSO_B0d168_i{P<>*WS^=K0+~l1E;MODvc6QCZOrHbMV-#3lnLm<2@)9JUC7c>zEtS z8Yi^6DF`$u(?p+8MB-h4ZU{*kKS3Y@P4wtY1ma`Uh<@cS|2cKEe}4Jqn|1U=@ZG(l zuxg$N?vBdf@l$F(BJpRN1?80+rw4Nja+5XcX?)paCPy45sh_cimB_e#TO!h_H{O`p zoxJZw<8$yyH@2ohEGs{Irp)bfA+c}(@18%8r*m?!CMydHrBWh)(Y!=T2SyZtBVMmZ zYnL(%~Cl^qlpkHLZpaB`YtpQx6)T%W)g%~gn1T~nbgW#H8tq#>A_NZ zz%NKYY%mypGs$r$!_r7E?%oYIb-`#f;`)^<_}z&UGuxRD)<_<|9%3n&K%)Z#II+JN zKUiVF*IkJ?^y+zk$;SIF9{4pTK1 zX9{4t+5$UuqsP>N=YPIYvRR+bg-4{?HU%y`En!duL zQDf+F=%CMh3P+Fssdr%1vWGdydYI$3seq-k=YMp=p>>B3?M>5YqR`(zjH;4Ul)u-9 z)YK$698Mg1{hfx8MB>-%d0m&5x#6J%y~g6;?_~DX(=-T;xp z(MS;@MTiv9NdNceNXwS%QG4$9F!guB1vef}qKIhka|#YUrP%38z*TOA&%xnVx4X&{ zbnL@4(v{H*=wH$YED@nnsi0P?p_C~Je@aYDjXS@8YH4Z+sgVXJ1|?&=%?_8{1?Q9# zFRXe2AC`WI_&BYK?c{r1n5B`*tE(YWtx~SU=8VmV)5PKNq{lI4A45%Z4Wum~1fOL2 ziNwM@~chpcO|`OG`Ki)5u!k2)ak;$?0wjgy#uG)=o{@W zxR68|$`uQK{IguW{*eTQm%8U93fZP?aN3=i9GGx*z1w|lULFukVv&v#7*I;nl*m35 z!DcydbzzwP&V+Knrb*`q@BGw?Xr#zF(n9BdNDVi~apJedp^3C{IWDEdap`kuq|YhH zCF@ea#d7l!Nq))E4n?W`Pi_%C49K!fDQdn~ze6l_J94SH0ym zj<+LA_vF2kZOqb0q0&`z8**~9(bCi+*;uwj1$Du%k>*MVS`Xv8^=lt&yyFnv0(wry z@AhbA$ui9G)iyg{8*YPsZGx1|9y7Flt94laY=HqzAFcg*!_diEBnRx2nh}Y8WX_dN<-aOjH=Qnm*=xZ=PAyW7PoJ|Es&-2b2(G>1 xoNSM7l&^MO; delta 1811 zcmV+u2kiK_5V;PJ7Yb|$1^@s6V-qslks&942HQzQK~#9!?3jB{R8<_uzjycUgXOsk z1q-=|q80>JNExOBG~yqP7&FS$*yN*{O2@25O2&Z{!Ew}dreJJ(On;P4;~;5HFG|U* zz|t(qm0?Ykml&|TmVNKN{m$J-o5@PkOxDaE=IrI%bAG?`JFn0E-ph%ih<}n~_^0WA zSB^tB<$B7L?xVbdU0J!um#(1Kh*Ie;R6V9cycU2UN_KXO(7AjB^bPU`k>lW~QY{23>7!&?O`U z9L&zllrl@KEwhmdv%I;?BM73)ayiIO9=s3aZb5*P9275Fgf%NxpzrEcsqDXJvswdX))qd02mT0n z7J<|4#^tUq?5nTG{QK{h%Kl`bi3^my5lHhVV-7@L1TJcjtk^0ZL|^p0jdr4%*3?5o7$C#ix;kjJT9hnV zA~j~IX6x3#P}n^swG}x|WoHh5dPOlgmE)r2JdZ@$2V1MEZg_rJTXG%EY}rKUZM2u> zsMY)b&LMP=4YTELIuCBX1OBTmJld~FTeI5b#$zrIRKr$$maN4pLxK!Ebum&cV5ulF zBHd28jfiw|u6H86+wq|{QFU}Vo^!u1wl5;;d|jRS2;GYYgg{SqK!8YpWGoSh_CY1r zv|0YP(2J4*g-$2ft+?!#BU$E#P8*FW8a=XQ#gYRf5$VE)4M^X$3mHX4AR-+hCKR&> zrWfx1KnGht#q=8-)-zCPlz=h;&AUH>+d6z>BK4g+1f_xp$H_4~<^giVVT{HZqo0M$OP3@f?b^FHa5{PKgU0LN3lo;6 zLM*E|e4xzbbRw~+2M3QF!GpQEn46OWg;FVzXhI^T1N{oX9v2^fkC?bPWYR=cZrq3y zEiFgd1}>fi~|4-54Am&Q15 z=cF{!b5B1F7Y!jJBLhF5I)&G^Zx0-2K3F5UeR_zcU;+*H^kDmjV%#}Xk6+poQU2-? z$;R_19{4npiNf4}ymKe+&dQR?EXOIVG=7>q>V#ccnc3ven50H}YIz}yKc0q-hS6a> zhi4vNDA~+U=O#y_y0Z!#Z#stat*toO+zeI02Fd1m?T0re(z$LMw7ILGIN5}>^mMeg zp2fT0j$qu7XONbWG9%LF@9p-doJ8f|^i#(u_I=%p{QEM0Fl_t|(;|k@Vb>u(>j7-p z_Eu-lpm_~*kaH`?EmHwgu3i7Z1?BTLm9IpCg29jkyWN5EJs&iN zBoaS&%^qE9)`D9S;x%SFe>tn`jfPgkvnBCrPwH<2gX88)KYtU_0X?A-=@J)$2E#X> ziD8ZOZ)v1|>k)}*q%oOnavCWlktU;&LJ?_F8p%&2m%|YtQm3CtlhH_FB87<*)=2;R z??`Dg;!*d}>o9h=!3h^`O`?eC>~jhZ9i>?1Ou&!aOs|7YXI!pochF}arjbq!9z}Ol z7Z4>vrBXqyRzoRM68@AJwTw8vJKfwEQX}<__DaToHmeOzn-dO;18cL_;?vSk5f`gf zv6KAA5U$Zk6*V;wsa7dhVsYkT#A;%3N75Y_vJIiOr54f=5Q4vC`G~~Q$k>=fBzLqM zk$ePd9;!j7xf2y%RG`z*Np=F1YC^x8UY|k{>CDlu5D^uDZO6AEQW1&L*`?^W^uug3 zqv1k-13gQi4Effk_)uSm)R!j~-uq}? zeEie|g@=acAPQM6Ryb@9jP;B<+Yg$4nve$slNh9<1bURxG9|JXMX*)&U!Ay0e+NQ2 zV9TWQfp=nRg*8(6JJOB5BQ;(a!S+{*LlbF!;S3y4iRIF-r;$!jkWuqez{PMA5=nm1 zjE{$U5xwO=%e^4p!l8o&+ItMT2zKEK_8Z=yN;7uJS z3(qtXd>YANvmw)`lNgcYYB>~gd6-E5c_RHTzyOKmo_<6>mL~uJ002ovPDHLkV1j%_ BW;*}? diff --git a/plugins/calendar/skins/default/templates/calendar.html b/plugins/calendar/skins/default/templates/calendar.html index a878d392..4098e5dd 100644 --- a/plugins/calendar/skins/default/templates/calendar.html +++ b/plugins/calendar/skins/default/templates/calendar.html @@ -89,109 +89,7 @@
-
- - -
-
- -
- -
-
- -
- -
-
- -
- -
-
- - -   - -
-
- -   - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
- - - -
- -
-
- -
-
- -
-
-
- -
+
diff --git a/plugins/calendar/skins/default/templates/eventedit.html b/plugins/calendar/skins/default/templates/eventedit.html new file mode 100644 index 00000000..35484788 --- /dev/null +++ b/plugins/calendar/skins/default/templates/eventedit.html @@ -0,0 +1,103 @@ +
+
+
    +
  • +
  • +
  • +
  • +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ + +   + +
+
+ +   + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+ + + +
+ +
+
+ +
+
+ +
+
+
+ +
\ No newline at end of file