Multidoc Page 12 of 26

soo_multidoc Source code

   1 : require_plugin('soo_txp_obj');
   2 : @require_plugin('soo_plugin_pref');     // optional
   3 : 
   4 :   //---------------------------------------------------------------------//
   5 :  //                                 Globals                             //
   6 : //---------------------------------------------------------------------//
   7 : 
   8 : global $soo_multidoc;
   9 : 
  10 : $soo_multidoc = array(
  11 :     'custom_field'      =>  '',
  12 :     'init'              =>  false,
  13 :     'status'            =>  false,
  14 :     'collection'        =>  '',
  15 :     'noindex'           =>  '',
  16 :     'id_parent'         =>  '',
  17 :     'data'              =>  '',
  18 : );
  19 : 
  20 : $soo_multidoc_prefs function_exists('soo_plugin_pref_vals') ?
  21 :     soo_plugin_pref_vals('soo_multidoc') : soo_multidoc_defaults();
  22 : foreach ( $soo_multidoc_prefs as $name => $val )
  23 :     $soo_multidoc[$name] = is_array($val) ? $val['val'] : $val;
  24 : 
  25 : add_privs('plugin_prefs.soo_multidoc','1,2');
  26 : add_privs('plugin_lifecycle.soo_multidoc','1,2');
  27 : register_callback('soo_multidoc_prefs''plugin_prefs.soo_multidoc');
  28 : register_callback('soo_multidoc_prefs''plugin_lifecycle.soo_multidoc');
  29 : 
  30 : function soo_multidoc_prefs$event$step ) {
  31 :     if ( function_exists('soo_plugin_pref') )
  32 :         return soo_plugin_pref($event$stepsoo_multidoc_defaults());
  33 :     if ( substr($event012) == 'plugin_prefs' ) {
  34 :         $plugin substr($event12);
  35 :         $message '<p><br /><strong>' gTxt('edit') . " $plugin " .
  36 :             gTxt('edit_preferences') . ':</strong><br />' gTxt('install_plugin') .
  37 :             ' <a href="http://ipsedixit.net/txp/92/soo_plugin_pref">soo_plugin_pref</a></p>';
  38 :         pagetop(gTxt('edit_preferences') . " &#8250; $plugin"$message);
  39 :     }
  40 : }
  41 : 
  42 : function soo_multidoc_defaults( ) {
  43 :     return array(
  44 :         'custom_field_name'     =>  array(
  45 :             'val'   =>  'Multidoc',
  46 :             'html'  =>  'text_input',
  47 :             'text'  =>  'Custom field name',
  48 :         ),
  49 :         'dev_domain'    =>  array(
  50 :             'val'   =>  '',
  51 :             'html'  =>  'text_input',
  52 :             'text'  =>  'Development domain (no http:// or closing slash)',
  53 :         ),
  54 :         'list_all'  =>  array(
  55 :             'val'   =>  0,
  56 :             'html'  =>  'yesnoradio',
  57 :             'text'  =>  'Show Multidoc sub-pages in article lists?',
  58 :         ),
  59 :         'posted_time'   =>  array(
  60 :             'val'   =>  'past',
  61 :             'html'  =>  'text_input',
  62 :             'text'  =>  'Show articles posted &lsquo;past&rsquo;, &lsquo;future&rsquo;, or &lsquo;any&rsquo;',
  63 :         ),
  64 :     );
  65 : }
  66 : 
  67 :   //---------------------------------------------------------------------//
  68 :  //                         MLP Pack definitions                        //
  69 : //---------------------------------------------------------------------//
  70 : 
  71 : define('SOO_MULTIDOC_PREFIX''soo_mdoc');
  72 : global $soo_multidoc_strings;
  73 : $soo_multidoc_strings = array(
  74 :     'start'             =>  'start',
  75 :     'up'                =>  'up',
  76 :     'next'              =>  'next',
  77 :     'prev'              =>  'prev',
  78 :     'recursion_error'   =>  'Recursion warning: initialization aborted',
  79 :     'custom_field'      =>  'Custom field "',
  80 :     'not_found'         =>  '" not found',
  81 :     'multiple_listings' =>  'Multiple listings for at least one article. Start by checking articles ',
  82 :     'invalid_id_1'      =>  'Invalid ID detected: Article ',
  83 :     'invalid_id_2'      =>  ' has a Multidoc listing for article ',
  84 : );
  85 : 
  86 : register_callback('soo_multidoc_enumerate_strings''l10n.enumerate_strings');
  87 : 
  88 : function soo_multidoc_enumerate_strings$event$step ''$pre ) {
  89 :     global $soo_multidoc_strings;
  90 :     $r = array(
  91 :         'owner'     => 'soo_multidoc',
  92 :         'prefix'    => SOO_MULTIDOC_PREFIX,
  93 :         'lang'      => 'en-us',
  94 :         'event'     => 'public',
  95 :         'strings'   => $soo_multidoc_strings,
  96 :                 );
  97 :     return $r;
  98 : }
  99 : 
 100 : function soo_multidoc_gTxt$what $args = array() ) {
 101 :     global $textarray;
 102 :     global $soo_multidoc_strings;
 103 : 
 104 :     $key SOO_MULTIDOC_PREFIX '-' $what;
 105 :     $key strtolower($key);
 106 : 
 107 :     if(isset($textarray[$key]))
 108 :         $str $textarray[$key];
 109 : 
 110 :     else {
 111 :         $key strtolower($what);
 112 : 
 113 :         if( isset( $soo_multidoc_strings[$key] ) )
 114 :             $str $soo_multidoc_strings[$key];
 115 :         else
 116 :             $str $what;
 117 :     }
 118 : 
 119 :     if( !empty($args) )
 120 :         $str strtr$str $args );
 121 : 
 122 :     return $str;
 123 : }
 124 : 
 125 : 
 126 :   //---------------------------------------------------------------------//
 127 :  //                                 Classes                             //
 128 : //---------------------------------------------------------------------//
 129 : 
 130 : 
 131 : class soo_multidoc_node extends soo_obj {
 132 : 
 133 :     protected $id               '';
 134 :     protected $link_type        '';
 135 :     protected $title            '';
 136 :     protected $children         '';
 137 :     protected $next             '';
 138 :     protected $prev             '';
 139 :     protected $up               '';
 140 : 
 141 : 
 142 :     public function __construct$id ) {
 143 :         $this->id is_numeric($id) ? intval($id) : '';
 144 :     }
 145 : 
 146 :     // Getters /////////////////////////////////////
 147 :     // if $id argument given, will search child nodes
 148 : 
 149 :     public function get_link_type$id null ) {
 150 :         return $this->get_sub_node_prop($id'link_type');
 151 :     }
 152 : 
 153 :     public function get_next$id null ) {
 154 :         return $this->get_sub_node_prop($id'next');
 155 :     }
 156 : 
 157 :     public function get_prev$id null ) {
 158 :         return $this->get_sub_node_prop($id'prev');
 159 :     }
 160 : 
 161 :     public function get_up$id null ) {
 162 :         return $this->get_sub_node_prop($id'up');
 163 :     }
 164 : 
 165 :     // Utilities /////////////////////////////////////
 166 : 
 167 :     public function set_next_by_id$id$next ) {
 168 : 
 169 :         static $_soo_multidoc_failsafe;
 170 :         $_soo_multidoc_failsafe ++;
 171 :         if ( $_soo_multidoc_failsafe 999 )
 172 :             return soo_multidoc_gTxt('recursion_error');
 173 : 
 174 :         if ( $id == $this->id ) {
 175 :             $this->next $next;
 176 :             return $this->prev;
 177 :         }
 178 : 
 179 :         if ( ! is_array($this->children) )
 180 :             return false;
 181 : 
 182 :         foreach ( $this->children as $child ) {
 183 :             $done $child->set_next_by_id($id$next);
 184 :             if ( $done ) return $done;
 185 :         }
 186 :         return false;
 187 :     }
 188 : 
 189 :     public function youngest() {
 190 :     // return the id of this node's youngest descendant
 191 : 
 192 :         if ( is_array($this->children) ) {
 193 :             $my_children $this->children;
 194 :             $my_youngest array_pop($my_children);
 195 :             return $my_youngest->youngest();
 196 :         }
 197 :         else
 198 :             return $this->id;
 199 :     }
 200 : 
 201 :     public function are_you_my_ancestor$me$you ) {
 202 : 
 203 :         $my_parent $this->get_up($me);
 204 :         if (  $my_parent == $you ) return true;
 205 :         if ( $my_parent )
 206 :             return $this->are_you_my_ancestor($my_parent$you);
 207 :     }
 208 : 
 209 :     public function get_id_by_link_type$link_type ) {
 210 : 
 211 :         if ( strtolower($link_type) == $this->link_type )
 212 :             return $this->id;
 213 : 
 214 :         if ( is_array($this->children ) ) {
 215 :             foreach ( $this->children as $child ) {
 216 :                 if ( empty($out) )
 217 :                     $out $child->get_id_by_link_type($link_type);
 218 :             }
 219 :         }
 220 :         return isset($out) ? $out false;
 221 :     }
 222 : 
 223 :     public function get_next_by_link_type$id$link_type ) {
 224 : 
 225 :         $next $this->get_next($id);
 226 :         if ( $next )
 227 :             return strtolower($this->get_link_type($next)) == $link_type ?
 228 :                 $next $this->get_next_by_link_type($next$link_type);
 229 :     }
 230 : 
 231 :     public function get_prev_by_link_type$id$link_type ) {
 232 : 
 233 :         $prev $this->get_prev($id);
 234 :         if ( $prev )
 235 :             return strtolower($this->get_link_type($prev)) == $link_type ?
 236 :                 $prev $this->get_prev_by_link_type($prev$link_type);
 237 :     }
 238 : 
 239 :     public function get_sub_node$id ) {
 240 : 
 241 :         if ( $this->id == $id or is_null($id) )
 242 :             return $this;
 243 : 
 244 :         if ( is_array($this->children) )
 245 :             foreach ( $this->children as $child )
 246 :                 if ( empty($out) )
 247 :                     $out $child->get_sub_node($id);
 248 : 
 249 :         return isset($out) ? $out false;
 250 :     }
 251 : 
 252 :     public function get_sub_node_prop$id$prop ) {
 253 :         $node = &$this->get_sub_node($id);
 254 :         return $node->$prop;
 255 :     }
 256 : 
 257 :     public function next_array() {
 258 : 
 259 :         static $next_array_out;
 260 :         global $soo_multidoc;
 261 : 
 262 :         if ( isset($soo_multidoc['next_array']) )
 263 :             return $soo_multidoc['next_array'];
 264 : 
 265 :         $next_id $this->get_next();
 266 : 
 267 :         if ( $next_id ) {
 268 :             $next_array_out[] = $next_id;
 269 :             $next_node $soo_multidoc['collection']->get_sub_node($next_id);
 270 :             $next_node->next_array();
 271 :         }
 272 :         $soo_multidoc['next_array'] = $next_array_out;
 273 :         return $next_array_out;
 274 :     }
 275 : 
 276 : 
 277 :     function toc$type$current_page$active_class$include_self ) {
 278 :     // returns table of contents for this node, as a list object
 279 : 
 280 :         global $soo_multidoc;
 281 : 
 282 :         if ( is_array($this->children) ) {
 283 : 
 284 :             if ( $type == 'ul' )
 285 :                 $out = new soo_html_ul;
 286 :             elseif ( $type == 'ol' )
 287 :                 $out = new soo_html_ol;
 288 :             else
 289 :                 return false;
 290 : 
 291 :             if ( $include_self )
 292 :                 $out->contents(
 293 :                     new soo_html_li('',
 294 :                         new soo_html_anchor(
 295 :                             $soo_multidoc['data'][$this->id]['url'], $this->title)
 296 :                 ));
 297 :             $include_self false;
 298 : 
 299 :             foreach ( $this->children as $child ) {
 300 :                 if ( is_array($child->children) ) {
 301 :                     if ( $child->id == $current_page )
 302 :                         $item = new soo_html_span(
 303 :                             array('class' => $active_class)
 304 :                         );
 305 :                     else
 306 :                         $item = new soo_html_anchor(
 307 :                             $soo_multidoc['data'][$child->id]['url']
 308 :                         );
 309 :                     $item->contents($child->title);
 310 :                 }
 311 :                 $li = new soo_html_li('', isset($item) ? $item null);
 312 :                 $li->contents($child->toc($type$current_page$active_classfalse));
 313 :                 $out->contents($li);
 314 :                 unset($item);
 315 :                 unset($li);
 316 :             }
 317 :         }
 318 :         else {
 319 :             if ( $this->id == $current_page )
 320 :                 $out = new soo_html_span(array('class' => $active_class));
 321 :             else
 322 :                 $out = new soo_html_anchor(
 323 :                     $soo_multidoc['data'][$this->id]['url']
 324 :                 );
 325 :             $out->contents($this->title);
 326 :         }
 327 :         return isset($out) ? $out false;
 328 :     }
 329 : 
 330 : }
 331 : 
 332 : ///////////////////// end of class soo_multidoc_node ///////////////////////
 333 : 
 334 :   //---------------------------------------------------------------------//
 335 :  //                                 Tags                                //
 336 : //---------------------------------------------------------------------//
 337 : 
 338 : function soo_multidoc_link$atts$thing null ) {
 339 : // Output tag: display an HTML anchor
 340 : // Requires article context
 341 : 
 342 :     extract(lAtts(array(
 343 :         'rel'           =>  '',
 344 :         'add_title'     =>  '',
 345 :         'html_id'       =>  '',
 346 :         'class'         =>  '',
 347 :         'active_class'  =>  '',
 348 :         'wraptag'       =>  '',
 349 :     ), $atts));
 350 : 
 351 :     global $soo_multidoc;
 352 :     if ( ! ( _soo_multidoc_init() and $soo_multidoc['status'] ) ) return false;
 353 : 
 354 :     $start soo_multidoc_gTxt('start');
 355 :     $up soo_multidoc_gTxt('up');
 356 :     $next soo_multidoc_gTxt('next');
 357 :     $prev soo_multidoc_gTxt('prev');
 358 : 
 359 :     global $thisarticle;
 360 :     $collection $soo_multidoc['collection'];
 361 :     $thisid $thisarticle['thisid'];
 362 :     $rel trim($rel);
 363 : 
 364 :     // $rel value may be space-separated list of link types
 365 :     // this tag allows only 'prev' or 'next' in combination with another type
 366 :     if ( preg_match("/^($next|$prev)\s+(\w+)/i"$rel$match) ) {
 367 :         $rel_dir strtolower($match[1]);
 368 :         $rel_type strtolower($match[2]);
 369 : 
 370 :         if ( $rel_dir == 'next' )
 371 :             $link_id $collection->get_next_by_link_type($thisid$rel_type);
 372 : 
 373 :         // if I have an ancestor of the requested link type, that ancestor will
 374 :         // be the prev link of that type, which isn't what the user wants.
 375 :         // So continue back one more step.
 376 :         elseif ( $rel_dir == 'prev' ) {
 377 :             $link_id $collection->get_prev_by_link_type($thisid$rel_type);
 378 :             if ( $collection->are_you_my_ancestor($thisid$link_id) ) {
 379 :                 $next_link $collection->get_prev_by_link_type($link_id$rel_type);
 380 :                 if ( $next_link != $link_id and is_numeric($next_link) )
 381 :                     $link_id $next_link;
 382 :                 else
 383 :                     unset($link_id);
 384 :             }
 385 :         }
 386 :     }
 387 :     elseif (preg_match("/^($next|$prev|$up|$start)$/i"$rel$match) ) {
 388 : 
 389 :         switch ( strtolower($match[0]) ) {
 390 :             case $start:
 391 :                 $link_id $collection->id;
 392 :                 break;
 393 :             case $prev:
 394 :                 $link_id $collection->get_prev($thisid);
 395 :                 break;
 396 :             case $next:
 397 :                 $link_id $collection->get_next($thisid);
 398 :                 break;
 399 :             case $up:
 400 :                 $link_id $collection->get_up($thisid);
 401 :                 break;
 402 :         }
 403 :     }
 404 :     else
 405 :         $link_id $collection->get_id_by_link_type($rel);
 406 : 
 407 :     if ( ! empty($link_id) )
 408 :         $url $soo_multidoc['data'][$link_id]['url'];
 409 : 
 410 :     if ( ! isset($url) ) return false;
 411 : 
 412 :     if ( $add_title )
 413 :         $thing .= $collection->get_sub_node_prop($link_id'title');
 414 : 
 415 :     if ( $link_id == $thisid )
 416 :         $tag = new soo_html_span(array('class' => $active_class));
 417 : 
 418 :     else
 419 :         $tag = new soo_html_anchor(array('href' => $url'rel' => $rel));
 420 : 
 421 :     $tag->contents$thing $thing $rel );
 422 : 
 423 :     if ( $wraptag ) {
 424 :         $tag_class 'soo_html_' $wraptag;
 425 :         if ( class_exists($tag_class) ) {
 426 :             $wraptag = new $tag_class;
 427 :             return $wraptag->contents($tag)->class($class)->
 428 :                 id($html_id)->
 429 :                 tag();
 430 :         }
 431 :     }
 432 : 
 433 :     else {
 434 :         $tag->id($html_id);
 435 :         if ( $link_id != $thisid )
 436 :             $tag->class($class);
 437 :         return $tag->tag();
 438 :     }
 439 : }
 440 : ///////////////////// end of soo_multidoc_link() ///////////////////////
 441 : 
 442 : function soo_multidoc_pager$atts ) {
 443 : // Output tag: display a simple list of page links
 444 : // Requires article context
 445 : 
 446 :     extract(lAtts(array(
 447 :         'limit'         =>  0,
 448 :         'placeholder'   =>  ' &hellip; ',
 449 :         'html_id'       =>  '',
 450 :         'class'         =>  '',
 451 :         'active_class'  =>  '',
 452 :         'wraptag'       =>  '',
 453 :         'wrapclass'     =>  '',
 454 :         'break'         =>  '',
 455 :         'breakclass'    =>  '',
 456 :     ), $atts));
 457 : 
 458 :     global $soo_multidoc;
 459 :     if ( ! ( _soo_multidoc_init() and $soo_multidoc['status'] ) ) return false;
 460 : 
 461 :     global $thisarticle;
 462 :     $collection $soo_multidoc['collection'];
 463 :     $thisid $thisarticle['thisid'];
 464 : 
 465 :     $wraptag trim(strtolower($wraptag));
 466 :     if ( $wraptag == 'table' )
 467 :         $break 'td';
 468 :     elseif ( $wraptag == 'ul' or $wraptag == 'ol' )
 469 :         $break 'li';
 470 : 
 471 :     if ( $break ) {
 472 :         $break_obj 'soo_html_' trim(strtolower($break));
 473 :         if ( ! class_exists($break_obj) )
 474 :             $break_obj null;
 475 :         else {
 476 :             $break '';
 477 :             $test_obj = new $break_obj;
 478 :             $empty_break $test_obj->is_empty;
 479 :         }
 480 :     }
 481 :     else
 482 :         $break_obj null;
 483 : 
 484 :     $page_ids $collection->next_array();
 485 :     array_unshift($page_ids$collection->id);
 486 : 
 487 :     $total count($page_ids);
 488 :     $page_nums array_combine($page_idsrange(1$total));
 489 :     $this_num $page_nums[$thisid];
 490 : 
 491 :     $w_start max(1,
 492 :         min($this_num $limit$total - ( $limit ) + 1));
 493 :     $w_end min($w_start + ( $limit ) - 1$total);
 494 : 
 495 :     $show_nums array_unique(array_merge(
 496 :         array(1), range($w_start$w_end), array($total)
 497 :     ));
 498 : 
 499 :     $objs = array();
 500 : 
 501 :     while ( $show_nums ) {
 502 :         $n array_shift($show_nums);
 503 :         if ( $n == $this_num )
 504 :             $objs[] = new soo_html_span(array('class' => $active_class), $n);
 505 :         else
 506 :             $objs[] = new soo_html_anchor(array(
 507 :                 'href' => $soo_multidoc['data'][$page_ids[$n 1]]['url'],
 508 :                 'class' => $class), $n)
 509 :             ;
 510 : 
 511 :         $fill $show_nums ?
 512 :             ( $show_nums[0] > $n $placeholder $break ) : '';
 513 :         if ( $fill )
 514 :             $objs[] = new soo_html_span(''$fill);
 515 :     }
 516 : 
 517 :     if ( $break_obj ) {
 518 :         if ( $empty_break ) {
 519 :             while ( $objs ) {
 520 :                 $broken_objs[] = array_shift($objs);
 521 :                 $broken_objs[] = new $break_obj;
 522 :             }
 523 :             array_pop($broken_objs);
 524 :             $objs $broken_objs;
 525 :         }
 526 :         else
 527 :             foreach ( $objs as $i => $obj )
 528 :                 $objs[$i] = new $break_obj(''$obj);
 529 :         foreach ( $objs as $obj )
 530 :             if ( $obj instanceof $break_obj )
 531 :                 $obj->class($breakclass);
 532 :     }
 533 : 
 534 :     if ( $wraptag == 'table' )
 535 :         $wrap_obj = new soo_html_tr;
 536 : 
 537 :     else {
 538 :         $wrap_obj_class 'soo_html_' $wraptag;
 539 :         if ( class_exists($wrap_obj_class) )
 540 :             $wrap_obj = new $wrap_obj_class;
 541 :     }
 542 :     if ( isset($wrap_obj) ) {
 543 :         $wrap_obj->class($wrapclass);
 544 :         foreach ( $objs as $obj )
 545 :             $wrap_obj->contents($obj);
 546 : 
 547 :         if ( $wraptag == 'table' ) {
 548 :             $table = new soo_html_table(array('id' => $html_id),
 549 :                 new soo_html_tbody(''$wrap_obj));
 550 :             return $table->tag();
 551 :         }
 552 :         else
 553 :             return $wrap_obj->id($html_id)->tag();
 554 :     }
 555 :     else {
 556 :         $out = array();
 557 :         foreach ( $objs as $obj )
 558 :             $out[] = $obj->tag();
 559 :         return implode("\n"$out);
 560 :     }
 561 : }
 562 : ///////////////////// end of soo_multidoc_pager() ///////////////////////
 563 : 
 564 : function soo_multidoc_page_number$atts ) {
 565 : // Output tag: display current page number
 566 : // Requires article context
 567 : 
 568 :     extract(lAtts(array(
 569 :         'html_id'       =>  '',
 570 :         'class'         =>  '',
 571 :         'wraptag'       =>  'span',
 572 :         'format'        =>  'Page {page} of {total}',
 573 :     ), $atts));
 574 : 
 575 :     global $soo_multidoc;
 576 :     if ( ! ( _soo_multidoc_init() and $soo_multidoc['status'] ) ) return false;
 577 : 
 578 :     global $thisarticle;
 579 :     $collection $soo_multidoc['collection'];
 580 :     $thisid $thisarticle['thisid'];
 581 : 
 582 :     $page_ids $collection->next_array();
 583 :     array_unshift($page_ids$collection->id);
 584 : 
 585 :     $num_pages count($page_ids);
 586 :     $page_nums array_flip($page_ids);
 587 :     $this_page $page_nums[$thisid] + 1;
 588 : 
 589 :     $format str_replace('{page}'$this_page$format);
 590 :     $format str_replace('{total}'$num_pages$format);
 591 : 
 592 :     return doWrap(array($format), $wraptag''$class''''''$html_id);
 593 : 
 594 : }
 595 : 
 596 : function soo_multidoc_toc$atts ) {
 597 : // Output tag: display table of contents as tiered list
 598 : // Requires article context
 599 : 
 600 :     extract(lAtts(array(
 601 :         'wraptag'       =>  'ul',
 602 :         'root'          =>  '',
 603 :         'add_start'     =>  false,
 604 :         'html_id'       =>  '',
 605 :         'class'         =>  '',
 606 :         'active_class'  =>  '',
 607 :     ), $atts));
 608 : 
 609 :     global $soo_multidoc;
 610 :     if ( ! ( _soo_multidoc_init() and $soo_multidoc['status'] ) ) return false;
 611 : 
 612 :     global $thisarticle;
 613 :     $collection $soo_multidoc['collection'];
 614 :     $thisid $thisarticle['thisid'];
 615 : 
 616 :     $wraptag trim(strtolower($wraptag));
 617 :     if ( $wraptag != 'ul' and $wraptag != 'ol' )
 618 :         return false;
 619 : 
 620 :     if ( $root ) {
 621 :         if ( is_numeric($root) )
 622 :             $start_id intval($root);
 623 :         else
 624 :             $start_id $thisarticle['thisid'];
 625 :         $start_node $collection->get_sub_node($start_id);
 626 :         $out $start_node->toc($wraptag$thisid$active_class$add_start);
 627 :     }
 628 :     else
 629 :         $out $collection->toc($wraptag$thisid$active_class$add_start);
 630 : 
 631 :     return $out->class($class)->id($html_id)->tag();
 632 : 
 633 : }
 634 : 
 635 : function soo_multidoc_page_title$atts ) {
 636 : // Output tag: replacement for <txp:page_title />
 637 : // Requires article context
 638 : // If a Multidoc non-Start page, Start title will be added to output.
 639 : // Otherwise standard page_title() is returned
 640 : 
 641 :     extract(lAtts(array(
 642 :         'separator'     =>  ': ',
 643 :     ), $atts));
 644 : 
 645 :     global $soo_multidoc$sitename$thisarticle;
 646 :     if ( ! ( _soo_multidoc_init() and $soo_multidoc['status'] ) )
 647 :         return page_title($atts);
 648 : 
 649 :     $collection $soo_multidoc['collection'];
 650 :     $thisid $thisarticle['thisid'];
 651 : 
 652 :     return htmlspecialchars($sitename $separator $collection->title .
 653 :         ( $collection->id != $thisid ?
 654 :             $separator $collection->get_sub_node_prop($thisid'title')
 655 :             : ''
 656 :         )
 657 :     );
 658 : }
 659 : 
 660 : function soo_multidoc_breadcrumbs$atts ) {
 661 : // Output tag: show higher levels in Collection
 662 : // Requires article context
 663 : 
 664 :     extract(lAtts(array(
 665 :         'separator'     =>  ': ',
 666 :     ), $atts));
 667 : 
 668 :     global $soo_multidoc$thisarticle;
 669 :     if ( ! ( _soo_multidoc_init() and $soo_multidoc['status'] ) )
 670 :         return;
 671 : 
 672 :     $collection $soo_multidoc['collection'];
 673 :     $this_node $collection->get_sub_node($thisarticle['thisid']);
 674 : 
 675 :     $crumbs[] = $this_node->title;
 676 : 
 677 :     while ( $this_node->link_type != 'Start' ) {
 678 :         $parent $this_node->get_up();
 679 :         $this_node $collection->get_sub_node($parent);
 680 :         $url $soo_multidoc['data'][$parent]['url'];
 681 :         $tag = new soo_html_anchor(array('href' => $url),
 682 :             escape_title($this_node->title));
 683 :         array_unshift($crumbs$tag->tag());
 684 :     }
 685 : 
 686 :     return implode($separator$crumbs);
 687 : }
 688 : 
 689 : function soo_if_multidoc$atts$thing ) {
 690 : // Conditional: does current page belong to one of the specified Multidoc collections?
 691 : // If no collections specified, looks for any Multidoc collection
 692 : // Requires article context.
 693 : 
 694 :     extract(lAtts(array(
 695 :         'start_id'      =>  '',
 696 :     ), $atts));
 697 : 
 698 :     global $soo_multidoc;
 699 : 
 700 :     if ( ! ( _soo_multidoc_init() and $soo_multidoc['status'] ) )
 701 :         return parse(EvalElse($thingfalse));
 702 : 
 703 :     $collection $soo_multidoc['collection'];
 704 : 
 705 :     $start_ids do_list($start_id);
 706 : 
 707 :     $ok = ( ! $start_id or in_array($collection->id$start_ids) )
 708 :         ? true false;
 709 : 
 710 :     return parse(EvalElse($thing$ok));
 711 : }
 712 : 
 713 :   //---------------------------------------------------------------------//
 714 :  //                         Support Functions                           //
 715 : //---------------------------------------------------------------------//
 716 : 
 717 : function _soo_multidoc_init() {
 718 : // The central controller for the intialization routines: retrieve and parse
 719 : // Multidoc field data, build document tree ('collection'). Abort at any sign
 720 : // of trouble. Most Multidoc tags will abort if this function returns false.
 721 : 
 722 :     global $soo_multidoc$is_article_list$thisarticle$prefs;
 723 : 
 724 :     // Multidoc tags not allowed in lists...
 725 :     if ( $is_article_list ) return false;
 726 : 
 727 :     // only run init() once per page
 728 :     if ( $soo_multidoc['init'] ) return true;
 729 : 
 730 :     // populate global arrays of Multidoc article IDs
 731 :     _soo_multidoc_ids_init();
 732 : 
 733 :     // article context check ...............................................
 734 :     assert_article();
 735 :     if ( empty($thisarticle) )
 736 :         return _soo_multidoc_debug();
 737 : 
 738 :     $thisid $thisarticle['thisid'];
 739 : 
 740 : 
 741 :     // find Multidoc custom field ..........................................
 742 :     $custom_field _soo_multidoc_custom_field();   // e.g. 'custom_2'
 743 :     if ( empty($custom_field) )
 744 :         return _soo_multidoc_debug();
 745 : 
 746 :     if ( ! _soo_multidoc_data_init() )
 747 :         return _soo_multidoc_debug();
 748 : 
 749 :     extract($soo_multidoc);
 750 : 
 751 :     // is this a Multidoc article?
 752 :     if ( ! isset($id_parent[$thisid]) )
 753 :         return _soo_multidoc_debug();
 754 : 
 755 :     // Start page for current article's Multidoc collection
 756 :     $start = isset($id_root[$thisid]) ? $id_root[$thisid] : $thisid;
 757 : 
 758 : 
 759 :     // build document tree ///////...........................................
 760 :     $tree _soo_multidoc_build_tree($start);
 761 :     if ( ! is_array($tree) )
 762 :         return _soo_multidoc_debug($tree);
 763 : 
 764 :     // _soo_multidoc_build_tree() gets everything but the Start node itself
 765 :     $collection = new soo_multidoc_node($start);
 766 :     $collection->link_type('Start')
 767 :         ->title($data[$start]['Title'])
 768 :         ->children($tree);
 769 : 
 770 : 
 771 :     // go back and set 'next' values ///////.................................
 772 :     $next_node array_shift($tree);
 773 :     $collection->next($next_node->id);
 774 :     unset($next_node);
 775 :     $next $collection->youngest();
 776 :     $to_set $collection->get_prev($next);
 777 :     while ( is_numeric($to_set) and $to_set ) {
 778 :         $next_to_set $collection->set_next_by_id($to_set$next);
 779 :         $next $to_set;
 780 :         $to_set $next_to_set;
 781 :     }
 782 :     if ( $to_set )
 783 :         return _soo_multidoc_debug($to_set);
 784 : 
 785 : 
 786 :     // Success!!! ///////...................................................
 787 :     $soo_multidoc['collection'] = &$collection;
 788 :     $soo_multidoc['init'] = true;
 789 :     $soo_multidoc['status'] = true;
 790 :     return true;
 791 : }
 792 : 
 793 : function _soo_multidoc_build_tree($start_id) {
 794 : 
 795 :     global $soo_multidoc;
 796 :     extract($soo_multidoc);
 797 : 
 798 :     static $_soo_multidoc_failsafe;
 799 :     static $_soo_multidoc_prev;
 800 :     $_soo_multidoc_prev $start_id;
 801 :     $_soo_multidoc_failsafe ++;
 802 :     if ( $_soo_multidoc_failsafe 999 )
 803 :         return soo_multidoc_gTxt('recursion_warning') . ": ID $start_id";
 804 : 
 805 :     $out = array();
 806 : 
 807 :     foreach ( $id_children[$start_id] as $child ) {
 808 : 
 809 :         extract($data[$child]);
 810 :         $node = new soo_multidoc_node($child);
 811 :         $node->link_type($link_type)
 812 :             ->title($Title)
 813 :             ->up($parent);  // this node's parent
 814 :         $node->prev($_soo_multidoc_prev);
 815 :         $_soo_multidoc_prev $child;
 816 : 
 817 :         if ( isset($id_children[$child]) ) {
 818 :             $result _soo_multidoc_build_tree($child);
 819 :             if ( ! is_array($result) )  // recursion limit warning
 820 :                 return $result;
 821 :             $node->children($result);
 822 :             $out[$child] = $node;
 823 :         }
 824 :         else
 825 :             $out[$child] = $node;
 826 : 
 827 :         unset($node);
 828 :     }
 829 : 
 830 :     return $out;
 831 : }
 832 : 
 833 : function _soo_multidoc_custom_field() {
 834 : // find Multidoc custom field
 835 : 
 836 :     global $soo_multidoc$prefs;
 837 :     $f $soo_multidoc['custom_field'];
 838 : 
 839 :     if ( $f == -) return false;
 840 :     if ( $f ) return $f;
 841 : 
 842 :     $name $soo_multidoc['custom_field_name'];
 843 : 
 844 :     foreach ( $prefs as $key => $value )
 845 :         if ( preg_match('/^(custom_\d+)/i'$key$match) )
 846 :             if ( $value == $name ) {
 847 :                 $soo_multidoc['custom_field'] = $match[1];  // e.g. 'custom_2'
 848 :                 return $match[1];
 849 :             }
 850 :     $soo_multidoc['custom_field'] = -1;
 851 :     return _soo_multidoc_debug(
 852 :         soo_multidoc_gTxt('custom_field') . $name soo_multidoc_gTxt('not_found')
 853 :     );
 854 : }
 855 : 
 856 : function _soo_multidoc_ids_init() {
 857 : // find all articles belonging to Multidoc collections
 858 : // check for duplicate listings; abort if found
 859 : 
 860 :     global $soo_multidoc;
 861 : 
 862 :     if ( is_array($soo_multidoc['noindex']) )
 863 :         return true;
 864 : 
 865 :     $noindex = array();
 866 :     $id_parent = array();
 867 :     $id_link_type = array();
 868 :     $id_children = array();
 869 :     $duplicates = array();
 870 : 
 871 :     $custom_field _soo_multidoc_custom_field();   // e.g. 'custom_2'
 872 :     if ( empty($custom_field) )
 873 :         return false;
 874 : 
 875 :     $query = new soo_txp_select('textpattern');
 876 :     $query->select('ID')->where('Status'3'>');  // live or sticky status
 877 :     if ( ! get_pref('publish_expired_articles') ) {
 878 :         $query->where_clause('(now() <= Expires or Expires = ' .
 879 :             NULLDATETIME ')');
 880 :     }
 881 :     switch ( $soo_multidoc['posted_time'] ) {
 882 :         case 'past':
 883 :             $query->where_clause('Posted <= now()');
 884 :             break;
 885 :         case 'future':
 886 :             $query->where_clause('Posted > now()');
 887 :             break;
 888 :     }
 889 :     $all_ids = new soo_txp_rowset($query);
 890 :     $all_ids $all_ids->field_vals('ID');
 891 : 
 892 :     $query = new soo_txp_select('textpattern');
 893 :     $query->select(array('ID'$custom_field))
 894 :         ->regexp('[[:digit:]]'$custom_field);
 895 :     $data = new soo_txp_rowset($query);
 896 :     $data $data->field_vals($custom_field'ID');
 897 :     unset($query);
 898 : 
 899 :     foreach ( $data as $parent => $field ) {
 900 :         if ( in_array($parent$all_ids) ) {
 901 :             $groups do_list(strtolower($field));
 902 :             foreach ( $groups as $group ) {
 903 :                 preg_match_all('/\s(\d+)/'$group$children);
 904 :                 foreach ( $children[1] as $i => $child )
 905 :                     if ( ! in_array($child$all_ids) )
 906 :                         unset($children[1][$i]);
 907 :                 preg_match('/^\s*(\w+)\s/'$group$link_type);
 908 :                 if ( isset($id_children[$parent]) ) {
 909 :                     foreach ( $children[1] as $child )
 910 :                         array_push($id_children[$parent], $child);
 911 :                 }
 912 :                 else
 913 :                     $id_children[$parent] = $children[1];
 914 :                 foreach ( $children[1] as $child ) {
 915 :                     if ( isset($noindex[$child]) ) {
 916 :                         $duplicates[] = $child;
 917 :                         $duplicates[] = $parent;
 918 :                     }
 919 :                     else {
 920 :                         $noindex[$child] = $parent;
 921 :                         $id_link_type[$child] = $link_type[1];
 922 :                     }
 923 :                 }
 924 :             }
 925 :         }
 926 :     }
 927 : 
 928 :     $duplicates array_unique($duplicates);
 929 : 
 930 :     if ( count($duplicates) ) {
 931 :         _soo_multidoc_debug(
 932 :             soo_multidoc_gTxt('multiple_listings') . implode(', '$duplicates));
 933 :         $soo_multidoc['status'] = false;
 934 :         $soo_multidoc['noindex'] = array();
 935 :         return false;
 936 :     }
 937 : 
 938 :     $id_parent $noindex;
 939 : 
 940 :     $start_ids array_diff(array_keys($data), array_keys($noindex));
 941 : 
 942 :     foreach ( $start_ids as $id ) {
 943 :         $id_parent[$id] = 'start';
 944 :         $id_link_type[$id] = 'start';
 945 :     }
 946 : 
 947 :     $id_root = array();
 948 :     foreach ( $noindex as $id => $parent )
 949 :         $id_root[$id] = _soo_multidoc_find_root($id$id_parent);
 950 : 
 951 :     $soo_multidoc['id_parent'] = $id_parent;    // key = id, value = parent id
 952 :     $soo_multidoc['id_root'] = $id_root;        // key = id, value = root id
 953 :     $soo_multidoc['id_link_type'] = $id_link_type;      // key = id, value = link_type
 954 :     $soo_multidoc['id_children'] = $id_children;        // key = id, value = array
 955 :     $soo_multidoc['noindex'] = array_keys($noindex);    // just the ids
 956 :     return true;
 957 : 
 958 : }
 959 : 
 960 : function _soo_multidoc_find_root($id$id_parent) {
 961 : // little recursive function to find each article's Collection ID
 962 :     if ( is_numeric($id_parent[$id]) )
 963 :         return _soo_multidoc_find_root($id_parent[$id], $id_parent);
 964 :     return $id;
 965 : }
 966 : 
 967 : function _soo_multidoc_data_init() {
 968 : // assemble master array of Multidoc article info
 969 : 
 970 :     global $soo_multidoc$permlinks;
 971 :     extract($soo_multidoc);
 972 : 
 973 :     if ( is_array($data) )
 974 :         return true;
 975 : 
 976 :     if ( empty($id_parent) or $custom_field == '' or $custom_field == -)
 977 :             return false;
 978 : 
 979 :     $query = new soo_txp_select('textpattern');
 980 :     $rs $query->
 981 :         select(array(
 982 :             'ID',
 983 :             'Title',
 984 :             'url_title',
 985 :             'Section',
 986 :             'unix_timestamp(Posted) as posted',
 987 :             $custom_field)
 988 :             )->rows();
 989 :     unset($query);
 990 : 
 991 :     $out = array();
 992 : 
 993 :     $all_ids = array();
 994 : 
 995 :     foreach ( $rs as $r ) {
 996 :         $id $r['ID'];
 997 :         $all_ids[$id] = $id;
 998 :         if ( isset($id_parent[$id]) ) {
 999 :             $r['root'] = isset($id_root[$id]) ? $id_root[$id] : $id;
1000 :             $r['parent'] = $id_parent[$id];
1001 :             $r['link_type'] = $id_link_type[$id];
1002 :             $r['url'] = _soo_multidoc_url($r);
1003 :             $out[$id] = $r;
1004 :         }
1005 :     }
1006 : 
1007 :     $invalid_ids array_diff(array_keys($id_parent), $all_ids);
1008 : 
1009 :     if ( count($invalid_ids) ) {
1010 :         foreach ( $invalid_ids as $i )
1011 :             _soo_multidoc_debug(soo_multidoc_gTxt('invalid_id_1') . $id_parent[$i] .
1012 :                 soo_multidoc_gTxt('invalid_id_2') . $i);
1013 :         return false;
1014 :     }
1015 : 
1016 :     $soo_multidoc['data'] = $out;
1017 :     return true;
1018 : }
1019 : 
1020 : function _soo_multidoc_url$article_array ) {
1021 : // basically a copy of permlinkurl(), to reduce the number of db calls
1022 : 
1023 :     global $permlink_mode$prefs;
1024 : 
1025 :     if (isset($prefs['custom_url_func']) and is_callable($prefs['custom_url_func']))
1026 :         return call_user_func($prefs['custom_url_func'], $article_arrayPERMLINKURL);
1027 : 
1028 :     if (empty($article_array)) return;
1029 : 
1030 :     extract($article_array);
1031 : 
1032 :     $Section urlencode($Section);
1033 :     $url_title urlencode($url_title);
1034 : 
1035 :     switch($permlink_mode) {
1036 :         case 'section_id_title':
1037 :             if ($prefs['attach_titles_to_permalinks'])
1038 :             {
1039 :                 $out hu."$Section/$ID/$url_title";
1040 :             }else{
1041 :                 $out hu."$Section/$ID/";
1042 :             }
1043 :             break;
1044 :         case 'year_month_day_title':
1045 :             list($y,$m,$d) = explode("-",date("Y-m-d",$posted));
1046 :             $out =  hu."$y/$m/$d/$url_title";
1047 :             break;
1048 :         case 'id_title':
1049 :             if ($prefs['attach_titles_to_permalinks'])
1050 :             {
1051 :                 $out hu."$ID/$url_title";
1052 :             }else{
1053 :                 $out hu."$ID/";
1054 :             }
1055 :             break;
1056 :         case 'section_title':
1057 :             $out hu."$Section/$url_title";
1058 :             break;
1059 :         case 'title_only':
1060 :             $out hu."$url_title";
1061 :             break;
1062 :         case 'messy':
1063 :             $out hu."index.php?id=$ID";
1064 :             break;
1065 :     }
1066 :     return $out;
1067 : 
1068 : }
1069 : 
1070 : function _soo_multidoc_debug$message '' ) {
1071 : // display error message
1072 : 
1073 :     global $soo_multidoc;
1074 : 
1075 :     $soo_multidoc['init'] = true;
1076 : 
1077 :     if ( ! $message ) return false;
1078 : 
1079 :     $prefix 'soo_multidoc: ';
1080 :     $postfix n;
1081 : 
1082 :     $domain $_SERVER['HTTP_HOST'];
1083 :     $is_dev_site $domain == $soo_multidoc['dev_domain'] ? true false;
1084 :     if ( ! $is_dev_site ) {
1085 :         $prefix '<!-- ' $prefix;
1086 :         $postfix ' -->' $postfix;
1087 :     }
1088 :     else
1089 :         $postfix '<br />' $postfix;
1090 : 
1091 :     echo $prefix $message $postfix;
1092 : 
1093 :     return false;
1094 : }
1095 : 
1096 : function _soo_multidoc_temp_table ( ) {
1097 : // MySQL temporary table to filter Multidoc interior pages from article lists
1098 :     global $pretext$is_article_list$soo_multidoc;
1099 :     if ( ! $is_article_list or
1100 :         $pretext['q'] or
1101 :         $soo_multidoc['list_all'] or
1102 :         ! _soo_multidoc_ids_init() or
1103 :         empty($soo_multidoc['noindex'])
1104 :     )
1105 :         return;
1106 :     $table safe_pfx('textpattern');
1107 :     safe_query(
1108 :         "create temporary table $table select * from $table where ID not in ("
1109 :         implode(','$soo_multidoc['noindex']) . ")");
1110 : }
1111 : 
1112 : register_callback('_soo_multidoc_temp_table''pretext_end');