1<?php 2/** 3 * BookCreator plugin : Create a book from some pages. 4 * 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 * @author Luigi Micco <l.micco@tiscali.it> 7 */ 8 9// must be run within Dokuwiki 10use dokuwiki\Form\Form; 11 12/** 13 * All DokuWiki plugins to extend the parser/rendering mechanism 14 * need to inherit from this class 15 */ 16class syntax_plugin_bookcreator_bookmanager extends DokuWiki_Syntax_Plugin { 17 18 /** @var helper_plugin_bookcreator */ 19 protected $hlp; 20 21 /** 22 * Constructor 23 */ 24 public function __construct() { 25 $this->hlp = plugin_load('helper', 'bookcreator'); 26 } 27 /** 28 * @param string $mode 29 */ 30 function connectTo($mode) { 31 $this->Lexer->addSpecialPattern('~~\w*?BOOK.*?~~', $mode, 'plugin_bookcreator_bookmanager'); 32 } 33 34 /** 35 * Syntax Type 36 * 37 * @return string 38 */ 39 function getType() { 40 return 'container'; 41 } 42 43 /** 44 * Paragraph Type 45 * 46 * @return string 47 */ 48 function getPType() { 49 return 'block'; 50 } 51 52 /** 53 * Where to sort in? 54 */ 55 function getSort() { 56 return 190; 57 } 58 59 /** 60 * Handler to prepare matched data for the rendering process 61 * 62 * @param string $match The text matched by the patterns 63 * @param int $state The lexer state for the match 64 * @param int $pos The character position of the matched text 65 * @param Doku_Handler $handler The Doku_Handler object 66 * @return array Return an array with all data you want to use in render, false don't add an instruction 67 */ 68 function handle($match, $state, $pos, Doku_Handler $handler) { 69 70 $match = substr($match, 2, -2); // strip markup 71 if(substr($match, 0, 7) == 'ARCHIVE') { 72 $type = 'archive'; 73 } else { 74 $type = 'bookmanager'; 75 } 76 77 $num = 10; 78 $order = 'date'; 79 if($type == 'archive') { 80 [/* $junk */, $params] = array_pad(explode(':', $match, 2), 2, ''); 81 [$param1, $param2] = array_pad(explode('&', $params, 2),2, ''); 82 83 $sortoptions = ['date', 'title']; 84 if(is_numeric($param1)) { 85 $num = (int) $param1; 86 if(in_array($param2, $sortoptions)) { 87 $order = $param2; 88 } 89 } elseif(in_array($param1, $sortoptions)) { 90 $order = $param1; 91 if(is_numeric($param2)) { 92 $num = (int)$param2; 93 } 94 } elseif(is_numeric($param2)) { 95 $num = (int) $param2; 96 } 97 } 98 99 return array($type, $num, $order); 100 101 } 102 103 /** 104 * @param string $format render mode e.g. text, xhtml, meta,... 105 * @param Doku_Renderer $renderer 106 * @param array $data return of handle() 107 * @return bool 108 */ 109 function render($format, Doku_Renderer $renderer, $data) { 110 global $ID; 111 global $INPUT; 112 113 list($type, $num, $order) = $data; 114 115 if($type == "bookmanager") { 116 if($format == 'xhtml') { 117 /** @var Doku_Renderer_xhtml $renderer */ 118 $renderer->info['cache'] = false; 119 120 // verification that if the user can save / delete the selections 121 $usercansave = (auth_quickaclcheck($this->getConf('save_namespace').':*') >= AUTH_CREATE); 122 123 //intervents the normal export_* handling 124 $do = $INPUT->str('do'); 125 $ignore_onscreen_exports = [ 126 'export_html', 127 'export_htmlns' 128 ]; 129 if(in_array($do, $ignore_onscreen_exports)) { 130 //export as xhtml or text, is handled in action component 'export' 131 return false; 132 } 133 134 //show the bookmanager 135 $this->showBookManager($renderer, $usercansave); 136 137 // Displays the list of saved selections 138 $this->renderSelectionslist($renderer, true, $ID, $order); 139 $renderer->doc .= "<br />"; 140 } 141 142 } else { 143 // type == archive 144 145 if($format == 'xhtml') { 146 /** @var Doku_Renderer_xhtml $renderer */ 147 // generates the list of saved selections 148 $this->renderSelectionslist($renderer, false, $this->getConf('book_page'), $order, $num); 149 } 150 } 151 return false; 152 } 153 154 /** 155 * Generates the list of save selections 156 * 157 * @param Doku_Renderer_xhtml $renderer 158 * @param bool $bookmanager whether this list is displayed in the Book Manager 159 * @param string $bmpage pageid of the page with the Book Manager 160 * @param string $order sort by 'title' or 'date' 161 * @param int $num number of listed items, 0=all items 162 * 163 * if in the Book Manager, the delete buttons are displayed 164 * the list with save selections is only displayed once, and the bookmanager with priority 165 */ 166 public function renderSelectionslist($renderer, $bookmanager, $bmpage, $order, $num = 0) { 167 $result = $this->getlist($order, $num); 168 if(sizeof($result) > 0) { 169 $form = new Form(['action'=> wl($bmpage)]); 170 $form->addClass('bookcreator__selections__list'); 171 172 if($bookmanager) { 173 $form->addFieldsetOpen($this->getLang('listselections')); 174 $form->addHTML('<div class="message"></div>'); 175 } 176 $form->addHTML($this->showlist($result, $bookmanager)); 177 $form->setHiddenField('do', ''); 178 $form->setHiddenField('task', ''); 179 $form->setHiddenField('page', ''); 180 if($bookmanager) { 181 $form->addFieldsetClose(); 182 } 183 184 $renderer->doc .= $form->toHTML(); 185 } 186 } 187 188 /** 189 * Displays the Bookmanager - Let organize selections and export them 190 * Only visible when a selection is loaded from the save selections or from cookie FIXME 191 * 192 * @param Doku_renderer_xhtml $renderer 193 * @param bool $usercansave User has permissions to save the selection 194 */ 195 private function showBookManager($renderer, $usercansave) { 196 global $ID; 197// $title = ''; 198 199 //start main container - open left column 200 $renderer->doc .= "<div class='bookcreator__manager'>"; 201 // Display pagelists 202 // - selected pages 203 $renderer->doc .= "<div class='bookcreator__pagelist' >"; 204 $this->showPagelist($renderer, 'selected'); 205 $renderer->doc .= "<br />"; 206 207 // Add namespace to selection 208 209 $form = new dokuwiki\Form\Form(); 210 $form->addClass('selectnamespace'); 211 $form->addButton('selectns', $this->getLang('select_namespace')) 212 ->attr('type', 'submit'); 213 214 $renderer->doc .= "<div class='bookcreator__selectns'>"; 215 $renderer->doc .= $form->toHTML(); 216 $renderer->doc .= "</div>"; 217 218 // - excluded pages 219 $renderer->doc .= '<div id="bookcreator__delpglst">'; 220 $this->showPagelist($renderer, 'deleted'); 221 $renderer->doc .= '</div>'; 222 223 // Reset current selection 224 $form = new Form(); 225 $form->addClass('clearactive'); 226 $form->addButton('resetselection', $this->getLang('reset')) 227 ->attr('type', 'submit'); 228 229 $renderer->doc .= '<div>'; 230 $renderer->doc .= $form->toHTML(); 231 $renderer->doc .= '</div>'; 232 233 //close left column - open right column 234 $renderer->doc .= "</div>"; 235 $renderer->doc .= "<div class='bookcreator__actions'>"; 236 // PDF Export 237 $values = [ 238 'export_html'=> $this->getLang('exportprint') 239 ]; 240 $selected = 'export_html'; 241 if(file_exists(DOKU_PLUGIN."text/renderer.php") && !plugin_isdisabled("text")) { 242 $values['export_text'] = $this->getLang('exporttext'); 243 } 244 if(file_exists(DOKU_PLUGIN."odt/action/export.php") && !plugin_isdisabled("odt")) { 245 $values['export_odtbook'] = $this->getLang('exportodt'); 246 $selected = 'export_odtbook'; 247 } 248 if(file_exists(DOKU_PLUGIN."dw2pdf/action.php") && !plugin_isdisabled("dw2pdf")) { 249 $values['export_pdfbook'] = $this->getLang('exportpdf'); 250 $selected = 'export_pdfbook'; 251 } 252 253 $form = new Form(); 254 $form->addClass('downloadselection'); 255 256 $form->addFieldsetOpen($this->getLang('export')); 257 258 $form->addHTML($this->getLang('title')." "); 259 $form->addTextInput('book_title') 260 ->addClass('edit') 261 ->attrs(['size'=> 30]); 262 $form->addCheckbox('book_skipforbiddenpages', $this->getLang('skipforbiddenpages')) 263 ->addClass('book_skipforbiddenpages'); //note: class extra at input 264 $form->addDropdown('do', $values) 265 ->val($selected) 266 ->attrs(['size'=> 1]); 267 $form->setHiddenField('outputTarget', 'file'); 268 $form->setHiddenField('id', $ID); 269 $form->addButton('exportselection', $this->getLang('create'))->attr('type', 'submit'); 270 271 $form->addFieldsetClose(); 272 273 $renderer->doc .= $form->toHTML(); 274 275 276 // Save current selection to a wikipage 277 if($usercansave) { 278 $form = new Form(); 279 $form->addClass('saveselection'); 280 281 282 $form->addFieldsetOpen($this->getLang('saveselection')); 283 284 $form->addHTML('<div class="message"></div>'); 285 $form->addTextInput('bookcreator_title') 286 ->addClass('edit'); 287 $form->setHiddenField('task', 'save'); 288 $form->addButton('saveselection', $this->getLang('save'))->attr('type', 'submit'); 289 290 $form->addFieldsetClose(); 291 292 $renderer->doc .= $form->toHTML(); 293 } 294 295 //close containers 296 $renderer->doc .= '</div>' 297 . "</div><div class='clearer'></div>" 298 . "<br />"; 299 300 $renderer->doc .= "<div id='preparing-file-modal' title='{$this->getLang("titlepreparedownload")}' style='display: none;'>" 301 . $this->getLang('preparingdownload') 302 . ' <div class="ui-progressbar-value ui-corner-left ui-corner-right" style="width: 100%; height:22px; margin-top: 20px;"></div>' 303 . '</div>'; 304 305 $renderer->doc .= "<div id='error-modal' title='{$this->getLang("titleerrordownload")}' style='display: none;'>" 306 . " <div class='downloadresponse'>{$this->getLang('faileddownload')}</div>" 307 . '</div>'; 308 309 } 310 311 /** 312 * Displays list of selected/deleted pages 313 * 314 * @param Doku_Renderer_xhtml $renderer 315 * @param string $selection 'deleted' or 'selected' 316 */ 317 private function showPagelist($renderer, $selection) { 318 if($selection == 'deleted') { 319 $id = 'deletedpagelist'; 320 $heading = 'removed'; 321 } else { 322 $id = 'pagelist'; 323 $heading = 'toprint'; 324 } 325 326 $renderer->header($this->getLang($heading), 2, 0); 327 $renderer->doc .= "<ul id=$id class='pagelist $selection'>"; 328 $renderer->listu_close(); 329 } 330 331 /** 332 * usort callback to sort by file lastmodified time 333 * 334 * @param array $a 335 * @param array $b 336 * @return int 337 */ 338 function _datesort($a, $b) { 339 if($b['rev'] < $a['rev']) return -1; 340 if($b['rev'] > $a['rev']) return 1; 341 return strcmp($b['id'], $a['id']); 342 } 343 344 /** 345 * usort callback to sort by file title 346 * 347 * @param array $a 348 * @param array $b 349 * @return int 350 */ 351 function _titlesort($a, $b) { 352 if($a['id'] < $b['id']) return -1; 353 if($a['id'] > $b['id']) return 1; 354 return 0; 355 } 356 357 /** 358 * Lists saved selections, by looking up corresponding pages in the reserverd namespace 359 * 360 * @param string $order sort by 'date' or 'title' 361 * @param int $limit maximum number of selections, 0=all 362 * @return array 363 */ 364 private function getlist($order, $limit = 0) { 365 global $conf; 366 367 $ns = cleanID($this->getConf('save_namespace')); 368 $tt = utf8_encodeFN(str_replace(':', '/', $ns)); 369 $nsdepth = count(explode('/', $tt)); 370 $result = array(); 371 $opts = array( 372 'depth' => $nsdepth + 1, 373 'skipacl' => false 374 ); 375 $ns = cleanID($this->getConf('save_namespace')); 376 $tt = utf8_encodeFN(str_replace(':', '/', $ns)); 377 378 search($result, $conf['datadir'], 'search_allpages', $opts, $tt); 379 380 if(sizeof($result) > 0) { 381 382 if($order == 'date') { 383 usort($result, array($this, '_datesort')); 384 } elseif($order == 'title') { 385 usort($result, array($this, '_titlesort')); 386 } 387 388 if($limit != 0) $result = array_slice($result, 0, $limit); 389 } 390 return $result; 391 } 392 393 /** 394 * Displays the Selection List 395 * 396 * @param array $result results generated by search() 397 * @param bool $isbookmanager 398 * @return string html of list 399 */ 400 private function showlist($result, $isbookmanager = false) { 401 $output = '<ul>'; 402 foreach($result as $item) { 403 $output .= $this->hlp->createListitem($item, $isbookmanager); 404 } 405 $output .= '</ul>'; 406 return $output; 407 } 408} 409