Il y a plusieurs méthodes d'accomplir ce que nous désirons, commençons par la plus simple, avec un morceau de code:

function moveSelected(from, to) {
 
	var from	= document.getElementById(from);
	var to		= document.getElementById(to);
 
	if (from.type != 'select-mutiple' || to.type != 'select-multiple') {
	
		return false;
	
	}
	
	to.options[to.options.length] = new Option(from.options[from.options.selectedIndex].text);
	from.options[from.options.selectedIndex] = null;
	
	return true;
	
}

Bon alors d'abord, on met les objets select dans des variables, parceque DOM c'est sympa, mais l'API est vraiment indigeste (pour rester poli). Ensuite on a la présence d'esprit de vérifier que les deux objets sont bien du type voulus, parceque bon, faut pas nous prendre pour une tulipe non plus.

C'est après que cela devient interressant. L'objet HTMLSelectElement (c'est le nom que fournit un alert(from)) intègre un objet Option, accessible via from.options (oui tous les exemples utiliseront la variable from, ce sera plus simple). Cet objet dispose de quelques méthodes (dont je vous passerais le détail parceque 1) c'est pas le but de cet article et 2) j'y connais pas grand chose finalement), mais ce qui nous interresse vraiment sont ses attributs, et en particulier l'attribut selectedIndex, qui retourne l'index de l'élément sélectionné dans l'objet select. Il ne nous reste plus qu'a créer un nouvel objet Options dans le select destinataire, à supprimer l'entrée correspondante dans le from, et le tour est joué.

Cette méthode fonctionne, mais ne permet le déplacement que d'un seul élement à la fois, ce qui peut s'avérer lourd à l'utilisation dans certains cas. Pour remédier à cela, nous allons maintenant voir une version qui permet de déplacer plusieurs éléments d'un seul coup:

function moveSelected(from, to) {
 
	from	= document.getElementById(from);
	to		= document.getElementById(to);
 
	if (from.type != 'select-mutiple' || to.type != 'select-multiple') {
	
		return false;
	
	}
	
	len = from.options.length - 1;
	
	for (i = len; i >= 0; i--) {
	
		if (from.options[i].selected) {
		
			to.options[to.options.length] = new Option(from.options[i].text);
			from.options[i] = null;
			
		}
			
	}
	
	return true;
		
}

Pour se faire, on n'utilise plus l'attribut selectedIndex, mais on boucle sur tous les éléments pour voir lesquels sont sélectionnés, et on les déplace en conséquence. Le seul piège à éviter, c'est le sens de la boucle. Si on commence à zéro, un problème se pose dès lors qu'on déplace un élément. En effet, dès qu'un élément est supprimé d'une liste, les autres éléments sont retriés. Exemple, si on a une liste de deux éléments, foo et bar, et que foo est sélectionné; la première itération, d'index 0, concerne foo, qui sera déplacé, entrainant automatiquement l'accès de bar à l'index 0. Le problème qui se pose étant que notre boucle, elle, continuera à l'index 1, qui n'existe plus.

C'est clair ?

Donc pour éviter ça, on boucle à partir de la fin, c'est aussi simple que ça :-) Le reste du code est fondamentalement le même, donc pas de problème de ce côté là.