blob: 07943f099eef0769337d37aad6fadb2e3c632596 [file] [log] [blame]
Nils Diewald0e6992a2015-04-14 20:13:52 +00001/**
Nils Diewald4c221252015-04-21 20:19:25 +00002 * A new document criterion
Nils Diewald0e6992a2015-04-14 20:13:52 +00003 */
4
Nils Diewald0e6992a2015-04-14 20:13:52 +00005define([
Nils Diewald4c221252015-04-21 20:19:25 +00006 'vc/jsonld',
7 'vc/rewritelist',
Nils Diewaldf0c4f112015-05-05 12:56:59 +00008 'vc/stringval',
Nils Diewald4c221252015-04-21 20:19:25 +00009 'util'
Nils Diewaldf0c4f112015-05-05 12:56:59 +000010], function (jsonldClass, rewriteListClass, stringValClass) {
Nils Diewald1fcb2ad2015-04-20 19:19:18 +000011
Nils Diewald4c221252015-04-21 20:19:25 +000012 /*
13 var fieldMenu = menuClass.create([
Nils Diewald7148c6f2015-05-04 15:07:53 +000014 ['Titel', 'title', 'string'],
15 ['Untertitel', 'subTitle', 'string'],
16 ['Veröffentlichungsdatum', 'pubDate', 'date'],
17 ['Autor', 'author', 'string']
Nils Diewald4c221252015-04-21 20:19:25 +000018 ]);
19
20 fieldMenu.limit(5);
21 */
Nils Diewald0e6992a2015-04-14 20:13:52 +000022
23 _validRegexMatchRE = new RegExp("^(?:eq|ne)$");
24
Nils Diewald4c221252015-04-21 20:19:25 +000025 var loc = KorAP.Locale;
26 loc.EMPTY = loc.EMPTY || '⋯';
Nils Diewald1fcb2ad2015-04-20 19:19:18 +000027
Nils Diewald0e6992a2015-04-14 20:13:52 +000028 return {
Nils Diewald4c221252015-04-21 20:19:25 +000029
30 // The JSON-LD type
Nils Diewald0e6992a2015-04-14 20:13:52 +000031 _ldType : "doc",
Nils Diewald4c221252015-04-21 20:19:25 +000032
33 // The object ... maybe not important
Nils Diewald0e6992a2015-04-14 20:13:52 +000034 _obj : function () { return '???'; /*KorAP.Doc*/ },
35
Nils Diewald4c221252015-04-21 20:19:25 +000036 /**
37 * Create a new document criterion
38 * by passing the parent object and a json construct.
39 */
Nils Diewald0e6992a2015-04-14 20:13:52 +000040 create : function (parent, json) {
Nils Diewald4c221252015-04-21 20:19:25 +000041
42 // Create the object, inheriting from Json-LD class
Nils Diewald0e6992a2015-04-14 20:13:52 +000043 var obj = Object(jsonldClass).
44 create().
45 upgradeTo(this).
46 fromJson(json);
Nils Diewald4c221252015-04-21 20:19:25 +000047
48 // Bind the parent
Nils Diewald0e6992a2015-04-14 20:13:52 +000049 if (parent !== undefined)
50 obj._parent = parent;
51
52 obj.__changed = true;
53 return obj;
54 },
55
Nils Diewald4c221252015-04-21 20:19:25 +000056 /**
57 * Update the elements content.
58 */
Nils Diewald0e6992a2015-04-14 20:13:52 +000059 update : function () {
60 if (this._element === undefined)
61 return this.element();
62
63 // Get element
64 var e = this._element;
65
66 // Set ref - TODO: Cleanup!
67 e.refTo = this;
68
69 // Check if there is a change
70 if (this.__changed) {
71
72 // Was rewritten
73 if (this.rewrites() !== undefined) {
74 e.classList.add("rewritten");
75 };
76
77 // Added key
Nils Diewald4c221252015-04-21 20:19:25 +000078 this._keyE = document.createElement('span');
79 this._keyE.setAttribute('class', 'key');
Nils Diewald0e6992a2015-04-14 20:13:52 +000080
81 // Change key
Nils Diewald4c221252015-04-21 20:19:25 +000082 this._keyE.addEventListener('click', this._changeKey.bind(this));
Nils Diewald0e6992a2015-04-14 20:13:52 +000083
Nils Diewald4c221252015-04-21 20:19:25 +000084 if (this.key()) {
85 var k = this.key();
86 if (loc['VC_' + k] !== undefined)
87 k = loc['VC_' + k];
88 this._keyE.appendChild(document.createTextNode(k));
89 };
90
Nils Diewald0e6992a2015-04-14 20:13:52 +000091 // Added match operator
Nils Diewald4c221252015-04-21 20:19:25 +000092 this._matchopE = document.createElement('span');
93 this._matchopE.setAttribute('data-type', this.type());
94 this._matchopE.setAttribute('class', 'match');
95 this._matchopE.appendChild(
Nils Diewald0e6992a2015-04-14 20:13:52 +000096 document.createTextNode(this.matchop())
97 );
98
Nils Diewald4c221252015-04-21 20:19:25 +000099 // Change matchop
100 this._matchopE.addEventListener(
101 'click',
102 this._changeMatchop.bind(this)
103 );
104
105 // Added value operator
106 this._valueE = document.createElement('span');
107 this._valueE.setAttribute('data-type', this.type());
108 this._valueE.setAttribute('class', 'value');
109 if (this.value()) {
110 this._valueE.appendChild(document.createTextNode(this.value()));
111 }
112 else {
113 this._valueE.appendChild(document.createTextNode(loc.EMPTY));
114 };
115
116 // Change value
117 this._valueE.addEventListener(
118 'click',
119 this._changeValue.bind(this)
120 );
121
Nils Diewald0e6992a2015-04-14 20:13:52 +0000122
123 // Remove all element children
124 _removeChildren(e);
125
126 // Add spans
Nils Diewald4c221252015-04-21 20:19:25 +0000127 e.appendChild(this._keyE);
128 e.appendChild(this._matchopE);
129 e.appendChild(this._valueE);
Nils Diewald0e6992a2015-04-14 20:13:52 +0000130
131 this.__changed = false;
132 };
133
134 if (this._rewrites !== undefined) {
135 e.appendChild(this._rewrites.element());
136 };
137
138 if (this._parent !== undefined) {
139 // Set operators
140 var op = this.operators(
141 true,
142 true,
143 true
144 );
145
146 // Append new operators
147 e.appendChild(op.element());
148 };
149
150 return e;
151 },
152
Nils Diewald4c221252015-04-21 20:19:25 +0000153
154 /**
155 * Get the associated element
156 */
Nils Diewald0e6992a2015-04-14 20:13:52 +0000157 element : function () {
158 if (this._element !== undefined)
159 return this._element;
160
161 this._element = document.createElement('div');
162 this._element.setAttribute('class', 'doc');
163
164 this.update();
165 return this._element;
166 },
167
Nils Diewald4c221252015-04-21 20:19:25 +0000168 /**
169 * Wrap a new operation around the doc element
170 */
Nils Diewald0e6992a2015-04-14 20:13:52 +0000171 wrap : function (op) {
172 var parent = this.parent();
Nils Diewald7c8ced22015-04-15 19:21:00 +0000173 var group = require('vc/docgroup').create(parent);
Nils Diewald0e6992a2015-04-14 20:13:52 +0000174 group.operation(op);
175 group.append(this);
176 group.append();
177 return parent.replaceOperand(this, group).update();
178 },
179
Nils Diewald4c221252015-04-21 20:19:25 +0000180 /**
181 * Deserialize from json
182 */
Nils Diewald0e6992a2015-04-14 20:13:52 +0000183 fromJson : function (json) {
184 if (json === undefined)
185 return this;
186
187 if (json["@type"] === undefined) {
188 KorAP.log(701, "JSON-LD group has no @type attribute");
189 return;
190 };
191
192 if (json["value"] === undefined ||
193 typeof json["value"] != 'string') {
194 KorAP.log(805, "Value is invalid");
195 return;
196 };
197
198 // There is a defined key
199 if (json["key"] !== undefined &&
200 typeof json["key"] === 'string') {
201
202 // Set key
203 this.key(json["key"]);
204
205 // Set match operation
206 if (json["match"] !== undefined) {
207 if (typeof json["match"] === 'string') {
208 this.matchop(json["match"]);
209 }
210 else {
211 KorAP.log(802, "Match type is not supported by value type");
212 return;
213 };
214 };
215
216 // Key is a string
217 if (json["type"] === undefined ||
218 json["type"] == "type:string") {
219 this.type("string");
220
221 // Check match type
222 if (!KorAP._validStringMatchRE.test(this.matchop())) {
223 KorAP.log(802, "Match type is not supported by value type");
224 return;
225 };
226
227 // Set string value
228 this.value(json["value"]);
229 }
230
231 // Key is a date
232 else if (json["type"] === "type:date") {
233 this.type("date");
234
235 if (json["value"] !== undefined &&
236 KorAP._validDateRE.test(json["value"])) {
237
238 if (!KorAP._validDateMatchRE.test(this.matchop())) {
239 KorAP.log(802, "Match type is not supported by value type");
240 return;
241 };
242
243 // Set value
244 this.value(json["value"]);
245 }
246 else {
247 KorAP.log(806, "Value is not a valid date string");
248 return;
249 };
250 }
251
252 // Key is a regular expression
253 else if (json["type"] === "type:regex") {
254 this.type("regex");
255
256 try {
257
258 // Try to create a regular expression
259 var check = new RegExp(json["value"]);
260
261 if (!_validRegexMatchRE.test(this.matchop())) {
262 KorAP.log(802, "Match type is not supported by value type");
263 return;
264 };
265
266 this.value(json["value"]);
267 }
268
269 catch (e) {
270 KorAP.log(807, "Value is not a valid regular expression");
271 return;
272 };
273 this.type("regex");
274 }
275
276 else {
277 KorAP.log(804, "Unknown value type");
278 return;
279 };
280 };
281
282 if (json["rewrites"] !== undefined) {
283 this._rewrites = rewriteListClass.create(json["rewrites"]);
284 };
285
286 return this;
287 },
288
Nils Diewald4c221252015-04-21 20:19:25 +0000289 /**
290 * Get or set the key
291 */
Nils Diewald0e6992a2015-04-14 20:13:52 +0000292 key : function (value) {
293 if (arguments.length === 1) {
294 this._key = value;
295 this._changed();
296 return this;
297 };
298 return this._key;
299 },
300
Nils Diewald4c221252015-04-21 20:19:25 +0000301 // Click on the key, show me the menu
302 _changeKey : function (e) {
303 var menu = KorAP._vcKeyMenu;
304
305 // Insert menu
306 this._element.insertBefore(
307 menu.element(),
308 this._keyE
309 );
310
311 // Release event
312 var that = this;
313 menu.released(function (key, type) {
314 var doc = that.key(key).type(type);
315
316 // This may not be compatible - then switch to default
317 doc.matchop(doc.matchop());
318 doc.value(doc.value());
319
320 // Update the doc
321 doc.update();
322
323 // hide!
324 this.hide();
325 });
326
327 // TODO: Highlight the old value!
328 menu.show();
329 menu.focus();
330 },
331
332 /**
333 * Get or set the match operator
334 */
Nils Diewald0e6992a2015-04-14 20:13:52 +0000335 matchop : function (match) {
336 if (arguments.length === 1) {
Nils Diewald4c221252015-04-21 20:19:25 +0000337 var m = match.replace(/^match:/, '');
338 if (
Nils Diewald6283d692015-04-23 20:32:53 +0000339 (this._type === undefined)
340 ||
341 (
342 (this._type === 'string' || this._type === 'regex') &&
343 KorAP._validStringMatchRE.test(m)
344 )
345 ||
Nils Diewald4c221252015-04-21 20:19:25 +0000346 (this._type === 'date' && KorAP._validDateMatchRE.test(m))
347 ) {
348 this._matchop = m;
349 }
350 else {
351 this._matchop = "eq";
352 };
353
Nils Diewald0e6992a2015-04-14 20:13:52 +0000354 this._changed();
355 return this;
356 };
357 return this._matchop || "eq";
358 },
359
Nils Diewald4c221252015-04-21 20:19:25 +0000360
361 // Click on the match operator, show me the menu
362 _changeMatchop : function (e) {
363 var menu = KorAP._vcMatchopMenu[this.type()];
364
365 if (menu === undefined) {
366 KorAP.log(0, "Unable to init menu for " + this.type());
367 return;
368 };
369
370 // Insert menu
371 this._element.insertBefore(
372 menu.element(),
373 this._matchopE
374 );
375
376 // Release event
377 var that = this;
378 menu.released(function (mo) {
379 that.matchop(mo).update();
380 this.hide();
381 });
382
383 menu.show();
384 menu.focus();
385 },
386
387
388 /**
389 * Get or set the type
390 */
Nils Diewald0e6992a2015-04-14 20:13:52 +0000391 type : function (type) {
392 if (arguments.length === 1) {
393 this._type = type;
394 this._changed();
395 return this;
396 };
397 return this._type || "string";
398 },
399
Nils Diewald4c221252015-04-21 20:19:25 +0000400
401 /**
402 * Get or set the value
403 */
Nils Diewald0e6992a2015-04-14 20:13:52 +0000404 value : function (value) {
405 if (arguments.length === 1) {
Nils Diewald4c221252015-04-21 20:19:25 +0000406 if (this._type === 'date' && !KorAP._validDateRE.test(value)) {
407 delete this._value;
408 }
409 else {
410 this._value = value;
411 };
Nils Diewald0e6992a2015-04-14 20:13:52 +0000412 this._changed();
413 return this;
414 };
415 return this._value;
416 },
417
Nils Diewald4c221252015-04-21 20:19:25 +0000418
419 // Click on the match operator, show me the menu
420 _changeValue : function (e) {
Nils Diewaldc4c4b832015-05-05 16:00:08 +0000421 var v = this.value();
422 var that = this;
Nils Diewald87507832015-05-01 23:36:41 +0000423
Nils Diewald7148c6f2015-05-04 15:07:53 +0000424 // Show datepicker
Nils Diewald87507832015-05-01 23:36:41 +0000425 if (this.type() === 'date') {
426 var dp = KorAP._vcDatePicker;
Nils Diewald87507832015-05-01 23:36:41 +0000427 if (v !== undefined) {
Nils Diewald7148c6f2015-05-04 15:07:53 +0000428
429 var d = v.split('-', 3);
430 d[0] = parseInt(d[0]);
431 if (d[1]) d[1] = parseInt(d[1]);
432 if (d[2]) d[2] = parseInt(d[2]);
433
434 // Select values
435 dp.select(d[0], d[1], d[2]);
Nils Diewald87507832015-05-01 23:36:41 +0000436 };
437
Nils Diewaldc4c4b832015-05-05 16:00:08 +0000438 // Todo: change this
Nils Diewald87507832015-05-01 23:36:41 +0000439 dp.onclick(function (selected) {
440
441 // There are values selected
442 if (selected['year']) {
Nils Diewald7148c6f2015-05-04 15:07:53 +0000443 var v = '' + selected['year'];
Nils Diewald87507832015-05-01 23:36:41 +0000444 if (selected['month']) {
445 v += '-';
446 v += selected['month'] < 10 ? '0' + selected['month'] : selected['month'];
Nils Diewald7148c6f2015-05-04 15:07:53 +0000447 if (selected['day']) {
Nils Diewald87507832015-05-01 23:36:41 +0000448 v += '-';
449 v += selected['day'] < 10 ? '0' + selected['day'] : selected['day'];
Nils Diewald7148c6f2015-05-04 15:07:53 +0000450 };
Nils Diewald87507832015-05-01 23:36:41 +0000451 };
452 that.value(v);
453 that.update();
454 return;
455 };
456
457 // Remove datepicker
458 that._element.removeChild(
459 dp.element()
460 );
461 });
462
Nils Diewald7148c6f2015-05-04 15:07:53 +0000463 // Get element of the date picker
464 var dpElem = dp.show();
465
Nils Diewald87507832015-05-01 23:36:41 +0000466 this._element.insertBefore(
Nils Diewald7148c6f2015-05-04 15:07:53 +0000467 dpElem,
Nils Diewald87507832015-05-01 23:36:41 +0000468 this._valueE
469 );
Nils Diewald7148c6f2015-05-04 15:07:53 +0000470
471 dpElem.focus();
472 dpElem.addEventListener('blur', function (e) {
473 // Remove datepicker
474 that._element.removeChild(this);
475 });
Nils Diewald87507832015-05-01 23:36:41 +0000476 }
477 else {
Nils Diewaldc4c4b832015-05-05 16:00:08 +0000478 var regex = this.type() === 'regex' ? true : false;
479 var str = stringValClass.create(this.value(), regex);
480 var strElem = str.element();
481
482
483 str.store = function (value, regex) {
484 that.value(value);
485 if (regex === true)
486 that.type('regex');
487 else
488 that.type('string');
489
490 that._element.removeChild(
491 this._element
492 );
493 that.update();
494 };
495
496 // Insert element
497 this._element.insertBefore(
498 strElem,
499 this._valueE
500 );
501
502 str.focus();
Nils Diewald87507832015-05-01 23:36:41 +0000503 };
Nils Diewald4c221252015-04-21 20:19:25 +0000504 },
505
506
Nils Diewald0e6992a2015-04-14 20:13:52 +0000507 rewrites : function () {
508 return this._rewrites;
509 },
510
511 _changed : function () {
512 this.__changed = true;
513
Nils Diewald4347ee92015-05-04 20:32:48 +0000514 if (this._parent) {
515 };
516
Nils Diewald0e6992a2015-04-14 20:13:52 +0000517 if (this._rewrites === undefined)
518 return;
519
520 delete this["_rewrites"];
521
522 if (this._element === undefined)
523 return;
524 this._element.classList.remove("rewritten");
525 },
526
Nils Diewald4c221252015-04-21 20:19:25 +0000527
Nils Diewald0e6992a2015-04-14 20:13:52 +0000528 toJson : function () {
529 if (!this.matchop() || !this.key())
530 return {};
531
532 return {
533 "@type" : "koral:" + this.ldType(),
534 "key" : this.key(),
535 "match" : "match:" + this.matchop(),
536 "value" : this.value() || '',
537 "type" : "type:" + this.type()
538 };
539 },
540
Nils Diewald4c221252015-04-21 20:19:25 +0000541
Nils Diewald0e6992a2015-04-14 20:13:52 +0000542 toQuery : function () {
543 if (!this.matchop() || !this.key())
544 return "";
545
546 // Build doc string based on key
547 var string = this.key() + ' ';
548
549 // Add match operator
550 switch (this.matchop()) {
551 case "ne":
552 string += '!=';
553 break;
554 case "contains":
555 string += '~';
556 break;
557 case "excludes":
558 string += '!~';
559 break;
Akron6a535d42015-08-26 20:16:58 +0200560 case "containsnot":
561 string += '!~';
562 break;
Nils Diewald0e6992a2015-04-14 20:13:52 +0000563 case "geq":
564 string += 'since';
565 break;
566 case "leq":
567 string += 'until';
568 break;
569 default:
570 string += (this.type() == 'date') ? 'in' : '=';
571 break;
572 };
573
574 string += ' ';
575
576 // Add value
577 switch (this.type()) {
578 case "date":
579 return string + this.value();
580 break;
581 case "regex":
582 return string + '/' + this.value() + '/';
583 break;
584 case "string":
Nils Diewald7c8ced22015-04-15 19:21:00 +0000585 return string + '"' + this.value().quote() + '"';
Nils Diewald0e6992a2015-04-14 20:13:52 +0000586 break;
587 };
588
589 return "";
590 }
591 };
592});