@meistrari/minuta-nuxt 1.1.1 → 1.2.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.
- package/dist/module.json +1 -1
- package/dist/runtime/components/MinutaChromeCanvas.vue +1 -1
- package/dist/runtime/components/MinutaChromeEditor.vue +1 -1
- package/dist/runtime/components/MinutaDocxEditor.vue +64 -1302
- package/dist/runtime/components/MinutaEmbed.vue +2 -2
- package/dist/runtime/components/MinutaTemplateEditor.vue +2 -2
- package/dist/runtime/composables/useMinutaApi.d.ts +2 -2
- package/dist/runtime/composables/useMinutaApi.js +1 -1
- package/dist/runtime/composables/vaultImages.d.ts +1 -5
- package/dist/runtime/composables/vaultImages.js +2 -12
- package/package.json +2 -1
- package/dist/runtime/components/MinutaVariablePicker.vue +0 -149
- package/dist/runtime/composables/docxExport.d.ts +0 -24
- package/dist/runtime/composables/docxExport.js +0 -1304
- package/dist/runtime/composables/editorExtensions.d.ts +0 -93
- package/dist/runtime/composables/editorExtensions.js +0 -548
- package/dist/runtime/composables/paginationPlugin.d.ts +0 -139
- package/dist/runtime/composables/paginationPlugin.js +0 -505
- package/dist/runtime/utils/footnoteHtml.d.ts +0 -26
- package/dist/runtime/utils/footnoteHtml.js +0 -117
- package/dist/runtime/utils/pocKeepWithNext.d.ts +0 -44
- package/dist/runtime/utils/pocKeepWithNext.js +0 -9
- package/dist/runtime/utils/sanitizeRichHtml.d.ts +0 -10
- package/dist/runtime/utils/sanitizeRichHtml.js +0 -73
- package/dist/runtime/utils/templateVariables.d.ts +0 -49
- package/dist/runtime/utils/templateVariables.js +0 -36
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import type { Editor } from '@tiptap/core';
|
|
2
|
-
import { Extension as TiptapExtension, Mark as TiptapMark, Node as TiptapNode } from '@tiptap/core';
|
|
3
|
-
import type { EditorView as PMEditorView } from '@tiptap/pm/view';
|
|
4
|
-
import type { PocPageConfig } from './paginationPlugin.js';
|
|
5
|
-
import type { MinutaVariableDef } from '../utils/templateVariables.js';
|
|
6
|
-
/**
|
|
7
|
-
* Extensões Tiptap da PoC do editor de minuta.
|
|
8
|
-
*
|
|
9
|
-
* Modelo: doc → minutaBlock+ → (paragraph | heading | styledDiv | htmlIsland | ...)
|
|
10
|
-
* - minutaBlock: wrapper com proveniência (blockId/título do bloco do template)
|
|
11
|
-
* - htmlIsland: tabelas/listas/imagens/svg preservados como ilhas não-editáveis (HTML cru)
|
|
12
|
-
* - variableChip: <span data-variable-id> vira nó atômico — a variável continua "viva"
|
|
13
|
-
* - templateVariable: <span data-minuta-var> — placeholder NÃO resolvido do template
|
|
14
|
-
* - inlineStyle/styledDiv/passthrough: preservam o CSS inline do pipeline de render
|
|
15
|
-
*/
|
|
16
|
-
/**
|
|
17
|
-
* Meta de transação: troca de imagem fria pelo blob recém-baixado (load
|
|
18
|
-
* progressivo). Não é edição do advogado — fica fora do undo e não pode
|
|
19
|
-
* marcar o documento como sujo (senão o autosave dispara sozinho no load).
|
|
20
|
-
*/
|
|
21
|
-
export declare const POC_ASSET_SWAP = "pocAssetSwap";
|
|
22
|
-
export declare const PocDocument: TiptapNode<any, any>;
|
|
23
|
-
export declare const PocMinutaBlock: TiptapNode<any, any>;
|
|
24
|
-
export declare const PocHtmlIsland: TiptapNode<any, any>;
|
|
25
|
-
/**
|
|
26
|
-
* Aviso de imagem faltando — a caixa tracejada que o render emite quando a
|
|
27
|
-
* variável de imagem não foi preenchida.
|
|
28
|
-
*
|
|
29
|
-
* Antes ela chegava aqui como um `styledDiv` comum: apagar exigia selecionar o
|
|
30
|
-
* texto por dentro, e a moldura sobrava no documento. Como nó próprio ela é
|
|
31
|
-
* atômica e selecionável (um clique + Backspace resolve), ganha um botão de
|
|
32
|
-
* remover e um alvo de clique para escolher a imagem ali mesmo.
|
|
33
|
-
*
|
|
34
|
-
* Na etapa de edição o DOCUMENTO é a verdade — o checklist fica travado —, então
|
|
35
|
-
* escolher a imagem insere no texto editado; não mexe na variável do caso.
|
|
36
|
-
*
|
|
37
|
-
* O nó guarda só o ID da variável e REDESENHA a caixa a partir dele. Guardar o
|
|
38
|
-
* `outerHTML` e devolvê-lo a um `innerHTML` faria do corpo da edição — que é
|
|
39
|
-
* dado persistido, editável por qualquer um do workspace — um vetor de stored
|
|
40
|
-
* XSS: bastaria uma `div.missing-image-warning` forjada com `onerror` para
|
|
41
|
-
* rodar script no editor de quem abrisse o caso depois.
|
|
42
|
-
*/
|
|
43
|
-
export declare const PocMissingImage: TiptapNode<any, any>;
|
|
44
|
-
export declare const PocVariableChip: TiptapNode<any, any>;
|
|
45
|
-
/**
|
|
46
|
-
* Placeholder de variável do TEMPLATE — o `#NOME_VARIAVEL` de antigamente, só
|
|
47
|
-
* que como nó atômico em vez de texto (ver `utils/templateVariables.ts` para o
|
|
48
|
-
* porquê e para o formato).
|
|
49
|
-
*
|
|
50
|
-
* O catálogo (`options.catalog`) vem do app hospedeiro: o CDB não sabe o que é
|
|
51
|
-
* `SIGLA_FORO`, só sabe que existe um lugar no documento com esse nome. O nó
|
|
52
|
-
* guarda o rótulo junto (para um template abrir legível sem catálogo, ex.: no
|
|
53
|
-
* histórico), mas quem manda na exibição é o catálogo — renomear uma variável
|
|
54
|
-
* no host reflete em todo template já salvo, sem migrar documento nenhum.
|
|
55
|
-
*
|
|
56
|
-
* Sobrevive à geração: `resolveTemplateVariables` só troca o que tem valor, e o
|
|
57
|
-
* que sobra continua sendo este nó — um buraco visível no parágrafo em que ele
|
|
58
|
-
* está, e não um erro genérico no rodapé de um modal.
|
|
59
|
-
*/
|
|
60
|
-
/** o catálogo pode chegar depois do mount (host que carrega async) — daí o getter */
|
|
61
|
-
export type MinutaVariableCatalog = MinutaVariableDef[] | (() => MinutaVariableDef[]);
|
|
62
|
-
export declare const PocTemplateVariable: TiptapNode<{
|
|
63
|
-
catalog: MinutaVariableCatalog;
|
|
64
|
-
}, any>;
|
|
65
|
-
/**
|
|
66
|
-
* Nota de rodapé: o render devolve `<sup data-footnote="texto">n</sup>` e o
|
|
67
|
-
* export transforma em nota de rodapé DE VERDADE no Word (o pipeline legado faz
|
|
68
|
-
* o mesmo via footnotes_filter.lua do conversor). Precisa ser um nó do schema —
|
|
69
|
-
* senão o Tiptap descarta o data-footnote no round-trip e o texto da nota some.
|
|
70
|
-
*/
|
|
71
|
-
export declare const PocFootnoteRef: TiptapNode<any, any>;
|
|
72
|
-
/** re-sequencia a numeração das chamadas de nota na ordem do documento */
|
|
73
|
-
export declare function renumberPocFootnotes(editor: Editor): void;
|
|
74
|
-
export declare const PocStyledDiv: TiptapNode<any, any>;
|
|
75
|
-
export declare const PocInlineStyle: TiptapMark<any, any>;
|
|
76
|
-
export declare const PocUnderline: TiptapMark<any, any>;
|
|
77
|
-
/** Preserva style/class inline nos blocos de texto (o pipeline de render inlina todo o CSS). */
|
|
78
|
-
export declare const PocStylePassthrough: TiptapExtension<any, any>;
|
|
79
|
-
export declare function buildPocExtensions(pageConfig?: PocPageConfig, options?: {
|
|
80
|
-
/** catálogo de variáveis do host — habilita os chips do modo template */
|
|
81
|
-
variables?: MinutaVariableCatalog;
|
|
82
|
-
/**
|
|
83
|
-
* Primeiro a ver o teclado, ANTES do keymap do editor. Devolver `true`
|
|
84
|
-
* consome a tecla.
|
|
85
|
-
*
|
|
86
|
-
* Existe porque `editorProps.handleKeyDown` não serve: o `someProp` do
|
|
87
|
-
* ProseMirror percorre os plugins antes das props diretas, então o keymap
|
|
88
|
-
* do StarterKit trata o Enter (quebra o parágrafo) e o handler da view
|
|
89
|
-
* nunca roda. Quem precisa de um popover dirigido pelo teclado com o foco
|
|
90
|
-
* ainda no editor — o seletor de variável — depende disso.
|
|
91
|
-
*/
|
|
92
|
-
handleKeyDown?: (view: PMEditorView, event: KeyboardEvent) => boolean;
|
|
93
|
-
}): (TiptapNode<any, any> | TiptapMark<any, any> | TiptapExtension<any, any>)[];
|
|
@@ -1,548 +0,0 @@
|
|
|
1
|
-
import { Extension as TiptapExtension, Mark as TiptapMark, Node as TiptapNode, mergeAttributes } from "@tiptap/core";
|
|
2
|
-
import TiptapStarterKit from "@tiptap/starter-kit";
|
|
3
|
-
import Table from "@tiptap/extension-table";
|
|
4
|
-
import TableCell from "@tiptap/extension-table-cell";
|
|
5
|
-
import TableHeader from "@tiptap/extension-table-header";
|
|
6
|
-
import TableRow from "@tiptap/extension-table-row";
|
|
7
|
-
import { Plugin as PMPlugin } from "@tiptap/pm/state";
|
|
8
|
-
import { sanitizeRichHtml } from "../utils/sanitizeRichHtml.js";
|
|
9
|
-
import { PocPaginationPlugin } from "./paginationPlugin.js";
|
|
10
|
-
export const POC_ASSET_SWAP = "pocAssetSwap";
|
|
11
|
-
function htmlToDom(html) {
|
|
12
|
-
const tpl = document.createElement("template");
|
|
13
|
-
tpl.innerHTML = sanitizeRichHtml(html);
|
|
14
|
-
return tpl.content.firstElementChild ?? document.createElement("div");
|
|
15
|
-
}
|
|
16
|
-
export const PocDocument = TiptapNode.create({
|
|
17
|
-
name: "doc",
|
|
18
|
-
topNode: true,
|
|
19
|
-
content: "minutaBlock+"
|
|
20
|
-
});
|
|
21
|
-
export const PocMinutaBlock = TiptapNode.create({
|
|
22
|
-
name: "minutaBlock",
|
|
23
|
-
group: "block",
|
|
24
|
-
content: "block+",
|
|
25
|
-
defining: true,
|
|
26
|
-
isolating: true,
|
|
27
|
-
addAttributes() {
|
|
28
|
-
return {
|
|
29
|
-
blockId: { default: null },
|
|
30
|
-
blockTitle: { default: null }
|
|
31
|
-
};
|
|
32
|
-
},
|
|
33
|
-
parseHTML() {
|
|
34
|
-
return [{
|
|
35
|
-
tag: "div[data-minuta-block]",
|
|
36
|
-
priority: 120,
|
|
37
|
-
getAttrs: (el) => ({
|
|
38
|
-
blockId: el.getAttribute("data-block-id"),
|
|
39
|
-
blockTitle: el.getAttribute("data-block-title")
|
|
40
|
-
})
|
|
41
|
-
}];
|
|
42
|
-
},
|
|
43
|
-
renderHTML({ HTMLAttributes, node }) {
|
|
44
|
-
return ["div", mergeAttributes(HTMLAttributes, {
|
|
45
|
-
"data-minuta-block": "",
|
|
46
|
-
"data-block-id": node.attrs.blockId,
|
|
47
|
-
"data-block-title": node.attrs.blockTitle,
|
|
48
|
-
"class": "poc-minuta-block"
|
|
49
|
-
}), 0];
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
export const PocHtmlIsland = TiptapNode.create({
|
|
53
|
-
name: "htmlIsland",
|
|
54
|
-
group: "block",
|
|
55
|
-
atom: true,
|
|
56
|
-
selectable: true,
|
|
57
|
-
// atomos arrastáveis: mover imagens/tabelas pelo documento
|
|
58
|
-
draggable: true,
|
|
59
|
-
addAttributes() {
|
|
60
|
-
return { html: { default: "" } };
|
|
61
|
-
},
|
|
62
|
-
parseHTML() {
|
|
63
|
-
const capture = (el) => ({ html: el.outerHTML });
|
|
64
|
-
return ["ul", "ol", "img", "figure", "svg"].map((tag) => ({
|
|
65
|
-
tag,
|
|
66
|
-
priority: 100,
|
|
67
|
-
getAttrs: capture
|
|
68
|
-
}));
|
|
69
|
-
},
|
|
70
|
-
renderHTML({ node }) {
|
|
71
|
-
return htmlToDom(node.attrs.html);
|
|
72
|
-
},
|
|
73
|
-
addNodeView() {
|
|
74
|
-
return ({ node, getPos, editor }) => {
|
|
75
|
-
const dom = document.createElement("div");
|
|
76
|
-
dom.className = "poc-island";
|
|
77
|
-
dom.contentEditable = "false";
|
|
78
|
-
dom.innerHTML = sanitizeRichHtml(node.attrs.html);
|
|
79
|
-
const img = dom.children.length === 1 && dom.firstElementChild instanceof HTMLImageElement ? dom.firstElementChild : null;
|
|
80
|
-
if (img)
|
|
81
|
-
dom.classList.add("poc-island--img");
|
|
82
|
-
if (img && editor.isEditable) {
|
|
83
|
-
const handle = document.createElement("div");
|
|
84
|
-
handle.className = "poc-img-handle";
|
|
85
|
-
handle.title = "Arraste para redimensionar";
|
|
86
|
-
dom.appendChild(handle);
|
|
87
|
-
let startX = 0;
|
|
88
|
-
let startWidth = 0;
|
|
89
|
-
let scale = 1;
|
|
90
|
-
let maxWidth = Number.POSITIVE_INFINITY;
|
|
91
|
-
const onMove = (event) => {
|
|
92
|
-
const width = Math.round(startWidth + (event.clientX - startX) / scale);
|
|
93
|
-
img.style.width = `${Math.min(maxWidth, Math.max(40, width))}px`;
|
|
94
|
-
img.style.height = "auto";
|
|
95
|
-
};
|
|
96
|
-
const onUp = () => {
|
|
97
|
-
document.removeEventListener("mousemove", onMove);
|
|
98
|
-
document.removeEventListener("mouseup", onUp);
|
|
99
|
-
const pos = typeof getPos === "function" ? getPos() : null;
|
|
100
|
-
if (typeof pos === "number") {
|
|
101
|
-
const clone = dom.cloneNode(true);
|
|
102
|
-
clone.querySelector(".poc-img-handle")?.remove();
|
|
103
|
-
editor.view.dispatch(
|
|
104
|
-
editor.state.tr.setNodeMarkup(pos, void 0, { html: clone.innerHTML })
|
|
105
|
-
);
|
|
106
|
-
}
|
|
107
|
-
};
|
|
108
|
-
handle.addEventListener("mousedown", (event) => {
|
|
109
|
-
event.preventDefault();
|
|
110
|
-
event.stopPropagation();
|
|
111
|
-
startX = event.clientX;
|
|
112
|
-
startWidth = img.offsetWidth;
|
|
113
|
-
scale = img.offsetWidth ? img.getBoundingClientRect().width / img.offsetWidth : 1;
|
|
114
|
-
maxWidth = dom.parentElement?.clientWidth || Number.POSITIVE_INFINITY;
|
|
115
|
-
document.addEventListener("mousemove", onMove);
|
|
116
|
-
document.addEventListener("mouseup", onUp);
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
return { dom };
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
});
|
|
123
|
-
let missingImageSeq = 0;
|
|
124
|
-
function nextMissingImageUid() {
|
|
125
|
-
missingImageSeq += 1;
|
|
126
|
-
return `mi-${missingImageSeq}`;
|
|
127
|
-
}
|
|
128
|
-
const MISSING_IMAGE_BOX_STYLE = "box-sizing: border-box; max-width: 100%; border: 2px dashed rgba(223, 139, 13, 0.43); padding: 16px; margin: 12px 0; border-radius: 8px; background-color: rgba(254, 174, 0, 0.03); color: rgb(119, 54, 19); text-align: center; box-shadow: inset 0 0 8px #e6510011;";
|
|
129
|
-
const MISSING_IMAGE_ROW_STYLE = "display: flex; align-items: center; justify-content: center; gap: 8px;";
|
|
130
|
-
export const PocMissingImage = TiptapNode.create({
|
|
131
|
-
name: "missingImage",
|
|
132
|
-
group: "block",
|
|
133
|
-
atom: true,
|
|
134
|
-
selectable: true,
|
|
135
|
-
draggable: true,
|
|
136
|
-
addAttributes() {
|
|
137
|
-
return {
|
|
138
|
-
variableId: { default: null },
|
|
139
|
-
parentBlockId: { default: null },
|
|
140
|
-
/**
|
|
141
|
-
* Identidade do nó DENTRO desta sessão do editor.
|
|
142
|
-
*
|
|
143
|
-
* Um fluxo demorado (escolher arquivo + upload) precisa voltar
|
|
144
|
-
* exatamente ao aviso que foi clicado. Posição não serve: o
|
|
145
|
-
* documento muda no meio. Tipo + variável também não: o mesmo
|
|
146
|
-
* aviso pode aparecer várias vezes, e um delete+insert põe outro
|
|
147
|
-
* igual no mesmo lugar. Com um id por nó, achar é inequívoco —
|
|
148
|
-
* se ele sumiu, não achamos; se ele andou, achamos onde parou.
|
|
149
|
-
*
|
|
150
|
-
* Gerado no parse e NÃO serializado: vale enquanto o editor viver,
|
|
151
|
-
* que é o tempo de vida do fluxo. Colar um aviso passa pelo parse
|
|
152
|
-
* de novo e ganha id próprio, então nunca há dois iguais.
|
|
153
|
-
*/
|
|
154
|
-
uid: { default: null }
|
|
155
|
-
};
|
|
156
|
-
},
|
|
157
|
-
parseHTML() {
|
|
158
|
-
return [{
|
|
159
|
-
tag: "div.missing-image-warning",
|
|
160
|
-
// acima do styledDiv (40), senão a caixa vira container editável de novo
|
|
161
|
-
priority: 120,
|
|
162
|
-
getAttrs: (el) => ({
|
|
163
|
-
variableId: el.getAttribute("data-variable-id"),
|
|
164
|
-
parentBlockId: el.getAttribute("data-parent-block-id"),
|
|
165
|
-
uid: nextMissingImageUid()
|
|
166
|
-
})
|
|
167
|
-
}];
|
|
168
|
-
},
|
|
169
|
-
renderHTML({ node }) {
|
|
170
|
-
return [
|
|
171
|
-
"div",
|
|
172
|
-
{
|
|
173
|
-
"class": "missing-image-warning",
|
|
174
|
-
"data-variable-id": node.attrs.variableId ?? "",
|
|
175
|
-
"data-parent-block-id": node.attrs.parentBlockId ?? "",
|
|
176
|
-
"style": MISSING_IMAGE_BOX_STYLE
|
|
177
|
-
// `uid` fica de fora de propósito: é identidade de sessão, não dado
|
|
178
|
-
},
|
|
179
|
-
["span", { style: MISSING_IMAGE_ROW_STYLE }, `A imagem ${node.attrs.variableId ?? ""} est\xE1 faltando`]
|
|
180
|
-
];
|
|
181
|
-
},
|
|
182
|
-
addNodeView() {
|
|
183
|
-
return ({ node, getPos, editor }) => {
|
|
184
|
-
const dom = document.createElement("div");
|
|
185
|
-
dom.className = "poc-missing-image";
|
|
186
|
-
dom.contentEditable = "false";
|
|
187
|
-
const caixa = document.createElement("div");
|
|
188
|
-
caixa.className = "missing-image-warning";
|
|
189
|
-
caixa.setAttribute("style", MISSING_IMAGE_BOX_STYLE);
|
|
190
|
-
const linha = document.createElement("span");
|
|
191
|
-
linha.setAttribute("style", MISSING_IMAGE_ROW_STYLE);
|
|
192
|
-
linha.textContent = `\u26A0 A imagem ${node.attrs.variableId ?? ""} est\xE1 faltando`;
|
|
193
|
-
caixa.appendChild(linha);
|
|
194
|
-
dom.appendChild(caixa);
|
|
195
|
-
if (!editor.isEditable)
|
|
196
|
-
return { dom };
|
|
197
|
-
caixa.style.position = "relative";
|
|
198
|
-
caixa.style.cursor = "pointer";
|
|
199
|
-
caixa.title = "Clique para escolher uma imagem";
|
|
200
|
-
const remover = document.createElement("button");
|
|
201
|
-
remover.type = "button";
|
|
202
|
-
remover.className = "poc-missing-image__remove";
|
|
203
|
-
remover.title = "Remover este aviso";
|
|
204
|
-
remover.setAttribute("aria-label", "Remover este aviso");
|
|
205
|
-
remover.textContent = "\xD7";
|
|
206
|
-
remover.addEventListener("mousedown", (event) => {
|
|
207
|
-
event.preventDefault();
|
|
208
|
-
event.stopPropagation();
|
|
209
|
-
const pos = typeof getPos === "function" ? getPos() : null;
|
|
210
|
-
if (typeof pos === "number")
|
|
211
|
-
editor.view.dispatch(editor.state.tr.delete(pos, pos + node.nodeSize));
|
|
212
|
-
});
|
|
213
|
-
caixa.appendChild(remover);
|
|
214
|
-
dom.addEventListener("click", (event) => {
|
|
215
|
-
if (event.target.closest(".poc-missing-image__remove"))
|
|
216
|
-
return;
|
|
217
|
-
event.preventDefault();
|
|
218
|
-
const pos = typeof getPos === "function" ? getPos() : null;
|
|
219
|
-
window.dispatchEvent(new CustomEvent("poc:pick-image", {
|
|
220
|
-
detail: { variableId: node.attrs.variableId, uid: node.attrs.uid, hintPos: pos }
|
|
221
|
-
}));
|
|
222
|
-
});
|
|
223
|
-
return { dom };
|
|
224
|
-
};
|
|
225
|
-
}
|
|
226
|
-
});
|
|
227
|
-
export const PocVariableChip = TiptapNode.create({
|
|
228
|
-
name: "variableChip",
|
|
229
|
-
inline: true,
|
|
230
|
-
group: "inline",
|
|
231
|
-
atom: true,
|
|
232
|
-
selectable: true,
|
|
233
|
-
addAttributes() {
|
|
234
|
-
return {
|
|
235
|
-
variableId: { default: null },
|
|
236
|
-
parentBlockId: { default: null },
|
|
237
|
-
html: { default: "" },
|
|
238
|
-
text: { default: "" }
|
|
239
|
-
};
|
|
240
|
-
},
|
|
241
|
-
parseHTML() {
|
|
242
|
-
return [{
|
|
243
|
-
tag: "span[data-variable-id]",
|
|
244
|
-
priority: 110,
|
|
245
|
-
getAttrs: (el) => ({
|
|
246
|
-
variableId: el.getAttribute("data-variable-id"),
|
|
247
|
-
parentBlockId: el.getAttribute("data-parent-block-id"),
|
|
248
|
-
html: el.outerHTML,
|
|
249
|
-
text: el.textContent ?? ""
|
|
250
|
-
})
|
|
251
|
-
}];
|
|
252
|
-
},
|
|
253
|
-
renderHTML({ node }) {
|
|
254
|
-
return htmlToDom(node.attrs.html);
|
|
255
|
-
},
|
|
256
|
-
addNodeView() {
|
|
257
|
-
return ({ node }) => {
|
|
258
|
-
const dom = document.createElement("span");
|
|
259
|
-
dom.className = "poc-varchip";
|
|
260
|
-
dom.contentEditable = "false";
|
|
261
|
-
dom.innerHTML = sanitizeRichHtml(node.attrs.html);
|
|
262
|
-
dom.addEventListener("click", (event) => {
|
|
263
|
-
event.preventDefault();
|
|
264
|
-
window.dispatchEvent(new CustomEvent("poc:variable-click", {
|
|
265
|
-
detail: {
|
|
266
|
-
variableId: node.attrs.variableId,
|
|
267
|
-
parentBlockId: node.attrs.parentBlockId,
|
|
268
|
-
text: node.attrs.text
|
|
269
|
-
}
|
|
270
|
-
}));
|
|
271
|
-
});
|
|
272
|
-
return { dom };
|
|
273
|
-
};
|
|
274
|
-
}
|
|
275
|
-
});
|
|
276
|
-
function readCatalog(catalog) {
|
|
277
|
-
return typeof catalog === "function" ? catalog() : catalog;
|
|
278
|
-
}
|
|
279
|
-
export const PocTemplateVariable = TiptapNode.create({
|
|
280
|
-
name: "templateVariable",
|
|
281
|
-
inline: true,
|
|
282
|
-
group: "inline",
|
|
283
|
-
atom: true,
|
|
284
|
-
selectable: true,
|
|
285
|
-
addOptions() {
|
|
286
|
-
return { catalog: [] };
|
|
287
|
-
},
|
|
288
|
-
addAttributes() {
|
|
289
|
-
return {
|
|
290
|
-
varKey: { default: null },
|
|
291
|
-
label: { default: null }
|
|
292
|
-
};
|
|
293
|
-
},
|
|
294
|
-
parseHTML() {
|
|
295
|
-
return [{
|
|
296
|
-
// acima do PocInlineStyle (40): é nó, não span estilizado
|
|
297
|
-
tag: "span[data-minuta-var]",
|
|
298
|
-
priority: 115,
|
|
299
|
-
getAttrs: (el) => {
|
|
300
|
-
const key = el.getAttribute("data-minuta-var")?.trim();
|
|
301
|
-
if (!key)
|
|
302
|
-
return false;
|
|
303
|
-
return {
|
|
304
|
-
varKey: key,
|
|
305
|
-
label: el.getAttribute("data-minuta-var-label")?.trim() || el.textContent?.trim() || key
|
|
306
|
-
};
|
|
307
|
-
}
|
|
308
|
-
}];
|
|
309
|
-
},
|
|
310
|
-
renderHTML({ node }) {
|
|
311
|
-
const key = node.attrs.varKey ?? "";
|
|
312
|
-
const label = node.attrs.label || key;
|
|
313
|
-
return ["span", {
|
|
314
|
-
"data-minuta-var": key,
|
|
315
|
-
"data-minuta-var-label": label,
|
|
316
|
-
"class": "poc-tplvar"
|
|
317
|
-
}, label];
|
|
318
|
-
},
|
|
319
|
-
addNodeView() {
|
|
320
|
-
return ({ node }) => {
|
|
321
|
-
const key = node.attrs.varKey ?? "";
|
|
322
|
-
const catalog = readCatalog(this.options.catalog);
|
|
323
|
-
const def = catalog.find((item) => item.key === key);
|
|
324
|
-
const dom = document.createElement("span");
|
|
325
|
-
dom.className = "poc-tplvar";
|
|
326
|
-
dom.contentEditable = "false";
|
|
327
|
-
dom.setAttribute("data-minuta-var", key);
|
|
328
|
-
dom.textContent = def?.label || node.attrs.label || key;
|
|
329
|
-
dom.title = def?.description ? `${key} \u2014 ${def.description}` : key;
|
|
330
|
-
if (catalog.length && !def)
|
|
331
|
-
dom.classList.add("poc-tplvar--unknown");
|
|
332
|
-
return { dom };
|
|
333
|
-
};
|
|
334
|
-
},
|
|
335
|
-
addCommands() {
|
|
336
|
-
return {
|
|
337
|
-
insertTemplateVariable: (variable) => ({ commands }) => commands.insertContent({
|
|
338
|
-
type: "templateVariable",
|
|
339
|
-
attrs: { varKey: variable.key, label: variable.label }
|
|
340
|
-
})
|
|
341
|
-
};
|
|
342
|
-
}
|
|
343
|
-
});
|
|
344
|
-
export const PocFootnoteRef = TiptapNode.create({
|
|
345
|
-
name: "footnoteRef",
|
|
346
|
-
inline: true,
|
|
347
|
-
group: "inline",
|
|
348
|
-
atom: true,
|
|
349
|
-
selectable: false,
|
|
350
|
-
addAttributes() {
|
|
351
|
-
return {
|
|
352
|
-
number: { default: "" },
|
|
353
|
-
/** conteúdo da nota em HTML de ênfase (b/i/u/br) */
|
|
354
|
-
text: { default: "" },
|
|
355
|
-
/** corpo declarado no template (`font-size: 9pt`), em pontos */
|
|
356
|
-
size: { default: null }
|
|
357
|
-
};
|
|
358
|
-
},
|
|
359
|
-
parseHTML() {
|
|
360
|
-
return [{
|
|
361
|
-
tag: "sup[data-footnote]",
|
|
362
|
-
priority: 110,
|
|
363
|
-
getAttrs: (el) => ({
|
|
364
|
-
number: el.textContent ?? "",
|
|
365
|
-
text: el.getAttribute("data-footnote") ?? "",
|
|
366
|
-
size: Number.parseFloat(el.getAttribute("data-footnote-size") ?? "") || null
|
|
367
|
-
})
|
|
368
|
-
}];
|
|
369
|
-
},
|
|
370
|
-
renderHTML({ node }) {
|
|
371
|
-
const attrs = { "data-footnote": node.attrs.text, "class": "poc-footnote" };
|
|
372
|
-
if (node.attrs.size)
|
|
373
|
-
attrs["data-footnote-size"] = String(node.attrs.size);
|
|
374
|
-
return ["sup", attrs, node.attrs.number];
|
|
375
|
-
},
|
|
376
|
-
addNodeView() {
|
|
377
|
-
return ({ node, editor, getPos }) => {
|
|
378
|
-
const dom = document.createElement("sup");
|
|
379
|
-
dom.className = "poc-footnote";
|
|
380
|
-
dom.contentEditable = "false";
|
|
381
|
-
dom.textContent = node.attrs.number;
|
|
382
|
-
dom.title = node.attrs.text;
|
|
383
|
-
dom.addEventListener("click", (event) => {
|
|
384
|
-
if (!editor.isEditable || typeof getPos !== "function")
|
|
385
|
-
return;
|
|
386
|
-
event.preventDefault();
|
|
387
|
-
event.stopPropagation();
|
|
388
|
-
const pos = getPos();
|
|
389
|
-
if (pos == null)
|
|
390
|
-
return;
|
|
391
|
-
window.dispatchEvent(new CustomEvent("poc:edit-footnote", { detail: { pos } }));
|
|
392
|
-
});
|
|
393
|
-
return { dom };
|
|
394
|
-
};
|
|
395
|
-
}
|
|
396
|
-
});
|
|
397
|
-
export function renumberPocFootnotes(editor) {
|
|
398
|
-
if (!editor || editor.isDestroyed)
|
|
399
|
-
return;
|
|
400
|
-
const tr = editor.state.tr;
|
|
401
|
-
let index = 0;
|
|
402
|
-
let touched = false;
|
|
403
|
-
editor.state.doc.descendants((node, pos) => {
|
|
404
|
-
if (node.type.name !== "footnoteRef")
|
|
405
|
-
return;
|
|
406
|
-
index++;
|
|
407
|
-
const number = String(index);
|
|
408
|
-
if (node.attrs.number !== number) {
|
|
409
|
-
tr.setNodeMarkup(pos, void 0, { ...node.attrs, number });
|
|
410
|
-
touched = true;
|
|
411
|
-
}
|
|
412
|
-
});
|
|
413
|
-
if (touched)
|
|
414
|
-
editor.view.dispatch(tr);
|
|
415
|
-
}
|
|
416
|
-
export const PocStyledDiv = TiptapNode.create({
|
|
417
|
-
name: "styledDiv",
|
|
418
|
-
group: "block",
|
|
419
|
-
content: "block+",
|
|
420
|
-
addAttributes() {
|
|
421
|
-
const passthrough = (name) => ({
|
|
422
|
-
default: null,
|
|
423
|
-
parseHTML: (el) => el.getAttribute(name),
|
|
424
|
-
renderHTML: (attrs) => attrs[name] != null ? { [name]: attrs[name] } : {}
|
|
425
|
-
});
|
|
426
|
-
return {
|
|
427
|
-
"style": { default: null },
|
|
428
|
-
"class": { default: null },
|
|
429
|
-
// alinhamento de colunas do template (usado pelo CSS de centralização de imagens)
|
|
430
|
-
"data-horizontal-align": passthrough("data-horizontal-align"),
|
|
431
|
-
"data-vertical-align": passthrough("data-vertical-align"),
|
|
432
|
-
"data-width": passthrough("data-width")
|
|
433
|
-
};
|
|
434
|
-
},
|
|
435
|
-
parseHTML() {
|
|
436
|
-
return [{
|
|
437
|
-
tag: "div",
|
|
438
|
-
priority: 40,
|
|
439
|
-
getAttrs: (el) => {
|
|
440
|
-
if (el.hasAttribute("data-minuta-block"))
|
|
441
|
-
return false;
|
|
442
|
-
return { style: el.getAttribute("style"), class: el.getAttribute("class") };
|
|
443
|
-
}
|
|
444
|
-
}];
|
|
445
|
-
},
|
|
446
|
-
renderHTML({ HTMLAttributes }) {
|
|
447
|
-
return ["div", mergeAttributes(HTMLAttributes), 0];
|
|
448
|
-
}
|
|
449
|
-
});
|
|
450
|
-
export const PocInlineStyle = TiptapMark.create({
|
|
451
|
-
name: "inlineStyle",
|
|
452
|
-
addAttributes() {
|
|
453
|
-
return {
|
|
454
|
-
style: { default: null },
|
|
455
|
-
class: { default: null }
|
|
456
|
-
};
|
|
457
|
-
},
|
|
458
|
-
parseHTML() {
|
|
459
|
-
return [{
|
|
460
|
-
tag: "span",
|
|
461
|
-
priority: 40,
|
|
462
|
-
getAttrs: (el) => {
|
|
463
|
-
if (el.hasAttribute("data-variable-id") || el.hasAttribute("data-minuta-var"))
|
|
464
|
-
return false;
|
|
465
|
-
const style = el.getAttribute("style");
|
|
466
|
-
const cls = el.getAttribute("class");
|
|
467
|
-
if (!style && !cls)
|
|
468
|
-
return false;
|
|
469
|
-
return { style, class: cls };
|
|
470
|
-
}
|
|
471
|
-
}];
|
|
472
|
-
},
|
|
473
|
-
renderHTML({ HTMLAttributes }) {
|
|
474
|
-
return ["span", mergeAttributes(HTMLAttributes), 0];
|
|
475
|
-
}
|
|
476
|
-
});
|
|
477
|
-
export const PocUnderline = TiptapMark.create({
|
|
478
|
-
name: "underline",
|
|
479
|
-
parseHTML() {
|
|
480
|
-
return [
|
|
481
|
-
{ tag: "u" },
|
|
482
|
-
{ style: "text-decoration", consuming: false, getAttrs: (value) => value.includes("underline") ? {} : false }
|
|
483
|
-
];
|
|
484
|
-
},
|
|
485
|
-
renderHTML() {
|
|
486
|
-
return ["u", 0];
|
|
487
|
-
},
|
|
488
|
-
addCommands() {
|
|
489
|
-
return {
|
|
490
|
-
toggleUnderline: () => ({ commands }) => commands.toggleMark("underline")
|
|
491
|
-
};
|
|
492
|
-
}
|
|
493
|
-
});
|
|
494
|
-
export const PocStylePassthrough = TiptapExtension.create({
|
|
495
|
-
name: "pocStylePassthrough",
|
|
496
|
-
addGlobalAttributes() {
|
|
497
|
-
const attr = (name) => ({
|
|
498
|
-
default: null,
|
|
499
|
-
parseHTML: (el) => el.getAttribute(name),
|
|
500
|
-
renderHTML: (attrs) => attrs[name] ? { [name]: attrs[name] } : {}
|
|
501
|
-
});
|
|
502
|
-
return [{
|
|
503
|
-
types: ["paragraph", "heading", "blockquote", "table", "tableRow", "tableCell", "tableHeader"],
|
|
504
|
-
attributes: { style: attr("style"), class: attr("class") }
|
|
505
|
-
}];
|
|
506
|
-
}
|
|
507
|
-
});
|
|
508
|
-
export function buildPocExtensions(pageConfig, options) {
|
|
509
|
-
const extensions = [
|
|
510
|
-
PocDocument,
|
|
511
|
-
TiptapStarterKit.configure({ document: false }),
|
|
512
|
-
Table.configure({ resizable: true }),
|
|
513
|
-
TableRow,
|
|
514
|
-
TableCell,
|
|
515
|
-
TableHeader,
|
|
516
|
-
PocMinutaBlock,
|
|
517
|
-
PocHtmlIsland,
|
|
518
|
-
PocMissingImage,
|
|
519
|
-
PocVariableChip,
|
|
520
|
-
PocTemplateVariable.configure({ catalog: options?.variables ?? [] }),
|
|
521
|
-
PocFootnoteRef,
|
|
522
|
-
PocStyledDiv,
|
|
523
|
-
PocInlineStyle,
|
|
524
|
-
PocUnderline,
|
|
525
|
-
PocStylePassthrough
|
|
526
|
-
];
|
|
527
|
-
const handleKeyDown = options?.handleKeyDown;
|
|
528
|
-
if (handleKeyDown) {
|
|
529
|
-
extensions.push(TiptapExtension.create({
|
|
530
|
-
name: "pocKeyDownFirst",
|
|
531
|
-
// acima do StarterKit (100): o ExtensionManager ordena os plugins
|
|
532
|
-
// por prioridade, e é essa ordem que o someProp percorre
|
|
533
|
-
priority: 1e3,
|
|
534
|
-
addProseMirrorPlugins() {
|
|
535
|
-
return [new PMPlugin({ props: { handleKeyDown } })];
|
|
536
|
-
}
|
|
537
|
-
}));
|
|
538
|
-
}
|
|
539
|
-
if (pageConfig) {
|
|
540
|
-
extensions.push(TiptapExtension.create({
|
|
541
|
-
name: "pocPagination",
|
|
542
|
-
addProseMirrorPlugins() {
|
|
543
|
-
return [PocPaginationPlugin(pageConfig)];
|
|
544
|
-
}
|
|
545
|
-
}));
|
|
546
|
-
}
|
|
547
|
-
return extensions;
|
|
548
|
-
}
|