protofunc()

WAI-ARIA – Epic Fail: Wenn der Screenreader nicht mehr aufhören will zu plappern

Tags: accessibility, deutsch, javascript

Aria Live Regions gehören zu den spannenderen Attributen bei Wai-Aria und haben – trotz der noch schlechten Unterstützung durch Screenreader – für einiges an Aufsehen gesorgt. Das Aria Best Practices Dokument ist ein guter Einstieg in Liveregions. Neben dem Attribut aria-live können die Attribute aria-busy, aria-relevant und aria-atomic das Vorleseverhalten im Screenreader beeinflußen. Bei Liveregions muß immer bedacht werden, daß ein ständig oder zu viel plappernder Text nervt und den User eher bei der Erfüllung seiner Aufgaben stört als weiterhilft. Dieses Problem wird allerdings vom oben genannten Best Practice Dokument mehr als ausgiebig beschrieben, so daß selten Fehlimplementierungen zu finden sind.

Wann Liveregions überhaupt Sinn machen?

Das grundsätzliche Mißverständnis von Liveregions liegt darin, daß viele Entwickler Liveregions als generelle Antwort auf das Problem von dynamischen Änderungen des Contents sehen. Sie also meinen, das ein HTML-Bereich immer als Liveregion ausgezeichnet werden sollte, wenn sich der Content, zum Beispiel aufgrund einer Ajax-Response, dynamisch ändert.

Hierbei wird allzu gerne folgender Text des Best Practices Dokuments überlesen/mißverstanden:

Live regions enable assistive technologies, such as screen readers, to be informed of updates without losing the users’ place in the content.

Damit hört sich das Feature “Liveregion” ziemlich cool an (und ist es auch). Man kann nämlich ohne den Fokus des Users ändern zu müßen, Informationen vorlesen laßen: Zum Beispiel kann ein Warenkorb darüber informieren, daß das Produkt nun erfolgreich im Warenkorb abgelegt wurde, ohne daß der User wegbewegt wird, er also weiterhin innerhalb des Produktskatalogs surfen kann. Er kann über neu eingegangene Chat-Nachrichten informiert werden, ohne daß er bei seiner eigenen Eingabe einer Nachricht gestört wird. Oder der User kann mit Hilfe der Rolle alert, welche implizit eine Liveregion ist, auf Fehler innerhalb eines Formularprozeßes aufmerksam gemacht werden, ohne ihn am weiteren Ausfüllen anderer Formularfelder zu behindern.

Leider wird die Kehrseite hieraus nicht deutlich gemacht und es kommt dadurch zur Fehlimplementierung. Diese Kehrseite könnte beispielsweise wie folgt lauten:

Liveregions ermöglichen es assistiven Technologien über geänderte Inhalte informiert zu werden, ohne daß der User mit diesen Inhalten – zumindest sofort – interagieren kann/soll/muß.

Ist der Text etwas länger, stärker strukturiert oder bietet gar Eingabemöglichkeiten wie Links, Formulare oder andere Eingabewidgets, möchte der User diesen Text nicht dumpf vorgelesen bekommen, er möchte mit diesem interagieren. Hierzu muß er jedoch den aktuellen Bereich verlaßen und zum neu geänderten Content gebracht werden. Dies ist eine Aufgabe, die von Screenreadern in Kombination mit Liveregions (noch) nicht erfüllt wird (eine gewisse Ausnahme stellt hier der Screenreader Orca dar, welcher auf Wunsch des Users auch zu einer Liveregion springt), von der Aria-Spezifikation nicht gefordert wird (obwohl es Sinn machen würde), aber letztendlich auch gar nicht erfüllt werden muß.

Für diese Art von Content-Änderung benötigt man nämlich kein Aria. Die Lösung ist kinderleicht zu impelentieren und funktioniert auch in vielen nicht Aria-fähigen Screenreader-Browser-Kombinationen. Die Lösung heißt focus.

