ckeditor5-elements-actions 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 +35 -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/elementActions.d.ts +18 -0
- package/dist/elementActions.d.ts.map +1 -0
- package/dist/elementActions.js +29 -0
- package/dist/elementActions.js.map +1 -0
- package/dist/elementDeleteCommand.d.ts +19 -0
- package/dist/elementDeleteCommand.d.ts.map +1 -0
- package/dist/elementDeleteCommand.js +47 -0
- package/dist/elementDeleteCommand.js.map +1 -0
- package/dist/elementDuplicateCommand.d.ts +22 -0
- package/dist/elementDuplicateCommand.d.ts.map +1 -0
- package/dist/elementDuplicateCommand.js +49 -0
- package/dist/elementDuplicateCommand.js.map +1 -0
- package/dist/elementMoveCommand.d.ts +32 -0
- package/dist/elementMoveCommand.d.ts.map +1 -0
- package/dist/elementMoveCommand.js +59 -0
- package/dist/elementMoveCommand.js.map +1 -0
- package/dist/icons.d.ts +20 -0
- package/dist/icons.d.ts.map +1 -0
- package/dist/icons.js +28 -0
- package/dist/icons.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/package.json +45 -3
- package/src/augmentation.ts +14 -0
- package/src/elementActions.ts +31 -0
- package/src/elementDeleteCommand.ts +58 -0
- package/src/elementDuplicateCommand.ts +64 -0
- package/src/elementMoveCommand.ts +74 -0
- package/src/icons.ts +35 -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,36 @@
|
|
|
1
|
-
#
|
|
1
|
+
# ckeditor5-elements-actions
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Element actions for CKEditor 5 Elements: `ElementActions` registers `moveElementUp`, `moveElementDown`,
|
|
4
|
+
`duplicateElement` and `deleteElement`, which move an element within its parent, insert an empty copy of it after it, or
|
|
5
|
+
delete it.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
This package is part of `ckeditor5-elements`. Install the whole package to use it:
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npm install ckeditor5 ckeditor5-elements
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { ElementActions, ElementContextMenu } from 'ckeditor5-elements';
|
|
19
|
+
import 'ckeditor5-elements/index.css';
|
|
20
|
+
|
|
21
|
+
// In the editor config:
|
|
22
|
+
plugins: [..., ElementActions, ElementContextMenu],
|
|
23
|
+
elementContextMenu: (element, editor) => [
|
|
24
|
+
editor.commands.get('moveElementUp'),
|
|
25
|
+
editor.commands.get('moveElementDown'),
|
|
26
|
+
'|',
|
|
27
|
+
editor.commands.get('duplicateElement'),
|
|
28
|
+
editor.commands.get('deleteElement')
|
|
29
|
+
]
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
See the [Actions guide](https://ivankild.github.io/ckeditor5-elements/guide/actions) of the documentation.
|
|
33
|
+
|
|
34
|
+
## License
|
|
35
|
+
|
|
36
|
+
MIT
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ElementActions, ElementDeleteCommand, ElementDuplicateCommand, ElementMoveCommand } from './index.js';
|
|
2
|
+
declare module 'ckeditor5' {
|
|
3
|
+
interface PluginsMap {
|
|
4
|
+
[ElementActions.pluginName]: ElementActions;
|
|
5
|
+
}
|
|
6
|
+
interface CommandsMap {
|
|
7
|
+
moveElementUp: ElementMoveCommand;
|
|
8
|
+
moveElementDown: ElementMoveCommand;
|
|
9
|
+
duplicateElement: ElementDuplicateCommand;
|
|
10
|
+
deleteElement: ElementDeleteCommand;
|
|
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,cAAc,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEpH,OAAO,QAAQ,WAAW,CAAC;IAC1B,UAAU,UAAU;QACnB,CAAC,cAAc,CAAC,UAAU,CAAC,EAAE,cAAc,CAAC;KAC5C;IAED,UAAU,WAAW;QACpB,aAAa,EAAE,kBAAkB,CAAC;QAClC,eAAe,EAAE,kBAAkB,CAAC;QACpC,gBAAgB,EAAE,uBAAuB,CAAC;QAC1C,aAAa,EAAE,oBAAoB,CAAC;KACpC;CACD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"augmentation.js","sourceRoot":"","sources":["../src/augmentation.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Plugin } from 'ckeditor5';
|
|
2
|
+
/**
|
|
3
|
+
* Registers commands that act on an element: `moveElementUp`, `moveElementDown`, `duplicateElement` and
|
|
4
|
+
* `deleteElement`.
|
|
5
|
+
*
|
|
6
|
+
* ```ts
|
|
7
|
+
* editor.execute('duplicateElement'); // The element at the selection.
|
|
8
|
+
* editor.commands.get('moveElementUp').executeFor(element); // The given element.
|
|
9
|
+
* ```
|
|
10
|
+
*
|
|
11
|
+
* The commands have titles and icons, so they can be menu items (e.g. in the `elementContextMenu` config of
|
|
12
|
+
* `ElementContextMenu`) and buttons.
|
|
13
|
+
*/
|
|
14
|
+
export default class ElementActions extends Plugin {
|
|
15
|
+
static get pluginName(): 'ElementActions';
|
|
16
|
+
init(): void;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=elementActions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elementActions.d.ts","sourceRoot":"","sources":["../src/elementActions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAKnC;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,MAAM;IACjD,WAAkB,UAAU,IAAI,gBAAgB,CAE/C;IAEM,IAAI,IAAI,IAAI;CAQnB"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Plugin } from 'ckeditor5';
|
|
2
|
+
import ElementDeleteCommand from './elementDeleteCommand.js';
|
|
3
|
+
import ElementDuplicateCommand from './elementDuplicateCommand.js';
|
|
4
|
+
import ElementMoveCommand from './elementMoveCommand.js';
|
|
5
|
+
/**
|
|
6
|
+
* Registers commands that act on an element: `moveElementUp`, `moveElementDown`, `duplicateElement` and
|
|
7
|
+
* `deleteElement`.
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* editor.execute('duplicateElement'); // The element at the selection.
|
|
11
|
+
* editor.commands.get('moveElementUp').executeFor(element); // The given element.
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* The commands have titles and icons, so they can be menu items (e.g. in the `elementContextMenu` config of
|
|
15
|
+
* `ElementContextMenu`) and buttons.
|
|
16
|
+
*/
|
|
17
|
+
export default class ElementActions extends Plugin {
|
|
18
|
+
static get pluginName() {
|
|
19
|
+
return 'ElementActions';
|
|
20
|
+
}
|
|
21
|
+
init() {
|
|
22
|
+
const editor = this.editor;
|
|
23
|
+
editor.commands.add('moveElementUp', new ElementMoveCommand(editor, 'up'));
|
|
24
|
+
editor.commands.add('moveElementDown', new ElementMoveCommand(editor, 'down'));
|
|
25
|
+
editor.commands.add('duplicateElement', new ElementDuplicateCommand(editor));
|
|
26
|
+
editor.commands.add('deleteElement', new ElementDeleteCommand(editor));
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=elementActions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elementActions.js","sourceRoot":"","sources":["../src/elementActions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACnC,OAAO,oBAAoB,MAAM,2BAA2B,CAAC;AAC7D,OAAO,uBAAuB,MAAM,8BAA8B,CAAC;AACnE,OAAO,kBAAkB,MAAM,yBAAyB,CAAC;AAEzD;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,MAAM;IAC1C,MAAM,KAAK,UAAU;QAC3B,OAAO,gBAAyB,CAAC;IAClC,CAAC;IAEM,IAAI;QACV,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAE3B,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,kBAAkB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;QAC3E,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,iBAAiB,EAAE,IAAI,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;QAC/E,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,kBAAkB,EAAE,IAAI,uBAAuB,CAAC,MAAM,CAAC,CAAC,CAAC;QAC7E,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,oBAAoB,CAAC,MAAM,CAAC,CAAC,CAAC;IACxE,CAAC;CACD"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type Editor } from 'ckeditor5';
|
|
2
|
+
import { ElementOrPositionCommand, type ElementOrPosition } from 'ckeditor5-elements-core';
|
|
3
|
+
/**
|
|
4
|
+
* Deletes an element. When it was the only element in its parent, e.g. in a note, the parent gets an empty paragraph
|
|
5
|
+
* with the selection, so that it can still be written in.
|
|
6
|
+
*
|
|
7
|
+
* The element is the given one, the parent of the given position, or the selected element or the parent of the
|
|
8
|
+
* selection (see {@link ElementOrPositionCommand}). The command is disabled for parts of a structure, such as table
|
|
9
|
+
* cells.
|
|
10
|
+
*/
|
|
11
|
+
export default class ElementDeleteCommand extends ElementOrPositionCommand {
|
|
12
|
+
constructor(editor: Editor);
|
|
13
|
+
/**
|
|
14
|
+
* Deletes the element.
|
|
15
|
+
*/
|
|
16
|
+
execute(elementOrPosition?: ElementOrPosition): void;
|
|
17
|
+
protected _isEnabledFor(elementOrPosition?: ElementOrPosition): boolean;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=elementDeleteCommand.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elementDeleteCommand.d.ts","sourceRoot":"","sources":["../src/elementDeleteCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,wBAAwB,EAAgB,KAAK,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAGzG;;;;;;;GAOG;AACH,MAAM,CAAC,OAAO,OAAO,oBAAqB,SAAQ,wBAAwB;gBAC7D,MAAM,EAAE,MAAM;IAO1B;;OAEG;IACa,OAAO,CAAC,iBAAiB,CAAC,EAAE,iBAAiB,GAAG,IAAI;cA4BjD,aAAa,CAAC,iBAAiB,CAAC,EAAE,iBAAiB,GAAG,OAAO;CAMhF"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import {} from 'ckeditor5';
|
|
2
|
+
import { ElementOrPositionCommand, isStandalone } from 'ckeditor5-elements-core';
|
|
3
|
+
import { deleteIcon } from './icons.js';
|
|
4
|
+
/**
|
|
5
|
+
* Deletes an element. When it was the only element in its parent, e.g. in a note, the parent gets an empty paragraph
|
|
6
|
+
* with the selection, so that it can still be written in.
|
|
7
|
+
*
|
|
8
|
+
* The element is the given one, the parent of the given position, or the selected element or the parent of the
|
|
9
|
+
* selection (see {@link ElementOrPositionCommand}). The command is disabled for parts of a structure, such as table
|
|
10
|
+
* cells.
|
|
11
|
+
*/
|
|
12
|
+
export default class ElementDeleteCommand extends ElementOrPositionCommand {
|
|
13
|
+
constructor(editor) {
|
|
14
|
+
super(editor);
|
|
15
|
+
this.title = editor.t('Delete');
|
|
16
|
+
this.icon = deleteIcon;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Deletes the element.
|
|
20
|
+
*/
|
|
21
|
+
execute(elementOrPosition) {
|
|
22
|
+
const model = this.editor.model;
|
|
23
|
+
const element = this._getElement(elementOrPosition);
|
|
24
|
+
if (!element || !this._isEnabledFor(element)) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
model.change(writer => {
|
|
28
|
+
const parent = element.parent;
|
|
29
|
+
writer.remove(element);
|
|
30
|
+
// The root gets a paragraph from the editor itself.
|
|
31
|
+
if (parent?.is('element') &&
|
|
32
|
+
!parent.is('rootElement') &&
|
|
33
|
+
parent.isEmpty &&
|
|
34
|
+
model.schema.checkChild(parent, 'paragraph')) {
|
|
35
|
+
const paragraph = writer.createElement('paragraph');
|
|
36
|
+
writer.append(paragraph, parent);
|
|
37
|
+
writer.setSelection(paragraph, 0);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
_isEnabledFor(elementOrPosition) {
|
|
42
|
+
const model = this.editor.model;
|
|
43
|
+
const element = this._getElement(elementOrPosition);
|
|
44
|
+
return !!element && isStandalone(model.schema, element) && model.canEditAt(element);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=elementDeleteCommand.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elementDeleteCommand.js","sourceRoot":"","sources":["../src/elementDeleteCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,wBAAwB,EAAE,YAAY,EAA0B,MAAM,yBAAyB,CAAC;AACzG,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC;;;;;;;GAOG;AACH,MAAM,CAAC,OAAO,OAAO,oBAAqB,SAAQ,wBAAwB;IACzE,YAAY,MAAc;QACzB,KAAK,CAAC,MAAM,CAAC,CAAC;QAEd,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;QAChC,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACxB,CAAC;IAED;;OAEG;IACa,OAAO,CAAC,iBAAqC;QAC5D,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;QAChC,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,iBAAiB,CAAC,CAAC;QAEpD,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC;YAC9C,OAAO;QACR,CAAC;QAED,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE;YACrB,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YAE9B,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAEvB,oDAAoD;YACpD,IACC,MAAM,EAAE,EAAE,CAAC,SAAS,CAAC;gBACrB,CAAC,MAAM,CAAC,EAAE,CAAC,aAAa,CAAC;gBACzB,MAAM,CAAC,OAAO;gBACd,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,WAAW,CAAC,EAC3C,CAAC;gBACF,MAAM,SAAS,GAAG,MAAM,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;gBAEpD,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;gBACjC,MAAM,CAAC,YAAY,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;YACnC,CAAC;QACF,CAAC,CAAC,CAAC;IACJ,CAAC;IAEkB,aAAa,CAAC,iBAAqC;QACrE,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;QAChC,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,iBAAiB,CAAC,CAAC;QAEpD,OAAO,CAAC,CAAC,OAAO,IAAI,YAAY,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IACrF,CAAC;CACD"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type Editor } from 'ckeditor5';
|
|
2
|
+
import { ElementOrPositionCommand, type ElementOrPosition } from 'ckeditor5-elements-core';
|
|
3
|
+
/**
|
|
4
|
+
* Duplicates an element: inserts the same element, empty, after it, and puts the selection in it: in the copy of an
|
|
5
|
+
* element that holds text, or in a new paragraph in the copy of an element that holds blocks.
|
|
6
|
+
*
|
|
7
|
+
* The copy has the same name and attributes. A list item gets a new list item id, so it is a new list item, not a second
|
|
8
|
+
* block of the same one. Objects, e.g. an image or a table, are copied with their content, as they cannot be empty.
|
|
9
|
+
*
|
|
10
|
+
* The element is the given one, the parent of the given position, or the selected element or the parent of the
|
|
11
|
+
* selection (see {@link ElementOrPositionCommand}). The command is disabled for parts of a structure, such as table
|
|
12
|
+
* cells.
|
|
13
|
+
*/
|
|
14
|
+
export default class ElementDuplicateCommand extends ElementOrPositionCommand {
|
|
15
|
+
constructor(editor: Editor);
|
|
16
|
+
/**
|
|
17
|
+
* Inserts the copy of the element after it.
|
|
18
|
+
*/
|
|
19
|
+
execute(elementOrPosition?: ElementOrPosition): void;
|
|
20
|
+
protected _isEnabledFor(elementOrPosition?: ElementOrPosition): boolean;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=elementDuplicateCommand.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elementDuplicateCommand.d.ts","sourceRoot":"","sources":["../src/elementDuplicateCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,KAAK,MAAM,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EACN,wBAAwB,EAGxB,KAAK,iBAAiB,EACtB,MAAM,yBAAyB,CAAC;AAGjC;;;;;;;;;;GAUG;AACH,MAAM,CAAC,OAAO,OAAO,uBAAwB,SAAQ,wBAAwB;gBAChE,MAAM,EAAE,MAAM;IAO1B;;OAEG;IACa,OAAO,CAAC,iBAAiB,CAAC,EAAE,iBAAiB,GAAG,IAAI;cAoBjD,aAAa,CAAC,iBAAiB,CAAC,EAAE,iBAAiB,GAAG,OAAO;CAYhF"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { uid } from 'ckeditor5';
|
|
2
|
+
import { ElementOrPositionCommand, isStandalone, selectNewElement } from 'ckeditor5-elements-core';
|
|
3
|
+
import { duplicateIcon } from './icons.js';
|
|
4
|
+
/**
|
|
5
|
+
* Duplicates an element: inserts the same element, empty, after it, and puts the selection in it: in the copy of an
|
|
6
|
+
* element that holds text, or in a new paragraph in the copy of an element that holds blocks.
|
|
7
|
+
*
|
|
8
|
+
* The copy has the same name and attributes. A list item gets a new list item id, so it is a new list item, not a second
|
|
9
|
+
* block of the same one. Objects, e.g. an image or a table, are copied with their content, as they cannot be empty.
|
|
10
|
+
*
|
|
11
|
+
* The element is the given one, the parent of the given position, or the selected element or the parent of the
|
|
12
|
+
* selection (see {@link ElementOrPositionCommand}). The command is disabled for parts of a structure, such as table
|
|
13
|
+
* cells.
|
|
14
|
+
*/
|
|
15
|
+
export default class ElementDuplicateCommand extends ElementOrPositionCommand {
|
|
16
|
+
constructor(editor) {
|
|
17
|
+
super(editor);
|
|
18
|
+
this.title = editor.t('Duplicate');
|
|
19
|
+
this.icon = duplicateIcon;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Inserts the copy of the element after it.
|
|
23
|
+
*/
|
|
24
|
+
execute(elementOrPosition) {
|
|
25
|
+
const model = this.editor.model;
|
|
26
|
+
const element = this._getElement(elementOrPosition);
|
|
27
|
+
if (!element || !this._isEnabledFor(element)) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
model.change(writer => {
|
|
31
|
+
const copy = writer.cloneElement(element, model.schema.isObject(element));
|
|
32
|
+
if (copy.hasAttribute('listItemId')) {
|
|
33
|
+
writer.setAttribute('listItemId', uid(), copy);
|
|
34
|
+
}
|
|
35
|
+
writer.insert(copy, writer.createPositionAfter(element));
|
|
36
|
+
selectNewElement(writer, copy);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
_isEnabledFor(elementOrPosition) {
|
|
40
|
+
const model = this.editor.model;
|
|
41
|
+
const element = this._getElement(elementOrPosition);
|
|
42
|
+
if (!element || !isStandalone(model.schema, element)) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
const position = model.createPositionAfter(element);
|
|
46
|
+
return model.canEditAt(position) && model.schema.checkChild(position, element);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=elementDuplicateCommand.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elementDuplicateCommand.js","sourceRoot":"","sources":["../src/elementDuplicateCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAe,MAAM,WAAW,CAAC;AAC7C,OAAO,EACN,wBAAwB,EACxB,YAAY,EACZ,gBAAgB,EAEhB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C;;;;;;;;;;GAUG;AACH,MAAM,CAAC,OAAO,OAAO,uBAAwB,SAAQ,wBAAwB;IAC5E,YAAY,MAAc;QACzB,KAAK,CAAC,MAAM,CAAC,CAAC;QAEd,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;QACnC,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;IAC3B,CAAC;IAED;;OAEG;IACa,OAAO,CAAC,iBAAqC;QAC5D,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;QAChC,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,iBAAiB,CAAC,CAAC;QAEpD,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC;YAC9C,OAAO;QACR,CAAC;QAED,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE;YACrB,MAAM,IAAI,GAAG,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;YAE1E,IAAI,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,CAAC;gBACrC,MAAM,CAAC,YAAY,CAAC,YAAY,EAAE,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;YAChD,CAAC;YAED,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAC;YACzD,gBAAgB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAChC,CAAC,CAAC,CAAC;IACJ,CAAC;IAEkB,aAAa,CAAC,iBAAqC;QACrE,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;QAChC,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,iBAAiB,CAAC,CAAC;QAEpD,IAAI,CAAC,OAAO,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;YACtD,OAAO,KAAK,CAAC;QACd,CAAC;QAED,MAAM,QAAQ,GAAG,KAAK,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC;QAEpD,OAAO,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAChF,CAAC;CACD"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type Editor } from 'ckeditor5';
|
|
2
|
+
import { ElementOrPositionCommand, type ElementOrPosition } from 'ckeditor5-elements-core';
|
|
3
|
+
/**
|
|
4
|
+
* Where the element moves.
|
|
5
|
+
*/
|
|
6
|
+
export type ElementMoveDirection = 'up' | 'down';
|
|
7
|
+
/**
|
|
8
|
+
* Moves an element up or down: swaps it with the element before or after it, in the same parent. The selection stays
|
|
9
|
+
* in the element.
|
|
10
|
+
*
|
|
11
|
+
* The element is the given one, the parent of the given position, or the selected element or the parent of the
|
|
12
|
+
* selection (see {@link ElementOrPositionCommand}). The command is disabled when there is no element before it (up) or
|
|
13
|
+
* after it (down), e.g. for the first element of a note, and for parts of a structure, such as table cells.
|
|
14
|
+
*/
|
|
15
|
+
export default class ElementMoveCommand extends ElementOrPositionCommand {
|
|
16
|
+
/**
|
|
17
|
+
* Where the element moves.
|
|
18
|
+
*/
|
|
19
|
+
readonly direction: ElementMoveDirection;
|
|
20
|
+
constructor(editor: Editor, direction: ElementMoveDirection);
|
|
21
|
+
/**
|
|
22
|
+
* Moves the element up or down.
|
|
23
|
+
*/
|
|
24
|
+
execute(elementOrPosition?: ElementOrPosition): void;
|
|
25
|
+
protected _isEnabledFor(elementOrPosition?: ElementOrPosition): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Returns the element the element swaps with: the one before it (up) or after it (down), if it is an element.
|
|
28
|
+
*/
|
|
29
|
+
private _getSibling;
|
|
30
|
+
private _canMove;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=elementMoveCommand.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elementMoveCommand.d.ts","sourceRoot":"","sources":["../src/elementMoveCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAqB,MAAM,WAAW,CAAC;AAC3D,OAAO,EAAE,wBAAwB,EAAgB,KAAK,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAGzG;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,IAAI,GAAG,MAAM,CAAC;AAEjD;;;;;;;GAOG;AACH,MAAM,CAAC,OAAO,OAAO,kBAAmB,SAAQ,wBAAwB;IACvE;;OAEG;IACH,SAAgB,SAAS,EAAE,oBAAoB,CAAC;gBAEpC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,oBAAoB;IAQ3D;;OAEG;IACa,OAAO,CAAC,iBAAiB,CAAC,EAAE,iBAAiB,GAAG,IAAI;cAkBjD,aAAa,CAAC,iBAAiB,CAAC,EAAE,iBAAiB,GAAG,OAAO;IAOhF;;OAEG;IACH,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,QAAQ;CAKhB"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import {} from 'ckeditor5';
|
|
2
|
+
import { ElementOrPositionCommand, isStandalone } from 'ckeditor5-elements-core';
|
|
3
|
+
import { moveDownIcon, moveUpIcon } from './icons.js';
|
|
4
|
+
/**
|
|
5
|
+
* Moves an element up or down: swaps it with the element before or after it, in the same parent. The selection stays
|
|
6
|
+
* in the element.
|
|
7
|
+
*
|
|
8
|
+
* The element is the given one, the parent of the given position, or the selected element or the parent of the
|
|
9
|
+
* selection (see {@link ElementOrPositionCommand}). The command is disabled when there is no element before it (up) or
|
|
10
|
+
* after it (down), e.g. for the first element of a note, and for parts of a structure, such as table cells.
|
|
11
|
+
*/
|
|
12
|
+
export default class ElementMoveCommand extends ElementOrPositionCommand {
|
|
13
|
+
/**
|
|
14
|
+
* Where the element moves.
|
|
15
|
+
*/
|
|
16
|
+
direction;
|
|
17
|
+
constructor(editor, direction) {
|
|
18
|
+
super(editor);
|
|
19
|
+
this.direction = direction;
|
|
20
|
+
this.title = direction === 'up' ? editor.t('Move up') : editor.t('Move down');
|
|
21
|
+
this.icon = direction === 'up' ? moveUpIcon : moveDownIcon;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Moves the element up or down.
|
|
25
|
+
*/
|
|
26
|
+
execute(elementOrPosition) {
|
|
27
|
+
const element = this._getElement(elementOrPosition);
|
|
28
|
+
const sibling = element && this._getSibling(element);
|
|
29
|
+
if (!element || !sibling || !this._canMove(element, sibling)) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
this.editor.model.change(writer => {
|
|
33
|
+
// Either way, the selection stays in the element: it moves with the element, or the sibling moves past it.
|
|
34
|
+
if (this.direction === 'up') {
|
|
35
|
+
writer.move(writer.createRangeOn(element), writer.createPositionBefore(sibling));
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
writer.move(writer.createRangeOn(sibling), writer.createPositionBefore(element));
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
_isEnabledFor(elementOrPosition) {
|
|
43
|
+
const element = this._getElement(elementOrPosition);
|
|
44
|
+
const sibling = element && this._getSibling(element);
|
|
45
|
+
return !!element && !!sibling && this._canMove(element, sibling);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Returns the element the element swaps with: the one before it (up) or after it (down), if it is an element.
|
|
49
|
+
*/
|
|
50
|
+
_getSibling(element) {
|
|
51
|
+
const sibling = this.direction === 'up' ? element.previousSibling : element.nextSibling;
|
|
52
|
+
return sibling?.is('element') ? sibling : null;
|
|
53
|
+
}
|
|
54
|
+
_canMove(element, sibling) {
|
|
55
|
+
const model = this.editor.model;
|
|
56
|
+
return isStandalone(model.schema, element) && model.canEditAt(element) && model.canEditAt(sibling);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=elementMoveCommand.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elementMoveCommand.js","sourceRoot":"","sources":["../src/elementMoveCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkC,MAAM,WAAW,CAAC;AAC3D,OAAO,EAAE,wBAAwB,EAAE,YAAY,EAA0B,MAAM,yBAAyB,CAAC;AACzG,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAOtD;;;;;;;GAOG;AACH,MAAM,CAAC,OAAO,OAAO,kBAAmB,SAAQ,wBAAwB;IACvE;;OAEG;IACa,SAAS,CAAuB;IAEhD,YAAY,MAAc,EAAE,SAA+B;QAC1D,KAAK,CAAC,MAAM,CAAC,CAAC;QAEd,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,KAAK,GAAG,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;QAC9E,IAAI,CAAC,IAAI,GAAG,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC;IAC5D,CAAC;IAED;;OAEG;IACa,OAAO,CAAC,iBAAqC;QAC5D,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,iBAAiB,CAAC,CAAC;QACpD,MAAM,OAAO,GAAG,OAAO,IAAI,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QAErD,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC;YAC9D,OAAO;QACR,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE;YACjC,2GAA2G;YAC3G,IAAI,IAAI,CAAC,SAAS,KAAK,IAAI,EAAE,CAAC;gBAC7B,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC,CAAC;YAClF,CAAC;iBAAM,CAAC;gBACP,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC,CAAC;YAClF,CAAC;QACF,CAAC,CAAC,CAAC;IACJ,CAAC;IAEkB,aAAa,CAAC,iBAAqC;QACrE,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,iBAAiB,CAAC,CAAC;QACpD,MAAM,OAAO,GAAG,OAAO,IAAI,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QAErD,OAAO,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAClE,CAAC;IAED;;OAEG;IACK,WAAW,CAAC,OAAqB;QACxC,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;QAExF,OAAO,OAAO,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;IAChD,CAAC;IAEO,QAAQ,CAAC,OAAqB,EAAE,OAAqB;QAC5D,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;QAEhC,OAAO,YAAY,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IACpG,CAAC;CACD"}
|
package/dist/icons.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The icons of the element actions, in the style of the CKEditor 5 icons (20×20).
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Move up: an arrow up, above a block.
|
|
6
|
+
*/
|
|
7
|
+
export declare const moveUpIcon: string;
|
|
8
|
+
/**
|
|
9
|
+
* Move down: a block, above an arrow down.
|
|
10
|
+
*/
|
|
11
|
+
export declare const moveDownIcon: string;
|
|
12
|
+
/**
|
|
13
|
+
* Duplicate: a block, above a new block.
|
|
14
|
+
*/
|
|
15
|
+
export declare const duplicateIcon: string;
|
|
16
|
+
/**
|
|
17
|
+
* Delete: CKEditor's own remove icon.
|
|
18
|
+
*/
|
|
19
|
+
export declare const deleteIcon: string;
|
|
20
|
+
//# sourceMappingURL=icons.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"icons.d.ts","sourceRoot":"","sources":["../src/icons.ts"],"names":[],"mappings":"AAEA;;GAEG;AAEH;;GAEG;AACH,eAAO,MAAM,UAAU,QAGkC,CAAC;AAE1D;;GAEG;AACH,eAAO,MAAM,YAAY,QAGyC,CAAC;AAEnE;;GAEG;AACH,eAAO,MAAM,aAAa,QAIJ,CAAC;AAEvB;;GAEG;AACH,eAAO,MAAM,UAAU,QAAa,CAAC"}
|
package/dist/icons.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { IconRemove } from 'ckeditor5';
|
|
2
|
+
/**
|
|
3
|
+
* The icons of the element actions, in the style of the CKEditor 5 icons (20×20).
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Move up: an arrow up, above a block.
|
|
7
|
+
*/
|
|
8
|
+
export const moveUpIcon = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path fill-rule="evenodd" d="' +
|
|
9
|
+
'M10 1.5l3.75 3.75-1.05 1.05-1.95-1.95V8.5h-1.5V4.35L7.3 6.3 6.25 5.25zM3.5 11h13a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1h-13a1 ' +
|
|
10
|
+
'1 0 0 1-1-1v-5a1 1 0 0 1 1-1zm.5 1.5v4h12v-4z"/></svg>';
|
|
11
|
+
/**
|
|
12
|
+
* Move down: a block, above an arrow down.
|
|
13
|
+
*/
|
|
14
|
+
export const moveDownIcon = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path fill-rule="evenodd" d="' +
|
|
15
|
+
'M3.5 2h13a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1h-13a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1zm.5 1.5v4h12v-4zM10 18.5l-3.75-3.75 ' +
|
|
16
|
+
'1.05-1.05 1.95 1.95V11.5h1.5v4.15l1.95-1.95 1.05 1.05z"/></svg>';
|
|
17
|
+
/**
|
|
18
|
+
* Duplicate: a block, above a new block.
|
|
19
|
+
*/
|
|
20
|
+
export const duplicateIcon = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path fill-rule="evenodd" d="' +
|
|
21
|
+
'M3.5 2h13a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1h-13a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1zm.5 1.5v4h12v-4zM3.5 11h13a1 1 0 0 1 1 ' +
|
|
22
|
+
'1v5a1 1 0 0 1-1 1h-13a1 1 0 0 1-1-1v-5a1 1 0 0 1 1-1zm.5 1.5v4h12v-4zM9.25 13h1.5v.75h.75v1.5h-.75V16h-1.5v-.75H8.5' +
|
|
23
|
+
'v-1.5h.75z"/></svg>';
|
|
24
|
+
/**
|
|
25
|
+
* Delete: CKEditor's own remove icon.
|
|
26
|
+
*/
|
|
27
|
+
export const deleteIcon = IconRemove;
|
|
28
|
+
//# sourceMappingURL=icons.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"icons.js","sourceRoot":"","sources":["../src/icons.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC;;GAEG;AAEH;;GAEG;AACH,MAAM,CAAC,MAAM,UAAU,GACtB,2FAA2F;IAC3F,uHAAuH;IACvH,wDAAwD,CAAC;AAE1D;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GACxB,2FAA2F;IAC3F,gHAAgH;IAChH,iEAAiE,CAAC;AAEnE;;GAEG;AACH,MAAM,CAAC,MAAM,aAAa,GACzB,2FAA2F;IAC3F,mHAAmH;IACnH,qHAAqH;IACrH,qBAAqB,CAAC;AAEvB;;GAEG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,UAAU,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Element actions: move an element up or down, duplicate it, or delete it.
|
|
3
|
+
*
|
|
4
|
+
* @module ckeditor5-elements-actions
|
|
5
|
+
*/
|
|
6
|
+
export { default as ElementActions } from './elementActions.js';
|
|
7
|
+
export { default as ElementMoveCommand, type ElementMoveDirection } from './elementMoveCommand.js';
|
|
8
|
+
export { default as ElementDuplicateCommand } from './elementDuplicateCommand.js';
|
|
9
|
+
export { default as ElementDeleteCommand } from './elementDeleteCommand.js';
|
|
10
|
+
export { deleteIcon, duplicateIcon, moveDownIcon, moveUpIcon } from './icons.js';
|
|
11
|
+
import './augmentation.js';
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAGhE,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,KAAK,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AACnG,OAAO,EAAE,OAAO,IAAI,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAClF,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAG5E,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEjF,OAAO,mBAAmB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Element actions: move an element up or down, duplicate it, or delete it.
|
|
3
|
+
*
|
|
4
|
+
* @module ckeditor5-elements-actions
|
|
5
|
+
*/
|
|
6
|
+
// Plugins.
|
|
7
|
+
export { default as ElementActions } from './elementActions.js';
|
|
8
|
+
// Commands.
|
|
9
|
+
export { default as ElementMoveCommand } from './elementMoveCommand.js';
|
|
10
|
+
export { default as ElementDuplicateCommand } from './elementDuplicateCommand.js';
|
|
11
|
+
export { default as ElementDeleteCommand } from './elementDeleteCommand.js';
|
|
12
|
+
// Icons.
|
|
13
|
+
export { deleteIcon, duplicateIcon, moveDownIcon, moveUpIcon } from './icons.js';
|
|
14
|
+
import './augmentation.js';
|
|
15
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,WAAW;AACX,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAEhE,YAAY;AACZ,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAA6B,MAAM,yBAAyB,CAAC;AACnG,OAAO,EAAE,OAAO,IAAI,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAClF,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAE5E,SAAS;AACT,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEjF,OAAO,mBAAmB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,48 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ckeditor5-elements-actions",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "49.0.0-alpha.2",
|
|
4
|
+
"description": "Element actions for CKEditor 5: move an element up or down, duplicate it, or delete it.",
|
|
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/actions",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/ivankild/ckeditor5-elements.git",
|
|
18
|
+
"directory": "packages/ckeditor5-elements-actions"
|
|
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 { ElementActions, ElementDeleteCommand, ElementDuplicateCommand, ElementMoveCommand } from './index.js';
|
|
2
|
+
|
|
3
|
+
declare module 'ckeditor5' {
|
|
4
|
+
interface PluginsMap {
|
|
5
|
+
[ElementActions.pluginName]: ElementActions;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
interface CommandsMap {
|
|
9
|
+
moveElementUp: ElementMoveCommand;
|
|
10
|
+
moveElementDown: ElementMoveCommand;
|
|
11
|
+
duplicateElement: ElementDuplicateCommand;
|
|
12
|
+
deleteElement: ElementDeleteCommand;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Plugin } from 'ckeditor5';
|
|
2
|
+
import ElementDeleteCommand from './elementDeleteCommand.js';
|
|
3
|
+
import ElementDuplicateCommand from './elementDuplicateCommand.js';
|
|
4
|
+
import ElementMoveCommand from './elementMoveCommand.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Registers commands that act on an element: `moveElementUp`, `moveElementDown`, `duplicateElement` and
|
|
8
|
+
* `deleteElement`.
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* editor.execute('duplicateElement'); // The element at the selection.
|
|
12
|
+
* editor.commands.get('moveElementUp').executeFor(element); // The given element.
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* The commands have titles and icons, so they can be menu items (e.g. in the `elementContextMenu` config of
|
|
16
|
+
* `ElementContextMenu`) and buttons.
|
|
17
|
+
*/
|
|
18
|
+
export default class ElementActions extends Plugin {
|
|
19
|
+
public static get pluginName(): 'ElementActions' {
|
|
20
|
+
return 'ElementActions' as const;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public init(): void {
|
|
24
|
+
const editor = this.editor;
|
|
25
|
+
|
|
26
|
+
editor.commands.add('moveElementUp', new ElementMoveCommand(editor, 'up'));
|
|
27
|
+
editor.commands.add('moveElementDown', new ElementMoveCommand(editor, 'down'));
|
|
28
|
+
editor.commands.add('duplicateElement', new ElementDuplicateCommand(editor));
|
|
29
|
+
editor.commands.add('deleteElement', new ElementDeleteCommand(editor));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { type Editor } from 'ckeditor5';
|
|
2
|
+
import { ElementOrPositionCommand, isStandalone, type ElementOrPosition } from 'ckeditor5-elements-core';
|
|
3
|
+
import { deleteIcon } from './icons.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Deletes an element. When it was the only element in its parent, e.g. in a note, the parent gets an empty paragraph
|
|
7
|
+
* with the selection, so that it can still be written in.
|
|
8
|
+
*
|
|
9
|
+
* The element is the given one, the parent of the given position, or the selected element or the parent of the
|
|
10
|
+
* selection (see {@link ElementOrPositionCommand}). The command is disabled for parts of a structure, such as table
|
|
11
|
+
* cells.
|
|
12
|
+
*/
|
|
13
|
+
export default class ElementDeleteCommand extends ElementOrPositionCommand {
|
|
14
|
+
constructor(editor: Editor) {
|
|
15
|
+
super(editor);
|
|
16
|
+
|
|
17
|
+
this.title = editor.t('Delete');
|
|
18
|
+
this.icon = deleteIcon;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Deletes the element.
|
|
23
|
+
*/
|
|
24
|
+
public override execute(elementOrPosition?: ElementOrPosition): void {
|
|
25
|
+
const model = this.editor.model;
|
|
26
|
+
const element = this._getElement(elementOrPosition);
|
|
27
|
+
|
|
28
|
+
if (!element || !this._isEnabledFor(element)) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
model.change(writer => {
|
|
33
|
+
const parent = element.parent;
|
|
34
|
+
|
|
35
|
+
writer.remove(element);
|
|
36
|
+
|
|
37
|
+
// The root gets a paragraph from the editor itself.
|
|
38
|
+
if (
|
|
39
|
+
parent?.is('element') &&
|
|
40
|
+
!parent.is('rootElement') &&
|
|
41
|
+
parent.isEmpty &&
|
|
42
|
+
model.schema.checkChild(parent, 'paragraph')
|
|
43
|
+
) {
|
|
44
|
+
const paragraph = writer.createElement('paragraph');
|
|
45
|
+
|
|
46
|
+
writer.append(paragraph, parent);
|
|
47
|
+
writer.setSelection(paragraph, 0);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
protected override _isEnabledFor(elementOrPosition?: ElementOrPosition): boolean {
|
|
53
|
+
const model = this.editor.model;
|
|
54
|
+
const element = this._getElement(elementOrPosition);
|
|
55
|
+
|
|
56
|
+
return !!element && isStandalone(model.schema, element) && model.canEditAt(element);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { uid, type Editor } from 'ckeditor5';
|
|
2
|
+
import {
|
|
3
|
+
ElementOrPositionCommand,
|
|
4
|
+
isStandalone,
|
|
5
|
+
selectNewElement,
|
|
6
|
+
type ElementOrPosition
|
|
7
|
+
} from 'ckeditor5-elements-core';
|
|
8
|
+
import { duplicateIcon } from './icons.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Duplicates an element: inserts the same element, empty, after it, and puts the selection in it: in the copy of an
|
|
12
|
+
* element that holds text, or in a new paragraph in the copy of an element that holds blocks.
|
|
13
|
+
*
|
|
14
|
+
* The copy has the same name and attributes. A list item gets a new list item id, so it is a new list item, not a second
|
|
15
|
+
* block of the same one. Objects, e.g. an image or a table, are copied with their content, as they cannot be empty.
|
|
16
|
+
*
|
|
17
|
+
* The element is the given one, the parent of the given position, or the selected element or the parent of the
|
|
18
|
+
* selection (see {@link ElementOrPositionCommand}). The command is disabled for parts of a structure, such as table
|
|
19
|
+
* cells.
|
|
20
|
+
*/
|
|
21
|
+
export default class ElementDuplicateCommand extends ElementOrPositionCommand {
|
|
22
|
+
constructor(editor: Editor) {
|
|
23
|
+
super(editor);
|
|
24
|
+
|
|
25
|
+
this.title = editor.t('Duplicate');
|
|
26
|
+
this.icon = duplicateIcon;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Inserts the copy of the element after it.
|
|
31
|
+
*/
|
|
32
|
+
public override execute(elementOrPosition?: ElementOrPosition): void {
|
|
33
|
+
const model = this.editor.model;
|
|
34
|
+
const element = this._getElement(elementOrPosition);
|
|
35
|
+
|
|
36
|
+
if (!element || !this._isEnabledFor(element)) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
model.change(writer => {
|
|
41
|
+
const copy = writer.cloneElement(element, model.schema.isObject(element));
|
|
42
|
+
|
|
43
|
+
if (copy.hasAttribute('listItemId')) {
|
|
44
|
+
writer.setAttribute('listItemId', uid(), copy);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
writer.insert(copy, writer.createPositionAfter(element));
|
|
48
|
+
selectNewElement(writer, copy);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
protected override _isEnabledFor(elementOrPosition?: ElementOrPosition): boolean {
|
|
53
|
+
const model = this.editor.model;
|
|
54
|
+
const element = this._getElement(elementOrPosition);
|
|
55
|
+
|
|
56
|
+
if (!element || !isStandalone(model.schema, element)) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const position = model.createPositionAfter(element);
|
|
61
|
+
|
|
62
|
+
return model.canEditAt(position) && model.schema.checkChild(position, element);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { type Editor, type ModelElement } from 'ckeditor5';
|
|
2
|
+
import { ElementOrPositionCommand, isStandalone, type ElementOrPosition } from 'ckeditor5-elements-core';
|
|
3
|
+
import { moveDownIcon, moveUpIcon } from './icons.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Where the element moves.
|
|
7
|
+
*/
|
|
8
|
+
export type ElementMoveDirection = 'up' | 'down';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Moves an element up or down: swaps it with the element before or after it, in the same parent. The selection stays
|
|
12
|
+
* in the element.
|
|
13
|
+
*
|
|
14
|
+
* The element is the given one, the parent of the given position, or the selected element or the parent of the
|
|
15
|
+
* selection (see {@link ElementOrPositionCommand}). The command is disabled when there is no element before it (up) or
|
|
16
|
+
* after it (down), e.g. for the first element of a note, and for parts of a structure, such as table cells.
|
|
17
|
+
*/
|
|
18
|
+
export default class ElementMoveCommand extends ElementOrPositionCommand {
|
|
19
|
+
/**
|
|
20
|
+
* Where the element moves.
|
|
21
|
+
*/
|
|
22
|
+
public readonly direction: ElementMoveDirection;
|
|
23
|
+
|
|
24
|
+
constructor(editor: Editor, direction: ElementMoveDirection) {
|
|
25
|
+
super(editor);
|
|
26
|
+
|
|
27
|
+
this.direction = direction;
|
|
28
|
+
this.title = direction === 'up' ? editor.t('Move up') : editor.t('Move down');
|
|
29
|
+
this.icon = direction === 'up' ? moveUpIcon : moveDownIcon;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Moves the element up or down.
|
|
34
|
+
*/
|
|
35
|
+
public override execute(elementOrPosition?: ElementOrPosition): void {
|
|
36
|
+
const element = this._getElement(elementOrPosition);
|
|
37
|
+
const sibling = element && this._getSibling(element);
|
|
38
|
+
|
|
39
|
+
if (!element || !sibling || !this._canMove(element, sibling)) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
this.editor.model.change(writer => {
|
|
44
|
+
// Either way, the selection stays in the element: it moves with the element, or the sibling moves past it.
|
|
45
|
+
if (this.direction === 'up') {
|
|
46
|
+
writer.move(writer.createRangeOn(element), writer.createPositionBefore(sibling));
|
|
47
|
+
} else {
|
|
48
|
+
writer.move(writer.createRangeOn(sibling), writer.createPositionBefore(element));
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
protected override _isEnabledFor(elementOrPosition?: ElementOrPosition): boolean {
|
|
54
|
+
const element = this._getElement(elementOrPosition);
|
|
55
|
+
const sibling = element && this._getSibling(element);
|
|
56
|
+
|
|
57
|
+
return !!element && !!sibling && this._canMove(element, sibling);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Returns the element the element swaps with: the one before it (up) or after it (down), if it is an element.
|
|
62
|
+
*/
|
|
63
|
+
private _getSibling(element: ModelElement): ModelElement | null {
|
|
64
|
+
const sibling = this.direction === 'up' ? element.previousSibling : element.nextSibling;
|
|
65
|
+
|
|
66
|
+
return sibling?.is('element') ? sibling : null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
private _canMove(element: ModelElement, sibling: ModelElement): boolean {
|
|
70
|
+
const model = this.editor.model;
|
|
71
|
+
|
|
72
|
+
return isStandalone(model.schema, element) && model.canEditAt(element) && model.canEditAt(sibling);
|
|
73
|
+
}
|
|
74
|
+
}
|
package/src/icons.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { IconRemove } from 'ckeditor5';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The icons of the element actions, in the style of the CKEditor 5 icons (20×20).
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Move up: an arrow up, above a block.
|
|
9
|
+
*/
|
|
10
|
+
export const moveUpIcon =
|
|
11
|
+
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path fill-rule="evenodd" d="' +
|
|
12
|
+
'M10 1.5l3.75 3.75-1.05 1.05-1.95-1.95V8.5h-1.5V4.35L7.3 6.3 6.25 5.25zM3.5 11h13a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1h-13a1 ' +
|
|
13
|
+
'1 0 0 1-1-1v-5a1 1 0 0 1 1-1zm.5 1.5v4h12v-4z"/></svg>';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Move down: a block, above an arrow down.
|
|
17
|
+
*/
|
|
18
|
+
export const moveDownIcon =
|
|
19
|
+
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path fill-rule="evenodd" d="' +
|
|
20
|
+
'M3.5 2h13a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1h-13a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1zm.5 1.5v4h12v-4zM10 18.5l-3.75-3.75 ' +
|
|
21
|
+
'1.05-1.05 1.95 1.95V11.5h1.5v4.15l1.95-1.95 1.05 1.05z"/></svg>';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Duplicate: a block, above a new block.
|
|
25
|
+
*/
|
|
26
|
+
export const duplicateIcon =
|
|
27
|
+
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path fill-rule="evenodd" d="' +
|
|
28
|
+
'M3.5 2h13a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1h-13a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1zm.5 1.5v4h12v-4zM3.5 11h13a1 1 0 0 1 1 ' +
|
|
29
|
+
'1v5a1 1 0 0 1-1 1h-13a1 1 0 0 1-1-1v-5a1 1 0 0 1 1-1zm.5 1.5v4h12v-4zM9.25 13h1.5v.75h.75v1.5h-.75V16h-1.5v-.75H8.5' +
|
|
30
|
+
'v-1.5h.75z"/></svg>';
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Delete: CKEditor's own remove icon.
|
|
34
|
+
*/
|
|
35
|
+
export const deleteIcon = IconRemove;
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Element actions: move an element up or down, duplicate it, or delete it.
|
|
3
|
+
*
|
|
4
|
+
* @module ckeditor5-elements-actions
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Plugins.
|
|
8
|
+
export { default as ElementActions } from './elementActions.js';
|
|
9
|
+
|
|
10
|
+
// Commands.
|
|
11
|
+
export { default as ElementMoveCommand, type ElementMoveDirection } from './elementMoveCommand.js';
|
|
12
|
+
export { default as ElementDuplicateCommand } from './elementDuplicateCommand.js';
|
|
13
|
+
export { default as ElementDeleteCommand } from './elementDeleteCommand.js';
|
|
14
|
+
|
|
15
|
+
// Icons.
|
|
16
|
+
export { deleteIcon, duplicateIcon, moveDownIcon, moveUpIcon } from './icons.js';
|
|
17
|
+
|
|
18
|
+
import './augmentation.js';
|