@ckeditor/ckeditor5-editor-classic 48.2.0 → 48.3.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2,388 +2,346 @@
2
2
  * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
4
  */
5
- import { ElementReplacer, Rect, CKEditorError } from '@ckeditor/ckeditor5-utils/dist/index.js';
6
- import { rootAcceptsBlocks, ElementApiMixin, Editor, normalizeSingleRootEditorConstructorParams, normalizeRootsConfig, registerAndInitializeRootConfigAttributes, attachToForm, verifyRootElements } from '@ckeditor/ckeditor5-core/dist/index.js';
7
- import { EditorUI, normalizeToolbarConfig, DialogView, BoxedEditorUIView, StickyPanelView, ToolbarView, MenuBarView, InlineEditableUIView } from '@ckeditor/ckeditor5-ui/dist/index.js';
8
- import { enableViewPlaceholder } from '@ckeditor/ckeditor5-engine/dist/index.js';
9
- import { isElement as isElement$1 } from 'es-toolkit/compat';
5
+ import { CKEditorError, ElementReplacer, Rect } from "@ckeditor/ckeditor5-utils";
6
+ import { Editor, ElementApiMixin, attachToForm, normalizeRootsConfig, normalizeSingleRootEditorConstructorParams, registerAndInitializeRootConfigAttributes, rootAcceptsBlocks, verifyRootElements } from "@ckeditor/ckeditor5-core";
7
+ import { BoxedEditorUIView, DialogView, EditorUI, InlineEditableUIView, MenuBarView, StickyPanelView, ToolbarView, normalizeToolbarConfig } from "@ckeditor/ckeditor5-ui";
8
+ import { enableViewPlaceholder } from "@ckeditor/ckeditor5-engine";
9
+ import { isElement } from "es-toolkit/compat";
10
10
 
