blob: 703e13352f10ce5e315c7a752d1bf6c7a927880f [file] [log] [blame]
Akron99713ef2017-06-28 18:19:28 +02001/**
2 * Information about a match.
3 */
Nils Diewald7c8ced22015-04-15 19:21:00 +00004define([
5 'match/infolayer',
6 'match/table',
7 'match/tree',
Akron0988d882017-11-10 16:13:12 +01008 'match/relations',
Nils Diewald7c8ced22015-04-15 19:21:00 +00009 'match/treemenu',
Akron99713ef2017-06-28 18:19:28 +020010 'match/querycreator',
Nils Diewald7c8ced22015-04-15 19:21:00 +000011 'util'
12], function (infoLayerClass,
Akron3bb91bc2016-12-02 16:43:17 +010013 matchTableClass,
14 matchTreeClass,
Akron0988d882017-11-10 16:13:12 +010015 matchRelClass,
Akron99713ef2017-06-28 18:19:28 +020016 matchTreeMenuClass,
Akron0988d882017-11-10 16:13:12 +010017 matchQueryCreator) {
Akron3bb91bc2016-12-02 16:43:17 +010018
Nils Diewald7148c6f2015-05-04 15:07:53 +000019 // Override
Nils Diewald0e6992a2015-04-14 20:13:52 +000020 KorAP.API.getMatchInfo = KorAP.API.getMatchInfo || function () {
21 KorAP.log(0, 'KorAP.API.getMatchInfo() not implemented')
22 return {};
23 };
24
25 var loc = KorAP.Locale;
26
Nils Diewald0e6992a2015-04-14 20:13:52 +000027 return {
Nils Diewald7148c6f2015-05-04 15:07:53 +000028
29 /**
30 * Create new match object
31 */
Nils Diewald0e6992a2015-04-14 20:13:52 +000032 create : function (match) {
33 return Object.create(this)._init(match);
34 },
35
36 /**
37 * Initialize object
38 */
39 _init : function (match) {
40 this._match = match;
41 this.opened = false;
42 return this;
43 },
44
45 /**
46 * Get match object
47 */
48 match : function () {
49 return this._match;
50 },
51
Nils Diewald7148c6f2015-05-04 15:07:53 +000052
53 /**
54 * Open the information view,
55 * if closed, otherwise close.
56 */
Nils Diewald0e6992a2015-04-14 20:13:52 +000057 toggle : function () {
Akron3bb91bc2016-12-02 16:43:17 +010058
Akron08b82d62016-12-05 15:06:05 +010059 var elem = this._match.element();
Akron3bb91bc2016-12-02 16:43:17 +010060
61 if (this.opened == true) {
Akrond67d45b2017-05-18 21:47:38 +020062 elem.removeChild(
63 this.element()
64 );
65 this.opened = false;
Nils Diewald0e6992a2015-04-14 20:13:52 +000066 }
67 else {
Akrond67d45b2017-05-18 21:47:38 +020068 // Append element to match
Akron3bb91bc2016-12-02 16:43:17 +010069 elem.appendChild(
Akrond67d45b2017-05-18 21:47:38 +020070 this.element()
71 );
72 this.opened = true;
Nils Diewald0e6992a2015-04-14 20:13:52 +000073 };
74
75 return this.opened;
76 },
77
78
79 /**
Nils Diewald7148c6f2015-05-04 15:07:53 +000080 * Retrieve and parse snippet for table
81 * representation
Nils Diewald0e6992a2015-04-14 20:13:52 +000082 */
83 getTable : function (tokens, cb) {
84 var focus = [];
85
86 // Get all tokens
87 if (tokens === undefined) {
Akrond67d45b2017-05-18 21:47:38 +020088 focus = this._match.getTokens();
Nils Diewald0e6992a2015-04-14 20:13:52 +000089 }
90
91 // Get only some tokens
92 else {
Akrond67d45b2017-05-18 21:47:38 +020093
94 // Push newly to focus array
95 for (var i = 0; i < tokens.length; i++) {
96 var term = tokens[i];
97 try {
98 // Create info layer objects
99 var layer = infoLayerClass.create(term);
100 layer.type = "tokens";
101 focus.push(layer);
102 }
103 catch (e) {
104 continue;
105 };
106 };
Nils Diewald0e6992a2015-04-14 20:13:52 +0000107 };
108
109 // No tokens chosen
110 if (focus.length == 0)
Akrond67d45b2017-05-18 21:47:38 +0200111 cb(null);
Nils Diewald0e6992a2015-04-14 20:13:52 +0000112
113 // Get info (may be cached)
Nils Diewald0e6992a2015-04-14 20:13:52 +0000114 KorAP.API.getMatchInfo(
Akrond67d45b2017-05-18 21:47:38 +0200115 this._match,
116 { 'spans' : false, 'layer' : focus },
117
118 // Callback for retrieval
119 function (matchResponse) {
Akron3bb91bc2016-12-02 16:43:17 +0100120
Akron515851a2017-05-02 12:53:17 +0200121 if (matchResponse === undefined)
122 cb(null);
123
Akrond67d45b2017-05-18 21:47:38 +0200124 // Get snippet from match info
125 if (matchResponse["snippet"] !== undefined) {
126 this._table = matchTableClass.create(matchResponse["snippet"]);
127 cb(this._table);
128 };
129 }.bind(this)
Nils Diewald0e6992a2015-04-14 20:13:52 +0000130 );
131
132 /*
133 // Todo: Store the table as a hash of the focus
134 return null;
135 */
136 },
137
138
139 /**
140 * Retrieve and parse snippet for tree representation
141 */
Akron0988d882017-11-10 16:13:12 +0100142 getTree : function (foundry, layer, type, cb) {
Nils Diewald0e6992a2015-04-14 20:13:52 +0000143 var focus = [];
144
145 // TODO: Support and cache multiple trees
146 KorAP.API.getMatchInfo(
Akrond67d45b2017-05-18 21:47:38 +0200147 this._match, {
148 'spans' : true,
149 'foundry' : foundry,
150 'layer' : layer
151 },
152 function (matchResponse) {
153 // Get snippet from match info
154 if (matchResponse["snippet"] !== undefined) {
155 // Todo: This should be cached somehow
Akronc56cf2d2016-11-09 22:02:38 +0100156
Akron0988d882017-11-10 16:13:12 +0100157 if (type === "spans") {
158 cb(matchTreeClass.create(matchResponse["snippet"]));
159 }
160 else if (type === "rels") {
161 cb(matchRelClass.create(matchResponse["snippet"]));
162 }
163
164 // Unknown tree type
165 else {
166 cb(null);
167 };
Akrond67d45b2017-05-18 21:47:38 +0200168 }
169 else {
170 cb(null);
171 };
172 }.bind(this)
Nils Diewald0e6992a2015-04-14 20:13:52 +0000173 );
174 },
175
176 /**
177 * Destroy this match information view.
178 */
179 destroy : function () {
180
181 // Remove circular reference
182 if (this._treeMenu !== undefined)
Akron99713ef2017-06-28 18:19:28 +0200183 delete this._treeMenu["info"];
Nils Diewald0e6992a2015-04-14 20:13:52 +0000184
185 this._treeMenu.destroy();
186 this._treeMenu = undefined;
187 this._match = undefined;
Akron99713ef2017-06-28 18:19:28 +0200188 this._matchCreator = undefined;
Nils Diewald0e6992a2015-04-14 20:13:52 +0000189 // Element destroy
190 },
191
192 /**
193 * Add a new tree view to the list
194 */
Akron0988d882017-11-10 16:13:12 +0100195 addTree : function (foundry, layer, type, cb) {
Nils Diewald0e6992a2015-04-14 20:13:52 +0000196 var matchtree = document.createElement('div');
197 matchtree.classList.add('matchtree');
198
199 var h6 = matchtree.appendChild(document.createElement('h6'));
200 h6.appendChild(document.createElement('span'))
Akron99713ef2017-06-28 18:19:28 +0200201 .appendChild(document.createTextNode(foundry));
Nils Diewald0e6992a2015-04-14 20:13:52 +0000202 h6.appendChild(document.createElement('span'))
Akrond67d45b2017-05-18 21:47:38 +0200203 .appendChild(document.createTextNode(layer));
204
Nils Diewald0e6992a2015-04-14 20:13:52 +0000205 var tree = matchtree.appendChild(
Akrond67d45b2017-05-18 21:47:38 +0200206 document.createElement('div')
Nils Diewald0e6992a2015-04-14 20:13:52 +0000207 );
208
209 this._element.insertBefore(matchtree, this._element.lastChild);
210
Akronc56cf2d2016-11-09 22:02:38 +0100211 var actions = tree.appendChild(document.createElement('ul'));
212 actions.classList.add('action', 'image');
213 var close = actions.appendChild(document.createElement('li'));
214 close.className = 'close';
215 close.appendChild(document.createElement('span'));
Nils Diewald0e6992a2015-04-14 20:13:52 +0000216 close.addEventListener(
Akrond67d45b2017-05-18 21:47:38 +0200217 'click', function (e) {
218 matchtree.parentNode.removeChild(matchtree);
219 e.halt();
220 }
Nils Diewald0e6992a2015-04-14 20:13:52 +0000221 );
222
Nils Diewald0ec142f2015-05-05 00:29:23 +0000223 tree.classList.add('loading');
224
Nils Diewald0e6992a2015-04-14 20:13:52 +0000225 // Get tree data async
Akron0988d882017-11-10 16:13:12 +0100226 this.getTree(foundry, layer, type, function (treeObj) {
Nils Diewald0ec142f2015-05-05 00:29:23 +0000227
Akrond67d45b2017-05-18 21:47:38 +0200228 tree.classList.remove('loading');
Nils Diewald0ec142f2015-05-05 00:29:23 +0000229
Akrond67d45b2017-05-18 21:47:38 +0200230 // Something went wrong - probably log!!!
Nils Diewald0ec142f2015-05-05 00:29:23 +0000231
Akrond67d45b2017-05-18 21:47:38 +0200232 if (treeObj === null) {
233 tree.appendChild(document.createTextNode('No data available.'));
234 }
235 else {
236 tree.appendChild(treeObj.element());
Akron0988d882017-11-10 16:13:12 +0100237 treeObj.show();
Akrond67d45b2017-05-18 21:47:38 +0200238 // Reposition the view to the center
239 // (This may in a future release be a reposition
240 // to move the root into the center or the actual
241 // match)
Akronc56cf2d2016-11-09 22:02:38 +0100242
Akron0988d882017-11-10 16:13:12 +0100243 // This is currently not supported by relations
244 if (type === "spans") {
245 var dl = document.createElement('li');
246 dl.className = 'download';
247 dl.addEventListener(
248 'click', function (e) {
Akronc56cf2d2016-11-09 22:02:38 +0100249
Akron0988d882017-11-10 16:13:12 +0100250 var a = document.createElement('a');
251 a.setAttribute('href-lang', 'image/svg+xml');
252 a.setAttribute('href', 'data:image/svg+xml;base64,'+treeObj.toBase64());
253 a.setAttribute('download', 'tree.svg');
254 a.target = '_blank';
Akrona27f0d42017-11-13 14:08:41 +0100255 a.setAttribute('rel', 'noopener noreferrer');
Akron0988d882017-11-10 16:13:12 +0100256
257 document.body.appendChild(a);
258 a.click();
259 document.body.removeChild(a)
260 e.halt();
261 }
262 );
263
264 actions.appendChild(dl);
265 };
266
Akronc56cf2d2016-11-09 22:02:38 +0100267 treeObj.center();
Akrond67d45b2017-05-18 21:47:38 +0200268 };
269
270 if (cb !== undefined)
271 cb(treeObj);
Nils Diewald0e6992a2015-04-14 20:13:52 +0000272 });
273 },
274
275 /**
276 * Create match information view.
277 */
278 element : function () {
279
280 if (this._element !== undefined)
Akrond67d45b2017-05-18 21:47:38 +0200281 return this._element;
Nils Diewald0e6992a2015-04-14 20:13:52 +0000282
283 // Create info table
284 var info = document.createElement('div');
285 info.classList.add('matchinfo');
286
287 // Append default table
288 var matchtable = document.createElement('div');
Nils Diewald0ec142f2015-05-05 00:29:23 +0000289 matchtable.classList.add('matchtable', 'loading');
Nils Diewald0e6992a2015-04-14 20:13:52 +0000290 info.appendChild(matchtable);
291
292 // Create the table asynchronous
293 this.getTable(undefined, function (table) {
Akron3bb91bc2016-12-02 16:43:17 +0100294
Akrond67d45b2017-05-18 21:47:38 +0200295 if (table !== null) {
Akron3bb91bc2016-12-02 16:43:17 +0100296 matchtable.appendChild(table.element());
297 };
Akron515851a2017-05-02 12:53:17 +0200298 matchtable.classList.remove('loading');
Akron99713ef2017-06-28 18:19:28 +0200299
300 // Add query creator
Akrone8ea0002017-06-28 18:51:52 +0200301 this._matchCreator = matchQueryCreator.create(info);
Nils Diewald0e6992a2015-04-14 20:13:52 +0000302 });
303
Akrond67d45b2017-05-18 21:47:38 +0200304 // Join spans and relations
305 var treeLayers = []
306 var spans = this._match.getSpans();
307 var rels = this._match.getRels();
308 var i;
309 for (i in spans) {
310 treeLayers.push(spans[i]);
311 };
312 for (i in rels) {
313 treeLayers.push(rels[i]);
314 };
315
Nils Diewald0e6992a2015-04-14 20:13:52 +0000316 // Get spans
Akrond67d45b2017-05-18 21:47:38 +0200317 treeLayers = treeLayers.sort(
318 function (a, b) {
319 if (a.foundry < b.foundry) {
320 return -1;
321 }
322 else if (a.foundry > b.foundry) {
323 return 1;
324 }
325 else if (a.layer < b.layer) {
326 return -1;
327 }
328 else if (a.layer > b.layer) {
329 return 1;
330 };
331 return 0;
332 });
Nils Diewald0e6992a2015-04-14 20:13:52 +0000333
334 var menuList = [];
335
336 // Show tree views
Akrond67d45b2017-05-18 21:47:38 +0200337 for (var i = 0; i < treeLayers.length; i++) {
338 var span = treeLayers[i];
339
340 // Add foundry/layer to menu list
341 menuList.push([
342 span.foundry + '/' + span.layer,
343 span.foundry,
Akron0988d882017-11-10 16:13:12 +0100344 span.layer,
345 span.type
Akrond67d45b2017-05-18 21:47:38 +0200346 ]);
Nils Diewald0e6992a2015-04-14 20:13:52 +0000347 };
348
349 // Create tree menu
350 var treemenu = this.treeMenu(menuList);
351 var span = info.appendChild(document.createElement('p'));
352 span.classList.add('addtree');
353 span.appendChild(document.createTextNode(loc.ADDTREE));
354
355 var treeElement = treemenu.element();
356 span.appendChild(treeElement);
357
358 span.addEventListener('click', function (e) {
Akrond67d45b2017-05-18 21:47:38 +0200359 treemenu.show();
360 treemenu.focus();
Nils Diewald0e6992a2015-04-14 20:13:52 +0000361 });
362
363 this._element = info;
364
365 return info;
366 },
367
368
369 /**
370 * Get tree menu.
371 * There is only one menu rendered
372 * - no matter how many trees exist
373 */
374 treeMenu : function (list) {
375 if (this._treeMenu !== undefined)
Akrond67d45b2017-05-18 21:47:38 +0200376 return this._treeMenu;
Nils Diewald0e6992a2015-04-14 20:13:52 +0000377
378 return this._treeMenu = matchTreeMenuClass.create(this, list);
379 }
380 };
381});