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