backup MDL-22142 Several changes to the backup UI and it's classes as noted below
[moodle.git] / lib / outputcomponents.php
CommitLineData
d9c8f425 1<?php
2
3// This file is part of Moodle - http://moodle.org/
4//
5// Moodle is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// Moodle is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
17
18/**
19 * Classes representing HTML elements, used by $OUTPUT methods
20 *
21 * Please see http://docs.moodle.org/en/Developement:How_Moodle_outputs_HTML
22 * for an overview.
23 *
24 * @package moodlecore
25 * @copyright 2009 Tim Hunt
26 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
27 */
28
5d0c95a5
PS
29
30/**
31 * Interface marking other classes as suitable for renderer_base::render()
32 * @author 2010 Petr Skoda (skodak) info@skodak.org
33 */
34interface renderable {
35 // intentionally empty
36}
37
38
39/**
bf11293a 40 * Data structure representing a user picture.
5d0c95a5
PS
41 *
42 * @copyright 2009 Nicolas Connault, 2010 Petr Skoda
43 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
44 * @since Moodle 2.0
45 */
46class user_picture implements renderable {
47 /**
48 * List of mandatory fields in user record here.
49 * @var string
50 */
51 const FIELDS = 'id,picture,firstname,lastname,imagealt';
52
53 /**
54 * @var object $user A user object with at least fields id, picture, imagealt, firstname and lastname set.
55 */
56 public $user;
57 /**
58 * @var int $courseid The course id. Used when constructing the link to the user's profile,
59 * page course id used if not specified.
60 */
61 public $courseid;
62 /**
63 * @var bool $link add course profile link to image
64 */
65 public $link = true;
66 /**
67 * @var int $size Size in pixels. Special values are (true/1 = 100px) and (false/0 = 35px) for backward compatibility
68 */
69 public $size = 35;
70 /**
71 * @var boolean $alttext add non-blank alt-text to the image.
72 * Default true, set to false when image alt just duplicates text in screenreaders.
73 */
74 public $alttext = true;
75 /**
76 * @var boolean $popup Whether or not to open the link in a popup window.
77 */
78 public $popup = false;
79 /**
80 * @var string Image class attribute
81 */
82 public $class = 'userpicture';
83
84 /**
85 * User picture constructor.
86 *
87 * @param object $user user record with at least id, picture, imagealt, firstname and lastname set.
88 * @param array $options such as link, size, link, ...
89 */
90 public function __construct(stdClass $user) {
91 global $DB;
92
93 static $fields = null;
94 if (is_null($fields)) {
95 $fields = explode(',', self::FIELDS);
96 }
97
98 if (empty($user->id)) {
99 throw new coding_exception('User id is required when printing user avatar image.');
100 }
101
102 // only touch the DB if we are missing data and complain loudly...
103 $needrec = false;
104 foreach ($fields as $field) {
105 if (!array_key_exists($field, $user)) {
106 $needrec = true;
107 debugging('Missing '.$field.' property in $user object, this is a performance problem that needs to be fixed by a developer. '
108 .'Please use user_picture::fields() to get the full list of required fields.', DEBUG_DEVELOPER);
109 break;
110 }
111 }
112
113 if ($needrec) {
114 $this->user = $DB->get_record('user', array('id'=>$user->id), self::FIELDS, MUST_EXIST);
115 } else {
116 $this->user = clone($user);
117 }
118 }
119
120 /**
121 * Returns a list of required user fields, usefull when fetching required user info from db.
f3afba4e
PS
122 *
123 * In some cases we have to fetch the user data together with some other information,
124 * the idalias is useful there because the id would otherwise override the main
125 * id of the result record. Please note it has to be converted back to id before rendering.
126 *
5d0c95a5 127 * @param string $tableprefix name of database table prefix in query
f3afba4e 128 * @param string $idalias alias of id field
5d0c95a5
PS
129 * @return string
130 */
f3afba4e
PS
131 public static function fields($tableprefix = '', $idalias = '') {
132 if ($tableprefix === '' and $idalias === '') {
5d0c95a5 133 return self::FIELDS;
5d0c95a5 134 }
f3afba4e
PS
135 $fields = explode(',', self::FIELDS);
136 foreach ($fields as $key=>$field) {
137 if ($field === 'id' and $idalias !== '') {
138 $field = "$field AS $idalias";
139 }
140 $fields[$key] = "$tableprefix.$field";
141 }
142 return implode(',', $fields);
5d0c95a5
PS
143 }
144}
145
bf11293a
PS
146
147/**
148 * Data structure representing a help icon.
149 *
150 * @copyright 2009 Nicolas Connault, 2010 Petr Skoda
151 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
152 * @since Moodle 2.0
153 */
596509e4 154class old_help_icon implements renderable {
bf11293a 155 /**
49f0d481 156 * @var string $helpidentifier lang pack identifier
bf11293a 157 */
53a78cef 158 public $helpidentifier;
bf11293a
PS
159 /**
160 * @var string $title A descriptive text for title tooltip
161 */
97c10099 162 public $title = null;
bf11293a
PS
163 /**
164 * @var string $component Component name, the same as in get_string()
165 */
166 public $component = 'moodle';
167 /**
168 * @var string $linktext Extra descriptive text next to the icon
169 */
97c10099 170 public $linktext = null;
bf11293a
PS
171
172 /**
173 * Constructor: sets up the other components in case they are needed
53a78cef 174 * @param string $helpidentifier The keyword that defines a help page
bf11293a
PS
175 * @param string $title A descriptive text for accesibility only
176 * @param string $component
177 * @param bool $linktext add extra text to icon
178 * @return void
179 */
53a78cef 180 public function __construct($helpidentifier, $title, $component = 'moodle') {
bf11293a
PS
181 if (empty($title)) {
182 throw new coding_exception('A help_icon object requires a $text parameter');
183 }
53a78cef
PS
184 if (empty($helpidentifier)) {
185 throw new coding_exception('A help_icon object requires a $helpidentifier parameter');
bf11293a
PS
186 }
187
53a78cef
PS
188 $this->helpidentifier = $helpidentifier;
189 $this->title = $title;
190 $this->component = $component;
bf11293a
PS
191 }
192}
193
49f0d481
PS
194/**
195 * Data structure representing a help icon.
196 *
197 * @copyright 2010 Petr Skoda (info@skodak.org)
198 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
199 * @since Moodle 2.0
200 */
201class help_icon implements renderable {
202 /**
5435c9dc
MD
203 * @var string $identifier lang pack identifier (without the "_help" suffix),
204 * both get_string($identifier, $component) and get_string($identifier.'_help', $component)
49f0d481
PS
205 * must exist.
206 */
207 public $identifier;
208 /**
209 * @var string $component Component name, the same as in get_string()
210 */
211 public $component;
212 /**
213 * @var string $linktext Extra descriptive text next to the icon
214 */
215 public $linktext = null;
216
217 /**
218 * Constructor
219 * @param string $identifier string for help page title,
5435c9dc
MD
220 * string with _help suffix is used for the actual help text.
221 * string with _link suffix is used to create a link to further info (if it exists)
49f0d481
PS
222 * @param string $component
223 */
259c165d
PS
224 public function __construct($identifier, $component) {
225 $this->identifier = $identifier;
49f0d481
PS
226 $this->component = $component;
227 }
259c165d
PS
228
229 /**
230 * Verifies that both help strings exists, shows debug warnings if not
231 */
232 public function diag_strings() {
233 $sm = get_string_manager();
234 if (!$sm->string_exists($this->identifier, $this->component)) {
235 debugging("Help title string does not exist: [$this->identifier, $this->component]");
236 }
5435c9dc 237 if (!$sm->string_exists($this->identifier.'_help', $this->component)) {
876521ac 238 debugging("Help contents string does not exist: [{$this->identifier}_help, $this->component]");
259c165d
PS
239 }
240 }
49f0d481
PS
241}
242
bf11293a 243
000c278c
PS
244/**
245 * Data structure representing an icon.
246 *
247 * @copyright 2010 Petr Skoda
248 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
249 * @since Moodle 2.0
250 */
251class pix_icon implements renderable {
252 var $pix;
253 var $component;
254 var $attributes = array();
255
256 /**
257 * Constructor
258 * @param string $pix short icon name
259 * @param string $component component name
260 * @param array $attributes html attributes
261 */
262 public function __construct($pix, $alt, $component='moodle', array $attributes = null) {
c80877aa
PS
263 $this->pix = $pix;
264 $this->component = $component;
000c278c
PS
265 $this->attributes = (array)$attributes;
266
267 $this->attributes['alt'] = $alt;
268 if (empty($this->attributes['class'])) {
269 $this->attributes['class'] = 'smallicon';
270 }
271 if (!isset($this->attributes['title'])) {
272 $this->attributes['title'] = $this->attributes['alt'];
273 }
274 }
275}
276
277
3ba60ee1
PS
278/**
279 * Data structure representing a simple form with only one button.
280 *
281 * @copyright 2009 Petr Skoda
282 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
283 * @since Moodle 2.0
284 */
285class single_button implements renderable {
574fbea4
PS
286 /**
287 * Target url
288 * @var moodle_url
289 */
3ba60ee1 290 var $url;
574fbea4
PS
291 /**
292 * Button label
293 * @var string
294 */
3ba60ee1 295 var $label;
574fbea4
PS
296 /**
297 * Form submit method
298 * @var string post or get
299 */
3ba60ee1 300 var $method = 'post';
574fbea4
PS
301 /**
302 * Wrapping div class
303 * @var string
304 * */
3ba60ee1 305 var $class = 'singlebutton';
574fbea4
PS
306 /**
307 * True if button disabled, false if normal
308 * @var boolean
309 */
3ba60ee1 310 var $disabled = false;
574fbea4
PS
311 /**
312 * Button tooltip
313 * @var string
314 */
97c10099 315 var $tooltip = null;
574fbea4
PS
316 /**
317 * Form id
318 * @var string
319 */
3ba60ee1 320 var $formid;
574fbea4
PS
321 /**
322 * List of attached actions
323 * @var array of component_action
324 */
3ba60ee1
PS
325 var $actions = array();
326
327 /**
328 * Constructor
574fbea4 329 * @param string|moodle_url $url
3ba60ee1
PS
330 * @param string $label button text
331 * @param string $method get or post submit method
3ba60ee1
PS
332 */
333 public function __construct(moodle_url $url, $label, $method='post') {
334 $this->url = clone($url);
335 $this->label = $label;
336 $this->method = $method;
337 }
338
339 /**
574fbea4 340 * Shortcut for adding a JS confirm dialog when the button is clicked.
3ba60ee1
PS
341 * The message must be a yes/no question.
342 * @param string $message The yes/no confirmation question. If "Yes" is clicked, the original action will occur.
343 * @return void
344 */
345 public function add_confirm_action($confirmmessage) {
20fb563e 346 $this->add_action(new component_action('click', 'M.util.show_confirm_dialog', array('message' => $confirmmessage)));
3ba60ee1
PS
347 }
348
574fbea4
PS
349 /**
350 * Add action to the button.
351 * @param component_action $action
352 * @return void
353 */
3ba60ee1
PS
354 public function add_action(component_action $action) {
355 $this->actions[] = $action;
356 }
357}
358
359
a9967cf5
PS
360/**
361 * Simple form with just one select field that gets submitted automatically.
362 * If JS not enabled small go button is printed too.
363 *
364 * @copyright 2009 Petr Skoda
365 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
366 * @since Moodle 2.0
367 */
368class single_select implements renderable {
369 /**
370 * Target url - includes hidden fields
371 * @var moodle_url
372 */
373 var $url;
374 /**
375 * Name of the select element.
376 * @var string
377 */
378 var $name;
379 /**
380 * @var array $options associative array value=>label ex.:
381 * array(1=>'One, 2=>Two)
382 * it is also possible to specify optgroup as complex label array ex.:
383 * array(array('Odd'=>array(1=>'One', 3=>'Three)), array('Even'=>array(2=>'Two')))
384 * array(1=>'One', '--1uniquekey'=>array('More'=>array(2=>'Two', 3=>'Three')))
385 */
386 var $options;
387 /**
388 * Selected option
389 * @var string
390 */
391 var $selected;
392 /**
393 * Nothing selected
394 * @var array
395 */
396 var $nothing;
397 /**
398 * Extra select field attributes
399 * @var array
400 */
401 var $attributes = array();
402 /**
403 * Button label
404 * @var string
405 */
406 var $label = '';
407 /**
408 * Form submit method
409 * @var string post or get
410 */
411 var $method = 'get';
412 /**
413 * Wrapping div class
414 * @var string
415 * */
416 var $class = 'singleselect';
417 /**
418 * True if button disabled, false if normal
419 * @var boolean
420 */
421 var $disabled = false;
422 /**
423 * Button tooltip
424 * @var string
425 */
426 var $tooltip = null;
427 /**
428 * Form id
429 * @var string
430 */
431 var $formid = null;
432 /**
433 * List of attached actions
434 * @var array of component_action
435 */
436 var $helpicon = null;
437 /**
438 * Constructor
439 * @param moodle_url $url form action target, includes hidden fields
440 * @param string $name name of selection field - the changing parameter in url
441 * @param array $options list of options
442 * @param string $selected selected element
443 * @param array $nothing
f8dab966 444 * @param string $formid
a9967cf5 445 */
f8dab966 446 public function __construct(moodle_url $url, $name, array $options, $selected='', $nothing=array(''=>'choosedots'), $formid=null) {
a9967cf5
PS
447 $this->url = $url;
448 $this->name = $name;
449 $this->options = $options;
450 $this->selected = $selected;
451 $this->nothing = $nothing;
f8dab966 452 $this->formid = $formid;
a9967cf5
PS
453 }
454
455 /**
456 * Shortcut for adding a JS confirm dialog when the button is clicked.
457 * The message must be a yes/no question.
458 * @param string $message The yes/no confirmation question. If "Yes" is clicked, the original action will occur.
459 * @return void
460 */
461 public function add_confirm_action($confirmmessage) {
462 $this->add_action(new component_action('submit', 'M.util.show_confirm_dialog', array('message' => $confirmmessage)));
463 }
464
465 /**
466 * Add action to the button.
467 * @param component_action $action
468 * @return void
469 */
470 public function add_action(component_action $action) {
471 $this->actions[] = $action;
472 }
f8dab966
PS
473
474 /**
259c165d 475 * Adds help icon.
f8dab966
PS
476 * @param string $page The keyword that defines a help page
477 * @param string $title A descriptive text for accesibility only
478 * @param string $component
479 * @param bool $linktext add extra text to icon
480 * @return void
481 */
596509e4
PS
482 public function set_old_help_icon($helppage, $title, $component = 'moodle') {
483 $this->helpicon = new old_help_icon($helppage, $title, $component);
f8dab966
PS
484 }
485
259c165d
PS
486 /**
487 * Adds help icon.
488 * @param string $identifier The keyword that defines a help page
489 * @param string $component
490 * @param bool $linktext add extra text to icon
491 * @return void
492 */
493 public function set_help_icon($identifier, $component = 'moodle') {
9c7b24bf 494 $this->helpicon = new help_icon($identifier, $component);
259c165d
PS
495 }
496
f8dab966
PS
497 /**
498 * Set's select lable
499 * @param string $label
500 * @return void
501 */
502 public function set_label($label) {
503 $this->label = $label;
504 }
a9967cf5
PS
505}
506
507
4d10e579
PS
508/**
509 * Simple URL selection widget description.
510 * @copyright 2009 Petr Skoda
511 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
512 * @since Moodle 2.0
513 */
514class url_select implements renderable {
515 /**
516 * @var array $urls associative array value=>label ex.:
517 * array(1=>'One, 2=>Two)
518 * it is also possible to specify optgroup as complex label array ex.:
519 * array(array('Odd'=>array(1=>'One', 3=>'Three)), array('Even'=>array(2=>'Two')))
520 * array(1=>'One', '--1uniquekey'=>array('More'=>array(2=>'Two', 3=>'Three')))
521 */
522 var $urls;
523 /**
524 * Selected option
525 * @var string
526 */
527 var $selected;
528 /**
529 * Nothing selected
530 * @var array
531 */
532 var $nothing;
533 /**
534 * Extra select field attributes
535 * @var array
536 */
537 var $attributes = array();
538 /**
539 * Button label
540 * @var string
541 */
542 var $label = '';
543 /**
544 * Wrapping div class
545 * @var string
546 * */
547 var $class = 'urlselect';
548 /**
549 * True if button disabled, false if normal
550 * @var boolean
551 */
552 var $disabled = false;
553 /**
554 * Button tooltip
555 * @var string
556 */
557 var $tooltip = null;
558 /**
559 * Form id
560 * @var string
561 */
562 var $formid = null;
563 /**
564 * List of attached actions
565 * @var array of component_action
566 */
567 var $helpicon = null;
568 /**
569 * Constructor
570 * @param array $urls list of options
571 * @param string $selected selected element
572 * @param array $nothing
573 * @param string $formid
574 */
575 public function __construct(array $urls, $selected='', $nothing=array(''=>'choosedots'), $formid=null) {
576 $this->urls = $urls;
577 $this->selected = $selected;
578 $this->nothing = $nothing;
579 $this->formid = $formid;
580 }
581
582 /**
259c165d 583 * Adds help icon.
4d10e579
PS
584 * @param string $page The keyword that defines a help page
585 * @param string $title A descriptive text for accesibility only
586 * @param string $component
587 * @param bool $linktext add extra text to icon
588 * @return void
589 */
596509e4
PS
590 public function set_old_help_icon($helppage, $title, $component = 'moodle') {
591 $this->helpicon = new old_help_icon($helppage, $title, $component);
4d10e579
PS
592 }
593
259c165d
PS
594 /**
595 * Adds help icon.
596 * @param string $identifier The keyword that defines a help page
597 * @param string $component
598 * @param bool $linktext add extra text to icon
599 * @return void
600 */
601 public function set_help_icon($identifier, $component = 'moodle') {
9c7b24bf 602 $this->helpicon = new help_icon($identifier, $component);
259c165d
PS
603 }
604
4d10e579
PS
605 /**
606 * Set's select lable
607 * @param string $label
608 * @return void
609 */
610 public function set_label($label) {
611 $this->label = $label;
612 }
613}
614
615
574fbea4
PS
616/**
617 * Data structure describing html link with special action attached.
618 * @copyright 2010 Petr Skoda
619 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
620 * @since Moodle 2.0
621 */
622class action_link implements renderable {
623 /**
624 * Href url
625 * @var moodle_url
626 */
627 var $url;
628 /**
629 * Link text
630 * @var string HTML fragment
631 */
632 var $text;
633 /**
634 * HTML attributes
635 * @var array
636 */
637 var $attributes;
638 /**
639 * List of actions attached to link
640 * @var array of component_action
641 */
642 var $actions;
643
644 /**
645 * Constructor
646 * @param string|moodle_url $url
647 * @param string $text HTML fragment
648 * @param component_action $action
11820bac 649 * @param array $attributes associative array of html link attributes + disabled
574fbea4
PS
650 */
651 public function __construct(moodle_url $url, $text, component_action $action=null, array $attributes=null) {
652 $this->url = clone($url);
653 $this->text = $text;
b0fef57b 654 $this->attributes = (array)$attributes;
f14b641b 655 if ($action) {
574fbea4
PS
656 $this->add_action($action);
657 }
658 }
659
660 /**
661 * Add action to the link.
662 * @param component_action $action
663 * @return void
664 */
665 public function add_action(component_action $action) {
666 $this->actions[] = $action;
667 }
c63923bd
PS
668
669 public function add_class($class) {
67da0bf7
DM
670 if (empty($this->attributes['class'])) {
671 $this->attributes['class'] = $class;
c63923bd 672 } else {
67da0bf7 673 $this->attributes['class'] .= ' ' . $class;
c63923bd
PS
674 }
675 }
574fbea4 676}
3ba60ee1 677
227255b8 678// ==== HTML writer and helper classes, will be probably moved elsewhere ======
5d0c95a5
PS
679
680/**
681 * Simple html output class
682 * @copyright 2009 Tim Hunt, 2010 Petr Skoda
683 */
684class html_writer {
685 /**
686 * Outputs a tag with attributes and contents
687 * @param string $tagname The name of tag ('a', 'img', 'span' etc.)
5d0c95a5 688 * @param string $contents What goes between the opening and closing tags
26acc814 689 * @param array $attributes The tag attributes (array('src' => $url, 'class' => 'class1') etc.)
5d0c95a5
PS
690 * @return string HTML fragment
691 */
26acc814 692 public static function tag($tagname, $contents, array $attributes = null) {
5d0c95a5
PS
693 return self::start_tag($tagname, $attributes) . $contents . self::end_tag($tagname);
694 }
695
696 /**
697 * Outputs an opening tag with attributes
698 * @param string $tagname The name of tag ('a', 'img', 'span' etc.)
699 * @param array $attributes The tag attributes (array('src' => $url, 'class' => 'class1') etc.)
700 * @return string HTML fragment
701 */
702 public static function start_tag($tagname, array $attributes = null) {
703 return '<' . $tagname . self::attributes($attributes) . '>';
704 }
705
706 /**
707 * Outputs a closing tag
708 * @param string $tagname The name of tag ('a', 'img', 'span' etc.)
709 * @return string HTML fragment
710 */
711 public static function end_tag($tagname) {
712 return '</' . $tagname . '>';
713 }
714
715 /**
716 * Outputs an empty tag with attributes
717 * @param string $tagname The name of tag ('input', 'img', 'br' etc.)
718 * @param array $attributes The tag attributes (array('src' => $url, 'class' => 'class1') etc.)
719 * @return string HTML fragment
720 */
721 public static function empty_tag($tagname, array $attributes = null) {
722 return '<' . $tagname . self::attributes($attributes) . ' />';
723 }
724
836c47d7
TH
725 /**
726 * Outputs a tag, but only if the contents are not empty
727 * @param string $tagname The name of tag ('a', 'img', 'span' etc.)
728 * @param string $contents What goes between the opening and closing tags
729 * @param array $attributes The tag attributes (array('src' => $url, 'class' => 'class1') etc.)
730 * @return string HTML fragment
731 */
732 public static function nonempty_tag($tagname, $contents, array $attributes = null) {
733 if ($contents === '' || is_null($contents)) {
734 return '';
735 }
736 return self::tag($tagname, $contents, $attributes);
737 }
738
5d0c95a5
PS
739 /**
740 * Outputs a HTML attribute and value
741 * @param string $name The name of the attribute ('src', 'href', 'class' etc.)
742 * @param string $value The value of the attribute. The value will be escaped with {@link s()}
743 * @return string HTML fragment
744 */
745 public static function attribute($name, $value) {
746 if (is_array($value)) {
747 debugging("Passed an array for the HTML attribute $name", DEBUG_DEVELOPER);
748 }
bf11293a
PS
749 if ($value instanceof moodle_url) {
750 return ' ' . $name . '="' . $value->out() . '"';
751 }
97c10099
PS
752
753 // special case, we do not want these in output
754 if ($value === null) {
755 return '';
5d0c95a5 756 }
97c10099
PS
757
758 // no sloppy trimming here!
759 return ' ' . $name . '="' . s($value) . '"';
5d0c95a5
PS
760 }
761
762 /**
763 * Outputs a list of HTML attributes and values
764 * @param array $attributes The tag attributes (array('src' => $url, 'class' => 'class1') etc.)
765 * The values will be escaped with {@link s()}
766 * @return string HTML fragment
767 */
768 public static function attributes(array $attributes = null) {
769 $attributes = (array)$attributes;
770 $output = '';
771 foreach ($attributes as $name => $value) {
772 $output .= self::attribute($name, $value);
773 }
774 return $output;
775 }
776
777 /**
778 * Generates random html element id.
779 * @param string $base
780 * @return string
781 */
782 public static function random_id($base='random') {
783 return uniqid($base);
784 }
0f4c64b7
PS
785
786 /**
787 * Generates a simple html link
788 * @param string|moodle_url $url
789 * @param string $text link txt
790 * @param array $attributes extra html attributes
791 * @return string HTML fragment
792 */
793 public static function link($url, $text, array $attributes = null) {
794 $attributes = (array)$attributes;
795 $attributes['href'] = $url;
26acc814 796 return self::tag('a', $text, $attributes);
0f4c64b7 797 }
3ff163c5 798
14dce022
PS
799 /**
800 * generates a simple checkbox with optional label
801 * @param string $name
802 * @param string $value
803 * @param bool $checked
804 * @param string $label
805 * @param array $attributes
806 * @return string html fragment
807 */
808 public static function checkbox($name, $value, $checked = true, $label = '', array $attributes = null) {
809 $attributes = (array)$attributes;
810 $output = '';
811
812 if ($label !== '' and !is_null($label)) {
813 if (empty($attributes['id'])) {
814 $attributes['id'] = self::random_id('checkbox_');
815 }
816 }
53868425
PS
817 $attributes['type'] = 'checkbox';
818 $attributes['value'] = $value;
819 $attributes['name'] = $name;
14dce022 820 $attributes['checked'] = $checked ? 'selected' : null;
53868425 821
14dce022
PS
822 $output .= self::empty_tag('input', $attributes);
823
824 if ($label !== '' and !is_null($label)) {
26acc814 825 $output .= self::tag('label', $label, array('for'=>$attributes['id']));
14dce022
PS
826 }
827
828 return $output;
829 }
830
78bdac64
PS
831 /**
832 * Generates a simple select yes/no form field
833 * @param string $name name of select element
834 * @param bool $selected
835 * @param array $attributes - html select element attributes
836 * @return string HRML fragment
837 */
19f3bbb2 838 public static function select_yes_no($name, $selected=true, array $attributes = null) {
78bdac64
PS
839 $options = array('1'=>get_string('yes'), '0'=>get_string('no'));
840 return self::select($options, $name, $selected, null, $attributes);
841 }
842
3ff163c5
PS
843 /**
844 * Generates a simple select form field
6770330d
PS
845 * @param array $options associative array value=>label ex.:
846 * array(1=>'One, 2=>Two)
847 * it is also possible to specify optgroup as complex label array ex.:
bde156b3 848 * array(array('Odd'=>array(1=>'One', 3=>'Three)), array('Even'=>array(2=>'Two')))
6770330d 849 * array(1=>'One', '--1uniquekey'=>array('More'=>array(2=>'Two', 3=>'Three')))
3ff163c5
PS
850 * @param string $name name of select element
851 * @param string|array $selected value or arary of values depending on multiple attribute
852 * @param array|bool $nothing, add nothing selected option, or false of not added
853 * @param array $attributes - html select element attributes
78bdac64 854 * @return string HTML fragment
3ff163c5 855 */
aa2dea70 856 public static function select(array $options, $name, $selected = '', $nothing = array(''=>'choosedots'), array $attributes = null) {
3ff163c5
PS
857 $attributes = (array)$attributes;
858 if (is_array($nothing)) {
859 foreach ($nothing as $k=>$v) {
4b9210f3 860 if ($v === 'choose' or $v === 'choosedots') {
3ff163c5
PS
861 $nothing[$k] = get_string('choosedots');
862 }
863 }
864 $options = $nothing + $options; // keep keys, do not override
3750c3bd
PS
865
866 } else if (is_string($nothing) and $nothing !== '') {
867 // BC
868 $options = array(''=>$nothing) + $options;
bde156b3 869 }
3ff163c5
PS
870
871 // we may accept more values if multiple attribute specified
872 $selected = (array)$selected;
873 foreach ($selected as $k=>$v) {
874 $selected[$k] = (string)$v;
875 }
876
877 if (!isset($attributes['id'])) {
878 $id = 'menu'.$name;
879 // name may contaion [], which would make an invalid id. e.g. numeric question type editing form, assignment quickgrading
880 $id = str_replace('[', '', $id);
881 $id = str_replace(']', '', $id);
882 $attributes['id'] = $id;
883 }
884
885 if (!isset($attributes['class'])) {
886 $class = 'menu'.$name;
887 // name may contaion [], which would make an invalid class. e.g. numeric question type editing form, assignment quickgrading
888 $class = str_replace('[', '', $class);
889 $class = str_replace(']', '', $class);
890 $attributes['class'] = $class;
891 }
892 $attributes['class'] = 'select ' . $attributes['class']; /// Add 'select' selector always
893
894 $attributes['name'] = $name;
895
896 $output = '';
897 foreach ($options as $value=>$label) {
6770330d
PS
898 if (is_array($label)) {
899 // ignore key, it just has to be unique
900 $output .= self::select_optgroup(key($label), current($label), $selected);
901 } else {
902 $output .= self::select_option($label, $value, $selected);
3ff163c5 903 }
3ff163c5 904 }
26acc814 905 return self::tag('select', $output, $attributes);
3ff163c5 906 }
6770330d
PS
907
908 private static function select_option($label, $value, array $selected) {
909 $attributes = array();
910 $value = (string)$value;
911 if (in_array($value, $selected, true)) {
912 $attributes['selected'] = 'selected';
913 }
914 $attributes['value'] = $value;
26acc814 915 return self::tag('option', $label, $attributes);
6770330d
PS
916 }
917
918 private static function select_optgroup($groupname, $options, array $selected) {
919 if (empty($options)) {
920 return '';
921 }
922 $attributes = array('label'=>$groupname);
923 $output = '';
924 foreach ($options as $value=>$label) {
925 $output .= self::select_option($label, $value, $selected);
926 }
26acc814 927 return self::tag('optgroup', $output, $attributes);
6770330d 928 }
6ea66ff3 929
f83b9b63
PS
930 /**
931 * This is a shortcut for making an hour selector menu.
932 * @param string $type The type of selector (years, months, days, hours, minutes)
933 * @param string $name fieldname
934 * @param int $currenttime A default timestamp in GMT
935 * @param int $step minute spacing
936 * @param array $attributes - html select element attributes
937 * @return HTML fragment
938 */
939 public static function select_time($type, $name, $currenttime=0, $step=5, array $attributes=null) {
940 if (!$currenttime) {
941 $currenttime = time();
942 }
943 $currentdate = usergetdate($currenttime);
944 $userdatetype = $type;
945 $timeunits = array();
946
947 switch ($type) {
948 case 'years':
949 for ($i=1970; $i<=2020; $i++) {
950 $timeunits[$i] = $i;
951 }
952 $userdatetype = 'year';
953 break;
954 case 'months':
955 for ($i=1; $i<=12; $i++) {
956 $timeunits[$i] = userdate(gmmktime(12,0,0,$i,15,2000), "%B");
957 }
958 $userdatetype = 'month';
959 $currentdate['month'] = $currentdate['mon'];
960 break;
961 case 'days':
962 for ($i=1; $i<=31; $i++) {
963 $timeunits[$i] = $i;
964 }
965 $userdatetype = 'mday';
966 break;
967 case 'hours':
968 for ($i=0; $i<=23; $i++) {
969 $timeunits[$i] = sprintf("%02d",$i);
970 }
971 break;
972 case 'minutes':
973 if ($step != 1) {
974 $currentdate['minutes'] = ceil($currentdate['minutes']/$step)*$step;
975 }
976
977 for ($i=0; $i<=59; $i+=$step) {
978 $timeunits[$i] = sprintf("%02d",$i);
979 }
980 break;
981 default:
982 throw new coding_exception("Time type $type is not supported by html_writer::select_time().");
983 }
984
985 if (empty($attributes['id'])) {
986 $attributes['id'] = self::random_id('ts_');
987 }
988 $timerselector = self::select($timeunits, $name, $currentdate[$userdatetype], null, array('id'=>$attributes['id']));
26acc814 989 $label = self::tag('label', get_string(substr($type, 0, -1), 'form'), array('for'=>$attributes['id'], 'class'=>'accesshide'));
f83b9b63
PS
990
991 return $label.$timerselector;
992 }
993
5be262b6
PS
994 /**
995 * Shortcut for quick making of lists
996 * @param array $items
997 * @param string $tag ul or ol
998 * @param array $attributes
999 * @return string
1000 */
1001 public static function alist(array $items, array $attributes = null, $tag = 'ul') {
1002 //note: 'list' is a reserved keyword ;-)
1003
1004 $output = '';
1005
1006 foreach ($items as $item) {
1007 $output .= html_writer::start_tag('li') . "\n";
1008 $output .= $item . "\n";
1009 $output .= html_writer::end_tag('li') . "\n";
1010 }
1011
26acc814 1012 return html_writer::tag($tag, $output, $attributes);
5be262b6
PS
1013 }
1014
6ea66ff3
PS
1015 /**
1016 * Returns hidden input fields created from url parameters.
1017 * @param moodle_url $url
1018 * @param array $exclude list of excluded parameters
1019 * @return string HTML fragment
1020 */
1021 public static function input_hidden_params(moodle_url $url, array $exclude = null) {
1022 $exclude = (array)$exclude;
1023 $params = $url->params();
1024 foreach ($exclude as $key) {
1025 unset($params[$key]);
1026 }
1027
1028 $output = '';
bde156b3 1029 foreach ($params as $key => $value) {
6ea66ff3
PS
1030 $attributes = array('type'=>'hidden', 'name'=>$key, 'value'=>$value);
1031 $output .= self::empty_tag('input', $attributes)."\n";
1032 }
1033 return $output;
1034 }
77774f6a
PS
1035
1036 /**
1037 * Generate a script tag containing the the specified code.
1038 *
1039 * @param string $js the JavaScript code
e50b4c89 1040 * @param moodle_url|string optional url of the external script, $code ignored if specified
77774f6a
PS
1041 * @return string HTML, the code wrapped in <script> tags.
1042 */
e50b4c89 1043 public static function script($jscode, $url=null) {
77774f6a 1044 if ($jscode) {
e50b4c89 1045 $attributes = array('type'=>'text/javascript');
26acc814 1046 return self::tag('script', "\n//<![CDATA[\n$jscode\n//]]>\n", $attributes) . "\n";
e50b4c89
PS
1047
1048 } else if ($url) {
1049 $attributes = array('type'=>'text/javascript', 'src'=>$url);
26acc814 1050 return self::tag('script', '', $attributes) . "\n";
a9967cf5 1051
77774f6a
PS
1052 } else {
1053 return '';
1054 }
1055 }
16be8974
DM
1056
1057 /**
1058 * Renders HTML table
1059 *
1060 * This method may modify the passed instance by adding some default properties if they are not set yet.
1061 * If this is not what you want, you should make a full clone of your data before passing them to this
1062 * method. In most cases this is not an issue at all so we do not clone by default for performance
1063 * and memory consumption reasons.
1064 *
1065 * @param html_table $table data to be rendered
1066 * @return string HTML code
1067 */
1068 public static function table(html_table $table) {
1069 // prepare table data and populate missing properties with reasonable defaults
1070 if (!empty($table->align)) {
1071 foreach ($table->align as $key => $aa) {
1072 if ($aa) {
1073 $table->align[$key] = 'text-align:'. fix_align_rtl($aa) .';'; // Fix for RTL languages
1074 } else {
1075 $table->align[$key] = null;
1076 }
1077 }
1078 }
1079 if (!empty($table->size)) {
1080 foreach ($table->size as $key => $ss) {
1081 if ($ss) {
1082 $table->size[$key] = 'width:'. $ss .';';
1083 } else {
1084 $table->size[$key] = null;
1085 }
1086 }
1087 }
1088 if (!empty($table->wrap)) {
1089 foreach ($table->wrap as $key => $ww) {
1090 if ($ww) {
1091 $table->wrap[$key] = 'white-space:nowrap;';
1092 } else {
1093 $table->wrap[$key] = '';
1094 }
1095 }
1096 }
1097 if (!empty($table->head)) {
1098 foreach ($table->head as $key => $val) {
1099 if (!isset($table->align[$key])) {
1100 $table->align[$key] = null;
1101 }
1102 if (!isset($table->size[$key])) {
1103 $table->size[$key] = null;
1104 }
1105 if (!isset($table->wrap[$key])) {
1106 $table->wrap[$key] = null;
1107 }
1108
1109 }
1110 }
1111 if (empty($table->attributes['class'])) {
1112 $table->attributes['class'] = 'generaltable';
1113 }
1114 if (!empty($table->tablealign)) {
1115 $table->attributes['class'] .= ' boxalign' . $table->tablealign;
1116 }
1117
1118 // explicitly assigned properties override those defined via $table->attributes
e126c0cc 1119 $table->attributes['class'] = trim($table->attributes['class']);
16be8974
DM
1120 $attributes = array_merge($table->attributes, array(
1121 'id' => $table->id,
1122 'width' => $table->width,
1123 'summary' => $table->summary,
1124 'cellpadding' => $table->cellpadding,
1125 'cellspacing' => $table->cellspacing,
1126 ));
1127 $output = html_writer::start_tag('table', $attributes) . "\n";
1128
1129 $countcols = 0;
1130
1131 if (!empty($table->head)) {
1132 $countcols = count($table->head);
1133 $output .= html_writer::start_tag('thead', array()) . "\n";
1134 $output .= html_writer::start_tag('tr', array()) . "\n";
1135 $keys = array_keys($table->head);
1136 $lastkey = end($keys);
1137
1138 foreach ($table->head as $key => $heading) {
1139 // Convert plain string headings into html_table_cell objects
1140 if (!($heading instanceof html_table_cell)) {
1141 $headingtext = $heading;
1142 $heading = new html_table_cell();
1143 $heading->text = $headingtext;
1144 $heading->header = true;
1145 }
1146
1147 if ($heading->header !== false) {
1148 $heading->header = true;
1149 }
1150
e126c0cc
DM
1151 if ($heading->header && empty($heading->scope)) {
1152 $heading->scope = 'col';
1153 }
1154
16be8974
DM
1155 $heading->attributes['class'] .= ' header c' . $key;
1156 if (isset($table->headspan[$key]) && $table->headspan[$key] > 1) {
1157 $heading->colspan = $table->headspan[$key];
1158 $countcols += $table->headspan[$key] - 1;
1159 }
1160
1161 if ($key == $lastkey) {
1162 $heading->attributes['class'] .= ' lastcol';
1163 }
1164 if (isset($table->colclasses[$key])) {
1165 $heading->attributes['class'] .= ' ' . $table->colclasses[$key];
1166 }
e126c0cc 1167 $heading->attributes['class'] = trim($heading->attributes['class']);
16be8974
DM
1168 $attributes = array_merge($heading->attributes, array(
1169 'style' => $table->align[$key] . $table->size[$key] . $heading->style,
1170 'scope' => $heading->scope,
1171 'colspan' => $heading->colspan,
1172 ));
1173
1174 $tagtype = 'td';
1175 if ($heading->header === true) {
1176 $tagtype = 'th';
1177 }
1178 $output .= html_writer::tag($tagtype, $heading->text, $attributes) . "\n";
1179 }
1180 $output .= html_writer::end_tag('tr') . "\n";
1181 $output .= html_writer::end_tag('thead') . "\n";
1182
1183 if (empty($table->data)) {
1184 // For valid XHTML strict every table must contain either a valid tr
1185 // or a valid tbody... both of which must contain a valid td
1186 $output .= html_writer::start_tag('tbody', array('class' => 'empty'));
1187 $output .= html_writer::tag('tr', html_writer::tag('td', '', array('colspan'=>count($table->head))));
1188 $output .= html_writer::end_tag('tbody');
1189 }
1190 }
1191
1192 if (!empty($table->data)) {
1193 $oddeven = 1;
1194 $keys = array_keys($table->data);
1195 $lastrowkey = end($keys);
1196 $output .= html_writer::start_tag('tbody', array());
1197
1198 foreach ($table->data as $key => $row) {
1199 if (($row === 'hr') && ($countcols)) {
1200 $output .= html_writer::tag('td', html_writer::tag('div', '', array('class' => 'tabledivider')), array('colspan' => $countcols));
1201 } else {
1202 // Convert array rows to html_table_rows and cell strings to html_table_cell objects
1203 if (!($row instanceof html_table_row)) {
1204 $newrow = new html_table_row();
1205
e126c0cc 1206 foreach ($row as $item) {
16be8974
DM
1207 $cell = new html_table_cell();
1208 $cell->text = $item;
1209 $newrow->cells[] = $cell;
1210 }
1211 $row = $newrow;
1212 }
1213
1214 $oddeven = $oddeven ? 0 : 1;
1215 if (isset($table->rowclasses[$key])) {
1216 $row->attributes['class'] .= ' ' . $table->rowclasses[$key];
1217 }
1218
1219 $row->attributes['class'] .= ' r' . $oddeven;
1220 if ($key == $lastrowkey) {
1221 $row->attributes['class'] .= ' lastrow';
1222 }
1223
e126c0cc 1224 $output .= html_writer::start_tag('tr', array('class' => trim($row->attributes['class']), 'style' => $row->style, 'id' => $row->id)) . "\n";
16be8974
DM
1225 $keys2 = array_keys($row->cells);
1226 $lastkey = end($keys2);
1227
1228 foreach ($row->cells as $key => $cell) {
1229 if (!($cell instanceof html_table_cell)) {
1230 $mycell = new html_table_cell();
1231 $mycell->text = $cell;
1232 $cell = $mycell;
1233 }
1234
e126c0cc
DM
1235 if (($cell->header === true) && empty($cell->scope)) {
1236 $cell->scope = 'row';
1237 }
1238
16be8974
DM
1239 if (isset($table->colclasses[$key])) {
1240 $cell->attributes['class'] .= ' ' . $table->colclasses[$key];
1241 }
1242
1243 $cell->attributes['class'] .= ' cell c' . $key;
1244 if ($key == $lastkey) {
1245 $cell->attributes['class'] .= ' lastcol';
1246 }
1247 $tdstyle = '';
1248 $tdstyle .= isset($table->align[$key]) ? $table->align[$key] : '';
1249 $tdstyle .= isset($table->size[$key]) ? $table->size[$key] : '';
1250 $tdstyle .= isset($table->wrap[$key]) ? $table->wrap[$key] : '';
e126c0cc 1251 $cell->attributes['class'] = trim($cell->attributes['class']);
16be8974
DM
1252 $tdattributes = array_merge($cell->attributes, array(
1253 'style' => $tdstyle . $cell->style,
1254 'colspan' => $cell->colspan,
1255 'rowspan' => $cell->rowspan,
1256 'id' => $cell->id,
1257 'abbr' => $cell->abbr,
1258 'scope' => $cell->scope,
1259 ));
1260 $tagtype = 'td';
1261 if ($cell->header === true) {
1262 $tagtype = 'th';
1263 }
1264 $output .= html_writer::tag($tagtype, $cell->text, $tdattributes) . "\n";
1265 }
1266 }
1267 $output .= html_writer::end_tag('tr') . "\n";
1268 }
1269 $output .= html_writer::end_tag('tbody') . "\n";
1270 }
1271 $output .= html_writer::end_tag('table') . "\n";
1272
1273 return $output;
1274 }
1275
5d0c95a5
PS
1276}
1277
227255b8
PS
1278// ==== JS writer and helper classes, will be probably moved elsewhere ======
1279
1280/**
1281 * Simple javascript output class
1282 * @copyright 2010 Petr Skoda
1283 */
1284class js_writer {
1285 /**
1286 * Returns javascript code calling the function
1287 * @param string $function function name, can be complex lin Y.Event.purgeElement
1288 * @param array $arguments parameters
1289 * @param int $delay execution delay in seconds
1290 * @return string JS code fragment
1291 */
1292 public function function_call($function, array $arguments = null, $delay=0) {
1b4e41af
PS
1293 if ($arguments) {
1294 $arguments = array_map('json_encode', $arguments);
1295 $arguments = implode(', ', $arguments);
1296 } else {
1297 $arguments = '';
1298 }
227255b8
PS
1299 $js = "$function($arguments);";
1300
1301 if ($delay) {
1302 $delay = $delay * 1000; // in miliseconds
1303 $js = "setTimeout(function() { $js }, $delay);";
1304 }
1305 return $js . "\n";
1306 }
1307
3b01539c
PS
1308 /**
1309 * Special function which adds Y as first argument of fucntion call.
1310 * @param string $function
1311 * @param array $extraarguments
1312 * @return string
1313 */
1314 public function function_call_with_Y($function, array $extraarguments = null) {
1315 if ($extraarguments) {
1316 $extraarguments = array_map('json_encode', $extraarguments);
1317 $arguments = 'Y, ' . implode(', ', $extraarguments);
1318 } else {
1319 $arguments = 'Y';
1320 }
1321 return "$function($arguments);\n";
1322 }
1323
1ce15fda
SH
1324 /**
1325 * Returns JavaScript code to initialise a new object
1326 * @param string|null $var If it is null then no var is assigned the new object
1327 * @param string $class
1328 * @param array $arguments
1329 * @param array $requirements
1330 * @param int $delay
1331 * @return string
1332 */
1333 public function object_init($var, $class, array $arguments = null, array $requirements = null, $delay=0) {
1334 if (is_array($arguments)) {
1335 $arguments = array_map('json_encode', $arguments);
1336 $arguments = implode(', ', $arguments);
1337 }
1338
1339 if ($var === null) {
53fc3e70 1340 $js = "new $class(Y, $arguments);";
1ce15fda 1341 } else if (strpos($var, '.')!==false) {
53fc3e70 1342 $js = "$var = new $class(Y, $arguments);";
1ce15fda 1343 } else {
53fc3e70 1344 $js = "var $var = new $class(Y, $arguments);";
1ce15fda
SH
1345 }
1346
1347 if ($delay) {
1348 $delay = $delay * 1000; // in miliseconds
1349 $js = "setTimeout(function() { $js }, $delay);";
1350 }
1351
1352 if (count($requirements) > 0) {
1353 $requirements = implode("', '", $requirements);
53fc3e70 1354 $js = "Y.use('$requirements', function(Y){ $js });";
1ce15fda
SH
1355 }
1356 return $js."\n";
1357 }
1358
227255b8
PS
1359 /**
1360 * Returns code setting value to variable
1361 * @param string $name
1362 * @param mixed $value json serialised value
1363 * @param bool $usevar add var definition, ignored for nested properties
1364 * @return string JS code fragment
1365 */
1366 public function set_variable($name, $value, $usevar=true) {
1367 $output = '';
1368
1369 if ($usevar) {
1370 if (strpos($name, '.')) {
1371 $output .= '';
1372 } else {
1373 $output .= 'var ';
1374 }
1375 }
1376
1377 $output .= "$name = ".json_encode($value).";";
1378
1379 return $output;
1380 }
1381
1382 /**
1383 * Writes event handler attaching code
1384 * @param mixed $selector standard YUI selector for elemnts, may be array or string, element id is in the form "#idvalue"
1385 * @param string $event A valid DOM event (click, mousedown, change etc.)
1386 * @param string $function The name of the function to call
1387 * @param array $arguments An optional array of argument parameters to pass to the function
1388 * @return string JS code fragment
1389 */
1390 public function event_handler($selector, $event, $function, array $arguments = null) {
1391 $selector = json_encode($selector);
1392 $output = "Y.on('$event', $function, $selector, null";
1393 if (!empty($arguments)) {
1394 $output .= ', ' . json_encode($arguments);
1395 }
1396 return $output . ");\n";
1397 }
1398}
1399
d9c8f425 1400/**
16be8974 1401 * Holds all the information required to render a <table> by {@see core_renderer::table()}
d9c8f425 1402 *
16be8974
DM
1403 * Example of usage:
1404 * $t = new html_table();
1405 * ... // set various properties of the object $t as described below
1406 * echo html_writer::table($t);
d9c8f425 1407 *
16be8974 1408 * @copyright 2009 David Mudrak <david.mudrak@gmail.com>
d9c8f425 1409 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1410 * @since Moodle 2.0
1411 */
16be8974 1412class html_table {
d9c8f425 1413 /**
16be8974 1414 * @var string value to use for the id attribute of the table
d9c8f425 1415 */
97c10099 1416 public $id = null;
d9c8f425 1417 /**
16be8974 1418 * @var array attributes of HTML attributes for the <table> element
d9c8f425 1419 */
16be8974 1420 public $attributes = array();
7b1f2c82 1421 /**
a0ead5eb 1422 * For more control over the rendering of the headers, an array of html_table_cell objects
54a007e8 1423 * can be passed instead of an array of strings.
7b1f2c82 1424 * @var array of headings. The n-th array item is used as a heading of the n-th column.
1425 *
1426 * Example of usage:
1427 * $t->head = array('Student', 'Grade');
1428 */
1429 public $head;
1430 /**
1431 * @var array can be used to make a heading span multiple columns
1432 *
1433 * Example of usage:
1434 * $t->headspan = array(2,1);
1435 *
1436 * In this example, {@see html_table:$data} is supposed to have three columns. For the first two columns,
1437 * the same heading is used. Therefore, {@see html_table::$head} should consist of two items.
1438 */
1439 public $headspan;
1440 /**
1441 * @var array of column alignments. The value is used as CSS 'text-align' property. Therefore, possible
1442 * values are 'left', 'right', 'center' and 'justify'. Specify 'right' or 'left' from the perspective
1443 * of a left-to-right (LTR) language. For RTL, the values are flipped automatically.
1444 *
beb56299 1445 * Examples of usage:
1446 * $t->align = array(null, 'right');
1447 * or
1448 * $t->align[1] = 'right';
1449 *
d9c8f425 1450 */
beb56299 1451 public $align;
d9c8f425 1452 /**
beb56299 1453 * @var array of column sizes. The value is used as CSS 'size' property.
1454 *
1455 * Examples of usage:
1456 * $t->size = array('50%', '50%');
1457 * or
1458 * $t->size[1] = '120px';
d9c8f425 1459 */
beb56299 1460 public $size;
d9c8f425 1461 /**
beb56299 1462 * @var array of wrapping information. The only possible value is 'nowrap' that sets the
1463 * CSS property 'white-space' to the value 'nowrap' in the given column.
1464 *
1465 * Example of usage:
1466 * $t->wrap = array(null, 'nowrap');
d9c8f425 1467 */
beb56299 1468 public $wrap;
d9c8f425 1469 /**
beb56299 1470 * @var array of arrays or html_table_row objects containing the data. Alternatively, if you have
1471 * $head specified, the string 'hr' (for horizontal ruler) can be used
1472 * instead of an array of cells data resulting in a divider rendered.
d9c8f425 1473 *
beb56299 1474 * Example of usage with array of arrays:
1475 * $row1 = array('Harry Potter', '76 %');
1476 * $row2 = array('Hermione Granger', '100 %');
1477 * $t->data = array($row1, $row2);
d9c8f425 1478 *
beb56299 1479 * Example with array of html_table_row objects: (used for more fine-grained control)
1480 * $cell1 = new html_table_cell();
1481 * $cell1->text = 'Harry Potter';
1482 * $cell1->colspan = 2;
1483 * $row1 = new html_table_row();
1484 * $row1->cells[] = $cell1;
1485 * $cell2 = new html_table_cell();
1486 * $cell2->text = 'Hermione Granger';
1487 * $cell3 = new html_table_cell();
1488 * $cell3->text = '100 %';
1489 * $row2 = new html_table_row();
1490 * $row2->cells = array($cell2, $cell3);
1491 * $t->data = array($row1, $row2);
1492 */
1493 public $data;
1494 /**
16be8974 1495 * @var string width of the table, percentage of the page preferred. Defaults to 80%
beb56299 1496 * @deprecated since Moodle 2.0. Styling should be in the CSS.
1497 */
1498 public $width = null;
1499 /**
1500 * @var string alignment the whole table. Can be 'right', 'left' or 'center' (default).
1501 * @deprecated since Moodle 2.0. Styling should be in the CSS.
1502 */
1503 public $tablealign = null;
1504 /**
1505 * @var int padding on each cell, in pixels
1506 * @deprecated since Moodle 2.0. Styling should be in the CSS.
1507 */
1508 public $cellpadding = null;
1509 /**
1510 * @var int spacing between cells, in pixels
1511 * @deprecated since Moodle 2.0. Styling should be in the CSS.
1512 */
1513 public $cellspacing = null;
1514 /**
1515 * @var array classes to add to particular rows, space-separated string.
1516 * Classes 'r0' or 'r1' are added automatically for every odd or even row,
1517 * respectively. Class 'lastrow' is added automatically for the last row
1518 * in the table.
d9c8f425 1519 *
beb56299 1520 * Example of usage:
1521 * $t->rowclasses[9] = 'tenth'
1522 */
1523 public $rowclasses;
1524 /**
1525 * @var array classes to add to every cell in a particular column,
1526 * space-separated string. Class 'cell' is added automatically by the renderer.
1527 * Classes 'c0' or 'c1' are added automatically for every odd or even column,
1528 * respectively. Class 'lastcol' is added automatically for all last cells
1529 * in a row.
d9c8f425 1530 *
beb56299 1531 * Example of usage:
1532 * $t->colclasses = array(null, 'grade');
d9c8f425 1533 */
beb56299 1534 public $colclasses;
1535 /**
1536 * @var string description of the contents for screen readers.
1537 */
1538 public $summary;
d9c8f425 1539
1540 /**
16be8974 1541 * Constructor
d9c8f425 1542 */
16be8974
DM
1543 public function __construct() {
1544 $this->attributes['class'] = '';
d9c8f425 1545 }
d9c8f425 1546}
1547
34059565 1548
d9c8f425 1549/**
7b1f2c82 1550 * Component representing a table row.
d9c8f425 1551 *
1552 * @copyright 2009 Nicolas Connault
1553 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1554 * @since Moodle 2.0
1555 */
16be8974
DM
1556class html_table_row {
1557 /**
1558 * @var string value to use for the id attribute of the row
1559 */
1560 public $id = null;
d9c8f425 1561 /**
7b1f2c82 1562 * @var array $cells Array of html_table_cell objects
d9c8f425 1563 */
7b1f2c82 1564 public $cells = array();
beb56299 1565 /**
16be8974 1566 * @var string $style value to use for the style attribute of the table row
beb56299 1567 */
16be8974
DM
1568 public $style = null;
1569 /**
1570 * @var array attributes of additional HTML attributes for the <tr> element
1571 */
1572 public $attributes = array();
a0ead5eb 1573
54a007e8 1574 /**
8cea545e 1575 * Constructor
54a007e8 1576 * @param array $cells
8cea545e
PS
1577 */
1578 public function __construct(array $cells=null) {
16be8974 1579 $this->attributes['class'] = '';
8cea545e
PS
1580 $cells = (array)$cells;
1581 foreach ($cells as $cell) {
1582 if ($cell instanceof html_table_cell) {
1583 $this->cells[] = $cell;
a019627a 1584 } else {
8cea545e 1585 $this->cells[] = new html_table_cell($cell);
a019627a 1586 }
1587 }
54a007e8 1588 }
d9c8f425 1589}
1590
34059565 1591
d9c8f425 1592/**
7b1f2c82 1593 * Component representing a table cell.
d9c8f425 1594 *
1595 * @copyright 2009 Nicolas Connault
1596 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1597 * @since Moodle 2.0
1598 */
16be8974
DM
1599class html_table_cell {
1600 /**
1601 * @var string value to use for the id attribute of the cell
1602 */
1603 public $id = null;
d9c8f425 1604 /**
7b1f2c82 1605 * @var string $text The contents of the cell
d9c8f425 1606 */
7b1f2c82 1607 public $text;
d9c8f425 1608 /**
7b1f2c82 1609 * @var string $abbr Abbreviated version of the contents of the cell
d9c8f425 1610 */
97c10099 1611 public $abbr = null;
d9c8f425 1612 /**
7b1f2c82 1613 * @var int $colspan Number of columns this cell should span
d9c8f425 1614 */
97c10099 1615 public $colspan = null;
d9c8f425 1616 /**
7b1f2c82 1617 * @var int $rowspan Number of rows this cell should span
d9c8f425 1618 */
97c10099 1619 public $rowspan = null;
d9c8f425 1620 /**
7b1f2c82 1621 * @var string $scope Defines a way to associate header cells and data cells in a table
d9c8f425 1622 */
97c10099 1623 public $scope = null;
1ae3767a 1624 /**
1625 * @var boolean $header Whether or not this cell is a header cell
1626 */
a4998d01 1627 public $header = null;
16be8974
DM
1628 /**
1629 * @var string $style value to use for the style attribute of the table cell
1630 */
1631 public $style = null;
1632 /**
1633 * @var array attributes of additional HTML attributes for the <tr> element
1634 */
1635 public $attributes = array();
d9c8f425 1636
8cea545e
PS
1637 public function __construct($text = null) {
1638 $this->text = $text;
16be8974 1639 $this->attributes['class'] = '';
d9c8f425 1640 }
1641}
1642
34059565 1643
7b1f2c82 1644/// Complex components aggregating simpler components
1645
34059565 1646
d9c8f425 1647/**
beb56299 1648 * Component representing a paging bar.
d9c8f425 1649 *
1650 * @copyright 2009 Nicolas Connault
1651 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1652 * @since Moodle 2.0
1653 */
929d7a83 1654class paging_bar implements renderable {
d9c8f425 1655 /**
beb56299 1656 * @var int $maxdisplay The maximum number of pagelinks to display
d9c8f425 1657 */
beb56299 1658 public $maxdisplay = 18;
d9c8f425 1659 /**
beb56299 1660 * @var int $totalcount post or get
d9c8f425 1661 */
beb56299 1662 public $totalcount;
d9c8f425 1663 /**
beb56299 1664 * @var int $page The page you are currently viewing
d9c8f425 1665 */
929d7a83 1666 public $page;
d9c8f425 1667 /**
beb56299 1668 * @var int $perpage The number of entries that should be shown per page
d9c8f425 1669 */
beb56299 1670 public $perpage;
d9c8f425 1671 /**
beb56299 1672 * @var string $baseurl If this is a string then it is the url which will be appended with $pagevar, an equals sign and the page number.
1673 * If this is a moodle_url object then the pagevar param will be replaced by the page no, for each page.
d9c8f425 1674 */
beb56299 1675 public $baseurl;
d9c8f425 1676 /**
beb56299 1677 * @var string $pagevar This is the variable name that you use for the page number in your code (ie. 'tablepage', 'blogpage', etc)
d9c8f425 1678 */
929d7a83 1679 public $pagevar;
beb56299 1680 /**
56ddb719 1681 * @var string $previouslink A HTML link representing the "previous" page
beb56299 1682 */
1683 public $previouslink = null;
1684 /**
56ddb719 1685 * @var tring $nextlink A HTML link representing the "next" page
beb56299 1686 */
1687 public $nextlink = null;
1688 /**
56ddb719 1689 * @var tring $firstlink A HTML link representing the first page
beb56299 1690 */
1691 public $firstlink = null;
1692 /**
56ddb719 1693 * @var tring $lastlink A HTML link representing the last page
beb56299 1694 */
1695 public $lastlink = null;
1696 /**
56ddb719 1697 * @var array $pagelinks An array of strings. One of them is just a string: the current page
beb56299 1698 */
1699 public $pagelinks = array();
d9c8f425 1700
929d7a83
PS
1701 /**
1702 * Constructor paging_bar with only the required params.
1703 *
1704 * @param int $totalcount Thetotal number of entries available to be paged through
1705 * @param int $page The page you are currently viewing
1706 * @param int $perpage The number of entries that should be shown per page
1707 * @param string|moodle_url $baseurl url of the current page, the $pagevar parameter is added
1708 * @param string $pagevar name of page parameter that holds the page number
1709 */
1710 public function __construct($totalcount, $page, $perpage, $baseurl, $pagevar = 'page') {
1711 $this->totalcount = $totalcount;
1712 $this->page = $page;
1713 $this->perpage = $perpage;
1714 $this->baseurl = $baseurl;
1715 $this->pagevar = $pagevar;
1716 }
1717
d9c8f425 1718 /**
d9c8f425 1719 * @return void
1720 */
34059565 1721 public function prepare(renderer_base $output, moodle_page $page, $target) {
1c1f64a2 1722 if (!isset($this->totalcount) || is_null($this->totalcount)) {
929d7a83 1723 throw new coding_exception('paging_bar requires a totalcount value.');
beb56299 1724 }
1725 if (!isset($this->page) || is_null($this->page)) {
929d7a83 1726 throw new coding_exception('paging_bar requires a page value.');
beb56299 1727 }
1728 if (empty($this->perpage)) {
929d7a83 1729 throw new coding_exception('paging_bar requires a perpage value.');
beb56299 1730 }
1731 if (empty($this->baseurl)) {
929d7a83 1732 throw new coding_exception('paging_bar requires a baseurl value.');
beb56299 1733 }
d9c8f425 1734
beb56299 1735 if ($this->totalcount > $this->perpage) {
1736 $pagenum = $this->page - 1;
d9c8f425 1737
beb56299 1738 if ($this->page > 0) {
929d7a83 1739 $this->previouslink = html_writer::link(new moodle_url($this->baseurl, array($this->pagevar=>$pagenum)), get_string('previous'), array('class'=>'previous'));
beb56299 1740 }
d9c8f425 1741
beb56299 1742 if ($this->perpage > 0) {
1743 $lastpage = ceil($this->totalcount / $this->perpage);
1744 } else {
1745 $lastpage = 1;
1746 }
1747
1748 if ($this->page > 15) {
1749 $startpage = $this->page - 10;
1750
929d7a83 1751 $this->firstlink = html_writer::link(new moodle_url($this->baseurl, array($this->pagevar=>0)), '1', array('class'=>'first'));
beb56299 1752 } else {
1753 $startpage = 0;
1754 }
1755
1756 $currpage = $startpage;
1757 $displaycount = $displaypage = 0;
1758
1759 while ($displaycount < $this->maxdisplay and $currpage < $lastpage) {
1760 $displaypage = $currpage + 1;
1761
f43cdceb 1762 if ($this->page == $currpage) {
beb56299 1763 $this->pagelinks[] = $displaypage;
1764 } else {
56ddb719 1765 $pagelink = html_writer::link(new moodle_url($this->baseurl, array($this->pagevar=>$currpage)), $displaypage);
beb56299 1766 $this->pagelinks[] = $pagelink;
1767 }
1768
1769 $displaycount++;
1770 $currpage++;
1771 }
1772
1773 if ($currpage < $lastpage) {
1774 $lastpageactual = $lastpage - 1;
abdac127 1775 $this->lastlink = html_writer::link(new moodle_url($this->baseurl, array($this->pagevar=>$lastpageactual)), $lastpage, array('class'=>'last'));
beb56299 1776 }
1777
1778 $pagenum = $this->page + 1;
1779
1780 if ($pagenum != $displaypage) {
abdac127 1781 $this->nextlink = html_writer::link(new moodle_url($this->baseurl, array($this->pagevar=>$pagenum)), get_string('next'), array('class'=>'next'));
beb56299 1782 }
d9c8f425 1783 }
1784 }
d9c8f425 1785}
1786
34059565 1787
d9c8f425 1788/**
beb56299 1789 * This class represents how a block appears on a page.
d9c8f425 1790 *
beb56299 1791 * During output, each block instance is asked to return a block_contents object,
1792 * those are then passed to the $OUTPUT->block function for display.
1793 *
1794 * {@link $contents} should probably be generated using a moodle_block_..._renderer.
1795 *
1796 * Other block-like things that need to appear on the page, for example the
1797 * add new block UI, are also represented as block_contents objects.
1798 *
1799 * @copyright 2009 Tim Hunt
d9c8f425 1800 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1801 * @since Moodle 2.0
1802 */
dd72b308 1803class block_contents {
beb56299 1804 /** @var int used to set $skipid. */
1805 protected static $idcounter = 1;
1806
1807 const NOT_HIDEABLE = 0;
1808 const VISIBLE = 1;
1809 const HIDDEN = 2;
1810
d9c8f425 1811 /**
dd72b308 1812 * @var integer $skipid All the blocks (or things that look like blocks)
beb56299 1813 * printed on a page are given a unique number that can be used to construct
1814 * id="" attributes. This is set automatically be the {@link prepare()} method.
1815 * Do not try to set it manually.
d9c8f425 1816 */
beb56299 1817 public $skipid;
d9c8f425 1818
1819 /**
beb56299 1820 * @var integer If this is the contents of a real block, this should be set to
1821 * the block_instance.id. Otherwise this should be set to 0.
1822 */
1823 public $blockinstanceid = 0;
1824
1825 /**
1826 * @var integer if this is a real block instance, and there is a corresponding
1827 * block_position.id for the block on this page, this should be set to that id.
1828 * Otherwise it should be 0.
1829 */
1830 public $blockpositionid = 0;
1831
1832 /**
1833 * @param array $attributes an array of attribute => value pairs that are put on the
1834 * outer div of this block. {@link $id} and {@link $classes} attributes should be set separately.
1835 */
dd72b308 1836 public $attributes;
beb56299 1837
1838 /**
1839 * @param string $title The title of this block. If this came from user input,
1840 * it should already have had format_string() processing done on it. This will
1841 * be output inside <h2> tags. Please do not cause invalid XHTML.
1842 */
1843 public $title = '';
1844
1845 /**
1846 * @param string $content HTML for the content
1847 */
1848 public $content = '';
1849
1850 /**
1851 * @param array $list an alternative to $content, it you want a list of things with optional icons.
1852 */
1853 public $footer = '';
1854
1855 /**
1856 * Any small print that should appear under the block to explain to the
1857 * teacher about the block, for example 'This is a sticky block that was
1858 * added in the system context.'
1859 * @var string
1860 */
1861 public $annotation = '';
1862
1863 /**
1864 * @var integer one of the constants NOT_HIDEABLE, VISIBLE, HIDDEN. Whether
1865 * the user can toggle whether this block is visible.
1866 */
1867 public $collapsible = self::NOT_HIDEABLE;
1868
1869 /**
1870 * A (possibly empty) array of editing controls. Each element of this array
1871 * should be an array('url' => $url, 'icon' => $icon, 'caption' => $caption).
b5d0cafc 1872 * $icon is the icon name. Fed to $OUTPUT->pix_url.
beb56299 1873 * @var array
1874 */
1875 public $controls = array();
1876
dd72b308 1877
beb56299 1878 /**
dd72b308
PS
1879 * Create new instance of block content
1880 * @param array $attributes
d9c8f425 1881 */
dd72b308 1882 public function __construct(array $attributes=null) {
beb56299 1883 $this->skipid = self::$idcounter;
1884 self::$idcounter += 1;
dd72b308
PS
1885
1886 if ($attributes) {
1887 // standard block
1888 $this->attributes = $attributes;
1889 } else {
1890 // simple "fake" blocks used in some modules and "Add new block" block
6605ff8c 1891 $this->attributes = array('class'=>'block');
beb56299 1892 }
dd72b308
PS
1893 }
1894
1895 /**
1896 * Add html class to block
1897 * @param string $class
1898 * @return void
1899 */
1900 public function add_class($class) {
1901 $this->attributes['class'] .= ' '.$class;
d9c8f425 1902 }
1903}
beb56299 1904
34059565 1905
beb56299 1906/**
1907 * This class represents a target for where a block can go when it is being moved.
1908 *
1909 * This needs to be rendered as a form with the given hidden from fields, and
1910 * clicking anywhere in the form should submit it. The form action should be
1911 * $PAGE->url.
1912 *
1913 * @copyright 2009 Tim Hunt
1914 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1915 * @since Moodle 2.0
1916 */
dd72b308 1917class block_move_target {
beb56299 1918 /**
dd72b308
PS
1919 * Move url
1920 * @var moodle_url
beb56299 1921 */
dd72b308 1922 public $url;
beb56299 1923 /**
dd72b308
PS
1924 * label
1925 * @var string
beb56299 1926 */
dd72b308
PS
1927 public $text;
1928
1929 /**
1930 * Cosntructor
1931 * @param string $text
1932 * @param moodle_url $url
1933 */
1934 public function __construct($text, moodle_url $url) {
1935 $this->text = $text;
1936 $this->url = $url;
1937 }
beb56299 1938}