1<?php 2/** 3 * This plugin allows to embed wikipages into the current page 4 * In addition, parts marked with id's can be replaced. 5 * 6 * Inspired (and copy&pasted) from the include plugin: 7 * http://wiki.splitbrain.org/plugin:include 8 * 9 * For wikipage-portion-replacements, the label-plugin is required: http://wiki.splitbrain.org/plugin:label 10 * 11 * 12 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 13 * @author Pascal Bihler <bihler@iai.uni-bonn.de> 14 */ 15 16// must be run within Dokuwiki 17if(!defined('DOKU_INC')) die(); 18 19if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/'); 20if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); 21require_once(DOKU_PLUGIN.'syntax.php'); 22 23// 24 25class syntax_plugin_embed extends DokuWiki_Syntax_Plugin { 26 27 function syntax_plugin_embed() { 28 global $embedded_pages_by_plugin_embed; 29 if (! $embedded_pages_by_plugin_embed) { 30 $embedded_pages_by_plugin_embed = array(); // To avoid recursion; 31 } 32 } 33 34 function getInfo(){ 35 return array( 36 'author' => 'Pascal Bihler', 37 'email' => 'bihler@iai.uni-bonn.de', 38 'date' => '2007-05-14', 39 'name' => 'Embed', 40 'desc' => 'Allows to embed wikipages in other ones, while offering the possibility to replace parts of the original page marked with labels.', 41 'url' => 'http://wiki.splitbrain.org/plugin:embed', 42 ); 43 } 44 45 function getType(){ 46 return 'substition'; 47 } 48 49 function getSort(){ 50 return 500; 51 } 52 53 function connectTo($mode) { 54 $this->Lexer->addSpecialPattern('<embed\s+[^>]+\s*>.*?</embed>',$mode,'plugin_embed'); 55 $this->Lexer->addSpecialPattern('<embed\s+[^/]+\s*/>',$mode,'plugin_embed'); 56 } 57 58 59 /** 60 * Handle the match 61 */ 62 function handle($match, $state, $pos, &$handler){ 63 switch ($state) { 64 case DOKU_LEXER_SPECIAL : 65 if (preg_match('/<embed\s+([^>]+)\s*>(.*?)<\/embed>/ms',$match,$matches)) 66 return array($matches[1],$matches[2]); 67 else if (preg_match('/<embed\s+([^>]+)\s*\/>/',$match,$matches)) 68 return array($matches[1],''); 69 break; 70 } 71 return array(); 72 } 73 74 /** 75 * Create output 76 */ 77 function render($mode, &$renderer, $data) { 78 global $ID; 79 global $embedded_pages_by_plugin_embed; 80 81 82 if($mode == 'xhtml'){ 83 list($id,$replacement) = $data; 84 85 $renderer->info['cache'] = false; // prevent caching (to ensure ACL conformity) (TODO sometimes: make more intelligent) 86 87 resolve_pageid(getNS($ID), $id, $exists); // resolve shortcuts 88 89 //resolve_pageid(getNS($ID), $id, $exists); // resolve shortcuts 90 91 // avoid circular references 92 if (! (array_search($id,$embedded_pages_by_plugin_embed) === false)) 93 return false; 94 95 array_push($embedded_pages_by_plugin_embed,$id); 96 97 $ins = $this->_embed_file($id,$replacement); 98 $renderer->doc .= p_render('xhtml', $ins, $info); // ptype = 'normal' 99 100 array_pop($embedded_pages_by_plugin_embed); 101 102 return true; 103 } 104 return false; 105 } 106 107 function _embed_file($id,$replacement) { 108 109 110 // check permission 111 $perm = auth_quickaclcheck($id); 112 if ($perm < AUTH_READ) return false; 113 114 115 //Read embeded page 116 $page = io_readfile(wikiFN($id)); 117 118 // convert relative links 119 $page = $this->_convertInstructions($page,$id); 120 121 // do replacements (on text-base to preserve List indentation and ordering etc.): 122 $page = $this->_do_replacements($page,$replacement); 123 124 $ins = p_get_instructions($page); 125 126 return $ins; 127 } 128 129 function _do_replacements($page,$r_str) { 130 //Build up list of replacements (this needs to be done manually to allow several replacements with nesting if <label>s 131 $r_list = array(); 132 preg_match_all('/<label\s+([a-zA-Z0-9_]+)\s*>/',$r_str, $matches_label, PREG_OFFSET_CAPTURE); 133 preg_match_all('/<\/label>/',$r_str, $matches_labelx, PREG_OFFSET_CAPTURE); 134 135 $level = 0; 136 $element = array_shift($matches_label[1]); 137 $end_element = array_shift($matches_labelx[0]); 138 while ($element || $end_element) { 139 if ($element && $element[1] < $end_element[1]) { // <label ..> before </label> 140 if ($level == 0) { 141 $section_name = $element[0]; 142 $section_start = $element[1]+strlen($section_name)+1; 143 } 144 $level++; 145 $element = array_shift($matches_label[1]); 146 } else { //</label> before <label ..> 147 $level--; 148 if ($level == 0) { 149 $section_end = $end_element[1]; 150 $r_list[$section_name] = substr($r_str,$section_start,$section_end-$section_start); 151 } 152 $end_element = array_shift($matches_labelx[0]); 153 } 154 } 155 156 // now do replacements 157 foreach ($r_list as $section => $rep) { 158 $page = preg_replace('/<label\s+' . $section .'\s*>.*?<\/label>/ms',$rep, $page); 159 } 160 return $page; 161 } 162 163 //Does not support CamelCase Links currently 164 function _convert_link($link,$inclNS) { 165 166 //Check if external: 167 if (preg_match('/^(https?:\/\/|mailto:|\\\\)/',$link)) 168 return $link; 169 170 //check if interwiki or email: 171 if ((! strpos('>',$link) === false) || (! strpos('@',$link) === false)) 172 return $link; 173 174 // convert internal links and media from relative to absolute 175 176 // relative subnamespace 177 if ($link{0} == '.') { 178 // parent namespace 179 if ($link{1} == '.') 180 $link = getNS($inclNS).':'.substr($link, 2); 181 // current namespace 182 else 183 $link = $inclNS.':'.substr($link, 1); 184 } elseif (strpos($link, ':') === false){ 185 $link = $inclNS.':'.$link; 186 } 187 188 return $link; 189 } 190 191 function _convertInstructions($page,$page_id) { 192 global $ID; 193 194 if (! $page) return; 195 196 // check if embeded page is in same namespace 197 $inclNS = getNS($page_id); 198 if (getNS($ID) == $inclNS) return $page; 199 200 // convert links 201 $page = preg_replace("/\[\[([^\|\]]+)(\|[^\]]+)?\]\]/e", 202 "'[[' . \$this->_convert_link('\\1','$inclNS') . '\\2]]'", 203 $page); 204 205 //convert embeddings 206 $page = preg_replace("/<embed\s+([^>]+)\s*\/?>/e", 207 "'<embed ' . \$this->_convert_link('\\1','$inclNS') . '>'", 208 $page); 209 210 //convert images 211 $page = preg_replace("/{{(\s*)([^ \|}]+)(\s*)(||[^}]+)}}/e", 212 "'{{\\1' . \$this->_convert_link('\\2','$inclNS') . '\\3\\4}}'", 213 $page); 214 return $page; 215 216 } 217} 218//Setup VIM: ex: et ts=4 enc=utf-8 : 219