blob: f04b4456743f352e4f27a95bcf9a88bf864d4861 [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',
8 'util'
9], function (jsonldClass, rewriteListClass) {
Nils Diewald1fcb2ad2015-04-20 19:19:18 +000010
Nils Diewald4c221252015-04-21 20:19:25 +000011 /*
12 var fieldMenu = menuClass.create([
Nils Diewald7148c6f2015-05-04 15:07:53 +000013 ['Titel', 'title', 'string'],
14 ['Untertitel', 'subTitle', 'string'],
15 ['Veröffentlichungsdatum', 'pubDate', 'date'],
16 ['Autor', 'author', 'string']
Nils Diewald4c221252015-04-21 20:19:25 +000017 ]);
18
19 fieldMenu.limit(5);
20 */
Nils Diewald0e6992a2015-04-14 20:13:52 +000021
22 _validRegexMatchRE = new RegExp("^(?:eq|ne)$");
23
Nils Diewald4c221252015-04-21 20:19:25 +000024 var loc = KorAP.Locale;
25 loc.EMPTY = loc.EMPTY || '⋯';
Nils Diewald1fcb2ad2015-04-20 19:19:18 +000026
Nils Diewald0e6992a2015-04-14 20:13:52 +000027 return {
Nils Diewald4c221252015-04-21 20:19:25 +000028
29 // The JSON-LD type
Nils Diewald0e6992a2015-04-14 20:13:52 +000030 _ldType : "doc",
Nils Diewald4c221252015-04-21 20:19:25 +000031
32 // The object ... maybe not important
Nils Diewald0e6992a2015-04-14 20:13:52 +000033 _obj : function () { return '???'; /*KorAP.Doc*/ },
34
Nils Diewald4c221252015-04-21 20:19:25 +000035 /**
36 * Create a new document criterion
37 * by passing the parent object and a json construct.
38 */
Nils Diewald0e6992a2015-04-14 20:13:52 +000039 create : function (parent, json) {
Nils Diewald4c221252015-04-21 20:19:25 +000040
41 // Create the object, inheriting from Json-LD class
Nils Diewald0e6992a2015-04-14 20:13:52 +000042 var obj = Object(jsonldClass).
43 create().
44 upgradeTo(this).
45 fromJson(json);
Nils Diewald4c221252015-04-21 20:19:25 +000046
47 // Bind the parent
Nils Diewald0e6992a2015-04-14 20:13:52 +000048 if (parent !== undefined)
49 obj._parent = parent;
50
51 obj.__changed = true;
52 return obj;
53 },
54
Nils Diewald4c221252015-04-21 20:19:25 +000055 /**
56 * Update the elements content.
57 */
Nils Diewald0e6992a2015-04-14 20:13:52 +000058 update : function () {
59 if (this._element === undefined)
60 return this.element();
61
62 // Get element
63 var e = this._element;
64
65 // Set ref - TODO: Cleanup!
66 e.refTo = this;
67
68 // Check if there is a change
69 if (this.__changed) {
70
71 // Was rewritten
72 if (this.rewrites() !== undefined) {
73 e.classList.add("rewritten");
74 };
75
76 // Added key
Nils Diewald4c221252015-04-21 20:19:25 +000077 this._keyE = document.createElement('span');
78 this._keyE.setAttribute('class', 'key');
Nils Diewald0e6992a2015-04-14 20:13:52 +000079
80 // Change key
Nils Diewald4c221252015-04-21 20:19:25 +000081 this._keyE.addEventListener('click', this._changeKey.bind(this));
Nils Diewald0e6992a2015-04-14 20:13:52 +000082
Nils Diewald4c221252015-04-21 20:19:25 +000083 if (this.key()) {
84 var k = this.key();
85 if (loc['VC_' + k] !== undefined)
86 k = loc['VC_' + k];
87 this._keyE.appendChild(document.createTextNode(k));
88 };
89
Nils Diewald0e6992a2015-04-14 20:13:52 +000090 // Added match operator
Nils Diewald4c221252015-04-21 20:19:25 +000091 this._matchopE = document.createElement('span');
92 this._matchopE.setAttribute('data-type', this.type());
93 this._matchopE.setAttribute('class', 'match');
94 this._matchopE.appendChild(
Nils Diewald0e6992a2015-04-14 20:13:52 +000095 document.createTextNode(this.matchop())
96 );
97
Nils Diewald4c221252015-04-21 20:19:25 +000098 // Change matchop
99 this._matchopE.addEventListener(
100 'click',
101 this._changeMatchop.bind(this)
102 );
103
104 // Added value operator
105 this._valueE = document.createElement('span');
106 this._valueE.setAttribute('data-type', this.type());
107 this._valueE.setAttribute('class', 'value');
108 if (this.value()) {
109 this._valueE.appendChild(document.createTextNode(this.value()));
110 }
111 else {
112 this._valueE.appendChild(document.createTextNode(loc.EMPTY));
113 };
114
115 // Change value
116 this._valueE.addEventListener(
117 'click',
118 this._changeValue.bind(this)
119 );
120
Nils Diewald0e6992a2015-04-14 20:13:52 +0000121
122 // Remove all element children
123 _removeChildren(e);
124
125 // Add spans
Nils Diewald4c221252015-04-21 20:19:25 +0000126 e.appendChild(this._keyE);
127 e.appendChild(this._matchopE);
128 e.appendChild(this._valueE);
Nils Diewald0e6992a2015-04-14 20:13:52 +0000129
130 this.__changed = false;
131 };
132
133 if (this._rewrites !== undefined) {
134 e.appendChild(this._rewrites.element());
135 };
136
137 if (this._parent !== undefined) {
138 // Set operators
139 var op = this.operators(
140 true,
141 true,
142 true
143 );
144
145 // Append new operators
146 e.appendChild(op.element());
147 };
148
149 return e;
150 },
151
Nils Diewald4c221252015-04-21 20:19:25 +0000152
153 /**
154 * Get the associated element
155 */
Nils Diewald0e6992a2015-04-14 20:13:52 +0000156 element : function () {
157 if (this._element !== undefined)
158 return this._element;
159
160 this._element = document.createElement('div');
161 this._element.setAttribute('class', 'doc');
162
163 this.update();
164 return this._element;
165 },
166
Nils Diewald4c221252015-04-21 20:19:25 +0000167 /**
168 * Wrap a new operation around the doc element
169 */
Nils Diewald0e6992a2015-04-14 20:13:52 +0000170 wrap : function (op) {
171 var parent = this.parent();
Nils Diewald7c8ced22015-04-15 19:21:00 +0000172 var group = require('vc/docgroup').create(parent);
Nils Diewald0e6992a2015-04-14 20:13:52 +0000173 group.operation(op);
174 group.append(this);
175 group.append();
176 return parent.replaceOperand(this, group).update();
177 },
178
Nils Diewald4c221252015-04-21 20:19:25 +0000179 /**
180 * Deserialize from json
181 */
Nils Diewald0e6992a2015-04-14 20:13:52 +0000182 fromJson : function (json) {
183 if (json === undefined)
184 return this;
185
186 if (json["@type"] === undefined) {
187 KorAP.log(701, "JSON-LD group has no @type attribute");
188 return;
189 };
190
191 if (json["value"] === undefined ||
192 typeof json["value"] != 'string') {
193 KorAP.log(805, "Value is invalid");
194 return;
195 };
196
197 // There is a defined key
198 if (json["key"] !== undefined &&
199 typeof json["key"] === 'string') {
200
201 // Set key
202 this.key(json["key"]);
203
204 // Set match operation
205 if (json["match"] !== undefined) {
206 if (typeof json["match"] === 'string') {
207 this.matchop(json["match"]);
208 }
209 else {
210 KorAP.log(802, "Match type is not supported by value type");
211 return;
212 };
213 };
214
215 // Key is a string
216 if (json["type"] === undefined ||
217 json["type"] == "type:string") {
218 this.type("string");
219
220 // Check match type
221 if (!KorAP._validStringMatchRE.test(this.matchop())) {
222 KorAP.log(802, "Match type is not supported by value type");
223 return;
224 };
225
226 // Set string value
227 this.value(json["value"]);
228 }
229
230 // Key is a date
231 else if (json["type"] === "type:date") {
232 this.type("date");
233
234 if (json["value"] !== undefined &&
235 KorAP._validDateRE.test(json["value"])) {
236
237 if (!KorAP._validDateMatchRE.test(this.matchop())) {
238 KorAP.log(802, "Match type is not supported by value type");
239 return;
240 };
241
242 // Set value
243 this.value(json["value"]);
244 }
245 else {
246 KorAP.log(806, "Value is not a valid date string");
247 return;
248 };
249 }
250
251 // Key is a regular expression
252 else if (json["type"] === "type:regex") {
253 this.type("regex");
254
255 try {
256
257 // Try to create a regular expression
258 var check = new RegExp(json["value"]);
259
260 if (!_validRegexMatchRE.test(this.matchop())) {
261 KorAP.log(802, "Match type is not supported by value type");
262 return;
263 };
264
265 this.value(json["value"]);
266 }
267
268 catch (e) {
269 KorAP.log(807, "Value is not a valid regular expression");
270 return;
271 };
272 this.type("regex");
273 }
274
275 else {
276 KorAP.log(804, "Unknown value type");
277 return;
278 };
279 };
280
281 if (json["rewrites"] !== undefined) {
282 this._rewrites = rewriteListClass.create(json["rewrites"]);
283 };
284
285 return this;
286 },
287
Nils Diewald4c221252015-04-21 20:19:25 +0000288 /**
289 * Get or set the key
290 */
Nils Diewald0e6992a2015-04-14 20:13:52 +0000291 key : function (value) {
292 if (arguments.length === 1) {
293 this._key = value;
294 this._changed();
295 return this;
296 };
297 return this._key;
298 },
299
Nils Diewald4c221252015-04-21 20:19:25 +0000300 // Click on the key, show me the menu
301 _changeKey : function (e) {
302 var menu = KorAP._vcKeyMenu;
303
304 // Insert menu
305 this._element.insertBefore(
306 menu.element(),
307 this._keyE
308 );
309
310 // Release event
311 var that = this;
312 menu.released(function (key, type) {
313 var doc = that.key(key).type(type);
314
315 // This may not be compatible - then switch to default
316 doc.matchop(doc.matchop());
317 doc.value(doc.value());
318
319 // Update the doc
320 doc.update();
321
322 // hide!
323 this.hide();
324 });
325
326 // TODO: Highlight the old value!
327 menu.show();
328 menu.focus();
329 },
330
331 /**
332 * Get or set the match operator
333 */
Nils Diewald0e6992a2015-04-14 20:13:52 +0000334 matchop : function (match) {
335 if (arguments.length === 1) {
Nils Diewald4c221252015-04-21 20:19:25 +0000336 var m = match.replace(/^match:/, '');
337 if (
Nils Diewald6283d692015-04-23 20:32:53 +0000338 (this._type === undefined)
339 ||
340 (
341 (this._type === 'string' || this._type === 'regex') &&
342 KorAP._validStringMatchRE.test(m)
343 )
344 ||
Nils Diewald4c221252015-04-21 20:19:25 +0000345 (this._type === 'date' && KorAP._validDateMatchRE.test(m))
346 ) {
347 this._matchop = m;
348 }
349 else {
350 this._matchop = "eq";
351 };
352
Nils Diewald0e6992a2015-04-14 20:13:52 +0000353 this._changed();
354 return this;
355 };
356 return this._matchop || "eq";
357 },
358
Nils Diewald4c221252015-04-21 20:19:25 +0000359
360 // Click on the match operator, show me the menu
361 _changeMatchop : function (e) {
362 var menu = KorAP._vcMatchopMenu[this.type()];
363
364 if (menu === undefined) {
365 KorAP.log(0, "Unable to init menu for " + this.type());
366 return;
367 };
368
369 // Insert menu
370 this._element.insertBefore(
371 menu.element(),
372 this._matchopE
373 );
374
375 // Release event
376 var that = this;
377 menu.released(function (mo) {
378 that.matchop(mo).update();
379 this.hide();
380 });
381
382 menu.show();
383 menu.focus();
384 },
385
386
387 /**
388 * Get or set the type
389 */
Nils Diewald0e6992a2015-04-14 20:13:52 +0000390 type : function (type) {
391 if (arguments.length === 1) {
392 this._type = type;
393 this._changed();
394 return this;
395 };
396 return this._type || "string";
397 },
398
Nils Diewald4c221252015-04-21 20:19:25 +0000399
400 /**
401 * Get or set the value
402 */
Nils Diewald0e6992a2015-04-14 20:13:52 +0000403 value : function (value) {
404 if (arguments.length === 1) {
Nils Diewald4c221252015-04-21 20:19:25 +0000405 if (this._type === 'date' && !KorAP._validDateRE.test(value)) {
406 delete this._value;
407 }
408 else {
409 this._value = value;
410 };
Nils Diewald0e6992a2015-04-14 20:13:52 +0000411 this._changed();
412 return this;
413 };
414 return this._value;
415 },
416
Nils Diewald4c221252015-04-21 20:19:25 +0000417
418 // Click on the match operator, show me the menu
419 _changeValue : function (e) {
Nils Diewald87507832015-05-01 23:36:41 +0000420
Nils Diewald7148c6f2015-05-04 15:07:53 +0000421 // Show datepicker
Nils Diewald87507832015-05-01 23:36:41 +0000422 if (this.type() === 'date') {
423 var dp = KorAP._vcDatePicker;
424
425 var v = this.value();
426 if (v !== undefined) {
Nils Diewald7148c6f2015-05-04 15:07:53 +0000427
428 var d = v.split('-', 3);
429 d[0] = parseInt(d[0]);
430 if (d[1]) d[1] = parseInt(d[1]);
431 if (d[2]) d[2] = parseInt(d[2]);
432
433 // Select values
434 dp.select(d[0], d[1], d[2]);
Nils Diewald87507832015-05-01 23:36:41 +0000435 };
436
437 var that = this;
Nils Diewald7148c6f2015-05-04 15:07:53 +0000438
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 Diewald7148c6f2015-05-04 15:07:53 +0000478 // TODO: Just kidding - this is temporary!
Nils Diewald87507832015-05-01 23:36:41 +0000479 this.value(window.prompt('Enter new value'));
480 this.update();
481 };
Nils Diewald4c221252015-04-21 20:19:25 +0000482 },
483
484
Nils Diewald0e6992a2015-04-14 20:13:52 +0000485 rewrites : function () {
486 return this._rewrites;
487 },
488
489 _changed : function () {
490 this.__changed = true;
491
492 if (this._rewrites === undefined)
493 return;
494
495 delete this["_rewrites"];
496
497 if (this._element === undefined)
498 return;
499 this._element.classList.remove("rewritten");
500 },
501
Nils Diewald4c221252015-04-21 20:19:25 +0000502
Nils Diewald0e6992a2015-04-14 20:13:52 +0000503 toJson : function () {
504 if (!this.matchop() || !this.key())
505 return {};
506
507 return {
508 "@type" : "koral:" + this.ldType(),
509 "key" : this.key(),
510 "match" : "match:" + this.matchop(),
511 "value" : this.value() || '',
512 "type" : "type:" + this.type()
513 };
514 },
515
Nils Diewald4c221252015-04-21 20:19:25 +0000516
Nils Diewald0e6992a2015-04-14 20:13:52 +0000517 toQuery : function () {
518 if (!this.matchop() || !this.key())
519 return "";
520
521 // Build doc string based on key
522 var string = this.key() + ' ';
523
524 // Add match operator
525 switch (this.matchop()) {
526 case "ne":
527 string += '!=';
528 break;
529 case "contains":
530 string += '~';
531 break;
532 case "excludes":
533 string += '!~';
534 break;
535 case "geq":
536 string += 'since';
537 break;
538 case "leq":
539 string += 'until';
540 break;
541 default:
542 string += (this.type() == 'date') ? 'in' : '=';
543 break;
544 };
545
546 string += ' ';
547
548 // Add value
549 switch (this.type()) {
550 case "date":
551 return string + this.value();
552 break;
553 case "regex":
554 return string + '/' + this.value() + '/';
555 break;
556 case "string":
Nils Diewald7c8ced22015-04-15 19:21:00 +0000557 return string + '"' + this.value().quote() + '"';
Nils Diewald0e6992a2015-04-14 20:13:52 +0000558 break;
559 };
560
561 return "";
562 }
563 };
564});