@meistrari/minuta-editor 1.4.0 → 1.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,4 @@
|
|
|
1
|
-
import { f as footnoteHtmlToRuns, p as pocLoneCellIndex, a as formatTopicNumber, b as pocLooksLikeTitle, T as TOPIC_DEFAULT_GROUP } from '../shared/minuta-editor.
|
|
1
|
+
import { f as footnoteHtmlToRuns, p as pocLoneCellIndex, a as formatTopicNumber, b as pocLooksLikeTitle, c as pocNodeHasVisibleContent, d as pocNodePaintsBox, T as TOPIC_DEFAULT_GROUP } from '../shared/minuta-editor.f1239e0b.mjs';
|
|
2
2
|
import { BorderStyle, TextRun, ExternalHyperlink, Paragraph, Document, LevelFormat, AlignmentType, LevelSuffix, Header, Packer, LineRuleType, Table, TableRow, TableCell, WidthType, TableLayoutType, Footer, FootnoteReferenceRun, VerticalAlign, ImageRun, HorizontalPositionRelativeFrom, VerticalPositionRelativeFrom, TextWrappingType, FrameAnchorType, PageNumber, HeadingLevel } from 'docx';
|
|
3
3
|
import '@tiptap/pm/state';
|
|
4
4
|
import '@tiptap/pm/view';
|
|
@@ -18,6 +18,48 @@ function topicSequenceFor(ctx, group, roman, number) {
|
|
|
18
18
|
seq.next = number + 1;
|
|
19
19
|
return seq.reference;
|
|
20
20
|
}
|
|
21
|
+
function listFormatFor(type) {
|
|
22
|
+
switch (type) {
|
|
23
|
+
case "a":
|
|
24
|
+
return LevelFormat.LOWER_LETTER;
|
|
25
|
+
case "A":
|
|
26
|
+
return LevelFormat.UPPER_LETTER;
|
|
27
|
+
case "i":
|
|
28
|
+
return LevelFormat.LOWER_ROMAN;
|
|
29
|
+
case "I":
|
|
30
|
+
return LevelFormat.UPPER_ROMAN;
|
|
31
|
+
default:
|
|
32
|
+
return LevelFormat.DECIMAL;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function listFormatFromCss(listStyleType) {
|
|
36
|
+
switch (listStyleType) {
|
|
37
|
+
case "lower-alpha":
|
|
38
|
+
case "lower-latin":
|
|
39
|
+
return LevelFormat.LOWER_LETTER;
|
|
40
|
+
case "upper-alpha":
|
|
41
|
+
case "upper-latin":
|
|
42
|
+
return LevelFormat.UPPER_LETTER;
|
|
43
|
+
case "lower-roman":
|
|
44
|
+
return LevelFormat.LOWER_ROMAN;
|
|
45
|
+
case "upper-roman":
|
|
46
|
+
return LevelFormat.UPPER_ROMAN;
|
|
47
|
+
default:
|
|
48
|
+
return LevelFormat.DECIMAL;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function listSequenceFor(ctx, list, run) {
|
|
52
|
+
const reference = `cdb-list-${ctx.listNumbering.size + 1}`;
|
|
53
|
+
const start = Number.parseInt(String(list.start ?? 1), 10);
|
|
54
|
+
ctx.listNumbering.set(reference, {
|
|
55
|
+
format: list.format,
|
|
56
|
+
// `start="0"` é válido (o Word aceita w:start=0); só o ausente/inválido vira 1
|
|
57
|
+
start: Number.isFinite(start) && start >= 0 ? start : 1,
|
|
58
|
+
suffix: list.suffix || ".",
|
|
59
|
+
run
|
|
60
|
+
});
|
|
61
|
+
return reference;
|
|
62
|
+
}
|
|
21
63
|
function leadingTopicNumber(node) {
|
|
22
64
|
for (let i = 0; i < node.childCount; i++) {
|
|
23
65
|
const child = node.child(i);
|
|
@@ -466,20 +508,28 @@ async function islandToDocx(node, pos, contentWidthPx, ctx) {
|
|
|
466
508
|
const paragraphs = [];
|
|
467
509
|
const liveLis = islandEl ? [...islandEl.querySelectorAll(":scope > ul > li, :scope > ol > li, :scope > li")] : [];
|
|
468
510
|
const parsedLis = [...el.querySelectorAll(":scope > li")];
|
|
469
|
-
let
|
|
511
|
+
let reference = null;
|
|
470
512
|
for (let i = 0; i < parsedLis.length; i++) {
|
|
471
513
|
const live = liveLis[i] ?? null;
|
|
472
514
|
const source = live ?? parsedLis[i];
|
|
473
515
|
const m = live ? measureEl(live) : null;
|
|
474
|
-
const
|
|
475
|
-
|
|
516
|
+
const markerRun = { color: m?.color, size: m?.sizeHalf, font: m ? primaryFont(m.cs) : void 0 };
|
|
517
|
+
if (tag === "ol" && !reference) {
|
|
518
|
+
const liveStyleType = liveLis[0] ? getComputedStyle(liveLis[0]).listStyleType : "";
|
|
519
|
+
reference = listSequenceFor(ctx, {
|
|
520
|
+
format: el.hasAttribute("type") ? listFormatFor(el.getAttribute("type")) : listFormatFromCss(liveStyleType),
|
|
521
|
+
start: el.getAttribute("start"),
|
|
522
|
+
suffix: el.getAttribute("data-list-suffix")
|
|
523
|
+
}, markerRun);
|
|
524
|
+
}
|
|
476
525
|
const runs = live ? domInlineToRuns(live) : [new TextRun({ text: source.textContent?.trim() || "", ...runOptions(parseStyle(source.getAttribute("style"))) })];
|
|
477
526
|
const indentPx = live && islandEl ? live.offsetLeft : 24;
|
|
478
527
|
paragraphs.push(new Paragraph({
|
|
479
528
|
children: [
|
|
480
|
-
new TextRun({ text:
|
|
529
|
+
...tag === "ul" ? [new TextRun({ text: "\u2022 ", ...markerRun })] : [],
|
|
481
530
|
...runs
|
|
482
531
|
],
|
|
532
|
+
numbering: reference ? { reference, level: 0 } : void 0,
|
|
483
533
|
spacing: m ? { after: m.afterTw, before: m.beforeTw, ...m.lineExactTw ? { line: m.lineExactTw, lineRule: LineRuleType.EXACT } : {} } : { after: 80 },
|
|
484
534
|
indent: { left: Math.round(indentPx * PX_TO_TWIP) },
|
|
485
535
|
alignment: m?.align,
|
|
@@ -694,6 +744,27 @@ async function flexRowToDocx(node, pos, contentWidthPx, ctx) {
|
|
|
694
744
|
}
|
|
695
745
|
return tables;
|
|
696
746
|
}
|
|
747
|
+
const INVISIBLE_NODE_TYPES = /* @__PURE__ */ new Set(["paragraph", "styledDiv", "missingImage", "hardBreak", "text"]);
|
|
748
|
+
function rowPaintsOrShowsAnything(row, rowPos, ctx) {
|
|
749
|
+
const paintsAt = (node, pos) => {
|
|
750
|
+
if (pocNodePaintsBox(node))
|
|
751
|
+
return true;
|
|
752
|
+
const dom = domAt(ctx, pos);
|
|
753
|
+
return Boolean(bordersFrom(measureAt(ctx, pos), node.attrs?.style)) || Boolean(cellShading(dom ? getComputedStyle(dom) : null));
|
|
754
|
+
};
|
|
755
|
+
if (paintsAt(row, rowPos))
|
|
756
|
+
return true;
|
|
757
|
+
let found = false;
|
|
758
|
+
row.descendants((node, offset) => {
|
|
759
|
+
if (found)
|
|
760
|
+
return false;
|
|
761
|
+
const pos = rowPos + 1 + offset;
|
|
762
|
+
if (!INVISIBLE_NODE_TYPES.has(node.type.name) || pocNodeHasVisibleContent(node) || paintsAt(node, pos))
|
|
763
|
+
found = true;
|
|
764
|
+
return !found;
|
|
765
|
+
});
|
|
766
|
+
return found;
|
|
767
|
+
}
|
|
697
768
|
function isPlainContainer(node) {
|
|
698
769
|
return node.type.name === "styledDiv" && !isFlexRow(node);
|
|
699
770
|
}
|
|
@@ -930,6 +1001,18 @@ async function nodeToDocx(node, pos, contentWidthPx, ctx) {
|
|
|
930
1001
|
}
|
|
931
1002
|
case "styledDiv": {
|
|
932
1003
|
if (isFlexRow(node)) {
|
|
1004
|
+
if (!rowPaintsOrShowsAnything(node, pos, ctx)) {
|
|
1005
|
+
const rowM2 = measureAt(ctx, pos);
|
|
1006
|
+
const breakBefore = consumeBreak(ctx);
|
|
1007
|
+
const before = breakBefore ? rowM2?.beforeTw ?? 0 : Math.max(0, (rowM2?.beforeTw ?? 0) - ctx.lastAfterTw);
|
|
1008
|
+
const lugar = new Paragraph({
|
|
1009
|
+
children: [],
|
|
1010
|
+
spacing: { after: rowM2?.afterTw ?? 0, before },
|
|
1011
|
+
pageBreakBefore: breakBefore
|
|
1012
|
+
});
|
|
1013
|
+
ctx.lastAfterTw = rowM2?.afterTw ?? 0;
|
|
1014
|
+
return [lugar];
|
|
1015
|
+
}
|
|
933
1016
|
const loneIndex = pocLoneCellIndex(node);
|
|
934
1017
|
if (loneIndex != null) {
|
|
935
1018
|
let childPos = pos + 1;
|
|
@@ -1012,31 +1095,41 @@ async function nodeToDocx(node, pos, contentWidthPx, ctx) {
|
|
|
1012
1095
|
case "bulletList":
|
|
1013
1096
|
case "orderedList": {
|
|
1014
1097
|
const paragraphs = [];
|
|
1015
|
-
|
|
1098
|
+
const ordered = node.type.name === "orderedList";
|
|
1099
|
+
let reference = null;
|
|
1016
1100
|
let liPos = pos + 1;
|
|
1017
1101
|
for (let i = 0; i < node.childCount; i++) {
|
|
1018
1102
|
const li = node.child(i);
|
|
1019
1103
|
let childPos = liPos + 1;
|
|
1104
|
+
let marked = false;
|
|
1020
1105
|
li.forEach((child) => {
|
|
1021
1106
|
if (child.isTextblock) {
|
|
1022
1107
|
const m = measureAt(ctx, childPos);
|
|
1023
1108
|
const base = m ? { bold: m.bold, italics: m.italics, color: m.color, size: m.sizeHalf } : parseStyle(child.attrs.style);
|
|
1024
|
-
const marker = node.type.name === "orderedList" ? `${n}. ` : "\u2022 ";
|
|
1025
1109
|
const liDom = domAt(ctx, liPos);
|
|
1026
1110
|
const indentPx = liDom?.offsetLeft ?? 48;
|
|
1027
1111
|
const liBreak = consumeBreak(ctx);
|
|
1112
|
+
if (ordered && !reference) {
|
|
1113
|
+
reference = listSequenceFor(
|
|
1114
|
+
ctx,
|
|
1115
|
+
{ format: listFormatFor(node.attrs.type), start: node.attrs.start },
|
|
1116
|
+
{ bold: base.bold, italics: base.italics, color: base.color, size: base.size, font: base.font }
|
|
1117
|
+
);
|
|
1118
|
+
}
|
|
1119
|
+
const bullet = !ordered && !marked ? [new TextRun({ text: "\u2022 ", ...runOptions(base) })] : [];
|
|
1028
1120
|
const liParagraph = new Paragraph({
|
|
1029
|
-
children: [
|
|
1121
|
+
children: [...bullet, ...inlineToRuns(child, base, ctx)],
|
|
1122
|
+
numbering: ordered && !marked && reference ? { reference, level: 0 } : void 0,
|
|
1030
1123
|
spacing: spacingFrom(m, child.attrs.style),
|
|
1031
1124
|
indent: { left: Math.round(indentPx * PX_TO_TWIP) },
|
|
1032
1125
|
pageBreakBefore: liBreak
|
|
1033
1126
|
});
|
|
1127
|
+
marked = true;
|
|
1034
1128
|
ctx.meta.set(liParagraph, { breakBefore: liBreak });
|
|
1035
1129
|
paragraphs.push(liParagraph);
|
|
1036
1130
|
}
|
|
1037
1131
|
childPos += child.nodeSize;
|
|
1038
1132
|
});
|
|
1039
|
-
n++;
|
|
1040
1133
|
liPos += li.nodeSize;
|
|
1041
1134
|
}
|
|
1042
1135
|
return paragraphs;
|
|
@@ -1355,7 +1448,8 @@ async function pocExportDocx(editor, margins, chrome, options = {}) {
|
|
|
1355
1448
|
meta: /* @__PURE__ */ new WeakMap(),
|
|
1356
1449
|
footnotes: [],
|
|
1357
1450
|
topicNumbering: /* @__PURE__ */ new Map(),
|
|
1358
|
-
topicSequences: /* @__PURE__ */ new Map()
|
|
1451
|
+
topicSequences: /* @__PURE__ */ new Map(),
|
|
1452
|
+
listNumbering: /* @__PURE__ */ new Map()
|
|
1359
1453
|
};
|
|
1360
1454
|
const children = [];
|
|
1361
1455
|
let pos = 0;
|
|
@@ -1404,21 +1498,38 @@ async function pocExportDocx(editor, margins, chrome, options = {}) {
|
|
|
1404
1498
|
}
|
|
1405
1499
|
},
|
|
1406
1500
|
footnotes: Object.keys(footnotes).length ? footnotes : void 0,
|
|
1407
|
-
numbering: ctx.topicNumbering.size ? {
|
|
1408
|
-
config: [
|
|
1409
|
-
reference,
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1501
|
+
numbering: ctx.topicNumbering.size || ctx.listNumbering.size ? {
|
|
1502
|
+
config: [
|
|
1503
|
+
...[...ctx.topicNumbering].map(([reference, { roman, start }]) => ({
|
|
1504
|
+
reference,
|
|
1505
|
+
levels: [{
|
|
1506
|
+
level: 0,
|
|
1507
|
+
format: roman ? LevelFormat.UPPER_ROMAN : LevelFormat.DECIMAL,
|
|
1508
|
+
text: "%1",
|
|
1509
|
+
start,
|
|
1510
|
+
alignment: AlignmentType.START,
|
|
1511
|
+
// o ". " depois do número é texto do template; e sem
|
|
1512
|
+
// recuo/tab o parágrafo fica igual ao preview
|
|
1513
|
+
suffix: LevelSuffix.NOTHING,
|
|
1514
|
+
style: { paragraph: { indent: { left: 0, hanging: 0 } } }
|
|
1515
|
+
}]
|
|
1516
|
+
})),
|
|
1517
|
+
...[...ctx.listNumbering].map(([reference, { format, start, suffix, run }]) => ({
|
|
1518
|
+
reference,
|
|
1519
|
+
levels: [{
|
|
1520
|
+
level: 0,
|
|
1521
|
+
format,
|
|
1522
|
+
text: `%1${suffix}`,
|
|
1523
|
+
start,
|
|
1524
|
+
alignment: AlignmentType.LEFT,
|
|
1525
|
+
// "a. texto": marcador colado ao item com um espaço,
|
|
1526
|
+
// como o preview (list-style-position: inside); o
|
|
1527
|
+
// recuo é o do parágrafo, não da sequência
|
|
1528
|
+
suffix: LevelSuffix.SPACE,
|
|
1529
|
+
style: { paragraph: { indent: { left: 0, hanging: 0 } }, run }
|
|
1530
|
+
}]
|
|
1531
|
+
}))
|
|
1532
|
+
]
|
|
1422
1533
|
} : void 0,
|
|
1423
1534
|
sections: [{
|
|
1424
1535
|
properties: {
|
package/dist/docx.mjs
CHANGED
package/dist/index.mjs
CHANGED
|
@@ -22,8 +22,8 @@ import TableCell from '@tiptap/extension-table-cell';
|
|
|
22
22
|
import TableHeader from '@tiptap/extension-table-header';
|
|
23
23
|
import TableRow from '@tiptap/extension-table-row';
|
|
24
24
|
import { Plugin } from '@tiptap/pm/state';
|
|
25
|
-
import { s as sanitizeRichHtml, T as TOPIC_DEFAULT_GROUP,
|
|
26
|
-
export {
|
|
25
|
+
import { s as sanitizeRichHtml, e as sanitizeFootnoteHtml, g as footnoteSizePt, T as TOPIC_DEFAULT_GROUP, h as TOPIC_NUMBER_ATTR, r as readTopicNumber, i as TOPIC_GROUP_ATTR, j as TOPIC_ROMAN_ATTR, k as TOPIC_REF_ATTR, a as formatTopicNumber, P as PocPaginationPlugin, l as computePocBreaks, m as pocPageKey, n as breaksEqual, o as PAGINATE_META } from './shared/minuta-editor.f1239e0b.mjs';
|
|
26
|
+
export { v as buildPocFooterEl, u as buildPocHeaderEl, w as buildPocNotesEl, z as computePocLoneRows, f as footnoteHtmlToRuns, C as fromRoman, t as isPocChromeCanvas, y as isPocFlexRow, q as pocChromeFlowHeight, x as pocDescendsInto, p as pocLoneCellIndex, b as pocLooksLikeTitle, c as pocNodeHasVisibleContent, d as pocNodePaintsBox, A as shouldMoveBreakToHeading, B as toRoman, D as topicNumberHtml } from './shared/minuta-editor.f1239e0b.mjs';
|
|
27
27
|
import '@tiptap/pm/view';
|
|
28
28
|
|
|
29
29
|
const POC_ASSET_SWAP = "pocAssetSwap";
|
|
@@ -46,7 +46,17 @@ const PocMinutaBlock = Node$1.create({
|
|
|
46
46
|
addAttributes() {
|
|
47
47
|
return {
|
|
48
48
|
blockId: { default: null },
|
|
49
|
-
blockTitle: { default: null }
|
|
49
|
+
blockTitle: { default: null },
|
|
50
|
+
/**
|
|
51
|
+
* impressão digital do texto GERADO pelo checklist (ver
|
|
52
|
+
* utils/minutaBlockFingerprint no app): enquanto o conteúdo bater
|
|
53
|
+
* com ela o trecho não foi editado e o checklist pode re-gerá-lo
|
|
54
|
+
*/
|
|
55
|
+
genHash: {
|
|
56
|
+
default: null,
|
|
57
|
+
parseHTML: (el) => el.getAttribute("data-gen-hash"),
|
|
58
|
+
renderHTML: (attrs) => attrs.genHash ? { "data-gen-hash": attrs.genHash } : {}
|
|
59
|
+
}
|
|
50
60
|
};
|
|
51
61
|
},
|
|
52
62
|
parseHTML() {
|
|
@@ -408,7 +418,9 @@ const PocFootnoteRef = Node$1.create({
|
|
|
408
418
|
selectable: false,
|
|
409
419
|
addAttributes() {
|
|
410
420
|
return {
|
|
411
|
-
|
|
421
|
+
// o Tiptap relê `number="1"` do `<footnote>` e o converte em número —
|
|
422
|
+
// e o render do ProseMirror só aceita texto como conteúdo
|
|
423
|
+
number: { default: "", parseHTML: (el) => el.getAttribute("number") ?? el.textContent ?? "" },
|
|
412
424
|
/** conteúdo da nota em HTML de ênfase (b/i/u/br) */
|
|
413
425
|
text: { default: "" },
|
|
414
426
|
/** corpo declarado no template (`font-size: 9pt`), em pontos */
|
|
@@ -424,6 +436,17 @@ const PocFootnoteRef = Node$1.create({
|
|
|
424
436
|
text: el.getAttribute("data-footnote") ?? "",
|
|
425
437
|
size: Number.parseFloat(el.getAttribute("data-footnote-size") ?? "") || null
|
|
426
438
|
})
|
|
439
|
+
}, {
|
|
440
|
+
// `<footnote>` cru do template (HTML de servidor antigo ou de
|
|
441
|
+
// outra origem): sem esta regra a tag some e o texto da nota
|
|
442
|
+
// cai no meio do parágrafo
|
|
443
|
+
tag: "footnote",
|
|
444
|
+
priority: 110,
|
|
445
|
+
getAttrs: (el) => ({
|
|
446
|
+
number: el.getAttribute("number") ?? "",
|
|
447
|
+
text: sanitizeFootnoteHtml(el.innerHTML.replace(/ /g, " ")),
|
|
448
|
+
size: footnoteSizePt(el.getAttribute("style"))
|
|
449
|
+
})
|
|
427
450
|
}];
|
|
428
451
|
},
|
|
429
452
|
renderHTML({ node }) {
|
|
@@ -2163,4 +2186,4 @@ function createMinutaEditor(element, opts) {
|
|
|
2163
2186
|
return api;
|
|
2164
2187
|
}
|
|
2165
2188
|
|
|
2166
|
-
export { A4_HEIGHT_PX, A4_WIDTH_PX, DEFAULT_MARGINS, DOC_FONTS, ICON_PATHS, PAGINATE_META, POC_ASSET_SWAP, PocDocument, PocFootnoteRef, PocHtmlIsland, PocInlineStyle, PocMinutaBlock, PocMissingImage, PocPaginationPlugin, PocStylePassthrough, PocStyledDiv, PocTemplateVariable, PocTopicNumber, PocTopicRenumber, PocUnderline, PocVariableChip, TOPIC_DEFAULT_GROUP, TOPIC_GROUP_ATTR, TOPIC_NUMBER_ATTR, TOPIC_REF_ATTR, TOPIC_ROMAN_ATTR, breaksEqual, buildPocExtensions, collectVaultRefs, computePocBreaks, createMinutaEditor, decodeVaultAttr, dispatchVariableClick, escapeHtml, escapeVaultAttr, extractTemplateVariables, formatTopicNumber, iconSvg, pocPageKey, readTopicNumber, refreshVaultImages, renewVaultImageTags, renumberPocFootnotes, renumberPocTopics, renumberPocTopicsIn, resolveTemplateVariables, sanitizeFootnoteHtml, sanitizeRichHtml, swapVaultSrc, variableChipHtml, vaultImageHtml, vaultRefOf };
|
|
2189
|
+
export { A4_HEIGHT_PX, A4_WIDTH_PX, DEFAULT_MARGINS, DOC_FONTS, ICON_PATHS, PAGINATE_META, POC_ASSET_SWAP, PocDocument, PocFootnoteRef, PocHtmlIsland, PocInlineStyle, PocMinutaBlock, PocMissingImage, PocPaginationPlugin, PocStylePassthrough, PocStyledDiv, PocTemplateVariable, PocTopicNumber, PocTopicRenumber, PocUnderline, PocVariableChip, TOPIC_DEFAULT_GROUP, TOPIC_GROUP_ATTR, TOPIC_NUMBER_ATTR, TOPIC_REF_ATTR, TOPIC_ROMAN_ATTR, breaksEqual, buildPocExtensions, collectVaultRefs, computePocBreaks, createMinutaEditor, decodeVaultAttr, dispatchVariableClick, escapeHtml, escapeVaultAttr, extractTemplateVariables, footnoteSizePt, formatTopicNumber, iconSvg, pocPageKey, readTopicNumber, refreshVaultImages, renewVaultImageTags, renumberPocFootnotes, renumberPocTopics, renumberPocTopicsIn, resolveTemplateVariables, sanitizeFootnoteHtml, sanitizeRichHtml, swapVaultSrc, variableChipHtml, vaultImageHtml, vaultRefOf };
|
|
@@ -75,84 +75,6 @@ function sanitizeRichHtml(html) {
|
|
|
75
75
|
return tpl.innerHTML;
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
const TOPIC_NUMBER_ATTR = "data-topic-number";
|
|
79
|
-
const TOPIC_GROUP_ATTR = "data-topic-group";
|
|
80
|
-
const TOPIC_ROMAN_ATTR = "data-topic-roman";
|
|
81
|
-
const TOPIC_REF_ATTR = "data-topic-ref";
|
|
82
|
-
const TOPIC_DEFAULT_GROUP = "default";
|
|
83
|
-
function toRoman(num) {
|
|
84
|
-
if (!Number.isFinite(num) || num <= 0)
|
|
85
|
-
return "";
|
|
86
|
-
const numerals = [
|
|
87
|
-
[1e3, "M"],
|
|
88
|
-
[900, "CM"],
|
|
89
|
-
[500, "D"],
|
|
90
|
-
[400, "CD"],
|
|
91
|
-
[100, "C"],
|
|
92
|
-
[90, "XC"],
|
|
93
|
-
[50, "L"],
|
|
94
|
-
[40, "XL"],
|
|
95
|
-
[10, "X"],
|
|
96
|
-
[9, "IX"],
|
|
97
|
-
[5, "V"],
|
|
98
|
-
[4, "IV"],
|
|
99
|
-
[1, "I"]
|
|
100
|
-
];
|
|
101
|
-
let result = "";
|
|
102
|
-
let rest = Math.floor(num);
|
|
103
|
-
for (const [value, numeral] of numerals) {
|
|
104
|
-
while (rest >= value) {
|
|
105
|
-
result += numeral;
|
|
106
|
-
rest -= value;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
return result;
|
|
110
|
-
}
|
|
111
|
-
function fromRoman(text) {
|
|
112
|
-
const upper = text.trim().toUpperCase();
|
|
113
|
-
if (!upper || !/^M{0,3}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$/.test(upper))
|
|
114
|
-
return null;
|
|
115
|
-
const values = { I: 1, V: 5, X: 10, L: 50, C: 100, D: 500, M: 1e3 };
|
|
116
|
-
let total = 0;
|
|
117
|
-
for (let i = 0; i < upper.length; i++) {
|
|
118
|
-
const current = values[upper[i]];
|
|
119
|
-
const next = values[upper[i + 1] ?? ""] ?? 0;
|
|
120
|
-
total += current < next ? -current : current;
|
|
121
|
-
}
|
|
122
|
-
return total;
|
|
123
|
-
}
|
|
124
|
-
function formatTopicNumber(number, roman) {
|
|
125
|
-
return roman ? toRoman(number) : String(number);
|
|
126
|
-
}
|
|
127
|
-
function escapeAttr(value) {
|
|
128
|
-
return value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
129
|
-
}
|
|
130
|
-
function topicNumberHtml(info) {
|
|
131
|
-
let attrs = `${TOPIC_NUMBER_ATTR}="${info.number}" ${TOPIC_GROUP_ATTR}="${escapeAttr(info.group || TOPIC_DEFAULT_GROUP)}"`;
|
|
132
|
-
if (info.roman)
|
|
133
|
-
attrs += ` ${TOPIC_ROMAN_ATTR}="true"`;
|
|
134
|
-
if (info.ref)
|
|
135
|
-
attrs += ` ${TOPIC_REF_ATTR}="true"`;
|
|
136
|
-
return `<span ${attrs}>${formatTopicNumber(info.number, info.roman)}</span>`;
|
|
137
|
-
}
|
|
138
|
-
function readTopicNumber(el) {
|
|
139
|
-
const roman = el.getAttribute(TOPIC_ROMAN_ATTR) === "true";
|
|
140
|
-
const raw = el.getAttribute(TOPIC_NUMBER_ATTR) ?? "";
|
|
141
|
-
let number = Number.parseInt(raw, 10);
|
|
142
|
-
if (!Number.isFinite(number)) {
|
|
143
|
-
const text = el.textContent?.trim() ?? "";
|
|
144
|
-
number = Number.parseInt(text, 10);
|
|
145
|
-
if (!Number.isFinite(number))
|
|
146
|
-
number = fromRoman(text) ?? 1;
|
|
147
|
-
}
|
|
148
|
-
return {
|
|
149
|
-
number,
|
|
150
|
-
group: el.getAttribute(TOPIC_GROUP_ATTR) || TOPIC_DEFAULT_GROUP,
|
|
151
|
-
roman,
|
|
152
|
-
ref: el.getAttribute(TOPIC_REF_ATTR) === "true"
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
|
|
156
78
|
const INLINE_TAGS = /* @__PURE__ */ new Set(["B", "STRONG", "I", "EM", "U", "SUP", "SUB", "BR"]);
|
|
157
79
|
function safeHref(value) {
|
|
158
80
|
const href = (value ?? "").trim();
|
|
@@ -208,12 +130,12 @@ function sanitizeFootnoteHtml(html) {
|
|
|
208
130
|
return style ? `<span style="${style}">${inner}</span>` : inner;
|
|
209
131
|
}
|
|
210
132
|
if (node.tagName === "DIV" || node.tagName === "P")
|
|
211
|
-
return inner ? `${inner}<br>` : "";
|
|
133
|
+
return inner.trim() ? `${inner}<br>` : "";
|
|
212
134
|
if (INLINE_TAGS.has(node.tagName))
|
|
213
135
|
return `<${node.tagName.toLowerCase()}>${inner}</${node.tagName.toLowerCase()}>`;
|
|
214
136
|
return inner;
|
|
215
137
|
};
|
|
216
|
-
return Array.from(root.childNodes).map(walk).join("").replace(/\s+/g, " ").replace(/(<br>\s*)+$/i, "").trim();
|
|
138
|
+
return Array.from(root.childNodes).map(walk).join("").replace(/\s+/g, " ").replace(/^(\s*<br>)+/i, "").replace(/(<br>\s*)+$/i, "").trim();
|
|
217
139
|
}
|
|
218
140
|
function footnoteHtmlToRuns(html) {
|
|
219
141
|
const runs = [];
|
|
@@ -271,6 +193,84 @@ function footnoteSizePt(style) {
|
|
|
271
193
|
return Number.isFinite(value) ? value : null;
|
|
272
194
|
}
|
|
273
195
|
|
|
196
|
+
const TOPIC_NUMBER_ATTR = "data-topic-number";
|
|
197
|
+
const TOPIC_GROUP_ATTR = "data-topic-group";
|
|
198
|
+
const TOPIC_ROMAN_ATTR = "data-topic-roman";
|
|
199
|
+
const TOPIC_REF_ATTR = "data-topic-ref";
|
|
200
|
+
const TOPIC_DEFAULT_GROUP = "default";
|
|
201
|
+
function toRoman(num) {
|
|
202
|
+
if (!Number.isFinite(num) || num <= 0)
|
|
203
|
+
return "";
|
|
204
|
+
const numerals = [
|
|
205
|
+
[1e3, "M"],
|
|
206
|
+
[900, "CM"],
|
|
207
|
+
[500, "D"],
|
|
208
|
+
[400, "CD"],
|
|
209
|
+
[100, "C"],
|
|
210
|
+
[90, "XC"],
|
|
211
|
+
[50, "L"],
|
|
212
|
+
[40, "XL"],
|
|
213
|
+
[10, "X"],
|
|
214
|
+
[9, "IX"],
|
|
215
|
+
[5, "V"],
|
|
216
|
+
[4, "IV"],
|
|
217
|
+
[1, "I"]
|
|
218
|
+
];
|
|
219
|
+
let result = "";
|
|
220
|
+
let rest = Math.floor(num);
|
|
221
|
+
for (const [value, numeral] of numerals) {
|
|
222
|
+
while (rest >= value) {
|
|
223
|
+
result += numeral;
|
|
224
|
+
rest -= value;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return result;
|
|
228
|
+
}
|
|
229
|
+
function fromRoman(text) {
|
|
230
|
+
const upper = text.trim().toUpperCase();
|
|
231
|
+
if (!upper || !/^M{0,3}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$/.test(upper))
|
|
232
|
+
return null;
|
|
233
|
+
const values = { I: 1, V: 5, X: 10, L: 50, C: 100, D: 500, M: 1e3 };
|
|
234
|
+
let total = 0;
|
|
235
|
+
for (let i = 0; i < upper.length; i++) {
|
|
236
|
+
const current = values[upper[i]];
|
|
237
|
+
const next = values[upper[i + 1] ?? ""] ?? 0;
|
|
238
|
+
total += current < next ? -current : current;
|
|
239
|
+
}
|
|
240
|
+
return total;
|
|
241
|
+
}
|
|
242
|
+
function formatTopicNumber(number, roman) {
|
|
243
|
+
return roman ? toRoman(number) : String(number);
|
|
244
|
+
}
|
|
245
|
+
function escapeAttr(value) {
|
|
246
|
+
return value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
247
|
+
}
|
|
248
|
+
function topicNumberHtml(info) {
|
|
249
|
+
let attrs = `${TOPIC_NUMBER_ATTR}="${info.number}" ${TOPIC_GROUP_ATTR}="${escapeAttr(info.group || TOPIC_DEFAULT_GROUP)}"`;
|
|
250
|
+
if (info.roman)
|
|
251
|
+
attrs += ` ${TOPIC_ROMAN_ATTR}="true"`;
|
|
252
|
+
if (info.ref)
|
|
253
|
+
attrs += ` ${TOPIC_REF_ATTR}="true"`;
|
|
254
|
+
return `<span ${attrs}>${formatTopicNumber(info.number, info.roman)}</span>`;
|
|
255
|
+
}
|
|
256
|
+
function readTopicNumber(el) {
|
|
257
|
+
const roman = el.getAttribute(TOPIC_ROMAN_ATTR) === "true";
|
|
258
|
+
const raw = el.getAttribute(TOPIC_NUMBER_ATTR) ?? "";
|
|
259
|
+
let number = Number.parseInt(raw, 10);
|
|
260
|
+
if (!Number.isFinite(number)) {
|
|
261
|
+
const text = el.textContent?.trim() ?? "";
|
|
262
|
+
number = Number.parseInt(text, 10);
|
|
263
|
+
if (!Number.isFinite(number))
|
|
264
|
+
number = fromRoman(text) ?? 1;
|
|
265
|
+
}
|
|
266
|
+
return {
|
|
267
|
+
number,
|
|
268
|
+
group: el.getAttribute(TOPIC_GROUP_ATTR) || TOPIC_DEFAULT_GROUP,
|
|
269
|
+
roman,
|
|
270
|
+
ref: el.getAttribute(TOPIC_REF_ATTR) === "true"
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
|
|
274
274
|
function shouldMoveBreakToHeading(params) {
|
|
275
275
|
const { heading, item, pageStart, capacity } = params;
|
|
276
276
|
if (!heading || !heading.heading || heading.marker)
|
|
@@ -897,4 +897,4 @@ function PocPaginationPlugin(cfg) {
|
|
|
897
897
|
});
|
|
898
898
|
}
|
|
899
899
|
|
|
900
|
-
export { shouldMoveBreakToHeading as A, toRoman as B, fromRoman as C, topicNumberHtml as D, PocPaginationPlugin as P, TOPIC_DEFAULT_GROUP as T, formatTopicNumber as a, pocLooksLikeTitle as b,
|
|
900
|
+
export { shouldMoveBreakToHeading as A, toRoman as B, fromRoman as C, topicNumberHtml as D, PocPaginationPlugin as P, TOPIC_DEFAULT_GROUP as T, formatTopicNumber as a, pocLooksLikeTitle as b, pocNodeHasVisibleContent as c, pocNodePaintsBox as d, sanitizeFootnoteHtml as e, footnoteHtmlToRuns as f, footnoteSizePt as g, TOPIC_NUMBER_ATTR as h, TOPIC_GROUP_ATTR as i, TOPIC_ROMAN_ATTR as j, TOPIC_REF_ATTR as k, computePocBreaks as l, pocPageKey as m, breaksEqual as n, PAGINATE_META as o, pocLoneCellIndex as p, pocChromeFlowHeight as q, readTopicNumber as r, sanitizeRichHtml as s, isPocChromeCanvas as t, buildPocHeaderEl as u, buildPocFooterEl as v, buildPocNotesEl as w, pocDescendsInto as x, isPocFlexRow as y, computePocLoneRows as z };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meistrari/minuta-editor",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "Editor de minuta do defesa.ai sem framework: folha A4 paginada, edição rica, placeholders de variável e export DOCX fiel ao preview — monta em qualquer app (React, Vue, vanilla)",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|