forked from GitHub/gf-core
First version of ajax / fastcgi interface with completion.
This commit is contained in:
@@ -11,6 +11,7 @@ import qualified Codec.Binary.UTF8.String as UTF8 (encodeString)
|
|||||||
import Control.Exception
|
import Control.Exception
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
import Data.Dynamic
|
import Data.Dynamic
|
||||||
|
import qualified Data.Map as Map
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
|
|
||||||
|
|
||||||
@@ -31,12 +32,13 @@ cgiMain :: PGF -> CGI CGIResult
|
|||||||
cgiMain pgf =
|
cgiMain pgf =
|
||||||
do path <- pathInfo
|
do path <- pathInfo
|
||||||
json <- case path of
|
json <- case path of
|
||||||
"/parse" -> return (doParse pgf) `ap` getText `ap` getCat `ap` getFrom
|
"/parse" -> return (doParse pgf) `ap` getText `ap` getCat `ap` getFrom
|
||||||
"/linearize" -> return (doLinearize pgf) `ap` getTree `ap` getTo
|
"/complete" -> return (doComplete pgf) `ap` getText `ap` getCat `ap` getFrom
|
||||||
"/translate" -> return (doTranslate pgf) `ap` getText `ap` getCat `ap` getFrom `ap` getTo
|
"/linearize" -> return (doLinearize pgf) `ap` getTree `ap` getTo
|
||||||
"/categories" -> return $ doCategories pgf
|
"/translate" -> return (doTranslate pgf) `ap` getText `ap` getCat `ap` getFrom `ap` getTo
|
||||||
"/languages" -> return $ doLanguages pgf
|
"/categories" -> return $ doCategories pgf
|
||||||
_ -> throwCGIError 404 "Not Found" ["Resource not found: " ++ path]
|
"/languages" -> return $ doLanguages pgf
|
||||||
|
_ -> throwCGIError 404 "Not Found" ["Resource not found: " ++ path]
|
||||||
outputJSON json
|
outputJSON json
|
||||||
where
|
where
|
||||||
getText :: CGI String
|
getText :: CGI String
|
||||||
@@ -80,6 +82,9 @@ doParse :: PGF -> String -> Maybe PGF.Category -> Maybe PGF.Language -> JSValue
|
|||||||
doParse pgf input mcat mfrom = showJSON $ toJSObject $
|
doParse pgf input mcat mfrom = showJSON $ toJSObject $
|
||||||
[(from, map PGF.showTree trees) | (from,trees) <- parse' pgf input mcat mfrom]
|
[(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 -> PGF.Tree -> Maybe PGF.Language -> JSValue
|
||||||
doLinearize pgf tree mto = showJSON $ toJSObject $ linearize' pgf mto tree
|
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 -> String -> Maybe PGF.Category -> Maybe PGF.Language -> [(PGF.Language,[PGF.Tree])]
|
||||||
parse' pgf input mcat mfrom =
|
parse' pgf input mcat mfrom =
|
||||||
case mfrom of
|
[(from,ts) | from <- froms, PGF.canParse pgf from, let ts = PGF.parse pgf from cat input, not (null ts)]
|
||||||
Nothing -> PGF.parseAllLang pgf cat input
|
where froms = maybe (PGF.languages pgf) (:[]) mfrom
|
||||||
Just from -> [(from, PGF.parse pgf from cat input)]
|
cat = fromMaybe (PGF.startCat pgf) mcat
|
||||||
where 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 -> Maybe PGF.Language -> PGF.Tree -> [(PGF.Language,String)]
|
||||||
linearize' pgf mto tree =
|
linearize' pgf mto tree =
|
||||||
|
|||||||
@@ -13,10 +13,11 @@
|
|||||||
var input = document.getElementById('inputText').value;
|
var input = document.getElementById('inputText').value;
|
||||||
var fromLang = document.getElementById('fromLang').value;
|
var fromLang = document.getElementById('fromLang').value;
|
||||||
var toLang = document.getElementById('toLang').value;
|
var toLang = document.getElementById('toLang').value;
|
||||||
var output = document.getElementById('output');
|
var output = document.getElementById('translation');
|
||||||
|
|
||||||
var callback = function(translation) {
|
var callback = function(translation) {
|
||||||
removeChildren(output);
|
clearTranslation();
|
||||||
output.appendChild(formatTranslation(translation));
|
output.appendChild(formatTranslation(translation));
|
||||||
};
|
};
|
||||||
gf.translate(input, fromLang, toLang, '', callback);
|
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() {
|
function initialize() {
|
||||||
gf.getLanguages(populateLangs);
|
gf.languages(populateLangs);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<title>AJAX GF Translator</title>
|
<title>AJAX GF Translator</title>
|
||||||
</head>
|
</head>
|
||||||
<body onload="initialize()">
|
<body onload="initialize()">
|
||||||
<form id="translate" onsubmit="updateTranslation(); return false;">
|
<div id="translator">
|
||||||
<p>
|
<form onsubmit="update(); return false;">
|
||||||
<input type="text" name="inputText" id="inputText" value="this cheese is warm" size="50" />
|
<p>
|
||||||
</p>
|
<input type="text" id="inputText" value="this cheese is warm" size="50" onkeyup="update()"/>
|
||||||
<p>
|
</p>
|
||||||
From: <select name="fromLang" id="fromLang" onchange="updateTranslation()"><option value="">Any language</option></select>
|
<p>
|
||||||
To: <select name="toLang" id="toLang" onchange="updateTranslation()"><option value="">All languages</option></select>
|
<label>From: <select id="fromLang" onchange="update()"><option value="">Any language</option></select></label>
|
||||||
<input type="submit" value="Translate" />
|
<label>To: <select id="toLang" onchange="update()"><option value="">All languages</option></select></label>
|
||||||
</p>
|
<input type="submit" value="Translate" />
|
||||||
</form>
|
</p>
|
||||||
<div id="output"></div>
|
</form>
|
||||||
|
<div id="completion"></div>
|
||||||
|
<div id="translation"></div>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -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.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)); });
|
gf.httpGetText("gf.fcgi/languages", function (output) { callback(gf.readJSON(output)); });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ executable gf.fcgi
|
|||||||
old-time,
|
old-time,
|
||||||
unix,
|
unix,
|
||||||
directory,
|
directory,
|
||||||
|
containers,
|
||||||
gf,
|
gf,
|
||||||
cgi,
|
cgi,
|
||||||
fastcgi,
|
fastcgi,
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
body {
|
body {
|
||||||
color: black;
|
color: black;
|
||||||
background-color: white;
|
background-color: white;
|
||||||
|
font-family: sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
dl {
|
dl {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
dt {
|
dt {
|
||||||
@@ -17,6 +19,29 @@ dl dd {
|
|||||||
padding: 0;
|
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 {
|
dl.fromLang dt {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
@@ -32,23 +57,33 @@ dl.toLang dt {
|
|||||||
display: block;
|
display: block;
|
||||||
float: left;
|
float: left;
|
||||||
width: 5em;
|
width: 5em;
|
||||||
|
font-size: 80%;
|
||||||
|
padding: 1px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
dl.toLang dd {
|
dl.toLang dd {
|
||||||
border-width: 0 0 1px 0;
|
border-width: 0 0 1px 0;
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
border-color: #c0c0c0;
|
border-color: #c0c0c0;
|
||||||
|
padding: 0.2em 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Completions */
|
||||||
|
|
||||||
ul {
|
#completion {
|
||||||
margin: 0;
|
font-size: 80%;
|
||||||
padding: 0;
|
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;
|
|
||||||
}
|
|
||||||
@@ -17,6 +17,18 @@ function formatTranslation (outputs) {
|
|||||||
return dl1;
|
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 */
|
/* DOM utilities for specific tags */
|
||||||
|
|
||||||
function addDefinition (dl, t, d) {
|
function addDefinition (dl, t, d) {
|
||||||
|
|||||||
Reference in New Issue
Block a user