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