xref: /plugin/include/helper.php (revision 61053b0410e7270611fe8e396b5a81b1441e1a07)
1f9f65fc3Swikidesign<?php
2f9f65fc3Swikidesign/**
3f9f65fc3Swikidesign * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
4f9f65fc3Swikidesign * @author     Esther Brunner <wikidesign@gmail.com>
5dbdadbd9SGina Haeussge * @author     Christopher Smith <chris@jalakai.co.uk>
6dbdadbd9SGina Haeussge * @author     Gina Häußge, Michael Klier <dokuwiki@chimeric.de>
7f9f65fc3Swikidesign */
8f9f65fc3Swikidesign
9f9f65fc3Swikidesign// must be run within Dokuwiki
10f9f65fc3Swikidesignif (!defined('DOKU_INC')) die();
11f9f65fc3Swikidesign
12f9f65fc3Swikidesignif (!defined('DOKU_LF')) define('DOKU_LF', "\n");
13f9f65fc3Swikidesignif (!defined('DOKU_TAB')) define('DOKU_TAB', "\t");
14f9f65fc3Swikidesignif (!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN', DOKU_INC.'lib/plugins/');
15f9f65fc3Swikidesign
16f9f65fc3Swikidesignclass helper_plugin_include extends DokuWiki_Plugin { // DokuWiki_Helper_Plugin
17f9f65fc3Swikidesign
18b6337848Swikidesign    var $pages     = array();   // filechain of included pages
19f9f65fc3Swikidesign    var $page      = array();   // associative array with data about the page to include
20f9f65fc3Swikidesign    var $ins       = array();   // instructions array
21f9f65fc3Swikidesign    var $doc       = '';        // the final output XHTML string
22f9f65fc3Swikidesign    var $mode      = 'section'; // inclusion mode: 'page' or 'section'
23*61053b04SMichael Klier    var $clevel    = 1;         // current section level
24f9f65fc3Swikidesign    var $firstsec  = 0;         // show first section only
256c836050Swikidesign    var $editbtn   = 1;         // show edit button
266b088758Swikidesign    var $footer    = 1;         // show metaline below page
27990ad87fSwikidesign    var $noheader  = 0;         // omit header
2871ec1101SGina Haeussge    var $permalink = 0;         // make first headline permalink to included page
29c44026dcSMichael Hamann    var $redirect  = 1;         // redirect back to original page after an edit
3039af1bf1Swikidesign    var $header    = array();   // included page / section header
3139af1bf1Swikidesign    var $renderer  = NULL;      // DokuWiki renderer object
32*61053b04SMichael Klier    var $toplevel_id = NULL;
33*61053b04SMichael Klier    var $toc       = array();
34f9f65fc3Swikidesign
35c01ce462SGina Haeussge    var $INCLUDE_LIMIT = 12;
36c01ce462SGina Haeussge
37a58d2b0aSwikidesign    // private variables
38a58d2b0aSwikidesign    var $_offset   = NULL;
39a58d2b0aSwikidesign
4052e31fceSwikidesign    /**
41656a5d08Swikidesign     * Constructor loads some config settings
4252e31fceSwikidesign     */
4352e31fceSwikidesign    function helper_plugin_include() {
4452e31fceSwikidesign        $this->firstsec = $this->getConf('firstseconly');
456c836050Swikidesign        $this->editbtn  = $this->getConf('showeditbtn');
466b088758Swikidesign        $this->footer   = $this->getConf('showfooter');
47c44026dcSMichael Hamann        $this->redirect = $this->getConf('doredirect');
48cf0272c0Swikidesign        $this->noheader = 0;
4971ec1101SGina Haeussge        $this->permalink = 0;
50cf0272c0Swikidesign        $this->header   = array();
5152e31fceSwikidesign    }
5252e31fceSwikidesign
53f9f65fc3Swikidesign    function getInfo() {
54f9f65fc3Swikidesign        return array(
5571ec1101SGina Haeussge                'author' => 'Gina Häußge, Michael Klier, Esther Brunner',
56dbdadbd9SGina Haeussge                'email'  => 'dokuwiki@chimeric.de',
574052f233SGina Haeussge                'date'   => @file_get_contents(DOKU_PLUGIN . 'blog/VERSION'),
58f9f65fc3Swikidesign                'name'   => 'Include Plugin (helper class)',
59f9f65fc3Swikidesign                'desc'   => 'Functions to include another page in a wiki page',
601f7a99c4SMichael Klier                'url'    => 'http://wiki.splitbrain.org/plugin:include',
61f9f65fc3Swikidesign                );
62f9f65fc3Swikidesign    }
63f9f65fc3Swikidesign
64f9f65fc3Swikidesign    function getMethods() {
65f9f65fc3Swikidesign        $result = array();
66f9f65fc3Swikidesign        $result[] = array(
67f9f65fc3Swikidesign                'name'   => 'setPage',
68f9f65fc3Swikidesign                'desc'   => 'sets the page to include',
69f9f65fc3Swikidesign                'params' => array("page attributes, 'id' required, 'section' for filtering" => 'array'),
70f9f65fc3Swikidesign                'return' => array('success' => 'boolean'),
71f9f65fc3Swikidesign                );
72f9f65fc3Swikidesign        $result[] = array(
73f9f65fc3Swikidesign                'name'   => 'setMode',
74f9f65fc3Swikidesign                'desc'   => 'sets inclusion mode: should indention be merged?',
75f9f65fc3Swikidesign                'params' => array("'page' (original) or 'section' (merged indention)" => 'string'),
76f9f65fc3Swikidesign                );
77f9f65fc3Swikidesign        $result[] = array(
78f9f65fc3Swikidesign                'name'   => 'setLevel',
79f9f65fc3Swikidesign                'desc'   => 'sets the indention for the current section level',
80f9f65fc3Swikidesign                'params' => array('level: 0 to 5' => 'integer'),
81f9f65fc3Swikidesign                'return' => array('success' => 'boolean'),
82f9f65fc3Swikidesign                );
83f9f65fc3Swikidesign        $result[] = array(
84656a5d08Swikidesign                'name'   => 'setFlags',
856b088758Swikidesign                'desc'   => 'overrides standard values for showfooter and firstseconly settings',
86656a5d08Swikidesign                'params' => array('flags' => 'array'),
87656a5d08Swikidesign                );
88656a5d08Swikidesign        $result[] = array(
89b6337848Swikidesign                'name'   => 'renderXHTML',
90b6337848Swikidesign                'desc'   => 'renders the XHTML output of the included page',
91f9f65fc3Swikidesign                'params' => array('DokuWiki renderer' => 'object'),
92b6337848Swikidesign                'return' => array('XHTML' => 'string'),
93f9f65fc3Swikidesign                );
94f9f65fc3Swikidesign        return $result;
95f9f65fc3Swikidesign    }
96f9f65fc3Swikidesign
97f9f65fc3Swikidesign    /**
98f9f65fc3Swikidesign     * Sets the page to include if it is not already included (prevent recursion)
99990ad87fSwikidesign     * and the current user is allowed to read it
100f9f65fc3Swikidesign     */
101f9f65fc3Swikidesign    function setPage($page) {
102f9f65fc3Swikidesign        global $ID;
103f9f65fc3Swikidesign
104b6337848Swikidesign        $id     = $page['id'];
105b6337848Swikidesign        $fullid = $id.'#'.$page['section'];
106f9f65fc3Swikidesign
107b6337848Swikidesign        if (!$id) return false;       // no page id given
108b6337848Swikidesign        if ($id == $ID) return false; // page can't include itself
109f9f65fc3Swikidesign
110b6337848Swikidesign        // prevent include recursion
111c01ce462SGina Haeussge        if ($this->_in_filechain($id,$page['section']) || (count($this->pages) >= $this->INCLUDE_LIMIT)) return false;
112b6337848Swikidesign
113990ad87fSwikidesign        // we need to make sure 'perm', 'file' and 'exists' are set
114990ad87fSwikidesign        if (!isset($page['perm'])) $page['perm'] = auth_quickaclcheck($page['id']);
115990ad87fSwikidesign        if (!isset($page['file'])) $page['file'] = wikiFN($page['id']);
116990ad87fSwikidesign        if (!isset($page['exists'])) $page['exists'] = @file_exists($page['file']);
117990ad87fSwikidesign
118990ad87fSwikidesign        // check permission
119f83ac5f7Swikidesign        if ($page['perm'] < AUTH_READ) return false;
120990ad87fSwikidesign
121b6337848Swikidesign        // add the page to the filechain
122c01ce462SGina Haeussge        $this->page = $page;
123f9f65fc3Swikidesign        return true;
124f9f65fc3Swikidesign    }
125f9f65fc3Swikidesign
126*61053b04SMichael Klier    function _push_page($id,$section='') {
127c01ce462SGina Haeussge        global $ID;
128c01ce462SGina Haeussge        if (empty($this->pages)) array_push($this->pages, $ID.'#');
129c01ce462SGina Haeussge        array_push($this->pages, $id.'#'.$section);
130c01ce462SGina Haeussge    }
131c01ce462SGina Haeussge
132c01ce462SGina Haeussge    function _pop_page() {
133c01ce462SGina Haeussge        $page = array_pop($this->pages);
134c01ce462SGina Haeussge        if (count($this->pages=1)) $this->pages = array();
135c01ce462SGina Haeussge
136c01ce462SGina Haeussge        return $page;
137c01ce462SGina Haeussge    }
138c01ce462SGina Haeussge
139c01ce462SGina Haeussge    function _in_filechain($id,$section) {
140*61053b04SMichael Klier        $pattern = ($section) ? "/^($id#$section|$id#)$/" : "/^$id#/";
141c01ce462SGina Haeussge        $match = preg_grep($pattern, $this->pages);
142c01ce462SGina Haeussge
143c01ce462SGina Haeussge        return (!empty($match));
144c01ce462SGina Haeussge    }
145c01ce462SGina Haeussge
146f9f65fc3Swikidesign    /**
147a3a7e530Swikidesign     * Sets the inclusion mode: 'page' or 'section'
148f9f65fc3Swikidesign     */
149f9f65fc3Swikidesign    function setMode($mode) {
150f9f65fc3Swikidesign        $this->mode = $mode;
151f9f65fc3Swikidesign    }
152f9f65fc3Swikidesign
153f9f65fc3Swikidesign    /**
154f9f65fc3Swikidesign     * Sets the right indention for a given section level
155f9f65fc3Swikidesign     */
156f9f65fc3Swikidesign    function setLevel($level) {
157f9f65fc3Swikidesign        if ((is_numeric($level)) && ($level >= 0) && ($level <= 5)) {
158f9f65fc3Swikidesign            $this->clevel = $level;
159f9f65fc3Swikidesign            return true;
160f9f65fc3Swikidesign        }
161f9f65fc3Swikidesign        return false;
162f9f65fc3Swikidesign    }
163f9f65fc3Swikidesign
164f9f65fc3Swikidesign    /**
1656b088758Swikidesign     * Overrides standard values for showfooter and firstseconly settings
166656a5d08Swikidesign     */
167656a5d08Swikidesign    function setFlags($flags) {
168656a5d08Swikidesign        foreach ($flags as $flag) {
169656a5d08Swikidesign            switch ($flag) {
1706b088758Swikidesign                case 'footer':
1716b088758Swikidesign                    $this->footer = 1;
172656a5d08Swikidesign                    break;
1736b088758Swikidesign                case 'nofooter':
1746b088758Swikidesign                    $this->footer = 0;
175656a5d08Swikidesign                    break;
176656a5d08Swikidesign                case 'firstseconly':
17743dcb6deSwikidesign                case 'firstsectiononly':
178656a5d08Swikidesign                    $this->firstsec = 1;
179656a5d08Swikidesign                    break;
180656a5d08Swikidesign                case 'fullpage':
181656a5d08Swikidesign                    $this->firstsec = 0;
182656a5d08Swikidesign                    break;
183990ad87fSwikidesign                case 'noheader':
184990ad87fSwikidesign                    $this->noheader = 1;
185990ad87fSwikidesign                    break;
18643dcb6deSwikidesign                case 'editbtn':
187a3a7e530Swikidesign                case 'editbutton':
1886c836050Swikidesign                    $this->editbtn = 1;
1896c836050Swikidesign                    break;
19043dcb6deSwikidesign                case 'noeditbtn':
191a3a7e530Swikidesign                case 'noeditbutton':
1926c836050Swikidesign                    $this->editbtn = 0;
1936c836050Swikidesign                    break;
19471ec1101SGina Haeussge                case 'permalink':
19571ec1101SGina Haeussge                    $this->permalink = 1;
19671ec1101SGina Haeussge                    break;
19771ec1101SGina Haeussge                case 'nopermalink':
19871ec1101SGina Haeussge                    $this->permalink = 0;
19971ec1101SGina Haeussge                    break;
200c44026dcSMichael Hamann                case 'redirect':
201c44026dcSMichael Hamann                    $this->redirect = 1;
202c44026dcSMichael Hamann                    break;
203c44026dcSMichael Hamann                case 'noredirect':
204c44026dcSMichael Hamann                    $this->redirect = 0;
205c44026dcSMichael Hamann                    break;
206656a5d08Swikidesign            }
207656a5d08Swikidesign        }
208656a5d08Swikidesign    }
209656a5d08Swikidesign
210656a5d08Swikidesign    /**
211f9f65fc3Swikidesign     * Builds the XHTML to embed the page to include
212f9f65fc3Swikidesign     */
213c01ce462SGina Haeussge    function renderXHTML(&$renderer, &$info) {
21451b9ed81Swikidesign        global $ID;
21551b9ed81Swikidesign
216b6337848Swikidesign        if (!$this->page['id']) return ''; // page must be set first
21758de0a6fSwikidesign        if (!$this->page['exists'] && ($this->page['perm'] < AUTH_CREATE)) return '';
218f9f65fc3Swikidesign
219c01ce462SGina Haeussge        $this->_push_page($this->page['id'],$this->page['section']);
220c01ce462SGina Haeussge
22152e31fceSwikidesign        // prepare variables
222c01ce462SGina Haeussge        $rdoc = $renderer->doc;
223c01ce462SGina Haeussge        $doc = '';
22439af1bf1Swikidesign        $this->renderer =& $renderer;
225f9f65fc3Swikidesign
226c01ce462SGina Haeussge        $page = $this->page;
227c01ce462SGina Haeussge        $clevel = $this->clevel;
228c01ce462SGina Haeussge        $mode = $this->mode;
229c01ce462SGina Haeussge
2308c434f1aSGina Haeussge        // exchange page ID for included one
2318c434f1aSGina Haeussge        $backupID = $ID;               // store the current ID
2328c434f1aSGina Haeussge        $ID       = $this->page['id']; // change ID to the included page
2338c434f1aSGina Haeussge
234f9f65fc3Swikidesign        // get instructions and render them on the fly
235f9f65fc3Swikidesign        $this->ins = p_cached_instructions($this->page['file']);
236f9f65fc3Swikidesign
237f9f65fc3Swikidesign        // show only a given section?
238656a5d08Swikidesign        if ($this->page['section'] && $this->page['exists']) $this->_getSection();
239f9f65fc3Swikidesign
240f9f65fc3Swikidesign        // convert relative links
24139af1bf1Swikidesign        $this->_convertInstructions();
242f9f65fc3Swikidesign
243c01ce462SGina Haeussge        $xhtml = p_render('xhtml', $this->ins, $info);
244c01ce462SGina Haeussge        $ID = $backupID;               // restore ID
245c01ce462SGina Haeussge
246c01ce462SGina Haeussge        $this->mode = $mode;
247c01ce462SGina Haeussge        $this->clevel = $clevel;
248c01ce462SGina Haeussge        $this->page = $page;
249c01ce462SGina Haeussge
250fd6f7029SGina Haeussge        $xhtml = $this->_cleanXHTML($xhtml);
251fd6f7029SGina Haeussge        $xhtml = $this->_convertFootnotes($xhtml, $this->page['id']);
252fd6f7029SGina Haeussge
253f9f65fc3Swikidesign        // render the included page
254*61053b04SMichael Klier        $content = '<div class="entry-content">' . DOKU_LF
255*61053b04SMichael Klier                 . $xhtml . DOKU_LF
256*61053b04SMichael Klier                 . '</div><!-- .entry-content -->' . DOKU_LF;
2578c434f1aSGina Haeussge
2588c434f1aSGina Haeussge        // restore ID
2598c434f1aSGina Haeussge        $ID = $backupID;
260f9f65fc3Swikidesign
261f9f65fc3Swikidesign        // embed the included page
262e62bb8f0Swikidesign        $class = ($this->page['draft'] ? 'include draft' : 'include');
263c01ce462SGina Haeussge
26452611c13SMichael Klier        $doc .= DOKU_LF.'<!-- including '.str_replace('--', '-', $this->page['id']).' // '.$this->page['file'].' -->'.DOKU_LF;
265c01ce462SGina Haeussge        $doc .= '<div class="'.$class.' hentry"'.$this->_showTagLogos().'>'.DOKU_LF;
26639af1bf1Swikidesign        if (!$this->header && $this->clevel && ($this->mode == 'section'))
267c01ce462SGina Haeussge            $doc .= '<div class="level'.$this->clevel.'">'.DOKU_LF;
268c01ce462SGina Haeussge
2698d99695dSwikidesign        if ((@file_exists(DOKU_PLUGIN.'editsections/action.php'))
2708d99695dSwikidesign                && (!plugin_isdisabled('editsections'))) { // for Edit Section Reorganizer Plugin
271c01ce462SGina Haeussge            $doc .= $this->_editButton().$content;
2726cad866dSwikidesign        } else {
273c01ce462SGina Haeussge            $doc .= $content.$this->_editButton();
2746cad866dSwikidesign        }
275656a5d08Swikidesign
276ec00fca6Swikidesign        // output meta line (if wanted) and remove page from filechain
277c01ce462SGina Haeussge        $doc .= $this->_footer($this->page);
278ec00fca6Swikidesign
27939af1bf1Swikidesign        if (!$this->header && $this->clevel && ($this->mode == 'section'))
280c01ce462SGina Haeussge            $doc .= '</div>'.DOKU_LF; // class="level?"
281c01ce462SGina Haeussge        $doc .= '</div>'.DOKU_LF; // class="include hentry"
282c01ce462SGina Haeussge        $doc .= DOKU_LF.'<!-- /including '.$this->page['id'].' -->'.DOKU_LF;
283f9f65fc3Swikidesign
284ec00fca6Swikidesign        // reset defaults
285656a5d08Swikidesign        $this->helper_plugin_include();
286c01ce462SGina Haeussge        $this->_pop_page();
287f9f65fc3Swikidesign
288ec00fca6Swikidesign        // return XHTML
289c01ce462SGina Haeussge        $renderer->doc = $rdoc.$doc;
290c01ce462SGina Haeussge        return $doc;
291f9f65fc3Swikidesign    }
292f9f65fc3Swikidesign
293f9f65fc3Swikidesign    /* ---------- Private Methods ---------- */
294f9f65fc3Swikidesign
295f9f65fc3Swikidesign    /**
296f9f65fc3Swikidesign     * Get a section including its subsections
297f9f65fc3Swikidesign     */
298f9f65fc3Swikidesign    function _getSection() {
299f9f65fc3Swikidesign        foreach ($this->ins as $ins) {
300f9f65fc3Swikidesign            if ($ins[0] == 'header') {
301f9f65fc3Swikidesign
302f9f65fc3Swikidesign                // found the right header
303f9f65fc3Swikidesign                if (cleanID($ins[1][0]) == $this->page['section']) {
304f9f65fc3Swikidesign                    $level = $ins[1][1];
305f9f65fc3Swikidesign                    $i[] = $ins;
306f9f65fc3Swikidesign
307f9f65fc3Swikidesign                    // next header of the same or higher level -> exit
308f9f65fc3Swikidesign                } elseif ($ins[1][1] <= $level) {
309f9f65fc3Swikidesign                    $this->ins = $i;
310f9f65fc3Swikidesign                    return true;
311f9f65fc3Swikidesign                } elseif (isset($level)) {
312f9f65fc3Swikidesign                    $i[] = $ins;
313f9f65fc3Swikidesign                }
314f9f65fc3Swikidesign
315f9f65fc3Swikidesign                // add instructions from our section
316f9f65fc3Swikidesign            } elseif (isset($level)) {
317f9f65fc3Swikidesign                $i[] = $ins;
318f9f65fc3Swikidesign            }
319f9f65fc3Swikidesign        }
320f9f65fc3Swikidesign        $this->ins = $i;
321f9f65fc3Swikidesign        return true;
322f9f65fc3Swikidesign    }
323f9f65fc3Swikidesign
324f9f65fc3Swikidesign    /**
325f9f65fc3Swikidesign     * Corrects relative internal links and media and
326f9f65fc3Swikidesign     * converts headers of included pages to subheaders of the current page
327f9f65fc3Swikidesign     */
32839af1bf1Swikidesign    function _convertInstructions() {
32951b9ed81Swikidesign        global $ID;
33051b9ed81Swikidesign
33158de0a6fSwikidesign        if (!$this->page['exists']) return false;
33258de0a6fSwikidesign
333f9f65fc3Swikidesign        // check if included page is in same namespace
3349a79957fSwikidesign        $ns      = getNS($this->page['id']);
33551b9ed81Swikidesign        $convert = (getNS($ID) == $ns ? false : true);
336f9f65fc3Swikidesign
337f9f65fc3Swikidesign        $n = count($this->ins);
338f9f65fc3Swikidesign        for ($i = 0; $i < $n; $i++) {
339a58d2b0aSwikidesign            $current = $this->ins[$i][0];
340f9f65fc3Swikidesign
341f9f65fc3Swikidesign            // convert internal links and media from relative to absolute
342a58d2b0aSwikidesign            if ($convert && (substr($current, 0, 8) == 'internal')) {
3439a79957fSwikidesign                $this->ins[$i][1][0] = $this->_convertInternalLink($this->ins[$i][1][0], $ns);
344a58d2b0aSwikidesign
345a58d2b0aSwikidesign                // set header level to current section level + header level
346a58d2b0aSwikidesign            } elseif ($current == 'header') {
3479a79957fSwikidesign                $this->_convertHeader($i);
348a58d2b0aSwikidesign
349a58d2b0aSwikidesign                // the same for sections
3509a79957fSwikidesign            } elseif (($current == 'section_open') && ($this->mode == 'section')) {
351a58d2b0aSwikidesign                $this->ins[$i][1][0] = $this->_convertSectionLevel($this->ins[$i][1][0]);
352a58d2b0aSwikidesign
353a58d2b0aSwikidesign                // show only the first section?
354a58d2b0aSwikidesign            } elseif ($this->firstsec && ($current == 'section_close')
355a58d2b0aSwikidesign                    && ($this->ins[$i-1][0] != 'section_open')) {
356a58d2b0aSwikidesign                $this->_readMore($i);
357a58d2b0aSwikidesign                return true;
358a58d2b0aSwikidesign            }
359a58d2b0aSwikidesign        }
360a58d2b0aSwikidesign        $this->_finishConvert();
361a58d2b0aSwikidesign        return true;
362a58d2b0aSwikidesign    }
363a58d2b0aSwikidesign
364a58d2b0aSwikidesign    /**
365a58d2b0aSwikidesign     * Convert relative internal links and media
366a58d2b0aSwikidesign     *
367a58d2b0aSwikidesign     * @param    integer $i: counter for current instruction
368a58d2b0aSwikidesign     * @param    string  $ns: namespace of included page
369a58d2b0aSwikidesign     * @return   string  $link: converted, now absolute link
370a58d2b0aSwikidesign     */
3719a79957fSwikidesign    function _convertInternalLink($link, $ns) {
372f9f65fc3Swikidesign
373f9f65fc3Swikidesign        // relative subnamespace
3749a79957fSwikidesign        if ($link{0} == '.') {
3759a79957fSwikidesign            if ($link{1} == '.') return getNS($ns).':'.substr($link, 2); // parent namespace
3769a79957fSwikidesign            else return $ns.':'.substr($link, 1);                        // current namespace
377f9f65fc3Swikidesign
378f9f65fc3Swikidesign            // relative link
3799a79957fSwikidesign        } elseif (strpos($link, ':') === false) {
3809a79957fSwikidesign            return $ns.':'.$link;
3819a79957fSwikidesign
3829a79957fSwikidesign            // absolute link - don't change
3839a79957fSwikidesign        } else {
3849a79957fSwikidesign            return $link;
385a58d2b0aSwikidesign        }
386f9f65fc3Swikidesign    }
387f9f65fc3Swikidesign
388a58d2b0aSwikidesign    /**
389a58d2b0aSwikidesign     * Convert header level and add header to TOC
390a58d2b0aSwikidesign     *
391a58d2b0aSwikidesign     * @param    integer $i: counter for current instruction
392a58d2b0aSwikidesign     * @return   boolean true
393a58d2b0aSwikidesign     */
3949a79957fSwikidesign    function _convertHeader($i) {
395cf0272c0Swikidesign        global $conf;
396cf0272c0Swikidesign
397f9f65fc3Swikidesign        $text = $this->ins[$i][1][0];
39839af1bf1Swikidesign        $hid  = $this->renderer->_headerToLink($text, 'true');
399b448b725Swikidesign        if (empty($this->header)) {
400a58d2b0aSwikidesign            $this->_offset = $this->clevel - $this->ins[$i][1][1] + 1;
401cf0272c0Swikidesign            $level = $this->_convertSectionLevel(1);
402cf0272c0Swikidesign            $this->header = array('hid' => $hid, 'title' => hsc($text), 'level' => $level);
403990ad87fSwikidesign            if ($this->noheader) {
40439af1bf1Swikidesign                unset($this->ins[$i]);
405990ad87fSwikidesign                return true;
40671ec1101SGina Haeussge            } else if ($this->permalink){
4074eb6b7abSGina Haeussge                $this->ins[$i] = $this->_permalinkHeader($text, $level, $this->ins[$i][1][2]);
408990ad87fSwikidesign            }
409656a5d08Swikidesign        } else {
410a58d2b0aSwikidesign            $level = $this->_convertSectionLevel($this->ins[$i][1][1]);
41139af1bf1Swikidesign        }
41271ec1101SGina Haeussge        if ($this->mode == 'section') {
4134eb6b7abSGina Haeussge            if (is_array($this->ins[$i][1][1])) { // permalink header
41471ec1101SGina Haeussge                $this->ins[$i][1][1][1] = $level;
4154eb6b7abSGina Haeussge            } else { // normal header
41671ec1101SGina Haeussge                $this->ins[$i][1][1] = $level;
41771ec1101SGina Haeussge            }
41871ec1101SGina Haeussge        }
419990ad87fSwikidesign
420*61053b04SMichael Klier
421a58d2b0aSwikidesign        // add TOC item
422656a5d08Swikidesign        if (($level >= $conf['toptoclevel']) && ($level <= $conf['maxtoclevel'])) {
4232e4815a3SMichael Klier            $item = array(
424656a5d08Swikidesign                    'hid'   => $hid,
425656a5d08Swikidesign                    'title' => $text,
426656a5d08Swikidesign                    'type'  => 'ul',
427656a5d08Swikidesign                    'level' => $level - $conf['toptoclevel'] + 1
428656a5d08Swikidesign                    );
429*61053b04SMichael Klier            $this->toc[] = $item;
430f9f65fc3Swikidesign        }
431f9f65fc3Swikidesign        return true;
432a58d2b0aSwikidesign    }
433a58d2b0aSwikidesign
434a58d2b0aSwikidesign    /**
43571ec1101SGina Haeussge     * Create instruction item for a permalink header
43671ec1101SGina Haeussge     *
43771ec1101SGina Haeussge     * @param   string  $text: Headline text
43871ec1101SGina Haeussge     * @param   integer $level: Headline level
43971ec1101SGina Haeussge     * @param   integer $pos: I wish I knew what this is for...
44071ec1101SGina Haeussge     *
44171ec1101SGina Haeussge     * @author Gina Haeussge <osd@foosel.net>
44271ec1101SGina Haeussge     */
44371ec1101SGina Haeussge    function _permalinkHeader($text, $level, $pos) {
44471ec1101SGina Haeussge        $newIns = array(
44571ec1101SGina Haeussge            'plugin',
44671ec1101SGina Haeussge            array(
44771ec1101SGina Haeussge                'include_header',
44871ec1101SGina Haeussge                array(
44971ec1101SGina Haeussge                    $text,
4504eb6b7abSGina Haeussge                    $level
45171ec1101SGina Haeussge                ),
45271ec1101SGina Haeussge            ),
45371ec1101SGina Haeussge            $pos
45471ec1101SGina Haeussge        );
45571ec1101SGina Haeussge
45671ec1101SGina Haeussge        return $newIns;
45771ec1101SGina Haeussge    }
45871ec1101SGina Haeussge
45971ec1101SGina Haeussge    /**
460a58d2b0aSwikidesign     * Convert the level of headers and sections
461a58d2b0aSwikidesign     *
462a58d2b0aSwikidesign     * @param    integer $in: current level
463a58d2b0aSwikidesign     * @return   integer $out: converted level
464a58d2b0aSwikidesign     */
465a58d2b0aSwikidesign    function _convertSectionLevel($in) {
466a58d2b0aSwikidesign        $out = $in + $this->_offset;
467cf0272c0Swikidesign        if ($out >= 5) return 5;
468cf0272c0Swikidesign        if ($out <= $this->clevel + 1) return $this->clevel + 1;
469a58d2b0aSwikidesign        return $out;
470a58d2b0aSwikidesign    }
471a58d2b0aSwikidesign
472a58d2b0aSwikidesign    /**
473a58d2b0aSwikidesign     * Adds a read more... link at the bottom of the first section
474a58d2b0aSwikidesign     *
475a58d2b0aSwikidesign     * @param    integer $i: counter for current instruction
476a58d2b0aSwikidesign     * @return   boolean true
477a58d2b0aSwikidesign     */
478a58d2b0aSwikidesign    function _readMore($i) {
479a58d2b0aSwikidesign        $more = ((is_array($this->ins[$i+1])) && ($this->ins[$i+1][0] != 'document_end'));
480a58d2b0aSwikidesign
481a58d2b0aSwikidesign        if ($this->ins[0][0] == 'document_start') $this->ins = array_slice($this->ins, 1, $i);
482a58d2b0aSwikidesign        else $this->ins = array_slice($this->ins, 0, $i);
483a58d2b0aSwikidesign
484a58d2b0aSwikidesign        if ($more) {
485a58d2b0aSwikidesign            array_unshift($this->ins, array('document_start', array(), 0));
486a58d2b0aSwikidesign            $last = array_pop($this->ins);
487a58d2b0aSwikidesign            $this->ins[] = array('p_open', array(), $last[2]);
488a58d2b0aSwikidesign            $this->ins[] = array('internallink',array($this->page['id'], $this->getLang('readmore')),$last[2]);
489a58d2b0aSwikidesign            $this->ins[] = array('p_close', array(), $last[2]);
490a58d2b0aSwikidesign            $this->ins[] = $last;
491a58d2b0aSwikidesign            $this->ins[] = array('document_end', array(), $last[2]);
492f9f65fc3Swikidesign        } else {
493a58d2b0aSwikidesign            $this->_finishConvert();
494a58d2b0aSwikidesign        }
495f9f65fc3Swikidesign        return true;
496f9f65fc3Swikidesign    }
497a58d2b0aSwikidesign
498a58d2b0aSwikidesign    /**
499a58d2b0aSwikidesign     * Adds 'document_start' and 'document_end' instructions if not already there
500a58d2b0aSwikidesign     */
501a58d2b0aSwikidesign    function _finishConvert() {
502b088012cSwikidesign        if ($this->ins[0][0] != 'document_start')
503e959a620SMichael Klier            @array_unshift($this->ins, array('document_start', array(), 0));
504b088012cSwikidesign        $c = count($this->ins) - 1;
505b088012cSwikidesign        if ($this->ins[$c][0] != 'document_end')
50678f60e2aSwikidesign            $this->ins[] = array('document_end', array(), 0);
50778f60e2aSwikidesign    }
508f9f65fc3Swikidesign
509f9f65fc3Swikidesign    /**
510f9f65fc3Swikidesign     * Remove TOC, section edit buttons and tags
511f9f65fc3Swikidesign     */
512f9f65fc3Swikidesign    function _cleanXHTML($xhtml) {
513f9f65fc3Swikidesign        $replace = array(
514f9f65fc3Swikidesign                '!<div class="toc">.*?(</div>\n</div>)!s'   => '', // remove toc
515f9f65fc3Swikidesign                '#<!-- SECTION "(.*?)" \[(\d+-\d*)\] -->#e' => '', // remove section edit buttons
516f9f65fc3Swikidesign                '!<div class="tags">.*?(</div>)!s'          => '', // remove category tags
517f9f65fc3Swikidesign                );
518b088012cSwikidesign        if ($this->clevel)
519b088012cSwikidesign            $replace['#<div class="footnotes">#s'] = '<div class="footnotes level'.$this->clevel.'">';
520f9f65fc3Swikidesign        $xhtml  = preg_replace(array_keys($replace), array_values($replace), $xhtml);
521f9f65fc3Swikidesign        return $xhtml;
522f9f65fc3Swikidesign    }
523f9f65fc3Swikidesign
524f9f65fc3Swikidesign    /**
525fd6f7029SGina Haeussge     * Convert footnotes to include page id to make them unique if more than
526fd6f7029SGina Haeussge     * one page or section are included in one wiki node. (FS#93)
527fd6f7029SGina Haeussge     *
528fd6f7029SGina Haeussge     * Gotta admit, this fix is kind of ugly, but since we have no chance to
529fd6f7029SGina Haeussge     * fix the generated footnote ids on instruction level, this has to be
530fd6f7029SGina Haeussge     * done on the generated XHTML.
531fd6f7029SGina Haeussge     *
532fd6f7029SGina Haeussge     * @param $xhtml XHTML code of the page
533fd6f7029SGina Haeussge     * @param $id    included page's id
534fd6f7029SGina Haeussge     * @return XHTML code with converted footnote anchors and ids
535fd6f7029SGina Haeussge     *
536fd6f7029SGina Haeussge     * @author Gina Haeussge <osd@foosel.net>
537fd6f7029SGina Haeussge     */
538fd6f7029SGina Haeussge    function _convertFootnotes($xhtml, $id) {
539fd6f7029SGina Haeussge    	$id = str_replace(':', '_', $id);
540fd6f7029SGina Haeussge    	$replace = array(
541fd6f7029SGina Haeussge    		'!<a href="#fn__(\d+)" name="fnt__(\d+)" id="fnt__(\d+)" class="fn_top">!' =>
542fd6f7029SGina Haeussge				'<a href="#fn__'.$id.'__\1" name="fnt__'.$id.'__\2" id="fnt__'.$id.'__\3" class="fn_top">',
543fd6f7029SGina Haeussge    		'!<a href="#fnt__(\d+)" id="fn__(\d+)" name="fn__(\d+)" class="fn_bot">!' =>
544fd6f7029SGina Haeussge				'<a href="#fnt__'.$id.'__\1" name="fn__'.$id.'__\2" id="fn__'.$id.'__\3" class="fn_bot">',
545fd6f7029SGina Haeussge    	);
546fd6f7029SGina Haeussge    	$xhtml = preg_replace(array_keys($replace), array_values($replace), $xhtml);
547fd6f7029SGina Haeussge    	return $xhtml;
548fd6f7029SGina Haeussge    }
549fd6f7029SGina Haeussge
550fd6f7029SGina Haeussge    /**
551f9f65fc3Swikidesign     * Optionally display logo for the first tag found in the included page
552f9f65fc3Swikidesign     */
553f9f65fc3Swikidesign    function _showTagLogos() {
554fc5d061eSwikidesign        if ((!$this->getConf('showtaglogos'))
555fc5d061eSwikidesign                || (plugin_isdisabled('tag'))
556fc5d061eSwikidesign                || (!$taghelper =& plugin_load('helper', 'tag')))
557fc5d061eSwikidesign            return '';
558f9f65fc3Swikidesign
559fc5d061eSwikidesign        $subject = p_get_metadata($this->page['id'], 'subject');
560fc5d061eSwikidesign        if (is_array($subject)) $tag = $subject[0];
561fc5d061eSwikidesign        else list($tag, $rest) = explode(' ', $subject, 2);
562fc5d061eSwikidesign        $title = str_replace('_', ' ', noNS($tag));
563fc5d061eSwikidesign        resolve_pageid($taghelper->namespace, $tag, $exists); // resolve shortcuts
564fc5d061eSwikidesign
565f9f65fc3Swikidesign        $logosrc = mediaFN($logoID);
566f9f65fc3Swikidesign        $types = array('.png', '.jpg', '.gif'); // auto-detect filetype
567f9f65fc3Swikidesign        foreach ($types as $type) {
568f9f65fc3Swikidesign            if (!@file_exists($logosrc.$type)) continue;
569fc5d061eSwikidesign            $logoID   = $tag.$type;
570f9f65fc3Swikidesign            $logosrc .= $type;
571f9f65fc3Swikidesign            list($w, $h, $t, $a) = getimagesize($logosrc);
572f9f65fc3Swikidesign            return ' style="min-height: '.$h.'px">'.
573fc5d061eSwikidesign                '<img class="mediaright" src="'.ml($logoID).'" alt="'.$title.'"/';
574f9f65fc3Swikidesign        }
575f9f65fc3Swikidesign        return '';
576f9f65fc3Swikidesign    }
577f9f65fc3Swikidesign
578f9f65fc3Swikidesign    /**
579f9f65fc3Swikidesign     * Display an edit button for the included page
580f9f65fc3Swikidesign     */
581f9f65fc3Swikidesign    function _editButton() {
582c44026dcSMichael Hamann        global $ID;
583990ad87fSwikidesign        if ($this->page['exists']) {
584f9f65fc3Swikidesign            if (($this->page['perm'] >= AUTH_EDIT) && (is_writable($this->page['file'])))
585f9f65fc3Swikidesign                $action = 'edit';
586f9f65fc3Swikidesign            else return '';
587f9f65fc3Swikidesign        } elseif ($this->page['perm'] >= AUTH_CREATE) {
588f9f65fc3Swikidesign            $action = 'create';
589f9f65fc3Swikidesign        }
5906c836050Swikidesign        if ($this->editbtn) {
591c44026dcSMichael Hamann            $params = array('do' => 'edit');
592c44026dcSMichael Hamann            if ($this->redirect)
593c44026dcSMichael Hamann                $params['redirect_id'] = $ID;
594f9f65fc3Swikidesign            return '<div class="secedit">'.DOKU_LF.DOKU_TAB.
595c44026dcSMichael Hamann                html_btn($action, $this->page['id'], '', $params, 'post').DOKU_LF.
596f9f65fc3Swikidesign                '</div>'.DOKU_LF;
5973c01153cSwikidesign        } else {
5983c01153cSwikidesign            return '';
5993c01153cSwikidesign        }
600f9f65fc3Swikidesign    }
601f9f65fc3Swikidesign
602f9f65fc3Swikidesign    /**
603f9f65fc3Swikidesign     * Returns the meta line below the included page
604f9f65fc3Swikidesign     */
6056b088758Swikidesign    function _footer($page) {
606817828faSwikidesign        global $conf, $ID;
607817828faSwikidesign
6086b088758Swikidesign        if (!$this->footer) return ''; // '<div class="inclmeta">&nbsp;</div>'.DOKU_LF;
609f9f65fc3Swikidesign
610b6337848Swikidesign        $id   = $page['id'];
611f9f65fc3Swikidesign        $meta = p_get_metadata($id);
612f9f65fc3Swikidesign        $ret  = array();
613f9f65fc3Swikidesign
614f9f65fc3Swikidesign        // permalink
615f9f65fc3Swikidesign        if ($this->getConf('showlink')) {
616b6337848Swikidesign            $title = ($page['title'] ? $page['title'] : $meta['title']);
617f9f65fc3Swikidesign            if (!$title) $title = str_replace('_', ' ', noNS($id));
618656a5d08Swikidesign            $class = ($page['exists'] ? 'wikilink1' : 'wikilink2');
61939af1bf1Swikidesign            $link = array(
62039af1bf1Swikidesign                    'url'    => wl($id),
62139af1bf1Swikidesign                    'title'  => $id,
62239af1bf1Swikidesign                    'name'   => hsc($title),
62339af1bf1Swikidesign                    'target' => $conf['target']['wiki'],
624656a5d08Swikidesign                    'class'  => $class.' permalink',
62539af1bf1Swikidesign                    'more'   => 'rel="bookmark"',
62639af1bf1Swikidesign                    );
62739af1bf1Swikidesign            $ret[] = $this->renderer->_formatLink($link);
628f9f65fc3Swikidesign        }
629f9f65fc3Swikidesign
630f9f65fc3Swikidesign        // date
631f9f65fc3Swikidesign        if ($this->getConf('showdate')) {
632b6337848Swikidesign            $date = ($page['date'] ? $page['date'] : $meta['date']['created']);
63339af1bf1Swikidesign            if ($date)
634ee335396SMichael Klier                $ret[] = '<abbr class="published" title="'.strftime('%Y-%m-%dT%H:%M:%SZ', $date).'">'.
635ee335396SMichael Klier                    strftime($conf['dformat'], $date).
63639af1bf1Swikidesign                    '</abbr>';
637f9f65fc3Swikidesign        }
638f9f65fc3Swikidesign
639f9f65fc3Swikidesign        // author
640f9f65fc3Swikidesign        if ($this->getConf('showuser')) {
641b6337848Swikidesign            $author   = ($page['user'] ? $page['user'] : $meta['creator']);
642f9f65fc3Swikidesign            if ($author) {
643f9f65fc3Swikidesign                $userpage = cleanID($this->getConf('usernamespace').':'.$author);
64451b9ed81Swikidesign                resolve_pageid(getNS($ID), $userpage, $exists);
64539af1bf1Swikidesign                $class = ($exists ? 'wikilink1' : 'wikilink2');
64639af1bf1Swikidesign                $link = array(
64739af1bf1Swikidesign                        'url'    => wl($userpage),
64839af1bf1Swikidesign                        'title'  => $userpage,
64939af1bf1Swikidesign                        'name'   => hsc($author),
65039af1bf1Swikidesign                        'target' => $conf['target']['wiki'],
65139af1bf1Swikidesign                        'class'  => $class.' url fn',
65239af1bf1Swikidesign                        'pre'    => '<span class="vcard author">',
65339af1bf1Swikidesign                        'suf'    => '</span>',
65439af1bf1Swikidesign                        );
65539af1bf1Swikidesign                $ret[]    = $this->renderer->_formatLink($link);
656f9f65fc3Swikidesign            }
657f9f65fc3Swikidesign        }
658f9f65fc3Swikidesign
659f9f65fc3Swikidesign        // comments - let Discussion Plugin do the work for us
660b6337848Swikidesign        if (!$page['section'] && $this->getConf('showcomments')
661e4624397Swikidesign                && (!plugin_isdisabled('discussion'))
662e4624397Swikidesign                && ($discussion =& plugin_load('helper', 'discussion'))) {
663e4624397Swikidesign            $disc = $discussion->td($id);
66439af1bf1Swikidesign            if ($disc) $ret[] = '<span class="comment">'.$disc.'</span>';
665f9f65fc3Swikidesign        }
666f9f65fc3Swikidesign
667564e71f6Sraymond.scholz        // linkbacks - let Linkback Plugin do the work for us
668564e71f6Sraymond.scholz        if (!$page['section'] && $this->getConf('showlinkbacks')
669564e71f6Sraymond.scholz                && (!plugin_isdisabled('linkback'))
670564e71f6Sraymond.scholz                && ($linkback =& plugin_load('helper', 'linkback'))) {
671564e71f6Sraymond.scholz            $link = $linkback->td($id);
672564e71f6Sraymond.scholz            if ($link) $ret[] = '<span class="linkback">'.$link.'</span>';
673564e71f6Sraymond.scholz        }
674564e71f6Sraymond.scholz
675ec00fca6Swikidesign        $ret = implode(DOKU_LF.DOKU_TAB.'&middot; ', $ret);
676f9f65fc3Swikidesign
677fc5d061eSwikidesign        // tags - let Tag Plugin do the work for us
678fc5d061eSwikidesign        if (!$page['section'] && $this->getConf('showtags')
679fc5d061eSwikidesign                && (!plugin_isdisabled('tag'))
680fc5d061eSwikidesign                && ($tag =& plugin_load('helper', 'tag'))) {
681fc5d061eSwikidesign            $page['tags'] = '<div class="tags"><span>'.DOKU_LF.
682fc5d061eSwikidesign                DOKU_TAB.$tag->td($id).DOKU_LF.
683fc5d061eSwikidesign                DOKU_TAB.'</span></div>'.DOKU_LF;
684fc5d061eSwikidesign            $ret = $page['tags'].DOKU_TAB.$ret;
685f9f65fc3Swikidesign        }
686f9f65fc3Swikidesign
687f9f65fc3Swikidesign        if (!$ret) $ret = '&nbsp;';
688ec00fca6Swikidesign        $class = 'inclmeta';
689*61053b04SMichael Klier        if ($this->header && $this->clevel && ($this->mode == 'section')) {
690ec00fca6Swikidesign            $class .= ' level'.$this->clevel;
691*61053b04SMichael Klier        }
692ec00fca6Swikidesign        return '<div class="'.$class.'">'.DOKU_LF.DOKU_TAB.$ret.DOKU_LF.'</div>'.DOKU_LF;
693f9f65fc3Swikidesign    }
694f9f65fc3Swikidesign
6951f7a99c4SMichael Klier    /**
6961f7a99c4SMichael Klier     * Builds the ODT to embed the page to include
6971f7a99c4SMichael Klier     */
6981f7a99c4SMichael Klier    function renderODT(&$renderer) {
6991f7a99c4SMichael Klier        global $ID;
7001f7a99c4SMichael Klier
7011f7a99c4SMichael Klier        if (!$this->page['id']) return ''; // page must be set first
7021f7a99c4SMichael Klier        if (!$this->page['exists'] && ($this->page['perm'] < AUTH_CREATE)) return '';
7031f7a99c4SMichael Klier
7041f7a99c4SMichael Klier        // prepare variable
7051f7a99c4SMichael Klier        $this->renderer =& $renderer;
7061f7a99c4SMichael Klier
7071f7a99c4SMichael Klier        // get instructions and render them on the fly
7081f7a99c4SMichael Klier        $this->ins = p_cached_instructions($this->page['file']);
7091f7a99c4SMichael Klier
7101f7a99c4SMichael Klier        // show only a given section?
7111f7a99c4SMichael Klier        if ($this->page['section'] && $this->page['exists']) $this->_getSection();
7121f7a99c4SMichael Klier
7131f7a99c4SMichael Klier        // convert relative links
7141f7a99c4SMichael Klier        $this->_convertInstructions();
7151f7a99c4SMichael Klier
7161f7a99c4SMichael Klier        // render the included page
7171f7a99c4SMichael Klier        $backupID = $ID;               // store the current ID
7181f7a99c4SMichael Klier        $ID       = $this->page['id']; // change ID to the included page
7191f7a99c4SMichael Klier        // remove document_start and document_end to avoid zipping
7201f7a99c4SMichael Klier        $this->ins = array_slice($this->ins, 1, -1);
7211f7a99c4SMichael Klier        p_render('odt', $this->ins, $info);
7221f7a99c4SMichael Klier        $ID = $backupID;               // restore ID
7231f7a99c4SMichael Klier        // reset defaults
7241f7a99c4SMichael Klier        $this->helper_plugin_include();
7251f7a99c4SMichael Klier    }
726*61053b04SMichael Klier
727*61053b04SMichael Klier    /**
728*61053b04SMichael Klier     * Makes user or date dependent includes possible
729*61053b04SMichael Klier     */
730*61053b04SMichael Klier    function _applyMacro($id) {
731*61053b04SMichael Klier        global $INFO, $auth;
732*61053b04SMichael Klier
733*61053b04SMichael Klier        // if we don't have an auth object, do nothing
734*61053b04SMichael Klier        if (!$auth)
735*61053b04SMichael Klier        	return $id;
736*61053b04SMichael Klier
737*61053b04SMichael Klier        $user     = $_SERVER['REMOTE_USER'];
738*61053b04SMichael Klier        $userdata = $auth->getUserData($user);
739*61053b04SMichael Klier        $group    = $userdata['grps'][0];
740*61053b04SMichael Klier
741*61053b04SMichael Klier        $replace = array(
742*61053b04SMichael Klier                '@USER@'  => cleanID($user),
743*61053b04SMichael Klier                '@NAME@'  => cleanID($INFO['userinfo']['name']),
744*61053b04SMichael Klier                '@GROUP@' => cleanID($group),
745*61053b04SMichael Klier                '@YEAR@'  => date('Y'),
746*61053b04SMichael Klier                '@MONTH@' => date('m'),
747*61053b04SMichael Klier                '@DAY@'   => date('d'),
748*61053b04SMichael Klier                );
749*61053b04SMichael Klier        return str_replace(array_keys($replace), array_values($replace), $id);
750*61053b04SMichael Klier    }
751f9f65fc3Swikidesign}
752df4e907bSMichael Klier//vim:ts=4:sw=4:et:enc=utf-8:
753