<?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; Webmastering</title>
	<atom:link href="http://m1chu.eu/category/webmastering/feed/" rel="self" type="application/rss+xml" />
	<link>http://m1chu.eu</link>
	<description>we live, as we dream... alone - another devblog</description>
	<lastBuildDate>Sun, 14 Nov 2010 11:07:18 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.4</generator>
		<item>
		<title>Szybka porada: jak zmusić Internet Explorer 8 i Firefox 2 do obsługi HTML 5? (#1)</title>
		<link>http://m1chu.eu/2010/08/24/szybka-porada-jak-zmusic-internet-explorer-8-i-firefox-2-do-obslugi-html-5-1/</link>
		<comments>http://m1chu.eu/2010/08/24/szybka-porada-jak-zmusic-internet-explorer-8-i-firefox-2-do-obslugi-html-5-1/#comments</comments>
		<pubDate>Tue, 24 Aug 2010 20:38:47 +0000</pubDate>
		<dc:creator>m1chu</dc:creator>
				<category><![CDATA[(x)HTML]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[Pozostałe]]></category>
		<category><![CDATA[Szybka porada]]></category>
		<category><![CDATA[Webhosting]]></category>
		<category><![CDATA[createelement]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[firefox 2]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[html5]]></category>
		<category><![CDATA[internet explorer]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[porada]]></category>
		<category><![CDATA[shiv]]></category>
		<category><![CDATA[xml]]></category>

		<guid isPermaLink="false">http://m1chu.eu/?p=1825</guid>
		<description><![CDATA[Sieć została ogarnięta szałem najnowszej, piątej wersji języka HTML. Jak to zazwyczaj bywa słabo z jej obsługą radzi sobie Internet Explorer. We wszystkich wydanych wersjach pojawia się problem z parsowaniem elementów języka HTML 5, a co za tym idzie nie ma domyślnie możliwości ich poprawnego ostylowania. Podobny problem w przeszłości występował w Firefoksie 2. Zarys [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: center;"><img class="iborder" src="http://images.m1chu.eu/index.php?res=MjJfMDhfMTBfcXVpY2tfaGludF9pZThfYW5kX2h0bWw1O3F1aWNrX2hpbnRfaWU4X2FuZF9odG1sNV9wb3N0X2hlYWRlci5wbmc=" alt="Jak zmusić Internet Explorer 8 do obsługi HTML 5?" style="height: 119px;" /></p>
<p>Sieć została ogarnięta szałem najnowszej, <a href="http://m1chu.eu/2010/03/19/html5-obsluga-elementow-audio-i-video/" >piątej wersji języka HTML</a>. Jak to zazwyczaj bywa słabo z jej obsługą radzi sobie Internet Explorer. We wszystkich wydanych wersjach pojawia się problem z parsowaniem elementów języka HTML 5, a co za tym idzie nie ma domyślnie możliwości ich poprawnego ostylowania. Podobny problem w przeszłości występował w Firefoksie 2.</p>
<p><span id="more-1825"></span></p>
<h2>Zarys problemu</h2>
<p>Załóżmy więc, że tworzymy nowy projekt i jesteśmy na etapie dodawania nagłówka oraz stopki dokumentu.</p>
<pre class="brush: xml; title: ;">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
    &lt;meta charset=&quot;utf-8&quot;&gt;
    &lt;title&gt;Obsługa HTML 5 z CSS&lt;/title&gt;
    &lt;style&gt;
    body { text-align: center; margin: 0; padding: 0; font-family: Tahoma, Verdana, Arial; font-size: 11px; }
    header { font-style: italic; width: 770px; height: 70px; padding: 15px; margin: 5px auto; background-color: #FC0; text-align: left; }
    footer { font-weight: bold; clear: both; width: 770px; height: 15px; padding: 15px; margin: 5px auto; background-color: #FC0; text-align: left; }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;header&gt;Nagłówek&lt;/header&gt;
    &lt;footer&gt;Stopka&lt;/footer&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
<p>Nadaliśmy powyżej kilka atrybutów stylów pozycjonujących elementy oraz nadających im odpowiedni wygląd. Po przetestowaniu w Internet Explorerze i alternatywnych przeglądarkach zobaczymy jednak różne wyniki.</p>
<p style="text-align: center; font-size: 10px;"><img class="iborder" src="http://images.m1chu.eu/index.php?res=MjJfMDhfMTBfcXVpY2tfaGludF9pZThfYW5kX2h0bWw1O3F1aWNrX2hpbnRfaWU4X2FuZF9odG1sNV8wMl9meDQucG5n" alt="Wynik w Firefoksie 4" style="height: 298px;" /><br />Wynik w Firefoksie 4.</p>
<p style="text-align: center; font-size: 10px;"><img class="iborder" src="http://images.m1chu.eu/index.php?res=MjJfMDhfMTBfcXVpY2tfaGludF9pZThfYW5kX2h0bWw1O3F1aWNrX2hpbnRfaWU4X2FuZF9odG1sNV8wMV9pZTgucG5n" alt="Wynik w Internet Explorerze 8" style="height: 298px;" /><br />Wynik w Internet Explorerze 8.</p>
<h2>Internet Explorer &#8211; rozwiązanie pierwsze</h2>
<p>Aby pozbyć się tego problemu należy do sekcji <code>head</code> wstawić:</p>
<pre class="brush: xml; title: ;">&lt;script&gt;
document.createElement('header');
document.createElement('footer');
&lt;/script&gt;</pre>
<h2>Internet Explorer &#8211; rozwiązanie drugie</h2>
<p>Dla każdej wersji Internet Explorera można także dodać do dokumentu HTML (w sekcję <code>head</code>) zewnętrzny kod JavaScript, dzięki któremu osiągniemy wyżej opisany skutek.</p>
<pre class="brush: xml; title: ;">&lt;!--[if IE lt 9]&gt;
  &lt;script src=&quot;http://html5shiv.googlecode.com/svn/trunk/html5.js&quot;&gt;&lt;/script&gt;
&lt;![endif]--&gt;</pre>
<h2>Firefox 2</h2>
<p>Niespełna jeden procent internautów nadal używa drugiej odsłony popularnego lisa. Zarówno on, jak i wszystkie przeglądarki oparte na silniku Gecko pre 1.9b5 (np. <a target="_blank" href="http://caminobrowser.org/" >Camino</a> 1.x) posiadają <a target="_blank" href="http://blog.whatwg.org/supporting-new-elements-in-firefox-2" >błąd parsowania</a> dzięki któremu w przypadku otwarcia nowego znacznika każdy nieznany, wcześniej otwarty zostanie automatycznie zamknięty.</p>
<p>Rozważmy więc przykładowy kod.</p>
<pre class="brush: xml; title: ;">&lt;body&gt;
    &lt;header&gt;&lt;h1&gt;Nagłówek&lt;/h1&gt;&lt;/header&gt;
    &lt;footer&gt;
        &lt;p&gt;&lt;strong&gt;S&lt;/strong&gt;topka&lt;/p&gt;
    &lt;/footer&gt;
&lt;/body&gt;</pre>
<p>Przeglądarki oparte na omawianej wersji silnika Gecko przeparsują go w następujący sposób:</p>
<pre class="brush: xml; title: ;">&lt;body&gt;
    &lt;header&gt;&lt;/header&gt;&lt;h1&gt;Nagłówek&lt;/h1&gt;
    &lt;footer&gt;&lt;/footer&gt;&lt;p&gt;&lt;strong&gt;S&lt;/strong&gt;topka&lt;/p&gt;
&lt;/body&gt;</pre>
<p>Aby rozpocząć modyfikacje należy wykonać <a target="_blank" href="http://remysharp.com/2009/04/14/html5-and-firefox2/" >dwie rzeczy</a>:</p>
<ol>
<li>Wykonać przekierowanie przykładowo za pomocą <code>mod_rewrite</code> lub PHP tak, aby Firefox 2 uważał analizowany dokument jako XHTML
<ul>
<li>
<pre class="brush: plain; title: ;">RewriteCond %{REQUEST_URI} \.html$
RewriteCond %{HTTP_USER_AGENT} rv:1\.(([1-8]|9pre|9a|9b[0-4])\.[0-9.]+).*Gecko
RewriteRule .* - [T=application/xhtml+xml]</pre>
</li>
<li>
<pre class="brush: php; title: ;">if (preg_match('/rv:1\.(([1-8]|9pre|9a|9b[0-4])\.[0-9.]+).*Gecko/', $_SERVER['HTTP_USER_AGENT'])) {
  header('Content-type: application/xhtml+xml');
}</pre>
</li>
</ul>
</li>
<li>Dodać atrybut <code>xmlns</code> do znacznika <code>html</code>
<pre class="brush: xml; title: ;">&lt;html lang=&quot;pl&quot; xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;</pre>
</li>
</ol>
<p>W tym wypadku należy jednak pamiętać o tym, że XML jest wrażliwy na encje HTML-owe. Przykładowo więc używanie <code>&#038;</code><code>sdot;</code> należy zaniechać na rzecz <code>&#038;</code><code>#8901;</code>.</p>
<h2>Następnym razem dowiecie się&#8230;</h2>
<p>jak stworzyć wielokolumnową treść w CSS3?</p>
]]></content:encoded>
			<wfw:commentRss>http://m1chu.eu/2010/08/24/szybka-porada-jak-zmusic-internet-explorer-8-i-firefox-2-do-obslugi-html-5-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>HTML 5: obsługa elementów AUDIO i VIDEO</title>
		<link>http://m1chu.eu/2010/03/19/html5-obsluga-elementow-audio-i-video/</link>
		<comments>http://m1chu.eu/2010/03/19/html5-obsluga-elementow-audio-i-video/#comments</comments>
		<pubDate>Fri, 19 Mar 2010 21:14:33 +0000</pubDate>
		<dc:creator>m1chu</dc:creator>
				<category><![CDATA[(x)HTML]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Webhosting]]></category>
		<category><![CDATA[audio]]></category>
		<category><![CDATA[chrome]]></category>
		<category><![CDATA[elementy]]></category>
		<category><![CDATA[firefox]]></category>
		<category><![CDATA[flash]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[html 5]]></category>
		<category><![CDATA[natywnie]]></category>
		<category><![CDATA[object]]></category>
		<category><![CDATA[opera]]></category>
		<category><![CDATA[safari]]></category>
		<category><![CDATA[tagi]]></category>
		<category><![CDATA[video]]></category>

		<guid isPermaLink="false">http://m1chu.eu/?p=1752</guid>
		<description><![CDATA[Serwisów oferujących przeglądanie zasobów multimedialnych nie brakuje w sieci. Do niedawna jednak wszystkie oparte były o wykorzystanie możliwości znaczników object lub niepoprawnego embed. Problem w tym, że rozwiązania te opierały się o wtyczki firm trzecich, takie jak QuickTime, czy Flash. HTML 5 standaryzuje osadzanie plików muzycznych i filmów. Kwestia dźwiękowa: element AUDIO Jedna z najbardziej, [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: center;"><img class="iborder" src="http://images.m1chu.eu/index.php?res=MTlfMDNfMTBfaHRtbDVfYXVkaW9fdmlkZW87aHRtbDVfYXVkaW9fdmlkZW9fcG9zdF9oZWFkZXIucG5n" alt="HTML5: obsługa elementów AUDIO i VIDEO" style="height: 119px;" /></p>
<p>Serwisów oferujących przeglądanie zasobów multimedialnych nie brakuje w sieci. Do niedawna jednak wszystkie oparte były o wykorzystanie możliwości znaczników <code><a href="http://m1chu.eu/2008/12/14/jak-poprawnie-osadzic-flasha-w-kodzie-xhtml-strony/"  title="Jak poprawnie osadzić Flasha w kodzie (x)HTML strony?">object</a></code> lub niepoprawnego <code>embed</code>. Problem w tym, że rozwiązania te opierały się o wtyczki firm trzecich, takie jak QuickTime, czy Flash. HTML 5 standaryzuje osadzanie plików muzycznych i filmów.</p>
<p><span id="more-1752"></span></p>
<h2>Kwestia dźwiękowa: element AUDIO</h2>
<p>Jedna z najbardziej, od dawna oczekiwanych możliwości w HTML 5. Pozwala na natywne odtwarzanie utworów muzycznych w przeglądarce. Określana znacznikiem <code><a target="_blank" href="http://utnij.eu/html5_audio/"  title="Specyfikacja: audio">audio</a></code>.</p>
<p>Wg. specyfikacji może przyjmować pięć atrybutów:</p>
<ul>
<li><code><a target="_blank" href="http://utnij.eu/html5_video_autoplay/"  title="Specyfikacja: autoplay">autoplay</a></code> &#8211; określa czy odtwarzać automatycznie dźwięk, gdy zostanie on załadowany,</li>
<li><code><a target="_blank" href="http://utnij.eu/html5_video_controls/"  title="Specyfikacja: controls">controls</a></code> &#8211; określa czy wyświetlić odtwarzacz w standardowym układzie,</li>
<li><code><a target="_blank" href="http://utnij.eu/html5_video_loop/"  title="Specyfikacja: loop">loop</a></code> &#8211; określa czy powtarzać odtwarzanie,</li>
<li><code><a target="_blank" href="http://utnij.eu/html5_video_preload/"  title="Specyfikacja: preload">preload</a></code> &#8211; wyznacza, czy załadować zasobów w trakcie ładowania strony,</li>
<li><code><a target="_blank" href="http://utnij.eu/html5_src/"  title="Specyfikacja: src">src</a></code> &#8211; adres URL do pierwotnego, ładowanego źródła.</li>
</ul>
<p>Korzystając z powyższych informacji możemy otrzymać następujący przykład:</p>
<pre class="brush: xml; title: ;">&lt;!-- domyślny układ, startuje automatycznie, jedno źródło --&gt;
&lt;audio src=&quot;test.ogg&quot; controls autoplay&gt;&lt;/audio&gt;</pre>
<p>W praktyce pojawi się jednak problem, związany z implementacją różnych wersji kodeków w przeglądarkach (np. Vorbis, Advanced Audio Coding, MPEG-1 Audio Layer 3). Z tego powodu, trzeba aktualnie definiować dodatkowe zasoby w tagu <code><a target="_blank" href="http://utnij.eu/html5_source/"  title="Specyfikacja: source">source</a></code>. Obsługuje on atrybuty:</p>
<ul>
<li><code><a target="_blank" href="http://utnij.eu/html5_media/"  title="Specyfikacja: media">media</a></code> &#8211; zdefiniowanie typu zasobu. Domyślnie odpowiada wszystkim typom mediów,</li>
<li><code><a target="_blank" href="http://utnij.eu/html5_src/"  title="Specyfikacja: src">src</a></code> &#8211; adres URL do pierwotnego, ładowanego źródła,</li>
<li><code><a target="_blank" href="http://utnij.eu/html5_type/"  title="Specyfikacja: type">type</a></code> &#8211; definiuje typ zasobu, pozwalając na określenie przeglądarce, czy może odtworzyć go, bez konieczności pobierania. Musi być pod postacią prawidłowego <a target="_blank" href="http://utnij.eu/valid-mime-type/"  title="Specyfikacja: typy MIME">typu MIME</a>. Opcjonalnie, wewnątrz niego można zdefiniować parametr <code>codecs</code>, określający jak zakodowany jest zasób.</li>
</ul>
<pre class="brush: xml; title: ;">&lt;!-- domyślny układ, startuje automatycznie, wiele źródeł --&gt;
&lt;audio controls autoplay&gt;
	&lt;!-- Firefox ge 3.5, Chrome ge 3 beta, Opera ge 10.5 --&gt;
	&lt;source src=&quot;test.ogg&quot; type=&quot;audio/ogg; codecs=vorbis&quot;&gt;
	&lt;!-- Safari ge 4, Chrome ge 3 beta --&gt;
	&lt;source src=&quot;test.mp3&quot;&gt;
	&lt;!-- Opera ge 10.5, Firefox ge 3.5 --&gt;
	&lt;source src=&quot;test.wav&quot;&gt;
&lt;/audio&gt;</pre>
<p>Na wypadek niekompatybilnej przeglądarki można wewnątrz elementu <code>audio</code> wstawić alternatywną wiadomość, bądź <a href="http://m1chu.eu/2008/12/14/jak-poprawnie-osadzic-flasha-w-kodzie-xhtml-strony/"  title="Jak poprawnie osadzić Flasha w kodzie (x)HTML strony?">plik Flash</a> z autorskim odtwarzaczem.</p>
<pre class="brush: xml; title: ;">&lt;!-- domyślny układ, startuje automatycznie, wiele źródeł --&gt;
&lt;audio controls autoplay&gt;
	&lt;!-- Firefox ge 3.5, Chrome ge 3 beta, Opera ge 10.5 --&gt;
	&lt;source src=&quot;test.ogg&quot; type=&quot;audio/ogg; codecs=vorbis&quot;&gt;
	&lt;!-- Safari ge 4, Chrome ge 3 beta --&gt;
	&lt;source src=&quot;test.mp3&quot;&gt;
	&lt;!-- Opera ge 10.5, Firefox ge 3.5 --&gt;
	&lt;source src=&quot;test.wav&quot;&gt;
	&lt;!-- alternatywny wynik --&gt;
	Twoja przeglądarka nie obsługuje HTML 5.
&lt;/audio&gt;</pre>
<p>W rozwiązaniu powyższego problemu pomóc może także użycie możliwości JavaScriptu i metod/atrybutów/zdarzeń dostępnych w API. Pozwalają one na manipulację na obsługiwanych plikach. Niestety skorzystanie z możliwości obiektu <code>Audio</code> nie będzie możliwe w jakiejkolwiek wersji IE.</p>
<ul>
<li><code><a target="_blank" href="http://utnij.eu/html5_buffered/"  title="Specyfikacja: buffered">buffered</a></code> &#8211; określa ilość oraz początkowy i końcowy czas zbuforowanego zasobu,</li>
<li><code><a target="_blank" href="http://utnij.eu/html5_canplaytype/"  title="Specyfikacja: canPlayType()">canPlayType(typ_MIME)</a></code> &#8211; zwraca informacje na temat tego, czy dany typ obsługiwany jest przez klienta. Możliwe wyniki to: <em>no</em>, <em>maybe</em>, <em>probably</em>,</li>
<li><code><a target="_blank" href="http://utnij.eu/html5_currenttime/"  title="Specyfikacja: currentTime">currentTime</a></code> &#8211; pozwala na ustawienie lub pobranie aktualnego czasu odtwarzania,</li>
<li><code><a target="_blank" href="http://utnij.eu/html5_duration/"  title="Specyfikacja: duration">duration</a></code> &#8211; wyświetla czas trwania utworu. W wypadku nie załadowania go, zwraca <strong>NaN</strong> (Not a Number),</li>
<li><code><a target="_blank" href="http://utnij.eu/html5_ended/"  title="Specyfikacja: ended">ended</a></code> &#8211; zwraca prawdę, jeżeli zakończono odtwarzanie (w przód),</li>
<li><code><a target="_blank" href="http://utnij.eu/html5_loop/"  title="Specyfikacja: loop">loop</a></code> &#8211; wartość logiczna, pozwalająca na zapętlanie dźwięku,</li>
<li><code><a target="_blank" href="http://utnij.eu/html5_muted/"  title="Specyfikacja: muted">muted</a></code> &#8211; zwraca lub ustawia, czy kanały audio są wyciszone,</li>
<li><code><a target="_blank" href="http://utnij.eu/html5_pause/"  title="Specyfikacja: pause()">pause()</a></code> &#8211; pauzuje odtwarzanie,</li>
<li><code><a target="_blank" href="http://utnij.eu/html5_paused/"  title="Specyfikacja: paused">paused</a></code> &#8211; przetrzymuje informacje o tym, czy element jest spauzowany,</li>
<li><code><a target="_blank" href="http://utnij.eu/html5_play/"  title="Specyfikacja: play()">play()</a></code> &#8211; wznawia odtwarzanie,</li>
<li><code><a target="_blank" href="http://utnij.eu/html5_played/"  title="Specyfikacja: played">played</a></code> &#8211; przetrzymuje informacje o odtwarzanym elemencie,</li>
<li><code><a target="_blank" href="http://utnij.eu/html5_volume/"  title="Specyfikacja: volume">volume</a></code> &#8211; zwraca lub ustawia głośność dźwięku w zakresie od 0.0&#8230;0.1.</li>
</ul>
<p>Przykład:</p>
<pre class="brush: xml; title: ;">&lt;p&gt;
	&lt;button type=&quot;button&quot; onclick=&quot;stop();&quot;&gt;Stop&lt;/button&gt;
	&lt;button type=&quot;button&quot; onclick=&quot;lour();&quot;&gt;Wycisz&lt;/button&gt;
&lt;/p&gt;</pre>
<pre class="brush: jscript; title: ;">&lt;script type=&quot;text/javascript&quot;&gt;
var element = document.getElementById(&quot;audio&quot;); /* pobranie elementu */
function stop() { /* funkcja zatrzymująca */
	if ( !!(element.canPlayType) != false ) {
		element.currentTime = 0; /* ustawienie czasu na początek */
		element.pause(); /* pauza */
	}
}
function lour() { /* funkcja wyciszająca */
	if ( !!(element.canPlayType) != false ) {
		element.volume = 0; /* głośność na zero */
	}
}
&lt;/script&gt;</pre>
<p>Przykład z użyciem <code>new Audio()</code>:</p>
<pre class="brush: jscript; title: ;">var obj = new Audio('');
alert(!!(obj.canPlayType));</pre>
<h2>Kwestia filmowa: element VIDEO</h2>
<p>Drugi, ważny element HTML 5. Oparty o znacznik <code><a target="_blank" href="http://utnij.eu/html5_video/"  title="Specyfikacja: video">video</a></code>. Przyjmuje te same atrybuty co <code>audio</code>, a ponadto:</p>
<ul>
<li><code><a target="_blank" href="http://utnij.eu/html5_height/"  title="Specyfikacja: height">height</a></code> &#8211; określa wysokość okna playera,</li>
<li><code><a target="_blank" href="http://utnij.eu/html5_poster/"  title="Specyfikacja: poster">poster</a></code> &#8211; adres URL alternatywnej grafiki, wyświetlanej jeżeli domyślny zasób nie będzie dostępny,</li>
<li><code><a target="_blank" href="http://utnij.eu/html5_width/"  title="Specyfikacja: width">width</a></code> &#8211; określa szerokość okna odtwarzacza.</li>
</ul>
<p>Tak oto możemy stworzyć podstawowy przykład użycia:</p>
<pre class="brush: xml; title: ;">&lt;!-- buforowanie zasobu w trakcie ładowania strony, jeden plik --&gt;
&lt;video src=&quot;test.mp4&quot; preload&gt;&lt;/video&gt;</pre>
<p>Ponownie, w praktyce, powinno się zdefiniować kilka, różnych źródeł plików, w celu obsługi odtwarzacza przez większą ilość przeglądarek.</p>
<pre class="brush: xml; title: ;">&lt;!-- domyślny układ, buforuje przy ładowaniu, wiele źródeł --&gt;
&lt;video controls preload&gt;
	&lt;!-- Firefox ge 3.5, Chrome ge 3 beta, Opera ge 10.5 --&gt;
	&lt;source src=&quot;test.ogv&quot; type=&quot;audio/ogg; codecs='theora, vorbis'&quot;&gt;
	&lt;!-- Safari ge 4, Chrome ge 3 beta --&gt;
	&lt;source src=&quot;test.mp4&quot; type=&quot;video/mp4; codecs='avc1.42E01E, mp4a.40.2'&quot;&gt;
	&lt;!-- mobilne --&gt;
	&lt;source src=&quot;video.3gp&quot; type=&quot;video/3gpp; codecs='mp4v.20.8, samr'&quot;&gt;
	&lt;!-- alternatywny wynik --&gt;
	Twoja przeglądarka nie obsługuje HTML 5.
&lt;/video&gt;</pre>
<p style="text-align: center; font-size: 10px;"><video controls style="width: 480px; height: 320px;" poster="http://farm5.static.flickr.com/4019/4447584693_278f64dba5_o.png"><source src="http://osaddict.com/files/elephantsdream-480-h264-st-aac.mov" /><source src="http://mirrorblender.top-ix.org/peach/bigbuckbunny_movies/big_buck_bunny_480p_stereo.ogg" /><img src="http://farm5.static.flickr.com/4019/4447584693_278f64dba5_o.png" alt="Znacznik video nieobsługiwany" /></video><br />W odtwarzaczu wyświetlane są dwa filmy (Elephants Dream, Big Buck Bunny) na licencji zezwalającej na rozprowadzanie kopii w trybie online.</p>
<h2>Obróbka</h2>
<p>Zarówno w przypadku jednego, jak i drugiego elementu możemy je stylować.</p>
<pre class="brush: css; title: ;">audio, video {
	width: 480px;
	height: 320px;
}</pre>
<h2>Kompatybilność</h2>
<table class="article_table">
<thead>
<tr>
<th>Kodek (kontener)</th>
<th>Android</th>
<th>Chrome >= 3.0</th>
<th>Firefox >= 3.5</th>
<th>Iphone</th>
<th>Opera >= 10.5</th>
<th>Safari >= 4</th>
</tr>
</thead>
<tbody>
<tr>
<td class="t_sm">Theora video (Ogg/.ogv)</td>
<td>x</td>
<td>✓</td>
<td>✓</td>
<td>x</td>
<td>✓</td>
<td>x</td>
</tr>
<tr>
<td class="t_sm">Vorbis audio (Ogg/.ogg)</td>
<td>x</td>
<td>✓</td>
<td>✓</td>
<td>x</td>
<td>✓</td>
<td>x</td>
</tr>
<tr>
<td class="t_sm">H.264 video (MP4/.mp4)</td>
<td>✓</td>
<td>✓</td>
<td>x</td>
<td>✓</td>
<td>x</td>
<td>✓</td>
</tr>
<tr>
<td class="t_sm">AAC audio (MP4/.mp3)</td>
<td>✓</td>
<td>✓</td>
<td>x</td>
<td>✓</td>
<td>x</td>
<td>✓</td>
</tr>
<tr>
<td class="t_sm">WAV audio (WAV/.wav)</td>
<td>-</td>
<td>-</td>
<td>✓</td>
<td>-</td>
<td>✓</td>
<td>✓</td>
</tr>
</tbody>
</table>
]]></content:encoded>
			<wfw:commentRss>http://m1chu.eu/2010/03/19/html5-obsluga-elementow-audio-i-video/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
<enclosure url="http://osaddict.com/files/elephantsdream-480-h264-st-aac.mov" length="103636531" type="video/quicktime" />
		</item>
		<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 [...]]]></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; title: ;">/* metoda */
jQuery.fn.nazwa = function() {
	[...]
};</pre>
<pre class="brush: jscript; title: ;">/* 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; title: ;">/* wywołanie: metoda */
$(element).nazwa();</pre>
<pre class="brush: jscript; title: ;">/* 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; title: ;">/* metoda z parametrem */
jQuery.fn.nazwa = function(options) {
	[...]
};</pre>
<pre class="brush: jscript; title: ;">/* 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; title: ;">&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; title: ;">$('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; title: ;">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; title: ;">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; title: ;">$('#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; title: ;">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; title: ;">// 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; title: ;">(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; title: ;">[...]
        &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; title: ;">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; title: ;">[...]
    	&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; title: ;">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; title: ;">	// 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; title: ;">(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>15 przydatnych wyrażeń regularnych w PHP</title>
		<link>http://m1chu.eu/2009/10/13/15-przydatnych-wyrazen-regularnych-w-php/</link>
		<comments>http://m1chu.eu/2009/10/13/15-przydatnych-wyrazen-regularnych-w-php/#comments</comments>
		<pubDate>Tue, 13 Oct 2009 20:23:51 +0000</pubDate>
		<dc:creator>m1chu</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Webhosting]]></category>
		<category><![CDATA[Świat IT]]></category>
		<category><![CDATA[e-mail]]></category>
		<category><![CDATA[pear]]></category>
		<category><![CDATA[perl]]></category>
		<category><![CDATA[regexp]]></category>
		<category><![CDATA[regexp.pl]]></category>
		<category><![CDATA[url]]></category>
		<category><![CDATA[wyrażenia regularne]]></category>
		<category><![CDATA[wzorzec]]></category>

		<guid isPermaLink="false">http://m1chu.eu/?p=1536</guid>
		<description><![CDATA[W pewnym stadium zaawansowania wyrażenia regularne stają się potężnym narzędziem każdego programisty PHP (i nie tylko). A to dlatego, że pozwalają na wykonywanie operacji, których często nie sposób dokonać w prosty sposób przy pomocy standardowych funkcji zawartych w tym języku. Walidacja zawartości zmiennych, czy podmienianie specyficznej części ich zawartości &#8211; na to pozwalają wyrażenia regularne. [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: center;"><img class="iborder" src="http://images.m1chu.eu/index.php?res=MTNfMDlfMDlfMTVfcmVnZXhwczsxNV9yZWdleHBzX3Bvc3RfaGVhZGVyLnBuZw==" alt="Gotowe wyrażenia regularne" style="height: 119px;" /></p>
<p>W pewnym stadium zaawansowania wyrażenia regularne stają się potężnym narzędziem każdego programisty PHP (i nie tylko). A to dlatego, że pozwalają na wykonywanie operacji, których często nie sposób dokonać w prosty sposób przy pomocy standardowych funkcji zawartych w tym języku. Walidacja zawartości zmiennych, czy podmienianie specyficznej części ich zawartości &#8211; na to pozwalają wyrażenia regularne. 15-ście przykładowych, najbardziej niezbędnych dla każdego web developera, skompletowałem w dalszej części artykułu. Do Waszej dyspozycji oddaję także prosty <a target="_blank" href="http://regexp.pl/"  title="regexp.pl - tester wyrażeń regularnych"><strong>serwis</strong></a> sprawdzający poprawność wprowadzanych wzorców.</p>
<p><span id="more-1536"></span></p>
<h2>1. Walidacja adresu e-mail opartego na hoście</h2>
<h3>Wzorzec:</h3>
<pre class="brush: plain; title: ;">/^([a-z0-9]{1})([^\s\t\.@]*)((\.[^\s\t\.@]+)*)@([a-z0-9]{1})((([a-z0-9-]*[-]{2})|([a-z0-9])*|([a-z0-9-]*[-]{1}[a-z0-9]+))*)((\.[a-z0-9](([a-z0-9-]*[-]{2})|([a-z0-9]*)|([a-z0-9-]*[-]{1}[a-z0-9]+))+)*)\.([a-z0-9]{2,6})([.]?)$/Diu</pre>
<h3>Opis:</h3>
<p>Wyrażenie ma za zadanie sprawdzać, czy wprowadzony przez użytkownika adres e-mail ma poprawną formę. Aby test zakończył się sukcesem muszą zostać spełnione następujące warunki:</p>
<ul>
<li>nazwa użytkownika musi zaczynać się od znaku litery lub cyfry, nie może zawierać spacji, tabulatorów, aty, za to mogą się znajdować w nim kropki, pod warunkiem, że nie występują jedna, po drugiej,</li>
<li>po nazwie użytkownika musi pojawiać się znak małpy,</li>
<li>domena, podobnie jak nazwa użytkownika, musi rozpoczynać się od litery, bądź cyfry, po czym do znaków dozwolonych dochodzą <strong>-</strong> oraz <strong>.</strong>, pod warunkiem, że pierwszy z wcześniej wymienionych znaków nie znajduje się na początku lub na końcu nazwy subdomeny (wyjątkiem są dwa myślniki na jej końcu odpowiadające często prefiksom <strong>xn--</strong>), a drugi nie jest poprzedzany swoim odpowiednikiem. <a target="_blank" href="http://pl.wikipedia.org/wiki/Domena_najwy%C5%BCszego_poziomu"  title="TLD - informacje">TLD</a> może mieć długość od dwóch do sześciu znaków,</li>
<li>domena może być zakończona kropką,</li>
<li>rozwiązanie nie sprawdza jak długi jest wprowadzony adres e-mail.</li>
</ul>
<h3>Strona testowa:</h3>
<p><a href="http://use.m1chu.eu/-php/-ready-made-expressions/point-email/index.php"  title="Przykład walidacji adresu e-mail">Tutaj</a>.</p>
<h3>Tekst spełniający warunki:</h3>
<p>2.a_a-d@n-do.x-d.pl</p>
<h3>Tekst nie spełniający warunków:</h3>
<p>2.a_a-d@n-do.x-d.v-.pl (część domeny kończąca się nieprawidłowym znakiem)</p>
<h3>Uwagi:</h3>
<p>Jeżeli rozwiązanie w jakimkolwiek stopniu zawiedzie można pokusić się o użycie wyrażenia z ostatniej aktualizacji <a target="_blank" href="http://utnij.eu/f24/"  title="Zmiany w pliku logical_filters.c">pliku logical_filters.c ze źródeł PHP</a>.</p>
<h3>Rozwiązanie oparte o wyrażenie regularne:</h3>
<pre class="brush: php; title: ;">$email = trim('adres@domena.pl');
if ( !preg_match('/^([a-z0-9]{1})([^\s\t\.@]*)((\.[^\s\t\.@]+)*)@([a-z0-9]{1})((([a-z0-9-]*[-]{2})|([a-z0-9])*|([a-z0-9-]*[-]{1}[a-z0-9]+))*)((\.[a-z0-9](([a-z0-9-]*[-]{2})|([a-z0-9]*)|([a-z0-9-]*[-]{1}[a-z0-9]+))+)*)\.([a-z0-9]{2,6})([.]?)$/Diu', $email) )
{
	print 'Nieprawidłowy adres e-mail';
}</pre>
<h3>Rozwiązanie oparte o <a target="_blank" href="http://pl2.php.net/filter_var"  title="Specyfikacja filter_var()">filter_var</a> (PHP >= 5.2):</h3>
<pre class="brush: php; title: ;">$email = trim('adres@domena.pl');
if ( (bool)filter_var($email, FILTER_VALIDATE_EMAIL) === false )
{
	print 'Nieprawidłowy adres e-mail';
}</pre>
<h2>2. Walidacja adresu e-mail opartego na hoście lub IPv4 serwera</h2>
<h3>Wzorzec:</h3>
<pre class="brush: plain; title: ;">/^([a-z0-9]{1})([^\s\t\.@]*)((\.[^\s\t\.@]+)*)@((([a-z0-9]{1})((([a-z0-9-]*[-]{2})|([a-z0-9])*|([a-z0-9-]*[-]{1}[a-z0-9]+))*)((\.[a-z0-9](([a-z0-9-]*[-]{2})|([a-z0-9]*)|([a-z0-9-]*[-]{1}[a-z0-9]+))+)*)\.([a-z0-9]{2,6})([.]?))|((\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))$/Diu</pre>
<h3>Opis:</h3>
<p>Wyrażenie ma za zadanie sprawdzać, czy wprowadzony przez użytkownika adres e-mail ma poprawną formę. Aby test zakończył się sukcesem muszą zostać spełnione warunki z poprzedniego punktu oraz:</p>
<ul>
<li>po znaku @ musi się pojawić opisany już wcześniej prawidłowo sformowany host lub adres IPv4 serwera w postaci czterech, dziesiętnych oktetów.</li>
</ul>
<h3>Strona testowa:</h3>
<p><a href="http://use.m1chu.eu/-php/-ready-made-expressions/point-email/index.php"  title="Przykład walidacji adresu e-mail">Tutaj</a>.</p>
<h3>Tekst spełniający warunki:</h3>
<p>2.a_a-d@64.64.100.100</p>
<h3>Tekst nie spełniający warunków:</h3>
<p>2.a_a-d@64.64.256.100 (trzeci oktet jest po za zakresem)</p>
<h3>Uwagi:</h3>
<p>Jeżeli rozwiązanie w jakimkolwiek stopniu zawiedzie można pokusić się o użycie wyrażenia z ostatniej aktualizacji <a target="_blank" href="http://utnij.eu/f24/"  title="Zmiany w pliku logical_filters.c">pliku logical_filters.c ze źródeł PHP</a>.</p>
<h3>Rozwiązanie oparte o wyrażenie regularne:</h3>
<pre class="brush: php; title: ;">$email = trim('adres@85.64.100.100');
if ( !preg_match('/^([a-z0-9]{1})([^\s\t\.@]*)((\.[^\s\t\.@]+)*)@((([a-z0-9]{1})((([a-z0-9-]*[-]{2})|([a-z0-9])*|([a-z0-9-]*[-]{1}[a-z0-9]+))*)((\.[a-z0-9](([a-z0-9-]*[-]{2})|([a-z0-9]*)|([a-z0-9-]*[-]{1}[a-z0-9]+))+)*)\.([a-z0-9]{2,6})([.]?))|((\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))$/Diu', $email) )
{
	print 'Nieprawidłowy adres e-mail';
}</pre>
<h3>Rozwiązanie oparte o <a target="_blank" href="http://pl2.php.net/filter_var"  title="Specyfikacja filter_var()">filter_var</a> (PHP >= 5.2):</h3>
<pre class="brush: php; title: ;">$email = trim('adres@domena.pl');
if ( (bool)filter_var($email, FILTER_VALIDATE_EMAIL) === false )
{
	print 'Nieprawidłowy adres e-mail';
}</pre>
<h2>3. Prosta weryfikacja adresu URL</h2>
<h3>Wzorzec:</h3>
<pre class="brush: plain; title: ;">/^(http|ftp)([s]{0,1}):\/\/([a-z0-9]{1})((([a-z0-9-]*[-]{2})|([a-z0-9])*|([a-z0-9-]*[-]{1}[a-z0-9]+))*)((\.[a-z0-9](([a-z0-9-]*[-]{2})|([a-z0-9]*)|([a-z0-9-]*[-]{1}[a-z0-9]+))+)*)(\.([a-z0-9]{2,6})){0,1}((:[0-9]){0}|(:[1-9]{1}[0-9]*))\//iu</pre>
<h3>Opis:</h3>
<p>Zweryfikować, czy użytkownik wprowadził adres URL, wg wzoru:</p>
<pre class="brush: plain; title: ;">protokół://adres_serwera:port/</pre>
<ul>
<li>dozwolone protokoły: <strong>http</strong>, <strong>https</strong>, <strong>ftp</strong>, <strong>ftps</strong>,</li>
<li>adres serwera w formie serwera lokalnego, subdomen, domeny i rozszerzenia,</li>
<li>port jest opcjonalny,</li>
<li>dalsze wprowadzone dane (jak Query String) nie są sprawdzane,</li>
<li>konstrukcja jest przeznaczona do sprawdzanie adresów opartych na IPv4.</li>
</ul>
<h3>Strona testowa:</h3>
<p><a href="http://use.m1chu.eu/-php/-ready-made-expressions/point-url/index.php"  title="Przykład walidacji adresu URL">Tutaj</a>.</p>
<h3>Tekst spełniający warunki:</h3>
<p>http://m1chu.eu/</p>
<h3>Tekst nie spełniający warunków:</h3>
<p>htt://adres.com/temp/ (nieprawidłowy schemat)</p>
<h3>Rozwiązanie oparte o wyrażenie regularne:</h3>
<pre class="brush: php; title: ;">$url = trim('http://m1chu.eu');
if ( !preg_match('/^(http|ftp)([s]{0,1}):\/\/([a-z0-9]{1})((([a-z0-9-]*[-]{2})|([a-z0-9])*|([a-z0-9-]*[-]{1}[a-z0-9]+))*)((\.[a-z0-9](([a-z0-9-]*[-]{2})|([a-z0-9]*)|([a-z0-9-]*[-]{1}[a-z0-9]+))+)*)(\.([a-z0-9]{2,6})){0,1}((:[0-9]){0}|(:[1-9]{1}[0-9]*))\//iu', $url) )
{
	print 'Nieprawidłowy adres URL';
}</pre>
<h2>4. Wycinanie hosta z portem z adresu URL</h2>
<h3>Wzorzec:</h3>
<pre class="brush: plain; title: ;">/^(http|ftp)([s]{0,1}):\/\/((.*)\.[a-z0-9]{2,6}|((\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5]))){0,1}((:[0-9]){0}|(:[1-9]{1}[0-9]*))\//iu</pre>
<h3>Opis:</h3>
<p>Pobrać host wraz z portem (jeżeli został podany) z URI. Pozostałe zasady są tożsame z wymienionymi w poprzednim punkcie.</p>
<h3>Strona testowa:</h3>
<p><a href="http://use.m1chu.eu/-php/-ready-made-expressions/point-extract-domain/index.php"  title="Przykład wycinania hosta z portem">Tutaj</a>.</p>
<h3>Tekst spełniający warunki:</h3>
<p>http://m1chu.eu:80/ (zwróci: m1chu.eu:80)</p>
<h3>Tekst nie spełniający warunków:</h3>
<p>htt://adres.com/temp/ (nieprawidłowy schemat)</p>
<h3>Rozwiązanie oparte o wyrażenie regularne:</h3>
<pre class="brush: php; title: ;">$url = trim('ftps://stro.eu:1000/file.exe');
if ( preg_match('/^(http|ftp)([s]{0,1}):\/\/((.*)\.[a-z0-9]{2,6}|((\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5]))){0,1}((:[0-9]){0}|(:[1-9]{1}[0-9]*))\//iu', $url, $matches) )
{
	// $matches[3] - nazwa serwera z domeną lub adres IPv4
	// $matches[10] - port
	print $matches[3] . ':' . $matches[10];
}</pre>
<h2>5. Sprawdzanie adresu IP (protokół IPv4)</h2>
<h3>Wzorzec:</h3>
<pre class="brush: plain; title: ;">/^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/Du</pre>
<h3>Opis:</h3>
<p>Wykryć poprawność wprowadzonego w formie dziesiętnych oktetów IP (w wersji czwartej protokołu).</p>
<h3>Strona testowa:</h3>
<p><a href="http://use.m1chu.eu/-php/-ready-made-expressions/point-ipv4/index.php"  title="Przykład walidacji adresu IPv4">Tutaj</a>.</p>
<h3>Tekst spełniający warunki:</h3>
<p>0.0.0.0</p>
<h3>Tekst nie spełniający warunków:</h3>
<p>101.256.0.1 (drugi oktet poza zakresem)</p>
<h3>Rozwiązanie oparte o wyrażenie regularne:</h3>
<pre class="brush: php; title: ;">$ipv4 = trim('192.168.0.1');
if ( !preg_match('/^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/Du', $ipv4) )
{
	print 'Nieprawidłowy adres IPv4';
}</pre>
<h3>Rozwiązanie oparte o <a target="_blank" href="http://pl2.php.net/filter_var"  title="Specyfikacja filter_var()">filter_var</a> (PHP >= 5.2):</h3>
<pre class="brush: php; title: ;">$ipv4 = trim('192.168.0.1');
if ( (bool)filter_var($ipv4, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) === false )
{
	print 'Nieprawidłowy adres IPv4';
}</pre>
<h2>6. Sprawdzamy adres IP z wykluczeniem puli prywatnych adresów (protokół IPv4)</h2>
<h3>Wzorzec:</h3>
<pre class="brush: plain; title: ;">/^([1-9]{1}[1-9]{0,1}|1\d([1-6]{1}|[8-9]{1})|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-4])$/Du</pre>
<h3>Opis:</h3>
<p>Wykryć poprawność wprowadzonego IP (w wersji czwartej protokołu) z wykluczeniem części prywatnych i zastrzeżonych pul. Metoda nie dotyczy masek podsieci. Objęte wyjątki:</p>
<ul>
<li>10.0.0.0 &#8211; 10.255.255.255,</li>
<li>0.0.0.0 &#8211; 0.255.255.255,</li>
<li>255.255.255.255,</li>
<li>127.0.0.0 &#8211; 127.255.255.255.</li>
</ul>
<h3>Strona testowa:</h3>
<p><a href="http://use.m1chu.eu/-php/-ready-made-expressions/point-ipv4-noprivate/index.php"  title="Przykład walidacji adresu IPv4 z wykluczeniem puli prywatnych adresów">Tutaj</a>.</p>
<h3>Tekst spełniający warunki:</h3>
<p>192.168.0.136</p>
<h3>Tekst nie spełniający warunków:</h3>
<p>0.0.0.0 (adres prywatny)</p>
<h3>Uwagi:</h3>
<p>Stosując funkcję ze zbioru <strong>filter_*</strong> odrzucone zostaną wszystkie zakresy adresów prywatnych i zastrzeżonych (np. 255.255.255.x).</p>
<h3>Rozwiązanie oparte o wyrażenie regularne:</h3>
<pre class="brush: php; title: ;">$ipv4 = trim('68.78.205.0');
if ( !preg_match('/^([1-9]{1}[1-9]{0,1}|1\d([1-6]{1}|[8-9]{1})|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-4])$/Du', $ipv4) )
{
	print 'Nieprawidłowy adres IPv4';
}</pre>
<h3>Rozwiązanie oparte o <a target="_blank" href="http://pl2.php.net/filter_var"  title="Specyfikacja filter_var()">filter_var</a> (PHP >= 5.2):</h3>
<pre class="brush: php; title: ;">$ipv4 = trim('68.78.205.0');
if ( (bool)filter_var($ipv4, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) === false )
{
	print 'Nieprawidłowy adres IPv4';
}</pre>
<h2>7. Sprawdzamy adres IP (protokół <a target="_blank" href="http://pl.wikipedia.org/wiki/IPv6"  title="IPv6 - informacje">IPv6</a> i IPv4)</h2>
<h3>Wzorzec:</h3>
<pre class="brush: plain; title: ;">/^((([0-9A-Fa-f]{1,4}:){7}(([0-9A-Fa-f]{1,4})|:))|(([0-9A-Fa-f]{1,4}:){6}(:|((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})|(:[0-9A-Fa-f]{1,4})))|(([0-9A-Fa-f]{1,4}:){5}((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:){4}(:[0-9A-Fa-f]{1,4}){0,1}((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:){3}(:[0-9A-Fa-f]{1,4}){0,2}((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:){2}(:[0-9A-Fa-f]{1,4}){0,3}((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:)(:[0-9A-Fa-f]{1,4}){0,4}((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(:(:[0-9A-Fa-f]{1,4}){0,5}((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})))(%.+)?$/Du</pre>
<h3>Opis:</h3>
<p>Wykryć poprawność wprowadzonego IP (w wersji szóstej i czwartej protokołu).</p>
<h3>Strona testowa:</h3>
<p><a href="http://use.m1chu.eu/-php/-ready-made-expressions/point-ipv6/index.php"  title="Przykład walidacji adresu IPv6">Tutaj</a>.</p>
<h3>Tekst spełniający warunki:</h3>
<p>fe80:0:0:0:0204:61ff:254.157.241.86</p>
<h3>Tekst nie spełniający warunków:</h3>
<p>2001:::db8:: (błędna notacja)</p>
<h3>Uwagi:</h3>
<p>Stosując funkcję ze zbioru <strong>filter_*</strong> odrzucone zostaną wszelkie adresy <a target="_blank" href="http://pl.wikipedia.org/wiki/IPv4"  title="IPv4 - informacje">IPv4</a>. W przedstawionym wyrażeniu regularnym adresy z tej wersji są akceptowane zarówno występując samotnie, jak i w postaci sekwencji czterech ostatnich bajtów w IPv6 (np. :247.125.68.4).</p>
<h3>Rozwiązanie oparte o wyrażenie regularne:</h3>
<pre class="brush: php; title: ;">$ipv6 = trim('fe80::204:61ff:fe9d:f156');
if ( !preg_match('/^((([0-9A-Fa-f]{1,4}:){7}(([0-9A-Fa-f]{1,4})|:))|(([0-9A-Fa-f]{1,4}:){6}(:|((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})|(:[0-9A-Fa-f]{1,4})))|(([0-9A-Fa-f]{1,4}:){5}((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:){4}(:[0-9A-Fa-f]{1,4}){0,1}((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:){3}(:[0-9A-Fa-f]{1,4}){0,2}((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:){2}(:[0-9A-Fa-f]{1,4}){0,3}((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:)(:[0-9A-Fa-f]{1,4}){0,4}((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(:(:[0-9A-Fa-f]{1,4}){0,5}((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})))(%.+)?$/Du', $ipv6) )
{
	print 'Nieprawidłowy adres IPv6/IPv4';
}</pre>
<h3>Rozwiązanie oparte o <a target="_blank" href="http://pl2.php.net/filter_var"  title="Specyfikacja filter_var()">filter_var</a> (PHP >= 5.2):</h3>
<pre class="brush: php; title: ;">$ipv6 = trim('fe80::204:61ff:fe9d:f156');
if ( (bool)filter_var($ipv6, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false )
{
	print 'Nieprawidłowy adres IPv6';
}</pre>
<h2>8. Wykrywanie kolorów RGB w postaci szesnastkowej</h2>
<h3>Wzorzec:</h3>
<pre class="brush: plain; title: ;">/^#?[0-9a-f]{3}(?:[0-9a-f]{3})?$/Diu</pre>
<h3>Opis:</h3>
<p>Sprawdzić, czy wprowadzone dane są szesnastkowymi odpowiednikami zapisu kolorów modelu RGB.</p>
<h3>Strona testowa:</h3>
<p><a href="http://use.m1chu.eu/-php/-ready-made-expressions/point-hex-color/index.php"  title="Przykład wykrywania koloru w postaci szesnastkowej">Tutaj</a>.</p>
<h3>Tekst spełniający warunki:</h3>
<p>#ff0000</p>
<h3>Tekst nie spełniający warunków:</h3>
<p>#a0hfg1 (g i h nie są znakami używanymi przy zapisie heksadecymalnym)</p>
<h3>Rozwiązanie oparte o wyrażenie regularne:</h3>
<pre class="brush: php; title: ;">$hex = trim('#0F15a2');
if ( !preg_match('/^#?[0-9a-f]{3}(?:[0-9a-f]{3})?$/Diu', $hex) )
{
	print 'Nieprawidłowy kod szesnastkowy koloru!';
}</pre>
<h2>9. Proste sprawdzenie nazwy użytkownika</h2>
<h3>Wzorzec:</h3>
<pre class="brush: plain; title: ;">/^([a-z0-9]{1})([a-z0-9_-]{2,11})$/Diu</pre>
<h3>Opis:</h3>
<p>Wprowadzone dane muszą rozpoczynać się od znaku alfanumerycznego. Kolejne znaki mogą być ponadto myślnikiem lub podkreśleniem. Długość tekstu nie może być większa niż 12ście znaków.</p>
<h3>Strona testowa:</h3>
<p>Brak.</p>
<h3>Tekst spełniający warunki:</h3>
<p>m1chu</p>
<h3>Tekst nie spełniający warunków:</h3>
<p>_nick (pierwszy znak nie jest cyfrą, ani literą)</p>
<h3>Rozwiązanie oparte o wyrażenie regularne:</h3>
<pre class="brush: php; title: ;">$username = trim('m1chu');
if ( !preg_match('/^([a-z0-9]{1})([a-z0-9_-]{2,11})$/Diu', $username) )
{
	print 'Nieprawidłowa nazwa użytkownika!';
}</pre>
<h2>10. Proste sprawdzenie hasła użytkownika</h2>
<h3>Wzorzec:</h3>
<pre class="brush: plain; title: ;">/^(?=[a-z0-9_#@%\*-]*?[A-Z])(?=[a-z0-9_#@%\*-]*?[a-z])(?=[a-z0-9_#@%\*-]*?[0-9])([a-z0-9_#@%\*-]{8,24})$/Diu</pre>
<h3>Opis:</h3>
<p>Wpisane hasło użytkownika musi mieć od ośmiu, do dwudziestu czterech znaków, pośród których musi być co najmniej jedna wielka litera, jedna mała i jedna cyfra. Dodatkowo dozwolone są: <strong>_</strong>, <strong>#</strong>, <strong>@</strong>, <strong>%</strong>, <strong>*</strong> i <strong>-</strong>.</p>
<h3>Strona testowa:</h3>
<p>Brak.</p>
<h3>Tekst spełniający warunki:</h3>
<p>1xY#n6%2V</p>
<h3>Tekst nie spełniający warunków:</h3>
<p>@1bbd2 (za krótki ciąg, brak wielkiej litery)</p>
<h3>Rozwiązanie oparte o wyrażenie regularne:</h3>
<pre class="brush: php; title: ;">$password = trim('To#jEst@_haSL-o%usera*');
if ( !preg_match('/^(?=[a-z0-9_#@%\*-]*?[A-Z])(?=[a-z0-9_#@%\*-]*?[a-z])(?=[a-z0-9_#@%\*-]*?[0-9])([a-z0-9_#@%\*-]{8,24})$/Diu', $password) )
{
	print 'Nieprawidłowa nazwa użytkownika!';
}</pre>
<h2>11. Zaznaczanie frazy w tekście</h2>
<h3>Wzorzec:</h3>
<pre class="brush: plain; title: ;">/\b(fraza)\b/iu</pre>
<h3>Opis:</h3>
<p>Zamienianie podanej frazy na inną lub wystylowanie jej formy. Przydatna funkcja w wyszukiwarkach.</p>
<h3>Strona testowa:</h3>
<p>Brak.</p>
<h3>Działanie:</h3>
<p>szukana_fraza -> <strong>szukana_fraza</strong></p>
<h3>Rozwiązanie oparte o wyrażenie regularne:</h3>
<pre class="brush: php; title: ;">$text = 'Wyszukane frazy: wyrażenia, regularne, preg_match, preg_replace';
$find = 'regularne';
print preg_replace('/\b(' . $find . ')\b/iu', '&lt;strong&gt;\\1&lt;/strong&gt;', $text);</pre>
<h3>Rozwiązanie oparte o <a target="_blank" href="http://pl2.php.net/manual/en/function.str-ireplace.php"  title="Specyfikacja str_ireplace()">str_ireplace</a>:</h3>
<pre class="brush: php; title: ;">$text = 'Wyszukane frazy: wyrażenia, regularne, preg_match, preg_replace';
$find = 'regularne';
print str_ireplace($find, '&lt;strong&gt;' . $find . '&lt;/strong&gt;', $text);</pre>
<h2>12. Zamiana tekstowych emotikon na graficzne</h2>
<h3>Opis:</h3>
<p>Podmiana tekstowych uśmieszków na ich odpowiedniki graficzne. Wersja z użyciem <strong>str_ireplace</strong>.</p>
<h3>Strona testowa:</h3>
<p>Brak.</p>
<h3>Rozwiązanie oparte o wbudowaną funkcję PHP:</h3>
<pre class="brush: php; title: ;">$text_format = array(
	array(';)', ';-)', 'x)', ';]', ';-]'),
	array(':)', ':-)', '=)', ':]', ':-]'),
	array(':(', ':-(', '=(', ':[', ':-['),
	array(';(', ';-(', 'x(', ';[', ';-['),
	array(':P', ':-P', '=P'),
	array(':D', ':-D', '=D'),
	array(':*', ':-*', '=*'),
	array(':O', ':-O', '=O'),
	array(':/', ':-/', '=/')
	);

$image_format = array(
	'wink.png',
	'smile.png',
	'sad.png',
	'cry.png',
	'tongue.png',
	'bigsmile.png',
	'kiss.png',
	'surprise.png',
	'grimace.png'
	);

$text = 'To jest przykładowy tekst ;] Prawda, że fajny? :-D Pogrymasiłbym trochę =/, ale po co? :) Także do zobaczenia :*';

foreach ( $text_format as $key =&gt; $val )
{
	$text = str_ireplace($val, '&lt;img src=&quot;smiles/' . $image_format[$key] . '&quot; alt=&quot;' . $image_format[$key] . '&quot; /&gt;', $text);
}

print $text;</pre>
<h2>13. Zamiana BBCode na HTML</h2>
<h3>Wzorzec przykładowy:</h3>
<pre class="brush: plain; title: ;">/\[b\](.*?)\[\/b\]/Dius</pre>
<h3>Opis:</h3>
<p>Podmiana BBCode poprzez kod HTML. Funkcjonalność znana z forów internetowych.</p>
<h3>Strona testowa:</h3>
<p>Brak.</p>
<h3>Działanie:</h3>
<p>[i]pochylenie[/i] -> <em>pochylenie</em></p>
<h3>Uwagi:</h3>
<p>W komercyjnych projektach należy skorzystać z bardziej zaawansowanych klas do obsługi tego problemu. Pozwoli to uniknąć np. problemu z nieprawidłowym zagnieżdżeniem kilku tagów BBCode w sobie.</p>
<h3>Rozwiązanie oparte o wyrażenie regularne:</h3>
<pre class="brush: php; title: ;">function bbcode2html($code) {
	$search = array(
        '/\[b\](.*?)\[\/b\]/Dius',
        '/\[i\](.*?)\[\/i\]/Dius',
        '/\[u\](.*?)\[\/u\]/Dius',
        '/\[s\](.*?)\[\/s\]/Dius',
        '/\[img\=(.*?)\](.*?)\[\/img\]/Dius',
        '/\[img\](.*?)\[\/img\]/Dius',
        '/\[url\](.*?)\[\/url\]/Dius',
        '/\[url\=(.*?)\](.*?)\[\/url\]/Dius',
        '/\[color\=(#?([a-f0-9]{6}|[a-f0-9]{3}))\](.*?)\[\/color\]/Dius',
        '/\[size\=([1-9]{1}[0-9]{0,2})(px|pt|em)\](.*?)\[\/size\]/Dius',
    	'/\[font\=([a-z0-9\s&quot;]+)\](.*?)\[\/font\]/Dius',
    );

	$replace = array(
        '&lt;strong&gt;\\1&lt;/strong&gt;',
        '&lt;em&gt;\\1&lt;/em&gt;',
        '&lt;span style=&quot;text-decoration: underline;&quot;&gt;\\1&lt;/u&gt;',
        '&lt;strike&gt;\\1&lt;/strike&gt;',
        '&lt;img src=&quot;\\2&quot; alt=&quot;\\1&quot; /&gt;',
        '&lt;img src=&quot;\\1&quot; alt=&quot;&quot; /&gt;',
        '&lt;a href=&quot;\\1&quot;&gt;\\1&lt;/a&gt;',
        '&lt;a href=&quot;\\1&quot;&gt;\\2&lt;/a&gt;',
        '&lt;span style=&quot;color: \\1;&quot;&gt;\\2&lt;/span&gt;',
        '&lt;span style=&quot;font-size: \\1\\2;&quot;&gt;\\3&lt;/span&gt;',
    	'&lt;span style=&quot;font-family: \\1;&quot;&gt;\\2&lt;/span&gt;'
    );

	return preg_replace($search, $replace, $code);
}</pre>
<h2>14. Sprawdzenie poprawności wprowadzonego kodu pocztowego</h2>
<h3>Wzorzec:</h3>
<pre class="brush: plain; title: ;">/^[0-9]{2}-?[0-9]{3}$/Du</pre>
<h3>Opis:</h3>
<p>Testowanie poprawności wpisanego kodu pocztowego (w formacie używanym w Polsce). Dozwolone są wersje z myślnikiem pomiędzy drugą i trzecią cyfrą, oraz bez niego.</p>
<h3>Strona testowa:</h3>
<p>Brak.</p>
<h3>Tekst spełniający warunki:</h3>
<p>62-150</p>
<h3>Tekst nie spełniający warunków:</h3>
<p>611-10</p>
<h3>Rozwiązanie oparte o wyrażenie regularne:</h3>
<pre class="brush: php; title: ;">$postcode = '61-610';
if ( !preg_match('/^[0-9]{2}-?[0-9]{3}$/Du', $postcode) )
{
	print 'Nieprawidłowy kod pocztowy';
}</pre>
<h2>15. Operowanie na znacznikach XML/XHTML</h2>
<h3>Wzorzec:</h3>
<pre class="brush: plain; title: ;">/&lt;([a-z]+)([\s]{1}[^=]+[=]{1}[^&lt;]+)*(?:&gt;(.*)&lt;\/\1&gt;|\s+\/&gt;)/u</pre>
<h3>Opis:</h3>
<p>Sprawdzenie znaczników XML/XHTML oraz pobranie treści znajdującej się pomiędzy nimi.</p>
<h3>Strona testowa:</h3>
<p>Brak.</p>
<h3>Rozwiązanie oparte o wyrażenie regularne:</h3>
<pre class="brush: php; title: ;">$tag = '&lt;a href=&quot;http://m1chu.eu/&quot; title=&quot;m1chu.eu - another devblog&quot;&gt;m1chu.eu&lt;/a&gt; - &lt;strong&gt;another devblog&lt;/strong&gt;';
if ( !preg_match_all('/&lt;([a-z]+)([\s]{1}[^=]+[=]{1}[^&lt;]+)*(?:&gt;(.*)&lt;\/\1&gt;|\s+\/&gt;)/u', $tag, $matches, PREG_PATTERN_ORDER) )
{
	print 'Nieprawidłowa konstrukcja znacznika';
}
else {
	print_r($matches); // print_r($matches[3]) - lista treści zawieranych w tagach
}</pre>
<h2>Słowem zakończenia</h2>
<p>Starałem się jak najdokładniej sprawdzić powyższe wzorce. Nie mniej jednak, jak to zwykle bywa, mogą się w nich znaleźć błędy. Jeżeli ktoś takowe znajdzie, ma jakieś pytania, czy lepsze propozycje to proszę o komentarze pod wpisem.</p>
<p>Jak wspomniałem na wstępie, uruchomiłem serwis pozwalający na sprawdzanie wyrażeń regularnych względem podanego tekstu. Jest on aktualnie w fazie testów, więc mogą występować błędy w jego działaniu. Po zakończeniu wprowadzania poprawek baza wpisów zostanie wyczyszczona do zera. Można go testować, a w przyszłości korzystać pod dwoma adresami:</p>
<ol>
<li><a target="_blank" href="http://regexp.pl/"  title="regexp.pl - tester wyrażeń regularnych"><strong>regexp.pl</strong></a> (adres główny)</li>
<li><a href="http://regexp.m1chu.eu/"  title="regexp.pl - tester wyrażeń regularnych"><strong>regexp.m1chu.eu</strong></a> (adres alternatywny)</li>
</ol>
<p>Pod względem danych sesyjnych obydwa adresy działają niezależnie. <strong>Zapraszam do testowania i wyrażania swojego zdania na moim blogu, w komentarzach tego artykułu.</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://m1chu.eu/2009/10/13/15-przydatnych-wyrazen-regularnych-w-php/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Jak wyizolować liczbę subskrybentów RSS korzystając z FeedBurner&#8217;a?</title>
		<link>http://m1chu.eu/2009/02/15/jak-wyizolowac-liczbe-subskrybentow-rss-korzystajac-z-feedburnera/</link>
		<comments>http://m1chu.eu/2009/02/15/jak-wyizolowac-liczbe-subskrybentow-rss-korzystajac-z-feedburnera/#comments</comments>
		<pubDate>Sun, 15 Feb 2009 12:55:53 +0000</pubDate>
		<dc:creator>m1chu</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Webhosting]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[easy feed counter]]></category>
		<category><![CDATA[feedburner]]></category>
		<category><![CDATA[feedcount]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[repozytorium]]></category>
		<category><![CDATA[simplexmlelement]]></category>
		<category><![CDATA[xml]]></category>

		<guid isPermaLink="false">http://m1chu.eu/?p=1237</guid>
		<description><![CDATA[W niezbędniku prawie każdego blogera leży możliwość menadżerowania swoimi kanałami RSS, bądź Atom. Któż z nas nie zna FeedBurner&#8217;a?. Zestawu narzędzi ułatwiających nam, czy to udostępnianie użytkownikom możliwości subskrypcji treści naszej strony, czy po prostu możliwość przejrzenia lub zamieszczenia statystyk w naszym serwisie. Pomimo dostarczonego API nie znajdziemy jednak bezpośrednio w panelu FeedBurner&#8217;a kodu pozwalającego [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: center;"><img class="iborder" src="http://farm4.static.flickr.com/3316/3276810158_fd2d4b8829_o.png" alt="Pobieramy liczbę subskrybentów RSS poprzez FeedBurner" style="height: 119px;" /></p>
<p>W niezbędniku prawie każdego blogera leży możliwość menadżerowania swoimi kanałami RSS, bądź Atom. Któż z nas nie zna <strong>FeedBurner&#8217;a</strong>?. Zestawu narzędzi ułatwiających nam, czy to udostępnianie użytkownikom możliwości subskrypcji treści naszej strony, czy po prostu możliwość przejrzenia lub zamieszczenia statystyk w naszym serwisie. Pomimo dostarczonego API nie znajdziemy jednak bezpośrednio w panelu <strong>FeedBurner&#8217;a</strong> kodu pozwalającego na umieszczenie samej liczby subskrybentów bloga. I rozwiązanie tego, pozornie błahego problemu postaram się Wam dziś przedstawić&#8230;<br />
<span id="more-1237"></span></p>
<h2>Stary, dobry FeedBurner.com&#8230;</h2>
<p>Niespełna dwa lata temu słynny serwis zajmujący się obsługą kanałów RSS został przejęty za sto milionów dolarów przez <strong>Google</strong>. Pomimo tego, że minęło aż tyle czasu wielu blogerów nadal korzysta z zasobów starego, wysłużonego, pierwotnego FeedBurner&#8217;a. I co może wydawać się dziwne, to właśnie oni mają najbardziej ułatwioną sytuację.</p>
<p>Zarówno stara, jak i nowa odsłona serwisu oferują usługę <strong>FeedCount</strong> dostępną z poziomu menu <strong>Publicize</strong>. Pozwala ona na dobranie typu wbudowanego tła wyświetlającego ilość subskrybentów (statyczne, bądź animowane) oraz na dobranie jego barwy i koloru tekstu. Wraz z ustawieniem tych parametrów otrzymujemy kod HTML do wstawienia na naszą stronę. I tu rodzi się problem. Prócz kilku stylistycznych zmian wygląd tychże &#8222;chickletów&#8221; jest zawsze taki sam i najczęściej nijak pasuje do designu naszego bloga. Co zrobić jeżeli np. chcemy wraz z tekstem przycisku odnoszącego użytkowników do wygenerowanego kanału wstawić także ilość osób śledzących naszą stronę?</p>
<p>Rozwiązanie zaprezentuje na podstawie użytkowania platformy <a target="_blank" href="http://wordpress.org/"  title="Wordpress">WordPress</a> (oczywiście ilość subskrybentów &#8211; opierając się na dalszym tekście &#8211; można zamieścić w każdym innym systemie zarządzania treścią, bądź nawet na własnej, prywatnej stronie). W takim wypadku wystarczy zainteresować się wtyczkami <a target="_blank" href="http://utnij.eu/5b5/"  title="FeedBurner FeedSmith 2.3">FeedSmith 2.3</a> (<a target="_blank" href="http://utnij.eu/632cd7/"  title="FeedBurner FeedSmith 2.3 PL">polska wersja</a>) (wg. developerów WordPress&#8217;a kompatybilną ze wszystkimi wersjami 2.x) i <a target="_blank" href="http://utnij.eu/feed-count-plugin/"  title="Feed Count 1.2">Feed Count 1.2</a> (<a target="_blank" href="http://utnij.eu/776e/"  title="Feed Count 1.2 PL">polska wersja</a>). Pierwsza z nich niezbędna jest do obsługi kanału RSS przez serwis FeedBurner. </p>
<p>Jej instalacja oraz rejestracja w serwisie jest niezbędna do działania drugiej z nich. Jak wykonuje się instalacje wtyczek? Wystarczy wyodrębnić z archiwum odpowiednie pliki (w naszym pierwszym przypadku będzie to <strong>FeedBurner_FeedSmith_Plugin.php</strong>, w drugim <strong>feedcount.php</strong>) i umieścić je w katalogu <strong>wp-content/plugins/</strong> systemu WordPress. Następnie wtyczki należy zaktywować w panelu administratora (<strong>Wtyczki / Nazwa wtyczki / Włącz</strong>).</p>
<p>Obydwa pluginy należy dodatkowo skonfigurować w zakładce <strong>Ustawienia</strong>. Pierwszy z nich swoje opcje ukrywa w podmenu <strong>FeedBurner</strong>. Zobaczycie tam dwa pola do uzupełnienia, jedno wymagane, drugie opcjonalne. Pierwsze z nich to pełny odnośnik do feedu strony w serwisie FeedBurner (i dla starej odsłony, i dla nowej na serwerach Google), a drugi to link do kanału RSS komentarzy.</p>
<p style="text-align: center; font-size: 10px;"><img class="iborder" src="http://farm4.static.flickr.com/3325/3278708424_d49400bae8_o.png" alt="Konfiguracja wtyczki FeedSmith w panelu" style="height: 280px;" /><br />Konfiguracja wtyczki FeedSmith w panelu.</p>
<p>Co do drugiego rozszerzenia to działa ono dla wersji <strong>2.x</strong> WordPress&#8217;a, z tymże przy najnowszej <strong>2.7x</strong> może sprawiać problemy natury zwracania wyniku w postaci <strong>N/A</strong> zamiast poprawnej wartości.</p>
<p style="text-align: center; font-size: 10px;"><img class="iborder" src="http://farm4.static.flickr.com/3447/3277035819_12a3295a07_o.png" alt="Konfiguracja wtyczki Feed Count w panelu" style="height: 280px;" /><br />Konfiguracja wtyczki Feed Count w panelu.</p>
<p>Rozszerzenie to także należy dodatkowo skonfigurować. Robimy to w panelu poprzez menu <strong>Ustawienia / Feed Count</strong>. W jej opcjach trzeba podać co najmniej adres kanału (<em>Feed Url</em>) w postaci nazwy kanału na <strong>FeedBurner&#8217;ze</strong>, częstość aktualizowania ilości subskrybentów (<em>Update interval</em>) oraz częstość aktualizacji po wystąpieniu błędu (<em>Update interval (recovery)</em>). Pozostałe pola nie są wymagane. <em>Link url</em> to adres odnośnika pojawiającego się na zwróconej przez skrypt ilości osób śledzących stronę. <em>Before</em> za to jest treścią pojawiającą się przed liczbą w.w. użytkowników, a <em>After</em> to treść po.</p>
<p>Po wykonaniu konfiguracji należy jeszcze w strukturze szablonu strony dodać odpowiedni kod.</p>
<pre class="brush: php; title: ;">&lt;?php if (function_exists('fc_feedcount')) fc_feedcount(); ?&gt;</pre>
<p>Wstawić go musimy w miejscu w którym chcemy wyświetlać wystylizowaną liczbę użytkowników RSS (plugin ten nie zwraca tylko liczby otaczając ją poprzez dodatkowe tagi HTML). Oczywiście możemy go modyfikować. Jeżeli chcielibyście np. wyświetlić go w odnośniku (w <strong>header.php</strong>) o nazwie <strong>RSS</strong> w dodatkowych nawiasach to możecie to zrobić w następujący sposób:</p>
<pre class="brush: php; title: ;">&lt;?php
if (function_exists('fc_feedcount'))
{
	print ' (' . fc_feedcount() . ')';
}
?&gt;</pre>
<p>No i ostatecznie musicie w panelu <strong>FeedBurner&#8217;a</strong> (nie wtyczki, a profilu w serwisie w którym zakładaliście konto) zezwolić wtyczce na działanie z API tegoż serwisu. Wystarczy wejść do zakładki <strong>Publicize</strong>, a następnie do menu <strong>Awareness API</strong> i zaktywować tą funkcjonalność.</p>
<h2>Wtyczka Feed Count 1.2 dla Google FeedBurner!</h2>
<p>Jeżeli zdecydowaliście się jednak na migracje z starych serwerów serwisu, na ultraszybkie i megafajne klastry Google, a wcześniej trafnie stosowaliście w.w. metodę do wyodrębniania liczby użytkowników to prawdopodobnie będzie ona także działać po przejściu na <a target="_blank" href="http://feedburner.google.com/"  title="Google FeedBurner">feedburner.google.com</a>.</p>
<p>Trzeba jednak w takim wypadku dokonać pewnych, małych zmian w kodzie wyżej opisywanej wtyczki <strong>Feed Count</strong>. W tym celu edytujemy plik <strong>feedcount.php</strong> (np. poprzez <strong>Notepad++</strong> lub <strong>ZendStudio</strong>). Przechodzimy w okolice <strong>41</strong> linii w celu odnalezienia następującego kodu.</p>
<pre class="brush: php; title: ;">		  'map_fc_queryurl' =&gt;'http://api.feedburner.com/awareness/1.0/GetFeedData?uri=',</pre>
<p>Co można zauważyć element tablicy o nazwie przed <code>=></code> wskazuje na adres dostępowy do API, ale <em>feedburner.com</em>. A my przecież chcemy korzystać już z API Google. W tym celu należy tą linijkę zmienić niżej wymienionym kodem, po czym zapisać plik i ponownie wysłać go na serwer.</p>
<pre class="brush: php; title: ;">		  'map_fc_queryurl' =&gt;'https://feedburner.google.com/api/awareness/1.0/GetFeedData?uri=',</pre>
<h2>C&#8230; bombki strzelił! Jedyne co otrzymuje w wyniku to ten niewdzięczny &#8222;N/A&#8221;&#8230;</h2>
<p>Po pierwsze musicie sprawdzić czy biblioteka <a target="_blank" href="http://utnij.eu/curl-wiki/"  title="cURL Wiki">cURL (Client URL Library Functions)</a> jest dostępna w konfiguracjach Waszych serwerów (jako pakiet PHP). W tym celu wystarczy stworzyć jakikolwiek plik o rozszerzeniu <strong>.php</strong>, wypełnić go poniższym kodem i wywołać na hipotetycznie problematycznym serwerze.</p>
<pre class="brush: php; title: ;">&lt;?php
phpinfo();
?&gt;</pre>
<p>W wylistowanych wynikach wystarczy poszukać wpisu <strong>cURL support</strong> i sprawdzić, czy jego flaga ustawiona jest na <strong>enabled</strong>. Jeżeli nie, to właśnie znaleźliście przyczynę problemu. Powyższa, kluczowa dla nas wtyczka oparta jest na tym libie, a co za tym idzie jego brak powoduje niemożność poprawnego wykonania kodu tego rozszerzenia.</p>
<h2>Diagnoza problemu: cURL&#8230;</h2>
<p>Kiedy zawodzą dostępne już rozwiązania najlepszym sposobem na pozbycie się własnego problemu jest&#8230; napisanie indywidualnej solucji. Niestety to wiążę się najczęściej z jedną z dwóch rzeczy. Albo z posiadaniem konkretnej wiedzy odnośnie danego problemu, albo z wydatkiem związanym z opłaceniem osoby która rozwiąże Waszą dolegliwość.</p>
<p>Jeżeli dotarliście do tego punktu tzn. że nadal nie uzyskaliście pożądanego efektu. Pora więc właśnie na w.w. sposób, z tymże ja dla Was przygotuję go w stu procentach&#8230; za friko :] Mógłbym Wam zaprezentować kilkulinijkowy sposób, bo praktycznie do tego ogranicza się rozwiązanie &#8211; pytanie po co? Blog ten ma uczyć, dlatego postaram się Wam przedstawić dwie metody pobierania potrzebnych nam danych które po lekkim tuningu złożą się w jedną, w pełni funkcjonalną wtyczkę napisaną specjalnie na potrzeby tego artykułu. I w gruncie rzeczy będzie to najbardziej optymalne rozwiązanie ze wszystkich tutaj przedstawionych&#8230;</p>
<p>Przypadek numer jeden: <strong>brak możności użytkowania cURL&#8217;a</strong>. Jak to w życiu bywa, jak nie da wejść się jednym oknem, trzeba próbować drugim. Sposobów jest wiele, ja wybiorę użycie funkcji <a target="_blank" href="http://pl.php.net/file_get_contents"  title="file_get_contents - php.net">file_get_contents</a>. Zaimplementowana jest ona w PHP od wersji <strong>4.3</strong> i dodatkowo do jej działania konfiguracja serwera musi zezwalać na zdalne (z zewnętrznych źródeł) pobieranie plików. Trik który zastosujemy ogranicza się kolejno do:</p>
<ul>
<li>pobrania danych z adresu FeedBurner&#8217;a korzystając z udostępnionego przez niego API,</li>
<li>sprawdzenia czy odebrane dane są poprawne (pod kątem poprawności adresu i ewentualnych wyjątków),</li>
<li>wyszukanie frazy <code>circulation="</code> w posiadanym buforze. Kod który pobraliśmy wcześniej <strong>musi</strong> być w formacie XML, a co za tym idzie składa się on ze znaczników i parametrów. Właśnie parametr <code>circulation</code> zawiera w sobie wartość będącą ilością subskrybentów,</li>
<li>jeżeli fraza nie zostanie znaleziona, zwrócenie błędu,</li>
<li>w przeciwnym razie pobranie ciągu od pozycji wyszukiwanej wyżej frazy + 13 znaków (długość szukanego słowa), aż do znalezienia następnego cudzysłowia (bez niego).</li>
</ul>
<pre class="brush: php; title: ;">&lt;?php
$buffer = file_get_contents(ADRES_SERWER . NAZWA_KANALU); // pobranie pliku
if ( $buffer === false ) // zwrócenie błędu
{
	print 'n/d';
}

$pre_position = strpos($buffer, 'circulation=&quot;'); // wyszukanie pozycji frazy z drugiego argumentu
if ( $pre_position === false ) // w wypadku nieodnalezienia zwrócenie błędu (niepoprawny plik)
{
	print 'n/d';
}
else {
	print substr($buffer, ($pre_position+13), strpos($buffer, '&quot;', ($pre_position+14)) - ($pre_position+13)); // &quot;wypisanie na ekran&quot; zawartości parametru &quot;circulation&quot; z pobranego pliku XML
}
?&gt;</pre>
<h2>Kiedy problemem nie jest jednak cURL&#8230;</h2>
<div class="explain"><code>SimpleXMLElement</code> &#8211; klasa rozszerzenia <code>SimpleXML</code> dostarczająca prosty zestaw narzędzi do konwersji XML na obiekt na którym można operować poprzez użycie selektorów.</p>
<p>Przykład:</p>
<pre class="brush: xml; title: ;">&lt;parent&gt;
	&lt;children&gt;raz&lt;/children&gt;
	&lt;children&gt;dwa&lt;/children&gt;
&lt;/parent&gt;</pre>
<pre class="brush: php; title: ;">$xml = new SimpleXMLElement(XML);
$found = $xml-&gt;xpath('parent/children'); // wyszukiwanie potomka w drzewie dokumentu XML (argument w postaci np. rodzic/potomek/potomek_potomka/itp.)
print_r($found); // wypisanie tablicy wyników</pre>
</div>
<p>Plugin <strong>FeedCount</strong> nie zawsze działa na WordPress&#8217;ie <strong>2.7x</strong>. Nie pytajcie dlaczego. Szczerze? Nie wiem i nie chciało mi się dociekać co jest tego powodem. Postanowiłem jakiś czas temu spotykając się z tą przypadłością po prostu stworzyć bardziej uproszczony kod, niż ten z popularnej wtyczki. Jak wygląda jego schemat krokowy? Po kolei:</p>
<ul>
<li>inicjalizacja cURL,</li>
<li>ustawienie opcji transferu biblioteki (zwracanie zawartości bez wypisywania jej na ekran oraz wprowadzenie adresu docelowego),</li>
<li>wykonanie zadania, po czym zniszczenie sesji połączenia,</li>
<li>sprawdzenie, czy nie występuje znacznik nadrzędny <code>err</code> z parametrem <code>code</code> o wartości <strong>1</strong> (oznaka zwrócenia błędu, najczęściej nieodnalezienia pliku),</li>
<li>jeżeli powyższy punkt nie okaże się prawdą to utworzenie obiektu <a target="_blank" href="http://pl.php.net/simplexml"  title="SimpleXML - php.net"><code>SimpleXMLElement</code></a> i wyszukanie zawartości wyżej już wspomnianego atrybutu <code>circulation</code>.</li>
</ul>
<pre class="brush: php; title: ;">&lt;?php
$resource = curl_init(); // inicjalizacja
curl_setopt($resource, CURLOPT_RETURNTRANSFER, 1); // bez wypisania na ekran
curl_setopt($resource, CURLOPT_URL, ADRES_SERWER . NAZWA_KANALU); // przekazanie adresu do pobrania
$buffer = curl_exec($resource); // wykonanie
curl_close($resource); // zamknięcie sesji

$xml = new SimpleXMLElement($buffer); // obiekt analizy składni XML
if ( $xml-&gt;err['code'] == '1' ) // sprawdzenie wystąpienia błędu
{
	print 'n/d';
}
print $xml-&gt;feed-&gt;entry['circulation']; // pobranie ilości subskrybentów
?&gt;</pre>
<p>Aby bardziej wyjaśnić działanie powyższej partii kodu posłużę się przykładowymi danymi, jakie mogą zostać pobrane.</p>
<pre class="brush: xml; title: ;">&lt;rsp stat=&quot;ok&quot;&gt;
  &lt;!--This information is part of the FeedBurner Awareness API. If you want to hide this information, you may do so via your FeedBurner Account.--&gt;
  &lt;feed id=&quot;0ua2berteje16lsipgq0b8uk74&quot; uri=&quot;worldclub-pl&quot;&gt;
    &lt;entry date=&quot;2009-02-13&quot; circulation=&quot;1&quot; hits=&quot;2&quot; downloads=&quot;0&quot; reach=&quot;0&quot; /&gt;
  &lt;/feed&gt;
&lt;/rsp&gt;</pre>
<p>Można z niego wywnioskować, że odpowiednio operując na klasie <code>SimpleXMLElement</code> moglibyśmy uzyskać identyfikator konta, jego część adresu zwaną w tym artykule po prostu nazwą, datę utworzenia, ilość osób śledzących RSS&#8217;a, liczbę kliknięć oraz ściągnięć. Działanie powyższej klasy jest proste. Z kodu XML tworzymy obiekt po którym możemy przesuwać się za pomocą zwyczajnych selektorów. Przykładowo jeżeli chcielibyśmy wyłuskać z powyższego przykładu identyfikator (<code>id</code>) zrobilibyśmy to w następujący sposób:</p>
<pre class="brush: php; title: ;">print $xml-&gt;feed['id'];</pre>
<p>Pierwszy, główny element <code>rsp</code> jest pomijany w instancji obiektu.</p>
<p style="text-align: center; font-size: 10px;"><img class="iborder" src="http://farm4.static.flickr.com/3601/3279482457_2255ac2de9_o.png" alt="Zasada działania SimpleXMLElement na podstawie kodu pobierania liczby subskrybentów" style="height: 230px;" /><br />Zasada działania SimpleXMLElement na podstawie kodu pobierania liczby subskrybentów.</p>
<h2>Autorska wtyczka finalnym rozwiązaniem naszego problemu!</h2>
<p>I tak oto dochodząc do meritum przedstawiam Wam rozszerzenie uproszczone, ale za to bardziej wzbogacone o trzy, moim zdaniem niezbędne funkcjonalności. <a href="http://dev.m1chu.eu/index.php?title=Easy_Feed_Counter"  title="Easy Feed Counter"><strong>Easy Feed Counter</strong></a> posiada możliwość łatwej instalacji i konfiguracji poprzez panel administratora. Proces wdrażania tego pluginu jest adekwatny do dodawania opisywanego wcześniej <strong>FeedCount</strong> (jest także dokładnie opisany w linku powyżej w repozytorium modyfikacji). Pozwala on na ustawienie serwera feedów, metody pobierania statystyk oraz wpisanie nazwy konta kanału RSS na FeedBurner&#8217;ze. Opcjonalnie możecie także dodać konto komentarzy na tym serwisie, o ile takowe posiadacie.</p>
<p style="text-align: center; font-size: 10px;"><img class="iborder" src="http://farm4.static.flickr.com/3302/3279600765_6edbcf3db2_o.png" alt="Rezultaty działania wtyczki" style="height: 171px;" /><br />Rezultaty działania wtyczki.</p>
<p>Rozwiązanie to ma także jeden wielki, dodatkowy atut. Nie formatuje jak inne pluginy zwracanej treści, a ogranicza się do podania wartości (liczby użytkowników), bądź kodu błędu (<strong>n/d</strong>). To pozwala na szersze modyfikacje położenia bądź wyglądu wyników po wywołaniu funkcji <code>easyfeedcounter_get([opcjonalny: parametr])</code> bez dodatkowej ingerencji w sam kod rozszerzenia.</p>
<pre class="brush: php; title: ;">&lt;?php
if (function_exists('easyfeedcounter_get'))
{
	$subscribers = easyfeedcounter_get(1); // argument o wartości 1 wskazuje wtyczce, że ma zwrócić dane dotyczące komentarzy
	if ( is_numeric($subscribers) !== false ) // brak błędów
	{
		print $subscribers . ' osób subskrybuje aktualnie Twoje komentarze!';
	}
}
?&gt;</pre>
<p>Bardziej skrupulatne objaśnienie, opisane krok po kroku znajdziecie w moim <a href="http://dev.m1chu.eu/index.php?title=Easy_Feed_Counter"  title="Easy Feed Counter">repozytorium</a>. W przypadku wątpliwości dotyczących tematu, bądź instalacji tego tworu proszę śmiało pytać :]</p>
]]></content:encoded>
			<wfw:commentRss>http://m1chu.eu/2009/02/15/jak-wyizolowac-liczbe-subskrybentow-rss-korzystajac-z-feedburnera/feed/</wfw:commentRss>
		<slash:comments>1</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 &#8222;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; title: ;">&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; title: ;">&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; title: ;">/* 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; title: ;">	&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; title: ;">		&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; title: ;">$(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; title: ;">$(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; title: ;">&lt;p id=&quot;test&quot;&gt;Prototype&lt;/p&gt;</pre>
<pre class="brush: jscript; title: ;">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; title: ;">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; title: ;">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; title: ;">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>5</slash:comments>
		</item>
		<item>
		<title>Pozycjonujemy za pomocą kaskadowego arkusza stylów (CSS)</title>
		<link>http://m1chu.eu/2009/01/08/pozycjonujemy-za-pomoca-kaskadowego-arkusza-stylow-css/</link>
		<comments>http://m1chu.eu/2009/01/08/pozycjonujemy-za-pomoca-kaskadowego-arkusza-stylow-css/#comments</comments>
		<pubDate>Wed, 07 Jan 2009 23:14:44 +0000</pubDate>
		<dc:creator>m1chu</dc:creator>
				<category><![CDATA[(x)HTML]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[Webhosting]]></category>
		<category><![CDATA[absolute]]></category>
		<category><![CDATA[clip]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[fixed]]></category>
		<category><![CDATA[float]]></category>
		<category><![CDATA[position]]></category>
		<category><![CDATA[pozycjonowanie]]></category>
		<category><![CDATA[relative]]></category>
		<category><![CDATA[static]]></category>

		<guid isPermaLink="false">http://m1chu.eu/?p=956</guid>
		<description><![CDATA[Pozycjonowanie najczęściej kojarzy się wszystkim z optymalizacją stron w taki sposób, aby uzyskać jak najwyższe miejsce w wyszukiwarkach, pod zadanymi frazami. W skrócie &#8211; z SEO (Search Engine Optimization). W procesie tworzenia stron internetowych, a dokładniej w trakcie opisywania formy wyświetlania strony poprzez arkusz stylów pojęcie te przyjmuje zgoła inne znaczenie. A mianowicie jest to [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: center;"><img class="iborder" src="http://farm2.static.flickr.com/1137/3174553434_0d9c5ff2d0_o.png" alt="Pozycjonowanie elementów w CSS" style="height: 119px;" /></p>
<p>Pozycjonowanie najczęściej kojarzy się wszystkim z optymalizacją stron w taki sposób, aby uzyskać jak najwyższe miejsce w wyszukiwarkach, pod zadanymi frazami. W skrócie &#8211; z <a target="_blank" href="http://utnij.eu/seo-wiki/"  title="SEO Wiki">SEO (Search Engine Optimization)</a>. W procesie tworzenia stron internetowych, a dokładniej w trakcie opisywania formy wyświetlania strony poprzez arkusz stylów pojęcie te przyjmuje zgoła inne znaczenie. A mianowicie jest to metoda tworzenia układu strony poprzez użycie właściwości <code>position</code>. Za namową kilku użytkowników <strong>Vivee</strong> przedstawię dziś na czym właśnie ta metoda polega&#8230;</p>
<p><span id="more-956"></span></p>
<div class="explain">Właściwością CSS określającą położenie elementów w oknie przeglądarki jest <code>position</code>. Może ona przyjąć pięć wartości działających zgodnie w przeglądarkach od wersji <strong>Mozilla Firefox 0.1+</strong>, <strong>Opera 4.0+</strong>, <strong>Safari 3</strong> oraz <strong>IE 7</strong>. Wszystkie są zgodne z specyfikacją <strong>CSS 2.0+</strong>:</p>
<ul>
<li><strong>static</strong> &#8211; wartość domyślna przyjmowana kiedy dla danego obiektu nie zostanie przypisana żadna wartość <code>position</code>. Wartość ta określa standardowe, statyczne rozmieszczenie fragmentów strony &#8211; tzn., od góry do dołu i od lewej do prawej. Można je w łatwy sposób umieszczać szeregowo tworząc z nich elementy liniowe (za pomocą <code>display: inline;</code>), a także równolegle, jeden pod drugim tworząc z nich elementy blokowe (<code>display: block;</code>).</li>
<li><strong>relative</strong> &#8211; powoduje zastosowanie pozycjonowania relatywnego względem elementu nadrzędnego. Obiekt może zmienić pozycję za pomocą dodatkowych właściwości <code>left</code> i <code>top</code>, nie mniej jednak elementy sąsiadujące zachowywać się będą tak jakby on nadal był na swoim pierwotnym miejscu. W praktyce jednak dodatkowych właściwości się najczęściej nie używa, gdyż rozwarstwiają one stronę tworząc kilka osobnych układów. Najczęściej stosowane w połączeniu z pozycjonowaniem absolutnym (<code>absolute</code>), gdzie element relatywny jest kontenerem (obiektem zawierającym, rodzicem), a absolutny jego zawartością.</li>
<li><strong>absolute</strong> &#8211; blok rozmieszczany jest absolutnie względem elementu nadrzędnego, którym domyślnie jest <code>body</code>. Kontenerem nadrzędnym może zostać każdy fragment z nadaną wartością <code>position</code> inną niż <code>static</code>. Wymaga nadania dodatkowych właściwości <code>left</code> i/lub <code>right</code> i/lub <code>top</code> i/lub <code>bottom</code>. Obiekt z taką wartością jest wyrzucany z biegu dokumentu (tworzona jest nowa warstwa).</li>
<li><strong>fixed</strong> &#8211; pozycjonowanie względem okna przeglądarki. Wymaga nadania dodatkowych właściwości <code>left</code> i/lub <code>right</code> i/lub <code>top</code> i/lub <code>bottom</code>.</li>
<li><strong>inherit</strong> &#8211; przejmuje wartość rodzica.</li>
</ul>
<p>Dodatkowe, wyżej wspomniane właściwości to:</p>
<ul>
<li><code>left</code> przyjmująca wartość będącą odległością od lewej krawędzi elementu nadrzędnego.</li>
<li><code>bottom</code> &#8211; wartość jako odległość od dolnej krawędzi elementu nadrzędnego.</li>
<li><code>right</code> &#8211; odległość od prawej krawędzi kontenera.</li>
<li><code>top</code> &#8211; odległość od górnej krawędzi kontenera.</li>
</ul>
<p>Przykład:</p>
<pre class="brush: css; title: ;">#absolutnieSpozycjonowanyElement {
	position: absolute;
	width: 150px;
	height: 150px;
	left: 150px;
	top: 150px;
}</pre>
</div>
<h2>Spoglądamy kątem oka na statyczne pozycjonowanie&#8230;</h2>
<p>Najprostszym przykładem zobrazowania tego przykładu będzie utworzenie dwóch szeregowych elementów, a pod nimi jeszcze jednego o szerokości dwóch powyższych.</p>
<p style="text-align: center;"><img class="iborder" src="http://farm4.static.flickr.com/3421/3176978234_37339eaabd_o.png" alt="Pozycjonowanie statyczne w CSS" style="height: 300px;" /></p>
<p>Na takim edukacyjnym szablonie będziemy opierać się we wszystkich metodach. W tej tradycyjnej, statycznie aby uzyskać powyższy efekt musimy <code>#left</code> i <code>#right</code> wyświetlić liniowo (w tym wypadku <code>display: inline;</code>, ale w innych może to być np. <code>display: table-cell;</code>, itp.), a <code>#bottom</code> blokowo (<code>display: block;</code>).</p>
<pre class="brush: xml; title: ;">&lt;div id=&quot;left&quot;&gt;#left&lt;/div&gt;
&lt;div id=&quot;right&quot;&gt;#right&lt;/div&gt;
&lt;div id=&quot;bottom&quot;&gt;#bottom&lt;/div&gt;</pre>
<p>Moglibyśmy dwa pierwsze tagi <code>div</code> umieścić w jednym innym, który byłby blokiem. W praktyce się to przydaje, w przedstawianej teorii nie ma jednak takiej potrzeby. Ponieważ jednak <code>#left</code> i <code>#right</code> są fragmentami liniowymi to nadane im szerokości w arkuszu nie będą odpowiadać realnie wyświetlanym rozmiarom. Z tego powodu skorzystamy z właściwości <code>float</code>.</p>
<div class="explain"><code>float</code> &#8211; tworzy obiekty pływające w celu otoczenia ich przez tekst, bądź tworzenia szeregu kolumn w układzie strony, co wywołane jest własnością przyklejającą obiekty do siebie względem lewej lub prawej krawędzi (<a target="_blank" href="http://utnij.eu/float-position/"  title="Float-position">CSS2+</a>). Powoduje ona utworzenie nowego biegu dokumentu przez elementy z nadanym <code>float</code> przez co nie mogą się one na siebie nakładać. Posiada następujące wartości:</p>
<ul>
<li><strong>left</strong> &#8211; umieszcza obiekt przyklejając go z lewej strony.</li>
<li><strong>right</strong> &#8211; umieszcza element przyklejając go z prawej strony.</li>
<li><strong>none</strong> &#8211; wartość domyślna, element nie jest pływający.</li>
</ul>
</div>
<p>W takim wypadku jednak stworzenie z <code>#bottom</code> obiektu blokowego nie spowoduje przeniesienia go do nowej linii. Musimy wprowadzić elementy z <code>float</code> z powrotem do biegu dokumenty, do czego służy <code>clear</code>.</p>
<div class="explain"><code>clear</code> definiuje położenie nowego akapitu. Rozwijane od <a target="_blank" href="http://utnij.eu/flow-control/"  title="Flow-control">CSS1+</a>. Przyjmuje wartości:</p>
<ul>
<li><strong>none</strong> &#8211; domyślna flaga, nie powoduje zmian.</li>
<li><strong>left</strong> &#8211; następna linia znajdzie się za elementami położonymi z lewej strony (w poruszanym temacie: <code>float: left;</code>).</li>
<li><strong>right</strong> &#8211; kolejna linia znajdzie się za elementami położonymi z prawej strony (<code>float: right;</code>).</li>
<li><strong>both</strong> &#8211; nastąpi bezprecedensowe przejście do nowej linii (bez znaczenia na wartość <code>float</code>).</li>
<li><strong>inherit</strong> &#8211; przejmuje wartość rodzica.</li>
</ul>
</div>
<p>No i ostatecznie nadając margines szerokości i wysokości <strong>50 pikseli</strong> otrzymujemy finalny kod prezentujący układ jak na obrazku:</p>
<pre class="brush: css; title: ;">* { /* usuniecie marginesow i paddingu */
	margin: 0px;
	padding: 0px;
}
html, body {
	color: #DEDBD1;
	font-size: 12px;
	font-family: Verdana, Tahoma, Arial;
	background-color: #F6F7EE;
}
body {
	margin: 50px; /* ustawienie marginesu na 50px */
}
div#left {
	width: 198px; /* szerokosc -2 px z powodu nadania obramowania o szerokosci 1px */
	height: 148px; /* wysokosc -2 px z powodu nadania obramowania o szerokosci 1px */
	display: inline; /* liniowy element */
	float: left; /* stworzenie elementu plywajacego z lewej strony */
	border: 1px solid #DEDBD1;
	background-color: #F6F7EE;
}
div#right {
	height: 148px; /* wysokosc -2 px z powodu nadania obramowania o szerokosci 1px */
	width: 198px; /* szerokosc -2 px z powodu nadania obramowania o szerokosci 1px */
	float: left; /* stworzenie elementu plywajacego z lewej strony */
	display: inline; /* liniowy element */
	border: 1px solid #DEDBD1;
	background-color: #F6F7EE;
}
div#bottom {
	width: 398px; /* szerokosc -2 px z powodu nadania obramowania o szerokosci 1px */
	display: block; /* element blokowy */
	height: 148px; /* wysokosc -2 px z powodu nadania obramowania o szerokosci 1px */
	border: 1px solid #DEDBD1;
	clear: left; /* usuniecie oplywania dla float: left;, przejscie do nowej linii */
	background-color: #F6F7EE;
}</pre>
<p>I oto <a href="http://use.m1chu.eu/-css/positioning-elements/index_static_float.html"  title="Statyczne pozycjonowanie z float"><strong>rezultat</strong></a>, jaki otrzymamy po złożeniu całego kodu.</p>
<h2>Position relative i position absolute!</h2>
<p>Ponieważ najczęściej, albo korzysta się z samotnego <code>position: absolute;</code> lub z łączenia <code>position: relative;</code> z <code>position: absolute;</code> to zajmiemy się tymi dwoma przypadkami, tylko i wyłącznie.</p>
<p>Jak już wspomniałem standardowym kontenerem części układu strony z nadanym <code>position: absolute;</code> jest ciało strony (<code>body</code>). Przykładowo:</p>
<pre class="brush: css; title: ;">div#pozycjonowanieAbsolutne {
	position: absolute /* wzgledem body */
	left: 10%; /* 10% szerokosci ciala strony zostanie odsuniety div o tym identyfikatorze */
	top: 500px;
}</pre>
<p>Spowoduje to umieszczenie na nowej warstwie (po za biegiem statycznym dokumentu) <code>div</code> w odległości <strong>500 pikseli</strong> od górnej krawędzi ciała strony i <strong>10 procent</strong> szerokości <code>body</code> od jego lewej krawędzi.</p>
<p>Tego typu model rozmieszczania elementów ma jeden dodatkowy atut. Pozwala na rozciąganie oraz przycinanie pozycjonowanych w taki sposób obiektów.</p>
<p>Pierwszą funkcjonalność otrzymamy operując na dodatkowych właściwościach określających położenie obiektu. Wystarczy podać wartości <code>left</code> i <code>right</code>, aby dokonać rozszerzenia i/lub nadać <code>top</code> i <code>bottom</code> w celu dokonania wydłużenia. <a href="http://use.m1chu.eu/-css/positioning-elements/index_abs_en.html"  title="Absolutnie pozycjonowany, rozszerzony obiekt"><strong>Przykładowy kod</strong></a>:</p>
<pre class="brush: css; title: ;">div {
	position: absolute; /* rozmieszczanie absolutne wzgledem relatywnego, nadrzednego rodzica */
	left: 50px; right: 50px; /* rozszerzenie: 50px od lewej krawedzi, az do 50px z prawej krawedzi rodzica */
	bottom: 10%; top: 15%; /* wydłuzenie od gornej odleglosci 10% dlugosci ciala strony, do dolnej krawedzi oddalonej o 15% dlugosci strony */
}</pre>
<div class="explain"><code>clip</code> &#8211; określa widoczną przestrzeń o kształtach prostokątnych. Zgodne z <a target="_blank" href="http://utnij.eu/propdef-clip/"  title="Clip">CSS2+</a>. Parametry:</p>
<ul>
<li><strong>auto</strong> &#8211; domyślny, cały element jest widoczny.</li>
<li><strong>rect(top, right, bottom, left)</strong> &#8211; określa krawędzie widoczności obiektu. Wg. specyfikacji wartością jest <strong>shape(wartości)</strong>, ale zarówno w <strong>CSS2</strong> i <strong>CSS2.1</strong> został zaimplementowany tylko kształt prostokąta (<strong>rect</strong>).</li>
<li><strong>inherit</strong> &#8211; przejmuje wartość rodzica.</li>
</ul>
<p>Przykład:</p>
<pre class="brush: css; title: ;">#e {
	position: absolute;
	clip: rect(0px, 10px, 10px, 0px); /* kwadrat o krawedziach 10x10px */
}</pre>
<p>Zobrazowanie:</p>
<p style="text-align: center;"><img src="http://farm4.static.flickr.com/3324/3176726733_1c13196b23_o.png" alt="Zobrazowanie działania przykładu z clip" /></p>
</div>
<p>Drugą funkcjonalność otrzymamy poprzez użycie <code>clip</code>. Chcąc absolutny fragment skrócić według rozmiarów <strong>x</strong>, <strong>y</strong> o połowę patrząc z punktu <strong>0</strong> możemy posłużyć się <a href="http://use.m1chu.eu/-css/positioning-elements/index_abs_clip.html"  title="Absolutnie pozycjonowany, przycięcie"><strong>następującym kodem</strong></a>:</p>
<pre class="brush: css; title: ;">div {
	position: absolute; /* rozmieszczanie absolutne wzgledem relatywnego, nadrzednego rodzica */
	left: 50px;
	bottom: 10%;
	width: 300px; /* szerokosc */
	height: 500px; /* wysokosc */
	/*
		top: 		krawedz gorna przyciecia w miejscu krawedzi gornej div;
		right: 		krawedz prawa przyciecia w polowie szerokosci div;
		bottom:		krawedz dolna przyciecia w polowie wysokosci div;
		left:		krawedz lewa przyciecia w miejscu krawedzi lewej div;
	*/
	clip: rect(0px, 150px, 250px, 0px);
}</pre>
<p>Pora przejść do konteneryzacji elementów absolutnie ustawianych w ciele dokumentu. Jak już wspomniałem służy do tego <code>position: relative;</code> które należy ustawić na rodzicu będącym dzieckiem <code>body</code> lub innego obiektu potomnego ciała dokumentu.</p>
<pre class="brush: xml; title: ;">&lt;div&gt;
	&lt;div id=&quot;left&quot;&gt;#left&lt;/div&gt;
	&lt;div id=&quot;right&quot;&gt;#right&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;bottom&quot;&gt;#bottom&lt;/div&gt;</pre>
