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) && $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']; 25else if(isset($_GET['call'])) 26 $call = $_GET['call']; 27else 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, false); 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 = shorten(noNS($id), ' ('.$ns.')',30); 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 97 // limit results to 15 hits 98 $data = array_slice($data, 0, 15); 99 $data = array_map('trim',$data); 100 $data = array_map('noNS',$data); 101 $data = array_unique($data); 102 sort($data); 103 104 /* now construct a json */ 105 $suggestions = array( 106 $query, // the original query 107 $data, // some suggestions 108 array(), // no description 109 array() // no urls 110 ); 111 $json = new JSON(); 112 113 header('Content-Type: application/x-suggestions+json'); 114 print $json->encode($suggestions); 115} 116 117/** 118 * Refresh a page lock and save draft 119 * 120 * Andreas Gohr <andi@splitbrain.org> 121 */ 122function ajax_lock(){ 123 global $conf; 124 global $lang; 125 $id = cleanID($_POST['id']); 126 if(empty($id)) return; 127 128 if(!checklock($id)){ 129 lock($id); 130 echo 1; 131 } 132 133 if($conf['usedraft'] && $_POST['wikitext']){ 134 $client = $_SERVER['REMOTE_USER']; 135 if(!$client) $client = clientIP(true); 136 137 $draft = array('id' => $id, 138 'prefix' => $_POST['prefix'], 139 'text' => $_POST['wikitext'], 140 'suffix' => $_POST['suffix'], 141 'date' => $_POST['date'], 142 'client' => $client, 143 ); 144 $cname = getCacheName($draft['client'].$id,'.draft'); 145 if(io_saveFile($cname,serialize($draft))){ 146 echo $lang['draftdate'].' '.dformat(); 147 } 148 } 149 150} 151 152/** 153 * Delete a draft 154 * 155 * @author Andreas Gohr <andi@splitbrain.org> 156 */ 157function ajax_draftdel(){ 158 $id = cleanID($_POST['id']); 159 if(empty($id)) return; 160 161 $client = $_SERVER['REMOTE_USER']; 162 if(!$client) $client = clientIP(true); 163 164 $cname = getCacheName($client.$id,'.draft'); 165 @unlink($cname); 166} 167 168/** 169 * Return subnamespaces for the Mediamanager 170 * 171 * @author Andreas Gohr <andi@splitbrain.org> 172 */ 173function ajax_medians(){ 174 global $conf; 175 176 // wanted namespace 177 $ns = cleanID($_POST['ns']); 178 $dir = utf8_encodeFN(str_replace(':','/',$ns)); 179 180 $lvl = count(explode(':',$ns)); 181 182 $data = array(); 183 search($data,$conf['mediadir'],'search_index',array('nofiles' => true),$dir); 184 foreach($data as $item){ 185 $item['level'] = $lvl+1; 186 echo media_nstree_li($item); 187 echo media_nstree_item($item); 188 echo '</li>'; 189 } 190} 191 192/** 193 * Return list of files for the Mediamanager 194 * 195 * @author Andreas Gohr <andi@splitbrain.org> 196 */ 197function ajax_medialist(){ 198 global $conf; 199 global $NS; 200 201 $NS = $_POST['ns']; 202 tpl_mediaContent(true); 203} 204 205/** 206 * Return sub index for index view 207 * 208 * @author Andreas Gohr <andi@splitbrain.org> 209 */ 210function ajax_index(){ 211 global $conf; 212 213 // wanted namespace 214 $ns = cleanID($_POST['idx']); 215 $dir = utf8_encodeFN(str_replace(':','/',$ns)); 216 217 $lvl = count(explode(':',$ns)); 218 219 $data = array(); 220 search($data,$conf['datadir'],'search_index',array('ns' => $ns),$dir); 221 foreach($data as $item){ 222 $item['level'] = $lvl+1; 223 echo html_li_index($item); 224 echo '<div class="li">'; 225 echo html_list_index($item); 226 echo '</div>'; 227 echo '</li>'; 228 } 229} 230 231/** 232 * List matching namespaces and pages for the link wizard 233 * 234 * @author Andreas Gohr <gohr@cosmocode.de> 235 */ 236function ajax_linkwiz(){ 237 global $conf; 238 global $lang; 239 240 $q = ltrim($_POST['q'],':'); 241 $id = noNS($q); 242 $ns = getNS($q); 243 244 $ns = cleanID($ns); 245 $id = cleanID($id); 246 247 $nsd = utf8_encodeFN(str_replace(':','/',$ns)); 248 $idd = utf8_encodeFN(str_replace(':','/',$id)); 249 250 $data = array(); 251 if($q && !$ns){ 252 253 // use index to lookup matching pages 254 $pages = array(); 255 $pages = ft_pageLookup($id,false); 256 257 // result contains matches in pages and namespaces 258 // we now extract the matching namespaces to show 259 // them seperately 260 $dirs = array(); 261 $count = count($pages); 262 for($i=0; $i<$count; $i++){ 263 if(strpos(noNS($pages[$i]),$id) === false){ 264 // match was in the namespace 265 $dirs[getNS($pages[$i])] = 1; // assoc array avoids dupes 266 }else{ 267 // it is a matching page, add it to the result 268 $data[] = array( 269 'id' => $pages[$i], 270 'title' => p_get_first_heading($pages[$i],false), 271 'type' => 'f', 272 ); 273 } 274 unset($pages[$i]); 275 } 276 foreach($dirs as $dir => $junk){ 277 $data[] = array( 278 'id' => $dir, 279 'type' => 'd', 280 ); 281 } 282 283 }else{ 284 285 $opts = array( 286 'depth' => 1, 287 'listfiles' => true, 288 'listdirs' => true, 289 'pagesonly' => true, 290 'firsthead' => true, 291 'sneakyacl' => $conf['sneaky_index'], 292 ); 293 if($id) $opts['filematch'] = '^.*\/'.$id; 294 if($id) $opts['dirmatch'] = '^.*\/'.$id; 295 search($data,$conf['datadir'],'search_universal',$opts,$nsd); 296 297 // add back to upper 298 if($ns){ 299 array_unshift($data,array( 300 'id' => getNS($ns), 301 'type' => 'u', 302 )); 303 } 304 } 305 306 // fixme sort results in a useful way ? 307 308 if(!count($data)){ 309 echo $lang['nothingfound']; 310 exit; 311 } 312 313 // output the found data 314 $even = 1; 315 foreach($data as $item){ 316 $even *= -1; //zebra 317 318 if(($item['type'] == 'd' || $item['type'] == 'u') && $item['id']) $item['id'] .= ':'; 319 $link = wl($item['id']); 320 321 echo '<div class="'.(($even > 0)?'even':'odd').' type_'.$item['type'].'">'; 322 323 324 if($item['type'] == 'u'){ 325 $name = $lang['upperns']; 326 }else{ 327 $name = htmlspecialchars($item['id']); 328 } 329 330 echo '<a href="'.$link.'" title="'.htmlspecialchars($item['id']).'" class="wikilink1">'.$name.'</a>'; 331 332 if($item['title']){ 333 echo '<span>'.htmlspecialchars($item['title']).'</span>'; 334 } 335 echo '</div>'; 336 } 337 338} 339 340//Setup VIM: ex: et ts=2 enc=utf-8 : 341