* @since PHP 5.0.2 */ if (!defined('PHP_EOL')) { switch (strtoupper(substr(PHP_OS, 0, 3))) { // Windows case 'WIN': define('PHP_EOL', "\r\n"); break; // Mac case 'DAR': define('PHP_EOL', "\r"); break; // Unix default: define('PHP_EOL', "\n"); } } // {{{ HTML_QuickForm_altselect /** * HTML QuickForm Alternate Select * * HTML_QuickForm plugin that changes a select into a group of radio buttons * or checkboxes with an optional textbox for other options not listed. If * the select element is listed as multiple, then it will be rendered with * checkboxes, otherwise it is rendered with radio buttons. * * @category HTML * @package HTML_QuickForm_altselect * @author David Sanders (shang.xiao.sanders@gmail.com) * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version Release: 1.1.0 * @link http://pear.php.net/package/HTML_QuickForm_altselect * @see HTML_QuickForm_select */ class HTML_QuickForm_altselect extends HTML_QuickForm_select { // {{{ properties /** * Include the other text field for non-listed entry. * * @var bool * @access public */ var $includeOther = false; /** * Other text type: 'text' or 'textarea' * * @var string * @access public * @see setIncludeOther(), includeOther */ var $includeOtherType = 'text'; /** * Label for the Other option. * * @var string * @access public */ var $otherLabel = 'Other'; /** * Text label to go in front of other text field (singular mode). * * @var string * @access public */ var $otherText = 'If other please specify:'; /** * Text label to go in front of other text field (multiple mode). * * @var string * @access public */ var $otherTextMultiple = 'Other:'; /** * Delimiter between subelements. Use br to go vertical, or nbsp to go * horizontal. * * @var string * @access public */ var $delimiter = '
'; /** * Rather than render with a delimiter you may choose to render as a HTML * list. * * @var string * @access public * @see delimiter */ var $list_type; /** * Other value storage. * * @var string * @access private */ var $_otherValue; /** * Associative array of attributes for each of the individual form elements. * NOTE: use "_qf_other" for the other radio button, and "_qf_other_text" * for the text field. * * @var array Associative array of attributes (see HTML_Common) * @access private */ var $_individualAttributes; // }}} // {{{ HTML_QuickForm_altselect /** * Constructor. Used to distinguish the attributes array which should be * an associative array of options to either a typical HTML attribute string * or another associative array * * @param string $elementName select name attribute * @param mixed $elementLabel label(s) for the select * @param mixed $options data to be used to populate options * @param mixed $attributes an associative array of option value * -> attributes. Each attribute is either * a typical HTML attribute string or an * associative array. * NOTE: use "_qf_other" for the other radio * button, "_qf_other_text" for the * text field and "_qf_all" to apply the * attributes to all the option elements. * @return void */ function HTML_QuickForm_altselect($elementName = null, $elementLabel = null, $options = null, $attributes = null) { if (func_get_args()) { HTML_QuickForm_select::HTML_QuickForm_select($elementName, $elementLabel, $options); $this->_individualAttributes = $attributes; } } // }}} // {{{ toHtml /** * Render the HTML_QuickForm element. * * @access public * @return string The rendered HTML */ function toHtml() { return $this->getElements(false); } // }}} // {{{ getElements /** * Arrange the buttons/boxes and other bits either concatenated as a html * string or in an array. When this element is registered as a group, * getElements should act in the same way as HTML_QuickForm_group::getElements(). * (Therefore the default must be to format as an array) * * @param bool $formatArray set true for an array (default), false for HTML * @access public * @see HTML_QuickForm_group::getElements() * @return mixed Array or HTML string */ function getElements($formatArray = true) { $html_func_to_use = $this->_flagFrozen ? 'getFrozenHtml' : 'toHtml'; $is_multiple = $this->getMultiple(); if ($formatArray) { $elements = array(); } else { $preHtml = ''; $postHtml = ''; $htmlArray = array(); $tabs = $this->_getTabs(); if ($this->getComment() != '') { $preHtml .= '' . PHP_EOL; } } if ($this->includeOther && !defined('HTML_QUICKFORM_ALTSELECT_JS_DISABLE_ELEMENT')) { $disable_element_js = << // EOT; if ($formatArray && !$this->_flagFrozen) { $elements['_qf_altselect_disableElement'] =& HTML_QuickForm::createElement('static', '_qf_altselect_disableElement', null, $disable_element_js); } else { $javascript = $disable_element_js; } define('HTML_QUICKFORM_ALTSELECT_JS_DISABLE_ELEMENT',true); } else { $javascript = ''; } $myName = $this->getName(); if ($is_multiple) { $myName .= '[]'; } foreach ($this->_options as $option) { if ($is_multiple) { $element =& HTML_QuickForm::createElement('checkbox',$myName); //xxx - qf won't take a value as constructor argument $element->updateAttributes(array('value' => $option['attr']['value'])); } else { $element =& HTML_QuickForm::createElement('radio', $myName, null, null, $option['attr']['value']); if ($this->includeOther) { $element->updateAttributes(array( 'onclick' => "_qf_altselect_disableElement(this.form.elements[this.name + '_qf_other'],true);")); } } if (isset($this->_individualAttributes['_qf_all'])) { $element->updateAttributes($this->_individualAttributes['_qf_all']); } if (isset($this->_individualAttributes[$option['attr']['value']])) { $element->updateAttributes($this->_individualAttributes[$option['attr']['value']]); } if (is_array($this->_values) && in_array((string)$option['attr']['value'], $this->_values)) { $element->setChecked(true); } if ($formatArray) { if ($this->_flagFrozen) { $element->freeze(); } $elements[$option['attr']['value']] =& $element; } else { // write our own label instead of adding text to the radio/cbox // as we may want to render without any text when doing from a group $htmlArray['_qf_' . $option['attr']['value']] = $tabs . $element->$html_func_to_use() . ''; } } if ($this->includeOther) { if (!$is_multiple) { // // create the other radio button // $element =& HTML_QuickForm::createElement('radio', $myName, null, null, '_qf_other'); if (isset($this->_individualAttributes['_qf_other'])) { $element->updateAttributes($this->_individualAttributes['_qf_other']); } $element->updateAttributes(array( 'onclick'=>"_qf_altselect_disableElement(this.form.elements[this.name+'_qf_other'],false);this.form.elements[this.name+'_qf_other'].focus();this.form.elements[this.name+'_qf_other'].select();")); if (is_array($this->_values) && in_array('_qf_other', $this->_values)) { $element->setChecked(true); } $other_msg = $this->otherText; if ($formatArray) { if ($this->_flagFrozen) { $element->freeze(); } $elements['_qf_other'] =& $element; } else { $htmlArray['_qf_other'] = $tabs . $element->$html_func_to_use() . ''; $preHtml .= $javascript; } $textName = $myName.'_qf_other'; } else { $other_msg = $this->otherTextMultiple; $textName = $myName; } // // create the 'other' text element // $other_id = 'qf_' . uniqid(''); $element =& HTML_QuickForm::createElement($this->includeOtherType, $textName, null, array('id'=>$other_id)); if (isset($this->_individualAttributes['_qf_other_text'])) { $element->updateAttributes($this->_individualAttributes['_qf_other_text']); } // if either the other button is selected, or some text is entered // (meaning _qf_other will also be a value), then set the value of // the other value in the text field. if (is_array($this->_values) && in_array('_qf_other', $this->_values) && isset($this->_otherValue)) { $element->updateAttributes(array('value' => $this->_otherValue)); } // otherwise just disable it // only disable with javascript otherwise if the browser doesn't have // javascript, then we'll never be able to enter the other text else if (!$is_multiple) { $disable_js = << // EOT; if ($formatArray && !$this->_flagFrozen) { $elements['disable_js'] =& HTML_QuickForm::createElement('static', 'disable_js', null, $disable_js); } else { $postHtml .= $disable_js; } } if ($formatArray) { if ($this->_flagFrozen) { $element->freeze(); } $elements[$textName] =& $element; } else { $tempHtml = $tabs . ' ' . $element->$html_func_to_use(); $htmlArray['_qf_other_text'] = $tempHtml; } } if ($formatArray) { return $elements; } else { if ($this->list_type === 'ul' || $this->list_type === 'ol') { $tempHtml = $preHtml . PHP_EOL . '<' . $this->list_type . '>' . PHP_EOL; foreach ($htmlArray as $key => $piece) { $tempHtml .= '
  • getAttribute('id'); if ($id !== null) { $tempHtml .= 'id="' . $key . '_' . $id . '" '; } if ($key === '_qf_other' || $key === '_qf_other_text') { $tempHtml .= 'class="' . $key . '">'; } else { $tempHtml .= 'class="_qf_option">'; } $tempHtml .= $piece . '
  • ' . PHP_EOL; } $tempHtml .= 'list_type . '>' . PHP_EOL . $postHtml; return $tempHtml; } else { return $preHtml . PHP_EOL . implode($this->delimiter . PHP_EOL, $htmlArray) . PHP_EOL . $postHtml; } } } // }}} // {{{ exportValue /** * Exports the value. * * If the other value is set, this will be exported if in singular mode * and the other radio button is selected. Otherwise if in multiple mode * the other value is added to the array of values. * * @param array $submitValues submitValues values submitted * @param bool $assoc propagate on to * HTML_QuickForm_select::exportValue() * @access public * @return mixed Single value or array of values */ function exportValue(&$submitValues, $assoc = false) { if (!$this->includeOther) { return parent::exportValue($submitValues, $assoc); } if ($this->getMultiple()) { // kinda defeats the purpose of using exportValue to return only // allowed options $value = $this->_findValue($submitValues); // if nothing was posted, then grab the defaults if (is_null($value)) { $value = $this->getValue(); } // _findValue may return a scalar if that's what was posted if (is_array($value)) { // remove the empty string from the other option foreach ($value as $key => $item) { if ($item === '') { unset($value[$key]); } } } else { // if a scalar, force an array to be exported $value = array($value); } return $this->_prepareValue($value, $assoc); } else { // NB: If an array was submitted with an other value, then it will // not be exported, as we're expecting '_qf_other' to be submitted // in singular mode. $myName = $this->getName(); // XXX $this->addOption(null,'_qf_other'); $value = parent::exportValue($submitValues, $assoc); // XXX array_pop($this->_options); if (is_array($value) && $value[$myName] == '_qf_other' || $value == '_qf_other') { if (isset($submitValues[$myName.'_qf_other'])) { $value = $submitValues[$myName.'_qf_other']; } else { $value = $this->_otherValue; } } return $this->_prepareValue($value, $assoc); } } // }}} // {{{ setSelected /** * Set the selected options. If a non-listed option is specified, it * will go into the other text field. Note at this point, the other and * multiple attributes may not have been set. * * @param mixed $values array or comma delimited string of selected values * @access public * @return void */ function setSelected($values) { parent::setSelected($values); // // we need to do some extra work here in case the other // option will be/has been set... // $other_values = array(); foreach ($this->_values as $value) { // if we are in singular mode and the other button is selected from // the submit values then we'll need to record the real other value // in _otherValue if ($value == '_qf_other') { $myName = $this->getName(); $this->_otherValue = @$_REQUEST[$myName.'_qf_other']; // we only need to grasp the first other value, because we // are in singular mode, so we'll return... return; } // otherwise the real other value might be listed in _values // from setSelected('junk') or if we're in multiple mode and it was // submitted... // if we find something not part of the options then we record it in // _otherValue and set the _qf_other as part of the values else { $found = false; foreach ($this->_options as $option) { if ((string) $value == (string) $option['attr']['value']) { $found = true; } } if (!$found) { $this->_values[] = '_qf_other'; $other_values[] = $value; } } } if (!empty($other_values)) { $this->_otherValue = implode(',',$other_values); } } // }}} // {{{ setIncludeOther /** * Set the select to include the 'other' textfield/textarea. * * @param bool/string $include If bool: whether to include the other text field, * else if string: either 'text' or 'textarea' * @access public * @return void */ function setIncludeOther($include = true) { if ($include === 'text' || $include === 'textarea') { $this->includeOther = true; $this->includeOtherType = $include; } else { $this->includeOther = (bool) $include; $this->includeOtherType = 'text'; } } // }}} // {{{ setDelimiter /** * Set the delimiter. * * @param string $delimiter delimiter to use between the subelements * @access public * @return void */ function setDelimiter($delimiter) { if (!is_string($delimiter)) { $this->delimiter = '
    '; } else { $this->delimiter = $delimiter; } } // }}} // {{{ setList /** * Set the options to render as an ordered/unordered list * * @param string $list_type The list type * @access public * @return void */ function setListType($list_type) { $this->list_type = $list_type; } // }}} // {{{ setGroup /** * Tell this element to act like a group when being accepted. * * @param bool $is_group whether to act like a group or not * @see HTML_QuickForm_element::_type * @access public * @return void */ function setGroup($is_group = true) { $this->_type = $is_group ? 'group' : 'select'; } // }}} // {{{ accept /** * Accepts a renderer. Overload select in case we'd like to see the * checkboxes/radio buttons in a group when renderering with another * renderer. * * This function was copied from HTML_QuickForm_group::accept() and * modified for use with this class. * * @param HTML_QuickForm_Renderer $renderer the QF renderer * @param bool $require whether a group is required * @param string $error an error message associated with a group * @see HTML_QuickForm_group::accept() * @access public * @return void */ function accept(&$renderer, $required = false, $error = null) { // if not asked to act like a group, then pass off to regular accept method if ($this->_type != 'group') { return parent::accept($renderer, $required, $error); } $this->_separator = null; $this->_appendName = null; $this->_required = array(); // Beginning of code from HTML_QuickForm_group::accept() // ---8<--- //$this->_createElementsIfNotExist(); $renderer->startGroup($this, $required, $error); $name = $this->getName(); // --->8--- // use our method to get the elements instead $this->_elements = $this->getElements(); // ---8<--- foreach (array_keys($this->_elements) as $key) { $element =& $this->_elements[$key]; if ($this->_appendName) { $elementName = $element->getName(); if (isset($elementName)) { $element->setName($name . '[' . (strlen($elementName)? $elementName: $key) . ']'); } else { $element->setName($name); } } $required = !$element->isFrozen() && in_array($element->getName(), $this->_required); $element->accept($renderer, $required); // restore the element's name if ($this->_appendName) { $element->setName($elementName); } } $renderer->finishGroup($this); // --->8--- } // }}} // {{{ getElementName /** * Returns the name of this element. Used by HTML_QuickForm::getSubmitValue() * when this element is registered as a group. * * @see HTML_QuickForm::getSubmitValue() * @access public * @return string */ function getElementName() { return $this->getName(); } // }}} } // }}} if (class_exists('HTML_QuickForm')) { HTML_QuickForm::registerElementType('altselect', 'HTML/QuickForm/altselect.php', 'HTML_QuickForm_altselect'); } /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * c-hanging-comment-ender-p: nil * End: */ ?>