MDL-49684 timezones: rewrite timezone support
[moodle.git] / lib / form / selectgroups.php
blob2d5dd635d3142701ae8c233dd17c940da194a8ba
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.
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/>.
18 /**
19 * select type form element
21 * Class to dynamically create an HTML SELECT with all options grouped in optgroups
23 * @package core_form
24 * @copyright 2007 Jamie Pratt <me@jamiep.org>
25 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
28 require_once('HTML/QuickForm/element.php');
30 /**
31 * select type form element
33 * Class to dynamically create an HTML SELECT with all options grouped in optgroups
35 * @package core_form
36 * @category form
37 * @copyright 2007 Jamie Pratt <me@jamiep.org>
38 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
40 class MoodleQuickForm_selectgroups extends HTML_QuickForm_element {
42 /** @var bool add choose option */
43 var $showchoose = false;
45 /** @var array Contains the select optgroups */
46 var $_optGroups = array();
48 /** @var string Default values of the SELECT */
49 var $_values = null;
51 /** @var string html for help button, if empty then no help */
52 var $_helpbutton='';
54 /** @var bool if true label will be hidden */
55 var $_hiddenLabel=false;
57 /**
58 * Class constructor
60 * @param string $elementName Select name attribute
61 * @param mixed $elementLabel Label(s) for the select
62 * @param array $optgrps Data to be used to populate options
63 * @param mixed $attributes Either a typical HTML attribute string or an associative array
64 * @param bool $showchoose add standard moodle "Choose..." option as first item
66 function MoodleQuickForm_selectgroups($elementName=null, $elementLabel=null, $optgrps=null, $attributes=null, $showchoose=false)
68 $this->showchoose = $showchoose;
69 HTML_QuickForm_element::HTML_QuickForm_element($elementName, $elementLabel, $attributes);
70 $this->_persistantFreeze = true;
71 $this->_type = 'selectgroups';
72 if (isset($optgrps)) {
73 $this->loadArrayOptGroups($optgrps);
77 /**
78 * Sets the default values of the select box
80 * @param mixed $values Array or comma delimited string of selected values
82 function setSelected($values)
84 if (is_string($values) && $this->getMultiple()) {
85 $values = preg_split("/[ ]?,[ ]?/", $values);
87 if (is_array($values)) {
88 $this->_values = array_values($values);
89 } else {
90 $this->_values = array($values);
94 /**
95 * Returns an array of the selected values
97 * @return array of selected values
99 function getSelected()
101 return $this->_values;
105 * Sets the input field name
107 * @param string $name Input field name attribute
109 function setName($name)
111 $this->updateAttributes(array('name' => $name));
115 * Returns the element name
117 * @return string
119 function getName()
121 return $this->getAttribute('name');
125 * Returns the element name (possibly with brackets appended)
127 * @return string
129 function getPrivateName()
131 if ($this->getAttribute('multiple')) {
132 return $this->getName() . '[]';
133 } else {
134 return $this->getName();
139 * Sets the value of the form element
141 * @param mixed $value Array or comma delimited string of selected values
143 function setValue($value)
145 $this->setSelected($value);
149 * Returns an array of the selected values
151 * @return array of selected values
153 function getValue()
155 return $this->_values;
159 * Sets the select field size, only applies to 'multiple' selects
161 * @param int $size Size of select field
163 function setSize($size)
165 $this->updateAttributes(array('size' => $size));
169 * Returns the select field size
171 * @return int
173 function getSize()
175 return $this->getAttribute('size');
179 * Sets the select mutiple attribute
181 * @param bool $multiple Whether the select supports multi-selections
183 function setMultiple($multiple)
185 if ($multiple) {
186 $this->updateAttributes(array('multiple' => 'multiple'));
187 } else {
188 $this->removeAttribute('multiple');
193 * Returns the select mutiple attribute
195 * @return bool true if multiple select, false otherwise
197 function getMultiple()
199 return (bool)$this->getAttribute('multiple');
203 * Loads the options from an associative array
205 * @param array $arr Associative array of options
206 * @param mixed $values (optional) Array or comma delimited string of selected values
207 * @return PEAR_Error|bool on error or true
208 * @throws PEAR_Error
210 function loadArrayOptGroups($arr, $values=null)
212 if (!is_array($arr)) {
213 return self::raiseError('Argument 1 of HTML_Select::loadArrayOptGroups is not a valid array');
215 if (isset($values)) {
216 $this->setSelected($values);
218 foreach ($arr as $key => $val) {
219 // Warning: new API since release 2.3
220 $this->addOptGroup($key, $val);
222 return true;
226 * Adds a new OPTION to the SELECT
228 * @param string $text Display text for the OPTION
229 * @param string $value Value for the OPTION
230 * @param mixed $attributes Either a typical HTML attribute string
231 * or an associative array
233 function addOptGroup($text, $value, $attributes=null)
235 if (null === $attributes) {
236 $attributes = array('label' => $text);
237 } else {
238 $attributes = $this->_parseAttributes($attributes);
239 $this->_updateAttrArray($attributes, array('label' => $text));
241 $index = count($this->_optGroups);
242 $this->_optGroups[$index] = array('attr' => $attributes);
243 $this->loadArrayOptions($index, $value);
247 * Loads the options from an associative array
249 * @param string $optgroup name of the options group
250 * @param array $arr Associative array of options
251 * @param mixed $values (optional) Array or comma delimited string of selected values
252 * @return PEAR_Error|bool on error or true
253 * @throws PEAR_Error
255 function loadArrayOptions($optgroup, $arr, $values=null)
257 if (!is_array($arr)) {
258 return self::raiseError('Argument 1 of HTML_Select::loadArray is not a valid array');
260 if (isset($values)) {
261 $this->setSelected($values);
263 foreach ($arr as $key => $val) {
264 // Warning: new API since release 2.3
265 $this->addOption($optgroup, $val, $key);
267 return true;
271 * Adds a new OPTION to an optgroup
273 * @param string $optgroup name of the option group
274 * @param string $text Display text for the OPTION
275 * @param string $value Value for the OPTION
276 * @param mixed $attributes Either a typical HTML attribute string
277 * or an associative array
279 function addOption($optgroup, $text, $value, $attributes=null)
281 if (null === $attributes) {
282 $attributes = array('value' => $value);
283 } else {
284 $attributes = $this->_parseAttributes($attributes);
285 if (isset($attributes['selected'])) {
286 // the 'selected' attribute will be set in toHtml()
287 $this->_removeAttr('selected', $attributes);
288 if (is_null($this->_values)) {
289 $this->_values = array($value);
290 } elseif (!in_array($value, $this->_values)) {
291 $this->_values[] = $value;
294 $this->_updateAttrArray($attributes, array('value' => $value));
296 $this->_optGroups[$optgroup]['options'][] = array('text' => $text, 'attr' => $attributes);
300 * Returns the SELECT in HTML
302 * @return string
304 function toHtml()
306 if ($this->_flagFrozen) {
307 return $this->getFrozenHtml();
308 } else {
309 $tabs = $this->_getTabs();
310 $strHtml = '';
312 if ($this->getComment() != '') {
313 $strHtml .= $tabs . '<!-- ' . $this->getComment() . " //-->\n";
316 if (!$this->getMultiple()) {
317 $attrString = $this->_getAttrString($this->_attributes);
318 } else {
319 $myName = $this->getName();
320 $this->setName($myName . '[]');
321 $attrString = $this->_getAttrString($this->_attributes);
322 $this->setName($myName);
324 $strHtml .= $tabs;
325 if ($this->_hiddenLabel){
326 $this->_generateId();
327 $strHtml .= '<label class="accesshide" for="'.$this->getAttribute('id').'" >'.
328 $this->getLabel().'</label>';
330 $strHtml .= '<select' . $attrString . ">\n";
331 if ($this->showchoose) {
332 $strHtml .= $tabs . "\t\t<option value=\"\">" . get_string('choose') . "...</option>\n";
334 foreach ($this->_optGroups as $optGroup) {
335 if (empty($optGroup['options'])) {
336 //xhtml strict
337 continue;
339 $strHtml .= $tabs . "\t<optgroup" . ($this->_getAttrString($optGroup['attr'])) . '>';
340 foreach ($optGroup['options'] as $option){
341 if (is_array($this->_values) && in_array((string)$option['attr']['value'], $this->_values)) {
342 $this->_updateAttrArray($option['attr'], array('selected' => 'selected'));
344 $strHtml .= $tabs . "\t\t<option" . $this->_getAttrString($option['attr']) . '>' .
345 $option['text'] . "</option>\n";
347 $strHtml .= $tabs . "\t</optgroup>\n";
349 return $strHtml . $tabs . '</select>';
354 * Returns the value of field without HTML tags
356 * @return string
358 function getFrozenHtml()
360 $value = array();
361 if (is_array($this->_values)) {
362 foreach ($this->_values as $key => $val) {
363 foreach ($this->_optGroups as $optGroup) {
364 for ($i = 0, $optCount = count($optGroup['options']); $i < $optCount; $i++) {
365 if ((string)$val == (string)$optGroup['options'][$i]['attr']['value']) {
366 $value[$key] = $optGroup['options'][$i]['text'];
367 break;
373 $html = empty($value)? '&nbsp;': join('<br />', $value);
374 if ($this->_persistantFreeze) {
375 $name = $this->getPrivateName();
376 // Only use id attribute if doing single hidden input
377 if (1 == count($value)) {
378 $id = $this->getAttribute('id');
379 $idAttr = isset($id)? array('id' => $id): array();
380 } else {
381 $idAttr = array();
383 foreach ($value as $key => $item) {
384 $html .= '<input' . $this->_getAttrString(array(
385 'type' => 'hidden',
386 'name' => $name,
387 'value' => $this->_values[$key]
388 ) + $idAttr) . ' />';
391 return $html;
395 * We check the options and return only the values that _could_ have been
396 * selected. We also return a scalar value if select is not "multiple"
398 * @param array $submitValues submitted values
399 * @param bool $assoc if true the retured value is associated array
400 * @return mixed
402 function exportValue(&$submitValues, $assoc = false)
404 if (empty($this->_optGroups)) {
405 return $this->_prepareValue(null, $assoc);
408 $value = $this->_findValue($submitValues);
409 if (is_null($value)) {
410 $value = $this->getValue();
412 $value = (array)$value;
414 $cleaned = array();
415 foreach ($value as $v) {
416 foreach ($this->_optGroups as $optGroup){
417 if (empty($optGroup['options'])) {
418 continue;
420 foreach ($optGroup['options'] as $option) {
421 if ((string)$option['attr']['value'] === (string)$v) {
422 $cleaned[] = (string)$option['attr']['value'];
423 break;
429 if (empty($cleaned)) {
430 return $this->_prepareValue(null, $assoc);
432 if ($this->getMultiple()) {
433 return $this->_prepareValue($cleaned, $assoc);
434 } else {
435 return $this->_prepareValue($cleaned[0], $assoc);
440 * Called by HTML_QuickForm whenever form event is made on this element
442 * @param string $event Name of event
443 * @param mixed $arg event arguments
444 * @param object $caller calling object
445 * @return bool
447 function onQuickFormEvent($event, $arg, &$caller)
449 if ('updateValue' == $event) {
450 $value = $this->_findValue($caller->_constantValues);
451 if (null === $value) {
452 $value = $this->_findValue($caller->_submitValues);
453 // Fix for bug #4465 & #5269
454 // XXX: should we push this to element::onQuickFormEvent()?
455 if (null === $value && (!$caller->isSubmitted() || !$this->getMultiple())) {
456 $value = $this->_findValue($caller->_defaultValues);
459 if (null !== $value) {
460 $this->setValue($value);
462 return true;
463 } else {
464 return parent::onQuickFormEvent($event, $arg, $caller);
469 * Sets label to be hidden
471 * @param bool $hiddenLabel sets if label should be hidden
473 function setHiddenLabel($hiddenLabel){
474 $this->_hiddenLabel = $hiddenLabel;
478 * get html for help button
480 * @return string html for help button
482 function getHelpButton(){
483 return $this->_helpbutton;
487 * Slightly different container template when frozen. Don't want to use a label tag
488 * with a for attribute in that case for the element label but instead use a div.
489 * Templates are defined in renderer constructor.
491 * @return string
493 function getElementTemplateType(){
494 if ($this->_flagFrozen){
495 return 'static';
496 } else {
497 return 'default';