11
11
  /**
12
- * The classic editor UI class.
13
- */ class ClassicEditorUI extends EditorUI {
14
- /**
15
- * The main (top–most) view of the editor UI.
16
- */ view;
17
- /**
18
- * A normalized `config.toolbar` object.
19
- */ _toolbarConfig;
20
- /**
21
- * The element replacer instance used to hide the editor's source element.
22
- */ _elementReplacer;
23
- /**
24
- * Creates an instance of the classic editor UI class.
25
- *
26
- * @param editor The editor instance.
27
- * @param view The view of the UI.
28
- */ constructor(editor, view){
29
- super(editor);
30
- this.view = view;
31
- this._toolbarConfig = normalizeToolbarConfig(editor.config.get('toolbar'));
32
- this._elementReplacer = new ElementReplacer();
33
- this.listenTo(editor.editing.view, 'scrollToTheSelection', this._handleScrollToTheSelectionWithStickyPanel.bind(this));
34
- }
35
- /**
36
- * @inheritDoc
37
- */ get element() {
38
- return this.view.element;
39
- }
40
- /**
41
- * Initializes the UI.
42
- *
43
- * @param replacementElement The DOM element that will be the source for the created editor.
44
- */ init(replacementElement) {
45
- const editor = this.editor;
46
- const view = this.view;
47
- const editingView = editor.editing.view;
48
- const editable = view.editable;
49
- const editingRoot = editingView.document.getRoot();
50
- // The editable UI and editing root should share the same name. Then name is used
51
- // to recognize the particular editable, for instance in ARIA attributes.
52
- editable.name = editingRoot.rootName;
53
- // Resolved during UI init rather than in the editor constructor: by this point the plugin
54
- // initialization phase has finished, so the schema is fully populated and the check below
55
- // reflects any plugin-registered root types or additional content rules.
56
- editable.isInlineRoot = !rootAcceptsBlocks(editor, editingRoot.rootName);
57
- view.render();
58
- // The editable UI element in DOM is available for sure only after the editor UI view has been rendered.
59
- // But it can be available earlier if a DOM element has been passed to BalloonEditor.create().
60
- const editableElement = editable.element;
61
- // Register the editable UI view in the editor. A single editor instance can aggregate multiple
62
- // editable areas (roots) but the classic editor has only one.
63
- this.setEditableElement(editable.name, editableElement);
64
- // Let the editable UI element respond to the changes in the global editor focus
65
- // tracker. It has been added to the same tracker a few lines above but, in reality, there are
66
- // many focusable areas in the editor, like balloons, toolbars or dropdowns and as long
67
- // as they have focus, the editable should act like it is focused too (although technically
68
- // it isn't), e.g. by setting the proper CSS class, visually announcing focus to the user.
69
- // Doing otherwise will result in editable focus styles disappearing, once e.g. the
70
- // toolbar gets focused.
71
- view.editable.bind('isFocused').to(this.focusTracker);
72
- // Bind the editable UI element to the editing view, making it an end– and entry–point
73
- // of the editor's engine. This is where the engine meets the UI.
74
- editingView.attachDomRoot(editableElement);
75
- // If an element containing the initial data of the editor was provided, replace it with
76
- // an editor instance's UI in DOM until the editor is destroyed. For instance, a <textarea>
77
- // can be such element.
78
- if (replacementElement) {
79
- this._elementReplacer.replace(replacementElement, this.element);
80
- }
81
- this._initPlaceholder();
82
- this._initToolbar();
83
- if (view.menuBarView) {
84
- this.initMenuBar(view.menuBarView);
85
- }
86
- this._initDialogPluginIntegration();
87
- this._initContextualBalloonIntegration();
88
- this.fire('ready');
89
- }
90
- /**
91
- * @inheritDoc
92
- */ destroy() {
93
- super.destroy();
94
- const view = this.view;
95
- const editingView = this.editor.editing.view;
96
- this._elementReplacer.restore();
97
- if (editingView.getDomRoot(view.editable.name)) {
98
- editingView.detachDomRoot(view.editable.name);
99
- }
100
- view.destroy();
101
- }
102
- /**
103
- * Initializes the editor toolbar.
104
- */ _initToolbar() {
105
- const view = this.view;
106
- // Set–up the sticky panel with toolbar.
107
- view.stickyPanel.bind('isActive').to(this.focusTracker, 'isFocused');
108
- view.stickyPanel.limiterElement = view.element;
109
- view.stickyPanel.bind('viewportTopOffset').to(this, 'viewportOffset', ({ visualTop })=>visualTop || 0);
110
- view.toolbar.fillFromConfig(this._toolbarConfig, this.componentFactory);
111
- // Register the toolbar so it becomes available for Alt+F10 and Esc navigation.
112
- this.addToolbar(view.toolbar);
113
- }
114
- /**
115
- * Enable the placeholder text on the editing root.
116
- */ _initPlaceholder() {
117
- const editor = this.editor;
118
- const editingView = editor.editing.view;
119
- const editingRoot = editingView.document.getRoot();
120
- const sourceElement = editor.sourceElement;
121
- let placeholderText;
122
- const placeholder = editor.config.get('roots')[this.view.editable.name].placeholder;
123
- if (placeholder) {
124
- placeholderText = placeholder;
125
- }
126
- if (!placeholderText && sourceElement && sourceElement.tagName.toLowerCase() === 'textarea') {
127
- placeholderText = sourceElement.getAttribute('placeholder');
128
- }
129
- if (placeholderText) {
130
- editingRoot.placeholder = placeholderText;
131
- }
132
- enableViewPlaceholder({
133
- view: editingView,
134
- element: editingRoot,
135
- isDirectHost: this.view.editable.isInlineRoot,
136
- keepOnFocus: true
137
- });
138
- }
139
- /**
140
- * Provides an integration between the sticky toolbar and {@link module:ui/panel/balloon/contextualballoon contextual balloon plugin}.
141
- * It allows the contextual balloon to consider the height of the
142
- * {@link module:editor-classic/classiceditoruiview~ClassicEditorUIView#stickyPanel}. It prevents the balloon from overlapping
143
- * the sticky toolbar by adjusting the balloon's position using viewport offset configuration.
144
- */ _initContextualBalloonIntegration() {
145
- if (!this.editor.plugins.has('ContextualBalloon')) {
146
- return;
147
- }
148
- const { stickyPanel } = this.view;
149
- const contextualBalloon = this.editor.plugins.get('ContextualBalloon');
150
- contextualBalloon.on('getPositionOptions', (evt)=>{
151
- const position = evt.return;
152
- if (!position || !stickyPanel.isSticky || !stickyPanel.element) {
153
- return;
154
- }
155
- // Measure toolbar (and menu bar) height.
156
- const stickyPanelHeight = new Rect(stickyPanel.element).height;
157
- // Handle edge case when the target element is larger than the limiter.
158
- // It's an issue because the contextual balloon can overlap top table cells when the table is larger than the viewport
159
- // and it's placed at the top of the editor. It's better to overlap toolbar in that situation.
160
- // Check this issue: https://github.com/ckeditor/ckeditor5/issues/15744
161
- const target = typeof position.target === 'function' ? position.target() : position.target;
162
- const limiter = typeof position.limiter === 'function' ? position.limiter() : position.limiter;
163
- if (target && limiter && new Rect(target).height >= new Rect(limiter).height - stickyPanelHeight) {
164
- return;
165
- }
166
- // Ensure that viewport offset is present, it can be undefined according to the typing.
167
- const viewportOffsetConfig = {
168
- ...position.viewportOffsetConfig
169
- };
170
- const newTopViewportOffset = (viewportOffsetConfig.top || 0) + stickyPanelHeight;
171
- evt.return = {
172
- ...position,
173
- viewportOffsetConfig: {
174
- ...viewportOffsetConfig,
175
- top: newTopViewportOffset
176
- }
177
- };
178
- }, {
179
- priority: 'low'
180
- });
181
- // Update balloon position when the toolbar becomes sticky or when ui viewportOffset changes.
182
- const updateBalloonPosition = ()=>{
183
- if (contextualBalloon.visibleView) {
184
- contextualBalloon.updatePosition();
185
- }
186
- };
187
- this.listenTo(stickyPanel, 'change:isSticky', updateBalloonPosition);
188
- this.listenTo(this.editor.ui, 'change:viewportOffset', updateBalloonPosition);
189
- }
190
- /**
191
- * Provides an integration between the sticky toolbar and {@link module:utils/dom/scroll~scrollViewportToShowTarget}.
192
- * It allows the UI-agnostic engine method to consider the geometry of the
193
- * {@link module:editor-classic/classiceditoruiview~ClassicEditorUIView#stickyPanel} that pins to the
194
- * edge of the viewport and can obscure the user caret after scrolling the window.
195
- *
196
- * @param evt The `scrollToTheSelection` event info.
197
- * @param data The payload carried by the `scrollToTheSelection` event.
198
- * @param originalArgs The original arguments passed to `scrollViewportToShowTarget()` method (see implementation to learn more).
199
- */ _handleScrollToTheSelectionWithStickyPanel(evt, data, originalArgs) {
200
- const stickyPanel = this.view.stickyPanel;
201
- if (stickyPanel.isSticky) {
202
- const stickyPanelHeight = new Rect(stickyPanel.element).height;
203
- data.viewportOffset.top += stickyPanelHeight;
204
- } else {
205
- const scrollViewportOnPanelGettingSticky = ()=>{
206
- this.editor.editing.view.scrollToTheSelection(originalArgs);
207
- };
208
- this.listenTo(stickyPanel, 'change:isSticky', scrollViewportOnPanelGettingSticky);
209
- // This works as a post-scroll-fixer because it's impossible predict whether the panel will be sticky after scrolling or not.
210
- // Listen for a short period of time only and if the toolbar does not become sticky very soon, cancel the listener.
211
- setTimeout(()=>{
212
- this.stopListening(stickyPanel, 'change:isSticky', scrollViewportOnPanelGettingSticky);
213
- }, 20);
214
- }
215
- }
216
- /**
217
- * Provides an integration between the sticky toolbar and {@link module:ui/dialog/dialog the Dialog plugin}.
218
- *
219
- * It moves the dialog down to ensure that the
220
- * {@link module:editor-classic/classiceditoruiview~ClassicEditorUIView#stickyPanel sticky panel}
221
- * used by the editor UI will not get obscured by the dialog when the dialog uses one of its automatic positions.
222
- */ _initDialogPluginIntegration() {
223
- if (!this.editor.plugins.has('Dialog')) {
224
- return;
225
- }
226
- const stickyPanel = this.view.stickyPanel;
227
- const dialogPlugin = this.editor.plugins.get('Dialog');
228
- dialogPlugin.on('show', ()=>{
229
- const dialogView = dialogPlugin.view;
230
- dialogView.on('moveTo', (evt, data)=>{
231
- // Engage only when the panel is sticky, and the dialog is using one of default positions.
232
- // Ignore modals because they are displayed on top of the page (and overlay) and they do not collide with anything
233
- // See (https://github.com/ckeditor/ckeditor5/issues/17339).
234
- if (!stickyPanel.isSticky || dialogView.wasMoved || dialogView.isModal) {
235
- return;
236
- }
237
- const stickyPanelContentRect = new Rect(stickyPanel.contentPanelElement);
238
- if (data[1] < stickyPanelContentRect.bottom + DialogView.defaultOffset) {
239
- data[1] = stickyPanelContentRect.bottom + DialogView.defaultOffset;
240
- }
241
- }, {
242
- priority: 'high'
243
- });
244
- }, {
245
- priority: 'low'
246
- });
247
- }
248
- }
12
+ * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
13
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
14
+ */
15
+ /**
16
+ * @module editor-classic/classiceditorui
17
+ */
18
+ /**
19
+ * The classic editor UI class.
20
+ */
21
+ var ClassicEditorUI = class extends EditorUI {
22
+ /**
23
+ * The main (top–most) view of the editor UI.
24
+ */
25
+ view;
26
+ /**
27
+ * A normalized `config.toolbar` object.
28
+ */
29
+ _toolbarConfig;
30
+ /**
31
+ * The element replacer instance used to hide the editor's source element.
32
+ */
33
+ _elementReplacer;
34
+ /**
35
+ * Creates an instance of the classic editor UI class.
36
+ *
37
+ * @param editor The editor instance.
38
+ * @param view The view of the UI.
39
+ */
40
+ constructor(editor, view) {
41
+ super(editor);
42
+ this.view = view;
43
+ this._toolbarConfig = normalizeToolbarConfig(editor.config.get("toolbar"));
44
+ this._elementReplacer = new ElementReplacer();
45
+ this.listenTo(editor.editing.view, "scrollToTheSelection", this._handleScrollToTheSelectionWithStickyPanel.bind(this));
46
+ }
47
+ /**
48
+ * @inheritDoc
49
+ */
50
+ get element() {
51
+ return this.view.element;
52
+ }
53
+ /**
54
+ * Initializes the UI.
55
+ *
56
+ * @param replacementElement The DOM element that will be the source for the created editor.
57
+ */
58
+ init(replacementElement) {
59
+ const editor = this.editor;
60
+ const view = this.view;
61
+ const editingView = editor.editing.view;
62
+ const editable = view.editable;
63
+ const editingRoot = editingView.document.getRoot();
64
+ editable.name = editingRoot.rootName;
65
+ editable.isInlineRoot = !rootAcceptsBlocks(editor, editingRoot.rootName);
66
+ view.render();
67
+ const editableElement = editable.element;
68
+ this.setEditableElement(editable.name, editableElement);
69
+ view.editable.bind("isFocused").to(this.focusTracker);
70
+ editingView.attachDomRoot(editableElement);
71
+ if (replacementElement) this._elementReplacer.replace(replacementElement, this.element);
72
+ this._initPlaceholder();
73
+ this._initToolbar();
74
+ if (view.menuBarView) this.initMenuBar(view.menuBarView);
75
+ this._initDialogPluginIntegration();
76
+ this._initContextualBalloonIntegration();
77
+ this.fire("ready");
78
+ }
79
+ /**
80
+ * @inheritDoc
81
+ */
82
+ destroy() {
83
+ super.destroy();
84
+ const view = this.view;
85
+ const editingView = this.editor.editing.view;
86
+ this._elementReplacer.restore();
87
+ if (editingView.getDomRoot(view.editable.name)) editingView.detachDomRoot(view.editable.name);
88
+ view.destroy();
89
+ }
90
+ /**
91
+ * Initializes the editor toolbar.
92
+ */
93
+ _initToolbar() {
94
+ const view = this.view;
95
+ view.stickyPanel.bind("isActive").to(this.focusTracker, "isFocused");
96
+ view.stickyPanel.limiterElement = view.element;
97
+ view.stickyPanel.bind("viewportTopOffset").to(this, "viewportOffset", ({ visualTop }) => visualTop || 0);
98
+ view.toolbar.fillFromConfig(this._toolbarConfig, this.componentFactory);
99
+ this.addToolbar(view.toolbar);
100
+ }
101
+ /**
102
+ * Enable the placeholder text on the editing root.
103
+ */
104
+ _initPlaceholder() {
105
+ const editor = this.editor;
106
+ const editingView = editor.editing.view;
107
+ const editingRoot = editingView.document.getRoot();
108
+ const sourceElement = editor.sourceElement;
109
+ let placeholderText;
110
+ const placeholder = editor.config.get("roots")[this.view.editable.name].placeholder;
111
+ if (placeholder) placeholderText = placeholder;
112
+ if (!placeholderText && sourceElement && sourceElement.tagName.toLowerCase() === "textarea") placeholderText = sourceElement.getAttribute("placeholder");
113
+ if (placeholderText) editingRoot.placeholder = placeholderText;
114
+ enableViewPlaceholder({
115
+ view: editingView,
116
+ element: editingRoot,
117
+ isDirectHost: this.view.editable.isInlineRoot,
118
+ keepOnFocus: true
119
+ });
120
+ }
121
+ /**
122
+ * Provides an integration between the sticky toolbar and {@link module:ui/panel/balloon/contextualballoon contextual balloon plugin}.
123
+ * It allows the contextual balloon to consider the height of the
124
+ * {@link module:editor-classic/classiceditoruiview~ClassicEditorUIView#stickyPanel}. It prevents the balloon from overlapping
125
+ * the sticky toolbar by adjusting the balloon's position using viewport offset configuration.
126
+ */
127
+ _initContextualBalloonIntegration() {
128
+ if (!this.editor.plugins.has("ContextualBalloon")) return;
129
+ const { stickyPanel } = this.view;
130
+ const contextualBalloon = this.editor.plugins.get("ContextualBalloon");
131
+ contextualBalloon.on("getPositionOptions", (evt) => {
132
+ const position = evt.return;
133
+ if (!position || !stickyPanel.isSticky || !stickyPanel.element) return;
134
+ const stickyPanelHeight = new Rect(stickyPanel.element).height;
135
+ const target = typeof position.target === "function" ? position.target() : position.target;
136
+ const limiter = typeof position.limiter === "function" ? position.limiter() : position.limiter;
137
+ if (target && limiter && new Rect(target).height >= new Rect(limiter).height - stickyPanelHeight) return;
138
+ const viewportOffsetConfig = { ...position.viewportOffsetConfig };
139
+ const newTopViewportOffset = (viewportOffsetConfig.top || 0) + stickyPanelHeight;
140
+ evt.return = {
141
+ ...position,
142
+ viewportOffsetConfig: {
143
+ ...viewportOffsetConfig,
144
+ top: newTopViewportOffset
145
+ }
146
+ };
147
+ }, { priority: "low" });
148
+ const updateBalloonPosition = () => {
149
+ if (contextualBalloon.visibleView) contextualBalloon.updatePosition();
150
+ };
151
+ this.listenTo(stickyPanel, "change:isSticky", updateBalloonPosition);
152
+ this.listenTo(this.editor.ui, "change:viewportOffset", updateBalloonPosition);
153
+ }
154
+ /**
155
+ * Provides an integration between the sticky toolbar and {@link module:utils/dom/scroll~scrollViewportToShowTarget}.
156
+ * It allows the UI-agnostic engine method to consider the geometry of the
157
+ * {@link module:editor-classic/classiceditoruiview~ClassicEditorUIView#stickyPanel} that pins to the
158
+ * edge of the viewport and can obscure the user caret after scrolling the window.
159
+ *
160
+ * @param evt The `scrollToTheSelection` event info.
161
+ * @param data The payload carried by the `scrollToTheSelection` event.
162
+ * @param originalArgs The original arguments passed to `scrollViewportToShowTarget()` method (see implementation to learn more).
163
+ */
164
+ _handleScrollToTheSelectionWithStickyPanel(evt, data, originalArgs) {
165
+ const stickyPanel = this.view.stickyPanel;
166
+ if (stickyPanel.isSticky) {
167
+ const stickyPanelHeight = new Rect(stickyPanel.element).height;
168
+ data.viewportOffset.top += stickyPanelHeight;
169
+ } else {
170
+ const scrollViewportOnPanelGettingSticky = () => {
171
+ this.editor.editing.view.scrollToTheSelection(originalArgs);
172
+ };
173
+ this.listenTo(stickyPanel, "change:isSticky", scrollViewportOnPanelGettingSticky);
174
+ setTimeout(() => {
175
+ this.stopListening(stickyPanel, "change:isSticky", scrollViewportOnPanelGettingSticky);
176
+ }, 20);
177
+ }
178
+ }
179
+ /**
180
+ * Provides an integration between the sticky toolbar and {@link module:ui/dialog/dialog the Dialog plugin}.
181
+ *
182
+ * It moves the dialog down to ensure that the
183
+ * {@link module:editor-classic/classiceditoruiview~ClassicEditorUIView#stickyPanel sticky panel}
184
+ * used by the editor UI will not get obscured by the dialog when the dialog uses one of its automatic positions.
185
+ */
186
+ _initDialogPluginIntegration() {
187
+ if (!this.editor.plugins.has("Dialog")) return;
188
+ const stickyPanel = this.view.stickyPanel;
189
+ const dialogPlugin = this.editor.plugins.get("Dialog");
190
+ dialogPlugin.on("show", () => {
191
+ const dialogView = dialogPlugin.view;
192
+ dialogView.on("moveTo", (evt, data) => {
193
+ if (!stickyPanel.isSticky || dialogView.wasMoved || dialogView.isModal) return;
194
+ const stickyPanelContentRect = new Rect(stickyPanel.contentPanelElement);
195
+ if (data[1] < stickyPanelContentRect.bottom + DialogView.defaultOffset) data[1] = stickyPanelContentRect.bottom + DialogView.defaultOffset;
196
+ }, { priority: "high" });
197
+ }, { priority: "low" });
198
+ }
199
+ };
249
200
 
