* * This plugin is based on the iCalEvents plugin by Robert Rackl . * */ // must be run within Dokuwiki if(!defined('DOKU_INC')) die(); if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); require_once(DOKU_PLUGIN.'syntax.php'); include_once(DOKU_INC.'lib/plugins/iCalendar/functions.php'); /** * This plugin gets an iCalendar file via HTTP and parses it into HTML. * * Usage: {{iCalendar>http://host/myCalendar.ics#from=today&previewDays=30}} * * You can filter the events that are shown with two parametes: * 1. 'from' a date from which on to show events. MUST be in the format MM/dd/yyyy * or you can simplay say "from=today". * If from is ommited, then all events are shown. * 2. 'previewDays' amount of days to preview into the future. * * from <= eventdate <= from+(previewDays*24*60*3600) * * There are some more configuration settins in plugins/iCalendar/conf/default.php * * @see http://de.wikipedia.org/wiki/ICalendar */ class syntax_plugin_iCalendar extends DokuWiki_Syntax_Plugin { function getInfo() { return array( 'author' => 'J. Drost-Tenfelde', 'email' => 'info@drost-tenfelde.de', 'date' => '2011-09-28', 'name' => 'iCalendar', 'desc' => 'Parses an iCalendar .ics file into HTML', 'url' => 'http://www.drost-tenfelde.de/?id=dokuwiki:plugins:icalendar', ); } // implement necessary Dokuwiki_Syntax_Plugin methods function getType() { return 'substition'; } function getSort() { return 42; } function connectTo($mode) { $this->Lexer->addSpecialPattern('\{\{iCalendar>.*?\}\}',$mode,'plugin_iCalendar'); } /** * parse parameters from the {{iCalendar>...}} tag. * @return an array that will be passed to the renderer function */ function handle($match, $state, $pos, &$handler) { $match = substr($match, 13, -2); // strip {{iCalendar> from start and }} from end list($icsURL, $flagStr) = explode('#', $match); parse_str($flagStr, $params); // Get the from parameter if ($params['from'] == 'today') { $from = time(); } else if (preg_match('#(\d\d)/(\d\d)/(\d\d\d\d)#', $params['from'], $fromDate)) { // must be MM/dd/yyyy $from = mktime(0, 0, 0, $fromDate[1], $fromDate[2], $fromDate[3]); } else if (preg_match('/\d+/', $params['from'])) { $from = $params['from']; } // Get the to parameter if ($params['to'] == 'today') { $to = mktime(24, 0, 0, date("m") , date("d"), date("Y")); } else if (preg_match('#(\d\d)/(\d\d)/(\d\d\d\d)#', $params['to'], $toDate)) { // must be MM/dd/yyyy $to = mktime(0, 0, 0, $toDate[1], $toDate[2], $toDate[3]); } else if (preg_match('/\d+/', $params['to'])) { $to = $params['to']; } // Get the numberOfEntries parameter if ($params['numberOfEntries']) { $numberOfEntries = $params['numberOfEntries']; } else { $numberOfEntries = -1; } // Get the show end dates parameter if ($params['showEndDates'] == 1 ) { $showEndDates = true; } else { $showEndDates = false; } // Get the show as list parameter if ( $params['showAs'] ) { $showAs = $params['showAs']; } else { $showAs = 'default'; } // Get the showAs parameter (since v1.4) if ( $params['showAs'] ) { $showAs = $params['showAs']; } else { // Backward compatibiltiy of v1.3 or earlier if ($params['showAsList'] == 1) { $showAs = 'list'; } else { $showAs = 'default'; } } // Get the appropriate template $template = $this->getConf($showAs); if ( !isset($template ) || $template == '' ) { $template = $this->getConf('default'); } // Find out if the events should be sorted in reserve $sort_descending = false; if ( $params['sort'] == 'DESC') { $sort_descending = true; } //echo $rsort; //exit( 0 ); // Get the previewDays parameter if ( $params['previewDays'] ) { $previewDays = $params['previewDays']; } else { $previewDays = -1; } #echo "url=$icsURL from = $from numberOfEntries = $numberOfEntries
"; return array($icsURL, $from, $to, $previewDays, $numberOfEntries, $showEndDates, $template, $sort_descending); } /** * loads the ics file via HTTP, parses it and renders an HTML table. */ function render($mode, &$renderer, $data) { list($url, $from, $to, $previewDays, $numberOfEntries, $showEndDates, $template, $sort_descending) = $data; $ret = ''.$mediadir; if ($mode == 'xhtml') { # parse the ICS file $entries = $this->_parseIcs($url, $from, $to, $previewDays, $numberOfEntries, $sort_descending); if ($this->error) { $renderer->doc .= "Error in Plugin iCalendar: ".$this->error; return true; } #loop over entries and create a table row for each one. $rowCount = 0; foreach ($entries as $entry) { $rowCount++; # Get the html for the entries $entryTemplate = $template; // {description} $entryTemplate = str_replace('{description}', $entry['description'], $entryTemplate ); // {summary} $entryTemplate = str_replace('{summary}', $entry['summary'], $entryTemplate ); // {summary_link} $summary_link = array(); $summary_link['class'] = 'urlintern'; $summary_link['style'] = 'background-image: url(lib/plugins/iCalendar/ics.png); background-repeat:no-repeat; padding-left:16px; text-decoration: none;'; $summary_link['pre'] = ''; $summary_link['suf'] = ''; $summary_link['more'] = 'rel="nofollow"'; $summary_link['target'] = ''; $summary_link['title'] = $entry['summary']; $summary_link['url'] = 'lib/plugins/iCalendar/vevent.php?vevent='.urlencode( $entry['vevent'] ); $summary_link['name'] = $entry['summary']; $entryTemplate = str_replace('{summary_link}', ''.$renderer->_formatLink($summary_link).'', $entryTemplate ); // See if a location was set $location = $entry['location']; if ( $location != '' ) { // {location} $entryTemplate = str_replace('{location}', $location, $entryTemplate ); // {location_link} $location_link = 'http://maps.google.com/maps?q='.str_replace(' ', '+', str_replace(',', ' ', $location)); $entryTemplate = str_replace('{location_link}', '[['.$location_link.'|'.$location.']]', $entryTemplate ); } else { // {location} $entryTemplate = str_replace('{location}', 'Unknown', $entryTemplate ); // {location_link} $entryTemplate = str_replace('{location_link}', 'Unknown', $entryTemplate ); } $dateString = ""; // Get the start and end day $startDay = date("Ymd", $entry['startunixdate']); $endDay = date("Ymd", $entry['endunixdate']); if ( $endDay > $startDay ) { if ( $entry['allday'] ) { $dateString = $entry['startdate'].'-'.$entry['enddate']; } else { $dateString = $entry['startdate'].' '.$entry['starttime'].'-'.$entry['enddate'].' '.$entry['endtime']; } } else { if ( $showEndDates ) { if ( $entry['allday'] ) { $dateString = $entry['startdate']; } else { $dateString = $entry['startdate'].' '.$entry['starttime'].'-'.$entry['endtime']; } } else { $dateString = $entry['startdate']; } } // {date} $entryTemplate = str_replace('{date}', $dateString, $entryTemplate ); $ret .= $entryTemplate.' '; } //$renderer->doc .= $ret; $html = p_render($mode, p_get_instructions( $ret ), $info ); $html = str_replace( '\\n', '
', $html ); $renderer->doc .= $html; return true; } return false; } /** * Load the iCalendar file from 'url' and parse all * events that are within the range * from <= eventdate <= from+previewSec * * @param url HTTP URL of an *.ics file * @param from unix timestamp in seconds (may be null) * @param to unix timestamp in seconds (may be null) * @param previewDays Limit the entries to 30 days in the future * @param numberOfEntries Number of entries to display * @param $sort_descending * @return an array of entries sorted by their startdate */ function _parseIcs($url, $from, $to, $previewDays, $numberOfEntries, $sort_descending ) { global $conf; $http = new DokuHTTPClient(); if (!$http->get($url)) { $this->error = "Could not get '$url': ".$http->status; return array(); } $content = $http->resp_body; $entries = array(); # If dateformat is set in plugin configuration ('dformat'), then use it. # Otherwise fall back to dokuwiki's default dformat from the global /conf/dokuwiki.php. $dateFormat = $this->getConf('dformat') ? $this->getConf('dformat') : $conf['dformat']; //$timeFormat = $this->getConf('tformat') ? $this->getConf('tformat') : $conf['tformat']; # regular expressions for items that we want to extract from the iCalendar file $regex_vevent = '/BEGIN:VEVENT(.*?)END:VEVENT/s'; #split the whole content into VEVENTs preg_match_all($regex_vevent, $content, $matches, PREG_PATTERN_ORDER); if ( $previewDays > 0 ) { $previewSec = $previewDays * 24 * 3600; } else { $previewSec = -1; } // loop over VEVENTs and parse out some itmes foreach ($matches[1] as $vevent) { $entry = parse_vevent( $vevent, $dateFormat ); // if entry is to old then filter it if ($from && $entry['endunixdate']) { if ($entry['endunixdate'] < $from) { continue; } if (($previewSec > 0) && ($entry['startunixdate'] > time()+$previewSec)) { continue; } } // if entry is to new then filter it if ($to && $entry['startunixdate']) { if ($entry['startunixdate'] > $to) { continue; } } $entries[] = $entry; } if ( $to && ($from == null) ) { // sort entries by startunixdate usort($entries, 'compareByEndUnixDate'); } else if ( $from ) { // sort entries by startunixdate usort($entries, 'compareByStartUnixDate'); } else if ( $sort_descending ) { $entries = array_reverse( $entries, true ); } // See if a maximum number of entries was set if ( $numberOfEntries > 0 ) { $entries = array_slice( $entries, 0, $numberOfEntries ); // Reverse array? if ( $from && $sort_descending) { $entries = array_reverse( $entries, true ); } else if ( $to && !$from && (!$sort_descending)) { $entries = array_reverse( $entries, true ); } } return $entries; } } /** compares two entries by their startunixdate value */ function compareByStartUnixDate($a, $b) { return strnatcmp($a['startunixdate'], $b['startunixdate']); } /** compares two entries by their startunixdate value */ function compareByEndUnixDate($a, $b) { return strnatcmp($b['endunixdate'], $a['endunixdate']); } ?>