{"id":227,"date":"2010-07-23T13:00:05","date_gmt":"2010-07-23T12:00:05","guid":{"rendered":"http:\/\/eriz.pcinside.pl\/weblog\/javascript-i-uploadify-227.html"},"modified":"2010-07-23T13:02:50","modified_gmt":"2010-07-23T12:02:50","slug":"javascript-jquery-i-uploadify-odlamkowy","status":"publish","type":"post","link":"https:\/\/eriz.pcinside.pl\/weblog\/javascript-jquery-i-uploadify-odlamkowy-227.html","title":{"rendered":"JavaScript, jQuery i Uploadify &#8211; od\u0142amkowy!"},"content":{"rendered":"<p>Przyznam, \u017ce ju\u017c dawno nie mia\u0142em takiej zagwozdki, jak ta, kt\u00f3ra spotka\u0142a mnie przez ostatnie 3 dni.<\/p>\n<p>Zacz\u0105\u0142 mnie &#8211; delikatnie m\u00f3wi\u0105c &#8211; irytowa\u0107 fakt, i\u017c na maila lec\u0105 czasem za\u0142\u0105czniki 40 MiB, wi\u0119c postanowi\u0142em napisa\u0107 na potrzeby <a href=\"http:\/\/team.pcinside.pl\">teamu<\/a> ma\u0142\u0105 aplikacj\u0119, kt\u00f3ra mia\u0142a:<\/p>\n<ul>\n<li>zautoryzowa\u0107 u\u017cytkownika (to nie *share, \u017ce wszyscy maj\u0105 mie\u0107 dost\u0119p)<\/li>\n<li>u\u0142atwi\u0107 wyb\u00f3r i upload<\/li>\n<li>przyj\u0105\u0107 pliki na serwerze i da\u0107 zna\u0107, komu trzeba<\/li>\n<\/ul>\n<p>Co\u015b podobnego ju\u017c dzia\u0142a, jednak to wybitna prowizorka &#8211; najprostszy formularz i jedno pole. Ot, filozofia. Ale potrzebne jest co\u015b, co dzia\u0142a troch\u0119 lepiej i nie zra\u017ca interfejsem. <img src=\"https:\/\/eriz.pcinside.pl\/weblog\/wp-includes\/images\/smilies\/e_wink.png\" alt=\";)\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\" \/><\/p>\n<p>Teoria fajna?<\/p>\n<p><!--more--><\/p>\n<h3>nieco wi\u0119cej za\u0142o\u017ce\u0144<\/h3>\n<p>Wszystko fajnie, drugie podej\u015bcie, bo kiedy\u015b nie by\u0142o to a\u017c tak potrzebne, wi\u0119c sobie le\u017ca\u0142o gdzie\u015b na poligonie, w oczekiwaniu na lepsze czasy. A\u017c do tego tygodnia, gdy uda\u0142o mi si\u0119 w ci\u0105gu 5 minut naskroba\u0107 szkic ca\u0142ej logiki (kartka papieru i d\u0142ugopis rz\u0105dz\u0105; trzeba sobie tylko pewne wytyczne stworzy\u0107, \u017ceby by\u0142o \u0142atwo i przyjemnie ;)). Ok, back-end nie jest problemem, schody zacz\u0119\u0142y si\u0119, gdy przysz\u0142o do front-endu.<\/p>\n<p>Pierwszym b\u0142\u0119dem, kt\u00f3ry zrobi\u0142em po zaprojektowaniu pierwszych prototyp\u00f3w, by\u0142o skupienie na IE. Ech, cz\u0142owiek by\u0142 m\u0142ody i g\u0142upi (teraz tylko g\u0142upi ;)), teraz przysz\u0142a pora na skupienie si\u0119 na w\u0142a\u015bciwej aplikacji.<\/p>\n<p>Teraz, gdy balast odrzucony, mo\u017cna by\u0142o si\u0119 skupi\u0107 na w\u0142a\u015bciwym problemie i jego rozwi\u0105zaniach:<\/p>\n<ul>\n<li>podstawowy uploader, kt\u00f3ry dzia\u0142a bazuj\u0105c na zwyk\u0142ym formularzu<\/li>\n<li>uploader rozszerzony, pozwalaj\u0105cy na wy\u015bwietlenie rozmiaru poszczeg\u00f3lnych plik\u00f3w kolejki i ew. ostrze\u017cenie, gdy delikwent spr\u00f3buje wrzuci\u0107 wi\u0119cej ni\u017c wynosi przydzielony limit<\/li>\n<li>uploader &bdquo;wypasiony&rdquo; pokazuj\u0105cy post\u0119p uploadu w czasie rzeczywistym<\/li>\n<\/ul>\n<p>Najwi\u0119kszy problem, to stworzenie ujednoliconego GUI. Ostatnia opcja jednak mog\u0142a wymusi\u0107 na mnie kompromis w postaci dw\u00f3ch osobnych interfejs\u00f3w.<\/p>\n<p>Pierwsze dwie wersje by\u0142o stosunkowo \u0142atwo zrealizowa\u0107 &ndash; zwyk\u0142e elementy formularza, tworzona dynamicznie ukryta ramka (gdy\u017c upload AJAX-owy plik\u00f3w nie istnieje), formularz gdzie\u015b na dnie DOM, z ustawionym celem (target) na t\u0119 ramk\u0119. Najwi\u0119kszy problem stanowi\u0142o tutaj odpowiednie skopiowanie pola z wybranym plikiem, gdy\u017c JS &ndash; ze wzgl\u0119d\u00f3w bezpiecze\u0144stwa &ndash; nie ma mo\u017cliwo\u015bci manipulacji warto\u015bci\u0105. Ale wystarczy sklonowa\u0107 w\u0119ze\u0142 DOM (<em>cloneNode()<\/em>) do wirtualnego formularza i go pos\u0142a\u0107. Problem z g\u0142owy.<\/p>\n<p>Wyci\u0105gni\u0119cie rozmiar\u00f3w pliku, b\u0105d\u017a wielu p\u00f3l, r\u00f3wnie\u017c nie jest a\u017c takie problematyczne &ndash; przegl\u0105darki dzia\u0142aj\u0105ce na silniku WebKit oraz Gecko, dla ka\u017cdego pola wyboru pliku, ustawiaj\u0105 w\u0142asno\u015b\u0107 <em>file<\/em>, kt\u00f3ra zawiera tablic\u0119 wybranych przez u\u017cytkownika plik\u00f3w, jest tam r\u00f3wnie\u017c podklucz <em>size<\/em>. Nie b\u0119d\u0119 si\u0119 teraz rozwodzi\u0142 nad mo\u017cliwo\u015bci\u0105 wyboru wielu plik\u00f3w naraz, bo nie jest to tematem notki.<\/p>\n<p>Teraz najtwardszy orzech do zgryzienia, mianiowicie &ndash; uploader flashowy.<\/p>\n<h3>Kt\u00f3ry wybra\u0107?<\/h3>\n<p>W Sieci jest dost\u0119pnych kilka uploader\u00f3w dzia\u0142aj\u0105cych jako animacja flash (statystycznie, najcz\u0119\u015bciej odpalana wtyczka w przegl\u0105darkach;  cz\u0119\u015bciej ni\u017c Java, z tego co si\u0119 zorientowa\u0142em). Niestety, PHP bez niestandardowych rozszerze\u0144 nie ma mo\u017cliwo\u015bci raportowania o post\u0119pie uploadu do klienta. Pozostaj\u0105 albo inne j\u0119zyki (widzia\u0142em gdzie\u015b back-end w Perlu do tego celu), albo prosta aplikacja kliencka, kt\u00f3ra b\u0119dzie zawiera\u0142a odpowiednie metody ci\u0105gn\u0105ce za w\u0142a\u015bciwe sznurki w skrypcie. <img src=\"https:\/\/eriz.pcinside.pl\/weblog\/wp-includes\/images\/smilies\/e_wink.png\" alt=\";)\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\" \/><\/p>\n<p>Z tej racji, \u017ce uploader jest projektem wewn\u0119trznym, poszukiwa\u0142em jakiego\u015b darmowego narz\u0119dzia z API pozwalaj\u0105cym na zaadaptowanie do w\u0142asnej aplikacji. Poszpera\u0142em na Sieci, w miar\u0119 godne uwagi okaza\u0142y si\u0119 dwa <a href=\"http:\/\/swfupload.org\/\">SWFUploader<\/a> i <a href=\"http:\/\/uploadify.com\/\">Uploadify<\/a>. Reszta, to by\u0142y<\/p>\n<ul>\n<li>rozwi\u0105zania wyspecjalizowane (np. g\u0142\u00f3wnie upload zdj\u0119\u0107)<\/li>\n<li>p\u0142atne<\/li>\n<li>pozwalaj\u0105ce na wys\u0142anie pliku wy\u0142\u0105cznie we w\u0142asnym interfejsie<\/li>\n<li>nie pozwalaj\u0105ce na jak\u0105kolwiek kontrol\u0119 procesu wysy\u0142ki\/wybierania plik\u00f3w z poziomu skryptu<\/li>\n<\/ul>\n<p>Chcia\u0142em ujednolici\u0107 GUI ca\u0142ej aplikacji, wi\u0119c potrzebowa\u0142em:<\/p>\n<ul>\n<li>API pozwalaj\u0105cego na pobranie informacji o dodanym pliku<\/li>\n<li>Mo\u017cliwo\u015bci utworzenia i zarz\u0105dzania w\u0142asn\u0105 kolejk\u0105<\/li>\n<li>Wyzwalacza powiadamiaj\u0105cego m\u00f3j skrypt o post\u0119pie wysy\u0142ki<\/li>\n<\/ul>\n<p>SWFUpload wzi\u0105\u0142em na tapet\u0119 jako pierwszy, ze wzgl\u0119du na przyzwoit\u0105 dokumentacj\u0119 oraz popularno\u015b\u0107. Niestety, je\u015bli chodzi\u0142o o w\u0142asn\u0105 kolejk\u0119, to pojawi\u0142y si\u0119 problemy (albo po prostu nie znalaz\u0142em odpowiedniego opisu\/metod w API). Za to Uploadify okaza\u0142o si\u0119 pod tym wzgl\u0119dem do\u015b\u0107 sympatyczne. Wystarczy\u0142o &ndash; w\u0142a\u015bciwie &ndash; uruchomi\u0107 istniej\u0105ce przyk\u0142ady, poprzeci\u0105ga\u0107 troch\u0119 po stronie kursorem, \u017ceby zauwa\u017cy\u0107, \u017ce ca\u0142a kolejka by\u0142a zbudowana z element\u00f3w HTML-owych.<\/p>\n<p>Zapowiada\u0142o si\u0119 \u0142atwo i przyjemnie. W\u0142a\u015bnie, <em>zapowiada\u0142o<\/em>, bo zgodnie z prawami Murphy&rsquo;ego: <em>Je\u017celi co\u015b mo\u017ce si\u0119 nie uda\u0107 &mdash; nie uda si\u0119 na pewno.<\/em><\/p>\n<p>Po trzech dniach po\u015bwi\u0119conych na rozwalanie k\u0142\u00f3d pod nogami, siekiera jednak dopi\u0119\u0142a swego.<\/p>\n<h3>Uploadify?<\/h3>\n<h4>Starcie#1 &ndash; przyk\u0142ady<\/H4><\/p>\n<p>Pierwsz\u0105 k\u0142od\u0105 by\u0142y wspomniane przeze mnie przyk\u0142ady. Je\u015bli odpalimy je samodzielnie, wszystko jest fajnie. Naprawd\u0119 fajnie. Dzia\u0142a, buczy, czasem te\u017c i skwierczy.<\/p>\n<p>Jednak po \u015bci\u0105gni\u0119ciu najnowszej wersji uploadera i podpi\u0119ciu pod demo &ndash; co\u015b nie dzia\u0142a. <em>Ooops?<\/em> Ta, okaza\u0142o si\u0119, \u017ce w starszej wersji jest inna konwencja nazewnictwa metod. Ot, po co w dokumentacji to pisa\u0107? No fakt, jest PDF, jest changelog na stronie. Ale tylko w tym ostatnim by\u0142a wzmianka, \u017ce zmieniono nazwy metod API. Tylko w za\u0142\u0105czonym archiwum z przyk\u0142adami ju\u017c nie ma tego napisanego, \u017ce dzia\u0142a to tylko ze starszym. S\u0142odko. Dopiero gdy Firebug wrzeszczy, \u017ce co\u015b jest nie tak, to cz\u0142owiek dochodzi do wniosku, \u017ce nie ma metod w obiekcie. Ok, kr\u00f3tkie poszukiwania i wiadomo, co jest nie tak. Szkoda, \u017ce ni w z\u0105b nie jest o tym wspomniane w paczce. O ile w wi\u0119kszo\u015bci bibliotek jest do\u0142\u0105czony changelog, to w tej nie by\u0142o.<\/p>\n<p>Mo\u017ce nie jest to a\u017c takie ci\u0119\u017ckie do przetrawienia, ale potrafi niepotrzebnie wprawi\u0107 w zak\u0142opotanie. Ot taka rada dla innych, gdyby kto\u015b zacz\u0105\u0142 przygod\u0119 z Uploadify od tego tekstu. <img src=\"https:\/\/eriz.pcinside.pl\/weblog\/wp-includes\/images\/smilies\/e_wink.png\" alt=\";)\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\" \/><\/p>\n<h4>Starcie#2 &ndash; instalacja<\/H4><\/p>\n<p>Za to do\u015b\u0107 dziwn\u0105 jest filozofia pod\u0142\u0105czania Uploadify pod nasze skrypty. Mianowicie, wyszukujemy przez standardow\u0105 funkcj\u0119 jQuery element z odpowiednim selektorem, wywo\u0142ujemy na niej metod\u0119 <em>uploadify<\/em> z po\u017c\u0105danymi opcjami. I tu zaczynaj\u0105 si\u0119 schody &ndash; element <strong>musi <\/strong> posiada\u0107 atrybut <em>ID<\/em>, inaczej b\u0119dzie si\u0119 sypa\u0107. No bez przesady, przecie\u017c da\u0142o si\u0119 to zrealizowa\u0107 w prosty i elegancki spos\u00f3b, jak jest pisana reszta plugin\u00f3w &ndash; byleby by\u0142 to obiekt widziany przez metod\u0119 pieni\u0119\u017cn\u0105 (<em>$<\/em> ;)). Fakt, Uploadify musi w jaki\u015b spos\u00f3b si\u0119 odwo\u0142ywa\u0107 do animacji. Ale mo\u017cna by\u0142o to za\u0142atwi\u0107 wewn\u0119trznymi wywo\u0142aniami mi\u0119dzy obiektami, a nie w taki brudny spos\u00f3b&#8230;<\/p>\n<p>Je\u015bli chodzi o podczepianie uploadera jest jeszcze inna dziwna sprawa. Mianowicie, gdy ju\u017c wywo\u0142amy metod\u0119 konstrukcji Uploadify, to:<\/p>\n<ul>\n<li>Obiekt macierzysty, dla kt\u00f3rego zosta\u0142a wywo\u0142ana, jest ukrywany<\/li>\n<li>Wstawiana jest animacja poprzez stworzenie <em>OBJECT<\/em>\/<em>EMBED<\/em> o identyfikatorze <em>pierwotnyIDUploader<\/em><\/li>\n<li>A w\u0142a\u015bciwe zdarzenia s\u0105 podrzucane do pierwszego, ukrytego obiektu.<\/li>\n<\/ul>\n<p>Co komu szkodzi\u0142o podmieni\u0107 wybrany obiekt na animacj\u0119 flash b\u0105d\u017a dodane jej jako dziecko w DOM&#8230;? A tak, to trzeba kombinowa\u0107 z CSS, pozycjonowaniem ca\u0142o\u015bci, do tego \u015bmietnik w DOM&#8230;<\/p>\n<p>A i jeszcze jedna rzecz &ndash; nauczony tym, \u017ce w dokumentacji prawie nic nie ma (opr\u00f3cz opisu opcji konfiguracyjnych), w \u017cyciu nie pomy\u015bla\u0142em o tym, \u017ceby wysy\u0142a\u0107 zdarzenia do obiektu macierzystego, kt\u00f3ry zosta\u0142 ukryty. Wtf&#8230;?<\/p>\n<h4>Starcie#3 &ndash; spos\u00f3b obs\u0142ugi zdarze\u0144<\/H4><\/p>\n<p>Ca\u0142e jQuery posiada nie\u017ale zorganizowany system obs\u0142ugi zdarze\u0144 &ndash; nie do\u015b\u0107, \u017ce mo\u017cna \u0142atwo i szybko obs\u0142u\u017cy\u0107 standardowe, to dopisanie w\u0142asnych nie jest \u017cadnym problemem. Tak samo z konwencj\u0105 nazewnictwa &ndash; wsz\u0119dzie porzucono przedrostki <em>on<\/em> i skupiono si\u0119 na samych zdarzeniach. Za to tw\u00f3rca Uploadify poszed\u0142 troch\u0119 dziwn\u0105 drog\u0105 &ndash; zdarzenia wyzwalane przez jQuery przeznaczy\u0142 raczej na cele wewn\u0119trzne biblioteki (bo tak s\u0105 przez animacj\u0119 flash wyzwalane), a u\u017cytkownikowi pozostawi\u0142 metody definiowane przy konstrukcji uploadera, np. <em>onComplete, onProgress<\/em>. Ok, ale wewn\u0105trz przecie\u017c i tak si\u0119 wykonuj\u0105 <em>uploadifyComplete, uploadifyProgress<\/em>.<\/p>\n<p>I \u017ceby wygodnie z tego korzysta\u0107, nale\u017ca\u0142oby najpierw zdj\u0105\u0107 obs\u0142ug\u0119 wszystkich tych zdarze\u0144 ze standardowej biblioteki API. Na usprawiedliwienie decyzji autor\u00f3w &#8211; w Uploadify jest zintegrowana jaka\u015b prowizoryczna kolejka. Fakt, dzia\u0142a, ale &ndash; moim zdaniem &ndash; programi\u015bci i tak samodzielnie zaimplementuj\u0105 w\u0142asn\u0105, a fakt wrzucenia tego do ca\u0142o\u015bci przez autor\u00f3w do jednego wora tylko niepotrzebnie zwi\u0119kszy\u0142 rozmiar pliku wynikowego. Z drugiej strony, pozwala to na \u0142atwe dorzucenie uploadu przez pocz\u0105tkuj\u0105cych, zapewnienie funkcjonalno\u015bci <em>Out of The Box<\/em>.<\/p>\n<p>Jednak wcale bym si\u0119 nie obrazi\u0142, gdyby by\u0142o to ujednolicone, i np. w przyk\u0142adach mo\u017cna by by\u0142o eleganck\u0105 kolejk\u0119 zaimplementowa\u0107 jako ustawienia przy konstrukcji. I wtedy nie by\u0142oby nadmiarowego kodu, a ka\u017cdy mia\u0142by skrojone na miar\u0119 &ndash; czyste, fajne API.<\/p>\n<h4>Starcie#4 &ndash; fochy wtyczki Flash<\/H4><\/p>\n<p>Przyznam, \u017ce ju\u017c dawno mia\u0142em tak\u0105 chochlicz\u0105 zagadk\u0119, kt\u00f3ra sprawi\u0142a, \u017ce sp\u0119dzi\u0142em mn\u00f3stwo czasu na testowaniu r\u00f3\u017cnych kombinacji uniemo\u017cliwiaj\u0105cych dzia\u0142anie skryptu. Mia\u0142em zagwozdk\u0119, dlaczego przy wybraniu paru plik\u00f3w, Uploadify w og\u00f3le nie wyzwala\u0142o zdarzenia <em>onComplete,<\/em> pomimo \u017ce pierwszy plik by\u0142 wysy\u0142any na serwer. Za to <em>onProgress<\/em> by\u0142o &ndash; 100% post\u0119pu w wysy\u0142ce.<\/p>\n<p>Winowajca&#8230;? Nadawanie <em>display: none<\/em> dla warstwy zawieraj\u0105cej uploader. Na forach Uploadify wyczyta\u0142em, \u017ce je\u017celi taka sytuacja ma miejsce, to wtyczka Adobe zamra\u017ca dzia\u0142anie animacji. Zreszt\u0105 &ndash; nie wiedzie\u0107 czemu &ndash; czasem wynikaj\u0105 dziwne problemy, kt\u00f3re &ndash; pomimo ksi\u0105\u017ckowego zapisu kodu &ndash; bior\u0105 si\u0119 znik\u0105d. Zatem &ndash; na czas uploadu trzeba zadba\u0107, aby w naszym kreatorze obiekt z uploaderem by\u0142 ca\u0142y czas widoczny, dla kodu. Co nie znaczy, \u017ce nie mo\u017cemy go schowa\u0107 ujemnym <em>z-index<\/em>em, czy zerow\u0105 przezroczysto\u015bci\u0105 (gdy zastosujemy tylko to ostatnie, to w Operze tak \u015brednio przechodzi&#8230;).<\/p>\n<h4>Starcie#5 &ndash; JS + Flash + Firebug = WTF?<\/H4><\/p>\n<p>Przyznam, \u017ce mnie to troch\u0119 zaskoczy\u0142o &ndash; w ka\u017cdym zdarzeniu wyzwalanym przez Uploadify, u\u017cycie funkcji, kt\u00f3re zatrzymuj\u0105 dzia\u0142anie GUI (np. a<em>lert()<\/em>), powoduje zamro\u017cenie dzia\u0142ania Firefoksa. Nie wiem, czym jest to spowodowane (gdy\u017c ten sam kod na np. Chromium dzia\u0142a bez problem\u00f3w), ale pomaga stary dobry kod. Zamiast <em>alert:<\/em><\/p>\n<p><code lang=\"javascript\"><br \/>\nsetTimeout(function(){<br \/>\n\talert('asd');<br \/>\n}, 1);<br \/>\n<\/code><\/p>\n<p>Jest to jedna z rzeczy, kt\u00f3ra stanowi dla mnie zagadk\u0119. I chyba ni\u0105 pozostanie. Huh&#8230;<\/p>\n<h2>Czysty kod<\/h2>\n<p>Ok, 3 strony A4 rozwa\u017ca\u0144 teoretycznych, teraz przejd\u017amy do implementacji w praktyce. Moim zdaniem, do\u015b\u0107 czytelnej, w kt\u00f3rej panuje porz\u0105dek i \u0142atwo jest to dostosowa\u0107. <img src=\"https:\/\/eriz.pcinside.pl\/weblog\/wp-includes\/images\/smilies\/e_smile.png\" alt=\":)\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\" \/><\/p>\n<p>Zacznijmy od szkieletu.<\/p>\n<h4>HTML<\/H4><\/p>\n<p><code lang=\"html\"><br \/>\n<head><br \/>\n<script type=\"text\/javascript\" src=\"jquery.js\"><\/script><br \/>\n<script type=\"text\/javascript\" src=\"swfobject.js\"><\/script><br \/>\n<script type=\"text\/javascript\" src=\"jquery.uploadify.js\"><\/script><\/p>\n<p><script type=\"text\/javascript\" src=\"script.js\"><\/script><\/p>\n<style>\n#queue\n    { list-style-type: none; padding: 0; margin: 0; }<\/p>\n<p>    #queue li\n        { overflow: hidden; }<\/p>\n<p>    #queue li span.size, #queue li a\n        { float: right }<\/p>\n<p>    #queue li div.progress\n        { height: 20px; border: 1px solid #000; overflow: hidden; }<\/p>\n<p>        #queue li div.progress span\n            { float: left; height: 20px; background: #000; }<\/p>\n<\/style>\n<p><\/head><br \/>\n<body><\/p>\n<div id=\"add\">asd<\/div>\n<p><\/body><br \/>\n<\/code><\/p>\n<p>No zbyt wiele nie ma tu do t\u0142umaczenia &ndash; par\u0119 regu\u0142 CSS, element b\u0119d\u0105cy pojemnikiem na uploader, wszystko.<\/p>\n<h4>JS<\/H4><\/p>\n<p><code lang=\"javascript\"><br \/>\n$(function(){<br \/>\n    \/\/ jaki\u015b uchwyt do listy ;)<br \/>\n    var list = $('<\/p>\n<ul id=\"queue\" \/>').appendTo('body');<\/p>\n<p>    $(\"#add\")<br \/>\n        .uploadify({<br \/>\n            'uploader': 'uploadify.swf',<br \/>\n            'script': 'upload.php',<br \/>\n            'multi': true,<br \/>\n            'displayData': 'speed',<br \/>\n        });<\/p>\n<p>    $('#add')   \/\/ uploadify nie zwraca metody \u0142a\u0144cuchowej, niestety...<br \/>\n        .unbind('uploadifySelect uploadifyComplete uploadifyCancel uploadifyProgress')  \/\/ pozbywamy si\u0119 domy\u015blnych handler\u00f3w<br \/>\n        .bind('uploadifySelect', function(event, ID, data){ \/\/ zdarzenie wyzwalane przy dodaniu pliku, ka\u017cdego z osobna<br \/>\n            var item = $(<br \/>\n                '<\/p>\n<li>'+<br \/>\n                '<span class=\"size\" \/>'+<br \/>\n                '<\/p>\n<div class=\"progress\"><span \/><\/div>\n<p>'+<br \/>\n                '<a>usu\u0144<\/a>'+<br \/>\n                '<\/li>\n<p>'); \/\/ tworzymy element listy - nazwa w <\/p>\n<li \/>, rozmiar, post\u0119p i kasowanie\n<p>            item.attr('rel', ID);    \/\/ ID pliku zwracane przez Uploadify<\/p>\n<p>            item.find('span.size').html(data.size); \/\/ etykietka z rozmiarem<br \/>\n            item.append(data.name); \/\/ nazwa ;)<\/p>\n<p>            list.append(item);  \/\/ dopisanie do kolejki<br \/>\n        })<br \/>\n        .bind('uploadifyComplete uploadifyCancel', function(event, ID, data){   \/\/ uko\u0144czenie uploadu pliku b\u0105d\u017a jego anulowania<br \/>\n            list.find('li[rel='+ID+']').remove();   \/\/ przy zako\u0144czeniu\/anulowaniu pliku - usu\u0144 z listy<br \/>\n        })<br \/>\n        .bind('uploadifyProgress', function(event, ID, data, progress){<br \/>\n            list.find('li[rel='+ID+'] div.progress span').width(progress.percentage+'%');<br \/>\n        });<\/p>\n<p>    \/\/ \u017ceby si\u0119 da\u0142o skasowa\u0107 ;)<br \/>\n    $('li a', list).live('click', function(e){  \/\/ pilnujemy, aby ka\u017cdy nowy element mia\u0142 dodan\u0105 odpowiedni\u0105 funkcj\u0119<br \/>\n        e.preventDefault();<br \/>\n        $('#add').uploadifyCancel(<br \/>\n            $(this).parent().attr('rel')<br \/>\n        );<br \/>\n    });<\/p>\n<p>    \/\/ w\u0142a\u015bciwy upload<br \/>\n    $('<a>wy\u015blij<\/a>').click(function(e){<br \/>\n        e.preventDefault();<br \/>\n        $('#add').uploadifyUpload();<br \/>\n    }).appendTo('body');<br \/>\n});<br \/>\n<\/code><\/p>\n<p>Co si\u0119 da\u0142o, opatrzy\u0142em komentarzem. A teraz pora na reszt\u0119 wyja\u015bnie\u0144. <img src=\"https:\/\/eriz.pcinside.pl\/weblog\/wp-includes\/images\/smilies\/e_wink.png\" alt=\";)\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\" \/> Najwa\u017cniejsze jest pozbycie si\u0119 domy\u015blnej funkcji obs\u0142uguj\u0105cej wybrane zdarzenia. Je\u015bli tego nie zrobimy, Uploadify wrzuci obs\u0142ug\u0119 swojej, wbudowanej kolejki.<\/p>\n<p>Pewnie kto\u015b mnie zapyta, dlaczego u\u017cy\u0142em dwa razy <em>$(&lsquo;#add&rsquo;)<\/em>. C\u00f3\u017c, developerzy Uploadify nie zadbali o to, aby ich metody by\u0142y \u0142a\u0144cuchowe. Trzeba si\u0119 pom\u0119czy\u0107.<\/p>\n<p>Do pe\u0142ni szcz\u0119scia potrzebujemy obs\u0142u\u017cy\u0107 zaledwie 4 metody:<\/p>\n<ul>\n<li><strong>uploadifySelect<\/strong>\n<p>metoda ta jest wyzwalana przez Flash dla ka\u017cdego dodanego przez nas pliku. Pozwala obs\u0142u\u017cy\u0107 dodawanie do w\u0142asnej kolejki, jako argument podaje m.in. ID, kt\u00f3ry jest istotny ze wzgl\u0119du na to, aby identyfikowa\u0107 konkretny plik w wewn\u0119trznej kolejce uploadera (nasza lista ni\u0105 nie jest, gwoli \u015bcis\u0142o\u015bci). Mo\u017cna, dzi\u0119ki temu, kasowa\u0107 wybrany obiekt z kolejki, uploadowa\u0107 tylko jeden wybrany plik, czy te\u017c zidentyfikowa\u0107 wysy\u0142any plik. Zachowa\u0142em go w atrybucie <em>rel<\/em>, aby p\u00f3\u017aniej mo\u017cna by\u0142o przy pomocy selektora pobra\u0107 odpowiedni wiersz<\/p>\n<\/li>\n<li><strong>uploadifyComplete\/uploadifyCancel<\/strong>\n<p>te dwie mo\u017cemy obs\u0142u\u017cy\u0107 jedn\u0105 funkcj\u0105 &ndash; pozwala na wywalenie z w\u0142asnej kolejki ju\u017c wys\u0142anego, czy anulowanego pliku<\/p>\n<\/li>\n<li><strong>uploadProgress<\/strong>\n<p>pozwala na pokazanie w\u0142asnego paska post\u0119pu. Nie skupia\u0142em si\u0119 na takich szczeg\u00f3\u0142ach, jak pr\u0119dko\u015b\u0107 (co jest do zrobienia). Przy ka\u017cdym wywo\u0142aniu otrzymujemy ID, po kt\u00f3rym identyfikujemy, kt\u00f3ry plik jest wysy\u0142any (jest to istotne, gdy\u017c Uploadify pozwala na wysy\u0142anie kilku naraz)<\/p>\n<\/li>\n<\/ul>\n<p>Pozosta\u0142o jeszcze przypilnowa\u0107, aby da\u0142o si\u0119 wykasowa\u0107 pliki z kolejki. Po to metoda <em>live()<\/em> operuj\u0105ca na ka\u017cdym nowo utworzonym linku w kolejce. Przy klikni\u0119ciu nakazuje ona uploaderowi anulowanie konkretnego pliku. Aby pobra\u0107 parametr &ndash; skaczemy w hierarchi wy\u017cej i pobieramy ID z atrybutu <em>rel<\/em>.<\/p>\n<p>Skrypt-cel uploadu nie jest wielk\u0105 filozofi\u0105, wystarczy przeklepa\u0107 <A HREF=\"http:\/\/pl.php.net\/manual\/pl\/features.file-upload.post-method.php\" >ksi\u0105\u017ckowy przyk\u0142ad<\/a>.<\/p>\n<p>Dzia\u0142a? Sprawd\u017a. <img src=\"https:\/\/eriz.pcinside.pl\/weblog\/wp-includes\/images\/smilies\/e_wink.png\" alt=\";)\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\" \/><\/p>\n<h4>Podsumowanie<\/H4><\/p>\n<p>Uploadify jest naprawd\u0119 fajnym narz\u0119dziem, tylko z troch\u0119 kiepskim front-endem je\u015bli chodzi o JavaScript. Niestety, odbieganie od standard\u00f3w, jakimi s\u0105 obs\u0142uga zdarze\u0144 oraz brak chainingu, powoduje, \u017ce trzeba si\u0119 jednak troch\u0119 napoci\u0107, \u017ceby praca z uploaderem by\u0142a naprawd\u0119 przyjemna. Tekst napisa\u0142em na bazie moich parodniowych do\u015bwiadcze\u0144, mam nadziej\u0119, \u017ce si\u0119 przyda. <img src=\"https:\/\/eriz.pcinside.pl\/weblog\/wp-includes\/images\/smilies\/e_wink.png\" alt=\";)\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\" \/><\/p>\n<p>O czym trzeba pami\u0119ta\u0107:<\/p>\n<ul>\n<li>uwa\u017caj przy tworzeniu kreator\u00f3w z Uploadify &ndash; warstwa z uploaderem musi by\u0107 ca\u0142y czas widoczna w DOM<\/li>\n<li>nie kr\u0119puj si\u0119 z kompletnym wy\u0142\u0105czaniem standardowych zdarze\u0144 &ndash; zaimplementuj je zgodnie z modelem jQuery<\/li>\n<li>pilnuj si\u0119 z przyzwyczajeniami &ndash; chaining z metodami API Uploadify spowoduje tylko siwienie Twoich w\u0142os\u00f3w<\/li>\n<\/ul>\n<p>A czemu nie SWFUpload&#8230;? C\u00f3\u017c:<\/p>\n<ul>\n<li>ci\u0119\u017csze ni\u017c Uploadify<\/li>\n<li>wygodne wykorzystanie z jQuery wymaga\u0142oby do\u0142\u0105czenia <a href=\"http:\/\/blogs.bigfish.tv\/adam\/2009\/06\/14\/swfupload-jquery-plugin\/\" >dodatkowej biblioteki<\/a><\/li>\n<li>Uploadify posiada wszystkie niezb\u0119dne funkcje <img src=\"https:\/\/eriz.pcinside.pl\/weblog\/wp-includes\/images\/smilies\/e_wink.png\" alt=\";)\" class=\"wp-smiley\" style=\"height: 1em; max-height: 1em;\" \/><\/li>\n<\/ul>\n<p>Cho\u0107 jedno musz\u0119 przyzna\u0107 &ndash; wtyczka SWFUpload do jQuery zosta\u0142a jednak lepiej przemy\u015blana pod k\u0105tem obs\u0142ugi zdarze\u0144.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Przyznam, \u017ce ju\u017c dawno nie mia\u0142em takiej zagwozdki, jak ta, kt\u00f3ra spotka\u0142a mnie przez ostatnie 3 dni. Zacz\u0105\u0142 mnie &#8211; delikatnie m\u00f3wi\u0105c &#8211; irytowa\u0107 fakt, i\u017c na maila lec\u0105 czasem za\u0142\u0105czniki 40 MiB, wi\u0119c postanowi\u0142em napisa\u0107 na potrzeby teamu ma\u0142\u0105 aplikacj\u0119, kt\u00f3ra mia\u0142a: zautoryzowa\u0107 u\u017cytkownika (to nie *share, \u017ce wszyscy maj\u0105 mie\u0107 dost\u0119p) u\u0142atwi\u0107 wyb\u00f3r [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3,11],"tags":[48,79,93,30],"_links":{"self":[{"href":"https:\/\/eriz.pcinside.pl\/weblog\/wp-json\/wp\/v2\/posts\/227"}],"collection":[{"href":"https:\/\/eriz.pcinside.pl\/weblog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/eriz.pcinside.pl\/weblog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/eriz.pcinside.pl\/weblog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/eriz.pcinside.pl\/weblog\/wp-json\/wp\/v2\/comments?post=227"}],"version-history":[{"count":0,"href":"https:\/\/eriz.pcinside.pl\/weblog\/wp-json\/wp\/v2\/posts\/227\/revisions"}],"wp:attachment":[{"href":"https:\/\/eriz.pcinside.pl\/weblog\/wp-json\/wp\/v2\/media?parent=227"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/eriz.pcinside.pl\/weblog\/wp-json\/wp\/v2\/categories?post=227"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/eriz.pcinside.pl\/weblog\/wp-json\/wp\/v2\/tags?post=227"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}