<?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>MGdevelop</title>
	<atom:link href="http://mgdevelop.pl/index.php/feed/" rel="self" type="application/rss+xml" />
	<link>http://mgdevelop.pl</link>
	<description>Programming is an art form that fights back</description>
	<lastBuildDate>Thu, 07 Jul 2011 16:59:51 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.3</generator>
		<item>
		<title>Uploader plików z wykorzystaniem HTML5</title>
		<link>http://mgdevelop.pl/index.php/2011/06/uploader-plikow-z-wykorzystaniem-html5/</link>
		<comments>http://mgdevelop.pl/index.php/2011/06/uploader-plikow-z-wykorzystaniem-html5/#comments</comments>
		<pubDate>Tue, 21 Jun 2011 17:37:47 +0000</pubDate>
		<dc:creator>Elektryk</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[drag&drop]]></category>
		<category><![CDATA[FileReader]]></category>
		<category><![CDATA[html5]]></category>
		<category><![CDATA[plik]]></category>
		<category><![CDATA[upload]]></category>

		<guid isPermaLink="false">http://mgdevelop.pl/?p=609</guid>
		<description><![CDATA[Swego czasu problemem dla twórców stron internetowych było wysyłanie plików bez przeładowywania strony. Mieliśmy do wyboru albo użyć apleta flash albo szpecić... <a href="http://mgdevelop.pl/index.php/2011/06/uploader-plikow-z-wykorzystaniem-html5/">Czytaj dalej&#187;</a>]]></description>
			<content:encoded><![CDATA[<p>Swego czasu problemem dla twórców stron internetowych było wysyłanie plików bez przeładowywania strony. Mieliśmy do wyboru albo użyć <a title="Zewnętrzny odnośnik" rel="nofollow external" href="http://www.uploadify.com/">apleta flash</a> albo <a title="Zewnętrzny odnośnik" rel="nofollow external" href="http://www.openjs.com/articles/ajax/ajax_file_upload/">szpecić swój kod iframami</a>. Czasy na szczęście się zmieniają i powstają nowe technologie które to pozwalają na coraz więcej. Aktualnie nowoczesne przeglądarki udostępniają obiekt<em>File</em> z poziomu kodu JS który w połączeniu z ajaxem pozwala stworzyć uploader plików dorównujący możliwościami tym flashowym lub javowym.<span id="more-609"></span></p>
<h1>Stawiamy cele</h1>
<p>Najpierw postaram się omówić co będę chciał zbudować w tym tutorialu. Moim celem jest napisanie uploadera który będzie w przeglądarkach Chrome i Firefox zastępować tradycyjny HTMLowy formularz. Nasz skrypt bedzie przyjmował pliki metodą <a title="Zewnętrzny odnośnik" rel="nofollow external" href="http://pl.wikipedia.org/wiki/Przeci%C4%85gnij_i_upu%C5%9B%C4%87">drag &amp; drop</a> i wyświetlał ich listę w postaci kontenerów. Po wykryciu, że internauta trzyma pliki nad przeglądarką nastąpi zachęcenie go do upuszczenia ich w odpowiednim miejscu poprzez podmianę napisu. Każdy kontener zaś będzie wyświetlał nazwę wybranego pliku, miniaturkę jeśli wybrany plik jest grafiką lub ewentualnie ikonkę zastępczą, pole tekstowe gdzie można dodać opis oraz przycisk wysyłania. Kontener będzie zawierał także przycisk usuwający dany plik z listy do wysłania oraz pole na wyświetlanie komunikatów. W momencie kliknięcia przycisku wysłania sam przycisk zniknie (aby użytkownik nie wysłał kilka razy tego samego pliku) i pojawi się w razie nie udanego uploadu. Każdorazowa próba wysłania spowoduje wyświetlenie odpowiedniego napisu w polu komunikatów. Jeśli chodzi o przesłane pliki to będą one zapisywane pod ustawionym adresem a opisy do nich będą lądować w pliku tekstowym o nazwie <em>&lt;nazwa pliku&gt;.txt</em>.</p>
<p><a title="Zewnętrzny odnośnik" rel="nofollow external" href="http://example.mgdevelop.pl/uploadhtml5/">Wersja demonstracyjna skryptu (nie zapisuje plików na serwerze)</a></p>
<p>Gotowiec do pobrania na dole strony.</p>
<h1>Kod HTML</h1>
<p>Zacznijmy od napisania kodu tradycyjnego formularza:</p>
<pre class="brush:html">&lt;div id="uploadHTML"&gt;
    &lt;form enctype="multipart/form-data" action="uploadHtml.php" method="POST"&gt;
        &lt;input name="upload" type="file" /&gt;
        &lt;input value="Wyślij" type="submit" /&gt;
    &lt;/form&gt;
&lt;/div&gt;</pre>
<p>Ważne jest by objąć tą część kodu w blok z nadaną klasą <em>uploadHTML</em> gdyż później będziemy usuwać stary typ formularz poprzez odwołanie się do tej klasy. Podobny blok tworzymy dla naszego nowoczesnego uploadera:</p>
<pre class="brush:html">&lt;div id="uploadJS" style="display: none"&gt;
    //tu dalsza część kodu
&lt;/div&gt;</pre>
<p>Teraz wrzucamy do niego dwa elementy. Pole gdzie użytkownik ma upuścić plik:</p>
<pre class="brush:html">&lt;div class="uploader" id="uploader"&gt;
    Przenieś tu pliki które chcesz&lt;br /&gt;wysłać na serwer
&lt;/div&gt;</pre>
<p>oraz miejsce na listę plików do wysłania na serwer:</p>
<pre class="brush:html">&lt;div class="uploadList"&gt;
    //tu dalsza część kodu
&lt;/div&gt;</pre>
<p>Do tego diva wstawimy teraz przykładowy element a następnie go schowamy. Będzie to szablon dla skryptu jak mają wyglądać nowe elementy na liście.</p>
<pre class="brush:html">&lt;div id="uploadFileTemplate" class="uploadFile"&gt;
    &lt;div class="header"&gt;
        &lt;div class="name"&gt;Nazwa pliku.jpg&lt;/div&gt;
        &lt;div class="delete"&gt;×&lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="thumb"&gt;
        &lt;img src="file.png" alt="Miniaturka" class="image" /&gt;
    &lt;/div&gt;
    &lt;div class="info"&gt;
        &lt;textarea name="description"&gt;&lt;/textarea&gt;
        &lt;p class="alert"&gt;&lt;/p&gt;
        &lt;input type="hidden" name="file" value=""&gt;
        &lt;div id="startUpload" class="submit"&gt;Wyślij plik&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;</pre>
<p>W powyższym nie trzeba raczej niczego tłumaczyć po za tym, że div z id <em>startUpload</em> będzie przyciskiem który rozpocznie upload a zaś plik file.png jest naszą domyślną ikonką. Aby szablon był niewidoczny dla użytkownika w arkuszu CSS piszemy:</p>
<pre class="brush:css">#uploadFileTemplate{
        display: none;
}</pre>
<h1>A teraz Javascript</h1>
<p>Po pierwsze dołączymy do naszego kodu bibliotekę <a title="Zewnętrzny odnośnik" rel="nofollow external" href="http://jquery.com/">jQuery</a> ponieważ dla łatwości pisania najlepiej będzie oprzeć nasz skrypt na tym frameworku.</p>
<pre class="brush:javascript">&lt;script type="text/javascript" src="http://code.jquery.com/jquery-1.6.1.min.js"&gt;&lt;/script&gt;</pre>
<p>Teraz zdefiniujemy parę zmiennym których użycie będę wyjaśniał później oraz napiszemy instrukcję która zapewni nam, że nasz kod nie wykona się za nim wszystkie elementy strony nie będą załadowane.</p>
<pre class="brush:javascript">var ePage;
var eDropPlace;
var eStartUpload;
var filesToUpload;
var newId;
var idi = 0;

$(document).ready(function(){
    //tu dalsza część kodu
});</pre>
<p>Wewnątrz tego kodu umieszczamy teraz instrukcję warunkową która wyświetli nasz uploader w przeglądarkah obsługujących wykorzystywane przez nas technologie:</p>
<pre class="brush:javascript">if (window.File &amp;&amp; window.FileReader &amp;&amp; window.FileList) {
    $("#uploadHTML").remove();
    $("#uploadJS").show();
    ePage               = document.getElementsByTagName('body').item(0);
    eDropPlace          = document.getElementById("uploader");
    //tu dalsza część kodu
}</pre>
<p>Powyższy kod działa w ten sposób, że sprawdzane jest czy przeglądarka obsługuje używane przez nas obiekty <em>File</em>, <em>FileReader</em> oraz <em>FileList</em>. Jeśli tak to usuwamy tradycyjny formularz a wyświetlamy ten nasz. Po tej operacji możemy już pobrać referencje do dwóch ważnych obiektów w naszym kodzie. <em>ePage</em> to cała nasza strona dla której będziemy wykrywali czy użytkownik przeniósł pliki nad okno przeglądarki. <em>eDropPlace</em> natomiast to miejsce gdzie użytkownik ma upuścić pliki. Mogłoby być to to samo miejsce ale w tym tutorialu zrobimy rozróżnienie aby lepiej wytłumaczyć czym to się różni.</p>
<h1>Zdarzenia ondragover i ondragleave</h1>
<p>Teraz poniżej tego (ale przed nawiasem klamrowym) dodamy obsługę zdarzeń. Po pierwsze obsłużmy przeniesienie plików nad przeglądarkę:</p>
<pre class="brush:javascript">ePage.ondragover=function(f){
    eDropPlace.innerHTML="Upuśc plik na to pole";
    f.dataTransfer.dropEffect="copy";
    f.preventDefault();
    return false
};</pre>
<p><em>ondragover</em> to właśnie zdarzenie polegające na tym, że użytkownik zaznaczył w folderze pliki i za pomocą myszki przeniósł je nad okno przeglądarki. Jeśli takie coś wykryjemy to zmieniamy treść napisu oraz zmieniamy kursor na informujący, że będziemy kopiować pliki (w Chrome np. przy kursorze pojawia się napis Kopiuj). Metoda<em>preventDefault()</em> natomiast zapewni nam, że przeglądarka nie zacznie się dziwnie zachowywać np. nie będzie zaznaczany tekst podczas przesuwania kursora nad oknem.</p>
<p>Podobne operacje wykonujemy dla zdarzenia przeciwnego czyli <em>ondragleave</em>:</p>
<pre class="brush:javascript">ePage.ondragleave=function(f){
    eDropPlace.innerHTML="Przenieś tu pliki które chcesz&lt;br /&gt;wysłać na serwer";
    f.dataTransfer.dropEffect="copy";
    f.preventDefault();
    return false
};</pre>
<p>Teraz czas na najważniejszą część kodu która obsłuży upuszczenie plików na okno przeglądarki (zdarzenie <em>ondrop</em>) i doda je do listy.</p>
<h1>Zdarzenie ondrop</h1>
<pre class="brush:javascript">ePage.ondrop=function(g){
    g.preventDefault();
    files = g.dataTransfer.files;
    eDropPlace.innerHTML ="Przenieś tu pliki które chcesz&lt;br /&gt;wysłać na serwer";

    //tu dalsza część kodu
}</pre>
<p>Ponownie skorzystaliśmy z metody <em>preventDefault()</em> gdyż przeglądarki domyślnie po upuszczeniu na nie pliku próbują je wyświetlać lub &#8222;ściągnąć&#8221;. Musimy temu zapobiec aby mógł się wykonać dalszy kod. Gdy to już mamy zapewnione to możemy skorzystać z instrukcji <em>g.dataTransfer.files</em> która zwróci nam tablicę obiektów poszczególnych plików. G zostało nam podane jako argument funkcji która wykona się w momencie zajścia zdarzenia <em>ondrop</em>. A jako, że internauta nie trzyma już plików to nie zajdzie zdarzenie <em>ondragleave</em> więc w powyższym kodzie obsługujemy przywrócenie napisu.</p>
<p>Teraz możemy już sobie iterować po tej tablicy i wyciągać kolejne obiekty plików do uploadu:</p>
<pre class="brush:javascript">for(var i = 0, f; f = files[i]; i++){
    var reader=new FileReader();

    //tu dalsza część kodu

    reader.readAsDataURL(f);
}</pre>
<p>Powyższa pętla przypisuje kolejne obiekty plików do zmiennej f, tworzy nowy obiekt klasy <em>FileReader</em> i wczytuje plik do stworzonego obiektu. I teraz naszym zadaniem jest napisanie funkcji która zostanie wykonana gdy cały plik zostanie wczytany (jest on wczytywany asynchronicznie z powodu opóźnienia jakie może wywołać obciążony dysk twardy). Wykonuje się to za pomocą nietypowej konstrukcji która należy umieścić przed użyciem metody <em>readAsDataURL</em>:</p>
<pre class="brush:javascript">reader.onload = (function(theFile) {
    return function(e) {
        //tu dalsza część kodu
    };
})(f);</pre>
<p>Jakkolwiek dziwnie powyższy kod wygląda to nadszedł czas na napisanie funkcji tworzącego nowe elementy na liście. Na początek musimy przyjąć, że każdemu nowemu kontenerowi będziemy nadawać ID wg schematu: <em>file1</em>, <em>file2</em>, <em>file3</em> itd. Realizuje to poniższy kod:</p>
<pre class="brush:javascript">var newId = "file"+idi; idi++;
$(".uploadList").prepend("&lt;div id=\""+newId+"\" class=\"uploadFile\"&gt;"+$("#uploadFileTemplate").html()+"&lt;/div&gt;");</pre>
<p>Jak widać stworzyliśmy nowy kontener, nadaliśmy mu id i skopiowaliśmy do niego nasz szablon z diva <em>uploadFileTemplate</em>. Nowy element pojawi się na liście plików na samej górze dzięki metodzie <a title="Zewnętrzny odnośnik" rel="nofollow external" href="http://api.jquery.com/prepend/">prepend</a> z biblioteki jQuery.</p>
<p>Teraz czas na wypełnienie naszego szablonu i nadaniu zdarzeń dla przycisków:</p>
<pre class="brush:javascript">$("#"+newId+" .header .name").text(theFile.name);

//wrzuca miniatirku zdjęć
if(theFile.type.match(/image.*/))
    $("#"+newId+" .thumb .image").attr("src",e.target.result);</pre>
<p>Obiekt theFile w tym momencie przechowuje informacje i naszym pliku. Pobieramy z niego nazwę pliku (<em>theFile.name</em>) i wpisujemy w odpowiednim miejscu. Dalej sprawdzamy czy nasz plik jest obrazkiem za pomocą <em>theFile.type.match(/image.*/)</em>. Jeśli tak to odczytujemy nasz plik z zmiennej <em>e.target.result</em> i wpisujemy jako atrybut<em>src</em> miniaturki. Plik jest przechowywany w wspomnianej zmiennej w formacie <a title="Zewnętrzny odnośnik" rel="nofollow external" href="http://pl.wikipedia.org/wiki/Base64">base64</a>. Polecam kliknąć na tak wyświetloną grafikę PPM i wybrać opcję <em>Pokaż obrazek</em>. Zobaczymy wtedy w pasku adresu jak wygląda grafika w takim kodowaniu.</p>
<pre class="brush:javascript">//zapisuje plik do pola tekstowego
$("#"+newId+" input[name=\"file\"]").val(e.target.result.split(",")[1]);

//obsługa usuwania pliku
$("#"+newId+" .delete").click(function(z){
    $("#"+newId).remove();
});

//obsługa wysyłania
$("#"+newId+" #startUpload").click(function(z){
    trySendFile(newId);
});</pre>
<p>Wracając do naszego szablonu to teraz znowu musimy odczytać nasz plik i zapisać go do pola tekstowego o nazwie <em>file</em>. Teraz jednak przypiszemy tylko sam kod bez informacji o typie kodowania. Przy użyciu javascriptowej metody <a title="Zewnętrzny odnośnik" rel="nofollow external" href="https://developer.mozilla.org/en/Javascript/Reference/Global_Objects/String/split">split</a> wytniemy zbędny w tym przypadku napis <em>data:image/png;base64,</em>. W dalszej części kodu oskryptowujemy przycisk anulowania wysyłania pliku którego kliknięcie spowoduje usunięcie całego kontenera oraz przycisk wysyłania pliku którego kliknięcie wywoła większą funkcję <em>trySendFile</em>.</p>
<p>I to wszystko jeśli chodzi o obsługę zdarzenia <em>ondrop</em>. Czy czegoś nam brakuje? Tak, definicji funkcji&#8230;</p>
<h1>trySendFile</h1>
<pre class="brush:javascript">function trySendFile(eId){
    $("#"+eId+" #startUpload").hide();

    var fileData = $("#"+eId+" input[name=\"file\"]").val();
    fileData = fileData.replace(/\+/gi, '-');
    fileData = fileData.replace(/\//gi, '_');

    //dalsza część kodu
}</pre>
<p>Po kliknięciu przycisku wysyłania pierwsze co musi się stać to schowanie owego guzika. Następnie z pola tekstowego <em>file</em> odczytujemy zakodowany plik i podmieniamy w nim pewne znaki. Ktoś może zapytać po co? Po odpowiedź odprowadzam do <a title="Zewnętrzny odnośnik" rel="nofollow external" href="http://pl.wikipedia.org/wiki/Base64">artykułu o base64 na Wikipedii</a> a dokładniej to do akapitu pod tabelką. My będziemy transportować plik w ciągu <em>zmienna1=wartosc1&amp;zmienna1=wartosc2&#8230;</em> więc musimy zadbać by żadne znaki nam nie uszkodziły danych. Dwie linijki z powyższego kodu realizują właśnie podmianę omówioną na Wikipedii.</p>
<p>Teraz możemy w końcu znapisać kod które wyśle wszystkie dane na serwer (np do <em>pliku php/getFile.php</em>):</p>
<pre class="brush:javascript">$.ajax({
    type: "POST",
    url: "php/getFile.php",
    data:   "file="+fileData+
            "&amp;name="+encodeURIComponent($("#"+eId+" .header .name").html())+
            "&amp;description="+encodeURIComponent($("#"+eId+" textarea[name=\"description\"]").val()),
    //tu za chwilę dalszy ciąg kodu
});</pre>
<p>Jak widać używamy tu funkcji <a title="Zewnętrzny odnośnik" rel="nofollow external" href="http://api.jquery.com/jQuery.ajax/">ajax</a> z biblioteki jQuery. Jako parametr <em>data</em> podajemy ciąg gdzie kolejno składamy zmienne <em>file</em> zawierającą kod base64, <em>name</em> zawierającą nazwę pliku oraz <em>description</em> zawierającą treść z pola tekstowego. Wartości pól <em>name</em> i <em>description</em> zabezpieczyliśmy funkcją <a title="Zewnętrzny odnośnik" rel="nofollow external" href="http://www.w3schools.com/jsref/jsref_encodeURIComponent.asp">encodeURIComponent</a> aby dało się je bezpiecznie przesłać w tej formie. I tu znowu ktoś może zapytać dlaczego nie użyliśmy tej metody wcześniej przy zabezpieczaniu base64. Powód jest prosty. Wspomniana metoda podmienia wszystkie znaki specjalne. Jeśli plik waży kilka megabajtów (np. plik <em>.mp3</em>) to użycie omawianej metody powoduje chwilowe zawieszenie przeglądarki. A, że na szczęście w base64 występują tylko dwa <em>psujaki</em> to o wiele optymalnej jest użyć podmiany metodą <em>replace</em>.</p>
<p>Dane zostały wysłane więc teraz trzeba by było obsłużyć odpowiedź. Za nim to jednak zrobimy napiszmy:</p>
<h1>Kod po stronie serwera</h1>
<p>Tu nie będziemy się rozpisywać. Nie podam tu jakiegoś bardzo użytecznego kodu a tylko skrypt który pozwoli przetestować nam uploader i zrozumieć jak należy odbierać kod base64.</p>
<pre class="brush:php">&lt;?php
    $name = str_replace('..',' ',$_POST['name']);
    $name = str_replace('/',' ',$_POST['name']);
    $name = str_replace('.exe',' ',$name);

    if(!file_exists("files/".$name)){
        //dalszy kod
    } else echo "error!Taki plik już istnieje";
?&gt;</pre>
<p>Jak widać w pliku getFile.php najpierw usuwamy z nazwy pliku podwójne kropki i ukośniki aby zapobiec, że jakiś spryciarz zapisze nam plik po za naszym folderem. Usuwamy także rozszerzenia z plików wykonywalnych dla bezpieczeństwa serwera i osoby która będzie te pliki przeglądać. Gdy to już zrobimy sprawdzamy czy nie ma takiego pliku w folderze do uploadu. Jeśli nie to wykonujemy dalszy kod, w przeciwnym wypadku zwracamy przeglądarce komunikat o błędzie. Komunikaty będziemy zwracać w formacie <em>&lt;typ komunikatu&gt;!&lt;treść komunikatu&gt;</em>. Wspomniany dalszy kod wygląda następująco:</p>
<pre class="brush:php">$file = str_replace('-','+',$_POST['file']);
$file = str_replace('_','/',$file);
$f = fopen("files/".$name, "wb");
fwrite($f, base64_decode($file));
fclose($f);
$f = fopen("files/".$name.".txt", "wb");
fwrite($f, $_POST['description']);
fclose($f);
echo "ok!Plik zapisano";</pre>
<p>Po pierwsze przywracamy podmienione wcześniej znaki. Po drugie otwieramy plik o odpowiedniej nazwie i zapisujemy do niego odkodowaną za pomocą <a title="Zewnętrzny odnośnik" rel="nofollow external" href="http://www.php.net/manual/en/function.base64-decode.php">base64_decode</a>treść pliku. Po trzecie zaś otwieramy plik o nazwie <em>&lt;nazwa pliku uploadowanego&gt;.txt</em> i wrzucamy do niego opis napisany przez internautę. Po czwarte zwracamy komunikat, że wszystko poczło dobrze i po piąte&#8230;</p>
<h1>Piszemy ostatni fragment kodu JS</h1>
<p>Teraz wracamy do naszej niedokończonej funkcji ajaxowej i dopisujemy odbiór komunikatów:</p>
<pre class="brush:javascript">    error: function(xhr, ajaxOptions, thrownError){
            $("#"+eId+" p.alert").text("Błąd połęczenia");
            $("#"+eId+" #startUpload").show();
        },
    success: function(msg){
            $("#"+eId+" #startUpload").show();
            var data = msg.split("!");
            switch(data[0]){
                case "error":    $("#"+eId+" p.alert").text(data[1]);
                                 break
                case "ok":       $("#"+eId+" p.alert").text(data[1]);
                                 $("#"+eId+" #startUpload").remove();
                                 break;
                default:         alert(msg);
                                 break;        
            }
        }</pre>
<p>Funkcja napisana po parametrze <em>error</em> jest wykonywana gdy przeglądarka nie może połączyć się z serwerem lub znaleźć pliku. W takim przypadku wyświetlamy internaucie napis, że <em>Brak połączenia</em> i przywracamy przycisk by mógł spróbować raz jeszcze. Zaś <em>success</em> odnosi się do przypadku gdy serwer zwrócił nam jakąś sensowną odpowiedź. Wtedy także przywracamy przycisk a odpowiedź z serwera (zmienna msg) rozwalamy na dwie części znaną już metodą split. Potem sprawdzamy czy komunikat jest typu error czy ok i wykonujemy odpowiednie operacje: wyświetlamy treść komunikatu i ewentualnie kasujemy przycisk wysyłania jak wszystko poszło ok. Gdyby zaś nie udało nam się rozpoznać typu komunikatu (np. zwrócono nam błąd php) to wyświetlamy całość za pomocć alertu</p>
<h1>Gotowiec</h1>
<p>Wszystkie pliki potrzebne do uruchomienia stworzone uploadera można pobrać <a title="Uploader w HTML5" href="http://example.mgdevelop.pl/uploadhtml5/uploader.zip">stąd</a>.</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://mgdevelop.pl/index.php/2011/06/uploader-plikow-z-wykorzystaniem-html5/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>RockMelt &#8211; Facebookowa wizja przegladarki</title>
		<link>http://mgdevelop.pl/index.php/2010/11/rockmelt-facebookowa-wizja-przegladarki/</link>
		<comments>http://mgdevelop.pl/index.php/2010/11/rockmelt-facebookowa-wizja-przegladarki/#comments</comments>
		<pubDate>Wed, 10 Nov 2010 15:26:51 +0000</pubDate>
		<dc:creator>Elektryk</dc:creator>
				<category><![CDATA[Moim okiem]]></category>
		<category><![CDATA[Facebook]]></category>
		<category><![CDATA[przeglądarka]]></category>
		<category><![CDATA[RockMeIt]]></category>
		<category><![CDATA[społeczność]]></category>

		<guid isPermaLink="false">http://mgdevelop.pl/?p=565</guid>
		<description><![CDATA[Ostatnim czasy ciężko nie zauważyć, że wiele firm działających na rynku internetowym ma przyrost ambicji i postanawiają wkraczać w inne... <a href="http://mgdevelop.pl/index.php/2010/11/rockmelt-facebookowa-wizja-przegladarki/">Czytaj dalej&#187;</a>]]></description>
			<content:encoded><![CDATA[<p>Ostatnim czasy ciężko nie zauważyć, że wiele firm działających na rynku internetowym ma przyrost ambicji i postanawiają wkraczać w inne sektory IT. Tak było między innymi z Googlem który wydał swoją przeglądarkę i system operacyjny oraz Mozillą która zamierza wyprodukować swój smartfon. Do grona podbijaczy rynku dojdzie teraz także Facebook który zamierza zdobyć swoje procenty na polu przeglądarek.<span id="more-565"></span></p>
<h1>Pierwsze zderzenie</h1>
<p>Podczas pierwszego uruchamiania przeglądarki RockMelt zostajemy poproszeni o wpisanie swoich danych logowania do Facebooka. Już od pierwszego okienka twórcy przeglądarki jasno pokazują nam, że integracja programu z popularnym serwisem społecznościowym będzie maksymalna. Bez zalogowania nie będziemy mogli uruchomić żadnej strony. Gdy już to jednak zrobimy możemy zostać zaskoczeni. O to bowiem naszym oczom ukazuje się&#8230; Google Chrome! Nie, moment. Są drobne różnice ale charakterystyczny minimalizm i wygląd zakładek natychmiast zdradza na bazie jakiego kodu jest zbudowana przeglądarka RockMelt. Po chwili dopiero wyświetlają się dodatkowe paski po bokach. O nich jednak powiem później.</p>
<h1>Interfejs rozłożony na czynniki</h1>
<p>Póki co zajmijmy się paskiem adresu. Podobnie jak w Google Chrome mamy tu uniwersalne pole do wpisywania wszystkiego. Obok tego znajduje się jednak dodatkowy przycisk Share. Jak łatwo się domyślić służy on do szybkiego umieszczania aktualnie oglądanej stronie na swojej <em>fejsowej</em> Tablicy. Co ciekawsze zaś jeszcze bardziej na prawo mamy pole wyszukiwarki. Widać zatem, że twórcy RockMelt  postawili przed sobą ambitne zadanie zadowolenia wszystkich internautów. Chromiarze otrzymają swoje inteligentne pole adresu a ci którzy postanowią się przerzucić z Firefoxa będą mieli dostęp do osobnego pola wyszukiwarki. Co różni je od tego z przeglądarki Mozilli to to, że wyniki wyszukiwania nie pojawiają się automatycznie w nowej zakładce a w specjalnym okienku. Dopiero stamtąd po kliknięciu More Results można przenieść się do nowej zakładki. Tego rodzaju okienka to powszechne rozwiązanie w programie RockMelt. Na moje oko wyglądają one dosyć elegancko i przejrzyście ale to już sprawa gustu.</p>
<p>Interesujący element znajduje się zaś w lewym górnym rogu okna na lewo od zakładek. Gdy pierwszy raz dostrzegłem ten przycisk przez chwilę zastanawiałem czy przypadkiem nie otwarła mi się Opera. Po chwili jednak zrozumiałem, że podopieczni Zuckenberga lubią ciągnąć wzorce z różnych źródeł i tak na przykład postanowili ukraść pomysł na przycisk menu z niedawnych wersji Opery. Po kliknięciu na ten zaokrąglony prostokąt ukazuje nam się menu prawie kropka w kropkę identyczne do tego spod ikonki klucza w Google Chrome. Czy przenosiny tego przycisku spodobają się internautom to się dopiero okaże. Bądź co bądź jednak norwescy programiści uznali ten pomysł za niewypał i usunęli go z najnowszej wersji Opery.</p>
<p><a href="http://mgdevelop.pl/mgdevelop/wp-content/uploads/2010/11/Bez-nazwy-2.png"><img style="margin-right: 20px;" title="Wyniki wyszukiwania" src="http://mgdevelop.pl/mgdevelop/wp-content/uploads/2010/11/Bez-nazwy-2-300x230.png" alt="" width="180" height="138" /></a> <a href="http://mgdevelop.pl/mgdevelop/wp-content/uploads/2010/11/Bez-nazwy-1.png"><img style="margin-right: 20px;" title="Menu opcji" src="http://mgdevelop.pl/mgdevelop/wp-content/uploads/2010/11/Bez-nazwy-1-300x230.png" alt="" width="180" height="138" /></a> <a href="http://mgdevelop.pl/mgdevelop/wp-content/uploads/2010/11/Bez-nazwy-3x.png"><img class="alignnone size-medium wp-image-599" style="margin-right: 20px;" title="Przycisk share" src="http://mgdevelop.pl/mgdevelop/wp-content/uploads/2010/11/Bez-nazwy-3x-300x230.png" alt="" width="180" height="138" /></a></p>
<h1>Przeglądarka dla społeczniaków</h1>
<p>Jeśli lubisz rozmawiać z znajomymi przez komunikator FB, śledzić ich aktywność oraz kolekcjonować kanały RSS to pokochasz dwa boczne paski z RockMelt. Co innego jeśli cenisz sobie sporą ilość wolnego miejsca na ekranie.  Autorzy facebookowej przeglądarki postanowili bowiem uszczęśliwić nas poprzez dwa sidebary po bokach ekranu. Jeden zwany Krawędzią znajomych zawiera listę naszych kumpli z facebooka wraz z zdjęciami, ikonką statusu, możliwością szybkiego chatu oraz podejrzenia ich tablicy. Po drugiej stronie mamy Krawędź aplikacji. Możemy tam w szybki sposób podejrzeć śledzone przez nas kanały RSS a także w wygodny i zasługujący na pochwałę sposób dodać nowe. Aplikacja sama na podstawie ostatnio przeglądanych stron będzie nam sugerować co chcielibyśmy dodać. Rozwiązanie idealne dla mało zaawansowanych internetów by móc korzystać z RSSa nie wiedząc nawet, że taka technologia istnieje.</p>
<p><a href="http://mgdevelop.pl/mgdevelop/wp-content/uploads/2010/11/Bez-nazwy-5.png"><img class="alignnone size-medium wp-image-584" style="margin-right: 20px;" title="Info z Facebooka" src="http://mgdevelop.pl/mgdevelop/wp-content/uploads/2010/11/Bez-nazwy-5-300x230.png" alt="" width="180" height="138" /></a><a href="http://mgdevelop.pl/mgdevelop/wp-content/uploads/2010/11/Bez-nazwy-4.png"><img class="alignnone size-medium wp-image-583" style="margin-right: 20px;" title="Kanały RSS" src="http://mgdevelop.pl/mgdevelop/wp-content/uploads/2010/11/Bez-nazwy-4-300x230.png" alt="" width="180" height="138" /></a> <a href="http://mgdevelop.pl/mgdevelop/wp-content/uploads/2010/11/Bez-nazwy-6.png"><img class="alignnone size-medium wp-image-585" style="margin-right: 20px;" title="Dodawanie kanału RSS" src="http://mgdevelop.pl/mgdevelop/wp-content/uploads/2010/11/Bez-nazwy-6-300x230.png" alt="" width="180" height="138" /></a></p>
<h1>Myśl końcowa</h1>
<p>Tak jak już wspominałem wygląd programu zrobił na mnie bardzo dobre wrażenie. RockMelt wydaje się być ładnie zaprojektowaną alternatywą dla miłośników serwisów społecznościowych. O wiele ładniej niż w Chromie prezentuje się okno Nowej karty. Widać także sporą ilość pracy włożonej w możliwość dostosowania programu do siebie. Mam tu na przykład na myśli możliwość wyłączenia pasków bocznych oraz zmianę kolejności znajomych i aplikacji na nich.</p>
<p>Jeśli zaś miałbym się do czegoś przyczepić to w sumie ciężko. Ok, program scrashował mi się raz czy dwa, nie umie zaimportować zakładek z Chrome (chociaż z historią poszło gładko) ale tak ogólnie to po wyjściu z faz testów RockMeltwydaje się być dobrą propozycją dla pewnej grupy odbiorców. Oczywiście odezwą się głosy, że to kolejny wynalazek szatana by okradać nas z prywatności oraz, że jest to przeglądarka do słodkich idiotek ale&#8230; czy te głosy są poparte dobrymi argumentami? Osobiście nie będę na co dzień korzystał z tego cuda ale projekt będę śledził z uwagą gdyż sądzę, że to w tą stronę będą szły w przyszłości przeglądarki. W stronę unifikacji aplikacji internetowych z aplikacjami desktopowymi.</p>
]]></content:encoded>
			<wfw:commentRss>http://mgdevelop.pl/index.php/2010/11/rockmelt-facebookowa-wizja-przegladarki/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Dodawanie tagów do MediaWiki</title>
		<link>http://mgdevelop.pl/index.php/2010/09/dodawanie-tagow-do-mediawiki/</link>
		<comments>http://mgdevelop.pl/index.php/2010/09/dodawanie-tagow-do-mediawiki/#comments</comments>
		<pubDate>Tue, 28 Sep 2010 14:48:47 +0000</pubDate>
		<dc:creator>Elektryk</dc:creator>
				<category><![CDATA[MediaWiki]]></category>
		<category><![CDATA[parser]]></category>
		<category><![CDATA[rozszerzenie]]></category>
		<category><![CDATA[tag]]></category>
		<category><![CDATA[usability]]></category>

		<guid isPermaLink="false">http://mgdevelop.pl/?p=507</guid>
		<description><![CDATA[Jeśli posiadamy własną encyklopedię na silniku MediaWiki to zapewne chcemy aby naszym redaktorom pisanie stron sprawiało jak najmniej problemów ale... <a href="http://mgdevelop.pl/index.php/2010/09/dodawanie-tagow-do-mediawiki/">Czytaj dalej&#187;</a>]]></description>
			<content:encoded><![CDATA[<p>Jeśli posiadamy własną encyklopedię na silniku MediaWiki to zapewne chcemy aby naszym redaktorom pisanie stron sprawiało jak najmniej problemów ale jednocześnie aby tworzona przez nas wiki wyglądała jak najładniej. Pchanie htmla w kod stron mija się z celem. Szablony? Sprawdzą się. Ale co jeśli chcemy dać więcej możliwości edytującym np. automatyczne generowanie obrazka? Składnia MW na to nie pozwala ale PHP już tak. Musimy wiec dodać własne tagi do składni wiki za pomocą rozszerzenia!</p>
<p><span id="more-507"></span></p>
<h1>Przygotowanie</h1>
<p>Na początek ustalmy jaki mamy cel w naszej pracy. W tym poradniku chciałbym pokazać jak dodać tag &lt;ramka&gt; który pozwoli na szybkie tworzenie rameczek z obrazkowym tłem i treścią w środku. Jako tło będzie można ustawić dowolną grafikę spośród zuploadowanych na serwer wpisując jej nazwę jako wartość atrybutu <em>grafika</em>.</p>
<p>Teraz czas na napisanie rozszerzenia. Zaczniemy od stworzenia pliku z rozszerzeniem php. Musimy ten plik umieścić w folderze extensions naszej instalacji MW. U mnie będzie to <em>extensions/nowetagi.php</em>. Tak przygotowany plik musimy podpiąć do skryptu. W tym celu otwieramy plik LocalSettings i mniej więcej po środku dopisujemy linijkę:</p>
<pre class="brush: php">require_once("extensions/nowetagi.php");</pre>
<h1>Włączanie parsowania</h1>
<p>Kolejnym krokiem w naszej pracy będzie otwarcie pliku <em>nowetagi.php</em> i dodanie odpowiedniego zdarzenia wewnątrz znaczników php:</p>
<pre class="brush: php">$wgHooks['ParserFirstCallInit'][] = 'mojParser';</pre>
<p>Powyższa linijka spowoduje, że w momencie jak MediaWiki będzie parsował artykuł to wywoła funkcję mojParser by dowiedzieć się jak parsować tagi obsługiwane przez nasze rozszerzenie. Poniżej tej linijki umieszczamy ciało wspomnianej funkcji:</p>
<pre class="brush: php">function mojParser( &amp;$parser ) {
   $parser-&gt;setHook( 'ramka', 'parsowanieRamka');
   return true;
}</pre>
<p>W podanym przykładzie poinformowaliśmy parser, że tag &lt;ramka&gt; ma być obsługiwany za pomocą funkcji <em>parsowanieRamka()</em>. W obrębie jednej funkcji mojParser możemy dodać nielimitowaną liczbę nowych tagów. Ważne jest tylko aby na końcu zwrócić <em>true</em>.</p>
<h1>Funkcja parsująca</h1>
<p>Teraz zdefiniujmy funkcję <em>parsowanieRamka().</em></p>
<pre class="brush: php">function parsowanieRamka( $input, $args, $parser, $frame ) {
}</pre>
<p>Póki co ciało funkcji jest puste. Musimy bowiem najpierw wyjaśnić co zawierają przekazane argumenty. Jak wiadomo tagi dzielą się na dwuelementowe (&lt;ramka&gt;&lt;/ramka&gt;) i jednoelementowe (&lt;cytat /&gt;). Jeśli parsowany tag składa się z otwarcia i zamknięcia to zmienna $input będzie zawierała to co znajduje się pomiędzy czyli inaczej mówiąc zawartość tagu. Zmienna $args jest zaś tablicą o indeksach identycznych jak atrybuty parsowanego tagu i z wartościami równymi wartościom tych atrybutów. Dla przykładu tag <em>&lt;ramka grafika=&#8221;tlo.jpg&#8221;&gt;Dowolny tekst&lt;/ramka&gt;</em> zostanie podzielony na zmienną <em>$input</em> o wartości <em>Dowolny tekst</em> oraz na jednoelementową tablicę <em>$args</em> gdzie $args['grafika']=&#8217;tlo.jpg&#8217;. Pozostałe argumenty przekazane funkcji <em>parsowanieRamka()</em> nie są dla nas istotne.</p>
<p>Uzbrojeni w powyższą wiedzę możemy zacząć pisać skrypt który zwróci kod html w miejsce tagu w artykule. Musimy jeszcze tylko pobrać adres URL do grafiki której nazwa została przekazana w atrybucie <em>grafika</em>.</p>
<pre class="brush: php">if(!empty($args['grafika'])){
   $file = wfFindFile($args['grafika']);
   $url = $file-&gt;getFullUrl();
}</pre>
<p>Powyższa instrukcja sprawi, że jeśli zdefiniowano wartość atrybutu grafika to zmienna $url będzie przechowywała bezwzględny adres do tego pliku. Możemy ją teraz użyć przy generowaniu pierwszej części kodu wynikowegoi ustawić obrazek jako tło bloku:</p>
<pre class="brush: php">$output = '&lt;div class="ramka" style="background-image: url('.$url.');"&gt;';</pre>
<p>Teraz trzeba dołączyć do tego treść spomiędzy znaczników. Ale tu należy pamiętać o jednej rzeczy, że tam również może zostać użyta składania wiki i inne tagi. Dlatego też zmienną $input należy jeszcze raz przepuścić przez parser za pomocą specjalnej funkcji:</p>
<pre class="brush: php">$output .= $parser-&gt;recursiveTagParse( $input, $frame );</pre>
<p>Argumentami tej funkcji jest treść do ponownego sparsowania oraz zmienna <em>$frame</em> którą otrzymaliśmy wcześniej jako czwarty argument funkcji <em>parsowanieRamka</em>. Gdy to już mamy możemy zamknąć blok i zwrócić gotowy kod html:</p>
<pre class="brush: php">$output .= '&lt;/div&gt;';
return $output;</pre>
<p>Pełny kod naszego rozszerzenia wygląda tak:</p>
<pre class="brush: php">&lt;?php
$wgHooks['ParserFirstCallInit'][] = 'mojParser';

function mojParser( &amp;$parser ) {
   $parser-&gt;setHook( 'ramka', 'parsowanieRamka');
   return true;
}

function parsowanieRamka( $input, $args, $parser, $frame ) {
   if(!empty($args['grafika'])){
      $file = wfFindFile($args['grafika']);
      $url = $file-&gt;getFullUrl();
   }
   $output = '&lt;div class="ramka" style="background-image: url('.$url.');"&gt;';
   $output .= $parser-&gt;recursiveTagParse( $input, $frame );
   $output .= '&lt;/div&gt;';
   return $output;
}
?&gt;</pre>
<h1>Nieco więcej o parsowaniu</h1>
<p>W powyższym przykładowym rozszerzeniu użyliśmy funkcji $parser-&gt;recursiveTagParse();. Jak już pisałem służy ona do tego by sparsować składnię wiki i dodatkowe tagi wewnątrz jakiegoś tekstu. Należy jednak pamiętać, że nie zostaną wtedy podmienione podpisy (~~~~). Tym zajmuję się tzw parser wstępny ale on także w tym wypadku nam nie pomoże. Jest to związane z tym, że tekst wewnątrz tagów dodawanych przez rozszerzenia jest parsowany przy każdym wyświetleniu strony na nowo a w bazie danych ląduje niezmieniony. Z tego też powodu własne tagi nie sprawdzą się w miejscach gdzie użytkownicy będą się podpisywać za pomoca 4 tyld.</p>
<p>Inną sprawą jest to, że należy uważać by nie parsować znaczników html które nie działają na stronach MediaWiki. Np. próba sparsowania tekstu <em>&lt;img src=&#8221;adres.png&#8221;&gt; </em>spowoduje, że ten kod pojawi się na stronie w formie tekstu a nie obrazka. Można jednak bezpiecznie parsować kod obrazka zapisany w wikiskładni tzn <em>[[Grafika:Plik.png]]</em>. Identyczna sytuacja zachodzi przy odnośnikach. Dlatego należy uważać by nie wrzucać do parsera przypadkowego kodu html a jedynie parsować to co można.</p>
<h1>Inny przykład: tag &lt;cytat&gt;</h1>
<p>Na koniec zamieszczę jeszcze jeden kod parsowania tagu. Jego składnia wygląda tak:<em> &lt;cytat autor=&#8221;Imię Nazwisko&#8221;&gt;&lt;/cytat&gt;</em> a skrypt który go parsuje przedstawia się następująco:</p>
<pre class="brush: php">function parsowanieCytat($input, $args, $parser, $frame ) {
   $output = '&lt;blockquote&gt;'.$input.'&lt;div&gt;'.$args['autor'].'&lt;/div&gt;&lt;/blockquote&gt;&lt;br style="clear: left;" /&gt;';
   return $parser-&gt;recursiveTagParse( $output, $frame );
}</pre>
<p>Do tego dochodzi jeszcze krótki kod CSS:</p>
<pre class="brush: css">blockquote{
  padding-left: 50px;
  background: url('quote.png') left 5px no-repeat;
  margin: 0px 20px 10px 0px;
  font-family: Georgia;
  font-style: italic;
  min-height: 27px;
  float: left;
  color: #333;
  max-width: 500px;
}
blockquote div{
  text-align: right;
  color: #666;
  font-style: normal;
  font-size: 10px;
  font-family: Arial;
  margin-right: 10px;
}</pre>
<p>Całość w akcji można zobaczyć na górze<a title="Dodatkowy tag Cytat w akcji" href="http://borealis.net.pl/index.php/Zombine"> tej strony</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://mgdevelop.pl/index.php/2010/09/dodawanie-tagow-do-mediawiki/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Tekstura jeansu</title>
		<link>http://mgdevelop.pl/index.php/2010/08/tekstura-jeansu/</link>
		<comments>http://mgdevelop.pl/index.php/2010/08/tekstura-jeansu/#comments</comments>
		<pubDate>Mon, 23 Aug 2010 14:31:26 +0000</pubDate>
		<dc:creator>Elektryk</dc:creator>
				<category><![CDATA[Poradniki]]></category>
		<category><![CDATA[jeans]]></category>
		<category><![CDATA[photoshop]]></category>
		<category><![CDATA[tekstura]]></category>
		<category><![CDATA[tile]]></category>

		<guid isPermaLink="false">http://mgdevelop.pl/?p=510</guid>
		<description><![CDATA[W tym poradniku zaprezentuję jak szybko wykonać teksturę jeansu za pomocą programu Adobe Photoshop. Zabierzmy się do pracy. Na początek ustawiamy... <a href="http://mgdevelop.pl/index.php/2010/08/tekstura-jeansu/">Czytaj dalej&#187;</a>]]></description>
			<content:encoded><![CDATA[<p>W tym poradniku zaprezentuję jak szybko wykonać teksturę jeansu za pomocą programu Adobe Photoshop. Zabierzmy się do pracy. <span id="more-510"></span>Na początek ustawiamy kolory na dwa różne odcienie niebieskiego. U mnie będzie to #1d2862 jako kolor główny oraz #6a83ff jako tło. Następnie tworzymy nowy obrazek o rozmiarach trzy razy większych niż ma mieć finałowa grafika. Chcę stworzyć teksturę wielkości 512&#215;512 pikseli więc w okienku tworzenia nowego pliku rozmiary ustawiam na 1536&#215;1536.</p>
<p>Gdy to już mamy gotowe wypełniamy grafikę naszym kolorem głównym. Następnie wybieramy menu <em>Filtr &gt; Pikselowanie &gt; Rastrowanie koloru</em> (Filter &gt; pixelate &gt; color halftone) i ustawiamy takie wartości:</p>
<p><a href="http://mgdevelop.pl/mgdevelop/wp-content/uploads/2010/08/pikselyzacja.png"><img class="alignnone size-full wp-image-511" title="pikselyzacja" src="http://mgdevelop.pl/mgdevelop/wp-content/uploads/2010/08/pikselyzacja.png" alt="" width="408" height="267" /></a></p>
<p>Po tej operacji powinniśmy otrzymać coś takiego:</p>
<p><a href="http://mgdevelop.pl/mgdevelop/wp-content/uploads/2010/08/piksele.png"><img class="alignnone size-full wp-image-512" title="piksele" src="http://mgdevelop.pl/mgdevelop/wp-content/uploads/2010/08/piksele.png" alt="" width="150" height="150" /></a></p>
<p>Kolejnym krokiem jest nałożenie odpowiedniego filtru który sprawi, że na naszej teksturze pojawią się jeansowe włókna. Otwieramy zatem <em>Filtr &gt; Szkic &gt; Kreda i węgiel</em> (filter &gt; sketch &gt; chalk and charcoal) i ustawiamy wartości jak na obrazku poniżej:</p>
<p><a href="http://mgdevelop.pl/mgdevelop/wp-content/uploads/2010/08/wegielikreda.png"><img class="alignnone size-full wp-image-513" title="wegielikreda" src="http://mgdevelop.pl/mgdevelop/wp-content/uploads/2010/08/wegielikreda.png" alt="" width="268" height="167" /></a></p>
<p>W tym momencie nasz obraz będzie wyglądał tak:</p>
<p><a href="http://mgdevelop.pl/mgdevelop/wp-content/uploads/2010/08/wlokna.png"><img class="alignnone size-full wp-image-514" title="wlokna" src="http://mgdevelop.pl/mgdevelop/wp-content/uploads/2010/08/wlokna.png" alt="" width="150" height="150" /></a></p>
<p>Teraz przyszedł czas by zmniejszyć naszą grafikę do takich rozmiarów jakie chcemy uzyskać. Moja tekstura po trzykrotnym pomniejszeniu wygląda następująco:</p>
<p><a href="http://mgdevelop.pl/mgdevelop/wp-content/uploads/2010/08/prawiegotowe.png"><img class="alignnone size-full wp-image-515" title="prawiegotowe" src="http://mgdevelop.pl/mgdevelop/wp-content/uploads/2010/08/prawiegotowe.png" alt="" width="150" height="150" /></a></p>
<p>Teraz możemy przejść do O<em>braz &gt; Dopasowania  &gt; Jasność i kontrast</em> by poprawić kolory. Ja dla przykładu ustawiłem jasność na -3 a kontrast na +90. W zależności jakie wartości tu damy to uzyskamy różne odmiany jeansu.</p>
<p><a href="http://mgdevelop.pl/mgdevelop/wp-content/uploads/2010/08/gotowe.png"><img class="alignnone size-full wp-image-516" title="gotowe" src="http://mgdevelop.pl/mgdevelop/wp-content/uploads/2010/08/gotowe.png" alt="" width="150" height="150" /></a></p>
<p>Na koniec zamieszczam <a title="tekstura jeans 512x512" href="http://mgdevelop.pl/mgdevelop/wp-content/uploads/2010/08/tekstura_jeans_512x512.png">gotowy plik z teksturą jeansu w rozmiarze 512&#215;512 pikseli</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://mgdevelop.pl/index.php/2010/08/tekstura-jeansu/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Rozmowa z wujkiem Marcinem cz.2</title>
		<link>http://mgdevelop.pl/index.php/2010/08/rozmowa-z-wujkiem-marcinem-cz-2/</link>
		<comments>http://mgdevelop.pl/index.php/2010/08/rozmowa-z-wujkiem-marcinem-cz-2/#comments</comments>
		<pubDate>Mon, 16 Aug 2010 09:46:11 +0000</pubDate>
		<dc:creator>Elektryk</dc:creator>
				<category><![CDATA[HTML i CSS]]></category>
		<category><![CDATA[frame]]></category>
		<category><![CDATA[iframe]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[standardy]]></category>
		<category><![CDATA[W3C]]></category>

		<guid isPermaLink="false">http://mgdevelop.pl/?p=488</guid>
		<description><![CDATA[O, to znowu Ty, mój początkujący miłośniku tworzenia stron internetowych. Pewnie znowu przyszedłeś o coś zapytać. Nie ma problemu. Wejdź... <a href="http://mgdevelop.pl/index.php/2010/08/rozmowa-z-wujkiem-marcinem-cz-2/">Czytaj dalej&#187;</a>]]></description>
			<content:encoded><![CDATA[<p>O, to znowu Ty, mój początkujący miłośniku tworzenia stron internetowych. Pewnie znowu przyszedłeś o coś zapytać. Nie ma problemu. Wejdź i usiądź. Opowiedz z czym masz problem. Zaparzyć Ci herbaty?<span id="more-488"></span></p>
<p><strong>Nie, dziękuję. Chodzi to, że niedawno przerzuciłem się z tabelek na divy bo wszyscy mówią, że to jest lepsze. Ale ostatnio zaglądałem do kodu phpBB3 i tam wszystko stoi na tabelkach. Wydawało mi się, że twórcy tego skryptu znają się na swojej pracy a jednak korzystają z starych rozwiązań. To jak to w końcu jest? Co jest lepsze? Tabelki czy divy?</strong></p>
<p>Obydwa rozwiązania są dobre w zależności do czego je używasz. Mówiąc krótko divy powinny być używane do budowy kontrukcji wyglądu strony. Na przykład umieszczenia loga na górze, sidebara z boku i stopki na dole. Tabelki zaś należy stosować tylko gdy chcemy wyświetlić jakieś dane tabelaryczne. Podchodzą pod to między innymi dane statystyczne oraz wielokolumnowe listy jak na np. interfejsy na forach. Tabelek nie powinno zaś się używać gdy chcemy dla przykładu stworzyć trzy kolumnową stronę i w tym celu tworzyć tabeli z trzema kolumnami. Takie rozwiązanie to nieporozumienie gdyż zwiększa czas jaki przeglądarki potrzebują do wyświetlenia witryny. Da się zauważyć to opóźnienie gdy np. środkowa kolumna zawiera dużo grafik. Wtedy na wyświetlenie komórki po prawej możemy musieć trochę poczekać.</p>
<p><strong>Ok. A jak wygląda sprawa z ramkami?</strong></p>
<p>Zwykłe ramki wyszły już całkiem z użycia. Chodzi mi tu o elementy <em>frame</em> i <em>frameset</em>. Nie powinno się ich używać gdyż obecnie istnieją o wiele lepsze rozwiązania jak na przykład php lub ajax. Co zaś się tyczy ramek pływających, to znaczy elementów <em>iframe</em> to są one wciąż w użyciu ale radzi się ich już wystrzegać. Inaczej mówiąc skorzystanie z nich to nic złego ale jeśli tylko jest możliwość to powinno skorzystać się z innej techniki.</p>
<p><strong>Ciekawe. A są jeszcze jakieś nowe standardy o których powinien wiedzieć każdy początkujący?</strong></p>
<p>Długo by tu wymieniać ale pokrótce mogę wymienić parę punktów. Po pierwsze aktualnie jedyne kodowanie znaków jakiego powinno się używać to UTF-8. I od tego nie ma odstępstw. Używając tego kodowania pozbędziesz się problemów na stronach wielojęzykowych oraz przy korzystaniu z zewnętrznych interfejsów np. przycisków Facebooka. Ponadto wycofano wszystkie dziwne znaczniki typu <em>&lt;font&gt;</em>, <em>&lt;big&gt;</em> itd dotyczących wyglądu tekstu. Zamiast nich należy stosować znacznika <em>&lt;span&gt;</em> i odpowiednie style CSS. Nawet zamiast <em>&lt;b&gt;</em> radzi się korzystać z <em>&lt;strong&gt;</em> chociaż ten pierwszy wciąż oficjalnie jest w użyciu.</p>
<p><strong>Dobrze, przestańmy już mówić o tym htmlu. Ostatnio chciałem poszerzyć swoje horyzonty i pouczyć się JavaScriptu. Ale mam mały dylemat. Czego radzisz się uczyć? JavaScriptu czy może tej słynnej biblioteki jQuery.</strong></p>
<p>Na początek może wyjaśnię, że jQuery to zestaw funkcji napisanych w języku  JavaScript. Ale jeśli dopiero zaczynasz swoją przygodę z językami skryptowymi to radzę ci zacząć uczyć się samego JS. Dlaczego? Ponieważ umiejąc korzystać z jQ ale nie znając dobrze niektórych możliwości JavaScriptu będziesz mocno ograniczony. Mam tu na myśli wszystkie funkcję odpowiedzialne za przetwarzanie tekstu, dokonywanie obliczeń czy obsługę zdarzeń. Gdy to już opanujesz możesz śmiało ruszać do nauki JQuery. Pisanie skryptów stanie się dla Ciebie o wiele łatwiejsze i ponadto będziesz miał wiedzę potrzebną do pisania zaawansowanych aplikacji internetowych.</p>
<p><strong>A istnieją jakieś alternatywy do jQuery?</strong></p>
<p>Tak, np. Prototype i Moo Tools. Te biblioteki są jednak mniej popularne od jQuery i możesz przy nich liczyć na mniejsze wsparcie społeczności.</p>
<p><strong>Dobrze wiedzieć. Ok, to chyba dziś już na tyle.</strong></p>
<p>W porządku. Wracaj jak tylko nazbierają Ci się znowu jakieś problemy.</p>
<p><strong>Na pewno przyjdę Cię pomęczyć, cześć.</strong></p>
<p>Trzymaj się.</p>
]]></content:encoded>
			<wfw:commentRss>http://mgdevelop.pl/index.php/2010/08/rozmowa-z-wujkiem-marcinem-cz-2/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Zaokrąglony przycisk o nieustalonej szerokości</title>
		<link>http://mgdevelop.pl/index.php/2010/08/zaokraglony-przycisk-o-nieustalonej-szerokosci/</link>
		<comments>http://mgdevelop.pl/index.php/2010/08/zaokraglony-przycisk-o-nieustalonej-szerokosci/#comments</comments>
		<pubDate>Mon, 02 Aug 2010 15:23:57 +0000</pubDate>
		<dc:creator>Elektryk</dc:creator>
				<category><![CDATA[HTML i CSS]]></category>
		<category><![CDATA[background]]></category>
		<category><![CDATA[cięcie]]></category>
		<category><![CDATA[przycisk]]></category>

		<guid isPermaLink="false">http://mgdevelop.pl/?p=472</guid>
		<description><![CDATA[W tym poradniku postaram się wyjaśnić jak koduje się obrazkowe przyciski z zaokrąglonymi rogami jeśli nie wiemy ile będzie w... <a href="http://mgdevelop.pl/index.php/2010/08/zaokraglony-przycisk-o-nieustalonej-szerokosci/">Czytaj dalej&#187;</a>]]></description>
			<content:encoded><![CDATA[<p>W tym poradniku postaram się wyjaśnić jak koduje się obrazkowe przyciski z zaokrąglonymi rogami jeśli nie wiemy ile będzie w nich tekstu, a co za tym idzie nie ma on konkretnej szerokości. Taki przypadek może się zdarzyć np. przy budowie CMSa gdzie nie możemy przewidzieć jakie napisy umieści użytkownik w menu.</p>
<h1><span id="more-472"></span> Grafika</h1>
<p>Finalnie nasza praca ma wyglądać tak:</p>
<p><a href="http://mgdevelop.pl/mgdevelop/wp-content/uploads/2010/08/button.png"><img class="alignnone size-full wp-image-475" title="button" src="http://mgdevelop.pl/mgdevelop/wp-content/uploads/2010/08/button.png" alt="" width="200" height="30" /></a></p>
<p>Jak widać przy większej ilości tekstu grafika musi się się rozszerzać. Aby tak było trzeba to sprytnie zakodować. Najpierw jednak musimy przygotować dwie grafiki. Jedną która będzie się składała tylko z prawych zaokrągleń i druga która będzie bardzo szeroką wersją buttonu ale bez zaokrągleń po prawej. Dokładniej to potrzebujemy takich obrazków:</p>
<p><a href="http://mgdevelop.pl/mgdevelop/wp-content/uploads/2010/08/right.png"><img class="alignnone size-full wp-image-477" title="right" src="http://mgdevelop.pl/mgdevelop/wp-content/uploads/2010/08/right.png" alt="" width="22" height="30" /></a></p>
<p><a href="http://mgdevelop.pl/mgdevelop/wp-content/uploads/2010/08/right.png"></a><a href="http://mgdevelop.pl/mgdevelop/wp-content/uploads/2010/08/left.png"><img class="alignnone size-full wp-image-476" title="left" src="http://mgdevelop.pl/mgdevelop/wp-content/uploads/2010/08/left.png" alt="" width="500" height="30" /></a></p>
<p>Ważne jest to aby obrazki miały jednolite lub prawie jednolite tło. W tym przypadku jest ono białe.</p>
<h1>Kod</h1>
<p>Przy kodowaniu użyjemy pewnej sztuczki. Krótszy obrazek wstawimy jako tło linku przycisku a sam link wstawimy do diva któremu jako tło nadamy dłuższy obrazek. Dzięki temu krótsza grafika odpowiednio zasłoni tą dłuższą. Oto kod html:</p>
<pre class="brush: html">&lt;div class="przycisk"&gt;&lt;a href="#"&gt;Przejdź do galerii zdjęć&lt;/a&gt;&lt;/div&gt;</pre>
<p>A poniżej kod CSS:</p>
<pre class="brush: css"> .przycisk{
    height: 30px;
    background: url('left.png') no-repeat;
    display: block;
    float: left;
 }
 .przycisk a{
    height: 30px;
    background: url('right.png') right no-repeat;
    display: block;
    padding: 0 15px 0 15px;
    font: italic normal bolder 14px Georgia;
    text-decoration: none;
    color: #dadada;
    line-height: 30px;
 }</pre>
<p>Jak widać obrazek <em>right.png</em> dosunęliśmy do prawej strony aby pojawił się w odpowiednim miejscu. Musieliśmy także użyć <em>float: left</em> aby wszystko przyjmowało możliwie najmniejszą szerokość. Kod w działaniu można zobaczyć <a title="zaokrąglony przycisk" href="http://example.mgdevelop.pl/zaokraglonyprzycisk/">pod tym linkiem</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://mgdevelop.pl/index.php/2010/08/zaokraglony-przycisk-o-nieustalonej-szerokosci/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>WPEngine &#8211; hosting stworzony pod WordPressa</title>
		<link>http://mgdevelop.pl/index.php/2010/07/wpengine-hosting-stworzony-pod-wordpressa/</link>
		<comments>http://mgdevelop.pl/index.php/2010/07/wpengine-hosting-stworzony-pod-wordpressa/#comments</comments>
		<pubDate>Thu, 29 Jul 2010 10:05:26 +0000</pubDate>
		<dc:creator>Elektryk</dc:creator>
				<category><![CDATA[Wordpress]]></category>
		<category><![CDATA[Wydarzenia]]></category>
		<category><![CDATA[hosting]]></category>
		<category><![CDATA[serwis]]></category>
		<category><![CDATA[usługa]]></category>
		<category><![CDATA[WPEngine]]></category>

		<guid isPermaLink="false">http://mgdevelop.pl/?p=463</guid>
		<description><![CDATA[W chwili obecnej istnieją dwie możliwości tworzenia serwisu na systemie WordPress. Pierwsza to założenie strony w serwisie WordPress.com. Otrzymujemy tam... <a href="http://mgdevelop.pl/index.php/2010/07/wpengine-hosting-stworzony-pod-wordpressa/">Czytaj dalej&#187;</a>]]></description>
			<content:encoded><![CDATA[<p>W chwili obecnej istnieją dwie możliwości tworzenia serwisu na systemie WordPress. Pierwsza to założenie strony w serwisie WordPress.com. Otrzymujemy tam gotową instalację, nie musimy się martwić o transfer ani o odpowiednią konfigurację. Wadą tego rozwiązania jest jednak to, że nie możemy instalować własnych wtyczek i motywów bez dodatkowych opłat. Alternatywą jest własna instalacja WP na opłaconym serwerze. Tu jednak musimy zmierzyć się z ręcznym dostosowaniem skryptu oraz wydajnością całego systemu. Niedługo jednak do tych dwóch opcji dołączy trzecia możliwość.<span id="more-463"></span></p>
<h1>WPEngine &#8211; o co chodzi?</h1>
<p>Opisywana <a title="WPEngine" href="http://wpengine.com">platforma WPEngine</a> ma być połączeniem zalet obecnych dwóch rozwiązań. Za dosyć wysoką cenę 50$ miesięcznie otrzymamy możliwość utworzenia swojego serwisu internetowego z użyciem WordPressa na hostingu idealnie zoptymalizowanym pod tą platformę. Autorzy pomysłu kusza nas  ogromną galerią gotowych wtyczek i skórek. Co więcej możemy także instalować własne rozszerzenia i motywy. Ponadto oto by nasza strona nie padła w okresie wzmożonego ruchu będą dbać odpowiednie narzędzia odpowiedzialne za cachowanie treści, minimalizowanie plików oraz kompresję grafik. Zaś developerzy będą mieli pełny dostęp do logów serwera PHP.</p>
<h1>&#8222;It&#8217;s safer here&#8221;</h1>
<p><a title="WPEngine" href="http://wpengine.com">Platforma WPEngine</a> w przeciwieństwie do typowych hostingów będzie dbało o to czy wszystkie pliki mają dobrze nadane prawa dostępu. Dzięki temu nie ma  możliwości, że przez źle ustawione chmody ktoś usunie nam zdalnie plik. Ponadto będzie można uruchamiać wszystkie wtyczki i skórki w trybie piaskownicy. To znaczy, że możemy sprawdzić działania nowego składnika na swoim blogu ale internauci nie zobaczą od razu efektów tych eksperymentów. Dopiero gdy stwierdzimy, że wszystko działa prawidłowo będziemy mogli zatwierdzić zmiany i oddać nowe funkcjonalności w ręce użytkowników. Taki sposób pracy chroni nas przed uszkodzeniem instalacji WP przez złośliwą wtyczkę. Co więcej wszystkie konta na serwerze są od siebie odseparowane przez co nie ma możliwości ataku na nasz serwis przez innego klienta WPEngine.</p>
<h1>Gdzie to można dostać?</h1>
<p>Aktualnie aby móc skorzystać z platformy trzeba <a href="http://wpengine.com/waiting-list/">otrzymać zaproszenie</a>. Na pełne otwarcie usługi przyjdzie nam pewnie jeszcze poczekać. Niemniej już teraz wydaje się, że będzie to doskonałe rozwiązanie dla wszelkich stron firmowych i dużych blogów. Jak to wyjdzie w praniu to się okaże. W każdej chwili można opuścić szeregi klientów WPEngine ale przenoszenie swojego istniejącego serwisu to i tak poważny krok.</p>
]]></content:encoded>
			<wfw:commentRss>http://mgdevelop.pl/index.php/2010/07/wpengine-hosting-stworzony-pod-wordpressa/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Baner z ilością artykułów w MediaWiki</title>
		<link>http://mgdevelop.pl/index.php/2010/07/baner-z-iloscia-artykulow-w-mediawiki/</link>
		<comments>http://mgdevelop.pl/index.php/2010/07/baner-z-iloscia-artykulow-w-mediawiki/#comments</comments>
		<pubDate>Sun, 25 Jul 2010 15:59:49 +0000</pubDate>
		<dc:creator>Elektryk</dc:creator>
				<category><![CDATA[MediaWiki]]></category>
		<category><![CDATA[artykuły]]></category>
		<category><![CDATA[baza danych]]></category>
		<category><![CDATA[php GD]]></category>
		<category><![CDATA[reklama]]></category>

		<guid isPermaLink="false">http://mgdevelop.pl/?p=431</guid>
		<description><![CDATA[O świetności danej encyklopedii internetowej świadczy ilość i jakość znajdujących się tam artykułów. Dlatego nie ma powodu by wstydzić się... <a href="http://mgdevelop.pl/index.php/2010/07/baner-z-iloscia-artykulow-w-mediawiki/">Czytaj dalej&#187;</a>]]></description>
			<content:encoded><![CDATA[<p>O świetności danej encyklopedii internetowej świadczy ilość i jakość znajdujących się tam artykułów. Dlatego nie ma powodu by wstydzić się numerka reprezentującego ile jest stron w naszej wiki. Przeciwnie! Należy się z tym obnosić. A jeszcze lepiej jak robią to nasi użytkownicy. Dlatego w tym poradniku nauczymy się tworzyć dynamiczny obrazkowy banerek, na którym będzie wypisana ilość artykułów na naszej stronie w MediaWiki.</p>
<h1><span id="more-431"></span>Nasze miejsce pracy</h1>
<p>Dla naszych banerków najlepiej przygotować osobny folder. W nim umieśćmy obrazek który będzie podstawą naszego dzieła. Ja dla banerka mojej encyklopedii o grach firmy Valve  przygotowałem coś takiego:</p>
<p><a href="http://mgdevelop.pl/mgdevelop/wp-content/uploads/2010/07/dynamicsignature1.png"><img class="alignnone size-full wp-image-434" title="dynamicsignature1" src="http://mgdevelop.pl/mgdevelop/wp-content/uploads/2010/07/dynamicsignature1.png" alt="" width="468" height="60" /></a></p>
<p>Plan jest taki aby pod tytułem strony znajdował się napis <em>n artykuły(ów) o grach Valve</em> gdzie n jest oczywiście liczbą stron. Przed napisaniem tego skryptu musimy jednak zadbać jeszcze o jedną rzecz. Nasz baner będzie generowany w PHP przy każdym zapytaniu. Link do naszego obrazka nie może być jednak linkiem do pliku php, gdyż wtedy nie będzie się wyświetlał w podpisach na forach internetowych. Musimy skorzystać z możliwości jakie daje nam plik <em>.htaccess. </em>Po utworzeniu go w folderze z naszym banerem umieszczaniu w nim poniższy kod:</p>
<pre class="brush:shell">RewriteEngine On
RewriteRule ^baner.png$ generator.php [L]</pre>
<p>Ta instrukcja spowoduje, że chociaż adres będzie prowadził do pliku baner.png to serwer będzie zwracał treść z pliku generator.php.</p>
<h1>Generowanie obrazka</h1>
<p>Teraz możemy przystąpić do pisania skryptu PHP. Tworzymy więc nasz plik generator.php i na samym jego początku łączymy się z bazą naszej wiki</p>
<pre class="brush:php">$serverdb='localhost'; //adres serwera bazy danych
$dbuser='user'; //uzytkownik bazy danych
$dbuserpass='password'; //haslo uzytkownika
$db='database'; //nazwa bazy danych

$link = mysql_connect ($serverdb, $dbuser, $dbuserpass)
   or die (mysql_error());
mysql_select_db ($db);</pre>
<p>Gdy jesteśmy już połączeni z bazą możemy pobrać informacje o ilości artykułów. Wyciągniemy ta informację ze specjalnych tabel gdzie są przechowywane tego typu statystyki.</p>
<pre class="brush: js">$uchwyt = mysql_query ('SELECT ss_good_articles from wiki_site_stats');
$rekord = mysql_fetch_array($uchwyt);
$ilosc = $rekord['ss_good_articles'];</pre>
<p>Teraz, gdy ilość artykułów mamy już w w zmiennej <em>$ilosc</em> możemy napisać część kodu, która odmieni wyraz <em>artykuły</em> na potrzeby naszego napisu i złoży cały tekst w całość.</p>
<pre class="brush: js">$jednostki = substr($ilosc, strlen($ilosc)-1, 1);
if($jednostki == 2 || $jednostki == 3 || $jednostki == 4) $art = 'arykuły';
   else $art = 'arykułów';
$tekst = "$ilosc $art o grach Valve";</pre>
<p>Gdy to już mamy gotowe nic nie stoi na przeszkodzie by rozpocząć generowanie grafiki.</p>
<pre class="brush: js">$image = imagecreatefrompng("baner.png");
$black = imagecolorallocate($image, 0, 0, 0);
imagettftext($image, 10, 0, 250, 45, $black, 'calibri.ttf', $tekst);</pre>
<p>Podany kod kolejno wczytuje obrazek <em>baner.png</em>, tworzy indeks koloru czarnego i na końcu nakłada tekst na załadowaną grafikę. Użyta przy ostatniej operacji funkcja imagettftext przyjmuje kolejno jako argumenty zmienną z obrazkiem, rozmiar czcionki, pochylenie fontu w stopniach, współrzędne umieszczenia napisu, link do pliku z czcionką oraz na końcu treść napisu. W tym przykładzie użyliśmy czcionki <em>calibri.ttf, </em>której plik należy również umieścić w folderze z banerem.</p>
<h1>W stronę przeglądarki</h1>
<p>Aktualnie w zmiennej <em>$image</em> przechowujemy gotowy obrazek. Przed jego wyświetleniem musimy jednak zamienić co najmniej jedną informację w nagłówku wysyłanym do przeglądarki. Wersja minimalistyczna kodu odpowiedzialnego za wyświetlanie baneru wygląda tak:</p>
<pre class="brush: js">header("Content-type: image/jpeg");
imagejpeg($image);</pre>
<p>W tym przypadku informujemy tylko, że przesyłana treść jest grafiką, a nie tekstem jak wskazywałoby jego pochodzenie z pliku .php. Później przesyłamy sam obrazek. Jeśli zaś chcemy aby informacje wyświetlane na banerze były zawsze aktualne, musimy wymusić na przeglądarce by za każdym razem na nowo go pobierała z serwera. Użyjemy do tego tricku polegającego na wyłączeniu cachowania grafiki oraz ustawieniu przeszłej daty wygaśnięcia jej ważności.</p>
<pre class="brush: js">header("Cache-Control: no-cache, must-revalidate");
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Content-type: image/jpeg");
imagejpeg($image);</pre>
<h1>Podsumowanie</h1>
<p>Oto gotowy efekt nasze pracy:</p>
<p><a href="http://www.borealis.x-12.pl"><img class=" alignnone" title="Baner Borealis" src="http://borealis.net.pl/dynamic/combine/baner.png" alt="Baner Borealis" /></a></p>
<p>Fajnie wygląda i co najważniejsze spełnia swoje zadania. Należy jednak pamiętać by nie nadużywać opcji wyłączania cachowania przy dużych serwisach by nie obciążyć bazy danych. A przy naprawdę dużych encyklopediach internetowych zalecane jest napisanie skryptu cachującego liczbę artykułów.</p>
<p>Na koniec załączam <a title="Pliki baneru" href="http://mgdevelop.pl/mgdevelop/wp-content/uploads/2010/07/banermediawiki.zip">paczkę z wszystkimi plikami powyższego baneru</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://mgdevelop.pl/index.php/2010/07/baner-z-iloscia-artykulow-w-mediawiki/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Dołączanie skryptów JS do WordPressa</title>
		<link>http://mgdevelop.pl/index.php/2010/07/dolaczanie-skryptow-js-do-wordpressa/</link>
		<comments>http://mgdevelop.pl/index.php/2010/07/dolaczanie-skryptow-js-do-wordpressa/#comments</comments>
		<pubDate>Mon, 19 Jul 2010 14:07:35 +0000</pubDate>
		<dc:creator>Elektryk</dc:creator>
				<category><![CDATA[Wordpress]]></category>
		<category><![CDATA[plik]]></category>
		<category><![CDATA[rotator]]></category>
		<category><![CDATA[skrypt]]></category>
		<category><![CDATA[wp_head()]]></category>

		<guid isPermaLink="false">http://mgdevelop.pl/?p=409</guid>
		<description><![CDATA[Tworząc skórkę do WordPressa warto wzbogacić ją o ciekawe efekty. Najłatwiej osiągnąć je za pomocą skryptów JavaScript np. tworząc rotator... <a href="http://mgdevelop.pl/index.php/2010/07/dolaczanie-skryptow-js-do-wordpressa/">Czytaj dalej&#187;</a>]]></description>
			<content:encoded><![CDATA[<p>Tworząc skórkę do WordPressa warto wzbogacić ją o ciekawe efekty. Najłatwiej osiągnąć je za pomocą skryptów JavaScript np. tworząc rotator zdjęć przy użyciu <a title="Strona Tiny Carousel" href="http://www.baijs.nl/tinycarousel/">Tiny Carousel</a>. Może się jednak zrodzić pytanie czy można tak wprost dołączać własne skrypty do WP? Zwłaszcza, że np. wyżej wymieniony rotator wymaga biblioteki jQuery która jest często, choć nie zawsze automatycznie dołączana przez WordPressa. W tym poradniku wyjaśnimy tą kwestię.<span id="more-409"></span></p>
<h1>Podstawy dołączania skryptów</h1>
<p>Aby dołączyć zewnętrzny skrypt do naszego WP musimy w w skórce naszej witryny odszukać intrukcję <em>wp_head()</em>. Najczęściej można ją odnaleźć w pliku <em>header.php</em>. Tuż przed nią trzeba dopisać dwie funkcję: pierwszą która zarejestruje nowy skrypt, drugą która go dołączy do strony. Schamtycznie wygląda to tak:</p>
<pre class="brush: php">wp_register_script($nazwa, $sciezka, $biblioteki, $wersja);
wp_enqueue_script($nazwa);
wp_head();</pre>
<p>Teraz wyjaśnię pokrótce co należy wstawiać w miejsce kolejnych zmiennych. $nazwa to wewnętrzna nazwa dołączanego skryptu. Nie ma znaczenia co tam wpiszemy. Ważne tylko by w obu miejscach, przy rejestracji i dołączaniu skryptu, wpisany wyraz był taki sam. $sciezka to jak łatwo się domyślić adres do pliku z naszym kodem. Można tu wykorzystać funkcję <em><a title="o get_bloginfo() w codexie WP" href="http://codex.wordpress.org/Function_Reference/get_bloginfo">get_bloginfo()</a></em> aby WP sam wstawił aktualny adres strony lub ścieżkę do folderu z skórką. <em>$biblioteki</em> to parametr który musi być tablicą zawierającą listę bibliotek wykorzystywanych przez nasz kod. Dzięki temu WordPress kontroluje kiedy i jakie skrypty są podpinane do strony i nigdy nie zdarzy się, że np. jQuery będzie ładowane dwa razy. Listę dostępnych bibliotek i ich nazw kodowych można sprawdzić <a title="lista bibliotek dostępnych w WP" href="http://codex.wordpress.org/Function_Reference/wp_enqueue_script#Default_scripts_included_with_WordPress">tutaj</a>. Ostatni parametr to zmienna $wersja. Po każdorazowej modyfikacji skryptu musimy obowiązkowo zmienić tą liczbę by wymusić na przeglądarkach ponowne pobranie pliku zamiast korzystania z starej wersji z cachu.</p>
<p>Przykładowy pełny kod wygląda tak:</p>
<pre class="brush: php">wp_register_script('tinycarousel', get_bloginfo('template_directory') . '/js/jquery.tinycarousel.min.js', array('jquery'), '1.0' );
wp_enqueue_script('tinycarousel');</pre>
<p>W powyższym przykładzie zarejestrowaliśmy wtyczkę<em> tinycarousel</em> której plik znajduje się w folderze z skórką i która wymaga biblioteki jQuery. Następnie dołączyliśmy ją do kodu.</p>
<h1>Dołączanie warunkowe</h1>
<p>Jeśli z naszego skryptu korzystamy tylko na niektórych stronach to nie ma potrzeby dołączania plików przy każdym wyświetleniu witryny. Warto więc dopisać instrukcję warunkową która spowoduje, że nasz kod będzie dołączany jedynie na wybranych stronach. Poniższy przykłąd będzie dołączał dodatkowe pliki tylko na stronie głównej:</p>
<pre class="brush: php">if(is_home){
   wp_register_script('tinycarousel', get_bloginfo('template_directory') . '/js/jquery.tinycarousel.min.js', array('jquery'), '1.0' );
   wp_enqueue_script('tinycarousel');
}</pre>
<p>Zaś ten kod spowoduje załadowanie skryptu JS jedynie na stronie z <em>id</em> równym 29:</p>
<pre class="brush: php">if(is_page('29')){
   wp_register_script('tinycarousel', get_bloginfo('template_directory') . '/js/jquery.tinycarousel.min.js', array('jquery'), '1.0' );
   wp_enqueue_script('tinycarousel');
}</pre>
<p>Jako argument w funkcji <em>if</em> podajemy odpowiedni tag warunkowy. Więcej informacji o nich można znaleźć <a title="O tagach warunkowych w dokumentacji WP" href="http://codex.wordpress.org/Conditional_Tags">pod tym linkiem</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://mgdevelop.pl/index.php/2010/07/dolaczanie-skryptow-js-do-wordpressa/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Poezja błędu 404</title>
		<link>http://mgdevelop.pl/index.php/2010/07/poezja-bledu-404/</link>
		<comments>http://mgdevelop.pl/index.php/2010/07/poezja-bledu-404/#comments</comments>
		<pubDate>Wed, 14 Jul 2010 12:30:58 +0000</pubDate>
		<dc:creator>Elektryk</dc:creator>
				<category><![CDATA[Internet]]></category>
		<category><![CDATA[błąd]]></category>
		<category><![CDATA[ciekawe]]></category>
		<category><![CDATA[poezja]]></category>
		<category><![CDATA[strona]]></category>

		<guid isPermaLink="false">http://mgdevelop.pl/?p=371</guid>
		<description><![CDATA[Przeglądając internet od czasu do czasu zdarza się nam natrafić na błąd 404, informację o braku pliku który chcemy zobaczyć.... <a href="http://mgdevelop.pl/index.php/2010/07/poezja-bledu-404/">Czytaj dalej&#187;</a>]]></description>
			<content:encoded><![CDATA[<p>Przeglądając internet od czasu do czasu zdarza się nam natrafić na błąd 404, informację o braku pliku który chcemy zobaczyć. Jeśli ta treść jest nam bardzo potrzebna to możemy się poważnie zdenerwować. Dlatego liczba 404 nigdy nie kojarzy się internautom dobrze. A może by tak spróbować odczarować zły urok tego numeru? Na przykład poprzez poezję?</p>
<p><span id="more-371"></span>Jedną z osób która się tego podjęła był internauta o nicku Wctaiwan. Na <a title="Strona WCtaiwana" href="http://wctaiwan.tumblr.com">swojej stronie</a> umieścił wiersz własnego autorstwa. W utworze którego podmiotem lirycznym jest serwer dowiadujemy się co zmusiło to urządzenie do tak desperackiego czynu jakim jest zwrócenie błędu 404.</p>
<blockquote><p><em>It is said, “To err is human,”<br />
That quote from alt.times.lore,<br />
Alas, you have made an error,<br />
So I say, “404.”</em></p>
<p><em>Double-check your URL,<br />
As we all have heard before.<br />
You ask for an invalid filename,<br />
And I respond, “404.</em></p>
<p><em>”Perhaps you made a typo—<br />
Your fingers may be sore—<br />
But until you type it right,<br />
You’ll only get 404.[...]</em></p></blockquote>
<p><em> </em>Reszta utworu do przeczytania pod adresem: <a href="http://wctaiwan.tumblr.com/post/53783479/the-404-poem">http://wctaiwan.tumblr.com/post/53783479/the-404-poem</a>.</p>
<p>Moim faworytem jest jednak następujący wiersz którego autora niestety nie odnalazłem:</p>
<blockquote><p><em>once upon a midnight dreary,<br />
while i porn surfed, weak and weary,<br />
over many a strange and spurious site of &#8216;hot chicks galore&#8217;.</em></p>
<p><em> </em></p>
<p><em>While i clicked my fav&#8217;rite bookmark,<br />
Suddenly there came a warning,<br />
And my heart was filled with mourning,<br />
Mourning for my dear amour.</em></p>
<p><em>&#8216;Tis not possible!, I pleaded,<br />
But my browser, so conceited,<br />
Remained blank, I then repeated,<br />
Just a blank and nothing more.</em></p>
<p><em>With a scream, I was defeated,<br />
For my cookies were deleted,<br />
So i begged, no longer seated,<br />
Give me back my free hardcore!</em></p>
<p><em>Then, in answer to my query,<br />
Through the net I loved so dearly,<br />
Came its answer, dark and dreary:<br />
Quoth the server, 404</em></p></blockquote>
<p>Innym, bardziej nostalgicznym wierszem może się pochwalić pan Thomas Thurman:</p>
<blockquote><address>So many years have passed since first you sought<br />
the lands beyond the edges of the sky,<br />
so many moons reflected in your eye,<br />
(familiar newness, fear of leaving port),<br />
since first you sought, and failed, and learned to fall,<br />
(first hope, then cynicism, silent dread,<br />
the countless stars, still counting overhead<br />
the seconds to your final voyage of all&#8230;)<br />
and last, in glory gold and red around<br />
your greatest search, your final quest to know!<br />
yet&#8230; ashes drift, the embers cease to glow,<br />
and darkened life in frozen death is drowned;<br />
and ashes on the swell are seen no more.<br />
The silence surges. <strong>Error 404.</strong></address>
</blockquote>
<p>Wiersz znaleziony pod adresem: <a href="http://hellopoetry.com/poem/404/#ixzz0tecZlBC5">http://he</a><a href="http://hellopoetry.com/poem/404/#ixzz0tecZlBC5">llopoetry.com/poem/404/</a></p>
<p>Zaś na <a title="Wiersz o 404 na poemofquotes.com" href="http://www.poemofquotes.com/404">poemofquotes.com</a> można przeczytać ciekawy utwór gdzie strona 404 buntuje się przeciwko nazywaniu jej &#8222;Pliku nie znaleziono&#8221; bo przecież znaleziono: ją samą!</p>
<blockquote><p><em> &#8216;File not found&#8217;,<br />
how dare they say!<br />
I am here,<br />
just out of the way.</em></p>
<p><em>How was I found?<br />
A typo? A mistake?<br />
Or were you snooping!</em></p>
<p><em>Nonetheless we meet at last.<br />
I am found &#8211; hip hip hooray!<br />
Nevermore can they say:<br />
&#8216;File not found! I loath that page!&#8217;</em></p></blockquote>
<p>Ale to jeszcze nie wszystkie wiersze. Wiecie co to <a title="Co to jest Haiku" href="http://pl.wikipedia.org/wiki/Haiku">haiku</a>? To 17 sylabowe utwory wywodzące się z japonii które dzielą się na trzy wersy mające kolejno 5, 7 i znowu 5 sylab. Przykładowe haiku mówiące o błędzie 404 wygląda tak:</p>
<blockquote><p><em> Something you entered<br />
transcended parameters.<br />
So much is unknown. </em></p></blockquote>
<p>Ten jak i inne utwory w ciekawy sposób opisujące błędu komputerowe można poczytać na stronie: <a href="http://www.snopes.com/computer/internet/haiku.asp">http://www.snopes.com/computer/internet/haiku.asp</a>.</p>
<p>Zabawny wiersz umieścił także użytkownik mind21_98 na forum <a title="wiersz o 404" href="http://www.webhostingtalk.com/showthread.php?t=72406">webhostingtalk.com</a>:</p>
<blockquote><p><em>oh what a wonderful tizzy<br />
which was in a fizzy<br />
he couldn&#8217;t find the file<br />
which was hiding in the bushes</em></p>
<p><em> </em></p>
<p><em>push the back button oh traveller<br />
contact the owner of the last tavern<br />
find out how to get to where you&#8217;re going<br />
and be on your way</em></p></blockquote>
<p>A co u nas? Oczywiście na MGdevelop również nie mogło zabraknąć poezji. Jeśli ktoś jest ciekawy może sprawdzić jak wygląda tutaj strona 404. Dowie się wtedy, że skorzystano z następującego wiersza którego autora nie odnaleziono:</p>
<blockquote><p><em>Hello. This is a 404.<br />
I can tell you but a little more!<br />
The page you seek cannot be found,<br />
i&#8217;m sad to say it&#8217;s not around.<br />
I hope with all that&#8217;s good in me<br />
this is not a great catastrophe.<br />
Where blame should lie, i cannot say<br />
there are many ways to go astray.<br />
But this one thing i can declare<br />
this life, this world is rarely fair.<br />
So take that word and go your way<br />
i have no other words to say&#8230;</em></p></blockquote>
<p>Znacie jeszcze jakieś wiersze nt. tego paskudnego błędu? Piszcie, linkujcie, pomóżcie uzupełnić autorów.</p>
]]></content:encoded>
			<wfw:commentRss>http://mgdevelop.pl/index.php/2010/07/poezja-bledu-404/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>

