@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.
Files changed (37) hide show
  1. package/README.md +13 -7
  2. package/dist/badge/badge.d.ts +133 -0
  3. package/dist/dropdown/dropdownview.d.ts +6 -0
  4. package/dist/editorui/bodycollection.d.ts +47 -12
  5. package/dist/editorui/editorui.d.ts +5 -0
  6. package/dist/editorui/evaluationbadge.d.ts +37 -0
  7. package/dist/editorui/poweredby.d.ts +12 -49
  8. package/dist/index-editor.css +52 -3
  9. package/dist/index.css +62 -3
  10. package/dist/index.css.map +1 -1
  11. package/dist/index.js +351 -144
  12. package/dist/index.js.map +1 -1
  13. package/dist/menubar/menubarmenupanelview.d.ts +1 -1
  14. package/dist/menubar/menubarmenuview.d.ts +5 -0
  15. package/dist/menubar/utils.d.ts +1 -0
  16. package/package.json +4 -4
  17. package/src/badge/badge.d.ts +129 -0
  18. package/src/badge/badge.js +218 -0
  19. package/src/dialog/dialogview.js +6 -2
  20. package/src/dropdown/dropdownview.d.ts +6 -0
  21. package/src/dropdown/dropdownview.js +9 -1
  22. package/src/editorui/bodycollection.d.ts +47 -12
  23. package/src/editorui/bodycollection.js +50 -19
  24. package/src/editorui/editorui.d.ts +5 -0
  25. package/src/editorui/editorui.js +3 -0
  26. package/src/editorui/evaluationbadge.d.ts +33 -0
  27. package/src/editorui/evaluationbadge.js +99 -0
  28. package/src/editorui/poweredby.d.ts +12 -49
  29. package/src/editorui/poweredby.js +36 -194
  30. package/src/menubar/menubarmenupanelview.d.ts +1 -1
  31. package/src/menubar/menubarmenuview.d.ts +5 -0
  32. package/src/menubar/menubarmenuview.js +23 -1
  33. package/src/menubar/utils.d.ts +1 -0
  34. package/src/menubar/utils.js +2 -0
  35. package/theme/globals/_evaluationbadge.css +54 -0
  36. package/theme/globals/_poweredby.css +15 -3
  37. package/theme/globals/globals.css +1 -0
@@ -9,6 +9,7 @@
9
9
  import ComponentFactory from '../componentfactory.js';
10
10
  import TooltipManager from '../tooltipmanager.js';
11
11
  import PoweredBy from './poweredby.js';
12
+ import EvaluationBadge from './evaluationbadge.js';
12
13
  import AriaLiveAnnouncer from '../arialiveannouncer.js';
13
14
  import { ObservableMixin, isVisible, FocusTracker } from '@ckeditor/ckeditor5-utils';
14
15
  import { normalizeMenuBarConfig } from '../menubar/utils.js';
