@ckeditor/ckeditor5-ui 41.1.0 → 41.2.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/ckeditor5-metadata.json +14 -0
- package/lang/contexts.json +7 -1
- package/lang/translations/ar.po +24 -0
- package/lang/translations/ast.po +24 -0
- package/lang/translations/az.po +24 -0
- package/lang/translations/bg.po +24 -0
- package/lang/translations/bn.po +24 -0
- package/lang/translations/ca.po +24 -0
- package/lang/translations/cs.po +24 -0
- package/lang/translations/da.po +24 -0
- package/lang/translations/de-ch.po +24 -0
- package/lang/translations/de.po +24 -0
- package/lang/translations/el.po +24 -0
- package/lang/translations/en-au.po +24 -0
- package/lang/translations/en-gb.po +24 -0
- package/lang/translations/en.po +24 -0
- package/lang/translations/eo.po +24 -0
- package/lang/translations/es.po +24 -0
- package/lang/translations/et.po +24 -0
- package/lang/translations/eu.po +24 -0
- package/lang/translations/fa.po +24 -0
- package/lang/translations/fi.po +24 -0
- package/lang/translations/fr.po +24 -0
- package/lang/translations/gl.po +24 -0
- package/lang/translations/he.po +25 -1
- package/lang/translations/hi.po +24 -0
- package/lang/translations/hr.po +24 -0
- package/lang/translations/hu.po +24 -0
- package/lang/translations/id.po +24 -0
- package/lang/translations/it.po +24 -0
- package/lang/translations/ja.po +24 -0
- package/lang/translations/km.po +24 -0
- package/lang/translations/kn.po +24 -0
- package/lang/translations/ko.po +24 -0
- package/lang/translations/ku.po +24 -0
- package/lang/translations/lt.po +24 -0
- package/lang/translations/lv.po +24 -0
- package/lang/translations/ms.po +24 -0
- package/lang/translations/nb.po +24 -0
- package/lang/translations/ne.po +24 -0
- package/lang/translations/nl.po +24 -0
- package/lang/translations/no.po +24 -0
- package/lang/translations/pl.po +24 -0
- package/lang/translations/pt-br.po +24 -0
- package/lang/translations/pt.po +25 -1
- package/lang/translations/ro.po +24 -0
- package/lang/translations/ru.po +24 -0
- package/lang/translations/sk.po +24 -0
- package/lang/translations/sl.po +24 -0
- package/lang/translations/sq.po +24 -0
- package/lang/translations/sr-latn.po +24 -0
- package/lang/translations/sr.po +24 -0
- package/lang/translations/sv.po +24 -0
- package/lang/translations/th.po +24 -0
- package/lang/translations/tk.po +24 -0
- package/lang/translations/tr.po +24 -0
- package/lang/translations/tt.po +24 -0
- package/lang/translations/ug.po +24 -0
- package/lang/translations/uk.po +24 -0
- package/lang/translations/ur.po +24 -0
- package/lang/translations/uz.po +24 -0
- package/lang/translations/vi.po +24 -0
- package/lang/translations/zh-cn.po +24 -0
- package/lang/translations/zh.po +24 -0
- package/package.json +3 -3
- package/src/augmentation.d.ts +2 -1
- package/src/dialog/dialog.js +10 -0
- package/src/editorui/accessibilityhelp/accessibilityhelp.d.ts +47 -0
- package/src/editorui/accessibilityhelp/accessibilityhelp.js +111 -0
- package/src/editorui/accessibilityhelp/accessibilityhelpcontentview.d.ts +35 -0
- package/src/editorui/accessibilityhelp/accessibilityhelpcontentview.js +112 -0
- package/src/formheader/formheaderview.js +2 -1
- package/src/index.d.ts +1 -0
- package/src/index.js +1 -0
- package/src/toolbar/balloon/balloontoolbar.d.ts +0 -5
- package/src/toolbar/balloon/balloontoolbar.js +5 -8
- package/src/toolbar/block/blocktoolbar.d.ts +0 -8
- package/src/toolbar/block/blocktoolbar.js +9 -14
- package/src/tooltipmanager.d.ts +5 -1
- package/src/tooltipmanager.js +32 -4
- package/theme/components/editorui/accessibilityhelp.css +10 -0
- package/theme/icons/accessibility.svg +1 -0
|
@@ -0,0 +1,47 @@
|
|
|
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/accessibilityhelp/accessibilityhelp
|
|
7
|
+
*/
|
|
8
|
+
import { Plugin } from '@ckeditor/ckeditor5-core';
|
|
9
|
+
import { Dialog } from '../../index.js';
|
|
10
|
+
import AccessibilityHelpContentView from './accessibilityhelpcontentview.js';
|
|
11
|
+
import '../../../theme/components/editorui/accessibilityhelp.css';
|
|
12
|
+
/**
|
|
13
|
+
* A plugin that brings the accessibility help dialog to the editor available under the <kbd>Alt</kbd>+<kbd>0</kbd>
|
|
14
|
+
* keystroke and via the "Accessibility help" toolbar button. The dialog displays a list of keystrokes that can be used
|
|
15
|
+
* by the user to perform various actions in the editor.
|
|
16
|
+
*
|
|
17
|
+
* Keystroke information is loaded from {@link module:core/accessibility~Accessibility#keystrokeInfos}. New entries can be
|
|
18
|
+
* added using the API provided by the {@link module:core/accessibility~Accessibility} class.
|
|
19
|
+
*/
|
|
20
|
+
export default class AccessibilityHelp extends Plugin {
|
|
21
|
+
/**
|
|
22
|
+
* The view that displays the dialog content (list of keystrokes).
|
|
23
|
+
* Created when the dialog is opened for the first time.
|
|
24
|
+
*/
|
|
25
|
+
contentView: AccessibilityHelpContentView | null;
|
|
26
|
+
/**
|
|
27
|
+
* @inheritDoc
|
|
28
|
+
*/
|
|
29
|
+
static get requires(): readonly [typeof Dialog];
|
|
30
|
+
/**
|
|
31
|
+
* @inheritDoc
|
|
32
|
+
*/
|
|
33
|
+
static get pluginName(): "AccessibilityHelp";
|
|
34
|
+
/**
|
|
35
|
+
* @inheritDoc
|
|
36
|
+
*/
|
|
37
|
+
init(): void;
|
|
38
|
+
/**
|
|
39
|
+
* Injects a help text into each editing root's `aria-label` attribute allowing assistive technology users
|
|
40
|
+
* to discover the availability of the Accessibility help dialog.
|
|
41
|
+
*/
|
|
42
|
+
private _setupRootLabels;
|
|
43
|
+
/**
|
|
44
|
+
* Shows the accessibility help dialog. Also, creates {@link #contentView} on demand.
|
|
45
|
+
*/
|
|
46
|
+
private _showDialog;
|
|
47
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
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/accessibilityhelp/accessibilityhelp
|
|
7
|
+
*/
|
|
8
|
+
import { Plugin } from '@ckeditor/ckeditor5-core';
|
|
9
|
+
import { ButtonView, Dialog } from '../../index.js';
|
|
10
|
+
import AccessibilityHelpContentView from './accessibilityhelpcontentview.js';
|
|
11
|
+
import { getEnvKeystrokeText } from '@ckeditor/ckeditor5-utils';
|
|
12
|
+
import accessibilityIcon from '../../../theme/icons/accessibility.svg';
|
|
13
|
+
import '../../../theme/components/editorui/accessibilityhelp.css';
|
|
14
|
+
/**
|
|
15
|
+
* A plugin that brings the accessibility help dialog to the editor available under the <kbd>Alt</kbd>+<kbd>0</kbd>
|
|
16
|
+
* keystroke and via the "Accessibility help" toolbar button. The dialog displays a list of keystrokes that can be used
|
|
17
|
+
* by the user to perform various actions in the editor.
|
|
18
|
+
*
|
|
19
|
+
* Keystroke information is loaded from {@link module:core/accessibility~Accessibility#keystrokeInfos}. New entries can be
|
|
20
|
+
* added using the API provided by the {@link module:core/accessibility~Accessibility} class.
|
|
21
|
+
*/
|
|
22
|
+
export default class AccessibilityHelp extends Plugin {
|
|
23
|
+
constructor() {
|
|
24
|
+
super(...arguments);
|
|
25
|
+
/**
|
|
26
|
+
* The view that displays the dialog content (list of keystrokes).
|
|
27
|
+
* Created when the dialog is opened for the first time.
|
|
28
|
+
*/
|
|
29
|
+
this.contentView = null;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* @inheritDoc
|
|
33
|
+
*/
|
|
34
|
+
static get requires() {
|
|
35
|
+
return [Dialog];
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* @inheritDoc
|
|
39
|
+
*/
|
|
40
|
+
static get pluginName() {
|
|
41
|
+
return 'AccessibilityHelp';
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* @inheritDoc
|
|
45
|
+
*/
|
|
46
|
+
init() {
|
|
47
|
+
const editor = this.editor;
|
|
48
|
+
const t = editor.locale.t;
|
|
49
|
+
editor.ui.componentFactory.add('accessibilityHelp', locale => {
|
|
50
|
+
const buttonView = new ButtonView(locale);
|
|
51
|
+
buttonView.set({
|
|
52
|
+
label: t('Accessibility help'),
|
|
53
|
+
tooltip: true,
|
|
54
|
+
withText: false,
|
|
55
|
+
keystroke: 'Alt+0',
|
|
56
|
+
icon: accessibilityIcon
|
|
57
|
+
});
|
|
58
|
+
buttonView.on('execute', () => this._showDialog());
|
|
59
|
+
return buttonView;
|
|
60
|
+
});
|
|
61
|
+
editor.keystrokes.set('Alt+0', (evt, cancel) => {
|
|
62
|
+
this._showDialog();
|
|
63
|
+
cancel();
|
|
64
|
+
});
|
|
65
|
+
this._setupRootLabels();
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Injects a help text into each editing root's `aria-label` attribute allowing assistive technology users
|
|
69
|
+
* to discover the availability of the Accessibility help dialog.
|
|
70
|
+
*/
|
|
71
|
+
_setupRootLabels() {
|
|
72
|
+
const editor = this.editor;
|
|
73
|
+
const editingView = editor.editing.view;
|
|
74
|
+
const t = editor.t;
|
|
75
|
+
editor.ui.on('ready', () => {
|
|
76
|
+
editingView.change(writer => {
|
|
77
|
+
for (const root of editingView.document.roots) {
|
|
78
|
+
addAriaLabelTextToRoot(writer, root);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
editor.on('addRoot', (evt, modelRoot) => {
|
|
82
|
+
const viewRoot = editor.editing.view.document.getRoot(modelRoot.rootName);
|
|
83
|
+
editingView.change(writer => addAriaLabelTextToRoot(writer, viewRoot));
|
|
84
|
+
}, { priority: 'low' });
|
|
85
|
+
});
|
|
86
|
+
function addAriaLabelTextToRoot(writer, viewRoot) {
|
|
87
|
+
const currentAriaLabel = viewRoot.getAttribute('aria-label');
|
|
88
|
+
const newAriaLabel = `${currentAriaLabel}. ${t('Press %0 for help.', [getEnvKeystrokeText('Alt+0')])}`;
|
|
89
|
+
writer.setAttribute('aria-label', newAriaLabel, viewRoot);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Shows the accessibility help dialog. Also, creates {@link #contentView} on demand.
|
|
94
|
+
*/
|
|
95
|
+
_showDialog() {
|
|
96
|
+
const editor = this.editor;
|
|
97
|
+
const dialog = editor.plugins.get('Dialog');
|
|
98
|
+
const t = editor.locale.t;
|
|
99
|
+
if (!this.contentView) {
|
|
100
|
+
this.contentView = new AccessibilityHelpContentView(editor.locale, editor.accessibility.keystrokeInfos);
|
|
101
|
+
}
|
|
102
|
+
dialog.show({
|
|
103
|
+
id: 'accessibilityHelp',
|
|
104
|
+
className: 'ck-accessibility-help-dialog',
|
|
105
|
+
title: t('Accessibility help'),
|
|
106
|
+
icon: accessibilityIcon,
|
|
107
|
+
hasCloseButton: true,
|
|
108
|
+
content: this.contentView
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
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/accessibilityhelp/accessibilityhelpcontentview
|
|
7
|
+
*/
|
|
8
|
+
import { type Locale } from '@ckeditor/ckeditor5-utils';
|
|
9
|
+
import View from '../../view.js';
|
|
10
|
+
import type { KeystrokeInfoDefinitions } from '@ckeditor/ckeditor5-core';
|
|
11
|
+
/**
|
|
12
|
+
* The view displaying keystrokes in the Accessibility help dialog.
|
|
13
|
+
*/
|
|
14
|
+
export default class AccessibilityHelpContentView extends View<HTMLDivElement> {
|
|
15
|
+
/**
|
|
16
|
+
* @inheritDoc
|
|
17
|
+
*/
|
|
18
|
+
constructor(locale: Locale, keystrokes: KeystrokeInfoDefinitions);
|
|
19
|
+
/**
|
|
20
|
+
* @inheritDoc
|
|
21
|
+
*/
|
|
22
|
+
focus(): void;
|
|
23
|
+
/**
|
|
24
|
+
* Creates `<section><h3>Category label</h3>...</section>` elements for each category of keystrokes.
|
|
25
|
+
*/
|
|
26
|
+
private _createCategories;
|
|
27
|
+
/**
|
|
28
|
+
* Creates `[<h4>Optional label</h4>]<dl>...</dl>` elements for each group of keystrokes in a category.
|
|
29
|
+
*/
|
|
30
|
+
private _createGroup;
|
|
31
|
+
/**
|
|
32
|
+
* Creates `<dt>Keystroke label</dt><dd>Keystroke definition</dd>` elements for each keystroke in a group.
|
|
33
|
+
*/
|
|
34
|
+
private _createGroupRow;
|
|
35
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
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/accessibilityhelp/accessibilityhelpcontentview
|
|
7
|
+
*/
|
|
8
|
+
import { createElement, env, getEnvKeystrokeText } from '@ckeditor/ckeditor5-utils';
|
|
9
|
+
import View from '../../view.js';
|
|
10
|
+
import LabelView from '../../label/labelview.js';
|
|
11
|
+
/**
|
|
12
|
+
* The view displaying keystrokes in the Accessibility help dialog.
|
|
13
|
+
*/
|
|
14
|
+
export default class AccessibilityHelpContentView extends View {
|
|
15
|
+
/**
|
|
16
|
+
* @inheritDoc
|
|
17
|
+
*/
|
|
18
|
+
constructor(locale, keystrokes) {
|
|
19
|
+
super(locale);
|
|
20
|
+
const t = locale.t;
|
|
21
|
+
const helpLabel = new LabelView();
|
|
22
|
+
helpLabel.text = t('Help Contents. To close this dialog press ESC.');
|
|
23
|
+
this.setTemplate({
|
|
24
|
+
tag: 'div',
|
|
25
|
+
attributes: {
|
|
26
|
+
class: ['ck', 'ck-accessibility-help-dialog__content'],
|
|
27
|
+
'aria-labelledby': helpLabel.id,
|
|
28
|
+
role: 'document',
|
|
29
|
+
tabindex: -1
|
|
30
|
+
},
|
|
31
|
+
children: [
|
|
32
|
+
createElement(document, 'p', {}, t('Below, you can find a list of keyboard shortcuts that can be used in the editor.')),
|
|
33
|
+
...this._createCategories(Array.from(keystrokes.values())),
|
|
34
|
+
helpLabel
|
|
35
|
+
]
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* @inheritDoc
|
|
40
|
+
*/
|
|
41
|
+
focus() {
|
|
42
|
+
this.element.focus();
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Creates `<section><h3>Category label</h3>...</section>` elements for each category of keystrokes.
|
|
46
|
+
*/
|
|
47
|
+
_createCategories(categories) {
|
|
48
|
+
return categories.map(categoryDefinition => {
|
|
49
|
+
const elements = [
|
|
50
|
+
// Category header.
|
|
51
|
+
createElement(document, 'h3', {}, categoryDefinition.label),
|
|
52
|
+
// Category definitions (<dl>) and their optional headers (<h4>).
|
|
53
|
+
...Array.from(categoryDefinition.groups.values())
|
|
54
|
+
.map(groupDefinition => this._createGroup(groupDefinition))
|
|
55
|
+
.flat()
|
|
56
|
+
];
|
|
57
|
+
// Category description (<p>).
|
|
58
|
+
if (categoryDefinition.description) {
|
|
59
|
+
elements.splice(1, 0, createElement(document, 'p', {}, categoryDefinition.description));
|
|
60
|
+
}
|
|
61
|
+
return createElement(document, 'section', {}, elements);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Creates `[<h4>Optional label</h4>]<dl>...</dl>` elements for each group of keystrokes in a category.
|
|
66
|
+
*/
|
|
67
|
+
_createGroup(groupDefinition) {
|
|
68
|
+
const definitionAndDescriptionElements = groupDefinition.keystrokes
|
|
69
|
+
.sort((a, b) => a.label.localeCompare(b.label))
|
|
70
|
+
.map(keystrokeDefinition => this._createGroupRow(keystrokeDefinition))
|
|
71
|
+
.flat();
|
|
72
|
+
const elements = [
|
|
73
|
+
createElement(document, 'dl', {}, definitionAndDescriptionElements)
|
|
74
|
+
];
|
|
75
|
+
if (groupDefinition.label) {
|
|
76
|
+
elements.unshift(createElement(document, 'h4', {}, groupDefinition.label));
|
|
77
|
+
}
|
|
78
|
+
return elements;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Creates `<dt>Keystroke label</dt><dd>Keystroke definition</dd>` elements for each keystroke in a group.
|
|
82
|
+
*/
|
|
83
|
+
_createGroupRow(keystrokeDefinition) {
|
|
84
|
+
const t = this.locale.t;
|
|
85
|
+
const dt = createElement(document, 'dt');
|
|
86
|
+
const dd = createElement(document, 'dd');
|
|
87
|
+
const normalizedKeystrokeDefinition = normalizeKeystrokeDefinition(keystrokeDefinition.keystroke);
|
|
88
|
+
const keystrokeAlternativeHTMLs = [];
|
|
89
|
+
for (const keystrokeAlternative of normalizedKeystrokeDefinition) {
|
|
90
|
+
keystrokeAlternativeHTMLs.push(keystrokeAlternative.map(keystrokeToEnvKbd).join(''));
|
|
91
|
+
}
|
|
92
|
+
dt.innerHTML = keystrokeDefinition.label;
|
|
93
|
+
dd.innerHTML = keystrokeAlternativeHTMLs.join(', ') +
|
|
94
|
+
(keystrokeDefinition.mayRequireFn && env.isMac ? ` ${t('(may require <kbd>Fn</kbd>)')}` : '');
|
|
95
|
+
return [dt, dd];
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
function keystrokeToEnvKbd(keystroke) {
|
|
99
|
+
return getEnvKeystrokeText(keystroke)
|
|
100
|
+
.split('+')
|
|
101
|
+
.map(part => `<kbd>${part}</kbd>`)
|
|
102
|
+
.join('+');
|
|
103
|
+
}
|
|
104
|
+
function normalizeKeystrokeDefinition(definition) {
|
|
105
|
+
if (typeof definition === 'string') {
|
|
106
|
+
return [[definition]];
|
|
107
|
+
}
|
|
108
|
+
if (typeof definition[0] === 'string') {
|
|
109
|
+
return [definition];
|
|
110
|
+
}
|
|
111
|
+
return definition;
|
|
112
|
+
}
|
package/src/index.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export { default as injectCssTransitionDisabler } from './bindings/injectcsstran
|
|
|
10
10
|
export { default as CssTransitionDisablerMixin, type ViewWithCssTransitionDisabler } from './bindings/csstransitiondisablermixin.js';
|
|
11
11
|
export { default as submitHandler } from './bindings/submithandler.js';
|
|
12
12
|
export { default as addKeyboardHandlingForGrid } from './bindings/addkeyboardhandlingforgrid.js';
|
|
13
|
+
export { default as AccessibilityHelp } from './editorui/accessibilityhelp/accessibilityhelp.js';
|
|
13
14
|
export { default as BodyCollection } from './editorui/bodycollection.js';
|
|
14
15
|
export { type ButtonExecuteEvent } from './button/button.js';
|
|
15
16
|
export type { default as ButtonLabel } from './button/buttonlabel.js';
|
package/src/index.js
CHANGED
|
@@ -10,6 +10,7 @@ export { default as injectCssTransitionDisabler } from './bindings/injectcsstran
|
|
|
10
10
|
export { default as CssTransitionDisablerMixin } from './bindings/csstransitiondisablermixin.js';
|
|
11
11
|
export { default as submitHandler } from './bindings/submithandler.js';
|
|
12
12
|
export { default as addKeyboardHandlingForGrid } from './bindings/addkeyboardhandlingforgrid.js';
|
|
13
|
+
export { default as AccessibilityHelp } from './editorui/accessibilityhelp/accessibilityhelp.js';
|
|
13
14
|
export { default as BodyCollection } from './editorui/bodycollection.js';
|
|
14
15
|
export { default as ButtonView } from './button/buttonview.js';
|
|
15
16
|
export { default as ButtonLabelView } from './button/buttonlabelview.js';
|
|
@@ -68,11 +68,6 @@ export default class BalloonToolbar extends Plugin {
|
|
|
68
68
|
* @inheritDoc
|
|
69
69
|
*/
|
|
70
70
|
init(): void;
|
|
71
|
-
/**
|
|
72
|
-
* Creates toolbar components based on given configuration.
|
|
73
|
-
* This needs to be done when all plugins are ready.
|
|
74
|
-
*/
|
|
75
|
-
afterInit(): void;
|
|
76
71
|
/**
|
|
77
72
|
* Creates the toolbar view instance.
|
|
78
73
|
*/
|
|
@@ -117,14 +117,11 @@ export default class BalloonToolbar extends Plugin {
|
|
|
117
117
|
this.listenTo(this.toolbarView, 'groupedItemsUpdate', () => {
|
|
118
118
|
this._updatePosition();
|
|
119
119
|
});
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
afterInit() {
|
|
126
|
-
const factory = this.editor.ui.componentFactory;
|
|
127
|
-
this.toolbarView.fillFromConfig(this._balloonConfig, factory);
|
|
120
|
+
// Creates toolbar components based on given configuration.
|
|
121
|
+
// This needs to be done when all plugins are ready.
|
|
122
|
+
editor.ui.once('ready', () => {
|
|
123
|
+
this.toolbarView.fillFromConfig(this._balloonConfig, this.editor.ui.componentFactory);
|
|
124
|
+
});
|
|
128
125
|
}
|
|
129
126
|
/**
|
|
130
127
|
* Creates the toolbar view instance.
|
|
@@ -75,8 +75,6 @@ export default class BlockToolbar extends Plugin {
|
|
|
75
75
|
*
|
|
76
76
|
* **Note**: Used only when `shouldNotGroupWhenFull` was **not** set in the
|
|
77
77
|
* {@link module:core/editor/editorconfig~EditorConfig#blockToolbar configuration}.
|
|
78
|
-
*
|
|
79
|
-
* **Note:** Created in {@link #afterInit}.
|
|
80
78
|
*/
|
|
81
79
|
private _resizeObserver;
|
|
82
80
|
/**
|
|
@@ -95,12 +93,6 @@ export default class BlockToolbar extends Plugin {
|
|
|
95
93
|
* @inheritDoc
|
|
96
94
|
*/
|
|
97
95
|
init(): void;
|
|
98
|
-
/**
|
|
99
|
-
* Fills the toolbar with its items based on the configuration.
|
|
100
|
-
*
|
|
101
|
-
* **Note:** This needs to be done after all plugins are ready.
|
|
102
|
-
*/
|
|
103
|
-
afterInit(): void;
|
|
104
96
|
/**
|
|
105
97
|
* @inheritDoc
|
|
106
98
|
*/
|
|
@@ -79,8 +79,6 @@ export default class BlockToolbar extends Plugin {
|
|
|
79
79
|
*
|
|
80
80
|
* **Note**: Used only when `shouldNotGroupWhenFull` was **not** set in the
|
|
81
81
|
* {@link module:core/editor/editorconfig~EditorConfig#blockToolbar configuration}.
|
|
82
|
-
*
|
|
83
|
-
* **Note:** Created in {@link #afterInit}.
|
|
84
82
|
*/
|
|
85
83
|
this._resizeObserver = null;
|
|
86
84
|
this._blockToolbarConfig = normalizeToolbarConfig(this.editor.config.get('blockToolbar'));
|
|
@@ -138,18 +136,15 @@ export default class BlockToolbar extends Plugin {
|
|
|
138
136
|
beforeFocus: () => this._showPanel(),
|
|
139
137
|
afterBlur: () => this._hidePanel()
|
|
140
138
|
});
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
for (const item of this.toolbarView.items) {
|
|
151
|
-
item.on('execute', () => this._hidePanel(true), { priority: 'high' });
|
|
152
|
-
}
|
|
139
|
+
// Fills the toolbar with its items based on the configuration.
|
|
140
|
+
// This needs to be done after all plugins are ready.
|
|
141
|
+
editor.ui.once('ready', () => {
|
|
142
|
+
this.toolbarView.fillFromConfig(this._blockToolbarConfig, this.editor.ui.componentFactory);
|
|
143
|
+
// Hide panel before executing each button in the panel.
|
|
144
|
+
for (const item of this.toolbarView.items) {
|
|
145
|
+
item.on('execute', () => this._hidePanel(true), { priority: 'high' });
|
|
146
|
+
}
|
|
147
|
+
});
|
|
153
148
|
}
|
|
154
149
|
/**
|
|
155
150
|
* @inheritDoc
|
package/src/tooltipmanager.d.ts
CHANGED
|
@@ -100,6 +100,10 @@ export default class TooltipManager extends TooltipManager_base {
|
|
|
100
100
|
* {@link module:core/editor/editorconfig~EditorConfig#balloonToolbar configuration}.
|
|
101
101
|
*/
|
|
102
102
|
private _resizeObserver;
|
|
103
|
+
/**
|
|
104
|
+
* An instance of the mutation observer that keeps track on target element attributes changes.
|
|
105
|
+
*/
|
|
106
|
+
private _mutationObserver;
|
|
103
107
|
/**
|
|
104
108
|
* A debounced version of {@link #_pinTooltip}. Tooltips show with a delay to avoid flashing and
|
|
105
109
|
* to improve the UX.
|
|
@@ -172,7 +176,7 @@ export default class TooltipManager extends TooltipManager_base {
|
|
|
172
176
|
/**
|
|
173
177
|
* Updates the position of the tooltip so it stays in sync with the element it is pinned to.
|
|
174
178
|
*
|
|
175
|
-
* Hides the tooltip when the element is no longer visible in DOM.
|
|
179
|
+
* Hides the tooltip when the element is no longer visible in DOM or the tooltip text was removed.
|
|
176
180
|
*/
|
|
177
181
|
private _updateTooltipPosition;
|
|
178
182
|
}
|
package/src/tooltipmanager.js
CHANGED
|
@@ -87,6 +87,10 @@ class TooltipManager extends DomEmitterMixin() {
|
|
|
87
87
|
* {@link module:core/editor/editorconfig~EditorConfig#balloonToolbar configuration}.
|
|
88
88
|
*/
|
|
89
89
|
this._resizeObserver = null;
|
|
90
|
+
/**
|
|
91
|
+
* An instance of the mutation observer that keeps track on target element attributes changes.
|
|
92
|
+
*/
|
|
93
|
+
this._mutationObserver = null;
|
|
90
94
|
TooltipManager._editors.add(editor);
|
|
91
95
|
// TooltipManager must be a singleton. Multiple instances would mean multiple tooltips attached
|
|
92
96
|
// to the same DOM element with data-cke-tooltip-* attributes.
|
|
@@ -113,6 +117,9 @@ class TooltipManager extends DomEmitterMixin() {
|
|
|
113
117
|
this.balloonPanelView = new BalloonPanelView(editor.locale);
|
|
114
118
|
this.balloonPanelView.class = BALLOON_CLASS;
|
|
115
119
|
this.balloonPanelView.content.add(this.tooltipTextView);
|
|
120
|
+
this._mutationObserver = createMutationObserver(() => {
|
|
121
|
+
this._updateTooltipPosition();
|
|
122
|
+
});
|
|
116
123
|
this._pinTooltipDebounced = debounce(this._pinTooltip, 600);
|
|
117
124
|
this.listenTo(global.document, 'mouseenter', this._onEnterOrFocus.bind(this), { useCapture: true });
|
|
118
125
|
this.listenTo(global.document, 'mouseleave', this._onLeaveOrBlur.bind(this), { useCapture: true });
|
|
@@ -275,6 +282,7 @@ class TooltipManager extends DomEmitterMixin() {
|
|
|
275
282
|
this._unpinTooltip();
|
|
276
283
|
}
|
|
277
284
|
});
|
|
285
|
+
this._mutationObserver.attach(targetDomElement);
|
|
278
286
|
this.balloonPanelView.class = [BALLOON_CLASS, cssClass]
|
|
279
287
|
.filter(className => className)
|
|
280
288
|
.join(' ');
|
|
@@ -301,22 +309,24 @@ class TooltipManager extends DomEmitterMixin() {
|
|
|
301
309
|
if (this._resizeObserver) {
|
|
302
310
|
this._resizeObserver.destroy();
|
|
303
311
|
}
|
|
312
|
+
this._mutationObserver.detach();
|
|
304
313
|
}
|
|
305
314
|
/**
|
|
306
315
|
* Updates the position of the tooltip so it stays in sync with the element it is pinned to.
|
|
307
316
|
*
|
|
308
|
-
* Hides the tooltip when the element is no longer visible in DOM.
|
|
317
|
+
* Hides the tooltip when the element is no longer visible in DOM or the tooltip text was removed.
|
|
309
318
|
*/
|
|
310
319
|
_updateTooltipPosition() {
|
|
320
|
+
const tooltipData = getTooltipData(this._currentElementWithTooltip);
|
|
311
321
|
// This could happen if the tooltip was attached somewhere in a contextual content toolbar and the toolbar
|
|
312
|
-
// disappeared (e.g. removed an image).
|
|
313
|
-
if (!isVisible(this._currentElementWithTooltip)) {
|
|
322
|
+
// disappeared (e.g. removed an image), or the tooltip text was removed.
|
|
323
|
+
if (!isVisible(this._currentElementWithTooltip) || !tooltipData.text) {
|
|
314
324
|
this._unpinTooltip();
|
|
315
325
|
return;
|
|
316
326
|
}
|
|
317
327
|
this.balloonPanelView.pin({
|
|
318
328
|
target: this._currentElementWithTooltip,
|
|
319
|
-
positions: TooltipManager.getPositioningFunctions(
|
|
329
|
+
positions: TooltipManager.getPositioningFunctions(tooltipData.position)
|
|
320
330
|
});
|
|
321
331
|
}
|
|
322
332
|
}
|
|
@@ -352,3 +362,21 @@ function getTooltipData(element) {
|
|
|
352
362
|
cssClass: element.dataset.ckeTooltipClass || ''
|
|
353
363
|
};
|
|
354
364
|
}
|
|
365
|
+
// Creates a simple `MutationObserver` instance wrapper that observes changes in the tooltip-related attributes of the given element.
|
|
366
|
+
// Used instead of the `MutationObserver` from the engine for simplicity.
|
|
367
|
+
function createMutationObserver(callback) {
|
|
368
|
+
const mutationObserver = new MutationObserver(() => {
|
|
369
|
+
callback();
|
|
370
|
+
});
|
|
371
|
+
return {
|
|
372
|
+
attach(element) {
|
|
373
|
+
mutationObserver.observe(element, {
|
|
374
|
+
attributes: true,
|
|
375
|
+
attributeFilter: ['data-cke-tooltip-text', 'data-cke-tooltip-position']
|
|
376
|
+
});
|
|
377
|
+
},
|
|
378
|
+
detach() {
|
|
379
|
+
mutationObserver.disconnect();
|
|
380
|
+
}
|
|
381
|
+
};
|
|
382
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
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
|
+
/*
|
|
7
|
+
* Note: This file should contain the wireframe styles only. But since there are no such styles,
|
|
8
|
+
* it acts as a message to the builder telling that it should look for the corresponding styles
|
|
9
|
+
* **in the theme** when compiling the editor.
|
|
10
|
+
*/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M10 6.628a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"/><path d="M8.5 9.125a.3.3 0 0 0-.253-.296L5.11 8.327a.75.75 0 1 1 .388-1.449l4.04.716c.267.072.624.08.893.009l4.066-.724a.75.75 0 1 1 .388 1.45l-3.132.5a.3.3 0 0 0-.253.296v1.357a.3.3 0 0 0 .018.102l1.615 4.438a.75.75 0 0 1-1.41.513l-1.35-3.71a.3.3 0 0 0-.281-.197h-.209a.3.3 0 0 0-.282.198l-1.35 3.711a.75.75 0 0 1-1.41-.513l1.64-4.509a.3.3 0 0 0 .019-.103V9.125Z"/><path clip-rule="evenodd" d="M10 18.5a8.5 8.5 0 1 1 0-17 8.5 8.5 0 0 1 0 17Zm0 1.5c5.523 0 10-4.477 10-10S15.523 0 10 0 0 4.477 0 10s4.477 10 10 10Z"/></svg>
|