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