blob: 23cec0770eadf49874587cafb9ac9076ba1b1dcf [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 Diewald87507832015-05-01 23:36:41 +0000421
Nils Diewald7148c6f2015-05-04 15:07:53 +0000422 // Show datepicker
Nils Diewald87507832015-05-01 23:36:41 +0000423 if (this.type() === 'date') {
424 var dp = KorAP._vcDatePicker;
425
426 var v = this.value();
427 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
438 var that = this;
Nils Diewald7148c6f2015-05-04 15:07:53 +0000439
Nils Diewald87507832015-05-01 23:36:41 +0000440 dp.onclick(function (selected) {
441
442 // There are values selected
443 if (selected['year']) {
Nils Diewald7148c6f2015-05-04 15:07:53 +0000444 var v = '' + selected['year'];
Nils Diewald87507832015-05-01 23:36:41 +0000445 if (selected['month']) {
446 v += '-';
447 v += selected['month'] < 10 ? '0' + selected['month'] : selected['month'];
Nils Diewald7148c6f2015-05-04 15:07:53 +0000448 if (selected['day']) {
Nils Diewald87507832015-05-01 23:36:41 +0000449 v += '-';
450 v += selected['day'] < 10 ? '0' + selected['day'] : selected['day'];
Nils Diewald7148c6f2015-05-04 15:07:53 +0000451 };
Nils Diewald87507832015-05-01 23:36:41 +0000452 };
453 that.value(v);
454 that.update();
455 return;
456 };
457
458 // Remove datepicker
459 that._element.removeChild(
460 dp.element()
461 );
462 });
463
Nils Diewald7148c6f2015-05-04 15:07:53 +0000464 // Get element of the date picker
465 var dpElem = dp.show();
466
Nils Diewald87507832015-05-01 23:36:41 +0000467 this._element.insertBefore(
Nils Diewald7148c6f2015-05-04 15:07:53 +0000468 dpElem,
Nils Diewald87507832015-05-01 23:36:41 +0000469 this._valueE
470 );
Nils Diewald7148c6f2015-05-04 15:07:53 +0000471
472 dpElem.focus();
473 dpElem.addEventListener('blur', function (e) {
474 // Remove datepicker
475 that._element.removeChild(this);
476 });
Nils Diewald87507832015-05-01 23:36:41 +0000477 }
478 else {
Nils Diewald7148c6f2015-05-04 15:07:53 +0000479 // TODO: Just kidding - this is temporary!
Nils Diewald87507832015-05-01 23:36:41 +0000480 this.value(window.prompt('Enter new value'));
481 this.update();
482 };
Nils Diewald4c221252015-04-21 20:19:25 +0000483 },
484
485
Nils Diewald0e6992a2015-04-14 20:13:52 +0000486 rewrites : function () {
487 return this._rewrites;
488 },
489
490 _changed : function () {
491 this.__changed = true;
492
Nils Diewald4347ee92015-05-04 20:32:48 +0000493 if (this._parent) {
494 };
495
Nils Diewald0e6992a2015-04-14 20:13:52 +0000496 if (this._rewrites === undefined)
497 return;
498
499 delete this["_rewrites"];
500
501 if (this._element === undefined)
502 return;
503 this._element.classList.remove("rewritten");
504 },
505
Nils Diewald4c221252015-04-21 20:19:25 +0000506
Nils Diewald0e6992a2015-04-14 20:13:52 +0000507 toJson : function () {
508 if (!this.matchop() || !this.key())
509 return {};
510
511 return {
512 "@type" : "koral:" + this.ldType(),
513 "key" : this.key(),
514 "match" : "match:" + this.matchop(),
515 "value" : this.value() || '',
516 "type" : "type:" + this.type()
517 };
518 },
519
Nils Diewald4c221252015-04-21 20:19:25 +0000520
Nils Diewald0e6992a2015-04-14 20:13:52 +0000521 toQuery : function () {
522 if (!this.matchop() || !this.key())
523 return "";
524
525 // Build doc string based on key
526 var string = this.key() + ' ';
527
528 // Add match operator
529 switch (this.matchop()) {
530 case "ne":
531 string += '!=';
532 break;
533 case "contains":
534 string += '~';
535 break;
536 case "excludes":
537 string += '!~';
538 break;
539 case "geq":
540 string += 'since';
541 break;
542 case "leq":
543 string += 'until';
544 break;
545 default:
546 string += (this.type() == 'date') ? 'in' : '=';
547 break;
548 };
549
550 string += ' ';
551
552 // Add value
553 switch (this.type()) {
554 case "date":
555 return string + this.value();
556 break;
557 case "regex":
558 return string + '/' + this.value() + '/';
559 break;
560 case "string":
Nils Diewald7c8ced22015-04-15 19:21:00 +0000561 return string + '"' + this.value().quote() + '"';
Nils Diewald0e6992a2015-04-14 20:13:52 +0000562 break;
563 };
564
565 return "";
566 }
567 };
568});