[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Classes representing HTML elements, used by $OUTPUT methods 19 * 20 * Please see http://docs.moodle.org/en/Developement:How_Moodle_outputs_HTML 21 * for an overview. 22 * 23 * @package core 24 * @category output 25 * @copyright 2009 Tim Hunt 26 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 27 */ 28 29 defined('MOODLE_INTERNAL') || die(); 30 31 /** 32 * Interface marking other classes as suitable for renderer_base::render() 33 * 34 * @copyright 2010 Petr Skoda (skodak) info@skodak.org 35 * @package core 36 * @category output 37 */ 38 interface renderable { 39 // intentionally empty 40 } 41 42 /** 43 * Interface marking other classes having the ability to export their data for use by templates. 44 * 45 * @copyright 2015 Damyon Wiese 46 * @package core 47 * @category output 48 * @since 2.9 49 */ 50 interface templatable { 51 52 /** 53 * Function to export the renderer data in a format that is suitable for a 54 * mustache template. This means: 55 * 1. No complex types - only stdClass, array, int, string, float, bool 56 * 2. Any additional info that is required for the template is pre-calculated (e.g. capability checks). 57 * 58 * @param renderer_base $output Used to do a final render of any components that need to be rendered for export. 59 * @return stdClass|array 60 */ 61 public function export_for_template(renderer_base $output); 62 } 63 64 /** 65 * Data structure representing a file picker. 66 * 67 * @copyright 2010 Dongsheng Cai 68 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 69 * @since Moodle 2.0 70 * @package core 71 * @category output 72 */ 73 class file_picker implements renderable { 74 75 /** 76 * @var stdClass An object containing options for the file picker 77 */ 78 public $options; 79 80 /** 81 * Constructs a file picker object. 82 * 83 * The following are possible options for the filepicker: 84 * - accepted_types (*) 85 * - return_types (FILE_INTERNAL) 86 * - env (filepicker) 87 * - client_id (uniqid) 88 * - itemid (0) 89 * - maxbytes (-1) 90 * - maxfiles (1) 91 * - buttonname (false) 92 * 93 * @param stdClass $options An object containing options for the file picker. 94 */ 95 public function __construct(stdClass $options) { 96 global $CFG, $USER, $PAGE; 97 require_once($CFG->dirroot. '/repository/lib.php'); 98 $defaults = array( 99 'accepted_types'=>'*', 100 'return_types'=>FILE_INTERNAL, 101 'env' => 'filepicker', 102 'client_id' => uniqid(), 103 'itemid' => 0, 104 'maxbytes'=>-1, 105 'maxfiles'=>1, 106 'buttonname'=>false 107 ); 108 foreach ($defaults as $key=>$value) { 109 if (empty($options->$key)) { 110 $options->$key = $value; 111 } 112 } 113 114 $options->currentfile = ''; 115 if (!empty($options->itemid)) { 116 $fs = get_file_storage(); 117 $usercontext = context_user::instance($USER->id); 118 if (empty($options->filename)) { 119 if ($files = $fs->get_area_files($usercontext->id, 'user', 'draft', $options->itemid, 'id DESC', false)) { 120 $file = reset($files); 121 } 122 } else { 123 $file = $fs->get_file($usercontext->id, 'user', 'draft', $options->itemid, $options->filepath, $options->filename); 124 } 125 if (!empty($file)) { 126 $options->currentfile = html_writer::link(moodle_url::make_draftfile_url($file->get_itemid(), $file->get_filepath(), $file->get_filename()), $file->get_filename()); 127 } 128 } 129 130 // initilise options, getting files in root path 131 $this->options = initialise_filepicker($options); 132 133 // copying other options 134 foreach ($options as $name=>$value) { 135 if (!isset($this->options->$name)) { 136 $this->options->$name = $value; 137 } 138 } 139 } 140 } 141 142 /** 143 * Data structure representing a user picture. 144 * 145 * @copyright 2009 Nicolas Connault, 2010 Petr Skoda 146 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 147 * @since Modle 2.0 148 * @package core 149 * @category output 150 */ 151 class user_picture implements renderable { 152 /** 153 * @var array List of mandatory fields in user record here. (do not include 154 * TEXT columns because it would break SELECT DISTINCT in MSSQL and ORACLE) 155 */ 156 protected static $fields = array('id', 'picture', 'firstname', 'lastname', 'firstnamephonetic', 'lastnamephonetic', 157 'middlename', 'alternatename', 'imagealt', 'email'); 158 159 /** 160 * @var stdClass A user object with at least fields all columns specified 161 * in $fields array constant set. 162 */ 163 public $user; 164 165 /** 166 * @var int The course id. Used when constructing the link to the user's 167 * profile, page course id used if not specified. 168 */ 169 public $courseid; 170 171 /** 172 * @var bool Add course profile link to image 173 */ 174 public $link = true; 175 176 /** 177 * @var int Size in pixels. Special values are (true/1 = 100px) and 178 * (false/0 = 35px) 179 * for backward compatibility. 180 */ 181 public $size = 35; 182 183 /** 184 * @var bool Add non-blank alt-text to the image. 185 * Default true, set to false when image alt just duplicates text in screenreaders. 186 */ 187 public $alttext = true; 188 189 /** 190 * @var bool Whether or not to open the link in a popup window. 191 */ 192 public $popup = false; 193 194 /** 195 * @var string Image class attribute 196 */ 197 public $class = 'userpicture'; 198 199 /** 200 * @var bool Whether to be visible to screen readers. 201 */ 202 public $visibletoscreenreaders = true; 203 204 /** 205 * User picture constructor. 206 * 207 * @param stdClass $user user record with at least id, picture, imagealt, firstname and lastname set. 208 * It is recommended to add also contextid of the user for performance reasons. 209 */ 210 public function __construct(stdClass $user) { 211 global $DB; 212 213 if (empty($user->id)) { 214 throw new coding_exception('User id is required when printing user avatar image.'); 215 } 216 217 // only touch the DB if we are missing data and complain loudly... 218 $needrec = false; 219 foreach (self::$fields as $field) { 220 if (!array_key_exists($field, $user)) { 221 $needrec = true; 222 debugging('Missing '.$field.' property in $user object, this is a performance problem that needs to be fixed by a developer. ' 223 .'Please use user_picture::fields() to get the full list of required fields.', DEBUG_DEVELOPER); 224 break; 225 } 226 } 227 228 if ($needrec) { 229 $this->user = $DB->get_record('user', array('id'=>$user->id), self::fields(), MUST_EXIST); 230 } else { 231 $this->user = clone($user); 232 } 233 } 234 235 /** 236 * Returns a list of required user fields, useful when fetching required user info from db. 237 * 238 * In some cases we have to fetch the user data together with some other information, 239 * the idalias is useful there because the id would otherwise override the main 240 * id of the result record. Please note it has to be converted back to id before rendering. 241 * 242 * @param string $tableprefix name of database table prefix in query 243 * @param array $extrafields extra fields to be included in result (do not include TEXT columns because it would break SELECT DISTINCT in MSSQL and ORACLE) 244 * @param string $idalias alias of id field 245 * @param string $fieldprefix prefix to add to all columns in their aliases, does not apply to 'id' 246 * @return string 247 */ 248 public static function fields($tableprefix = '', array $extrafields = NULL, $idalias = 'id', $fieldprefix = '') { 249 if (!$tableprefix and !$extrafields and !$idalias) { 250 return implode(',', self::$fields); 251 } 252 if ($tableprefix) { 253 $tableprefix .= '.'; 254 } 255 foreach (self::$fields as $field) { 256 if ($field === 'id' and $idalias and $idalias !== 'id') { 257 $fields[$field] = "$tableprefix$field AS $idalias"; 258 } else { 259 if ($fieldprefix and $field !== 'id') { 260 $fields[$field] = "$tableprefix$field AS $fieldprefix$field"; 261 } else { 262 $fields[$field] = "$tableprefix$field"; 263 } 264 } 265 } 266 // add extra fields if not already there 267 if ($extrafields) { 268 foreach ($extrafields as $e) { 269 if ($e === 'id' or isset($fields[$e])) { 270 continue; 271 } 272 if ($fieldprefix) { 273 $fields[$e] = "$tableprefix$e AS $fieldprefix$e"; 274 } else { 275 $fields[$e] = "$tableprefix$e"; 276 } 277 } 278 } 279 return implode(',', $fields); 280 } 281 282 /** 283 * Extract the aliased user fields from a given record 284 * 285 * Given a record that was previously obtained using {@link self::fields()} with aliases, 286 * this method extracts user related unaliased fields. 287 * 288 * @param stdClass $record containing user picture fields 289 * @param array $extrafields extra fields included in the $record 290 * @param string $idalias alias of the id field 291 * @param string $fieldprefix prefix added to all columns in their aliases, does not apply to 'id' 292 * @return stdClass object with unaliased user fields 293 */ 294 public static function unalias(stdClass $record, array $extrafields = null, $idalias = 'id', $fieldprefix = '') { 295 296 if (empty($idalias)) { 297 $idalias = 'id'; 298 } 299 300 $return = new stdClass(); 301 302 foreach (self::$fields as $field) { 303 if ($field === 'id') { 304 if (property_exists($record, $idalias)) { 305 $return->id = $record->{$idalias}; 306 } 307 } else { 308 if (property_exists($record, $fieldprefix.$field)) { 309 $return->{$field} = $record->{$fieldprefix.$field}; 310 } 311 } 312 } 313 // add extra fields if not already there 314 if ($extrafields) { 315 foreach ($extrafields as $e) { 316 if ($e === 'id' or property_exists($return, $e)) { 317 continue; 318 } 319 $return->{$e} = $record->{$fieldprefix.$e}; 320 } 321 } 322 323 return $return; 324 } 325 326 /** 327 * Works out the URL for the users picture. 328 * 329 * This method is recommended as it avoids costly redirects of user pictures 330 * if requests are made for non-existent files etc. 331 * 332 * @param moodle_page $page 333 * @param renderer_base $renderer 334 * @return moodle_url 335 */ 336 public function get_url(moodle_page $page, renderer_base $renderer = null) { 337 global $CFG; 338 339 if (is_null($renderer)) { 340 $renderer = $page->get_renderer('core'); 341 } 342 343 // Sort out the filename and size. Size is only required for the gravatar 344 // implementation presently. 345 if (empty($this->size)) { 346 $filename = 'f2'; 347 $size = 35; 348 } else if ($this->size === true or $this->size == 1) { 349 $filename = 'f1'; 350 $size = 100; 351 } else if ($this->size > 100) { 352 $filename = 'f3'; 353 $size = (int)$this->size; 354 } else if ($this->size >= 50) { 355 $filename = 'f1'; 356 $size = (int)$this->size; 357 } else { 358 $filename = 'f2'; 359 $size = (int)$this->size; 360 } 361 362 $defaulturl = $renderer->pix_url('u/'.$filename); // default image 363 364 if ((!empty($CFG->forcelogin) and !isloggedin()) || 365 (!empty($CFG->forceloginforprofileimage) && (!isloggedin() || isguestuser()))) { 366 // Protect images if login required and not logged in; 367 // also if login is required for profile images and is not logged in or guest 368 // do not use require_login() because it is expensive and not suitable here anyway. 369 return $defaulturl; 370 } 371 372 // First try to detect deleted users - but do not read from database for performance reasons! 373 if (!empty($this->user->deleted) or strpos($this->user->email, '@') === false) { 374 // All deleted users should have email replaced by md5 hash, 375 // all active users are expected to have valid email. 376 return $defaulturl; 377 } 378 379 // Did the user upload a picture? 380 if ($this->user->picture > 0) { 381 if (!empty($this->user->contextid)) { 382 $contextid = $this->user->contextid; 383 } else { 384 $context = context_user::instance($this->user->id, IGNORE_MISSING); 385 if (!$context) { 386 // This must be an incorrectly deleted user, all other users have context. 387 return $defaulturl; 388 } 389 $contextid = $context->id; 390 } 391 392 $path = '/'; 393 if (clean_param($page->theme->name, PARAM_THEME) == $page->theme->name) { 394 // We append the theme name to the file path if we have it so that 395 // in the circumstance that the profile picture is not available 396 // when the user actually requests it they still get the profile 397 // picture for the correct theme. 398 $path .= $page->theme->name.'/'; 399 } 400 // Set the image URL to the URL for the uploaded file and return. 401 $url = moodle_url::make_pluginfile_url($contextid, 'user', 'icon', NULL, $path, $filename); 402 $url->param('rev', $this->user->picture); 403 return $url; 404 } 405 406 if ($this->user->picture == 0 and !empty($CFG->enablegravatar)) { 407 // Normalise the size variable to acceptable bounds 408 if ($size < 1 || $size > 512) { 409 $size = 35; 410 } 411 // Hash the users email address 412 $md5 = md5(strtolower(trim($this->user->email))); 413 // Build a gravatar URL with what we know. 414 415 // Find the best default image URL we can (MDL-35669) 416 if (empty($CFG->gravatardefaulturl)) { 417 $absoluteimagepath = $page->theme->resolve_image_location('u/'.$filename, 'core'); 418 if (strpos($absoluteimagepath, $CFG->dirroot) === 0) { 419 $gravatardefault = $CFG->wwwroot . substr($absoluteimagepath, strlen($CFG->dirroot)); 420 } else { 421 $gravatardefault = $CFG->wwwroot . '/pix/u/' . $filename . '.png'; 422 } 423 } else { 424 $gravatardefault = $CFG->gravatardefaulturl; 425 } 426 427 // If the currently requested page is https then we'll return an 428 // https gravatar page. 429 if (is_https()) { 430 $gravatardefault = str_replace($CFG->wwwroot, $CFG->httpswwwroot, $gravatardefault); // Replace by secure url. 431 return new moodle_url("https://secure.gravatar.com/avatar/{$md5}", array('s' => $size, 'd' => $gravatardefault)); 432 } else { 433 return new moodle_url("http://www.gravatar.com/avatar/{$md5}", array('s' => $size, 'd' => $gravatardefault)); 434 } 435 } 436 437 return $defaulturl; 438 } 439 } 440 441 /** 442 * Data structure representing a help icon. 443 * 444 * @copyright 2010 Petr Skoda (info@skodak.org) 445 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 446 * @since Moodle 2.0 447 * @package core 448 * @category output 449 */ 450 class help_icon implements renderable { 451 452 /** 453 * @var string lang pack identifier (without the "_help" suffix), 454 * both get_string($identifier, $component) and get_string($identifier.'_help', $component) 455 * must exist. 456 */ 457 public $identifier; 458 459 /** 460 * @var string Component name, the same as in get_string() 461 */ 462 public $component; 463 464 /** 465 * @var string Extra descriptive text next to the icon 466 */ 467 public $linktext = null; 468 469 /** 470 * Constructor 471 * 472 * @param string $identifier string for help page title, 473 * string with _help suffix is used for the actual help text. 474 * string with _link suffix is used to create a link to further info (if it exists) 475 * @param string $component 476 */ 477 public function __construct($identifier, $component) { 478 $this->identifier = $identifier; 479 $this->component = $component; 480 } 481 482 /** 483 * Verifies that both help strings exists, shows debug warnings if not 484 */ 485 public function diag_strings() { 486 $sm = get_string_manager(); 487 if (!$sm->string_exists($this->identifier, $this->component)) { 488 debugging("Help title string does not exist: [$this->identifier, $this->component]"); 489 } 490 if (!$sm->string_exists($this->identifier.'_help', $this->component)) { 491 debugging("Help contents string does not exist: [{$this->identifier}_help, $this->component]"); 492 } 493 } 494 } 495 496 497 /** 498 * Data structure representing an icon. 499 * 500 * @copyright 2010 Petr Skoda 501 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 502 * @since Moodle 2.0 503 * @package core 504 * @category output 505 */ 506 class pix_icon implements renderable, templatable { 507 508 /** 509 * @var string The icon name 510 */ 511 var $pix; 512 513 /** 514 * @var string The component the icon belongs to. 515 */ 516 var $component; 517 518 /** 519 * @var array An array of attributes to use on the icon 520 */ 521 var $attributes = array(); 522 523 /** 524 * Constructor 525 * 526 * @param string $pix short icon name 527 * @param string $alt The alt text to use for the icon 528 * @param string $component component name 529 * @param array $attributes html attributes 530 */ 531 public function __construct($pix, $alt, $component='moodle', array $attributes = null) { 532 $this->pix = $pix; 533 $this->component = $component; 534 $this->attributes = (array)$attributes; 535 536 if (empty($this->attributes['class'])) { 537 $this->attributes['class'] = 'smallicon'; 538 } 539 540 // If the alt is empty, don't place it in the attributes, otherwise it will override parent alt text. 541 if (!is_null($alt)) { 542 $this->attributes['alt'] = $alt; 543 544 // If there is no title, set it to the attribute. 545 if (!isset($this->attributes['title'])) { 546 $this->attributes['title'] = $this->attributes['alt']; 547 } 548 } else { 549 unset($this->attributes['alt']); 550 } 551 552 if (empty($this->attributes['title'])) { 553 // Remove the title attribute if empty, we probably want to use the parent node's title 554 // and some browsers might overwrite it with an empty title. 555 unset($this->attributes['title']); 556 } 557 } 558 559 /** 560 * Export this data so it can be used as the context for a mustache template. 561 * 562 * @param renderer_base $output Used to do a final render of any components that need to be rendered for export. 563 * @return array 564 */ 565 public function export_for_template(renderer_base $output) { 566 $attributes = $this->attributes; 567 $attributes['src'] = $output->pix_url($this->pix, $this->component); 568 $templatecontext = array(); 569 foreach ($attributes as $name => $value) { 570 $templatecontext[] = array('name' => $name, 'value' => $value); 571 } 572 $data = array('attributes' => $templatecontext); 573 574 return $data; 575 } 576 } 577 578 /** 579 * Data structure representing an emoticon image 580 * 581 * @copyright 2010 David Mudrak 582 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 583 * @since Moodle 2.0 584 * @package core 585 * @category output 586 */ 587 class pix_emoticon extends pix_icon implements renderable { 588 589 /** 590 * Constructor 591 * @param string $pix short icon name 592 * @param string $alt alternative text 593 * @param string $component emoticon image provider 594 * @param array $attributes explicit HTML attributes 595 */ 596 public function __construct($pix, $alt, $component = 'moodle', array $attributes = array()) { 597 if (empty($attributes['class'])) { 598 $attributes['class'] = 'emoticon'; 599 } 600 parent::__construct($pix, $alt, $component, $attributes); 601 } 602 } 603 604 /** 605 * Data structure representing a simple form with only one button. 606 * 607 * @copyright 2009 Petr Skoda 608 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 609 * @since Moodle 2.0 610 * @package core 611 * @category output 612 */ 613 class single_button implements renderable { 614 615 /** 616 * @var moodle_url Target url 617 */ 618 var $url; 619 620 /** 621 * @var string Button label 622 */ 623 var $label; 624 625 /** 626 * @var string Form submit method post or get 627 */ 628 var $method = 'post'; 629 630 /** 631 * @var string Wrapping div class 632 */ 633 var $class = 'singlebutton'; 634 635 /** 636 * @var bool True if button disabled, false if normal 637 */ 638 var $disabled = false; 639 640 /** 641 * @var string Button tooltip 642 */ 643 var $tooltip = null; 644 645 /** 646 * @var string Form id 647 */ 648 var $formid; 649 650 /** 651 * @var array List of attached actions 652 */ 653 var $actions = array(); 654 655 /** 656 * @var array $params URL Params 657 */ 658 var $params; 659 660 /** 661 * @var string Action id 662 */ 663 var $actionid; 664 665 /** 666 * Constructor 667 * @param moodle_url $url 668 * @param string $label button text 669 * @param string $method get or post submit method 670 */ 671 public function __construct(moodle_url $url, $label, $method='post') { 672 $this->url = clone($url); 673 $this->label = $label; 674 $this->method = $method; 675 } 676 677 /** 678 * Shortcut for adding a JS confirm dialog when the button is clicked. 679 * The message must be a yes/no question. 680 * 681 * @param string $confirmmessage The yes/no confirmation question. If "Yes" is clicked, the original action will occur. 682 */ 683 public function add_confirm_action($confirmmessage) { 684 $this->add_action(new confirm_action($confirmmessage)); 685 } 686 687 /** 688 * Add action to the button. 689 * @param component_action $action 690 */ 691 public function add_action(component_action $action) { 692 $this->actions[] = $action; 693 } 694 } 695 696 697 /** 698 * Simple form with just one select field that gets submitted automatically. 699 * 700 * If JS not enabled small go button is printed too. 701 * 702 * @copyright 2009 Petr Skoda 703 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 704 * @since Moodle 2.0 705 * @package core 706 * @category output 707 */ 708 class single_select implements renderable { 709 710 /** 711 * @var moodle_url Target url - includes hidden fields 712 */ 713 var $url; 714 715 /** 716 * @var string Name of the select element. 717 */ 718 var $name; 719 720 /** 721 * @var array $options associative array value=>label ex.: array(1=>'One, 2=>Two) 722 * it is also possible to specify optgroup as complex label array ex.: 723 * array(array('Odd'=>array(1=>'One', 3=>'Three)), array('Even'=>array(2=>'Two'))) 724 * array(1=>'One', '--1uniquekey'=>array('More'=>array(2=>'Two', 3=>'Three'))) 725 */ 726 var $options; 727 728 /** 729 * @var string Selected option 730 */ 731 var $selected; 732 733 /** 734 * @var array Nothing selected 735 */ 736 var $nothing; 737 738 /** 739 * @var array Extra select field attributes 740 */ 741 var $attributes = array(); 742 743 /** 744 * @var string Button label 745 */ 746 var $label = ''; 747 748 /** 749 * @var array Button label's attributes 750 */ 751 var $labelattributes = array(); 752 753 /** 754 * @var string Form submit method post or get 755 */ 756 var $method = 'get'; 757 758 /** 759 * @var string Wrapping div class 760 */ 761 var $class = 'singleselect'; 762 763 /** 764 * @var bool True if button disabled, false if normal 765 */ 766 var $disabled = false; 767 768 /** 769 * @var string Button tooltip 770 */ 771 var $tooltip = null; 772 773 /** 774 * @var string Form id 775 */ 776 var $formid = null; 777 778 /** 779 * @var array List of attached actions 780 */ 781 var $helpicon = null; 782 783 /** 784 * Constructor 785 * @param moodle_url $url form action target, includes hidden fields 786 * @param string $name name of selection field - the changing parameter in url 787 * @param array $options list of options 788 * @param string $selected selected element 789 * @param array $nothing 790 * @param string $formid 791 */ 792 public function __construct(moodle_url $url, $name, array $options, $selected = '', $nothing = array('' => 'choosedots'), $formid = null) { 793 $this->url = $url; 794 $this->name = $name; 795 $this->options = $options; 796 $this->selected = $selected; 797 $this->nothing = $nothing; 798 $this->formid = $formid; 799 } 800 801 /** 802 * Shortcut for adding a JS confirm dialog when the button is clicked. 803 * The message must be a yes/no question. 804 * 805 * @param string $confirmmessage The yes/no confirmation question. If "Yes" is clicked, the original action will occur. 806 */ 807 public function add_confirm_action($confirmmessage) { 808 $this->add_action(new component_action('submit', 'M.util.show_confirm_dialog', array('message' => $confirmmessage))); 809 } 810 811 /** 812 * Add action to the button. 813 * 814 * @param component_action $action 815 */ 816 public function add_action(component_action $action) { 817 $this->actions[] = $action; 818 } 819 820 /** 821 * Adds help icon. 822 * 823 * @deprecated since Moodle 2.0 824 */ 825 public function set_old_help_icon($helppage, $title, $component = 'moodle') { 826 throw new coding_exception('set_old_help_icon() can not be used any more, please see set_help_icon().'); 827 } 828 829 /** 830 * Adds help icon. 831 * 832 * @param string $identifier The keyword that defines a help page 833 * @param string $component 834 */ 835 public function set_help_icon($identifier, $component = 'moodle') { 836 $this->helpicon = new help_icon($identifier, $component); 837 } 838 839 /** 840 * Sets select's label 841 * 842 * @param string $label 843 * @param array $attributes (optional) 844 */ 845 public function set_label($label, $attributes = array()) { 846 $this->label = $label; 847 $this->labelattributes = $attributes; 848 849 } 850 } 851 852 /** 853 * Simple URL selection widget description. 854 * 855 * @copyright 2009 Petr Skoda 856 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 857 * @since Moodle 2.0 858 * @package core 859 * @category output 860 */ 861 class url_select implements renderable { 862 /** 863 * @var array $urls associative array value=>label ex.: array(1=>'One, 2=>Two) 864 * it is also possible to specify optgroup as complex label array ex.: 865 * array(array('Odd'=>array(1=>'One', 3=>'Three)), array('Even'=>array(2=>'Two'))) 866 * array(1=>'One', '--1uniquekey'=>array('More'=>array(2=>'Two', 3=>'Three'))) 867 */ 868 var $urls; 869 870 /** 871 * @var string Selected option 872 */ 873 var $selected; 874 875 /** 876 * @var array Nothing selected 877 */ 878 var $nothing; 879 880 /** 881 * @var array Extra select field attributes 882 */ 883 var $attributes = array(); 884 885 /** 886 * @var string Button label 887 */ 888 var $label = ''; 889 890 /** 891 * @var array Button label's attributes 892 */ 893 var $labelattributes = array(); 894 895 /** 896 * @var string Wrapping div class 897 */ 898 var $class = 'urlselect'; 899 900 /** 901 * @var bool True if button disabled, false if normal 902 */ 903 var $disabled = false; 904 905 /** 906 * @var string Button tooltip 907 */ 908 var $tooltip = null; 909 910 /** 911 * @var string Form id 912 */ 913 var $formid = null; 914 915 /** 916 * @var array List of attached actions 917 */ 918 var $helpicon = null; 919 920 /** 921 * @var string If set, makes button visible with given name for button 922 */ 923 var $showbutton = null; 924 925 /** 926 * Constructor 927 * @param array $urls list of options 928 * @param string $selected selected element 929 * @param array $nothing 930 * @param string $formid 931 * @param string $showbutton Set to text of button if it should be visible 932 * or null if it should be hidden (hidden version always has text 'go') 933 */ 934 public function __construct(array $urls, $selected = '', $nothing = array('' => 'choosedots'), $formid = null, $showbutton = null) { 935 $this->urls = $urls; 936 $this->selected = $selected; 937 $this->nothing = $nothing; 938 $this->formid = $formid; 939 $this->showbutton = $showbutton; 940 } 941 942 /** 943 * Adds help icon. 944 * 945 * @deprecated since Moodle 2.0 946 */ 947 public function set_old_help_icon($helppage, $title, $component = 'moodle') { 948 throw new coding_exception('set_old_help_icon() can not be used any more, please see set_help_icon().'); 949 } 950 951 /** 952 * Adds help icon. 953 * 954 * @param string $identifier The keyword that defines a help page 955 * @param string $component 956 */ 957 public function set_help_icon($identifier, $component = 'moodle') { 958 $this->helpicon = new help_icon($identifier, $component); 959 } 960 961 /** 962 * Sets select's label 963 * 964 * @param string $label 965 * @param array $attributes (optional) 966 */ 967 public function set_label($label, $attributes = array()) { 968 $this->label = $label; 969 $this->labelattributes = $attributes; 970 } 971 } 972 973 /** 974 * Data structure describing html link with special action attached. 975 * 976 * @copyright 2010 Petr Skoda 977 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 978 * @since Moodle 2.0 979 * @package core 980 * @category output 981 */ 982 class action_link implements renderable { 983 984 /** 985 * @var moodle_url Href url 986 */ 987 public $url; 988 989 /** 990 * @var string Link text HTML fragment 991 */ 992 public $text; 993 994 /** 995 * @var array HTML attributes 996 */ 997 public $attributes; 998 999 /** 1000 * @var array List of actions attached to link 1001 */ 1002 public $actions; 1003 1004 /** 1005 * @var pix_icon Optional pix icon to render with the link 1006 */ 1007 public $icon; 1008 1009 /** 1010 * Constructor 1011 * @param moodle_url $url 1012 * @param string $text HTML fragment 1013 * @param component_action $action 1014 * @param array $attributes associative array of html link attributes + disabled 1015 * @param pix_icon $icon optional pix_icon to render with the link text 1016 */ 1017 public function __construct(moodle_url $url, 1018 $text, 1019 component_action $action=null, 1020 array $attributes=null, 1021 pix_icon $icon=null) { 1022 $this->url = clone($url); 1023 $this->text = $text; 1024 $this->attributes = (array)$attributes; 1025 if ($action) { 1026 $this->add_action($action); 1027 } 1028 $this->icon = $icon; 1029 } 1030 1031 /** 1032 * Add action to the link. 1033 * 1034 * @param component_action $action 1035 */ 1036 public function add_action(component_action $action) { 1037 $this->actions[] = $action; 1038 } 1039 1040 /** 1041 * Adds a CSS class to this action link object 1042 * @param string $class 1043 */ 1044 public function add_class($class) { 1045 if (empty($this->attributes['class'])) { 1046 $this->attributes['class'] = $class; 1047 } else { 1048 $this->attributes['class'] .= ' ' . $class; 1049 } 1050 } 1051 1052 /** 1053 * Returns true if the specified class has been added to this link. 1054 * @param string $class 1055 * @return bool 1056 */ 1057 public function has_class($class) { 1058 return strpos(' ' . $this->attributes['class'] . ' ', ' ' . $class . ' ') !== false; 1059 } 1060 } 1061 1062 /** 1063 * Simple html output class 1064 * 1065 * @copyright 2009 Tim Hunt, 2010 Petr Skoda 1066 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 1067 * @since Moodle 2.0 1068 * @package core 1069 * @category output 1070 */ 1071 class html_writer { 1072 1073 /** 1074 * Outputs a tag with attributes and contents 1075 * 1076 * @param string $tagname The name of tag ('a', 'img', 'span' etc.) 1077 * @param string $contents What goes between the opening and closing tags 1078 * @param array $attributes The tag attributes (array('src' => $url, 'class' => 'class1') etc.) 1079 * @return string HTML fragment 1080 */ 1081 public static function tag($tagname, $contents, array $attributes = null) { 1082 return self::start_tag($tagname, $attributes) . $contents . self::end_tag($tagname); 1083 } 1084 1085 /** 1086 * Outputs an opening tag with attributes 1087 * 1088 * @param string $tagname The name of tag ('a', 'img', 'span' etc.) 1089 * @param array $attributes The tag attributes (array('src' => $url, 'class' => 'class1') etc.) 1090 * @return string HTML fragment 1091 */ 1092 public static function start_tag($tagname, array $attributes = null) { 1093 return '<' . $tagname . self::attributes($attributes) . '>'; 1094 } 1095 1096 /** 1097 * Outputs a closing tag 1098 * 1099 * @param string $tagname The name of tag ('a', 'img', 'span' etc.) 1100 * @return string HTML fragment 1101 */ 1102 public static function end_tag($tagname) { 1103 return '</' . $tagname . '>'; 1104 } 1105 1106 /** 1107 * Outputs an empty tag with attributes 1108 * 1109 * @param string $tagname The name of tag ('input', 'img', 'br' etc.) 1110 * @param array $attributes The tag attributes (array('src' => $url, 'class' => 'class1') etc.) 1111 * @return string HTML fragment 1112 */ 1113 public static function empty_tag($tagname, array $attributes = null) { 1114 return '<' . $tagname . self::attributes($attributes) . ' />'; 1115 } 1116 1117 /** 1118 * Outputs a tag, but only if the contents are not empty 1119 * 1120 * @param string $tagname The name of tag ('a', 'img', 'span' etc.) 1121 * @param string $contents What goes between the opening and closing tags 1122 * @param array $attributes The tag attributes (array('src' => $url, 'class' => 'class1') etc.) 1123 * @return string HTML fragment 1124 */ 1125 public static function nonempty_tag($tagname, $contents, array $attributes = null) { 1126 if ($contents === '' || is_null($contents)) { 1127 return ''; 1128 } 1129 return self::tag($tagname, $contents, $attributes); 1130 } 1131 1132 /** 1133 * Outputs a HTML attribute and value 1134 * 1135 * @param string $name The name of the attribute ('src', 'href', 'class' etc.) 1136 * @param string $value The value of the attribute. The value will be escaped with {@link s()} 1137 * @return string HTML fragment 1138 */ 1139 public static function attribute($name, $value) { 1140 if ($value instanceof moodle_url) { 1141 return ' ' . $name . '="' . $value->out() . '"'; 1142 } 1143 1144 // special case, we do not want these in output 1145 if ($value === null) { 1146 return ''; 1147 } 1148 1149 // no sloppy trimming here! 1150 return ' ' . $name . '="' . s($value) . '"'; 1151 } 1152 1153 /** 1154 * Outputs a list of HTML attributes and values 1155 * 1156 * @param array $attributes The tag attributes (array('src' => $url, 'class' => 'class1') etc.) 1157 * The values will be escaped with {@link s()} 1158 * @return string HTML fragment 1159 */ 1160 public static function attributes(array $attributes = null) { 1161 $attributes = (array)$attributes; 1162 $output = ''; 1163 foreach ($attributes as $name => $value) { 1164 $output .= self::attribute($name, $value); 1165 } 1166 return $output; 1167 } 1168 1169 /** 1170 * Generates a simple image tag with attributes. 1171 * 1172 * @param string $src The source of image 1173 * @param string $alt The alternate text for image 1174 * @param array $attributes The tag attributes (array('height' => $max_height, 'class' => 'class1') etc.) 1175 * @return string HTML fragment 1176 */ 1177 public static function img($src, $alt, array $attributes = null) { 1178 $attributes = (array)$attributes; 1179 $attributes['src'] = $src; 1180 $attributes['alt'] = $alt; 1181 1182 return self::empty_tag('img', $attributes); 1183 } 1184 1185 /** 1186 * Generates random html element id. 1187 * 1188 * @staticvar int $counter 1189 * @staticvar type $uniq 1190 * @param string $base A string fragment that will be included in the random ID. 1191 * @return string A unique ID 1192 */ 1193 public static function random_id($base='random') { 1194 static $counter = 0; 1195 static $uniq; 1196 1197 if (!isset($uniq)) { 1198 $uniq = uniqid(); 1199 } 1200 1201 $counter++; 1202 return $base.$uniq.$counter; 1203 } 1204 1205 /** 1206 * Generates a simple html link 1207 * 1208 * @param string|moodle_url $url The URL 1209 * @param string $text The text 1210 * @param array $attributes HTML attributes 1211 * @return string HTML fragment 1212 */ 1213 public static function link($url, $text, array $attributes = null) { 1214 $attributes = (array)$attributes; 1215 $attributes['href'] = $url; 1216 return self::tag('a', $text, $attributes); 1217 } 1218 1219 /** 1220 * Generates a simple checkbox with optional label 1221 * 1222 * @param string $name The name of the checkbox 1223 * @param string $value The value of the checkbox 1224 * @param bool $checked Whether the checkbox is checked 1225 * @param string $label The label for the checkbox 1226 * @param array $attributes Any attributes to apply to the checkbox 1227 * @return string html fragment 1228 */ 1229 public static function checkbox($name, $value, $checked = true, $label = '', array $attributes = null) { 1230 $attributes = (array)$attributes; 1231 $output = ''; 1232 1233 if ($label !== '' and !is_null($label)) { 1234 if (empty($attributes['id'])) { 1235 $attributes['id'] = self::random_id('checkbox_'); 1236 } 1237 } 1238 $attributes['type'] = 'checkbox'; 1239 $attributes['value'] = $value; 1240 $attributes['name'] = $name; 1241 $attributes['checked'] = $checked ? 'checked' : null; 1242 1243 $output .= self::empty_tag('input', $attributes); 1244 1245 if ($label !== '' and !is_null($label)) { 1246 $output .= self::tag('label', $label, array('for'=>$attributes['id'])); 1247 } 1248 1249 return $output; 1250 } 1251 1252 /** 1253 * Generates a simple select yes/no form field 1254 * 1255 * @param string $name name of select element 1256 * @param bool $selected 1257 * @param array $attributes - html select element attributes 1258 * @return string HTML fragment 1259 */ 1260 public static function select_yes_no($name, $selected=true, array $attributes = null) { 1261 $options = array('1'=>get_string('yes'), '0'=>get_string('no')); 1262 return self::select($options, $name, $selected, null, $attributes); 1263 } 1264 1265 /** 1266 * Generates a simple select form field 1267 * 1268 * @param array $options associative array value=>label ex.: 1269 * array(1=>'One, 2=>Two) 1270 * it is also possible to specify optgroup as complex label array ex.: 1271 * array(array('Odd'=>array(1=>'One', 3=>'Three)), array('Even'=>array(2=>'Two'))) 1272 * array(1=>'One', '--1uniquekey'=>array('More'=>array(2=>'Two', 3=>'Three'))) 1273 * @param string $name name of select element 1274 * @param string|array $selected value or array of values depending on multiple attribute 1275 * @param array|bool $nothing add nothing selected option, or false of not added 1276 * @param array $attributes html select element attributes 1277 * @return string HTML fragment 1278 */ 1279 public static function select(array $options, $name, $selected = '', $nothing = array('' => 'choosedots'), array $attributes = null) { 1280 $attributes = (array)$attributes; 1281 if (is_array($nothing)) { 1282 foreach ($nothing as $k=>$v) { 1283 if ($v === 'choose' or $v === 'choosedots') { 1284 $nothing[$k] = get_string('choosedots'); 1285 } 1286 } 1287 $options = $nothing + $options; // keep keys, do not override 1288 1289 } else if (is_string($nothing) and $nothing !== '') { 1290 // BC 1291 $options = array(''=>$nothing) + $options; 1292 } 1293 1294 // we may accept more values if multiple attribute specified 1295 $selected = (array)$selected; 1296 foreach ($selected as $k=>$v) { 1297 $selected[$k] = (string)$v; 1298 } 1299 1300 if (!isset($attributes['id'])) { 1301 $id = 'menu'.$name; 1302 // name may contaion [], which would make an invalid id. e.g. numeric question type editing form, assignment quickgrading 1303 $id = str_replace('[', '', $id); 1304 $id = str_replace(']', '', $id); 1305 $attributes['id'] = $id; 1306 } 1307 1308 if (!isset($attributes['class'])) { 1309 $class = 'menu'.$name; 1310 // name may contaion [], which would make an invalid class. e.g. numeric question type editing form, assignment quickgrading 1311 $class = str_replace('[', '', $class); 1312 $class = str_replace(']', '', $class); 1313 $attributes['class'] = $class; 1314 } 1315 $attributes['class'] = 'select ' . $attributes['class']; // Add 'select' selector always 1316 1317 $attributes['name'] = $name; 1318 1319 if (!empty($attributes['disabled'])) { 1320 $attributes['disabled'] = 'disabled'; 1321 } else { 1322 unset($attributes['disabled']); 1323 } 1324 1325 $output = ''; 1326 foreach ($options as $value=>$label) { 1327 if (is_array($label)) { 1328 // ignore key, it just has to be unique 1329 $output .= self::select_optgroup(key($label), current($label), $selected); 1330 } else { 1331 $output .= self::select_option($label, $value, $selected); 1332 } 1333 } 1334 return self::tag('select', $output, $attributes); 1335 } 1336 1337 /** 1338 * Returns HTML to display a select box option. 1339 * 1340 * @param string $label The label to display as the option. 1341 * @param string|int $value The value the option represents 1342 * @param array $selected An array of selected options 1343 * @return string HTML fragment 1344 */ 1345 private static function select_option($label, $value, array $selected) { 1346 $attributes = array(); 1347 $value = (string)$value; 1348 if (in_array($value, $selected, true)) { 1349 $attributes['selected'] = 'selected'; 1350 } 1351 $attributes['value'] = $value; 1352 return self::tag('option', $label, $attributes); 1353 } 1354 1355 /** 1356 * Returns HTML to display a select box option group. 1357 * 1358 * @param string $groupname The label to use for the group 1359 * @param array $options The options in the group 1360 * @param array $selected An array of selected values. 1361 * @return string HTML fragment. 1362 */ 1363 private static function select_optgroup($groupname, $options, array $selected) { 1364 if (empty($options)) { 1365 return ''; 1366 } 1367 $attributes = array('label'=>$groupname); 1368 $output = ''; 1369 foreach ($options as $value=>$label) { 1370 $output .= self::select_option($label, $value, $selected); 1371 } 1372 return self::tag('optgroup', $output, $attributes); 1373 } 1374 1375 /** 1376 * This is a shortcut for making an hour selector menu. 1377 * 1378 * @param string $type The type of selector (years, months, days, hours, minutes) 1379 * @param string $name fieldname 1380 * @param int $currenttime A default timestamp in GMT 1381 * @param int $step minute spacing 1382 * @param array $attributes - html select element attributes 1383 * @return HTML fragment 1384 */ 1385 public static function select_time($type, $name, $currenttime = 0, $step = 5, array $attributes = null) { 1386 if (!$currenttime) { 1387 $currenttime = time(); 1388 } 1389 $calendartype = \core_calendar\type_factory::get_calendar_instance(); 1390 $currentdate = $calendartype->timestamp_to_date_array($currenttime); 1391 $userdatetype = $type; 1392 $timeunits = array(); 1393 1394 switch ($type) { 1395 case 'years': 1396 $timeunits = $calendartype->get_years(); 1397 $userdatetype = 'year'; 1398 break; 1399 case 'months': 1400 $timeunits = $calendartype->get_months(); 1401 $userdatetype = 'month'; 1402 $currentdate['month'] = (int)$currentdate['mon']; 1403 break; 1404 case 'days': 1405 $timeunits = $calendartype->get_days(); 1406 $userdatetype = 'mday'; 1407 break; 1408 case 'hours': 1409 for ($i=0; $i<=23; $i++) { 1410 $timeunits[$i] = sprintf("%02d",$i); 1411 } 1412 break; 1413 case 'minutes': 1414 if ($step != 1) { 1415 $currentdate['minutes'] = ceil($currentdate['minutes']/$step)*$step; 1416 } 1417 1418 for ($i=0; $i<=59; $i+=$step) { 1419 $timeunits[$i] = sprintf("%02d",$i); 1420 } 1421 break; 1422 default: 1423 throw new coding_exception("Time type $type is not supported by html_writer::select_time()."); 1424 } 1425 1426 if (empty($attributes['id'])) { 1427 $attributes['id'] = self::random_id('ts_'); 1428 } 1429 $timerselector = self::select($timeunits, $name, $currentdate[$userdatetype], null, $attributes); 1430 $label = self::tag('label', get_string(substr($type, 0, -1), 'form'), array('for'=>$attributes['id'], 'class'=>'accesshide')); 1431 1432 return $label.$timerselector; 1433 } 1434 1435 /** 1436 * Shortcut for quick making of lists 1437 * 1438 * Note: 'list' is a reserved keyword ;-) 1439 * 1440 * @param array $items 1441 * @param array $attributes 1442 * @param string $tag ul or ol 1443 * @return string 1444 */ 1445 public static function alist(array $items, array $attributes = null, $tag = 'ul') { 1446 $output = html_writer::start_tag($tag, $attributes)."\n"; 1447 foreach ($items as $item) { 1448 $output .= html_writer::tag('li', $item)."\n"; 1449 } 1450 $output .= html_writer::end_tag($tag); 1451 return $output; 1452 } 1453 1454 /** 1455 * Returns hidden input fields created from url parameters. 1456 * 1457 * @param moodle_url $url 1458 * @param array $exclude list of excluded parameters 1459 * @return string HTML fragment 1460 */ 1461 public static function input_hidden_params(moodle_url $url, array $exclude = null) { 1462 $exclude = (array)$exclude; 1463 $params = $url->params(); 1464 foreach ($exclude as $key) { 1465 unset($params[$key]); 1466 } 1467 1468 $output = ''; 1469 foreach ($params as $key => $value) { 1470 $attributes = array('type'=>'hidden', 'name'=>$key, 'value'=>$value); 1471 $output .= self::empty_tag('input', $attributes)."\n"; 1472 } 1473 return $output; 1474 } 1475 1476 /** 1477 * Generate a script tag containing the the specified code. 1478 * 1479 * @param string $jscode the JavaScript code 1480 * @param moodle_url|string $url optional url of the external script, $code ignored if specified 1481 * @return string HTML, the code wrapped in <script> tags. 1482 */ 1483 public static function script($jscode, $url=null) { 1484 if ($jscode) { 1485 $attributes = array('type'=>'text/javascript'); 1486 return self::tag('script', "\n//<![CDATA[\n$jscode\n//]]>\n", $attributes) . "\n"; 1487 1488 } else if ($url) { 1489 $attributes = array('type'=>'text/javascript', 'src'=>$url); 1490 return self::tag('script', '', $attributes) . "\n"; 1491 1492 } else { 1493 return ''; 1494 } 1495 } 1496 1497 /** 1498 * Renders HTML table 1499 * 1500 * This method may modify the passed instance by adding some default properties if they are not set yet. 1501 * If this is not what you want, you should make a full clone of your data before passing them to this 1502 * method. In most cases this is not an issue at all so we do not clone by default for performance 1503 * and memory consumption reasons. 1504 * 1505 * @param html_table $table data to be rendered 1506 * @return string HTML code 1507 */ 1508 public static function table(html_table $table) { 1509 // prepare table data and populate missing properties with reasonable defaults 1510 if (!empty($table->align)) { 1511 foreach ($table->align as $key => $aa) { 1512 if ($aa) { 1513 $table->align[$key] = 'text-align:'. fix_align_rtl($aa) .';'; // Fix for RTL languages 1514 } else { 1515 $table->align[$key] = null; 1516 } 1517 } 1518 } 1519 if (!empty($table->size)) { 1520 foreach ($table->size as $key => $ss) { 1521 if ($ss) { 1522 $table->size[$key] = 'width:'. $ss .';'; 1523 } else { 1524 $table->size[$key] = null; 1525 } 1526 } 1527 } 1528 if (!empty($table->wrap)) { 1529 foreach ($table->wrap as $key => $ww) { 1530 if ($ww) { 1531 $table->wrap[$key] = 'white-space:nowrap;'; 1532 } else { 1533 $table->wrap[$key] = ''; 1534 } 1535 } 1536 } 1537 if (!empty($table->head)) { 1538 foreach ($table->head as $key => $val) { 1539 if (!isset($table->align[$key])) { 1540 $table->align[$key] = null; 1541 } 1542 if (!isset($table->size[$key])) { 1543 $table->size[$key] = null; 1544 } 1545 if (!isset($table->wrap[$key])) { 1546 $table->wrap[$key] = null; 1547 } 1548 1549 } 1550 } 1551 if (empty($table->attributes['class'])) { 1552 $table->attributes['class'] = 'generaltable'; 1553 } 1554 if (!empty($table->tablealign)) { 1555 $table->attributes['class'] .= ' boxalign' . $table->tablealign; 1556 } 1557 1558 // explicitly assigned properties override those defined via $table->attributes 1559 $table->attributes['class'] = trim($table->attributes['class']); 1560 $attributes = array_merge($table->attributes, array( 1561 'id' => $table->id, 1562 'width' => $table->width, 1563 'summary' => $table->summary, 1564 'cellpadding' => $table->cellpadding, 1565 'cellspacing' => $table->cellspacing, 1566 )); 1567 $output = html_writer::start_tag('table', $attributes) . "\n"; 1568 1569 $countcols = 0; 1570 1571 // Output a caption if present. 1572 if (!empty($table->caption)) { 1573 $captionattributes = array(); 1574 if ($table->captionhide) { 1575 $captionattributes['class'] = 'accesshide'; 1576 } 1577 $output .= html_writer::tag( 1578 'caption', 1579 $table->caption, 1580 $captionattributes 1581 ); 1582 } 1583 1584 if (!empty($table->head)) { 1585 $countcols = count($table->head); 1586 1587 $output .= html_writer::start_tag('thead', array()) . "\n"; 1588 $output .= html_writer::start_tag('tr', array()) . "\n"; 1589 $keys = array_keys($table->head); 1590 $lastkey = end($keys); 1591 1592 foreach ($table->head as $key => $heading) { 1593 // Convert plain string headings into html_table_cell objects 1594 if (!($heading instanceof html_table_cell)) { 1595 $headingtext = $heading; 1596 $heading = new html_table_cell(); 1597 $heading->text = $headingtext; 1598 $heading->header = true; 1599 } 1600 1601 if ($heading->header !== false) { 1602 $heading->header = true; 1603 } 1604 1605 if ($heading->header && empty($heading->scope)) { 1606 $heading->scope = 'col'; 1607 } 1608 1609 $heading->attributes['class'] .= ' header c' . $key; 1610 if (isset($table->headspan[$key]) && $table->headspan[$key] > 1) { 1611 $heading->colspan = $table->headspan[$key]; 1612 $countcols += $table->headspan[$key] - 1; 1613 } 1614 1615 if ($key == $lastkey) { 1616 $heading->attributes['class'] .= ' lastcol'; 1617 } 1618 if (isset($table->colclasses[$key])) { 1619 $heading->attributes['class'] .= ' ' . $table->colclasses[$key]; 1620 } 1621 $heading->attributes['class'] = trim($heading->attributes['class']); 1622 $attributes = array_merge($heading->attributes, array( 1623 'style' => $table->align[$key] . $table->size[$key] . $heading->style, 1624 'scope' => $heading->scope, 1625 'colspan' => $heading->colspan, 1626 )); 1627 1628 $tagtype = 'td'; 1629 if ($heading->header === true) { 1630 $tagtype = 'th'; 1631 } 1632 $output .= html_writer::tag($tagtype, $heading->text, $attributes) . "\n"; 1633 } 1634 $output .= html_writer::end_tag('tr') . "\n"; 1635 $output .= html_writer::end_tag('thead') . "\n"; 1636 1637 if (empty($table->data)) { 1638 // For valid XHTML strict every table must contain either a valid tr 1639 // or a valid tbody... both of which must contain a valid td 1640 $output .= html_writer::start_tag('tbody', array('class' => 'empty')); 1641 $output .= html_writer::tag('tr', html_writer::tag('td', '', array('colspan'=>count($table->head)))); 1642 $output .= html_writer::end_tag('tbody'); 1643 } 1644 } 1645 1646 if (!empty($table->data)) { 1647 $keys = array_keys($table->data); 1648 $lastrowkey = end($keys); 1649 $output .= html_writer::start_tag('tbody', array()); 1650 1651 foreach ($table->data as $key => $row) { 1652 if (($row === 'hr') && ($countcols)) { 1653 $output .= html_writer::tag('td', html_writer::tag('div', '', array('class' => 'tabledivider')), array('colspan' => $countcols)); 1654 } else { 1655 // Convert array rows to html_table_rows and cell strings to html_table_cell objects 1656 if (!($row instanceof html_table_row)) { 1657 $newrow = new html_table_row(); 1658 1659 foreach ($row as $cell) { 1660 if (!($cell instanceof html_table_cell)) { 1661 $cell = new html_table_cell($cell); 1662 } 1663 $newrow->cells[] = $cell; 1664 } 1665 $row = $newrow; 1666 } 1667 1668 if (isset($table->rowclasses[$key])) { 1669 $row->attributes['class'] .= ' ' . $table->rowclasses[$key]; 1670 } 1671 1672 if ($key == $lastrowkey) { 1673 $row->attributes['class'] .= ' lastrow'; 1674 } 1675 1676 // Explicitly assigned properties should override those defined in the attributes. 1677 $row->attributes['class'] = trim($row->attributes['class']); 1678 $trattributes = array_merge($row->attributes, array( 1679 'id' => $row->id, 1680 'style' => $row->style, 1681 )); 1682 $output .= html_writer::start_tag('tr', $trattributes) . "\n"; 1683 $keys2 = array_keys($row->cells); 1684 $lastkey = end($keys2); 1685 1686 $gotlastkey = false; //flag for sanity checking 1687 foreach ($row->cells as $key => $cell) { 1688 if ($gotlastkey) { 1689 //This should never happen. Why do we have a cell after the last cell? 1690 mtrace("A cell with key ($key) was found after the last key ($lastkey)"); 1691 } 1692 1693 if (!($cell instanceof html_table_cell)) { 1694 $mycell = new html_table_cell(); 1695 $mycell->text = $cell; 1696 $cell = $mycell; 1697 } 1698 1699 if (($cell->header === true) && empty($cell->scope)) { 1700 $cell->scope = 'row'; 1701 } 1702 1703 if (isset($table->colclasses[$key])) { 1704 $cell->attributes['class'] .= ' ' . $table->colclasses[$key]; 1705 } 1706 1707 $cell->attributes['class'] .= ' cell c' . $key; 1708 if ($key == $lastkey) { 1709 $cell->attributes['class'] .= ' lastcol'; 1710 $gotlastkey = true; 1711 } 1712 $tdstyle = ''; 1713 $tdstyle .= isset($table->align[$key]) ? $table->align[$key] : ''; 1714 $tdstyle .= isset($table->size[$key]) ? $table->size[$key] : ''; 1715 $tdstyle .= isset($table->wrap[$key]) ? $table->wrap[$key] : ''; 1716 $cell->attributes['class'] = trim($cell->attributes['class']); 1717 $tdattributes = array_merge($cell->attributes, array( 1718 'style' => $tdstyle . $cell->style, 1719 'colspan' => $cell->colspan, 1720 'rowspan' => $cell->rowspan, 1721 'id' => $cell->id, 1722 'abbr' => $cell->abbr, 1723 'scope' => $cell->scope, 1724 )); 1725 $tagtype = 'td'; 1726 if ($cell->header === true) { 1727 $tagtype = 'th'; 1728 } 1729 $output .= html_writer::tag($tagtype, $cell->text, $tdattributes) . "\n"; 1730 } 1731 } 1732 $output .= html_writer::end_tag('tr') . "\n"; 1733 } 1734 $output .= html_writer::end_tag('tbody') . "\n"; 1735 } 1736 $output .= html_writer::end_tag('table') . "\n"; 1737 1738 return $output; 1739 } 1740 1741 /** 1742 * Renders form element label 1743 * 1744 * By default, the label is suffixed with a label separator defined in the 1745 * current language pack (colon by default in the English lang pack). 1746 * Adding the colon can be explicitly disabled if needed. Label separators 1747 * are put outside the label tag itself so they are not read by 1748 * screenreaders (accessibility). 1749 * 1750 * Parameter $for explicitly associates the label with a form control. When 1751 * set, the value of this attribute must be the same as the value of 1752 * the id attribute of the form control in the same document. When null, 1753 * the label being defined is associated with the control inside the label 1754 * element. 1755 * 1756 * @param string $text content of the label tag 1757 * @param string|null $for id of the element this label is associated with, null for no association 1758 * @param bool $colonize add label separator (colon) to the label text, if it is not there yet 1759 * @param array $attributes to be inserted in the tab, for example array('accesskey' => 'a') 1760 * @return string HTML of the label element 1761 */ 1762 public static function label($text, $for, $colonize = true, array $attributes=array()) { 1763 if (!is_null($for)) { 1764 $attributes = array_merge($attributes, array('for' => $for)); 1765 } 1766 $text = trim($text); 1767 $label = self::tag('label', $text, $attributes); 1768 1769 // TODO MDL-12192 $colonize disabled for now yet 1770 // if (!empty($text) and $colonize) { 1771 // // the $text may end with the colon already, though it is bad string definition style 1772 // $colon = get_string('labelsep', 'langconfig'); 1773 // if (!empty($colon)) { 1774 // $trimmed = trim($colon); 1775 // if ((substr($text, -strlen($trimmed)) == $trimmed) or (substr($text, -1) == ':')) { 1776 // //debugging('The label text should not end with colon or other label separator, 1777 // // please fix the string definition.', DEBUG_DEVELOPER); 1778 // } else { 1779 // $label .= $colon; 1780 // } 1781 // } 1782 // } 1783 1784 return $label; 1785 } 1786 1787 /** 1788 * Combines a class parameter with other attributes. Aids in code reduction 1789 * because the class parameter is very frequently used. 1790 * 1791 * If the class attribute is specified both in the attributes and in the 1792 * class parameter, the two values are combined with a space between. 1793 * 1794 * @param string $class Optional CSS class (or classes as space-separated list) 1795 * @param array $attributes Optional other attributes as array 1796 * @return array Attributes (or null if still none) 1797 */ 1798 private static function add_class($class = '', array $attributes = null) { 1799 if ($class !== '') { 1800 $classattribute = array('class' => $class); 1801 if ($attributes) { 1802 if (array_key_exists('class', $attributes)) { 1803 $attributes['class'] = trim($attributes['class'] . ' ' . $class); 1804 } else { 1805 $attributes = $classattribute + $attributes; 1806 } 1807 } else { 1808 $attributes = $classattribute; 1809 } 1810 } 1811 return $attributes; 1812 } 1813 1814 /** 1815 * Creates a <div> tag. (Shortcut function.) 1816 * 1817 * @param string $content HTML content of tag 1818 * @param string $class Optional CSS class (or classes as space-separated list) 1819 * @param array $attributes Optional other attributes as array 1820 * @return string HTML code for div 1821 */ 1822 public static function div($content, $class = '', array $attributes = null) { 1823 return self::tag('div', $content, self::add_class($class, $attributes)); 1824 } 1825 1826 /** 1827 * Starts a <div> tag. (Shortcut function.) 1828 * 1829 * @param string $class Optional CSS class (or classes as space-separated list) 1830 * @param array $attributes Optional other attributes as array 1831 * @return string HTML code for open div tag 1832 */ 1833 public static function start_div($class = '', array $attributes = null) { 1834 return self::start_tag('div', self::add_class($class, $attributes)); 1835 } 1836 1837 /** 1838 * Ends a <div> tag. (Shortcut function.) 1839 * 1840 * @return string HTML code for close div tag 1841 */ 1842 public static function end_div() { 1843 return self::end_tag('div'); 1844 } 1845 1846 /** 1847 * Creates a <span> tag. (Shortcut function.) 1848 * 1849 * @param string $content HTML content of tag 1850 * @param string $class Optional CSS class (or classes as space-separated list) 1851 * @param array $attributes Optional other attributes as array 1852 * @return string HTML code for span 1853 */ 1854 public static function span($content, $class = '', array $attributes = null) { 1855 return self::tag('span', $content, self::add_class($class, $attributes)); 1856 } 1857 1858 /** 1859 * Starts a <span> tag. (Shortcut function.) 1860 * 1861 * @param string $class Optional CSS class (or classes as space-separated list) 1862 * @param array $attributes Optional other attributes as array 1863 * @return string HTML code for open span tag 1864 */ 1865 public static function start_span($class = '', array $attributes = null) { 1866 return self::start_tag('span', self::add_class($class, $attributes)); 1867 } 1868 1869 /** 1870 * Ends a <span> tag. (Shortcut function.) 1871 * 1872 * @return string HTML code for close span tag 1873 */ 1874 public static function end_span() { 1875 return self::end_tag('span'); 1876 } 1877 } 1878 1879 /** 1880 * Simple javascript output class 1881 * 1882 * @copyright 2010 Petr Skoda 1883 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 1884 * @since Moodle 2.0 1885 * @package core 1886 * @category output 1887 */ 1888 class js_writer { 1889 1890 /** 1891 * Returns javascript code calling the function 1892 * 1893 * @param string $function function name, can be complex like Y.Event.purgeElement 1894 * @param array $arguments parameters 1895 * @param int $delay execution delay in seconds 1896 * @return string JS code fragment 1897 */ 1898 public static function function_call($function, array $arguments = null, $delay=0) { 1899 if ($arguments) { 1900 $arguments = array_map('json_encode', convert_to_array($arguments)); 1901 $arguments = implode(', ', $arguments); 1902 } else { 1903 $arguments = ''; 1904 } 1905 $js = "$function($arguments);"; 1906 1907 if ($delay) { 1908 $delay = $delay * 1000; // in miliseconds 1909 $js = "setTimeout(function() { $js }, $delay);"; 1910 } 1911 return $js . "\n"; 1912 } 1913 1914 /** 1915 * Special function which adds Y as first argument of function call. 1916 * 1917 * @param string $function The function to call 1918 * @param array $extraarguments Any arguments to pass to it 1919 * @return string Some JS code 1920 */ 1921 public static function function_call_with_Y($function, array $extraarguments = null) { 1922 if ($extraarguments) { 1923 $extraarguments = array_map('json_encode', convert_to_array($extraarguments)); 1924 $arguments = 'Y, ' . implode(', ', $extraarguments); 1925 } else { 1926 $arguments = 'Y'; 1927 } 1928 return "$function($arguments);\n"; 1929 } 1930 1931 /** 1932 * Returns JavaScript code to initialise a new object 1933 * 1934 * @param string $var If it is null then no var is assigned the new object. 1935 * @param string $class The class to initialise an object for. 1936 * @param array $arguments An array of args to pass to the init method. 1937 * @param array $requirements Any modules required for this class. 1938 * @param int $delay The delay before initialisation. 0 = no delay. 1939 * @return string Some JS code 1940 */ 1941 public static function object_init($var, $class, array $arguments = null, array $requirements = null, $delay=0) { 1942 if (is_array($arguments)) { 1943 $arguments = array_map('json_encode', convert_to_array($arguments)); 1944 $arguments = implode(', ', $arguments); 1945 } 1946 1947 if ($var === null) { 1948 $js = "new $class(Y, $arguments);"; 1949 } else if (strpos($var, '.')!==false) { 1950 $js = "$var = new $class(Y, $arguments);"; 1951 } else { 1952 $js = "var $var = new $class(Y, $arguments);"; 1953 } 1954 1955 if ($delay) { 1956 $delay = $delay * 1000; // in miliseconds 1957 $js = "setTimeout(function() { $js }, $delay);"; 1958 } 1959 1960 if (count($requirements) > 0) { 1961 $requirements = implode("', '", $requirements); 1962 $js = "Y.use('$requirements', function(Y){ $js });"; 1963 } 1964 return $js."\n"; 1965 } 1966 1967 /** 1968 * Returns code setting value to variable 1969 * 1970 * @param string $name 1971 * @param mixed $value json serialised value 1972 * @param bool $usevar add var definition, ignored for nested properties 1973 * @return string JS code fragment 1974 */ 1975 public static function set_variable($name, $value, $usevar = true) { 1976 $output = ''; 1977 1978 if ($usevar) { 1979 if (strpos($name, '.')) { 1980 $output .= ''; 1981 } else { 1982 $output .= 'var '; 1983 } 1984 } 1985 1986 $output .= "$name = ".json_encode($value).";"; 1987 1988 return $output; 1989 } 1990 1991 /** 1992 * Writes event handler attaching code 1993 * 1994 * @param array|string $selector standard YUI selector for elements, may be 1995 * array or string, element id is in the form "#idvalue" 1996 * @param string $event A valid DOM event (click, mousedown, change etc.) 1997 * @param string $function The name of the function to call 1998 * @param array $arguments An optional array of argument parameters to pass to the function 1999 * @return string JS code fragment 2000 */ 2001 public static function event_handler($selector, $event, $function, array $arguments = null) { 2002 $selector = json_encode($selector); 2003 $output = "Y.on('$event', $function, $selector, null"; 2004 if (!empty($arguments)) { 2005 $output .= ', ' . json_encode($arguments); 2006 } 2007 return $output . ");\n"; 2008 } 2009 } 2010 2011 /** 2012 * Holds all the information required to render a <table> by {@link core_renderer::table()} 2013 * 2014 * Example of usage: 2015 * $t = new html_table(); 2016 * ... // set various properties of the object $t as described below 2017 * echo html_writer::table($t); 2018 * 2019 * @copyright 2009 David Mudrak <david.mudrak@gmail.com> 2020 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 2021 * @since Moodle 2.0 2022 * @package core 2023 * @category output 2024 */ 2025 class html_table { 2026 2027 /** 2028 * @var string Value to use for the id attribute of the table 2029 */ 2030 public $id = null; 2031 2032 /** 2033 * @var array Attributes of HTML attributes for the <table> element 2034 */ 2035 public $attributes = array(); 2036 2037 /** 2038 * @var array An array of headings. The n-th array item is used as a heading of the n-th column. 2039 * For more control over the rendering of the headers, an array of html_table_cell objects 2040 * can be passed instead of an array of strings. 2041 * 2042 * Example of usage: 2043 * $t->head = array('Student', 'Grade'); 2044 */ 2045 public $head; 2046 2047 /** 2048 * @var array An array that can be used to make a heading span multiple columns. 2049 * In this example, {@link html_table:$data} is supposed to have three columns. For the first two columns, 2050 * the same heading is used. Therefore, {@link html_table::$head} should consist of two items. 2051 * 2052 * Example of usage: 2053 * $t->headspan = array(2,1); 2054 */ 2055 public $headspan; 2056 2057 /** 2058 * @var array An array of column alignments. 2059 * The value is used as CSS 'text-align' property. Therefore, possible 2060 * values are 'left', 'right', 'center' and 'justify'. Specify 'right' or 'left' from the perspective 2061 * of a left-to-right (LTR) language. For RTL, the values are flipped automatically. 2062 * 2063 * Examples of usage: 2064 * $t->align = array(null, 'right'); 2065 * or 2066 * $t->align[1] = 'right'; 2067 */ 2068 public $align; 2069 2070 /** 2071 * @var array The value is used as CSS 'size' property. 2072 * 2073 * Examples of usage: 2074 * $t->size = array('50%', '50%'); 2075 * or 2076 * $t->size[1] = '120px'; 2077 */ 2078 public $size; 2079 2080 /** 2081 * @var array An array of wrapping information. 2082 * The only possible value is 'nowrap' that sets the 2083 * CSS property 'white-space' to the value 'nowrap' in the given column. 2084 * 2085 * Example of usage: 2086 * $t->wrap = array(null, 'nowrap'); 2087 */ 2088 public $wrap; 2089 2090 /** 2091 * @var array Array of arrays or html_table_row objects containing the data. Alternatively, if you have 2092 * $head specified, the string 'hr' (for horizontal ruler) can be used 2093 * instead of an array of cells data resulting in a divider rendered. 2094 * 2095 * Example of usage with array of arrays: 2096 * $row1 = array('Harry Potter', '76 %'); 2097 * $row2 = array('Hermione Granger', '100 %'); 2098 * $t->data = array($row1, $row2); 2099 * 2100 * Example with array of html_table_row objects: (used for more fine-grained control) 2101 * $cell1 = new html_table_cell(); 2102 * $cell1->text = 'Harry Potter'; 2103 * $cell1->colspan = 2; 2104 * $row1 = new html_table_row(); 2105 * $row1->cells[] = $cell1; 2106 * $cell2 = new html_table_cell(); 2107 * $cell2->text = 'Hermione Granger'; 2108 * $cell3 = new html_table_cell(); 2109 * $cell3->text = '100 %'; 2110 * $row2 = new html_table_row(); 2111 * $row2->cells = array($cell2, $cell3); 2112 * $t->data = array($row1, $row2); 2113 */ 2114 public $data; 2115 2116 /** 2117 * @deprecated since Moodle 2.0. Styling should be in the CSS. 2118 * @var string Width of the table, percentage of the page preferred. 2119 */ 2120 public $width = null; 2121 2122 /** 2123 * @deprecated since Moodle 2.0. Styling should be in the CSS. 2124 * @var string Alignment for the whole table. Can be 'right', 'left' or 'center' (default). 2125 */ 2126 public $tablealign = null; 2127 2128 /** 2129 * @deprecated since Moodle 2.0. Styling should be in the CSS. 2130 * @var int Padding on each cell, in pixels 2131 */ 2132 public $cellpadding = null; 2133 2134 /** 2135 * @var int Spacing between cells, in pixels 2136 * @deprecated since Moodle 2.0. Styling should be in the CSS. 2137 */ 2138 public $cellspacing = null; 2139 2140 /** 2141 * @var array Array of classes to add to particular rows, space-separated string. 2142 * Class 'lastrow' is added automatically for the last row in the table. 2143 * 2144 * Example of usage: 2145 * $t->rowclasses[9] = 'tenth' 2146 */ 2147 public $rowclasses; 2148 2149 /** 2150 * @var array An array of classes to add to every cell in a particular column, 2151 * space-separated string. Class 'cell' is added automatically by the renderer. 2152 * Classes 'c0' or 'c1' are added automatically for every odd or even column, 2153 * respectively. Class 'lastcol' is added automatically for all last cells 2154 * in a row. 2155 * 2156 * Example of usage: 2157 * $t->colclasses = array(null, 'grade'); 2158 */ 2159 public $colclasses; 2160 2161 /** 2162 * @var string Description of the contents for screen readers. 2163 */ 2164 public $summary; 2165 2166 /** 2167 * @var string Caption for the table, typically a title. 2168 * 2169 * Example of usage: 2170 * $t->caption = "TV Guide"; 2171 */ 2172 public $caption; 2173 2174 /** 2175 * @var bool Whether to hide the table's caption from sighted users. 2176 * 2177 * Example of usage: 2178 * $t->caption = "TV Guide"; 2179 * $t->captionhide = true; 2180 */ 2181 public $captionhide = false; 2182 2183 /** 2184 * Constructor 2185 */ 2186 public function __construct() { 2187 $this->attributes['class'] = ''; 2188 } 2189 } 2190 2191 /** 2192 * Component representing a table row. 2193 * 2194 * @copyright 2009 Nicolas Connault 2195 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 2196 * @since Moodle 2.0 2197 * @package core 2198 * @category output 2199 */ 2200 class html_table_row { 2201 2202 /** 2203 * @var string Value to use for the id attribute of the row. 2204 */ 2205 public $id = null; 2206 2207 /** 2208 * @var array Array of html_table_cell objects 2209 */ 2210 public $cells = array(); 2211 2212 /** 2213 * @var string Value to use for the style attribute of the table row 2214 */ 2215 public $style = null; 2216 2217 /** 2218 * @var array Attributes of additional HTML attributes for the <tr> element 2219 */ 2220 public $attributes = array(); 2221 2222 /** 2223 * Constructor 2224 * @param array $cells 2225 */ 2226 public function __construct(array $cells=null) { 2227 $this->attributes['class'] = ''; 2228 $cells = (array)$cells; 2229 foreach ($cells as $cell) { 2230 if ($cell instanceof html_table_cell) { 2231 $this->cells[] = $cell; 2232 } else { 2233 $this->cells[] = new html_table_cell($cell); 2234 } 2235 } 2236 } 2237 } 2238 2239 /** 2240 * Component representing a table cell. 2241 * 2242 * @copyright 2009 Nicolas Connault 2243 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 2244 * @since Moodle 2.0 2245 * @package core 2246 * @category output 2247 */ 2248 class html_table_cell { 2249 2250 /** 2251 * @var string Value to use for the id attribute of the cell. 2252 */ 2253 public $id = null; 2254 2255 /** 2256 * @var string The contents of the cell. 2257 */ 2258 public $text; 2259 2260 /** 2261 * @var string Abbreviated version of the contents of the cell. 2262 */ 2263 public $abbr = null; 2264 2265 /** 2266 * @var int Number of columns this cell should span. 2267 */ 2268 public $colspan = null; 2269 2270 /** 2271 * @var int Number of rows this cell should span. 2272 */ 2273 public $rowspan = null; 2274 2275 /** 2276 * @var string Defines a way to associate header cells and data cells in a table. 2277 */ 2278 public $scope = null; 2279 2280 /** 2281 * @var bool Whether or not this cell is a header cell. 2282 */ 2283 public $header = null; 2284 2285 /** 2286 * @var string Value to use for the style attribute of the table cell 2287 */ 2288 public $style = null; 2289 2290 /** 2291 * @var array Attributes of additional HTML attributes for the <td> element 2292 */ 2293 public $attributes = array(); 2294 2295 /** 2296 * Constructs a table cell 2297 * 2298 * @param string $text 2299 */ 2300 public function __construct($text = null) { 2301 $this->text = $text; 2302 $this->attributes['class'] = ''; 2303 } 2304 } 2305 2306 /** 2307 * Component representing a paging bar. 2308 * 2309 * @copyright 2009 Nicolas Connault 2310 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 2311 * @since Moodle 2.0 2312 * @package core 2313 * @category output 2314 */ 2315 class paging_bar implements renderable { 2316 2317 /** 2318 * @var int The maximum number of pagelinks to display. 2319 */ 2320 public $maxdisplay = 18; 2321 2322 /** 2323 * @var int The total number of entries to be pages through.. 2324 */ 2325 public $totalcount; 2326 2327 /** 2328 * @var int The page you are currently viewing. 2329 */ 2330 public $page; 2331 2332 /** 2333 * @var int The number of entries that should be shown per page. 2334 */ 2335 public $perpage; 2336 2337 /** 2338 * @var string|moodle_url If this is a string then it is the url which will be appended with $pagevar, 2339 * an equals sign and the page number. 2340 * If this is a moodle_url object then the pagevar param will be replaced by 2341 * the page no, for each page. 2342 */ 2343 public $baseurl; 2344 2345 /** 2346 * @var string This is the variable name that you use for the pagenumber in your 2347 * code (ie. 'tablepage', 'blogpage', etc) 2348 */ 2349 public $pagevar; 2350 2351 /** 2352 * @var string A HTML link representing the "previous" page. 2353 */ 2354 public $previouslink = null; 2355 2356 /** 2357 * @var string A HTML link representing the "next" page. 2358 */ 2359 public $nextlink = null; 2360 2361 /** 2362 * @var string A HTML link representing the first page. 2363 */ 2364 public $firstlink = null; 2365 2366 /** 2367 * @var string A HTML link representing the last page. 2368 */ 2369 public $lastlink = null; 2370 2371 /** 2372 * @var array An array of strings. One of them is just a string: the current page 2373 */ 2374 public $pagelinks = array(); 2375 2376 /** 2377 * Constructor paging_bar with only the required params. 2378 * 2379 * @param int $totalcount The total number of entries available to be paged through 2380 * @param int $page The page you are currently viewing 2381 * @param int $perpage The number of entries that should be shown per page 2382 * @param string|moodle_url $baseurl url of the current page, the $pagevar parameter is added 2383 * @param string $pagevar name of page parameter that holds the page number 2384 */ 2385 public function __construct($totalcount, $page, $perpage, $baseurl, $pagevar = 'page') { 2386 $this->totalcount = $totalcount; 2387 $this->page = $page; 2388 $this->perpage = $perpage; 2389 $this->baseurl = $baseurl; 2390 $this->pagevar = $pagevar; 2391 } 2392 2393 /** 2394 * Prepares the paging bar for output. 2395 * 2396 * This method validates the arguments set up for the paging bar and then 2397 * produces fragments of HTML to assist display later on. 2398 * 2399 * @param renderer_base $output 2400 * @param moodle_page $page 2401 * @param string $target 2402 * @throws coding_exception 2403 */ 2404 public function prepare(renderer_base $output, moodle_page $page, $target) { 2405 if (!isset($this->totalcount) || is_null($this->totalcount)) { 2406 throw new coding_exception('paging_bar requires a totalcount value.'); 2407 } 2408 if (!isset($this->page) || is_null($this->page)) { 2409 throw new coding_exception('paging_bar requires a page value.'); 2410 } 2411 if (empty($this->perpage)) { 2412 throw new coding_exception('paging_bar requires a perpage value.'); 2413 } 2414 if (empty($this->baseurl)) { 2415 throw new coding_exception('paging_bar requires a baseurl value.'); 2416 } 2417 2418 if ($this->totalcount > $this->perpage) { 2419 $pagenum = $this->page - 1; 2420 2421 if ($this->page > 0) { 2422 $this->previouslink = html_writer::link(new moodle_url($this->baseurl, array($this->pagevar=>$pagenum)), get_string('previous'), array('class'=>'previous')); 2423 } 2424 2425 if ($this->perpage > 0) { 2426 $lastpage = ceil($this->totalcount / $this->perpage); 2427 } else { 2428 $lastpage = 1; 2429 } 2430 2431 if ($this->page > round(($this->maxdisplay/3)*2)) { 2432 $currpage = $this->page - round($this->maxdisplay/3); 2433 2434 $this->firstlink = html_writer::link(new moodle_url($this->baseurl, array($this->pagevar=>0)), '1', array('class'=>'first')); 2435 } else { 2436 $currpage = 0; 2437 } 2438 2439 $displaycount = $displaypage = 0; 2440 2441 while ($displaycount < $this->maxdisplay and $currpage < $lastpage) { 2442 $displaypage = $currpage + 1; 2443 2444 if ($this->page == $currpage) { 2445 $this->pagelinks[] = html_writer::span($displaypage, 'current-page'); 2446 } else { 2447 $pagelink = html_writer::link(new moodle_url($this->baseurl, array($this->pagevar=>$currpage)), $displaypage); 2448 $this->pagelinks[] = $pagelink; 2449 } 2450 2451 $displaycount++; 2452 $currpage++; 2453 } 2454 2455 if ($currpage < $lastpage) { 2456 $lastpageactual = $lastpage - 1; 2457 $this->lastlink = html_writer::link(new moodle_url($this->baseurl, array($this->pagevar=>$lastpageactual)), $lastpage, array('class'=>'last')); 2458 } 2459 2460 $pagenum = $this->page + 1; 2461 2462 if ($pagenum != $lastpage) { 2463 $this->nextlink = html_writer::link(new moodle_url($this->baseurl, array($this->pagevar=>$pagenum)), get_string('next'), array('class'=>'next')); 2464 } 2465 } 2466 } 2467 } 2468 2469 /** 2470 * This class represents how a block appears on a page. 2471 * 2472 * During output, each block instance is asked to return a block_contents object, 2473 * those are then passed to the $OUTPUT->block function for display. 2474 * 2475 * contents should probably be generated using a moodle_block_..._renderer. 2476 * 2477 * Other block-like things that need to appear on the page, for example the 2478 * add new block UI, are also represented as block_contents objects. 2479 * 2480 * @copyright 2009 Tim Hunt 2481 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 2482 * @since Moodle 2.0 2483 * @package core 2484 * @category output 2485 */ 2486 class block_contents { 2487 2488 /** Used when the block cannot be collapsed **/ 2489 const NOT_HIDEABLE = 0; 2490 2491 /** Used when the block can be collapsed but currently is not **/ 2492 const VISIBLE = 1; 2493 2494 /** Used when the block has been collapsed **/ 2495 const HIDDEN = 2; 2496 2497 /** 2498 * @var int Used to set $skipid. 2499 */ 2500 protected static $idcounter = 1; 2501 2502 /** 2503 * @var int All the blocks (or things that look like blocks) printed on 2504 * a page are given a unique number that can be used to construct id="" attributes. 2505 * This is set automatically be the {@link prepare()} method. 2506 * Do not try to set it manually. 2507 */ 2508 public $skipid; 2509 2510 /** 2511 * @var int If this is the contents of a real block, this should be set 2512 * to the block_instance.id. Otherwise this should be set to 0. 2513 */ 2514 public $blockinstanceid = 0; 2515 2516 /** 2517 * @var int If this is a real block instance, and there is a corresponding 2518 * block_position.id for the block on this page, this should be set to that id. 2519 * Otherwise it should be 0. 2520 */ 2521 public $blockpositionid = 0; 2522 2523 /** 2524 * @var array An array of attribute => value pairs that are put on the outer div of this 2525 * block. {@link $id} and {@link $classes} attributes should be set separately. 2526 */ 2527 public $attributes; 2528 2529 /** 2530 * @var string The title of this block. If this came from user input, it should already 2531 * have had format_string() processing done on it. This will be output inside 2532 * <h2> tags. Please do not cause invalid XHTML. 2533 */ 2534 public $title = ''; 2535 2536 /** 2537 * @var string The label to use when the block does not, or will not have a visible title. 2538 * You should never set this as well as title... it will just be ignored. 2539 */ 2540 public $arialabel = ''; 2541 2542 /** 2543 * @var string HTML for the content 2544 */ 2545 public $content = ''; 2546 2547 /** 2548 * @var array An alternative to $content, it you want a list of things with optional icons. 2549 */ 2550 public $footer = ''; 2551 2552 /** 2553 * @var string Any small print that should appear under the block to explain 2554 * to the teacher about the block, for example 'This is a sticky block that was 2555 * added in the system context.' 2556 */ 2557 public $annotation = ''; 2558 2559 /** 2560 * @var int One of the constants NOT_HIDEABLE, VISIBLE, HIDDEN. Whether 2561 * the user can toggle whether this block is visible. 2562 */ 2563 public $collapsible = self::NOT_HIDEABLE; 2564 2565 /** 2566 * Set this to true if the block is dockable. 2567 * @var bool 2568 */ 2569 public $dockable = false; 2570 2571 /** 2572 * @var array A (possibly empty) array of editing controls. Each element of 2573 * this array should be an array('url' => $url, 'icon' => $icon, 'caption' => $caption). 2574 * $icon is the icon name. Fed to $OUTPUT->pix_url. 2575 */ 2576 public $controls = array(); 2577 2578 2579 /** 2580 * Create new instance of block content 2581 * @param array $attributes 2582 */ 2583 public function __construct(array $attributes = null) { 2584 $this->skipid = self::$idcounter; 2585 self::$idcounter += 1; 2586 2587 if ($attributes) { 2588 // standard block 2589 $this->attributes = $attributes; 2590 } else { 2591 // simple "fake" blocks used in some modules and "Add new block" block 2592 $this->attributes = array('class'=>'block'); 2593 } 2594 } 2595 2596 /** 2597 * Add html class to block 2598 * 2599 * @param string $class 2600 */ 2601 public function add_class($class) { 2602 $this->attributes['class'] .= ' '.$class; 2603 } 2604 } 2605 2606 2607 /** 2608 * This class represents a target for where a block can go when it is being moved. 2609 * 2610 * This needs to be rendered as a form with the given hidden from fields, and 2611 * clicking anywhere in the form should submit it. The form action should be 2612 * $PAGE->url. 2613 * 2614 * @copyright 2009 Tim Hunt 2615 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 2616 * @since Moodle 2.0 2617 * @package core 2618 * @category output 2619 */ 2620 class block_move_target { 2621 2622 /** 2623 * @var moodle_url Move url 2624 */ 2625 public $url; 2626 2627 /** 2628 * Constructor 2629 * @param moodle_url $url 2630 */ 2631 public function __construct(moodle_url $url) { 2632 $this->url = $url; 2633 } 2634 } 2635 2636 /** 2637 * Custom menu item 2638 * 2639 * This class is used to represent one item within a custom menu that may or may 2640 * not have children. 2641 * 2642 * @copyright 2010 Sam Hemelryk 2643 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 2644 * @since Moodle 2.0 2645 * @package core 2646 * @category output 2647 */ 2648 class custom_menu_item implements renderable { 2649 2650 /** 2651 * @var string The text to show for the item 2652 */ 2653 protected $text; 2654 2655 /** 2656 * @var moodle_url The link to give the icon if it has no children 2657 */ 2658 protected $url; 2659 2660 /** 2661 * @var string A title to apply to the item. By default the text 2662 */ 2663 protected $title; 2664 2665 /** 2666 * @var int A sort order for the item, not necessary if you order things in 2667 * the CFG var. 2668 */ 2669 protected $sort; 2670 2671 /** 2672 * @var custom_menu_item A reference to the parent for this item or NULL if 2673 * it is a top level item 2674 */ 2675 protected $parent; 2676 2677 /** 2678 * @var array A array in which to store children this item has. 2679 */ 2680 protected $children = array(); 2681 2682 /** 2683 * @var int A reference to the sort var of the last child that was added 2684 */ 2685 protected $lastsort = 0; 2686 2687 /** 2688 * Constructs the new custom menu item 2689 * 2690 * @param string $text 2691 * @param moodle_url $url A moodle url to apply as the link for this item [Optional] 2692 * @param string $title A title to apply to this item [Optional] 2693 * @param int $sort A sort or to use if we need to sort differently [Optional] 2694 * @param custom_menu_item $parent A reference to the parent custom_menu_item this child 2695 * belongs to, only if the child has a parent. [Optional] 2696 */ 2697 public function __construct($text, moodle_url $url=null, $title=null, $sort = null, custom_menu_item $parent = null) { 2698 $this->text = $text; 2699 $this->url = $url; 2700 $this->title = $title; 2701 $this->sort = (int)$sort; 2702 $this->parent = $parent; 2703 } 2704 2705 /** 2706 * Adds a custom menu item as a child of this node given its properties. 2707 * 2708 * @param string $text 2709 * @param moodle_url $url 2710 * @param string $title 2711 * @param int $sort 2712 * @return custom_menu_item 2713 */ 2714 public function add($text, moodle_url $url = null, $title = null, $sort = null) { 2715 $key = count($this->children); 2716 if (empty($sort)) { 2717 $sort = $this->lastsort + 1; 2718 } 2719 $this->children[$key] = new custom_menu_item($text, $url, $title, $sort, $this); 2720 $this->lastsort = (int)$sort; 2721 return $this->children[$key]; 2722 } 2723 2724 /** 2725 * Removes a custom menu item that is a child or descendant to the current menu. 2726 * 2727 * Returns true if child was found and removed. 2728 * 2729 * @param custom_menu_item $menuitem 2730 * @return bool 2731 */ 2732 public function remove_child(custom_menu_item $menuitem) { 2733 $removed = false; 2734 if (($key = array_search($menuitem, $this->children)) !== false) { 2735 unset($this->children[$key]); 2736 $this->children = array_values($this->children); 2737 $removed = true; 2738 } else { 2739 foreach ($this->children as $child) { 2740 if ($removed = $child->remove_child($menuitem)) { 2741 break; 2742 } 2743 } 2744 } 2745 return $removed; 2746 } 2747 2748 /** 2749 * Returns the text for this item 2750 * @return string 2751 */ 2752 public function get_text() { 2753 return $this->text; 2754 } 2755 2756 /** 2757 * Returns the url for this item 2758 * @return moodle_url 2759 */ 2760 public function get_url() { 2761 return $this->url; 2762 } 2763 2764 /** 2765 * Returns the title for this item 2766 * @return string 2767 */ 2768 public function get_title() { 2769 return $this->title; 2770 } 2771 2772 /** 2773 * Sorts and returns the children for this item 2774 * @return array 2775 */ 2776 public function get_children() { 2777 $this->sort(); 2778 return $this->children; 2779 } 2780 2781 /** 2782 * Gets the sort order for this child 2783 * @return int 2784 */ 2785 public function get_sort_order() { 2786 return $this->sort; 2787 } 2788 2789 /** 2790 * Gets the parent this child belong to 2791 * @return custom_menu_item 2792 */ 2793 public function get_parent() { 2794 return $this->parent; 2795 } 2796 2797 /** 2798 * Sorts the children this item has 2799 */ 2800 public function sort() { 2801 usort($this->children, array('custom_menu','sort_custom_menu_items')); 2802 } 2803 2804 /** 2805 * Returns true if this item has any children 2806 * @return bool 2807 */ 2808 public function has_children() { 2809 return (count($this->children) > 0); 2810 } 2811 2812 /** 2813 * Sets the text for the node 2814 * @param string $text 2815 */ 2816 public function set_text($text) { 2817 $this->text = (string)$text; 2818 } 2819 2820 /** 2821 * Sets the title for the node 2822 * @param string $title 2823 */ 2824 public function set_title($title) { 2825 $this->title = (string)$title; 2826 } 2827 2828 /** 2829 * Sets the url for the node 2830 * @param moodle_url $url 2831 */ 2832 public function set_url(moodle_url $url) { 2833 $this->url = $url; 2834 } 2835 } 2836 2837 /** 2838 * Custom menu class 2839 * 2840 * This class is used to operate a custom menu that can be rendered for the page. 2841 * The custom menu is built using $CFG->custommenuitems and is a structured collection 2842 * of custom_menu_item nodes that can be rendered by the core renderer. 2843 * 2844 * To configure the custom menu: 2845 * Settings: Administration > Appearance > Themes > Theme settings 2846 * 2847 * @copyright 2010 Sam Hemelryk 2848 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 2849 * @since Moodle 2.0 2850 * @package core 2851 * @category output 2852 */ 2853 class custom_menu extends custom_menu_item { 2854 2855 /** 2856 * @var string The language we should render for, null disables multilang support. 2857 */ 2858 protected $currentlanguage = null; 2859 2860 /** 2861 * Creates the custom menu 2862 * 2863 * @param string $definition the menu items definition in syntax required by {@link convert_text_to_menu_nodes()} 2864 * @param string $currentlanguage the current language code, null disables multilang support 2865 */ 2866 public function __construct($definition = '', $currentlanguage = null) { 2867 $this->currentlanguage = $currentlanguage; 2868 parent::__construct('root'); // create virtual root element of the menu 2869 if (!empty($definition)) { 2870 $this->override_children(self::convert_text_to_menu_nodes($definition, $currentlanguage)); 2871 } 2872 } 2873 2874 /** 2875 * Overrides the children of this custom menu. Useful when getting children 2876 * from $CFG->custommenuitems 2877 * 2878 * @param array $children 2879 */ 2880 public function override_children(array $children) { 2881 $this->children = array(); 2882 foreach ($children as $child) { 2883 if ($child instanceof custom_menu_item) { 2884 $this->children[] = $child; 2885 } 2886 } 2887 } 2888 2889 /** 2890 * Converts a string into a structured array of custom_menu_items which can 2891 * then be added to a custom menu. 2892 * 2893 * Structure: 2894 * text|url|title|langs 2895 * The number of hyphens at the start determines the depth of the item. The 2896 * languages are optional, comma separated list of languages the line is for. 2897 * 2898 * Example structure: 2899 * First level first item|http://www.moodle.com/ 2900 * -Second level first item|http://www.moodle.com/partners/ 2901 * -Second level second item|http://www.moodle.com/hq/ 2902 * --Third level first item|http://www.moodle.com/jobs/ 2903 * -Second level third item|http://www.moodle.com/development/ 2904 * First level second item|http://www.moodle.com/feedback/ 2905 * First level third item 2906 * English only|http://moodle.com|English only item|en 2907 * German only|http://moodle.de|Deutsch|de,de_du,de_kids 2908 * 2909 * 2910 * @static 2911 * @param string $text the menu items definition 2912 * @param string $language the language code, null disables multilang support 2913 * @return array 2914 */ 2915 public static function convert_text_to_menu_nodes($text, $language = null) { 2916 $root = new custom_menu(); 2917 $lastitem = $root; 2918 $lastdepth = 0; 2919 $hiddenitems = array(); 2920 $lines = explode("\n", $text); 2921 foreach ($lines as $linenumber => $line) { 2922 $line = trim($line); 2923 if (strlen($line) == 0) { 2924 continue; 2925 } 2926 // Parse item settings. 2927 $itemtext = null; 2928 $itemurl = null; 2929 $itemtitle = null; 2930 $itemvisible = true; 2931 $settings = explode('|', $line); 2932 foreach ($settings as $i => $setting) { 2933 $setting = trim($setting); 2934 if (!empty($setting)) { 2935 switch ($i) { 2936 case 0: 2937 $itemtext = ltrim($setting, '-'); 2938 $itemtitle = $itemtext; 2939 break; 2940 case 1: 2941 try { 2942 $itemurl = new moodle_url($setting); 2943 } catch (moodle_exception $exception) { 2944 // We're not actually worried about this, we don't want to mess up the display 2945 // just for a wrongly entered URL. 2946 $itemurl = null; 2947 } 2948 break; 2949 case 2: 2950 $itemtitle = $setting; 2951 break; 2952 case 3: 2953 if (!empty($language)) { 2954 $itemlanguages = array_map('trim', explode(',', $setting)); 2955 $itemvisible &= in_array($language, $itemlanguages); 2956 } 2957 break; 2958 } 2959 } 2960 } 2961 // Get depth of new item. 2962 preg_match('/^(\-*)/', $line, $match); 2963 $itemdepth = strlen($match[1]) + 1; 2964 // Find parent item for new item. 2965 while (($lastdepth - $itemdepth) >= 0) { 2966 $lastitem = $lastitem->get_parent(); 2967 $lastdepth--; 2968 } 2969 $lastitem = $lastitem->add($itemtext, $itemurl, $itemtitle, $linenumber + 1); 2970 $lastdepth++; 2971 if (!$itemvisible) { 2972 $hiddenitems[] = $lastitem; 2973 } 2974 } 2975 foreach ($hiddenitems as $item) { 2976 $item->parent->remove_child($item); 2977 } 2978 return $root->get_children(); 2979 } 2980 2981 /** 2982 * Sorts two custom menu items 2983 * 2984 * This function is designed to be used with the usort method 2985 * usort($this->children, array('custom_menu','sort_custom_menu_items')); 2986 * 2987 * @static 2988 * @param custom_menu_item $itema 2989 * @param custom_menu_item $itemb 2990 * @return int 2991 */ 2992 public static function sort_custom_menu_items(custom_menu_item $itema, custom_menu_item $itemb) { 2993 $itema = $itema->get_sort_order(); 2994 $itemb = $itemb->get_sort_order(); 2995 if ($itema == $itemb) { 2996 return 0; 2997 } 2998 return ($itema > $itemb) ? +1 : -1; 2999 } 3000 } 3001 3002 /** 3003 * Stores one tab 3004 * 3005 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 3006 * @package core 3007 */ 3008 class tabobject implements renderable { 3009 /** @var string unique id of the tab in this tree, it is used to find selected and/or inactive tabs */ 3010 var $id; 3011 /** @var moodle_url|string link */ 3012 var $link; 3013 /** @var string text on the tab */ 3014 var $text; 3015 /** @var string title under the link, by defaul equals to text */ 3016 var $title; 3017 /** @var bool whether to display a link under the tab name when it's selected */ 3018 var $linkedwhenselected = false; 3019 /** @var bool whether the tab is inactive */ 3020 var $inactive = false; 3021 /** @var bool indicates that this tab's child is selected */ 3022 var $activated = false; 3023 /** @var bool indicates that this tab is selected */ 3024 var $selected = false; 3025 /** @var array stores children tabobjects */ 3026 var $subtree = array(); 3027 /** @var int level of tab in the tree, 0 for root (instance of tabtree), 1 for the first row of tabs */ 3028 var $level = 1; 3029 3030 /** 3031 * Constructor 3032 * 3033 * @param string $id unique id of the tab in this tree, it is used to find selected and/or inactive tabs 3034 * @param string|moodle_url $link 3035 * @param string $text text on the tab 3036 * @param string $title title under the link, by defaul equals to text 3037 * @param bool $linkedwhenselected whether to display a link under the tab name when it's selected 3038 */ 3039 public function __construct($id, $link = null, $text = '', $title = '', $linkedwhenselected = false) { 3040 $this->id = $id; 3041 $this->link = $link; 3042 $this->text = $text; 3043 $this->title = $title ? $title : $text; 3044 $this->linkedwhenselected = $linkedwhenselected; 3045 } 3046 3047 /** 3048 * Travels through tree and finds the tab to mark as selected, all parents are automatically marked as activated 3049 * 3050 * @param string $selected the id of the selected tab (whatever row it's on), 3051 * if null marks all tabs as unselected 3052 * @return bool whether this tab is selected or contains selected tab in its subtree 3053 */ 3054 protected function set_selected($selected) { 3055 if ((string)$selected === (string)$this->id) { 3056 $this->selected = true; 3057 // This tab is selected. No need to travel through subtree. 3058 return true; 3059 } 3060 foreach ($this->subtree as $subitem) { 3061 if ($subitem->set_selected($selected)) { 3062 // This tab has child that is selected. Mark it as activated. No need to check other children. 3063 $this->activated = true; 3064 return true; 3065 } 3066 } 3067 return false; 3068 } 3069 3070 /** 3071 * Travels through tree and finds a tab with specified id 3072 * 3073 * @param string $id 3074 * @return tabtree|null 3075 */ 3076 public function find($id) { 3077 if ((string)$this->id === (string)$id) { 3078 return $this; 3079 } 3080 foreach ($this->subtree as $tab) { 3081 if ($obj = $tab->find($id)) { 3082 return $obj; 3083 } 3084 } 3085 return null; 3086 } 3087 3088 /** 3089 * Allows to mark each tab's level in the tree before rendering. 3090 * 3091 * @param int $level 3092 */ 3093 protected function set_level($level) { 3094 $this->level = $level; 3095 foreach ($this->subtree as $tab) { 3096 $tab->set_level($level + 1); 3097 } 3098 } 3099 } 3100 3101 /** 3102 * Renderable for the main page header. 3103 * 3104 * @package core 3105 * @category output 3106 * @since 2.9 3107 * @copyright 2015 Adrian Greeve <adrian@moodle.com> 3108 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 3109 */ 3110 class context_header implements renderable { 3111 3112 /** 3113 * @var string $heading Main heading. 3114 */ 3115 public $heading; 3116 /** 3117 * @var int $headinglevel Main heading 'h' tag level. 3118 */ 3119 public $headinglevel; 3120 /** 3121 * @var string|null $imagedata HTML code for the picture in the page header. 3122 */ 3123 public $imagedata; 3124 /** 3125 * @var array $additionalbuttons Additional buttons for the header e.g. Messaging button for the user header. 3126 * array elements - title => alternate text for the image, or if no image is available the button text. 3127 * url => Link for the button to head to. Should be a moodle_url. 3128 * image => location to the image, or name of the image in /pix/t/{image name}. 3129 * linkattributes => additional attributes for the <a href> element. 3130 * page => page object. Don't include if the image is an external image. 3131 */ 3132 public $additionalbuttons; 3133 3134 /** 3135 * Constructor. 3136 * 3137 * @param string $heading Main heading data. 3138 * @param int $headinglevel Main heading 'h' tag level. 3139 * @param string|null $imagedata HTML code for the picture in the page header. 3140 * @param string $additionalbuttons Buttons for the header e.g. Messaging button for the user header. 3141 */ 3142 public function __construct($heading = null, $headinglevel = 1, $imagedata = null, $additionalbuttons = null) { 3143 3144 $this->heading = $heading; 3145 $this->headinglevel = $headinglevel; 3146 $this->imagedata = $imagedata; 3147 $this->additionalbuttons = $additionalbuttons; 3148 // If we have buttons then format them. 3149 if (isset($this->additionalbuttons)) { 3150 $this->format_button_images(); 3151 } 3152 } 3153 3154 /** 3155 * Adds an array element for a formatted image. 3156 */ 3157 protected function format_button_images() { 3158 3159 foreach ($this->additionalbuttons as $buttontype => $button) { 3160 $page = $button['page']; 3161 // If no image is provided then just use the title. 3162 if (!isset($button['image'])) { 3163 $this->additionalbuttons[$buttontype]['formattedimage'] = $button['title']; 3164 } else { 3165 // Check to see if this is an internal Moodle icon. 3166 $internalimage = $page->theme->resolve_image_location('t/' . $button['image'], 'moodle'); 3167 if ($internalimage) { 3168 $this->additionalbuttons[$buttontype]['formattedimage'] = 't/' . $button['image']; 3169 } else { 3170 // Treat as an external image. 3171 $this->additionalbuttons[$buttontype]['formattedimage'] = $button['image']; 3172 } 3173 } 3174 // Add the bootstrap 'btn' class for formatting. 3175 $this->additionalbuttons[$buttontype]['linkattributes'] = array_merge($button['linkattributes'], 3176 array('class' => 'btn')); 3177 } 3178 } 3179 } 3180 3181 /** 3182 * Stores tabs list 3183 * 3184 * Example how to print a single line tabs: 3185 * $rows = array( 3186 * new tabobject(...), 3187 * new tabobject(...) 3188 * ); 3189 * echo $OUTPUT->tabtree($rows, $selectedid); 3190 * 3191 * Multiple row tabs may not look good on some devices but if you want to use them 3192 * you can specify ->subtree for the active tabobject. 3193 * 3194 * @copyright 2013 Marina Glancy 3195 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 3196 * @since Moodle 2.5 3197 * @package core 3198 * @category output 3199 */ 3200 class tabtree extends tabobject { 3201 /** 3202 * Constuctor 3203 * 3204 * It is highly recommended to call constructor when list of tabs is already 3205 * populated, this way you ensure that selected and inactive tabs are located 3206 * and attribute level is set correctly. 3207 * 3208 * @param array $tabs array of tabs, each of them may have it's own ->subtree 3209 * @param string|null $selected which tab to mark as selected, all parent tabs will 3210 * automatically be marked as activated 3211 * @param array|string|null $inactive list of ids of inactive tabs, regardless of 3212 * their level. Note that you can as weel specify tabobject::$inactive for separate instances 3213 */ 3214 public function __construct($tabs, $selected = null, $inactive = null) { 3215 $this->subtree = $tabs; 3216 if ($selected !== null) { 3217 $this->set_selected($selected); 3218 } 3219 if ($inactive !== null) { 3220 if (is_array($inactive)) { 3221 foreach ($inactive as $id) { 3222 if ($tab = $this->find($id)) { 3223 $tab->inactive = true; 3224 } 3225 } 3226 } else if ($tab = $this->find($inactive)) { 3227 $tab->inactive = true; 3228 } 3229 } 3230 $this->set_level(0); 3231 } 3232 } 3233 3234 /** 3235 * An action menu. 3236 * 3237 * This action menu component takes a series of primary and secondary actions. 3238 * The primary actions are displayed permanently and the secondary attributes are displayed within a drop 3239 * down menu. 3240 * 3241 * @package core 3242 * @category output 3243 * @copyright 2013 Sam Hemelryk 3244 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 3245 */ 3246 class action_menu implements renderable { 3247 3248 /** 3249 * Top right alignment. 3250 */ 3251 const TL = 1; 3252 3253 /** 3254 * Top right alignment. 3255 */ 3256 const TR = 2; 3257 3258 /** 3259 * Top right alignment. 3260 */ 3261 const BL = 3; 3262 3263 /** 3264 * Top right alignment. 3265 */ 3266 const BR = 4; 3267 3268 /** 3269 * The instance number. This is unique to this instance of the action menu. 3270 * @var int 3271 */ 3272 protected $instance = 0; 3273 3274 /** 3275 * An array of primary actions. Please use {@link action_menu::add_primary_action()} to add actions. 3276 * @var array 3277 */ 3278 protected $primaryactions = array(); 3279 3280 /** 3281 * An array of secondary actions. Please use {@link action_menu::add_secondary_action()} to add actions. 3282 * @var array 3283 */ 3284 protected $secondaryactions = array(); 3285 3286 /** 3287 * An array of attributes added to the container of the action menu. 3288 * Initialised with defaults during construction. 3289 * @var array 3290 */ 3291 public $attributes = array(); 3292 /** 3293 * An array of attributes added to the container of the primary actions. 3294 * Initialised with defaults during construction. 3295 * @var array 3296 */ 3297 public $attributesprimary = array(); 3298 /** 3299 * An array of attributes added to the container of the secondary actions. 3300 * Initialised with defaults during construction. 3301 * @var array 3302 */ 3303 public $attributessecondary = array(); 3304 3305 /** 3306 * The string to use next to the icon for the action icon relating to the secondary (dropdown) menu. 3307 * @var array 3308 */ 3309 public $actiontext = null; 3310 3311 /** 3312 * An icon to use for the toggling the secondary menu (dropdown). 3313 * @var actionicon 3314 */ 3315 public $actionicon; 3316 3317 /** 3318 * Any text to use for the toggling the secondary menu (dropdown). 3319 * @var menutrigger 3320 */ 3321 public $menutrigger = ''; 3322 3323 /** 3324 * Place the action menu before all other actions. 3325 * @var prioritise 3326 */ 3327 public $prioritise = false; 3328 3329 /** 3330 * Constructs the action menu with the given items. 3331 * 3332 * @param array $actions An array of actions. 3333 */ 3334 public function __construct(array $actions = array()) { 3335 static $initialised = 0; 3336 $this->instance = $initialised; 3337 $initialised++; 3338 3339 $this->attributes = array( 3340 'id' => 'action-menu-'.$this->instance, 3341 'class' => 'moodle-actionmenu', 3342 'data-enhance' => 'moodle-core-actionmenu' 3343 ); 3344 $this->attributesprimary = array( 3345 'id' => 'action-menu-'.$this->instance.'-menubar', 3346 'class' => 'menubar', 3347 'role' => 'menubar' 3348 ); 3349 $this->attributessecondary = array( 3350 'id' => 'action-menu-'.$this->instance.'-menu', 3351 'class' => 'menu', 3352 'data-rel' => 'menu-content', 3353 'aria-labelledby' => 'action-menu-toggle-'.$this->instance, 3354 'role' => 'menu' 3355 ); 3356 $this->set_alignment(self::TR, self::BR); 3357 foreach ($actions as $action) { 3358 $this->add($action); 3359 } 3360 } 3361 3362 public function set_menu_trigger($trigger) { 3363 $this->menutrigger = $trigger; 3364 } 3365 3366 /** 3367 * Initialises JS required fore the action menu. 3368 * The JS is only required once as it manages all action menu's on the page. 3369 * 3370 * @param moodle_page $page 3371 */ 3372 public function initialise_js(moodle_page $page) { 3373 static $initialised = false; 3374 if (!$initialised) { 3375 $page->requires->yui_module('moodle-core-actionmenu', 'M.core.actionmenu.init'); 3376 $initialised = true; 3377 } 3378 } 3379 3380 /** 3381 * Adds an action to this action menu. 3382 * 3383 * @param action_menu_link|pix_icon|string $action 3384 */ 3385 public function add($action) { 3386 if ($action instanceof action_link) { 3387 if ($action->primary) { 3388 $this->add_primary_action($action); 3389 } else { 3390 $this->add_secondary_action($action); 3391 } 3392 } else if ($action instanceof pix_icon) { 3393 $this->add_primary_action($action); 3394 } else { 3395 $this->add_secondary_action($action); 3396 } 3397 } 3398 3399 /** 3400 * Adds a primary action to the action menu. 3401 * 3402 * @param action_menu_link|action_link|pix_icon|string $action 3403 */ 3404 public function add_primary_action($action) { 3405 if ($action instanceof action_link || $action instanceof pix_icon) { 3406 $action->attributes['role'] = 'menuitem'; 3407 if ($action instanceof action_menu_link) { 3408 $action->actionmenu = $this; 3409 } 3410 } 3411 $this->primaryactions[] = $action; 3412 } 3413 3414 /** 3415 * Adds a secondary action to the action menu. 3416 * 3417 * @param action_link|pix_icon|string $action 3418 */ 3419 public function add_secondary_action($action) { 3420 if ($action instanceof action_link || $action instanceof pix_icon) { 3421 $action->attributes['role'] = 'menuitem'; 3422 if ($action instanceof action_menu_link) { 3423 $action->actionmenu = $this; 3424 } 3425 } 3426 $this->secondaryactions[] = $action; 3427 } 3428 3429 /** 3430 * Returns the primary actions ready to be rendered. 3431 * 3432 * @param core_renderer $output The renderer to use for getting icons. 3433 * @return array 3434 */ 3435 public function get_primary_actions(core_renderer $output = null) { 3436 global $OUTPUT; 3437 if ($output === null) { 3438 $output = $OUTPUT; 3439 } 3440 $pixicon = $this->actionicon; 3441 $linkclasses = array('toggle-display'); 3442 3443 $title = ''; 3444 if (!empty($this->menutrigger)) { 3445 $pixicon = '<b class="caret"></b>'; 3446 $linkclasses[] = 'textmenu'; 3447 } else { 3448 $title = new lang_string('actions', 'moodle'); 3449 $this->actionicon = new pix_icon( 3450 't/edit_menu', 3451 '', 3452 'moodle', 3453 array('class' => 'iconsmall actionmenu', 'title' => '') 3454 ); 3455 $pixicon = $this->actionicon; 3456 } 3457 if ($pixicon instanceof renderable) { 3458 $pixicon = $output->render($pixicon); 3459 if ($pixicon instanceof pix_icon && isset($pixicon->attributes['alt'])) { 3460 $title = $pixicon->attributes['alt']; 3461 } 3462 } 3463 $string = ''; 3464 if ($this->actiontext) { 3465 $string = $this->actiontext; 3466 } 3467 $actions = $this->primaryactions; 3468 $attributes = array( 3469 'class' => implode(' ', $linkclasses), 3470 'title' => $title, 3471 'id' => 'action-menu-toggle-'.$this->instance, 3472 'role' => 'menuitem' 3473 ); 3474 $link = html_writer::link('#', $string . $this->menutrigger . $pixicon, $attributes); 3475 if ($this->prioritise) { 3476 array_unshift($actions, $link); 3477 } else { 3478 $actions[] = $link; 3479 } 3480 return $actions; 3481 } 3482 3483 /** 3484 * Returns the secondary actions ready to be rendered. 3485 * @return array 3486 */ 3487 public function get_secondary_actions() { 3488 return $this->secondaryactions; 3489 } 3490 3491 /** 3492 * Sets the selector that should be used to find the owning node of this menu. 3493 * @param string $selector A CSS/YUI selector to identify the owner of the menu. 3494 */ 3495 public function set_owner_selector($selector) { 3496 $this->attributes['data-owner'] = $selector; 3497 } 3498 3499 /** 3500 * Sets the alignment of the dialogue in relation to button used to toggle it. 3501 * 3502 * @param int $dialogue One of action_menu::TL, action_menu::TR, action_menu::BL, action_menu::BR. 3503 * @param int $button One of action_menu::TL, action_menu::TR, action_menu::BL, action_menu::BR. 3504 */ 3505 public function set_alignment($dialogue, $button) { 3506 if (isset($this->attributessecondary['data-align'])) { 3507 // We've already got one set, lets remove the old class so as to avoid troubles. 3508 $class = $this->attributessecondary['class']; 3509 $search = 'align-'.$this->attributessecondary['data-align']; 3510 $this->attributessecondary['class'] = str_replace($search, '', $class); 3511 } 3512 $align = $this->get_align_string($dialogue) . '-' . $this->get_align_string($button); 3513 $this->attributessecondary['data-align'] = $align; 3514 $this->attributessecondary['class'] .= ' align-'.$align; 3515 } 3516 3517 /** 3518 * Returns a string to describe the alignment. 3519 * 3520 * @param int $align One of action_menu::TL, action_menu::TR, action_menu::BL, action_menu::BR. 3521 * @return string 3522 */ 3523 protected function get_align_string($align) { 3524 switch ($align) { 3525 case self::TL : 3526 return 'tl'; 3527 case self::TR : 3528 return 'tr'; 3529 case self::BL : 3530 return 'bl'; 3531 case self::BR : 3532 return 'br'; 3533 default : 3534 return 'tl'; 3535 } 3536 } 3537 3538 /** 3539 * Sets a constraint for the dialogue. 3540 * 3541 * The constraint is applied when the dialogue is shown and limits the display of the dialogue to within the 3542 * element the constraint identifies. 3543 * 3544 * @param string $ancestorselector A snippet of CSS used to identify the ancestor to contrain the dialogue to. 3545 */ 3546 public function set_constraint($ancestorselector) { 3547 $this->attributessecondary['data-constraint'] = $ancestorselector; 3548 } 3549 3550 /** 3551 * If you call this method the action menu will be displayed but will not be enhanced. 3552 * 3553 * By not displaying the menu enhanced all items will be displayed in a single row. 3554 */ 3555 public function do_not_enhance() { 3556 unset($this->attributes['data-enhance']); 3557 } 3558 3559 /** 3560 * Returns true if this action menu will be enhanced. 3561 * 3562 * @return bool 3563 */ 3564 public function will_be_enhanced() { 3565 return isset($this->attributes['data-enhance']); 3566 } 3567 3568 /** 3569 * Sets nowrap on items. If true menu items should not wrap lines if they are longer than the available space. 3570 * 3571 * This property can be useful when the action menu is displayed within a parent element that is either floated 3572 * or relatively positioned. 3573 * In that situation the width of the menu is determined by the width of the parent element which may not be large 3574 * enough for the menu items without them wrapping. 3575 * This disables the wrapping so that the menu takes on the width of the longest item. 3576 * 3577 * @param bool $value If true nowrap gets set, if false it gets removed. Defaults to true. 3578 */ 3579 public function set_nowrap_on_items($value = true) { 3580 $class = 'nowrap-items'; 3581 if (!empty($this->attributes['class'])) { 3582 $pos = strpos($this->attributes['class'], $class); 3583 if ($value === true && $pos === false) { 3584 // The value is true and the class has not been set yet. Add it. 3585 $this->attributes['class'] .= ' '.$class; 3586 } else if ($value === false && $pos !== false) { 3587 // The value is false and the class has been set. Remove it. 3588 $this->attributes['class'] = substr($this->attributes['class'], $pos, strlen($class)); 3589 } 3590 } else if ($value) { 3591 // The value is true and the class has not been set yet. Add it. 3592 $this->attributes['class'] = $class; 3593 } 3594 } 3595 } 3596 3597 /** 3598 * An action menu filler 3599 * 3600 * @package core 3601 * @category output 3602 * @copyright 2013 Andrew Nicols 3603 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 3604 */ 3605 class action_menu_filler extends action_link implements renderable { 3606 3607 /** 3608 * True if this is a primary action. False if not. 3609 * @var bool 3610 */ 3611 public $primary = true; 3612 3613 /** 3614 * Constructs the object. 3615 */ 3616 public function __construct() { 3617 } 3618 } 3619 3620 /** 3621 * An action menu action 3622 * 3623 * @package core 3624 * @category output 3625 * @copyright 2013 Sam Hemelryk 3626 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 3627 */ 3628 class action_menu_link extends action_link implements renderable { 3629 3630 /** 3631 * True if this is a primary action. False if not. 3632 * @var bool 3633 */ 3634 public $primary = true; 3635 3636 /** 3637 * The action menu this link has been added to. 3638 * @var action_menu 3639 */ 3640 public $actionmenu = null; 3641 3642 /** 3643 * Constructs the object. 3644 * 3645 * @param moodle_url $url The URL for the action. 3646 * @param pix_icon $icon The icon to represent the action. 3647 * @param string $text The text to represent the action. 3648 * @param bool $primary Whether this is a primary action or not. 3649 * @param array $attributes Any attribtues associated with the action. 3650 */ 3651 public function __construct(moodle_url $url, pix_icon $icon = null, $text, $primary = true, array $attributes = array()) { 3652 parent::__construct($url, $text, null, $attributes, $icon); 3653 $this->primary = (bool)$primary; 3654 $this->add_class('menu-action'); 3655 $this->attributes['role'] = 'menuitem'; 3656 } 3657 } 3658 3659 /** 3660 * A primary action menu action 3661 * 3662 * @package core 3663 * @category output 3664 * @copyright 2013 Sam Hemelryk 3665 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 3666 */ 3667 class action_menu_link_primary extends action_menu_link { 3668 /** 3669 * Constructs the object. 3670 * 3671 * @param moodle_url $url 3672 * @param pix_icon $icon 3673 * @param string $text 3674 * @param array $attributes 3675 */ 3676 public function __construct(moodle_url $url, pix_icon $icon = null, $text, array $attributes = array()) { 3677 parent::__construct($url, $icon, $text, true, $attributes); 3678 } 3679 } 3680 3681 /** 3682 * A secondary action menu action 3683 * 3684 * @package core 3685 * @category output 3686 * @copyright 2013 Sam Hemelryk 3687 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 3688 */ 3689 class action_menu_link_secondary extends action_menu_link { 3690 /** 3691 * Constructs the object. 3692 * 3693 * @param moodle_url $url 3694 * @param pix_icon $icon 3695 * @param string $text 3696 * @param array $attributes 3697 */ 3698 public function __construct(moodle_url $url, pix_icon $icon = null, $text, array $attributes = array()) { 3699 parent::__construct($url, $icon, $text, false, $attributes); 3700 } 3701 } 3702 3703 /** 3704 * Represents a set of preferences groups. 3705 * 3706 * @package core 3707 * @category output 3708 * @copyright 2015 Frédéric Massart - FMCorz.net 3709 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 3710 */ 3711 class preferences_groups implements renderable { 3712 3713 /** 3714 * Array of preferences_group. 3715 * @var array 3716 */ 3717 public $groups; 3718 3719 /** 3720 * Constructor. 3721 * @param array $groups of preferences_group 3722 */ 3723 public function __construct($groups) { 3724 $this->groups = $groups; 3725 } 3726 3727 } 3728 3729 /** 3730 * Represents a group of preferences page link. 3731 * 3732 * @package core 3733 * @category output 3734 * @copyright 2015 Frédéric Massart - FMCorz.net 3735 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 3736 */ 3737 class preferences_group implements renderable { 3738 3739 /** 3740 * Title of the group. 3741 * @var string 3742 */ 3743 public $title; 3744 3745 /** 3746 * Array of navigation_node. 3747 * @var array 3748 */ 3749 public $nodes; 3750 3751 /** 3752 * Constructor. 3753 * @param string $title The title. 3754 * @param array $nodes of navigation_node. 3755 */ 3756 public function __construct($title, $nodes) { 3757 $this->title = $title; 3758 $this->nodes = $nodes; 3759 } 3760 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |