@kolkov/angular-editor 3.1.1 → 3.1.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.
@@ -1,1564 +1,1541 @@
1
- import * as i0 from '@angular/core';
2
- import { inject, DOCUMENT, Injectable, EventEmitter, ElementRef, Renderer2, forwardRef, HostListener, ViewChild, Output, HostBinding, Input, Component, ChangeDetectorRef, SecurityContext, ContentChild, Attribute, ViewEncapsulation, NgModule } from '@angular/core';
3
- import { HttpClient, HttpResponse } from '@angular/common/http';
4
- import * as i1$1 from '@angular/forms';
5
- import { NG_VALUE_ACCESSOR, FormsModule, ReactiveFormsModule } from '@angular/forms';
6
- import { DomSanitizer } from '@angular/platform-browser';
7
- import * as i1 from '@angular/common';
8
- import { CommonModule } from '@angular/common';
9
-
10
- class AngularEditorService {
11
- savedSelection = null;
12
- selectedText = '';
13
- uploadUrl = '';
14
- uploadWithCredentials = false;
15
- http = inject(HttpClient);
16
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
17
- doc = inject(DOCUMENT);
18
- /**
19
- * Executed command from editor header buttons exclude toggleEditorMode
20
- * @param command string from triggerCommand
21
- * @param value
22
- */
23
- executeCommand(command, value) {
24
- const commands = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'pre'];
25
- if (commands.includes(command)) {
26
- this.doc.execCommand('formatBlock', false, command);
27
- return;
28
- }
29
- this.doc.execCommand(command, false, value);
30
- }
31
- /**
32
- * Create URL link
33
- * @param url string from UI prompt
34
- */
35
- createLink(url) {
36
- if (!url.includes('http')) {
37
- this.doc.execCommand('createlink', false, url);
38
- }
39
- else {
40
- const newUrl = '<a href="' + url + '" target="_blank">' + this.selectedText + '</a>';
41
- this.insertHtml(newUrl);
42
- }
43
- }
44
- /**
45
- * insert color either font or background
46
- *
47
- * @param color color to be inserted
48
- * @param where where the color has to be inserted either text/background
49
- */
50
- insertColor(color, where) {
51
- const restored = this.restoreSelection();
52
- if (restored) {
53
- if (where === 'textColor') {
54
- this.doc.execCommand('foreColor', false, color);
55
- }
56
- else {
57
- this.doc.execCommand('hiliteColor', false, color);
58
- }
59
- }
60
- }
61
- /**
62
- * Set font name
63
- * @param fontName string
64
- */
65
- setFontName(fontName) {
66
- this.doc.execCommand('fontName', false, fontName);
67
- }
68
- /**
69
- * Set font size
70
- * @param fontSize string
71
- */
72
- setFontSize(fontSize) {
73
- this.doc.execCommand('fontSize', false, fontSize);
74
- }
75
- /**
76
- * Create raw HTML
77
- * @param html HTML string
78
- */
79
- insertHtml(html) {
80
- const isHTMLInserted = this.doc.execCommand('insertHTML', false, html);
81
- if (!isHTMLInserted) {
82
- throw new Error('Unable to perform the operation');
83
- }
84
- }
85
- /**
86
- * save selection when the editor is focussed out
87
- */
88
- saveSelection = () => {
89
- if (this.doc.getSelection) {
90
- const sel = this.doc.getSelection();
91
- if (sel.getRangeAt && sel.rangeCount) {
92
- this.savedSelection = sel.getRangeAt(0);
93
- this.selectedText = sel.toString();
94
- }
95
- }
96
- else {
97
- this.savedSelection = null;
98
- }
99
- };
100
- /**
101
- * restore selection when the editor is focused in
102
- *
103
- * saved selection when the editor is focused out
104
- */
105
- restoreSelection() {
106
- if (this.savedSelection) {
107
- if (this.doc.getSelection) {
108
- const sel = this.doc.getSelection();
109
- sel.removeAllRanges();
110
- sel.addRange(this.savedSelection);
111
- return true;
112
- }
113
- }
114
- return false;
115
- }
116
- /**
117
- * setTimeout used for execute 'saveSelection' method in next event loop iteration
118
- */
119
- executeInNextQueueIteration(callbackFn, timeout = 1e2) {
120
- setTimeout(callbackFn, timeout);
121
- }
122
- /** check any selection is made or not */
123
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
124
- checkSelection() {
125
- if (!this.savedSelection) {
126
- throw new Error('No Selection Made');
127
- }
128
- const selectedText = this.savedSelection.toString();
129
- if (selectedText.length === 0) {
130
- throw new Error('No Selection Made');
131
- }
132
- return true;
133
- }
134
- /**
135
- * Upload file to uploadUrl
136
- * @param file The file
137
- */
138
- uploadImage(file) {
139
- const uploadData = new FormData();
140
- uploadData.append('file', file, file.name);
141
- return this.http.post(this.uploadUrl, uploadData, {
142
- reportProgress: true,
143
- observe: 'events',
144
- withCredentials: this.uploadWithCredentials,
145
- });
146
- }
147
- /**
148
- * Insert image with Url
149
- * @param imageUrl The imageUrl.
150
- */
151
- insertImage(imageUrl) {
152
- this.doc.execCommand('insertImage', false, imageUrl);
153
- }
154
- setDefaultParagraphSeparator(separator) {
155
- this.doc.execCommand('defaultParagraphSeparator', false, separator);
156
- }
157
- /**
158
- * Apply custom class to selection with enterprise-level HTML structure preservation.
159
- * Supports three modes:
160
- * - 'inline': Wrap selection in a single element (legacy behavior)
161
- * - 'block': Apply class to each block element in selection
162
- * - 'auto': Smart detection based on selection span (default)
163
- *
164
- * @param customClass The custom class configuration
165
- */
166
- createCustomClass(customClass) {
167
- if (!customClass || !this.savedSelection) {
168
- return;
169
- }
170
- const mode = customClass.mode || 'auto';
171
- const range = this.savedSelection;
172
- // Restore selection before applying
173
- this.restoreSelection();
174
- if (mode === 'inline') {
175
- this.applyClassInline(range, customClass);
176
- }
177
- else if (mode === 'block') {
178
- this.applyClassToBlocks(range, customClass);
179
- }
180
- else {
181
- // Auto mode: detect if selection spans multiple blocks
182
- const blocks = this.getBlockElementsInRange(range);
183
- if (blocks.length > 1) {
184
- this.applyClassToBlocks(range, customClass);
185
- }
186
- else {
187
- this.applyClassInline(range, customClass);
188
- }
189
- }
190
- }
191
- /**
192
- * Apply class inline by wrapping selection in a single element.
193
- * Uses extractContents + insertNode pattern for safety.
194
- */
195
- applyClassInline(range, customClass) {
196
- const tagName = customClass.tag || 'span';
197
- try {
198
- // Create wrapper element
199
- const wrapper = this.doc.createElement(tagName);
200
- wrapper.className = customClass.class;
201
- // Extract contents and wrap (safer than surroundContents)
202
- const contents = range.extractContents();
203
- wrapper.appendChild(contents);
204
- range.insertNode(wrapper);
205
- // Normalize to merge adjacent text nodes
206
- if (wrapper.parentNode) {
207
- wrapper.parentNode.normalize();
208
- }
209
- // Update selection to the new wrapper
210
- range.selectNodeContents(wrapper);
211
- const sel = this.doc.getSelection();
212
- sel.removeAllRanges();
213
- sel.addRange(range);
214
- }
215
- catch (e) {
216
- // Fallback to legacy method if DOM manipulation fails
217
- console.warn('applyClassInline failed, using fallback:', e);
218
- this.applyClassInlineFallback(customClass);
219
- }
220
- }
221
- /**
222
- * Fallback method for inline class application (legacy behavior).
223
- */
224
- applyClassInlineFallback(customClass) {
225
- const tagName = customClass.tag || 'span';
226
- const newTag = '<' + tagName + ' class="' + customClass.class + '">' + this.selectedText + '</' + tagName + '>';
227
- this.insertHtml(newTag);
228
- }
229
- /**
230
- * Apply class to each block element in selection.
231
- * Preserves HTML structure by adding class to existing elements.
232
- */
233
- applyClassToBlocks(range, customClass) {
234
- const blocks = this.getBlockElementsInRange(range);
235
- if (blocks.length === 0) {
236
- // No blocks found, fall back to inline
237
- this.applyClassInline(range, customClass);
238
- return;
239
- }
240
- // Apply class to each block element
241
- blocks.forEach(block => {
242
- // Toggle class: remove if present, add if not
243
- if (block.classList.contains(customClass.class)) {
244
- block.classList.remove(customClass.class);
245
- }
246
- else {
247
- block.classList.add(customClass.class);
248
- }
249
- });
250
- // Trigger change detection by moving cursor
251
- const sel = this.doc.getSelection();
252
- if (sel && blocks.length > 0) {
253
- // Reselect the original range
254
- sel.removeAllRanges();
255
- sel.addRange(range);
256
- }
257
- }
258
- /**
259
- * Get all block-level elements within a range.
260
- * Returns elements that are fully or partially selected.
261
- */
262
- getBlockElementsInRange(range) {
263
- const blockTags = [
264
- 'P', 'DIV', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6',
265
- 'LI', 'BLOCKQUOTE', 'PRE', 'ADDRESS', 'ARTICLE',
266
- 'ASIDE', 'FIGCAPTION', 'FIGURE', 'FOOTER', 'HEADER',
267
- 'MAIN', 'NAV', 'SECTION'
268
- ];
269
- const blocks = [];
270
- const seen = new Set();
271
- // Get the common ancestor
272
- const container = range.commonAncestorContainer;
273
- const root = container.nodeType === Node.ELEMENT_NODE
274
- ? container
275
- : container.parentElement;
276
- if (!root) {
277
- return blocks;
278
- }
279
- // If root itself is a block element and fully contains the range
280
- if (blockTags.includes(root.tagName) && this.isNodeFullyInRange(root, range)) {
281
- return [root];
282
- }
283
- // Find all block elements within the range using TreeWalker
284
- const walker = this.doc.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, {
285
- acceptNode: (node) => {
286
- if (!blockTags.includes(node.tagName)) {
287
- return NodeFilter.FILTER_SKIP;
288
- }
289
- // Check if node intersects with selection
290
- if (range.intersectsNode(node)) {
291
- return NodeFilter.FILTER_ACCEPT;
292
- }
293
- return NodeFilter.FILTER_SKIP;
294
- }
295
- });
296
- let node;
297
- while ((node = walker.nextNode())) {
298
- const element = node;
299
- // Avoid duplicates and nested blocks
300
- if (!seen.has(element) && !this.hasAncestorInSet(element, seen)) {
301
- seen.add(element);
302
- blocks.push(element);
303
- }
304
- }
305
- // If no blocks found, check if we're inside a block
306
- if (blocks.length === 0) {
307
- let parent = root;
308
- while (parent && parent !== this.doc.body) {
309
- if (blockTags.includes(parent.tagName)) {
310
- blocks.push(parent);
311
- break;
312
- }
313
- parent = parent.parentElement;
314
- }
315
- }
316
- return blocks;
317
- }
318
- /**
319
- * Check if a node is fully contained within a range.
320
- */
321
- isNodeFullyInRange(node, range) {
322
- const nodeRange = this.doc.createRange();
323
- nodeRange.selectNodeContents(node);
324
- return range.compareBoundaryPoints(Range.START_TO_START, nodeRange) <= 0 &&
325
- range.compareBoundaryPoints(Range.END_TO_END, nodeRange) >= 0;
326
- }
327
- /**
328
- * Check if element has an ancestor in the given set.
329
- */
330
- hasAncestorInSet(element, set) {
331
- let parent = element.parentElement;
332
- while (parent) {
333
- if (set.has(parent)) {
334
- return true;
335
- }
336
- parent = parent.parentElement;
337
- }
338
- return false;
339
- }
340
- insertVideo(videoUrl) {
341
- if (videoUrl.match('www.youtube.com') || videoUrl.match('youtu.be')) {
342
- this.insertYouTubeVideoTag(videoUrl);
343
- }
344
- if (videoUrl.match('vimeo.com')) {
345
- this.insertVimeoVideoTag(videoUrl);
346
- }
347
- }
348
- insertYouTubeVideoTag(videoUrl) {
349
- // Support both formats: youtube.com/watch?v=ID and youtu.be/ID
350
- let id;
351
- if (videoUrl.includes('youtu.be/')) {
352
- id = videoUrl.split('youtu.be/')[1].split('?')[0];
353
- }
354
- else {
355
- id = videoUrl.split('v=')[1].split('&')[0];
356
- }
357
- const imageUrl = `https://img.youtube.com/vi/${id}/0.jpg`;
358
- const thumbnail = `
1
+ import * as i0 from "@angular/core";
2
+ import { Attribute, ChangeDetectorRef, Component, ContentChild, DOCUMENT, ElementRef, EventEmitter, HostBinding, HostListener, Injectable, Input, NgModule, Output, Renderer2, SecurityContext, ViewChild, ViewEncapsulation, forwardRef, inject } from "@angular/core";
3
+ import { HttpClient, HttpResponse } from "@angular/common/http";
4
+ import * as i1 from "@angular/forms";
5
+ import { FormsModule, NG_VALUE_ACCESSOR, ReactiveFormsModule } from "@angular/forms";
6
+ import { DomSanitizer } from "@angular/platform-browser";
7
+ import * as i1$1 from "@angular/common";
8
+ import { CommonModule } from "@angular/common";
9
+ var AngularEditorService = class AngularEditorService {
10
+ savedSelection = null;
11
+ selectedText = "";
12
+ uploadUrl = "";
13
+ uploadWithCredentials = false;
14
+ http = inject(HttpClient);
15
+ doc = inject(DOCUMENT);
16
+ executeCommand(command, value) {
17
+ if ([
18
+ "h1",
19
+ "h2",
20
+ "h3",
21
+ "h4",
22
+ "h5",
23
+ "h6",
24
+ "p",
25
+ "pre"
26
+ ].includes(command)) {
27
+ this.doc.execCommand("formatBlock", false, command);
28
+ return;
29
+ }
30
+ this.doc.execCommand(command, false, value);
31
+ }
32
+ createLink(url) {
33
+ if (!url.includes("http")) this.doc.execCommand("createlink", false, url);
34
+ else {
35
+ const newUrl = "<a href=\"" + url + "\" target=\"_blank\">" + this.selectedText + "</a>";
36
+ this.insertHtml(newUrl);
37
+ }
38
+ }
39
+ insertColor(color, where) {
40
+ if (this.restoreSelection()) {
41
+ if (where === "textColor") this.doc.execCommand("foreColor", false, color);
42
+ else this.doc.execCommand("hiliteColor", false, color);
43
+ }
44
+ }
45
+ setFontName(fontName) {
46
+ this.doc.execCommand("fontName", false, fontName);
47
+ }
48
+ setFontSize(fontSize) {
49
+ this.doc.execCommand("fontSize", false, fontSize);
50
+ }
51
+ insertHtml(html) {
52
+ if (!this.doc.execCommand("insertHTML", false, html)) throw new Error("Unable to perform the operation");
53
+ }
54
+ saveSelection = () => {
55
+ if (this.doc.getSelection) {
56
+ const sel = this.doc.getSelection();
57
+ if (sel.getRangeAt && sel.rangeCount) {
58
+ this.savedSelection = sel.getRangeAt(0);
59
+ this.selectedText = sel.toString();
60
+ }
61
+ } else this.savedSelection = null;
62
+ };
63
+ restoreSelection() {
64
+ if (this.savedSelection) {
65
+ if (this.doc.getSelection) {
66
+ const sel = this.doc.getSelection();
67
+ sel.removeAllRanges();
68
+ sel.addRange(this.savedSelection);
69
+ return true;
70
+ }
71
+ }
72
+ return false;
73
+ }
74
+ executeInNextQueueIteration(callbackFn, timeout = 100) {
75
+ setTimeout(callbackFn, timeout);
76
+ }
77
+ checkSelection() {
78
+ if (!this.savedSelection) throw new Error("No Selection Made");
79
+ if (this.savedSelection.toString().length === 0) throw new Error("No Selection Made");
80
+ return true;
81
+ }
82
+ uploadImage(file) {
83
+ const uploadData = new FormData();
84
+ uploadData.append("file", file, file.name);
85
+ return this.http.post(this.uploadUrl, uploadData, {
86
+ reportProgress: true,
87
+ observe: "events",
88
+ withCredentials: this.uploadWithCredentials
89
+ });
90
+ }
91
+ insertImage(imageUrl) {
92
+ this.doc.execCommand("insertImage", false, imageUrl);
93
+ }
94
+ setDefaultParagraphSeparator(separator) {
95
+ this.doc.execCommand("defaultParagraphSeparator", false, separator);
96
+ }
97
+ createCustomClass(customClass) {
98
+ if (!customClass || !this.savedSelection) return;
99
+ const mode = customClass.mode || "auto";
100
+ const range = this.savedSelection;
101
+ this.restoreSelection();
102
+ if (mode === "inline") this.applyClassInline(range, customClass);
103
+ else if (mode === "block") this.applyClassToBlocks(range, customClass);
104
+ else if (this.getBlockElementsInRange(range).length > 1) this.applyClassToBlocks(range, customClass);
105
+ else this.applyClassInline(range, customClass);
106
+ }
107
+ applyClassInline(range, customClass) {
108
+ const tagName = customClass.tag || "span";
109
+ try {
110
+ const wrapper = this.doc.createElement(tagName);
111
+ wrapper.className = customClass.class;
112
+ const contents = range.extractContents();
113
+ wrapper.appendChild(contents);
114
+ range.insertNode(wrapper);
115
+ if (wrapper.parentNode) wrapper.parentNode.normalize();
116
+ range.selectNodeContents(wrapper);
117
+ const sel = this.doc.getSelection();
118
+ sel.removeAllRanges();
119
+ sel.addRange(range);
120
+ } catch (e) {
121
+ console.warn("applyClassInline failed, using fallback:", e);
122
+ this.applyClassInlineFallback(customClass);
123
+ }
124
+ }
125
+ applyClassInlineFallback(customClass) {
126
+ const tagName = customClass.tag || "span";
127
+ const newTag = "<" + tagName + " class=\"" + customClass.class + "\">" + this.selectedText + "</" + tagName + ">";
128
+ this.insertHtml(newTag);
129
+ }
130
+ applyClassToBlocks(range, customClass) {
131
+ const blocks = this.getBlockElementsInRange(range);
132
+ if (blocks.length === 0) {
133
+ this.applyClassInline(range, customClass);
134
+ return;
135
+ }
136
+ blocks.forEach((block) => {
137
+ if (block.classList.contains(customClass.class)) block.classList.remove(customClass.class);
138
+ else block.classList.add(customClass.class);
139
+ });
140
+ const sel = this.doc.getSelection();
141
+ if (sel && blocks.length > 0) {
142
+ sel.removeAllRanges();
143
+ sel.addRange(range);
144
+ }
145
+ }
146
+ getBlockElementsInRange(range) {
147
+ const blockTags = [
148
+ "P",
149
+ "DIV",
150
+ "H1",
151
+ "H2",
152
+ "H3",
153
+ "H4",
154
+ "H5",
155
+ "H6",
156
+ "LI",
157
+ "BLOCKQUOTE",
158
+ "PRE",
159
+ "ADDRESS",
160
+ "ARTICLE",
161
+ "ASIDE",
162
+ "FIGCAPTION",
163
+ "FIGURE",
164
+ "FOOTER",
165
+ "HEADER",
166
+ "MAIN",
167
+ "NAV",
168
+ "SECTION"
169
+ ];
170
+ const blocks = [];
171
+ const seen = /* @__PURE__ */ new Set();
172
+ const container = range.commonAncestorContainer;
173
+ const root = container.nodeType === Node.ELEMENT_NODE ? container : container.parentElement;
174
+ if (!root) return blocks;
175
+ if (blockTags.includes(root.tagName) && this.isNodeFullyInRange(root, range)) return [root];
176
+ const walker = this.doc.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, { acceptNode: (node) => {
177
+ if (!blockTags.includes(node.tagName)) return NodeFilter.FILTER_SKIP;
178
+ if (range.intersectsNode(node)) return NodeFilter.FILTER_ACCEPT;
179
+ return NodeFilter.FILTER_SKIP;
180
+ } });
181
+ let node;
182
+ while (node = walker.nextNode()) {
183
+ const element = node;
184
+ if (!seen.has(element) && !this.hasAncestorInSet(element, seen)) {
185
+ seen.add(element);
186
+ blocks.push(element);
187
+ }
188
+ }
189
+ if (blocks.length === 0) {
190
+ let parent = root;
191
+ while (parent && parent !== this.doc.body) {
192
+ if (blockTags.includes(parent.tagName)) {
193
+ blocks.push(parent);
194
+ break;
195
+ }
196
+ parent = parent.parentElement;
197
+ }
198
+ }
199
+ return blocks;
200
+ }
201
+ isNodeFullyInRange(node, range) {
202
+ const nodeRange = this.doc.createRange();
203
+ nodeRange.selectNodeContents(node);
204
+ return range.compareBoundaryPoints(Range.START_TO_START, nodeRange) <= 0 && range.compareBoundaryPoints(Range.END_TO_END, nodeRange) >= 0;
205
+ }
206
+ hasAncestorInSet(element, set) {
207
+ let parent = element.parentElement;
208
+ while (parent) {
209
+ if (set.has(parent)) return true;
210
+ parent = parent.parentElement;
211
+ }
212
+ return false;
213
+ }
214
+ insertVideo(videoUrl) {
215
+ if (videoUrl.match("www.youtube.com") || videoUrl.match("youtu.be")) this.insertYouTubeVideoTag(videoUrl);
216
+ if (videoUrl.match("vimeo.com")) this.insertVimeoVideoTag(videoUrl);
217
+ }
218
+ insertYouTubeVideoTag(videoUrl) {
219
+ let id;
220
+ if (videoUrl.includes("youtu.be/")) id = videoUrl.split("youtu.be/")[1].split("?")[0];
221
+ else id = videoUrl.split("v=")[1].split("&")[0];
222
+ const thumbnail = `
359
223
  <div style='position: relative'>
360
224
  <a href='${videoUrl}' target='_blank'>
361
- <img src="${imageUrl}" alt="click to watch"/>
225
+ <img src="${`https://img.youtube.com/vi/${id}/0.jpg`}" alt="click to watch"/>
362
226
  <img style='position: absolute; left:200px; top:140px'
363
227
  src="https://img.icons8.com/color/96/000000/youtube-play.png"/>
364
228
  </a>
365
229
  </div>`;
366
- this.insertHtml(thumbnail);
367
- }
368
- insertVimeoVideoTag(videoUrl) {
369
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
370
- const sub = this.http.get(`https://vimeo.com/api/oembed.json?url=${videoUrl}`).subscribe(data => {
371
- const imageUrl = data.thumbnail_url_with_play_button;
372
- const thumbnail = `<div>
230
+ this.insertHtml(thumbnail);
231
+ }
232
+ insertVimeoVideoTag(videoUrl) {
233
+ const sub = this.http.get(`https://vimeo.com/api/oembed.json?url=${videoUrl}`).subscribe((data) => {
234
+ const thumbnail = `<div>
373
235
  <a href='${videoUrl}' target='_blank'>
374
- <img src="${imageUrl}" alt="${data.title}"/>
236
+ <img src="${data.thumbnail_url_with_play_button}" alt="${data.title}"/>
375
237
  </a>
376
238
  </div>`;
377
- this.insertHtml(thumbnail);
378
- sub.unsubscribe();
379
- });
380
- }
381
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
382
- nextNode(node) {
383
- if (node.hasChildNodes()) {
384
- return node.firstChild;
385
- }
386
- else {
387
- while (node && !node.nextSibling) {
388
- node = node.parentNode;
389
- }
390
- if (!node) {
391
- return null;
392
- }
393
- return node.nextSibling;
394
- }
395
- }
396
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
397
- getRangeSelectedNodes(range, includePartiallySelectedContainers) {
398
- let node = range.startContainer;
399
- const endNode = range.endContainer;
400
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
401
- let rangeNodes = [];
402
- // Special case for a range that is contained within a single node
403
- if (node === endNode) {
404
- rangeNodes = [node];
405
- }
406
- else {
407
- // Iterate nodes until we hit the end container
408
- while (node && node !== endNode) {
409
- rangeNodes.push(node = this.nextNode(node));
410
- }
411
- // Add partially selected nodes at the start of the range
412
- node = range.startContainer;
413
- while (node && node !== range.commonAncestorContainer) {
414
- rangeNodes.unshift(node);
415
- node = node.parentNode;
416
- }
417
- }
418
- // Add ancestors of the range container, if required
419
- if (includePartiallySelectedContainers) {
420
- node = range.commonAncestorContainer;
421
- while (node) {
422
- rangeNodes.push(node);
423
- node = node.parentNode;
424
- }
425
- }
426
- return rangeNodes;
427
- }
428
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
429
- getSelectedNodes() {
430
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
431
- const nodes = [];
432
- if (this.doc.getSelection) {
433
- const sel = this.doc.getSelection();
434
- for (let i = 0, len = sel.rangeCount; i < len; ++i) {
435
- nodes.push(...this.getRangeSelectedNodes(sel.getRangeAt(i), true));
436
- }
437
- }
438
- return nodes;
439
- }
440
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
441
- replaceWithOwnChildren(el) {
442
- const parent = el.parentNode;
443
- while (el.hasChildNodes()) {
444
- parent.insertBefore(el.firstChild, el);
445
- }
446
- parent.removeChild(el);
447
- }
448
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
449
- removeSelectedElements(tagNames) {
450
- const tagNamesArray = tagNames.toLowerCase().split(',');
451
- this.getSelectedNodes().forEach((node) => {
452
- if (node.nodeType === 1 &&
453
- tagNamesArray.indexOf(node.tagName.toLowerCase()) > -1) {
454
- // Remove the node and replace it with its children
455
- this.replaceWithOwnChildren(node);
456
- }
457
- });
458
- }
459
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: AngularEditorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
460
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: AngularEditorService });
461
- }
462
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: AngularEditorService, decorators: [{
463
- type: Injectable
464
- }] });
465
-
239
+ this.insertHtml(thumbnail);
240
+ sub.unsubscribe();
241
+ });
242
+ }
243
+ nextNode(node) {
244
+ if (node.hasChildNodes()) return node.firstChild;
245
+ else {
246
+ while (node && !node.nextSibling) node = node.parentNode;
247
+ if (!node) return null;
248
+ return node.nextSibling;
249
+ }
250
+ }
251
+ getRangeSelectedNodes(range, includePartiallySelectedContainers) {
252
+ let node = range.startContainer;
253
+ const endNode = range.endContainer;
254
+ let rangeNodes = [];
255
+ if (node === endNode) rangeNodes = [node];
256
+ else {
257
+ while (node && node !== endNode) rangeNodes.push(node = this.nextNode(node));
258
+ node = range.startContainer;
259
+ while (node && node !== range.commonAncestorContainer) {
260
+ rangeNodes.unshift(node);
261
+ node = node.parentNode;
262
+ }
263
+ }
264
+ if (includePartiallySelectedContainers) {
265
+ node = range.commonAncestorContainer;
266
+ while (node) {
267
+ rangeNodes.push(node);
268
+ node = node.parentNode;
269
+ }
270
+ }
271
+ return rangeNodes;
272
+ }
273
+ getSelectedNodes() {
274
+ const nodes = [];
275
+ if (this.doc.getSelection) {
276
+ const sel = this.doc.getSelection();
277
+ for (let i = 0, len = sel.rangeCount; i < len; ++i) nodes.push(...this.getRangeSelectedNodes(sel.getRangeAt(i), true));
278
+ }
279
+ return nodes;
280
+ }
281
+ replaceWithOwnChildren(el) {
282
+ const parent = el.parentNode;
283
+ while (el.hasChildNodes()) parent.insertBefore(el.firstChild, el);
284
+ parent.removeChild(el);
285
+ }
286
+ removeSelectedElements(tagNames) {
287
+ const tagNamesArray = tagNames.toLowerCase().split(",");
288
+ this.getSelectedNodes().forEach((node) => {
289
+ if (node.nodeType === 1 && tagNamesArray.indexOf(node.tagName.toLowerCase()) > -1) this.replaceWithOwnChildren(node);
290
+ });
291
+ }
292
+ static ɵfac = i0.ɵɵngDeclareFactory({
293
+ minVersion: "12.0.0",
294
+ version: "22.2.0",
295
+ ngImport: i0,
296
+ type: AngularEditorService,
297
+ deps: [],
298
+ target: i0.ɵɵFactoryTarget.Injectable
299
+ });
300
+ static ɵprov = i0.ɵɵngDeclareInjectable({
301
+ minVersion: "12.0.0",
302
+ version: "22.2.0",
303
+ ngImport: i0,
304
+ type: AngularEditorService
305
+ });
306
+ };
307
+ i0.ɵɵngDeclareClassMetadata({
308
+ minVersion: "12.0.0",
309
+ version: "22.2.0",
310
+ ngImport: i0,
311
+ type: AngularEditorService,
312
+ decorators: [{ type: Injectable }]
313
+ });
466
314
  const angularEditorConfig = {
467
- editable: true,
468
- spellcheck: true,
469
- height: 'auto',
470
- minHeight: '0',
471
- maxHeight: 'auto',
472
- width: 'auto',
473
- minWidth: '0',
474
- translate: 'yes',
475
- enableToolbar: true,
476
- showToolbar: true,
477
- placeholder: 'Enter text here...',
478
- defaultParagraphSeparator: '',
479
- defaultFontName: '',
480
- defaultFontSize: '',
481
- fonts: [
482
- { class: 'arial', name: 'Arial' },
483
- { class: 'times-new-roman', name: 'Times New Roman' },
484
- { class: 'calibri', name: 'Calibri' },
485
- { class: 'comic-sans-ms', name: 'Comic Sans MS' }
486
- ],
487
- uploadUrl: 'v1/image',
488
- uploadWithCredentials: false,
489
- sanitize: true,
490
- toolbarPosition: 'top',
491
- outline: true,
492
- /*toolbarHiddenButtons: [
493
- ['bold', 'italic', 'underline', 'strikeThrough', 'superscript', 'subscript'],
494
- ['heading', 'fontName', 'fontSize', 'color'],
495
- ['justifyLeft', 'justifyCenter', 'justifyRight', 'justifyFull', 'indent', 'outdent'],
496
- ['cut', 'copy', 'delete', 'removeFormat', 'undo', 'redo'],
497
- ['paragraph', 'blockquote', 'removeBlockquote', 'horizontalLine', 'orderedList', 'unorderedList'],
498
- ['link', 'unlink', 'image', 'video']
499
- ]*/
315
+ editable: true,
316
+ spellcheck: true,
317
+ height: "auto",
318
+ minHeight: "0",
319
+ maxHeight: "auto",
320
+ width: "auto",
321
+ minWidth: "0",
322
+ translate: "yes",
323
+ enableToolbar: true,
324
+ showToolbar: true,
325
+ placeholder: "Enter text here...",
326
+ defaultParagraphSeparator: "",
327
+ defaultFontName: "",
328
+ defaultFontSize: "",
329
+ fonts: [
330
+ {
331
+ class: "arial",
332
+ name: "Arial"
333
+ },
334
+ {
335
+ class: "times-new-roman",
336
+ name: "Times New Roman"
337
+ },
338
+ {
339
+ class: "calibri",
340
+ name: "Calibri"
341
+ },
342
+ {
343
+ class: "comic-sans-ms",
344
+ name: "Comic Sans MS"
345
+ }
346
+ ],
347
+ uploadUrl: "v1/image",
348
+ uploadWithCredentials: false,
349
+ sanitize: true,
350
+ toolbarPosition: "top",
351
+ outline: true
500
352
  };
501
-
502
353
  function isDefined(value) {
503
- return value !== undefined && value !== null;
504
- }
505
-
506
- class AeSelectComponent {
507
- options = [];
508
- // eslint-disable-next-line @angular-eslint/no-input-rename
509
- isHidden = false;
510
- selectedOption;
511
- disabled = false;
512
- optionId = 0;
513
- get label() {
514
- return this.selectedOption && Object.prototype.hasOwnProperty.call(this.selectedOption, 'label') ? this.selectedOption.label : 'Select';
515
- }
516
- opened = false;
517
- get value() {
518
- return this.selectedOption.value;
519
- }
520
- hidden = 'inline-block';
521
- // eslint-disable-next-line @angular-eslint/no-output-native, @angular-eslint/no-output-rename
522
- changeEvent = new EventEmitter();
523
- labelButton;
524
- elRef = inject(ElementRef);
525
- r = inject(Renderer2);
526
- ngOnInit() {
527
- this.selectedOption = this.options[0];
528
- if (isDefined(this.isHidden) && this.isHidden) {
529
- this.hide();
530
- }
531
- }
532
- hide() {
533
- this.hidden = 'none';
534
- }
535
- optionSelect(option, event) {
536
- //console.log(event.button, event.buttons);
537
- if (event.buttons !== 1) {
538
- return;
539
- }
540
- event.preventDefault();
541
- event.stopPropagation();
542
- this.setValue(option.value);
543
- this.onChange(this.selectedOption.value);
544
- this.changeEvent.emit(this.selectedOption.value);
545
- this.onTouched();
546
- this.opened = false;
547
- }
548
- toggleOpen(event) {
549
- // event.stopPropagation();
550
- if (this.disabled) {
551
- return;
552
- }
553
- this.opened = !this.opened;
554
- }
555
- onClick($event) {
556
- if (!this.elRef.nativeElement.contains($event.target)) {
557
- this.close();
558
- }
559
- }
560
- close() {
561
- this.opened = false;
562
- }
563
- get isOpen() {
564
- return this.opened;
565
- }
566
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
567
- writeValue(value) {
568
- if (!value || typeof value !== 'string') {
569
- return;
570
- }
571
- this.setValue(value);
572
- }
573
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
574
- setValue(value) {
575
- let index = 0;
576
- const selectedEl = this.options.find((el, i) => {
577
- index = i;
578
- return el.value === value;
579
- });
580
- if (selectedEl) {
581
- this.selectedOption = selectedEl;
582
- this.optionId = index;
583
- }
584
- }
585
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
586
- onChange = () => { };
587
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
588
- onTouched = () => { };
589
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
590
- registerOnChange(fn) {
591
- this.onChange = fn;
592
- }
593
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
594
- registerOnTouched(fn) {
595
- this.onTouched = fn;
596
- }
597
- setDisabledState(isDisabled) {
598
- this.labelButton.nativeElement.disabled = isDisabled;
599
- const div = this.labelButton.nativeElement;
600
- const action = isDisabled ? 'addClass' : 'removeClass';
601
- this.r[action](div, 'disabled');
602
- this.disabled = isDisabled;
603
- }
604
- handleKeyDown($event) {
605
- if (!this.opened) {
606
- return;
607
- }
608
- // console.log($event.key);
609
- // if (KeyCode[$event.key]) {
610
- switch ($event.key) {
611
- case 'ArrowDown':
612
- this._handleArrowDown($event);
613
- break;
614
- case 'ArrowUp':
615
- this._handleArrowUp($event);
616
- break;
617
- case 'Space':
618
- this._handleSpace($event);
619
- break;
620
- case 'Enter':
621
- this._handleEnter($event);
622
- break;
623
- case 'Tab':
624
- this._handleTab($event);
625
- break;
626
- case 'Escape':
627
- this.close();
628
- $event.preventDefault();
629
- break;
630
- case 'Backspace':
631
- this._handleBackspace();
632
- break;
633
- }
634
- // } else if ($event.key && $event.key.length === 1) {
635
- // this._keyPress$.next($event.key.toLocaleLowerCase());
636
- // }
637
- }
638
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
639
- _handleArrowDown($event) {
640
- if (this.optionId < this.options.length - 1) {
641
- this.optionId++;
642
- }
643
- }
644
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
645
- _handleArrowUp($event) {
646
- if (this.optionId >= 1) {
647
- this.optionId--;
648
- }
649
- }
650
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
651
- _handleSpace($event) {
652
- }
653
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
654
- _handleEnter($event) {
655
- this.optionSelect(this.options[this.optionId], $event);
656
- }
657
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
658
- _handleTab($event) {
659
- }
660
- _handleBackspace() {
661
- }
662
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: AeSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
663
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.7", type: AeSelectComponent, isStandalone: false, selector: "ae-select", inputs: { options: "options", isHidden: ["hidden", "isHidden"] }, outputs: { changeEvent: "change" }, host: { listeners: { "document:click": "onClick($event)", "keydown": "handleKeyDown($event)" }, properties: { "style.display": "this.hidden" } }, providers: [
664
- {
665
- provide: NG_VALUE_ACCESSOR,
666
- useExisting: forwardRef(() => AeSelectComponent),
667
- multi: true,
668
- }
669
- ], viewQueries: [{ propertyName: "labelButton", first: true, predicate: ["labelButton"], descendants: true, static: true }], ngImport: i0, template: "<span class=\"ae-picker\" [ngClass]=\"{'ae-expanded':isOpen}\">\n <button [tabIndex]=\"-1\" #labelButton tabindex=\"-1\" type=\"button\" role=\"button\" class=\"ae-picker-label\" (click)=\"toggleOpen($event);\">{{label}}\n <svg>\n <use [attr.href]=\"'assets/ae-icons/icons.svg#sort'\" [attr.xlink:href]=\"'assets/ae-icons/icons.svg#sort'\"></use>\n </svg>\n </button>\n <span class=\"ae-picker-options\">\n @for (item of options; track item.value; let i = $index) {\n <span tabindex=\"-1\" type=\"button\" role=\"button\" class=\"ae-picker-item\"\n [ngClass]=\"{'selected': item.value === value, 'focused': i === optionId}\"\n (mousedown)=\"optionSelect(item, $event)\">\n {{item.label}}\n </span>\n }\n @if (!options.length) {\n <span class=\"dropdown-item\">No items for select</span>\n }\n </span>\n</span>\n", styles: ["a{cursor:pointer}svg{width:100%;height:100%}.ae-picker{color:var(--ae-picker-color, #444);display:inline-block;float:left;width:100%;position:relative;vertical-align:middle}.ae-picker-label{cursor:pointer;display:inline-block;padding-left:8px;padding-right:10px;position:relative;width:100%;line-height:1.8rem;vertical-align:middle;font-size:85%;text-align:left;background-color:var(--ae-picker-label-color, white);min-width:2rem;float:left;border:1px solid #ddd;border-radius:var(--ae-button-radius, 4px);text-overflow:clip;overflow:hidden;white-space:nowrap;height:2rem}.ae-picker-label:before{content:\"\";position:absolute;right:0;top:0;width:20px;height:100%;background:linear-gradient(to right,var(--ae-picker-label-color, white),var(--ae-picker-label-color, white) 100%)}.ae-picker-label:focus{outline:none}.ae-picker-label:hover{cursor:pointer;background-color:#f1f1f1;transition:.2s ease}.ae-picker-label:hover:before{background:linear-gradient(to right,#f5f5f5 100%,#fff)}.ae-picker-label:disabled{background-color:#f5f5f5;pointer-events:none;cursor:not-allowed}.ae-picker-label:disabled:before{background:linear-gradient(to right,#f5f5f5 100%,#fff)}.ae-picker-label svg{position:absolute;right:0;width:1rem}.ae-picker-label svg:not(:root){overflow:hidden}.ae-picker-label svg .ae-stroke{fill:none;stroke:#444;stroke-linecap:round;stroke-linejoin:round;stroke-width:2}.ae-picker-options{background-color:var(--ae-picker-option-bg-color, #fff);display:none;min-width:100%;position:absolute;white-space:nowrap;z-index:3;border:1px solid transparent;box-shadow:#0003 0 2px 8px}.ae-picker-options .ae-picker-item{cursor:pointer;display:block;padding:5px;z-index:3;text-align:left;background-color:transparent;min-width:2rem;border:0 solid #ddd}.ae-picker-options .ae-picker-item.selected{color:#06c;background-color:var(--ae-picker-option-active-bg-color, #fff4c2)}.ae-picker-options .ae-picker-item.focused{background-color:var(--ae-picker-option-focused-bg-color, #fbf9b0)}.ae-picker-options .ae-picker-item:hover{background-color:var(--ae-picker-option-hover-bg-color, #fffa98)}.ae-expanded{display:block;margin-top:-1px;z-index:1}.ae-expanded .ae-picker-label{color:#ccc;z-index:2}.ae-expanded .ae-picker-label svg{color:#ccc;z-index:2}.ae-expanded .ae-picker-label svg .ae-stroke{stroke:#ccc}.ae-expanded .ae-picker-options{display:flex;flex-direction:column;margin-top:-1px;top:100%;z-index:3;border-color:#ccc}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
354
+ return value !== void 0 && value !== null;
670
355
  }
