blob: 45f24f55418868761f3a2b4c19a02d0b1aebab91 [file] [log] [blame]
/**
* Make annotations visible.
*
* @author Nils Diewald
*/
/*
- Scroll with a static left legend.
- Highlight (at least mark as bold) the match
- Scroll to match vertically per default
*/
var KorAP = KorAP || {};
(function (KorAP) {
"use strict";
KorAP._AvailableRE = new RegExp("^([^\/]+?)\/([^=]+?)(?:=(spans|rels|tokens))?$");
KorAP._TermRE = new RegExp("^([^\/]+?)(?:\/([^:]+?))?:(.+?)$");
KorAP._matchTerms = ["corpusID", "docID", "textID"];
// API requests
KorAP.API = KorAP.API || {};
// TODO: Make this async
KorAP.API.getMatchInfo = KorAP.API.getMatchInfo || function () { return {} };
KorAP.MatchInfo = {
/**
* Create a new annotation object.
* Expects an array of available foundry/layer=type terms.
* Supported types are 'spans', 'tokens' and 'rels'.
*/
create : function (match, available) {
if (arguments.length < 2)
throw new Error("Missing parameters");
return Object.create(KorAP.MatchInfo)._init(match, available);
},
_init : function (match, available) {
this._match = KorAP.Match.create(match);
this._available = {
tokens : [],
spans : [],
rels : []
};
for (var i = 0; i < available.length; i++) {
var term = available[i];
// Create info layer objects
try {
var layer = KorAP.InfoLayer.create(term);
this._available[layer.type].push(layer);
}
catch (e) {
continue;
};
};
return this;
},
/**
* Return a list of parseable tree annotations.
*/
getSpans : function () {
return this._available.spans;
},
/**
* Return a list of parseable token annotations.
*/
getTokens : function () {
return this._available.tokens;
},
/**
* Return a list of parseable relation annotations.
*/
getRels : function () {
return this._available.rels;
},
/**
* Get table object.
*/
getTable : function (tokens) {
var focus = [];
// Get all tokens
if (tokens === undefined) {
focus = this.getTokens();
}
// Get only some tokens
else {
// Push newly to focus array
for (var i = 0; i < tokens.length; i++) {
var term = tokens[i];
try {
// Create info layer objects
var layer = KorAP.InfoLayer.create(term);
layer.type = "tokens";
focus.push(layer);
}
catch (e) {
continue;
};
};
};
// No tokens chosen
if (focus.length == 0)
return;
// Get info (may be cached)
var matchResponse = KorAP.API.getMatchInfo(
this._match,
{ 'spans' : true, 'layer' : focus }
);
// Get snippet from match info
if (matchResponse["snippet"] !== undefined) {
this._table = KorAP.MatchTable.create(matchResponse["snippet"]);
return this._table;
};
return null;
}
/*
// Parse snippet for table visualization
getTree : function (foundry, layer) {
}
*/
};
KorAP.Match = {
create : function (match) {
return Object.create(KorAP.Match)._init(match);
},
_init : function (match) {
for (var i in KorAP._matchTerms) {
var term = KorAP._matchTerms[i];
if (match[term] !== undefined) {
this[term] = match[term];
}
else {
this[term] = undefined;
}
};
return this;
},
};
/**
*
* Alternatively pass a string as <tt>base/s=span</tt>
*
* @param foundry
*/
KorAP.InfoLayer = {
create : function (foundry, layer, type) {
return Object.create(KorAP.InfoLayer)._init(foundry, layer, type);
},
_init : function (foundry, layer, type) {
if (foundry === undefined)
throw new Error("Missing parameters");
if (layer === undefined) {
if (KorAP._AvailableRE.exec(foundry)) {
this.foundry = RegExp.$1;
this.layer = RegExp.$2;
this.type = RegExp.$3;
}
else {
throw new Error("Missing parameters");
};
}
else {
this.foundry = foundry;
this.layer = layer;
this.type = type;
};
if (this.type === undefined)
this.type = 'tokens';
return this;
}
};
KorAP.MatchTable = {
create : function (snippet) {
return Object.create(KorAP.MatchTable)._init(snippet);
},
_init : function (snippet) {
// Create html for traversal
var html = document.createElement("div");
html.innerHTML = snippet;
this._pos = 0;
this._token = [];
this._info = [];
this._foundry = {};
this._layer = {};
// Parse the snippet
this._parse(html.childNodes);
html.innerHTML = '';
return this;
},
length : function () {
return this._pos;
},
getToken : function (pos) {
if (pos === undefined)
return this._token;
return this._token[pos];
},
getValue : function (pos, foundry, layer) {
return this._info[pos][foundry + '/' + layer]
},
getLayerPerFoundry : function (foundry) {
return this._foundry[foundry]
},
getFoundryPerLayer : function (layer) {
return this._layer[layer];
},
// Parse the snippet
_parse : function (children) {
// Get all children
for (var i in children) {
var c = children[i];
// Create object on position unless it exists
if (this._info[this._pos] === undefined)
this._info[this._pos] = {};
// Store at position in foundry/layer as array
var found = this._info[this._pos];
// Element with title
if (c.nodeType === 1) {
if (c.getAttribute("title") &&
KorAP._TermRE.exec(c.getAttribute("title"))) {
// Fill position with info
var foundry, layer, value;
if (RegExp.$2) {
foundry = RegExp.$1;
layer = RegExp.$2;
}
else {
foundry = "base";
layer = RegExp.$1
};
value = RegExp.$3;
if (found[foundry + "/" + layer] === undefined)
found[foundry + "/" + layer] = [];
// Push value to foundry/layer at correct position
found[foundry + "/" + layer].push(RegExp.$3);
// Set foundry
if (this._foundry[foundry] === undefined)
this._foundry[foundry] = {};
this._foundry[foundry][layer] = 1;
// Set layer
if (this._layer[layer] === undefined)
this._layer[layer] = {};
this._layer[layer][foundry] = 1;
};
// depth search
if (c.hasChildNodes())
this._parse(c.childNodes);
}
// Leaf node
// store string on position and go to next string
else if (c.nodeType === 3) {
if (c.nodeValue.match(/[a-z0-9]/i))
this._token[this._pos++] = c.nodeValue;
};
};
delete this._info[this._pos];
},
element : function () {
// First the legend table
var d = document;
var table = d.createElement('table');
var tr = table.appendChild(d.createElement('thead'))
.appendChild(
d.createElement('tr')
);
var addCell = function (type, name) {
var c = this.appendChild(d.createElement(type))
if (name === undefined)
return c;
if (name instanceof Array) {
for (var n = 0; n < name.length; n++) {
c.appendChild(d.createTextNode(name[n]));
if (n !== name.length - 1) {
c.appendChild(d.createElement('br'));
};
};
}
else {
c.appendChild(d.createTextNode(name));
};
};
tr.addCell = addCell;
// Add header information
tr.addCell('th', 'Foundry');
tr.addCell('th', 'Layer');
// Add tokens
for (var i in this._token) {
tr.addCell('th', this.getToken(i));
};
var tbody = table.appendChild(
d.createElement('tbody')
);
var foundryList = Object.keys(this._foundry).sort();
for (var f = 0; f < foundryList.length; f++) {
var foundry = foundryList[f];
var layerList =
Object.keys(this._foundry[foundry]).sort();
for (var l = 0; l < layerList.length; l++) {
var layer = layerList[l];
tr = tbody.appendChild(
d.createElement('tr')
);
tr.setAttribute('tabindex', 0);
tr.addCell = addCell;
tr.addCell('th', foundry);
tr.addCell('th', layer);
for (var v = 0; v < this.length(); v++) {
tr.addCell(
'td',
this.getValue(v, foundry, layer)
);
};
};
};
return table;
}
};
/*
KorAP.InfoFoundryLayer = {};
KorAP.InfoTree = {};
KorAP.MatchTable = {};
*/
}(this.KorAP));