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' 23f9f65fc3Swikidesign var $clevel = 0; // 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 32f9f65fc3Swikidesign 33c01ce462SGina Haeussge var $INCLUDE_LIMIT = 12; 34c01ce462SGina Haeussge 35a58d2b0aSwikidesign // private variables 36a58d2b0aSwikidesign var $_offset = NULL; 37a58d2b0aSwikidesign 3852e31fceSwikidesign /** 39656a5d08Swikidesign * Constructor loads some config settings 4052e31fceSwikidesign */ 4152e31fceSwikidesign function helper_plugin_include() { 4252e31fceSwikidesign $this->firstsec = $this->getConf('firstseconly'); 436c836050Swikidesign $this->editbtn = $this->getConf('showeditbtn'); 446b088758Swikidesign $this->footer = $this->getConf('showfooter'); 45c44026dcSMichael Hamann $this->redirect = $this->getConf('doredirect'); 46cf0272c0Swikidesign $this->noheader = 0; 4771ec1101SGina Haeussge $this->permalink = 0; 48cf0272c0Swikidesign $this->header = array(); 492e4815a3SMichael Klier global $TOC; 502e4815a3SMichael Klier if(!empty($TOC)) $TOC = 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 126c01ce462SGina Haeussge 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) { 140c01ce462SGina Haeussge $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 254990ad87fSwikidesign $content = '<div class="entry-content">'.DOKU_LF. 255fd6f7029SGina Haeussge $xhtml.DOKU_LF. 256c01ce462SGina Haeussge '</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 264*52611c13SMichael 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 420a58d2b0aSwikidesign // add TOC item 421656a5d08Swikidesign if (($level >= $conf['toptoclevel']) && ($level <= $conf['maxtoclevel'])) { 4222e4815a3SMichael Klier $item = array( 423656a5d08Swikidesign 'hid' => $hid, 424656a5d08Swikidesign 'title' => $text, 425656a5d08Swikidesign 'type' => 'ul', 426656a5d08Swikidesign 'level' => $level - $conf['toptoclevel'] + 1 427656a5d08Swikidesign ); 4282e4815a3SMichael Klier 4292e4815a3SMichael Klier $this->renderer->toc[] = $item; 4302e4815a3SMichael Klier global $TOC; 4312e4815a3SMichael Klier $TOC[] = $item; 432f9f65fc3Swikidesign } 433f9f65fc3Swikidesign return true; 434a58d2b0aSwikidesign } 435a58d2b0aSwikidesign 436a58d2b0aSwikidesign /** 43771ec1101SGina Haeussge * Create instruction item for a permalink header 43871ec1101SGina Haeussge * 43971ec1101SGina Haeussge * @param string $text: Headline text 44071ec1101SGina Haeussge * @param integer $level: Headline level 44171ec1101SGina Haeussge * @param integer $pos: I wish I knew what this is for... 44271ec1101SGina Haeussge * 44371ec1101SGina Haeussge * @author Gina Haeussge <osd@foosel.net> 44471ec1101SGina Haeussge */ 44571ec1101SGina Haeussge function _permalinkHeader($text, $level, $pos) { 44671ec1101SGina Haeussge $newIns = array( 44771ec1101SGina Haeussge 'plugin', 44871ec1101SGina Haeussge array( 44971ec1101SGina Haeussge 'include_header', 45071ec1101SGina Haeussge array( 45171ec1101SGina Haeussge $text, 4524eb6b7abSGina Haeussge $level 45371ec1101SGina Haeussge ), 45471ec1101SGina Haeussge ), 45571ec1101SGina Haeussge $pos 45671ec1101SGina Haeussge ); 45771ec1101SGina Haeussge 45871ec1101SGina Haeussge return $newIns; 45971ec1101SGina Haeussge } 46071ec1101SGina Haeussge 46171ec1101SGina Haeussge /** 462a58d2b0aSwikidesign * Convert the level of headers and sections 463a58d2b0aSwikidesign * 464a58d2b0aSwikidesign * @param integer $in: current level 465a58d2b0aSwikidesign * @return integer $out: converted level 466a58d2b0aSwikidesign */ 467a58d2b0aSwikidesign function _convertSectionLevel($in) { 468a58d2b0aSwikidesign $out = $in + $this->_offset; 469cf0272c0Swikidesign if ($out >= 5) return 5; 470cf0272c0Swikidesign if ($out <= $this->clevel + 1) return $this->clevel + 1; 471a58d2b0aSwikidesign return $out; 472a58d2b0aSwikidesign } 473a58d2b0aSwikidesign 474a58d2b0aSwikidesign /** 475a58d2b0aSwikidesign * Adds a read more... link at the bottom of the first section 476a58d2b0aSwikidesign * 477a58d2b0aSwikidesign * @param integer $i: counter for current instruction 478a58d2b0aSwikidesign * @return boolean true 479a58d2b0aSwikidesign */ 480a58d2b0aSwikidesign function _readMore($i) { 481a58d2b0aSwikidesign $more = ((is_array($this->ins[$i+1])) && ($this->ins[$i+1][0] != 'document_end')); 482a58d2b0aSwikidesign 483a58d2b0aSwikidesign if ($this->ins[0][0] == 'document_start') $this->ins = array_slice($this->ins, 1, $i); 484a58d2b0aSwikidesign else $this->ins = array_slice($this->ins, 0, $i); 485a58d2b0aSwikidesign 486a58d2b0aSwikidesign if ($more) { 487a58d2b0aSwikidesign array_unshift($this->ins, array('document_start', array(), 0)); 488a58d2b0aSwikidesign $last = array_pop($this->ins); 489a58d2b0aSwikidesign $this->ins[] = array('p_open', array(), $last[2]); 490a58d2b0aSwikidesign $this->ins[] = array('internallink',array($this->page['id'], $this->getLang('readmore')),$last[2]); 491a58d2b0aSwikidesign $this->ins[] = array('p_close', array(), $last[2]); 492a58d2b0aSwikidesign $this->ins[] = $last; 493a58d2b0aSwikidesign $this->ins[] = array('document_end', array(), $last[2]); 494f9f65fc3Swikidesign } else { 495a58d2b0aSwikidesign $this->_finishConvert(); 496a58d2b0aSwikidesign } 497f9f65fc3Swikidesign return true; 498f9f65fc3Swikidesign } 499a58d2b0aSwikidesign 500a58d2b0aSwikidesign /** 501a58d2b0aSwikidesign * Adds 'document_start' and 'document_end' instructions if not already there 502a58d2b0aSwikidesign */ 503a58d2b0aSwikidesign function _finishConvert() { 504b088012cSwikidesign if ($this->ins[0][0] != 'document_start') 505e959a620SMichael Klier @array_unshift($this->ins, array('document_start', array(), 0)); 506b088012cSwikidesign $c = count($this->ins) - 1; 507b088012cSwikidesign if ($this->ins[$c][0] != 'document_end') 50878f60e2aSwikidesign $this->ins[] = array('document_end', array(), 0); 50978f60e2aSwikidesign } 510f9f65fc3Swikidesign 511f9f65fc3Swikidesign /** 512f9f65fc3Swikidesign * Remove TOC, section edit buttons and tags 513f9f65fc3Swikidesign */ 514f9f65fc3Swikidesign function _cleanXHTML($xhtml) { 515f9f65fc3Swikidesign $replace = array( 516f9f65fc3Swikidesign '!<div class="toc">.*?(</div>\n</div>)!s' => '', // remove toc 517f9f65fc3Swikidesign '#<!-- SECTION "(.*?)" \[(\d+-\d*)\] -->#e' => '', // remove section edit buttons 518f9f65fc3Swikidesign '!<div class="tags">.*?(</div>)!s' => '', // remove category tags 519f9f65fc3Swikidesign ); 520b088012cSwikidesign if ($this->clevel) 521b088012cSwikidesign $replace['#<div class="footnotes">#s'] = '<div class="footnotes level'.$this->clevel.'">'; 522f9f65fc3Swikidesign $xhtml = preg_replace(array_keys($replace), array_values($replace), $xhtml); 523f9f65fc3Swikidesign return $xhtml; 524f9f65fc3Swikidesign } 525f9f65fc3Swikidesign 526f9f65fc3Swikidesign /** 527fd6f7029SGina Haeussge * Convert footnotes to include page id to make them unique if more than 528fd6f7029SGina Haeussge * one page or section are included in one wiki node. (FS#93) 529fd6f7029SGina Haeussge * 530fd6f7029SGina Haeussge * Gotta admit, this fix is kind of ugly, but since we have no chance to 531fd6f7029SGina Haeussge * fix the generated footnote ids on instruction level, this has to be 532fd6f7029SGina Haeussge * done on the generated XHTML. 533fd6f7029SGina Haeussge * 534fd6f7029SGina Haeussge * @param $xhtml XHTML code of the page 535fd6f7029SGina Haeussge * @param $id included page's id 536fd6f7029SGina Haeussge * @return XHTML code with converted footnote anchors and ids 537fd6f7029SGina Haeussge * 538fd6f7029SGina Haeussge * @author Gina Haeussge <osd@foosel.net> 539fd6f7029SGina Haeussge */ 540fd6f7029SGina Haeussge function _convertFootnotes($xhtml, $id) { 541fd6f7029SGina Haeussge $id = str_replace(':', '_', $id); 542fd6f7029SGina Haeussge $replace = array( 543fd6f7029SGina Haeussge '!<a href="#fn__(\d+)" name="fnt__(\d+)" id="fnt__(\d+)" class="fn_top">!' => 544fd6f7029SGina Haeussge '<a href="#fn__'.$id.'__\1" name="fnt__'.$id.'__\2" id="fnt__'.$id.'__\3" class="fn_top">', 545fd6f7029SGina Haeussge '!<a href="#fnt__(\d+)" id="fn__(\d+)" name="fn__(\d+)" class="fn_bot">!' => 546fd6f7029SGina Haeussge '<a href="#fnt__'.$id.'__\1" name="fn__'.$id.'__\2" id="fn__'.$id.'__\3" class="fn_bot">', 547fd6f7029SGina Haeussge ); 548fd6f7029SGina Haeussge $xhtml = preg_replace(array_keys($replace), array_values($replace), $xhtml); 549fd6f7029SGina Haeussge return $xhtml; 550fd6f7029SGina Haeussge } 551fd6f7029SGina Haeussge 552fd6f7029SGina Haeussge /** 553f9f65fc3Swikidesign * Optionally display logo for the first tag found in the included page 554f9f65fc3Swikidesign */ 555f9f65fc3Swikidesign function _showTagLogos() { 556fc5d061eSwikidesign if ((!$this->getConf('showtaglogos')) 557fc5d061eSwikidesign || (plugin_isdisabled('tag')) 558fc5d061eSwikidesign || (!$taghelper =& plugin_load('helper', 'tag'))) 559fc5d061eSwikidesign return ''; 560f9f65fc3Swikidesign 561fc5d061eSwikidesign $subject = p_get_metadata($this->page['id'], 'subject'); 562fc5d061eSwikidesign if (is_array($subject)) $tag = $subject[0]; 563fc5d061eSwikidesign else list($tag, $rest) = explode(' ', $subject, 2); 564fc5d061eSwikidesign $title = str_replace('_', ' ', noNS($tag)); 565fc5d061eSwikidesign resolve_pageid($taghelper->namespace, $tag, $exists); // resolve shortcuts 566fc5d061eSwikidesign 567f9f65fc3Swikidesign $logosrc = mediaFN($logoID); 568f9f65fc3Swikidesign $types = array('.png', '.jpg', '.gif'); // auto-detect filetype 569f9f65fc3Swikidesign foreach ($types as $type) { 570f9f65fc3Swikidesign if (!@file_exists($logosrc.$type)) continue; 571fc5d061eSwikidesign $logoID = $tag.$type; 572f9f65fc3Swikidesign $logosrc .= $type; 573f9f65fc3Swikidesign list($w, $h, $t, $a) = getimagesize($logosrc); 574f9f65fc3Swikidesign return ' style="min-height: '.$h.'px">'. 575fc5d061eSwikidesign '<img class="mediaright" src="'.ml($logoID).'" alt="'.$title.'"/'; 576f9f65fc3Swikidesign } 577f9f65fc3Swikidesign return ''; 578f9f65fc3Swikidesign } 579f9f65fc3Swikidesign 580f9f65fc3Swikidesign /** 581f9f65fc3Swikidesign * Display an edit button for the included page 582f9f65fc3Swikidesign */ 583f9f65fc3Swikidesign function _editButton() { 584c44026dcSMichael Hamann global $ID; 585990ad87fSwikidesign if ($this->page['exists']) { 586f9f65fc3Swikidesign if (($this->page['perm'] >= AUTH_EDIT) && (is_writable($this->page['file']))) 587f9f65fc3Swikidesign $action = 'edit'; 588f9f65fc3Swikidesign else return ''; 589f9f65fc3Swikidesign } elseif ($this->page['perm'] >= AUTH_CREATE) { 590f9f65fc3Swikidesign $action = 'create'; 591f9f65fc3Swikidesign } 5926c836050Swikidesign if ($this->editbtn) { 593c44026dcSMichael Hamann $params = array('do' => 'edit'); 594c44026dcSMichael Hamann if ($this->redirect) 595c44026dcSMichael Hamann $params['redirect_id'] = $ID; 596f9f65fc3Swikidesign return '<div class="secedit">'.DOKU_LF.DOKU_TAB. 597c44026dcSMichael Hamann html_btn($action, $this->page['id'], '', $params, 'post').DOKU_LF. 598f9f65fc3Swikidesign '</div>'.DOKU_LF; 5993c01153cSwikidesign } else { 6003c01153cSwikidesign return ''; 6013c01153cSwikidesign } 602f9f65fc3Swikidesign } 603f9f65fc3Swikidesign 604f9f65fc3Swikidesign /** 605f9f65fc3Swikidesign * Returns the meta line below the included page 606f9f65fc3Swikidesign */ 6076b088758Swikidesign function _footer($page) { 608817828faSwikidesign global $conf, $ID; 609817828faSwikidesign 6106b088758Swikidesign if (!$this->footer) return ''; // '<div class="inclmeta"> </div>'.DOKU_LF; 611f9f65fc3Swikidesign 612b6337848Swikidesign $id = $page['id']; 613f9f65fc3Swikidesign $meta = p_get_metadata($id); 614f9f65fc3Swikidesign $ret = array(); 615f9f65fc3Swikidesign 616f9f65fc3Swikidesign // permalink 617f9f65fc3Swikidesign if ($this->getConf('showlink')) { 618b6337848Swikidesign $title = ($page['title'] ? $page['title'] : $meta['title']); 619f9f65fc3Swikidesign if (!$title) $title = str_replace('_', ' ', noNS($id)); 620656a5d08Swikidesign $class = ($page['exists'] ? 'wikilink1' : 'wikilink2'); 62139af1bf1Swikidesign $link = array( 62239af1bf1Swikidesign 'url' => wl($id), 62339af1bf1Swikidesign 'title' => $id, 62439af1bf1Swikidesign 'name' => hsc($title), 62539af1bf1Swikidesign 'target' => $conf['target']['wiki'], 626656a5d08Swikidesign 'class' => $class.' permalink', 62739af1bf1Swikidesign 'more' => 'rel="bookmark"', 62839af1bf1Swikidesign ); 62939af1bf1Swikidesign $ret[] = $this->renderer->_formatLink($link); 630f9f65fc3Swikidesign } 631f9f65fc3Swikidesign 632f9f65fc3Swikidesign // date 633f9f65fc3Swikidesign if ($this->getConf('showdate')) { 634b6337848Swikidesign $date = ($page['date'] ? $page['date'] : $meta['date']['created']); 63539af1bf1Swikidesign if ($date) 636ee335396SMichael Klier $ret[] = '<abbr class="published" title="'.strftime('%Y-%m-%dT%H:%M:%SZ', $date).'">'. 637ee335396SMichael Klier strftime($conf['dformat'], $date). 63839af1bf1Swikidesign '</abbr>'; 639f9f65fc3Swikidesign } 640f9f65fc3Swikidesign 641f9f65fc3Swikidesign // author 642f9f65fc3Swikidesign if ($this->getConf('showuser')) { 643b6337848Swikidesign $author = ($page['user'] ? $page['user'] : $meta['creator']); 644f9f65fc3Swikidesign if ($author) { 645f9f65fc3Swikidesign $userpage = cleanID($this->getConf('usernamespace').':'.$author); 64651b9ed81Swikidesign resolve_pageid(getNS($ID), $userpage, $exists); 64739af1bf1Swikidesign $class = ($exists ? 'wikilink1' : 'wikilink2'); 64839af1bf1Swikidesign $link = array( 64939af1bf1Swikidesign 'url' => wl($userpage), 65039af1bf1Swikidesign 'title' => $userpage, 65139af1bf1Swikidesign 'name' => hsc($author), 65239af1bf1Swikidesign 'target' => $conf['target']['wiki'], 65339af1bf1Swikidesign 'class' => $class.' url fn', 65439af1bf1Swikidesign 'pre' => '<span class="vcard author">', 65539af1bf1Swikidesign 'suf' => '</span>', 65639af1bf1Swikidesign ); 65739af1bf1Swikidesign $ret[] = $this->renderer->_formatLink($link); 658f9f65fc3Swikidesign } 659f9f65fc3Swikidesign } 660f9f65fc3Swikidesign 661f9f65fc3Swikidesign // comments - let Discussion Plugin do the work for us 662b6337848Swikidesign if (!$page['section'] && $this->getConf('showcomments') 663e4624397Swikidesign && (!plugin_isdisabled('discussion')) 664e4624397Swikidesign && ($discussion =& plugin_load('helper', 'discussion'))) { 665e4624397Swikidesign $disc = $discussion->td($id); 66639af1bf1Swikidesign if ($disc) $ret[] = '<span class="comment">'.$disc.'</span>'; 667f9f65fc3Swikidesign } 668f9f65fc3Swikidesign 669564e71f6Sraymond.scholz // linkbacks - let Linkback Plugin do the work for us 670564e71f6Sraymond.scholz if (!$page['section'] && $this->getConf('showlinkbacks') 671564e71f6Sraymond.scholz && (!plugin_isdisabled('linkback')) 672564e71f6Sraymond.scholz && ($linkback =& plugin_load('helper', 'linkback'))) { 673564e71f6Sraymond.scholz $link = $linkback->td($id); 674564e71f6Sraymond.scholz if ($link) $ret[] = '<span class="linkback">'.$link.'</span>'; 675564e71f6Sraymond.scholz } 676564e71f6Sraymond.scholz 677ec00fca6Swikidesign $ret = implode(DOKU_LF.DOKU_TAB.'· ', $ret); 678f9f65fc3Swikidesign 679fc5d061eSwikidesign // tags - let Tag Plugin do the work for us 680fc5d061eSwikidesign if (!$page['section'] && $this->getConf('showtags') 681fc5d061eSwikidesign && (!plugin_isdisabled('tag')) 682fc5d061eSwikidesign && ($tag =& plugin_load('helper', 'tag'))) { 683fc5d061eSwikidesign $page['tags'] = '<div class="tags"><span>'.DOKU_LF. 684fc5d061eSwikidesign DOKU_TAB.$tag->td($id).DOKU_LF. 685fc5d061eSwikidesign DOKU_TAB.'</span></div>'.DOKU_LF; 686fc5d061eSwikidesign $ret = $page['tags'].DOKU_TAB.$ret; 687f9f65fc3Swikidesign } 688f9f65fc3Swikidesign 689f9f65fc3Swikidesign if (!$ret) $ret = ' '; 690ec00fca6Swikidesign $class = 'inclmeta'; 691ec00fca6Swikidesign if ($this->header && $this->clevel && ($this->mode == 'section')) 692ec00fca6Swikidesign $class .= ' level'.$this->clevel; 693ec00fca6Swikidesign return '<div class="'.$class.'">'.DOKU_LF.DOKU_TAB.$ret.DOKU_LF.'</div>'.DOKU_LF; 694f9f65fc3Swikidesign } 695f9f65fc3Swikidesign 6961f7a99c4SMichael Klier /** 6971f7a99c4SMichael Klier * Builds the ODT to embed the page to include 6981f7a99c4SMichael Klier */ 6991f7a99c4SMichael Klier function renderODT(&$renderer) { 7001f7a99c4SMichael Klier global $ID; 7011f7a99c4SMichael Klier 7021f7a99c4SMichael Klier if (!$this->page['id']) return ''; // page must be set first 7031f7a99c4SMichael Klier if (!$this->page['exists'] && ($this->page['perm'] < AUTH_CREATE)) return ''; 7041f7a99c4SMichael Klier 7051f7a99c4SMichael Klier // prepare variable 7061f7a99c4SMichael Klier $this->renderer =& $renderer; 7071f7a99c4SMichael Klier 7081f7a99c4SMichael Klier // get instructions and render them on the fly 7091f7a99c4SMichael Klier $this->ins = p_cached_instructions($this->page['file']); 7101f7a99c4SMichael Klier 7111f7a99c4SMichael Klier // show only a given section? 7121f7a99c4SMichael Klier if ($this->page['section'] && $this->page['exists']) $this->_getSection(); 7131f7a99c4SMichael Klier 7141f7a99c4SMichael Klier // convert relative links 7151f7a99c4SMichael Klier $this->_convertInstructions(); 7161f7a99c4SMichael Klier 7171f7a99c4SMichael Klier // render the included page 7181f7a99c4SMichael Klier $backupID = $ID; // store the current ID 7191f7a99c4SMichael Klier $ID = $this->page['id']; // change ID to the included page 7201f7a99c4SMichael Klier // remove document_start and document_end to avoid zipping 7211f7a99c4SMichael Klier $this->ins = array_slice($this->ins, 1, -1); 7221f7a99c4SMichael Klier p_render('odt', $this->ins, $info); 7231f7a99c4SMichael Klier $ID = $backupID; // restore ID 7241f7a99c4SMichael Klier // reset defaults 7251f7a99c4SMichael Klier $this->helper_plugin_include(); 7261f7a99c4SMichael Klier } 727f9f65fc3Swikidesign} 728df4e907bSMichael Klier//vim:ts=4:sw=4:et:enc=utf-8: 729