autumnnote 1.8.2 → 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.
@@ -1437,6 +1437,8 @@
1437
1437
  autoSaveRestoreTimeout: 7,
1438
1438
  onAutoSaveRestore: null,
1439
1439
  markdownShortcuts: true,
1440
+ maxPasteSize: 5 * 1024 * 1024,
1441
+ minImageSize: 20,
1440
1442
  bubbleToolbar: false,
1441
1443
  bubbleToolbarItems: [
1442
1444
  "bold",
@@ -5307,7 +5309,7 @@
5307
5309
  * @returns {boolean} `true` if any Markdown-like pattern is present, `false` otherwise.
5308
5310
  */
5309
5311
  function isMarkdown(text) {
5310
- return /^#{1,6} [^\s]|^[ \t]*[-*+] [^\s]|^[ \t]*\d+\. [^\s]|^> [^\s]|^```|^\*{2}[^*\n]+\*{2}/m.test(text);
5312
+ 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);
5311
5313
  }
5312
5314
  /**
5313
5315
  * Converts a Markdown string to an HTML string.
@@ -5334,6 +5336,18 @@
5334
5336
  i++;
5335
5337
  continue;
5336
5338
  }
5339
+ if (line.trim() && !/^(-{3,}|\*{3,}|_{3,})\s*$/.test(line) && !/^#{1,6} /.test(line) && i + 1 < lines.length) {
5340
+ if (/^=+\s*$/.test(lines[i + 1])) {
5341
+ out.push(`<h1>${_inline(line.trim())}</h1>`);
5342
+ i += 2;
5343
+ continue;
5344
+ }
5345
+ if (/^-{2,}\s*$/.test(lines[i + 1])) {
5346
+ out.push(`<h2>${_inline(line.trim())}</h2>`);
5347
+ i += 2;
5348
+ continue;
5349
+ }
5350
+ }
5337
5351
  if (/^(-{3,}|\*{3,}|_{3,})\s*$/.test(line)) {
5338
5352
  out.push("<hr>");
5339
5353
  i++;
@@ -5356,30 +5370,15 @@
5356
5370
  continue;
5357
5371
  }
5358
5372
  if (/^[-*+] /.test(line)) {
5359
- const items = [];
5360
- const isChecklist = /^[-*+]\s+\[[ xX]\]\s+/.test(line);
5361
- const listTag = isChecklist ? "ul class=\"an-checklist\"" : "ul";
5362
- while (i < lines.length && /^[-*+] /.test(lines[i])) {
5363
- if (/^[-*+]\s+\[[ xX]\]\s+/.test(lines[i]) !== isChecklist) break;
5364
- const content = lines[i].slice(2);
5365
- if (isChecklist) {
5366
- const cbMatch = /^\[([ xX])\][ \t]+/.exec(content);
5367
- const cbHtml = `<input type="checkbox" contenteditable="false"${cbMatch?.[1]?.toLowerCase() === "x" ? " checked" : ""}>`;
5368
- const textContent = cbMatch ? content.slice(cbMatch[0].length) : content;
5369
- items.push(`<li>${cbHtml}${_inline(textContent)}</li>`);
5370
- } else items.push(`<li>${_inline(content)}</li>`);
5371
- i++;
5372
- }
5373
- out.push(`<${listTag}>${items.join("")}</${listTag.split(" ")[0]}>`);
5373
+ const { html: listHtml, endIdx } = _parseListBlock(lines, i);
5374
+ out.push(listHtml);
5375
+ i = endIdx;
5374
5376
  continue;
5375
5377
  }
5376
5378
  if (/^\d+\. /.test(line)) {
5377
- const items = [];
5378
- while (i < lines.length && /^\d+\. /.test(lines[i])) {
5379
- items.push(`<li>${_inline(lines[i].replace(/^\d+\. /, ""))}</li>`);
5380
- i++;
5381
- }
5382
- out.push(`<ol>${items.join("")}</ol>`);
5379
+ const { html: listHtml, endIdx } = _parseListBlock(lines, i);
5380
+ out.push(listHtml);
5381
+ i = endIdx;
5383
5382
  continue;
5384
5383
  }
5385
5384
  if (line.trim() === "") {
@@ -5388,20 +5387,29 @@
5388
5387
  }
5389
5388
  if (/^\|.+\|/.test(line) && i + 1 < lines.length && /^\|[\s|:-]+\|/.test(lines[i + 1])) {
5390
5389
  const headerCells = _parseTableRow(line);
5390
+ const alignments = _parseTableRow(lines[i + 1]).map((c) => {
5391
+ if (c.startsWith(":") && c.endsWith(":")) return "center";
5392
+ if (c.endsWith(":")) return "right";
5393
+ if (c.startsWith(":")) return "left";
5394
+ return null;
5395
+ });
5391
5396
  i += 2;
5392
5397
  const bodyRows = [];
5393
5398
  while (i < lines.length && /^\|.+\|/.test(lines[i])) {
5394
5399
  bodyRows.push(_parseTableRow(lines[i]));
5395
5400
  i++;
5396
5401
  }
5397
- const thead = `<thead><tr>${headerCells.map((c) => `<th>${_inline(c)}</th>`).join("")}</tr></thead>`;
5398
- const renderRow = (row) => `<tr>${row.map((c) => `<td>${_inline(c)}</td>`).join("")}</tr>`;
5402
+ const _cell = (tag, content, align) => {
5403
+ return `<${tag}${align ? ` style="text-align:${align}"` : ""}>${_inline(content)}</${tag}>`;
5404
+ };
5405
+ const thead = `<thead><tr>${headerCells.map((c, idx) => _cell("th", c, alignments[idx])).join("")}</tr></thead>`;
5406
+ const renderRow = (row) => `<tr>${row.map((c, idx) => _cell("td", c, alignments[idx])).join("")}</tr>`;
5399
5407
  const tbody = bodyRows.length ? `<tbody>${bodyRows.map(renderRow).join("")}</tbody>` : "";
5400
5408
  out.push(`<table>${thead}${tbody}</table>`);
5401
5409
  continue;
5402
5410
  }
5403
5411
  const paraLines = [];
5404
- while (i < lines.length && lines[i].trim() !== "" && !/^(#{1,6} |> |[-*+] |\d+\. |```|---\s*$|\*{3}\s*$|_{3}\s*$)/.test(lines[i]) && !/^\|.+\|/.test(lines[i])) {
5412
+ 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]))) {
5405
5413
  paraLines.push(lines[i]);
5406
5414
  i++;
5407
5415
  }
@@ -5418,6 +5426,57 @@
5418
5426
  function _parseTableRow(row) {
5419
5427
  return row.replace(/^\|/, "").replace(/\|$/, "").split("|").map((c) => c.trim());
5420
5428
  }
5429
+ function _parseListBlock(lines, startIdx) {
5430
+ const baseIndent = lines[startIdx].match(/^(\s*)/)[1].length;
5431
+ const isOL = /^\s*\d+\. /.test(lines[startIdx]);
5432
+ const items = [];
5433
+ let firstIsCB = null;
5434
+ let i = startIdx;
5435
+ while (i < lines.length) {
5436
+ const line = lines[i];
5437
+ if (line.trim() === "") break;
5438
+ const indent = line.match(/^(\s*)/)[1].length;
5439
+ if (indent < baseIndent) break;
5440
+ if (indent === baseIndent) {
5441
+ if (!/^\s*(?:[-*+]|\d+\.) /.test(line)) break;
5442
+ if (/^\s*\d+\. /.test(line) !== isOL) break;
5443
+ const raw = isOL ? line.replace(/^\s*\d+\. /, "") : line.replace(/^\s*[-*+] /, "");
5444
+ const isCB = !isOL && /^\[[ xX]\]\s+/.test(raw);
5445
+ if (firstIsCB === null) firstIsCB = isCB;
5446
+ if (isCB !== firstIsCB) break;
5447
+ const checked = isCB && raw[1].toLowerCase() === "x";
5448
+ const text = isCB ? raw.replace(/^\[[ xX]\]\s+/, "") : raw;
5449
+ items.push({
5450
+ text,
5451
+ isCB,
5452
+ checked,
5453
+ sub: ""
5454
+ });
5455
+ i++;
5456
+ } else {
5457
+ if (!items.length) {
5458
+ i++;
5459
+ continue;
5460
+ }
5461
+ if (/^\s*(?:[-*+]|\d+\.) /.test(line)) {
5462
+ const nested = _parseListBlock(lines, i);
5463
+ items[items.length - 1].sub += nested.html;
5464
+ i = nested.endIdx;
5465
+ } else {
5466
+ items[items.length - 1].text += " " + line.trim();
5467
+ i++;
5468
+ }
5469
+ }
5470
+ }
5471
+ const open = isOL ? "<ol>" : !isOL && firstIsCB === true ? "<ul class=\"an-checklist\">" : "<ul>";
5472
+ const close = isOL ? "</ol>" : "</ul>";
5473
+ return {
5474
+ html: `${open}${items.map(({ text, isCB, checked, sub }) => {
5475
+ return `<li>${isCB ? `<input type="checkbox" contenteditable="false"${checked ? " checked" : ""}>` : ""}${_inline(text)}${sub}</li>`;
5476
+ }).join("")}${close}`,
5477
+ endIdx: i
5478
+ };
5479
+ }
5421
5480
  function _inline(text) {
5422
5481
  text = text.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, (_, alt, src) => `<img src="${_escAttr(src)}" alt="${_escAttr(alt)}" class="an-image">`);
5423
5482
  text = text.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_, label, href) => `<a href="${_escAttr(href)}">${_esc(label)}</a>`);
@@ -6969,6 +7028,29 @@
6969
7028
  return doc.body.innerHTML;
6970
7029
  }
6971
7030
  /**
7031
+ * Normalizes task lists from external sources (GitHub, GitLab, etc.) so they
7032
+ * pass the sanitiser's `ul.an-checklist` guard. Runs before sanitiseHTML().
7033
+ * @param {string} html
7034
+ * @returns {string}
7035
+ */
7036
+ _normalizeExternalTaskLists(html) {
7037
+ const doc = new DOMParser().parseFromString(`<body>${html}</body>`, "text/html");
7038
+ for (const cb of doc.querySelectorAll("input[type=\"checkbox\"]")) {
7039
+ const li = cb.closest("li");
7040
+ const ul = li?.closest("ul");
7041
+ if (!li || !ul || ul.classList.contains("an-checklist")) continue;
7042
+ ul.classList.add("an-checklist");
7043
+ cb.removeAttribute("disabled");
7044
+ cb.setAttribute("contenteditable", "false");
7045
+ for (const attr of Array.from(cb.attributes)) if (![
7046
+ "type",
7047
+ "checked",
7048
+ "contenteditable"
7049
+ ].includes(attr.name)) cb.removeAttribute(attr.name);
7050
+ }
7051
+ return doc.body.innerHTML;
7052
+ }
7053
+ /**
6972
7054
  * Forces the next paste operation to strip all HTML formatting.
6973
7055
  * Called by Editor when Ctrl+Shift+V is pressed.
6974
7056
  * @param {boolean} val
@@ -7026,6 +7108,7 @@
7026
7108
  let html = raw;
7027
7109
  if (isWordContent) html = this._cleanWordHtml(html);
7028
7110
  else if (isSocialContent) html = this._cleanSocialHtml(html);
7111
+ html = this._normalizeExternalTaskLists(html);
7029
7112
  html = sanitiseHTML(html);
7030
7113
  if (this.options.pasteStripAttributes) html = this._stripAttributes(html);
7031
7114
  execCommand("insertHTML", html);
@@ -7140,7 +7223,7 @@
7140
7223
  _compressImage(file) {
7141
7224
  const MAX_DIM = 1920;
7142
7225
  const QUALITY = .85;
7143
- return new Promise((resolve) => {
7226
+ return new Promise((resolve, reject) => {
7144
7227
  const objectUrl = URL.createObjectURL(file);
7145
7228
  const img = new Image();
7146
7229
  img.onload = () => {
@@ -7160,6 +7243,7 @@
7160
7243
  if (!ctx) {
7161
7244
  const reader = new FileReader();
7162
7245
  reader.onload = (e) => resolve(e.target.result);
7246
+ reader.onerror = () => reject(/* @__PURE__ */ new Error("FileReader failed"));
7163
7247
  reader.readAsDataURL(file);
