| /** |
| * Document group criterion |
| */ |
| /* |
| * TODO: Let the UPDATE event bubble up through parents! |
| */ |
| define([ |
| 'vc/jsonld', |
| 'vc/unspecified', |
| 'vc/doc', |
| 'vc/docgroupref', |
| 'util' |
| ], function (jsonldClass, |
| unspecClass, |
| docClass, |
| docGroupRefClass) { |
| |
| const _validGroupOpRE = new RegExp("^(?:and|or)$"); |
| |
| const docGroupClass = { |
| _ldType : "docGroup", |
| |
| create : function (parent, json) { |
| var obj = Object.create(jsonldClass).upgradeTo(this); |
| obj._operands = []; |
| obj.fromJson(json); |
| if (parent !== undefined) |
| obj._parent = parent; |
| return obj; |
| }, |
| |
| newAfter : function (obj) { |
| for (var i = 0; i < this._operands.length; i++) { |
| if (this._operands[i] === obj) { |
| var operand = unspecClass.create(this); |
| this._operands.splice(i + 1, 0, operand); |
| return this.update(); |
| }; |
| }; |
| }, |
| |
| // The doc is already set in the group |
| _duplicate : function (operand) { |
| |
| // TODO: |
| // Also check for duplicate docGroupRefs! |
| |
| if (operand.ldType() !== 'doc') |
| return null; |
| |
| for (var i = 0; i < this._operands.length; i++) { |
| var op = this.getOperand(i); |
| if (op.ldType() === 'doc' |
| && operand.key() === op.key() |
| && operand.matchop() === op.matchop() |
| && operand.value() === op.value()) { |
| return op; |
| }; |
| }; |
| return null; |
| }, |
| |
| append : function (operand) { |
| |
| // Append unspecified object |
| if (operand === undefined) { |
| |
| // Be aware of cyclic structures! |
| operand = unspecClass.create(this); |
| this._operands.push(operand); |
| return operand; |
| }; |
| |
| switch (operand["@type"]) { |
| |
| case undefined: |
| // No @type defined |
| if (operand["ldType"] !== undefined) { |
| if (operand.ldType() !== 'doc' && |
| operand.ldType() !== 'docGroup' && |
| operand.ldType() !== 'docGroupRef') { |
| KorAP.log(812, "Operand not supported in document group"); |
| return; |
| }; |
| |
| // Be aware of cyclic structures! |
| operand.parent(this); |
| |
| var dupl = this._duplicate(operand); |
| if (dupl === null) { |
| this._operands.push(operand); |
| return operand; |
| }; |
| return dupl; |
| }; |
| |
| KorAP.log(701, "JSON-LD group has no @type attribute"); |
| return; |
| |
| case "koral:doc": |
| // Be aware of cyclic structures! |
| var doc = docClass.create(this, operand); |
| if (doc === undefined) |
| return; |
| var dupl = this._duplicate(doc); |
| if (dupl === null) { |
| this._operands.push(doc); |
| return doc; |
| }; |
| return dupl; |
| |
| case "koral:docGroup": |
| // Be aware of cyclic structures! |
| var docGroup = docGroupClass.create(this, operand); |
| if (docGroup === undefined) |
| return; |
| |
| // Flatten group |
| if (docGroup.operation() === this.operation()) { |
| for (var op in docGroup.operands()) { |
| op = docGroup.getOperand(op); |
| var dupl = this._duplicate(op); |
| if (dupl === null) { |
| this._operands.push(op); |
| op.parent(this); |
| }; |
| }; |
| docGroup._operands = []; |
| docGroup.destroy(); |
| return this; |
| }; |
| this._operands.push(docGroup); |
| return docGroup; |
| |
| case "koral:docGroupRef": |
| |
| var docGroupRef = docGroupRefClass.create(this, operand); |
| |
| if (docGroupRef === undefined) { |
| return |
| }; |
| |
| // TODO: |
| // Currently this doesn't do anything meaningful, |
| // as duplicate only checks on docs for the moment |
| /* |
| var dupl = this._duplicate(doc); |
| if (dupl === null) { |
| this._operands.push(doc); |
| return doc; |
| }; |
| return dupl; |
| */ |
| this._operands.push(docGroupRef); |
| return docGroupRef; |
| |
| default: |
| KorAP.log(812, "Operand not supported in document group"); |
| return; |
| }; |
| }, |
| |
| update : function () { |
| // There is only one operand in group |
| |
| if (this._operands.length === 1) { |
| |
| var parent = this.parent(); |
| var op = this.getOperand(0); |
| |
| // This will prevent destruction of |
| // the operand |
| this._operands = []; |
| |
| // Parent is a group |
| if (parent.ldType() !== null) |
| return parent.replaceOperand(this, op).update(); |
| |
| // Parent is vc |
| else { |
| this.destroy(); |
| // Cyclic madness |
| parent.root(op); |
| op.parent(parent); |
| return parent.root(); |
| }; |
| }; |
| |
| if (this._element === undefined) |
| return this; |
| |
| var group = this._element; |
| group.setAttribute('data-operation', this.operation()); |
| |
| _removeChildren(group); |
| |
| // Append operands |
| for (var i = 0; i < this._operands.length; i++) { |
| group.appendChild( |
| this.getOperand(i).element() |
| ); |
| }; |
| |
| // Set operators |
| var op = this.operators( |
| this.operation() == 'and' ? false : true, |
| this.operation() == 'or' ? false : true, |
| true |
| ); |
| |
| group.appendChild(op.element()); |
| |
| if (KorAP.vc) { |
| var vcchevent = new CustomEvent('vcChange', {'detail':this}); |
| KorAP.vc.element().dispatchEvent(vcchevent); |
| }; |
| |
| return this; |
| }, |
| |
| element : function () { |
| if (this._element !== undefined) |
| return this._element; |
| |
| this._element = document.createElement('div'); |
| this._element.setAttribute('class', 'docGroup'); |
| |
| // Update the object - including optimization |
| this.update(); |
| |
| return this._element; |
| }, |
| |
| operation : function (op) { |
| if (arguments.length === 1) { |
| if (_validGroupOpRE.test(op)) { |
| this._op = op; |
| } |
| else { |
| KorAP.log(810, "Unknown operation type"); |
| return; |
| }; |
| }; |
| return this._op || 'and'; |
| }, |
| |
| operands : function () { |
| return this._operands; |
| }, |
| |
| getOperand : function (index) { |
| return this._operands[index]; |
| }, |
| |
| // Replace operand |
| replaceOperand : function (oldOp, newOp) { |
| |
| for (var i = 0; i < this._operands.length; i++) { |
| if (this._operands[i] === oldOp) { |
| |
| // Just insert a doc or ... |
| if (newOp.ldType() === "doc" || |
| newOp.ldType() === "non" || |
| newOp.ldType() === 'docGroupRef' || |
| // ... insert a group of a different operation |
| // (i.e. "and" in "or"/"or" in "and") |
| newOp.operation() != this.operation()) { |
| this._operands[i] = newOp; |
| newOp.parent(this); |
| } |
| |
| // Flatten group |
| else { |
| // Remove old group |
| this._operands.splice(i, 1); |
| |
| // Inject new operands |
| for (var op in newOp.operands().reverse()) { |
| op = newOp.getOperand(op); |
| this._operands.splice(i, 0, op); |
| op.parent(this); |
| }; |
| // Prevent destruction of operands |
| newOp._operands = []; |
| newOp.destroy(); |
| }; |
| oldOp.destroy(); |
| return this; |
| } |
| }; |
| return false; |
| }, |
| |
| // Delete operand from group |
| delOperand : function (obj) { |
| for (var i = 0; i < this._operands.length; i++) { |
| if (this._operands[i] === obj) { |
| |
| // Delete identified operand |
| this._operands.splice(i,1); |
| |
| // Destroy object for cyclic references |
| obj.destroy(); |
| |
| return this; |
| }; |
| }; |
| |
| // Operand not found |
| return undefined; |
| }, |
| |
| // Deserialize from json |
| fromJson : function (json) { |
| if (json === undefined) |
| return this; |
| |
| if (json["@type"] === undefined) { |
| KorAP.log(701, "JSON-LD group has no @type attribute"); |
| return; |
| }; |
| |
| if (json["operation"] === undefined || |
| typeof json["operation"] !== 'string') { |
| KorAP.log(811, "Document group expects operation"); |
| return; |
| }; |
| |
| var operation = json["operation"]; |
| |
| this.operation(operation.replace(/^operation:/,'')); |
| |
| if (json["operands"] === undefined || |
| !(json["operands"] instanceof Array)) { |
| KorAP.log(704, "Operation needs operand list") |
| return; |
| }; |
| |
| // Add all documents |
| for (var i in json["operands"]) { |
| var operand = json["operands"][i]; |
| this.append(operand); |
| }; |
| |
| return this; |
| }, |
| |
| toJson : function () { |
| var opArray = new Array(); |
| for (var i = 0; i < this._operands.length; i++) { |
| if (this._operands[i].ldType() !== 'non') |
| opArray.push(this._operands[i].toJson()); |
| }; |
| return { |
| "@type" : "koral:" + this.ldType(), |
| "operation" : "operation:" + this.operation(), |
| "operands" : opArray |
| }; |
| }, |
| |
| toQuery : function (brackets) { |
| var list = this._operands |
| .filter(function (op) { |
| return !op.incomplete(); |
| }) |
| .map(function (op) { |
| return (op.ldType() === 'docGroup') ? |
| op.toQuery(true) : |
| op.toQuery(); |
| }); |
| |
| if (list.length === 1) |
| return list.join(''); |
| else { |
| var str = list.join(this.operation() === 'or' ? ' | ' : ' & '); |
| return brackets ? '(' + str + ')' : str; |
| }; |
| } |
| }; |
| return docGroupClass; |
| }); |