Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Web программирование > JavaScript, Ajax
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 03.11.2015, 11:58   #1
OliverVood
Пользователь
 
Регистрация: 06.05.2010
Сообщений: 32
По умолчанию Помогите понять код

Доброго времени суток. Пытаюсь сделать upload для своего сайта, нашёл то что мне надо. Но не могу разобраться в коде. Здесь много лишнего. А я в js не шарю. Помогите пожалуйста понять что тут надо, а что можно выкинуть...
Код HTML:
<!DOCTYPE html>
<html lang="ru-RU"><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
  <meta charset="utf-8">
</head>
<body>
    <form method="POST" enctype="multipart/form-data">
      <label for="image">Фотография:</label>
      <input id="image" name="image" accept="image/*" multiple="" type="file">
      <div class="preview"></div>
      <p class="description">Подходящие форматы для фотографии: PNG, JPG, GIF.</p>
        <button disabled="disabled" type="submit">Отправить</button>
    </form>

    <output name="echo" class="hidden"></output>

  <script>
  (function(window, document) {

    var form    = document.querySelector('form'),
        submit  = form.querySelector('[type=submit]'),
        support = window.FormData && window.File && window.FileList && window.FileReader,
        preview = document.querySelector('.preview'),
        echo    = document.querySelector('output'),
        queue   = [],

    previewImages = function(files) {
      [].forEach.call(files, function(file) {
        if (file.type.match(/image.*/)) {
          var reader = new FileReader();

          reader.onload = function(event) {
            var exist = [].some.call(preview.querySelectorAll('img'), function(element) {
              return element.src == event.target.result;
            });

            if (!exist) {
              var img = document.createElement('img');
              img.src = event.target.result;

              img.onclick = function() {
                removePreview(img);
              };

              preview.appendChild(img);

              queue.push({file: file, element: img});
              checkValidity();
            }
          };

          reader.readAsDataURL(file);
        }
      });
    },

    removePreview = function(element) {
      queue = queue.filter(function(file) {
        return file.element != element;
      });

      element.parentNode.removeChild(element);
      checkValidity();
    },

    checkValidity = function() {};

    if (form.checkValidity) {
      checkValidity = function() {
        submit.disabled = !(form.checkValidity() && queue.length > 0);
      };
    };

    if (window.localStorage) {
      var elements = form.querySelectorAll('[name]'),
          length = elements.length,
          i;

      for (i=0; i<length; i++) {
        (function(element) {
          var name = element.getAttribute('name');

          if (name != 'image') {
            element.value = localStorage.getItem(name) || '';

            element.onkeyup = function() {
              var value = element.value;
              if (!value) {
                value = '';
              }

              localStorage.setItem(name, value);
              checkValidity();
            };
          }
        })(elements[i]);
      }
    }

    if (support) {
      form.querySelector('[type=file]').addEventListener('change', function() {
        previewImages(this.files);
        this.value = '';
      }, false);
    }

    checkValidity();

    form.onsubmit = function(event) {
      submit.disabled = true;
      submit.value = 'Отправляется...';

      if (window.localStorage) {
        localStorage.removeItem('message');
      }

      if (support) {
        event.preventDefault();

        var data = new FormData(form),
            xhr  = new XMLHttpRequest();

        queue.forEach(function(element) {
          data.append('image', element.file);
        });

        xhr.open('post', '/temp/echo?t=' + (new Date()).getTime());
        // xhr.open(form.getAttribute('method'), form.getAttribute('action'));
        xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');

        xhr.onreadystatechange = function() {
          if (xhr.readyState == 4) {
            if (xhr.status == 200) {
              var message = JSON.parse(xhr.responseText);

              if (message.result) {
                echo.innerHTML = message.body;
                echo.classList.remove('hidden');
              } else {
                alert('Error parsing JSON');
              }
            } else if (xhr.status == 413) {
              alert('Большой объём файлов для демонстрации. Извините :)');
            }

            var textarea = form.querySelector('textarea');
            textarea.value = '';
            textarea.focus();

            queue = [];
            preview.innerHTML = '';

            submit.value = 'Отправить';
            checkValidity();
          }
        };

        xhr.send(data);
      }
    };

  })(window, document);
  </script>
</body></html>
OliverVood вне форума Ответить с цитированием
Старый 03.11.2015, 12:06   #2
Naive
Раздолбайских Дел
Старожил
 
Аватар для Naive
 
