r13425 - in Products.Archetypes/trunk: . Products/Archetypes Products/Archetypes/skins/archetypes/widgets/js

"Eric Steele" <[email protected]>
Newsgroups gmane.comp.web.zope.plone.archetypes.cvs
Message-ID <[email protected]>
Author: esteele
Date: Thu Jan 20 15:09:56 2011
New Revision: 13425

Added:
   Products.Archetypes/trunk/Products/Archetypes/skins/archetypes/widgets/js/keywordmultiselect.js
      - copied, changed from r13098, Products.Archetypes/branches/plip11017-tag-selector-rmattb/Products/Archetypes/skins/archetypes/widgets/js/keywordmultiselect.js
Modified:
   Products.Archetypes/trunk/   (props changed)
   Products.Archetypes/trunk/Products/Archetypes/   (props changed)
   Products.Archetypes/trunk/Products/Archetypes/Widget.py
Log:
Merge changes from Tag Selector PLIP. refs #11017.

Modified: Products.Archetypes/trunk/Products/Archetypes/Widget.py
==============================================================================
--- Products.Archetypes/trunk/Products/Archetypes/Widget.py	(original)
+++ Products.Archetypes/trunk/Products/Archetypes/Widget.py	Thu Jan 20 15:09:56 2011
@@ -505,6 +505,7 @@
         'size'  : 5,
         'vocab_source' : 'portal_catalog',
         'roleBasedAdd' : True,
+        'helper_js': ('widgets/js/keywordmultiselect.js',),
         })
 
     security = ClassSecurityInfo()

Copied: Products.Archetypes/trunk/Products/Archetypes/skins/archetypes/widgets/js/keywordmultiselect.js (from r13098, Products.Archetypes/branches/plip11017-tag-selector-rmattb/Products/Archetypes/skins/archetypes/widgets/js/keywordmultiselect.js)
==============================================================================
--- Products.Archetypes/branches/plip11017-tag-selector-rmattb/Products/Archetypes/skins/archetypes/widgets/js/keywordmultiselect.js	(original)
+++ Products.Archetypes/trunk/Products/Archetypes/skins/archetypes/widgets/js/keywordmultiselect.js	Thu Jan 20 15:09:56 2011
@@ -1,26 +1,23 @@
 /*
 // jQuery multiSelect
 //
-// Version 1.2.2 beta
+// Version 1.3
 //
 // Cory S.N. LaViska
 // A Beautiful Site (http://abeautifulsite.net/)
-// 09 September 2009
-//
 // Visit http://abeautifulsite.net/notebook/62 for more information
 //
 // (Amended by Andy Richmond, Letters & Science Deans' Office, University of California, Davis)
 //
-// Usage: $('#control_id').multiSelect( options, callback )
+// (Amended and trimmed for the Plone open source CMS by Matt Barkau, WebLion Group, PSU.edu)
+//
+// Usage: $('#control_id').multiSelect( arguments )
 //
-// Options:  selectAll          - whether or not to display the Select All option; true/false, default = true
-//           selectAllText      - text to display for selecting/unselecting all options simultaneously
+// Arguments:
 //           noneSelected       - text to display when there are no selected items in the list
 //           oneOrMoreSelected  - text to display when there are one or more selected items in the list
 //                                (note: you can use % as a placeholder for the number of items selected).
 //                                Use * to show a comma separated list of all selected; default = '% selected'
-//           optGroupSelectable - whether or not optgroups are selectable if you use them; true/false, default = false
-//           listHeight         - the max height of the droptdown options
 //
 // Dependencies:  jQuery 1.2.6 or higher (http://jquery.com/)
 //
@@ -34,78 +31,60 @@
 //				- Renamed from jqueryMultiSelect.* to jquery.multiSelect.* per the standard recommended at
 //				  http://docs.jquery.com/Plugins/Authoring (does not affect API methods)
 //
-//		1.0.3	- Now uses the bgiframe plugin (if it exists) to fix the IE6 layering bug.
-//              - Forces IE6 to use a min-height of 200px (this needs to be added to the options)
-//
 //		1.1.0	- Added the ability to update the options dynamically via javascript: multiSelectOptionsUpdate(JSON)
 //              - Added a title that displays the whole comma delimited list when using oneOrMoreSelected = *
 //              - Moved some of the functions to be closured to make them private
 //              - Changed the way the keyboard navigation worked to more closely match how a standard dropdown works
 //              - ** by Andy Richmond **
 //
-//		1.2.0	- Added support for optgroups
-//              - Added the ability for selectable optgroups (i.e. select all for an optgroup)
-//              - ** by Andy Richmond **
-//
 //		1.2.1	- Fixed bug where input text overlapped dropdown arrow in IE (i.e. when using oneOrMoreSelected = *)
-//              - Added option "listHeight" for min-height of the dropdown
-//              - Fixed bug where bgiframe was causing a horizontal scrollbar and on short lists extra whitespace below the options
 //              - ** by Andy Richmond **
 //
-//		1.2.2	- Fixed bug where the keypress stopped showing the dropdown because in jQuery 1.3.2 they changed the way ':visible' works
+//		1.2.2	- 06 January 2010 (per http://abeautifulsite.net/blog/2008/04/jquery-multiselect )
+//				- Fixed bug where the keypress stopped showing the dropdown because in jQuery 1.3.2 they changed the way ':visible' works
 //              - Fixed some other bugs in the way the keyboard interface worked
 //              - Changed the main textbox to an <a> tag (with 'display: inline-block') to prevent the display text from being selected/highlighted
 //              - Added the ability to jump to an option by typing the first character of that option (simular to a normal drop down)
 //              - ** by Andy Richmond **
 //				- Added [] to make each control submit an HTML array so $.serialize() works properly
 //
+//		1.3		- 2010 October-November
+//				- Adapted for Plone open source CMS tag selector
+//				- Fixed bug related to mouse hover when using arrow keys
+//				- Improved many areas of keyboard support & accessibility
+//				- see https://dev.plone.org/archetypes/log/Products.Archetypes/branches/plip11017-tag-selector-rmattb/Products/Archetypes/skins/archetypes/widgets/js/keywordmultiselect.js
+//				- ** by Matt Barkau **
+//
 // Licensing & Terms of Use
 // 
 // This plugin is dual-licensed under the GNU General Public License and the MIT License and
 // is copyright 2008 A Beautiful Site, LLC. 
 //	
 */
