Po kolei, żeby mniej wtajemniczeni cokolwiek chwycili. Dawno temu, najmniej 10 lat temu, znalazłem w Sieci edytor, jakiego potrzebowałem. Edytor wysiwyg, czyli że to co piszesz w jego okienku, (zaraz) potem zobaczysz jako tekst na stronie. Do czego był (i jest) mi potrzebny ten edytor? – Ano, do pisania, redagowania i szybkiego poprawiania tekstów żyjących w Sieci, w tym komentarzy pod artykułami, wpisów na forum itp, czyli wszelkich notek i subnotek, wszystkiego.

Ten edytor nazywa się NicEdit, „nic” zapewne od ang. nice, nie od pl „nic”, bo skądby. Faktycznie jest nice. Spodobał mi się przez swoją prostotę, wygodę, sprawność i – ważne! – nie-rozdęcie i brak nadmiaru, a właśnie na nadmiar wodotrysków cierpią alternatywne edytory, które wiele razy szukałem, znajdowałem, badałem i odrzucałem. NicEdita używałem (i używam; czemu na boga język pl nie ma present-perfectu?) we wszystkich moich projektach: w Tarace, w AstroAkademii i w tym blogu.

Ten wielki edytor zrobił w 2008 r. Amerykanin Brian Kirchoff, zapewne wtedy będąc studentem. Zrobił i zostawił. Uznawszy pewnie, że dzieło jest doskonałe i nie wymaga napraw-popraw. W 2012 coś ulepszał na stronie swojego produktu, ale (raczej) samego skrypu nie zmienił.

Jednak NicEdit ma ten gorzki rodzynek. Jest nim funkcja („funkcjonalność”) wklejania grafiki. Uploadu. Na czym polega gorzkość? – Na tym, że w jednych miejscach sieci ten upload działa, a w innych nie chce. Także w jednych miejscach pewnej strony upload działa, w innych nie chce. I tego jak dotąd nie rozszyfrowałem.

W AstroAkademii działa śpiewająco, chociaż nie wiem dlaczego. Trafiłem na takie „umocowanie” tego edytora, w którym upload zadziałał, ale stało się to po mnóstwie prób i błędów, które zajęły mi parę lat. Parę lat oczywiście nie ciurkiem, tylko porzucałem nieudane próby, do których wracałem po roku lub iluś.

Przy okazji tych prób ktoś kiedyś (ale kto? Jeśli mnie czytasz, Zapomniany Dobroczyńco, daj znać!) przysłał mi inny-lepszy skrypt nicUpload.php niż oryginalny Kirchoffowski. Tu dodam dla wiedzących o co chodzi, że sam edytor Kirchoffa jest zbudowany w czystym JavaScripcie, bez zewnętrznych dodatków w rodzaju jQuery. (Ta czystość kodu bardzo mi się podoba!) Ale żeby użytkownik wyciągnął plik z grafiką ze swojego dysku i wysłał go na serwer, temu zadaniu sam JavaScript nie poradzi i trzeba użyć języka do obsługi serwera. Czyli PHP. Przez to edytor Kirchoffa prócz skryptu w JS potrzebuje dodatkowego skryptu w PHP czyli owego nicUpload.php. Oryginalne nicUpload.php jest zawiłe i tym bardziej ucieszył mnie tamten korespondent, który przysłał mi alternatywne nicUpload.php radykalnie prostsze – i które działa! (Nie zawsze, ale jednak.)

W WojciechJozwiak.PL czyli w niniejszym blogu, upload nie zadziałał i w końcu wyszło tak, że go nie używam: w edytorze przycisk na upload jest zaślepiony.

Niedawno, maj/czerwiec, uruchamiałem forum dla odbudowniczych Taraki (zob. odpowiedni tekst). W tym celu oskryptowanie tworzące „kieszeń” dla NicEdita przeniosłem z AstroAkademii (gdzie działało i działa bez zarzutu) – i kicha. W nowym miejscu upload nie zadziałał.

Co się dzieje? Upload coś jednak robi: pobiera plik graficzny z dysku i przesyła go na serwer i tam zapisuje w przewidzianym katalogu. Po czym nie potrafi zakończyć tej akcji, tj. wkleić do edytowanego tekstu odpowiedniego kodu img src="...". Wiesza się po zapisaniu pliku na dysku.

Serwerowy skrypt nicUpload.php jest uruchamiany przez nicEdit.js (jak zwykle) przy pomocy technologii Ajax i obiektu XMLHttpRequest. Zwrot z nicUpload.php jest w formacie Json i jest czytany (jak zwykle) przez funkcję JSON.parse.

Dla chcących się przyjrzeć tej sprawie, zamieszczam fragment kodu nicEdit.js zawierający funkcję obsługi przycisku „Upload”. Cały kod jest na stronie Kirchoffa albo (prościej) w podglądzie tej strony. Miejsca „krytyczne” zaznaczyłem czerwono.

var nicUploadButton = nicEditorAdvancedButton.extend({
	nicURI:"https://api.imgur.com/3/image",
	errorText:"Failed to upload image",
	addPane:function(){
		if(typeof window.FormData === "undefined"){
				return this.onError("Image uploads are not supported in this browser,  use Chrome,  Firefox,  or Safari instead.")
			}
		this.im = this.ne.selectedInstance.selElm().parentTag("IMG");
		var A = new bkElement("div").setStyle({padding:"10px"}).appendTo(this.pane.pane);
		new bkElement("div").setStyle({fontSize:"14px", fontWeight:"bold", paddingBottom:"5px"}).setContent("Insert an Image #!#").appendTo(A);
		this.fileInput = new bkElement("input").setAttributes({type:"file"}).appendTo(A);
		this.progress = new bkElement("progress").setStyle({width:"100%", display:"none"}).setAttributes("max", 100).appendTo(A);
		this.fileInput.onchange = this.uploadFile.closure(this)
	}, 
	onError:function(A){
		this.removePane();
		alert(A||"Failed to upload image")
	},
	uploadFile:function(){
			var B = this.fileInput.files[0];
			if(!B||!B.type.match(/image.*/)){this.onError("Only image files can be uploaded");
			return
		}
		this.fileInput.setStyle({display:"none"});
		this.setProgress(0);
		var A = new FormData();
		A.append("image", B);
		var C = new XMLHttpRequest();
		C.open("POST", this.ne.options.uploadURI||this.nicURI);
		C.onload = function(){
				try{var D = JSON.parse(C.responseText).data}
				catch(E){return this.onError()}
				if(D.error){return this.onError(D.error)}
				this.onUploaded(D)
			}.closure(this);
		C.onerror = this.onError.closure(this);
		C.upload.onprogress = function(D){this.setProgress(D.loaded/D.total)}.closure(this);
		C.setRequestHeader("Authorization", "Client-ID c37fc05199a05b7");
		C.send(A)
	}, 
	setProgress:function(A){
		this.progress.setStyle({display:"block"});
		if(A<0.98){this.progress.value = A}
		else{this.progress.removeAttribute("value")}
	}, 
	onUploaded:function(B){
		this.removePane();
		var D = B.link;
		if(!this.im){this.ne.selectedInstance.restoreRng();
		var C = "javascript:nicImTemp();";
		this.ne.nicCommand("insertImage", D);
		this.im = this.findElm("IMG", "src", D)}
		var A = parseInt(this.ne.selectedInstance.elm.getStyle("width"));
		if(this.im){
			this.im.setAttributes({src:D, width:(A&&B.width)?Math.min(A, B.width):""})
		}
	}
});

Jeśli potrzebujesz więcej, pisz – niżej.