250
201
  /**
251
- * Classic editor UI view. Uses an inline editable and a sticky toolbar, all
252
- * enclosed in a boxed UI view.
253
- */ class ClassicEditorUIView extends BoxedEditorUIView {
254
- /**
255
- * Sticky panel view instance. This is a parent view of a {@link #toolbar}
256
- * that makes toolbar sticky.
257
- */ stickyPanel;
258
- /**
259
- * Toolbar view instance.
260
- */ toolbar;
261
- /**
262
- * Editable UI view.
263
- */ editable;
264
- /**
265
- * Creates an instance of the classic editor UI view.
266
- *
267
- * @param locale The {@link module:core/editor/editor~Editor#locale} instance.
268
- * @param editingView The editing view instance this view is related to.
269
- * @param options Configuration options for the view instance.
270
- * @param options.shouldToolbarGroupWhenFull When set `true` enables automatic items grouping
271
- * in the main {@link module:editor-classic/classiceditoruiview~ClassicEditorUIView#toolbar toolbar}.
272
- * See {@link module:ui/toolbar/toolbarview~ToolbarOptions#shouldGroupWhenFull} to learn more.
273
- * @param options.editableElement A {@link module:core/editor/editorconfig~ViewRootElementDefinition}
274
- * describing the editable element to create inside the UI box. When omitted, a default `<div>` is used.
275
- * @param options.label When set, this value will be used as an accessible `aria-label` of the
276
- * {@link module:ui/editableui/editableuiview~EditableUIView editable view}.
277
- */ constructor(locale, editingView, options = {}){
278
- super(locale);
279
- this.stickyPanel = new StickyPanelView(locale);
280
- this.toolbar = new ToolbarView(locale, {
281
- shouldGroupWhenFull: options.shouldToolbarGroupWhenFull
282
- });
283
- if (options.useMenuBar) {
284
- this.menuBarView = new MenuBarView(locale);
285
- }
286
- this.editable = new InlineEditableUIView(locale, editingView, options.editableElement, {
287
- label: options.label
288
- });
289
- }
290
- /**
291
- * @inheritDoc
292
- */ render() {
293
- super.render();
294
- if (this.menuBarView) {
295
- // Set toolbar as a child of a stickyPanel and makes toolbar sticky.
296
- this.stickyPanel.content.addMany([
297
- this.menuBarView,
298
- this.toolbar
299
- ]);
300
- } else {
301
- this.stickyPanel.content.add(this.toolbar);
302
- }
303
- this.top.add(this.stickyPanel);
304
- this.main.add(this.editable);
305
- }
306
- }
202
+ * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
203
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
204
+ */
205
+ /**
206
+ * @module editor-classic/classiceditoruiview
207
+ */
208
+ /**
209
+ * Classic editor UI view. Uses an inline editable and a sticky toolbar, all
210
+ * enclosed in a boxed UI view.
211
+ */
212
+ var ClassicEditorUIView = class extends BoxedEditorUIView {
213
+ /**
214
+ * Sticky panel view instance. This is a parent view of a {@link #toolbar}
215
+ * that makes toolbar sticky.
216
+ */
217
+ stickyPanel;
218
+ /**
219
+ * Toolbar view instance.
220
+ */
221
+ toolbar;
222
+ /**
223
+ * Editable UI view.
224
+ */
225
+ editable;
226
+ /**
227
+ * Creates an instance of the classic editor UI view.
228
+ *
229
+ * @param locale The {@link module:core/editor/editor~Editor#locale} instance.
230
+ * @param editingView The editing view instance this view is related to.
231
+ * @param options Configuration options for the view instance.
232
+ * @param options.shouldToolbarGroupWhenFull When set `true` enables automatic items grouping
233
+ * in the main {@link module:editor-classic/classiceditoruiview~ClassicEditorUIView#toolbar toolbar}.
234
+ * See {@link module:ui/toolbar/toolbarview~ToolbarOptions#shouldGroupWhenFull} to learn more.
235
+ * @param options.editableElement A {@link module:core/editor/editorconfig~ViewRootElementDefinition}
236
+ * describing the editable element to create inside the UI box. When omitted, a default `<div>` is used.
237
+ * @param options.label When set, this value will be used as an accessible `aria-label` of the
238
+ * {@link module:ui/editableui/editableuiview~EditableUIView editable view}.
239
+ */
240
+ constructor(locale, editingView, options = {}) {
241
+ super(locale);
242
+ this.stickyPanel = new StickyPanelView(locale);
243
+ this.toolbar = new ToolbarView(locale, { shouldGroupWhenFull: options.shouldToolbarGroupWhenFull });
244
+ if (options.useMenuBar) this.menuBarView = new MenuBarView(locale);
245
+ this.editable = new InlineEditableUIView(locale, editingView, options.editableElement, { label: options.label });
246
+ }
247
+ /**
248
+ * @inheritDoc
249
+ */
250
+ render() {
251
+ super.render();
252
+ if (this.menuBarView) this.stickyPanel.content.addMany([this.menuBarView, this.toolbar]);
253
+ else this.stickyPanel.content.add(this.toolbar);
254
+ this.top.add(this.stickyPanel);
255
+ this.main.add(this.editable);
256
+ }
257
+ };
307
258
 
