// Public interfaces: convenience functions
function smd_prev($atts, $thing) {
$atts['dir'] = 'prev';
return smd_nearest($atts, $thing);
}
function smd_next($atts, $thing) {
$atts['dir'] = 'next';
return smd_nearest($atts, $thing);
}
function smd_link_to_prev($atts, $thing) {
$atts['dir'] = 'prev';
return smd_link_to($atts, $thing);
}
function smd_link_to_next($atts, $thing) {
$atts['dir'] = 'next';
return smd_link_to($atts, $thing);
}
function smd_if_start($atts, $thing) {
$atts['dir'] = 'prev';
return smd_if_horizon($atts, $thing);
}
function smd_if_end($atts, $thing) {
$atts['dir'] = 'next';
return smd_if_horizon($atts, $thing);
}
// ****************************
// Private function: not for public consumption
// ****************************
function smd_if_horizon($atts, $thing) {
global $pretext, $thisarticle, $thiscategory, $smd_last, $smd_first, $smd_in_nearest;
extract(lAtts(array(
'type' => 'list',
'logic' => 'or',
'dir' => 'next',
'debug' => 0,
), $atts));
$itout = array(); // For debug only
$type = do_list($type);
$out = array();
foreach ($type as $item) {
if ($debug) {
$itout[] = $item;
}
switch ($item) {
case 'list':
if ($smd_in_nearest) {
if ($dir == 'next') {
$out[] = (empty($smd_last)) ? true : false;
} else {
$out[] = (empty($smd_first)) ? true : false;
}
}
break;
case 'category':
if ($smd_in_nearest) {
if ($dir == 'next') {
$out[] = (!empty($smd_last) && ($smd_last['category1'] != $thisarticle['category1'] || $smd_last['category2'] != $thisarticle['category2'])) ? true : false;
} else {
$out[] = (!empty($smd_first) && ($smd_first['category1'] != $thisarticle['category1'] || $smd_first['category2'] != $thisarticle['category2'])) ? true : false;
}
} else {
if ($dir == 'next') {
$out[] = (!empty($thiscategory['is_last'])) ? true : false;
} else {
$out[] = (!empty($thiscategory['is_first'])) ? true : false;
}
}
break;
case 'author':
if ($smd_in_nearest) {
if ($dir == 'next') {
$out[] = (!empty($smd_last) && $smd_last['author'] != $thisarticle['authorid']) ? true : false;
} else {
$out[] = (!empty($smd_first) && $smd_first['author'] != $thisarticle['authorid']) ? true : false;
}
} else {
// Not possible since author lists are not permitted in TXP
}
break;
case 'cat1':
case 'category1':
if ($smd_in_nearest) {
if ($dir == 'next') {
$out[] = (!empty($smd_last) && $smd_last['category1'] != $thisarticle['category1']) ? true : false;
} else {
$out[] = (!empty($smd_first) && $smd_first['category1'] != $thisarticle['category1']) ? true : false;
}
} else {
if ($dir == 'next') {
$out[] = (!empty($thiscategory['is_last'])) ? true : false;
} else {
$out[] = (!empty($thiscategory['is_first'])) ? true : false;
}
}
break;
case 'cat2':
case 'category2':
if ($smd_in_nearest) {
if ($dir == 'next') {
$out[] = (!empty($smd_last) && $smd_last['category2'] != $thisarticle['category2']) ? true : false;
} else {
$out[] = (!empty($smd_first) && $smd_first['category2'] != $thisarticle['category2']) ? true : false;
}
} else {
if ($dir == 'next') {
$out[] = (!empty($thiscategory['is_last'])) ? true : false;
} else {
$out[] = (!empty($thiscategory['is_first'])) ? true : false;
}
}
break;
case 'section':
default:
if ($smd_in_nearest) {
if ($dir == 'next') {
$out[] = (!empty($smd_last) && $smd_last['section'] != $thisarticle['section']) ? true : false;
} else {
$out[] = (!empty($smd_first) && $smd_first['section'] != $thisarticle['section']) ? true : false;
}
} else {
if ($dir == 'next') {
$out[] = empty($pretext['next_id']) ? true : false;
} else {
$out[] = empty($pretext['prev_id']) ? true : false;
}
}
break;
}
}
if ($debug) {
echo '++ TEST RESULTS ++';
dmp($itout);
dmp($out);
}
$res = ($out) ? true : false;
if (strtolower($logic) == "and" && in_array(false, $out)) {
$res = false;
}
if (strtolower($logic) == "or" && !in_array(true, $out)) {
$res = false;
}
if ($debug) {
echo '++ FINAL RESULT ++';
dmp($res);
}
return parse(EvalElse($thing, $res));
}
// ****************************
// Private function: not for public consumption
// ****************************
function smd_nearest($atts, $thing) {
global $pretext, $thisarticle, $thiscategory, $prefs, $next_id, $prev_id, $next_title, $prev_title, $smd_last, $smd_first, $smd_in_nearest;
extract(lAtts(array(
'section' => $pretext['s'],
'category' => $pretext['c'],
'author' => $pretext['author'],
'realname' => '',
'status' => '4',
'time' => 'any', // any, future, past
'datasort' => 'section, category1, category2, author',
'timesort' => 'posted',
'form' => '',
'dir' => 'next', // Set by wrapper tags
'debug' => 0,
), $atts));
extract($prefs);
$smd_in_nearest = true;
$thing = (empty($form)) ? $thing : fetch_form($form);
$expired = ($publish_expired_articles) ? '' : ' AND (now() <= Expires or Expires = '.NULLDATETIME.')';
$safe_name = safe_pfx('textpattern');
// Filters
$catSQL = $secSQL = $authSQL = '';
if($category) {
$catSQL = doQuote(join("','", doSlash(do_list($category))));
$catSQL = ' AND ( Category1 IN ('.$catSQL.') OR Category2 IN ('.$catSQL.') ) ';
}
if($section) {
$secSQL = ' AND Section IN ('.doQuote(join("','", doSlash(do_list($section)))).') ';
}
if($realname) {
$author = join(',', safe_column('name', 'txp_users', 'RealName IN ('. doQuote(join("','", doSlash(doArray(do_list($realname), 'urldecode')))) .')' ));
}
if($author) {
$authSQL = ' AND AuthorID IN ('.doQuote(join("','", doSlash(do_list($author)))).') ';
}
$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);
}
}
$statSQL = 'Status IN ('.join(',', $stati).')';
$timeSQL = '';
switch($time) {
case "any" : break;
case "future" : $timeSQL = " AND Posted > now()"; break;
default : $timeSQL = " AND Posted < now()"; break; // The past
}
// Sort
$sorder = (($dir=='next') ? ' DESC' : ' ASC'); // Negative logic to avoid lookahead: the "last" row seen is always the one required
$orderby = array();
if ($datasort) {
$datasort = do_list($datasort);
foreach ($datasort as $item) {
switch($item) {
case 'section':
if ($section) {
$orderby[] = 'Section'.$sorder;
}
break;
case 'category':
if ($category) {
$orderby[] = 'Category1'.$sorder;
$orderby[] = 'Category2'.$sorder;
}
break;
case 'category1':
if ($category) {
$orderby[] = 'Category1'.$sorder;
}
break;
case 'category2':
if ($category) {
$orderby[] = 'Category2'.$sorder;
}
break;
case 'author':
if ($author) {
$orderby[] = 'AuthorID'.$sorder;
}
break;
}
}
}
if ($timesort) {
$timesort = do_list($timesort);
foreach ($timesort as $item) {
switch(strtolower($item)) {
case 'lastmod':
$orderby[] = 'LastMod'.$sorder;
break;
case 'expires':
$orderby[] = 'Expires'.$sorder;
break;
case 'posted':
default:
$orderby[] = 'Posted'.$sorder;
break;
}
}
}
$orderby = ' ORDER BY ' . join(',', $orderby);
// Do it
assert_article();
$rs = safe_rows('*, unix_timestamp(Posted) as uPosted, unix_timestamp(Expires) as uExpires, unix_timestamp(LastMod) as uLastMod',
'textpattern',
$statSQL.
(($category) ? $catSQL : '').
(($section) ? $secSQL : '').
(($author) ? $authSQL : '').
$timeSQL.
$expired.
$orderby,
$debug);
if ($debug > 1 && $rs) {
echo '++ RECORD SET ++';
dmp($rs);
}
// Find the current article in the record set, then move to find next/prev
$last = $curr = $ctr = 1;
foreach ($rs as $row) {
if ($row['ID'] == $thisarticle['thisid']) {
$curr = $last;
break;
}
$last = $row; // Store current
$ctr++;
}
if ($curr !== 1) {
if ($dir=='next') {
$smd_last['position'] = $ctr;
$smd_last['section'] = $thisarticle['section'];
$smd_last['psec'] = $pretext['s'];
$smd_last['pcat'] = $pretext['c'];
$smd_last['category1'] = $thisarticle['category1'];
$smd_last['category2'] = $thisarticle['category2'];
$smd_last['author'] = $thisarticle['authorid'];
} else {
$smd_first['position'] = $ctr;
$smd_first['psec'] = $pretext['s'];
$smd_first['pcat'] = $pretext['c'];
$smd_first['section'] = $thisarticle['section'];
$smd_first['category1'] = $thisarticle['category1'];
$smd_first['category2'] = $thisarticle['category2'];
$smd_first['author'] = $thisarticle['authorid'];
}
} else {
if ($dir=='next') {
$smd_last = array();
} else {
$smd_first = array();
}
}
if ($debug) {
if ($dir=='next') {
echo '++ MOST RECENT (NEXT) ++';
dmp($smd_last);
} else {
echo '++ MOST RECENT (PREV) ++';
dmp($smd_first);
}
}
// Populate globals if the next/prev article exists
$out = '';
$saved = array();
if ($curr === 1) {
$out = parse($thing);
} else {
// Keep a note of where we were
article_push();
$saved['prev_id'] = $prev_id;
$saved['next_id'] = $next_id;
$saved['prev_title'] = $prev_title;
$saved['next_title'] = $next_title;
// Pretend we're in the new article, and fake the global vars
populateArticleData($curr);
$prev_id = ($dir=='prev') ? $curr['ID'] : '';
$next_id = ($dir=='next') ? $curr['ID'] : '';
$prev_title = ($dir=='prev') ? $curr['Title'] : '';
$next_title = ($dir=='next') ? $curr['Title'] : '';
$url = permlinkurl_id($curr['ID']);
$thing = (empty($thing)) ? ''.$curr['Title'].'' : $thing;
$out = parse($thing);
// Restore everything
$prev_id = $saved['prev_id'];
$next_id = $saved['next_id'];
$prev_title = $saved['prev_title'];
$next_title = $saved['next_title'];
article_pop();
}
$smd_in_nearest = false;
return $out;
}
// ****************************
// Private function: not for public consumption
// ****************************
function smd_link_to($atts, $thing = NULL) {
global $next_id, $prev_id, $next_title, $prev_title, $smd_last, $smd_first, $smd_in_nearest;
extract(lAtts(array(
'showalways' => 0,
'wraptag' => '',
'class' => '',
'urlvars' => '',
'dir' => 'next', // Set by wrapper tags
'debug' => '0',
), $atts));
// Maintain any URL variables
$addArgs = array();
if($urlvars) {
$optencode = $optforce = $optpri = false;
if (strpos($urlvars, 'SMD_ALL') === 0) {
// Determine if options are to be applied globally
$urlopts = do_list($urlvars, ':');
$optencode = (in_array('ESCAPE', $urlopts)) ? true : false;
$optforce = (in_array('FORCE', $urlopts)) ? true : false;
$optpri = (in_array('TAG_PRIORITY', $urlopts)) ? true : false;
// POST overrides GET if both exist
$urlvars = array_merge(array_keys($_GET), array_keys($_POST));
} else {
$urlvars = do_list($urlvars);
}
foreach ($urlvars as $urlvar) {
$urlopts = do_list($urlvar, ':');
$encode = ($optencode || in_array('ESCAPE', $urlopts)) ? true : false;
$force = ($optforce || in_array('FORCE', $urlopts)) ? true : false;
$pri = ($optpri || in_array('TAG_PRIORITY', $urlopts)) ? true : false;
$urlparts = do_list($urlopts[0], '=');
$var = $urlparts[0];
$val = gps($urlparts[0]);
if ($pri) {
$val = (isset($urlparts[1])) ? $urlparts[1] : gps($urlparts[0]);
} else {
if ($val=='' && isset($urlparts[1])) {
$val = $urlparts[1];
}
}
$val = ($encode) ? htmlentities($val) : $val;
if ($val !== '' || $force) {
$addArgs[] = $var.'='.$val;
}
}
}
if ($debug && $addArgs) {
echo '++ URL VARS ++';
dmp($addArgs);
}
if ($dir=='next' && (($smd_in_nearest) ? $smd_last : 1)) {
if ($next_id) {
$url = permlinkurl_id($next_id) . (($addArgs) ? '?'. join(a, $addArgs) : '');
if ($thing) {
$thing = parse($thing);
$next_title = escape_title($next_title);
return doWrap(array(''.$thing.''), $wraptag, '', $class);
}
return $url;
} else {
return ($showalways) ? parse($thing) : '';
}
}
if ($dir=='prev' && (($smd_in_nearest) ? $smd_first : 1)) {
if ($prev_id) {
$url = permlinkurl_id($prev_id) . (($addArgs) ? '?'. join(a, $addArgs) : '');
if ($thing) {
$thing = parse($thing);
$prev_title = escape_title($prev_title);
return doWrap(array(''.$thing.''), $wraptag, '', $class);
}
return $url;
} else {
return ($showalways) ? parse($thing) : '';
}
}
return;
}