@componyx/ui 0.0.0-stage → 1.0.4

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.
Files changed (169) hide show
  1. package/AppSkin/AppSkin.css +1268 -0
  2. package/AppSkin/AppSkin.js +2748 -0
  3. package/AppSkin/Themes/Default.css +241 -0
  4. package/Base/Base.js +3407 -0
  5. package/Base/ComponentIcons.css +66 -0
  6. package/Base/Font/ComponentIcons.woff +0 -0
  7. package/Base/Font/UI.woff +0 -0
  8. package/Base/Library.js +8432 -0
  9. package/Base/NavigationManager.js +462 -0
  10. package/Base/ResponsiveTemplates.js +371 -0
  11. package/Base/Sanitizer.js +288 -0
  12. package/Base/Themes/Default.css +255 -0
  13. package/Base/UI.css +618 -0
  14. package/Base/UIResourcePath.js +6 -0
  15. package/Bindary/Bindary.js +2011 -0
  16. package/Bindary/Modules/Connection.js +216 -0
  17. package/Bindary/Modules/Core.js +854 -0
  18. package/Bindary/Modules/DataUpdater.js +351 -0
  19. package/Bindary/Modules/ExpressionEngine.js +347 -0
  20. package/Bindary/Modules/ProxyManager.js +482 -0
  21. package/Bindary/Modules/Renderer.js +605 -0
  22. package/Bindary/Modules/Router.js +291 -0
  23. package/Bindary/Modules/Scroller.js +89 -0
  24. package/Bindary/Modules/Template.js +1273 -0
  25. package/BookmarkSpy/BookmarkSpy.js +430 -0
  26. package/Box/Box.css +36 -0
  27. package/Box/Box.js +1685 -0
  28. package/Button/Button.css +470 -0
  29. package/Button/Button.js +1398 -0
  30. package/Button/Themes/Default.css +200 -0
  31. package/Carousel/Carousel.css +273 -0
  32. package/Carousel/Carousel.js +607 -0
  33. package/ColorButton/ColorButton.css +39 -0
  34. package/ColorButton/ColorButton.js +336 -0
  35. package/ColorPicker/ColorPicker.css +359 -0
  36. package/ColorPicker/ColorPicker.js +972 -0
  37. package/ComboBox/ComboBox.css +357 -0
  38. package/ComboBox/ComboBox.js +2342 -0
  39. package/ComboBox/Themes/Default.css +23 -0
  40. package/DataPager/DataPager.css +72 -0
  41. package/DataPager/DataPager.js +674 -0
  42. package/DatePicker/DatePicker.css +227 -0
  43. package/DatePicker/DatePicker.js +1531 -0
  44. package/DatePicker/Themes/Default.css +26 -0
  45. package/Dialog/Dialog.css +106 -0
  46. package/Dialog/Dialog.js +572 -0
  47. package/Dialog/Themes/Default.css +10 -0
  48. package/Editor/Data/Emoji.json +8285 -0
  49. package/Editor/Data/Special.json +1042 -0
  50. package/Editor/Editor.css +1562 -0
  51. package/Editor/Editor.js +4058 -0
  52. package/Editor/Font/Editor.woff +0 -0
  53. package/Editor/Modules/ComponentFactory.js +565 -0
  54. package/Editor/Modules/ContentManager.js +748 -0
  55. package/Editor/Modules/DialogManager.js +1234 -0
  56. package/Editor/Modules/EventManager.js +458 -0
  57. package/Editor/Modules/Format.js +950 -0
  58. package/Editor/Modules/History.js +191 -0
  59. package/Editor/Modules/LayoutState.js +379 -0
  60. package/Editor/Modules/ListManager.js +296 -0
  61. package/Editor/Modules/MenuManager.js +388 -0
  62. package/Editor/Modules/NodeManager.js +681 -0
  63. package/Editor/Modules/ParagraphButtons.js +122 -0
  64. package/Editor/Modules/Resizer.js +176 -0
  65. package/Editor/Modules/SelectionRange.js +564 -0
  66. package/Editor/Modules/SourceViewBuilder.js +212 -0
  67. package/Editor/Modules/SymbolPicker.js +208 -0
  68. package/Editor/Modules/Table.js +2327 -0
  69. package/Editor/Modules/TableDialog.js +757 -0
  70. package/Editor/Modules/Toolbar.js +375 -0
  71. package/Editor/Modules/TooltipMenu.js +125 -0
  72. package/Editor/Modules/Utility.js +131 -0
  73. package/Editor/Themes/Default.css +204 -0
  74. package/FileUpload/FileUpload.css +156 -0
  75. package/FileUpload/FileUpload.js +898 -0
  76. package/FileUpload/Themes/Default.css +17 -0
  77. package/Form/Form.css +1934 -0
  78. package/Form/Form.js +4943 -0
  79. package/Form/Modules/ActionManager.js +368 -0
  80. package/Form/Modules/BuildPanelManager.js +319 -0
  81. package/Form/Modules/ComponentFactory.js +468 -0
  82. package/Form/Modules/ComponentPanel.js +265 -0
  83. package/Form/Modules/ConfigPanelManager.js +685 -0
  84. package/Form/Modules/DataBinder.js +602 -0
  85. package/Form/Modules/DataObserver.js +717 -0
  86. package/Form/Modules/Draggable.js +756 -0
  87. package/Form/Modules/OptionsPanel.js +342 -0
  88. package/Form/Modules/Renderer.js +1889 -0
  89. package/Form/Modules/RuleEngine.js +585 -0
  90. package/Form/Modules/RulesPanel.js +1158 -0
  91. package/Form/Modules/Types.js +1709 -0
  92. package/Form/Modules/ValidationManager.js +194 -0
  93. package/Form/Themes/Default.css +216 -0
  94. package/FormField/FormField.css +468 -0
  95. package/FormField/FormField.js +576 -0
  96. package/FormField/Themes/Default.css +99 -0
  97. package/Grid/Grid.css +544 -0
  98. package/Grid/Grid.js +3761 -0
  99. package/Grid/Themes/Default.css +43 -0
  100. package/LICENSE +126 -0
  101. package/MaskedTextBox/MaskedTextBox.css +28 -0
  102. package/MaskedTextBox/MaskedTextBox.js +642 -0
  103. package/MaskedTextBox/Themes/Default.css +6 -0
  104. package/Menu/Menu.css +328 -0
  105. package/Menu/Menu.js +2386 -0
  106. package/Menu/Themes/Default.css +24 -0
  107. package/NumericBox/NumericBox.css +120 -0
  108. package/NumericBox/NumericBox.js +984 -0
  109. package/PanelBar/PanelBar.css +123 -0
  110. package/PanelBar/PanelBar.js +505 -0
  111. package/PanelBar/Themes/Default.css +51 -0
  112. package/PieChart/PieChart.css +95 -0
  113. package/PieChart/PieChart.js +820 -0
  114. package/PieChart/Themes/Default.css +9 -0
  115. package/README.md +178 -3
  116. package/Slider/Slider.css +348 -0
  117. package/Slider/Slider.js +1306 -0
  118. package/Slider/Themes/Default.css +44 -0
  119. package/TabStrip/TabStrip.css +52 -0
  120. package/TabStrip/TabStrip.js +362 -0
  121. package/TabStrip/Themes/Default.css +35 -0
  122. package/TimePicker/Themes/Default.css +30 -0
  123. package/TimePicker/TimePicker.css +253 -0
  124. package/TimePicker/TimePicker.js +1485 -0
  125. package/TooltipManager/Themes/Default.css +21 -0
  126. package/TooltipManager/TooltipManager.css +227 -0
  127. package/TooltipManager/TooltipManager.js +791 -0
  128. package/Validator/Validator.css +54 -0
  129. package/Validator/Validator.js +2508 -0
  130. package/componyx.html-data.json +619 -0
  131. package/index.js +27 -0
  132. package/package.json +43 -4
  133. package/types/AppSkin.d.ts +842 -0
  134. package/types/Base.d.ts +1034 -0
  135. package/types/Bindary.d.ts +1196 -0
  136. package/types/BookmarkSpy.d.ts +112 -0
  137. package/types/Box.d.ts +374 -0
  138. package/types/Button.d.ts +455 -0
  139. package/types/Carousel.d.ts +136 -0
  140. package/types/ColorButton.d.ts +120 -0
  141. package/types/ColorPicker.d.ts +225 -0
  142. package/types/ComboBox.d.ts +507 -0
  143. package/types/DataPager.d.ts +152 -0
  144. package/types/DatePicker.d.ts +354 -0
  145. package/types/Dialog.d.ts +160 -0
  146. package/types/Editor.d.ts +1289 -0
  147. package/types/FileUpload.d.ts +206 -0
  148. package/types/Form.d.ts +3078 -0
  149. package/types/FormField.d.ts +204 -0
  150. package/types/Grid.d.ts +911 -0
  151. package/types/Library.d.ts +1899 -0
  152. package/types/MaskedTextBox.d.ts +91 -0
  153. package/types/Menu.d.ts +577 -0
  154. package/types/NumericBox.d.ts +310 -0
  155. package/types/PanelBar.d.ts +223 -0
  156. package/types/PieChart.d.ts +224 -0
  157. package/types/ResponsiveTemplates.d.ts +108 -0
  158. package/types/Slider.d.ts +227 -0
  159. package/types/TabStrip.d.ts +185 -0
  160. package/types/TimePicker.d.ts +265 -0
  161. package/types/TooltipManager.d.ts +178 -0
  162. package/types/UI.d.ts +29 -0
  163. package/types/Validator.d.ts +653 -0
  164. package/types/index.d.ts +59 -0
  165. package/ui.css +11783 -0
  166. package/ui.js +79477 -0
  167. package/ui.min.css +138 -0
  168. package/ui.min.js +264 -0
  169. package/ui.min.js.map +1 -0
