@ckeditor/ckeditor5-ui 45.0.0-alpha.9 → 45.1.0-alpha.0
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/LICENSE.md +4 -0
- package/dist/index.js +244 -103
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
- package/src/colorselector/colorgridsfragmentview.d.ts +9 -8
- package/src/colorselector/colorgridsfragmentview.js +9 -8
- package/src/colorselector/colorpickerfragmentview.d.ts +5 -4
- package/src/colorselector/colorpickerfragmentview.js +5 -4
- package/src/colorselector/colorselectorview.d.ts +8 -7
- package/src/colorselector/colorselectorview.js +9 -8
- package/src/componentfactory.js +1 -1
- package/src/dropdown/dropdownpanelview.js +2 -2
- package/src/dropdown/utils.d.ts +0 -2
- package/src/dropdown/utils.js +97 -20
- package/src/editorui/editorui.d.ts +29 -8
- package/src/editorui/editorui.js +56 -3
- package/src/menubar/menubarview.js +2 -2
- package/src/menubar/utils.js +7 -7
- package/src/panel/balloon/balloonpanelview.js +16 -8
- package/src/panel/balloon/contextualballoon.js +4 -1
- package/src/panel/sticky/stickypanelview.d.ts +0 -4
- package/src/panel/sticky/stickypanelview.js +35 -29
- package/src/textarea/textareaview.js +3 -3
- package/src/toolbar/toolbarview.d.ts +1 -1
- package/src/toolbar/toolbarview.js +1 -1
- package/src/tooltipmanager.d.ts +2 -0
- package/src/tooltipmanager.js +2 -0
- package/src/viewcollection.d.ts +1 -1
- package/src/viewcollection.js +1 -1
package/LICENSE.md
CHANGED
@@ -18,7 +18,11 @@ Where not otherwise indicated, all CKEditor content is authored by CKSource engi
|
|
18
18
|
|
19
19
|
The following libraries are included in CKEditor under the [MIT license](https://opensource.org/licenses/MIT):
|
20
20
|
|
21
|
+
* @types/color-convert - Copyright (c) DefinitelyTyped.
|
21
22
|
* es-toolkit - Copyright (c) 2024 Viva Republica, Inc.
|
23
|
+
* color-convert - Copyright (c) 2011–2016 Heather Arthur <fayearthur@gmail.com>, copyright (c) 2016–2021 Josh Junon <josh@junon.me>.
|
24
|
+
* color-parse - Copyright (c) 2015 Dmitry Ivanov.
|
25
|
+
* vanilla-colorful - Copyright (c) 2020 Serhii Kulykov <iamkulykov@gmail.com>.
|
22
26
|
|
23
27
|
Trademarks
|
24
28
|
----------
|
package/dist/index.js
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
* @license Copyright (c) 2003-2025, 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 { Collection, CKEditorError, EmitterMixin, isNode, toArray, DomEmitterMixin, ObservableMixin, isIterable, uid, env, delay, getEnvKeystrokeText, isVisible, global, KeystrokeHandler, FocusTracker, toUnit, Rect, createElement, ResizeObserver, getBorderWidths, logWarning, getOptimalPosition, isText, isRange, priorities, first, parseBase64EncodedObject, getAncestors } from '@ckeditor/ckeditor5-utils/dist/index.js';
|
5
|
+
import { Collection, CKEditorError, EmitterMixin, isNode, toArray, DomEmitterMixin, ObservableMixin, isIterable, uid, env, delay, getEnvKeystrokeText, isVisible, global, KeystrokeHandler, FocusTracker, toUnit, Rect, createElement, ResizeObserver, getBorderWidths, logWarning, getOptimalPosition, isText, isRange, priorities, first, parseBase64EncodedObject, getVisualViewportOffset, getAncestors } from '@ckeditor/ckeditor5-utils/dist/index.js';
|
6
6
|
import { cloneDeepWith, isObject, isElement, debounce, throttle, cloneDeep, extend, escapeRegExp, escape } from 'es-toolkit/compat';
|
7
7
|
import { Plugin, ContextPlugin } from '@ckeditor/ckeditor5-core/dist/index.js';
|
8
8
|
import { IconCancel, IconCheck, IconAccessibility, IconDropdownArrow, IconColorTileCheck, IconDragIndicator, IconPilcrow, IconThreeVerticalDots, IconText, IconPlus, IconParagraph, IconImportExport, IconBold, IconAlignLeft, IconColorPalette, IconEraser, IconProjectLogo, IconPreviousArrow, IconNextArrow, IconLoupe } from '@ckeditor/ckeditor5-icons/dist/index.js';
|
@@ -87,7 +87,7 @@ import { Observer } from '@ckeditor/ckeditor5-engine/dist/index.js';
|
|
87
87
|
* {@link #remove removing} views in the collection synchronizes their
|
88
88
|
* {@link module:ui/view~View#element elements} in the parent element.
|
89
89
|
*
|
90
|
-
* @param
|
90
|
+
* @param elementOrDocFragment A new parent element or document fragment.
|
91
91
|
*/ setParent(elementOrDocFragment) {
|
92
92
|
this._parentElement = elementOrDocFragment;
|
93
93
|
// Take care of the initial collection items passed to the constructor.
|
@@ -5715,9 +5715,9 @@ function isInputElementEmpty(domElement) {
|
|
5715
5715
|
* The minimum number of rows is greater than the maximum number of rows.
|
5716
5716
|
*
|
5717
5717
|
* @error ui-textarea-view-min-rows-greater-than-max-rows
|
5718
|
-
* @param textareaView The misconfigured textarea view instance.
|
5719
|
-
* @param minRows The value of `minRows` property.
|
5720
|
-
* @param maxRows The value of `maxRows` property.
|
5718
|
+
* @param {module:ui/textarea/textareaview~TextareaView} textareaView The misconfigured textarea view instance.
|
5719
|
+
* @param {number} minRows The value of `minRows` property.
|
5720
|
+
* @param {number} maxRows The value of `maxRows` property.
|
5721
5721
|
*/ throw new CKEditorError('ui-textarea-view-min-rows-greater-than-max-rows', {
|
5722
5722
|
textareaView: this,
|
5723
5723
|
minRows: this.minRows,
|
@@ -5808,8 +5808,8 @@ function getTextareaElementClone(element, value) {
|
|
5808
5808
|
* provides the `focus()` method for the best user experience.
|
5809
5809
|
*
|
5810
5810
|
* @error ui-dropdown-panel-focus-child-missing-focus
|
5811
|
-
* @param childView
|
5812
|
-
* @param dropdownPanel
|
5811
|
+
* @param {module:ui/view~View} childView Child view.
|
5812
|
+
* @param {module:ui/dropdown/dropdownpanelview~DropdownPanelView} dropdownPanel A parent of a child.
|
5813
5813
|
*/ logWarning('ui-dropdown-panel-focus-child-missing-focus', {
|
5814
5814
|
childView: this.children.first,
|
5815
5815
|
dropdownPanel: this
|
@@ -7522,18 +7522,25 @@ const POSITION_OFF_SCREEN = {
|
|
7522
7522
|
}
|
7523
7523
|
}),
|
7524
7524
|
// ------- Sticky
|
7525
|
-
viewportStickyNorth: (targetRect, balloonRect, viewportRect
|
7526
|
-
|
7527
|
-
|
7525
|
+
viewportStickyNorth: (targetRect, balloonRect, viewportRect)=>{
|
7526
|
+
// Get the intersection of the viewport and the document body.
|
7527
|
+
const boundaryRect = new Rect(global.document.body).getIntersection(viewportRect.getVisible());
|
7528
|
+
if (!boundaryRect) {
|
7528
7529
|
return null;
|
7529
7530
|
}
|
7530
|
-
//
|
7531
|
-
|
7532
|
-
if
|
7531
|
+
// Get the visible intersection of the boundary and the document body.
|
7532
|
+
const visibleBoundaryRect = boundaryRect.getVisible();
|
7533
|
+
// Check if the target is in the boundary.
|
7534
|
+
if (!targetRect.getIntersection(visibleBoundaryRect)) {
|
7535
|
+
return null;
|
7536
|
+
}
|
7537
|
+
// Checks if there is enough space to put the balloon on the top or bottom of the target.
|
7538
|
+
// If not, makes the balloon sticky.
|
7539
|
+
if (!(visibleBoundaryRect.top - targetRect.top - stickyVerticalOffset < balloonRect.height && visibleBoundaryRect.bottom - targetRect.bottom < balloonRect.height)) {
|
7533
7540
|
return null;
|
7534
7541
|
}
|
7535
7542
|
return {
|
7536
|
-
top:
|
7543
|
+
top: visibleBoundaryRect.top + stickyVerticalOffset,
|
7537
7544
|
left: targetRect.left + targetRect.width / 2 - balloonRect.width / 2,
|
7538
7545
|
name: 'arrowless',
|
7539
7546
|
config: {
|
@@ -8821,7 +8828,7 @@ const NESTED_TOOLBAR_ICONS = /* #__PURE__ */ (()=>({
|
|
8821
8828
|
* ```
|
8822
8829
|
*
|
8823
8830
|
* @error toolbarview-item-unavailable
|
8824
|
-
* @param item The name of the component or nested toolbar definition.
|
8831
|
+
* @param {string} item The name of the component or nested toolbar definition.
|
8825
8832
|
*/ logWarning('toolbarview-item-unavailable', {
|
8826
8833
|
item
|
8827
8834
|
});
|
@@ -9544,8 +9551,6 @@ const NESTED_TOOLBAR_ICONS = /* #__PURE__ */ (()=>({
|
|
9544
9551
|
*
|
9545
9552
|
* @param locale The locale instance.
|
9546
9553
|
* @param ButtonClassOrInstance The dropdown button view class. Needs to implement the
|
9547
|
-
* @param behaviorOptions Attributes for the default behavior of the dropdown.
|
9548
|
-
*
|
9549
9554
|
* {@link module:ui/dropdown/button/dropdownbutton~DropdownButton} interface.
|
9550
9555
|
* @returns The dropdown view instance.
|
9551
9556
|
*/ function createDropdown(locale, ButtonClassOrInstance = DropdownButtonView) {
|
@@ -9844,7 +9849,7 @@ function addMenuToOpenDropdown(dropdownView, options) {
|
|
9844
9849
|
* experience.
|
9845
9850
|
*
|
9846
9851
|
* @error ui-dropdown-focus-child-on-open-child-missing-focus
|
9847
|
-
* @param {module:ui/view~View} view
|
9852
|
+
* @param {module:ui/view~View} view Child to focus.
|
9848
9853
|
*/ logWarning('ui-dropdown-focus-child-on-open-child-missing-focus', {
|
9849
9854
|
view: childToFocus
|
9850
9855
|
});
|
@@ -9975,25 +9980,7 @@ function addMenuToOpenDropdown(dropdownView, options) {
|
|
9975
9980
|
* @param definitions
|
9976
9981
|
* @param locale
|
9977
9982
|
*/ function bindViewCollectionItemsToDefinitions(dropdownView, listItems, definitions, locale) {
|
9978
|
-
|
9979
|
-
// to adjust the layout accordingly. It'd look weird if the items on the list were not aligned horizontally.
|
9980
|
-
//
|
9981
|
-
// Possible theoretical performance problem if many items are added one by one, as this will be called for each item.
|
9982
|
-
listItems.on('change', ()=>{
|
9983
|
-
// Filter-map. Check all items, leave only these that have buttons and return the buttons.
|
9984
|
-
const listItemButtons = [
|
9985
|
-
...listItems
|
9986
|
-
].reduce((acc, item)=>{
|
9987
|
-
if (item instanceof ListItemView && item.children.first instanceof ListItemButtonView) {
|
9988
|
-
acc.push(item.children.first);
|
9989
|
-
}
|
9990
|
-
return acc;
|
9991
|
-
}, []);
|
9992
|
-
const hasAnyCheckboxOnList = listItemButtons.some((button)=>button.isToggleable);
|
9993
|
-
listItemButtons.forEach((item)=>{
|
9994
|
-
item.hasCheckSpace = hasAnyCheckboxOnList;
|
9995
|
-
});
|
9996
|
-
});
|
9983
|
+
bindDropdownToggleableButtonsAlignment(listItems);
|
9997
9984
|
listItems.bindTo(definitions).using((def)=>{
|
9998
9985
|
if (def.type === 'separator') {
|
9999
9986
|
return new ListSeparatorView(locale);
|
@@ -10026,6 +10013,100 @@ function addMenuToOpenDropdown(dropdownView, options) {
|
|
10026
10013
|
return null;
|
10027
10014
|
});
|
10028
10015
|
}
|
10016
|
+
/**
|
10017
|
+
* Sets up alignment handling for toggleable buttons in a dropdown list.
|
10018
|
+
*
|
10019
|
+
* Buttons in dropdowns have reserved space for a check icon when they are toggleable.
|
10020
|
+
* When at least one button in the list is toggleable, all other buttons (even non-toggleable ones)
|
10021
|
+
* will have space on their left side to align with toggleable buttons.
|
10022
|
+
*
|
10023
|
+
* This function handles a special case where a new toggleable button is added (or removed) to a list
|
10024
|
+
* where previous buttons weren't toggleable. In that case, those previous buttons will
|
10025
|
+
* automatically allocate space to align with the new toggleable button.
|
10026
|
+
*
|
10027
|
+
* Example:
|
10028
|
+
* ```
|
10029
|
+
* Before adding toggleable button:
|
10030
|
+
* +----------------+
|
10031
|
+
* | Normal Button |
|
10032
|
+
* +----------------+
|
10033
|
+
* | Another Button |
|
10034
|
+
* +----------------+
|
10035
|
+
*
|
10036
|
+
* After adding toggleable button:
|
10037
|
+
* +-------------------+
|
10038
|
+
* | Normal Button |
|
10039
|
+
* +-------------------+
|
10040
|
+
* | Another Button |
|
10041
|
+
* +-------------------+
|
10042
|
+
* | ✓ Toggle Button |
|
10043
|
+
* +-------------------+
|
10044
|
+
* ```
|
10045
|
+
*
|
10046
|
+
* @param listItems Collection of list items to observe for toggleable buttons.
|
10047
|
+
*/ function bindDropdownToggleableButtonsAlignment(listItems) {
|
10048
|
+
// Keep track of how many toggleable buttons are in the list.
|
10049
|
+
let toggleableButtonsCount = 0;
|
10050
|
+
// Helper function that checks if a view item is a list item button.
|
10051
|
+
const pickListItemButtonIfPresent = (item)=>{
|
10052
|
+
// Check if the item is a ListItemView with a ListItemButtonView as its first child.
|
10053
|
+
if (!(item instanceof ListItemView) || !(item.children.first instanceof ListItemButtonView)) {
|
10054
|
+
return null;
|
10055
|
+
}
|
10056
|
+
return item.children.first;
|
10057
|
+
};
|
10058
|
+
// Helper function that checks if a view item is a toggleable button.
|
10059
|
+
// Returns the button if it's toggleable - otherwise, returns null.
|
10060
|
+
const pickListItemToggleableButtonIfPresent = (item)=>{
|
10061
|
+
const listItemButtonView = pickListItemButtonIfPresent(item);
|
10062
|
+
// Only return buttons that are configured as toggleable.
|
10063
|
+
if (!listItemButtonView || !listItemButtonView.isToggleable) {
|
10064
|
+
return null;
|
10065
|
+
}
|
10066
|
+
return listItemButtonView;
|
10067
|
+
};
|
10068
|
+
// Updates all buttons in the list to either allocate space for check marks or not.
|
10069
|
+
// This ensures all buttons are properly aligned regardless of their toggleable state.
|
10070
|
+
const updateAllButtonsCheckSpace = (hasSpace)=>{
|
10071
|
+
for (const listItem of listItems){
|
10072
|
+
const listItemButton = pickListItemButtonIfPresent(listItem);
|
10073
|
+
if (listItemButton) {
|
10074
|
+
listItemButton.hasCheckSpace = hasSpace;
|
10075
|
+
}
|
10076
|
+
}
|
10077
|
+
};
|
10078
|
+
// Listen for changes in the list items collection.
|
10079
|
+
listItems.on('change', (evt, data)=>{
|
10080
|
+
// Remember the current state - whether we have any toggleable buttons.
|
10081
|
+
const prevToggleable = toggleableButtonsCount > 0;
|
10082
|
+
// Process removed items - decrease count for each toggleable button removed.
|
10083
|
+
for (const item of data.removed){
|
10084
|
+
if (pickListItemToggleableButtonIfPresent(item)) {
|
10085
|
+
toggleableButtonsCount--;
|
10086
|
+
}
|
10087
|
+
}
|
10088
|
+
// Process added items - increase count for each toggleable button added.
|
10089
|
+
for (const item of data.added){
|
10090
|
+
const button = pickListItemButtonIfPresent(item);
|
10091
|
+
if (!button) {
|
10092
|
+
continue;
|
10093
|
+
}
|
10094
|
+
if (button.isToggleable) {
|
10095
|
+
// Check if the button is toggleable and increase the count.
|
10096
|
+
toggleableButtonsCount++;
|
10097
|
+
}
|
10098
|
+
// Depending on the current state, set the check space for the button.
|
10099
|
+
button.hasCheckSpace = toggleableButtonsCount > 0;
|
10100
|
+
}
|
10101
|
+
// Check if the current state has changed.
|
10102
|
+
const currentToggleable = toggleableButtonsCount > 0;
|
10103
|
+
// Only update button alignment if we've crossed the threshold between
|
10104
|
+
// having no toggleable buttons and having at least one.
|
10105
|
+
if (prevToggleable !== currentToggleable) {
|
10106
|
+
updateAllButtonsCheckSpace(currentToggleable);
|
10107
|
+
}
|
10108
|
+
});
|
10109
|
+
}
|
10029
10110
|
|
10030
10111
|
/**
|
10031
10112
|
* A helper for creating labeled inputs.
|
@@ -10634,14 +10715,15 @@ class ColorPickerInputRowView extends View {
|
|
10634
10715
|
* Creates an instance of the view.
|
10635
10716
|
*
|
10636
10717
|
* @param locale The localization services instance.
|
10637
|
-
* @param
|
10638
|
-
* @param
|
10639
|
-
* @param
|
10640
|
-
* @param
|
10641
|
-
* @param
|
10642
|
-
* @param
|
10643
|
-
* @param
|
10644
|
-
* @param
|
10718
|
+
* @param options Constructor options.
|
10719
|
+
* @param options.colors An array with definitions of colors to be displayed in the table.
|
10720
|
+
* @param options.columns The number of columns in the color grid.
|
10721
|
+
* @param options.removeButtonLabel The label of the button responsible for removing the color.
|
10722
|
+
* @param options.colorPickerLabel The label of the button responsible for color picker appearing.
|
10723
|
+
* @param options.documentColorsLabel The label for the section with the document colors.
|
10724
|
+
* @param options.documentColorsCount The number of colors in the document colors section inside the color dropdown.
|
10725
|
+
* @param options.focusTracker Tracks information about the DOM focus in the list.
|
10726
|
+
* @param options.focusables A collection of views that can be focused in the view.
|
10645
10727
|
*/ constructor(locale, { colors, columns, removeButtonLabel, documentColorsLabel, documentColorsCount, colorPickerLabel, focusTracker, focusables }){
|
10646
10728
|
super(locale);
|
10647
10729
|
const bind = this.bindTemplate;
|
@@ -10927,10 +11009,11 @@ class ColorPickerInputRowView extends View {
|
|
10927
11009
|
* Creates an instance of the view.
|
10928
11010
|
*
|
10929
11011
|
* @param locale The localization services instance.
|
10930
|
-
* @param
|
10931
|
-
* @param
|
10932
|
-
* @param
|
10933
|
-
* @param
|
11012
|
+
* @param options Constructor options.
|
11013
|
+
* @param options.focusTracker Tracks information about the DOM focus in the list.
|
11014
|
+
* @param options.focusables A collection of views that can be focused in the view.
|
11015
|
+
* @param options.keystrokes An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}.
|
11016
|
+
* @param options.colorPickerViewConfig The configuration of color picker feature. If set to `false`, the color picker
|
10934
11017
|
* will not be rendered.
|
10935
11018
|
*/ constructor(locale, { focusTracker, focusables, keystrokes, colorPickerViewConfig }){
|
10936
11019
|
super(locale);
|
@@ -11186,13 +11269,14 @@ class ColorPickerInputRowView extends View {
|
|
11186
11269
|
* Creates a view to be inserted as a child of {@link module:ui/dropdown/dropdownview~DropdownView}.
|
11187
11270
|
*
|
11188
11271
|
* @param locale The localization services instance.
|
11189
|
-
* @param
|
11190
|
-
* @param
|
11191
|
-
* @param
|
11192
|
-
* @param
|
11193
|
-
* @param
|
11194
|
-
* @param
|
11195
|
-
* @param
|
11272
|
+
* @param options Constructor options.
|
11273
|
+
* @param options.colors An array with definitions of colors to be displayed in the table.
|
11274
|
+
* @param options.columns The number of columns in the color grid.
|
11275
|
+
* @param options.removeButtonLabel The label of the button responsible for removing the color.
|
11276
|
+
* @param options.colorPickerLabel The label of the button responsible for color picker appearing.
|
11277
|
+
* @param options.documentColorsLabel The label for the section with the document colors.
|
11278
|
+
* @param options.documentColorsCount The number of colors in the document colors section inside the color dropdown.
|
11279
|
+
* @param options.colorPickerViewConfig The configuration of color picker feature. If set to `false`, the color picker will be hidden.
|
11196
11280
|
*/ constructor(locale, { colors, columns, removeButtonLabel, documentColorsLabel, documentColorsCount, colorPickerLabel, colorPickerViewConfig }){
|
11197
11281
|
super(locale);
|
11198
11282
|
this.items = this.createCollection();
|
@@ -11234,7 +11318,7 @@ class ColorPickerInputRowView extends View {
|
|
11234
11318
|
this.colorPickerFragmentView.bind('isVisible').to(this, '_isColorPickerFragmentVisible');
|
11235
11319
|
/**
|
11236
11320
|
* This is kind of bindings. Unfortunately we could not use this.bind() method because the same property
|
11237
|
-
*
|
11321
|
+
* cannot be bound twice. So this is work around how to bind 'selectedColor' property between components.
|
11238
11322
|
*/ this.on('change:selectedColor', (evt, evtName, data)=>{
|
11239
11323
|
this.colorGridsFragmentView.set('selectedColor', data);
|
11240
11324
|
this.colorPickerFragmentView.set('selectedColor', data);
|
@@ -11444,7 +11528,7 @@ class ColorPickerInputRowView extends View {
|
|
11444
11528
|
* {@link module:ui/componentfactory~ComponentFactory#add added} to the factory.
|
11445
11529
|
*
|
11446
11530
|
* @error componentfactory-item-missing
|
11447
|
-
* @param name The name of the missing component.
|
11531
|
+
* @param {string} name The name of the missing component.
|
11448
11532
|
*/ throw new CKEditorError('componentfactory-item-missing', this, {
|
11449
11533
|
name
|
11450
11534
|
});
|
@@ -11801,6 +11885,8 @@ const BALLOON_CLASS = 'ck-tooltip';
|
|
11801
11885
|
/**
|
11802
11886
|
* Pins the tooltip to a specific DOM element.
|
11803
11887
|
*
|
11888
|
+
* @param targetDomElement Element to be pinned to.
|
11889
|
+
* @param options Options for the tooltip.
|
11804
11890
|
* @param options.text Text of the tooltip to display.
|
11805
11891
|
* @param options.position The position of the tooltip.
|
11806
11892
|
* @param options.cssClass Additional CSS class of the balloon with the tooltip.
|
@@ -13608,8 +13694,8 @@ const DefaultMenuBarItems = [
|
|
13608
13694
|
* {@link module:core/editor/editorconfig~EditorConfig#menuBar menu bar configuration}.
|
13609
13695
|
*
|
13610
13696
|
* @error menu-bar-item-could-not-be-removed
|
13611
|
-
* @param menuBarConfig The full configuration of the menu bar.
|
13612
|
-
* @param
|
13697
|
+
* @param {object} menuBarConfig The full configuration of the menu bar.
|
13698
|
+
* @param {object} addedItemConfig The name of the item that was not removed from the menu bar.
|
13613
13699
|
*/ logWarning('menu-bar-item-could-not-be-added', {
|
13614
13700
|
menuBarConfig: originalConfig,
|
13615
13701
|
addedItemConfig
|
@@ -13681,9 +13767,9 @@ const DefaultMenuBarItems = [
|
|
13681
13767
|
* menu bar item.
|
13682
13768
|
*
|
13683
13769
|
* @error menu-bar-item-unavailable
|
13684
|
-
* @param menuBarConfig The full configuration of the menu bar.
|
13685
|
-
* @param parentMenuConfig The config of the menu the unavailable component was defined in.
|
13686
|
-
* @param componentName The name of the unavailable component.
|
13770
|
+
* @param {object} menuBarConfig The full configuration of the menu bar.
|
13771
|
+
* @param {object} parentMenuConfig The config of the menu the unavailable component was defined in.
|
13772
|
+
* @param {string} componentName The name of the unavailable component.
|
13687
13773
|
*/ logWarning('menu-bar-item-unavailable', {
|
13688
13774
|
menuBarConfig: originalConfig,
|
13689
13775
|
parentMenuConfig: cloneDeep(menuDefinition),
|
@@ -13760,8 +13846,8 @@ function warnAboutEmptyMenu(originalConfig, emptyMenuConfig, isUsingDefaultConfi
|
|
13760
13846
|
* to account for the missing menu items.
|
13761
13847
|
*
|
13762
13848
|
* @error menu-bar-menu-empty
|
13763
|
-
* @param menuBarConfig The full configuration of the menu bar.
|
13764
|
-
* @param emptyMenuConfig The definition of the menu that has no child items.
|
13849
|
+
* @param {object} menuBarConfig The full configuration of the menu bar.
|
13850
|
+
* @param {object} emptyMenuConfig The definition of the menu that has no child items.
|
13765
13851
|
*/ logWarning('menu-bar-menu-empty', {
|
13766
13852
|
menuBarConfig: originalConfig,
|
13767
13853
|
emptyMenuConfig
|
@@ -13912,6 +13998,9 @@ function isMenuDefinition(definition) {
|
|
13912
13998
|
/**
|
13913
13999
|
* The last focused element to which focus should return on `Esc` press.
|
13914
14000
|
*/ _lastFocusedForeignElement = null;
|
14001
|
+
/**
|
14002
|
+
* The DOM emitter instance used for visual viewport watching.
|
14003
|
+
*/ _domEmitter;
|
13915
14004
|
/**
|
13916
14005
|
* Creates an instance of the editor UI class.
|
13917
14006
|
*
|
@@ -13926,7 +14015,7 @@ function isMenuDefinition(definition) {
|
|
13926
14015
|
this.poweredBy = new PoweredBy(editor);
|
13927
14016
|
this.evaluationBadge = new EvaluationBadge(editor);
|
13928
14017
|
this.ariaLiveAnnouncer = new AriaLiveAnnouncer(editor);
|
13929
|
-
this.
|
14018
|
+
this._initViewportOffset(this._readViewportOffsetFromConfig());
|
13930
14019
|
this.once('ready', ()=>{
|
13931
14020
|
this._bindBodyCollectionWithFocusTracker();
|
13932
14021
|
this.isReady = true;
|
@@ -13935,6 +14024,7 @@ function isMenuDefinition(definition) {
|
|
13935
14024
|
this.listenTo(editingView.document, 'layoutChanged', this.update.bind(this));
|
13936
14025
|
this.listenTo(editingView, 'scrollToTheSelection', this._handleScrollToTheSelection.bind(this));
|
13937
14026
|
this._initFocusTracking();
|
14027
|
+
this._initVisualViewportSupport();
|
13938
14028
|
}
|
13939
14029
|
/**
|
13940
14030
|
* The main (outermost) DOM element of the editor UI.
|
@@ -13973,6 +14063,9 @@ function isMenuDefinition(definition) {
|
|
13973
14063
|
}
|
13974
14064
|
this._editableElementsMap = new Map();
|
13975
14065
|
this._focusableToolbarDefinitions = [];
|
14066
|
+
if (this._domEmitter) {
|
14067
|
+
this._domEmitter.stopListening();
|
14068
|
+
}
|
13976
14069
|
}
|
13977
14070
|
/**
|
13978
14071
|
* Stores the native DOM editable element used by the editor under a unique name.
|
@@ -14109,7 +14202,7 @@ function isMenuDefinition(definition) {
|
|
14109
14202
|
* {@link module:ui/editorui/editorui~EditorUI#getEditableElement `getEditableElement()`} methods instead.
|
14110
14203
|
*
|
14111
14204
|
* @error editor-ui-deprecated-editable-elements
|
14112
|
-
* @param editorUI Editor UI instance the deprecated property belongs to.
|
14205
|
+
* @param {module:ui/editorui/editorui~EditorUI} editorUI Editor UI instance the deprecated property belongs to.
|
14113
14206
|
*/ console.warn('editor-ui-deprecated-editable-elements: ' + 'The EditorUI#_editableElements property has been deprecated and will be removed in the near future.', {
|
14114
14207
|
editorUI: this
|
14115
14208
|
});
|
@@ -14342,6 +14435,54 @@ function isMenuDefinition(definition) {
|
|
14342
14435
|
this.focusTracker.remove(view.element);
|
14343
14436
|
});
|
14344
14437
|
}
|
14438
|
+
/**
|
14439
|
+
* Set initial viewport offset and setup visualTop augmentation.
|
14440
|
+
*/ _initViewportOffset(viewportOffsetConfig) {
|
14441
|
+
// Augment the viewport offset set from outside the editor with the visualTop property.
|
14442
|
+
this.on('set:viewportOffset', (evt, name, value)=>{
|
14443
|
+
const visualTop = this._getVisualViewportTopOffset(value);
|
14444
|
+
// Update only if there is a change in a value, so we do not trigger
|
14445
|
+
// listeners to the viewportOffset observable.
|
14446
|
+
if (value.visualTop !== visualTop) {
|
14447
|
+
evt.return = {
|
14448
|
+
...value,
|
14449
|
+
visualTop
|
14450
|
+
};
|
14451
|
+
}
|
14452
|
+
});
|
14453
|
+
// Set the initial value after augmenting the setter.
|
14454
|
+
this.set('viewportOffset', viewportOffsetConfig);
|
14455
|
+
}
|
14456
|
+
/**
|
14457
|
+
* Listen to visual viewport changes and update the viewportOffset with the visualTop property
|
14458
|
+
* according to the visible part of it (visual viewport).
|
14459
|
+
*/ _initVisualViewportSupport() {
|
14460
|
+
if (!global.window.visualViewport) {
|
14461
|
+
return;
|
14462
|
+
}
|
14463
|
+
const updateViewport = ()=>{
|
14464
|
+
const visualTop = this._getVisualViewportTopOffset(this.viewportOffset);
|
14465
|
+
// Update only if there is a change in a value, so we do not trigger
|
14466
|
+
// listeners to the viewportOffset observable.
|
14467
|
+
if (this.viewportOffset.visualTop !== visualTop) {
|
14468
|
+
this.viewportOffset = {
|
14469
|
+
...this.viewportOffset,
|
14470
|
+
visualTop
|
14471
|
+
};
|
14472
|
+
}
|
14473
|
+
};
|
14474
|
+
// Listen to the changes in the visual viewport to adjust the visualTop of viewport offset.
|
14475
|
+
this._domEmitter = new (DomEmitterMixin())();
|
14476
|
+
this._domEmitter.listenTo(global.window.visualViewport, 'scroll', updateViewport);
|
14477
|
+
this._domEmitter.listenTo(global.window.visualViewport, 'resize', updateViewport);
|
14478
|
+
}
|
14479
|
+
/**
|
14480
|
+
* Calculate the viewport top offset according to the visible part of it (visual viewport).
|
14481
|
+
*/ _getVisualViewportTopOffset(viewportOffset) {
|
14482
|
+
const visualViewportOffsetTop = getVisualViewportOffset().top;
|
14483
|
+
const viewportTopOffset = viewportOffset.top || 0;
|
14484
|
+
return visualViewportOffsetTop > viewportTopOffset ? 0 : viewportTopOffset - visualViewportOffsetTop;
|
14485
|
+
}
|
14345
14486
|
}
|
14346
14487
|
/**
|
14347
14488
|
* Returns a number (weight) for a toolbar definition. Visible toolbars have a higher priority and so do
|
@@ -15233,7 +15374,10 @@ const toPx$4 = /* #__PURE__ */ toUnit('px');
|
|
15233
15374
|
}
|
15234
15375
|
// Don't modify the original options object.
|
15235
15376
|
position = Object.assign({}, position, {
|
15236
|
-
viewportOffsetConfig:
|
15377
|
+
viewportOffsetConfig: {
|
15378
|
+
...this.editor.ui.viewportOffset,
|
15379
|
+
top: this.editor.ui.viewportOffset.visualTop
|
15380
|
+
}
|
15237
15381
|
});
|
15238
15382
|
}
|
15239
15383
|
return position;
|
@@ -15660,7 +15804,7 @@ const toPx$3 = /* #__PURE__ */ toUnit('px');
|
|
15660
15804
|
this.listenTo(this, 'change:isActive', ()=>{
|
15661
15805
|
this.checkIfShouldBeSticky();
|
15662
15806
|
});
|
15663
|
-
if (
|
15807
|
+
if (global.window.visualViewport) {
|
15664
15808
|
this.listenTo(global.window.visualViewport, 'scroll', ()=>{
|
15665
15809
|
this.checkIfShouldBeSticky();
|
15666
15810
|
});
|
@@ -15673,24 +15817,20 @@ const toPx$3 = /* #__PURE__ */ toUnit('px');
|
|
15673
15817
|
* Analyzes the environment to decide whether the panel should be sticky or not.
|
15674
15818
|
* Then handles the positioning of the panel.
|
15675
15819
|
*/ checkIfShouldBeSticky() {
|
15820
|
+
// @if CK_DEBUG_STICKYPANEL // RectDrawer.clear();
|
15676
15821
|
if (!this.limiterElement || !this.isActive) {
|
15677
15822
|
this._unstick();
|
15678
15823
|
return;
|
15679
15824
|
}
|
15680
|
-
const { left: visualViewportOffsetLeft, top: visualViewportOffsetTop } = this._getVisualViewportOffset();
|
15681
15825
|
const limiterRect = new Rect(this.limiterElement);
|
15682
15826
|
let visibleLimiterRect = limiterRect.getVisible();
|
15683
15827
|
if (visibleLimiterRect) {
|
15684
15828
|
const windowRect = new Rect(global.window);
|
15685
|
-
|
15686
|
-
|
15687
|
-
// Adjust the viewport top offset to height visible in the visual viewport.
|
15688
|
-
viewportTopOffset = visualViewportOffsetTop > this.viewportTopOffset ? 0 : this.viewportTopOffset - visualViewportOffsetTop;
|
15689
|
-
}
|
15690
|
-
windowRect.top += viewportTopOffset;
|
15691
|
-
windowRect.height -= viewportTopOffset;
|
15829
|
+
windowRect.top += this.viewportTopOffset;
|
15830
|
+
windowRect.height -= this.viewportTopOffset;
|
15692
15831
|
visibleLimiterRect = visibleLimiterRect.getIntersection(windowRect);
|
15693
15832
|
}
|
15833
|
+
const { left: visualViewportOffsetLeft, top: visualViewportOffsetTop } = getVisualViewportOffset();
|
15694
15834
|
limiterRect.moveBy(visualViewportOffsetLeft, visualViewportOffsetTop);
|
15695
15835
|
if (visibleLimiterRect) {
|
15696
15836
|
visibleLimiterRect.moveBy(visualViewportOffsetLeft, visualViewportOffsetTop);
|
@@ -15699,20 +15839,29 @@ const toPx$3 = /* #__PURE__ */ toUnit('px');
|
|
15699
15839
|
// * the limiter's ancestors are intersecting with each other so that some of their rects are visible,
|
15700
15840
|
// * and the limiter's top edge is above the visible ancestors' top edge.
|
15701
15841
|
if (visibleLimiterRect && limiterRect.top < visibleLimiterRect.top) {
|
15702
|
-
const visibleLimiterTop = visibleLimiterRect.top;
|
15703
15842
|
// Check if there's a change the panel can be sticky to the bottom of the limiter.
|
15704
|
-
if (
|
15843
|
+
if (this._contentPanelRect.height + this.limiterBottomOffset > visibleLimiterRect.height) {
|
15705
15844
|
const stickyBottomOffset = Math.max(limiterRect.bottom - visibleLimiterRect.bottom, 0) + this.limiterBottomOffset;
|
15845
|
+
// @if CK_DEBUG_STICKYPANEL // const stickyBottomOffsetRect = new Rect( {
|
15846
|
+
// @if CK_DEBUG_STICKYPANEL // top: limiterRect.bottom - stickyBottomOffset, left: 0, right: 2000,
|
15847
|
+
// @if CK_DEBUG_STICKYPANEL // bottom: limiterRect.bottom - stickyBottomOffset, width: 2000, height: 1
|
15848
|
+
// @if CK_DEBUG_STICKYPANEL // } );
|
15849
|
+
// @if CK_DEBUG_STICKYPANEL // RectDrawer.draw( stickyBottomOffsetRect,
|
15850
|
+
// @if CK_DEBUG_STICKYPANEL // { outlineWidth: '1px', opacity: '.8', outlineColor: 'black' },
|
15851
|
+
// @if CK_DEBUG_STICKYPANEL // 'Sticky bottom offset',
|
15852
|
+
// @if CK_DEBUG_STICKYPANEL // { visualViewportOrigin: true }
|
15853
|
+
// @if CK_DEBUG_STICKYPANEL // );
|
15706
15854
|
// Check if sticking the panel to the bottom of the limiter does not cause it to suddenly
|
15707
15855
|
// move upwards if there's not enough space for it.
|
15708
|
-
//
|
15709
|
-
|
15856
|
+
// To avoid toolbar flickering we are adding 1 for potential style change (sticky has all borders set,
|
15857
|
+
// non-sticky lacks bottom border).
|
15858
|
+
if (this._contentPanelRect.height + stickyBottomOffset + 1 < limiterRect.height) {
|
15710
15859
|
this._stickToBottomOfLimiter(stickyBottomOffset);
|
15711
15860
|
} else {
|
15712
15861
|
this._unstick();
|
15713
15862
|
}
|
15714
15863
|
} else if (this._contentPanelRect.height + this.limiterBottomOffset < limiterRect.height) {
|
15715
|
-
this._stickToTopOfAncestors(
|
15864
|
+
this._stickToTopOfAncestors(visibleLimiterRect.top);
|
15716
15865
|
} else {
|
15717
15866
|
this._unstick();
|
15718
15867
|
}
|
@@ -15724,6 +15873,15 @@ const toPx$3 = /* #__PURE__ */ toUnit('px');
|
|
15724
15873
|
// @if CK_DEBUG_STICKYPANEL // console.log( '_isStickyToTheBottomOfLimiter', this._isStickyToTheBottomOfLimiter );
|
15725
15874
|
// @if CK_DEBUG_STICKYPANEL // console.log( '_stickyTopOffset', this._stickyTopOffset );
|
15726
15875
|
// @if CK_DEBUG_STICKYPANEL // console.log( '_stickyBottomOffset', this._stickyBottomOffset );
|
15876
|
+
// @if CK_DEBUG_STICKYPANEL // if ( visibleLimiterRect ) {
|
15877
|
+
// @if CK_DEBUG_STICKYPANEL // RectDrawer.draw( visibleLimiterRect,
|
15878
|
+
// @if CK_DEBUG_STICKYPANEL // { ...diagonalStylesBlack,
|
15879
|
+
// @if CK_DEBUG_STICKYPANEL // outlineWidth: '3px', opacity: '.8', outlineColor: 'orange', outlineOffset: '-3px',
|
15880
|
+
// @if CK_DEBUG_STICKYPANEL // backgroundColor: 'rgba(0, 0, 255, .2)', zIndex: 2000 },
|
15881
|
+
// @if CK_DEBUG_STICKYPANEL // 'visibleLimiterRect',
|
15882
|
+
// @if CK_DEBUG_STICKYPANEL // { visualViewportOrigin: true }
|
15883
|
+
// @if CK_DEBUG_STICKYPANEL // );
|
15884
|
+
// @if CK_DEBUG_STICKYPANEL // }
|
15727
15885
|
}
|
15728
15886
|
/**
|
15729
15887
|
* Sticks the panel at the given CSS `top` offset.
|
@@ -15735,7 +15893,7 @@ const toPx$3 = /* #__PURE__ */ toUnit('px');
|
|
15735
15893
|
this._isStickyToTheBottomOfLimiter = false;
|
15736
15894
|
this._stickyTopOffset = topOffset;
|
15737
15895
|
this._stickyBottomOffset = null;
|
15738
|
-
this._marginLeft = toPx$3(-global.window.scrollX +
|
15896
|
+
this._marginLeft = toPx$3(-global.window.scrollX + getVisualViewportOffset().left);
|
15739
15897
|
}
|
15740
15898
|
/**
|
15741
15899
|
* Sticks the panel at the bottom of the limiter with a given CSS `bottom` offset.
|
@@ -15747,7 +15905,7 @@ const toPx$3 = /* #__PURE__ */ toUnit('px');
|
|
15747
15905
|
this._isStickyToTheBottomOfLimiter = true;
|
15748
15906
|
this._stickyTopOffset = null;
|
15749
15907
|
this._stickyBottomOffset = stickyBottomOffset;
|
15750
|
-
this._marginLeft = toPx$3(-global.window.scrollX +
|
15908
|
+
this._marginLeft = toPx$3(-global.window.scrollX + getVisualViewportOffset().left);
|
15751
15909
|
}
|
15752
15910
|
/**
|
15753
15911
|
* Unsticks the panel putting it back to its original position.
|
@@ -15767,23 +15925,6 @@ const toPx$3 = /* #__PURE__ */ toUnit('px');
|
|
15767
15925
|
*/ get _contentPanelRect() {
|
15768
15926
|
return new Rect(this.contentPanelElement);
|
15769
15927
|
}
|
15770
|
-
/**
|
15771
|
-
* Returns normalized visual viewport offsets (only for Safari and iOS).
|
15772
|
-
*/ _getVisualViewportOffset() {
|
15773
|
-
const visualViewport = global.window.visualViewport;
|
15774
|
-
if (!(env.isiOS || env.isSafari) || !visualViewport) {
|
15775
|
-
return {
|
15776
|
-
left: 0,
|
15777
|
-
top: 0
|
15778
|
-
};
|
15779
|
-
}
|
15780
|
-
const left = Math.max(Math.round(visualViewport.offsetLeft), 0);
|
15781
|
-
const top = Math.max(Math.round(visualViewport.offsetTop), 0);
|
15782
|
-
return {
|
15783
|
-
left,
|
15784
|
-
top
|
15785
|
-
};
|
15786
|
-
}
|
15787
15928
|
}
|
15788
15929
|
|
15789
15930
|
/**
|
@@ -17886,8 +18027,8 @@ const EVENT_NAME_DELEGATES = [
|
|
17886
18027
|
* {@link module:ui/menubar/menubarmenulistitembuttonview~MenuBarMenuListItemButtonView} (button).
|
17887
18028
|
*
|
17888
18029
|
* @error menu-bar-component-unsupported
|
17889
|
-
* @param componentName A name of the unsupported component used in the configuration.
|
17890
|
-
* @param componentView An unsupported component view.
|
18030
|
+
* @param {string} componentName A name of the unsupported component used in the configuration.
|
18031
|
+
* @param {module:ui/view~View} componentView An unsupported component view.
|
17891
18032
|
*/ logWarning('menu-bar-component-unsupported', {
|
17892
18033
|
componentName,
|
17893
18034
|
componentView
|