@ai-matrx/print 0.4.0 → 0.5.0

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.
@@ -1,4 +1,5 @@
1
1
  // src/core.ts
2
+ import { escapeHtml } from "@ai-matrx/kit/html-escape";
2
3
  var PRINT_STYLES = `
3
4
  *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
4
5
 
@@ -69,9 +70,6 @@ var PRINT_STYLES = `
69
70
  th { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
70
71
  }
71
72
  `;
72
- function escapeHtml(str) {
73
- return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
74
- }
75
73
  function buildPrintDocument(bodyHtml, title = "AI Response", extraStyles = "") {
76
74
  return `<!DOCTYPE html>
77
75
  <html lang="en">
@@ -152,6 +150,7 @@ function buildFitTextScript(selectors) {
152
150
  }
153
151
 
154
152
  // src/flashcards.ts
153
+ import { escapeHtml as escapeHtml2 } from "@ai-matrx/kit/html-escape";
155
154
  var SETTING_DEFAULTS = {
156
155
  showSideLabel: false,
157
156
  showCardNumber: false,
@@ -187,7 +186,7 @@ function faceImageHtml(card, face, showImages = true) {
187
186
  const url = face === "front" ? card.frontImageUrl : card.backImageUrl;
188
187
  if (!url || !/^https?:\/\//.test(url)) return "";
189
188
  const alt = (face === "front" ? card.frontImageAlt : card.backImageAlt) ?? "";
190
- return `<img class="face-image" src="${escapeHtml(url)}" alt="${escapeHtml(alt)}">`;
189
+ return `<img class="face-image" src="${escapeHtml2(url)}" alt="${escapeHtml2(alt)}">`;
191
190
  }
192
191
  var BASE_STYLES = `
193
192
  img.face-image {
@@ -358,13 +357,13 @@ function renderCutCards(cards, title, s, startIndex = 0) {
358
357
  const globalIdx = startIndex + p * PAGE_SIZE + i + 1;
359
358
  const frontSize = sizeClass(card.front);
360
359
  const backSize = sizeClass(card.back ?? "");
361
- const backContent = (card.back ?? "").split("\n").map((line) => escapeHtml(line)).join("<br>");
360
+ const backContent = (card.back ?? "").split("\n").map((line) => escapeHtml2(line)).join("<br>");
362
361
  return `<div class="card-cell">
363
362
  <span class="card-number-badge">#${globalIdx}</span>
364
363
  <div class="card-inner">
365
364
  <div class="card-face card-front-face">
366
365
  <div class="card-side-label">Question / Term</div>
367
- ${faceImageHtml(card, "front", s.showImages)}<div class="front-text ${frontSize}">${escapeHtml(card.front)}</div>
366
+ ${faceImageHtml(card, "front", s.showImages)}<div class="front-text ${frontSize}">${escapeHtml2(card.front)}</div>
368
367
  </div>
369
368
  <div class="card-face card-back-face">
370
369
  <div class="card-side-label">Answer / Definition</div>
@@ -377,7 +376,7 @@ function renderCutCards(cards, title, s, startIndex = 0) {
377
376
  const pageClass = isFirst ? "" : ' class="page-break"';
378
377
  pages.push(`<div${pageClass}>
379
378
  ${isFirst ? `<div class="deck-header">
380
- <h1 class="deck-title">${escapeHtml(title)}</h1>
379
+ <h1 class="deck-title">${escapeHtml2(title)}</h1>
381
380
  <div class="deck-meta">${cards.length} card${cards.length !== 1 ? "s" : ""} &nbsp;\xB7&nbsp; Cut along dashed lines</div>
382
381
  </div>
383
382
  <div class="instructions">
@@ -438,13 +437,13 @@ function renderBothSides(cards, title, s, startIndex = 0) {
438
437
  (card, i) => `<div class="card-cell">
439
438
  <div class="card-front">
440
439
  <div class="card-number">Card ${startIndex + i + 1}</div>
441
- ${faceImageHtml(card, "front", s.showImages)}${escapeHtml(card.front)}
440
+ ${faceImageHtml(card, "front", s.showImages)}${escapeHtml2(card.front)}
442
441
  </div>
443
- <div class="card-back">${faceImageHtml(card, "back", s.showImages)}${escapeHtml(card.back ?? "")}</div>
442
+ <div class="card-back">${faceImageHtml(card, "back", s.showImages)}${escapeHtml2(card.back ?? "")}</div>
444
443
  </div>`
445
444
  ).join("\n");
446
445
  return `<div class="deck-header">
447
- <h1 class="deck-title">${escapeHtml(title)}</h1>
446
+ <h1 class="deck-title">${escapeHtml2(title)}</h1>
448
447
  <div class="deck-meta">${cards.length} card${cards.length !== 1 ? "s" : ""} &nbsp;\xB7&nbsp; Front and back</div>
449
448
  </div>
450
449
  <div class="cards-grid">
@@ -504,12 +503,12 @@ var STUDY_SHEET_STYLES = `
504
503
  function renderStudySheet(cards, title, s, startIndex = 0) {
505
504
  const rows = cards.map(
506
505
  (card, i) => ` <tr>
507
- <td><span class="row-num">${startIndex + i + 1}.</span>${faceImageHtml(card, "front", s.showImages)}${escapeHtml(card.front)}</td>
508
- <td>${faceImageHtml(card, "back", s.showImages)}${escapeHtml(card.back ?? "")}</td>
506
+ <td><span class="row-num">${startIndex + i + 1}.</span>${faceImageHtml(card, "front", s.showImages)}${escapeHtml2(card.front)}</td>
507
+ <td>${faceImageHtml(card, "back", s.showImages)}${escapeHtml2(card.back ?? "")}</td>
509
508
  </tr>`
510
509
  ).join("\n");
511
510
  return `<div class="deck-header">
512
- <h1 class="deck-title">${escapeHtml(title)}</h1>
511
+ <h1 class="deck-title">${escapeHtml2(title)}</h1>
513
512
  <div class="deck-meta">${cards.length} card${cards.length !== 1 ? "s" : ""} &nbsp;\xB7&nbsp; Study sheet</div>
514
513
  </div>
515
514
  <table>
@@ -574,13 +573,13 @@ function renderFrontOnly(cards, title, s, startIndex = 0) {
574
573
  (card, i) => `<div class="card-cell">
575
574
  <div class="card-front">
576
575
  <div class="card-number">Card ${startIndex + i + 1}</div>
577
- ${faceImageHtml(card, "front", s.showImages)}${escapeHtml(card.front)}
576
+ ${faceImageHtml(card, "front", s.showImages)}${escapeHtml2(card.front)}
578
577
  </div>
579
578
  <div class="answer-blank"></div>
580
579
  </div>`
581
580
  ).join("\n");
582
581
  return `<div class="deck-header">
583
- <h1 class="deck-title">${escapeHtml(title)}</h1>
582
+ <h1 class="deck-title">${escapeHtml2(title)}</h1>
584
583
  <div class="deck-meta">${cards.length} card${cards.length !== 1 ? "s" : ""} &nbsp;\xB7&nbsp; Self-test \u2014 write your answers in the blank space</div>
585
584
  </div>
586
585
  <div class="cards-grid">
@@ -628,11 +627,11 @@ function renderBackOnly(cards, title, s, startIndex = 0) {
628
627
  const cells = cards.map(
629
628
  (card, i) => `<div class="card-cell">
630
629
  <div class="card-back-header">Card ${startIndex + i + 1}</div>
631
- <div class="card-back-content">${faceImageHtml(card, "back", s.showImages)}${escapeHtml(card.back ?? "")}</div>
630
+ <div class="card-back-content">${faceImageHtml(card, "back", s.showImages)}${escapeHtml2(card.back ?? "")}</div>
632
631
  </div>`
633
632
  ).join("\n");
634
633
  return `<div class="deck-header">
635
- <h1 class="deck-title">${escapeHtml(title)}</h1>
634
+ <h1 class="deck-title">${escapeHtml2(title)}</h1>
636
635
  <div class="deck-meta">${cards.length} card${cards.length !== 1 ? "s" : ""} &nbsp;\xB7&nbsp; Answers and definitions only</div>
637
636
  </div>
638
637
  <div class="cards-grid">
@@ -848,14 +847,14 @@ function renderCardText(text, isFront, extraStyle = "") {
848
847
  if (isFront) {
849
848
  const styleAttr2 = extraStyle ? ` style="${extraStyle}"` : "";
850
849
  return {
851
- html: `<div class="card-text-inner"${styleAttr2}>${escapeHtml(text).replace(/\n/g, "<br>")}</div>`,
850
+ html: `<div class="card-text-inner"${styleAttr2}>${escapeHtml2(text).replace(/\n/g, "<br>")}</div>`,
852
851
  isList: false
853
852
  };
854
853
  }
855
854
  const bullet = isBulletContent(text);
856
855
  if (bullet) {
857
856
  const lines = text.split("\n");
858
- const items = lines.map((l) => l.trim()).filter((l) => l.length > 0).map((l) => l.replace(/^[-•*]\s*/, "")).map((l) => `<li>${escapeHtml(l)}</li>`).join("");
857
+ const items = lines.map((l) => l.trim()).filter((l) => l.length > 0).map((l) => l.replace(/^[-•*]\s*/, "")).map((l) => `<li>${escapeHtml2(l)}</li>`).join("");
859
858
  const styleAttr2 = extraStyle ? ` style="${extraStyle}"` : "";
860
859
  return {
861
860
  html: `<ul class="card-text-inner card-list"${styleAttr2}>${items}</ul>`,
@@ -866,7 +865,7 @@ function renderCardText(text, isFront, extraStyle = "") {
866
865
  const cls = ml ? "card-text-inner multiline" : "card-text-inner";
867
866
  const styleAttr = extraStyle ? ` style="${extraStyle}"` : "";
868
867
  return {
869
- html: `<div class="${cls}"${styleAttr}>${escapeHtml(text).replace(/\n/g, "<br>")}</div>`,
868
+ html: `<div class="${cls}"${styleAttr}>${escapeHtml2(text).replace(/\n/g, "<br>")}</div>`,
870
869
  isList: false
871
870
  };
872
871
  }
@@ -935,7 +934,7 @@ function openLandscapeWindow(bodyHtml, title) {
935
934
  <html lang="en">
936
935
  <head>
937
936
  <meta charset="UTF-8">
938
- <title>${escapeHtml(title)}</title>
937
+ <title>${escapeHtml2(title)}</title>
939
938
  <style>${LANDSCAPE_STYLES}</style>
940
939
  </head>
941
940
  <body>
@@ -1079,10 +1078,10 @@ function buildAveryCard(text, cardNum, isFront, s) {
1079
1078
  const styleAttr = innerStyle ? ` style="${innerStyle}"` : "";
1080
1079
  let innerHtml;
1081
1080
  if (isBullet) {
1082
- const items = text.split("\n").map((l) => l.trim()).filter((l) => l.length > 0).map((l) => l.replace(/^[-•*]\s*/, "")).map((l) => `<li>${escapeHtml(l)}</li>`).join("");
1081
+ const items = text.split("\n").map((l) => l.trim()).filter((l) => l.length > 0).map((l) => l.replace(/^[-•*]\s*/, "")).map((l) => `<li>${escapeHtml2(l)}</li>`).join("");
1083
1082
  innerHtml = `<ul class="${cls}"${styleAttr}>${items}</ul>`;
1084
1083
  } else {
1085
- const escaped = escapeHtml(text).replace(/\n/g, "<br>");
1084
+ const escaped = escapeHtml2(text).replace(/\n/g, "<br>");
1086
1085
  innerHtml = `<div class="${cls}"${styleAttr}>${escaped}</div>`;
1087
1086
  }
1088
1087
  const wrapExtra = isBullet ? ' style="align-items:flex-start;"' : "";
@@ -1117,7 +1116,7 @@ function openAveryWindow(bodyHtml, title) {
1117
1116
  <html lang="en">
1118
1117
  <head>
1119
1118
  <meta charset="UTF-8">
1120
- <title>${escapeHtml(title)} \u2014 Avery 5388</title>
1119
+ <title>${escapeHtml2(title)} \u2014 Avery 5388</title>
1121
1120
  <style>${AVERY_5388_STYLES}</style>
1122
1121
  </head>
1123
1122
  <body>
@@ -1355,7 +1354,7 @@ function openPortrait6UpWindow(bodyHtml, title) {
1355
1354
  <html lang="en">
1356
1355
  <head>
1357
1356
  <meta charset="UTF-8">
1358
- <title>${escapeHtml(title)} \u2014 6 per page</title>
1357
+ <title>${escapeHtml2(title)} \u2014 6 per page</title>
1359
1358
  <style>${PORTRAIT_6UP_STYLES}</style>
1360
1359
  </head>
1361
1360
  <body>