Obsługa klawiszy shift i ctrl w javascript.. na żywym przykładzie :)

Pewną bolączką webowych interfejsów użytkownika, jest brak niektórych możliwości jakie można na co dzień spotkać w interfejsach systemów operacyjnych. Jednym z takich brakujących elementów, jest możliwość wybierania myszką wielu pozycji z listy, wspomagając się klawiszami SHIFT i CTRL. Pora więc nadrobić braki i wykonać mechanizm implementujący taką funkcję na stronie WWW. Jak się okaże, nie jest to nic trudnego.

Zacznijmy od utworzenia kodu HTML naszej listy wyboru. Kolejne elementy listy będą umieszczone na oddzielnych warstwach, chociaż nic nie stoi na przeszkodzie aby były to inne elementy, na przykład wiersze tabeli lub wypunktowania. Wszystkie elementy zgrupujemy na warstwie głównej, co ułatwi nam automatyczne przypisywanie do nich zdarzeń. Nasz kod może wyglądać w ten sposób:

<div id="ListaDiv">
<div><input type="checkbox"> Opcja nr 1</div>
<div><input type="checkbox"> Opcja nr 2</div>
<div><input type="checkbox"> Opcja nr 3</div>
<div><input type="checkbox"> Opcja nr 4</div>
</div>

Następnie, poszczególnym Divom odpowiadającym kolejnym elementom naszej listy powinniśmy przypisać zdarzenie onclick tak aby reagowały na kliknięcie na nich myszką. Napiszemy więc funkcję przypisz(), która pobierze wszystkie Divy należące do listy i w pętli przypisze im handler zdarzenia onclick:

var ListKontenerID='ListaDiv';
 
function przypisz() {
 var x=document.getElementById(ListKontenerID).getElementsByTagName('div');
 for(var i=0;i&amp;ltx.length;i++) {
  x[i].onclick = klik;
  x[i].setAttribute('numer',i);
 }
}

Tutaj należą się dwa słowa wyjaśnienia. Zdarzenia dodajemy poprzez przypisanie elementowi nazwy funkcji, która obsłuży nasze kliknięcia. Zgodnie z specyfikacją DOM Level 2 powinniśmy to robić za pomocą metody addEventListener(), jednakże jak na razie ani Opera ani MSIE nie obsługują tego modelu zdarzeń.

Dodatkowo, w pętli numerujemy sobie poszczególne warstwy, tak abyśmy później szybko mogli stwierdzić, który w kolejności element listy został kliknięty. Numerację wykonujemy poprzez dodanie do Diva nowego atrybutu o nazwie “numer”.

Funkcję przypisz() powinniśmy wywoływać po załadowaniu strony, np. w zdarzeniu onload:

Zanim przejdziemy do właściwej obsługi zdarzenia onclick, utwórzmy jeszcze dwie funkcje pomocnicze, które będą nam zaznaczać i odznaczać wskazany element listy:

function zaznacz(obiekt) {
 obiekt.setAttribute('wybrany','wybrany');
 obiekt.className='podswietlony';
}
 
function odznacz(obiekt) {
 obiekt.setAttribute('wybrany','');
 obiekt.className='';
}

W tych funkcjach można zaimplementować dowolnie skomplikowane akcje; istotne jest aby pozostawić jedynie ustawianie i gaszenie atrybutu “wybrany”, który będzie wykorzystywany podczas obsługi zdarzeń. W przykładzie powyżej, wykonujemy dodatkowo jedynie ustawianie stylu “podswietlony” do wybranego elementu.

Po przygotowaniu terenu działań możemy przystąpić do implementacji najważniejszej funkcji przechwytującej zdarzenia. Jak się okazuje, sprawdzenie czy był wciśnięty klawisz shift lub ctrl jest banalnie proste: obiekt zdarzenia przechowuje właściwości o nazwie shiftKey oraz ctrlKey. Wystarczy więc sprawdzić jej stan podczas kliknięcia myszką i zależnie od wyniku podjąć odpowiednią akcję:

function klik(e) {
	if (!e &amp;&amp; event) {
		e=event;
		e.target=event.srcElement;
	}
 
	if (e.shiftKey &amp;&amp; PoprzedniNumer!=null) {
 
		var n1=e.target.getAttribute('numer');
		var n2=PoprzedniNumer;
 
		if (n1&gt;n2) { var tmp=n2; n2=n1; n1=tmp; }
		x=document.getElementById(ListKontenerID).getElementsByTagName('div');
 
		for(var i=n1;i&lt;=n2;i++) {
			zaznacz(x[i]);
		}
 
	} else if (e.ctrlKey) {
		if (e.target.getAttribute('wybrany')!='wybrany') {
			zaznacz(e.target);
		} else {
			odznacz(e.target);
		}		
 
	} else {
		x=document.getElementById(ListKontenerID).getElementsByTagName('div');
		for(var i=0;i&lt;x.length;i++) {
			odznacz(x[i]);
		}
 
		if (e.target.getAttribute('wybrany')!='wybrany') {
			zaznacz(e.target);
		} else {
			odznacz(e.target);
		}
	}
 
	PoprzedniNumer=e.target.getAttribute('numer');
 
	return false;
}

Działające demo można zobaczyć tutaj: detekcja klawiszy specjalnych w javascript.