Регистрация: 22.05.2009
Сообщений: 3,828
По умолчанию

И что по-твоему тут лишнее?
ИМХО, код замечательный, все к месту и по делу, даже у себя юзану кое-что, пожалуй.
Alar, верни репу!
Naive вне форума Ответить с цитированием
Старый 03.11.2015, 12:09   #3
OliverVood
Пользователь
 
Регистрация: 06.05.2010
Сообщений: 32
По умолчанию

Цитата:
Сообщение от Naive Посмотреть сообщение
И что по-твоему тут лишнее?
ИМХО, код замечательный, все к месту и по делу, даже у себя юзану кое-что, пожалуй.
Скажите здесь всё относится к загрузке картинок?
Можете пояснить основные функции и что передаётся обработчику после отправки формы?
OliverVood вне форума Ответить с цитированием
Старый 03.11.2015, 13:15   #4
Naive
Раздолбайских Дел
Старожил
 
Аватар для Naive
 
Регистрация: 22.05.2009
Сообщений: 3,828
По умолчанию

Превью и асинхронная передача файлов, еще есть намек на кеширование заполненной формы, но частично вырезано, так что можно не обращать внимания.
Alar, верни репу!
Naive вне форума Ответить с цитированием
Старый 03.11.2015, 13:32   #5
OliverVood
Пользователь
 
Регистрация: 06.05.2010
Сообщений: 32
По умолчанию

Цитата:
Сообщение от Naive Посмотреть сообщение
Превью и асинхронная передача файлов, еще есть намек на кеширование заполненной формы, но частично вырезано, так что можно не обращать внимания.
А где, что? Если только превьюшку оставить без кеширования, то что надо вырезать (мне как бы модуль отдельный надо на загрузку, что бы я его в любом месте подключить мог без лишнего кода)? И почему после сабмита нет данных в массиве $_POST?
OliverVood вне форума Ответить с цитированием
Старый 03.11.2015, 20:42   #6
Naive
Раздолбайских Дел
Старожил
 
Аватар для Naive
 
Регистрация: 22.05.2009
Сообщений: 3,828
По умолчанию

Код действительно очень хорош, тут я редко такое вижу, так что откомментил его.
Цитата:
А где, что? Если только превьюшку оставить без кеширования, то что надо вырезать (мне как бы модуль отдельный надо на загрузку, что бы я его в любом месте подключить мог без лишнего кода)?
Кеширование тебе не помешает, как модуль смотри коммент к первой же строке.
Цитата:
И почему после сабмита нет данных в массиве $_POST?
А вот в пыхе я не асс, никогда плотно с ним не работал, но чего-та вспоминается, что там вроде есть специальный массив $_FILES или как-то так, загугли и будет тебе счастье.
Alar, верни репу!
Naive вне форума Ответить с цитированием
Старый 03.11.2015, 20:43   #7
Naive
Раздолбайских Дел
Старожил
 
Аватар для Naive
 
Регистрация: 22.05.2009
Сообщений: 3,828
По умолчанию

