-
Notifications
You must be signed in to change notification settings - Fork 3.6k
/
htmlembedcommand.ts
115 lines (98 loc) · 3.59 KB
/
htmlembedcommand.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/**
* @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @module html-embed/htmlembedcommand
*/
import type { DocumentSelection, Element, Model, Schema, Selection } from 'ckeditor5/src/engine.js';
import { Command } from 'ckeditor5/src/core.js';
import { findOptimalInsertionRange } from 'ckeditor5/src/widget.js';
/**
* The insert HTML embed element command.
*
* The command is registered by {@link module:html-embed/htmlembedediting~HtmlEmbedEditing} as `'htmlEmbed'`.
*
* To insert an empty HTML embed element at the current selection, execute the command:
*
* ```ts
* editor.execute( 'htmlEmbed' );
* ```
*
* You can specify the initial content of a new HTML embed in the argument:
*
* ```ts
* editor.execute( 'htmlEmbed', '<b>Initial content.</b>' );
* ```
*
* To update the content of the HTML embed, select it in the model and pass the content in the argument:
*
* ```ts
* editor.execute( 'htmlEmbed', '<b>New content of an existing embed.</b>' );
* ```
*/
export default class HtmlEmbedCommand extends Command {
/**
* @inheritDoc
*/
public override refresh(): void {
const model = this.editor.model;
const schema = model.schema;
const selection = model.document.selection;
const selectedRawHtmlElement = getSelectedRawHtmlModelWidget( selection );
this.isEnabled = isHtmlEmbedAllowedInParent( selection, schema, model );
this.value = selectedRawHtmlElement ? selectedRawHtmlElement.getAttribute( 'value' ) || '' : null;
}
/**
* Executes the command, which either:
*
* * creates and inserts a new HTML embed element if none was selected,
* * updates the content of the HTML embed if one was selected.
*
* @fires execute
* @param value When passed, the value (content) will be set on a new embed or a selected one.
*/
public override execute( value?: string ): void {
const model = this.editor.model;
const selection = model.document.selection;
model.change( writer => {
let htmlEmbedElement;
// If the command has a non-null value, there must be some HTML embed selected in the model.
if ( this.value !== null ) {
htmlEmbedElement = getSelectedRawHtmlModelWidget( selection );
} else {
htmlEmbedElement = writer.createElement( 'rawHtml' );
model.insertObject( htmlEmbedElement, null, null, { setSelection: 'on' } );
}
writer.setAttribute( 'value', value, htmlEmbedElement! );
} );
}
}
/**
* Checks if an HTML embed is allowed by the schema in the optimal insertion parent.
*/
function isHtmlEmbedAllowedInParent( selection: DocumentSelection, schema: Schema, model: Model ): boolean {
const parent = getInsertHtmlEmbedParent( selection, model );
return schema.checkChild( parent, 'rawHtml' );
}
/**
* Returns a node that will be used to insert a html embed with `model.insertContent` to check if a html embed element can be placed there.
*/
function getInsertHtmlEmbedParent( selection: Selection | DocumentSelection, model: Model ): Element {
const insertionRange = findOptimalInsertionRange( selection, model );
const parent = insertionRange.start.parent as Element;
if ( parent.isEmpty && !parent.is( 'rootElement' ) ) {
return parent.parent as Element;
}
return parent;
}
/**
* Returns the selected HTML embed element in the model, if any.
*/
function getSelectedRawHtmlModelWidget( selection: DocumentSelection ): Element | null {
const selectedElement = selection.getSelectedElement();
if ( selectedElement && selectedElement.is( 'element', 'rawHtml' ) ) {
return selectedElement;
}
return null;
}