Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [jQuery] Plugin uploadu zdjęć z podglądem
Forum PHP.pl > Inne > Oceny
phpion
Witam,
dziś postanowiłem spróbować swych sił w napisaniu pluginu jQuery. Jest to mój pierwszy plugin tak więc wszelkie uwagi mile widziane. Docelowo planuję dołożyć obsługę zdarzeń by móc dowolnie reagować na określone sytuacje.

Zadaniem pluginu jest upload plików graficznych z podglądem pliku po wgraniu. Całość działa na zasadzie wysyłania dynamicznie tworzonych formularzy do ramek pływających (oba elementy ukryte). Skrypt cyklicznie sprawdza zawartość ramki, w której pojawia się odpowiedź w postaci JSON. Odpowiedź błędna zawiera komunikat błędu, natomiast poprawna ścieżkę do wgranego zdjęcia.

Po wgraniu plików na serwer ich nazwy zawarte są w ukrytych polach o takich samych nazwach, jak nazwy pól typu file. Zatem po wysłaniu formularza (uzupełnionego np. o inne dane) otrzymujemy również ścieżki do wcześniej wgranych plików, dzięki czemu można je przenieść w konkretne miejsce.

Demo znajduje się tutaj:
http://notifero.pl/ntfrUploadPreview/

Kod pluginu:
[JAVASCRIPT] pobierz, plaintext
  1. /**
  2.  * Plugin uploadu plików graficznych z podglądem.
  3.  *
  4.  * @author Michał "phpion" Płonka
  5.  */
  6. (function($){
  7. var counter = 0;
  8.  
  9. var methods = {
  10. init: function(options) {
  11. var settings = $.extend( {
  12. field: 'ntfrUploadPreview_file', // Nazwa pola z plikiem.
  13. preview: 'img/t.png', // Domyślny plik podglądu.
  14. uploader: 'ntfrUploadPreview_uploader.php', // Skrypt uploadu.
  15. timeout: 250 // Czas cyklicznego odczytywania zawartości ramki.
  16. }, options);
  17.  
  18. return this.each(function() {
  19. var $this = $(this);
  20.  
  21. // Ustalenie ID elementu.
  22. var id = $this.attr('id');
  23.  
  24. if (typeof id == 'undefined' || id == false) {
  25. id = 'ntfrUploadPreview_' + (++counter);
  26. $this.attr('id', id);
  27. }
  28. //
  29.  
  30. // Utworzenie elementu podglądu.
  31. var preview = '<div id="' + id + '_preview" class="ntfrUploadPreview_preview">';
  32. preview += '<img src="' + settings.preview + '" alt="' + settings.preview + '" id="' + id + '_uploader_preview" />';
  33. preview += '<input type="hidden" name="' + $this.attr('name') + '" id="' + id + '_uploader_file" />';
  34. preview += '</div>';
  35.  
  36. $(preview).insertAfter($this);
  37. //
  38.  
  39. // Utworzenie elementów uploadera.
  40. var uploader = '<div id="' + id + '_uploader" class="ntfrUploadPreview_uploader">';
  41. uploader += '<form action="' + settings.uploader + '" method="post" id="' + id + '_uploader_form" target="' + id + '_uploader_iframe" enctype="multipart/form-data">';
  42. uploader += '<fieldset></fieldset>';
  43. uploader += '</form>';
  44. uploader += '<iframe src="" name="' + id + '_uploader_iframe" id="' + id + '_uploader_iframe"></iframe>';
  45. uploader += '</div>';
  46.  
  47. $("body").append(uploader);
  48. //
  49.  
  50. // Zmiana nazwy pola.
  51. $this.attr('name', settings.field);
  52. //
  53.  
  54. // Przypisanie zdarzenia onchange.
  55. $this.change(function() {
  56. var $this = $(this);
  57. var id = $this.attr('id');
  58.  
  59. // Wyczyszczenie zawartości ramki.
  60. document.getElementById(id + '_uploader_iframe').contentWindow.document.body.innerHTML = '';
  61. //
  62.  
  63. // Utworzenie klona pola.
  64. var clone = $this.clone();
  65. clone
  66. .val('')
  67. .attr('id', id + '_clone')
  68. .attr('disabled', 'disabled')
  69. ;
  70. clone.insertBefore('#' + id + '_preview');
  71. //
  72.  
  73. // Dodanie pola i wysłanie formularza do ramki.
  74. $('#' + id + '_uploader_form fieldset').append($this);
  75. $('#' + id + '_uploader_form').submit();
  76. //
  77.  
  78. // Odbieranie odpowiedzi jako zawartości ramki.
  79. catchUploadResponse = function() {
  80. var id = $this.attr('id');
  81. var response = document.getElementById(id + '_uploader_iframe').contentWindow.document.body.innerHTML;
  82.  
  83. if (response.length > 0) {
  84. response = $.parseJSON(response);
  85.  
  86. if (response.status == 1) {
  87. // Aktualizacja podglądu wgranego zdjęcia.
  88. $('#' + id + '_uploader_preview')
  89. .attr('src', response.message)
  90. .attr('alt', response.message)
  91. ;
  92. //
  93.  
  94. // Aktualizacja wartości pola z nazwą pliku.
  95. $('#' + id + '_uploader_file').val(response.message);
  96. //
  97. }
  98. else {
  99. alert(response.message);
  100. }
  101.  
  102. // Przywrócenie pola do formy wyjściowej.
  103. $('#' + id + '_clone').remove();
  104. $this.val('');
  105. $this.insertBefore('#' + id + '_preview');
  106. //
  107. }
  108. else {
  109. setTimeout('catchUploadResponse()', settings.timeout);
  110. }
  111. };
  112.  
  113. catchUploadResponse();
  114. //
  115. });
  116. });
  117. }
  118. };
  119.  
  120. $.fn.ntfrUploadPreview = function(method) {
  121. if (methods[method]) {
  122. return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
  123. } else if (typeof method === 'object' || !method) {
  124. return methods.init.apply(this, arguments);
  125. } else {
  126. $.error('Method ' + method + ' does not exist on jQuery.ntfrUploadPreview');
  127. }
  128. };
  129. })(jQuery);
