HTML5 drag a drop image upload

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
CJHornster
Člen | 56
+
0
-

Čau,

na netu jsem našel tento tutoriál, ale je řešený přes php … tak se nějak pokouším přijít jak to spojit s presenterem v nette

http://tutorialzine.com/2011/09/html5-file-upload-jquery-php/

nemáte nějaký nápad jak místo post_file.php volat metodu z presenteru?

MartinitCZ
Člen | 580
+
0
-

Osobně bych se soubor nesnažil volat z presenteru, ale celý soubor bych přepsal do „Nette way“. ;)
Vytvořit si formulář s uploadem a zpracovat to čistě v něm, tedy žádné $_FILE, $_GET …

Editoval MartinitCZ (26. 7. 2014 17:39)

CJHornster
Člen | 56
+
0
-

no to mám už teď, ale problém je, že přesně nevím jak na to navázat ten HTML5 drag n drop uploader (s progresem uploadu)

Editoval CJHornster (26. 7. 2014 23:11)

CJHornster
Člen | 56
+
0
-

tak sem se to pokoušel zprovoznit, nejdříve normálně podle návodu, ale skončil jsem u toho, že mě to řve:

POST http://localhost:8080/VyzadameNette/www/admin/post_file.php 500 (Internal Server Error) jquery.filedrop.js:311
XMLHttpRequest.sendAsBinary jquery.filedrop.js:311
send jquery.filedrop.js:215

Uncaught SyntaxError: Unexpected token < jquery.js:4
x.extend.parseJSON jquery.js:4
xhr.onload

Script mam takhle:

