Do not show multiple identical annotations in table view

Change-Id: I312a47a80cb9008216136712d2656144c11f1a33
diff --git a/Changes b/Changes
index 1171357..ce8ab1f 100755
--- a/Changes
+++ b/Changes
@@ -1,4 +1,4 @@
-0.21 2016-11-07
+0.21 2016-11-10
         - Use textSigle for API communication instead of
           {corpus,doc,text}ID.
         - Added alert to hint helper.
@@ -12,6 +12,9 @@
           initialization.
         - Improved compatibility for new text sigles.
         - Fixed alert to not be correctly hidden.
+        - Added download of tree visualizations.
+        - Do not show multiple identical annotations
+          in table view.
 
 0.20 2016-05-25
         - Improved menu using sliders.
diff --git a/dev/js/spec/matchSpec.js b/dev/js/spec/matchSpec.js
index ab3a00f..09c8da7 100644
--- a/dev/js/spec/matchSpec.js
+++ b/dev/js/spec/matchSpec.js
@@ -31,8 +31,10 @@
   "  <span title=\"cnx/p:ADV\">" +
   "    <span title=\"cnx/syn:@PREMOD\">" +
   "      <span title=\"mate/l:meist\">" +
-  "        <span title=\"mate/p:ADV\">" +
-  "          <span title=\"opennlp/p:ADV\">meist</span>" +
+  "        <span title=\"mate/l:meist\">" +
+  "          <span title=\"mate/p:ADV\">" +
+  "            <span title=\"opennlp/p:ADV\">meist</span>" +
+  "          </span>" +
   "        </span>" +
   "      </span>" +
   "    </span>" +
@@ -338,8 +340,8 @@
       expect(info).toBeTruthy();
 
       info.getTable([], function (tablen) {
-	table1 = tablen;
-	done();
+	      table1 = tablen;
+	      done();
       });
     });
 
@@ -350,8 +352,8 @@
     it('should load a working table async', function(done) {
       expect(info).toBeTruthy();
       info.getTable(undefined, function (tablem) {
-	table2 = tablem;
-	done();
+	      table2 = tablem;
+	      done();
       });
     });
     
@@ -366,9 +368,13 @@
 
       expect(table2.getValue(0, "cnx", "p")[0]).toBe("ADV");
       expect(table2.getValue(0, "cnx", "syn")[0]).toBe("@PREMOD");
+      expect(table2.getValue(0, "mate", "l")[0]).toBe("meist");
+      expect(table2.getValue(0, "mate", "l")[1]).toBeUndefined();
 
       expect(table2.getValue(2, "cnx", "l")[0]).toBe("fähig");
       expect(table2.getValue(2, "cnx", "l")[1]).toBe("leistung");