[JAVASCRIPT] pobierz, plaintext


Kod pliku uploadu:
  1. <?php
  2. $file = 'ntfrUploadPreview_file'; // Nazwa pola z plikiem.
  3.  
  4. $response = array(
  5. 'status' => 0,
  6. 'message' => ''
  7. );
  8.  
  9. if (isset($_FILES[$file]) && is_array($_FILES[$file]) && array_key_exists('error', $_FILES[$file]) && $_FILES[$file]['error'] == UPLOAD_ERR_OK) {
  10. $path_rel = 'upload/'.time().'_'.$_FILES[$file]['name']; // Ścieżka relatywna.
  11. $path_abs = pathinfo(__FILE__, PATHINFO_DIRNAME).DIRECTORY_SEPARATOR.$path_rel; // Ścieżka absolutna.
  12.  
  13. if (in_array(strtolower(pathinfo($_FILES[$file]['name'], PATHINFO_EXTENSION)), array('jpg', 'jpeg', 'png', 'gif'))) {
  14. if (@move_uploaded_file($_FILES[$file]['tmp_name'], $path_abs)) {
  15. $response = array(
  16. 'status' => 1,
  17. 'message' => $path_rel
  18. );
  19. }
  20. else {
  21. $response['message'] = 'Błąd podczas wgrywania pliku.';
  22. }
  23. }
  24. else {
  25. $response['message'] = 'Wybrany plik powinien być plikiem typu *.jpg, *.png lub *.gif.';
  26. }
  27. }
  28. else {
  29. $response['message'] = 'Brak pliku.';
  30. }
  31.  
  32. echo json_encode($response);


Zapraszam do testowania i zgłaszania swoich uwag smile.gif
prowseed
Moja taka uwaga, jesli wgrywam plik o rozszerzeniu gif, to moze by po prostu wyjmowac z niego pierwsza klatke, a nie skalowac caly plik. Poza tym przez pomylke wybieram inny plik i musze czekac az sie wgra bez mozliwosci anulowania (pole sie zmienia w disabled). Ogolnie bardzo fajne : )
ShadowD
Jak dla mnie taki skrypt powinien posiadać:
- Pasek postępu
- Multi upload
- Możliwość przerwania wysyłania
- W polu powinna pojawić się notka z nazwą wgrywanego pliku lub ścieżką jego dostępu

Nie wiem czy to wszystko jest realne do wykonania, bo gdzieś czytałem o potrzebie zastosowania flasha do postępu, ale jak się za to zabierasz to podałem kilka todo. :-)

To co już napisałeś działa zgrabnie!
phpion
Dzięki za pierwsze opinie.

