@wrrdev/fenix-ui 1.1.13 → 1.1.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -5
- package/dist/components/autocomplete/autocomplete.d.ts +11 -5
- package/dist/components/autocomplete/autocomplete.d.ts.map +1 -1
- package/dist/components/autocomplete/autocomplete.js +18 -2
- package/dist/components/autocomplete/autocomplete.js.map +1 -1
- package/dist/components/button/button.d.ts +15 -0
- package/dist/components/button/button.d.ts.map +1 -1
- package/dist/components/button/button.js +20 -1
- package/dist/components/button/button.js.map +1 -1
- package/dist/components/checkbox/checkbox.d.ts +20 -4
- package/dist/components/checkbox/checkbox.d.ts.map +1 -1
- package/dist/components/checkbox/checkbox.js +39 -2
- package/dist/components/checkbox/checkbox.js.map +1 -1
- package/dist/components/datepicker/datepicker.d.ts +16 -2
- package/dist/components/datepicker/datepicker.d.ts.map +1 -1
- package/dist/components/datepicker/datepicker.js +46 -2
- package/dist/components/datepicker/datepicker.js.map +1 -1
- package/dist/components/editor/commands.d.ts +27 -0
- package/dist/components/editor/commands.d.ts.map +1 -0
- package/dist/components/editor/commands.js +235 -0
- package/dist/components/editor/commands.js.map +1 -0
- package/dist/components/editor/editor.d.ts +83 -0
- package/dist/components/editor/editor.d.ts.map +1 -0
- package/dist/components/editor/editor.js +1951 -0
- package/dist/components/editor/editor.js.map +1 -0
- package/dist/components/editor/index.d.ts +12 -0
- package/dist/components/editor/index.d.ts.map +1 -0
- package/dist/components/editor/index.js +7 -0
- package/dist/components/editor/index.js.map +1 -0
- package/dist/components/editor/normalize-html.d.ts +33 -0
- package/dist/components/editor/normalize-html.d.ts.map +1 -0
- package/dist/components/editor/normalize-html.js +316 -0
- package/dist/components/editor/normalize-html.js.map +1 -0
- package/dist/components/editor/sanitize-html.d.ts +37 -0
- package/dist/components/editor/sanitize-html.d.ts.map +1 -0
- package/dist/components/editor/sanitize-html.js +247 -0
- package/dist/components/editor/sanitize-html.js.map +1 -0
- package/dist/components/editor/schema.d.ts +36 -0
- package/dist/components/editor/schema.d.ts.map +1 -0
- package/dist/components/editor/schema.js +232 -0
- package/dist/components/editor/schema.js.map +1 -0
- package/dist/components/editor/selection.d.ts +22 -0
- package/dist/components/editor/selection.d.ts.map +1 -0
- package/dist/components/editor/selection.js +97 -0
- package/dist/components/editor/selection.js.map +1 -0
- package/dist/components/editor/styles.d.ts +10 -0
- package/dist/components/editor/styles.d.ts.map +1 -0
- package/dist/components/editor/styles.js +446 -0
- package/dist/components/editor/styles.js.map +1 -0
- package/dist/components/editor/table-utils.d.ts +33 -0
- package/dist/components/editor/table-utils.d.ts.map +1 -0
- package/dist/components/editor/table-utils.js +150 -0
- package/dist/components/editor/table-utils.js.map +1 -0
- package/dist/components/fileupload/fileupload.d.ts +10 -2
- package/dist/components/fileupload/fileupload.d.ts.map +1 -1
- package/dist/components/fileupload/fileupload.js +17 -2
- package/dist/components/fileupload/fileupload.js.map +1 -1
- package/dist/components/floatlabel/floatlabel.d.ts +9 -3
- package/dist/components/floatlabel/floatlabel.d.ts.map +1 -1
- package/dist/components/floatlabel/floatlabel.js +22 -7
- package/dist/components/floatlabel/floatlabel.js.map +1 -1
- package/dist/components/input/input.d.ts +18 -7
- package/dist/components/input/input.d.ts.map +1 -1
- package/dist/components/input/input.js +33 -3
- package/dist/components/input/input.js.map +1 -1
- package/dist/components/knob/knob.d.ts +7 -3
- package/dist/components/knob/knob.d.ts.map +1 -1
- package/dist/components/knob/knob.js +4 -2
- package/dist/components/knob/knob.js.map +1 -1
- package/dist/components/multiselect/multiselect.d.ts +13 -3
- package/dist/components/multiselect/multiselect.d.ts.map +1 -1
- package/dist/components/multiselect/multiselect.js +27 -2
- package/dist/components/multiselect/multiselect.js.map +1 -1
- package/dist/components/radio/radio.d.ts +27 -4
- package/dist/components/radio/radio.d.ts.map +1 -1
- package/dist/components/radio/radio.js +67 -8
- package/dist/components/radio/radio.js.map +1 -1
- package/dist/components/rating/rating.d.ts +8 -4
- package/dist/components/rating/rating.d.ts.map +1 -1
- package/dist/components/rating/rating.js +5 -2
- package/dist/components/rating/rating.js.map +1 -1
- package/dist/components/select/select.d.ts +9 -3
- package/dist/components/select/select.d.ts.map +1 -1
- package/dist/components/select/select.js +11 -2
- package/dist/components/select/select.js.map +1 -1
- package/dist/components/slider/slider.d.ts +12 -6
- package/dist/components/slider/slider.d.ts.map +1 -1
- package/dist/components/slider/slider.js +10 -2
- package/dist/components/slider/slider.js.map +1 -1
- package/dist/components/switch/switch.d.ts +20 -4
- package/dist/components/switch/switch.d.ts.map +1 -1
- package/dist/components/switch/switch.js +40 -2
- package/dist/components/switch/switch.js.map +1 -1
- package/dist/components/textarea/textarea.d.ts +12 -5
- package/dist/components/textarea/textarea.d.ts.map +1 -1
- package/dist/components/textarea/textarea.js +12 -2
- package/dist/components/textarea/textarea.js.map +1 -1
- package/dist/components/toast/toast.d.ts +27 -15
- package/dist/components/toast/toast.d.ts.map +1 -1
- package/dist/components/toast/toast.js +205 -32
- package/dist/components/toast/toast.js.map +1 -1
- package/dist/components/toggle-button-group/toggle-button-group.d.ts +13 -5
- package/dist/components/toggle-button-group/toggle-button-group.d.ts.map +1 -1
- package/dist/components/toggle-button-group/toggle-button-group.js +19 -2
- package/dist/components/toggle-button-group/toggle-button-group.js.map +1 -1
- package/dist/core/base.d.ts +7 -0
- package/dist/core/base.d.ts.map +1 -1
- package/dist/core/base.js +4 -1
- package/dist/core/base.js.map +1 -1
- package/dist/core/form-element.d.ts +81 -0
- package/dist/core/form-element.d.ts.map +1 -0
- package/dist/core/form-element.js +129 -0
- package/dist/core/form-element.js.map +1 -0
- package/dist/core/jsx.d.ts +25 -1
- package/dist/core/jsx.d.ts.map +1 -1
- package/dist/core/jsx.js.map +1 -1
- package/dist/core/presets.d.ts +8 -3
- package/dist/core/presets.d.ts.map +1 -1
- package/dist/core/presets.js +6 -17
- package/dist/core/presets.js.map +1 -1
- package/dist/core/types.d.ts +4 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/vue.d.ts +3 -1
- package/dist/core/vue.d.ts.map +1 -1
- package/dist/core/vue.js.map +1 -1
- package/dist/docs/app.d.ts.map +1 -1
- package/dist/docs/componentes/autocomplete.doc.d.ts.map +1 -1
- package/dist/docs/componentes/checkbox.doc.d.ts.map +1 -1
- package/dist/docs/componentes/datepicker.doc.d.ts.map +1 -1
- package/dist/docs/componentes/editor.doc.d.ts +6 -0
- package/dist/docs/componentes/editor.doc.d.ts.map +1 -0
- package/dist/docs/componentes/fileupload.doc.d.ts.map +1 -1
- package/dist/docs/componentes/index.d.ts.map +1 -1
- package/dist/docs/componentes/input.doc.d.ts.map +1 -1
- package/dist/docs/componentes/knob.doc.d.ts.map +1 -1
- package/dist/docs/componentes/multiselect.doc.d.ts.map +1 -1
- package/dist/docs/componentes/rating.doc.d.ts.map +1 -1
- package/dist/docs/componentes/select.doc.d.ts.map +1 -1
- package/dist/docs/componentes/slider.doc.d.ts.map +1 -1
- package/dist/docs/componentes/switch.doc.d.ts.map +1 -1
- package/dist/docs/componentes/textarea.doc.d.ts.map +1 -1
- package/dist/docs/componentes/toast.doc.d.ts.map +1 -1
- package/dist/docs/componentes/toggle-button-group.doc.d.ts.map +1 -1
- package/dist/docs/frameworks.d.ts +75 -0
- package/dist/docs/frameworks.d.ts.map +1 -0
- package/dist/docs/ui/code.d.ts +4 -0
- package/dist/docs/ui/code.d.ts.map +1 -1
- package/dist/fenix-ui.umd.min.js +786 -254
- package/dist/fenix-ui2.esm.js.map +1 -1
- package/dist/fenix-ui4.esm.js +4396 -172
- package/dist/fenix-ui4.esm.js.map +1 -1
- package/dist/fenix-ui5.esm.js +1 -0
- package/dist/fenix-ui5.esm.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -1
- package/dist/index.js.map +1 -1
- package/dist/plugins/auto-import.d.ts.map +1 -1
- package/dist/plugins/auto-import.js +1 -0
- package/dist/plugins/auto-import.js.map +1 -1
- package/package.json +5 -1
|
@@ -0,0 +1,1951 @@
|
|
|
1
|
+
var __typeError = (msg) => {
|
|
2
|
+
throw TypeError(msg);
|
|
3
|
+
};
|
|
4
|
+
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
|
|
5
|
+
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
|
|
6
|
+
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
7
|
+
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
|
|
8
|
+
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
|
|
9
|
+
var __privateWrapper = (obj, member, setter, getter) => ({
|
|
10
|
+
set _(value) {
|
|
11
|
+
__privateSet(obj, member, value, setter);
|
|
12
|
+
},
|
|
13
|
+
get _() {
|
|
14
|
+
return __privateGet(obj, member, getter);
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
var _built, _eventsBound, _initialized, _defaultValue, _value, _dirty, _sourceMode, _lastRange, _rafId, _emitTimer, _lastLimitError, _snapshotTimer, _history, _historyIndex, _imagePicker, _mediaFigure, _linkAnchor, _resizeDispose, _dialogReturnFocus, _dialogResolve, _disposers, _selectionRaf, _bodyOverflow, _FxEditor_instances, on_fn, bindEvents_fn, syncChrome_fn, applyCssVars_fn, updateEmpty_fn, updateCount_fn, fits_fn, limitError_fn, validate_fn, cleanHtml_fn, serialize_fn, applyValue_fn, scheduleEmit_fn, emitNow_fn, emitChange_fn, pushHistory_fn, scheduleSnapshot_fn, historyUndo_fn, historyRedo_fn, bindGlobalSelection_fn, restoreSelection_fn, syncBodyOverflow_fn, updateSourceUi_fn, releaseDialog_fn, renderToolbar_fn, updateToolbar_fn, handleToolbarKeydown_fn, moveToolbarTabStop_fn, trapDialogFocus_fn, execCommand_fn, afterCommand_fn, action_fn, handleKeydown_fn, tabInTable_fn, handleBeforeInput_fn, handlePaste_fn, handleDrop_fn, insertPlainText_fn, toggleSource_fn, applySource_fn, cancelSource_fn, openDialog_fn, fieldHtml_fn, submitDialog_fn, openLinkDialog_fn, openImageDialog_fn, toEmbedUrl_fn, openVideoDialog_fn, decorateMediaFigures_fn, syncQuickActions_fn, selectAnchor_fn, handleLinkOverlayClick_fn, openLink_fn, removeLink_fn, showLinkOverlay_fn, hideLinkOverlay_fn, positionLinkOverlay_fn, handleEditorClick_fn, showMediaOverlay_fn, hideMediaOverlay_fn, deleteMediaFigure_fn, positionMediaOverlay_fn, startResize_fn, endResize_fn, handleDoubleClick_fn, insertImage_fn, insertVideo_fn, insertEmbed_fn, insertTable_fn, insertColumns_fn, showTablePanel_fn, showColumnsPanel_fn, hidePanel_fn, currentTable_fn, tableAction_fn, handleImageFile_fn, fileToDataUrl_fn, error_fn;
|
|
18
|
+
import { FxFormElement } from "../../core/form-element.js";
|
|
19
|
+
import { defineElement } from "../../core/define.js";
|
|
20
|
+
import { esc } from "../../core/sanitize.js";
|
|
21
|
+
import { FENIX_ICON_BASE_CSS, fenixIconHtml } from "../../icons/base-css.js";
|
|
22
|
+
import { loadFenixIconsFont } from "../../icons/font.js";
|
|
23
|
+
import { sanitizeBody, sanitizeLinkUrl, sanitizeMediaUrl, sanitizeEmbedUrl } from "./sanitize-html.js";
|
|
24
|
+
import { normalizeElement } from "./normalize-html.js";
|
|
25
|
+
import { EDITOR_STYLES } from "./styles.js";
|
|
26
|
+
import { saveRange, getRange, placeCaretAtEnd, restoreRange, getBlock, closestInEditor } from "./selection.js";
|
|
27
|
+
import { formatBlock, nativeExec, insertHtml, removeFormat, toggleList, align, toggleInline, unlink, indent, escapeText, applyLink, escapeAttr } from "./commands.js";
|
|
28
|
+
import { mergeSelectedCells, splitCell } from "./table-utils.js";
|
|
29
|
+
const MAX_PASTE_BYTES = 1024 * 1024;
|
|
30
|
+
const MAX_IMAGE_BYTES = 8 * 1024 * 1024;
|
|
31
|
+
const LARGE_DOC_CHARS = 2e4;
|
|
32
|
+
const EMIT_DEBOUNCE_MS = 140;
|
|
33
|
+
const HISTORY_LIMIT = 50;
|
|
34
|
+
const QUICK_SVG = {
|
|
35
|
+
left: '<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M4 6h16M4 10h10M4 14h16M4 18h10"/></svg>',
|
|
36
|
+
center: '<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M4 6h16M7 10h10M4 14h16M7 18h10"/></svg>',
|
|
37
|
+
right: '<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M4 6h16M10 10h10M4 14h16M10 18h10"/></svg>',
|
|
38
|
+
delete: '<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 6h18M8 6V4h8v2M6 6l1 15h10l1-15M10 10v7M14 10v7"/></svg>'
|
|
39
|
+
};
|
|
40
|
+
const _FxEditor = class _FxEditor extends FxFormElement {
|
|
41
|
+
constructor() {
|
|
42
|
+
super(...arguments);
|
|
43
|
+
__privateAdd(this, _FxEditor_instances);
|
|
44
|
+
__privateAdd(this, _built, false);
|
|
45
|
+
__privateAdd(this, _eventsBound, false);
|
|
46
|
+
__privateAdd(this, _initialized, false);
|
|
47
|
+
__privateAdd(this, _defaultValue, "");
|
|
48
|
+
__privateAdd(this, _value, "");
|
|
49
|
+
__privateAdd(this, _dirty, false);
|
|
50
|
+
__privateAdd(this, _sourceMode, false);
|
|
51
|
+
__privateAdd(this, _lastRange, null);
|
|
52
|
+
__privateAdd(this, _rafId, 0);
|
|
53
|
+
__privateAdd(this, _emitTimer, null);
|
|
54
|
+
__privateAdd(this, _lastLimitError, 0);
|
|
55
|
+
__privateAdd(this, _snapshotTimer, null);
|
|
56
|
+
__privateAdd(this, _history, []);
|
|
57
|
+
__privateAdd(this, _historyIndex, -1);
|
|
58
|
+
__privateAdd(this, _imagePicker, null);
|
|
59
|
+
__privateAdd(this, _mediaFigure, null);
|
|
60
|
+
__privateAdd(this, _linkAnchor, null);
|
|
61
|
+
__privateAdd(this, _resizeDispose, null);
|
|
62
|
+
__privateAdd(this, _dialogReturnFocus, null);
|
|
63
|
+
__privateAdd(this, _dialogResolve, null);
|
|
64
|
+
__privateAdd(this, _disposers, []);
|
|
65
|
+
__privateAdd(this, _selectionRaf, 0);
|
|
66
|
+
__privateAdd(this, _bodyOverflow, "");
|
|
67
|
+
}
|
|
68
|
+
static get observedAttributes() {
|
|
69
|
+
return [
|
|
70
|
+
"toolbar",
|
|
71
|
+
"features",
|
|
72
|
+
"placeholder",
|
|
73
|
+
"readonly",
|
|
74
|
+
"disabled",
|
|
75
|
+
"required",
|
|
76
|
+
"full",
|
|
77
|
+
"error",
|
|
78
|
+
"invalid",
|
|
79
|
+
"success",
|
|
80
|
+
"valid",
|
|
81
|
+
"show-count",
|
|
82
|
+
"paste-mode",
|
|
83
|
+
"min-height",
|
|
84
|
+
"max-height",
|
|
85
|
+
"fullscreen",
|
|
86
|
+
"maxlength"
|
|
87
|
+
];
|
|
88
|
+
}
|
|
89
|
+
get editor() {
|
|
90
|
+
return this.root.querySelector(".content");
|
|
91
|
+
}
|
|
92
|
+
get source() {
|
|
93
|
+
return this.root.querySelector(".source");
|
|
94
|
+
}
|
|
95
|
+
get toolbarEl() {
|
|
96
|
+
return this.root.querySelector(".toolbar");
|
|
97
|
+
}
|
|
98
|
+
get value() {
|
|
99
|
+
if (__privateGet(this, _sourceMode) && this.source) return __privateMethod(this, _FxEditor_instances, serialize_fn).call(this);
|
|
100
|
+
if (__privateGet(this, _dirty)) __privateSet(this, _value, __privateMethod(this, _FxEditor_instances, serialize_fn).call(this));
|
|
101
|
+
return __privateGet(this, _value);
|
|
102
|
+
}
|
|
103
|
+
set value(next) {
|
|
104
|
+
const clean = __privateMethod(this, _FxEditor_instances, cleanHtml_fn).call(this, next ?? "");
|
|
105
|
+
__privateSet(this, _value, clean);
|
|
106
|
+
__privateSet(this, _dirty, false);
|
|
107
|
+
if (!__privateGet(this, _defaultValue)) __privateSet(this, _defaultValue, clean);
|
|
108
|
+
__privateMethod(this, _FxEditor_instances, applyValue_fn).call(this, clean);
|
|
109
|
+
this.updateFormValue();
|
|
110
|
+
}
|
|
111
|
+
get html() {
|
|
112
|
+
return this.value;
|
|
113
|
+
}
|
|
114
|
+
set html(next) {
|
|
115
|
+
this.value = next;
|
|
116
|
+
}
|
|
117
|
+
get text() {
|
|
118
|
+
return (this.editor?.textContent ?? "").replace(/\u200b/g, "").trim();
|
|
119
|
+
}
|
|
120
|
+
get defaultValue() {
|
|
121
|
+
return __privateGet(this, _defaultValue);
|
|
122
|
+
}
|
|
123
|
+
set defaultValue(next) {
|
|
124
|
+
__privateSet(this, _defaultValue, __privateMethod(this, _FxEditor_instances, cleanHtml_fn).call(this, next ?? ""));
|
|
125
|
+
if (!__privateGet(this, _dirty)) this.value = __privateGet(this, _defaultValue);
|
|
126
|
+
}
|
|
127
|
+
get disabled() {
|
|
128
|
+
return this.hasAttr("disabled");
|
|
129
|
+
}
|
|
130
|
+
set disabled(value) {
|
|
131
|
+
this.toggleAttr("disabled", Boolean(value));
|
|
132
|
+
}
|
|
133
|
+
get readonly() {
|
|
134
|
+
return this.hasAttr("readonly");
|
|
135
|
+
}
|
|
136
|
+
set readonly(value) {
|
|
137
|
+
this.toggleAttr("readonly", Boolean(value));
|
|
138
|
+
}
|
|
139
|
+
get required() {
|
|
140
|
+
return this.hasAttr("required");
|
|
141
|
+
}
|
|
142
|
+
set required(value) {
|
|
143
|
+
this.toggleAttr("required", Boolean(value));
|
|
144
|
+
}
|
|
145
|
+
get placeholder() {
|
|
146
|
+
return this.getAttr("placeholder");
|
|
147
|
+
}
|
|
148
|
+
set placeholder(value) {
|
|
149
|
+
this.setAttribute("placeholder", value);
|
|
150
|
+
}
|
|
151
|
+
get toolbar() {
|
|
152
|
+
const value = this.getAttr("toolbar", "standard");
|
|
153
|
+
return ["minimal", "basic", "standard", "full", "none"].includes(value) ? value : "standard";
|
|
154
|
+
}
|
|
155
|
+
set toolbar(value) {
|
|
156
|
+
this.setAttribute("toolbar", value);
|
|
157
|
+
}
|
|
158
|
+
get pasteMode() {
|
|
159
|
+
return this.getAttr("paste-mode", "clean") === "plain" ? "plain" : "clean";
|
|
160
|
+
}
|
|
161
|
+
set pasteMode(value) {
|
|
162
|
+
this.setAttribute("paste-mode", value);
|
|
163
|
+
}
|
|
164
|
+
get fullscreen() {
|
|
165
|
+
return this.hasAttr("fullscreen");
|
|
166
|
+
}
|
|
167
|
+
set fullscreen(value) {
|
|
168
|
+
this.toggleAttr("fullscreen", Boolean(value));
|
|
169
|
+
}
|
|
170
|
+
/** Limite de caracteres de texto (0 desativa). Padrão: 30.000. */
|
|
171
|
+
get maxlength() {
|
|
172
|
+
const value = Number.parseInt(this.getAttr("maxlength", "30000"), 10);
|
|
173
|
+
return Number.isFinite(value) && value > 0 ? value : 0;
|
|
174
|
+
}
|
|
175
|
+
set maxlength(value) {
|
|
176
|
+
if (Number.isFinite(value) && value >= 0) this.setAttribute("maxlength", String(Math.floor(value)));
|
|
177
|
+
else this.removeAttribute("maxlength");
|
|
178
|
+
}
|
|
179
|
+
connectedCallback() {
|
|
180
|
+
loadFenixIconsFont();
|
|
181
|
+
super.connectedCallback();
|
|
182
|
+
if (this.fullscreen) __privateMethod(this, _FxEditor_instances, syncBodyOverflow_fn).call(this);
|
|
183
|
+
if (!__privateGet(this, _initialized)) {
|
|
184
|
+
__privateSet(this, _initialized, true);
|
|
185
|
+
const initial = __privateGet(this, _value) || this.getAttr("value") || this.innerHTML;
|
|
186
|
+
this.replaceChildren();
|
|
187
|
+
__privateSet(this, _defaultValue, __privateMethod(this, _FxEditor_instances, cleanHtml_fn).call(this, initial));
|
|
188
|
+
__privateSet(this, _value, __privateGet(this, _defaultValue));
|
|
189
|
+
__privateMethod(this, _FxEditor_instances, applyValue_fn).call(this, __privateGet(this, _defaultValue));
|
|
190
|
+
this.updateFormValue();
|
|
191
|
+
__privateMethod(this, _FxEditor_instances, pushHistory_fn).call(this, __privateGet(this, _value));
|
|
192
|
+
this.dispatchEvent(new CustomEvent("ready", { bubbles: true, composed: true }));
|
|
193
|
+
} else if (__privateGet(this, _built) && !__privateGet(this, _eventsBound)) {
|
|
194
|
+
__privateMethod(this, _FxEditor_instances, bindEvents_fn).call(this);
|
|
195
|
+
__privateSet(this, _eventsBound, true);
|
|
196
|
+
}
|
|
197
|
+
__privateMethod(this, _FxEditor_instances, bindGlobalSelection_fn).call(this);
|
|
198
|
+
}
|
|
199
|
+
disconnectedCallback() {
|
|
200
|
+
for (const dispose of __privateGet(this, _disposers)) dispose();
|
|
201
|
+
__privateSet(this, _disposers, []);
|
|
202
|
+
__privateSet(this, _eventsBound, false);
|
|
203
|
+
cancelAnimationFrame(__privateGet(this, _rafId));
|
|
204
|
+
cancelAnimationFrame(__privateGet(this, _selectionRaf));
|
|
205
|
+
if (__privateGet(this, _emitTimer)) clearTimeout(__privateGet(this, _emitTimer));
|
|
206
|
+
if (__privateGet(this, _snapshotTimer)) clearTimeout(__privateGet(this, _snapshotTimer));
|
|
207
|
+
__privateMethod(this, _FxEditor_instances, endResize_fn).call(this);
|
|
208
|
+
__privateMethod(this, _FxEditor_instances, hideMediaOverlay_fn).call(this);
|
|
209
|
+
__privateMethod(this, _FxEditor_instances, hideLinkOverlay_fn).call(this);
|
|
210
|
+
if (this.hasAttr("fullscreen")) document.body.style.overflow = __privateGet(this, _bodyOverflow);
|
|
211
|
+
__privateMethod(this, _FxEditor_instances, releaseDialog_fn).call(this, null);
|
|
212
|
+
super.disconnectedCallback();
|
|
213
|
+
}
|
|
214
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
215
|
+
if (oldValue === newValue || !__privateGet(this, _built)) return;
|
|
216
|
+
if (name === "toolbar" || name === "features") __privateMethod(this, _FxEditor_instances, renderToolbar_fn).call(this);
|
|
217
|
+
if (name === "fullscreen") __privateMethod(this, _FxEditor_instances, syncBodyOverflow_fn).call(this);
|
|
218
|
+
__privateMethod(this, _FxEditor_instances, syncChrome_fn).call(this);
|
|
219
|
+
}
|
|
220
|
+
formResetCallback() {
|
|
221
|
+
__privateSet(this, _dirty, false);
|
|
222
|
+
this.value = __privateGet(this, _defaultValue);
|
|
223
|
+
}
|
|
224
|
+
getFormValue() {
|
|
225
|
+
return this.hasAttr("disabled") ? null : this.value;
|
|
226
|
+
}
|
|
227
|
+
render() {
|
|
228
|
+
if (__privateGet(this, _built)) return;
|
|
229
|
+
this.setTemplate(`
|
|
230
|
+
<div class="editor" part="editor">
|
|
231
|
+
<div class="toolbar" part="toolbar" role="toolbar" aria-label="Formatação" aria-orientation="horizontal"></div>
|
|
232
|
+
<div class="body">
|
|
233
|
+
<div class="content" part="content" contenteditable="true" role="textbox"
|
|
234
|
+
aria-multiline="true" spellcheck="true"></div>
|
|
235
|
+
<textarea class="source" part="source" spellcheck="false" hidden aria-label="HTML do conteúdo"></textarea>
|
|
236
|
+
<div class="media-overlay" part="media-overlay" hidden>
|
|
237
|
+
<span class="media-handle nw" data-handle="nw"></span>
|
|
238
|
+
<span class="media-handle ne" data-handle="ne"></span>
|
|
239
|
+
<span class="media-handle sw" data-handle="sw"></span>
|
|
240
|
+
<span class="media-handle se" data-handle="se"></span>
|
|
241
|
+
<span class="media-size"></span>
|
|
242
|
+
<button type="button" class="media-delete" data-media-action="delete" aria-label="Excluir mídia" title="Excluir mídia">${fenixIconHtml("delete")}</button>
|
|
243
|
+
</div>
|
|
244
|
+
<div class="link-overlay" part="link-overlay" hidden>
|
|
245
|
+
<button type="button" data-link-action="open">Abrir</button>
|
|
246
|
+
<button type="button" data-link-action="edit">Editar</button>
|
|
247
|
+
<button type="button" data-link-action="remove">Remover</button>
|
|
248
|
+
</div>
|
|
249
|
+
</div>
|
|
250
|
+
<div class="statusbar" part="statusbar">
|
|
251
|
+
<span class="count"></span>
|
|
252
|
+
<span class="source-actions" hidden>
|
|
253
|
+
<button type="button" class="btn source-apply">Aplicar</button>
|
|
254
|
+
<button type="button" class="btn source-cancel">Cancelar</button>
|
|
255
|
+
</span>
|
|
256
|
+
<slot name="footer"></slot>
|
|
257
|
+
</div>
|
|
258
|
+
<input type="file" class="image-picker" accept="image/*" hidden>
|
|
259
|
+
<div class="backdrop" part="dialog" hidden>
|
|
260
|
+
<div class="dialog" role="dialog" aria-modal="true" aria-labelledby="fx-editor-dialog-title">
|
|
261
|
+
<header>
|
|
262
|
+
<h3 id="fx-editor-dialog-title"></h3>
|
|
263
|
+
<button type="button" class="dialog-close" aria-label="Fechar">×</button>
|
|
264
|
+
</header>
|
|
265
|
+
<div class="dialog-body"></div>
|
|
266
|
+
<footer>
|
|
267
|
+
<button type="button" class="btn dialog-cancel">Cancelar</button>
|
|
268
|
+
<button type="button" class="btn dialog-ok">Aplicar</button>
|
|
269
|
+
</footer>
|
|
270
|
+
</div>
|
|
271
|
+
</div>
|
|
272
|
+
</div>
|
|
273
|
+
`);
|
|
274
|
+
__privateSet(this, _built, true);
|
|
275
|
+
__privateSet(this, _imagePicker, this.root.querySelector(".image-picker"));
|
|
276
|
+
__privateMethod(this, _FxEditor_instances, bindEvents_fn).call(this);
|
|
277
|
+
__privateSet(this, _eventsBound, true);
|
|
278
|
+
__privateMethod(this, _FxEditor_instances, renderToolbar_fn).call(this);
|
|
279
|
+
__privateMethod(this, _FxEditor_instances, syncChrome_fn).call(this);
|
|
280
|
+
}
|
|
281
|
+
/* ---------------------------------------------------------------------
|
|
282
|
+
* API pública
|
|
283
|
+
* ------------------------------------------------------------------ */
|
|
284
|
+
focus(options) {
|
|
285
|
+
this.editor?.focus(options ?? { preventScroll: true });
|
|
286
|
+
}
|
|
287
|
+
blur() {
|
|
288
|
+
this.editor?.blur();
|
|
289
|
+
}
|
|
290
|
+
execute(command, value) {
|
|
291
|
+
if (value !== void 0) {
|
|
292
|
+
__privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
|
|
293
|
+
nativeExec("styleWithCSS", "true");
|
|
294
|
+
nativeExec(command, value);
|
|
295
|
+
__privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
__privateMethod(this, _FxEditor_instances, execCommand_fn).call(this, command);
|
|
299
|
+
}
|
|
300
|
+
insertHTML(html) {
|
|
301
|
+
const clean = __privateMethod(this, _FxEditor_instances, cleanHtml_fn).call(this, html);
|
|
302
|
+
const probe = document.createElement("div");
|
|
303
|
+
probe.innerHTML = clean;
|
|
304
|
+
const extra = probe.textContent?.length ?? 0;
|
|
305
|
+
if (!__privateMethod(this, _FxEditor_instances, fits_fn).call(this, extra)) {
|
|
306
|
+
__privateMethod(this, _FxEditor_instances, limitError_fn).call(this);
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
__privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
|
|
310
|
+
insertHtml(this.editor, clean);
|
|
311
|
+
__privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
|
|
312
|
+
}
|
|
313
|
+
/** Mescla as células tocadas pela seleção. */
|
|
314
|
+
mergeCells() {
|
|
315
|
+
const table = __privateMethod(this, _FxEditor_instances, currentTable_fn).call(this);
|
|
316
|
+
const editor = this.editor;
|
|
317
|
+
const range = editor ? getRange(editor, __privateGet(this, _lastRange)) : null;
|
|
318
|
+
if (!table || !range) return false;
|
|
319
|
+
const merged = mergeSelectedCells(table, range);
|
|
320
|
+
if (!merged) return false;
|
|
321
|
+
placeCaretAtEnd(merged);
|
|
322
|
+
__privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
|
|
323
|
+
return true;
|
|
324
|
+
}
|
|
325
|
+
/** Divide a célula mesclada atual. */
|
|
326
|
+
splitCell() {
|
|
327
|
+
const table = __privateMethod(this, _FxEditor_instances, currentTable_fn).call(this);
|
|
328
|
+
const editor = this.editor;
|
|
329
|
+
const range = editor ? getRange(editor, __privateGet(this, _lastRange)) : null;
|
|
330
|
+
const cell = editor ? closestInEditor(editor, range?.startContainer ?? null, "td,th") : null;
|
|
331
|
+
if (!table || !cell) return false;
|
|
332
|
+
const created = splitCell(table, cell);
|
|
333
|
+
if (!created.length) return false;
|
|
334
|
+
placeCaretAtEnd(cell);
|
|
335
|
+
__privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
|
|
336
|
+
return true;
|
|
337
|
+
}
|
|
338
|
+
getHtml() {
|
|
339
|
+
return this.value;
|
|
340
|
+
}
|
|
341
|
+
setHtml(html) {
|
|
342
|
+
this.value = html;
|
|
343
|
+
}
|
|
344
|
+
getText() {
|
|
345
|
+
return this.text;
|
|
346
|
+
}
|
|
347
|
+
clear() {
|
|
348
|
+
this.value = "";
|
|
349
|
+
__privateSet(this, _dirty, false);
|
|
350
|
+
__privateMethod(this, _FxEditor_instances, applyValue_fn).call(this, "");
|
|
351
|
+
this.updateFormValue();
|
|
352
|
+
__privateMethod(this, _FxEditor_instances, emitChange_fn).call(this);
|
|
353
|
+
this.focus();
|
|
354
|
+
}
|
|
355
|
+
undo() {
|
|
356
|
+
this.execute("undo");
|
|
357
|
+
}
|
|
358
|
+
redo() {
|
|
359
|
+
this.execute("redo");
|
|
360
|
+
}
|
|
361
|
+
saveSelection() {
|
|
362
|
+
if (this.editor) __privateSet(this, _lastRange, saveRange(this.editor) ?? __privateGet(this, _lastRange));
|
|
363
|
+
}
|
|
364
|
+
restoreSelection() {
|
|
365
|
+
__privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
|
|
366
|
+
}
|
|
367
|
+
openDialog(kind) {
|
|
368
|
+
if (kind === "link") void __privateMethod(this, _FxEditor_instances, openLinkDialog_fn).call(this);
|
|
369
|
+
else if (kind === "image") void __privateMethod(this, _FxEditor_instances, openImageDialog_fn).call(this);
|
|
370
|
+
else void __privateMethod(this, _FxEditor_instances, openVideoDialog_fn).call(this);
|
|
371
|
+
}
|
|
372
|
+
toggleSource() {
|
|
373
|
+
__privateMethod(this, _FxEditor_instances, toggleSource_fn).call(this);
|
|
374
|
+
}
|
|
375
|
+
toggleFullscreen() {
|
|
376
|
+
this.fullscreen = !this.fullscreen;
|
|
377
|
+
}
|
|
378
|
+
};
|
|
379
|
+
_built = new WeakMap();
|
|
380
|
+
_eventsBound = new WeakMap();
|
|
381
|
+
_initialized = new WeakMap();
|
|
382
|
+
_defaultValue = new WeakMap();
|
|
383
|
+
_value = new WeakMap();
|
|
384
|
+
_dirty = new WeakMap();
|
|
385
|
+
_sourceMode = new WeakMap();
|
|
386
|
+
_lastRange = new WeakMap();
|
|
387
|
+
_rafId = new WeakMap();
|
|
388
|
+
_emitTimer = new WeakMap();
|
|
389
|
+
_lastLimitError = new WeakMap();
|
|
390
|
+
_snapshotTimer = new WeakMap();
|
|
391
|
+
_history = new WeakMap();
|
|
392
|
+
_historyIndex = new WeakMap();
|
|
393
|
+
_imagePicker = new WeakMap();
|
|
394
|
+
_mediaFigure = new WeakMap();
|
|
395
|
+
_linkAnchor = new WeakMap();
|
|
396
|
+
_resizeDispose = new WeakMap();
|
|
397
|
+
_dialogReturnFocus = new WeakMap();
|
|
398
|
+
_dialogResolve = new WeakMap();
|
|
399
|
+
_disposers = new WeakMap();
|
|
400
|
+
_selectionRaf = new WeakMap();
|
|
401
|
+
_bodyOverflow = new WeakMap();
|
|
402
|
+
_FxEditor_instances = new WeakSet();
|
|
403
|
+
on_fn = function(target, type, handler, options) {
|
|
404
|
+
target.addEventListener(type, handler, options);
|
|
405
|
+
__privateGet(this, _disposers).push(() => target.removeEventListener(type, handler, options));
|
|
406
|
+
};
|
|
407
|
+
bindEvents_fn = function() {
|
|
408
|
+
const editor = this.editor;
|
|
409
|
+
const toolbar = this.toolbarEl;
|
|
410
|
+
if (!editor || !toolbar) return;
|
|
411
|
+
__privateMethod(this, _FxEditor_instances, on_fn).call(this, toolbar, "mousedown", (event) => {
|
|
412
|
+
const target = event.target;
|
|
413
|
+
__privateSet(this, _lastRange, saveRange(editor) ?? __privateGet(this, _lastRange));
|
|
414
|
+
__privateMethod(this, _FxEditor_instances, hideLinkOverlay_fn).call(this);
|
|
415
|
+
if (target.closest("button")) event.preventDefault();
|
|
416
|
+
});
|
|
417
|
+
__privateMethod(this, _FxEditor_instances, on_fn).call(this, toolbar, "click", (event) => {
|
|
418
|
+
const target = event.target.closest("[data-cmd],[data-action]");
|
|
419
|
+
if (!target || target.disabled) return;
|
|
420
|
+
const cmd = target.dataset.cmd;
|
|
421
|
+
const action = target.dataset.action;
|
|
422
|
+
if (cmd) __privateMethod(this, _FxEditor_instances, execCommand_fn).call(this, cmd);
|
|
423
|
+
else if (action) __privateMethod(this, _FxEditor_instances, action_fn).call(this, action);
|
|
424
|
+
});
|
|
425
|
+
__privateMethod(this, _FxEditor_instances, on_fn).call(this, toolbar, "change", (event) => {
|
|
426
|
+
const select = event.target.closest("[data-block]");
|
|
427
|
+
if (!select) return;
|
|
428
|
+
__privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
|
|
429
|
+
formatBlock(editor, select.value || "p");
|
|
430
|
+
__privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
|
|
431
|
+
});
|
|
432
|
+
__privateMethod(this, _FxEditor_instances, on_fn).call(this, toolbar, "input", (event) => {
|
|
433
|
+
const input = event.target.closest("[data-color]");
|
|
434
|
+
if (!input) return;
|
|
435
|
+
__privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
|
|
436
|
+
nativeExec("styleWithCSS", "true");
|
|
437
|
+
nativeExec(input.dataset.color ?? "foreColor", input.value);
|
|
438
|
+
__privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
|
|
439
|
+
});
|
|
440
|
+
__privateMethod(this, _FxEditor_instances, on_fn).call(this, toolbar, "keydown", (event) => __privateMethod(this, _FxEditor_instances, handleToolbarKeydown_fn).call(this, event));
|
|
441
|
+
__privateMethod(this, _FxEditor_instances, on_fn).call(this, toolbar, "focusin", (event) => {
|
|
442
|
+
const button = event.target.closest(".tb-btn");
|
|
443
|
+
if (button) __privateMethod(this, _FxEditor_instances, moveToolbarTabStop_fn).call(this, button);
|
|
444
|
+
});
|
|
445
|
+
__privateMethod(this, _FxEditor_instances, on_fn).call(this, editor, "input", (event) => {
|
|
446
|
+
event.stopPropagation();
|
|
447
|
+
__privateMethod(this, _FxEditor_instances, hideLinkOverlay_fn).call(this);
|
|
448
|
+
__privateSet(this, _dirty, true);
|
|
449
|
+
__privateMethod(this, _FxEditor_instances, updateEmpty_fn).call(this);
|
|
450
|
+
__privateMethod(this, _FxEditor_instances, scheduleEmit_fn).call(this);
|
|
451
|
+
__privateMethod(this, _FxEditor_instances, scheduleSnapshot_fn).call(this);
|
|
452
|
+
});
|
|
453
|
+
__privateMethod(this, _FxEditor_instances, on_fn).call(this, editor, "focus", () => {
|
|
454
|
+
this.dispatchEvent(new CustomEvent("focus", { bubbles: true, composed: true }));
|
|
455
|
+
});
|
|
456
|
+
__privateMethod(this, _FxEditor_instances, on_fn).call(this, editor, "blur", () => {
|
|
457
|
+
__privateSet(this, _lastRange, saveRange(editor) ?? __privateGet(this, _lastRange));
|
|
458
|
+
__privateMethod(this, _FxEditor_instances, emitNow_fn).call(this);
|
|
459
|
+
__privateMethod(this, _FxEditor_instances, emitChange_fn).call(this);
|
|
460
|
+
this.dispatchEvent(new CustomEvent("blur", { bubbles: true, composed: true }));
|
|
461
|
+
});
|
|
462
|
+
__privateMethod(this, _FxEditor_instances, on_fn).call(this, editor, "keydown", (event) => __privateMethod(this, _FxEditor_instances, handleKeydown_fn).call(this, event));
|
|
463
|
+
__privateMethod(this, _FxEditor_instances, on_fn).call(this, editor, "beforeinput", (event) => __privateMethod(this, _FxEditor_instances, handleBeforeInput_fn).call(this, event));
|
|
464
|
+
__privateMethod(this, _FxEditor_instances, on_fn).call(this, editor, "paste", (event) => __privateMethod(this, _FxEditor_instances, handlePaste_fn).call(this, event));
|
|
465
|
+
__privateMethod(this, _FxEditor_instances, on_fn).call(this, editor, "dragover", (event) => event.preventDefault());
|
|
466
|
+
__privateMethod(this, _FxEditor_instances, on_fn).call(this, editor, "drop", (event) => __privateMethod(this, _FxEditor_instances, handleDrop_fn).call(this, event));
|
|
467
|
+
__privateMethod(this, _FxEditor_instances, on_fn).call(this, editor, "dblclick", (event) => __privateMethod(this, _FxEditor_instances, handleDoubleClick_fn).call(this, event));
|
|
468
|
+
__privateMethod(this, _FxEditor_instances, on_fn).call(this, editor, "click", (event) => __privateMethod(this, _FxEditor_instances, handleEditorClick_fn).call(this, event));
|
|
469
|
+
__privateMethod(this, _FxEditor_instances, on_fn).call(this, editor, "scroll", () => {
|
|
470
|
+
__privateMethod(this, _FxEditor_instances, positionMediaOverlay_fn).call(this);
|
|
471
|
+
__privateMethod(this, _FxEditor_instances, positionLinkOverlay_fn).call(this);
|
|
472
|
+
}, { passive: true });
|
|
473
|
+
__privateMethod(this, _FxEditor_instances, on_fn).call(this, window, "resize", () => {
|
|
474
|
+
__privateMethod(this, _FxEditor_instances, positionMediaOverlay_fn).call(this);
|
|
475
|
+
__privateMethod(this, _FxEditor_instances, positionLinkOverlay_fn).call(this);
|
|
476
|
+
});
|
|
477
|
+
const overlay = this.root.querySelector(".media-overlay");
|
|
478
|
+
if (overlay) {
|
|
479
|
+
__privateMethod(this, _FxEditor_instances, on_fn).call(this, overlay, "pointerdown", (event) => __privateMethod(this, _FxEditor_instances, startResize_fn).call(this, event));
|
|
480
|
+
__privateMethod(this, _FxEditor_instances, on_fn).call(this, overlay, "click", (event) => {
|
|
481
|
+
const action = event.target.closest("[data-media-action]");
|
|
482
|
+
if (action?.dataset.mediaAction === "delete") __privateMethod(this, _FxEditor_instances, deleteMediaFigure_fn).call(this);
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
const linkOverlay = this.root.querySelector(".link-overlay");
|
|
486
|
+
if (linkOverlay) {
|
|
487
|
+
__privateMethod(this, _FxEditor_instances, on_fn).call(this, linkOverlay, "click", (event) => __privateMethod(this, _FxEditor_instances, handleLinkOverlayClick_fn).call(this, event));
|
|
488
|
+
}
|
|
489
|
+
if (this.source) {
|
|
490
|
+
__privateMethod(this, _FxEditor_instances, on_fn).call(this, this.source, "input", () => {
|
|
491
|
+
__privateSet(this, _dirty, true);
|
|
492
|
+
__privateMethod(this, _FxEditor_instances, scheduleEmit_fn).call(this);
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
if (__privateGet(this, _imagePicker)) {
|
|
496
|
+
__privateMethod(this, _FxEditor_instances, on_fn).call(this, __privateGet(this, _imagePicker), "change", () => {
|
|
497
|
+
const file = __privateGet(this, _imagePicker)?.files?.[0];
|
|
498
|
+
if (file) void __privateMethod(this, _FxEditor_instances, handleImageFile_fn).call(this, file);
|
|
499
|
+
if (__privateGet(this, _imagePicker)) __privateGet(this, _imagePicker).value = "";
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
const backdrop = this.root.querySelector(".backdrop");
|
|
503
|
+
if (backdrop) {
|
|
504
|
+
__privateMethod(this, _FxEditor_instances, on_fn).call(this, backdrop, "click", (event) => {
|
|
505
|
+
if (event.target === backdrop) __privateMethod(this, _FxEditor_instances, releaseDialog_fn).call(this, null);
|
|
506
|
+
});
|
|
507
|
+
__privateMethod(this, _FxEditor_instances, on_fn).call(this, backdrop, "keydown", (event) => __privateMethod(this, _FxEditor_instances, trapDialogFocus_fn).call(this, event));
|
|
508
|
+
}
|
|
509
|
+
const dialogBody = this.root.querySelector(".dialog-body");
|
|
510
|
+
if (dialogBody) {
|
|
511
|
+
__privateMethod(this, _FxEditor_instances, on_fn).call(this, dialogBody, "keydown", (event) => {
|
|
512
|
+
const target = event.target;
|
|
513
|
+
if (event.key === "Enter" && target.tagName !== "BUTTON") {
|
|
514
|
+
event.preventDefault();
|
|
515
|
+
__privateMethod(this, _FxEditor_instances, submitDialog_fn).call(this);
|
|
516
|
+
}
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
for (const selector of [".dialog-close", ".dialog-cancel"]) {
|
|
520
|
+
const btn = this.root.querySelector(selector);
|
|
521
|
+
if (btn) __privateMethod(this, _FxEditor_instances, on_fn).call(this, btn, "click", () => __privateMethod(this, _FxEditor_instances, releaseDialog_fn).call(this, null));
|
|
522
|
+
}
|
|
523
|
+
const ok = this.root.querySelector(".dialog-ok");
|
|
524
|
+
if (ok) __privateMethod(this, _FxEditor_instances, on_fn).call(this, ok, "click", () => __privateMethod(this, _FxEditor_instances, submitDialog_fn).call(this));
|
|
525
|
+
const applySource = this.root.querySelector(".source-apply");
|
|
526
|
+
if (applySource) __privateMethod(this, _FxEditor_instances, on_fn).call(this, applySource, "click", () => __privateMethod(this, _FxEditor_instances, applySource_fn).call(this));
|
|
527
|
+
const cancelSource = this.root.querySelector(".source-cancel");
|
|
528
|
+
if (cancelSource) __privateMethod(this, _FxEditor_instances, on_fn).call(this, cancelSource, "click", () => __privateMethod(this, _FxEditor_instances, cancelSource_fn).call(this));
|
|
529
|
+
};
|
|
530
|
+
syncChrome_fn = function() {
|
|
531
|
+
const editor = this.editor;
|
|
532
|
+
if (!editor) return;
|
|
533
|
+
const locked = this.disabled || this.readonly;
|
|
534
|
+
editor.setAttribute("contenteditable", locked ? "false" : "true");
|
|
535
|
+
editor.setAttribute("aria-readonly", String(this.readonly));
|
|
536
|
+
editor.setAttribute("aria-disabled", String(this.disabled));
|
|
537
|
+
if (this.placeholder) editor.setAttribute("data-placeholder", this.placeholder);
|
|
538
|
+
else editor.removeAttribute("data-placeholder");
|
|
539
|
+
const toolbar = this.toolbarEl;
|
|
540
|
+
toolbar?.toggleAttribute("hidden", this.toolbar === "none" || this.readonly);
|
|
541
|
+
for (const control of Array.from(this.root.querySelectorAll(
|
|
542
|
+
".tb-btn, .tb-select, .tb-color input"
|
|
543
|
+
))) {
|
|
544
|
+
const isSourceToggle = control.closest('[data-action="source"]') !== null;
|
|
545
|
+
const isFullscreenToggle = control.closest('[data-action="fullscreen"]') !== null;
|
|
546
|
+
control.disabled = this.readonly || this.disabled || __privateGet(this, _sourceMode) && !isSourceToggle && !isFullscreenToggle;
|
|
547
|
+
}
|
|
548
|
+
__privateMethod(this, _FxEditor_instances, applyCssVars_fn).call(this);
|
|
549
|
+
__privateMethod(this, _FxEditor_instances, updateEmpty_fn).call(this);
|
|
550
|
+
__privateMethod(this, _FxEditor_instances, updateCount_fn).call(this);
|
|
551
|
+
__privateMethod(this, _FxEditor_instances, validate_fn).call(this);
|
|
552
|
+
__privateMethod(this, _FxEditor_instances, updateSourceUi_fn).call(this);
|
|
553
|
+
const fullscreenButton = this.root.querySelector('[data-action="fullscreen"]');
|
|
554
|
+
fullscreenButton?.classList.toggle("active", this.fullscreen);
|
|
555
|
+
fullscreenButton?.setAttribute("aria-pressed", String(this.fullscreen));
|
|
556
|
+
if (locked || __privateGet(this, _sourceMode)) __privateMethod(this, _FxEditor_instances, hideMediaOverlay_fn).call(this);
|
|
557
|
+
};
|
|
558
|
+
applyCssVars_fn = function() {
|
|
559
|
+
const min = this.getAttr("min-height");
|
|
560
|
+
const max = this.getAttr("max-height");
|
|
561
|
+
if (min) this.style.setProperty("--fx-editor-min-height", min);
|
|
562
|
+
else this.style.removeProperty("--fx-editor-min-height");
|
|
563
|
+
if (max) this.style.setProperty("--fx-editor-max-height", max);
|
|
564
|
+
else this.style.removeProperty("--fx-editor-max-height");
|
|
565
|
+
};
|
|
566
|
+
updateEmpty_fn = function() {
|
|
567
|
+
const editor = this.editor;
|
|
568
|
+
if (!editor) return;
|
|
569
|
+
const empty = !editor.textContent?.trim() && !editor.querySelector("img,video,iframe,table,hr");
|
|
570
|
+
editor.classList.toggle("is-empty", empty);
|
|
571
|
+
};
|
|
572
|
+
updateCount_fn = function() {
|
|
573
|
+
const count = this.root.querySelector(".count");
|
|
574
|
+
if (!count) return;
|
|
575
|
+
const statusbar = this.root.querySelector(".statusbar");
|
|
576
|
+
const hasFooter = this.querySelector('[slot="footer"]') !== null;
|
|
577
|
+
if (statusbar) statusbar.hidden = !__privateGet(this, _sourceMode) && !this.hasAttr("show-count") && !hasFooter;
|
|
578
|
+
if (!this.hasAttr("show-count")) {
|
|
579
|
+
count.textContent = "";
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
582
|
+
const text = this.text;
|
|
583
|
+
const words = text ? text.split(/\s+/).filter(Boolean).length : 0;
|
|
584
|
+
count.textContent = `${words} palavra${words === 1 ? "" : "s"} · ${text.length} caractere${text.length === 1 ? "" : "s"}`;
|
|
585
|
+
};
|
|
586
|
+
fits_fn = function(extra) {
|
|
587
|
+
const max = this.maxlength;
|
|
588
|
+
if (!max) return true;
|
|
589
|
+
const editor = this.editor;
|
|
590
|
+
const range = editor ? getRange(editor, __privateGet(this, _lastRange)) : null;
|
|
591
|
+
const selected = range && !range.collapsed ? range.toString().length : 0;
|
|
592
|
+
return this.text.length - selected + extra <= max;
|
|
593
|
+
};
|
|
594
|
+
limitError_fn = function() {
|
|
595
|
+
const now = Date.now();
|
|
596
|
+
if (now - __privateGet(this, _lastLimitError) < 1200) return;
|
|
597
|
+
__privateSet(this, _lastLimitError, now);
|
|
598
|
+
__privateMethod(this, _FxEditor_instances, error_fn).call(this, `Limite de ${this.maxlength.toLocaleString("pt-BR")} caracteres atingido.`);
|
|
599
|
+
};
|
|
600
|
+
validate_fn = function() {
|
|
601
|
+
if (!this.internals || typeof this.internals.setValidity !== "function") return;
|
|
602
|
+
try {
|
|
603
|
+
if (this.required && !this.text) {
|
|
604
|
+
this.internals.setValidity(
|
|
605
|
+
{ valueMissing: true },
|
|
606
|
+
"Preencha este campo.",
|
|
607
|
+
this.editor ?? void 0
|
|
608
|
+
);
|
|
609
|
+
} else {
|
|
610
|
+
this.internals.setValidity({});
|
|
611
|
+
}
|
|
612
|
+
} catch {
|
|
613
|
+
}
|
|
614
|
+
};
|
|
615
|
+
/** Sanitiza + normaliza em uma única parseada do HTML. */
|
|
616
|
+
cleanHtml_fn = function(html, forEditor = false) {
|
|
617
|
+
const body = sanitizeBody(html);
|
|
618
|
+
if (!body) return forEditor ? "<p><br></p>" : "";
|
|
619
|
+
return normalizeElement(body, { forEditor });
|
|
620
|
+
};
|
|
621
|
+
serialize_fn = function() {
|
|
622
|
+
if (__privateGet(this, _sourceMode) && this.source) {
|
|
623
|
+
return __privateMethod(this, _FxEditor_instances, cleanHtml_fn).call(this, this.source.value);
|
|
624
|
+
}
|
|
625
|
+
const editor = this.editor;
|
|
626
|
+
if (!editor) return "";
|
|
627
|
+
if (!editor.textContent?.trim() && !editor.querySelector("img,video,iframe,table,hr")) return "";
|
|
628
|
+
let clean = __privateMethod(this, _FxEditor_instances, cleanHtml_fn).call(this, editor.innerHTML);
|
|
629
|
+
if (this.sanitizeHtml) {
|
|
630
|
+
clean = __privateMethod(this, _FxEditor_instances, cleanHtml_fn).call(this, this.sanitizeHtml(clean));
|
|
631
|
+
}
|
|
632
|
+
return clean;
|
|
633
|
+
};
|
|
634
|
+
applyValue_fn = function(html) {
|
|
635
|
+
const editor = this.editor;
|
|
636
|
+
if (!editor) return;
|
|
637
|
+
__privateMethod(this, _FxEditor_instances, hideMediaOverlay_fn).call(this);
|
|
638
|
+
const normalized = __privateMethod(this, _FxEditor_instances, cleanHtml_fn).call(this, html, true);
|
|
639
|
+
if (editor.innerHTML !== normalized) editor.innerHTML = normalized;
|
|
640
|
+
__privateMethod(this, _FxEditor_instances, hideLinkOverlay_fn).call(this);
|
|
641
|
+
__privateMethod(this, _FxEditor_instances, hideMediaOverlay_fn).call(this);
|
|
642
|
+
__privateMethod(this, _FxEditor_instances, decorateMediaFigures_fn).call(this);
|
|
643
|
+
__privateMethod(this, _FxEditor_instances, updateEmpty_fn).call(this);
|
|
644
|
+
__privateMethod(this, _FxEditor_instances, updateCount_fn).call(this);
|
|
645
|
+
};
|
|
646
|
+
scheduleEmit_fn = function() {
|
|
647
|
+
cancelAnimationFrame(__privateGet(this, _rafId));
|
|
648
|
+
if (__privateGet(this, _emitTimer)) {
|
|
649
|
+
clearTimeout(__privateGet(this, _emitTimer));
|
|
650
|
+
__privateSet(this, _emitTimer, null);
|
|
651
|
+
}
|
|
652
|
+
const size = this.editor?.textContent?.length ?? 0;
|
|
653
|
+
if (size < LARGE_DOC_CHARS) {
|
|
654
|
+
__privateSet(this, _rafId, requestAnimationFrame(() => __privateMethod(this, _FxEditor_instances, emitNow_fn).call(this)));
|
|
655
|
+
return;
|
|
656
|
+
}
|
|
657
|
+
__privateSet(this, _emitTimer, setTimeout(() => {
|
|
658
|
+
__privateSet(this, _emitTimer, null);
|
|
659
|
+
__privateMethod(this, _FxEditor_instances, emitNow_fn).call(this);
|
|
660
|
+
}, EMIT_DEBOUNCE_MS));
|
|
661
|
+
};
|
|
662
|
+
emitNow_fn = function() {
|
|
663
|
+
cancelAnimationFrame(__privateGet(this, _rafId));
|
|
664
|
+
if (__privateGet(this, _emitTimer)) {
|
|
665
|
+
clearTimeout(__privateGet(this, _emitTimer));
|
|
666
|
+
__privateSet(this, _emitTimer, null);
|
|
667
|
+
}
|
|
668
|
+
const value = __privateMethod(this, _FxEditor_instances, serialize_fn).call(this);
|
|
669
|
+
__privateSet(this, _value, value);
|
|
670
|
+
__privateSet(this, _dirty, false);
|
|
671
|
+
const detail = { value, html: value, text: this.text };
|
|
672
|
+
for (const type of ["input", "valueChange"]) {
|
|
673
|
+
this.dispatchEvent(new CustomEvent(type, { bubbles: true, composed: true, detail }));
|
|
674
|
+
}
|
|
675
|
+
__privateMethod(this, _FxEditor_instances, updateCount_fn).call(this);
|
|
676
|
+
__privateMethod(this, _FxEditor_instances, validate_fn).call(this);
|
|
677
|
+
};
|
|
678
|
+
emitChange_fn = function() {
|
|
679
|
+
const value = this.value;
|
|
680
|
+
const detail = { value, html: value, text: this.text };
|
|
681
|
+
this.dispatchEvent(new CustomEvent("change", { bubbles: true, composed: true, detail }));
|
|
682
|
+
};
|
|
683
|
+
pushHistory_fn = function(html) {
|
|
684
|
+
if (__privateGet(this, _history)[__privateGet(this, _historyIndex)] === html) return;
|
|
685
|
+
__privateSet(this, _history, __privateGet(this, _history).slice(0, __privateGet(this, _historyIndex) + 1));
|
|
686
|
+
__privateGet(this, _history).push(html);
|
|
687
|
+
if (__privateGet(this, _history).length > HISTORY_LIMIT) __privateGet(this, _history).shift();
|
|
688
|
+
__privateSet(this, _historyIndex, __privateGet(this, _history).length - 1);
|
|
689
|
+
};
|
|
690
|
+
scheduleSnapshot_fn = function() {
|
|
691
|
+
if (__privateGet(this, _snapshotTimer)) clearTimeout(__privateGet(this, _snapshotTimer));
|
|
692
|
+
__privateSet(this, _snapshotTimer, setTimeout(() => {
|
|
693
|
+
__privateMethod(this, _FxEditor_instances, pushHistory_fn).call(this, __privateGet(this, _dirty) ? __privateMethod(this, _FxEditor_instances, serialize_fn).call(this) : __privateGet(this, _value));
|
|
694
|
+
}, 600));
|
|
695
|
+
};
|
|
696
|
+
historyUndo_fn = function() {
|
|
697
|
+
if (__privateGet(this, _historyIndex) <= 0) return;
|
|
698
|
+
__privateWrapper(this, _historyIndex)._--;
|
|
699
|
+
__privateMethod(this, _FxEditor_instances, applyValue_fn).call(this, __privateGet(this, _history)[__privateGet(this, _historyIndex)]);
|
|
700
|
+
if (this.editor) placeCaretAtEnd(this.editor);
|
|
701
|
+
__privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
|
|
702
|
+
};
|
|
703
|
+
historyRedo_fn = function() {
|
|
704
|
+
if (__privateGet(this, _historyIndex) >= __privateGet(this, _history).length - 1) return;
|
|
705
|
+
__privateWrapper(this, _historyIndex)._++;
|
|
706
|
+
__privateMethod(this, _FxEditor_instances, applyValue_fn).call(this, __privateGet(this, _history)[__privateGet(this, _historyIndex)]);
|
|
707
|
+
if (this.editor) placeCaretAtEnd(this.editor);
|
|
708
|
+
__privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
|
|
709
|
+
};
|
|
710
|
+
bindGlobalSelection_fn = function() {
|
|
711
|
+
const handler = () => {
|
|
712
|
+
const editor = this.editor;
|
|
713
|
+
if (!editor) return;
|
|
714
|
+
const range = getRange(editor, __privateGet(this, _lastRange));
|
|
715
|
+
if (!range) return;
|
|
716
|
+
__privateSet(this, _lastRange, range.cloneRange());
|
|
717
|
+
cancelAnimationFrame(__privateGet(this, _selectionRaf));
|
|
718
|
+
__privateSet(this, _selectionRaf, requestAnimationFrame(() => __privateMethod(this, _FxEditor_instances, updateToolbar_fn).call(this)));
|
|
719
|
+
};
|
|
720
|
+
document.addEventListener("selectionchange", handler);
|
|
721
|
+
__privateGet(this, _disposers).push(() => document.removeEventListener("selectionchange", handler));
|
|
722
|
+
};
|
|
723
|
+
restoreSelection_fn = function() {
|
|
724
|
+
const editor = this.editor;
|
|
725
|
+
if (!editor) return;
|
|
726
|
+
if (__privateGet(this, _lastRange)) restoreRange(editor, __privateGet(this, _lastRange));
|
|
727
|
+
else editor.focus({ preventScroll: true });
|
|
728
|
+
};
|
|
729
|
+
syncBodyOverflow_fn = function() {
|
|
730
|
+
if (this.fullscreen) {
|
|
731
|
+
__privateSet(this, _bodyOverflow, document.body.style.overflow);
|
|
732
|
+
document.body.style.overflow = "hidden";
|
|
733
|
+
} else {
|
|
734
|
+
document.body.style.overflow = __privateGet(this, _bodyOverflow);
|
|
735
|
+
}
|
|
736
|
+
};
|
|
737
|
+
updateSourceUi_fn = function() {
|
|
738
|
+
const source = this.source;
|
|
739
|
+
const content = this.editor;
|
|
740
|
+
const actions = this.root.querySelector(".source-actions");
|
|
741
|
+
if (actions) actions.toggleAttribute("hidden", !__privateGet(this, _sourceMode));
|
|
742
|
+
if (source) source.hidden = !__privateGet(this, _sourceMode);
|
|
743
|
+
if (content) content.hidden = __privateGet(this, _sourceMode);
|
|
744
|
+
const toggle = this.root.querySelector('[data-action="source"]');
|
|
745
|
+
toggle?.classList.toggle("active", __privateGet(this, _sourceMode));
|
|
746
|
+
toggle?.setAttribute("aria-pressed", String(__privateGet(this, _sourceMode)));
|
|
747
|
+
};
|
|
748
|
+
releaseDialog_fn = function(result) {
|
|
749
|
+
const backdrop = this.root.querySelector(".backdrop");
|
|
750
|
+
backdrop?.setAttribute("hidden", "");
|
|
751
|
+
const resolve = __privateGet(this, _dialogResolve);
|
|
752
|
+
__privateSet(this, _dialogResolve, null);
|
|
753
|
+
const returnFocus = __privateGet(this, _dialogReturnFocus);
|
|
754
|
+
__privateSet(this, _dialogReturnFocus, null);
|
|
755
|
+
resolve?.(result);
|
|
756
|
+
if (returnFocus && returnFocus.isConnected) returnFocus.focus({ preventScroll: true });
|
|
757
|
+
else __privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
|
|
758
|
+
};
|
|
759
|
+
renderToolbar_fn = function() {
|
|
760
|
+
const toolbar = this.toolbarEl;
|
|
761
|
+
if (!toolbar) return;
|
|
762
|
+
const preset = this.toolbar;
|
|
763
|
+
if (preset === "none") {
|
|
764
|
+
toolbar.innerHTML = "";
|
|
765
|
+
toolbar.hidden = true;
|
|
766
|
+
return;
|
|
767
|
+
}
|
|
768
|
+
toolbar.hidden = false;
|
|
769
|
+
const features = new Set(
|
|
770
|
+
this.getAttr("features").split(",").map((item) => item.trim()).filter(Boolean)
|
|
771
|
+
);
|
|
772
|
+
const has = (feature) => features.size === 0 || features.has(feature);
|
|
773
|
+
const button = (cmd, icon, label, action = "") => `<button type="button" class="tb-btn" tabindex="-1" ${action ? `data-action="${action}"` : `data-cmd="${cmd}"`} title="${label}" aria-label="${label}" aria-pressed="false">${fenixIconHtml(icon)}</button>`;
|
|
774
|
+
const select = `<select class="tb-select" data-block aria-label="Formato do bloco">
|
|
775
|
+
<option value="p">Parágrafo</option>
|
|
776
|
+
<option value="h1">Título 1</option>
|
|
777
|
+
<option value="h2">Título 2</option>
|
|
778
|
+
<option value="h3">Título 3</option>
|
|
779
|
+
<option value="h4">Título 4</option>
|
|
780
|
+
<option value="blockquote">Citação</option>
|
|
781
|
+
<option value="pre">Código</option>
|
|
782
|
+
</select>`;
|
|
783
|
+
const history = button("undo", "undo", "Desfazer") + button("redo", "redo", "Refazer");
|
|
784
|
+
const inline = [
|
|
785
|
+
button("bold", "format_bold", "Negrito"),
|
|
786
|
+
button("italic", "format_italic", "Itálico"),
|
|
787
|
+
button("underline", "format_underlined", "Sublinhado"),
|
|
788
|
+
button("strikeThrough", "format_strikethrough", "Riscado"),
|
|
789
|
+
button("code", "code", "Código inline"),
|
|
790
|
+
button("removeFormat", "format_clear", "Limpar formatação")
|
|
791
|
+
].join("");
|
|
792
|
+
const color = [
|
|
793
|
+
`<label class="tb-color" title="Cor do texto"><input type="color" data-color="foreColor" value="#111827" aria-label="Cor do texto"></label>`,
|
|
794
|
+
`<label class="tb-color" title="Realçar texto"><input type="color" data-color="hiliteColor" value="#fef08a" aria-label="Realçar texto"></label>`
|
|
795
|
+
].join("");
|
|
796
|
+
const alignGroup = [
|
|
797
|
+
button("justifyLeft", "format_align_left", "Alinhar à esquerda"),
|
|
798
|
+
button("justifyCenter", "format_align_center", "Centralizar"),
|
|
799
|
+
button("justifyRight", "format_align_right", "Alinhar à direita"),
|
|
800
|
+
button("justifyFull", "format_align_justify", "Justificar")
|
|
801
|
+
].join("");
|
|
802
|
+
const indentation = [
|
|
803
|
+
button("outdent", "format_indent_decrease", "Diminuir recuo", "outdent"),
|
|
804
|
+
button("indent", "format_indent_increase", "Aumentar recuo", "indent")
|
|
805
|
+
].join("");
|
|
806
|
+
const lists = [
|
|
807
|
+
button("insertUnorderedList", "format_list_bulleted", "Lista com marcadores"),
|
|
808
|
+
button("insertOrderedList", "format_list_numbered", "Lista numerada")
|
|
809
|
+
].join("");
|
|
810
|
+
const blocks = button("", "format_quote", "Citação", "blockquote") + button("", "code_blocks", "Bloco de código", "codeblock");
|
|
811
|
+
const insert = [];
|
|
812
|
+
if (has("link")) {
|
|
813
|
+
insert.push(button("", "link", "Link (Ctrl+K)", "link"));
|
|
814
|
+
insert.push(button("", "link_off", "Remover link", "unlink"));
|
|
815
|
+
}
|
|
816
|
+
if (preset !== "minimal") {
|
|
817
|
+
if (has("image")) insert.push(button("", "image", "Imagem", "image"));
|
|
818
|
+
if (has("video")) insert.push(button("", "videocam", "Vídeo", "video"));
|
|
819
|
+
if (has("table")) insert.push(button("", "table", "Tabela", "table"));
|
|
820
|
+
if (has("columns")) insert.push(button("", "view_column", "Colunas", "columns"));
|
|
821
|
+
insert.push(button("insertHorizontalRule", "horizontal_rule", "Linha horizontal"));
|
|
822
|
+
}
|
|
823
|
+
const tools = [];
|
|
824
|
+
if (preset === "standard" || preset === "full") {
|
|
825
|
+
if (has("source")) tools.push(button("", "code", "Ver HTML", "source"));
|
|
826
|
+
if (has("fullscreen")) tools.push(button("", "fullscreen", "Tela cheia", "fullscreen"));
|
|
827
|
+
}
|
|
828
|
+
const groups = [history, select + inline];
|
|
829
|
+
if (preset !== "minimal") groups.push(lists);
|
|
830
|
+
if (preset !== "minimal" && preset !== "basic") {
|
|
831
|
+
groups.push(color, alignGroup, indentation, blocks);
|
|
832
|
+
}
|
|
833
|
+
if (insert.length) groups.push(insert.join(""));
|
|
834
|
+
if (tools.length) groups.push(tools.join(""));
|
|
835
|
+
toolbar.innerHTML = groups.map((group) => `<div class="tb-group">${group}</div>`).join("") + `<div class="panel" data-panel hidden></div>`;
|
|
836
|
+
toolbar.querySelector(".tb-btn")?.setAttribute("tabindex", "0");
|
|
837
|
+
};
|
|
838
|
+
updateToolbar_fn = function() {
|
|
839
|
+
const editor = this.editor;
|
|
840
|
+
if (!editor) return;
|
|
841
|
+
const range = getRange(editor, __privateGet(this, _lastRange));
|
|
842
|
+
if (!range) return;
|
|
843
|
+
const setActive = (cmd, active) => {
|
|
844
|
+
const button = this.root.querySelector(`[data-cmd="${cmd}"]`);
|
|
845
|
+
if (!button) return;
|
|
846
|
+
button.classList.toggle("active", active);
|
|
847
|
+
button.setAttribute("aria-pressed", String(active));
|
|
848
|
+
};
|
|
849
|
+
const ancestor = (selector) => {
|
|
850
|
+
const node = range.startContainer;
|
|
851
|
+
const el = node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;
|
|
852
|
+
const match = el?.closest(selector);
|
|
853
|
+
return Boolean(match && editor.contains(match));
|
|
854
|
+
};
|
|
855
|
+
setActive("bold", ancestor("strong,b"));
|
|
856
|
+
setActive("italic", ancestor("em,i"));
|
|
857
|
+
setActive("underline", ancestor("u"));
|
|
858
|
+
setActive("strikeThrough", ancestor("s,del,strike"));
|
|
859
|
+
setActive("code", ancestor("code"));
|
|
860
|
+
setActive("insertUnorderedList", ancestor("ul"));
|
|
861
|
+
setActive("insertOrderedList", ancestor("ol"));
|
|
862
|
+
const block = getBlock(editor, range);
|
|
863
|
+
const blockTag = block?.tagName.toLowerCase() ?? "p";
|
|
864
|
+
const blockSelect = this.root.querySelector("[data-block]");
|
|
865
|
+
if (blockSelect) {
|
|
866
|
+
const value = Array.from(blockSelect.options).some((option) => option.value === blockTag) ? blockTag : "p";
|
|
867
|
+
blockSelect.value = value;
|
|
868
|
+
}
|
|
869
|
+
const alignment = block ? block.style.textAlign || "left" : "left";
|
|
870
|
+
setActive("justifyLeft", alignment === "left" || alignment === "start" || alignment === "");
|
|
871
|
+
setActive("justifyCenter", alignment === "center");
|
|
872
|
+
setActive("justifyRight", alignment === "right" || alignment === "end");
|
|
873
|
+
setActive("justifyFull", alignment === "justify");
|
|
874
|
+
};
|
|
875
|
+
handleToolbarKeydown_fn = function(event) {
|
|
876
|
+
const active = this.root.activeElement;
|
|
877
|
+
if (!active || !active.classList.contains("tb-btn")) return;
|
|
878
|
+
if (!["ArrowRight", "ArrowLeft", "Home", "End"].includes(event.key)) return;
|
|
879
|
+
const controls = Array.from(
|
|
880
|
+
this.toolbarEl?.querySelectorAll(
|
|
881
|
+
".tb-btn:not(:disabled), .tb-select:not(:disabled), .tb-color input:not(:disabled)"
|
|
882
|
+
) ?? []
|
|
883
|
+
);
|
|
884
|
+
if (!controls.length) return;
|
|
885
|
+
event.preventDefault();
|
|
886
|
+
let index = controls.indexOf(active);
|
|
887
|
+
if (event.key === "Home") index = 0;
|
|
888
|
+
else if (event.key === "End") index = controls.length - 1;
|
|
889
|
+
else index = (index + (event.key === "ArrowRight" ? 1 : -1) + controls.length) % controls.length;
|
|
890
|
+
const next = controls[index];
|
|
891
|
+
if (!next) return;
|
|
892
|
+
__privateMethod(this, _FxEditor_instances, moveToolbarTabStop_fn).call(this, next);
|
|
893
|
+
next.focus();
|
|
894
|
+
};
|
|
895
|
+
moveToolbarTabStop_fn = function(active) {
|
|
896
|
+
this.toolbarEl?.querySelectorAll(".tb-btn").forEach((button) => {
|
|
897
|
+
button.setAttribute("tabindex", button === active ? "0" : "-1");
|
|
898
|
+
});
|
|
899
|
+
};
|
|
900
|
+
trapDialogFocus_fn = function(event) {
|
|
901
|
+
if (!__privateGet(this, _dialogResolve) || event.key !== "Tab") return;
|
|
902
|
+
const dialog = this.root.querySelector(".dialog");
|
|
903
|
+
if (!dialog) return;
|
|
904
|
+
const focusables = Array.from(
|
|
905
|
+
dialog.querySelectorAll(
|
|
906
|
+
'button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), a[href], [tabindex]:not([tabindex="-1"])'
|
|
907
|
+
)
|
|
908
|
+
);
|
|
909
|
+
if (!focusables.length) return;
|
|
910
|
+
const first = focusables[0];
|
|
911
|
+
const last = focusables[focusables.length - 1];
|
|
912
|
+
const active = this.root.activeElement;
|
|
913
|
+
if (event.shiftKey && (active === first || !active || !dialog.contains(active))) {
|
|
914
|
+
event.preventDefault();
|
|
915
|
+
last.focus();
|
|
916
|
+
} else if (!event.shiftKey && (active === last || !active || !dialog.contains(active))) {
|
|
917
|
+
event.preventDefault();
|
|
918
|
+
first.focus();
|
|
919
|
+
}
|
|
920
|
+
};
|
|
921
|
+
execCommand_fn = function(cmd) {
|
|
922
|
+
const editor = this.editor;
|
|
923
|
+
if (!editor) return;
|
|
924
|
+
__privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
|
|
925
|
+
switch (cmd) {
|
|
926
|
+
case "undo":
|
|
927
|
+
if (!nativeExec("undo")) __privateMethod(this, _FxEditor_instances, historyUndo_fn).call(this);
|
|
928
|
+
break;
|
|
929
|
+
case "redo":
|
|
930
|
+
if (!nativeExec("redo")) __privateMethod(this, _FxEditor_instances, historyRedo_fn).call(this);
|
|
931
|
+
break;
|
|
932
|
+
case "bold":
|
|
933
|
+
toggleInline(editor, "strong");
|
|
934
|
+
break;
|
|
935
|
+
case "italic":
|
|
936
|
+
toggleInline(editor, "em");
|
|
937
|
+
break;
|
|
938
|
+
case "underline":
|
|
939
|
+
toggleInline(editor, "u");
|
|
940
|
+
break;
|
|
941
|
+
case "strikeThrough":
|
|
942
|
+
toggleInline(editor, "s");
|
|
943
|
+
break;
|
|
944
|
+
case "code":
|
|
945
|
+
toggleInline(editor, "code");
|
|
946
|
+
break;
|
|
947
|
+
case "justifyLeft":
|
|
948
|
+
align(editor, "left");
|
|
949
|
+
break;
|
|
950
|
+
case "justifyCenter":
|
|
951
|
+
align(editor, "center");
|
|
952
|
+
break;
|
|
953
|
+
case "justifyRight":
|
|
954
|
+
align(editor, "right");
|
|
955
|
+
break;
|
|
956
|
+
case "justifyFull":
|
|
957
|
+
align(editor, "justify");
|
|
958
|
+
break;
|
|
959
|
+
case "insertUnorderedList":
|
|
960
|
+
toggleList(editor, false);
|
|
961
|
+
break;
|
|
962
|
+
case "insertOrderedList":
|
|
963
|
+
toggleList(editor, true);
|
|
964
|
+
break;
|
|
965
|
+
case "removeFormat":
|
|
966
|
+
removeFormat(editor);
|
|
967
|
+
break;
|
|
968
|
+
case "insertHorizontalRule":
|
|
969
|
+
insertHtml(editor, "<hr><p><br></p>");
|
|
970
|
+
break;
|
|
971
|
+
case "foreColor":
|
|
972
|
+
case "hiliteColor":
|
|
973
|
+
nativeExec("styleWithCSS", "true");
|
|
974
|
+
nativeExec(cmd, this.root.querySelector(`[data-color="${cmd}"]`)?.value);
|
|
975
|
+
break;
|
|
976
|
+
default:
|
|
977
|
+
nativeExec(cmd);
|
|
978
|
+
}
|
|
979
|
+
__privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
|
|
980
|
+
};
|
|
981
|
+
afterCommand_fn = function() {
|
|
982
|
+
__privateSet(this, _dirty, true);
|
|
983
|
+
__privateMethod(this, _FxEditor_instances, hideLinkOverlay_fn).call(this);
|
|
984
|
+
__privateMethod(this, _FxEditor_instances, decorateMediaFigures_fn).call(this);
|
|
985
|
+
__privateMethod(this, _FxEditor_instances, updateEmpty_fn).call(this);
|
|
986
|
+
__privateMethod(this, _FxEditor_instances, scheduleEmit_fn).call(this);
|
|
987
|
+
__privateMethod(this, _FxEditor_instances, scheduleSnapshot_fn).call(this);
|
|
988
|
+
__privateMethod(this, _FxEditor_instances, updateToolbar_fn).call(this);
|
|
989
|
+
};
|
|
990
|
+
action_fn = function(action) {
|
|
991
|
+
const editor = this.editor;
|
|
992
|
+
if (!editor) return;
|
|
993
|
+
switch (action) {
|
|
994
|
+
case "link":
|
|
995
|
+
void __privateMethod(this, _FxEditor_instances, openLinkDialog_fn).call(this);
|
|
996
|
+
break;
|
|
997
|
+
case "image":
|
|
998
|
+
void __privateMethod(this, _FxEditor_instances, openImageDialog_fn).call(this);
|
|
999
|
+
break;
|
|
1000
|
+
case "video":
|
|
1001
|
+
void __privateMethod(this, _FxEditor_instances, openVideoDialog_fn).call(this);
|
|
1002
|
+
break;
|
|
1003
|
+
case "table":
|
|
1004
|
+
__privateMethod(this, _FxEditor_instances, showTablePanel_fn).call(this);
|
|
1005
|
+
break;
|
|
1006
|
+
case "columns":
|
|
1007
|
+
__privateMethod(this, _FxEditor_instances, showColumnsPanel_fn).call(this);
|
|
1008
|
+
break;
|
|
1009
|
+
case "source":
|
|
1010
|
+
__privateMethod(this, _FxEditor_instances, toggleSource_fn).call(this);
|
|
1011
|
+
break;
|
|
1012
|
+
case "fullscreen":
|
|
1013
|
+
this.fullscreen = !this.fullscreen;
|
|
1014
|
+
break;
|
|
1015
|
+
case "blockquote":
|
|
1016
|
+
__privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
|
|
1017
|
+
formatBlock(editor, "blockquote");
|
|
1018
|
+
__privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
|
|
1019
|
+
break;
|
|
1020
|
+
case "codeblock":
|
|
1021
|
+
__privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
|
|
1022
|
+
formatBlock(editor, "pre");
|
|
1023
|
+
__privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
|
|
1024
|
+
break;
|
|
1025
|
+
case "indent":
|
|
1026
|
+
__privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
|
|
1027
|
+
indent(editor, 24);
|
|
1028
|
+
__privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
|
|
1029
|
+
break;
|
|
1030
|
+
case "outdent":
|
|
1031
|
+
__privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
|
|
1032
|
+
indent(editor, -24);
|
|
1033
|
+
__privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
|
|
1034
|
+
break;
|
|
1035
|
+
case "clear":
|
|
1036
|
+
__privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
|
|
1037
|
+
removeFormat(editor);
|
|
1038
|
+
__privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
|
|
1039
|
+
break;
|
|
1040
|
+
case "unlink":
|
|
1041
|
+
__privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
|
|
1042
|
+
unlink(editor);
|
|
1043
|
+
__privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
|
|
1044
|
+
break;
|
|
1045
|
+
}
|
|
1046
|
+
};
|
|
1047
|
+
handleKeydown_fn = function(event) {
|
|
1048
|
+
if (event.isComposing) return;
|
|
1049
|
+
const active = this.root.activeElement;
|
|
1050
|
+
const overlay = this.root.querySelector(".media-overlay");
|
|
1051
|
+
if (__privateGet(this, _mediaFigure) && (event.key === "Delete" || event.key === "Backspace") && (active === __privateGet(this, _mediaFigure) || __privateGet(this, _mediaFigure).contains(active) || Boolean(overlay && active && overlay.contains(active)))) {
|
|
1052
|
+
event.preventDefault();
|
|
1053
|
+
__privateMethod(this, _FxEditor_instances, deleteMediaFigure_fn).call(this);
|
|
1054
|
+
return;
|
|
1055
|
+
}
|
|
1056
|
+
const mod = event.ctrlKey || event.metaKey;
|
|
1057
|
+
const key = event.key.toLowerCase();
|
|
1058
|
+
if (mod && !event.altKey) {
|
|
1059
|
+
if (key === "b") {
|
|
1060
|
+
event.preventDefault();
|
|
1061
|
+
__privateMethod(this, _FxEditor_instances, execCommand_fn).call(this, "bold");
|
|
1062
|
+
return;
|
|
1063
|
+
}
|
|
1064
|
+
if (key === "i") {
|
|
1065
|
+
event.preventDefault();
|
|
1066
|
+
__privateMethod(this, _FxEditor_instances, execCommand_fn).call(this, "italic");
|
|
1067
|
+
return;
|
|
1068
|
+
}
|
|
1069
|
+
if (key === "u") {
|
|
1070
|
+
event.preventDefault();
|
|
1071
|
+
__privateMethod(this, _FxEditor_instances, execCommand_fn).call(this, "underline");
|
|
1072
|
+
return;
|
|
1073
|
+
}
|
|
1074
|
+
if (key === "k") {
|
|
1075
|
+
event.preventDefault();
|
|
1076
|
+
void __privateMethod(this, _FxEditor_instances, openLinkDialog_fn).call(this);
|
|
1077
|
+
return;
|
|
1078
|
+
}
|
|
1079
|
+
if (key === "z" && !event.shiftKey) {
|
|
1080
|
+
event.preventDefault();
|
|
1081
|
+
__privateMethod(this, _FxEditor_instances, execCommand_fn).call(this, "undo");
|
|
1082
|
+
return;
|
|
1083
|
+
}
|
|
1084
|
+
if (key === "y" || key === "z" && event.shiftKey) {
|
|
1085
|
+
event.preventDefault();
|
|
1086
|
+
__privateMethod(this, _FxEditor_instances, execCommand_fn).call(this, "redo");
|
|
1087
|
+
return;
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
if (event.key === "Escape") {
|
|
1091
|
+
if (__privateGet(this, _dialogResolve)) __privateMethod(this, _FxEditor_instances, releaseDialog_fn).call(this, null);
|
|
1092
|
+
else if (__privateGet(this, _sourceMode)) __privateMethod(this, _FxEditor_instances, cancelSource_fn).call(this);
|
|
1093
|
+
else if (this.fullscreen) this.fullscreen = false;
|
|
1094
|
+
else if (__privateGet(this, _linkAnchor)) __privateMethod(this, _FxEditor_instances, hideLinkOverlay_fn).call(this);
|
|
1095
|
+
else if (__privateGet(this, _mediaFigure)) __privateMethod(this, _FxEditor_instances, hideMediaOverlay_fn).call(this);
|
|
1096
|
+
else __privateMethod(this, _FxEditor_instances, hidePanel_fn).call(this);
|
|
1097
|
+
return;
|
|
1098
|
+
}
|
|
1099
|
+
if (event.key === "Tab" && __privateMethod(this, _FxEditor_instances, tabInTable_fn).call(this, event.shiftKey)) {
|
|
1100
|
+
event.preventDefault();
|
|
1101
|
+
}
|
|
1102
|
+
};
|
|
1103
|
+
tabInTable_fn = function(backwards) {
|
|
1104
|
+
const editor = this.editor;
|
|
1105
|
+
if (!editor) return false;
|
|
1106
|
+
const range = getRange(editor, __privateGet(this, _lastRange));
|
|
1107
|
+
if (!range) return false;
|
|
1108
|
+
const cell = closestInEditor(editor, range.startContainer, "td,th");
|
|
1109
|
+
const table = cell?.closest("table");
|
|
1110
|
+
if (!cell || !table) return false;
|
|
1111
|
+
const cells = Array.from(table.querySelectorAll("td,th"));
|
|
1112
|
+
let index = cells.indexOf(cell);
|
|
1113
|
+
if (index < 0) return false;
|
|
1114
|
+
if (backwards) {
|
|
1115
|
+
index = Math.max(0, index - 1);
|
|
1116
|
+
} else {
|
|
1117
|
+
index++;
|
|
1118
|
+
if (index >= cells.length) {
|
|
1119
|
+
const row = cell.parentElement;
|
|
1120
|
+
if (!row) return false;
|
|
1121
|
+
const clone = row.cloneNode(true);
|
|
1122
|
+
for (const cloned of Array.from(clone.querySelectorAll("td,th"))) {
|
|
1123
|
+
cloned.innerHTML = "<p><br></p>";
|
|
1124
|
+
}
|
|
1125
|
+
row.after(clone);
|
|
1126
|
+
cells.push(...Array.from(clone.querySelectorAll("td,th")));
|
|
1127
|
+
index = cells.indexOf(clone.querySelector("td,th"));
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
const target = cells[index];
|
|
1131
|
+
if (!target) return false;
|
|
1132
|
+
const next = document.createRange();
|
|
1133
|
+
next.selectNodeContents(target);
|
|
1134
|
+
next.collapse(true);
|
|
1135
|
+
const selection = document.getSelection();
|
|
1136
|
+
selection?.removeAllRanges();
|
|
1137
|
+
selection?.addRange(next);
|
|
1138
|
+
return true;
|
|
1139
|
+
};
|
|
1140
|
+
handleBeforeInput_fn = function(event) {
|
|
1141
|
+
if (this.disabled || this.readonly || !this.maxlength) return;
|
|
1142
|
+
const type = event.inputType;
|
|
1143
|
+
if (type === "insertFromPaste" || type === "insertFromDrop" || type.startsWith("history") || type.startsWith("format")) {
|
|
1144
|
+
return;
|
|
1145
|
+
}
|
|
1146
|
+
const extra = event.data?.length ?? (type === "insertParagraph" || type === "insertLineBreak" ? 1 : 0);
|
|
1147
|
+
if (!extra) return;
|
|
1148
|
+
if (!__privateMethod(this, _FxEditor_instances, fits_fn).call(this, extra)) {
|
|
1149
|
+
event.preventDefault();
|
|
1150
|
+
__privateMethod(this, _FxEditor_instances, limitError_fn).call(this);
|
|
1151
|
+
}
|
|
1152
|
+
};
|
|
1153
|
+
handlePaste_fn = function(event) {
|
|
1154
|
+
const clipboard = event.clipboardData;
|
|
1155
|
+
if (!clipboard) return;
|
|
1156
|
+
const file = Array.from(clipboard.files ?? []).find((item) => item.type.startsWith("image/"));
|
|
1157
|
+
if (file) {
|
|
1158
|
+
event.preventDefault();
|
|
1159
|
+
void __privateMethod(this, _FxEditor_instances, handleImageFile_fn).call(this, file);
|
|
1160
|
+
return;
|
|
1161
|
+
}
|
|
1162
|
+
const html = clipboard.getData("text/html");
|
|
1163
|
+
const text = clipboard.getData("text/plain");
|
|
1164
|
+
if (html.length > MAX_PASTE_BYTES || text.length > MAX_PASTE_BYTES) return;
|
|
1165
|
+
event.preventDefault();
|
|
1166
|
+
if (!__privateMethod(this, _FxEditor_instances, fits_fn).call(this, text.length)) {
|
|
1167
|
+
__privateMethod(this, _FxEditor_instances, limitError_fn).call(this);
|
|
1168
|
+
return;
|
|
1169
|
+
}
|
|
1170
|
+
if (this.pasteMode === "plain" || !html) {
|
|
1171
|
+
__privateMethod(this, _FxEditor_instances, insertPlainText_fn).call(this, text);
|
|
1172
|
+
return;
|
|
1173
|
+
}
|
|
1174
|
+
const clean = __privateMethod(this, _FxEditor_instances, cleanHtml_fn).call(this, html);
|
|
1175
|
+
if (!clean) {
|
|
1176
|
+
__privateMethod(this, _FxEditor_instances, insertPlainText_fn).call(this, text);
|
|
1177
|
+
return;
|
|
1178
|
+
}
|
|
1179
|
+
__privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
|
|
1180
|
+
insertHtml(this.editor, clean);
|
|
1181
|
+
__privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
|
|
1182
|
+
};
|
|
1183
|
+
handleDrop_fn = function(event) {
|
|
1184
|
+
const transfer = event.dataTransfer;
|
|
1185
|
+
if (!transfer) return;
|
|
1186
|
+
event.preventDefault();
|
|
1187
|
+
const file = Array.from(transfer.files ?? []).find((item) => item.type.startsWith("image/"));
|
|
1188
|
+
if (file) {
|
|
1189
|
+
void __privateMethod(this, _FxEditor_instances, handleImageFile_fn).call(this, file);
|
|
1190
|
+
return;
|
|
1191
|
+
}
|
|
1192
|
+
const html = transfer.getData("text/html");
|
|
1193
|
+
const text = transfer.getData("text/plain");
|
|
1194
|
+
if (!__privateMethod(this, _FxEditor_instances, fits_fn).call(this, text.length)) {
|
|
1195
|
+
__privateMethod(this, _FxEditor_instances, limitError_fn).call(this);
|
|
1196
|
+
return;
|
|
1197
|
+
}
|
|
1198
|
+
if (html) {
|
|
1199
|
+
insertHtml(this.editor, __privateMethod(this, _FxEditor_instances, cleanHtml_fn).call(this, html));
|
|
1200
|
+
__privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
|
|
1201
|
+
} else if (text) {
|
|
1202
|
+
__privateMethod(this, _FxEditor_instances, insertPlainText_fn).call(this, text);
|
|
1203
|
+
}
|
|
1204
|
+
};
|
|
1205
|
+
insertPlainText_fn = function(text) {
|
|
1206
|
+
const paragraphs = text.replace(/\r\n/g, "\n").split(/\n{2,}/).map((block) => `<p>${escapeText(block).replace(/\n/g, "<br>")}</p>`).join("");
|
|
1207
|
+
insertHtml(this.editor, paragraphs || "<p><br></p>");
|
|
1208
|
+
__privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
|
|
1209
|
+
};
|
|
1210
|
+
toggleSource_fn = function() {
|
|
1211
|
+
if (__privateGet(this, _sourceMode)) {
|
|
1212
|
+
__privateMethod(this, _FxEditor_instances, applySource_fn).call(this);
|
|
1213
|
+
return;
|
|
1214
|
+
}
|
|
1215
|
+
const source = this.source;
|
|
1216
|
+
if (!source) return;
|
|
1217
|
+
source.value = __privateMethod(this, _FxEditor_instances, serialize_fn).call(this);
|
|
1218
|
+
__privateSet(this, _sourceMode, true);
|
|
1219
|
+
__privateMethod(this, _FxEditor_instances, syncChrome_fn).call(this);
|
|
1220
|
+
source.focus();
|
|
1221
|
+
};
|
|
1222
|
+
applySource_fn = function() {
|
|
1223
|
+
const source = this.source;
|
|
1224
|
+
if (!source) return;
|
|
1225
|
+
const clean = __privateMethod(this, _FxEditor_instances, cleanHtml_fn).call(this, source.value);
|
|
1226
|
+
__privateSet(this, _sourceMode, false);
|
|
1227
|
+
__privateSet(this, _value, clean);
|
|
1228
|
+
__privateSet(this, _dirty, false);
|
|
1229
|
+
__privateMethod(this, _FxEditor_instances, applyValue_fn).call(this, clean);
|
|
1230
|
+
__privateMethod(this, _FxEditor_instances, syncChrome_fn).call(this);
|
|
1231
|
+
this.updateFormValue();
|
|
1232
|
+
__privateMethod(this, _FxEditor_instances, emitChange_fn).call(this);
|
|
1233
|
+
__privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
|
|
1234
|
+
};
|
|
1235
|
+
cancelSource_fn = function() {
|
|
1236
|
+
__privateSet(this, _sourceMode, false);
|
|
1237
|
+
__privateMethod(this, _FxEditor_instances, applyValue_fn).call(this, __privateGet(this, _value));
|
|
1238
|
+
__privateMethod(this, _FxEditor_instances, syncChrome_fn).call(this);
|
|
1239
|
+
};
|
|
1240
|
+
openDialog_fn = function(title, fields) {
|
|
1241
|
+
const backdrop = this.root.querySelector(".backdrop");
|
|
1242
|
+
const titleEl = this.root.querySelector(".dialog h3");
|
|
1243
|
+
const body = this.root.querySelector(".dialog-body");
|
|
1244
|
+
if (!backdrop || !titleEl || !body) return Promise.resolve(null);
|
|
1245
|
+
titleEl.textContent = title;
|
|
1246
|
+
body.innerHTML = fields.map((field) => __privateMethod(this, _FxEditor_instances, fieldHtml_fn).call(this, field)).join("");
|
|
1247
|
+
__privateSet(this, _dialogReturnFocus, this.root.activeElement ?? this.editor);
|
|
1248
|
+
backdrop.removeAttribute("hidden");
|
|
1249
|
+
const first = body.querySelector("input,select");
|
|
1250
|
+
first?.focus();
|
|
1251
|
+
return new Promise((resolve) => {
|
|
1252
|
+
__privateSet(this, _dialogResolve, resolve);
|
|
1253
|
+
});
|
|
1254
|
+
};
|
|
1255
|
+
fieldHtml_fn = function(field) {
|
|
1256
|
+
const label = esc(field.label);
|
|
1257
|
+
if (field.type === "select") {
|
|
1258
|
+
const options = (field.options ?? []).map((option) => `<option value="${esc(option.value)}" ${option.value === field.value ? "selected" : ""}>${esc(option.label)}</option>`).join("");
|
|
1259
|
+
return `<label class="field"><span>${label}</span><select data-field="${esc(field.name)}">${options}</select></label>`;
|
|
1260
|
+
}
|
|
1261
|
+
const type = field.type === "url" ? "url" : field.type === "number" ? "number" : "text";
|
|
1262
|
+
return `<label class="field"><span>${label}</span><input data-field="${esc(field.name)}" type="${type}" value="${esc(field.value ?? "")}" placeholder="${esc(field.placeholder ?? "")}"></label>`;
|
|
1263
|
+
};
|
|
1264
|
+
submitDialog_fn = function() {
|
|
1265
|
+
const body = this.root.querySelector(".dialog-body");
|
|
1266
|
+
if (!body) return;
|
|
1267
|
+
const result = {};
|
|
1268
|
+
for (const field of Array.from(body.querySelectorAll("[data-field]"))) {
|
|
1269
|
+
result[field.dataset.field ?? ""] = field.value.trim();
|
|
1270
|
+
}
|
|
1271
|
+
__privateMethod(this, _FxEditor_instances, releaseDialog_fn).call(this, result);
|
|
1272
|
+
};
|
|
1273
|
+
openLinkDialog_fn = async function(existing) {
|
|
1274
|
+
__privateMethod(this, _FxEditor_instances, hideLinkOverlay_fn).call(this);
|
|
1275
|
+
const editor = this.editor;
|
|
1276
|
+
if (!editor) return;
|
|
1277
|
+
if (existing) __privateMethod(this, _FxEditor_instances, selectAnchor_fn).call(this, existing);
|
|
1278
|
+
let range = getRange(editor, __privateGet(this, _lastRange));
|
|
1279
|
+
if (!range) {
|
|
1280
|
+
placeCaretAtEnd(editor);
|
|
1281
|
+
range = getRange(editor);
|
|
1282
|
+
__privateSet(this, _lastRange, range?.cloneRange() ?? null);
|
|
1283
|
+
}
|
|
1284
|
+
const anchor = existing ?? closestInEditor(editor, range?.startContainer ?? null, "a");
|
|
1285
|
+
const selected = range && !range.collapsed ? range.toString() : anchor?.textContent ?? "";
|
|
1286
|
+
const result = await __privateMethod(this, _FxEditor_instances, openDialog_fn).call(this, "Link", [
|
|
1287
|
+
{ name: "url", label: "URL", type: "url", value: anchor?.getAttribute("href") ?? "", placeholder: "https://..." },
|
|
1288
|
+
{ name: "text", label: "Texto (quando não há seleção)", value: selected, placeholder: "Texto do link" },
|
|
1289
|
+
{
|
|
1290
|
+
name: "target",
|
|
1291
|
+
label: "Abrir em",
|
|
1292
|
+
type: "select",
|
|
1293
|
+
value: anchor?.getAttribute("target") ?? "_blank",
|
|
1294
|
+
options: [
|
|
1295
|
+
{ value: "_blank", label: "Nova aba" },
|
|
1296
|
+
{ value: "_self", label: "Mesma aba" }
|
|
1297
|
+
]
|
|
1298
|
+
}
|
|
1299
|
+
]);
|
|
1300
|
+
if (!result) return;
|
|
1301
|
+
const href = sanitizeLinkUrl(result.url ?? "");
|
|
1302
|
+
if (!href) {
|
|
1303
|
+
__privateMethod(this, _FxEditor_instances, error_fn).call(this, "URL de link inválida.");
|
|
1304
|
+
return;
|
|
1305
|
+
}
|
|
1306
|
+
const target = result.target === "_self" ? "_self" : "_blank";
|
|
1307
|
+
const label = (result.text ?? "").trim() || (anchor ? void 0 : selected || href);
|
|
1308
|
+
if (anchor) {
|
|
1309
|
+
anchor.setAttribute("href", href);
|
|
1310
|
+
anchor.setAttribute("target", target);
|
|
1311
|
+
anchor.setAttribute("rel", "noopener noreferrer");
|
|
1312
|
+
if (label) anchor.textContent = label;
|
|
1313
|
+
__privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
|
|
1314
|
+
__privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
|
|
1315
|
+
return;
|
|
1316
|
+
}
|
|
1317
|
+
__privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
|
|
1318
|
+
applyLink(editor, href, label ?? (selected || href), target);
|
|
1319
|
+
__privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
|
|
1320
|
+
};
|
|
1321
|
+
openImageDialog_fn = async function(existing) {
|
|
1322
|
+
__privateMethod(this, _FxEditor_instances, hideMediaOverlay_fn).call(this);
|
|
1323
|
+
const figure = existing?.closest("figure");
|
|
1324
|
+
const caption = figure?.querySelector("figcaption")?.textContent ?? "";
|
|
1325
|
+
const alignValue = figure?.getAttribute("data-align") ?? "center";
|
|
1326
|
+
const widthValue = figure?.style.width?.replace("%", "") || "100";
|
|
1327
|
+
const dialog = __privateMethod(this, _FxEditor_instances, openDialog_fn).call(this, existing ? "Editar imagem" : "Inserir imagem", [
|
|
1328
|
+
{ name: "src", label: "URL da imagem", type: "url", value: existing?.getAttribute("src") ?? "", placeholder: "https://..." },
|
|
1329
|
+
{ name: "alt", label: "Texto alternativo", value: existing?.getAttribute("alt") ?? "" },
|
|
1330
|
+
{ name: "caption", label: "Legenda", value: caption },
|
|
1331
|
+
{
|
|
1332
|
+
name: "width",
|
|
1333
|
+
label: "Largura",
|
|
1334
|
+
type: "select",
|
|
1335
|
+
value: widthValue,
|
|
1336
|
+
options: [
|
|
1337
|
+
{ value: "25", label: "25%" },
|
|
1338
|
+
{ value: "50", label: "50%" },
|
|
1339
|
+
{ value: "75", label: "75%" },
|
|
1340
|
+
{ value: "100", label: "100%" }
|
|
1341
|
+
]
|
|
1342
|
+
},
|
|
1343
|
+
{
|
|
1344
|
+
name: "align",
|
|
1345
|
+
label: "Alinhamento",
|
|
1346
|
+
type: "select",
|
|
1347
|
+
value: alignValue,
|
|
1348
|
+
options: [
|
|
1349
|
+
{ value: "left", label: "Esquerda" },
|
|
1350
|
+
{ value: "center", label: "Centro" },
|
|
1351
|
+
{ value: "right", label: "Direita" }
|
|
1352
|
+
]
|
|
1353
|
+
}
|
|
1354
|
+
]);
|
|
1355
|
+
const body = this.root.querySelector(".dialog-body");
|
|
1356
|
+
if (body) {
|
|
1357
|
+
const upload = document.createElement("button");
|
|
1358
|
+
upload.type = "button";
|
|
1359
|
+
upload.className = "btn";
|
|
1360
|
+
upload.textContent = "Escolher arquivo…";
|
|
1361
|
+
upload.addEventListener("click", () => {
|
|
1362
|
+
__privateMethod(this, _FxEditor_instances, releaseDialog_fn).call(this, null);
|
|
1363
|
+
__privateGet(this, _imagePicker)?.click();
|
|
1364
|
+
});
|
|
1365
|
+
body.appendChild(upload);
|
|
1366
|
+
}
|
|
1367
|
+
const result = await dialog;
|
|
1368
|
+
if (!result) return;
|
|
1369
|
+
const src = sanitizeMediaUrl(result.src ?? "", "img");
|
|
1370
|
+
if (!src) {
|
|
1371
|
+
__privateMethod(this, _FxEditor_instances, error_fn).call(this, "URL de imagem inválida.");
|
|
1372
|
+
return;
|
|
1373
|
+
}
|
|
1374
|
+
if (existing && figure) {
|
|
1375
|
+
existing.setAttribute("src", src);
|
|
1376
|
+
existing.setAttribute("alt", result.alt ?? "");
|
|
1377
|
+
figure.setAttribute("data-align", result.align || "center");
|
|
1378
|
+
figure.style.width = `${result.width || 100}%`;
|
|
1379
|
+
const cap = figure.querySelector("figcaption");
|
|
1380
|
+
if (result.caption) {
|
|
1381
|
+
if (cap) cap.textContent = result.caption;
|
|
1382
|
+
else figure.insertAdjacentHTML("beforeend", `<figcaption>${escapeText(result.caption)}</figcaption>`);
|
|
1383
|
+
} else {
|
|
1384
|
+
cap?.remove();
|
|
1385
|
+
}
|
|
1386
|
+
__privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
|
|
1387
|
+
return;
|
|
1388
|
+
}
|
|
1389
|
+
__privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
|
|
1390
|
+
__privateMethod(this, _FxEditor_instances, insertImage_fn).call(this, src, result.alt ?? "", result.caption ?? "", result.width || "100", result.align || "center");
|
|
1391
|
+
};
|
|
1392
|
+
toEmbedUrl_fn = function(value) {
|
|
1393
|
+
try {
|
|
1394
|
+
const url = new URL(value);
|
|
1395
|
+
const host = url.hostname.replace(/^www\./, "");
|
|
1396
|
+
if (host === "youtu.be") {
|
|
1397
|
+
return `https://www.youtube-nocookie.com/embed/${url.pathname.slice(1)}`;
|
|
1398
|
+
}
|
|
1399
|
+
if (host === "youtube.com" || host === "m.youtube.com") {
|
|
1400
|
+
const id = url.searchParams.get("v");
|
|
1401
|
+
if (id) return `https://www.youtube-nocookie.com/embed/${id}`;
|
|
1402
|
+
if (url.pathname.startsWith("/shorts/")) {
|
|
1403
|
+
return `https://www.youtube-nocookie.com/embed/${url.pathname.split("/")[2] ?? ""}`;
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
if (host === "vimeo.com") {
|
|
1407
|
+
const id = url.pathname.split("/").filter(Boolean)[0];
|
|
1408
|
+
if (id) return `https://player.vimeo.com/video/${id}`;
|
|
1409
|
+
}
|
|
1410
|
+
return value;
|
|
1411
|
+
} catch {
|
|
1412
|
+
return value;
|
|
1413
|
+
}
|
|
1414
|
+
};
|
|
1415
|
+
openVideoDialog_fn = async function() {
|
|
1416
|
+
const result = await __privateMethod(this, _FxEditor_instances, openDialog_fn).call(this, "Inserir vídeo", [
|
|
1417
|
+
{ name: "src", label: "URL do vídeo ou embed", type: "url", placeholder: "https://.../video.mp4 ou YouTube/Vimeo" },
|
|
1418
|
+
{ name: "caption", label: "Legenda", value: "" },
|
|
1419
|
+
{
|
|
1420
|
+
name: "width",
|
|
1421
|
+
label: "Largura",
|
|
1422
|
+
type: "select",
|
|
1423
|
+
value: "100",
|
|
1424
|
+
options: [
|
|
1425
|
+
{ value: "50", label: "50%" },
|
|
1426
|
+
{ value: "75", label: "75%" },
|
|
1427
|
+
{ value: "100", label: "100%" }
|
|
1428
|
+
]
|
|
1429
|
+
},
|
|
1430
|
+
{
|
|
1431
|
+
name: "align",
|
|
1432
|
+
label: "Alinhamento",
|
|
1433
|
+
type: "select",
|
|
1434
|
+
value: "center",
|
|
1435
|
+
options: [
|
|
1436
|
+
{ value: "left", label: "Esquerda" },
|
|
1437
|
+
{ value: "center", label: "Centro" },
|
|
1438
|
+
{ value: "right", label: "Direita" }
|
|
1439
|
+
]
|
|
1440
|
+
}
|
|
1441
|
+
]);
|
|
1442
|
+
if (!result) return;
|
|
1443
|
+
const src = result.src ?? "";
|
|
1444
|
+
const embed = sanitizeEmbedUrl(__privateMethod(this, _FxEditor_instances, toEmbedUrl_fn).call(this, src));
|
|
1445
|
+
if (embed) {
|
|
1446
|
+
__privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
|
|
1447
|
+
__privateMethod(this, _FxEditor_instances, insertEmbed_fn).call(this, embed, result.caption ?? "", result.width || "100", result.align || "center");
|
|
1448
|
+
return;
|
|
1449
|
+
}
|
|
1450
|
+
const media = sanitizeMediaUrl(src, "video");
|
|
1451
|
+
if (!media) {
|
|
1452
|
+
__privateMethod(this, _FxEditor_instances, error_fn).call(this, "URL de vídeo inválida.");
|
|
1453
|
+
return;
|
|
1454
|
+
}
|
|
1455
|
+
__privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
|
|
1456
|
+
__privateMethod(this, _FxEditor_instances, insertVideo_fn).call(this, media, result.caption ?? "", result.width || "100", result.align || "center");
|
|
1457
|
+
};
|
|
1458
|
+
decorateMediaFigures_fn = function() {
|
|
1459
|
+
const editor = this.editor;
|
|
1460
|
+
if (!editor || __privateGet(this, _sourceMode)) return;
|
|
1461
|
+
for (const figure of Array.from(
|
|
1462
|
+
editor.querySelectorAll("figure.fx-image, figure.fx-video, figure.fx-embed")
|
|
1463
|
+
)) {
|
|
1464
|
+
if (figure.querySelector(":scope > .fx-media-quick")) {
|
|
1465
|
+
__privateMethod(this, _FxEditor_instances, syncQuickActions_fn).call(this, figure);
|
|
1466
|
+
continue;
|
|
1467
|
+
}
|
|
1468
|
+
for (const kind of ["left", "center", "right", "delete"]) {
|
|
1469
|
+
const label = kind === "delete" ? "Excluir mídia" : kind === "left" ? "Alinhar à esquerda" : kind === "center" ? "Centralizar" : "Alinhar à direita";
|
|
1470
|
+
const button = document.createElement("button");
|
|
1471
|
+
button.type = "button";
|
|
1472
|
+
button.className = `fx-media-quick quick-${kind}`;
|
|
1473
|
+
button.title = label;
|
|
1474
|
+
button.setAttribute("aria-label", label);
|
|
1475
|
+
if (kind === "delete") button.dataset.mediaDelete = "";
|
|
1476
|
+
else button.dataset.mediaAlign = kind;
|
|
1477
|
+
button.innerHTML = QUICK_SVG[kind];
|
|
1478
|
+
button.addEventListener("click", (event) => {
|
|
1479
|
+
event.preventDefault();
|
|
1480
|
+
event.stopPropagation();
|
|
1481
|
+
if (kind === "delete") {
|
|
1482
|
+
figure.remove();
|
|
1483
|
+
__privateMethod(this, _FxEditor_instances, hideMediaOverlay_fn).call(this);
|
|
1484
|
+
__privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
|
|
1485
|
+
} else {
|
|
1486
|
+
figure.setAttribute("data-align", kind);
|
|
1487
|
+
__privateMethod(this, _FxEditor_instances, syncQuickActions_fn).call(this, figure);
|
|
1488
|
+
__privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
|
|
1489
|
+
}
|
|
1490
|
+
});
|
|
1491
|
+
figure.appendChild(button);
|
|
1492
|
+
}
|
|
1493
|
+
__privateMethod(this, _FxEditor_instances, syncQuickActions_fn).call(this, figure);
|
|
1494
|
+
}
|
|
1495
|
+
};
|
|
1496
|
+
syncQuickActions_fn = function(figure) {
|
|
1497
|
+
const align2 = figure.getAttribute("data-align") || "center";
|
|
1498
|
+
for (const button of Array.from(
|
|
1499
|
+
figure.querySelectorAll(":scope > .fx-media-quick[data-media-align]")
|
|
1500
|
+
)) {
|
|
1501
|
+
button.classList.toggle("active", button.dataset.mediaAlign === align2);
|
|
1502
|
+
}
|
|
1503
|
+
};
|
|
1504
|
+
selectAnchor_fn = function(anchor) {
|
|
1505
|
+
const editor = this.editor;
|
|
1506
|
+
if (!editor) return;
|
|
1507
|
+
editor.focus({ preventScroll: true });
|
|
1508
|
+
const range = document.createRange();
|
|
1509
|
+
range.selectNodeContents(anchor);
|
|
1510
|
+
const selection = document.getSelection();
|
|
1511
|
+
if (!selection) return;
|
|
1512
|
+
selection.removeAllRanges();
|
|
1513
|
+
selection.addRange(range);
|
|
1514
|
+
__privateSet(this, _lastRange, range.cloneRange());
|
|
1515
|
+
};
|
|
1516
|
+
handleLinkOverlayClick_fn = function(event) {
|
|
1517
|
+
const action = event.target.closest("[data-link-action]");
|
|
1518
|
+
const anchor = __privateGet(this, _linkAnchor);
|
|
1519
|
+
if (!action || !anchor) return;
|
|
1520
|
+
event.preventDefault();
|
|
1521
|
+
event.stopPropagation();
|
|
1522
|
+
const kind = action.dataset.linkAction;
|
|
1523
|
+
if (kind === "open") __privateMethod(this, _FxEditor_instances, openLink_fn).call(this, anchor);
|
|
1524
|
+
else if (kind === "edit") void __privateMethod(this, _FxEditor_instances, openLinkDialog_fn).call(this, anchor);
|
|
1525
|
+
else if (kind === "remove") __privateMethod(this, _FxEditor_instances, removeLink_fn).call(this, anchor);
|
|
1526
|
+
};
|
|
1527
|
+
openLink_fn = function(anchor) {
|
|
1528
|
+
const href = anchor.getAttribute("href") ?? "";
|
|
1529
|
+
if (!href) return;
|
|
1530
|
+
__privateMethod(this, _FxEditor_instances, hideLinkOverlay_fn).call(this);
|
|
1531
|
+
const target = anchor.getAttribute("target") === "_self" ? "_self" : "_blank";
|
|
1532
|
+
window.open(href, target, target === "_blank" ? "noopener,noreferrer" : void 0);
|
|
1533
|
+
};
|
|
1534
|
+
removeLink_fn = function(anchor) {
|
|
1535
|
+
const parent = anchor.parentNode;
|
|
1536
|
+
if (!parent) return;
|
|
1537
|
+
while (anchor.firstChild) parent.insertBefore(anchor.firstChild, anchor);
|
|
1538
|
+
anchor.remove();
|
|
1539
|
+
__privateMethod(this, _FxEditor_instances, hideLinkOverlay_fn).call(this);
|
|
1540
|
+
__privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
|
|
1541
|
+
this.editor?.focus({ preventScroll: true });
|
|
1542
|
+
};
|
|
1543
|
+
showLinkOverlay_fn = function(anchor) {
|
|
1544
|
+
__privateSet(this, _linkAnchor, anchor);
|
|
1545
|
+
const overlay = this.root.querySelector(".link-overlay");
|
|
1546
|
+
if (!overlay) return;
|
|
1547
|
+
const target = anchor.getAttribute("target") === "_self" ? "mesma janela" : "nova aba";
|
|
1548
|
+
const open = overlay.querySelector('[data-link-action="open"]');
|
|
1549
|
+
if (open) open.title = `Abrir na ${target}`;
|
|
1550
|
+
overlay.hidden = false;
|
|
1551
|
+
__privateMethod(this, _FxEditor_instances, positionLinkOverlay_fn).call(this);
|
|
1552
|
+
};
|
|
1553
|
+
hideLinkOverlay_fn = function() {
|
|
1554
|
+
__privateSet(this, _linkAnchor, null);
|
|
1555
|
+
const overlay = this.root.querySelector(".link-overlay");
|
|
1556
|
+
if (overlay) overlay.hidden = true;
|
|
1557
|
+
};
|
|
1558
|
+
positionLinkOverlay_fn = function() {
|
|
1559
|
+
const overlay = this.root.querySelector(".link-overlay");
|
|
1560
|
+
const anchor = __privateGet(this, _linkAnchor);
|
|
1561
|
+
const editor = this.editor;
|
|
1562
|
+
if (!overlay) return;
|
|
1563
|
+
if (!anchor || !editor || __privateGet(this, _sourceMode) || !anchor.isConnected || !editor.contains(anchor)) {
|
|
1564
|
+
overlay.hidden = true;
|
|
1565
|
+
return;
|
|
1566
|
+
}
|
|
1567
|
+
const body = overlay.parentElement;
|
|
1568
|
+
if (!body) return;
|
|
1569
|
+
const bodyRect = body.getBoundingClientRect();
|
|
1570
|
+
const rect = anchor.getBoundingClientRect();
|
|
1571
|
+
if (!rect.width || !rect.height || rect.bottom < bodyRect.top || rect.top > bodyRect.bottom) {
|
|
1572
|
+
overlay.hidden = true;
|
|
1573
|
+
return;
|
|
1574
|
+
}
|
|
1575
|
+
overlay.hidden = false;
|
|
1576
|
+
const width = overlay.offsetWidth || 180;
|
|
1577
|
+
const height = overlay.offsetHeight || 30;
|
|
1578
|
+
const left = Math.max(4, Math.min(rect.left - bodyRect.left, bodyRect.width - width - 4));
|
|
1579
|
+
let top = rect.bottom - bodyRect.top + 6;
|
|
1580
|
+
if (top + height > bodyRect.height) top = rect.top - bodyRect.top - height - 6;
|
|
1581
|
+
overlay.style.left = `${left}px`;
|
|
1582
|
+
overlay.style.top = `${Math.max(4, top)}px`;
|
|
1583
|
+
};
|
|
1584
|
+
handleEditorClick_fn = function(event) {
|
|
1585
|
+
const target = event.target;
|
|
1586
|
+
const anchor = target.closest("a[href]");
|
|
1587
|
+
if (anchor && this.editor?.contains(anchor)) {
|
|
1588
|
+
__privateMethod(this, _FxEditor_instances, hideMediaOverlay_fn).call(this);
|
|
1589
|
+
__privateMethod(this, _FxEditor_instances, showLinkOverlay_fn).call(this, anchor);
|
|
1590
|
+
if (event.ctrlKey || event.metaKey) {
|
|
1591
|
+
event.preventDefault();
|
|
1592
|
+
__privateMethod(this, _FxEditor_instances, openLink_fn).call(this, anchor);
|
|
1593
|
+
}
|
|
1594
|
+
return;
|
|
1595
|
+
}
|
|
1596
|
+
__privateMethod(this, _FxEditor_instances, hideLinkOverlay_fn).call(this);
|
|
1597
|
+
const figure = target.closest("figure.fx-image, figure.fx-video, figure.fx-embed");
|
|
1598
|
+
if (figure) __privateMethod(this, _FxEditor_instances, showMediaOverlay_fn).call(this, figure);
|
|
1599
|
+
else __privateMethod(this, _FxEditor_instances, hideMediaOverlay_fn).call(this);
|
|
1600
|
+
};
|
|
1601
|
+
showMediaOverlay_fn = function(figure) {
|
|
1602
|
+
__privateSet(this, _mediaFigure, figure);
|
|
1603
|
+
figure.setAttribute("tabindex", "0");
|
|
1604
|
+
if (figure.classList.contains("fx-image")) figure.focus({ preventScroll: true });
|
|
1605
|
+
const overlay = this.root.querySelector(".media-overlay");
|
|
1606
|
+
if (!overlay) return;
|
|
1607
|
+
overlay.hidden = false;
|
|
1608
|
+
__privateMethod(this, _FxEditor_instances, positionMediaOverlay_fn).call(this);
|
|
1609
|
+
};
|
|
1610
|
+
hideMediaOverlay_fn = function() {
|
|
1611
|
+
__privateGet(this, _mediaFigure)?.removeAttribute("tabindex");
|
|
1612
|
+
__privateSet(this, _mediaFigure, null);
|
|
1613
|
+
const overlay = this.root.querySelector(".media-overlay");
|
|
1614
|
+
if (!overlay) return;
|
|
1615
|
+
overlay.hidden = true;
|
|
1616
|
+
const size = overlay.querySelector(".media-size");
|
|
1617
|
+
if (size) size.textContent = "";
|
|
1618
|
+
};
|
|
1619
|
+
deleteMediaFigure_fn = function() {
|
|
1620
|
+
const figure = __privateGet(this, _mediaFigure);
|
|
1621
|
+
if (!figure) return;
|
|
1622
|
+
figure.remove();
|
|
1623
|
+
__privateMethod(this, _FxEditor_instances, hideMediaOverlay_fn).call(this);
|
|
1624
|
+
__privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
|
|
1625
|
+
this.editor?.focus({ preventScroll: true });
|
|
1626
|
+
};
|
|
1627
|
+
positionMediaOverlay_fn = function() {
|
|
1628
|
+
const overlay = this.root.querySelector(".media-overlay");
|
|
1629
|
+
const figure = __privateGet(this, _mediaFigure);
|
|
1630
|
+
const editor = this.editor;
|
|
1631
|
+
if (!overlay) return;
|
|
1632
|
+
if (!figure || !editor || __privateGet(this, _sourceMode) || !figure.isConnected || !editor.contains(figure)) {
|
|
1633
|
+
overlay.hidden = true;
|
|
1634
|
+
return;
|
|
1635
|
+
}
|
|
1636
|
+
const body = overlay.parentElement;
|
|
1637
|
+
if (!body) return;
|
|
1638
|
+
const bodyRect = body.getBoundingClientRect();
|
|
1639
|
+
const rect = figure.getBoundingClientRect();
|
|
1640
|
+
if (!rect.width || !rect.height || rect.bottom < bodyRect.top || rect.top > bodyRect.bottom) {
|
|
1641
|
+
overlay.hidden = true;
|
|
1642
|
+
return;
|
|
1643
|
+
}
|
|
1644
|
+
overlay.hidden = false;
|
|
1645
|
+
overlay.style.left = `${rect.left - bodyRect.left}px`;
|
|
1646
|
+
overlay.style.top = `${rect.top - bodyRect.top}px`;
|
|
1647
|
+
overlay.style.width = `${rect.width}px`;
|
|
1648
|
+
overlay.style.height = `${rect.height}px`;
|
|
1649
|
+
const size = overlay.querySelector(".media-size");
|
|
1650
|
+
if (size) size.textContent = `${Math.round(rect.width)} × ${Math.round(rect.height)}`;
|
|
1651
|
+
};
|
|
1652
|
+
startResize_fn = function(event) {
|
|
1653
|
+
const handle = event.target.closest("[data-handle]");
|
|
1654
|
+
const figure = __privateGet(this, _mediaFigure);
|
|
1655
|
+
const editor = this.editor;
|
|
1656
|
+
if (!handle || !figure || !editor) return;
|
|
1657
|
+
event.preventDefault();
|
|
1658
|
+
event.stopPropagation();
|
|
1659
|
+
__privateMethod(this, _FxEditor_instances, endResize_fn).call(this);
|
|
1660
|
+
const parent = figure.parentElement;
|
|
1661
|
+
if (!parent) return;
|
|
1662
|
+
const parentWidth = parent.getBoundingClientRect().width || editor.clientWidth;
|
|
1663
|
+
if (!parentWidth) return;
|
|
1664
|
+
const rect = figure.getBoundingClientRect();
|
|
1665
|
+
const startWidth = rect.width ? rect.width / parentWidth * 100 : Number.parseFloat(figure.style.width) || 100;
|
|
1666
|
+
const startX = event.clientX;
|
|
1667
|
+
const direction = handle.dataset.handle?.includes("w") ? -1 : 1;
|
|
1668
|
+
const move = (moveEvent) => {
|
|
1669
|
+
const deltaPct = (moveEvent.clientX - startX) * direction * 100 / parentWidth;
|
|
1670
|
+
const width = Math.min(100, Math.max(15, startWidth + deltaPct));
|
|
1671
|
+
figure.style.width = `${width.toFixed(1).replace(/\.0$/, "")}%`;
|
|
1672
|
+
__privateMethod(this, _FxEditor_instances, positionMediaOverlay_fn).call(this);
|
|
1673
|
+
};
|
|
1674
|
+
const up = () => {
|
|
1675
|
+
__privateMethod(this, _FxEditor_instances, endResize_fn).call(this);
|
|
1676
|
+
__privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
|
|
1677
|
+
__privateMethod(this, _FxEditor_instances, positionMediaOverlay_fn).call(this);
|
|
1678
|
+
};
|
|
1679
|
+
window.addEventListener("pointermove", move);
|
|
1680
|
+
window.addEventListener("pointerup", up, { once: true });
|
|
1681
|
+
window.addEventListener("pointercancel", up, { once: true });
|
|
1682
|
+
__privateSet(this, _resizeDispose, () => {
|
|
1683
|
+
window.removeEventListener("pointermove", move);
|
|
1684
|
+
window.removeEventListener("pointerup", up);
|
|
1685
|
+
window.removeEventListener("pointercancel", up);
|
|
1686
|
+
});
|
|
1687
|
+
};
|
|
1688
|
+
endResize_fn = function() {
|
|
1689
|
+
var _a;
|
|
1690
|
+
(_a = __privateGet(this, _resizeDispose)) == null ? void 0 : _a.call(this);
|
|
1691
|
+
__privateSet(this, _resizeDispose, null);
|
|
1692
|
+
};
|
|
1693
|
+
handleDoubleClick_fn = function(event) {
|
|
1694
|
+
const target = event.target;
|
|
1695
|
+
const image = target.closest("img");
|
|
1696
|
+
if (image) {
|
|
1697
|
+
event.preventDefault();
|
|
1698
|
+
void __privateMethod(this, _FxEditor_instances, openImageDialog_fn).call(this, image);
|
|
1699
|
+
}
|
|
1700
|
+
};
|
|
1701
|
+
insertImage_fn = function(src, alt, caption, width, align2) {
|
|
1702
|
+
const html = `<figure class="fx-image" contenteditable="false" data-align="${escapeAttr(align2)}" style="width:${escapeAttr(width)}%"><img src="${escapeAttr(src)}" alt="${escapeAttr(alt)}" loading="lazy" decoding="async">${caption ? `<figcaption>${escapeText(caption)}</figcaption>` : ""}</figure><p><br></p>`;
|
|
1703
|
+
insertHtml(this.editor, html);
|
|
1704
|
+
__privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
|
|
1705
|
+
};
|
|
1706
|
+
insertVideo_fn = function(src, caption, width, align2 = "center") {
|
|
1707
|
+
const html = `<figure class="fx-video" contenteditable="false" data-align="${escapeAttr(align2)}" style="width:${escapeAttr(width)}%"><video controls preload="metadata" src="${escapeAttr(src)}" style="width:100%"></video>${caption ? `<figcaption>${escapeText(caption)}</figcaption>` : ""}</figure><p><br></p>`;
|
|
1708
|
+
insertHtml(this.editor, html);
|
|
1709
|
+
__privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
|
|
1710
|
+
};
|
|
1711
|
+
insertEmbed_fn = function(src, caption, width, align2 = "center") {
|
|
1712
|
+
const html = `<figure class="fx-embed" contenteditable="false" data-align="${escapeAttr(align2)}" style="width:${escapeAttr(width)}%"><iframe src="${escapeAttr(src)}" title="${escapeAttr(caption || "Vídeo")}" loading="lazy" allowfullscreen sandbox="allow-scripts allow-same-origin allow-presentation" referrerpolicy="strict-origin-when-cross-origin" style="width:100%;aspect-ratio:16/9;border:0"></iframe>${caption ? `<figcaption>${escapeText(caption)}</figcaption>` : ""}</figure><p><br></p>`;
|
|
1713
|
+
insertHtml(this.editor, html);
|
|
1714
|
+
__privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
|
|
1715
|
+
};
|
|
1716
|
+
insertTable_fn = function(rows, cols) {
|
|
1717
|
+
const rowCount = Math.min(20, Math.max(1, rows));
|
|
1718
|
+
const colCount = Math.min(12, Math.max(1, cols));
|
|
1719
|
+
const width = (100 / colCount).toFixed(4).replace(/\.?0+$/, "");
|
|
1720
|
+
const colsHtml = `<colgroup>${Array.from({ length: colCount }, () => `<col style="width:${width}%">`).join("")}</colgroup>`;
|
|
1721
|
+
const head = `<thead><tr>${Array.from({ length: colCount }, () => '<th scope="col"><p><br></p></th>').join("")}</tr></thead>`;
|
|
1722
|
+
const bodyRows = Math.max(0, rowCount - 1);
|
|
1723
|
+
const body = bodyRows ? `<tbody>${Array.from(
|
|
1724
|
+
{ length: bodyRows },
|
|
1725
|
+
() => `<tr>${Array.from({ length: colCount }, () => "<td><p><br></p></td>").join("")}</tr>`
|
|
1726
|
+
).join("")}</tbody>` : "";
|
|
1727
|
+
const html = `<figure class="fx-table"><table>${colsHtml}${head}${body}</table></figure><p><br></p>`;
|
|
1728
|
+
insertHtml(this.editor, html);
|
|
1729
|
+
__privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
|
|
1730
|
+
};
|
|
1731
|
+
insertColumns_fn = function(cols) {
|
|
1732
|
+
const count = Math.min(4, Math.max(1, cols));
|
|
1733
|
+
const width = (100 / count).toFixed(4).replace(/\.?0+$/, "");
|
|
1734
|
+
const cells = Array.from(
|
|
1735
|
+
{ length: count },
|
|
1736
|
+
() => `<td style="width:${width}%;vertical-align:top;padding:8px"><p><br></p></td>`
|
|
1737
|
+
).join("");
|
|
1738
|
+
const html = `<table class="fx-grid" role="presentation" data-cols="${count}" data-stack="sm" style="width:100%;border-collapse:collapse"><tbody><tr>${cells}</tr></tbody></table><p><br></p>`;
|
|
1739
|
+
insertHtml(this.editor, html);
|
|
1740
|
+
__privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
|
|
1741
|
+
};
|
|
1742
|
+
showTablePanel_fn = function() {
|
|
1743
|
+
const panel = this.root.querySelector("[data-panel]");
|
|
1744
|
+
if (!panel) return;
|
|
1745
|
+
const table = __privateMethod(this, _FxEditor_instances, currentTable_fn).call(this);
|
|
1746
|
+
const grid = Array.from({ length: 64 }, (_, index) => {
|
|
1747
|
+
const rows = Math.floor(index / 8) + 1;
|
|
1748
|
+
const cols = index % 8 + 1;
|
|
1749
|
+
return `<button type="button" data-grid="${rows},${cols}" aria-label="${rows} por ${cols}"></button>`;
|
|
1750
|
+
}).join("");
|
|
1751
|
+
panel.innerHTML = `<p class="panel-title">Inserir tabela</p><div class="grid-picker">${grid}</div>` + (table ? `<p class="panel-title" style="margin-top:8px">Tabela atual</p><div class="panel-actions"><button type="button" class="btn" data-table-action="add-row">+ Linha</button><button type="button" class="btn" data-table-action="add-col">+ Coluna</button><button type="button" class="btn" data-table-action="del-row">− Linha</button><button type="button" class="btn" data-table-action="del-col">− Coluna</button><button type="button" class="btn" data-table-action="toggle-header">Cabeçalho</button><button type="button" class="btn" data-table-action="merge-cells">Mesclar</button><button type="button" class="btn" data-table-action="split-cell">Dividir</button><button type="button" class="btn" data-table-action="del-table">Excluir tabela</button></div>` : "");
|
|
1752
|
+
panel.removeAttribute("hidden");
|
|
1753
|
+
panel.querySelectorAll("[data-grid]").forEach((button) => {
|
|
1754
|
+
button.addEventListener("click", () => {
|
|
1755
|
+
const [rows, cols] = (button.dataset.grid ?? "").split(",").map(Number);
|
|
1756
|
+
__privateMethod(this, _FxEditor_instances, hidePanel_fn).call(this);
|
|
1757
|
+
__privateMethod(this, _FxEditor_instances, insertTable_fn).call(this, rows, cols);
|
|
1758
|
+
});
|
|
1759
|
+
});
|
|
1760
|
+
panel.querySelectorAll("[data-table-action]").forEach((button) => {
|
|
1761
|
+
button.addEventListener("click", () => {
|
|
1762
|
+
__privateMethod(this, _FxEditor_instances, tableAction_fn).call(this, button.dataset.tableAction ?? "");
|
|
1763
|
+
__privateMethod(this, _FxEditor_instances, hidePanel_fn).call(this);
|
|
1764
|
+
});
|
|
1765
|
+
});
|
|
1766
|
+
};
|
|
1767
|
+
showColumnsPanel_fn = function() {
|
|
1768
|
+
const panel = this.root.querySelector("[data-panel]");
|
|
1769
|
+
if (!panel) return;
|
|
1770
|
+
panel.innerHTML = `<p class="panel-title">Inserir colunas</p><div class="panel-actions">` + [1, 2, 3, 4].map((count) => `<button type="button" class="btn" data-columns="${count}">${count}</button>`).join("") + `</div>`;
|
|
1771
|
+
panel.removeAttribute("hidden");
|
|
1772
|
+
panel.querySelectorAll("[data-columns]").forEach((button) => {
|
|
1773
|
+
button.addEventListener("click", () => {
|
|
1774
|
+
__privateMethod(this, _FxEditor_instances, hidePanel_fn).call(this);
|
|
1775
|
+
__privateMethod(this, _FxEditor_instances, insertColumns_fn).call(this, Number(button.dataset.columns ?? 1));
|
|
1776
|
+
});
|
|
1777
|
+
});
|
|
1778
|
+
};
|
|
1779
|
+
hidePanel_fn = function() {
|
|
1780
|
+
this.root.querySelector("[data-panel]")?.setAttribute("hidden", "");
|
|
1781
|
+
};
|
|
1782
|
+
currentTable_fn = function() {
|
|
1783
|
+
const editor = this.editor;
|
|
1784
|
+
if (!editor) return null;
|
|
1785
|
+
const range = getRange(editor, __privateGet(this, _lastRange));
|
|
1786
|
+
return closestInEditor(editor, range?.startContainer ?? null, "table");
|
|
1787
|
+
};
|
|
1788
|
+
tableAction_fn = function(action) {
|
|
1789
|
+
const table = __privateMethod(this, _FxEditor_instances, currentTable_fn).call(this);
|
|
1790
|
+
if (!table) return;
|
|
1791
|
+
const editor = this.editor;
|
|
1792
|
+
const range = editor ? getRange(editor, __privateGet(this, _lastRange)) : null;
|
|
1793
|
+
const cell = editor ? closestInEditor(editor, range?.startContainer ?? null, "td,th") : null;
|
|
1794
|
+
const row = cell?.parentElement;
|
|
1795
|
+
if (action === "merge-cells") {
|
|
1796
|
+
if (!range) return;
|
|
1797
|
+
const merged = mergeSelectedCells(table, range);
|
|
1798
|
+
if (!merged) return;
|
|
1799
|
+
placeCaretAtEnd(merged);
|
|
1800
|
+
__privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
|
|
1801
|
+
return;
|
|
1802
|
+
}
|
|
1803
|
+
if (action === "split-cell") {
|
|
1804
|
+
if (!cell) return;
|
|
1805
|
+
const created = splitCell(table, cell);
|
|
1806
|
+
if (!created.length) return;
|
|
1807
|
+
placeCaretAtEnd(cell);
|
|
1808
|
+
__privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
|
|
1809
|
+
return;
|
|
1810
|
+
}
|
|
1811
|
+
if (action === "add-row" && row) {
|
|
1812
|
+
const clone = row.cloneNode(true);
|
|
1813
|
+
for (const cloneCell of Array.from(clone.querySelectorAll("td,th"))) {
|
|
1814
|
+
cloneCell.innerHTML = "<p><br></p>";
|
|
1815
|
+
}
|
|
1816
|
+
row.after(clone);
|
|
1817
|
+
} else if (action === "add-col" && cell) {
|
|
1818
|
+
const index = Array.from(row?.children ?? []).indexOf(cell);
|
|
1819
|
+
for (const currentRow of Array.from(table.rows)) {
|
|
1820
|
+
const target = currentRow.cells[Math.max(0, index)];
|
|
1821
|
+
const clone = (target ?? currentRow.cells[currentRow.cells.length - 1])?.cloneNode(false);
|
|
1822
|
+
if (!clone) continue;
|
|
1823
|
+
clone.innerHTML = "<p><br></p>";
|
|
1824
|
+
currentRow.insertBefore(clone, target?.nextSibling ?? null);
|
|
1825
|
+
}
|
|
1826
|
+
} else if (action === "del-row" && row && table.rows.length > 1) {
|
|
1827
|
+
row.remove();
|
|
1828
|
+
} else if (action === "del-col" && cell && table.rows[0]?.cells.length > 1) {
|
|
1829
|
+
const index = Array.from(row?.children ?? []).indexOf(cell);
|
|
1830
|
+
for (const currentRow of Array.from(table.rows)) {
|
|
1831
|
+
currentRow.cells[index]?.remove();
|
|
1832
|
+
}
|
|
1833
|
+
} else if (action === "toggle-header") {
|
|
1834
|
+
const thead = table.tHead;
|
|
1835
|
+
if (thead && thead.rows.length) {
|
|
1836
|
+
const headerRow = thead.rows[0];
|
|
1837
|
+
for (const headerCell of Array.from(headerRow.cells)) {
|
|
1838
|
+
const td = document.createElement("td");
|
|
1839
|
+
td.innerHTML = headerCell.innerHTML;
|
|
1840
|
+
headerCell.replaceWith(td);
|
|
1841
|
+
}
|
|
1842
|
+
const tbody = table.tBodies[0] ?? table.createTBody();
|
|
1843
|
+
tbody.insertBefore(headerRow, tbody.firstChild);
|
|
1844
|
+
thead.remove();
|
|
1845
|
+
} else {
|
|
1846
|
+
const firstRow = table.rows[0];
|
|
1847
|
+
if (firstRow) {
|
|
1848
|
+
for (const firstCell of Array.from(firstRow.cells)) {
|
|
1849
|
+
const th = document.createElement("th");
|
|
1850
|
+
th.setAttribute("scope", "col");
|
|
1851
|
+
th.innerHTML = firstCell.innerHTML;
|
|
1852
|
+
firstCell.replaceWith(th);
|
|
1853
|
+
}
|
|
1854
|
+
table.createTHead().appendChild(firstRow);
|
|
1855
|
+
}
|
|
1856
|
+
}
|
|
1857
|
+
} else if (action === "del-table") {
|
|
1858
|
+
const figure = table.closest("figure.fx-table");
|
|
1859
|
+
(figure ?? table).remove();
|
|
1860
|
+
}
|
|
1861
|
+
__privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
|
|
1862
|
+
};
|
|
1863
|
+
handleImageFile_fn = async function(file) {
|
|
1864
|
+
if (!file.type.startsWith("image/")) {
|
|
1865
|
+
__privateMethod(this, _FxEditor_instances, error_fn).call(this, "O arquivo selecionado não é uma imagem.");
|
|
1866
|
+
return;
|
|
1867
|
+
}
|
|
1868
|
+
if (file.type === "image/svg+xml") {
|
|
1869
|
+
__privateMethod(this, _FxEditor_instances, error_fn).call(this, "SVG não é permitido por segurança. Use PNG, JPEG, WebP ou GIF.");
|
|
1870
|
+
return;
|
|
1871
|
+
}
|
|
1872
|
+
if (file.size > MAX_IMAGE_BYTES) {
|
|
1873
|
+
__privateMethod(this, _FxEditor_instances, error_fn).call(this, "Imagem muito grande (máximo 8 MB).");
|
|
1874
|
+
return;
|
|
1875
|
+
}
|
|
1876
|
+
let src = "";
|
|
1877
|
+
let alt = file.name.replace(/\.[a-z0-9]+$/i, "");
|
|
1878
|
+
try {
|
|
1879
|
+
if (this.uploadImage) {
|
|
1880
|
+
const uploaded = await this.uploadImage(file);
|
|
1881
|
+
if (typeof uploaded === "string") src = uploaded;
|
|
1882
|
+
else {
|
|
1883
|
+
src = uploaded.url;
|
|
1884
|
+
if (uploaded.alt) alt = uploaded.alt;
|
|
1885
|
+
}
|
|
1886
|
+
} else {
|
|
1887
|
+
src = await __privateMethod(this, _FxEditor_instances, fileToDataUrl_fn).call(this, file);
|
|
1888
|
+
}
|
|
1889
|
+
} catch {
|
|
1890
|
+
__privateMethod(this, _FxEditor_instances, error_fn).call(this, "Não foi possível processar a imagem.");
|
|
1891
|
+
return;
|
|
1892
|
+
}
|
|
1893
|
+
if (!src || !sanitizeMediaUrl(src, "img")) {
|
|
1894
|
+
__privateMethod(this, _FxEditor_instances, error_fn).call(this, "A imagem resultante não tem uma URL segura.");
|
|
1895
|
+
return;
|
|
1896
|
+
}
|
|
1897
|
+
__privateMethod(this, _FxEditor_instances, restoreSelection_fn).call(this);
|
|
1898
|
+
__privateMethod(this, _FxEditor_instances, insertImage_fn).call(this, src, alt, "", "100", "center");
|
|
1899
|
+
};
|
|
1900
|
+
fileToDataUrl_fn = async function(file) {
|
|
1901
|
+
const dataUrl = await new Promise((resolve, reject) => {
|
|
1902
|
+
const reader = new FileReader();
|
|
1903
|
+
reader.onload = () => resolve(String(reader.result ?? ""));
|
|
1904
|
+
reader.onerror = () => reject(new Error("read-error"));
|
|
1905
|
+
reader.readAsDataURL(file);
|
|
1906
|
+
});
|
|
1907
|
+
if (file.type === "image/gif") return dataUrl;
|
|
1908
|
+
return new Promise((resolve) => {
|
|
1909
|
+
const image = new Image();
|
|
1910
|
+
image.onload = () => {
|
|
1911
|
+
const maxWidth = 1600;
|
|
1912
|
+
const scale = Math.min(1, maxWidth / (image.naturalWidth || maxWidth));
|
|
1913
|
+
if (scale >= 1) {
|
|
1914
|
+
resolve(dataUrl);
|
|
1915
|
+
return;
|
|
1916
|
+
}
|
|
1917
|
+
const canvas = document.createElement("canvas");
|
|
1918
|
+
canvas.width = Math.round((image.naturalWidth || maxWidth) * scale);
|
|
1919
|
+
canvas.height = Math.round((image.naturalHeight || maxWidth) * scale);
|
|
1920
|
+
const context = canvas.getContext("2d");
|
|
1921
|
+
if (!context) {
|
|
1922
|
+
resolve(dataUrl);
|
|
1923
|
+
return;
|
|
1924
|
+
}
|
|
1925
|
+
context.drawImage(image, 0, 0, canvas.width, canvas.height);
|
|
1926
|
+
resolve(canvas.toDataURL("image/webp", 0.85));
|
|
1927
|
+
};
|
|
1928
|
+
image.onerror = () => resolve(dataUrl);
|
|
1929
|
+
image.src = dataUrl;
|
|
1930
|
+
});
|
|
1931
|
+
};
|
|
1932
|
+
error_fn = function(message) {
|
|
1933
|
+
this.dispatchEvent(
|
|
1934
|
+
new CustomEvent("editor-error", {
|
|
1935
|
+
bubbles: true,
|
|
1936
|
+
composed: true,
|
|
1937
|
+
detail: { message }
|
|
1938
|
+
})
|
|
1939
|
+
);
|
|
1940
|
+
};
|
|
1941
|
+
_FxEditor.styles = `${FENIX_ICON_BASE_CSS}
|
|
1942
|
+
${EDITOR_STYLES}`;
|
|
1943
|
+
let FxEditor = _FxEditor;
|
|
1944
|
+
function defineFxEditor() {
|
|
1945
|
+
return defineElement("fx-editor", FxEditor);
|
|
1946
|
+
}
|
|
1947
|
+
export {
|
|
1948
|
+
FxEditor,
|
|
1949
|
+
defineFxEditor
|
|
1950
|
+
};
|
|
1951
|
+
//# sourceMappingURL=editor.js.map
|