blob: 0db4b4c037fbe398eb35e2472a3794d924195344 [file] [log] [blame]
Nils Diewald0e6992a2015-04-14 20:13:52 +00001/**
2 * Document group criterion
3 */
4define([
5 'vc/jsonld',
6 'vc/unspecified',
7 'vc/doc',
8 'util'
9], function (jsonldClass,
10 unspecClass,
11 docClass) {
12
13 var _validGroupOpRE = new RegExp("^(?:and|or)$");
14
Nils Diewald359a72c2015-04-20 17:40:29 +000015 var loc = KorAP.Locale;
16
Nils Diewald0e6992a2015-04-14 20:13:52 +000017 var docGroupClass = {
18 _ldType : "docGroup",
19
20 create : function (parent, json) {
21 var obj = Object.create(jsonldClass).upgradeTo(this);
22 obj._operands = [];
23 obj.fromJson(json);
24 if (parent !== undefined)
25 obj._parent = parent;
26 return obj;
27 },
28
29 newAfter : function (obj) {
30 for (var i = 0; i < this._operands.length; i++) {
31 if (this._operands[i] === obj) {
32 var operand = unspecClass.create(this);
33 this._operands.splice(i + 1, 0, operand);
34 return this.update();
35 };
36 };
37 },
38
39 // The doc is already set in the group
40 _duplicate : function (operand) {
41 if (operand.ldType() !== 'doc')
42 return null;
43
44 for (var i = 0; i < this._operands.length; i++) {
45 var op = this.getOperand(i);
46 if (op.ldType() === 'doc'
47 && operand.key() === op.key()
48 && operand.matchop() === op.matchop()
49 && operand.value() === op.value()) {
50 return op;
51 };
52 };
53 return null;
54 },
55
56 append : function (operand) {
57
58 // Append unspecified object
59 if (operand === undefined) {
60
61 // Be aware of cyclic structures!
62 operand = unspecClass.create(this);
63 this._operands.push(operand);
64 return operand;
65 };
66
67 switch (operand["@type"]) {
68
69 case undefined:
70 // No @type defined
71 if (operand["ldType"] !== undefined) {
72 if (operand.ldType() !== 'doc' &&
73 operand.ldType() !== 'docGroup') {
74 KorAP.log(812, "Operand not supported in document group");
75 return;
76 };
77
78 // Be aware of cyclic structures!
79 operand.parent(this);
80
81 var dupl = this._duplicate(operand);
82 if (dupl === null) {
83 this._operands.push(operand);
84 return operand;
85 };
86 return dupl;
87 };
88
89 KorAP.log(701, "JSON-LD group has no @type attribute");
90 return;
91
92 case "koral:doc":
93 // Be aware of cyclic structures!
94 var doc = docClass.create(this, operand);
95 if (doc === undefined)
96 return;
97 var dupl = this._duplicate(doc);
98 if (dupl === null) {
99 this._operands.push(doc);
100 return doc;
101 };
102 return dupl;
103
104 case "koral:docGroup":
105 // Be aware of cyclic structures!
106 var docGroup = docGroupClass.create(this, operand);
107 if (docGroup === undefined)
108 return;
109
110 // Flatten group
111 if (docGroup.operation() === this.operation()) {
112 for (var op in docGroup.operands()) {
113 op = docGroup.getOperand(op);
114 var dupl = this._duplicate(op);
115 if (dupl === null) {
116 this._operands.push(op);
117 op.parent(this);
118 };
119 };
120 docGroup._operands = [];
121 docGroup.destroy();
122 return this;
123 };
124 this._operands.push(docGroup);
125 return docGroup;
126
127 default:
128 KorAP.log(812, "Operand not supported in document group");
129 return;
130 };
131 },
132
133 update : function () {
134 // There is only one operand in group
135
136 if (this._operands.length === 1) {
137
138 var parent = this.parent();
139 var op = this.getOperand(0);
140
141 // This will prevent destruction of
142 // the operand
143 this._operands = [];
144
145 // Parent is a group
146 if (parent.ldType() !== null)
147 return parent.replaceOperand(this, op).update();
148
149 // Parent is vc
150 else {
151 this.destroy();
152 // Cyclic madness
153 parent.root(op);
154 op.parent(parent);
155 return parent.root();
156 };
157 };
158
159 if (this._element === undefined)
160 return this;
161
162 var group = this._element;
163 group.setAttribute('data-operation', this.operation());
164
165 _removeChildren(group);
166
167 // Append operands
168 for (var i = 0; i < this._operands.length; i++) {
169 group.appendChild(
170 this.getOperand(i).element()
171 );
172 };
173
174 // Set operators
175 var op = this.operators(
176 this.operation() == 'and' ? false : true,
177 this.operation() == 'or' ? false : true,
178 true
179 );
180
181 group.appendChild(op.element());
182
183 return this;
184 },
185
186 element : function () {
187 if (this._element !== undefined)
188 return this._element;
189
190 this._element = document.createElement('div');
191 this._element.setAttribute('class', 'docGroup');
192
193 // Update the object - including optimization
194 this.update();
195
196 return this._element;
197 },
198
199 operation : function (op) {
200 if (arguments.length === 1) {
201 if (_validGroupOpRE.test(op)) {
202 this._op = op;
203 }
204 else {
205 KorAP.log(810, "Unknown operation type");
206 return;
207 };
208 };
209 return this._op || 'and';
210 },
211
212 operands : function () {
213 return this._operands;
214 },
215
216 getOperand : function (index) {
217 return this._operands[index];
218 },
219
220 // Replace operand
221 replaceOperand : function (oldOp, newOp) {
222
223 for (var i = 0; i < this._operands.length; i++) {
224 if (this._operands[i] === oldOp) {
225
226 // Just insert a doc or ...
227 if (newOp.ldType() === "doc" ||
228 newOp.ldType() === "non" ||
229 // ... insert a group of a different operation
230 // (i.e. "and" in "or"/"or" in "and")
231 newOp.operation() != this.operation()) {
232 this._operands[i] = newOp;
233 newOp.parent(this);
234 }
235
236 // Flatten group
237 else {
238 // Remove old group
239 this._operands.splice(i, 1);
240
241 // Inject new operands
242 for (var op in newOp.operands().reverse()) {
243 op = newOp.getOperand(op);
244 this._operands.splice(i, 0, op);
245 op.parent(this);
246 };
247 // Prevent destruction of operands
248 newOp._operands = [];
249 newOp.destroy();
250 };
251 oldOp.destroy();
252 return this;
253 }
254 };
255 return false;
256 },
257
258 // Delete operand from group
259 delOperand : function (obj) {
260 for (var i = 0; i < this._operands.length; i++) {
261 if (this._operands[i] === obj) {
262
263 // Delete identified operand
264 this._operands.splice(i,1);
265
266 // Destroy object for cyclic references
267 obj.destroy();
268
269 return this;
270 };
271 };
272
273 // Operand not found
274 return undefined;
275 },
276
277 // Deserialize from json
278 fromJson : function (json) {
279 if (json === undefined)
280 return this;
281
282 if (json["@type"] === undefined) {
283 KorAP.log(701, "JSON-LD group has no @type attribute");
284 return;
285 };
286
287 if (json["operation"] === undefined ||
288 typeof json["operation"] !== 'string') {
289 KorAP.log(811, "Document group expects operation");
290 return;
291 };
292
293 var operation = json["operation"];
294
295 this.operation(operation.replace(/^operation:/,''));
296
297 if (json["operands"] === undefined ||
298 !(json["operands"] instanceof Array)) {
299 KorAP.log(704, "Operation needs operand list")
300 return;
301 };
302
303 // Add all documents
304 for (var i in json["operands"]) {
305 var operand = json["operands"][i];
306 this.append(operand);
307 };
308
309 return this;
310 },
311
312 toJson : function () {
313 var opArray = new Array();
314 for (var i = 0; i < this._operands.length; i++) {
315 if (this._operands[i].ldType() !== 'non')
316 opArray.push(this._operands[i].toJson());
317 };
318 return {
319 "@type" : "koral:" + this.ldType(),
320 "operation" : "operation:" + this.operation(),
321 "operands" : opArray
322 };
323 },
324
325 toQuery : function (brackets) {
326 var list = this._operands
327 .filter(function (op) {
328 return op.ldType() !== 'non';
329 })
330 .map(function (op) {
331 return (op.ldType() === 'docGroup') ?
332 op.toQuery(true) :
333 op.toQuery();
334 });
335
336 if (list.length === 1)
337 return list.join('');
338 else {
339 var str = list.join(this.operation() === 'or' ? ' | ' : ' & ');
340 return brackets ? '(' + str + ')' : str;
341 };
342 }
343 };
344 return docGroupClass;
345});