Pokročilé zpracování událostí napříč platformami podruhé
Když jsem před několika dny četl předchozí článek o zpracování událostí, ihned se mi v textu nastíněná idea zalíbila. Přes zdařilý nápad jsem se kriticky vyjádřil, že řešení problému jde opačným směrem, než bych si osobně představoval. Od této diskuse nebylo daleko k myšlence sjednocení modelu událostí dnešních prohlížečů podle W3C standardu.
Ve zmíněném článku byl totiž upřednostňován model IE na úkor ostatních prohlížečů, respektive standardu. Princip níže popisované knihovny je v základu stejný (nahrazení, respektive vytvoření vykonávajících „mezifunkcí“), s tím rozdílem, že tento postup je rozvíjen dále. Jak tento experiment dopadl, se můžete nyní přesvědčit.
Nejprve však malé ohlednutí proč vlastně tento fix vznikl. Jak jste se již mnozí v jiných článcích dočetli, model událostí patří k té oblasti, která se u prohlížečů liší, často naprosto diametrálně. Primátem je v tomto Internet Explorer, mezi jehož největší nedostatky patří:
- chybějící implementace zachytávání událostí
- odlišný způsob dynamické registrace (odstranění) posluchačů
- odlišnost a absence atributů objektu Event
- používání přípon „on“
Prohlížeč Mozilla (jádro), je na tom o poznání lépe, nicméně i to obsahuje jednu nepřesnost. Pakliže chceme dostát našemu požadavku identického chování, nesmíme ji opomenout. Podle W3C se ovladač zachytávané události nemá vyvolávat, jestliže je událost vyvolána přímo elementem, jemuž byl posluchač registrován. Jinými slovy, registrujete-li ovladač způsobem elm.addEventListener('mousedown', klik, true)
, přímé kliknutí na element elm
nesmí vyvolat funkci klik()
. Tento aspekt jádro Mozilly porušuje. Co se týče nové Opery 7, ta podle všeho doporučení respektuje.
Registrace (odstranění) posluchače
Narozdíl od předchozího textu nebudu vytvářet zvláštní objekt obsahující nové metody addEventListener/removeEventListener
. Abychom ve výsledku nepoznali rozdíl při práci na Mozille a IE, nové metody spojíme přímo s elementy. Začneme tedy funkcí fixElement()
, která elementu přidá „softwarově“ vytvořené metody addEventListener
a removeEventLister
.
function fixElement(elm)
{
if(document.all && !document.addEventListener)
{
elm.addEventListener = function(handle, fce, typ)
{ ……}
elm.removeEventListener = function(handle, fce, typ)
{ ……}
}
Podle první podmínky vidíte, že se budu nejprve zabývat metodami pro IE. Metoda addEventListener
je náhrada existujícího attachEvent
s tím, že vykoná ještě kroky, které budeme později nutně potřebovat. Především je to vytvoření dvou matic typů událostí a jim odpovídajících ovladačů (funkcí), které jsou k danému elementu registrovány. Matice proto, neboť typů událostí je více (řádky), stejně tak k jednomu typu události může být pověšeno více funkcí (sloupce). Jedna matice odpovídá událostem zachytávaným, druhá bublajícím. Při vyvolání této metody se tedy vloží reference na funkci na odpovídající místo v matici a poté pomocí attachEvent
„fyzicky“ registruje posluchač s ovladačem makeIE
. Ten funguje jako zmiňovaná „mezifunkce“ obstarávající zbylou režii.
elm.addEventListener = function(handle, fce, typ)
{
// Existuje již řádek toho typu události ?
if(!this.captures[handle]) this.captures[handle]=new Array();
if(!this.bubbles[handle]) this.bubbles[handle]=new Array();
if(this.captures[handle].length==0 && this.bubbles[handle].length==0)
eval(„this.attachEvent(\“on\“+handle, makeIE);“);
if(typ)
{
this.captures[handle][this.captures[handle].length] = fce;
this.captures[handle][this.captures[handle].length] = this;
}
else
{
this.bubbles[handle][this.bubbles[handle].length] = fce;
this.bubbles[handle][this.bubbles[handle].length] = this;
}
}
Metoda removeEventListener
je podobného ražení, funguje však opačným směrem. Podle zadaných parametrů nalezne v matici odpovídající typ události (řádek) a název funkce (sloupec). Odstranění z matice probíhá trošku kostrbatěji, ale bohužel IE5 nezná metodu splice
. Na závěr musíme pomocí detachEvent
zrušit opravdový posluchač události, pokud je řádek v maticích daného typu události prázdný.
….
if(this.captures[handle].length==0 && this.bubbles[handle].length==0)
{
eval(„this.detachEvent(\“on\“+handle, makeIE);“);
}
…
U Mozilly je situace odlišná. Především tak složité řešení nepotřebujeme, navíc metody již existují. Našim cílem je před vyvoláním funkce vložit podmínku, opravující vyřčené tvrzení. Řešení spočívá v tom, že nově vytvořená metoda addEventListener2
dynamicky vytvoří novou funkci (mezifunkce). Ta obsahuje ve svém těle požadovanou podmínku, která, je-li splněna, vyvolá původní funkci. Tato mezifunkce se pak registruje jako ovladač dané události.
Zpracování události u IE
Jak jste doufám z předchozích řádků pochopili, každé IE události je přirazena funkce makeIE
, jejíž účel je zřejmý. Uměle provést všechny fáze ohlášení události a doplnit objekt Event
o potřebné parametry tak, aby co nejvíce splňoval doporučení W3C. K těmto krokům ale potřebuje získat některé informace. Element, který byl cílem události (event.target) známe, byť pod jiným názvem (event.srcElement). Aby funkce byla schopna provést odhlášení od document k elementu (zachytávání) a od elementu k document (bublání), musí znát cestu, respektive elementy, které sdílí větev v stromové hierarchii dokumentu. Jednoduchým cyklem cestu najdeme a u každého elementu, který po cestě „potkáme“, zaznamenáme registrované posluchače a podle typu je vložíme do seznamu toCapture
nebo toBubble
.
…
while(temp)
{
if(temp.bubbles[event.type])toBubble = toBubble.concat(temp.bubbles[event.type]);
if(temp.captures[event.type])toCapture = toCapture.concat(temp.captures[event.type]);
if(temp.nodeName == „HTML“) {temp = document;}
else {temp = temp.parentNode;}
}
…
Nyní již máme všechna potřebná data a nic nebrání doplnění objektu Event o standardní prvky, emulaci zachytávání zpětným průchodem seznamu toCapture
a emulaci bublání průchodem seznamu toBubble
. V závěru pak musíme zabránit opravdovému bublání, neboť by se tento postup mohl nežádaně opakovat.
…
/// Faze zachytavani
event.eventPhase=1;
for(x=toCapture.length-1; (x>=0 && event.stop==false); x=x-2)
{
event.currentTarget = toCapture[x];
toCapture[x-1](event);
}
….
Použití
Cílem této knihovny je zajistit stejné chování v prohlížečích jádra Internet Explorer 5+ a jádra Mozilla 0.9.1+. Před využíváním je třeba (nejlépe po načtení stránky) upravit všechny elementy dokumentu. Pro tento případ slouží funkce fixAllElements()
, procházející celý dokument a aplikující fixElement()
na každý jeho prvek. Jako výsledek vám bude k dispozici v rámci možností jednotné rozhraní a chování modelu událostí. Jako drobnou ilustraci doporučuji vytvořený testovací příklad events.htm, případně jednoduchou aplikaci drag.htm.
Vše má i své stinné stránky. Pokud se podíváte do zdroje, zjistíte, že zpracování události si žádá větší režii, víceméně danou požadavky na standardní chování. To se na starých konfiguracích projevuje delší odezvou u náročných řetězení, například typu drag&drop. Ačkoli se prohlížeče chovají „standardně“, nemohu zaručit, že u všech doposud napsaných skriptů postačí jednoduché odstranění dělících podmínek. Spíše bych skript doporučil jako výchozí bod pro psaní dalších aplikací.
Související články
Starší komentáře ke článku
Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.
Mohlo by vás také zajímat
-
Chcete jedinečnou doménu? Objevte koncovky FOOD, MEME a MUSIC!
7. listopadu 2024 -
Monitory OLED: klíčové pojmy a funkce
13. května 2024 -
AI na dosah ruky: Jak je to s AI v osobních zařízeních?
22. ledna 2024 -
Jak vybrat doménu: Co je dobré vědět?
2. září 2024
Nejnovější
-
Jak rozšířit úložiště Macu za pětinovou cenu?
16. prosince 2024 -
Nové trendy v doménách pro osobní projekty – DIY, LIVING a LIFESTYLE
9. prosince 2024 -
Jak chránit webové stránky před Web/AI Scrapingem
27. listopadu 2024 -
Jaký monitor je nejlepší k novému Macu Mini?
25. listopadu 2024