FIX: Support checkboxes in unordered lists, more edge-cases (#20)

FIX: Support checkboxes in unordered lists, more edge-cases (#20)

diff --git a/assets/javascripts/discourse/initializers/checklist.js.es6 b/assets/javascripts/discourse/initializers/checklist.js.es6
index 8e6134b..129c2ca 100644
--- a/assets/javascripts/discourse/initializers/checklist.js.es6
+++ b/assets/javascripts/discourse/initializers/checklist.js.es6
@@ -37,12 +37,16 @@ export function checklistSyntax($elem, post) {
           // Computing offsets where checkbox are not evaluated (i.e. inside
           // code blocks).
           [
+            // inline code
             /`[^`\n]*\n?[^`\n]*`/gm,
+            // multi-line code
             /^`‍``[^]*?^`‍``/gm,
+            // bbcode
             /\[code\][^]*?\[\/code\]/gm,
-            /_.*?_/gm,
-            /\*[^\]].*?[^\[]\*/gm,
-            /~~.*?~~/gm
+            // italic/bold
+            /_(?=\S).*?\S_/gm,
+            // strikethrough
+            /~~(?=\S).*?\S~~/gm
           ].forEach(regex => {
             let match;
             while ((match = regex.exec(result.raw)) != null) {
@@ -50,6 +54,17 @@ export function checklistSyntax($elem, post) {
             }
           });
 
+          [
+            // italic/bold
+            /([^\[\n]|^)\*\S.+?\S\*(?=[^\]\n]|$)/gm
+          ].forEach(regex => {
+            let match;
+            while ((match = regex.exec(result.raw)) != null) {
+              // Simulate lookbehind - skip the first character
+              blocks.push([match.index + 1, match.index + match[0].length]);
+            }
+          });
+
           // make the first run go to index = 0
           let nth = -1;
           let found = false;
@@ -60,7 +75,9 @@ export function checklistSyntax($elem, post) {
                 return match;
               }
 
-              nth += blocks.every(b => b[0] > off + match.length || off > b[1]);
+              nth += blocks.every(
+                b => b[0] >= off + match.length || off > b[1]
+              );
 
               if (nth === idx) {
                 found = true; // Do not replace any further matches
diff --git a/test/javascripts/lib/checklist-test.js.es6 b/test/javascripts/lib/checklist-test.js.es6
index fc6e14b..b60ca72 100644
--- a/test/javascripts/lib/checklist-test.js.es6
+++ b/test/javascripts/lib/checklist-test.js.es6
@@ -36,7 +36,8 @@ QUnit.test("checkbox before a code block", async assert => {
 \`[x] nope\`
   `);
 
-  $elem.find(".chcklst-box:nth(1)").click();
+  assert.equal($elem.find(".chcklst-box").length, 2);
+  $elem.find(".chcklst-box")[1].click();
 
   const output = await updated;
   assert.ok(output.includes("[ ] first"));
@@ -54,7 +55,8 @@ QUnit.test("checkbox before a multiline code block", async assert => {
 \`\`\`
   `);
 
-  $elem.find(".chcklst-box:nth(1)").click();
+  assert.equal($elem.find(".chcklst-box").length, 2);
+  $elem.find(".chcklst-box")[1].click();
 
   const output = await updated;
   assert.ok(output.includes("[ ] first"));
@@ -67,12 +69,52 @@ QUnit.test("checkbox before italic/bold sequence", async assert => {
 [*] *test*
   `);
 
-  $elem.find(".chcklst-box:nth(0)").click();
+  assert.equal($elem.find(".chcklst-box").length, 1);
+  $elem.find(".chcklst-box")[0].click();
 
   const output = await updated;
   assert.ok(output.includes("[ ] *test*"));
 });
 
+QUnit.test("checkboxes in an unordered list", async assert => {
+  const [$elem, updated] = await prepare(`
+* [*] checked
+* [] test
+* [] two
+`);
+
+  assert.equal($elem.find(".chcklst-box").length, 3);
+  $elem.find(".chcklst-box")[1].click();
+
+  const output = await updated;
+  assert.ok(output.includes("* [*] checked"));
+  assert.ok(output.includes("* [\\*] test"));
+  assert.ok(output.includes("* [] two"));
+});
+
+QUnit.test("checkboxes in italic/bold-like blocks", async assert => {
+  const [$elem, updated] = await prepare(`
+*[\*
+*a [*] \*]*
+[*\*]
+~~[*]~~
+
+* []* 0
+
+~~[] ~~ 1
+
+~~ [*]~~ 2
+
+* [*] 3
+`);
+
+  assert.equal($elem.find(".chcklst-box").length, 4);
+  $elem.find(".chcklst-box")[3].click();
+
+  const output = await updated;
+  assert.ok(output.includes("* [ ] 3"));
+});
+
 QUnit.test("correct checkbox is selected", async assert => {
   const [$elem, updated] = await prepare(`
 \`[x]\`
@@ -99,12 +141,14 @@ __[x]__
 Actual checkboxes:
 [] first
 [*] second
-[x] third
-[_] fourth
+* test[*]*thrid*
+[x] fourth
+[_] fifth
   `);
 
-  $elem.find(".chcklst-box:nth(2)").click();
+  assert.equal($elem.find(".chcklst-box").length, 5);
+  $elem.find(".chcklst-box")[3].click();
 
   const output = await updated;
-  assert.ok(output.includes("[ ] third"));
+  assert.ok(output.includes("[ ] fourth"));
 });

GitHub sha: 21021491

1 Like

This commit appears in #20 which was approved by ZogStriP. It was merged by CvX.

This commit appears in #20 which was approved by ZogStriP. It was merged by CvX.