$(document).ready(function() { $('label').popover(); }); /** * Launches the parsing process by calling the parser with the data entered in the interface, * and processing the results. */ function parse() { var textToParse = $("#lojban-text-area").val(); $("#result-row").slideDown(); try { var start = new Date().getTime(); var parse = camxes.parse(textToParse); var end = new Date().getTime(); $("#time-label").html("(parsing took " + (end - start) + " ms)"); parse = remove_morphology(parse); parse = remove_spaces(parse); var simplified = simplifyTree(parse); numberSumti(simplified); if (parse) { tokens = []; findTokens(parse, tokens); var $parseResultHighlighted = $("#parse-result-highlighted"); showHighlighting(simplified[0], tokens, $parseResultHighlighted); var $parseResultRaw = $("#parse-result-raw"); showRawTree(parse, $parseResultRaw); var $parseResultTree = $("#parse-result-tree"); showParseTree(parse, $parseResultTree); var $parseResultSimplified = $("#parse-result-simplified"); showSimplifiedTree(simplified, $parseResultSimplified); var $parseResultBoxes = $("#parse-result-boxes"); showBoxes(simplified, $parseResultBoxes); var $parseResultGlossing = $("#parse-result-glossing"); showGlossing(tokens, $parseResultGlossing); } $("#parse-result-highlighted-tab").html("Highlighted"); $("#parse-result-tree-tab").html("Parse tree"); $("#parse-result-raw-tab").html("Raw tree"); $("#parse-result-simplified-tab").html("Simplified tree"); $("#parse-result-boxes-tab").html("Boxes"); $("#parse-result-glossing-tab").html("Glosses"); } catch (e) { if (e.name && e.name === "SyntaxError") { $("#parse-result-highlighted-tab").html("Highlighted"); showSyntaxError(e, textToParse, $("#parse-result-highlighted")); $("#parse-result-raw-tab").html("Raw tree"); showSyntaxError(e, textToParse, $("#parse-result-raw")); $("#parse-result-simplified-tab").html("Simplified tree"); showSyntaxError(e, textToParse, $("#parse-result-simplified")); $("#parse-result-tree-tab").html("Parse tree"); showSyntaxError(e, textToParse, $("#parse-result-tree")); $("#parse-result-boxes-tab").html("Boxes"); showSyntaxError(e, textToParse, $("#parse-result-boxes")); $("#parse-result-glossing-tab").html("Glosses"); showSyntaxError(e, textToParse, $("#parse-result-glossing")); } else { throw e; } } } /** * Finds all tokens in the resulting parse tree, and puts them in the tokens array. */ function findTokens(parse, tokens) { if (parse instanceof Array) { if (parse.length == 2 && isString(parse[0]) && isString(parse[1])) { tokens.push(parse[1]); } else { for (child in parse) { findTokens(parse[child], tokens); } } } } /** * Shows the parse result in the interface. */ function showRawTree(parse, $element) { $element.html("
" + JSON.stringify(parse, undefined, 2) + "
"); } /** * Shows the parse result in the interface. */ function showParseTree(parse, $element) { $element.html(constructParseTreeOutput(parse, 0)); } function constructParseTreeOutput(parse, depth) { // precaution against infinite recursion; this should not actually happen of course if (depth > 50) { return "too much recursion :-("; } // if we get null, just print that if (parse === null) { return "(none?)"; } // if we get undefined, just print that if (!parse) { return "(undefined?)"; } if (parse instanceof Array) { if (parse.length == 0) { return "(empty array?)"; } var output = ""; // what is the type of parse[0]? if (isString(parse[0])) { // it is the type output += parse[0] + ":"; if (isString(parse[1])) { // a literal output += " [" + getVlasiskuLink(parse[1]) + "]"; if (shortDescriptions[parse[1]]) { output += " " + shortDescriptions[parse[1]] + ""; } return output; } output += ""; return output; } else { output += "a list:"; output += "
    "; for (var child in parse) { output += "
  1. " + constructParseTreeOutput(parse[child], depth + 1) + "
  2. "; } output += "
"; return output; } return "(huh 2?)"; } return "(huh? " + parse + ")"; } /** * Shows the simplified parse tree in the interface. */ function showSimplifiedTree(simplified, $element) { $element.html(constructSimplifiedTreeOutput(simplified[0], 0)); } function constructSimplifiedTreeOutput(parse, depth) { // precaution against infinite recursion; this should not actually happen of course if (depth > 50) { return "too much recursion :-("; } // if we get null, just print that if (parse === null) { return "(none?)"; } // if we get undefined, just print that if (!parse) { return "(undefined?)"; } var output = parse.type; if (parse.sumtiPlace) { output += parse.sumtiPlace; } if (parse.word) { // we have a terminal output += " [" + getVlasiskuLink(parse.word) + "]"; if (shortDescriptions[parse.word]) { output += " " + shortDescriptions[parse.word] + ""; } } else { // we have a non-terminal output += ""; } return output; } /** * Shows the boxes in the interface. */ function showBoxes(simplified, $element) { var output = ""; output += constructBoxesOutput(simplified[0], 0); /*output += "

Legend: "; var types = ["sentence", "prenex", "selbri", "sumti"]; for (var type in types) { output += "

" + types[type] + "
"; } output += "

";*/ $element.html(output); } function constructBoxesOutput(parse, depth) { // precaution against infinite recursion; this should not actually happen of course if (depth > 50) { return "too much recursion :-("; } // if we get null, just print that if (parse === null) { return "(none?)"; } // if we get undefined, just print that if (!parse) { return "(undefined?)"; } var output = ""; if (parse.word) { output += "
"; // we have a terminal output += " " + getVlasiskuLink(parse.word) + " 
"; output += " " + parse.type + " 
"; if (shortDescriptions[parse.word]) { output += " " + shortDescriptions[parse.word] + " "; } else { output += "..."; } output += "
"; } else { // we have a non-terminal output += "
"; for (var child in parse.children) { output += constructBoxesOutput(parse.children[child], depth + 1); } if (boxClassForType(parse) !== "box box-not-shown") { output += "
" + parse.type; if (parse.sumtiPlace) { output += parse.sumtiPlace; } } output += "
"; } return output; } function boxClassForType(parse) { if (parse.type === "sentence") { return "box box-sentence"; } if (parse.type === "sumti x") { if (parse.sumtiPlace > 5) { return "box box-sumti6"; } else if (parse.sumtiPlace == "fai") { return "box box-sumti-fai"; } else { return "box box-sumti" + parse.sumtiPlace; } } if (parse.type === "modal sumti") { return "box box-modal"; } if (parse.type === "sumti") { return "box box-sumti"; } if (parse.type === "selbri") { return "box box-selbri"; } if (parse.type === "prenex") { return "box box-prenex"; } return "box box-not-shown"; } /** * Shows a syntax error in the interface. */ function showSyntaxError(e, textToParse, $element) { var output = "
" + "

Syntax error on line " + e.line + ", at column " + e.column + ": " + e.message + "

" + "

" + generateErrorPosition(e, textToParse) + "

" + generateFixes(e) + "
"; $element.html(output); } /** * Generates the text sample that shows the error position. */ function generateErrorPosition(e, textToParse) { //"mi vau do cusku ..." + var before = textToParse.substring(e.offset - 20, e.offset); var after = textToParse.substring(e.offset + 0, e.offset + 20); if (e.offset > 20) { before = "..." + before; } if (e.offset < textToParse.length - 20) { after = after + "..."; } return before + "" + after; } function generateFixes(e) { if (!e.fix) { //return "

No quick fixes available.

"; return ""; } var fixes = "

Quick fixes:

"; return fixes; } /** * Shows the highlighting in the interface. */ function showHighlighting(simplified, tokens, $element) { var output = ""; if ($("#latin-button").hasClass('active')) { var mode = 1; var classString = "latin-highlighting"; } else if ($("#cyrillic-button").hasClass('active')) { var mode = 2; var classString = "cyrillic-highlighting"; } else if ($("#tengwar-button").hasClass('active')) { var mode = 3; var classString = "tengwar-highlighting"; } else if ($("#hiragana-button").hasClass('active')) { var mode = 4; var classString = "hiragana-highlighting"; } output += ""; output += markupHighlighting(simplified, mode); output += ""; $element.html(output); } function markupHighlighting(simplified, mode) { var output = ""; var beforeOutput = ""; var afterOutput = " "; if (simplified.type === "selbri") { beforeOutput += ""; afterOutput = " "; } else if (simplified.type === "modal sumti") { beforeOutput += "m"; afterOutput = " "; } else if (simplified.type === "sumti x") { if (simplified.sumtiPlace > 5) { beforeOutput += "" + simplified.sumtiPlace + ""; afterOutput = " "; } else { beforeOutput += "" + simplified.sumtiPlace + ""; afterOutput = " "; } } else if (simplified.type === "prenex") { beforeOutput += "p"; afterOutput = " "; } else if (simplified.type === "free") { beforeOutput += "v"; afterOutput = " "; } if (simplified.word) { output += outputWord(simplified.word, mode); } else { if (beforeOutput === "") { for (child in simplified.children) { output += markupHighlighting(simplified.children[child], mode); } } else { output += "" + enumerateTokens(simplified, mode) + ""; } } return beforeOutput + output + afterOutput; } function enumerateTokens(simplified, mode) { var output = ""; if (simplified.word) { output += outputWord(simplified.word, mode); } else { for (child in simplified.children) { var textToAdd = enumerateTokens(simplified.children[child], mode); if (textToAdd) { output += textToAdd + " "; } } } if (endsWith(output, " ")) { output = output.substring(0, output.length - 1); } return output; } function isModalSumti(sumti) { var tag = sumti[1][0]; return tag === "tag"; // TODO It would be much nicer to make some methods for walking the parse tree, and using them } function markupError(error, before, after) { // TODO before[error.position] = "" + before[error.position]; after[error.position] = after[error.position] + ""; } /** * Shows the glossing in the interface. */ function showGlossing(text, $element) { var output = "
"; for (var j = 0; j < text.length; j++) { output += "
" + getVlasiskuLink(text[j]) + "
"; if (shortDescriptions[text[j]]) { output += "
" + shortDescriptions[text[j]] + "
"; } else { output += "
(?)
"; } } output += "
"; $element.html(output); } /** * Shows the translation in the interface. */ function showTranslation(parse, text, $element) { var output = "

This translation feature tries to give an approximate translation of the Lojban text into English. However, it does only work for a few sentences as of now. (Try [mi gleki] or something simple like that...)

"; //var translation = translate(parse); var translation = "Sorry! Translation is switched off at the moment, to prevent crashes in the other parts :-("; output += "
" + translation + "
"; $element.html(output); } // Auxiliary function isString(s) { return typeof(s) === 'string' || s instanceof String; } function getVlasiskuLink(word) { return "" + outputWord(word, getSelectedMode()) + ""; } function outputWord(word, mode) { if (mode === 1) { // Latin mode return addDotsToWord(word); } else if (mode === 2) { // Cyrillic mode return wordToCyrillic(addDotsToWord(word)); } else if (mode === 3) { // Tengwar mode return wordToTengwar(addDotsToWord(word)); } else if (mode === 4) { // Hiragana mode return wordToHiragana(addDotsToWord(word)); } } function getSelectedMode() { if ($("#latin-button").hasClass('active')) { return 1; } else if ($("#cyrillic-button").hasClass('active')) { return 2; } else if ($("#tengwar-button").hasClass('active')) { return 3; } else if ($("#hiragana-button").hasClass('active')) { return 4; } } function endsWith(str, suffix) { return str.indexOf(suffix, str.length - suffix.length) !== -1; }