. /** * Classes representing HTML elements, used by $OUTPUT methods * * Please see http://docs.moodle.org/en/Developement:How_Moodle_outputs_HTML * for an overview. * * @package moodlecore * @copyright 2009 Tim Hunt * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ /** * Interface marking other classes as suitable for renderer_base::render() * @author 2010 Petr Skoda (skodak) info@skodak.org */ interface renderable { // intentionally empty } /** * Data structure representing a user picture. * * @copyright 2009 Nicolas Connault, 2010 Petr Skoda * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @since Moodle 2.0 */ class user_picture implements renderable { /** * List of mandatory fields in user record here. * @var string */ const FIELDS = 'id,picture,firstname,lastname,imagealt'; /** * @var object $user A user object with at least fields id, picture, imagealt, firstname and lastname set. */ public $user; /** * @var int $courseid The course id. Used when constructing the link to the user's profile, * page course id used if not specified. */ public $courseid; /** * @var bool $link add course profile link to image */ public $link = true; /** * @var int $size Size in pixels. Special values are (true/1 = 100px) and (false/0 = 35px) for backward compatibility */ public $size = 35; /** * @var boolean $alttext add non-blank alt-text to the image. * Default true, set to false when image alt just duplicates text in screenreaders. */ public $alttext = true; /** * @var boolean $popup Whether or not to open the link in a popup window. */ public $popup = false; /** * @var string Image class attribute */ public $class = 'userpicture'; /** * User picture constructor. * * @param object $user user record with at least id, picture, imagealt, firstname and lastname set. * @param array $options such as link, size, link, ... */ public function __construct(stdClass $user) { global $DB; static $fields = null; if (is_null($fields)) { $fields = explode(',', self::FIELDS); } if (empty($user->id)) { throw new coding_exception('User id is required when printing user avatar image.'); } // only touch the DB if we are missing data and complain loudly... $needrec = false; foreach ($fields as $field) { if (!array_key_exists($field, $user)) { $needrec = true; debugging('Missing '.$field.' property in $user object, this is a performance problem that needs to be fixed by a developer. ' .'Please use user_picture::fields() to get the full list of required fields.', DEBUG_DEVELOPER); break; } } if ($needrec) { $this->user = $DB->get_record('user', array('id'=>$user->id), self::FIELDS, MUST_EXIST); } else { $this->user = clone($user); } } /** * Returns a list of required user fields, usefull when fetching required user info from db. * @param string $tableprefix name of database table prefix in query * @return string */ public static function fields($tableprefix = '') { if ($tableprefix === '') { return self::FIELDS; } else { return "$tableprefix." . str_replace(',', ",$tableprefix.", self::FIELDS); } } } /** * Data structure representing a help icon. * * @copyright 2009 Nicolas Connault, 2010 Petr Skoda * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @since Moodle 2.0 */ class help_icon implements renderable { /** * @var string $page name of help page */ public $helppage; /** * @var string $title A descriptive text for title tooltip */ public $title = null; /** * @var string $component Component name, the same as in get_string() */ public $component = 'moodle'; /** * @var string $linktext Extra descriptive text next to the icon */ public $linktext = null; /** * Constructor: sets up the other components in case they are needed * @param string $page The keyword that defines a help page * @param string $title A descriptive text for accesibility only * @param string $component * @param bool $linktext add extra text to icon * @return void */ public function __construct($helppage, $title, $component = 'moodle') { if (empty($title)) { throw new coding_exception('A help_icon object requires a $text parameter'); } if (empty($helppage)) { throw new coding_exception('A help_icon object requires a $helppage parameter'); } $this->helppage = $helppage; $this->title = $title; $this->component = $component; } } /** * Data structure representing a simple form with only one button. * * @copyright 2009 Petr Skoda * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @since Moodle 2.0 */ class single_button implements renderable { /** * Target url * @var moodle_url */ var $url; /** * Button label * @var string */ var $label; /** * Form submit method * @var string post or get */ var $method = 'post'; /** * Wrapping div class * @var string * */ var $class = 'singlebutton'; /** * True if button disabled, false if normal * @var boolean */ var $disabled = false; /** * Button tooltip * @var string */ var $tooltip = null; /** * Form id * @var string */ var $formid; /** * List of attached actions * @var array of component_action */ var $actions = array(); /** * Constructor * @param string|moodle_url $url * @param string $label button text * @param string $method get or post submit method */ public function __construct(moodle_url $url, $label, $method='post') { $this->url = clone($url); $this->label = $label; $this->method = $method; } /** * Shortcut for adding a JS confirm dialog when the button is clicked. * The message must be a yes/no question. * @param string $message The yes/no confirmation question. If "Yes" is clicked, the original action will occur. * @return void */ public function add_confirm_action($confirmmessage) { $this->add_action(new component_action('click', 'M.util.show_confirm_dialog', array('message' => $confirmmessage))); } /** * Add action to the button. * @param component_action $action * @return void */ public function add_action(component_action $action) { $this->actions[] = $action; } } /** * Simple form with just one select field that gets submitted automatically. * If JS not enabled small go button is printed too. * * @copyright 2009 Petr Skoda * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @since Moodle 2.0 */ class single_select implements renderable { /** * Target url - includes hidden fields * @var moodle_url */ var $url; /** * Name of the select element. * @var string */ var $name; /** * @var array $options associative array value=>label ex.: * array(1=>'One, 2=>Two) * it is also possible to specify optgroup as complex label array ex.: * array(array('Odd'=>array(1=>'One', 3=>'Three)), array('Even'=>array(2=>'Two'))) * array(1=>'One', '--1uniquekey'=>array('More'=>array(2=>'Two', 3=>'Three'))) */ var $options; /** * Selected option * @var string */ var $selected; /** * Nothing selected * @var array */ var $nothing; /** * Extra select field attributes * @var array */ var $attributes = array(); /** * Button label * @var string */ var $label = ''; /** * Form submit method * @var string post or get */ var $method = 'get'; /** * Wrapping div class * @var string * */ var $class = 'singleselect'; /** * True if button disabled, false if normal * @var boolean */ var $disabled = false; /** * Button tooltip * @var string */ var $tooltip = null; /** * Form id * @var string */ var $formid = null; /** * List of attached actions * @var array of component_action */ var $helpicon = null; /** * Constructor * @param moodle_url $url form action target, includes hidden fields * @param string $name name of selection field - the changing parameter in url * @param array $options list of options * @param string $selected selected element * @param array $nothing */ public function __construct(moodle_url $url, $name, array $options, $selected='', $nothing=array(''=>'choosedots')) { $this->url = $url; $this->name = $name; $this->options = $options; $this->selected = $selected; $this->nothing = $nothing; } /** * Shortcut for adding a JS confirm dialog when the button is clicked. * The message must be a yes/no question. * @param string $message The yes/no confirmation question. If "Yes" is clicked, the original action will occur. * @return void */ public function add_confirm_action($confirmmessage) { $this->add_action(new component_action('submit', 'M.util.show_confirm_dialog', array('message' => $confirmmessage))); } /** * Add action to the button. * @param component_action $action * @return void */ public function add_action(component_action $action) { $this->actions[] = $action; } } /** * Data structure describing html link with special action attached. * @copyright 2010 Petr Skoda * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @since Moodle 2.0 */ class action_link implements renderable { /** * Href url * @var moodle_url */ var $url; /** * Link text * @var string HTML fragment */ var $text; /** * HTML attributes * @var array */ var $attributes; /** * List of actions attached to link * @var array of component_action */ var $actions; /** * Constructor * @param string|moodle_url $url * @param string $text HTML fragment * @param component_action $action * @param array $attributes associative array of html link attributes + disabled */ public function __construct(moodle_url $url, $text, component_action $action=null, array $attributes=null) { $this->url = clone($url); $this->text = $text; if ($action) { $this->add_action($action); } } /** * Add action to the link. * @param component_action $action * @return void */ public function add_action(component_action $action) { $this->actions[] = $action; } } // ==== HTML writer and helper classes, will be probably moved elsewhere ====== /** * Simple html output class * @copyright 2009 Tim Hunt, 2010 Petr Skoda */ class html_writer { /** * Outputs a tag with attributes and contents * @param string $tagname The name of tag ('a', 'img', 'span' etc.) * @param array $attributes The tag attributes (array('src' => $url, 'class' => 'class1') etc.) * @param string $contents What goes between the opening and closing tags * @return string HTML fragment */ public static function tag($tagname, array $attributes = null, $contents) { return self::start_tag($tagname, $attributes) . $contents . self::end_tag($tagname); } /** * Outputs an opening tag with attributes * @param string $tagname The name of tag ('a', 'img', 'span' etc.) * @param array $attributes The tag attributes (array('src' => $url, 'class' => 'class1') etc.) * @return string HTML fragment */ public static function start_tag($tagname, array $attributes = null) { return '<' . $tagname . self::attributes($attributes) . '>'; } /** * Outputs a closing tag * @param string $tagname The name of tag ('a', 'img', 'span' etc.) * @return string HTML fragment */ public static function end_tag($tagname) { return ''; } /** * Outputs an empty tag with attributes * @param string $tagname The name of tag ('input', 'img', 'br' etc.) * @param array $attributes The tag attributes (array('src' => $url, 'class' => 'class1') etc.) * @return string HTML fragment */ public static function empty_tag($tagname, array $attributes = null) { return '<' . $tagname . self::attributes($attributes) . ' />'; } /** * Outputs a HTML attribute and value * @param string $name The name of the attribute ('src', 'href', 'class' etc.) * @param string $value The value of the attribute. The value will be escaped with {@link s()} * @return string HTML fragment */ public static function attribute($name, $value) { if (is_array($value)) { debugging("Passed an array for the HTML attribute $name", DEBUG_DEVELOPER); } if ($value instanceof moodle_url) { return ' ' . $name . '="' . $value->out() . '"'; } // special case, we do not want these in output if ($value === null) { return ''; } // no sloppy trimming here! return ' ' . $name . '="' . s($value) . '"'; } /** * Outputs a list of HTML attributes and values * @param array $attributes The tag attributes (array('src' => $url, 'class' => 'class1') etc.) * The values will be escaped with {@link s()} * @return string HTML fragment */ public static function attributes(array $attributes = null) { $attributes = (array)$attributes; $output = ''; foreach ($attributes as $name => $value) { $output .= self::attribute($name, $value); } return $output; } /** * Generates random html element id. * @param string $base * @return string */ public static function random_id($base='random') { return uniqid($base); } /** * Generates a simple html link * @param string|moodle_url $url * @param string $text link txt * @param array $attributes extra html attributes * @return string HTML fragment */ public static function link($url, $text, array $attributes = null) { $attributes = (array)$attributes; $attributes['href'] = $url; return self::tag('a', $attributes, $text); } /** * generates a simple checkbox with optional label * @param string $name * @param string $value * @param bool $checked * @param string $label * @param array $attributes * @return string html fragment */ public static function checkbox($name, $value, $checked = true, $label = '', array $attributes = null) { $attributes = (array)$attributes; $output = ''; if ($label !== '' and !is_null($label)) { if (empty($attributes['id'])) { $attributes['id'] = self::random_id('checkbox_'); } } $attributes['type'] = 'checkbox'; $attributes['value'] = $value; $attributes['name'] = $name; $attributes['checked'] = $checked ? 'selected' : null; $output .= self::empty_tag('input', $attributes); if ($label !== '' and !is_null($label)) { $output .= self::tag('label', array('for'=>$attributes['id']), $label); } return $output; } /** * Generates a simple select form field * @param array $options associative array value=>label ex.: * array(1=>'One, 2=>Two) * it is also possible to specify optgroup as complex label array ex.: * array(array('Odd'=>array(1=>'One', 3=>'Three)), array('Even'=>array(2=>'Two'))) * array(1=>'One', '--1uniquekey'=>array('More'=>array(2=>'Two', 3=>'Three'))) * @param string $name name of select element * @param string|array $selected value or arary of values depending on multiple attribute * @param array|bool $nothing, add nothing selected option, or false of not added * @param array $attributes - html select element attributes * @return string HRML fragment */ public static function select(array $options, $name, $selected = '', $nothing = array(''=>'choosedots'), array $attributes = null) { $attributes = (array)$attributes; if (is_array($nothing)) { foreach ($nothing as $k=>$v) { if ($v === 'choose' or $v === 'choosedots') { $nothing[$k] = get_string('choosedots'); } } $options = $nothing + $options; // keep keys, do not override } else if (is_string($nothing) and $nothing !== '') { // BC $options = array(''=>$nothing) + $options; } // we may accept more values if multiple attribute specified $selected = (array)$selected; foreach ($selected as $k=>$v) { $selected[$k] = (string)$v; } if (!isset($attributes['id'])) { $id = 'menu'.$name; // name may contaion [], which would make an invalid id. e.g. numeric question type editing form, assignment quickgrading $id = str_replace('[', '', $id); $id = str_replace(']', '', $id); $attributes['id'] = $id; } if (!isset($attributes['class'])) { $class = 'menu'.$name; // name may contaion [], which would make an invalid class. e.g. numeric question type editing form, assignment quickgrading $class = str_replace('[', '', $class); $class = str_replace(']', '', $class); $attributes['class'] = $class; } $attributes['class'] = 'select ' . $attributes['class']; /// Add 'select' selector always $attributes['name'] = $name; $output = ''; foreach ($options as $value=>$label) { if (is_array($label)) { // ignore key, it just has to be unique $output .= self::select_optgroup(key($label), current($label), $selected); } else { $output .= self::select_option($label, $value, $selected); } } return self::tag('select', $attributes, $output); } private static function select_option($label, $value, array $selected) { $attributes = array(); $value = (string)$value; if (in_array($value, $selected, true)) { $attributes['selected'] = 'selected'; } $attributes['value'] = $value; return self::tag('option', $attributes, $label); } private static function select_optgroup($groupname, $options, array $selected) { if (empty($options)) { return ''; } $attributes = array('label'=>$groupname); $output = ''; foreach ($options as $value=>$label) { $output .= self::select_option($label, $value, $selected); } return self::tag('optgroup', $attributes, $output); } /** * Returns hidden input fields created from url parameters. * @param moodle_url $url * @param array $exclude list of excluded parameters * @return string HTML fragment */ public static function input_hidden_params(moodle_url $url, array $exclude = null) { $exclude = (array)$exclude; $params = $url->params(); foreach ($exclude as $key) { unset($params[$key]); } $output = ''; foreach ($params as $key => $value) { $attributes = array('type'=>'hidden', 'name'=>$key, 'value'=>$value); $output .= self::empty_tag('input', $attributes)."\n"; } return $output; } /** * Generate a script tag containing the the specified code. * * @param string $js the JavaScript code * @param moodle_url|string optional url of the external script, $code ignored if specified * @return string HTML, the code wrapped in