Pod trochu tajemným názvem se neskrývá nic jiného než umění pracovat s událostmi. Co se v prohlížeči vlastně děje, jak by měl model událostí podle specifikace W3C pracovat a jaká je jeho současná implementace?

Tak jako vždy předpokládám základní znalost pojmů jako je událost nebo ovladač události. Pokud jste se ještě s nimi vůbec nesetkali, doporučuji článek Slabikář JavaScriptu – události myši a objekt Event nebo Myší události – základní syntaxe, kde se dozvíte nutné informace k úspěšnému pochopení tohoto textu. A protože budu opět potřebovat HTML kód, vrátím se k zápisu html_zapis_1, na němž budu některé poznatky demonstrovat.

 <div id=“div1″>
   <span id=“text1″> Hello world</span>
   <span id=“text2″> Hello world</span>
 </div>

Událost jako attribut

Víte-li předem, že nějaký element v dokumentu bude kromě informační hodnoty zpracovávat i nějakou událost, nejjednodušším řešením je ovladač, je-li součástí DTD příslušného dokumentu, zahrnout přímo do zápisu (X)HTML. Tento způsob vychází z prvních pokusů o začlenění událostí do webových dokumentů, jež W3C standardizoval ve svém HTML 4.0. Takovýto zápis vypadá například následovně: <span id="text1" onClick="Javascript: alert('Interval');"> Hello world </span>. Dáme tím najevo, že po kliknutí myší (ovladač onclick) na element span se spustí kód JS. V tomto případě vyskočí alert box.

Na úrovni Javascriptu je téměř ekvivalentní vlastnost psaná malými písmeny, v tomto případě document.getElementById('text1').onclick. Otevírá se tak možnost využít JS k pozdějšímu přiřazování nebo modifikaci handle události, což statická úroveň HTML pochopitelně neumožňuje. Slovo ‚téměř‘ jsem použil záměrně, neboť ačkoli HTML zápis vypadá jako klasický textový atribut, na úrovni JS je již funkcí. Proto bude marná snaha přepsat jej způsobem document.getElementById('text1').onclick = "Javascript:alert(0);" . V zápise níže vidíte tři postupy, jak dynamicky registrovat či měnit událost a přiřadit jí vykonávající JS kód. V prvním je přirazena již existující funkce click(), v dalších dvou jsou uvedeny různé verze inline definice. Poslední konstrukce je postup odstranění ovladače.

 // Prvni zpusob registrace
 function click() {alert(‚Interval.cz‘);}
 document.getElementById(‚text1‘).onclick = click;
 // Druhy zpusob registrace
 document.getElementById(‚text1‘).onclick = function() {alert(‚Interval.cz‘);}
 // Treti zpusob registrace
 document.getElementById(‚text1‘).onclick = new Function(„alert(‚Interval.cz‘);“);
 // Ostraneni ovladace
 document.getElementById(‚text1‘).onclick = null;

Objekt Event

Na tomto místě končí shoda mezi standardy a prohlížeči, respektive standardem W3C, které v zásadě podporuje Mozilla/NS, a prohlížečem Internet Explorer. Existuje určité společné jádro, ale tento průnik je malý. Začneme tedy objektem Event, který reprezentuje vyvolanou událost a shrnuje její vlastnosti. Důkazem předchozího tvrzení je chování IE, který u atributově registrovaných ovladačů definuje tento objekt automaticky jako globální proměnnou vykonávající funkce, ačkoli má být předáván jako první parametr dané funkce. Řešením je buď kód podmiňovat pro jednotlivé prohlížeče nebo funkci přiřadit parametr (např. e ) a na začátek vložit uvedenou jednořádkovou konstrukci napravující rozdíl. Možná vás napadá, proč nepojmenovat parametr přímo event. Důvodem je možné přepsání globální proměnné event stejnojmenným prázdným parametrem. Pak bychom se k žádanému objektu nedostali.

// Ziskaní objektu Event
document.getElementById(‚text1‘).onclick = s;
function s(e)
 {
  if(e) {event = e;}
  alert(event.type);
 }

Základní rozhraní objektu Event nese užitečné údaje, například fázi zpracování události, její typ apod. Následně je rozšiřováno podle toho, o jaký konkrétní typ se jedná, rozhraními MouseEvents (události myši), HTMLEvents (události HTML) a MutationEvents (událost struktury dokumentu). Vstupy z klávesnice jsou standardizovány až od veze W3C DOM LEVEL3 pod názvem TextEvents. To však ještě nemá oporu v prohlížečích. Proto je stále používaná zaběhnutá vlastnost keyCode uchovávající hodnotu stisknutého znaku. Jak sami vidíte, zpracování událostí u obou prohlížečů je více či méně odlišné od standardu, proto doporučuji přímé reference výrobců Mozilla a Microsoft.

Pokročilá registrace událostí

