var AjaxCatList, AjaxCatTranslation, Suggestions, TranslationTable, Utils,
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
AjaxCatList = (function() {
function AjaxCatList() { this.add_translation = __bind(this.add_translation, this); this.create_new_translation = __bind(this.create_new_translation, this); this.show_translations = __bind(this.show_translations, this); this.new_translation = __bind(this.new_translation, this); this.new_experiment_translation = __bind(this.new_experiment_translation, this); this.create_experiment_translation = __bind(this.create_experiment_translation, this); var _this = this; $('#new-translation-modal').hide(); $('#new-experiment-modal').hide(); $('#new-translation').on('click', this.new_translation); $('#create-new-translation').on('click', this.create_new_translation); this.show_translations(); $(".example").click(function(event) { var text; text = $(event.currentTarget).data("text"); $('#new-translation-text').val(text); return false; }); $("#new-experiment-translation").click(function() { return _this.new_experiment_translation(); }); $("#create-new-experiment").click(function() { return _this.create_experiment_translation(); }); } AjaxCatList.prototype.create_experiment_translation = function() { var email, filter, pair, _this = this; email = $("#new-experiment-email").val(); pair = $("#new-experiment-pair").val(); filter = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/; if (!filter.test(email)) { alert("Write your email, please."); return; } $.cookie("email", email); return $.ajax("/admin/get_experiment", { data: { email: email, pair: pair }, success: function(data) { var id; data = JSON.parse(data); id = _this.add_translation(JSON.parse(data.sentences), "EXPERIMENT #" + data.task_id + ", " + data.email, data.pair, data.task_id, data.email, data); return window.location = "/translation.html#" + id; }, error: function() { return alert("Could not find experiment for you."); } }); }; AjaxCatList.prototype.new_experiment_translation = function() { var _this = this; $("#new-experiment-pair").html(""); $("#new-experiment-email").val($.cookie("email")); return $.ajax("/api/info", { success: function(data) { var p, _i, _len, _ref; data = JSON.parse(data); _ref = data.pairs; for (_i = 0, _len = _ref.length; _i < _len; _i++) { p = _ref[_i]; $("#new-experiment-pair").append("<option value='" + p + "'>" + p + "</option>"); } return $('#new-experiment-modal').modal('show'); } }); }; AjaxCatList.prototype.new_translation = function() { var _this = this; $("#new-translation-pair").html(""); return $.ajax("/api/info", { success: function(data) { var p, _i, _len, _ref; data = JSON.parse(data); _ref = data.pairs; for (_i = 0, _len = _ref.length; _i < _len; _i++) { p = _ref[_i]; $("#new-translation-pair").append("<option value='" + p + "'>" + p + "</option>"); } $('#new-translation-name').val('Name'); $('#new-translation-text').val(''); $('#new-translation-modal').modal('show'); return $('#new-translation-text').focus(); } }); }; AjaxCatList.prototype.show_translations = function() { var doc, i, ids, _i, _len, _this = this; $("#translation-list").html(''); if (!localStorage['ac-data']) return; ids = JSON.parse(localStorage['ac-data']); for (_i = 0, _len = ids.length; _i < _len; _i++) { i = ids[_i]; doc = JSON.parse(localStorage[i]); $("#translation-list").append("<tr><td width='100%'><a href='/translation.html#" + doc.id + "'>" + doc.name + "</a></td><td><button data-id='" + doc.id + "' class='btn btn-danger btn-mini delete-button'>delete</button></td></tr>"); } return $(".delete-button").click(function(event) { var id; id = $(event.currentTarget).data("id"); if (confirm("Delete this translation?")) { AjaxCatList.delete_document(id); return _this.show_translations(); } }); }; AjaxCatList.delete_document = function(id) { var i, ids, new_ids, _i, _len; if (!localStorage['ac-data']) return; ids = JSON.parse(localStorage['ac-data']); new_ids = []; for (_i = 0, _len = ids.length; _i < _len; _i++) { i = ids[_i]; if (i !== id) new_ids.push(i); } localStorage.removeItem(id); return localStorage.setItem('ac-data', JSON.stringify(new_ids)); }; AjaxCatList.prototype.create_new_translation = function() { var name, pair, text; text = $('#new-translation-text').val(); name = $('#new-translation-name').val(); pair = $('#new-translation-pair').val(); this.add_translation(text, name, pair); $('#new-translation-modal').modal('hide'); return this.show_translations(); }; AjaxCatList.prototype.add_translation = function(text, name, pair, task_id, email, experiment_data) { var doc, docs; if (task_id == null) task_id = false; if (email == null) email = false; if (localStorage['ac-data']) { docs = JSON.parse(localStorage['ac-data']); } else { docs = []; } doc = {}; doc.id = Utils.random_string(); doc.name = name; doc.pair = pair; doc.email = email; doc.task_id = task_id; if (jQuery.isArray(text)) { doc.source = text; doc.options = JSON.parse(experiment_data.options); } else { doc.source = Utils.split_source(text); } doc.target = new Array(doc.source.length); docs.push(doc.id); localStorage.setItem('ac-data', JSON.stringify(docs)); localStorage.setItem(doc.id, JSON.stringify(doc)); return doc.id; }; return AjaxCatList;
}).call(this);
AjaxCatTranslation = (function() {
AjaxCatTranslation.prototype.cur_position = false; AjaxCatTranslation.prototype.experiment = false; AjaxCatTranslation.prototype.param_suggestion = true; function AjaxCatTranslation() { this.add_words = __bind(this.add_words, this); this.change_position = __bind(this.change_position, this); this.load_translation_table = __bind(this.load_translation_table, this); this.save_target = __bind(this.save_target, this); this.show_preview = __bind(this.show_preview, this); this.bind_events = __bind(this.bind_events, this); this.resize = __bind(this.resize, this); this.log = __bind(this.log, this); this.prepare_test = __bind(this.prepare_test, this); this.change_experiment_sentence = __bind(this.change_experiment_sentence, this); this.time = __bind(this.time, this); var data, i, s, t, _i, _j, _len, _len2, _ref, _ref2, _this = this; this.now = Date.now(); $('#new-experiment-modal').hide(); $("#send-experiment").hide(); this.suggestions = new Suggestions(this); $('#translation-preview-modal').hide(); $('#myTab').tab('show'); this.hash = window.location.hash.substr(1); data = localStorage.getItem(this.hash); if (!data) { alert("No such document."); return; } this.doc = JSON.parse(data); if (this.doc.task_id) this.prepare_test(); this.pair = this.doc.pair; $('h1').html("" + this.doc.name + " <small>" + this.pair + "</small>"); $("title").html("" + this.doc.name + " - AJAX-CAT"); i = 0; _ref = this.doc.source; for (_i = 0, _len = _ref.length; _i < _len; _i++) { s = _ref[_i]; $("#source-top").append("<span class='ac-element ac-source' data-position='" + i + "'>" + s + "</span>"); $("#source-bottom").append("<span class='ac-element ac-source' data-position='" + i + "'>" + s + "</span>"); i += 1; } i = 0; _ref2 = this.doc.target; for (_j = 0, _len2 = _ref2.length; _j < _len2; _j++) { t = _ref2[_j]; if (!t) t = ""; $("#target-top").append("<span class='ac-element ac-target' data-position='" + i + "'>" + t + "</span>"); $("#target-bottom").append("<span class='ac-element ac-target' data-position='" + i + "'>" + t + "</span>"); i += 1; } $('.ac-element').click(function(event) { var position; position = $(event.target).data('position'); return _this.change_position(position); }); this.length = $("#source-top").children().length; this.change_position(0); this.bind_events(); this.resize(); } AjaxCatTranslation.prototype.time = function() { var sec, t; sec = parseInt((Date.now() - this.now) / 1000); t = "time from start: " + (parseInt(sec / 60)) + ":" + (sec % 60); $("#time").html(t); return setTimeout(this.time, 10); }; AjaxCatTranslation.prototype.change_experiment_sentence = function() { var _this = this; if (this.cur_position + 1 < this.doc.source.length) { return this.change_position(this.cur_position + 1); } else { $("#send-experiment").hide(); return $.ajax("/admin/save_experiment", { data: { "log_id": this.doc.task_id, log: JSON.stringify(this.doc) }, type: "post", success: function() { alert("Experiment saved."); return window.location = "/"; }, error: function() { return alert("Could not save experiment."); } }); } }; AjaxCatTranslation.prototype.prepare_test = function() { var _this = this; AjaxCatList.delete_document(this.hash); this.experiment = true; $("#save").hide(); $("#experiment-settings").show(); $("#top-translations").hide(); $("#bottom-translations").hide(); $("#send-experiment").show(); $("#send-experiment").click(function() { return _this.change_experiment_sentence(); }); this.doc.log = []; this.time(); return $("#log").append("<h2>Log</h2>"); }; AjaxCatTranslation.prototype.log = function(type, param) { var new_log; if (type == null) type = false; if (param == null) param = false; if (!this.doc.task_id) return; new_log = { time: Date.now(), target: $("#target-sentence").val() }; if (type) new_log.type = type; if (param) new_log.param = param; if (this.doc.log[this.cur_position] === void 0) { this.doc.log[this.cur_position] = []; } this.doc.log[this.cur_position].push(new_log); return $("#log").append(JSON.stringify(new_log) + "<br>"); }; AjaxCatTranslation.prototype.resize = function() { var width; width = $(window).width(); return $("#translation-table-container").width(width - 60); }; AjaxCatTranslation.prototype.bind_events = function() { var _this = this; $("#target-sentence").on('keyup', function() {}); $("#target-sentence").on('click', function() {}); $("#target-sentence").on('keydown', function(event) { var ar, text, word; _this.log("keydown", event.which); switch (event.which) { case 13: return _this.suggestions.take_suggestion(); case 32: text = $("#target-sentence").val(); text = Utils.trim(text); if (text.length > 0) { ar = text.split(/[ ]+/); word = ar[ar.length - 1]; return _this.table.mark_words(word); } break; case 33: if (_this.cur_position > 0) { _this.change_position(_this.cur_position - 1); } return false; case 34: if ((_this.cur_position + 1) < _this.length) { _this.change_position(_this.cur_position + 1); } return false; case 38: return _this.suggestions.up(); case 40: return _this.suggestions.down(); default: return $(window).trigger('loadSuggestions'); } }); $("#preview").click(function() { _this.save_target(); _this.show_preview(); return false; }); return $("#save").click(function() { _this.save_target(); return alert("Translation was saved into your browser."); }); }; AjaxCatTranslation.prototype.show_preview = function() { $("#source").text(this.doc.source.join('')); $("#target").text(this.doc.target.join('')); return $('#translation-preview-modal').modal('show'); }; AjaxCatTranslation.prototype.save_target = function() { var el, tar, _i, _len, _ref; $("#target-top .ac-target[data-position=" + this.cur_position + "]").text($("#target-sentence").val()); $("#target-bottom .ac-target[data-position=" + this.cur_position + "]").text($("#target-sentence").val()); tar = []; _ref = $("#target-top .ac-target"); for (_i = 0, _len = _ref.length; _i < _len; _i++) { el = _ref[_i]; tar.push($(el).text()); } this.doc.target = tar; return localStorage.setItem(this.doc.id, JSON.stringify(this.doc)); }; AjaxCatTranslation.prototype.load_translation_table = function(sentence) { var _this = this; if (this.table_request) this.table_request.abort(); sentence = Utils.tokenize(sentence); if (sentence.match(/^[\ \t]*$/)) { $("#translation-table-container").html(""); this.suggestions.clear(); return; } $("#translation-table-container").text(""); return this.table_request = $.ajax("/api/table", { data: { pair: this.pair, q: sentence }, success: function(data) { _this.log("translation_table_loaded", data); _this.table = new TranslationTable(_this, data); $("#translation-table-container").html(_this.table.get_table()); return $(window).trigger('loadSuggestions'); }, error: function() {} }); }; AjaxCatTranslation.prototype.change_position = function(position) { if (this.experiment) { if (!((position === 0 && this.cur_position === false) || (this.cur_position + 1 === position))) { return; } this.param_suggestion = this.doc.options[position].suggestion; $("#suggestion-panel-is-on").text(this.param_suggestion); $("#translated-status").text("translating sentence " + (position + 1) + " out of " + this.doc.source.length); if ((position + 1) === this.doc.source.length) { $("#send-experiment").text("Finish experiment"); } this.log("start"); } this.suggestions.clear(); if (this.cur_position !== false) this.save_target(); $("#source-top").children().slice(0, position).show(); $("#source-top").children().slice(position, this.length).hide(); $("#source-bottom").children().slice(0, position + 1).hide(); $("#source-bottom").children().slice(position + 1, this.length).show(); $("#target-top").children().slice(0, position).show(); $("#target-top").children().slice(position, this.length).hide(); $("#target-bottom").children().slice(0, position + 1).hide(); $("#target-bottom").children().slice(position + 1, this.length).show(); $("#source-sentence").text($("#source-top .ac-source[data-position=" + position + "]").text()); $("#target-sentence").val($("#target-top .ac-target[data-position=" + position + "]").text()); this.cur_position = position; $("#target-sentence").focus(); return this.load_translation_table($("#source-top .ac-source[data-position=" + position + "]").text()); }; AjaxCatTranslation.prototype.add_words = function(words, change_covered) { var text; if (change_covered == null) change_covered = false; text = $("#target-sentence").val(); text = Utils.trim(text); words = Utils.trim(words); text = Utils.trim(text); text += " " + words + " "; $("#target-sentence").val(text); return $("#target-sentence").click(); }; return AjaxCatTranslation;
})();
Suggestions = (function() {
function Suggestions(translation, limit) { var i, sug, _this = this; this.translation = translation; if (limit == null) limit = 5; this.down = __bind(this.down, this); this.up = __bind(this.up, this); this.set_position = __bind(this.set_position, this); this.get_position = __bind(this.get_position, this); this.positions = __bind(this.positions, this); this.process_suggestions = __bind(this.process_suggestions, this); this.take_suggestion = __bind(this.take_suggestion, this); this.load_suggestions = __bind(this.load_suggestions, this); this.clear = __bind(this.clear, this); i = 0; while (i < limit) { sug = $("<div>", { "class": 'ac-suggestion', 'data-suggestion-position': i, click: function() { return _this.take_suggestion(); }, mouseover: function(event) { var target; target = $(event.currentTarget); if (target.hasClass('suggestion-enabled')) { return _this.set_position(target.data('suggestion-position')); } } }); $("#suggestions-container").append(sug); i += 1; } $(window).bind('loadSuggestions', function() { _this.load_suggestions(); return $("#target-sentence").focus(); }); } Suggestions.prototype.clear = function() { if (this.suggestion_request) this.suggestion_request.abort(); $(".ac-suggestion").text(""); $(".ac-suggestion").removeClass('suggestion-enabled'); return $(".ac-suggestion").removeClass('suggestion-active'); }; Suggestions.prototype.load_suggestions = function() { var covered, data, sentence, translated, _this = this; this.clear(); if (!this.translation.param_suggestion) return; sentence = $("#source-sentence").text(); sentence = Utils.tokenize(sentence); translated = Utils.tokenize($("#source-target").text()); covered = this.translation.table.covered_vector(); data = { pair: this.translation.pair, q: Utils.tokenize(sentence), covered: covered, translated: translated }; this.translation.log("load_suggestions", data); return this.suggestion_request = $.ajax("/api/suggestion", { data: data, success: function(data) { data = JSON.parse(data); return _this.process_suggestions(data); }, error: function() {} }); }; Suggestions.prototype.take_suggestion = function() { var from, text, to; if (this.get_position() === false) return; text = $(".suggestion-active span").text(); from = $(".suggestion-active").data('from'); to = $(".suggestion-active").data('to'); this.translation.add_words(text); log_data({ text: text, from: from, to: to }); this.translation.table.mark_interval(from, to); return this.load_suggestions(); }; Suggestions.prototype.process_suggestions = function(data) { var el, i, suggestion, translation, _i, _len, _ref, _results; i = 0; _ref = data.suggestions; _results = []; for (_i = 0, _len = _ref.length; _i < _len; _i++) { suggestion = _ref[_i]; translation = $("#target-sentence").val(); el = $(".ac-suggestion").slice(i, i + 1); el.html("" + translation + " <span>" + suggestion.text + "</span>"); el.data('from', suggestion.from); el.data('to', suggestion.to); el.addClass('suggestion-enabled'); _results.push(i += 1); } return _results; }; Suggestions.prototype.positions = function() { return $(".suggestion-enabled").length; }; Suggestions.prototype.get_position = function() { var el; el = $(".suggestion-active"); if (!el.length) return false; return el.data('suggestion-position'); }; Suggestions.prototype.set_position = function(position) { $(".suggestion-active").removeClass('suggestion-active'); return $(".suggestion-enabled[data-suggestion-position=" + position + "]").addClass('suggestion-active'); }; Suggestions.prototype.up = function() { var position; position = this.get_position(); if (position === false) return; return this.set_position(position - 1); }; Suggestions.prototype.down = function() { var position; position = this.get_position(); if (position === false) { this.set_position(0); return; } if ((position + 1) < this.positions()) return this.set_position(position + 1); }; return Suggestions;
})();
TranslationTable = (function() {
function TranslationTable(translation, data) { this.translation = translation; this.covered_vector = __bind(this.covered_vector, this); this.unmark_position = __bind(this.unmark_position, this); this.mark_position = __bind(this.mark_position, this); this.mark_interval = __bind(this.mark_interval, this); this.mark_words_OLD = __bind(this.mark_words_OLD, this); this.mark_words = __bind(this.mark_words, this); this.position_marked = __bind(this.position_marked, this); this.get_row = __bind(this.get_row, this); this.get_header = __bind(this.get_header, this); this.get_table = __bind(this.get_table, this); this.data = JSON.parse(data); } TranslationTable.prototype.get_table = function() { var ret, row, _i, _len, _ref; ret = $("<table>", { "class": 'translation-table' }); ret.append(this.get_header()); _ref = this.data.table; for (_i = 0, _len = _ref.length; _i < _len; _i++) { row = _ref[_i]; ret.append(this.get_row(row)); } return ret; }; TranslationTable.prototype.get_header = function() { var i, ret, src, word, _i, _len, _ref, _this = this; ret = $("<tr>"); i = 0; _ref = this.data.source; for (_i = 0, _len = _ref.length; _i < _len; _i++) { word = _ref[_i]; src = $("<th>", { "class": 'ac-source', html: word, "data-position": i, click: function(event) { var position; position = parseInt($(event.currentTarget).data('position')); if (_this.position_marked(position)) { _this.unmark_position(position); } else { _this.mark_position(position); } return $(window).trigger('loadSuggestions'); } }); ret.append(src); i += 1; } return ret; }; TranslationTable.prototype.get_row = function(row) { var cell, content, i, len, ret, word, _i, _len, _this = this; ret = $("<tr>"); i = 0; for (_i = 0, _len = row.length; _i < _len; _i++) { word = row[_i]; len = parseInt(word.w); if (!word.str) { ret.append("<td colspan='" + len + "' class='ac-empty'></td>"); } else { cell = $("<td colspan='" + len + "' class='ac-word'></td>"); content = $("<div>", { 'data-position-from': i, 'data-position-to': i + len - 1, html: word.str, click: function(event) { i = parseInt($(event.currentTarget).data('position-from')); while (i <= parseInt($(event.currentTarget).data('position-to'))) { _this.mark_position(i); i += 1; } _this.translation.add_words($(event.currentTarget).text()); return $(window).trigger('loadSuggestions'); } }); cell.append(content); ret.append(cell); } i += len; } return ret; }; TranslationTable.prototype.position_marked = function(position) { if ($("th.ac-source").slice(position, position + 1).hasClass('ac-selected')) { return true; } return false; }; TranslationTable.prototype.mark_words = function(word) { var best_element, best_result, el, element_text, maximal_acceptable_distance, result, _i, _len, _ref; word = Utils.trim(word); best_result = 10000; best_element = null; maximal_acceptable_distance = 1; if (word.length < 5) maximal_acceptable_distance = 0; if (word.length > 10) maximal_acceptable_distance = 2; _ref = $(".ac-word div"); for (_i = 0, _len = _ref.length; _i < _len; _i++) { el = _ref[_i]; element_text = Utils.trim($(el).text()); result = Utils.edit_distance(word, element_text); if (result < best_result) { best_result = result; best_element = $(el); } } if (best_element !== null && best_result <= maximal_acceptable_distance) { return this.mark_interval(best_element.data('position-from'), best_element.data('position-to')); } }; TranslationTable.prototype.mark_words_OLD = function(words) { var el, el_text, _i, _len, _ref; console.log("MARKING WORDS: " + words); words = "" + words + " "; _ref = $(".ac-word div"); for (_i = 0, _len = _ref.length; _i < _len; _i++) { el = _ref[_i]; el_text = Utils.trim($(el).text()); el_text = "" + el_text + " "; if ((words.indexOf(el_text) === 0) && (words.length >= el_text.length)) { this.mark_interval($(el).data('position-from'), $(el).data('position-to')); $(window).trigger('loadSuggestions'); words = words.substr(el_text.length); words = Utils.trim(words); words = "" + words + " "; if (!(words.length > 0)) return; } } }; TranslationTable.prototype.mark_interval = function(from, to) { var i, _results; i = from; _results = []; while (i <= to) { this.mark_position(i); _results.push(i += 1); } return _results; }; TranslationTable.prototype.mark_position = function(position) { return $("th.ac-source").slice(position, position + 1).addClass('ac-selected'); }; TranslationTable.prototype.unmark_position = function(position) { return $("th.ac-source").slice(position, position + 1).removeClass('ac-selected'); }; TranslationTable.prototype.covered_vector = function() { var el, ret, _i, _len, _ref; ret = ""; _ref = $("th.ac-source"); for (_i = 0, _len = _ref.length; _i < _len; _i++) { el = _ref[_i]; if ($(el).hasClass('ac-selected')) { ret += "1"; } else { ret += "0"; } } return ret; }; return TranslationTable;
})();
Utils = (function() {
function Utils() {} Utils.random_string = function() { var chars, i, ret, rnum; chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz"; ret = ""; for (i = 0; i <= 16; i++) { rnum = Math.floor(Math.random() * chars.length); ret += chars.substring(rnum, rnum + 1); } return ret; }; Utils.tokenize = function(input) { input = input.toLowerCase(); input = input.replace(/\,/g, " , "); input = input.replace(/\./g, " . "); input = input.replace(/\n/g, ""); input = input.replace(/\ \ /g, " "); return input; }; Utils.split_source = function(text) { var c, delimiters, firstSplit, input, last, line, spliting, white, _i, _len; delimiters = [".", "!", "?"]; line = ""; spliting = false; firstSplit = false; input = new Array(); white = 0; last = ' '; for (_i = 0, _len = text.length; _i < _len; _i++) { c = text[_i]; if (spliting === true) { if (c !== ' ' && c !== '\n' && c !== '\t') { if (white > 0 || last === '\n') { input[input.length] = line; line = ""; } spliting = false; } else { ++white; } } line += c; if (c === '.' || c === '!' || c === '?' || c === '\n') { spliting = true; white = 0; } last = c; } input[input.length] = line; return input; }; Utils.trim = function(text) { return text.replace(/^\s+|\s+$/g, ""); }; Utils.edit_distance = function(source, target) { var a, i, j, substitute_cost, _i, _ref, _ref2, _ref3, _ref4, _results; a = []; for (i = 0, _ref = source.length; 0 <= _ref ? i <= _ref : i >= _ref; 0 <= _ref ? i++ : i--) { a[i] = new Array(target.length + 1); a[i][0] = i; } a[0] = (function() { _results = []; for (var _i = 0, _ref2 = target.length; 0 <= _ref2 ? _i <= _ref2 : _i >= _ref2; 0 <= _ref2 ? _i++ : _i--){ _results.push(_i); } return _results; }).apply(this); for (i = 1, _ref3 = source.length; 1 <= _ref3 ? i <= _ref3 : i >= _ref3; 1 <= _ref3 ? i++ : i--) { for (j = 1, _ref4 = target.length; 1 <= _ref4 ? j <= _ref4 : j >= _ref4; 1 <= _ref4 ? j++ : j--) { substitute_cost = a[i - 1][j - 1]; if (source.charAt(i - 1) !== target.charAt(j - 1)) substitute_cost += 1; a[i][j] = Math.min(substitute_cost, a[i - 1][j] + 1, a[i][j - 1] + 1); } } return a[source.length][target.length]; }; return Utils;
}).call(this);