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