1<?php 2/** 3 * DokuWiki AJAX call handler 4 * 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 * @author Andreas Gohr <andi@splitbrain.org> 7 */ 8 9//fix for Opera XMLHttpRequests 10if(!count($_POST) && !empty($HTTP_RAW_POST_DATA)){ 11 parse_str($HTTP_RAW_POST_DATA, $_POST); 12} 13 14if(!defined('DOKU_INC')) define('DOKU_INC',dirname(__FILE__).'/../../'); 15require_once(DOKU_INC.'inc/init.php'); 16//close session 17session_write_close(); 18 19header('Content-Type: text/html; charset=utf-8'); 20 21 22//call the requested function 23if(isset($_POST['call'])){ 24 $call = $_POST['call']; 25}else if(isset($_GET['call'])){ 26 $call = $_GET['call']; 27}else{ 28 exit; 29} 30$callfn = 'ajax_'.$call; 31 32if(function_exists($callfn)){ 33 $callfn(); 34}else{ 35 $evt = new Doku_Event('AJAX_CALL_UNKNOWN', $call); 36 if ($evt->advise_before()) { 37 print "AJAX call '".htmlspecialchars($call)."' unknown!\n"; 38 exit; 39 } 40 $evt->advise_after(); 41 unset($evt); 42} 43 44/** 45 * Searches for matching pagenames 46 * 47 * @author Andreas Gohr <andi@splitbrain.org> 48 */ 49function ajax_qsearch(){ 50 global $conf; 51 global $lang; 52 53 $query = $_POST['q']; 54 if(empty($query)) $query = $_GET['q']; 55 if(empty($query)) return; 56 57 $data = ft_pageLookup($query, true, useHeading('navigation')); 58 59 if(!count($data)) return; 60 61 print '<strong>'.$lang['quickhits'].'</strong>'; 62 print '<ul>'; 63 foreach($data as $id => $title){ 64 if (useHeading('navigation')) { 65 $name = $title; 66 } else { 67 $ns = getNS($id); 68 if($ns){ 69 $name = noNS($id).' ('.$ns.')'; 70 }else{ 71 $name = $id; 72 } 73 } 74 echo '<li>' . html_wikilink(':'.$id,$name) . '</li>'; 75 } 76 print '</ul>'; 77} 78 79/** 80 * Support OpenSearch suggestions 81 * 82 * @link http://www.opensearch.org/Specifications/OpenSearch/Extensions/Suggestions/1.0 83 * @author Mike Frysinger <vapier@gentoo.org> 84 */ 85function ajax_suggestions() { 86 global $conf; 87 global $lang; 88 89 $query = cleanID($_POST['q']); 90 if(empty($query)) $query = cleanID($_GET['q']); 91 if(empty($query)) return; 92 93 $data = array(); 94 $data = ft_pageLookup($query); 95 if(!count($data)) return; 96 $data = array_keys($data); 97 98 // limit results to 15 hits 99 $data = array_slice($data, 0, 15); 100 $data = array_map('trim',$data); 101 $data = array_map('noNS',$data); 102 $data = array_unique($data); 103 sort($data); 104 105 /* now construct a json */ 106 $suggestions = array( 107 $query, // the original query 108 $data, // some suggestions 109 array(), // no description 110 array() // no urls 111 ); 112 $json = new JSON(); 113 114 header('Content-Type: application/x-suggestions+json'); 115 print $json->encode($suggestions); 116} 117 118/** 119 * Refresh a page lock and save draft 120 * 121 * Andreas Gohr <andi@splitbrain.org> 122 */ 123function ajax_lock(){ 124 global $conf; 125 global $lang; 126 global $ID; 127 global $INFO; 128 129 $ID = cleanID($_POST['id']); 130 if(empty($ID)) return; 131 if (!checkSecurityToken()) return; 132 133 $INFO = pageinfo(); 134 135 if (!$INFO['writable']) { 136 echo 'Permission denied'; 137 return; 138 } 139 140 if(!checklock($ID)){ 141 lock($ID); 142 echo 1; 143 } 144 145 if($conf['usedraft'] && $_POST['wikitext']){ 146 $client = $_SERVER['REMOTE_USER']; 147 if(!$client) $client = clientIP(true); 148 149 $draft = array('id' => $ID, 150 'prefix' => substr($_POST['prefix'], 0, -1), 151 'text' => $_POST['wikitext'], 152 'suffix' => $_POST['suffix'], 153 'date' => (int) $_POST['date'], 154 'client' => $client, 155 ); 156 $cname = getCacheName($draft['client'].$ID,'.draft'); 157 if(io_saveFile($cname,serialize($draft))){ 158 echo $lang['draftdate'].' '.dformat(); 159 } 160 } 161 162} 163 164/** 165 * Delete a draft 166 * 167 * @author Andreas Gohr <andi@splitbrain.org> 168 */ 169function ajax_draftdel(){ 170 $id = cleanID($_REQUEST['id']); 171 if(empty($id)) return; 172 if (!checkSecurityToken()) return; 173 174 $client = $_SERVER['REMOTE_USER']; 175 if(!$client) $client = clientIP(true); 176 177 $cname = getCacheName($client.$id,'.draft'); 178 @unlink($cname); 179} 180 181/** 182 * Return subnamespaces for the Mediamanager 183 * 184 * @author Andreas Gohr <andi@splitbrain.org> 185 */ 186function ajax_medians(){ 187 global $conf; 188 189 // wanted namespace 190 $ns = cleanID($_POST['ns']); 191 $dir = utf8_encodeFN(str_replace(':','/',$ns)); 192 193 $lvl = count(explode(':',$ns)); 194 195 $data = array(); 196 search($data,$conf['mediadir'],'search_index',array('nofiles' => true),$dir); 197 foreach($data as $item){ 198 $item['level'] = $lvl+1; 199 echo media_nstree_li($item); 200 echo media_nstree_item($item); 201 echo '</li>'; 202 } 203} 204 205/** 206 * Return list of files for the Mediamanager 207 * 208 * @author Andreas Gohr <andi@splitbrain.org> 209 */ 210function ajax_medialist(){ 211 global $conf; 212 global $NS; 213 214 $NS = $_POST['ns']; 215 tpl_mediaContent(true); 216} 217 218/** 219 * Return sub index for index view 220 * 221 * @author Andreas Gohr <andi@splitbrain.org> 222 */ 223function ajax_index(){ 224 global $conf; 225 226 // wanted namespace 227 $ns = cleanID($_POST['idx']); 228 $dir = utf8_encodeFN(str_replace(':','/',$ns)); 229 230 $lvl = count(explode(':',$ns)); 231 232 $data = array(); 233 search($data,$conf['datadir'],'search_index',array('ns' => $ns),$dir); 234 foreach($data as $item){ 235 $item['level'] = $lvl+1; 236 echo html_li_index($item); 237 echo '<div class="li">'; 238 echo html_list_index($item); 239 echo '</div>'; 240 echo '</li>'; 241 } 242} 243 244/** 245 * List matching namespaces and pages for the link wizard 246 * 247 * @author Andreas Gohr <gohr@cosmocode.de> 248 */ 249function ajax_linkwiz(){ 250 global $conf; 251 global $lang; 252 253 $q = ltrim(trim($_POST['q']),':'); 254 $id = noNS($q); 255 $ns = getNS($q); 256 257 $ns = cleanID($ns); 258 $id = cleanID($id); 259 260 $nsd = utf8_encodeFN(str_replace(':','/',$ns)); 261 $idd = utf8_encodeFN(str_replace(':','/',$id)); 262 263 $data = array(); 264 if($q && !$ns){ 265 266 // use index to lookup matching pages 267 $pages = array(); 268 $pages = ft_pageLookup($id,true); 269 270 // result contains matches in pages and namespaces 271 // we now extract the matching namespaces to show 272 // them seperately 273 $dirs = array(); 274 275 foreach($pages as $pid => $title){ 276 if(strpos(noNS($pid),$id) === false){ 277 // match was in the namespace 278 $dirs[getNS($pid)] = 1; // assoc array avoids dupes 279 }else{ 280 // it is a matching page, add it to the result 281 $data[] = array( 282 'id' => $pid, 283 'title' => $title, 284 'type' => 'f', 285 ); 286 } 287 unset($pages[$pid]); 288 } 289 foreach($dirs as $dir => $junk){ 290 $data[] = array( 291 'id' => $dir, 292 'type' => 'd', 293 ); 294 } 295 296 }else{ 297 298 $opts = array( 299 'depth' => 1, 300 'listfiles' => true, 301 'listdirs' => true, 302 'pagesonly' => true, 303 'firsthead' => true, 304 'sneakyacl' => $conf['sneaky_index'], 305 ); 306 if($id) $opts['filematch'] = '^.*\/'.$id; 307 if($id) $opts['dirmatch'] = '^.*\/'.$id; 308 search($data,$conf['datadir'],'search_universal',$opts,$nsd); 309 310 // add back to upper 311 if($ns){ 312 array_unshift($data,array( 313 'id' => getNS($ns), 314 'type' => 'u', 315 )); 316 } 317 } 318 319 // fixme sort results in a useful way ? 320 321 if(!count($data)){ 322 echo $lang['nothingfound']; 323 exit; 324 } 325 326 // output the found data 327 $even = 1; 328 foreach($data as $item){ 329 $even *= -1; //zebra 330 331 if(($item['type'] == 'd' || $item['type'] == 'u') && $item['id']) $item['id'] .= ':'; 332 $link = wl($item['id']); 333 334 echo '<div class="'.(($even > 0)?'even':'odd').' type_'.$item['type'].'">'; 335 336 if($item['type'] == 'u'){ 337 $name = $lang['upperns']; 338 }else{ 339 $name = htmlspecialchars($item['id']); 340 } 341 342 echo '<a href="'.$link.'" title="'.htmlspecialchars($item['id']).'" class="wikilink1">'.$name.'</a>'; 343 344 if($item['title']){ 345 echo '<span>'.htmlspecialchars($item['title']).'</span>'; 346 } 347 echo '</div>'; 348 } 349 350} 351 352//Setup VIM: ex: et ts=2 : 353