Kromě ovladačů typu atribut definuje DOM tzv. posluchače, které lze na jakýkoli objekt „zavěsit“. Ty pak naslouchají dění v prohlížeči a spouští přiřazený kód. Pokud toto rozhraní implementace DOMu podporuje, každý objekt je zároveň tzv. EventTarget, disponující metodami přiřazení a odstranění posluchače a možností umělého vyvolání libovolné události. Možná namítnete, že je to identické jako první způsob, navíc mírně komplikovanější. Složitější tento postup je, ale má minimálně dvě výhody. Jednak lze přiřadit libovolný počet posluchačů stejné události k jednomu objektu a IE konečně předává objekt Event i jako první parametr. Bohužel radost zkazí názvy příslušných metod, které IE zase pojmenovává odlišně. Syntaxe přidání a odstranění události je tedy následující, přičemž parametr udalost je typem události (např. onmouseclick u IE a mouseclick u mozilly), funkce je označení metody, která se vyvolá a typ značí užití zachytávání.

 // Syntaxe u IE
 document.getElementById(‚text1‘).attachEvent(udalost, funkce);
 document.getElementById(‚text1‘).detachEvent(udalost, funkce);
 // Syntaxe u W3C – Mozilla/NS
 document.getElementById(‚text1‘).addEventListener(udalost, funkce, typ);
 document.getElementById(‚text1‘).removeEventListener(udalost, funkce, typ);

Zachytávání a probublávání

Nyní se dostavám k tomu, jak vlastně události pracují a co se vlastně v prohlížeči děje, když nějakou vyvoláte. Bohužel i zde IE nedodržuje navržený standard, ačkoli se na něm podílel. Proto pojednání o zachytávání patří pouze Mozille. IE zná sice metody setCapture a releaseCapture, ale ty fungují na odlišném principu. Vraťme se k zápisu html_zapis_1 a předpokládejme, že na některém ze vnořených elementů span je pověšen ovladač události, například onclick. Jakmile kliknete na daný element, ohlášení události prostupuje celou větví uzlů od nejvyššího #document, přes uzly html, head, body, div, až k cílenému span. Pokud má po této cestě některý z uzlů nastaveno zachytávání (capture) daného typu události, což v praxi znamená, že parametr typ při volání procedury addEventListener je true, událost se vyhodnotí a spustí se příslušná procedura. Ukázkový příklad práce se zachytáváním je v dokumentu capture.htm

Dojde-li událost až k cílovému elementu, provede obrazně řečeno obrat o 180° a stejnou cestou jde zpět až k uzlu #document. Této fázi se říká probublávání, snad podle stoupajících bublinek v nejmenovaných přeslazených nápojích. K pochopení jistě poslouží dokument bubble.htm, jež je podobný předchozímu zachytávání s tím rozdílem, že pracuje opačným směrem a je spustitelný i v IE. Malá poznámka na závěr, je-li událost zachycena již cestou k cílovému elementu, ve fázi bublání je ignorována.

Obě fáze ohlašování vzniku události lze jednouše přerušit. V následujících zápisech vidíte, jak se zastavení nechtěného probublávání nebo prostupovaní provádí:

function klik(event)
{
 // Zastaveni probublani u IE
 if(IE) {event.cancelBubble = true;}
 // Zastaveni probublani ci postupovani u Mozilla/NS
 if(NS) {event.stopPropagation();}
}

Při čtení příslušných rozhraní jste si mohli všimnout, že W3C DOM povoluje i automatické vyvolávání libovolné události, aniž by k ní reálně došlo. Avšak zatím mě nenapadá nějaké rozumné využití této ‚feature‘. Zato negativní dopad může mít pro nepříznivce automatického a nevyžádaného vyskakování po-pup oken, neboť tímto postupem lze u prohlížečů Mozilla/NS obejít monitorovací programy. Jen pro ilustraci jsem vyzkoušel dokument popup.htm na firewall ZoneAlarm, který přidává do každého HTML kódu deaktivaci metody open objektu window a prohlížeč Phoenix 0.4. Ten má tuto ochranu zabudovanou přímo. Bohužel žádný z nich nebyl úspěšný.

Popisek elemetu

Na závěr jeden typický příklad na procvičení výše uvedených informací. Jistě znáte atribut TITLE značky IMG, který se po najetí myši na obrázek po menší časové prodlevě objeví. Úkolem toho skriptu je vytvořit jeho dynamickou verzi s možností případného využití HTML, navíc použitelnou pro všechny elementy dokumentu. Celý kód uvádět nebudu, neb si myslím, že je lehce pochopitelný a je k dispozici v ukázce. Samotný popisek je definován pouze jednou, jelikož by nemělo smysl stále dokola vytvářet a mazat stále stejnou strukturu. Proto se mění pouze jeho textový obsah. Pro použití stačí vložit do dokumentu knihovnu title2.js, přiřadit funkcí pridejPopis() elementům žádaný popisek a vše dokončit metodou initPopis(). Její tělo pak přiřadí dotyčným elementům pomocí výše zmíněných metod addEventListener|attachEvent reakci na myš v podobě zobrazení, resp. skrytí popisu.

Všechny soubory použité v tomto díle si můžete najednou stáhnout v souboru dhtml5.zip

Starší komentáře ke článku

Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.

Žádný příspěvek v diskuzi

Odpovědět