+
+      
     });
 
     it('should parse into a table view', function () {
diff --git a/dev/js/src/match/table.js b/dev/js/src/match/table.js
index 1a167d2..89ab555 100644
--- a/dev/js/src/match/table.js
+++ b/dev/js/src/match/table.js
@@ -52,7 +52,7 @@
      */
     getToken : function (pos) {
       if (pos === undefined)
-	return this._token;
+        return this._token;
       return this._token[pos];
     },
 
@@ -83,61 +83,66 @@
 
       // Get all children
       for (var i in children) {
-	var c = children[i];
+        var c = children[i];
 
-	// Create object on position unless it exists
-	if (this._info[this._pos] === undefined)
-	  this._info[this._pos] = {};
+        // Create object on position unless it exists
+        if (this._info[this._pos] === undefined) {
+          this._info[this._pos] = {};
+        };
 
-	// Store at position in foundry/layer as array
-	var found = this._info[this._pos];
+        // Store at position in foundry/layer as array
+        var found = this._info[this._pos];
 
-	// Element with title
-	if (c.nodeType === 1) {
-	  if (c.getAttribute("title") &&
-	      _TermRE.exec(c.getAttribute("title"))) {
+        // Element with title
+        if (c.nodeType === 1) {
+          if (c.getAttribute("title") &&
+              _TermRE.exec(c.getAttribute("title"))) {
 
-	    // Fill position with info
-	    var foundry, layer, value;
-	    if (RegExp.$2) {
-	      foundry = RegExp.$1;
-	      layer   = RegExp.$2;
-	    }
-	    else {
-	      foundry = "base";
-	      layer   = RegExp.$1
-	    };
+            // Fill position with info
+            var foundry, layer, value;
+            if (RegExp.$2) {
+              foundry = RegExp.$1;
+              layer   = RegExp.$2;
+            }
+            else {
+              foundry = "base";
+              layer   = RegExp.$1
+            };
 
-	    value = RegExp.$3;
-	    
-	    if (found[foundry + "/" + layer] === undefined)
-	      found[foundry + "/" + layer] = [];
+            value = RegExp.$3;
+      
+            if (found[foundry + "/" + layer] === undefined) {
+              found[foundry + "/" + layer] = [value];
+            }
+            else {
+              if (found[foundry + "/" + layer].indexOf(value) === -1) {
+                // Push value to foundry/layer at correct position
+                found[foundry + "/" + layer].push(value);
+              };
+            }
 
-	    // Push value to foundry/layer at correct position
-	    found[foundry + "/" + layer].push(RegExp.$3);
+            // Set foundry
+            if (this._foundry[foundry] === undefined)
+              this._foundry[foundry] = {};
+            this._foundry[foundry][layer] = 1;
 
-	    // Set foundry
-	    if (this._foundry[foundry] === undefined)
-	      this._foundry[foundry] = {};
-	    this._foundry[foundry][layer] = 1;
+            // Set layer
+            if (this._layer[layer] === undefined)
+              this._layer[layer] = {};
+            this._layer[layer][foundry] = 1;
+          };
 
-	    // Set layer
-	    if (this._layer[layer] === undefined)
-	      this._layer[layer] = {};
-	    this._layer[layer][foundry] = 1;
-	  };
+          // depth search
+          if (c.hasChildNodes())
+            this._parse(c.childNodes);
+        }
 
-	  // depth search
-	  if (c.hasChildNodes())
-	    this._parse(c.childNodes);
-	}
-
-	// Leaf node
-	// store string on position and go to next string
-	else if (c.nodeType === 3) {
-	  if (c.nodeValue.match(/[a-z0-9]/i))
-	    this._token[this._pos++] = c.nodeValue;
-	};
+        // Leaf node
+        // store string on position and go to next string
+        else if (c.nodeType === 3) {
+          if (c.nodeValue.match(/[a-z0-9]/i))
+            this._token[this._pos++] = c.nodeValue;
+        };
       };
 
       delete this._info[this._pos];
@@ -149,7 +154,7 @@
      */
     element : function () {
       if (this._element !== undefined)
-	return this._element;
+        return this._element;
 
       // First the legend table
       var d = document;
@@ -157,25 +162,25 @@
 
       // Single row in head
       var tr = table.appendChild(d.createElement('thead'))
-	.appendChild(d.createElement('tr'));
+          .appendChild(d.createElement('tr'));
 
       // Add cell to row
       var addCell = function (type, name) {
-	var c = this.appendChild(d.createElement(type))
-	if (name === undefined)
-	  return c;
+        var c = this.appendChild(d.createElement(type))
+        if (name === undefined)
+          return c;
 
-	if (name instanceof Array) {
-	  for (var n = 0; n < name.length; n++) {
-	    c.appendChild(d.createTextNode(name[n]));
-	    if (n !== name.length - 1) {
-	      c.appendChild(d.createElement('br'));
-	    };
-	  };
-	}
-	else {
-	  c.appendChild(d.createTextNode(name));
-	};
+        if (name instanceof Array) {
+          for (var n = 0; n < name.length; n++) {
+            c.appendChild(d.createTextNode(name[n]));
+            if (n !== name.length - 1) {
+              c.appendChild(d.createElement('br'));
+            };
+          };
+        }
+        else {
+          c.appendChild(d.createTextNode(name));
+        };
       };
 
       tr.addCell = addCell;
@@ -186,38 +191,38 @@
 
       // Add tokens
       for (var i in this._token) {
-	tr.addCell('th', this.getToken(i));
+        tr.addCell('th', this.getToken(i));
       };
-
+      
       var tbody = table.appendChild(
-	d.createElement('tbody')
+        d.createElement('tbody')
       );
 
       var foundryList = Object.keys(this._foundry).sort();
 
       for (var f = 0; f < foundryList.length; f++) {
-	var foundry = foundryList[f];
-	var layerList =
-	  Object.keys(this._foundry[foundry]).sort();
+  var foundry = foundryList[f];
+  var layerList =
+    Object.keys(this._foundry[foundry]).sort();
 
-	for (var l = 0; l < layerList.length; l++) {
-	  var layer = layerList[l];
-	  tr = tbody.appendChild(
-	    d.createElement('tr')
-	  );
-	  tr.setAttribute('tabindex', 0);
-	  tr.addCell = addCell;
+  for (var l = 0; l < layerList.length; l++) {
+    var layer = layerList[l];
+    tr = tbody.appendChild(
+      d.createElement('tr')
+    );
+    tr.setAttribute('tabindex', 0);
+    tr.addCell = addCell;
 
-	  tr.addCell('th', foundry);
-	  tr.addCell('th', layer);
+    tr.addCell('th', foundry);
+    tr.addCell('th', layer);
 
-	  for (var v = 0; v < this.length(); v++) {
-	    tr.addCell(
-	      'td',
-	      this.getValue(v, foundry, layer) 
-	    );
-	  };
-	};
+    for (var v = 0; v < this.length(); v++) {
+      tr.addCell(
+        'td',
+        this.getValue(v, foundry, layer) 
+      );
+    };
+  };
       };
 
       return this._element = table;