Wenn wir beispielsweise folgendes geändertes HTML haben…

<div id="live-content">
	<h2 tabindex="-1">Überschrift von neuem Content</h2>
	<!-- weiterer Inhalt -->
</div>

können wir mit folgender Funktion …

function setFocus(elem){
	setTimeout(function(){
		try {
			elem.focus();
		} catch(e){}
	}, 0);
}

den Fokus auf folgende Weise…

setFocus(document.getElementById('live-content').getElementsByTagName('h2')[0]);

ganz einfach verschieben, so daß die Überschrift des neuen Contents vorgelesen und der User mit dem neuen Content interagieren kann. Das uncolle an dieser einfachen Art für Zugänglichkeit zu sorgen, ist einzig und alleine, daß wir im Prinzip praktisch keine neue Technik einsetzen und es potentiell die Möglichkeit gibt, daß es auch in “älteren” Screenreadern funktionieren könnte.

Wer dies in möglichst vielen Screenreadern zum Laufen bringen möchte, sollte sich den großen Screenreader Fokus Test durchlesen.

Written December 30, 2009 by
protofunc

WAI-ARIA – Epic Fail (Too much accessibility – good intentions, badly implemented)

Tags: accessibility, deutsch, javascript

Wenn Frontend-Entwickler neues Spielzeug bekommen, passiert eigentlich immer das gleiche. Sie laden sich, wenn nicht bereits geschehen, die neueste Alpha/Beta Version von Safari, Firefox und / oder Opera herunter und fangen dann an, die neuen Techniken zu testen, zu experimentieren und schließlich einzusetzen.

Bei WAI-Aria ist dies anders. Hier wird zwar bereits von einigen fleißig eingesetzt, aber kaum ein Entwickler kommt auf die Idee sich die neueste Version von Jaws herunterzuladen, zu installieren und zu testen. Hinzu kommt, daß viele Frontendentwickler eigentlich mehr so etwas wie theologisch und / oder philosophisch veranlagte Semantik-Professoren der HTML-Meta-Ebene sind, als gestandene Entwickler. Anstatt Aria so zu implemtieren, daß es funktioniert, wird lieber nach einem tieferen Sinn gesucht und die Aria Attribute und das Verhalten implementiert, welches nach der jeweiligen tiefen, manchmal religiösen, Überzeugung das semantisch näher liegende ist.

Nicht anders ist es zu erklären, daß mit Aria ausgetattete Javascript Widgets häufig größere Barrieren darstellen, als die identische Widget-Version, welche überhaupt kein Aria einsetzt.

Im Prinzip ist die Aria-Entwicklung ziemlich leicht, wenn man sich an die Fakten hält:

  • Was sagt das Aria-Best Practice Dokument (für Entwickler wichtiger als die Spezifikation)
  • Was für Accessibility-Informationen und welches Verhalten zeigen native, zugängliche Applikationen (MSAA-Inspect und/oder Accessibility Probe)
  • Mit welchen Aria-Attributen erreiche ich die selben Accessibility-Informationen im HTML
  • Und das wichtigste: Was liest mir die aktuellste Jaws-Version im aktuellsten Firefox vor (Vorsicht: Nicht wenige User verwenden häufig ältere Jaws-Versionen und den Internet Explorer 7/8)

Im Ergebnis tue ich mich mit diesem Zustand schwer. Die meisten Veröffentlichungen in diesem Blog zum Thema Barrierefreiheit gehen auf ein einziges Gefühl zurück, nämlich Wut über die Werke anderer Entwickler. In der Regel schreibe ich erst einen bitter bösen “Pranger-Artikel”, um diesen dann zu verwerfen und einfach ein Tutorial zu schreiben, wie man es hätte besser machen können, ohne den Bezug zum Original zu nennen. Ich glaube letztendlich, daß beide Formate nämlich Pranger-Artikel einerseits und Tutorial andererseits nicht weiterhelfen und wechsel hiermit nun das Format. Die WAI-Aria Epic Fail-Reihe soll nicht unbedingt zeigen, wie man es besser macht, sondern typische Fehlansätze bei der Aria Entwicklung aus der Praxis aufgreifen und darauf aufmerksam machen, ohne dabei Texte bzw. Scripte bzw. ihre Autoren/Entwickler an den Pranger zu stellen. Obwohl ich selbst inzwischen, gerade durch Beschäftigung mit Aria – merke, daß ich häufig gar kein Aria brauche, um Widgets überhaupt zugänglich zu machen, werde ich mich nur auf Aria konzentrieren, da hier zumindest die Zukunft zugänglicher Widgets liegt.

