NEW Escape commas and asterisks in query-by-match query creator

Change-Id: I9bb4c7d6663d81c15430ea2ddc28b0875763c163
diff --git a/Changes b/Changes
index 66f0b14..85ff5e7 100644
--- a/Changes
+++ b/Changes
@@ -9,6 +9,7 @@
         - Fix test suite for glimpse-rearrangement (diewald)
         - Mark "notinindex"-fields (diewald)
         - Fix test suite for "allow-same-origin" sandbox rule (diewald)
+        - Escape commas and asterisks in query-by-match query creator (kupietz, hebasta)
 
 0.64 2026-02-14
         - Improve 'Plugins' mounting (diewald)
diff --git a/dev/js/spec/queryCreatorSpec.js b/dev/js/spec/queryCreatorSpec.js
index 16b8c36..a7e9860 100644
--- a/dev/js/spec/queryCreatorSpec.js
+++ b/dev/js/spec/queryCreatorSpec.js
@@ -95,13 +95,21 @@
     "          <td class=\"mark\">NN</td>" +
     "        </tr>" +
     "        <tr tabindex=\"0\">" +
-    "          <th>tt</th>" +
+    "          <th>gender</th>" +
     "          <th>l</th>" +
     "          <td>Lese|Lesen</td>" +
     "          <td>a b</td>" +
     "          <td></td>" +
     "          <td class=\"mark\">NN</td>" +
     "        </tr>" +
+    "        <tr tabindex=\"0\">" +
+    "          <th>tt</th>" +
+    "          <th>l</th>" +
+    "          <td>Lehrer*in</td>" +
+    "          <td>gender:fem,masc,nonbin</td>" +
+    "          <td></td>" +
+    "          <td class=\"mark\">NN</td>" +
+    "        </tr>" +
     "      </tbody>" +
     "    </table>";
   var info = document.createElement('div');
@@ -651,7 +659,7 @@
       expect(cell.classList.contains("chosen")).toBe(false);
       cell.click();
       expect(cell.classList.contains("chosen")).toBeTruthy();
-      expect(qc.toString()).toEqual("[tt/l='Lese|Lesen']");
+      expect(qc.toString()).toEqual("[gender/l='Lese|Lesen']");
       cell.click()
       expect(cell.classList.contains("chosen")).toBe(false);
       expect(qc.toString()).toEqual("");
@@ -660,7 +668,7 @@
       expect(cell.classList.contains("chosen")).toBe(false);
       cell.click();
       expect(cell.classList.contains("chosen")).toBeTruthy();
-      expect(qc.toString()).toEqual("[tt/l='a b']");
+      expect(qc.toString()).toEqual("[gender/l='a b']");
       cell.click()
       expect(cell.classList.contains("chosen")).toBe(false);
       expect(qc.toString()).toEqual("");
@@ -674,6 +682,24 @@
       cell.click()
       expect(cell.classList.contains("chosen")).toBe(false);
       expect(qc.toString()).toEqual("");
+
+      cell = matchTable.querySelector("tbody > tr:nth-child(4) > td:nth-child(3)");
+      expect(cell.classList.contains("chosen")).toBe(false);
+      cell.click();
+      expect(cell.classList.contains("chosen")).toBeTruthy();
+      expect(qc.toString()).toEqual("[tt/l='Lehrer*in']");
+      cell.click()
+      expect(cell.classList.contains("chosen")).toBe(false);
+      expect(qc.toString()).toEqual("");
+
+      cell = matchTable.querySelector("tbody > tr:nth-child(4) > td:nth-child(4)");
+      expect(cell.classList.contains("chosen")).toBe(false);
+      cell.click();
+      expect(cell.classList.contains("chosen")).toBeTruthy();
+      expect(qc.toString()).toEqual("[tt/l='gender:fem,masc,nonbin']");
+      cell.click()
+      expect(cell.classList.contains("chosen")).toBe(false);
+      expect(qc.toString()).toEqual("");
     });
 
     it('should respect marked elements', function () {
diff --git a/dev/js/src/match/querycreator.js b/dev/js/src/match/querycreator.js
index 12614d3..8e59143 100644
--- a/dev/js/src/match/querycreator.js
+++ b/dev/js/src/match/querycreator.js
@@ -20,7 +20,7 @@
   const loc = KorAP.Locale;
   loc.NEW_QUERY = loc.NEW_QUERY || 'New Query';
 
-  const esc = RegExp("^(?:[^ \:\.\'\\\\\|\&]+:)?[^ \:\.\'\\\\\|\&]+$");
+  const esc = RegExp("^(?:[^ \:\.\'\\\\\|\&,\*]+:)?[^ \:\.\'\\\\\|\&,\*]+$");
   
   function _getKeyValue (keyValue) {
     if (keyValue.match(esc) === null) {