[Seaside] Using nginx file upload module
Nick Ager
nick.ager at gmail.com
Thu Jun 16 08:13:31 UTC 2011
Hi Johan,
> But I'm looking forward to reading your write-up too!
>
For what it's worth I started writing it up here:
http://www.nickager.com/blog/file-upload-using-Nginx-and-Seaside - though
it's little more than notes at the moment..
In the meantime here is a raw dump of some code. Hope it might help, though
I'm afraid it's more complex than it needs to be as it includes upload
tracking, Iframe submission, additional user feedback.
I set the target of the form to a hidden Iframe:
form := html form.
form
id: #fileUploadForm;
style: 'margin:0px';
attributeAt: 'target' put: 'hiddenImageUploader';
onSubmit: 'startUploadProgressBar(); return true;';
I manipulate the path using javascript:
fileuploadSpecificJavascript
^ String streamContents: [:aStream |
aStream
nextPutAll: 'var xProgressId="';
nextPutAll: self xProgressId;
nextPutAll: '";
function checkFileAndSubmitIfImage(actionUrl) {
var filename = $("#fileUploadId").val();
var extensionIndex=filename.lastIndexOf(''.'') + 1;
var extension=filename.substring(extensionIndex).toLowerCase();
if (extension && /^(jpg|png|jpeg|gif)$/.test(extension)) {
var newUrl = "/fileupload" + actionUrl+"&X-Progress-ID=" + xProgressId;
$("#fileUploadForm").attr("action", newUrl);
$("#fileUploadForm").submit();
} else {
$("#uploadNotification").append("<ul class=\"errors\"><li>''" + filename +
> "'' is not a valid image file (jpg, jpeg, gif, png), try another
> file</li></ul>");
}
> $("#fileUploadId").val("");
return false;
}
' ]
You trigger an update with the iframe as a target. The image is uploaded and
a minimal response is returned to the iframe. That response triggers the
onload. The onload then calls a method in the iframes parent - the main
page. I've called it imageUploadedCallback() then performs the following:
1) clears the upload progress
2) renders any upload errors
3) renders thumb nails of the images uploaded
4) sets a new xProgressId for the next upload.
The imageUploadedCallback() code looks like:
imageUploadedCallbackScriptOn: html
^ html jQuery ajax script: [ :s |
s << (JSStream on: 'clearUploadProgress()').
s << (s jQuery: #uploadNotification)
html: [ :renderer |
errorText notNil
ifTrue: [
renderer div
class: 'error';
with: errorText ]
ifFalse: [
renderer div] ].
s << (s jQuery: #projectUploadedFilesContainer)
html: [ :renderer |
renderer render: self imageRenderer ].
s << (JSStream on: 'xProgressId="', self xProgressId, '"') ]
with the form I also render a hiddenInput, whose callback is fired when the
form is submitted and I extract the nginx post parameters which tell me the
location nginx has stored the file:
"The hiddenInput callback will contain the file upload fields if we've
> loading via nginx
file upload module"
html hiddenInput
value: 'hidden';
callback: [:val | | request postFields fileName uploadFieldName |
request := self requestContext request.
postFields := request postFields.
uploadFieldName := fileUploadField attributeAt: 'name'.
fileName := (postFields at: (uploadFieldName, '.name') ifAbsent: [nil]).
"has nginx file upload module inserted it's post fields in the request?"
fileName notNil ifTrue: [
fileMoveCallback value: postFields value: uploadFieldName ] ]
I use the OSes 'mv' to move the files:
moveFrom: fromString to: toString
| shellMoveFileCommand |
shellMoveFileCommand := String streamContents: [:stream |
stream
nextPutAll: 'mv ';
nextPutAll: fromString;
nextPutAll: ' ''';
nextPutAll: toString;
nextPutAll: '''' ].
IZLogger logInfo: 'IZShellScripts>>#moveFrom:to:' with:
> shellMoveFileCommand.
SpEnvironment runShellCommandString: shellMoveFileCommand.
some more javascript:
imageUploadedCallbackScriptOn: html
^ html jQuery ajax script: [ :s |
s << (JSStream on: 'clearUploadProgress()').
s << (s jQuery: #uploadNotification)
html: [ :renderer |
errorText notNil
ifTrue: [
renderer div
class: 'error';
with: errorText ]
ifFalse: [
renderer div] ].
s << (s jQuery: #projectUploadedFilesContainer)
html: [ :renderer |
renderer render: self imageRenderer ].
s << (JSStream on: 'xProgressId="', self xProgressId, '"') ]
and one more javascript method:
startUploadProgressBarJavascript
^'
var interval = null;
> function startUploadProgressBar() {
$("#progressBar").progressbar({ value: 0 });
$("#progressBar").css("display", "block");
$("#fileUploadContainer").css("display", "none");
interval = window.setInterval( function () { fetch(xProgressId); }, 1000);
}
> function clearUploadProgress() {
window.clearTimeout(interval);
$("#progressBar").css("display", "none");
$("#fileUploadContainer").css("display", "block");
}
> function setUploadStatus (statusText) {
$("#uploadNotification").html("<div class=''status''>" + statusText +
> "</div>");
}
function fetch(uuid) {
$.ajax({
url: "/progress",
beforeSend: function (xhr) {
xhr.setRequestHeader("X-Progress-ID", uuid);
},
success: function (data, textStatus, xhr) {
var upload = eval(data);
> if (upload.state == "done" || upload.state == "uploading") {
var percentageComplete = Math.floor(upload.received * 100 / upload.size);
$("#progressBar").progressbar({ value: percentageComplete });
if (upload.received != upload.size) {
setUploadStatus("Uploading: " + percentageComplete + "%");
} else {
setUploadStatus("Uploaded: processing");
}
}
if (upload.state == "starting") {
setUploadStatus("Starting upload");
}
if (upload.state == "done") {
clearUploadProgress();
}
},
error: function(xhr, textError) {
setUploadStatus("Error: " + textError);
}
});
}
'
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.squeakfoundation.org/pipermail/seaside/attachments/20110616/2f8f9a12/attachment-0001.htm
More information about the seaside
mailing list