blob: 61c100a136641bbd608cece82abcb087d53293c5 [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;
Nils Diewald0e6992a2015-04-14 20:13:52 +000038 this._info = [];
39 this._foundry = {};
40 this._layer = {};
41
42 // Parse the snippet
Akronad1e46a2018-09-19 15:55:40 +020043 this._parse(html.childNodes, false);
Akronb6685bb2018-02-04 00:44:47 +010044
Nils Diewald0e6992a2015-04-14 20:13:52 +000045 html.innerHTML = '';
46 return this;
47 },
Akronb6685bb2018-02-04 00:44:47 +010048
49 // TODO: Destroy match!
50 destroy : function () {
51 this._matchCreator = undefined;
52 },
Nils Diewald7148c6f2015-05-04 15:07:53 +000053
54 /**
55 * Length of the table (columns),
56 * aka the number of tokens
57 * in the snippet.
58 */
Nils Diewald0e6992a2015-04-14 20:13:52 +000059 length : function () {
60 return this._pos;
61 },
62
Akronad1e46a2018-09-19 15:55:40 +020063
64 /**
65 * Move the viewport to the match
66 */
67 toMark : function () {
68 if (this._markE === undefined)
69 return;
70 this._markE.scrollIntoView({
71 inline: "start",
72 block: "nearest"
73 });
74 },
75
Nils Diewald7148c6f2015-05-04 15:07:53 +000076 /**
77 * Get the token in the snippet
78 * At a given position.
79 *
80 * @param pos
81 */
Nils Diewald0e6992a2015-04-14 20:13:52 +000082 getToken : function (pos) {
83 if (pos === undefined)
Akron916ec252016-11-10 17:06:32 +010084 return this._token;
Nils Diewald0e6992a2015-04-14 20:13:52 +000085 return this._token[pos];
86 },
Nils Diewald7148c6f2015-05-04 15:07:53 +000087
88 /**
89 * Get the annotation of a token
90 * in the snippet based on the position,
91 * the foundry, and the layer.
92 *
93 * @param pos
94 * @param foundry
95 * @param layer
96 */
Nils Diewald0e6992a2015-04-14 20:13:52 +000097 getValue : function (pos, foundry, layer) {
98 return this._info[pos][foundry + '/' + layer]
99 },
Nils Diewald0e6992a2015-04-14 20:13:52 +0000100
Akronaeceda72018-02-02 20:44:06 +0100101
Nils Diewald0e6992a2015-04-14 20:13:52 +0000102 // Parse the snippet
Akronad1e46a2018-09-19 15:55:40 +0200103 _parse : function (children, mark) {
Nils Diewald0e6992a2015-04-14 20:13:52 +0000104
105 // Get all children
106 for (var i in children) {
Akron916ec252016-11-10 17:06:32 +0100107 var c = children[i];
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
125 else if (c.getAttribute("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;
161 };
Nils Diewald0e6992a2015-04-14 20:13:52 +0000162
Akron916ec252016-11-10 17:06:32 +0100163 // depth search
164 if (c.hasChildNodes())
Akronad1e46a2018-09-19 15:55:40 +0200165 this._parse(c.childNodes, newMark);
Akron916ec252016-11-10 17:06:32 +0100166 }
Nils Diewald0e6992a2015-04-14 20:13:52 +0000167
Akron916ec252016-11-10 17:06:32 +0100168 // Leaf node
169 // store string on position and go to next string
170 else if (c.nodeType === 3) {
Akronad1e46a2018-09-19 15:55:40 +0200171 if (c.nodeValue.match(/[a-z0-9]/i)) {
172 this._mark[this._pos] = mark ? true : false;
Akron916ec252016-11-10 17:06:32 +0100173 this._token[this._pos++] = c.nodeValue;
Akronad1e46a2018-09-19 15:55:40 +0200174 };
Akron916ec252016-11-10 17:06:32 +0100175 };
Nils Diewald0e6992a2015-04-14 20:13:52 +0000176 };
177
178 delete this._info[this._pos];
179 },
180
181
182 /**
183 * Get HTML table view of annotations.
184 */
185 element : function () {
186 if (this._element !== undefined)
Akron916ec252016-11-10 17:06:32 +0100187 return this._element;
Nils Diewald0e6992a2015-04-14 20:13:52 +0000188
189 // First the legend table
Akronaeceda72018-02-02 20:44:06 +0100190 var wrap = d.createElement('div');
191
192 var table = wrap.addE('table');
193
194 this._element = wrap;
Nils Diewald0e6992a2015-04-14 20:13:52 +0000195
196 // Single row in head
Akron0b489ad2018-02-02 16:49:32 +0100197 var tr = table.addE('thead').addE('tr');
Nils Diewald0e6992a2015-04-14 20:13:52 +0000198
Akronf2279c42017-12-21 13:48:46 +0100199 var ah = KorAP.annotationHelper || { "getDesc" : function () {}};
200
Nils Diewald0e6992a2015-04-14 20:13:52 +0000201 // Add cell to row
Akronf2279c42017-12-21 13:48:46 +0100202 var addCell = function (type, key, value) {
Akron0b489ad2018-02-02 16:49:32 +0100203 var c = this.addE(type);
204
Akronf2279c42017-12-21 13:48:46 +0100205 if (value === undefined)
Akron916ec252016-11-10 17:06:32 +0100206 return c;
Nils Diewald0e6992a2015-04-14 20:13:52 +0000207
Akronf2279c42017-12-21 13:48:46 +0100208 if (key && value instanceof Array && value[1] !== undefined) {
Akron4e47d0b2017-07-03 17:58:37 +0200209
210 // There are multiple values to add
Akron856af1e2017-07-03 19:57:46 +0200211 c.classList.add('matchkeyvalues');
Akronf2279c42017-12-21 13:48:46 +0100212 for (var n = 0; n < value.length; n++) {
Akron5b1a6af2018-02-05 15:41:16 +0100213 var e = c.addE('div');
214 e.addT(value[n]);
Akronf2279c42017-12-21 13:48:46 +0100215
216 var anno = ah.getDesc(key, value[n]);
217
218 if (anno)
219 e.setAttribute("title", anno);
Akron856af1e2017-07-03 19:57:46 +0200220 };
Akron916ec252016-11-10 17:06:32 +0100221 }
Akronf2279c42017-12-21 13:48:46 +0100222
Akron916ec252016-11-10 17:06:32 +0100223 else {
Akronf2279c42017-12-21 13:48:46 +0100224
225 if (value instanceof Array)
226 value = value[0];
227
Akron0b489ad2018-02-02 16:49:32 +0100228 c.addT(value);
Akronf2279c42017-12-21 13:48:46 +0100229
230 // Add tooltip
231 var anno = ah.getDesc(key, value);
232 if (anno)
233 c.setAttribute("title", anno);
Akron916ec252016-11-10 17:06:32 +0100234 };
Akron80055992017-12-20 16:30:52 +0100235
236 return c;
Nils Diewald0e6992a2015-04-14 20:13:52 +0000237 };
238
239 tr.addCell = addCell;
240
241 // Add header information
Akronf2279c42017-12-21 13:48:46 +0100242 tr.addCell('th', undefined, 'Foundry');
243 tr.addCell('th', undefined, 'Layer');
Nils Diewald0e6992a2015-04-14 20:13:52 +0000244
245 // Add tokens
246 for (var i in this._token) {
Akron5dc31172019-05-15 18:43:48 +0200247 let surface = this.getToken(i);
248 var c = tr.addCell('th', undefined, surface);
Akronad1e46a2018-09-19 15:55:40 +0200249 if (this._mark[i]) {
250 c.classList.add('mark');
251 if (this._markE === undefined) {
252 this._markE = c;
253 };
254 };
Akron5dc31172019-05-15 18:43:48 +0200255
256 // In case the title is very long - add a title attribute
257 if (surface.length > 20) {
258 c.setAttribute("title", surface)
259 }
Nils Diewald0e6992a2015-04-14 20:13:52 +0000260 };
Akron916ec252016-11-10 17:06:32 +0100261
Akron0b489ad2018-02-02 16:49:32 +0100262 var tbody = table.addE('tbody');
Nils Diewald0e6992a2015-04-14 20:13:52 +0000263
264 var foundryList = Object.keys(this._foundry).sort();
265
266 for (var f = 0; f < foundryList.length; f++) {
Akron99713ef2017-06-28 18:19:28 +0200267 var foundry = foundryList[f];
268 var layerList =
269 Object.keys(this._foundry[foundry]).sort();
Nils Diewald0e6992a2015-04-14 20:13:52 +0000270
Akron99713ef2017-06-28 18:19:28 +0200271 for (var l = 0; l < layerList.length; l++) {
272 var layer = layerList[l];
Akron0b489ad2018-02-02 16:49:32 +0100273 tr = tbody.addE('tr');
Akron99713ef2017-06-28 18:19:28 +0200274 tr.setAttribute('tabindex', 0);
275 tr.addCell = addCell;
Nils Diewald0e6992a2015-04-14 20:13:52 +0000276
Akronf2279c42017-12-21 13:48:46 +0100277 tr.addCell('th', undefined, foundry);
278 tr.addCell('th', undefined, layer);
Nils Diewald0e6992a2015-04-14 20:13:52 +0000279
Akron80055992017-12-20 16:30:52 +0100280 var key = foundry + '/' + layer + '=';
Akron80055992017-12-20 16:30:52 +0100281
Akron99713ef2017-06-28 18:19:28 +0200282 for (var v = 0; v < this.length(); v++) {
Akron80055992017-12-20 16:30:52 +0100283
284 // Get the cell value
285 var value = this.getValue(v, foundry, layer);
286
287 // Add cell to row
288 var cell = tr.addCell(
Akron99713ef2017-06-28 18:19:28 +0200289 'td',
Akronf2279c42017-12-21 13:48:46 +0100290 key,
Akron80055992017-12-20 16:30:52 +0100291 value
Akron99713ef2017-06-28 18:19:28 +0200292 );
Akronad1e46a2018-09-19 15:55:40 +0200293
294 if (this._mark[v]) {
295 cell.classList.add('mark');
296 };
Akron99713ef2017-06-28 18:19:28 +0200297 };
298 };
Nils Diewald0e6992a2015-04-14 20:13:52 +0000299 };
Akronb6685bb2018-02-04 00:44:47 +0100300
301 // Add query creator
302 this._matchCreator = matchQueryCreator.create(this._element);
303
Akronaeceda72018-02-02 20:44:06 +0100304 return this._element;
305 },
Nils Diewald0e6992a2015-04-14 20:13:52 +0000306 };
307});