@@ -52,6 +53,7 @@ export default class EditorUI extends /* #__PURE__ */ ObservableMixin() {
52
53
  this.focusTracker = new FocusTracker();
53
54
  this.tooltipManager = new TooltipManager(editor);
54
55
  this.poweredBy = new PoweredBy(editor);
56
+ this.evaluationBadge = new EvaluationBadge(editor);
55
57
  this.ariaLiveAnnouncer = new AriaLiveAnnouncer(editor);
56
58
  this.set('viewportOffset', this._readViewportOffsetFromConfig());
57
59
  this.once('ready', () => {
@@ -95,6 +97,7 @@ export default class EditorUI extends /* #__PURE__ */ ObservableMixin() {
95
97
  this.focusTracker.destroy();
96
98
  this.tooltipManager.destroy(this.editor);
97
99
  this.poweredBy.destroy();
100
+ this.evaluationBadge.destroy();
98
101
  // Clean–up the references to the CKEditor instance stored in the native editable DOM elements.
99
102
  for (const domElement of this._editableElementsMap.values()) {
100
103
  domElement.ckeditorInstance = null;
@@ -0,0 +1,33 @@
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/editorui/evaluationbadge
7
+ */
8
+ import type { Editor } from '@ckeditor/ckeditor5-core';
9
+ import View from '../view.js';
10
+ import Badge, { type BadgeConfig } from '../badge/badge.js';
11
+ /**
12
+ * A helper that enables the "evaluation badge" feature in the editor at the bottom of the editable element
13
+ * (editor root, source editing area, etc.) when the editor is focused.
14
+ *
15
+ * @private
16
+ */
17
+ export default class EvaluationBadge extends Badge {
18
+ private licenseTypeMessage;
19
+ constructor(editor: Editor);
20
+ /**
21
+ * Enables "evaluation badge" label.
22
+ */
23
+ protected _isEnabled(): boolean;
24
+ /**
25
+ * Creates the content of the "evaluation badge".
26
+ */
27
+ protected _createBadgeContent(): View<HTMLElement>;
28
+ /**
29
+ * Returns the normalized configuration for the "evaluation badge".
30
+ * It takes 'ui.poweredBy' configuration into account to determine the badge position and side.
31
+ */
32
+ protected _getNormalizedConfig(): BadgeConfig;
33
+ }
@@ -0,0 +1,99 @@
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 { parseBase64EncodedObject } from '@ckeditor/ckeditor5-utils';
6
+ import View from '../view.js';
7
+ import Badge from '../badge/badge.js';
8
+ /**
9
+ * A helper that enables the "evaluation badge" feature in the editor at the bottom of the editable element
10
+ * (editor root, source editing area, etc.) when the editor is focused.
11
+ *
12
+ * @private
13
+ */
14
+ export default class EvaluationBadge extends Badge {
15
+ constructor(editor) {
16
+ super(editor, { balloonClass: 'ck-evaluation-badge-balloon' });
17
+ this.licenseTypeMessage = {
18
+ evaluation: 'For evaluation purposes only',
19
+ trial: 'For evaluation purposes only',
20
+ development: 'For development purposes only'
21
+ };
22
+ }
23
+ /**
24
+ * Enables "evaluation badge" label.
25
+ */
26
+ _isEnabled() {
27
+ const editor = this.editor;
28
+ const licenseKey = editor.config.get('licenseKey');
29
+ const licenseType = getLicenseTypeFromLicenseKey(licenseKey);
30
+ return Boolean(licenseType && this.licenseTypeMessage[licenseType]);
31
+ }
32
+ /**
33
+ * Creates the content of the "evaluation badge".
34
+ */
35
+ _createBadgeContent() {
36
+ const licenseKey = this.editor.config.get('licenseKey');
37
+ const licenseType = getLicenseTypeFromLicenseKey(licenseKey);
38
+ return new EvaluationBadgeView(this.editor.locale, this.licenseTypeMessage[licenseType]);
39
+ }
40
+ /**
41
+ * Returns the normalized configuration for the "evaluation badge".
42
+ * It takes 'ui.poweredBy' configuration into account to determine the badge position and side.
43
+ */
44
+ _getNormalizedConfig() {
45
+ const badgeConfig = super._getNormalizedConfig();
46
+ const userConfig = this.editor.config.get('ui.poweredBy') || {};
47
+ const position = userConfig.position || badgeConfig.position;
48
+ const poweredBySide = userConfig.side || badgeConfig.side;
49
+ return {
50
+ position,
51
+ side: poweredBySide === 'left' ? 'right' : 'left',
52
+ verticalOffset: badgeConfig.verticalOffset,
53
+ horizontalOffset: badgeConfig.horizontalOffset
54
+ };
55
+ }
56
+ }
57
+ /**
58
+ * A view displaying the "evaluation badge".
59
+ */
60
+ class EvaluationBadgeView extends View {
61
+ /**
62
+ * Creates an instance of the "evaluation badge" view.
63
+ *
64
+ * @param locale The localization services instance.
65
+ * @param label The label text.
66
+ */
67
+ constructor(locale, label) {
68
+ super(locale);
69
+ this.setTemplate({
70
+ tag: 'div',
71
+ attributes: {
72
+ class: ['ck', 'ck-evaluation-badge'],
73
+ 'aria-hidden': true
74
+ },
75
+ children: [
76
+ {
77
+ tag: 'span',
78
+ attributes: {
79
+ class: ['ck', 'ck-evaluation-badge__label']
80
+ },
81
+ children: [label]
82
+ }
83
+ ]
84
+ });
85
+ }
86
+ }
87
+ /**
88
+ * Returns the license type based on the license key.
89
+ */
90
+ function getLicenseTypeFromLicenseKey(licenseKey) {
91
+ if (licenseKey == 'GPL') {
92
+ return 'GPL';
93
+ }
94
+ const licenseContent = parseBase64EncodedObject(licenseKey.split('.')[1]);
95
+ if (!licenseContent) {
96
+ return null;
97
+ }
98
+ return licenseContent.licenseType || 'production';
99
+ }
@@ -5,67 +5,30 @@
5
5
  /**
6
6
  * @module ui/editorui/poweredby
7
7
  */
8
- import type { Editor } from '@ckeditor/ckeditor5-core';
9
- declare const PoweredBy_base: {
10
- new (): import("@ckeditor/ckeditor5-utils").DomEmitter;
11
- prototype: import("@ckeditor/ckeditor5-utils").DomEmitter;
12
- };
8
+ import type { Editor, UiConfig } from '@ckeditor/ckeditor5-core';
9
+ import View from '../view.js';
10
+ import Badge from '../badge/badge.js';
11
+ type PoweredByConfig = Required<UiConfig>['poweredBy'];
13
12
  /**
14
13
  * A helper that enables the "powered by" feature in the editor and renders a link to the project's
15
14
  * webpage next to the bottom of the editable element (editor root, source editing area, etc.) when the editor is focused.
16
15
  *
17
16
  * @private
18
17
  */
19
- export default class PoweredBy extends /* #__PURE__ */ PoweredBy_base {
20
- /**
21
- * Editor instance the helper was created for.
22
- */
23
- private readonly editor;
24
- /**
25
- * A reference to the balloon panel hosting and positioning the "powered by" link and logo.
26
- */
27
- private _balloonView;
28
- /**
29
- * A throttled version of the {@link #_showBalloon} method meant for frequent use to avoid performance loss.
30
- */
31
- private _showBalloonThrottled;
32
- /**
33
- * A reference to the last editable element (root, source editing area, etc.) focused by the user.
34
- * Since the focus can move to other focusable elements in the UI, this reference allows positioning the balloon over the
35
- * right element whether the user is typing or using the UI.
36
- */
37
- private _lastFocusedEditableElement;
38
- /**
39
- * Creates a "powered by" helper for a given editor. The feature is initialized on Editor#ready
40
- * event.
41
- *
42
- * @param editor
43
- */
18
+ export default class PoweredBy extends Badge {
44
19
  constructor(editor: Editor);
45
20
  /**
46
- * Destroys the "powered by" helper along with its view.
47
- */
48
- destroy(): void;
49
- /**
50
- * Enables "powered by" label once the editor (ui) is ready.
51
- */
52
- private _handleEditorReady;
53
- /**
54
- * Creates an instance of the {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView balloon panel}
55
- * with the "powered by" view inside ready for positioning.
56
- */
57
- private _createBalloonView;
58
- /**
59
- * Attempts to display the balloon with the "powered by" view.
21
+ * Enables "powered by" label.
60
22
  */
61
- private _showBalloon;
23
+ protected _isEnabled(): boolean;
62
24
  /**
63
- * Hides the "powered by" balloon if already visible.
25
+ * Creates a "powered by" badge content.
64
26
  */
65
- private _hideBalloon;
27
+ protected _createBadgeContent(): View<HTMLElement>;
66
28
  /**
67
- * Updates the {@link #_lastFocusedEditableElement} based on the state of the global focus tracker.
29
+ * Returns the normalized configuration for the "powered by" badge.
30
+ * It takes the user configuration into account and falls back to the default one.
68
31
  */
69
- private _updateLastFocusedEditableElement;
32
+ protected _getNormalizedConfig(): Required<PoweredByConfig>;
70
33
  }
71
34
  export {};
@@ -2,18 +2,11 @@
2
2
  * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
4
  */
5
- import { DomEmitterMixin, Rect, verifyLicense } from '@ckeditor/ckeditor5-utils';
6
- import BalloonPanelView from '../panel/balloon/balloonpanelview.js';
7
- import IconView from '../icon/iconview.js';
5
+ import { parseBase64EncodedObject } from '@ckeditor/ckeditor5-utils';
8
6
  import View from '../view.js';
9
- import { throttle } from 'lodash-es';
7
+ import Badge from '../badge/badge.js';
8
+ import IconView from '../icon/iconview.js';
10
9
  import poweredByIcon from '../../theme/icons/project-logo.svg';
11
- const ICON_WIDTH = 53;
12
- const ICON_HEIGHT = 10;
13
- // ⚠ Note, whenever changing the threshold, make sure to update the docs/support/managing-ckeditor-logo.md docs
14
- // as this information is also mentioned there ⚠.
15
- const NARROW_ROOT_HEIGHT_THRESHOLD = 50;
16
- const NARROW_ROOT_WIDTH_THRESHOLD = 350;
17
10
  const DEFAULT_LABEL = 'Powered by';
18
11
  /**
19
12
  * A helper that enables the "powered by" feature in the editor and renders a link to the project's
@@ -21,129 +14,52 @@ const DEFAULT_LABEL = 'Powered by';
21
14
  *
22
15
  * @private
23
16
  */
24
- export default class PoweredBy extends /* #__PURE__ */ DomEmitterMixin() {
25
- /**
26
- * Creates a "powered by" helper for a given editor. The feature is initialized on Editor#ready
27
- * event.
28
- *
29
- * @param editor
30
- */
17
+ export default class PoweredBy extends Badge {
31
18
  constructor(editor) {
32
- super();
33
- this.editor = editor;
34
- this._balloonView = null;
35
- this._lastFocusedEditableElement = null;
36
- this._showBalloonThrottled = throttle(this._showBalloon.bind(this), 50, { leading: true });
37
- editor.on('ready', this._handleEditorReady.bind(this));
19
+ super(editor, { balloonClass: 'ck-powered-by-balloon' });
38
20
  }
39
21
  /**
40
- * Destroys the "powered by" helper along with its view.
22
+ * Enables "powered by" label.
41
23
  */
42
- destroy() {
43
- const balloon = this._balloonView;
44
- if (balloon) {
45
- // Balloon gets destroyed by the body collection.
46
- // The powered by view gets destroyed by the balloon.
47
- balloon.unpin();
48
- this._balloonView = null;
49
- }
50
- this._showBalloonThrottled.cancel();
51
- this.stopListening();
52
- }
53
- /**
54
- * Enables "powered by" label once the editor (ui) is ready.
55
- */
56
- _handleEditorReady() {
24
+ _isEnabled() {
57
25
  const editor = this.editor;
58
- const forceVisible = !!editor.config.get('ui.poweredBy.forceVisible');
59
- /* istanbul ignore next -- @preserve */
60
- if (!forceVisible && verifyLicense(editor.config.get('licenseKey')) === 'VALID') {
61
- return;
26
+ const forceVisible = editor.config.get('ui.poweredBy.forceVisible');
27
+ if (forceVisible) {
28
+ return true;
62
29
  }
63
- // No view means no body collection to append the powered by balloon to.
64
- if (!editor.ui.view) {
65
- return;
66
- }
67
- editor.ui.focusTracker.on('change:isFocused', (evt, data, isFocused) => {
68
- this._updateLastFocusedEditableElement();
69
- if (isFocused) {
70
- this._showBalloon();
71
- }
72
- else {
73
- this._hideBalloon();
74
- }
75
- });
76
- editor.ui.focusTracker.on('change:focusedElement', (evt, data, focusedElement) => {
77
- this._updateLastFocusedEditableElement();
78
- if (focusedElement) {
79
- this._showBalloon();
80
- }
81
- });
82
- editor.ui.on('update', () => {
83
- this._showBalloonThrottled();
84
- });
85
- }
86
- /**
87
- * Creates an instance of the {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView balloon panel}
88
- * with the "powered by" view inside ready for positioning.
89
- */
90
- _createBalloonView() {
91
- const editor = this.editor;
92
- const balloon = this._balloonView = new BalloonPanelView();
93
- const poweredByConfig = getNormalizedConfig(editor);
94
- const view = new PoweredByView(editor.locale, poweredByConfig.label);
95
- balloon.content.add(view);
96
- balloon.set({
97
- class: 'ck-powered-by-balloon'
98
- });
99
- editor.ui.view.body.add(balloon);
100
- this._balloonView = balloon;
101
- }
102
- /**
103
- * Attempts to display the balloon with the "powered by" view.
104
- */
105
- _showBalloon() {
106
- if (!this._lastFocusedEditableElement) {
107
- return;
30
+ const licenseKey = editor.config.get('licenseKey');
31
+ if (licenseKey == 'GPL') {
32
+ return true;
108
33
  }
109
- const attachOptions = getBalloonAttachOptions(this.editor, this._lastFocusedEditableElement);
110
- if (attachOptions) {
111
- if (!this._balloonView) {
112
- this._createBalloonView();
113
- }
114
- this._balloonView.pin(attachOptions);
34
+ const licenseContent = parseBase64EncodedObject(licenseKey.split('.')[1]);
35
+ if (!licenseContent) {
36
+ return true;
115
37
  }
38
+ return !licenseContent.whiteLabel;
116
39
  }
117
40
  /**
118
- * Hides the "powered by" balloon if already visible.
41
+ * Creates a "powered by" badge content.
119
42
  */
120
- _hideBalloon() {
121
- if (this._balloonView) {
122
- this._balloonView.unpin();
123
- }
43
+ _createBadgeContent() {
44
+ return new PoweredByView(this.editor.locale, this._getNormalizedConfig().label);
124
45
  }
125
46
  /**
126
- * Updates the {@link #_lastFocusedEditableElement} based on the state of the global focus tracker.
47
+ * Returns the normalized configuration for the "powered by" badge.
48
+ * It takes the user configuration into account and falls back to the default one.
127
49
  */
128
- _updateLastFocusedEditableElement() {
129
- const editor = this.editor;
130
- const isFocused = editor.ui.focusTracker.isFocused;
131
- const focusedElement = editor.ui.focusTracker.focusedElement;
132
- if (!isFocused || !focusedElement) {
133
- this._lastFocusedEditableElement = null;
134
- return;
135
- }
136
- const editableEditorElements = Array.from(editor.ui.getEditableElementsNames()).map(name => {
137
- return editor.ui.getEditableElement(name);
138
- });
139
- if (editableEditorElements.includes(focusedElement)) {
140
- this._lastFocusedEditableElement = focusedElement;
141
- }
142
- else {
143
- // If it's none of the editable element, then the focus is somewhere in the UI. Let's display powered by
144
- // over the first element then.
145
- this._lastFocusedEditableElement = editableEditorElements[0];
146
- }
50
+ _getNormalizedConfig() {
51
+ const badgeConfig = super._getNormalizedConfig();
52
+ const userConfig = this.editor.config.get('ui.poweredBy') || {};
53
+ const position = userConfig.position || badgeConfig.position;
54
+ const verticalOffset = position === 'inside' ? 5 : badgeConfig.verticalOffset;
55
+ return {
56
+ position,
57
+ side: userConfig.side || badgeConfig.side,
58
+ label: userConfig.label === undefined ? DEFAULT_LABEL : userConfig.label,
59
+ verticalOffset: userConfig.verticalOffset !== undefined ? userConfig.verticalOffset : verticalOffset,
60
+ horizontalOffset: userConfig.horizontalOffset !== undefined ? userConfig.horizontalOffset : badgeConfig.horizontalOffset,
61
+ forceVisible: !!userConfig.forceVisible
62
+ };
147
63
  }
148
64
  }
149
65
  /**
@@ -151,7 +67,7 @@ export default class PoweredBy extends /* #__PURE__ */ DomEmitterMixin() {
151
67
  */
152
68
  class PoweredByView extends View {
153
69
  /**
154
- * Created an instance of the "powered by" view.
70
+ * Creates an instance of the "powered by" view.
155
71
  *
156
72
  * @param locale The localization services instance.
157
73
  * @param label The label text.
@@ -164,14 +80,6 @@ class PoweredByView extends View {
164
80
  content: poweredByIcon,
165
81
  isColorInherited: false
166
82
  });
167
- iconView.extendTemplate({
168
- attributes: {
169
- style: {
170
- width: ICON_WIDTH + 'px',
171
- height: ICON_HEIGHT + 'px'
172
- }
173
- }
174
- });
175
83
  this.setTemplate({
176
84
  tag: 'div',
177
85
  attributes: {
@@ -207,69 +115,3 @@ class PoweredByView extends View {
207
115
  });
208
116
  }
209
117
  }
210
- function getBalloonAttachOptions(editor, focusedEditableElement) {
211
- const poweredByConfig = getNormalizedConfig(editor);
212
- const positioningFunction = poweredByConfig.side === 'right' ?
213
- getLowerRightCornerPosition(focusedEditableElement, poweredByConfig) :
214
- getLowerLeftCornerPosition(focusedEditableElement, poweredByConfig);
215
- return {
216
- target: focusedEditableElement,
217
- positions: [positioningFunction]
218
- };
219
- }
220
- function getLowerRightCornerPosition(focusedEditableElement, config) {
221
- return getLowerCornerPosition(focusedEditableElement, config, (rootRect, balloonRect) => {
222
- return rootRect.left + rootRect.width - balloonRect.width - config.horizontalOffset;
223
- });
224
- }
225
- function getLowerLeftCornerPosition(focusedEditableElement, config) {
226
- return getLowerCornerPosition(focusedEditableElement, config, rootRect => rootRect.left + config.horizontalOffset);
227
- }
228
- function getLowerCornerPosition(focusedEditableElement, config, getBalloonLeft) {
229
- return (visibleEditableElementRect, balloonRect) => {
230
- const editableElementRect = new Rect(focusedEditableElement);
231
- if (editableElementRect.width < NARROW_ROOT_WIDTH_THRESHOLD || editableElementRect.height < NARROW_ROOT_HEIGHT_THRESHOLD) {
232
- return null;
233
- }
234
- let balloonTop;
235
- if (config.position === 'inside') {
236
- balloonTop = editableElementRect.bottom - balloonRect.height;
237
- }
238
- else {
239
- balloonTop = editableElementRect.bottom - balloonRect.height / 2;
240
- }
241
- balloonTop -= config.verticalOffset;
242
- const balloonLeft = getBalloonLeft(editableElementRect, balloonRect);
243
- // Clone the editable element rect and place it where the balloon would be placed.
244
- // This will allow getVisible() to work from editable element's perspective (rect source).
245
- // and yield a result as if the balloon was on the same (scrollable) layer as the editable element.
246
- const newBalloonPositionRect = visibleEditableElementRect
247
- .clone()
248
- .moveTo(balloonLeft, balloonTop)
249
- .getIntersection(balloonRect.clone().moveTo(balloonLeft, balloonTop));
250
- const newBalloonPositionVisibleRect = newBalloonPositionRect.getVisible();
251
- if (!newBalloonPositionVisibleRect || newBalloonPositionVisibleRect.getArea() < balloonRect.getArea()) {
252
- return null;
253
- }
254
- return {
255
- top: balloonTop,
256
- left: balloonLeft,
257
- name: `position_${config.position}-side_${config.side}`,
258
- config: {
259
- withArrow: false
260
- }
261
- };
262
- };
263
- }
264
- function getNormalizedConfig(editor) {
265
- const userConfig = editor.config.get('ui.poweredBy');
266
- const position = userConfig && userConfig.position || 'border';
267
- return {
268
- position,
269
- label: DEFAULT_LABEL,
270
- verticalOffset: position === 'inside' ? 5 : 0,
271
- horizontalOffset: 5,
272
- side: editor.locale.contentLanguageDirection === 'ltr' ? 'right' : 'left',
273
- ...userConfig
274
- };
275
- }
@@ -50,4 +50,4 @@ export default class MenuBarMenuPanelView extends View implements FocusableView
50
50
  *
51
51
  * They are reflected as CSS class suffixes on the panel view element.
52
52
  */
53
- export type MenuBarMenuPanelPosition = 'se' | 'sw' | 'ne' | 'nw' | 'w' | 'e';
53
+ export type MenuBarMenuPanelPosition = 'se' | 'sw' | 'ne' | 'nw' | 'w' | 'ws' | 'e' | 'es';
@@ -100,6 +100,11 @@ export default class MenuBarMenuView extends View implements FocusableView {
100
100
  * the {@link module:ui/menubar/menubarview~MenuBarView menu bar} and the UI language direction.
101
101
  */
102
102
  get _panelPositions(): Array<PositioningFunction>;
103
+ /**
104
+ * The default position of the panel when the menu is opened.
105
+ * It is used when the optimal position cannot be calculated.
106
+ */
107
+ private get _defaultMenuPositionName();
103
108
  /**
104
109
  * A function used to calculate the optimal position for the dropdown panel.
105
110
  *
@@ -118,7 +118,7 @@ class MenuBarMenuView extends View {
118
118
  fitInViewport: true,
119
119
  positions: this._panelPositions
120
120
  });
121
- this.panelView.position = (optimalPanelPosition ? optimalPanelPosition.name : this._panelPositions[0].name);
121
+ this.panelView.position = (optimalPanelPosition ? optimalPanelPosition.name : this._defaultMenuPositionName);
122
122
  });
123
123
  }
124
124
  /**
@@ -150,6 +150,28 @@ class MenuBarMenuView extends View {
150
150
  }
151
151
  }
152
152
  }
153
+ /**
154
+ * The default position of the panel when the menu is opened.
155
+ * It is used when the optimal position cannot be calculated.
156
+ */
157
+ get _defaultMenuPositionName() {
158
+ if (this.locale.uiLanguageDirection === 'ltr') {
159
+ if (this.parentMenuView) {
160
+ return 'es';
161
+ }
162
+ else {
163
+ return 'se';
164
+ }
165
+ }
166
+ else {
167
+ if (this.parentMenuView) {
168
+ return 'ws';
169
+ }
170
+ else {
171
+ return 'sw';
172
+ }
173
+ }
174
+ }
153
175
  }
154
176
  /**
155
177
  * A function used to calculate the optimal position for the dropdown panel.
@@ -268,6 +268,7 @@ export declare const MenuBarMenuViewPanelPositioningFunctions: Record<string, Po
268
268
  * groupId: 'insertInline',
269
269
  * items: [
270
270
  * 'menuBar:link',
271
+ * 'menuBar:bookmark',
271
272
  * 'menuBar:comment',
272
273
  * 'menuBar:insertMergeField'
273
274
  * ]
@@ -496,6 +496,7 @@ export const MenuBarMenuViewPanelPositioningFunctions = {
496
496
  * groupId: 'insertInline',
497
497
  * items: [
498
498
  * 'menuBar:link',
499
+ * 'menuBar:bookmark',
499
500
  * 'menuBar:comment',
500
501
  * 'menuBar:insertMergeField'
501
502
  * ]
@@ -753,6 +754,7 @@ export const DefaultMenuBarItems = [
753
754
  groupId: 'insertInline',
754
755
  items: [
755
756
  'menuBar:link',
757
+ 'menuBar:bookmark',
756
758
  'menuBar:comment',
757
759
  'menuBar:insertMergeField'
758
760
  ]
@@ -0,0 +1,54 @@
1
+ /*
2
+ * 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
+ :root {
7
+ /* where 7.5(px) is the font size of the evaluation badge label and 13(px) is the base font size. */
8
+ --ck-evaluation-badge-font-size: calc(var(--ck-font-size-base) * 7.5 / 13);
9
+ /* where 7.5(px) is the line height of the evaluation badge label and 13(px) is the base font size. */
10
+ --ck-evaluation-badge-line-height: calc(var(--ck-font-size-base) * 7.5 / 13);
11
+ /* where -0.2(px) is the letter spacing of the evaluation badge label and 13(px) is the base font size. */
12
+ --ck-evaluation-badge-letter-spacing: calc(var(--ck-font-size-base) * -0.2 / 13);
13
+ --ck-evaluation-badge-padding-vertical: 2px;
14
+ --ck-evaluation-badge-padding-horizontal: 4px;
15
+ --ck-evaluation-badge-text-color: hsl(0, 0%, 31%);
16
+ --ck-evaluation-badge-border-radius: var(--ck-border-radius);
17
+ --ck-evaluation-badge-background: hsl(0, 0%, 100%);
18
+ --ck-evaluation-badge-border-color: var(--ck-color-focus-border);
19
+ }
20
+
21
+ .ck.ck-balloon-panel.ck-evaluation-badge-balloon {
22
+ --ck-border-radius: var(--ck-evaluation-badge-border-radius);
23
+
24
+ box-shadow: none;
25
+ background: var(--ck-evaluation-badge-background);
26
+ min-height: unset;
27
+ z-index: calc( var(--ck-z-panel) - 1 );
28
+
29
+ & .ck.ck-evaluation-badge {
30
+ line-height: var(--ck-evaluation-badge-line-height);
31
+ padding: var(--ck-evaluation-badge-padding-vertical) var(--ck-evaluation-badge-padding-horizontal);
32
+
33
+ & .ck-evaluation-badge__label {
34
+ display: block;
35
+ padding: 0 2px;
36
+ font-size: var(--ck-evaluation-badge-font-size);
37
+ letter-spacing: var(--ck-evaluation-badge-letter-spacing);
38
+ font-weight: bold;
39
+ line-height: normal;
40
+ text-transform: uppercase;
41
+ color: var(--ck-evaluation-badge-text-color);
42
+ }
43
+ }
44
+
45
+ &[class*="position_inside"] {
46
+ border-color: transparent;
47
+ }
48
+
49
+ &[class*="position_border"] {
50
+ border: var(--ck-focus-ring);
51
+ border-color: var(--ck-evaluation-badge-border-color);
52
+ }
53
+ }
54
+