MDL-33121 Book Module: Fixed documentation header
[moodle.git] / mod / book / locallib.php
CommitLineData
e355240d 1<?php
b15ef0b0 2// This file is part of Moodle - http://moodle.org/
e355240d
PS
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 *
3542c4f4
EL
20 * @package mod_book
21 * @copyright 2010-2011 Petr Skoda {@link http://skodak.org}
e355240d
PS
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 */
24
25defined('MOODLE_INTERNAL') || die;
26
29656fe2 27require_once(dirname(__FILE__).'/lib.php');
f6ca19ae
PS
28require_once($CFG->libdir.'/filelib.php');
29
2cd972c1
SH
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 */
45573d5a
PS
37define('BOOK_NUM_NONE', '0');
38define('BOOK_NUM_NUMBERS', '1');
39define('BOOK_NUM_BULLETS', '2');
40define('BOOK_NUM_INDENTED', '3');
41
2c1e98e6 42/**
ad1c11bd
PS
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 *
b962f030 49 * @param stdClass $book
ad1c11bd 50 * @return array of id=>chapter
2c1e98e6 51 */
b1a9b01e 52function book_preload_chapters($book) {
2c1e98e6 53 global $DB;
b1a9b01e 54 $chapters = $DB->get_records('book_chapters', array('bookid'=>$book->id), 'pagenum', 'id, pagenum, subchapter, title, hidden');
ad1c11bd
PS
55 if (!$chapters) {
56 return array();
57 }
58
59 $prev = null;
60 $prevsub = null;
2c1e98e6 61
ad1c11bd
PS
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
29656fe2 68 foreach ($chapters as $id => $ch) {
ad1c11bd
PS
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 $ch->prev = $prev;
79 $ch->next = null;
80 if ($prev) {
81 $chapters[$prev]->next = $ch->id;
82 }
83 if ($ch->hidden) {
b1a9b01e
PS
84 if ($book->numbering == BOOK_NUM_NUMBERS) {
85 $ch->number = 'x';
86 } else {
87 $ch->number = null;
88 }
ad1c11bd
PS
89 } else {
90 $i++;
91 $ch->number = $i;
92 }
93 $j = 0;
94 $prevsub = null;
95 $hidesub = $ch->hidden;
96 $parent = $ch->id;
97 $ch->parent = null;
2cd972c1 98 $ch->subchapters = array();
ad1c11bd
PS
99 } else {
100 $ch->prev = $prevsub;
101 $ch->next = null;
102 if ($prevsub) {
103 $chapters[$prevsub]->next = $ch->id;
e355240d 104 }
ad1c11bd 105 $ch->parent = $parent;
2cd972c1 106 $ch->subchapters = null;
ad1c11bd
PS
107 $chapters[$parent]->subchapters[$ch->id] = $ch->id;
108 if ($hidesub) {
109 // all subchapters in hidden chapter must be hidden too
bc953600 110 $ch->hidden = 1;
e355240d 111 }
ad1c11bd 112 if ($ch->hidden) {
b1a9b01e
PS
113 if ($book->numbering == BOOK_NUM_NUMBERS) {
114 $ch->number = 'x';
115 } else {
116 $ch->number = null;
117 }
ad1c11bd
PS
118 } else {
119 $j++;
120 $ch->number = $j;
23b02c4f 121 }
e355240d 122 }
ad1c11bd
PS
123 if ($oldch->subchapter != $ch->subchapter or $oldch->pagenum != $ch->pagenum or $oldch->hidden != $ch->hidden) {
124 // update only if something changed
125 $DB->update_record('book_chapters', $ch);
126 }
127 $chapters[$id] = $ch;
e355240d 128 }
ad1c11bd
PS
129
130 return $chapters;
e355240d
PS
131}
132
3542c4f4
EL
133/**
134 * Returns the title for a given chapter
135 *
136 * @param int $chid
137 * @param array $chapters
138 * @param stdClass $book
139 * @param context_module $context
140 * @return string
141 */
b1a9b01e
PS
142function book_get_chapter_title($chid, $chapters, $book, $context) {
143 $ch = $chapters[$chid];
144 $title = trim(format_string($ch->title, true, array('context'=>$context)));
145 $numbers = array();
146 if ($book->numbering == BOOK_NUM_NUMBERS) {
147 if ($ch->parent and $chapters[$ch->parent]->number) {
148 $numbers[] = $chapters[$ch->parent]->number;
149 }
150 if ($ch->number) {
151 $numbers[] = $ch->number;
152 }
153 }
154
155 if ($numbers) {
156 $title = implode('.', $numbers).' '.$title;
157 }
158
159 return $title;
160}
161
f6ca19ae
PS
162/**
163 * General logging to table
164 * @param string $str1
165 * @param string $str2
166 * @param int $level
167 * @return void
168 */
e355240d
PS
169function book_log($str1, $str2, $level = 0) {
170 switch ($level) {
171 case 1:
172 echo '<tr><td><span class="dimmed_text">'.$str1.'</span></td><td><span class="dimmed_text">'.$str2.'</span></td></tr>';
173 break;
174 case 2:
175 echo '<tr><td><span style="color: rgb(255, 0, 0);">'.$str1.'</span></td><td><span style="color: rgb(255, 0, 0);">'.$str2.'</span></td></tr>';
176 break;
177 default:
178 echo '<tr><td>'.$str1.'</class></td><td>'.$str2.'</td></tr>';
179 break;
180 }
181}
182
3542c4f4
EL
183/**
184 * Add the book TOC sticky block to the 1st region available
185 *
186 * @param array $chapters
187 * @param stdClass $chapter
188 * @param stdClass $book
189 * @param stdClass $cm
190 * @param bool $edit
191 */
ad1c11bd
PS
192function book_add_fake_block($chapters, $chapter, $book, $cm, $edit) {
193 global $OUTPUT, $PAGE;
194
8cb50b2a 195 $toc = book_get_toc($chapters, $chapter, $book, $cm, $edit, 0);
ad1c11bd 196
ad1c11bd
PS
197 $bc = new block_contents();
198 $bc->title = get_string('toc', 'mod_book');
199 $bc->attributes['class'] = 'block';
200 $bc->content = $toc;
201
202 $regions = $PAGE->blocks->get_regions();
203 $firstregion = reset($regions);
204 $PAGE->blocks->add_fake_block($bc, $firstregion);
205}
206
ee952cbb
PS
207/**
208 * Generate toc structure
209 *
210 * @param array $chapters
211 * @param stdClass $chapter
212 * @param stdClass $book
213 * @param stdClass $cm
214 * @param bool $edit
ee952cbb
PS
215 * @return string
216 */
217function book_get_toc($chapters, $chapter, $book, $cm, $edit) {
218 global $USER, $OUTPUT;
219
3542c4f4
EL
220 $toc = ''; // Representation of toc (HTML)
221 $nch = 0; // Chapter number
222 $ns = 0; // Subchapter number
ee952cbb
PS
223 $first = 1;
224
1fc9e895 225 $context = context_module::instance($cm->id);
ee952cbb
PS
226
227 switch ($book->numbering) {
29656fe2
EL
228 case BOOK_NUM_NONE:
229 $toc .= '<div class="book_toc_none">';
230 break;
231 case BOOK_NUM_NUMBERS:
232 $toc .= '<div class="book_toc_numbered">';
233 break;
234 case BOOK_NUM_BULLETS:
235 $toc .= '<div class="book_toc_bullets">';
236 break;
237 case BOOK_NUM_INDENTED:
238 $toc .= '<div class="book_toc_indented">';
239 break;
ee952cbb
PS
240 }
241
3542c4f4 242 if ($edit) { // Teacher's TOC
f6ca19ae
PS
243 $toc .= '<ul>';
244 $i = 0;
29656fe2 245 foreach ($chapters as $ch) {
f6ca19ae 246 $i++;
dc888a31 247 $title = trim(format_string($ch->title, true, array('context'=>$context)));
f6ca19ae
PS
248 if (!$ch->subchapter) {
249 $toc .= ($first) ? '<li>' : '</ul></li><li>';
250 if (!$ch->hidden) {
251 $nch++;
252 $ns = 0;
253 if ($book->numbering == BOOK_NUM_NUMBERS) {
254 $title = "$nch $title";
255 }
256 } else {
257 if ($book->numbering == BOOK_NUM_NUMBERS) {
258 $title = "x $title";
259 }
260 $title = '<span class="dimmed_text">'.$title.'</span>';
261 }
f6ca19ae
PS
262 } else {
263 $toc .= ($first) ? '<li><ul><li>' : '<li>';
264 if (!$ch->hidden) {
265 $ns++;
266 if ($book->numbering == BOOK_NUM_NUMBERS) {
267 $title = "$nch.$ns $title";
268 }
269 } else {
270 if ($book->numbering == BOOK_NUM_NUMBERS) {
271 $title = "x.x $title";
272 }
273 $title = '<span class="dimmed_text">'.$title.'</span>';
274 }
275 }
276
277 if ($ch->id == $chapter->id) {
278 $toc .= '<strong>'.$title.'</strong>';
f6ca19ae
PS
279 } else {
280 $toc .= '<a title="'.s($title).'" href="view.php?id='.$cm->id.'&amp;chapterid='.$ch->id.'">'.$title.'</a>';
281 }
282 $toc .= '&nbsp;&nbsp;';
283 if ($i != 1) {
29656fe2
EL
284 $toc .= ' <a title="'.get_string('up').'" href="move.php?id='.$cm->id.'&amp;chapterid='.$ch->id.
285 '&amp;up=1&amp;sesskey='.$USER->sesskey.'"><img src="'.$OUTPUT->pix_url('t/up').'" class="iconsmall" alt="'.get_string('up').'" /></a>';
f6ca19ae
PS
286 }
287 if ($i != count($chapters)) {
29656fe2
EL
288 $toc .= ' <a title="'.get_string('down').'" href="move.php?id='.$cm->id.'&amp;chapterid='.$ch->id.
289 '&amp;up=0&amp;sesskey='.$USER->sesskey.'"><img src="'.$OUTPUT->pix_url('t/down').'" class="iconsmall" alt="'.get_string('down').'" /></a>';
f6ca19ae 290 }
29656fe2
EL
291 $toc .= ' <a title="'.get_string('edit').'" href="edit.php?cmid='.$cm->id.'&amp;id='.$ch->id.'"><img src="'.
292 $OUTPUT->pix_url('t/edit').'" class="iconsmall" alt="'.get_string('edit').'" /></a>';
293 $toc .= ' <a title="'.get_string('delete').'" href="delete.php?id='.$cm->id.'&amp;chapterid='.$ch->id.
294 '&amp;sesskey='.$USER->sesskey.'"><img src="'.$OUTPUT->pix_url('t/delete').'" class="iconsmall" alt="'.get_string('delete').'" /></a>';
f6ca19ae 295 if ($ch->hidden) {
29656fe2
EL
296 $toc .= ' <a title="'.get_string('show').'" href="show.php?id='.$cm->id.'&amp;chapterid='.$ch->id.
297 '&amp;sesskey='.$USER->sesskey.'"><img src="'.$OUTPUT->pix_url('t/show').'" class="iconsmall" alt="'.get_string('show').'" /></a>';
f6ca19ae 298 } else {
29656fe2
EL
299 $toc .= ' <a title="'.get_string('hide').'" href="show.php?id='.$cm->id.'&amp;chapterid='.$ch->id.
300 '&amp;sesskey='.$USER->sesskey.'"><img src="'.$OUTPUT->pix_url('t/hide').'" class="iconsmall" alt="'.get_string('hide').'" /></a>';
f6ca19ae 301 }
29656fe2
EL
302 $toc .= ' <a title="'.get_string('addafter', 'mod_book').'" href="edit.php?cmid='.$cm->id.
303 '&amp;pagenum='.$ch->pagenum.'&amp;subchapter='.$ch->subchapter.'"><img src="'.
304 $OUTPUT->pix_url('add', 'mod_book').'" class="iconsmall" alt="'.get_string('addafter', 'mod_book').'" /></a>';
f6ca19ae
PS
305
306 $toc .= (!$ch->subchapter) ? '<ul>' : '</li>';
307 $first = 0;
308 }
309 $toc .= '</ul></li></ul>';
3542c4f4 310 } else { // Normal students view
f6ca19ae 311 $toc .= '<ul>';
29656fe2 312 foreach ($chapters as $ch) {
dc888a31 313 $title = trim(format_string($ch->title, true, array('context'=>$context)));
f6ca19ae
PS
314 if (!$ch->hidden) {
315 if (!$ch->subchapter) {
316 $nch++;
317 $ns = 0;
318 $toc .= ($first) ? '<li>' : '</ul></li><li>';
319 if ($book->numbering == BOOK_NUM_NUMBERS) {
320 $title = "$nch $title";
321 }
f6ca19ae
PS
322 } else {
323 $ns++;
324 $toc .= ($first) ? '<li><ul><li>' : '<li>';
325 if ($book->numbering == BOOK_NUM_NUMBERS) {
326 $title = "$nch.$ns $title";
327 }
328 }
329 if ($ch->id == $chapter->id) {
330 $toc .= '<strong>'.$title.'</strong>';
f6ca19ae
PS
331 } else {
332 $toc .= '<a title="'.s($title).'" href="view.php?id='.$cm->id.'&amp;chapterid='.$ch->id.'">'.$title.'</a>';
333 }
334 $toc .= (!$ch->subchapter) ? '<ul>' : '</li>';
335 $first = 0;
336 }
337 }
338 $toc .= '</ul></li></ul>';
339 }
340
341 $toc .= '</div>';
342
3542c4f4 343 $toc = str_replace('<ul></ul>', '', $toc); // Cleanup of invalid structures.
f6ca19ae 344
ee952cbb 345 return $toc;
f6ca19ae 346}
dd9b772b
PS
347
348
349/**
350 * File browsing support class
3542c4f4
EL
351 *
352 * @copyright 2010-2011 Petr Skoda {@link http://skodak.org}
353 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
dd9b772b
PS
354 */
355class book_file_info extends file_info {
3542c4f4 356 /** @var stdClass Course object */
dd9b772b 357 protected $course;
3542c4f4 358 /** @var stdClass Course module object */
dd9b772b 359 protected $cm;
3542c4f4 360 /** @var array Available file areas */
dd9b772b 361 protected $areas;
3542c4f4 362 /** @var string File area to browse */
dd9b772b
PS
363 protected $filearea;
364
3542c4f4
EL
365 /**
366 * Constructor
367 *
368 * @param file_browser $browser file_browser instance
369 * @param stdClass $course course object
370 * @param stdClass $cm course module object
371 * @param stdClass $context module context
372 * @param array $areas available file areas
373 * @param string $filearea file area to browse
374 */
dd9b772b
PS
375 public function __construct($browser, $course, $cm, $context, $areas, $filearea) {
376 parent::__construct($browser, $context);
377 $this->course = $course;
378 $this->cm = $cm;
379 $this->areas = $areas;
380 $this->filearea = $filearea;
381 }
382
383 /**
384 * Returns list of standard virtual file/directory identification.
385 * The difference from stored_file parameters is that null values
386 * are allowed in all fields
387 * @return array with keys contextid, filearea, itemid, filepath and filename
388 */
389 public function get_params() {
390 return array('contextid'=>$this->context->id,
391 'component'=>'mod_book',
392 'filearea' =>$this->filearea,
393 'itemid' =>null,
394 'filepath' =>null,
395 'filename' =>null);
396 }
397
398 /**
399 * Returns localised visible name.
400 * @return string
401 */
402 public function get_visible_name() {
403 return $this->areas[$this->filearea];
404 }
405
406 /**
407 * Can I add new files or directories?
408 * @return bool
409 */
410 public function is_writable() {
411 return false;
412 }
413
414 /**
415 * Is directory?
416 * @return bool
417 */
418 public function is_directory() {
419 return true;
420 }
421
422 /**
423 * Returns list of children.
424 * @return array of file_info instances
425 */
426 public function get_children() {
427 global $DB;
428
429 $children = array();
430 $chapters = $DB->get_records('book_chapters', array('bookid'=>$this->cm->instance), 'pagenum', 'id, pagenum');
29656fe2 431 foreach ($chapters as $itemid => $unused) {
dd9b772b
PS
432 if ($child = $this->browser->get_file_info($this->context, 'mod_book', $this->filearea, $itemid)) {
433 $children[] = $child;
434 }
435 }
436 return $children;
437 }
438
439 /**
440 * Returns parent file_info instance
441 * @return file_info or null for root
442 */
443 public function get_parent() {
444 return $this->browser->get_file_info($this->context);
445 }
446}