@@ -0,0 +1,4058 @@
1
+ /*! Componyx.UI | (c) E.H. Daanen / Componyx | BUSL-1.1 | componyx.com/license */
2
+ import '../Base/Base.js';
3
+ import '../Base/Library.js';
4
+ import '../Base/Sanitizer.js';
5
+ import './Modules/ContentManager.js';
6
+ import './Modules/ComponentFactory.js';
7
+ import './Modules/DialogManager.js';
8
+ import './Modules/EventManager.js';
9
+ import './Modules/Format.js';
10
+ import './Modules/History.js';
11
+ import './Modules/LayoutState.js';
12
+ import './Modules/ListManager.js';
13
+ import './Modules/MenuManager.js';
14
+ import './Modules/NodeManager.js';
15
+ import './Modules/ParagraphButtons.js';
16
+ import './Modules/Resizer.js';
17
+ import './Modules/SelectionRange.js';
18
+ import './Modules/SourceViewBuilder.js';
19
+ import './Modules/SymbolPicker.js';
20
+ import './Modules/Table.js';
21
+ import './Modules/TableDialog.js';
22
+ import './Modules/Toolbar.js';
23
+ import './Modules/TooltipMenu.js';
24
+ import './Modules/Utility.js';
25
+ import '../Button/Button.js';
26
+ import '../FormField/FormField.js';
27
+ import '../ComboBox/ComboBox.js';
28
+ import '../Dialog/Dialog.js';
29
+ import '../Menu/Menu.js';
30
+ import '../ColorButton/ColorButton.js';
31
+ import '../ColorPicker/ColorPicker.js';
32
+ import '../NumericBox/NumericBox.js';
33
+ import '../Validator/Validator.js';
34
+ import '../TooltipManager/TooltipManager.js';
35
+
36
+ (async function (window)
37
+ {
38
+ /**
39
+ * Namespace for editor modules.
40
+ * @namespace componyx.UI.editor_modules
41
+ */
42
+ componyx.UI.editor_modules = componyx.UI.editor_modules || {};
43
+
44
+ /**
45
+ * Promise that resolves when all editor modules are loaded asynchronously.
46
+ * @type {Promise<void>}
47
+ * @memberof componyx.UI.editor_modules
48
+ */
49
+ componyx.UI.editor_modules.loaded = (async () =>
50
+ {
51
+ // these dynamic imports are removed when files are bundled into UI(.min).js
52
+ })();
53
+
54
+ await componyx.UI.editor_modules.loaded;
55
+ const Sanitizer = componyx.base_modules.Sanitizer;
56
+ const ContentManager = componyx.UI.editor_modules.ContentManager;
57
+ const ComponentFactory = componyx.UI.editor_modules.ComponentFactory;
58
+ const DialogManager = componyx.UI.editor_modules.DialogManager;
59
+ const EventManager = componyx.UI.editor_modules.EventManager;
60
+ const Format = componyx.UI.editor_modules.Format;
61
+ const History = componyx.UI.editor_modules.History;
62
+ const LayoutState = componyx.UI.editor_modules.LayoutState;
63
+ const ListManager = componyx.UI.editor_modules.ListManager;
64
+ const MenuManager = componyx.UI.editor_modules.MenuManager;
65
+ const NodeManager = componyx.UI.editor_modules.NodeManager;
66
+ const ParagraphButtons = componyx.UI.editor_modules.ParagraphButtons;
67
+ const Resizer = componyx.UI.editor_modules.Resizer;
68
+ const SelectionRange = componyx.UI.editor_modules.SelectionRange;
69
+ const SourceViewBuilder = componyx.UI.editor_modules.SourceViewBuilder;
70
+ const Table = componyx.UI.editor_modules.Table;
71
+ const Toolbar = componyx.UI.editor_modules.Toolbar;
72
+ const TooltipMenu = componyx.UI.editor_modules.TooltipMenu;
73
+ const Utility = componyx.UI.editor_modules.Utility;
74
+
75
+ /**
76
+ * @typedef {Object} EditableElement.
77
+ * @memberof componyx.UI.Editor
78
+ * @property {String} [id] The identifier of the content editable element.
79
+ * @property {HTMLElement} [element] The HTML element instead of the identifier.
80
+ * @property {ToolbarDisplayOption} [settings.toolbarDisplay] The toolbar display for the editable element.
81
+ */
82
+
83
+ /**
84
+ * @typedef {Object.<string, string>} LabelSettings
85
+ * @memberof componyx.UI.Editor
86
+ * @property {String} comboBoxPlaceholderEditable = - Select or Type - - Gets or sets the default placeholder for a combobox that allows input.
87
+ * @property {String} comboBoxPlaceholderReadOnly = - Select - - Gets or sets the default placeholder for a combobox that is read-only.
88
+ * @property {String} alignLeft = Left - Gets or sets the label for left alignment.
89
+ * @property {String} alignCenter = Center - Gets or sets the label for center alignment.
90
+ * @property {String} alignRight = Right - Gets or sets the label for right alignment.
91
+ * @property {String} alignJustify = Justify - Gets or sets the label for justified text alignment.
92
+ * @property {String} alignTop = Top - Gets or sets the label for vertical top alignment.
93
+ * @property {String} alignMiddle = Middle - Gets or sets the label for vertical middle alignment.
94
+ * @property {String} alignBottom = Center - Gets or sets the label for vertical bottom alignment.
95
+ * @property {String} borderStyleNone = None - Gets or sets the label for border-style none.
96
+ * @property {String} borderStyleSolid = Solid - Gets or sets the label for border-style solid.
97
+ * @property {String} borderStyleDashed = Dashed - Gets or sets the label for border-style dashed.
98
+ * @property {String} borderStyleDotted = Dotted - Gets or sets the label for border-style dotted.
99
+ * @property {String} borderStyleDouble = Double - Gets or sets the label for border-style double.
100
+ *
101
+ * @property {String} dialogConfirm = OK - Gets or sets the label for the confirm button in dialogs.
102
+ * @property {String} dialogCancel = Cancel - Gets or sets the label for the cancel button in dialogs.
103
+ * @property {String} sourceViewDialogHeader = Source View - Gets or sets the header label for the Source View dialog.
104
+ * @property {String} sourceViewRootItem = document - Gets or sets the label for the root item in Source View.
105
+ * @property {String} bookmarkDialogHeader = Insert/Edit Bookmark - Gets or sets the header label for the Insert/Edit Bookmark dialog.
106
+ * @property {String} bookmarkInputPlaceholder = Bookmark name - Gets or sets the placeholder text for the bookmark name input.
107
+ * @property {String} bookmarkPrefix = Bookmark - Gets or sets the prefix text for bookmarks.
108
+ * @property {String} symbolSearchInputPlaceholder = Search - Gets or sets the placeholder text for the symbol search input.
109
+ *
110
+ * @property {String} linkDialogHeader = Insert/Edit Link - Gets or sets the header label for the Insert/Edit Link dialog.
111
+ * @property {String} linkHref = URL - Gets or sets the label for the URL field in the Link dialog.
112
+ * @property {String} linkText = Text - Gets or sets the label for the text field in the Link dialog.
113
+ * @property {String} linkTitle = Title - Gets or sets the label for the Title field in the Link dialog.
114
+ * @property {String} linkTarget = Target - Gets or sets the label for the Target field in the Link dialog.
115
+ * @property {String} linkTargetCurrent = Current window - Gets or sets the label for opening the link in the current window.
116
+ * @property {String} linkTargetNew = New window - Gets or sets the label for opening the link in a new window.
117
+ * @property {String} linkDownloadable = Downloadable - Gets or sets the label indicating a downloadable link.
118
+ * @property {String} removeLink = Remove link - Gets or sets the label for removing a link.
119
+ *
120
+ * @property {String} imageDialogHeader = Insert/Edit Image - Gets or sets the header label for the Insert/Edit Image dialog.
121
+ * @property {String} imageSource = Image URL/File - Gets or sets the label for the image URL or file input.
122
+ * @property {String} imageAlt = Alternative text - Gets or sets the label for the alternative text of an image.
123
+ * @property {String} imageWidth = Width - Gets or sets the label for the width of an image.
124
+ * @property {String} imageHeight = Height - Gets or sets the label for the height of an image.
125
+ * @property {String} imageAlignment = Alignment - Gets or sets the label for image alignment.
126
+ * @property {String} imageInline = Inline image - Gets or sets the label for inline images.
127
+ * @property {String} imageFileButtonTooltip = Upload file from computer - Gets or sets the tooltip text for the image upload button.
128
+ * @property {String} imageConstrainButtonTooltip = Lock/Unlock image proportions - Gets or sets the tooltip text for the image constrain proportions button.
129
+ *
130
+ * @property {String} mediaDialogHeader = Insert/Edit Media - Gets or sets the header label for the Insert/Edit Media dialog.
131
+ * @property {String} mediaSource = Media URL - Gets or sets the label for the media URL input.
132
+ * @property {String} mediaEmbed = Media Embed - Gets or sets the label for the media embed input.
133
+ * @property {String} mediaWidth = Width - Gets or sets the label for the width of media elements.
134
+ *
135
+ * @property {String} comboBoxNoResult = - Gets or sets the label shown when no results are found in combo boxes.
136
+ * @property {String} default = - Default - - Gets or sets the label for the default option.
137
+ * @property {String[]} emojiSymbolCategories = ['All'] - Gets or sets the list of emoji symbol categories.
138
+ * @property {String[]} specialSymbolCategories = ['All'] - Gets or sets the list of special symbol categories.
139
+ *
140
+ * @property {String} tableDialogHeader = Table Settings - Gets or sets the header label for the Table Settings dialog.
141
+ * @property {String} tableDialogCategoryTable = Table - Gets or sets the label for the Table category in the Table Settings dialog.
142
+ * @property {String} tableDialogCategoryRow = Row - Gets or sets the label for the Row category in the Table Settings dialog.
143
+ * @property {String} tableDialogCategoryCell = Cell - Gets or sets the label for the Cell category in the Table Settings dialog.
144
+ * @property {String} tableWidth = Width - Gets or sets the label for the table width field.
145
+ * @property {String} tableAlignment = Alignment - Gets or sets the label for the table alignment field.
146
+ * @property {String} tableCellSpacing = Cell Spacing - Gets or sets the label for the table cell spacing field.
147
+ * @property {String} tableCellPadding = Cell Padding - Gets or sets the label for the table cell padding field.
148
+ * @property {String} headerRow = Header Row - Gets or sets the label for the row header toggle.
149
+ * @property {String} footerRow = Footer Row - Gets or sets the label for the row footer toggle.
150
+ * @property {String} rowHeight = Height - Gets or sets the label for the row height.
151
+ * @property {String} cellWidth = Width - Gets or sets the label for the cell width field.
152
+ * @property {String} cellHeight = Height - Gets or sets the label for the cell height field.
153
+ * @property {String} cellPadding = Padding - Gets or sets the label for the cell padding field.
154
+ * @property {String} caption = Caption - Gets or sets the label for caption fields (table, image, media).
155
+ * @property {String} bgColor = Background Color - Gets or sets the label for background color fields (row, cell).
156
+ * @property {String} borderWidth = Border Width - Gets or sets the label for border width fields (table, cell).
157
+ * @property {String} borderStyle = Border Style - Gets or sets the label for border style fields (table, cell).
158
+ * @property {String} borderColor = Border Color - Gets or sets the label for border color fields (table, cell).
159
+ * @property {String} verticalAlign = Vertical Align - Gets or sets the label for the vertical alignment field.
160
+ * @property {String} horizontalAlign = Horizontal Align - Gets or sets the label for the horizontal alignment field.
161
+ *
162
+ * @property {String} tableMenuCut = Cut - Gets or sets the label for cutting selected table content.
163
+ * @property {String} tableMenuCopy = Copy - Gets or sets the label for copying selected table content.
164
+ * @property {String} tableMenuPaste = Paste - Gets or sets the label for pasting clipboard content into the table.
165
+ * @property {String} tableMenuPastePlainText = Paste as plain text - Gets or sets the label for pasting clipboard content without formatting.
166
+ * @property {String} tableMenuRow = Row - Gets or sets the label for the row submenu.
167
+ * @property {String} tableMenuAddRowAbove = Add Row above - Gets or sets the label for inserting a row above the current row.
168
+ * @property {String} tableMenuAddRowBelow = Add Row below - Gets or sets the label for inserting a row below the current row.
169
+ * @property {String} tableMenuRemoveRow = Remove Row - Gets or sets the label for removing the selected row.
170
+ * @property {String} tableMenuColumn = Column - Gets or sets the label for the column submenu.
171
+ * @property {String} tableMenuAddColumnLeft = Add Column left - Gets or sets the label for inserting a column to the left.
172
+ * @property {String} tableMenuAddColumnRight = Add Column right - Gets or sets the label for inserting a column to the right.
173
+ * @property {String} tableMenuRemoveColumn = Remove Column - Gets or sets the label for removing the selected column.
174
+ * @property {String} tableMenuMerge = Merge - Gets or sets the label for the merge submenu.
175
+ * @property {String} tableMenuMergeSelection = Merge Selection - Gets or sets the label for merging selected cells into one cell.
176
+ * @property {String} tableMenuMergeRight = Merge Right - Gets or sets the label for merging the current cell with the cell to the right.
177
+ * @property {String} tableMenuMergeDown = Merge Down - Gets or sets the label for merging the current cell with the cell below.
178
+ * @property {String} tableMenuSplit = Split Cells - Gets or sets the label for splitting a merged cell into individual cells.
179
+ * @property {String} tableMenuSettings = Settings - Gets or sets the label for opening the table settings dialog.
180
+ * @property {String} tableMenuDelete = Delete Table - Gets or sets the label for deleting the entire table.
181
+ *
182
+ * @property {String} undoCommandTooltip - Gets or sets the tooltip text for the Undo command button.
183
+ * @property {String} redoCommandTooltip - Gets or sets the tooltip text for the Redo command button.
184
+ * @property {String} boldCommandTooltip - Gets or sets the tooltip text for the Bold command button.
185
+ * @property {String} italicCommandTooltip - Gets or sets the tooltip text for the Italic command button.
186
+ * @property {String} underlineCommandTooltip - Gets or sets the tooltip text for the Underline command button.
187
+ * @property {String} strikeThroughCommandTooltip - Gets or sets the tooltip text for the StrikeThrough command button.
188
+ * @property {String} fontColorCommandTooltip - Gets or sets the tooltip text for the Font Color command button.
189
+ * @property {String} fontBGColorCommandTooltip - Gets or sets the tooltip text for the Background Color command button.
190
+ * @property {String} blockCommandTooltip - Gets or sets the tooltip text for the Block style command button.
191
+ * @property {String} fontFamilyCommandTooltip - Gets or sets the tooltip text for the Font Family command button.
192
+ * @property {String} fontSizeCommandTooltip - Gets or sets the tooltip text for the Font Size command button.
193
+ * @property {String} styleCommandTooltip - Gets or sets the tooltip text for the Style command button.
194
+ * @property {String} alignCommandTooltip - Gets or sets the tooltip text for the Align command button.
195
+ * @property {String} lineHeightCommandTooltip - Gets or sets the tooltip text for the Line Height command button.
196
+ * @property {String} indentMinCommandTooltip - Gets or sets the tooltip text for the Decrease Indent command button.
197
+ * @property {String} indentPlusCommandTooltip - Gets or sets the tooltip text for the Increase Indent command button.
198
+ * @property {String} orderedListCommandTooltip - Gets or sets the tooltip text for the Ordered List command button.
199
+ * @property {String} unorderedListCommandTooltip - Gets or sets the tooltip text for the Unordered List command button.
200
+ * @property {String} checkListCommandTooltip - Gets or sets the tooltip text for the Check List command button.
201
+ * @property {String} linkCommandTooltip - Gets or sets the tooltip text for the Link command button.
202
+ * @property {String} imageCommandTooltip - Gets or sets the tooltip text for the Image command button.
203
+ * @property {String} mediaCommandTooltip - Gets or sets the tooltip text for the Media command button.
204
+ * @property {String} tableCommandTooltip - Gets or sets the tooltip text for the Table command button.
205
+ * @property {String} subscriptCommandTooltip - Gets or sets the tooltip text for the Subscript command button.
206
+ * @property {String} superscriptCommandTooltip - Gets or sets the tooltip text for the Superscript command button.
207
+ * @property {String} copyFormatCommandTooltip - Gets or sets the tooltip text for the Copy Format command button.
208
+ * @property {String} clearFormatCommandTooltip - Gets or sets the tooltip text for the Clear Format command button.
209
+ * @property {String} bookmarkCommandTooltip - Gets or sets the tooltip text for the Bookmark command button.
210
+ * @property {String} horizontalLineCommandTooltip - Gets or sets the tooltip text for the Horizontal Line command button.
211
+ * @property {String} pageBreakCommandTooltip - Gets or sets the tooltip text for the Page Break command button.
212
+ * @property {String} sourceCommandTooltip - Gets or sets the tooltip text for the Source View command button.
213
+ * @property {String} expandCommandTooltip - Gets or sets the tooltip text for the Expand View command button.
214
+ * @property {String} previewCommandTooltip - Gets or sets the tooltip text for the Preview command button.
215
+ * @property {String} saveCommandTooltip - Gets or sets the tooltip text for the Save command button.
216
+ * @property {String} exportCommandTooltip - Gets or sets the tooltip text for the Export to PDF command button.
217
+ * @property {String} printCommandTooltip - Gets or sets the tooltip text for the Print command button.
218
+ * @property {String} moreCommandTooltip - Gets or sets the tooltip text for the More options command button.
219
+ * @property {String} blockViewCommandTooltip - Gets or sets the tooltip text for the Block View command button.
220
+ * @property {String} specialCommandTooltip - Gets or sets the tooltip text for the Special Symbols command button.
221
+ * @property {String} emojiCommandTooltip - Gets or sets the tooltip text for the Emoji Symbols command button.
222
+ */
223
+
224
+ /**
225
+ * Editor CSS Variables.
226
+ * @typedef {Object} CSSVariables
227
+ * @memberof componyx.UI.Editor
228
+ * @property {string} ["--font-color"] - The font color.
229
+ * @property {string} ["--font-bg-color"] - The font background color.
230
+ * @property {string} ["--image-width"] - The image width.
231
+ * @property {string} ["--image-height"] - The image height.
232
+ */
233
+
234
+ /**
235
+ * @function isActiveFunction
236
+ * @memberof componyx.UI.Editor
237
+ * @param {HTMLElement} node - The HTML Element node.
238
+ * @param {CommandSettings} cmd - The command settings.
239
+ */
240
+
241
+ /**
242
+ * @function getNodeFunction
243
+ * @memberof componyx.UI.Editor
244
+ * @param {HTMLElement} node - The HTML Element node.
245
+ */
246
+
247
+ /**
248
+ * @typedef {Object.<string, any>} ReplacementItem
249
+ * @memberof componyx.UI.Editor
250
+ * @param {RegExp} match - The matching RegExp.
251
+ * @param {String} replace - The replacement text.
252
+ */
253
+
254
+ /**
255
+ * @typedef {Object.<string, any>} HTMLElementSettings
256
+ * @memberof componyx.UI.Editor
257
+ * @property {Node} node Gets or sets the node.
258
+ * @property {String} tag Gets or sets the tag of the element.
259
+ * @property {String} cssClass Gets or sets the CSS class of the element.
260
+ * @property {Object.<string, string>} styles Gets or sets the CSS styles of the element.
261
+ * @property {Object.<string, string>} attributes Gets or sets the attributes of the element.
262
+ * @property {String} textContent Gets or sets the text content of the element.
263
+ * @property {String} innerHTML Gets or sets the inner HTML of the element (overwrites textContent).
264
+ * @property {String} outerHTML Gets or sets the outer HTML of the element. When a value is provided the tag, cssClass, styles, attributes, textContent and innerHTML properties are ignored.
265
+ * @property {Boolean} isPhrasingContent Gets or sets a value indicating if the element is phrasing content and can be placed inside a P tag.
266
+ * @property {Boolean} selectable Gets or sets a value indicating if the element is selectable. For selectability on document reload, ensure the element matches a selector in selectableNodes so the node will remain selectable.
267
+ * @property {Boolean} select Gets or sets a value indicating if the element is selected when inserted.
268
+ * @property {Boolean} allowContent Gets or sets a value indicating if the element allows editable content.
269
+ */
270
+
271
+ /**
272
+ * @typedef {Object.<string, any>} CommandSettings
273
+ * @memberof componyx.UI.Editor
274
+ * @property {Function} command Gets or sets the button command.
275
+ * @property {String} shortcutKey Gets or sets the key used to trigger the command when the CTRL key is held.
276
+ * @property {String} tooltip Gets or sets the tooltip text to display when the command is in focus.
277
+ * @property {String} cssClassIcon Gets or sets thecss class name of the button icon.
278
+ * @property {Boolean} show Gets or sets a value indicating if the command button is shown.
279
+ * @property {componyx.UI.Editor.IsActiveFunction} isActive Gets or sets the function which should return true if the command button is active (selected).
280
+ * @property {componyx.UI.Editor.GetNodeFunction} getNode Gets or sets the function which should return the layout node when it is deeper inside the root-node of the active selection range (e.g. FIGURE > IMG).
281
+ * @property {String} buttonId Gets or sets the id of the base item button.
282
+ * @property {componyx.UI.Button.TypeOption} type Gets or sets a value indicating the button type. 0: command-button, 1: check-button, 2: radio-button.
283
+ * @property {String} menuId Gets or sets the id of the menu component.
284
+ * @property {String} menuItemId Gets or sets the menu-item id.
285
+ * @property {Number} group Gets or sets the index number of the group to which the command belongs.
286
+ * @property {Number} position Gets or sets the position of the command within the group. If no positions are specified commands are ordered by insertion order.
287
+ * @property {componyx.UI.Editor.HTMLElementSettings} elementSettings Gets or sets the settings which configure the element to insert into the document.
288
+ */
289
+
290
+ /**
291
+ * @typedef {Object.<string, any>} SymbolCategory
292
+ * @memberof componyx.UI.Editor
293
+ * @property {String} name Gets or sets the category name.
294
+ * @property {componyx.UI.Editor.Symbol[]} values Gets or sets the symbols of the category.
295
+ */
296
+
297
+ /**
298
+ * @typedef {Object.<string, any>} Symbol
299
+ * @memberof componyx.UI.Editor
300
+ * @property {String} name Gets or sets the symbol name.
301
+ * @property {String} value Gets or sets the symbol value.
302
+ */
303
+
304
+ /**
305
+ * Editor class.
306
+ * Note: if you use $lib alongside the editor API in an iframe configuration, be aware that editor operations temporarily switch $lib.document to the iframe document.
307
+ * This resets automatically via microtask after each callstack. Call editor.deactivateDocument() explicitly (or reset $lib.document) if you need to restore the context immediately within the same callstack.
308
+ * @class
309
+ * @memberof componyx.UI
310
+ * @augments componyx.UI.base.Component
311
+ * @mixes componyx.UI.base.methods
312
+ * @param {String} id The id of the component.
313
+ * @param {Object|HTMLElement} properties The properties used to initialize the component or the container element.
314
+ * @returns {String} An instance of the component.
315
+ */
316
+ componyx.UI.Editor = function Editor(id, properties)
317
+ {
318
+ // define private properties
319
+ let _instance = this,
320
+ _themeOption = $base.static.ThemeOption,
321
+ _toolbarDisplayOption = componyx.UI.Editor.ToolbarDisplayOption,
322
+ _resizeTimerId,
323
+ _range, _sortedCommands = [],
324
+ _toolbar, _footerEl, _pathEl, _wordCountEl, _doc, _editableElement, _editor, _iframe,
325
+ _resizeHandle, _resizeMask,
326
+ _sourceElement = new Map(),
327
+ _sourceViewStore = new Map(),
328
+ _sanitizer,
329
+ _iconPrefix = 'ico-editor-';
330
+
331
+ /**
332
+ * Internal CSS class name constants.
333
+ * You can override any of these classes on the Component instance by defining a property named
334
+ * `cssClass<Key>` where <Key> is the PascalCase key from this object.
335
+ * Example:
336
+ * 'BUILD_PANE' -> 'cssClassBuildPane'
337
+ * Be cautious: overriding these classes without including the default names may break styling and functionality.
338
+ * @constant
339
+ * @type {Readonly<Object<string, string>>}
340
+ */
341
+ this.classOption = Object.freeze(
342
+ {
343
+ TOOLBAR: 'toolbar',
344
+ TOOLBAR_BOX: 'toolbar-box',
345
+ TOOLBAR_MORE: 'toolbar-more',
346
+ GROUP: 'group',
347
+ CONTENT: 'editor-content',
348
+ FOOTER: 'footer',
349
+ PATH: 'path',
350
+ WORD_COUNT: 'word-count',
351
+ FULLSCREEN: 'fullscreen',
352
+ PREVIEW: 'preview',
353
+ SOURCE_VIEW: 'source-view',
354
+ BOOKMARK: 'bookmark',
355
+ FIGURE: 'figure',
356
+ MEDIA: 'media',
357
+ LINK_DIALOG: 'link-dialog',
358
+ BOOKMARK_DIALOG: 'bookmark-dialog',
359
+ IMAGE_DIALOG: 'image-dialog',
360
+ MEDIA_DIALOG: 'media-dialog',
361
+ SOURCE_DIALOG: 'source-dialog',
362
+ FOCUS: 'focus',
363
+ FRAMED: 'framed',
364
+ HIDDEN: 'hidden',
365
+ TOOLTIP_MENU_LINK: 'tooltip-menu-link',
366
+ DOC_TOOLTIPS: 'doc-tooltips',
367
+ IMG_INLINE_ALIGN_DEFAULT_TOP: 'img-inline-align-default-top',
368
+ IMG_INLINE_ALIGN_DEFAULT_CENTER: 'img-inline-align-default-center',
369
+ IMG_INLINE_ALIGN_DEFAULT_BOTTOM: 'img-inline-align-default-bottom',
370
+ IMG_INLINE_ALIGN_LEFT: 'img-inline-align-left',
371
+ IMG_INLINE_ALIGN_RIGHT: 'img-inline-align-right',
372
+ IMG_ALIGN_LEFT: 'img-align-left',
373
+ IMG_ALIGN_CENTER: 'img-align-center',
374
+ IMG_ALIGN_RIGHT: 'img-align-right',
375
+ COLORSWATCH_BOX: 'box color-swatch',
376
+ SWATCH: 'swatch',
377
+ SWATCH_COLOR: 'swatch-color',
378
+ CLEARCOLOR_BUTTON: 'clear-color-button',
379
+ COLORPICKER_BUTTON: 'color-picker-button',
380
+ SYMBOL_PICKER_BOX: 'box symbol-picker',
381
+ EMOJI_SYMBOL_PICKER: 'emoji-picker',
382
+ SPECIAL_SYMBOL_PICKER: 'special-picker',
383
+ SYMBOL_CATEGORIES: 'symbol-categories',
384
+ SYMBOL_VIEW: 'symbol-view',
385
+ SYMBOL_CATEGORY: 'symbol-category',
386
+ SYMBOL_ITEMS: 'symbol-items',
387
+ SYMBOL_HEADER: 'symbol-header',
388
+ SYMBOL_FOOTER: 'symbol-footer',
389
+ SYMBOL: 'symbol',
390
+ TABLE_PICKER: 'te-picker',
391
+ TABLE_PICKER_GRID: 'te-picker-grid',
392
+ TABLE_PICKER_LABEL: 'te-picker-label',
393
+ TABLE_WRAPPER: 'te-wrapper',
394
+ TABLE_ANCHOR: 'te-anchor',
395
+ TABLE_SELECTED: 'te-selected',
396
+ TABLE_COL_HANDLE: 'te-col-handle',
397
+ TABLE_COL_HANDLE_ACTIVE: 'te-col-handle-active',
398
+ TABLE_MENU_BUTTON: 'te-menu-button',
399
+ TABLE_DIALOG: 'table-dialog',
400
+ TABLE_DIALOG_CATEGORIES: 'table-dialog-categories',
401
+ TABLE_DIALOG_VIEW: 'table-dialog-view',
402
+ TABLE_DIALOG_PANEL: 'table-dialog-panel',
403
+ TABLE_DIALOG_CATEGORY: 'table-dialog-category',
404
+ ACTIVE: 'active',
405
+ REMOVE: 'remove',
406
+ LOCK: 'lock',
407
+ FILE_SELECT: 'file-select',
408
+ FIELD_HALF: 'field-half',
409
+ PARAGRAPH: 'paragraph',
410
+ PDF_EXPORT: 'editor-pdf-export'
411
+ });
412
+
413
+ // define public properties
414
+ /**
415
+ * Gets or sets the editor height.
416
+ * @type {String}
417
+ */
418
+ this.editorHeight = '';
419
+
420
+ /**
421
+ * Gets or sets the default font size.
422
+ * @type {String}
423
+ */
424
+ this.defaultFontSize = '16px';
425
+
426
+ /**
427
+ * Gets or sets the default font family.
428
+ * @type {String}
429
+ */
430
+ this.defaultFontFamily = 'Arial';
431
+
432
+ /**
433
+ * Gets or sets the default alignment.
434
+ * @type {String}
435
+ */
436
+ this.defaultAlign = '';
437
+
438
+ /**
439
+ * Gets or sets the default line-height.
440
+ * @type {String}
441
+ */
442
+ this.defaultLineHeight = '';
443
+
444
+ /**
445
+ * Gets or sets the content.
446
+ * @type {String}
447
+ */
448
+ this.content = '';
449
+
450
+ /**
451
+ * Gets or sets the toolbar display option.
452
+ * @type {String}
453
+ */
454
+ this.toolbarDisplay = _toolbarDisplayOption.HEADER;
455
+
456
+ /**
457
+ * Gets or sets a value indicating uses an iframe (instead of content-editable DIV).
458
+ * @type {Boolean}
459
+ * @default false
460
+ */
461
+ this.iframe = false;
462
+
463
+ /**
464
+ * Gets or sets a value indicating if CSS imported fonts should be detected.
465
+ * @type {Boolean}
466
+ * @default true
467
+ */
468
+ this.detectFonts = true;
469
+
470
+ /**
471
+ * Gets or sets a value indicating if default WebSafe fonts are included in the fontFamily menu.
472
+ * @type {Boolean}
473
+ * @default true
474
+ */
475
+ this.includeWebSafeFonts = true;
476
+
477
+ /**
478
+ * Gets or sets a value indicating if missing font-sizes are added to the font-size menu.
479
+ * @type {Boolean}
480
+ * @default true
481
+ */
482
+ this.addMissingFontSize = true;
483
+
484
+ /**
485
+ * Gets or sets a value indicating if the default Browser spellcheck is enabled.
486
+ * @type {Boolean}
487
+ * @default true
488
+ */
489
+ this.defaultSpellcheck = true;
490
+
491
+ /**
492
+ * Gets or sets a value indicating if the source view is displayed in a dialog.
493
+ * @type {Boolean}
494
+ * @default false
495
+ */
496
+ this.sourceViewInDialog = false;
497
+
498
+ /**
499
+ * Gets or sets a value indicating if a local image file can be selected.
500
+ * @type {Boolean}
501
+ * @default true
502
+ */
503
+ this.allowImageFileSelect = true;
504
+
505
+ /**
506
+ * Gets or sets a value indicating if an url can be entered for images.
507
+ * @type {Boolean}
508
+ * @default true
509
+ */
510
+ this.allowImageUrlInput = true;
511
+
512
+ /**
513
+ * Gets or sets the default indent CSS unit value.
514
+ * @type {String}
515
+ * @default '20px'
516
+ */
517
+ this.indentValue = '20px';
518
+
519
+ /**
520
+ * Gets or sets the maximum items allowed in the history stack. Null means no limit.
521
+ * @type {number|null}
522
+ */
523
+ this.maxHistoryLength = null;
524
+
525
+ /**
526
+ * Gets or sets the prefix used to store data in local storage like color swatch colors.
527
+ * @type {String}
528
+ */
529
+ this.localStoragePrefix = 'editor';
530
+
531
+ /**
532
+ * Gets or sets the resource path for fetching the emojis.
533
+ * @type {String}
534
+ * @default 'src?d=Editor.Emoji.json'
535
+ */
536
+ this.emojiSymbolResourcePath = 'src?d=Editor.Emoji.json';
537
+
538
+ /**
539
+ * Gets or sets the resource path for fetching the special characters.
540
+ * @type {String}
541
+ * @default 'src?d=Editor.Special.json'
542
+ */
543
+ this.specialSymbolResourcePath = 'src?d=Editor.Special.json';
544
+
545
+ /**
546
+ * Gets or sets the emoji symbol data.
547
+ * @type {componyx.UI.Editor.SymbolCategory[]}
548
+ */
549
+ this.emojiSymbolData = null;
550
+
551
+ /**
552
+ * Gets or sets the special symbol data.
553
+ * @type {componyx.UI.Editor.SymbolCategory[]}
554
+ */
555
+ this.specialSymbolData = null;
556
+
557
+ /**
558
+ * Gets or sets a list of editable elements.
559
+ * @type {EditableElement[]}
560
+ */
561
+ this.editableElements = [];
562
+
563
+ /**
564
+ * Gets or sets a list of custom fonts to include in the fontFamily menu.
565
+ * @type {String[]}
566
+ */
567
+ this.fonts = [];
568
+
569
+ /**
570
+ * Gets or sets a list fonts to specifically exclude from the fontFamily menu.
571
+ * @type {String[]}
572
+ */
573
+ this.excludeFonts = [];
574
+
575
+ /**
576
+ * Gets or sets a list CSS unit font sizes to show in the fontSize menu.
577
+ * @type {String[]}
578
+ */
579
+ this.fontSizes = ["8px", "9px", "10px", "11px", "12px", "13px", "14px", "16px", "18px", "20px", "24px", "28px", "32px", "36px", "40px", "48px", "60px", "72px", "96px"];
580
+
581
+ /**
582
+ * Gets or sets a list style items to show in the style menu.
583
+ * @type {componyx.UI.Editor.StyleItem[]}
584
+ */
585
+ this.styles = [];
586
+
587
+ /**
588
+ * Gets or sets a list of line height options.
589
+ * @type {String[]}
590
+ */
591
+ this.lineHeights = ["0", "0.5", "1", "1.1", "1.2", "1.3", "1.4", "1.5", "2", "2.5", "3", "4"];
592
+
593
+ /**
594
+ * Gets or sets a list of ordered list-item options.
595
+ * @type {String[]}
596
+ */
597
+ this.orderedList = ['decimal', 'lower-alpha', 'lower-greek', 'lower-roman', 'upper-alpha', 'upper-roman'];
598
+
599
+ /**
600
+ * Gets or sets a list of unordered list-item options.
601
+ * @type {String[]}
602
+ */
603
+ this.unorderedList = ['disc', 'circle', 'square'];
604
+
605
+ /**
606
+ * Gets or sets a list of colors displayed in the color-swatch.
607
+ * @type {String[]}
608
+ */
609
+ this.colorSwatchColors = ['LightCoral', 'Plum', 'LightBlue', 'PaleTurquoise', 'PaleGreen', 'LemonChiffon',
610
+ 'IndianRed', 'Orchid', 'SkyBlue', 'Turquoise', 'LightGreen', 'PaleGoldenrod',
611
+ 'Red', 'MediumOrchid', 'DeepSkyBlue', 'Cyan', 'GreenYellow', 'Gold',
612
+ 'Crimson', 'DarkOrchid', 'SteelBlue', 'LightSeaGreen', 'LimeGreen', 'Orange',
613
+ 'DarkRed', 'Indigo', 'MidnightBlue', 'DarkCyan', 'Green', 'DarkOrange',
614
+ 'White', 'LightGray', 'DarkGray', 'Gray', 'DimGray', 'Black'];
615
+
616
+ /**
617
+ * Gets or sets a list of unique command names (or special keywords) to show on initialization.
618
+ * By default all supported commands are visible. If set, only these listed commands are visible.
619
+ * core ['undo','redo','bold','italic','underline','strikeThrough','align','indentMin','indentPlus','copyFormat','clearFormat'].
620
+ * list ['orderedList','unorderedList'].
621
+ * font ['fontSize','fontFamily'].
622
+ * font-color ['fontColor','fontBGColor']
623
+ * @type {String[]}
624
+ */
625
+ this.visibleCommands = [];
626
+
627
+ /**
628
+ * Gets or sets a list of extra commands to add on initialization.
629
+ * Each object key is the unique command name and the value holds the command settings.
630
+ * @type {Object.<string, CommandSettings>}
631
+ */
632
+ this.extraCommands = {};
633
+
634
+ /**
635
+ * Gets or sets the text labels used by the editor.
636
+ * @type {componyx.UI.Editor.LabelSettings}
637
+ */
638
+ this.labels = {
639
+ comboBoxPlaceholderEditable: '- Select or Enter -',
640
+ comboBoxPlaceholderReadOnly: '- Select - ',
641
+ alignLeft: 'Left',
642
+ alignCenter: 'Center',
643
+ alignRight: 'Right',
644
+ alignJustify: 'Justify',
645
+ alignTop: 'Top',
646
+ alignMiddle: 'Middle',
647
+ alignBottom: 'Bottom',
648
+ borderStyleNone: 'None',
649
+ borderStyleSolid: 'Solid',
650
+ borderStyleDashed: 'Dashed',
651
+ borderStyleDotted: 'Dotted',
652
+ borderStyleDouble: 'Double',
653
+ dialogConfirm: 'OK',
654
+ dialogCancel: 'Cancel',
655
+ sourceViewDialogHeader: 'Source View',
656
+ sourceViewRootItem: 'document',
657
+ bookmarkDialogHeader: 'Insert/Edit Bookmark',
658
+ bookmarkInputPlaceholder: 'Bookmark name',
659
+ bookmarkPrefix: 'Bookmark',
660
+ symbolSearchInputPlaceholder: 'Search',
661
+ linkDialogHeader: 'Insert/Edit Link',
662
+ linkHref: 'URL',
663
+ linkText: 'Text',
664
+ linkTitle: 'Title',
665
+ linkTarget: 'Target',
666
+ linkTargetCurrent: 'Current window',
667
+ linkTargetNew: 'New window',
668
+ linkDownloadable: 'Downloadable',
669
+ removeLink: 'Remove link',
670
+ imageDialogHeader: 'Insert/Edit Image',
671
+ imageSource: 'Image URL/File',
672
+ imageAlt: 'Alternative text',
673
+ imageWidth: 'Width',
674
+ imageHeight: 'Height',
675
+ imageAlignment: 'Alignment',
676
+ imageAlignLeft: 'Left',
677
+ imageAlignCenter: 'Center',
678
+ imageAlignRight: 'Right',
679
+ imageInlineAlignDefaultTop: 'Top',
680
+ imageInlineAlignDefaultCenter: 'Center',
681
+ imageInlineAlignDefaultBottom: 'Bottom',
682
+ imageInlineAlignLeft: 'Left',
683
+ imageInlineAlignRight: 'Right',
684
+ imageInline: 'Inline image',
685
+ imageFileButtonTooltip: 'Upload file from computer',
686
+ imageConstrainButtonTooltip: 'Lock/Unlock image proportions',
687
+ mediaDialogHeader: 'Insert/Edit Media',
688
+ mediaSource: 'Media URL',
689
+ mediaEmbed: 'Media Embed',
690
+ mediaWidth: 'Width',
691
+ comboBoxNoResult: '',
692
+ default: '- Default -',
693
+ emojiSymbolCategories: ['All'],
694
+ specialSymbolCategories: ['All'],
695
+ tableDialogHeader: 'Table Settings',
696
+ tableDialogCategoryTable: 'Table',
697
+ tableDialogCategoryRow: 'Row',
698
+ tableDialogCategoryCell: 'Cell',
699
+ tableWidth: 'Width',
700
+ tableAlignment: 'Alignment',
701
+ tableCellSpacing: 'Cell Spacing',
702
+ tableCellPadding: 'Cell Padding',
703
+ headerRow: 'Header Row',
704
+ footerRow: 'Footer Row',
705
+ rowHeight: 'Height',
706
+ cellWidth: 'Width',
707
+ cellHeight: 'Height',
708
+ cellPadding: 'Padding',
709
+ caption: 'Caption',
710
+ bgColor: 'Background Color',
711
+ borderWidth: 'Border Width',
712
+ borderStyle: 'Border Style',
713
+ borderColor: 'Border Color',
714
+ verticalAlign: 'Vertical Align',
715
+ horizontalAlign: 'Horizontal Align',
716
+
717
+ tableMenuCut: 'Cut',
718
+ tableMenuCopy: 'Copy',
719
+ tableMenuPaste: 'Paste',
720
+ tableMenuPastePlainText: 'Paste as plain text',
721
+ tableMenuRow: 'Row',
722
+ tableMenuAddRowAbove: 'Add Row above',
723
+ tableMenuAddRowBelow: 'Add Row below',
724
+ tableMenuRemoveRow: 'Remove Row',
725
+ tableMenuColumn: 'Column',
726
+ tableMenuAddColumnLeft: 'Add Column left',
727
+ tableMenuAddColumnRight: 'Add Column right',
728
+ tableMenuRemoveColumn: 'Remove Column',
729
+ tableMenuMerge: 'Merge',
730
+ tableMenuMergeSelection: 'Merge Selection',
731
+ tableMenuMergeRight: 'Merge Right',
732
+ tableMenuMergeDown: 'Merge Down',
733
+ tableMenuSplit: 'Split Cells',
734
+ tableMenuSettings: 'Settings',
735
+ tableMenuDelete: 'Delete Table',
736
+
737
+ undoCommandTooltip: '',
738
+ redoCommandTooltip: '',
739
+ boldCommandTooltip: '',
740
+ italicCommandTooltip: '',
741
+ underlineCommandTooltip: '',
742
+ strikeThroughCommandTooltip: '',
743
+ fontColorCommandTooltip: '',
744
+ fontBGColorCommandTooltip: '',
745
+ blockCommandTooltip: '',
746
+ fontFamilyCommandTooltip: '',
747
+ fontSizeCommandTooltip: '',
748
+ styleCommandTooltip: '',
749
+ alignCommandTooltip: '',
750
+ lineHeightCommandTooltip: '',
751
+ indentMinCommandTooltip: '',
752
+ indentPlusCommandTooltip: '',
753
+ orderedListCommandTooltip: '',
754
+ unorderedListCommandTooltip: '',
755
+ checkListCommandTooltip: '',
756
+ linkCommandTooltip: '',
757
+ imageCommandTooltip: '',
758
+ mediaCommandTooltip: '',
759
+ tableCommandTooltip: '',
760
+ subscriptCommandTooltip: '',
761
+ superscriptCommandTooltip: '',
762
+ copyFormatCommandTooltip: '',
763
+ clearFormatCommandTooltip: '',
764
+ bookmarkCommandTooltip: '',
765
+ horizontalLineCommandTooltip: '',
766
+ pageBreakCommandTooltip: '',
767
+ sourceCommandTooltip: '',
768
+ expandCommandTooltip: '',
769
+ previewCommandTooltip: '',
770
+ saveCommandTooltip: '',
771
+ exportCommandTooltip: '',
772
+ printCommandTooltip: '',
773
+ moreCommandTooltip: '',
774
+ blockViewCommandTooltip: '',
775
+ specialCommandTooltip: '',
776
+ emojiCommandTooltip: ''
777
+ };
778
+
779
+ /**
780
+ * Gets or sets a list stylesheets to include in the iframe. Setting only applicable when iframe is set to true.
781
+ * @type {String[]}
782
+ */
783
+ this.includeStylesheets = [];
784
+
785
+ /**
786
+ * Gets or sets the PDF export settings for jsPDF. View https://github.com/parallax/jsPDF
787
+ * @type {Object}
788
+ */
789
+ this.PDFExportSettings = {
790
+ filename: "export.pdf",
791
+ margin: [10, 10, 10, 10],
792
+ autoPaging: "text",
793
+ html2canvas: {
794
+ useCORS: true,
795
+ allowTaint: false,
796
+ logging: false
797
+ },
798
+ x: 0,
799
+ y: 0,
800
+ width: 180, // mm on the page
801
+ windowWidth: 680 // CSS px the content is laid out in
802
+ };
803
+
804
+ /**
805
+ * Gets or sets media URL replacement options.
806
+ * @type {componyx.UI.Editor.ReplacementItem[]}
807
+ */
808
+ this.mediaURLReplacement = [
809
+ {
810
+ match: /(youtube\.com\/)watch\?v=/gi,
811
+ replace: '$1embed/'
812
+ },
813
+ {
814
+ match: /youtu\.be\/([a-zA-Z0-9_-]+)/gi,
815
+ replace: 'youtube.com/embed/$1'
816
+ }
817
+ ];
818
+
819
+ /**
820
+ * Gets or sets CSS Selectors for nodes that are selectable in the editor.
821
+ * Defaults include anchors, figures and non-editable elements.
822
+ * Additional selectors can be added before render to support custom selectable elements.
823
+ * @type {String[]}
824
+ */
825
+ this.selectableNodes = ['a', 'figure', '[contenteditable="false"]'];
826
+
827
+ /**
828
+ * Gets or sets the id of the base menu.
829
+ * @type {String}
830
+ */
831
+ this.menuId = null;
832
+
833
+ /**
834
+ * Gets or sets the id of the base table menu.
835
+ * @type {String}
836
+ */
837
+ this.tableMenuId = null;
838
+
839
+ /**
840
+ * Gets or sets the id of the base toolbar box.
841
+ * @type {String}
842
+ */
843
+ this.toolbarBoxId = null;
844
+
845
+ /**
846
+ * Gets or sets the id of the base toolbar-more box.
847
+ * @type {String}
848
+ */
849
+ this.toolbarMoreBoxId = null;
850
+
851
+ /**
852
+ * Gets or sets the id of the base color swatch box.
853
+ * @type {String}
854
+ */
855
+ this.colorSwatchBoxId = null;
856
+
857
+ /**
858
+ * Gets or sets the id of the base clear-color button.
859
+ * @type {String}
860
+ */
861
+ this.clearColorButtonId = null;
862
+
863
+ /**
864
+ * Gets or sets the id of the base color picker.
865
+ * @type {String}
866
+ */
867
+ this.colorPickerId = null;
868
+
869
+ /**
870
+ * Gets or sets the id of the base source-dialog.
871
+ * @type {String}
872
+ */
873
+ this.sourceDialogId = null;
874
+
875
+ /**
876
+ * Gets or sets the id of the base bookmark-dialog.
877
+ * @type {String}
878
+ */
879
+ this.bookmarkDialogId = null;
880
+
881
+ /**
882
+ * Gets or sets the id of the base link-dialog.
883
+ * @type {String}
884
+ */
885
+ this.linkDialogId = null;
886
+
887
+ /**
888
+ * Gets or sets the id of the base image-dialog.
889
+ * @type {String}
890
+ */
891
+ this.imageDialogId = null;
892
+
893
+ /**
894
+ * Gets or sets the id of the base media-dialog.
895
+ * @type {String}
896
+ */
897
+ this.mediaDialogId = null;
898
+
899
+ /**
900
+ * Gets or sets identifiers for controls in the link dialog.
901
+ * @type {Object}
902
+ */
903
+ this.linkDialog = {
904
+ /**
905
+ * Gets or sets the id of the base link-href form-field.
906
+ * @type {String}
907
+ */
908
+ hrefFormFieldId: null,
909
+
910
+ /**
911
+ * Gets or sets the id of the base link-text form-field.
912
+ * @type {String}
913
+ */
914
+ textFormFieldId: null,
915
+
916
+ /**
917
+ * Gets or sets the id of the base link-title form-field.
918
+ * @type {String}
919
+ */
920
+ titleFormFieldId: null,
921
+
922
+ /**
923
+ * Gets or sets the id of the base link-target form-field.
924
+ * @type {String}
925
+ */
926
+ targetFormFieldId: null,
927
+
928
+ /**
929
+ * Gets or sets the id of the base link-downloadable form-field.
930
+ * @type {String}
931
+ */
932
+ downloadableFormFieldId: null,
933
+
934
+ /**
935
+ * Gets or sets the id of the base link-href combo-box.
936
+ * @type {String}
937
+ */
938
+ hrefComboBoxId: null,
939
+
940
+ /**
941
+ * Gets or sets the id of the base link-target combo-box.
942
+ * @type {String}
943
+ */
944
+ targetComboBoxId: null,
945
+
946
+ /**
947
+ * Gets or sets the id of the base remove-link button.
948
+ * @type {String}
949
+ */
950
+ removeButtonId: null
951
+ };
952
+
953
+ /**
954
+ * Gets or sets identifiers for controls in the image dialog.
955
+ * @type {Object}
956
+ */
957
+ this.imageDialog = {
958
+ /**
959
+ * Gets or sets the id of the base image-source form-field.
960
+ * @type {String}
961
+ */
962
+ sourceFormFieldId: null,
963
+
964
+ /**
965
+ * Gets or sets the id of the base image-alt form-field.
966
+ * @type {String}
967
+ */
968
+ altFormFieldId: null,
969
+
970
+ /**
971
+ * Gets or sets the id of the base image-width form-field.
972
+ * @type {String}
973
+ */
974
+ widthFormFieldId: null,
975
+
976
+ /**
977
+ * Gets or sets the id of the base image-height form-field.
978
+ * @type {String}
979
+ */
980
+ heightFormFieldId: null,
981
+
982
+ /**
983
+ * Gets or sets the id of the base caption form-field.
984
+ * @type {String}
985
+ */
986
+ captionFormFieldId: null,
987
+
988
+ /**
989
+ * Gets or sets the id of the base alignment form-field.
990
+ * @type {String}
991
+ */
992
+ alignmentFormFieldId: null,
993
+
994
+ /**
995
+ * Gets or sets the id of the base image file button.
996
+ * @type {String}
997
+ */
998
+ fileButtonId: null,
999
+
1000
+ /**
1001
+ * Gets or sets the id of the base image constrain button.
1002
+ * @type {String}
1003
+ */
1004
+ constrainButtonId: null
1005
+ };
1006
+
1007
+ /**
1008
+ * Gets or sets identifiers for controls in the media dialog.
1009
+ * @type {Object}
1010
+ */
1011
+ this.mediaDialog = {
1012
+ /**
1013
+ * Gets or sets the id of the base media-source form-field.
1014
+ * @type {String}
1015
+ */
1016
+ sourceFormFieldId: null,
1017
+
1018
+ /**
1019
+ * Gets or sets the id of the base media-embed form-field.
1020
+ * @type {String}
1021
+ */
1022
+ embedFormFieldId: null,
1023
+
1024
+ /**
1025
+ * Gets or sets the id of the base media-width form-field.
1026
+ * @type {String}
1027
+ */
1028
+ widthFormFieldId: null,
1029
+
1030
+ /**
1031
+ * Gets or sets the id of the base media-caption form-field.
1032
+ * @type {String}
1033
+ */
1034
+ captionFormFieldId: null
1035
+ };
1036
+
1037
+ /**
1038
+ * Gets or sets identifiers for controls in the table dialog.
1039
+ * @type {Object}
1040
+ */
1041
+ this.tableDialog = {
1042
+ /**
1043
+ * Gets or sets the id of the base table-width form-field.
1044
+ * @type {String}
1045
+ */
1046
+ tableWidthFormFieldId: null,
1047
+
1048
+ /**
1049
+ * Gets or sets the id of the base table-align form-field.
1050
+ * @type {String}
1051
+ */
1052
+ tableAlignFormFieldId: null,
1053
+
1054
+ /**
1055
+ * Gets or sets the id of the base table-border-width form-field.
1056
+ * @type {String}
1057
+ */
1058
+ tableBorderWidthFormFieldId: null,
1059
+
1060
+ /**
1061
+ * Gets or sets the id of the base table-border-style form-field.
1062
+ * @type {String}
1063
+ */
1064
+ tableBorderStyleFormFieldId: null,
1065
+
1066
+ /**
1067
+ * Gets or sets the id of the base table-cell-spacing form-field.
1068
+ * @type {String}
1069
+ */
1070
+ tableCellSpacingFormFieldId: null,
1071
+
1072
+ /**
1073
+ * Gets or sets the id of the base table-cell-padding form-field.
1074
+ * @type {String}
1075
+ */
1076
+ tableCellPaddingFormFieldId: null,
1077
+
1078
+ /**
1079
+ * Gets or sets the id of the base table-caption form-field.
1080
+ * @type {String}
1081
+ */
1082
+ tableCaptionFormFieldId: null,
1083
+
1084
+ /**
1085
+ * Gets or sets the id of the base table-background-color form-field.
1086
+ * @type {String}
1087
+ */
1088
+ tableBgColorFormFieldId: null,
1089
+
1090
+ /**
1091
+ * Gets or sets the id of the base table-border-color form-field.
1092
+ * @type {String}
1093
+ */
1094
+ tableBorderColorFormFieldId: null,
1095
+
1096
+ /**
1097
+ * Gets or sets the id of the base row-is-header form-field.
1098
+ * @type {String}
1099
+ */
1100
+ rowIsHeaderFormFieldId: null,
1101
+
1102
+ /**
1103
+ * Gets or sets the id of the base row-is-footer form-field.
1104
+ * @type {String}
1105
+ */
1106
+ rowIsFooterFormFieldId: null,
1107
+
1108
+ /**
1109
+ * Gets or sets the id of the base row-height form-field.
1110
+ * @type {String}
1111
+ */
1112
+ rowHeightFormFieldId: null,
1113
+
1114
+ /**
1115
+ * Gets or sets the id of the base row-background-color form-field.
1116
+ * @type {String}
1117
+ */
1118
+ rowBgColorFormFieldId: null,
1119
+
1120
+ /**
1121
+ * Gets or sets the id of the base row-border-style form-field.
1122
+ * @type {String}
1123
+ */
1124
+ rowBorderStyleFormFieldId: null,
1125
+
1126
+ /**
1127
+ * Gets or sets the id of the base row-border-color form-field.
1128
+ * @type {String}
1129
+ */
1130
+ rowBorderColorFormFieldId: null,
1131
+
1132
+ /**
1133
+ * Gets or sets the id of the base cell-width form-field.
1134
+ * @type {String}
1135
+ */
1136
+ cellWidthFormFieldId: null,
1137
+
1138
+ /**
1139
+ * Gets or sets the id of the base cell-height form-field.
1140
+ * @type {String}
1141
+ */
1142
+ cellHeightFormFieldId: null,
1143
+
1144
+ /**
1145
+ * Gets or sets the id of the base cell-vertical-align form-field.
1146
+ * @type {String}
1147
+ */
1148
+ cellVerticalAlignFormFieldId: null,
1149
+
1150
+ /**
1151
+ * Gets or sets the id of the base cell-horizontal-align form-field.
1152
+ * @type {String}
1153
+ */
1154
+ cellHorizontalAlignFormFieldId: null,
1155
+
1156
+ /**
1157
+ * Gets or sets the id of the base cell-border-width form-field.
1158
+ * @type {String}
1159
+ */
1160
+ cellBorderWidthFormFieldId: null,
1161
+
1162
+ /**
1163
+ * Gets or sets the id of the base cell-border-style form-field.
1164
+ * @type {String}
1165
+ */
1166
+ cellBorderStyleFormFieldId: null,
1167
+
1168
+ /**
1169
+ * Gets or sets the id of the base cell-padding form-field.
1170
+ * @type {String}
1171
+ */
1172
+ cellPaddingFormFieldId: null,
1173
+
1174
+ /**
1175
+ * Gets or sets the id of the base cell-background-color form-field.
1176
+ * @type {String}
1177
+ */
1178
+ cellBgColorFormFieldId: null,
1179
+
1180
+ /**
1181
+ * Gets or sets the id of the base cell-border-color form-field.
1182
+ * @type {String}
1183
+ */
1184
+ cellBorderColorFormFieldId: null,
1185
+
1186
+
1187
+ /**
1188
+ * Gets or sets the id of the base cell-horizontal-align combo-box.
1189
+ * @type {String}
1190
+ */
1191
+ horizontalAlignComboBoxId: null,
1192
+
1193
+ /**
1194
+ * Gets or sets the id of the base cell-vertical-align combo-box.
1195
+ * @type {String}
1196
+ */
1197
+ verticalAlignComboBoxId: null,
1198
+
1199
+ /**
1200
+ * Gets or sets the id of the base border-style combo-box, shared across table, row and cell panels.
1201
+ * @type {String}
1202
+ */
1203
+ borderStyleComboBoxId: null,
1204
+
1205
+ /**
1206
+ * Gets or sets the id of the base border-color button, shared across table, row and cell panels.
1207
+ * @type {String}
1208
+ */
1209
+ borderColorButtonId: null,
1210
+
1211
+ /**
1212
+ * Gets or sets the id of the base background-color button, shared across table, row and cell panels.
1213
+ * @type {String}
1214
+ */
1215
+ bgColorButtonId: null,
1216
+ };
1217
+
1218
+ /**
1219
+ * Gets or sets the id of the base validator.
1220
+ * @type {String}
1221
+ */
1222
+ this.validatorId = null;
1223
+
1224
+ /**
1225
+ * Gets or sets the id of the base emoji symbol picker box.
1226
+ * @type {String}
1227
+ */
1228
+ this.emojiSymbolPickerBoxId = null;
1229
+
1230
+ /**
1231
+ * Gets or sets the id of the base special symbol picker box.
1232
+ * @type {String}
1233
+ */
1234
+ this.specialSymbolPickerBoxId = null;
1235
+
1236
+ /**
1237
+ * Gets or sets the id of the base button tooltip manager.
1238
+ * @type {String}
1239
+ */
1240
+ this.buttonTooltipManagerId = null;
1241
+
1242
+ /**
1243
+ * Gets or sets the id of the base document tooltip manager.
1244
+ * @type {String}
1245
+ */
1246
+ this.documentTooltipManagerId = null;
1247
+
1248
+ /**
1249
+ * Gets or sets the id of the base table picker box.
1250
+ * @type {String}
1251
+ */
1252
+ this.tablePickerBoxId = null;
1253
+
1254
+
1255
+ /**
1256
+ * Gets or sets a custom sanitizer function to sanitize HTML. When set, overrides the built-in sanitizer.
1257
+ * The function receives an HTML string and should return a sanitized HTML string.
1258
+ * For high-security requirements, consider a dedicated library such as DOMPurify.
1259
+ * Client-side sanitization is not a substitute for server-side validation.
1260
+ * @type {Function|null}
1261
+ */
1262
+ this.sanitizer = null;
1263
+
1264
+ /** --- Editor Module API --- */
1265
+
1266
+ /**
1267
+ * Provides utilities for working with the DOM selection and ranges within the editor document.
1268
+ * Use this in custom commands to get, manipulate and restore the selection range.
1269
+ * @type {componyx.UI.editor_modules.SelectionRange}
1270
+ */
1271
+ this.selectionRange = null;
1272
+
1273
+ /**
1274
+ * Provides utilities for querying and manipulating DOM nodes within the editor document.
1275
+ * @type {componyx.UI.editor_modules.NodeManager}
1276
+ */
1277
+ this.nodeManager = null;
1278
+
1279
+ /**
1280
+ * Manages the editor document content, including inserting and sanitizing HTML.
1281
+ * @type {componyx.UI.editor_modules.ContentManager}
1282
+ */
1283
+ this.contentManager = null;
1284
+
1285
+ /**
1286
+ * Provides text formatting operations on the current selection range.
1287
+ * @type {componyx.UI.editor_modules.Format}
1288
+ */
1289
+ this.format = null;
1290
+
1291
+ /**
1292
+ * Manages the undo/redo history stack.
1293
+ * Call history.addItem() at the end of every custom command that mutates the document,
1294
+ * otherwise undo will not work correctly.
1295
+ * @type {componyx.UI.editor_modules.History}
1296
+ */
1297
+ this.history = null;
1298
+
1299
+ /**
1300
+ * Tracks the current layout state of the editor, including the active selection context
1301
+ * (link, image, table etc.). Call layoutState.getState() after mutations that affect
1302
+ * the active layout to keep the toolbar in sync.
1303
+ * @type {componyx.UI.editor_modules.LayoutState}
1304
+ */
1305
+ this.layoutState = null;
1306
+
1307
+ /**
1308
+ * Provides general editor utilities.
1309
+ * @type {componyx.UI.editor_modules.Utility}
1310
+ */
1311
+ this.utility = null;
1312
+
1313
+ /** --- Editor Internal Modules --- */
1314
+
1315
+ /** @ignore
1316
+ * @type {componyx.UI.editor_modules.ComponentFactory}
1317
+ */
1318
+ this.componentFactory = null;
1319
+
1320
+ /** @ignore
1321
+ * @type {componyx.UI.editor_modules.DialogManager}
1322
+ */
1323
+ this.dialogManager = null;
1324
+
1325
+ /** @ignore
1326
+ * @type {componyx.UI.editor_modules.EventManager}
1327
+ */
1328
+ this.eventManager = null;
1329
+
1330
+ /** @ignore
1331
+ * @type {componyx.UI.editor_modules.ListManager}
1332
+ */
1333
+ this.listManager = null;
1334
+
1335
+ /** @ignore
1336
+ * @type {componyx.UI.editor_modules.MenuManager}
1337
+ */
1338
+ this.menuManager = null;
1339
+
1340
+ /** @ignore
1341
+ * @type {componyx.UI.editor_modules.ParagraphButtons}
1342
+ */
1343
+ this.paragraphButtons = null;
1344
+
1345
+ /** @ignore
1346
+ * @type {componyx.UI.editor_modules.Resizer}
1347
+ */
1348
+ this.resizer = null;
1349
+
1350
+ /** @ignore
1351
+ * @type {componyx.UI.editor_modules.SourceViewBuilder}
1352
+ */
1353
+ this.sourceViewBuilder = null;
1354
+
1355
+ /** @ignore
1356
+ * @type {componyx.UI.editor_modules.Table}
1357
+ */
1358
+ this.table = null;
1359
+
1360
+ /** @ignore
1361
+ * @type {componyx.UI.editor_modules.Toolbar}
1362
+ */
1363
+ this.toolbar = null;
1364
+
1365
+ /** @ignore
1366
+ * @type {componyx.UI.editor_modules.TooltipMenu}
1367
+ */
1368
+ this.tooltipMenu = null;
1369
+
1370
+ /**
1371
+ * Gets or sets a value indicating if the toolbar box is allowed to hide.
1372
+ * @private
1373
+ * @ignore
1374
+ */
1375
+ this.allowToolbarBoxHide = true;
1376
+
1377
+ /**
1378
+ * Gets or sets a value indicating if the selection change event needs to be canceled.
1379
+ * @private
1380
+ * @ignore
1381
+ */
1382
+ this.cancelSelectionChange = false;
1383
+
1384
+ /**
1385
+ * Gets the iframe element.
1386
+ * @private
1387
+ * @ignore
1388
+ */
1389
+ Object.defineProperty(this, '_iframe', { get: () => _iframe });
1390
+
1391
+ /**
1392
+ * Selects the node (must be called with bind).
1393
+ * @ignore
1394
+ */
1395
+ this.selectNode = selectNode;
1396
+
1397
+ /**
1398
+ * Gets the selected nodes.
1399
+ * @returns {any} return value
1400
+ * @ignore
1401
+ */
1402
+ this.getSelectedNodes = () =>
1403
+ {
1404
+ return _editableElement.querySelectorAll(`*[${_instance.utility.selAttr}="1"]`);
1405
+ };
1406
+
1407
+ /**
1408
+ * Clears the selected nodes.
1409
+ * @ignore
1410
+ */
1411
+ this.clearSelection = () =>
1412
+ {
1413
+ let nodes = _instance.getSelectedNodes();
1414
+ $lib.each(nodes, (node) =>
1415
+ {
1416
+ node.setAttribute(_instance.utility.selAttr, '');
1417
+ });
1418
+
1419
+ _instance.paragraphButtons.hide();
1420
+ };
1421
+
1422
+ /**
1423
+ * Returns a value indicating if the editor body has content.
1424
+ * @returns {boolean}
1425
+ * @ignore
1426
+ */
1427
+ this.hasContent = () => { return _instance.contentManager.hasContent(); };
1428
+
1429
+ /**
1430
+ * Gets the toolbar display setting for an editable element.
1431
+ * @param {HTMLElement} el
1432
+ * @returns {ToolbarDisplayOption}
1433
+ * @ignore
1434
+ */
1435
+ this.getToolbarDisplay = (el) => { return getToolbarDisplay(el); };
1436
+
1437
+ /**
1438
+ * Shows or hides the toolbar box.
1439
+ * @param {boolean} show
1440
+ * @ignore
1441
+ */
1442
+ this.setToolbarBoxDisplay = (show) => { setToolbarBoxDisplay(show); };
1443
+
1444
+ /**
1445
+ Activates the current document.
1446
+ */
1447
+ this.activateDocument = () =>
1448
+ {
1449
+ activateDocument();
1450
+ };
1451
+
1452
+ /** Deactivates the current document.
1453
+ */
1454
+ this.deactivateDocument = () =>
1455
+ {
1456
+ deactivateDocument();
1457
+ };
1458
+
1459
+ /**
1460
+ * Gets the active editor based on a node.
1461
+ * @param {Node} activeNode - The node to set as active editor.
1462
+ * @returns {any} - Result of setting the active editor.
1463
+ * @ignore
1464
+ */
1465
+ this.getActiveEditor = function (activeNode)
1466
+ {
1467
+ return getActiveEditor(activeNode);
1468
+ };
1469
+
1470
+ /**
1471
+ * Sets the active editor based on a node.
1472
+ * @param {Node} activeNode - The node to set as active editor.
1473
+ * @returns {any} - Result of setting the active editor.
1474
+ * @ignore
1475
+ */
1476
+ this.setActiveEditor = function (activeNode)
1477
+ {
1478
+ return setActiveEditor(activeNode);
1479
+ };
1480
+
1481
+ /**
1482
+ * Binds events for selectable elements within a node.
1483
+ * @param {Node} node - The node whose child elements will receive events.
1484
+ * @ignore
1485
+ */
1486
+ this.bindNodeEvents = (node) =>
1487
+ {
1488
+ bindNodeEvents(node);
1489
+ };
1490
+
1491
+ /**
1492
+ * Returns the current document object.
1493
+ * @returns {Document} - The editor's document.
1494
+ * @ignore
1495
+ */
1496
+ this.getDoc = () =>
1497
+ {
1498
+ return _doc;
1499
+ };
1500
+
1501
+ /**
1502
+ * Gets the stored selection range.
1503
+ * @returns {Range}
1504
+ * @ignore
1505
+ */
1506
+ this.getStoredRange = () =>
1507
+ {
1508
+ return _range;
1509
+ };
1510
+
1511
+ /**
1512
+ * Stores the selection range.
1513
+ * @returns {Range}
1514
+ * @ignore
1515
+ */
1516
+ this.storeRange = (range) =>
1517
+ {
1518
+ _range = range;
1519
+ };
1520
+
1521
+ /**
1522
+ * Returns the word count container element.
1523
+ * @returns {HTMLElement}
1524
+ * @ignore
1525
+ */
1526
+ this.getWordCountElement = () =>
1527
+ {
1528
+ return _wordCountEl;
1529
+ };
1530
+
1531
+ /**
1532
+ * Returns the path container element.
1533
+ * @returns {HTMLElement}
1534
+ * @ignore
1535
+ */
1536
+ this.getPathElement = () =>
1537
+ {
1538
+ return _pathEl;
1539
+ };
1540
+
1541
+ /**
1542
+ * Returns a UI component by its ID.
1543
+ * @param {string} id - Component ID.
1544
+ * @returns {any} - The component from $UI.store.
1545
+ * @ignore
1546
+ */
1547
+ this.getComponent = (id) =>
1548
+ {
1549
+ return $UI.store[getId(id)];
1550
+ };
1551
+
1552
+ /**
1553
+ * Gets the source viewer store.
1554
+ * @ignore
1555
+ */
1556
+ this.getSourceViewStore = () =>
1557
+ {
1558
+ return _sourceViewStore;
1559
+ };
1560
+
1561
+ /**
1562
+ * Checks if block view mode is currently selected.
1563
+ * @returns {boolean} - True if block view is active, false otherwise.
1564
+ * @ignore
1565
+ */
1566
+ this.isBlockViewSelected = () =>
1567
+ {
1568
+ return isBlockViewSelected();
1569
+ };
1570
+
1571
+ /**
1572
+ * Disables block view mode.
1573
+ * @ignore
1574
+ */
1575
+ this.disableBlockView = () =>
1576
+ {
1577
+ disableBlockView();
1578
+ };
1579
+
1580
+ /**
1581
+ * Hide overlays.
1582
+ * @ignore
1583
+ */
1584
+ this.hideOverlays = () =>
1585
+ {
1586
+ _instance.resizer.clear(true);
1587
+ _instance.paragraphButtons.destroy(_instance.getEditorElement());
1588
+ _instance.hideTooltips();
1589
+ };
1590
+
1591
+ /**
1592
+ * Hides tooltips.
1593
+ * @ignore
1594
+ */
1595
+ this.hideTooltips = () =>
1596
+ {
1597
+ _instance.tooltipMenu.tooltipManager.hideAllTooltips(true);
1598
+ _instance.componentFactory.tooltipManager.hideAllTooltips(true);
1599
+ };
1600
+
1601
+ /**
1602
+ * Creates the source view builder.
1603
+ * @param {HTMLElement} source
1604
+ * @param {HTMLElement} target
1605
+ * @ignore
1606
+ */
1607
+ this.createSourceViewBuilder = (source, target) =>
1608
+ {
1609
+ createSourceViewBuilder(source, target);
1610
+ };
1611
+
1612
+ /**
1613
+ * Sets the source view builder html.
1614
+ * @param {HTMLElement} source
1615
+ * @ignore
1616
+ */
1617
+ this.setSourceViewBuilderHTML = (source) =>
1618
+ {
1619
+ setSourceViewBuilderHTML(source);
1620
+ };
1621
+
1622
+ /**
1623
+ * Gets the commands as sorted array.
1624
+ * @ignore
1625
+ */
1626
+ this.getSortedCommands = () =>
1627
+ {
1628
+ return _sortedCommands;
1629
+ };
1630
+
1631
+ /**
1632
+ * Gets the css class if it exists and otherwise the default css class.
1633
+ * @returns {String} The css class.
1634
+ * @ignore
1635
+ */
1636
+ this.getCssClass = (cssClassValue) =>
1637
+ {
1638
+ const classOption = _instance.classOption;
1639
+ const key = Object.keys(classOption).find(key => classOption[key] === cssClassValue);
1640
+ const propertyName = key.split('_').map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(''); // Convert enum key to a proper property format (e.g., 'BUILD_PANE' -> 'BuildPane')
1641
+
1642
+ return _instance[`cssClass${propertyName}`] || cssClassValue;
1643
+ };
1644
+
1645
+ /**
1646
+ * Gets the Sanitizer object to sanitize HTML.
1647
+ * @returns {componyx.bindary_modules.Sanitizer} The Sanitizer object.
1648
+ * @ignore
1649
+ */
1650
+ this.getSanitizer = function ()
1651
+ {
1652
+ if (!_sanitizer)
1653
+ {
1654
+ _sanitizer = new Sanitizer();
1655
+ _instance.events.onCreateSanitizer.fire(_instance, { sanitizer: _sanitizer });
1656
+ }
1657
+
1658
+ return _sanitizer;
1659
+ };
1660
+
1661
+ /**
1662
+ * Callback for image-related events.
1663
+ * @typedef {function} componyx.UI.Editor.ImageEventHandler
1664
+ * @param {componyx.UI.Editor} editor - The editor instance firing the event.
1665
+ * @param {componyx.UI.Editor.ImageEventArgs} eventArgs - The event details.
1666
+ */
1667
+
1668
+ /**
1669
+ * @typedef {Object} componyx.UI.Editor.ImageEventArgs
1670
+ * @property {HTMLImageElement} imageElement - The image element involved.
1671
+ * @property {File|null} [file] - The image file if available, otherwise null.
1672
+ */
1673
+
1674
+ /**
1675
+ * Callback for paste events.
1676
+ * @typedef {function} componyx.UI.Editor.PasteEventHandler
1677
+ * @param {componyx.UI.Editor} editor - The editor instance firing the event.
1678
+ * @param {componyx.UI.Editor.PasteEventArgs} eventArgs - The event details.
1679
+ */
1680
+
1681
+ /**
1682
+ * @typedef {Object} componyx.UI.Editor.PasteEventArgs
1683
+ * @property {ClipboardEvent} event - The native paste event.
1684
+ */
1685
+
1686
+ /**
1687
+ * Callback for base editor events (stylesheets loaded, undo, redo, selection change).
1688
+ * @typedef {function} componyx.UI.Editor.BaseEventHandler
1689
+ * @param {componyx.UI.Editor} editor - The editor instance firing the event.
1690
+ */
1691
+
1692
+ /**
1693
+ * @typedef {function} componyx.UI.Editor.LinkDialogShowEventHandler
1694
+ * @param {componyx.UI.Editor} editor - The editor instance firing the event.
1695
+ * @param {componyx.UI.Editor.LinkDialogShowEventArgs} eventArgs - The event details.
1696
+ */
1697
+
1698
+ /**
1699
+ * @typedef {Object} componyx.UI.Editor.LinkDialogShowEventArgs
1700
+ * @property {HTMLElement} container - The dialog content container element.
1701
+ * @property {componyx.UI.Editor.ActiveLinkItem|null} activeItem - The currently active link in the editor, or null if no link is selected.
1702
+ * @property {componyx.UI.Editor.ConfirmLinkSelectionCallback} confirmSelection - A function to confirm the selected link and insert it into the document.
1703
+ */
1704
+
1705
+ /**
1706
+ * @typedef {Object} componyx.UI.Editor.ActiveLinkItem
1707
+ * @property {string} href - The URL or path of the link.
1708
+ * @property {string} text - The link text.
1709
+ * @property {string} title - The link title.
1710
+ * @property {string} target - The link target.
1711
+ */
1712
+
1713
+ /**
1714
+ * @callback componyx.UI.Editor.ConfirmLinkSelectionCallback
1715
+ * @param {String} url - The URL or path of the selected image.
1716
+ * @param {String} [linkText] - The link text.
1717
+ * @param {String} [linkTitle] - The link title.
1718
+ */
1719
+
1720
+ /**
1721
+ * @typedef {function} componyx.UI.Editor.ImageDialogShowEventHandler
1722
+ * @param {componyx.UI.Editor} editor - The editor instance firing the event.
1723
+ * @param {componyx.UI.Editor.ImageDialogShowEventArgs} eventArgs - The event details.
1724
+ */
1725
+
1726
+ /**
1727
+ * @typedef {Object} componyx.UI.Editor.ImageDialogShowEventArgs
1728
+ * @property {HTMLElement} container - The dialog content container element.
1729
+ * @property {componyx.UI.Editor.ActiveImageItem|null} activeItem - The currently active image in the editor, or null if no image is selected.
1730
+ * @property {componyx.UI.Editor.ConfirmImageSelectionCallback} confirmSelection - A function to confirm the selected image and insert it into the document.
1731
+ */
1732
+
1733
+ /**
1734
+ * @typedef {Object} componyx.UI.Editor.ActiveImageItem
1735
+ * @property {string} src - The URL or path of the image.
1736
+ * @property {string} alt - The alternative text.
1737
+ * @property {number} width - The image width.
1738
+ * @property {number} height - The image height.
1739
+ * @property {string} caption - The caption text.
1740
+ */
1741
+
1742
+ /**
1743
+ * @callback componyx.UI.Editor.ConfirmImageSelectionCallback
1744
+ * @param {String} url - The URL or path of the selected image.
1745
+ * @param {String} [alt] - The alternative text.
1746
+ * @param {String} [caption] - The caption text.
1747
+ */
1748
+
1749
+ /**
1750
+ * @typedef {function} componyx.UI.Editor.MediaDialogShowEventHandler
1751
+ * @param {componyx.UI.Editor} editor - The editor instance firing the event.
1752
+ * @param {componyx.UI.Editor.MediaDialogShowEventArgs} eventArgs - The event details.
1753
+ */
1754
+
1755
+ /**
1756
+ * @typedef {Object} componyx.UI.Editor.MediaDialogShowEventArgs
1757
+ * @property {HTMLElement} container - The dialog content container element.
1758
+ * @property {componyx.UI.Editor.ActiveMediaItem|null} activeItem - The currently active media in the editor, or null if no media is selected.
1759
+ * @property {componyx.UI.Editor.ConfirmMediaSelectionCallback} confirmSelection - A function to confirm the selected media and insert it into the document.
1760
+ */
1761
+
1762
+ /**
1763
+ * @typedef {Object} componyx.UI.Editor.ActiveMediaItem
1764
+ * @property {string|null} src - The URL or path of the media, or null if embedded.
1765
+ * @property {string|null} embed - The embed HTML, or null if a URL is used.
1766
+ * @property {string} width - The media width.
1767
+ * @property {string} caption - The caption text.
1768
+ */
1769
+
1770
+ /**
1771
+ * @callback componyx.UI.Editor.ConfirmMediaSelectionCallback
1772
+ * @param {String} url - The URL or path of the selected media.
1773
+ */
1774
+
1775
+ /**
1776
+ * Callback for sanitizer creation events.
1777
+ * @typedef {function} componyx.UI.Editor.CreateSanitizerEventHandler
1778
+ * @param {componyx.UI.Editor} editor - The editor instance firing the event.
1779
+ * @param {componyx.UI.Editor.CreateSanitizerEventArgs} eventArgs - The event details.
1780
+ */
1781
+
1782
+ /**
1783
+ * @typedef {Object} componyx.UI.Editor.CreateSanitizerEventArgs
1784
+ * @property {componyx.base_modules.Sanitizer} sanitizer - The created sanitizer class instance.
1785
+ */
1786
+
1787
+ /**
1788
+ * Callback for save events.
1789
+ * @typedef {function} componyx.UI.Editor.SaveEventHandler
1790
+ * @param {componyx.UI.Editor} editor - The editor instance firing the event.
1791
+ * @param {componyx.UI.Editor.SaveEventArgs} eventArgs - The event details.
1792
+ */
1793
+
1794
+ /**
1795
+ * @typedef {Object} componyx.UI.Editor.SaveEventArgs
1796
+ * @property {String} html - The document HTML content.
1797
+ */
1798
+
1799
+ /**
1800
+ * @class
1801
+ * @augments componyx.UI.base.Events
1802
+ * @memberof componyx.UI.Editor
1803
+ * @property {componyx.UI.base.Event} onStylesheetsLoaded - Fires when all included iframe stylesheets are loaded. @see {@link componyx.UI.Editor.BaseEventHandler}
1804
+ * @property {componyx.UI.base.Event} onImageDrop - Fires when an image is dragged and dropped into the editor. @see {@link componyx.UI.Editor.ImageEventHandler}
1805
+ * @property {componyx.UI.base.Event} onImageSelect - Fires when an image is selected or URL provided. @see {@link componyx.UI.Editor.ImageEventHandler}
1806
+ * @property {componyx.UI.base.Event} onImageLoad - Fires when an image is fully loaded. @see {@link componyx.UI.Editor.ImageEventHandler}
1807
+ * @property {componyx.UI.base.Event} onPaste - Fires on paste. @see {@link componyx.UI.Editor.PasteEventHandler}
1808
+ * @property {componyx.UI.base.Event} onUndo - Fires on undo. @see {@link componyx.UI.Editor.BaseEventHandler}
1809
+ * @property {componyx.UI.base.Event} onRedo - Fires on redo. @see {@link componyx.UI.Editor.BaseEventHandler}
1810
+ * @property {componyx.UI.base.Event} onSelectionChange - Fires on text selection change. @see {@link componyx.UI.Editor.BaseEventHandler}
1811
+ * @property {componyx.UI.base.Event} onSave - Fires on save. @see {@link componyx.UI.Editor.SaveEventHandler}
1812
+ * @property {componyx.UI.base.Event} onLinkDialogShow - Fires when the image dialog content is rendered. @see {@link componyx.UI.Editor.LinkDialogShowEventHandler}
1813
+ * @property {componyx.UI.base.Event} onImageDialogShow - Fires when the image dialog content is rendered. @see {@link componyx.UI.Editor.ImageDialogShowEventHandler}
1814
+ * @property {componyx.UI.base.Event} onMediaDialogShow - Fires when the image dialog content is rendered. @see {@link componyx.UI.Editor.MediaDialogShowEventHandler}
1815
+ * @property {componyx.UI.base.Event} onCreateSanitizer - Fires when the default HTML sanitizer is created, allowing optional configuration. @see {@link componyx.UI.Editor.CreateSanitizerEventHandler}
1816
+ * @see {@link componyx.UI.base.Events}
1817
+ */
1818
+ function EditorEvents(events)
1819
+ {
1820
+ Object.assign(this, events);
1821
+ this.onStylesheetsLoaded = $base.static.createEvent('onStylesheetsLoaded');
1822
+ this.onImageDrop = $base.static.createEvent('onImageDrop');
1823
+ this.onImageSelect = $base.static.createEvent('onImageSelect');
1824
+ this.onImageLoad = $base.static.createEvent('onImageLoad');
1825
+ this.onPaste = $base.static.createEvent('onPaste');
1826
+ this.onUndo = $base.static.createEvent('onUndo');
1827
+ this.onRedo = $base.static.createEvent('onRedo');
1828
+ this.onSelectionChange = $base.static.createEvent('onSelectionChange');
1829
+ this.onSave = $base.static.createEvent('onSave');
1830
+ this.onLinkDialogShow = $base.static.createEvent('onLinkDialogShow');
1831
+ this.onImageDialogShow = $base.static.createEvent('onImageDialogShow');
1832
+ this.onMediaDialogShow = $base.static.createEvent('onMediaDialogShow');
1833
+ this.onCreateSanitizer = $base.static.createEvent('onCreateSanitizer');
1834
+ }
1835
+ /**
1836
+ * Editor events
1837
+ * @type {componyx.UI.Editor.EditorEvents}
1838
+ */
1839
+ this.events = new EditorEvents(this.events);
1840
+
1841
+ // inherit base instance members
1842
+ $base.Component.apply(this, [id, properties]);
1843
+
1844
+ /** --- public API Methods --- */
1845
+
1846
+ /**
1847
+ * Adds a content editable element
1848
+ * @param {EditableElement} config The settings of the editable element.
1849
+ */
1850
+ this.addEditableElement = function (config)
1851
+ {
1852
+ const element = config.element || $lib('#' + config.id),
1853
+ exists = this.editableElements.some(c =>
1854
+ {
1855
+ const existing = c.element || $lib('#' + c.id);
1856
+ return existing === element;
1857
+ });
1858
+
1859
+ if (exists)
1860
+ return;
1861
+
1862
+ const active = { doc: _doc, el: _editableElement };
1863
+
1864
+ this.editableElements.push(config);
1865
+ setupEditor(element);
1866
+
1867
+ if (active.el?.isConnected)
1868
+ {
1869
+ _doc = active.doc;
1870
+ _editableElement = active.el;
1871
+ }
1872
+ };
1873
+
1874
+ /**
1875
+ * Undoes an action.
1876
+ */
1877
+ this.undo = function () { _instance.history.undo(_editableElement); };
1878
+ /**
1879
+ * Redoes an action.
1880
+ */
1881
+ this.redo = function () { _instance.history.redo(_editableElement); };
1882
+ /**
1883
+ * Set/unsets bold on the currently selected text range.
1884
+ */
1885
+ this.bold = () => { toggleLayoutNode({ tag: 'strong' }); };
1886
+ /**
1887
+ * Set/unsets italic on the currently selected text range.
1888
+ */
1889
+ this.italic = () => { toggleLayoutNode({ tag: 'em' }); };
1890
+ /**
1891
+ * Set/unsets underline on the currently selected text range.
1892
+ */
1893
+ this.underline = () => { toggleLayoutNode({ tag: 'u' }); };
1894
+ /**
1895
+ * Set/unsets strike-through on the currently selected text range.
1896
+ */
1897
+ this.strikeThrough = () => { toggleLayoutNode({ tag: 's' }); };
1898
+ /**
1899
+ * Set/unsets sub on the currently selected text range.
1900
+ */
1901
+ this.sub = () => { toggleLayoutNode({ tag: 'sub' }); };
1902
+ /**
1903
+ * Set/unsets super on the currently selected text range.
1904
+ */
1905
+ this.sup = () => { toggleLayoutNode({ tag: 'sup' }); };
1906
+ /**
1907
+ * Increases/decreases the indent on the current root block element.
1908
+ * @param {String} value A positive or negative CSS value.
1909
+ */
1910
+ this.indent = (value) => { indent(value); };
1911
+ /**
1912
+ * Clears the formatting on the currently selected text range.
1913
+ */
1914
+ this.clearFormat = () => { clearFormat(); };
1915
+ /**
1916
+ * Copies the formatting on the currently selected text range.
1917
+ * @returns {Node[]} A list of formatting nodes currently active on the selected text range.
1918
+ */
1919
+ this.copyFormat = () => { return copyFormat(); };
1920
+ /**
1921
+ * Pastes the formatting on the currently selected text range.
1922
+ * @param {Node[]} format A list of formatting nodes to apply to the selected text range.
1923
+ */
1924
+ this.pasteFormat = (format) => { _instance.format.pasteFormat(format); };
1925
+ /**
1926
+ * Converts the root block-level nodes in the currently selected text range to the specified block-level tag.
1927
+ * @param {String} tag The block-level element tag.
1928
+ */
1929
+ this.setBlock = (tag) => { setBlock(tag); };
1930
+ /**
1931
+ * Surrounds/unsurrounds the currently selected text range with the specified layout node.
1932
+ * @param {String} tag The layout-node tag.
1933
+ * @param {Object<string, any>} styles The CSS styles.
1934
+ */
1935
+ this.toggleLayoutNode = (settings) => { toggleLayoutNode(settings); };
1936
+ /**
1937
+ * Inserts HTML on the currently selected text range.
1938
+ * @param {ElementSettings} settings The element settings.
1939
+ */
1940
+ this.insert = (settings) => { insertHTML(settings); };
1941
+ /**
1942
+ * Shows/hides the HTML source viewer.
1943
+ * @param {Boolean} on Use value null to toggle, true to force on, false to force off.
1944
+ */
1945
+ this.toggleSourceView = (on = null) =>
1946
+ {
1947
+ toggleMenuButton($UI.store[getId('source')], on);
1948
+ sourceView();
1949
+ };
1950
+ /**
1951
+ * Enables/disables the visibility of block level elements in the document.
1952
+ * @param {Boolean} on Use value null to toggle, true to force on, false to force off.
1953
+ */
1954
+ this.toggleBlockView = (on = null) =>
1955
+ {
1956
+ toggleMenuButton($UI.store[getId('blockView')], on);
1957
+ blockView();
1958
+ };
1959
+ /**
1960
+ * Expand/collapse the editor view to fullscreen.
1961
+ * @param {Boolean} on Use value null to toggle, true to force on, false to force off.
1962
+ */
1963
+ this.toggleExpandedView = (on = null) =>
1964
+ {
1965
+ toggleMenuButton($UI.store[getId('expand')], on);
1966
+ expandedView();
1967
+ };
1968
+ /**
1969
+ * Shows/hides the document in preview modus.
1970
+ * @param {Boolean} on Use value null to toggle, true to force on, false to force off.
1971
+ */
1972
+ this.togglePreview = (on = null) =>
1973
+ {
1974
+ toggleMenuButton($UI.store[getId('preview')], on);
1975
+ preview();
1976
+ };
1977
+ /**
1978
+ * Saves the document.
1979
+ */
1980
+ this.save = () => { save(); };
1981
+ /**
1982
+ * Exports the document. Configure settings via PDFExportSettings.
1983
+ */
1984
+ this.exportToPDF = () => { exportToPDF(); };
1985
+ /**
1986
+ * Prints the document.
1987
+ */
1988
+ this.print = () => { print(); };
1989
+
1990
+ /**
1991
+ * Gets a value indicating if the editor has editable elements.
1992
+ * @returns {boolean}
1993
+ */
1994
+ this.hasEditables = () => { return hasEditables(); };
1995
+
1996
+ /**
1997
+ * Show bookmark dialog.
1998
+ */
1999
+ this.bookmark = () => { bookmark(); };
2000
+
2001
+ /**
2002
+ * Show the insert link dialog to create a link for the selection range.
2003
+ */
2004
+ this.insertLink = () => { insertLink(); };
2005
+
2006
+ /**
2007
+ * Removes the active link in the selection range.
2008
+ */
2009
+ this.removeLink = () => { removeLink(); };
2010
+
2011
+ /**
2012
+ * Show the insert image dialog to create a link for the selection range.
2013
+ */
2014
+ this.insertImage = () => { insertImage(); };
2015
+
2016
+ /**
2017
+ * Removes the active image in the selection range.
2018
+ */
2019
+ this.removeImage = () => { removeImage(); };
2020
+
2021
+ /**
2022
+ * Show the insert media dialog to create a link for the selection range.
2023
+ */
2024
+ this.insertMedia = () => { insertMedia(); };
2025
+
2026
+ /**
2027
+ * Removes the active media in the selection range.
2028
+ */
2029
+ this.removeMedia = () => { removeMedia(); };
2030
+
2031
+ /**
2032
+ * Sets the text-align value on the nodes in the selection range.
2033
+ * @param {Number} value
2034
+ */
2035
+ this.align = (value) => { _instance.format.setBlockStyle('text-align', value); };
2036
+
2037
+ /**
2038
+ * Sets the line-height on the nodes in the selection range.
2039
+ * @param {Number} value
2040
+ */
2041
+ this.lineHeight = (value) => { _instance.format.setBlockStyle('line-height', value); };
2042
+
2043
+ /**
2044
+ * Sets the font family.
2045
+ * @param {any} font
2046
+ * @ignore
2047
+ */
2048
+ this.setFontFamily = (font) =>
2049
+ {
2050
+ toggleLayoutNode({ tag: 'span', styles: { 'font-family': font } });
2051
+ };
2052
+
2053
+ /**
2054
+ * Sets the font size.
2055
+ * @param {any} size
2056
+ * @ignore
2057
+ */
2058
+ this.setFontSize = (size) =>
2059
+ {
2060
+ toggleLayoutNode({ tag: 'span', styles: { 'font-size': size } });
2061
+ };
2062
+
2063
+ /**
2064
+ * Sets the font color.
2065
+ * @param {any} cmd
2066
+ * @ignore
2067
+ */
2068
+ this.setFontColor = (cmd) =>
2069
+ {
2070
+ let button = _instance.getComponent(cmd.id);
2071
+
2072
+ toggleLayoutNode({ tag: 'span', styles: { 'color': button.__color } });
2073
+ };
2074
+
2075
+ /**
2076
+ * Sets the font BG color.
2077
+ * @param {any} cmd
2078
+ * @ignore
2079
+ */
2080
+ this.setFontBGColor = (cmd) =>
2081
+ {
2082
+ let button = _instance.getComponent(cmd.id);
2083
+
2084
+ toggleLayoutNode({ tag: 'span', styles: { 'background-color': button.__color } });
2085
+ };
2086
+
2087
+ /**
2088
+ * Sets the style.
2089
+ * @param {any} styleItem
2090
+ * @ignore
2091
+ */
2092
+ this.setStyle = (styleItem) =>
2093
+ {
2094
+ insertHTML(styleItem.elementSettings);
2095
+ };
2096
+
2097
+ /**
2098
+ * Editor commands.
2099
+ * @type {Object.<string, CommandSettings>}
2100
+ */
2101
+ this.commands =
2102
+ {
2103
+ undo:
2104
+ {
2105
+ command: _instance.undo,
2106
+ shortcutKey: 'z',
2107
+ cssClassIcon: _iconPrefix + 'undo',
2108
+ show: true,
2109
+ buttonId: null,
2110
+ group: 0,
2111
+ position: 0
2112
+ },
2113
+ redo:
2114
+ {
2115
+ command: _instance.redo,
2116
+ shortcutKey: 'y',
2117
+ cssClassIcon: _iconPrefix + 'redo',
2118
+ show: true,
2119
+ buttonId: null,
2120
+ group: 0,
2121
+ position: 0
2122
+ },
2123
+
2124
+ bold:
2125
+ {
2126
+ id: 'strong',
2127
+ command: _instance.bold,
2128
+ shortcutKey: 'b',
2129
+ cssClassIcon: _iconPrefix + 'bold',
2130
+ show: true,
2131
+ isActive: isTagMatch.bind(_instance, 'strong'),
2132
+ type: 1,
2133
+ buttonId: null,
2134
+ group: 1,
2135
+ position: 0,
2136
+ elementSettings: { tag: 'strong' }
2137
+ },
2138
+ italic:
2139
+ {
2140
+ id: 'em',
2141
+ command: _instance.italic,
2142
+ shortcutKey: 'i',
2143
+ cssClassIcon: _iconPrefix + 'italic',
2144
+ show: true,
2145
+ isActive: isTagMatch.bind(_instance, 'em'),
2146
+ type: 1,
2147
+ buttonId: null,
2148
+ group: 1,
2149
+ position: 0,
2150
+ elementSettings: { tag: 'em' }
2151
+ },
2152
+ underline:
2153
+ {
2154
+ id: 'u',
2155
+ command: _instance.underline,
2156
+ shortcutKey: 'u',
2157
+ cssClassIcon: _iconPrefix + 'underline',
2158
+ show: true,
2159
+ isActive: isTagMatch.bind(_instance, 'u'),
2160
+ type: 1,
2161
+ buttonId: null,
2162
+ group: 1,
2163
+ position: 0,
2164
+ elementSettings: { tag: 'u' }
2165
+ },
2166
+ strikeThrough:
2167
+ {
2168
+ id: 's',
2169
+ command: _instance.strikeThrough,
2170
+ cssClassIcon: _iconPrefix + 'strikethrough',
2171
+ show: true,
2172
+ isActive: isTagMatch.bind(_instance, 's'),
2173
+ type: 1,
2174
+ buttonId: null,
2175
+ group: 1,
2176
+ position: 0,
2177
+ elementSettings: { tag: 's' }
2178
+ },
2179
+ fontColor:
2180
+ {
2181
+ command: _instance.setFontColor,
2182
+ cssClassIcon: _iconPrefix + 'font-color',
2183
+ show: true,
2184
+ buttonId: null,
2185
+ type: 1,
2186
+ boxId: 'ColorSwatch',
2187
+ cssVariable: '--font-color',
2188
+ group: 1,
2189
+ position: 0
2190
+ },
2191
+ fontBGColor:
2192
+ {
2193
+ command: _instance.setFontBGColor,
2194
+ cssClassIcon: _iconPrefix + 'font-bgcolor',
2195
+ show: true,
2196
+ buttonId: null,
2197
+ type: 1,
2198
+ boxId: 'ColorSwatch',
2199
+ cssVariable: '--font-bg-color',
2200
+ group: 1,
2201
+ position: 0
2202
+ },
2203
+
2204
+ block:
2205
+ {
2206
+ command: null,
2207
+ show: true,
2208
+ buttonId: null,
2209
+ menuId: null,
2210
+ menuItemId: 'Block',
2211
+ cssClass: 'block',
2212
+ contentAlign: 0,
2213
+ group: 2,
2214
+ position: 0
2215
+ },
2216
+ fontFamily:
2217
+ {
2218
+ command: null,
2219
+ show: true,
2220
+ buttonId: null,
2221
+ menuId: null,
2222
+ menuItemId: 'FontFamily',
2223
+ cssClass: 'font-family',
2224
+ contentAlign: 0,
2225
+ group: 2,
2226
+ position: 0
2227
+ },
2228
+ fontSize:
2229
+ {
2230
+ command: null,
2231
+ show: true,
2232
+ buttonId: null,
2233
+ menuId: null,
2234
+ menuItemId: 'FontSize',
2235
+ cssClass: 'font-size',
2236
+ contentAlign: 0,
2237
+ group: 2,
2238
+ position: 0
2239
+ },
2240
+ style:
2241
+ {
2242
+ command: null,
2243
+ show: false,
2244
+ buttonId: null,
2245
+ menuId: null,
2246
+ menuItemId: 'Style',
2247
+ cssClass: 'style',
2248
+ contentAlign: 0,
2249
+ group: 2,
2250
+ position: 0
2251
+ },
2252
+
2253
+ align:
2254
+ {
2255
+ command: null,
2256
+ cssClassIcon: _iconPrefix + 'align-left',
2257
+ show: true,
2258
+ buttonId: null,
2259
+ menuItemId: 'Align',
2260
+ group: 3,
2261
+ position: 0
2262
+ },
2263
+
2264
+ lineHeight:
2265
+ {
2266
+ command: null,
2267
+ cssClassIcon: _iconPrefix + 'line-height',
2268
+ show: true,
2269
+ buttonId: null,
2270
+ menuItemId: 'LineHeight',
2271
+ group: 3,
2272
+ position: 0
2273
+ },
2274
+
2275
+ indentMin:
2276
+ {
2277
+ command: indent.bind(_instance, '-' + _instance.indentValue),
2278
+ cssClassIcon: _iconPrefix + 'indent-min',
2279
+ show: true,
2280
+ buttonId: null,
2281
+ group: 3,
2282
+ position: 0
2283
+ },
2284
+ indentPlus:
2285
+ {
2286
+ command: indent.bind(_instance, _instance.indentValue),
2287
+ cssClassIcon: _iconPrefix + 'indent-plus',
2288
+ show: true,
2289
+ buttonId: null,
2290
+ group: 3,
2291
+ position: 0
2292
+ },
2293
+
2294
+ orderedList:
2295
+ {
2296
+ command: toggleListItem.bind(_instance, 'OL', null),
2297
+ cssClassIcon: _iconPrefix + 'ol',
2298
+ show: true,
2299
+ buttonId: null,
2300
+ menuId: null,
2301
+ menuItemId: 'OrderedList',
2302
+ group: 4,
2303
+ position: 0
2304
+ },
2305
+ unorderedList:
2306
+ {
2307
+ command: toggleListItem.bind(_instance, 'UL', null),
2308
+ cssClassIcon: _iconPrefix + 'ul',
2309
+ show: true,
2310
+ buttonId: null,
2311
+ menuId: null,
2312
+ menuItemId: 'UnorderedList',
2313
+ group: 4,
2314
+ position: 0
2315
+ },
2316
+ link:
2317
+ {
2318
+ command: insertLink,
2319
+ shortcutKey: 'k',
2320
+ cssClassIcon: _iconPrefix + 'link',
2321
+ show: true,
2322
+ isActive: isLink,
2323
+ selectable: true,
2324
+ buttonId: null,
2325
+ group: 5,
2326
+ position: 0
2327
+ },
2328
+ image:
2329
+ {
2330
+ command: insertImage,
2331
+ cssClassIcon: _iconPrefix + 'image',
2332
+ show: true,
2333
+ isActive: isImage,
2334
+ getNode: getImageFromNode.bind(_instance),
2335
+ selectable: true,
2336
+ buttonId: null,
2337
+ group: 5,
2338
+ position: 0
2339
+ },
2340
+ media:
2341
+ {
2342
+ command: insertMedia,
2343
+ cssClassIcon: _iconPrefix + 'media',
2344
+ show: true,
2345
+ isActive: isMedia,
2346
+ selectable: true,
2347
+ buttonId: null,
2348
+ group: 5,
2349
+ position: 0
2350
+ },
2351
+ table:
2352
+ {
2353
+ command: null,
2354
+ cssClassIcon: _iconPrefix + 'table',
2355
+ show: true,
2356
+ selectable: true,
2357
+ buttonId: null,
2358
+ boxId: 'TablePicker',
2359
+ group: 5,
2360
+ position: 0
2361
+ },
2362
+
2363
+ subscript:
2364
+ {
2365
+ id: 'sub',
2366
+ command: _instance.sub,
2367
+ cssClassIcon: _iconPrefix + 'sub',
2368
+ show: true,
2369
+ isActive: isTagMatch.bind(_instance, 'sub'),
2370
+ type: 1,
2371
+ buttonId: null,
2372
+ group: 6,
2373
+ position: 0,
2374
+ elementSettings: { tag: 'sub' }
2375
+ },
2376
+ superscript:
2377
+ {
2378
+ id: 'sup',
2379
+ command: _instance.sup,
2380
+ cssClassIcon: _iconPrefix + 'super',
2381
+ show: true,
2382
+ isActive: isTagMatch.bind(_instance, 'sup'),
2383
+ type: 1,
2384
+ buttonId: null,
2385
+ group: 6,
2386
+ position: 0,
2387
+ elementSettings: { tag: 'sup' }
2388
+ },
2389
+ copyFormat:
2390
+ {
2391
+ command: copyFormat,
2392
+ cssClassIcon: _iconPrefix + 'brush',
2393
+ show: true,
2394
+ buttonId: null,
2395
+ group: 6,
2396
+ position: 0
2397
+ },
2398
+ clearFormat:
2399
+ {
2400
+ command: clearFormat,
2401
+ cssClassIcon: _iconPrefix + 'formatting-clear',
2402
+ show: true,
2403
+ buttonId: null,
2404
+ group: 6,
2405
+ position: 0
2406
+ },
2407
+
2408
+ bookmark:
2409
+ {
2410
+ command: bookmark,
2411
+ cssClassIcon: _iconPrefix + 'bookmark',
2412
+ show: true,
2413
+ isActive: isBookmark,
2414
+ buttonId: null,
2415
+ group: 7,
2416
+ position: 0
2417
+ },
2418
+ horizontalLine:
2419
+ {
2420
+ command: insertHR,
2421
+ cssClassIcon: _iconPrefix + 'line',
2422
+ show: true,
2423
+ buttonId: null,
2424
+ group: 7,
2425
+ position: 0
2426
+ },
2427
+ pageBreak:
2428
+ {
2429
+ command: insertPageBreak,
2430
+ cssClassIcon: _iconPrefix + 'pagebreak',
2431
+ show: true,
2432
+ buttonId: null,
2433
+ group: 7,
2434
+ position: 0
2435
+ },
2436
+
2437
+ source:
2438
+ {
2439
+ command: sourceView,
2440
+ cssClassIcon: _iconPrefix + 'source',
2441
+ show: true,
2442
+ type: 1,
2443
+ buttonId: null,
2444
+ group: 8,
2445
+ position: 0
2446
+ },
2447
+ expand:
2448
+ {
2449
+ command: expandedView,
2450
+ cssClassIcon: _iconPrefix + 'expand',
2451
+ show: true,
2452
+ buttonId: null,
2453
+ type: 1,
2454
+ group: 8,
2455
+ position: 0
2456
+ },
2457
+ preview:
2458
+ {
2459
+ command: preview,
2460
+ cssClassIcon: _iconPrefix + 'preview',
2461
+ show: true,
2462
+ buttonId: null,
2463
+ type: 1,
2464
+ group: 8,
2465
+ position: 0
2466
+ },
2467
+ save:
2468
+ {
2469
+ command: save,
2470
+ cssClassIcon: _iconPrefix + 'save',
2471
+ show: true,
2472
+ buttonId: null,
2473
+ group: 8,
2474
+ position: 0
2475
+ },
2476
+ export:
2477
+ {
2478
+ command: exportToPDF,
2479
+ cssClassIcon: _iconPrefix + 'pdf',
2480
+ show: true,
2481
+ buttonId: null,
2482
+ group: 8,
2483
+ position: 0
2484
+ },
2485
+ print:
2486
+ {
2487
+ command: print,
2488
+ cssClassIcon: _iconPrefix + 'print',
2489
+ show: true,
2490
+ buttonId: null,
2491
+ group: 8,
2492
+ position: 0
2493
+ },
2494
+
2495
+ more:
2496
+ {
2497
+ command: null,
2498
+ cssClass: 'more',
2499
+ cssClassIcon: _iconPrefix + 'more',
2500
+ show: true,
2501
+ buttonId: null,
2502
+ type: 1,
2503
+ boxId: 'ToolbarMore',
2504
+ expandDirection: 'right',
2505
+ group: 9,
2506
+ position: 0
2507
+ },
2508
+ blockView:
2509
+ {
2510
+ command: blockView,
2511
+ cssClassIcon: _iconPrefix + 'block',
2512
+ show: true,
2513
+ type: 1,
2514
+ buttonId: null,
2515
+ group: 10,
2516
+ position: 0
2517
+ },
2518
+ special:
2519
+ {
2520
+ command: specialSymbols,
2521
+ cssClassIcon: _iconPrefix + 'omega',
2522
+ show: true,
2523
+ buttonId: null,
2524
+ group: 10,
2525
+ position: 0
2526
+ },
2527
+ emoji:
2528
+ {
2529
+ command: emojiSymbols,
2530
+ cssClassIcon: _iconPrefix + 'emoji',
2531
+ show: true,
2532
+ buttonId: null,
2533
+ group: 10,
2534
+ position: 0
2535
+ }
2536
+ };
2537
+
2538
+ /**
2539
+ * Sets the link dialog content template.
2540
+ * Available placeholders:
2541
+ * - {href} - The href field.
2542
+ * - {text} - The text field.
2543
+ * - {title} - The title field.
2544
+ * - {target} - The target field.
2545
+ * @param {HTMLElement|HTMLElement[]|DocumentFragment|String} content The HTML template.
2546
+ */
2547
+ this.setLinkDialogContentTemplate = function (content)
2548
+ {
2549
+ _instance.addTemplate('LinkDialogContent', content, false);
2550
+ };
2551
+
2552
+ /**
2553
+ * Sets the image dialog content template.
2554
+ * Available placeholders:
2555
+ * - {source} - The source field.
2556
+ * - {alt} - The alternative text field.
2557
+ * - {width} - The width field.
2558
+ * - {height} - The height field.
2559
+ * - {caption} - The caption field.
2560
+ * - {alignment} - The alignment radio buttons.
2561
+ * - {inline} - The inline checkbox (renders in footer).
2562
+ * @param {HTMLElement|HTMLElement[]|DocumentFragment|String} content The HTML template.
2563
+ */
2564
+ this.setImageDialogContentTemplate = function (content)
2565
+ {
2566
+ _instance.addTemplate('ImageDialogContent', content, false);
2567
+ };
2568
+
2569
+ /**
2570
+ * Sets the media dialog content template.
2571
+ * Available placeholders:
2572
+ * - {source} - The source field.
2573
+ * - {width} - The width field.
2574
+ * - {caption} - The caption field.
2575
+ * @param {HTMLElement|HTMLElement[]|DocumentFragment|String} content The HTML template.
2576
+ */
2577
+ this.setMediaDialogContentTemplate = function (content)
2578
+ {
2579
+ _instance.addTemplate('MediaDialogContent', content, false);
2580
+ };
2581
+
2582
+ /**
2583
+ * Sets the table dialog Table panel content template.
2584
+ * Available placeholders:
2585
+ * - {width} - The width field.
2586
+ * - {alignment} - The alignment field.
2587
+ * - {bgColor} - The background color field.
2588
+ * - {borderWidth} - The border width field.
2589
+ * - {borderStyle} - The border style field.
2590
+ * - {borderColor} - The border color field.
2591
+ * - {cellSpacing} - The cell spacing field.
2592
+ * - {caption} - The caption field.
2593
+ * @param {HTMLElement|HTMLElement[]|DocumentFragment|String} content The HTML template.
2594
+ */
2595
+ this.setTableDialogTableTemplate = function (content)
2596
+ {
2597
+ _instance.addTemplate('TableDialogTable', content, false);
2598
+ };
2599
+
2600
+ /**
2601
+ * Sets the table dialog Row panel content template.
2602
+ * Available placeholders:
2603
+ * - {isHeader} - The header row toggle.
2604
+ * - {isFooter} - The footer row toggle.
2605
+ * - {height} - The height field.
2606
+ * - {bgColor} - The background color field.
2607
+ * - {borderStyle} - The border style field.
2608
+ * - {borderColor} - The border color field.
2609
+ * @param {HTMLElement|HTMLElement[]|DocumentFragment|String} content The HTML template.
2610
+ */
2611
+ this.setTableDialogRowTemplate = function (content)
2612
+ {
2613
+ _instance.addTemplate('TableDialogRow', content, false);
2614
+ };
2615
+
2616
+ /**
2617
+ * Sets the table dialog Cell panel content template.
2618
+ * Available placeholders:
2619
+ * - {width} - The width field.
2620
+ * - {height} - The height field.
2621
+ * - {verticalAlign} - The vertical alignment field.
2622
+ * - {horizontalAlign}- The horizontal alignment field.
2623
+ * - {bgColor} - The background color field.
2624
+ * - {borderWidth} - The border width field.
2625
+ * - {borderStyle} - The border style field.
2626
+ * - {borderColor} - The border color field.
2627
+ * - {padding} - The padding field.
2628
+ * @param {HTMLElement|HTMLElement[]|DocumentFragment|String} content The HTML template.
2629
+ */
2630
+ this.setTableDialogCellTemplate = function (content)
2631
+ {
2632
+ _instance.addTemplate('TableDialogCell', content, false);
2633
+ };
2634
+
2635
+ /**
2636
+ * Sets the word count template. The template supports the below listed placeholders.
2637
+ * - {words} This value will be replaced with the word count.
2638
+ * - {chars} This value will be replaced with the character count.
2639
+ * @param {HTMLElement|HTMLElement[]|DocumentFragment|String} content The HTML template.
2640
+ */
2641
+ this.setWordCountTemplate = function (content)
2642
+ {
2643
+ _instance.addTemplate('WordCount', content, false);
2644
+ };
2645
+
2646
+ /**
2647
+ * Sets the menu tooltip template. The template supports the below listed placeholders.
2648
+ * - {href} This value will be replaced with link href.
2649
+ * - {editButton} This value will be replaced with the edit link/image/media button.
2650
+ * - {removeButton} This value will be replaced with the remove link/image/media button.
2651
+ * @param {HTMLElement|HTMLElement[]|DocumentFragment|String} content The HTML template.
2652
+ */
2653
+ this.setTooltipMenuTemplate = function (content)
2654
+ {
2655
+ _instance.addTemplate('TooltipMenu', content, false);
2656
+ };
2657
+
2658
+ /**
2659
+ * Adds a toolbar command.
2660
+ * @param {String} name The unique command name.
2661
+ * @param {CommandSettings} settings The command settings.
2662
+ */
2663
+ this.addCommand = function (name, settings)
2664
+ {
2665
+ _instance.commands[name] = settings;
2666
+ };
2667
+
2668
+ /**
2669
+ * Initializes the editor with ONLY the specified commands set to enabled (or disabled when the enable parameter is set to false).
2670
+ * For other commands, the opposite action is applied.
2671
+ * Special keywords can be used to refer to predefined groups of commands:
2672
+ * - '*core' : ['undo','redo','bold','italic','underline','strikeThrough','align','indentMin','indentPlus','copyFormat','clearFormat']
2673
+ * - '*list' : ['orderedList','unorderedList']
2674
+ * - '*font' : ['fontSize','fontFamily']
2675
+ * - '*font-color' : ['fontColor','fontBGColor']
2676
+ * @param {String[]} commands The unique command names or special keywords to enable/disable.
2677
+ * @param {Boolean} [enable=true] If true, specified commands are enabled; if false, they are disabled.
2678
+ */
2679
+ this.initCommands = function (commands, enable = true)
2680
+ {
2681
+ const special = {
2682
+ '*core': ['undo', 'redo', 'bold', 'italic', 'underline', 'strikeThrough', 'align', 'indentMin', 'indentPlus', 'copyFormat', 'clearFormat'],
2683
+ '*list': ['orderedList', 'unorderedList'],
2684
+ '*font': ['fontSize', 'fontFamily'],
2685
+ '*font-color': ['fontColor', 'fontBGColor']
2686
+ },
2687
+ commandSet = new Set(commands.flatMap(cmd => special[cmd] || cmd));
2688
+
2689
+ for (const key in _instance.commands)
2690
+ {
2691
+ _instance.commands[key].show = commandSet.has(key) ? enable : !enable;
2692
+ }
2693
+ };
2694
+
2695
+
2696
+ /**
2697
+ * Gets the active content-editable editor element (when iframe is set to true this will return the document.body element of the iframe).
2698
+ * @returns {String} The editor HTML content.
2699
+ */
2700
+ this.getEditorElement = function ()
2701
+ {
2702
+ return _editableElement;
2703
+ };
2704
+
2705
+ /**
2706
+ * Sets focus to the editable element.
2707
+ * @param {boolean} [caretAtEnd=true] A value indicating to set the caret at the end of the content.
2708
+ */
2709
+ this.focus = function (caretAtEnd = true)
2710
+ {
2711
+ _editableElement.focus();
2712
+
2713
+ if (caretAtEnd)
2714
+ {
2715
+ let sel = _instance.selectionRange.getSelection();
2716
+ sel.selectAllChildren(_editableElement.lastElementChild || _editableElement);
2717
+ sel.collapseToEnd();
2718
+ }
2719
+ };
2720
+
2721
+ /**
2722
+ * Cleans the HTML source.
2723
+ * @param {boolean} clearZeroWidthCharacters
2724
+ */
2725
+ this.cleanSource = (clearZeroWidthCharacters = true) =>
2726
+ {
2727
+ _instance.contentManager.cleanSource(null, clearZeroWidthCharacters);
2728
+ };
2729
+
2730
+ /**
2731
+ * Gets the editor content (equal to getContent()).
2732
+ * @param {HTMLElement|null} [editableElement] The specific editable element to get content from. Only applicable if this editor instance uses multiple editable elements.
2733
+ * @returns {String} The editor HTML content.
2734
+ */
2735
+ this.getValue = (editableElement) => this.getContent(editableElement);
2736
+
2737
+ /**
2738
+ * Gets the editor content.
2739
+ * @param {HTMLElement|null} [editableElement] The specific editable element to get content from. Only applicable if this editor instance uses multiple editable elements.
2740
+ * @returns {String} The editor HTML content.
2741
+ */
2742
+ this.getContent = function (editableElement)
2743
+ {
2744
+ return _instance.contentManager.getContent(editableElement);
2745
+ };
2746
+
2747
+ /**
2748
+ * Sets the editor content (equal to setContent()).
2749
+ * @param {String} content The HTML content.
2750
+ * @param {HTMLElement|null} [editableElement] The specific editable element to set content for. Only applicable if this editor instance uses multiple editable elements.
2751
+ */
2752
+ this.setValue = (content, editableElement) => this.setContent(content, editableElement);
2753
+
2754
+ /**
2755
+ * Sets the editor content.
2756
+ * @param {String} content The HTML content.
2757
+ * @param {HTMLElement|null} [editableElement] The specific editable element to set content for. Only applicable if this editor instance uses multiple editable elements.
2758
+ * @param {Boolean} sanitize A value indicating if the content should be sanitized.
2759
+ */
2760
+ this.setContent = function (content, editableElement, sanitize = true)
2761
+ {
2762
+ editableElement = editableElement || _editableElement;
2763
+ editableElement.innerHTML = _instance.sanitizer ? _instance.sanitizer(content) : _instance.getSanitizer().sanitize(content);
2764
+ _instance.contentManager.ensureDocStructure(editableElement);
2765
+ };
2766
+
2767
+ /**
2768
+ * Gets the active selection range.
2769
+ * @returns {Range} The active selection range.
2770
+ */
2771
+ this.getRange = function ()
2772
+ {
2773
+ activateDocument();
2774
+ let range = _instance.selectionRange.getRange();
2775
+ deactivateDocument();
2776
+ return range;
2777
+ };
2778
+
2779
+ /**
2780
+ * Sets the state of the toolbar button.
2781
+ * @param {boolean} enable A value that indicates if buttons are enabled or disabled.
2782
+ * @param {String[]} exclude A list of command id's to exclude.
2783
+ */
2784
+ this.setToolbarButtonState = function (enable, exclude = [])
2785
+ {
2786
+ setToolbarButtonState(enable, exclude);
2787
+ };
2788
+
2789
+ /**
2790
+ * Renders the component
2791
+ */
2792
+ this.render = function ()
2793
+ {
2794
+ if (_instance.renderState != $base.static.RenderState.RENDERING)
2795
+ {
2796
+ // call base render and return
2797
+ $base.methods.render.call(_instance, preRender, 'editor', _themeOption.DEFAULT);
2798
+ return;
2799
+ }
2800
+
2801
+ // render logic after loading resources
2802
+ if (!_instance.hasTemplate('WordCount'))
2803
+ _instance.addTemplate('WordCount', '{words} words, {chars} characters', false);
2804
+
2805
+ $lib.each(_instance.extraCommands, (settings, name) => { _instance.addCommand(name, settings); });
2806
+
2807
+ if (!$lib.isEmpty(_instance.visibleCommands))
2808
+ _instance.initCommands(_instance.visibleCommands);
2809
+
2810
+ instantiateModules();
2811
+ draw();
2812
+ };
2813
+
2814
+ /**
2815
+ * Executes the post render procedure.
2816
+ */
2817
+ this.postRender = function ()
2818
+ {
2819
+ if (_instance.renderState != $base.static.RenderState.RENDERING) // extra safety to never execute a postRender when the component state is incorrect
2820
+ return;
2821
+
2822
+ if (!_instance.iframe)
2823
+ {
2824
+ if (hasEditables())
2825
+ {
2826
+ $lib.each(_instance.editableElements, (item) =>
2827
+ {
2828
+ setupEditor(item.element || $lib('#' + item.id));
2829
+ });
2830
+
2831
+ _instance.element.classList.add(_instance.getCssClass(_instance.classOption.HIDDEN));
2832
+ }
2833
+ else
2834
+ {
2835
+ setupEditor(_editor, false);
2836
+ setTimeout(function ()
2837
+ {
2838
+ _doc.defaultView.focus();
2839
+ _editableElement.focus();
2840
+ });
2841
+ }
2842
+ }
2843
+
2844
+ $base.methods.postRender.call(this);
2845
+ _instance.layoutState.updateLayoutSettings();
2846
+ };
2847
+
2848
+ /**
2849
+ * Destroys the component.
2850
+ * @see {@link componyx.UI.base.methods#destroy}
2851
+ */
2852
+ this.destroy = function (...args)
2853
+ {
2854
+ dispose();
2855
+ $base.methods.destroy.call(this, ...args);
2856
+ };
2857
+
2858
+ /** Initializes script and css.
2859
+ * @ignore
2860
+ */
2861
+ function preRender()
2862
+ {
2863
+ var script = ['Button', 'FormField', 'ComboBox', 'Dialog', 'Menu', 'ColorButton', 'ColorPicker', 'NumericBox', 'Validator', 'TooltipManager'];
2864
+ return ['Editor', script];
2865
+ }
2866
+
2867
+ /** Initializes the editor.
2868
+ * @ignore
2869
+ */
2870
+ function init()
2871
+ {
2872
+ activateDocument();
2873
+
2874
+ if (_instance.content)
2875
+ _instance.setContent(content);
2876
+
2877
+ deactivateDocument();
2878
+
2879
+ if (_instance.renderState == 2)
2880
+ _instance.layoutState.updateLayoutSettings();
2881
+ }
2882
+
2883
+
2884
+ function instantiateModules()
2885
+ {
2886
+ _instance.utility = new Utility(_instance);
2887
+ _instance.componentFactory = new ComponentFactory(_instance);
2888
+ _instance.contentManager = new ContentManager(_instance);
2889
+ _instance.dialogManager = new DialogManager(_instance);
2890
+ _instance.eventManager = new EventManager(_instance);
2891
+ _instance.format = new Format(_instance);
2892
+ _instance.history = new History(_instance);
2893
+ _instance.layoutState = new LayoutState(_instance);
2894
+ _instance.listManager = new ListManager(_instance);
2895
+ _instance.menuManager = new MenuManager(_instance);
2896
+ _instance.nodeManager = new NodeManager(_instance);
2897
+ _instance.paragraphButtons = new ParagraphButtons(_instance);
2898
+ _instance.resizer = new Resizer(_instance);
2899
+ _instance.selectionRange = new SelectionRange(_instance);
2900
+ _instance.sourceViewBuilder = new SourceViewBuilder(_instance);
2901
+ _instance.table = new Table(_instance);
2902
+ _instance.toolbar = new Toolbar(_instance);
2903
+ _instance.tooltipMenu = new TooltipMenu(_instance);
2904
+ }
2905
+
2906
+ /** Draws the editor.
2907
+ * @ignore
2908
+ */
2909
+ async function draw()
2910
+ {
2911
+ _toolbar = _instance.toolbar.createToolbar();
2912
+
2913
+ _instance.layoutState.init();
2914
+
2915
+ if (hasEditables() || _instance.toolbarDisplay == _toolbarDisplayOption.FOOTER)
2916
+ _instance.toolbar.createToolbarBox();
2917
+
2918
+ if (!hasEditables())
2919
+ {
2920
+ createEditor();
2921
+ createFooter();
2922
+
2923
+ if (_instance.toolbarDisplay == _toolbarDisplayOption.FOOTER) // set toolbar as footer
2924
+ _instance.element.appendChild(_toolbar);
2925
+ }
2926
+ else
2927
+ {
2928
+ _instance.sourceViewInDialog = true;
2929
+ }
2930
+
2931
+ if (_instance.sourceViewInDialog)
2932
+ _instance.dialogManager.createSourceDialog();
2933
+
2934
+ await _instance.menuManager.createMenu();
2935
+ _instance.componentFactory.createColorSwatch();
2936
+ _instance.componentFactory.createColorPicker();
2937
+ await _instance.toolbar.createEmojiSymbolPicker();
2938
+ await _instance.toolbar.createSpecialSymbolPicker();
2939
+ _instance.table.createPicker();
2940
+ _instance.renderChildren();
2941
+ }
2942
+
2943
+ function hasEditables()
2944
+ {
2945
+ return !$lib.isEmpty(_instance.editableElements);
2946
+ }
2947
+
2948
+ /**
2949
+ * Creates the source view builder.
2950
+ * @param {any} source
2951
+ * @param {any} target
2952
+ * @ignore
2953
+ */
2954
+ function createSourceViewBuilder(source, target)
2955
+ {
2956
+ let viewer = new SourceViewBuilder(target, `${_instance.utility.buttonCss} ${_instance.getThemeCSS()} edit`, 'span', _instance.labels.sourceViewRootItem, _instance.utility.voidNodeRegEx);
2957
+ viewer.build(source.cloneNode(true));
2958
+ _sourceViewStore.set(source, viewer);
2959
+ }
2960
+
2961
+ /**
2962
+ * Sets the source view HTML on the specified source.
2963
+ * @param {any} source
2964
+ * @ignore
2965
+ */
2966
+ function setSourceViewBuilderHTML(source)
2967
+ {
2968
+ source.innerHTML = _sourceViewStore.get(source).outerHTML();
2969
+ }
2970
+
2971
+ /**
2972
+ * Binds the select events for the specified node.
2973
+ * @param {any} node
2974
+ * @ignore
2975
+ */
2976
+ function bindNodeEvents(node)
2977
+ {
2978
+ const selection = _instance.selectionRange;
2979
+
2980
+ if (isBookmark(node) || (node.nodeName == 'FIGURE' && !node.querySelector('table')))
2981
+ node.contentEditable = false;
2982
+
2983
+ node.setAttribute(_instance.utility.selAttr, "");
2984
+ $lib.on(node, 'click', selectNode.bind(node, false, true));
2985
+
2986
+ if (node.nodeName != 'A')
2987
+ {
2988
+ $lib.on(node, 'pointerenter', function (e)
2989
+ {
2990
+ if (!setActiveEditor(e.target))
2991
+ return;
2992
+
2993
+ activateDocument();
2994
+ _range = selection.getRange();
2995
+
2996
+ if (_range.collapsed && !_instance.getSelectedNodes().length)
2997
+ _instance.paragraphButtons.show(_editableElement, this);
2998
+ });
2999
+ $lib.on(node, 'pointerleave', function (e)
3000
+ {
3001
+ if (!setActiveEditor(e.target))
3002
+ return;
3003
+
3004
+ activateDocument();
3005
+ _range = selection.getRange();
3006
+
3007
+ if (!_instance.getSelectedNodes().length)
3008
+ _instance.paragraphButtons.hide();
3009
+ });
3010
+ }
3011
+ }
3012
+
3013
+ /** Creates the footer.
3014
+ * @ignore
3015
+ */
3016
+ function createFooter()
3017
+ {
3018
+ _footerEl = $lib.element(_instance.element, '', '', '', null, { className: _instance.getCssClass(_instance.classOption.FOOTER) });
3019
+ _pathEl = $lib.element(_footerEl, '', '', '', null, { className: _instance.getCssClass(_instance.classOption.PATH) });
3020
+ _wordCountEl = $lib.element(_footerEl, '', '', '', null, { className: _instance.getCssClass(_instance.classOption.WORD_COUNT) });
3021
+ $lib.element(_footerEl, '', '', '', null, { className: 'c-logo' });
3022
+ _resizeHandle = $lib.element(_footerEl, '', '', '', null, { className: 'resize-handle' });
3023
+
3024
+ _pathEl.innerHTML = '&nbsp;';
3025
+ let resizeSettings = { defaultHandles: false, resizeHandles: { s: _resizeHandle } };
3026
+
3027
+ if (_instance.iframe)
3028
+ {
3029
+ resizeSettings.onResizeStart = createResizeMask;
3030
+ resizeSettings.onResizeEnd = removeResizeMask;
3031
+ }
3032
+
3033
+ $lib.resizable(_editor, resizeSettings);
3034
+ }
3035
+
3036
+ /** Creates a resize mask to cover the iframe otherwise the resize-drag can stop.
3037
+ * @ignore
3038
+ */
3039
+ function createResizeMask()
3040
+ {
3041
+ _resizeMask = $lib.element(document.body, '', '', '', { style: 'position: fixed; z-index: 9999; inset: 0px 0px 0px 0px; opacity: 0;' });
3042
+ }
3043
+
3044
+ /** Removes the created resize mask.
3045
+ * @ignore
3046
+ */
3047
+ function removeResizeMask()
3048
+ {
3049
+ $lib.remove(_resizeMask);
3050
+ }
3051
+
3052
+ /** Creates the editor.
3053
+ * @ignore
3054
+ */
3055
+ function createEditor()
3056
+ {
3057
+ _editor = $lib.element(_instance.element);
3058
+ _editor.className = _instance.getCssClass(_instance.classOption.CONTENT);
3059
+ _editor.style.boxSizing = 'border-box';
3060
+
3061
+ if (!$lib.isEmpty(_instance.name))
3062
+ _editor.setAttribute('name', _instance.name);
3063
+
3064
+ if (_instance.editorHeight)
3065
+ _editor.style.height = $lib.unit(_instance.editorHeight);
3066
+
3067
+ if (_instance.iframe)
3068
+ {
3069
+ _iframe = document.createElement('iframe');
3070
+ _iframe.setAttribute('allowtransparency', 'true');
3071
+ _iframe.setAttribute('frameborder', '0');
3072
+ _iframe.style.width = _iframe.style.height = "100%";
3073
+ _iframe.style.display = 'block';
3074
+ _editor.appendChild(_iframe);
3075
+
3076
+ _instance.element.classList.add(_instance.getCssClass(_instance.classOption.FRAMED));
3077
+
3078
+ _iframe.onload = function () // directly fired on postRender() -> show()
3079
+ {
3080
+ setupEditor(_iframe.contentWindow.document.body);
3081
+ $lib.addClass(_editableElement, 'iframe');
3082
+ addStylesheets();
3083
+ };
3084
+ }
3085
+ }
3086
+
3087
+ /**
3088
+ * @ignore
3089
+ * @param {any} editorBody
3090
+ * @param {any} useMainCssClass
3091
+ */
3092
+ function setupEditor(editorBody, useMainCssClass = true)
3093
+ {
3094
+ _doc = editorBody.ownerDocument;
3095
+ _editableElement = editorBody;
3096
+ _instance.history.init(_editableElement);
3097
+ _instance.eventManager.bindEvents();
3098
+
3099
+ if (useMainCssClass)
3100
+ copyCssClass(editorBody);
3101
+
3102
+ init();
3103
+
3104
+ if (_editableElement.tabIndex == -1 && !$lib.isEmpty(_instance.tabIndex))
3105
+ _editableElement.setAttribute('tabindex', _instance.tabIndex);
3106
+
3107
+ if (!_instance.sourceViewInDialog)
3108
+ {
3109
+ let source = $lib.element(_instance.element);
3110
+ source.className = _instance.getCssClass(_instance.classOption.SOURCE_VIEW);
3111
+ source.style.display = 'none';
3112
+ _sourceElement.set(_editableElement, source);
3113
+ }
3114
+ }
3115
+ /**
3116
+ * @ignore
3117
+ * @param {any} editorBody
3118
+ */
3119
+ function copyCssClass(editorBody)
3120
+ {
3121
+ const classesToAdd = _instance.element.className.replace(/\bhidden\b/g, '').trim().replace(/\s+/g, ' ');
3122
+ $lib.addClass(editorBody, classesToAdd);
3123
+ $lib.removeClass(editorBody, _instance.getCssClass(_instance.classOption.FOCUS) + ' ' + _instance.getCssClass(_instance.classOption.FRAMED));
3124
+ }
3125
+
3126
+ /** Adds stylesheets.
3127
+ * @ignore
3128
+ */
3129
+ function addStylesheets()
3130
+ {
3131
+ let sheets = _instance.includeStylesheets,
3132
+ length = (!$lib.isEmpty(sheets)) ? sheets.length : 0, cssLoaded = 0,
3133
+ onComplete = () =>
3134
+ {
3135
+ if (++cssLoaded >= length)
3136
+ _instance.events.onStylesheetsLoaded.fire(_instance);
3137
+ };
3138
+
3139
+ if (!$lib.isEmpty(_instance.includeStylesheets))
3140
+ {
3141
+ activateDocument();
3142
+ $lib.each(_instance.includeStylesheets, (src) =>
3143
+ {
3144
+ $lib.addCssSource(src, '', { onComplete: onComplete });
3145
+ });
3146
+ deactivateDocument();
3147
+ }
3148
+ else
3149
+ onComplete();
3150
+ }
3151
+
3152
+ /**
3153
+ * @param {any} show
3154
+ * @returns {any} return value
3155
+ * @ignore
3156
+ */
3157
+ function setToolbarBoxDisplay(show = true)
3158
+ {
3159
+ _instance.toolbar.setToolbarBoxDisplay(show);
3160
+ }
3161
+
3162
+ /**
3163
+ * Gets the toolbar display setting.
3164
+ * @param {any} el
3165
+ * @returns {ToolbarDisplayOption} the toolbar display.
3166
+ * @ignore
3167
+ */
3168
+ function getToolbarDisplay(el)
3169
+ {
3170
+ let els = _instance.editableElements,
3171
+ index = _instance.editableElements.findIndex((item) =>
3172
+ {
3173
+ return (!$lib.isEmpty(item.toolbarDisplay) && (item.element === el || item.id === el.id));
3174
+ });
3175
+
3176
+ return (index > -1) ? els[index].toolbarDisplay : _instance.toolbarDisplay;
3177
+ }
3178
+
3179
+ /** Activates the document.
3180
+ * @ignore
3181
+ */
3182
+ function activateDocument()
3183
+ {
3184
+ let sel = _instance.selectionRange.getSelection();
3185
+
3186
+ if (_instance.iframe)
3187
+ {
3188
+ $lib.document = _doc;
3189
+ $lib.defer(deactivateDocument);
3190
+ }
3191
+
3192
+ _doc.defaultView.focus();
3193
+
3194
+ if (!sel.rangeCount || !$lib.contains(_editableElement, _instance.selectionRange.getRange().startContainer))
3195
+ {
3196
+ sel.removeAllRanges();
3197
+ _editableElement.focus();
3198
+ }
3199
+ }
3200
+
3201
+ /** Deactivates the document.
3202
+ * @ignore
3203
+ */
3204
+ function deactivateDocument()
3205
+ {
3206
+ $lib.document = window.document;
3207
+ }
3208
+
3209
+ /**
3210
+ * Sets the global active editor and document variables.
3211
+ * @param {any} activeNode
3212
+ * @returns {boolean} A value indicating if the active node was equal or inside an editor element.
3213
+ * @ignore
3214
+ */
3215
+ function setActiveEditor(activeNode)
3216
+ {
3217
+ let editor = getActiveEditor(activeNode);
3218
+
3219
+ if (hasEditables())
3220
+ {
3221
+ if (editor)
3222
+ {
3223
+ _editor = _editableElement = editor;
3224
+ _doc = _editableElement.ownerDocument;
3225
+ return true;
3226
+ }
3227
+ else return false;
3228
+ }
3229
+ else
3230
+ return (editor === _editableElement);
3231
+ }
3232
+
3233
+ /**
3234
+ * Gets the active editor.
3235
+ * @param {any} activeNode
3236
+ * @returns {Node} The active editor element.
3237
+ * @ignore
3238
+ */
3239
+ function getActiveEditor(activeNode)
3240
+ {
3241
+ let editor = _instance.utility.getContentEditable(activeNode);
3242
+
3243
+ if (hasEditables())
3244
+ {
3245
+ if (_instance.editableElements.findIndex((item) =>
3246
+ {
3247
+ let el = item.element || $lib('#' + item.id);
3248
+ return el == editor;
3249
+ }) > -1)
3250
+ {
3251
+ return editor;
3252
+ }
3253
+ return null;
3254
+ }
3255
+ else
3256
+ return editor;
3257
+ }
3258
+
3259
+ /**
3260
+ * Returns a value indicating if the node is a bookmark node.
3261
+ * @param {Node} node
3262
+ * @ignore
3263
+ */
3264
+ function isBookmark(node)
3265
+ {
3266
+ return _instance.nodeManager.isBookmark(node);
3267
+ }
3268
+
3269
+ /**
3270
+ * Returns a value indicating if the node is an image node.
3271
+ * @param {Node} node
3272
+ * @ignore
3273
+ */
3274
+ function isImage(node)
3275
+ {
3276
+ return _instance.nodeManager.isImage(node);
3277
+ }
3278
+
3279
+ /**
3280
+ * Returns a value indicating if the node is a media node.
3281
+ * @param {Node} node
3282
+ * @ignore
3283
+ */
3284
+ function isMedia(node)
3285
+ {
3286
+ return _instance.nodeManager.isMedia(node);
3287
+ }
3288
+
3289
+ /**
3290
+ * Returns a value indicating if the node is a link node.
3291
+ * @param {Node} node
3292
+ * @ignore
3293
+ */
3294
+ function isLink(node)
3295
+ {
3296
+ return _instance.nodeManager.isLink(node);
3297
+ }
3298
+
3299
+ /**
3300
+ * Returns a value indicating if the node matches the tag.
3301
+ * @param {string[]|string} tag
3302
+ * @param {Node} node
3303
+ * @ignore
3304
+ */
3305
+ function isTagMatch(tag, node)
3306
+ {
3307
+ return _instance.nodeManager.isTagMatch(tag, node);
3308
+ }
3309
+
3310
+ /**
3311
+ * Gets the image element inside the figure element.
3312
+ * @param {Node} el
3313
+ * @ignore
3314
+ */
3315
+ function getImageFromNode(el)
3316
+ {
3317
+ return _instance.nodeManager.getInnerNodeByName(el, 'IMG');
3318
+ }
3319
+
3320
+ /**
3321
+ * Selects the node.
3322
+ * @param {Node} node
3323
+ * @ignore
3324
+ */
3325
+ function selectNode(selectContents = false, singleSelect = false, e)
3326
+ {
3327
+ if (_editableElement.contentEditable != 'true' || this.parentNode.hasAttribute(_instance.utility.selAttr)) // return when A is inside FIGURE
3328
+ return;
3329
+
3330
+ const selection = _instance.selectionRange;
3331
+ activateDocument();
3332
+ _instance.cancelSelectionChange = true;
3333
+
3334
+ if (!_instance.contentManager.hasContent())
3335
+ _instance.contentManager.insertParagraph();
3336
+
3337
+ let node = this,
3338
+ range = selection.getRange();
3339
+
3340
+ selectContents = (selectContents || (node.contentEditable == 'false' && node.firstElementChild?.nodeName !== 'TABLE' && !node.querySelector('[contenteditable="true"]')));
3341
+
3342
+ if (singleSelect)
3343
+ _instance.clearSelection();
3344
+
3345
+ if (singleSelect && selectContents)
3346
+ range.collapse(true);
3347
+
3348
+ if (range.collapsed && selectContents)
3349
+ range = _instance.selectionRange.selectNodeContents(node);
3350
+
3351
+ if (node.hasAttribute(_instance.utility.selAttr))
3352
+ node.setAttribute(_instance.utility.selAttr, '1');
3353
+
3354
+ _instance.layoutState.getState();
3355
+
3356
+ let selectedNodes = _instance.getSelectedNodes(),
3357
+ layout = _instance.layoutState.activeLayout;
3358
+
3359
+ if (selectedNodes.length == 1 && layout.image)
3360
+ _instance.resizer.set(layout.image);
3361
+ else
3362
+ _instance.resizer.clear(true);
3363
+
3364
+ if (node.nodeName != 'A')
3365
+ {
3366
+ if (selectedNodes.length == 1)
3367
+ _instance.paragraphButtons.show(_editableElement, node);
3368
+ else
3369
+ _instance.paragraphButtons.hide();
3370
+ }
3371
+
3372
+ if (selectedNodes.length == 1)
3373
+ _instance.tooltipMenu.show(node);
3374
+
3375
+ _instance.cancelSelectionChange = false;
3376
+ _range = range;
3377
+
3378
+ if (e)
3379
+ e.stopPropagation();
3380
+ }
3381
+
3382
+ /**
3383
+ * Handles the bookmark command.
3384
+ * @ignore
3385
+ */
3386
+ function bookmark()
3387
+ {
3388
+ if (!_instance.dialogManager.bookmarkDialog)
3389
+ _instance.dialogManager.createBookmarkDialog();
3390
+
3391
+ _instance.dialogManager.bookmarkDialog.show();
3392
+ }
3393
+
3394
+ /**
3395
+ * @ignore
3396
+ */
3397
+ function insertHR()
3398
+ {
3399
+ let hr = $lib.element('', '', 'hr');
3400
+
3401
+ insertHTML(
3402
+ {
3403
+ tag: 'div',
3404
+ isPhrasingContent: false,
3405
+ selectable: true,
3406
+ allowContent: false,
3407
+ innerHTML: hr.outerHTML
3408
+ });
3409
+ }
3410
+
3411
+ /**
3412
+ * @ignore
3413
+ * */
3414
+ function insertPageBreak()
3415
+ {
3416
+ let hr = $lib.element({ tag: 'hr', attrs: { style: 'page-break-before: always;', [`${_instance.utility.attrPrefix}pagebreak`]: '' } });
3417
+ insertHTML(
3418
+ {
3419
+ tag: 'div',
3420
+ isPhrasingContent: false,
3421
+ selectable: true,
3422
+ allowContent: false,
3423
+ innerHTML: hr.outerHTML
3424
+ });
3425
+ }
3426
+
3427
+ /**
3428
+ *
3429
+ * @param {any} settings
3430
+ * @returns {any} return value
3431
+ * @ignore
3432
+ */
3433
+ function insertHTML(settings)
3434
+ {
3435
+ return _instance.contentManager.insertHTML(settings);
3436
+ }
3437
+
3438
+ /** Toggles the block view.
3439
+ * @ignore
3440
+ */
3441
+ function blockView()
3442
+ {
3443
+ if (!$UI.store[getId('blockView')])
3444
+ return;
3445
+
3446
+ let blockViewButton = $UI.store[getId('blockView')],
3447
+ on = (blockViewButton.selected);
3448
+
3449
+ _instance.contentManager.setBlockAttrAll(on);
3450
+
3451
+ if (on)
3452
+ _instance.layoutState.addActiveMode('blockView', _instance.toggleBlockView);
3453
+ else
3454
+ _instance.layoutState.removeActiveMode('blockView');
3455
+ }
3456
+
3457
+ /**
3458
+ *
3459
+ * @param {any} el
3460
+ * @ignore
3461
+ * @returns {boolean} A value indicating if the block view is selected.
3462
+ */
3463
+ function isBlockViewSelected()
3464
+ {
3465
+ let blockViewButton = $UI.store[getId('blockView')];
3466
+
3467
+ return (blockViewButton) ? blockViewButton.selected : false;
3468
+ }
3469
+
3470
+ /**
3471
+ * Toggles the special character view.
3472
+ * @param {any} cmd
3473
+ * @ignore
3474
+ */
3475
+ function specialSymbols(cmd)
3476
+ {
3477
+ _instance.toolbar.showSpecialSymbolPicker(cmd);
3478
+ }
3479
+
3480
+ /**
3481
+ * Toggles the emojis view.
3482
+ * @param {any} cmd
3483
+ * @ignore
3484
+ */
3485
+ function emojiSymbols(cmd)
3486
+ {
3487
+ _instance.toolbar.showEmojiSymbolPicker(cmd);
3488
+ }
3489
+
3490
+ /**
3491
+ * Sets the indent value on the selection range.
3492
+ * @param {any} value
3493
+ * @ignore
3494
+ */
3495
+ function indent(value)
3496
+ {
3497
+ activateDocument();
3498
+
3499
+ let lm = _instance.listManager,
3500
+ rm = _instance.selectionRange,
3501
+ nm = _instance.nodeManager,
3502
+ nr = parseFloat(value),
3503
+ increase = nr > 0,
3504
+ unit = value.replace(nr, ''),
3505
+ range = rm.getRange(),
3506
+ nodesInRange = rm.getNodesInRange(range),
3507
+ selectedListItems = rm.getListItemNodesInRange(nodesInRange),
3508
+ rootNodes = rm.getRootNodesInRange(range, nodesInRange, false),
3509
+ marker = rm.createRangeMarker(rm.ensureTextRange(range));
3510
+
3511
+ $lib.each(rootNodes, (node) =>
3512
+ {
3513
+ if (!nm.isList(node))
3514
+ {
3515
+ let newValue = (node.style.marginLeft) ? parseFloat(node.style.marginLeft) + nr : nr;
3516
+
3517
+ if (newValue < 0)
3518
+ node.style.removeProperty('margin-left');
3519
+ else
3520
+ node.style.marginLeft = newValue + unit;
3521
+ }
3522
+ else if (!increase)
3523
+ {
3524
+ lm.decreaseListIndent(node, selectedListItems);
3525
+ }
3526
+ });
3527
+
3528
+ selectedListItems.forEach(node =>
3529
+ {
3530
+ if (increase)
3531
+ lm.increaseListIndent(node);
3532
+ });
3533
+
3534
+ _instance.history.addItem(range, marker);
3535
+ }
3536
+
3537
+ /**
3538
+ * Toggles a list item node.
3539
+ * @param {any} tag
3540
+ * @param {any} on
3541
+ * @ignore
3542
+ */
3543
+ function toggleListItem(tag, on)
3544
+ {
3545
+ _instance.listManager.toggleListItem(tag, on);
3546
+ }
3547
+
3548
+ /** Inserts a link.
3549
+ * @ignore
3550
+ */
3551
+ function insertLink()
3552
+ {
3553
+ if (!_instance.dialogManager.linkDialog)
3554
+ _instance.dialogManager.createLinkDialog();
3555
+
3556
+ _instance.dialogManager.linkDialog.show();
3557
+ }
3558
+
3559
+ /**
3560
+ * Removes the currently selected link.
3561
+ * @ignore
3562
+ * */
3563
+ function removeLink()
3564
+ {
3565
+ if (_instance.layoutState.activeLayout.link)
3566
+ {
3567
+ let selection = _instance.selectionRange,
3568
+ range = selection.ensureTextRange(selection.getRange()),
3569
+ marker = selection.createRangeMarker(range);
3570
+
3571
+ $lib.unsurround(_instance.layoutState.activeLayout.link);
3572
+ _instance.history.addItem(range, marker);
3573
+
3574
+ if (_instance.dialogManager.linkDialog.showing)
3575
+ _instance.dialogManager.linkDialog.hide();
3576
+ }
3577
+ }
3578
+
3579
+ /**
3580
+ * Inserts an image.
3581
+ * @param {any} cmd
3582
+ * @ignore
3583
+ */
3584
+ function insertImage(cmd)
3585
+ {
3586
+ if (!_instance.dialogManager.imageDialog)
3587
+ _instance.dialogManager.createImageDialog();
3588
+
3589
+ _instance.dialogManager.imageDialog.show();
3590
+ }
3591
+
3592
+ /**
3593
+ * Removes the currently selected image. If the image is wrapped in a FIGURE element, the figure is removed.
3594
+ * @ignore
3595
+ */
3596
+ function removeImage()
3597
+ {
3598
+ const image = _instance.layoutState.activeLayout.image;
3599
+ if (!image) return;
3600
+
3601
+ _instance.resizer.clear(true);
3602
+ _instance.hideTooltips();
3603
+
3604
+ const node = image.closest('figure') || image;
3605
+ removeNodeAndRestoreCaret(node);
3606
+ }
3607
+
3608
+ /**
3609
+ * Inserts a media item.
3610
+ * @param {any} cmd
3611
+ * @ignore
3612
+ */
3613
+ function insertMedia(cmd)
3614
+ {
3615
+ if (!_instance.dialogManager.mediaDialog)
3616
+ _instance.dialogManager.createMediaDialog();
3617
+
3618
+ _instance.dialogManager.mediaDialog.show();
3619
+ }
3620
+
3621
+ /**
3622
+ * Removes the currently selected media element. If the media is wrapped in a FIGURE element, the figure is removed.
3623
+ * @ignore
3624
+ */
3625
+ function removeMedia()
3626
+ {
3627
+ const media = _instance.layoutState.activeLayout.media;
3628
+ if (!media) return;
3629
+
3630
+ _instance.hideTooltips();
3631
+ removeNodeAndRestoreCaret(media);
3632
+ }
3633
+ function removeNodeAndRestoreCaret(node)
3634
+ {
3635
+ if (!node)
3636
+ return;
3637
+
3638
+ const editorEl = _instance.getEditorElement(),
3639
+ nm = _instance.nodeManager,
3640
+ sel = _instance.selectionRange,
3641
+ target = nm.sibling(node, editorEl, false) || nm.sibling(node, editorEl, true),
3642
+ range = sel.getRange();
3643
+
3644
+ node.remove();
3645
+
3646
+ if (target)
3647
+ {
3648
+ range.selectNodeContents(target);
3649
+ range.collapse(true);
3650
+ }
3651
+ else if (!_instance.contentManager.hasContent())
3652
+ _instance.contentManager.insertParagraph();
3653
+
3654
+ _instance.history.addItem();
3655
+ }
3656
+
3657
+ /** Toggles the source viewer.
3658
+ * @ignore
3659
+ */
3660
+ function sourceView()
3661
+ {
3662
+ if (_instance.dialogManager.sourceDialog)
3663
+ {
3664
+ _instance.dialogManager.sourceDialog.show();
3665
+ return;
3666
+ }
3667
+
3668
+ let sourceEl = _sourceElement.get(_editableElement),
3669
+ sourceButton = $UI.store[getId('source')];
3670
+
3671
+ if (sourceButton.selected)
3672
+ {
3673
+ _instance.layoutState.addActiveMode('source', _instance.toggleSourceView);
3674
+ setToolbarButtonState(false, ['source', 'expand']);
3675
+ sourceEl.style.display = '';
3676
+ sourceEl.style.height = _editor.style.height;
3677
+ _editor.style.display = 'none';
3678
+
3679
+ if (_footerEl)
3680
+ _footerEl.style.display = 'none';
3681
+
3682
+ _instance.eventManager.disposeEvents();
3683
+
3684
+ _instance.hideOverlays();
3685
+ _instance.disableBlockView();
3686
+ _instance.cleanSource();
3687
+ createSourceViewBuilder(_editableElement, sourceEl);
3688
+ sourceEl.focus();
3689
+ }
3690
+ else
3691
+ {
3692
+ setToolbarButtonState(true);
3693
+ _editor.style.display = '';
3694
+
3695
+ if (_footerEl)
3696
+ _footerEl.style.display = '';
3697
+
3698
+ sourceEl.style.display = 'none';
3699
+ _instance.eventManager.bindEvents();
3700
+
3701
+ setSourceViewBuilderHTML(_editableElement);
3702
+ _instance.contentManager.ensureDocStructure(_editableElement);
3703
+ _instance.layoutState.removeActiveMode('source');
3704
+ _editableElement.focus();
3705
+ }
3706
+ }
3707
+
3708
+ /**
3709
+ * Sets the state of the toolbar button.
3710
+ * @param {boolean} enable A value that indicates if buttons are enabled or disabled.
3711
+ * @param {String[]} exclude A list of command id's to exclude.
3712
+ * @ignore
3713
+ */
3714
+ function setToolbarButtonState(enable, exclude = [])
3715
+ {
3716
+ $lib.each(_sortedCommands, function (cmd)
3717
+ {
3718
+ if (!cmd.show || exclude.indexOf(cmd.id) > -1)
3719
+ return;
3720
+
3721
+ let button = $UI.store[getId(cmd.id)];
3722
+
3723
+ if (enable && button.disabled)
3724
+ button.enable();
3725
+ else if (!enable && !button.disabled)
3726
+ button.disable();
3727
+ });
3728
+ }
3729
+
3730
+ /** Expands the editor view port
3731
+ * @ignore
3732
+ */
3733
+ function expandedView()
3734
+ {
3735
+ let toolbarDisplay = (getToolbarDisplay(_editableElement) != 1) ? _toolbarDisplayOption.HEADER : _toolbarDisplayOption.FOOTER,
3736
+ cssClass = _instance.getCssClass(_instance.classOption.FULLSCREEN),
3737
+ cssClassFullscreen = cssClass + '-' + _toolbarDisplayOption.getName(toolbarDisplay),
3738
+ el = (hasEditables()) ? _editableElement : _instance.element,
3739
+ expandButton = $UI.store[getId('expand')];
3740
+
3741
+ if (expandButton.selected)
3742
+ {
3743
+ _instance.layoutState.addActiveMode('expand', _instance.toggleExpandedView);
3744
+ $lib.addClass(_instance.element, cssClass);
3745
+ $lib.addClass(el, cssClassFullscreen);
3746
+ $lib.on(window, 'resize', updateHeight);
3747
+ updateHeight();
3748
+ }
3749
+ else
3750
+ {
3751
+ $lib.removeClass(_instance.element, cssClass);
3752
+ $lib.removeClass(el, cssClassFullscreen);
3753
+ _editor.style.height = '';
3754
+
3755
+ if (_instance.editorHeight)
3756
+ _editor.style.height = $lib.unit(_instance.editorHeight);
3757
+
3758
+ if (!_instance.sourceViewInDialog)
3759
+ {
3760
+ let sourceEl = _sourceElement.get(_editableElement);
3761
+ sourceEl.style.height = _editor.style.height;
3762
+ }
3763
+
3764
+ $lib.off(window, 'resize', updateHeight);
3765
+ _instance.layoutState.removeActiveMode('expand');
3766
+ }
3767
+ setToolbarBoxDisplay(_instance.toolbar.toolbarBoxShowing);
3768
+ }
3769
+
3770
+ /** Displayes the document in preview modus.
3771
+ * @ignore
3772
+ */
3773
+ function preview()
3774
+ {
3775
+ let cssClassPreview = _instance.getCssClass(_instance.classOption.PREVIEW),
3776
+ previewButton = $UI.store[getId('preview')];
3777
+
3778
+ if (previewButton.selected)
3779
+ {
3780
+ _instance.layoutState.addActiveMode('preview', _instance.togglePreview);
3781
+ $lib.addClass(_editableElement, cssClassPreview);
3782
+ setToolbarButtonState(false, ['preview', 'expand']);
3783
+ _range = _instance.selectionRange.getRange();
3784
+ _instance.selectionRange.getSelection().removeAllRanges();
3785
+ _instance.hideOverlays();
3786
+ _instance.disableBlockView();
3787
+ _instance.cleanSource();
3788
+ _instance.eventManager.disposeEvents();
3789
+ _editableElement.contentEditable = false;
3790
+ }
3791
+ else
3792
+ {
3793
+ $lib.removeClass(_editableElement, cssClassPreview);
3794
+ setToolbarButtonState(true);
3795
+ _editableElement.contentEditable = true;
3796
+ _instance.contentManager.ensureDocStructure(_editableElement);
3797
+ _instance.eventManager.bindEvents();
3798
+ _instance.layoutState.removeActiveMode('preview');
3799
+ _editableElement.focus();
3800
+
3801
+ if (_range)
3802
+ _instance.selectionRange.restoreRange(_range);
3803
+ }
3804
+ }
3805
+
3806
+ /** Saves the document.
3807
+ * @ignore
3808
+ */
3809
+ function save()
3810
+ {
3811
+ _instance.events.onSave.fire(_instance, { html: _instance.getContent(_editableElement) });
3812
+ }
3813
+
3814
+ /** Prints the document.
3815
+ * @ignore
3816
+ */
3817
+ function print()
3818
+ {
3819
+ const win = (_instance.iframe) ? _iframe.contentWindow : window;
3820
+ const editorEl = _editableElement;
3821
+ const original = editorEl.innerHTML;
3822
+
3823
+ editorEl.innerHTML = _instance.getContent();
3824
+ win.print();
3825
+ editorEl.innerHTML = original;
3826
+ _instance.contentManager.createSelectables(editorEl);
3827
+ }
3828
+
3829
+ /**
3830
+ * Exports document to PDF.
3831
+ * @param {any} settings
3832
+ * @ignore
3833
+ */
3834
+ function exportToPDF()
3835
+ {
3836
+ let pdf = new window.jspdf.jsPDF(),
3837
+ element = $lib.element({ props: { className: _instance.getCssClass(_instance.classOption.PDF_EXPORT) }, content: [_instance.getContent(_editableElement)] }),
3838
+ options = $lib.clone({
3839
+ target: {},
3840
+ source: _instance.PDFExportSettings,
3841
+ deep: true,
3842
+ overwrite: 1
3843
+ });
3844
+
3845
+ element.style.width = (options.windowWidth || 1024) + 'px';
3846
+
3847
+ return pdf.html(element, options)
3848
+ .then(() => pdf.save(options.filename || 'document.pdf'))
3849
+ .catch(error => console.error('PDF export failed:', error));
3850
+ }
3851
+
3852
+ /**
3853
+ * Sets the block tag.
3854
+ * @param {any} tag
3855
+ * @param {any} layoutNode
3856
+ * @ignore
3857
+ */
3858
+ function setBlock(tag, layoutNode)
3859
+ {
3860
+ activateDocument();
3861
+ _editableElement.focus();
3862
+
3863
+ let selection = _instance.selectionRange,
3864
+ nm = _instance.nodeManager,
3865
+ range = selection.ensureTextRange(selection.getRange()),
3866
+ nodes = selection.getRootNodesInRange(range),
3867
+ marker = selection.createRangeMarker(range);
3868
+
3869
+ $lib.each(nodes, (node) =>
3870
+ {
3871
+ if (node.nodeName.toLowerCase() != tag)
3872
+ nm.setBlockElement(node, (!layoutNode) ? _instance.format.createLayoutNode(tag) : nm.getRootNode(layoutNode).cloneNode(true));
3873
+ });
3874
+
3875
+ blockView();
3876
+ range = _instance.selectionRange.restoreRangeToMarker(marker, _doc.createRange());
3877
+ _instance.history.addItem(range, marker);
3878
+ }
3879
+
3880
+ /** Copies the formatting.
3881
+ * @ignore
3882
+ */
3883
+ function copyFormat()
3884
+ {
3885
+ return _instance.format.copyFormat();
3886
+ }
3887
+
3888
+ /** Clears the formatting on the current range.
3889
+ * @ignore
3890
+ */
3891
+ function clearFormat()
3892
+ {
3893
+ _instance.format.clearFormat();
3894
+ }
3895
+
3896
+ /**
3897
+ * Toggles the layout node on/off.
3898
+ * @param {any} settings
3899
+ * @ignore
3900
+ */
3901
+ function toggleLayoutNode(settings)
3902
+ {
3903
+ _instance.format.toggleLayoutNode(settings);
3904
+ }
3905
+
3906
+ /** Updates editor height.
3907
+ * @ignore
3908
+ */
3909
+ function updateHeight()
3910
+ {
3911
+ clearTimeout(_resizeTimerId);
3912
+ _resizeTimerId = setTimeout(function ()
3913
+ {
3914
+ deactivateDocument();
3915
+ let footerHeight = (_footerEl) ? _footerEl.offsetHeight : 0,
3916
+ height = $lib.getWindowSize().height - (_toolbar.offsetHeight + footerHeight);
3917
+
3918
+ _editor.style.height = $lib.unit(height);
3919
+
3920
+ if (!_instance.sourceViewInDialog)
3921
+ {
3922
+ let sourceEl = _sourceElement.get(_editableElement);
3923
+ sourceEl.style.height = _editor.style.height;
3924
+ }
3925
+
3926
+ }, 0);
3927
+ }
3928
+
3929
+ /**
3930
+ * Disables the block view.
3931
+ * @ignore
3932
+ */
3933
+ function disableBlockView()
3934
+ {
3935
+ if (!$UI.store[getId('blockView')])
3936
+ return;
3937
+
3938
+ let blockViewButton = $UI.store[getId('blockView')];
3939
+
3940
+ if (blockViewButton.selected)
3941
+ {
3942
+ blockViewButton.deselect();
3943
+ blockView();
3944
+ }
3945
+ }
3946
+
3947
+ /**
3948
+ * Toggles the menu button.
3949
+ * @param {any} button
3950
+ * @param {any} on
3951
+ * @ignore
3952
+ */
3953
+ function toggleMenuButton(button, on = null)
3954
+ {
3955
+ if (on === true)
3956
+ button.select();
3957
+ else if (on === false)
3958
+ button.deselect();
3959
+ else
3960
+ {
3961
+ if (button.selected)
3962
+ button.deselect();
3963
+ else
3964
+ button.select();
3965
+ }
3966
+ }
3967
+
3968
+ /**
3969
+ *
3970
+ * @param {any} id
3971
+ * @returns {any} return value
3972
+ * @ignore
3973
+ */
3974
+ function getId(id)
3975
+ {
3976
+ return _instance.id + '_' + id;
3977
+ }
3978
+
3979
+ /**
3980
+ * @ignore
3981
+ */
3982
+ function dispose()
3983
+ {
3984
+ if (hasEditables())
3985
+ {
3986
+ $lib.each(_instance.editableElements, (item) =>
3987
+ {
3988
+ _editableElement = item.element || $lib('#' + item.id);
3989
+ _instance.eventManager.disposeEvents();
3990
+ _instance.table.destroy();
3991
+ });
3992
+ }
3993
+ else
3994
+ {
3995
+ _instance.eventManager.disposeEvents();
3996
+ _instance.table.destroy();
3997
+ }
3998
+
3999
+ _instance.cancelSelectionChange = false;
4000
+ _instance.layoutState.dispose();
4001
+ _instance.tooltipMenu.dispose();
4002
+ _instance.history.dispose();
4003
+
4004
+ _sortedCommands = [];
4005
+ _sourceElement = new Map();
4006
+ _sourceViewStore = new Map();
4007
+ }
4008
+ };
4009
+
4010
+ /**
4011
+ * Creates an instance of the Style item.
4012
+ * @class
4013
+ * @param {Object} properties The properties used to initialize the object.
4014
+ * @property {String} [id] Gets or sets the identifier of the item (id is generated by default).
4015
+ * @property {String} text Gets or sets the display text of the item.
4016
+ * @property {String} previewCssClass Gets or sets the css class of the preview element.
4017
+ * @property {Boolean} [isCategory=false] Gets or sets a value indicating that the item is a category. Child-items of a category are rendered as root-level navigation and are displayed when the category-item is selected (hiding the current root menu/category).
4018
+ * @property {String} templateId Gets or sets the id of the menu item template.
4019
+ * @property {componyx.UI.Editor.HTMLElementSettings} elementSettings Gets or sets the settings which configure the element to insert into the document.
4020
+ * @property {componyx.UI.Editor.StyleItem[]} [itemList] Gets or sets the child-item list of the item.
4021
+ */
4022
+ componyx.UI.Editor.StyleItem = function (properties)
4023
+ {
4024
+ var p = properties;
4025
+
4026
+ this.id = (p) ? p.id : $lib.guid();
4027
+ this.text = (p) ? p.text : "";
4028
+ this.previewCssClass = (p) ? p.previewCssClass : "";
4029
+ this.isCategory = (p) ? p.isCategory : false;
4030
+ this.templateId = (p) ? p.templateId : "";
4031
+ this.elementSettings = (p) ? p.elementSettings || {} : {};
4032
+ this.itemList = [];
4033
+ };
4034
+
4035
+ /**
4036
+ * ToolbarDisplayOption
4037
+ * @readonly
4038
+ * @enum {number}
4039
+ */
4040
+ componyx.UI.Editor.ToolbarDisplayOption =
4041
+ {
4042
+ HEADER: 0,
4043
+ FOOTER: 1,
4044
+ CARET: 2,
4045
+
4046
+ getName: function (value) { return $base.static.getKeyByValue(this, value).toLowerCase(); }
4047
+ };
4048
+
4049
+ /**
4050
+ * @see {@link componyx.UI.base.methods}
4051
+ */
4052
+ componyx.UI.Editor.prototype = Object.create($base.methods);
4053
+ componyx.UI.Editor.prototype.constructor = componyx.UI.Editor;
4054
+ })(window);
4055
+
4056
+ const Editor = componyx.UI.Editor;
4057
+
4058
+ export { Editor };