blob: 10a49a80033593f0f78c98a6bdd4688e1883f295 [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([
13 ['Titel', 'title', 'string'],
14 ['Untertitel', 'subTitle', 'string'],
15 ['Veröffentlichungsdatum', 'pubDate', 'date'],
16 ['Autor', 'author', 'string']
17 ]);
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 (
338 (
339 (this._type === 'string' || this._type === 'regex') &&
340 KorAP._validStringMatchRE.test(m)
341 ) ||
342 (this._type === 'date' && KorAP._validDateMatchRE.test(m))
343 ) {
344 this._matchop = m;
345 }
346 else {
347 this._matchop = "eq";
348 };
349
Nils Diewald0e6992a2015-04-14 20:13:52 +0000350 this._changed();
351 return this;
352 };
353 return this._matchop || "eq";
354 },
355
Nils Diewald4c221252015-04-21 20:19:25 +0000356
357 // Click on the match operator, show me the menu
358 _changeMatchop : function (e) {
359 var menu = KorAP._vcMatchopMenu[this.type()];
360
361 if (menu === undefined) {
362 KorAP.log(0, "Unable to init menu for " + this.type());
363 return;
364 };
365
366 // Insert menu
367 this._element.insertBefore(
368 menu.element(),
369 this._matchopE
370 );
371
372 // Release event
373 var that = this;
374 menu.released(function (mo) {
375 that.matchop(mo).update();
376 this.hide();
377 });
378
379 menu.show();
380 menu.focus();
381 },
382
383
384 /**
385 * Get or set the type
386 */
Nils Diewald0e6992a2015-04-14 20:13:52 +0000387 type : function (type) {
388 if (arguments.length === 1) {
389 this._type = type;
390 this._changed();
391 return this;
392 };
393 return this._type || "string";
394 },
395
Nils Diewald4c221252015-04-21 20:19:25 +0000396
397 /**
398 * Get or set the value
399 */
Nils Diewald0e6992a2015-04-14 20:13:52 +0000400 value : function (value) {
401 if (arguments.length === 1) {
Nils Diewald4c221252015-04-21 20:19:25 +0000402 if (this._type === 'date' && !KorAP._validDateRE.test(value)) {
403 delete this._value;
404 }
405 else {
406 this._value = value;
407 };
Nils Diewald0e6992a2015-04-14 20:13:52 +0000408 this._changed();
409 return this;
410 };
411 return this._value;
412 },
413
Nils Diewald4c221252015-04-21 20:19:25 +0000414
415 // Click on the match operator, show me the menu
416 _changeValue : function (e) {
417 // TODO: Just kidding - this is temporary!
418 this.value(window.prompt('Enter new value'));
419 this.update();
420 },
421
422
Nils Diewald0e6992a2015-04-14 20:13:52 +0000423 rewrites : function () {
424 return this._rewrites;
425 },
426
427 _changed : function () {
428 this.__changed = true;
429
430 if (this._rewrites === undefined)
431 return;
432
433 delete this["_rewrites"];
434
435 if (this._element === undefined)
436 return;
437 this._element.classList.remove("rewritten");
438 },
439
Nils Diewald4c221252015-04-21 20:19:25 +0000440
Nils Diewald0e6992a2015-04-14 20:13:52 +0000441 toJson : function () {
442 if (!this.matchop() || !this.key())
443 return {};
444
445 return {
446 "@type" : "koral:" + this.ldType(),
447 "key" : this.key(),
448 "match" : "match:" + this.matchop(),
449 "value" : this.value() || '',
450 "type" : "type:" + this.type()
451 };
452 },
453
Nils Diewald4c221252015-04-21 20:19:25 +0000454
Nils Diewald0e6992a2015-04-14 20:13:52 +0000455 toQuery : function () {
456 if (!this.matchop() || !this.key())
457 return "";
458
459 // Build doc string based on key
460 var string = this.key() + ' ';
461
462 // Add match operator
463 switch (this.matchop()) {
464 case "ne":
465 string += '!=';
466 break;
467 case "contains":
468 string += '~';
469 break;
470 case "excludes":
471 string += '!~';
472 break;
473 case "geq":
474 string += 'since';
475 break;
476 case "leq":
477 string += 'until';
478 break;
479 default:
480 string += (this.type() == 'date') ? 'in' : '=';
481 break;
482 };
483
484 string += ' ';
485
486 // Add value
487 switch (this.type()) {
488 case "date":
489 return string + this.value();
490 break;
491 case "regex":
492 return string + '/' + this.value() + '/';
493 break;
494 case "string":
Nils Diewald7c8ced22015-04-15 19:21:00 +0000495 return string + '"' + this.value().quote() + '"';
Nils Diewald0e6992a2015-04-14 20:13:52 +0000496 break;
497 };
498
499 return "";
500 }
501 };
502});