Den Anfang machen die Aria-Liveregions.

Written by
protofunc

mwheelIntent: Das gebrauchstaugliche mouswheel-Event

Tags: Usability, deutsch, javascript, jquery

Eine Möglichkeit die Usability von Javascript Widgets zu erhöhen, ist es eine reichhaltige Interaktionsmöglichkeit zu bieten. D.h. beispielsweise, daß ein Carousel nicht nur durch einen Click auf die Vorwärts-/Rückwärts-Schalter, sondern beispielsweise auch durch Tastatur oder eben das Mausrad bedient werden kann.

Javascript Widgets, die typischwerweise mit dem Mausrad bedient werden können, sind Karten wie Googlemaps, Yahoo Maps, Scrollbar-Ersetzungen sowie Laufbänder/Carousels. Mit dem Hinzufügen einer einfachen Mausradbehandlung zu diesen Widgets verursacht man jedoch in der Regel gleichzeitig ein größeres Usability-Problem. Denn diese Widgets sind in der Regel innerhalb eines Dokuments angelegt, welches ebenfalls mit dem Mausrad bedient werden kann. Möchte der User beispielsweise das Dokument mit dem Mausrad scrollen und kommt dabei eher zufällig auf ein Widget, welches ebenfalls per Mausrad gesteuert werden kann, fängt gerade dieses Widget die Mausradeingabe ab. Dies dürfte vom User nicht gewüsncht sein und ihn mehr verärgern als daß es ihn freut, daß er das Widget auch mit dem Mausrad bedienen kann.

Die Lösung für dieses Problem ist relativ einfach (und ist alleine deshalb bereits genial) und wird beispielsweise in einigen nativen Appliaktionen wie beispielsweise Firefox genutzt, um zu entscheiden, welches Widget gerade mit dem Mausrad bedient werden soll.

Hat der User nämlich in einem bestimmten “Mausradinteraktionsbereich” angefangen das Mausrad zu bedienen, so erhält dieser Bereich das Mausrad-Event exklusiv, solange der User sich a) über diesen Bereich bewegt und b) nicht die Maus bewegt, selbst wenn er dabei über andere interaktive Bereiche scrollt.

Ich habe mir erlaubt für eine solche Behandlung des Mausradevents ein jQuery-Plugin mit mwheelIntent-Demo zu schreiben. Die Nutzung ist relativ einfach:

$('div.widget').bind('mwheelIntent', function(e, d){
	//die mausrad implementierung
}):

Wie wurde dies implementiert

Das Grundgerüst

Für alle die es interessiert ein neues tolles custom-Event für jQuery zu schreiben, hier eine kurze Anleitung am Beispiel des mwheelIntent-Codes.

Als 1. definieren wir einige Variablen, welche wir noch benötigen werden. Besondere Beachtung sollte der Variable mwheelI geschenkt werden. Unter der Eigenschaft pos speichern wir mit jeder Mausradbewegung ab, wo sich das Mausrad gerade innerhalb des Viewports befindet, um zu entscheiden, ob der User die Maus zwischenzeitlich bewegt hat. Anfangs setzen wir diese mit jeweils -260 für x und y Koordinate weit aus dem Viewport, so daß anfangs immer von einer Mausbwegung ausgegangen wird.

