diff --git a/wire/modules/Inputfield/InputfieldToggle/InputfieldToggle.css b/wire/modules/Inputfield/InputfieldToggle/InputfieldToggle.css new file mode 100644 index 00000000..5da8e41c --- /dev/null +++ b/wire/modules/Inputfield/InputfieldToggle/InputfieldToggle.css @@ -0,0 +1,43 @@ +.InputfieldToggleGroup { + display: flex; + float: left; +} + +.InputfieldToggleGroup input { + position: absolute !important; + clip: rect(0, 0, 0, 0); + height: 1px; + width: 1px; + border: 0; + overflow: hidden; +} + +.InputfieldToggleGroup label { + background-color: #eee; + color: rgba(0, 0, 0, 0.6); + line-height: 1; + text-align: center; + padding: 8px 16px; + margin-right: -1px; + border: 1px solid rgba(0,0,0,0.1); + font-size: 16px; +} + +.InputfieldToggleGroup label:hover { + cursor: pointer; +} + +.InputfieldToggleGroup input:checked + label { + background-color: #999; + color: #fff; + box-shadow: none; +} + +.InputfieldToggleGroup label:first-of-type { + border-radius: 4px 0 0 4px; +} + +.InputfieldToggleGroup label:last-of-type { + border-radius: 0 4px 4px 0; +} + diff --git a/wire/modules/Inputfield/InputfieldToggle/InputfieldToggle.js b/wire/modules/Inputfield/InputfieldToggle/InputfieldToggle.js new file mode 100644 index 00000000..b43612a7 --- /dev/null +++ b/wire/modules/Inputfield/InputfieldToggle/InputfieldToggle.js @@ -0,0 +1,85 @@ +function InputfieldToggleInit() { + + // this becomes true when we are in a click event, used to avoid double calls to handler + var isClick = false; + + // event handler for labels/inputs in a .InputfieldToggleUseDeselect container + function toggleInputEvent($input) { + + var cls = 'InputfieldToggleChecked'; + + // allow for labels as prev sibling of input or label as parent element of input + // var $label = $input.prev('label').length ? $input.prev('label') : $input.closest('label'); + var $prevInput = $input.closest('.Inputfield').find('input.' + cls); + // var $prevLabel = $prevInput.prev('label').length ? $prevInput.prev('label') : $prevInput.closest('label'); + + // check of another item was clicked when an existing selection was in place + if($prevInput.length && $prevInput.attr('id') != $input.attr('id')) { + // remove our custom class from existing selection + $prevInput.removeClass(cls).removeAttr('checked'); + } + + // check if clicked input was already checked + if($input.hasClass(cls) && $input.closest('.InputfieldToggleUseDeselect').length) { + // if clicked input was already checked, now make it un-checked + $input.removeAttr('checked').removeClass(cls); + // if this de-select was the first selection in the request, it's necessary to remove + // the checked attribute again a short while later for some reason + setTimeout(function() { $input.removeAttr('checked') }, 100); + } else { + // input was just checked (and wasn't before), so add our checked class to the input + // $input.attr('checked', 'checked').addClass(cls); + $input.addClass(cls); + } + } + + $(document).on('change', '.InputfieldToggle input', function() { + // change event for de-selectable radios + if(isClick) return false; + toggleInputEvent($(this)); + + }).on('click', '.InputfieldToggle label:not(.InputfieldHeader)', function() { + // click event for de-selectable radios + if(isClick) return false; + var $label = $(this); + var $input = $label.prev('input.InputfieldToggleChecked'); // toggle buttons + if(!$input.length) $input = $label.children('input.InputfieldToggleChecked'); // radios + if(!$input.length) return; + isClick = true; + toggleInputEvent($input); + setTimeout(function() { isClick = false; }, 200); + }); + + // button style for default toggle button group + // inherit colors from existing inputs and buttons + var $button = $('button.ui-button:eq(0)'); + var $input = $('.InputfieldForm input[type=text]:eq(0)'); + if($button.length && $input.length) { + var onBgcolor, onColor, offBgcolor, offColor, borderColor, style; + onBgcolor = $button.css('background-color'); + onColor = $button.css('color'); + offBgcolor = $input.css('background-color'); + offColor = $input.css('color'); + borderColor = $input.css('border-color'); + style = + ""; + + $('body').append(style); + } +} + + +jQuery(document).ready(function($) { + InputfieldToggleInit(); +}); \ No newline at end of file diff --git a/wire/modules/Inputfield/InputfieldToggle/InputfieldToggle.min.js b/wire/modules/Inputfield/InputfieldToggle/InputfieldToggle.min.js new file mode 100644 index 00000000..c8712430 --- /dev/null +++ b/wire/modules/Inputfield/InputfieldToggle/InputfieldToggle.min.js @@ -0,0 +1 @@ +function InputfieldToggleInit(){var isClick=false;function toggleInputEvent($input){var cls="InputfieldToggleChecked";var $prevInput=$input.closest(".Inputfield").find("input."+cls);if($prevInput.length&&$prevInput.attr("id")!=$input.attr("id")){$prevInput.removeClass(cls).removeAttr("checked")}if($input.hasClass(cls)&&$input.closest(".InputfieldToggleUseDeselect").length){$input.removeAttr("checked").removeClass(cls);setTimeout(function(){$input.removeAttr("checked")},100)}else{$input.addClass(cls)}}$(document).on("change",".InputfieldToggle input",function(){if(isClick)return false;toggleInputEvent($(this))}).on("click",".InputfieldToggle label:not(.InputfieldHeader)",function(){if(isClick)return false;var $label=$(this);var $input=$label.prev("input.InputfieldToggleChecked");if(!$input.length)$input=$label.children("input.InputfieldToggleChecked");if(!$input.length)return;isClick=true;toggleInputEvent($input);setTimeout(function(){isClick=false},200)});var $button=$("button.ui-button:eq(0)");var $input=$(".InputfieldForm input[type=text]:eq(0)");if($button.length&&$input.length){var onBgcolor,onColor,offBgcolor,offColor,borderColor,style;onBgcolor=$button.css("background-color");onColor=$button.css("color");offBgcolor=$input.css("background-color");offColor=$input.css("color");borderColor=$input.css("border-color");style="";$("body").append(style)}}jQuery(document).ready(function($){InputfieldToggleInit()}); \ No newline at end of file diff --git a/wire/modules/Inputfield/InputfieldToggle/InputfieldToggle.module b/wire/modules/Inputfield/InputfieldToggle/InputfieldToggle.module index a5587eaa..c89080fa 100644 --- a/wire/modules/Inputfield/InputfieldToggle/InputfieldToggle.module +++ b/wire/modules/Inputfield/InputfieldToggle/InputfieldToggle.module @@ -9,17 +9,17 @@ * ProcessWire 3.x, Copyright 2019 by Ryan Cramer * https://processwire.com * - * @property int $labelType - * @property int $valueType + * @property int $labelType Label type to use, see the labelType constants (default=labelTypeYes) + * @property int $valueType Type of value for methods that ask for it (use one of the valueType constants) * @property string $yesLabel Custom yes/on label - * @property string $noLabel Custom no/off label - * @property string $otherLabel Custom label for optional other value - * @property int|bool $useReverse - * @property int|bool $useOther - * @property bool|int $useVertical - * @property int $defaultValue - * @property int|string $defaultOption - * @property string $inputfieldClass + * @property string $noLabel Custom no/off label + * @property string $otherLabel Custom label for optional other value Label to use for "other" option + * @property int|bool $useReverse Reverse the order of the Yes/No options? (default=false) + * @property int|bool $useOther Use the "other" option? (default=false) + * @property bool|int $useVertical Use vertically oriented radio buttons? (default=false) + * @property bool|int $useDeselect Allow radios or toggles to be de-selected, enabling possibility of no-selection? (default=false) + * @property int|string $defaultOption Default selected value of 0, 1, 2 or '' (default='') + * @property string $inputfieldClass Inputfield class to use or blank for this toggle buttons (default='') * * @method InputfieldSelect|InputfieldRadios getInputfield() * @@ -47,9 +47,6 @@ class InputfieldToggle extends Inputfield { const valueOther = 2; const valueUnknown = ''; - // default or fallback Inputfield clasr - const defaultInputfieldClass = 'InputfieldRadios'; - /** * Array of all label types * @@ -93,6 +90,14 @@ class InputfieldToggle extends Inputfield { */ protected $allLabels = array(); + /** + * Manually added options of [ value => label ] + * + * @var array + * + */ + protected $options = array(); + /** * Construct and set default settings * @@ -106,8 +111,9 @@ class InputfieldToggle extends Inputfield { $this->set('useOther', 0); $this->set('useReverse', 0); $this->set('useVertical', 0); + $this->set('useDeselect', 0); $this->set('defaultOption', 'none'); - $this->set('inputfieldClass', self::defaultInputfieldClass); + $this->set('inputfieldClass', '0'); $this->attr('value', self::valueUnknown); @@ -132,8 +138,14 @@ class InputfieldToggle extends Inputfield { */ public function isEmpty() { $value = $this->val(); - if($value === '') return true; - if(is_int($value) && $value > -1) return false; + if($value === self::valueUnknown) return true; + if(is_int($value)) { + if($this->hasOptions()) { + if(isset($this->options[$value])) return false; + } else { + if($value > -1) return false; + } + } if($value === self::valueOther && $this->useOther) return false; return true; } @@ -153,7 +165,11 @@ class InputfieldToggle extends Inputfield { $intValue = strlen("$value") && ctype_digit("$value") ? (int) $value : ''; $strValue = strtolower("$value"); - if($intValue === self::valueNo || $intValue === self::valueYes) { + if($this->hasOptions()) { + if($intValue !== '') $value = $intValue; + $value = isset($this->options[$value]) ? $value : self::valueUnknown; + + } else if($intValue === self::valueNo || $intValue === self::valueYes) { $value = $intValue; } else if($intValue === self::valueOther) { @@ -203,18 +219,26 @@ class InputfieldToggle extends Inputfield { /** * Get the delegated Inputfield that will be used for rendering selectable options * - * @return InputfieldRadios|InputfieldSelect + * @return InputfieldRadios|InputfieldSelect|InputfieldToggle * */ public function ___getInputfield() { - + if($this->inputfield) return $this->inputfield; $class = $this->getSetting('inputfieldClass'); - if(empty($class)) $class = self::defaultInputfieldClass; + if(empty($class) || $class === $this->className()) { + if($this->wire('adminTheme') == 'AdminThemeDefault') { + // clicking toggles jumps to top of page on AdminThemeDefault for some reason + // even if JS click events are canceled, so use radios instead + $class = 'InputfieldRadios'; + } else { + return $this; + } + } $f = $this->wire('modules')->get($class); - if(!$f) $f = $this->wire('modules')->get(self::defaultInputfieldClass); + if(!$f || $f === $this) return $this; $this->addClass($class, 'wrapClass'); @@ -226,22 +250,17 @@ class InputfieldToggle extends Inputfield { if(!$this->useVertical) { $f->set('optionColumns', 1); } - - $labels = $this->getLabels($this->labelType); - if($this->useReverse) { - $f->addOption(self::valueNo, $labels['no']); - $f->addOption(self::valueYes, $labels['yes']); - } else { - $f->addOption(self::valueYes, $labels['yes']); - $f->addOption(self::valueNo, $labels['no']); + $val = $this->val(); + $options = $this->getOptions(); + $f->addOptions($options); + + if(isset($options[$val]) && method_exists($f, 'addOptionAttributes')) { + $f->addOptionAttributes($val, array('input.class' => 'InputfieldToggleChecked')); } - if($this->useOther) { - $f->addOption(self::valueOther, $labels['other']); - } + $f->val($val); - $f->val($this->val()); $this->inputfield = $f; return $f; @@ -257,7 +276,10 @@ class InputfieldToggle extends Inputfield { */ public function renderReady(Inputfield $parent = null, $renderValueMode = false) { $f = $this->getInputfield(); - if($f) $f->renderReady($parent, $renderValueMode); + if($f && $f !== $this) $f->renderReady($parent, $renderValueMode); + if($this->useDeselect && $this->defaultOption === 'none') { + $this->addClass('InputfieldToggleUseDeselect', 'wrapClass'); + } return parent::renderReady($parent, $renderValueMode); } @@ -269,7 +291,7 @@ class InputfieldToggle extends Inputfield { */ public function ___renderValue() { $label = $this->getValueLabel($this->attr('value')); - $value = $this->wire('sanitizer')->entities1($label); + $value = $this->formatLabel($label, true); return $value; } @@ -282,9 +304,9 @@ class InputfieldToggle extends Inputfield { public function ___render() { $value = $this->val(); - - // check if we should assign a default value $default = $this->getSetting('defaultOption'); + + // check if we should assign a default value if($default && ("$value" === self::valueUnknown || !strlen("$value"))) { if($default === 'yes') { $this->val(self::valueYes); @@ -296,10 +318,46 @@ class InputfieldToggle extends Inputfield { } $f = $this->getInputfield(); - if(!$f) return "Unable to load Inputfield"; - $f->val($this->val()); + + if($f && $f !== $this) { + $f->val($this->val()); + $out = $f->render(); + } else { + $out = $this->renderToggle(); + } + + // hidden input to indicate presence when no selection is made (like with radios) + $out .= ""; - return $f->render(); + return $out; + } + + /** + * Render default input toggles + * + * @return string + * + */ + protected function renderToggle() { + + $id = $this->attr('id'); + $name = $this->attr('name'); + $checkedValue = $this->val(); + $out = ''; + + foreach($this->getOptions() as $value => $label) { + $checked = "$checkedValue" === "$value" ? "checked " : ""; + $class = $checked ? 'InputfieldToggleChecked' : ''; + $label = $this->formatLabel($label); + $out .= + "" . + ""; + } + + return + "
" . + "
$out
" . + "
"; } /** @@ -311,12 +369,17 @@ class InputfieldToggle extends Inputfield { */ public function ___processInput(WireInputData $input) { + $prevValue = $this->val(); $value = $input[$this->name]; $intValue = strlen($value) && ctype_digit("$value") ? (int) $value : null; + + if($value === null && $input["_{$this->name}_"] === null) { + // input was not rendered in the submitted post, so should be ignored - if($value === null) { - // selection not present in input - + } else if($this->hasOptions()) { + // custom options + if(isset($this->options[$value])) $this->val($value); + } else if($intValue === self::valueYes || $intValue === self::valueNo) { // yes or no selected $this->val($intValue); @@ -325,14 +388,18 @@ class InputfieldToggle extends Inputfield { // other selected $this->val($intValue); - } else if($value === self::valueUnknown) { - // no selection (not reachable when using radios) + } else if($value === self::valueUnknown || $value === null) { + // no selection $this->val(self::valueUnknown); } else { // something we don't recognize } - + + if($this->val() !== $prevValue) { + $this->trackChange('value', $prevValue, $this->val()); + } + return $this; } @@ -453,7 +520,7 @@ class InputfieldToggle extends Inputfield { } /** - * Get the label for the currently set or given value + * Get the label for the currently set (or given) value * * @param bool|int|string|null $value Optionally provide value or omit to use currently set value attribute. * @param int|null $labelType Specify labelType constant or omit for selected label type. @@ -463,6 +530,11 @@ class InputfieldToggle extends Inputfield { */ public function getValueLabel($value = null, $labelType = null, $language = null) { + if($value !== null && $labelType === null && $this->hasOptions()) { + // get custom defined option label from addOption() call (API usage only) + if(isset($this->options[$value])) return $this->options[$value]; + } + $labels = $this->getLabels($labelType, $language); if($value === null) $value = $this->attr('value'); @@ -484,7 +556,7 @@ class InputfieldToggle extends Inputfield { * @return string * */ - public function getYesLabel($labelType = null, $language = null) { + protected function getYesLabel($labelType = null, $language = null) { return $this->getValueLabel(self::valueYes, $labelType, $language); } @@ -496,7 +568,7 @@ class InputfieldToggle extends Inputfield { * @return string * */ - public function getNoLabel($labelType = null, $language = null) { + protected function getNoLabel($labelType = null, $language = null) { return $this->getValueLabel(self::valueNo, $labelType, $language); } @@ -508,7 +580,7 @@ class InputfieldToggle extends Inputfield { * @return string * */ - public function getOtherLabel($labelType = null, $language = null) { + protected function getOtherLabel($labelType = null, $language = null) { return $this->getValueLabel(self::valueOther, $labelType, $language); } @@ -520,9 +592,122 @@ class InputfieldToggle extends Inputfield { * @return string * */ - public function getUnknownLabel($labelType = null, $language = null) { + protected function getUnknownLabel($labelType = null, $language = null) { return $this->getValueLabel(self::valueUnknown, $labelType, $language); } + + /** + * Format label for HTML output (entity encode, etc.) + * + * @param string $label + * @param bool $allowIcon Allow icon markup to appear in label? + * @return string + * + */ + public function formatLabel($label, $allowIcon = true) { + $label = $this->wire('sanitizer')->entities1($label); + if(strpos($label, 'icon-') !== false && preg_match('/\bicon-([-_a-z0-9]+)/', $label, $matches)) { + $name = $matches[1]; + $icon = $allowIcon ? $icon = wireIconMarkup($name, 'fw') : ''; + $label = str_replace("icon-$name", $icon, $label); + } + return trim($label); + } + + /** + * Get all selectable options as array of [ value => label ] + * + * @return array + * + */ + public function getOptions() { + // use custom options instead if any have been set from an addOption() call + if($this->hasOptions()) return $this->options; + // use built in toggle options + $options = array(); + $values = $this->useReverse ? array(self::valueNo, self::valueYes) : array(self::valueYes, self::valueNo); + if($this->useOther) $values[] = self::valueOther; + foreach($values as $value) { + $options[$value] = $this->getValueLabel($value); + } + return $options; + } + + /** + * Add a selectable option (custom API usage only, overrides built-in options) + * + * Note that once you use this, your options take over and Toggle's default yes/no/other + * are no longer applicable. This is for custom API use and is not used by FieldtypeToggle. + * + * @param int|string $value + * @param null|string $label + * @return $this + * @throws WireException if you attempt to call this method when used with FieldtypeToggle + * + */ + public function addOption($value, $label = null) { + if($this->hasFieldtype) { + throw new WireException('The addOption() method is not available for FieldtypeToggle'); + } + if($label === null) $label = $value; + $this->options[$value] = $label; + return $this; + } + + /** + * Set all options with array of [ value => label ] (custom API usage only, overrides built-in options) + * + * Once you use this (with a non-empty array, your set options take over and the + * built-in yes/no/other no longer apply. This is for custom API use and is not used + * by FieldtypeToggle. + * + * The value for each option must be an integer value between -128 and 127. + * + * @param array $options + * @return $this + * @throws WireException if you attempt to call this method when used with FieldtypeToggle + * + */ + public function setOptions(array $options) { + $this->options = array(); + foreach($options as $key => $value) { + $this->addOption($key, $value); + } + return $this; + } + + /** + * Are custom options in use? + * + * @return bool + * + */ + protected function hasOptions() { + return !$this->hasFieldtype && count($this->options) > 0; + } + + /** + * Return a list of config property names allowed for fieldgroup/template context + * + * @param Field $field + * @return array of Inputfield names + * @see Fieldtype::getConfigAllowContext() + * + */ + public function ___getConfigAllowContext($field) { + return array_merge(parent::___getConfigAllowContext($field), array( + 'labelType', + 'inputfieldClass', + 'yesLabel', + 'noLabel', + 'otherLabel', + 'useVertical', + 'useDeselect', + 'useOther', + 'useReverse', + 'defaultOption', + )); + } /** * Configure Inputfield @@ -534,12 +719,20 @@ class InputfieldToggle extends Inputfield { /** @var Modules $modules */ $modules = $this->wire('modules'); - /** @var Languages $languages */ $languages = $this->wire('languages'); - $inputfields = parent::___getConfigInputfields(); + if($this->hasFieldtype) { + /** @var InputfieldFieldset $fieldset */ + $fieldset = $modules->get('InputfieldFieldset'); + $fieldset->label = $this->_('Toggle field labels and input settings'); + $fieldset->icon = 'toggle-on'; + $inputfields->prepend($fieldset); + } else { + $fieldset = $inputfields; + } + $removals = array('defaultValue'); foreach($removals as $name) { $f = $inputfields->getChildByName($name); @@ -560,20 +753,22 @@ class InputfieldToggle extends Inputfield { } $f->attr('value', (int) $this->labelType); $f->columnWidth = 34; - $inputfields->add($f); + $fieldset->add($f); /** @var InputfieldRadios $f */ $f = $modules->get('InputfieldRadios'); $f->attr('name', 'inputfieldClass'); $f->label = $this->_('Input type'); + $f->addOption('0', $this->_('Toggle buttons')); foreach($modules->findByPrefix('Inputfield') as $name) { if(!wireInstanceOf($name, 'InputfieldSelect')) continue; if(wireInstanceOf($name, 'InputfieldHasArrayValue')) continue; - $f->addOption($name, str_replace('Inputfield', '', $name)); + $label = str_replace('Inputfield', '', $name); + $f->addOption($name, $label); } $f->val($this->getSetting('inputfieldClass')); $f->columnWidth = 33; - $inputfields->add($f); + $fieldset->add($f); /** @var InputfieldRadios $f */ $f = $modules->get('InputfieldRadios'); @@ -584,7 +779,33 @@ class InputfieldToggle extends Inputfield { $f->val($this->useVertical ? 1 : 0); $f->columnWidth = 33; $f->showIf = 'inputfieldClass=InputfieldRadios'; - $inputfields->add($f); + $fieldset->add($f); + + /** @var InputfieldCheckbox $f */ + $f = $modules->get('InputfieldCheckbox'); + $f->attr('name', 'useOther'); + $f->label = $this->_('Use a 3rd “other” option?'); + if($this->useOther) $f->attr('checked', 'checked'); + $f->columnWidth = 34; + $fieldset->add($f); + + /** @var InputfieldCheckbox $f */ + $f = $modules->get('InputfieldCheckbox'); + $f->attr('name', 'useReverse'); + $f->label = $this->_('Reverse order of yes/no options?'); + if($this->useReverse) $f->attr('checked', 'checked'); + $f->columnWidth = 33; + $fieldset->add($f); + + /** @var InputfieldCheckbox $f */ + $f = $modules->get('InputfieldCheckbox'); + $f->attr('name', 'useDeselect'); + $f->label = $this->_('Support click to de-select?'); + $f->showIf = "inputfieldClass=0|InputfieldRadios"; + if($this->useDeselect) $f->attr('checked', 'checked'); + $f->columnWidth = 33; + $f->showIf = 'defaultOption=none'; + $fieldset->add($f); $customStates = array( 'yesLabel' => $this->_('Yes/On'), @@ -597,7 +818,7 @@ class InputfieldToggle extends Inputfield { $f->attr('name', $name); $f->label = sprintf($this->_('Label for “%s” option'), $label); $f->showIf = 'labelType=' . self::labelTypeCustom; - $f->attr('value', $this->get($name)); + $f->val($this->get($name)); $f->columnWidth = 50; if($languages) { $f->useLanguages = true; @@ -606,50 +827,35 @@ class InputfieldToggle extends Inputfield { if(!$language->isDefault()) $f->set("value$language", $langValue); } } - $inputfields->add($f); + $fieldset->add($f); } /** @var InputfieldText $f */ $f = $modules->get('InputfieldText'); $f->attr('name', 'otherLabel'); - $f->label = sprintf($this->_('Label for 3rd option')); + $f->label = sprintf($this->_('Label for 3rd “other” option')); $f->showIf = 'useOther=1'; - $f->attr('value', $this->get('otherLabel')); - $f->columnWidth = 50; + $f->val($this->get('otherLabel')); if($languages) { $f->useLanguages = true; foreach($languages as $language) { if(!$language->isDefault()) $f->set("value$language", $this->get("otherLabel$language")); } } - $inputfields->add($f); - - /** @var InputfieldCheckbox $f */ - $f = $modules->get('InputfieldCheckbox'); - $f->attr('name', 'useOther'); - $f->label = $this->_('Show a 3rd option?'); - if($this->useOther) $f->attr('checked', 'checked'); - $f->columnWidth = 50; - $inputfields->add($f); - - /** @var InputfieldCheckbox $f */ - $f = $modules->get('InputfieldCheckbox'); - $f->attr('name', 'useReverse'); - $f->label = $this->_('Reverse order of yes/no options?'); - if($this->useReverse) $f->attr('checked', 'checked'); - $inputfields->add($f); + $fieldset->add($f); - /** @var InputfieldRadios $f */ - $f = $modules->get('InputfieldRadios'); + /** @var InputfieldToggle $f */ + $f = $modules->get('InputfieldToggle'); + $f->set('inputfieldClass', $this->inputfieldClass); $f->attr('name', 'defaultOption'); $f->label = $this->_('Default selected option'); $f->addOption('yes', $this->getYesLabel()); $f->addOption('no', $this->getNoLabel()); if($this->useOther) $f->addOption('other', $this->getOtherLabel()); $f->addOption('none', $this->_('No selection')); - $f->optionColumns = 1; - $f->attr('value', $this->defaultOption); - $inputfields->add($f); + $f->val($this->defaultOption); + $f->addClass('InputfieldToggle', 'wrapClass'); + $fieldset->add($f); return $inputfields; }