<p>Będziemy starali się osiągnąć rezultat jak w przykładzie tradycyjnego ułożenia strony. Posłuży nam do tego powyższa struktura, która różni się tylko tym, że pierwsze dwa (w poprzednim paragrafie liniowe) elementy <code>div</code> opatrzyliśmy w jeden kontener (który będzie pozycjonowany relatywnie w tym przypadku).</p>
<pre class="brush: css; title: ;">* { /* usuniecie marginesow i paddingu */
	margin: 0px;
	padding: 0px;
}
html, body {
	color: #DEDBD1;
	font-size: 12px;
	font-family: Verdana, Tahoma, Arial;
	background-color: #F6F7EE;
}
div:first-child { /* :first-child - klasa okreslajaca pierwszy element div u danego rodzica */
	position: relative; /* pozycjonowanie relatywne */
	width: 450px; /* szerokosc potomkow + left */
	height: 200px; /* wysokosc potomkow + top */
}
div#left {
	position: absolute; /* pozycjonowanie absolutne wzgledem relatywnego, nadrzednego rodzica */
	left: 50px; /* odleglosc od lewej krawedzi diva - rodzica */
	top: 50px; /* odleglosc od gornej krawedzi diva - rodzica */
	width: 198px; /* szerokosc -2 px z powodu nadania obramowania o szerokosci 1px */
	height: 148px; /* wysokosc -2 px z powodu nadania obramowania o szerokosci 1px */
	border: 1px solid #DEDBD1;
	background-color: #F6F7EE;
}
div#right {
	position: absolute; /* pozycjonowanie absolutne wzgledem relatywnego, nadrzednego rodzica */
	left: 250px; /* odleglosc od lewej krawedzi diva - rodzica, szerokosc div#left + left div#left */
	top: 50px; /* odleglosc od gornej krawedzi diva - rodzica, wysokosc div#left + top div#left */
	height: 148px; /* wysokosc -2 px z powodu nadania obramowania o szerokosci 1px */
	width: 198px; /* szerokosc -2 px z powodu nadania obramowania o szerokosci 1px */
	border: 1px solid #DEDBD1;
	background-color: #F6F7EE;
}
div#bottom {
	position: absolute; /* pozycjonowanie absolutne wzgledem ciala strony */
	left: 50px;
	top: 200px; /* odleglosc od gornej krawedzi body, wysokosc rodzica div#left */
	width: 398px; /* szerokosc -2 px z powodu nadania obramowania o szerokosci 1px */
	height: 148px; /* wysokosc -2 px z powodu nadania obramowania o szerokosci 1px */
	border: 1px solid #DEDBD1;
	background-color: #F6F7EE;
}</pre>
<p>Porzuciliśmy typy wyświetlania (<code>display</code>) oraz opływanie (<code>float</code>) w tym listingu, które są zbyteczne w tak prostym rozmieszczeniu, a zarazem przy zastosowaniu w.w. metod umieszczania.</p>
<p>Obiektowi nadrzędnemu, poprzez klasę <code>:first-child</code> nadany jest typ i rozmiary. W blokach jemu potomnych nadane są typy absolutne, rozmiary oraz odległości od lewej i górnej krawędzi. W przypadku <code>#right</code> przesunięcie w prawo w postaci <code>left</code> jest sumą odległości przesunięcia <code>#left</code> i szerokości tego diva (wraz z grubością obramowania). Efekt&#8230; <a href="http://use.m1chu.eu/-css/positioning-elements/index_rel_abs.html"  title="Relatywne i absolutne pozycjonowanie"><strong>identyczny</strong></a> :]</p>
<p>Dla <code>#bottom</code> nie ma już kontenera. W tym wypadku chciałem pokazać jak rozmieszczać absolutnie z rodzicem w postaci ciała strony. Tym razem to pozycja od górnej krawędzi <code>body</code> jest równa wysokości relatywnego elementu zawierającego <code>#left</code> i <code>#right</code>.</p>
<p>Co należy pamiętać, że elementy tabel nie mogą być relatywne, a absolutne pozycjonowanie nie działa względem ich treści.</p>
<h2>Tworzymy nieruchomą stopkę za pomocą rozmieszczenia ustalonego (fixed)</h2>
<p>Za pomocą <code>position: absolute;</code> możemy umieścić stopkę na dole <strong>nieprzewijalnej</strong> strony stosując atrybuty <code>left</code> / <code>right</code> i <code>bottom</code>. W przypadku tradycyjnej, statycznej metody możemy stopkę umieścić w dolnych częściach <strong>każdej</strong> odpowiednio układając bloki, jeden nad drugim. Niekiedy jednak może zdarzyć się, że chcielibyśmy takowy &#8222;footer&#8221; przykleić do dolnej krawędzi okna przeglądarki bez względu, czy treść strony możemy <strong>przewijać</strong>, czy nie. O tego typu rzeczy pytali właśnie czytelnicy&#8230;</p>
<p>Rozmieszczanie ustalone, oznaczane jako <code>position: fixed;</code> działa podobnie jak absolutne, tylko że umiejscawiane obiekty są przyklejane do okna przeglądarki. Bez względu, czy mamy możliwość przewijania treści strony to one zawsze pozostają w stałym miejscu na ekranie. Typ ten jest także podatny na rozciąganie (<code>left</code> i <code>right</code> oraz <code>bottom</code> i <code>top</code>) i przycinanie (<code>clip</code>).</p>
<pre class="brush: xml; title: ;">&lt;div id=&quot;left&quot;&gt;#left&lt;/div&gt;
&lt;div id=&quot;right&quot;&gt;#right&lt;/div&gt;
&lt;div id=&quot;bottom&quot;&gt;#bottom&lt;/div&gt;
&lt;div id=&quot;footer&quot;&gt;#footer&lt;/div&gt;
&lt;div id=&quot;down&quot;&gt;#down&lt;/div&gt;</pre>
<p>Dodałem dodatkowo elementy o id <strong>footer</strong>, aby pokazać w jaki sposób można przykleić stopkę, a także <strong>down</strong> dzięki któremu w przykładzie będzie można przewijać przeglądany dokument.</p>
<pre class="brush: css; title: ;">* { /* usuniecie marginesow i paddingu */
	margin: 0px;
	padding: 0px;
}
html, body {
	color: #DEDBD1;
	font-size: 12px;
	font-family: Verdana, Tahoma, Arial;
	background-color: #F6F7EE;
}
div#left {
	position: fixed; /* pozycjonowanie ustalone względem okna przeglądarki */
	left: 50px; /* odleglosc od lewej krawedzi diva - rodzica */
	top: 50px; /* odleglosc od gornej krawedzi diva - rodzica */
	width: 198px; /* szerokosc -2 px z powodu nadania obramowania o szerokosci 1px */
	height: 148px; /* wysokosc -2 px z powodu nadania obramowania o szerokosci 1px */
	border: 1px solid #DEDBD1;
	background-color: #F6F7EE;
}
div#right {
	position: fixed; /* pozycjonowanie ustalone */
	left: 250px; /* odleglosc od lewej krawedzi diva - rodzica, szerokosc div#left + left div#left */
	top: 50px; /* odleglosc od gornej krawedzi diva - rodzica, wysokosc div#left + top div#left */
	height: 148px; /* wysokosc -2 px z powodu nadania obramowania o szerokosci 1px */
	width: 198px; /* szerokosc -2 px z powodu nadania obramowania o szerokosci 1px */
	border: 1px solid #DEDBD1;
	background-color: #F6F7EE;
}
div#bottom {
	position: fixed; /* pozycjonowanie ustalone */
	left: 50px;
	top: 200px; /* odleglosc od gornej krawedzi body, wysokosc rodzica div#left */
	width: 398px; /* szerokosc -2 px z powodu nadania obramowania o szerokosci 1px */
	height: 148px; /* wysokosc -2 px z powodu nadania obramowania o szerokosci 1px */
	border: 1px solid #DEDBD1;
	background-color: #F6F7EE;
}
div#footer {
	position: fixed; /* pozycjonowanie ustalone */
	left: 50px; right: 50px; /* rozciagniecie */
	bottom: 0px; /* odleglosc od gornej krawedzi body, wysokosc rodzica div#left */
	height: 50px; /* wysokosc -2 px z powodu nadania obramowania o szerokosci 1px */
	border: 1px solid #DEDBD1;
	border-bottom: 0px;
	background-color: #F6F7EE;
}
div#down {
	position: absolute;
	left: 50px;
	top: 2500px;
}</pre>
<p>Jeżeli przewiniecie stronę w dół, a później w górę zauważycie, że elementy nie zanikają i nie pojawiają się. To cecha tej metody. I praktycznie jedyna różnica względem <code>position: absolute;</code>, bo użycie w arkuszu jest jak widać prawie identyczne.</p>
<p>Ważnym jest także, aby usunąć wszelkie marginesy i paddingi z wbudowanych elementów drzewa dokumentu. Chodzi tutaj o <code>html</code> i <code>body</code>. Jeżeli tego nie zrobimy to w różnych przeglądarkach możemy otrzymać różny wynik przykładów, a w przyszłości tworzonych przez nas stron. Jedne fragmenty mogą zaczynać się w innym miejscu niż inne, pomimo że np. nadaliśmy wszystkim ten sam odstęp od lewej (<code>left</code>) i górnej (<code>top</code>) krawędzi kontenera. W swoich paragrafach robiłem to za pomocą <code>*</code>.</p>
<pre class="brush: css; title: ;">* { /* usuniecie marginesow i paddingu */
	margin: 0px;
	padding: 0px;
}</pre>
<h2>A gdybyśmy to tak wszystko połączyli&#8230;</h2>
<p>To w jednym z najprostszych, tworzonych czysto do nauki przykładów otrzymalibyśmy <a href="http://use.m1chu.eu/-css/positioning-elements/"  title="Łączenie absolutnego, statycznego, relatywnego i ustalonego pozycjonowania"><strong>coś takiego</strong></a>. Zapraszam do źródła i miłego czytania :]</p>
<p><span style="font-size: 9px;">&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
(<strong>*</strong>) zamiast frazy <strong>element</strong> w tekście zostały użyte także ogólne synonimy <strong>obiekt</strong> i <strong>fragment</strong>.<br />
(<strong>**</strong>) zamiast frazy <strong>pozycjonowanie</strong> użyto w tekście także synonimu <strong>rozmieszczenie</strong>.</span></p>
]]></content:encoded>
			<wfw:commentRss>http://m1chu.eu/2009/01/08/pozycjonujemy-za-pomoca-kaskadowego-arkusza-stylow-css/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
	</channel>
</rss>

