Test events (deletion and extension with 'and' and 'or')
diff --git a/public/js/demo/vc.html b/public/js/demo/vc.html
index 372571c..79f7d0e 100644
--- a/public/js/demo/vc.html
+++ b/public/js/demo/vc.html
@@ -66,6 +66,9 @@
}
]
};
+ KorAP.Locale.AND = 'und';
+ KorAP.Locale.OR = 'oder';
+
var vc = KorAP.VirtualCollection.render(json);
document.getElementById('vc').appendChild(vc.element());
diff --git a/public/js/spec/vcSpec.js b/public/js/spec/vcSpec.js
index 767f010..32a018f 100644
--- a/public/js/spec/vcSpec.js
+++ b/public/js/spec/vcSpec.js
@@ -465,7 +465,7 @@
var docElement = doc.element();
expect(docElement.getAttribute('class')).toEqual('doc unspecified');
expect(docElement.firstChild.firstChild.data).toEqual('⋯');
- expect(docElement.lastChild.getAttribute('class')).toEqual('operators');
+ expect(docElement.lastChild.lastChild.data).toEqual('⋯');
expect(doc.toQuery()).toEqual('⋯');
// Only removable
@@ -1060,3 +1060,372 @@
expect(e.children[1].firstChild.data).toEqual('or');
});
});
+
+describe('KorAP._delete (event)', function () {
+ var complexVCFactory = buildFactory(KorAP.VirtualCollection,{
+ "@type": 'korap:docGroup',
+ 'operation' : 'operation:and',
+ 'operands' : [
+ {
+ "@type": 'korap:doc',
+ "key": 'pubDate',
+ "match": 'match:eq',
+ "value": '2014-12-05',
+ "type": 'type:date'
+ },
+ {
+ "@type" : 'korap:docGroup',
+ 'operation' : 'operation:or',
+ 'operands' : [
+ {
+ '@type' : 'korap:doc',
+ 'key' : 'title',
+ 'value' : 'Hello World!'
+ },
+ {
+ '@type' : 'korap:doc',
+ 'key' : 'foo',
+ 'value' : 'bar'
+ }
+ ]
+ }
+ ]
+ });
+
+ it('should clean on root docs', function () {
+ var vc = KorAP.VirtualCollection.render({
+ "@type": 'korap:doc',
+ "key": 'pubDate',
+ "match": 'match:eq',
+ "value": '2014-12-05',
+ "type": 'type:date'
+ });
+ expect(vc.root().toQuery()).toEqual('pubDate in 2014-12-05');
+ expect(vc.root().element().lastChild.getAttribute('class')).toEqual('operators');
+
+ // Clean with delete from root
+ expect(vc.root().element().lastChild.lastChild.getAttribute('class')).toEqual('delete');
+ KorAP._delete.bind(vc.root().element().lastChild.lastChild).apply();
+ expect(vc.root().toQuery()).toEqual('⋯');
+ expect(vc.root().element().lastChild.lastChild.data).toEqual('⋯');
+ });
+
+ it ('should remove on nested docs', function () {
+ var vc = KorAP.VirtualCollection.render(
+ {
+ "@type": 'korap:docGroup',
+ 'operation' : 'operation:and',
+ 'operands' : [
+ {
+ "@type": 'korap:doc',
+ "key": 'pubDate',
+ "match": 'match:eq',
+ "value": '2014-12-05',
+ "type": 'type:date'
+ },
+ {
+ "@type" : 'korap:doc',
+ 'key' : 'foo',
+ 'value' : 'bar'
+ }
+ ]
+ }
+ );
+
+ // Delete with direct element access
+ expect(vc.toQuery()).toEqual('pubDate in 2014-12-05 & foo = "bar"');
+ KorAP._delete.bind(vc.root().getOperand(0).element().lastChild.lastChild).apply();
+ expect(vc.toQuery()).toEqual('foo = "bar"');
+ expect(vc.root().ldType()).toEqual('doc');
+ });
+
+ it ('should clean on doc groups', function () {
+ var vc = KorAP.VirtualCollection.render(
+ {
+ "@type": 'korap:docGroup',
+ 'operation' : 'operation:and',
+ 'operands' : [
+ {
+ "@type": 'korap:doc',
+ "key": 'pubDate',
+ "match": 'match:eq',
+ "value": '2014-12-05',
+ "type": 'type:date'
+ },
+ {
+ "@type" : 'korap:doc',
+ 'key' : 'foo',
+ 'value' : 'bar'
+ }
+ ]
+ }
+ );
+
+ // Cleanwith direct element access
+ expect(vc.toQuery()).toEqual('pubDate in 2014-12-05 & foo = "bar"');
+ KorAP._delete.bind(vc.root().element().lastChild.lastChild).apply();
+ expect(vc.toQuery()).toEqual('⋯');
+ expect(vc.root().ldType()).toEqual('non');
+ });
+
+ it ('should remove on nested doc groups (case of ungrouping 1)', function () {
+ var vc = complexVCFactory.create();
+
+ // Delete with direct element access
+ expect(vc.toQuery()).toEqual(
+ 'pubDate in 2014-12-05 & (title = "Hello World!" | foo = "bar")'
+ );
+
+ // Remove hello world:
+ KorAP._delete.bind(vc.root().getOperand(1).getOperand(0).element().lastChild.lastChild).apply();
+ expect(vc.toQuery()).toEqual('pubDate in 2014-12-05 & foo = "bar"');
+ expect(vc.root().ldType()).toEqual('docGroup');
+ });
+
+ it ('should remove on nested doc groups (case of ungrouping 2)', function () {
+ var vc = complexVCFactory.create();
+
+ // Delete with direct element access
+ expect(vc.toQuery()).toEqual(
+ 'pubDate in 2014-12-05 & (title = "Hello World!" | foo = "bar")'
+ );
+
+ // Remove bar
+ KorAP._delete.bind(vc.root().getOperand(1).getOperand(1).element().lastChild.lastChild).apply();
+ expect(vc.toQuery()).toEqual('pubDate in 2014-12-05 & title = "Hello World!"');
+ expect(vc.root().ldType()).toEqual('docGroup');
+ expect(vc.root().operation()).toEqual('and');
+ });
+
+ it ('should remove on nested doc groups (case of root changing)', function () {
+ var vc = complexVCFactory.create();
+
+ // Delete with direct element access
+ expect(vc.toQuery()).toEqual(
+ 'pubDate in 2014-12-05 & (title = "Hello World!" | foo = "bar")'
+ );
+
+ // Remove bar
+ KorAP._delete.bind(vc.root().getOperand(0).element().lastChild.lastChild).apply();
+ expect(vc.toQuery()).toEqual('title = "Hello World!" | foo = "bar"');
+ expect(vc.root().ldType()).toEqual('docGroup');
+ expect(vc.root().operation()).toEqual('or');
+ });
+
+ it ('should remove on nested doc groups (list flattening)', function () {
+ var vc = KorAP.VirtualCollection.render(
+ {
+ "@type": 'korap:docGroup',
+ 'operation' : 'operation:or',
+ 'operands' : [
+ {
+ "@type": 'korap:doc',
+ "key": 'pubDate',
+ "match": 'match:eq',
+ "value": '2014-12-05',
+ "type": 'type:date'
+ },
+ {
+ "@type" : 'korap:doc',
+ 'key' : 'foo',
+ 'value' : 'bar'
+ },
+ {
+ "@type": 'korap:docGroup',
+ 'operation' : 'operation:and',
+ 'operands' : [
+ {
+ "@type": 'korap:doc',
+ "key": 'pubDate',
+ "match": 'match:eq',
+ "value": '2014-12-05',
+ "type": 'type:date'
+ },
+ {
+ "@type" : 'korap:docGroup',
+ 'operation' : 'operation:or',
+ 'operands' : [
+ {
+ '@type' : 'korap:doc',
+ 'key' : 'title',
+ 'value' : 'Hello World!'
+ },
+ {
+ '@type' : 'korap:doc',
+ 'key' : 'yeah',
+ 'value' : 'juhu'
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ );
+
+ // Delete with direct element access
+ expect(vc.toQuery()).toEqual(
+ 'pubDate in 2014-12-05 | foo = "bar" | ' +
+ '(pubDate in 2014-12-05 & ' +
+ '(title = "Hello World!" | yeah = "juhu"))'
+ );
+
+ expect(vc.root().ldType()).toEqual('docGroup');
+ expect(vc.root().operation()).toEqual('or');
+
+ // Operands and operators
+ expect(vc.element().firstChild.children.length).toEqual(4);
+ expect(vc.element().firstChild.lastChild.getAttribute('class')).toEqual('operators');
+
+ // Remove inner group and flatten
+ KorAP._delete.bind(
+ vc.root().getOperand(2).getOperand(0).element().lastChild.lastChild
+ ).apply();
+
+ expect(vc.toQuery()).toEqual(
+ 'pubDate in 2014-12-05 | foo = "bar" | title = "Hello World!" | yeah = "juhu"'
+ );
+ expect(vc.root().ldType()).toEqual('docGroup');
+ expect(vc.root().operation()).toEqual('or');
+
+ // Operands and operators
+ expect(vc.element().firstChild.children.length).toEqual(5);
+ expect(vc.element().firstChild.lastChild.getAttribute('class')).toEqual('operators');
+ });
+});
+
+describe('KorAP._add (event)', function () {
+ var complexVCFactory = buildFactory(KorAP.VirtualCollection,{
+ "@type": 'korap:docGroup',
+ 'operation' : 'operation:and',
+ 'operands' : [
+ {
+ "@type": 'korap:doc',
+ "key": 'pubDate',
+ "match": 'match:eq',
+ "value": '2014-12-05',
+ "type": 'type:date'
+ },
+ {
+ "@type" : 'korap:docGroup',
+ 'operation' : 'operation:or',
+ 'operands' : [
+ {
+ '@type' : 'korap:doc',
+ 'key' : 'title',
+ 'value' : 'Hello World!'
+ },
+ {
+ '@type' : 'korap:doc',
+ 'key' : 'foo',
+ 'value' : 'bar'
+ }
+ ]
+ }
+ ]
+ });
+
+ it ('should add new unspecified doc with "and"', function () {
+ var vc = KorAP.VirtualCollection.render(
+ {
+ "@type": 'korap:docGroup',
+ 'operation' : 'operation:and',
+ 'operands' : [
+ {
+ "@type": 'korap:doc',
+ "key": 'pubDate',
+ "match": 'match:eq',
+ "value": '2014-12-05',
+ "type": 'type:date'
+ },
+ {
+ "@type" : 'korap:doc',
+ 'key' : 'foo',
+ 'value' : 'bar'
+ }
+ ]
+ }
+ );
+
+ expect(vc.toQuery()).toEqual('pubDate in 2014-12-05 & foo = "bar"');
+
+ var fc = vc.element().firstChild;
+ expect(fc.getAttribute('data-operation')).toEqual('and');
+ expect(fc.children.length).toEqual(3);
+ expect(fc.lastChild.getAttribute('class')).toEqual('operators');
+ expect(fc.children[0].getAttribute('class')).toEqual('doc');
+ expect(fc.children[1].getAttribute('class')).toEqual('doc');
+
+ // add with 'and' in the middle
+ KorAP._and.bind(vc.root().getOperand(0).element().lastChild.lastChild).apply();
+ expect(vc.toQuery()).toEqual('pubDate in 2014-12-05 & foo = "bar"');
+
+ fc = vc.element().firstChild;
+ expect(fc.getAttribute('data-operation')).toEqual('and');
+ expect(fc.children.length).toEqual(4);
+ expect(fc.lastChild.getAttribute('class')).toEqual('operators');
+
+ expect(fc.children[0].getAttribute('class')).toEqual('doc');
+ expect(fc.children[1].getAttribute('class')).toEqual('doc unspecified');
+ expect(fc.children[2].getAttribute('class')).toEqual('doc');
+ });
+
+ it ('should add new unspecified doc with "or"', function () {
+ var vc = KorAP.VirtualCollection.render(
+ {
+ "@type": 'korap:docGroup',
+ 'operation' : 'operation:and',
+ 'operands' : [
+ {
+ "@type": 'korap:doc',
+ "key": 'pubDate',
+ "match": 'match:eq',
+ "value": '2014-12-05',
+ "type": 'type:date'
+ },
+ {
+ "@type" : 'korap:doc',
+ 'key' : 'foo',
+ 'value' : 'bar'
+ }
+ ]
+ }
+ );
+
+ expect(vc.toQuery()).toEqual('pubDate in 2014-12-05 & foo = "bar"');
+
+ var fc = vc.element().firstChild;
+ expect(fc.children.length).toEqual(3);
+ expect(fc.lastChild.getAttribute('class')).toEqual('operators');
+ expect(fc.children[0].getAttribute('class')).toEqual('doc');
+ expect(fc.children[1].getAttribute('class')).toEqual('doc');
+
+ // add with 'or' in the middle
+ KorAP._or.bind(vc.root().getOperand(0).element().lastChild.lastChild).apply();
+ expect(vc.toQuery()).toEqual('pubDate in 2014-12-05 & foo = "bar"');
+ fc = vc.element().firstChild;
+
+ expect(fc.getAttribute('data-operation')).toEqual('and');
+ expect(fc.children.length).toEqual(3);
+ expect(fc.children[0].getAttribute('class')).toEqual('docGroup');
+ expect(fc.children[0].getAttribute('data-operation')).toEqual('or');
+ expect(fc.children[1].getAttribute('class')).toEqual('doc');
+ expect(fc.children[2].getAttribute('class')).toEqual('operators');
+ expect(fc.lastChild.getAttribute('class')).toEqual('operators');
+
+ fc = vc.element().firstChild.firstChild;
+ expect(fc.children.length).toEqual(3);
+ expect(fc.children[0].getAttribute('class')).toEqual('doc');
+ expect(fc.children[1].getAttribute('class')).toEqual('doc unspecified');
+ expect(fc.children[2].getAttribute('class')).toEqual('operators');
+ expect(fc.lastChild.getAttribute('class')).toEqual('operators');
+ });
+
+ // Todo: wrap on root!!
+});
+
+/*
+ Todo: test event sequences:
+ - In a nested group with a 'doc' and a 'non', remove the 'doc',
+ so the 'non' needs to be flattened!
+*/
diff --git a/public/js/src/vc.js b/public/js/src/vc.js
index 06fcb18..09d20ea 100644
--- a/public/js/src/vc.js
+++ b/public/js/src/vc.js
@@ -34,6 +34,7 @@
KorAP._validGroupOpRE = new RegExp("^(?:and|or)$");
KorAP._quote = new RegExp("([\"\\\\])", 'g');
+ // Localization values
var loc = (KorAP.Locale = KorAP.Locale || {} );
loc.AND = loc.AND || 'and';
loc.OR = loc.OR || 'or';
@@ -41,11 +42,13 @@
loc.EMPTY = loc.EMPTY || '⋯'
+ // Utility for analysing boolean values
function _bool (bool) {
- return (bool === undefined || bool === false) ? false : true;
+ return (bool === undefined || bool === null || bool === false) ? false : true;
};
+ // Utility for removing all children of a node
function _removeChildren (node) {
// Remove everything underneath
while (node.firstChild)
@@ -72,8 +75,19 @@
};
+ // Add doc with 'and' relation
+ KorAP._and = function () {
+ return KorAP._add(this, 'and');
+ };
+
+
+ // Add doc with 'or' relation
+ KorAP._or = function () {
+ return KorAP._add(this, 'or');
+ };
+
// Remove doc or docGroup
- KorAP._delete = function (e) {
+ KorAP._delete = function () {
var ref = this.parentNode.refTo;
if (ref.parent().ldType() !== null)
ref.parent().delOperand(ref).update();
@@ -208,7 +222,7 @@
if (this._and === true) {
var andE = document.createElement('span');
andE.setAttribute('class', 'and');
- andE.addEventListener('click', function () { return KorAP._add(this, 'and') }, false);
+ andE.addEventListener('click', KorAP._and, false);
andE.appendChild(
document.createTextNode(KorAP.Locale.AND)
);
@@ -219,7 +233,7 @@
if (this._or === true) {
var orE = document.createElement('span');
orE.setAttribute('class', 'or');
- orE.addEventListener('click', function () { return KorAP._add(this, 'or') }, false);
+ orE.addEventListener('click', KorAP._or, false);
orE.appendChild(document.createTextNode(KorAP.Locale.OR));
op.appendChild(orE);
};
@@ -305,17 +319,17 @@
this._element.appendChild(ellipsis);
// Set operators
- var op = this.operators(
- false,
- false,
- // No delete object, if this is the root
- (this._parent !== undefined &&
- this.parent().ldType() !== null) ? true : false
- );
+ if (this._parent !== undefined && this.parent().ldType() !== null) {
+ var op = this.operators(
+ false,
+ false,
+ true
+ );
- this._element.appendChild(
- op.element()
- );
+ this._element.appendChild(
+ op.element()
+ );
+ };
return this.element();
},
@@ -793,14 +807,11 @@
for (var i in this._operands) {
if (this._operands[i] === oldOp) {
- // Just insert a doc
- if (newOp.ldType() === "doc") {
- this._operands[i] = newOp;
- newOp.parent(this);
- }
- // Insert a group of a different operation
- // (i.e. "and" in "or"/"or" in "and")
- else if (newOp.operation() != this.operation()) {
+ // Just insert a doc or ...
+ if (newOp.ldType() === "doc" ||
+ // ... 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);
}
@@ -883,7 +894,8 @@
toJson : function () {
var opArray = new Array();
for (var i in this._operands) {
- opArray.push(this._operands[i].toJson());
+ if (this._operands[i].ldType() !== 'non')
+ opArray.push(this._operands[i].toJson());
};
return {
"@type" : "korap:" + this.ldType(),
@@ -892,13 +904,23 @@
};
},
- toQuery : function () {
- return this._operands.
- map(function (op) {
+ toQuery : function (brackets) {
+ var list = this._operands
+ .filter(function (op) {
+ return op.ldType() !== 'non';
+ })
+ .map(function (op) {
return (op.ldType() === 'docGroup') ?
- '(' + op.toQuery() + ')' :
+ op.toQuery(true) :
op.toQuery();
- }).join(this.operation() === 'or' ? ' | ' : ' & ')
+ });
+
+ if (list.length === 1)
+ return list.join('');
+ else {
+ var str = list.join(this.operation() === 'or' ? ' | ' : ' & ');
+ return brackets ? '(' + str + ')' : str;
+ };
}
};