1<?php 2/** 3 * DokuWiki Plugin DAVCal (Table Syntax Component) 4 * 5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 6 * @author Andreas Böhler <dev@aboehler.at> 7 */ 8 9// must be run within Dokuwiki 10if(!defined('DOKU_INC')) die(); 11 12if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); 13require_once(DOKU_PLUGIN.'syntax.php'); 14 15class syntax_plugin_davcal_table extends DokuWiki_Syntax_Plugin { 16 17 protected $hlp = null; 18 19 // Load the helper plugin 20 public function syntax_plugin_davcal_table() { 21 $this->hlp =& plugin_load('helper', 'davcal'); 22 } 23 24 25 /** 26 * What kind of syntax are we? 27 */ 28 function getType(){ 29 return 'substition'; 30 } 31 32 /** 33 * What about paragraphs? 34 */ 35 function getPType(){ 36 return 'normal'; 37 } 38 39 /** 40 * Where to sort in? 41 */ 42 function getSort(){ 43 return 165; 44 } 45 46 /** 47 * Connect pattern to lexer 48 */ 49 function connectTo($mode) { 50 $this->Lexer->addSpecialPattern('\{\{davcaltable>[^}]*\}\}',$mode,'plugin_davcal_table'); 51 } 52 53 /** 54 * Handle the match 55 */ 56 function handle($match, $state, $pos, Doku_Handler $handler){ 57 global $ID; 58 $options = trim(substr($match,14,-2)); 59 $options = explode(',', $options); 60 61 $data = array('id' => array(), 62 'startdate' => 'today', 63 'numdays' => 30, 64 'startisend' => false, 65 'dateformat' => 'Y-m-d H:i', 66 'alldayformat' => 'Y-m-d', 67 'onlystart' => false, 68 'location' => true, 69 'calname' => false, 70 'sort' => 'desc', 71 'timezone' => 'local' 72 ); 73 $lastid = $ID; 74 75 foreach($options as $option) 76 { 77 list($key, $val) = explode('=', $option); 78 $key = strtolower(trim($key)); 79 $val = trim($val); 80 switch($key) 81 { 82 case 'id': 83 $lastid = $val; 84 if(!in_array($val, $data['id'])) 85 $data['id'][$val] = '#3a87ad'; 86 break; 87 case 'onlystart': 88 if(($val === 'on') || ($val === 'true')) 89 $data['onlystart'] = true; 90 break; 91 case 'startisend': 92 if(($val === 'on') || ($val === 'true')) 93 $data['startisend'] = true; 94 break; 95 case 'timezone': 96 $tzlist = \DateTimeZone::listIdentifiers(DateTimeZone::ALL); 97 if(in_array($val, $tzlist) || $val === 'no') 98 $data['timezone'] = $val; 99 else 100 msg($this->getLang('error_timezone_not_in_list'), -1); 101 break; 102 case 'nolocation': 103 $data['location'] = false; 104 break; 105 case 'calname': 106 $data['calname'] = true; 107 break; 108 default: 109 $data[$key] = $val; 110 } 111 } 112 113 // Handle the default case when the user didn't enter a different ID 114 if(empty($data['id'])) 115 { 116 $data['id'] = array($ID => '#3a87ad'); 117 } 118 119 return $data; 120 } 121 122 private static function sort_events_asc($a, $b) 123 { 124 $from1 = new \DateTime($a['start']); 125 $from2 = new \DateTime($b['start']); 126 return $from2 < $from1; 127 } 128 129 private static function sort_events_desc($a, $b) 130 { 131 $from1 = new \DateTime($a['start']); 132 $from2 = new \DateTime($b['start']); 133 return $from1 < $from2; 134 } 135 136 /** 137 * Create output 138 */ 139 function render($format, Doku_Renderer $R, $data) { 140 if($format == 'metadata') 141 { 142 $R->meta['plugin_davcal']['table'] = true; 143 return true; 144 } 145 if(($format != 'xhtml') && ($format != 'odt')) return false; 146 global $ID; 147 148 $events = array(); 149 $from = $data['startdate']; 150 $toStr = null; 151 152 // Handle the various options to 'startDate' 153 if($from === 'today') 154 { 155 $from = new \DateTime(); 156 } 157 elseif(strpos($from, 'today-') === 0) 158 { 159 $days = intval(str_replace('today-', '', $from)); 160 $from = new \DateTime(); 161 $from->sub(new \DateInterval('P'.$days.'D')); 162 } 163 elseif(strpos($from, 'today+') === 0) 164 { 165 $days = intval(str_replace('today+', '', $from)); 166 $from = new \DateTime(); 167 $from->add(new \DateInterval('P'.$days.'D')); 168 } 169 else 170 { 171 $from = new \DateTime($from); 172 } 173 174 // Handle the option 'startisend' 175 if($data['startisend'] === true) 176 { 177 if($data['numdays'] > 0) 178 { 179 $to = clone $from; 180 $to->sub(new \DateInterval('P'.$data['numdays'].'D')); 181 $fromStr = $to->format('Y-m-d'); 182 } 183 else 184 { 185 $fromStr = null; 186 } 187 $toStr = $from->format('Y-m-d'); 188 } 189 else 190 { 191 if($data['numdays'] > 0) 192 { 193 $to = clone $from; 194 $to->add(new \DateInterval('P'.$data['numdays'].'D')); 195 $toStr = $to->format('Y-m-d'); 196 } 197 else 198 { 199 $toStr = null; 200 } 201 $fromStr = $from->format('Y-m-d'); 202 } 203 204 // Support for timezone 205 $timezone = $data['timezone']; 206 207 // Filter events by user permissions 208 $userEvents = $this->hlp->filterCalendarPagesByUserPermission($data['id']); 209 210 // Fetch the events 211 foreach($userEvents as $calPage => $color) 212 { 213 $events = array_merge($events, $this->hlp->getEventsWithinDateRange($calPage, 214 $user, $fromStr, $toStr, $timezone)); 215 } 216 217 // Sort the events 218 if($data['sort'] === 'desc') 219 usort($events, array("syntax_plugin_davcal_table", "sort_events_desc")); 220 else 221 usort($events, array("syntax_plugin_davcal_table", "sort_events_asc")); 222 223 // Create tabular output 224 $R->table_open(); 225 $R->tablethead_open(); 226 $R->tableheader_open(); 227 $R->doc .= $data['onlystart'] ? hsc($this->getLang('at')) : hsc($this->getLang('from')); 228 $R->tableheader_close(); 229 if(!$data['onlystart']) 230 { 231 $R->tableheader_open(); 232 $R->doc .= hsc($this->getLang('to')); 233 $R->tableheader_close(); 234 } 235 $R->tableheader_open(); 236 $R->doc .= hsc($this->getLang('title')); 237 $R->tableheader_close(); 238 if($data['location']) 239 { 240 $R->tableheader_open(); 241 $R->doc .= hsc($this->getLang('location')); 242 $R->tableheader_close(); 243 } 244 if($data['calname']) 245 { 246 $R->tableheader_open(); 247 $R->doc .= hsc($this->getLang('calendar')); 248 $R->tableheader_close(); 249 } 250 $R->tableheader_open(); 251 $R->doc .= hsc($this->getLang('description')); 252 $R->tableheader_close(); 253 $R->tablethead_close(); 254 foreach($events as $event) 255 { 256 $R->tablerow_open(); 257 $R->tablecell_open(); 258 $from = new \DateTime($event['start']); 259 if($timezone !== 'local') 260 { 261 $from->setTimezone(new \DateTimeZone($timezone)); 262 $to->setTimezone(new \DateTimeZone($timezone)); 263 } 264 if($event['allDay'] === true) 265 $R->doc .= $from->format($data['alldayformat']); 266 else 267 $R->doc .= $from->format($data['dateformat']); 268 $R->tablecell_close(); 269 if(!$data['onlystart']) 270 { 271 $to = new \DateTime($event['end']); 272 // Fixup all day events, which have one day in excess 273 if($event['allDay'] === true) 274 { 275 $to->sub(new \DateInterval('P1D')); 276 } 277 $R->tablecell_open(); 278 if($event['allDay'] === true) 279 $R->doc .= $to->format($data['alldayformat']); 280 else 281 $R->doc .= $to->format($data['dateformat']); 282 $R->tablecell_close(); 283 } 284 $R->tablecell_open(); 285 $R->doc .= hsc($event['title']); 286 $R->tablecell_close(); 287 if($data['location']) 288 { 289 $R->tablecell_open(); 290 $R->doc .= hsc($event['location']); 291 $R->tablecell_close(); 292 } 293 if($data['calname']) 294 { 295 $R->tablecell_open(); 296 $R->doc .= hsc($event['calendarname']); 297 $R->tablecell_close(); 298 } 299 $R->tablecell_open(); 300 $R->doc .= hsc($event['description']); 301 $R->tablecell_close(); 302 $R->tablerow_close(); 303 } 304 $R->table_close(); 305 } 306 307 308 309} 310 311// vim:ts=4:sw=4:et:enc=utf-8: 312