if(class_exists('\Textpattern\Tag\Registry')) {
Txp::get('\Textpattern\Tag\Registry')
->register('soo_multidoc_link')
->register('soo_multidoc_pager')
->register('soo_multidoc_page_number')
->register('soo_multidoc_toc')
->register('soo_multidoc_page_title')
->register('soo_multidoc_breadcrumbs')
->register('soo_if_multidoc')
->register('soo_if_multidoc_linear')
->register('soo_if_multidoc_link')
;
}
require_plugin('soo_txp_obj');
@require_plugin('soo_plugin_pref'); if ( @txpinterface == 'admin' )
{
add_privs('plugin_prefs.soo_multidoc','1,2');
add_privs('plugin_lifecycle.soo_multidoc','1,2');
register_callback('soo_multidoc_prefs', 'plugin_prefs.soo_multidoc');
register_callback('soo_multidoc_prefs', 'plugin_lifecycle.soo_multidoc');
}
global $soo_multidoc;
$soo_multidoc = function_exists('soo_plugin_pref_vals') ?
array_merge(soo_multidoc_defaults(true), soo_plugin_pref_vals('soo_multidoc'))
: soo_multidoc_defaults(true);
$soo_multidoc = array_merge($soo_multidoc, array(
'init' => false,
'status' => false,
'id_parent' => '',
'data' => '',
));
function soo_multidoc_prefs( $event, $step )
{
if ( function_exists('soo_plugin_pref') )
return soo_plugin_pref($event, $step, soo_multidoc_defaults());
if ( substr($event, 0, 12) == 'plugin_prefs' ) {
$plugin = substr($event, 12);
$message = '<p><br /><strong>' . gTxt('edit') . " $plugin " .
gTxt('edit_preferences') . ':</strong><br />' . gTxt('install_plugin') .
' <a href="http://ipsedixit.net/txp/92/soo_plugin_pref">soo_plugin_pref</a></p>';
pagetop(gTxt('edit_preferences') . " › $plugin", $message);
}
}
function soo_multidoc_defaults( $vals_only = false )
{
$defaults = array(
'list_all' => array(
'val' => 0,
'html' => 'yesnoradio',
'text' => 'Show Multidoc sub-pages in article lists?',
),
'posted_time' => array(
'val' => 'past',
'html' => 'text_input',
'text' => 'Show articles posted ‘past’, ‘future’, or ‘any’',
),
);
if ( $vals_only )
foreach ( $defaults as $name => $arr )
$defaults[$name] = $arr['val'];
return $defaults;
}
define('SOO_MULTIDOC_PREFIX', 'soo_mdoc');
global $soo_multidoc_strings;
$soo_multidoc_strings = array(
'start' => 'start',
'up' => 'up',
'next' => 'next',
'prev' => 'prev',
);
register_callback('soo_multidoc_enumerate_strings', 'l10n.enumerate_strings');
function soo_multidoc_enumerate_strings( $event, $step = '', $pre = 0 )
{
global $soo_multidoc_strings;
$r = array(
'owner' => 'soo_multidoc',
'prefix' => SOO_MULTIDOC_PREFIX,
'lang' => 'en-us',
'event' => 'public',
'strings' => $soo_multidoc_strings,
);
return $r;
}
function soo_multidoc_gTxt( $what , $args = array() )
{
global $textarray;
global $soo_multidoc_strings;
$key = SOO_MULTIDOC_PREFIX . '-' . $what;
$key = strtolower($key);
if(isset($textarray[$key]))
$str = $textarray[$key];
else
{
$key = strtolower($what);
if( isset( $soo_multidoc_strings[$key] ) )
$str = $soo_multidoc_strings[$key];
else
$str = $what;
}
if( !empty($args) )
$str = strtr( $str , $args );
return $str;
}
class soo_multidoc_rowset extends soo_nested_set
{
public function has_subnode( $a, $b )
{
return ( $this->$b->lft > $this->$a->lft and $this->$b->rgt < $this->$a->rgt );
}
public function find_by_link_type( $link_type, $current = null, $dir = 'next' )
{
$rs = $this->rows;
if ( $dir == 'prev' )
$rs = array_reverse($rs, true);
$ids = array_keys($rs);
$link_type = strtolower($link_type);
if ( $current and in_array($current, $ids) )
{
$id_position = array_search($current, $ids);
if ( $dir == 'prev' )
$id_position++;
$searchable_ids = array_flip(array_slice($ids, $id_position));
$rs = array_intersect_key($rs, $searchable_ids);
}
foreach ( $rs as $k => $r )
if ( $r->link_type == $link_type )
return $k;
}
}
function soo_multidoc_link( $atts, $thing = null )
{
extract(lAtts(array(
'rel' => '',
'add_title' => '',
'text' => '{rel}',
'html_id' => '',
'class' => '',
'active_class' => '',
'wraptag' => '',
), $atts));
global $soo_multidoc;
if ( ! ( _soo_multidoc_init() and $soo_multidoc['status'] ) ) return false;
foreach ( array('start', 'up', 'next', 'prev') as $type )
$reserved_rel[$type] = $$type = strtolower(soo_multidoc_gTxt($type));
global $thisarticle;
$rowset = &$soo_multidoc['rowset'];
$thisid = $thisarticle['thisid'];
$rel = trim($rel);
if ( preg_match("/^($next|$prev)\s+(\w+)/i", $rel, $match) )
{
$rel_dir = strtolower($match[1]);
$rel_type = strtolower($match[2]);
$link_id = $rowset->find_by_link_type($rel_type, $thisid, $rel_dir);
if ( $rel_dir == 'prev' and $rowset->has_subnode($link_id, $thisid) )
{
$next_link = $rowset->find_by_link_type($rel_type, $link_id, $rel_dir);
if ( $next_link != $link_id and is_numeric($next_link) )
$link_id = $next_link;
else
unset($link_id);
}
}
elseif ( in_array($relcomp = strtolower($rel), $reserved_rel) )
{
if ( $relcomp == $start )
$link_id = $soo_multidoc['id_root'][$thisid];
elseif ( $relcomp == $up )
{
$link_id = $soo_multidoc['id_parent'][$thisid];
if ( ! intval($link_id) )
$link_id = 0;
}
else {
$next_array = $soo_multidoc['next_array'];
if ( $relcomp == $prev )
$next_array = array_reverse($next_array);
$i = array_search($thisid, $next_array);
$link_id = isset($next_array[$i + 1]) ? $next_array[$i + 1] : 0;
}
}
else
$link_id = $rowset->find_by_link_type($rel);
if ( ! empty($link_id) )
$url = $soo_multidoc['data'][$link_id]['url'];
if ( ! isset($url) ) return false;
if ( $add_title )
$thing .= $rowset->$link_id->title;
if ( ! $thing )
$thing = str_replace(array('{rel}', '{title}'), array($rel, $rowset->$link_id->title), $text);
if ( $link_id == $thisid )
$tag = new soo_html_span(array('class' => $active_class));
else
$tag = new soo_html_anchor(array('href' => $url, 'rel' => $rel));
$tag->contents(parse($thing));
if ( $wraptag and class_exists($tag_class = 'soo_html_' . $wraptag) )
{
$wraptag = new $tag_class;
return $wraptag->contents($tag)->class($class)->
id($html_id)->
tag();
}
else
{
$tag->id($html_id);
if ( $link_id != $thisid )
$tag->class($class);
return $tag->tag();
}
}
function soo_multidoc_pager( $atts )
{
extract(lAtts(array(
'limit' => 0,
'placeholder' => ' … ',
'html_id' => '',
'class' => '',
'active_class' => '',
'wraptag' => '',
'wrapclass' => '',
'break' => '',
'breakclass' => '',
), $atts));
global $soo_multidoc;
if ( ! ( _soo_multidoc_init() and $soo_multidoc['status'] ) ) return false;
global $thisarticle;
$thisid = $thisarticle['thisid'];
$wraptag = trim(strtolower($wraptag));
if ( $wraptag == 'table' )
$break = 'td';
elseif ( $wraptag == 'ul' or $wraptag == 'ol' )
$break = 'li';
if ( $break )
{
$break_obj = 'soo_html_' . trim(strtolower($break));
if ( ! class_exists($break_obj) )
$break_obj = null;
else {
$break = '';
$test_obj = new $break_obj;
$empty_break = $test_obj->is_empty;
}
}
else
$break_obj = null;
$page_ids = $soo_multidoc['next_array'];
$total = count($page_ids);
$page_nums = array_combine($page_ids, range(1, $total));
$this_num = $page_nums[$thisid];
$w_start = max(1,
min($this_num - $limit, $total - ( $limit * 2 ) + 1));
$w_end = min($w_start + ( $limit * 2 ) - 1, $total);
$show_nums = array_unique(array_merge(
array(1), range($w_start, $w_end), array($total)
));
$objs = array();
while ( $n = array_shift($show_nums) )
{
if ( $n == $this_num )
$objs[] = new soo_html_span(array('class' => $active_class), $n);
else
$objs[] = new soo_html_anchor(array(
'href' => $soo_multidoc['data'][$page_ids[$n - 1]]['url'],
'class' => $class), $n)
;
$fill = $show_nums ?
( $show_nums[0] > $n + 1 ? $placeholder : $break ) : '';
if ( $fill )
$objs[] = new soo_html_span('', $fill);
}
if ( $break_obj )
{
if ( $empty_break )
{
while ( $objs )
{
$broken_objs[] = array_shift($objs);
$broken_objs[] = new $break_obj;
}
array_pop($broken_objs);
$objs = $broken_objs;
}
else
foreach ( $objs as $i => $obj )
$objs[$i] = new $break_obj('', $obj);
foreach ( $objs as $obj )
if ( $obj instanceof $break_obj )
$obj->class($breakclass);
}
if ( $wraptag == 'table' )
$wrap_obj = new soo_html_tr;
else {
$wrap_obj_class = 'soo_html_' . $wraptag;
if ( class_exists($wrap_obj_class) )
$wrap_obj = new $wrap_obj_class;
}
if ( isset($wrap_obj) )
{
$wrap_obj->class($wrapclass);
foreach ( $objs as $obj )
$wrap_obj->contents($obj);
if ( $wraptag == 'table' )
{
$table = new soo_html_table(array('id' => $html_id),
new soo_html_tbody('', $wrap_obj));
return $table->tag();
}
else
return $wrap_obj->id($html_id)->tag();
}
else
{
$out = array();
foreach ( $objs as $obj )
$out[] = $obj->tag();
return implode("\n", $out);
}
}
function soo_multidoc_page_number( $atts )
{
extract(lAtts(array(
'html_id' => '',
'class' => '',
'wraptag' => 'span',
'format' => 'Page {page} of {total}',
), $atts));
global $soo_multidoc;
if ( ! ( _soo_multidoc_init() and $soo_multidoc['status'] ) ) return false;
global $thisarticle;
$thisid = $thisarticle['thisid'];
$page_ids = $soo_multidoc['next_array'];
$num_pages = count($page_ids);
$page_nums = array_flip($page_ids);
$this_page = $page_nums[$thisid] + 1;
$format = str_replace('{page}', $this_page, $format);
$format = str_replace('{total}', $num_pages, $format);
return doWrap(array($format), $wraptag, '', $class, '', '', '', $html_id);
}
function soo_multidoc_toc( $atts )
{
extract(lAtts(array(
'wraptag' => 'ul',
'root' => '',
'add_start' => false,
'html_id' => '',
'class' => '',
'active_class' => '',
), $atts));
global $soo_multidoc;
if ( ! ( _soo_multidoc_init() and $soo_multidoc['status'] ) ) return false;
global $thisarticle;
if ( $root )
{
$start_id = is_numeric($root) ? intval($root) : $thisarticle['thisid'];
$object_array = $soo_multidoc['rowset']->subtree($start_id, 'id')->as_object_array();
}
else
$object_array = $soo_multidoc['rowset']->as_object_array();
if ( ! $add_start )
$object_array = $object_array[1];
array_walk_recursive($object_array, '_soo_multidoc_toc_prep', array('id' => $thisarticle['thisid'], 'class' => $active_class));
$wraptag = trim(strtolower($wraptag));
if ( ! in_array($wraptag, array('ul', 'ol')) )
return false;
$wrap_obj_class = 'soo_html_' . $wraptag;
$out = new $wrap_obj_class(array(), $object_array);
return $out->class($class)->id($html_id)->tag();
}
function soo_multidoc_page_title( $atts )
{
extract(lAtts(array(
'separator' => ': ',
), $atts));
global $soo_multidoc, $sitename, $thisarticle;
if ( ! ( _soo_multidoc_init() and $soo_multidoc['status'] ) )
return page_title($atts);
$thisid = $thisarticle['thisid'];
$rs = &$soo_multidoc['rowset']->rows;
$root = $soo_multidoc['id_root'][$thisid];
return htmlspecialchars($sitename . $separator . $rs[$root]->title .
( $root != $thisid ? $separator . $rs[$thisid]->title : '' )
);
}
function soo_multidoc_breadcrumbs( $atts )
{
extract(lAtts(array(
'separator' => ': ',
), $atts));
global $soo_multidoc, $thisarticle;
if ( ! ( _soo_multidoc_init() and $soo_multidoc['status'] ) )
return;
$data = &$soo_multidoc['data'];
$this_id = $thisarticle['thisid'];
$crumbs[] = $data[$this_id]['title'];
while ( $this_id = $soo_multidoc['id_parent'][$this_id] and intval($this_id) )
{
$tag = new soo_html_anchor(array('href' => $data[$this_id]['url']),
escape_title($data[$this_id]['title']));
array_unshift($crumbs, $tag->tag());
}
return implode($separator, $crumbs);
}
function soo_if_multidoc( $atts, $thing )
{
extract(lAtts(array(
'start_id' => '',
), $atts));
global $soo_multidoc;
if ( ! ( _soo_multidoc_init() and $soo_multidoc['status'] ) )
return parse(EvalElse($thing, false));
global $thisarticle;
$thisid = $thisarticle['thisid'];
$start_ids = do_list($start_id);
$ok = ( ! $start_id or in_array($soo_multidoc['id_root'][$thisid], $start_ids) );
return parse(EvalElse($thing, $ok));
}
function soo_if_multidoc_linear( $atts, $thing )
{
global $soo_multidoc;
if ( ! ( _soo_multidoc_init() and $soo_multidoc['status'] ) )
return parse(EvalElse($thing, false));
$is_linear = count(array_unique($soo_multidoc['id_parent'])) == 2;
return parse(EvalElse($thing, $is_linear));
}
function soo_if_multidoc_link( $atts, $thing )
{
extract(lAtts(array(
'rel' => '',
'id' => '',
'link_type' => '',
), $atts));
$rel = strtolower($rel);
global $soo_multidoc;
if ( ! (
$rel && in_array($rel, array('up', 'next', 'prev')) &&
( $id || $link_type ) &&
_soo_multidoc_init() &&
$soo_multidoc['status']
) )
return parse(EvalElse($thing, false));
global $thisarticle;
$this_id = $thisarticle['thisid'];
switch ( $rel )
{
case 'up':
$link_id = $soo_multidoc['id_parent'][$this_id];
break;
case 'next':
$link_id = $soo_multidoc['data'][$this_id]['next'];
break;
case 'prev':
$pos = array_search($this_id, $soo_multidoc['next_array']);
$link_id = $pos ? $soo_multidoc['next_array'][$pos - 1] : 0;
}
if ( $id )
$match = $link_id == $id;
elseif ( is_numeric($link_id) )
$match = strcasecmp($link_type, $soo_multidoc['rowset']->$link_id->link_type) === 0;
else
$match = false;
return parse(EvalElse($thing, $match));
}
function _soo_multidoc_init()
{
global $soo_multidoc;
if ( $soo_multidoc['init'] ) return true;
$soo_multidoc['init'] = true;
global $is_article_list, $thisarticle;
if ( $is_article_list ) return false;
assert_article();
if ( empty($thisarticle) ) return false;
_soo_multidoc_ids_init($thisid = $thisarticle['thisid']);
if ( empty($soo_multidoc['id_parent'][$thisid]) ) return false;
return $soo_multidoc['status'] = true;
}
function _soo_multidoc_ids_init( $thisid = null, $force = false )
{
global $soo_multidoc;
if ( is_array($soo_multidoc['id_parent']) and ! $force )
return true;
$query = new soo_txp_left_join('soo_multidoc', 'textpattern', 'id', 'ID');
$query->select(array('id', 'root', 'lft', 'rgt', 'children', 'type as link_type'))
->select_join(array('ID', 'Title as title', 'url_title', 'Section', 'Posted'))
->order_by(array('root', 'lft'));
if ( @txpinterface != 'admin' )
$query->where_join('Status', 3, '>'); if ( ! get_pref('publish_expired_articles') )
$query->where_clause('(now() <= Expires OR Expires IS NULL)');
if ( $thisid )
{
$root_query = new soo_txp_select('soo_multidoc', array('id' => $thisid), 'root');
$query->in('root', $root_query);
}
switch ( $soo_multidoc['posted_time'] )
{
case 'past':
$query->where_clause('Posted <= now()');
break;
case 'future':
$query->where_clause('Posted > now()');
}
if ( ! $join_count = $query->count() )
return false;
$rs = new soo_multidoc_rowset($query);
$ids = $rs->field_vals('id');
$rs->rows = array_combine($ids, $rs->rows);
$id_parent = array();
$id_children = array();
foreach ( $rs->rows as $r )
{
if ( $r->link_type == 'start' )
$id_parent[$r->id] = 'Start';
if ( $r->children )
{
$id_children[$r->id] = do_list($r->children);
foreach ( $id_children[$r->id] as $child )
$id_parent[$child] = $r->id;
}
else
$id_children[$r->id] = array();
}
$soo_multidoc['id_parent'] = $id_parent; $soo_multidoc['id_children'] = $id_children; $soo_multidoc['id_root'] = $rs->field_vals('root', 'id'); $soo_multidoc['id_link_type'] = $rs->field_vals('link_type', 'id'); $soo_multidoc['rowset'] = $rs;
if ( $thisid and array_key_exists($thisid, $id_parent) )
{
$next = $soo_multidoc['rowset']->field_vals('id');
$soo_multidoc['next_array'] = $next;
array_shift($next);
$soo_multidoc['data'] = [];
foreach ( $soo_multidoc['rowset']->rows as $id => $r )
$soo_multidoc['data'][$id] = array_merge($r->data, array(
'parent' => $id_parent[$id],
'url' => permlinkurl($r->data),
'next' => array_shift($next),
));
}
return true;
}
function _soo_multidoc_toc_prep ( &$row, $k, $active )
{
global $soo_multidoc;
if ( $row->id == $active['id'] )
$row = new soo_html_span(array('class' => $active['class']), $row->title);
else
$row = new soo_html_anchor(array('href' => $soo_multidoc['data'][$row->id]['url']), $row->title);
}
function _soo_multidoc_temp_table ( )
{
global $pretext, $is_article_list, $soo_multidoc;
if ( ! $is_article_list or
$pretext['q'] or
! empty($soo_multidoc['list_all']) or
! getRow("show tables like 'soo_multidoc'") or
! _soo_multidoc_ids_init()
)
return;
$t1 = safe_pfx('textpattern');
$t2 = safe_pfx('soo_multidoc');
safe_query(
"create temporary table $t1 select * from $t1 where ID not in (select id from $t2 where id != root)");
}
register_callback('_soo_multidoc_temp_table', 'pretext_end');