// Based on mdp_calendar - thanks Marshall! // TODO: * allow table header to be removed / restyled completely (the month/week dropdown & nav icons) // -- a form (navform?) for the header row with access to all vars such as which month is being displayed? // -- tools to allow the header to be generated from components and laid out in any manner? // * allow URL vars to be passed as POST (to bypass gbp_permlinks) // * add custom rows to the table (header, footer) -- header could be used to replace the current nav/dropdowns // * div-based calendar layout? // TODO: Fix expiry dates on extra+ allspanned dates in smd_article_event (and calendar?). They currently 'creep' a day for every day of a spanned event if( $date = gps('date') ) { $_GET['month'] = $date; } function smd_calendar($atts, $thing='') { global $pretext, $thisarticle, $variable, $prefs, $smd_cal_flag, $smd_date, $smd_calinfo, $smd_cal_ucls; extract(lAtts(array( 'time' => 'any', 'size' => 'large', 'expired' => '', 'category' => '', 'subcats' => '', 'section' => '', 'author' => '', 'realname' => '', 'status' => 'live', 'showall' => '0', 'static' => '', 'form' => '', 'spanform' => 'SMD_SAME', 'recurform' => 'SMD_SAME', 'cellform' => '', 'headerform' => '', 'stepfield' => '', 'skipfield' => '', 'omitfield' => '', 'extrafield' => '', 'extrastrict' => '0', 'datefields' => '', 'showskipped' => '0', 'showspanned' => '1', 'holidays' => '', 'holidayflags' => 'standard', 'classlevels' => 'cell, event', 'linkposted' => 'recur, multi, multiprev, multilast', 'classprefixes' => 'smd_cal_, smd_cal_ev_', 'class' => '', 'rowclass' => '', 'cellclass' => '', 'emptyclass' => 'empty', 'isoweekclass' => 'week', 'navclass' => 'navprev, navnext', 'navarrow' => '<, >', 'navid' => '', 'eventclasses' => 'category', 'eventwraptag' => 'span', 'select' => '', 'selectbtn' => '', 'myclass' => '', 'mywraptag' => '', 'caption' => '', 'summary' => '', 'id' => '', 'week' => '', 'month' => '', 'year' => '', 'remap' => '', 'yearwidth' => '0', 'isoweeks' => '', 'dayformat' => 'ABBR', 'monthformat' => 'FULL', 'firstday' => 0, 'maintain' => 'calid', 'nameval' => '', 'gmt' => 0, 'lang' => '', 'debug' => 0, ), $atts)); $size = (in_array($size, array('small', 'large'))) ? $size : 'large'; $status = ($status) ? $status : 'live'; // in case status is empty $firstday = ($isoweeks == '') ? $firstday : 1; $spanform = ($spanform == 'SMD_SAME') ? $form : $spanform; $recurform = ($recurform == 'SMD_SAME') ? $form : $recurform; $cellform = (empty($cellform)) ? '' : fetch_form($cellform); $headerform = (empty($headerform)) ? '' : fetch_form($headerform); $frontpage = ($section=='' && $pretext['s']=='default') ? true : false; // Set up the class prefixes $clevs = do_list($classlevels); $cls = do_list($classprefixes); $cls_pfx = $evc_pfx = $cls[0]; if (count($cls) > 1){ $evc_pfx = $cls[1]; } // Set up the nav class(es) $maintain = do_list($maintain); $navarrow = do_list($navarrow); $navparr = $navarrow[0]; $navnarr = (count($navarrow) > 1) ? $navarrow[1] : $navarrow[0]; $navclass = do_list($navclass); $navpclass = $navclass[0]; $navnclass = (count($navclass) > 1) ? $navclass[1] : $navclass[0]; // Filters $fopts = array(); $catSQL = $secSQL = $authSQL = $fpSQL = ''; if($category) { $fopts['c'] = $category; // TODO: Can fopts take a list? Should it include subcats? $allcats = do_list($category); $subcats = (empty($subcats)) ? 0 : ((strtolower($subcats)=="all") ? 99999 : intval($subcats)); if ($subcats) { $outcats = array(); foreach ($allcats as $cat) { $cats = getTree(doslash($cat), 'article'); foreach ($cats as $jdx => $val) { if ($cats[$jdx]['level'] <= $subcats) { $outcats[] = $cats[$jdx]['name']; } } } $allcats = $outcats; } $catSQL = doQuote(join("','", doSlash($allcats))); $catSQL = " AND ( Category1 IN (".$catSQL.") OR Category2 IN (".$catSQL.") ) "; } if($section) { $secs = do_list($section); $smd_calinfo['s'] = $secs[0]; $secSQL = doQuote(join("','", doSlash($secs))); $secSQL = " AND Section IN (".$secSQL.") "; } if($realname) { $authors = safe_column('name', 'txp_users', 'RealName IN ('. doQuote(join("','", doArray(do_list($realname), 'urldecode'))) .')' ); $author = join(',', $authors); } if($author) { $fopts['author'] = htmlentities(gps('author')); $authSQL = doQuote(join("','", doSlash(do_list($author)))); $authSQL = " AND AuthorID IN (".$authSQL.") "; } if ($frontpage && !$showall) { $fpSQL = filterFrontPage(); } $smd_calinfo['evid'] = 0; $smd_calinfo['artid'] = $thisarticle['thisid']; $smd_calinfo['artitle'] = $thisarticle['url_title']; $nameval = do_list($nameval); foreach ($nameval as $nv) { $nv = explode("=", $nv); if ($nv[0]) { $fopts[$nv[0]] = ((isset($nv[1])) ? $nv[1] : ''); } } $status = do_list($status); $stati = array(); foreach ($status as $stat) { if (empty($stat)) { continue; } else if (is_numeric($stat)) { $stati[] = $stat; } else { $stati[] = getStatusNum($stat); } } $stati = " Status IN (".join(',', $stati).")"; $expired = ($expired) ? $expired : $prefs['publish_expired_articles']; $expired = (($expired) ? '' : ' AND (now() <= Expires OR Expires = '.NULLDATETIME.')'); $eventclasses = do_list($eventclasses); $holidayflags = do_list($holidayflags); $linkposted = do_list($linkposted); $datefields = do_list($datefields); // Work out the first and last posts to determine the year range - probably a better way of doing this than 3 queries $filt = $stati . (($category) ? $catSQL : '') . (($section) ? $secSQL : '') . (($author) ? $authSQL : '') . $fpSQL; $earliest = safe_field('unix_timestamp(Posted) AS uPosted', 'textpattern', $filt .' ORDER BY Posted ASC LIMIT 0, 1', $debug); $lp = safe_field('unix_timestamp(Posted) AS uPosted', 'textpattern', $filt .' ORDER BY Posted DESC LIMIT 0, 1', $debug); $lm = safe_field('unix_timestamp(LastMod) AS uLastMod', 'textpattern', $filt .' ORDER BY LastMod DESC LIMIT 0, 1', $debug); $latest = ($time=="past") ? time() : (($lp > $lm) ? $lp : $lm); $yearwidth = do_list($yearwidth); $yearwidth[0] = (empty($yearwidth[0])) ? 0 : $yearwidth[0]; if (count($yearwidth) == 1) { $yearwidth[1] = $yearwidth[0]; } $usenow = array(false,false); foreach ($yearwidth as $yridx => $yritem) { if (strpos($yritem,"c") !== false) { $yearwidth[$yridx] = intval($yritem); $usenow[$yridx] = true; } } // Remap w/m/y to other vars if required $remap = do_list($remap); $dmap = array("y" => "y", "m" => "m", "w" => "w"); foreach ($remap as $dpair) { $dpair = do_list($dpair, ':'); $dmap[$dpair[0]] = (isset($dpair[1])) ? $dpair[1] : $dpair[0]; } $earliest = date("Y", strtotime("-".$yearwidth[0]." year", ( (empty($earliest) || $usenow[0]==true) ? time() : $earliest) ) ); $latest = date("Y", strtotime("+".$yearwidth[1]." year", ( (empty($latest) || $usenow[1]==true) ? time() : $latest) ) ); // Check the URL for current date and calendar target info $in_calid = gps('calid'); $in_year = (gps($dmap["y"]) and is_numeric(gps($dmap["y"]))) ? (int)gps($dmap["y"]) : ''; $in_month = (gps($dmap["m"]) and is_numeric(gps($dmap["m"]))) ? (int)gps($dmap["m"]) : ''; $in_week = (gps($dmap["w"]) and is_numeric(gps($dmap["w"]))) ? (int)gps($dmap["w"]) : ''; if($static) { // if we're static w/o any supplied vars, use the current date if(!$year) { $year = safe_strftime('%Y'); } if(!$month) { $month = safe_strftime('%m'); } } else { // otherwise use current date only if there's nothing else if( $id == $in_calid ) { // use incoming $year = ($in_year) ? $in_year : (($year) ? $year : safe_strftime('%Y')); $month = ($in_month) ? $in_month : (($month) ? $month : safe_strftime('%m')); // If week is used, adjust month so it encompasses the given week $week = $in_week; if ($week) { $month = safe_strftime("%m", strtotime($year."W".str_pad($week, 2, '0', STR_PAD_LEFT))); // Get the month from the week } } else { // use current if(!$year) { $year = safe_strftime('%Y'); } if(!$month) { $month = safe_strftime('%m'); } if($week) { $month = safe_strftime("%m", strtotime($year."W".str_pad($week, 2, '0', STR_PAD_LEFT))); } } } $smd_calinfo['id'] = ($in_calid) ? $in_calid : $id; $smd_date['y'] = $year; $smd_date['m'] = $month; // $week/day/isoyear are set per event later $ts_first = mktime(0, 0, 0, $month, 1, $year); $ts_last = mktime(23, 59, 59, $month, date('t',$ts_first), $year); $ts_lastoff = $ts_last - tz_offset($ts_last); if ($debug) { echo "++ THIS MONTH'S CALENDAR [ start stamp // end date // end stamp // end date // tz offset (end) ] ++"; 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); } $extrasql = $catSQL . $secSQL . $authSQL . $fpSQL; switch($time) { case "any" : break; case "future" : $extrasql .= " AND Posted > now()"; break; default : $extrasql .= " AND Posted < now()"; break; // The past } // Holidays are global 'exclusions', either defined directly or in a txp:variable $holidays = do_list($holidays); $txphols = do_list($holidays[0], ":"); if ($txphols[0] == "txpvar") { $holidays = do_list($variable[$txphols[1]]); } // Force each holiday to a known format. Holidays without years use current year foreach ($holidays as $key => $val) { if (empty($val)) continue; $numparts = preg_match('/^([\d\w]+).?([\d\w]+).?([\d\w]+)?$/', $val, $parts); if ($numparts) { if (count($parts) == 3) { $parts[3] = $year; } $val = str_pad($parts[1], 2, '0', STR_PAD_LEFT).'-'.str_pad($parts[2], 2, '0', STR_PAD_LEFT).'-'.$parts[3]; } $holidays[$key] = date("d-M-Y", safe_strtotime($val)); } if ($debug > 0 && !empty($holidays) && $holidays[0] != '') { echo "++ HOLIDAYS ++ "; dmp($holidays); } // Get all matching articles in (and before) this month $events = array(); $uposted_field = (empty($datefields[0])) ? 'uPosted' : "UNIX_TIMESTAMP($datefields[0])"; $sql2 = $stati . " HAVING $uposted_field <= ".$ts_lastoff. $expired . $extrasql ." ORDER BY Posted ASC"; $grabCols = '*, unix_timestamp(Posted) as uPosted, unix_timestamp(LastMod) as uLastMod, unix_timestamp(Expires) as uExpires'; $evlist = safe_rows($grabCols, 'textpattern', $sql2, $debug); article_push(); // If any events recur and fall within the current month, add those as well // If any dates are to be excluded, the entry is skipped UNLESS showskipped indicates otherwise foreach ($evlist as $row) { $idx = 0; // In case the 1st day of the month is a continuation of an event from the end of the previous month $start = (!empty($datefields[0]) && !empty($row[$datefields[0]]) && ($stdt = strtotime($row[$datefields[0]])) !== false) ? $stdt : $row['uPosted'] + tz_offset($row['uPosted']); $start_date = date("Y-m-d", $start); // For recurring/spanned events on a minical, this is the event the cell links to $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'])); // If end < start the user-specified dates cannot be trusted if ($real_end != 0 && $real_end <= $start) { $start = $row['uPosted'] + tz_offset($row['uPosted']); $real_end = $row['uExpires'] + tz_offset($row['uExpires']); trigger_error('Expiry cannot be before start date in "'.$row['Title'].'": ignored', E_USER_WARNING); } $end = ($real_end != 0 && $real_end < $ts_last) ? $real_end : $ts_last; $real_diff = ($real_end==0) ? 0 : $real_end - $start; $fake_diff = strtotime(date("Y-M-d", $real_end) . " 23:59:59"); $diff = ($real_end==0) ? 0 : $fake_diff - $start; $smd_cal_flag = $smd_cal_ucls = array(); $ev_month = date('m', $start); $ev_year = date('Y', $start); $ev_hr = date('H', $start); $ev_mn = date('i', $start); $ev_sc = date('s', $start); if ($debug > 1) { echo '++ EVENT START // END // (if non-zero) REAL END ++'; 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) )); dmp($row['Title']); if ($debug > 2) { dmp($row); } } $multi = (($end > $start) && ($real_end > $start) && ($real_end > $ts_first) && (date("d-m-Y", $real_end) != date("d-m-Y", $start))) ? true : false; $recur = (empty($row[$stepfield])) ? false : true; $hol_hit = in_array(date("d-M-Y", $start), $holidays); $evclasses = array(); foreach ($eventclasses as $evcls) { switch ($evcls) { case "": break; case "gcat": if (isset($pretext['c']) && !empty($pretext['c'])) { $evclasses[] = $evc_pfx.$pretext['c']; } break; case "category": if (isset($row['Category1']) && !empty($row['Category1'])) { $evclasses[] = $evc_pfx.$row['Category1']; } if (isset($row['Category2']) && !empty($row['Category2'])) { $evclasses[] = $evc_pfx.$row['Category2']; } break; case "section": if (isset($pretext['s']) && !empty($pretext['s'])) { $evclasses[] = $evc_pfx.$pretext['s']; } break; case "author": if (isset($pretext['author']) && !empty($pretext['author'])) { $evclasses[] = $evc_pfx.$pretext['author']; } break; default: if (isset($row[$evcls]) && !empty($row[$evcls])) { $evclasses[] = $evc_pfx.$row[$evcls]; } break; } } $evclasses = ($evclasses) ? ' '. join(' ', $evclasses) : ''; $ignore = $omit = $cflag = array(); if ($debug > 1 && $evclasses) { echo '++ EVENT CLASSES ++'; dmp($evclasses); } // Events that start or are added this month if (($start < $end) && ($start > $ts_first)) { populateArticleData($row); $smd_calinfo['evid'] = $row['ID']; // a standard event or start of a multi if ($showspanned && $multi && !$recur) { $smd_cal_flag[] = 'multifirst'; } if ($recur) { $smd_cal_flag[] = 'recurfirst'; } if (!$smd_cal_flag) { $smd_cal_flag[] = 'standard'; } 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) ) ) { $smd_cal_flag[] = 'cancel'; } foreach ($smd_cal_flag as $item) { $cflag[] = $cls_pfx.$item; } $idx = $smd_date['d'] = (int)strftime('%d', $start); $smd_date['w'] = strftime(smd_cal_reformat_win('%V', $start), $start); $smd_date['iy'] = strftime(smd_cal_reformat_win('%G', $start), $start); $use_posted = in_array('standard', $linkposted); $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'].'"')) ); $events[$idx][] = array('ev' => $op, 'flag' => $smd_cal_flag, 'classes' => (($cflag) ? join(' ',array_merge($cflag, $smd_cal_ucls)) : '').$evclasses, 'posted' => $start_date); $smd_cal_flag = $cflag = $smd_cal_ucls = array(); $use_posted = ''; } // Generate a skip array for this event if ($skipfield && $row[$skipfield] != '') { $ignores = do_list($row[$skipfield]); foreach ($ignores as $val) { $igrng = smd_expand_daterange($val, $start, $end); foreach ($igrng as $theval) { $ignore[] = date("d-M-Y", $theval); // Force each date to a known format } } } // Generate an omit array for this event if ($omitfield && $row[$omitfield] != '') { $omits = do_list($row[$omitfield]); foreach ($omits as $val) { $omrng = smd_expand_daterange($val, $start, $end); foreach ($omrng as $theval) { $omit[] = date("d-M-Y", $theval); } } } if ($debug > 1 && ($ignore || $omit)) { echo '++ OMITTED DATES ++'; dmp($omit); echo '++ CANCELLED DATES ++'; dmp($ignore); } // Calculate the date offsets and check recurring events that fall within the month of interest if ($stepfield && $row[$stepfield] != '') { $freq = do_list($row[$stepfield]); $stampoff = (int)(3600*$ev_hr) + (int)(60*$ev_mn) + (int)$ev_sc; foreach ($freq as $interval) { $max_loop = 99999; // Yuk, but practically limitless $origerval = $interval; $interval = str_replace("?month", date('F', mktime(0,0,0,$month,1)), $interval); $interval = str_replace("?year", $year, $interval); if (strpos($interval, "last") === 0) { $interval = date("l, F jS Y", strtotime( $interval, mktime(12, 0, 0, date("n", mktime(0,0,0,$month,1,$year))+1, 1, $year) )); $max_loop = 1; } else if (strpos($interval, "first") === 0) { $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)) )); $max_loop = 1; } else if (strpos($interval, "this") === 0) { $max_loop = 1; } $ts_loop = 0; $ts_curr = $start; if (strpos($origerval, "?month") || strpos($origerval, "?year")) { $max_loop = 1; } while ($ts_curr < $end && $ts_loop < $max_loop) { if ($max_loop == 1) { $ts_curr = strtotime($interval); $ts_curr = ($ts_curr < $start || $ts_curr > $end) ? $start : $ts_curr; } else { $ts_curr = strtotime($interval, $ts_curr); } if ($ts_curr === false) { $ts_loop++; break; } else { if ($debug > 1) { dmp("INTERVAL: ". date('d-M-Y H:i:s', $ts_curr+$stampoff)); } if ($ts_curr < $end && $ts_curr >= $ts_first && $ts_curr != $start) { // A recurring event. Check it isn't a holiday or to be ignored populateArticleData($row); $op = ''; $idx = (int)strftime('%d', $ts_curr); $smd_cal_flag[] = 'recur'; $thisdate = date("d-M-Y", $ts_curr); $omit_me = in_array($thisdate, $omit); $show_me = !in_array($thisdate, $ignore); $hol_hit = in_array($thisdate, $holidays); $show_hol = ($hol_hit && !in_array('recur',$holidayflags) ) ? false : true; $use_posted = smd_cal_in_array(array('recur', 'recurfirst'), $linkposted); if ( $omit_me ) { $smd_cal_flag[] = 'omit'; } if ( (!$show_me || !$show_hol) && !$omit_me ) { $smd_cal_flag[] = 'cancel'; } foreach ($smd_cal_flag as $item) { $cflag[] = $cls_pfx.$item; } // Create the events that appear in the cell but only if they've not appeared before, or are to be ignored/omitted if (!$omit_me) { if (($show_me && $show_hol) || $showskipped) { $smd_date['d'] = $idx; $smd_date['w'] = strftime(smd_cal_reformat_win('%V', $ts_curr), $ts_curr); $smd_date['iy'] = strftime(smd_cal_reformat_win('%G', $ts_curr), $ts_curr); $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'].'"')) ); } } $used = array(); if (isset($events[$idx]) && $events[$idx] != NULL) { foreach ($events[$idx] as $ev) { $used[] = $ev['ev']; } } if (isset($events[$idx]) && $events[$idx] == NULL || !in_array($op, $used)) { $events[$idx][] = array('ev' => $op, 'flag' => $smd_cal_flag, 'classes' => (($cflag) ? join(' ',array_merge($cflag, $smd_cal_ucls)) : '').$evclasses, 'posted' => $start_date); } $smd_cal_flag = $cflag = $smd_cal_ucls = array(); $use_posted = ''; } $ts_loop++; } } } } else if ($showspanned && $multi) { // Non-recurring events may span more than one date but they must still respect ignored dates and holidays populateArticleData($row); $lastday = (int)strftime('%d', $end); $real_lastday = (int)strftime('%d', $real_end); while (++$idx <= $lastday) { $op = ''; $multiflag = ($idx==$real_lastday) ? 'multilast' : (($idx==1) ? 'multiprev' : 'multi'); $smd_cal_flag[] = $multiflag; $thistime = mktime(0, 0, 0, $month, $idx, $year); $thisdate = date("d-M-Y", $thistime); $omit_me = in_array($thisdate, $omit); $show_me = !in_array($thisdate, $ignore); $hol_hit = in_array($thisdate, $holidays); $show_hol = ($hol_hit && !in_array('multi',$holidayflags) ) ? false : true; $use_posted = smd_cal_in_array(array('multi', 'multifirst', 'multilast', 'multiprev'), $linkposted); if ( $omit_me ) { $smd_cal_flag[] = 'omit'; } if ( (!$show_me || !$show_hol) && !$omit_me ) { $smd_cal_flag[] = 'cancel'; } foreach ($smd_cal_flag as $item) { $cflag[] = $cls_pfx.$item; } // Create the spanned event that appears in the cell if (!$omit_me) { if ( ($show_me && $show_hol) || $showskipped) { $smd_date['d'] = $idx; $smd_date['w'] = strftime(smd_cal_reformat_win('%V', $thistime), $thistime); $smd_date['iy'] = strftime(smd_cal_reformat_win('%G', $thistime), $thistime); $op = ($spanform) ? parse_form($spanform) : (($thing) ? parse($thing) : (($size=="small") ? smd_cal_minilink($row, $idx, $month, $year, $use_posted) : href('→', permlinkurl($row), ' title="'.$row['Title'].'"')) ); } } $events[$idx][] = array('ev' => $op, 'flag' => $smd_cal_flag, 'classes' => (($cflag) ? join(' ',array_merge($cflag, $smd_cal_ucls)) : '').$evclasses, 'posted' => $start_date); $smd_cal_flag = $cflag = $smd_cal_ucls = array(); $use_posted = ''; } } // Add any extra dates for this event that are within the current month if ($extrafield && $row[$extrafield] != '') { $xtra = do_list($row[$extrafield]); $ev_hr = date('H', $start); $ev_mn = date('i', $start); $ev_sc = date('s', $start); $stampoff = (int)(3600*$ev_hr) + (int)(60*$ev_mn) + (int)$ev_sc; foreach ($xtra as $val) { if (strpos($val, "+") === false) { $exrng = smd_expand_daterange($val); $val = date("Y-m-d", $exrng[0]); $spidth = count($exrng); $spex = 0; } else { $chk = $showspanned && !$recur; $spidth = $chk ? ceil($diff / (60*60*24)) : 1; // days between dates $val = rtrim($val, '+'); $spex = $chk ? 1 : 0; } for ($jdx = 1; $jdx <= $spidth; $jdx++) { $tm = safe_strtotime($val . (($jdx==1) ? '' : '+'.($jdx-1).' days')); if ($diff > 0 && $jdx == 1) { $expstamp = $tm+$stampoff+$real_diff; } $idx = $smd_date['d'] = (int)strftime('%d', $tm); $dt = date("Y-m-d", $tm); $lst = ($extrastrict) ? $end : $ts_last; if ($tm < $lst && $tm >= $ts_first) { $fakerow = $row; $fakerow['Posted'] = date("Y-m-d H:i:s", $tm+$stampoff); $fakerow['uPosted'] = $tm+$stampoff; if ($diff>0) { $fakerow['Expires'] = date("Y-m-d H:i:s", $expstamp); $fakerow['uExpires'] = $expstamp; } populateArticleData($fakerow); $smd_cal_flag[] = 'extra'; $cflag[] = $cls_pfx.'extra'; $omit_me = false; $show_me = $show_hol = true; if ($spex) { $multiflag = ($jdx==1) ? 'multifirst' : (($jdx==$spidth) ? 'multilast' : (($idx==1) ? 'multiprev' : 'multi')); $thisdate = date("d-M-Y", $tm); $omit_me = in_array($thisdate, $omit); $show_me = !in_array($thisdate, $ignore); $hol_hit = in_array($thisdate, $holidays); $show_hol = ($hol_hit && !in_array('multi',$holidayflags) ) ? false : true; $use_posted = in_array('extra', $linkposted); if ($omit_me) { $smd_cal_flag[] = 'omit'; } if ( (!$show_me || !$show_hol) && !$omit_me ) { $smd_cal_flag[] = 'cancel'; } $smd_cal_flag[] = $multiflag; $cflag[] = $cls_pfx.$multiflag; } if (!$omit_me) { if ( ($show_me && $show_hol) || $showskipped) { $smd_date['w'] = strftime(smd_cal_reformat_win('%V', $tm), $tm); $smd_date['iy'] = strftime(smd_cal_reformat_win('%G', $tm), $tm); $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) ? '→' : $row['Title']), permlinkurl($row), ' title="'.$row['Title'].'"')) )); $events[$idx][] = array('ev' => $op, 'flag' => $smd_cal_flag, 'classes' => (($cflag) ? join(' ',array_merge($cflag, $smd_cal_ucls)) : '').$evclasses, 'posted' => $dt); $smd_cal_flag = $cflag = $smd_cal_ucls = array(); $use_posted = ''; } } } } } } } article_pop(); if ($debug > 1 && $events) { echo '++ ALL EVENTS ++'; dmp($events); } // Generate the calendar $calendar = new SMD_Calendar($size, $year, $month, $events, $section, $category, $debug); $calendar->setWeek($week); $calendar->setGMT($gmt); $calendar->setLang($lang); $calendar->setClassLevels($clevs); $calendar->setClassPrefix($cls_pfx); $calendar->setEventWraptag($eventwraptag); $calendar->setCellForm($cellform); $calendar->setHdrForm($headerform); $calendar->setMYWraptag($mywraptag); $calendar->setSummary($summary); $calendar->setCaption($caption); $calendar->setTableID($id); $calendar->setTableClass($class); $calendar->setRowClass($rowclass); $calendar->setCellClass($cellclass); $calendar->setEmptyClass($emptyclass); $calendar->setISOWeekClass($isoweekclass); $calendar->setNavInfo($navpclass,$navnclass,$navparr,$navnarr,$navid); $calendar->setNavKeep($maintain); $calendar->setMYClass($myclass); $calendar->setNameFormat($dayformat, "d"); $calendar->setNameFormat($monthformat, "m"); $calendar->setRemap($dmap); $calendar->setShowISOWeek($isoweeks); $calendar->setEYear($earliest); $calendar->setLYear($latest); $calendar->setFilterOpts($fopts); $calendar->setHolidays($holidays); $calendar->setSelectors(do_list($select), $selectbtn); $calendar->setFirstDayOfWeek($firstday); return $calendar->display($static); } class SMD_Calendar extends SMD_Raw_Calendar { // Override Constructor // Permits multiple events to show per day var $section = ''; var $category = ''; var $size = ''; var $debug = 0; var $events = array(); function SMD_Calendar($size,$year,$month,$events,$section,$category, $debug=0) { $this->debug = $debug; $this->section = $section; $this->category = $category; $this->events = $events; $this->size = $size; $this->smd_Raw_Calendar($year,$month,$debug); } // Override dspDayCell to display stuff right function dspDayCell($theday) { global $smd_cal_flag, $smd_calinfo, $smd_cal_ucls, $smd_date, $permlink_mode; $smd_cal_flag = $smd_cal_ucls = array(); $hasarticle = isset($this->events[$theday]); $now = time() + tz_offset(); $thedate = mktime(0, 0, 0, $this->month, $theday, $this->year); $hol_hit = in_array(date("d-M-Y", $thedate), $this->holidays); if ($hasarticle) { $smd_cal_flag[] = 'event'; } if ($hol_hit) { $smd_cal_flag[] = 'hols'; } $cflag = array(); foreach ($smd_cal_flag as $item) { $cflag[] = $this->cls_pfx.$item; } $tdclass = trim($this->cellclass . (($cflag) ? ' '.join(' ', $cflag) : '')); $runningclass = (in_array("cell", $this->cls_lev) || in_array("cellplus", $this->cls_lev)) ? explode(' ', $tdclass) : array(); if($this->year == date('Y',$now) and $this->month == date('n',$now) and $theday == date('j',$now) ) { $smd_cal_flag[] = 'today'; $runningclass[] = $this->cls_pfx.'today'; } $out = $flags = array(); $fout = array('standard'=>array(),'recur'=>array(),'recurfirst'=>array(),'multifirst'=>array(),'multi'=>array(),'multiprev'=>array(),'multilast'=>array(),'cancel'=>array(),'extra'=>array()); if (empty($this->cellform) && $this->size == 'large') { $out[] = hed($theday,4); } if( isset($this->events[$theday]) ) { $days_events = $this->events[$theday]; $evcnt = 0; foreach($days_events as $ev) { $evclass = trim($ev['classes']); $flags = array_merge($flags, $ev['flag']); if (in_array("cellplus", $this->cls_lev)) { foreach (explode(' ', $evclass) as $evc) { $runningclass[]= $evc; } } $cls = ($evclass && in_array("event", $this->cls_lev)) ? ' class="'.trim($evclass).'"' : ''; $op = ($this->evwraptag) ? tag($ev['ev'], $this->evwraptag, $cls) : $ev['ev']; foreach ($ev['flag'] as $flev) { $fout[$flev][] = $op; } $out[] = $op; $evcnt++; if ($this->size == 'small' && $evcnt == 1) { break; } } } elseif ($this->size == 'small') { $out[] = hed($theday,4); } // Amalgamate the event-level classes and cell-level classes if required $runningclass = array_unique($runningclass); if (in_array("cellplus", $this->cls_lev)) { $smd_cal_flag = array_merge($smd_cal_flag, $flags); } if ($this->cellform) { $thistime = mktime(0, 0, 0, $this->month, $theday, $this->year); $smd_calinfo['id'] = $this->tableID; $smd_date['y'] = $this->year; $smd_date['m'] = $this->month; $smd_date['w'] = strftime(smd_cal_reformat_win('%V', $thistime), $thistime); $smd_date['iy'] = strftime(smd_cal_reformat_win('%G', $thistime), $thistime); $smd_date['d'] = $theday; $reps = array( '{evid}' => $smd_calinfo['evid'], '{standard}' => join('',$fout['standard']), '{recur}' => join('',$fout['recur']), '{recurfirst}' => join('',$fout['recurfirst']), '{allrecur}' => join('',array_merge($fout['recur'], $fout['recurfirst'])), '{multifirst}' => join('',$fout['multifirst']), '{multiprev}' => join('',$fout['multiprev']), '{multi}' => join('',$fout['multilast']), '{multilast}' => join('',$fout['multilast']), '{allmulti}' => join('',array_merge($fout['multifirst'],$fout['multi'],$fout['multiprev'],$fout['multilast'])), '{cancel}' => join('',$fout['cancel']), '{extra}' => join('',$fout['extra']), '{events}' => join('',$out), '{day}' => $theday, '{dayzeros}' => str_pad($theday, 2, '0', STR_PAD_LEFT), '{weekday}' => ((is_array($this->dayNameFmt)) ? $this->dayNames[date('w',$thistime)] : strftime($this->dayNameFmt, $thistime)), '{weekdayabbr}' => strftime('%a', $thistime), '{weekdayfull}' => strftime('%A', $thistime), '{week}' => $smd_date['w'], '{month}' => $this->month, '{monthzeros}' => str_pad($this->month, 2, '0', STR_PAD_LEFT), '{monthname}' => ((is_array($this->mthNameFmt)) ? $this->mthNames[date('n',$thistime)] : strftime($this->mthNameFmt, $thistime)), '{monthnameabbr}' => strftime('%b', $thistime), '{monthnamefull}' => strftime('%B', $thistime), '{year}' => $this->year, '{shortyear}' => strftime('%y', $thistime), '{isoyear}' => $smd_date['iy'], '{shortisoyear}' => strftime(smd_cal_reformat_win('%g', $thistime), $thistime), ); $cellout = parse(strtr($this->cellform, $reps)); $carray = array_merge($runningclass, $smd_cal_ucls); $smd_cal_ucls = array(); return doTag($cellout,'td',join(' ',$carray)); } else { return doTag(join('',$out),'td',join(' ',$runningclass)); } } function display($static=false) { $sum = ($this->tblSummary) ? ' summary="'.$this->tblSummary.'"' : ''; $id = ($this->tableID) ? ' id="'.$this->tableID.'"' : ''; $c[] = ($this->tblCaption) ? ''.$this->tblCaption.'' : ''; $c[] = ''; $c[] = $this->dspHeader($static); $c[] = $this->dspDayNames(); $c[] = ''; $c[] = $this->dspDayCells(); return doTag(join('',$c),'table',$this->tableclass,$sum.$id); } function dspHeader($static) { global $pretext, $smd_calinfo, $permlink_mode; $currmo = $this->month; $curryr = $this->year; $navpclass = $this->getNavInfo("pc"); $navnclass = $this->getNavInfo("nc"); $navparrow = $this->getNavInfo("pa"); $navnarrow = $this->getNavInfo("na"); $navid = $this->getNavInfo("id"); $navpclass = ($navpclass) ? ' class="'.$navpclass.'"' : ''; $navnclass = ($navnclass) ? ' class="'.$navnclass.'"' : ''; $fopts = $this->fopts; $sec = (isset($smd_calinfo['s']) && !empty($smd_calinfo['s'])) ? $smd_calinfo['s'] : ''; foreach ($this->maintain as $col) { switch ($col) { case "section": if ($pretext['s'] && $permlink_mode != 'year_month_day_title') { $fopts = array('s' => $pretext['s']) + $fopts; } break; case "article": if ($pretext['id']) { $fopts = array('id' => $pretext['id']) + $fopts; } break; case "category": if ($pretext['c']) { $fopts = array('c' => $pretext['c']) + $fopts; } break; case "author": if (gps('author')) { $fopts = array('author' => gps('author')) + $fopts; } break; case "date": if (gps('date')) { $fopts = array('date' => gps('date')) + $fopts; } break; case "pg": if ($pretext['pg']) { $fopts = array('pg' => $pretext['pg']) + $fopts; } break; case "calid": if ($this->tableID) { $fopts = array('calid' => $this->tableID) + $fopts; } break; default: if (gps($col)) { $fopts = array($col => gps($col)) + $fopts; } break; } } $fopts = array_unique($fopts); $filters = array(); $filterHid = array(); if (!$static) { foreach($fopts as $key => $val) { $filters[] = $key.'='.$val; $filterHid[] = hInput($key, $val); } } // Week select list if ($this->useSelector('week') && !$static) { $currwk = ($this->week) ? $this->week : date('W', safe_strtotime($curryr."-".$currmo."-1 12:00")); for ( $idx = 1; $idx <= 53; $idx++ ) { $tagatts = ' value="'.$idx.'"'; if ( $idx == $currwk ) $tagatts .= ' selected="selected"'; $optiontags[] = doTag($this->selpfx['week'].str_pad($idx, 2, '0', STR_PAD_LEFT).$this->selsfx['week'], 'option', '', $tagatts); } $selector[] = doTag(join(n, $optiontags), 'select', (($this->mywraptag) ? '' : $this->myclass), ' name="'.$this->remap['w'].'"'.(($this->selbtn) ? '' : ' onchange="submit()"'), '') . (($this->useSelector('year')) ? '' : hInput($this->remap['y'], $curryr)); $optiontags = array(); // Blank out } // Month select list - note mktime has the day forced to 1. If not you get // bizarre repeated month names on the 31st of some months :-\ if (!$this->useSelector('week')) { if ($this->useSelector('month') && !$static) { for ( $idx = 1; $idx <= 12; $idx++ ) { $tagatts = ' value="'.$idx.'"'; if ( $idx == $currmo ) $tagatts .= ' selected="selected"'; $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); } $selector[] = doTag(join(n, $optiontags), 'select', (($this->mywraptag) ? '' : $this->myclass), ' name="'.$this->remap['m'].'"'.(($this->selbtn) ? '' : ' onchange="submit()"'), '') . (($this->useSelector('year')) ? '' : hInput($this->remap['y'], $curryr)); $optiontags = array(); // Blank out } else { $selector[] = doTag($this->getMonthName(), 'span', (($this->mywraptag) ? '' : $this->myclass)); } } // Year select list $y0 = $this->eyr; $y1 = $this->lyr; if ($this->useSelector('year') && ($y0 != $y1) && !$static) { for ( $idx = $y0; $idx <= $y1; $idx++ ) { $tagatts = ' value="'.$idx.'"'; if ( $idx == $curryr ) $tagatts .= ' selected="selected"'; $optiontags[] = doTag($this->selpfx['year'].$idx.$this->selsfx['year'], 'option', '', $tagatts); } $selector[] = doTag(join(n, $optiontags), 'select', (($this->mywraptag) ? '' : $this->myclass), ' name="'.$this->remap['y'].'"'.(($this->selbtn) ? '' : ' onchange="submit()"'), '') . (($this->useSelector('month') || $this->useSelector('week')) ? '' : hInput($this->remap['m'], $currmo)); } else { $selector[] = doTag($curryr, 'span', (($this->mywraptag) ? '' : $this->myclass)); } $request = serverSet('REQUEST_URI'); $redirect = serverSet('REDIRECT_URL'); if (!empty($redirect) && ($request != $redirect) && is_callable('_l10n_set_browse_language')) { // MLP in da house: use the redirect URL instead $request = $redirect; } $urlp = parse_url($request); $action = $urlp['path']; if ($permlink_mode == 'messy') { $out = makeOut('id','s','c','q','pg','p','month'); foreach($out as $key => $val) { if ($val) { $filters[] = $key.'='.$val; $filterHid[] = hInput($key, $val); } } } $filterHid = array_unique($filterHid); $filters = array_unique($filters); $extras = ''; if (!$static && ( $this->useSelector('month') || $this->useSelector('year') )) { if ($this->selbtn) { $extras .= doTag('', 'input', 'smd_cal_input', ' type="submit" value="'.$this->selbtn.'"'); } $extras .= join(n, $filterHid); } $selector = '
'.doTag(join(sp, $selector).$extras, $this->mywraptag, $this->myclass).'
'; $nav_back_link = $this->navigation($curryr, $currmo, '-', $filters, $urlp['path']); $nav_fwd_link = $this->navigation($curryr, $currmo, '+', $filters, $urlp['path']); $nav_back = (!$static && $nav_back_link) ? ''.$navparrow.'' : ' '; $nav_fwd = (!$static && $nav_fwd_link) ? ''.$navnarrow.'' : ' '; $c[] = doTag($nav_back,'th'); $c[] = ''.$selector.''; $c[] = doTag($nav_fwd,'th'); return doTag(join('',$c),'tr', 'smd_cal_navrow'); } function navigation($year,$month,$direction,$flt,$url='') { global $permlink_mode; if($direction == '-') { if($month - 1 < 1) { $month = 12; $year -= 1; } else { $month -= 1; } } else { if($month + 1 > 12) { $month = 1; $year += 1; } else { $month += 1; } } // Abort if we're about to go out of range if ($year < $this->eyr || $year > $this->lyr) { return ''; } $flt[] = $this->remap['m']."=$month"; $flt[] = $this->remap['y']."=$year"; return $url . "?" . join(a, $flt); } } /** * Basic Calendar data and display * http://www.oscarm.org/static/pg/calendarClass/ * @author Oscar Merida * @created Jan 18 2004 */ class SMD_Raw_Calendar { var $gmt = 1, $lang, $debug = 0; var $year, $eyr, $lyr, $month, $week; var $dayNameFmt, $mthNameFmt, $dayNames, $mthNames, $startDay, $endDay, $firstDayOfWeek = 0, $startOffset = 0; var $selectors, $selbtn, $selpfx, $selsfx; var $showISOWeek, $ISOWeekHead, $ISOWeekCell; var $cls_lev, $cls_pfx, $fopts; var $evwraptag, $mywraptag; var $rowclass, $cellclass, $emptyclass, $isoclass, $myclass, $tableID, $tblSummary, $tblCaption; var $navpclass, $navnclass, $navparrow, $navnarrow, $navid; var $holidays, $cellform, $hdrform, $maintain, $remap; /** * Constructor * * @param integer, year * @param integer, month * @return object * @public */ function SMD_Raw_Calendar ($yr, $mo, $debug=0) { $this->setDebug($debug); $this->setYear($yr); $this->setMonth($mo); $this->setClassPrefix('smd_cal_'); $this->startTime = strtotime( "$yr-$mo-01 00:00" ); $this->startDay = date( 'D', $this->startTime ); $this->endDay = date( 't', $this->startTime ); $this->endTime = strtotime( "$yr-$mo-".$this->endDay." 23:59:59" ); if ($this->debug) { echo "++ THIS MONTH'S RENDERED CALENDAR [ start stamp // end date // start day // end stamp // end date // end day number ] ++"; 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); } $this->setNameFormat('%a', 'd'); $this->setNameFormat('%B', 'm'); $this->setFirstDayOfWeek(0); $this->setShowISOWeek(''); $this->setTableID(''); $this->setTableClass(''); } // === end Calendar === // Getters function useSelector($val) { return in_array($val, $this->selectors); } function getDayName($day) { return ($this->dayNames[$day%7]); } function getMonthName() { if (is_array($this->mthNameFmt)) { return $this->mthNames[date('n',$this->startTime)]; } else { return strftime($this->mthNameFmt, $this->startTime); } } function getNavInfo($type) { $r = ''; switch ($type) { case "id": $r = $this->navid; break; case "pc": $r = $this->navpclass; break; case "nc": $r = $this->navnclass; break; case "pa": $r = $this->navparrow; break; case "na": $r = $this->navnarrow; break; } return $r; } // Setters function setDebug($d){ $this->debug = $d; } function setGMT($b){ $this->gmt = $b; } function setLang($code){ $this->lang = $code; } function setSummary($txt){ $this->tblSummary = $txt; } function setCaption($txt){ $this->tblCaption = $txt; } function setCellForm($frm){ $this->cellform = $frm; } function setHdrForm($frm){ $this->hdrform = $frm; } function setTableID($id){ $this->tableID = $id; } function setYear($yr){ $this->year = $yr; } function setEYear($yr){ $this->eyr = $yr; } function setLYear($yr){ $this->lyr = $yr; } function setMonth($mth){ $this->month = (int)$mth; } function setWeek($wk){ if ($wk) { $wk = str_pad($wk, 2, '0', STR_PAD_LEFT); $this->week = $wk; $this->month = safe_strftime("%m", strtotime($this->year."W".$wk)); } } function setNavKeep($ar){ $this->maintain = $ar; } function setShowISOWeek($val) { $this->showISOWeek = ($val) ? true : false; if ($val) { $val = do_list($val); $this->ISOWeekHead = $val[0]; $this->ISOWeekCell = (isset($val[1])) ? $val[1] : '{week}'; } } function setRemap($map){ $this->remap = $map; } function setClassLevels($cls){ $this->cls_lev = $cls; } function setClassPrefix($cls){ $this->cls_pfx = $cls; } function setEventWraptag($wrap){ $this->evwraptag = $wrap; } function setMYWraptag($wrap){ $this->mywraptag = $wrap; } function setTableClass($cls) { $this->tableclass = ($cls) ? $this->cls_pfx.$cls : ''; } function setRowClass($cls){ $this->rowclass = ($cls) ? $this->cls_pfx.$cls : ''; } function setCellClass($cls){ $this->cellclass = ($cls) ? $this->cls_pfx.$cls : ''; } function setEmptyClass($cls){ $this->emptyclass = ($cls) ? $this->cls_pfx.$cls : ''; } function setISOWeekClass($cls){ $this->isoclass = ($cls) ? $this->cls_pfx.$cls : ''; } function setNavInfo($clsp, $clsn, $arrp, $arrn, $nid){ $this->navpclass = ($clsp) ? $this->cls_pfx.$clsp : ''; $this->navnclass = ($clsn) ? $this->cls_pfx.$clsn : ''; $this->navparrow = ($arrp) ? $arrp : ''; $this->navnarrow = ($arrn) ? $arrn : ''; $this->navid = ($nid) ? $this->cls_pfx.$nid : ''; } function setMYClass($cls){ $this->myclass = ($cls) ? $this->cls_pfx.$cls : ''; } function setFilterOpts($f) { $this->fopts = $f; } function setHolidays($hols) { $this->holidays = $hols; } function setSelectors($sel, $btn) { foreach ($sel as $idx => $item) { $selparts = explode(":", $item); $sel[$idx] = $selparts[0]; $this->selpfx[$selparts[0]] = (isset($selparts[1])) ? $selparts[1] : ''; $this->selsfx[$selparts[0]] = (isset($selparts[2])) ? $selparts[2] : ''; } $this->selectors = $sel; $this->selbtn = $btn; } function setFirstDayOfWeek($d) { $this->firstDayOfWeek = ((int)$d <= 6 and (int)$d >= 0) ? (int)$d : 0; $this->startOffset = date('w', $this->startTime) - $this->firstDayOfWeek; if ( $this->startOffset < 0 ) { $this->startOffset = 7 - abs($this->startOffset); } } /** * frm: any valid PHP strftime() string or ABBR/FULL * typ: d to set day, m to set month format */ function setNameFormat($frm, $typ="d") { switch ($frm) { case "full": case "FULL": $fmt = ($typ == 'd') ? "%A" : "%B"; break; case "abbr": case "ABBR": $fmt = ($typ == 'd') ? "%a" : "%b"; break; default: if (strpos($frm, '%') === 0) { $fmt = $frm; } else { $frm = trim($frm, '{}'); $frm = do_list($frm); $fmt = $frm; } break; } if ($typ == "d") { $this->dayNameFmt = $fmt; $this->dayNames = array(); // This is done to make sure Sunday is always the first day of our array // Unix time gets a little funky at the beginning depending upon the timezone. $serveroffset = gmmktime(0,0,0) - mktime(0,0,0); $start = ($serveroffset < 0) ? 4 : 3; $end = $start + 7; for($i=$start; $i<$end; $i++) { if (is_array($fmt)) { $this->dayNames[] = $fmt[$i-$start]; } else { $this->dayNames[] = ucfirst(strftime($fmt, 86400*$i)); } } } else { $this->mthNameFmt = $fmt; $this->mthNames = array(); for ($i=0; $i<12; $i++) { if (is_array($fmt)) { $this->mthNames[$i+1] = $fmt[$i]; } else { $this->mthNames[$i+1] = ucfirst(strftime($fmt, 86400*$i)); } } } } /** * Return markup for displaying the calendar. * @return * @public */ function display ( ) { $id = ($this->tableID) ? ' id="'.$this->tableID.'"' : ''; $c[] = ''; $c[] = '' . $this->dspDayNames() . ''; $c[] = $this->dspDayCells(); $c[] = ''; return join('',$c); } // === end display === /** * Displays the row of day names. * @return string * @private */ function dspDayNames ( ) { if ($this->hdrform) { $reps = array( '{firstday}' => $this->firstDayOfWeek, '{daynames}' => join(',', $this->dayNames), '{isoweekhead}' => $this->ISOWeekHead, '{week}' => date('W', $this->startTime), '{month}' => date('n', $this->startTime), '{year}' => date('Y', $this->startTime), '{isoyear}' => date('o', $this->startTime), ); return parse(strtr($this->hdrform, $reps)); } else { $c[] = ''; $i = $this->firstDayOfWeek; $j = 0; // count number of days displayed $end = false; if ($this->showISOWeek) { $c[] = "".$this->ISOWeekHead.""; } for($j = 0; $j<=6; $j++, $i++) { if($i == 7) { $i = 0; } $c[] = ''.$this->getDayName($i).""; } $c[] = ''; return join('',$c); } } // === end dspDayNames === /** * Displays all day cells for the month * * @return string * @private */ function dspDayCells ( ) { $i = 0; // cell counter $emptyClass = $this->emptyclass; $isoClass = $this->isoclass; $rowClass = $this->rowclass; $rowClass = ($rowClass) ? ' class="'.$rowClass.'"' : ''; $c[] = ''; if ($this->showISOWeek) { $reps = array( '{week}' => date('W', $this->startTime), '{month}' => date('n', $this->startTime), '{year}' => date('Y', $this->startTime), '{isoyear}' => date('o', $this->startTime), ); $wkcell = strtr($this->ISOWeekCell, $reps); $c[] = ''.$wkcell.''; } // first display empty cells based on what weekday the month starts in for( $j=0; $j<$this->startOffset; $j++ ) { $i++; $c[] = ' '; } // end offset cells // write out the rest of the days, at each sunday, start a new row. for( $d=1; $d<=$this->endDay; $d++ ) { $i++; $c[] = $this->dspDayCell( $d ); if ( $i%7 == 0 ) { $c[] = ''; } if ( $d<$this->endDay && $i%7 == 0 ) { $c[] = ''; if ($this->showISOWeek) { $theTime = safe_strtotime($this->year."-".$this->month."-".(int)($d + 1) ." 00:00"); $reps = array( '{week}' => date('W', $theTime), '{month}' => date('n', $theTime), '{year}' => date('Y', $theTime), '{isoyear}' => date('o', $theTime), ); $wkcell = strtr($this->ISOWeekCell, $reps); $c[] = ''.$wkcell.''; } } } // fill in the final row $left = 7 - ( $i%7 ); if ( $left < 7) { for ( $j=0; $j<$left; $j++ ) { $c[] = ' '; } $c[] = "\n\t"; } return '' . join('',$c) . ''; } // === end dspDayCells === /** * outputs the contents for a given day * * @param integer, day * @abstract */ function dspDayCell ( $day ) { return ''.$day.''; } // === end dayCell === } // end class function smd_cal_minilink($row, $day, $month, $year, $use_posted=false) { global $permlink_mode; $lang = ''; $request = serverSet('REQUEST_URI'); $redirect = serverSet('REDIRECT_URL'); if (!empty($redirect) && ($request != $redirect) && is_callable('_l10n_set_browse_language')) { // MLP in da house so extract the language currently in use -- is there an MLP-native method for this? $reqparts = explode('/', $request); $redparts = explode('/', $redirect); $lang = join('', array_diff($redparts, $reqparts)) . '/'; } if( $permlink_mode == 'year_month_day_title' ) { $linkdate = ($use_posted) ? date('Y/m/d', $row['uPosted']) : $year.'/'.str_pad($month,2,"0",STR_PAD_LEFT).'/'.str_pad($day,2,"0",STR_PAD_LEFT); $href = ' href="'.hu.$lang.$linkdate.'"'; } else { $linkdate = ($use_posted) ? date('Y-m-d', $row['uPosted']) : $year.'-'.str_pad($month,2,"0",STR_PAD_LEFT).'-'.str_pad($day,2,"0",STR_PAD_LEFT); $href = ' href="'.hu.$lang.'?date='.$linkdate; if($row['Section']) { $href = $href.a.'s='.$row['Section']; } // if($category) { $href = $href.a.'c='.$category; } $href .= '"'; } return tag($day, 'a', $href); } // Perform one of two types of test: a flag-based test, or an info-based test function smd_if_cal($atts, $thing) { global $smd_cal_flag, $smd_calinfo, $smd_date; extract(lAtts(array( 'flag' => '', 'calid' => '', 'isoyear' => '', 'year' => '', 'month' => '', 'week' => '', 'day' => '', 'logic' => 'or', 'debug' => '0', ), $atts)); $flag = do_list($flag); $ctr = $num = 0; if ($debug) { dmp($atts); } if ($flag && $flag[0] != '') { $num += count($flag); foreach ($flag as $whatnot) { if (empty($whatnot)) continue; $ctr += (in_array($whatnot, $smd_cal_flag) || ($whatnot == 'SMD_ANY' && !empty($smd_cal_flag))) ? 1 : 0; } } if ($calid) { $num++; $ctr += ($smd_calinfo['id'] === $calid) ? 1 : 0; } foreach (array("iy" => "isoyear", "y" => "year", "m" => "month", "w" => "week", "d" => "day") as $idx => $test) { $tester = $$test; $compare = $smd_date[$idx]; if ($tester) { $num++; preg_match('/([!=<>]+)?([\d]+)/', $tester, $matches); if ($debug) { dmp("TEST IF: ". $compare. (($matches[1]) ? $matches[1] : '=') . $matches[2] ); } switch ($matches[1]) { case "!": $ctr += ($compare!=$matches[2]) ? 1 : 0; break; case ">": $ctr += ($compare>$matches[2]) ? 1 : 0; break; case ">=": $ctr += ($compare>=$matches[2]) ? 1 : 0; break; case "<": $ctr += ($compare<$matches[2]) ? 1 : 0; break; case "<=": $ctr += ($compare<=$matches[2]) ? 1 : 0; break; default: $ctr += ($compare==$matches[2]) ? 1 : 0; break; } } } $result = (($ctr === $num && $logic == "and") || $ctr > 0 && $logic == "or") ? true : false; return parse(EvalElse($thing, $result)); } // Convenient wrapper for smd_cal_info use="event" function smd_event_info($atts) { $atts['use'] = 'event'; return smd_cal_info($atts); } // Grab additional information about the current event function smd_cal_info($atts) { global $pretext, $thisarticle, $smd_cal_flag, $smd_calinfo, $smd_date, $smd_eventinfo; extract(lAtts(array( 'type' => 'flag', 'join' => ' ', 'join_prefix' => 'SMD_AUTO', 'html' => 0, 'escape' => 'html', 'use' => 'cal', // 'cal' for calendar (uses $smd_calinfo) or 'event' for event lists (uses $smd_eventinfo). Not publically alterable 'debug' => 0, ), $atts)); // Validate $use attribute $use = (in_array($use, array('cal', 'event'))) ? $use : 'cal'; $cal_global = ${'smd_'.$use.'info'}; if ($debug && $thisarticle) { echo '++ Event name ++'; dmp($thisarticle['title']); } if ($debug && $cal_global) { echo '++ Available '.$use.' info ++'; dmp($cal_global); } if ($debug && $smd_date) { echo '++ Available date info ++'; dmp($smd_date); } if ($debug && $smd_cal_flag) { echo '++ Available flag info ++'; dmp($smd_cal_flag); } // Type: 0=date, 1=smd_cal/eventinfo, 2=pretext, 3=thisarticle, 4(or other)=user value $map = array( 'year' => array(0, 'y'), 'isoyear' => array(0, 'iy', 'y'), 'month' => array(0, 'm'), 'week' => array(0, 'w'), 'day' => array(0, 'd'), 'section' => array(3, '', 's'), 'category1' => array(3, '', 'c'), 'category2' => array(3, '', 'c'), 'thisid' => array(3, 'thisid', 'id'), 'article' => array(1, 'artid', 'id'), 'calid' => array(1, 'id', 'calid'), 'category' => array(2, 'c'), 'realname' => array(2, 'author'), ); $join = ($html) ? a : $join; // html mode forces ampersand join $type = do_list($type); $ret = array(); foreach ($type as $item) { $pts = do_list($item, ':'); $item = $pts[0]; if (empty($item)) continue; // Default html id $hid = (isset($map[$item])) ? ((isset($map[$item][2])) ? $map[$item][2] : $map[$item][1]) : $item; // User-specified htmlid overrides it $hid = (count($pts) > 1 && !empty($pts[1])) ? $pts[1] : $hid; if ($item == "flag") { $ret[] = (($join_prefix=="SMD_AUTO") ? $join : '').join($join, $smd_cal_flag); } else if ($item == "author" || $item == "realname") { $currauthor = ($thisarticle == NULL) ? '' : author(array()); if ($currauthor) { $ret[] = (($html) ? $hid.'=' : '') . $currauthor; } } else if ($item == "s") { $sec = (!empty($pretext['s'])) ? $pretext['s'] : ((isset($cal_global['s']) && !empty($cal_global['s'])) ? $cal_global['s'] : ''); if ($sec) { $ret[] = (($html) ? $hid.'=' : '') . $sec; } } else if (isset($map[$item])) { $typ = $map[$item][0]; $idx = empty($map[$item][1]) ? $item : $map[$item][1]; switch ($typ) { case 0: if ($smd_date[$idx]) { $ret[] = (($html) ? $hid.'=' : '') . $smd_date[$idx]; } break; case 1: if (!empty($cal_global[$idx])) { $ret[] = (($html) ? $hid.'=' : '') . $cal_global[$idx]; } break; case 2: if (!empty($pretext[$idx])) { $ret[] = (($html) ? $hid.'=' : '') . $pretext[$idx]; } break; case 3: if ($thisarticle != NULL && isset($thisarticle[$idx]) && !empty($thisarticle[$idx])) { $ret[] = (($html) ? $hid.'=' : '') . $thisarticle[$idx]; } break; } } else if (array_key_exists($item, $pretext)) { if ($pretext[$item]) { $ret[] = (($html) ? $hid.'=' : '') . $pretext[$item]; } } else if (isset($cal_global[$item])) { if (!empty($cal_global[$item])) { $ret[] = (($html) ? $hid.'=' : '') . $cal_global[$item]; } } else { if ($thisarticle != NULL && isset($thisarticle[$item]) && !empty($thisarticle[$item])) { $ret[] = (($html) ? $hid.'=' : '') . $thisarticle[$item]; } } } $ret = array_unique($ret); $out = (($join_prefix=="SMD_AUTO") ? (($html) ? '?' : '') : $join_prefix).join($join, $ret); return ($escape=='html') ? htmlspecialchars($out) : $out; } // Return a formatted timestamp, with optional 'time now' override function smd_cal_now($atts) { global $dateformat; extract(lAtts(array( 'format' => $dateformat, 'now' => '', 'offset' => '', 'gmt' => '', 'lang' => '', ), $atts)); $theDay = (gps('d') && is_numeric(gps('d'))) ? (int)gps('d') : safe_strftime('%d'); $theMonth = (gps('m') && is_numeric(gps('m'))) ? (int)gps('m') : safe_strftime('%m'); $theYear = (gps('y') && is_numeric(gps('y'))) ? (int)gps('y') : safe_strftime('%Y'); if ($now) { $now = str_replace("?month", date('F', mktime(12,0,0,$theMonth,$theDay,$theYear)), $now); $now = str_replace("?year", $theYear, $now); $now = str_replace("?day", $theDay, $now); $now = is_numeric($now) ? $now : strtotime($now); } else { $now = time(); } if ($offset) { $now = strtotime($offset, $now); } $format = smd_cal_reformat_win($format, $now); return safe_strftime($format, $now, $gmt, $lang); } // Set user-defined classes for a cell function smd_cal_class($atts) { global $smd_cal_ucls; extract(lAtts(array( 'name' => '', ), $atts)); $name = do_list($name); $smd_cal_ucls = array_merge($smd_cal_ucls, $name); } // replacement(ish) tag that understands how to handle recurring events function smd_article_event($atts, $thing=NULL) { global $prefs, $pretext, $thispage, $thisarticle, $smd_eventinfo, $smd_cal_flag, $smd_date; extract(lAtts(array( 'time' => 'any', 'type' => 'standard,recur,multi', 'expired' => '', 'id' => '', 'category' => '', 'section' => '', 'author' => '', 'realname' => '', 'custom' => '', 'status' => 'live', 'param_delim' => ':', 'sort' => '', 'form' => '', 'stepfield' => '', 'skipfield' => '', 'omitfield' => '', 'extrafield' => '', 'allspanned' => '0', 'datefields' => '', 'month' => '', 'from' => '', 'to' => '', 'offset' => 0, 'limit' => '10', 'eventlimit' => '10', 'paging' => '1', 'pageby' => '', 'pgonly' => '', 'wraptag' => '', 'break' => '', 'class' => '', 'debug' => 0, ), $atts)); // Phase 1 filters $filtSQL = $subSQL = array(); if($category) { $tmp = doQuote(join("','", doSlash(do_list($category)))); $filtSQL[] = '( Category1 IN ('.$tmp.') OR Category2 IN ('.$tmp.') )'; } if($section) { $filtSQL[] = 'Section IN ('.doQuote(join("','", doSlash(do_list($section)))).')'; } if($realname) { $authors = safe_column('name', 'txp_users', 'RealName IN ('. doQuote(join("','", doArray(do_list($realname), 'urldecode'))) .')' ); $author = join(',', $authors); } if($author) { $filtSQL[] = 'AuthorID IN ('.doQuote(join("','", doSlash(do_list($author)))).')'; } if($id) { $filtSQL[] = 'ID IN ('.join(',', array_map('intval', do_list($id))).')'; } if($custom) { $custs = do_list($custom); $validOps = array('=', '!=', '>', '>=', '<', '<=', 'like', 'not', 'not like'); foreach ($custs as $set) { if (strpos($set, $param_delim) !== false) { $clauseOpts = do_list($set, $param_delim); $fld = $clauseOpts[0]; $oper = ((count($clauseOpts) == 3) && (in_array(strtolower($clauseOpts[1]), $validOps))) ? $clauseOpts[1] : '='; $clause = (count($clauseOpts) == 3) ? $clauseOpts[2] : ((count($clauseOpts) == 2) ? $clauseOpts[1] : ''); $filtSQL[] = $fld . " $oper " . doQuote(doSlash($clause)); } } } $type = do_list($type); $pageby = (empty($pageby) ? $limit : $pageby); foreach ($type as $evtyp) { switch($evtyp) { case 'standard': if ($stepfield) { $subSQL[] = "(".$stepfield." = '' AND Expires = ".NULLDATETIME.")"; } break; case 'recur': if ($stepfield) { $subSQL[] = "(".$stepfield." != '')"; } break; case 'multi': if ($stepfield) { $subSQL[] = "(".$stepfield." = '' AND Expires != ".NULLDATETIME.")"; } break; } } if ($subSQL) { $filtSQL[] = '('.join(' OR ', $subSQL).')'; } $status = ($status) ? $status : 'live'; // in case status has been emptied $status = do_list($status); $stati = array(); foreach ($status as $stat) { if (empty($stat)) { continue; } else if (is_numeric($stat)) { $stati[] = $stat; } else { $stati[] = getStatusNum($stat); } } $filtSQL[] = 'Status IN ('.doQuote(join("','", $stati)).')'; $expired = ($expired) ? $expired : $prefs['publish_expired_articles']; if (!$expired) { $filtSQL[] = '(now() <= Expires OR Expires = '.NULLDATETIME.')'; } // Sorting rules: data is sorted once as it is extracted via SQL and then again after the fake dates have been inserted $sort = (empty($sort)) ? 'Posted asc' : $sort; $sort = do_list($sort); $sortPrefix = "SORT_"; $sortOrder = array(); for ($idx = 0; $idx < count($sort); $idx++) { $sorties = explode(' ', $sort[$idx]); if (count($sorties) <= 1) { $sorties[1] = "asc"; } $sorties[1] = $sortPrefix.(($sorties[1] == "desc") ? 'DESC' : 'ASC'); $sortOrder[] = array("by" => $sorties[0], "dir" => $sorties[1]); } $filtSQL = join(' AND ', $filtSQL); $filtSQL .= ' ORDER BY '.join(',',doSlash($sort)); $grabCols = '*, unix_timestamp(Posted) as uPosted, unix_timestamp(LastMod) as uLastMod, unix_timestamp(Expires) as uExpires'; $evlist = safe_rows($grabCols, 'textpattern', $filtSQL, $debug); if ($debug>2) { echo "++ RECORD SET ++"; dmp($evlist); } $all_evs = $ev_tally = array(); $now = time() + tz_offset(); $eventlimit = do_list($eventlimit); if (count($eventlimit) == 1) { $eventlimit[1] = $eventlimit[0]; } $datefields = do_list($datefields); // Phase 2: expand any recurring dates and collate all events that fall within the alloted ranges foreach ($evlist as $row) { $ev_posted = (!empty($datefields[0]) && !empty($row[$datefields[0]]) && ($stdt = strtotime($row[$datefields[0]])) !== false) ? $stdt : $row['uPosted']+tz_offset($row['uPosted']); $ev_expires = (isset($datefields[1]) && !empty($row[$datefields[1]]) && ($endt = strtotime($row[$datefields[1]])) !== false) ? $endt : (($row['uExpires']==0) ? 0 : $row['uExpires']+tz_offset($row['uExpires'])); $skip = ($skipfield && $row[$skipfield] != ''); $omit = ($omitfield && $row[$omitfield] != ''); $recur = ($stepfield && $row[$stepfield] != ''); $extra = ($extrafield && $row[$extrafield] != ''); $multi = ($ev_expires > $ev_posted && (date("d-m-Y", $ev_expires) != date("d-m-Y", $ev_posted))) ? true : false; // If end < start the user-specified dates cannot be trusted if ($ev_expires != 0 && $ev_expires <= $ev_posted) { $ev_posted = $row['uPosted']+tz_offset($row['uPosted']); $ev_expires = (($row['uExpires']==0) ? 0 : $row['uExpires']+tz_offset($row['uExpires'])); trigger_error('Expiry cannot be before start date in "'.$row['Title'].'": ignored', E_USER_WARNING); } if ($debug > 1) { echo '++ EVENT START // END ++'; dmp($row['Title']); dmp($ev_posted, date('Y-m-d H:i:s', $ev_posted), $ev_expires, date('Y-m-d H:i:s', $ev_expires)); } // Rewrite the start/end dates in case they are user-defined $row['uPosted'] = $ev_posted; $row['Posted'] = date("Y-m-d H:i:s", $ev_posted); $row['uExpires'] = $ev_expires; $row['Expires'] = ($ev_expires==0) ? '0000-00-00 00:00:00' : date("Y-m-d H:i:s", $ev_expires); $diff = ($ev_expires == 0) ? 0 : $ev_expires - $ev_posted; $ev_month = date('m', $ev_posted); $ev_year = date('Y', $ev_posted); $ev_hr = date('H', $ev_posted); $ev_mn = date('i', $ev_posted); $ev_sc = date('s', $ev_posted); $ignore = array(); // Generate a skip array for this event if ($skip) { $ignores = do_list($row[$skipfield]); foreach ($ignores as $val) { $igrng = smd_expand_daterange($val, $ev_posted, $ev_expires); foreach ($igrng as $theval) { $ignore[] = date("d-M-Y", $theval); // Force each date to a known format } } } // Append any omitted events if ($omit) { $omits = do_list($row[$omitfield]); foreach ($omits as $val) { $omrng = smd_expand_daterange($val, $ev_posted, $ev_expires); foreach ($omrng as $theval) { $ignore[] = date("d-M-Y", $theval); } } } if ($debug > 1 && $ignore) { echo '++ IGNORED DATES ++'; dmp($ignore); } // Does the base event deserve to be in the results? if (smd_include_event($ev_posted, $now, $ignore, $time, $from, $to, $month)) { $all_evs[] = array('ev' => $row, 'flags' => ($multi ? array('multifirst') : array('standard')) ); $ev_tally[$row['uPosted']] = (isset($ev_tally[$row['uPosted']])) ? $ev_tally[$row['uPosted']]+1 : 1; } // Add any extra dates for this event if ($extra) { $xtra = do_list($row[$extrafield]); $xtras = array(); // Make up an array of all extra dates foreach ($xtra as $val) { if (strpos($val, "+") === false) { $exrng = smd_expand_daterange($val); $xtras[] = date("Y-m-d", $exrng[0]); $spex = 0; } else { $fake_diff = safe_strtotime(date("Y-M-d", $ev_expires) . " 23:59:59"); $fdiff = ($ev_expires==0) ? 0 : $fake_diff - $ev_posted; $chk = $allspanned && $multi && !$recur; $spidth = $chk ? ceil($fdiff / (60*60*24)) : 1; // days between dates $val = rtrim($val, '+'); for ($jdx = 1; $jdx <= $spidth; $jdx++) { $xtras[] = date("Y-m-d", safe_strtotime($val . (($jdx==1) ? '' : '+'.($jdx-1).' days'))); } $spex = $chk ? 1 : 0; } } $xtras = array_unique($xtras); $stampoff = (int)(3600*$ev_hr) + (int)(60*$ev_mn) + (int)$ev_sc; foreach ($xtras as $jdx => $val) { $tm = strtotime($val); $flags = array('extra'); // No $ignore for additional events, as they always show up if (smd_include_event($tm+$stampoff, $now, array(), $time, $from, $to, $month)) { $fakerow = $row; $fakerow['Posted'] = date("Y-m-d H:i:s", $tm+$stampoff); $fakerow['uPosted'] = $tm+$stampoff; if ($diff > 0) { $fakerow['Expires'] = date("Y-m-d H:i:s", $tm+$stampoff+$diff); $fakerow['uExpires'] = $tm+$stampoff+$diff; } if ($spex) { $flags[] = ($jdx==0) ? 'multifirst' : (($jdx==$spidth-1) ? 'multilast' : 'multi'); } $all_evs[] = array('ev' => $fakerow, 'flags' => $flags); $ev_tally[$fakerow['uPosted']] = (isset($ev_tally[$fakerow['uPosted']])) ? $ev_tally[$fakerow['uPosted']]+1 : 1; } } } if ($recur) { $flags = array('recurfirst'); $freq = do_list($row[$stepfield]); $monthly = false; $currmonth = $ev_month; $curryear = $ev_year; foreach ($freq as $interval) { $fakerow = $row; $cstamp = $ev_posted; for($idx = 0; $idx < 99999; $idx++) { $lstamp = $cstamp; if ((isset($ev_tally[$row['uPosted']]) && ($ev_tally[$row['uPosted']] >= $eventlimit[0])) || ($to && $cstamp > safe_strtotime($to))) { break; } $ival = str_replace("?month", date('F', mktime(0,0,0,$currmonth,1)), $interval); $ival = str_replace("?year", $curryear, $ival); if (strpos($ival, "last") === 0) { $ival = date("l, F jS Y", strtotime( $ival, mktime(12, 0, 0, date("n", mktime(0,0,0,$currmonth,1,$curryear))+1, 1, $curryear) )); $monthly = true; } else if (strpos($ival, "first") === 0) { $ival = date("l, F jS Y", strtotime( $ival, mktime(12, 0, 0, (($currmonth>1) ? $currmonth-1 : 12), date("t", mktime(0,0,0,$currmonth-1,1,(($currmonth==1) ? $curryear-1: $curryear)) ), (($currmonth==1) ? $curryear-1: $curryear)) )); $monthly = true; } else if (strpos($ival, "this") === 0) { $monthly = true; } if (strpos($interval, "?month") || strpos($interval, "?year")) { $monthly = true; } if ($monthly) { $cstamp = strtotime($ival); } else { $cstamp = strtotime($ival, $cstamp); } // This kludge takes account of timestamps like "last Thursday" (of the month). The last 'whatever day' of // a month can only be a maximum of 31 days before the last timestamp we saw, so check for that (+/- 10 mins) $diffstamp = $cstamp - $lstamp; if ($diffstamp < 0) { if ($diffstamp > -(60*60*24*31)+600) { $cstamp = false; // Some 'last weekday' of the previous month } else { break; // PHP_INT_MAX exceeded } } if ($cstamp !== false) { if ($debug > 1) { dmp("INTERVAL: ". $cstamp . ' // ' .date('d-M-Y H:i:s', $cstamp)); } if (($cstamp < $ev_expires || $ev_expires == '0') && ($cstamp != $ev_posted)) { $show_me = smd_include_event($cstamp, $now, $ignore, $time, $from, $to, $month); if ($show_me) { $flags[] = 'recur'; $fakerow['Posted'] = date("Y-m-d H:i:s", $cstamp); $fakerow['uPosted'] = $cstamp; $all_evs[] = array('ev' => $fakerow, 'flags' => $flags); $ev_tally[$row['uPosted']] = (isset($ev_tally[$row['uPosted']])) ? $ev_tally[$row['uPosted']]+1 : 1; $flags = array(); // reset so recurfirst is removed } } else { break; } } // Increment the month/year ready for the next interval if ($monthly) { $curryear = ($currmonth==12) ? $curryear+1 : $curryear; $currmonth = ($currmonth==12) ? 1 : $currmonth+1; } } if ($debug>1) { if (isset($ev_tally[$row['uPosted']])) { dmp("TALLY: ". $ev_tally[$row['uPosted']]); } } } } else if ($allspanned && date("Y-M-d", $ev_expires) != date("Y-M-d", $ev_posted)) { $postdate = date("Y-M-d H:i:s", $ev_posted); $fake_diff = safe_strtotime(date("Y-M-d", $ev_expires) . " 23:59:59"); $diff = ($ev_expires==0) ? 0 : $fake_diff - $ev_posted; $spidth = ceil($diff / (60*60*24)); // days between dates for ($jdx = 1; $jdx < $spidth; $jdx++) { $flags = array(); $tm = safe_strtotime($postdate.'+'.$jdx.' days'); $show_me = smd_include_event($tm, $now, $ignore, $time, $from, $to, $month); if ($show_me) { $flags[] = ($jdx==$spidth-1) ? 'multilast' : 'multi'; $fakerow = $row; $fakerow['Posted'] = date("Y-m-d H:i:s", $tm); $fakerow['uPosted'] = $tm; $all_evs[] = array('ev' => $fakerow, 'flags' => $flags); } } } } if ($debug>2) { echo "++ PRE-SORTED ++"; dmp($all_evs); } // Make up an array_multisort arg list and execute it foreach($all_evs as $key => $entry) { $row = $entry['ev']; foreach ($row as $identifier => $item) { $varname = "col_".$identifier; ${$varname}[$key] = $item; } } if(count($all_evs) > 0) { for ($idx = 0; $idx < count($sortOrder); $idx++) { $sortargs[] = '$col_'.$sortOrder[$idx]['by']; $sortargs[] = $sortOrder[$idx]['dir']; } $sortit = 'array_multisort('.implode(", ",$sortargs).', $all_evs);'; eval($sortit); } if ($debug>2) { echo "++ POST-SORTED ++"; dmp($all_evs); } // Handle paging if ($paging) { $grand_total = count($all_evs); $total = $grand_total - $offset; $numPages = ceil($total/$pageby); $pg = (!$pretext['pg']) ? 1 : $pretext['pg']; $pgoffset = $offset + (($pg - 1) * $pageby); // send paging info to txp:newer and txp:older $pageout['pg'] = $pg; $pageout['numPages'] = $numPages; $pageout['s'] = $pretext['s']; $pageout['c'] = $pretext['c']; $pageout['grand_total'] = $grand_total; $pageout['total'] = $total; if (empty($thispage)) $thispage = $pageout; if ($pgonly) return; } else { $pgoffset = $offset; } // Phase 3: iterate over the new array obeying any offset/limit. Anything in the range gets populated and parsed $out = array(); $ctr = 0; article_push(); $lastposted = 0; foreach ($all_evs as $idx => $entry) { $smd_cal_flag = $smd_date = $smd_eventinfo = array(); if ($idx >= $pgoffset && $ctr < $limit) { $row = $entry['ev']; $smd_cal_flag = $entry['flags']; $thisposted = date('Y-m-d', $row['uPosted']); $nextposted = isset($all_evs['ev'][$idx+1]) ? date('Y-m-d', $all_evs['ev'][$idx+1]['uPosted']) : 0; // Adjust times so txp:posted/expires return correct stamps $row['Posted'] = $row['Posted']-tz_offset(strtotime($row['Posted'])); $row['uPosted'] = $row['uPosted']-tz_offset($row['uPosted']); $row['Expires'] = ($row['uExpires'] == 0) ? '0000-00-00 00:00:00' : $row['Expires']-tz_offset(strtotime($row['Expires'])); $row['uExpires'] = ($row['uExpires'] == 0) ? 0 : $row['uExpires']-tz_offset($row['uExpires']); // Populate additional event information $fakestamp = ($row['uExpires'] == 0) ? 0 : strtotime(date("Y-M-d", $row['uExpires']) . " 23:59:59"); $smd_eventinfo['duration'] = ($row['uExpires'] == 0) ? 0 : $row['uExpires'] - $row['uPosted']; $smd_eventinfo['durationdays'] = ($fakestamp) ? ceil(($fakestamp - $row['uPosted']) / (60*60*24)) : 0; $smd_date['y'] = strftime('%Y', $row['uPosted']); $smd_date['m'] = strftime('%m', $row['uPosted']); $smd_date['d'] = (int)strftime('%d', $row['uPosted']); $smd_date['w'] = strftime(smd_cal_reformat_win('%V', $row['uPosted']), $row['uPosted']); $smd_date['iy'] = strftime(smd_cal_reformat_win('%G', $row['uPosted']), $row['uPosted']); if ($row['uExpires'] == 0) { $smd_date['expy'] = $smd_date['expm'] = $smd_date['expd'] = $smd_date['expw'] = $smd_date['expiy'] = ''; } else { $smd_date['expy'] = strftime('%Y', $row['uExpires']); $smd_date['expm'] = strftime('%m', $row['uExpires']); $smd_date['expd'] = (int)strftime('%d', $row['uExpires']); $smd_date['expw'] = strftime(smd_cal_reformat_win('%V', $row['uExpires']), $row['uExpires']); $smd_date['expiy'] = strftime(smd_cal_reformat_win('%G', $row['uExpires']), $row['uExpires']); } populateArticleData($row); $thisarticle['is_first'] = ($thisposted != $lastposted); $thisarticle['is_last'] = ($thisposted != $nextposted); $lastposted = $thisposted; $out[] = ($thing) ? parse($thing) : (($form) ? parse_form($form) : href($row['Posted'], permlinkurl($row), ' title="'.$row['Title'].'"') ); $ctr++; } } article_pop(); return doWrap($out, $wraptag, $break, $class); } // Try and output "nice" dates that read well across month/year boundaries. // For example: 28 May - 05 Jun 2011 or May 11-16 2011, depending on format function smd_event_duration($atts) { extract(lAtts(array( 'start' => posted(array('format' => '%s')), 'end' => expires(array('format' => '%s')), 'format' => '%d %b %Y', 'separator' => ' – ', 'debug' => 0, ), $atts)); // Extract the relevant portions of the format so we can muck about with them preg_match_all('/\%([dejbBmhgGyY])/', $format, $matches); $indexes = array('day' => '', 'month' => '', 'year' => ''); foreach($matches[1] as $idx => $token) { switch ($token) { case 'd': case 'e': case 'j': $indexes['day'] = $idx; break; case 'b': case 'B': case 'm': case 'h': $indexes['month'] = $idx; break; case 'g': case 'G': case 'y': case 'Y': $indexes['year'] = $idx; break; } } $day_first = ($indexes['day'] < $indexes['month']); $year_first = ($indexes['year'] == 0); $has_year = false; if ($end) { if (strftime('%Y %m %d', $start) == strftime('%Y %m %d',$end)) { // begin and end on same day $s_format = ''; $e_format = $format; $has_year = true; } else { if (strftime('%Y', $start) == strftime('%Y', $end)) { // same year if (strftime('%m', $start) == strftime('%m', $end)) { // and same month $re1 = ($day_first) ? '/\%[bBmhgGyY]/' : '/\%[gGyY]/'; $re2 = ($day_first) ? '/\%[gGyY]/' : '/\%[bBmhgGyY]/'; $s_format = trim(preg_replace($re1, '', $format)); $e_format = ($re2) ? trim(preg_replace($re2, '', $format)) : $format; } else { // not same month $s_format = $e_format = trim(preg_replace('/\%[gGyY]/', '', $format)); } } else { // different year $s_format = $e_format = $format; $has_year = true; } $s_format .= $separator; } // Add the year back in the correct position $s_format = ($has_year) ? $s_format : (($year_first) ? $matches[0][$indexes['year']] . ' ' . $s_format : $s_format); $e_format = ($has_year) ? $e_format : (($year_first) ? $e_format : $e_format . ' ' . $matches[0][$indexes['year']]); } else { $s_format = $format; $e_format =''; } return (($s_format) ? strftime($s_format, $start) : '') . (($e_format) ? strftime($e_format, $end) : ''); } // An unoptimized workaround when "%V" and "%G" fails (usually on Windows) // Algorithm adapted from http://www.personal.ecu.edu/mccartyr/ISOwdALG.txt with thanks. // All other shortcut algorithms failed edge cases function smd_cal_iso_week($format='%V', $time = null) { if (!$time) $time = time(); $yr = strftime("%Y", $time); $leap = ( ( ($yr % 4 == 0) && ($yr % 100 != 0) ) || $yr % 400 == 0 ); $leap_prev = ( ( (($yr-1) % 4 == 0) && (($yr-1) % 100 != 0) ) || ($yr-1) % 400 == 0 ); $day_of_year = strftime('%j', $time); // Find the weekday of Jan 1st in the given year $yy = ($yr - 1) % 100; $c = ($yr - 1) - $yy; $g = $yy + ($yy / 4); $jan1weekday = 1 + ((((($c / 100) % 4) * 5) + $g) % 7); // Find weekday ( could use: $weekday = strftime('%u', $time); ) $h = $day_of_year + ($jan1weekday - 1); $weekday = 1 + ( ($h - 1) % 7); // Find if $time falls in iso_year Y-1, iso_week 52 or 53 if (($day_of_year <= (8 - $jan1weekday)) && $jan1weekday > 4) { $iso_year = $yr - 1; if ($jan1weekday == 5 || ($jan1weekday == 6 && $leap_prev)) { $iso_week = 53; } else { $iso_week = 52; } } else { $iso_year = $yr; } // Find if $time falls in iso_year Y+1, iso_week 1 if ($iso_year == $yr) { $idx = ($leap) ? 366 : 365; if ( ($idx - $day_of_year) < (4 - $weekday) ) { $iso_year = $yr + 1; $iso_week = 1; } } // Find if $time falls in iso_year Y, iso_week 1 thru 53 if ($iso_year == $yr) { $jdx = $day_of_year + (7 - $weekday) + ($jan1weekday - 1); $iso_week = $jdx / 7; if ($jan1weekday > 4) { $iso_week--; } } // Replacement array $reps = array( '%V' => str_pad($iso_week, 2, '0', STR_PAD_LEFT), '%G' => $iso_year, '%g' => substr($iso_year, 2), ); return strtr($format, $reps); } // Adapted from: http://php.net/manual/en/function.strftime.php function smd_cal_reformat_win($format, $ts = null) { // Only Win platforms need apply if (!is_windows()) return $format; if (!$ts) $ts = time(); $mapping = array( '%C' => sprintf("%02d", date("Y", $ts) / 100), '%D' => '%m/%d/%y', '%e' => sprintf("%' 2d", date("j", $ts)), '%F' => '%Y-%m-%d', '%g' => smd_cal_iso_week('%g', $ts), '%G' => smd_cal_iso_week('%G', $ts), '%h' => '%b', '%l' => sprintf("%' 2d", date("g", $ts)), '%n' => "\n", '%P' => date('a', $ts), '%r' => date("h:i:s", $ts) . " %p", '%R' => date("H:i", $ts), '%s' => date('U', $ts), '%t' => "\t", '%T' => '%H:%M:%S', '%u' => ($w = date("w", $ts)) ? $w : 7, '%V' => smd_cal_iso_week('%V', $ts), ); $format = str_replace( array_keys($mapping), array_values($mapping), $format ); return $format; } // Find if the haystack contains one of the values in needle. Is there a cleverer way to do this? function smd_cal_in_array($needle, $haystack) { foreach ($haystack as $val) { if (in_array($val, $needle)) { return true; } } return false; } // Check the passed timestamp against every time restriction and return true if it passes them all function smd_include_event($ts, $now, $ign, $time, $from, $to, $month) { $show = array(); $show[] = !in_array(date("d-M-Y", $ts), $ign); $time = do_list($time); $showor = false; foreach($time as $tm) { switch($tm) { case "any": $showor = true; break; case "future": $showor = $showor || (($ts > $now) ? true : false); break; case "today": $showor = $showor || (($ts >= strtotime(date('Y-m-d 00:00:00', $now)) && $ts <= strtotime(date('Y-m-d 23:59:59', $now))) ? true : false); break; default : $showor = $showor || (($ts < $now) ? true : false); break; } } $show[] = $showor; if ($from) { $show[] = ($ts >= safe_strtotime($from)) ? true : false; } if ($to) { $show[] = ($ts <= safe_strtotime($to)) ? true : false; } if ($month) { $show[] = (date("Y-m", $ts) == $month) ? true : false; } return (!in_array(0, $show)) ? true : false; } // Convert date ranges like 24-Oct-08 => 5-Nov-08 to an array of discrete date entities // Also, weekday vals such as {Sun:Mon:Wed} would return those days between $start and $end function smd_expand_daterange($range, $start='', $end='', $fmt='%s') { $out = array(); $rng = do_list($range, "=>"); if (count($rng) > 1) { // Range expansion $diff = safe_strtotime($rng[1]) - safe_strtotime($rng[0]); $diffdays = ceil($diff / (60*60*24)); // days between dates for ($jdx = 0; $jdx <= $diffdays; $jdx++) { $out[] = safe_strftime($fmt, safe_strtotime($rng[0] . (($jdx==0) ? '' : '+'.$jdx.' days'))); } } else if ($start && $end && strpos($range, '{') === 0 && strpos($range, '}') === strlen($range)-1) { // Day of week expansion $days = do_list(trim($range,'{}'), ':'); $diffdays = ceil(($end-$start) / (60*60*24)); for ($jdx = 0; $jdx <= $diffdays; $jdx++) { $tm = $start + ($jdx*60*60*24); if (in_array(date('D', $tm), $days)) { $out[] = safe_strftime($fmt, $tm); } } } else { // Single date $out[] = safe_strftime($fmt, safe_strtotime($rng[0])); } return $out; }