-if(jQuery) (function($){
+
+// Removed a test for jQuery, since we know it is available.
+(function($){
 	
 	// render the html for a single option
-	function renderOption(id, option)
+	function renderOption(id, option, i, selectName)
 	{
-		var html = '<label><input type="checkbox" name="' + id + '[]" value="' + option.value + '"';
+		// dl, dt, & dd semantically associates selector name with values
+		// label makes the text clickable, like a multiple-select
+		var html = '<dd><label for="tag' + i + '"><input type="checkbox" name="' + selectName + '" value="' + option.value + '" id="tag' + i + '"';
 		if( option.selected ){
 			html += ' checked="checked"';
 		}
-		html += ' />' + option.text + '</label>';
-		
+		html += ' />' + option.text + '</label></dd>';
 		return html;
 	}
 	
 	// render the html for the options/optgroups
-	function renderOptions(id, options, o)
+	function renderOptions(id, options, o, selectName)
 	{
 		var html = "";
-		
 		for(var i = 0; i < options.length; i++) {
-			if(options[i].optgroup) {
-				html += '<label class="optGroup">';
-				
-				if(o.optGroupSelectable) {
-					html += '<input type="checkbox" class="optGroup" />' + options[i].optgroup;
-				}
-				else {
-					html += options[i].optgroup;
-				}
-				
-				html += '</label><div class="optGroupContainer">';
-				
-				html += renderOptions(id, options[i].options, o);
-				
-				html += '</div>';
-			}
-			else {
-				html += renderOption(id, options[i]);
-			}
+			html += renderOption(id, options[i], i, selectName);
 		}
-		
 		return html;
 	}
 	
@@ -115,65 +94,18 @@
 		var multiSelect = $(this);
 		var multiSelectOptions = multiSelect.next('.multiSelectOptions');
 		var o = multiSelect.data("config");
-		var callback = multiSelect.data("callback");
+		
+		$("#existingTagsHelp").text(o.existingTagsHelpText);
 
 		// clear the existing options
 		multiSelectOptions.html("");
 		var html = "";
 
-		// if we should have a select all option then add it
-		if( o.selectAll ) {
-			html += '<label class="selectAll"><input type="checkbox" class="selectAll" />' + o.selectAllText + '</label>';
-		}
-
 		// generate the html for the new options
-		html += renderOptions(multiSelect.attr('id'), options, o);
+		html += renderOptions(multiSelect.attr('id'), options, o, multiSelect.attr('name'));
 		
 		multiSelectOptions.html(html);
 		
-		// variables needed to account for width changes due to a scrollbar
-		var initialWidth = multiSelectOptions.width();
-		var hasScrollbar = false;
-		
-		// set the height of the dropdown options
-		if(multiSelectOptions.height() > o.listHeight) {
-			multiSelectOptions.css("height", o.listHeight + 'px');
-			hasScrollbar = true;
-		} else {
-			multiSelectOptions.css("height", '');
-		}
-		
-		// if the there is a scrollbar and the browser did not already handle adjusting the width (i.e. Firefox) then we will need to manaually add the scrollbar width
-		var scrollbarWidth = hasScrollbar && (initialWidth == multiSelectOptions.width()) ? 17 : 0;
-
-		// set the width of the dropdown options
-		if((multiSelectOptions.width() + scrollbarWidth) < multiSelect.outerWidth()) {
-			multiSelectOptions.css("width", multiSelect.outerWidth() - 2/*border*/ + 'px');
-		} else {
-			multiSelectOptions.css("width", (multiSelectOptions.width() + scrollbarWidth) + 'px');
-		}
-		
-		// Apply bgiframe if available on IE6
-		if( $.fn.bgiframe ) multiSelect.next('.multiSelectOptions').bgiframe( { width: multiSelectOptions.width(), height: multiSelectOptions.height() });
-
-		// Handle selectAll oncheck
-		if(o.selectAll) {
-			multiSelectOptions.find('INPUT.selectAll').click( function() {
-				// update all the child checkboxes
-				multiSelectOptions.find('INPUT:checkbox').attr('checked', $(this).attr('checked')).parent("LABEL").toggleClass('checked', $(this).attr('checked'));
-			});
-		}
-		
-		// Handle OptGroup oncheck
-		if(o.optGroupSelectable) {
-			multiSelectOptions.addClass('optGroupHasCheckboxes');
-		
-			multiSelectOptions.find('INPUT.optGroup').click( function() {
-				// update all the child checkboxes
-				$(this).parent().next().find('INPUT:checkbox').attr('checked', $(this).attr('checked')).parent("LABEL").toggleClass('checked', $(this).attr('checked'));
-			});
-		}
-		
 		// Handle all checkboxes
 		multiSelectOptions.find('INPUT:checkbox').click( function() {
 			// set the label checked class
@@ -181,12 +113,16 @@
 			
 			updateSelected.call(multiSelect);
 			multiSelect.focus();
+			lastNavClickCheckbox = null;
+			// If this checkbox was navigated to with the tab key before being checked, 
+			// then put focus back on it.
+			if(typeof(lastNavTabKeyCheckbox) != "undefined" && lastNavTabKeyCheckbox != null) {
+				lastNavTabKeyCheckbox.focus();
+				lastNavTabKeyCheckbox = null;
+			}
 			if($(this).parent().parent().hasClass('optGroupContainer')) {
 				updateOptGroup.call(multiSelect, $(this).parent().parent().prev());
 			}
-			if( callback ) {
-				callback($(this));
-			}
 		});
 		
 		// Initial display
@@ -194,44 +130,62 @@
 			$(this).find('INPUT:checked').parent().addClass('checked');
 		});
 		
-		// Initialize selected and select all 
+		// Initialize selected
 		updateSelected.call(multiSelect);
 		
-		// Initialize optgroups
-		if(o.optGroupSelectable) {
-			multiSelectOptions.find('LABEL.optGroup').each( function() {
-				updateOptGroup.call(multiSelect, $(this));
-			});
-		}
+		// Handle hovers (entering an option) *and* mouse moving within an option
+		multiSelectOptions.find('LABEL').mousemove( function(e) {
+			// Workaround Safari's errant reporting of mousemove when the mouse hasn't moved.
+			// At this point, the browser is saying that the mouse moved.
+			// Initialize position variables.
+			if(multiSelect.oldPositionX == null || multiSelect.oldPositionY == null) {
+				multiSelect.oldPositionX = e.pageX;
+				multiSelect.oldPositionY = e.pageY;
+			}
+			if( multiSelect.oldPositionX != e.pageX || multiSelect.oldPositionY != e.pageY ) {
+				// At this point, the mouse actually did move.  
+				$(this).parent().parent().find('LABEL').removeClass('hover');
+				$(this).addClass('hover');
+				lastNavTabKeyCheckbox = null;
+				multiSelect.oldPositionX = e.pageX;
+				multiSelect.oldPositionY = e.pageY;
+				multiSelect.focus();
+				adjustViewPort(multiSelectOptions);
+			}
+		});
 		
-		// Handle hovers
-		multiSelectOptions.find('LABEL:has(INPUT)').hover( function() {
-			$(this).parent().find('LABEL').removeClass('hover');
-			$(this).addClass('hover');
-		}, function() {
-			$(this).parent().find('LABEL').removeClass('hover');
+		// Style checkbox parent with tab-driven focus
+		multiSelectOptions.find('LABEL').mousedown(function(){
+			// Track mouse clicks, 
+			// so that tab key navigation focus on checkboxes can be maintained separately.
+			lastNavClickTag = this;
+		});
+		multiSelectOptions.find('INPUT').focus(function(){
+			if(typeof(lastNavClickTag) == "undefined" || lastNavClickTag == null) {
+				// This only happens with tab key navgation.
+				// Must keep track of this, because mouse-driven nav always keeps *focus* on multiSelect, 
+				// while the active multiSelectOptions get *hover*.
+				// Tab navigation is different - it's active option checkbox gets *focus*, 
+				// rather than *hover*, since keyboard navigation never hovers.
+				// If the checkbox is tabbed to & checked , save it so that focus can be put back on it.
+				// Without this, both moused & tabbed checks return focus to multiSelect, 
+				// causing tabbed checkboxes to lose focus.
+				lastNavTabKeyCheckbox = $(this);
+				lastNavTabKeyCheckbox.parent().parent().parent().find('LABEL').removeClass('hover');
+				lastNavTabKeyCheckbox.parent().addClass('hover');
+			}
+			lastNavClickTag = null;
 		});
 		
 		// Keyboard
 		multiSelect.keydown( function(e) {
 		
 			var multiSelectOptions = $(this).next('.multiSelectOptions');
-
+			
 			// Is dropdown visible?
 			if( multiSelectOptions.css('visibility') != 'hidden' ) {
 				// Dropdown is visible
-				// Tab
-				if( e.keyCode == 9 ) {
-					$(this).addClass('focus').trigger('click'); // esc, left, right - hide
-					$(this).focus().next(':input').focus();
-					return true;
-				}
 				
-				// ESC, Left, Right
-				if( e.keyCode == 27 || e.keyCode == 37 || e.keyCode == 39 ) {
-					// Hide dropdown
-					$(this).addClass('focus').trigger('click');
-				}
 				// Down || Up
 				if( e.keyCode == 40 || e.keyCode == 38) {
 					var allOptions = multiSelectOptions.find('LABEL');
@@ -257,6 +211,7 @@
 					if(newHoverIndex >= 0) {
 						$(allOptions.get(oldHoverIndex)).removeClass('hover'); // remove the current highlight
 						$(allOptions.get(newHoverIndex)).addClass('hover'); // add the new highlight
+						lastNavTabKeyCheckbox = null;
 						
 						// Adjust the viewport if necessary
 						adjustViewPort(multiSelectOptions);
@@ -265,6 +220,33 @@
 					return false;
 				}
 
+				// Page up || Page down
+				if( e.keyCode == 33 || e.keyCode == 34) {
+					var allOptions = multiSelectOptions.find('LABEL');
+					var oldHoverIndex = allOptions.index(allOptions.filter('.hover'));
+					var newHoverIndex = -1;
+					var optionsPerPage = 8;  // depends on css
+					// if we are moving up and there is a prev item then move
+					if(e.keyCode == 33 && oldHoverIndex > 0) {
+						newHoverIndex = oldHoverIndex - optionsPerPage;
+						if(newHoverIndex < 0) {
+							newHoverIndex = 0;
+						}
+					}
+					if(e.keyCode == 34 && oldHoverIndex < allOptions.length - 1) {
+						newHoverIndex = oldHoverIndex + optionsPerPage;
+						if(newHoverIndex > allOptions.length - 1) {
+							newHoverIndex = allOptions.length - 1;
+						}
+					}
+					$(allOptions).removeClass('hover'); // remove all highlights
+					$(allOptions.get(newHoverIndex)).addClass('hover'); // add the new highlight
+					lastNavTabKeyCheckbox = null;
+					// Adjust the viewport if necessary
+					adjustViewPort(multiSelectOptions);
+					return false;
+				}
+					
 				// Enter, Space
 				if( e.keyCode == 13 || e.keyCode == 32 ) {
 					var selectedCheckbox = multiSelectOptions.find('LABEL.hover INPUT:checkbox');
@@ -278,8 +260,6 @@
 					}
 
 					updateSelected.call(multiSelect);
-					
-					if( callback ) callback($(this));
 					return false;
 				}
 
@@ -300,26 +280,13 @@
 
 					if(match.length == 1) {
 						// if we found a match then move the hover
-						multiSelectOptions.find('LABEL.hover').removeClass('hover');								
+						multiSelectOptions.find('LABEL.hover').removeClass('hover');
 						match.addClass('hover');
+						lastNavTabKeyCheckbox = null;
 						
 						adjustViewPort(multiSelectOptions);
 					}
 				}
-			} else {
-				// Dropdown is not visible
-				if( e.keyCode == 38 || e.keyCode == 40 || e.keyCode == 13 || e.keyCode == 32 ) { //up, down, enter, space - show
-					// Show dropdown
-					$(this).removeClass('focus').trigger('click');
-					multiSelectOptions.find('LABEL:first').addClass('hover');
-					return false;
-				}
-				//  Tab key
-				if( e.keyCode == 9 ) {
-					// Shift focus to next INPUT element on page
-					multiSelectOptions.next(':input').focus();
-					return true;
-				}
 			}
 			// Prevent enter key from submitting form
 			if( e.keyCode == 13 ) return false;
@@ -329,165 +296,98 @@
 	// Adjust the viewport if necessary
 	function adjustViewPort(multiSelectOptions)
 	{
-		// check for and move down
-		var selectionBottom = multiSelectOptions.find('LABEL.hover').position().top + multiSelectOptions.find('LABEL.hover').outerHeight();
-		
-		if(selectionBottom > multiSelectOptions.innerHeight()){		
-			multiSelectOptions.scrollTop(multiSelectOptions.scrollTop() + selectionBottom - multiSelectOptions.innerHeight());
-		}
-		
-		// check for and move up						
-		if(multiSelectOptions.find('LABEL.hover').position().top < 0){		
-			multiSelectOptions.scrollTop(multiSelectOptions.scrollTop() + multiSelectOptions.find('LABEL.hover').position().top);
-		}
-	}
-	
-	// Update the optgroup checked status
-	function updateOptGroup(optGroup)
-	{
-		var multiSelect = $(this);
-		var o = multiSelect.data("config");
-		
-		// Determine if the optgroup should be checked
-		if(o.optGroupSelectable) {
-			var optGroupSelected = true;
-			$(optGroup).next().find('INPUT:checkbox').each( function() {
-				if( !$(this).attr('checked') ) {
-					optGroupSelected = false;
-					return false;
-				}
-			});
-			
-			$(optGroup).find('INPUT.optGroup').attr('checked', optGroupSelected).parent("LABEL").toggleClass('checked', optGroupSelected);
+		// check for and move scrollbar down, content up
+		var hoverTop = multiSelectOptions.find('LABEL.hover').position().top;
+		var hoverHeight = multiSelectOptions.find('LABEL.hover').outerHeight();
+		var selectionBottom = hoverTop + hoverHeight;
+		// The integer 18 is a manual approximation for typical scale, 
+		// since there's extra padding at the top of the div.multiSelectOptions
+		// which is not showing up anywhere quantitatively. 
+		// Could use improvement.
+		var optionsHeight = multiSelectOptions.outerHeight() + 18;
+		var optionsScrollTop = multiSelectOptions.scrollTop();
+		if(selectionBottom > optionsHeight){		
+			multiSelectOptions.scrollTop(optionsScrollTop + selectionBottom - optionsHeight);
+		}
+		
+		// check for and move scrollbar up, content down
+		var hoveredTop = multiSelectOptions.find('LABEL.hover').position().top;
+		var optionsTop = multiSelectOptions.position().top;
+		var optionsScrollTop = multiSelectOptions.scrollTop();
+		if(hoveredTop < optionsTop){		
+			multiSelectOptions.scrollTop(optionsScrollTop + hoveredTop - optionsTop);
 		}
 	}
 	
-	// Update the textbox with the total number of selected items, and determine select all
+	// Update the textbox with the total number of selected items
 	function updateSelected() {
 		var multiSelect = $(this);
 		var multiSelectOptions = multiSelect.next('.multiSelectOptions');
 		var o = multiSelect.data("config");
-		
 		var i = 0;
 		var selectAll = true;
 		var display = '';
 		multiSelectOptions.find('INPUT:checkbox').not('.selectAll, .optGroup').each( function() {
 			if( $(this).attr('checked') ) {
 				i++;
-				display = display + $(this).parent().text() + ', ';
+				display = 
+					display + 
+					'<p class="selectedTag"><span class="selectedTag">' + 
+					$(this).parent().text() + 
+					'</span></p>';
 			}
 			else selectAll = false;
 		});
 		
-		// trim any end comma and surounding whitespace
-		display = display.replace(/\s*\,\s*$/,'');
-		
 		if( i == 0 ) {
-			multiSelect.find("span").html( o.noneSelected );
+			$("#selectedTagsHeading").html( o.noneSelected );
+			$("#selectedTags").text('');
 		} else {
-			if( o.oneOrMoreSelected == '*' ) {
-				multiSelect.find("span").html( display );
-				multiSelect.attr( "title", display );
-			} else {
-				multiSelect.find("span").html( o.oneOrMoreSelected.replace('%', i) );
-			}
-		}
-
-		// Determine if Select All should be checked
-		if(o.selectAll) {
-			multiSelectOptions.find('INPUT.selectAll').attr('checked', selectAll).parent("LABEL").toggleClass('checked', selectAll);
+			$("#selectedTags").html( display )
+			$("#selectedTagsHeading").html( o.oneOrMoreSelected.replace('%', i) );
 		}
 	}
 	
 	$.extend($.fn, {
-		multiSelect: function(o, callback) {
+		multiSelect: function(o) {
 			// Default options
 			if( !o ) o = {};
-			if( o.selectAll == undefined ) o.selectAll = true;
-			if( o.selectAllText == undefined ) o.selectAllText = "Select All";
-			if( o.noneSelected == undefined ) o.noneSelected = 'Select options';
-			if( o.oneOrMoreSelected == undefined ) o.oneOrMoreSelected = '% selected';
-			if( o.optGroupSelectable == undefined ) o.optGroupSelectable = false;
-			if( o.listHeight == undefined ) o.listHeight = 150;
 
 			// Initialize each multiSelect
 			$(this).each( function() {
 				var select = $(this);
-				var html = '<a href="javascript:;" class="multiSelect"><span></span></a>';
-				html += '<div class="multiSelectOptions" style="position: absolute; z-index: 99999; visibility: hidden;"></div>';
+				// anchor originally used for dropdown
+				var html = '<a href="javascript:;" class="multiSelect" tabindex="1"><span></span></a>';
+				// overflow-y: auto enables the scrollbar, like a multiple-select
+				html += '<div class="multiSelectOptions" tabindex="9999" style="overflow-y: auto;"></div>';
+				//display:block makes the blank area right of the text clickable, like a multiple-select
+				html += '<style type="text/css">label {display: block;}</style>';
 				$(select).after(html);
 				
 				var multiSelect = $(select).next('.multiSelect');
 				var multiSelectOptions = multiSelect.next('.multiSelectOptions');
 				
-				// if the select object had a width defined then match the new multilsect to it
-				multiSelect.find("span").css("width", $(select).width() + 'px');
-				
 				// Attach the config options to the multiselect
 				multiSelect.data("config", o);
 				
-				// Attach the callback to the multiselect
-				multiSelect.data("callback", callback);
-				
 				// Serialize the select options into json options
 				var options = [];
 				$(select).children().each( function() {
-					if(this.tagName.toUpperCase() == 'OPTGROUP')
-					{
-						var suboptions = [];
-						options.push({ optgroup: $(this).attr('label'), options: suboptions });
-						
-						$(this).children('OPTION').each( function() {
-							if( $(this).val() != '' ) {
-								suboptions.push({ text: $(this).html(), value: $(this).val(), selected: $(this).attr('selected') });
-							}
-						});
-					}
-					else if(this.tagName.toUpperCase() == 'OPTION')
-					{
-						if( $(this).val() != '' ) {
-							options.push({ text: $(this).html(), value: $(this).val(), selected: $(this).attr('selected') });
-						}
+					if( $(this).val() != '' ) {
+						options.push({ text: $(this).html(), value: $(this).val(), selected: $(this).attr('selected') });
 					}
 				});
 				
 				// Eliminate the original form element
 				$(select).remove();
 				
-				// Add the id that was on the original select element to the new input
+				// Add the id & name that was on the original select element to the new input
 				multiSelect.attr("id", $(select).attr("id"));
+				multiSelect.attr("name", $(select).attr("name"));
 				
 				// Build the dropdown options
 				buildOptions.call(multiSelect, options);
-
-				// Events
-				multiSelect.hover( function() {
-					$(this).addClass('hover');
-				}, function() {
-					$(this).removeClass('hover');
-				}).click( function() {
-					// Show/hide on click
-					if( $(this).hasClass('active') ) {
-						$(this).multiSelectOptionsHide();
-					} else {
-						$(this).multiSelectOptionsShow();
-					}
-					return false;
-				}).focus( function() {
-					// So it can be styled with CSS
-					$(this).addClass('focus');
-				}).blur( function() {
-					// So it can be styled with CSS
-					$(this).removeClass('focus');
-				});
-				
-				// Add an event listener to the window to close the multiselect if the user clicks off
-				$(document).click( function(event) {
-					// If somewhere outside of the multiselect was clicked then hide the multiselect
-					if(!($(event.target).parents().andSelf().is('.multiSelectOptions'))){
-						multiSelect.multiSelectOptionsHide();
-					}
-				});
+			
 			});
 		},
 		
@@ -496,36 +396,10 @@
 			buildOptions.call($(this), options);
 		},
 		
-		// Hide the dropdown
-		multiSelectOptionsHide: function() {
-			$(this).removeClass('active').removeClass('hover').next('.multiSelectOptions').css('visibility', 'hidden');
-		},
-		
-		// Show the dropdown
-		multiSelectOptionsShow: function() {
-			var multiSelect = $(this);
-			var multiSelectOptions = multiSelect.next('.multiSelectOptions');
-			var o = multiSelect.data("config");
-		
-			// Hide any open option boxes
-			$('.multiSelect').multiSelectOptionsHide();
-			multiSelectOptions.find('LABEL').removeClass('hover');
-			multiSelect.addClass('active').next('.multiSelectOptions').css('visibility', 'visible');
-			multiSelect.focus();
-			
-			// reset the scroll to the top
-			multiSelect.next('.multiSelectOptions').scrollTop(0);
-
-			// Position it
-			var offset = multiSelect.position();
-			multiSelect.next('.multiSelectOptions').css({ top:  offset.top + $(this).outerHeight() + 'px' });
-			multiSelect.next('.multiSelectOptions').css({ left: offset.left + 'px' });
-		},
-		
-		// get a coma-delimited list of selected values
+		// get a comma-delimited list of selected values
 		selectedValuesString: function() {
 			var selectedValues = "";
-			$(this).next('.multiSelectOptions').find('INPUT:checkbox:checked').not('.optGroup, .selectAll').each(function() {
+			$(this).next('.multiSelectOptions').find('INPUT:checkbox:checked').not('.optGroup, .selectAll')(function() {
 				selectedValues += $(this).attr('value') + ",";
 			});
 			// trim any end comma and surounding whitespace

------------------------------------------------------------------------------
Protect Your Site and Customers from Malware Attacks
Learn about various malware tactics and how to avoid them. Understand 
malware threats, the impact they can have on your business, and how you 
can protect your company and customers by using code signing.
http://p.sf.net/sfu/oracle-sfdevnl
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.