blob: 90787800c46ab2741d00a345b936b9e94afd8dd4 [file] [log] [blame]
Nils Diewald7148c6f2015-05-04 15:07:53 +00001/**
Akronb6685bb2018-02-04 00:44:47 +01002 * Table representation of token-based
Nils Diewald7148c6f2015-05-04 15:07:53 +00003 * annotations of a match.
4 */
Akronb6685bb2018-02-04 00:44:47 +01005define([
6 'match/querycreator',
7 "util"
8], function (matchQueryCreator) {
9 /*
10 * TODO:
11 * Create base object for all matchinfo classes!
12 * TODO:
13 * Rename to match/annotationtable
14 */
Akron0b489ad2018-02-02 16:49:32 +010015 const _TermRE = new RegExp("^(?:([^\/]+?)\/)?([^:]+?):(.+?)$");
16 const d = document;
17
Nils Diewald0e6992a2015-04-14 20:13:52 +000018 return {
Nils Diewald7148c6f2015-05-04 15:07:53 +000019
20 /**
21 * Create new table view for a match
22 * based on a snippet string.
23 */
Nils Diewald0e6992a2015-04-14 20:13:52 +000024 create : function (snippet) {
25 return Object.create(this)._init(snippet);
26 },
Nils Diewald7148c6f2015-05-04 15:07:53 +000027
28 // Initialize table based on snippet
Nils Diewald0e6992a2015-04-14 20:13:52 +000029 _init : function (snippet) {
30 // Create html for traversal
Akron0b489ad2018-02-02 16:49:32 +010031 var html = d.createElement("div");
Nils Diewald0e6992a2015-04-14 20:13:52 +000032 html.innerHTML = snippet;
33
34 this._pos = 0;
35 this._token = [];
Akronad1e46a2018-09-19 15:55:40 +020036 this._mark = [];
37 this._markE = undefined;
Akron1a780fe2019-05-21 15:59:00 +020038 this._cutted = [];
Nils Diewald0e6992a2015-04-14 20:13:52 +000039 this._info = [];
40 this._foundry = {};
41 this._layer = {};
42
43 // Parse the snippet
Akronad1e46a2018-09-19 15:55:40 +020044 this._parse(html.childNodes, false);
Akronb6685bb2018-02-04 00:44:47 +010045
Nils Diewald0e6992a2015-04-14 20:13:52 +000046 html.innerHTML = '';
47 return this;
48 },
Akronb6685bb2018-02-04 00:44:47 +010049
50 // TODO: Destroy match!
51 destroy : function () {
52 this._matchCreator = undefined;
53 },
Nils Diewald7148c6f2015-05-04 15:07:53 +000054
55 /**
56 * Length of the table (columns),
57 * aka the number of tokens
58 * in the snippet.
59 */
Nils Diewald0e6992a2015-04-14 20:13:52 +000060 length : function () {
61 return this._pos;
62 },
63
Akronad1e46a2018-09-19 15:55:40 +020064
65 /**
66 * Move the viewport to the match
67 */
68 toMark : function () {
69 if (this._markE === undefined)
70 return;
71 this._markE.scrollIntoView({
72 inline: "start",
73 block: "nearest"
74 });
75 },
76
Nils Diewald7148c6f2015-05-04 15:07:53 +000077 /**
78 * Get the token in the snippet
79 * At a given position.
80 *
81 * @param pos
82 */
Nils Diewald0e6992a2015-04-14 20:13:52 +000083 getToken : function (pos) {
84 if (pos === undefined)
Akron916ec252016-11-10 17:06:32 +010085 return this._token;
Nils Diewald0e6992a2015-04-14 20:13:52 +000086 return this._token[pos];
87 },
Nils Diewald7148c6f2015-05-04 15:07:53 +000088
89 /**
90 * Get the annotation of a token
91 * in the snippet based on the position,
92 * the foundry, and the layer.
93 *
94 * @param pos
95 * @param foundry
96 * @param layer
97 */
Nils Diewald0e6992a2015-04-14 20:13:52 +000098 getValue : function (pos, foundry, layer) {
99 return this._info[pos][foundry + '/' + layer]
100 },
Nils Diewald0e6992a2015-04-14 20:13:52 +0000101
Akronaeceda72018-02-02 20:44:06 +0100102
Nils Diewald0e6992a2015-04-14 20:13:52 +0000103 // Parse the snippet
Akronad1e46a2018-09-19 15:55:40 +0200104 _parse : function (children, mark) {
Nils Diewald0e6992a2015-04-14 20:13:52 +0000105
106 // Get all children
Akron678c26f2020-10-09 08:52:50 +0200107 children.forEach(function(c) {
Nils Diewald0e6992a2015-04-14 20:13:52 +0000108
Akron916ec252016-11-10 17:06:32 +0100109 // Create object on position unless it exists
110 if (this._info[this._pos] === undefined) {
111 this._info[this._pos] = {};
112 };
Nils Diewald0e6992a2015-04-14 20:13:52 +0000113
Akron916ec252016-11-10 17:06:32 +0100114 // Store at position in foundry/layer as array
115 var found = this._info[this._pos];
Nils Diewald0e6992a2015-04-14 20:13:52 +0000116
Akron916ec252016-11-10 17:06:32 +0100117 // Element with title
118 if (c.nodeType === 1) {
Akronad1e46a2018-09-19 15:55:40 +0200119 var newMark = mark;
120
121 if (c.tagName === 'MARK') {
122 newMark = true;
123 }
124
Akron083ec572019-05-16 18:30:40 +0200125 else if (c.hasAttribute("title") &&
Akron916ec252016-11-10 17:06:32 +0100126 _TermRE.exec(c.getAttribute("title"))) {
Nils Diewald0e6992a2015-04-14 20:13:52 +0000127
Akron916ec252016-11-10 17:06:32 +0100128 // Fill position with info
129 var foundry, layer, value;
130 if (RegExp.$2) {
131 foundry = RegExp.$1;
132 layer = RegExp.$2;
133 }
134 else {
135 foundry = "base";
136 layer = RegExp.$1
137 };
Nils Diewald0e6992a2015-04-14 20:13:52 +0000138
Akron916ec252016-11-10 17:06:32 +0100139 value = RegExp.$3;
140
141 if (found[foundry + "/" + layer] === undefined) {
142 found[foundry + "/" + layer] = [value];
143 }
144 else {
Akron3b253d32018-07-15 10:16:06 +0200145 // if (found[foundry + "/" + layer].indexOf(value) === -1) {
146 if (!found[foundry + "/" + layer].includes(value)) {
Akron916ec252016-11-10 17:06:32 +0100147 // Push value to foundry/layer at correct position
148 found[foundry + "/" + layer].push(value);
149 };
150 }
Nils Diewald0e6992a2015-04-14 20:13:52 +0000151
Akron916ec252016-11-10 17:06:32 +0100152 // Set foundry
153 if (this._foundry[foundry] === undefined)
154 this._foundry[foundry] = {};
155 this._foundry[foundry][layer] = 1;
Nils Diewald0e6992a2015-04-14 20:13:52 +0000156
Akron916ec252016-11-10 17:06:32 +0100157 // Set layer
158 if (this._layer[layer] === undefined)
159 this._layer[layer] = {};
160 this._layer[layer][foundry] = 1;
Akron083ec572019-05-16 18:30:40 +0200161 }
162
163 // The current position marks a cut
164 else if (c.hasAttribute("class") && c.getAttribute("class") == "cutted") {
Akron1a780fe2019-05-21 15:59:00 +0200165 this._cutted.push(this._pos);
Akron083ec572019-05-16 18:30:40 +0200166 this._token[this._pos++] = "";
167 }
Nils Diewald0e6992a2015-04-14 20:13:52 +0000168
Akron916ec252016-11-10 17:06:32 +0100169 // depth search
170 if (c.hasChildNodes())
Akronad1e46a2018-09-19 15:55:40 +0200171 this._parse(c.childNodes, newMark);
Akron916ec252016-11-10 17:06:32 +0100172 }
Nils Diewald0e6992a2015-04-14 20:13:52 +0000173
Akron916ec252016-11-10 17:06:32 +0100174 // Leaf node
175 // store string on position and go to next string
176 else if (c.nodeType === 3) {
Akron158fce12019-12-17 14:43:29 +0100177 if (c.nodeValue.match(/[a-z0-9\u25ae]/iu)) {
Akronad1e46a2018-09-19 15:55:40 +0200178 this._mark[this._pos] = mark ? true : false;
Akron916ec252016-11-10 17:06:32 +0100179 this._token[this._pos++] = c.nodeValue;
Akronad1e46a2018-09-19 15:55:40 +0200180 };
Akron916ec252016-11-10 17:06:32 +0100181 };
Akron678c26f2020-10-09 08:52:50 +0200182 }, this);
Nils Diewald0e6992a2015-04-14 20:13:52 +0000183
184 delete this._info[this._pos];
185 },
186
187
188 /**
189 * Get HTML table view of annotations.
190 */
191 element : function () {
192 if (this._element !== undefined)
Akron916ec252016-11-10 17:06:32 +0100193 return this._element;
Nils Diewald0e6992a2015-04-14 20:13:52 +0000194
195 // First the legend table
Akronaeceda72018-02-02 20:44:06 +0100196 var wrap = d.createElement('div');
197
198 var table = wrap.addE('table');
199
200 this._element = wrap;
Nils Diewald0e6992a2015-04-14 20:13:52 +0000201
202 // Single row in head
Akron0b489ad2018-02-02 16:49:32 +0100203 var tr = table.addE('thead').addE('tr');
Nils Diewald0e6992a2015-04-14 20:13:52 +0000204
Akronf2279c42017-12-21 13:48:46 +0100205 var ah = KorAP.annotationHelper || { "getDesc" : function () {}};
206
Nils Diewald0e6992a2015-04-14 20:13:52 +0000207 // Add cell to row
Akronf2279c42017-12-21 13:48:46 +0100208 var addCell = function (type, key, value) {
Akron0b489ad2018-02-02 16:49:32 +0100209 var c = this.addE(type);
210
Akronf2279c42017-12-21 13:48:46 +0100211 if (value === undefined)
Akron916ec252016-11-10 17:06:32 +0100212 return c;
Nils Diewald0e6992a2015-04-14 20:13:52 +0000213
Akronf2279c42017-12-21 13:48:46 +0100214 if (key && value instanceof Array && value[1] !== undefined) {
Akron4e47d0b2017-07-03 17:58:37 +0200215
216 // There are multiple values to add
Akron856af1e2017-07-03 19:57:46 +0200217 c.classList.add('matchkeyvalues');
Akronf2279c42017-12-21 13:48:46 +0100218 for (var n = 0; n < value.length; n++) {
Akron5b1a6af2018-02-05 15:41:16 +0100219 var e = c.addE('div');
220 e.addT(value[n]);
Akronf2279c42017-12-21 13:48:46 +0100221
222 var anno = ah.getDesc(key, value[n]);
223
224 if (anno)
225 e.setAttribute("title", anno);
Akron856af1e2017-07-03 19:57:46 +0200226 };
Akron916ec252016-11-10 17:06:32 +0100227 }
Akronf2279c42017-12-21 13:48:46 +0100228
Akron916ec252016-11-10 17:06:32 +0100229 else {
Akronf2279c42017-12-21 13:48:46 +0100230
231 if (value instanceof Array)
232 value = value[0];
233
Akron0b489ad2018-02-02 16:49:32 +0100234 c.addT(value);
Akronf2279c42017-12-21 13:48:46 +0100235
236 // Add tooltip
237 var anno = ah.getDesc(key, value);
238 if (anno)
239 c.setAttribute("title", anno);
Akron916ec252016-11-10 17:06:32 +0100240 };
Akron80055992017-12-20 16:30:52 +0100241
242 return c;
Nils Diewald0e6992a2015-04-14 20:13:52 +0000243 };
244
245 tr.addCell = addCell;
246
247 // Add header information
Akronf2279c42017-12-21 13:48:46 +0100248 tr.addCell('th', undefined, 'Foundry');
249 tr.addCell('th', undefined, 'Layer');
Nils Diewald0e6992a2015-04-14 20:13:52 +0000250
251 // Add tokens
Akron678c26f2020-10-09 08:52:50 +0200252 Object.keys(this._token).forEach(function(i) {
Akron5dc31172019-05-15 18:43:48 +0200253 let surface = this.getToken(i);
254 var c = tr.addCell('th', undefined, surface);
Akronad1e46a2018-09-19 15:55:40 +0200255 if (this._mark[i]) {
256 c.classList.add('mark');
257 if (this._markE === undefined) {
258 this._markE = c;
259 };
Akron083ec572019-05-16 18:30:40 +0200260 }
Akron1a780fe2019-05-21 15:59:00 +0200261 else if (this._cutted[0] == i || this._cutted[1] == i) {
Akron083ec572019-05-16 18:30:40 +0200262 c.classList.add('cutted');
Akronad1e46a2018-09-19 15:55:40 +0200263 };
Akron5dc31172019-05-15 18:43:48 +0200264
265 // In case the title is very long - add a title attribute
266 if (surface.length > 20) {
267 c.setAttribute("title", surface)
268 }
Akron678c26f2020-10-09 08:52:50 +0200269 }, this);
Akron916ec252016-11-10 17:06:32 +0100270
Akron0b489ad2018-02-02 16:49:32 +0100271 var tbody = table.addE('tbody');
Nils Diewald0e6992a2015-04-14 20:13:52 +0000272
273 var foundryList = Object.keys(this._foundry).sort();
274
275 for (var f = 0; f < foundryList.length; f++) {
Akron99713ef2017-06-28 18:19:28 +0200276 var foundry = foundryList[f];
277 var layerList =
278 Object.keys(this._foundry[foundry]).sort();
Nils Diewald0e6992a2015-04-14 20:13:52 +0000279
Akron99713ef2017-06-28 18:19:28 +0200280 for (var l = 0; l < layerList.length; l++) {
281 var layer = layerList[l];
Akron0b489ad2018-02-02 16:49:32 +0100282 tr = tbody.addE('tr');
Akron99713ef2017-06-28 18:19:28 +0200283 tr.setAttribute('tabindex', 0);
284 tr.addCell = addCell;
Nils Diewald0e6992a2015-04-14 20:13:52 +0000285
Akronf2279c42017-12-21 13:48:46 +0100286 tr.addCell('th', undefined, foundry);
287 tr.addCell('th', undefined, layer);
Nils Diewald0e6992a2015-04-14 20:13:52 +0000288
Akron80055992017-12-20 16:30:52 +0100289 var key = foundry + '/' + layer + '=';
Akron80055992017-12-20 16:30:52 +0100290
Akron99713ef2017-06-28 18:19:28 +0200291 for (var v = 0; v < this.length(); v++) {
Akron80055992017-12-20 16:30:52 +0100292
293 // Get the cell value
294 var value = this.getValue(v, foundry, layer);
295
296 // Add cell to row
297 var cell = tr.addCell(
Akron99713ef2017-06-28 18:19:28 +0200298 'td',
Akronf2279c42017-12-21 13:48:46 +0100299 key,
Akron80055992017-12-20 16:30:52 +0100300 value
Akron99713ef2017-06-28 18:19:28 +0200301 );
Akronad1e46a2018-09-19 15:55:40 +0200302
303 if (this._mark[v]) {
304 cell.classList.add('mark');
305 };
Akron99713ef2017-06-28 18:19:28 +0200306 };
307 };
Nils Diewald0e6992a2015-04-14 20:13:52 +0000308 };
Akronb6685bb2018-02-04 00:44:47 +0100309
310 // Add query creator
311 this._matchCreator = matchQueryCreator.create(this._element);
312
Akronaeceda72018-02-02 20:44:06 +0100313 return this._element;
314 },
Nils Diewald0e6992a2015-04-14 20:13:52 +0000315 };
316});