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                    if(($val === 'on') || ($val === 'true'))
107                        $data['calname'] = true;
108                break;
109                default:
110                    $data[$key] = $val;
111            }
112        }
113
114        // Handle the default case when the user didn't enter a different ID
115        if(empty($data['id']))
116        {
117            $data['id'] = array($ID => '#3a87ad');
118        }
119
120        return $data;
121    }
122
123    private static function sort_events_asc($a, $b)
124    {
125        $from1 = new \DateTime($a['start']);
126        $from2 = new \DateTime($b['start']);
127        return $from2 < $from1;
128    }
129
130    private static function sort_events_desc($a, $b)
131    {
132        $from1 = new \DateTime($a['start']);
133        $from2 = new \DateTime($b['start']);
134        return $from1 < $from2;
135    }
136
137    /**
138     * Create output
139     */
140    function render($format, Doku_Renderer $R, $data) {
141        if($format == 'metadata')
142        {
143            $R->meta['plugin_davcal']['table'] = true;
144            return true;
145        }
146        if(($format != 'xhtml') && ($format != 'odt')) return false;
147        global $ID;
148
149        $events = array();
150        $from = $data['startdate'];
151        $toStr = null;
152
153        // Handle the various options to 'startDate'
154        if($from === 'today')
155        {
156            $from = new \DateTime();
157        }
158        elseif(strpos($from, 'today-') === 0)
159        {
160            $days = intval(str_replace('today-', '', $from));
161            $from = new \DateTime();
162            $from->sub(new \DateInterval('P'.$days.'D'));
163        }
164        elseif(strpos($from, 'today+') === 0)
165        {
166            $days = intval(str_replace('today+', '', $from));
167            $from = new \DateTime();
168            $from->add(new \DateInterval('P'.$days.'D'));
169        }
170        else
171        {
172            $from = new \DateTime($from);
173        }
174
175        // Handle the option 'startisend'
176        if($data['startisend'] === true)
177        {
178            if($data['numdays'] > 0)
179            {
180                $to = clone $from;
181                $to->sub(new \DateInterval('P'.$data['numdays'].'D'));
182                $fromStr = $to->format('Y-m-d');
183            }
184            else
185            {
186                $fromStr = null;
187            }
188            $toStr = $from->format('Y-m-d');
189        }
190        else
191        {
192            if($data['numdays'] > 0)
193            {
194                $to = clone $from;
195                $to->add(new \DateInterval('P'.$data['numdays'].'D'));
196                $toStr = $to->format('Y-m-d');
197            }
198            else
199            {
200                $toStr = null;
201            }
202            $fromStr = $from->format('Y-m-d');
203        }
204
205        // Support for timezone
206        $timezone = $data['timezone'];
207
208        // Filter events by user permissions
209        $userEvents = $this->hlp->filterCalendarPagesByUserPermission($data['id']);
210
211        // Fetch the events
212        foreach($userEvents as $calPage => $color)
213        {
214            $events = array_merge($events, $this->hlp->getEventsWithinDateRange($calPage,
215                                      $user, $fromStr, $toStr, $timezone));
216        }
217
218        // Sort the events
219        if($data['sort'] === 'desc')
220            usort($events, array("syntax_plugin_davcal_table", "sort_events_desc"));
221        else
222            usort($events, array("syntax_plugin_davcal_table", "sort_events_asc"));
223
224        // Create tabular output
225        $R->table_open();
226        $R->tablethead_open();
227        $R->tableheader_open();
228        $R->doc .= $data['onlystart'] ? hsc($this->getLang('at')) : hsc($this->getLang('from'));
229        $R->tableheader_close();
230        if(!$data['onlystart'])
231        {
232            $R->tableheader_open();
233            $R->doc .= hsc($this->getLang('to'));
234            $R->tableheader_close();
235        }
236        $R->tableheader_open();
237        $R->doc .= hsc($this->getLang('title'));
238        $R->tableheader_close();
239        if($data['location'])
240        {
241            $R->tableheader_open();
242            $R->doc .= hsc($this->getLang('location'));
243            $R->tableheader_close();
244        }
245        if($data['calname'])
246        {
247            $R->tableheader_open();
248            $R->doc .= hsc($this->getLang('calendar'));
249            $R->tableheader_close();
250        }
251        $R->tableheader_open();
252        $R->doc .= hsc($this->getLang('description'));
253        $R->tableheader_close();
254        $R->tablethead_close();
255        foreach($events as $event)
256        {
257            $R->tablerow_open();
258            $R->tablecell_open();
259            $from = new \DateTime($event['start']);
260            if($timezone !== 'local')
261            {
262                $from->setTimezone(new \DateTimeZone($timezone));
263                $to->setTimezone(new \DateTimeZone($timezone));
264            }
265            if($event['allDay'] === true)
266                $R->doc .= $from->format($data['alldayformat']);
267            else
268                $R->doc .= $from->format($data['dateformat']);
269            $R->tablecell_close();
270            if(!$data['onlystart'])
271            {
272                $to = new \DateTime($event['end']);
273                // Fixup all day events, which have one day in excess
274                if($event['allDay'] === true)
275                {
276                    $to->sub(new \DateInterval('P1D'));
277                }
278                $R->tablecell_open();
279                if($event['allDay'] === true)
280                    $R->doc .= $to->format($data['alldayformat']);
281                else
282                    $R->doc .= $to->format($data['dateformat']);
283                $R->tablecell_close();
284            }
285            $R->tablecell_open();
286            $R->doc .= hsc($event['title']);
287            $R->tablecell_close();
288            if($data['location'])
289            {
290                $R->tablecell_open();
291                $R->doc .= hsc($event['location']);
292                $R->tablecell_close();
293            }
294			if($data['calname'])
295            {
296                $R->tablecell_open();
297                $R->doc .= hsc($event['calendarname']);
298                $R->tablecell_close();
299            }
300            $R->tablecell_open();
301            $R->doc .= hsc($event['description']);
302            $R->tablecell_close();
303            $R->tablerow_close();
304        }
305        $R->table_close();
306    }
307
308
309
310}
311
312// vim:ts=4:sw=4:et:enc=utf-8:
313