Цитата:
Вы ввели слишком длинный текст (8323 символов). Пожалуйста, сократите его до 5000 символов.
Серьезно!?
Код:
  (function(window, document) {

    var form    = document.querySelector('form'), // ищем форму
      // не очень то разумно, лучше искать конкретную форму
      // скажем, по классу
        submit  = form.querySelector('[type=submit]'),
      // внутри формы ищем кнопку отправки оной
        support = window.FormData && window.File && window.FileList && window.FileReader,
      // проверяем поддерживает ли браузер необходимые технологии
        preview = document.querySelector('.preview'),
      // ищем блок, в который будем скидывать превьюхи картинок
        echo    = document.querySelector('output'),
      // ищем блок, в который сбросим результат отправки
        queue   = [],
      // создаем хранилище для файликов

    previewImages = function(files) {
    // функция для показа превьюшек
    // не большой фанат такого вида задавания функций, 
    // предпочитаю классический, он исключает больше ошибок,
    // но тут все к месту
      [].forEach.call(files, function(file) {
      // а вот эта конструкция уже говорит о том, что код писал
      // грамотный кодер, у нубов такого не увидишь
      // тут мы берем метод forEach массива и вызываем его 
      // с контекстом нашего псевдомассива файлов
        if (file.type.match(/image.*/)) {
        // проверяем через свойство mime-type файла,
        // является ли он картинкой
          var reader = new FileReader();
          // создаем экземпляр ридера
          reader.onload = function(event) {
          // указываем callback на чтение
            var exist = [].some.call(preview.querySelectorAll('img'), function(element) {
              return element.src == event.target.result;
            });
            // ищем в превьюхе уже созданную эту картинку
            // и если ее нет, то создаем
            if (!exist) {
              var img = document.createElement('img');
              // собсна создаем экземпляр картинки
              img.src = event.target.result;
              // указываем ему base64 адрес
              img.onclick = function() {
                removePreview(img);
              };
              // вешаем на элемент ивент удалить при клике

              preview.appendChild(img);
              // засовываем в превьюху
              queue.push({file: file, element: img});
              // засовываем в очередь для загрузки
              checkValidity();
              // запускаем перерасчет валидности формы
            }
          };

          reader.readAsDataURL(file);
          // запускаем чтение файла в ридере
        }
      });
    },

    removePreview = function(element) {
    // хандлер для удаления картинки из очереди загрузки
      queue = queue.filter(function(file) {
      // не очень логичный ход, но быстрый, выбрасываем из массива
      // файлов выбранный
        return file.element != element;
      });


      element.parentNode.removeChild(element);
      // удаляем сам элемент и dom-дерева
      checkValidity();
      // запускаем перерасчет валидности формы
    },

    checkValidity = function() {};
    // перерасчет валидности формы, объявляем пока пустой

    if (form.checkValidity) {
      checkValidity = function() {
      // а тут задаем реальную, где указываем отключать ли сабмит формы
        submit.disabled = !(form.checkValidity() && queue.length > 0);
      };
    };

    if (window.localStorage) {
    // кешируем в хранилище заполненую форму, но у нас нет полей 
    // кроме файла, так что насрать
      var elements = form.querySelectorAll('[name]'),
          length = elements.length,
          i;

      for (i=0; i<length; i++) {
        (function(element) {
          var name = element.getAttribute('name');

          if (name != 'image') {
            element.value = localStorage.getItem(name) || '';

            element.onkeyup = function() {
              var value = element.value;
              if (!value) {
                value = '';
              }

              localStorage.setItem(name, value);
              checkValidity();
            };
          }
        })(elements[i]);
      }
    }

    if (support) {
    // если браузер поддерживает клиентский файло-подсос
      form.querySelector('[type=file]').addEventListener('change', function() {
        previewImages(this.files);
        // то запинываем картинки в превьюху
        this.value = '';
      }, false);
    }

    checkValidity();
    // считаем валидность формы
Alar, верни репу!
Naive вне форума Ответить с цитированием
Старый 03.11.2015, 20:44   #8
Naive
Раздолбайских Дел
Старожил
 
Аватар для Naive
 
Регистрация: 22.05.2009
Сообщений: 3,828
По умолчанию

Код:
form.onsubmit = function(event) {
    // при отправке формы...
      submit.disabled = true;
      // дизаблим кнопку отправки
      submit.value = 'Отправляется...';
      // это и далее подобное действие — единственное узкое место в коде
      // использованы константы внутри. Я бы вынес это в dataSet

      if (window.localStorage) {
        localStorage.removeItem('message');
        // удаляем несуществующий итем, видимо автор порезал общий скриптец
      }

      if (support) {
      // если клиентская подсоска файлов работает, то
        event.preventDefault();
        // отрубаем стандартное действие сабмита
        // если саппорт где-то не работает, то файлы отправятся
        // стандартным синхронным методом на эту же самую страницу
        // так как у формы нет атрибута action

        var data = new FormData(form),
            xhr  = new XMLHttpRequest();
        // создаем формоданные для передачи
        // и канал соединения

        queue.forEach(function(element) {
          data.append('image', element.file);
        });
        // закидываем файлы в формоданные

        xhr.open('post', '/temp/echo?t=' + (new Date()).getTime());
        // открываем соединение
        // с учетом предыдущей проверки на саппорт можно было бы 
        // сократить тайм-штамп на ES5: Date.now(), но это не важно
        
        xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
        // устанавливаем заголовки

        xhr.onreadystatechange = function() {
        // создаем реакцию на ответ AJAX-а
          if (xhr.readyState == 4) {
            if (xhr.status == 200) {
            // если соединение прошло
              var message = JSON.parse(xhr.responseText);
              // читаем ответ
              if (message.result) {
              // если чота пришло
                echo.innerHTML = message.body;
                // пишем для юзера ответ в специально отведенный 
                // для этого аутпут
                echo.classList.remove('hidden');
                // удаляем класс hidden, видимо оно должно показаться
                // но на странице нет ни единого стиля, 
                // так что аутпут был и так виден
              } else {
                // ниче не пришло
                alert('Error parsing JSON');
                // имя ошибки не соответствует действительности, нигде нет и намека на парсинг JSON-а
              }
            } else if (xhr.status == 413) {
              // ну и банальный фейл
              alert('Большой объём файлов для демонстрации. Извините :)');
              // опять эта же лажа. Все комменты должы быть вынесены за код
              // в идеале — в отдельный файл локализации,
              // так же неплохим решением было бы использовать dataSet
              // чтобы JS юзал скомпилированый файл с сервера для отображения
              // сообщений. Предыдущий алерт на инглише так же к этому 
              // относится
            }

            var textarea = form.querySelector('textarea');
            textarea.value = '';
            textarea.focus();
            // нахер ненужные 3 строчки, код видимо из какого-то чата дернут
            queue = [];
            // опустошаем файлолист
            preview.innerHTML = '';
            // варварски уничтожаем превьюхи (есть же метод empty!)

            submit.value = 'Отправить';
            // возвращаем написание кнопки отправления
            // снова эта дрянь, с константами в коде

            checkValidity();
            // и дизаблим отправку формы
          }
        };

        xhr.send(data);
        // отправляем запрос
      }
    };

  })(window, document);
