ckeditor5-elements-menu 0.0.0-stage → 49.0.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 +21 -0
- package/README.md +50 -2
- package/dist/augmentation.d.ts +30 -0
- package/dist/augmentation.d.ts.map +1 -0
- package/dist/augmentation.js +2 -0
- package/dist/augmentation.js.map +1 -0
- package/dist/breadcrumbs/breadcrumbItemView.d.ts +47 -0
- package/dist/breadcrumbs/breadcrumbItemView.d.ts.map +1 -0
- package/dist/breadcrumbs/breadcrumbItemView.js +30 -0
- package/dist/breadcrumbs/breadcrumbItemView.js.map +1 -0
- package/dist/breadcrumbs/breadcrumbLabelView.d.ts +29 -0
- package/dist/breadcrumbs/breadcrumbLabelView.d.ts.map +1 -0
- package/dist/breadcrumbs/breadcrumbLabelView.js +39 -0
- package/dist/breadcrumbs/breadcrumbLabelView.js.map +1 -0
- package/dist/breadcrumbs/breadcrumbsView.d.ts +68 -0
- package/dist/breadcrumbs/breadcrumbsView.d.ts.map +1 -0
- package/dist/breadcrumbs/breadcrumbsView.js +134 -0
- package/dist/breadcrumbs/breadcrumbsView.js.map +1 -0
- package/dist/breadcrumbs/elementBreadcrumbs.d.ts +73 -0
- package/dist/breadcrumbs/elementBreadcrumbs.d.ts.map +1 -0
- package/dist/breadcrumbs/elementBreadcrumbs.js +225 -0
- package/dist/breadcrumbs/elementBreadcrumbs.js.map +1 -0
- package/dist/contextMenu/contextMenuObserver.d.ts +19 -0
- package/dist/contextMenu/contextMenuObserver.d.ts.map +1 -0
- package/dist/contextMenu/contextMenuObserver.js +18 -0
- package/dist/contextMenu/contextMenuObserver.js.map +1 -0
- package/dist/contextMenu/elementContextMenu.d.ts +34 -0
- package/dist/contextMenu/elementContextMenu.d.ts.map +1 -0
- package/dist/contextMenu/elementContextMenu.js +88 -0
- package/dist/contextMenu/elementContextMenu.js.map +1 -0
- package/dist/domTarget.d.ts +8 -0
- package/dist/domTarget.d.ts.map +1 -0
- package/dist/domTarget.js +20 -0
- package/dist/domTarget.js.map +1 -0
- package/dist/elementMenu.d.ts +93 -0
- package/dist/elementMenu.d.ts.map +1 -0
- package/dist/elementMenu.js +140 -0
- package/dist/elementMenu.js.map +1 -0
- package/dist/elementMenuView.d.ts +40 -0
- package/dist/elementMenuView.d.ts.map +1 -0
- package/dist/elementMenuView.js +143 -0
- package/dist/elementMenuView.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/quickInsert/elementQuickInsert.d.ts +57 -0
- package/dist/quickInsert/elementQuickInsert.d.ts.map +1 -0
- package/dist/quickInsert/elementQuickInsert.js +96 -0
- package/dist/quickInsert/elementQuickInsert.js.map +1 -0
- package/dist/quickInsert/icons.d.ts +16 -0
- package/dist/quickInsert/icons.d.ts.map +1 -0
- package/dist/quickInsert/icons.js +21 -0
- package/dist/quickInsert/icons.js.map +1 -0
- package/dist/quickInsert/quickInsertCommand.d.ts +47 -0
- package/dist/quickInsert/quickInsertCommand.d.ts.map +1 -0
- package/dist/quickInsert/quickInsertCommand.js +81 -0
- package/dist/quickInsert/quickInsertCommand.js.map +1 -0
- package/dist/quickInsert/quickInsertListView.d.ts +29 -0
- package/dist/quickInsert/quickInsertListView.d.ts.map +1 -0
- package/dist/quickInsert/quickInsertListView.js +44 -0
- package/dist/quickInsert/quickInsertListView.js.map +1 -0
- package/dist/quickInsert/quickInsertPositionCommand.d.ts +33 -0
- package/dist/quickInsert/quickInsertPositionCommand.d.ts.map +1 -0
- package/dist/quickInsert/quickInsertPositionCommand.js +52 -0
- package/dist/quickInsert/quickInsertPositionCommand.js.map +1 -0
- package/dist/quickInsert/quickInsertView.d.ts +20 -0
- package/dist/quickInsert/quickInsertView.d.ts.map +1 -0
- package/dist/quickInsert/quickInsertView.js +52 -0
- package/dist/quickInsert/quickInsertView.js.map +1 -0
- package/package.json +52 -3
- package/src/augmentation.ts +44 -0
- package/src/breadcrumbs/breadcrumbItemView.ts +74 -0
- package/src/breadcrumbs/breadcrumbLabelView.ts +55 -0
- package/src/breadcrumbs/breadcrumbsView.ts +176 -0
- package/src/breadcrumbs/elementBreadcrumbs.ts +323 -0
- package/src/contextMenu/contextMenuObserver.ts +27 -0
- package/src/contextMenu/elementContextMenu.ts +104 -0
- package/src/domTarget.ts +27 -0
- package/src/elementMenu.ts +249 -0
- package/src/elementMenuView.ts +202 -0
- package/src/index.ts +54 -0
- package/src/quickInsert/elementQuickInsert.ts +135 -0
- package/src/quickInsert/icons.ts +26 -0
- package/src/quickInsert/quickInsertCommand.ts +96 -0
- package/src/quickInsert/quickInsertListView.ts +71 -0
- package/src/quickInsert/quickInsertPositionCommand.ts +68 -0
- package/src/quickInsert/quickInsertView.ts +64 -0
- package/theme/menu.css +131 -0
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { Plugin } from 'ckeditor5';
|
|
2
|
+
import { isInDocument } from 'ckeditor5-elements-core';
|
|
3
|
+
import ElementMenu, {} from '../elementMenu.js';
|
|
4
|
+
import {} from './breadcrumbItemView.js';
|
|
5
|
+
import BreadcrumbsView, {} from './breadcrumbsView.js';
|
|
6
|
+
/**
|
|
7
|
+
* Converting the data view of a large document takes a while. When the last conversion took longer than this (in
|
|
8
|
+
* milliseconds), the next one waits for {@link THROTTLE_TIME}, so editing elements quickly does not convert every time.
|
|
9
|
+
*/
|
|
10
|
+
const SLOW_CONVERSION_TIME = 10;
|
|
11
|
+
const THROTTLE_TIME = 250;
|
|
12
|
+
/**
|
|
13
|
+
* Shows the data view structure at the current selection (the elements of the editor data, as in `getData()`), e.g.
|
|
14
|
+
* `aside.note › p`, `ul › li` or `figure.table › table › tbody › tr › td`.
|
|
15
|
+
*
|
|
16
|
+
* Inline elements are items, as any element. CKEditor's text attributes, marks on the text such as its `<strong>`, are
|
|
17
|
+
* skipped. The selected element, e.g. an image, is the innermost item.
|
|
18
|
+
*
|
|
19
|
+
* Place them in a toolbar as the `breadcrumbs` component, or anywhere else using a view from {@link createView}.
|
|
20
|
+
*
|
|
21
|
+
* Clicking is configured only by the `elementBreadcrumbs.menu` editor config option (see {@link ElementBreadcrumbsConfig}): with it,
|
|
22
|
+
* the items are buttons that open the menu of their element, with `ElementMenu`, as the context menu does; without it,
|
|
23
|
+
* they are labels.
|
|
24
|
+
*
|
|
25
|
+
* The data view is converted again only when elements change, not when typing or moving the cursor. For a large
|
|
26
|
+
* document, that happens at most every 250 ms.
|
|
27
|
+
*/
|
|
28
|
+
export default class ElementBreadcrumbs extends Plugin {
|
|
29
|
+
_dataView = null;
|
|
30
|
+
_isDataViewOutdated = true;
|
|
31
|
+
_isConversionSlow = false;
|
|
32
|
+
_conversionTimeout = null;
|
|
33
|
+
static get pluginName() {
|
|
34
|
+
return 'ElementBreadcrumbs';
|
|
35
|
+
}
|
|
36
|
+
static get requires() {
|
|
37
|
+
return [ElementMenu];
|
|
38
|
+
}
|
|
39
|
+
constructor(editor) {
|
|
40
|
+
super(editor);
|
|
41
|
+
this.set('items', []);
|
|
42
|
+
}
|
|
43
|
+
init() {
|
|
44
|
+
const editor = this.editor;
|
|
45
|
+
editor.ui.componentFactory.add('breadcrumbs', locale => this.createView(locale));
|
|
46
|
+
this.listenTo(editor.ui, 'ready', () => {
|
|
47
|
+
this.refresh();
|
|
48
|
+
});
|
|
49
|
+
// Both selection and data changes.
|
|
50
|
+
this.listenTo(editor.model.document, 'change', () => {
|
|
51
|
+
if (hasElementChanges(editor.model.document.differ.getChanges())) {
|
|
52
|
+
this._isDataViewOutdated = true;
|
|
53
|
+
}
|
|
54
|
+
this._update();
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Creates a breadcrumbs view that follows {@link items}.
|
|
59
|
+
*/
|
|
60
|
+
createView(locale = this.editor.locale) {
|
|
61
|
+
const isClickable = typeof this.editor.config.get('elementBreadcrumbs')?.menu === 'function';
|
|
62
|
+
const view = new BreadcrumbsView(locale, { isClickable });
|
|
63
|
+
view.setItems(this.items);
|
|
64
|
+
view.listenTo(this, 'change:items', () => {
|
|
65
|
+
view.setItems(this.items);
|
|
66
|
+
});
|
|
67
|
+
view.on('execute', (evt, item) => {
|
|
68
|
+
this._openMenu(item);
|
|
69
|
+
});
|
|
70
|
+
return view;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Updates {@link items} from the current selection, converting the data view first when elements changed.
|
|
74
|
+
*/
|
|
75
|
+
refresh() {
|
|
76
|
+
const root = this.editor.model.document.selection.getFirstPosition()?.root;
|
|
77
|
+
if (root?.is('rootElement') && (this._isDataViewOutdated || root !== this._dataView?.root)) {
|
|
78
|
+
this._convert(root);
|
|
79
|
+
}
|
|
80
|
+
const items = this._getItems();
|
|
81
|
+
if (!areEqual(items, this.items)) {
|
|
82
|
+
this.items = items;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
destroy() {
|
|
86
|
+
this._cancelConversion();
|
|
87
|
+
super.destroy();
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Refreshes the items after a change. When converting is slow, the data view is converted later, and the items
|
|
91
|
+
* follow the outdated data view until then.
|
|
92
|
+
*/
|
|
93
|
+
_update() {
|
|
94
|
+
const root = this.editor.model.document.selection.getFirstPosition()?.root;
|
|
95
|
+
if (this._isDataViewOutdated && this._isConversionSlow && root === this._dataView?.root) {
|
|
96
|
+
this._conversionTimeout ??= setTimeout(() => {
|
|
97
|
+
this._conversionTimeout = null;
|
|
98
|
+
this.refresh();
|
|
99
|
+
}, THROTTLE_TIME);
|
|
100
|
+
}
|
|
101
|
+
if (this._conversionTimeout) {
|
|
102
|
+
const items = this._getItems();
|
|
103
|
+
if (!areEqual(items, this.items)) {
|
|
104
|
+
this.items = items;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
this.refresh();
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Converts the root to the data view, and maps its model elements to their view elements.
|
|
113
|
+
*/
|
|
114
|
+
_convert(root) {
|
|
115
|
+
const data = this.editor.data;
|
|
116
|
+
const start = performance.now();
|
|
117
|
+
const viewElements = new WeakMap();
|
|
118
|
+
const modelElements = new WeakMap();
|
|
119
|
+
// The mapper of the data pipeline is cleared by the next conversion (e.g. `getData()`), so keep the mapping.
|
|
120
|
+
data.toView(root);
|
|
121
|
+
for (const { item } of this.editor.model.createRangeIn(root)) {
|
|
122
|
+
const viewElement = item.is('element') ? data.mapper.toViewElement(item) : undefined;
|
|
123
|
+
if (item.is('element') && viewElement) {
|
|
124
|
+
viewElements.set(item, viewElement);
|
|
125
|
+
modelElements.set(viewElement, item);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
this._dataView = { root, viewElements, modelElements };
|
|
129
|
+
this._isDataViewOutdated = false;
|
|
130
|
+
this._isConversionSlow = performance.now() - start > SLOW_CONVERSION_TIME;
|
|
131
|
+
this._cancelConversion();
|
|
132
|
+
}
|
|
133
|
+
_cancelConversion() {
|
|
134
|
+
if (this._conversionTimeout) {
|
|
135
|
+
clearTimeout(this._conversionTimeout);
|
|
136
|
+
this._conversionTimeout = null;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Returns the data view elements at the selection: the view element of the selected element, or of the innermost
|
|
141
|
+
* element with the selection, and its ancestors.
|
|
142
|
+
*/
|
|
143
|
+
_getItems() {
|
|
144
|
+
const dataView = this._dataView;
|
|
145
|
+
const selection = this.editor.model.document.selection;
|
|
146
|
+
const position = selection.getFirstPosition();
|
|
147
|
+
if (!dataView || position?.root !== dataView.root) {
|
|
148
|
+
return [];
|
|
149
|
+
}
|
|
150
|
+
// Elements created since the last conversion are not mapped yet; their closest mapped ancestor is used meanwhile.
|
|
151
|
+
let viewElement;
|
|
152
|
+
for (let element = selection.getSelectedElement() ?? position.parent; element?.is('element') && !element.is('rootElement') && !viewElement; element = element.parent) {
|
|
153
|
+
viewElement = dataView.viewElements.get(element);
|
|
154
|
+
}
|
|
155
|
+
return viewElement ? getPath(viewElement).map(node => createItem(node, dataView)) : [];
|
|
156
|
+
}
|
|
157
|
+
_openMenu(item) {
|
|
158
|
+
const menuItems = this.editor.config.get('elementBreadcrumbs')?.menu;
|
|
159
|
+
const element = item.modelElement;
|
|
160
|
+
if (!menuItems || !item.element || !element || !isInDocument(element)) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
item.isExpanded = this.editor.plugins.get(ElementMenu).open(element, item.element, menuItems, {
|
|
164
|
+
// The breadcrumbs may have been replaced while the menu was open.
|
|
165
|
+
returnFocusTo: {
|
|
166
|
+
focus: () => {
|
|
167
|
+
if (item.element?.isConnected) {
|
|
168
|
+
item.focus();
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
this.editor.editing.view.focus();
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
onHide: () => {
|
|
176
|
+
item.isExpanded = false;
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Whether the changes add, remove or change elements. Typing (text changes) does not change the data view structure.
|
|
183
|
+
*/
|
|
184
|
+
function hasElementChanges(changes) {
|
|
185
|
+
return changes.some(change => change.type === 'attribute'
|
|
186
|
+
? Array.from(change.range.getItems({ shallow: true })).some(item => item.is('element'))
|
|
187
|
+
: change.name !== '$text');
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Returns the view element and its ancestors, outermost first, without:
|
|
191
|
+
*
|
|
192
|
+
* * text attributes (attribute elements without a block inside, such as `<strong>` or `<a>`); list items (`<ul>`,
|
|
193
|
+
* `<li>`) are attribute elements too, but wrap blocks,
|
|
194
|
+
* * elements that are not rendered in the data, such as the paragraph in a list item or a table cell that has only
|
|
195
|
+
* one paragraph.
|
|
196
|
+
*/
|
|
197
|
+
function getPath(viewElement) {
|
|
198
|
+
const path = [];
|
|
199
|
+
let hasBlock = false;
|
|
200
|
+
for (let node = viewElement; node?.is('element'); node = node.parent) {
|
|
201
|
+
const isTextAttribute = node.is('attributeElement') && !hasBlock;
|
|
202
|
+
if (!isTextAttribute && !node.getCustomProperty('dataPipeline:transparentRendering')) {
|
|
203
|
+
path.unshift(node);
|
|
204
|
+
}
|
|
205
|
+
hasBlock ||= node.is('containerElement');
|
|
206
|
+
}
|
|
207
|
+
return path;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Creates the item of a view element. Its model element is the mapped one, or the closest mapped ancestor of a part of
|
|
211
|
+
* a structure (e.g. a `tbody` is a part of a table). List items have none: they come from the attributes of the blocks
|
|
212
|
+
* in them, not from an element.
|
|
213
|
+
*/
|
|
214
|
+
function createItem(viewElement, dataView) {
|
|
215
|
+
let modelElement = null;
|
|
216
|
+
for (let node = viewElement; node?.is('element') && !modelElement && !node.is('attributeElement'); node = node.parent) {
|
|
217
|
+
modelElement = dataView.modelElements.get(node) ?? null;
|
|
218
|
+
}
|
|
219
|
+
return { label: [viewElement.name, ...viewElement.getClassNames()].join('.'), viewElement, modelElement };
|
|
220
|
+
}
|
|
221
|
+
function areEqual(a, b) {
|
|
222
|
+
return (a.length === b.length &&
|
|
223
|
+
a.every((item, index) => item.label === b[index]?.label && item.modelElement === b[index].modelElement));
|
|
224
|
+
}
|
|
225
|
+
//# sourceMappingURL=elementBreadcrumbs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elementBreadcrumbs.js","sourceRoot":"","sources":["../../src/breadcrumbs/elementBreadcrumbs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { DomEventObserver, type ViewDocumentDomEventData } from 'ckeditor5';
|
|
2
|
+
/**
|
|
3
|
+
* Fires the `contextmenu` event on the view document when the user opens the native context menu in an editable.
|
|
4
|
+
*/
|
|
5
|
+
export default class ContextMenuObserver extends DomEventObserver<'contextmenu'> {
|
|
6
|
+
get domEventType(): 'contextmenu';
|
|
7
|
+
/**
|
|
8
|
+
* Fires `contextmenu` on the view document for the DOM event.
|
|
9
|
+
*/
|
|
10
|
+
onDomEvent(domEvent: MouseEvent): void;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Fired on the view document by the {@link ContextMenuObserver}.
|
|
14
|
+
*/
|
|
15
|
+
export interface ViewDocumentContextMenuEvent {
|
|
16
|
+
name: 'contextmenu';
|
|
17
|
+
args: [data: ViewDocumentDomEventData<MouseEvent>];
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=contextMenuObserver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contextMenuObserver.d.ts","sourceRoot":"","sources":["../../src/contextMenu/contextMenuObserver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,KAAK,wBAAwB,EAAE,MAAM,WAAW,CAAC;AAE5E;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,mBAAoB,SAAQ,gBAAgB,CAAC,aAAa,CAAC;IAG/E,IAAW,YAAY,IAAI,aAAa,CAEvC;IAED;;OAEG;IACI,UAAU,CAAC,QAAQ,EAAE,UAAU,GAAG,IAAI;CAG7C;AAED;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC5C,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,EAAE,CAAC,IAAI,EAAE,wBAAwB,CAAC,UAAU,CAAC,CAAC,CAAC;CACnD"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { DomEventObserver } from 'ckeditor5';
|
|
2
|
+
/**
|
|
3
|
+
* Fires the `contextmenu` event on the view document when the user opens the native context menu in an editable.
|
|
4
|
+
*/
|
|
5
|
+
export default class ContextMenuObserver extends DomEventObserver {
|
|
6
|
+
// The base class declares it as an accessor, so it cannot be a field here.
|
|
7
|
+
// eslint-disable-next-line @typescript-eslint/class-literal-property-style
|
|
8
|
+
get domEventType() {
|
|
9
|
+
return 'contextmenu';
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Fires `contextmenu` on the view document for the DOM event.
|
|
13
|
+
*/
|
|
14
|
+
onDomEvent(domEvent) {
|
|
15
|
+
this.fire(domEvent.type, domEvent);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=contextMenuObserver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contextMenuObserver.js","sourceRoot":"","sources":["../../src/contextMenu/contextMenuObserver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAiC,MAAM,WAAW,CAAC;AAE5E;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,mBAAoB,SAAQ,gBAA+B;IAC/E,2EAA2E;IAC3E,2EAA2E;IAC3E,IAAW,YAAY;QACtB,OAAO,aAAa,CAAC;IACtB,CAAC;IAED;;OAEG;IACI,UAAU,CAAC,QAAoB;QACrC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACpC,CAAC;CACD"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Plugin, type ModelElement, type RectSource, type ViewElement } from 'ckeditor5';
|
|
2
|
+
import ElementMenu from '../elementMenu.js';
|
|
3
|
+
/**
|
|
4
|
+
* Shows the menu of an element when the user right-clicks it, or opens the context menu with the keyboard (the menu
|
|
5
|
+
* key, or Shift+F10) while the cursor is in it.
|
|
6
|
+
*
|
|
7
|
+
* The items come from the `elementContextMenu` editor config option only (see `ElementMenuConfig`): commands, submenus
|
|
8
|
+
* and `'|'` separators. Without it, or when it returns no items for an
|
|
9
|
+
* element, the native context menu shows. The menu itself is shown by the `ElementMenu` plugin.
|
|
10
|
+
*/
|
|
11
|
+
export default class ElementContextMenu extends Plugin {
|
|
12
|
+
static get requires(): readonly [typeof ElementMenu];
|
|
13
|
+
static get pluginName(): 'ElementContextMenu';
|
|
14
|
+
init(): void;
|
|
15
|
+
/**
|
|
16
|
+
* Opens the menu of the element next to the target (e.g. a button, or a `DOMRect` in viewport coordinates), with
|
|
17
|
+
* the items from the `elementContextMenu` config option.
|
|
18
|
+
*
|
|
19
|
+
* Returns `false` when there are no items, so the caller can let the native context menu show instead.
|
|
20
|
+
*/
|
|
21
|
+
open(element: ModelElement, target: RectSource): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Opens the menu of the element at the selection (the selected element, or the element with the cursor), next to
|
|
24
|
+
* the selection.
|
|
25
|
+
*
|
|
26
|
+
* Returns `false` when there is no such element or no items.
|
|
27
|
+
*/
|
|
28
|
+
openAtSelection(): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Returns the closest model element mapped to the given view element or its ancestors, skipping the root.
|
|
31
|
+
*/
|
|
32
|
+
getModelElement(viewElement: ViewElement): ModelElement | null;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=elementContextMenu.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elementContextMenu.d.ts","sourceRoot":"","sources":["../../src/contextMenu/elementContextMenu.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,YAAY,EAAE,KAAK,UAAU,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAGzF,OAAO,WAAW,MAAM,mBAAmB,CAAC;AAG5C;;;;;;;GAOG;AACH,MAAM,CAAC,OAAO,OAAO,kBAAmB,SAAQ,MAAM;IACrD,WAAkB,QAAQ,IAAI,SAAS,CAAC,OAAO,WAAW,CAAC,CAE1D;IAED,WAAkB,UAAU,IAAI,oBAAoB,CAEnD;IAEM,IAAI,IAAI,IAAI;IAmCnB;;;;;OAKG;IACI,IAAI,CAAC,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,GAAG,OAAO;IAY/D;;;;;OAKG;IACI,eAAe,IAAI,OAAO;IAWjC;;OAEG;IACI,eAAe,CAAC,WAAW,EAAE,WAAW,GAAG,YAAY,GAAG,IAAI;CAOrE"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { Plugin } from 'ckeditor5';
|
|
2
|
+
import { getElementAtSelection, getElementsAround, isInDocument } from 'ckeditor5-elements-core';
|
|
3
|
+
import { getDomTarget } from '../domTarget.js';
|
|
4
|
+
import ElementMenu from '../elementMenu.js';
|
|
5
|
+
import ContextMenuObserver, {} from './contextMenuObserver.js';
|
|
6
|
+
/**
|
|
7
|
+
* Shows the menu of an element when the user right-clicks it, or opens the context menu with the keyboard (the menu
|
|
8
|
+
* key, or Shift+F10) while the cursor is in it.
|
|
9
|
+
*
|
|
10
|
+
* The items come from the `elementContextMenu` editor config option only (see `ElementMenuConfig`): commands, submenus
|
|
11
|
+
* and `'|'` separators. Without it, or when it returns no items for an
|
|
12
|
+
* element, the native context menu shows. The menu itself is shown by the `ElementMenu` plugin.
|
|
13
|
+
*/
|
|
14
|
+
export default class ElementContextMenu extends Plugin {
|
|
15
|
+
static get requires() {
|
|
16
|
+
return [ElementMenu];
|
|
17
|
+
}
|
|
18
|
+
static get pluginName() {
|
|
19
|
+
return 'ElementContextMenu';
|
|
20
|
+
}
|
|
21
|
+
init() {
|
|
22
|
+
const editor = this.editor;
|
|
23
|
+
const editingView = editor.editing.view;
|
|
24
|
+
editingView.addObserver(ContextMenuObserver);
|
|
25
|
+
this.listenTo(editingView.document, 'contextmenu', (evt, data) => {
|
|
26
|
+
const { domEvent } = data;
|
|
27
|
+
const element = this.getModelElement(data.target);
|
|
28
|
+
// A context menu opened with the keyboard (the menu key, or Shift+F10 in some browsers) targets the editable
|
|
29
|
+
// itself, not the element at the cursor. A right-click outside any element keeps the native menu.
|
|
30
|
+
const isOpen = element
|
|
31
|
+
? this.open(element, new DOMRect(domEvent.clientX, domEvent.clientY, 0, 0))
|
|
32
|
+
: domEvent.button !== 2 && this.openAtSelection();
|
|
33
|
+
if (isOpen) {
|
|
34
|
+
data.preventDefault();
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
// Not every browser opens the context menu on Shift+F10 (e.g. on macOS), so handle it in all of them.
|
|
38
|
+
editor.keystrokes.set('Shift+F10', (data, cancel) => {
|
|
39
|
+
if (this.openAtSelection()) {
|
|
40
|
+
cancel();
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
if (typeof editor.config.get('elementContextMenu') === 'function') {
|
|
44
|
+
editor.accessibility.addKeystrokeInfos({
|
|
45
|
+
keystrokes: [{ label: editor.t('Open the menu of the element at the cursor'), keystroke: 'Shift+F10' }]
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Opens the menu of the element next to the target (e.g. a button, or a `DOMRect` in viewport coordinates), with
|
|
51
|
+
* the items from the `elementContextMenu` config option.
|
|
52
|
+
*
|
|
53
|
+
* Returns `false` when there are no items, so the caller can let the native context menu show instead.
|
|
54
|
+
*/
|
|
55
|
+
open(element, target) {
|
|
56
|
+
const config = this.editor.config.get('elementContextMenu');
|
|
57
|
+
if (typeof config !== 'function') {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
return this.editor.plugins
|
|
61
|
+
.get(ElementMenu)
|
|
62
|
+
.open(element, target, config, { label: this.editor.t('Element menu') });
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Opens the menu of the element at the selection (the selected element, or the element with the cursor), next to
|
|
66
|
+
* the selection.
|
|
67
|
+
*
|
|
68
|
+
* Returns `false` when there is no such element or no items.
|
|
69
|
+
*/
|
|
70
|
+
openAtSelection() {
|
|
71
|
+
const element = getElementAtSelection(this.editor.model.document.selection);
|
|
72
|
+
const target = getDomTarget(this.editor);
|
|
73
|
+
if (!element || !isInDocument(element) || !target) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
return this.open(element, target);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Returns the closest model element mapped to the given view element or its ancestors, skipping the root.
|
|
80
|
+
*/
|
|
81
|
+
getModelElement(viewElement) {
|
|
82
|
+
for (const { element } of getElementsAround(this.editor.editing.mapper, viewElement)) {
|
|
83
|
+
return element;
|
|
84
|
+
}
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=elementContextMenu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elementContextMenu.js","sourceRoot":"","sources":["../../src/contextMenu/elementContextMenu.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type Editor } from 'ckeditor5';
|
|
2
|
+
import type { ElementOrPosition } from 'ckeditor5-elements-core';
|
|
3
|
+
/**
|
|
4
|
+
* Returns what a menu for the target is shown next to: the DOM element of an element, or the DOM range of a position.
|
|
5
|
+
* Without a target, the ones of the selection: its selected element, or its range. `null` when it is not rendered.
|
|
6
|
+
*/
|
|
7
|
+
export declare function getDomTarget(editor: Editor, target?: ElementOrPosition): HTMLElement | Range | null;
|
|
8
|
+
//# sourceMappingURL=domTarget.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"domTarget.d.ts","sourceRoot":"","sources":["../src/domTarget.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,MAAM,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAEjE;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,iBAAiB,GAAG,WAAW,GAAG,KAAK,GAAG,IAAI,CAmBnG"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ModelPosition } from 'ckeditor5';
|
|
2
|
+
/**
|
|
3
|
+
* Returns what a menu for the target is shown next to: the DOM element of an element, or the DOM range of a position.
|
|
4
|
+
* Without a target, the ones of the selection: its selected element, or its range. `null` when it is not rendered.
|
|
5
|
+
*/
|
|
6
|
+
export function getDomTarget(editor, target) {
|
|
7
|
+
const { mapper, view } = editor.editing;
|
|
8
|
+
if (target instanceof ModelPosition) {
|
|
9
|
+
return view.domConverter.viewRangeToDom(view.createRange(mapper.toViewPosition(target)));
|
|
10
|
+
}
|
|
11
|
+
const element = target ?? editor.model.document.selection.getSelectedElement();
|
|
12
|
+
if (element) {
|
|
13
|
+
const viewElement = mapper.toViewElement(element);
|
|
14
|
+
const domElement = viewElement && view.domConverter.mapViewToDom(viewElement);
|
|
15
|
+
return domElement instanceof HTMLElement ? domElement : null;
|
|
16
|
+
}
|
|
17
|
+
const viewRange = view.document.selection.getFirstRange();
|
|
18
|
+
return viewRange ? view.domConverter.viewRangeToDom(viewRange) : null;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=domTarget.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"domTarget.js","sourceRoot":"","sources":["../src/domTarget.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAe,MAAM,WAAW,CAAC;AAGvD;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,MAAc,EAAE,MAA0B;IACtE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC;IAExC,IAAI,MAAM,YAAY,aAAa,EAAE,CAAC;QACrC,OAAO,IAAI,CAAC,YAAY,CAAC,cAAc,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAC1F,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,IAAI,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,kBAAkB,EAAE,CAAC;IAE/E,IAAI,OAAO,EAAE,CAAC;QACb,MAAM,WAAW,GAAG,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QAClD,MAAM,UAAU,GAAG,WAAW,IAAI,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;QAE9E,OAAO,UAAU,YAAY,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;IAC9D,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,aAAa,EAAE,CAAC;IAE1D,OAAO,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACvE,CAAC"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { ContextualBalloon, Notification, Plugin, type Editor, type FocusableView, type ModelElement, type RectSource } from 'ckeditor5';
|
|
2
|
+
import { type ElementOrPositionCommand } from 'ckeditor5-elements-core';
|
|
3
|
+
/**
|
|
4
|
+
* A submenu of an element menu. Missing items are skipped, as in the menu.
|
|
5
|
+
*/
|
|
6
|
+
export interface ElementSubmenu {
|
|
7
|
+
title: string;
|
|
8
|
+
/**
|
|
9
|
+
* The icon (SVG string) shown next to the title.
|
|
10
|
+
*/
|
|
11
|
+
icon?: string;
|
|
12
|
+
items: (ElementMenuItem | null | undefined)[];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* An item of an element menu:
|
|
16
|
+
*
|
|
17
|
+
* * a command, shown as a button with its `title` and `icon`, enabled and "on" according to its
|
|
18
|
+
* {@link ElementOrPositionCommand#getState state} for the element,
|
|
19
|
+
* * a submenu,
|
|
20
|
+
* * `'|'`, a separator. Separators at the start or the end of a menu, and repeated ones, are not shown, so a group of
|
|
21
|
+
* items can start with one.
|
|
22
|
+
*/
|
|
23
|
+
export type ElementMenuItem = ElementOrPositionCommand | ElementSubmenu | '|';
|
|
24
|
+
/**
|
|
25
|
+
* Returns the items of the menu of the given element, e.g. as the `elementContextMenu` or `elementBreadcrumbs.menu` editor
|
|
26
|
+
* config option. Missing items (e.g. commands that are not registered) are skipped. No items means no menu.
|
|
27
|
+
*/
|
|
28
|
+
export type ElementMenuConfig = (element: ModelElement, editor: Editor) => (ElementMenuItem | null | undefined)[];
|
|
29
|
+
/**
|
|
30
|
+
* The options of {@link ElementMenu#open} and {@link ElementMenu#show}.
|
|
31
|
+
*/
|
|
32
|
+
export interface ElementMenuShowOptions {
|
|
33
|
+
/**
|
|
34
|
+
* The accessible name of the menu of an element (see {@link ElementMenu#open}). Defaults to "Element menu".
|
|
35
|
+
*/
|
|
36
|
+
label?: string;
|
|
37
|
+
/**
|
|
38
|
+
* Called when the document data changes while the menu is open. When it returns `true`, the menu closes, e.g.
|
|
39
|
+
* because the element it is for was removed.
|
|
40
|
+
*/
|
|
41
|
+
isObsolete?: () => boolean;
|
|
42
|
+
/**
|
|
43
|
+
* What gets the focus when the menu is closed with Esc, e.g. the button that opened the menu. Defaults to the editor.
|
|
44
|
+
*/
|
|
45
|
+
returnFocusTo?: {
|
|
46
|
+
focus(): void;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Called when the menu closes, for any reason: Esc, a click outside, an executed item, or another menu replacing it.
|
|
50
|
+
*/
|
|
51
|
+
onHide?: () => void;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Shows menus in a balloon: the menu of an element, built from commands, submenus and separators (see {@link open}),
|
|
55
|
+
* or any view, e.g. the quick insert search (see {@link show}).
|
|
56
|
+
*
|
|
57
|
+
* The element context menu, the breadcrumbs and quick insert show their menus with it. The menu of an element is
|
|
58
|
+
* CKEditor's dropdown menu (see {@link ElementMenuView}).
|
|
59
|
+
*
|
|
60
|
+
* Executing an item closes the menu. Esc and clicking outside close it too; Esc returns the focus to the editor, or to
|
|
61
|
+
* {@link ElementMenuShowOptions.returnFocusTo}.
|
|
62
|
+
*/
|
|
63
|
+
export default class ElementMenu extends Plugin {
|
|
64
|
+
/**
|
|
65
|
+
* The view in the open menu, if any.
|
|
66
|
+
*/
|
|
67
|
+
view: FocusableView | null;
|
|
68
|
+
private _keystrokes;
|
|
69
|
+
private _isObsolete;
|
|
70
|
+
private _onHide;
|
|
71
|
+
static get requires(): readonly [typeof ContextualBalloon, typeof Notification];
|
|
72
|
+
static get pluginName(): 'ElementMenu';
|
|
73
|
+
init(): void;
|
|
74
|
+
/**
|
|
75
|
+
* Opens the menu of the element next to the target (e.g. a button, or a `DOMRect` in viewport coordinates), with
|
|
76
|
+
* the items from the config callback. The menu closes when the element is removed.
|
|
77
|
+
*
|
|
78
|
+
* Returns `false` when there are no items.
|
|
79
|
+
*/
|
|
80
|
+
open(element: ModelElement, target: RectSource, config: ElementMenuConfig, { label, isObsolete, ...options }?: ElementMenuShowOptions): boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Shows the view (e.g. a menu) next to the target (e.g. a button, or a `DOMRect` in viewport coordinates), and
|
|
83
|
+
* focuses it. The menu closes when the view, or an item of CKEditor's dropdown menu in it, fires `execute`.
|
|
84
|
+
*/
|
|
85
|
+
show(view: FocusableView, target: RectSource, { isObsolete, returnFocusTo, onHide }?: ElementMenuShowOptions): void;
|
|
86
|
+
/**
|
|
87
|
+
* Hides the open menu, if any.
|
|
88
|
+
*/
|
|
89
|
+
hide(): void;
|
|
90
|
+
destroy(): void;
|
|
91
|
+
private get _balloon();
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=elementMenu.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elementMenu.d.ts","sourceRoot":"","sources":["../src/elementMenu.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,iBAAiB,EAGjB,YAAY,EACZ,MAAM,EAEN,KAAK,MAAM,EACX,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,MAAM,WAAW,CAAC;AACnB,OAAO,EAAgB,KAAK,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AAGtF;;GAEG;AACH,MAAM,WAAW,cAAc;IAC9B,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,KAAK,EAAE,CAAC,eAAe,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,CAAC;CAC9C;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,eAAe,GAAG,wBAAwB,GAAG,cAAc,GAAG,GAAG,CAAC;AAE9E;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC,eAAe,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,CAAC;AAElH;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACtC;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC;IAE3B;;OAEG;IACH,aAAa,CAAC,EAAE;QAAE,KAAK,IAAI,IAAI,CAAA;KAAE,CAAC;IAElC;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;CACpB;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,OAAO,OAAO,WAAY,SAAQ,MAAM;IAC9C;;OAEG;IACI,IAAI,EAAE,aAAa,GAAG,IAAI,CAAQ;IAEzC,OAAO,CAAC,WAAW,CAAiC;IACpD,OAAO,CAAC,WAAW,CAAgC;IACnD,OAAO,CAAC,OAAO,CAA6B;IAE5C,WAAkB,QAAQ,IAAI,SAAS,CAAC,OAAO,iBAAiB,EAAE,OAAO,YAAY,CAAC,CAGrF;IAED,WAAkB,UAAU,IAAI,aAAa,CAE5C;IAEM,IAAI,IAAI,IAAI;IAQnB;;;;;OAKG;IACI,IAAI,CACV,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,UAAU,EAClB,MAAM,EAAE,iBAAiB,EACzB,EAAE,KAAqC,EAAE,UAAU,EAAE,GAAG,OAAO,EAAE,GAAE,sBAA2B,GAC5F,OAAO;IAwBV;;;OAGG;IACI,IAAI,CACV,IAAI,EAAE,aAAa,EACnB,MAAM,EAAE,UAAU,EAClB,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,EAAE,GAAE,sBAA2B,GAChE,IAAI;IAqDP;;OAEG;IACI,IAAI,IAAI,IAAI;IAuBH,OAAO,IAAI,IAAI;IAK/B,OAAO,KAAK,QAAQ,GAEnB;CACD"}
|