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 namespace core\output\local\dropdown; 18 19 use core\output\named_templatable; 20 use renderable; 21 22 /** 23 * Class to render a dropdown dialog element. 24 * 25 * A dropdown dialog allows to render any arbitrary HTML into a dropdown elements triggered 26 * by a button. 27 * 28 * @package core 29 * @category output 30 * @copyright 2023 Ferran Recio <ferran@moodle.com> 31 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 32 */ 33 class dialog implements named_templatable, renderable { 34 /** Dropdown dialog positions. */ 35 public const POSITION = [ 36 'start' => 'dropdown-menu-left', 37 'end' => 'dropdown-menu-right', 38 ]; 39 40 /** Dropdown dialog positions. */ 41 public const WIDTH = [ 42 'default' => '', 43 'big' => 'dialog-big', 44 'small' => 'dialog-small', 45 ]; 46 47 /** 48 * @var string content of dialog. 49 */ 50 protected $dialogcontent = ''; 51 52 /** 53 * @var bool if the footer should auto enable or not. 54 */ 55 protected $buttoncontent = true; 56 57 /** 58 * @var string trigger button CSS classes. 59 */ 60 protected $buttonclasses = ''; 61 62 /** 63 * @var string component CSS classes. 64 */ 65 protected $classes = ''; 66 67 /** 68 * @var string the dropdown position. 69 */ 70 protected $dropdownposition = self::POSITION['start']; 71 72 /** 73 * @var string dropdown preferred width. 74 */ 75 protected $dropdownwidth = self::WIDTH['default']; 76 77 78 /** 79 * @var array extra HTML attributes (attribute => value). 80 */ 81 protected $extras = []; 82 83 /** 84 * Constructor. 85 * 86 * The definition object could contain the following keys: 87 * - classes: component CSS classes. 88 * - buttonclasses: the button CSS classes. 89 * - dialogwidth: the dropdown width. 90 * - dropdownposition: the dropdown position. 91 * - extras: extra HTML attributes (attribute => value). 92 * 93 * @param string $buttoncontent the button content 94 * @param string $dialogcontent the footer content 95 * @param array $definition an optional array of the element definition 96 */ 97 public function __construct(string $buttoncontent, string $dialogcontent, array $definition = []) { 98 $this->buttoncontent = $buttoncontent; 99 $this->dialogcontent = $dialogcontent; 100 if (isset($definition['classes'])) { 101 $this->classes = $definition['classes']; 102 } 103 if (isset($definition['buttonclasses'])) { 104 $this->buttonclasses = $definition['buttonclasses']; 105 } 106 if (isset($definition['extras'])) { 107 $this->extras = $definition['extras']; 108 } 109 if (isset($definition['dialogwidth'])) { 110 $this->dropdownwidth = $definition['dialogwidth']; 111 } 112 if (isset($definition['dropdownposition'])) { 113 $this->dropdownposition = $definition['dropdownposition']; 114 } 115 } 116 117 /** 118 * Set the dialog contents. 119 * 120 * @param string $dialogcontent 121 */ 122 public function set_content(string $dialogcontent) { 123 $this->dialogcontent = $dialogcontent; 124 } 125 126 /** 127 * Set the button contents. 128 * 129 * @param string $buttoncontent 130 * @param string|null $buttonclasses the button classes 131 */ 132 public function set_button(string $buttoncontent, ?string $buttonclasses = null) { 133 $this->buttoncontent = $buttoncontent; 134 if ($buttonclasses !== null) { 135 $this->buttonclasses = $buttonclasses; 136 } 137 } 138 139 /** 140 * Set the dialog width. 141 * 142 * @param string $width 143 */ 144 public function set_dialog_width(string $width) { 145 $this->dropdownwidth = $width; 146 } 147 148 /** 149 * Add extra classes to trigger butotn. 150 * 151 * @param string $buttonclasses the extra classes 152 */ 153 public function set_button_classes(string $buttonclasses) { 154 $this->buttonclasses = $buttonclasses; 155 } 156 157 /** 158 * Add extra classes to the component. 159 * 160 * @param string $classes the extra classes 161 */ 162 public function set_classes(string $classes) { 163 $this->classes = $classes; 164 } 165 166 /** 167 * Add extra extras to the sticky footer element. 168 * 169 * @param string $attribute the extra attribute 170 * @param string $value the value 171 */ 172 public function add_extra(string $attribute, string $value) { 173 $this->extras[$attribute] = $value; 174 } 175 176 /** 177 * Set the button element id. 178 * 179 * @param string $value the value 180 */ 181 public function add_button_id(string $value) { 182 $this->extras['buttonid'] = $value; 183 } 184 185 /** 186 * Set the dropdown position. 187 * @param string $position the position 188 */ 189 public function set_position(string $position) { 190 $this->dropdownposition = $position; 191 } 192 193 /** 194 * Export this data so it can be used as the context for a mustache template (core/inplace_editable). 195 * 196 * @param \renderer_base $output typically, the renderer that's calling this function 197 * @return array data context for a mustache template 198 */ 199 public function export_for_template(\renderer_base $output): array { 200 $extras = []; 201 // Id is required to add JS controls to the dropdown. 202 $dropdownid = $this->extras['id'] ?? \html_writer::random_id('dropdownDialog_'); 203 if (isset($this->extras['id'])) { 204 unset($this->extras['id']); 205 } 206 foreach ($this->extras as $attribute => $value) { 207 $extras[] = [ 208 'attribute' => $attribute, 209 'value' => $value, 210 ]; 211 } 212 $data = [ 213 // Id is required for the correct HTML labelling. 214 'dropdownid' => $dropdownid, 215 'buttonid' => $this->extras['buttonid'] ?? \html_writer::random_id('dropwdownbutton_'), 216 'buttoncontent' => (string) $this->buttoncontent, 217 'dialogcontent' => (string) $this->dialogcontent, 218 'classes' => $this->classes, 219 'buttonclasses' => $this->buttonclasses, 220 'dialogclasses' => $this->dropdownwidth, 221 'extras' => $extras, 222 ]; 223 // Bootstrap 4 dropdown position still uses left and right literals. 224 $data["position"] = $this->dropdownposition; 225 if (right_to_left()) { 226 $rltposition = [ 227 self::POSITION['start'] => self::POSITION['end'], 228 self::POSITION['end'] => self::POSITION['end'], 229 ]; 230 $data["position"] = $rltposition[$this->dropdownposition]; 231 } 232 return $data; 233 } 234 235 /** 236 * Get the name of the template to use for this templatable. 237 * 238 * @param \renderer_base $renderer The renderer requesting the template name 239 * @return string the template name 240 */ 241 public function get_template_name(\renderer_base $renderer): string { 242 return 'core/local/dropdown/dialog'; 243 } 244 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body