@editora/core 1.0.1 → 1.0.2
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/README.md +9 -0
- package/dist/A11yCheckerPlugin.native-CZKpi3uF.mjs +475 -0
- package/dist/A11yCheckerPlugin.native-CZKpi3uF.mjs.map +1 -0
- package/dist/AnchorPlugin.native-7es9PVZ9.mjs +340 -0
- package/dist/AnchorPlugin.native-7es9PVZ9.mjs.map +1 -0
- package/dist/BackgroundColorPlugin.native-Dip5uqTg.mjs +449 -0
- package/dist/BackgroundColorPlugin.native-Dip5uqTg.mjs.map +1 -0
- package/dist/BlockquotePlugin.native-JFmOLsxN.mjs +48 -0
- package/dist/BlockquotePlugin.native-JFmOLsxN.mjs.map +1 -0
- package/dist/BoldPlugin.native-BAzzoqU5.mjs +45 -0
- package/dist/BoldPlugin.native-BAzzoqU5.mjs.map +1 -0
- package/dist/CapitalizationPlugin.native-DOMsh5R7.mjs +79 -0
- package/dist/CapitalizationPlugin.native-DOMsh5R7.mjs.map +1 -0
- package/dist/ChecklistPlugin.native-Dccs3nLe.mjs +153 -0
- package/dist/ChecklistPlugin.native-Dccs3nLe.mjs.map +1 -0
- package/dist/ClearFormattingPlugin.native-BZPDHswo.mjs +27 -0
- package/dist/ClearFormattingPlugin.native-BZPDHswo.mjs.map +1 -0
- package/dist/CodePlugin.native-DD9xFIid.mjs +1679 -0
- package/dist/CodePlugin.native-DD9xFIid.mjs.map +1 -0
- package/dist/CodeSamplePlugin.native-DMbEdO9j.mjs +326 -0
- package/dist/CodeSamplePlugin.native-DMbEdO9j.mjs.map +1 -0
- package/dist/CommentsPlugin.native-2zQV8Ia4.mjs +473 -0
- package/dist/CommentsPlugin.native-2zQV8Ia4.mjs.map +1 -0
- package/dist/DirectionPlugin.native-Be7wCzkI.mjs +59 -0
- package/dist/DirectionPlugin.native-Be7wCzkI.mjs.map +1 -0
- package/dist/DocumentManagerPlugin.native-BvZL5CSG.mjs +116 -0
- package/dist/DocumentManagerPlugin.native-BvZL5CSG.mjs.map +1 -0
- package/dist/EmbedIframePlugin.native-ifr9KLdN.mjs +461 -0
- package/dist/EmbedIframePlugin.native-ifr9KLdN.mjs.map +1 -0
- package/dist/EmojisPlugin.native-D6mJSnSR.mjs +1033 -0
- package/dist/EmojisPlugin.native-D6mJSnSR.mjs.map +1 -0
- package/dist/FontFamilyPlugin.native-BzS_9qbM.mjs +106 -0
- package/dist/FontFamilyPlugin.native-BzS_9qbM.mjs.map +1 -0
- package/dist/FontSizePlugin.native-DkLMLPue.mjs +186 -0
- package/dist/FontSizePlugin.native-DkLMLPue.mjs.map +1 -0
- package/dist/FootnotePlugin.native-BciVc9W6.mjs +128 -0
- package/dist/FootnotePlugin.native-BciVc9W6.mjs.map +1 -0
- package/dist/FullscreenPlugin.native-ChXyxeNw.mjs +77 -0
- package/dist/FullscreenPlugin.native-ChXyxeNw.mjs.map +1 -0
- package/dist/HeadingPlugin.native-DrLYwQnQ.mjs +64 -0
- package/dist/HeadingPlugin.native-DrLYwQnQ.mjs.map +1 -0
- package/dist/HistoryPlugin.native-DoDRifCf.mjs +89 -0
- package/dist/HistoryPlugin.native-DoDRifCf.mjs.map +1 -0
- package/dist/IndentPlugin.native-CbFugPoi.mjs +133 -0
- package/dist/IndentPlugin.native-CbFugPoi.mjs.map +1 -0
- package/dist/ItalicPlugin.native-CQjjDyUL.mjs +43 -0
- package/dist/ItalicPlugin.native-CQjjDyUL.mjs.map +1 -0
- package/dist/LineHeightPlugin.native-CWQT2FIa.mjs +73 -0
- package/dist/LineHeightPlugin.native-CWQT2FIa.mjs.map +1 -0
- package/dist/LinkPlugin.native-BdAOV-iu.mjs +206 -0
- package/dist/LinkPlugin.native-BdAOV-iu.mjs.map +1 -0
- package/dist/ListPlugin.native-CLFU5AUQ.mjs +59 -0
- package/dist/ListPlugin.native-CLFU5AUQ.mjs.map +1 -0
- package/dist/MathPlugin.native-DE_ii-LA.mjs +182 -0
- package/dist/MathPlugin.native-DE_ii-LA.mjs.map +1 -0
- package/dist/MediaManagerPlugin.native-DaYFDzNM.mjs +533 -0
- package/dist/MediaManagerPlugin.native-DaYFDzNM.mjs.map +1 -0
- package/dist/MergeTagPlugin.native-CrxyThyn.mjs +178 -0
- package/dist/MergeTagPlugin.native-CrxyThyn.mjs.map +1 -0
- package/dist/PageBreakPlugin.native-DDjcDyRW.mjs +172 -0
- package/dist/PageBreakPlugin.native-DDjcDyRW.mjs.map +1 -0
- package/dist/PreviewPlugin.native-DBvfpmIv.mjs +322 -0
- package/dist/PreviewPlugin.native-DBvfpmIv.mjs.map +1 -0
- package/dist/PrintPlugin.native-BUpm52VJ.mjs +311 -0
- package/dist/PrintPlugin.native-BUpm52VJ.mjs.map +1 -0
- package/dist/SpecialCharactersPlugin.native-x7a2SWXc.mjs +731 -0
- package/dist/SpecialCharactersPlugin.native-x7a2SWXc.mjs.map +1 -0
- package/dist/SpellCheckPlugin.native-B7yTh0iE.mjs +465 -0
- package/dist/SpellCheckPlugin.native-B7yTh0iE.mjs.map +1 -0
- package/dist/StrikethroughPlugin.native-ChaZLaXw.mjs +43 -0
- package/dist/StrikethroughPlugin.native-ChaZLaXw.mjs.map +1 -0
- package/dist/TablePlugin.native-EEWXn1-s.mjs +491 -0
- package/dist/TablePlugin.native-EEWXn1-s.mjs.map +1 -0
- package/dist/TemplatePlugin.native-BlSn1c9h.mjs +564 -0
- package/dist/TemplatePlugin.native-BlSn1c9h.mjs.map +1 -0
- package/dist/TextAlignmentPlugin.native-CQIs1m7R.mjs +97 -0
- package/dist/TextAlignmentPlugin.native-CQIs1m7R.mjs.map +1 -0
- package/dist/TextColorPlugin.native-D6SmTglm.mjs +432 -0
- package/dist/TextColorPlugin.native-D6SmTglm.mjs.map +1 -0
- package/dist/UnderlinePlugin.native-QpIcK4L2.mjs +35 -0
- package/dist/UnderlinePlugin.native-QpIcK4L2.mjs.map +1 -0
- package/dist/documentManager-irzj9n3V.mjs +37627 -0
- package/dist/documentManager-irzj9n3V.mjs.map +1 -0
- package/dist/editorContainerHelpers-C7kdWnS0.mjs +27 -0
- package/dist/editorContainerHelpers-C7kdWnS0.mjs.map +1 -0
- package/dist/editora.min.js +14 -12
- package/dist/editora.min.js.map +1 -1
- package/dist/editora.umd.js +14 -12
- package/dist/editora.umd.js.map +1 -1
- package/dist/index-BF5RBhL9.js +4 -0
- package/dist/index-BF5RBhL9.js.map +1 -0
- package/dist/{index-BS4zT-KN.mjs → index-BPsf460l.mjs} +286 -162
- package/dist/index-BPsf460l.mjs.map +1 -0
- package/dist/index.cjs.js +3 -3
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es-CuicffkQ.mjs +6665 -0
- package/dist/index.es-CuicffkQ.mjs.map +1 -0
- package/dist/index.esm.js +117 -112
- package/dist/index.esm.js.map +1 -1
- package/dist/plugin-loader.js +55 -0
- package/dist/plugin-loader.js.map +1 -0
- package/dist/purify.es-CKpwg8Tk.mjs +471 -0
- package/dist/purify.es-CKpwg8Tk.mjs.map +1 -0
- package/dist/webcomponent-core.js +1243 -0
- package/dist/webcomponent-core.js.map +1 -0
- package/dist/webcomponent-core.min.css +1 -0
- package/dist/webcomponent-core.min.js +597 -0
- package/dist/webcomponent-core.min.js.map +1 -0
- package/dist/webcomponent.cjs.js +1 -1
- package/dist/webcomponent.esm.js +3 -3
- package/dist/webcomponent.js +1286 -0
- package/dist/webcomponent.js.map +1 -0
- package/dist/webcomponent.min.css +1 -0
- package/dist/webcomponent.min.js +337 -334
- package/dist/webcomponent.min.js.map +1 -1
- package/package.json +16 -4
- package/dist/index-BK2lHfHK.js +0 -2
- package/dist/index-BK2lHfHK.js.map +0 -1
- package/dist/index-BS4zT-KN.mjs.map +0 -1
- package/dist/webcomponent.umd.js +0 -4073
- package/dist/webcomponent.umd.js.map +0 -1
|
@@ -0,0 +1,564 @@
|
|
|
1
|
+
import S from "./purify.es-CKpwg8Tk.mjs";
|
|
2
|
+
let n = null, s = null, d = null, o = null, m = "", g = "", b = "insert";
|
|
3
|
+
const M = [
|
|
4
|
+
{
|
|
5
|
+
id: "formal-letter",
|
|
6
|
+
name: "Formal Letter",
|
|
7
|
+
category: "Letters",
|
|
8
|
+
description: "Professional business letter template",
|
|
9
|
+
html: `<p><strong>{{ Company Name }}</strong></p>
|
|
10
|
+
<p>{{ Today }}</p>
|
|
11
|
+
<p>Dear {{ first_name }} {{ last_name }},</p>
|
|
12
|
+
<p>I hope this letter finds you well. [Your letter content here]</p>
|
|
13
|
+
<p>Thank you for your time and consideration.</p>
|
|
14
|
+
<p>Sincerely,<br>Your Name</p>`
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
id: "meeting-notes",
|
|
18
|
+
name: "Meeting Notes",
|
|
19
|
+
category: "Notes",
|
|
20
|
+
description: "Template for meeting notes with attendees and action items",
|
|
21
|
+
html: `<h2>Meeting Notes - {{ today }}</h2>
|
|
22
|
+
<p><strong>Attendees:</strong> [List attendees]</p>
|
|
23
|
+
<p><strong>Agenda:</strong></p>
|
|
24
|
+
<ul>
|
|
25
|
+
<li>[Item 1]</li>
|
|
26
|
+
<li>[Item 2]</li>
|
|
27
|
+
<li>[Item 3]</li>
|
|
28
|
+
</ul>
|
|
29
|
+
<p><strong>Action Items:</strong></p>
|
|
30
|
+
<ul>
|
|
31
|
+
<li>[Owner]: [Task] - [Due Date]</li>
|
|
32
|
+
</ul>
|
|
33
|
+
<p><strong>Next Meeting:</strong> [Date]</p>`
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
id: "proposal",
|
|
37
|
+
name: "Project Proposal",
|
|
38
|
+
category: "Business",
|
|
39
|
+
description: "Structured project proposal template",
|
|
40
|
+
html: `<h1>Project Proposal</h1>
|
|
41
|
+
<h2>Executive Summary</h2>
|
|
42
|
+
<p>[Summary of the proposal]</p>
|
|
43
|
+
<h2>Objectives</h2>
|
|
44
|
+
<ul>
|
|
45
|
+
<li>[Objective 1]</li>
|
|
46
|
+
<li>[Objective 2]</li>
|
|
47
|
+
</ul>
|
|
48
|
+
<h2>Scope</h2>
|
|
49
|
+
<p>[Project scope details]</p>
|
|
50
|
+
<h2>Timeline</h2>
|
|
51
|
+
<p>[Project timeline]</p>
|
|
52
|
+
<h2>Budget</h2>
|
|
53
|
+
<p>[Budget details]</p>
|
|
54
|
+
<h2>Contact</h2>
|
|
55
|
+
<p>{{ first_name }} {{ last_name }}<br>{{ email }}<br>{{ phone }}</p>`
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
id: "faq",
|
|
59
|
+
name: "FAQ Template",
|
|
60
|
+
category: "Documentation",
|
|
61
|
+
description: "FAQ document structure",
|
|
62
|
+
html: `<h1>Frequently Asked Questions</h1>
|
|
63
|
+
<h2>General Questions</h2>
|
|
64
|
+
<h3>Q: What is this about?</h3>
|
|
65
|
+
<p>A: [Answer here]</p>
|
|
66
|
+
<h3>Q: Who should use this?</h3>
|
|
67
|
+
<p>A: [Answer here]</p>
|
|
68
|
+
<h2>Technical Questions</h2>
|
|
69
|
+
<h3>Q: How do I get started?</h3>
|
|
70
|
+
<p>A: [Answer here]</p>
|
|
71
|
+
<h3>Q: What are the requirements?</h3>
|
|
72
|
+
<p>A: [Answer here]</p>`
|
|
73
|
+
}
|
|
74
|
+
];
|
|
75
|
+
let h = [...M];
|
|
76
|
+
const w = () => h, P = (e) => h.filter((t) => t.category === e), L = () => {
|
|
77
|
+
const e = new Set(h.map((t) => t.category));
|
|
78
|
+
return Array.from(e);
|
|
79
|
+
}, R = (e) => {
|
|
80
|
+
const t = e.toLowerCase();
|
|
81
|
+
return h.filter(
|
|
82
|
+
(r) => {
|
|
83
|
+
var i, c;
|
|
84
|
+
return r.name.toLowerCase().includes(t) || ((i = r.description) == null ? void 0 : i.toLowerCase().includes(t)) || ((c = r.tags) == null ? void 0 : c.some((u) => u.toLowerCase().includes(t)));
|
|
85
|
+
}
|
|
86
|
+
);
|
|
87
|
+
}, A = (e) => S.sanitize(e, {
|
|
88
|
+
ALLOWED_TAGS: ["p", "br", "strong", "em", "u", "h1", "h2", "h3", "h4", "ul", "ol", "li", "blockquote", "table", "thead", "tbody", "tr", "th", "td", "a", "span"],
|
|
89
|
+
ALLOWED_ATTR: ["href", "target", "class", "data-key", "data-category"]
|
|
90
|
+
}), _ = (e) => h.some((t) => t.id === e.id) ? (console.warn(`Template with ID ${e.id} already exists`), !1) : (h.push(e), !0), j = (e) => !!(e.id && e.name && e.category && e.html && e.html.trim().length > 0);
|
|
91
|
+
function D() {
|
|
92
|
+
s = document.createElement("div"), s.className = "rte-dialog-overlay", s.addEventListener("click", () => p()), n = document.createElement("div"), n.className = "rte-dialog rte-template-dialog", n.addEventListener("click", (t) => t.stopPropagation());
|
|
93
|
+
const e = L();
|
|
94
|
+
e.length > 0 && !m && (m = e[0]), y(), s.appendChild(n), document.body.appendChild(s);
|
|
95
|
+
}
|
|
96
|
+
function y() {
|
|
97
|
+
if (!n) return;
|
|
98
|
+
const e = L(), t = T();
|
|
99
|
+
n.innerHTML = `
|
|
100
|
+
<div class="rte-dialog-header">
|
|
101
|
+
<h2>Insert Template</h2>
|
|
102
|
+
<button class="rte-dialog-close" aria-label="Close">✕</button>
|
|
103
|
+
</div>
|
|
104
|
+
|
|
105
|
+
<div class="rte-dialog-body">
|
|
106
|
+
<!-- Search -->
|
|
107
|
+
<input
|
|
108
|
+
type="text"
|
|
109
|
+
placeholder="Search templates..."
|
|
110
|
+
value="${g}"
|
|
111
|
+
class="rte-input rte-template-search"
|
|
112
|
+
aria-label="Search templates"
|
|
113
|
+
/>
|
|
114
|
+
|
|
115
|
+
<!-- Category Tabs -->
|
|
116
|
+
<div class="rte-tabs">
|
|
117
|
+
${e.map((r) => `
|
|
118
|
+
<button class="rte-tab ${m === r ? "active" : ""}" data-category="${r}">
|
|
119
|
+
${r}
|
|
120
|
+
</button>
|
|
121
|
+
`).join("")}
|
|
122
|
+
</div>
|
|
123
|
+
|
|
124
|
+
<!-- Template List -->
|
|
125
|
+
<div class="rte-template-list">
|
|
126
|
+
${t.length > 0 ? t.map((r) => `
|
|
127
|
+
<div
|
|
128
|
+
class="rte-template-item ${(o == null ? void 0 : o.id) === r.id ? "selected" : ""}"
|
|
129
|
+
data-template-id="${r.id}"
|
|
130
|
+
>
|
|
131
|
+
<div class="template-name">${r.name}</div>
|
|
132
|
+
${r.description ? `<div class="template-description">${r.description}</div>` : ""}
|
|
133
|
+
</div>
|
|
134
|
+
`).join("") : '<div class="rte-empty-state">No templates found</div>'}
|
|
135
|
+
</div>
|
|
136
|
+
|
|
137
|
+
<!-- Preview -->
|
|
138
|
+
${o ? `
|
|
139
|
+
<div class="rte-template-preview">
|
|
140
|
+
<strong>Preview:</strong>
|
|
141
|
+
<div class="template-preview-content">${o.html}</div>
|
|
142
|
+
</div>
|
|
143
|
+
` : ""}
|
|
144
|
+
|
|
145
|
+
<!-- Insert Mode Toggle -->
|
|
146
|
+
<div class="rte-insert-mode">
|
|
147
|
+
<label>
|
|
148
|
+
<input type="radio" name="insertMode" value="insert" ${b === "insert" ? "checked" : ""} />
|
|
149
|
+
Insert at cursor
|
|
150
|
+
</label>
|
|
151
|
+
<label>
|
|
152
|
+
<input type="radio" name="insertMode" value="replace" ${b === "replace" ? "checked" : ""} />
|
|
153
|
+
Replace document
|
|
154
|
+
</label>
|
|
155
|
+
</div>
|
|
156
|
+
</div>
|
|
157
|
+
|
|
158
|
+
<div class="rte-dialog-footer">
|
|
159
|
+
<button class="rte-button-secondary rte-cancel-btn">Cancel</button>
|
|
160
|
+
<button class="rte-button-primary rte-insert-btn" ${o ? "" : "disabled"}>
|
|
161
|
+
${b === "insert" ? "Insert" : "Replace"}
|
|
162
|
+
</button>
|
|
163
|
+
</div>
|
|
164
|
+
`, H();
|
|
165
|
+
}
|
|
166
|
+
function $() {
|
|
167
|
+
if (!n) return;
|
|
168
|
+
n.innerHTML = `
|
|
169
|
+
<div class="rte-dialog-header">
|
|
170
|
+
<h2>Replace Document?</h2>
|
|
171
|
+
</div>
|
|
172
|
+
<div class="rte-dialog-body">
|
|
173
|
+
<p>This will replace your current document content. Continue?</p>
|
|
174
|
+
</div>
|
|
175
|
+
<div class="rte-dialog-footer">
|
|
176
|
+
<button class="rte-button-secondary rte-cancel-warning-btn">Cancel</button>
|
|
177
|
+
<button class="rte-button-primary rte-confirm-replace-btn">Replace</button>
|
|
178
|
+
</div>
|
|
179
|
+
`;
|
|
180
|
+
const e = n.querySelector(".rte-cancel-warning-btn"), t = n.querySelector(".rte-confirm-replace-btn");
|
|
181
|
+
e == null || e.addEventListener("click", () => y()), t == null || t.addEventListener("click", () => N());
|
|
182
|
+
}
|
|
183
|
+
function T() {
|
|
184
|
+
const e = w();
|
|
185
|
+
return g.trim() ? R(g) : m ? e.filter((t) => t.category === m) : e;
|
|
186
|
+
}
|
|
187
|
+
function H() {
|
|
188
|
+
if (!n) return;
|
|
189
|
+
const e = n.querySelector(".rte-dialog-close");
|
|
190
|
+
e == null || e.addEventListener("click", () => p());
|
|
191
|
+
const t = n.querySelector(".rte-cancel-btn");
|
|
192
|
+
t == null || t.addEventListener("click", () => p());
|
|
193
|
+
const r = n.querySelector(".rte-insert-btn");
|
|
194
|
+
r == null || r.addEventListener("click", () => v());
|
|
195
|
+
const i = n.querySelector(".rte-template-search");
|
|
196
|
+
i == null || i.addEventListener("input", (a) => {
|
|
197
|
+
g = a.target.value, E();
|
|
198
|
+
}), i == null || i.addEventListener("keydown", (a) => {
|
|
199
|
+
a.key === "Enter" && o ? v() : a.key === "Escape" && p();
|
|
200
|
+
}), n.querySelectorAll(".rte-tab").forEach((a) => {
|
|
201
|
+
a.addEventListener("click", () => {
|
|
202
|
+
const l = a.getAttribute("data-category");
|
|
203
|
+
l && (m = l, g = "", E());
|
|
204
|
+
});
|
|
205
|
+
}), n.querySelectorAll(".rte-template-item").forEach((a) => {
|
|
206
|
+
a.addEventListener("click", () => {
|
|
207
|
+
const l = a.getAttribute("data-template-id");
|
|
208
|
+
if (l) {
|
|
209
|
+
const f = w().find((x) => x.id === l);
|
|
210
|
+
f && (o = f, y());
|
|
211
|
+
}
|
|
212
|
+
}), a.addEventListener("dblclick", () => {
|
|
213
|
+
const l = a.getAttribute("data-template-id");
|
|
214
|
+
if (l) {
|
|
215
|
+
const f = w().find((x) => x.id === l);
|
|
216
|
+
f && (o = f, v());
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
}), n.querySelectorAll('input[name="insertMode"]').forEach((a) => {
|
|
220
|
+
a.addEventListener("change", (l) => {
|
|
221
|
+
b = l.target.value, y();
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
function E() {
|
|
226
|
+
const e = T();
|
|
227
|
+
e.length > 0 ? (!o || !e.find((t) => t.id === o.id)) && (o = e[0]) : o = null, y();
|
|
228
|
+
}
|
|
229
|
+
function v() {
|
|
230
|
+
var e;
|
|
231
|
+
if (o)
|
|
232
|
+
if (b === "replace") {
|
|
233
|
+
let t = null;
|
|
234
|
+
if (d) {
|
|
235
|
+
let r = d.startContainer;
|
|
236
|
+
for (; r && r !== document.body; ) {
|
|
237
|
+
if (r.nodeType === Node.ELEMENT_NODE) {
|
|
238
|
+
const i = r;
|
|
239
|
+
if (i.getAttribute("contenteditable") === "true") {
|
|
240
|
+
t = i;
|
|
241
|
+
break;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
r = r.parentNode;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
if (t || (t = document.querySelector('[contenteditable="true"]')), (e = t == null ? void 0 : t.innerHTML) != null && e.trim()) {
|
|
248
|
+
$();
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
C(o), p();
|
|
252
|
+
} else
|
|
253
|
+
I(o), p();
|
|
254
|
+
}
|
|
255
|
+
function N() {
|
|
256
|
+
o && (C(o), p());
|
|
257
|
+
}
|
|
258
|
+
function I(e) {
|
|
259
|
+
if (d) {
|
|
260
|
+
const u = window.getSelection();
|
|
261
|
+
u && (u.removeAllRanges(), u.addRange(d));
|
|
262
|
+
}
|
|
263
|
+
const t = window.getSelection();
|
|
264
|
+
if (!t || t.rangeCount === 0) return;
|
|
265
|
+
const r = t.getRangeAt(0), i = document.createRange().createContextualFragment(A(e.html));
|
|
266
|
+
r.deleteContents(), r.insertNode(i);
|
|
267
|
+
const c = document.createRange();
|
|
268
|
+
c.setStartAfter(r.endContainer), c.collapse(!0), t.removeAllRanges(), t.addRange(c), console.log(`Template inserted: ${e.name}`);
|
|
269
|
+
}
|
|
270
|
+
function C(e) {
|
|
271
|
+
let t = null;
|
|
272
|
+
if (d) {
|
|
273
|
+
let r = d.startContainer;
|
|
274
|
+
for (; r && r !== document.body; ) {
|
|
275
|
+
if (r.nodeType === Node.ELEMENT_NODE) {
|
|
276
|
+
const i = r;
|
|
277
|
+
if (i.getAttribute("contenteditable") === "true") {
|
|
278
|
+
t = i;
|
|
279
|
+
break;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
r = r.parentNode;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
t || (t = document.querySelector('[contenteditable="true"]')), t && (t.innerHTML = A(e.html), t.dispatchEvent(new Event("input", { bubbles: !0 }))), console.log(`Document replaced with template: ${e.name}`);
|
|
286
|
+
}
|
|
287
|
+
function p() {
|
|
288
|
+
s && (s.remove(), s = null), n = null, d = null, g = "";
|
|
289
|
+
}
|
|
290
|
+
function V() {
|
|
291
|
+
const e = window.getSelection();
|
|
292
|
+
e && e.rangeCount > 0 ? d = e.getRangeAt(0).cloneRange() : d = null;
|
|
293
|
+
const t = T();
|
|
294
|
+
t.length > 0 && !o && (o = t[0]), D();
|
|
295
|
+
}
|
|
296
|
+
function k() {
|
|
297
|
+
if (!window.__templatePluginInitialized && (window.__templatePluginInitialized = !0, !document.getElementById("template-plugin-styles"))) {
|
|
298
|
+
const e = document.createElement("style");
|
|
299
|
+
e.id = "template-plugin-styles", e.textContent = `
|
|
300
|
+
.rte-dialog-overlay {
|
|
301
|
+
position: fixed;
|
|
302
|
+
top: 0;
|
|
303
|
+
left: 0;
|
|
304
|
+
right: 0;
|
|
305
|
+
bottom: 0;
|
|
306
|
+
background-color: rgba(0, 0, 0, 0.5);
|
|
307
|
+
display: flex;
|
|
308
|
+
align-items: center;
|
|
309
|
+
justify-content: center;
|
|
310
|
+
z-index: 10000;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
.rte-dialog {
|
|
314
|
+
background: white;
|
|
315
|
+
border-radius: 8px;
|
|
316
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
|
317
|
+
max-width: 90vw;
|
|
318
|
+
max-height: 90vh;
|
|
319
|
+
overflow: hidden;
|
|
320
|
+
display: flex;
|
|
321
|
+
flex-direction: column;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
.rte-dialog-header {
|
|
325
|
+
padding: 16px;
|
|
326
|
+
border-bottom: 1px solid #eee;
|
|
327
|
+
display: flex;
|
|
328
|
+
justify-content: space-between;
|
|
329
|
+
align-items: center;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
.rte-dialog-header h2 {
|
|
333
|
+
margin: 0;
|
|
334
|
+
font-size: 18px;
|
|
335
|
+
font-weight: 600;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
.rte-dialog-close {
|
|
339
|
+
background: none;
|
|
340
|
+
border: none;
|
|
341
|
+
font-size: 24px;
|
|
342
|
+
cursor: pointer;
|
|
343
|
+
color: #999;
|
|
344
|
+
padding: 0;
|
|
345
|
+
width: 32px;
|
|
346
|
+
height: 32px;
|
|
347
|
+
display: flex;
|
|
348
|
+
align-items: center;
|
|
349
|
+
justify-content: center;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
.rte-dialog-close:hover {
|
|
353
|
+
color: #333;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
.rte-dialog-body {
|
|
357
|
+
padding: 16px;
|
|
358
|
+
overflow-y: auto;
|
|
359
|
+
flex: 1;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
.rte-dialog-footer {
|
|
363
|
+
padding: 12px 16px;
|
|
364
|
+
border-top: 1px solid #eee;
|
|
365
|
+
display: flex;
|
|
366
|
+
gap: 8px;
|
|
367
|
+
justify-content: flex-end;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
.rte-button-primary {
|
|
371
|
+
padding: 8px 16px;
|
|
372
|
+
border: none;
|
|
373
|
+
border-radius: 4px;
|
|
374
|
+
font-size: 14px;
|
|
375
|
+
cursor: pointer;
|
|
376
|
+
background-color: #1976d2;
|
|
377
|
+
color: white;
|
|
378
|
+
transition: all 0.2s;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
.rte-button-primary:hover:not([disabled]) {
|
|
382
|
+
background-color: #1565c0;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
.rte-button-primary[disabled] {
|
|
386
|
+
opacity: 0.5;
|
|
387
|
+
cursor: not-allowed;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
.rte-button-secondary {
|
|
391
|
+
padding: 8px 16px;
|
|
392
|
+
border: 1px solid #ddd;
|
|
393
|
+
border-radius: 4px;
|
|
394
|
+
font-size: 14px;
|
|
395
|
+
cursor: pointer;
|
|
396
|
+
background-color: #f5f5f5;
|
|
397
|
+
color: #333;
|
|
398
|
+
transition: all 0.2s;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
.rte-button-secondary:hover {
|
|
402
|
+
background-color: #eeeeee;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
.rte-template-dialog {
|
|
406
|
+
width: 600px;
|
|
407
|
+
max-height: 700px;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
.rte-input {
|
|
411
|
+
width: 100%;
|
|
412
|
+
padding: 8px 12px;
|
|
413
|
+
border: 1px solid #ddd;
|
|
414
|
+
border-radius: 4px;
|
|
415
|
+
font-size: 14px;
|
|
416
|
+
box-sizing: border-box;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
.rte-input:focus {
|
|
420
|
+
outline: none;
|
|
421
|
+
border-color: #1976d2;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
.rte-tabs {
|
|
425
|
+
display: flex;
|
|
426
|
+
gap: 8px;
|
|
427
|
+
margin-top: 12px;
|
|
428
|
+
border-bottom: 1px solid #eee;
|
|
429
|
+
padding-bottom: 8px;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
.rte-tab {
|
|
433
|
+
padding: 6px 12px;
|
|
434
|
+
border: none;
|
|
435
|
+
background: none;
|
|
436
|
+
cursor: pointer;
|
|
437
|
+
font-size: 14px;
|
|
438
|
+
color: #666;
|
|
439
|
+
border-bottom: 2px solid transparent;
|
|
440
|
+
transition: all 0.2s;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
.rte-tab:hover {
|
|
444
|
+
color: #333;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
.rte-tab.active {
|
|
448
|
+
color: #1976d2;
|
|
449
|
+
border-bottom-color: #1976d2;
|
|
450
|
+
font-weight: 600;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
.rte-template-list {
|
|
454
|
+
border: 1px solid #ddd;
|
|
455
|
+
border-radius: 4px;
|
|
456
|
+
max-height: 250px;
|
|
457
|
+
overflow-y: auto;
|
|
458
|
+
margin: 12px 0;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
.rte-template-item {
|
|
462
|
+
padding: 12px;
|
|
463
|
+
border-bottom: 1px solid #f0f0f0;
|
|
464
|
+
cursor: pointer;
|
|
465
|
+
transition: background-color 0.2s;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
.rte-template-item:last-child {
|
|
469
|
+
border-bottom: none;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
.rte-template-item:hover,
|
|
473
|
+
.rte-template-item.selected {
|
|
474
|
+
background-color: #f5f5f5;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
.template-name {
|
|
478
|
+
font-weight: 600;
|
|
479
|
+
color: #333;
|
|
480
|
+
margin-bottom: 4px;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
.template-description {
|
|
484
|
+
font-size: 12px;
|
|
485
|
+
color: #999;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
.rte-template-preview {
|
|
489
|
+
padding: 12px;
|
|
490
|
+
background-color: #fafafa;
|
|
491
|
+
border: 1px solid #eee;
|
|
492
|
+
border-radius: 4px;
|
|
493
|
+
margin-top: 12px;
|
|
494
|
+
max-height: 200px;
|
|
495
|
+
overflow-y: auto;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
.template-preview-content {
|
|
499
|
+
font-size: 13px;
|
|
500
|
+
line-height: 1.5;
|
|
501
|
+
margin-top: 8px;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
.template-preview-content * {
|
|
505
|
+
margin: 4px 0;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
.rte-insert-mode {
|
|
509
|
+
margin-top: 12px;
|
|
510
|
+
padding: 12px;
|
|
511
|
+
background-color: #f5f5f5;
|
|
512
|
+
border-radius: 4px;
|
|
513
|
+
display: flex;
|
|
514
|
+
gap: 16px;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
.rte-insert-mode label {
|
|
518
|
+
display: flex;
|
|
519
|
+
align-items: center;
|
|
520
|
+
cursor: pointer;
|
|
521
|
+
font-size: 14px;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
.rte-insert-mode input {
|
|
525
|
+
margin-right: 6px;
|
|
526
|
+
cursor: pointer;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
.rte-empty-state {
|
|
530
|
+
padding: 40px;
|
|
531
|
+
text-align: center;
|
|
532
|
+
color: #999;
|
|
533
|
+
font-size: 14px;
|
|
534
|
+
}
|
|
535
|
+
`, document.head.appendChild(e);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
document.readyState === "loading" ? document.addEventListener("DOMContentLoaded", k) : setTimeout(k, 100);
|
|
539
|
+
const O = () => ({
|
|
540
|
+
name: "template",
|
|
541
|
+
toolbar: [
|
|
542
|
+
{
|
|
543
|
+
label: "Template",
|
|
544
|
+
command: "insertTemplate",
|
|
545
|
+
icon: '<svg width="24px" height="24px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <path fill-rule="evenodd" clip-rule="evenodd" d="M3 3V9H21V3H3ZM19 5H5V7H19V5Z" fill="#000000"></path> <path fill-rule="evenodd" clip-rule="evenodd" d="M3 11V21H11V11H3ZM9 13H5V19H9V13Z" fill="#000000"></path> <path d="M21 11H13V13H21V11Z" fill="#000000"></path> <path d="M13 15H21V17H13V15Z" fill="#000000"></path> <path d="M21 19H13V21H21V19Z" fill="#000000"></path> </g></svg>'
|
|
546
|
+
}
|
|
547
|
+
],
|
|
548
|
+
commands: {
|
|
549
|
+
insertTemplate: () => (V(), !0)
|
|
550
|
+
},
|
|
551
|
+
keymap: {}
|
|
552
|
+
});
|
|
553
|
+
export {
|
|
554
|
+
M as PREDEFINED_TEMPLATES,
|
|
555
|
+
O as TemplatePlugin,
|
|
556
|
+
_ as addCustomTemplate,
|
|
557
|
+
w as getAllTemplates,
|
|
558
|
+
L as getTemplateCategories,
|
|
559
|
+
P as getTemplatesByCategory,
|
|
560
|
+
A as sanitizeTemplate,
|
|
561
|
+
R as searchTemplates,
|
|
562
|
+
j as validateTemplate
|
|
563
|
+
};
|
|
564
|
+
//# sourceMappingURL=TemplatePlugin.native-BlSn1c9h.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TemplatePlugin.native-BlSn1c9h.mjs","sources":["../../plugins/template/src/TemplatePlugin.native.ts"],"sourcesContent":["import { Plugin } from '@editora/core';\nimport DOMPurify from 'dompurify';\n\n/**\n * Template Plugin - Native Implementation\n *\n * Allows insertion of predefined document templates with:\n * - Template categories and search\n * - Preview functionality\n * - Replace or insert options\n * - HTML sanitization\n * - Undo/redo support\n * - Merge tag integration\n *\n * Rules:\n * - Templates are sanitized on insertion\n * - Scripts are always stripped\n * - CSS may be filtered for security\n * - Existing content warning dialog\n * - Undo restores entire document\n */\n\n// ============================================================================\n// Module-Level State\n// ============================================================================\nlet dialogElement: HTMLDivElement | null = null;\nlet overlayElement: HTMLDivElement | null = null;\nlet savedRange: Range | null = null;\nlet selectedTemplate: Template | null = null;\nlet selectedCategory: string = '';\nlet searchTerm: string = '';\nlet insertMode: 'insert' | 'replace' = 'insert';\n\n// ============================================================================\n// Template Data Model\n// ============================================================================\nexport interface Template {\n id: string;\n name: string;\n category: string;\n html: string;\n description?: string;\n preview?: string;\n tags?: string[];\n}\n\n/**\n * Predefined templates\n */\nexport const PREDEFINED_TEMPLATES: Template[] = [\n {\n id: 'formal-letter',\n name: 'Formal Letter',\n category: 'Letters',\n description: 'Professional business letter template',\n html: `<p><strong>{{ Company Name }}</strong></p>\n<p>{{ Today }}</p>\n<p>Dear {{ first_name }} {{ last_name }},</p>\n<p>I hope this letter finds you well. [Your letter content here]</p>\n<p>Thank you for your time and consideration.</p>\n<p>Sincerely,<br>Your Name</p>`\n },\n {\n id: 'meeting-notes',\n name: 'Meeting Notes',\n category: 'Notes',\n description: 'Template for meeting notes with attendees and action items',\n html: `<h2>Meeting Notes - {{ today }}</h2>\n<p><strong>Attendees:</strong> [List attendees]</p>\n<p><strong>Agenda:</strong></p>\n<ul>\n <li>[Item 1]</li>\n <li>[Item 2]</li>\n <li>[Item 3]</li>\n</ul>\n<p><strong>Action Items:</strong></p>\n<ul>\n <li>[Owner]: [Task] - [Due Date]</li>\n</ul>\n<p><strong>Next Meeting:</strong> [Date]</p>`\n },\n {\n id: 'proposal',\n name: 'Project Proposal',\n category: 'Business',\n description: 'Structured project proposal template',\n html: `<h1>Project Proposal</h1>\n<h2>Executive Summary</h2>\n<p>[Summary of the proposal]</p>\n<h2>Objectives</h2>\n<ul>\n <li>[Objective 1]</li>\n <li>[Objective 2]</li>\n</ul>\n<h2>Scope</h2>\n<p>[Project scope details]</p>\n<h2>Timeline</h2>\n<p>[Project timeline]</p>\n<h2>Budget</h2>\n<p>[Budget details]</p>\n<h2>Contact</h2>\n<p>{{ first_name }} {{ last_name }}<br>{{ email }}<br>{{ phone }}</p>`\n },\n {\n id: 'faq',\n name: 'FAQ Template',\n category: 'Documentation',\n description: 'FAQ document structure',\n html: `<h1>Frequently Asked Questions</h1>\n<h2>General Questions</h2>\n<h3>Q: What is this about?</h3>\n<p>A: [Answer here]</p>\n<h3>Q: Who should use this?</h3>\n<p>A: [Answer here]</p>\n<h2>Technical Questions</h2>\n<h3>Q: How do I get started?</h3>\n<p>A: [Answer here]</p>\n<h3>Q: What are the requirements?</h3>\n<p>A: [Answer here]</p>`\n }\n];\n\n/**\n * Template cache\n */\nlet templateCache: Template[] = [...PREDEFINED_TEMPLATES];\n\n// ============================================================================\n// Template Functions\n// ============================================================================\n\n/**\n * Get all available templates\n */\nexport const getAllTemplates = (): Template[] => {\n return templateCache;\n};\n\n/**\n * Get templates by category\n */\nexport const getTemplatesByCategory = (category: string): Template[] => {\n return templateCache.filter(t => t.category === category);\n};\n\n/**\n * Get unique template categories\n */\nexport const getTemplateCategories = (): string[] => {\n const categories = new Set(templateCache.map(t => t.category));\n return Array.from(categories);\n};\n\n/**\n * Search templates\n */\nexport const searchTemplates = (query: string): Template[] => {\n const q = query.toLowerCase();\n return templateCache.filter(t =>\n t.name.toLowerCase().includes(q) ||\n t.description?.toLowerCase().includes(q) ||\n t.tags?.some(tag => tag.toLowerCase().includes(q))\n );\n};\n\n/**\n * Sanitize template HTML\n * Removes scripts and potentially dangerous content\n */\nexport const sanitizeTemplate = (html: string): string => {\n return DOMPurify.sanitize(html, {\n ALLOWED_TAGS: ['p', 'br', 'strong', 'em', 'u', 'h1', 'h2', 'h3', 'h4', 'ul', 'ol', 'li', 'blockquote', 'table', 'thead', 'tbody', 'tr', 'th', 'td', 'a', 'span'],\n ALLOWED_ATTR: ['href', 'target', 'class', 'data-key', 'data-category']\n });\n};\n\n/**\n * Add custom template\n */\nexport const addCustomTemplate = (template: Template): boolean => {\n // Check for duplicate ID\n if (templateCache.some(t => t.id === template.id)) {\n console.warn(`Template with ID ${template.id} already exists`);\n return false;\n }\n\n templateCache.push(template);\n return true;\n};\n\n/**\n * Validate template integrity\n */\nexport const validateTemplate = (template: Template): boolean => {\n return !!(\n template.id &&\n template.name &&\n template.category &&\n template.html &&\n template.html.trim().length > 0\n );\n};\n\n// ============================================================================\n// Dialog Functions\n// ============================================================================\n\n/**\n * Create the template dialog\n */\nfunction createTemplateDialog(): void {\n // Create overlay\n overlayElement = document.createElement('div');\n overlayElement.className = 'rte-dialog-overlay';\n overlayElement.addEventListener('click', () => closeDialog());\n\n // Create dialog\n dialogElement = document.createElement('div');\n dialogElement.className = 'rte-dialog rte-template-dialog';\n dialogElement.addEventListener('click', (e) => e.stopPropagation());\n\n // Initialize with first category\n const categories = getTemplateCategories();\n if (categories.length > 0 && !selectedCategory) {\n selectedCategory = categories[0];\n }\n\n renderDialogContent();\n\n overlayElement.appendChild(dialogElement);\n document.body.appendChild(overlayElement);\n}\n\n/**\n * Render dialog content (normal mode)\n */\nfunction renderDialogContent(): void {\n if (!dialogElement) return;\n\n const categories = getTemplateCategories();\n const filteredTemplates = getFilteredTemplates();\n\n dialogElement.innerHTML = `\n <div class=\"rte-dialog-header\">\n <h2>Insert Template</h2>\n <button class=\"rte-dialog-close\" aria-label=\"Close\">✕</button>\n </div>\n\n <div class=\"rte-dialog-body\">\n <!-- Search -->\n <input\n type=\"text\"\n placeholder=\"Search templates...\"\n value=\"${searchTerm}\"\n class=\"rte-input rte-template-search\"\n aria-label=\"Search templates\"\n />\n\n <!-- Category Tabs -->\n <div class=\"rte-tabs\">\n ${categories.map(cat => `\n <button class=\"rte-tab ${selectedCategory === cat ? 'active' : ''}\" data-category=\"${cat}\">\n ${cat}\n </button>\n `).join('')}\n </div>\n\n <!-- Template List -->\n <div class=\"rte-template-list\">\n ${filteredTemplates.length > 0 ? filteredTemplates.map(template => `\n <div\n class=\"rte-template-item ${selectedTemplate?.id === template.id ? 'selected' : ''}\"\n data-template-id=\"${template.id}\"\n >\n <div class=\"template-name\">${template.name}</div>\n ${template.description ? `<div class=\"template-description\">${template.description}</div>` : ''}\n </div>\n `).join('') : '<div class=\"rte-empty-state\">No templates found</div>'}\n </div>\n\n <!-- Preview -->\n ${selectedTemplate ? `\n <div class=\"rte-template-preview\">\n <strong>Preview:</strong>\n <div class=\"template-preview-content\">${selectedTemplate.html}</div>\n </div>\n ` : ''}\n\n <!-- Insert Mode Toggle -->\n <div class=\"rte-insert-mode\">\n <label>\n <input type=\"radio\" name=\"insertMode\" value=\"insert\" ${insertMode === 'insert' ? 'checked' : ''} />\n Insert at cursor\n </label>\n <label>\n <input type=\"radio\" name=\"insertMode\" value=\"replace\" ${insertMode === 'replace' ? 'checked' : ''} />\n Replace document\n </label>\n </div>\n </div>\n\n <div class=\"rte-dialog-footer\">\n <button class=\"rte-button-secondary rte-cancel-btn\">Cancel</button>\n <button class=\"rte-button-primary rte-insert-btn\" ${!selectedTemplate ? 'disabled' : ''}>\n ${insertMode === 'insert' ? 'Insert' : 'Replace'}\n </button>\n </div>\n `;\n\n attachDialogListeners();\n}\n\n/**\n * Render warning dialog for replacing content\n */\nfunction renderWarningDialog(): void {\n if (!dialogElement) return;\n\n dialogElement.innerHTML = `\n <div class=\"rte-dialog-header\">\n <h2>Replace Document?</h2>\n </div>\n <div class=\"rte-dialog-body\">\n <p>This will replace your current document content. Continue?</p>\n </div>\n <div class=\"rte-dialog-footer\">\n <button class=\"rte-button-secondary rte-cancel-warning-btn\">Cancel</button>\n <button class=\"rte-button-primary rte-confirm-replace-btn\">Replace</button>\n </div>\n `;\n\n // Attach warning listeners\n const cancelBtn = dialogElement.querySelector('.rte-cancel-warning-btn');\n const confirmBtn = dialogElement.querySelector('.rte-confirm-replace-btn');\n\n cancelBtn?.addEventListener('click', () => renderDialogContent());\n confirmBtn?.addEventListener('click', () => handleConfirmReplace());\n}\n\n/**\n * Get filtered templates based on search and category\n */\nfunction getFilteredTemplates(): Template[] {\n const allTemplates = getAllTemplates();\n\n if (searchTerm.trim()) {\n return searchTemplates(searchTerm);\n } else if (selectedCategory) {\n return allTemplates.filter(t => t.category === selectedCategory);\n }\n\n return allTemplates;\n}\n\n/**\n * Attach event listeners to dialog elements\n */\nfunction attachDialogListeners(): void {\n if (!dialogElement) return;\n\n // Close button\n const closeBtn = dialogElement.querySelector('.rte-dialog-close');\n closeBtn?.addEventListener('click', () => closeDialog());\n\n // Cancel button\n const cancelBtn = dialogElement.querySelector('.rte-cancel-btn');\n cancelBtn?.addEventListener('click', () => closeDialog());\n\n // Insert button\n const insertBtn = dialogElement.querySelector('.rte-insert-btn');\n insertBtn?.addEventListener('click', () => handleInsert());\n\n // Search input\n const searchInput = dialogElement.querySelector('.rte-template-search') as HTMLInputElement;\n searchInput?.addEventListener('input', (e) => {\n searchTerm = (e.target as HTMLInputElement).value;\n updateTemplateList();\n });\n searchInput?.addEventListener('keydown', (e) => {\n if (e.key === 'Enter' && selectedTemplate) {\n handleInsert();\n } else if (e.key === 'Escape') {\n closeDialog();\n }\n });\n\n // Category tabs\n const categoryTabs = dialogElement.querySelectorAll('.rte-tab');\n categoryTabs.forEach(tab => {\n tab.addEventListener('click', () => {\n const category = tab.getAttribute('data-category');\n if (category) {\n selectedCategory = category;\n searchTerm = ''; // Clear search when switching categories\n updateTemplateList();\n }\n });\n });\n\n // Template items\n const templateItems = dialogElement.querySelectorAll('.rte-template-item');\n templateItems.forEach(item => {\n item.addEventListener('click', () => {\n const templateId = item.getAttribute('data-template-id');\n if (templateId) {\n const template = getAllTemplates().find(t => t.id === templateId);\n if (template) {\n selectedTemplate = template;\n renderDialogContent();\n }\n }\n });\n\n // Double-click to insert\n item.addEventListener('dblclick', () => {\n const templateId = item.getAttribute('data-template-id');\n if (templateId) {\n const template = getAllTemplates().find(t => t.id === templateId);\n if (template) {\n selectedTemplate = template;\n handleInsert();\n }\n }\n });\n });\n\n // Insert mode radio buttons\n const insertModeRadios = dialogElement.querySelectorAll('input[name=\"insertMode\"]');\n insertModeRadios.forEach(radio => {\n radio.addEventListener('change', (e) => {\n insertMode = (e.target as HTMLInputElement).value as 'insert' | 'replace';\n renderDialogContent();\n });\n });\n}\n\n/**\n * Update template list after search or category change\n */\nfunction updateTemplateList(): void {\n const filteredTemplates = getFilteredTemplates();\n\n // Update selected template if it's not in filtered list\n if (filteredTemplates.length > 0) {\n if (!selectedTemplate || !filteredTemplates.find(t => t.id === selectedTemplate!.id)) {\n selectedTemplate = filteredTemplates[0];\n }\n } else {\n selectedTemplate = null;\n }\n\n renderDialogContent();\n}\n\n/**\n * Handle insert button click\n */\nfunction handleInsert(): void {\n if (!selectedTemplate) return;\n\n if (insertMode === 'replace') {\n // Find the correct editor based on saved range\n let editor: Element | null = null;\n \n if (savedRange) {\n let node: Node | null = savedRange.startContainer;\n while (node && node !== document.body) {\n if (node.nodeType === Node.ELEMENT_NODE) {\n const element = node as Element;\n if (element.getAttribute('contenteditable') === 'true') {\n editor = element;\n break;\n }\n }\n node = node.parentNode;\n }\n }\n \n // Fallback to first editor\n if (!editor) {\n editor = document.querySelector('[contenteditable=\"true\"]');\n }\n \n if (editor?.innerHTML?.trim()) {\n // Show warning dialog\n renderWarningDialog();\n return;\n }\n replaceDocumentWithTemplate(selectedTemplate);\n closeDialog();\n } else {\n insertTemplateAtCursor(selectedTemplate);\n closeDialog();\n }\n}\n\n/**\n * Handle confirm replace in warning dialog\n */\nfunction handleConfirmReplace(): void {\n if (selectedTemplate) {\n replaceDocumentWithTemplate(selectedTemplate);\n closeDialog();\n }\n}\n\n/**\n * Insert template at cursor position\n */\nfunction insertTemplateAtCursor(template: Template): void {\n // Restore saved selection\n if (savedRange) {\n const selection = window.getSelection();\n if (selection) {\n selection.removeAllRanges();\n selection.addRange(savedRange);\n }\n }\n\n const selection = window.getSelection();\n if (!selection || selection.rangeCount === 0) return;\n\n const range = selection.getRangeAt(0);\n const fragment = document.createRange().createContextualFragment(sanitizeTemplate(template.html));\n\n range.deleteContents();\n range.insertNode(fragment);\n\n // Move cursor after inserted template\n const newRange = document.createRange();\n newRange.setStartAfter(range.endContainer);\n newRange.collapse(true);\n selection.removeAllRanges();\n selection.addRange(newRange);\n\n console.log(`Template inserted: ${template.name}`);\n}\n\n/**\n * Replace entire document with template\n */\nfunction replaceDocumentWithTemplate(template: Template): void {\n // Find the correct editor based on saved range\n let editor: Element | null = null;\n \n if (savedRange) {\n // Find editor containing the saved range\n let node: Node | null = savedRange.startContainer;\n while (node && node !== document.body) {\n if (node.nodeType === Node.ELEMENT_NODE) {\n const element = node as Element;\n if (element.getAttribute('contenteditable') === 'true') {\n editor = element;\n break;\n }\n }\n node = node.parentNode;\n }\n }\n \n // Fallback to first editor if we couldn't find the specific one\n if (!editor) {\n editor = document.querySelector('[contenteditable=\"true\"]');\n }\n \n if (editor) {\n editor.innerHTML = sanitizeTemplate(template.html);\n \n // Trigger input event to notify editor of change\n editor.dispatchEvent(new Event('input', { bubbles: true }));\n }\n\n console.log(`Document replaced with template: ${template.name}`);\n}\n\n/**\n * Close dialog\n */\nfunction closeDialog(): void {\n if (overlayElement) {\n overlayElement.remove();\n overlayElement = null;\n }\n dialogElement = null;\n savedRange = null;\n searchTerm = '';\n}\n\n/**\n * Open template dialog\n */\nfunction openTemplateDialog(): void {\n // Save current selection\n const selection = window.getSelection();\n if (selection && selection.rangeCount > 0) {\n savedRange = selection.getRangeAt(0).cloneRange();\n } else {\n savedRange = null;\n }\n\n // Initialize selected template\n const filteredTemplates = getFilteredTemplates();\n if (filteredTemplates.length > 0 && !selectedTemplate) {\n selectedTemplate = filteredTemplates[0];\n }\n\n createTemplateDialog();\n}\n\n// ============================================================================\n// Plugin Initialization\n// ============================================================================\n\n/**\n * Initialize plugin (called once when editor loads)\n */\nfunction initTemplatePlugin(): void {\n if ((window as any).__templatePluginInitialized) {\n return;\n }\n\n (window as any).__templatePluginInitialized = true;\n\n // Add CSS styles\n if (!document.getElementById('template-plugin-styles')) {\n const styleElement = document.createElement('style');\n styleElement.id = 'template-plugin-styles';\n styleElement.textContent = `\n .rte-dialog-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10000;\n }\n\n .rte-dialog {\n background: white;\n border-radius: 8px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);\n max-width: 90vw;\n max-height: 90vh;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n }\n\n .rte-dialog-header {\n padding: 16px;\n border-bottom: 1px solid #eee;\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n\n .rte-dialog-header h2 {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n }\n\n .rte-dialog-close {\n background: none;\n border: none;\n font-size: 24px;\n cursor: pointer;\n color: #999;\n padding: 0;\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .rte-dialog-close:hover {\n color: #333;\n }\n\n .rte-dialog-body {\n padding: 16px;\n overflow-y: auto;\n flex: 1;\n }\n\n .rte-dialog-footer {\n padding: 12px 16px;\n border-top: 1px solid #eee;\n display: flex;\n gap: 8px;\n justify-content: flex-end;\n }\n\n .rte-button-primary {\n padding: 8px 16px;\n border: none;\n border-radius: 4px;\n font-size: 14px;\n cursor: pointer;\n background-color: #1976d2;\n color: white;\n transition: all 0.2s;\n }\n\n .rte-button-primary:hover:not([disabled]) {\n background-color: #1565c0;\n }\n\n .rte-button-primary[disabled] {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .rte-button-secondary {\n padding: 8px 16px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 14px;\n cursor: pointer;\n background-color: #f5f5f5;\n color: #333;\n transition: all 0.2s;\n }\n\n .rte-button-secondary:hover {\n background-color: #eeeeee;\n }\n\n .rte-template-dialog {\n width: 600px;\n max-height: 700px;\n }\n\n .rte-input {\n width: 100%;\n padding: 8px 12px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 14px;\n box-sizing: border-box;\n }\n\n .rte-input:focus {\n outline: none;\n border-color: #1976d2;\n }\n\n .rte-tabs {\n display: flex;\n gap: 8px;\n margin-top: 12px;\n border-bottom: 1px solid #eee;\n padding-bottom: 8px;\n }\n\n .rte-tab {\n padding: 6px 12px;\n border: none;\n background: none;\n cursor: pointer;\n font-size: 14px;\n color: #666;\n border-bottom: 2px solid transparent;\n transition: all 0.2s;\n }\n\n .rte-tab:hover {\n color: #333;\n }\n\n .rte-tab.active {\n color: #1976d2;\n border-bottom-color: #1976d2;\n font-weight: 600;\n }\n\n .rte-template-list {\n border: 1px solid #ddd;\n border-radius: 4px;\n max-height: 250px;\n overflow-y: auto;\n margin: 12px 0;\n }\n\n .rte-template-item {\n padding: 12px;\n border-bottom: 1px solid #f0f0f0;\n cursor: pointer;\n transition: background-color 0.2s;\n }\n\n .rte-template-item:last-child {\n border-bottom: none;\n }\n\n .rte-template-item:hover,\n .rte-template-item.selected {\n background-color: #f5f5f5;\n }\n\n .template-name {\n font-weight: 600;\n color: #333;\n margin-bottom: 4px;\n }\n\n .template-description {\n font-size: 12px;\n color: #999;\n }\n\n .rte-template-preview {\n padding: 12px;\n background-color: #fafafa;\n border: 1px solid #eee;\n border-radius: 4px;\n margin-top: 12px;\n max-height: 200px;\n overflow-y: auto;\n }\n\n .template-preview-content {\n font-size: 13px;\n line-height: 1.5;\n margin-top: 8px;\n }\n\n .template-preview-content * {\n margin: 4px 0;\n }\n\n .rte-insert-mode {\n margin-top: 12px;\n padding: 12px;\n background-color: #f5f5f5;\n border-radius: 4px;\n display: flex;\n gap: 16px;\n }\n\n .rte-insert-mode label {\n display: flex;\n align-items: center;\n cursor: pointer;\n font-size: 14px;\n }\n\n .rte-insert-mode input {\n margin-right: 6px;\n cursor: pointer;\n }\n\n .rte-empty-state {\n padding: 40px;\n text-align: center;\n color: #999;\n font-size: 14px;\n }\n `;\n document.head.appendChild(styleElement);\n }\n}\n\n// Auto-initialize when DOM is ready\nif (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', initTemplatePlugin);\n} else {\n // DOM already loaded\n setTimeout(initTemplatePlugin, 100);\n}\n\n// ============================================================================\n// Plugin Definition\n// ============================================================================\n\nexport const TemplatePlugin = (): Plugin => ({\n name: 'template',\n\n toolbar: [\n {\n label: 'Template',\n command: 'insertTemplate',\n icon: '<svg width=\"24px\" height=\"24px\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><g id=\"SVGRepo_bgCarrier\" stroke-width=\"0\"></g><g id=\"SVGRepo_tracerCarrier\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></g><g id=\"SVGRepo_iconCarrier\"> <path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M3 3V9H21V3H3ZM19 5H5V7H19V5Z\" fill=\"#000000\"></path> <path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M3 11V21H11V11H3ZM9 13H5V19H9V13Z\" fill=\"#000000\"></path> <path d=\"M21 11H13V13H21V11Z\" fill=\"#000000\"></path> <path d=\"M13 15H21V17H13V15Z\" fill=\"#000000\"></path> <path d=\"M21 19H13V21H21V19Z\" fill=\"#000000\"></path> </g></svg>'\n }\n ],\n\n commands: {\n insertTemplate: () => {\n openTemplateDialog();\n return true;\n }\n },\n\n keymap: {}\n});\n"],"names":["dialogElement","overlayElement","savedRange","selectedTemplate","selectedCategory","searchTerm","insertMode","PREDEFINED_TEMPLATES","templateCache","getAllTemplates","getTemplatesByCategory","category","getTemplateCategories","categories","searchTemplates","query","q","t","_a","_b","tag","sanitizeTemplate","html","DOMPurify","addCustomTemplate","template","validateTemplate","createTemplateDialog","closeDialog","e","renderDialogContent","filteredTemplates","getFilteredTemplates","cat","attachDialogListeners","renderWarningDialog","cancelBtn","confirmBtn","handleConfirmReplace","allTemplates","closeBtn","insertBtn","handleInsert","searchInput","updateTemplateList","tab","item","templateId","radio","editor","node","element","replaceDocumentWithTemplate","insertTemplateAtCursor","selection","range","fragment","newRange","openTemplateDialog","initTemplatePlugin","styleElement","TemplatePlugin"],"mappings":"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"}
|