move gf.cabal and all compiler dependent files into src/compiler

This commit is contained in:
Krasimir Angelov
2022-06-18 20:42:31 +02:00
parent 96c8218564
commit a8ad145aeb
264 changed files with 71 additions and 71 deletions

314
src/compiler/www/js/d3Tree.js vendored Normal file
View File

@@ -0,0 +1,314 @@
// Copied from https://github.com/christos-c/tree-viewer (TH 2015-03-24)
// Inspired by "D3.js Drag and Drop Zoomable Tree" by Rob Schmuecker <robert.schmuecker@gmail.com>
// https://gist.github.com/robschmuecker/7880033
function d3Tree(treeData) {
// panning variables
var panSpeed = 200;
// Misc. variables
var i = 0;
var duration = 450;
var root;
// size of the diagram
var pageWidth = $(document).width();
var viewerWidth = pageWidth - (0.2 * pageWidth);
var viewerHeight = 500;
var tree = d3.layout.tree()
.size([viewerWidth-20, viewerHeight]);
// define a d3 diagonal projection for use by the node paths later on.
var diagonal = d3.svg.diagonal()
.projection(function(d) {
return [d.x, d.y];
});
// Can be used to draw the links between nodes instead of the diagonal
// TODO Doesn't work with the collapse/expand transition
//function straightLine(d) {
// return "M" + d.source.x + "," + d.source.y + "L" + d.target.x + "," + d.target.y;
//}
// A recursive helper function for performing some setup by walking through all nodes
function visit(parent, visitFn, childrenFn) {
if (!parent) return;
visitFn(parent);
var children = childrenFn(parent);
if (children) {
var count = children.length;
for (var i = 0; i < count; i++) {
visit(children[i], visitFn, childrenFn);
}
}
}
// TODO: Pan function, can be better implemented.
function pan(domNode, direction) {
var speed = panSpeed;
if (panTimer) {
clearTimeout(panTimer);
translateCoords = d3.transform(svgGroup.attr("transform"));
if (direction == 'left' || direction == 'right') {
translateX = direction == 'left' ? translateCoords.translate[0] + speed : translateCoords.translate[0] - speed;
translateY = translateCoords.translate[1];
} else if (direction == 'up' || direction == 'down') {
translateX = translateCoords.translate[0];
translateY = direction == 'up' ? translateCoords.translate[1] + speed : translateCoords.translate[1] - speed;
}
scaleX = translateCoords.scale[0];
scaleY = translateCoords.scale[1];
scale = zoomListener.scale();
svgGroup.transition().attr("transform", "translate(" + translateX + "," + translateY + ")scale(" + scale + ")");
d3.select(domNode).select('g.node').attr("transform", "translate(" + translateX + "," + translateY + ")");
zoomListener.scale(zoomListener.scale());
zoomListener.translate([translateX, translateY]);
panTimer = setTimeout(function() {
pan(domNode, speed, direction);
}, 50);
}
}
// Define the zoom function for the zoomable tree
function zoom() {
svgGroup.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
// define the zoomListener which calls the zoom function on the "zoom" event constrained within the scaleExtents
var zoomListener = d3.behavior.zoom().scaleExtent([0.1, 3]).on("zoom", zoom);
// remove the previous svg if there
d3.select("svg").remove();
// define the baseSvg, attaching a class for styling and the zoomListener
var baseSvg = d3.select("#tree-container").append("svg")
.attr("width", viewerWidth)
.attr("height", viewerHeight)
.attr("class", "overlay")
.call(zoomListener)
.on("dblclick.zoom", null);
// The arrowmarker to be appended at the end of each path
// TODO Looks terrible (not currently used)
baseSvg.append("marker")
.attr("id", "markerArrow")
.attr("markerWidth", 4)
.attr("markerHeight", 4)
.attr("refY","2")
.attr("refX", "10")
.attr("orient", "auto")
.append("polygon")
.attr("points", "0,0 4,2 0,4")
.attr("style", "fill: #ccc");
// Helper functions for collapsing and expanding nodes.
function collapse(d) {
if (d.children) {
d._children = d.children;
d._children.forEach(collapse);
d.children = null;
}
}
function expand(d) {
if (d._children) {
d.children = d._children;
d.children.forEach(expand);
d._children = null;
}
}
var overCircle = function(d) {
selectedNode = d;
updateTempConnector();
};
var outCircle = function(d) {
selectedNode = null;
updateTempConnector();
};
// Toggle children function
function toggleChildren(d) {
if (d.children) {
d._children = d.children;
d.children = null;
} else if (d._children) {
d.children = d._children;
d._children = null;
}
return d;
}
// Toggle children on click.
function click(d) {
if (d3.event.defaultPrevented) return; // click suppressed
d = toggleChildren(d);
update(d);
}
function update(source) {
// Compute the new height, function counts total children of root node and sets tree height accordingly.
// This prevents the layout looking squashed when new nodes are made visible or looking sparse when nodes are removed
// This makes the layout more consistent.
var levelHeight = [1];
var childCount = function(level, n) {
if (n.children && n.children.length > 0) {
if (levelHeight.length <= level + 1) levelHeight.push(0);
levelHeight[level + 1] += n.children.length;
n.children.forEach(function(d) {
childCount(level + 1, d);
});
}
};
childCount(0, root);
var maxLevel = levelHeight.length+2;
// Compute the new tree layout.
var nodes = tree.nodes(root).reverse(),
links = tree.links(nodes);
// Set heights between levels based on maxLevel.
nodes.forEach(function(d) {
d.y = (d.depth * (viewerHeight/(maxLevel)));
});
// Update the nodes…
var node = svgGroup.selectAll("g.node")
.data(nodes, function(d) {
return d.id || (d.id = ++i);
});
// Enter any new nodes at the parent's previous position.
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) {
return "translate(" + source.x0 + "," + source.y0 + ")";
})
.on('click', click);
nodeEnter.append("rect")
.attr('class', 'nodeRect')
// Size of the rectangle/2
.attr("x", function(d){return -(d.name.length*5+10)/2})
.attr("y", -10)
.attr("width", 0)
.attr("height", 0)
.style("fill", function(d) {
return d._children ? "lightsteelblue" : "#fff";
});
nodeEnter.append("text")
.attr("y", 0)
.attr("dy", ".35em")
.attr('class', 'nodeText')
.attr("text-anchor", "middle")
.text(function(d) {
return d.name;
})
.style("fill-opacity", 0);
// Update the text to reflect whether node has children or not.
node.select('text')
.attr("y", 0)
.attr("text-anchor", "middle")
.text(function(d) {
return d.name;
});
node.select("rect.nodeRect")
.attr("width", function(d) {
// Adjust the size of the square according to the label
return d.children || d._children ? d.name.length*5+10 : 0;
})
.attr("height", function(d) {
return d.children || d._children ? 20 : 0;
})
.style("fill", function(d) {
return d._children ? "lightsteelblue" : "#fff";
});
// Transition nodes to their new position.
var nodeUpdate = node.transition()
.duration(duration)
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
// Fade the text in
nodeUpdate.select("text")
.style("fill-opacity", 1);
// Transition exiting nodes to the parent's new position.
var nodeExit = node.exit().transition()
.duration(duration)
.attr("transform", function(d) {
return "translate(" + source.x + "," + source.y + ")";
})
.remove();
nodeExit.select("circle")
.attr("r", 0);
nodeExit.select("text")
.style("fill-opacity", 0);
// Update the links…
var link = svgGroup.selectAll("path.link")
.data(links, function(d) {
return d.target.id;
});
// Enter any new links at the parent's previous position.
link.enter().insert("path", "g")
.attr("class", "link")
//TODO MARKERS LOOK TERRIBLE
// .attr("marker-end", "url(#markerArrow)")
.attr("d", function(d) {
var o = {x: source.x, y: source.y};
return diagonal({source: o,target: o});
});
// TODO doesn't work with the transition
// .attr("d", straightLine);
// Transition links to their new position.
link.transition()
.duration(duration)
.attr("d", diagonal);
// TODO doesn't work with the transition
// .attr("d", straightLine);
// Transition exiting nodes to the parent's new position.
link.exit().transition()
.duration(duration)
.attr("d", function(d) {
var o = {x: source.x, y: source.y};
return diagonal({source: o,target: o});
})
// TODO doesn't work with the transition
// .attr("d", straightLine)
.remove();
// Stash the old positions for transition.
nodes.forEach(function(d) {
d.x0 = d.x;
d.y0 = d.y;
});
}
// Append a group which holds all nodes and which the zoom Listener can act upon.
var svgGroup = baseSvg.append("g");
// Define the root
root = treeData;
root.x0 = viewerWidth / 2;
root.y0 = 0;
// Layout the tree initially and center on the root node.
update(root);
d3.select('g').attr("transform", "translate(0,20)");
}

View File

@@ -0,0 +1,43 @@
/* --- GF robust parser interface ------------------------------------------- */
var gfrobust = {}
gfrobust.url="http://www.grammaticalframework.org:41296/robust-parser/parse"
gfrobust.jsonurl="http://www.grammaticalframework.org:41296/robust-parser.cgi"
gfrobust.grammar="Parse" // the name of the grammar
gfrobust.targetlist=[] // do not use, exposed only for debugging
gfrobust.call=function(querystring,cont) {
http_get_json(gfrobust.jsonurl+querystring,cont)
}
// Translate a sentence to the given target language
gfrobust.translate=function(source,to,cont) {
var encsrc=encodeURIComponent(source)
if(encsrc.length<200) // match limit in runtime/c/utils/pgf-server.c
gfrobust.call("?sentence="+encsrc+"&to="+gfrobust.grammar+to,cont)
else cont("[GF robust parser: sentence too long]")
}
// Get the url of a parse tree image (SVG)
gfrobust.parsetree_url=function(source) {
return gfrobust.url+"?sentence="+encodeURIComponent(source)
}
// Get functions to test which source and target langauges are supported
gfrobust.get_support=function(cont) {
function ssupport(code) { return code=="Eng" }
function tsupport(code) { return gfrobust.targets[code] }
function init2(langstr) {
var ls=langstr.split(" "); // ls probably contains an empty string here
var langs=[], pre=gfrobust.grammar, n=pre.length
for(var i=0;i<ls.length;i++)
if(ls[i].substr(0,n)==pre) langs.push(ls[i].substr(n))
gfrobust.targetlist=langs
gfrobust.targets=toSet(langs)
cont(ssupport,tsupport)
}
if(gfrobust.target) cont(ssupport,tsupport)
else gfrobust.call("",init2) // retrieve list of supported target languages
}

View File

@@ -0,0 +1,167 @@
/* --- GF wide coverage translation interface ------------------------------- */
var gftranslate = {}
gftranslate.jsonurl="/robust/App16.pgf"
gftranslate.grammar="App" // the name of the grammar
gftranslate.documented_classes=
["N", "N2", "N3", "A", "A2", "V", "V2", "VV", "VS", "VQ", "VA", "V3", "V2V",
"V2S", "V2Q", "V2A", "Adv", "Prep"]
gftranslate.call=function(querystring,cont,errcont) {
http_get_json(gftranslate.jsonurl+querystring,cont,errcont)
}
function enc_langs(g,to) {
return Array.isArray(to)
? to.map(function(l){return g+l}).join("+")
: g+to
}
function unspace_translations(g,trans) {
var langs=[g+"Chi",g+"Jpn",g+"Tha"]
for(var i=0;i<trans.length;i++) {
var lins=trans[i].linearizations
if(lins) {
for(var j=0;j<lins.length;j++) {
var lin=lins[j]
if(elem(lin.to,langs)) {
//console.log(i,j,"space",lin.to,lin.text)
lin.text=lin.text.split(" ").join("")
//console.log(i,j,"unspace",lin.to,lin.text)
}
}
}
}
return trans
}
function length_limit(lang) {
switch(lang) {
case "Bul":
case "Chi":
case "Eng":
case "Swe":
return 500
default:
return 200
}
}
function check_limit(lang,source) {
var len=source.length, limit=length_limit(lang)
return len<=limit ? null : "sentense too long, "+len+">"+limit
}
// Translate a sentence
gftranslate.translate=function(source,from,to,start,limit,cont) {
var g=gftranslate.grammar
var lexer="&lexer=text"
if(from=="Chi") lexer="",source=source.split("").join(" ")
function errcont(text,code) { cont([{error:code+" "+text}]) }
function extract(result) {
cont(unspace_translations(g,result[0].translations))
}
var too_long=check_limit(from,source)
if(too_long) cont([{error:too_long}])
else
gftranslate.call("?command=c-translate&jsontree=true&input="
+encodeURIComponent(source)
+lexer+"&unlexer=text&from="+g+from+"&to="+enc_langs(g,to)
+"&start="+start+"&limit="+limit,extract,errcont)
}
// Translate a sentence word for word (if all else fails...)
gftranslate.wordforword=function(source,from,to,cont) {
var g=gftranslate.grammar
var lexer="&lexer=text"
if(from=="Chi") lexer="",source=source.split("").join(" ")
function errcont(text,code) { cont([{error:code+" "+text}]) }
function extract(result) {
cont(unspace_translations(g,result[0].translations))
}
var enc_to = enc_langs(g,to)
var too_long=check_limit(from,source)
if(too_long) cont([{error:too_long}])
else
gftranslate.call("?command=c-wordforword&input="
+encodeURIComponent(source)
+lexer+"&unlexer=text&from="+g+from+"&to="+enc_to
,extract,errcont)
}
// Get list of supported languages
gftranslate.waiting=[]
gftranslate.get_languages=function(cont,errcont) {
function init2(grammar_info) {
var ls=grammar_info.languages
gftranslate.grammar=grammar_info.name
var langs=[], pre=gftranslate.grammar, n=pre.length
for(var i=0;i<ls.length;i++)
if(ls[i].name.substr(0,n)==pre) langs.push(ls[i].name.substr(n))
gftranslate.targetlist=langs
var w=gftranslate.waiting
for (var i=0;i<w.length;i++) w[i].cont(langs)
gftranslate.waiting=[]
}
function init2error(text,status,ct) {
var w=gftranslate.waiting
for (var i=0;i<w.length;i++) {
var e=w[i].errcont
if(e) e(text,status,ct)
}
gftranslate.waiting=[]
}
if(gftranslate.targetlist) cont(gftranslate.targetlist)
else {
gftranslate.waiting.push({cont:cont,errcont:errcont})
if(gftranslate.waiting.length<2)
gftranslate.call("?command=c-grammar",init2,init2error)
}
}
// Get functions to test which source and target langauges are supported
gftranslate.get_support=function(cont,errcont) {
function support(code) { return gftranslate.targets[code] }
function init2(langs) {
gftranslate.targets=toSet(langs)
cont(support,support)
}
if(gftranslate.targets) cont(support,support)
else gftranslate.get_languages(init2,errcont)
}
// trans_text_quality : String -> {quality:String, text:String}
function trans_text_quality(text) {
var quality="default_quality"
switch(text[0]) {
case '+': text=text.substr(1).trimLeft(); quality="high_quality"; break;
case '*': text=text.substr(1).trimLeft(); quality="low_quality"; break;
}
return {quality:quality,text:text}
}
// find_to :: Lang -> [{to:Lang,...}] -> Int
function find_to(to,lins) {
for(var i=0;i<lins.length;i++)
if(lins[i].to==to) return i
return -1 // Hmm....
}
function trans_quality(r,to) {
var ix=to ? find_to(to,r.linearizations) : 0
if(ix<0) return null
else {
var text=r.linearizations[ix].text
if(r.prob==0) return {quality:"high_quality",text:text}
else if(r.prob<0) return {quality:"bad_quality",text:text}
else {
var t=trans_text_quality(text)
if(t.quality=="default_quality" && r.tree && r.tree[0]=="?")
t.quality="low_quality"
return t
}
}
}

View File

@@ -0,0 +1,180 @@
/* --- Grammar Manager object ----------------------------------------------- */
/*
This object stores the state for:
- grammar
- startcat
- languages
Hooks which actions can be hooked to:
- onload
- change_grammar
- change_startcat
- change_languages
*/
function GrammarManager(server,opts) {
var t = this;
/* --- Configuration ---------------------------------------------------- */
// default values
this.options = {
initial: {}
};
this.actions = {
onload: [
function(gm){ debug("default action: onload"); }
],
change_grammar: [
function(grammar){ debug("default action: change grammar"); }
],
change_startcat: [
function(startcat){ debug("default action: change startcat"); }
],
change_languages: [
function(languages){ debug("default action: change languages"); }
]
}
// Apply supplied options
if(opts) for(var o in opts) this.options[o]=opts[o];
/* --- Client state initialisation -------------------------------------- */
this.server = server;
this.grammar = null; // current grammar
this.grammars=[];
this.grammar_dirs=[];
this.startcat = null; // current startcat
this.languages = this.options.initial.languages || [];
// current languages (empty means all langs)
/* --- Main program, this gets things going ----------------------------- */
this.init=function(){
this.server.get_grammarlists(bind(this.onload,this));
}
this.init();
}
//
//GrammarManager.prototype.update_grammar_list=function(dir,grammar_names,dir_count) {
GrammarManager.prototype.onload=function(dir,grammar_names,dir_count) {
var t=this;
t.grammars=[];
t.grammar_dirs=[];
t.grammar_dirs.push(dir);
t.grammars=t.grammars.concat(grammar_names.map(function(g){return dir+g}));
var grammar0=t.options.initial.grammar || t.grammars[0];
t.change_grammar(grammar0);
// Execute hooked actions
t.run_actions("onload",dir,grammar_names,dir_count);
}
/* --- Registering / unregistering actions to hooks ------------------------- */
GrammarManager.prototype.register_action=function(hook,action) {
var hookring = this.actions[hook];
hookring.push(action);
}
GrammarManager.prototype.unregister_action=function(hook,action) {
var hookring = this.actions[hook];
for (var f=0; f < hookring.length; f++) {
if (hookring[f] == action) {
hookring = Array.remove(hookring, f);
}
}
}
// Execute actions for a given hook
// TODO: any number of arguments
GrammarManager.prototype.run_actions=function(hook,arg1,arg2,arg3) {
var acts = this.actions[hook];
for (f in acts) {
acts[f](arg1,arg2,arg3);
}
}
/* --- Grammar -------------------------------------------------------------- */
// API
GrammarManager.prototype.change_grammar=function(grammar_url) {
var t=this;
t.server.switch_to_other_grammar(grammar_url, function() {
t.server.grammar_info(function(grammar){
// Set internal state
t.grammar = grammar;
// Call internal functions
t.update_startcat(grammar);
t.update_language_list(grammar);
// Execute hooked actions
t.run_actions("change_grammar",grammar);
});
});
}
/* --- Start category ------------------------------------------------------- */
// Internal
// Sets default startcat for grammar
GrammarManager.prototype.update_startcat=function(grammar) {
var t=this;
var cats=grammar.categories;
var startcat0 = t.options.initial.startcat;
if (elem(startcat0, cats))
t.startcat = startcat0;
else
t.startcat = grammar.startcat;
}
// API
GrammarManager.prototype.change_startcat=function(startcat) {
var t = this;
// Set internal state
t.startcat = startcat;
// Call internal functions
// ...
// Execute hooked actions
t.run_actions("change_startcat",startcat);
}
/* --- Languages ------------------------------------------------------------ */
// Internal
// Sets default languages for grammar
GrammarManager.prototype.update_language_list=function(grammar) {
var t = this;
function langpart(conc,abs) { // langpart("FoodsEng","Foods") == "Eng"
return hasPrefix(conc,abs) ? conc.substr(abs.length) : conc;
}
// Replace the options in the menu with the languages in the grammar
var langs=grammar.languages;
for(var i=0; i<langs.length; i++) {
var ln=langs[i].name; // "PhrasebookEng"
if(!hasPrefix(ln,"Disamb")) {
var lp=langpart(ln,grammar.name); // "Eng"
if (elem(lp, t.options.initial.languages)) {
t.languages.push(ln);
}
}
}
}
// API
GrammarManager.prototype.change_languages=function(languages) {
var t = this;
// Set internal state
t.languages = languages;
// Call internal functions
// ...
// Execute hooked actions
t.run_actions("change_languages",languages);
}

View File

@@ -0,0 +1,70 @@
// Language names and ISO-639 codes (both 3-letter and 2-letter codes)
// See http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
var languages =
function() {
function lang1(namecode2) {
function lang(code,name,code2) {
return {code:code, name:name, code2:code2}
}
var nc=namecode2.split(":")
var name=nc[0]
var ws=name.split("/")
var code2=nc.length>1 ? nc[1] : ""
return ws.length==1 ? lang(name.substr(0,3),name,code2)
: lang(ws[0],ws[1],code2)
}
var ls
// [ISO-639-2 code "/"] language name ":" ISO 639-1 code
ls=["Afrikaans:af","Amharic:am","Arabic:ar","Bulgarian:bg","Catalan:ca",
"Chinese:zh","Czech:cs","Danish:da","Dutch:nl","English:en",
"Estonian:et","Finnish:fi","French:fr","German:de","Greek:el",
"Hebrew:he","Hindi:hi","Ina/Interlingua:ia",
"Icelandic:is","Gle/Irish:ga","Italian:it","Jpn/Japanese:ja",
"Latin:la","Lav/Latvian:lv","Mlt/Maltese:mt","Mongolian:mn",
"Nepali:ne","Norwegian:nb","Pes/Persian:fa","Polish:pl",
"Portuguese:pt","Pnb/Punjabi:pa",
"Ron/Romanian:ro","Russian:ru","Snd/Sindhi:sd","Spanish:es",
"Swedish:sv","Thai:th","Turkish:tr","Urdu:ur"]
// GF uses nonstd 3-letter codes? Pes/Persian:fa, Pnb/Punjabi:pa
return map(lang1,ls)
}()
var langname={}
var langcode={}
var langcode2={}
var langcode3={}
for(var i in languages) {
langname[languages[i].code]=languages[i].name
langcode[languages[i].name]=languages[i]
langcode2[languages[i].code]=languages[i].code2
langcode3[languages[i].code2]=languages[i].code
}
function concname(code) { return langname[code] || code; }
function alangcode(code) { return langcode2[code] || code; }
// Add a country code to the language code
function add_country(code) {
switch(code) {
case "en": return "en-US" // "en-scotland" // or "en-GB"
case "sv": return "sv-SE"
case "fr": return "fr-FR"
case "de": return "de-DE"
case "fi": return "fi-FI"
case "zh": return "zh-CN"
case "hi": return "hi-IN"
case "es": return "es-ES"
case "it": return "it-IT"
case "bg": return "bg-BG" // ?
case "da": return "da-DK"
case "nb": return "nb-NO"
case "nl": return "nl-NL"
case "ja": return "ja-JP"
case "ro": return "ja-RO"
case "el": return "el-GR"
case "th": return "th-TH"
// ...
default: return code
}
}

View File

@@ -0,0 +1,60 @@
// See http://diveintohtml5.info/storage.html
function supports_html5_storage() {
try {
return 'localStorage' in window && window['localStorage'] !== null;
} catch (e) {
return false;
}
}
var fakedLocalStorage = [] // a shared substitute for persistent localStorage
// An interface to localStorage, to store JSON data under a unique prefix
function appLocalStorage(appPrefix,privateStorage) {
function parse(s,def) {
try { return JSON.parse(s) } catch(e) { return def }
}
function methods(storage) {
return {
get: function (name,def) {
var id=appPrefix+name
return parse(storage[id]||"",def);
},
put: function (name,value) {
var id=appPrefix+name;
storage[id]=JSON.stringify(value);
},
remove: function(name) {
var id=appPrefix+name;
delete storage[id]
},
ls: function(prefix) {
var pre=appPrefix+(prefix||"")
var files=[]
for(var i in storage)
if(hasPrefix(i,pre)) files.push(i.substr(pre.length))
files.sort()
return files
},
get count() { return this.get("count",0); },
set count(v) { this.put("count",v); }
}
}
function get_html5_storage() {
try {
return 'localStorage' in window
&& window['localStorage']
|| fakedLocalStorage
} catch (e) {
return fakedLocalStorage; // fake it
}
}
return methods(privateStorage || get_html5_storage())
}

View File

@@ -0,0 +1,80 @@
/* --- Grammar access object ------------------------------------------------ */
function pgf_online(options) {
var server = {
// State variables (private):
grammars_url: "/grammars/",
other_grammars_urls: [],
grammar_list: null,
current_grammar_url: null,
// Methods:
switch_grammar: function(grammar_url,cont) {
this.current_grammar_url=this.grammars_url+grammar_url;
if(cont) cont();
},
add_grammars_url: function(grammars_url,cont) {
this.other_grammars_urls.push(grammars_url);
if(cont) cont();
},
switch_to_other_grammar: function(grammar_url,cont) {
this.current_grammar_url=grammar_url;
if(cont) cont();
},
get_grammarlist: function(cont,err) {
if(this.grammar_list) cont(this.grammar_list)
else http_get_json(this.grammars_url+"grammars.cgi",cont,err);
},
get_grammarlists: function(cont,err) { // May call cont several times!
var ds=this.other_grammars_urls;
var n=1+ds.length;
function pair(dir) {
return function(grammar_list){cont(dir,grammar_list,n)}
}
function ignore_error(err) { console.log(err) }
this.get_grammarlist(pair(this.grammars_url),err)
for(var i in ds)
http_get_json(ds[i]+"grammars.cgi",pair(ds[i]),ignore_error);
},
pgf_call: function(cmd,args,cont,err) {
var url=this.current_grammar_url+"?command="+cmd+encodeArgs(args)
http_get_json(url,cont,err);
},
get_languages: function(cont,err) {
this.pgf_call("grammar",{},cont,err);
},
grammar_info: function(cont,err) {
this.pgf_call("grammar",{},cont,err);
},
get_random: function(args,cont,err) { // cat, limit
args.random=Math.random(); // side effect!!
this.pgf_call("random",args,cont,err);
},
linearize: function(args,cont,err) { // tree, to
this.pgf_call("linearize",args,cont,err);
},
complete: function(args,cont,err) { // from, input, cat, limit
this.pgf_call("complete",args,cont,err);
},
parse: function(args,cont,err) { // from, input, cat
this.pgf_call("parse",args,cont,err);
},
translate: function(args,cont,err) { // from, input, cat, to
this.pgf_call("translate",args,cont,err);
},
translategroup: function(args,cont,err) { // from, input, cat, to
this.pgf_call("translategroup",args,cont,err);
},
browse: function(args,cont,err) { // id, format
if(!args.format) args.format="json"; // sife effect!!
this.pgf_call("browse",args,cont,err);
}
};
for(var o in options) server[o]=options[o];
if(server.grammar_list && server.grammar_list.length>0)
server.switch_grammar(server.grammar_list[0]);
return server;
}

View File

@@ -0,0 +1,431 @@
/* --- Accessing document elements ------------------------------------------ */
function element(id) {
return document.getElementById(id);
}
/* --- JavaScript tricks ---------------------------------------------------- */
// To be able to use object methods that refer to "this" as callbacks
// See section 3.3 of https://github.com/spencertipping/js-in-ten-minutes/raw/master/js-in-ten-minutes.pdf
function bind(f, this_value) {
return function () {return f.apply (this_value, arguments)};
};
// Implement Array.isArray for older browsers that lack it.
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/isArray
if(!Array.isArray) {
Array.isArray = function (arg) {
return Object.prototype.toString.call(arg) == '[object Array]';
};
}
// Create a clone of an array
// http://davidwalsh.name/javascript-clone-array
if(!Array.clone) {
Array.clone = function(arg) {
return arg.slice(0);
};
}
// Array Remove - By John Resig (MIT Licensed)
// http://ejohn.org/blog/javascript-array-remove/if(!Array.remove) {
if(!Array.remove) {
Array.remove = function(arg, from, to) {
var rest = arg.slice((to || from) + 1 || arg.length);
arg.length = from < 0 ? arg.length + from : from;
return arg.push.apply(arg, rest);
};
}
/* --- JSONP ---------------------------------------------------------------- */
// Inspired by the function jsonp from
// http://www.west-wind.com/Weblog/posts/107136.aspx
// See also http://niryariv.wordpress.com/2009/05/05/jsonp-quickly/
// http://en.wikipedia.org/wiki/JSONP
function jsonp(url,callback)
{
if (url.indexOf("?") > -1)
url += "&jsonp="
else
url += "?jsonp="
url += callback;
//url += "&" + new Date().getTime().toString(); // prevent caching
var script = empty("script");
script.setAttribute("src",url);
script.setAttribute("type","text/javascript");
document.body.appendChild(script);
}
var json = {next:0};
// Like jsonp, but instead of passing the name of the callback function, you
// pass the callback function directly, making it possible to use anonymous
// functions.
function jsonpf(url,callback,errorcallback)
{
var name="callback"+(json.next++);
json[name]=function(x) { delete json[name]; callback(x); }
jsonp(url,"json."+name);
}
/* --- AJAX ----------------------------------------------------------------- */
function GetXmlHttpObject(handler)
{
var objXMLHttp=null
if (window.XMLHttpRequest)
{
// See http://www.w3.org/TR/XMLHttpRequest/
// https://developer.mozilla.org/en/xmlhttprequest
objXMLHttp=new XMLHttpRequest()
}
else if (window.ActiveXObject)
{
objXMLHttp=new ActiveXObject("Microsoft.XMLHTTP")
}
return objXMLHttp
}
function ajax_http(method,url,body,contenttype,callback,errorcallback) {
var http=GetXmlHttpObject()
if (!http) {
var errortext="Browser does not support HTTP Request";
if(errorcallback) errorcallback(errortext,500)
else alert(errortext)
}
else {
function statechange() {
if (http.readyState==4 || http.readyState=="complete") {
if(http.status<300) callback(http.responseText,http.status);
else if(errorcallback)
errorcallback(http.responseText,http.status,
http.getResponseHeader("Content-Type"));
else alert("Request for "+url+" failed: "
+http.status+" "+http.statusText);
}
}
http.onreadystatechange=statechange;
http.open(method,url,true)
if (contenttype != null) {
http.setRequestHeader("Content-Type", contenttype)
}
http.send(body)
}
return http
}
function ajax_http_get(url,callback,errorcallback) {
ajax_http("GET",url,null,null,callback,errorcallback)
}
function ajax_http_post(url,formdata,callback,errorcallback) {
ajax_http("POST",url,formdata,null,callback,errorcallback)
// See https://developer.mozilla.org/En/XMLHttpRequest/Using_XMLHttpRequest#Using_FormData_objects
}
// JSON via AJAX
function ajax_http_get_json(url,cont,errorcallback) {
ajax_http_get(url, with_json(cont,errorcallback), errorcallback);
}
function ajax_http_post_json(url,formdata,cont,errorcallback) {
ajax_http_post(url, formdata, with_json(cont,errorcallback), errorcallback);
}
function ajax_http_post_querystring_json(url,querystring,cont,errorcallback) {
ajax_http("POST",url,querystring,"application/x-www-form-urlencoded",with_json(cont,errorcallback),errorcallback);
}
function with_json(cont,errorcallback) {
return function(txt){
if(txt) {
try {
var json=eval("("+txt+")")
} catch (e) {
if(errorcallback)
errorcallback("JSON parsing problem",500,"text/plain")
return
}
cont(json);
}
else {
if(errorcallback)
errorcallback("Empty response form server (crash?)",500,"text/plain")
}
}
}
function sameOrigin(url) {
var a=empty("a");
a.href=url; // converts to an absolute URL
return hasPrefix(a.href,location.protocol+"//"+location.host+"/");
}
/*
// Use AJAX when possible, fallback to JSONP
function http_get_json(url,cont,errorcallback) {
if(sameOrigin(url)) ajax_http_get_json(url,cont,errorcallback);
else jsonpf(url,cont,errorcallback);
}
*/
// For better error handling, always use AJAX, don't fallback to JSONP
// Cross-origin requests are allowed by the PGF service and are supported in
// all modern browsers.
// See http://en.wikipedia.org/wiki/Cross-origin_resource_sharing
function http_get_json(url,cont,errorcallback) {
ajax_http_get_json(url,cont,errorcallback);
}
/* --- URL construction ----------------------------------------------------- */
function encodeArgs(args) {
var q=""
for(var arg in args)
if(args[arg]!=undefined)
q+="&"+arg+"="+encodeURIComponent(args[arg]);
return q;
}
/* --- HTML construction ---------------------------------------------------- */
function text(s) { return document.createTextNode(s); }
function node(tag,as,ds) {
var n=attr(as,document.createElement(tag));
if(ds) for(var i in ds) n.appendChild(ds[i]);
return n;
}
function attr(as,n) {
for(var a in as) n.setAttribute(a,as[a]);
return n
}
function empty(tag,name,value) {
var el=node(tag,{},[])
if(name && value) el.setAttribute(name,value);
return el;
}
function empty_id(tag,id) { return empty(tag,"id",id); }
function empty_class(tag,cls) { return empty(tag,"class",cls); }
function div_id(id,cs) { return node("div",{id:id},cs); }
function span_id(id) { return empty_id("span",id); }
function wrap(tag,contents) {
return node(tag,{},Array.isArray(contents) ? contents : [contents]);
}
function wrap_class(tag,cls,contents) {
return node(tag,{"class":cls},
contents ? Array.isArray(contents) ?
contents : [contents] : [])
}
function span_class(cls,contents) { return wrap_class("span",cls,contents); }
function div_class(cls,contents) { return wrap_class("div",cls,contents); }
function p(contents) { return wrap("p",contents); }
function dt(contents) { return wrap("dt",contents); }
function dd(contents) { return wrap("dd",contents); }
function li(contents) { return wrap("li",contents); }
function th(contents) { return wrap("th",contents); }
function td(contents) { return wrap("td",contents); }
function tr(cells) { return wrap("tr",cells); }
function button(label,action,key) {
var el=node("input",{"type":"button","value":label},[]);
if(typeof action=="string") el.setAttribute("onclick",action);
else el.onclick=action;
if(key) el.setAttribute("accesskey",key);
return el;
}
function option(label,value) {
return node("option",{"value":value},[text(label)]);
}
function hidden(name,value) {
return node("input",{type:"hidden",name:name,value:value},[])
}
function tda(cs) { return node("td",{},cs); }
function img(src) { return empty("img","src",src); }
function title(t,n) { return attr({title:t},n) }
/* --- Document modification ------------------------------------------------ */
function clear(el) { replaceInnerHTML(el,""); }
function replaceInnerHTML(el,html) { if(el) el.innerHTML=html; }
function replaceChildren(el,newchild) { clear(el); el.appendChild(newchild); }
function appendChildren(el,ds) {
for(var i in ds) el.appendChild(ds[i]);
return el;
}
function replaceNode(el,ref) {
ref.parentNode.replaceChild(el,ref)
}
function insertFirst(parent,child) {
parent.insertBefore(child,parent.firstChild);
}
function insertBefore(el,ref) { ref.parentNode.insertBefore(el,ref); }
function insertAfter(el,ref) {
ref.parentNode.insertBefore(el,ref.nextSibling);
}
function toggleHidden(el) {
if (el.classList.contains("hidden"))
el.classList.remove("hidden")
else
el.classList.add("hidden")
}
// Update the selected options in a menu that allow multiple selections
function updateMultiMenu(menu,selection) {
var set=toSet(selection)
var os=menu.options
for(var i=0;i<os.length;i++)
os[i].selected=set[os[i].value] || false
}
/* --- Document data extraction --------------------------------------------- */
// List the selected options in a menu that allows multiple selections
function multiMenuSelections(menu) {
var selection=[]
var os=menu.options;
for(var i=0;i<os.length;i++)
if(os[i].selected) selection.push(os[i].value)
return selection
}
/* --- Debug ---------------------------------------------------------------- */
function debug(s) {
var d=element("debug");
if(d) d.appendChild(text(s+"\n"))
}
function show_props(obj, objName) {
var result = "";
for (var i in obj) {
result += objName + "." + i + " = " + obj[i] + "<br>";
}
return result;
}
function field_names(obj) {
var result = "";
for (var i in obj) {
result += " " + i;
}
return result;
}
/* --- Data manipulation ---------------------------------------------------- */
function swap(a,i,j) { // Note: this doesn't work on strings.
var tmp=a[i];
a[i]=a[j];
a[j]=tmp;
return a;
}
function sort(a) {
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Array/sort
return a.sort();
/* // Note: this doesn't work on strings.
for(var i=0;i<a.length-1;i++) {
var min=i;
for(var j=i+1;j<a.length;j++)
if(a[j]<a[min]) min=j;
if(min!=i) swap(a,i,min);
}
return a;
*/
}
function filter(p,xs) {
var ys=[];
for(var i=0;i<xs.length;i++)
if(p(xs[i])) ys[ys.length]=xs[i];
return ys;
}
function implode(cs) { // array of strings to string
/*
var s="";
for(var i=0;i<cs.length;i++)
s+=cs[i];
return s;
*/
return cs.join("");
}
function hasPrefix(s,pre) { return s.substr(0,pre.length)==pre; }
function commonPrefix(s1,s2) {
for(var i=0;i<s1.length && i<s2.length && s1[i]==s2[i];i++);
return s1.substr(0,i);
}
/*
function all(p,xs) {
for(var i=0;i<xs.length;i++)
if(!p(xs[i])) return false;
return true;
}
*/
function map(f,xs) {
var ys=[];
for(var i=0;i<xs.length;i++) ys[i]=f(xs[i]);
return ys;
}
// map in continuation passing style
function mapc(f,xs,cont) { mapc_from(f,xs,0,[],cont); }
function mapc_from(f,xs,i,ys,cont) {
if(i<xs.length)
f(xs[i],function(y){ys[i]=y;mapc_from(f,xs,i+1,ys,cont)});
else
cont(ys);
}
function overlaps(as,bs) {
for(var i=0;i<as.length;i++)
if(elem(as[i],bs)) return true;
return false;
}
function elem(a,as) {
if (!as) return false;
for(var i=0;i<as.length;i++)
if(a==as[i]) return true;
return false;
}
function shuffle(a) {
for(i=0;i<a.length;i++) swap(a,i,Math.floor(Math.random()*a.length))
return a;
}
// Convert an array of strings to a set (for quick & easy membership tests)
function toSet(a) {
var set={}
for(var i=0;i<a.length;i++) set[a[i]]=true
return set
}

