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(); 4952e31fceSwikidesign } 5052e31fceSwikidesign 51f9f65fc3Swikidesign function getInfo() { 52f9f65fc3Swikidesign return array( 5371ec1101SGina Haeussge 'author' => 'Gina Häußge, Michael Klier, Esther Brunner', 54dbdadbd9SGina Haeussge 'email' => 'dokuwiki@chimeric.de', 554052f233SGina Haeussge 'date' => @file_get_contents(DOKU_PLUGIN . 'blog/VERSION'), 56f9f65fc3Swikidesign 'name' => 'Include Plugin (helper class)', 57f9f65fc3Swikidesign 'desc' => 'Functions to include another page in a wiki page', 581f7a99c4SMichael Klier 'url' => 'http://wiki.splitbrain.org/plugin:include', 59f9f65fc3Swikidesign ); 60f9f65fc3Swikidesign } 61f9f65fc3Swikidesign 62f9f65fc3Swikidesign function getMethods() { 63f9f65fc3Swikidesign $result = array(); 64f9f65fc3Swikidesign $result[] = array( 65f9f65fc3Swikidesign 'name' => 'setPage', 66f9f65fc3Swikidesign 'desc' => 'sets the page to include', 67f9f65fc3Swikidesign 'params' => array("page attributes, 'id' required, 'section' for filtering" => 'array'), 68f9f65fc3Swikidesign 'return' => array('success' => 'boolean'), 69f9f65fc3Swikidesign ); 70f9f65fc3Swikidesign $result[] = array( 71f9f65fc3Swikidesign 'name' => 'setMode', 72f9f65fc3Swikidesign 'desc' => 'sets inclusion mode: should indention be merged?', 73f9f65fc3Swikidesign 'params' => array("'page' (original) or 'section' (merged indention)" => 'string'), 74f9f65fc3Swikidesign ); 75f9f65fc3Swikidesign $result[] = array( 76f9f65fc3Swikidesign 'name' => 'setLevel', 77f9f65fc3Swikidesign 'desc' => 'sets the indention for the current section level', 78f9f65fc3Swikidesign 'params' => array('level: 0 to 5' => 'integer'), 79f9f65fc3Swikidesign 'return' => array('success' => 'boolean'), 80f9f65fc3Swikidesign ); 81f9f65fc3Swikidesign $result[] = array( 82656a5d08Swikidesign 'name' => 'setFlags', 836b088758Swikidesign 'desc' => 'overrides standard values for showfooter and firstseconly settings', 84656a5d08Swikidesign 'params' => array('flags' => 'array'), 85656a5d08Swikidesign ); 86656a5d08Swikidesign $result[] = array( 87b6337848Swikidesign 'name' => 'renderXHTML', 88b6337848Swikidesign 'desc' => 'renders the XHTML output of the included page', 89f9f65fc3Swikidesign 'params' => array('DokuWiki renderer' => 'object'), 90b6337848Swikidesign 'return' => array('XHTML' => 'string'), 91f9f65fc3Swikidesign ); 92f9f65fc3Swikidesign return $result; 93f9f65fc3Swikidesign } 94f9f65fc3Swikidesign 95f9f65fc3Swikidesign /** 96f9f65fc3Swikidesign * Sets the page to include if it is not already included (prevent recursion) 97990ad87fSwikidesign * and the current user is allowed to read it 98f9f65fc3Swikidesign */ 99f9f65fc3Swikidesign function setPage($page) { 100f9f65fc3Swikidesign global $ID; 101f9f65fc3Swikidesign 102b6337848Swikidesign $id = $page['id']; 103b6337848Swikidesign $fullid = $id.'#'.$page['section']; 104f9f65fc3Swikidesign 105b6337848Swikidesign if (!$id) return false; // no page id given 106b6337848Swikidesign if ($id == $ID) return false; // page can't include itself 107f9f65fc3Swikidesign 108b6337848Swikidesign // prevent include recursion 109c01ce462SGina Haeussge if ($this->_in_filechain($id,$page['section']) || (count($this->pages) >= $this->INCLUDE_LIMIT)) return false; 110b6337848Swikidesign 111990ad87fSwikidesign // we need to make sure 'perm', 'file' and 'exists' are set 112990ad87fSwikidesign if (!isset($page['perm'])) $page['perm'] = auth_quickaclcheck($page['id']); 113990ad87fSwikidesign if (!isset($page['file'])) $page['file'] = wikiFN($page['id']); 114990ad87fSwikidesign if (!isset($page['exists'])) $page['exists'] = @file_exists($page['file']); 115990ad87fSwikidesign 116990ad87fSwikidesign // check permission 117f83ac5f7Swikidesign if ($page['perm'] < AUTH_READ) return false; 118990ad87fSwikidesign 119b6337848Swikidesign // add the page to the filechain 120c01ce462SGina Haeussge $this->page = $page; 121f9f65fc3Swikidesign return true; 122f9f65fc3Swikidesign } 123f9f65fc3Swikidesign 124c01ce462SGina Haeussge function _push_page($id,$section) { 125c01ce462SGina Haeussge global $ID; 126c01ce462SGina Haeussge if (empty($this->pages)) array_push($this->pages, $ID.'#'); 127c01ce462SGina Haeussge array_push($this->pages, $id.'#'.$section); 128c01ce462SGina Haeussge } 129c01ce462SGina Haeussge 130c01ce462SGina Haeussge function _pop_page() { 131c01ce462SGina Haeussge $page = array_pop($this->pages); 132c01ce462SGina Haeussge if (count($this->pages=1)) $this->pages = array(); 133c01ce462SGina Haeussge 134c01ce462SGina Haeussge return $page; 135c01ce462SGina Haeussge } 136c01ce462SGina Haeussge 137c01ce462SGina Haeussge function _in_filechain($id,$section) { 138c01ce462SGina Haeussge $pattern = $section ? "/^($id#$section|$id#)$/" : "/^$id#/"; 139c01ce462SGina Haeussge $match = preg_grep($pattern, $this->pages); 140c01ce462SGina Haeussge 141c01ce462SGina Haeussge return (!empty($match)); 142c01ce462SGina Haeussge } 143c01ce462SGina Haeussge 144f9f65fc3Swikidesign /** 145a3a7e530Swikidesign * Sets the inclusion mode: 'page' or 'section' 146f9f65fc3Swikidesign */ 147f9f65fc3Swikidesign function setMode($mode) { 148f9f65fc3Swikidesign $this->mode = $mode; 149f9f65fc3Swikidesign } 150f9f65fc3Swikidesign 151f9f65fc3Swikidesign /** 152f9f65fc3Swikidesign * Sets the right indention for a given section level 153f9f65fc3Swikidesign */ 154f9f65fc3Swikidesign function setLevel($level) { 155f9f65fc3Swikidesign if ((is_numeric($level)) && ($level >= 0) && ($level <= 5)) { 156f9f65fc3Swikidesign $this->clevel = $level; 157f9f65fc3Swikidesign return true; 158f9f65fc3Swikidesign } 159f9f65fc3Swikidesign return false; 160f9f65fc3Swikidesign } 161f9f65fc3Swikidesign 162f9f65fc3Swikidesign /** 1636b088758Swikidesign * Overrides standard values for showfooter and firstseconly settings 164656a5d08Swikidesign */ 165656a5d08Swikidesign function setFlags($flags) { 166656a5d08Swikidesign foreach ($flags as $flag) { 167656a5d08Swikidesign switch ($flag) { 1686b088758Swikidesign case 'footer': 1696b088758Swikidesign $this->footer = 1; 170656a5d08Swikidesign break; 1716b088758Swikidesign case 'nofooter': 1726b088758Swikidesign $this->footer = 0; 173656a5d08Swikidesign break; 174656a5d08Swikidesign case 'firstseconly': 17543dcb6deSwikidesign case 'firstsectiononly': 176656a5d08Swikidesign $this->firstsec = 1; 177656a5d08Swikidesign break; 178656a5d08Swikidesign case 'fullpage': 179656a5d08Swikidesign $this->firstsec = 0; 180656a5d08Swikidesign break; 181990ad87fSwikidesign case 'noheader': 182990ad87fSwikidesign $this->noheader = 1; 183990ad87fSwikidesign break; 18443dcb6deSwikidesign case 'editbtn': 185a3a7e530Swikidesign case 'editbutton': 1866c836050Swikidesign $this->editbtn = 1; 1876c836050Swikidesign break; 18843dcb6deSwikidesign case 'noeditbtn': 189a3a7e530Swikidesign case 'noeditbutton': 1906c836050Swikidesign $this->editbtn = 0; 1916c836050Swikidesign break; 19271ec1101SGina Haeussge case 'permalink': 19371ec1101SGina Haeussge $this->permalink = 1; 19471ec1101SGina Haeussge break; 19571ec1101SGina Haeussge case 'nopermalink': 19671ec1101SGina Haeussge $this->permalink = 0; 19771ec1101SGina Haeussge break; 198c44026dcSMichael Hamann case 'redirect': 199c44026dcSMichael Hamann $this->redirect = 1; 200c44026dcSMichael Hamann break; 201c44026dcSMichael Hamann case 'noredirect': 202c44026dcSMichael Hamann $this->redirect = 0; 203c44026dcSMichael Hamann break; 204656a5d08Swikidesign } 205656a5d08Swikidesign } 206656a5d08Swikidesign } 207656a5d08Swikidesign 208656a5d08Swikidesign /** 209f9f65fc3Swikidesign * Builds the XHTML to embed the page to include 210f9f65fc3Swikidesign */ 211c01ce462SGina Haeussge function renderXHTML(&$renderer, &$info) { 21251b9ed81Swikidesign global $ID; 21351b9ed81Swikidesign 214b6337848Swikidesign if (!$this->page['id']) return ''; // page must be set first 21558de0a6fSwikidesign if (!$this->page['exists'] && ($this->page['perm'] < AUTH_CREATE)) return ''; 216f9f65fc3Swikidesign 217c01ce462SGina Haeussge $this->_push_page($this->page['id'],$this->page['section']); 218c01ce462SGina Haeussge 21952e31fceSwikidesign // prepare variables 220c01ce462SGina Haeussge $rdoc = $renderer->doc; 221c01ce462SGina Haeussge $doc = ''; 22239af1bf1Swikidesign $this->renderer =& $renderer; 223f9f65fc3Swikidesign 224c01ce462SGina Haeussge $page = $this->page; 225c01ce462SGina Haeussge $clevel = $this->clevel; 226c01ce462SGina Haeussge $mode = $this->mode; 227c01ce462SGina Haeussge 2288c434f1aSGina Haeussge // exchange page ID for included one 2298c434f1aSGina Haeussge $backupID = $ID; // store the current ID 2308c434f1aSGina Haeussge $ID = $this->page['id']; // change ID to the included page 2318c434f1aSGina Haeussge 232f9f65fc3Swikidesign // get instructions and render them on the fly 233f9f65fc3Swikidesign $this->ins = p_cached_instructions($this->page['file']); 234f9f65fc3Swikidesign 235f9f65fc3Swikidesign // show only a given section? 236656a5d08Swikidesign if ($this->page['section'] && $this->page['exists']) $this->_getSection(); 237f9f65fc3Swikidesign 238f9f65fc3Swikidesign // convert relative links 23939af1bf1Swikidesign $this->_convertInstructions(); 240f9f65fc3Swikidesign 241c01ce462SGina Haeussge $xhtml = p_render('xhtml', $this->ins, $info); 242c01ce462SGina Haeussge $ID = $backupID; // restore ID 243c01ce462SGina Haeussge 244c01ce462SGina Haeussge $this->mode = $mode; 245c01ce462SGina Haeussge $this->clevel = $clevel; 246c01ce462SGina Haeussge $this->page = $page; 247c01ce462SGina Haeussge 248fd6f7029SGina Haeussge $xhtml = $this->_cleanXHTML($xhtml); 249fd6f7029SGina Haeussge $xhtml = $this->_convertFootnotes($xhtml, $this->page['id']); 250fd6f7029SGina Haeussge 251f9f65fc3Swikidesign // render the included page 252990ad87fSwikidesign $content = '<div class="entry-content">'.DOKU_LF. 253fd6f7029SGina Haeussge $xhtml.DOKU_LF. 254c01ce462SGina Haeussge '</div><!-- .entry-content -->'.DOKU_LF; 2558c434f1aSGina Haeussge 2568c434f1aSGina Haeussge // restore ID 2578c434f1aSGina Haeussge $ID = $backupID; 258f9f65fc3Swikidesign 259f9f65fc3Swikidesign // embed the included page 260e62bb8f0Swikidesign $class = ($this->page['draft'] ? 'include draft' : 'include'); 261c01ce462SGina Haeussge 262c01ce462SGina Haeussge $doc .= DOKU_LF.'<!-- including '.$this->page['id'].' // '.$this->page['file'].' -->'.DOKU_LF; 263c01ce462SGina Haeussge $doc .= '<div class="'.$class.' hentry"'.$this->_showTagLogos().'>'.DOKU_LF; 26439af1bf1Swikidesign if (!$this->header && $this->clevel && ($this->mode == 'section')) 265c01ce462SGina Haeussge $doc .= '<div class="level'.$this->clevel.'">'.DOKU_LF; 266c01ce462SGina Haeussge 2678d99695dSwikidesign if ((@file_exists(DOKU_PLUGIN.'editsections/action.php')) 2688d99695dSwikidesign && (!plugin_isdisabled('editsections'))) { // for Edit Section Reorganizer Plugin 269c01ce462SGina Haeussge $doc .= $this->_editButton().$content; 2706cad866dSwikidesign } else { 271c01ce462SGina Haeussge $doc .= $content.$this->_editButton(); 2726cad866dSwikidesign } 273656a5d08Swikidesign 274ec00fca6Swikidesign // output meta line (if wanted) and remove page from filechain 275c01ce462SGina Haeussge $doc .= $this->_footer($this->page); 276ec00fca6Swikidesign 27739af1bf1Swikidesign if (!$this->header && $this->clevel && ($this->mode == 'section')) 278c01ce462SGina Haeussge $doc .= '</div>'.DOKU_LF; // class="level?" 279c01ce462SGina Haeussge $doc .= '</div>'.DOKU_LF; // class="include hentry" 280c01ce462SGina Haeussge $doc .= DOKU_LF.'<!-- /including '.$this->page['id'].' -->'.DOKU_LF; 281f9f65fc3Swikidesign 282ec00fca6Swikidesign // reset defaults 283656a5d08Swikidesign $this->helper_plugin_include(); 284c01ce462SGina Haeussge $this->_pop_page(); 285f9f65fc3Swikidesign 286ec00fca6Swikidesign // return XHTML 287c01ce462SGina Haeussge $renderer->doc = $rdoc.$doc; 288c01ce462SGina Haeussge return $doc; 289f9f65fc3Swikidesign } 290f9f65fc3Swikidesign 291f9f65fc3Swikidesign /* ---------- Private Methods ---------- */ 292f9f65fc3Swikidesign 293f9f65fc3Swikidesign /** 294f9f65fc3Swikidesign * Get a section including its subsections 295f9f65fc3Swikidesign */ 296f9f65fc3Swikidesign function _getSection() { 297f9f65fc3Swikidesign foreach ($this->ins as $ins) { 298f9f65fc3Swikidesign if ($ins[0] == 'header') { 299f9f65fc3Swikidesign 300f9f65fc3Swikidesign // found the right header 301f9f65fc3Swikidesign if (cleanID($ins[1][0]) == $this->page['section']) { 302f9f65fc3Swikidesign $level = $ins[1][1]; 303f9f65fc3Swikidesign $i[] = $ins; 304f9f65fc3Swikidesign 305f9f65fc3Swikidesign // next header of the same or higher level -> exit 306f9f65fc3Swikidesign } elseif ($ins[1][1] <= $level) { 307f9f65fc3Swikidesign $this->ins = $i; 308f9f65fc3Swikidesign return true; 309f9f65fc3Swikidesign } elseif (isset($level)) { 310f9f65fc3Swikidesign $i[] = $ins; 311f9f65fc3Swikidesign } 312f9f65fc3Swikidesign 313f9f65fc3Swikidesign // add instructions from our section 314f9f65fc3Swikidesign } elseif (isset($level)) { 315f9f65fc3Swikidesign $i[] = $ins; 316f9f65fc3Swikidesign } 317f9f65fc3Swikidesign } 318f9f65fc3Swikidesign $this->ins = $i; 319f9f65fc3Swikidesign return true; 320f9f65fc3Swikidesign } 321f9f65fc3Swikidesign 322f9f65fc3Swikidesign /** 323f9f65fc3Swikidesign * Corrects relative internal links and media and 324f9f65fc3Swikidesign * converts headers of included pages to subheaders of the current page 325f9f65fc3Swikidesign */ 32639af1bf1Swikidesign function _convertInstructions() { 32751b9ed81Swikidesign global $ID; 32851b9ed81Swikidesign 32958de0a6fSwikidesign if (!$this->page['exists']) return false; 33058de0a6fSwikidesign 331f9f65fc3Swikidesign // check if included page is in same namespace 3329a79957fSwikidesign $ns = getNS($this->page['id']); 33351b9ed81Swikidesign $convert = (getNS($ID) == $ns ? false : true); 334f9f65fc3Swikidesign 335f9f65fc3Swikidesign $n = count($this->ins); 336f9f65fc3Swikidesign for ($i = 0; $i < $n; $i++) { 337a58d2b0aSwikidesign $current = $this->ins[$i][0]; 338f9f65fc3Swikidesign 339f9f65fc3Swikidesign // convert internal links and media from relative to absolute 340a58d2b0aSwikidesign if ($convert && (substr($current, 0, 8) == 'internal')) { 3419a79957fSwikidesign $this->ins[$i][1][0] = $this->_convertInternalLink($this->ins[$i][1][0], $ns); 342a58d2b0aSwikidesign 343a58d2b0aSwikidesign // set header level to current section level + header level 344a58d2b0aSwikidesign } elseif ($current == 'header') { 3459a79957fSwikidesign $this->_convertHeader($i); 346a58d2b0aSwikidesign 347a58d2b0aSwikidesign // the same for sections 3489a79957fSwikidesign } elseif (($current == 'section_open') && ($this->mode == 'section')) { 349a58d2b0aSwikidesign $this->ins[$i][1][0] = $this->_convertSectionLevel($this->ins[$i][1][0]); 350a58d2b0aSwikidesign 351a58d2b0aSwikidesign // show only the first section? 352a58d2b0aSwikidesign } elseif ($this->firstsec && ($current == 'section_close') 353a58d2b0aSwikidesign && ($this->ins[$i-1][0] != 'section_open')) { 354a58d2b0aSwikidesign $this->_readMore($i); 355a58d2b0aSwikidesign return true; 356a58d2b0aSwikidesign } 357a58d2b0aSwikidesign } 358a58d2b0aSwikidesign $this->_finishConvert(); 359a58d2b0aSwikidesign return true; 360a58d2b0aSwikidesign } 361a58d2b0aSwikidesign 362a58d2b0aSwikidesign /** 363a58d2b0aSwikidesign * Convert relative internal links and media 364a58d2b0aSwikidesign * 365a58d2b0aSwikidesign * @param integer $i: counter for current instruction 366a58d2b0aSwikidesign * @param string $ns: namespace of included page 367a58d2b0aSwikidesign * @return string $link: converted, now absolute link 368a58d2b0aSwikidesign */ 3699a79957fSwikidesign function _convertInternalLink($link, $ns) { 370f9f65fc3Swikidesign 371f9f65fc3Swikidesign // relative subnamespace 3729a79957fSwikidesign if ($link{0} == '.') { 3739a79957fSwikidesign if ($link{1} == '.') return getNS($ns).':'.substr($link, 2); // parent namespace 3749a79957fSwikidesign else return $ns.':'.substr($link, 1); // current namespace 375f9f65fc3Swikidesign 376f9f65fc3Swikidesign // relative link 3779a79957fSwikidesign } elseif (strpos($link, ':') === false) { 3789a79957fSwikidesign return $ns.':'.$link; 3799a79957fSwikidesign 3809a79957fSwikidesign // absolute link - don't change 3819a79957fSwikidesign } else { 3829a79957fSwikidesign return $link; 383a58d2b0aSwikidesign } 384f9f65fc3Swikidesign } 385f9f65fc3Swikidesign 386a58d2b0aSwikidesign /** 387a58d2b0aSwikidesign * Convert header level and add header to TOC 388a58d2b0aSwikidesign * 389a58d2b0aSwikidesign * @param integer $i: counter for current instruction 390a58d2b0aSwikidesign * @return boolean true 391a58d2b0aSwikidesign */ 3929a79957fSwikidesign function _convertHeader($i) { 393cf0272c0Swikidesign global $conf; 394cf0272c0Swikidesign 395f9f65fc3Swikidesign $text = $this->ins[$i][1][0]; 39639af1bf1Swikidesign $hid = $this->renderer->_headerToLink($text, 'true'); 397b448b725Swikidesign if (empty($this->header)) { 398a58d2b0aSwikidesign $this->_offset = $this->clevel - $this->ins[$i][1][1] + 1; 399cf0272c0Swikidesign $level = $this->_convertSectionLevel(1); 400cf0272c0Swikidesign $this->header = array('hid' => $hid, 'title' => hsc($text), 'level' => $level); 401990ad87fSwikidesign if ($this->noheader) { 40239af1bf1Swikidesign unset($this->ins[$i]); 403990ad87fSwikidesign return true; 40471ec1101SGina Haeussge } else if ($this->permalink){ 4054eb6b7abSGina Haeussge $this->ins[$i] = $this->_permalinkHeader($text, $level, $this->ins[$i][1][2]); 406990ad87fSwikidesign } 407656a5d08Swikidesign } else { 408a58d2b0aSwikidesign $level = $this->_convertSectionLevel($this->ins[$i][1][1]); 40939af1bf1Swikidesign } 41071ec1101SGina Haeussge if ($this->mode == 'section') { 4114eb6b7abSGina Haeussge if (is_array($this->ins[$i][1][1])) { // permalink header 41271ec1101SGina Haeussge $this->ins[$i][1][1][1] = $level; 4134eb6b7abSGina Haeussge } else { // normal header 41471ec1101SGina Haeussge $this->ins[$i][1][1] = $level; 41571ec1101SGina Haeussge } 41671ec1101SGina Haeussge } 417990ad87fSwikidesign 418a58d2b0aSwikidesign // add TOC item 419656a5d08Swikidesign if (($level >= $conf['toptoclevel']) && ($level <= $conf['maxtoclevel'])) { 420656a5d08Swikidesign $this->renderer->toc[] = array( 421656a5d08Swikidesign 'hid' => $hid, 422656a5d08Swikidesign 'title' => $text, 423656a5d08Swikidesign 'type' => 'ul', 424656a5d08Swikidesign 'level' => $level - $conf['toptoclevel'] + 1 425656a5d08Swikidesign ); 426f9f65fc3Swikidesign } 427f9f65fc3Swikidesign return true; 428a58d2b0aSwikidesign } 429a58d2b0aSwikidesign 430a58d2b0aSwikidesign /** 43171ec1101SGina Haeussge * Create instruction item for a permalink header 43271ec1101SGina Haeussge * 43371ec1101SGina Haeussge * @param string $text: Headline text 43471ec1101SGina Haeussge * @param integer $level: Headline level 43571ec1101SGina Haeussge * @param integer $pos: I wish I knew what this is for... 43671ec1101SGina Haeussge * 43771ec1101SGina Haeussge * @author Gina Haeussge <osd@foosel.net> 43871ec1101SGina Haeussge */ 43971ec1101SGina Haeussge function _permalinkHeader($text, $level, $pos) { 44071ec1101SGina Haeussge $newIns = array( 44171ec1101SGina Haeussge 'plugin', 44271ec1101SGina Haeussge array( 44371ec1101SGina Haeussge 'include_header', 44471ec1101SGina Haeussge array( 44571ec1101SGina Haeussge $text, 4464eb6b7abSGina Haeussge $level 44771ec1101SGina Haeussge ), 44871ec1101SGina Haeussge ), 44971ec1101SGina Haeussge $pos 45071ec1101SGina Haeussge ); 45171ec1101SGina Haeussge 45271ec1101SGina Haeussge return $newIns; 45371ec1101SGina Haeussge } 45471ec1101SGina Haeussge 45571ec1101SGina Haeussge /** 456a58d2b0aSwikidesign * Convert the level of headers and sections 457a58d2b0aSwikidesign * 458a58d2b0aSwikidesign * @param integer $in: current level 459a58d2b0aSwikidesign * @return integer $out: converted level 460a58d2b0aSwikidesign */ 461a58d2b0aSwikidesign function _convertSectionLevel($in) { 462a58d2b0aSwikidesign $out = $in + $this->_offset; 463cf0272c0Swikidesign if ($out >= 5) return 5; 464cf0272c0Swikidesign if ($out <= $this->clevel + 1) return $this->clevel + 1; 465a58d2b0aSwikidesign return $out; 466a58d2b0aSwikidesign } 467a58d2b0aSwikidesign 468a58d2b0aSwikidesign /** 469a58d2b0aSwikidesign * Adds a read more... link at the bottom of the first section 470a58d2b0aSwikidesign * 471a58d2b0aSwikidesign * @param integer $i: counter for current instruction 472a58d2b0aSwikidesign * @return boolean true 473a58d2b0aSwikidesign */ 474a58d2b0aSwikidesign function _readMore($i) { 475a58d2b0aSwikidesign $more = ((is_array($this->ins[$i+1])) && ($this->ins[$i+1][0] != 'document_end')); 476a58d2b0aSwikidesign 477a58d2b0aSwikidesign if ($this->ins[0][0] == 'document_start') $this->ins = array_slice($this->ins, 1, $i); 478a58d2b0aSwikidesign else $this->ins = array_slice($this->ins, 0, $i); 479a58d2b0aSwikidesign 480a58d2b0aSwikidesign if ($more) { 481a58d2b0aSwikidesign array_unshift($this->ins, array('document_start', array(), 0)); 482a58d2b0aSwikidesign $last = array_pop($this->ins); 483a58d2b0aSwikidesign $this->ins[] = array('p_open', array(), $last[2]); 484a58d2b0aSwikidesign $this->ins[] = array('internallink',array($this->page['id'], $this->getLang('readmore')),$last[2]); 485a58d2b0aSwikidesign $this->ins[] = array('p_close', array(), $last[2]); 486a58d2b0aSwikidesign $this->ins[] = $last; 487a58d2b0aSwikidesign $this->ins[] = array('document_end', array(), $last[2]); 488f9f65fc3Swikidesign } else { 489a58d2b0aSwikidesign $this->_finishConvert(); 490a58d2b0aSwikidesign } 491f9f65fc3Swikidesign return true; 492f9f65fc3Swikidesign } 493a58d2b0aSwikidesign 494a58d2b0aSwikidesign /** 495a58d2b0aSwikidesign * Adds 'document_start' and 'document_end' instructions if not already there 496a58d2b0aSwikidesign */ 497a58d2b0aSwikidesign function _finishConvert() { 498b088012cSwikidesign if ($this->ins[0][0] != 'document_start') 499*e959a620SMichael Klier @array_unshift($this->ins, array('document_start', array(), 0)); 500b088012cSwikidesign $c = count($this->ins) - 1; 501b088012cSwikidesign if ($this->ins[$c][0] != 'document_end') 50278f60e2aSwikidesign $this->ins[] = array('document_end', array(), 0); 50378f60e2aSwikidesign } 504f9f65fc3Swikidesign 505f9f65fc3Swikidesign /** 506f9f65fc3Swikidesign * Remove TOC, section edit buttons and tags 507f9f65fc3Swikidesign */ 508f9f65fc3Swikidesign function _cleanXHTML($xhtml) { 509f9f65fc3Swikidesign $replace = array( 510f9f65fc3Swikidesign '!<div class="toc">.*?(</div>\n</div>)!s' => '', // remove toc 511f9f65fc3Swikidesign '#<!-- SECTION "(.*?)" \[(\d+-\d*)\] -->#e' => '', // remove section edit buttons 512f9f65fc3Swikidesign '!<div class="tags">.*?(</div>)!s' => '', // remove category tags 513f9f65fc3Swikidesign ); 514b088012cSwikidesign if ($this->clevel) 515b088012cSwikidesign $replace['#<div class="footnotes">#s'] = '<div class="footnotes level'.$this->clevel.'">'; 516f9f65fc3Swikidesign $xhtml = preg_replace(array_keys($replace), array_values($replace), $xhtml); 517f9f65fc3Swikidesign return $xhtml; 518f9f65fc3Swikidesign } 519f9f65fc3Swikidesign 520f9f65fc3Swikidesign /** 521fd6f7029SGina Haeussge * Convert footnotes to include page id to make them unique if more than 522fd6f7029SGina Haeussge * one page or section are included in one wiki node. (FS#93) 523fd6f7029SGina Haeussge * 524fd6f7029SGina Haeussge * Gotta admit, this fix is kind of ugly, but since we have no chance to 525fd6f7029SGina Haeussge * fix the generated footnote ids on instruction level, this has to be 526fd6f7029SGina Haeussge * done on the generated XHTML. 527fd6f7029SGina Haeussge * 528fd6f7029SGina Haeussge * @param $xhtml XHTML code of the page 529fd6f7029SGina Haeussge * @param $id included page's id 530fd6f7029SGina Haeussge * @return XHTML code with converted footnote anchors and ids 531fd6f7029SGina Haeussge * 532fd6f7029SGina Haeussge * @author Gina Haeussge <osd@foosel.net> 533fd6f7029SGina Haeussge */ 534fd6f7029SGina Haeussge function _convertFootnotes($xhtml, $id) { 535fd6f7029SGina Haeussge $id = str_replace(':', '_', $id); 536fd6f7029SGina Haeussge $replace = array( 537fd6f7029SGina Haeussge '!<a href="#fn__(\d+)" name="fnt__(\d+)" id="fnt__(\d+)" class="fn_top">!' => 538fd6f7029SGina Haeussge '<a href="#fn__'.$id.'__\1" name="fnt__'.$id.'__\2" id="fnt__'.$id.'__\3" class="fn_top">', 539fd6f7029SGina Haeussge '!<a href="#fnt__(\d+)" id="fn__(\d+)" name="fn__(\d+)" class="fn_bot">!' => 540fd6f7029SGina Haeussge '<a href="#fnt__'.$id.'__\1" name="fn__'.$id.'__\2" id="fn__'.$id.'__\3" class="fn_bot">', 541fd6f7029SGina Haeussge ); 542fd6f7029SGina Haeussge $xhtml = preg_replace(array_keys($replace), array_values($replace), $xhtml); 543fd6f7029SGina Haeussge return $xhtml; 544fd6f7029SGina Haeussge } 545fd6f7029SGina Haeussge 546fd6f7029SGina Haeussge /** 547f9f65fc3Swikidesign * Optionally display logo for the first tag found in the included page 548f9f65fc3Swikidesign */ 549f9f65fc3Swikidesign function _showTagLogos() { 550fc5d061eSwikidesign if ((!$this->getConf('showtaglogos')) 551fc5d061eSwikidesign || (plugin_isdisabled('tag')) 552fc5d061eSwikidesign || (!$taghelper =& plugin_load('helper', 'tag'))) 553fc5d061eSwikidesign return ''; 554f9f65fc3Swikidesign 555fc5d061eSwikidesign $subject = p_get_metadata($this->page['id'], 'subject'); 556fc5d061eSwikidesign if (is_array($subject)) $tag = $subject[0]; 557fc5d061eSwikidesign else list($tag, $rest) = explode(' ', $subject, 2); 558fc5d061eSwikidesign $title = str_replace('_', ' ', noNS($tag)); 559fc5d061eSwikidesign resolve_pageid($taghelper->namespace, $tag, $exists); // resolve shortcuts 560fc5d061eSwikidesign 561f9f65fc3Swikidesign $logosrc = mediaFN($logoID); 562f9f65fc3Swikidesign $types = array('.png', '.jpg', '.gif'); // auto-detect filetype 563f9f65fc3Swikidesign foreach ($types as $type) { 564f9f65fc3Swikidesign if (!@file_exists($logosrc.$type)) continue; 565fc5d061eSwikidesign $logoID = $tag.$type; 566f9f65fc3Swikidesign $logosrc .= $type; 567f9f65fc3Swikidesign list($w, $h, $t, $a) = getimagesize($logosrc); 568f9f65fc3Swikidesign return ' style="min-height: '.$h.'px">'. 569fc5d061eSwikidesign '<img class="mediaright" src="'.ml($logoID).'" alt="'.$title.'"/'; 570f9f65fc3Swikidesign } 571f9f65fc3Swikidesign return ''; 572f9f65fc3Swikidesign } 573f9f65fc3Swikidesign 574f9f65fc3Swikidesign /** 575f9f65fc3Swikidesign * Display an edit button for the included page 576f9f65fc3Swikidesign */ 577f9f65fc3Swikidesign function _editButton() { 578c44026dcSMichael Hamann global $ID; 579990ad87fSwikidesign if ($this->page['exists']) { 580f9f65fc3Swikidesign if (($this->page['perm'] >= AUTH_EDIT) && (is_writable($this->page['file']))) 581f9f65fc3Swikidesign $action = 'edit'; 582f9f65fc3Swikidesign else return ''; 583f9f65fc3Swikidesign } elseif ($this->page['perm'] >= AUTH_CREATE) { 584f9f65fc3Swikidesign $action = 'create'; 585f9f65fc3Swikidesign } 5866c836050Swikidesign if ($this->editbtn) { 587c44026dcSMichael Hamann $params = array('do' => 'edit'); 588c44026dcSMichael Hamann if ($this->redirect) 589c44026dcSMichael Hamann $params['redirect_id'] = $ID; 590f9f65fc3Swikidesign return '<div class="secedit">'.DOKU_LF.DOKU_TAB. 591c44026dcSMichael Hamann html_btn($action, $this->page['id'], '', $params, 'post').DOKU_LF. 592f9f65fc3Swikidesign '</div>'.DOKU_LF; 5933c01153cSwikidesign } else { 5943c01153cSwikidesign return ''; 5953c01153cSwikidesign } 596f9f65fc3Swikidesign } 597f9f65fc3Swikidesign 598f9f65fc3Swikidesign /** 599f9f65fc3Swikidesign * Returns the meta line below the included page 600f9f65fc3Swikidesign */ 6016b088758Swikidesign function _footer($page) { 602817828faSwikidesign global $conf, $ID; 603817828faSwikidesign 6046b088758Swikidesign if (!$this->footer) return ''; // '<div class="inclmeta"> </div>'.DOKU_LF; 605f9f65fc3Swikidesign 606b6337848Swikidesign $id = $page['id']; 607f9f65fc3Swikidesign $meta = p_get_metadata($id); 608f9f65fc3Swikidesign $ret = array(); 609f9f65fc3Swikidesign 610f9f65fc3Swikidesign // permalink 611f9f65fc3Swikidesign if ($this->getConf('showlink')) { 612b6337848Swikidesign $title = ($page['title'] ? $page['title'] : $meta['title']); 613f9f65fc3Swikidesign if (!$title) $title = str_replace('_', ' ', noNS($id)); 614656a5d08Swikidesign $class = ($page['exists'] ? 'wikilink1' : 'wikilink2'); 61539af1bf1Swikidesign $link = array( 61639af1bf1Swikidesign 'url' => wl($id), 61739af1bf1Swikidesign 'title' => $id, 61839af1bf1Swikidesign 'name' => hsc($title), 61939af1bf1Swikidesign 'target' => $conf['target']['wiki'], 620656a5d08Swikidesign 'class' => $class.' permalink', 62139af1bf1Swikidesign 'more' => 'rel="bookmark"', 62239af1bf1Swikidesign ); 62339af1bf1Swikidesign $ret[] = $this->renderer->_formatLink($link); 624f9f65fc3Swikidesign } 625f9f65fc3Swikidesign 626f9f65fc3Swikidesign // date 627f9f65fc3Swikidesign if ($this->getConf('showdate')) { 628b6337848Swikidesign $date = ($page['date'] ? $page['date'] : $meta['date']['created']); 62939af1bf1Swikidesign if ($date) 630ee335396SMichael Klier $ret[] = '<abbr class="published" title="'.strftime('%Y-%m-%dT%H:%M:%SZ', $date).'">'. 631ee335396SMichael Klier strftime($conf['dformat'], $date). 63239af1bf1Swikidesign '</abbr>'; 633f9f65fc3Swikidesign } 634f9f65fc3Swikidesign 635f9f65fc3Swikidesign // author 636f9f65fc3Swikidesign if ($this->getConf('showuser')) { 637b6337848Swikidesign $author = ($page['user'] ? $page['user'] : $meta['creator']); 638f9f65fc3Swikidesign if ($author) { 639f9f65fc3Swikidesign $userpage = cleanID($this->getConf('usernamespace').':'.$author); 64051b9ed81Swikidesign resolve_pageid(getNS($ID), $userpage, $exists); 64139af1bf1Swikidesign $class = ($exists ? 'wikilink1' : 'wikilink2'); 64239af1bf1Swikidesign $link = array( 64339af1bf1Swikidesign 'url' => wl($userpage), 64439af1bf1Swikidesign 'title' => $userpage, 64539af1bf1Swikidesign 'name' => hsc($author), 64639af1bf1Swikidesign 'target' => $conf['target']['wiki'], 64739af1bf1Swikidesign 'class' => $class.' url fn', 64839af1bf1Swikidesign 'pre' => '<span class="vcard author">', 64939af1bf1Swikidesign 'suf' => '</span>', 65039af1bf1Swikidesign ); 65139af1bf1Swikidesign $ret[] = $this->renderer->_formatLink($link); 652f9f65fc3Swikidesign } 653f9f65fc3Swikidesign } 654f9f65fc3Swikidesign 655f9f65fc3Swikidesign // comments - let Discussion Plugin do the work for us 656b6337848Swikidesign if (!$page['section'] && $this->getConf('showcomments') 657e4624397Swikidesign && (!plugin_isdisabled('discussion')) 658e4624397Swikidesign && ($discussion =& plugin_load('helper', 'discussion'))) { 659e4624397Swikidesign $disc = $discussion->td($id); 66039af1bf1Swikidesign if ($disc) $ret[] = '<span class="comment">'.$disc.'</span>'; 661f9f65fc3Swikidesign } 662f9f65fc3Swikidesign 663564e71f6Sraymond.scholz // linkbacks - let Linkback Plugin do the work for us 664564e71f6Sraymond.scholz if (!$page['section'] && $this->getConf('showlinkbacks') 665564e71f6Sraymond.scholz && (!plugin_isdisabled('linkback')) 666564e71f6Sraymond.scholz && ($linkback =& plugin_load('helper', 'linkback'))) { 667564e71f6Sraymond.scholz $link = $linkback->td($id); 668564e71f6Sraymond.scholz if ($link) $ret[] = '<span class="linkback">'.$link.'</span>'; 669564e71f6Sraymond.scholz } 670564e71f6Sraymond.scholz 671ec00fca6Swikidesign $ret = implode(DOKU_LF.DOKU_TAB.'· ', $ret); 672f9f65fc3Swikidesign 673fc5d061eSwikidesign // tags - let Tag Plugin do the work for us 674fc5d061eSwikidesign if (!$page['section'] && $this->getConf('showtags') 675fc5d061eSwikidesign && (!plugin_isdisabled('tag')) 676fc5d061eSwikidesign && ($tag =& plugin_load('helper', 'tag'))) { 677fc5d061eSwikidesign $page['tags'] = '<div class="tags"><span>'.DOKU_LF. 678fc5d061eSwikidesign DOKU_TAB.$tag->td($id).DOKU_LF. 679fc5d061eSwikidesign DOKU_TAB.'</span></div>'.DOKU_LF; 680fc5d061eSwikidesign $ret = $page['tags'].DOKU_TAB.$ret; 681f9f65fc3Swikidesign } 682f9f65fc3Swikidesign 683f9f65fc3Swikidesign if (!$ret) $ret = ' '; 684ec00fca6Swikidesign $class = 'inclmeta'; 685ec00fca6Swikidesign if ($this->header && $this->clevel && ($this->mode == 'section')) 686ec00fca6Swikidesign $class .= ' level'.$this->clevel; 687ec00fca6Swikidesign return '<div class="'.$class.'">'.DOKU_LF.DOKU_TAB.$ret.DOKU_LF.'</div>'.DOKU_LF; 688f9f65fc3Swikidesign } 689f9f65fc3Swikidesign 6901f7a99c4SMichael Klier /** 6911f7a99c4SMichael Klier * Builds the ODT to embed the page to include 6921f7a99c4SMichael Klier */ 6931f7a99c4SMichael Klier function renderODT(&$renderer) { 6941f7a99c4SMichael Klier global $ID; 6951f7a99c4SMichael Klier 6961f7a99c4SMichael Klier if (!$this->page['id']) return ''; // page must be set first 6971f7a99c4SMichael Klier if (!$this->page['exists'] && ($this->page['perm'] < AUTH_CREATE)) return ''; 6981f7a99c4SMichael Klier 6991f7a99c4SMichael Klier // prepare variable 7001f7a99c4SMichael Klier $this->renderer =& $renderer; 7011f7a99c4SMichael Klier 7021f7a99c4SMichael Klier // get instructions and render them on the fly 7031f7a99c4SMichael Klier $this->ins = p_cached_instructions($this->page['file']); 7041f7a99c4SMichael Klier 7051f7a99c4SMichael Klier // show only a given section? 7061f7a99c4SMichael Klier if ($this->page['section'] && $this->page['exists']) $this->_getSection(); 7071f7a99c4SMichael Klier 7081f7a99c4SMichael Klier // convert relative links 7091f7a99c4SMichael Klier $this->_convertInstructions(); 7101f7a99c4SMichael Klier 7111f7a99c4SMichael Klier // render the included page 7121f7a99c4SMichael Klier $backupID = $ID; // store the current ID 7131f7a99c4SMichael Klier $ID = $this->page['id']; // change ID to the included page 7141f7a99c4SMichael Klier // remove document_start and document_end to avoid zipping 7151f7a99c4SMichael Klier $this->ins = array_slice($this->ins, 1, -1); 7161f7a99c4SMichael Klier p_render('odt', $this->ins, $info); 7171f7a99c4SMichael Klier $ID = $backupID; // restore ID 7181f7a99c4SMichael Klier // reset defaults 7191f7a99c4SMichael Klier $this->helper_plugin_include(); 7201f7a99c4SMichael Klier } 721f9f65fc3Swikidesign} 722df4e907bSMichael Klier//vim:ts=4:sw=4:et:enc=utf-8: 723