"use strict";
var Datum = require("./Datum").Datum;
var FieldDBObject = require("./../FieldDBObject").FieldDBObject;
/**
* @class The LanguageDatum widget is the place where all linguistic data is
* entered; one at a time.
*
* @property {DatumField} transcription The transcription field generally
* corresponds to the first line in linguistic examples that can
* either be written in the language's orthography or a
* romanization of the language. An additional field can be added
* if the language has a non-roman script. (This was previously called the utterance field).
* @property {DatumField} gloss The gloss field corresponds to the gloss
* line in linguistic examples where the morphological details of
* the words are displayed.
* @property {DatumField} translation The translation field corresponds to
* the third line in linguistic examples where in general an
* English translation. An additional field can be added if
* translations into other languages is needed.
* @property {DatumField} judgement The judgement is the grammaticality
* judgement associated with the datum, so grammatical,
* ungrammatical, felicitous, unfelicitous etc.
* @property {AudioVisual} audioVideo LanguageDatums can be associated with an audio or video
* file.
* @property {Session} session The session provides details about the set of
* data elicited. The session will contain details such as date,
* language, consultant etc.
* @property {Comments} comments The comments is a collection of comments
* associated with the datum, this is meant for comments like on a
* blog, not necessarily notes, which can be encoded in a
* field.(Use Case: team discussing a particular datum)
* @property {DatumTags} datumtags The datum tags are a collection of tags
* associated with the datum. These are made completely by the
* user.They are like blog tags, a way for the user to make
* categories without make a hierarchical structure, and make
* datum easier for search.
* @property {Date} dateEntered The date the LanguageDatum was first saved.
* @property {Date} dateModified The date the LanguageDatum was last saved.
*
* @description The initialize function brings up the datum widget in small
* view with one set of datum fields. However, the datum widget
* can contain more than datum field set and can also be viewed
* in full screen mode.
*
* @name LanguageDatum
* @extends Datum
* @constructs
*/
var LanguageDatum = function LanguageDatum(options) {
if (!this._fieldDBtype) {
this._fieldDBtype = "LanguageDatum";
}
if (options && typeof options === "string") {
this.debug("Turning LanguageDatum " + options + " to an object");
options = {
orthography: options
};
}
this.debug("Constructing LanguageDatum: ", options);
Datum.apply(this, [options]);
};
LanguageDatum.prototype = Object.create(Datum.prototype, /** @lends LanguageDatum.prototype */ {
constructor: {
value: LanguageDatum
},
length: {
get: function() {
if (this.utterance) {
return this.utterance.length;
}
if (this.orthography) {
return this.orthography.length;
}
if (this.morphemes) {
return this.morphemes.length;
}
}
},
orthography: {
configurable: true,
get: function() {
if (this.fields && this.fields.orthography) {
this.debug(" getting orthography " + this._id + " to " + this.fields.orthography.value);
return this.fields.orthography.value;
} else {
return FieldDBObject.DEFAULT_STRING;
}
},
set: function(value) {
if (!this.fields || !this.fields.orthography) {
this.addField("orthography");
}
this.debug(" Setting orthography " + this._id + " to " + value);
this.fields.orthography.value = value;
}
},
utterance: {
configurable: true,
get: function() {
if (this.fields && this.fields.utterance) {
return this.fields.utterance.value;
} else {
return FieldDBObject.DEFAULT_STRING;
}
},
set: function(value) {
if (!this.fields || !this.fields.utterance) {
this.addField("utterance");
}
this.fields.utterance.value = value;
}
},
/**
* Morphemes of the datum, if morphemes is empty it will provide the utterance
* or the orthography as a last resort copy
*
* @return {String} morphemes, or utterance or orthography
*/
morphemes: {
configurable: true,
get: function() {
if (this.fields && this.fields.morphemes) {
if (this.fields.morphemes.value) {
return this.fields.morphemes.value;
}
var placeholder = this.utterance || this.orthography || FieldDBObject.DEFAULT_STRING;
this.debug("morphemes is not defined so using " + placeholder);
return placeholder + "";
} else {
return FieldDBObject.DEFAULT_STRING;
}
},
set: function(value) {
this.debug("setting morphemes " + value);
if (!this.fields || !this.fields.morphemes) {
this.addField("morphemes");
}
this.debug(" this.fields.morphemes ", this.fields.morphemes);
this.fields.morphemes.value = value;
this.debug(" this.fields.morphemes.value ", this.fields.morphemes.value);
}
},
allomorphs: {
configurable: true,
get: function() {
if (this.fields && this.fields.allomorphs) {
return this.fields.allomorphs.value;
} else {
return FieldDBObject.DEFAULT_STRING;
}
},
set: function(value) {
if (!this.fields || !this.fields.allomorphs) {
this.addField("allomorphs");
}
this.fields.allomorphs.value = value;
}
},
gloss: {
configurable: true,
get: function() {
if (this.fields && this.fields.gloss) {
return this.fields.gloss.value;
} else {
return FieldDBObject.DEFAULT_STRING;
}
},
set: function(value) {
if (!this.fields || !this.fields.gloss) {
this.addField("gloss");
}
this.fields.gloss.value = value;
}
},
syntacticCategory: {
configurable: true,
get: function() {
if (this.fields && this.fields.syntacticCategory) {
return this.fields.syntacticCategory.value;
} else {
return FieldDBObject.DEFAULT_STRING;
}
},
set: function(value) {
if (!this.fields || !this.fields.syntacticCategory) {
this.addField("syntacticCategory");
}
this.fields.syntacticCategory.value = value;
}
},
translation: {
configurable: true,
get: function() {
if (this.fields && this.fields.translation) {
return this.fields.translation.value;
} else {
return FieldDBObject.DEFAULT_STRING;
}
},
set: function(value) {
if (!this.fields || !this.fields.translation) {
this.addField("translation");
}
this.fields.translation.value = value;
}
},
igt: {
get: function() {
var igtLines = {},
parallelText = {},
tuples = [],
feederWord,
fullWord,
lengthOfLongestIGTLineInWords,
igtLine,
cellIndex,
tuple;
var punctuationToRemove = /[#?!,\/\(\)\*\#]/g;
var whiteSpaceSplit = /[ \t\n]+/;
// var leipzigSplit = /[=-]+/;
var cleanUngrammaticalitySubstitutions = false;
this.fields.map(function(field) {
if (field.type && field.type.indexOf("parallelText") > -1) {
parallelText[field.id] = field.value;
}
if (!field.type || field.type.indexOf("IGT") === -1) {
return;
}
var chunks = field.value.replace(/#?!.,\//g, "").split(whiteSpaceSplit);
chunks = chunks.map(function(chunk) {
if (cleanUngrammaticalitySubstitutions) {
// If the token it not null or the empty string
if (chunk) {
// Replace (*_) with _
feederWord = chunk.replace(/\(\*[^)]*\)/g, "$1");
// Replace *(_) with _
feederWord = feederWord.replace(/\*\(([^)]*)\)/, "$1");
// Remove all remaining punctuation
fullWord = feederWord.replace(punctuationToRemove, "");
chunk = fullWord;
}
}
// return chunk.split(leipzigSplit);
return chunk;
});
igtLines[field.id] = chunks;
});
this.debug("Collected all the IGT lines", igtLines);
this.debug("Collected all the Paralel Text lines", parallelText);
// Build triples
lengthOfLongestIGTLineInWords = 0;
for (igtLine in igtLines) {
if (igtLines[igtLine] && igtLines[igtLine].length > lengthOfLongestIGTLineInWords) {
lengthOfLongestIGTLineInWords = igtLines[igtLine].length;
}
}
// for each word
for (cellIndex = 0; cellIndex < lengthOfLongestIGTLineInWords; cellIndex++) {
tuple = {};
// for each row of the igt
for (igtLine in igtLines) {
this.debug("working on " + igtLine, igtLines[igtLine]);
if (igtLines[igtLine] && igtLines[igtLine].length > cellIndex && igtLines[igtLine][cellIndex]) {
tuple[igtLine] = igtLines[igtLine][cellIndex];
} else {
tuple[igtLine] = "";
}
}
tuples.push(tuple);
}
this.debug("IGT+ tuples", tuples);
return {
tuples: tuples,
parallelText: parallelText
};
},
set: function() {
this.warn("Setting the igt has to be copy pasted from one of the other codebases");
}
},
/**
* The LaTeXiT function automatically mark-ups an example in LaTeX code
* (\exg. \"a) and then copies it on the export modal so that when the user
* switches over to their LaTeX file they only need to paste it in.
*
* We did a poll on Facebook among EGGers, and other linguists we know and
* found that Linguex was very popular, and GB4E, so we did the export in
* GB4E.
*/
/* jshint ignore:start */
laTeXiT: {
value: function(showInExportModal) {
this.debug(showInExportModal);
//corpus's most frequent fields
var frequentFields;
if (this.application && this.application.corpus && this.application.corpus.frequentFields) {
frequentFields = this.application.corpus.frequentFields;
} else {
frequentFields = this.fields.map(function(field) {
return field.id
});
}
//this datum/datalist's datumfields and their names
var fields = this.fields.map(function(field) {
return field.value;
});
var fieldLabels = this.fields.map(function(field) {
return field.id;
});
//setting up for IGT case...
var judgementIndex = -1;
var judgement = "";
var utteranceIndex = -1;
var utterance = "";
var morphemesIndex = -1;
var morphemes = "";
var glossIndex = -1;
var gloss = "";
var translationIndex = -1;
var translation = "";
var result = "\n\\begin{exe} \n \\ex \[";
//IGT case:
if (this.datumIsInterlinearGlossText()) {
/* get the key pieces of the IGT and delete them from the fields and fieldLabels arrays*/
judgementIndex = fieldLabels.indexOf("judgement");
if (judgementIndex >= 0) {
judgement = fields[judgementIndex];
fieldLabels.splice(judgementIndex, 1);
fields.splice(judgementIndex, 1);
}
utteranceIndex = fieldLabels.indexOf("utterance");
if (utteranceIndex >= 0) {
utterance = fields[utteranceIndex];
fieldLabels.splice(utteranceIndex, 1);
fields.splice(utteranceIndex, 1);
}
morphemesIndex = fieldLabels.indexOf("morphemes");
if (morphemesIndex >= 0) {
morphemes = fields[morphemesIndex];
fieldLabels.splice(morphemesIndex, 1);
fields.splice(morphemesIndex, 1);
}
glossIndex = fieldLabels.indexOf("gloss");
if (glossIndex >= 0) {
gloss = fields[glossIndex];
fieldLabels.splice(glossIndex, 1);
fields.splice(glossIndex, 1);
}
translationIndex = fieldLabels.indexOf("translation");
if (translationIndex >= 0) {
translation = fields[translationIndex];
fieldLabels.splice(translationIndex, 1);
fields.splice(translationIndex, 1);
}
//print the main IGT, escaping special latex chars
/* ignore unnecessary escapement */
result = result + this.escapeLatexChars(judgement) + "\]\{" + this.escapeLatexChars(utterance) +
"\n \\gll " + this.escapeLatexChars(morphemes) + "\\\\" +
"\n " + this.escapeLatexChars(gloss) + "\\\\" +
"\n \\trans " + this.escapeLatexChars(translation) + "\}" +
"\n\\label\{\}";
}
//remove any empty fields from our arrays
for (var i = fields.length - 1; i >= 0; i--) {
if (!fields[i]) {
fields.splice(i, 1);
fieldLabels.splice(i, 1);
}
}
/*throughout this next section, print frequent fields and infrequent ones differently
frequent fields get latex'd as items in a description and infrequent ones are the same,
but commented out.*/
if (fields && (fields.length > 0)) {
var numInfrequent = 0;
for (var field in fields) {
if (frequentFields.indexOf(fieldLabels[field]) >= 0) {
break;
}
numInfrequent++;
}
if (numInfrequent !== fieldLabels.length) {
result = result + "\n \\begin\{description\}";
} else {
result = result + "\n% \\begin\{description\}";
}
for (field in fields) {
if (fields[field] && (frequentFields.indexOf(fieldLabels[field]) >= 0)) {
result = result + "\n \\item\[\\sc\{" + this.escapeLatexChars(fieldLabels[field]) + "\}\] " + this.escapeLatexChars(fields[field]);
} else if (fields[field]) {
/* If as a field that is designed for LaTex dont excape the LaTeX characters */
if (fieldLabels[field].toLowerCase().indexOf("latex") > -1) {
result = result + "\n " + fields[field];
} else {
result = result + "\n% \\item\[\\sc\{" + this.escapeLatexChars(fieldLabels[field]) + "\}\] " + this.escapeLatexChars(fields[field]);
}
}
}
if (numInfrequent !== fieldLabels.length) {
result = result + "\n \\end\{description\}";
} else {
result = result + "\n% \\end\{description\}";
}
}
result = result + "\n\\end{exe}\n\n";
return result;
}
},
/* jshint ignore:end */
datumIsInterlinearGlossText: {
value: function(fieldLabels) {
if (!fieldLabels) {
fieldLabels = this.fields.map(function(field) {
return field.id;
});
}
var utteranceOrMorphemes = false;
var gloss = false;
var trans = false;
for (var fieldLabel in fieldLabels) {
if (fieldLabels[fieldLabel] === "utterance" || fieldLabels[fieldLabel] === "morphemes") {
utteranceOrMorphemes = true;
}
if (fieldLabels[fieldLabel] === "gloss") {
gloss = true;
}
if (fieldLabels[fieldLabel] === "translation") {
trans = true;
}
}
if (gloss || utteranceOrMorphemes || trans) {
return true;
} else {
return false;
}
}
}
});
exports.LanguageDatum = LanguageDatum;