blob: 9aef8d59ea4e8395d25b85d7a05f1f2baba82484 [file] [log] [blame]
Nils Diewald86dad5b2015-01-28 15:09:07 +00001/**
2 * Create virtual collections with a visual user interface.
Nils Diewald4c221252015-04-21 20:19:25 +00003 * This resembles the collection type objects of a KoralQuery
4 * "collection" object.
5 *
6 * KoralQuery v0.3 is expected.
Nils Diewald86dad5b2015-01-28 15:09:07 +00007 *
8 * @author Nils Diewald
9 */
Nils Diewald2fe12e12015-03-06 16:47:06 +000010/*
Nils Diewald1fcb2ad2015-04-20 19:19:18 +000011 * This replaces a previous version written by Mengfei Zhou
Nils Diewald2fe12e12015-03-06 16:47:06 +000012 */
Nils Diewald2fe12e12015-03-06 16:47:06 +000013
Nils Diewaldd0770492014-12-19 03:55:00 +000014/*
Nils Diewald86dad5b2015-01-28 15:09:07 +000015 TODO: Disable "and" or "or" in case it's followed
16 by an unspecified document
Akron0a6768f2016-07-13 18:00:43 +020017 TODO: Add "and"-method to root to add further constraints based on match-
18 input (like clicking on a pubDate timestamp in a match)
Nils Diewald1fcb2ad2015-04-20 19:19:18 +000019 TODO: Implement "persistence"-Option,
Nils Diewald6e43ffd2015-03-25 18:55:39 +000020 injecting the current creation date stamp
Nils Diewald709f52f2015-05-21 18:32:58 +000021 TODO: Implement vec-Type for document-id vectors
22 like docID in [1,2,3,4 ...]
Nils Diewald86dad5b2015-01-28 15:09:07 +000023
Nils Diewaldd599d542015-01-08 20:41:34 +000024 Error codes:
Nils Diewaldd0770492014-12-19 03:55:00 +000025 701: "JSON-LD group has no @type attribute"
26 704: "Operation needs operand list"
Nils Diewald3a2d8022014-12-16 02:45:41 +000027 802: "Match type is not supported by value type"
28 804: "Unknown value type"
29 805: "Value is invalid"
30 806: "Value is not a valid date string"
31 807: "Value is not a valid regular expression"
Nils Diewald3a2d8022014-12-16 02:45:41 +000032 810: "Unknown document group operation" (like 711)
33 811: "Document group expects operation" (like 703)
34 812: "Operand not supported in document group" (like 744)
Nils Diewaldd0770492014-12-19 03:55:00 +000035 813: "Collection type is not supported" (like 713)
Nils Diewald86dad5b2015-01-28 15:09:07 +000036 814: "Unknown rewrite operation"
37 815: "Rewrite expects source"
Nils Diewald1fcb2ad2015-04-20 19:19:18 +000038
39 Localization strings:
40 KorAP.Locale = {
41 EMPTY : '...',
42 AND : 'and',
43 OR : 'or',
44 DELETE : 'x'
45 }
Nils Diewald4c221252015-04-21 20:19:25 +000046 and various field names with the prefix 'VC_'
Nils Diewaldd0770492014-12-19 03:55:00 +000047*/
48
Nils Diewald0e6992a2015-04-14 20:13:52 +000049define([
50 'vc/unspecified',
51 'vc/doc',
52 'vc/docgroup',
Nils Diewald1fcb2ad2015-04-20 19:19:18 +000053 'vc/menu',
Nils Diewald87507832015-05-01 23:36:41 +000054 'datepicker',
Nils Diewald0e6992a2015-04-14 20:13:52 +000055 'util'
Nils Diewald87507832015-05-01 23:36:41 +000056], function (unspecDocClass, docClass, docGroupClass, menuClass, dpClass) {
Nils Diewald3a2d8022014-12-16 02:45:41 +000057 "use strict";
58
Akron31d89942018-04-06 16:44:51 +020059 KorAP._validUnspecMatchRE = new RegExp("^(?:eq|ne|contains(?:not)?|excludes)$");
60 KorAP._validStringMatchRE = new RegExp("^(?:eq|ne)$");
61 KorAP._validTextMatchRE = KorAP._validUnspecMatchRE;
62 KorAP._validTextOnlyMatchRE = new RegExp("^(?:contains(?:not)?|excludes)$");
Nils Diewald359a72c2015-04-20 17:40:29 +000063 KorAP._overrideStyles = false;
Akron31d89942018-04-06 16:44:51 +020064 // KorAP._validDateMatchRE is defined in datepicker.js!
Nils Diewald3a2d8022014-12-16 02:45:41 +000065
Akron0b489ad2018-02-02 16:49:32 +010066 const loc = KorAP.Locale;
Nils Diewaldd599d542015-01-08 20:41:34 +000067
Nils Diewald1fcb2ad2015-04-20 19:19:18 +000068 KorAP._vcKeyMenu = undefined;
Nils Diewald87507832015-05-01 23:36:41 +000069 KorAP._vcDatePicker = dpClass.create();
Nils Diewald1fcb2ad2015-04-20 19:19:18 +000070
Akron712733a2018-04-05 18:17:47 +020071 // Create match menus ....
72 KorAP._vcMatchopMenu = {
73 'string' : menuClass.create([
74 ['eq', null],
75 ['ne', null]
76 ]),
77 'text' : menuClass.create([
78 ['eq', null], // Requires exact match
79 ['ne', null],
80 ['contains', null], // Requires token sequence match
81 ['containsnot', null]
82 ]),
83 'date' : menuClass.create([
84 ['eq', null],
Akron31d89942018-04-06 16:44:51 +020085 ['ne', null],
Akron712733a2018-04-05 18:17:47 +020086 ['geq', null],
87 ['leq', null]
88 ]),
89 'regex' : menuClass.create([
90 ['eq', null],
91 ['ne', null]
92 ])
93 };
94
Nils Diewaldd599d542015-01-08 20:41:34 +000095 /**
96 * Virtual Collection
97 */
Nils Diewald0e6992a2015-04-14 20:13:52 +000098 return {
Nils Diewald1fcb2ad2015-04-20 19:19:18 +000099
100 /**
101 * The JSON-LD type of the virtual collection
102 */
Nils Diewaldf219eb82015-01-07 20:15:42 +0000103 ldType : function () {
104 return null;
105 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000106
Nils Diewald1fcb2ad2015-04-20 19:19:18 +0000107 // Initialize virtual collection
108 _init : function (keyList) {
109
110 // Inject localized css styles
Nils Diewald359a72c2015-04-20 17:40:29 +0000111 if (!KorAP._overrideStyles) {
Akrone4961b12017-05-10 21:04:46 +0200112 var sheet = KorAP.newStyleSheet();
Nils Diewald359a72c2015-04-20 17:40:29 +0000113
Akrone4961b12017-05-10 21:04:46 +0200114 // Add css rule for OR operations
115 sheet.insertRule(
116 '.vc .docGroup[data-operation=or] > .doc::before,' +
117 '.vc .docGroup[data-operation=or] > .docGroup::before ' +
118 '{ content: "' + loc.OR + '" }',
119 0
120 );
Nils Diewald359a72c2015-04-20 17:40:29 +0000121
Akrone4961b12017-05-10 21:04:46 +0200122 // Add css rule for AND operations
123 sheet.insertRule(
124 '.vc .docGroup[data-operation=and] > .doc::before,' +
125 '.vc .docGroup[data-operation=and] > .docGroup::before ' +
126 '{ content: "' + loc.AND + '" }',
127 1
128 );
Nils Diewald359a72c2015-04-20 17:40:29 +0000129
Akrone4961b12017-05-10 21:04:46 +0200130 KorAP._overrideStyles = true;
Nils Diewald359a72c2015-04-20 17:40:29 +0000131 };
132
Akron712733a2018-04-05 18:17:47 +0200133 // Create key menu
134 KorAP._vcKeyMenu = menuClass.create(keyList);
135 KorAP._vcKeyMenu.limit(6);
136
Nils Diewald359a72c2015-04-20 17:40:29 +0000137 return this;
138 },
139
Nils Diewald1fcb2ad2015-04-20 19:19:18 +0000140 /**
141 * Create a new virtual collection.
142 */
143 create : function (keyList) {
Nils Diewald6283d692015-04-23 20:32:53 +0000144 var obj = Object.create(this)._init(keyList);
145 obj._root = unspecDocClass.create(obj);
146 return obj;
Nils Diewald4019bd22015-01-08 19:57:50 +0000147 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000148
Nils Diewald7148c6f2015-05-04 15:07:53 +0000149
Nils Diewald1fcb2ad2015-04-20 19:19:18 +0000150 /**
151 * Create and render a new virtual collection
152 * based on a KoralQuery collection document
153 */
Nils Diewald6283d692015-04-23 20:32:53 +0000154 fromJson : function (json) {
Nils Diewaldd0770492014-12-19 03:55:00 +0000155 if (json !== undefined) {
Akrone4961b12017-05-10 21:04:46 +0200156 // Parse root document
157 if (json['@type'] == 'koral:doc') {
158 this._root = docClass.create(this, json);
159 }
160 // parse root group
161 else if (json['@type'] == 'koral:docGroup') {
162 this._root = docGroupClass.create(this, json);
163 }
164 // Unknown collection type
165 else {
166 KorAP.log(813, "Collection type is not supported");
167 return;
168 };
Nils Diewaldd0770492014-12-19 03:55:00 +0000169 }
170
171 else {
Akrone4961b12017-05-10 21:04:46 +0200172 // Add unspecified object
173 this._root = unspecDocClass.create(this);
Nils Diewaldd0770492014-12-19 03:55:00 +0000174 };
175
Nils Diewald8e7182e2015-01-08 15:02:07 +0000176 // Init element and update
Nils Diewald6283d692015-04-23 20:32:53 +0000177 this.update();
Nils Diewaldd0770492014-12-19 03:55:00 +0000178
Nils Diewald6283d692015-04-23 20:32:53 +0000179 return this;
180 },
181
Nils Diewald7148c6f2015-05-04 15:07:53 +0000182
Akron04671e72017-05-11 20:47:32 +0200183 // Check if the virtual corpus contains a rewrite
184 // This is a class method
185 checkRewrite : function (json) {
186
187 // There is a rewrite attribute
188 if (json['rewrites'] !== undefined) {
189 return true;
190 }
191
192 // There is a group to check for rewrites
193 else if (json['@type'] === 'koral:docGroup') {
194 var ops = json['operands'];
195 if (ops === undefined)
196 return false;
197
198 for (var i in ops) {
199
200 // "this" is the class
201 if (this.checkRewrite(ops[i])) {
202 return true;
203 };
204 };
205 };
206 return false;
207 },
208
Nils Diewald7148c6f2015-05-04 15:07:53 +0000209 /**
210 * Clean the virtual document to uspecified doc.
211 */
Nils Diewald6283d692015-04-23 20:32:53 +0000212 clean : function () {
213 if (this._root.ldType() !== "non") {
Akron04671e72017-05-11 20:47:32 +0200214 this._root.destroy();
215 this.root(unspecDocClass.create(this));
Nils Diewald6283d692015-04-23 20:32:53 +0000216 };
217 return this;
Nils Diewald3a2d8022014-12-16 02:45:41 +0000218 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000219
Nils Diewald7148c6f2015-05-04 15:07:53 +0000220
Nils Diewald1fcb2ad2015-04-20 19:19:18 +0000221 /**
222 * Get or set the root object of the
223 * virtual collection.
224 */
Nils Diewaldf219eb82015-01-07 20:15:42 +0000225 root : function (obj) {
Nils Diewald8e7182e2015-01-08 15:02:07 +0000226 if (arguments.length === 1) {
Akrone4961b12017-05-10 21:04:46 +0200227 var e = this.element();
Nils Diewald845282c2015-05-14 07:53:03 +0000228
Akrone4961b12017-05-10 21:04:46 +0200229 if (e.firstChild !== null) {
230 if (e.firstChild !== obj.element()) {
231 e.replaceChild(obj.element(), e.firstChild);
232 };
233 }
Nils Diewald8f6b6102015-01-08 18:25:33 +0000234
Akrone4961b12017-05-10 21:04:46 +0200235 // Append root element
236 else {
237 e.appendChild(obj.element());
238 };
Nils Diewald8f6b6102015-01-08 18:25:33 +0000239
Akrone4961b12017-05-10 21:04:46 +0200240 // Update parent child relations
241 this._root = obj;
242 obj.parent(this);
Nils Diewald8f6b6102015-01-08 18:25:33 +0000243
Akrone4961b12017-05-10 21:04:46 +0200244 this.update();
Nils Diewald8e7182e2015-01-08 15:02:07 +0000245 };
Nils Diewaldd0770492014-12-19 03:55:00 +0000246 return this._root;
Nils Diewald3a2d8022014-12-16 02:45:41 +0000247 },
Nils Diewald8f6b6102015-01-08 18:25:33 +0000248
Nils Diewald7148c6f2015-05-04 15:07:53 +0000249
Nils Diewald1fcb2ad2015-04-20 19:19:18 +0000250 /**
251 * Get the element associated with the virtual collection
252 */
Nils Diewaldd0770492014-12-19 03:55:00 +0000253 element : function () {
Akron12971a02018-01-03 16:38:10 +0100254 if (this._element !== undefined) {
255 return this._element;
256 };
Nils Diewaldd0770492014-12-19 03:55:00 +0000257
258 this._element = document.createElement('div');
259 this._element.setAttribute('class', 'vc');
Nils Diewald8e7182e2015-01-08 15:02:07 +0000260
Nils Diewald8f6b6102015-01-08 18:25:33 +0000261 // Initialize root
262 this._element.appendChild(this._root.element());
Nils Diewald845282c2015-05-14 07:53:03 +0000263
Nils Diewaldd0770492014-12-19 03:55:00 +0000264 return this._element;
Nils Diewaldf219eb82015-01-07 20:15:42 +0000265 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000266
Nils Diewald1fcb2ad2015-04-20 19:19:18 +0000267
268 /**
269 * Update the whole object based on the underlying
270 * data structure
271 */
Nils Diewaldd599d542015-01-08 20:41:34 +0000272 update : function () {
273 this._root.update();
274 return this;
275 },
276
Nils Diewald845282c2015-05-14 07:53:03 +0000277 /**
278 * Make the vc persistant by injecting the current timestamp
279 * as a creation date limit criterion.
280 */
281 makePersistant : function () {
Akron12971a02018-01-03 16:38:10 +0100282 // this.root().wrapOnRoot('and');
Nils Diewald845282c2015-05-14 07:53:03 +0000283 var todayStr = KorAP._vcDatePicker.today();
284 var doc = docClass.create();
285 var root = this.root();
286
287 if (root.ldType() === 'docGroup' &&
Akron12971a02018-01-03 16:38:10 +0100288 root.operation === 'and') {
289 root.append(cond);
Nils Diewald845282c2015-05-14 07:53:03 +0000290 }
291 else {
Akron12971a02018-01-03 16:38:10 +0100292 root.wrapOnRoot('and');
293 root.append(doc);
Nils Diewald845282c2015-05-14 07:53:03 +0000294 };
295
296 doc.key("creationDate");
297 doc.type("date");
298 doc.matchop("leq");
299 doc.value(todayStr);
300
301/*
302 {
303 "@type" : "koral:doc",
304 "key" : "creationDate",
305 "type" : "type:date",
306 "match" : "match:leq",
307 "value" : todayStr
308 }
309 this.root().append(cond);
310*/
311 this.update();
312 },
Nils Diewald1fcb2ad2015-04-20 19:19:18 +0000313
314 /**
315 * Get the generated json string
316 */
Nils Diewaldf219eb82015-01-07 20:15:42 +0000317 toJson : function () {
318 return this._root.toJson();
319 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000320
Nils Diewald1fcb2ad2015-04-20 19:19:18 +0000321
322 /**
323 * Get the generated query string
324 */
Nils Diewaldd599d542015-01-08 20:41:34 +0000325 toQuery : function () {
326 return this._root.toQuery();
Nils Diewald3a2d8022014-12-16 02:45:41 +0000327 }
328 };
Nils Diewald0e6992a2015-04-14 20:13:52 +0000329});