6 use dokuwiki\Utf8\Sort
;
9 * Manage all builtin AJAX calls
11 * @todo The calls should be refactored out to their own proper classes
17 * Execute the given call
19 * @param string $call name of the ajax call
21 public function __construct($call) {
22 $callfn = 'call' . ucfirst($call);
23 if(method_exists($this, $callfn)) {
26 $evt = new Extension\
Event('AJAX_CALL_UNKNOWN', $call);
27 if($evt->advise_before()) {
28 print "AJAX call '" . hsc($call) . "' unknown!\n";
37 * Searches for matching pagenames
39 * @author Andreas Gohr <andi@splitbrain.org>
41 protected function callQsearch() {
45 $maxnumbersuggestions = 50;
47 $query = $INPUT->post
->str('q');
48 if(empty($query)) $query = $INPUT->get
->str('q');
49 if(empty($query)) return;
51 $query = urldecode($query);
53 $data = ft_pageLookup($query, true, useHeading('navigation'));
55 if(!count($data)) return;
57 print '<strong>' . $lang['quickhits'] . '</strong>';
60 foreach($data as $id => $title) {
61 if(useHeading('navigation')) {
66 $name = noNS($id) . ' (' . $ns . ')';
71 echo '<li>' . html_wikilink(':' . $id, $name) . '</li>';
74 if($counter > $maxnumbersuggestions) {
83 * Support OpenSearch suggestions
85 * @link http://www.opensearch.org/Specifications/OpenSearch/Extensions/Suggestions/1.0
86 * @author Mike Frysinger <vapier@gentoo.org>
88 protected function callSuggestions() {
91 $query = cleanID($INPUT->post
->str('q'));
92 if(empty($query)) $query = cleanID($INPUT->get
->str('q'));
93 if(empty($query)) return;
95 $data = ft_pageLookup($query);
96 if(!count($data)) return;
97 $data = array_keys($data);
99 // limit results to 15 hits
100 $data = array_slice($data, 0, 15);
101 $data = array_map('trim', $data);
102 $data = array_map('noNS', $data);
103 $data = array_unique($data);
106 /* now construct a json */
107 $suggestions = array(
108 $query, // the original query
109 $data, // some suggestions
110 array(), // no description
114 header('Content-Type: application/x-suggestions+json');
115 print json_encode($suggestions);
119 * Refresh a page lock and save draft
121 * Andreas Gohr <andi@splitbrain.org>
123 protected function callLock() {
128 $ID = cleanID($INPUT->post
->str('id'));
129 if(empty($ID)) return;
138 if(!$INFO['writable']) {
139 $response['errors'][] = 'Permission to write this page has been denied.';
140 echo json_encode($response);
144 if(!checklock($ID)) {
146 $response['lock'] = '1';
149 $draft = new Draft($ID, $INFO['client']);
150 if ($draft->saveDraft()) {
151 $response['draft'] = $draft->getDraftMessage();
153 $response['errors'] = array_merge($response['errors'], $draft->getErrors());
155 echo json_encode($response);
161 * @author Andreas Gohr <andi@splitbrain.org>
163 protected function callDraftdel() {
165 $id = cleanID($INPUT->str('id'));
166 if(empty($id)) return;
168 $client = $INPUT->server
->str('REMOTE_USER');
169 if(!$client) $client = clientIP(true);
171 $draft = new Draft($id, $client);
172 if ($draft->isDraftAvailable() && checkSecurityToken()) {
173 $draft->deleteDraft();
178 * Return subnamespaces for the Mediamanager
180 * @author Andreas Gohr <andi@splitbrain.org>
182 protected function callMedians() {
187 $ns = cleanID($INPUT->post
->str('ns'));
188 $dir = utf8_encodeFN(str_replace(':', '/', $ns));
190 $lvl = count(explode(':', $ns));
193 search($data, $conf['mediadir'], 'search_index', array('nofiles' => true), $dir);
194 foreach(array_keys($data) as $item) {
195 $data[$item]['level'] = $lvl +
1;
197 echo html_buildlist($data, 'idx', 'media_nstree_item', 'media_nstree_li');
201 * Return list of files for the Mediamanager
203 * @author Andreas Gohr <andi@splitbrain.org>
205 protected function callMedialist() {
209 $NS = cleanID($INPUT->post
->str('ns'));
210 $sort = $INPUT->post
->bool('recent') ?
'date' : 'natural';
211 if($INPUT->post
->str('do') == 'media') {
214 tpl_mediaContent(true, $sort);
219 * Return the content of the right column
220 * (image details) for the Mediamanager
222 * @author Kate Arzamastseva <pshns@ukr.net>
224 protected function callMediadetails() {
225 global $IMG, $JUMPTO, $REV, $fullscreen, $INPUT;
227 require_once(DOKU_INC
. 'lib/exe/mediamanager.php');
230 if($INPUT->has('image')) $image = cleanID($INPUT->str('image'));
231 if(isset($IMG)) $image = $IMG;
232 if(isset($JUMPTO)) $image = $JUMPTO;
234 if(isset($REV) && !$JUMPTO) $rev = $REV;
237 tpl_mediaFileDetails($image, $rev);
241 * Returns image diff representation for mediamanager
243 * @author Kate Arzamastseva <pshns@ukr.net>
245 protected function callMediadiff() {
249 if($INPUT->has('image')) $image = cleanID($INPUT->str('image'));
250 (new Ui\
MediaDiff($image))->preference('fromAjax', true)->show();
254 * Manages file uploads
256 * @author Kate Arzamastseva <pshns@ukr.net>
258 protected function callMediaupload() {
259 global $NS, $MSG, $INPUT;
262 if(isset($_FILES['qqfile']['tmp_name'])) {
263 $id = $INPUT->post
->str('mediaid', $_FILES['qqfile']['name']);
264 } elseif($INPUT->get
->has('qqfile')) {
265 $id = $INPUT->get
->str('qqfile');
270 $NS = $INPUT->str('ns');
271 $ns = $NS . ':' . getNS($id);
273 $AUTH = auth_quickaclcheck("$ns:*");
274 if($AUTH >= AUTH_UPLOAD
) {
275 io_createNamespace("$ns:xxx", 'media');
278 if(isset($_FILES['qqfile']['error']) && $_FILES['qqfile']['error']) unset($_FILES['qqfile']);
281 if(isset($_FILES['qqfile']['tmp_name'])) $res = media_upload($NS, $AUTH, $_FILES['qqfile']);
282 if($INPUT->get
->has('qqfile')) $res = media_upload_xhr($NS, $AUTH);
287 'link' => media_managerURL(array('ns' => $ns, 'image' => $NS . ':' . $id), '&'),
288 'id' => $NS . ':' . $id,
294 foreach($MSG as $msg) {
295 $error .= $msg['msg'];
304 header('Content-Type: application/json');
305 echo json_encode($result);
309 * Return sub index for index view
311 * @author Andreas Gohr <andi@splitbrain.org>
313 protected function callIndex() {
318 $ns = cleanID($INPUT->post
->str('idx'));
319 $dir = utf8_encodeFN(str_replace(':', '/', $ns));
321 $lvl = count(explode(':', $ns));
324 search($data, $conf['datadir'], 'search_index', array('ns' => $ns), $dir);
325 foreach (array_keys($data) as $item) {
326 $data[$item]['level'] = $lvl +
1;
329 echo html_buildlist($data, 'idx', [$idx,'formatListItem'], [$idx,'tagListItem']);
333 * List matching namespaces and pages for the link wizard
335 * @author Andreas Gohr <gohr@cosmocode.de>
337 protected function callLinkwiz() {
342 $q = ltrim(trim($INPUT->post
->str('q')), ':');
349 $nsd = utf8_encodeFN(str_replace(':', '/', $ns));
352 if($q !== '' && $ns === '') {
354 // use index to lookup matching pages
355 $pages = ft_pageLookup($id, true);
357 // If 'useheading' option is 'always' or 'content',
358 // search page titles with original query as well.
359 if ($conf['useheading'] == '1' ||
$conf['useheading'] == 'content') {
360 $pages = array_merge($pages, ft_pageLookup($q, true, true));
361 asort($pages, SORT_STRING
);
364 // result contains matches in pages and namespaces
365 // we now extract the matching namespaces to show
369 foreach($pages as $pid => $title) {
370 if(strpos(getNS($pid), $id) !== false) {
371 // match was in the namespace
372 $dirs[getNS($pid)] = 1; // assoc array avoids dupes
374 // it is a matching page, add it to the result
383 foreach($dirs as $dir => $junk) {
398 'sneakyacl' => $conf['sneaky_index'],
400 if($id) $opts['filematch'] = '^.*\/' . $id;
401 if($id) $opts['dirmatch'] = '^.*\/' . $id;
402 search($data, $conf['datadir'], 'search_universal', $opts, $nsd);
415 // fixme sort results in a useful way ?
418 echo $lang['nothingfound'];
422 // output the found data
424 foreach($data as $item) {
427 if(($item['type'] == 'd' ||
$item['type'] == 'u') && $item['id'] !== '') $item['id'] .= ':';
428 $link = wl($item['id']);
430 echo '<div class="' . (($even > 0) ?
'even' : 'odd') . ' type_' . $item['type'] . '">';
432 if($item['type'] == 'u') {
433 $name = $lang['upperns'];
435 $name = hsc($item['id']);
438 echo '<a href="' . $link . '" title="' . hsc($item['id']) . '" class="wikilink1">' . $name . '</a>';
440 if(!blank($item['title'])) {
441 echo '<span>' . hsc($item['title']) . '</span>';