PEAR is archived and read-only

This mirror preserves historical PEAR package releases and metadata so existing references remain available.

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.