Support verbatim keys/values in QueryCreator

Change-Id: I8c13f2429b41b1ecab9099dd206eae3701c7daca
diff --git a/Changes b/Changes
index d89f49e..f9638d4 100755
--- a/Changes
+++ b/Changes
@@ -1,4 +1,4 @@
-0.27 2018-07-17
+0.27 2018-07-23
         - Introduced content blocks to create
           flexible entry lists in the footer
         - Add marker for "cutted" matches.
@@ -6,6 +6,8 @@
         - Added buttongroup class.
         - Introduced panel and view system for
           results and matches.
+        - Support verbatim keys/values in QueryCreator
+          to deal with Koral issue #42.
 
 0.26 2018-04-06
         - Added meta data view.
diff --git a/dev/js/spec/queryCreatorSpec.js b/dev/js/spec/queryCreatorSpec.js
index dffd3d3..59547ef 100644
--- a/dev/js/spec/queryCreatorSpec.js
+++ b/dev/js/spec/queryCreatorSpec.js
@@ -1,3 +1,7 @@
+/**
+ * Specification for the query creator.
+ */
+
 function matchTableFactory () {
   var table = document.createElement('div');
 
@@ -83,6 +87,7 @@
     "            <div>case:nom</div>" +
     "            <div>gender:masc</div>" +
     "            <div>number:sg</div>" +
+    "            <div>morphemes:.::_SORSZ \\ZERO::NOM 'period::PUNCT'</div>" +
     "          </td>" +
     "          <td>ADJA</td>" +
     "          <td></td>" +
@@ -561,5 +566,20 @@
           "[(corenlp/p=gender:fem | corenlp/p=gender:masc) & corenlp/p=case:nom & corenlp/p=number:sg]"
       );
     });
+
+    it('should support verbatim strings', function () {
+      var matchTable = matchTableComplexFactory();
+      var qc = qcClass.create(matchTable);
+      expect(qc.toString()).toEqual("");
+
+      // TODO:
+      // This does not respect keys vs values at the moment, but neither does Koral
+      var cell = matchTable.querySelector("tbody > tr:nth-child(2) > td > div:nth-child(4)");
+      expect(cell.innerString()).toEqual("morphemes:.::_SORSZ \\ZERO::NOM 'period::PUNCT'");
+      expect(cell.classList.contains("chosen")).toBe(false);
+      cell.click();
+      expect(cell.classList.contains("chosen")).toBeTruthy();
+      expect(qc.toString()).toEqual("[opennlp/p='morphemes:.::_SORSZ \\\\ZERO::NOM \\\'period::PUNCT\\\'']");
+    });
   });
 });
diff --git a/dev/js/src/match/querycreator.js b/dev/js/src/match/querycreator.js
index 72c672e..42a0b62 100644
--- a/dev/js/src/match/querycreator.js
+++ b/dev/js/src/match/querycreator.js
@@ -19,6 +19,16 @@
   const loc = KorAP.Locale;
   loc.NEW_QUERY = loc.NEW_QUERY || 'New Query';
 
+  var esc = RegExp("[ \.\'\\\\]");
+  
+  function _getKeyValue (keyValue) {
+    if (keyValue.match(esc) != null) {
+      return "'" + keyValue.replace(/\\/g, "\\\\").replace(/'/g, "\\'") + "'";
+    };
+    return keyValue;
+  };
+
+  
   function _getAnnotation (prefix, target) {
 
     // Complex annotation
@@ -28,7 +38,7 @@
       // Iterate over alternative annotations
       target.childNodes.forEach(function (item) {
         if (item.nodeType === 3)
-          orGroup.push(prefix + item.data);
+          orGroup.push(prefix + _getKeyValue(item.data));
       });
       return '(' + orGroup.sort().join(' | ') + ')';
     }
@@ -38,7 +48,7 @@
       if (target.innerText == '')
         return '';
 
-      return prefix + target.innerText;
+      return prefix + _getKeyValue(target.innerText);
     };
   };