From 25ae9b2dc4d2a2a5bd2e1920e1ee82dfbef4162e Mon Sep 17 00:00:00 2001 From: hallgren Date: Wed, 8 Jun 2011 15:29:50 +0000 Subject: gfse: initial support for grammars in the cloud This lets the user access the same set of grammars from multiple devices. Sharing grammars between multiple users is possible but discouraged at the moment. There is no version handling, so concurrent editing of the same grammar by different users might result in one user overwriting changes made by another user. (The same goes for cuncurrent editing on multiple devices by a single user, of course.) --- src/editor/simple/P/1306856253_weather_06.png | Bin 0 -> 2311 bytes src/editor/simple/P/1307545089_weather_04.png | Bin 0 -> 2376 bytes src/editor/simple/editor.css | 11 +- src/editor/simple/editor.js | 197 +++++++++++++++++++++++--- src/editor/simple/save.hs | 15 +- src/editor/simple/upload.cgi | 108 ++++++++++---- 6 files changed, 276 insertions(+), 55 deletions(-) create mode 100644 src/editor/simple/P/1306856253_weather_06.png create mode 100644 src/editor/simple/P/1307545089_weather_04.png (limited to 'src') diff --git a/src/editor/simple/P/1306856253_weather_06.png b/src/editor/simple/P/1306856253_weather_06.png new file mode 100644 index 000000000..3f01afcaa Binary files /dev/null and b/src/editor/simple/P/1306856253_weather_06.png differ diff --git a/src/editor/simple/P/1307545089_weather_04.png b/src/editor/simple/P/1307545089_weather_04.png new file mode 100644 index 000000000..8a7f1e3ae Binary files /dev/null and b/src/editor/simple/P/1307545089_weather_04.png differ diff --git a/src/editor/simple/editor.css b/src/editor/simple/editor.css index 7bce43c3f..32625e699 100644 --- a/src/editor/simple/editor.css +++ b/src/editor/simple/editor.css @@ -4,7 +4,8 @@ h1,h2,h3,h4,small { font-family: sans-serif; } h1:first-child, h2:first-child { margin-top: 0; margin-bottom: 1ex; } #editor { max-width: 50em; } -div.grammar { border: 1px solid black; background: #9df; } +div.home, div.grammar { border: 1px solid black; background: #9df; } +div.home { padding: 5px; } div.files { margin: 0 8px 8px 8px; } div#file { border: 2px solid #009; border-top-width: 0; } @@ -13,12 +14,12 @@ div#file, pre.plain { background: white; padding: 0.6ex; } .slideshow .hidden { display: none; } -img.right, div.right, div.modtime { float: right; } +img.cloud, img.right, div.right, div.modtime { float: right; } .modtime { color: #999; white-space: nowrap; } div.namebar { background: #9df; } div.namebar table { width: 100%; } -.namebar h3 { margin: 0; color: #009; } +.namebar h3, .home h3 { margin: 0; color: #009; } td.right { text-align: right; } @@ -74,4 +75,6 @@ table.tabs input[type=button] { /*text-decoration: underline;*/ } -input.string_edit { font-family: inherit; font-size: inherit; } \ No newline at end of file +input.string_edit { font-family: inherit; font-size: inherit; } + +ul.languages { -moz-column-width: 20em; } diff --git a/src/editor/simple/editor.js b/src/editor/simple/editor.js index 30e989940..21a04dcb4 100644 --- a/src/editor/simple/editor.js +++ b/src/editor/simple/editor.js @@ -12,9 +12,16 @@ function table(rows) { return node("table",{},rows); } function td_right(cs) { return node("td",{"class":"right"},cs); } function jsurl(js) { return "javascript:"+js; } +function hidden(name,value) { + return node("input",{type:"hidden",name:name,value:value},[]) +} + +function insertBefore(el,ref) { ref.parentNode.insertBefore(el,ref); } + function insertAfter(el,ref) { ref.parentNode.insertBefore(el,ref.nextSibling); } + /* -------------------------------------------------------------------------- */ function initial_view() { @@ -27,7 +34,24 @@ function initial_view() { function draw_grammar_list() { local.put("current",0); editor.innerHTML=""; - editor.appendChild(node("h3",{},[text("Your grammars")])); + var cloud_upload= + a(jsurl("upload_json()"), + [node("img",{"class":"cloud", + src:"P/1306856253_weather_06.png",alt:"[Up Cloud]", + title:"Click to store your grammars in the cloud"}, + [])]); + var home=div_class("home",[node("h3",{}, + [text("Your grammars"),cloud_upload])]); + if(local.get("json_uploaded")) { + var cloud_download= + a(jsurl("download_json()"), + [node("img",{"class":"cloud", + src:"P/1307545089_weather_04.png",alt:"[Down Cloud]", + title:"Click to download grammar updates from the cloud"}, + [])]); + insertAfter(cloud_download,cloud_upload); + } + editor.appendChild(home) var gs=ul([]); function del(i) { return function () { delete_grammar(i); } } for(var i=0;i0) get_file(i+".json",file_ok,file_err) + else { + local.count=new_count; + //alert("Download finished"); + setTimeout(function(){location.href="."},3000); + } + } + function download_files(count) { + new_count=count; + local.put("current",0); + download_files_from(count); + } + get_file("count.json",download_files); +} + +function download_from_cloud() { + var olddir=local.get("dir",null) + var newdir="/tmp/"+location.hash.substr(1) + if(newdir==olddir || confirm("Cloud grammars will replace your local grammars")) { + local.put("dir",newdir); + download_json(newdir) + } +} + +function timestamp(obj,prop) { + obj[prop || "timestamp"]=Date.now(); +} + +function draw_timestamp(obj) { + var t=obj.timestamp; + return node("small",{"class":"modtime"}, + [text(t ? " -- "+new Date(t).toLocaleString() : "")]); } /* -------------------------------------------------------------------------- */ @@ -919,5 +1074,7 @@ function touch_edit() { //document.body.appendChild(empty_id("div","debug")); -initial_view(); -touch_edit(); +if(editor) { + initial_view(); + touch_edit(); +} diff --git a/src/editor/simple/save.hs b/src/editor/simple/save.hs index 01d3ce270..e29287d33 100644 --- a/src/editor/simple/save.hs +++ b/src/editor/simple/save.hs @@ -1,12 +1,17 @@ -import Monad(zipWithM_) +import Monad(zipWithM) import System(getArgs) main = save =<< getArgs save [dir] = do fs@[ns,_] <- readIO =<< getContents - save_all fs - putStrLn $ unwords [n++".gf"|n<-ns] + nes <- save_all fs + putStrLn $ unwords nes where - save_all [ns,cs] = zipWithM_ write1 ns cs - write1 n = writeFile (dir++"/"++n++".gf") + save_all [ns,cs] = zipWithM write1 ns cs + write1 n c = + do writeFile (dir++"/"++ne) c + return ne + where + ne=if '.' `elem` n then n else n++".gf" + \ No newline at end of file diff --git a/src/editor/simple/upload.cgi b/src/editor/simple/upload.cgi index 9ef113ebf..ec6bdc476 100644 --- a/src/editor/simple/upload.cgi +++ b/src/editor/simple/upload.cgi @@ -12,7 +12,7 @@ style_url="editor.css" tmp="$documentRoot/tmp" make_dir() { - dir="$(mktemp -d "$tmp/gfse.XXXXXXXX")" + dir="$(mktemp -d "$tmp/gfse.XXXXXXXXXX")" # chmod a+rxw "$dir" chmod a+rx "$dir" cp "grammars.cgi" "$dir" @@ -25,30 +25,58 @@ check_grammar() { chgrp everyone "$dir" chmod g+ws "$dir" umask 002 - files=$(Reg from-url | LC_CTYPE=sv_SE.ISO8859-1 ./save "$dir") - cd $dir - begin pre - if gf -s -make $files 2>&1 ; then - end - h3 OK - begin dl - [ -z "$minibar_url" ] || { dt; echo "▸"; link "$minibar_url?/tmp/${dir##*/}/" "Minibar"; } - [ -z "$transquiz_url" ] || { dt; echo "▸"; link "$transquiz_url?/tmp/${dir##*/}/" "Translation Quiz"; } - [ -z "$gfshell_url" ] || { dt; echo "▸"; link "$gfshell_url?dir=${dir##*/}" "GF Shell"; } - dt ; echo "◂"; link "javascript:history.back()" "Back to Editor" + files=( $(Reg from-url | LC_CTYPE=sv_SE.ISO8859-1 ./save "$dir") ) + gffiles=( ) + otherfiles=( ) + for f in ${files[*]} ; do + case "$f" in + *.gf) gffiles=( ${gffiles[*]} "$f" ) ;; + *) otherfiles=( ${otherfiles[*]} "$f" ) ;; + esac + done + + if [ ${#otherfiles} -gt 0 -a -n "$PATH_INFO" ] ; then + echo "Use the following link for shared access to your grammars from multiple devices:" + begin ul + case "$SERVER_PORT" in + 80) port="" ;; + *) port=":$SERVER_PORT" + esac + parent="http://$SERVER_NAME$port${REQUEST_URI%/upload.cgi/tmp/gfse.*}" + cloudurl="$parent/share.html#${dir##*/}" + li; link "$cloudurl" "$cloudurl" + end + begin dl + dt ; echo "◂"; link "javascript:history.back()" "Back to Editor" + end + fi - end + cd $dir + if [ ${#gffiles} -gt 0 ] ; then begin pre - ls -l *.pgf - else - end - begin h3 class=error_message; echo Error; end - for f in *.gf ; do - h4 "$f" - begin pre class=plain - cat -n "$f" + echo "gf -s -make ${gffiles[*]}" + if gf -s -make ${gffiles[*]} 2>&1 ; then end - done + h3 OK + begin dl + [ -z "$minibar_url" ] || { dt; echo "▸"; link "$minibar_url?/tmp/${dir##*/}/" "Minibar"; } + [ -z "$transquiz_url" ] || { dt; echo "▸"; link "$transquiz_url?/tmp/${dir##*/}/" "Translation Quiz"; } + [ -z "$gfshell_url" ] || { dt; echo "▸"; link "$gfshell_url?dir=${dir##*/}" "GF Shell"; } + dt ; echo "◂"; link "javascript:history.back()" "Back to Editor" + + end + begin pre + ls -l *.pgf + else + end + begin h3 class=error_message; echo Error; end + for f in ${gffiles[*]} ; do + h4 "$f" + begin pre class=plain + cat -n "$f" + end + done + fi fi hr date @@ -56,6 +84,20 @@ check_grammar() { endall } +error400() { + echo "Status: 400" + pagestart "Error" + echo "What do you want?" + endall +} + +error404() { + echo "Status: 404" + pagestart "Not found" + echo "Not found" + endall +} + if [ -z "$tmp" ] || ! [ -d "$tmp" ] ; then pagestart "Error" begin pre @@ -87,11 +129,25 @@ case "$REQUEST_METHOD" in dir) make_dir ContentType="text/plain" cgiheaders - echo "/tmp/${dir##*/}" + echo_n "/tmp/${dir##*/}" ;; - *) pagestart "Error" - echo "What do you want?" - endall + download=*) + file=$(qparse "$QUERY_STRING" download) + case "$file" in + /tmp/gfse.*/*.json) # shouldn't allow .. in path !!! + path="$documentRoot$file" + if [ -r "$path" ] ; then + ContentType="text/javascript; charset=$charset" + cgiheaders + cat "$path" + else + error404 + fi + ;; + *) error400 + esac + ;; + *) error400 esac esac fi -- cgit v1.2.3