diff --git a/src/www/translator/translator.css b/src/www/translator/translator.css index 39763e3b6..277e964c8 100644 --- a/src/www/translator/translator.css +++ b/src/www/translator/translator.css @@ -50,10 +50,11 @@ td.options { padding: 1ex 1em; } vertical-align: baseline; } td.options > div, td.actions > div { position: relative; margin: 0; } -td.options:hover > div > dl,td.actions:hover > div > dl { display: block; } -td.options > div > dl, td.actions > div > dl { - left: 0.8em; - padding: 0.6ex; +td.options:hover > div > form > dl,td.actions:hover > div > dl { + display: block; +} +td.options > div > form > dl, td.actions > div > dl { + left: 1em; font-family: sans-serif; white-space: nowrap; } @@ -77,6 +78,8 @@ table.paralleltexts td.target { padding-left: 0.7em; } label { font-family: sans-serif; } +form { margin: 0; } + form.import { min-width: 90%; /* extend to availiable width for Safari */ /*background: #eee;*/ diff --git a/src/www/translator/translator.js b/src/www/translator/translator.js index 4f535a605..deb00ab58 100644 --- a/src/www/translator/translator.js +++ b/src/www/translator/translator.js @@ -3,21 +3,23 @@ /* --- Translator object ---------------------------------------------------- */ function Translator() { - this.local=tr_local(); - this.view=element("document") + var t=this + t.local=tr_local(); + t.view=element("document") if(!supports_html5_storage()) { var warning=span_class("error",text("It appears that localStorage is unsupported or disabled in this browser. Documents will not be preserved after you leave or reload this page!")) - insertAfter(warning,this.view) + insertAfter(warning,t.view) } - this.current=this.local.get("current") - this.document=this.current && this.current!="/" && this.local.get("/"+this.current) || empty_document() - this.server=pgf_online({}) - this.server.get_grammarlist(bind(this.extend_methods,this)) - update_language_menu(this,"source") - update_language_menu(this,"target") - if(apertium) this.add_apertium() + t.current=t.local.get("current") + t.document=t.current && t.current!="/" && t.local.get("/"+t.current) || empty_document() + t.servers={}; //The API is stateful, use one pgf_online object per grammar + t.grammar_info={}; + pgf_online({}).get_grammarlist(bind(t.extend_methods,t)) + update_language_menu(t,"source") + update_language_menu(t,"target") + if(apertium) t.add_apertium() //initialize_sorting(["TR"],["segment"]) - this.redraw(); + t.redraw(); } function update_language_menu(t,id) { @@ -37,25 +39,34 @@ Translator.prototype.redraw=function() { clear(t.view) appendChildren(t.view,t.drawing.doc) var o=t.document.options - update_radiobutton("method",o.method) - update_radiobutton("source",o.from) - update_radiobutton("target",o.to) - update_radiobutton("view",o.view || "segmentbysegment") + var form=document.forms.options + update_radiobutton(form,"method",o.method) + update_radiobutton(form,"source",o.from) + update_radiobutton(form,"target",o.to) + update_radiobutton(form,"view",o.view || "segmentbysegment") update_checkbox("cloud",o.cloud || false) - switch(o.method) { - case "Manual": - case "Apertium": - t.update_language_menus() - t.update_translations() - break; - default: // GF + t.update_language_menus() + t.update_translations() + } +} + +Translator.prototype.switch_grammar=function(grammar,cont) { + var t=this + var gi=t.grammar_info[grammar] + if(gi) cont(gi) + else { + var pgf=t.servers[grammar] + if(pgf) pgf.waiting.push(cont) + else { + pgf=t.servers[grammar]=pgf_online({}) + pgf.waiting=[cont] function cont2(gr_info) { - t.grammar_info=gr_info - t.update_language_menus() // needs grammar_info - t.update_translations() + t.grammar_info[grammar]=gr_info + console.log("Passing grammar info for "+grammar+" to "+pgf.waiting.length+" clients") + while(pgf.waiting.length>0) pgf.waiting.pop()(gr_info) } - function cont1() { t.server.grammar_info(cont2)} - t.server.switch_grammar(o.method,cont1) + function cont1() { pgf.grammar_info(cont2)} + pgf.switch_grammar(grammar,cont1) } } } @@ -91,15 +102,18 @@ Translator.prototype.update_language_menus=function() { mark_menus(ssupport,tsupport) break; default: // GF - var supported=bind(t.gf_supported,t) - mark_menus(supported,supported) + function cont() { + function gfsupport(code) { return t.gf_supported(o.method,code) } + mark_menus(gfsupport,gfsupport) + } + t.switch_grammar(o.method,cont) } } -Translator.prototype.gf_supported=function(langcode) { +Translator.prototype.gf_supported=function(grammar,langcode) { var t=this; - var concname=t.grammar_info.name+langcode - var l=t.grammar_info.languages + var concname=t.grammar_info[grammar].name+langcode + var l=t.grammar_info[grammar].languages for(var i in l) if(l[i].name==concname) return true return false } @@ -125,17 +139,17 @@ Translator.prototype.update_translations=function() { ts[i].appendChild(text(segment.target+" ")) } } - function update_segment(i,txts) { + function update_segment(m,i,txts) { var segment=ss[i] segment.target=txts[0]; - segment.options={method:o.method,from:o.from,to:o.to} // no sharing! + segment.options={method:m,from:o.from,to:o.to} // no sharing! if(txts.length>1) segment.choices=txts else delete segment.choices replace(i) } function update_apertium_translation(i,afrom,ato) { var segment=ss[i] - function upd3(txts) { update_segment(i,txts) } + function upd3(txts) { update_segment("Apertium",i,txts) } function upd1(res) { //console.log(translate_output) if(res.translation) upd3([res.translation]) @@ -143,17 +157,16 @@ Translator.prototype.update_translations=function() { } function upd0(source) { apertium.translate(source,afrom,ato,upd1) } if(apertium.isTranslatablePair(afrom,ato)) { - if(segment.options.method!="Manual" - && !eq_options(segment.options,o)) - upd0(segment.source) + if(!eq_options(segment.options,o)) upd0(segment.source) } else upd3(["[Apertium does not support "+show_translation(o)+"]"]) } - function update_gf_translation(i,gfrom,gto) { + function update_gf_translation(i,grammar,gfrom,gto) { var segment=ss[i] - function upd3(txts) { update_segment(i,txts) } + var server=t.servers[grammar] + function upd3(txts) { update_segment(grammar,i,txts) } function upd2(ts) { function unlex(txt,cont) { gfshell('ps -unlextext "'+txt+'"',cont) } @@ -167,14 +180,17 @@ Translator.prototype.update_translations=function() { upd2(collect_texts(translate_output[0].translations)) } function upd0(source) { - t.server.translate({from:gfrom,to:gto,input:source},upd1) + server.translate({from:gfrom,to:gto,input:source},upd1) } - var fls=t.gf_supported(o.from) - var tls=t.gf_supported(o.to) + var fls=t.gf_supported(grammar,o.from) + var tls=t.gf_supported(grammar,o.to) if(fls && tls) { - if(segment.options.method!="Manual" - && !eq_options(segment.options,o)) + var want={from:o.from, to:o.to, method:grammar} + if(!eq_options(segment.options,want)) { + console.log("Updating "+i) gfshell('ps -lextext "'+segment.source+'"',upd0) + } + else if(i==0) console.log("No update ",want,segment.options) } else { var fn=concname(o.from) @@ -182,43 +198,64 @@ Translator.prototype.update_translations=function() { var unsup=" is not supported by the grammar" var sup=" is supported by the grammar" var msg= fls ? tn+unsup : tls ? fn+unsup : - "Neither "+fn+" nor "+tn+sup + "Neither "+fn+" nor "+tn+sup upd3(["["+msg+"]"]) } } - switch(doc.options.method) { - case "Manual": - break; - case "Apertium": - var afrom=alangcode(o.from) - var ato=alangcode(o.to) - for(var i in ss) update_apertium_translation(i,afrom,ato) - break; - default: // GF - var gname=t.grammar_info.name - var gfrom=gname+o.from - var gto=gname+o.to - for(var i in ss) update_gf_translation(i,gfrom,gto) + for(var i in ss) { + var m= ss[i].options.method || doc.options.method + var d=ss[i].use_default + if(d || d==null) m=doc.options.method + switch(m) { + case "Manual": + console.log("Manual "+i) + break; + case "Apertium": + var afrom=alangcode(o.from) + var ato=alangcode(o.to) + update_apertium_translation(i,afrom,ato) + break; + default: // GF + function capture(i,m) { // Capture current values of loop variables + function upd00(grammar_info) { + var gname=grammar_info.name + console.log("Got grammar info "+gname+" for "+i) + var gfrom=gname+o.from + var gto=gname+o.to + update_gf_translation(i,m,gfrom,gto) + } + t.switch_grammar(m,upd00) + } + capture(i,m) + } } } Translator.prototype.add_apertium=function() { var dl=element("methods") - if(dl) - dl.appendChild(dt(radiobutton("method","Apertium","Apertium", - bind(this.change,this)))) + if(dl) add_apertium_to_menu(dl,bind(this.change,this)) +} + +function add_apertium_to_menu(dl,action) { + dl.appendChild(dt(radiobutton("method","Apertium","Apertium",action))) } Translator.prototype.extend_methods=function(grammars) { this.grammars=grammars var dl=element("methods") + if(dl) this.extend_methods_menu(dl,bind(this.change,this)) + update_radiobutton(document.forms.options,"method",this.document.options.method) + this.redraw() +} + +Translator.prototype.extend_methods_menu=function(dl,action) { + var grammars=this.grammars if(dl) for(var i in grammars) { dl.appendChild(dt(radiobutton("method",grammars[i], "GF: "+grammars[i], - bind(this.change,this)))) + action))) } - update_radiobutton("method",this.document.options.method) } Translator.prototype.change=function(el) { @@ -642,22 +679,33 @@ function draw_choices(txts,onclick) { Translator.prototype.draw_segment_given_target=function(s,target,i) { var t=this - function draw_options2(o) { + function draw_options2() { + var o=s.options function change(el) { - o.method=el.value // side effect, updating the document in-place - t.update_translations() + s.use_default = el.value=="Default" + var m = s.use_default ? t.document.options.method : el.value + if(m!=o.method) { + o.method=m // side effect, updating the document in-place + o.to="" // hack to force an update + console.log("Method changed to "+m) + t.update_translations() + } } - var manual=o.method=="Manual" - var autoB=radiobutton("method","Auto","Auto",change,!manual) - var manualB=radiobutton("method","Manual","Manual",change,manual) - return wrap("form", - [dt(autoB), - dt(manualB), - dt(draw_translation(o))]) + var autoB=radiobutton("method","Default","Default",change) + var manualB=radiobutton("method","Manual","Manual",change) + var dl=wrap_class("dl","popupmenu", + [dt(autoB), + dt([manualB,text(" "),draw_translation(o)])]) + if(apertium) add_apertium_to_menu(dl,change) + t.extend_methods_menu(dl,change) + var form=wrap("form",dl) + var d = s.use_default + var m = d || d==null ? "Default" : o.method || "Default" + update_radiobutton(form,"method",m) + return form } - function draw_options(o) { - return wrap("div",[span_class("arrow",text(" ⇒ ")), - wrap("dl",draw_options2(o))]) + function draw_options() { + return wrap("div",[span_class("arrow",text(" ⇒ ")),draw_options2()]) } var insertB=dt(text("Insert a new segment")) @@ -670,7 +718,7 @@ Translator.prototype.draw_segment_given_target=function(s,target,i) { [insertB,removeB])])) var source=wrap_class("td","source",text(s.source)) source.onclick=function() { t.edit_source(source,i); } - var options=wrap_class("td","options",draw_options(s.options)) + var options=wrap_class("td","options",draw_options()) return node("tr",{"class":"segment",id:i},[actions,source,options,target]) } @@ -825,8 +873,8 @@ function radiobutton(name,value,label,change,checked) { return wrap("label",[b,text(label)]) } -function update_radiobutton(name,value) { - var bs=document.forms.options[name] +function update_radiobutton(form,name,value) { + var bs=form[name] if(bs.length) for(var i in bs) if(bs[i].value==value) bs[i].checked=true }