Alar, верни репу!
Naive вне форума Ответить с цитированием
Старый 04.11.2015, 03:52   #9
OliverVood
Пользователь
 
Регистрация: 06.05.2010
Сообщений: 32
По умолчанию

Спасибо, я вечером сегодня посмотрю.
Кстати если убрать не нужные 3 строчки, то это как-то на работу кнопку формы влияет.
Цитата:
var textarea = form.querySelector('textarea');
textarea.value = '';
textarea.focus();
// нахер ненужные 3 строчки, код видимо из какого-то чата дернут
Ладно, я вроде немного разобрался. Но почему если я сабмиту присвою name = "enter", то он это значение не отправляет вовсе. Т.е. значения $_POST['enter'] не существует?
Сразу говорю, что event.preventDefault(); закоментил.
Где-то он сбрасывает значение? Или вообще его не отправляет?

При вызове var_dump($_FILES);
Результат: erarray(1) { ["image"]=> array(5) { ["name"]=> string(0) "" ["type"]=> string(0) "" ["tmp_name"]=> string(0) "" ["error"]=> int(4) ["size"]=> int(0) } }.
Т.е. и информация о файлах тоже не передаётся.

Почему он ругается на эту строчку при отправке формы?
Код:
var message = JSON.parse(xhr.responseText);

Последний раз редактировалось Stilet; 15.11.2015 в 10:50.
OliverVood вне форума Ответить с цитированием
Старый 07.11.2015, 03:58   #10
Fenex
Форумчанин
 
Аватар для Fenex
 
Регистрация: 15.02.2012
Сообщений: 823
По умолчанию

Цитата:
Сообщение от OliverVood Посмотреть сообщение
Почему он ругается на эту строчку при отправке формы?
Код:
var message = JSON.parse(xhr.responseText);
Обычно "он" объясняет почему ему не нравится та или иная строка.

Но поскольку все упорно думают, что на этом форуме сидят экстрасенсы, то постараюсь оправдать ожидания и назову три причины, на каждую из которых интерпретатор может жаловаться:
- `xhr.responseText` не является JSON-форматом;
- `xhr` не существует в контексте;
- вместо вменяемого интерпретатора используется какой-то динозавр, который не знает объект `JSON`.

Ну и добавлю ещё уж совсем извращённое:
- Объект `JSON` был переопределён на другой объект, не имеющий метода `parse`.
^-.-^ My GitHub

Последний раз редактировалось Fenex; 07.11.2015 в 04:04.
Fenex вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Как понять данный код? SkyWay Microsoft Office Excel 1 12.02.2015 02:36
Помогите понять код (прокомментировать код шифрации на C++). bicks Помощь студентам 3 10.12.2013 21:31
Как понять код Lepton Visual C++ 1 13.01.2012 17:56
Помогите понять код Arassir JavaScript, Ajax 1 12.05.2009 13:00
Помогите понять код MaGiCeYe Помощь студентам 1 02.04.2007 19:57