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