protofunc()

widgetExtend: jQuery UI Widgets erweitern

Tags: deutsch, javascript, jquery

Letztendlich gibt es mehrere Möglichkeiten vorhandene jQuery UI Widgets zu erweitern. Die hierzu am häufigsten verwendete Methode ist die $.extend. Was in etwa so aussieht:

//neues a11yTabs erweitert tabs
$.widget('ui.a11yTabs', $.extend({}, $.ui.tabs.prototype, {
	select: function(){
		$.ui.tabs.prototype.select.apply(this, arguments);
	}
});
// tabs selbst erweitern
//altes select sichern
var oldSelect = $.ui.tabs.prototype.select;
$.extend($.ui.tabs.prototype, {
	select: function(){
		oldSelect.apply(this, arguments);
	}
});

Überschreibt man hierdurch eine bereits vorhandene Funktion, welche man noch nutzen möchte, muß man diese, wie im zweiten Beispiel geschehen, vor dem überschreiben zwischenspeichern, so daß man weiterhin auf die Originalmethode Zugriff hat.

Eine relativ elegante Schreibweise hierzu findet sich bei Felix Nagel, welcher folgenden einfachen Code zeigt:

// extends original ui.tabs widget
$.extend($.ui.tabs.prototype,{
	// copy original method
	_original_init: $.ui.tabs.prototype._init,
	// when widget is initiated
	_init: function() {
		var self = this, options = this.options;
		// fire original method
		self._original_init();

		// now we can do some accessibility stuff
	}
});

Wenn man derartiges drei- bis viermal schreiben muß, kommt man sich aber doch recht schnell etwas blöd vor. Als sich mir eben dieses Problem stellte, hatte ich daher folgende kleine extend-Methode geschrieben (noch nicht völlig durchgetestet):

var slice = Array.prototype.slice;
$.widgetExtend = function(widget, exts){
	var args = arguments;

	$.each(exts, function(name, fn){
		if( name in widget ){
			if( fn && $.isFunction(fn) ){
				fn._super = widget[name];
			} else {
				widget['_super'+ name] = widget[name];
			}
		}
		widget[name] = fn;
	});

	if( args.length > 2 ){
		args = slice.call(arguments, 2);
		args.unshift(widget);
		widget = $.widgetExtend.apply(this, args);
	}

	return widget;
};

Mit dieser kleinen Methode kann man, dannn ohne lästiges zwischenspeichern über arguments.callee._super auf die Hauptmethode zugreifen:

//neues a11yTabs erweitert tabs
$.widget('ui.a11yTabs', $.widgetExtend({}, $.ui.tabs.prototype, {
	select: function(){
                //$.ui.tabs.prototype.select kann eigentlich auch noch verwendet werden
		arguments.callee._super.apply(this, arguments);
	}
});
// tabs selbst erweitern

$.widgetExtend($.ui.tabs.prototype, {
	select: function(){
		arguments.callee._super.apply(this, arguments);
	}
});
Written January 9, 2010 by
alexander farkas

3 Comments »

  1. Super snippet! Vielen, vielen Dank :)

    Nur als kleine Frage: Kommt man irgendwie um arguments.callee herum, da deprecated?

    grüße

    Comment by Basti — June 29, 2010 @ 1:52 pm

  2. @basti

    ja, klar. arguments.callee zeigt ja immer auf die aufgerufene function, du kannst das _super in dem beispiel oben auf über this.select._super erreichen.

    Für das vererben haben die leute von jQuery UI übrigens in der aktuellen Version ein tolles Feature eingebaut. (Beispiel: a11yTabs erbt von tabs), welches man auch nutzen kann/sollte.

    Ich werde, wenn ich ein bißchen Zeit habe mal darüber schreiben.

    Grüße
    Alex

    Comment by alexander farkas — June 29, 2010 @ 8:03 pm

  3. Oh stimmt. Dumme Frage :) Danke für die Hinweise, dann schau ich mir mal die Vererbung in der aktuellen 1.8er an.

    super Beiträge, weiter so!

    Comment by Basti — June 30, 2010 @ 4:57 pm

RSS feed for comments on this post | TrackBack URL

Leave a comment