Die Variable minDif gibt an, um wieviel Pixel der User die Maus mindestens bewegt haben muß, um eine Änderung des “Mausradinteraktionsbereichs” zu bewirken. Das eigentliche Kernstück unseres Events befindet sich unter $.event.special.mwheelIntent.

Die Methode setup wird aufgerufen, sobald der 1. mwheelIntent-Handler an einem DOM-Objekt gebindet wird, teardown, wenn der letzte mwheelIntent-Handler wieder entfernt wird. Die Methode handler wird letztendlich durch unser Event-System selbst aufgerufen und stößt das Aufrufen der eigentlich hinzugefügten Handler als eine Art proxy-Handler an. Dieser Methodenname könnte – meines Wissens nach – auch anders heißen, es ist jedoch Konvention ihn so zu nennen.

(function($){

//einige variablen
var mwheelI = {
			pos: [-260, -260]
		},
	minDif 	= 3,
	doc 	= document,
	root 	= doc.documentElement,
	body 	= doc.body,
	longDelay, shortDelay
;

// das eigentliche event grundgerüst
$.event.special.mwheelIntent = {
	setup: function(){

    },
	teardown: function(){

    },
    handler: function(e, d){

    }
};

// shortcuts  .bind('mwheelIntent', fn) -> .mwheelIntent()
$.fn.extend({
	mwheelIntent: function(fn) {
		return fn ? this.bind("mwheelIntent", fn) : this.trigger("mwheelIntent");
	},

	unmwheelIntent: function(fn) {
		return this.unbind("mwheelIntent", fn);
	}
});

//initialisierung des scrollbaren bereichs
$(function(){
	// falls body anfangs undefined gewesen sein sollte
	body = doc.body;
	// falls der User das cross-browser-mousewheel-Plugin nicht eingebunden hat
	if(!$.fn.mousewheel){
		setTimeout(function(){
			throw('Please include the mousewheel plugin before the mwheelIntent-plugin');
		}, 0);
	}
	//document als immer scrollbaren bereich berücksichtigen
	$(doc).bind('mwheelIntent.mwheelIntentDefault', function(){});
});
})(jQuery);

jQuery 1.4 wird zudem die beiden neuen Event-Hooks add und remove einführen, welche mit jedem hinzugefügten bzw. jedem entfernten Handler aufgerufen werden. (Mehr zu den neuen jQuery 1.4 Event hooks). Allerdings brauchen wir diese nicht.

Die Mausradbehandlung

Kommen wir nun zu der eigentlichen Implementierung. Unsere setup-Methode fügt letztendlich einen Eventlistener für das normale Mausradevent hinzu, welche unsere Handler Methode aufruft, in dem die Berechnung stattfindet, ob das Mausradevent durchgelassen werden soll oder nicht. Außerdem wird beim Verlassen der Maus aus dem Bereich die Funktion unsetPos aufgerufen, welche unsere eventuell gesetzten Werte auf den Anfangswert zurücksetzt. Bei den Objekten document, html und body wird dieser Listener nicht hinzugefügt, da er hier keinen Sinn machen würde und aufgrund der Tatsache, daß mouseleave ein auf mouseout aufbauendes Special-Event ist, einiges an Performance Kosten würde. Die teardown entfernt beide Listener wieder.

Die handler-Methode verfügt nun über den bereits erwähnten simplen, aber wirkungsvollen Code. Jedesmal wenn der User das Mausrad bewegt, wird die Mausposition abgespeichert und mit der letzten verglichen. Ist das DOM-Objekt mit dem letzten -durch das Mausrad bedienten – Objekt identisch oder hat der User seitdem die Maus weiter bewegt als in minDif definiert, wird das Event durchgelassen und die gebindeten handler mit der Methode $.event.handle.call(this, e, d); aufgerufen.

function unsetPos(){
	if(this === mwheelI.elem){
		mwheelI.pos = [-260, -260];
		mwheelI.elem = false;
		minDif = 3;
	}
}

$.event.special.mwheelIntent = {
	setup: function(){
		var jElm = $(this).bind('mousewheel', $.event.special.mwheelIntent.handler);
		if( this !== doc && this !== root && this !== body ){
			jElm.bind('mouseleave', unsetPos);
		}
		jElm = null;
        return true;
    },
	teardown: function(){
        $(this)
			.unbind('mousewheel', $.event.special.mwheelIntent.handler)
			.unbind('mouseleave', unsetPos)
		;
        return true;
    },
    handler: function(e, d){
		var pos = [e.clientX, e.clientY];
		if( this === mwheelI.elem || Math.abs(mwheelI.pos[0] - pos[0]) > minDif || Math.abs(mwheelI.pos[1] - pos[1]) > minDif ){
            mwheelI.elem = this;
			mwheelI.pos = pos;
			e = $.extend({}, e, {type: 'mwheelIntent'});
            return $.event.handle.call(this, e, d);
		}
    }
};

Verfeinerung der Mausradbehandlung

Dem aufmerksamen Leser wird aufgefallen sein, daß ich die Variable minDif ebenfalls auf 3 zurücksetze, obwohl ich sie gar nicht geändert haben. Außerdem habe ich 2 Variablen (longDelay, shortDelay) deklariert, die noch gar nicht genutzt werden. Dies hat mit einer kleineren Verfeinerung unseres Script zu tun. Hat der User gerade erst das Mausrad gedreht, soll er größere Mausbewegungen machen können, um eine ungewollte Verschiebung der Maus eben durch die Betätigung des Mausrads abzufangen. Dieser Code ist in der handler-Methode untergebracht und sieht wie folgt aus:

handler: function(e, d){
	var pos = [e.clientX, e.clientY];
	if( this === mwheelI.elem || Math.abs(mwheelI.pos[0] - pos[0]) > minDif || Math.abs(mwheelI.pos[1] - pos[1]) > minDif ){
		mwheelI.elem = this;
		mwheelI.pos = pos;
		minDif = 250;

		clearTimeout(shortDelay);
		shortDelay = setTimeout(function(){
			minDif = 10;
		}, 200);
		clearTimeout(longDelay);
		longDelay = setTimeout(function(){
			minDif = 3;
		}, 1500);
		e = $.extend({}, e, {type: 'mwheelIntent'});
		return $.event.handle.call(this, e, d);
	}
}

Im Ergebnis kann der User also 200ms nachdem er das Mausrad bedient hat die Maus um 250 Pixel bewegen, ohne daß dies eine Änderung des durch das Mausrad bedienbaren Bereichs zur Folge hat. Außerdem ist der Bereich für 1.5 Sekunden von 3 auf 10 Pixel erhöht.

Fazit

Die Berücksichtigung von Mausradeingaben kann die Userexpierence und die Bedienbarkeit von Widgets steigern, aber auch gleichzeitig große Usability-Problem verursachen, wenn die Intention des Users nicht berücksichtigt wird. Mit ein bißchen JS kann die wahrscheinliche Intention des Nutzers berechnet werden. (zur mwheelIntent-Projekt-Seite)

Written December 29, 2009 by
protofunc

jQuery: live-Methode / Braucht jQuery 1.4 eine neue API für Event Delegation?

Tags: deutsch, javascript, jquery

Jedes jQuery-Major-Release hat wesentliche Neuerungen/Verbesserungen gebracht. Bei jQuery 1.3 war es wohl die Einführung von Sizzle, die Umstellung von Browser-Sniffing auf Feature-Detection und die Einführung der live-Methode für Event Delegation.

Letztendlich habe ich die live-Methode in jQuery 1.3 so gut wie nie genutzt, da ich es für meine Usecases für ineffizient gehalten habe, das document-Objekt mit Eventlistener zu zuknallen. Eine präzisere Möglichkeit Event Delegation in jQuery 1.3 zu nutzen, war für mich immer die Nutzung der closest-Methode:

$('#nav').bind('click', function(e){
	// Der zweite Parameter wird erst in jQuery 1.4 eingeführt!
	var anchor = $(e.target).closest('a', this);
	if(!anchor[0]){return;)
	// mach was mit anchor
});

Das Problem mit der live-Methode

Mit jQuery 1.4 wird Event Delegation und die Möglichkeiten der live-Methode stark erweitert. Zum einen werden Events unterstützt, die nicht bubbeln und zum anderen soll der Entwickler bestimmen können, an welches DOM-Objekt der Eventlistener hinzugefügt wird. Dies dürfte in jedem Fall dazu führen, daß die Methode häufiger eingesetzt wird. Gleichzeitig haben einige Leute in der Vergangenheit gefordert, die live-Mwthode entweder abzuändern oder zumindest eine neue Methode einzuführen. Dies geschah mit besonderer Rücksicht auf Performance und wurde – meiner Meinung nach – zurecht abgelehnt.

Das Problem ist jedoch, daß die live-Methode schwer zu erklären/dokumentieren ist, leicht zu Fehlern führen kann und den Entwickler dazu zwingt bereits beim Instantiieren eines jQuery-Objekts über die spätere Art der Event Delegation nachzudenken. Diese Grundproblematik läßt sich bereits bei jQuery 1.3 ausmachen und wird bei jQuery 1.4 noch komplizierter (aber nicht unbedingt schlimmer).

Problem bei jQuery 1.3

Laut jQuery-Dokumentation kann live u.a. nicht verwendet werden, wenn man beim Instanzieren den Context-Parameter nutzt bzw. wenn man Traversing-Methoden zwischenschaltet. Eine ältere jQuery Dokumentation hat hiervon ausdrücklich die Methode find als nicht funktionierende Traversing Methode ausgenommen. Letztendlich stimmt diese Behauptung in der Dokumentation nicht ganz. Eine Erklärung wann dies funktionieren kann und wann nicht, wäre jedoch einfach zu kompliziert. Hier eine kurze Erklärung

// funktioniert in 1.3 nicht,
$('li', $('#nav')[0]).live('click'....
// ... da
// 1. der Eventlistener dem document-Objekt hinzugefügt wird
// 2. jQuery ausschließlich den 'li', aber nicht den '#nav' Selektor kennt

// funktioniert in 1.3,
$('li', $('#nav')).live('click'....
$('#nav').find('li').live('click'....
// ... da
// jQuery beide Selektor-Bestandteile kennt und diese zu '#nav li' zusammenfassen kann

// funktioniert in 1.3 nicht,
$('li, a', $('#nav')).live('click'....
// ... da jQuery beide Selektor-Bestandteile zu '#nav li, a' zusammenfaßt

Eskalierung des Problems mit jQuery 1.4 (nightly-Stand)

jQuery 1.4 ist noch nicht draußen, aber der derzeitige Stand kann über github eingesehen werden. Zudem existiert eine öffentliche Alpha, welche ich zum Testen herangezogen habe.

Mit dem derzeitigen Stand von jQuery 1.4a1 wird die oben beschriebene Ungenauigkeit zu einem großen Problem, denn die Verwendung des context-Parameters soll nicht nur ermöglicht werden, sondern wird zu einem elementaren Feature, da nun der context-Parameter bestimmen soll, an welchem Element der Eventhanlder gebunden werden soll. Das Problem hierbei ist jedoch eben die Tatsache, daß es eine Reihe von Bedingungen auftreten müssen, damit das ganze funktioniert.

//Event wird in der Regel an nav-Element gebunden und funktioniert in der Regel wie gewünscht
$('li', $('#nav')[0]).live('click'....
// aber dann nicht, wenn $('#nav')[0] === undefined ist

//Event wird an document-body gebunden (Obwohl ein context-Parameter angegeben wurde, funktioniert aber ansonsten wie gewünscht.)
$('li', $('#nav')).live('click'....

//Funktioniert wie bei jQuery 1.3 nicht wie gewünscht
$('li, a', $('#nav')).live('click'....

Die Dokumentation müßte hier einerseits auf die Unterscheidung hinweisen, was alleine für sich bereits ziemlich verwirrend sein könnte und andererseits darauf, daß die 1. Zeile fehleranfällig ist. Kommt nämlich auf der gesamten Seite kein #nav-Element vor, ist $(‘#nav’)[0] undefined, was dazu führt, daß erstens der Eventhandler zum document.body hinzugefügt und zweitens der Eventhandler bei jedem Click auf/in irgend ein li aufgerufen wird und damit nicht so funktioniert wie gewünscht.

Das gesamte Problem wird zusätzlich verschärft, wenn man einen Eventhandler mehreren Elementen hinzufügen möchte.

//Event wird an das document.body gebunden und funktioniert wie gewünscht
$('div.teaser', $('div.teaser-wrapper')).live('click'...

//Schreibweise wird von jQuery nicht unterstützt, Event wird an document.body gebunden und jeder Click auf/in ein div.teaser löst Event aus
$('div.teaser', $('div.teaser-wrapper').get()).live('click'...

Funktionierender Code, der das neue Event Delegation-Feature von jQuery 1.4 nutzt und dabei sowohl klar, verständlich als auch robust ist, könnte beispielsweise wie folgt aussehen:

$('#nav').each(function(){
	$('a', this).live('click' ...
});
//oder
$('div.teaser-wrapper').each(function(){
	$('div.teaser', this).live('click' ...
});

Letztendlich sind wir damit ziemlich nah an dem dran, was wir bereits in jQuery 1.3 schreiben können, um Event Delegation mit anderem context als document bzw. document.body zu nutzen, nämlich:

$('#nav').bind('click', function(e){
	// Der zweite Parameter wird erst in jQuery 1.4 eingeführt!
	var anchor = $(e.target).closest('a', this);
	if(!anchor[0]){return;)
	// mach was mit anchor
});

Es ist ziemlich “jQuery-unlike” mehrere Zeilen-Code zu schreiben, um nur eine “einfache” Sache zu erreichen, aber genau das würde bei einer Beibehaltung der derzeitigen API passieren. Ganz abgesehen davon, daß die Dokumentation um weitere kompliziertere Erklärungen nicht umhin kommen würde.

Eine einfache Implementierung einer neuen jQuery-Event Delegation API könnte hierbei beispielsweise wie folgt aussehen.

(function($){
	var dummy = $([]);

	$.each({addLive: 'live', removeLive: 'die'}, function(name, jMethod){
		$.fn[name] = function(sel){
			var args = (this[0]) ? Array.prototype.slice.call(arguments, 1) : [];
			return this.each(function(){
				dummy.selector = sel;
				dummy.context = this;
				$.fn[jMethod].apply(dummy, args);
			});
		};
	});
})(jQuery);

Die Nutzung würde hierbei wie folgt aussehen:

function fn(){
	alert('F');
}
//bind live:
$('div.teaser-wrapper').addLive('div.teaser', 'click', fn);
// unbind live/die
$('div.teaser-wrapper').removeLive('div.teaser', 'click', fn);

Fazit:

jQuery 1.4 benötigt nicht unbedingt eine neue Methode für Event-Delegation. Die Verwendung des context-Parameters wird nun grundsätzlich ermöglicht und damit mögliche Fehler einer flaschen Benutzung minimiert. “Power User”, die jedoch Wert darauf legen, daß sie die volle Kontrolle darüber haben, welchem Element der Event-Listener genau hinzugefügt wird, würden sich jedoch stark über eine anders funktionierende Methode freuen.

Eine solche Methode wäre dann nicht nur einfacher zu erklären, sondern würde ebenfalls die Forderung nach einer performanteren (ohne Unnötiges Selektieren von Elementen, die man nicht braucht) berücksichtigen.

Written December 8, 2009 by
protofunc