[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Book module local lib functions 19 * 20 * @package mod_book 21 * @copyright 2010-2011 Petr Skoda {@link http://skodak.org} 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 defined('MOODLE_INTERNAL') || die; 26 27 require_once (__DIR__.'/lib.php'); 28 require_once($CFG->libdir.'/filelib.php'); 29 30 /** 31 * The following defines are used to define how the chapters and subchapters of a book should be displayed in that table of contents. 32 * BOOK_NUM_NONE No special styling will applied and the editor will be able to do what ever thay want in the title 33 * BOOK_NUM_NUMBERS Chapters and subchapters are numbered (1, 1.1, 1.2, 2, ...) 34 * BOOK_NUM_BULLETS Subchapters are indented and displayed with bullets 35 * BOOK_NUM_INDENTED Subchapters are indented 36 */ 37 define('BOOK_NUM_NONE', '0'); 38 define('BOOK_NUM_NUMBERS', '1'); 39 define('BOOK_NUM_BULLETS', '2'); 40 define('BOOK_NUM_INDENTED', '3'); 41 42 /** 43 * The following defines are used to define the navigation style used within a book. 44 * BOOK_LINK_TOCONLY Only the table of contents is shown, in a side region. 45 * BOOK_LINK_IMAGE Arrows link to previous/next/exit pages, in addition to the TOC. 46 * BOOK_LINK_TEXT Page names and arrows link to previous/next/exit pages, in addition to the TOC. 47 */ 48 define ('BOOK_LINK_TOCONLY', '0'); 49 define ('BOOK_LINK_IMAGE', '1'); 50 define ('BOOK_LINK_TEXT', '2'); 51 52 /** 53 * Preload book chapters and fix toc structure if necessary. 54 * 55 * Returns array of chapters with standard 'pagenum', 'id, pagenum, subchapter, title, hidden' 56 * and extra 'parent, number, subchapters, prev, next'. 57 * Please note the content/text of chapters is not included. 58 * 59 * @param stdClass $book 60 * @return array of id=>chapter 61 */ 62 function book_preload_chapters($book) { 63 global $DB; 64 $chapters = $DB->get_records('book_chapters', array('bookid'=>$book->id), 'pagenum', 'id, pagenum, subchapter, title, hidden'); 65 if (!$chapters) { 66 return array(); 67 } 68 69 $prev = null; 70 $prevsub = null; 71 72 $first = true; 73 $hidesub = true; 74 $parent = null; 75 $pagenum = 0; // chapter sort 76 $i = 0; // main chapter num 77 $j = 0; // subchapter num 78 foreach ($chapters as $id => $ch) { 79 $oldch = clone($ch); 80 $pagenum++; 81 $ch->pagenum = $pagenum; 82 if ($first) { 83 // book can not start with a subchapter 84 $ch->subchapter = 0; 85 $first = false; 86 } 87 if (!$ch->subchapter) { 88 if ($ch->hidden) { 89 if ($book->numbering == BOOK_NUM_NUMBERS) { 90 $ch->number = 'x'; 91 } else { 92 $ch->number = null; 93 } 94 } else { 95 $i++; 96 $ch->number = $i; 97 } 98 $j = 0; 99 $prevsub = null; 100 $hidesub = $ch->hidden; 101 $parent = $ch->id; 102 $ch->parent = null; 103 $ch->subchapters = array(); 104 } else { 105 $ch->parent = $parent; 106 $ch->subchapters = null; 107 $chapters[$parent]->subchapters[$ch->id] = $ch->id; 108 if ($hidesub) { 109 // all subchapters in hidden chapter must be hidden too 110 $ch->hidden = 1; 111 } 112 if ($ch->hidden) { 113 if ($book->numbering == BOOK_NUM_NUMBERS) { 114 $ch->number = 'x'; 115 } else { 116 $ch->number = null; 117 } 118 } else { 119 $j++; 120 $ch->number = $j; 121 } 122 } 123 124 if ($oldch->subchapter != $ch->subchapter or $oldch->pagenum != $ch->pagenum or $oldch->hidden != $ch->hidden) { 125 // update only if something changed 126 $DB->update_record('book_chapters', $ch); 127 } 128 $chapters[$id] = $ch; 129 } 130 131 return $chapters; 132 } 133 134 /** 135 * Returns the title for a given chapter 136 * 137 * @param int $chid 138 * @param array $chapters 139 * @param stdClass $book 140 * @param context_module $context 141 * @return string 142 */ 143 function book_get_chapter_title($chid, $chapters, $book, $context) { 144 $ch = $chapters[$chid]; 145 $title = trim(format_string($ch->title, true, array('context'=>$context))); 146 $numbers = array(); 147 if ($book->numbering == BOOK_NUM_NUMBERS) { 148 if ($ch->parent and $chapters[$ch->parent]->number) { 149 $numbers[] = $chapters[$ch->parent]->number; 150 } 151 if ($ch->number) { 152 $numbers[] = $ch->number; 153 } 154 } 155 156 if ($numbers) { 157 $title = implode('.', $numbers).' '.$title; 158 } 159 160 return $title; 161 } 162 163 /** 164 * Add the book TOC sticky block to the default region 165 * 166 * @param array $chapters 167 * @param stdClass $chapter 168 * @param stdClass $book 169 * @param stdClass $cm 170 * @param bool $edit 171 */ 172 function book_add_fake_block($chapters, $chapter, $book, $cm, $edit) { 173 global $OUTPUT, $PAGE; 174 175 $toc = book_get_toc($chapters, $chapter, $book, $cm, $edit, 0); 176 177 $bc = new block_contents(); 178 $bc->title = get_string('toc', 'mod_book'); 179 $bc->attributes['class'] = 'block block_book_toc'; 180 $bc->content = $toc; 181 182 $defaultregion = $PAGE->blocks->get_default_region(); 183 $PAGE->blocks->add_fake_block($bc, $defaultregion); 184 } 185 186 /** 187 * Generate toc structure 188 * 189 * @param array $chapters 190 * @param stdClass $chapter 191 * @param stdClass $book 192 * @param stdClass $cm 193 * @param bool $edit 194 * @return string 195 */ 196 function book_get_toc($chapters, $chapter, $book, $cm, $edit) { 197 global $USER, $OUTPUT; 198 199 $toc = ''; 200 $nch = 0; // Chapter number 201 $ns = 0; // Subchapter number 202 $first = 1; 203 204 $context = context_module::instance($cm->id); 205 206 switch ($book->numbering) { 207 case BOOK_NUM_NONE: 208 $toc .= html_writer::start_tag('div', array('class' => 'book_toc_none clearfix')); 209 break; 210 case BOOK_NUM_NUMBERS: 211 $toc .= html_writer::start_tag('div', array('class' => 'book_toc_numbered clearfix')); 212 break; 213 case BOOK_NUM_BULLETS: 214 $toc .= html_writer::start_tag('div', array('class' => 'book_toc_bullets clearfix')); 215 break; 216 case BOOK_NUM_INDENTED: 217 $toc .= html_writer::start_tag('div', array('class' => 'book_toc_indented clearfix')); 218 break; 219 } 220 221 if ($edit) { // Teacher's TOC 222 $toc .= html_writer::start_tag('ul'); 223 $i = 0; 224 foreach ($chapters as $ch) { 225 $i++; 226 $title = trim(format_string($ch->title, true, array('context' => $context))); 227 $titleunescaped = trim(format_string($ch->title, true, array('context' => $context, 'escape' => false))); 228 $titleout = $title; 229 230 if (!$ch->subchapter) { 231 232 if ($first) { 233 $toc .= html_writer::start_tag('li', array('class' => 'clearfix')); 234 } else { 235 $toc .= html_writer::end_tag('ul'); 236 $toc .= html_writer::end_tag('li'); 237 $toc .= html_writer::start_tag('li', array('class' => 'clearfix')); 238 } 239 240 if (!$ch->hidden) { 241 $nch++; 242 $ns = 0; 243 if ($book->numbering == BOOK_NUM_NUMBERS) { 244 $title = "$nch $title"; 245 $titleout = $title; 246 } 247 } else { 248 if ($book->numbering == BOOK_NUM_NUMBERS) { 249 $title = "x $title"; 250 } 251 $titleout = html_writer::tag('span', $title, array('class' => 'dimmed_text')); 252 } 253 } else { 254 255 if ($first) { 256 $toc .= html_writer::start_tag('li', array('class' => 'clearfix')); 257 $toc .= html_writer::start_tag('ul'); 258 $toc .= html_writer::start_tag('li', array('class' => 'clearfix')); 259 } else { 260 $toc .= html_writer::start_tag('li', array('class' => 'clearfix')); 261 } 262 263 if (!$ch->hidden) { 264 $ns++; 265 if ($book->numbering == BOOK_NUM_NUMBERS) { 266 $title = "$nch.$ns $title"; 267 $titleout = $title; 268 } 269 } else { 270 if ($book->numbering == BOOK_NUM_NUMBERS) { 271 if (empty($chapters[$ch->parent]->hidden)) { 272 $title = "$nch.x $title"; 273 } else { 274 $title = "x.x $title"; 275 } 276 } 277 $titleout = html_writer::tag('span', $title, array('class' => 'dimmed_text')); 278 } 279 } 280 281 if ($ch->id == $chapter->id) { 282 $toc .= html_writer::tag('strong', $titleout); 283 } else { 284 $toc .= html_writer::link(new moodle_url('view.php', array('id' => $cm->id, 'chapterid' => $ch->id)), $titleout, 285 array('title' => $titleunescaped)); 286 } 287 288 $toc .= html_writer::start_tag('div', array('class' => 'action-list')); 289 if ($i != 1) { 290 $toc .= html_writer::link(new moodle_url('move.php', array('id' => $cm->id, 'chapterid' => $ch->id, 'up' => '1', 'sesskey' => $USER->sesskey)), 291 $OUTPUT->pix_icon('t/up', get_string('movechapterup', 'mod_book', $title)), 292 array('title' => get_string('movechapterup', 'mod_book', $titleunescaped))); 293 } 294 if ($i != count($chapters)) { 295 $toc .= html_writer::link(new moodle_url('move.php', array('id' => $cm->id, 'chapterid' => $ch->id, 'up' => '0', 'sesskey' => $USER->sesskey)), 296 $OUTPUT->pix_icon('t/down', get_string('movechapterdown', 'mod_book', $title)), 297 array('title' => get_string('movechapterdown', 'mod_book', $titleunescaped))); 298 } 299 $toc .= html_writer::link(new moodle_url('edit.php', array('cmid' => $cm->id, 'id' => $ch->id)), 300 $OUTPUT->pix_icon('t/edit', get_string('editchapter', 'mod_book', $title)), 301 array('title' => get_string('editchapter', 'mod_book', $titleunescaped))); 302 $toc .= html_writer::link(new moodle_url('delete.php', array('id' => $cm->id, 'chapterid' => $ch->id, 'sesskey' => $USER->sesskey)), 303 $OUTPUT->pix_icon('t/delete', get_string('deletechapter', 'mod_book', $title)), 304 array('title' => get_string('deletechapter', 'mod_book', $titleunescaped))); 305 if ($ch->hidden) { 306 $toc .= html_writer::link(new moodle_url('show.php', array('id' => $cm->id, 'chapterid' => $ch->id, 'sesskey' => $USER->sesskey)), 307 $OUTPUT->pix_icon('t/show', get_string('showchapter', 'mod_book', $title)), 308 array('title' => get_string('showchapter', 'mod_book', $titleunescaped))); 309 } else { 310 $toc .= html_writer::link(new moodle_url('show.php', array('id' => $cm->id, 'chapterid' => $ch->id, 'sesskey' => $USER->sesskey)), 311 $OUTPUT->pix_icon('t/hide', get_string('hidechapter', 'mod_book', $title)), 312 array('title' => get_string('hidechapter', 'mod_book', $titleunescaped))); 313 } 314 $toc .= html_writer::link(new moodle_url('edit.php', array('cmid' => $cm->id, 'pagenum' => $ch->pagenum, 'subchapter' => $ch->subchapter)), 315 $OUTPUT->pix_icon('add', get_string('addafter', 'mod_book'), 'mod_book'), array('title' => get_string('addafter', 'mod_book'))); 316 $toc .= html_writer::end_tag('div'); 317 318 if (!$ch->subchapter) { 319 $toc .= html_writer::start_tag('ul'); 320 } else { 321 $toc .= html_writer::end_tag('li'); 322 } 323 $first = 0; 324 } 325 326 $toc .= html_writer::end_tag('ul'); 327 $toc .= html_writer::end_tag('li'); 328 $toc .= html_writer::end_tag('ul'); 329 330 } else { // Normal students view 331 $toc .= html_writer::start_tag('ul'); 332 foreach ($chapters as $ch) { 333 $title = trim(format_string($ch->title, true, array('context'=>$context))); 334 $titleunescaped = trim(format_string($ch->title, true, array('context' => $context, 'escape' => false))); 335 if (!$ch->hidden) { 336 if (!$ch->subchapter) { 337 $nch++; 338 $ns = 0; 339 340 if ($first) { 341 $toc .= html_writer::start_tag('li', array('class' => 'clearfix')); 342 } else { 343 $toc .= html_writer::end_tag('ul'); 344 $toc .= html_writer::end_tag('li'); 345 $toc .= html_writer::start_tag('li', array('class' => 'clearfix')); 346 } 347 348 if ($book->numbering == BOOK_NUM_NUMBERS) { 349 $title = "$nch $title"; 350 } 351 } else { 352 $ns++; 353 354 if ($first) { 355 $toc .= html_writer::start_tag('li', array('class' => 'clearfix')); 356 $toc .= html_writer::start_tag('ul'); 357 $toc .= html_writer::start_tag('li', array('class' => 'clearfix')); 358 } else { 359 $toc .= html_writer::start_tag('li', array('class' => 'clearfix')); 360 } 361 362 if ($book->numbering == BOOK_NUM_NUMBERS) { 363 $title = "$nch.$ns $title"; 364 } 365 } 366 if ($ch->id == $chapter->id) { 367 $toc .= html_writer::tag('strong', $title); 368 } else { 369 $toc .= html_writer::link(new moodle_url('view.php', 370 array('id' => $cm->id, 'chapterid' => $ch->id)), 371 $title, array('title' => s($titleunescaped))); 372 } 373 374 if (!$ch->subchapter) { 375 $toc .= html_writer::start_tag('ul'); 376 } else { 377 $toc .= html_writer::end_tag('li'); 378 } 379 380 $first = 0; 381 } 382 } 383 384 $toc .= html_writer::end_tag('ul'); 385 $toc .= html_writer::end_tag('li'); 386 $toc .= html_writer::end_tag('ul'); 387 388 } 389 390 $toc .= html_writer::end_tag('div'); 391 392 $toc = str_replace('<ul></ul>', '', $toc); // Cleanup of invalid structures. 393 394 return $toc; 395 } 396 397 398 /** 399 * File browsing support class 400 * 401 * @copyright 2010-2011 Petr Skoda {@link http://skodak.org} 402 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 403 */ 404 class book_file_info extends file_info { 405 /** @var stdClass Course object */ 406 protected $course; 407 /** @var stdClass Course module object */ 408 protected $cm; 409 /** @var array Available file areas */ 410 protected $areas; 411 /** @var string File area to browse */ 412 protected $filearea; 413 414 /** 415 * Constructor 416 * 417 * @param file_browser $browser file_browser instance 418 * @param stdClass $course course object 419 * @param stdClass $cm course module object 420 * @param stdClass $context module context 421 * @param array $areas available file areas 422 * @param string $filearea file area to browse 423 */ 424 public function __construct($browser, $course, $cm, $context, $areas, $filearea) { 425 parent::__construct($browser, $context); 426 $this->course = $course; 427 $this->cm = $cm; 428 $this->areas = $areas; 429 $this->filearea = $filearea; 430 } 431 432 /** 433 * Returns list of standard virtual file/directory identification. 434 * The difference from stored_file parameters is that null values 435 * are allowed in all fields 436 * @return array with keys contextid, filearea, itemid, filepath and filename 437 */ 438 public function get_params() { 439 return array('contextid'=>$this->context->id, 440 'component'=>'mod_book', 441 'filearea' =>$this->filearea, 442 'itemid' =>null, 443 'filepath' =>null, 444 'filename' =>null); 445 } 446 447 /** 448 * Returns localised visible name. 449 * @return string 450 */ 451 public function get_visible_name() { 452 return $this->areas[$this->filearea]; 453 } 454 455 /** 456 * Can I add new files or directories? 457 * @return bool 458 */ 459 public function is_writable() { 460 return false; 461 } 462 463 /** 464 * Is directory? 465 * @return bool 466 */ 467 public function is_directory() { 468 return true; 469 } 470 471 /** 472 * Returns list of children. 473 * @return array of file_info instances 474 */ 475 public function get_children() { 476 return $this->get_filtered_children('*', false, true); 477 } 478 479 /** 480 * Help function to return files matching extensions or their count 481 * 482 * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg') 483 * @param bool|int $countonly if false returns the children, if an int returns just the 484 * count of children but stops counting when $countonly number of children is reached 485 * @param bool $returnemptyfolders if true returns items that don't have matching files inside 486 * @return array|int array of file_info instances or the count 487 */ 488 private function get_filtered_children($extensions = '*', $countonly = false, $returnemptyfolders = false) { 489 global $DB; 490 $params = array('contextid' => $this->context->id, 491 'component' => 'mod_book', 492 'filearea' => $this->filearea, 493 'bookid' => $this->cm->instance); 494 $sql = 'SELECT DISTINCT bc.id, bc.pagenum 495 FROM {files} f, {book_chapters} bc 496 WHERE f.contextid = :contextid 497 AND f.component = :component 498 AND f.filearea = :filearea 499 AND bc.bookid = :bookid 500 AND bc.id = f.itemid'; 501 if (!$returnemptyfolders) { 502 $sql .= ' AND filename <> :emptyfilename'; 503 $params['emptyfilename'] = '.'; 504 } 505 list($sql2, $params2) = $this->build_search_files_sql($extensions, 'f'); 506 $sql .= ' '.$sql2; 507 $params = array_merge($params, $params2); 508 if ($countonly === false) { 509 $sql .= ' ORDER BY bc.pagenum'; 510 } 511 512 $rs = $DB->get_recordset_sql($sql, $params); 513 $children = array(); 514 foreach ($rs as $record) { 515 if ($child = $this->browser->get_file_info($this->context, 'mod_book', $this->filearea, $record->id)) { 516 if ($returnemptyfolders || $child->count_non_empty_children($extensions)) { 517 $children[] = $child; 518 } 519 } 520 if ($countonly !== false && count($children) >= $countonly) { 521 break; 522 } 523 } 524 $rs->close(); 525 if ($countonly !== false) { 526 return count($children); 527 } 528 return $children; 529 } 530 531 /** 532 * Returns list of children which are either files matching the specified extensions 533 * or folders that contain at least one such file. 534 * 535 * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg') 536 * @return array of file_info instances 537 */ 538 public function get_non_empty_children($extensions = '*') { 539 return $this->get_filtered_children($extensions, false); 540 } 541 542 /** 543 * Returns the number of children which are either files matching the specified extensions 544 * or folders containing at least one such file. 545 * 546 * @param string|array $extensions, for example '*' or array('.gif','.jpg') 547 * @param int $limit stop counting after at least $limit non-empty children are found 548 * @return int 549 */ 550 public function count_non_empty_children($extensions = '*', $limit = 1) { 551 return $this->get_filtered_children($extensions, $limit); 552 } 553 554 /** 555 * Returns parent file_info instance 556 * @return file_info or null for root 557 */ 558 public function get_parent() { 559 return $this->browser->get_file_info($this->context); 560 } 561 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |