/** * creates formatted output for calendar component property trigger * * @author Kjell-Inge Gustafsson, kigkonsult <*****@*****.**> * @since 2.4.16 - 2008-10-21 * @return string */ function createTrigger() { if (empty($this->trigger)) { return FALSE; } if (empty($this->trigger['value'])) { return $this->getConfig('allowEmpty') ? $this->_createElement('TRIGGER') : FALSE; } $content = $attributes = null; if (isset($this->trigger['value']['year']) && isset($this->trigger['value']['month']) && isset($this->trigger['value']['day'])) { $content .= iCalUtilityFunctions::_format_date_time($this->trigger['value']); } else { if (TRUE !== $this->trigger['value']['relatedStart']) { $attributes .= $this->intAttrDelimiter . 'RELATED=END'; } if ($this->trigger['value']['before']) { $content .= '-'; } $content .= iCalUtilityFunctions::_format_duration($this->trigger['value']); } $attributes .= $this->_createParams($this->trigger['params']); return $this->_createElement('TRIGGER', $attributes, $content); }
/** * Parses an VEVENT for Fullcalendar */ function parse_vevent_fullcalendar($vevent, $href, $etag, $calendar = 'calendario', $tz, $timezones) { $this_event = array('href' => $href, 'calendar' => $calendar, 'etag' => $etag, 'disableDragging' => FALSE, 'disableResizing' => FALSE, 'ignoreTimezone' => TRUE, 'timezone' => $tz->getName()); // Start and end date $dtstart = $this->extract_date($vevent, 'DTSTART', $tz); $dtend = $this->extract_date($vevent, 'DTEND', $tz); // We have for sure DTSTART $start = $dtstart['result']; // Do we have DTEND? if (!is_null($dtend)) { $end = $dtend['result']; } else { $duration = $vevent->getProperty('duration', false, false, true); // Calculate dtend if not present if ($duration !== FALSE) { $end = $this->CI->dates->idt2datetime($duration, $tz); } else { // RFC 2445, p52 if ($dtstart['value'] == 'DATE-TIME') { $end = clone $start; } else { $end = clone $start; $end->add(new DateInterval('P1D')); } } } // Is this a recurrent event? if (FALSE !== ($current_dtstart = $vevent->getProperty('x-current-dtstart'))) { // Is this a multiday event? In that case, ignore this event // Hack to avoid getProperty() ignore next getProperty() on // RRULE. if (FALSE === $vevent->rrule) { return FALSE; } $this_event['expanded'] = TRUE; // Format depends on DTSTART if (!isset($dtstart['property']['value']['hour'])) { $current_dtstart[1] .= ' 00:00:00'; } // Keep a copy $orig_start = clone $start; $start = $this->CI->dates->x_current2datetime($current_dtstart[1], $tz); unset($this_event['end']); $current_dtend = $vevent->getProperty('x-current-dtend'); if ($current_dtend !== FALSE) { if (!isset($dtstart['property']['value']['hour'])) { $current_dtend[1] .= ' 00:00:00'; } $orig_end = clone $end; $end = $this->CI->dates->x_current2datetime($current_dtend[1], $tz); } } $interesting_props = array('summary', 'uid', 'description', 'rrule', 'duration', 'location', 'class', 'recurrence-id', 'transp'); foreach ($interesting_props as $p) { // TODO: more properties // TODO multiple ocurrences of the same property? // TODO current-dtstart $prop = $vevent->getProperty($p, FALSE, TRUE); if ($prop === FALSE) { continue; } $val = $prop['value']; $params = $prop['params']; switch ($p) { case 'summary': $this_event['title'] = $val; break; case 'uid': $this_event['uid'] = $val; break; case 'description': $description = $val; $this_event['description'] = preg_replace('/\\\\n|\\\\r/', "\n", $description); // Format $this_event['formatted_description'] = preg_replace('/\\\\n|\\\\r/', '<br />', $description); break; case 'rrule': $this_event['rrule_serialized'] = base64_encode(serialize($val)); $new_val = trim($vevent->_format_recur('RRULE', array($prop))); $this_event['rrule'] = $new_val; $explanation = $this->CI->recurrence->rrule_explain($val, $unused); if ($explanation !== FALSE) { $this_event['rrule_explained'] = $explanation; } // TODO make it editable when able to parse it $this_event['editable'] = FALSE; break; case 'duration': $this_event['duration'] = iCalUtilityFunctions::_format_duration($val); break; case 'location': $this_event['location'] = $val; break; case 'class': $this_event['icalendar_class'] = $val; break; case 'transp': $this_event['transp'] = $val; break; case 'recurrence-id': // TODO parse a little bit $this_event['recurrence_id'] = $val; break; default: $this->CI->extended_logs->message('ERROR', 'Attempt to parse iCalendar property ' . $p . ' on VEVENT which is not developed ' . 'yet'); break; } } // Internal fullCalendar id $this_event['id'] = $calendar . ':' . $this_event['uid']; // Is this an all day event? $this_event['allDay'] = FALSE; if (isset($dtstart['value']) && $dtstart['value'] == 'DATE') { $this_event['allDay'] = TRUE; } else { if ($start->diff($end)->format('s') == '86400') { if ($start->format('Hi') == '0000') { $this_event['allDay'] = TRUE; } // Check using UTC and local time if ($start->getTimeZone()->getName() == 'UTC') { $test_start = clone $start; $test_start->setTimeZone($this->tz); if ($test_start->format('Hi') == '0000') { $this_event['allDay'] = TRUE; } } } } if ($this_event['allDay'] === TRUE) { // Fool fullcalendar (dates are inclusive). // For expanded events have special care, // iCalcreator expands them using start_day=end_day, which // confuses fullCalendar $start->setTime(0, 0, 0); $end->setTime(0, 0, 0); $end->sub(new DateInterval('P1D'))->add(new DateInterval('PT1H')); if (isset($this_event['expanded'])) { $orig_start->setTime(0, 0, 0); $orig_end->setTime(0, 0, 0); $orig_end->sub(new DateInterval('P1D'))->add(new DateInterval('PT1H')); } $this_event['orig_allday'] = TRUE; } else { $this_event['orig_allday'] = FALSE; } // To be used with strftime() $ts_start = $start->getTimestamp(); $ts_end = $end->getTimestamp(); // Needed for some conversions (Fullcalendar timestamp and am/pm // indicator) if (!isset($this_event['allDay']) || $this_event['allDay'] !== TRUE) { $start->setTimeZone($this->tz); $end->setTimeZone($this->tz); } // Expanded events if (isset($orig_start)) { $orig_start->setTimeZone($this->tz); $orig_end->setTimeZone($this->tz); $this_event['orig_start'] = $orig_start->format(DateTime::ISO8601); $this_event['orig_end'] = $orig_end->format(DateTime::ISO8601); } // Readable dates for start and end // Keep all day events as they are (UTC) $system_tz = date_default_timezone_get(); if (!isset($this_event['allDay']) || $this_event['allDay'] !== TRUE) { date_default_timezone_set($this->tz->getName()); } $this_event['formatted_start'] = strftime($this->date_format, $ts_start); if (isset($this_event['allDay']) && $this_event['allDay'] == TRUE) { // Next day? if ($start->format('Ymd') == $end->format('Ymd')) { $this_event['formatted_end'] = '(' . $this->CI->i18n->_('labels', 'allday') . ')'; } else { $this_event['formatted_end'] = strftime($this->date_format, $ts_end); } } else { // Are they in the same day? $this_event['formatted_start'] .= ' ' . $this->CI->dates->strftime_time($ts_start, $start); if ($start->format('Ymd') == $end->format('Ymd')) { $this_event['formatted_end'] = $this->CI->dates->strftime_time($ts_end, $end); } else { $this_event['formatted_end'] = strftime($this->date_format, $ts_end) . ' ' . $this->CI->dates->strftime_time($ts_end, $end); } } // Restore TZ date_default_timezone_set($system_tz); // Empty title? if (!isset($this_event['title'])) { $this_event['title'] = $this->CI->i18n->_('labels', 'untitled'); } $this_event['start'] = $start->format(DateTime::ISO8601); $this_event['end'] = $end->format(DateTime::ISO8601); // Reminders for this event $this_event['visible_reminders'] = array(); $this_event['reminders'] = array(); $valarms = $this->parse_valarms($vevent, $timezones); foreach ($valarms as $order => $reminder) { $this_event['visible_reminders'][] = $order; $this_event['reminders'][] = $reminder; } return $this_event; }