671
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: AeSelectComponent, decorators: [{
672
- type: Component,
673
- args: [{ selector: 'ae-select', providers: [
674
- {
675
- provide: NG_VALUE_ACCESSOR,
676
- useExisting: forwardRef(() => AeSelectComponent),
677
- multi: true,
678
- }
679
- ], standalone: false, template: "<span class=\"ae-picker\" [ngClass]=\"{'ae-expanded':isOpen}\">\n <button [tabIndex]=\"-1\" #labelButton tabindex=\"-1\" type=\"button\" role=\"button\" class=\"ae-picker-label\" (click)=\"toggleOpen($event);\">{{label}}\n <svg>\n <use [attr.href]=\"'assets/ae-icons/icons.svg#sort'\" [attr.xlink:href]=\"'assets/ae-icons/icons.svg#sort'\"></use>\n </svg>\n </button>\n <span class=\"ae-picker-options\">\n @for (item of options; track item.value; let i = $index) {\n <span tabindex=\"-1\" type=\"button\" role=\"button\" class=\"ae-picker-item\"\n [ngClass]=\"{'selected': item.value === value, 'focused': i === optionId}\"\n (mousedown)=\"optionSelect(item, $event)\">\n {{item.label}}\n </span>\n }\n @if (!options.length) {\n <span class=\"dropdown-item\">No items for select</span>\n }\n </span>\n</span>\n", styles: ["a{cursor:pointer}svg{width:100%;height:100%}.ae-picker{color:var(--ae-picker-color, #444);display:inline-block;float:left;width:100%;position:relative;vertical-align:middle}.ae-picker-label{cursor:pointer;display:inline-block;padding-left:8px;padding-right:10px;position:relative;width:100%;line-height:1.8rem;vertical-align:middle;font-size:85%;text-align:left;background-color:var(--ae-picker-label-color, white);min-width:2rem;float:left;border:1px solid #ddd;border-radius:var(--ae-button-radius, 4px);text-overflow:clip;overflow:hidden;white-space:nowrap;height:2rem}.ae-picker-label:before{content:\"\";position:absolute;right:0;top:0;width:20px;height:100%;background:linear-gradient(to right,var(--ae-picker-label-color, white),var(--ae-picker-label-color, white) 100%)}.ae-picker-label:focus{outline:none}.ae-picker-label:hover{cursor:pointer;background-color:#f1f1f1;transition:.2s ease}.ae-picker-label:hover:before{background:linear-gradient(to right,#f5f5f5 100%,#fff)}.ae-picker-label:disabled{background-color:#f5f5f5;pointer-events:none;cursor:not-allowed}.ae-picker-label:disabled:before{background:linear-gradient(to right,#f5f5f5 100%,#fff)}.ae-picker-label svg{position:absolute;right:0;width:1rem}.ae-picker-label svg:not(:root){overflow:hidden}.ae-picker-label svg .ae-stroke{fill:none;stroke:#444;stroke-linecap:round;stroke-linejoin:round;stroke-width:2}.ae-picker-options{background-color:var(--ae-picker-option-bg-color, #fff);display:none;min-width:100%;position:absolute;white-space:nowrap;z-index:3;border:1px solid transparent;box-shadow:#0003 0 2px 8px}.ae-picker-options .ae-picker-item{cursor:pointer;display:block;padding:5px;z-index:3;text-align:left;background-color:transparent;min-width:2rem;border:0 solid #ddd}.ae-picker-options .ae-picker-item.selected{color:#06c;background-color:var(--ae-picker-option-active-bg-color, #fff4c2)}.ae-picker-options .ae-picker-item.focused{background-color:var(--ae-picker-option-focused-bg-color, #fbf9b0)}.ae-picker-options .ae-picker-item:hover{background-color:var(--ae-picker-option-hover-bg-color, #fffa98)}.ae-expanded{display:block;margin-top:-1px;z-index:1}.ae-expanded .ae-picker-label{color:#ccc;z-index:2}.ae-expanded .ae-picker-label svg{color:#ccc;z-index:2}.ae-expanded .ae-picker-label svg .ae-stroke{stroke:#ccc}.ae-expanded .ae-picker-options{display:flex;flex-direction:column;margin-top:-1px;top:100%;z-index:3;border-color:#ccc}\n"] }]
680
- }], propDecorators: { options: [{
681
- type: Input
682
- }], isHidden: [{
683
- type: Input,
684
- args: ['hidden']
685
- }], hidden: [{
686
- type: HostBinding,
687
- args: ['style.display']
688
- }], changeEvent: [{
689
- type: Output,
690
- args: ['change']
691
- }], labelButton: [{
692
- type: ViewChild,
693
- args: ['labelButton', { static: true }]
694
- }], onClick: [{
695
- type: HostListener,
696
- args: ['document:click', ['$event']]
697
- }], handleKeyDown: [{
698
- type: HostListener,
699
- args: ['keydown', ['$event']]
700
- }] } });
701
-
702
- class AeButtonComponent {
703
- iconName = '';
704
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: AeButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
705
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.7", type: AeButtonComponent, isStandalone: false, selector: "ae-button, button[aeButton]", inputs: { iconName: "iconName" }, host: { properties: { "attr.tabIndex": "-1", "attr.type": "\"button\"" }, classAttribute: "angular-editor-button" }, ngImport: i0, template: "@if (iconName) {\n <svg>\n <use [attr.href]=\"'assets/ae-icons/icons.svg#' + iconName\" [attr.xlink:href]=\"'assets/ae-icons/icons.svg#' + iconName\"></use>\n </svg>\n} @else {\n <ng-content></ng-content>\n}\n", styles: ["a{cursor:pointer}:host.angular-editor-button{background-color:var(--ae-button-bg-color, white);vertical-align:middle;border:var(--ae-button-border, 1px solid #ddd);border-radius:var(--ae-button-radius, 4px);padding:.4rem;float:left;width:2rem;height:2rem}:host.angular-editor-button svg{width:100%;height:100%}:host.angular-editor-button:hover{cursor:pointer;background-color:var(--ae-button-hover-bg-color, #f1f1f1);transition:.2s ease}:host.angular-editor-button:focus,:host.angular-editor-button.focus{outline:0}:host.angular-editor-button:disabled{background-color:var(--ae-button-disabled-bg-color, #f5f5f5);pointer-events:none;cursor:not-allowed}:host.angular-editor-button:disabled>.color-label{pointer-events:none;cursor:not-allowed}:host.angular-editor-button:disabled>.color-label.foreground :after{background:#555}:host.angular-editor-button:disabled>.color-label.background{background:#555}:host.angular-editor-button.active{background:var(--ae-button-active-bg-color, #fffbd3)}:host.angular-editor-button.active:hover{background-color:var(--ae-button-active-hover-bg-color, #fffaad)}\n"] });
706
- }
707
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: AeButtonComponent, decorators: [{
708
- type: Component,
709
- args: [{ selector: 'ae-button, button[aeButton]', host: {
710
- 'class': 'angular-editor-button',
711
- '[attr.tabIndex]': '-1',
712
- '[attr.type]': '"button"',
713
- }, standalone: false, template: "@if (iconName) {\n <svg>\n <use [attr.href]=\"'assets/ae-icons/icons.svg#' + iconName\" [attr.xlink:href]=\"'assets/ae-icons/icons.svg#' + iconName\"></use>\n </svg>\n} @else {\n <ng-content></ng-content>\n}\n", styles: ["a{cursor:pointer}:host.angular-editor-button{background-color:var(--ae-button-bg-color, white);vertical-align:middle;border:var(--ae-button-border, 1px solid #ddd);border-radius:var(--ae-button-radius, 4px);padding:.4rem;float:left;width:2rem;height:2rem}:host.angular-editor-button svg{width:100%;height:100%}:host.angular-editor-button:hover{cursor:pointer;background-color:var(--ae-button-hover-bg-color, #f1f1f1);transition:.2s ease}:host.angular-editor-button:focus,:host.angular-editor-button.focus{outline:0}:host.angular-editor-button:disabled{background-color:var(--ae-button-disabled-bg-color, #f5f5f5);pointer-events:none;cursor:not-allowed}:host.angular-editor-button:disabled>.color-label{pointer-events:none;cursor:not-allowed}:host.angular-editor-button:disabled>.color-label.foreground :after{background:#555}:host.angular-editor-button:disabled>.color-label.background{background:#555}:host.angular-editor-button.active{background:var(--ae-button-active-bg-color, #fffbd3)}:host.angular-editor-button.active:hover{background-color:var(--ae-button-active-hover-bg-color, #fffaad)}\n"] }]
714
- }], propDecorators: { iconName: [{
715
- type: Input
716
- }] } });
717
-
718
- class AeToolbarSetComponent {
719
- constructor() {
720
- }
721
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: AeToolbarSetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
722
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.0.7", type: AeToolbarSetComponent, isStandalone: false, selector: "ae-toolbar-set, [aeToolbarSet]", host: { classAttribute: "angular-editor-toolbar-set" }, ngImport: i0, template: "<ng-content></ng-content>\n", styles: ["a{cursor:pointer}:host.angular-editor-toolbar-set{display:flex;gap:1px;width:fit-content;vertical-align:baseline}\n"] });
723
- }
724
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: AeToolbarSetComponent, decorators: [{
725
- type: Component,
726
- args: [{ selector: 'ae-toolbar-set, [aeToolbarSet]', host: {
727
- 'class': 'angular-editor-toolbar-set'
728
- }, standalone: false, template: "<ng-content></ng-content>\n", styles: ["a{cursor:pointer}:host.angular-editor-toolbar-set{display:flex;gap:1px;width:fit-content;vertical-align:baseline}\n"] }]
729
- }], ctorParameters: () => [] });
730
-
731
- class AeToolbarComponent {
732
- htmlMode = false;
733
- linkSelected = false;
734
- block = 'default';
735
- fontName = 'Times New Roman';
736
- fontSize = '3';
737
- foreColour = '';
738
- backColor = '';
739
- headings = [
740
- {
741
- label: 'Heading 1',
742
- value: 'h1',
743
- },
744
- {
745
- label: 'Heading 2',
746
- value: 'h2',
747
- },
748
- {
749
- label: 'Heading 3',
750
- value: 'h3',
751
- },
752
- {
753
- label: 'Heading 4',
754
- value: 'h4',
755
- },
756
- {
757
- label: 'Heading 5',
758
- value: 'h5',
759
- },
760
- {
761
- label: 'Heading 6',
762
- value: 'h6',
763
- },
764
- {
765
- label: 'Paragraph',
766
- value: 'p',
767
- },
768
- {
769
- label: 'Predefined',
770
- value: 'pre'
771
- },
772
- {
773
- label: 'Standard',
774
- value: 'div'
775
- },
776
- {
777
- label: 'default',
778
- value: 'default'
779
- }
780
- ];
781
- fontSizes = [
782
- {
783
- label: '1',
784
- value: '1',
785
- },
786
- {
787
- label: '2',
788
- value: '2',
789
- },
790
- {
791
- label: '3',
792
- value: '3',
793
- },
794
- {
795
- label: '4',
796
- value: '4',
797
- },
798
- {
799
- label: '5',
800
- value: '5',
801
- },
802
- {
803
- label: '6',
804
- value: '6',
805
- },
806
- {
807
- label: '7',
808
- value: '7',
809
- }
810
- ];
811
- customClassId = '-1';
812
- _customClasses = [];
813
- customClassList = [{ label: '', value: '' }];
814
- tagMap = {
815
- BLOCKQUOTE: 'indent',
816
- A: 'link'
817
- };
818
- select = ['H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'P', 'PRE', 'DIV'];
819
- buttons = ['bold', 'italic', 'underline', 'strikeThrough', 'subscript', 'superscript', 'justifyLeft', 'justifyCenter',
820
- 'justifyRight', 'justifyFull', 'indent', 'outdent', 'insertUnorderedList', 'insertOrderedList', 'link'];
821
- id = '';
822
- uploadUrl = '';
823
- upload;
824
- showToolbar = false;
825
- fonts = [{ label: '', value: '' }];
826
- set customClasses(classes) {
827
- if (classes) {
828
- this._customClasses = classes;
829
- this.customClassList = this._customClasses.map((x, i) => ({ label: x.name, value: i.toString() }));
830
- this.customClassList.unshift({ label: 'Clear Class', value: '-1' });
831
- }
832
- }
833
- set defaultFontName(value) {
834
- if (value) {
835
- this.fontName = value;
836
- }
837
- }
838
- set defaultFontSize(value) {
839
- if (value) {
840
- this.fontSize = value;
841
- }
842
- }
843
- hiddenButtons = [];
844
- execute = new EventEmitter();
845
- myInputFile;
846
- get isLinkButtonDisabled() {
847
- return this.htmlMode || !this.editorService.selectedText;
848
- }
849
- r = inject(Renderer2);
850
- editorService = inject(AngularEditorService);
851
- er = inject(ElementRef);
852
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
853
- doc = inject(DOCUMENT);
854
- /**
855
- * Trigger command from editor header buttons
856
- * @param command string from toolbar buttons
857
- */
858
- triggerCommand(command) {
859
- this.execute.emit(command);
860
- }
861
- /**
862
- * highlight editor buttons when cursor moved or positioning
863
- */
864
- triggerButtons() {
865
- if (!this.showToolbar) {
866
- return;
867
- }
868
- this.buttons.forEach(e => {
869
- const result = this.doc.queryCommandState(e);
870
- const elementById = this.doc.getElementById(e + '-' + this.id);
871
- if (result) {
872
- this.r.addClass(elementById, 'active');
873
- }
874
- else {
875
- this.r.removeClass(elementById, 'active');
876
- }
877
- });
878
- }
879
- /**
880
- * trigger highlight editor buttons when cursor moved or positioning in block
881
- */
882
- triggerBlocks(nodes) {
883
- if (!this.showToolbar) {
884
- return;
885
- }
886
- this.linkSelected = nodes.findIndex(x => x.nodeName === 'A') > -1;
887
- let found = false;
888
- this.select.forEach(y => {
889
- const node = nodes.find(x => x.nodeName === y);
890
- if (node !== undefined && y === node.nodeName) {
891
- if (found === false) {
892
- this.block = node.nodeName.toLowerCase();
893
- found = true;
894
- }
895
- }
896
- else if (found === false) {
897
- this.block = 'default';
898
- }
899
- });
900
- found = false;
901
- if (this._customClasses) {
902
- this._customClasses.forEach((y, index) => {
903
- const node = nodes.find(x => {
904
- if (x instanceof Element) {
905
- return x.className === y.class;
906
- }
907
- return false;
908
- });
909
- if (node !== undefined) {
910
- if (found === false) {
911
- this.customClassId = index.toString();
912
- found = true;
913
- }
914
- }
915
- else if (found === false) {
916
- this.customClassId = '-1';
917
- }
918
- });
919
- }
920
- Object.keys(this.tagMap).map(e => {
921
- const elementById = this.doc.getElementById(this.tagMap[e] + '-' + this.id);
922
- const node = nodes.find(x => x.nodeName === e);
923
- if (node !== undefined && e === node.nodeName) {
924
- this.r.addClass(elementById, 'active');
925
- }
926
- else {
927
- this.r.removeClass(elementById, 'active');
928
- }
929
- });
930
- this.foreColour = this.doc.queryCommandValue('ForeColor');
931
- this.fontSize = this.doc.queryCommandValue('FontSize');
932
- this.fontName = this.doc.queryCommandValue('FontName').replace(/"/g, '');
933
- this.backColor = this.doc.queryCommandValue('backColor');
934
- }
935
- /**
936
- * insert URL link
937
- */
938
- insertUrl() {
939
- let url = 'https://';
940
- const selection = this.editorService.savedSelection;
941
- if (selection && selection.commonAncestorContainer.parentElement?.nodeName === 'A') {
942
- const parent = selection.commonAncestorContainer.parentElement;
943
- // Use getAttribute to preserve relative URLs instead of href which returns absolute URL
944
- const href = parent.getAttribute('href');
945
- if (href !== '' && href !== null) {
946
- url = href;
947
- }
948
- }
949
- const promptUrl = prompt('Insert URL link', url);
950
- if (promptUrl && promptUrl !== '' && promptUrl !== 'https://') {
951
- this.editorService.createLink(promptUrl);
952
- }
953
- }
954
- /**
955
- * insert Video link
956
- */
957
- insertVideo() {
958
- this.execute.emit('');
959
- const url = prompt('Insert Video link', `https://`);
960
- if (url && url !== '' && url !== `https://`) {
961
- this.editorService.insertVideo(url);
962
- }
963
- }
964
- /** insert color */
965
- insertColor(color, where) {
966
- this.editorService.insertColor(color, where);
967
- this.execute.emit('');
968
- }
969
- /**
970
- * set font Name/family
971
- * @param foreColor string
972
- */
973
- setFontName(foreColor) {
974
- this.editorService.setFontName(foreColor);
975
- this.execute.emit('');
976
- }
977
- /**
978
- * set font Size
979
- * @param fontSize string
980
- */
981
- setFontSize(fontSize) {
982
- this.editorService.setFontSize(fontSize);
983
- this.execute.emit('');
984
- }
985
- /**
986
- * toggle editor mode (WYSIWYG or SOURCE)
987
- * @param m boolean
988
- */
989
- setEditorMode(m) {
990
- const toggleEditorModeButton = this.doc.getElementById('toggleEditorMode' + '-' + this.id);
991
- if (m) {
992
- this.r.addClass(toggleEditorModeButton, 'active');
993
- }
994
- else {
995
- this.r.removeClass(toggleEditorModeButton, 'active');
996
- }
997
- this.htmlMode = m;
998
- }
999
- /**
1000
- * Upload image when file is selected.
1001
- */
1002
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1003
- onFileChanged(event) {
1004
- const file = event.target.files[0];
1005
- if (file.type.includes('image/')) {
1006
- if (this.upload) {
1007
- this.upload(file).subscribe((response) => {
1008
- if (response instanceof HttpResponse) {
1009
- this.watchUploadImage(response, event);
1010
- }
1011
- });
1012
- }
1013
- else if (this.uploadUrl) {
1014
- this.editorService.uploadImage(file).subscribe((response) => {
1015
- if (response instanceof HttpResponse) {
1016
- this.watchUploadImage(response, event);
1017
- }
1018
- });
1019
- }
1020
- else {
1021
- const reader = new FileReader();
1022
- reader.onload = (e) => {
1023
- const fr = e.currentTarget;
1024
- if (fr.result !== null) {
1025
- this.editorService.insertImage(fr.result.toString());
1026
- }
1027
- // Reset input value to allow re-uploading the same file
1028
- event.target.value = null;
1029
- };
1030
- reader.readAsDataURL(file);
1031
- }
1032
- }
1033
- }
1034
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1035
- watchUploadImage(response, event) {
1036
- const body = response.body;
1037
- if (body) {
1038
- const { imageUrl } = body;
1039
- this.editorService.insertImage(imageUrl);
1040
- }
1041
- event.srcElement.value = null;
1042
- }
1043
- /**
1044
- * Set custom class
1045
- */
1046
- setCustomClass(classId) {
1047
- if (classId === '-1') {
1048
- this.execute.emit('clear');
1049
- }
1050
- else {
1051
- this.editorService.createCustomClass(this._customClasses[+classId]);
1052
- }
1053
- }
1054
- isButtonHidden(name) {
1055
- if (!name) {
1056
- return false;
1057
- }
1058
- if (!(this.hiddenButtons instanceof Array)) {
1059
- return false;
1060
- }
1061
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1062
- let result;
1063
- for (const arr of this.hiddenButtons) {
1064
- if (arr instanceof Array) {
1065
- result = arr.find(item => item === name);
1066
- }
1067
- if (result) {
1068
- break;
1069
- }
1070
- }
1071
- return result !== undefined;
1072
- }
1073
- focus() {
1074
- this.execute.emit('focus');
1075
- }
1076
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: AeToolbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1077
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.7", type: AeToolbarComponent, isStandalone: false, selector: "angular-editor-toolbar, ae-toolbar, div[aeToolbar]", inputs: { id: "id", uploadUrl: "uploadUrl", upload: "upload", showToolbar: "showToolbar", fonts: "fonts", customClasses: "customClasses", defaultFontName: "defaultFontName", defaultFontSize: "defaultFontSize", hiddenButtons: "hiddenButtons" }, outputs: { execute: "execute" }, viewQueries: [{ propertyName: "myInputFile", first: true, predicate: ["fileInput"], descendants: true }], ngImport: i0, template: "@if (showToolbar) {\n <div class=\"angular-editor-toolbar\">\n @if (!isButtonHidden('undo') || !isButtonHidden('redo')) {\n <div aeToolbarSet>\n @if (!isButtonHidden('undo')) {\n <button aeButton title=\"Undo\" iconName=\"undo\" (click)=\"triggerCommand('undo')\">\n </button>\n }\n @if (!isButtonHidden('redo')) {\n <button aeButton title=\"Redo\" iconName=\"redo\" (click)=\"triggerCommand('redo')\">\n </button>\n }\n </div>\n }\n @if (!isButtonHidden('bold') || !isButtonHidden('italic') || !isButtonHidden('underline') || !isButtonHidden('strikeThrough') || !isButtonHidden('subscript') || !isButtonHidden('superscript')) {\n <div aeToolbarSet>\n @if (!isButtonHidden('bold')) {\n <button [id]=\"'bold-'+id\" aeButton title=\"Bold\" iconName=\"bold\" (click)=\"triggerCommand('bold')\"\n [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('italic')) {\n <button [id]=\"'italic-'+id\" aeButton iconName=\"italic\" title=\"Italic\" (click)=\"triggerCommand('italic')\"\n [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('underline')) {\n <button [id]=\"'underline-'+id\" aeButton title=\"Underline\" iconName=\"underline\"\n (click)=\"triggerCommand('underline')\" [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('strikeThrough')) {\n <button [id]=\"'strikeThrough-'+id\" aeButton iconName=\"strikeThrough\" title=\"Strikethrough\"\n (click)=\"triggerCommand('strikeThrough')\" [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('subscript')) {\n <button [id]=\"'subscript-'+id\" aeButton title=\"Subscript\" iconName=\"subscript\"\n (click)=\"triggerCommand('subscript')\" [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('superscript')) {\n <button [id]=\"'superscript-'+id\" aeButton iconName=\"superscript\" title=\"Superscript\"\n (click)=\"triggerCommand('superscript')\" [disabled]=\"htmlMode\">\n </button>\n }\n </div>\n }\n @if (!isButtonHidden('justifyLeft') || !isButtonHidden('justifyCenter') || !isButtonHidden('justifyRight') || !isButtonHidden('justifyFull')) {\n <div aeToolbarSet>\n @if (!isButtonHidden('justifyLeft')) {\n <button [id]=\"'justifyLeft-'+id\" aeButton iconName=\"justifyLeft\" title=\"Justify Left\"\n (click)=\"triggerCommand('justifyLeft')\" [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('justifyCenter')) {\n <button [id]=\"'justifyCenter-'+id\" aeButton iconName=\"justifyCenter\" title=\"Justify Center\"\n (click)=\"triggerCommand('justifyCenter')\" [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('justifyRight')) {\n <button [id]=\"'justifyRight-'+id\" aeButton iconName=\"justifyRight\" title=\"Justify Right\"\n (click)=\"triggerCommand('justifyRight')\" [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('justifyFull')) {\n <button [id]=\"'justifyFull-'+id\" aeButton iconName=\"justifyFull\" title=\"Justify Full\"\n (click)=\"triggerCommand('justifyFull')\" [disabled]=\"htmlMode\">\n </button>\n }\n </div>\n }\n @if (!isButtonHidden('indent') || !isButtonHidden('outdent')) {\n <div aeToolbarSet>\n @if (!isButtonHidden('indent')) {\n <button [id]=\"'indent-'+id\" aeButton iconName=\"indent\" title=\"Indent\"\n (click)=\"triggerCommand('indent')\"\n [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('outdent')) {\n <button [id]=\"'outdent-'+id\" aeButton iconName=\"outdent\" title=\"Outdent\"\n (click)=\"triggerCommand('outdent')\"\n [disabled]=\"htmlMode\">\n </button>\n }\n </div>\n }\n @if (!isButtonHidden('insertUnorderedList') || !isButtonHidden('insertOrderedList')) {\n <div aeToolbarSet>\n @if (!isButtonHidden('insertUnorderedList')) {\n <button [id]=\"'insertUnorderedList-'+id\" aeButton iconName=\"unorderedList\" title=\"Unordered List\"\n (click)=\"triggerCommand('insertUnorderedList')\" [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('insertOrderedList')) {\n <button [id]=\"'insertOrderedList-'+id\" aeButton iconName=\"orderedList\" title=\"Ordered List\"\n (click)=\"triggerCommand('insertOrderedList')\" [disabled]=\"htmlMode\">\n </button>\n }\n </div>\n }\n @if (!isButtonHidden('heading')) {\n <div aeToolbarSet>\n <ae-select class=\"select-heading\" [options]=\"headings\"\n [(ngModel)]=\"block\"\n (change)=\"triggerCommand(block)\"\n [disabled]=\"htmlMode\"\n tabindex=\"-1\"></ae-select>\n </div>\n }\n @if (!isButtonHidden('fontName')) {\n <div aeToolbarSet>\n <ae-select class=\"select-font\" [options]=\"fonts\"\n [(ngModel)]=\"fontName\"\n (change)=\"setFontName(fontName)\"\n [disabled]=\"htmlMode\"\n tabindex=\"-1\"></ae-select>\n </div>\n }\n @if (!isButtonHidden('fontSize')) {\n <div aeToolbarSet>\n <ae-select class=\"select-font-size\" [options]=\"fontSizes\"\n [(ngModel)]=\"fontSize\"\n (change)=\"setFontSize(fontSize)\"\n [disabled]=\"htmlMode\"\n tabindex=\"-1\">\n </ae-select>\n </div>\n }\n @if (!isButtonHidden('textColor') || !isButtonHidden('backgroundColor')) {\n <div aeToolbarSet>\n @if (!isButtonHidden('textColor')) {\n <input\n style=\"display: none\"\n type=\"color\" (change)=\"insertColor(fgInput.value, 'textColor')\"\n #fgInput>\n <button [id]=\"'foregroundColorPicker-'+id\" aeButton iconName=\"textColor\"\n (click)=\"focus(); fgInput.click()\"\n title=\"Text Color\"\n [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('backgroundColor')) {\n <input\n style=\"display: none\"\n type=\"color\" (change)=\"insertColor(bgInput.value, 'backgroundColor')\"\n #bgInput>\n <button [id]=\"'backgroundColorPicker-'+id\" aeButton iconName=\"backgroundColor\"\n (click)=\"focus(); bgInput.click()\"\n title=\"Background Color\"\n [disabled]=\"htmlMode\">\n </button>\n }\n </div>\n }\n @if (_customClasses && !isButtonHidden('customClasses')) {\n <div aeToolbarSet>\n <ae-select class=\"select-custom-style\" [options]=\"customClassList\"\n [(ngModel)]=\"customClassId\"\n (change)=\"setCustomClass(customClassId)\"\n [disabled]=\"htmlMode\"\n tabindex=\"-1\"></ae-select>\n </div>\n }\n @if (!isButtonHidden('link') || !isButtonHidden('unlink') || !isButtonHidden('insertImage') || !isButtonHidden('insertVideo') || !isButtonHidden('insertHorizontalRule')) {\n <div aeToolbarSet>\n @if (!isButtonHidden('link')) {\n <button [id]=\"'link-'+id\" aeButton iconName=\"link\" (click)=\"insertUrl()\"\n title=\"Insert Link\" [disabled]=\"isLinkButtonDisabled\">\n </button>\n }\n @if (!isButtonHidden('unlink')) {\n <button [id]=\"'unlink-'+id\" aeButton iconName=\"unlink\" (click)=\"triggerCommand('unlink')\"\n title=\"Unlink\" [disabled]=\"htmlMode || !linkSelected\">\n </button>\n }\n @if (!isButtonHidden('insertImage')) {\n <input\n style=\"display: none\"\n accept=\"image/*\"\n type=\"file\" (change)=\"onFileChanged($event)\"\n #fileInput>\n <button [id]=\"'insertImage-'+id\" aeButton iconName=\"image\" (click)=\"focus(); fileInput.click()\"\n title=\"Insert Image\"\n [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('insertVideo')) {\n <button [id]=\"'insertVideo-'+id\" aeButton iconName=\"video\"\n (click)=\"insertVideo()\" title=\"Insert Video\" [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('insertHorizontalRule')) {\n <button [id]=\"'insertHorizontalRule-'+id\" aeButton iconName=\"horizontalLine\" title=\"Horizontal Line\"\n (click)=\"triggerCommand('insertHorizontalRule')\" [disabled]=\"htmlMode\">\n </button>\n }\n </div>\n }\n @if (!isButtonHidden('removeFormat')) {\n <div aeToolbarSet>\n <button [id]=\"'clearFormatting-'+id\" aeButton iconName=\"removeFormat\" title=\"Clear Formatting\"\n class=\"angular-editor-button\"\n (click)=\"triggerCommand('removeFormat')\" [disabled]=\"htmlMode\">\n </button>\n </div>\n }\n @if (!isButtonHidden('toggleEditorMode')) {\n <div aeToolbarSet>\n <button [id]=\"'toggleEditorMode-'+id\" aeButton iconName=\"htmlCode\" title=\"HTML Code\"\n (click)=\"triggerCommand('toggleEditorMode')\">\n </button>\n </div>\n }\n <ng-content></ng-content>\n </div>\n}\n", styles: ["a{cursor:pointer}.angular-editor-toolbar{font:100 14px/15px Roboto,Arial,sans-serif;background-color:var(--ae-toolbar-bg-color, #f5f5f5);font-size:.8rem;padding:var(--ae-toolbar-padding, .2rem);border:var(--ae-toolbar-border-radius, 1px solid #ddd);display:flex;flex-wrap:wrap;gap:4px}.select-heading{display:inline-block;width:90px}@supports not (-moz-appearance: none){.select-heading optgroup{font-size:12px;background-color:#f4f4f4;padding:5px}.select-heading option{border:1px solid;background-color:#fff}}.select-heading:disabled{background-color:#f5f5f5;pointer-events:none;cursor:not-allowed}.select-heading:hover{cursor:pointer;background-color:#f1f1f1;transition:.2s ease}.select-font{display:inline-block;width:90px}@supports not (-moz-appearance: none){.select-font optgroup{font-size:12px;background-color:#f4f4f4;padding:5px}.select-font option{border:1px solid;background-color:#fff}}.select-font:disabled{background-color:#f5f5f5;pointer-events:none;cursor:not-allowed}.select-font:hover{cursor:pointer;background-color:#f1f1f1;transition:.2s ease}.select-font-size{display:inline-block;width:50px}@supports not (-moz-appearance: none){.select-font-size optgroup{font-size:12px;background-color:#f4f4f4;padding:5px}.select-font-size option{border:1px solid;background-color:#fff}.select-font-size .size1{font-size:10px}.select-font-size .size2{font-size:12px}.select-font-size .size3{font-size:14px}.select-font-size .size4{font-size:16px}.select-font-size .size5{font-size:18px}.select-font-size .size6{font-size:20px}.select-font-size .size7{font-size:22px}}.select-font-size:disabled{background-color:#f5f5f5;pointer-events:none;cursor:not-allowed}.select-font-size:hover{cursor:pointer;background-color:#f1f1f1;transition:.2s ease}.select-custom-style{display:inline-block;width:90px}@supports not (-moz-appearance: none){.select-custom-style optgroup{font-size:12px;background-color:#f4f4f4;padding:5px}.select-custom-style option{border:1px solid;background-color:#fff}}.select-custom-style:disabled{background-color:#f5f5f5;pointer-events:none;cursor:not-allowed}.select-custom-style:hover{cursor:pointer;background-color:#f1f1f1;transition:.2s ease}.color-label{position:relative;cursor:pointer}.background{font-size:smaller;background:#1b1b1b;color:#fff;padding:3px}.foreground :after{position:absolute;content:\"\";inset:auto auto -3px -1px;width:15px;height:2px;z-index:0;background:#1b1b1b}.default{font-size:16px}h1{font-size:24px}h2{font-size:20px}h3{font-size:16px}h4{font-size:15px}h5{font-size:14px}h6{font-size:13px}div,pre{font-size:12px}\n"], dependencies: [{ kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: AeSelectComponent, selector: "ae-select", inputs: ["options", "hidden"], outputs: ["change"] }, { kind: "component", type: AeButtonComponent, selector: "ae-button, button[aeButton]", inputs: ["iconName"] }, { kind: "component", type: AeToolbarSetComponent, selector: "ae-toolbar-set, [aeToolbarSet]" }] });
1078
- }
1079
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: AeToolbarComponent, decorators: [{
1080
- type: Component,
1081
- args: [{ selector: 'angular-editor-toolbar, ae-toolbar, div[aeToolbar]', standalone: false, template: "@if (showToolbar) {\n <div class=\"angular-editor-toolbar\">\n @if (!isButtonHidden('undo') || !isButtonHidden('redo')) {\n <div aeToolbarSet>\n @if (!isButtonHidden('undo')) {\n <button aeButton title=\"Undo\" iconName=\"undo\" (click)=\"triggerCommand('undo')\">\n </button>\n }\n @if (!isButtonHidden('redo')) {\n <button aeButton title=\"Redo\" iconName=\"redo\" (click)=\"triggerCommand('redo')\">\n </button>\n }\n </div>\n }\n @if (!isButtonHidden('bold') || !isButtonHidden('italic') || !isButtonHidden('underline') || !isButtonHidden('strikeThrough') || !isButtonHidden('subscript') || !isButtonHidden('superscript')) {\n <div aeToolbarSet>\n @if (!isButtonHidden('bold')) {\n <button [id]=\"'bold-'+id\" aeButton title=\"Bold\" iconName=\"bold\" (click)=\"triggerCommand('bold')\"\n [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('italic')) {\n <button [id]=\"'italic-'+id\" aeButton iconName=\"italic\" title=\"Italic\" (click)=\"triggerCommand('italic')\"\n [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('underline')) {\n <button [id]=\"'underline-'+id\" aeButton title=\"Underline\" iconName=\"underline\"\n (click)=\"triggerCommand('underline')\" [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('strikeThrough')) {\n <button [id]=\"'strikeThrough-'+id\" aeButton iconName=\"strikeThrough\" title=\"Strikethrough\"\n (click)=\"triggerCommand('strikeThrough')\" [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('subscript')) {\n <button [id]=\"'subscript-'+id\" aeButton title=\"Subscript\" iconName=\"subscript\"\n (click)=\"triggerCommand('subscript')\" [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('superscript')) {\n <button [id]=\"'superscript-'+id\" aeButton iconName=\"superscript\" title=\"Superscript\"\n (click)=\"triggerCommand('superscript')\" [disabled]=\"htmlMode\">\n </button>\n }\n </div>\n }\n @if (!isButtonHidden('justifyLeft') || !isButtonHidden('justifyCenter') || !isButtonHidden('justifyRight') || !isButtonHidden('justifyFull')) {\n <div aeToolbarSet>\n @if (!isButtonHidden('justifyLeft')) {\n <button [id]=\"'justifyLeft-'+id\" aeButton iconName=\"justifyLeft\" title=\"Justify Left\"\n (click)=\"triggerCommand('justifyLeft')\" [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('justifyCenter')) {\n <button [id]=\"'justifyCenter-'+id\" aeButton iconName=\"justifyCenter\" title=\"Justify Center\"\n (click)=\"triggerCommand('justifyCenter')\" [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('justifyRight')) {\n <button [id]=\"'justifyRight-'+id\" aeButton iconName=\"justifyRight\" title=\"Justify Right\"\n (click)=\"triggerCommand('justifyRight')\" [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('justifyFull')) {\n <button [id]=\"'justifyFull-'+id\" aeButton iconName=\"justifyFull\" title=\"Justify Full\"\n (click)=\"triggerCommand('justifyFull')\" [disabled]=\"htmlMode\">\n </button>\n }\n </div>\n }\n @if (!isButtonHidden('indent') || !isButtonHidden('outdent')) {\n <div aeToolbarSet>\n @if (!isButtonHidden('indent')) {\n <button [id]=\"'indent-'+id\" aeButton iconName=\"indent\" title=\"Indent\"\n (click)=\"triggerCommand('indent')\"\n [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('outdent')) {\n <button [id]=\"'outdent-'+id\" aeButton iconName=\"outdent\" title=\"Outdent\"\n (click)=\"triggerCommand('outdent')\"\n [disabled]=\"htmlMode\">\n </button>\n }\n </div>\n }\n @if (!isButtonHidden('insertUnorderedList') || !isButtonHidden('insertOrderedList')) {\n <div aeToolbarSet>\n @if (!isButtonHidden('insertUnorderedList')) {\n <button [id]=\"'insertUnorderedList-'+id\" aeButton iconName=\"unorderedList\" title=\"Unordered List\"\n (click)=\"triggerCommand('insertUnorderedList')\" [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('insertOrderedList')) {\n <button [id]=\"'insertOrderedList-'+id\" aeButton iconName=\"orderedList\" title=\"Ordered List\"\n (click)=\"triggerCommand('insertOrderedList')\" [disabled]=\"htmlMode\">\n </button>\n }\n </div>\n }\n @if (!isButtonHidden('heading')) {\n <div aeToolbarSet>\n <ae-select class=\"select-heading\" [options]=\"headings\"\n [(ngModel)]=\"block\"\n (change)=\"triggerCommand(block)\"\n [disabled]=\"htmlMode\"\n tabindex=\"-1\"></ae-select>\n </div>\n }\n @if (!isButtonHidden('fontName')) {\n <div aeToolbarSet>\n <ae-select class=\"select-font\" [options]=\"fonts\"\n [(ngModel)]=\"fontName\"\n (change)=\"setFontName(fontName)\"\n [disabled]=\"htmlMode\"\n tabindex=\"-1\"></ae-select>\n </div>\n }\n @if (!isButtonHidden('fontSize')) {\n <div aeToolbarSet>\n <ae-select class=\"select-font-size\" [options]=\"fontSizes\"\n [(ngModel)]=\"fontSize\"\n (change)=\"setFontSize(fontSize)\"\n [disabled]=\"htmlMode\"\n tabindex=\"-1\">\n </ae-select>\n </div>\n }\n @if (!isButtonHidden('textColor') || !isButtonHidden('backgroundColor')) {\n <div aeToolbarSet>\n @if (!isButtonHidden('textColor')) {\n <input\n style=\"display: none\"\n type=\"color\" (change)=\"insertColor(fgInput.value, 'textColor')\"\n #fgInput>\n <button [id]=\"'foregroundColorPicker-'+id\" aeButton iconName=\"textColor\"\n (click)=\"focus(); fgInput.click()\"\n title=\"Text Color\"\n [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('backgroundColor')) {\n <input\n style=\"display: none\"\n type=\"color\" (change)=\"insertColor(bgInput.value, 'backgroundColor')\"\n #bgInput>\n <button [id]=\"'backgroundColorPicker-'+id\" aeButton iconName=\"backgroundColor\"\n (click)=\"focus(); bgInput.click()\"\n title=\"Background Color\"\n [disabled]=\"htmlMode\">\n </button>\n }\n </div>\n }\n @if (_customClasses && !isButtonHidden('customClasses')) {\n <div aeToolbarSet>\n <ae-select class=\"select-custom-style\" [options]=\"customClassList\"\n [(ngModel)]=\"customClassId\"\n (change)=\"setCustomClass(customClassId)\"\n [disabled]=\"htmlMode\"\n tabindex=\"-1\"></ae-select>\n </div>\n }\n @if (!isButtonHidden('link') || !isButtonHidden('unlink') || !isButtonHidden('insertImage') || !isButtonHidden('insertVideo') || !isButtonHidden('insertHorizontalRule')) {\n <div aeToolbarSet>\n @if (!isButtonHidden('link')) {\n <button [id]=\"'link-'+id\" aeButton iconName=\"link\" (click)=\"insertUrl()\"\n title=\"Insert Link\" [disabled]=\"isLinkButtonDisabled\">\n </button>\n }\n @if (!isButtonHidden('unlink')) {\n <button [id]=\"'unlink-'+id\" aeButton iconName=\"unlink\" (click)=\"triggerCommand('unlink')\"\n title=\"Unlink\" [disabled]=\"htmlMode || !linkSelected\">\n </button>\n }\n @if (!isButtonHidden('insertImage')) {\n <input\n style=\"display: none\"\n accept=\"image/*\"\n type=\"file\" (change)=\"onFileChanged($event)\"\n #fileInput>\n <button [id]=\"'insertImage-'+id\" aeButton iconName=\"image\" (click)=\"focus(); fileInput.click()\"\n title=\"Insert Image\"\n [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('insertVideo')) {\n <button [id]=\"'insertVideo-'+id\" aeButton iconName=\"video\"\n (click)=\"insertVideo()\" title=\"Insert Video\" [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('insertHorizontalRule')) {\n <button [id]=\"'insertHorizontalRule-'+id\" aeButton iconName=\"horizontalLine\" title=\"Horizontal Line\"\n (click)=\"triggerCommand('insertHorizontalRule')\" [disabled]=\"htmlMode\">\n </button>\n }\n </div>\n }\n @if (!isButtonHidden('removeFormat')) {\n <div aeToolbarSet>\n <button [id]=\"'clearFormatting-'+id\" aeButton iconName=\"removeFormat\" title=\"Clear Formatting\"\n class=\"angular-editor-button\"\n (click)=\"triggerCommand('removeFormat')\" [disabled]=\"htmlMode\">\n </button>\n </div>\n }\n @if (!isButtonHidden('toggleEditorMode')) {\n <div aeToolbarSet>\n <button [id]=\"'toggleEditorMode-'+id\" aeButton iconName=\"htmlCode\" title=\"HTML Code\"\n (click)=\"triggerCommand('toggleEditorMode')\">\n </button>\n </div>\n }\n <ng-content></ng-content>\n </div>\n}\n", styles: ["a{cursor:pointer}.angular-editor-toolbar{font:100 14px/15px Roboto,Arial,sans-serif;background-color:var(--ae-toolbar-bg-color, #f5f5f5);font-size:.8rem;padding:var(--ae-toolbar-padding, .2rem);border:var(--ae-toolbar-border-radius, 1px solid #ddd);display:flex;flex-wrap:wrap;gap:4px}.select-heading{display:inline-block;width:90px}@supports not (-moz-appearance: none){.select-heading optgroup{font-size:12px;background-color:#f4f4f4;padding:5px}.select-heading option{border:1px solid;background-color:#fff}}.select-heading:disabled{background-color:#f5f5f5;pointer-events:none;cursor:not-allowed}.select-heading:hover{cursor:pointer;background-color:#f1f1f1;transition:.2s ease}.select-font{display:inline-block;width:90px}@supports not (-moz-appearance: none){.select-font optgroup{font-size:12px;background-color:#f4f4f4;padding:5px}.select-font option{border:1px solid;background-color:#fff}}.select-font:disabled{background-color:#f5f5f5;pointer-events:none;cursor:not-allowed}.select-font:hover{cursor:pointer;background-color:#f1f1f1;transition:.2s ease}.select-font-size{display:inline-block;width:50px}@supports not (-moz-appearance: none){.select-font-size optgroup{font-size:12px;background-color:#f4f4f4;padding:5px}.select-font-size option{border:1px solid;background-color:#fff}.select-font-size .size1{font-size:10px}.select-font-size .size2{font-size:12px}.select-font-size .size3{font-size:14px}.select-font-size .size4{font-size:16px}.select-font-size .size5{font-size:18px}.select-font-size .size6{font-size:20px}.select-font-size .size7{font-size:22px}}.select-font-size:disabled{background-color:#f5f5f5;pointer-events:none;cursor:not-allowed}.select-font-size:hover{cursor:pointer;background-color:#f1f1f1;transition:.2s ease}.select-custom-style{display:inline-block;width:90px}@supports not (-moz-appearance: none){.select-custom-style optgroup{font-size:12px;background-color:#f4f4f4;padding:5px}.select-custom-style option{border:1px solid;background-color:#fff}}.select-custom-style:disabled{background-color:#f5f5f5;pointer-events:none;cursor:not-allowed}.select-custom-style:hover{cursor:pointer;background-color:#f1f1f1;transition:.2s ease}.color-label{position:relative;cursor:pointer}.background{font-size:smaller;background:#1b1b1b;color:#fff;padding:3px}.foreground :after{position:absolute;content:\"\";inset:auto auto -3px -1px;width:15px;height:2px;z-index:0;background:#1b1b1b}.default{font-size:16px}h1{font-size:24px}h2{font-size:20px}h3{font-size:16px}h4{font-size:15px}h5{font-size:14px}h6{font-size:13px}div,pre{font-size:12px}\n"] }]
1082
- }], propDecorators: { id: [{
1083
- type: Input
1084
- }], uploadUrl: [{
1085
- type: Input
1086
- }], upload: [{
1087
- type: Input
1088
- }], showToolbar: [{
1089
- type: Input
1090
- }], fonts: [{
1091
- type: Input
1092
- }], customClasses: [{
1093
- type: Input
1094
- }], defaultFontName: [{
1095
- type: Input
1096
- }], defaultFontSize: [{
1097
- type: Input
1098
- }], hiddenButtons: [{
1099
- type: Input
1100
- }], execute: [{
1101
- type: Output
1102
- }], myInputFile: [{
1103
- type: ViewChild,
1104
- args: ['fileInput', { static: false }]
1105
- }] } });
1106
-
1107
- class AngularEditorComponent {
1108
- autoFocus;
1109
- onChange;
1110
- onTouched;
1111
- modeVisual = true;
1112
- showPlaceholder = false;
1113
- disabled = false;
1114
- focused = false;
1115
- touched = false;
1116
- changed = false;
1117
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1118
- focusInstance;
1119
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1120
- blurInstance;
1121
- id = '';
1122
- config = angularEditorConfig;
1123
- placeholder = '';
1124
- tabIndex = null;
1125
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1126
- html = new EventEmitter();
1127
- textArea;
1128
- editorWrapper;
1129
- editorToolbar;
1130
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1131
- customButtonsTemplateRef;
1132
- executeCommandFn = this.executeCommand.bind(this);
1133
- viewMode = new EventEmitter();
1134
- /** emits `blur` event when focused out from the textarea */
1135
- // eslint-disable-next-line @angular-eslint/no-output-native, @angular-eslint/no-output-rename
1136
- blurEvent = new EventEmitter();
1137
- /** emits `focus` event when focused in to the textarea */
1138
- // eslint-disable-next-line @angular-eslint/no-output-rename, @angular-eslint/no-output-native
1139
- focusEvent = new EventEmitter();
1140
- tabindex = -1;
1141
- onFocus() {
1142
- this.focus();
1143
- }
1144
- r = inject(Renderer2);
1145
- editorService = inject(AngularEditorService);
1146
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1147
- doc = inject(DOCUMENT);
1148
- sanitizer = inject(DomSanitizer);
1149
- cdRef = inject(ChangeDetectorRef);
1150
- constructor(defaultTabIndex,
1151
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1152
- autoFocus) {
1153
- this.autoFocus = autoFocus;
1154
- const parsedTabIndex = Number(defaultTabIndex);
1155
- this.tabIndex = (parsedTabIndex || parsedTabIndex === 0) ? parsedTabIndex : null;
1156
- }
1157
- ngOnInit() {
1158
- this.config.toolbarPosition = this.config.toolbarPosition ? this.config.toolbarPosition : angularEditorConfig.toolbarPosition;
1159
- }
1160
- ngAfterViewInit() {
1161
- if (isDefined(this.autoFocus)) {
1162
- this.focus();
1163
- }
1164
- }
1165
- onPaste(event) {
1166
- if (this.config.rawPaste) {
1167
- event.preventDefault();
1168
- const text = event.clipboardData?.getData('text/plain') ?? '';
1169
- document.execCommand('insertHTML', false, text);
1170
- return text;
1171
- }
1172
- return undefined;
1173
- }
1174
- /**
1175
- * Executed command from editor header buttons
1176
- * @param command string from triggerCommand
1177
- * @param value
1178
- */
1179
- executeCommand(command, value) {
1180
- this.focus();
1181
- if (command === 'focus') {
1182
- return;
1183
- }
1184
- if (command === 'toggleEditorMode') {
1185
- this.toggleEditorMode(this.modeVisual);
1186
- }
1187
- else if (command !== '') {
1188
- if (command === 'clear') {
1189
- this.editorService.removeSelectedElements(this.getCustomTags());
1190
- this.onContentChange(this.textArea.nativeElement);
1191
- }
1192
- else if (command === 'default') {
1193
- this.editorService.removeSelectedElements('h1,h2,h3,h4,h5,h6,p,pre');
1194
- this.onContentChange(this.textArea.nativeElement);
1195
- }
1196
- else {
1197
- this.editorService.executeCommand(command, value);
1198
- }
1199
- this.exec();
1200
- }
1201
- }
1202
- /**
1203
- * focus event
1204
- */
1205
- onTextAreaFocus(event) {
1206
- if (this.focused) {
1207
- event.stopPropagation();
1208
- return;
1209
- }
1210
- this.focused = true;
1211
- this.focusEvent.emit(event);
1212
- if (!this.touched || !this.changed) {
1213
- this.editorService.executeInNextQueueIteration(() => {
1214
- this.configure();
1215
- this.touched = true;
1216
- });
1217
- }
1218
- }
1219
- /**
1220
- * @description fires when cursor leaves textarea
1221
- */
1222
- onTextAreaMouseOut(event) {
1223
- this.editorService.saveSelection();
1224
- }
1225
- /**
1226
- * blur event
1227
- */
1228
- onTextAreaBlur(event) {
1229
- /**
1230
- * save selection if focussed out
1231
- */
1232
- this.editorService.executeInNextQueueIteration(this.editorService.saveSelection);
1233
- if (typeof this.onTouched === 'function') {
1234
- (this.onTouched)();
1235
- }
1236
- if (event.relatedTarget !== null) {
1237
- const parent = event.relatedTarget.parentElement;
1238
- if (!parent?.classList.contains('angular-editor-toolbar-set') && !parent?.classList.contains('ae-picker')) {
1239
- this.blurEvent.emit(event);
1240
- this.focused = false;
1241
- }
1242
- }
1243
- }
1244
- /**
1245
- * focus the text area when the editor is focused
1246
- */
1247
- focus() {
1248
- if (this.modeVisual) {
1249
- this.textArea.nativeElement.focus();
1250
- }
1251
- else {
1252
- const sourceText = this.doc.getElementById('sourceText' + this.id);
1253
- sourceText.focus();
1254
- this.focused = true;
1255
- }
1256
- }
1257
- /**
1258
- * Executed from the contenteditable section while the input property changes
1259
- * @param element html element from contenteditable
1260
- */
1261
- onContentChange(element) {
1262
- let html = this.modeVisual ? element.innerHTML : element.innerText;
1263
- if ((!html || html === '<br>')) {
1264
- html = '';
1265
- }
1266
- if (typeof this.onChange === 'function') {
1267
- const sanitized = (this.config.sanitize || this.config.sanitize === undefined)
1268
- ? (this.sanitizer.sanitize(SecurityContext.HTML, html) ?? '')
1269
- : html;
1270
- (this.onChange)(sanitized);
1271
- if ((!html) !== this.showPlaceholder) {
1272
- this.togglePlaceholder(this.showPlaceholder);
1273
- }
1274
- }
1275
- this.changed = true;
1276
- }
1277
- /**
1278
- * Set the function to be called
1279
- * when the control receives a change event.
1280
- *
1281
- * @param fn a function
1282
- */
1283
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1284
- registerOnChange(fn) {
1285
- this.onChange = (e) => (e === '<br>' ? fn('') : fn(e));
1286
- }
1287
- /**
1288
- * Set the function to be called
1289
- * when the control receives a touch event.
1290
- *
1291
- * @param fn a function
1292
- */
1293
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1294
- registerOnTouched(fn) {
1295
- this.onTouched = fn;
1296
- }
1297
- /**
1298
- * Write a new value to the element.
1299
- *
1300
- * @param value value to be executed when there is a change in contenteditable
1301
- */
1302
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1303
- writeValue(value) {
1304
- if ((!value || value === '<br>' || value === '') !== this.showPlaceholder) {
1305
- this.togglePlaceholder(this.showPlaceholder);
1306
- }
1307
- if (value === undefined || value === '' || value === '<br>') {
1308
- value = null;
1309
- }
1310
- this.refreshView(value);
1311
- }
1312
- /**
1313
- * refresh view/HTML of the editor
1314
- *
1315
- * @param value html string from the editor
1316
- */
1317
- refreshView(value) {
1318
- const normalizedValue = value === null ? '' : value;
1319
- // Apply sanitization to prevent XSS when setting innerHTML
1320
- const sanitizedValue = this.config.sanitize !== false
1321
- ? this.sanitizer.sanitize(SecurityContext.HTML, normalizedValue)
1322
- : normalizedValue;
1323
- this.r.setProperty(this.textArea.nativeElement, 'innerHTML', sanitizedValue);
1324
- return;
1325
- }
1326
- /**
1327
- * toggles placeholder based on input string
1328
- *
1329
- * @param value A HTML string from the editor
1330
- */
1331
- togglePlaceholder(value) {
1332
- if (!value) {
1333
- this.r.addClass(this.editorWrapper.nativeElement, 'show-placeholder');
1334
- this.showPlaceholder = true;
1335
- }
1336
- else {
1337
- this.r.removeClass(this.editorWrapper.nativeElement, 'show-placeholder');
1338
- this.showPlaceholder = false;
1339
- }
1340
- }
1341
- /**
1342
- * Implements disabled state for this element
1343
- *
1344
- * @param isDisabled Disabled flag
1345
- */
1346
- setDisabledState(isDisabled) {
1347
- const div = this.textArea.nativeElement;
1348
- const action = isDisabled ? 'addClass' : 'removeClass';
1349
- this.r[action](div, 'disabled');
1350
- this.disabled = isDisabled;
1351
- }
1352
- /**
1353
- * toggles editor mode based on bToSource bool
1354
- *
1355
- * @param bToSource A boolean value from the editor
1356
- */
1357
- toggleEditorMode(bToSource) {
1358
- let oContent;
1359
- const editableElement = this.textArea.nativeElement;
1360
- if (bToSource) {
1361
- oContent = this.r.createText(editableElement.innerHTML);
1362
- this.r.setProperty(editableElement, 'innerHTML', '');
1363
- this.r.setProperty(editableElement, 'contentEditable', false);
1364
- const oPre = this.r.createElement('pre');
1365
- this.r.setStyle(oPre, 'margin', '0');
1366
- this.r.setStyle(oPre, 'outline', 'none');
1367
- const oCode = this.r.createElement('code');
1368
- this.r.setProperty(oCode, 'id', 'sourceText' + this.id);
1369
- this.r.setStyle(oCode, 'display', 'block');
1370
- this.r.setStyle(oCode, 'white-space', 'pre-wrap');
1371
- this.r.setStyle(oCode, 'word-break', 'keep-all');
1372
- this.r.setStyle(oCode, 'outline', 'none');
1373
- this.r.setStyle(oCode, 'margin', '0');
1374
- this.r.setStyle(oCode, 'background-color', '#fff5b9');
1375
- this.r.setProperty(oCode, 'contentEditable', true);
1376
- this.r.appendChild(oCode, oContent);
1377
- this.focusInstance = this.r.listen(oCode, 'focus', (event) => this.onTextAreaFocus(event));
1378
- this.blurInstance = this.r.listen(oCode, 'blur', (event) => this.onTextAreaBlur(event));
1379
- this.r.appendChild(oPre, oCode);
1380
- this.r.appendChild(editableElement, oPre);
1381
- // ToDo move to service
1382
- this.doc.execCommand('defaultParagraphSeparator', false, 'div');
1383
- this.modeVisual = false;
1384
- this.viewMode.emit(false);
1385
- oCode.focus();
1386
- }
1387
- else {
1388
- if (this.doc.querySelectorAll) {
1389
- // Apply sanitization to prevent XSS when switching from HTML mode
1390
- if (this.config.sanitize !== false) {
1391
- editableElement.innerText = this.sanitizer.sanitize(SecurityContext.HTML, editableElement.innerText);
1392
- }
1393
- this.r.setProperty(editableElement, 'innerHTML', editableElement.innerText);
1394
- }
1395
- else {
1396
- oContent = this.doc.createRange();
1397
- oContent.selectNodeContents(editableElement.firstChild);
1398
- let oContentString = oContent.toString();
1399
- // Apply sanitization to prevent XSS when switching from HTML mode
1400
- if (this.config.sanitize !== false) {
1401
- oContentString = this.sanitizer.sanitize(SecurityContext.HTML, oContentString);
1402
- }
1403
- this.r.setProperty(editableElement, 'innerHTML', oContentString);
1404
- }
1405
- this.r.setProperty(editableElement, 'contentEditable', true);
1406
- this.modeVisual = true;
1407
- this.viewMode.emit(true);
1408
- this.onContentChange(editableElement);
1409
- editableElement.focus();
1410
- }
1411
- this.editorToolbar.setEditorMode(!this.modeVisual);
1412
- }
1413
- /**
1414
- * toggles editor buttons when cursor moved or positioning
1415
- *
1416
- * Send a node array from the contentEditable of the editor
1417
- */
1418
- exec() {
1419
- this.editorToolbar.triggerButtons();
1420
- let userSelection;
1421
- if (this.doc.getSelection) {
1422
- userSelection = this.doc.getSelection();
1423
- this.editorService.executeInNextQueueIteration(this.editorService.saveSelection);
1424
- }
1425
- let a = userSelection.focusNode;
1426
- const els = [];
1427
- while (a && a.id !== 'editor') {
1428
- els.unshift(a);
1429
- a = a.parentNode;
1430
- }
1431
- this.editorToolbar.triggerBlocks(els);
1432
- }
1433
- configure() {
1434
- this.editorService.uploadUrl = this.config.uploadUrl ?? '';
1435
- this.editorService.uploadWithCredentials = this.config.uploadWithCredentials ?? false;
1436
- if (this.config.defaultParagraphSeparator) {
1437
- this.editorService.setDefaultParagraphSeparator(this.config.defaultParagraphSeparator);
1438
- }
1439
- if (this.config.defaultFontName) {
1440
- this.editorService.setFontName(this.config.defaultFontName);
1441
- }
1442
- if (this.config.defaultFontSize) {
1443
- this.editorService.setFontSize(this.config.defaultFontSize);
1444
- }
1445
- }
1446
- getFonts() {
1447
- const fonts = this.config.fonts ? this.config.fonts : (angularEditorConfig.fonts ?? []);
1448
- return fonts.map(x => {
1449
- return { label: x.name, value: x.name };
1450
- });
1451
- }
1452
- getCustomTags() {
1453
- const tags = ['span'];
1454
- (this.config.customClasses ?? []).forEach(x => {
1455
- if (x.tag !== undefined) {
1456
- if (!tags.includes(x.tag)) {
1457
- tags.push(x.tag);
1458
- }
1459
- }
1460
- });
1461
- return tags.join(',');
1462
- }
1463
- ngOnDestroy() {
1464
- if (this.blurInstance) {
1465
- this.blurInstance();
1466
- }
1467
- if (this.focusInstance) {
1468
- this.focusInstance();
1469
- }
1470
- }
1471
- filterStyles(html) {
1472
- html = html.replace('position: fixed;', '');
1473
- return html;
1474
- }
1475
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: AngularEditorComponent, deps: [{ token: 'tabindex', attribute: true }, { token: 'autofocus', attribute: true }], target: i0.ɵɵFactoryTarget.Component });
1476
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.0.7", type: AngularEditorComponent, isStandalone: false, selector: "angular-editor", inputs: { id: "id", config: "config", placeholder: "placeholder", tabIndex: "tabIndex" }, outputs: { html: "html", viewMode: "viewMode", blurEvent: "blur", focusEvent: "focus" }, host: { listeners: { "focus": "onFocus()" }, properties: { "attr.tabindex": "this.tabindex" } }, providers: [
1477
- {
1478
- provide: NG_VALUE_ACCESSOR,
1479
- useExisting: forwardRef(() => AngularEditorComponent),
1480
- multi: true
1481
- },
1482
- AngularEditorService
1483
- ], queries: [{ propertyName: "customButtonsTemplateRef", first: true, predicate: ["customButtons"], descendants: true }], viewQueries: [{ propertyName: "textArea", first: true, predicate: ["editor"], descendants: true, static: true }, { propertyName: "editorWrapper", first: true, predicate: ["editorWrapper"], descendants: true, static: true }, { propertyName: "editorToolbar", first: true, predicate: ["editorToolbar"], descendants: true }], ngImport: i0, template: "<div\n class=\"angular-editor\"\n #angularEditor\n [style.width]=\"config.width\"\n [style.minWidth]=\"config.minWidth\"\n [ngClass]=\"{\n 'bottom': config.toolbarPosition === 'bottom'\n }\"\n>\n <angular-editor-toolbar\n #editorToolbar\n [id]=\"id\"\n [uploadUrl]=\"config.uploadUrl || ''\"\n [upload]=\"$any(config.upload)\"\n [showToolbar]=\"config.showToolbar !== undefined ? config.showToolbar : true\"\n [fonts]=\"getFonts()\"\n [customClasses]=\"config.customClasses || []\"\n [defaultFontName]=\"config.defaultFontName || ''\"\n [defaultFontSize]=\"config.defaultFontSize || ''\"\n [hiddenButtons]=\"config.toolbarHiddenButtons || []\"\n (execute)=\"executeCommand($event)\"\n >\n <ng-container\n [ngTemplateOutlet]=\"customButtonsTemplateRef\"\n [ngTemplateOutletContext]=\"{ executeCommandFn: this.executeCommandFn}\"\n >\n </ng-container>\n </angular-editor-toolbar>\n\n <div\n class=\"angular-editor-wrapper\"\n #editorWrapper\n >\n <div\n #editor\n class=\"angular-editor-textarea\"\n [attr.contenteditable]=\"config.editable\"\n [attr.tabindex]=\"disabled ? -1 : tabIndex\"\n [attr.translate]=\"config.translate\"\n [attr.spellcheck]=\"config.spellcheck\"\n [attr.dir]=\"config.textDirection\"\n [style.height]=\"config.height\"\n [style.minHeight]=\"config.minHeight\"\n [style.maxHeight]=\"config.maxHeight\"\n [style.outline]=\"config.outline === false ? 'none': undefined\"\n (input)=\"onContentChange($any($event.target))\"\n (focus)=\"onTextAreaFocus($event)\"\n (blur)=\"onTextAreaBlur($event)\"\n (click)=\"exec()\"\n (keyup)=\"exec()\"\n (mouseout)=\"onTextAreaMouseOut($event)\"\n (paste)=\"onPaste($event)\"\n >\n </div>\n <span class=\"angular-editor-placeholder\">{{ placeholder || config['placeholder'] }}</span>\n </div>\n</div>\n", styles: ["a{cursor:pointer}.angular-editor{display:flex;flex-direction:column;gap:var(--ae-gap, 5px)}.angular-editor.bottom{flex-direction:column-reverse}.angular-editor ::ng-deep [contenteditable=true]:empty:before{content:attr(placeholder);color:#868e96;opacity:1}.angular-editor .angular-editor-wrapper{position:relative}.angular-editor .angular-editor-wrapper .angular-editor-textarea{min-height:150px;overflow:auto;resize:vertical}.angular-editor .angular-editor-wrapper .angular-editor-textarea:after{content:\"\";position:absolute;bottom:0;right:0;display:block;width:8px;height:8px;cursor:nwse-resize;background-color:#ffffff80}.angular-editor .angular-editor-wrapper .angular-editor-textarea{min-height:5rem;padding:.5rem .8rem 1rem;border-radius:var(--ae-text-area-border-radius, .3rem);border:var(--ae-text-area-border, 1px solid #ddd);background-color:transparent;overflow-x:hidden;overflow-y:auto;position:relative}.angular-editor .angular-editor-wrapper .angular-editor-textarea:focus,.angular-editor .angular-editor-wrapper .angular-editor-textarea.focus{outline:var(--ae-focus-outline-color, -webkit-focus-ring-color auto 1px)}.angular-editor .angular-editor-wrapper .angular-editor-textarea ::ng-deep blockquote{margin-left:1rem;border-left:.2em solid #dfe2e5;padding-left:.5rem}.angular-editor .angular-editor-wrapper ::ng-deep p{margin-bottom:0}.angular-editor .angular-editor-wrapper .angular-editor-placeholder{display:none;position:absolute;top:0;padding:.6rem .8rem 1rem .9rem;color:#6c757d;opacity:.75}.angular-editor .angular-editor-wrapper.show-placeholder .angular-editor-placeholder{display:block}.angular-editor .angular-editor-wrapper.disabled{cursor:not-allowed;opacity:.5;pointer-events:none}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: AeToolbarComponent, selector: "angular-editor-toolbar, ae-toolbar, div[aeToolbar]", inputs: ["id", "uploadUrl", "upload", "showToolbar", "fonts", "customClasses", "defaultFontName", "defaultFontSize", "hiddenButtons"], outputs: ["execute"] }], encapsulation: i0.ViewEncapsulation.None });
1484
- }
1485
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: AngularEditorComponent, decorators: [{
1486
- type: Component,
1487
- args: [{ selector: 'angular-editor', encapsulation: ViewEncapsulation.None, providers: [
1488
- {
1489
- provide: NG_VALUE_ACCESSOR,
1490
- useExisting: forwardRef(() => AngularEditorComponent),
1491
- multi: true
1492
- },
1493
- AngularEditorService
1494
- ], standalone: false, template: "<div\n class=\"angular-editor\"\n #angularEditor\n [style.width]=\"config.width\"\n [style.minWidth]=\"config.minWidth\"\n [ngClass]=\"{\n 'bottom': config.toolbarPosition === 'bottom'\n }\"\n>\n <angular-editor-toolbar\n #editorToolbar\n [id]=\"id\"\n [uploadUrl]=\"config.uploadUrl || ''\"\n [upload]=\"$any(config.upload)\"\n [showToolbar]=\"config.showToolbar !== undefined ? config.showToolbar : true\"\n [fonts]=\"getFonts()\"\n [customClasses]=\"config.customClasses || []\"\n [defaultFontName]=\"config.defaultFontName || ''\"\n [defaultFontSize]=\"config.defaultFontSize || ''\"\n [hiddenButtons]=\"config.toolbarHiddenButtons || []\"\n (execute)=\"executeCommand($event)\"\n >\n <ng-container\n [ngTemplateOutlet]=\"customButtonsTemplateRef\"\n [ngTemplateOutletContext]=\"{ executeCommandFn: this.executeCommandFn}\"\n >\n </ng-container>\n </angular-editor-toolbar>\n\n <div\n class=\"angular-editor-wrapper\"\n #editorWrapper\n >\n <div\n #editor\n class=\"angular-editor-textarea\"\n [attr.contenteditable]=\"config.editable\"\n [attr.tabindex]=\"disabled ? -1 : tabIndex\"\n [attr.translate]=\"config.translate\"\n [attr.spellcheck]=\"config.spellcheck\"\n [attr.dir]=\"config.textDirection\"\n [style.height]=\"config.height\"\n [style.minHeight]=\"config.minHeight\"\n [style.maxHeight]=\"config.maxHeight\"\n [style.outline]=\"config.outline === false ? 'none': undefined\"\n (input)=\"onContentChange($any($event.target))\"\n (focus)=\"onTextAreaFocus($event)\"\n (blur)=\"onTextAreaBlur($event)\"\n (click)=\"exec()\"\n (keyup)=\"exec()\"\n (mouseout)=\"onTextAreaMouseOut($event)\"\n (paste)=\"onPaste($event)\"\n >\n </div>\n <span class=\"angular-editor-placeholder\">{{ placeholder || config['placeholder'] }}</span>\n </div>\n</div>\n", styles: ["a{cursor:pointer}.angular-editor{display:flex;flex-direction:column;gap:var(--ae-gap, 5px)}.angular-editor.bottom{flex-direction:column-reverse}.angular-editor ::ng-deep [contenteditable=true]:empty:before{content:attr(placeholder);color:#868e96;opacity:1}.angular-editor .angular-editor-wrapper{position:relative}.angular-editor .angular-editor-wrapper .angular-editor-textarea{min-height:150px;overflow:auto;resize:vertical}.angular-editor .angular-editor-wrapper .angular-editor-textarea:after{content:\"\";position:absolute;bottom:0;right:0;display:block;width:8px;height:8px;cursor:nwse-resize;background-color:#ffffff80}.angular-editor .angular-editor-wrapper .angular-editor-textarea{min-height:5rem;padding:.5rem .8rem 1rem;border-radius:var(--ae-text-area-border-radius, .3rem);border:var(--ae-text-area-border, 1px solid #ddd);background-color:transparent;overflow-x:hidden;overflow-y:auto;position:relative}.angular-editor .angular-editor-wrapper .angular-editor-textarea:focus,.angular-editor .angular-editor-wrapper .angular-editor-textarea.focus{outline:var(--ae-focus-outline-color, -webkit-focus-ring-color auto 1px)}.angular-editor .angular-editor-wrapper .angular-editor-textarea ::ng-deep blockquote{margin-left:1rem;border-left:.2em solid #dfe2e5;padding-left:.5rem}.angular-editor .angular-editor-wrapper ::ng-deep p{margin-bottom:0}.angular-editor .angular-editor-wrapper .angular-editor-placeholder{display:none;position:absolute;top:0;padding:.6rem .8rem 1rem .9rem;color:#6c757d;opacity:.75}.angular-editor .angular-editor-wrapper.show-placeholder .angular-editor-placeholder{display:block}.angular-editor .angular-editor-wrapper.disabled{cursor:not-allowed;opacity:.5;pointer-events:none}\n"] }]
1495
- }], ctorParameters: () => [{ type: undefined, decorators: [{
1496
- type: Attribute,
1497
- args: ['tabindex']
1498
- }] }, { type: undefined, decorators: [{
1499
- type: Attribute,
1500
- args: ['autofocus']
1501
- }] }], propDecorators: { id: [{
1502
- type: Input
1503
- }], config: [{
1504
- type: Input
1505
- }], placeholder: [{
1506
- type: Input
1507
- }], tabIndex: [{
1508
- type: Input
1509
- }], html: [{
1510
- type: Output
1511
- }], textArea: [{
1512
- type: ViewChild,
1513
- args: ['editor', { static: true }]
1514
- }], editorWrapper: [{
1515
- type: ViewChild,
1516
- args: ['editorWrapper', { static: true }]
1517
- }], editorToolbar: [{
1518
- type: ViewChild,
1519
- args: ['editorToolbar']
1520
- }], customButtonsTemplateRef: [{
1521
- type: ContentChild,
1522
- args: ["customButtons"]
1523
- }], viewMode: [{
1524
- type: Output
1525
- }], blurEvent: [{
1526
- type: Output,
1527
- args: ['blur']
1528
- }], focusEvent: [{
1529
- type: Output,
1530
- args: ['focus']
1531
- }], tabindex: [{
1532
- type: HostBinding,
1533
- args: ['attr.tabindex']
1534
- }], onFocus: [{
1535
- type: HostListener,
1536
- args: ['focus']
1537
- }] } });
1538
-
1539
- class AngularEditorModule {
1540
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: AngularEditorModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1541
- static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.0.7", ngImport: i0, type: AngularEditorModule, declarations: [AngularEditorComponent, AeToolbarComponent, AeSelectComponent, AeButtonComponent, AeToolbarSetComponent], imports: [CommonModule, FormsModule, ReactiveFormsModule], exports: [AngularEditorComponent, AeToolbarComponent, AeButtonComponent, AeToolbarSetComponent] });
1542
- static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: AngularEditorModule, imports: [CommonModule, FormsModule, ReactiveFormsModule] });
1543
- }
1544
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: AngularEditorModule, decorators: [{
1545
- type: NgModule,
1546
- args: [{
1547
- imports: [
1548
- CommonModule, FormsModule, ReactiveFormsModule
1549
- ],
1550
- declarations: [AngularEditorComponent, AeToolbarComponent, AeSelectComponent, AeButtonComponent, AeToolbarSetComponent],
1551
- exports: [AngularEditorComponent, AeToolbarComponent, AeButtonComponent, AeToolbarSetComponent]
1552
- }]
1553
- }] });
1554
-
1555
- /*
1556
- * Public API Surface of angular-editor
1557
- */
1558
-
1559
- /**
1560
- * Generated bundle index. Do not edit.
1561
- */
1562
-
356
+ var AeSelectComponent = class AeSelectComponent {
357
+ options = [];
358
+ isHidden = false;
359
+ selectedOption;
360
+ disabled = false;
361
+ optionId = 0;
362
+ get label() {
363
+ return this.selectedOption && Object.prototype.hasOwnProperty.call(this.selectedOption, "label") ? this.selectedOption.label : "Select";
364
+ }
365
+ opened = false;
366
+ get value() {
367
+ return this.selectedOption.value;
368
+ }
369
+ hidden = "inline-block";
370
+ changeEvent = new EventEmitter();
371
+ labelButton;
372
+ elRef = inject(ElementRef);
373
+ r = inject(Renderer2);
374
+ ngOnInit() {
375
+ this.selectedOption = this.options[0];
376
+ if (isDefined(this.isHidden) && this.isHidden) this.hide();
377
+ }
378
+ hide() {
379
+ this.hidden = "none";
380
+ }
381
+ optionSelect(option, event) {
382
+ if (event.buttons !== 1) return;
383
+ event.preventDefault();
384
+ event.stopPropagation();
385
+ this.setValue(option.value);
386
+ this.onChange(this.selectedOption.value);
387
+ this.changeEvent.emit(this.selectedOption.value);
388
+ this.onTouched();
389
+ this.opened = false;
390
+ }
391
+ toggleOpen(event) {
392
+ if (this.disabled) return;
393
+ this.opened = !this.opened;
394
+ }
395
+ onClick($event) {
396
+ if (!this.elRef.nativeElement.contains($event.target)) this.close();
397
+ }
398
+ close() {
399
+ this.opened = false;
400
+ }
401
+ get isOpen() {
402
+ return this.opened;
403
+ }
404
+ writeValue(value) {
405
+ if (!value || typeof value !== "string") return;
406
+ this.setValue(value);
407
+ }
408
+ setValue(value) {
409
+ let index = 0;
410
+ const selectedEl = this.options.find((el, i) => {
411
+ index = i;
412
+ return el.value === value;
413
+ });
414
+ if (selectedEl) {
415
+ this.selectedOption = selectedEl;
416
+ this.optionId = index;
417
+ }
418
+ }
419
+ onChange = () => {};
420
+ onTouched = () => {};
421
+ registerOnChange(fn) {
422
+ this.onChange = fn;
423
+ }
424
+ registerOnTouched(fn) {
425
+ this.onTouched = fn;
426
+ }
427
+ setDisabledState(isDisabled) {
428
+ this.labelButton.nativeElement.disabled = isDisabled;
429
+ const div = this.labelButton.nativeElement;
430
+ const action = isDisabled ? "addClass" : "removeClass";
431
+ this.r[action](div, "disabled");
432
+ this.disabled = isDisabled;
433
+ }
434
+ handleKeyDown($event) {
435
+ if (!this.opened) return;
436
+ switch ($event.key) {
437
+ case "ArrowDown":
438
+ this._handleArrowDown($event);
439
+ break;
440
+ case "ArrowUp":
441
+ this._handleArrowUp($event);
442
+ break;
443
+ case "Space":
444
+ this._handleSpace($event);
445
+ break;
446
+ case "Enter":
447
+ this._handleEnter($event);
448
+ break;
449
+ case "Tab":
450
+ this._handleTab($event);
451
+ break;
452
+ case "Escape":
453
+ this.close();
454
+ $event.preventDefault();
455
+ break;
456
+ case "Backspace": this._handleBackspace();
457
+ }
458
+ }
459
+ _handleArrowDown($event) {
460
+ if (this.optionId < this.options.length - 1) this.optionId++;
461
+ }
462
+ _handleArrowUp($event) {
463
+ if (this.optionId >= 1) this.optionId--;
464
+ }
465
+ _handleSpace($event) {}
466
+ _handleEnter($event) {
467
+ this.optionSelect(this.options[this.optionId], $event);
468
+ }
469
+ _handleTab($event) {}
470
+ _handleBackspace() {}
471
+ static ɵfac = i0.ɵɵngDeclareFactory({
472
+ minVersion: "12.0.0",
473
+ version: "22.2.0",
474
+ ngImport: i0,
475
+ type: AeSelectComponent,
476
+ deps: [],
477
+ target: i0.ɵɵFactoryTarget.Component
478
+ });
479
+ static ɵcmp = i0.ɵɵngDeclareComponent({
480
+ minVersion: "17.0.0",
481
+ version: "22.2.0",
482
+ type: AeSelectComponent,
483
+ isStandalone: false,
484
+ selector: "ae-select",
485
+ inputs: {
486
+ options: "options",
487
+ isHidden: ["hidden", "isHidden"]
488
+ },
489
+ outputs: { changeEvent: "change" },
490
+ host: {
491
+ listeners: {
492
+ "document:click": "onClick($event)",
493
+ "keydown": "handleKeyDown($event)"
494
+ },
495
+ properties: { "style.display": "this.hidden" }
496
+ },
497
+ providers: [{
498
+ provide: NG_VALUE_ACCESSOR,
499
+ useExisting: forwardRef(() => AeSelectComponent),
500
+ multi: true
501
+ }],
502
+ viewQueries: [{
503
+ propertyName: "labelButton",
504
+ first: true,
505
+ predicate: ["labelButton"],
506
+ descendants: true,
507
+ static: true
508
+ }],
509
+ ngImport: i0,
510
+ template: "<span class=\"ae-picker\" [ngClass]=\"{'ae-expanded':isOpen}\">\n <button [tabIndex]=\"-1\" #labelButton tabindex=\"-1\" type=\"button\" role=\"button\" class=\"ae-picker-label\" (click)=\"toggleOpen($event);\">{{label}}\n <svg>\n <use [attr.href]=\"'assets/ae-icons/icons.svg#sort'\" [attr.xlink:href]=\"'assets/ae-icons/icons.svg#sort'\"></use>\n </svg>\n </button>\n <span class=\"ae-picker-options\">\n @for (item of options; track item.value; let i = $index) {\n <span tabindex=\"-1\" type=\"button\" role=\"button\" class=\"ae-picker-item\"\n [ngClass]=\"{'selected': item.value === value, 'focused': i === optionId}\"\n (mousedown)=\"optionSelect(item, $event)\">\n {{item.label}}\n </span>\n }\n @if (!options.length) {\n <span class=\"dropdown-item\">No items for select</span>\n }\n </span>\n</span>\n",
511
+ styles: ["a{cursor:pointer}svg{width:100%;height:100%}.ae-picker{color:var(--ae-picker-color, #444);display:inline-block;float:left;width:100%;position:relative;vertical-align:middle}.ae-picker-label{cursor:pointer;display:inline-block;padding-left:8px;padding-right:10px;position:relative;width:100%;line-height:1.8rem;vertical-align:middle;font-size:85%;text-align:left;background-color:var(--ae-picker-label-color, white);min-width:2rem;float:left;border:1px solid #ddd;border-radius:var(--ae-button-radius, 4px);text-overflow:clip;overflow:hidden;white-space:nowrap;height:2rem}.ae-picker-label:before{content:\"\";position:absolute;right:0;top:0;width:20px;height:100%;background:linear-gradient(to right,var(--ae-picker-label-color, white),var(--ae-picker-label-color, white) 100%)}.ae-picker-label:focus{outline:none}.ae-picker-label:hover{cursor:pointer;background-color:#f1f1f1;transition:.2s ease}.ae-picker-label:hover:before{background:linear-gradient(to right,#f5f5f5 100%,#fff)}.ae-picker-label:disabled{background-color:#f5f5f5;pointer-events:none;cursor:not-allowed}.ae-picker-label:disabled:before{background:linear-gradient(to right,#f5f5f5 100%,#fff)}.ae-picker-label svg{position:absolute;right:0;width:1rem}.ae-picker-label svg:not(:root){overflow:hidden}.ae-picker-label svg .ae-stroke{fill:none;stroke:#444;stroke-linecap:round;stroke-linejoin:round;stroke-width:2}.ae-picker-options{background-color:var(--ae-picker-option-bg-color, #fff);display:none;min-width:100%;position:absolute;white-space:nowrap;z-index:3;border:1px solid transparent;box-shadow:#0003 0 2px 8px}.ae-picker-options .ae-picker-item{cursor:pointer;display:block;padding:5px;z-index:3;text-align:left;background-color:transparent;min-width:2rem;border:0 solid #ddd}.ae-picker-options .ae-picker-item.selected{color:#06c;background-color:var(--ae-picker-option-active-bg-color, #fff4c2)}.ae-picker-options .ae-picker-item.focused{background-color:var(--ae-picker-option-focused-bg-color, #fbf9b0)}.ae-picker-options .ae-picker-item:hover{background-color:var(--ae-picker-option-hover-bg-color, #fffa98)}.ae-expanded{display:block;margin-top:-1px;z-index:1}.ae-expanded .ae-picker-label{color:#ccc;z-index:2}.ae-expanded .ae-picker-label svg{color:#ccc;z-index:2}.ae-expanded .ae-picker-label svg .ae-stroke{stroke:#ccc}.ae-expanded .ae-picker-options{display:flex;flex-direction:column;margin-top:-1px;top:100%;z-index:3;border-color:#ccc}\n"],
512
+ dependencies: [{
513
+ kind: "directive",
514
+ type: i1$1.NgClass,
515
+ selector: "[ngClass]",
516
+ inputs: ["class", "ngClass"]
517
+ }]
518
+ });
519
+ };
520
+ i0.ɵɵngDeclareClassMetadata({
521
+ minVersion: "12.0.0",
522
+ version: "22.2.0",
523
+ ngImport: i0,
524
+ type: AeSelectComponent,
525
+ decorators: [{
526
+ type: Component,
527
+ args: [{
528
+ selector: "ae-select",
529
+ providers: [{
530
+ provide: NG_VALUE_ACCESSOR,
531
+ useExisting: forwardRef(() => AeSelectComponent),
532
+ multi: true
533
+ }],
534
+ standalone: false,
535
+ template: "<span class=\"ae-picker\" [ngClass]=\"{'ae-expanded':isOpen}\">\n <button [tabIndex]=\"-1\" #labelButton tabindex=\"-1\" type=\"button\" role=\"button\" class=\"ae-picker-label\" (click)=\"toggleOpen($event);\">{{label}}\n <svg>\n <use [attr.href]=\"'assets/ae-icons/icons.svg#sort'\" [attr.xlink:href]=\"'assets/ae-icons/icons.svg#sort'\"></use>\n </svg>\n </button>\n <span class=\"ae-picker-options\">\n @for (item of options; track item.value; let i = $index) {\n <span tabindex=\"-1\" type=\"button\" role=\"button\" class=\"ae-picker-item\"\n [ngClass]=\"{'selected': item.value === value, 'focused': i === optionId}\"\n (mousedown)=\"optionSelect(item, $event)\">\n {{item.label}}\n </span>\n }\n @if (!options.length) {\n <span class=\"dropdown-item\">No items for select</span>\n }\n </span>\n</span>\n",
536
+ styles: ["a{cursor:pointer}svg{width:100%;height:100%}.ae-picker{color:var(--ae-picker-color, #444);display:inline-block;float:left;width:100%;position:relative;vertical-align:middle}.ae-picker-label{cursor:pointer;display:inline-block;padding-left:8px;padding-right:10px;position:relative;width:100%;line-height:1.8rem;vertical-align:middle;font-size:85%;text-align:left;background-color:var(--ae-picker-label-color, white);min-width:2rem;float:left;border:1px solid #ddd;border-radius:var(--ae-button-radius, 4px);text-overflow:clip;overflow:hidden;white-space:nowrap;height:2rem}.ae-picker-label:before{content:\"\";position:absolute;right:0;top:0;width:20px;height:100%;background:linear-gradient(to right,var(--ae-picker-label-color, white),var(--ae-picker-label-color, white) 100%)}.ae-picker-label:focus{outline:none}.ae-picker-label:hover{cursor:pointer;background-color:#f1f1f1;transition:.2s ease}.ae-picker-label:hover:before{background:linear-gradient(to right,#f5f5f5 100%,#fff)}.ae-picker-label:disabled{background-color:#f5f5f5;pointer-events:none;cursor:not-allowed}.ae-picker-label:disabled:before{background:linear-gradient(to right,#f5f5f5 100%,#fff)}.ae-picker-label svg{position:absolute;right:0;width:1rem}.ae-picker-label svg:not(:root){overflow:hidden}.ae-picker-label svg .ae-stroke{fill:none;stroke:#444;stroke-linecap:round;stroke-linejoin:round;stroke-width:2}.ae-picker-options{background-color:var(--ae-picker-option-bg-color, #fff);display:none;min-width:100%;position:absolute;white-space:nowrap;z-index:3;border:1px solid transparent;box-shadow:#0003 0 2px 8px}.ae-picker-options .ae-picker-item{cursor:pointer;display:block;padding:5px;z-index:3;text-align:left;background-color:transparent;min-width:2rem;border:0 solid #ddd}.ae-picker-options .ae-picker-item.selected{color:#06c;background-color:var(--ae-picker-option-active-bg-color, #fff4c2)}.ae-picker-options .ae-picker-item.focused{background-color:var(--ae-picker-option-focused-bg-color, #fbf9b0)}.ae-picker-options .ae-picker-item:hover{background-color:var(--ae-picker-option-hover-bg-color, #fffa98)}.ae-expanded{display:block;margin-top:-1px;z-index:1}.ae-expanded .ae-picker-label{color:#ccc;z-index:2}.ae-expanded .ae-picker-label svg{color:#ccc;z-index:2}.ae-expanded .ae-picker-label svg .ae-stroke{stroke:#ccc}.ae-expanded .ae-picker-options{display:flex;flex-direction:column;margin-top:-1px;top:100%;z-index:3;border-color:#ccc}\n"]
537
+ }]
538
+ }],
539
+ propDecorators: {
540
+ options: [{ type: Input }],
541
+ isHidden: [{
542
+ type: Input,
543
+ args: ["hidden"]
544
+ }],
545
+ hidden: [{
546
+ type: HostBinding,
547
+ args: ["style.display"]
548
+ }],
549
+ changeEvent: [{
550
+ type: Output,
551
+ args: ["change"]
552
+ }],
553
+ labelButton: [{
554
+ type: ViewChild,
555
+ args: ["labelButton", { static: true }]
556
+ }],
557
+ onClick: [{
558
+ type: HostListener,
559
+ args: ["document:click", ["$event"]]
560
+ }],
561
+ handleKeyDown: [{
562
+ type: HostListener,
563
+ args: ["keydown", ["$event"]]
564
+ }]
565
+ }
566
+ });
567
+ var AeButtonComponent = class AeButtonComponent {
568
+ iconName = "";
569
+ static ɵfac = i0.ɵɵngDeclareFactory({
570
+ minVersion: "12.0.0",
571
+ version: "22.2.0",
572
+ ngImport: i0,
573
+ type: AeButtonComponent,
574
+ deps: [],
575
+ target: i0.ɵɵFactoryTarget.Component
576
+ });
577
+ static ɵcmp = i0.ɵɵngDeclareComponent({
578
+ minVersion: "17.0.0",
579
+ version: "22.2.0",
580
+ type: AeButtonComponent,
581
+ isStandalone: false,
582
+ selector: "ae-button, button[aeButton]",
583
+ inputs: { iconName: "iconName" },
584
+ host: {
585
+ properties: {
586
+ "attr.tabIndex": "-1",
587
+ "attr.type": "\"button\""
588
+ },
589
+ classAttribute: "angular-editor-button"
590
+ },
591
+ ngImport: i0,
592
+ template: "@if (iconName) {\n <svg>\n <use [attr.href]=\"'assets/ae-icons/icons.svg#' + iconName\" [attr.xlink:href]=\"'assets/ae-icons/icons.svg#' + iconName\"></use>\n </svg>\n} @else {\n <ng-content></ng-content>\n}\n",
593
+ styles: ["a{cursor:pointer}:host.angular-editor-button{background-color:var(--ae-button-bg-color, white);vertical-align:middle;border:var(--ae-button-border, 1px solid #ddd);border-radius:var(--ae-button-radius, 4px);padding:.4rem;float:left;width:2rem;height:2rem}:host.angular-editor-button svg{width:100%;height:100%}:host.angular-editor-button:hover{cursor:pointer;background-color:var(--ae-button-hover-bg-color, #f1f1f1);transition:.2s ease}:host.angular-editor-button:focus,:host.angular-editor-button.focus{outline:0}:host.angular-editor-button:disabled{background-color:var(--ae-button-disabled-bg-color, #f5f5f5);pointer-events:none;cursor:not-allowed}:host.angular-editor-button:disabled>.color-label{pointer-events:none;cursor:not-allowed}:host.angular-editor-button:disabled>.color-label.foreground :after{background:#555}:host.angular-editor-button:disabled>.color-label.background{background:#555}:host.angular-editor-button.active{background:var(--ae-button-active-bg-color, #fffbd3)}:host.angular-editor-button.active:hover{background-color:var(--ae-button-active-hover-bg-color, #fffaad)}\n"]
594
+ });
595
+ };
596
+ i0.ɵɵngDeclareClassMetadata({
597
+ minVersion: "12.0.0",
598
+ version: "22.2.0",
599
+ ngImport: i0,
600
+ type: AeButtonComponent,
601
+ decorators: [{
602
+ type: Component,
603
+ args: [{
604
+ selector: "ae-button, button[aeButton]",
605
+ host: {
606
+ "class": "angular-editor-button",
607
+ "[attr.tabIndex]": "-1",
608
+ "[attr.type]": "\"button\""
609
+ },
610
+ standalone: false,
611
+ template: "@if (iconName) {\n <svg>\n <use [attr.href]=\"'assets/ae-icons/icons.svg#' + iconName\" [attr.xlink:href]=\"'assets/ae-icons/icons.svg#' + iconName\"></use>\n </svg>\n} @else {\n <ng-content></ng-content>\n}\n",
612
+ styles: ["a{cursor:pointer}:host.angular-editor-button{background-color:var(--ae-button-bg-color, white);vertical-align:middle;border:var(--ae-button-border, 1px solid #ddd);border-radius:var(--ae-button-radius, 4px);padding:.4rem;float:left;width:2rem;height:2rem}:host.angular-editor-button svg{width:100%;height:100%}:host.angular-editor-button:hover{cursor:pointer;background-color:var(--ae-button-hover-bg-color, #f1f1f1);transition:.2s ease}:host.angular-editor-button:focus,:host.angular-editor-button.focus{outline:0}:host.angular-editor-button:disabled{background-color:var(--ae-button-disabled-bg-color, #f5f5f5);pointer-events:none;cursor:not-allowed}:host.angular-editor-button:disabled>.color-label{pointer-events:none;cursor:not-allowed}:host.angular-editor-button:disabled>.color-label.foreground :after{background:#555}:host.angular-editor-button:disabled>.color-label.background{background:#555}:host.angular-editor-button.active{background:var(--ae-button-active-bg-color, #fffbd3)}:host.angular-editor-button.active:hover{background-color:var(--ae-button-active-hover-bg-color, #fffaad)}\n"]
613
+ }]
614
+ }],
615
+ propDecorators: { iconName: [{ type: Input }] }
616
+ });
617
+ var AeToolbarSetComponent = class AeToolbarSetComponent {
618
+ constructor() {}
619
+ static ɵfac = i0.ɵɵngDeclareFactory({
620
+ minVersion: "12.0.0",
621
+ version: "22.2.0",
622
+ ngImport: i0,
623
+ type: AeToolbarSetComponent,
624
+ deps: [],
625
+ target: i0.ɵɵFactoryTarget.Component
626
+ });
627
+ static ɵcmp = i0.ɵɵngDeclareComponent({
628
+ minVersion: "14.0.0",
629
+ version: "22.2.0",
630
+ type: AeToolbarSetComponent,
631
+ isStandalone: false,
632
+ selector: "ae-toolbar-set, [aeToolbarSet]",
633
+ host: { classAttribute: "angular-editor-toolbar-set" },
634
+ ngImport: i0,
635
+ template: "<ng-content></ng-content>\n",
636
+ styles: ["a{cursor:pointer}:host.angular-editor-toolbar-set{display:flex;gap:1px;width:fit-content;vertical-align:baseline}\n"]
637
+ });
638
+ };
639
+ i0.ɵɵngDeclareClassMetadata({
640
+ minVersion: "12.0.0",
641
+ version: "22.2.0",
642
+ ngImport: i0,
643
+ type: AeToolbarSetComponent,
644
+ decorators: [{
645
+ type: Component,
646
+ args: [{
647
+ selector: "ae-toolbar-set, [aeToolbarSet]",
648
+ host: { "class": "angular-editor-toolbar-set" },
649
+ standalone: false,
650
+ template: "<ng-content></ng-content>\n",
651
+ styles: ["a{cursor:pointer}:host.angular-editor-toolbar-set{display:flex;gap:1px;width:fit-content;vertical-align:baseline}\n"]
652
+ }]
653
+ }],
654
+ ctorParameters: () => []
655
+ });
656
+ var AeToolbarComponent = class AeToolbarComponent {
657
+ htmlMode = false;
658
+ linkSelected = false;
659
+ block = "default";
660
+ fontName = "Times New Roman";
661
+ fontSize = "3";
662
+ foreColour = "";
663
+ backColor = "";
664
+ headings = [
665
+ {
666
+ label: "Heading 1",
667
+ value: "h1"
668
+ },
669
+ {
670
+ label: "Heading 2",
671
+ value: "h2"
672
+ },
673
+ {
674
+ label: "Heading 3",
675
+ value: "h3"
676
+ },
677
+ {
678
+ label: "Heading 4",
679
+ value: "h4"
680
+ },
681
+ {
682
+ label: "Heading 5",
683
+ value: "h5"
684
+ },
685
+ {
686
+ label: "Heading 6",
687
+ value: "h6"
688
+ },
689
+ {
690
+ label: "Paragraph",
691
+ value: "p"
692
+ },
693
+ {
694
+ label: "Predefined",
695
+ value: "pre"
696
+ },
697
+ {
698
+ label: "Standard",
699
+ value: "div"
700
+ },
701
+ {
702
+ label: "default",
703
+ value: "default"
704
+ }
705
+ ];
706
+ fontSizes = [
707
+ {
708
+ label: "1",
709
+ value: "1"
710
+ },
711
+ {
712
+ label: "2",
713
+ value: "2"
714
+ },
715
+ {
716
+ label: "3",
717
+ value: "3"
718
+ },
719
+ {
720
+ label: "4",
721
+ value: "4"
722
+ },
723
+ {
724
+ label: "5",
725
+ value: "5"
726
+ },
727
+ {
728
+ label: "6",
729
+ value: "6"
730
+ },
731
+ {
732
+ label: "7",
733
+ value: "7"
734
+ }
735
+ ];
736
+ customClassId = "-1";
737
+ _customClasses = [];
738
+ customClassList = [{
739
+ label: "",
740
+ value: ""
741
+ }];
742
+ tagMap = {
743
+ BLOCKQUOTE: "indent",
744
+ A: "link"
745
+ };
746
+ select = [
747
+ "H1",
748
+ "H2",
749
+ "H3",
750
+ "H4",
751
+ "H5",
752
+ "H6",
753
+ "P",
754
+ "PRE",
755
+ "DIV"
756
+ ];
757
+ buttons = [
758
+ "bold",
759
+ "italic",
760
+ "underline",
761
+ "strikeThrough",
762
+ "subscript",
763
+ "superscript",
764
+ "justifyLeft",
765
+ "justifyCenter",
766
+ "justifyRight",
767
+ "justifyFull",
768
+ "indent",
769
+ "outdent",
770
+ "insertUnorderedList",
771
+ "insertOrderedList",
772
+ "link"
773
+ ];
774
+ id = "";
775
+ uploadUrl = "";
776
+ upload;
777
+ showToolbar = false;
778
+ fonts = [{
779
+ label: "",
780
+ value: ""
781
+ }];
782
+ set customClasses(classes) {
783
+ if (classes) {
784
+ this._customClasses = classes;
785
+ this.customClassList = this._customClasses.map((x, i) => ({
786
+ label: x.name,
787
+ value: i.toString()
788
+ }));
789
+ this.customClassList.unshift({
790
+ label: "Clear Class",
791
+ value: "-1"
792
+ });
793
+ }
794
+ }
795
+ set defaultFontName(value) {
796
+ if (value) this.fontName = value;
797
+ }
798
+ set defaultFontSize(value) {
799
+ if (value) this.fontSize = value;
800
+ }
801
+ hiddenButtons = [];
802
+ execute = new EventEmitter();
803
+ myInputFile;
804
+ get isLinkButtonDisabled() {
805
+ return this.htmlMode || !this.editorService.selectedText;
806
+ }
807
+ r = inject(Renderer2);
808
+ editorService = inject(AngularEditorService);
809
+ er = inject(ElementRef);
810
+ doc = inject(DOCUMENT);
811
+ triggerCommand(command) {
812
+ this.execute.emit(command);
813
+ }
814
+ triggerButtons() {
815
+ if (!this.showToolbar) return;
816
+ this.buttons.forEach((e) => {
817
+ if (this.isButtonHidden(e)) return;
818
+ const result = this.doc.queryCommandState(e);
819
+ const elementById = this.doc.getElementById(e + "-" + this.id);
820
+ if (!elementById) return;
821
+ if (result) this.r.addClass(elementById, "active");
822
+ else this.r.removeClass(elementById, "active");
823
+ });
824
+ }
825
+ triggerBlocks(nodes) {
826
+ if (!this.showToolbar) return;
827
+ this.linkSelected = nodes.findIndex((x) => x.nodeName === "A") > -1;
828
+ let found = false;
829
+ this.select.forEach((y) => {
830
+ const node = nodes.find((x) => x.nodeName === y);
831
+ if (node !== void 0 && y === node.nodeName) {
832
+ if (found === false) {
833
+ this.block = node.nodeName.toLowerCase();
834
+ found = true;
835
+ }
836
+ } else if (found === false) this.block = "default";
837
+ });
838
+ found = false;
839
+ if (this._customClasses) this._customClasses.forEach((y, index) => {
840
+ if (nodes.find((x) => {
841
+ if (x instanceof Element) return x.className === y.class;
842
+ return false;
843
+ }) !== void 0) {
844
+ if (found === false) {
845
+ this.customClassId = index.toString();
846
+ found = true;
847
+ }
848
+ } else if (found === false) this.customClassId = "-1";
849
+ });
850
+ Object.keys(this.tagMap).map((e) => {
851
+ const elementById = this.doc.getElementById(this.tagMap[e] + "-" + this.id);
852
+ const node = nodes.find((x) => x.nodeName === e);
853
+ if (node !== void 0 && e === node.nodeName) this.r.addClass(elementById, "active");
854
+ else this.r.removeClass(elementById, "active");
855
+ });
856
+ this.foreColour = this.doc.queryCommandValue("ForeColor");
857
+ this.fontSize = this.doc.queryCommandValue("FontSize");
858
+ this.fontName = this.doc.queryCommandValue("FontName").replace(/"/g, "");
859
+ this.backColor = this.doc.queryCommandValue("backColor");
860
+ }
861
+ insertUrl() {
862
+ let url = "https://";
863
+ const selection = this.editorService.savedSelection;
864
+ if (selection && selection.commonAncestorContainer.parentElement?.nodeName === "A") {
865
+ const href = selection.commonAncestorContainer.parentElement.getAttribute("href");
866
+ if (href !== "" && href !== null) url = href;
867
+ }
868
+ const promptUrl = prompt("Insert URL link", url);
869
+ if (promptUrl && promptUrl !== "" && promptUrl !== "https://") this.editorService.createLink(promptUrl);
870
+ }
871
+ insertVideo() {
872
+ this.execute.emit("");
873
+ const url = prompt("Insert Video link", `https://`);
874
+ if (url && url !== "" && url !== `https://`) this.editorService.insertVideo(url);
875
+ }
876
+ insertColor(color, where) {
877
+ this.editorService.insertColor(color, where);
878
+ this.execute.emit("");
879
+ }
880
+ setFontName(foreColor) {
881
+ this.editorService.setFontName(foreColor);
882
+ this.execute.emit("");
883
+ }
884
+ setFontSize(fontSize) {
885
+ this.editorService.setFontSize(fontSize);
886
+ this.execute.emit("");
887
+ }
888
+ setEditorMode(m) {
889
+ const toggleEditorModeButton = this.doc.getElementById("toggleEditorMode-" + this.id);
890
+ if (m) this.r.addClass(toggleEditorModeButton, "active");
891
+ else this.r.removeClass(toggleEditorModeButton, "active");
892
+ this.htmlMode = m;
893
+ }
894
+ onFileChanged(event) {
895
+ const file = event.target.files[0];
896
+ if (file.type.includes("image/")) {
897
+ if (this.upload) this.upload(file).subscribe((response) => {
898
+ if (response instanceof HttpResponse) this.watchUploadImage(response, event);
899
+ });
900
+ else if (this.uploadUrl) this.editorService.uploadImage(file).subscribe((response) => {
901
+ if (response instanceof HttpResponse) this.watchUploadImage(response, event);
902
+ });
903
+ else {
904
+ const reader = new FileReader();
905
+ reader.onload = (e) => {
906
+ const fr = e.currentTarget;
907
+ if (fr.result !== null) this.editorService.insertImage(fr.result.toString());
908
+ event.target.value = null;
909
+ };
910
+ reader.readAsDataURL(file);
911
+ }
912
+ }
913
+ }
914
+ watchUploadImage(response, event) {
915
+ const body = response.body;
916
+ if (body) {
917
+ const { imageUrl } = body;
918
+ this.editorService.insertImage(imageUrl);
919
+ }
920
+ event.srcElement.value = null;
921
+ }
922
+ setCustomClass(classId) {
923
+ if (classId === "-1") this.execute.emit("clear");
924
+ else this.editorService.createCustomClass(this._customClasses[+classId]);
925
+ }
926
+ isButtonHidden(name) {
927
+ if (!name) return false;
928
+ if (!(this.hiddenButtons instanceof Array)) return false;
929
+ let result;
930
+ for (const arr of this.hiddenButtons) {
931
+ if (arr instanceof Array) result = arr.find((item) => item === name);
932
+ if (result) break;
933
+ }
934
+ return result !== void 0;
935
+ }
936
+ focus() {
937
+ this.execute.emit("focus");
938
+ }
939
+ static ɵfac = i0.ɵɵngDeclareFactory({
940
+ minVersion: "12.0.0",
941
+ version: "22.2.0",
942
+ ngImport: i0,
943
+ type: AeToolbarComponent,
944
+ deps: [],
945
+ target: i0.ɵɵFactoryTarget.Component
946
+ });
947
+ static ɵcmp = i0.ɵɵngDeclareComponent({
948
+ minVersion: "17.0.0",
949
+ version: "22.2.0",
950
+ type: AeToolbarComponent,
951
+ isStandalone: false,
952
+ selector: "angular-editor-toolbar, ae-toolbar, div[aeToolbar]",
953
+ inputs: {
954
+ id: "id",
955
+ uploadUrl: "uploadUrl",
956
+ upload: "upload",
957
+ showToolbar: "showToolbar",
958
+ fonts: "fonts",
959
+ customClasses: "customClasses",
960
+ defaultFontName: "defaultFontName",
961
+ defaultFontSize: "defaultFontSize",
962
+ hiddenButtons: "hiddenButtons"
963
+ },
964
+ outputs: { execute: "execute" },
965
+ viewQueries: [{
966
+ propertyName: "myInputFile",
967
+ first: true,
968
+ predicate: ["fileInput"],
969
+ descendants: true
970
+ }],
971
+ ngImport: i0,
972
+ template: "@if (showToolbar) {\n <div class=\"angular-editor-toolbar\">\n @if (!isButtonHidden('undo') || !isButtonHidden('redo')) {\n <div aeToolbarSet>\n @if (!isButtonHidden('undo')) {\n <button aeButton title=\"Undo\" iconName=\"undo\" (click)=\"triggerCommand('undo')\">\n </button>\n }\n @if (!isButtonHidden('redo')) {\n <button aeButton title=\"Redo\" iconName=\"redo\" (click)=\"triggerCommand('redo')\">\n </button>\n }\n </div>\n }\n @if (!isButtonHidden('bold') || !isButtonHidden('italic') || !isButtonHidden('underline') || !isButtonHidden('strikeThrough') || !isButtonHidden('subscript') || !isButtonHidden('superscript')) {\n <div aeToolbarSet>\n @if (!isButtonHidden('bold')) {\n <button [id]=\"'bold-'+id\" aeButton title=\"Bold\" iconName=\"bold\" (click)=\"triggerCommand('bold')\"\n [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('italic')) {\n <button [id]=\"'italic-'+id\" aeButton iconName=\"italic\" title=\"Italic\" (click)=\"triggerCommand('italic')\"\n [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('underline')) {\n <button [id]=\"'underline-'+id\" aeButton title=\"Underline\" iconName=\"underline\"\n (click)=\"triggerCommand('underline')\" [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('strikeThrough')) {\n <button [id]=\"'strikeThrough-'+id\" aeButton iconName=\"strikeThrough\" title=\"Strikethrough\"\n (click)=\"triggerCommand('strikeThrough')\" [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('subscript')) {\n <button [id]=\"'subscript-'+id\" aeButton title=\"Subscript\" iconName=\"subscript\"\n (click)=\"triggerCommand('subscript')\" [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('superscript')) {\n <button [id]=\"'superscript-'+id\" aeButton iconName=\"superscript\" title=\"Superscript\"\n (click)=\"triggerCommand('superscript')\" [disabled]=\"htmlMode\">\n </button>\n }\n </div>\n }\n @if (!isButtonHidden('justifyLeft') || !isButtonHidden('justifyCenter') || !isButtonHidden('justifyRight') || !isButtonHidden('justifyFull')) {\n <div aeToolbarSet>\n @if (!isButtonHidden('justifyLeft')) {\n <button [id]=\"'justifyLeft-'+id\" aeButton iconName=\"justifyLeft\" title=\"Justify Left\"\n (click)=\"triggerCommand('justifyLeft')\" [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('justifyCenter')) {\n <button [id]=\"'justifyCenter-'+id\" aeButton iconName=\"justifyCenter\" title=\"Justify Center\"\n (click)=\"triggerCommand('justifyCenter')\" [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('justifyRight')) {\n <button [id]=\"'justifyRight-'+id\" aeButton iconName=\"justifyRight\" title=\"Justify Right\"\n (click)=\"triggerCommand('justifyRight')\" [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('justifyFull')) {\n <button [id]=\"'justifyFull-'+id\" aeButton iconName=\"justifyFull\" title=\"Justify Full\"\n (click)=\"triggerCommand('justifyFull')\" [disabled]=\"htmlMode\">\n </button>\n }\n </div>\n }\n @if (!isButtonHidden('indent') || !isButtonHidden('outdent')) {\n <div aeToolbarSet>\n @if (!isButtonHidden('indent')) {\n <button [id]=\"'indent-'+id\" aeButton iconName=\"indent\" title=\"Indent\"\n (click)=\"triggerCommand('indent')\"\n [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('outdent')) {\n <button [id]=\"'outdent-'+id\" aeButton iconName=\"outdent\" title=\"Outdent\"\n (click)=\"triggerCommand('outdent')\"\n [disabled]=\"htmlMode\">\n </button>\n }\n </div>\n }\n @if (!isButtonHidden('insertUnorderedList') || !isButtonHidden('insertOrderedList')) {\n <div aeToolbarSet>\n @if (!isButtonHidden('insertUnorderedList')) {\n <button [id]=\"'insertUnorderedList-'+id\" aeButton iconName=\"unorderedList\" title=\"Unordered List\"\n (click)=\"triggerCommand('insertUnorderedList')\" [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('insertOrderedList')) {\n <button [id]=\"'insertOrderedList-'+id\" aeButton iconName=\"orderedList\" title=\"Ordered List\"\n (click)=\"triggerCommand('insertOrderedList')\" [disabled]=\"htmlMode\">\n </button>\n }\n </div>\n }\n @if (!isButtonHidden('heading')) {\n <div aeToolbarSet>\n <ae-select class=\"select-heading\" [options]=\"headings\"\n [(ngModel)]=\"block\"\n (change)=\"triggerCommand(block)\"\n [disabled]=\"htmlMode\"\n tabindex=\"-1\"></ae-select>\n </div>\n }\n @if (!isButtonHidden('fontName')) {\n <div aeToolbarSet>\n <ae-select class=\"select-font\" [options]=\"fonts\"\n [(ngModel)]=\"fontName\"\n (change)=\"setFontName(fontName)\"\n [disabled]=\"htmlMode\"\n tabindex=\"-1\"></ae-select>\n </div>\n }\n @if (!isButtonHidden('fontSize')) {\n <div aeToolbarSet>\n <ae-select class=\"select-font-size\" [options]=\"fontSizes\"\n [(ngModel)]=\"fontSize\"\n (change)=\"setFontSize(fontSize)\"\n [disabled]=\"htmlMode\"\n tabindex=\"-1\">\n </ae-select>\n </div>\n }\n @if (!isButtonHidden('textColor') || !isButtonHidden('backgroundColor')) {\n <div aeToolbarSet>\n @if (!isButtonHidden('textColor')) {\n <input\n style=\"display: none\"\n type=\"color\" (change)=\"insertColor(fgInput.value, 'textColor')\"\n #fgInput>\n <button [id]=\"'foregroundColorPicker-'+id\" aeButton iconName=\"textColor\"\n (click)=\"focus(); fgInput.click()\"\n title=\"Text Color\"\n [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('backgroundColor')) {\n <input\n style=\"display: none\"\n type=\"color\" (change)=\"insertColor(bgInput.value, 'backgroundColor')\"\n #bgInput>\n <button [id]=\"'backgroundColorPicker-'+id\" aeButton iconName=\"backgroundColor\"\n (click)=\"focus(); bgInput.click()\"\n title=\"Background Color\"\n [disabled]=\"htmlMode\">\n </button>\n }\n </div>\n }\n @if (_customClasses && !isButtonHidden('customClasses')) {\n <div aeToolbarSet>\n <ae-select class=\"select-custom-style\" [options]=\"customClassList\"\n [(ngModel)]=\"customClassId\"\n (change)=\"setCustomClass(customClassId)\"\n [disabled]=\"htmlMode\"\n tabindex=\"-1\"></ae-select>\n </div>\n }\n @if (!isButtonHidden('link') || !isButtonHidden('unlink') || !isButtonHidden('insertImage') || !isButtonHidden('insertVideo') || !isButtonHidden('insertHorizontalRule')) {\n <div aeToolbarSet>\n @if (!isButtonHidden('link')) {\n <button [id]=\"'link-'+id\" aeButton iconName=\"link\" (click)=\"insertUrl()\"\n title=\"Insert Link\" [disabled]=\"isLinkButtonDisabled\">\n </button>\n }\n @if (!isButtonHidden('unlink')) {\n <button [id]=\"'unlink-'+id\" aeButton iconName=\"unlink\" (click)=\"triggerCommand('unlink')\"\n title=\"Unlink\" [disabled]=\"htmlMode || !linkSelected\">\n </button>\n }\n @if (!isButtonHidden('insertImage')) {\n <input\n style=\"display: none\"\n accept=\"image/*\"\n type=\"file\" (change)=\"onFileChanged($event)\"\n #fileInput>\n <button [id]=\"'insertImage-'+id\" aeButton iconName=\"image\" (click)=\"focus(); fileInput.click()\"\n title=\"Insert Image\"\n [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('insertVideo')) {\n <button [id]=\"'insertVideo-'+id\" aeButton iconName=\"video\"\n (click)=\"insertVideo()\" title=\"Insert Video\" [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('insertHorizontalRule')) {\n <button [id]=\"'insertHorizontalRule-'+id\" aeButton iconName=\"horizontalLine\" title=\"Horizontal Line\"\n (click)=\"triggerCommand('insertHorizontalRule')\" [disabled]=\"htmlMode\">\n </button>\n }\n </div>\n }\n @if (!isButtonHidden('removeFormat')) {\n <div aeToolbarSet>\n <button [id]=\"'clearFormatting-'+id\" aeButton iconName=\"removeFormat\" title=\"Clear Formatting\"\n class=\"angular-editor-button\"\n (click)=\"triggerCommand('removeFormat')\" [disabled]=\"htmlMode\">\n </button>\n </div>\n }\n @if (!isButtonHidden('toggleEditorMode')) {\n <div aeToolbarSet>\n <button [id]=\"'toggleEditorMode-'+id\" aeButton iconName=\"htmlCode\" title=\"HTML Code\"\n (click)=\"triggerCommand('toggleEditorMode')\">\n </button>\n </div>\n }\n <ng-content></ng-content>\n </div>\n}\n",
973
+ styles: ["a{cursor:pointer}.angular-editor-toolbar{font:100 14px/15px Roboto,Arial,sans-serif;background-color:var(--ae-toolbar-bg-color, #f5f5f5);font-size:.8rem;padding:var(--ae-toolbar-padding, .2rem);border:var(--ae-toolbar-border-radius, 1px solid #ddd);display:flex;flex-wrap:wrap;gap:4px}.select-heading{display:inline-block;width:90px}@supports not (-moz-appearance: none){.select-heading optgroup{font-size:12px;background-color:#f4f4f4;padding:5px}.select-heading option{border:1px solid;background-color:#fff}}.select-heading:disabled{background-color:#f5f5f5;pointer-events:none;cursor:not-allowed}.select-heading:hover{cursor:pointer;background-color:#f1f1f1;transition:.2s ease}.select-font{display:inline-block;width:90px}@supports not (-moz-appearance: none){.select-font optgroup{font-size:12px;background-color:#f4f4f4;padding:5px}.select-font option{border:1px solid;background-color:#fff}}.select-font:disabled{background-color:#f5f5f5;pointer-events:none;cursor:not-allowed}.select-font:hover{cursor:pointer;background-color:#f1f1f1;transition:.2s ease}.select-font-size{display:inline-block;width:50px}@supports not (-moz-appearance: none){.select-font-size optgroup{font-size:12px;background-color:#f4f4f4;padding:5px}.select-font-size option{border:1px solid;background-color:#fff}.select-font-size .size1{font-size:10px}.select-font-size .size2{font-size:12px}.select-font-size .size3{font-size:14px}.select-font-size .size4{font-size:16px}.select-font-size .size5{font-size:18px}.select-font-size .size6{font-size:20px}.select-font-size .size7{font-size:22px}}.select-font-size:disabled{background-color:#f5f5f5;pointer-events:none;cursor:not-allowed}.select-font-size:hover{cursor:pointer;background-color:#f1f1f1;transition:.2s ease}.select-custom-style{display:inline-block;width:90px}@supports not (-moz-appearance: none){.select-custom-style optgroup{font-size:12px;background-color:#f4f4f4;padding:5px}.select-custom-style option{border:1px solid;background-color:#fff}}.select-custom-style:disabled{background-color:#f5f5f5;pointer-events:none;cursor:not-allowed}.select-custom-style:hover{cursor:pointer;background-color:#f1f1f1;transition:.2s ease}.color-label{position:relative;cursor:pointer}.background{font-size:smaller;background:#1b1b1b;color:#fff;padding:3px}.foreground :after{position:absolute;content:\"\";inset:auto auto -3px -1px;width:15px;height:2px;z-index:0;background:#1b1b1b}.default{font-size:16px}h1{font-size:24px}h2{font-size:20px}h3{font-size:16px}h4{font-size:15px}h5{font-size:14px}h6{font-size:13px}div,pre{font-size:12px}\n"],
974
+ dependencies: [
975
+ {
976
+ kind: "directive",
977
+ type: i1.NgControlStatus,
978
+ selector: "[formControlName],[ngModel],[formControl]"
979
+ },
980
+ {
981
+ kind: "directive",
982
+ type: i1.NgModel,
983
+ selector: "[ngModel]:not([formControlName]):not([formControl])",
984
+ inputs: [
985
+ "name",
986
+ "disabled",
987
+ "ngModel",
988
+ "ngModelOptions"
989
+ ],
990
+ outputs: ["ngModelChange"],
991
+ exportAs: ["ngModel"]
992
+ },
993
+ {
994
+ kind: "component",
995
+ type: AeSelectComponent,
996
+ selector: "ae-select",
997
+ inputs: ["options", "hidden"],
998
+ outputs: ["change"]
999
+ },
1000
+ {
1001
+ kind: "component",
1002
+ type: AeButtonComponent,
1003
+ selector: "ae-button, button[aeButton]",
1004
+ inputs: ["iconName"]
1005
+ },
1006
+ {
1007
+ kind: "component",
1008
+ type: AeToolbarSetComponent,
1009
+ selector: "ae-toolbar-set, [aeToolbarSet]"
1010
+ }
1011
+ ]
1012
+ });
1013
+ };
1014
+ i0.ɵɵngDeclareClassMetadata({
1015
+ minVersion: "12.0.0",
1016
+ version: "22.2.0",
1017
+ ngImport: i0,
1018
+ type: AeToolbarComponent,
1019
+ decorators: [{
1020
+ type: Component,
1021
+ args: [{
1022
+ selector: "angular-editor-toolbar, ae-toolbar, div[aeToolbar]",
1023
+ standalone: false,
1024
+ template: "@if (showToolbar) {\n <div class=\"angular-editor-toolbar\">\n @if (!isButtonHidden('undo') || !isButtonHidden('redo')) {\n <div aeToolbarSet>\n @if (!isButtonHidden('undo')) {\n <button aeButton title=\"Undo\" iconName=\"undo\" (click)=\"triggerCommand('undo')\">\n </button>\n }\n @if (!isButtonHidden('redo')) {\n <button aeButton title=\"Redo\" iconName=\"redo\" (click)=\"triggerCommand('redo')\">\n </button>\n }\n </div>\n }\n @if (!isButtonHidden('bold') || !isButtonHidden('italic') || !isButtonHidden('underline') || !isButtonHidden('strikeThrough') || !isButtonHidden('subscript') || !isButtonHidden('superscript')) {\n <div aeToolbarSet>\n @if (!isButtonHidden('bold')) {\n <button [id]=\"'bold-'+id\" aeButton title=\"Bold\" iconName=\"bold\" (click)=\"triggerCommand('bold')\"\n [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('italic')) {\n <button [id]=\"'italic-'+id\" aeButton iconName=\"italic\" title=\"Italic\" (click)=\"triggerCommand('italic')\"\n [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('underline')) {\n <button [id]=\"'underline-'+id\" aeButton title=\"Underline\" iconName=\"underline\"\n (click)=\"triggerCommand('underline')\" [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('strikeThrough')) {\n <button [id]=\"'strikeThrough-'+id\" aeButton iconName=\"strikeThrough\" title=\"Strikethrough\"\n (click)=\"triggerCommand('strikeThrough')\" [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('subscript')) {\n <button [id]=\"'subscript-'+id\" aeButton title=\"Subscript\" iconName=\"subscript\"\n (click)=\"triggerCommand('subscript')\" [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('superscript')) {\n <button [id]=\"'superscript-'+id\" aeButton iconName=\"superscript\" title=\"Superscript\"\n (click)=\"triggerCommand('superscript')\" [disabled]=\"htmlMode\">\n </button>\n }\n </div>\n }\n @if (!isButtonHidden('justifyLeft') || !isButtonHidden('justifyCenter') || !isButtonHidden('justifyRight') || !isButtonHidden('justifyFull')) {\n <div aeToolbarSet>\n @if (!isButtonHidden('justifyLeft')) {\n <button [id]=\"'justifyLeft-'+id\" aeButton iconName=\"justifyLeft\" title=\"Justify Left\"\n (click)=\"triggerCommand('justifyLeft')\" [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('justifyCenter')) {\n <button [id]=\"'justifyCenter-'+id\" aeButton iconName=\"justifyCenter\" title=\"Justify Center\"\n (click)=\"triggerCommand('justifyCenter')\" [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('justifyRight')) {\n <button [id]=\"'justifyRight-'+id\" aeButton iconName=\"justifyRight\" title=\"Justify Right\"\n (click)=\"triggerCommand('justifyRight')\" [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('justifyFull')) {\n <button [id]=\"'justifyFull-'+id\" aeButton iconName=\"justifyFull\" title=\"Justify Full\"\n (click)=\"triggerCommand('justifyFull')\" [disabled]=\"htmlMode\">\n </button>\n }\n </div>\n }\n @if (!isButtonHidden('indent') || !isButtonHidden('outdent')) {\n <div aeToolbarSet>\n @if (!isButtonHidden('indent')) {\n <button [id]=\"'indent-'+id\" aeButton iconName=\"indent\" title=\"Indent\"\n (click)=\"triggerCommand('indent')\"\n [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('outdent')) {\n <button [id]=\"'outdent-'+id\" aeButton iconName=\"outdent\" title=\"Outdent\"\n (click)=\"triggerCommand('outdent')\"\n [disabled]=\"htmlMode\">\n </button>\n }\n </div>\n }\n @if (!isButtonHidden('insertUnorderedList') || !isButtonHidden('insertOrderedList')) {\n <div aeToolbarSet>\n @if (!isButtonHidden('insertUnorderedList')) {\n <button [id]=\"'insertUnorderedList-'+id\" aeButton iconName=\"unorderedList\" title=\"Unordered List\"\n (click)=\"triggerCommand('insertUnorderedList')\" [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('insertOrderedList')) {\n <button [id]=\"'insertOrderedList-'+id\" aeButton iconName=\"orderedList\" title=\"Ordered List\"\n (click)=\"triggerCommand('insertOrderedList')\" [disabled]=\"htmlMode\">\n </button>\n }\n </div>\n }\n @if (!isButtonHidden('heading')) {\n <div aeToolbarSet>\n <ae-select class=\"select-heading\" [options]=\"headings\"\n [(ngModel)]=\"block\"\n (change)=\"triggerCommand(block)\"\n [disabled]=\"htmlMode\"\n tabindex=\"-1\"></ae-select>\n </div>\n }\n @if (!isButtonHidden('fontName')) {\n <div aeToolbarSet>\n <ae-select class=\"select-font\" [options]=\"fonts\"\n [(ngModel)]=\"fontName\"\n (change)=\"setFontName(fontName)\"\n [disabled]=\"htmlMode\"\n tabindex=\"-1\"></ae-select>\n </div>\n }\n @if (!isButtonHidden('fontSize')) {\n <div aeToolbarSet>\n <ae-select class=\"select-font-size\" [options]=\"fontSizes\"\n [(ngModel)]=\"fontSize\"\n (change)=\"setFontSize(fontSize)\"\n [disabled]=\"htmlMode\"\n tabindex=\"-1\">\n </ae-select>\n </div>\n }\n @if (!isButtonHidden('textColor') || !isButtonHidden('backgroundColor')) {\n <div aeToolbarSet>\n @if (!isButtonHidden('textColor')) {\n <input\n style=\"display: none\"\n type=\"color\" (change)=\"insertColor(fgInput.value, 'textColor')\"\n #fgInput>\n <button [id]=\"'foregroundColorPicker-'+id\" aeButton iconName=\"textColor\"\n (click)=\"focus(); fgInput.click()\"\n title=\"Text Color\"\n [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('backgroundColor')) {\n <input\n style=\"display: none\"\n type=\"color\" (change)=\"insertColor(bgInput.value, 'backgroundColor')\"\n #bgInput>\n <button [id]=\"'backgroundColorPicker-'+id\" aeButton iconName=\"backgroundColor\"\n (click)=\"focus(); bgInput.click()\"\n title=\"Background Color\"\n [disabled]=\"htmlMode\">\n </button>\n }\n </div>\n }\n @if (_customClasses && !isButtonHidden('customClasses')) {\n <div aeToolbarSet>\n <ae-select class=\"select-custom-style\" [options]=\"customClassList\"\n [(ngModel)]=\"customClassId\"\n (change)=\"setCustomClass(customClassId)\"\n [disabled]=\"htmlMode\"\n tabindex=\"-1\"></ae-select>\n </div>\n }\n @if (!isButtonHidden('link') || !isButtonHidden('unlink') || !isButtonHidden('insertImage') || !isButtonHidden('insertVideo') || !isButtonHidden('insertHorizontalRule')) {\n <div aeToolbarSet>\n @if (!isButtonHidden('link')) {\n <button [id]=\"'link-'+id\" aeButton iconName=\"link\" (click)=\"insertUrl()\"\n title=\"Insert Link\" [disabled]=\"isLinkButtonDisabled\">\n </button>\n }\n @if (!isButtonHidden('unlink')) {\n <button [id]=\"'unlink-'+id\" aeButton iconName=\"unlink\" (click)=\"triggerCommand('unlink')\"\n title=\"Unlink\" [disabled]=\"htmlMode || !linkSelected\">\n </button>\n }\n @if (!isButtonHidden('insertImage')) {\n <input\n style=\"display: none\"\n accept=\"image/*\"\n type=\"file\" (change)=\"onFileChanged($event)\"\n #fileInput>\n <button [id]=\"'insertImage-'+id\" aeButton iconName=\"image\" (click)=\"focus(); fileInput.click()\"\n title=\"Insert Image\"\n [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('insertVideo')) {\n <button [id]=\"'insertVideo-'+id\" aeButton iconName=\"video\"\n (click)=\"insertVideo()\" title=\"Insert Video\" [disabled]=\"htmlMode\">\n </button>\n }\n @if (!isButtonHidden('insertHorizontalRule')) {\n <button [id]=\"'insertHorizontalRule-'+id\" aeButton iconName=\"horizontalLine\" title=\"Horizontal Line\"\n (click)=\"triggerCommand('insertHorizontalRule')\" [disabled]=\"htmlMode\">\n </button>\n }\n </div>\n }\n @if (!isButtonHidden('removeFormat')) {\n <div aeToolbarSet>\n <button [id]=\"'clearFormatting-'+id\" aeButton iconName=\"removeFormat\" title=\"Clear Formatting\"\n class=\"angular-editor-button\"\n (click)=\"triggerCommand('removeFormat')\" [disabled]=\"htmlMode\">\n </button>\n </div>\n }\n @if (!isButtonHidden('toggleEditorMode')) {\n <div aeToolbarSet>\n <button [id]=\"'toggleEditorMode-'+id\" aeButton iconName=\"htmlCode\" title=\"HTML Code\"\n (click)=\"triggerCommand('toggleEditorMode')\">\n </button>\n </div>\n }\n <ng-content></ng-content>\n </div>\n}\n",
1025
+ styles: ["a{cursor:pointer}.angular-editor-toolbar{font:100 14px/15px Roboto,Arial,sans-serif;background-color:var(--ae-toolbar-bg-color, #f5f5f5);font-size:.8rem;padding:var(--ae-toolbar-padding, .2rem);border:var(--ae-toolbar-border-radius, 1px solid #ddd);display:flex;flex-wrap:wrap;gap:4px}.select-heading{display:inline-block;width:90px}@supports not (-moz-appearance: none){.select-heading optgroup{font-size:12px;background-color:#f4f4f4;padding:5px}.select-heading option{border:1px solid;background-color:#fff}}.select-heading:disabled{background-color:#f5f5f5;pointer-events:none;cursor:not-allowed}.select-heading:hover{cursor:pointer;background-color:#f1f1f1;transition:.2s ease}.select-font{display:inline-block;width:90px}@supports not (-moz-appearance: none){.select-font optgroup{font-size:12px;background-color:#f4f4f4;padding:5px}.select-font option{border:1px solid;background-color:#fff}}.select-font:disabled{background-color:#f5f5f5;pointer-events:none;cursor:not-allowed}.select-font:hover{cursor:pointer;background-color:#f1f1f1;transition:.2s ease}.select-font-size{display:inline-block;width:50px}@supports not (-moz-appearance: none){.select-font-size optgroup{font-size:12px;background-color:#f4f4f4;padding:5px}.select-font-size option{border:1px solid;background-color:#fff}.select-font-size .size1{font-size:10px}.select-font-size .size2{font-size:12px}.select-font-size .size3{font-size:14px}.select-font-size .size4{font-size:16px}.select-font-size .size5{font-size:18px}.select-font-size .size6{font-size:20px}.select-font-size .size7{font-size:22px}}.select-font-size:disabled{background-color:#f5f5f5;pointer-events:none;cursor:not-allowed}.select-font-size:hover{cursor:pointer;background-color:#f1f1f1;transition:.2s ease}.select-custom-style{display:inline-block;width:90px}@supports not (-moz-appearance: none){.select-custom-style optgroup{font-size:12px;background-color:#f4f4f4;padding:5px}.select-custom-style option{border:1px solid;background-color:#fff}}.select-custom-style:disabled{background-color:#f5f5f5;pointer-events:none;cursor:not-allowed}.select-custom-style:hover{cursor:pointer;background-color:#f1f1f1;transition:.2s ease}.color-label{position:relative;cursor:pointer}.background{font-size:smaller;background:#1b1b1b;color:#fff;padding:3px}.foreground :after{position:absolute;content:\"\";inset:auto auto -3px -1px;width:15px;height:2px;z-index:0;background:#1b1b1b}.default{font-size:16px}h1{font-size:24px}h2{font-size:20px}h3{font-size:16px}h4{font-size:15px}h5{font-size:14px}h6{font-size:13px}div,pre{font-size:12px}\n"]
1026
+ }]
1027
+ }],
1028
+ propDecorators: {
1029
+ id: [{ type: Input }],
1030
+ uploadUrl: [{ type: Input }],
1031
+ upload: [{ type: Input }],
1032
+ showToolbar: [{ type: Input }],
1033
+ fonts: [{ type: Input }],
1034
+ customClasses: [{ type: Input }],
1035
+ defaultFontName: [{ type: Input }],
1036
+ defaultFontSize: [{ type: Input }],
1037
+ hiddenButtons: [{ type: Input }],
1038
+ execute: [{ type: Output }],
1039
+ myInputFile: [{
1040
+ type: ViewChild,
1041
+ args: ["fileInput", { static: false }]
1042
+ }]
1043
+ }
1044
+ });
1045
+ var AngularEditorComponent = class AngularEditorComponent {
1046
+ autoFocus;
1047
+ onChange;
1048
+ onTouched;
1049
+ modeVisual = true;
1050
+ showPlaceholder = false;
1051
+ disabled = false;
1052
+ focused = false;
1053
+ touched = false;
1054
+ changed = false;
1055
+ focusInstance;
1056
+ blurInstance;
1057
+ id = "";
1058
+ config = angularEditorConfig;
1059
+ placeholder = "";
1060
+ tabIndex = null;
1061
+ html = new EventEmitter();
1062
+ textArea;
1063
+ editorWrapper;
1064
+ editorToolbar;
1065
+ customButtonsTemplateRef;
1066
+ executeCommandFn = this.executeCommand.bind(this);
1067
+ viewMode = new EventEmitter();
1068
+ blurEvent = new EventEmitter();
1069
+ focusEvent = new EventEmitter();
1070
+ tabindex = -1;
1071
+ onFocus() {
1072
+ this.focus();
1073
+ }
1074
+ r = inject(Renderer2);
1075
+ editorService = inject(AngularEditorService);
1076
+ doc = inject(DOCUMENT);
1077
+ sanitizer = inject(DomSanitizer);
1078
+ cdRef = inject(ChangeDetectorRef);
1079
+ constructor(defaultTabIndex, autoFocus) {
1080
+ this.autoFocus = autoFocus;
1081
+ const parsedTabIndex = Number(defaultTabIndex);
1082
+ this.tabIndex = parsedTabIndex || parsedTabIndex === 0 ? parsedTabIndex : null;
1083
+ }
1084
+ ngOnInit() {
1085
+ this.config.toolbarPosition = this.config.toolbarPosition ? this.config.toolbarPosition : angularEditorConfig.toolbarPosition;
1086
+ }
1087
+ ngAfterViewInit() {
1088
+ if (isDefined(this.autoFocus)) this.focus();
1089
+ }
1090
+ onPaste(event) {
1091
+ if (this.config.rawPaste) {
1092
+ event.preventDefault();
1093
+ const text = event.clipboardData?.getData("text/plain") ?? "";
1094
+ document.execCommand("insertHTML", false, text);
1095
+ return text;
1096
+ }
1097
+ }
1098
+ executeCommand(command, value) {
1099
+ this.focus();
1100
+ if (command === "focus") return;
1101
+ if (command === "toggleEditorMode") this.toggleEditorMode(this.modeVisual);
1102
+ else if (command !== "") {
1103
+ if (command === "clear") {
1104
+ this.editorService.removeSelectedElements(this.getCustomTags());
1105
+ this.onContentChange(this.textArea.nativeElement);
1106
+ } else if (command === "default") {
1107
+ this.editorService.removeSelectedElements("h1,h2,h3,h4,h5,h6,p,pre");
1108
+ this.onContentChange(this.textArea.nativeElement);
1109
+ } else this.editorService.executeCommand(command, value);
1110
+ this.exec();
1111
+ }
1112
+ }
1113
+ onTextAreaFocus(event) {
1114
+ if (this.focused) {
1115
+ event.stopPropagation();
1116
+ return;
1117
+ }
1118
+ this.focused = true;
1119
+ this.focusEvent.emit(event);
1120
+ if (!this.touched || !this.changed) this.editorService.executeInNextQueueIteration(() => {
1121
+ this.configure();
1122
+ this.touched = true;
1123
+ });
1124
+ }
1125
+ onTextAreaMouseOut(event) {
1126
+ this.editorService.saveSelection();
1127
+ }
1128
+ onTextAreaBlur(event) {
1129
+ this.editorService.executeInNextQueueIteration(this.editorService.saveSelection);
1130
+ if (typeof this.onTouched === "function") this.onTouched();
1131
+ if (event.relatedTarget !== null) {
1132
+ const parent = event.relatedTarget.parentElement;
1133
+ if (!parent?.classList.contains("angular-editor-toolbar-set") && !parent?.classList.contains("ae-picker")) {
1134
+ this.blurEvent.emit(event);
1135
+ this.focused = false;
1136
+ }
1137
+ }
1138
+ }
1139
+ focus() {
1140
+ if (this.modeVisual) this.textArea.nativeElement.focus();
1141
+ else {
1142
+ this.doc.getElementById("sourceText" + this.id).focus();
1143
+ this.focused = true;
1144
+ }
1145
+ }
1146
+ onContentChange(element) {
1147
+ let html = this.modeVisual ? element.innerHTML : element.innerText;
1148
+ if (!html || html === "<br>") html = "";
1149
+ if (typeof this.onChange === "function") {
1150
+ const sanitized = this.config.sanitize || this.config.sanitize === void 0 ? this.sanitizer.sanitize(SecurityContext.HTML, html) ?? "" : html;
1151
+ this.onChange(sanitized);
1152
+ if (!html !== this.showPlaceholder) this.togglePlaceholder(this.showPlaceholder);
1153
+ }
1154
+ this.changed = true;
1155
+ }
1156
+ registerOnChange(fn) {
1157
+ this.onChange = (e) => e === "<br>" ? fn("") : fn(e);
1158
+ }
1159
+ registerOnTouched(fn) {
1160
+ this.onTouched = fn;
1161
+ }
1162
+ writeValue(value) {
1163
+ if ((!value || value === "<br>" || value === "") !== this.showPlaceholder) this.togglePlaceholder(this.showPlaceholder);
1164
+ if (value === void 0 || value === "" || value === "<br>") value = null;
1165
+ this.refreshView(value);
1166
+ }
1167
+ refreshView(value) {
1168
+ const normalizedValue = value === null ? "" : value;
1169
+ const sanitizedValue = this.config.sanitize !== false ? this.sanitizer.sanitize(SecurityContext.HTML, normalizedValue) : normalizedValue;
1170
+ this.r.setProperty(this.textArea.nativeElement, "innerHTML", sanitizedValue);
1171
+ }
1172
+ togglePlaceholder(value) {
1173
+ if (!value) {
1174
+ this.r.addClass(this.editorWrapper.nativeElement, "show-placeholder");
1175
+ this.showPlaceholder = true;
1176
+ } else {
1177
+ this.r.removeClass(this.editorWrapper.nativeElement, "show-placeholder");
1178
+ this.showPlaceholder = false;
1179
+ }
1180
+ }
1181
+ setDisabledState(isDisabled) {
1182
+ const div = this.textArea.nativeElement;
1183
+ const action = isDisabled ? "addClass" : "removeClass";
1184
+ this.r[action](div, "disabled");
1185
+ this.disabled = isDisabled;
1186
+ }
1187
+ toggleEditorMode(bToSource) {
1188
+ let oContent;
1189
+ const editableElement = this.textArea.nativeElement;
1190
+ if (bToSource) {
1191
+ oContent = this.r.createText(editableElement.innerHTML);
1192
+ this.r.setProperty(editableElement, "innerHTML", "");
1193
+ this.r.setProperty(editableElement, "contentEditable", false);
1194
+ const oPre = this.r.createElement("pre");
1195
+ this.r.setStyle(oPre, "margin", "0");
1196
+ this.r.setStyle(oPre, "outline", "none");
1197
+ const oCode = this.r.createElement("code");
1198
+ this.r.setProperty(oCode, "id", "sourceText" + this.id);
1199
+ this.r.setStyle(oCode, "display", "block");
1200
+ this.r.setStyle(oCode, "white-space", "pre-wrap");
1201
+ this.r.setStyle(oCode, "word-break", "keep-all");
1202
+ this.r.setStyle(oCode, "outline", "none");
1203
+ this.r.setStyle(oCode, "margin", "0");
1204
+ this.r.setStyle(oCode, "background-color", "#fff5b9");
1205
+ this.r.setProperty(oCode, "contentEditable", true);
1206
+ this.r.appendChild(oCode, oContent);
1207
+ this.focusInstance = this.r.listen(oCode, "focus", (event) => this.onTextAreaFocus(event));
1208
+ this.blurInstance = this.r.listen(oCode, "blur", (event) => this.onTextAreaBlur(event));
1209
+ this.r.appendChild(oPre, oCode);
1210
+ this.r.appendChild(editableElement, oPre);
1211
+ this.doc.execCommand("defaultParagraphSeparator", false, "div");
1212
+ this.modeVisual = false;
1213
+ this.viewMode.emit(false);
1214
+ oCode.focus();
1215
+ } else {
1216
+ if (this.doc.querySelectorAll) {
1217
+ if (this.config.sanitize !== false) editableElement.innerText = this.sanitizer.sanitize(SecurityContext.HTML, editableElement.innerText);
1218
+ this.r.setProperty(editableElement, "innerHTML", editableElement.innerText);
1219
+ } else {
1220
+ oContent = this.doc.createRange();
1221
+ oContent.selectNodeContents(editableElement.firstChild);
1222
+ let oContentString = oContent.toString();
1223
+ if (this.config.sanitize !== false) oContentString = this.sanitizer.sanitize(SecurityContext.HTML, oContentString);
1224
+ this.r.setProperty(editableElement, "innerHTML", oContentString);
1225
+ }
1226
+ this.r.setProperty(editableElement, "contentEditable", true);
1227
+ this.modeVisual = true;
1228
+ this.viewMode.emit(true);
1229
+ this.onContentChange(editableElement);
1230
+ editableElement.focus();
1231
+ }
1232
+ this.editorToolbar.setEditorMode(!this.modeVisual);
1233
+ }
1234
+ exec() {
1235
+ this.editorToolbar.triggerButtons();
1236
+ let userSelection;
1237
+ if (this.doc.getSelection) {
1238
+ userSelection = this.doc.getSelection();
1239
+ this.editorService.executeInNextQueueIteration(this.editorService.saveSelection);
1240
+ }
1241
+ let a = userSelection.focusNode;
1242
+ const els = [];
1243
+ while (a && a.id !== "editor") {
1244
+ els.unshift(a);
1245
+ a = a.parentNode;
1246
+ }
1247
+ this.editorToolbar.triggerBlocks(els);
1248
+ }
1249
+ configure() {
1250
+ this.editorService.uploadUrl = this.config.uploadUrl ?? "";
1251
+ this.editorService.uploadWithCredentials = this.config.uploadWithCredentials ?? false;
1252
+ if (this.config.defaultParagraphSeparator) this.editorService.setDefaultParagraphSeparator(this.config.defaultParagraphSeparator);
1253
+ if (this.config.defaultFontName) this.editorService.setFontName(this.config.defaultFontName);
1254
+ if (this.config.defaultFontSize) this.editorService.setFontSize(this.config.defaultFontSize);
1255
+ }
1256
+ getFonts() {
1257
+ return (this.config.fonts ? this.config.fonts : angularEditorConfig.fonts ?? []).map((x) => {
1258
+ return {
1259
+ label: x.name,
1260
+ value: x.name
1261
+ };
1262
+ });
1263
+ }
1264
+ getCustomTags() {
1265
+ const tags = ["span"];
1266
+ (this.config.customClasses ?? []).forEach((x) => {
1267
+ if (x.tag !== void 0) {
1268
+ if (!tags.includes(x.tag)) tags.push(x.tag);
1269
+ }
1270
+ });
1271
+ return tags.join(",");
1272
+ }
1273
+ ngOnDestroy() {
1274
+ if (this.blurInstance) this.blurInstance();
1275
+ if (this.focusInstance) this.focusInstance();
1276
+ }
1277
+ filterStyles(html) {
1278
+ html = html.replace("position: fixed;", "");
1279
+ return html;
1280
+ }
1281
+ static ɵfac = i0.ɵɵngDeclareFactory({
1282
+ minVersion: "12.0.0",
1283
+ version: "22.2.0",
1284
+ ngImport: i0,
1285
+ type: AngularEditorComponent,
1286
+ deps: [{
1287
+ token: "tabindex",
1288
+ attribute: true
1289
+ }, {
1290
+ token: "autofocus",
1291
+ attribute: true
1292
+ }],
1293
+ target: i0.ɵɵFactoryTarget.Component
1294
+ });
1295
+ static ɵcmp = i0.ɵɵngDeclareComponent({
1296
+ minVersion: "14.0.0",
1297
+ version: "22.2.0",
1298
+ type: AngularEditorComponent,
1299
+ isStandalone: false,
1300
+ selector: "angular-editor",
1301
+ inputs: {
1302
+ id: "id",
1303
+ config: "config",
1304
+ placeholder: "placeholder",
1305
+ tabIndex: "tabIndex"
1306
+ },
1307
+ outputs: {
1308
+ html: "html",
1309
+ viewMode: "viewMode",
1310
+ blurEvent: "blur",
1311
+ focusEvent: "focus"
1312
+ },
1313
+ host: {
1314
+ listeners: { "focus": "onFocus()" },
1315
+ properties: { "attr.tabindex": "this.tabindex" }
1316
+ },
1317
+ providers: [{
1318
+ provide: NG_VALUE_ACCESSOR,
1319
+ useExisting: forwardRef(() => AngularEditorComponent),
1320
+ multi: true
1321
+ }, AngularEditorService],
1322
+ queries: [{
1323
+ propertyName: "customButtonsTemplateRef",
1324
+ first: true,
1325
+ predicate: ["customButtons"],
1326
+ descendants: true
1327
+ }],
1328
+ viewQueries: [
1329
+ {
1330
+ propertyName: "textArea",
1331
+ first: true,
1332
+ predicate: ["editor"],
1333
+ descendants: true,
1334
+ static: true
1335
+ },
1336
+ {
1337
+ propertyName: "editorWrapper",
1338
+ first: true,
1339
+ predicate: ["editorWrapper"],
1340
+ descendants: true,
1341
+ static: true
1342
+ },
1343
+ {
1344
+ propertyName: "editorToolbar",
1345
+ first: true,
1346
+ predicate: ["editorToolbar"],
1347
+ descendants: true
1348
+ }
1349
+ ],
1350
+ ngImport: i0,
1351
+ template: "<div\n class=\"angular-editor\"\n #angularEditor\n [style.width]=\"config.width\"\n [style.minWidth]=\"config.minWidth\"\n [ngClass]=\"{\n 'bottom': config.toolbarPosition === 'bottom'\n }\"\n>\n <angular-editor-toolbar\n #editorToolbar\n [id]=\"id\"\n [uploadUrl]=\"config.uploadUrl || ''\"\n [upload]=\"$any(config.upload)\"\n [showToolbar]=\"config.showToolbar !== undefined ? config.showToolbar : true\"\n [fonts]=\"getFonts()\"\n [customClasses]=\"config.customClasses || []\"\n [defaultFontName]=\"config.defaultFontName || ''\"\n [defaultFontSize]=\"config.defaultFontSize || ''\"\n [hiddenButtons]=\"config.toolbarHiddenButtons || []\"\n (execute)=\"executeCommand($event)\"\n >\n <ng-container\n [ngTemplateOutlet]=\"customButtonsTemplateRef\"\n [ngTemplateOutletContext]=\"{ executeCommandFn: this.executeCommandFn}\"\n >\n </ng-container>\n </angular-editor-toolbar>\n\n <div\n class=\"angular-editor-wrapper\"\n #editorWrapper\n >\n <div\n #editor\n class=\"angular-editor-textarea\"\n [attr.contenteditable]=\"config.editable\"\n [attr.tabindex]=\"disabled ? -1 : tabIndex\"\n [attr.translate]=\"config.translate\"\n [attr.spellcheck]=\"config.spellcheck\"\n [attr.dir]=\"config.textDirection\"\n [style.height]=\"config.height\"\n [style.minHeight]=\"config.minHeight\"\n [style.maxHeight]=\"config.maxHeight\"\n [style.outline]=\"config.outline === false ? 'none': undefined\"\n (input)=\"onContentChange($any($event.target))\"\n (focus)=\"onTextAreaFocus($event)\"\n (blur)=\"onTextAreaBlur($event)\"\n (click)=\"exec()\"\n (keyup)=\"exec()\"\n (mouseout)=\"onTextAreaMouseOut($event)\"\n (paste)=\"onPaste($event)\"\n >\n </div>\n <span class=\"angular-editor-placeholder\">{{ placeholder || config['placeholder'] }}</span>\n </div>\n</div>\n",
1352
+ styles: ["a{cursor:pointer}.angular-editor{display:flex;flex-direction:column;gap:var(--ae-gap, 5px)}.angular-editor.bottom{flex-direction:column-reverse}.angular-editor ::ng-deep [contenteditable=true]:empty:before{content:attr(placeholder);color:#868e96;opacity:1}.angular-editor .angular-editor-wrapper{position:relative}.angular-editor .angular-editor-wrapper .angular-editor-textarea{min-height:150px;overflow:auto;resize:vertical}.angular-editor .angular-editor-wrapper .angular-editor-textarea:after{content:\"\";position:absolute;bottom:0;right:0;display:block;width:8px;height:8px;cursor:nwse-resize;background-color:#ffffff80}.angular-editor .angular-editor-wrapper .angular-editor-textarea{min-height:5rem;padding:.5rem .8rem 1rem;border-radius:var(--ae-text-area-border-radius, .3rem);border:var(--ae-text-area-border, 1px solid #ddd);background-color:transparent;overflow-x:hidden;overflow-y:auto;position:relative}.angular-editor .angular-editor-wrapper .angular-editor-textarea:focus,.angular-editor .angular-editor-wrapper .angular-editor-textarea.focus{outline:var(--ae-focus-outline-color, -webkit-focus-ring-color auto 1px)}.angular-editor .angular-editor-wrapper .angular-editor-textarea ::ng-deep blockquote{margin-left:1rem;border-left:.2em solid #dfe2e5;padding-left:.5rem}.angular-editor .angular-editor-wrapper ::ng-deep p{margin-bottom:0}.angular-editor .angular-editor-wrapper .angular-editor-placeholder{display:none;position:absolute;top:0;padding:.6rem .8rem 1rem .9rem;color:#6c757d;opacity:.75}.angular-editor .angular-editor-wrapper.show-placeholder .angular-editor-placeholder{display:block}.angular-editor .angular-editor-wrapper.disabled{cursor:not-allowed;opacity:.5;pointer-events:none}\n"],
1353
+ dependencies: [
1354
+ {
1355
+ kind: "directive",
1356
+ type: i1$1.NgClass,
1357
+ selector: "[ngClass]",
1358
+ inputs: ["class", "ngClass"]
1359
+ },
1360
+ {
1361
+ kind: "directive",
1362
+ type: i1$1.NgTemplateOutlet,
1363
+ selector: "[ngTemplateOutlet]",
1364
+ inputs: [
1365
+ "ngTemplateOutletContext",
1366
+ "ngTemplateOutlet",
1367
+ "ngTemplateOutletInjector"
1368
+ ]
1369
+ },
1370
+ {
1371
+ kind: "component",
1372
+ type: AeToolbarComponent,
1373
+ selector: "angular-editor-toolbar, ae-toolbar, div[aeToolbar]",
1374
+ inputs: [
1375
+ "id",
1376
+ "uploadUrl",
1377
+ "upload",
1378
+ "showToolbar",
1379
+ "fonts",
1380
+ "customClasses",
1381
+ "defaultFontName",
1382
+ "defaultFontSize",
1383
+ "hiddenButtons"
1384
+ ],
1385
+ outputs: ["execute"]
1386
+ }
1387
+ ],
1388
+ encapsulation: i0.ViewEncapsulation.None
1389
+ });
1390
+ };
1391
+ i0.ɵɵngDeclareClassMetadata({
1392
+ minVersion: "12.0.0",
1393
+ version: "22.2.0",
1394
+ ngImport: i0,
1395
+ type: AngularEditorComponent,
1396
+ decorators: [{
1397
+ type: Component,
1398
+ args: [{
1399
+ selector: "angular-editor",
1400
+ encapsulation: ViewEncapsulation.None,
1401
+ providers: [{
1402
+ provide: NG_VALUE_ACCESSOR,
1403
+ useExisting: forwardRef(() => AngularEditorComponent),
1404
+ multi: true
1405
+ }, AngularEditorService],
1406
+ standalone: false,
1407
+ template: "<div\n class=\"angular-editor\"\n #angularEditor\n [style.width]=\"config.width\"\n [style.minWidth]=\"config.minWidth\"\n [ngClass]=\"{\n 'bottom': config.toolbarPosition === 'bottom'\n }\"\n>\n <angular-editor-toolbar\n #editorToolbar\n [id]=\"id\"\n [uploadUrl]=\"config.uploadUrl || ''\"\n [upload]=\"$any(config.upload)\"\n [showToolbar]=\"config.showToolbar !== undefined ? config.showToolbar : true\"\n [fonts]=\"getFonts()\"\n [customClasses]=\"config.customClasses || []\"\n [defaultFontName]=\"config.defaultFontName || ''\"\n [defaultFontSize]=\"config.defaultFontSize || ''\"\n [hiddenButtons]=\"config.toolbarHiddenButtons || []\"\n (execute)=\"executeCommand($event)\"\n >\n <ng-container\n [ngTemplateOutlet]=\"customButtonsTemplateRef\"\n [ngTemplateOutletContext]=\"{ executeCommandFn: this.executeCommandFn}\"\n >\n </ng-container>\n </angular-editor-toolbar>\n\n <div\n class=\"angular-editor-wrapper\"\n #editorWrapper\n >\n <div\n #editor\n class=\"angular-editor-textarea\"\n [attr.contenteditable]=\"config.editable\"\n [attr.tabindex]=\"disabled ? -1 : tabIndex\"\n [attr.translate]=\"config.translate\"\n [attr.spellcheck]=\"config.spellcheck\"\n [attr.dir]=\"config.textDirection\"\n [style.height]=\"config.height\"\n [style.minHeight]=\"config.minHeight\"\n [style.maxHeight]=\"config.maxHeight\"\n [style.outline]=\"config.outline === false ? 'none': undefined\"\n (input)=\"onContentChange($any($event.target))\"\n (focus)=\"onTextAreaFocus($event)\"\n (blur)=\"onTextAreaBlur($event)\"\n (click)=\"exec()\"\n (keyup)=\"exec()\"\n (mouseout)=\"onTextAreaMouseOut($event)\"\n (paste)=\"onPaste($event)\"\n >\n </div>\n <span class=\"angular-editor-placeholder\">{{ placeholder || config['placeholder'] }}</span>\n </div>\n</div>\n",
1408
+ styles: ["a{cursor:pointer}.angular-editor{display:flex;flex-direction:column;gap:var(--ae-gap, 5px)}.angular-editor.bottom{flex-direction:column-reverse}.angular-editor ::ng-deep [contenteditable=true]:empty:before{content:attr(placeholder);color:#868e96;opacity:1}.angular-editor .angular-editor-wrapper{position:relative}.angular-editor .angular-editor-wrapper .angular-editor-textarea{min-height:150px;overflow:auto;resize:vertical}.angular-editor .angular-editor-wrapper .angular-editor-textarea:after{content:\"\";position:absolute;bottom:0;right:0;display:block;width:8px;height:8px;cursor:nwse-resize;background-color:#ffffff80}.angular-editor .angular-editor-wrapper .angular-editor-textarea{min-height:5rem;padding:.5rem .8rem 1rem;border-radius:var(--ae-text-area-border-radius, .3rem);border:var(--ae-text-area-border, 1px solid #ddd);background-color:transparent;overflow-x:hidden;overflow-y:auto;position:relative}.angular-editor .angular-editor-wrapper .angular-editor-textarea:focus,.angular-editor .angular-editor-wrapper .angular-editor-textarea.focus{outline:var(--ae-focus-outline-color, -webkit-focus-ring-color auto 1px)}.angular-editor .angular-editor-wrapper .angular-editor-textarea ::ng-deep blockquote{margin-left:1rem;border-left:.2em solid #dfe2e5;padding-left:.5rem}.angular-editor .angular-editor-wrapper ::ng-deep p{margin-bottom:0}.angular-editor .angular-editor-wrapper .angular-editor-placeholder{display:none;position:absolute;top:0;padding:.6rem .8rem 1rem .9rem;color:#6c757d;opacity:.75}.angular-editor .angular-editor-wrapper.show-placeholder .angular-editor-placeholder{display:block}.angular-editor .angular-editor-wrapper.disabled{cursor:not-allowed;opacity:.5;pointer-events:none}\n"]
1409
+ }]
1410
+ }],
1411
+ ctorParameters: () => [{
1412
+ type: void 0,
1413
+ decorators: [{
1414
+ type: Attribute,
1415
+ args: ["tabindex"]
1416
+ }]
1417
+ }, {
1418
+ type: void 0,
1419
+ decorators: [{
1420
+ type: Attribute,
1421
+ args: ["autofocus"]
1422
+ }]
1423
+ }],
1424
+ propDecorators: {
1425
+ id: [{ type: Input }],
1426
+ config: [{ type: Input }],
1427
+ placeholder: [{ type: Input }],
1428
+ tabIndex: [{ type: Input }],
1429
+ html: [{ type: Output }],
1430
+ textArea: [{
1431
+ type: ViewChild,
1432
+ args: ["editor", { static: true }]
1433
+ }],
1434
+ editorWrapper: [{
1435
+ type: ViewChild,
1436
+ args: ["editorWrapper", { static: true }]
1437
+ }],
1438
+ editorToolbar: [{
1439
+ type: ViewChild,
1440
+ args: ["editorToolbar"]
1441
+ }],
1442
+ customButtonsTemplateRef: [{
1443
+ type: ContentChild,
1444
+ args: ["customButtons"]
1445
+ }],
1446
+ viewMode: [{ type: Output }],
1447
+ blurEvent: [{
1448
+ type: Output,
1449
+ args: ["blur"]
1450
+ }],
1451
+ focusEvent: [{
1452
+ type: Output,
1453
+ args: ["focus"]
1454
+ }],
1455
+ tabindex: [{
1456
+ type: HostBinding,
1457
+ args: ["attr.tabindex"]
1458
+ }],
1459
+ onFocus: [{
1460
+ type: HostListener,
1461
+ args: ["focus"]
1462
+ }]
1463
+ }
1464
+ });
1465
+ var AngularEditorModule = class AngularEditorModule {
1466
+ static ɵfac = i0.ɵɵngDeclareFactory({
1467
+ minVersion: "12.0.0",
1468
+ version: "22.2.0",
1469
+ ngImport: i0,
1470
+ type: AngularEditorModule,
1471
+ deps: [],
1472
+ target: i0.ɵɵFactoryTarget.NgModule
1473
+ });
1474
+ static ɵmod = i0.ɵɵngDeclareNgModule({
1475
+ minVersion: "14.0.0",
1476
+ version: "22.2.0",
1477
+ ngImport: i0,
1478
+ type: AngularEditorModule,
1479
+ declarations: [
1480
+ AngularEditorComponent,
1481
+ AeToolbarComponent,
1482
+ AeSelectComponent,
1483
+ AeButtonComponent,
1484
+ AeToolbarSetComponent
1485
+ ],
1486
+ imports: [
1487
+ CommonModule,
1488
+ FormsModule,
1489
+ ReactiveFormsModule
1490
+ ],
1491
+ exports: [
1492
+ AngularEditorComponent,
1493
+ AeToolbarComponent,
1494
+ AeButtonComponent,
1495
+ AeToolbarSetComponent
1496
+ ]
1497
+ });
1498
+ static ɵinj = i0.ɵɵngDeclareInjector({
1499
+ minVersion: "12.0.0",
1500
+ version: "22.2.0",
1501
+ ngImport: i0,
1502
+ type: AngularEditorModule,
1503
+ imports: [
1504
+ CommonModule,
1505
+ FormsModule,
1506
+ ReactiveFormsModule
1507
+ ]
1508
+ });
1509
+ };
1510
+ i0.ɵɵngDeclareClassMetadata({
1511
+ minVersion: "12.0.0",
1512
+ version: "22.2.0",
1513
+ ngImport: i0,
1514
+ type: AngularEditorModule,
1515
+ decorators: [{
1516
+ type: NgModule,
1517
+ args: [{
1518
+ imports: [
1519
+ CommonModule,
1520
+ FormsModule,
1521
+ ReactiveFormsModule
1522
+ ],
1523
+ declarations: [
1524
+ AngularEditorComponent,
1525
+ AeToolbarComponent,
1526
+ AeSelectComponent,
1527
+ AeButtonComponent,
1528
+ AeToolbarSetComponent
1529
+ ],
1530
+ exports: [
1531
+ AngularEditorComponent,
1532
+ AeToolbarComponent,
1533
+ AeButtonComponent,
1534
+ AeToolbarSetComponent
1535
+ ]
1536
+ }]
1537
+ }]
1538
+ });
1563
1539
  export { AeButtonComponent, AeSelectComponent, AeToolbarComponent, AeToolbarSetComponent, AngularEditorComponent, AngularEditorModule, AngularEditorService };
1564
- //# sourceMappingURL=kolkov-angular-editor.mjs.map
1540
+
1541
+ //# sourceMappingURL=kolkov-angular-editor.mjs.map