PEAR is discontinued

This is a static archive preserving historical releases and metadata. No new packages or updates will be published. For updates to existing packages, or to publish new packages, please use Composer and Packagist.

Home » HTML » HTML_QuickForm2 » Bug #1283

Feature request: Optgroup support

Details

Request #1283Feature request: Optgroup support
Submitted2004-04-26 09:35 UTC
Fromboci at dravanet dot hu
Assignedavb
StatusClosed
PackageHTML_QuickForm2
PHP VersionIrrelevant
OSLinux
Roadmaps0.1.0

Comments

[2004-04-26 09:35 UTC] boci at dravanet dot hu

Description:
------------
Hi!

I needed optgtoup support for the Select element. It's possible?

[2005-01-13 13:00 UTC] joao at cbpf dot br

I´m looking for this too.

[2005-03-31 13:26 UTC] no at mail dot com

Optgroup support with recursion would be great. (Like smarty's html_options).

[2005-09-28 13:52 UTC] chris dot yates1 at btconnect dot com

Here's how I did it, using an array for the options; recursive optgroups is supported.

There are changes to the addOption and toHtml functions, and the addition of the _optionToHtml function.

The code below shows the changes with the original code commented out.

Hope this helps

// CLY - modification to allow optgroups
// function addOption($text, $value, $attributes=null)
function addOption($text, $value, $attributes=null, &$optGroup=null)
{
// if text is an array, start an optgroup
if (is_array($text)) {

if (is_array($optGroup)) {
$optGroup[$value]['options'] = array();
$optGroup =& $optGroup[$value]['options'];
}
else {
$this->_options[$value]['options'] = array();
$optGroup =& $this->_options[$value]['options'];
};

foreach($text as $key=>$val) {
$this->addOption($val, $key, null, $optGroup);
} // foreach

// done all the options in the optgroup
return;
}
// end mod

if (null === $attributes) {
$attributes = array('value' => $value);
} else {
$attributes = $this->_parseAttributes($attributes);
if (isset($attributes['selected'])) {
// the 'selected' attribute will be set in toHtml()
$this->_removeAttr('selected', $attributes);
if (is_null($this->_values)) {
$this->_values = array($value);
} elseif (!in_array($value, $this->_values)) {
$this->_values[] = $value;
}
}
$this->_updateAttrArray($attributes, array('value' => $value));
}

// CLY - modification to allow optgroups
// if $optGroup is an array, add the option to it
if (is_array($optGroup)) {
$optGroup[$text]['attr'] = $attributes;
}
// if $optGroup is a string, add the option to the option group
// used if directly adding an option to an optgroup
elseif (is_string($optGroup)) {
$optGroups = explode($optGroup, ',');

$target =& $this->_options;

foreach($optGroups as $group) {
// create the option group if it does not exist
if (empty($target[$group]['options'])) {
$target[$group]['options'] = array();
}

$target =& $target[$group]['options'];
} // foreach

// add the option
$target[$text]['attr'] = $attributes;

}
// else if there are attributes, add them to the option
elseif (is_array($attributes)) {
$this->_options[$text]['attr'] = $attributes;
}
// $this->_options[] = array('text' => $text, 'attr' => $attributes);
// end mod
} // end func addOption

function toHtml()
{
if ($this->_flagFrozen) {
return $this->getFrozenHtml();
} else {
$tabs = $this->_getTabs();
$strHtml = '';

if ($this->getComment() != '') {
$strHtml .= $tabs . '<!-- ' . $this->getComment() . " //-->\n";
}

if (!$this->getMultiple()) {
$attrString = $this->_getAttrString($this->_attributes);
} else {
$myName = $this->getName();
$this->setName($myName . '[]');
$attrString = $this->_getAttrString($this->_attributes);
$this->setName($myName);
}
$strHtml .= $tabs . '<select' . $attrString . ">\n";

// CLY - modified to allow optgroups
foreach ($this->_options as $text=>$option) {
$strHtml .= $tabs . $this->_optionToHtml($text, $option);
}

/* foreach ($this->_options as $option) {
if (is_array($this->_values) && in_array((string)$option['attr']['value'], $this->_values)) {
$this->_updateAttrArray($option['attr'], array('selected' => 'selected'));
}
$strHtml .= $tabs . "\t<option" . $this->_getAttrString($option['attr']) . '>' .
$option['text'] . "</option>\n";
}
*/
// end mod

return $strHtml . $tabs . '</select>';
}
} //end func toHtml

// CLY - new function to allow optgroups
/**
* Returns an OPTION in HTML
*
* This function is called recursively to support optgroups
*
* @param string $text Display text for the option
* @param array $option The option
* @since ??
* @access private
* @return string
*/
// Creates the HTML for an option
function _optionToHtml($text, $option)
{
$tabs = $this->_getTabs();

// if an option has options it's an optgroup
if (isset($option['options'])) {
$strHtml = $tabs . "<optgroup label=\"$text\">\n";

foreach($option['options'] as $txt=>$opt) {
$strHtml .= $tabs . $this->_optionToHtml($txt, $opt);
} // foreach

$strHtml .= $tabs . "</optgroup>\n";

return($strHtml);
}

// else it's an option
else {
if (is_array($this->_values) && in_array((string)$option['attr']['value'], $this->_values)) {
$this->_updateAttrArray($option['attr'], array('selected' => 'selected'));
}
return("\t<option" . $this->_getAttrString($option['attr']) . ">$text</option>\n");
}
}

And here's an array of UK county names that shows two levels of optgroups. Just pass $ukCounties as the options to a select as modified above.

$ukCounties = array(
'0' => '-Select-',
'England' => array(
'B' => array(
'Bedfordshire' => 'Bedfordshire',
'Berkshire' => 'Berkshire',
'Buckinghamshire' => 'Buckinghamshire',
),
'C' => array(
'Cambridgeshire' => 'Cambridgeshire',
'Cheshire' => 'Cheshire',
'Cornwall' => 'Cornwall',
'Cumberland' => 'Cumberland',
),
'D' => array(
'Derbyshire' => 'Derbyshire',
'Devon' => 'Devon',
'Dorset' => 'Dorset',
'Durham' => 'Durham',
),
'E' => array(
'Essex' => 'Essex',
),
'G' => array(
'Gloucestershire' => 'Gloucestershire',
),
'H' => array(
'Hampshire' => 'Hampshire',
'Herefordshire' => 'Herefordshire',
'Hertfordshire' => 'Hertfordshire',
'Huntingdonshire' => 'Huntingdonshire',
),
'K' => array(
'Kent' => 'Kent',
),
'L' => array(
'Lancashire' => 'Lancashire',
'Leicestershire' => 'Leicestershire',
'Lincolnshire' => 'Lincolnshire',
),
'M' => array(
'Middlesex' => 'Middlesex',
),
'N' => array(
'Norfolk' => 'Norfolk',
'Northamptonshire' => 'Northamptonshire',
'Northumberland' => 'Northumberland',
'Nottinghamshire' => 'Nottinghamshire',
),
'O' => array(
'Oxfordshire' => 'Oxfordshire',
),
'R' => array(
'Rutland' => 'Rutland',
),
'S' => array(
'Shropshire' => 'Shropshire',
'Somerset' => 'Somerset',
'Staffordshire' => 'Staffordshire',
'Suffolk' => 'Suffolk',
'Surrey' => 'Surrey',
'Sussex' => 'Sussex',
),
'W' => array(
'Warwickshire' => 'Warwickshire',
'Westmorland' => 'Westmorland',
'Wiltshire' => 'Wiltshire',
'Worcestershire' => 'Worcestershire',
),
'Y' => array(
'Yorkshire' => 'Yorkshire',
),
),
'Scotland' => array(
'A' => array(
'Aberdeenshire' => 'Aberdeenshire',
'Angus' => 'Angus',
'Argyllshire' => 'Argyllshire',
'Ayrshire' => 'Ayrshire',
),
'B' => array(
'Banffshire' => 'Banffshire',
'Berwickshire' => 'Berwickshire',
'Buteshire' => 'Buteshire',
),
'C' => array(
'Cromartyshire' => 'Cromartyshire',
'Caithness' => 'Caithness',
'Clackmannanshire' => 'Clackmannanshire',
),
'D' => array(
'Dumfriesshire' => 'Dumfriesshire',
'Dunbartonshire' => 'Dunbartonshire',
),
'E' => array(
'East Lothian' => 'East Lothian',
),
'F' => array(
'Fife' => 'Fife',
),
'I' => array(
'Inverness-shire' => 'Inverness-shire',
),
'K' => array(
'Kincardineshire' => 'Kincardineshire',
'Kinross-shire' => 'Kinross-shire',
'Kirkcudbrightshire' => 'Kirkcudbrightshire',
),
'L' => array(
'Lanarkshire' => 'Lanarkshire',
),
'M' => array(
'Midlothian' => 'Midlothian',
'Morayshire' => 'Morayshire',
),
'N' => array(
'Nairnshire' => 'Nairnshire',
),
'O' => array(
'Orkney' => 'Orkney',
),
'P' => array(
'Peeblesshire' => 'Peeblesshire',
'Perthshire' => 'Perthshire',
),
'R' => array(
'Renfrewshire' => 'Renfrewshire',
'Ross-shire' => 'Ross-shire',
'Roxburghshire' => 'Roxburghshire',
),
'S' => array(
'Selkirkshire' => 'Selkirkshire',
'Shetland' => 'Shetland',
'Stirlingshire' => 'Stirlingshire',
'Sutherland' => 'Sutherland',
),
'W' => array(
'West Lothian' => 'West Lothian',
'Wigtownshire' => 'Wigtownshire',
),
),
'Ulster' => array(
'County Antrim' => 'County Antrim',
'County Armagh' => 'County Armagh',
'County Down' => 'County Down',
'County Fermanagh' => 'County Fermanagh',
'County Tyrone' => 'County Tyrone',
'County Londonderry' => 'County Londonderry',
),
'Wales' => array(
'A' => array(
'Anglesey' => 'Anglesey',
),
'B' => array(
'Brecknockshire' => 'Brecknockshire',
),
'C' => array(
'Caernarfonshire' => 'Caernarfonshire',
'Carmarthenshire' => 'Carmarthenshire',
'Cardiganshire' => 'Cardiganshire',
),
'D' => array(
'Denbighshire' => 'Denbighshire',
),
'F' => array(
'Flintshire' => 'Flintshire',
),
'G' => array(
'Glamorgan' => 'Glamorgan',
),
'M' => array(
'Merioneth' => 'Merioneth',
'Monmouthshire' => 'Monmouthshire',
'Montgomeryshire' => 'Montgomeryshire',
),
'P' => array(
'Pembrokeshire' => 'Pembrokeshire',
),
'R' => array(
'Radnorshire' => 'Radnorshire',
),
),
);

[2006-05-25 04:32 UTC] walter_tom at hotmail dot com

Hi

I came across a bug when using Chris Yates' modification to allow optgroups.

The exportValues function errors when it tries to check the submitted values against the _options array to see if it is clean.

I came up with this workaround. Warning, this has not been thoroughly tested at all!

Modify the exportValues function, from line 651, replacing the stuff which is commented out here:

// CLY - modified to allow optgroups
if ($this->_isInOptGroup($v, $this->_options)) {
$cleanValue[] = $v;
}
// for ($i = 0, $optCount = count($this->_options); $i < $optCount; $i++) {
// if ($v == $this->_options[$i]['attr']['value']) {
// $cleanValue[] = $v;
// break;
// }
// }
// end mod

Also, add this function:

// CLY - new function to allow optgroups
function _isInOptGroup($v, $opts) {
$isInOptGroup = false;
foreach ($opts as $opt) {
if (isset($opt['options'])) {
$isInOptGroup = $this->_isInOptGroup($v, $opt['options']);
} else {
if ($v == $opt['attr']['value']) {
$isInOptGroup = true;
}
}
}
return $isInOptGroup;
}

[2006-05-25 05:38 UTC] walter_tom at hotmail dot com

OOPS!

Yes, as I said, the aforementioned code is not really tested at all, and I discovered soon after posting there was an error. The _isInOptGroup function from the above code should be replaced with this:

function _isInOptGroup($v, $opts) {
$isInOptGroup = false;
foreach ($opts as $opt) {
if (isset($opt['options'])) {
$isInOptGroup = $this->_isInOptGroup($v, $opt['options']);
} else {
if ($v == $opt['attr']['value']) {
$isInOptGroup = true;
}
}
if ($isInOptGroup) break;
}
return $isInOptGroup;
}

The break; clause is the bit that changed.

Sorry. Use at your own risk.