<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>m1chu.eu - another devblog &#187; jQuery</title>
	<atom:link href="http://m1chu.eu/category/webmastering/client-side/jquery/feed/" rel="self" type="application/rss+xml" />
	<link>http://m1chu.eu</link>
	<description>we live, as we dream... alone - another devblog</description>
	<lastBuildDate>Fri, 25 Jun 2010 22:04:21 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=abc</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Wzorzec projektowania wtyczek jQuery na bazie metod i funkcji</title>
		<link>http://m1chu.eu/2010/03/06/wzorzec-projektowania-wtyczek-jquery-na-bazie-metod-i-funkcji/</link>
		<comments>http://m1chu.eu/2010/03/06/wzorzec-projektowania-wtyczek-jquery-na-bazie-metod-i-funkcji/#comments</comments>
		<pubDate>Sat, 06 Mar 2010 18:17:32 +0000</pubDate>
		<dc:creator>m1chu</dc:creator>
				<category><![CDATA[Webhosting]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[biblioteka]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[funkcja]]></category>
		<category><![CDATA[iteracja]]></category>
		<category><![CDATA[metoda]]></category>
		<category><![CDATA[obiekt]]></category>
		<category><![CDATA[parametryzacja]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[prototyp]]></category>
		<category><![CDATA[wtyczka]]></category>

		<guid isPermaLink="false">http://m1chu.eu/?p=1689</guid>
		<description><![CDATA[
Praca z jQuery prędzej, czy później wymusza na nas kompleksowe tworzenie rozwiązań wykonywanych po stronie użytkownika. Metody filtrujące, animacje, czy efekty na galeriach zdjęć łatwiej będzie osiągnąć i rozwijać posługując się, łączącymi się na wtyczki, mechanizmami metod i funkcji, dostępnymi w frameworku.

Metoda, a funkcja?
Podstawowa różnica pomiędzy nimi polega na tym, że operują na innych obiektach. [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: center;"><img class="iborder" src="http://images.m1chu.eu/index.php?res=MDZfMDVfMTBfanF1ZXJ5X3BsdWdpbnNfcGF0dGVybjtqcXVlcnlfcGx1Z2luc19wYXR0ZXJuX3Bvc3RfaGVhZGVyLnBuZw==" alt="Wzorzec projektowania wtyczek jQuery na bazie metod i funkcji" style="height: 119px;" /></p>
<p>Praca z jQuery prędzej, czy później wymusza na nas kompleksowe tworzenie rozwiązań wykonywanych po stronie użytkownika. Metody filtrujące, animacje, czy efekty na galeriach zdjęć łatwiej będzie osiągnąć i rozwijać posługując się, łączącymi się na wtyczki, mechanizmami metod i funkcji, dostępnymi w frameworku.</p>
<p><span id="more-1689"></span></p>
<h2>Metoda, a funkcja?</h2>
<p>Podstawowa różnica pomiędzy nimi polega na tym, że operują na innych obiektach. Każda nowa metoda musi być dołączona do prototypu <code>jQuery.fn</code>, a funkcja po prostu do obiektu <code>jQuery</code>.</p>
<pre class="brush: jscript;">/* metoda */
jQuery.fn.nazwa = function() {
	[...]
};</pre>
<pre class="brush: jscript;">/* funkcja */
jQuery.nazwa = function() {
	[...]
};</pre>
<p>W praktyce powoduje to, że do metody odwołujemy się operując na jakimś elemencie, identyfikatorze, bądź na klasie znajdującej się na stronie internetowej, a w przypadku funkcji, po prostu ją wywołujemy w celu wykonania jakieś akcji.</p>
<pre class="brush: jscript;">/* wywołanie: metoda */
$(element).nazwa();</pre>
<pre class="brush: jscript;">/* wywołanie: funkcja */
var x = $.nazwa();
alert(x);</pre>
<p>Obydwie możemy parametryzować. Argumentem może być zwykła zmienna, dowolnego, obsługiwanego przez JavaScript typu lub obiekt przechowujący zbiór pól o konkretnym przeznaczeniu.</p>
<pre class="brush: jscript;">/* metoda z parametrem */
jQuery.fn.nazwa = function(options) {
	[...]
};</pre>
<pre class="brush: jscript;">/* funkcja z parametrem */
jQuery.nazwa = function(options) {
	[...]
};</pre>
<h2>Umowne zasady tworzenia pluginów</h2>
<p>Twórcy <a target="_blank" href="http://jquery.com/" >jQuery</a>, poprzez dokumentację, podpowiadają jakimi zasadami należy się kierować, aby poprawnie tworzyć wtyczki. Mianowicie:</p>
<ol>
<li>Terminologie funkcja, metoda, czy klasa są stosowanie umownie, z racji specyfiki przeznaczenia każdego z tych elementów. Fraza <strong>metoda</strong> jest w powyższym wypadku synonimem całego pojęcia wtyczki.</li>
<li>Nazwy plików powinny być formowane następująco: <strong>jquery.[nazwa_wtyczki].js</strong>. Przykładowo: <strong>jquery.nazwa.js</strong>.</li>
<li>W metodach <code>this</code> jest referencją do aktualnie przetwarzanego obiektu jQuery.</li>
<li>Powinno się dołączać wtyczkę do obiektu nadrzędnego poprzez <code>jQuery</code>, a nie <code>$</code>, co użytkownikom zwiększa pole manewru we wprowadzaniu zmian z użyciem <code>jQuery.noConflict()</code>.</li>
<li>W celu uniknięcia problemów z poprawnością kodu po jego wcześniejszej kompresji, wszelkie metody oraz funkcje powinny kończyć się znakiem średnika (<code>;</code>).</li>
<li>Użycie <code><a target="_blank" href="http://utnij.eu/6f63d2/" >.each</a></code> pozwala na bezproblemową iteracje po wszystkich elementach na których operujemy w metodzie.</li>
<li>Metoda domyślnie musi zwracać wartość.</li>
</ol>
<div class="explain">
<p><code>.each(function(indeks, element))</code> &#8211; przenosi się po każdym elemencie drzewa DOM, będących częścią obiektu jQuery, za każdym razem wykonując funkcję określoną jako parametr opisywanej metody.</p>
<p><strong>Przykład:</strong></p>
<pre class="brush: xml;">&lt;ol&gt;
	&lt;li&gt;play&lt;/li&gt;
	&lt;li&gt;the&lt;/li&gt;
	&lt;li&gt;game&lt;/li&gt;
&lt;/ol&gt;</pre>
<pre class="brush: jscript;">$('ol').each(function(i, e) {
	// e == this
	// e jest warte użycia w konkretnych zagnieżdżeniach, kiedy to this nie zawsze wskazuje na aktualnie analizowany element pętli
	$(e).html('&lt;strong&gt;' + $(this).text() + '&lt;/strong&gt;');
});</pre>
</div>
<h2>Przekazywanie parametrów w celu kontrolowania zachowań wtyczki</h2>
<p>Czym byłby plugin bez możliwości prostej parametryzacji określonych zachowań? W celu ułatwienia zrozumienia ich tworzenia postaramy się stworzyć bardzo prosty tester poprawności wpisywanych do pola danych (np. o identyfikatorze <code>#nick</code>). Sprawdzimy w nich, czy wprowadzony tekst będzie odpowiadał odpowiedniemu wzorcowi wyrażenia regularnego i będzie wystarczająco długi. Ponadto określimy do jakiego elementu zwrócić informację na wypadek niespełnienia wcześniej wymienionych kryteriów. Warto więc będzie zdefiniować na stałe wartości tych opcji oraz dać przyszłym jej użytkownikom możliwość nadpisania ich w argumentach wywoływanej metody.</p>
<div class="explain"><code>jQuery.extend([ tryb_rekursywny ,] obiekt_rozszerzany, obiekt_1_rozszerzający [, ... obiekt_n_rozszerzający])</code> &#8211; łączenie dwóch lub kilku właściwości obiektów do osobnego.
<ul>
<li><strong>tryb_rekursywny</strong> &#8211; przyjmuje wartości logiczne (true/false) w celu wykonania rekursywnego łączenia,</li>
<li><strong>obiekt_rozszerzany</strong> &#8211; element nadpisywany (w celu uniknięcia należy pozostawić puste),</li>
<li><strong>obiekt_x_rozszerzający</strong> &#8211; elementy łączone.</li>
</ul>
</div>
<p>Załóżmy więc, że nazwiemy naszą wtyczkę <strong>filtrate</strong>, a domyślne dane będziemy przetrzymywać w obiekcie <strong>defaults</strong>.</p>
<pre class="brush: jscript;">jQuery.fn.filtrate = function() {
	var defaults = {
		length:		6, // minimalna długość wprowadzanego tekstu
		regexp:		/[0-9a-z]/gi, // kryterium wprowadzanych znaków
		returnto:	'footer' // informacja o błędzie zostanie zwrócona do tego elementu
	};

	alert(defaults.regexp); // przykładowe użycie
};</pre>
<p>Za pomocą parametru <strong>options</strong> przekażemy spersonalizowane dane konfiguracyjne.</p>
<pre class="brush: jscript;">jQuery.fn.filtrate = function(options) {
	var defaults = {
			length:		6, // minimalna długość wprowadzanego tekstu
			regexp:		/[0-9a-z]/gi, // kryterium wprowadzanych znaków
			returnto:	'footer' // informacja o błędzie zostanie zwrócona do tego elementu
	}; 

	// rozszerzenie domyślnej konfiguracji
	var options = $.extend(defaults, options);

	alert(options.regexp); // przykładowe użycie
};</pre>
<p>Propozycje wywołań metody z użyciem argumentów.</p>
<pre class="brush: jscript;">$('#nick').filtrate({length: 3});
// lub
$('#nick').filtrate({
	regexp: /[0-9]/gi,
	length: 3
});</pre>
<p>Do ustawień nie ma jednak publicznego dostępu. Możemy co prawda skonfigurować je przy wywoływaniu wtyczki, ale nie bezpośrednio, np. później. W tym celu należy przenieść domyślne wartości do własności składowej metody oraz połączyć wprowadzane i predefiniowane dane bez modyfikacji tych drugich.</p>
<pre class="brush: jscript;">jQuery.fn.filtrate = function(options) {
	// rozszerzenie domyślnej konfiguracji bez jej nadpisywania (pierwszy argument pusty)
	var options = $.extend({}, $.fn.filtrate.defaults, options);

	alert(options.regexp); // przykładowe użycie
};

$.fn.filtrate.defaults = {
	length:		6, // minimalna długość wprowadzanego tekstu
	regexp:		/[0-9a-z]/gi, // kryterium wprowadzanych znaków
	returnto:	'footer' // informacja o błędzie zostanie zwrócona do tego elementu
};</pre>
<p>Zewnętrzny programista ma teraz szansę wykonania ustawień przed i po wywołaniu wtyczki, a także bez konieczności robienia tego w bloku <code>jQuery(document).ready(function() [...]);</code>.</p>
<pre class="brush: jscript;">// nadpisanie długości spoza parametru
$.fn.filtrate.defaults.length = 3;
$('#nick').filtrate({regexp: /[0-9]/gi});</pre>
<h2>Prywatne funkcje &#8211; ukrywamy poszczególne elementy</h2>
<p>Nie każda partia kodu powinna być dostępna do bezpośredniego wywołania przez użytkownika wtyczki. Przykładem może być tutaj funkcja użytkowa, stworzona stricte do celów danej metody. Aby tego dokonać, należy opleść całą definicję pluginu w funkcję zamykającą (<em>closure</em>) oraz po za samą metodą użyć standardowej formy tworzenia funkcji w JavaScript. Metodologia tworzenia funkcji w jQuery nie zda tutaj prawidłowego rezultatu. Dostęp będzie nadal publiczny.</p>
<pre class="brush: jscript;">(function($) { // start: closure
	$.fn.filtrate = function() {
		$.logs(1); // ostrzeżenie z zawartością '1'

		logs(1); // ostrzeżenie z zawartością '1'
	};		

	function logs($obj) {
    	alert($obj);
  	};

	$.logs = function($obj) {
		alert($obj);
	};
})(jQuery); // end: closure

jQuery(document).ready(function() {
	$('#nick').filtrate();

	$.logs(1); // ostrzeżenie z zawartością '1'
	logs(1); // brak dostępu do tej funkcji z zewnątrz
});</pre>
<h2>Wywoływanie funkcji oraz innych metod we wtyczce</h2>
<p>Zaistnieć może także sytuacja przeciwna do powyższej. Z różnych powodów możemy chcieć skorzystać z publicznie dostępnej metody, zaimplementowanej wewnątrz wtyczki, którą tworzymy lub z funkcji przedstawionych na początku artykułu.</p>
<pre class="brush: xml;">[...]
        &lt;footer&gt;
        	&lt;p&gt;Wpisz swój script nick&lt;/p&gt;
            &lt;p&gt;Wpisz swój a href nick&lt;/p&gt;
        &lt;/footer&gt;
[...]</pre>
<p>Mamy przykładowy zestaw paragrafów, z których będziemy chcieli wykluczyć pewny ciąg znaków. Ponieważ będziemy sprawdzać więcej elementów niż jeden, skorzystamy z wcześniej wymienionej metody iteracyjnej <code>.each()</code>, a następnie pobierzemy ich zawartości, usuniemy stosowną frazę (korzystając z osobnej funkcji/metody) i zwrócimy wynik do znacznika je zawierającego.</p>
<pre class="brush: jscript;">jQuery.fn.filtrate = function(options) {
	var defaults = {
		erase:	 	/a href/g, // tekst do usunięcia
		usemethod:	true // pomocnicze, użycie metody lub funkcji
	};
	// rozszerzenie domyślnej konfiguracji
	var options = $.extend(defaults, options);

	return this.each(function() {
		var context = $(this).html(); // pobranie zawartości elementu
		switch (options.usemethod) // dodany w celach naukowych ;]
		{
			case false:
				context = $.cleanup(context, options.erase); // wywołanie funkcji
				break;
			default:
				context = $.fn.filtrate.cleanup(context, options.erase); // wywołanie metody
				break;
		}
		$(this).html(context); // zapisanie zmodyfikowanej zawartości elementu
	});
};		

// metoda zaimplementowana we wtyczce
jQuery.fn.filtrate.cleanup = function(context, erase) {
	return context.replace(erase, ''); // usunięcie frazy z ciągu
};

// osobna funkcja
jQuery.cleanup = function(context, erase) {
	return context.replace(erase, ''); // usunięcie frazy z ciągu
};

jQuery(document).ready(function() {
	// tryb wywoływania z metody
	$('footer p').filtrate({erase: /script/g});

	// tryb wywoływania spoza metody
	return $('footer p').each(function() {
		var context = $(this).html();
		context = $.fn.filtrate.cleanup(context, /a href/g);
		context = $.cleanup(context, /script/g);
		$(this).html(context);
	});
});</pre>
<h2>Osiągamy postawiony cel</h2>
<p>Na podstawie powyższych rad możemy osiągnąć postawiony sobie cel &#8211; tester poprawności wpisywanych danych do pola typu <code>input</code>. Rozwiązanie będzie zezwalać na testowanie wielu pól naraz.</p>
<pre class="brush: xml;">[...]
    	&lt;header&gt;
			&lt;p&gt;&lt;input type=&quot;text&quot; id=&quot;nick&quot;&gt;&lt;/p&gt;
			&lt;p&gt;&lt;input type=&quot;text&quot; id=&quot;nick_second&quot;&gt;&lt;/p&gt;
        &lt;/header&gt;
[...]</pre>
<p>Wywołanie odbywać się będzie w momencie zwolnienia przycisku klawiatury.</p>
<pre class="brush: jscript;">jQuery(document).ready(function() {
	$('input').keyup(function() {
		$('input').filtrate({regexp: /[a-z]/g});
	});
});</pre>
<p>W przestrzeni funkcji zawierającej wtyczkę znajdzie się prywatna funkcja logująca akcje oraz dwie publiczne metody implementowane w pluginie. Pierwsza z nich będzie sprawdzać poprawność wpisywanego tekstu pod względem zadanego wzorca, a druga długość wprowadzonego ciągu znaków.</p>
<pre class="brush: jscript;">	// metoda testująca poprawność wpisanych znaków
	$.fn.filtrate.preg_match = function(pattern, subject) {
		var subject_splited = subject.split(''); // utworzenie tablicy znaków
		for ( i=0; i &lt; subject_splited.length; ++i ) // iteracja po każdym ze znaków
		{
			// jeżeli którykolwiek znak nie będzie odpowiadał wzorcowi metoda zwraca fałsz
			if ( subject_splited[i].match(new RegExp(pattern)) == null )
			{
				return false;
			}
		}
		return true; // wszystkie znaki są odpowiednie, prawda - jedziemy dalej ;]
	};

	// metoda porównująca długości ciągów
	$.fn.filtrate.strlen_compare = function(string, min_length) {
		var length = string.length;
		if ( length &lt; 1 ) // tekst nie został wpisany
		{
			return false;
		}
		else if ( length &lt; min_length ) // tekst krótszej długości niż wymagana
		{
			return min_length - length;
		}
		return true; // tekst odpowiedniej długości
	};

	// funkcja prywatna, logująca akcje
	function log_alerts(returnto, text)
	{
		// jeżeli nie podano tekstu do wypisania, czyścimy zawartość znacznika przetrzymującego ostrzeżenia i informacje
		if ( text == undefined )
		{
			$(returnto).html('');
			return;
		}

		// dodanie nowego akapitu z zwróconą treścią do podanego znacznika
		$('&lt;p&gt;' + text + '&lt;/p&gt;').appendTo(returnto);
	}</pre>
<p>Domyślne opcje ustawimy poza wtyczką. W niej samej, dla każdego wskazanego elementu strony, sprawdzimy najpierw warunek długości, a gdy zostanie spełniony, także zawartości.</p>
<pre class="brush: jscript;">(function($) { // start: closure
	$.fn.filtrate = function(options) {
		// rozszerzenie domyslnej konfiguracji bez jej nadpisywania (pierwszy argument pusty)
		var options = $.extend({}, $.fn.filtrate.defaults, options);

		var context, strlen_compared_result;

		// czyszczenie znacznika zawierającego informacje o stanie pól
		log_alerts(options.returnto);

		// sprawdzenie każdego elementu
		return this.each(function(i) {
			context = $(this);

			// testowanie długości
			strlen_compared_result = $.fn.filtrate.strlen_compare(context.val(), options.length);
			switch (strlen_compared_result)
			{
				case false: // w wypadku niewpisania tekstu
					// logowanie akcji
					log_alerts(options.returnto, 'Pole &lt;strong&gt;' + context.attr('id') + '&lt;/strong&gt; jest puste');
					return true;
					break;
				case true: // w wypadku odpowiedniej długości tekstu
					// puste
					break;
				default: // w wypadku za krótkiego tekstu zwracany jest: tekst + wymagana długość + ilość brakujących znaków
					log_alerts(options.returnto, 'Pole &lt;strong&gt;' + context.attr('id') + '&lt;/strong&gt; zawiera za mało znaków (minimum: ' + options.length + ' / brakuje: ' + strlen_compared_result + ')');
					return true;
					break;
			}

			// testowanie typów znaków znajdujących się w tekście
			switch ($.fn.filtrate.preg_match(options.regexp, context.val()))
			{
				case false: // w wypadku pojawienia się niedozwolonych znaków
					log_alerts(options.returnto, 'Pole &lt;strong&gt;' + context.attr('id') + '&lt;/strong&gt; zawiera niedozwolone znaki');
					return true;
					break;
				default: // w wypadku poprawnego sformowania tekstu
					log_alerts(options.returnto, 'Pole &lt;strong&gt;' + context.attr('id') + '&lt;/strong&gt; jest prawidłowo wypełnione');
					break;
			}
		});
	};

	$.fn.filtrate.defaults = {
		length:	 6, // minimalna dlugosc wprowadzanego tekstu
		regexp:	 /[0-9a-z]/gi, // kryterium wprowadzanych znaków
		returnto:   'footer' // informacja o bledzie zostanie zwrócona do tego elementu
	};

	// pozostałe dwie metody + prywatna funkcja
})(jQuery); // end: closure</pre>
<p>Przykład ten powinien przybliżyć kwestię wcześniej poruszone w artykule. Na jego podstawie udostępniłem także <a href="http://use.m1chu.eu/-jquery/plugin-and-function-development-pattern/index.html" >testową stronę</a> oraz <a href="http://get.m1chu.eu/-examples/-jquery/plugin-and-function-development-pattern/get_pafdp.php" >gotowe pliki do pobrania</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://m1chu.eu/2010/03/06/wzorzec-projektowania-wtyczek-jquery-na-bazie-metod-i-funkcji/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Efekt graficznego podświetlenia w jQuery i Prototype z Scriptaculous</title>
		<link>http://m1chu.eu/2009/02/09/efekt-graficznego-podswietlenia-w-jquery-i-prototype-z-scriptaculous/</link>
		<comments>http://m1chu.eu/2009/02/09/efekt-graficznego-podswietlenia-w-jquery-i-prototype-z-scriptaculous/#comments</comments>
		<pubDate>Mon, 09 Feb 2009 12:45:54 +0000</pubDate>
		<dc:creator>m1chu</dc:creator>
				<category><![CDATA[(x)HTML]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Prototype]]></category>
		<category><![CDATA[Webhosting]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[highlighter]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[podświetlenie]]></category>
		<category><![CDATA[product]]></category>
		<category><![CDATA[scriptaculous]]></category>
		<category><![CDATA[xhtml]]></category>

		<guid isPermaLink="false">http://m1chu.eu/?p=1157</guid>
		<description><![CDATA[
Jedni nie korzystają z nich wcale, niektórzy tylko po to aby zwiększyć funkcjonalność tworzonych przez siebie stron, a u jeszcze innych zauważalny jest przepych tego typu rozwiązań. Biblioteki programistyczne języka JavaScript, bo o ich wykorzystaniu tu mowa to źródło bardzo różnorodnych, nie tylko funkcjonalnych, ale także estetycznych efektów. Sieć aż kipi od dobrych i słabych, [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: center;"><img class="iborder" src="http://farm1.static.flickr.com/242/3264023222_981cfd8fd0_o.png" alt="Efekt podświetlania w jQuery i Prototype" style="height: 119px;" /></p>
<p>Jedni nie korzystają z nich wcale, niektórzy tylko po to aby zwiększyć funkcjonalność tworzonych przez siebie stron, a u jeszcze innych zauważalny jest przepych tego typu rozwiązań. Biblioteki programistyczne języka JavaScript, bo o ich wykorzystaniu tu mowa to źródło bardzo różnorodnych, nie tylko funkcjonalnych, ale także estetycznych efektów. Sieć aż kipi od dobrych i słabych, lepiej oraz słabiej wytłumaczonych przykładów użycia możliwości <a target="_blank" href="http://mootools.net/"  title="MooTools">MooTools</a>, <a target="_blank" href="http://jquery.com/"  title="jQuery">jQuery</a>, <a target="_blank" href="http://www.prototypejs.org/"  title="Prototype">Prototype</a> z <a target="_blank" href="http://script.aculo.us/"  title="Scriptaculous">Scriptaculous</a>, czy innych mniej powszechnych frameworków.</p>
<p>Jednym z takich efektów jest możliwość stworzenia animowanego, graficznego podświetlenia pojawiającego się np. nad grafiką wywołującą animację. Interaktywność taka została opisana na <a target="_blank" href="http://utnij.eu/product-highlighter-mootools/"  title="Product highlighter with MooTools">NetTuts</a> z wykorzystaniem MooTools. My osiągniemy taki wynik dzięki zastosowaniu jQuery (w jednym przykładzie) oraz dodatkowo także za pomocą Prototype wraz z Scriptaculous (w drugim przykładzie).</p>
<p><span id="more-1157"></span></p>
<p style="text-align: center; font-size: 10px;"><object type="application/x-shockwave-flash" width="538" height="352" data="http://www.vimeo.com/moogaloop.swf?clip_id=3136566&amp;server=www.vimeo.com&amp;fullscreen=1&amp;show_title=1&amp;show_byline=0&amp;show_portrait=0&amp;color=01AAEA"><param name="quality" value="best" /><param name="allowfullscreen" value="true" /><param name="scale" value="showAll" /><param name="movie" value="http://www.vimeo.com/moogaloop.swf?clip_id=3136566&amp;server=www.vimeo.com&amp;fullscreen=1&amp;show_title=1&amp;show_byline=0&amp;show_portrait=0&amp;color=01AAEA" /><img class="iborder" src="http://farm1.static.flickr.com/190/3263308689_e6578263b5_o.png" alt="Oczekiwany efekt" style="height: 366px;" /></object><br />Oczekiwany efekt.</p>
<h2>Krok 1: Za co się chwycić na początku&#8230;</h2>
<p>Na początek musisz wiedzieć w jakim celu potrzebny jest Ci prezentowany w tym artykule efekt. Menu? Wyświetlanie dodatkowych informacji w graficznej liście produktów? Czy może szybki, animowany splash? Wybór jest Twój i podług niego będziesz musiał zaopatrzyć się w dodatkowe, niezbędne elementy do wykonania podświetlenia.</p>
<p>Chodzi tu mianowicie o grafiki, których musi być dwa razy więcej niż elementów podatnych na działanie mechanizmu. Powiedzmy, jeżeli chcemy w pięcioelementowym menu zastosować w każdym zdarzenie po najechaniu myszką zgodne z przesłaniem tego artykułu to potrzebujemy dziesięciu grafik. Pięć opisujących przyciski menu i drugie tyle będące &#8220;treścią&#8221; pojawiającą się po podświetleniu.</p>
<p>Po uporaniu się z wizualną częścią problemu oraz strony internetowej możemy ruszyć krok dalej.</p>
<h2>Krok 2: Zaopatrujemy się w jQuery i/lub Prototype i Scriptaculous!</h2>
<p><strong>jQuery</strong> to aktualnie najpopularniejsza biblioteka. I najłatwiej ją skatalogować w czeluścia własnego projektu. Wystarczy ze <a target="_blank" href="http://jquery.com/"  title="jQuery">strony głównej</a> pobrać wersję <strong>1.3.1 production/Minified</strong> i umieścić ją w obrębie plików tworzonego przez nas przykładu (niezbędny będzie tylko plik <strong>jquery-1.3.1.min.js</strong>).</p>
<p>Z <strong>Prototype</strong> sprawa jest ciut bardziej skomplikowana, bo prócz standardowego frameworka musimy pobrać także dodatkowy interfejs w postaci <strong>Scriptaculous</strong>, dzięki któremu uzyskamy dostęp do efektu pozwalającego na dynamiczne zmienianie właściwości CSS elementów strony. Ściągamy więc <a target="_blank" href="http://utnij.eu/prototype-download/"  title="Prototype">wersję 1.6.0.3 pierwszej biblioteki</a>, oraz paczkę z <a target="_blank" href="http://utnij.eu/scriptaculous-download/"  title="Scriptaculous">wersją 1.8.2 drugiej</a>. Z obydwu wyodrębniamy pliki i w ramach folderu tworzonego przez nas projektu umieszczamy tylko <strong>prototype.js</strong> oraz <strong>effects.js</strong> (z drugiego archiwum).</p>
<p>W przypadku tego artykułu umownie pliki związane z frameworkami będą znajdować się w podkatalogu <strong>javascript</strong> folderu głównego. Obydwa przykłady (dotyczące, jeden <strong>jQuery</strong>, a drugi <strong>Prototype z Scriptaculous</strong>) będą oczywiście wykonywane w osobnych plikach znajdujących się w dwóch różnych katalogach.</p>
<p style="text-align: center; font-size: 10px;"><img class="iborder" src="http://farm1.static.flickr.com/243/3263426717_b9e39151ce_o.png" alt="Rozdzielenie implementacji przykładów na dwa katalogi" style="height: 280px;" /><br />Przykładowe rozdzielenie implementacji przykładów na dwa katalogi. W naszym przypadku pliki <strong>.js</strong> znajdują się dodatkowo w podkatalogu <strong>javascript</strong>.</p>
<h2>Krok 3: Tworzymy strukturę XHTML</h2>
<p>Atutem naszego rozwiązania jest kompatybilność z serwowaniem dokumentu XHTML w postaci <code>application/xhtml+xml</code>, czego bardzo często brakuje w przypadku efektów opartych na bibliotekach JS. Z racji tego także, że i w przypadku <strong>Prototype</strong> i <strong>jQuery</strong> struktura strony pozostaje niezmienna to obojętnie który framework wykorzystujesz poniższe tłumaczenie i partie kodu będą prawidłowe.</p>
<p>Z powodu tego w jaki sposób będziemy wysyłać treść strony posłużymy się małą częścią kodu PHP, a co za tym idzie plik korzystający z naszego mechanizmu musi mieć też takie rozszerzenie (no chyba, że serwer jest inaczej skonfigurowany, ale to już problematyka do rozwiązania na inny temat).</p>
<pre class="brush: php;">&lt;?php
if ( stristr($_SERVER['HTTP_ACCEPT'], 'application/xhtml+xml') ) // jeżeli przeglądarka obsługuje application/xhtml+xml
{
	header(&quot;Content-Type: application/xhtml+xml; charset=utf-8&quot;); // wysłanie odpowiednich nagłówków
	print '&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;'.&quot;\r\n&quot;;
	print '&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.1//EN&quot;'.&quot;\r\n&quot;;
	print '&quot;http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd&quot;&gt;'.&quot;\r\n&quot;;
}
else // wysłanie dokumentu jako text/html dla przeglądarek nie obsługujących typu zawartości pliku z powyższego warunku, np. dla IE
{
	header(&quot;Content-Type: text/html; charset=utf-8&quot;);
	print '&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Strict//EN&quot;'.&quot;\r\n&quot;;
	print '&quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&quot;&gt;'.&quot;\r\n&quot;;
}
?&gt;</pre>
<p>Poniżej dodajemy uniwersalny układ strony. Ważnym ułatwieniem jest możliwość tworzenia odnośników z elementów graficznych podatnych mechanizmowi, a także fakt, że nie korzystamy w nim z tagów <code>img</code>, a efektu zbliżonego do <a href="http://m1chu.eu/webmastering/efekt-rollover-w-css-bez-przeladowywania-obrazka"  title="Efekt rollover">sliding-doors</a> w celu wyświetlania obrazów.</p>
<pre class="brush: xml;">&lt;html lang=&quot;pl&quot; xml:lang=&quot;pl&quot; xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;
&lt;head&gt;
	&lt;meta http-equiv=&quot;Content-type&quot; content=&quot;&lt;?php print ( stristr($_SERVER['HTTP_ACCEPT'], 'application/xhtml+xml') ? 'application/xhtml+xml' : 'text/html' ); // typ zawartości zależny do możliwości przeglądarki użytkownika ?&gt;; charset=utf-8&quot; /&gt;
  	&lt;meta name=&quot;Description&quot; content=&quot;Product highlighter - tworzenie dynamicznych opisów produktów - m1chu.eu&quot; /&gt;
  	&lt;meta name=&quot;Keywords&quot; content=&quot;product, highlighter&quot; /&gt;
	&lt;title&gt;Product highlighter&lt;/title&gt;
	&lt;style type=&quot;text/css&quot;&gt;@import url('stylesheet.css');&lt;/style&gt; &lt;!-- arkusz stylów --&gt;
&lt;/head&gt;
&lt;body&gt;
	&lt;div id=&quot;siteContainer&quot;&gt;
		&lt;div id=&quot;highlightsContainer&quot;&gt; &lt;!-- zbiór grafik wyświetlanych przy najechaniu kursorem --&gt;
			&lt;div class=&quot;highlights&quot; id=&quot;highlight1&quot;&gt;&lt;/div&gt;
			&lt;div class=&quot;highlights&quot; id=&quot;highlight2&quot;&gt;&lt;/div&gt;
			&lt;div class=&quot;highlights&quot; id=&quot;highlight3&quot;&gt;&lt;/div&gt;
		&lt;/div&gt;

		&lt;div id=&quot;pageContainer&quot;&gt; &lt;!-- zbiór grafik podatnych na efekt --&gt;
			&lt;div class=&quot;pages&quot; id=&quot;page1&quot;&gt;&lt;a href=&quot;http://m1chu.eu/&quot;&gt;&lt;/a&gt;&lt;/div&gt;
			&lt;div class=&quot;pages&quot; id=&quot;page2&quot;&gt;&lt;a href=&quot;http://vivee.info/&quot;&gt;&lt;/a&gt;&lt;/div&gt;
			&lt;div class=&quot;pages&quot; id=&quot;page3&quot;&gt;&lt;a href=&quot;http://utnij.eu/&quot;&gt;&lt;/a&gt;&lt;/div&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
<h2>Krok 4: Stylizujemy strukturę strony za pomocą CSS</h2>
<p>Posługując się metodami <a href="http://m1chu.eu/2009/01/08/pozycjonujemy-za-pomoca-kaskadowego-arkusza-stylow-css/"  title="Pozycjonowanie za pomocą CSS">pozycjonowania elementów</a> dostępnymi w kaskadowym arkuszu stylów możemy operując na elementach o identyfikatorach <code>siteContainer</code>, <code>pageContainer</code>, <code>highlightsContainer</code> oraz <code>divach</code> potomnych ułożyć i wystylizować wygląd, w tym położenie jak na wyżej zamieszczonym filmiku (screenie) obrazującym wykonanie zadania z tego artykułu.</p>
<p>Do wszystkich bloków kodu CSS odwołujących się do tagów zawierających identyfikatory grafik zostały dodane także właściwości <code>background</code> z adresem pliku tła.</p>
<p>W naszym przypadku poniższy kod zapisujemy do pliku <strong>stylesheet.css</strong>.</p>
<pre class="brush: css;">/* ustawienia domyślne dla ciała strony (w poprawnie wysyłanym XHTML jest to html+body, a nie tylko body) */
html, body {
	margin: 0px;
	padding: 0px;
	background: #000 url('bg.png') repeat-x;
}

#siteContainer {
	margin: 150px auto 0px auto; /* marginesy - wyśrodkowanie poziome */
	width: 573px;
	height: 345px;
	position: relative; /* relatywna pozycja, kontener */
	background: transparent url('container.png') no-repeat top left;
}
#pageContainer {
	position: absolute; /* pozycja względem #siteContainer */
	z-index: 5; /* ponad ciałem strony i pod #highlightsContainer */
	top: 128px;
	left: 0px;
}
#highlightsContainer {
	position: absolute; /* pozycja względem #siteContainer */
	z-index: 10; /* ponad pozostałymi elementami */
	left: 178px;
	top: 30px;
}
/* ustawienie w linii wraz z zmianą wyglądu kursora */
#pageContainer &gt; div {
	float: left;
	cursor: pointer;
}
/* rozmiary klikalnych divów potomnych znajdujących się w kontenerze listy grafik podatnych na działanie mechanizmu */
#pageContainer &gt; div a {
	width: 178px;
	height: 178px;
	display: block;
}
#page1 {
	margin-right: 19px; /* prawy margines - odstęp od kolejnego diva */
}
#page1 a {
	background: url('icon_1.png') no-repeat; /* tło grafiki podatnej na działanie efektu */
}
#page2 {
	margin-right: 20px; /* prawy margines - odstęp od kolejnego diva */
}
#page2 a {
	background: url('icon_2.png') no-repeat; /* tło grafiki podatnej na działanie efektu */
}
#page3 a {
	background: url('icon_3.png') no-repeat; /* tło grafiki podatnej na działanie efektu */
}

