blob: e551d63bf1b94fa27c66a4bcb389228b62900759 [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
Nils Diewald359a72c2015-04-20 17:40:29 +000059 // ???
Akron6a535d42015-08-26 20:16:58 +020060 KorAP._validStringMatchRE = new RegExp("^(?:eq|ne|contains(?:not)?|excludes)$");
Nils Diewaldd0770492014-12-19 03:55:00 +000061 KorAP._validDateMatchRE = new RegExp("^[lg]?eq$");
Nils Diewald3a2d8022014-12-16 02:45:41 +000062 KorAP._validDateRE = new RegExp("^(?:\\d{4})(?:-\\d\\d(?:-\\d\\d)?)?$");
Nils Diewald359a72c2015-04-20 17:40:29 +000063 KorAP._overrideStyles = false;
Nils Diewald3a2d8022014-12-16 02:45:41 +000064
Nils Diewald359a72c2015-04-20 17:40:29 +000065 var loc = KorAP.Locale;
Nils Diewaldd599d542015-01-08 20:41:34 +000066
Nils Diewald1fcb2ad2015-04-20 19:19:18 +000067 KorAP._vcKeyMenu = undefined;
Nils Diewald87507832015-05-01 23:36:41 +000068 KorAP._vcDatePicker = dpClass.create();
Nils Diewald1fcb2ad2015-04-20 19:19:18 +000069
Nils Diewaldd599d542015-01-08 20:41:34 +000070 /**
71 * Virtual Collection
72 */
Nils Diewald0e6992a2015-04-14 20:13:52 +000073 return {
Nils Diewald1fcb2ad2015-04-20 19:19:18 +000074
75 /**
76 * The JSON-LD type of the virtual collection
77 */
Nils Diewaldf219eb82015-01-07 20:15:42 +000078 ldType : function () {
79 return null;
80 },
Nils Diewaldd599d542015-01-08 20:41:34 +000081
Nils Diewald1fcb2ad2015-04-20 19:19:18 +000082 // Initialize virtual collection
83 _init : function (keyList) {
84
85 // Inject localized css styles
Nils Diewald359a72c2015-04-20 17:40:29 +000086 if (!KorAP._overrideStyles) {
87 var sheet = KorAP.newStyleSheet();
88
89 // Add css rule for OR operations
90 sheet.insertRule(
91 '.vc .docGroup[data-operation=or] > .doc::before,' +
92 '.vc .docGroup[data-operation=or] > .docGroup::before ' +
93 '{ content: "' + loc.OR + '" }',
94 0
95 );
96
97 // Add css rule for AND operations
98 sheet.insertRule(
99 '.vc .docGroup[data-operation=and] > .doc::before,' +
100 '.vc .docGroup[data-operation=and] > .docGroup::before ' +
101 '{ content: "' + loc.AND + '" }',
102 1
103 );
104
Nils Diewald359a72c2015-04-20 17:40:29 +0000105 KorAP._overrideStyles = true;
Nils Diewald1fcb2ad2015-04-20 19:19:18 +0000106
107 // Create key menu
108 KorAP._vcKeyMenu = menuClass.create(keyList);
Nils Diewald4c221252015-04-21 20:19:25 +0000109 KorAP._vcKeyMenu.limit(6);
110
111 // Create match menus ....
112 KorAP._vcMatchopMenu = {
113 'string' : menuClass.create([
114 ['eq', null],
Akron792f58b2015-07-08 18:59:36 +0200115 ['ne', null],
Nils Diewald4c221252015-04-21 20:19:25 +0000116 ['contains', null],
Akron6a535d42015-08-26 20:16:58 +0200117 ['containsnot', null]
Nils Diewald4c221252015-04-21 20:19:25 +0000118 ]),
119 'date' : menuClass.create([
120 ['eq', null],
121 ['geq', null],
122 ['leq', null]
123 ]),
124 'regex' : menuClass.create([
125 ['eq', null],
Akron792f58b2015-07-08 18:59:36 +0200126 ['ne', null],
Nils Diewald4c221252015-04-21 20:19:25 +0000127 ['contains', null],
Akron6a535d42015-08-26 20:16:58 +0200128 ['containsnot', null]
Nils Diewald4c221252015-04-21 20:19:25 +0000129 ])
130 };
Nils Diewald359a72c2015-04-20 17:40:29 +0000131 };
132
133 return this;
134 },
135
Nils Diewald1fcb2ad2015-04-20 19:19:18 +0000136 /**
137 * Create a new virtual collection.
138 */
139 create : function (keyList) {
Nils Diewald6283d692015-04-23 20:32:53 +0000140 var obj = Object.create(this)._init(keyList);
141 obj._root = unspecDocClass.create(obj);
142 return obj;
Nils Diewald4019bd22015-01-08 19:57:50 +0000143 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000144
Nils Diewald7148c6f2015-05-04 15:07:53 +0000145
Nils Diewald1fcb2ad2015-04-20 19:19:18 +0000146 /**
147 * Create and render a new virtual collection
148 * based on a KoralQuery collection document
149 */
Nils Diewald6283d692015-04-23 20:32:53 +0000150 fromJson : function (json) {
Nils Diewaldd0770492014-12-19 03:55:00 +0000151
152 if (json !== undefined) {
Nils Diewald1fcb2ad2015-04-20 19:19:18 +0000153 // Parse root document
Nils Diewald2fe12e12015-03-06 16:47:06 +0000154 if (json['@type'] == 'koral:doc') {
Nils Diewald6283d692015-04-23 20:32:53 +0000155 this._root = docClass.create(this, json);
Nils Diewaldd0770492014-12-19 03:55:00 +0000156 }
Nils Diewald1fcb2ad2015-04-20 19:19:18 +0000157 // parse root group
Nils Diewald2fe12e12015-03-06 16:47:06 +0000158 else if (json['@type'] == 'koral:docGroup') {
Nils Diewald6283d692015-04-23 20:32:53 +0000159 this._root = docGroupClass.create(this, json);
Nils Diewaldd0770492014-12-19 03:55:00 +0000160 }
Nils Diewald1fcb2ad2015-04-20 19:19:18 +0000161 // Unknown collection type
Nils Diewaldd0770492014-12-19 03:55:00 +0000162 else {
163 KorAP.log(813, "Collection type is not supported");
164 return;
165 };
166 }
167
168 else {
169 // Add unspecified object
Nils Diewald6283d692015-04-23 20:32:53 +0000170 this._root = unspecDocClass.create(this);
Nils Diewaldd0770492014-12-19 03:55:00 +0000171 };
172
Nils Diewald8e7182e2015-01-08 15:02:07 +0000173 // Init element and update
Nils Diewald6283d692015-04-23 20:32:53 +0000174 this.update();
Nils Diewaldd0770492014-12-19 03:55:00 +0000175
Nils Diewald6283d692015-04-23 20:32:53 +0000176 return this;
177 },
178
Nils Diewald7148c6f2015-05-04 15:07:53 +0000179
180 /**
181 * Clean the virtual document to uspecified doc.
182 */
Nils Diewald6283d692015-04-23 20:32:53 +0000183 clean : function () {
184 if (this._root.ldType() !== "non") {
185 this._root.destroy();
186 this.root(unspecDocClass.create(this));
187 };
188 return this;
Nils Diewald3a2d8022014-12-16 02:45:41 +0000189 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000190
Nils Diewald7148c6f2015-05-04 15:07:53 +0000191
Nils Diewald1fcb2ad2015-04-20 19:19:18 +0000192 /**
193 * Get or set the root object of the
194 * virtual collection.
195 */
Nils Diewaldf219eb82015-01-07 20:15:42 +0000196 root : function (obj) {
Nils Diewald8e7182e2015-01-08 15:02:07 +0000197 if (arguments.length === 1) {
Nils Diewald8f6b6102015-01-08 18:25:33 +0000198 var e = this.element();
Nils Diewald845282c2015-05-14 07:53:03 +0000199
Nils Diewald8f6b6102015-01-08 18:25:33 +0000200 if (e.firstChild !== null) {
Nils Diewaldd5070b02015-01-11 01:44:47 +0000201 if (e.firstChild !== obj.element()) {
Nils Diewald8f6b6102015-01-08 18:25:33 +0000202 e.replaceChild(obj.element(), e.firstChild);
Nils Diewaldd5070b02015-01-11 01:44:47 +0000203 };
Nils Diewald8f6b6102015-01-08 18:25:33 +0000204 }
205
206 // Append root element
207 else {
208 e.appendChild(obj.element());
209 };
210
211 // Update parent child relations
Nils Diewaldf219eb82015-01-07 20:15:42 +0000212 this._root = obj;
Nils Diewald8f6b6102015-01-08 18:25:33 +0000213 obj.parent(this);
214
Nils Diewald8e7182e2015-01-08 15:02:07 +0000215 this.update();
216 };
Nils Diewaldd0770492014-12-19 03:55:00 +0000217 return this._root;
Nils Diewald3a2d8022014-12-16 02:45:41 +0000218 },
Nils Diewald8f6b6102015-01-08 18:25:33 +0000219
Nils Diewald7148c6f2015-05-04 15:07:53 +0000220
Nils Diewald1fcb2ad2015-04-20 19:19:18 +0000221 /**
222 * Get the element associated with the virtual collection
223 */
Nils Diewaldd0770492014-12-19 03:55:00 +0000224 element : function () {
225 if (this._element !== undefined)
226 return this._element;
227
228 this._element = document.createElement('div');
229 this._element.setAttribute('class', 'vc');
Nils Diewald8e7182e2015-01-08 15:02:07 +0000230
Nils Diewald8f6b6102015-01-08 18:25:33 +0000231 // Initialize root
232 this._element.appendChild(this._root.element());
Nils Diewald845282c2015-05-14 07:53:03 +0000233
Nils Diewaldd0770492014-12-19 03:55:00 +0000234 return this._element;
Nils Diewaldf219eb82015-01-07 20:15:42 +0000235 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000236
Nils Diewald1fcb2ad2015-04-20 19:19:18 +0000237
238 /**
239 * Update the whole object based on the underlying
240 * data structure
241 */
Nils Diewaldd599d542015-01-08 20:41:34 +0000242 update : function () {
243 this._root.update();
244 return this;
245 },
246
Nils Diewald845282c2015-05-14 07:53:03 +0000247 /**
248 * Make the vc persistant by injecting the current timestamp
249 * as a creation date limit criterion.
250 */
251 makePersistant : function () {
252// this.root().wrapOnRoot('and');
253 var todayStr = KorAP._vcDatePicker.today();
254 var doc = docClass.create();
255 var root = this.root();
256
257 if (root.ldType() === 'docGroup' &&
258 root.operation === 'and') {
259 root.append(cond);
260 }
261 else {
262 root.wrapOnRoot('and');
263 root.append(doc);
264 };
265
266 doc.key("creationDate");
267 doc.type("date");
268 doc.matchop("leq");
269 doc.value(todayStr);
270
271/*
272 {
273 "@type" : "koral:doc",
274 "key" : "creationDate",
275 "type" : "type:date",
276 "match" : "match:leq",
277 "value" : todayStr
278 }
279 this.root().append(cond);
280*/
281 this.update();
282 },
Nils Diewald1fcb2ad2015-04-20 19:19:18 +0000283
284 /**
285 * Get the generated json string
286 */
Nils Diewaldf219eb82015-01-07 20:15:42 +0000287 toJson : function () {
288 return this._root.toJson();
289 },
Nils Diewaldd599d542015-01-08 20:41:34 +0000290
Nils Diewald1fcb2ad2015-04-20 19:19:18 +0000291
292 /**
293 * Get the generated query string
294 */
Nils Diewaldd599d542015-01-08 20:41:34 +0000295 toQuery : function () {
296 return this._root.toQuery();
Nils Diewald3a2d8022014-12-16 02:45:41 +0000297 }
298 };
Nils Diewald0e6992a2015-04-14 20:13:52 +0000299});