I'm creating input replacements for a legacy site, which means I'm stuck using prototype.js (1.7.1.0)
My select inputs work fine cross browsers, except for Firefox (26.0 OSX)
In FF the select options have the 'selected' attribute correctly set, but trying to read the element value or selectedIndex always returns the initial value, and this is essential due to some third party code that I have no control over.
While I was testing to see if the visibility of the original input was relevant (it wasn't) I discovered that it is possible to get the replacements to work, but only if you FIRST use the original input. Further, the original input will not work if you use the replacement first.
I have a test case here:
http://jsfiddle.net/DisasterMan/gUam3/4/
When the input replacements are used, the value and index are read and (should be) displayed below.
I've tried picking apart existing code to see how it's done, but haven't found usable select replacements with Prototype. Am planning to try and pick apart a working jQuery version such as http://groenroos.github.io/minimalect/ and see if I can work out how it's done, but any assistance would be greatly appreciated!
<!-- language: javascript -->
// To hell with IEh8! Not worth the time implementing the drop-down
if( ! $$( 'html' )[0].hasClassName( 'ltie9' ) )
{
//Replace select inputs
$$( 'select' ).each( function( select )
{
// All other checkboxs that share this name (i.e. this group)
var allOptions = $$( 'select[name="' + select.name + '"] option' ),
// id attribute of the input
replacementId = 'replace-' + select.name,
// CSS styled select replacement
replacement = '<div id="' + replacementId + '" data-name="' + select.name + '" class="select-replacement"><span class="option-label"></span><span class="arrow"><span class="head"></span></span></div>',
// Replacemet options container id
replacementOptionsId = replacementId + '-options',
// Replacement options container
replacementOptionsHtml = '<div id="' + replacementOptionsId + '" class="select-replacement-options">',
replacementOptionsElements,
selectedLabel = false;
// Build replacement options elements
allOptions.each( function ( option, index )
{
var selected = false,
label = option.innerHTML;
if( option.getAttribute( 'selected' ) !== null )
{
selected = true;
selectedLabel = label;
}
replacementOptionsHtml += '<span data-value="' + option.value + '" data-selected="' + selected + '" data-parent="' + replacementId + '" data-index="' + index + '">' + label + '</span>';
} );
replacementOptionsHtml += '</div>';
// Insert replacement
new Insertion.After( select, replacement );
replacementElement = $( replacementId );
replacementSelectedLabel = replacementElement.down( '.option-label' );
new Insertion.Bottom( replacementElement, replacementOptionsHtml );
if( selectedLabel )
{
Element.update( replacementSelectedLabel, selectedLabel );
}
replacementOptions = $( replacementOptionsId );
replacementOptionsElements = $$( '#' + replacementOptionsId + ' span' );
// Hide input
//select.hide( );
replacementOptions.hide( );
// Add click event listener to this select input
replacementElement.observe( 'click', function ( event )
{
var eventSrc = getEventSrc( this, event );
replacementOptions = $( eventSrc.id + '-options' );
replacementOptions.show( );
} );
// Options select handler
replacementOptionsElements.each( function ( option ){
option.observe( 'click', function ( event ){
event.stopPropagation( );
var option = getEventSrc( this, event ),
selectedValue = option.getAttribute( 'data-value' ),
selectedIndex = option.getAttribute( 'data-index' ),
replacementId = option.getAttribute( 'data-parent' ),
replacementElement = $( replacementId ),
replacementOptions = $( replacementId + '-options' ),
previouslySelected = replacementElement.down( '[data-selected="true"]' ),
replacementSelectedLabel = replacementElement.down( '.option-label' ),
selectName = replacementElement.getAttribute( 'data-name' ),
select = $$( 'select[name="' + selectName + '"]' )[0],
selectedOption = select.down( 'option[value="' + selectedValue + '"]' ),
currentSelectedOption = select.down( 'option[selected]' );
triggerEvent( select, 'click')
// Hide replacement options
replacementOptions.hide( );
// Set visibly selected option on replacement select input
Element.update( replacementSelectedLabel, option.innerHTML );
// Unset previous selected option
currentSelectedOption.removeAttribute( 'selected' );
// Unset previous selected replacement option
if( previouslySelected !== undefined )
{
previouslySelected.removeAttribute( 'data-selected' );
}
// Set selected option
selectedOption.setAttribute( 'selected', 'selected' );
selectedOption.selected = true;
// Set new selected replacement option attribute
option.setAttribute( 'data-selected', 'true' );
triggerEvent( select, 'change', function ( )
{
triggerEvent( select, 'blur' );
} );
var dateSegment = select.name.substring( select.name.indexOf( '_' ) + 1 ).toLowerCase(),
valDisplay = $$( '.' + dateSegment + '-value' )[0],
indexDisplay = $$( '.' + dateSegment + '-index' )[0];
valDisplay.update( select.value );
indexDisplay.update( select.selectedIndex );
console.log(select.value);
console.log(select.selectedIndex);
} );
} );
} );
}
triggerEvent = function( element, eventName, callback )
{
if (document.createEvent)
{
var evt = document.createEvent( 'HTMLEvents' );
evt.initEvent( eventName, true, true );
if( callback && typeof( callback ) === "function" )
{
callback();
}
return element.dispatchEvent( evt );
}
if ( element.fireEvent ){
return element.fireEvent( 'on' + eventName );
}
}
getEventSrc = function ( object, event )
{
if ( object === window )
{
return event.srcElement;
}
else
{
return object;
}
}