blob: a42ae260c01d54e1bc49406adf85eba93c5112b0 [file] [log] [blame]
Akronfbf3a782017-06-28 17:34:28 +02001/**
2 * QueryCreator for Kalamar.
3 *
4 * @author Nils Diewald
5 */
6define(['util'], function () {
7 "use strict";
8
9 var loc = KorAP.Locale;
10 loc.NEW_QUERY = loc.NEW_QUERY || 'New Query';
11
Akron7ec5f392017-06-29 15:05:44 +020012 function _getAnnotation (prefix, target) {
13 var annotation = '';
14
15 // Complex annotation
16 if (target.childNodes.length > 1) {
17 var orGroup = [];
18 target.childNodes.forEach(function (item) {
19 if (item.nodeType === 3)
20 orGroup.push(prefix + item.data);
21 });
22 return '(' + orGroup.sort().join(' | ') + ')';
23 }
24
25 // Simple annotation
26 else {
27 return prefix + target.innerText;
28 };
29 };
30
Akronfbf3a782017-06-28 17:34:28 +020031 return {
32 create : function (matchInfo) {
33 return Object.create(this)._init(matchInfo);
34 },
35
36 // Initialize query creator
37 _init : function (matchInfo) {
38
Akronb46d8e32017-06-29 14:26:14 +020039 // Parameter checks
40 if (matchInfo === undefined)
41 throw new Error('Missing parameters');
42 else if (!(matchInfo instanceof Node))
43 throw new Error('Requires element');
44
45 // Collect the token sequence in an array
Akronfbf3a782017-06-28 17:34:28 +020046 this._query = []
Akronb46d8e32017-06-29 14:26:14 +020047
48 // Remember the matchinfo that is the parent of
49 // the matchtable and the query frafment
Akronfbf3a782017-06-28 17:34:28 +020050 this._matchInfo = matchInfo;
51
Akrone8ea0002017-06-28 18:51:52 +020052 // Get the match table
53 this._matchTable = this._matchInfo.getElementsByClassName('matchtable')[0];
54
Akronb46d8e32017-06-29 14:26:14 +020055 if (this._matchTable === undefined)
56 throw new Error('Element contains no match table');
57
Akronfbf3a782017-06-28 17:34:28 +020058 // Listen on the match table
Akrone8ea0002017-06-28 18:51:52 +020059 this._matchTable.addEventListener(
Akronfbf3a782017-06-28 17:34:28 +020060 "click", this.clickOnAnno.bind(this), false
61 );
62
63 // Initialize element
64 this._element = document.createElement('p');
65 this._element.className = 'queryfragment';
66
67 // Prepend info text
68 this._element.appendChild(document.createElement('span'))
69 .appendChild(document.createTextNode(loc.NEW_QUERY + ':'));
70
71 // Append query fragment part
72 this._queryFragment = this._element.appendChild(
73 document.createElement('span')
74 );
75
Akron99713ef2017-06-28 18:19:28 +020076 // Event when the query fragment is clicked
77 this._element.addEventListener('click', this.toQueryBar.bind(this), 1);
78
79 // Get some basic information - see tutorial.js
80 // It may be better to consultate a global object like KorAP.Hint, however ...
81 this._ql = document.getElementById("ql-field");
82 this._q = document.getElementById("q-field")
83
Akronfbf3a782017-06-28 17:34:28 +020084 this._shown = false;
85 return this;
86 },
87
Akron7ec5f392017-06-29 15:05:44 +020088
Akron99713ef2017-06-28 18:19:28 +020089 // Realease a click event on the annotation table
Akronfbf3a782017-06-28 17:34:28 +020090 clickOnAnno : function (event) {
91
92 // Listen for clicks on table cells
93 if (event.target !== event.currentTarget) {
94
95 // Get target event
96 var target = event.target;
97
98 if (target.tagName == 'TD') {
99
Akron78655d12017-06-28 18:56:57 +0200100 if (target.innerText == '')
101 return;
102
Akronfbf3a782017-06-28 17:34:28 +0200103 // Check foundry and layer
104 var head = target.parentNode.getElementsByTagName('th');
105 var foundry = head[0].innerText;
106 var layer = head[1].innerText;
107
108 // Check index position:
109 var i = -2;
110 var sib = target;
111 while((sib = sib.previousSibling) != null) {
112 if (sib.nodeType === 1)
113 i++;
114 };
115
Akron2bd146c2017-06-28 19:10:36 +0200116
117 var prefix = foundry + '/' + layer + '=';
118 var annotation = '';
119
Akron7ec5f392017-06-29 15:05:44 +0200120 // Get annotation value from cell
121 var annotation = _getAnnotation(prefix, target);
Akron2bd146c2017-06-28 19:10:36 +0200122
123 // Add term
124 this.toggleInToken(target, i, annotation);
Akronfbf3a782017-06-28 17:34:28 +0200125 }
126
127 // Get orth values
128 else if (target.tagName == 'TH') {
129
130 // The head is in the top row
131 if (target.parentNode.parentNode.tagName == 'THEAD') {
132
133 var i = -2;
134 var sib = target;
135 while ((sib = sib.previousSibling) != null) {
136 if (sib.nodeType === 1)
137 i++;
138 };
139
140 // Target is an orth
141 if (i >= 0) {
142 this.toggleInToken(target, i, 'orth=' + target.innerText);
143 }
144 }
145
146 // The head refers to the complete row
147 else {
148
149 // Check foundry and layer
150 var head = target.parentNode.getElementsByTagName('th');
151 var foundry = head[0].innerText;
152 var layer = head[1].innerText;
153 var prefix = foundry + '/' + layer + '=';
154
155 // Iterate over all siblings
156 var i = 0;
157 var sib = target;
158 while ((sib = sib.nextSibling) != null) {
159 if (sib.nodeType !== 1 || sib.tagName === 'TH')
160 continue;
Akron7ec5f392017-06-29 15:05:44 +0200161
162 // Get annotation value from cell
163 var annotation = _getAnnotation(prefix, sib);
164
165 // Add annotation to string
166 this.addToToken(i, annotation);
167
Akronfbf3a782017-06-28 17:34:28 +0200168 sib.className = 'chosen';
169 i++;
170 };
171 };
172 };
173 };
174
175 event.stopPropagation();
176 },
177
178 // Add term to token
179 addToToken : function (index, term) {
180
181 var token = this._query[index];
182
183 // Initialize token
184 if (token === undefined) {
185 token = this._query[index] = [];
186 };
187
188 // Push to token array
189 token.push(term);
190
191 // Make terms unique
192 this._query[index] = token.filter(
193 function (e, i, arr) {
194 return arr.lastIndexOf(e) === i;
195 }
196 );
197
198 this.show();
199 },
200
201 // Remove term from token
202 removeFromToken : function (index, term) {
203 var token = this._query[index];
204
205 if (token === undefined)
206 return;
207
208 token.splice(token.indexOf(term), 1);
209
210 if (token.length > 0)
211 this._query[index] = token;
212 else
213 this._query[index] = undefined;
214
215 this.show();
216 },
217
Akronb46d8e32017-06-29 14:26:14 +0200218
Akronfbf3a782017-06-28 17:34:28 +0200219 // Get element representing annotation line
220 element : function () {
221 return this._element;
222 },
223
Akronb46d8e32017-06-29 14:26:14 +0200224
225 // Check if the query fragment is shown
226 shown : function () {
227 return this._shown;
228 },
229
230
Akronfbf3a782017-06-28 17:34:28 +0200231 // Show annotation fragment
232 show : function () {
233
234 var str = this.toString();
235
236 // Fragment is empty
237 if (str === '') {
238
239 // Hide element
240 if (this._shown === true) {
241 this._matchInfo.removeChild(this._element);
242 this._shown = false;
243 }
244 }
245
246 // Fragment is defined
247 else {
248
249 if (this._shown === false) {
Akrone8ea0002017-06-28 18:51:52 +0200250 this._matchInfo.insertBefore(this._element, this._matchTable.nextSibling);
Akronfbf3a782017-06-28 17:34:28 +0200251 this._shown = true;
252 };
253
254 // set value
255 this._queryFragment.innerText = str;
256 };
257 },
258
259 // Add term to token if not yet chosen, otherwise remove
260 toggleInToken : function (node, index, term) {
261 if (node.className == 'chosen') {
262 this.removeFromToken(index, term);
263 node.className = '';
264 }
265 else {
266 this.addToToken(index, term);
267 node.className = 'chosen';
268 };
269 },
270
271
272 // Stringify annotation
273 toString : function () {
274 var str = '';
275 this._query.forEach(function (token) {
276 if (token !== undefined) {
277 str += '[' + token.sort().join(" & ") + ']';
278 };
279 });
280 return str;
281 },
282
Akron99713ef2017-06-28 18:19:28 +0200283 // Add query fragment to query bar
284 toQueryBar : function (e) {
285
Akronb46d8e32017-06-29 14:26:14 +0200286 if (this._ql === undefined || this._q === undefined)
287 return;
288
Akron99713ef2017-06-28 18:19:28 +0200289 // Set query language field
290 var qlf = this._ql.options;
291 for (var i in qlf) {
292 if (qlf[i].value == 'poliqarp') {
293 qlf[i].selected = true;
294 break;
295 };
296 };
297
298 // Insert to query bar
299 this._q.value = this.toString();
300
301 // Scroll to top
302 window.scrollTo(0, 0);
Akronfbf3a782017-06-28 17:34:28 +0200303 }
304 };
305});