blob: 58926f2eca6da8ed1c1d5d7cdb5a87bbd08a36e8 [file] [log] [blame]
Nils Diewald0e6992a2015-04-14 20:13:52 +00001/**
2 * Document group criterion
3 */
Nils Diewald4347ee92015-05-04 20:32:48 +00004/*
5 * TODO: Let the UPDATE event bubble up through parents!
6 */
Nils Diewald0e6992a2015-04-14 20:13:52 +00007define([
8 'vc/jsonld',
9 'vc/unspecified',
10 'vc/doc',
11 'util'
12], function (jsonldClass,
13 unspecClass,
14 docClass) {
15
Akron0b489ad2018-02-02 16:49:32 +010016 const _validGroupOpRE = new RegExp("^(?:and|or)$");
Nils Diewald0e6992a2015-04-14 20:13:52 +000017
Akron0b489ad2018-02-02 16:49:32 +010018 const loc = KorAP.Locale;
Nils Diewald359a72c2015-04-20 17:40:29 +000019
Akron0b489ad2018-02-02 16:49:32 +010020 const docGroupClass = {
Nils Diewald0e6992a2015-04-14 20:13:52 +000021 _ldType : "docGroup",
22
23 create : function (parent, json) {
24 var obj = Object.create(jsonldClass).upgradeTo(this);
25 obj._operands = [];
26 obj.fromJson(json);
27 if (parent !== undefined)
Akron0b489ad2018-02-02 16:49:32 +010028 obj._parent = parent;
Nils Diewald0e6992a2015-04-14 20:13:52 +000029 return obj;
30 },
31
32 newAfter : function (obj) {
33 for (var i = 0; i < this._operands.length; i++) {
Akron0b489ad2018-02-02 16:49:32 +010034 if (this._operands[i] === obj) {
35 var operand = unspecClass.create(this);
36 this._operands.splice(i + 1, 0, operand);
37 return this.update();
38 };
Nils Diewald0e6992a2015-04-14 20:13:52 +000039 };
40 },
41
42 // The doc is already set in the group
43 _duplicate : function (operand) {
44 if (operand.ldType() !== 'doc')
Akron0b489ad2018-02-02 16:49:32 +010045 return null;
Nils Diewald0e6992a2015-04-14 20:13:52 +000046
47 for (var i = 0; i < this._operands.length; i++) {
Akron0b489ad2018-02-02 16:49:32 +010048 var op = this.getOperand(i);
49 if (op.ldType() === 'doc'
50 && operand.key() === op.key()
51 && operand.matchop() === op.matchop()
52 && operand.value() === op.value()) {
53 return op;
54 };
Nils Diewald0e6992a2015-04-14 20:13:52 +000055 };
56 return null;
57 },
58
59 append : function (operand) {
60
61 // Append unspecified object
62 if (operand === undefined) {
63
Akron0b489ad2018-02-02 16:49:32 +010064 // Be aware of cyclic structures!
65 operand = unspecClass.create(this);
66 this._operands.push(operand);
67 return operand;
Nils Diewald0e6992a2015-04-14 20:13:52 +000068 };
69
70 switch (operand["@type"]) {
Akron0b489ad2018-02-02 16:49:32 +010071
Nils Diewald0e6992a2015-04-14 20:13:52 +000072 case undefined:
Akron0b489ad2018-02-02 16:49:32 +010073 // No @type defined
74 if (operand["ldType"] !== undefined) {
75 if (operand.ldType() !== 'doc' &&
76 operand.ldType() !== 'docGroup') {
77 KorAP.log(812, "Operand not supported in document group");
78 return;
79 };
Nils Diewald0e6992a2015-04-14 20:13:52 +000080
Akron0b489ad2018-02-02 16:49:32 +010081 // Be aware of cyclic structures!
82 operand.parent(this);
Nils Diewald0e6992a2015-04-14 20:13:52 +000083
Akron0b489ad2018-02-02 16:49:32 +010084 var dupl = this._duplicate(operand);
85 if (dupl === null) {
86 this._operands.push(operand);
87 return operand;
88 };
89 return dupl;
90 };
Nils Diewald0e6992a2015-04-14 20:13:52 +000091
Akron0b489ad2018-02-02 16:49:32 +010092 KorAP.log(701, "JSON-LD group has no @type attribute");
93 return;
Nils Diewald0e6992a2015-04-14 20:13:52 +000094
95 case "koral:doc":
Akron0b489ad2018-02-02 16:49:32 +010096 // Be aware of cyclic structures!
97 var doc = docClass.create(this, operand);
98 if (doc === undefined)
99 return;
100 var dupl = this._duplicate(doc);
101 if (dupl === null) {
102 this._operands.push(doc);
103 return doc;
104 };
105 return dupl;
Nils Diewald0e6992a2015-04-14 20:13:52 +0000106
107 case "koral:docGroup":
Akron0b489ad2018-02-02 16:49:32 +0100108 // Be aware of cyclic structures!
109 var docGroup = docGroupClass.create(this, operand);
110 if (docGroup === undefined)
111 return;
Nils Diewald0e6992a2015-04-14 20:13:52 +0000112
Akron0b489ad2018-02-02 16:49:32 +0100113 // Flatten group
114 if (docGroup.operation() === this.operation()) {
115 for (var op in docGroup.operands()) {
116 op = docGroup.getOperand(op);
117 var dupl = this._duplicate(op);
118 if (dupl === null) {
119 this._operands.push(op);
120 op.parent(this);
121 };
122 };
123 docGroup._operands = [];
124 docGroup.destroy();
125 return this;
126 };
127 this._operands.push(docGroup);
128 return docGroup;
Nils Diewald0e6992a2015-04-14 20:13:52 +0000129
130 default:
Akron0b489ad2018-02-02 16:49:32 +0100131 KorAP.log(812, "Operand not supported in document group");
132 return;
Nils Diewald0e6992a2015-04-14 20:13:52 +0000133 };
134 },
135
136 update : function () {
137 // There is only one operand in group
138
139 if (this._operands.length === 1) {
Akron0b489ad2018-02-02 16:49:32 +0100140
141 var parent = this.parent();
142 var op = this.getOperand(0);
143
144 // This will prevent destruction of
145 // the operand
146 this._operands = [];
Nils Diewald0e6992a2015-04-14 20:13:52 +0000147
Akron0b489ad2018-02-02 16:49:32 +0100148 // Parent is a group
149 if (parent.ldType() !== null)
150 return parent.replaceOperand(this, op).update();
Nils Diewald0e6992a2015-04-14 20:13:52 +0000151
Akron0b489ad2018-02-02 16:49:32 +0100152 // Parent is vc
153 else {
154 this.destroy();
155 // Cyclic madness
156 parent.root(op);
157 op.parent(parent);
158 return parent.root();
159 };
Nils Diewald0e6992a2015-04-14 20:13:52 +0000160 };
161
162 if (this._element === undefined)
Akron0b489ad2018-02-02 16:49:32 +0100163 return this;
Nils Diewald0e6992a2015-04-14 20:13:52 +0000164
165 var group = this._element;
166 group.setAttribute('data-operation', this.operation());
167
168 _removeChildren(group);
169
170 // Append operands
171 for (var i = 0; i < this._operands.length; i++) {
Akron0b489ad2018-02-02 16:49:32 +0100172 group.appendChild(
173 this.getOperand(i).element()
174 );
Nils Diewald0e6992a2015-04-14 20:13:52 +0000175 };
176
177 // Set operators
178 var op = this.operators(
Akron0b489ad2018-02-02 16:49:32 +0100179 this.operation() == 'and' ? false : true,
180 this.operation() == 'or' ? false : true,
181 true
Nils Diewald0e6992a2015-04-14 20:13:52 +0000182 );
183
184 group.appendChild(op.element());
185
186 return this;
187 },
188
189 element : function () {
190 if (this._element !== undefined)
Akron0b489ad2018-02-02 16:49:32 +0100191 return this._element;
Nils Diewald0e6992a2015-04-14 20:13:52 +0000192
193 this._element = document.createElement('div');
194 this._element.setAttribute('class', 'docGroup');
195
196 // Update the object - including optimization
197 this.update();
198
199 return this._element;
200 },
201
202 operation : function (op) {
203 if (arguments.length === 1) {
Akron0b489ad2018-02-02 16:49:32 +0100204 if (_validGroupOpRE.test(op)) {
205 this._op = op;
206 }
207 else {
208 KorAP.log(810, "Unknown operation type");
209 return;
210 };
Nils Diewald0e6992a2015-04-14 20:13:52 +0000211 };
212 return this._op || 'and';
213 },
214
215 operands : function () {
216 return this._operands;
217 },
218
219 getOperand : function (index) {
220 return this._operands[index];
221 },
222
223 // Replace operand
224 replaceOperand : function (oldOp, newOp) {
225
226 for (var i = 0; i < this._operands.length; i++) {
Akron0b489ad2018-02-02 16:49:32 +0100227 if (this._operands[i] === oldOp) {
228
229 // Just insert a doc or ...
230 if (newOp.ldType() === "doc" ||
231 newOp.ldType() === "non" ||
232 // ... insert a group of a different operation
233 // (i.e. "and" in "or"/"or" in "and")
234 newOp.operation() != this.operation()) {
235 this._operands[i] = newOp;
236 newOp.parent(this);
237 }
Nils Diewald0e6992a2015-04-14 20:13:52 +0000238
Akron0b489ad2018-02-02 16:49:32 +0100239 // Flatten group
240 else {
241 // Remove old group
242 this._operands.splice(i, 1);
Nils Diewald0e6992a2015-04-14 20:13:52 +0000243
Akron0b489ad2018-02-02 16:49:32 +0100244 // Inject new operands
245 for (var op in newOp.operands().reverse()) {
246 op = newOp.getOperand(op);
247 this._operands.splice(i, 0, op);
248 op.parent(this);
249 };
250 // Prevent destruction of operands
251 newOp._operands = [];
252 newOp.destroy();
253 };
254 oldOp.destroy();
255 return this;
256 }
Nils Diewald0e6992a2015-04-14 20:13:52 +0000257 };
258 return false;
259 },
260
261 // Delete operand from group
262 delOperand : function (obj) {
263 for (var i = 0; i < this._operands.length; i++) {
Akron0b489ad2018-02-02 16:49:32 +0100264 if (this._operands[i] === obj) {
265
266 // Delete identified operand
267 this._operands.splice(i,1);
Nils Diewald0e6992a2015-04-14 20:13:52 +0000268
Akron0b489ad2018-02-02 16:49:32 +0100269 // Destroy object for cyclic references
270 obj.destroy();
Nils Diewald0e6992a2015-04-14 20:13:52 +0000271
Akron0b489ad2018-02-02 16:49:32 +0100272 return this;
273 };
Nils Diewald0e6992a2015-04-14 20:13:52 +0000274 };
275
276 // Operand not found
277 return undefined;
278 },
279
280 // Deserialize from json
281 fromJson : function (json) {
282 if (json === undefined)
Akron0b489ad2018-02-02 16:49:32 +0100283 return this;
Nils Diewald0e6992a2015-04-14 20:13:52 +0000284
285 if (json["@type"] === undefined) {
Akron0b489ad2018-02-02 16:49:32 +0100286 KorAP.log(701, "JSON-LD group has no @type attribute");
287 return;
Nils Diewald0e6992a2015-04-14 20:13:52 +0000288 };
289
290 if (json["operation"] === undefined ||
Akron0b489ad2018-02-02 16:49:32 +0100291 typeof json["operation"] !== 'string') {
292 KorAP.log(811, "Document group expects operation");
293 return;
Nils Diewald0e6992a2015-04-14 20:13:52 +0000294 };
295
296 var operation = json["operation"];
297
298 this.operation(operation.replace(/^operation:/,''));
299
300 if (json["operands"] === undefined ||
Akron0b489ad2018-02-02 16:49:32 +0100301 !(json["operands"] instanceof Array)) {
302 KorAP.log(704, "Operation needs operand list")
303 return;
Nils Diewald0e6992a2015-04-14 20:13:52 +0000304 };
305
306 // Add all documents
307 for (var i in json["operands"]) {
Akron0b489ad2018-02-02 16:49:32 +0100308 var operand = json["operands"][i];
309 this.append(operand);
Nils Diewald0e6992a2015-04-14 20:13:52 +0000310 };
311
312 return this;
313 },
314
315 toJson : function () {
316 var opArray = new Array();
317 for (var i = 0; i < this._operands.length; i++) {
Akron0b489ad2018-02-02 16:49:32 +0100318 if (this._operands[i].ldType() !== 'non')
319 opArray.push(this._operands[i].toJson());
Nils Diewald0e6992a2015-04-14 20:13:52 +0000320 };
321 return {
Akron0b489ad2018-02-02 16:49:32 +0100322 "@type" : "koral:" + this.ldType(),
323 "operation" : "operation:" + this.operation(),
324 "operands" : opArray
Nils Diewald0e6992a2015-04-14 20:13:52 +0000325 };
326 },
327
328 toQuery : function (brackets) {
329 var list = this._operands
Akron0b489ad2018-02-02 16:49:32 +0100330 .filter(function (op) {
331 return op.ldType() !== 'non';
332 })
333 .map(function (op) {
334 return (op.ldType() === 'docGroup') ?
335 op.toQuery(true) :
336 op.toQuery();
337 });
Nils Diewald0e6992a2015-04-14 20:13:52 +0000338
339 if (list.length === 1)
Akron0b489ad2018-02-02 16:49:32 +0100340 return list.join('');
Nils Diewald0e6992a2015-04-14 20:13:52 +0000341 else {
Akron0b489ad2018-02-02 16:49:32 +0100342 var str = list.join(this.operation() === 'or' ? ' | ' : ' & ');
343 return brackets ? '(' + str + ')' : str;
Nils Diewald0e6992a2015-04-14 20:13:52 +0000344 };
345 }
346 };
347 return docGroupClass;
348});