Cytat(prowseed @ 18.04.2012, 17:13:26 ) *
Moja taka uwaga, jesli wgrywam plik o rozszerzeniu gif, to moze by po prostu wyjmowac z niego pierwsza klatke, a nie skalowac caly plik.

To co zrobisz po stronie skryptu PHP to Twoja sprawa. Jest to totalny przykład. W odpowiedzi musisz zwrócić ścieżkę do pliku do wyświetlenia. Jest ona podstawiana pod src obrazka podglądu.

Cytat(prowseed @ 18.04.2012, 17:13:26 ) *
Poza tym przez pomylke wybieram inny plik i musze czekac az sie wgra bez mozliwosci anulowania (pole sie zmienia w disabled).

No tak, pomyślę o tym.

Cytat(ShadowD @ 18.04.2012, 17:57:37 ) *
- Pasek postępu
- Multi upload
- Możliwość przerwania wysyłania
- W polu powinna pojawić się notka z nazwą wgrywanego pliku lub ścieżką jego dostępu

- Nierealne, do tego trzeba stosować cuda w postaci chociażby Flasha, a chcę tego uniknąć. Jedyne co będzie można zrobić to podstawienie jakiegoś animowanego gifa symbolizującego wgrywanie pliku. No ale to prawdopodobnie zrobię jako zdarzenie.
- Też nierealne. Główną ideą było podpięcie się pod zwykłe pola input type="file" bez konieczności jakichkolwiek dodatkowych modyfikacji. Wybieranie pliku po kliknięciu w to pole nie umożliwia wyboru kilku plików czy wręcz całego katalogu.
- Zgadza się, o tym samym pisał prowseed.
- W sumie nazwa pliku pojawia się w polu wyboru pliku - tak, jak w przypadku zwykłego pola wyboru pliku. Również rozważę to jako zdarzenia umożliwiając dowolną operację na otrzymanej odpowiedzi.
uncuncunc
Cytat(phpion @ 19.04.2012, 07:32:53 ) *
- Nierealne, do tego trzeba stosować cuda w postaci chociażby Flasha, a chcę tego uniknąć. Jedyne co będzie można zrobić to podstawienie jakiegoś animowanego gifa symbolizującego wgrywanie pliku. No ale to prawdopodobnie zrobię jako zdarzenie.
- Też nierealne. Główną ideą było podpięcie się pod zwykłe pola input type="file" bez konieczności jakichkolwiek dodatkowych modyfikacji. Wybieranie pliku po kliknięciu w to pole nie umożliwia wyboru kilku plików czy wręcz całego katalogu.
- Zgadza się, o tym samym pisał prowseed.
- W sumie nazwa pliku pojawia się w polu wyboru pliku - tak, jak w przypadku zwykłego pola wyboru pliku. Również rozważę to jako zdarzenia umożliwiając dowolną operację na otrzymanej odpowiedzi.


A o html5 słyszałeś? Jest multiupload, paski postępu, do wyboru do koloru.
phpion
Dopóki HTML5 nie będzie powszechnym standardem pozostanę przy dotychczasowych rozwiązaniach.
!*!
Cytat(phpion @ 19.04.2012, 11:26:04 ) *
Dopóki HTML5 nie będzie powszechnym standardem pozostanę przy dotychczasowych rozwiązaniach.


Powszechnym standardem? To się już stare robi i jest w ogólnym użytku od bardzo dawna. Poza tym kto Ci broni zrobić progressbar tradycyjnie? Html5 daje tylko znaczniki w tym zakresie i nic więcej, równie dobrze możesz zrobić to na div. Multiupload jest stosowany, Ty masz go tylko obsłużyć a nie się na nim opierać.
ShadowD
Co do postępu to wiem, że wymaga flash'a, ale multi upload jest i funkcjonuje dobrze bez tego typu "ficzerów" - nie jestem znawcą więc może głupoty prawię, nigdy się tym nie zajmowałem, nie mniej jednak od systemu uploadu właśnie tego wymagam i jeśli coś potrzebuje flash'a to z niego bym korzystał jest to na prawdę wielki plus! :-)

Ps. Gmail ma fajnie zaimplementowany upload, tak jak w moim mniemaniu powinien wyglądać ideał.
!*!
Cytat(ShadowD @ 19.04.2012, 13:13:08 ) *
Co do postępu to wiem, że wymaga flash'a


Od kiedy? Skoro używasz jQ to użyj jQ. http://t.wits.sg/misc/jQueryProgressBar/demo.php i wiele innych.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2024 Invision Power Services, Inc.