PageRenderTime 61ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/~enabled/smd_calendar.php

https://bitbucket.org/mrdale/txp-plugins
PHP | 3258 lines | 2916 code | 178 blank | 164 comment | 400 complexity | 9765c280f80ce3fb85716ea8c1d6be92 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. // This is a PLUGIN TEMPLATE for Textpattern CMS.
  3. // Copy this file to a new name like abc_myplugin.php. Edit the code, then
  4. // run this file at the command line to produce a plugin for distribution:
  5. // $ php abc_myplugin.php > abc_myplugin-0.1.txt
  6. // Plugin name is optional. If unset, it will be extracted from the current
  7. // file name. Plugin names should start with a three letter prefix which is
  8. // unique and reserved for each plugin author ("abc" is just an example).
  9. // Uncomment and edit this line to override:
  10. $plugin['name'] = 'smd_calendar';
  11. // Allow raw HTML help, as opposed to Textile.
  12. // 0 = Plugin help is in Textile format, no raw HTML allowed (default).
  13. // 1 = Plugin help is in raw HTML. Not recommended.
  14. # $plugin['allow_html_help'] = 1;
  15. $plugin['version'] = '0.54';
  16. $plugin['author'] = 'Stef Dawson';
  17. $plugin['author_uri'] = 'http://stefdawson.com/';
  18. $plugin['description'] = 'Calendar / event / schedule system with events as Textpattern articles';
  19. // Plugin load order:
  20. // The default value of 5 would fit most plugins, while for instance comment
  21. // spam evaluators or URL redirectors would probably want to run earlier
  22. // (1...4) to prepare the environment for everything else that follows.
  23. // Values 6...9 should be considered for plugins which would work late.
  24. // This order is user-overrideable.
  25. $plugin['order'] = '5';
  26. // Plugin 'type' defines where the plugin is loaded
  27. // 0 = public : only on the public side of the website (default)
  28. // 1 = public+admin : on both the public and admin side
  29. // 2 = library : only when include_plugin() or require_plugin() is called
  30. // 3 = admin : only on the admin side (no AJAX)
  31. // 4 = admin+ajax : only on the admin side (AJAX supported)
  32. // 5 = public+admin+ajax : on both the public and admin side (AJAX supported)
  33. $plugin['type'] = '0';
  34. // Plugin "flags" signal the presence of optional capabilities to the core plugin loader.
  35. // Use an appropriately OR-ed combination of these flags.
  36. // The four high-order bits 0xf000 are available for this plugin's private use
  37. if (!defined('PLUGIN_HAS_PREFS')) define('PLUGIN_HAS_PREFS', 0x0001); // This plugin wants to receive "plugin_prefs.{$plugin['name']}" events
  38. if (!defined('PLUGIN_LIFECYCLE_NOTIFY')) define('PLUGIN_LIFECYCLE_NOTIFY', 0x0002); // This plugin wants to receive "plugin_lifecycle.{$plugin['name']}" events
  39. $plugin['flags'] = '0';
  40. // Plugin 'textpack' is optional. It provides i18n strings to be used in conjunction with gTxt().
  41. // Syntax:
  42. // ## arbitrary comment
  43. // #@event
  44. // #@language ISO-LANGUAGE-CODE
  45. // abc_string_name => Localized String
  46. /** Uncomment me, if you need a textpack
  47. $plugin['textpack'] = <<< EOT
  48. #@admin
  49. #@language en-gb
  50. abc_sample_string => Sample String
  51. abc_one_more => One more
  52. #@language de-de
  53. abc_sample_string => Beispieltext
  54. abc_one_more => Noch einer
  55. EOT;
  56. **/
  57. // End of textpack
  58. if (!defined('txpinterface'))
  59. @include_once('zem_tpl.php');
  60. # --- BEGIN PLUGIN CODE ---
  61. /**
  62. * smd_calendar
  63. *
  64. * A Textpattern CMS plugin for complete monthly event and calendar management
  65. * -> Originally based on mdp_calendar - thanks Marshall!
  66. * -> Full-size / mini calendar by month, with ISO week support
  67. * -> Txp articles are events. Future, past, and today's events are supported. Multi-day (spanned) events are based on article expiry
  68. * -> Next/prev month/year select list with customisable start/end years
  69. * -> Filter events by cat / section / author / status / time / expiry
  70. * -> Specify event frequency in custom field (1 week / 10 days / 3 months / etc)
  71. * -> Optionally (re)schedule / cancel / omit event dates
  72. * -> Customisable output for events and cells using multiple forms/container and classes
  73. * -> Conditional tags for building custom logic
  74. *
  75. * @author Stef Dawson
  76. * @link http://stefdawson.com/
  77. */
  78. // TODO:
  79. // * allow table header to be removed / restyled completely (the month/week dropdown & nav icons)
  80. // -- a form (navform?) for the header row with access to all vars such as which month is being displayed?
  81. // -- tools to allow the header to be generated from components and laid out in any manner?
  82. // * allow URL vars to be passed as POST (to bypass gbp_permlinks)
  83. // * add custom rows to the table (header, footer) -- header could be used to replace the current nav/dropdowns
  84. // * div-based calendar layout?
  85. // TOFIX:
  86. // * Expiry dates on extra+ allspanned dates in smd_article_event (and calendar?). They currently 'creep' a day for every day of a spanned event
  87. // * Ranges in stepfields (http://forum.textpattern.com/viewtopic.php?pid=254395#p254395 and http://forum.textpattern.com/viewtopic.php?pid=255617#p255617)
  88. if( $date = gps('date') ) {
  89. $_GET['month'] = $date;
  90. }
  91. function smd_calendar($atts, $thing='') {
  92. global $pretext, $thisarticle, $variable, $prefs, $smd_cal_flag, $smd_date, $smd_calinfo, $smd_cal_ucls;
  93. extract(lAtts(array(
  94. 'time' => 'any',
  95. 'size' => 'large',
  96. 'expired' => '',
  97. 'category' => null,
  98. 'subcats' => '',
  99. 'section' => '',
  100. 'author' => '',
  101. 'realname' => '',
  102. 'status' => 'live',
  103. 'showall' => '0',
  104. 'static' => '',
  105. 'form' => '',
  106. 'spanform' => 'SMD_SAME',
  107. 'recurform' => 'SMD_SAME',
  108. 'cellform' => '',
  109. 'headerform' => '',
  110. 'stepfield' => '',
  111. 'skipfield' => '',
  112. 'omitfield' => '',
  113. 'extrafield' => '',
  114. 'extrastrict' => '0',
  115. 'datefields' => '',
  116. 'showskipped' => '0',
  117. 'showspanned' => '1',
  118. 'holidays' => '',
  119. 'holidayflags' => 'standard',
  120. 'classlevels' => 'cell, event',
  121. 'linkposted' => 'recur, multi, multiprev, multilast',
  122. 'classprefixes' => 'smd_cal_, smd_cal_ev_',
  123. 'class' => '',
  124. 'rowclass' => '',
  125. 'cellclass' => '',
  126. 'emptyclass' => 'empty',
  127. 'isoweekclass' => 'week',
  128. 'navclass' => 'navprev, navnext',
  129. 'navarrow' => '&#60;, &#62;',
  130. 'navid' => '',
  131. 'eventclasses' => 'category',
  132. 'eventwraptag' => 'span',
  133. 'select' => '',
  134. 'selectbtn' => '',
  135. 'myclass' => '',
  136. 'mywraptag' => '',
  137. 'caption' => '',
  138. 'summary' => '',
  139. 'id' => '',
  140. 'week' => '',
  141. 'month' => '',
  142. 'year' => '',
  143. 'remap' => '',
  144. 'yearwidth' => '0',
  145. 'isoweeks' => '',
  146. 'dayformat' => 'ABBR',
  147. 'monthformat' => 'FULL',
  148. 'firstday' => 0,
  149. 'maintain' => 'calid',
  150. 'nameval' => '',
  151. 'event_delim' => ',',
  152. 'gmt' => 0,
  153. 'lang' => '',
  154. 'debug' => 0,
  155. ), $atts));
  156. $size = (in_array($size, array('small', 'large'))) ? $size : 'large';
  157. $status = ($status) ? $status : 'live'; // in case status is empty
  158. $firstday = ($isoweeks == '') ? $firstday : 1;
  159. $spanform = ($spanform == 'SMD_SAME') ? $form : $spanform;
  160. $recurform = ($recurform == 'SMD_SAME') ? $form : $recurform;
  161. $cellform = (empty($cellform)) ? '' : fetch_form($cellform);
  162. $headerform = (empty($headerform)) ? '' : fetch_form($headerform);
  163. $frontpage = ($section=='' && $pretext['s']=='default') ? true : false;
  164. // Set up the class prefixes
  165. $clevs = do_list($classlevels);
  166. $cls = do_list($classprefixes);
  167. $cls_pfx = $evc_pfx = $cls[0];
  168. if (count($cls) > 1){
  169. $evc_pfx = $cls[1];
  170. }
  171. // Set up the nav class(es)
  172. $maintain = do_list($maintain);
  173. $navarrow = do_list($navarrow);
  174. $navparr = $navarrow[0];
  175. $navnarr = (count($navarrow) > 1) ? $navarrow[1] : $navarrow[0];
  176. $navclass = do_list($navclass);
  177. $navpclass = $navclass[0];
  178. $navnclass = (count($navclass) > 1) ? $navclass[1] : $navclass[0];
  179. // Filters
  180. $fopts = array();
  181. $catSQL = $secSQL = $authSQL = $fpSQL = '';
  182. if($category !== null) {
  183. $uncats = false;
  184. $allcats = do_list($category);
  185. if (($pos = array_search('SMD_UNCAT', $allcats)) !== false) {
  186. $uncats = true;
  187. unset($allcats[$pos]);
  188. $category = join(',', $allcats);
  189. }
  190. $fopts['c'] = $category; // TODO: Can fopts take a list? Should it include subcats?
  191. $subcats = (empty($subcats)) ? 0 : ((strtolower($subcats)=="all") ? 99999 : intval($subcats));
  192. if ($subcats) {
  193. $outcats = array();
  194. foreach ($allcats as $cat) {
  195. $cats = getTree(doslash($cat), 'article');
  196. foreach ($cats as $jdx => $val) {
  197. if ($cats[$jdx]['level'] <= $subcats) {
  198. $outcats[] = $cats[$jdx]['name'];
  199. }
  200. }
  201. }
  202. $allcats = $outcats;
  203. }
  204. $catSQL = doQuote(join("','", doSlash($allcats)));
  205. $catSQL = ($uncats ? " AND (Category1 = '' AND Category2 = '')" : '') .
  206. ($uncats && $allcats ? " OR " : ($allcats ? " AND " : '')) .
  207. ($allcats ? "( Category1 IN (".$catSQL.") OR Category2 IN (".$catSQL.") ) " : '');
  208. }
  209. if($section) {
  210. $secs = do_list($section);
  211. $smd_calinfo['s'] = $secs[0];
  212. $secSQL = doQuote(join("','", doSlash($secs)));
  213. $secSQL = " AND Section IN (".$secSQL.") ";
  214. }
  215. if($realname) {
  216. $authors = safe_column('name', 'txp_users', 'RealName IN ('. doQuote(join("','", doArray(do_list($realname), 'urldecode'))) .')' );
  217. $author = join(',', $authors);
  218. }
  219. if($author) {
  220. $fopts['author'] = htmlentities(gps('author'));
  221. $authSQL = doQuote(join("','", doSlash(do_list($author))));
  222. $authSQL = " AND AuthorID IN (".$authSQL.") ";
  223. }
  224. if ($frontpage && !$showall) {
  225. $fpSQL = filterFrontPage();
  226. }
  227. $smd_calinfo['artid'] = $thisarticle['thisid'];
  228. $smd_calinfo['artitle'] = $thisarticle['url_title'];
  229. $nameval = do_list($nameval);
  230. foreach ($nameval as $nv) {
  231. $nv = explode("=", $nv);
  232. if ($nv[0]) {
  233. $fopts[$nv[0]] = ((isset($nv[1])) ? $nv[1] : '');
  234. }
  235. }
  236. $status = do_list($status);
  237. $stati = array();
  238. foreach ($status as $stat) {
  239. if (empty($stat)) {
  240. continue;
  241. } else if (is_numeric($stat)) {
  242. $stati[] = $stat;
  243. } else {
  244. $stati[] = getStatusNum($stat);
  245. }
  246. }
  247. $stati = " Status IN (".join(',', $stati).")";
  248. $expired = ($expired) ? $expired : $prefs['publish_expired_articles'];
  249. $expired = (($expired) ? '' : ' AND (now() <= Expires OR Expires = '.NULLDATETIME.')');
  250. $eventclasses = do_list($eventclasses);
  251. $holidayflags = do_list($holidayflags);
  252. $linkposted = do_list($linkposted);
  253. $datefields = do_list($datefields);
  254. // Work out the first and last posts to determine the year range - probably a better way of doing this than 3 queries
  255. $filt = $stati . (($category !== null) ? $catSQL : '') . (($section) ? $secSQL : '') . (($author) ? $authSQL : '') . $fpSQL;
  256. $earliest = safe_field('unix_timestamp(Posted) AS uPosted', 'textpattern', $filt .' ORDER BY Posted ASC LIMIT 0, 1', $debug);
  257. $lp = safe_field('unix_timestamp(Posted) AS uPosted', 'textpattern', $filt .' ORDER BY Posted DESC LIMIT 0, 1', $debug);
  258. $lm = safe_field('unix_timestamp(LastMod) AS uLastMod', 'textpattern', $filt .' ORDER BY LastMod DESC LIMIT 0, 1', $debug);
  259. $latest = ($time=="past") ? time() : (($lp > $lm) ? $lp : $lm);
  260. $yearwidth = do_list($yearwidth);
  261. $yearwidth[0] = (empty($yearwidth[0])) ? 0 : $yearwidth[0];
  262. if (count($yearwidth) == 1) {
  263. $yearwidth[1] = $yearwidth[0];
  264. }
  265. $usenow = array(false,false);
  266. foreach ($yearwidth as $yridx => $yritem) {
  267. if (strpos($yritem,"c") !== false) {
  268. $yearwidth[$yridx] = intval($yritem);
  269. $usenow[$yridx] = true;
  270. }
  271. }
  272. // Remap w/m/y to other vars if required
  273. $remap = do_list($remap);
  274. $dmap = array("y" => "y", "m" => "m", "w" => "w");
  275. foreach ($remap as $dpair) {
  276. $dpair = do_list($dpair, ':');
  277. $dmap[$dpair[0]] = (isset($dpair[1])) ? $dpair[1] : $dpair[0];
  278. }
  279. $earliest = date("Y", strtotime("-".$yearwidth[0]." year", ( (empty($earliest) || $usenow[0]==true) ? time() : $earliest) ) );
  280. $latest = date("Y", strtotime("+".$yearwidth[1]." year", ( (empty($latest) || $usenow[1]==true) ? time() : $latest) ) );
  281. // Check the URL for current date and calendar target info
  282. $in_calid = gps('calid');
  283. $in_year = (gps($dmap["y"]) and is_numeric(gps($dmap["y"]))) ? (int)gps($dmap["y"]) : '';
  284. $in_month = (gps($dmap["m"]) and is_numeric(gps($dmap["m"]))) ? (int)gps($dmap["m"]) : '';
  285. $in_week = (gps($dmap["w"]) and is_numeric(gps($dmap["w"]))) ? (int)gps($dmap["w"]) : '';
  286. if($static) { // if we're static w/o any supplied vars, use the current date
  287. if(!$year) { $year = safe_strftime('%Y'); }
  288. if(!$month) { $month = safe_strftime('%m'); }
  289. } else { // otherwise use current date only if there's nothing else
  290. if( $id == $in_calid ) { // use incoming
  291. $year = ($in_year) ? $in_year : (($year) ? $year : safe_strftime('%Y'));
  292. $month = ($in_month) ? $in_month : (($month) ? $month : safe_strftime('%m'));
  293. // If week is used, adjust month so it encompasses the given week
  294. $week = $in_week;
  295. if ($week) {
  296. $month = safe_strftime("%m", strtotime($year."W".str_pad($week, 2, '0', STR_PAD_LEFT))); // Get the month from the week
  297. }
  298. } else { // use current
  299. if(!$year) { $year = safe_strftime('%Y'); }
  300. if(!$month) { $month = safe_strftime('%m'); }
  301. if($week) { $month = safe_strftime("%m", strtotime($year."W".str_pad($week, 2, '0', STR_PAD_LEFT))); }
  302. }
  303. }
  304. $smd_calinfo['id'] = ($in_calid) ? $in_calid : $id;
  305. $smd_date['y'] = $year; $smd_date['m'] = $month; // $week/day/isoyear are set per event later
  306. $ts_first = mktime(0, 0, 0, $month, 1, $year);
  307. $ts_last = mktime(23, 59, 59, $month, date('t',$ts_first), $year);
  308. $ts_lastoff = $ts_last - tz_offset($ts_last);
  309. if ($debug) {
  310. echo "++ THIS MONTH'S CALENDAR [ start stamp // end date // end stamp // end date // tz offset (end) ] ++";
  311. dmp($ts_first, date('Y-m-d H:i:s', $ts_first), $ts_last, date('Y-m-d H:i:s', $ts_last), $ts_lastoff);
  312. }
  313. $extrasql = $catSQL . $secSQL . $authSQL . $fpSQL;
  314. switch($time) {
  315. case "any" : break;
  316. case "future" : $extrasql .= " AND Posted > now()"; break;
  317. default : $extrasql .= " AND Posted < now()"; break; // The past
  318. }
  319. // Holidays are global 'exclusions', either defined directly or in a txp:variable
  320. $holidays = do_list($holidays);
  321. $txphols = do_list($holidays[0], ":");
  322. if ($txphols[0] == "txpvar") {
  323. $holidays = do_list($variable[$txphols[1]]);
  324. }
  325. // Force each holiday to a known format. Holidays without years use current year
  326. foreach ($holidays as $key => $val) {
  327. if (empty($val)) continue;
  328. $numparts = preg_match('/^([\d\w]+).?([\d\w]+).?([\d\w]+)?$/', $val, $parts);
  329. if ($numparts) {
  330. if (count($parts) == 3) {
  331. $parts[3] = $year;
  332. }
  333. $val = str_pad($parts[1], 2, '0', STR_PAD_LEFT).'-'.str_pad($parts[2], 2, '0', STR_PAD_LEFT).'-'.$parts[3];
  334. }
  335. $holidays[$key] = date("d-M-Y", safe_strtotime($val));
  336. }
  337. if ($debug > 0 && !empty($holidays) && $holidays[0] != '') {
  338. echo "++ HOLIDAYS ++ ";
  339. dmp($holidays);
  340. }
  341. // Get all matching articles in (and before) this month
  342. $events = array();
  343. $uposted_field = (empty($datefields[0])) ? 'uPosted' : "UNIX_TIMESTAMP($datefields[0])";
  344. $sql2 = $stati . " HAVING $uposted_field <= ".$ts_lastoff. $expired . $extrasql ." ORDER BY Posted ASC";
  345. $grabCols = '*, unix_timestamp(Posted) as uPosted, unix_timestamp(LastMod) as uLastMod, unix_timestamp(Expires) as uExpires';
  346. $evlist = safe_rows($grabCols, 'textpattern', $sql2, $debug);
  347. article_push();
  348. // If any events recur and fall within the current month, add those as well
  349. // If any dates are to be excluded, the entry is skipped UNLESS showskipped indicates otherwise
  350. foreach ($evlist as $row) {
  351. $idx = 0; // In case the 1st day of the month is a continuation of an event from the end of the previous month
  352. $start = (!empty($datefields[0]) && !empty($row[$datefields[0]]) && ($stdt = strtotime($row[$datefields[0]])) !== false) ? $stdt : $row['uPosted'] + tz_offset($row['uPosted']);
  353. $start_date = date("Y-m-d", $start); // For recurring/spanned events on a minical, this is the event the cell links to
  354. $real_end = (isset($datefields[1]) && !empty($row[$datefields[1]]) && ($endt = strtotime($row[$datefields[1]])) !== false) ? $endt : (($row['uExpires']==0) ? 0 : $row['uExpires'] + tz_offset($row['uExpires']));
  355. // If end < start the user-specified dates cannot be trusted
  356. if ($real_end != 0 && $real_end <= $start) {
  357. $start = $row['uPosted'] + tz_offset($row['uPosted']);
  358. $real_end = $row['uExpires'] + tz_offset($row['uExpires']);
  359. trigger_error('Expiry cannot be before start date in "'.$row['Title'].'": ignored', E_USER_WARNING);
  360. }
  361. $end = ($real_end != 0 && $real_end < $ts_last) ? $real_end : $ts_last;
  362. $real_diff = ($real_end==0) ? 0 : $real_end - $start;
  363. $real_end_month = ($real_end==0) ? 0 : date('m', $real_end);
  364. $real_end_year = ($real_end==0) ? 0 : date('Y', $real_end);
  365. $fake_diff = strtotime(date("Y-M-d", $real_end) . " 23:59:59");
  366. $diff = ($real_end==0) ? 0 : $fake_diff - $start;
  367. $smd_cal_flag = array();
  368. $smd_cal_ucls = array();
  369. $ev_month = date('m', $start);
  370. $ev_year = date('Y', $start);
  371. $ev_hr = date('H', $start);
  372. $ev_mn = date('i', $start);
  373. $ev_sc = date('s', $start);
  374. if ($debug > 1) {
  375. echo '++ EVENT START // END // (if non-zero) REAL END ++';
  376. dmp(date('d-M-Y H:i:s', $start) .' // '. date('d-M-Y H:i:s', $end) .' // '. ( ($real_end == 0) ? '' : date('d-M-Y H:i:s', $real_end) ));
  377. dmp($row['Title']);
  378. if ($debug > 2) {
  379. dmp($row);
  380. }
  381. }
  382. $multi = (($end > $start) && ($real_end > $start) && ($real_end > $ts_first) && (date("d-m-Y", $real_end) != date("d-m-Y", $start))) ? true : false;
  383. $recur = (empty($row[$stepfield])) ? false : true;
  384. $hol_hit = in_array(date("d-M-Y", $start), $holidays);
  385. $evclasses = array();
  386. foreach ($eventclasses as $evcls) {
  387. switch ($evcls) {
  388. case "":
  389. break;
  390. case "gcat":
  391. if (isset($pretext['c']) && !empty($pretext['c'])) {
  392. $evclasses[] = $evc_pfx.$pretext['c'];
  393. }
  394. break;
  395. case "category":
  396. if (isset($row['Category1']) && !empty($row['Category1'])) {
  397. $evclasses[] = $evc_pfx.$row['Category1'];
  398. }
  399. if (isset($row['Category2']) && !empty($row['Category2'])) {
  400. $evclasses[] = $evc_pfx.$row['Category2'];
  401. }
  402. break;
  403. case "section":
  404. if (isset($pretext['s']) && !empty($pretext['s'])) {
  405. $evclasses[] = $evc_pfx.$pretext['s'];
  406. }
  407. break;
  408. case "author":
  409. if (isset($pretext['author']) && !empty($pretext['author'])) {
  410. $evclasses[] = $evc_pfx.$pretext['author'];
  411. }
  412. break;
  413. default:
  414. if (isset($row[$evcls]) && !empty($row[$evcls])) {
  415. $evclasses[] = $evc_pfx.$row[$evcls];
  416. }
  417. break;
  418. }
  419. }
  420. $ignore = array();
  421. $omit = array();
  422. $cflag = array();
  423. if ($debug > 1 && $evclasses) {
  424. echo '++ EVENT CLASSES ++';
  425. dmp($evclasses);
  426. }
  427. // Events that start or are added this month
  428. if (($start < $end) && ($start > $ts_first)) {
  429. populateArticleData($row);
  430. // a standard event or start of a multi
  431. if ($showspanned && $multi && !$recur) {
  432. $smd_cal_flag[] = 'multifirst';
  433. }
  434. if ($recur) {
  435. $smd_cal_flag[] = 'recurfirst';
  436. }
  437. if (!$smd_cal_flag) {
  438. $smd_cal_flag[] = 'standard';
  439. }
  440. if ( ( $hol_hit && !in_array('multi',$holidayflags) && in_array('multifirst',$smd_cal_flag) ) || ( $hol_hit && !in_array('standard',$holidayflags) && in_array('standard',$smd_cal_flag) ) ) {
  441. $smd_cal_flag[] = 'cancel';
  442. }
  443. foreach ($smd_cal_flag as $item) {
  444. $cflag[] = $cls_pfx.$item;
  445. }
  446. $idx = $smd_date['d'] = (int)strftime('%d', $start);
  447. $smd_date['w'] = strftime(smd_cal_reformat_win('%V', $start), $start);
  448. $smd_date['iy'] = strftime(smd_cal_reformat_win('%G', $start), $start);
  449. $use_posted = in_array('standard', $linkposted);
  450. $op = ($thing) ? parse($thing) : (($form) ? parse_form($form) : (($size=="small") ? smd_cal_minilink($row, $idx, $month, $year, $use_posted) : href($row['Title'], permlinkurl($row), ' title="'.$row['Title'].'"')) );
  451. $events[$idx][] = array('ev' => $op, 'evid' => $row['ID'], 'flag' => $smd_cal_flag, 'classes' => array_merge($cflag, $smd_cal_ucls, $evclasses), 'posted' => $start_date);
  452. $smd_cal_flag = array();
  453. $cflag = array();
  454. $smd_cal_ucls = array();
  455. $use_posted = '';
  456. }
  457. // Generate a skip array for this event
  458. if ($skipfield && $row[$skipfield] != '') {
  459. $ignores = do_list($row[$skipfield]);
  460. foreach ($ignores as $val) {
  461. $igrng = smd_expand_daterange($val, $start, $end);
  462. foreach ($igrng as $theval) {
  463. $ignore[] = date("d-M-Y", $theval); // Force each date to a known format
  464. }
  465. }
  466. }
  467. // Generate an omit array for this event
  468. if ($omitfield && $row[$omitfield] != '') {
  469. $omits = do_list($row[$omitfield]);
  470. foreach ($omits as $val) {
  471. $omrng = smd_expand_daterange($val, $start, $end);
  472. foreach ($omrng as $theval) {
  473. $omit[] = date("d-M-Y", $theval);
  474. }
  475. }
  476. }
  477. if ($debug > 1 && ($ignore || $omit)) {
  478. echo '++ OMITTED DATES ++';
  479. dmp($omit);
  480. echo '++ CANCELLED DATES ++';
  481. dmp($ignore);
  482. }
  483. // Calculate the date offsets and check recurring events that fall within the month of interest
  484. if ($stepfield && $row[$stepfield] != '') {
  485. $freq = do_list($row[$stepfield]);
  486. $stampoff = (int)(3600*$ev_hr) + (int)(60*$ev_mn) + (int)$ev_sc;
  487. foreach ($freq as $interval) {
  488. $max_loop = 99999; // Yuk, but practically limitless
  489. $origerval = $interval;
  490. $interval = str_replace("?month", date('F', mktime(0,0,0,$month,1)), $interval);
  491. $interval = str_replace("?year", $year, $interval);
  492. if (strpos($interval, "last") === 0) {
  493. $interval = date("l, F jS Y", strtotime( $interval, mktime(12, 0, 0, date("n", mktime(0,0,0,$month,1,$year))+1, 1, $year) ));
  494. $max_loop = 1;
  495. } else if (strpos($interval, "first") === 0) {
  496. $interval = date("l, F jS Y", strtotime( $interval, mktime(12, 0, 0, (($month>1) ? $month-1 : 12), date("t", mktime(0,0,0,$month-1,1,(($month==1) ? $year-1: $year))), (($month==1) ? $year-1: $year)) ));
  497. $max_loop = 1;
  498. } else if (strpos($interval, "this") === 0) {
  499. $max_loop = 1;
  500. }
  501. $ts_loop = 0;
  502. $ts_curr = $start;
  503. if (strpos($origerval, "?month") || strpos($origerval, "?year")) {
  504. $max_loop = 1;
  505. }
  506. // $rng = smd_expand_daterange($interval);
  507. //dmp($interval, $rng);
  508. while ($ts_curr < $end && $ts_loop < $max_loop) {
  509. if ($max_loop == 1) {
  510. $ts_curr = strtotime($interval);
  511. $ts_curr = ($ts_curr < $start || $ts_curr > $end) ? $start : $ts_curr;
  512. } else {
  513. $ts_curr = strtotime($interval, $ts_curr);
  514. }
  515. if ($ts_curr === false) {
  516. $ts_loop++;
  517. break;
  518. } else {
  519. if ($debug > 1) {
  520. dmp("INTERVAL: ". date('d-M-Y H:i:s', $ts_curr+$stampoff));
  521. }
  522. if ($ts_curr < $end && $ts_curr >= $ts_first && $ts_curr != $start) {
  523. // A recurring event. Check it isn't a holiday or to be ignored
  524. populateArticleData($row);
  525. $op = '';
  526. $idx = (int)strftime('%d', $ts_curr);
  527. $smd_cal_flag[] = 'recur';
  528. $thisdate = date("d-M-Y", $ts_curr);
  529. $omit_me = in_array($thisdate, $omit);
  530. $show_me = !in_array($thisdate, $ignore);
  531. $hol_hit = in_array($thisdate, $holidays);
  532. $show_hol = ($hol_hit && !in_array('recur',$holidayflags) ) ? false : true;
  533. $use_posted = smd_cal_in_array(array('recur', 'recurfirst'), $linkposted);
  534. if ( $omit_me ) {
  535. $smd_cal_flag[] = 'omit';
  536. }
  537. if ( (!$show_me || !$show_hol) && !$omit_me ) {
  538. $smd_cal_flag[] = 'cancel';
  539. }
  540. foreach ($smd_cal_flag as $item) {
  541. $cflag[] = $cls_pfx.$item;
  542. }
  543. // Create the events that appear in the cell but only if they've not appeared before, or are to be ignored/omitted
  544. if (!$omit_me) {
  545. if (($show_me && $show_hol) || $showskipped) {
  546. $smd_date['d'] = $idx;
  547. $smd_date['w'] = strftime(smd_cal_reformat_win('%V', $ts_curr), $ts_curr);
  548. $smd_date['iy'] = strftime(smd_cal_reformat_win('%G', $ts_curr), $ts_curr);
  549. $op = ($recurform) ? parse_form($recurform) : (($thing) ? parse($thing) : (($size=="small") ? smd_cal_minilink($row, $idx, $month, $year, $use_posted) : href($row['Title'], permlinkurl($row), ' title="'.$row['Title'].'"')) );
  550. }
  551. }
  552. $used = array();
  553. if (isset($events[$idx]) && $events[$idx] != NULL) {
  554. foreach ($events[$idx] as $ev) {
  555. $used[] = $ev['ev'];
  556. }
  557. }
  558. if (isset($events[$idx]) && $events[$idx] == NULL || !in_array($op, $used)) {
  559. $events[$idx][] = array('ev' => $op, 'evid' => $row['ID'], 'flag' => $smd_cal_flag, 'classes' => array_merge($cflag, $smd_cal_ucls, $evclasses), 'posted' => $start_date);
  560. }
  561. $smd_cal_flag = array();
  562. $cflag = array();
  563. $smd_cal_ucls = array();
  564. $use_posted = '';
  565. }
  566. $ts_loop++;
  567. }
  568. }
  569. }
  570. } else if ($showspanned && $multi) {
  571. // Non-recurring events may span more than one date but they must still respect ignored dates and holidays
  572. populateArticleData($row);
  573. $lastday = (int)strftime('%d', $end);
  574. $real_lastday = (int)strftime('%d', $real_end);
  575. while (++$idx <= $lastday) {
  576. $op = '';
  577. $multiflag = (($year==$real_end_year) && ($month==$real_end_month) && ($idx==$real_lastday)) ? 'multilast' : (($idx==1) ? 'multiprev' : 'multi');
  578. $smd_cal_flag[] = $multiflag;
  579. $thistime = mktime(0, 0, 0, $month, $idx, $year);
  580. $thisdate = date("d-M-Y", $thistime);
  581. $omit_me = in_array($thisdate, $omit);
  582. $show_me = !in_array($thisdate, $ignore);
  583. $hol_hit = in_array($thisdate, $holidays);
  584. $show_hol = ($hol_hit && !in_array('multi',$holidayflags) ) ? false : true;
  585. $use_posted = smd_cal_in_array(array('multi', 'multifirst', 'multilast', 'multiprev'), $linkposted);
  586. if ( $omit_me ) {
  587. $smd_cal_flag[] = 'omit';
  588. }
  589. if ( (!$show_me || !$show_hol) && !$omit_me ) {
  590. $smd_cal_flag[] = 'cancel';
  591. }
  592. foreach ($smd_cal_flag as $item) {
  593. $cflag[] = $cls_pfx.$item;
  594. }
  595. // Create the spanned event that appears in the cell
  596. if (!$omit_me) {
  597. if ( ($show_me && $show_hol) || $showskipped) {
  598. $smd_date['d'] = $idx;
  599. $smd_date['w'] = strftime(smd_cal_reformat_win('%V', $thistime), $thistime);
  600. $smd_date['iy'] = strftime(smd_cal_reformat_win('%G', $thistime), $thistime);
  601. $op = ($spanform) ? parse_form($spanform) : (($thing) ? parse($thing) : (($size=="small") ? smd_cal_minilink($row, $idx, $month, $year, $use_posted) : href('&rarr;', permlinkurl($row), ' title="'.$row['Title'].'"')) );
  602. }
  603. }
  604. $events[$idx][] = array('ev' => $op, 'evid' => $row['ID'], 'flag' => $smd_cal_flag, 'classes' => array_merge($cflag, $smd_cal_ucls, $evclasses), 'posted' => $start_date);
  605. $smd_cal_flag = array();
  606. $cflag = array();
  607. $smd_cal_ucls = array();
  608. $use_posted = '';
  609. }
  610. }
  611. // Add any extra dates for this event that are within the current month
  612. if ($extrafield && $row[$extrafield] != '') {
  613. $xtra = do_list($row[$extrafield]);
  614. $ev_hr = date('H', $start);
  615. $ev_mn = date('i', $start);
  616. $ev_sc = date('s', $start);
  617. $stampoff = (int)(3600*$ev_hr) + (int)(60*$ev_mn) + (int)$ev_sc;
  618. foreach ($xtra as $val) {
  619. if (strpos($val, "+") === false) {
  620. $exrng = smd_expand_daterange($val);
  621. $val = date("Y-m-d", $exrng[0]);
  622. $spidth = count($exrng);
  623. $spex = 0;
  624. } else {
  625. $chk = $showspanned && !$recur;
  626. $spidth = $chk ? ceil($diff / (60*60*24)) : 1; // days between dates
  627. $val = rtrim($val, '+');
  628. $spex = $chk ? 1 : 0;
  629. }
  630. for ($jdx = 1; $jdx <= $spidth; $jdx++) {
  631. $tm = safe_strtotime($val . (($jdx==1) ? '' : '+'.($jdx-1).' days'));
  632. if ($diff > 0 && $jdx == 1) {
  633. $expstamp = $tm+$stampoff+$real_diff;
  634. }
  635. $idx = $smd_date['d'] = (int)strftime('%d', $tm);
  636. $dt = date("Y-m-d", $tm);
  637. $lst = ($extrastrict) ? $end : $ts_last;
  638. if ($tm < $lst && $tm >= $ts_first) {
  639. $fakerow = $row;
  640. $fakerow['Posted'] = date("Y-m-d H:i:s", $tm+$stampoff);
  641. $fakerow['uPosted'] = $tm+$stampoff;
  642. if ($diff>0) {
  643. $fakerow['Expires'] = date("Y-m-d H:i:s", $expstamp);
  644. $fakerow['uExpires'] = $expstamp;
  645. }
  646. populateArticleData($fakerow);
  647. $smd_cal_flag[] = 'extra';
  648. $cflag[] = $cls_pfx.'extra';
  649. $omit_me = false;
  650. $show_me = $show_hol = true;
  651. if ($spex) {
  652. $multiflag = ($jdx==1) ? 'multifirst' : (($jdx==$spidth) ? 'multilast' : (($idx==1) ? 'multiprev' : 'multi'));
  653. $thisdate = date("d-M-Y", $tm);
  654. $omit_me = in_array($thisdate, $omit);
  655. $show_me = !in_array($thisdate, $ignore);
  656. $hol_hit = in_array($thisdate, $holidays);
  657. $show_hol = ($hol_hit && !in_array('multi',$holidayflags) ) ? false : true;
  658. $use_posted = in_array('extra', $linkposted);
  659. if ($omit_me) {
  660. $smd_cal_flag[] = 'omit';
  661. }
  662. if ( (!$show_me || !$show_hol) && !$omit_me ) {
  663. $smd_cal_flag[] = 'cancel';
  664. }
  665. $smd_cal_flag[] = $multiflag;
  666. $cflag[] = $cls_pfx.$multiflag;
  667. }
  668. if (!$omit_me) {
  669. if ( ($show_me && $show_hol) || $showskipped) {
  670. $smd_date['w'] = strftime(smd_cal_reformat_win('%V', $tm), $tm);
  671. $smd_date['iy'] = strftime(smd_cal_reformat_win('%G', $tm), $tm);
  672. $op = ($spex && $spanform) ? parse_form($spanform) : (($thing) ? parse($thing) : (($form) ? parse_form($form) : (($size=="small") ? smd_cal_minilink($row, $idx, $month, $year, $use_posted) : href((($spex && $jdx>1) ? '&rarr;' : $row['Title']), permlinkurl($row), ' title="'.$row['Title'].'"')) ));
  673. $events[$idx][] = array('ev' => $op, 'evid' => $row['ID'], 'flag' => $smd_cal_flag, 'classes' => array_merge($cflag, $smd_cal_ucls, $evclasses), 'posted' => $dt);
  674. $smd_cal_flag = array();
  675. $cflag = array();
  676. $smd_cal_ucls = array();
  677. $use_posted = '';
  678. }
  679. }
  680. }
  681. }
  682. }
  683. }
  684. }
  685. article_pop();
  686. if ($debug > 1 && $events) {
  687. echo '++ ALL EVENTS ++';
  688. dmp($events);
  689. }
  690. // Generate the calendar
  691. $calendar = new SMD_Calendar($size, $year, $month, $events, $section, $category, $debug);
  692. $calendar->setWeek($week);
  693. $calendar->setFirstDayOfWeek($firstday);
  694. $calendar->setGMT($gmt);
  695. $calendar->setLang($lang);
  696. $calendar->setClassLevels($clevs);
  697. $calendar->setClassPrefix($cls_pfx);
  698. $calendar->setEventWraptag($eventwraptag);
  699. $calendar->setCellForm($cellform);
  700. $calendar->setHdrForm($headerform);
  701. $calendar->setMYWraptag($mywraptag);
  702. $calendar->setSummary($summary);
  703. $calendar->setCaption($caption);
  704. $calendar->setTableID($id);
  705. $calendar->setTableClass($class);
  706. $calendar->setRowClass($rowclass);
  707. $calendar->setCellClass($cellclass);
  708. $calendar->setEmptyClass($emptyclass);
  709. $calendar->setISOWeekClass($isoweekclass);
  710. $calendar->setNavInfo($navpclass,$navnclass,$navparr,$navnarr,$navid);
  711. $calendar->setNavKeep($maintain);
  712. $calendar->setMYClass($myclass);
  713. $calendar->setNameFormat($dayformat, "d");
  714. $calendar->setNameFormat($monthformat, "m");
  715. $calendar->setRemap($dmap);
  716. $calendar->setShowISOWeek($isoweeks);
  717. $calendar->setEYear($earliest);
  718. $calendar->setLYear($latest);
  719. $calendar->setFilterOpts($fopts);
  720. $calendar->setDelim($event_delim);
  721. $calendar->setHolidays($holidays);
  722. $calendar->setSelectors(do_list($select), $selectbtn);
  723. return $calendar->display($static);
  724. }
  725. class SMD_Calendar extends SMD_Raw_Calendar {
  726. // Override Constructor
  727. // Permits multiple events to show per day
  728. var $section = '';
  729. var $category = '';
  730. var $size = '';
  731. var $debug = 0;
  732. var $events = array();
  733. function SMD_Calendar($size,$year,$month,$events,$section,$category, $debug=0) {
  734. $this->debug = $debug;
  735. $this->section = $section;
  736. $this->category = $category;
  737. $this->events = $events;
  738. $this->size = $size;
  739. $this->smd_Raw_Calendar($year,$month,$debug);
  740. }
  741. // Override dspDayCell to display stuff right
  742. function dspDayCell($theday) {
  743. global $smd_cal_flag, $smd_calinfo, $smd_cal_ucls, $smd_date, $permlink_mode;
  744. $smd_cal_flag = array();
  745. $smd_cal_ucls = array();
  746. $tdclass = array();
  747. $hasarticle = isset($this->events[$theday]);
  748. $now = time() + tz_offset();
  749. $thedate = mktime(0, 0, 0, $this->month, $theday, $this->year);
  750. $hol_hit = in_array(date("d-M-Y", $thedate), $this->holidays);
  751. if ($hasarticle) {
  752. $smd_cal_flag[] = 'event';
  753. }
  754. if ($hol_hit) {
  755. $smd_cal_flag[] = 'hols';
  756. }
  757. $cflag = array();
  758. foreach ($smd_cal_flag as $item) {
  759. $cflag[] = $this->cls_pfx.$item;
  760. }
  761. if ($this->cellclass) {
  762. $tdclass[] = $this->cellclass;
  763. }
  764. $tdclass = array_merge($tdclass, $cflag);
  765. $runningclass = (in_array("cell", $this->cls_lev) || in_array("cellplus", $this->cls_lev)) ? $tdclass : array();
  766. if($this->year == date('Y',$now) and $this->month == date('n',$now) and $theday == date('j',$now) ) {
  767. $smd_cal_flag[] = 'today';
  768. $runningclass[] = $this->cls_pfx.'today';
  769. }
  770. $out = array();
  771. $flags = array();
  772. $evid = array();
  773. $fout = array('standard'=>array(),'recur'=>array(),'recurfirst'=>array(),'multifirst'=>array(),'multi'=>array(),'multiprev'=>array(),'multilast'=>array(),'cancel'=>array(),'extra'=>array());
  774. if (empty($this->cellform) && $this->size == 'large') {
  775. $out[] = hed($theday,4);
  776. }
  777. $evcnt = 0;
  778. if( isset($this->events[$theday]) ) {
  779. $days_events = $this->events[$theday];
  780. foreach($days_events as $ev) {
  781. $evclass = $ev['classes'];
  782. $evid[] = $ev['evid'];
  783. $flags = array_merge($flags, $ev['flag']);
  784. if (in_array("cellplus", $this->cls_lev)) {
  785. $runningclass = array_merge($runningclass, $evclass);
  786. }
  787. $cls = ($evclass && in_array("event", $this->cls_lev)) ? ' class="'.join(' ', $evclass).'"' : '';
  788. $op = ($this->evwraptag) ? tag($ev['ev'], $this->evwraptag, $cls) : $ev['ev'];
  789. foreach ($ev['flag'] as $flev) {
  790. $fout[$flev][] = $op;
  791. }
  792. $out[] = $op;
  793. $evcnt++;
  794. if ($this->size == 'small' && $evcnt == 1) {
  795. break;
  796. }
  797. }
  798. } elseif ($this->size == 'small') {
  799. $out[] = hed($theday,4);
  800. }
  801. // Amalgamate the event-level classes and cell-level classes if required
  802. $runningclass = array_unique($runningclass);
  803. if (in_array("cellplus", $this->cls_lev)) {
  804. $smd_cal_flag = array_merge($smd_cal_flag, $flags);
  805. }
  806. if ($this->cellform) {
  807. $thistime = mktime(0, 0, 0, $this->month, $theday, $this->year);
  808. $smd_calinfo['id'] = $this->tableID;
  809. $smd_date['y'] = $this->year;
  810. $smd_date['m'] = $this->month;
  811. $smd_date['w'] = strftime(smd_cal_reformat_win('%V', $thistime), $thistime);
  812. $smd_date['iy'] = strftime(smd_cal_reformat_win('%G', $thistime), $thistime);
  813. $smd_date['d'] = $theday;
  814. $reps = array(
  815. '{evid}' => join($this->event_delim, $evid),
  816. '{standard}' => join('',$fout['standard']),
  817. '{recur}' => join('',$fout['recur']),
  818. '{recurfirst}' => join('',$fout['recurfirst']),
  819. '{allrecur}' => join('',array_merge($fout['recur'], $fout['recurfirst'])),
  820. '{multifirst}' => join('',$fout['multifirst']),
  821. '{multiprev}' => join('',$fout['multiprev']),
  822. '{multi}' => join('',$fout['multilast']),
  823. '{multilast}' => join('',$fout['multilast']),
  824. '{allmulti}' => join('',array_merge($fout['multifirst'],$fout['multi'],$fout['multiprev'],$fout['multilast'])),
  825. '{cancel}' => join('',$fout['cancel']),
  826. '{extra}' => join('',$fout['extra']),
  827. '{events}' => join('',$out),
  828. '{numevents}' => $evcnt,
  829. '{day}' => $theday,
  830. '{dayzeros}' => str_pad($theday, 2, '0', STR_PAD_LEFT),
  831. '{weekday}' => ((is_array($this->dayNameFmt)) ? $this->dayNames[date('w',$thistime)] : strftime($this->dayNameFmt, $thistime)),
  832. '{weekdayabbr}' => strftime('%a', $thistime),
  833. '{weekdayfull}' => strftime('%A', $thistime),
  834. '{week}' => $smd_date['w'],
  835. '{month}' => $this->month,
  836. '{monthzeros}' => str_pad($this->month, 2, '0', STR_PAD_LEFT),
  837. '{monthname}' => ((is_array($this->mthNameFmt)) ? $this->mthNames[date('n',$thistime)] : strftime($this->mthNameFmt, $thistime)),
  838. '{monthnameabbr}' => strftime('%b', $thistime),
  839. '{monthnamefull}' => strftime('%B', $thistime),
  840. '{year}' => $this->year,
  841. '{shortyear}' => strftime('%y', $thistime),
  842. '{isoyear}' => $smd_date['iy'],
  843. '{shortisoyear}' => strftime(smd_cal_reformat_win('%g', $thistime), $thistime),
  844. );
  845. $cellout = parse(strtr($this->cellform, $reps));
  846. $carray = array_merge($runningclass, $smd_cal_ucls);
  847. $smd_cal_ucls = array();
  848. return doTag($cellout,'td',join(' ',$carray));
  849. } else {
  850. return doTag(join('',$out),'td',join(' ',$runningclass));
  851. }
  852. }
  853. function display($static=false) {
  854. $sum = ($this->tblSummary) ? ' summary="'.$this->tblSummary.'"' : '';
  855. $id = ($this->tableID) ? ' id="'.$this->tableID.'"' : '';
  856. $c[] = ($this->tblCaption) ? '<caption>'.$this->tblCaption.'</caption>' : '';
  857. $c[] = '<thead>';
  858. $c[] = $this->dspHeader($static);
  859. $c[] = $this->dspDayNames();
  860. $c[] = '</thead>';
  861. $c[] = $this->dspDayCells();
  862. return doTag(join('',$c),'table',$this->tableclass,$sum.$id);
  863. }
  864. function dspHeader($static) {
  865. global $pretext, $smd_calinfo, $permlink_mode;
  866. $currmo = $this->month;
  867. $curryr = $this->year;
  868. $navpclass = $this->getNavInfo("pc");
  869. $navnclass = $this->getNavInfo("nc");
  870. $navparrow = $this->getNavInfo("pa");
  871. $navnarrow = $this->getNavInfo("na");
  872. $navid = $this->getNavInfo("id");
  873. $navpclass = ($navpclass) ? ' class="'.$navpclass.'"' : '';
  874. $navnclass = ($navnclass) ? ' class="'.$navnclass.'"' : '';
  875. $fopts = $this->fopts;
  876. $sec = (isset($smd_calinfo['s']) && !empty($smd_calinfo['s'])) ? $smd_calinfo['s'] : '';
  877. foreach ($this->maintain as $col) {
  878. switch ($col) {
  879. case "section":
  880. if ($pretext['s'] && $permlink_mode != 'year_month_day_title') {
  881. $fopts = array('s' => $pretext['s']) + $fopts;
  882. }
  883. break;
  884. case "article":
  885. if ($pretext['id']) {
  886. $fopts = array('id' => $pretext['id']) + $fopts;
  887. }
  888. break;
  889. case "category":
  890. if ($pretext['c']) {
  891. $fopts = array('c' => $pretext['c']) + $fopts;
  892. }
  893. break;
  894. case "author":
  895. if (gps('author')) {
  896. $fopts = array('author' => gps('author')) + $fopts;
  897. }
  898. break;
  899. case "date":
  900. if (gps('date')) {
  901. $fopts = array('date' => gps('date')) + $fopts;
  902. }
  903. break;
  904. case "pg":
  905. if ($pretext['pg']) {
  906. $fopts = array('pg' => $pretext['pg']) + $fopts;
  907. }
  908. break;
  909. case "calid":
  910. if ($this->tableID) {
  911. $fopts = array('calid' => $this->tableID) + $fopts;
  912. }
  913. break;
  914. default:
  915. if (gps($col)) {
  916. $fopts = array($col => gps($col)) + $fopts;
  917. }
  918. break;
  919. }
  920. }
  921. $fopts = array_unique($fopts);
  922. $filters = array();
  923. $filterHid = array();
  924. if (!$static) {
  925. foreach($fopts as $key => $val) {
  926. $filters[] = $key.'='.$val;
  927. $filterHid[] = hInput($key, $val);
  928. }
  929. }
  930. // Week select list
  931. if ($this->useSelector('week') && !$static) {
  932. $currwk = ($this->week) ? $this->week : date('W', safe_strtotime($curryr."-".$currmo."-1 12:00"));
  933. for ( $idx = 1; $idx <= 53; $idx++ ) {
  934. $tagatts = ' value="'.$idx.'"';
  935. if ( $idx == $currwk ) $tagatts .= ' selected="selected"';
  936. $optiontags[] = doTag($this->selpfx['week'].str_pad($idx, 2, '0', STR_PAD_LEFT).$this->selsfx['week'], 'option', '', $tagatts);
  937. }
  938. $selector[] = doTag(join(n, $optiontags), 'select', (($this->mywraptag) ? '' : $this->myclass), ' name="'.$this->remap['w'].'"'.(($this->selbtn) ? '' : ' onchange="this.form.submit()"'), '')
  939. . (($this->useSelector('year')) ? '' : hInput($this->remap['y'], $curryr));
  940. $optiontags = array(); // Blank out
  941. }
  942. // Month select list - note mktime has the day forced to 1. If not you get
  943. // bizarre repeated month names on the 31st of some months :-\
  944. if (!$this->useSelector('week')) {
  945. if ($this->useSelector('month') && !$static) {
  946. for ( $idx = 1; $idx <= 12; $idx++ ) {
  947. $tagatts = ' value="'.$idx.'"';
  948. if ( $idx == $currmo ) $tagatts .= ' selected="selected"';
  949. $optiontags[] = doTag($this->selpfx['month'].((is_array($this->mthNameFmt)) ? $this->mthNames[date('n',mktime(12,0,0,$idx,1))] : safe_strftime($this->mthNameFmt, mktime(12,0,0,$idx,1) )).$this->selsfx['month'], 'option', '', $tagatts);
  950. }
  951. $selector[] = doTag(join(n, $optiontags), 'select', (($this->mywraptag) ? '' : $this->myclass), ' name="'.$this->remap['m'].'"'.(($this->selbtn) ? '' : ' onchange="this.form.submit()"'), '')
  952. . (($this->useSelector('year')) ? '' : hInput($this->remap['y'], $curryr));
  953. $optiontags = array(); // Blank out
  954. } else {
  955. $selector[] = doTag($this->getMonthName(), 'span', (($this->mywraptag) ? '' : $this->myclass));
  956. }
  957. }
  958. // Year select list
  959. $y0 = $this->eyr;
  960. $y1 = $this->lyr;
  961. if ($this->useSelector('year') && ($y0 != $y1) && !$static) {
  962. for ( $idx = $y0; $idx <= $y1; $idx++ ) {
  963. $tagatts = ' value="'.$idx.'"';
  964. if ( $idx == $curryr ) $tagatts .= ' selected="selected"';
  965. $optiontags[] = doTag($this->selpfx['year'].$idx.$this->selsfx['year'], 'option', '', $tagatts);
  966. }
  967. $selector[] = doTag(join(n, $optiontags), 'select', (($this->mywraptag) ? '' : $this->myclass), ' name="'.$this->remap['y'].'"'.(($this->selbtn) ? '' : ' onchange="this.form.submit()"'), '')
  968. . (($this->useSelector('month') || $this->useSelector('week')) ? '' : hInput($this->remap['m'], $currmo));
  969. } else {
  970. $selector[] = doTag($curryr, 'span', (($this->mywraptag) ? '' : $this->myclass));
  971. }
  972. $request = serverSet('REQUEST_URI');
  973. $redirect = serverSet('REDIRECT_URL');
  974. if (!empty($redirect) && ($request != $redirect) && is_callable('_l10n_set_browse_language')) {
  975. // MLP in da house: use the redirect URL instead
  976. $request = $redirect;
  977. }
  978. $urlp = parse_url($request);
  979. $action = $urlp['path'];
  980. if ($permlink_mode == 'messy') {
  981. $out = makeOut('id','s','c','q','pg','p','month');
  982. foreach($out as $key => $val) {
  983. if ($val) {
  984. $filters[] = $key.'='.$val;
  985. $filterHid[] = hInput($key, $val);
  986. }
  987. }
  988. }
  989. $filterHid = array_unique($filterHid);
  990. $filters = array_unique($filters);
  991. $extras = '';
  992. if (!$static && ( $this->useSelector('month') || $this->useSelector('year') )) {
  993. if ($this->selbtn) {
  994. $extras .= doTag('', 'input', 'smd_cal_input', ' type="submit" value="'.$this->selbtn.'"');
  995. }
  996. $extras .= join(n, $filterHid);
  997. }
  998. $selector = '<form action="'.$action.'" method="get"'.(($navid) ? ' id="'.$navid.'"' : '').'>'.doTag(join(sp, $selector).$extras, $this->mywraptag, $this->myclass).'</form>';
  999. $nav_back_link = $this->navigation($curryr, $currmo, '-', $filters, $urlp['path']);
  1000. $nav_fwd_link = $this->navigation($curryr, $currmo, '+', $filters, $urlp['path']);
  1001. $nav_back = (!$static && $nav_back_link) ? '<a href="'.$nav_back_link.'"'.$navpclass.'>'.$navparrow.'</a>' : '&nbsp;';
  1002. $nav_fwd = (!$static && $nav_fwd_link) ? '<a href="'.$nav_fwd_link.'"'.$navnclass.'>'.$navnarrow.'</a>' : '&nbsp;';
  1003. $c[] = doTag($nav_back,'th');
  1004. $c[] = '<th colspan="'.(($this->showISOWeek) ? 6 : 5).'">'.$selector.'</th>';
  1005. $c[] = doTag($nav_fwd,'th');
  1006. return doTag(join('',$c),'tr', 'smd_cal_navrow');
  1007. }
  1008. function navigation($year,$month,$direction,$flt,$url='') {
  1009. global $permlink_mode;
  1010. if($direction == '-') {
  1011. if($month - 1 < 1) {
  1012. $month = 12;
  1013. $year -= 1;
  1014. } else {
  1015. $month -= 1;
  1016. }
  1017. } else {
  1018. if($month + 1 > 12) {
  1019. $month = 1;
  1020. $year += 1;
  1021. } else {
  1022. $month += 1;
  1023. }
  1024. }
  1025. // Abort if we're about to go out of range
  1026. if ($year < $this->eyr || $year > $this->lyr) {
  1027. return '';
  1028. }
  1029. $flt[] = $this->remap['m']."=$month";
  1030. $flt[] = $this->remap['y']."=$year";
  1031. return $url . "?" . join(a, $flt);
  1032. }
  1033. }
  1034. /**
  1035. * Basic Calendar data and display
  1036. * http://www.oscarm.org/static/pg/calendarClass/
  1037. * @author Oscar Merida
  1038. * @created Jan 18 2004
  1039. */
  1040. class SMD_Raw_Calendar {
  1041. var $gmt = 1, $lang, $debug = 0;
  1042. var $year, $eyr, $lyr, $month, $week;
  1043. var $dayNameFmt, $mthNameFmt, $dayNames, $mthNames, $startDay, $endDay, $firstDayOfWeek = 0, $startOffset = 0;
  1044. var $selectors, $selbtn, $selpfx, $selsfx;
  1045. var $showISOWeek, $ISOWeekHead, $ISOWeekCell;
  1046. var $cls_lev, $cls_pfx, $fopts;
  1047. var $evwraptag, $mywraptag;
  1048. var $rowclass, $cellclass, $emptyclass, $isoclass, $myclass, $tableID, $tblSummary, $tblCaption;
  1049. var $navpclass, $navnclass, $navparrow, $navnarrow, $navid;
  1050. var $holidays, $cellform, $hdrform, $maintain, $remap;
  1051. var $event_delim;
  1052. /**
  1053. * Constructor
  1054. *
  1055. * @param integer, year
  1056. * @param integer, month
  1057. * @return object
  1058. * @public
  1059. */
  1060. function SMD_Raw_Calendar ($yr, $mo, $debug=0) {
  1061. $this->setDebug($debug);
  1062. $this->setYear($yr);
  1063. $this->setMonth($mo);
  1064. $this->setClassPrefix('smd_cal_');
  1065. $this->startTime = strtotime( "$yr-$mo-01 00:00" );
  1066. $this->startDay = date( 'D', $this->startTime );
  1067. $this->endDay = date( 't', $this->startTime );
  1068. $this->endTime = strtotime( "$yr-$mo-".$this->endDay." 23:59:59" );
  1069. if ($this->debug) {
  1070. echo "++ THIS MONTH'S RENDERED CALENDAR [ start stamp // end date // start day // end stamp // end date // end day number ] ++";
  1071. dmp($this->startTime, date('Y-m-d H:i:s', $this->startTime), $this->startDay, $this->endTime, date('Y-m-d H:i:s', $this->endTime), $this->endDay);
  1072. }
  1073. $this->setNameFormat('%a', 'd');
  1074. $this->setNameFormat('%B', 'm');
  1075. $this->setFirstDayOfWeek(0);
  1076. $this->setShowISOWeek('');
  1077. $this->setTableID('');
  1078. $this->setTableClass('');
  1079. }
  1080. // === end Calendar ===
  1081. // Getters
  1082. function useSelector($val) { return in_array($val, $this->selectors); }
  1083. function getDayName($day) { return ($this->dayNames[$day%7]); }
  1084. function getMonthName() {
  1085. if (is_array($this->mthNameFmt)) {
  1086. return $this->mthNames[date('n',$this->startTime)];
  1087. } else {
  1088. return strftime($this->mthNameFmt, $this->startTime);
  1089. }
  1090. }
  1091. function getNavInfo($type) {
  1092. $r = '';
  1093. switch ($type) {
  1094. case "id": $r = $this->navid; break;
  1095. case "pc": $r = $this->navpclass; break;
  1096. case "nc": $r = $this->navnclass; break;
  1097. case "pa": $r = $this->navparrow; break;
  1098. case "na": $r = $this->navnarrow; break;
  1099. }
  1100. return $r;
  1101. }
  1102. // Setters
  1103. function setDebug($d){ $this->debug = $d; }
  1104. function setGMT($b){ $this->gmt = $b; }
  1105. function setLang($code){ $this->lang = $code; }
  1106. function setSummary($txt){ $this->tblSummary = $txt; }
  1107. function setCaption($txt){ $this->tblCaption = $txt; }
  1108. function setCellForm($frm){ $this->cellform = $frm; }
  1109. function setHdrForm($frm){ $this->hdrform = $frm; }
  1110. function setTableID($id){ $this->tableID = $id; }
  1111. function setYear($yr){ $this->year = $yr; }
  1112. function setEYear($yr){ $this->eyr = $yr; }
  1113. function setLYear($yr){ $this->lyr = $yr; }
  1114. function setMonth($mth){ $this->month = (int)$mth; }
  1115. function setWeek($wk){
  1116. if ($wk) {
  1117. $wk = str_pad($wk, 2, '0', STR_PAD_LEFT);
  1118. $this->week = $wk;
  1119. $this->month = safe_strftime("%m", strtotime($this->year."W".$wk));
  1120. }
  1121. }
  1122. function setNavKeep($ar){ $this->maintain = $ar; }
  1123. function setShowISOWeek($val) {
  1124. $this->showISOWeek = ($val) ? true : false;
  1125. if ($val) {
  1126. $val = do_list($val);
  1127. $this->ISOWeekHead = $val[0];
  1128. $this->ISOWeekCell = (isset($val[1])) ? $val[1] : '{week}';
  1129. }
  1130. }
  1131. function setRemap($map){ $this->remap = $map; }
  1132. function setClassLevels($cls){ $this->cls_lev = $cls; }
  1133. function setClassPrefix($cls){ $this->cls_pfx = $cls; }
  1134. function setEventWraptag($wrap){ $this->evwraptag = $wrap; }
  1135. function setMYWraptag($wrap){ $this->mywraptag = $wrap; }
  1136. function setTableClass($cls) { $this->tableclass = ($cls) ? $this->cls_pfx.$cls : ''; }
  1137. function setRowClass($cls){ $this->rowclass = ($cls) ? $this->cls_pfx.$cls : ''; }
  1138. function setCellClass($cls){ $this->cellclass = ($cls) ? $this->cls_pfx.$cls : ''; }
  1139. function setEmptyClass($cls){ $this->emptyclass = ($cls) ? $this->cls_pfx.$cls : ''; }
  1140. function setISOWeekClass($cls){ $this->isoclass = ($cls) ? $this->cls_pfx.$cls : ''; }
  1141. function setDelim($dlm){ $this->event_delim = $dlm; }
  1142. function setNavInfo($clsp, $clsn, $arrp, $arrn, $nid){
  1143. $this->navpclass = ($clsp) ? $this->cls_pfx.$clsp : '';
  1144. $this->navnclass = ($clsn) ? $this->cls_pfx.$clsn : '';
  1145. $this->navparrow = ($arrp) ? $arrp : '';
  1146. $this->navnarrow = ($arrn) ? $arrn : '';
  1147. $this->navid = ($nid) ? $this->cls_pfx.$nid : '';
  1148. }
  1149. function setMYClass($cls){ $this->myclass = ($cls) ? $this->cls_pfx.$cls : ''; }
  1150. function setFilterOpts($f) { $this->fopts = $f; }
  1151. function setHolidays($hols) { $this->holidays = $hols; }
  1152. function setSelectors($sel, $btn) {
  1153. foreach ($sel as $idx => $item) {
  1154. $selparts = explode(":", $item);
  1155. $sel[$idx] = $selparts[0];
  1156. $this->selpfx[$selparts[0]] = (isset($selparts[1])) ? $selparts[1] : '';
  1157. $this->selsfx[$selparts[0]] = (isset($selparts[2])) ? $selparts[2] : '';
  1158. }
  1159. $this->selectors = $sel;
  1160. $this->selbtn = $btn;
  1161. }
  1162. function setFirstDayOfWeek($d) {
  1163. $this->firstDayOfWeek = ((int)$d <= 6 and (int)$d >= 0) ? (int)$d : 0;
  1164. $this->startOffset = date('w', $this->startTime) - $this->firstDayOfWeek;
  1165. if ( $this->startOffset < 0 ) {
  1166. $this->startOffset = 7 - abs($this->startOffset);
  1167. }
  1168. }
  1169. /**
  1170. * frm: any valid PHP strftime() string or ABBR/FULL
  1171. * typ: d to set day, m to set month format
  1172. */
  1173. function setNameFormat($frm, $typ="d") {
  1174. switch ($frm) {
  1175. case "full":
  1176. case "FULL":
  1177. $fmt = ($typ == 'd') ? "%A" : "%B";
  1178. break;
  1179. case "abbr":
  1180. case "ABBR":
  1181. $fmt = ($typ == 'd') ? "%a" : "%b";
  1182. break;
  1183. default:
  1184. if (strpos($frm, '%') === 0) {
  1185. $fmt = $frm;
  1186. } else {
  1187. $frm = trim($frm, '{}');
  1188. $frm = do_list($frm);
  1189. $fmt = $frm;
  1190. }
  1191. break;
  1192. }
  1193. if ($typ == "d") {
  1194. $this->dayNameFmt = $fmt;
  1195. $this->dayNames = array();
  1196. // This is done to make sure Sunday is always the first day of our array
  1197. $start = 0;
  1198. $end = $start + 7;
  1199. $sunday = strtotime('1970-Jan-04 12:00:00');
  1200. for($i=$start; $i<$end; $i++) {
  1201. if (is_array($fmt)) {
  1202. $this->dayNames[] = $fmt[$i-$start];
  1203. } else {
  1204. $this->dayNames[] = ucfirst(strftime($fmt, ($sunday + (86400*$i))));
  1205. }
  1206. }
  1207. } else {
  1208. $this->mthNameFmt = $fmt;
  1209. $this->mthNames = array();
  1210. for ($i=0; $i<12; $i++) {
  1211. if (is_array($fmt)) {
  1212. $this->mthNames[$i+1] = $fmt[$i];
  1213. }
  1214. }
  1215. }
  1216. }
  1217. /**
  1218. * Return markup for displaying the calendar.
  1219. * @return
  1220. * @public
  1221. */
  1222. function display ( ) {
  1223. $id = ($this->tableID) ? ' id="'.$this->tableID.'"' : '';
  1224. $c[] = '<table'.$id.'>';
  1225. $c[] = '<thead>' . $this->dspDayNames() . '</thead>';
  1226. $c[] = $this->dspDayCells();
  1227. $c[] = '</table>';
  1228. return join('',$c);
  1229. }
  1230. /

Large files files are truncated, but you can click here to view the full file