$(function(){

	var dropbox = $('#dropbox'),
		message = $('.message', dropbox);

	dropbox.filedrop({
		// The name of the $_FILES entry:
		paramname:'pic',

		maxfiles: 5,
    	maxfilesize: 2,
		url:  'post_file.php',

		uploadFinished:function(i,file,response){
			$.data(file).addClass('done');
			// response is the JSON object that post_file.php returns
		},

    	error: function(err, file) {
			switch(err) {
				case 'BrowserNotSupported':
					showMessage('Your browser does not support HTML5 file uploads!');
					break;
				case 'TooManyFiles':
					alert('Too many files! Please select 5 at most! (configurable)');
					break;
				case 'FileTooLarge':
					alert(file.name+' is too large! Please upload files up to 2mb (configurable).');
					break;
				default:
					break;
			}
		},

		// Called before each upload is started
		beforeEach: function(file){
			if(!file.type.match(/^image\//)){
				alert('Only images are allowed!');

				// Returning false will cause the
				// file to be rejected
				return false;
			}
		},

		uploadStarted:function(i, file, len){
			createImage(file);
		},

		progressUpdated: function(i, file, progress) {
			$.data(file).find('.progress').width(progress);
		}

	});

	var template = '<div class="preview">'+
						'<span class="imageHolder">'+
							'<img />'+
							'<span class="uploaded"></span>'+
						'</span>'+
						'<div class="progressHolder">'+
							'<div class="progress"></div>'+
						'</div>'+
					'</div>';


	function createImage(file){

		var preview = $(template),
			image = $('img', preview);

		var reader = new FileReader();

		image.width = 100;
		image.height = 100;

		reader.onload = function(e){

			// e.target.result holds the DataURL which
			// can be used as a source of the image:

			image.attr('src',e.target.result);
		};

		// Reading the file as a DataURL. When finished,
		// this will trigger the onload function above:
		reader.readAsDataURL(file);

		message.hide();
		preview.appendTo(dropbox);

		// Associating a preview container
		// with the file, using jQuery's $.data():

		$.data(file,preview);
	}

	function showMessage(msg){
		message.html(msg);
	}

});

v budoucnu sem myslel, že by to mohlo bejt propojený z nette nějak takhle:

$(function(){

	var dropbox = $('#dropbox'),
		message = $('.message', dropbox);

	dropbox.filedrop({
		// The name of the $_FILES entry:
		paramname:'pic',

		maxfiles: 5,
    	maxfilesize: 2,
		url:  {link imageUpload!},

		uploadFinished:function(i,file,response){
			//$.data(file).addClass('done');
			// response is the JSON object that post_file.php returns
		},
... atd

Nevíte co s tím, nebo nevvíte o jiném způsobu jak implementovat drag n drop?

Editoval CJHornster (28. 7. 2014 11:00)

David Kudera
Člen | 455
+
0
-

V té chybě: určitě jsi tam chtěl mít v URL {BasePath}? Jen se ptám, třeba je to úmysl..

CJHornster
Člen | 56
+
0
-

tak už to funguje:

tahle úprava pomohla

	dropbox.filedrop({
		// The name of the $_FILES entry:
		paramname:'pic',
		maxfiles: 5,
	maxfilesize: 2,
		url:  '../post_file.php',

ted jen vyřešit jak to spojit s nette, protože na každý obrázek potřebuji uložit cestu do DB

Editoval CJHornster (28. 7. 2014 11:07)

David Kudera
Člen | 455
+
0
-

spojení s nette by nemělo být nijak složité. Můžeš si vytvořit nějakou akci v presenteru a v ní ty soubory zpracuješ. Tady je dokumentace, kde je popsáno, jak přistoupit k souborům. Jak uložit takový soubor je tady na fóru několikrát (hledej např. form upload) a místo té funkce exist_status můžeš použít třeba JsonResponse

$this->sendResponse(new JsonResponse(array('status' => $status)));
CJHornster
Člen | 56
+
0
-

jj na to jsem taky narazil, ale nějak se mě to nevede dát dohromady s mým kódem

David Kudera
Člen | 455
+
0
-

Nastavuješ v tom skriptu správnou url? Zavolá se vůbec ta akce presenteru? Klidně pošli i kód té akce samotné. První je ale dobrý vědět, jestli se vůbec zavolá..

CJHornster
Člen | 56
+
0
-

ta akce se nejspíše vůbec nezavolá, protože cokoliv zkusím, tak mě píše script.js syntax error

jde mě vlastně o to drag n dropem nahrát ty obrázky na server a pak jejich adresy (odkazy na ně uložit do DB) (popřípadě je ještě zformátovat jako všem nastavit pomocí nette 200px width)

Editoval CJHornster (28. 7. 2014 12:58)

David Kudera
Člen | 455
+
0
-

A tu url nastavuješ jak?

CJHornster
Člen | 56
+
0
-

právě, že takhle, když volám nějakeou metodu z presenteru, tak mě to nefunguje a kříčí, že to nemůže nic takovýho najít

dropbox.filedrop({
    // The name of the $_FILES entry:
    paramname:'pic',
    maxfiles: 5,
    maxfilesize: 2,
    url:  '../post_file.php',
David Kudera
Člen | 455
+
0
-

no ale ../post_file.php určitě není url na akci toho presenteru že? nějak mu ji musíš nastavit. Jedna možnost je si např. udělat v layoutu nebo v templatě proměnnou

<script type="text/javascript">
	var imageUploadUrl = {link ImagePresenter:upload};
</script>

no a pak ji použít v té konfiguraci

url: imageUploadUrl
CJHornster
Člen | 56
+
0
-

jj o něco podbného jsem se pokoušel, ale narazil jsem na problém

Uncaught SyntaxError: Unexpected token < jquery.js:4
x.extend.parseJSON jquery.js:4
xhr.onload

toto mám v layoutu

<script type="text/javascript">
    var imageUploadUrl = {link ImagePresenter:upload};
</script>

a toto v script.js

	dropbox.filedrop({
		// The name of the $_FILES entry:
		paramname:'pic',
		maxfiles: 5,
		maxfilesize: 2,
		url:  imageUploadUrl,

už jsme se do toho tak zamotal, že nevím ani kde pořádně sem :D

David Kudera
Člen | 455
+
0
-

jo sorry, ono se to escapuje.. tak např. takhle:

var imageUploadUrl = "{$presenter->link('Image:upload')|noescape}";

z nějakýho důvodu mi nefunguje {link Image:upload|noescape}, jinak bych použil to..

jo a kdyžtak se i podívej a pošli sem, co to vlastně vrací za ten response

CJHornster
Člen | 56
+
0
-

no ted to vyhazuje tohle:

Uncaught SyntaxError: Unexpected token < jquery.js:4
x.extend.parseJSON jquery.js:4
xhr.onload

spíš mam pocit, že to tam dávám nějak blbě já
tady je view (images.latte)

{block content}

<script type="text/javascript">
var imageUploadUrl = "{$presenter->link('AdminPresenter:imageUpload')|noescape}";
</script>
<div id="dropbox" class="col-md-12">
			<span class="message">Drop images here to upload. <br /><i>(they will only be visible to you)</i></span>
</div>

ten script ted vypadá takhle:

$(function(){

	var dropbox = $('#dropbox'),
		message = $('.message', dropbox);

	dropbox.filedrop({
		// The name of the $_FILES entry:
		paramname:'pic',
		maxfiles: 5,
    	maxfilesize: 2,
		url:  imageUploadUrl,

		uploadFinished:function(i,file,response){
			$.data(file).addClass('done');
			// response is the JSON object that post_file.php alert
			//returns("prdel");

		},

    	error: function(err, file) {
			switch(err) {
				case 'BrowserNotSupported':
					showMessage('Your browser does not support HTML5 file uploads!');
					break;
				case 'TooManyFiles':
					alert('Too many files! Please select 5 at most! (configurable)');
					break;
				case 'FileTooLarge':
					alert(file.name+' is too large! Please upload files up to 2mb (configurable).');
					break;
				default:
					break;
			}
		},

		// Called before each upload is started
		beforeEach: function(file){
			if(!file.type.match(/^image\//)){
				alert('Only images are allowed!');

				// Returning false will cause the
				// file to be rejected
				return false;
			}
		},

		uploadStarted:function(i, file, len){
			createImage(file);
		},

		progressUpdated: function(i, file, progress) {
			$.data(file).find('.progress').width(progress);
		}

	});

	var template = '<div class="preview">'+
						'<span class="imageHolder">'+
							'<img />'+
							'<span class="uploaded"></span>'+
						'</span>'+
						'<div class="progressHolder">'+
							'<div class="progress"></div>'+
						'</div>'+
					'</div>';


	function createImage(file){

		var preview = $(template),
			image = $('img', preview);

		var reader = new FileReader();

		image.width = 100;
		image.height = 100;

		reader.onload = function(e){

			// e.target.result holds the DataURL which
			// can be used as a source of the image:

			image.attr('src',e.target.result);
		};

		// Reading the file as a DataURL. When finished,
		// this will trigger the onload function above:
		reader.readAsDataURL(file);

		message.hide();
		preview.appendTo(dropbox);
		// Associating a preview container
		// with the file, using jQuery's $.data():
		$.data(file,preview);
	}

	function showMessage(msg){
		message.html(msg);
	}

});

a funkce v AdminPresenter je:

public function handleImageUpload()
    {
    	$demo_mode = false;
		$upload_dir = 'uploads/';
		$allowed_ext = array('jpg','jpeg','png','gif');


		if(strtolower($_SERVER['REQUEST_METHOD']) != 'post'){
			exit_status('Error! Wrong HTTP method!');
		}


		if(array_key_exists('pic',$_FILES) && $_FILES['pic']['error'] == 0 ){

			$pic = $_FILES['pic'];

			if(!in_array(get_extension($pic['name']),$allowed_ext)){
				exit_status('Only '.implode(',',$allowed_ext).' files are allowed!');
			}

			if($demo_mode){

				// File uploads are ignored. We only log them.

				$line = implode('		', array( date('r'), $_SERVER['REMOTE_ADDR'], $pic['size'], $pic['name']));
				file_put_contents('log.txt', $line.PHP_EOL, FILE_APPEND);

				exit_status('Uploads are ignored in demo mode.');
			}


			// Move the uploaded file from the temporary
			// directory to the uploads folder:

			if(move_uploaded_file($pic['tmp_name'], $upload_dir.$pic['name'])){
				exit_status('File was uploaded successfuly!');
			}

		}

		exit_status('Something went wrong with your upload!');


		// Helper functions

		function exit_status($str){
			echo json_encode(array('status'=>$str));
			exit;
		}

		function get_extension($file_name){
			$ext = explode('.', $file_name);
			$ext = array_pop($ext);
			return strtolower($ext);
		}
    }

Editoval CJHornster (28. 7. 2014 17:13)

David Kudera
Člen | 455
+
0
-

Já být na tvým místě, tak bych si to určitě debugoval.

Jo ale teď koukám.. Víš určitě nebude jen tak fungovat když kód z nějakýho souboru jen tak přesuneš do akce presenteru. Musíš to přepsat postupně do nette, takže použít ty odkazy a věci, co jsem ti psal nahoře. Např. vytvořit funkce exit_status a get_extension uvnitř metody presenteru určitě není tak úplně správně. Takže mrkni i do log složky, jestli tam jsou uložené nějaké chyby

CJHornster
Člen | 56
+
0
-

jj to je pravda, ale asi mám problém se vůbec dostat na server

ještě mě napadlo to udělat na prasáka a třeba v js z funkce createImage nějak volat metodu z presenteru a tý předat jméno toho filu a to uložit do DB

David Kudera
Člen | 455
+
+1
-

To takhle nejde. Leda by jsi to poslal „předem“ název přes ajax a v další fázy samotný soubor a nějak je spojil.. To mi přijde ale docela dost strašný a děsivý… Napřímo totiž z js nic v php nezavoláš.

A myslím tím „asi“ jako asi jo nebo asi ne? :-)

Chtělo by to vědět na jisto. Klidně si na začátek té metody dej Debugger::log(‚funguje‘); a pak se mrkni do logu a taky na to, jestli ti to nepadá přímo na nějaké chybě, ale to taky uvidíš ve složce log

Editoval David Kudera (28. 7. 2014 20:51)

CJHornster
Člen | 56
+
0
-

tak jsem to zkoušel debugovat a funkce se vůbec neprovede

Edit1: nakonec se na to asi vykašlu a zkusím implementovat MultipleFileUpload

Edit2: Ten se mě nakonec povedlo implementovat, ale nějak se mě nedaří zaplnout vzhled uploadify

Editoval CJHornster (29. 7. 2014 10:26)