blob: d9cde4ea8a20f06a4dcd7e80cd6301b3b08952b3 [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 Diewalde15b7a22015-01-09 21:50:21 +000037 // Localization values
Nils Diewaldf219eb82015-01-07 20:15:42 +000038 var loc = (KorAP.Locale = KorAP.Locale || {} );
39 loc.AND = loc.AND || 'and';
40 loc.OR = loc.OR || 'or';
41 loc.DEL = loc.DEL || '×';
42 loc.EMPTY = loc.EMPTY || '⋯'
Nils Diewaldd0770492014-12-19 03:55:00 +000043
Nils Diewaldd599d542015-01-08 20:41:34 +000044
Nils Diewalde15b7a22015-01-09 21:50:21 +000045 // Utility for analysing boolean values
Nils Diewald966abf12014-12-20 02:27:45 +000046 function _bool (bool) {
Nils Diewalde15b7a22015-01-09 21:50:21 +000047 return (bool === undefined || bool === null || bool === false) ? false : true;
Nils Diewald966abf12014-12-20 02:27:45 +000048 };
49
Nils Diewaldd599d542015-01-08 20:41:34 +000050
Nils Diewalde15b7a22015-01-09 21:50:21 +000051 // Utility for removing all children of a node
Nils Diewald966abf12014-12-20 02:27:45 +000052 function _removeChildren (node) {
53 // Remove everything underneath
Nils Diewald8f6b6102015-01-08 18:25:33 +000054 while (node.firstChild)
Nils Diewald966abf12014-12-20 02:27:45 +000055 node.removeChild(node.firstChild);
Nils Diewald966abf12014-12-20 02:27:45 +000056 };
57
Nils Diewald4019bd22015-01-08 19:57:50 +000058
Nils Diewald9fcc1712015-01-09 14:24:32 +000059 // Add doc
60 KorAP._add = function (obj, type) {
61 var ref = obj.parentNode.refTo;
Nils Diewaldd5070b02015-01-11 01:44:47 +000062 var parent = ref.parent();
Nils Diewald9fcc1712015-01-09 14:24:32 +000063 if (ref.ldType() === 'docGroup') {
Nils Diewaldd5070b02015-01-11 01:44:47 +000064
65 // Check that the action differs from the type
66 if (ref.operation() === type)
67 return;
68
69 if (parent.ldType() !== null) {
70 return parent.newAfter(ref);
Nils Diewald9fcc1712015-01-09 14:24:32 +000071 }
72 else {
Nils Diewaldd5070b02015-01-11 01:44:47 +000073 // The group is on root - wrap
74 return ref.wrapOnRoot();
75 };
76 }
77 else if (ref.ldType() === 'doc') {
78// Todo: Check if parent is a group
79 if (parent.operation() === type) {
80 return parent.newAfter(ref);
81 }
82 else {
83 return ref.wrap(type);
Nils Diewald9fcc1712015-01-09 14:24:32 +000084 };
Nils Diewaldd599d542015-01-08 20:41:34 +000085 };
Nils Diewald4019bd22015-01-08 19:57:50 +000086 };
87
Nils Diewaldd599d542015-01-08 20:41:34 +000088
Nils Diewalde15b7a22015-01-09 21:50:21 +000089 // Add doc with 'and' relation
90 KorAP._and = function () {
91 return KorAP._add(this, 'and');
92 };
93
94
95 // Add doc with 'or' relation
96 KorAP._or = function () {
97 return KorAP._add(this, 'or');
98 };
99
Nils Diewald4019bd22015-01-08 19:57:50 +0000100 // Remove doc or docGroup
Nils Diewalde15b7a22015-01-09 21:50:21 +0000101 KorAP._delete = function () {
Nils Diewald9fcc1712015-01-09 14:24:32 +0000102 var ref = this.parentNode.refTo;
103 if (ref.parent().ldType() !== null)
104 ref.parent().delOperand(ref).update();
Nils Diewald4019bd22015-01-08 19:57:50 +0000105 else
Nils Diewald9fcc1712015-01-09 14:24:32 +0000106 ref.parent().clean();
Nils Diewald4019bd22015-01-08 19:57:50 +0000107 };
108
Nils Diewaldd599d542015-01-08 20:41:34 +0000109
110 /**
111 * Virtual Collection
112 */
Nils Diewald3a2d8022014-12-16 02:45:41 +0000113 KorAP.VirtualCollection = {
Nils Diewaldf219eb82015-01-07 20:15:42 +0000114 ldType : function () {
115 return null;
116 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000117
Nils Diewald3a2d8022014-12-16 02:45:41 +0000118 create : function () {
119 return Object.create(KorAP.VirtualCollection);
120 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000121
Nils Diewald4019bd22015-01-08 19:57:50 +0000122 clean : function () {
123 if (this._root.ldType() !== "non") {
124 this._root.destroy();
125 this.root(KorAP.UnspecifiedDoc.create(this));
126 };
127 return this;
128 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000129
Nils Diewaldd0770492014-12-19 03:55:00 +0000130 render : function (json) {
131 var obj = Object.create(KorAP.VirtualCollection);
132
133 if (json !== undefined) {
134 // Root object
135 if (json['@type'] == 'korap:doc') {
Nils Diewaldf219eb82015-01-07 20:15:42 +0000136 obj._root = KorAP.Doc.create(obj, json);
Nils Diewaldd0770492014-12-19 03:55:00 +0000137 }
138 else if (json['@type'] == 'korap:docGroup') {
Nils Diewaldf219eb82015-01-07 20:15:42 +0000139 obj._root = KorAP.DocGroup.create(obj, json);
Nils Diewaldd0770492014-12-19 03:55:00 +0000140 }
141 else {
142 KorAP.log(813, "Collection type is not supported");
143 return;
144 };
145 }
146
147 else {
148 // Add unspecified object
Nils Diewaldf219eb82015-01-07 20:15:42 +0000149 obj._root = KorAP.UnspecifiedDoc.create(obj);
Nils Diewaldd0770492014-12-19 03:55:00 +0000150 };
151
Nils Diewald8e7182e2015-01-08 15:02:07 +0000152 // Init element and update
153 obj.update();
Nils Diewaldd0770492014-12-19 03:55:00 +0000154
155 return obj;
Nils Diewald3a2d8022014-12-16 02:45:41 +0000156 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000157
Nils Diewaldf219eb82015-01-07 20:15:42 +0000158 root : function (obj) {
Nils Diewald8e7182e2015-01-08 15:02:07 +0000159 if (arguments.length === 1) {
Nils Diewald8f6b6102015-01-08 18:25:33 +0000160 var e = this.element();
161 if (e.firstChild !== null) {
Nils Diewaldd5070b02015-01-11 01:44:47 +0000162 console.log(e.firstChild);
163 if (e.firstChild !== obj.element()) {
164console.log(e.firstChild);
Nils Diewald8f6b6102015-01-08 18:25:33 +0000165 e.replaceChild(obj.element(), e.firstChild);
Nils Diewaldd5070b02015-01-11 01:44:47 +0000166 };
Nils Diewald8f6b6102015-01-08 18:25:33 +0000167 }
168
169 // Append root element
170 else {
171 e.appendChild(obj.element());
172 };
173
174 // Update parent child relations
Nils Diewaldf219eb82015-01-07 20:15:42 +0000175 this._root = obj;
Nils Diewald8f6b6102015-01-08 18:25:33 +0000176 obj.parent(this);
177
Nils Diewald8e7182e2015-01-08 15:02:07 +0000178 this.update();
179 };
Nils Diewaldd0770492014-12-19 03:55:00 +0000180 return this._root;
Nils Diewald3a2d8022014-12-16 02:45:41 +0000181 },
Nils Diewald8f6b6102015-01-08 18:25:33 +0000182
Nils Diewaldd0770492014-12-19 03:55:00 +0000183 element : function () {
184 if (this._element !== undefined)
185 return this._element;
186
187 this._element = document.createElement('div');
188 this._element.setAttribute('class', 'vc');
Nils Diewald8e7182e2015-01-08 15:02:07 +0000189
Nils Diewald8f6b6102015-01-08 18:25:33 +0000190 // Initialize root
191 this._element.appendChild(this._root.element());
192
Nils Diewaldd0770492014-12-19 03:55:00 +0000193 return this._element;
Nils Diewaldf219eb82015-01-07 20:15:42 +0000194 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000195
196 update : function () {
197 this._root.update();
198 return this;
199 },
200
Nils Diewaldf219eb82015-01-07 20:15:42 +0000201 toJson : function () {
202 return this._root.toJson();
203 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000204
205 toQuery : function () {
206 return this._root.toQuery();
Nils Diewald3a2d8022014-12-16 02:45:41 +0000207 }
208 };
209
Nils Diewaldd599d542015-01-08 20:41:34 +0000210
Nils Diewald8f4e2542014-12-19 04:42:09 +0000211 /**
212 * Operators for criteria
213 */
Nils Diewaldd0770492014-12-19 03:55:00 +0000214 KorAP.Operators = {
215 create : function (and, or, del) {
216 var op = Object.create(KorAP.Operators);
217 op.and(and);
218 op.or(or);
219 op.del(del);
220 return op;
221 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000222
Nils Diewaldd0770492014-12-19 03:55:00 +0000223 update : function () {
Nils Diewaldd0770492014-12-19 03:55:00 +0000224 // Init the element
225 if (this._element === undefined)
226 return this.element();
227
228 var op = this._element;
229
Nils Diewald0297ba12015-01-05 21:56:12 +0000230 op.refTo = this.parent();
231
Nils Diewaldd0770492014-12-19 03:55:00 +0000232 // Remove everything underneath
Nils Diewald966abf12014-12-20 02:27:45 +0000233 _removeChildren(op);
Nils Diewaldd0770492014-12-19 03:55:00 +0000234
235 // Add and button
236 if (this._and === true) {
237 var andE = document.createElement('span');
238 andE.setAttribute('class', 'and');
Nils Diewalde15b7a22015-01-09 21:50:21 +0000239 andE.addEventListener('click', KorAP._and, false);
Nils Diewald8f6b6102015-01-08 18:25:33 +0000240 andE.appendChild(
241 document.createTextNode(KorAP.Locale.AND)
242 );
Nils Diewaldd0770492014-12-19 03:55:00 +0000243 op.appendChild(andE);
244 };
245
246 // Add or button
247 if (this._or === true) {
248 var orE = document.createElement('span');
249 orE.setAttribute('class', 'or');
Nils Diewalde15b7a22015-01-09 21:50:21 +0000250 orE.addEventListener('click', KorAP._or, false);
Nils Diewaldd0770492014-12-19 03:55:00 +0000251 orE.appendChild(document.createTextNode(KorAP.Locale.OR));
252 op.appendChild(orE);
253 };
254
255 // Add delete button
256 if (this._del === true) {
257 var delE = document.createElement('span');
258 delE.setAttribute('class', 'delete');
259 delE.appendChild(document.createTextNode(KorAP.Locale.DEL));
Nils Diewald0297ba12015-01-05 21:56:12 +0000260 delE.addEventListener('click', KorAP._delete, false);
Nils Diewaldd0770492014-12-19 03:55:00 +0000261 op.appendChild(delE);
262 };
Nils Diewald966abf12014-12-20 02:27:45 +0000263
264 return op;
Nils Diewaldd0770492014-12-19 03:55:00 +0000265 },
Nils Diewald0297ba12015-01-05 21:56:12 +0000266
267 // Be aware! This may be cyclic
268 parent : function (obj) {
269 if (arguments.length === 1)
270 this._parent = obj;
271 return this._parent;
272 },
Nils Diewald5c817a42015-01-06 01:08:56 +0000273
Nils Diewaldd0770492014-12-19 03:55:00 +0000274 element : function () {
275
276 // Return existing element
277 if (this._element !== undefined)
278 return this._element;
279
280 this._element = document.createElement('div');
281 this._element.setAttribute('class', 'operators');
282
283 // Init elements
284 this.update();
285 return this._element;
286 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000287
Nils Diewaldd0770492014-12-19 03:55:00 +0000288 and : function (bool) {
289 if (arguments.length === 1)
Nils Diewald966abf12014-12-20 02:27:45 +0000290 this._and = _bool(bool);
Nils Diewaldd0770492014-12-19 03:55:00 +0000291 return this._and;
292 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000293
Nils Diewaldd0770492014-12-19 03:55:00 +0000294 or : function (bool) {
295 if (arguments.length === 1)
Nils Diewald966abf12014-12-20 02:27:45 +0000296 this._or = _bool(bool);
Nils Diewaldd0770492014-12-19 03:55:00 +0000297 return this._or;
298 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000299
Nils Diewaldd0770492014-12-19 03:55:00 +0000300 del : function (bool) {
301 if (arguments.length === 1)
Nils Diewald966abf12014-12-20 02:27:45 +0000302 this._del = _bool(bool);
Nils Diewaldd0770492014-12-19 03:55:00 +0000303 return this._del;
304 }
305 };
306
307
308 /**
309 * Unspecified criterion
310 */
Nils Diewald8f4e2542014-12-19 04:42:09 +0000311 KorAP.UnspecifiedDoc = {
Nils Diewald4019bd22015-01-08 19:57:50 +0000312 _ldType : "non",
Nils Diewaldd0770492014-12-19 03:55:00 +0000313 create : function (parent) {
Nils Diewald8f6b6102015-01-08 18:25:33 +0000314 var obj = Object.create(KorAP.JsonLD).
315 upgradeTo(KorAP.UnspecifiedDoc);
316
Nils Diewaldd0770492014-12-19 03:55:00 +0000317 if (parent !== undefined)
318 obj._parent = parent;
Nils Diewald8f6b6102015-01-08 18:25:33 +0000319
Nils Diewaldd0770492014-12-19 03:55:00 +0000320 return obj;
321 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000322
Nils Diewald966abf12014-12-20 02:27:45 +0000323 update : function () {
Nils Diewald4019bd22015-01-08 19:57:50 +0000324
Nils Diewald966abf12014-12-20 02:27:45 +0000325 if (this._element === undefined)
326 return this.element();
327
Nils Diewald8f6b6102015-01-08 18:25:33 +0000328 // Remove element content
Nils Diewald966abf12014-12-20 02:27:45 +0000329 _removeChildren(this._element);
330
331 var ellipsis = document.createElement('span');
Nils Diewaldf219eb82015-01-07 20:15:42 +0000332 ellipsis.appendChild(document.createTextNode(loc.EMPTY));
Nils Diewald966abf12014-12-20 02:27:45 +0000333 this._element.appendChild(ellipsis);
334
335 // Set operators
Nils Diewalde15b7a22015-01-09 21:50:21 +0000336 if (this._parent !== undefined && this.parent().ldType() !== null) {
337 var op = this.operators(
338 false,
339 false,
340 true
341 );
Nils Diewald966abf12014-12-20 02:27:45 +0000342
Nils Diewalde15b7a22015-01-09 21:50:21 +0000343 this._element.appendChild(
344 op.element()
345 );
346 };
Nils Diewald966abf12014-12-20 02:27:45 +0000347
Nils Diewald966abf12014-12-20 02:27:45 +0000348 return this.element();
349 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000350
Nils Diewaldd0770492014-12-19 03:55:00 +0000351 element : function () {
352 if (this._element !== undefined)
353 return this._element;
354 this._element = document.createElement('div');
Nils Diewaldd599d542015-01-08 20:41:34 +0000355 this._element.setAttribute('class', 'doc unspecified');
Nils Diewald966abf12014-12-20 02:27:45 +0000356 this.update();
Nils Diewaldd0770492014-12-19 03:55:00 +0000357 return this._element;
358 }
359 };
360
361
Nils Diewald8f4e2542014-12-19 04:42:09 +0000362 /**
Nils Diewaldd599d542015-01-08 20:41:34 +0000363 * Document criterion
Nils Diewald8f4e2542014-12-19 04:42:09 +0000364 */
365 KorAP.Doc = {
366 _ldType : "doc",
367 _obj : function () { return KorAP.Doc; },
Nils Diewaldd0770492014-12-19 03:55:00 +0000368
369 create : function (parent, json) {
Nils Diewald8f6b6102015-01-08 18:25:33 +0000370 var obj = Object(KorAP.JsonLD).
371 create().
372 upgradeTo(KorAP.Doc).
373 fromJson(json);
374
Nils Diewaldd0770492014-12-19 03:55:00 +0000375 if (parent !== undefined)
376 obj._parent = parent;
Nils Diewald8f6b6102015-01-08 18:25:33 +0000377
378 obj._changed = true;
Nils Diewaldd0770492014-12-19 03:55:00 +0000379 return obj;
380 },
Nils Diewald5c817a42015-01-06 01:08:56 +0000381
Nils Diewald966abf12014-12-20 02:27:45 +0000382 update : function () {
383 if (this._element === undefined)
384 return this.element();
Nils Diewaldd0770492014-12-19 03:55:00 +0000385
Nils Diewald8f6b6102015-01-08 18:25:33 +0000386 // Get element
Nils Diewald966abf12014-12-20 02:27:45 +0000387 var e = this._element;
388
Nils Diewald8f6b6102015-01-08 18:25:33 +0000389 // Check if there is a change
390 if (this._changed) {
Nils Diewald966abf12014-12-20 02:27:45 +0000391
Nils Diewald8f6b6102015-01-08 18:25:33 +0000392 // Added key
393 var key = document.createElement('span');
394 key.setAttribute('class', 'key');
395 if (this.key())
396 key.appendChild(document.createTextNode(this.key()));
Nils Diewald966abf12014-12-20 02:27:45 +0000397
Nils Diewald8f6b6102015-01-08 18:25:33 +0000398 // Added match operator
399 var matchop = document.createElement('span');
400 matchop.setAttribute('data-type', this.type());
401 matchop.setAttribute('class', 'match');
402 matchop.appendChild(
403 document.createTextNode(this.matchop())
404 );
405
406 // Added match operator
407 var value = document.createElement('span');
408 value.setAttribute('data-type', this.type());
409 value.setAttribute('class', 'value');
410 if (this.value())
411 value.appendChild(
412 document.createTextNode(this.value())
413 );
414
415 // Remove all element children
416 _removeChildren(e);
417
418 // Add spans
419 e.appendChild(key);
420 e.appendChild(matchop);
421 e.appendChild(value);
422
423 this._changed = false;
424 };
425
426 if (this._parent !== undefined) {
427 // Set operators
428 var op = this.operators(
429 true,
430 true,
Nils Diewald4019bd22015-01-08 19:57:50 +0000431 true
Nils Diewald8f6b6102015-01-08 18:25:33 +0000432 );
433
434 // Append new operators
435 e.appendChild(op.element());
436 };
Nils Diewald966abf12014-12-20 02:27:45 +0000437
Nils Diewaldd0770492014-12-19 03:55:00 +0000438 return e;
439 },
440
Nils Diewald966abf12014-12-20 02:27:45 +0000441 element : function () {
442 if (this._element !== undefined)
443 return this._element;
444
445 this._element = document.createElement('div');
446 this._element.setAttribute('class', 'doc');
447
448 this.update();
449 return this._element;
450 },
451
Nils Diewaldd0770492014-12-19 03:55:00 +0000452 // Wrap a new operation around the doc element
453 wrap : function (op) {
Nils Diewald9fcc1712015-01-09 14:24:32 +0000454 var parent = this.parent();
455 var group = KorAP.DocGroup.create(parent);
456 group.operation(op);
Nils Diewald966abf12014-12-20 02:27:45 +0000457 group.append(this);
Nils Diewald9fcc1712015-01-09 14:24:32 +0000458 group.append();
459 return parent.replaceOperand(this, group).update();
Nils Diewaldd0770492014-12-19 03:55:00 +0000460 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000461
Nils Diewald3a2d8022014-12-16 02:45:41 +0000462 // Deserialize from json
463 fromJson : function (json) {
Nils Diewald3a2d8022014-12-16 02:45:41 +0000464 if (json === undefined)
Nils Diewaldd0770492014-12-19 03:55:00 +0000465 return this;
Nils Diewald3a2d8022014-12-16 02:45:41 +0000466
Nils Diewald3a2d8022014-12-16 02:45:41 +0000467 if (json["@type"] !== "korap:doc") {
468 KorAP.log(701, "JSON-LD group has no @type attribute");
469 return;
470 };
471
Nils Diewald3a2d8022014-12-16 02:45:41 +0000472 if (json["value"] === undefined ||
473 typeof json["value"] != 'string') {
474 KorAP.log(805, "Value is invalid");
475 return;
476 };
477
478 // There is a defined key
479 if (json["key"] !== undefined &&
480 typeof json["key"] === 'string') {
481
482 // Set key
Nils Diewaldd0770492014-12-19 03:55:00 +0000483 this.key(json["key"]);
Nils Diewald3a2d8022014-12-16 02:45:41 +0000484
485 // Set match operation
486 if (json["match"] !== undefined) {
Nils Diewaldd0770492014-12-19 03:55:00 +0000487 if (typeof json["match"] === 'string') {
488 this.matchop(json["match"]);
489 }
Nils Diewald3a2d8022014-12-16 02:45:41 +0000490 else {
491 KorAP.log(802, "Match type is not supported by value type");
492 return;
493 };
494 };
495
496 // Key is a string
497 if (json["type"] === undefined ||
498 json["type"] == "type:string") {
Nils Diewaldd0770492014-12-19 03:55:00 +0000499 this.type("string");
Nils Diewald3a2d8022014-12-16 02:45:41 +0000500
501 // Check match type
Nils Diewaldd0770492014-12-19 03:55:00 +0000502 if (!KorAP._validStringMatchRE.test(this.matchop())) {
Nils Diewald3a2d8022014-12-16 02:45:41 +0000503 KorAP.log(802, "Match type is not supported by value type");
504 return;
505 };
506
507 // Set string value
Nils Diewaldd0770492014-12-19 03:55:00 +0000508 this.value(json["value"]);
Nils Diewald3a2d8022014-12-16 02:45:41 +0000509 }
510
511 // Key is a date
512 else if (json["type"] === "type:date") {
Nils Diewaldd0770492014-12-19 03:55:00 +0000513 this.type("date");
Nils Diewald3a2d8022014-12-16 02:45:41 +0000514
515 if (json["value"] !== undefined &&
516 KorAP._validDateRE.test(json["value"])) {
517
Nils Diewaldd0770492014-12-19 03:55:00 +0000518 if (!KorAP._validDateMatchRE.test(this.matchop())) {
Nils Diewald3a2d8022014-12-16 02:45:41 +0000519 KorAP.log(802, "Match type is not supported by value type");
520 return;
521 };
522
523 // Set value
Nils Diewaldd0770492014-12-19 03:55:00 +0000524 this.value(json["value"]);
Nils Diewald3a2d8022014-12-16 02:45:41 +0000525 }
526 else {
527 KorAP.log(806, "Value is not a valid date string");
528 return;
529 };
530 }
531
532 // Key is a regular expression
533 else if (json["type"] === "type:regex") {
Nils Diewaldd0770492014-12-19 03:55:00 +0000534 this.type("regex");
Nils Diewald3a2d8022014-12-16 02:45:41 +0000535
536 try {
537
538 // Try to create a regular expression
539 var check = new RegExp(json["value"]);
540
Nils Diewaldd0770492014-12-19 03:55:00 +0000541 if (!KorAP._validRegexMatchRE.test(this.matchop())) {
Nils Diewald3a2d8022014-12-16 02:45:41 +0000542 KorAP.log(802, "Match type is not supported by value type");
543 return;
544 };
545
Nils Diewaldd0770492014-12-19 03:55:00 +0000546 this.value(json["value"]);
Nils Diewald3a2d8022014-12-16 02:45:41 +0000547 }
Nils Diewaldd0770492014-12-19 03:55:00 +0000548
Nils Diewald3a2d8022014-12-16 02:45:41 +0000549 catch (e) {
550 KorAP.log(807, "Value is not a valid regular expression");
551 return;
552 };
Nils Diewaldd0770492014-12-19 03:55:00 +0000553 this.type("regex");
Nils Diewald3a2d8022014-12-16 02:45:41 +0000554 }
555
556 else {
557 KorAP.log(804, "Unknown value type");
558 return;
559 };
560 };
561
562 return this;
563 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000564
Nils Diewaldd0770492014-12-19 03:55:00 +0000565 key : function (value) {
Nils Diewald8f6b6102015-01-08 18:25:33 +0000566 if (arguments.length === 1) {
Nils Diewaldd0770492014-12-19 03:55:00 +0000567 this._key = value;
Nils Diewald8f6b6102015-01-08 18:25:33 +0000568 this._changed = true;
569 };
Nils Diewald3a2d8022014-12-16 02:45:41 +0000570 return this._key;
571 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000572
Nils Diewaldd0770492014-12-19 03:55:00 +0000573 matchop : function (match) {
Nils Diewald8f6b6102015-01-08 18:25:33 +0000574 if (arguments.length === 1) {
Nils Diewaldd0770492014-12-19 03:55:00 +0000575 this._matchop = match.replace(/^match:/, '');
Nils Diewald8f6b6102015-01-08 18:25:33 +0000576 this._changed = true;
577 };
Nils Diewald3a2d8022014-12-16 02:45:41 +0000578 return this._matchop || "eq";
579 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000580
Nils Diewaldd0770492014-12-19 03:55:00 +0000581 type : function (type) {
Nils Diewald8f6b6102015-01-08 18:25:33 +0000582 if (arguments.length === 1) {
Nils Diewaldd0770492014-12-19 03:55:00 +0000583 this._type = type;
Nils Diewald8f6b6102015-01-08 18:25:33 +0000584 this._changed = true;
585 };
Nils Diewald3a2d8022014-12-16 02:45:41 +0000586 return this._type || "string";
587 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000588
Nils Diewaldd0770492014-12-19 03:55:00 +0000589 value : function (value) {
Nils Diewald8f6b6102015-01-08 18:25:33 +0000590 if (arguments.length === 1) {
Nils Diewaldd0770492014-12-19 03:55:00 +0000591 this._value = value;
Nils Diewald8f6b6102015-01-08 18:25:33 +0000592 this._changed = true;
593 };
Nils Diewald3a2d8022014-12-16 02:45:41 +0000594 return this._value;
595 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000596
Nils Diewald3a2d8022014-12-16 02:45:41 +0000597 toJson : function () {
Nils Diewaldd0770492014-12-19 03:55:00 +0000598 if (!this.matchop() || !this.key())
Nils Diewald3a2d8022014-12-16 02:45:41 +0000599 return {};
600
601 return {
Nils Diewaldd0770492014-12-19 03:55:00 +0000602 "@type" : "korap:" + this.ldType(),
603 "key" : this.key(),
604 "match" : "match:" + this.matchop(),
605 "value" : this.value() || '',
606 "type" : "type:" + this.type()
Nils Diewald3a2d8022014-12-16 02:45:41 +0000607 };
Nils Diewaldf219eb82015-01-07 20:15:42 +0000608 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000609
610 toQuery : function () {
Nils Diewaldf219eb82015-01-07 20:15:42 +0000611 if (!this.matchop() || !this.key())
612 return "";
613
614 // Build doc string based on key
615 var string = this.key() + ' ';
616
617 // Add match operator
618 switch (this.matchop()) {
619 case "ne":
620 string += '!=';
621 break;
622 case "contains":
623 string += '~';
624 break;
625 case "geq":
626 string += 'since';
627 break;
628 case "leq":
629 string += 'until';
630 break;
631 default:
632 string += (this.type() == 'date') ? 'in' : '=';
633 break;
634 };
635
636 string += ' ';
637
638 // Add value
639 switch (this.type()) {
640 case "date":
641 return string + this.value();
642 break;
643 case "regex":
644 return string + '/' + this.value() + '/';
645 break;
646 case "string":
647 return string + '"' + this.value().replace(KorAP._quote, '\\$1') + '"';
648 break;
649 };
650
Nils Diewaldd599d542015-01-08 20:41:34 +0000651 return "";
Nils Diewald3a2d8022014-12-16 02:45:41 +0000652 }
653 };
Nils Diewald8f4e2542014-12-19 04:42:09 +0000654
Nils Diewaldd599d542015-01-08 20:41:34 +0000655
Nils Diewald8f4e2542014-12-19 04:42:09 +0000656 /**
Nils Diewaldd599d542015-01-08 20:41:34 +0000657 * Document group criterion
Nils Diewald8f4e2542014-12-19 04:42:09 +0000658 */
659 KorAP.DocGroup = {
660 _ldType : "docGroup",
661
662 create : function (parent, json) {
663 var obj = Object.create(KorAP.JsonLD).upgradeTo(KorAP.DocGroup);
664 obj._operands = [];
665 obj.fromJson(json);
666 if (parent !== undefined)
667 obj._parent = parent;
668 return obj;
669 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000670
671 newAfter : function (obj) {
672 for (var i in this._operands) {
673 if (this._operands[i] === obj) {
674 var operand = KorAP.UnspecifiedDoc.create(this);
675 this._operands.splice(i + 1, 0, operand);
676 return this.update();
677 };
678 };
679 },
680
Nils Diewald966abf12014-12-20 02:27:45 +0000681 append : function (operand) {
682
683 // Append unspecified object
684 if (operand === undefined) {
685
686 // Be aware of cyclic structures!
687 operand = KorAP.UnspecifiedDoc.create(this);
688 this._operands.push(operand);
Nils Diewald966abf12014-12-20 02:27:45 +0000689 return operand;
690 };
691
Nils Diewald8f4e2542014-12-19 04:42:09 +0000692 switch (operand["@type"]) {
693 case undefined:
694 if (operand["ldType"] !== undefined) {
695 if (operand.ldType() !== 'doc' &&
Nils Diewald966abf12014-12-20 02:27:45 +0000696 operand.ldType() !== 'docGroup') {
Nils Diewald8f4e2542014-12-19 04:42:09 +0000697 KorAP.log(812, "Operand not supported in document group");
698 return;
699 };
Nils Diewald966abf12014-12-20 02:27:45 +0000700 // Be aware of cyclic structures!
701 operand.parent(this);
Nils Diewald8f4e2542014-12-19 04:42:09 +0000702 this._operands.push(operand);
703 return operand;
704 };
705
706 KorAP.log(701, "JSON-LD group has no @type attribute");
707 return;
708
709 case "korap:doc":
Nils Diewald966abf12014-12-20 02:27:45 +0000710 // Be aware of cyclic structures!
711 var doc = KorAP.Doc.create(this, operand);
Nils Diewald8f4e2542014-12-19 04:42:09 +0000712 if (doc === undefined)
713 return;
714 this._operands.push(doc);
715 return doc;
716
717 case "korap:docGroup":
Nils Diewald966abf12014-12-20 02:27:45 +0000718 // Be aware of cyclic structures!
719 var docGroup = KorAP.DocGroup.create(this, operand);
Nils Diewald8f4e2542014-12-19 04:42:09 +0000720 if (docGroup === undefined)
721 return;
722 this._operands.push(docGroup);
723 return docGroup;
724
725 default:
726 KorAP.log(812, "Operand not supported in document group");
727 return;
728 };
729 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000730
Nils Diewaldd5070b02015-01-11 01:44:47 +0000731 // Wrap a new operation around the root group element
732 wrapOnRoot : function () {
733 var parent = this.parent();
734
735 var group = KorAP.DocGroup.create(parent);
736 group.operation(
737 this.operation() === 'and' ? 'or' : 'and'
738 );
739 group.append(this);
740 this.parent(group);
741 group.append();
742 group.element(); // Init (seems to be necessary)
743 parent.root(group);
744 return this.parent();
745 },
746
Nils Diewald966abf12014-12-20 02:27:45 +0000747 update : function () {
Nils Diewaldf219eb82015-01-07 20:15:42 +0000748 // There is only one operand in group
749 if (this._operands.length === 1) {
750 var parent = this.parent();
Nils Diewald8e7182e2015-01-08 15:02:07 +0000751 var op = this.getOperand(0);
752
Nils Diewald8f6b6102015-01-08 18:25:33 +0000753 // This will prevent destruction of
754 // the operand
755 this._operands = [];
Nils Diewaldf219eb82015-01-07 20:15:42 +0000756
757 // Parent is a group
758 if (parent.ldType() !== null) {
Nils Diewald8e7182e2015-01-08 15:02:07 +0000759 return parent.replaceOperand(this, op).update();
Nils Diewaldf219eb82015-01-07 20:15:42 +0000760 }
761
Nils Diewald8f6b6102015-01-08 18:25:33 +0000762 // Parent is vc
Nils Diewaldf219eb82015-01-07 20:15:42 +0000763 else {
Nils Diewaldf219eb82015-01-07 20:15:42 +0000764 this.destroy();
Nils Diewald8f6b6102015-01-08 18:25:33 +0000765 // Cyclic madness
766 parent.root(op);
767 op.parent(parent);
Nils Diewaldf219eb82015-01-07 20:15:42 +0000768 return parent.root();
Nils Diewald5c817a42015-01-06 01:08:56 +0000769 };
770 };
771
Nils Diewald966abf12014-12-20 02:27:45 +0000772 if (this._element === undefined)
Nils Diewald5c817a42015-01-06 01:08:56 +0000773 return this;
Nils Diewald966abf12014-12-20 02:27:45 +0000774
Nils Diewald5c817a42015-01-06 01:08:56 +0000775 var group = this._element;
776 group.setAttribute('data-operation', this.operation());
Nils Diewald966abf12014-12-20 02:27:45 +0000777
Nils Diewald5c817a42015-01-06 01:08:56 +0000778 _removeChildren(group);
Nils Diewald966abf12014-12-20 02:27:45 +0000779
780 // Append operands
Nils Diewald5c817a42015-01-06 01:08:56 +0000781 for (var i in this._operands) {
782 group.appendChild(
Nils Diewald966abf12014-12-20 02:27:45 +0000783 this.getOperand(i).element()
784 );
785 };
786
787 // Set operators
788 var op = this.operators(
789 this.operation() == 'and' ? false : true,
790 this.operation() == 'or' ? false : true,
791 true
792 );
793
Nils Diewald5c817a42015-01-06 01:08:56 +0000794 group.appendChild(
Nils Diewald966abf12014-12-20 02:27:45 +0000795 op.element()
796 );
797
Nils Diewald5c817a42015-01-06 01:08:56 +0000798 return this;
Nils Diewald966abf12014-12-20 02:27:45 +0000799 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000800
Nils Diewald8f4e2542014-12-19 04:42:09 +0000801 element : function () {
802 if (this._element !== undefined)
803 return this._element;
804
805 this._element = document.createElement('div');
806 this._element.setAttribute('class', 'docGroup');
Nils Diewald8f4e2542014-12-19 04:42:09 +0000807
Nils Diewaldf219eb82015-01-07 20:15:42 +0000808 // Update the object - including optimization
Nils Diewald966abf12014-12-20 02:27:45 +0000809 this.update();
Nils Diewald8f4e2542014-12-19 04:42:09 +0000810
811 return this._element;
812 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000813
Nils Diewald8f4e2542014-12-19 04:42:09 +0000814 operation : function (op) {
815 if (arguments.length === 1) {
816 if (KorAP._validGroupOpRE.test(op)) {
817 this._op = op;
818 }
819 else {
820 KorAP.log(810, "Unknown operation type");
821 return;
822 };
823 };
824 return this._op || 'and';
825 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000826
Nils Diewald8f4e2542014-12-19 04:42:09 +0000827 operands : function () {
828 return this._operands;
829 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000830
Nils Diewald8f4e2542014-12-19 04:42:09 +0000831 getOperand : function (index) {
832 return this._operands[index];
833 },
834
Nils Diewald5c817a42015-01-06 01:08:56 +0000835 // Replace operand
Nils Diewaldf219eb82015-01-07 20:15:42 +0000836 replaceOperand : function (oldOp, newOp) {
Nils Diewald5c817a42015-01-06 01:08:56 +0000837 for (var i in this._operands) {
Nils Diewaldf219eb82015-01-07 20:15:42 +0000838 if (this._operands[i] === oldOp) {
839
Nils Diewalde15b7a22015-01-09 21:50:21 +0000840 // Just insert a doc or ...
841 if (newOp.ldType() === "doc" ||
842 // ... insert a group of a different operation
843 // (i.e. "and" in "or"/"or" in "and")
844 newOp.operation() != this.operation()) {
Nils Diewaldf219eb82015-01-07 20:15:42 +0000845 this._operands[i] = newOp;
Nils Diewald8f6b6102015-01-08 18:25:33 +0000846 newOp.parent(this);
Nils Diewaldf219eb82015-01-07 20:15:42 +0000847 }
848
849 // Flatten the group
850 else {
Nils Diewald8e7182e2015-01-08 15:02:07 +0000851 // Remove old group
852 this._operands.splice(i, 1);
853
854 // Inject new operands
Nils Diewald8f6b6102015-01-08 18:25:33 +0000855 for (var op in newOp.operands().reverse()) {
856 this._operands.splice(i, 0, newOp.getOperand(op));
857 newOp.getOperand(0).parent(this);
858 };
859 // Prevent destruction of operands
860 newOp._operands = [];
861 newOp.destroy();
Nils Diewaldf219eb82015-01-07 20:15:42 +0000862 };
863 oldOp.destroy();
864 return this;
Nils Diewald5c817a42015-01-06 01:08:56 +0000865 }
866 };
867 return false;
868 },
869
Nils Diewald0297ba12015-01-05 21:56:12 +0000870 // Delete operand from group
871 delOperand : function (obj) {
872 for (var i in this._operands) {
873 if (this._operands[i] === obj) {
Nils Diewald8e7182e2015-01-08 15:02:07 +0000874
Nils Diewald8f6b6102015-01-08 18:25:33 +0000875 // Delete identified operand
Nils Diewald0297ba12015-01-05 21:56:12 +0000876 this._operands.splice(i,1);
877
Nils Diewald5c817a42015-01-06 01:08:56 +0000878 // Destroy object for cyclic references
879 obj.destroy();
880
Nils Diewaldf219eb82015-01-07 20:15:42 +0000881 return this;
Nils Diewald0297ba12015-01-05 21:56:12 +0000882 };
883 };
Nils Diewald5c817a42015-01-06 01:08:56 +0000884
885 // Operand not found
886 return undefined;
Nils Diewald0297ba12015-01-05 21:56:12 +0000887 },
888
Nils Diewald8f4e2542014-12-19 04:42:09 +0000889 // Deserialize from json
890 fromJson : function (json) {
891 if (json === undefined)
892 return this;
893
894 if (json["@type"] !== "korap:docGroup") {
895 KorAP.log(701, "JSON-LD group has no @type attribute");
896 return;
897 };
898
899 if (json["operation"] === undefined ||
900 typeof json["operation"] !== 'string') {
901 KorAP.log(811, "Document group expects operation");
902 return;
903 };
904
905 var operation = json["operation"];
906
907 this.operation(operation.replace(/^operation:/,''));
908
909 if (json["operands"] === undefined ||
910 !(json["operands"] instanceof Array)) {
911 KorAP.log(704, "Operation needs operand list")
912 return;
913 };
914
915 // Add all documents
916 for (var i in json["operands"]) {
917 var operand = json["operands"][i];
Nils Diewald966abf12014-12-20 02:27:45 +0000918 this.append(operand);
Nils Diewald8f4e2542014-12-19 04:42:09 +0000919 };
920
921 return this;
922 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000923
Nils Diewald8f4e2542014-12-19 04:42:09 +0000924 toJson : function () {
925 var opArray = new Array();
926 for (var i in this._operands) {
Nils Diewalde15b7a22015-01-09 21:50:21 +0000927 if (this._operands[i].ldType() !== 'non')
928 opArray.push(this._operands[i].toJson());
Nils Diewald8f4e2542014-12-19 04:42:09 +0000929 };
930 return {
931 "@type" : "korap:" + this.ldType(),
932 "operation" : "operation:" + this.operation(),
933 "operands" : opArray
934 };
Nils Diewaldf219eb82015-01-07 20:15:42 +0000935 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000936
Nils Diewalde15b7a22015-01-09 21:50:21 +0000937 toQuery : function (brackets) {
938 var list = this._operands
939 .filter(function (op) {
940 return op.ldType() !== 'non';
941 })
942 .map(function (op) {
Nils Diewaldd599d542015-01-08 20:41:34 +0000943 return (op.ldType() === 'docGroup') ?
Nils Diewalde15b7a22015-01-09 21:50:21 +0000944 op.toQuery(true) :
Nils Diewaldd599d542015-01-08 20:41:34 +0000945 op.toQuery();
Nils Diewalde15b7a22015-01-09 21:50:21 +0000946 });
947
948 if (list.length === 1)
949 return list.join('');
950 else {
951 var str = list.join(this.operation() === 'or' ? ' | ' : ' & ');
952 return brackets ? '(' + str + ')' : str;
953 };
Nils Diewald8f4e2542014-12-19 04:42:09 +0000954 }
955 };
956
957
Nils Diewaldd599d542015-01-08 20:41:34 +0000958 /**
959 * Abstract JsonLD criterion object
960 */
Nils Diewald8f4e2542014-12-19 04:42:09 +0000961 KorAP.JsonLD = {
Nils Diewald8f6b6102015-01-08 18:25:33 +0000962 _changed : false,
963
Nils Diewald8f4e2542014-12-19 04:42:09 +0000964 create : function () {
965 return Object.create(KorAP.JsonLD);
966 },
967
968 /**
969 * Upgrade this object to another object
970 * while private data stays intact
971 */
972 upgradeTo : function (props) {
973 for (var prop in props) {
974 this[prop] = props[prop];
975 };
976 return this;
977 },
Nils Diewald8f6b6102015-01-08 18:25:33 +0000978
Nils Diewald8f4e2542014-12-19 04:42:09 +0000979 ldType : function (type) {
980 if (arguments.length === 1)
981 this._ldType = type;
982 return this._ldType;
983 },
Nils Diewald8f6b6102015-01-08 18:25:33 +0000984
Nils Diewald8f4e2542014-12-19 04:42:09 +0000985 parent : function (obj) {
Nils Diewald8f6b6102015-01-08 18:25:33 +0000986 if (arguments.length === 1) {
Nils Diewald8f4e2542014-12-19 04:42:09 +0000987 this._parent = obj;
Nils Diewald8f6b6102015-01-08 18:25:33 +0000988 this._changed = true;
989 };
Nils Diewald8f4e2542014-12-19 04:42:09 +0000990 return this._parent;
Nils Diewald966abf12014-12-20 02:27:45 +0000991 },
Nils Diewald0297ba12015-01-05 21:56:12 +0000992
Nils Diewald5c817a42015-01-06 01:08:56 +0000993 // Destroy object - especially for
994 // acyclic structures!
995 // I'm a paranoid chicken!
996 destroy : function () {
997 if (this._ops != undefined) {
998 this._ops._parent = undefined;
999 if (this._ops._element !== undefined)
1000 this._ops._element.refTo = undefined;
1001 this._ops = undefined;
1002 };
1003 if (this._element !== undefined)
1004 this._element = undefined;
1005
1006 // In case of a group, destroy all operands
1007 if (this._operands !== undefined) {
1008 for (var i in this._operands)
1009 this.getOperand(i).destroy();
Nils Diewaldf219eb82015-01-07 20:15:42 +00001010 this._operands = [];
Nils Diewald5c817a42015-01-06 01:08:56 +00001011 };
1012 },
1013
Nils Diewald0297ba12015-01-05 21:56:12 +00001014 // Be aware! This may be cyclic
Nils Diewald966abf12014-12-20 02:27:45 +00001015 operators : function (and, or, del) {
1016 if (arguments === 0)
1017 return this._ops;
1018 this._ops = KorAP.Operators.create(
1019 and, or, del
1020 );
Nils Diewald0297ba12015-01-05 21:56:12 +00001021 this._ops.parent(this);
Nils Diewald966abf12014-12-20 02:27:45 +00001022 return this._ops;
1023 },
Nils Diewald8f6b6102015-01-08 18:25:33 +00001024
Nils Diewald966abf12014-12-20 02:27:45 +00001025 toJson : function () {
1026 return {
1027 // Unspecified object
1028 "@type" : "korap:" + this.ldType()
1029 };
Nils Diewald8f6b6102015-01-08 18:25:33 +00001030 },
Nils Diewaldd599d542015-01-08 20:41:34 +00001031
1032 toQuery : function () {
Nils Diewald8f6b6102015-01-08 18:25:33 +00001033 return loc.EMPTY;
Nils Diewald8f4e2542014-12-19 04:42:09 +00001034 }
1035 };
1036
Nils Diewald3a2d8022014-12-16 02:45:41 +00001037}(this.KorAP));