Mercurial > ajaxUpload
changeset 1:f84d5e8aa992
Complete working example with required submit button click
author | Adam Chlipala <adam@chlipala.net> |
---|---|
date | Thu, 29 Dec 2011 15:26:46 -0500 |
parents | 0c0f903d9440 |
children | df095eecba63 |
files | examples/server.ur examples/server.urp include/ajaxUpload.h src/c/ajaxUpload.c src/ur/ajaxUpload.ur src/ur/ajaxUpload.urs src/ur/ajaxUploadFfi.urs src/ur/lib.urp |
diffstat | 8 files changed, 94 insertions(+), 10 deletions(-) [+] |
line wrap: on
line diff
--- a/examples/server.ur Thu Dec 29 14:37:31 2011 -0500 +++ b/examples/server.ur Thu Dec 29 15:26:46 2011 -0500 @@ -1,5 +1,39 @@ +sequence ids + +table images : { Id : int, MimeType : string, Content : blob } + PRIMARY KEY Id + fun main () = - au <- AjaxUpload.render (); + status <- source <xml/>; + au <- AjaxUpload.render {OnBegin = set status <xml>Uploading</xml>, + OnSuccess = fn h => + let + fun addImage () = + r <- AjaxUpload.claim h; + case r of + AjaxUpload.NotFound => return None + | AjaxUpload.Found r => + id <- nextval ids; + dml (INSERT INTO images (Id, MimeType, Content) + VALUES ({[id]}, {[r.MimeType]}, {[r.Content]})); + return (Some id) + in + ido <- rpc (addImage ()); + case ido of + None => alert "Newly uploaded image not found!" + | Some id => + let + fun image () = + r <- oneRow1 (SELECT images.MimeType, images.Content + FROM images + WHERE images.Id = {[id]}); + returnBlob r.Content (blessMime r.MimeType) + in + set status <xml><img src={url (image ())}/></xml> + end + end}; return <xml><body> {au} + <hr/> + <dyn signal={signal status}/> </body></xml>
--- a/examples/server.urp Thu Dec 29 14:37:31 2011 -0500 +++ b/examples/server.urp Thu Dec 29 15:26:46 2011 -0500 @@ -2,5 +2,6 @@ rewrite url Server/* database dbname=test sql server.sql +allow mime image/jpeg server
--- a/include/ajaxUpload.h Thu Dec 29 14:37:31 2011 -0500 +++ b/include/ajaxUpload.h Thu Dec 29 15:26:46 2011 -0500 @@ -1,3 +1,7 @@ #include <urweb.h> uw_Basis_string uw_AjaxUploadFfi_tweakForm(uw_context, uw_Basis_string iframeId, uw_Basis_string submitId); +uw_Basis_string uw_AjaxUploadFfi_notifySuccess(uw_context, uw_Basis_string submitId, uw_Basis_int handle); + +uw_Basis_string uw_AjaxUploadFfi_idToString(uw_context, uw_Basis_string); +uw_Basis_string uw_AjaxUploadFfi_stringToId(uw_context, uw_Basis_string);
--- a/src/c/ajaxUpload.c Thu Dec 29 14:37:31 2011 -0500 +++ b/src/c/ajaxUpload.c Thu Dec 29 15:26:46 2011 -0500 @@ -1,3 +1,6 @@ +#include <ctype.h> +#include <stdio.h> + #include <ajaxUpload.h> uw_Basis_string uw_AjaxUploadFfi_tweakForm(uw_context ctx, uw_Basis_string iframeId, uw_Basis_string submitId) { @@ -6,10 +9,37 @@ iframeId, "\" name=\"", iframeId, - "\" src=\"#\"></iframe>\n<script type=\"text/javascript\">var subm = document.getElementById(\"", + "\" src=\"#\" style=\"width:0;height:0;border:0px solid #fff;\"></iframe>\n<script type=\"text/javascript\">var subm = document.getElementById(\"", submitId, "\"); subm.parentNode.target = \"", iframeId, - "\";</script>", + "\"; var onSub = subm.onmousedown; subm.onmousedown = undefined; subm.parentNode.onsubmit = function() { onSub(); return true; }; subm.withHandle = subm.onkeydown; subm.onkeydown = undefined; </script>", NULL); } + +uw_Basis_string uw_AjaxUploadFfi_notifySuccess(uw_context ctx, uw_Basis_string submitId, uw_Basis_int handle) { + return uw_Basis_mstrcat(ctx, + "<script type=\"text/javascript\">var subm = window.top.document.getElementById(\"", + submitId, + "\"); window.top.event = {keyCode : ", + uw_Basis_htmlifyInt(ctx, handle), + "}; subm.withHandle(); </script>", + NULL); +} + +uw_Basis_string uw_AjaxUploadFfi_idToString(uw_context ctx, uw_Basis_string s) { + return s; +} + +uw_Basis_string uw_AjaxUploadFfi_stringToId(uw_context ctx, uw_Basis_string s) { + char *s2 = s; + + if (*s2 == '-') + ++s2; + + for (++s2; *s2; ++s2) + if (!isdigit(*s2)) + uw_error(ctx, FATAL, "AjaxUploadFfi.stringToId: Invalid ID"); + + return s; +}
--- a/src/ur/ajaxUpload.ur Thu Dec 29 14:37:31 2011 -0500 +++ b/src/ur/ajaxUpload.ur Thu Dec 29 15:26:46 2011 -0500 @@ -25,24 +25,30 @@ ro <- oneOrNoRows1 (SELECT scratch.Filename, scratch.MimeType, scratch.Content FROM scratch WHERE scratch.Handle = {[h]}); - return (case ro of - None => NotFound - | Some r => Found r) + case ro of + None => return NotFound + | Some r => + dml (DELETE FROM scratch + WHERE Handle = {[h]}); + return (Found r) -fun render {} = +fun render {OnBegin = ob, OnSuccess = os} = iframeId <- fresh; submitId <- fresh; + submitId' <- return (AjaxUploadFfi.idToString submitId); let fun upload r = h <- nextval handles; dml (INSERT INTO scratch (Handle, Filename, MimeType, Content, Created) VALUES ({[h]}, {[fileName r.File]}, {[fileMimeType r.File]}, {[fileData r.File]}, CURRENT_TIMESTAMP)); - return <xml>OK!</xml> + return <xml><body> + {AjaxUploadFfi.notifySuccess (AjaxUploadFfi.stringToId submitId') h} + </body></xml> in return <xml> <form> <upload{#File}/> - <submit action={upload} id={submitId}/> + <submit action={upload} id={submitId} onmousedown={ob} onkeydown={os}/> </form> {AjaxUploadFfi.tweakForm iframeId submitId} </xml>
--- a/src/ur/ajaxUpload.urs Thu Dec 29 14:37:31 2011 -0500 +++ b/src/ur/ajaxUpload.urs Thu Dec 29 15:26:46 2011 -0500 @@ -12,5 +12,9 @@ val claim : handle -> transaction claim_result (* In server-side code, claim ownership of a [handle]'s contents, deleting the persistent record of the file data. *) -val render : {} -> transaction xbody +val render : {OnBegin : transaction {}, + (* Run this when an upload begins. *) + OnSuccess : handle -> transaction {} + (* Run this after a successful upload. *)} + -> transaction xbody (* Produce HTML for a file upload control *)