blob: f22f3b42fa2ea8b1e6c0b62e7bc1d383d3b7cedd [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;
Akron56ea7e32016-04-20 12:25:52 +0200427 dp.fromString(v)
Nils Diewald87507832015-05-01 23:36:41 +0000428
Nils Diewaldc4c4b832015-05-05 16:00:08 +0000429 // Todo: change this
Nils Diewald87507832015-05-01 23:36:41 +0000430 dp.onclick(function (selected) {
431
432 // There are values selected
433 if (selected['year']) {
Akron56ea7e32016-04-20 12:25:52 +0200434 that.value(this.toString());
Nils Diewald87507832015-05-01 23:36:41 +0000435 that.update();
436 return;
437 };
438
439 // Remove datepicker
440 that._element.removeChild(
441 dp.element()
442 );
443 });
444
Nils Diewald7148c6f2015-05-04 15:07:53 +0000445 // Get element of the date picker
446 var dpElem = dp.show();
447
Nils Diewald87507832015-05-01 23:36:41 +0000448 this._element.insertBefore(
Nils Diewald7148c6f2015-05-04 15:07:53 +0000449 dpElem,
Nils Diewald87507832015-05-01 23:36:41 +0000450 this._valueE
451 );
Nils Diewald7148c6f2015-05-04 15:07:53 +0000452
453 dpElem.focus();
Akronc59f7322016-04-20 13:46:05 +0200454 /*
Nils Diewald7148c6f2015-05-04 15:07:53 +0000455 dpElem.addEventListener('blur', function (e) {
Akronc59f7322016-04-20 13:46:05 +0200456 e.halt();
457
Nils Diewald7148c6f2015-05-04 15:07:53 +0000458 // Remove datepicker
Akronc59f7322016-04-20 13:46:05 +0200459 // TODO: If focus is not set to string input
Nils Diewald7148c6f2015-05-04 15:07:53 +0000460 that._element.removeChild(this);
461 });
Akronc59f7322016-04-20 13:46:05 +0200462 */
Nils Diewald87507832015-05-01 23:36:41 +0000463 }
464 else {
Nils Diewaldc4c4b832015-05-05 16:00:08 +0000465 var regex = this.type() === 'regex' ? true : false;
466 var str = stringValClass.create(this.value(), regex);
467 var strElem = str.element();
468
469
470 str.store = function (value, regex) {
471 that.value(value);
472 if (regex === true)
473 that.type('regex');
474 else
475 that.type('string');
476
477 that._element.removeChild(
478 this._element
479 );
480 that.update();
481 };
482
483 // Insert element
484 this._element.insertBefore(
485 strElem,
486 this._valueE
487 );
488
489 str.focus();
Nils Diewald87507832015-05-01 23:36:41 +0000490 };
Nils Diewald4c221252015-04-21 20:19:25 +0000491 },
492
493
Nils Diewald0e6992a2015-04-14 20:13:52 +0000494 rewrites : function () {
495 return this._rewrites;
496 },
497
498 _changed : function () {
499 this.__changed = true;
500
Nils Diewald4347ee92015-05-04 20:32:48 +0000501 if (this._parent) {
502 };
503
Nils Diewald0e6992a2015-04-14 20:13:52 +0000504 if (this._rewrites === undefined)
505 return;
506
507 delete this["_rewrites"];
508
509 if (this._element === undefined)
510 return;
511 this._element.classList.remove("rewritten");
512 },
513
Nils Diewald4c221252015-04-21 20:19:25 +0000514
Nils Diewald0e6992a2015-04-14 20:13:52 +0000515 toJson : function () {
516 if (!this.matchop() || !this.key())
517 return {};
518
519 return {
520 "@type" : "koral:" + this.ldType(),
521 "key" : this.key(),
522 "match" : "match:" + this.matchop(),
523 "value" : this.value() || '',
524 "type" : "type:" + this.type()
525 };
526 },
527
Nils Diewald4c221252015-04-21 20:19:25 +0000528
Nils Diewald0e6992a2015-04-14 20:13:52 +0000529 toQuery : function () {
530 if (!this.matchop() || !this.key())
531 return "";
532
533 // Build doc string based on key
534 var string = this.key() + ' ';
535
536 // Add match operator
537 switch (this.matchop()) {
538 case "ne":
539 string += '!=';
540 break;
541 case "contains":
542 string += '~';
543 break;
544 case "excludes":
545 string += '!~';
546 break;
Akron6a535d42015-08-26 20:16:58 +0200547 case "containsnot":
548 string += '!~';
549 break;
Nils Diewald0e6992a2015-04-14 20:13:52 +0000550 case "geq":
551 string += 'since';
552 break;
553 case "leq":
554 string += 'until';
555 break;
556 default:
557 string += (this.type() == 'date') ? 'in' : '=';
558 break;
559 };
560
561 string += ' ';
562
563 // Add value
564 switch (this.type()) {
565 case "date":
566 return string + this.value();
567 break;
568 case "regex":
569 return string + '/' + this.value() + '/';
570 break;
571 case "string":
Nils Diewald7c8ced22015-04-15 19:21:00 +0000572 return string + '"' + this.value().quote() + '"';
Nils Diewald0e6992a2015-04-14 20:13:52 +0000573 break;
574 };
575
576 return "";
577 }
578 };
579});