Wednesday, December 19, 2007

Accordion select list

Kevin Miller has created an accordion widget using prototype and script.aculo.us. In this article I'll demonstrate how to build a selection list that has sub-sections utilizing the accordion control.

Here is a demonstation comparing a basic select list control and the accordion select list:


To make the control work, you first add a read-only text box with the drop down button image floating to the right of it, for example:

<span style="float: right">
<img id="accSelectToggle" src="images/btn_dropdown.png" width="21" height="16" alt="Expand list" title="Expand list" />
</span>
<input type="text" id="accSelect" title="List" readonly="readonly" value="Option 1.1" />


You then define a div which contains the accordion control, such as:

<div id="accSelectOptions" class="accordion_container" style="display: none">
<h1 class="accordion_toggle">Category 1</h1>
<div class="accordion_content">
<ul>
<li value="option11">Option 1.1</li>
<li value="option12">Option 1.2</li>
<li value="option13">Option 1.3</li>
</ul>
</div>
...
</div>


Add your preferred CSS styling. In my example the CSS looks like:

#accSelect {
width: 169px;
height: 14px;
border-style: none;
padding-left: 4px;
}

.accordion_container {
z-index: 10;
position: absolute;
width: 198px;
border: solid 1px black;
}

.accordion_toggle {
display: block;
padding: 0.3em 0.5em;
font-weight: normal;
font-size: 1em;
text-decoration: none;
outline: none;
border-bottom: 1px solid #def;
color: #000000;
cursor: pointer;
margin: 0px;
background-image: url('images/expand.gif');
background-position: 99% 50%;
background-repeat: no-repeat;
padding-right: 5px;
background-color: #9BE;
}

.accordion_toggle_active {
color: #ffffff;
font-weight: bolder;
background-image: url('images/ns-expand.gif');
background-color: #47B;
}

.accordion_content {
background-color: #ffffff;
overflow: auto;
display: block;
}

.accordion_content ul {
padding-left: 1em;
margin: 0;
padding-right: 0;
padding-bottom: 0px;
list-style-type: none
}

.accordion_content li {
margin: auto;
padding: 0px;
}

.highlight {
background-color: #DDD;
}


And finally add a little JavaScript to make the magic happen:

function toggleAccordionSelect(event) {
var image = event.target;
var collapseIcon = "images/btn_dropdown-selected.png";
var expandIcon = "images/btn_dropdown.png";

if ($('accSelectOptions').style.display === 'none') {
image.src = collapseIcon;
image.alt = "Collapse List";
image.title = "Collapse List";
$('accSelectOptions').show();
}
else {
image.src = expandIcon;
image.alt = "Expand List";
image.title = "Expand List";
$('accSelectOptions').hide();
}
}

function toggleHighlight(event) {
var item = event.target;
item.toggleClassName('highlight');
}

function selectAccordionOption(event) {
var selectedOption = Event.element(event);

// update the selection input field value to the selected display value
$('accSelect').value = selectedOption.innerHTML;

// internal value is stored as an attribute, do whatever you need to with it
var realValue = selectedOption.getAttribute('value');

// hide the accordion list
toggleAccordionSelect({target: $('accSelectToggle')});
}


var accordionSelect = new accordion('accSelectOptions', {
classNames : {
toggle : 'accordion_toggle',
toggleActive : 'accordion_toggle_active',
content : 'accordion_content'
},
onEvent : 'mousedown'
});

// By default, open first accordion in the drop down
var accordionToggles = $$('#accSelectOptions .accordion_toggle');
accordionSelect.activate(accordionToggles[0]);

// register event observers
Event.observe('accSelectToggle', 'mousedown', toggleAccordionSelect);
$$('#accSelectOptions .accordion_content li').each(function(accSelectOption) {
Event.observe(accSelectOption, 'mousedown', selectAccordionOption);
Event.observe(accSelectOption, 'mouseover', toggleHighlight);
Event.observe(accSelectOption, 'mouseout', toggleHighlight);
});

No comments: