mirror of
https://github.com/GrammaticalFramework/gf-core.git
synced 2026-06-21 09:16:13 -06:00
move gf.cabal and all compiler dependent files into src/compiler
This commit is contained in:
314
src/compiler/www/js/d3Tree.js
vendored
Normal file
314
src/compiler/www/js/d3Tree.js
vendored
Normal 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)");
|
||||
}
|
||||
43
src/compiler/www/js/gfrobust.js
Normal file
43
src/compiler/www/js/gfrobust.js
Normal 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
|
||||
}
|
||||
167
src/compiler/www/js/gftranslate.js
Normal file
167
src/compiler/www/js/gftranslate.js
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
180
src/compiler/www/js/grammar_manager.js
Normal file
180
src/compiler/www/js/grammar_manager.js
Normal 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);
|
||||
}
|
||||
|
||||
70
src/compiler/www/js/langcode.js
Normal file
70
src/compiler/www/js/langcode.js
Normal 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
|
||||
}
|
||||
}
|
||||
60
src/compiler/www/js/localstorage.js
Normal file
60
src/compiler/www/js/localstorage.js
Normal 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())
|
||||
}
|
||||
80
src/compiler/www/js/pgf_online.js
Normal file
80
src/compiler/www/js/pgf_online.js
Normal 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;
|
||||
}
|
||||
431
src/compiler/www/js/support.js
Normal file
431
src/compiler/www/js/support.js
Normal 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
539
src/compiler/www/js/wc.js
Normal 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()
|
||||
}
|
||||
Reference in New Issue
Block a user