@ckeditor/ckeditor5-ui 43.3.1 → 44.0.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/README.md +13 -7
- package/dist/badge/badge.d.ts +133 -0
- package/dist/dropdown/dropdownview.d.ts +6 -0
- package/dist/editorui/bodycollection.d.ts +47 -12
- package/dist/editorui/editorui.d.ts +5 -0
- package/dist/editorui/evaluationbadge.d.ts +37 -0
- package/dist/editorui/poweredby.d.ts +12 -49
- package/dist/index-editor.css +52 -3
- package/dist/index.css +62 -3
- package/dist/index.css.map +1 -1
- package/dist/index.js +351 -144
- package/dist/index.js.map +1 -1
- package/dist/menubar/menubarmenupanelview.d.ts +1 -1
- package/dist/menubar/menubarmenuview.d.ts +5 -0
- package/dist/menubar/utils.d.ts +1 -0
- package/package.json +4 -4
- package/src/badge/badge.d.ts +129 -0
- package/src/badge/badge.js +218 -0
- package/src/dialog/dialogview.js +6 -2
- package/src/dropdown/dropdownview.d.ts +6 -0
- package/src/dropdown/dropdownview.js +9 -1
- package/src/editorui/bodycollection.d.ts +47 -12
- package/src/editorui/bodycollection.js +50 -19
- package/src/editorui/editorui.d.ts +5 -0
- package/src/editorui/editorui.js +3 -0
- package/src/editorui/evaluationbadge.d.ts +33 -0
- package/src/editorui/evaluationbadge.js +99 -0
- package/src/editorui/poweredby.d.ts +12 -49
- package/src/editorui/poweredby.js +36 -194
- package/src/menubar/menubarmenupanelview.d.ts +1 -1
- package/src/menubar/menubarmenuview.d.ts +5 -0
- package/src/menubar/menubarmenuview.js +23 -1
- package/src/menubar/utils.d.ts +1 -0
- package/src/menubar/utils.js +2 -0
- package/theme/globals/_evaluationbadge.css +54 -0
- package/theme/globals/_poweredby.css +15 -3
- package/theme/globals/globals.css +1 -0
|
@@ -54,4 +54,4 @@ export default class MenuBarMenuPanelView extends View implements FocusableView
|
|
|
54
54
|
*
|
|
55
55
|
* They are reflected as CSS class suffixes on the panel view element.
|
|
56
56
|
*/
|
|
57
|
-
export type MenuBarMenuPanelPosition = 'se' | 'sw' | 'ne' | 'nw' | 'w' | 'e';
|
|
57
|
+
export type MenuBarMenuPanelPosition = 'se' | 'sw' | 'ne' | 'nw' | 'w' | 'ws' | 'e' | 'es';
|
|
@@ -104,6 +104,11 @@ export default class MenuBarMenuView extends View implements FocusableView {
|
|
|
104
104
|
* the {@link module:ui/menubar/menubarview~MenuBarView menu bar} and the UI language direction.
|
|
105
105
|
*/
|
|
106
106
|
get _panelPositions(): Array<PositioningFunction>;
|
|
107
|
+
/**
|
|
108
|
+
* The default position of the panel when the menu is opened.
|
|
109
|
+
* It is used when the optimal position cannot be calculated.
|
|
110
|
+
*/
|
|
111
|
+
private get _defaultMenuPositionName();
|
|
107
112
|
/**
|
|
108
113
|
* A function used to calculate the optimal position for the dropdown panel.
|
|
109
114
|
*
|
package/dist/menubar/utils.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ckeditor/ckeditor5-ui",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "44.0.0-alpha.1",
|
|
4
4
|
"description": "The UI framework and standard UI library of CKEditor 5.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ckeditor",
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
"type": "module",
|
|
13
13
|
"main": "src/index.js",
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@ckeditor/ckeditor5-core": "
|
|
16
|
-
"@ckeditor/ckeditor5-engine": "
|
|
17
|
-
"@ckeditor/ckeditor5-utils": "
|
|
15
|
+
"@ckeditor/ckeditor5-core": "44.0.0-alpha.1",
|
|
16
|
+
"@ckeditor/ckeditor5-engine": "44.0.0-alpha.1",
|
|
17
|
+
"@ckeditor/ckeditor5-utils": "44.0.0-alpha.1",
|
|
18
18
|
"color-convert": "2.0.1",
|
|
19
19
|
"color-parse": "1.4.2",
|
|
20
20
|
"lodash-es": "4.17.21",
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* @module ui/badge/badge
|
|
7
|
+
*/
|
|
8
|
+
import type { Editor } from '@ckeditor/ckeditor5-core';
|
|
9
|
+
import type View from '../view.js';
|
|
10
|
+
declare const Badge_base: {
|
|
11
|
+
new (): import("@ckeditor/ckeditor5-utils").DomEmitter;
|
|
12
|
+
prototype: import("@ckeditor/ckeditor5-utils").DomEmitter;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* A helper that enables the badge feature in the editor and renders a custom view next to the bottom of the editable element
|
|
16
|
+
* (editor root, source editing area, etc.) when the editor is focused.
|
|
17
|
+
*
|
|
18
|
+
* @private
|
|
19
|
+
*/
|
|
20
|
+
export default abstract class Badge extends /* #__PURE__ */ Badge_base {
|
|
21
|
+
/**
|
|
22
|
+
* Editor instance the helper was created for.
|
|
23
|
+
*/
|
|
24
|
+
protected readonly editor: Editor;
|
|
25
|
+
/**
|
|
26
|
+
* A reference to the balloon panel hosting and positioning the badge content.
|
|
27
|
+
*/
|
|
28
|
+
private _balloonView;
|
|
29
|
+
/**
|
|
30
|
+
* A throttled version of the {@link #_showBalloon} method meant for frequent use to avoid performance loss.
|
|
31
|
+
*/
|
|
32
|
+
private _showBalloonThrottled;
|
|
33
|
+
/**
|
|
34
|
+
* A reference to the last editable element (root, source editing area, etc.) focused by the user.
|
|
35
|
+
* Since the focus can move to other focusable elements in the UI, this reference allows positioning the balloon over the
|
|
36
|
+
* right element whether the user is typing or using the UI.
|
|
37
|
+
*/
|
|
38
|
+
private _lastFocusedEditableElement;
|
|
39
|
+
/**
|
|
40
|
+
* An additional CSS class added to the `BalloonView`.
|
|
41
|
+
*/
|
|
42
|
+
private readonly _balloonClass;
|
|
43
|
+
/**
|
|
44
|
+
* Creates a badge for a given editor. The feature is initialized on Editor#ready
|
|
45
|
+
* event.
|
|
46
|
+
*/
|
|
47
|
+
protected constructor(editor: Editor, options?: {
|
|
48
|
+
balloonClass?: string;
|
|
49
|
+
});
|
|
50
|
+
/**
|
|
51
|
+
* Destroys the badge along with its view.
|
|
52
|
+
*/
|
|
53
|
+
destroy(): void;
|
|
54
|
+
/**
|
|
55
|
+
* Enables badge label once the editor (ui) is ready.
|
|
56
|
+
*/
|
|
57
|
+
protected _handleEditorReady(): void;
|
|
58
|
+
/**
|
|
59
|
+
* Returns normalized configuration for the badge.
|
|
60
|
+
*/
|
|
61
|
+
protected _getNormalizedConfig(): BadgeConfig;
|
|
62
|
+
/**
|
|
63
|
+
* Creates the badge content.
|
|
64
|
+
*/
|
|
65
|
+
protected abstract _createBadgeContent(): View<HTMLElement>;
|
|
66
|
+
/**
|
|
67
|
+
* Enables the badge feature.
|
|
68
|
+
*/
|
|
69
|
+
protected abstract _isEnabled(): boolean;
|
|
70
|
+
/**
|
|
71
|
+
* Attempts to display the balloon with the badge view.
|
|
72
|
+
*/
|
|
73
|
+
private _showBalloon;
|
|
74
|
+
/**
|
|
75
|
+
* Hides the badge balloon if already visible.
|
|
76
|
+
*/
|
|
77
|
+
private _hideBalloon;
|
|
78
|
+
/**
|
|
79
|
+
* Creates an instance of the {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView balloon panel}
|
|
80
|
+
* with the badge view inside ready for positioning.
|
|
81
|
+
*/
|
|
82
|
+
private _createBalloonView;
|
|
83
|
+
/**
|
|
84
|
+
* Returns the options for attaching the balloon to the focused editable element.
|
|
85
|
+
*/
|
|
86
|
+
private _getBalloonAttachOptions;
|
|
87
|
+
/**
|
|
88
|
+
* Updates the {@link #_lastFocusedEditableElement} based on the state of the global focus tracker.
|
|
89
|
+
*/
|
|
90
|
+
private _updateLastFocusedEditableElement;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* The badge configuration options.
|
|
94
|
+
**/
|
|
95
|
+
export interface BadgeConfig {
|
|
96
|
+
/**
|
|
97
|
+
* The position of the badge.
|
|
98
|
+
*
|
|
99
|
+
* * When `'inside'`, the badge will be displayed within the boundaries of the editing area.
|
|
100
|
+
* * When `'border'`, the basge will be displayed over the bottom border of the editing area.
|
|
101
|
+
*
|
|
102
|
+
* @default 'border'
|
|
103
|
+
*/
|
|
104
|
+
position: 'inside' | 'border';
|
|
105
|
+
/**
|
|
106
|
+
* Allows choosing the side of the editing area where the badge will be displayed.
|
|
107
|
+
*
|
|
108
|
+
* **Note:** If {@link module:core/editor/editorconfig~EditorConfig#language `config.language`} is set to an RTL (right-to-left)
|
|
109
|
+
* language, the side switches to `'left'` by default.
|
|
110
|
+
*
|
|
111
|
+
* @default 'right'
|
|
112
|
+
*/
|
|
113
|
+
side: 'left' | 'right';
|
|
114
|
+
/**
|
|
115
|
+
* The vertical distance the badge can be moved away from its default position.
|
|
116
|
+
*
|
|
117
|
+
* **Note:** If `position` is `'border'`, the offset is measured from the (vertical) center of the badge.
|
|
118
|
+
*
|
|
119
|
+
* @default 5
|
|
120
|
+
*/
|
|
121
|
+
verticalOffset: number;
|
|
122
|
+
/**
|
|
123
|
+
* The horizontal distance between the side of the editing root and the nearest side of the badge.
|
|
124
|
+
*
|
|
125
|
+
* @default 5
|
|
126
|
+
*/
|
|
127
|
+
horizontalOffset: number;
|
|
128
|
+
}
|
|
129
|
+
export {};
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
|
4
|
+
*/
|
|
5
|
+
import { Rect, DomEmitterMixin } from '@ckeditor/ckeditor5-utils';
|
|
6
|
+
import BalloonPanelView from '../panel/balloon/balloonpanelview.js';
|
|
7
|
+
import { throttle } from 'lodash-es';
|
|
8
|
+
// ⚠ Note, whenever changing the threshold, make sure to update the docs/support/managing-ckeditor-logo.md docs
|
|
9
|
+
// as this information is also mentioned there ⚠.
|
|
10
|
+
const NARROW_ROOT_HEIGHT_THRESHOLD = 50;
|
|
11
|
+
const NARROW_ROOT_WIDTH_THRESHOLD = 350;
|
|
12
|
+
/**
|
|
13
|
+
* A helper that enables the badge feature in the editor and renders a custom view next to the bottom of the editable element
|
|
14
|
+
* (editor root, source editing area, etc.) when the editor is focused.
|
|
15
|
+
*
|
|
16
|
+
* @private
|
|
17
|
+
*/
|
|
18
|
+
export default class Badge extends /* #__PURE__ */ DomEmitterMixin() {
|
|
19
|
+
/**
|
|
20
|
+
* Creates a badge for a given editor. The feature is initialized on Editor#ready
|
|
21
|
+
* event.
|
|
22
|
+
*/
|
|
23
|
+
constructor(editor, options = {}) {
|
|
24
|
+
super();
|
|
25
|
+
/**
|
|
26
|
+
* A reference to the balloon panel hosting and positioning the badge content.
|
|
27
|
+
*/
|
|
28
|
+
this._balloonView = null;
|
|
29
|
+
/**
|
|
30
|
+
* A throttled version of the {@link #_showBalloon} method meant for frequent use to avoid performance loss.
|
|
31
|
+
*/
|
|
32
|
+
this._showBalloonThrottled = throttle(() => this._showBalloon(), 50, { leading: true });
|
|
33
|
+
/**
|
|
34
|
+
* A reference to the last editable element (root, source editing area, etc.) focused by the user.
|
|
35
|
+
* Since the focus can move to other focusable elements in the UI, this reference allows positioning the balloon over the
|
|
36
|
+
* right element whether the user is typing or using the UI.
|
|
37
|
+
*/
|
|
38
|
+
this._lastFocusedEditableElement = null;
|
|
39
|
+
this.editor = editor;
|
|
40
|
+
this._balloonClass = options.balloonClass;
|
|
41
|
+
editor.on('ready', () => this._handleEditorReady());
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Destroys the badge along with its view.
|
|
45
|
+
*/
|
|
46
|
+
destroy() {
|
|
47
|
+
const balloon = this._balloonView;
|
|
48
|
+
if (balloon) {
|
|
49
|
+
// Balloon gets destroyed by the body collection.
|
|
50
|
+
// The badge view gets destroyed by the balloon.
|
|
51
|
+
balloon.unpin();
|
|
52
|
+
this._balloonView = null;
|
|
53
|
+
}
|
|
54
|
+
this._showBalloonThrottled.cancel();
|
|
55
|
+
this.stopListening();
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Enables badge label once the editor (ui) is ready.
|
|
59
|
+
*/
|
|
60
|
+
_handleEditorReady() {
|
|
61
|
+
const editor = this.editor;
|
|
62
|
+
if (!this._isEnabled()) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
// No view means no body collection to append the badge balloon to.
|
|
66
|
+
if (!editor.ui.view) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
editor.ui.focusTracker.on('change:isFocused', (evt, data, isFocused) => {
|
|
70
|
+
this._updateLastFocusedEditableElement();
|
|
71
|
+
if (isFocused) {
|
|
72
|
+
this._showBalloon();
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
this._hideBalloon();
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
editor.ui.focusTracker.on('change:focusedElement', (evt, data, focusedElement) => {
|
|
79
|
+
this._updateLastFocusedEditableElement();
|
|
80
|
+
if (focusedElement) {
|
|
81
|
+
this._showBalloon();
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
editor.ui.on('update', () => {
|
|
85
|
+
this._showBalloonThrottled();
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Returns normalized configuration for the badge.
|
|
90
|
+
*/
|
|
91
|
+
_getNormalizedConfig() {
|
|
92
|
+
return {
|
|
93
|
+
side: this.editor.locale.contentLanguageDirection === 'ltr' ? 'right' : 'left',
|
|
94
|
+
position: 'border',
|
|
95
|
+
verticalOffset: 0,
|
|
96
|
+
horizontalOffset: 5
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Attempts to display the balloon with the badge view.
|
|
101
|
+
*/
|
|
102
|
+
_showBalloon() {
|
|
103
|
+
const attachOptions = this._getBalloonAttachOptions();
|
|
104
|
+
if (!attachOptions) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
if (!this._balloonView) {
|
|
108
|
+
this._balloonView = this._createBalloonView();
|
|
109
|
+
}
|
|
110
|
+
this._balloonView.pin(attachOptions);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Hides the badge balloon if already visible.
|
|
114
|
+
*/
|
|
115
|
+
_hideBalloon() {
|
|
116
|
+
if (this._balloonView) {
|
|
117
|
+
this._balloonView.unpin();
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Creates an instance of the {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView balloon panel}
|
|
122
|
+
* with the badge view inside ready for positioning.
|
|
123
|
+
*/
|
|
124
|
+
_createBalloonView() {
|
|
125
|
+
const editor = this.editor;
|
|
126
|
+
const balloon = new BalloonPanelView();
|
|
127
|
+
const view = this._createBadgeContent();
|
|
128
|
+
balloon.content.add(view);
|
|
129
|
+
if (this._balloonClass) {
|
|
130
|
+
balloon.class = this._balloonClass;
|
|
131
|
+
}
|
|
132
|
+
editor.ui.view.body.add(balloon);
|
|
133
|
+
return balloon;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Returns the options for attaching the balloon to the focused editable element.
|
|
137
|
+
*/
|
|
138
|
+
_getBalloonAttachOptions() {
|
|
139
|
+
if (!this._lastFocusedEditableElement) {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
const badgeConfig = this._getNormalizedConfig();
|
|
143
|
+
const positioningFunction = badgeConfig.side === 'right' ?
|
|
144
|
+
getLowerRightCornerPosition(this._lastFocusedEditableElement, badgeConfig) :
|
|
145
|
+
getLowerLeftCornerPosition(this._lastFocusedEditableElement, badgeConfig);
|
|
146
|
+
return {
|
|
147
|
+
target: this._lastFocusedEditableElement,
|
|
148
|
+
positions: [positioningFunction]
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Updates the {@link #_lastFocusedEditableElement} based on the state of the global focus tracker.
|
|
153
|
+
*/
|
|
154
|
+
_updateLastFocusedEditableElement() {
|
|
155
|
+
const editor = this.editor;
|
|
156
|
+
const isFocused = editor.ui.focusTracker.isFocused;
|
|
157
|
+
const focusedElement = editor.ui.focusTracker.focusedElement;
|
|
158
|
+
if (!isFocused || !focusedElement) {
|
|
159
|
+
this._lastFocusedEditableElement = null;
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const editableEditorElements = Array.from(editor.ui.getEditableElementsNames()).map(name => {
|
|
163
|
+
return editor.ui.getEditableElement(name);
|
|
164
|
+
});
|
|
165
|
+
if (editableEditorElements.includes(focusedElement)) {
|
|
166
|
+
this._lastFocusedEditableElement = focusedElement;
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
// If it's none of the editable element, then the focus is somewhere in the UI. Let's display the badge
|
|
170
|
+
// over the first element then.
|
|
171
|
+
this._lastFocusedEditableElement = editableEditorElements[0];
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
function getLowerRightCornerPosition(focusedEditableElement, config) {
|
|
176
|
+
return getLowerCornerPosition(focusedEditableElement, config, (rootRect, balloonRect) => {
|
|
177
|
+
return rootRect.left + rootRect.width - balloonRect.width - config.horizontalOffset;
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
function getLowerLeftCornerPosition(focusedEditableElement, config) {
|
|
181
|
+
return getLowerCornerPosition(focusedEditableElement, config, rootRect => rootRect.left + config.horizontalOffset);
|
|
182
|
+
}
|
|
183
|
+
function getLowerCornerPosition(focusedEditableElement, config, getBalloonLeft) {
|
|
184
|
+
return (visibleEditableElementRect, balloonRect) => {
|
|
185
|
+
const editableElementRect = new Rect(focusedEditableElement);
|
|
186
|
+
if (editableElementRect.width < NARROW_ROOT_WIDTH_THRESHOLD || editableElementRect.height < NARROW_ROOT_HEIGHT_THRESHOLD) {
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
let balloonTop;
|
|
190
|
+
if (config.position === 'inside') {
|
|
191
|
+
balloonTop = editableElementRect.bottom - balloonRect.height;
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
balloonTop = editableElementRect.bottom - balloonRect.height / 2;
|
|
195
|
+
}
|
|
196
|
+
balloonTop -= config.verticalOffset;
|
|
197
|
+
const balloonLeft = getBalloonLeft(editableElementRect, balloonRect);
|
|
198
|
+
// Clone the editable element rect and place it where the balloon would be placed.
|
|
199
|
+
// This will allow getVisible() to work from editable element's perspective (rect source).
|
|
200
|
+
// and yield a result as if the balloon was on the same (scrollable) layer as the editable element.
|
|
201
|
+
const newBalloonPositionRect = visibleEditableElementRect
|
|
202
|
+
.clone()
|
|
203
|
+
.moveTo(balloonLeft, balloonTop)
|
|
204
|
+
.getIntersection(balloonRect.clone().moveTo(balloonLeft, balloonTop));
|
|
205
|
+
const newBalloonPositionVisibleRect = newBalloonPositionRect.getVisible();
|
|
206
|
+
if (!newBalloonPositionVisibleRect || newBalloonPositionVisibleRect.getArea() < balloonRect.getArea()) {
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
return {
|
|
210
|
+
top: balloonTop,
|
|
211
|
+
left: balloonLeft,
|
|
212
|
+
name: `position_${config.position}-side_${config.side}`,
|
|
213
|
+
config: {
|
|
214
|
+
withArrow: false
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
};
|
|
218
|
+
}
|
package/src/dialog/dialogview.js
CHANGED
|
@@ -126,8 +126,12 @@ class DialogView extends /* #__PURE__ */ DraggableViewMixin(View) {
|
|
|
126
126
|
render() {
|
|
127
127
|
super.render();
|
|
128
128
|
this.keystrokes.set('Esc', (data, cancel) => {
|
|
129
|
-
|
|
130
|
-
|
|
129
|
+
// Do not react to the Esc key if the event has already been handled and defaultPrevented
|
|
130
|
+
// by some logic of the dialog guest (child) view (https://github.com/ckeditor/ckeditor5/issues/17343).
|
|
131
|
+
if (!data.defaultPrevented) {
|
|
132
|
+
this.fire('close', { source: 'escKeyPress' });
|
|
133
|
+
cancel();
|
|
134
|
+
}
|
|
131
135
|
});
|
|
132
136
|
// Support for dragging the modal.
|
|
133
137
|
this.on('drag', (evt, { deltaX, deltaY }) => {
|
|
@@ -189,6 +189,12 @@ export default class DropdownView extends View<HTMLDivElement> {
|
|
|
189
189
|
* utility considering the direction of the language the UI of the editor is displayed in.
|
|
190
190
|
*/
|
|
191
191
|
private get _panelPositions();
|
|
192
|
+
/**
|
|
193
|
+
* Returns the default position of the dropdown panel based on the direction of the UI language.
|
|
194
|
+
* It is used when the {@link #panelPosition} is set to `'auto'` and the panel has not found a
|
|
195
|
+
* suitable position to fit into the viewport.
|
|
196
|
+
*/
|
|
197
|
+
private get _defaultPanelPositionName();
|
|
192
198
|
/**
|
|
193
199
|
* A set of positioning functions used by the dropdown view to determine
|
|
194
200
|
* the optimal position (i.e. fitting into the browser viewport) of its
|
|
@@ -134,7 +134,7 @@ class DropdownView extends View {
|
|
|
134
134
|
fitInViewport: true,
|
|
135
135
|
positions: this._panelPositions
|
|
136
136
|
});
|
|
137
|
-
this.panelView.position = (optimalPanelPosition ? optimalPanelPosition.name : this.
|
|
137
|
+
this.panelView.position = (optimalPanelPosition ? optimalPanelPosition.name : this._defaultPanelPositionName);
|
|
138
138
|
}
|
|
139
139
|
else {
|
|
140
140
|
this.panelView.position = this.panelPosition;
|
|
@@ -192,6 +192,14 @@ class DropdownView extends View {
|
|
|
192
192
|
];
|
|
193
193
|
}
|
|
194
194
|
}
|
|
195
|
+
/**
|
|
196
|
+
* Returns the default position of the dropdown panel based on the direction of the UI language.
|
|
197
|
+
* It is used when the {@link #panelPosition} is set to `'auto'` and the panel has not found a
|
|
198
|
+
* suitable position to fit into the viewport.
|
|
199
|
+
*/
|
|
200
|
+
get _defaultPanelPositionName() {
|
|
201
|
+
return this.locale.uiLanguageDirection === 'rtl' ? 'sw' : 'se';
|
|
202
|
+
}
|
|
195
203
|
}
|
|
196
204
|
/**
|
|
197
205
|
* A set of positioning functions used by the dropdown view to determine
|
|
@@ -6,20 +6,51 @@ import ViewCollection from '../viewcollection.js';
|
|
|
6
6
|
import type View from '../view.js';
|
|
7
7
|
import { type Locale } from '@ckeditor/ckeditor5-utils';
|
|
8
8
|
/**
|
|
9
|
-
* This is a special {@link module:ui/viewcollection~ViewCollection} dedicated to elements that are detached
|
|
10
|
-
*
|
|
9
|
+
* This is a special {@link module:ui/viewcollection~ViewCollection} dedicated to elements that are detached from the DOM structure of
|
|
10
|
+
* the editor, like floating panels, floating toolbars, dialogs, etc.
|
|
11
11
|
*
|
|
12
|
-
* The body collection is available
|
|
12
|
+
* The body collection is available under the {@link module:ui/editorui/editoruiview~EditorUIView#body `editor.ui.view.body`} property.
|
|
13
13
|
* Any plugin can add a {@link module:ui/view~View view} to this collection.
|
|
14
|
-
* These views will render in a container placed directly in the `<body>` element.
|
|
15
|
-
* The editor will detach and destroy this collection when the editor will be {@link module:core/editor/editor~Editor#destroy destroyed}.
|
|
16
14
|
*
|
|
17
|
-
*
|
|
15
|
+
* All views added to a body collection render in a dedicated DOM container (`<div class="ck ck-body ...">...</div>`). All body collection
|
|
16
|
+
* containers render in a common shared (`<div class="ck-body-wrapper">...</div>`) in the DOM to limit the pollution of
|
|
17
|
+
* the `<body>` element. The resulting DOM structure is as follows:
|
|
18
18
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
19
|
+
* ```html
|
|
20
|
+
* <body>
|
|
21
|
+
* <!-- Content of the webpage... -->
|
|
22
|
+
*
|
|
23
|
+
* <!-- The shared wrapper for all body collection containers. -->
|
|
24
|
+
* <div class="ck-body-wrapper">
|
|
25
|
+
* <!-- The container of the first body collection instance. -->
|
|
26
|
+
* <div class="ck ck-body ...">
|
|
27
|
+
* <!-- View elements belonging to the first body collection -->
|
|
28
|
+
* </div>
|
|
29
|
+
*
|
|
30
|
+
* <!-- The container of the second body collection instance. -->
|
|
31
|
+
* <div class="ck ck-body ...">...</div>
|
|
32
|
+
*
|
|
33
|
+
* <!-- More body collection containers for the rest of instances... -->
|
|
34
|
+
* </div>
|
|
35
|
+
* </body>
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* By default, the {@link module:ui/editorui/editoruiview~EditorUIView `editor.ui.view`} manages the life cycle of the
|
|
39
|
+
* {@link module:ui/editorui/editoruiview~EditorUIView#body `editor.ui.view.body`} collection, attaching and detaching it
|
|
40
|
+
* when the editor gets created or {@link module:core/editor/editor~Editor#destroy destroyed}.
|
|
41
|
+
*
|
|
42
|
+
* # Custom body collection instances
|
|
43
|
+
*
|
|
44
|
+
* Even though most editor instances come with a built-in body collection
|
|
45
|
+
* ({@link module:ui/editorui/editoruiview~EditorUIView#body `editor.ui.view.body`}), you can create your own instance of this
|
|
46
|
+
* class if you need to control their life cycle.
|
|
47
|
+
*
|
|
48
|
+
* The life cycle of a custom body collection must be handled manually by the developer using the dedicated API:
|
|
49
|
+
* * A body collection will render itself automatically in the DOM as soon as you call {@link ~BodyCollection#attachToDom}.
|
|
50
|
+
* * Calling {@link ~BodyCollection#detachFromDom} will remove the collection from the DOM.
|
|
51
|
+
*
|
|
52
|
+
* **Note**: The shared collection wrapper (`<div class="ck-body-wrapper">...</div>`) gets automatically removed from DOM when the
|
|
53
|
+
* last body collection is {@link ~BodyCollection#detachFromDom detached} and does not require any special handling.
|
|
23
54
|
*/
|
|
24
55
|
export default class BodyCollection extends ViewCollection {
|
|
25
56
|
/**
|
|
@@ -28,9 +59,13 @@ export default class BodyCollection extends ViewCollection {
|
|
|
28
59
|
*/
|
|
29
60
|
readonly locale: Locale;
|
|
30
61
|
/**
|
|
31
|
-
* The element holding elements of the body
|
|
62
|
+
* The element holding elements of the body collection.
|
|
32
63
|
*/
|
|
33
64
|
private _bodyCollectionContainer?;
|
|
65
|
+
/**
|
|
66
|
+
* The wrapper element that holds all of the {@link #_bodyCollectionContainer} elements.
|
|
67
|
+
*/
|
|
68
|
+
private static _bodyWrapper?;
|
|
34
69
|
/**
|
|
35
70
|
* Creates a new instance of the {@link module:ui/editorui/bodycollection~BodyCollection}.
|
|
36
71
|
*
|
|
@@ -39,7 +74,7 @@ export default class BodyCollection extends ViewCollection {
|
|
|
39
74
|
*/
|
|
40
75
|
constructor(locale: Locale, initialItems?: Iterable<View>);
|
|
41
76
|
/**
|
|
42
|
-
* The element holding elements of the body
|
|
77
|
+
* The element holding elements of the body collection.
|
|
43
78
|
*/
|
|
44
79
|
get bodyCollectionContainer(): HTMLElement | undefined;
|
|
45
80
|
/**
|
|
@@ -10,20 +10,51 @@ import Template from '../template.js';
|
|
|
10
10
|
import ViewCollection from '../viewcollection.js';
|
|
11
11
|
import { createElement } from '@ckeditor/ckeditor5-utils';
|
|
12
12
|
/**
|
|
13
|
-
* This is a special {@link module:ui/viewcollection~ViewCollection} dedicated to elements that are detached
|
|
14
|
-
*
|
|
13
|
+
* This is a special {@link module:ui/viewcollection~ViewCollection} dedicated to elements that are detached from the DOM structure of
|
|
14
|
+
* the editor, like floating panels, floating toolbars, dialogs, etc.
|
|
15
15
|
*
|
|
16
|
-
* The body collection is available
|
|
16
|
+
* The body collection is available under the {@link module:ui/editorui/editoruiview~EditorUIView#body `editor.ui.view.body`} property.
|
|
17
17
|
* Any plugin can add a {@link module:ui/view~View view} to this collection.
|
|
18
|
-
* These views will render in a container placed directly in the `<body>` element.
|
|
19
|
-
* The editor will detach and destroy this collection when the editor will be {@link module:core/editor/editor~Editor#destroy destroyed}.
|
|
20
18
|
*
|
|
21
|
-
*
|
|
19
|
+
* All views added to a body collection render in a dedicated DOM container (`<div class="ck ck-body ...">...</div>`). All body collection
|
|
20
|
+
* containers render in a common shared (`<div class="ck-body-wrapper">...</div>`) in the DOM to limit the pollution of
|
|
21
|
+
* the `<body>` element. The resulting DOM structure is as follows:
|
|
22
22
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
23
|
+
* ```html
|
|
24
|
+
* <body>
|
|
25
|
+
* <!-- Content of the webpage... -->
|
|
26
|
+
*
|
|
27
|
+
* <!-- The shared wrapper for all body collection containers. -->
|
|
28
|
+
* <div class="ck-body-wrapper">
|
|
29
|
+
* <!-- The container of the first body collection instance. -->
|
|
30
|
+
* <div class="ck ck-body ...">
|
|
31
|
+
* <!-- View elements belonging to the first body collection -->
|
|
32
|
+
* </div>
|
|
33
|
+
*
|
|
34
|
+
* <!-- The container of the second body collection instance. -->
|
|
35
|
+
* <div class="ck ck-body ...">...</div>
|
|
36
|
+
*
|
|
37
|
+
* <!-- More body collection containers for the rest of instances... -->
|
|
38
|
+
* </div>
|
|
39
|
+
* </body>
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* By default, the {@link module:ui/editorui/editoruiview~EditorUIView `editor.ui.view`} manages the life cycle of the
|
|
43
|
+
* {@link module:ui/editorui/editoruiview~EditorUIView#body `editor.ui.view.body`} collection, attaching and detaching it
|
|
44
|
+
* when the editor gets created or {@link module:core/editor/editor~Editor#destroy destroyed}.
|
|
45
|
+
*
|
|
46
|
+
* # Custom body collection instances
|
|
47
|
+
*
|
|
48
|
+
* Even though most editor instances come with a built-in body collection
|
|
49
|
+
* ({@link module:ui/editorui/editoruiview~EditorUIView#body `editor.ui.view.body`}), you can create your own instance of this
|
|
50
|
+
* class if you need to control their life cycle.
|
|
51
|
+
*
|
|
52
|
+
* The life cycle of a custom body collection must be handled manually by the developer using the dedicated API:
|
|
53
|
+
* * A body collection will render itself automatically in the DOM as soon as you call {@link ~BodyCollection#attachToDom}.
|
|
54
|
+
* * Calling {@link ~BodyCollection#detachFromDom} will remove the collection from the DOM.
|
|
55
|
+
*
|
|
56
|
+
* **Note**: The shared collection wrapper (`<div class="ck-body-wrapper">...</div>`) gets automatically removed from DOM when the
|
|
57
|
+
* last body collection is {@link ~BodyCollection#detachFromDom detached} and does not require any special handling.
|
|
27
58
|
*/
|
|
28
59
|
export default class BodyCollection extends ViewCollection {
|
|
29
60
|
/**
|
|
@@ -37,7 +68,7 @@ export default class BodyCollection extends ViewCollection {
|
|
|
37
68
|
this.locale = locale;
|
|
38
69
|
}
|
|
39
70
|
/**
|
|
40
|
-
* The element holding elements of the body
|
|
71
|
+
* The element holding elements of the body collection.
|
|
41
72
|
*/
|
|
42
73
|
get bodyCollectionContainer() {
|
|
43
74
|
return this._bodyCollectionContainer;
|
|
@@ -61,12 +92,12 @@ export default class BodyCollection extends ViewCollection {
|
|
|
61
92
|
},
|
|
62
93
|
children: this
|
|
63
94
|
}).render();
|
|
64
|
-
|
|
65
|
-
if (!
|
|
66
|
-
|
|
67
|
-
document.body.appendChild(
|
|
95
|
+
// Create a shared wrapper if there were none or the previous one got disconnected from DOM.
|
|
96
|
+
if (!BodyCollection._bodyWrapper || !BodyCollection._bodyWrapper.isConnected) {
|
|
97
|
+
BodyCollection._bodyWrapper = createElement(document, 'div', { class: 'ck-body-wrapper' });
|
|
98
|
+
document.body.appendChild(BodyCollection._bodyWrapper);
|
|
68
99
|
}
|
|
69
|
-
|
|
100
|
+
BodyCollection._bodyWrapper.appendChild(this._bodyCollectionContainer);
|
|
70
101
|
}
|
|
71
102
|
/**
|
|
72
103
|
* Detaches the collection from the DOM structure. Use this method when you do not need to use the body collection
|
|
@@ -77,9 +108,9 @@ export default class BodyCollection extends ViewCollection {
|
|
|
77
108
|
if (this._bodyCollectionContainer) {
|
|
78
109
|
this._bodyCollectionContainer.remove();
|
|
79
110
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
111
|
+
if (BodyCollection._bodyWrapper && !BodyCollection._bodyWrapper.childElementCount) {
|
|
112
|
+
BodyCollection._bodyWrapper.remove();
|
|
113
|
+
delete BodyCollection._bodyWrapper;
|
|
83
114
|
}
|
|
84
115
|
}
|
|
85
116
|
}
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import ComponentFactory from '../componentfactory.js';
|
|
9
9
|
import TooltipManager from '../tooltipmanager.js';
|
|
10
10
|
import PoweredBy from './poweredby.js';
|
|
11
|
+
import EvaluationBadge from './evaluationbadge.js';
|
|
11
12
|
import AriaLiveAnnouncer from '../arialiveannouncer.js';
|
|
12
13
|
import type EditorUIView from './editoruiview.js';
|
|
13
14
|
import type ToolbarView from '../toolbar/toolbarview.js';
|
|
@@ -44,6 +45,10 @@ export default abstract class EditorUI extends /* #__PURE__ */ EditorUI_base {
|
|
|
44
45
|
* A helper that enables the "powered by" feature in the editor and renders a link to the project's webpage.
|
|
45
46
|
*/
|
|
46
47
|
readonly poweredBy: PoweredBy;
|
|
48
|
+
/**
|
|
49
|
+
* A helper that enables the "evaluation badge" feature in the editor.
|
|
50
|
+
*/
|
|
51
|
+
readonly evaluationBadge: EvaluationBadge;
|
|
47
52
|
/**
|
|
48
53
|
* A helper that manages the content of an `aria-live` regions used by editor features to announce status changes
|
|
49
54
|
* to screen readers.
|