Fixed root wrapping and operand arithmetics (I'm an idiot ... sigh)
diff --git a/public/js/spec/vcSpec.js b/public/js/spec/vcSpec.js
index 4ac18a8..88b4734 100644
--- a/public/js/spec/vcSpec.js
+++ b/public/js/spec/vcSpec.js
@@ -17,6 +17,68 @@
}
};
+function _andOn (obj) {
+ KorAP._and.bind(obj.element().lastChild.firstChild).apply();
+};
+
+function _orOn (obj) {
+ KorAP._or.bind(obj.element().lastChild.firstChild).apply();
+};
+
+function _delOn (obj) {
+ KorAP._delete.bind(obj.element().lastChild.firstChild).apply();
+};
+
+var demoFactory = buildFactory(KorAP.VirtualCollection, {
+ "@type":"korap:docGroup",
+ "operation":"operation:or",
+ "operands":[
+ {
+ "@type":"korap:docGroup",
+ "operation":"operation:and",
+ "operands":[
+ {
+ "@type":"korap:doc",
+ "key":"Titel",
+ "value":"Baum",
+ "match":"match:eq"
+ },
+ {
+ "@type":"korap:doc",
+ "key":"Veröffentlichungsort",
+ "value":"hihi",
+ "match":"match:eq"
+ },
+ {
+ "@type":"korap:docGroup",
+ "operation":"operation:or",
+ "operands":[
+ {
+ "@type":"korap:doc",
+ "key":"Titel",
+ "value":"Baum",
+ "match":"match:eq"
+ },
+ {
+ "@type":"korap:doc",
+ "key":"Veröffentlichungsort",
+ "value":"hihi",
+ "match":"match:eq"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "@type":"korap:doc",
+ "key":"Untertitel",
+ "value":"huhu",
+ "match":"match:eq"
+ }
+ ]
+});
+
+
describe('KorAP.Doc', function () {
// Create example factories
@@ -728,55 +790,6 @@
}
]
});
-
- var demoFactory = buildFactory(KorAP.VirtualCollection, {
- "@type":"korap:docGroup",
- "operation":"operation:or",
- "operands":[
- {
- "@type":"korap:docGroup",
- "operation":"operation:and",
- "operands":[
- {
- "@type":"korap:doc",
- "key":"Titel",
- "value":"Baum",
- "match":"match:eq"
- },
- {
- "@type":"korap:doc",
- "key":"Veröffentlichungsort",
- "value":"hihi",
- "match":"match:eq"
- },
- {
- "@type":"korap:docGroup",
- "operation":"operation:or",
- "operands":[
- {
- "@type":"korap:doc",
- "key":"Titel",
- "value":"Baum",
- "match":"match:eq"
- },
- {
- "@type":"korap:doc",
- "key":"Veröffentlichungsort",
- "value":"hihi",
- "match":"match:eq"
- }
- ]
- }
- ]
- },
- {
- "@type":"korap:doc",
- "key":"Untertitel",
- "value":"huhu",
- "match":"match:eq"
- }
- ]
- });
it('should be initializable', function () {
var vc = KorAP.VirtualCollection.render();
@@ -1105,7 +1118,7 @@
// Clean with delete from root
expect(vc.root().element().lastChild.lastChild.getAttribute('class')).toEqual('delete');
- KorAP._delete.bind(vc.root().element().lastChild.lastChild).apply();
+ _delOn(vc.root());
expect(vc.root().toQuery()).toEqual('⋯');
expect(vc.root().element().lastChild.lastChild.data).toEqual('⋯');
});
@@ -1134,7 +1147,8 @@
// 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();
+ _delOn(vc.root().getOperand(0));
+
expect(vc.toQuery()).toEqual('foo = "bar"');
expect(vc.root().ldType()).toEqual('doc');
});
@@ -1163,7 +1177,7 @@
// Cleanwith direct element access
expect(vc.toQuery()).toEqual('pubDate in 2014-12-05 & foo = "bar"');
- KorAP._delete.bind(vc.root().element().lastChild.lastChild).apply();
+ _delOn(vc.root());
expect(vc.toQuery()).toEqual('⋯');
expect(vc.root().ldType()).toEqual('non');
});
@@ -1177,7 +1191,7 @@
);
// Remove hello world:
- KorAP._delete.bind(vc.root().getOperand(1).getOperand(0).element().lastChild.lastChild).apply();
+ _delOn(vc.root().getOperand(1).getOperand(0));
expect(vc.toQuery()).toEqual('pubDate in 2014-12-05 & foo = "bar"');
expect(vc.root().ldType()).toEqual('docGroup');
});
@@ -1191,7 +1205,7 @@
);
// Remove bar
- KorAP._delete.bind(vc.root().getOperand(1).getOperand(1).element().lastChild.lastChild).apply();
+ _delOn(vc.root().getOperand(1).getOperand(1));
expect(vc.toQuery()).toEqual('pubDate in 2014-12-05 & title = "Hello World!"');
expect(vc.root().ldType()).toEqual('docGroup');
expect(vc.root().operation()).toEqual('and');
@@ -1206,7 +1220,7 @@
);
// Remove bar
- KorAP._delete.bind(vc.root().getOperand(0).element().lastChild.lastChild).apply();
+ _delOn(vc.root().getOperand(0));
expect(vc.toQuery()).toEqual('title = "Hello World!" | foo = "bar"');
expect(vc.root().ldType()).toEqual('docGroup');
expect(vc.root().operation()).toEqual('or');
@@ -1278,9 +1292,7 @@
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();
+ _delOn(vc.root().getOperand(2).getOperand(0));
expect(vc.toQuery()).toEqual(
'pubDate in 2014-12-05 | foo = "bar" | title = "Hello World!" | yeah = "juhu"'
@@ -1357,7 +1369,7 @@
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();
+ _andOn(vc.root().getOperand(0));
expect(vc.toQuery()).toEqual('pubDate in 2014-12-05 & foo = "bar"');
fc = vc.element().firstChild;
@@ -1401,7 +1413,7 @@
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();
+ _orOn(vc.root().getOperand(0));
expect(vc.toQuery()).toEqual('pubDate in 2014-12-05 & foo = "bar"');
fc = vc.element().firstChild;
@@ -1421,7 +1433,103 @@
expect(fc.lastChild.getAttribute('class')).toEqual('operators');
});
- it ('should wrap on group (case "and")', function () {
+ it ('should add new unspecified doc with "and" before group', function () {
+ var vc = demoFactory.create();
+
+ // Wrap with direct element access
+ expect(vc.toQuery()).toEqual(
+ '(Titel = "Baum" & Veröffentlichungsort = "hihi" & (Titel = "Baum" | Veröffentlichungsort = "hihi")) | Untertitel = "huhu"'
+ );
+
+ expect(vc.root().getOperand(0).ldType()).toEqual('docGroup');
+ expect(vc.root().getOperand(0).operation()).toEqual('and');
+ expect(vc.root().getOperand(0).operands().length).toEqual(3);
+
+ // Add unspecified on the second doc
+ var secDoc = vc.root().getOperand(0).getOperand(1);
+ expect(secDoc.value()).toEqual('hihi');
+
+ // Add
+ _andOn(secDoc);
+
+ var fo = vc.root().getOperand(0);
+
+ expect(fo.ldType()).toEqual('docGroup');
+ expect(fo.operation()).toEqual('and');
+ expect(fo.operands().length).toEqual(4);
+
+ expect(fo.getOperand(0).ldType()).toEqual('doc');
+ expect(fo.getOperand(1).ldType()).toEqual('doc');
+ expect(fo.getOperand(2).ldType()).toEqual('non');
+ expect(fo.getOperand(3).ldType()).toEqual('docGroup');
+ });
+
+
+ it ('should remove a doc with an unspecified doc in a nested group', function () {
+ var vc = demoFactory.create();
+
+ // Wrap with direct element access
+ expect(vc.toQuery()).toEqual(
+ '(Titel = "Baum" & Veröffentlichungsort = "hihi" & (Titel = "Baum" | Veröffentlichungsort = "hihi")) | Untertitel = "huhu"'
+ );
+
+ var fo = vc.root().getOperand(0).getOperand(0);
+ expect(fo.key()).toEqual('Titel');
+ expect(fo.value()).toEqual('Baum');
+
+ // Add unspecified on the root group
+ _orOn(fo);
+
+ fo = vc.root().getOperand(0).getOperand(0);
+
+ expect(fo.operation()).toEqual('or');
+ expect(fo.getOperand(0).ldType()).toEqual('doc');
+ expect(fo.getOperand(1).ldType()).toEqual('non');
+
+ // Delete document
+ _delOn(fo.getOperand(0));
+
+ // The operand is now non
+ expect(vc.root().getOperand(0).getOperand(0).ldType()).toEqual('non');
+ expect(vc.root().getOperand(0).getOperand(1).ldType()).toEqual('doc');
+ expect(vc.root().getOperand(0).getOperand(2).ldType()).toEqual('docGroup');
+ });
+
+ it ('should remove an unspecified doc with an doc in a nested group', function () {
+ var vc = demoFactory.create();
+
+ // Wrap with direct element access
+ expect(vc.toQuery()).toEqual(
+ '(Titel = "Baum" & Veröffentlichungsort = "hihi" & (Titel = "Baum" | Veröffentlichungsort = "hihi")) | Untertitel = "huhu"'
+ );
+
+ var fo = vc.root().getOperand(0).getOperand(0);
+ expect(fo.key()).toEqual('Titel');
+ expect(fo.value()).toEqual('Baum');
+
+ // Add unspecified on the root group
+ _orOn(fo);
+
+ fo = vc.root().getOperand(0).getOperand(0);
+
+ expect(fo.operation()).toEqual('or');
+ expect(fo.getOperand(0).ldType()).toEqual('doc');
+ expect(fo.getOperand(1).ldType()).toEqual('non');
+
+ // Delete unspecified doc
+ _delOn(fo.getOperand(1));
+
+ // The operand is now non
+ fo = vc.root().getOperand(0);
+ expect(fo.getOperand(0).ldType()).toEqual('doc');
+ expect(fo.getOperand(0).key()).toEqual('Titel');
+ expect(fo.getOperand(0).value()).toEqual('Baum');
+ expect(fo.getOperand(1).ldType()).toEqual('doc');
+ expect(fo.getOperand(2).ldType()).toEqual('docGroup');
+ });
+
+
+ it ('should add on parent group (case "and")', function () {
var vc = complexVCFactory.create();
// Wrap with direct element access
@@ -1429,20 +1537,41 @@
'pubDate in 2014-12-05 & (title = "Hello World!" | foo = "bar")'
);
- // Add unspecified
- KorAP._and.bind(vc.root().getOperand(1).element().lastChild.firstChild).apply();
+ expect(vc.root().operands().length).toEqual(2);
+
+ // Add unspecified on the root group
+ _andOn(vc.root().getOperand(1));
expect(vc.toQuery()).toEqual(
'pubDate in 2014-12-05 & (title = "Hello World!" | foo = "bar")'
);
+
expect(vc.root().ldType()).toEqual('docGroup');
+ expect(vc.root().operands().length).toEqual(3);
+ expect(vc.root().getOperand(0).ldType()).toEqual('doc');
expect(vc.root().getOperand(1).ldType()).toEqual('docGroup');
- expect(vc.root().getOperand(1).operation()).toEqual('and');
-/*
- expect(vc.root().operation()).toEqual('and');
-*/
+ expect(vc.root().getOperand(1).operation()).toEqual('or');
+ expect(vc.root().getOperand(2).ldType()).toEqual('non');
+
+ // Add another unspecified on the root group
+ _andOn(vc.root().getOperand(1));
+
+ expect(vc.root().operands().length).toEqual(4);
+ expect(vc.root().getOperand(0).ldType()).toEqual('doc');
+ expect(vc.root().getOperand(1).ldType()).toEqual('docGroup');
+ expect(vc.root().getOperand(2).ldType()).toEqual('non');
+ expect(vc.root().getOperand(3).ldType()).toEqual('non');
+
+ // Add another unspecified after the first doc
+ _andOn(vc.root().getOperand(0));
+
+ expect(vc.root().operands().length).toEqual(5);
+ expect(vc.root().getOperand(0).ldType()).toEqual('doc');
+ expect(vc.root().getOperand(1).ldType()).toEqual('non');
+ expect(vc.root().getOperand(2).ldType()).toEqual('docGroup');
+ expect(vc.root().getOperand(3).ldType()).toEqual('non');
+ expect(vc.root().getOperand(4).ldType()).toEqual('non');
});
-/*
it ('should wrap on root', function () {
var vc = KorAP.VirtualCollection.render(
{
@@ -1465,17 +1594,58 @@
}
);
- // Delete with direct element access
+ // Wrap on root
expect(vc.toQuery()).toEqual('pubDate in 2014-12-05 & foo = "bar"');
- KorAP._or.bind(vc.root().element().lastChild.lastChild).apply();
+ expect(vc.root().ldType()).toEqual('docGroup');
+ expect(vc.root().operation()).toEqual('and');
+ _orOn(vc.root());
+ expect(vc.root().ldType()).toEqual('docGroup');
+ expect(vc.root().operation()).toEqual('or');
+
+ expect(vc.root().getOperand(0).ldType()).toEqual('docGroup');
+ expect(vc.root().getOperand(0).operation()).toEqual('and');
+ });
+
+ it ('should add on root (case "and")', function () {
+ var vc = KorAP.VirtualCollection.render(
+ {
+ "@type": 'korap:doc',
+ "key": 'pubDate',
+ "match": 'match:eq',
+ "value": '2014-12-05',
+ "type": 'type:date'
+ }
+ );
+
+ expect(vc.toQuery()).toEqual('pubDate in 2014-12-05');
+ expect(vc.root().ldType()).toEqual('doc');
+ expect(vc.root().key()).toEqual('pubDate');
+ expect(vc.root().value()).toEqual('2014-12-05');
+
+ // Wrap on root
+ _andOn(vc.root());
+ expect(vc.root().ldType()).toEqual('docGroup');
+ expect(vc.root().operation()).toEqual('and');
+ });
+
+ it ('should add on root (case "or")', function () {
+ var vc = KorAP.VirtualCollection.render(
+ {
+ "@type": 'korap:doc',
+ "key": 'pubDate',
+ "match": 'match:eq',
+ "value": '2014-12-05',
+ "type": 'type:date'
+ }
+ );
+
+ expect(vc.toQuery()).toEqual('pubDate in 2014-12-05');
+ expect(vc.root().key()).toEqual('pubDate');
+ expect(vc.root().value()).toEqual('2014-12-05');
+
+ // Wrap on root
+ _orOn(vc.root());
expect(vc.root().ldType()).toEqual('docGroup');
expect(vc.root().operation()).toEqual('or');
});
-*/
});
-
-/*
- 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 d9cde4e..42e51c3 100644
--- a/public/js/src/vc.js
+++ b/public/js/src/vc.js
@@ -1,8 +1,9 @@
var KorAP = KorAP || {};
// TODO: Implement a working localization solution!
-// TODO: Support 'update' method to update elements on change
-// TODO: Implement "toQuery"
+// TODO: Remove "and" or "or" in case it's followed
+// by an unspecified document
+// TODO: Add 'or' or 'and' on root
/*
Error codes:
@@ -56,10 +57,11 @@
};
- // Add doc
+ // Add new unspecified document
KorAP._add = function (obj, type) {
var ref = obj.parentNode.refTo;
var parent = ref.parent();
+
if (ref.ldType() === 'docGroup') {
// Check that the action differs from the type
@@ -75,8 +77,11 @@
};
}
else if (ref.ldType() === 'doc') {
-// Todo: Check if parent is a group
- if (parent.operation() === type) {
+
+ if (parent.ldType() === null) {
+ return ref.wrapOnRoot(type);
+ }
+ else if (parent.operation() === type) {
return parent.newAfter(ref);
}
else {
@@ -97,13 +102,16 @@
return KorAP._add(this, 'or');
};
+
// Remove doc or docGroup
KorAP._delete = function () {
var ref = this.parentNode.refTo;
- if (ref.parent().ldType() !== null)
- ref.parent().delOperand(ref).update();
- else
+ if (ref.parent().ldType() !== null) {
+ return ref.parent().delOperand(ref).update();
+ }
+ else {
ref.parent().clean();
+ };
};
@@ -159,9 +167,7 @@
if (arguments.length === 1) {
var e = this.element();
if (e.firstChild !== null) {
- console.log(e.firstChild);
if (e.firstChild !== obj.element()) {
-console.log(e.firstChild);
e.replaceChild(obj.element(), e.firstChild);
};
}
@@ -669,7 +675,7 @@
},
newAfter : function (obj) {
- for (var i in this._operands) {
+ for (var i = 0; i < this._operands.length; i++) {
if (this._operands[i] === obj) {
var operand = KorAP.UnspecifiedDoc.create(this);
this._operands.splice(i + 1, 0, operand);
@@ -728,25 +734,11 @@
};
},
- // Wrap a new operation around the root group element
- wrapOnRoot : function () {
- var parent = this.parent();
-
- var group = KorAP.DocGroup.create(parent);
- group.operation(
- this.operation() === 'and' ? 'or' : 'and'
- );
- group.append(this);
- this.parent(group);
- group.append();
- group.element(); // Init (seems to be necessary)
- parent.root(group);
- return this.parent();
- },
-
update : function () {
// There is only one operand in group
+
if (this._operands.length === 1) {
+
var parent = this.parent();
var op = this.getOperand(0);
@@ -755,9 +747,8 @@
this._operands = [];
// Parent is a group
- if (parent.ldType() !== null) {
+ if (parent.ldType() !== null)
return parent.replaceOperand(this, op).update();
- }
// Parent is vc
else {
@@ -778,7 +769,7 @@
_removeChildren(group);
// Append operands
- for (var i in this._operands) {
+ for (var i = 0; i < this._operands.length; i++) {
group.appendChild(
this.getOperand(i).element()
);
@@ -834,11 +825,13 @@
// Replace operand
replaceOperand : function (oldOp, newOp) {
- for (var i in this._operands) {
+
+ 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" ||
// ... insert a group of a different operation
// (i.e. "and" in "or"/"or" in "and")
newOp.operation() != this.operation()) {
@@ -869,7 +862,7 @@
// Delete operand from group
delOperand : function (obj) {
- for (var i in this._operands) {
+ for (var i = 0; i < this._operands.length; i++) {
if (this._operands[i] === obj) {
// Delete identified operand
@@ -923,7 +916,7 @@
toJson : function () {
var opArray = new Array();
- for (var i in this._operands) {
+ for (var i = 0; i < this._operands.length; i++) {
if (this._operands[i].ldType() !== 'non')
opArray.push(this._operands[i].toJson());
};
@@ -1005,12 +998,31 @@
// In case of a group, destroy all operands
if (this._operands !== undefined) {
- for (var i in this._operands)
+ for (var i = 0; i < this._operands.length; i++)
this.getOperand(i).destroy();
this._operands = [];
};
},
+ // Wrap a new operation around the root group element
+ wrapOnRoot : function (op) {
+ var parent = this.parent();
+
+ var group = KorAP.DocGroup.create(parent);
+ if (arguments.length === 1)
+ group.operation(op);
+ else
+ group.operation(
+ this.operation() === 'and' ? 'or' : 'and'
+ );
+ group.append(this);
+ this.parent(group);
+ group.append();
+ group.element(); // Init (seems to be necessary)
+ parent.root(group);
+ return this.parent();
+ },
+
// Be aware! This may be cyclic
operators : function (and, or, del) {
if (arguments === 0)