autumnnote 1.8.3 → 1.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5596,7 +5596,7 @@ function _domToMd(node, depth = 0) {
5596
5596
  * @returns {boolean} `true` if any Markdown-like pattern is present, `false` otherwise.
5597
5597
  */
5598
5598
  function isMarkdown(text) {
5599
- return /^#{1,6} [^\s]|^[ \t]*[-*+] [^\s]|^[ \t]*\d+\. [^\s]|^> [^\s]|^```|^\*{2}[^*\n]+\*{2}/m.test(text);
5599
+ return /^#{1,6} [^\s]|^[ \t]*[-*+] [^\s]|^[ \t]*\d+\. [^\s]|^> [^\s]|^```|^\*{2}[^*\n]+\*{2}/m.test(text) || /^.+\n=+\s*$/m.test(text) || /^.+\n-{2,}\s*$/m.test(text);
5600
5600
  }
5601
5601
  /**
5602
5602
  * Converts a Markdown string to an HTML string.
@@ -5623,6 +5623,18 @@ function markdownToHTML(text) {
5623
5623
  i++;
5624
5624
  continue;
5625
5625
  }
5626
+ if (line.trim() && !/^(-{3,}|\*{3,}|_{3,})\s*$/.test(line) && !/^#{1,6} /.test(line) && i + 1 < lines.length) {
5627
+ if (/^=+\s*$/.test(lines[i + 1])) {
5628
+ out.push(`<h1>${_inline(line.trim())}</h1>`);
5629
+ i += 2;
5630
+ continue;
5631
+ }
5632
+ if (/^-{2,}\s*$/.test(lines[i + 1])) {
5633
+ out.push(`<h2>${_inline(line.trim())}</h2>`);
5634
+ i += 2;
5635
+ continue;
5636
+ }
5637
+ }
5626
5638
  if (/^(-{3,}|\*{3,}|_{3,})\s*$/.test(line)) {
5627
5639
  out.push("<hr>");
5628
5640
  i++;
@@ -5645,30 +5657,15 @@ function markdownToHTML(text) {
5645
5657
  continue;
5646
5658
  }
5647
5659
  if (/^[-*+] /.test(line)) {
5648
- const items = [];
5649
- const isChecklist = /^[-*+]\s+\[[ xX]\]\s+/.test(line);
5650
- const listTag = isChecklist ? "ul class=\"an-checklist\"" : "ul";
5651
- while (i < lines.length && /^[-*+] /.test(lines[i])) {
5652
- if (/^[-*+]\s+\[[ xX]\]\s+/.test(lines[i]) !== isChecklist) break;
5653
- const content = lines[i].slice(2);
5654
- if (isChecklist) {
5655
- const cbMatch = /^\[([ xX])\][ \t]+/.exec(content);
5656
- const cbHtml = `<input type="checkbox" contenteditable="false"${cbMatch?.[1]?.toLowerCase() === "x" ? " checked" : ""}>`;
5657
- const textContent = cbMatch ? content.slice(cbMatch[0].length) : content;
5658
- items.push(`<li>${cbHtml}${_inline(textContent)}</li>`);
5659
- } else items.push(`<li>${_inline(content)}</li>`);
5660
- i++;
5661
- }
5662
- out.push(`<${listTag}>${items.join("")}</${listTag.split(" ")[0]}>`);
5660
+ const { html: listHtml, endIdx } = _parseListBlock(lines, i);
5661
+ out.push(listHtml);
5662
+ i = endIdx;
5663
5663
  continue;
5664
5664
  }
5665
5665
  if (/^\d+\. /.test(line)) {
5666
- const items = [];
5667
- while (i < lines.length && /^\d+\. /.test(lines[i])) {
5668
- items.push(`<li>${_inline(lines[i].replace(/^\d+\. /, ""))}</li>`);
5669
- i++;
5670
- }
5671
- out.push(`<ol>${items.join("")}</ol>`);
5666
+ const { html: listHtml, endIdx } = _parseListBlock(lines, i);
5667
+ out.push(listHtml);
5668
+ i = endIdx;
5672
5669
  continue;
5673
5670
  }
5674
5671
  if (line.trim() === "") {
@@ -5677,20 +5674,29 @@ function markdownToHTML(text) {
5677
5674
  }
5678
5675
  if (/^\|.+\|/.test(line) && i + 1 < lines.length && /^\|[\s|:-]+\|/.test(lines[i + 1])) {
5679
5676
  const headerCells = _parseTableRow(line);
5677
+ const alignments = _parseTableRow(lines[i + 1]).map((c) => {
5678
+ if (c.startsWith(":") && c.endsWith(":")) return "center";
5679
+ if (c.endsWith(":")) return "right";
5680
+ if (c.startsWith(":")) return "left";
5681
+ return null;
5682
+ });
5680
5683
  i += 2;
5681
5684
  const bodyRows = [];
5682
5685
  while (i < lines.length && /^\|.+\|/.test(lines[i])) {
5683
5686
  bodyRows.push(_parseTableRow(lines[i]));
5684
5687
  i++;
5685
5688
  }
5686
- const thead = `<thead><tr>${headerCells.map((c) => `<th>${_inline(c)}</th>`).join("")}</tr></thead>`;
5687
- const renderRow = (row) => `<tr>${row.map((c) => `<td>${_inline(c)}</td>`).join("")}</tr>`;
5689
+ const _cell = (tag, content, align) => {
5690
+ return `<${tag}${align ? ` style="text-align:${align}"` : ""}>${_inline(content)}</${tag}>`;
5691
+ };
5692
+ const thead = `<thead><tr>${headerCells.map((c, idx) => _cell("th", c, alignments[idx])).join("")}</tr></thead>`;
5693
+ const renderRow = (row) => `<tr>${row.map((c, idx) => _cell("td", c, alignments[idx])).join("")}</tr>`;
5688
5694
  const tbody = bodyRows.length ? `<tbody>${bodyRows.map(renderRow).join("")}</tbody>` : "";
5689
5695
  out.push(`<table>${thead}${tbody}</table>`);
5690
5696
  continue;
5691
5697
  }
5692
5698
  const paraLines = [];
5693
- while (i < lines.length && lines[i].trim() !== "" && !/^(#{1,6} |> |[-*+] |\d+\. |```|---\s*$|\*{3}\s*$|_{3}\s*$)/.test(lines[i]) && !/^\|.+\|/.test(lines[i])) {
5699
+ while (i < lines.length && lines[i].trim() !== "" && !/^(#{1,6} |> |[-*+] |\d+\. |```|---\s*$|\*{3}\s*$|_{3}\s*$)/.test(lines[i]) && !/^\|.+\|/.test(lines[i]) && !(i + 1 < lines.length && /^=+\s*$/.test(lines[i + 1])) && !(i + 1 < lines.length && /^-{2,}\s*$/.test(lines[i + 1]))) {
5694
5700
  paraLines.push(lines[i]);
5695
5701
  i++;
5696
5702
  }
@@ -5707,6 +5713,57 @@ function markdownToHTML(text) {
5707
5713
  function _parseTableRow(row) {
5708
5714
  return row.replace(/^\|/, "").replace(/\|$/, "").split("|").map((c) => c.trim());
5709
5715
  }
5716
+ function _parseListBlock(lines, startIdx) {
5717
+ const baseIndent = lines[startIdx].match(/^(\s*)/)[1].length;
5718
+ const isOL = /^\s*\d+\. /.test(lines[startIdx]);
5719
+ const items = [];
5720
+ let firstIsCB = null;
5721
+ let i = startIdx;
5722
+ while (i < lines.length) {
5723
+ const line = lines[i];
5724
+ if (line.trim() === "") break;
5725
+ const indent = line.match(/^(\s*)/)[1].length;
5726
+ if (indent < baseIndent) break;
5727
+ if (indent === baseIndent) {
5728
+ if (!/^\s*(?:[-*+]|\d+\.) /.test(line)) break;
5729
+ if (/^\s*\d+\. /.test(line) !== isOL) break;
5730
+ const raw = isOL ? line.replace(/^\s*\d+\. /, "") : line.replace(/^\s*[-*+] /, "");
5731
+ const isCB = !isOL && /^\[[ xX]\]\s+/.test(raw);
5732
+ if (firstIsCB === null) firstIsCB = isCB;
5733
+ if (isCB !== firstIsCB) break;
5734
+ const checked = isCB && raw[1].toLowerCase() === "x";
5735
+ const text = isCB ? raw.replace(/^\[[ xX]\]\s+/, "") : raw;
5736
+ items.push({
5737
+ text,
5738
+ isCB,
5739
+ checked,
5740
+ sub: ""
5741
+ });
5742
+ i++;
5743
+ } else {
5744
+ if (!items.length) {
5745
+ i++;
5746
+ continue;
5747
+ }
5748
+ if (/^\s*(?:[-*+]|\d+\.) /.test(line)) {
5749
+ const nested = _parseListBlock(lines, i);
5750
+ items[items.length - 1].sub += nested.html;
5751
+ i = nested.endIdx;
5752
+ } else {
5753
+ items[items.length - 1].text += " " + line.trim();
5754
+ i++;
5755
+ }
5756
+ }
5757
+ }
5758
+ const open = isOL ? "<ol>" : !isOL && firstIsCB === true ? "<ul class=\"an-checklist\">" : "<ul>";
5759
+ const close = isOL ? "</ol>" : "</ul>";
5760
+ return {
5761
+ html: `${open}${items.map(({ text, isCB, checked, sub }) => {
5762
+ return `<li>${isCB ? `<input type="checkbox" contenteditable="false"${checked ? " checked" : ""}>` : ""}${_inline(text)}${sub}</li>`;
5763
+ }).join("")}${close}`,
5764
+ endIdx: i
5765
+ };
5766
+ }
5710
5767
  function _inline(text) {
5711
5768
  text = text.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, (_, alt, src) => `<img src="${_escAttr(src)}" alt="${_escAttr(alt)}" class="an-image">`);
5712
5769
  text = text.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_, label, href) => `<a href="${_escAttr(href)}">${_esc(label)}</a>`);
@@ -7258,6 +7315,29 @@ var Clipboard = class {
7258
7315
  return doc.body.innerHTML;
7259
7316
  }
7260
7317
  /**
7318
+ * Normalizes task lists from external sources (GitHub, GitLab, etc.) so they
7319
+ * pass the sanitiser's `ul.an-checklist` guard. Runs before sanitiseHTML().
7320
+ * @param {string} html
7321
+ * @returns {string}
7322
+ */
7323
+ _normalizeExternalTaskLists(html) {
7324
+ const doc = new DOMParser().parseFromString(`<body>${html}</body>`, "text/html");
7325
+ for (const cb of doc.querySelectorAll("input[type=\"checkbox\"]")) {
7326
+ const li = cb.closest("li");
7327
+ const ul = li?.closest("ul");
7328
+ if (!li || !ul || ul.classList.contains("an-checklist")) continue;
7329
+ ul.classList.add("an-checklist");
7330
+ cb.removeAttribute("disabled");
7331
+ cb.setAttribute("contenteditable", "false");
7332
+ for (const attr of Array.from(cb.attributes)) if (![
7333
+ "type",
7334
+ "checked",
7335
+ "contenteditable"
7336
+ ].includes(attr.name)) cb.removeAttribute(attr.name);
7337
+ }
7338
+ return doc.body.innerHTML;
7339
+ }
7340
+ /**
7261
7341
  * Forces the next paste operation to strip all HTML formatting.
7262
7342
  * Called by Editor when Ctrl+Shift+V is pressed.
7263
7343
  * @param {boolean} val
@@ -7315,6 +7395,7 @@ var Clipboard = class {
7315
7395
  let html = raw;
7316
7396
  if (isWordContent) html = this._cleanWordHtml(html);
7317
7397
  else if (isSocialContent) html = this._cleanSocialHtml(html);
7398
+ html = this._normalizeExternalTaskLists(html);
7318
7399
  html = sanitiseHTML(html);
7319
7400
  if (this.options.pasteStripAttributes) html = this._stripAttributes(html);
7320
7401
  execCommand("insertHTML", html);
@@ -17500,7 +17581,7 @@ var AutumnNote = {
17500
17581
  /** All pre-built button definitions — accessible in every module format including UMD/CJS. */
17501
17582
  buttons,
17502
17583
  /** Library version */
17503
- version: "1.8.3"
17584
+ version: "1.9.1"
17504
17585
  };
17505
17586
  /**
17506
17587
  * @param {string|Element|NodeList|Element[]} selector