*/ // must be run within Dokuwiki if (!defined('DOKU_INC')) die(); if (!defined('DOKU_LF')) define('DOKU_LF', "\n"); if (!defined('DOKU_TAB')) define('DOKU_TAB', "\t"); if (!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN', DOKU_INC.'lib/plugins/'); class helper_plugin_include extends DokuWiki_Plugin { // DokuWiki_Helper_Plugin var $page = array(); // associative array with data about the page to include var $ins = array(); // instructions array var $doc = ''; // the final output XHTML string var $mode = 'section'; // inclusion mode: 'page' or 'section' var $clevel = 0; // current section level var $firstsec = 0; // show first section only var $hasheader = 0; // included page has header function getInfo(){ return array( 'author' => 'Esther Brunner', 'email' => 'wikidesign@gmail.com', 'date' => '2006-12-09', 'name' => 'Include Plugin (helper class)', 'desc' => 'Functions to include another page in a wiki page', 'url' => 'http://www.wikidesign/en/plugin/include/start', ); } function getMethods(){ $result = array(); $result[] = array( 'name' => 'setPage', 'desc' => 'sets the page to include', 'params' => array("page attributes, 'id' required, 'section' for filtering" => 'array'), 'return' => array('success' => 'boolean'), ); $result[] = array( 'name' => 'setMode', 'desc' => 'sets inclusion mode: should indention be merged?', 'params' => array("'page' (original) or 'section' (merged indention)" => 'string'), ); $result[] = array( 'name' => 'setLevel', 'desc' => 'sets the indention for the current section level', 'params' => array('level: 0 to 5' => 'integer'), 'return' => array('success' => 'boolean'), ); $result[] = array( 'name' => 'getXHTML', 'desc' => 'generates the XHTML output', 'params' => array('DokuWiki renderer' => 'object'), 'return' => array('xhtml' => 'string'), ); return $result; } /** * Sets the page to include if it is not already included (prevent recursion) */ function setPage($page){ global $ID; global $filechain; if (!isset($filechain)) $filechain = array(); if ($this->page['id'] == $ID) return true; // page can't include itself $id = preg_quote($this->page['id'], '/'); $section = preg_quote($this->page['section'], '/'); $pattern = ($section ? "/^($id#$section|$id#)$/" : "/^$id#/"); $match = preg_grep($pattern, $filechain); if (empty($match)){ $this->page = $page; return true; } return false; } /** * Sets the inclusion mode */ function setMode($mode){ $this->mode = $mode; } /** * Sets the right indention for a given section level */ function setLevel($level){ if ((is_numeric($level)) && ($level >= 0) && ($level <= 5)){ $this->clevel = $level; return true; } return false; } /** * Builds the XHTML to embed the page to include */ function getXHTML(&$renderer){ global $filechain; if (!isset($filechain)) $filechain = array(); $this->doc = ''; if (!$this->page['id']) return $this->doc; // page must be set first // add the page to the filechain array_push($filechain, $his->page['id'].'#'.$this->page['section']); $this->firstsec = $this->getConf('firstseconly'); // get instructions and render them on the fly $this->page['file'] = wikiFN($this->page['id']); $this->ins = p_cached_instructions($this->page['file']); if (!empty($this->ins)){ // show only a given section? if ($this->page['section']) $this->_getSection(); // convert relative links $this->_convertInstructions($renderer); // insert a read more link if only first section is shown if ($this->firstsec) $this->_readMore(); // render the included page $content = $this->_cleanXHTML(p_render('xhtml', $this->ins, $info)); // embed the included page $this->doc .= '
_showTagLogos().'>'.DOKU_LF; if (!$this->hasheader && $this->clevel && ($this->mode == 'section')) $this->doc .= '
'.DOKU_LF; $this->doc .= $content.DOKU_LF.$this->_editButton(); if (!$this->hasheader && $this->clevel && ($this->mode == 'section')) $this->doc .= '
'.DOKU_LF; $this->doc .= '
'.DOKU_LF; $this->doc .= $this->_metaLine($renderer); } // remove the page from the filechain again array_pop($filechain); return $this->doc; } /* ---------- Private Methods ---------- */ /** * Get a section including its subsections */ function _getSection(){ foreach ($this->ins as $ins){ if ($ins[0] == 'header'){ // found the right header if (cleanID($ins[1][0]) == $this->page['section']){ $level = $ins[1][1]; $i[] = $ins; // next header of the same or higher level -> exit } elseif ($ins[1][1] <= $level){ $this->ins = $i; return true; } elseif (isset($level)){ $i[] = $ins; } // add instructions from our section } elseif (isset($level)){ $i[] = $ins; } } $this->ins = $i; return true; } /** * Corrects relative internal links and media and * converts headers of included pages to subheaders of the current page */ function _convertInstructions(&$renderer){ global $ID; global $conf; // check if included page is in same namespace $inclNS = getNS($this->page['id']); if (getNS($ID) == $inclNS) $convert = false; else $convert = true; $n = count($this->ins); for ($i = 0; $i < $n; $i++){ // convert internal links and media from relative to absolute if ($convert && (substr($this->ins[$i][0], 0, 8) == 'internal')){ // relative subnamespace if ($this->ins[$i][1][0]{0} == '.'){ // parent namespace if ($this->ins[$i][1][0]{1} == '.') $ithis->ns[$i][1][0] = getNS($inclNS).':'.substr($this->ins[$i][1][0], 2); // current namespace else $this->ins[$i][1][0] = $inclNS.':'.substr($this->ins[$i][1][0], 1); // relative link } elseif (strpos($this->ins[$i][1][0], ':') === false){ $this->ins[$i][1][0] = $inclNS.':'.$this->ins[$i][1][0]; } // set header level to current section level + header level } elseif ($this->ins[$i][0] == 'header'){ $level = $this->ins[$i][1][1] + $this->clevel; if ($level > 5) $level = 5; $this->ins[$i][1][1] = $level; // add TOC items if (($level >= $conf['toptoclevel']) && ($level <= $conf['maxtoclevel'])){ $text = $this->ins[$i][1][0]; $hid = $renderer->_headerToLink($text, 'true'); $renderer->toc[] = array( 'hid' => $hid, 'title' => $text, 'type' => 'ul', 'level' => $level - $conf['toptoclevel'] + 1 ); $this->hasheader = true; } // the same for sections } elseif ($this->ins[$i][0] == 'section_open'){ $level = $this->ins[$i][1][0] + $this->clevel; if ($level > 5) $level = 5; $this->ins[$i][1][0] = $level; // show only the first section? } elseif ($this->firstsec && ($this->ins[$i][0] == 'section_close') && ($this->ins[$i-1][0] != 'section_open')){ if ($this->ins[0][0] == 'document_start'){ $this->ins = array_slice($this->ins, 1, $i); return true; } else { $this->ins = array_slice($this->ins, 0, $i); return true; } } } if ($this->ins[0][0] == 'document_start') $this->ins = array_slice($this->ins, 1, -1); return true; } /** * Remove TOC, section edit buttons and tags */ function _cleanXHTML($xhtml){ preg_match('!
.*?
!s', $xhtml, $match); $this->page['tags'] = $match[0]; $replace = array( '!
.*?(
\n)!s' => '', // remove toc '##e' => '', // remove section edit buttons '!
.*?(
)!s' => '', // remove category tags ); $xhtml = preg_replace(array_keys($replace), array_values($replace), $xhtml); return $xhtml; } /** * Optionally display logo for the first tag found in the included page */ function _showTagLogos(){ if (!$this->getConf('showtaglogos')) return ''; preg_match_all('/]*title="(.*?)" rel="tag"[^>]*>([^<]*)page['tags'], $tag); $logoID = getNS($tag[1][0]).':'.$tag[2][0]; $logosrc = mediaFN($logoID); $types = array('.png', '.jpg', '.gif'); // auto-detect filetype foreach ($types as $type){ if (!@file_exists($logosrc.$type)) continue; $logoID .= $type; $logosrc .= $type; list($w, $h, $t, $a) = getimagesize($logosrc); return ' style="min-height: '.$h.'px">'. ''.$tag[2][0].'page['perm'])) $this->page['perm'] = auth_quickaclcheck($this->page['id']); if (@file_exists($this->page['file'])){ if (($this->page['perm'] >= AUTH_EDIT) && (is_writable($this->page['file']))) $action = 'edit'; else return ''; } elseif ($this->page['perm'] >= AUTH_CREATE){ $action = 'create'; } return '
'.DOKU_LF.DOKU_TAB. html_btn($action, $this->page['id'], '', array('do' => 'edit'), 'post').DOKU_LF. '
'.DOKU_LF; } /** * Adds a read more... link at the bottom of the first section */ function _readMore(){ $last = $this->ins[count($this->ins) - 1]; if ($last[0] == 'section_close') $this->ins = array_slice($this->ins, 0, -1); $this->ins[] = array('p_open', array(), $last[2]); $this->ins[] = array('internallink', array($this->page['id'], $this->getLang('readmore')), $last[2]); $this->ins[] = array('p_close', array(), $last[2]); if ($last[0] == 'section_close') $this->ins[] = $last; } /** * Returns the meta line below the included page */ function _metaLine(&$renderer){ global $conf; if (!$this->getConf('showmetaline')) return '
 
