Commit | Line | Data |
---|---|---|
ec972ade | 1 | <?php |
4ca6cfbf PS |
2 | // This file is part of Moodle - http://moodle.org/ |
3 | // | |
ec972ade | 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. | |
4ca6cfbf | 13 | // |
ec972ade | 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/>. | |
0f3fe4b6 | 16 | |
c7e3bc51 | 17 | /** |
ccd3dd0c | 18 | * This file contains the parent class for moodle blocks, block_base. |
c7e3bc51 | 19 | * |
f25a6839 | 20 | * @package core_block |
78bfb562 | 21 | * @license http://www.gnu.org/copyleft/gpl.html GNU Public License |
c7e3bc51 | 22 | */ |
23 | ||
24 | /// Constants | |
25 | ||
26 | /** | |
27 | * Block type of list. Contents of block should be set as an associative array in the content object as items ($this->content->items). Optionally include footer text in $this->content->footer. | |
28 | */ | |
0f3fe4b6 | 29 | define('BLOCK_TYPE_LIST', 1); |
c7e3bc51 | 30 | |
31 | /** | |
32 | * Block type of text. Contents of block should be set to standard html text in the content object as items ($this->content->text). Optionally include footer text in $this->content->footer. | |
33 | */ | |
0f3fe4b6 | 34 | define('BLOCK_TYPE_TEXT', 2); |
7d2a0492 | 35 | /** |
36 | * Block type of tree. $this->content->items is a list of tree_item objects and $this->content->footer is a string. | |
37 | */ | |
38 | define('BLOCK_TYPE_TREE', 3); | |
c7e3bc51 | 39 | |
c7e3bc51 | 40 | /** |
e0134f84 | 41 | * Class for describing a moodle block, all Moodle blocks derive from this class |
c7e3bc51 | 42 | * |
43 | * @author Jon Papaioannou | |
f25a6839 | 44 | * @package core_block |
c7e3bc51 | 45 | */ |
e89d741a | 46 | class block_base { |
c7e3bc51 | 47 | |
48 | /** | |
49 | * Internal var for storing/caching translated strings | |
50 | * @var string $str | |
51 | */ | |
0f3fe4b6 | 52 | var $str; |
c7e3bc51 | 53 | |
54 | /** | |
f8582e3e | 55 | * The title of the block to be displayed in the block title area. |
c7e3bc51 | 56 | * @var string $title |
57 | */ | |
9b4b78fd | 58 | var $title = NULL; |
c7e3bc51 | 59 | |
47332703 JF |
60 | /** |
61 | * The name of the block to be displayed in the block title area if the title is empty. | |
62 | * @var string arialabel | |
63 | */ | |
64 | var $arialabel = NULL; | |
65 | ||
c7e3bc51 | 66 | /** |
ccd3dd0c | 67 | * The type of content that this block creates. Currently support options - BLOCK_TYPE_LIST, BLOCK_TYPE_TEXT |
c7e3bc51 | 68 | * @var int $content_type |
69 | */ | |
3ef642d9 | 70 | var $content_type = BLOCK_TYPE_TEXT; |
c7e3bc51 | 71 | |
72 | /** | |
73 | * An object to contain the information to be displayed in the block. | |
74 | * @var stdObject $content | |
75 | */ | |
9b4b78fd | 76 | var $content = NULL; |
c7e3bc51 | 77 | |
c7e3bc51 | 78 | /** |
79 | * The initialized instance of this block object. | |
80 | * @var block $instance | |
81 | */ | |
9b4b78fd | 82 | var $instance = NULL; |
c7e3bc51 | 83 | |
3179b000 | 84 | /** |
85 | * The page that this block is appearing on. | |
86 | * @var moodle_page | |
87 | */ | |
88 | public $page = NULL; | |
89 | ||
e92c286c | 90 | /** |
91 | * This blocks's context. | |
92 | * @var stdClass | |
93 | */ | |
94 | public $context = NULL; | |
95 | ||
c7e3bc51 | 96 | /** |
97 | * An object containing the instance configuration information for the current instance of this block. | |
98 | * @var stdObject $config | |
99 | */ | |
9b4b78fd | 100 | var $config = NULL; |
101 | ||
4ca6cfbf | 102 | /** |
f9648e77 | 103 | * How often the cronjob should run, 0 if not at all. |
104 | * @var int $cron | |
105 | */ | |
106 | ||
107 | var $cron = NULL; | |
108 | ||
e0134f84 | 109 | /// Class Functions |
c7e3bc51 | 110 | |
73554752 | 111 | /** |
112 | * Fake constructor to keep PHP5 happy | |
113 | * | |
114 | */ | |
115 | function __construct() { | |
8571833f | 116 | $this->init(); |
73554752 | 117 | } |
4ca6cfbf | 118 | |
44c55d46 | 119 | /** |
120 | * Function that can be overridden to do extra cleanup before | |
121 | * the database tables are deleted. (Called once per block, not per instance!) | |
122 | */ | |
123 | function before_delete() { | |
124 | } | |
4ca6cfbf | 125 | |
c7e3bc51 | 126 | /** |
127 | * Returns the block name, as present in the class name, | |
128 | * the database, the block directory, etc etc. | |
129 | * | |
130 | * @return string | |
131 | */ | |
0f3fe4b6 | 132 | function name() { |
133 | // Returns the block name, as present in the class name, | |
134 | // the database, the block directory, etc etc. | |
135 | static $myname; | |
c7e3bc51 | 136 | if ($myname === NULL) { |
0f3fe4b6 | 137 | $myname = strtolower(get_class($this)); |
138 | $myname = substr($myname, strpos($myname, '_') + 1); | |
139 | } | |
140 | return $myname; | |
141 | } | |
142 | ||
c7e3bc51 | 143 | /** |
144 | * Parent class version of this function simply returns NULL | |
145 | * This should be implemented by the derived class to return | |
146 | * the content object. | |
147 | * | |
148 | * @return stdObject | |
149 | */ | |
0f3fe4b6 | 150 | function get_content() { |
151 | // This should be implemented by the derived class. | |
152 | return NULL; | |
153 | } | |
c7e3bc51 | 154 | |
155 | /** | |
156 | * Returns the class $title var value. | |
157 | * | |
4ca6cfbf | 158 | * Intentionally doesn't check if a title is set. |
c7e3bc51 | 159 | * This is already done in {@link _self_test()} |
160 | * | |
161 | * @return string $this->title | |
162 | */ | |
0f3fe4b6 | 163 | function get_title() { |
6195e04a | 164 | // Intentionally doesn't check if a title is set. This is already done in _self_test() |
0f3fe4b6 | 165 | return $this->title; |
166 | } | |
c7e3bc51 | 167 | |
168 | /** | |
169 | * Returns the class $content_type var value. | |
170 | * | |
4ca6cfbf | 171 | * Intentionally doesn't check if content_type is set. |
c7e3bc51 | 172 | * This is already done in {@link _self_test()} |
173 | * | |
174 | * @return string $this->content_type | |
175 | */ | |
0f3fe4b6 | 176 | function get_content_type() { |
6195e04a | 177 | // Intentionally doesn't check if a content_type is set. This is already done in _self_test() |
0f3fe4b6 | 178 | return $this->content_type; |
179 | } | |
c7e3bc51 | 180 | |
3ef642d9 | 181 | /** |
182 | * Returns true or false, depending on whether this block has any content to display | |
7e874772 | 183 | * and whether the user has permission to view the block |
3ef642d9 | 184 | * |
185 | * @return boolean | |
186 | */ | |
187 | function is_empty() { | |
e92c286c | 188 | if ( !has_capability('moodle/block:view', $this->context) ) { |
7e874772 | 189 | return true; |
190 | } | |
191 | ||
3ef642d9 | 192 | $this->get_content(); |
193 | return(empty($this->content->text) && empty($this->content->footer)); | |
194 | } | |
195 | ||
c7e3bc51 | 196 | /** |
197 | * First sets the current value of $this->content to NULL | |
198 | * then calls the block's {@link get_content()} function | |
199 | * to set its value back. | |
200 | * | |
201 | * @return stdObject | |
202 | */ | |
0f3fe4b6 | 203 | function refresh_content() { |
204 | // Nothing special here, depends on content() | |
205 | $this->content = NULL; | |
206 | return $this->get_content(); | |
207 | } | |
c7e3bc51 | 208 | |
209 | /** | |
9c14c1c5 | 210 | * Return a block_contents object representing the full contents of this block. |
d4a03c00 | 211 | * |
212 | * This internally calls ->get_content(), and then adds the editing controls etc. | |
213 | * | |
214 | * You probably should not override this method, but instead override | |
215 | * {@link html_attributes()}, {@link formatted_contents()} or {@link get_content()}, | |
216 | * {@link hide_header()}, {@link (get_edit_controls)}, etc. | |
217 | * | |
9c14c1c5 | 218 | * @return block_contents a representation of the block, for rendering. |
d4a03c00 | 219 | * @since Moodle 2.0. |
c7e3bc51 | 220 | */ |
d4a03c00 | 221 | public function get_content_for_output($output) { |
222 | global $CFG; | |
0a0bb380 | 223 | |
dd72b308 | 224 | $bc = new block_contents($this->html_attributes()); |
a69a7e89 | 225 | $bc->attributes['data-block'] = $this->name(); |
d4a03c00 | 226 | $bc->blockinstanceid = $this->instance->id; |
227 | $bc->blockpositionid = $this->instance->blockpositionid; | |
c7e3bc51 | 228 | |
e54f4a78 | 229 | if ($this->instance->visible) { |
230 | $bc->content = $this->formatted_contents($output); | |
231 | if (!empty($this->content->footer)) { | |
232 | $bc->footer = $this->content->footer; | |
233 | } | |
234 | } else { | |
235 | $bc->add_class('invisible'); | |
236 | } | |
237 | ||
d4a03c00 | 238 | if (!$this->hide_header()) { |
239 | $bc->title = $this->title; | |
240 | } | |
47332703 | 241 | |
91d941c3 SH |
242 | if (empty($bc->title)) { |
243 | $bc->arialabel = new lang_string('pluginname', get_class($this)); | |
47332703 | 244 | $this->arialabel = $bc->arialabel; |
91d941c3 | 245 | } |
ae42ff6f | 246 | |
d4a03c00 | 247 | if ($this->page->user_is_editing()) { |
00a24d44 | 248 | $bc->controls = $this->page->blocks->edit_controls($this); |
9c14c1c5 PS |
249 | } else { |
250 | // we must not use is_empty on hidden blocks | |
251 | if ($this->is_empty() && !$bc->controls) { | |
252 | return null; | |
253 | } | |
f674ec86 | 254 | } |
255 | ||
0885166f JC |
256 | if (empty($CFG->allowuserblockhiding) |
257 | || (empty($bc->content) && empty($bc->footer)) | |
258 | || !$this->instance_can_be_collapsed()) { | |
d4a03c00 | 259 | $bc->collapsible = block_contents::NOT_HIDEABLE; |
260 | } else if (get_user_preferences('block' . $bc->blockinstanceid . 'hidden', false)) { | |
261 | $bc->collapsible = block_contents::HIDDEN; | |
262 | } else { | |
263 | $bc->collapsible = block_contents::VISIBLE; | |
0f3fe4b6 | 264 | } |
c4d951e1 | 265 | |
84192d78 SH |
266 | if ($this->instance_can_be_docked() && !$this->hide_header()) { |
267 | $bc->dockable = true; | |
268 | } | |
269 | ||
40928036 | 270 | $bc->annotation = ''; // TODO MDL-19398 need to work out what to say here. |
d4a03c00 | 271 | |
272 | return $bc; | |
0f3fe4b6 | 273 | } |
89adb174 | 274 | |
96d9a6e4 JL |
275 | |
276 | /** | |
277 | * Return an object containing all the block content to be returned by external functions. | |
278 | * | |
279 | * If your block is returning formatted content or provide files for download, you should override this method to use the | |
280 | * external_format_text, external_format_string functions for formatting or external_util::get_area_files for files. | |
281 | * | |
282 | * @param core_renderer $output the rendered used for output | |
283 | * @return stdClass object containing the block title, central content, footer and linked files (if any). | |
284 | * @since Moodle 3.6 | |
285 | */ | |
286 | public function get_content_for_external($output) { | |
287 | $bc = new stdClass; | |
288 | $bc->title = null; | |
289 | $bc->content = null; | |
290 | $bc->contentformat = FORMAT_HTML; | |
291 | $bc->footer = null; | |
292 | $bc->files = []; | |
293 | ||
294 | if ($this->instance->visible) { | |
295 | $bc->content = $this->formatted_contents($output); | |
296 | if (!empty($this->content->footer)) { | |
297 | $bc->footer = $this->content->footer; | |
298 | } | |
299 | } | |
300 | ||
301 | if (!$this->hide_header()) { | |
302 | $bc->title = $this->title; | |
303 | } | |
304 | ||
305 | return $bc; | |
306 | } | |
307 | ||
c7e3bc51 | 308 | /** |
d4a03c00 | 309 | * Convert the contents of the block to HTML. |
c7e3bc51 | 310 | * |
d4a03c00 | 311 | * This is used by block base classes like block_list to convert the structured |
312 | * $this->content->list and $this->content->icons arrays to HTML. So, in most | |
313 | * blocks, you probaby want to override the {@link get_contents()} method, | |
314 | * which generates that structured representation of the contents. | |
315 | * | |
316 | * @param $output The core_renderer to use when generating the output. | |
317 | * @return string the HTML that should appearn in the body of the block. | |
318 | * @since Moodle 2.0. | |
c7e3bc51 | 319 | */ |
d4a03c00 | 320 | protected function formatted_contents($output) { |
321 | $this->get_content(); | |
dde36f9d | 322 | $this->get_required_javascript(); |
d4a03c00 | 323 | if (!empty($this->content->text)) { |
324 | return $this->content->text; | |
325 | } else { | |
326 | return ''; | |
327 | } | |
328 | } | |
329 | ||
c7e3bc51 | 330 | /** |
331 | * Tests if this block has been implemented correctly. | |
332 | * Also, $errors isn't used right now | |
333 | * | |
334 | * @return boolean | |
335 | */ | |
4ca6cfbf | 336 | |
0f3fe4b6 | 337 | function _self_test() { |
338 | // Tests if this block has been implemented correctly. | |
339 | // Also, $errors isn't used right now | |
340 | $errors = array(); | |
341 | ||
342 | $correct = true; | |
c7e3bc51 | 343 | if ($this->get_title() === NULL) { |
0f3fe4b6 | 344 | $errors[] = 'title_not_set'; |
345 | $correct = false; | |
346 | } | |
7d2a0492 | 347 | if (!in_array($this->get_content_type(), array(BLOCK_TYPE_LIST, BLOCK_TYPE_TEXT, BLOCK_TYPE_TREE))) { |
0f3fe4b6 | 348 | $errors[] = 'invalid_content_type'; |
349 | $correct = false; | |
350 | } | |
4ca6cfbf | 351 | //following selftest was not working when roles&capabilities were used from block |
35a518c5 | 352 | /* if ($this->get_content() === NULL) { |
0f3fe4b6 | 353 | $errors[] = 'content_not_set'; |
354 | $correct = false; | |
35a518c5 | 355 | }*/ |
2b0d60ec | 356 | $formats = $this->applicable_formats(); |
c7e3bc51 | 357 | if (empty($formats) || array_sum($formats) === 0) { |
8a47e075 | 358 | $errors[] = 'no_formats'; |
0f3fe4b6 | 359 | $correct = false; |
360 | } | |
2b0d60ec | 361 | |
0f3fe4b6 | 362 | return $correct; |
363 | } | |
364 | ||
c7e3bc51 | 365 | /** |
366 | * Subclasses should override this and return true if the | |
4dd79132 | 367 | * subclass block has a settings.php file. |
c7e3bc51 | 368 | * |
369 | * @return boolean | |
370 | */ | |
0f3fe4b6 | 371 | function has_config() { |
372 | return false; | |
373 | } | |
c7e3bc51 | 374 | |
c7e3bc51 | 375 | /** |
376 | * Default behavior: save all variables as $CFG properties | |
377 | * You don't need to override this if you 're satisfied with the above | |
378 | * | |
53c74b18 | 379 | * @deprecated since Moodle 2.9 MDL-49385 - Please use Admin Settings functionality to save block configuration. |
c7e3bc51 | 380 | */ |
f8582e3e | 381 | function config_save($data) { |
94cec934 | 382 | throw new coding_exception('config_save() can not be used any more, use Admin Settings functionality to save block configuration.'); |
0f3fe4b6 | 383 | } |
4ca6cfbf | 384 | |
c7e3bc51 | 385 | /** |
40928036 | 386 | * Which page types this block may appear on. |
387 | * | |
388 | * The information returned here is processed by the | |
389 | * {@link blocks_name_allowed_in_format()} function. Look there if you need | |
390 | * to know exactly how this works. | |
391 | * | |
392 | * Default case: everything except mod and tag. | |
393 | * | |
394 | * @return array page-type prefix => true/false. | |
c7e3bc51 | 395 | */ |
0f3fe4b6 | 396 | function applicable_formats() { |
d232b8c7 | 397 | // Default case: the block can be used in courses and site index, but not in activities |
9591bc3c | 398 | return array('all' => true, 'mod' => false, 'tag' => false); |
0f3fe4b6 | 399 | } |
4ca6cfbf | 400 | |
c7e3bc51 | 401 | |
c7e3bc51 | 402 | /** |
403 | * Default return is false - header will be shown | |
404 | * @return boolean | |
405 | */ | |
0f3fe4b6 | 406 | function hide_header() { |
0f3fe4b6 | 407 | return false; |
408 | } | |
c7e3bc51 | 409 | |
410 | /** | |
d4a03c00 | 411 | * Return any HTML attributes that you want added to the outer <div> that |
412 | * of the block when it is output. | |
7d2a0492 | 413 | * |
414 | * Because of the way certain JS events are wired it is a good idea to ensure | |
415 | * that the default values here still get set. | |
416 | * I found the easiest way to do this and still set anything you want is to | |
417 | * override it within your block in the following way | |
418 | * | |
419 | * <code php> | |
420 | * function html_attributes() { | |
421 | * $attributes = parent::html_attributes(); | |
422 | * $attributes['class'] .= ' mynewclass'; | |
423 | * return $attributes; | |
424 | * } | |
425 | * </code> | |
426 | * | |
d4a03c00 | 427 | * @return array attribute name => value. |
c7e3bc51 | 428 | */ |
c5507e52 | 429 | function html_attributes() { |
9d897331 | 430 | $attributes = array( |
4ca6cfbf | 431 | 'id' => 'inst' . $this->instance->id, |
697f7bd7 SH |
432 | 'class' => 'block_' . $this->name(). ' block', |
433 | 'role' => $this->get_aria_role() | |
2f747639 | 434 | ); |
dc3337b2 AG |
435 | if ($this->hide_header()) { |
436 | $attributes['class'] .= ' no-header'; | |
437 | } | |
d2c394f3 | 438 | if ($this->instance_can_be_docked() && get_user_preferences('docked_block_instance_'.$this->instance->id, 0)) { |
9d897331 SH |
439 | $attributes['class'] .= ' dock_on_load'; |
440 | } | |
441 | return $attributes; | |
c5507e52 | 442 | } |
d4a03c00 | 443 | |
c7e3bc51 | 444 | /** |
40928036 | 445 | * Set up a particular instance of this class given data from the block_insances |
4ca6cfbf | 446 | * table and the current page. (See {@link block_manager::load_blocks()}.) |
40928036 | 447 | * |
448 | * @param stdClass $instance data from block_insances, block_positions, etc. | |
449 | * @param moodle_page $the page this block is on. | |
c7e3bc51 | 450 | */ |
3179b000 | 451 | function _load_instance($instance, $page) { |
c7e3bc51 | 452 | if (!empty($instance->configdata)) { |
9b4b78fd | 453 | $this->config = unserialize(base64_decode($instance->configdata)); |
454 | } | |
9b4b78fd | 455 | $this->instance = $instance; |
fe2fdd11 | 456 | $this->context = context_block::instance($instance->id); |
3179b000 | 457 | $this->page = $page; |
9b4b78fd | 458 | $this->specialization(); |
9d897331 SH |
459 | } |
460 | ||
84192d78 SH |
461 | /** |
462 | * Allows the block to load any JS it requires into the page. | |
463 | * | |
464 | * By default this function simply permits the user to dock the block if it is dockable. | |
9757c656 MM |
465 | * |
466 | * Left null as of MDL-64506. | |
84192d78 | 467 | */ |
9d897331 | 468 | function get_required_javascript() { |
9b4b78fd | 469 | } |
59b29207 | 470 | |
43038ce6 | 471 | /** |
472 | * This function is called on your subclass right after an instance is loaded | |
473 | * Use this function to act on instance data just after it's loaded and before anything else is done | |
67677908 | 474 | * For instance: if your block will have different title's depending on location (site, course, blog, etc) |
43038ce6 | 475 | */ |
9b4b78fd | 476 | function specialization() { |
477 | // Just to make sure that this method exists. | |
9b4b78fd | 478 | } |
479 | ||
c7e3bc51 | 480 | /** |
f032aa7a | 481 | * Is each block of this type going to have instance-specific configuration? |
40928036 | 482 | * Normally, this setting is controlled by {@link instance_allow_multiple()}: if multiple |
f032aa7a | 483 | * instances are allowed, then each will surely need its own configuration. However, in some |
484 | * cases it may be necessary to provide instance configuration to blocks that do not want to | |
485 | * allow multiple instances. In that case, make this function return true. | |
40928036 | 486 | * I stress again that this makes a difference ONLY if {@link instance_allow_multiple()} returns false. |
f032aa7a | 487 | * @return boolean |
f032aa7a | 488 | */ |
489 | function instance_allow_config() { | |
490 | return false; | |
491 | } | |
492 | ||
493 | /** | |
494 | * Are you going to allow multiple instances of each block? | |
c7e3bc51 | 495 | * If yes, then it is assumed that the block WILL USE per-instance configuration |
496 | * @return boolean | |
c7e3bc51 | 497 | */ |
9b4b78fd | 498 | function instance_allow_multiple() { |
499 | // Are you going to allow multiple instances of each block? | |
500 | // If yes, then it is assumed that the block WILL USE per-instance configuration | |
501 | return false; | |
502 | } | |
59b29207 | 503 | |
c7e3bc51 | 504 | /** |
505 | * Serialize and store config data | |
c7e3bc51 | 506 | */ |
f474a4e5 | 507 | function instance_config_save($data, $nolongerused = false) { |
a5d424df | 508 | global $DB; |
557554f9 | 509 | $DB->update_record('block_instances', ['id' => $this->instance->id, |
510 | 'configdata' => base64_encode(serialize($data)), 'timemodified' => time()]); | |
9b4b78fd | 511 | } |
512 | ||
0144a0a7 | 513 | /** |
514 | * Replace the instance's configuration data with those currently in $this->config; | |
0144a0a7 | 515 | */ |
f474a4e5 | 516 | function instance_config_commit($nolongerused = false) { |
a5d424df | 517 | global $DB; |
f474a4e5 | 518 | $this->instance_config_save($this->config); |
0144a0a7 | 519 | } |
520 | ||
d4a03c00 | 521 | /** |
b33dd23a | 522 | * Do any additional initialization you may need at the time a new block instance is created |
523 | * @return boolean | |
b33dd23a | 524 | */ |
525 | function instance_create() { | |
526 | return true; | |
527 | } | |
528 | ||
ad5c3230 NL |
529 | /** |
530 | * Copy any block-specific data when copying to a new block instance. | |
531 | * @param int $fromid the id number of the block instance to copy from | |
532 | * @return boolean | |
533 | */ | |
534 | public function instance_copy($fromid) { | |
535 | return true; | |
536 | } | |
537 | ||
d4a03c00 | 538 | /** |
b33dd23a | 539 | * Delete everything related to this instance if you have been using persistent storage other than the configdata field. |
540 | * @return boolean | |
b33dd23a | 541 | */ |
542 | function instance_delete() { | |
543 | return true; | |
544 | } | |
545 | ||
d4a03c00 | 546 | /** |
11306331 | 547 | * Allows the block class to have a say in the user's ability to edit (i.e., configure) blocks of this type. |
548 | * The framework has first say in whether this will be allowed (e.g., no editing allowed unless in edit mode) | |
549 | * but if the framework does allow it, the block can still decide to refuse. | |
550 | * @return boolean | |
11306331 | 551 | */ |
552 | function user_can_edit() { | |
03d9401e MD |
553 | global $USER; |
554 | ||
555 | if (has_capability('moodle/block:edit', $this->context)) { | |
556 | return true; | |
557 | } | |
558 | ||
559 | // The blocks in My Moodle are a special case. We want them to inherit from the user context. | |
560 | if (!empty($USER->id) | |
561 | && $this->instance->parentcontextid == $this->page->context->id // Block belongs to this page | |
562 | && $this->page->context->contextlevel == CONTEXT_USER // Page belongs to a user | |
563 | && $this->page->context->instanceid == $USER->id) { // Page belongs to this user | |
564 | return has_capability('moodle/my:manageblocks', $this->page->context); | |
565 | } | |
566 | ||
567 | return false; | |
11306331 | 568 | } |
569 | ||
d4a03c00 | 570 | /** |
11306331 | 571 | * Allows the block class to have a say in the user's ability to create new instances of this block. |
572 | * The framework has first say in whether this will be allowed (e.g., no adding allowed unless in edit mode) | |
573 | * but if the framework does allow it, the block can still decide to refuse. | |
574 | * This function has access to the complete page object, the creation related to which is being determined. | |
10a92c39 SH |
575 | * |
576 | * @param moodle_page $page | |
11306331 | 577 | * @return boolean |
11306331 | 578 | */ |
15a00b4b | 579 | function user_can_addto($page) { |
03d9401e MD |
580 | global $USER; |
581 | ||
ef78cf8f DM |
582 | // List of formats this block supports. |
583 | $formats = $this->applicable_formats(); | |
584 | ||
03d9401e MD |
585 | // The blocks in My Moodle are a special case and use a different capability. |
586 | if (!empty($USER->id) | |
b291b59d | 587 | && $page->context->contextlevel == CONTEXT_USER // Page belongs to a user |
9b06b507 MN |
588 | && $page->context->instanceid == $USER->id // Page belongs to this user |
589 | && $page->pagetype == 'my-index') { // Ensure we are on the My Moodle page | |
b6d7cff6 AD |
590 | |
591 | // If the block cannot be displayed on /my it is ok if the myaddinstance capability is not defined. | |
b6d7cff6 AD |
592 | // Is 'my' explicitly forbidden? |
593 | // If 'all' has not been allowed, has 'my' been explicitly allowed? | |
594 | if ((isset($formats['my']) && $formats['my'] == false) | |
595 | || (empty($formats['all']) && empty($formats['my']))) { | |
596 | ||
597 | // Block cannot be added to /my regardless of capabilities. | |
598 | return false; | |
599 | } else { | |
600 | $capability = 'block/' . $this->name() . ':myaddinstance'; | |
601 | return $this->has_add_block_capability($page, $capability) | |
602 | && has_capability('moodle/my:manageblocks', $page->context); | |
603 | } | |
03d9401e | 604 | } |
ef78cf8f DM |
605 | // Check if this is a block only used on /my. |
606 | unset($formats['my']); | |
607 | if (empty($formats)) { | |
608 | // Block can only be added to /my - return false. | |
609 | return false; | |
610 | } | |
03d9401e | 611 | |
464e00be MN |
612 | $capability = 'block/' . $this->name() . ':addinstance'; |
613 | if ($this->has_add_block_capability($page, $capability) | |
614 | && has_capability('moodle/block:edit', $page->context)) { | |
615 | return true; | |
616 | } | |
617 | ||
03d9401e | 618 | return false; |
11306331 | 619 | } |
620 | ||
b291b59d MN |
621 | /** |
622 | * Returns true if the user can add a block to a page. | |
623 | * | |
624 | * @param moodle_page $page | |
625 | * @param string $capability the capability to check | |
626 | * @return boolean true if user can add a block, false otherwise. | |
627 | */ | |
628 | private function has_add_block_capability($page, $capability) { | |
629 | // Check if the capability exists. | |
630 | if (!get_capability_info($capability)) { | |
631 | // Debug warning that the capability does not exist, but no more than once per page. | |
632 | static $warned = array(); | |
633 | if (!isset($warned[$this->name()])) { | |
634 | debugging('The block ' .$this->name() . ' does not define the standard capability ' . | |
635 | $capability , DEBUG_DEVELOPER); | |
636 | $warned[$this->name()] = 1; | |
637 | } | |
638 | // If the capability does not exist, the block can always be added. | |
639 | return true; | |
640 | } else { | |
641 | return has_capability($capability, $page->context); | |
642 | } | |
643 | } | |
644 | ||
324d210f | 645 | static function get_extra_capabilities() { |
d14edf06 | 646 | return array('moodle/block:view', 'moodle/block:edit'); |
f432bebf | 647 | } |
d4a03c00 | 648 | |
d8ef60bd SH |
649 | /** |
650 | * Can be overridden by the block to prevent the block from being dockable. | |
9c14c1c5 | 651 | * |
d8ef60bd | 652 | * @return bool |
9757c656 MM |
653 | * |
654 | * Return false as per MDL-64506 | |
d8ef60bd | 655 | */ |
d2c394f3 | 656 | public function instance_can_be_docked() { |
c8edee42 | 657 | return false; |
9d897331 SH |
658 | } |
659 | ||
d8ef60bd | 660 | /** |
0885166f | 661 | * If overridden and set to false by the block it will not be hidable when |
d8ef60bd SH |
662 | * editing is turned on. |
663 | * | |
664 | * @return bool | |
665 | */ | |
666 | public function instance_can_be_hidden() { | |
667 | return true; | |
668 | } | |
669 | ||
0885166f JC |
670 | /** |
671 | * If overridden and set to false by the block it will not be collapsible. | |
672 | * | |
673 | * @return bool | |
674 | */ | |
675 | public function instance_can_be_collapsed() { | |
676 | return true; | |
677 | } | |
678 | ||
1bcb7eb5 | 679 | /** @callback callback functions for comments api */ |
680 | public static function comment_template($options) { | |
681 | $ret = <<<EOD | |
4ca6cfbf | 682 | <div class="comment-userpicture">___picture___</div> |
1bcb7eb5 | 683 | <div class="comment-content"> |
684 | ___name___ - <span>___time___</span> | |
685 | <div>___content___</div> | |
686 | </div> | |
687 | EOD; | |
688 | return $ret; | |
689 | } | |
690 | public static function comment_permissions($options) { | |
691 | return array('view'=>true, 'post'=>true); | |
692 | } | |
693 | public static function comment_url($options) { | |
694 | return null; | |
695 | } | |
a0e68ffc DC |
696 | public static function comment_display($comments, $options) { |
697 | return $comments; | |
1bcb7eb5 | 698 | } |
699 | public static function comment_add(&$comments, $options) { | |
700 | return true; | |
701 | } | |
697f7bd7 SH |
702 | |
703 | /** | |
704 | * Returns the aria role attribute that best describes this block. | |
705 | * | |
706 | * Region is the default, but this should be overridden by a block is there is a region child, or even better | |
707 | * a landmark child. | |
708 | * | |
709 | * Options are as follows: | |
697f7bd7 SH |
710 | * - landmark |
711 | * - application | |
712 | * - banner | |
713 | * - complementary | |
714 | * - contentinfo | |
715 | * - form | |
716 | * - main | |
717 | * - navigation | |
718 | * - search | |
697f7bd7 SH |
719 | * |
720 | * @return string | |
721 | */ | |
722 | public function get_aria_role() { | |
5c4581fc | 723 | return 'complementary'; |
697f7bd7 | 724 | } |
0f3fe4b6 | 725 | } |
726 | ||
c7e3bc51 | 727 | /** |
3ef642d9 | 728 | * Specialized class for displaying a block with a list of icons/text labels |
729 | * | |
d4a03c00 | 730 | * The get_content method should set $this->content->items and (optionally) |
731 | * $this->content->icons, instead of $this->content->text. | |
732 | * | |
3ef642d9 | 733 | * @author Jon Papaioannou |
f25a6839 | 734 | * @package core_block |
3ef642d9 | 735 | */ |
736 | ||
737 | class block_list extends block_base { | |
738 | var $content_type = BLOCK_TYPE_LIST; | |
739 | ||
740 | function is_empty() { | |
e92c286c | 741 | if ( !has_capability('moodle/block:view', $this->context) ) { |
25a7d980 | 742 | return true; |
743 | } | |
744 | ||
3ef642d9 | 745 | $this->get_content(); |
746 | return (empty($this->content->items) && empty($this->content->footer)); | |
747 | } | |
748 | ||
d4a03c00 | 749 | protected function formatted_contents($output) { |
750 | $this->get_content(); | |
dde36f9d | 751 | $this->get_required_javascript(); |
d4a03c00 | 752 | if (!empty($this->content->items)) { |
753 | return $output->list_block_contents($this->content->icons, $this->content->items); | |
3ef642d9 | 754 | } else { |
d4a03c00 | 755 | return ''; |
3ef642d9 | 756 | } |
757 | } | |
740952e4 SH |
758 | |
759 | function html_attributes() { | |
760 | $attributes = parent::html_attributes(); | |
761 | $attributes['class'] .= ' list_block'; | |
762 | return $attributes; | |
763 | } | |
764 | ||
3ef642d9 | 765 | } |
766 | ||
7d2a0492 | 767 | /** |
768 | * Specialized class for displaying a tree menu. | |
4ca6cfbf | 769 | * |
7d2a0492 | 770 | * The {@link get_content()} method involves setting the content of |
771 | * <code>$this->content->items</code> with an array of {@link tree_item} | |
772 | * objects (these are the top-level nodes). The {@link tree_item::children} | |
773 | * property may contain more tree_item objects, and so on. The tree_item class | |
774 | * itself is abstract and not intended for use, use one of it's subclasses. | |
4ca6cfbf | 775 | * |
7d2a0492 | 776 | * Unlike {@link block_list}, the icons are specified as part of the items, |
777 | * not in a separate array. | |
778 | * | |
779 | * @author Alan Trick | |
f25a6839 | 780 | * @package core_block |
7d2a0492 | 781 | * @internal this extends block_list so we get is_empty() for free |
782 | */ | |
783 | class block_tree extends block_list { | |
4ca6cfbf | 784 | |
7d2a0492 | 785 | /** |
786 | * @var int specifies the manner in which contents should be added to this | |
787 | * block type. In this case <code>$this->content->items</code> is used with | |
788 | * {@link tree_item}s. | |
789 | */ | |
790 | public $content_type = BLOCK_TYPE_TREE; | |
4ca6cfbf | 791 | |
7d2a0492 | 792 | /** |
793 | * Make the formatted HTML ouput. | |
4ca6cfbf | 794 | * |
7d2a0492 | 795 | * Also adds the required javascript call to the page output. |
796 | * | |
78946b9b | 797 | * @param core_renderer $output |
7d2a0492 | 798 | * @return string HTML |
799 | */ | |
800 | protected function formatted_contents($output) { | |
801 | // based of code in admin_tree | |
802 | global $PAGE; // TODO change this when there is a proper way for blocks to get stuff into head. | |
803 | static $eventattached; | |
804 | if ($eventattached===null) { | |
805 | $eventattached = true; | |
806 | } | |
807 | if (!$this->content) { | |
808 | $this->content = new stdClass; | |
809 | $this->content->items = array(); | |
810 | } | |
d5cbccb3 | 811 | $this->get_required_javascript(); |
7d2a0492 | 812 | $this->get_content(); |
1ce15fda | 813 | $content = $output->tree_block_contents($this->content->items,array('class'=>'block_tree list')); |
7d2a0492 | 814 | if (isset($this->id) && !is_numeric($this->id)) { |
815 | $content = $output->box($content, 'block_tree_box', $this->id); | |
816 | } | |
817 | return $content; | |
818 | } | |
a0e68ffc | 819 | } |