/* rozmiary wszystkich potomków typu div kontenera zawierającego podświetlenia */
#highlightsContainer &gt; div {
	position: absolute;
	width: 222px;
	height: 101px;
	display: block;
}
/* pliki tła w pojawiających się podświetleniach */
#highlight1 {
	background: transparent url('highlights_1.png') no-repeat;
}
#highlight2 {
	background: transparent url('highlights_2.png') no-repeat;
}
#highlight3 {
	background: transparent url('highlights_3.png') no-repeat;
}</pre>
<h2>Krok 5a: Dodajemy jQuery do dokumentu</h2>
<p>Tego, czego zabrakło dotychczasowo w naszym dokumencie to załączenie bibliotek oraz pliku <strong>.js</strong> w którym będzie znajdować się kod animujący pożądany przez nas efekt.</p>
<p>Dla <strong>jQuery</strong> w sekcji <code>head</code> należy dodać pliki <strong>jquery-1.3.1.min.js</strong> oraz <strong>product-highlighter.js</strong> (który umownie będzie zawierał dodatkowy kod).</p>
<pre class="brush: xml;">	&lt;script type=&quot;text/javascript&quot; src=&quot;javascript/jquery-1.3.1.min.js&quot;&gt;&lt;/script&gt;
	&lt;script type=&quot;text/javascript&quot; src=&quot;javascript/product-highlighter.js&quot;&gt;&lt;/script&gt;</pre>