'.DOKU_LF; $id = $this->page['id']; $meta = p_get_metadata($id); $ret = array(); // permalink if ($this->getConf('showlink')){ $title = ($this->page['title'] ? $this->page['title'] : $meta['title']); if (!$title) $title = str_replace('_', ' ', noNS($id)); $ret[] = $renderer->internallink($id, $title, '', true); } // date if ($this->getConf('showdate')){ $date = ($this->page['date'] ? $this->page['date'] : $meta['date']['created']); $ret[] = date($conf['dformat'], $date); } // author if ($this->getConf('showuser')){ $author = ($this->page['user'] ? $this->page['user'] : $meta['creator']); if ($author){ $userpage = cleanID($this->getConf('usernamespace').':'.$author); $ret[] = $renderer->internallink($userpage, $author, '', true); } } // comments - let Discussion Plugin do the work for us if (!$this->page['section'] && $this->getConf('showcomments') && ($discussion = plugin_load('helper', 'discussion'))){ $ret[] = $discussion->td($id); } $ret = implode(' · ', $ret); // tags if (($this->getConf('showtags')) && ($this->page['tags'])){ $ret = $this->page['tags'].$ret; } if (!$ret) $ret = ' '; return '
'.DOKU_LF.$ret.DOKU_LF.'
'.DOKU_LF; } } //Setup VIM: ex: et ts=4 enc=utf-8 :