7164
7248
  return;
7165
7249
  }
@@ -7171,6 +7255,7 @@
7171
7255
  URL.revokeObjectURL(objectUrl);
7172
7256
  const reader = new FileReader();
7173
7257
  reader.onload = (e) => resolve(e.target.result);
7258
+ reader.onerror = () => reject(/* @__PURE__ */ new Error("FileReader failed"));
7174
7259
  reader.readAsDataURL(file);
7175
7260
  };
7176
7261
  img.src = objectUrl;
@@ -13892,7 +13977,7 @@
13892
13977
  };
13893
13978
  if (typeof navigator.clipboard.read === "function") navigator.clipboard.read().then((items) => {
13894
13979
  for (const item of items) if (item.types.includes("text/html")) {
13895
- item.getType("text/html").then((blob) => blob.text()).then((html) => doInsert(html, null));
13980
+ item.getType("text/html").then((blob) => blob.text()).then((html) => doInsert(html, null)).catch(() => {});
13896
13981
  return;
13897
13982
  }
13898
13983
  navigator.clipboard.readText().then((text) => doInsert(null, text)).catch(() => {});
@@ -15017,6 +15102,10 @@
15017
15102
  canvas.width = Math.round(renderW);
15018
15103
  canvas.height = Math.round(renderH);
15019
15104
  const ctx = canvas.getContext("2d");
15105
+ if (!ctx) {
15106
+ resolve(null);
15107
+ return;
15108
+ }
15020
15109
  try {
15021
15110
  ctx.drawImage(source, naturalRect.x, naturalRect.y, naturalRect.width, naturalRect.height, 0, 0, canvas.width, canvas.height);
15022
15111
  ctx.getImageData(0, 0, 1, 1);
@@ -17079,7 +17168,7 @@
17079
17168
  /** All pre-built button definitions — accessible in every module format including UMD/CJS. */
17080
17169
  buttons,
17081
17170
  /** Library version */
17082
- version: "1.8.2"
17171
+ version: "1.9.1"
17083
17172
  };
17084
17173
  /**
17085
17174
  * @param {string|Element|NodeList|Element[]} selector