1<?php 2/** 3 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 4 * @author Gerrit Uitslag <klapinklapin@gmail.com> 5 */ 6 7/** 8 * Show book bar and pagetool button at a wiki page 9 */ 10class action_plugin_bookcreator_handleselection extends DokuWiki_Action_Plugin { 11 12 /** @var helper_plugin_bookcreator */ 13 protected $hlp; 14 15 /** 16 * Constructor 17 */ 18 public function __construct() { 19 $this->hlp = plugin_load('helper', 'bookcreator'); 20 } 21 22 /** 23 * Registers a callback function for a given event 24 * 25 * @param Doku_Event_Handler $controller 26 */ 27 public function register(Doku_Event_Handler $controller) { 28 $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, '_handle_ajax'); 29 } 30 31 32 /** 33 * Handle ajax requests for the book manager 34 * 35 * @param Doku_Event $event 36 */ 37 public function _handle_ajax(Doku_Event $event) { 38 if ($event->data !== 'plugin_bookcreator_call') { 39 return; 40 } 41 $event->stopPropagation(); 42 $event->preventDefault(); 43 44 global $INPUT; 45 46 try { 47 if(!checkSecurityToken()) { 48 throw new Exception('Security Token did not match. Possible CSRF attack.'); 49 } 50 51 $action = $INPUT->post->str('action', '', true); 52 switch($action) { 53 case 'retrievePageinfo': 54 $response = $this->retrievePageInfo($this->getPOSTedSelection()); 55 break; 56 case 'saveSelection': 57 $title = $INPUT->post->str('savedselectionname'); 58 $response = $this->saveSelection($title, $this->getPOSTedSelection()); 59 break; 60 case 'loadSavedSelection': 61 $page = $INPUT->post->str('savedselectionname'); 62 $response = $this->loadSavedSelection($page); 63 break; 64 case 'deleteSavedSelection': 65 $page = $INPUT->post->str('savedselectionname'); 66 $response = $this->deleteSavedSelection($page); 67 break; 68 case 'searchPages': 69 $namespace = $INPUT->post->str('ns'); 70 $recursive = $INPUT->post->str('r'); 71 $response = $this->searchPages($namespace, $recursive); 72 break; 73 default: 74 $response['error'] = 'unknown action '; 75 } 76 } catch(Exception $e){ 77 $response['error'] = $e->getMessage(); 78 } 79 80 header('Content-Type: application/json'); 81 echo json_encode($response); 82 } 83 84 /** 85 * Get POSTed selection 86 * 87 * @return array 88 */ 89 protected function getPOSTedSelection() { 90 global $INPUT; 91 92 $selection = json_decode($INPUT->post->str('selection', '', true), true); 93 if(!is_array($selection)) { 94 $selection = array(); 95 } 96 return $selection; 97 } 98 99 /** 100 * Return the titles and urls to given pageids 101 * 102 * @param array $selection 103 * @return array with slection 104 */ 105 private function retrievePageInfo($selection) { 106 $response['selection'] = array(); 107 foreach($selection as $pageid) { 108 $page = cleanID($pageid); 109 if(auth_quickaclcheck($pageid) < AUTH_READ) { 110 continue; 111 } 112 $response['selection'][$page] = array(wl($page, false, true, "&"), $this->getTitle($page)); 113 } 114 return $response; 115 } 116 117 /** 118 * Construct a link title 119 * 120 * @see Doku_Renderer_xhtml::_getLinkTitle 121 * 122 * @param string $pageid 123 * @return string 124 */ 125 protected function getTitle($pageid) { 126 global $conf; 127 128 if(useHeading('navigation') && $pageid) { 129 $heading = p_get_first_heading($pageid); 130 if($heading) { 131 return $this->_xmlEntities($heading); 132 } 133 } 134 135 // Removes any Namespace from the given name but keeps casing and special chars 136 if($conf['useslash']) { 137 $pageid = strtr($pageid, ';/', ';:'); 138 } else { 139 $pageid = strtr($pageid, ';', ':'); 140 } 141 142 $name = noNSorNS($pageid); 143 return $this->_xmlEntities($name); 144 } 145 146 /** 147 * Escape string for output 148 * 149 * @see Doku_Renderer_xhtml::_xmlEntities 150 * 151 * @param string $string 152 * @return string 153 */ 154 protected function _xmlEntities($string) { 155 return htmlspecialchars($string, ENT_QUOTES, 'UTF-8'); 156 } 157 158 /** 159 * Handle request for saving the selection list 160 * 161 * Selection is saved as bullet list on a wikipage 162 * 163 * @param string $savedSelectionName Title for saved selection 164 * @param array $selection 165 * @return array with message and item for the list of saved selections 166 * @throws Exception 167 */ 168 private function saveSelection($savedSelectionName, $selection) { 169 if(auth_quickaclcheck($this->getConf('save_namespace').':*') < AUTH_CREATE) { 170 throw new Exception('no access to namespace: ' . $this->getConf('save_namespace')); 171 } 172 if(empty($selection)) { 173 throw new Exception($this->getLang('empty')); 174 } 175 if(empty($savedSelectionName)){ 176 throw new Exception($this->getLang('needtitle')); 177 } 178 179 //generate content 180 $content = "====== ".$savedSelectionName." ======".DOKU_LF; 181 182 foreach($selection as $pageid) { 183 $content .= " * [[:$pageid]]".DOKU_LF; 184 } 185 186 $save_pageid = cleanID($this->getConf('save_namespace') . ":" . $savedSelectionName); 187 saveWikiText($save_pageid, $content, $this->getLang('selectionstored')); 188 189 $response['success'] = sprintf($this->getLang('saved'), $save_pageid); 190 191 $item = array( 192 'id' => $save_pageid, 193 'mtime' => filemtime(wikiFN($save_pageid)) 194 ); 195 $response['item'] = $this->hlp->createListitem($item, true); 196 return $response; 197 } 198 199 /** 200 * Handle request for deleting of selection list 201 * 202 * @param string $page with saved selection 203 * @return array with message and deleted page name 204 * @throws Exception 205 */ 206 private function deleteSavedSelection($page) { 207 if(auth_quickaclcheck($this->getConf('save_namespace').':*') < AUTH_CREATE) { 208 throw new Exception('no access to namespace: ' . $this->getConf('save_namespace')); 209 } 210 211 $pageid = cleanID($this->getConf('save_namespace') . ":" . $page); 212 213 if(!file_exists(wikiFN($pageid))){ 214 throw new Exception(sprintf($this->getLang('selectiondontexist'), $pageid)); 215 } 216 217 saveWikiText($pageid, '', $this->getLang('selectiondeleted')); 218 $response['success'] = sprintf($this->getLang('deleted'), $pageid); 219 $response['deletedpage'] = noNS($pageid); 220 return $response; 221 } 222 223 /** 224 * Load the specified saved selection 225 * 226 * @param string $page with saved selection 227 * @return array with title and a list of pages 228 * @throws Exception 229 */ 230 public function loadSavedSelection($page) { 231 $pageid = cleanID($this->getConf('save_namespace') . ":" . $page); 232 233 if($page === '') { 234 throw new Exception(sprintf($this->getLang('selectiondontexist'), $pageid .':')); 235 } 236 237 if(auth_quickaclcheck($pageid) < AUTH_READ) { 238 throw new Exception(sprintf($this->getLang('selectionforbidden'), $pageid)); 239 } 240 241 if(!file_exists(wikiFN($pageid))) { 242 throw new Exception(sprintf($this->getLang('selectiondontexist'), $pageid)); 243 } 244 245 list($title, $list) = $this->getSavedSelection($pageid); 246 $response['title'] = $title; 247 $response['selection'] = $list; 248 return $response; 249 } 250 251 /** 252 * Returns title and list of pages from a Saved Selection 253 * 254 * @param string $pageid pagename containing the selection 255 * @return array(title, array(list)) 256 */ 257 protected function getSavedSelection($pageid) { 258 $title = ''; 259 $list = array(); 260 261 $pagecontent = rawWiki($pageid); 262 $lines = explode("\n", $pagecontent); 263 264 foreach($lines as $i => $line) { 265 //skip nonsense 266 if(trim($line) == '') continue; 267 if((($i > 0) && substr($line, 0, 7) != " * [[:")) continue; 268 269 //read title and list 270 if($i === 0) { 271 $title = trim(str_replace("======", '', $line)); 272 } else { 273 $line = str_replace(" * [[:", '', $line); 274 $line = str_replace("]]", '', $line); 275 list($id, /* $title */) = explode('|', $line, 2); 276 $id = cleanID($id); 277 if($id == '') { 278 continue; 279 } 280 $list[] = $id; 281 } 282 } 283 284 return array($title, $list); 285 } 286 287 /** 288 * Returns an array of pages in the given namespace. 289 * 290 * @param string $ns The namespace to search in 291 * @param boolean $recursive Search in sub-namespaces too? 292 * @return array with a list pages 293 */ 294 protected function searchPages($ns, $recursive) { 295 global $conf; 296 297 // Use inc/search.php 298 if ($recursive == 'true') { 299 $opts = array(); 300 } else { 301 $count = substr_count($ns, ':'); 302 $opts = array('depth' => 1+$count); 303 } 304 $items = array(); 305 $ns = trim($ns, ':'); 306 $ns = utf8_encodeFN(str_replace(':', '/', $ns)); 307 search($items, $conf['datadir'], 'search_allpages', $opts, $ns); 308 309 // Generate result. 310 $pages = array(); 311 foreach ($items as $item) { 312 $pages [] = $item['id']; 313 } 314 315 $response['pages'] = $pages; 316 return $response; 317 } 318} 319