1<?php
2/**
3 * Plugin monthcal: Display monthly calendar
4 *
5 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author     Milosz Galazka <milosz@sleeplessbeastie.eu>
7 */
8
9if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
10if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
11require_once(DOKU_PLUGIN.'syntax.php');
12require_once (DOKU_INC . 'inc/html.php');
13
14/**
15 * All DokuWiki plugins to extend the parser/rendering mechanism
16 * need to inherit from this class
17 */
18class syntax_plugin_monthcal extends DokuWiki_Syntax_Plugin {
19
20   /**
21    * Get the type of syntax this plugin defines.
22    *
23    */
24    function getType(){
25        return 'substition';
26    }
27
28   /**
29    * Define how this plugin is handled regarding paragraphs.
30    *
31    */
32    function getPType(){
33        return 'block';
34    }
35
36   /**
37    * Where to sort in?
38    *
39    * Doku_Parser_Mode_html	190
40    *  --> execute here <--
41    * Doku_Parser_Mode_code	200
42    */
43    function getSort(){
44        return 199;
45    }
46
47   /**
48    * Connect lookup pattern to lexer.
49    *
50    */
51    function connectTo($mode) {
52      $this->Lexer->addSpecialPattern('{{monthcal.*?}}',$mode,'plugin_monthcal');
53    }
54
55   /**
56    * Handler to prepare matched data for the rendering process.
57    *
58    */
59    function handle($match, $state, $pos, Doku_Handler $handler){
60	$data = array();
61
62	// get page info
63	$INFO = pageinfo();
64
65	// default vaues
66	$data['month'] = date('m');
67	$data['year'] =  date('Y');
68	$data['namespace'] = $INFO['namespace'];
69	$data['create_links'] = 1;
70	$data['week_start_on'] = 0;
71	$data['display_weeks'] = 0;
72	$data['do_not_create_past_links'] = 0;
73	$data['borders'] = 0;
74	$data['mark_today'] = 1;
75	$data['align'] = 0;
76	$data['create_prev_next_links'] = 0;
77
78	$provided_data = substr($match, 11, -2);
79	$arguments = explode (',', $provided_data);
80	foreach ($arguments as $argument) {
81		list($key, $value) = explode('=', $argument);
82		switch($key) {
83			case 'year':
84				$data['year'] = $value;
85				break;
86			case 'month':
87				$data['month'] = $value;
88				break;
89			case 'namespace':
90				$data['namespace'] = (strpos($value, ':') === false) ?  ':' . $value : $value;
91				break;
92			case 'create_links':
93				switch(strtolower($value)) {
94					case 'no':
95						$data['create_links'] = 0;
96						break;
97					case 'local':
98						$data['create_links'] = 2;
99						break;
100					default:
101						$data['create_links'] = 1;
102						break;
103				}
104				break;
105			case 'week_start_on':
106				if (strtolower($value) == "sunday")
107					$data['week_start_on'] = 1;
108				else
109					$data['week_start_on'] = 0;
110				break;
111			case 'display_weeks':
112				switch(strtolower($value)) {
113					case 'no':
114						$data['display_weeks'] = 0;
115						break;
116					default:
117						$data['display_weeks'] = 1;
118						break;
119				}
120				break;
121			case 'do_not_create_past_links':
122				switch(strtolower($value)) {
123					case 'no':
124						$data['do_not_create_past_links'] = 0;
125						break;
126					default:
127						$data['do_not_create_past_links'] = 1;
128						break;
129				}
130				break;
131			case 'create_prev_next_links':
132				switch(strtolower($value)) {
133					case 'no':
134						$data['create_prev_next_links'] = 0;
135						break;
136					default:
137						$data['create_prev_next_links'] = 1;
138						break;
139				}
140				break;
141			case 'borders':
142				switch(strtolower($value)) {
143					case 'all':
144						$data['borders'] = 1;
145						break;
146					case 'table':
147						$data['borders'] = 2;
148						break;
149					default:
150						$data['borders'] = 0;
151						break;
152				}
153				break;
154			case 'mark_today':
155				switch(strtolower($value)) {
156					case 'no':
157						$data['mark_today'] = 0;
158						break;
159					default:
160						$data['mark_today'] = 1;
161						break;
162				}
163				break;
164			case 'align':
165				switch(strtolower($value)) {
166					case 'left':
167						$data['align'] = 1;
168						break;
169					case 'right':
170						$data['align'] = 2;
171						break;
172					default:
173						$data['align'] = 0;
174						break;
175				}
176				break;
177		}
178	}
179        return $data;
180    }
181
182   /**
183    * Handle the actual output creation.
184    *
185    */
186    function render($mode, Doku_Renderer $renderer, $data) {
187        if ($mode == 'xhtml'){
188            $renderer->doc .= $this->create_calendar($data);
189            return true;
190        }
191        return false;
192    }
193
194   /**
195    * Create calendar
196    *
197    */
198    function create_calendar($data) {
199	// date today
200	$date_today = new DateTime();
201
202	// date yesterday
203	$date_yesterday = (new DateTime($date_today->format('Y-m-d')))->modify('-1 day');
204
205
206	// date: from -> to
207	$date_from = new DateTime($data['year'] . "-" . $data['month'] . "-01");
208	$date_to   = (new DateTime($date_from->format('Y-m-d')))->modify('+1 month');
209
210	// date prev/next month
211	$date_prev_month = (new DateTime($date_from->format('Y-m-d')))->modify('-1 month');
212	$date_next_month = $date_to; //(new DateTime($date_to->format('Y-m-d')))->modify('+1 month');
213
214	$date_interval = new DateInterval('P1D');
215	$date_range    = new DatePeriod($date_from, $date_interval, $date_to);
216
217	// first day in on ...
218	$date_from_on_weekday = $date_from->format('N');
219
220	// language specific
221	$weekdays = $this->getLang('monthcal_weekdays_short');
222	$months   = $this->getLang('monthcal_months');
223
224	// weekday variable which is used inside each loop
225	$wday = 1;
226
227	// move by one element to the right if week starts at Sunday
228	if ($data['week_start_on'] == 1) {
229		if ($date_from_on_weekday <= 6)
230			$date_from_on_weekday += 1;
231		else
232			$date_from_on_weekday  = 1;
233	}
234
235	// border css
236	switch($data['align']) {
237		case 1:
238			$css_align = 'left';
239			break;
240		case 2:
241			$css_align = 'right';
242			break;
243		default:
244			$css_align = '';
245			break;
246	}
247
248	// border css
249	switch($data['borders']) {
250		case 1:
251			$css_table_border = 'withborder';
252			$css_td_border    = 'withborder';
253			break;
254		case 2:
255			$css_table_border = 'withborder';
256			$css_td_border    = 'borderless';
257			break;
258		case 0:
259			$css_table_border = 'borderless';
260			$css_td_border    = 'borderless';
261			break;
262	}
263
264	// html code
265	$html = '<table class="monthcal ' . $css_table_border . ' ' . $css_align . '">';
266
267	// colspan for month/year
268	$colspan_month = 4;
269	if ($data['display_weeks'] == '1') {
270		$colspan_year= 4;
271	} else {
272		$colspan_year= 3;
273	}
274
275	// header
276	$html .= '<tr class="description">';
277	$html .= '<td class="month ' . $css_td_border . '" colspan="' . $colspan_month . '">' . $months[$date_from->format('m')-1] . ' ';
278	if ($data['create_prev_next_links']){
279		$html .= html_wikilink($data['namespace'] . ':' . $date_prev_month->format('Y') . ':' . $date_prev_month->format('m') . ':', '<<');
280		$html .= html_wikilink($data['namespace'] . ':' . $date_next_month->format('Y') . ':' . $date_next_month->format('m') . ':', '>>');
281	}
282	$html .= '</td>';
283	$html .= '<td class="year" colspan="' . $colspan_year . '">' . $date_from->format('Y') . '</td></tr>';
284
285	// swap weekdays if week starts at Sunday
286	if ($data['week_start_on'] == 1) { $weekdays=array($weekdays[6],$weekdays[0],$weekdays[1],$weekdays[2],$weekdays[3],$weekdays[4],$weekdays[5]);}
287
288	// append empty header for week numbers
289	if ($data['display_weeks'] == '1') {
290		array_unshift($weekdays,"");
291	}
292
293	// weekdays
294	$html .= '<tr>';
295	foreach($weekdays as $weekday) {
296		$html .= '<th class="' . $css_td_border . '">' . $weekday . '</th>';
297	}
298	$html .= '</tr>';
299	$html .= '<tr>';
300
301	// initial week number
302	if ($data['display_weeks'] == '1') {
303		$html .= '<td class="' . $css_td_border . '">' . $date_from->format("W") . '</td>';
304	}
305
306	// first empty days
307	if ($date_from_on_weekday > 1) {
308		for($wday;$wday < $date_from_on_weekday;$wday++) {
309			$html .= '<td class="' . $css_td_border . '"></td>';
310		}
311	}
312
313	// month days
314	foreach($date_range as $date) {
315		if ($wday > 7) {
316			$wday = 1;
317			$html .= "</tr>";
318			$html .= "<tr>";
319
320			if ($data['display_weeks'] == '1') {
321				$html .= '<td class="' . $css_td_border . '">' . $date->format("W") . '</td>';
322			}
323		}
324
325		if ($date->format('Ymd') == $date_today->format('Ymd') and $data['mark_today'] == 1)
326			$css_today='today';
327		else
328			$css_today='';
329
330		if ($data['create_links'] == '1' ) {
331			$id = $data['namespace'] . ':' . $date->format('Y') . ':' . $date->format('m') . ':' . $date->format('d');
332			if (($data['do_not_create_past_links'] == '1') and ($date->format('Ymd') <  $date_today->format('Ymd'))) {
333				$page_exists = null;
334				resolve_pageid($data['namespace'] . ':' . $date->format('Y') . ':' . $date->format('m'), $date->format('d'), $page_exists);
335				if ($page_exists) {
336					$html_day = html_wikilink($id, $date->format('d'));
337				} else {
338					$html_day = $date->format('d');
339				}
340			} else {
341				$html_day = html_wikilink($id, $date->format('d'));
342			}
343		} else if ($data['create_links'] == '2' ) {
344			$html_day = '<a href="#section' . $date->format('d') . '">' . $date->format('d') . '</a>';
345		} else {
346			$html_day = $date->format('d');
347		}
348
349		$html .= '<td class="' . $css_td_border . ' ' . $css_today . '">' . $html_day .  '</td>';
350		$wday++;
351	}
352
353	// last empty days
354	if ($wday < 8) {
355		for($wday;$wday<8;$wday++) {
356			$html .= '<td class="' . $css_td_border . '"></td>';
357		}
358	}
359
360	// close table
361	$html .= '</table>';
362
363	// return table
364        return $html;
365    }
366}
367
368//Setup VIM: ex: et ts=4 enc=utf-8 :
369?>
370