1<?php 2/** 3 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 4 * @author Esther Brunner <wikidesign@gmail.com> 5 * @author Christopher Smith <chris@jalakai.co.uk> 6 * @author Gina Häußge, Michael Klier <dokuwiki@chimeric.de> 7 */ 8 9// must be run within Dokuwiki 10if (!defined('DOKU_INC')) die(); 11 12if (!defined('DOKU_LF')) define('DOKU_LF', "\n"); 13if (!defined('DOKU_TAB')) define('DOKU_TAB', "\t"); 14if (!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN', DOKU_INC.'lib/plugins/'); 15 16class helper_plugin_include extends DokuWiki_Plugin { // DokuWiki_Helper_Plugin 17 18 var $pages = array(); // filechain of included pages 19 var $page = array(); // associative array with data about the page to include 20 var $ins = array(); // instructions array 21 var $doc = ''; // the final output XHTML string 22 var $mode = 'section'; // inclusion mode: 'page' or 'section' 23 var $clevel = 0; // current section level 24 var $firstsec = 0; // show first section only 25 var $editbtn = 1; // show edit button 26 var $footer = 1; // show metaline below page 27 var $noheader = 0; // omit header 28 var $permalink = 0; // make first headline permalink to included page 29 var $redirect = 1; // redirect back to original page after an edit 30 var $header = array(); // included page / section header 31 var $renderer = NULL; // DokuWiki renderer object 32 33 var $INCLUDE_LIMIT = 12; 34 35 // private variables 36 var $_offset = NULL; 37 38 /** 39 * Constructor loads some config settings 40 */ 41 function helper_plugin_include() { 42 $this->firstsec = $this->getConf('firstseconly'); 43 $this->editbtn = $this->getConf('showeditbtn'); 44 $this->footer = $this->getConf('showfooter'); 45 $this->redirect = $this->getConf('doredirect'); 46 $this->noheader = 0; 47 $this->permalink = 0; 48 $this->header = array(); 49 global $TOC; 50 if(!empty($TOC)) $TOC = array(); 51 } 52 53 function getInfo() { 54 return array( 55 'author' => 'Gina Häußge, Michael Klier, Esther Brunner', 56 'email' => 'dokuwiki@chimeric.de', 57 'date' => @file_get_contents(DOKU_PLUGIN . 'blog/VERSION'), 58 'name' => 'Include Plugin (helper class)', 59 'desc' => 'Functions to include another page in a wiki page', 60 'url' => 'http://wiki.splitbrain.org/plugin:include', 61 ); 62 } 63 64 function getMethods() { 65 $result = array(); 66 $result[] = array( 67 'name' => 'setPage', 68 'desc' => 'sets the page to include', 69 'params' => array("page attributes, 'id' required, 'section' for filtering" => 'array'), 70 'return' => array('success' => 'boolean'), 71 ); 72 $result[] = array( 73 'name' => 'setMode', 74 'desc' => 'sets inclusion mode: should indention be merged?', 75 'params' => array("'page' (original) or 'section' (merged indention)" => 'string'), 76 ); 77 $result[] = array( 78 'name' => 'setLevel', 79 'desc' => 'sets the indention for the current section level', 80 'params' => array('level: 0 to 5' => 'integer'), 81 'return' => array('success' => 'boolean'), 82 ); 83 $result[] = array( 84 'name' => 'setFlags', 85 'desc' => 'overrides standard values for showfooter and firstseconly settings', 86 'params' => array('flags' => 'array'), 87 ); 88 $result[] = array( 89 'name' => 'renderXHTML', 90 'desc' => 'renders the XHTML output of the included page', 91 'params' => array('DokuWiki renderer' => 'object'), 92 'return' => array('XHTML' => 'string'), 93 ); 94 return $result; 95 } 96 97 /** 98 * Sets the page to include if it is not already included (prevent recursion) 99 * and the current user is allowed to read it 100 */ 101 function setPage($page) { 102 global $ID; 103 104 $id = $page['id']; 105 $fullid = $id.'#'.$page['section']; 106 107 if (!$id) return false; // no page id given 108 if ($id == $ID) return false; // page can't include itself 109 110 // prevent include recursion 111 if ($this->_in_filechain($id,$page['section']) || (count($this->pages) >= $this->INCLUDE_LIMIT)) return false; 112 113 // we need to make sure 'perm', 'file' and 'exists' are set 114 if (!isset($page['perm'])) $page['perm'] = auth_quickaclcheck($page['id']); 115 if (!isset($page['file'])) $page['file'] = wikiFN($page['id']); 116 if (!isset($page['exists'])) $page['exists'] = @file_exists($page['file']); 117 118 // check permission 119 if ($page['perm'] < AUTH_READ) return false; 120 121 // add the page to the filechain 122 $this->page = $page; 123 return true; 124 } 125 126 function _push_page($id,$section) { 127 global $ID; 128 if (empty($this->pages)) array_push($this->pages, $ID.'#'); 129 array_push($this->pages, $id.'#'.$section); 130 } 131 132 function _pop_page() { 133 $page = array_pop($this->pages); 134 if (count($this->pages=1)) $this->pages = array(); 135 136 return $page; 137 } 138 139 function _in_filechain($id,$section) { 140 $pattern = $section ? "/^($id#$section|$id#)$/" : "/^$id#/"; 141 $match = preg_grep($pattern, $this->pages); 142 143 return (!empty($match)); 144 } 145 146 /** 147 * Sets the inclusion mode: 'page' or 'section' 148 */ 149 function setMode($mode) { 150 $this->mode = $mode; 151 } 152 153 /** 154 * Sets the right indention for a given section level 155 */ 156 function setLevel($level) { 157 if ((is_numeric($level)) && ($level >= 0) && ($level <= 5)) { 158 $this->clevel = $level; 159 return true; 160 } 161 return false; 162 } 163 164 /** 165 * Overrides standard values for showfooter and firstseconly settings 166 */ 167 function setFlags($flags) { 168 foreach ($flags as $flag) { 169 switch ($flag) { 170 case 'footer': 171 $this->footer = 1; 172 break; 173 case 'nofooter': 174 $this->footer = 0; 175 break; 176 case 'firstseconly': 177 case 'firstsectiononly': 178 $this->firstsec = 1; 179 break; 180 case 'fullpage': 181 $this->firstsec = 0; 182 break; 183 case 'noheader': 184 $this->noheader = 1; 185 break; 186 case 'editbtn': 187 case 'editbutton': 188 $this->editbtn = 1; 189 break; 190 case 'noeditbtn': 191 case 'noeditbutton': 192 $this->editbtn = 0; 193 break; 194 case 'permalink': 195 $this->permalink = 1; 196 break; 197 case 'nopermalink': 198 $this->permalink = 0; 199 break; 200 case 'redirect': 201 $this->redirect = 1; 202 break; 203 case 'noredirect': 204 $this->redirect = 0; 205 break; 206 } 207 } 208 } 209 210 /** 211 * Builds the XHTML to embed the page to include 212 */ 213 function renderXHTML(&$renderer, &$info) { 214 global $ID; 215 216 if (!$this->page['id']) return ''; // page must be set first 217 if (!$this->page['exists'] && ($this->page['perm'] < AUTH_CREATE)) return ''; 218 219 $this->_push_page($this->page['id'],$this->page['section']); 220 221 // prepare variables 222 $rdoc = $renderer->doc; 223 $doc = ''; 224 $this->renderer =& $renderer; 225 226 $page = $this->page; 227 $clevel = $this->clevel; 228 $mode = $this->mode; 229 230 // exchange page ID for included one 231 $backupID = $ID; // store the current ID 232 $ID = $this->page['id']; // change ID to the included page 233 234 // get instructions and render them on the fly 235 $this->ins = p_cached_instructions($this->page['file']); 236 237 // show only a given section? 238 if ($this->page['section'] && $this->page['exists']) $this->_getSection(); 239 240 // convert relative links 241 $this->_convertInstructions(); 242 243 $xhtml = p_render('xhtml', $this->ins, $info); 244 $ID = $backupID; // restore ID 245 246 $this->mode = $mode; 247 $this->clevel = $clevel; 248 $this->page = $page; 249 250 $xhtml = $this->_cleanXHTML($xhtml); 251 $xhtml = $this->_convertFootnotes($xhtml, $this->page['id']); 252 253 // render the included page 254 $content = '<div class="entry-content">'.DOKU_LF. 255 $xhtml.DOKU_LF. 256 '</div><!-- .entry-content -->'.DOKU_LF; 257 258 // restore ID 259 $ID = $backupID; 260 261 // embed the included page 262 $class = ($this->page['draft'] ? 'include draft' : 'include'); 263 264 $doc .= DOKU_LF.'<!-- including '.str_replace('--', '-', $this->page['id']).' // '.$this->page['file'].' -->'.DOKU_LF; 265 $doc .= '<div class="'.$class.' hentry"'.$this->_showTagLogos().'>'.DOKU_LF; 266 if (!$this->header && $this->clevel && ($this->mode == 'section')) 267 $doc .= '<div class="level'.$this->clevel.'">'.DOKU_LF; 268 269 if ((@file_exists(DOKU_PLUGIN.'editsections/action.php')) 270 && (!plugin_isdisabled('editsections'))) { // for Edit Section Reorganizer Plugin 271 $doc .= $this->_editButton().$content; 272 } else { 273 $doc .= $content.$this->_editButton(); 274 } 275 276 // output meta line (if wanted) and remove page from filechain 277 $doc .= $this->_footer($this->page); 278 279 if (!$this->header && $this->clevel && ($this->mode == 'section')) 280 $doc .= '</div>'.DOKU_LF; // class="level?" 281 $doc .= '</div>'.DOKU_LF; // class="include hentry" 282 $doc .= DOKU_LF.'<!-- /including '.$this->page['id'].' -->'.DOKU_LF; 283 284 // reset defaults 285 $this->helper_plugin_include(); 286 $this->_pop_page(); 287 288 // return XHTML 289 $renderer->doc = $rdoc.$doc; 290 return $doc; 291 } 292 293 /* ---------- Private Methods ---------- */ 294 295 /** 296 * Get a section including its subsections 297 */ 298 function _getSection() { 299 foreach ($this->ins as $ins) { 300 if ($ins[0] == 'header') { 301 302 // found the right header 303 if (cleanID($ins[1][0]) == $this->page['section']) { 304 $level = $ins[1][1]; 305 $i[] = $ins; 306 307 // next header of the same or higher level -> exit 308 } elseif ($ins[1][1] <= $level) { 309 $this->ins = $i; 310 return true; 311 } elseif (isset($level)) { 312 $i[] = $ins; 313 } 314 315 // add instructions from our section 316 } elseif (isset($level)) { 317 $i[] = $ins; 318 } 319 } 320 $this->ins = $i; 321 return true; 322 } 323 324 /** 325 * Corrects relative internal links and media and 326 * converts headers of included pages to subheaders of the current page 327 */ 328 function _convertInstructions() { 329 global $ID; 330 331 if (!$this->page['exists']) return false; 332 333 // check if included page is in same namespace 334 $ns = getNS($this->page['id']); 335 $convert = (getNS($ID) == $ns ? false : true); 336 337 $n = count($this->ins); 338 for ($i = 0; $i < $n; $i++) { 339 $current = $this->ins[$i][0]; 340 341 // convert internal links and media from relative to absolute 342 if ($convert && (substr($current, 0, 8) == 'internal')) { 343 $this->ins[$i][1][0] = $this->_convertInternalLink($this->ins[$i][1][0], $ns); 344 345 // set header level to current section level + header level 346 } elseif ($current == 'header') { 347 $this->_convertHeader($i); 348 349 // the same for sections 350 } elseif (($current == 'section_open') && ($this->mode == 'section')) { 351 $this->ins[$i][1][0] = $this->_convertSectionLevel($this->ins[$i][1][0]); 352 353 // show only the first section? 354 } elseif ($this->firstsec && ($current == 'section_close') 355 && ($this->ins[$i-1][0] != 'section_open')) { 356 $this->_readMore($i); 357 return true; 358 } 359 } 360 $this->_finishConvert(); 361 return true; 362 } 363 364 /** 365 * Convert relative internal links and media 366 * 367 * @param integer $i: counter for current instruction 368 * @param string $ns: namespace of included page 369 * @return string $link: converted, now absolute link 370 */ 371 function _convertInternalLink($link, $ns) { 372 373 // relative subnamespace 374 if ($link{0} == '.') { 375 if ($link{1} == '.') return getNS($ns).':'.substr($link, 2); // parent namespace 376 else return $ns.':'.substr($link, 1); // current namespace 377 378 // relative link 379 } elseif (strpos($link, ':') === false) { 380 return $ns.':'.$link; 381 382 // absolute link - don't change 383 } else { 384 return $link; 385 } 386 } 387 388 /** 389 * Convert header level and add header to TOC 390 * 391 * @param integer $i: counter for current instruction 392 * @return boolean true 393 */ 394 function _convertHeader($i) { 395 global $conf; 396 397 $text = $this->ins[$i][1][0]; 398 $hid = $this->renderer->_headerToLink($text, 'true'); 399 if (empty($this->header)) { 400 $this->_offset = $this->clevel - $this->ins[$i][1][1] + 1; 401 $level = $this->_convertSectionLevel(1); 402 $this->header = array('hid' => $hid, 'title' => hsc($text), 'level' => $level); 403 if ($this->noheader) { 404 unset($this->ins[$i]); 405 return true; 406 } else if ($this->permalink){ 407 $this->ins[$i] = $this->_permalinkHeader($text, $level, $this->ins[$i][1][2]); 408 } 409 } else { 410 $level = $this->_convertSectionLevel($this->ins[$i][1][1]); 411 } 412 if ($this->mode == 'section') { 413 if (is_array($this->ins[$i][1][1])) { // permalink header 414 $this->ins[$i][1][1][1] = $level; 415 } else { // normal header 416 $this->ins[$i][1][1] = $level; 417 } 418 } 419 420 // add TOC item 421 if (($level >= $conf['toptoclevel']) && ($level <= $conf['maxtoclevel'])) { 422 $item = array( 423 'hid' => $hid, 424 'title' => $text, 425 'type' => 'ul', 426 'level' => $level - $conf['toptoclevel'] + 1 427 ); 428 429 $this->renderer->toc[] = $item; 430 global $TOC; 431 $TOC[] = $item; 432 } 433 return true; 434 } 435 436 /** 437 * Create instruction item for a permalink header 438 * 439 * @param string $text: Headline text 440 * @param integer $level: Headline level 441 * @param integer $pos: I wish I knew what this is for... 442 * 443 * @author Gina Haeussge <osd@foosel.net> 444 */ 445 function _permalinkHeader($text, $level, $pos) { 446 $newIns = array( 447 'plugin', 448 array( 449 'include_header', 450 array( 451 $text, 452 $level 453 ), 454 ), 455 $pos 456 ); 457 458 return $newIns; 459 } 460 461 /** 462 * Convert the level of headers and sections 463 * 464 * @param integer $in: current level 465 * @return integer $out: converted level 466 */ 467 function _convertSectionLevel($in) { 468 $out = $in + $this->_offset; 469 if ($out >= 5) return 5; 470 if ($out <= $this->clevel + 1) return $this->clevel + 1; 471 return $out; 472 } 473 474 /** 475 * Adds a read more... link at the bottom of the first section 476 * 477 * @param integer $i: counter for current instruction 478 * @return boolean true 479 */ 480 function _readMore($i) { 481 $more = ((is_array($this->ins[$i+1])) && ($this->ins[$i+1][0] != 'document_end')); 482 483 if ($this->ins[0][0] == 'document_start') $this->ins = array_slice($this->ins, 1, $i); 484 else $this->ins = array_slice($this->ins, 0, $i); 485 486 if ($more) { 487 array_unshift($this->ins, array('document_start', array(), 0)); 488 $last = array_pop($this->ins); 489 $this->ins[] = array('p_open', array(), $last[2]); 490 $this->ins[] = array('internallink',array($this->page['id'], $this->getLang('readmore')),$last[2]); 491 $this->ins[] = array('p_close', array(), $last[2]); 492 $this->ins[] = $last; 493 $this->ins[] = array('document_end', array(), $last[2]); 494 } else { 495 $this->_finishConvert(); 496 } 497 return true; 498 } 499 500 /** 501 * Adds 'document_start' and 'document_end' instructions if not already there 502 */ 503 function _finishConvert() { 504 if ($this->ins[0][0] != 'document_start') 505 @array_unshift($this->ins, array('document_start', array(), 0)); 506 $c = count($this->ins) - 1; 507 if ($this->ins[$c][0] != 'document_end') 508 $this->ins[] = array('document_end', array(), 0); 509 } 510 511 /** 512 * Remove TOC, section edit buttons and tags 513 */ 514 function _cleanXHTML($xhtml) { 515 $replace = array( 516 '!<div class="toc">.*?(</div>\n</div>)!s' => '', // remove toc 517 '#<!-- SECTION "(.*?)" \[(\d+-\d*)\] -->#e' => '', // remove section edit buttons 518 '!<div class="tags">.*?(</div>)!s' => '', // remove category tags 519 ); 520 if ($this->clevel) 521 $replace['#<div class="footnotes">#s'] = '<div class="footnotes level'.$this->clevel.'">'; 522 $xhtml = preg_replace(array_keys($replace), array_values($replace), $xhtml); 523 return $xhtml; 524 } 525 526 /** 527 * Convert footnotes to include page id to make them unique if more than 528 * one page or section are included in one wiki node. (FS#93) 529 * 530 * Gotta admit, this fix is kind of ugly, but since we have no chance to 531 * fix the generated footnote ids on instruction level, this has to be 532 * done on the generated XHTML. 533 * 534 * @param $xhtml XHTML code of the page 535 * @param $id included page's id 536 * @return XHTML code with converted footnote anchors and ids 537 * 538 * @author Gina Haeussge <osd@foosel.net> 539 */ 540 function _convertFootnotes($xhtml, $id) { 541 $id = str_replace(':', '_', $id); 542 $replace = array( 543 '!<a href="#fn__(\d+)" name="fnt__(\d+)" id="fnt__(\d+)" class="fn_top">!' => 544 '<a href="#fn__'.$id.'__\1" name="fnt__'.$id.'__\2" id="fnt__'.$id.'__\3" class="fn_top">', 545 '!<a href="#fnt__(\d+)" id="fn__(\d+)" name="fn__(\d+)" class="fn_bot">!' => 546 '<a href="#fnt__'.$id.'__\1" name="fn__'.$id.'__\2" id="fn__'.$id.'__\3" class="fn_bot">', 547 ); 548 $xhtml = preg_replace(array_keys($replace), array_values($replace), $xhtml); 549 return $xhtml; 550 } 551 552 /** 553 * Optionally display logo for the first tag found in the included page 554 */ 555 function _showTagLogos() { 556 if ((!$this->getConf('showtaglogos')) 557 || (plugin_isdisabled('tag')) 558 || (!$taghelper =& plugin_load('helper', 'tag'))) 559 return ''; 560 561 $subject = p_get_metadata($this->page['id'], 'subject'); 562 if (is_array($subject)) $tag = $subject[0]; 563 else list($tag, $rest) = explode(' ', $subject, 2); 564 $title = str_replace('_', ' ', noNS($tag)); 565 resolve_pageid($taghelper->namespace, $tag, $exists); // resolve shortcuts 566 567 $logosrc = mediaFN($logoID); 568 $types = array('.png', '.jpg', '.gif'); // auto-detect filetype 569 foreach ($types as $type) { 570 if (!@file_exists($logosrc.$type)) continue; 571 $logoID = $tag.$type; 572 $logosrc .= $type; 573 list($w, $h, $t, $a) = getimagesize($logosrc); 574 return ' style="min-height: '.$h.'px">'. 575 '<img class="mediaright" src="'.ml($logoID).'" alt="'.$title.'"/'; 576 } 577 return ''; 578 } 579 580 /** 581 * Display an edit button for the included page 582 */ 583 function _editButton() { 584 global $ID; 585 if ($this->page['exists']) { 586 if (($this->page['perm'] >= AUTH_EDIT) && (is_writable($this->page['file']))) 587 $action = 'edit'; 588 else return ''; 589 } elseif ($this->page['perm'] >= AUTH_CREATE) { 590 $action = 'create'; 591 } 592 if ($this->editbtn) { 593 $params = array('do' => 'edit'); 594 if ($this->redirect) 595 $params['redirect_id'] = $ID; 596 return '<div class="secedit">'.DOKU_LF.DOKU_TAB. 597 html_btn($action, $this->page['id'], '', $params, 'post').DOKU_LF. 598 '</div>'.DOKU_LF; 599 } else { 600 return ''; 601 } 602 } 603 604 /** 605 * Returns the meta line below the included page 606 */ 607 function _footer($page) { 608 global $conf, $ID; 609 610 if (!$this->footer) return ''; // '<div class="inclmeta"> </div>'.DOKU_LF; 611 612 $id = $page['id']; 613 $meta = p_get_metadata($id); 614 $ret = array(); 615 616 // permalink 617 if ($this->getConf('showlink')) { 618 $title = ($page['title'] ? $page['title'] : $meta['title']); 619 if (!$title) $title = str_replace('_', ' ', noNS($id)); 620 $class = ($page['exists'] ? 'wikilink1' : 'wikilink2'); 621 $link = array( 622 'url' => wl($id), 623 'title' => $id, 624 'name' => hsc($title), 625 'target' => $conf['target']['wiki'], 626 'class' => $class.' permalink', 627 'more' => 'rel="bookmark"', 628 ); 629 $ret[] = $this->renderer->_formatLink($link); 630 } 631 632 // date 633 if ($this->getConf('showdate')) { 634 $date = ($page['date'] ? $page['date'] : $meta['date']['created']); 635 if ($date) 636 $ret[] = '<abbr class="published" title="'.strftime('%Y-%m-%dT%H:%M:%SZ', $date).'">'. 637 strftime($conf['dformat'], $date). 638 '</abbr>'; 639 } 640 641 // author 642 if ($this->getConf('showuser')) { 643 $author = ($page['user'] ? $page['user'] : $meta['creator']); 644 if ($author) { 645 $userpage = cleanID($this->getConf('usernamespace').':'.$author); 646 resolve_pageid(getNS($ID), $userpage, $exists); 647 $class = ($exists ? 'wikilink1' : 'wikilink2'); 648 $link = array( 649 'url' => wl($userpage), 650 'title' => $userpage, 651 'name' => hsc($author), 652 'target' => $conf['target']['wiki'], 653 'class' => $class.' url fn', 654 'pre' => '<span class="vcard author">', 655 'suf' => '</span>', 656 ); 657 $ret[] = $this->renderer->_formatLink($link); 658 } 659 } 660 661 // comments - let Discussion Plugin do the work for us 662 if (!$page['section'] && $this->getConf('showcomments') 663 && (!plugin_isdisabled('discussion')) 664 && ($discussion =& plugin_load('helper', 'discussion'))) { 665 $disc = $discussion->td($id); 666 if ($disc) $ret[] = '<span class="comment">'.$disc.'</span>'; 667 } 668 669 // linkbacks - let Linkback Plugin do the work for us 670 if (!$page['section'] && $this->getConf('showlinkbacks') 671 && (!plugin_isdisabled('linkback')) 672 && ($linkback =& plugin_load('helper', 'linkback'))) { 673 $link = $linkback->td($id); 674 if ($link) $ret[] = '<span class="linkback">'.$link.'</span>'; 675 } 676 677 $ret = implode(DOKU_LF.DOKU_TAB.'· ', $ret); 678 679 // tags - let Tag Plugin do the work for us 680 if (!$page['section'] && $this->getConf('showtags') 681 && (!plugin_isdisabled('tag')) 682 && ($tag =& plugin_load('helper', 'tag'))) { 683 $page['tags'] = '<div class="tags"><span>'.DOKU_LF. 684 DOKU_TAB.$tag->td($id).DOKU_LF. 685 DOKU_TAB.'</span></div>'.DOKU_LF; 686 $ret = $page['tags'].DOKU_TAB.$ret; 687 } 688 689 if (!$ret) $ret = ' '; 690 $class = 'inclmeta'; 691 if ($this->header && $this->clevel && ($this->mode == 'section')) 692 $class .= ' level'.$this->clevel; 693 return '<div class="'.$class.'">'.DOKU_LF.DOKU_TAB.$ret.DOKU_LF.'</div>'.DOKU_LF; 694 } 695 696 /** 697 * Builds the ODT to embed the page to include 698 */ 699 function renderODT(&$renderer) { 700 global $ID; 701 702 if (!$this->page['id']) return ''; // page must be set first 703 if (!$this->page['exists'] && ($this->page['perm'] < AUTH_CREATE)) return ''; 704 705 // prepare variable 706 $this->renderer =& $renderer; 707 708 // get instructions and render them on the fly 709 $this->ins = p_cached_instructions($this->page['file']); 710 711 // show only a given section? 712 if ($this->page['section'] && $this->page['exists']) $this->_getSection(); 713 714 // convert relative links 715 $this->_convertInstructions(); 716 717 // render the included page 718 $backupID = $ID; // store the current ID 719 $ID = $this->page['id']; // change ID to the included page 720 // remove document_start and document_end to avoid zipping 721 $this->ins = array_slice($this->ins, 1, -1); 722 p_render('odt', $this->ins, $info); 723 $ID = $backupID; // restore ID 724 // reset defaults 725 $this->helper_plugin_include(); 726 } 727} 728//vim:ts=4:sw=4:et:enc=utf-8: 729