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 9if(!defined('DOKU_INC')) define('DOKU_INC',dirname(__FILE__).'/../../'); 10require_once(DOKU_INC.'inc/init.php'); 11//close session 12session_write_close(); 13 14header('Content-Type: text/html; charset=utf-8'); 15 16//call the requested function 17if($INPUT->has('call')) { 18 $call = $INPUT->filter('utf8_stripspecials')->str('call'); 19} else { 20 exit; 21} 22$callfn = 'ajax_'.$call; 23 24if(function_exists($callfn)){ 25 $callfn(); 26}else{ 27 $evt = new Doku_Event('AJAX_CALL_UNKNOWN', $call); 28 if ($evt->advise_before()) { 29 print "AJAX call '".htmlspecialchars($call)."' unknown!\n"; 30 exit; 31 } 32 $evt->advise_after(); 33 unset($evt); 34} 35 36if (!function_exists('ajax_qsearch')) { 37/** 38 * Searches for matching pagenames 39 * 40 * @author Andreas Gohr <andi@splitbrain.org> 41 */ 42function ajax_qsearch(){ 43 global $lang; 44 global $INPUT; 45 46 $maxnumbersuggestions = 50; 47 48 $query = $INPUT->post->str('q'); 49 if(empty($query)) $query = $INPUT->get->str('q'); 50 if(empty($query)) return; 51 52 $query = urldecode($query); 53 54 $data = ft_pageLookup($query, true, useHeading('navigation')); 55 56 if(!count($data)) return; 57 58 print '<strong>'.$lang['quickhits'].'</strong>'; 59 print '<ul>'; 60 $counter = 0; 61 foreach($data as $id => $title){ 62 if (useHeading('navigation')) { 63 $name = $title; 64 } else { 65 $ns = getNS($id); 66 if($ns){ 67 $name = noNS($id).' ('.$ns.')'; 68 }else{ 69 $name = $id; 70 } 71 } 72 echo '<li>' . html_wikilink(':'.$id,$name) . '</li>'; 73 74 $counter ++; 75 if($counter > $maxnumbersuggestions) { 76 echo '<li>...</li>'; 77 break; 78 } 79 } 80 print '</ul>'; 81} 82} 83 84if (!function_exists('ajax_suggestions')) { 85/** 86 * Support OpenSearch suggestions 87 * 88 * @link http://www.opensearch.org/Specifications/OpenSearch/Extensions/Suggestions/1.0 89 * @author Mike Frysinger <vapier@gentoo.org> 90 */ 91function ajax_suggestions() { 92 global $INPUT; 93 94 $query = cleanID($INPUT->post->str('q')); 95 if(empty($query)) $query = cleanID($INPUT->get->str('q')); 96 if(empty($query)) return; 97 98 $data = ft_pageLookup($query); 99 if(!count($data)) return; 100 $data = array_keys($data); 101 102 // limit results to 15 hits 103 $data = array_slice($data, 0, 15); 104 $data = array_map('trim',$data); 105 $data = array_map('noNS',$data); 106 $data = array_unique($data); 107 sort($data); 108 109 /* now construct a json */ 110 $suggestions = array( 111 $query, // the original query 112 $data, // some suggestions 113 array(), // no description 114 array() // no urls 115 ); 116 $json = new JSON(); 117 118 header('Content-Type: application/x-suggestions+json'); 119 print $json->encode($suggestions); 120} 121} 122 123if (!function_exists('ajax_lock')) { 124/** 125 * Refresh a page lock and save draft 126 * 127 * Andreas Gohr <andi@splitbrain.org> 128 */ 129function ajax_lock(){ 130 global $conf; 131 global $lang; 132 global $ID; 133 global $INFO; 134 global $INPUT; 135 136 $ID = cleanID($INPUT->post->str('id')); 137 if(empty($ID)) return; 138 139 $INFO = pageinfo(); 140 141 if (!$INFO['writable']) { 142 echo 'Permission denied'; 143 return; 144 } 145 146 if(!checklock($ID)){ 147 lock($ID); 148 echo 1; 149 } 150 151 if($conf['usedraft'] && $INPUT->post->str('wikitext')){ 152 $client = $_SERVER['REMOTE_USER']; 153 if(!$client) $client = clientIP(true); 154 155 $draft = array('id' => $ID, 156 'prefix' => substr($INPUT->post->str('prefix'), 0, -1), 157 'text' => $INPUT->post->str('wikitext'), 158 'suffix' => $INPUT->post->str('suffix'), 159 'date' => $INPUT->post->int('date'), 160 'client' => $client, 161 ); 162 $cname = getCacheName($draft['client'].$ID,'.draft'); 163 if(io_saveFile($cname,serialize($draft))){ 164 echo $lang['draftdate'].' '.dformat(); 165 } 166 } 167 168} 169} 170 171if (!function_exists('ajax_draftdel')) { 172/** 173 * Delete a draft 174 * 175 * @author Andreas Gohr <andi@splitbrain.org> 176 */ 177function ajax_draftdel(){ 178 global $INPUT; 179 $id = cleanID($INPUT->str('id')); 180 if(empty($id)) return; 181 182 $client = $_SERVER['REMOTE_USER']; 183 if(!$client) $client = clientIP(true); 184 185 $cname = getCacheName($client.$id,'.draft'); 186 @unlink($cname); 187} 188} 189 190if (!function_exists('ajax_medians')) { 191/** 192 * Return subnamespaces for the Mediamanager 193 * 194 * @author Andreas Gohr <andi@splitbrain.org> 195 */ 196function ajax_medians(){ 197 global $conf; 198 global $INPUT; 199 200 // wanted namespace 201 $ns = cleanID($INPUT->post->str('ns')); 202 $dir = utf8_encodeFN(str_replace(':','/',$ns)); 203 204 $lvl = count(explode(':',$ns)); 205 206 $data = array(); 207 search($data,$conf['mediadir'],'search_index',array('nofiles' => true),$dir); 208 foreach(array_keys($data) as $item){ 209 $data[$item]['level'] = $lvl+1; 210 } 211 echo html_buildlist($data, 'idx', 'media_nstree_item', 'media_nstree_li'); 212} 213} 214if (!function_exists('ajax_medialist')) { 215/** 216 * Return list of files for the Mediamanager 217 * 218 * @author Andreas Gohr <andi@splitbrain.org> 219 */ 220function ajax_medialist(){ 221 global $NS; 222 global $INPUT; 223 224 $NS = cleanID($INPUT->post->str('ns')); 225 $sort = $INPUT->post->bool('recent') ? 'date' : 'natural'; 226 if ($INPUT->post->str('do') == 'media') { 227 tpl_mediaFileList(); 228 } else { 229 tpl_mediaContent(true, $sort); 230 } 231} 232} 233if(!function_exists('ajax_mediadetails')) { 234/** 235 * Return the content of the right column 236 * (image details) for the Mediamanager 237 * 238 * @author Kate Arzamastseva <pshns@ukr.net> 239 */ 240function ajax_mediadetails(){ 241 global $IMG, $JUMPTO, $REV, $fullscreen, $INPUT; 242 $fullscreen = true; 243 require_once(DOKU_INC.'lib/exe/mediamanager.php'); 244 245 $image = ''; 246 if ($INPUT->has('image')) $image = cleanID($INPUT->str('image')); 247 if (isset($IMG)) $image = $IMG; 248 if (isset($JUMPTO)) $image = $JUMPTO; 249 $rev = false; 250 if (isset($REV) && !$JUMPTO) $rev = $REV; 251 252 html_msgarea(); 253 tpl_mediaFileDetails($image, $rev); 254} 255} 256 257if(!function_exists('ajax_mediadiff')) { 258/** 259 * Returns image diff representation for mediamanager 260 * @author Kate Arzamastseva <pshns@ukr.net> 261 */ 262function ajax_mediadiff(){ 263 global $NS; 264 global $INPUT; 265 266 $image = ''; 267 if ($INPUT->has('image')) $image = cleanID($INPUT->str('image')); 268 $NS = getNS($image); 269 $auth = auth_quickaclcheck("$NS:*"); 270 media_diff($image, $NS, $auth, true); 271} 272} 273if (!function_exists('ajax_mediaupload')) { 274function ajax_mediaupload(){ 275 global $NS, $MSG, $INPUT; 276 277 $id = ''; 278 if ($_FILES['qqfile']['tmp_name']) { 279 $id = $INPUT->post->str('mediaid', $_FILES['qqfile']['name']); 280 } elseif ($INPUT->get->has('qqfile')) { 281 $id = $INPUT->get->str('qqfile'); 282 } 283 284 $id = cleanID($id); 285 286 $NS = $INPUT->str('ns'); 287 $ns = $NS.':'.getNS($id); 288 289 $AUTH = auth_quickaclcheck("$ns:*"); 290 if($AUTH >= AUTH_UPLOAD) { io_createNamespace("$ns:xxx", 'media'); } 291 292 if ($_FILES['qqfile']['error']) unset($_FILES['qqfile']); 293 294 $res = false; 295 if ($_FILES['qqfile']['tmp_name']) $res = media_upload($NS, $AUTH, $_FILES['qqfile']); 296 if ($INPUT->get->has('qqfile')) $res = media_upload_xhr($NS, $AUTH); 297 298 if($res) { 299 $result = array( 300 'success' => true, 301 'link' => media_managerURL(array('ns' => $ns, 'image' => $NS . ':' . $id), '&'), 302 'id' => $NS . ':' . $id, 303 'ns' => $NS 304 ); 305 } else { 306 $error = ''; 307 if(isset($MSG)) { 308 foreach($MSG as $msg) { 309 $error .= $msg['msg']; 310 } 311 } 312 $result = array( 313 'error' => $error, 314 'ns' => $NS 315 ); 316 } 317 $json = new JSON; 318 header('Content-Type: application/json'); 319 echo $json->encode($result); 320} 321} 322if (!function_exists('ajax_index')) { 323/** 324 * Return sub index for index view 325 * 326 * @author Andreas Gohr <andi@splitbrain.org> 327 */ 328function ajax_index(){ 329 global $conf; 330 global $INPUT; 331 332 // wanted namespace 333 $ns = cleanID($INPUT->post->str('idx')); 334 $dir = utf8_encodeFN(str_replace(':','/',$ns)); 335 336 $lvl = count(explode(':',$ns)); 337 338 $data = array(); 339 search($data,$conf['datadir'],'search_index',array('ns' => $ns),$dir); 340 foreach(array_keys($data) as $item){ 341 $data[$item]['level'] = $lvl+1; 342 } 343 echo html_buildlist($data, 'idx', 'html_list_index', 'html_li_index'); 344} 345} 346 347if (!function_exists('ajax_linkwiz')) { 348/** 349 * List matching namespaces and pages for the link wizard 350 * 351 * @author Andreas Gohr <gohr@cosmocode.de> 352 */ 353function ajax_linkwiz(){ 354 global $conf; 355 global $lang; 356 global $INPUT; 357 358 $q = ltrim(trim($INPUT->post->str('q')),':'); 359 $id = noNS($q); 360 $ns = getNS($q); 361 362 $ns = cleanID($ns); 363 $id = cleanID($id); 364 365 $nsd = utf8_encodeFN(str_replace(':','/',$ns)); 366 367 $data = array(); 368 if($q && !$ns){ 369 370 // use index to lookup matching pages 371 $pages = ft_pageLookup($id,true); 372 373 // result contains matches in pages and namespaces 374 // we now extract the matching namespaces to show 375 // them seperately 376 $dirs = array(); 377 378 foreach($pages as $pid => $title){ 379 if(strpos(noNS($pid),$id) === false){ 380 // match was in the namespace 381 $dirs[getNS($pid)] = 1; // assoc array avoids dupes 382 }else{ 383 // it is a matching page, add it to the result 384 $data[] = array( 385 'id' => $pid, 386 'title' => $title, 387 'type' => 'f', 388 ); 389 } 390 unset($pages[$pid]); 391 } 392 foreach($dirs as $dir => $junk){ 393 $data[] = array( 394 'id' => $dir, 395 'type' => 'd', 396 ); 397 } 398 399 }else{ 400 401 $opts = array( 402 'depth' => 1, 403 'listfiles' => true, 404 'listdirs' => true, 405 'pagesonly' => true, 406 'firsthead' => true, 407 'sneakyacl' => $conf['sneaky_index'], 408 ); 409 if($id) $opts['filematch'] = '^.*\/'.$id; 410 if($id) $opts['dirmatch'] = '^.*\/'.$id; 411 search($data,$conf['datadir'],'search_universal',$opts,$nsd); 412 413 // add back to upper 414 if($ns){ 415 array_unshift($data,array( 416 'id' => getNS($ns), 417 'type' => 'u', 418 )); 419 } 420 } 421 422 // fixme sort results in a useful way ? 423 424 if(!count($data)){ 425 echo $lang['nothingfound']; 426 exit; 427 } 428 429 // output the found data 430 $even = 1; 431 foreach($data as $item){ 432 $even *= -1; //zebra 433 434 if(($item['type'] == 'd' || $item['type'] == 'u') && $item['id']) $item['id'] .= ':'; 435 $link = wl($item['id']); 436 437 echo '<div class="'.(($even > 0)?'even':'odd').' type_'.$item['type'].'">'; 438 439 if($item['type'] == 'u'){ 440 $name = $lang['upperns']; 441 }else{ 442 $name = htmlspecialchars($item['id']); 443 } 444 445 echo '<a href="'.$link.'" title="'.htmlspecialchars($item['id']).'" class="wikilink1">'.$name.'</a>'; 446 447 if(!blank($item['title'])){ 448 echo '<span>'.htmlspecialchars($item['title']).'</span>'; 449 } 450 echo '</div>'; 451 } 452 453} 454} 455//Setup VIM: ex: et ts=2 : 456