blob: 06fcb187f032e998fc9556070a9fe22a6d139e4f [file] [log] [blame]
Nils Diewald3a2d8022014-12-16 02:45:41 +00001var KorAP = KorAP || {};
Nils Diewald3a2d8022014-12-16 02:45:41 +00002
Nils Diewald8f4e2542014-12-19 04:42:09 +00003// TODO: Implement a working localization solution!
4// TODO: Support 'update' method to update elements on change
Nils Diewald966abf12014-12-20 02:27:45 +00005// TODO: Implement "toQuery"
Nils Diewaldd0770492014-12-19 03:55:00 +00006
7/*
Nils Diewaldd599d542015-01-08 20:41:34 +00008 Error codes:
Nils Diewaldd0770492014-12-19 03:55:00 +00009 701: "JSON-LD group has no @type attribute"
10 704: "Operation needs operand list"
Nils Diewald3a2d8022014-12-16 02:45:41 +000011 802: "Match type is not supported by value type"
12 804: "Unknown value type"
13 805: "Value is invalid"
14 806: "Value is not a valid date string"
15 807: "Value is not a valid regular expression"
Nils Diewald3a2d8022014-12-16 02:45:41 +000016 810: "Unknown document group operation" (like 711)
17 811: "Document group expects operation" (like 703)
18 812: "Operand not supported in document group" (like 744)
Nils Diewaldd0770492014-12-19 03:55:00 +000019 813: "Collection type is not supported" (like 713)
20*/
21
Nils Diewald3a2d8022014-12-16 02:45:41 +000022(function (KorAP) {
23 "use strict";
24
25 // Default log message
26 KorAP.log = KorAP.log || function (type, msg) {
27 console.log(type + ": " + msg);
28 };
29
30 KorAP._validStringMatchRE = new RegExp("^(?:eq|ne|contains)$");
31 KorAP._validRegexMatchRE = new RegExp("^(?:eq|ne)$");
Nils Diewaldd0770492014-12-19 03:55:00 +000032 KorAP._validDateMatchRE = new RegExp("^[lg]?eq$");
Nils Diewald3a2d8022014-12-16 02:45:41 +000033 KorAP._validDateRE = new RegExp("^(?:\\d{4})(?:-\\d\\d(?:-\\d\\d)?)?$");
34 KorAP._validGroupOpRE = new RegExp("^(?:and|or)$");
Nils Diewaldf219eb82015-01-07 20:15:42 +000035 KorAP._quote = new RegExp("([\"\\\\])", 'g');
Nils Diewald3a2d8022014-12-16 02:45:41 +000036
Nils Diewaldf219eb82015-01-07 20:15:42 +000037 var loc = (KorAP.Locale = KorAP.Locale || {} );
38 loc.AND = loc.AND || 'and';
39 loc.OR = loc.OR || 'or';
40 loc.DEL = loc.DEL || '×';
41 loc.EMPTY = loc.EMPTY || '⋯'
Nils Diewaldd0770492014-12-19 03:55:00 +000042
Nils Diewaldd599d542015-01-08 20:41:34 +000043
Nils Diewald966abf12014-12-20 02:27:45 +000044 function _bool (bool) {
45 return (bool === undefined || bool === false) ? false : true;
46 };
47
Nils Diewaldd599d542015-01-08 20:41:34 +000048
Nils Diewald966abf12014-12-20 02:27:45 +000049 function _removeChildren (node) {
50 // Remove everything underneath
Nils Diewald8f6b6102015-01-08 18:25:33 +000051 while (node.firstChild)
Nils Diewald966abf12014-12-20 02:27:45 +000052 node.removeChild(node.firstChild);
Nils Diewald966abf12014-12-20 02:27:45 +000053 };
54
Nils Diewald4019bd22015-01-08 19:57:50 +000055
Nils Diewald9fcc1712015-01-09 14:24:32 +000056 // Add doc
57 KorAP._add = function (obj, type) {
58 var ref = obj.parentNode.refTo;
59 if (ref.ldType() === 'docGroup') {
Nils Diewaldd599d542015-01-08 20:41:34 +000060 console.log('~~~~~~~~~');
61 }
Nils Diewald9fcc1712015-01-09 14:24:32 +000062 else if (ref.ldType() === 'doc') {
63 var parent = ref.parent();
64// Todo: Check if parent is a group
65 if (parent.operation() === type) {
66 parent.newAfter(ref);
67 }
68 else {
69 ref.wrap(type);
70 };
Nils Diewaldd599d542015-01-08 20:41:34 +000071 };
Nils Diewald4019bd22015-01-08 19:57:50 +000072 };
73
Nils Diewaldd599d542015-01-08 20:41:34 +000074
Nils Diewald4019bd22015-01-08 19:57:50 +000075 // Remove doc or docGroup
76 KorAP._delete = function (e) {
Nils Diewald9fcc1712015-01-09 14:24:32 +000077 var ref = this.parentNode.refTo;
78 if (ref.parent().ldType() !== null)
79 ref.parent().delOperand(ref).update();
Nils Diewald4019bd22015-01-08 19:57:50 +000080 else
Nils Diewald9fcc1712015-01-09 14:24:32 +000081 ref.parent().clean();
Nils Diewald4019bd22015-01-08 19:57:50 +000082 };
83
Nils Diewaldd599d542015-01-08 20:41:34 +000084
85 /**
86 * Virtual Collection
87 */
Nils Diewald3a2d8022014-12-16 02:45:41 +000088 KorAP.VirtualCollection = {
Nils Diewaldf219eb82015-01-07 20:15:42 +000089 ldType : function () {
90 return null;
91 },
Nils Diewaldd599d542015-01-08 20:41:34 +000092
Nils Diewald3a2d8022014-12-16 02:45:41 +000093 create : function () {
94 return Object.create(KorAP.VirtualCollection);
95 },
Nils Diewaldd599d542015-01-08 20:41:34 +000096
Nils Diewald4019bd22015-01-08 19:57:50 +000097 clean : function () {
98 if (this._root.ldType() !== "non") {
99 this._root.destroy();
100 this.root(KorAP.UnspecifiedDoc.create(this));
101 };
102 return this;
103 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000104
Nils Diewaldd0770492014-12-19 03:55:00 +0000105 render : function (json) {
106 var obj = Object.create(KorAP.VirtualCollection);
107
108 if (json !== undefined) {
109 // Root object
110 if (json['@type'] == 'korap:doc') {
Nils Diewaldf219eb82015-01-07 20:15:42 +0000111 obj._root = KorAP.Doc.create(obj, json);
Nils Diewaldd0770492014-12-19 03:55:00 +0000112 }
113 else if (json['@type'] == 'korap:docGroup') {
Nils Diewaldf219eb82015-01-07 20:15:42 +0000114 obj._root = KorAP.DocGroup.create(obj, json);
Nils Diewaldd0770492014-12-19 03:55:00 +0000115 }
116 else {
117 KorAP.log(813, "Collection type is not supported");
118 return;
119 };
120 }
121
122 else {
123 // Add unspecified object
Nils Diewaldf219eb82015-01-07 20:15:42 +0000124 obj._root = KorAP.UnspecifiedDoc.create(obj);
Nils Diewaldd0770492014-12-19 03:55:00 +0000125 };
126
Nils Diewald8e7182e2015-01-08 15:02:07 +0000127 // Init element and update
128 obj.update();
Nils Diewaldd0770492014-12-19 03:55:00 +0000129
130 return obj;
Nils Diewald3a2d8022014-12-16 02:45:41 +0000131 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000132
Nils Diewaldf219eb82015-01-07 20:15:42 +0000133 root : function (obj) {
Nils Diewald8e7182e2015-01-08 15:02:07 +0000134 if (arguments.length === 1) {
Nils Diewald8f6b6102015-01-08 18:25:33 +0000135 var e = this.element();
136 if (e.firstChild !== null) {
137 if (e.firstChild !== obj.element())
138 e.replaceChild(obj.element(), e.firstChild);
139 }
140
141 // Append root element
142 else {
143 e.appendChild(obj.element());
144 };
145
146 // Update parent child relations
Nils Diewaldf219eb82015-01-07 20:15:42 +0000147 this._root = obj;
Nils Diewald8f6b6102015-01-08 18:25:33 +0000148 obj.parent(this);
149
Nils Diewald8e7182e2015-01-08 15:02:07 +0000150 this.update();
151 };
Nils Diewaldd0770492014-12-19 03:55:00 +0000152 return this._root;
Nils Diewald3a2d8022014-12-16 02:45:41 +0000153 },
Nils Diewald8f6b6102015-01-08 18:25:33 +0000154
Nils Diewaldd0770492014-12-19 03:55:00 +0000155 element : function () {
156 if (this._element !== undefined)
157 return this._element;
158
159 this._element = document.createElement('div');
160 this._element.setAttribute('class', 'vc');
Nils Diewald8e7182e2015-01-08 15:02:07 +0000161
Nils Diewald8f6b6102015-01-08 18:25:33 +0000162 // Initialize root
163 this._element.appendChild(this._root.element());
164
Nils Diewaldd0770492014-12-19 03:55:00 +0000165 return this._element;
Nils Diewaldf219eb82015-01-07 20:15:42 +0000166 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000167
168 update : function () {
169 this._root.update();
170 return this;
171 },
172
Nils Diewaldf219eb82015-01-07 20:15:42 +0000173 toJson : function () {
174 return this._root.toJson();
175 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000176
177 toQuery : function () {
178 return this._root.toQuery();
Nils Diewald3a2d8022014-12-16 02:45:41 +0000179 }
180 };
181
Nils Diewaldd599d542015-01-08 20:41:34 +0000182
Nils Diewald8f4e2542014-12-19 04:42:09 +0000183 /**
184 * Operators for criteria
185 */
Nils Diewaldd0770492014-12-19 03:55:00 +0000186 KorAP.Operators = {
187 create : function (and, or, del) {
188 var op = Object.create(KorAP.Operators);
189 op.and(and);
190 op.or(or);
191 op.del(del);
192 return op;
193 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000194
Nils Diewaldd0770492014-12-19 03:55:00 +0000195 update : function () {
Nils Diewaldd0770492014-12-19 03:55:00 +0000196 // Init the element
197 if (this._element === undefined)
198 return this.element();
199
200 var op = this._element;
201
Nils Diewald0297ba12015-01-05 21:56:12 +0000202 op.refTo = this.parent();
203
Nils Diewaldd0770492014-12-19 03:55:00 +0000204 // Remove everything underneath
Nils Diewald966abf12014-12-20 02:27:45 +0000205 _removeChildren(op);
Nils Diewaldd0770492014-12-19 03:55:00 +0000206
207 // Add and button
208 if (this._and === true) {
209 var andE = document.createElement('span');
210 andE.setAttribute('class', 'and');
Nils Diewald9fcc1712015-01-09 14:24:32 +0000211 andE.addEventListener('click', function () { return KorAP._add(this, 'and') }, false);
Nils Diewald8f6b6102015-01-08 18:25:33 +0000212 andE.appendChild(
213 document.createTextNode(KorAP.Locale.AND)
214 );
Nils Diewaldd0770492014-12-19 03:55:00 +0000215 op.appendChild(andE);
216 };
217
218 // Add or button
219 if (this._or === true) {
220 var orE = document.createElement('span');
221 orE.setAttribute('class', 'or');
Nils Diewald9fcc1712015-01-09 14:24:32 +0000222 orE.addEventListener('click', function () { return KorAP._add(this, 'or') }, false);
Nils Diewaldd0770492014-12-19 03:55:00 +0000223 orE.appendChild(document.createTextNode(KorAP.Locale.OR));
224 op.appendChild(orE);
225 };
226
227 // Add delete button
228 if (this._del === true) {
229 var delE = document.createElement('span');
230 delE.setAttribute('class', 'delete');
231 delE.appendChild(document.createTextNode(KorAP.Locale.DEL));
Nils Diewald0297ba12015-01-05 21:56:12 +0000232 delE.addEventListener('click', KorAP._delete, false);
Nils Diewaldd0770492014-12-19 03:55:00 +0000233 op.appendChild(delE);
234 };
Nils Diewald966abf12014-12-20 02:27:45 +0000235
236 return op;
Nils Diewaldd0770492014-12-19 03:55:00 +0000237 },
Nils Diewald0297ba12015-01-05 21:56:12 +0000238
239 // Be aware! This may be cyclic
240 parent : function (obj) {
241 if (arguments.length === 1)
242 this._parent = obj;
243 return this._parent;
244 },
Nils Diewald5c817a42015-01-06 01:08:56 +0000245
Nils Diewaldd0770492014-12-19 03:55:00 +0000246 element : function () {
247
248 // Return existing element
249 if (this._element !== undefined)
250 return this._element;
251
252 this._element = document.createElement('div');
253 this._element.setAttribute('class', 'operators');
254
255 // Init elements
256 this.update();
257 return this._element;
258 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000259
Nils Diewaldd0770492014-12-19 03:55:00 +0000260 and : function (bool) {
261 if (arguments.length === 1)
Nils Diewald966abf12014-12-20 02:27:45 +0000262 this._and = _bool(bool);
Nils Diewaldd0770492014-12-19 03:55:00 +0000263 return this._and;
264 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000265
Nils Diewaldd0770492014-12-19 03:55:00 +0000266 or : function (bool) {
267 if (arguments.length === 1)
Nils Diewald966abf12014-12-20 02:27:45 +0000268 this._or = _bool(bool);
Nils Diewaldd0770492014-12-19 03:55:00 +0000269 return this._or;
270 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000271
Nils Diewaldd0770492014-12-19 03:55:00 +0000272 del : function (bool) {
273 if (arguments.length === 1)
Nils Diewald966abf12014-12-20 02:27:45 +0000274 this._del = _bool(bool);
Nils Diewaldd0770492014-12-19 03:55:00 +0000275 return this._del;
276 }
277 };
278
279
280 /**
281 * Unspecified criterion
282 */
Nils Diewald8f4e2542014-12-19 04:42:09 +0000283 KorAP.UnspecifiedDoc = {
Nils Diewald4019bd22015-01-08 19:57:50 +0000284 _ldType : "non",
Nils Diewaldd0770492014-12-19 03:55:00 +0000285 create : function (parent) {
Nils Diewald8f6b6102015-01-08 18:25:33 +0000286 var obj = Object.create(KorAP.JsonLD).
287 upgradeTo(KorAP.UnspecifiedDoc);
288
Nils Diewaldd0770492014-12-19 03:55:00 +0000289 if (parent !== undefined)
290 obj._parent = parent;
Nils Diewald8f6b6102015-01-08 18:25:33 +0000291
Nils Diewaldd0770492014-12-19 03:55:00 +0000292 return obj;
293 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000294
Nils Diewald966abf12014-12-20 02:27:45 +0000295 update : function () {
Nils Diewald4019bd22015-01-08 19:57:50 +0000296
Nils Diewald966abf12014-12-20 02:27:45 +0000297 if (this._element === undefined)
298 return this.element();
299
Nils Diewald8f6b6102015-01-08 18:25:33 +0000300 // Remove element content
Nils Diewald966abf12014-12-20 02:27:45 +0000301 _removeChildren(this._element);
302
303 var ellipsis = document.createElement('span');
Nils Diewaldf219eb82015-01-07 20:15:42 +0000304 ellipsis.appendChild(document.createTextNode(loc.EMPTY));
Nils Diewald966abf12014-12-20 02:27:45 +0000305 this._element.appendChild(ellipsis);
306
307 // Set operators
308 var op = this.operators(
309 false,
310 false,
311 // No delete object, if this is the root
Nils Diewald8f6b6102015-01-08 18:25:33 +0000312 (this._parent !== undefined &&
313 this.parent().ldType() !== null) ? true : false
Nils Diewald966abf12014-12-20 02:27:45 +0000314 );
315
316 this._element.appendChild(
317 op.element()
318 );
319
Nils Diewald966abf12014-12-20 02:27:45 +0000320 return this.element();
321 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000322
Nils Diewaldd0770492014-12-19 03:55:00 +0000323 element : function () {
324 if (this._element !== undefined)
325 return this._element;
326 this._element = document.createElement('div');
Nils Diewaldd599d542015-01-08 20:41:34 +0000327 this._element.setAttribute('class', 'doc unspecified');
Nils Diewald966abf12014-12-20 02:27:45 +0000328 this.update();
Nils Diewaldd0770492014-12-19 03:55:00 +0000329 return this._element;
330 }
331 };
332
333
Nils Diewald8f4e2542014-12-19 04:42:09 +0000334 /**
Nils Diewaldd599d542015-01-08 20:41:34 +0000335 * Document criterion
Nils Diewald8f4e2542014-12-19 04:42:09 +0000336 */
337 KorAP.Doc = {
338 _ldType : "doc",
339 _obj : function () { return KorAP.Doc; },
Nils Diewaldd0770492014-12-19 03:55:00 +0000340
341 create : function (parent, json) {
Nils Diewald8f6b6102015-01-08 18:25:33 +0000342 var obj = Object(KorAP.JsonLD).
343 create().
344 upgradeTo(KorAP.Doc).
345 fromJson(json);
346
Nils Diewaldd0770492014-12-19 03:55:00 +0000347 if (parent !== undefined)
348 obj._parent = parent;
Nils Diewald8f6b6102015-01-08 18:25:33 +0000349
350 obj._changed = true;
Nils Diewaldd0770492014-12-19 03:55:00 +0000351 return obj;
352 },
Nils Diewald5c817a42015-01-06 01:08:56 +0000353
Nils Diewald966abf12014-12-20 02:27:45 +0000354 update : function () {
355 if (this._element === undefined)
356 return this.element();
Nils Diewaldd0770492014-12-19 03:55:00 +0000357
Nils Diewald8f6b6102015-01-08 18:25:33 +0000358 // Get element
Nils Diewald966abf12014-12-20 02:27:45 +0000359 var e = this._element;
360
Nils Diewald8f6b6102015-01-08 18:25:33 +0000361 // Check if there is a change
362 if (this._changed) {
Nils Diewald966abf12014-12-20 02:27:45 +0000363
Nils Diewald8f6b6102015-01-08 18:25:33 +0000364 // Added key
365 var key = document.createElement('span');
366 key.setAttribute('class', 'key');
367 if (this.key())
368 key.appendChild(document.createTextNode(this.key()));
Nils Diewald966abf12014-12-20 02:27:45 +0000369
Nils Diewald8f6b6102015-01-08 18:25:33 +0000370 // Added match operator
371 var matchop = document.createElement('span');
372 matchop.setAttribute('data-type', this.type());
373 matchop.setAttribute('class', 'match');
374 matchop.appendChild(
375 document.createTextNode(this.matchop())
376 );
377
378 // Added match operator
379 var value = document.createElement('span');
380 value.setAttribute('data-type', this.type());
381 value.setAttribute('class', 'value');
382 if (this.value())
383 value.appendChild(
384 document.createTextNode(this.value())
385 );
386
387 // Remove all element children
388 _removeChildren(e);
389
390 // Add spans
391 e.appendChild(key);
392 e.appendChild(matchop);
393 e.appendChild(value);
394
395 this._changed = false;
396 };
397
398 if (this._parent !== undefined) {
399 // Set operators
400 var op = this.operators(
401 true,
402 true,
Nils Diewald4019bd22015-01-08 19:57:50 +0000403 true
Nils Diewald8f6b6102015-01-08 18:25:33 +0000404 );
405
406 // Append new operators
407 e.appendChild(op.element());
408 };
Nils Diewald966abf12014-12-20 02:27:45 +0000409
Nils Diewaldd0770492014-12-19 03:55:00 +0000410 return e;
411 },
412
Nils Diewald966abf12014-12-20 02:27:45 +0000413 element : function () {
414 if (this._element !== undefined)
415 return this._element;
416
417 this._element = document.createElement('div');
418 this._element.setAttribute('class', 'doc');
419
420 this.update();
421 return this._element;
422 },
423
Nils Diewaldd0770492014-12-19 03:55:00 +0000424 // Wrap a new operation around the doc element
425 wrap : function (op) {
Nils Diewald9fcc1712015-01-09 14:24:32 +0000426 var parent = this.parent();
427 var group = KorAP.DocGroup.create(parent);
428 group.operation(op);
Nils Diewald966abf12014-12-20 02:27:45 +0000429 group.append(this);
Nils Diewald9fcc1712015-01-09 14:24:32 +0000430 group.append();
431 return parent.replaceOperand(this, group).update();
Nils Diewaldd0770492014-12-19 03:55:00 +0000432 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000433
Nils Diewald3a2d8022014-12-16 02:45:41 +0000434 // Deserialize from json
435 fromJson : function (json) {
Nils Diewald3a2d8022014-12-16 02:45:41 +0000436 if (json === undefined)
Nils Diewaldd0770492014-12-19 03:55:00 +0000437 return this;
Nils Diewald3a2d8022014-12-16 02:45:41 +0000438
Nils Diewald3a2d8022014-12-16 02:45:41 +0000439 if (json["@type"] !== "korap:doc") {
440 KorAP.log(701, "JSON-LD group has no @type attribute");
441 return;
442 };
443
Nils Diewald3a2d8022014-12-16 02:45:41 +0000444 if (json["value"] === undefined ||
445 typeof json["value"] != 'string') {
446 KorAP.log(805, "Value is invalid");
447 return;
448 };
449
450 // There is a defined key
451 if (json["key"] !== undefined &&
452 typeof json["key"] === 'string') {
453
454 // Set key
Nils Diewaldd0770492014-12-19 03:55:00 +0000455 this.key(json["key"]);
Nils Diewald3a2d8022014-12-16 02:45:41 +0000456
457 // Set match operation
458 if (json["match"] !== undefined) {
Nils Diewaldd0770492014-12-19 03:55:00 +0000459 if (typeof json["match"] === 'string') {
460 this.matchop(json["match"]);
461 }
Nils Diewald3a2d8022014-12-16 02:45:41 +0000462 else {
463 KorAP.log(802, "Match type is not supported by value type");
464 return;
465 };
466 };
467
468 // Key is a string
469 if (json["type"] === undefined ||
470 json["type"] == "type:string") {
Nils Diewaldd0770492014-12-19 03:55:00 +0000471 this.type("string");
Nils Diewald3a2d8022014-12-16 02:45:41 +0000472
473 // Check match type
Nils Diewaldd0770492014-12-19 03:55:00 +0000474 if (!KorAP._validStringMatchRE.test(this.matchop())) {
Nils Diewald3a2d8022014-12-16 02:45:41 +0000475 KorAP.log(802, "Match type is not supported by value type");
476 return;
477 };
478
479 // Set string value
Nils Diewaldd0770492014-12-19 03:55:00 +0000480 this.value(json["value"]);
Nils Diewald3a2d8022014-12-16 02:45:41 +0000481 }
482
483 // Key is a date
484 else if (json["type"] === "type:date") {
Nils Diewaldd0770492014-12-19 03:55:00 +0000485 this.type("date");
Nils Diewald3a2d8022014-12-16 02:45:41 +0000486
487 if (json["value"] !== undefined &&
488 KorAP._validDateRE.test(json["value"])) {
489
Nils Diewaldd0770492014-12-19 03:55:00 +0000490 if (!KorAP._validDateMatchRE.test(this.matchop())) {
Nils Diewald3a2d8022014-12-16 02:45:41 +0000491 KorAP.log(802, "Match type is not supported by value type");
492 return;
493 };
494
495 // Set value
Nils Diewaldd0770492014-12-19 03:55:00 +0000496 this.value(json["value"]);
Nils Diewald3a2d8022014-12-16 02:45:41 +0000497 }
498 else {
499 KorAP.log(806, "Value is not a valid date string");
500 return;
501 };
502 }
503
504 // Key is a regular expression
505 else if (json["type"] === "type:regex") {
Nils Diewaldd0770492014-12-19 03:55:00 +0000506 this.type("regex");
Nils Diewald3a2d8022014-12-16 02:45:41 +0000507
508 try {
509
510 // Try to create a regular expression
511 var check = new RegExp(json["value"]);
512
Nils Diewaldd0770492014-12-19 03:55:00 +0000513 if (!KorAP._validRegexMatchRE.test(this.matchop())) {
Nils Diewald3a2d8022014-12-16 02:45:41 +0000514 KorAP.log(802, "Match type is not supported by value type");
515 return;
516 };
517
Nils Diewaldd0770492014-12-19 03:55:00 +0000518 this.value(json["value"]);
Nils Diewald3a2d8022014-12-16 02:45:41 +0000519 }
Nils Diewaldd0770492014-12-19 03:55:00 +0000520
Nils Diewald3a2d8022014-12-16 02:45:41 +0000521 catch (e) {
522 KorAP.log(807, "Value is not a valid regular expression");
523 return;
524 };
Nils Diewaldd0770492014-12-19 03:55:00 +0000525 this.type("regex");
Nils Diewald3a2d8022014-12-16 02:45:41 +0000526 }
527
528 else {
529 KorAP.log(804, "Unknown value type");
530 return;
531 };
532 };
533
534 return this;
535 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000536
Nils Diewaldd0770492014-12-19 03:55:00 +0000537 key : function (value) {
Nils Diewald8f6b6102015-01-08 18:25:33 +0000538 if (arguments.length === 1) {
Nils Diewaldd0770492014-12-19 03:55:00 +0000539 this._key = value;
Nils Diewald8f6b6102015-01-08 18:25:33 +0000540 this._changed = true;
541 };
Nils Diewald3a2d8022014-12-16 02:45:41 +0000542 return this._key;
543 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000544
Nils Diewaldd0770492014-12-19 03:55:00 +0000545 matchop : function (match) {
Nils Diewald8f6b6102015-01-08 18:25:33 +0000546 if (arguments.length === 1) {
Nils Diewaldd0770492014-12-19 03:55:00 +0000547 this._matchop = match.replace(/^match:/, '');
Nils Diewald8f6b6102015-01-08 18:25:33 +0000548 this._changed = true;
549 };
Nils Diewald3a2d8022014-12-16 02:45:41 +0000550 return this._matchop || "eq";
551 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000552
Nils Diewaldd0770492014-12-19 03:55:00 +0000553 type : function (type) {
Nils Diewald8f6b6102015-01-08 18:25:33 +0000554 if (arguments.length === 1) {
Nils Diewaldd0770492014-12-19 03:55:00 +0000555 this._type = type;
Nils Diewald8f6b6102015-01-08 18:25:33 +0000556 this._changed = true;
557 };
Nils Diewald3a2d8022014-12-16 02:45:41 +0000558 return this._type || "string";
559 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000560
Nils Diewaldd0770492014-12-19 03:55:00 +0000561 value : function (value) {
Nils Diewald8f6b6102015-01-08 18:25:33 +0000562 if (arguments.length === 1) {
Nils Diewaldd0770492014-12-19 03:55:00 +0000563 this._value = value;
Nils Diewald8f6b6102015-01-08 18:25:33 +0000564 this._changed = true;
565 };
Nils Diewald3a2d8022014-12-16 02:45:41 +0000566 return this._value;
567 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000568
Nils Diewald3a2d8022014-12-16 02:45:41 +0000569 toJson : function () {
Nils Diewaldd0770492014-12-19 03:55:00 +0000570 if (!this.matchop() || !this.key())
Nils Diewald3a2d8022014-12-16 02:45:41 +0000571 return {};
572
573 return {
Nils Diewaldd0770492014-12-19 03:55:00 +0000574 "@type" : "korap:" + this.ldType(),
575 "key" : this.key(),
576 "match" : "match:" + this.matchop(),
577 "value" : this.value() || '',
578 "type" : "type:" + this.type()
Nils Diewald3a2d8022014-12-16 02:45:41 +0000579 };
Nils Diewaldf219eb82015-01-07 20:15:42 +0000580 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000581
582 toQuery : function () {
Nils Diewaldf219eb82015-01-07 20:15:42 +0000583 if (!this.matchop() || !this.key())
584 return "";
585
586 // Build doc string based on key
587 var string = this.key() + ' ';
588
589 // Add match operator
590 switch (this.matchop()) {
591 case "ne":
592 string += '!=';
593 break;
594 case "contains":
595 string += '~';
596 break;
597 case "geq":
598 string += 'since';
599 break;
600 case "leq":
601 string += 'until';
602 break;
603 default:
604 string += (this.type() == 'date') ? 'in' : '=';
605 break;
606 };
607
608 string += ' ';
609
610 // Add value
611 switch (this.type()) {
612 case "date":
613 return string + this.value();
614 break;
615 case "regex":
616 return string + '/' + this.value() + '/';
617 break;
618 case "string":
619 return string + '"' + this.value().replace(KorAP._quote, '\\$1') + '"';
620 break;
621 };
622
Nils Diewaldd599d542015-01-08 20:41:34 +0000623 return "";
Nils Diewald3a2d8022014-12-16 02:45:41 +0000624 }
625 };
Nils Diewald8f4e2542014-12-19 04:42:09 +0000626
Nils Diewaldd599d542015-01-08 20:41:34 +0000627
Nils Diewald8f4e2542014-12-19 04:42:09 +0000628 /**
Nils Diewaldd599d542015-01-08 20:41:34 +0000629 * Document group criterion
Nils Diewald8f4e2542014-12-19 04:42:09 +0000630 */
631 KorAP.DocGroup = {
632 _ldType : "docGroup",
633
634 create : function (parent, json) {
635 var obj = Object.create(KorAP.JsonLD).upgradeTo(KorAP.DocGroup);
636 obj._operands = [];
637 obj.fromJson(json);
638 if (parent !== undefined)
639 obj._parent = parent;
640 return obj;
641 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000642
643 newAfter : function (obj) {
644 for (var i in this._operands) {
645 if (this._operands[i] === obj) {
646 var operand = KorAP.UnspecifiedDoc.create(this);
647 this._operands.splice(i + 1, 0, operand);
648 return this.update();
649 };
650 };
651 },
652
Nils Diewald966abf12014-12-20 02:27:45 +0000653 append : function (operand) {
654
655 // Append unspecified object
656 if (operand === undefined) {
657
658 // Be aware of cyclic structures!
659 operand = KorAP.UnspecifiedDoc.create(this);
660 this._operands.push(operand);
Nils Diewald966abf12014-12-20 02:27:45 +0000661 return operand;
662 };
663
Nils Diewald8f4e2542014-12-19 04:42:09 +0000664 switch (operand["@type"]) {
665 case undefined:
666 if (operand["ldType"] !== undefined) {
667 if (operand.ldType() !== 'doc' &&
Nils Diewald966abf12014-12-20 02:27:45 +0000668 operand.ldType() !== 'docGroup') {
Nils Diewald8f4e2542014-12-19 04:42:09 +0000669 KorAP.log(812, "Operand not supported in document group");
670 return;
671 };
Nils Diewald966abf12014-12-20 02:27:45 +0000672 // Be aware of cyclic structures!
673 operand.parent(this);
Nils Diewald8f4e2542014-12-19 04:42:09 +0000674 this._operands.push(operand);
675 return operand;
676 };
677
678 KorAP.log(701, "JSON-LD group has no @type attribute");
679 return;
680
681 case "korap:doc":
Nils Diewald966abf12014-12-20 02:27:45 +0000682 // Be aware of cyclic structures!
683 var doc = KorAP.Doc.create(this, operand);
Nils Diewald8f4e2542014-12-19 04:42:09 +0000684 if (doc === undefined)
685 return;
686 this._operands.push(doc);
687 return doc;
688
689 case "korap:docGroup":
Nils Diewald966abf12014-12-20 02:27:45 +0000690 // Be aware of cyclic structures!
691 var docGroup = KorAP.DocGroup.create(this, operand);
Nils Diewald8f4e2542014-12-19 04:42:09 +0000692 if (docGroup === undefined)
693 return;
694 this._operands.push(docGroup);
695 return docGroup;
696
697 default:
698 KorAP.log(812, "Operand not supported in document group");
699 return;
700 };
701 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000702
Nils Diewald966abf12014-12-20 02:27:45 +0000703 update : function () {
Nils Diewaldf219eb82015-01-07 20:15:42 +0000704 // There is only one operand in group
705 if (this._operands.length === 1) {
706 var parent = this.parent();
Nils Diewald8e7182e2015-01-08 15:02:07 +0000707 var op = this.getOperand(0);
708
Nils Diewald8f6b6102015-01-08 18:25:33 +0000709 // This will prevent destruction of
710 // the operand
711 this._operands = [];
Nils Diewaldf219eb82015-01-07 20:15:42 +0000712
713 // Parent is a group
714 if (parent.ldType() !== null) {
Nils Diewald8e7182e2015-01-08 15:02:07 +0000715 return parent.replaceOperand(this, op).update();
Nils Diewaldf219eb82015-01-07 20:15:42 +0000716 }
717
Nils Diewald8f6b6102015-01-08 18:25:33 +0000718 // Parent is vc
Nils Diewaldf219eb82015-01-07 20:15:42 +0000719 else {
Nils Diewaldf219eb82015-01-07 20:15:42 +0000720 this.destroy();
Nils Diewald8f6b6102015-01-08 18:25:33 +0000721 // Cyclic madness
722 parent.root(op);
723 op.parent(parent);
Nils Diewaldf219eb82015-01-07 20:15:42 +0000724 return parent.root();
Nils Diewald5c817a42015-01-06 01:08:56 +0000725 };
726 };
727
Nils Diewald966abf12014-12-20 02:27:45 +0000728 if (this._element === undefined)
Nils Diewald5c817a42015-01-06 01:08:56 +0000729 return this;
Nils Diewald966abf12014-12-20 02:27:45 +0000730
Nils Diewald5c817a42015-01-06 01:08:56 +0000731 var group = this._element;
732 group.setAttribute('data-operation', this.operation());
Nils Diewald966abf12014-12-20 02:27:45 +0000733
Nils Diewald5c817a42015-01-06 01:08:56 +0000734 _removeChildren(group);
Nils Diewald966abf12014-12-20 02:27:45 +0000735
736 // Append operands
Nils Diewald5c817a42015-01-06 01:08:56 +0000737 for (var i in this._operands) {
738 group.appendChild(
Nils Diewald966abf12014-12-20 02:27:45 +0000739 this.getOperand(i).element()
740 );
741 };
742
743 // Set operators
744 var op = this.operators(
745 this.operation() == 'and' ? false : true,
746 this.operation() == 'or' ? false : true,
747 true
748 );
749
Nils Diewald5c817a42015-01-06 01:08:56 +0000750 group.appendChild(
Nils Diewald966abf12014-12-20 02:27:45 +0000751 op.element()
752 );
753
Nils Diewald5c817a42015-01-06 01:08:56 +0000754 return this;
Nils Diewald966abf12014-12-20 02:27:45 +0000755 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000756
Nils Diewald8f4e2542014-12-19 04:42:09 +0000757 element : function () {
758 if (this._element !== undefined)
759 return this._element;
760
761 this._element = document.createElement('div');
762 this._element.setAttribute('class', 'docGroup');
Nils Diewald8f4e2542014-12-19 04:42:09 +0000763
Nils Diewaldf219eb82015-01-07 20:15:42 +0000764 // Update the object - including optimization
Nils Diewald966abf12014-12-20 02:27:45 +0000765 this.update();
Nils Diewald8f4e2542014-12-19 04:42:09 +0000766
767 return this._element;
768 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000769
Nils Diewald8f4e2542014-12-19 04:42:09 +0000770 operation : function (op) {
771 if (arguments.length === 1) {
772 if (KorAP._validGroupOpRE.test(op)) {
773 this._op = op;
774 }
775 else {
776 KorAP.log(810, "Unknown operation type");
777 return;
778 };
779 };
780 return this._op || 'and';
781 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000782
Nils Diewald8f4e2542014-12-19 04:42:09 +0000783 operands : function () {
784 return this._operands;
785 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000786
Nils Diewald8f4e2542014-12-19 04:42:09 +0000787 getOperand : function (index) {
788 return this._operands[index];
789 },
790
Nils Diewald5c817a42015-01-06 01:08:56 +0000791 // Replace operand
Nils Diewaldf219eb82015-01-07 20:15:42 +0000792 replaceOperand : function (oldOp, newOp) {
Nils Diewald5c817a42015-01-06 01:08:56 +0000793 for (var i in this._operands) {
Nils Diewaldf219eb82015-01-07 20:15:42 +0000794 if (this._operands[i] === oldOp) {
795
796 // Just insert a doc
797 if (newOp.ldType() === "doc") {
Nils Diewaldf219eb82015-01-07 20:15:42 +0000798 this._operands[i] = newOp;
Nils Diewald8f6b6102015-01-08 18:25:33 +0000799 newOp.parent(this);
Nils Diewaldf219eb82015-01-07 20:15:42 +0000800 }
801 // Insert a group of a different operation
802 // (i.e. "and" in "or"/"or" in "and")
Nils Diewald8e7182e2015-01-08 15:02:07 +0000803 else if (newOp.operation() != this.operation()) {
Nils Diewaldf219eb82015-01-07 20:15:42 +0000804 this._operands[i] = newOp;
Nils Diewald8f6b6102015-01-08 18:25:33 +0000805 newOp.parent(this);
Nils Diewaldf219eb82015-01-07 20:15:42 +0000806 }
807
808 // Flatten the group
809 else {
Nils Diewald8e7182e2015-01-08 15:02:07 +0000810 // Remove old group
811 this._operands.splice(i, 1);
812
813 // Inject new operands
Nils Diewald8f6b6102015-01-08 18:25:33 +0000814 for (var op in newOp.operands().reverse()) {
815 this._operands.splice(i, 0, newOp.getOperand(op));
816 newOp.getOperand(0).parent(this);
817 };
818 // Prevent destruction of operands
819 newOp._operands = [];
820 newOp.destroy();
Nils Diewaldf219eb82015-01-07 20:15:42 +0000821 };
822 oldOp.destroy();
823 return this;
Nils Diewald5c817a42015-01-06 01:08:56 +0000824 }
825 };
826 return false;
827 },
828
Nils Diewald0297ba12015-01-05 21:56:12 +0000829 // Delete operand from group
830 delOperand : function (obj) {
831 for (var i in this._operands) {
832 if (this._operands[i] === obj) {
Nils Diewald8e7182e2015-01-08 15:02:07 +0000833
Nils Diewald8f6b6102015-01-08 18:25:33 +0000834 // Delete identified operand
Nils Diewald0297ba12015-01-05 21:56:12 +0000835 this._operands.splice(i,1);
836
Nils Diewald5c817a42015-01-06 01:08:56 +0000837 // Destroy object for cyclic references
838 obj.destroy();
839
Nils Diewaldf219eb82015-01-07 20:15:42 +0000840 return this;
Nils Diewald0297ba12015-01-05 21:56:12 +0000841 };
842 };
Nils Diewald5c817a42015-01-06 01:08:56 +0000843
844 // Operand not found
845 return undefined;
Nils Diewald0297ba12015-01-05 21:56:12 +0000846 },
847
Nils Diewald8f4e2542014-12-19 04:42:09 +0000848 // Deserialize from json
849 fromJson : function (json) {
850 if (json === undefined)
851 return this;
852
853 if (json["@type"] !== "korap:docGroup") {
854 KorAP.log(701, "JSON-LD group has no @type attribute");
855 return;
856 };
857
858 if (json["operation"] === undefined ||
859 typeof json["operation"] !== 'string') {
860 KorAP.log(811, "Document group expects operation");
861 return;
862 };
863
864 var operation = json["operation"];
865
866 this.operation(operation.replace(/^operation:/,''));
867
868 if (json["operands"] === undefined ||
869 !(json["operands"] instanceof Array)) {
870 KorAP.log(704, "Operation needs operand list")
871 return;
872 };
873
874 // Add all documents
875 for (var i in json["operands"]) {
876 var operand = json["operands"][i];
Nils Diewald966abf12014-12-20 02:27:45 +0000877 this.append(operand);
Nils Diewald8f4e2542014-12-19 04:42:09 +0000878 };
879
880 return this;
881 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000882
Nils Diewald8f4e2542014-12-19 04:42:09 +0000883 toJson : function () {
884 var opArray = new Array();
885 for (var i in this._operands) {
886 opArray.push(this._operands[i].toJson());
887 };
888 return {
889 "@type" : "korap:" + this.ldType(),
890 "operation" : "operation:" + this.operation(),
891 "operands" : opArray
892 };
Nils Diewaldf219eb82015-01-07 20:15:42 +0000893 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000894
895 toQuery : function () {
Nils Diewaldf219eb82015-01-07 20:15:42 +0000896 return this._operands.
897 map(function (op) {
Nils Diewaldd599d542015-01-08 20:41:34 +0000898 return (op.ldType() === 'docGroup') ?
899 '(' + op.toQuery() + ')' :
900 op.toQuery();
901 }).join(this.operation() === 'or' ? ' | ' : ' & ')
Nils Diewald8f4e2542014-12-19 04:42:09 +0000902 }
903 };
904
905
Nils Diewaldd599d542015-01-08 20:41:34 +0000906 /**
907 * Abstract JsonLD criterion object
908 */
Nils Diewald8f4e2542014-12-19 04:42:09 +0000909 KorAP.JsonLD = {
Nils Diewald8f6b6102015-01-08 18:25:33 +0000910 _changed : false,
911
Nils Diewald8f4e2542014-12-19 04:42:09 +0000912 create : function () {
913 return Object.create(KorAP.JsonLD);
914 },
915
916 /**
917 * Upgrade this object to another object
918 * while private data stays intact
919 */
920 upgradeTo : function (props) {
921 for (var prop in props) {
922 this[prop] = props[prop];
923 };
924 return this;
925 },
Nils Diewald8f6b6102015-01-08 18:25:33 +0000926
Nils Diewald8f4e2542014-12-19 04:42:09 +0000927 ldType : function (type) {
928 if (arguments.length === 1)
929 this._ldType = type;
930 return this._ldType;
931 },
Nils Diewald8f6b6102015-01-08 18:25:33 +0000932
Nils Diewald8f4e2542014-12-19 04:42:09 +0000933 parent : function (obj) {
Nils Diewald8f6b6102015-01-08 18:25:33 +0000934 if (arguments.length === 1) {
Nils Diewald8f4e2542014-12-19 04:42:09 +0000935 this._parent = obj;
Nils Diewald8f6b6102015-01-08 18:25:33 +0000936 this._changed = true;
937 };
Nils Diewald8f4e2542014-12-19 04:42:09 +0000938 return this._parent;
Nils Diewald966abf12014-12-20 02:27:45 +0000939 },
Nils Diewald0297ba12015-01-05 21:56:12 +0000940
Nils Diewald5c817a42015-01-06 01:08:56 +0000941 // Destroy object - especially for
942 // acyclic structures!
943 // I'm a paranoid chicken!
944 destroy : function () {
945 if (this._ops != undefined) {
946 this._ops._parent = undefined;
947 if (this._ops._element !== undefined)
948 this._ops._element.refTo = undefined;
949 this._ops = undefined;
950 };
951 if (this._element !== undefined)
952 this._element = undefined;
953
954 // In case of a group, destroy all operands
955 if (this._operands !== undefined) {
956 for (var i in this._operands)
957 this.getOperand(i).destroy();
Nils Diewaldf219eb82015-01-07 20:15:42 +0000958 this._operands = [];
Nils Diewald5c817a42015-01-06 01:08:56 +0000959 };
960 },
961
Nils Diewald0297ba12015-01-05 21:56:12 +0000962 // Be aware! This may be cyclic
Nils Diewald966abf12014-12-20 02:27:45 +0000963 operators : function (and, or, del) {
964 if (arguments === 0)
965 return this._ops;
966 this._ops = KorAP.Operators.create(
967 and, or, del
968 );
Nils Diewald0297ba12015-01-05 21:56:12 +0000969 this._ops.parent(this);
Nils Diewald966abf12014-12-20 02:27:45 +0000970 return this._ops;
971 },
Nils Diewald8f6b6102015-01-08 18:25:33 +0000972
Nils Diewald966abf12014-12-20 02:27:45 +0000973 toJson : function () {
974 return {
975 // Unspecified object
976 "@type" : "korap:" + this.ldType()
977 };
Nils Diewald8f6b6102015-01-08 18:25:33 +0000978 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000979
980 toQuery : function () {
Nils Diewald8f6b6102015-01-08 18:25:33 +0000981 return loc.EMPTY;
Nils Diewald8f4e2542014-12-19 04:42:09 +0000982 }
983 };
984
Nils Diewald3a2d8022014-12-16 02:45:41 +0000985}(this.KorAP));