/* --- Translator object ---------------------------------------------------- */ function Translator() { var t=this t.local=appLocalStorage("gf.translator.") t.view=element("document") t.filebox=element("filebox") if(!supports_html5_storage()) { var warning=span_class("error",text("It appears that localStorage is unsupported or disabled in this browser. Local documents will not be preserved after you leave or reload this page!")) insertAfter(warning,t.view) } if(!supports_local_files()) { var item=element("import_globalsight") if(item) item.style.display="none" } 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)) function update_language_menu(t,id) { var dl=element(id); clear(dl); for(var i in languages) { var l=languages[i] dl.appendChild(dt(radiobutton(id,l.code,l.name,bind(t.change,t)))) } } update_language_menu(t,"source") update_language_menu(t,"target") if(window.apertium) t.add_apertium() //initialize_sorting(["TR"],["segment"]) t.document=empty_document(); t.current=t.local.get("current") if(t.current && t.current!="/") { if(t.local.get("current_in_cloud")) t.open_from_cloud(t.current) else t.open(t.current) } } Translator.prototype.redraw=function() { var t=this; if(t.current=="/") t.browse() else { t.drawing=t.draw_document() clear(t.view) appendChildren(t.view,t.drawing.doc) var o=t.document.options 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) t.update_language_menus() t.update_translations() t.update_edit_menu() } } 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({grammar_list:[grammar]}) pgf.waiting=[cont] function cont2(gr_info) { 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() { pgf.grammar_info(cont2)} pgf.switch_grammar(grammar,cont1) } } } Translator.prototype.update_edit_menu=function() { var t=this function set_class(id,name) { var e=element(id) if(e) e.className=name } var able= t.document.globalsight ? "disabled" : "" set_class("edit_import",able) set_class("edit_add_segment",able) set_class("edit_remove_segment",able) } Translator.prototype.update_language_menus=function() { var t=this var o=t.document.options var method=o.method+(o.method=="Apertium"?"/"+o.from:"") if(t.menus_for==method) return; t.menus_for=method function mark_menu(name,supported) { var menu=document.forms.options[name] for(var i=0;i1) segment.choices=txts else delete segment.choices draw_update() } function update_apertium_translation() { var afrom=alangcode(o.from), ato=alangcode(o.to) function upd3(txts) { update_segment("Apertium",txts) } function upd3s(txt) { upd3([{quality:"error",text:txt}]) } function upd1(res) { //console.log(translate_output) if(res.translation) upd3([res.translation]) else upd3s("["+res.error.message+"]") } function upd0(source) { apertium.translate(source,afrom,ato,upd1) } if(!window.apertium) upd3s("[Apertium is not available]") else if(apertium.isTranslatablePair(afrom,ato)) { if(!eq_options(segment.options,o)) upd0(segment.source) } else upd3s("[Apertium does not support "+show_translation(o)+"]") } function update_gfrobust_translation() { function upd3(trans,sp,qf) { var ts=[] for(var i=0;i () function upd0b(sp) { function upd1b(translate_output) { //console.log(translate_output) upd2b(translate_output,sp) } gftranslate.wordforword(sp.txt,o.from,o.to,upd1b) } function upd2(trans,sp) { if(trans.length==0) upd0b(sp) // upd3s("[no translation]") else if(trans[0].error!=undefined) //upd3s("[GF robust translation problem: "+trans[0].error+"]") upd0b(sp) else upd3(trans,sp) } // upd0 :: {txt:String,punct:String} -> () function upd0(sp) { function upd1(translate_output) { //console.log(translate_output) upd2(translate_output,sp) } gftranslate.translate(sp.txt,o.from,o.to,0,10,upd1) } if(!window.gftranslate) upd3s("[GF robust parser is not available]") else { function check_support(ssupport,tsupport) { var fls=ssupport(o.from) var tls=tsupport(o.to) if(fls && tls) { var want={from:o.from, to:o.to, method:"GFRobust"} if(!eq_options(segment.options,want)) { //console.log("Updating "+i) //lexgfrobust(segment.source,upd0) upd0(rmpunct(segment.source)) } //else console.log("No update ",want,segment.options) } else { var fn=" from "+concname(o.from) var tn=" to "+concname(o.to) var msg="The GF robust translation service: not supported:" if(!fls) msg+=fn+(tls ? "." : ", ") if(!tls) msg+=tn+"." upd3s("["+msg+"]") } } function no_support(text,status,ct) { upd3s("[GF Robust translation service error: "+status+"]") } gftranslate.get_support(check_support,no_support) } } function update_gf_translation(grammar,gfrom,gto) { var server=t.servers[grammar] function upd3(txts) { update_segment(grammar,txts) } function upd3s(txt) { upd3([{quality:"error",text:txt}]) } function upd2(ts) { switch(ts.length) { case 0: upd3s("[no translation]");break; default: //mapc(unlextext,ts,upd3); upd3(ts) break; } } function upd1(translate_output) { //console.log(translate_output) upd2(collect_texts(translate_output[0].translations)) } function upd0(source) { server.translate({from:gfrom,to:gto,lexer:"text",unlexer:"text", input:source},upd1) } var fls=t.gf_supported(grammar,o.from) var tls=t.gf_supported(grammar,o.to) if(fls && tls) { var want={from:o.from, to:o.to, method:grammar} if(!eq_options(segment.options,want)) { //console.log("Updating "+i) //lextext(segment.source,upd0) upd0(segment.source) } //else console.log("No update ",want,segment.options) } else { var fn=concname(o.from) var tn=concname(o.to) var sup="supported by the grammar" var isnot=" is not "+sup var is=" is "+sup var msg= fls ? tn+isnot : tls ? fn+isnot : "Neither "+fn+" nor "+tn+is upd3s("["+msg+"]") } } var m=segment_method(doc,ss[i]) switch(m) { case "Manual": /* Nothing to do */ break; case "Apertium": update_apertium_translation(); break; case "GFRobust": update_gfrobust_translation(); break; default: // GF function upd00(grammar_info) { var gname=grammar_info.name var gfrom=gname+o.from, gto=gname+o.to update_gf_translation(m,gfrom,gto) } t.switch_grammar(m,upd00) } } Translator.prototype.add_apertium=function() { var dl=element("methods") 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], action))) } } Translator.prototype.change=function(el) { var t=this var o=t.document.options; function update(field) { if(el.value!=o[field]) { o[field]=el.value t.redraw() } } function update_checkbox(field) { if(el.checked!=o[field]) { o[field]=el.checked t.redraw() } } switch(el.name) { case "method": update("method"); break; case "source": update("from"); break; case "target": update("to"); break; case "view" : update("view"); break; case "cloud" : update_checkbox("cloud"); break; } } Translator.prototype.new=function(el) { hide_menu(el); this.current=null; this.local.put("current",null) this.document=empty_document() this.redraw(); } Translator.prototype.browse=function(el) { hide_menu(el); var t=this function ls(files,open,del) { var ul=empty_class("ul","files") for(var i in files) { var name=files[i] var link=a(jsurl(open+"('"+name+"')"),[text(name)]) ul.appendChild(li(deletable(del(name),link))) } return ul } function delete_local(name) { return function() { if(confirm("Are you sure you want to delete the local document "+name+"?")) { t.local.remove("/"+name) browse(); } } } function delete_from_cloud(name) { return function() { if(confirm("Are you sure you want to delete the cloud document "+name+"?")) { gfcloud("rm",{file:name+cloudext},browse) } } } function browse() { var list=empty("div") clear(t.filebox) t.filebox.appendChild(list) list.appendChild(wrap("h2",text("Open..."))) var files=t.local.ls("/") if(files.length>0) { list.appendChild(wrap("h3",text("Local documents"))) list.appendChild(ls(files,"translator.open",delete_local)) } function lscloud(result) { var filenames=JSON.parse(result) var files=map(strip_cloudext,filenames) if(files.length>0) { list.appendChild(wrap("h3",[text("Documents in the cloud "), img("../P/cloud.png")])) list.appendChild(ls(files,"translator.open_from_cloud",delete_from_cloud)) } } if(navigator.onLine) gfcloud("ls",{ext:cloudext},lscloud) /* t.current="/" t.local.put("current","/") */ t.filebox.appendChild(button("Cancel",function () { t.hide_filebox() })) t.show_filebox() } setTimeout(browse,100) // leave time to hide the menu first } Translator.prototype.open=function(name) { var t=this if(name) { var path="/"+name var document=t.local.get(path); if(document) t.load(name,document,false) else alert("No such document: "+name) } } Translator.prototype.show_filebox=function() { this.filebox.parentNode.style.display="block"; } Translator.prototype.hide_filebox=function() { var t=this t.filebox.parentNode.style.display=""; clear(t.filebox) } Translator.prototype.load=function(name,document,in_cloud) { var t=this t.current=name; t.current_in_cloud=in_cloud; t.local.put("current",name) t.local.put("current_in_cloud",in_cloud) t.document=document; t.hide_filebox(); t.redraw(); } Translator.prototype.open_from_cloud=function(name) { var t=this var filename=name+cloudext function ok(result) { var document=JSON.parse(result) if(document) t.load(name,document,true) } gfcloud("download",{file:encodeURIComponent(filename)},ok); } Translator.prototype.save=function(el) { var t=this hide_menu(el); if(t.current!="/") { if(t.current) { var path="/"+t.current if(t.document.options.cloud) { function done() { //t.local.remove(path) t.local.put("current_in_cloud",true) t.local.put("current",t.current) } save_in_cloud(t.current+cloudext,t.document,done) } else { t.local.put(path,t.document) t.local.put("current",t.current) } } else t.saveAs() } } Translator.prototype.saveAs=function(el) { var t=this hide_menu(el); if(t.current!="/") { var name=prompt("File name?") if(name) { t.current=t.document.name=name; t.local.put("current",name) t.save(); t.redraw(); } } } Translator.prototype.close=function(el) { hide_menu(el); this.browse(); } /* Translator.prototype.add_segment1=function(el) { hide_menu(el); var t=this function imp() { var text=prompt("Text segment to import?") if(text) { t.document.segments.push(new_segment(text)) t.redraw(); } } setTimeout(imp,100) } */ Translator.prototype.add_segment=function(el) { var t=this if(t.document.globalsight) return hide_menu(el); function imp() { var n=t.document.segments.length t.insert_segment(n) } if(t.current!="/") setTimeout(imp,100) } Translator.prototype.insert_segment=function(i) { var t=this function restore() { t.redraw() } function done() { var text=inp.value if(text) { var newseg=new_segment(text) t.document.segments=insert_ix(t.document.segments,i,newseg) } restore() return false } var inp=node("input",{name:"it",value:""}) var e=form({},[inp, submit(), button("Cancel",restore)]) var source=wrap_class("td","source",e) var edit=wrap_class("tr","segment",[td([]),source]) var ss=t.drawing.segments var n=ss ? ss.length : 0 if(n>0) { if(i==0) insertBefore(edit,ss[0]) else insertAfter(edit,ss[i-1]) } else t.view.appendChild(wrap_class("table","segments",edit)) e.onsubmit=done inp.focus(); } Translator.prototype.import=function(el) { var t=this if(t.document.globalsight) return // disabled hide_menu(el); function imp() { function restore() { t.redraw() } function done() { function add_segments(text) { var ls=window.lines(text) var segs= punct.firstChild.checked ? split_punct(text,punctchars.value) : paras.firstChild.checked ? join_paragraphs(ls) : ls for(var i in segs) t.document.segments.push(new_segment(segs[i])) } function import_text(text2) { var text=inp.value add_segments(text2) add_segments(text) restore() } function import_file(ev) { import_text(ev.target.result) } if(files.files && files.files.length>0) { var file=files.files[0] var r=new FileReader() r.onload=import_file r.readAsText(file) } else import_text("") return false } var inp=node("textarea",{name:"it",value:"",rows:"10"}) var punct=radiobutton("separator","punct", "Punctuation indicates where segments end: ",null,true) var lines=radiobutton("separator","lines", "Segments are separated by line breaks",null,false) var paras=radiobutton("separator","paras", "Segments are separated by blank lines",null,false) var punctchars=node("input",{name:"punctchars",value:".?!",size:"5"}) var lang=concname(t.document.options.from) var e=form({class:"import"}, [wrap("h3",text("Import text ("+lang+")")), inp, wrap("dl",[dt([punct,punctchars]),dt(lines),dt(paras)]), submit(), button("Cancel",restore)]) if(supports_local_files()) { // Allow import from local files, if the browers supports it. var files=node("input",{name:"files","type":"file"}) var extra=wrap("label",[text("Choose a file: "), files, text(" and/or enter text to import below.")]) e.insertBefore(extra,inp) } t.view.appendChild(e) e.onsubmit=done inp.focus(); } if(t.current!="/") setTimeout(imp,100) } Translator.prototype.export_globalsight=function() { t=this /* Taken from this discussion on saving to local files: http://stackoverflow.com/questions/2897619/using-html5-javascript-to-generate-and-save-a-file */ open("data:application/octet-stream," +encodeURIComponent(export_globalsight_download_file(t.document)), t.document.name /*,'toolbar=no,location=no,status=no'*/); /* Also consider: FileSaver saveAs() Not directly support in browsers: http://www.w3.org/TR/file-writer-api/#the-filesaver-interface Alternative implementation: FileSaver.js: https://github.com/eligrey/FileSaver.js http://eligrey.com/blog/post/saving-generated-files-on-the-client-side */ } Translator.prototype.import_globalsight=function(el) { hide_menu(el); var t=this function imp() { function done() { function import_text(name,text) { var ls=lines(text) if(ls.length>0 && ls[0]=="# GlobalSight Download File") { t.current=null; t.local.put("current",null) t.document=import_globalsight_download_file(ls) t.current=t.document.name=name t.hide_filebox(); t.redraw(); } else alert("Not a GlobalSight Download File") // !! improve } function import_file(name,ev) { import_text(name,ev.target.result) } if(files.files && files.files.length>0) { var file=files.files[0] var r=new FileReader() r.onload=function(ev) { import_file(file.name,ev); } r.readAsText(file) } return false } clear(t.filebox) t.filebox.appendChild(wrap("h2",text("Import"))) function restore() { t.hide_filebox() } var cancel_button=button("Cancel",restore) if(supports_local_files()) { // Allow import from local files, if the browers supports it. var files=node("input",{name:"files","type":"file"}) var inp=wrap("p",wrap("label",[text("Choose a file: "),files])) var e=form({class:"import"}, [wrap("h3",text("Import a GlobalSight Download File")), inp, submit(), cancel_button]) t.filebox.appendChild(e) e.onsubmit=done } else { t.filebox.appendChild(wrap("p",[text("Support for readling local files is missing in this browser.")])) t.filebox.appendChild(cancel_button) } t.show_filebox(); } setTimeout(imp,100) // leave time to hide the menu first } Translator.prototype.open_in_wc=function(el) { var t=this hide_menu(el) var doc=t.document var sourcetext=doc.segments.map(function(s){return s.source}).join(" ") var wc=appLocalStorage("gf.wc."+gftranslate.grammar+".") wc.put("from",doc.options.from) wc.put("to",doc.options.to) wc.put("input",sourcetext) var w=window.open("../wc.html","wc") w.focus() } Translator.prototype.remove=function(el) { var t=this if(t.document.globalsight) return hide_menu(el); function rm() { if(t.document && t.document.segments.length>0) { t.document.segments.pop(); t.redraw(); } } if(t.current!="/") setTimeout(rm,100) } Translator.prototype.remove_segment=function(i) { var t=this if(t.document && t.document.segments.length>i) { t.document.segments=delete_ix(t.document.segments,i) t.redraw(); } } Translator.prototype.replace_segment=function(i,sd) { var t=this; var ds=t.drawing.segments; if(ds) { var old=ds[i] ds[i]=sd replaceNode(sd,old) } } Translator.prototype.pick_translation=function(i,txt) { var t=this var s=t.document.segments[i] set_manual(s) s.target=txt // side effect, updating the document in-place t.replace_segment(i,t.draw_segment(s,i)) } Translator.prototype.edit_source=function(source,i) { var t=this var doc=t.document var s=doc.segments[i] function restore() { t.replace_segment(i,t.draw_segment(s,i)) } function change(str) { s.source=str // side effect, updating the document in-place restore(); if(s.options.method!="Manual") { s.options.to="" // hack to force an update t.update_translation(i) } } function done() { change(inp.value); return false; } function goto_minibar() { function cont(grammar_info) { var gname=grammar_info.name var gfrom=gname+doc.options.from var gto=gname+doc.options.to var pgf_server=t.servers[grammarname] function cont2(source) { function ok() { function cont(input) { unlextext(input,change) } minibar.get_current_input(cont) t.hide_filebox() } function cancel() { restore() t.hide_filebox() } var minibar_options= { startcat_menu: false, random_button: false, try_google: false, show_abstract: true, show_trees: true, show_grouped_translations: false, word_replacements: true, default_source_language: "Eng", initial_grammar: pgf_server.current_grammar_url, initial:{from:gfrom, startcat:grammar_info.startcat, input:source.split(" ")}, initial_toLangs: [gfrom,gto] } clear(t.filebox) appendChildren(t.filebox,[empty_id("div","minibar"), empty_id("div","syntax_editor")]) var minibar=new Minibar(pgf_server,minibar_options) appendChildren(t.filebox,[button("OK",ok), button("Cancel",cancel)]) t.show_filebox() } lextext(s.source,cont2) } t.switch_grammar(grammarname,cont) } var inp=node("input",{name:"it",value:s.source}) var e=form({},[inp, submit(), button("Cancel",restore),text(" ")]) var grammarname=uses_gf(doc,s) if(grammarname) e.appendChild(button("Minibar",goto_minibar)) replaceChildren(source,e) e.onsubmit=done inp.focus() } Translator.prototype.edit_translation=function(i) { var t=this var s=t.document.segments[i] function restore() { t.replace_segment(i,t.draw_segment(s,i)) } function done() { set_manual(s) s.options.from=t.document.options.from s.options.to=t.document.options.to s.target={quality:"manual_quality",text:inp.value} // side effect, updating the document in-place restore(); return false; } var inp=node("input",{name:"it",value:qstring(s.target)}) var e=form({},[inp, submit(), button("Cancel",restore)]) var target=wrap_class("td","target",e) var edit=t.draw_segment_given_target(s,target,i) t.replace_segment(i,edit) e.onsubmit=done inp.focus(); } function hide_menu(el) { function disp(s) { el.parentNode.style.display=s; } if(el) { disp("none") setTimeout(function(){disp("")},500) } } /* --- Documents ------------------------------------------------------------ */ /* type Document = { name:String, options:DocOptions, segments:[Segment], globalsight : GlobalSight|null } type Segment = { source:String, target:QText, options:Options } & ( {} | { choices:[QText] } ) type QText = { quality:Quality, text:String } | String // mostly for backward compatibility type Quality = "default_quality" | "low_quality" | "high_quality" | "manual_quality" type DocOptions = Options & { view:View, cloud:Bool } type Options = {from: Lang, to: Lang, method:Method} type Lang = String // Eng, Swe, Ita, etc type Method = "Manual" | "Apertium" | "GFRobust" | GFGrammarName type View = "segmentbysegment" | "paralleltexts" type GFGrammarName = String // e.g. "Foods.pgf" type GlobalSight = { header: [String], segments:[[String]] } */ function eq_options(o1,o2) { return o1.method==o2.method && o1.from==o2.from && o1.to==o2.to } Translator.prototype.draw_document=function() { var t=this var doc=t.document var o=doc.options; function draw_globalsight() { function gs_export() { t.export_globalsight(); } return doc.globalsight ? wrap("span",[text(" (from GlobalSight) "), button("Export",gs_export)]) : text("") } var hdr=wrap("h2",[text(doc.name),text(" "), wrap("small",[draw_translation(o),draw_globalsight()])]) if(doc.options.cloud) insertFirst(hdr,img("../P/cloud.png")) switch(o.view || "segmentbysegment") { case "paralleltexts": function src(seg) { return seg.source } function trg(seg) { return seg.target } function fmt(txt,i) { var sd=span_class("segment",[qtext(txt),text(" ")]) function setclass(cls) { return function() { targets[i].className=sources[i].className=cls } } sd.onmouseover=setclass("current_segment") sd.onmouseout=setclass("segment") return sd } var sources=mapix(fmt,map(src,doc.segments)) var targets=mapix(fmt,map(trg,doc.segments)) var drawing=[hdr,wrap_class("table","paralleltexts", tr([wrap_class("td","source",sources), wrap_class("td","target",targets)]))] return {doc:drawing,sources:sources,targets:targets} default: var segments=mapix(bind(t.draw_segment,t),doc.segments) var drawing=[hdr,wrap_class("table","segments",segments)] return {doc:drawing,segments:segments} } } Translator.prototype.draw_segment=function(s,i) { var t=this var dopt=t.document.options var opt=s.options var txt=qtext(s.target) if(opt.from!=dopt.from || opt.to!=dopt.to) txt=span_class("error",txt) var target=wrap_class("td","target",txt) function edit() { t.edit_translation(i) } function pick(txt) { t.pick_translation(i,txt) } target.onclick=edit if(s.choices) appendChildren(target,draw_choices(s.choices,pick)) return t.draw_segment_given_target(s,target,i) } function qtext(t) { switch(typeof(t)) { case "string": return text(t) default: return span_class(t.quality||"",text(t.text)) } } function qstring(t) { switch(typeof(t)) { case "string": return t default: return t.text } } function draw_choices(txts,onclick) { function opt(txt) { var o=dt(qtext(txt)) o.onclick=function(ev) { ev.stopPropagation(); onclick(txt) } return o } return [span_class("choices",text("+")), wrap_class("dl","popupmenu",map(opt,txts))] } Translator.prototype.draw_segment_given_target=function(s,target,i) { var t=this function draw_options2() { var o=s.options function change(el) { 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_translation(i) } } var autoB=radiobutton("method","Default","Default",change) var manualB=radiobutton("method","Manual","Manual",change) var gfrobustB=radiobutton("method","GFRobust","GF Wide Coverage Translation",change) var dl=wrap_class("dl","popupmenu", [dt(autoB), dt([manualB,text(" "),draw_translation(o)]), dt(gfrobustB)]) if(window.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() { return wrap("div",[span_class("arrow",hovertext(" ⇒ ")),draw_options2()]) } if(t.document.globalsight) var actions=empty_class("td","actions") else { var insertB=dt(text("Insert a new segment")) insertB.onclick=function() { t.insert_segment(i) } var removeB=dt(text("Remove this segment")) removeB.onclick=function() { t.remove_segment(i) } var actions=wrap_class("td","actions", wrap("div",[span_class("actions",hovertext("◊")), wrap_class("dl","popupmenu", [insertB,removeB])])) } var txt=wrap("span",text(s.source)) var source=wrap_class("td","source",txt) if(!t.document.globalsight) txt.onclick=function() { t.edit_source(source,i); } /* if(window.gftranslate && segment_method(t.document,s)=="GFRobust") { function add_button(src) { var btn=img("../minibar/tree-btn.png") btn.className="right" btn.other=gftranslate.parsetree_url(src) btn.title="Click to toggle parse tree view." btn.onclick=function() { toggle_img(btn) } source.appendChild(btn) } lexgfrobust(s.source,add_button) } */ var options=wrap_class("td","options",draw_options()) return node("tr",{"class":"segment",id:i},[actions,source,options,target]) } /* --- Document constructor ------------------------------------------------- */ function empty_document() { return { name:"Unnamed", options: {from:"Eng", to:"Swe", method:"Manual"}, segments:[] } } /* --- Segments ------------------------------------------------------------- */ function new_segment(source) { return { source:source, target:"", options:{} } // leave options empty } function set_manual(segment) { segment.options.method="Manual" segment.use_default=false } // Return the name of the grammar if the segment uses GF for translation function uses_gf(doc,segment) { var m= segment_method(doc,segment) return /\.pgf$/.test(m) ? m : null } // Return the translation method use by a segment function segment_method(doc,segment) { var m= segment.options.method || doc.options.method var d=segment.use_default if(d || d==null) m=doc.options.method return m } /* -------------------------------------------------------------------------- */ function draw_translation(o) { return text(show_translation(o)) } function show_translation(o) { return "("+concname(o.from||"?")+" → "+concname(o.to||"?")+")" } /* --- Auxiliary functions -------------------------------------------------- */ // Collect alternative texts in the output from PGF service translate command function collect_texts(ts) { var list=[] for(var i in ts) for(var j in ts[i].linearizations) { var t=ts[i].linearizations[j].text if(!elem(t,list)) list.push(t) // avoid duplicates } return list } function mapix(f,xs) { var ys=[]; for(var i in xs) ys.push(f(xs[i],i)) return ys; } function delete_ix(old,ix) { var a=[]; for(var i in old) if(i!=ix) a.push(old[i]); return a; } function insert_ix(old,ix,x) { var a=[]; var done=false; for(var i in old) { if(i==ix) { a.push(x); done=true; } a.push(old[i]) } if(!done) a.push(x) return a; } // Convert array of lines to array of paragraphs function join_paragraphs(lines) { var paras=[] var current=""; for(var i in lines) if(lines[i]=="") paras.push(current),current="" else current+=" "+lines[i] if(current) paras.push(current) return paras } function split_punct(text,punct) { var ss=text.split(new RegExp("(["+punct+"])")) var segs=[]; for(var i=0;i0 && segs[segs.length-1]=="") segs.pop(); return segs } // Break a string into lines function lines(text) { var ls=text.split("\r\n") // DOS if(ls.length<=1) ls=text.split(/\n|\r/) // Unix | Mac return ls } function supports_local_files() { // See http://www.html5rocks.com/en/tutorials/file/dndfiles/ return window.File && window.FileList && window.FileReader } /* --- GlobalSight support -------------------------------------------------- */ function import_globalsight_download_file(ls) { var doc=empty_document() doc.globalsight={header:[],segments:[]} var i=0; // Scan header and pick up source & target locale for(;i0 && /[.?!]/.test(ts[n-1])) { punct=ts[n-1]; ts.pop()} cont(gf_unlex(ts),punct) } lextext(txt,rmpunct) } */ // rmpunct :: String -> {txt:String,punct:String} function rmpunct(txt) { function ispunct(c) { switch(c) { case ' ': case '\t': case '\n': case '.': case '?': case '!': return true default: return false } } var i=txt.length-1 while(i>=0 && ispunct(txt[i])) i-- i++ return {txt:txt.substr(0,i),punct:txt.substr(i)} } /* --- DOM Support ---------------------------------------------------------- */ function a(url,linked) { return node("a",{href:url},linked); } function jsurl(js) { return "javascript:"+js; } function replaceNode(node,ref) { ref.parentNode.replaceChild(node,ref) } function radiobutton(name,value,label,change,checked) { var b=node("input",{type:"radio",name:name,value:value}) if(change) b.onchange=function(event) { return change(event.target) } if(checked) b.checked=true return wrap("label",[b,text(label)]) } 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 } function update_checkbox(name,checked) { document.forms.options[name].checked=checked } function form(attrs,fields) { return node("form",attrs,fields) } function submit(label) { return node("input",{type:"submit",value:label||"OK"}) } function deletable(del,el,hint) { var b=delete_button(del,hint) return node("span",{"class":"deletable"},[b,el]) } function delete_button(action,hint) { var b=node("span",{"class":"delete",title:hint || "Delete"},[text("×")]) b.onclick=action; return b; } function hovertext(txt) { return node("span",{onclick:""},[text(txt)]) }