-
Notifications
You must be signed in to change notification settings - Fork 3.6k
/
htmldataprocessor.ts
132 lines (113 loc) · 4.55 KB
/
htmldataprocessor.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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/**
* @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 engine/dataprocessor/htmldataprocessor
*/
/* globals DOMParser */
import BasicHtmlWriter from './basichtmlwriter.js';
import DomConverter from '../view/domconverter.js';
import type DataProcessor from './dataprocessor.js';
import type HtmlWriter from './htmlwriter.js';
import type ViewDocument from '../view/document.js';
import type ViewDocumentFragment from '../view/documentfragment.js';
import type { MatcherPattern } from '../view/matcher.js';
/**
* The HTML data processor class.
* This data processor implementation uses HTML as input and output data.
*/
export default class HtmlDataProcessor implements DataProcessor {
/**
* A DOM parser instance used to parse an HTML string to an HTML document.
*/
public domParser: DOMParser;
/**
* A DOM converter used to convert DOM elements to view elements.
*/
public domConverter: DomConverter;
/**
* A basic HTML writer instance used to convert DOM elements to an HTML string.
*/
public htmlWriter: HtmlWriter;
public skipComments: boolean = true;
/**
* Creates a new instance of the HTML data processor class.
*
* @param document The view document instance.
*/
constructor( document: ViewDocument ) {
this.domParser = new DOMParser();
this.domConverter = new DomConverter( document, { renderingMode: 'data' } );
this.htmlWriter = new BasicHtmlWriter();
}
/**
* Converts a provided {@link module:engine/view/documentfragment~DocumentFragment document fragment}
* to data format – in this case to an HTML string.
*
* @returns HTML string.
*/
public toData( viewFragment: ViewDocumentFragment ): string {
// Convert view DocumentFragment to DOM DocumentFragment.
const domFragment = this.domConverter.viewToDom( viewFragment );
// Convert DOM DocumentFragment to HTML output.
return this.htmlWriter.getHtml( domFragment );
}
/**
* Converts the provided HTML string to a view tree.
*
* @param data An HTML string.
* @returns A converted view element.
*/
public toView( data: string ): ViewDocumentFragment {
// Convert input HTML data to DOM DocumentFragment.
const domFragment = this._toDom( data );
// Convert DOM DocumentFragment to view DocumentFragment.
return this.domConverter.domToView( domFragment, { skipComments: this.skipComments } ) as ViewDocumentFragment;
}
/**
* Registers a {@link module:engine/view/matcher~MatcherPattern} for view elements whose content should be treated as raw data
* and not processed during the conversion from the DOM to the view elements.
*
* The raw data can be later accessed by a
* {@link module:engine/view/element~Element#getCustomProperty custom property of a view element} called `"$rawContent"`.
*
* @param pattern Pattern matching all view elements whose content should be treated as raw data.
*/
public registerRawContentMatcher( pattern: MatcherPattern ): void {
this.domConverter.registerRawContentMatcher( pattern );
}
/**
* If the processor is set to use marked fillers, it will insert ` ` fillers wrapped in `<span>` elements
* (`<span data-cke-filler="true"> </span>`) instead of regular ` ` characters.
*
* This mode allows for a more precise handling of the block fillers (so they do not leak into the editor content) but
* bloats the editor data with additional markup.
*
* This mode may be required by some features and will be turned on by them automatically.
*
* @param type Whether to use the default or the marked ` ` block fillers.
*/
public useFillerType( type: 'default' | 'marked' ): void {
this.domConverter.blockFillerMode = type == 'marked' ? 'markedNbsp' : 'nbsp';
}
/**
* Converts an HTML string to its DOM representation. Returns a document fragment containing nodes parsed from
* the provided data.
*/
protected _toDom( data: string ): DocumentFragment {
// Wrap data with a <body> tag so leading non-layout nodes (like <script>, <style>, HTML comment)
// will be preserved in the body collection.
// Do it only for data that is not a full HTML document.
if ( !data.match( /<(?:html|body|head|meta)(?:\s[^>]*)?>/i ) ) {
data = `<body>${ data }</body>`;
}
const document = this.domParser.parseFromString( data, 'text/html' );
const fragment = document.createDocumentFragment();
const bodyChildNodes = document.body.childNodes;
while ( bodyChildNodes.length > 0 ) {
fragment.appendChild( bodyChildNodes[ 0 ] );
}
return fragment;
}
}