blob: 3827af1bd71364d1de458f24ba86ef60155b95ca [file] [log] [blame]
Nils Diewalde8518f82015-03-18 22:41:49 +00001/**
Nils Diewalda297f062015-04-02 00:23:46 +00002 * Get information on matches,
3 * generate annotation tables and trees.
Nils Diewalde8518f82015-03-18 22:41:49 +00004 *
5 * @author Nils Diewald
6 */
7/*
Nils Diewald6e43ffd2015-03-25 18:55:39 +00008 * - Highlight (at least mark as bold) the match
9 * - Scroll to match vertically per default
Akron02360e42016-06-07 13:41:12 +020010 * - A click on a table field and a tree node should at the field description to the fragments list.
Nils Diewalde8518f82015-03-18 22:41:49 +000011 */
Nils Diewald0e6992a2015-04-14 20:13:52 +000012define([
Akron24866cf2018-01-23 20:22:01 +010013 'match/info', // rename to anno
Akron8b592d42018-01-26 18:33:06 +010014 'match/treemenu',
15 'util'
16], function (infoClass,matchTreeMenuClass) { //, refClass) {
Nils Diewald4f6521a2015-03-20 21:30:13 +000017
Nils Diewald6e43ffd2015-03-25 18:55:39 +000018 // Localization values
Nils Diewald0e6992a2015-04-14 20:13:52 +000019 var loc = KorAP.Locale;
Akron24866cf2018-01-23 20:22:01 +010020 loc.ADDTREE = loc.ADDTREE || 'Add tree view';
21 loc.SHOWINFO = loc.SHOWINFO || 'Show information';
22 loc.CLOSE = loc.CLOSE || 'Close';
23 loc.SHOW_META = loc.SHOW_META || 'Show metadata';
Nils Diewald0e6992a2015-04-14 20:13:52 +000024
Akron0a6768f2016-07-13 18:00:43 +020025 // 'corpusID', 'docID', 'textID'
26 var _matchTerms = ['textSigle', 'matchID', 'available'];
Nils Diewalda297f062015-04-02 00:23:46 +000027
28 /**
29 * Match object
30 */
Nils Diewald0e6992a2015-04-14 20:13:52 +000031 return {
Nils Diewalde8518f82015-03-18 22:41:49 +000032
33 /**
34 * Create a new annotation object.
35 * Expects an array of available foundry/layer=type terms.
36 * Supported types are 'spans', 'tokens' and 'rels'.
37 */
Nils Diewalda297f062015-04-02 00:23:46 +000038 create : function (match) {
Nils Diewald0e6992a2015-04-14 20:13:52 +000039 return Object.create(this)._init(match);
Nils Diewalde8518f82015-03-18 22:41:49 +000040 },
41
Nils Diewald7c8ced22015-04-15 19:21:00 +000042
Nils Diewald6e43ffd2015-03-25 18:55:39 +000043 /**
Nils Diewalda297f062015-04-02 00:23:46 +000044 * Initialize match.
Nils Diewald6e43ffd2015-03-25 18:55:39 +000045 */
Nils Diewalda297f062015-04-02 00:23:46 +000046 _init : function (match) {
47 this._element = null;
Nils Diewald6e43ffd2015-03-25 18:55:39 +000048
Nils Diewalda297f062015-04-02 00:23:46 +000049 // No match defined
50 if (arguments.length < 1 ||
Akron19d97fe2016-09-06 20:47:05 +020051 match === null ||
52 match === undefined) {
53 throw new Error('Missing parameters');
Nils Diewalda297f062015-04-02 00:23:46 +000054 }
Nils Diewald6e43ffd2015-03-25 18:55:39 +000055
Nils Diewalda297f062015-04-02 00:23:46 +000056 // Match defined as a node
57 else if (match instanceof Node) {
Akron19d97fe2016-09-06 20:47:05 +020058 this._element = match;
Nils Diewald6e43ffd2015-03-25 18:55:39 +000059
Akron19d97fe2016-09-06 20:47:05 +020060 // Circular reference !!
61 match["_match"] = this;
Nils Diewalda297f062015-04-02 00:23:46 +000062
Akron19d97fe2016-09-06 20:47:05 +020063 /*
64 this.corpusID = match.getAttribute('data-corpus-id'),
65 this.docID = match.getAttribute('data-doc-id'),
66 this.textID = match.getAttribute('data-text-id'),
67 */
68 if (match.hasAttribute('data-text-sigle')) {
69 this.textSigle = match.getAttribute('data-text-sigle')
70 }
71 else {
72 this.textSigle = match.getAttribute('data-corpus-id') +
73 '/' +
74 match.getAttribute('data-doc-id') +
75 '/' +
76 match.getAttribute('data-text-id');
77 };
Akron0a6768f2016-07-13 18:00:43 +020078
Akron19d97fe2016-09-06 20:47:05 +020079 this.matchID = match.getAttribute('data-match-id');
Nils Diewalda297f062015-04-02 00:23:46 +000080
Akron19d97fe2016-09-06 20:47:05 +020081 // List of available annotations
82 this.available = match.getAttribute('data-available-info').split(' ');
Nils Diewalda297f062015-04-02 00:23:46 +000083 }
84
85 // Match as an object
86 else {
87
Akron19d97fe2016-09-06 20:47:05 +020088 // Iterate over allowed match terms
89 for (var i in _matchTerms) {
90 var term = _matchTerms[i];
91 this[term] = match[term] !== undefined ? match[term] : undefined;
92 };
Nils Diewalda297f062015-04-02 00:23:46 +000093 };
Nils Diewald0e6992a2015-04-14 20:13:52 +000094
Nils Diewald7c8ced22015-04-15 19:21:00 +000095 this._avail = {
Akron19d97fe2016-09-06 20:47:05 +020096 tokens : [],
97 spans : [],
98 rels : []
Nils Diewalde8518f82015-03-18 22:41:49 +000099 };
Nils Diewalda297f062015-04-02 00:23:46 +0000100
101 // Iterate over info layers
102 for (var i = 0; i < this.available.length; i++) {
Akron19d97fe2016-09-06 20:47:05 +0200103 var term = this.available[i];
Nils Diewalda297f062015-04-02 00:23:46 +0000104
Akron19d97fe2016-09-06 20:47:05 +0200105 // Create info layer objects
106 try {
107 var layer = require('match/infolayer').create(term);
108 this._avail[layer.type].push(layer);
109 }
110 catch (e) {
111 continue;
112 };
Nils Diewalde8518f82015-03-18 22:41:49 +0000113 };
Akron3a4a08e2017-05-23 22:34:18 +0200114
Nils Diewalde8518f82015-03-18 22:41:49 +0000115 return this;
116 },
117
Nils Diewalde8518f82015-03-18 22:41:49 +0000118 /**
119 * Return a list of parseable tree annotations.
120 */
121 getSpans : function () {
Nils Diewald7c8ced22015-04-15 19:21:00 +0000122 return this._avail.spans;
Nils Diewalde8518f82015-03-18 22:41:49 +0000123 },
124
125
126 /**
127 * Return a list of parseable token annotations.
128 */
129 getTokens : function () {
Nils Diewald7c8ced22015-04-15 19:21:00 +0000130 return this._avail.tokens;
Nils Diewalde8518f82015-03-18 22:41:49 +0000131 },
132
133
134 /**
135 * Return a list of parseable relation annotations.
136 */
137 getRels : function () {
Nils Diewald7c8ced22015-04-15 19:21:00 +0000138 return this._avail.rels;
Nils Diewalde8518f82015-03-18 22:41:49 +0000139 },
140
Nils Diewald7c8ced22015-04-15 19:21:00 +0000141
Nils Diewalda297f062015-04-02 00:23:46 +0000142 /**
143 * Open match
144 */
145 open : function () {
146
147 // Add actions unless it's already activated
148 var element = this._element;
149
150 // There is an element to open
151 if (this._element === undefined || this._element === null)
Akron19d97fe2016-09-06 20:47:05 +0200152 return false;
Nils Diewalda297f062015-04-02 00:23:46 +0000153
154 // The element is already opened
155 if (element.classList.contains('active'))
Akron19d97fe2016-09-06 20:47:05 +0200156 return false;
Nils Diewalda297f062015-04-02 00:23:46 +0000157
158 // Add active class to element
159 element.classList.add('active');
160
Nils Diewald7c8ced22015-04-15 19:21:00 +0000161 // Already there
162 if (element.classList.contains('action'))
Akron19d97fe2016-09-06 20:47:05 +0200163 return true;
Nils Diewald7c8ced22015-04-15 19:21:00 +0000164
Nils Diewalda297f062015-04-02 00:23:46 +0000165 // Create action buttons
166 var ul = document.createElement('ul');
167 ul.classList.add('action', 'right');
Nils Diewalda297f062015-04-02 00:23:46 +0000168
Nils Diewald7c8ced22015-04-15 19:21:00 +0000169 element.appendChild(ul);
170 element.classList.add('action');
171
172 // Todo: Open in new frame
Nils Diewalda297f062015-04-02 00:23:46 +0000173
174 // Add close button
175 var close = document.createElement('li');
176 close.appendChild(document.createElement('span'))
Akron19d97fe2016-09-06 20:47:05 +0200177 .appendChild(document.createTextNode(loc.CLOSE));
Nils Diewalda297f062015-04-02 00:23:46 +0000178 close.classList.add('close');
179 close.setAttribute('title', loc.CLOSE);
Nils Diewald0e6992a2015-04-14 20:13:52 +0000180
Nils Diewalda297f062015-04-02 00:23:46 +0000181 // Add info button
Akron8b592d42018-01-26 18:33:06 +0100182 /*
Nils Diewalda297f062015-04-02 00:23:46 +0000183 var info = document.createElement('li');
184 info.appendChild(document.createElement('span'))
Akron19d97fe2016-09-06 20:47:05 +0200185 .appendChild(document.createTextNode(loc.SHOWINFO));
Nils Diewalda297f062015-04-02 00:23:46 +0000186 info.classList.add('info');
187 info.setAttribute('title', loc.SHOWINFO);
Akron8b592d42018-01-26 18:33:06 +0100188 */
Nils Diewalda297f062015-04-02 00:23:46 +0000189
190 var that = this;
191
Akron24866cf2018-01-23 20:22:01 +0100192 // Add meta button
193 var refLine = element.querySelector("p.ref");
194
195 // There is a reference line
Akron04905352018-01-24 02:06:32 +0100196 if (refLine) {
Akron8b592d42018-01-26 18:33:06 +0100197
198 // Temporary
199 var ops = document.createElement('div');
Akrond4b000b2018-01-28 18:33:14 +0100200 ops.classList.add('action', 'bottom', 'button-group');
Akron8b592d42018-01-26 18:33:06 +0100201
202 var meta = document.createElement('span');
203 ops.appendChild(meta);
204 meta.appendChild(document.createTextNode('+ Meta'));
205 meta.setAttribute('title', loc.SHOW_META);
206 meta.classList.add('meta');
207
208 var info = document.createElement('span');
209 ops.appendChild(info);
210 info.appendChild(document.createTextNode('+ Anno'));
211 info.setAttribute('title', loc.SHOWINFO);
212 info.classList.add('info');
213
214 var tree = document.createElement('span');
215 ops.appendChild(tree);
216 tree.appendChild(document.createTextNode('+ Tree'));
217 tree.setAttribute('title', loc.ADDTREE);
218 tree.classList.add('tree');
Akron24866cf2018-01-23 20:22:01 +0100219
Akron8b592d42018-01-26 18:33:06 +0100220 refLine.insertBefore(
221 ops,
222 refLine.firstChild
223 );
224
225 /*
Akron24866cf2018-01-23 20:22:01 +0100226 var meta = document.createElement('span');
227 meta.appendChild(
Akron04905352018-01-24 02:06:32 +0100228 document.createElement('span')
229 ).appendChild(
Akron24866cf2018-01-23 20:22:01 +0100230 document.createTextNode(loc.SHOW_META)
231 );
232 meta.setAttribute('title', loc.SHOW_META);
233 meta.classList.add('meta');
234 refLine.insertBefore(
235 meta,
236 refLine.firstChild
237 );
Akron8b592d42018-01-26 18:33:06 +0100238 */
Akron24866cf2018-01-23 20:22:01 +0100239
240 meta.addEventListener(
241 'click', function (e) {
242 e.halt();
Akronbd342982018-01-25 18:01:46 +0100243 that.info().addMeta();
Akron24866cf2018-01-23 20:22:01 +0100244 }
245 );
Akron8b592d42018-01-26 18:33:06 +0100246
247 // Add information, unless it already exists
248 info.addEventListener(
249 'click', function (e) {
250 e.halt();
251 that.info().addTable();
252 }
253 );
254
255 tree.addEventListener(
256 'click', function (e) {
257 e.halt();
258
Akroneaba63e2018-01-26 19:49:30 +0100259 if (KorAP.TreeMenu === undefined) {
260 KorAP.TreeMenu = matchTreeMenuClass.create([]);
261 };
262
263 var tm = KorAP.TreeMenu;
264
265 // Reread list
266 tm.info(that.info());
267 tm.readItems(that.treeMenuList());
268 tm.attachTo(this);
269
Akron8b592d42018-01-26 18:33:06 +0100270 // Not yet initialized
Akroneaba63e2018-01-26 19:49:30 +0100271 /*
272 if (that._treemenu === undefined) {
Akron8b592d42018-01-26 18:33:06 +0100273 that._treemenu = that.initTreeMenu();
274
275 // TODO:
276 // Do not add the tree menu to the button!
277 // Only reposition a global treemenu element there,
278 // that is positioned below the annotation helper!
279 this.appendChild(that._treemenu.element());
280 };
281 var tm = that._treemenu;
Akroneaba63e2018-01-26 19:49:30 +0100282 */
Akron8b592d42018-01-26 18:33:06 +0100283 tm.show();
284 tm.focus();
285 }
286 );
Akron24866cf2018-01-23 20:22:01 +0100287 };
288
Nils Diewalda297f062015-04-02 00:23:46 +0000289 // Close match
290 close.addEventListener('click', function (e) {
Akron19d97fe2016-09-06 20:47:05 +0200291 e.halt();
292 that.close()
Nils Diewalda297f062015-04-02 00:23:46 +0000293 });
294
295 // Add information, unless it already exists
Akron8b592d42018-01-26 18:33:06 +0100296 /*
Nils Diewalda297f062015-04-02 00:23:46 +0000297 info.addEventListener('click', function (e) {
Akron19d97fe2016-09-06 20:47:05 +0200298 e.halt();
Akronbd342982018-01-25 18:01:46 +0100299 that.info().addTable();
Nils Diewalda297f062015-04-02 00:23:46 +0000300 });
Akron8b592d42018-01-26 18:33:06 +0100301 */
Nils Diewalda297f062015-04-02 00:23:46 +0000302
303 ul.appendChild(close);
Akron8b592d42018-01-26 18:33:06 +0100304 // ul.appendChild(info);
Nils Diewalda297f062015-04-02 00:23:46 +0000305
306 return true;
307 },
308
Akron8c468a12016-11-13 23:57:41 +0100309
Akron6a535d42015-08-26 20:16:58 +0200310 // Todo: Test toggle
311 toggle : function () {
312 if (this._element.classList.contains('active'))
Akron19d97fe2016-09-06 20:47:05 +0200313 this.close();
Akron6a535d42015-08-26 20:16:58 +0200314 else
Akron19d97fe2016-09-06 20:47:05 +0200315 this.open();
Akron6a535d42015-08-26 20:16:58 +0200316 },
317
Nils Diewald7c8ced22015-04-15 19:21:00 +0000318
Nils Diewald8bc7e412015-03-19 22:08:27 +0000319 /**
Nils Diewalda297f062015-04-02 00:23:46 +0000320 * Close info view
321 */
322 close : function () {
323 this._element.classList.remove('active');
Nils Diewald7c8ced22015-04-15 19:21:00 +0000324 /* if (this._info !== undefined) {
325 * this._info.destroy();
326 * };
327 */
Nils Diewalda297f062015-04-02 00:23:46 +0000328 },
329
330
Nils Diewalda297f062015-04-02 00:23:46 +0000331 /**
332 * Get and open associated match info.
333 */
334 info : function () {
335
336 // Create match info
337 if (this._info === undefined)
Akron19d97fe2016-09-06 20:47:05 +0200338 this._info = infoClass.create(this);
Nils Diewalda297f062015-04-02 00:23:46 +0000339
340 // There is an element to append
341 if (this._element === undefined ||
Akron19d97fe2016-09-06 20:47:05 +0200342 this._element === null)
343 return this._info;
Nils Diewald7c8ced22015-04-15 19:21:00 +0000344
Nils Diewalda297f062015-04-02 00:23:46 +0000345 // Info is already activated
Nils Diewald5c5a7472015-04-02 22:13:38 +0000346 if (this._info._element !== undefined)
Akron19d97fe2016-09-06 20:47:05 +0200347 return this._info;
Nils Diewalda297f062015-04-02 00:23:46 +0000348
Akronbd342982018-01-25 18:01:46 +0100349 /*
350 this.element().appendChild(
351 this._info.element()
352 );
353 */
354 var refLine = this._element.querySelector("p.ref");
355 this._element.insertBefore(
356 this._info.element(),
357 refLine
358 );
359
Nils Diewalda297f062015-04-02 00:23:46 +0000360 return this._info;
361 },
362
Akron8b592d42018-01-26 18:33:06 +0100363
Akroneaba63e2018-01-26 19:49:30 +0100364 treeMenuList : function () {
365
366 if (this._menuList)
367 return this._menuList;
Akron8b592d42018-01-26 18:33:06 +0100368
369 // Join spans and relations
370 var treeLayers = []
371 var spans = this.getSpans();
372 var rels = this.getRels();
373 var i;
374 for (i in spans) {
375 treeLayers.push(spans[i]);
376 };
377 for (i in rels) {
378 treeLayers.push(rels[i]);
379 };
380
381 // Get spans
382 treeLayers = treeLayers.sort(
383 function (a, b) {
384 if (a.foundry < b.foundry) {
385 return -1;
386 }
387 else if (a.foundry > b.foundry) {
388 return 1;
389 }
390 else if (a.layer < b.layer) {
391 return -1;
392 }
393 else if (a.layer > b.layer) {
394 return 1;
395 };
396 return 0;
397 });
398
399 var menuList = [];
400
401 // Show tree views
402 for (var i = 0; i < treeLayers.length; i++) {
403 var span = treeLayers[i];
404
405 // Add foundry/layer to menu list
406 menuList.push([
407 span.foundry + '/' + span.layer,
408 span.foundry,
409 span.layer,
410 span.type
411 ]);
412 };
413
414 // Create tree menu
Akroneaba63e2018-01-26 19:49:30 +0100415 this._menuList = menuList;
416 return menuList;
Akron8b592d42018-01-26 18:33:06 +0100417 /*
418 var span = document.createElement('p');
419 span.classList.add('addtree');
420 span.appendChild(document.createTextNode(loc.ADDTREE));
421 var treeElement = treemenu.element();
422 span.appendChild(treeElement);
423
424 span.addEventListener('click', function (e) {
425 treemenu.show();
426 treemenu.focus();
427 });
428 */
429 },
430
431
432 /**
433 * Get tree menu.
434 * There is only one menu rendered
435 * - no matter how many trees exist
436 */
437 /*
438 treeMenu : function (list) {
439 if (this._treeMenu !== undefined)
440 return this._treeMenu;
441
442 return this._treeMenu = matchTreeMenuClass.create(this, list);
443 },
444 */
Nils Diewald7c8ced22015-04-15 19:21:00 +0000445
Nils Diewalda297f062015-04-02 00:23:46 +0000446 /**
447 * Get match element.
448 */
449 element : function () {
Nils Diewald7c8ced22015-04-15 19:21:00 +0000450 return this._element; // May be null
Nils Diewalda297f062015-04-02 00:23:46 +0000451 }
452 };
Nils Diewald0e6992a2015-04-14 20:13:52 +0000453});