blob: 527e11686041bc9fed9861415dd32faf5d6f02e5 [file] [log] [blame]
Nils Diewald86dad5b2015-01-28 15:09:07 +00001/**
hebastaa79d69d2018-07-24 12:13:02 +02002 * Create virtual collections with a visual user interface. This resembles the
3 * collection type objects of a KoralQuery "collection" object.
4 *
Nils Diewald4c221252015-04-21 20:19:25 +00005 * KoralQuery v0.3 is expected.
hebastaa79d69d2018-07-24 12:13:02 +02006 *
Nils Diewald86dad5b2015-01-28 15:09:07 +00007 * @author Nils Diewald
8 */
Nils Diewald2fe12e12015-03-06 16:47:06 +00009/*
Nils Diewald1fcb2ad2015-04-20 19:19:18 +000010 * This replaces a previous version written by Mengfei Zhou
Nils Diewald2fe12e12015-03-06 16:47:06 +000011 */
Nils Diewald2fe12e12015-03-06 16:47:06 +000012
Nils Diewaldd0770492014-12-19 03:55:00 +000013/*
hebastaa79d69d2018-07-24 12:13:02 +020014 * TODO: Disable "and" or "or" in case it's followed by an unspecified document
15 * TODO: Add "and"-method to root to add further constraints based on match-
16 * input (like clicking on a pubDate timestamp in a match) TODO: Implement
17 * "persistence"-Option, injecting the current creation date stamp TODO:
18 * Implement vec-Type for document-id vectors like docID in [1,2,3,4 ...]
19 *
20 * Error codes: 701: "JSON-LD group has no @type attribute" 704: "Operation
21 * needs operand list" 802: "Match type is not supported by value type" 804:
22 * "Unknown value type" 805: "Value is invalid" 806: "Value is not a valid date
23 * string" 807: "Value is not a valid regular expression" 810: "Unknown document
24 * group operation" (like 711) 811: "Document group expects operation" (like
25 * 703) 812: "Operand not supported in document group" (like 744) 813:
26 * "Collection type is not supported" (like 713) 814: "Unknown rewrite
27 * operation" 815: "Rewrite expects source"
28 *
29 * Localization strings: KorAP.Locale = { EMPTY : '...', AND : 'and', OR : 'or',
30 * DELETE : 'x' } and various field names with the prefix 'VC_'
31 */
Nils Diewald86dad5b2015-01-28 15:09:07 +000032
hebastaa79d69d2018-07-24 12:13:02 +020033define([ 'vc/unspecified', 'vc/doc', 'vc/docgroup', 'vc/menu', 'vc/statistic',
34 'datepicker', 'buttongroup', 'panel', 'view/corpstatv', 'util', ],
35 function(unspecDocClass, docClass, docGroupClass, menuClass, statClass,
36 dpClass, buttonGrClass, panelClass, corpStatVClass) {
37 "use strict";
Nils Diewald1fcb2ad2015-04-20 19:19:18 +000038
hebastaa79d69d2018-07-24 12:13:02 +020039 KorAP._validUnspecMatchRE = new RegExp(
40 "^(?:eq|ne|contains(?:not)?|excludes)$");
41 KorAP._validStringMatchRE = new RegExp("^(?:eq|ne)$");
42 KorAP._validTextMatchRE = KorAP._validUnspecMatchRE;
43 KorAP._validTextOnlyMatchRE = new RegExp(
44 "^(?:contains(?:not)?|excludes)$");
45 KorAP._overrideStyles = false;
46 // KorAP._validDateMatchRE is defined in datepicker.js!
Nils Diewaldd0770492014-12-19 03:55:00 +000047
hebastaa79d69d2018-07-24 12:13:02 +020048 const loc = KorAP.Locale;
49 loc.SHOW_STAT = loc.SHOW_STAT || 'Statistics';
50 loc.VERB_SHOWSTAT = loc.VERB_SHOWSTAT || 'Corpus Statistics';
Nils Diewald3a2d8022014-12-16 02:45:41 +000051
hebastaa79d69d2018-07-24 12:13:02 +020052 KorAP._vcKeyMenu = undefined;
53 KorAP._vcDatePicker = dpClass.create();
Nils Diewald3a2d8022014-12-16 02:45:41 +000054
hebastaa79d69d2018-07-24 12:13:02 +020055 // Create match menus ....
56 KorAP._vcMatchopMenu = {
57 'string' : menuClass.create([ [ 'eq', null ], [ 'ne', null ] ]),
58 'text' : menuClass.create([ [ 'eq', null ], // Requires exact match
59 [ 'ne', null ], [ 'contains', null ], // Requires token sequence match
60 [ 'containsnot', null ] ]),
61 'date' : menuClass.create([ [ 'eq', null ], [ 'ne', null ],
62 [ 'geq', null ], [ 'leq', null ] ]),
63 'regex' : menuClass.create([ [ 'eq', null ], [ 'ne', null ] ])
Nils Diewald359a72c2015-04-20 17:40:29 +000064 };
65
hebastaa79d69d2018-07-24 12:13:02 +020066 /**
67 * Virtual Collection
68 */
69 return {
Akron712733a2018-04-05 18:17:47 +020070
hebastaa79d69d2018-07-24 12:13:02 +020071 /**
72 * The JSON-LD type of the virtual collection
73 */
74 ldType : function() {
75 return null;
76 },
Nils Diewald359a72c2015-04-20 17:40:29 +000077
hebastaa79d69d2018-07-24 12:13:02 +020078 // Initialize virtual collection
79 _init : function(keyList) {
Nils Diewaldd599d542015-01-08 20:41:34 +000080
hebastaa79d69d2018-07-24 12:13:02 +020081 // Inject localized css styles
82 if (!KorAP._overrideStyles) {
83 var sheet = KorAP.newStyleSheet();
Nils Diewald7148c6f2015-05-04 15:07:53 +000084
hebastaa79d69d2018-07-24 12:13:02 +020085 // Add css rule for OR operations
86 sheet.insertRule('.vc .docGroup[data-operation=or] > .doc::before,'
87 + '.vc .docGroup[data-operation=or] > .docGroup::before '
88 + '{ content: "' + loc.OR + '" }', 0);
Nils Diewaldd0770492014-12-19 03:55:00 +000089
hebastaa79d69d2018-07-24 12:13:02 +020090 // Add css rule for AND operations
91 sheet.insertRule(
92 '.vc .docGroup[data-operation=and] > .doc::before,'
93 + '.vc .docGroup[data-operation=and] > .docGroup::before '
94 + '{ content: "' + loc.AND + '" }', 1);
Nils Diewaldd0770492014-12-19 03:55:00 +000095
hebastaa79d69d2018-07-24 12:13:02 +020096 KorAP._overrideStyles = true;
97 }
98 ;
Nils Diewaldd0770492014-12-19 03:55:00 +000099
hebastaa79d69d2018-07-24 12:13:02 +0200100 // Create key menu
101 KorAP._vcKeyMenu = menuClass.create(keyList);
102 KorAP._vcKeyMenu.limit(6);
Nils Diewald6283d692015-04-23 20:32:53 +0000103
hebastaa79d69d2018-07-24 12:13:02 +0200104 return this;
105 },
Nils Diewald7148c6f2015-05-04 15:07:53 +0000106
hebastaa79d69d2018-07-24 12:13:02 +0200107 /**
108 * Create a new virtual collection.
109 */
110 create : function(keyList) {
111 var obj = Object.create(this)._init(keyList);
112 obj._root = unspecDocClass.create(obj);
113 return obj;
114 },
Akron04671e72017-05-11 20:47:32 +0200115
hebastaa79d69d2018-07-24 12:13:02 +0200116 /**
117 * Create and render a new virtual collection based on a KoralQuery
118 * collection document
119 */
120 fromJson : function(json) {
121 if (json !== undefined) {
122 // Parse root document
123 if (json['@type'] == 'koral:doc') {
124 this._root = docClass.create(this, json);
125 }
126 // parse root group
127 else if (json['@type'] == 'koral:docGroup') {
128 this._root = docGroupClass.create(this, json);
129 }
130 // Unknown collection type
131 else {
132 KorAP.log(813, "Collection type is not supported");
133 return;
134 }
135 ;
136 }
Akron04671e72017-05-11 20:47:32 +0200137
hebastaa79d69d2018-07-24 12:13:02 +0200138 else {
139 // Add unspecified object
140 this._root = unspecDocClass.create(this);
141 }
142 ;
Akron04671e72017-05-11 20:47:32 +0200143
hebastaa79d69d2018-07-24 12:13:02 +0200144 // Init element and update
145 this.update();
Akron04671e72017-05-11 20:47:32 +0200146
hebastaa79d69d2018-07-24 12:13:02 +0200147 return this;
148 },
149
150 // Check if the virtual corpus contains a rewrite
151 // This is a class method
152 checkRewrite : function(json) {
153
154 // There is a rewrite attribute
155 if (json['rewrites'] !== undefined) {
Akron04671e72017-05-11 20:47:32 +0200156 return true;
hebastaa79d69d2018-07-24 12:13:02 +0200157 }
Akron04671e72017-05-11 20:47:32 +0200158
hebastaa79d69d2018-07-24 12:13:02 +0200159 // There is a group to check for rewrites
160 else if (json['@type'] === 'koral:docGroup') {
161 var ops = json['operands'];
162 if (ops === undefined)
163 return false;
Nils Diewaldd599d542015-01-08 20:41:34 +0000164
hebastaa79d69d2018-07-24 12:13:02 +0200165 for ( var i in ops) {
Nils Diewald7148c6f2015-05-04 15:07:53 +0000166
hebastaa79d69d2018-07-24 12:13:02 +0200167 // "this" is the class
168 if (this.checkRewrite(ops[i])) {
169 return true;
170 }
171 ;
172 }
173 ;
174 }
175 ;
176 return false;
177 },
Nils Diewald845282c2015-05-14 07:53:03 +0000178
hebastaa79d69d2018-07-24 12:13:02 +0200179 /**
180 * Clean the virtual document to uspecified doc.
181 */
182 clean : function() {
183 if (this._root.ldType() !== "non") {
184 this._root.destroy();
185 this.root(unspecDocClass.create(this));
186 }
187 ;
188 return this;
189 },
Nils Diewald8f6b6102015-01-08 18:25:33 +0000190
hebastaa79d69d2018-07-24 12:13:02 +0200191 /**
192 * Get or set the root object of the virtual collection.
193 */
194 root : function(obj) {
195 if (arguments.length === 1) {
196 var e = this.element();
Nils Diewald8f6b6102015-01-08 18:25:33 +0000197
hebastaa79d69d2018-07-24 12:13:02 +0200198 if (e.firstChild !== null) {
199 if (e.firstChild !== obj.element()) {
200 e.replaceChild(obj.element(), e.firstChild);
201 }
202 ;
203 }
Nils Diewald8f6b6102015-01-08 18:25:33 +0000204
hebastaa79d69d2018-07-24 12:13:02 +0200205 // Append root element
206 else {
207 e.appendChild(obj.element());
208 }
209 ;
Nils Diewald8f6b6102015-01-08 18:25:33 +0000210
hebastaa79d69d2018-07-24 12:13:02 +0200211 // Update parent child relations
212 this._root = obj;
213 obj.parent(this);
Nils Diewaldd0770492014-12-19 03:55:00 +0000214
hebastaa79d69d2018-07-24 12:13:02 +0200215 this.update();
216 }
217 ;
218 return this._root;
219 },
Nils Diewald8e7182e2015-01-08 15:02:07 +0000220
hebastaa79d69d2018-07-24 12:13:02 +0200221 /**
222 * Get the element associated with the virtual collection
223 */
224 element : function() {
225
226
227 if (this._element !== undefined) {
228 return this._element;
229 }
230 ;
231
232 this._element = document.createElement('div');
233 this._element.setAttribute('class', 'vc');
234
235 // Initialize root
236 this._element.appendChild(this._root.element());
237
238 /*
239 * TODO by Helge Hack! additional div, because statistic button is
240 * removed after choosing and/or/x in vc builder. REMOVE this lines
241 * after solving the problem!!!!
242 */
243 this._element.addE('div');
244 this._element.addE('div');
245 this._element.addE('div');
246
247 // Add panel to display corpus statistic, ...
248 this.addVcInfPanel();
Nils Diewald845282c2015-05-14 07:53:03 +0000249
hebastaa79d69d2018-07-24 12:13:02 +0200250 return this._element;
251 },
252
253 /**
254 * Update the whole object based on the underlying data structure
255 */
256 update : function() {
257 this._root.update();
258 return this;
259 },
260
261 /**
262 * Make the vc persistant by injecting the current timestamp as a
263 * creation date limit criterion.
264 */
265 makePersistant : function() {
266 // this.root().wrapOnRoot('and');
267 var todayStr = KorAP._vcDatePicker.today();
268 var doc = docClass.create();
269 var root = this.root();
270
271 if (root.ldType() === 'docGroup' && root.operation === 'and') {
272 root.append(cond);
273 } else {
274 root.wrapOnRoot('and');
275 root.append(doc);
276 }
277 ;
278
279 doc.key("creationDate");
280 doc.type("date");
281 doc.matchop("leq");
282 doc.value(todayStr);
283
284 /*
285 * { "@type" : "koral:doc", "key" : "creationDate", "type" :
286 * "type:date", "match" : "match:leq", "value" : todayStr }
287 * this.root().append(cond);
288 */
289 this.update();
290 },
291
292 /**
293 * Get the generated json string
294 */
295 toJson : function() {
296 return this._root.toJson();
297 },
298
299 /**
300 * Get the generated query string
301 */
302 toQuery : function() {
303 return this._root.toQuery();
304 },
305
306
307 /*
308 * Add panel to display virtual corpus information
309 */
310 addVcInfPanel : function() {
311
312 var dv = this._element.addE('div');
313 var panel = panelClass.create([ 'vcinfo' ]);
314 dv.appendChild(panel.element());
hebasta4c92eec2018-06-29 10:11:15 +0200315
hebastaa79d69d2018-07-24 12:13:02 +0200316 var that = this;
317 var actions = panel.actions;
318 var statView;
319
320 //delete log after solving the cq= -Problem.
321 console.log("vc._root.element() = " + that._root.element().innerHTML);
322 console.log("vc._root.toQuery = " + that._root.toQuery());
323
324 actions.add(loc.SHOW_STAT, [ 'statistic' ], function() {
325 if (statView === undefined || !statView.shown()) {
326
327 //delete log after solving the cq= -Problem
328 console.log("statView created mit vc.toQuery()= "
329 + that.toQuery());
330
331 statView = corpStatVClass.create(that);
332 panel.add(statView);
333 }
334 });
335 }
Nils Diewald845282c2015-05-14 07:53:03 +0000336 };
hebastaa79d69d2018-07-24 12:13:02 +0200337 });