jQuery.fn.extend({
	on: function( types, selector, data, fn ) {
		return on( this, types, selector, data, fn );
	}
});

function on( elem, types, selector, data, fn, one ) {
	var origFn, type;

	// Typy mogą być odwzorowaniem typów/procedur obsługi
	if ( typeof types === "object" ) {

		// ( types-Object, selector, data )
		if ( typeof selector !== "string" ) {

			// ( types-Object, data )
			data = data || selector;
			selector = undefined;
		}
		for ( type in types ) {
			on( elem, type, selector, data, types[ type ], one );
		}
		return elem;
	}

	if ( data == null && fn == null ) {

		// ( types, fn )
		fn = selector;
		data = selector = undefined;
	} else if ( fn == null ) {
		if ( typeof selector === "string" ) {

			// ( types, selector, fn )
			fn = data;
			data = undefined;
		} else {

			// ( types, data, fn )
			fn = data;
			data = selector;
			selector = undefined;
		}
	}
	if ( fn === false ) {
		fn = returnFalse;
	} else if ( !fn ) {
		return this;
	}

	if ( one === 1 ) {
		origFn = fn;
		fn = function( event ) {

			// Możliwe jest użycie pustego zbioru, ponieważ zdarzenie zawiera informacje
			jQuery().off( event );
			return origFn.apply( this, arguments );
		};

		// Użycie identycznego identyfikatora guid, aby element wywołujący
		// mógł dokonać usunięcia przy użyciu origFn
		fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
	}
	return elem.each( function() {
		jQuery.event.add( this, types, fn, data, selector );
	} );
}
