<!--
|
The MultiselectPicklist component implements a multiselect picklist similar
|
to that seen when adding tabs to a Force.com application.
|
|
HTML elements use the same classes as the native multiselect picklist, to
|
keep visual consistency in the UI.
|
|
In addition to the visible elements, the component contains two hidden input
|
elements, the purpose of which is to hold a string representation of the
|
contents of each listbox. As options are added, removed or moved within the
|
listboxes, the content of the hidden elements is synchronized to the content
|
of the listboxes. When the Visualforce page is submitted, the
|
MultiselectController updates its SelectOption[] variables from these hidden
|
elements.
|
-->
|
<apex:component controller="MultiselectController" id="MultiselectController">
|
<apex:attribute name="leftLabel" description="Label on left listbox."
|
type="String" required="true" />
|
<apex:attribute name="rightLabel" description="Label on right listbox."
|
type="String" required="true" />
|
<apex:attribute name="showUpDown" description="show Up Down btn on right listbox."
|
type="Boolean" required="true" />
|
<apex:attribute name="size" description="Size of listboxes."
|
type="Integer" required="true" />
|
<apex:attribute name="width" description="Width of listboxes."
|
type="String" required="true" />
|
|
<apex:attribute name="leftOptions"
|
description="Options list for left listbox." type="SelectOption[]"
|
required="true" assignTo="{!leftOptions}" />
|
<apex:attribute name="rightOptions"
|
description="Options list for right listbox." type="SelectOption[]"
|
required="true" assignTo="{!rightOptions}" />
|
|
<apex:outputPanel id="multiselectPanel" layout="block" styleClass="duelingListBox">
|
<table class="layout">
|
<tbody>
|
<tr>
|
<td class="selectCell">
|
<select id="{!$Component.multiselectPanel}:leftList"
|
class="multilist" multiple="multiple" size="{!size}"
|
style="width: {!width};">
|
<!--
|
Visualforce prepends the correct prefix to the outputLabel's
|
'for' attribute
|
-->
|
<optgroup style="text-decoration:none;" label="{!leftLabel}">
|
<apex:repeat value="{!leftOptions}" var="option">
|
<option value="{!option.value}">{!option.label}</option>
|
</apex:repeat>
|
</optgroup>
|
</select>
|
</td>
|
<td class="buttonCell">
|
<apex:outputPanel layout="block" styleClass="text">
|
<apex:outputLink value="javascript:moveSelectedOptions('{!$Component.multiselectPanel}:leftList',
|
'{!$Component.multiselectPanel}:rightList', '{!$Component.leftHidden}',
|
'{!$Component.rightHidden}');"
|
id="btnRight">
|
<apex:image value="/s.gif" alt="Add" styleClass="rightArrowIcon"
|
title="Add" />
|
</apex:outputLink>
|
</apex:outputPanel>
|
<apex:outputPanel layout="block" styleClass="text">
|
<apex:outputLink value="javascript:moveSelectedOptions('{!$Component.multiselectPanel}:rightList',
|
'{!$Component.multiselectPanel}:leftList', '{!$Component.rightHidden}',
|
'{!$Component.leftHidden}');"
|
id="btnLeft">
|
<apex:image value="/s.gif" alt="Remove"
|
styleClass="leftArrowIcon" title="Remove" />
|
</apex:outputLink>
|
</apex:outputPanel>
|
</td>
|
<td class="selectCell">
|
<select id="{!$Component.multiselectPanel}:rightList"
|
class="multilist" multiple="multiple" size="{!size}"
|
style="width: {!width};">
|
<optgroup style="text-decoration:none;" label="{!rightLabel}">
|
<apex:repeat value="{!rightOptions}" var="option">
|
<option value="{!option.value}">{!option.label}</option>
|
</apex:repeat>
|
</optgroup>
|
</select>
|
</td>
|
<apex:outputPanel layout="none" rendered="{!showUpDown}">
|
<td class="buttonCell"><apex:outputPanel layout="block"
|
styleClass="text">Up</apex:outputPanel>
|
<apex:outputPanel layout="block" styleClass="text">
|
<apex:outputLink value="javascript:slideSelectedOptionsUp('{!$Component.multiselectPanel}:rightList',
|
'{!$Component.rightHidden}');"
|
id="upBtn">
|
<apex:image value="/s.gif" alt="Up" styleClass="upArrowIcon"
|
title="Up" />
|
</apex:outputLink>
|
</apex:outputPanel>
|
<apex:outputPanel layout="block" styleClass="text">
|
<apex:outputLink value="javascript:slideSelectedOptionsDown('{!$Component.multiselectPanel}:rightList',
|
'{!$Component.rightHidden}');"
|
id="downBtn">
|
<apex:image value="/s.gif" alt="Down" styleClass="downArrowIcon"
|
title="Down" />
|
</apex:outputLink>
|
</apex:outputPanel>
|
<apex:outputPanel layout="block" styleClass="text">Down</apex:outputPanel>
|
</td>
|
</apex:outputPanel>
|
</tr>
|
</tbody>
|
</table>
|
<apex:inputHidden value="{!leftOptionsHidden}" id="leftHidden" />
|
<apex:inputHidden value="{!rightOptionsHidden}" id="rightHidden" />
|
</apex:outputPanel>
|
<script type="text/javascript">
|
if (!buildOutputString) {
|
// Create a string from the content of a listbox
|
var buildOutputString = function(listBox, hiddenInput) {
|
var str = '';
|
|
for ( var x = 0; x < listBox.options.length; x++) {
|
str += encodeURIComponent(listBox.options[x].value) + '&'
|
+ encodeURIComponent(listBox.options[x].text) + '&';
|
}
|
str.length--;
|
|
hiddenInput.value = str.slice(0, -1);
|
}
|
}
|
|
if (!moveSelectedOptions) {
|
// Move the selected options in the idFrom listbox to the idTo
|
// listbox, updating the corresponding strings in idHdnFrom and
|
// idHdnTo
|
var moveSelectedOptions = function(idFrom, idTo, idHdnFrom, idHdnTo) {
|
listFrom = document.getElementById(idFrom).children[0];
|
listTo = document.getElementById(idTo).children[0];
|
|
for ( var x = 0; x < listTo.children.length; x++) {
|
listTo.children[x].selected = false;
|
}
|
|
for ( var x = 0; x < listFrom.children.length; x++) {
|
if (listFrom.children[x].selected == true) {
|
listTo.appendChild(listFrom.children[x]);
|
x--;
|
}
|
}
|
|
listTo.focus();
|
|
buildOutputString(listFrom, document.getElementById(idHdnFrom));
|
buildOutputString(listTo, document.getElementById(idHdnTo));
|
}
|
}
|
|
if (!slideSelectedOptionsUp) {
|
// Slide the selected options in the idList listbox up by one position,
|
// updating the corresponding string in idHidden
|
var slideSelectedOptionsUp = function(idList, idHidden) {
|
listBox = document.getElementById(idList);
|
|
var len = listBox.options.length;
|
|
if (len > 0 && listBox.options[0].selected == true) {
|
return;
|
}
|
|
for ( var x = 1; x < len; x++) {
|
if (listBox.options[x].selected == true) {
|
listBox.insertBefore(listBox.options[x],
|
listBox.options[x - 1]);
|
}
|
}
|
|
listBox.focus();
|
|
buildOutputString(listBox, document.getElementById(idHidden));
|
}
|
}
|
|
if (!slideSelectedOptionsDown) {
|
// Slide the selected options in the idList listbox down by one position,
|
// updating the corresponding string in idHidden
|
var slideSelectedOptionsDown = function(idList, idHidden) {
|
listBox = document.getElementById(idList);
|
|
var len = listBox.options.length;
|
|
if (len > 0 && listBox.options[len - 1].selected == true) {
|
return;
|
}
|
|
for ( var x = listBox.options.length - 2; x >= 0; x--) {
|
if (listBox.options[x].selected == true) {
|
listBox.insertBefore(listBox.options[x + 1],
|
listBox.options[x]);
|
}
|
}
|
|
listBox.focus();
|
|
buildOutputString(listBox, document.getElementById(idHidden));
|
}
|
}
|
|
// initialize the string representations
|
buildOutputString(document.getElementById('{!$Component.multiselectPanel}:leftList'),
|
document.getElementById('{!$Component.leftHidden}'));
|
buildOutputString(document.getElementById('{!$Component.multiselectPanel}:rightList'),
|
document.getElementById('{!$Component.rightHidden}'));
|
</script>
|
</apex:component>
|