Передача пути к загруженному файлу из HTML5 drag & drop в поле ввода

Я работаю над приложением (в Node.js, что не имеет отношения к этому случаю), что позволяет пользователю загружать изображение. Он отлично работает с использованием формы с полем ввода (type="file").

Однако, я хочу, чтобы вы могли загружать изображение, используя вместо этого перетаскивание HTML5. Насколько я понял, можно перетащить изображение клиенту, а миниатюра изображения отображается в div. Однако мне действительно нужна помощь в том, чтобы загрузить файл.

Дело в том, что я хочу использовать форму, которую я использую прямо сейчас, и (каким-то образом) передать путь файла к полю ввода, то есть поток будет работать точно так же, как сейчас, но вместо того, чтобы выбирать файл, просматривая его. Я хочу привязать его к полю ввода путем перетаскивания.

В приведенном ниже js-коде для перетаскивания файл, перетаскиваемый клиенту, хранится в переменной "файл", и я могу использовать "file.name", "file.type" и "file.size" точно так же, как и раньше, с формой. Однако я не могу получить доступ к файлам "путь" (file.path), который делает невозможным доступ к стороне файлового сервера для загрузки так же, как я делаю это с тех пор.

Вопрос в том, можно ли передать объект файла в поле ввода после того, как файл был перенесен на клиент, чтобы я мог нажать "отправить" и загрузить файл? Если да, как это можно сделать?

Спасибо заранее!

dropbox, а также форму, которую я использую для загрузки файлов:

<div id='upload'>
    <article>
        <div id='holder'>
            <p id='status'>File API and FileReader API not supported</p>
        </div>
    </article> 

    <form method='post' enctype='multipart/form-data' action='/file-upload'>
        <p>
            <input type='file' name='thumbnail'>
        </p>
        <p>
            <input type='submit'>
        </p>
    </form>
</div>

код для перетаскивания:

uploadImage: function(){
    var holder = document.getElementById('holder'),
        state = document.getElementById('status');

    if (typeof window.FileReader === 'undefined') {
      state.className = 'fail';
    } else {
      state.className = 'success';
      state.innerHTML = 'File API & FileReader available';
    }

    holder.ondragover = function () { this.className = 'hover'; return false; };

    holder.ondragend = function () { this.className = ''; return false; };

    holder.ondrop = function (e) {
      this.className = '';
      e.preventDefault();

      var file = e.dataTransfer.files[0],
          reader = new FileReader();

      reader.onload = function (event) {
        holder.style.background = 'url(' + event.target.result + ') no-repeat center';
      };

      reader.readAsDataURL(file);

      return false;
    };
},

Ответы

Ответ 1

Вы не можете использовать ввод файла для добавления данных файла. Тем не менее, что вы можете сделать (среди других техник) - использовать base64 (изначально доступный через reader.onload event как event.target.result при использовании метода readAsDataURL) закодированные данные и помещать их в скрытое поле:

HTML

<article>
    <div id='holder'>
        <p id='status'>File API and FileReader API not supported</p>
    </div>
</article> 

<form method='post' enctype='multipart/form-data' action='/file-upload'>
        <input type='file' name='thumbnail' />
        <input type='hidden' name='base64data' />
        <input type='submit' formenctype='application/x-www-form-urlencoded' />
</form>

JS

reader = new FileReader();
reader.onload = function (event) {
    document.getElementById('base64data').setAttribute('value', event.target.result);
};
reader.readAsDataURL(file);

Со стороны сервера вы сможете получить кодированные данные base64 из файла, просто расшифруйте его и используйте, как хотите.

При отправке формы вы также можете изменить атрибут "enctype" (сделанный с помощью атрибута formenctype) и удалить основной вход файла html, поскольку данные будут помещены в текстовое поле.

Ответ 2

Невозможно узнать путь поля для целей безопасности. При перетаскивании вы должны загрузить его независимо от основной формы. Вот пример: http://www.sitepoint.com/html5-file-drag-and-drop/

Ответ 3

Я обнаружил, что скрытое поле, установленное в reader.onload (см. ответ по @challet), не устанавливается при обращении в коде позади. Я использую asp.net и проект WebForms. Чтобы получить доступ к скрытым полям, я должен добавить MainContent_ к именам полей. код aspx ниже


<asp:Content ID="Content3" ContentPlaceHolderID="MainContent" runat="server">
...
<script type="text/javascript">
    function dropHandler(ev) {
        alert("File(s) dropped");
        // Prevent default behavior (Prevent file from being opened)
        ev.preventDefault();
        //alert("Default prevented");
        if (ev.dataTransfer.items) {
            if (ev.dataTransfer.items.length > 1) {
                alert("Only single files can be dragged and dropped into Caption Pro Web");
                return;
            }
            // If dropped items aren't files, reject them
            if (ev.dataTransfer.items[0].kind === 'file') {
                var file = ev.dataTransfer.items[0].getAsFile();                    
                document.getElementById("MainContent_DroppedFileName").value = ev.dataTransfer.items[0].name
                reader = new FileReader();
                reader.onload = function (event) {
                    document.getElementById('MainContent_DroppedFileContent').value = event.target.result;
                };
                reader.readAsDataURL(ev.dataTransfer.items[0]);               
            }
        } else {
            // Use DataTransfer interface to access the file(s)
             if (ev.dataTransfer.files.length > 1) {
                alert("Only single files can be dragged and dropped into Caption Pro Web");
                return;
            }           
            document.getElementById("MainContent_DroppedFileName").value = ev.dataTransfer.files[0].name
            document.getElementById("MainContent_DroppedFileContent").value = "Test";

            reader = new FileReader();
            reader.onload = function (event) {
                 document.getElementById("MainContent_DroppedFileContent").value = event.target.result;
            };
            reader.readAsDataURL(ev.dataTransfer.files[0]);           
        }

        document.getElementById('<%=btnDrop.ClientID %>').click();

    }
</script>

...

    <div id="drop_zone" ondrop="dropHandler(event);" ondragover="dragOverHandler(event);">
    <p>Drag image to this Drop Zone ...</p>
    </div> 
    <asp:HiddenField ID="DroppedFileName" runat="server" />
    <asp:HiddenField ID="DroppedFileContent" runat="server" />
...
 </asp:Content>

Я получаю доступ к скрытым полям из c #, как показано ниже

protected void btnDrop_Click(object sender, EventArgs e)
         {
             string FileName = DroppedFileName.Value;
             string FileContent = DroppedFileContent.Value;
         }

Если я использую Internet Explorer в качестве целевого браузера (не запускаю VS как Admin, так как это отключает перетаскивание!) и устанавливаю точку останова в функции reader.onload(), скрытое поле DroppedFileContent содержит содержимое закодированного файла, но когда Я пытаюсь получить к нему доступ из btnDrop_Click, он содержит только "Test", как установлено до reader.onload(), и не содержит зашифрованного содержимого файла. Поле DroppedFileNam.Value является таким, как установлено в Javascript.