1<?php /** 2 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 3 * @author Michael Klier <chi@chimeric.de> 4 * @author Myron Turner <turnermm02@shaw.ca> 5 */ 6if(!defined('DOKU_INC')) die(); 7 8if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); 9require_once(DOKU_PLUGIN.'action.php'); 10 11/** 12 * All DokuWiki plugins to extend the parser/rendering mechanism 13 * need to inherit from this class 14 */ 15class action_plugin_snippets extends DokuWiki_Action_Plugin { 16 private $metafn; 17 private $helper; 18 /** 19 * Register callbacks 20 */ 21 function register(Doku_Event_Handler $controller) { 22 $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'handle_ajax_call'); 23 $controller->register_hook('IO_WIKIPAGE_READ', 'AFTER', $this, 'handle_wiki_read'); 24 $controller->register_hook('TPL_ACT_RENDER', 'AFTER', $this, 'handle_content_display'); 25 $controller->register_hook('IO_WIKIPAGE_WRITE', 'AFTER', $this, 'handle_wiki_write',array('after'=>true,'before'=>false)); 26 $controller->register_hook('IO_WIKIPAGE_WRITE', 'BEFORE', $this, 'handle_wiki_write', array('before'=>true, 'after'=>false)); 27 $controller->register_hook('DOKUWIKI_STARTED', 'BEFORE', $this, 'handle_dw_started'); 28 $controller->register_hook('COMMON_PAGETPL_LOAD', 'AFTER', $this, 'handle_template'); 29 $controller->register_hook('HTML_SHOWREV_OUTPUT', 'BEFORE', $this, 'handle_revoutput', array('before')); 30 } 31 32 /** 33 * Sets up database file for pages requiring updates 34 * @author Myron Turner<turnermm02@shaw.ca> 35 */ 36 function __construct() { 37 $this->metafn = metaFN('snippets_upd','.ser'); 38 if(!file_exists($this->metafn)) { 39 $ar = array('snip'=>array(), 'doc'=>array()); 40 io_saveFile($this->metafn,serialize($ar)); 41 } 42 $this->helper = $this->loadHelper('snippets'); 43 } 44 45 function handle_revoutput(Doku_Event $event, $param){ 46 47 global $INFO; 48 $metafn = $this->helper->getMetaFileName(); 49 $snip_data=unserialize(io_readFile($this->metafn,false)); 50 if(!array_key_exists($INFO['id'],$snip_data['doc'])) return; 51 52 $event->preventDefault(); 53 $old_rev=$this->getConf('old_revisions')?'on':'off'; 54 $onoff = get_doku_pref('snippets_old_rev', $old_rev); 55 $ON_CHKD=""; 56 $OFF_CHKD = ''; 57 $msg_2 = ""; 58 $yesno = ""; 59 if($onoff == 'on') { 60 $ON_CHKD='CHECKED'; 61 $yesno =$this->getLang('no'); 62 $msg_2 = $this->getLang('msg_2'); // 'Any outdated snippets have already been inserted. '; 63 } 64 else { 65 $OFF_CHKD='CHECKED'; 66 $yesno =$this->getLang('yes'); 67 } 68 $msg = p_locale_xhtml("showrev"); 69 $n = preg_match('/strong>(.*?)<\/strong/',$msg, $matches); 70 $msg = str_replace('!', '.',$matches[1]) . ' '; 71 echo $msg .$this->getLang('oldrev_msg'); 72 73 echo ' ' . $msg_2 . '<br /><span class="yesnosnippet" id="yesnosnippet">' . $this->getLang('replace') . '</span>' 74 . '<input type="radio" name="snippetOldRevwhich" ' . $ON_CHKD . ' value="on" onchange="snippets_InsertIntOldRev(this.value);" />Yes ' 75 .'<input type="radio" onchange="snippets_InsertIntOldRev(this.value);" ' . $OFF_CHKD . ' name="snippetOldRevwhich" value="off" />No<br/>'; 76 echo "<br /><hr />" ; 77 78 } 79 80 function handle_dw_started(Doku_Event $event, $param) { 81 global $JSINFO; 82 if($this->getConf('snips_updatable')) { 83 $JSINFO['updatable'] = 1; 84 } 85 else $JSINFO['updatable'] = 0; 86 87 if($this->getConf('userreplace')) { 88 $JSINFO['userreplace'] = 1; 89 } 90 else $JSINFO['userreplace'] = 0; 91 92 $JSINFO['default_macro_string'] = $this->getConf('default_macro_string') ? $this->getConf('default_macro_string') : ""; 93 } 94 95 function handle_template(Doku_Event $event, $param) { 96 $file = get_doku_pref('qs',''); 97 $event->data['tpl'] = preg_replace('/<snippet>.*?<\/snippet>/s',"",$event->data['tpl']); 98 99 $stringvars = // from newpagtemplate userreplace 100 array_map(function($v) { return explode(",",$v,2); }, 101 explode(';',$_REQUEST['macros'])); 102 foreach($stringvars as $value) { 103 $event->data['tpl'] = str_replace(trim($value[0]),hsc(trim($value[1])),$event->data['tpl']); 104 } 105 106 if(!$file) return; 107 $page_id = $file; 108 $file = noNS($file); 109 $page = cleanID($file); 110 if($this->getConf('prettytitles')) { 111 $title= str_replace('_',' ',$page); 112 } 113 else { 114 $title = $page; 115 } 116 $event->data['tpl'] = str_replace(array( 117 '#ID#', 118 '#NS#', 119 '#FILE#', 120 '#!FILE#', 121 '#!FILE!#', 122 '#PAGE#', 123 '#!PAGE#', 124 '#!!PAGE#', 125 '#!PAGE!#', 126 127 ), 128 array( 129 $page_id, 130 getNS($page_id), 131 $file, 132 utf8_ucfirst($file), 133 utf8_strtoupper($file), 134 $page, 135 utf8_ucfirst($title), 136 utf8_ucwords($title), 137 utf8_strtoupper($title) 138 ), 139 $event->data['tpl']); 140 141 } 142 /** 143 * Replaces outdated snippets with updated versions 144 * Is capable of replacing more than one snippet in a page 145 * 146 * @author Myron Turner <turnermm02@shaw.ca> 147 */ 148 function handle_wiki_read(Doku_Event $event,$param) { 149 150 $force_old = $this->getConf('old_revisions'); 151 $default = $force_old ? 'on' : 'off'; 152 $default = get_doku_pref('snippets_old_rev', $default); 153 if($default == 'on') { 154 $force_old = true; 155 } 156 else $force_old = false; 157 158 if($event->data[3] && !$force_old) return; 159 $force_old = true; 160 if($event->data[1]) { 161 $page_id = ltrim($event->data[1] . ':' . $event->data[2], ":"); 162 } 163 else { 164 $page_id = $event->data[2]; 165 } 166 $this->helper->insertSnippet($event->result, $page_id, $force_old); 167 } 168 169 170 171 /** 172 * Update the array of snippet timestamps in meta files of pages where snippets are inserted 173 * 174 * @author Myron Turner <turnermm02@shaw.ca> 175 */ 176 function handle_wiki_write(Doku_Event $event, $param) { 177 178 if(! $event->result && $param['after']) return; //write fail 179 180 if($event->data[1]) { 181 $page_id = ltrim($event->data[1] . ':' . $event->data[2], ":"); 182 } 183 else { 184 $page_id = $event->data[2]; 185 } 186 187 $snip_data=unserialize(io_readFile($this->metafn,false)); 188 189 if(!array_key_exists($page_id,$snip_data['doc'])) return; 190 $snippets = $snip_data['doc'][$page_id]; 191 if($param['before']) { 192 preg_match_all("/~~SNIPPET_C~~(.*?)~~/",$event->data[0][1],$matches); 193 $intersect = array_intersect($snippets,$matches[1]); 194 if(!empty($intersect)) { 195 $snip_data['doc'][$page_id] = $intersect; 196 io_saveFile($this->metafn,serialize($snip_data)); 197 } 198 return; 199 } 200 201 202 if(preg_match('#data/pages/#', $event->data[0][0])) { //make sure this is data/page not meta/attic save 203 foreach($snippets as $snip) { 204 $retv = $this->helper->updateMetaTime($page_id,$snip) ; 205 // msg($retv); 206 } 207 } 208 209 210 } 211 /* 212 * After a snippet has been revised, this outputs table of links on the snippet page itemizing those pages where this 213 * snippet is inserted. The links implement an ajax call to exe/update.php where the snippets can be updated 214 * and the timestamps of the updated snippets revised in the metafile of the pages where snippet is inserted 215 */ 216 function handle_content_display(Doku_Event $event, $param) { 217 global $INFO; 218 $snipid = $INFO['id']; 219 $table = array(); 220 221 $snip_data=unserialize(io_readFile($this->metafn,false)); 222 if(!array_key_exists($snipid,$snip_data['snip'])) return; 223 224 $snip_time= filemtime(wikiFN($snipid)); 225 226 $table[] = "<div id='snippet_update_table'>\nSnippet date: " . date('r',$snip_time) .'<br />'; 227 $table[]='<form><input type="checkbox" name="prune" value="prune" id="snip_prune" checked><span title =" '. $this->getLang('refresh_title') . '"> ' . $this->getLang('refresh') .'</span></form><br />'; 228 $table[] ="<table>\n"; 229 $table[] ='<tr><th>Page date<th>' . $this->getLang('click_to_update') .'</tr>'; 230 $bounding_rows = count($table); 231 $page_ids = $snip_data['snip'][$snipid]; 232 foreach($page_ids as $pid) { 233 $page_time= filemtime(wikiFN($pid)); 234 if($snip_time > $page_time) { 235 $span = str_replace(':','_',$pid); 236 $table[]= "<tr><td>" . date('r',$page_time) . '<td><a href="javascript:update_snippets(\''.$pid .'\');" id="' .$span . '">' .$pid .'</a><tr />'; 237 } 238 } 239 $table[]='</table></div>'; 240 $table[]='<p><span id="snip_updates_but" style="color:#2b73b7;">' .$this->getLang('hide_table') . '</span></p>'; 241 242 if(count($table) > $bounding_rows+2) { 243 foreach($table as $line) { 244 print $line . NL; 245 } 246 } 247 } 248 /** 249 * Handles the AJAX calls 250 * 251 * @author Michael Klier <chi@chimeric.de> 252 * @author Myron Turner <turnermm02@shaw.ca> 253 */ 254 function handle_ajax_call(Doku_Event $event, $param) { 255 global $lang; 256 257 if($event->data == 'snippet_preview' or $event->data == 'snippet_insert' or $event->data == 'snippet_update' ) { 258 $event->preventDefault(); 259 $event->stopPropagation(); 260 $id = cleanID($_REQUEST['id']); 261 if(page_exists($id)) { 262 if($event->data == 'snippet_preview') { 263 if(auth_quickaclcheck($id) >= AUTH_READ) { 264 print p_wiki_xhtml($id); 265 } else { 266 print p_locale_xhtml('denied'); 267 } 268 } elseif($event->data == 'snippet_insert' || $event->data == 'snippet_update') { 269 $template = false; 270 if(preg_match("/templ_|templ:/",$id)) $template = true; 271 if(auth_quickaclcheck($id) >= AUTH_READ) { 272 if($event->data == 'snippet_update' && ! $template) { // templates are permanent 273 $tm = time(); 274 print "\n~~SNIPPET_O${tm}~~$id~~\n"; 275 } 276 print "\n\n"; // always start on a new line (just to be safe) 277 if($template) { 278 $tpl = pageTemplate($id); 279 if($this->getConf('skip_unset_macros')) { 280 $tpl = preg_replace("/@\w+@/m","",$tpl); 281 } 282 print($tpl); 283 284 } 285 else print trim(preg_replace('/<snippet>.*?<\/snippet>/s', '', io_readFile(wikiFN($id)))); 286 287 if($event->data == 'snippet_update' && ! $template) { 288 print "\n\n~~SNIPPET_C~~$id~~\n"; 289 $curpage = cleanID($_REQUEST['curpage']); // $curpage is page into which snippet is being inserted 290 $snip_data=unserialize(io_readFile($this->metafn,false)); 291 if(!array_key_exists($curpage,$snip_data['doc'])) { // insert $curpage into doc array 292 $snip_data['doc'][$curpage] = array($id); // and put current snippet into its list of snippets 293 } 294 elseif(!in_array($id,$snip_data['doc'][$curpage])) { 295 // if already in doc array just put current snippet in its list of snippets 296 $snip_data['doc'][$curpage][]= $id; 297 } 298 if(!array_key_exists($id,$snip_data['snip'])) { // do the same as above but in reverse for snippets 299 $snip_data['snip'][$id] = array($curpage); 300 } 301 elseif(!in_array($curpage,$snip_data['snip'][$id])) { 302 $snip_data['snip'][$id][] = $curpage; 303 } 304 io_saveFile($this->metafn,serialize($snip_data)); 305 } 306 } 307 } 308 } 309 } 310 } 311} 312// vim:ts=4:sw=4:et:enc=utf-8: 313