<h2>Krok 5b: Dodajemy Prototype z Scriptaculous do dokumentu</h2>
<p>Tym razem musimy dodać jeden plik więcej. Bibliotekę (<strong>prototype.js</strong>), jej dodatkowy interfejs, a dokładniej plik zawierający obiekt <strong>Effect</strong> (<strong>effects.js</strong>) oraz jak w powyższym przypadku plik z naszym kodem animacji (<strong>product-highlighter.js</strong>).</p>
<pre class="brush: xml;">		&lt;script type=&quot;text/javascript&quot; src=&quot;javascript/prototype.js&quot;&gt;&lt;/script&gt;
	&lt;script type=&quot;text/javascript&quot; src=&quot;javascript/effects.js&quot;&gt;&lt;/script&gt;
	&lt;script type=&quot;text/javascript&quot; src=&quot;javascript/product-highlighter.js&quot;&gt;&lt;/script&gt;</pre>
<h2>Krok 6a: Implementujemy kod animacji z użyciem jQuery</h2>
<p>Jak to bywa w przypadku tego frameworka, aby jakieś zdarzenie działało poprawnie powinno się je umieszczać w funkcji <code>$(document).ready()</code>, której zawartość zostanie załadowana w momencie załadowania drzewa dokumentu.</p>
<pre class="brush: jscript;">$(document).ready(function() {
	[kod]
});</pre>
<p>W <strong>[</strong><strong>kod]</strong> musimy przypisać (do tablicy) wg. klasy wszystkie grafiki wyświetlane podczas podświetlenia, ustawić parametry podstawowe CSS oraz stworzyć sprawdzanie w pętli, czy dana grafika o klasie <code>.pages</code> nie jest najechana przez kursor i w zależności o danego trybu (<em>kursor na/kursor poza</em>) wykonać pożądaną animacji (<em>wyłonienie dodatkowego tła / zanikanie dodatkowego tła</em>).</p>
<p>Poniższy kod umieszczamy w pliku <strong>product-highlighter.js</strong>.</p>
<pre class="brush: jscript;">$(document).ready(function() {
	// tablica elementów o klasie .highlights
	var highlights = $('.highlights');

	// ustawienie pełnej przezroczystości elementów pojawiających się w czasie najechania myszką na obiekty podatne efektowi oraz widzialności ich kontenera
	$('.highlights').css('opacity', 0);
	$('#highlightsContainer').css('visibility', 'visible');

	// sprawdzanie każdego elementu podatnego mechanizmowi
	$('.pages').each(function(i) {
		// jeżeli na danym elemencie znajduje się kursor
		$(this).mouseover(function() {
			// wykonanie animacji grafiki wyłanianej i przypisanej do najechanego elementu (margines o 15px w górę i brak przezroczystości w czasie 0,5 sekundy)
			$(highlights[i]).animate({
				opacity: 1,
				marginTop: '-15px'
			}, 500);
		}).mouseout(function(){ // jeżeli na danym elemencie nie znajduje się już kursor
			$(highlights[i]).animate({
				opacity: 0,
				marginTop: '-0px'
			}, 500);
		});
	});
});</pre>
<p>Należy jeszcze wyjaśnić dokładniej w jaki sposób działa <code>$(highlights[i]).animate()</code>. Mianowicie przy każdej iteracji pętli <code>$('.pages').each()</code> przekazuje ona do parametru <code>function(i)</code> aktualny numer elementu na którym się znajduje. Ponieważ w id <code>pageContainer</code> znaczniki potomne muszą być posegregowane i musi być ich tyle samo co obiektów graficznych w <code>highlightsContainer</code> to jeżeli kursor znajduje się na pierwszym podatnym na efekt obrazie to w podświetleniu wyłania się także pierwsza grafika. Wszystko to dzięki wyłuskaniu jej z tablicy <code>highlights</code> poprzez parametr <code>i</code>.</p>
<h2>Krok 6b: Implementujemy kod animacji z użyciem Prototype z Scriptaculous</h2>
<div class="explain"><code>Event.observe</code> &#8211; uchwyt rejestrujący zdarzenie na drzewie dokumentu. Funkcja obiektu składającego się na bibliotekę <strong>Prototype</strong>. Posiada cztery argumenty:
<ul>
<li><strong>element</strong> &#8211; obserwowany element DOM, mogący być referencją do niego bądź jego identyfikatorem,</li>
<li><strong>nazwaZdarzenia</strong> &#8211; standaryzowana wg. <a target="_blank" href="http://utnij.eu/af/"  title="DOM Level 2 Events">DOM Level 2 Events</a> nazwa zdarzenia, np. <strong>load</strong>,</li>
<li><strong>uchwyt</strong> &#8211; uchwyt w postaci funkcji.</li>
</ul>
<p>Przykład:</p>
<pre class="brush: xml;">&lt;p id=&quot;test&quot;&gt;Prototype&lt;/p&gt;</pre>
<pre class="brush: jscript;">Event.observe('test', 'click', function() {
	[kod]
});</pre>
</div>
<p>Podobnie w <strong>Prototype</strong> obserwujemy zdarzenie, ale tym razem załadowania całej strony w celu późniejszej obserwacji aktywności kursora na wybranych elementach aktywnych. Można oczywiście podobnie jak w poprzednim podpunkcie wykonać obserwacje zdarzeń wraz z załadowanie DOM (drzewa dokumentu) poprzez użycie <code>document.observe('dom:loaded', function() {})</code>. To tylko kwestia osobistego wyboru.</p>
<pre class="brush: jscript;">Event.observe(window, 'load', function() {
	[kod]
});</pre>
<p>Dalsze postępowanie jest adekwatne do tego opisanego w przypadku zastosowania <strong>jQuery</strong>. Z tymże, tablicę elementów o danej klasie pobiera się poprzez podwójny znak dolara (<code>$$</code>), a najechanie oraz zjechanie kursorem poza zadany obszar rozpoznaje się także poprzez obiekt <code>Event</code> i metodę <code>observe()</code>. Do animacji służy funkcja <code>Morph</code> instancji <code>Effect</code> z pliku <code>effects.js</code> interfejsu <strong>Scriptaculous</strong >.</p>
<pre class="brush: jscript;">Event.observe(window, 'load', function() {
	var highlights = $$('.highlights'); // utworzenie tablicy

	$$('.highlights').invoke('setStyle', { opacity: 0 }); // ustawienie stylu przezroczystości
	$$('#highlightsContainer').invoke('setStyle', { visibility: 'visible' }); // widzialność kontenera

	$$('.pages').each(function(v, i) { // pętla
		Event.observe(v, 'mouseover', function() { // zdarzenie wykonywane w momencie pojawienia się kursora na elemencie
			new Effect.Morph(highlights[i], { // animacja
				style: 'opacity: 1; margin-top: -15px;',
				duration: 0.5 // czas 0,5 sekundy
			});
		});
		Event.observe(v, 'mouseout', function() { // zdarzenie wykonywane w momencie wyjechania kursorem poza element
			new Effect.Morph(highlights[i], {
				style: 'opacity: 0; margin-top: 0px;',
				duration: 0.5
			});
		});
	});
});</pre>
<p>Tym razem do funkcji w <code>$$('.pages').each()</code> przekazywane są dwa parametry: <code>v</code> i <code>i</code>. Pierwszy z nich jest odpowiednikiem <code>this</code> i wskazuje na aktualnie przetwarzany element tablicy znaczników o klasie <code>.pages</code>. Drugi to numer pokazujący który z kolei tag jest aktualnie sprawdzany. Inaczej pisząc jego zadanie jest równoznaczne do działania parametru <code>i</code> w przykładzie z <strong>jQuery</strong>.</p>
<div class="explain"><code>Effect.Morph</code> &#8211; metoda interfejsu <code>Scriptaculous</code> >= <strong>1.7</strong>. Pozwala na animacyjną zmianę właściwości CSS elementu. Przyjmuje jeden podstawowy argument <code>style</code> zawierający w sobie właściwości i wartości CSS w formie oryginalnej bądź w postaci <strong>Camel-Case</strong>, czyli bez spacji i znaków specjalnych pomiędzy kilkoma członami nazwy właściwości. Opcjonalnie można dodawać kolejne parametry rdzenia obiektu <code>Effect</code>, takie jak <code>duration</code> (czas animacji), czy <code>transition</code> (rodzaj animacji, wymaga <code>Effect.Transitions</code>).</p>
<p>Przykład:</p>
<pre class="brush: jscript;">new Effect.Morph('div_id', {
	style: {
		background-color: '#000',
		color: '#fff'
	},
	duration: 0.5,
	transition: Effect.Transitions.spring
});</pre>
</div>
<h2>Demonstracja wyników&#8230;</h2>
<p>Stworzyłem dwa gotowe przykłady, których analiza pozwoli Wam jeszcze bardziej zrozumieć jak stworzyć ten efekt. <a href="http://use.m1chu.eu/-jquery/product-highlighter/"  title="Product Highlighter - jQuery"><strong>Pierwszy</strong></a>, za pomocą jQuery. <a href="http://use.m1chu.eu/-prototype/product-highlighter/"  title="Product Highlighter - Prototype z Scriptaculous"><strong>Drugi</strong></a>, za pomocą Prototype z Scriptaculous.</p>
<p>Jeżeli chcecie dowiedzieć się więcej o tych bibliotekach to zapraszam do ich dokumentacji (<a target="_blank" href="http://www.prototypejs.org/api"  title="API Prototype">Prototype</a>, <a target="_blank" href="http://docs.jquery.com/Main_Page"  title="API jQuery">jQuery</a>).</p>
]]></content:encoded>
			<wfw:commentRss>http://m1chu.eu/2009/02/09/efekt-graficznego-podswietlenia-w-jquery-i-prototype-z-scriptaculous/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>2 animowane menu za pomocą funkcji jQuery &#8211; animate()</title>
		<link>http://m1chu.eu/2008/10/27/2-animowane-menu-za-pomoca-funkcji-jquery-animate/</link>
		<comments>http://m1chu.eu/2008/10/27/2-animowane-menu-za-pomoca-funkcji-jquery-animate/#comments</comments>
		<pubDate>Sun, 26 Oct 2008 23:24:14 +0000</pubDate>
		<dc:creator>m1chu</dc:creator>
				<category><![CDATA[(x)HTML]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Webhosting]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[animate()]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[floating]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[jumping]]></category>
		<category><![CDATA[navigation]]></category>
		<category><![CDATA[xhtml]]></category>

		<guid isPermaLink="false">http://m1chu.eu/?p=246</guid>
		<description><![CDATA[
Mając do dyspozycji jQuery możemy dokonać wielu mniej lub bardziej oryginalnych modyfikacji dla urozmaicenia wyglądu tworzonej przez nas nawigacji na stronie. Funkcja animate() znakomicie nadaje się do kreowania animacji różnego typu relatywnie lub absolutnie pozycjonowanych elementów pozwalając na operowanie np. na ich szerokości, czy wysokości.

animate() &#8211; funkcja zezwalająca na wykonywanie animacji elementów strony. Pozwala na [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: center;"><img class="iborder" src="http://farm4.static.flickr.com/3277/2978445162_490b1dd3a1_o.png" alt="Animacje nawigacji za pomocą jQuery" /></p>
<p>Mając do dyspozycji <strong>jQuery</strong> możemy dokonać wielu mniej lub bardziej oryginalnych modyfikacji dla urozmaicenia wyglądu tworzonej przez nas nawigacji na stronie. Funkcja <a target="_blank" href="http://docs.jquery.com/Effects/animate"  title="jQuery: animate()"><strong>animate()</strong></a> znakomicie nadaje się do kreowania animacji różnego typu relatywnie lub absolutnie pozycjonowanych elementów pozwalając na operowanie np. na ich szerokości, czy wysokości.</p>
<p><span id="more-246"></span></p>
<p class="explain"><strong>animate()</strong> &#8211; funkcja zezwalająca na wykonywanie animacji elementów strony. Pozwala na działanie na właściwościach stylów takich jak szerokość (<em>width</em>), wysokość (<em>height</em>), <em>padding</em>, margines (<em>margin</em>), krawędź (<em>border</em>), górny brzeg elementu (<em>top</em>), czy wielkość czcionki (<em>font-size</em>). Dozwolone są więc właściwości przyjmujące wartości numeryczne (bądź <strong>&#8220;toggle&#8221;</strong>, <strong>&#8220;show&#8221;</strong> lub <strong>&#8220;hide&#8221;</strong>), a zapis ich nazw musi być w formie <strong>CamelCase</strong>, czyli poprzez bikapitalizację pojęć złożonych (usunięcie spacji i zastąpienie pierwszych znaków kolejnych słów dużymi literami). Przykładowo odpowiednikiem <strong>margin-right</strong> będzie <strong>marginRight</strong>. Od wersji <strong>1.2 jQuery</strong> pozwala je animować poprzez nadanie w.w. wartości także w postaci <strong>em</strong> i <strong>%</strong>. Wprowadzono w nim także krótkie zwiększanie (<strong>&#8220;+=&#8221;</strong>, np. <em>width: &#8220;+=5px&#8221;</em>) i zmniejszanie (<strong>&#8220;-=&#8221;</strong>, np. <em>height: &#8220;-=&#8221;+value</em>) wartości.</p>
<h2>Przygotowanie grafiki&#8230;</h2>
<p>Po przeczytaniu tego artykułu dowiesz się jak utworzyć dwa typy różnych menu oparty na frameworku jQuery, CSS-ie i (X)HTML-ie. Przykłady zastosowane w artykule będą przystosowane do XHTML-a/HTML-a wysyłanego jako <strong>text/html</strong>, a także do XHTML-a wysyłanego jako <strong>application/xhtml+xml</strong>.</p>
<p>Pierwszy z naszych efektów będzie opierał się na gotowych elementach graficzny oraz dla ukazania zwiększonych możliwości na jednej grafice będącej logiem konkretnego serwisu. Zastosujemy w tym przypadku opisywany już przeze mnie efekt <a href="http://m1chu.eu/webmastering/efekt-rollover-w-css-bez-przeladowywania-obrazka"  title="Efekt rollover - sliding-doors"><strong>sliding-doors</strong></a> (także wyjaśniany na <a target="_blank" href="http://vivee.info/2008/06/07/poziome-menu-z-efektem-sliding-doors/"  title="Sliding-doors - vivee">vivee</a>) dzięki któremu pozbędziemy się problemu związanego z nadmiernym ładowaniem grafik.</p>
<p>Potrzebne będzie nam sześć obrazków. Trzy z których będziemy korzystać dla wyświetlania w stanie nie najechania myszką, w stanie najechania i w stanie kliknięcia (bądź wyboru za pomocą tabulatora), oraz drugie trzy używane w takiej samej kolejności, ale które będą stworzone specjalnie dla przykładu użycia grafiki oddzielnego typu dla konkretnego przycisku. Należy pamiętać, aby realna wysokość grafiki była co najmniej tak duża, żeby spełniała potrzeby po, a nie przed pojawieniem się kursora nad nią. Tak więc, jeśli np. w normalnej pozycji ma ona <strong>57px</strong>, a po rozszerzeniu o <strong>10px</strong> więcej to szerokość jednego, pojedynczego obrazu nie powinna być mniejsza niż <strong>67px</strong>.</p>
<p style="text-align: center;"><img class="iborder" src="http://farm4.static.flickr.com/3200/2975302246_39ff35023f_o.png" alt="Cięcie podstawowego typu grafiki" /></p>
<p>Jak widać na wyżej załączonym screenie dzielimy przyciski na trzy kolumny &#8211; lewą, prawą i środek. Dwie pierwsze w naszym rozwiązaniu będą stałe, a środek będzie powielany w arkuszu stylów względem osi X (<strong>repeat-x</strong>). W przypadku wspomnianego już przycisku specjalnego ten podział nie istnieje (zapisujemy całość), gdyż szerokość generowanego w HTML-u rozwiązania będzie niezmienna.</p>
<p style="text-align: center;"><img class="iborder" src="http://farm4.static.flickr.com/3248/2978566762_d835e142c0_o.png" alt="Tworzenie specjalnego typu grafiki" /></p>
<h2>I. Jumping navigation (nawigacja &#8220;podskakująca&#8221;): kod XHTML</h2>
<p>Kod struktury menu oprę o znaczniki listowania które oczywiście należy wstawić w sekcję <strong>body</strong>.</p>
<pre class="brush: xml;">&lt;ul id=&quot;jumping-nav&quot;&gt;
	&lt;li&gt;&lt;a href=&quot;#&quot; title=&quot;#&quot;&gt;&lt;span class=&quot;left&quot;&gt;&lt;/span&gt;Link 1&lt;span class=&quot;right&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;#&quot; title=&quot;#&quot;&gt;&lt;span class=&quot;left&quot;&gt;&lt;/span&gt;Link 2&lt;span class=&quot;right&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://m1chu.eu/&quot; title=&quot;Programowanie, webdeveloping&quot;&gt;&lt;span class=&quot;left&quot;&gt;&lt;/span&gt;m1chu.eu&lt;span class=&quot;right&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
	&lt;li id=&quot;with-image&quot;&gt;&lt;a href=&quot;http://utnij.eu/&quot; title=&quot;Prawdopodobnie najlepszy serwis do skracania linków&quot;&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</pre>
<p>Jak można zauważyć w trzech pierwszych odnośnikach nawigacji na stronie znajduje się tekst oraz znaczniki <strong>span</strong>. Odpowiadają one za wyświetlenie lewej oraz prawej krawędzi tła każdego z przycisków menu. W wypadku ostatniego linka nie jest to potrzebne, gdyż tło jest jednolitej szerokości, a tekst naniesiony jest bezpośrednio na nim. Specjalny element tej listy oznaczony jest ID <strong>with-image</strong>.</p>
<h2>I. Jumping navigation: kod CSS</h2>
<pre class="brush: css;">ul#jumping-nav
{
	position: relative;
	float: left; /* przemianowanie listy na szeregową */
	overflow: hidden;
	border-bottom: 1px solid #fff;
	padding: 0 10px;
	list-style: none;
	height: 4em; /* szerokosc przycisku */
}

ul#jumping-nav li, ul#jumping-nav li a
{
	position: relative;
	float: left; /* przemianowanie listy na szeregową */
} 

ul#jumping-nav li
{
	background: none;
	margin: 0;
	padding: 0;
	padding-left: 1px; /* 1-pikselowe rozdzielenie dwoch przyciskow od siebie */
	top: 15px; /* odleglosc od gornej krawedzi danej listy */
}

ul#jumping-nav li a
{
	display: block;
	background: url('srodkowa_czesc_grafiki.png') 0 0 repeat-x; /* adres do grafiki srodka przycisku powtarzany na osi X */
	padding: 0.9em 1.1em;
	text-decoration: none;
	color: #129397;
	height: 57px;
}

ul#jumping-nav li a span.left {
	display: block;
	/* pozycja absolutna */
	position: absolute;
	background: url('lewa_krawedz_grafiki.png') 0 0 no-repeat; /* adres do grafiki lewej krawedzi przycisku */
	height: 57px;
	width: 12px;
	/* ustawienie grafiki lewej krawedzi w pozycji lewego, gornego rogu elementu listy */
	left: 0;
	top: 0;
	z-index: 10; /* ustawienie grafiki granicznej nad powielana, srodkowa */
}

ul#jumping-nav li a span.right {
	display: block;
	/* pozycja absolutna */
	position: absolute;
	background: url('prawa_krawedz_grafiki.png') 0 0 no-repeat; /* adres do grafiki prawej krawedzi przycisku */
	height: 57px;
	width: 12px;
	/* ustawienie grafiki prawej krawedzi w pozycji prawego, gornego rogu elementu listy */
	right: 0;
	top: 0;
	z-index: 10; /* ustawienie grafiki granicznej nad powielana, srodkowa */
}

/* zmiany dokonywane przy najechaniu mysza na przycisk (grafika srodkowa + grafiki krawedzi) */
ul#jumping-nav li a:hover, ul#jumping-nav li a:hover span
{
	background-position: 0 -57px; /* przesuniecie pozycji tla o 57px w dol */
	color: #3f5f5a;
}

/* zmiany dokonywane przy kliknieciu mysza na przycisk lub po zaznaczeniu jej tabulatorem (grafika srodkowa + grafiki krawedzi) */
ul#jumping-nav li a:active, ul#jumping-nav li a:active span, ul#jumping-nav li a:focus, ul#jumping-nav li a:focus span
{
	background-position: 0 -114px; /* przesuniecie pozycji tla o 114px w dol */
	color: #333;
}</pre>
<p>Stosowne komentarze pozostawiłem w kodzie. Wytłumaczyć należałoby za to dokładniej zastosowaną w bloku elementu listy odległość od górnej granicy tejże listy.</p>
<pre class="brush: css;">top: 15px; /* odleglosc od gornej krawedzi danej listy */</pre>
<p>Odległość ta pozwala na ustalenie pozycji wyjściowej przycisków i będzie tak samo na stałe ustawiona w kodzie jQuery. Odejmując od niej otrzymamy pożądany przez nas efekt podniesienia przycisku po najechaniu na niego kursorem.</p>
<p>O czymś jednak pozornie zapomniałem w powyższym kodzie. Mianowicie o wspomnianym już przycisku specjalnym znajdującym się w tagu <strong>li</strong> o ID <strong>with-image</strong>. Sprawa jest prosta, a jej rozwiązanie będzie opierać się o dodanie kodu opartego na dwóch ostatnich blokach podanych w w.w. kodzie CSS.</p>
<pre class="brush: css;">ul#jumping-nav li#with-image a
{
	display: block;
	padding: 0.9em 1.1em;
	background: url('grafika_specjalna.png') 0 0 no-repeat; /* brak powtarzania w jakiejkolwiek osi */
	color: #333;
	text-decoration: none;
	height: 57px;
	width: 117px; /* okreslona na stale szerokosc przycisku */
}

/* zmiany dokonywane po najechaniu mysza na przycisk specjalny */
ul#jumping-nav li#with-image a:hover
{
	background-position: 0 -57px;
}

/* zmiany dokonywane przy kliknieciu mysza na przycisku specjalnym lub po zaznaczeniu jej tabulatorem */
ul#jumping-nav li#with-image a:active, ul#jumping-nav li#with-image a:focus
{
	background-position: 0 -114px;
}</pre>
<h2>I. Jumping navigation: animacja dzięki jQuery</h2>
<div class="explain"><strong>animate( parametry, [czas_wykonania], [styl_animacji], [akcja_zwrotna] )</strong></p>
<ul>
<li><strong>parametry</strong> &#8211; elementy animacji do wykonania (będące odpowiednikami dyrektyw CSS), np. <strong>top</strong>, <strong>left</strong>, <strong>marginLeft</strong>, <strong>width</strong>, <strong>height</strong>, czy <strong>opacity</strong>. Podawane są w formie <strong>nazwa: wartosc</strong> i rozdzielane przecinkami.</li>
<li><strong>czas_wykonywania</strong> &#8211; czas w milisekundach (lub w postaci wbudowanego ciągu znaków: <strong>&#8220;slow&#8221;</strong>, <strong>&#8220;normal&#8221;</strong> lub <strong>&#8220;fast</strong>) wykonywania animacji.</li>
<li><strong>styl_animacji</strong> (<em>opcjonalny</em>) &#8211; styl animacji, wymaga odpowiedniej wtyczki jQuery obsługującej tą opcję!</li>
<li><strong>akcja_zwrotna</strong> (<em>opcjonalny</em>) &#8211; funkcja zwracana wraz z zakończeniem animacji.</li>
</ul>
<p>Przykład:</p>
<pre class="brush: jscript;">$(&quot;div&quot;).animate({
      left: &quot;15px&quot;, opacity: .5
}, 300, &quot;easing&quot;, function(){alert(&quot;koniec!&quot;);});</pre>
</div>
<p>Na początek należy ściągnąć i zaimportować na swoją stronę najnowszą wersję <strong>jQuery</strong>. Pobrać ją można np. <a target="_blank" href="http://utnij.eu/jquery-min-1_2_6/"  title="jQuery 1.2.6">stąd</a>.</p>
<pre class="brush: xml;">&lt;script type=&quot;text/javascript&quot; src=&quot;jquery-1.2.6.min.js&quot;&gt;&lt;/script&gt; &lt;!-- jeżeli biblioteka będzie znajdować się w głównym katalogu strony --&gt;</pre>
<p>Nasz kod będzie przeznaczony dla jednego tego typu menu na danej podstronie. Po załadowaniu DOM zostanie wywołane zdarzenie <strong>:hover</strong> jQuery, a w nim funkcje wykonywane kolejno po najechaniu i po usunięciu kursora myszy z danego przycisku.</p>
<pre class="brush: jscript;">$(document).ready(function() {
    $('ul#jumping-nav li').hover(function() {
    	$(this).animate({ top : &quot;-=10px&quot; }, 150); // przesuniecie krawedzi przycisku o 10px w gore w czasie 150ms
    }, function() {
    	$(this).animate({ top : &quot;15px&quot; }, 150); // przesuniecie krawedzi do pozycji wejsciowej w czasie 150ms
    });
});</pre>
<h2>I. Jumping navigation: rezultat!</h2>
<p>Wynik jaki powinniście otrzymać po złożeniu tych części kodu w całość możecie podejrzeć <a href="http://use.m1chu.eu/-jquery/jumping-navigation/"  title="Jumping navigation - przykład"><strong>tutaj</strong></a>.</p>
<p style="text-align: center;"><img class="iborder" src="http://farm4.static.flickr.com/3031/2977596835_7b1c11d536_o.png" alt="Jumping navigation w przykładzie" /></p>
<h2>II. Floating navigation (nawigacja pływająca): kod XHTML</h2>
<p>Drugi przykład będzie ciut bardziej zaawansowany (pomysłodawcą i autorem efektu jest <a href="http://www.bedrichrios.com/"  title="Bedrich Rios" onclick="this.target='_blank';">Bedrich Rios</a>). Pod tym względem, że przedstawię użycie dwóch menu razem na stronie. Jednego poziomego i drugiego pionowego. Elementy graficzne obydwu będą opierać się tylko i wyłącznie o arkusz stylów.</p>
<p>Dla usystematyzowania położenia obydwu list odpowiedzialnych za wyświetlanie nawigacji na stronie wstawimy je w element blokowy <strong>div</strong>. Ponieważ będziemy chcieli, aby każde menu w trakcie wyświetlania aktywnego elementu podświetlane było na inny kolor to każdemu z nich nadamy odpowiedni identyfikator. Odpowiednio będą to <strong>yellow</strong> (gdzie tekst będzie podświetlany na odcień żółtego) i <strong>blue</strong> (gdzie tekst będzie podświetlany na odcień niebieskiego).</p>
<p>Ostatecznie naszym zamiarem jest dodanie także przy każdym menu tytułu. Aby jednak skrypt mógł rozróżnić go od normalnego pola z odnośnikiem musimy zastosować znacznik nagłówka. W naszym wypadku jest to <code>h4</code>.</p>
<pre class="brush: xml;">&lt;div id=&quot;nav-block&quot;&gt;
	&lt;ul class=&quot;floating-navigation&quot; id=&quot;yellow&quot;&gt;
		&lt;li&gt;&lt;h4&gt;Menu główne!&lt;/h4&gt;&lt;/li&gt; &lt;!-- nagłówek menu poziomego --&gt;
		&lt;li&gt;&lt;a href=&quot;#&quot; title=&quot;#&quot;&gt;Odnośnik 1&lt;/a&gt;&lt;/li&gt;

		&lt;li&gt;&lt;a href=&quot;#&quot; title=&quot;#&quot;&gt;Odnośnik 2&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href=&quot;http://thenet.pl/&quot; title=&quot;Technologiczne spojrzenie na świat&quot; onclick=&quot;this.target='_blank';&quot;&gt;thenet.pl&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href=&quot;http://after-all.eu/&quot; title=&quot;Nowoczesny bash z cytatami z IRC&quot; onclick=&quot;this.target='_blank';&quot;&gt;after-all.eu&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;
	&lt;ul class=&quot;floating-navigation&quot; id=&quot;blue&quot;&gt;
		&lt;li&gt;&lt;h4&gt;Menu boczne!&lt;/h4&gt;&lt;/li&gt; &lt;!-- nagłówek menu pionowego --&gt;
		&lt;li&gt;&lt;a href=&quot;#&quot; title=&quot;#&quot;&gt;Odnośnik 1&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href=&quot;#&quot; title=&quot;#&quot;&gt;Odnośnik 2&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href=&quot;http://m1chu.eu/&quot; title=&quot;Another devblog - programowanie, webdeveloping&quot; onclick=&quot;this.target='_blank';&quot;&gt;m1chu.eu&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href=&quot;http://utnij.eu/&quot; title=&quot;Prawdopodobnie najlepszy serwis do skracania linków&quot; onclick=&quot;this.target='_blank';&quot;&gt;utnij.eu&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;
&lt;/div&gt;</pre>
<h2>II. Floating navigation: kod CSS</h2>
<pre class="brush: css;">ul.floating-navigation
{
	list-style-type: none;
	font-size: 12px;
	margin: 30px 0px; /* odleglosc od lewej i prawej krawedzi */
	padding-top: 10px;
	&amp; padding-left: 30px; /* padding zastepujacy margines w IE */
	width: 985px; /* szerokosc wszystkich elementow poziomego menu + suma wymaganych szerokosci w efekcie &quot;wjezdzania&quot; (podawana w funkcji JS floatNav()) */
}

ul.floating-navigation li h4,
ul.floating-navigation li a
{
	display: block;
	width: 150px;
	padding: 5px 15px;
	margin: 0;
	margin-bottom: 2px;
}

ul.floating-navigation li h4
{
	color: #fff;
	background: #333;
	border: 1px solid #1a1a1a;
	font-weight: normal;
	font-size: 12px;
}

ul.floating-navigation li a
{
	color: #999;
	border: 1px solid #1a1a1a;
	background: #222;
	text-decoration: none;
	opacity: .7; /* opcjonalna przezroczystosc elementow */
}

ul#yellow li
{
	float: left; /* ustawienie w szeregu elementow listy w menu glownym - utworzenie menu poziomego */
}

ul#yellow li a:hover
{
	color: #ffff66; /* kolor tekst gdy myszka jest na obiekcie w menu poziomym */
	background-color: #1e1e1e;
}

ul#blue li a:hover
{
	color: #006699; /* kolor tekst gdy myszka jest na obiekcie w menu pionowym */
	background-color: #1e1e1e;
}</pre>
<p>Jedynym aspektem który należałoby wytłumaczyć jest magiczne <code>&#038; padding-left: 30px;</code>. Jest to wartość która tylko i wyłącznie pozycjonuje rozmieszczenie elementów którymi się tutaj zajmujemy. Zastanawiacie się za pewnie co robi to <strong>&#038;</strong> przez tą regułą? Jest to tzw. <strong>hack IE</strong> który działaja podobnie jak najbardziej znany <strong>*</strong> i dzięki którym dana dyrektywa wykonywana jest tylko w przeglądarkach opartych na Internet Explorerze. Musieliśmy dokonać takiego zabiegu, gdyż inaczej marginesy w przeglądarce Microsoftu byłyby ustawione na <strong>0</strong> (z niewiedzy, złej implementacji, złośliwości jej programistów&#8230; jak zwał, tak zwał :D).</p>
<h2>II. Floating navigation: animacja dzięki jQuery</h2>
<p>Podobnie jak w poprzednim typie nawigacji tutaj także trzeba skorzystać z ściągniętej już wcześniej biblioteki jQuery.</p>
<p>Tym razem jednak po załadowaniu DOM wywołamy kolejno dwie funkcje.</p>
<pre class="brush: jscript;">$(document).ready(function()
{
	floatNav(&quot;ul#yellow&quot;, 25, 15, 150, .7, 500, &quot;#fff&quot;);
	floatNav(&quot;ul#blue&quot;, 25, 15, 150, .7, 500);
});</pre>
<p>Posiadają one siedem parametrów o niżej wymienionym przeznaczeniu.</p>
<pre class="brush: plain;">floatNav(id_listy_menu, paddingLeft_gdy_kursor_jest_na_obiekcie, paddingLeft_gdy_kursor_jest_poza_obiektem, czas_wykonywania_animacji, mnoznik_kolejnego_animowania_wlotu_elementow_po_zaladowaniu_DOM [, kolor_napisow_menu_po_kliknieciu]);</pre>
<p>Ostatni parametr jest opcjonalny. W wypadku, gdy nie zostanie podany po kliknięciu zostanie zwrócony domyślny kolor. Należy zdawać sobie także sprawę, że ten sposób zadziała tylko w wypadku otwierania stron w oknach innych niż te używane przez skrypt.</p>
<pre class="brush: jscript;">function floatNav(float_nav_id, float_hover_out, float_hover_in, float_run_time, float_multiplier, float_click_effect, float_clicked_color)
{
	var list_elements = float_nav_id + &quot; li&quot;;
	var link_elements = list_elements + &quot; a&quot;;

	var timer = 0; // czas poczatkowy

	$(list_elements).each(function(i) // wczytywanie elementow po zaladowaniu strony
	{
		timer = (timer * float_multiplier + float_run_time); // zmienna przetrzymujaca czas wczytania elementu zwiekszana o wartosc sumy mnoznika i czas dzialania animacji w stosunku do czasu wczytania poprzedniego elementu

		$(this).css(&quot;margin-left&quot;,&quot;-180px&quot;); // wczytanie od strony lewego marginesu i kolejno efekt &quot;wstrzasniecia&quot; z jednej pozycji do drugiej i z powrotem
		$(this).animate({ marginLeft: &quot;0&quot; }, timer);
		$(this).animate({ marginLeft: float_hover_out }, timer);
		$(this).animate({ marginLeft: &quot;0&quot; }, timer);
	});

	var link_hover_width = $(link_elements).width(); // pobranie szerokosci wejsciowej elementu listy
	$(link_elements).hover(
		function()
		{
			$(this).animate({ paddingLeft: float_hover_out, opacity: 1, width: link_hover_width-(float_hover_out-float_hover_in) }, float_run_time); // w trakcie pojawienia sie kursora na elemencie nastepuje zmiana przezroczystosci na pelna, przesuniecie w prawo oraz zmniejszenie szerokosci elementu
		},
		function()
		{
			$(this).animate({ paddingLeft: float_hover_in, opacity: float_multiplier, width: link_hover_width }, float_run_time); // przywrocenie do wartosci podstawowych po przeniesieniu kursora poza menu
		}
	);

	$(link_elements).click(
		function()
		{
			$(this).fadeOut(float_click_effect); // efekt zanikania
			$(this).fadeIn((float_click_effect/2)); // efekt pojawiania sie w czasie dwukrotnie mniejszym niż w trakcie efektu zanikania
			if ( float_clicked_color != &quot;&quot; )
			{
				$(this).css(&quot;color&quot;, float_clicked_color); // zmiana koloru kliknietego elementu o ile podany zostal ostatni parametr funkcji nadrzednej
			}
		}
	);
}

$(document).ready(function()
{
	floatNav(&quot;ul#yellow&quot;, 25, 15, 150, .7, 500, &quot;#fff&quot;);
	floatNav(&quot;ul#blue&quot;, 25, 15, 150, .7, 500);
});</pre>
<h2>II. Jumping navigation: wynik!</h2>
<p>Także tym razem przygotowałem Wam praktyczne zobrazowanie tego co chcieliśmy osiągnąć. O! <a href="http://use.m1chu.eu/-jquery/floating-navigation/"  title="Floating navigation - przykład"><strong>tutaj, zapraszam</strong></a>.</p>
<p style="text-align: center;"><a target="_blank" href="http://farm4.static.flickr.com/3211/2975293355_49cb674e9e_o.png"  title="Pełny rozmiar - floating navigation" class="lightbox"><img class="iborder" src="http://farm4.static.flickr.com/3211/2975293355_702e58199f.jpg" alt="Jumping navigation w przykładzie" /></a></p>
<h2>Kurde! Tyle czytania i nie działa! Dlaczego?!</h2>
<p>Obydwie metody testowałem na poniższy przeglądarkach i na wszystkich działały prawidłowo:</p>
<ul>
<li>Firefox 3.0.3,</li>
<li>Opera 9.60</li>
<li>Safari 3.1.2</li>
<li>SeaMonkey 1.1.9</li>
<li>Flock 1.1.1</li>
<li>Sleipnir 2.7.2</li>
</ul>
<p>Mogę domniemać, że problem tkwi w użytkowaniu kilku frameworków naraz. Problem ten opisywałem <a href="http://m1chu.eu/wordpress/kolizje-wspoldzialania-bibliotek-javascript-na-podstawie-wtyczek-wordpress"  title="Kolizja bibliotek z jQuery w tle">tutaj</a> i radzę od jego przeczytania zacząć rozpoznawanie błędu :]</p>
]]></content:encoded>
			<wfw:commentRss>http://m1chu.eu/2008/10/27/2-animowane-menu-za-pomoca-funkcji-jquery-animate/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Kolizje współdziałania bibliotek JavaScript na podstawie wtyczek WordPress&#8230;</title>
		<link>http://m1chu.eu/2008/10/02/kolizje-wspoldzialania-bibliotek-javascript-na-podstawie-wtyczek-wordpress/</link>
		<comments>http://m1chu.eu/2008/10/02/kolizje-wspoldzialania-bibliotek-javascript-na-podstawie-wtyczek-wordpress/#comments</comments>
		<pubDate>Thu, 02 Oct 2008 10:45:38 +0000</pubDate>
		<dc:creator>m1chu</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Prototype]]></category>
		<category><![CDATA[Webhosting]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[biblioteka]]></category>
		<category><![CDATA[dom]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[wtyczka]]></category>

		<guid isPermaLink="false">http://m1chu.eu/?p=96</guid>
		<description><![CDATA[
Coraz więcej różnorodnych stron internetowych korzysta z techniki która w szeroki sposób pozwoliła rozwinąć się przede wszystkim JavaScriptowi &#8211; z Ajaxa. Podobnie jest z różnorodnymi wtyczkami do systemu blogów WordPress. Z reguły korzystają one jednak z jakiejś biblioteki JavaScript zbierającej w całość jego najważniejsze funkcje i pozwalającej na ich prostsze użycie. W momencie jednak, kiedy [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: center;"><img class="iborder" src="http://farm4.static.flickr.com/3066/2953934393_d684ed0058_o.png" alt="Współdziałanie framework'ów na przykładzie WordPress'a" /></p>
<p>Coraz więcej różnorodnych stron internetowych korzysta z techniki która w szeroki sposób pozwoliła rozwinąć się przede wszystkim JavaScriptowi &#8211; z Ajaxa. Podobnie jest z różnorodnymi wtyczkami do systemu blogów <a target="_blank" href="http://wordpress.org/"  title="WordPress">WordPress</a>. Z reguły korzystają one jednak z jakiejś biblioteki JavaScript zbierającej w całość jego najważniejsze funkcje i pozwalającej na ich prostsze użycie. W momencie jednak, kiedy w naszych pluginach pojawi się w użyciu kilka wtyczek możemy napotkać problem kolizji ich współdziałania.</p>
<p><span id="more-96"></span></p>
<h2>Prolog!</h2>
<p>Zanim zacznę muszę wspomnieć, że kolizja opisywana poniżej może występować na jakiejkolwiek stronie, a opisywana przeze mnie sytuacja jest tylko przykładem. Nie mniej jednak mankament ten postaram się wytłumaczyć na podstawie jednoczesnego działania <a target="_blank" href="http://utnij.eu/ajax-comments/"  title="WP Ajax Comments">AJAX Comments</a> i przystosowanej do personalnych potrzeb modyfikacji zakładek (przykładem są te umieszczone z lewej strony tego wpisu). Pierwsza wtyczka domyślnie używa <a target="_blank" href="http://script.aculo.us/"  title="Script.Aculo.Us">Script.Aculo.Us</a>, a co za tym idzie także frameworku <a target="_blank" href="http://www.prototypejs.org/"  title="Prototype">Prototype</a>. W drugim wypadku oprę się o <a target="_blank" href="http://vivee.info/2008/08/05/zakladki-do-sidebara/"  title="Zakładki do Sidebara">kurs tworzenia zakładek</a> w WP <strong>palmiaka</strong>, który używa za to <a target="_blank" href="http://jquery.com/"  title="jQuery">jQuery</a>.</p>
<p>Po poprawnej instalacji obydwu modyfikacji pewnie spora część z Was nie dostrzeże dręczącego nas feleru. Dlaczego? Gdyż na stronie głównej wszystko będzie działało prawidłowo, ale bynajmniej nie na podstronach w których będzie możliwe komentowanie wpisów. Dla przykładu w momencie wczytania najpierw <strong>prototype.js</strong> i <strong>scriptaculous.js</strong>, a później <strong>jquery.js</strong> stworzone przez nas zakładki nie będą poprawnie działać (nie zostaną one ukryte i nie będzie możliwości przejścia pomiędzy nimi). Dlaczego tak się dzieje? Tutaj należałoby poruszyć pewną sprawę dotyczącą samego działania frameworków tego typu.</p>
<h2>Funkcja $(argumenty)</h2>
<p>Między innymi do tworzenia obiektu danej biblioteki używa się funkcji <code>$(argumenty);</code>. Dzięki temu operujące np. na obiektach DOM, czy tablicach frameworki dzięki tej specjalnej konstrukcji pozwalają użytkownikowi na wykorzystywanie ich konkretnych funkcji.</p>
<p style="text-align: center;"><a target="_blank" href="http://farm4.static.flickr.com/3155/2905203185_36c209390b_o.png"  title="Powiększenie" class="lightbox"><img src="http://farm4.static.flickr.com/3155/2905203185_1e8236bb72.jpg" alt="Różnorodne metody korzystania z elementów strony" /></a></p>
<h2>Problematyka korzystania z więcej niż jednej biblioteki naraz&#8230;</h2>
<p>W momencie kiedy w skrypcie korzystamy z dwóch lub większej ilości frameworków może nastąpić kolizja w ich działaniu. W uproszczeniu przez użycie <code>$();</code> w każdej z nich. I tak to w naszym przykładzie funkcje, czy odwołania do obiektów które powinny być wykonane za pomocą <strong>jQuery</strong> zostaną wykonane przez pierwszą wczytaną klasę. A wszystko przez to, że każda z podanych bibliotek odwołuje się do danego elementu w taki sam sposób.</p>
<h2>Solucja!</h2>
<p>Na szczęście od wersji <strong>1.1.4</strong> z pomocą przychodzą nam developerzy <strong>jQuery</strong> wraz z funkcją pozwalającą na interoperacyjność &#8211; <code>jQuery.noConflict(param);</code>.</p>
<pre class="brush: jscript;">jQuery.noConflict(); // zwraca kontrolę nad $ bibliotece domyślnej (wcześniej używanej)
jQuery.noConflict(true); // zwraca kontrolę nad $ i jQuery (którego $ jest aliasem) oryginalnemu właścicielowi - należy używać z ostrożnością!</pre>
<p>Co należy wiedzieć w kwestii używania tego to przede wszystkim fakt, że wymaga się, aby powyższą funkcję wywołać przed użyciem elementów innych bibliotek, a także <strong>jQuery</strong> powinno być wczytywane po pozostałych frameworkach. W konkretnym wypadku związanym z WP który opisujemy należy także domyślnie dostarczone niżej wymienione biblioteki uaktualnić. Niestety w opisywanych tutaj wtyczkach i systemie blogów są to wersje starsze i przedstawiony trick w tym artykule nie zadziała dopóki nie ściągniemy zaktualizowanych wersji frameworków.</p>
<pre class="brush: jscript;">&lt;script type=&quot;text/javascript&quot; src=&quot;libs/prototype.js&quot; /&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;libs/scriptaculous.js&quot; /&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;libs/jquery.js&quot; /&gt;</pre>
<p>Domyślnie także należy używać w tym trybie <strong>jQuery</strong> zamiast <strong>$</strong>.</p>
<pre class="brush: jscript;">jQuery.noConflict();
jQuery(&quot;p&quot;).hide(); // użycie frameworka jQuery
$(&quot;div&quot;).style.display = 'none'; // użycie innego frameworka, np. prototype</pre>
<p>Ponieważ oczywiście zaprezentowana funkcja jest podatna na przypisywanie do zmiennych to niekoniecznie musimy używać standardowej, dłuższej nazwy. Negatywem tego rozwiązania jest jednak potencjalny konflikt nazw w przypadku pisania aplikacji internetowej przez wielu programistów.</p>
<pre class="brush: jscript;">var q = jQuery.noConflict();
q(&quot;p&quot;).hide();
$(&quot;div&quot;).style.display = 'none';</pre>
<p>Ostatecznie moglibyście także spytać <strong>&#8220;co zrobić, aby móc wewnątrz bloku kodu używać $ dla jQuery?&#8221;</strong>. Wystarczy poprzedzić zadaną funkcję przez <code>jQuery</code>, bądź zakończyć poprzez <code>(jQuery)</code>.</p>
<pre class="brush: jscript;">jQuery(function($) { [...] }); // wersja pierwsza
(function($) { [...] })(jQuery); // wersja druga</pre>
<p>Niestety w takim wypadku wewnątrz powyższych bloków kodu nie ma możliwości odniesienia się do obiektów innych bibliotek.</p>
<h2>Przykład pozwalający na prawidłowe działanie wspomnianych zakładek&#8230;</h2>
<p>Poprawiony przykład z <strong>vivee</strong>, który należy użyć w wypadku w.w. konfliktu (kod JavaScript).</p>
<pre class="brush: jscript;">jQuery.noConflict();

function tabs(id) {
	jQuery(&quot;#&quot;+id+&quot; h2:first a&quot;).addClass(&quot;active&quot;);
    jQuery(&quot;#&quot;+id+&quot; div&quot;).not(&quot;:first&quot;).hide();

    jQuery(&quot;#&quot;+id+&quot; h2 a&quot;).click(function() {
    	var licznik = jQuery(&quot;#&quot;+id+&quot; h2 *&quot;).index(this);                                             

        jQuery(&quot;#&quot;+id+&quot; h2 a&quot;).removeClass(&quot;active&quot;);
        jQuery(this).addClass(&quot;active&quot;);
        jQuery(&quot;#&quot;+id+&quot; div:visible&quot;).hide();

        jQuery(&quot;#&quot;+id+&quot; div&quot;).eq(licznik).show();
        return false;
    });
}

jQuery(document).ready(function(){
    tabs(&quot;zakladki&quot;);
});</pre>
<h2>Epilog&#8230;</h2>
<p><strong>WPNinja</strong> na swoim blogu poświęconym WordPressowi prawidłowo stwierdził w stosunku do mojej osoby, że mieszanie bibliotek nie jest dobrym zwyczajem.</p>
<pre class="brush: plain;">&quot;@m1chu,
Mieszanie ze sobą bibliotek to masakra. Nie dość, że zajmuje to niemiłosiernie dużo miejsca to, jak zauważyłeś w swoim artykule, może powodować konflikty.&quot;</pre>
<p>Opisany przeze mnie artykuł powinien być stosowany tylko w wyjątkowych sytuacjach. Należy z reguły <strong>unikać</strong> użytkowania kilku frameworków naraz, bo to obciąża w znacznym stopniu skrypt poprzez ich wagę, a co za tym idzie ilością danych do załadowania. Zdaję sobie jednak sprawę, że niekiedy jest to niezmiernie trudne (czego jak na razie w fazie rozwojowej przykładem jest mój blog ;]). Podziękowania za przypomnienie dla <strong>WPNinja&#8217;y</strong> o tym, że zapomniałem tak ważnego faktu umieścić w swoich wpisie.</p>
]]></content:encoded>
			<wfw:commentRss>http://m1chu.eu/2008/10/02/kolizje-wspoldzialania-bibliotek-javascript-na-podstawie-wtyczek-wordpress/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>