539
src/compiler/www/js/wc.js Normal file
View File

@@ -0,0 +1,539 @@
/* --- Wide Coverage Translation Demo web app ------------------------------- */
var wc={}
wc.selected_cnls=[] // list of grammar names
wc.cnls={} // maps grammars names to {pgf_online:...,grammar_info:{...}}
wc.f=document.forms[0]
wc.o=element("output")
wc.e=element("extra")
wc.i=element("grammarinfo")
wc.p=element("pick")
wc.grammarbox=element("grammarbox")
wc.os=[] /* output segment list
[{input,text:String; from,to::Lang;
target:Node;
rs::[TranslationResults];
current_pick::Int // index into rs or -1
}] */
wc.cache={} // output segment cache, indexed by source text
wc.translating=""
wc.delayed_translate=function() {
function restart(){
if(wc.f.input.value!=wc.translating) wc.translate()
var h=wc.f.input.scrollHeight,bh=document.body.clientHeight
if(h>bh) h=bh
if(wc.f.input.clientHeight<h) wc.f.input.style.height=h+15+"px"
}
if(wc.timer) clearTimeout(wc.timer);
wc.timer=setTimeout(restart,500)
}
wc.clear=function() {
wc.f.input.value=""
wc.f.input.style.height=""
clear(wc.o)
wc.delayed_translate()
}
wc.save=function() {
if(wc.local) {
var f=wc.f
wc.local.put("from",f.from.value)
wc.local.put("to",f.to.value)
wc.local.put("input",f.input.value)
wc.local.put("colors",f.colors.checked)
wc.local.put("cnls",wc.selected_cnls)
}
}
wc.load=function() {
if(wc.local) {
var f=wc.f
f.input.value=wc.local.get("input",f.input.value)
f.from.value=wc.local.get("from",f.from.value)
f.to.value=wc.local.get("to",f.to.value)
f.colors.checked=wc.local.get("colors",f.colors.checked)
wc.selected_cnls=wc.local.get("cnls",wc.selected_cnls)
wc.colors()
wc.delayed_translate()
}
}
wc.translate=function(redo) {
// redo=true => discard translated segment cache and resubmit translation
// requests to the server (browser cache may still be used)
var f=wc.f, e=wc.e, p=wc.p
/*
function disable(yes) {
f.translate.disabled=yes
f.to.disabled=yes
if(f.swap) f.swap.disabled=yes
}
*/
function split_punct(s) {
return s.split(/([.!?]+[ \t\n]+|\n\n+|[ \t\n]*[-•*+#]+[ \t\n]+)/)
}
function find_pick(rs) {
for(var i=0;i<rs.length && !rs[i].t;i++)
;
return i
}
function translate_segment(so) { // so = segment output
so.rs=[] // list of alternative translations for this segment
so.current_pick= -1 // index of currently selected alternative
function show_error(msg) {
//if(e) e.innerHTML="<span class=low_quality>Translation problem: "+msg+"</span>"
//else
{
replaceChildren(so.target,text("["+msg+"]"))
so.target.className="error"
}
//disable(false)
}
function show_pick(i) { return function() { show_trans(i); return false; } }
function show_picks() {
clear(p)
for(var i=0;i<so.rs.length;i++) {
if(so.rs[i].t) {
var pick=text(i+1) // +"⃝"
if(i!=so.current_pick) {
var pick=node("a",{href:"#"},[pick])
pick.onclick=pick.onmouseover=show_pick(i)
}
var q=so.rs[i].t.quality
p.appendChild(text(" "))
p.appendChild(span_class("pick "+q,pick))
}
}
if(!so.got_more) p.appendChild(text("..."))
/*
p.appendChild(wrap_class("small","pick",
node("a",{href:wc.google_translate_url(),
target:"google_translate"},
[text("Google Translate")])))
*/
}
function treetext(tree) {
function inflect(w,wcls) {
function show_inflections(lins) {
if(wc.e2) wc.e2.innerHTML=lins[0].text
}
function get_inflections() {
var tree="MkDocument+%22%22+(Inflection"+wcls+"+"+w+")+%22%22"
var l=gftranslate.grammar+f.to.value
gftranslate.call("?command=c-linearize&to="+l+"&tree="+tree,show_inflections)
}
var wn=wrap_class("span","inflect",text(w))
if(wc.e2) wn.onclick=get_inflections
return wn
}
function word(w) {
var ps=w.split("_")
var n=ps.length
return ps.length>1 && elem(ps[n-1],gftranslate.documented_classes)
? inflect(w,ps[n-1]) : text(w)
}
return tree.split(/([ ()]+)/).map(word)
}
function show_more() {
wc.selected=so
var r=so.rs[so.current_pick]
var prob=r.prob<=0 ? "" : r.prob || ""
if(e) {
clear(e)
var speak_from=speech_buttons(so.from,"",so.input)
var speak_to=speech_buttons(so.to,"",so.text)
speak_to.className=speak_from.className="speech_buttons"
e.appendChild(wrap("div",[speak_from,
text(so.input+" → "+so.text),
speak_to]))
e.appendChild(wrap("div",text(prob)))
if(r.tree) {
wc.e2=node("div",{id:"tree-container","class":"e2"})
e.appendChild(wrap("span",treetext(r.tree)))
/*
var g=gftranslate.jsonurl
var u="format=svg&tree="+encodeURIComponent(r.tree)
var from="&from="+r.grammar+f.to.value
r.imgurls=[g+"?command=c-abstrtree&"+u,
g+"?command=c-parsetree&"+u+from]
if(!r.img) {
r.img=node("img",{src:r.imgurls[0]},[])
r.img_ix=0
r.img.onclick=function() {
r.img_ix=1-r.img_ix
r.img.src=r.imgurls[r.img_ix]
}
}
else if(r.img.src!=r.imgurls[r.img_ix]) // language change?
r.img.src=r.imgurls[r.img_ix]
wc.e2.appendChild(r.img)
*/
e.appendChild(wc.e2)
if(window.d3 && window.d3Tree) window.d3Tree(wc.bracketsToD3(r.jsontree))
}
}
if(wc.p /*&& so.rs.length>1*/) show_picks()
//if(f.speak.checked) wc.speak(t.text,f.to.value)
if(!so.got_more) {
so.got_more=true
if(so.rs.length<10)
trans(so.input,so.rs.length,10-so.rs.length)
}
}
so.target.onclick=show_more
function show_trans(i) {
var r=so.rs[i]
if(!r.t) {
i=find_pick(so.rs)
r=so.rs[i]
}
if(r && r.t) {
replaceChildren(so.target,text(r.t.text))
so.text=r.t.text
so.target.className=r.t.quality
so.current_pick=i
if(wc.selected==so) show_more()
}
}
function showit(r,grammar) {
r.grammar=grammar
r.t=trans_quality(r,grammar+f.to.value)
so.rs.push(r)
var j=so.rs.length-1
if(so.current_pick<0 || so.current_pick==j) show_trans(j)
else if(wc.selected==so) show_picks()
//disable(false)
}
function word_for_word(text,cont) {
function step3(tra) {
if(tra.length>=1) {
var r=tra[0]
r.prob = -1
if(r.linearizations) showit(r,gftranslate.grammar)
else if(r.error!=undefined)
show_error(r.error)
}
else if(so.rs.length==0)
show_error("Unable to translate")
}
gftranslate.wordforword(text,f.from.value,wc.languages || f.to.value,step3)
}
function trans(text,i,count) {
function step3(tra) {
if(tra.length>=1) {
var r=tra[0]
if(r.error!=undefined) {
if(i==0 && so.rs.length==0) {
//show_error(r.error)
word_for_word(text)
}
}
else {
function cmp(a,b) { return a.prob-b.prob; }
tra=tra.sort(cmp)
for(var ti=0;ti<tra.length;ti++) {
var r=tra[ti]
if(r.linearizations) showit(r,gftranslate.grammar)
//else show_error("no linearizations")
}
}
}
else if(i==0 && so.rs.length==0)
show_error("Unable to translate")
}
gftranslate.translate(text,f.from.value,wc.languages || f.to.value,i,count,step3)
}
function step2(text) { trans(text,0,10) }
function step2cnl(text,ix) {
function step3cnl(results) {
var trans=results[0].translations
if(trans && trans.length>=1) {
for(var i=0;i<trans.length;i++) {
var r=trans[i]
r.prob=0
showit(r,cnl)
}
}
step2cnl(text,ix+1)
}
if(ix<wc.selected_cnls.length) {
var g=wc.cnls[wc.selected_cnls[ix]]
var gi=g.grammar_info
var langs=gi.languages.map(function(l) { return l.name; })
var cnl=gi.name
var from=cnl+f.from.value,to=cnl+f.to.value
if(elem(from,langs) && elem(to,langs))
g.pgf_online.translate({from:from,
//to:to,
lexer:"text",unlexer:"text",
jsontree:true,input:text},
step3cnl,
function(){step2cnl(text,ix+1)})
else step2cnl(text,ix+1)
}
else step2(text)
}
if(wc.selected_cnls) step2cnl(so.input,0)
else step2(so.input)
}
function change_segment_to(so,to) {
var rs=so.rs
if(rs) {
for(var i=0;i<rs.length;i++)
rs[i].t=trans_quality(rs[i],rs[i].grammar+to)
var i=so.current_pick
if(!rs[i].t) {
i=find_pick(rs)
//console.log("Change pick",so.current_pick,i)
so.current_pick=i
clear(p)
wc.selected=null
}
var r=rs[i]
so.text=r.t.text
replaceChildren(so.target,text(r.t.text))
so.target.className=r.t.quality
}
so.to=to
}
//disable(true)
clear(wc.o)
clear(e)
clear(p)
var old_selected=wc.selected
wc.selected=null
if(redo) {
wc.cache={}
var old=wc.cache
}
else {
var old=wc.cache
for(var i=0;i<wc.os.length;i++) old[wc.os[i].input]=wc.os[i]
// could also keep all copies if the same text occurs more than once...
wc.os=[]
}
wc.translating=f.input.value
var is=split_punct(wc.translating+"\n")
for(var i=0;i<is.length;i++) {
var same=old[is[i]]
if(same /*&& same.to==f.to.value*/ && same.from==f.from.value) {
// reuse an unchanged segment
wc.os[i]=same
wc.o.appendChild(same.target)
if(same==old_selected) wc.selected=same
delete old[is[i]] // can't use the same node twice
if(same.to!=f.to.value) change_segment_to(same,f.to.value)
}
else {
// create a new output segment
var o=wc.os[i]={input:is[i],text:is[i],
from:f.from.value,to:f.to.value}
if(i&1) { // punctuation
o.target=span_class("punct",text(is[i]))
wc.o.appendChild(o.target)
}
else { // text segment to be translated
o.target=span_class("placeholder",text(is[i]))
wc.o.appendChild(o.target)
translate_segment(o)
}
}
}
wc.save()
return false;
}
wc.speak=function(text,lang) {
if(wc.speech) {
var u=new SpeechSynthesisUtterance(text)
u.lang=add_country(alangcode(lang))
speechSynthesis.cancel()
speechSynthesis.speak(u)
}
}
wc.colors=function() {
document.body.className=wc.f.colors.checked ? "colors" : ""
wc.local.put("colors",wc.f.colors.checked)
}
wc.swap=function() {
var f=wc.f
function txt(so) { return so.text }
f.input.value=wc.os.map(txt).join("").trimRight()
var from=f.from.value
f.from.value=f.to.value
f.to.value=from
wc.translate()
}
wc.google_translate_url=function() {
return "http://translate.google.com/"
+"#"+alangcode(wc.f.from.value)
+"/"+alangcode(wc.f.to.value)
+"/"+encodeURIComponent(wc.f.input.value)
}
wc.try_google=function() {
var w=window.open(wc.google_translate_url(),
"google_translate")
w.focus()
}
wc.bracketsToD3=function(bs) {
if(bs.token) return {name:bs.token}
else if(bs.other) return {name:bs.other}
else if(bs.fun) {
var t={name:bs.fun}
if(bs.children/* && bs.children.length>0*/)
t.children=bs.children.map(wc.bracketsToD3)
return t
}
else return {name:"??"}
}
// Update language selection menus with the languages supported by the grammar
wc.init_languages=function () {
function init2(langs) {
replaceInnerHTML(wc.i,"Enter text to translate above")
wc.languages=langs
var langset=toSet(langs)
function update_menu(m) {
var l=m.value
clear(m)
for(var i=0;i<langs.length;i++)
m.appendChild(option(concname(langs[i]),langs[i]))
if(langset[l]) m.value=l
}
update_menu(wc.f.from)
update_menu(wc.f.to)
}
function initerror(errortext,status,ct) {
var msg = status==404 ? "The wide cover translation grammar was not found on the server" : "Server problem "+status
replaceChildren(wc.i,text(msg))
if(wc.i) wc.i.className="error"
}
replaceInnerHTML(wc.i,"Loading the wide coverage translation grammar, please wait...")
gftranslate.get_languages(init2,initerror)
}
wc.init_speech=function() {
var speak=element("speak")
if(speak) {
wc.speech=window.speechSynthesis && window.speechSynthesis.getVoices().length>0
if(wc.speech) speak.style.display="inline"
}
}
wc.show_grammarbox=function() {
wc.grammarbox.parentNode.style.display="block";
}
wc.hide_grammarbox=function() {
wc.grammarbox.parentNode.style.display="";
clear(wc.grammarbox)
}
wc.init_cnl=function(grammar) {
var g
if(wc.cnls[grammar]) g=wc.cnls[grammar]
else g=wc.cnls[grammar]={}
g.pgf_online=pgf_online({})
g.pgf_online.switch_grammar(grammar)
g.pgf_online.grammar_info(function(info){g.grammar_info=info})
}
wc.init_cnls=function() {
var gs=wc.selected_cnls
for(var i=0;i<gs.length;i++) wc.init_cnl(gs[i])
}
wc.select_grammars=function() {
function done() {
wc.hide_grammarbox()
var gs=[]
var glist=list.children
for(var i=0;i<glist.length;i++)
if(glist[i].cb.checked) gs.push(glist[i].grammar)
wc.selected_cnls=gs
wc.init_cnls()
wc.local.put("cnls",wc.selected_cnls)
wc.translate(true)
}
function cancel() {
wc.hide_grammarbox()
}
function remove(x,xs) {
function other(y) { return y!=x; }
return filter(other,xs)
}
function checkbox(grammar,checked) {
var vb=node("input",{type:"checkbox"})
vb.checked=checked
return vb
}
function grammar_pick(grammar,checked) {
var cb=checkbox(grammar,checked)
var p=[cb,text(" "+grammar.split(".pgf")[0])]
var dt=node("dt",{class:"grammar_pick"},p)
dt.cb=cb
dt.grammar=grammar
return dt
}
function show_list(grammars) {
var sg=wc.selected_cnls
for(var i=0;i<sg.length;i++) {
if(elem(sg[i],grammars))
list.appendChild(grammar_pick(sg[i],true))
else
remove(sg[i],wc.selected_cnls)
}
for(var i=0;i<grammars.length;i++)
if(!elem(grammars[i],wc.selected_cnls))
list.appendChild(grammar_pick(grammars[i],false))
}
clear(wc.grammarbox)
wc.grammarbox.appendChild(wrap("h2",[button("X",cancel),text("Select which domain-specific grammars to use")]))
wc.grammarbox.appendChild(text("These grammars are tried before the wide-coverage grammar. They can give higher quality translations within their respective domains."))
var list=empty("dl")
wc.grammarbox.appendChild(list)
wc.grammarbox.appendChild(button("OK",done))
wc.grammarbox.appendChild(button("Cancel",cancel))
wc.show_grammarbox()
wc.pgf_online.get_grammarlist(show_list)
}
wc.initialize=function(grammar_name,grammar_url) {
if(grammar_name && grammar_url) {
gftranslate.grammar=grammar_name
gftranslate.jsonurl=grammar_url
}
wc.init_languages()
//init_speech()
setTimeout(wc.init_speech,500) // A hack for Chrome.
wc.pgf_online=pgf_online({});
wc.local=appLocalStorage("gf.wc."+gftranslate.grammar+".")
wc.load()
wc.init_cnls()
initialize_sorting(["DT"],["grammar_pick"])
wc.f.input.focus()
}