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