ckeditor5-elements-clickable 0.0.0-stage → 49.0.0-alpha.2
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 +32 -2
- package/dist/augmentation.d.ts +13 -0
- package/dist/augmentation.d.ts.map +1 -0
- package/dist/augmentation.js +2 -0
- package/dist/augmentation.js.map +1 -0
- package/dist/doubleClickObserver.d.ts +20 -0
- package/dist/doubleClickObserver.d.ts.map +1 -0
- package/dist/doubleClickObserver.js +19 -0
- package/dist/doubleClickObserver.js.map +1 -0
- package/dist/elementClickable.d.ts +57 -0
- package/dist/elementClickable.d.ts.map +1 -0
- package/dist/elementClickable.js +60 -0
- package/dist/elementClickable.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/package.json +45 -3
- package/src/augmentation.ts +14 -0
- package/src/doubleClickObserver.ts +28 -0
- package/src/elementClickable.ts +117 -0
- package/src/index.ts +18 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ivan Kildyushov
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,33 @@
|
|
|
1
|
-
#
|
|
1
|
+
# ckeditor5-elements-clickable
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Clickable elements for CKEditor 5 Elements: `ElementClickable` calls a function, with the model element, when an element
|
|
4
|
+
that matches a model name or a filter function is clicked or double-clicked.
|
|
5
|
+
|
|
6
|
+
## Installation
|
|
7
|
+
|
|
8
|
+
This package is part of `ckeditor5-elements`. Install the whole package to use it:
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
npm install ckeditor5 ckeditor5-elements
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Usage
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
import { ElementClickable } from 'ckeditor5-elements';
|
|
18
|
+
|
|
19
|
+
// In the editor config:
|
|
20
|
+
plugins: [..., ElementClickable],
|
|
21
|
+
elementClickables: [
|
|
22
|
+
// By name. The default event is `click`.
|
|
23
|
+
{ element: 'imageBlock', callback: (element, editor) => console.log(element.getAttribute('src')) },
|
|
24
|
+
// By a filter, on double click.
|
|
25
|
+
{ element: element => element.name.startsWith('heading'), event: 'dblclick', callback: (element, editor) => {} }
|
|
26
|
+
]
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
See the [Clickable elements guide](https://ivankild.github.io/ckeditor5-elements/guide/clickable) of the documentation.
|
|
30
|
+
|
|
31
|
+
## License
|
|
32
|
+
|
|
33
|
+
MIT
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ElementClickable, ElementClickableDefinition } from './index.js';
|
|
2
|
+
declare module 'ckeditor5' {
|
|
3
|
+
interface PluginsMap {
|
|
4
|
+
[ElementClickable.pluginName]: ElementClickable;
|
|
5
|
+
}
|
|
6
|
+
interface EditorConfig {
|
|
7
|
+
/**
|
|
8
|
+
* The elements that react to clicks and double clicks. See {@link ElementClickable}.
|
|
9
|
+
*/
|
|
10
|
+
elementClickables?: ElementClickableDefinition[];
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=augmentation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"augmentation.d.ts","sourceRoot":"","sources":["../src/augmentation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC;AAE/E,OAAO,QAAQ,WAAW,CAAC;IAC1B,UAAU,UAAU;QACnB,CAAC,gBAAgB,CAAC,UAAU,CAAC,EAAE,gBAAgB,CAAC;KAChD;IAED,UAAU,YAAY;QACrB;;WAEG;QACH,iBAAiB,CAAC,EAAE,0BAA0B,EAAE,CAAC;KACjD;CACD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"augmentation.js","sourceRoot":"","sources":["../src/augmentation.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { DomEventObserver, type ViewDocumentDomEventData } from 'ckeditor5';
|
|
2
|
+
/**
|
|
3
|
+
* Fires `dblclick` on the view document when the user double-clicks in the editing view. (CKEditor has an observer for
|
|
4
|
+
* `click`, but not for `dblclick`.)
|
|
5
|
+
*/
|
|
6
|
+
export default class DoubleClickObserver extends DomEventObserver<'dblclick'> {
|
|
7
|
+
get domEventType(): 'dblclick';
|
|
8
|
+
/**
|
|
9
|
+
* Fires `dblclick` on the view document for the DOM event.
|
|
10
|
+
*/
|
|
11
|
+
onDomEvent(domEvent: MouseEvent): void;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Fired on the view document by the {@link DoubleClickObserver}.
|
|
15
|
+
*/
|
|
16
|
+
export interface ViewDocumentDoubleClickEvent {
|
|
17
|
+
name: 'dblclick';
|
|
18
|
+
args: [data: ViewDocumentDomEventData<MouseEvent>];
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=doubleClickObserver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doubleClickObserver.d.ts","sourceRoot":"","sources":["../src/doubleClickObserver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,KAAK,wBAAwB,EAAE,MAAM,WAAW,CAAC;AAE5E;;;GAGG;AACH,MAAM,CAAC,OAAO,OAAO,mBAAoB,SAAQ,gBAAgB,CAAC,UAAU,CAAC;IAG5E,IAAW,YAAY,IAAI,UAAU,CAEpC;IAED;;OAEG;IACI,UAAU,CAAC,QAAQ,EAAE,UAAU,GAAG,IAAI;CAG7C;AAED;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC5C,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,CAAC,IAAI,EAAE,wBAAwB,CAAC,UAAU,CAAC,CAAC,CAAC;CACnD"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { DomEventObserver } from 'ckeditor5';
|
|
2
|
+
/**
|
|
3
|
+
* Fires `dblclick` on the view document when the user double-clicks in the editing view. (CKEditor has an observer for
|
|
4
|
+
* `click`, but not for `dblclick`.)
|
|
5
|
+
*/
|
|
6
|
+
export default class DoubleClickObserver extends DomEventObserver {
|
|
7
|
+
// The base class declares it as an accessor, so it cannot be a field here.
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/class-literal-property-style
|
|
9
|
+
get domEventType() {
|
|
10
|
+
return 'dblclick';
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Fires `dblclick` on the view document for the DOM event.
|
|
14
|
+
*/
|
|
15
|
+
onDomEvent(domEvent) {
|
|
16
|
+
this.fire(domEvent.type, domEvent);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=doubleClickObserver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doubleClickObserver.js","sourceRoot":"","sources":["../src/doubleClickObserver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAiC,MAAM,WAAW,CAAC;AAE5E;;;GAGG;AACH,MAAM,CAAC,OAAO,OAAO,mBAAoB,SAAQ,gBAA4B;IAC5E,2EAA2E;IAC3E,2EAA2E;IAC3E,IAAW,YAAY;QACtB,OAAO,UAAU,CAAC;IACnB,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,57 @@
|
|
|
1
|
+
import { Plugin, type Editor, type ModelElement, type ViewElement } from 'ckeditor5';
|
|
2
|
+
import { type ElementMatcher } from 'ckeditor5-elements-core';
|
|
3
|
+
/**
|
|
4
|
+
* The mouse events an element can be made clickable with.
|
|
5
|
+
*/
|
|
6
|
+
export type ElementClickableEvent = 'click' | 'dblclick';
|
|
7
|
+
/**
|
|
8
|
+
* Makes the elements that match `element` react to clicks.
|
|
9
|
+
*/
|
|
10
|
+
export interface ElementClickableDefinition {
|
|
11
|
+
/**
|
|
12
|
+
* The elements the definition is for: the name of a model element (e.g. `'imageBlock'`), or a function that returns
|
|
13
|
+
* whether it is for the given element (e.g. `element => element.hasAttribute('linkHref')`).
|
|
14
|
+
*/
|
|
15
|
+
element: ElementMatcher;
|
|
16
|
+
/**
|
|
17
|
+
* The mouse event: `'click'` (the default) or `'dblclick'`.
|
|
18
|
+
*/
|
|
19
|
+
event?: ElementClickableEvent;
|
|
20
|
+
/**
|
|
21
|
+
* Called with the element that was clicked, the editor, and the DOM event.
|
|
22
|
+
*/
|
|
23
|
+
callback: (element: ModelElement, editor: Editor, domEvent: MouseEvent) => void;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Calls a function when an element is clicked or double-clicked, with the model element. Elements are matched by name or
|
|
27
|
+
* by a filter function, and the definitions are the `elementClickables` editor config option (see
|
|
28
|
+
* {@link ElementClickableDefinition}):
|
|
29
|
+
*
|
|
30
|
+
* ```ts
|
|
31
|
+
* elementClickables: [
|
|
32
|
+
* { element: 'imageBlock', callback: (element, editor) => console.log(element.getAttribute('src')) },
|
|
33
|
+
* { element: element => element.name.startsWith('heading'), event: 'dblclick', callback: edit }
|
|
34
|
+
* ];
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* The click is matched against the element that was clicked and its ancestors, the innermost first: the first element
|
|
38
|
+
* that matches a definition for the event calls its callback, and the event goes no further. For two definitions that
|
|
39
|
+
* match the same element, the first one in the config wins.
|
|
40
|
+
*
|
|
41
|
+
* It works in read-only mode too. The click still does what it does in the editor, e.g. selects an image: the plugin
|
|
42
|
+
* only reports it, before the other plugins handle it (some of them stop the event), and does not stop it.
|
|
43
|
+
*/
|
|
44
|
+
export default class ElementClickable extends Plugin {
|
|
45
|
+
static get pluginName(): 'ElementClickable';
|
|
46
|
+
init(): void;
|
|
47
|
+
/**
|
|
48
|
+
* Returns the definition and the element that a click on the view element is for: the innermost element, among the
|
|
49
|
+
* view element and its ancestors, that matches a definition for the event. `null` when there is none.
|
|
50
|
+
*/
|
|
51
|
+
find(viewElement: ViewElement, event?: ElementClickableEvent): {
|
|
52
|
+
element: ModelElement;
|
|
53
|
+
definition: ElementClickableDefinition;
|
|
54
|
+
} | null;
|
|
55
|
+
private _handle;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=elementClickable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elementClickable.d.ts","sourceRoot":"","sources":["../src/elementClickable.ts"],"names":[],"mappings":"AAAA,OAAO,EAEN,MAAM,EACN,KAAK,MAAM,EACX,KAAK,YAAY,EAEjB,KAAK,WAAW,EAChB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAqC,KAAK,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAGjG;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG,OAAO,GAAG,UAAU,CAAC;AAEzD;;GAEG;AACH,MAAM,WAAW,0BAA0B;IAC1C;;;OAGG;IACH,OAAO,EAAE,cAAc,CAAC;IAExB;;OAEG;IACH,KAAK,CAAC,EAAE,qBAAqB,CAAC;IAE9B;;OAEG;IACH,QAAQ,EAAE,CAAC,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,KAAK,IAAI,CAAC;CAChF;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,OAAO,OAAO,gBAAiB,SAAQ,MAAM;IACnD,WAAkB,UAAU,IAAI,kBAAkB,CAEjD;IAEM,IAAI,IAAI,IAAI;IA0BnB;;;OAGG;IACI,IAAI,CACV,WAAW,EAAE,WAAW,EACxB,KAAK,GAAE,qBAA+B,GACpC;QAAE,OAAO,EAAE,YAAY,CAAC;QAAC,UAAU,EAAE,0BAA0B,CAAA;KAAE,GAAG,IAAI;IAiB3E,OAAO,CAAC,OAAO;CAKf"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { ClickObserver, Plugin } from 'ckeditor5';
|
|
2
|
+
import { getElementsAround, matchesElement } from 'ckeditor5-elements-core';
|
|
3
|
+
import DoubleClickObserver, {} from './doubleClickObserver.js';
|
|
4
|
+
/**
|
|
5
|
+
* Calls a function when an element is clicked or double-clicked, with the model element. Elements are matched by name or
|
|
6
|
+
* by a filter function, and the definitions are the `elementClickables` editor config option (see
|
|
7
|
+
* {@link ElementClickableDefinition}):
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* elementClickables: [
|
|
11
|
+
* { element: 'imageBlock', callback: (element, editor) => console.log(element.getAttribute('src')) },
|
|
12
|
+
* { element: element => element.name.startsWith('heading'), event: 'dblclick', callback: edit }
|
|
13
|
+
* ];
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* The click is matched against the element that was clicked and its ancestors, the innermost first: the first element
|
|
17
|
+
* that matches a definition for the event calls its callback, and the event goes no further. For two definitions that
|
|
18
|
+
* match the same element, the first one in the config wins.
|
|
19
|
+
*
|
|
20
|
+
* It works in read-only mode too. The click still does what it does in the editor, e.g. selects an image: the plugin
|
|
21
|
+
* only reports it, before the other plugins handle it (some of them stop the event), and does not stop it.
|
|
22
|
+
*/
|
|
23
|
+
export default class ElementClickable extends Plugin {
|
|
24
|
+
static get pluginName() {
|
|
25
|
+
return 'ElementClickable';
|
|
26
|
+
}
|
|
27
|
+
init() {
|
|
28
|
+
const view = this.editor.editing.view;
|
|
29
|
+
view.addObserver(ClickObserver);
|
|
30
|
+
view.addObserver(DoubleClickObserver);
|
|
31
|
+
// With the highest priority, before other plugins: some stop the click, e.g. CKEditor's link handling stops the
|
|
32
|
+
// click on a link, with a high priority. The plugin reports the click and does not stop it.
|
|
33
|
+
this.listenTo(view.document, 'click', (evt, data) => {
|
|
34
|
+
this._handle('click', data.target, data.domEvent);
|
|
35
|
+
}, { priority: 'highest' });
|
|
36
|
+
this.listenTo(view.document, 'dblclick', (evt, data) => {
|
|
37
|
+
this._handle('dblclick', data.target, data.domEvent);
|
|
38
|
+
}, { priority: 'highest' });
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Returns the definition and the element that a click on the view element is for: the innermost element, among the
|
|
42
|
+
* view element and its ancestors, that matches a definition for the event. `null` when there is none.
|
|
43
|
+
*/
|
|
44
|
+
find(viewElement, event = 'click') {
|
|
45
|
+
const mapper = this.editor.editing.mapper;
|
|
46
|
+
const definitions = (this.editor.config.get('elementClickables') ?? []).filter(definition => (definition.event ?? 'click') === event);
|
|
47
|
+
for (const { element } of getElementsAround(mapper, viewElement)) {
|
|
48
|
+
const definition = definitions.find(({ element: matcher }) => matchesElement(matcher, element));
|
|
49
|
+
if (definition) {
|
|
50
|
+
return { element, definition };
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
_handle(event, target, domEvent) {
|
|
56
|
+
const found = this.isEnabled ? this.find(target, event) : null;
|
|
57
|
+
found?.definition.callback(found.element, this.editor, domEvent);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=elementClickable.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elementClickable.js","sourceRoot":"","sources":["../src/elementClickable.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,aAAa,EACb,MAAM,EAKN,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAuB,MAAM,yBAAyB,CAAC;AACjG,OAAO,mBAAmB,EAAE,EAAqC,MAAM,0BAA0B,CAAC;AA4BlG;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,OAAO,OAAO,gBAAiB,SAAQ,MAAM;IAC5C,MAAM,KAAK,UAAU;QAC3B,OAAO,kBAA2B,CAAC;IACpC,CAAC;IAEM,IAAI;QACV,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;QAEtC,IAAI,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC;QAChC,IAAI,CAAC,WAAW,CAAC,mBAAmB,CAAC,CAAC;QAEtC,gHAAgH;QAChH,4FAA4F;QAC5F,IAAI,CAAC,QAAQ,CACZ,IAAI,CAAC,QAAQ,EACb,OAAO,EACP,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE;YACb,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QACnD,CAAC,EACD,EAAE,QAAQ,EAAE,SAAS,EAAE,CACvB,CAAC;QACF,IAAI,CAAC,QAAQ,CACZ,IAAI,CAAC,QAAQ,EACb,UAAU,EACV,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE;YACb,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QACtD,CAAC,EACD,EAAE,QAAQ,EAAE,SAAS,EAAE,CACvB,CAAC;IACH,CAAC;IAED;;;OAGG;IACI,IAAI,CACV,WAAwB,EACxB,QAA+B,OAAO;QAEtC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;QAC1C,MAAM,WAAW,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,mBAAmB,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAC7E,UAAU,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,KAAK,IAAI,OAAO,CAAC,KAAK,KAAK,CACrD,CAAC;QAEF,KAAK,MAAM,EAAE,OAAO,EAAE,IAAI,iBAAiB,CAAC,MAAM,EAAE,WAAW,CAAC,EAAE,CAAC;YAClE,MAAM,UAAU,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;YAEhG,IAAI,UAAU,EAAE,CAAC;gBAChB,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;YAChC,CAAC;QACF,CAAC;QAED,OAAO,IAAI,CAAC;IACb,CAAC;IAEO,OAAO,CAAC,KAA4B,EAAE,MAAmB,EAAE,QAAoB;QACtF,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAE/D,KAAK,EAAE,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAClE,CAAC;CACD"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clickable elements: call a function, with the model element, when an element that matches a name or a filter is
|
|
3
|
+
* clicked or double-clicked.
|
|
4
|
+
*
|
|
5
|
+
* @module ckeditor5-elements-clickable
|
|
6
|
+
*/
|
|
7
|
+
export { default as ElementClickable, type ElementClickableDefinition, type ElementClickableEvent } from './elementClickable.js';
|
|
8
|
+
export { default as DoubleClickObserver, type ViewDocumentDoubleClickEvent } from './doubleClickObserver.js';
|
|
9
|
+
import './augmentation.js';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EACN,OAAO,IAAI,gBAAgB,EAC3B,KAAK,0BAA0B,EAC/B,KAAK,qBAAqB,EAC1B,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,KAAK,4BAA4B,EAAE,MAAM,0BAA0B,CAAC;AAE7G,OAAO,mBAAmB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clickable elements: call a function, with the model element, when an element that matches a name or a filter is
|
|
3
|
+
* clicked or double-clicked.
|
|
4
|
+
*
|
|
5
|
+
* @module ckeditor5-elements-clickable
|
|
6
|
+
*/
|
|
7
|
+
// Plugins.
|
|
8
|
+
export { default as ElementClickable } from './elementClickable.js';
|
|
9
|
+
// Observers.
|
|
10
|
+
export { default as DoubleClickObserver } from './doubleClickObserver.js';
|
|
11
|
+
import './augmentation.js';
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,WAAW;AACX,OAAO,EACN,OAAO,IAAI,gBAAgB,EAG3B,MAAM,uBAAuB,CAAC;AAE/B,aAAa;AACb,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAqC,MAAM,0BAA0B,CAAC;AAE7G,OAAO,mBAAmB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,48 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ckeditor5-elements-clickable",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "49.0.0-alpha.2",
|
|
4
|
+
"description": "Clickable elements for CKEditor 5: call a function, with the model element, when an element that matches a name or a filter is clicked or double-clicked.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"ckeditor",
|
|
7
|
+
"ckeditor5",
|
|
8
|
+
"ckeditor 5",
|
|
9
|
+
"ckeditor5-feature",
|
|
10
|
+
"ckeditor5-plugin"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"author": "Ivan Kildyushov",
|
|
14
|
+
"homepage": "https://ivankild.github.io/ckeditor5-elements/guide/clickable",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/ivankild/ckeditor5-elements.git",
|
|
18
|
+
"directory": "packages/ckeditor5-elements-clickable"
|
|
19
|
+
},
|
|
20
|
+
"bugs": {
|
|
21
|
+
"url": "https://github.com/ivankild/ckeditor5-elements/issues"
|
|
22
|
+
},
|
|
23
|
+
"type": "module",
|
|
24
|
+
"main": "./dist/index.js",
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"exports": {
|
|
27
|
+
".": {
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"import": "./dist/index.js"
|
|
30
|
+
},
|
|
31
|
+
"./package.json": "./package.json"
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"dist",
|
|
35
|
+
"src",
|
|
36
|
+
"README.md"
|
|
37
|
+
],
|
|
38
|
+
"sideEffects": false,
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"ckeditor5-elements-core": "49.0.0-alpha.2"
|
|
41
|
+
},
|
|
42
|
+
"peerDependencies": {
|
|
43
|
+
"ckeditor5": "^49.0.0"
|
|
44
|
+
},
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "tsc --build"
|
|
47
|
+
}
|
|
6
48
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ElementClickable, ElementClickableDefinition } from './index.js';
|
|
2
|
+
|
|
3
|
+
declare module 'ckeditor5' {
|
|
4
|
+
interface PluginsMap {
|
|
5
|
+
[ElementClickable.pluginName]: ElementClickable;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
interface EditorConfig {
|
|
9
|
+
/**
|
|
10
|
+
* The elements that react to clicks and double clicks. See {@link ElementClickable}.
|
|
11
|
+
*/
|
|
12
|
+
elementClickables?: ElementClickableDefinition[];
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { DomEventObserver, type ViewDocumentDomEventData } from 'ckeditor5';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Fires `dblclick` on the view document when the user double-clicks in the editing view. (CKEditor has an observer for
|
|
5
|
+
* `click`, but not for `dblclick`.)
|
|
6
|
+
*/
|
|
7
|
+
export default class DoubleClickObserver extends DomEventObserver<'dblclick'> {
|
|
8
|
+
// The base class declares it as an accessor, so it cannot be a field here.
|
|
9
|
+
// eslint-disable-next-line @typescript-eslint/class-literal-property-style
|
|
10
|
+
public get domEventType(): 'dblclick' {
|
|
11
|
+
return 'dblclick';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Fires `dblclick` on the view document for the DOM event.
|
|
16
|
+
*/
|
|
17
|
+
public onDomEvent(domEvent: MouseEvent): void {
|
|
18
|
+
this.fire(domEvent.type, domEvent);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Fired on the view document by the {@link DoubleClickObserver}.
|
|
24
|
+
*/
|
|
25
|
+
export interface ViewDocumentDoubleClickEvent {
|
|
26
|
+
name: 'dblclick';
|
|
27
|
+
args: [data: ViewDocumentDomEventData<MouseEvent>];
|
|
28
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ClickObserver,
|
|
3
|
+
Plugin,
|
|
4
|
+
type Editor,
|
|
5
|
+
type ModelElement,
|
|
6
|
+
type ViewDocumentClickEvent,
|
|
7
|
+
type ViewElement
|
|
8
|
+
} from 'ckeditor5';
|
|
9
|
+
import { getElementsAround, matchesElement, type ElementMatcher } from 'ckeditor5-elements-core';
|
|
10
|
+
import DoubleClickObserver, { type ViewDocumentDoubleClickEvent } from './doubleClickObserver.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The mouse events an element can be made clickable with.
|
|
14
|
+
*/
|
|
15
|
+
export type ElementClickableEvent = 'click' | 'dblclick';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Makes the elements that match `element` react to clicks.
|
|
19
|
+
*/
|
|
20
|
+
export interface ElementClickableDefinition {
|
|
21
|
+
/**
|
|
22
|
+
* The elements the definition is for: the name of a model element (e.g. `'imageBlock'`), or a function that returns
|
|
23
|
+
* whether it is for the given element (e.g. `element => element.hasAttribute('linkHref')`).
|
|
24
|
+
*/
|
|
25
|
+
element: ElementMatcher;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The mouse event: `'click'` (the default) or `'dblclick'`.
|
|
29
|
+
*/
|
|
30
|
+
event?: ElementClickableEvent;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Called with the element that was clicked, the editor, and the DOM event.
|
|
34
|
+
*/
|
|
35
|
+
callback: (element: ModelElement, editor: Editor, domEvent: MouseEvent) => void;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Calls a function when an element is clicked or double-clicked, with the model element. Elements are matched by name or
|
|
40
|
+
* by a filter function, and the definitions are the `elementClickables` editor config option (see
|
|
41
|
+
* {@link ElementClickableDefinition}):
|
|
42
|
+
*
|
|
43
|
+
* ```ts
|
|
44
|
+
* elementClickables: [
|
|
45
|
+
* { element: 'imageBlock', callback: (element, editor) => console.log(element.getAttribute('src')) },
|
|
46
|
+
* { element: element => element.name.startsWith('heading'), event: 'dblclick', callback: edit }
|
|
47
|
+
* ];
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* The click is matched against the element that was clicked and its ancestors, the innermost first: the first element
|
|
51
|
+
* that matches a definition for the event calls its callback, and the event goes no further. For two definitions that
|
|
52
|
+
* match the same element, the first one in the config wins.
|
|
53
|
+
*
|
|
54
|
+
* It works in read-only mode too. The click still does what it does in the editor, e.g. selects an image: the plugin
|
|
55
|
+
* only reports it, before the other plugins handle it (some of them stop the event), and does not stop it.
|
|
56
|
+
*/
|
|
57
|
+
export default class ElementClickable extends Plugin {
|
|
58
|
+
public static get pluginName(): 'ElementClickable' {
|
|
59
|
+
return 'ElementClickable' as const;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
public init(): void {
|
|
63
|
+
const view = this.editor.editing.view;
|
|
64
|
+
|
|
65
|
+
view.addObserver(ClickObserver);
|
|
66
|
+
view.addObserver(DoubleClickObserver);
|
|
67
|
+
|
|
68
|
+
// With the highest priority, before other plugins: some stop the click, e.g. CKEditor's link handling stops the
|
|
69
|
+
// click on a link, with a high priority. The plugin reports the click and does not stop it.
|
|
70
|
+
this.listenTo<ViewDocumentClickEvent>(
|
|
71
|
+
view.document,
|
|
72
|
+
'click',
|
|
73
|
+
(evt, data) => {
|
|
74
|
+
this._handle('click', data.target, data.domEvent);
|
|
75
|
+
},
|
|
76
|
+
{ priority: 'highest' }
|
|
77
|
+
);
|
|
78
|
+
this.listenTo<ViewDocumentDoubleClickEvent>(
|
|
79
|
+
view.document,
|
|
80
|
+
'dblclick',
|
|
81
|
+
(evt, data) => {
|
|
82
|
+
this._handle('dblclick', data.target, data.domEvent);
|
|
83
|
+
},
|
|
84
|
+
{ priority: 'highest' }
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Returns the definition and the element that a click on the view element is for: the innermost element, among the
|
|
90
|
+
* view element and its ancestors, that matches a definition for the event. `null` when there is none.
|
|
91
|
+
*/
|
|
92
|
+
public find(
|
|
93
|
+
viewElement: ViewElement,
|
|
94
|
+
event: ElementClickableEvent = 'click'
|
|
95
|
+
): { element: ModelElement; definition: ElementClickableDefinition } | null {
|
|
96
|
+
const mapper = this.editor.editing.mapper;
|
|
97
|
+
const definitions = (this.editor.config.get('elementClickables') ?? []).filter(
|
|
98
|
+
definition => (definition.event ?? 'click') === event
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
for (const { element } of getElementsAround(mapper, viewElement)) {
|
|
102
|
+
const definition = definitions.find(({ element: matcher }) => matchesElement(matcher, element));
|
|
103
|
+
|
|
104
|
+
if (definition) {
|
|
105
|
+
return { element, definition };
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
private _handle(event: ElementClickableEvent, target: ViewElement, domEvent: MouseEvent): void {
|
|
113
|
+
const found = this.isEnabled ? this.find(target, event) : null;
|
|
114
|
+
|
|
115
|
+
found?.definition.callback(found.element, this.editor, domEvent);
|
|
116
|
+
}
|
|
117
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clickable elements: call a function, with the model element, when an element that matches a name or a filter is
|
|
3
|
+
* clicked or double-clicked.
|
|
4
|
+
*
|
|
5
|
+
* @module ckeditor5-elements-clickable
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Plugins.
|
|
9
|
+
export {
|
|
10
|
+
default as ElementClickable,
|
|
11
|
+
type ElementClickableDefinition,
|
|
12
|
+
type ElementClickableEvent
|
|
13
|
+
} from './elementClickable.js';
|
|
14
|
+
|
|
15
|
+
// Observers.
|
|
16
|
+
export { default as DoubleClickObserver, type ViewDocumentDoubleClickEvent } from './doubleClickObserver.js';
|
|
17
|
+
|
|
18
|
+
import './augmentation.js';
|