1 <?php
  2 /**
  3  * @package     Joomla.Platform
  4  * @subpackage  Form
  5  *
  6  * @copyright   Copyright (C) 2005 - 2017 Open Source Matters, Inc. All rights reserved.
  7  * @license     GNU General Public License version 2 or later; see LICENSE
  8  */
  9 
 10 defined('JPATH_PLATFORM') or die;
 11 
 12 /**
 13  * Form Field class for the Joomla Platform.
 14  * Provides a grouped list select field.
 15  *
 16  * @since  11.1
 17  */
 18 class JFormFieldGroupedList extends JFormField
 19 {
 20     /**
 21      * The form field type.
 22      *
 23      * @var    string
 24      * @since  11.1
 25      */
 26     protected $type = 'GroupedList';
 27 
 28     /**
 29      * Method to get the field option groups.
 30      *
 31      * @return  array  The field option objects as a nested array in groups.
 32      *
 33      * @since   11.1
 34      * @throws  UnexpectedValueException
 35      */
 36     protected function getGroups()
 37     {
 38         $groups = array();
 39         $label = 0;
 40 
 41         foreach ($this->element->children() as $element)
 42         {
 43             switch ($element->getName())
 44             {
 45                 // The element is an <option />
 46                 case 'option':
 47                     // Initialize the group if necessary.
 48                     if (!isset($groups[$label]))
 49                     {
 50                         $groups[$label] = array();
 51                     }
 52 
 53                     $disabled = (string) $element['disabled'];
 54                     $disabled = ($disabled == 'true' || $disabled == 'disabled' || $disabled == '1');
 55 
 56                     // Create a new option object based on the <option /> element.
 57                     $tmp = JHtml::_(
 58                         'select.option', ($element['value']) ? (string) $element['value'] : trim((string) $element),
 59                         JText::alt(trim((string) $element), preg_replace('/[^a-zA-Z0-9_\-]/', '_', $this->fieldname)), 'value', 'text',
 60                         $disabled
 61                     );
 62 
 63                     // Set some option attributes.
 64                     $tmp->class = (string) $element['class'];
 65 
 66                     // Set some JavaScript option attributes.
 67                     $tmp->onclick = (string) $element['onclick'];
 68 
 69                     // Add the option.
 70                     $groups[$label][] = $tmp;
 71                     break;
 72 
 73                 // The element is a <group />
 74                 case 'group':
 75                     // Get the group label.
 76                     if ($groupLabel = (string) $element['label'])
 77                     {
 78                         $label = JText::_($groupLabel);
 79                     }
 80 
 81                     // Initialize the group if necessary.
 82                     if (!isset($groups[$label]))
 83                     {
 84                         $groups[$label] = array();
 85                     }
 86 
 87                     // Iterate through the children and build an array of options.
 88                     foreach ($element->children() as $option)
 89                     {
 90                         // Only add <option /> elements.
 91                         if ($option->getName() != 'option')
 92                         {
 93                             continue;
 94                         }
 95 
 96                         $disabled = (string) $option['disabled'];
 97                         $disabled = ($disabled == 'true' || $disabled == 'disabled' || $disabled == '1');
 98 
 99                         // Create a new option object based on the <option /> element.
100                         $tmp = JHtml::_(
101                             'select.option', ($option['value']) ? (string) $option['value'] : JText::_(trim((string) $option)),
102                             JText::_(trim((string) $option)), 'value', 'text', $disabled
103                         );
104 
105                         // Set some option attributes.
106                         $tmp->class = (string) $option['class'];
107 
108                         // Set some JavaScript option attributes.
109                         $tmp->onclick = (string) $option['onclick'];
110 
111                         // Add the option.
112                         $groups[$label][] = $tmp;
113                     }
114 
115                     if ($groupLabel)
116                     {
117                         $label = count($groups);
118                     }
119                     break;
120 
121                 // Unknown element type.
122                 default:
123                     throw new UnexpectedValueException(sprintf('Unsupported element %s in JFormFieldGroupedList', $element->getName()), 500);
124             }
125         }
126 
127         reset($groups);
128 
129         return $groups;
130     }
131 
132     /**
133      * Method to get the field input markup fora grouped list.
134      * Multiselect is enabled by using the multiple attribute.
135      *
136      * @return  string  The field input markup.
137      *
138      * @since   11.1
139      */
140     protected function getInput()
141     {
142         $html = array();
143         $attr = '';
144 
145         // Initialize some field attributes.
146         $attr .= !empty($this->class) ? ' class="' . $this->class . '"' : '';
147         $attr .= !empty($this->size) ? ' size="' . $this->size . '"' : '';
148         $attr .= $this->multiple ? ' multiple' : '';
149         $attr .= $this->required ? ' required aria-required="true"' : '';
150         $attr .= $this->autofocus ? ' autofocus' : '';
151 
152         // To avoid user's confusion, readonly="true" should imply disabled="true".
153         if ($this->readonly || $this->disabled)
154         {
155             $attr .= ' disabled="disabled"';
156         }
157 
158         // Initialize JavaScript field attributes.
159         $attr .= !empty($this->onchange) ? ' onchange="' . $this->onchange . '"' : '';
160 
161         // Get the field groups.
162         $groups = (array) $this->getGroups();
163 
164         // Create a read-only list (no name) with a hidden input to store the value.
165         if ($this->readonly)
166         {
167             $html[] = JHtml::_(
168                 'select.groupedlist', $groups, null,
169                 array(
170                     'list.attr' => $attr, 'id' => $this->id, 'list.select' => $this->value, 'group.items' => null, 'option.key.toHtml' => false,
171                     'option.text.toHtml' => false,
172                 )
173             );
174 
175             // E.g. form field type tag sends $this->value as array
176             if ($this->multiple && is_array($this->value))
177             {
178                 if (!count($this->value))
179                 {
180                     $this->value[] = '';
181                 }
182 
183                 foreach ($this->value as $value)
184                 {
185                     $html[] = '<input type="hidden" name="' . $this->name . '" value="' . htmlspecialchars($value, ENT_COMPAT, 'UTF-8') . '"/>';
186                 }
187             }
188             else
189             {
190                 $html[] = '<input type="hidden" name="' . $this->name . '" value="' . htmlspecialchars($this->value, ENT_COMPAT, 'UTF-8') . '"/>';
191             }
192         }
193 
194         // Create a regular list.
195         else
196         {
197             $html[] = JHtml::_(
198                 'select.groupedlist', $groups, $this->name,
199                 array(
200                     'list.attr' => $attr, 'id' => $this->id, 'list.select' => $this->value, 'group.items' => null, 'option.key.toHtml' => false,
201                     'option.text.toHtml' => false,
202                 )
203             );
204         }
205 
206         return implode($html);
207     }
208 }
209