From e1584715ccc2e2384e26be5cd80dfb633876957e Mon Sep 17 00:00:00 2001 From: bjorn Date: Tue, 19 Aug 2008 12:29:31 +0000 Subject: [PATCH] First version of ajax / fastcgi interface with completion. --- src/server/MainFastCGI.hs | 39 ++++++++++++++++------ src/server/gf-client.html | 63 ++++++++++++++++++++++++++--------- src/server/gf-server-jsapi.js | 6 +++- src/server/gf-server.cabal | 1 + src/server/translator.css | 55 ++++++++++++++++++++++++------ src/server/translator.js | 12 +++++++ 6 files changed, 140 insertions(+), 36 deletions(-) diff --git a/src/server/MainFastCGI.hs b/src/server/MainFastCGI.hs index d678c1579..230e09b00 100644 --- a/src/server/MainFastCGI.hs +++ b/src/server/MainFastCGI.hs @@ -11,6 +11,7 @@ import qualified Codec.Binary.UTF8.String as UTF8 (encodeString) import Control.Exception import Control.Monad import Data.Dynamic +import qualified Data.Map as Map import Data.Maybe @@ -31,12 +32,13 @@ cgiMain :: PGF -> CGI CGIResult cgiMain pgf = do path <- pathInfo json <- case path of - "/parse" -> return (doParse pgf) `ap` getText `ap` getCat `ap` getFrom - "/linearize" -> return (doLinearize pgf) `ap` getTree `ap` getTo - "/translate" -> return (doTranslate pgf) `ap` getText `ap` getCat `ap` getFrom `ap` getTo - "/categories" -> return $ doCategories pgf - "/languages" -> return $ doLanguages pgf - _ -> throwCGIError 404 "Not Found" ["Resource not found: " ++ path] + "/parse" -> return (doParse pgf) `ap` getText `ap` getCat `ap` getFrom + "/complete" -> return (doComplete pgf) `ap` getText `ap` getCat `ap` getFrom + "/linearize" -> return (doLinearize pgf) `ap` getTree `ap` getTo + "/translate" -> return (doTranslate pgf) `ap` getText `ap` getCat `ap` getFrom `ap` getTo + "/categories" -> return $ doCategories pgf + "/languages" -> return $ doLanguages pgf + _ -> throwCGIError 404 "Not Found" ["Resource not found: " ++ path] outputJSON json where getText :: CGI String @@ -80,6 +82,9 @@ doParse :: PGF -> String -> Maybe PGF.Category -> Maybe PGF.Language -> JSValue doParse pgf input mcat mfrom = showJSON $ toJSObject $ [(from, map PGF.showTree trees) | (from,trees) <- parse' pgf input mcat mfrom] +doComplete :: PGF -> String -> Maybe PGF.Category -> Maybe PGF.Language -> JSValue +doComplete pgf input mcat mfrom = showJSON $ toJSObject $ complete' pgf input mcat mfrom + doLinearize :: PGF -> PGF.Tree -> Maybe PGF.Language -> JSValue doLinearize pgf tree mto = showJSON $ toJSObject $ linearize' pgf mto tree @@ -96,10 +101,24 @@ doCategories pgf = showJSON (PGF.categories pgf) parse' :: PGF -> String -> Maybe PGF.Category -> Maybe PGF.Language -> [(PGF.Language,[PGF.Tree])] parse' pgf input mcat mfrom = - case mfrom of - Nothing -> PGF.parseAllLang pgf cat input - Just from -> [(from, PGF.parse pgf from cat input)] - where cat = fromMaybe (PGF.startCat pgf) mcat + [(from,ts) | from <- froms, PGF.canParse pgf from, let ts = PGF.parse pgf from cat input, not (null ts)] + where froms = maybe (PGF.languages pgf) (:[]) mfrom + cat = fromMaybe (PGF.startCat pgf) mcat + +complete' :: PGF -> String -> Maybe PGF.Category -> Maybe PGF.Language -> [(PGF.Language,[String])] +complete' pgf input mcat mfrom = + [(from,ss) | from <- froms, PGF.canParse pgf from, let ss = complete pgf from cat input, not (null ss)] + where froms = maybe (PGF.languages pgf) (:[]) mfrom + cat = fromMaybe (PGF.startCat pgf) mcat + +complete :: PGF -> PGF.Language -> PGF.Category -> String -> [String] +complete pgf from cat input = + let ws = words input + prefix = "" -- FIXME + state0 = PGF.initState pgf from cat + state = foldl PGF.nextState state0 ws + compls = PGF.getCompletions state prefix + in Map.keys compls linearize' :: PGF -> Maybe PGF.Language -> PGF.Tree -> [(PGF.Language,String)] linearize' pgf mto tree = diff --git a/src/server/gf-client.html b/src/server/gf-client.html index 4516d7e1e..a3558e25c 100644 --- a/src/server/gf-client.html +++ b/src/server/gf-client.html @@ -13,10 +13,11 @@ var input = document.getElementById('inputText').value; var fromLang = document.getElementById('fromLang').value; var toLang = document.getElementById('toLang').value; - var output = document.getElementById('output'); + var output = document.getElementById('translation'); + var callback = function(translation) { - removeChildren(output); - output.appendChild(formatTranslation(translation)); + clearTranslation(); + output.appendChild(formatTranslation(translation)); }; gf.translate(input, fromLang, toLang, '', callback); } @@ -32,23 +33,55 @@ } } + function updateCompletion() { + var input = document.getElementById('inputText').value; + var fromLang = document.getElementById('fromLang').value; + var completions = document.getElementById('completion'); + +// if (document.getElementById('enableCompletion').checked) { + var callback = function(output) { + clearCompletion(); + completions.appendChild(formatCompletions(output)); + }; + gf.complete(input, fromLang, '', callback); +// } + } + + function update() { + updateCompletion(); + updateTranslation(); + } + + function clearTranslation() { + var output = document.getElementById('translation'); + removeChildren(output); + } + + function clearCompletion() { + var completions = document.getElementById('completion'); + removeChildren(completions); + } + function initialize() { - gf.getLanguages(populateLangs); + gf.languages(populateLangs); } AJAX GF Translator -
-

- -

-

- From: - To: - -

-
-
+
+
+

+ +

+

+ + + +

+
+
+
+
diff --git a/src/server/gf-server-jsapi.js b/src/server/gf-server-jsapi.js index 9a2096532..dfa50c2f7 100644 --- a/src/server/gf-server-jsapi.js +++ b/src/server/gf-server-jsapi.js @@ -4,7 +4,11 @@ gf.translate = function (input,from,to,cat,callback) { gf.httpGetText("gf.fcgi/translate?input="+escape(input)+"&from="+escape(from)+"&to="+escape(to)+"&cat="+escape(cat), function (output) { callback(gf.readJSON(output)); }); }; -gf.getLanguages = function (callback) { +gf.complete = function (input,from,cat,callback) { + gf.httpGetText("gf.fcgi/complete?input="+escape(input)+"&from="+escape(from)+"&cat="+escape(cat), function (output) { callback(gf.readJSON(output)); }); +}; + +gf.languages = function (callback) { gf.httpGetText("gf.fcgi/languages", function (output) { callback(gf.readJSON(output)); }); }; diff --git a/src/server/gf-server.cabal b/src/server/gf-server.cabal index f6104e481..67935e491 100644 --- a/src/server/gf-server.cabal +++ b/src/server/gf-server.cabal @@ -11,6 +11,7 @@ executable gf.fcgi old-time, unix, directory, + containers, gf, cgi, fastcgi, diff --git a/src/server/translator.css b/src/server/translator.css index f7f771927..d4fb7be1f 100644 --- a/src/server/translator.css +++ b/src/server/translator.css @@ -1,10 +1,12 @@ body { color: black; background-color: white; + font-family: sans-serif; } dl { - + margin: 0; + padding: 0; } dt { @@ -17,6 +19,29 @@ dl dd { padding: 0; } +ul { + margin: 0; + padding: 0; +} + +li { + list-style-type: none; + margin: 0; + padding: 0; +} + +/* Translator widget */ + +#translator { + +} + +/* Translations */ + +#translation { + clear: both; +} + dl.fromLang dt { display: none; } @@ -32,23 +57,33 @@ dl.toLang dt { display: block; float: left; width: 5em; + font-size: 80%; + padding: 1px 0; } - dl.toLang dd { border-width: 0 0 1px 0; border-style: solid; border-color: #c0c0c0; + padding: 0.2em 0; } +/* Completions */ -ul { - margin: 0; - padding: 0; +#completion { + font-size: 80%; + color: #c0c0c0; + white-space: nowrap; + width: 100%; + overflow: hidden; +} + +#completion dt { + display: none; +} + +#completion li { + display: inline; + padding: 0 0.1em; } -li { - list-style-type: none; - margin: 0; - padding: 0; -} \ No newline at end of file diff --git a/src/server/translator.js b/src/server/translator.js index 31da04290..96acd52d2 100644 --- a/src/server/translator.js +++ b/src/server/translator.js @@ -17,6 +17,18 @@ function formatTranslation (outputs) { return dl1; } +function formatCompletions (compls) { + var dl = document.createElement("dl"); + for (var fromLang in compls) { + var ul = document.createElement("ul"); + for (var i in compls[fromLang]) { + addItem(ul, document.createTextNode(compls[fromLang][i])); + } + addDefinition(dl, document.createTextNode(fromLang), ul); + } + return dl; +} + /* DOM utilities for specific tags */ function addDefinition (dl, t, d) {