308
259
  /**
309
- * The classic editor implementation. It uses an inline editable and a sticky toolbar, all enclosed in a boxed UI.
310
- * See the {@glink examples/builds/classic-editor demo}.
311
- *
312
- * In order to create a classic editor instance, use the static
313
- * {@link module:editor-classic/classiceditor~ClassicEditor.create `ClassicEditor.create()`} method.
314
- */ class ClassicEditor extends /* #__PURE__ */ ElementApiMixin(Editor) {
315
- /**
316
- * @inheritDoc
317
- */ static get editorName() {
318
- return 'ClassicEditor';
319
- }
320
- /**
321
- * @inheritDoc
322
- */ ui;
323
- constructor(sourceElementOrDataOrConfig, config = {}){
324
- const { sourceElementOrData, editorConfig } = normalizeSingleRootEditorConstructorParams(sourceElementOrDataOrConfig, config);
325
- super(editorConfig);
326
- normalizeRootsConfig(sourceElementOrData, this.config, 'main', true);
327
- // From this point use only normalized `roots.main.element`.
328
- const sourceElement = this.config.get('attachTo');
329
- this.config.define('menuBar.isVisible', false);
330
- if (isElement(sourceElement)) {
331
- if (!sourceElement.isConnected) {
332
- /**
333
- * Cannot initialize the editor because the provided source element is not attached to the DOM and cannot be replaced.
334
- *
335
- * @error editor-source-element-not-attached
336
- */ throw new CKEditorError('editor-source-element-not-attached', null);
337
- }
338
- this.sourceElement = sourceElement;
339
- }
340
- this.model.document.createRoot(this.config.get('roots').main.modelElement);
341
- registerAndInitializeRootConfigAttributes(this);
342
- const shouldToolbarGroupWhenFull = !this.config.get('toolbar.shouldNotGroupWhenFull');
343
- const menuBarConfig = this.config.get('menuBar');
344
- // The `normalizeRootsConfig()` already normalized this.
345
- const editableElement = this.config.get('roots').main.element;
346
- const view = new ClassicEditorUIView(this.locale, this.editing.view, {
347
- shouldToolbarGroupWhenFull,
348
- useMenuBar: menuBarConfig.isVisible,
349
- label: this.config.get('roots').main.label,
350
- editableElement
351
- });
352
- this.ui = new ClassicEditorUI(this, view);
353
- attachToForm(this);
354
- }
355
- /**
356
- * Destroys the editor instance, releasing all resources used by it.
357
- *
358
- * Updates the original editor element with the data if the
359
- * {@link module:core/editor/editorconfig~EditorConfig#updateSourceElementOnDestroy `updateSourceElementOnDestroy`}
360
- * configuration option is set to `true`.
361
- */ async destroy() {
362
- if (this.sourceElement) {
363
- this.updateSourceElement();
364
- }
365
- this.ui.destroy();
366
- await super.destroy();
367
- // To satisfy the return type and to keep it backward compatible.
368
- // eslint-disable-next-line no-useless-return
369
- return;
370
- }
371
- static async create(sourceElementOrDataOrConfig, config = {}) {
372
- const editor = new this(sourceElementOrDataOrConfig, config);
373
- await editor.initPlugins();
374
- // Roots are created in the editor constructor (before plugins are loaded), but the schema is only fully
375
- // built after plugins register their items during init(). Custom root element names (e.g. registered by a
376
- // plugin) may not exist in the schema at construction time, so we defer this check until here.
377
- verifyRootElements(editor);
378
- await editor.ui.init(editor.config.get('attachTo') || null);
379
- await editor.data.init(editor.config.get('roots').main.initialData);
380
- editor.fire('ready');
381
- return editor;
382
- }
383
- }
384
- function isElement(value) {
385
- return isElement$1(value);
260
+ * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
261
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
262
+ */
263
+ /**
264
+ * @module editor-classic/classiceditor
265
+ */
266
+ const ClassicEditorBase = /* #__PURE__ */ ElementApiMixin(Editor);
267
+ /**
268
+ * The classic editor implementation. It uses an inline editable and a sticky toolbar, all enclosed in a boxed UI.
269
+ * See the {@glink examples/builds/classic-editor demo}.
270
+ *
271
+ * In order to create a classic editor instance, use the static
272
+ * {@link module:editor-classic/classiceditor~ClassicEditor.create `ClassicEditor.create()`} method.
273
+ */
274
+ var ClassicEditor = class extends ClassicEditorBase {
275
+ /**
276
+ * @inheritDoc
277
+ */
278
+ static get editorName() {
279
+ return "ClassicEditor";
280
+ }
281
+ /**
282
+ * @inheritDoc
283
+ */
284
+ ui;
285
+ constructor(sourceElementOrDataOrConfig, config = {}) {
286
+ const { sourceElementOrData, editorConfig } = normalizeSingleRootEditorConstructorParams(sourceElementOrDataOrConfig, config);
287
+ super(editorConfig);
288
+ normalizeRootsConfig(sourceElementOrData, this.config, "main", true);
289
+ const sourceElement = this.config.get("attachTo");
290
+ this.config.define("menuBar.isVisible", false);
291
+ if (isElement$1(sourceElement)) {
292
+ if (!sourceElement.isConnected)
293
+ /**
294
+ * Cannot initialize the editor because the provided source element is not attached to the DOM and cannot be replaced.
295
+ *
296
+ * @error editor-source-element-not-attached
297
+ */
298
+ throw new CKEditorError("editor-source-element-not-attached", null);
299
+ this.sourceElement = sourceElement;
300
+ }
301
+ this.model.document.createRoot(this.config.get("roots").main.modelElement);
302
+ registerAndInitializeRootConfigAttributes(this);
303
+ const shouldToolbarGroupWhenFull = !this.config.get("toolbar.shouldNotGroupWhenFull");
304
+ const menuBarConfig = this.config.get("menuBar");
305
+ const editableElement = this.config.get("roots").main.element;
306
+ const view = new ClassicEditorUIView(this.locale, this.editing.view, {
307
+ shouldToolbarGroupWhenFull,
308
+ useMenuBar: menuBarConfig.isVisible,
309
+ label: this.config.get("roots").main.label,
310
+ editableElement
311
+ });
312
+ this.ui = new ClassicEditorUI(this, view);
313
+ attachToForm(this);
314
+ }
315
+ /**
316
+ * Destroys the editor instance, releasing all resources used by it.
317
+ *
318
+ * Updates the original editor element with the data if the
319
+ * {@link module:core/editor/editorconfig~EditorConfig#updateSourceElementOnDestroy `updateSourceElementOnDestroy`}
320
+ * configuration option is set to `true`.
321
+ */
322
+ async destroy() {
323
+ if (this.sourceElement) this.updateSourceElement();
324
+ this.ui.destroy();
325
+ await super.destroy();
326
+ }
327
+ static async create(sourceElementOrDataOrConfig, config = {}) {
328
+ const editor = new this(sourceElementOrDataOrConfig, config);
329
+ await editor.initPlugins();
330
+ verifyRootElements(editor);
331
+ await editor.ui.init(editor.config.get("attachTo") || null);
332
+ await editor.data.init(editor.config.get("roots").main.initialData);
333
+ editor.fire("ready");
334
+ return editor;
335
+ }
336
+ };
337
+ function isElement$1(value) {
338
+ return isElement(value);
386
339
  }
387
340
 
341
+ /**
342
+ * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
343
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
344
+ */
345
+
388
346
  export { ClassicEditor, ClassicEditorUI, ClassicEditorUIView };
389
- //# sourceMappingURL=index.js.map
347
+ //# sourceMappingURL=index.js.map