blob: 9ff632567cc0969df50e31785c9acf08badd4607 [file] [log] [blame]
Nils Diewald3a2d8022014-12-16 02:45:41 +00001var KorAP = KorAP || {};
Nils Diewald3a2d8022014-12-16 02:45:41 +00002
Nils Diewaldd0770492014-12-19 03:55:00 +00003// Todo: Implement a working localization solution!
4// Todo: Refactor out the distinction between DocElement and Doc,
5// DocGroupElement and DocGroup
6
7/*
8 * Error codes:
9 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
22
23/*
24 - TODO: Support 'update' method to update elements on change
Nils Diewald3a2d8022014-12-16 02:45:41 +000025*/
26
27(function (KorAP) {
28 "use strict";
29
30 // Default log message
31 KorAP.log = KorAP.log || function (type, msg) {
32 console.log(type + ": " + msg);
33 };
34
35 KorAP._validStringMatchRE = new RegExp("^(?:eq|ne|contains)$");
36 KorAP._validRegexMatchRE = new RegExp("^(?:eq|ne)$");
Nils Diewaldd0770492014-12-19 03:55:00 +000037 KorAP._validDateMatchRE = new RegExp("^[lg]?eq$");
Nils Diewald3a2d8022014-12-16 02:45:41 +000038 KorAP._validDateRE = new RegExp("^(?:\\d{4})(?:-\\d\\d(?:-\\d\\d)?)?$");
39 KorAP._validGroupOpRE = new RegExp("^(?:and|or)$");
40
Nils Diewaldd0770492014-12-19 03:55:00 +000041 var loc = (KorAP.Locale = KorAP.Locale || {} );
42 loc.AND = loc.AND || 'and';
43 loc.OR = loc.OR || 'or';
44 loc.DEL = loc.DEL || '×';
45
Nils Diewald3a2d8022014-12-16 02:45:41 +000046 KorAP.VirtualCollection = {
Nils Diewaldd0770492014-12-19 03:55:00 +000047 _root : undefined,
Nils Diewald3a2d8022014-12-16 02:45:41 +000048 create : function () {
49 return Object.create(KorAP.VirtualCollection);
50 },
Nils Diewaldd0770492014-12-19 03:55:00 +000051 render : function (json) {
52 var obj = Object.create(KorAP.VirtualCollection);
53
54 if (json !== undefined) {
55 // Root object
56 if (json['@type'] == 'korap:doc') {
57 obj._root = KorAP.DocElement.create(undefined, json);
58 }
59 else if (json['@type'] == 'korap:docGroup') {
60 obj._root = KorAP.DocGroupElement.create(undefined, json);
61 }
62 else {
63 KorAP.log(813, "Collection type is not supported");
64 return;
65 };
66 }
67
68 else {
69 // Add unspecified object
70 obj._root = KorAP.UnspecifiedDocElement.create();
71 };
72
73 // Add root element to root node
74 obj.element().appendChild(
75 obj._root.element()
76 );
77
78 return obj;
Nils Diewald3a2d8022014-12-16 02:45:41 +000079 },
Nils Diewaldd0770492014-12-19 03:55:00 +000080 root : function () {
81 return this._root;
Nils Diewald3a2d8022014-12-16 02:45:41 +000082 },
Nils Diewaldd0770492014-12-19 03:55:00 +000083 element : function () {
84 if (this._element !== undefined)
85 return this._element;
86
87 this._element = document.createElement('div');
88 this._element.setAttribute('class', 'vc');
89 return this._element;
Nils Diewald3a2d8022014-12-16 02:45:41 +000090 }
91 };
92
Nils Diewaldd0770492014-12-19 03:55:00 +000093 KorAP.Operators = {
94 create : function (and, or, del) {
95 var op = Object.create(KorAP.Operators);
96 op.and(and);
97 op.or(or);
98 op.del(del);
99 return op;
100 },
101 update : function () {
102
103 // Init the element
104 if (this._element === undefined)
105 return this.element();
106
107 var op = this._element;
108
109 // Remove everything underneath
110 while (op.firstChild) {
111 op.removeChild(op.firstChild);
112 };
113
114 // Add and button
115 if (this._and === true) {
116 var andE = document.createElement('span');
117 andE.setAttribute('class', 'and');
118 andE.appendChild(document.createTextNode(KorAP.Locale.AND));
119 op.appendChild(andE);
120 };
121
122 // Add or button
123 if (this._or === true) {
124 var orE = document.createElement('span');
125 orE.setAttribute('class', 'or');
126 orE.appendChild(document.createTextNode(KorAP.Locale.OR));
127 op.appendChild(orE);
128 };
129
130 // Add delete button
131 if (this._del === true) {
132 var delE = document.createElement('span');
133 delE.setAttribute('class', 'delete');
134 delE.appendChild(document.createTextNode(KorAP.Locale.DEL));
135 op.appendChild(delE);
136 };
137 return true;
138 },
139 element : function () {
140
141 // Return existing element
142 if (this._element !== undefined)
143 return this._element;
144
145 this._element = document.createElement('div');
146 this._element.setAttribute('class', 'operators');
147
148 // Init elements
149 this.update();
150 return this._element;
151 },
152 and : function (bool) {
153 if (arguments.length === 1)
154 this._and = (bool === undefined || bool === false) ? false : true;
155 return this._and;
156 },
157 or : function (bool) {
158 if (arguments.length === 1)
159 this._or = (bool === undefined || bool === false) ? false : true;
160 return this._or;
161 },
162 del : function (bool) {
163 if (arguments.length === 1)
164 this._del = (bool === undefined || bool === false) ? false : true;
165 return this._del;
166 }
167 };
168
169
170 /**
171 * Unspecified criterion
172 */
173 KorAP.UnspecifiedDocElement = {
174 _obj : function () { return KorAP.UnspecifiedDocElement; },
175 _objType : 'UnspecifiedDocElement',
176 create : function (parent) {
177 var obj = Object.create(KorAP.JsonLD).extend(KorAP.UnspecifiedDocElement);
178 if (parent !== undefined)
179 obj._parent = parent;
180 return obj;
181 },
182 element : function () {
183 if (this._element !== undefined)
184 return this._element;
185 this._element = document.createElement('div');
186 this._element.setAttribute('class', 'undefined');
187 return this._element;
188 }
189 };
190
191
192 KorAP.DocElement = {
193 _obj : function () { return KorAP.DocElement; },
194 _objType : 'DocElement',
195
196 create : function (parent, json) {
197 var obj = KorAP.Doc.create().extend(KorAP.DocElement).fromJson(json);
198 if (parent !== undefined)
199 obj._parent = parent;
200 return obj;
201 },
202 element : function () {
203 if (this._element !== undefined)
204 return this._element;
205
206 this._element = document.createElement('div');
207 var e = this._element;
208 e.setAttribute('class', 'doc');
209
210 // Added key
211 var key = document.createElement('span');
212 key.setAttribute('class', 'key');
213 if (this.key())
214 key.appendChild(document.createTextNode(this.key()));
215
216 // Added match operator
217 var matchop = document.createElement('span');
218 matchop.setAttribute('data-type', this.type());
219 matchop.setAttribute('class', 'match');
220 matchop.appendChild(document.createTextNode(this.matchop()));
221
222 // Added match operator
223 var value = document.createElement('span');
224 value.setAttribute('data-type', this.type());
225 value.setAttribute('class', 'value');
226 if (this.value())
227 value.appendChild(document.createTextNode(this.value()));
228
229 // Add spans
230 e.appendChild(key);
231 e.appendChild(matchop);
232 e.appendChild(value);
233 return e;
234 },
235
236 // parent, element
237 // Wrap a new operation around the doc element
238 wrap : function (op) {
239 var group = KorAP.DocGroupElement.create(undefined);
240 group.appendOperand(this);
241 group.appendOperand(null);
242 this.parent(group);
243/*
244 var div = document.createElement('div');
245 div.setAttribute('data-operation', op);
246 var parent = this.element.parent;
247 parent.removeChild(this.element);
248 parent.appendChild(div);
249 div.appendChild(this.element);
250 return div;
251*/
252 }
253 };
254
255 KorAP.DocGroupElement = {
256 _obj : function () { return KorAP.DocGroupElement; },
257 _objType : 'DocGroupElement',
258
259 create : function (parent, json) {
260 var obj = KorAP.DocGroup.create().extend(KorAP.DocGroupElement).fromJson(json);
261 if (parent !== undefined)
262 obj._parent = parent;
263 return obj;
264 },
265 appendOperand : function (operand) {
266 switch (operand["@type"]) {
267 case undefined:
268 if (operand["objType"]) {
269 if (operand.objType() === 'Doc') {
270 operand = operand.upgrade(KorAP.DocElement);
271 }
272 else if (operand.objType() === 'DocGroup') {
273 operand = operand.upgrade(KorAP.DocElementGroup);
274 }
275 else if (operand.objType() !== 'DocElement' &&
276 operand.objType() !== 'DocElementGroup') {
277 KorAP.log(812, "Operand not supported in document group");
278 return;
279 };
280 this._operands.push(operand);
281 return operand;
282 };
283
284 KorAP.log(701, "JSON-LD group has no @type attribute");
285 return;
286
287 case "korap:doc":
288 var doc = KorAP.DocElement.create().fromJson(operand);
289 if (doc === undefined)
290 return;
291 this._operands.push(doc);
292 return doc;
293
294 case "korap:docGroup":
295 var docGroup = KorAP.DocGroupElement.create().fromJson(operand);
296 if (docGroup === undefined)
297 return;
298 this._operands.push(docGroup);
299 return docGroup;
300
301 default:
302 KorAP.log(812, "Operand not supported in document group");
303 return;
304 };
305 },
306 element : function () {
307 if (this._element !== undefined)
308 return this._element;
309
310 this._element = document.createElement('div');
311 this._element.setAttribute('class', 'docGroup');
312 this._element.setAttribute('data-operation', this.operation());
313
314 for (var i in this.operands()) {
315 this._element.appendChild(
316 this.getOperand(i).element()
317 );
318 };
319
320 return this._element;
321 },
322 };
323
324
325 // Abstract JsonLD object
326 KorAP.JsonLD = {
327 _obj : function () { return KorAP.JsonLD; },
328 _objType : 'JsonLD',
329 create : function () {
330 return Object.create(KorAP.JsonLD);
331 },
332
333 // Extend this object with another object
334 // Private data will be lost
335 extend : function (props) {
336 var jld = this._obj().create();
337 for (var prop in props) {
338 jld[prop] = props[prop];
339 };
340 return jld;
341 },
342
343 // Upgrade this object to another object
344 // Private data stays intact
345 upgrade : function (props) {
346 for (var prop in props) {
347 this[prop] = props[prop];
348 };
349 return this;
350 },
351 ldType : function (type) {
352 if (arguments.length === 1)
353 this._ldType = type;
354 return this._ldType;
355 },
356 objType : function () {
357 return this._objType;
358 },
359 parent : function (obj) {
360 if (arguments.length === 1)
361 this._parent = obj;
362 return this._parent;
363 }
364 };
365
366
Nils Diewald3a2d8022014-12-16 02:45:41 +0000367 KorAP.DocGroup = {
Nils Diewaldd0770492014-12-19 03:55:00 +0000368 _ldType : "docGroup",
369 _obj : function () { return KorAP.DocGroup; },
370 _objType : 'DocGroup',
Nils Diewald3a2d8022014-12-16 02:45:41 +0000371 create : function (type) {
Nils Diewaldd0770492014-12-19 03:55:00 +0000372 var docGroup = Object.create(KorAP.JsonLD).extend(KorAP.DocGroup);
373 if (type !== undefined)
374 docGroup.operation(type);
Nils Diewald3a2d8022014-12-16 02:45:41 +0000375 docGroup._operands = [];
Nils Diewald3a2d8022014-12-16 02:45:41 +0000376 return docGroup;
377 },
378
379 // Deserialize from json
380 fromJson : function (json) {
Nils Diewald3a2d8022014-12-16 02:45:41 +0000381 if (json === undefined)
Nils Diewaldd0770492014-12-19 03:55:00 +0000382 return this;
Nils Diewald3a2d8022014-12-16 02:45:41 +0000383
Nils Diewaldd0770492014-12-19 03:55:00 +0000384 if (json["@type"] !== "korap:docGroup") {
Nils Diewald3a2d8022014-12-16 02:45:41 +0000385 KorAP.log(701, "JSON-LD group has no @type attribute");
386 return;
387 };
388
Nils Diewald3a2d8022014-12-16 02:45:41 +0000389 if (json["operation"] === undefined ||
390 typeof json["operation"] !== 'string') {
391 KorAP.log(811, "Document group expects operation");
392 return;
393 };
394
395 var operation = json["operation"];
Nils Diewald3a2d8022014-12-16 02:45:41 +0000396
Nils Diewaldd0770492014-12-19 03:55:00 +0000397 this.operation(operation.replace(/^operation:/,''));
Nils Diewald3a2d8022014-12-16 02:45:41 +0000398
399 if (json["operands"] === undefined ||
400 !(json["operands"] instanceof Array)) {
401 KorAP.log(704, "Operation needs operand list")
402 return;
403 };
404
Nils Diewald3a2d8022014-12-16 02:45:41 +0000405 // Add all documents
Nils Diewaldd0770492014-12-19 03:55:00 +0000406 for (var i in json["operands"]) {
407 var operand = json["operands"][i];
408 this.appendOperand(operand);
409 };
410
411 return this;
412 },
413 operation : function (op) {
414 if (arguments.length === 1) {
415 if (KorAP._validGroupOpRE.test(op)) {
416 this._op = op;
417 }
418 else {
419 KorAP.log(810, "Unknown operation type");
Nils Diewald3a2d8022014-12-16 02:45:41 +0000420 return;
421 };
422 };
Nils Diewald3a2d8022014-12-16 02:45:41 +0000423 return this._op || 'and';
424 },
Nils Diewaldd0770492014-12-19 03:55:00 +0000425 operands : function () {
Nils Diewald3a2d8022014-12-16 02:45:41 +0000426 return this._operands;
427 },
Nils Diewaldd0770492014-12-19 03:55:00 +0000428 appendOperand : function (operand) {
429 switch (operand["@type"]) {
430 case undefined:
431 if (operand["objType"] && (
432 operand.objType() === 'Doc' ||
433 operand.objType() === 'DocGroup')) {
434 this._operands.push(operand);
435 return operand;
436 };
437 KorAP.log(701, "JSON-LD group has no @type attribute");
438 return;
439
440 case "korap:doc":
441 var doc = KorAP.Doc.create().fromJson(operand);
442 if (doc === undefined)
443 return;
444 this._operands.push(doc);
445 return doc;
446
447 case "korap:docGroup":
448 var docGroup = KorAP.DocGroup.create().fromJson(operand);
449 if (docGroup === undefined)
450 return;
451 this._operands.push(docGroup);
452 return docGroup;
453
454 default:
455 KorAP.log(812, "Operand not supported in document group");
456 return;
457 };
Nils Diewald3a2d8022014-12-16 02:45:41 +0000458 },
459 getOperand : function (index) {
460 return this._operands[index];
461 },
Nils Diewald3a2d8022014-12-16 02:45:41 +0000462 toJson : function () {
Nils Diewaldd0770492014-12-19 03:55:00 +0000463 var opArray = new Array();
Nils Diewald3a2d8022014-12-16 02:45:41 +0000464 for (var i in this._operands) {
Nils Diewaldd0770492014-12-19 03:55:00 +0000465 opArray.push(this._operands[i].toJson());
Nils Diewald3a2d8022014-12-16 02:45:41 +0000466 };
467 return {
Nils Diewaldd0770492014-12-19 03:55:00 +0000468 "@type" : "korap:" + this.ldType(),
469 "operation" : "operation:" + this.operation(),
470 "operands" : opArray
Nils Diewald3a2d8022014-12-16 02:45:41 +0000471 };
472 }
473 };
474
475 /**
476 * Virtual collection doc criterion.
477 */
478 KorAP.Doc = {
Nils Diewaldd0770492014-12-19 03:55:00 +0000479 _ldType : "doc",
480 _obj : function () { return KorAP.Doc; },
481 _objType : 'Doc',
Nils Diewald3a2d8022014-12-16 02:45:41 +0000482 // Create new
483 create : function () {
Nils Diewaldd0770492014-12-19 03:55:00 +0000484 return Object.create(KorAP.JsonLD).extend(KorAP.Doc);
Nils Diewald3a2d8022014-12-16 02:45:41 +0000485 },
486
487 // Deserialize from json
488 fromJson : function (json) {
Nils Diewald3a2d8022014-12-16 02:45:41 +0000489 if (json === undefined)
Nils Diewaldd0770492014-12-19 03:55:00 +0000490 return this;
491 // return this.create();
Nils Diewald3a2d8022014-12-16 02:45:41 +0000492
493 if (json["@type"] !== "korap:doc") {
494 KorAP.log(701, "JSON-LD group has no @type attribute");
495 return;
496 };
497
Nils Diewald3a2d8022014-12-16 02:45:41 +0000498 if (json["value"] === undefined ||
499 typeof json["value"] != 'string') {
500 KorAP.log(805, "Value is invalid");
501 return;
502 };
503
504 // There is a defined key
505 if (json["key"] !== undefined &&
506 typeof json["key"] === 'string') {
507
508 // Set key
Nils Diewaldd0770492014-12-19 03:55:00 +0000509 this.key(json["key"]);
Nils Diewald3a2d8022014-12-16 02:45:41 +0000510
511 // Set match operation
512 if (json["match"] !== undefined) {
Nils Diewaldd0770492014-12-19 03:55:00 +0000513 if (typeof json["match"] === 'string') {
514 this.matchop(json["match"]);
515 }
Nils Diewald3a2d8022014-12-16 02:45:41 +0000516 else {
517 KorAP.log(802, "Match type is not supported by value type");
518 return;
519 };
520 };
521
522 // Key is a string
523 if (json["type"] === undefined ||
524 json["type"] == "type:string") {
Nils Diewaldd0770492014-12-19 03:55:00 +0000525 this.type("string");
Nils Diewald3a2d8022014-12-16 02:45:41 +0000526
527 // Check match type
Nils Diewaldd0770492014-12-19 03:55:00 +0000528 if (!KorAP._validStringMatchRE.test(this.matchop())) {
Nils Diewald3a2d8022014-12-16 02:45:41 +0000529 KorAP.log(802, "Match type is not supported by value type");
530 return;
531 };
532
533 // Set string value
Nils Diewaldd0770492014-12-19 03:55:00 +0000534 this.value(json["value"]);
Nils Diewald3a2d8022014-12-16 02:45:41 +0000535 }
536
537 // Key is a date
538 else if (json["type"] === "type:date") {
Nils Diewaldd0770492014-12-19 03:55:00 +0000539 this.type("date");
Nils Diewald3a2d8022014-12-16 02:45:41 +0000540
541 if (json["value"] !== undefined &&
542 KorAP._validDateRE.test(json["value"])) {
543
Nils Diewaldd0770492014-12-19 03:55:00 +0000544 if (!KorAP._validDateMatchRE.test(this.matchop())) {
Nils Diewald3a2d8022014-12-16 02:45:41 +0000545 KorAP.log(802, "Match type is not supported by value type");
546 return;
547 };
548
549 // Set value
Nils Diewaldd0770492014-12-19 03:55:00 +0000550 this.value(json["value"]);
Nils Diewald3a2d8022014-12-16 02:45:41 +0000551 }
552 else {
553 KorAP.log(806, "Value is not a valid date string");
554 return;
555 };
556 }
557
558 // Key is a regular expression
559 else if (json["type"] === "type:regex") {
Nils Diewaldd0770492014-12-19 03:55:00 +0000560 this.type("regex");
Nils Diewald3a2d8022014-12-16 02:45:41 +0000561
562 try {
563
564 // Try to create a regular expression
565 var check = new RegExp(json["value"]);
566
Nils Diewaldd0770492014-12-19 03:55:00 +0000567 if (!KorAP._validRegexMatchRE.test(this.matchop())) {
Nils Diewald3a2d8022014-12-16 02:45:41 +0000568 KorAP.log(802, "Match type is not supported by value type");
569 return;
570 };
571
Nils Diewaldd0770492014-12-19 03:55:00 +0000572 this.value(json["value"]);
Nils Diewald3a2d8022014-12-16 02:45:41 +0000573 }
Nils Diewaldd0770492014-12-19 03:55:00 +0000574
Nils Diewald3a2d8022014-12-16 02:45:41 +0000575 catch (e) {
576 KorAP.log(807, "Value is not a valid regular expression");
577 return;
578 };
Nils Diewaldd0770492014-12-19 03:55:00 +0000579 this.type("regex");
Nils Diewald3a2d8022014-12-16 02:45:41 +0000580 }
581
582 else {
583 KorAP.log(804, "Unknown value type");
584 return;
585 };
586 };
587
588 return this;
589 },
Nils Diewaldd0770492014-12-19 03:55:00 +0000590 key : function (value) {
591 if (arguments.length === 1)
592 this._key = value;
Nils Diewald3a2d8022014-12-16 02:45:41 +0000593 return this._key;
594 },
Nils Diewaldd0770492014-12-19 03:55:00 +0000595 matchop : function (match) {
596 if (arguments.length === 1)
597 this._matchop = match.replace(/^match:/, '');
Nils Diewald3a2d8022014-12-16 02:45:41 +0000598 return this._matchop || "eq";
599 },
Nils Diewaldd0770492014-12-19 03:55:00 +0000600 type : function (type) {
601 if (arguments.length === 1)
602 this._type = type;
Nils Diewald3a2d8022014-12-16 02:45:41 +0000603 return this._type || "string";
604 },
Nils Diewaldd0770492014-12-19 03:55:00 +0000605 value : function (value) {
606 if (arguments.length === 1)
607 this._value = value;
Nils Diewald3a2d8022014-12-16 02:45:41 +0000608 return this._value;
609 },
Nils Diewald3a2d8022014-12-16 02:45:41 +0000610 toJson : function () {
Nils Diewaldd0770492014-12-19 03:55:00 +0000611 if (!this.matchop() || !this.key())
Nils Diewald3a2d8022014-12-16 02:45:41 +0000612 return {};
613
614 return {
Nils Diewaldd0770492014-12-19 03:55:00 +0000615 "@type" : "korap:" + this.ldType(),
616 "key" : this.key(),
617 "match" : "match:" + this.matchop(),
618 "value" : this.value() || '',
619 "type" : "type:" + this.type()
Nils Diewald3a2d8022014-12-16 02:45:41 +0000620 };
621 }
622 };
623}(this.KorAP));