@ckeditor/ckeditor5-html-support 33.0.0 → 34.2.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.md +2 -2
- package/README.md +2 -1
- package/build/html-support.js +1 -1
- package/build/translations/en-au.js +1 -0
- package/build/translations/hr.js +1 -0
- package/build/translations/jv.js +1 -0
- package/build/translations/lv.js +1 -0
- package/build/translations/ur.js +1 -0
- package/build/translations/zh-cn.js +1 -0
- package/lang/translations/en-au.po +21 -0
- package/lang/translations/es.po +1 -1
- package/lang/translations/hr.po +21 -0
- package/lang/translations/it.po +1 -1
- package/lang/translations/jv.po +21 -0
- package/lang/translations/lv.po +21 -0
- package/lang/translations/pt-br.po +1 -1
- package/lang/translations/ur.po +21 -0
- package/lang/translations/zh-cn.po +21 -0
- package/package.json +31 -31
- package/src/conversionutils.js +48 -5
- package/src/converters.js +33 -16
- package/src/datafilter.js +134 -14
- package/src/dataschema.js +3 -0
- package/src/generalhtmlsupport.js +231 -1
- package/src/integrations/codeblock.js +13 -4
- package/src/integrations/customelement.js +162 -0
- package/src/integrations/documentlist.js +207 -0
- package/src/integrations/dualcontent.js +19 -3
- package/src/integrations/heading.js +7 -0
- package/src/integrations/image.js +64 -27
- package/src/integrations/mediaembed.js +45 -8
- package/src/integrations/script.js +7 -0
- package/src/integrations/style.js +7 -0
- package/src/integrations/table.js +36 -7
- package/src/schemadefinitions.js +66 -66
- package/theme/datafilter.css +5 -0
- package/build/html-support.js.map +0 -1
|
@@ -43,6 +43,13 @@ export default class DualContentModelElementSupport extends Plugin {
|
|
|
43
43
|
return [ DataFilter ];
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
/**
|
|
47
|
+
* @inheritDoc
|
|
48
|
+
*/
|
|
49
|
+
static get pluginName() {
|
|
50
|
+
return 'DualContentModelElementSupport';
|
|
51
|
+
}
|
|
52
|
+
|
|
46
53
|
/**
|
|
47
54
|
* @inheritDoc
|
|
48
55
|
*/
|
|
@@ -111,10 +118,19 @@ export default class DualContentModelElementSupport extends Plugin {
|
|
|
111
118
|
* @returns {Boolean}
|
|
112
119
|
*/
|
|
113
120
|
_hasBlockContent( viewElement ) {
|
|
114
|
-
const
|
|
121
|
+
const view = this.editor.editing.view;
|
|
122
|
+
const blockElements = view.domConverter.blockElements;
|
|
123
|
+
|
|
124
|
+
// Traversing the viewElement subtree looking for block elements.
|
|
125
|
+
// Especially for the cases like <div><a href="#"><p>foo</p></a></div>.
|
|
126
|
+
// https://github.com/ckeditor/ckeditor5/issues/11513
|
|
127
|
+
for ( const viewItem of view.createRangeIn( viewElement ).getItems() ) {
|
|
128
|
+
if ( viewItem.is( 'element' ) && blockElements.includes( viewItem.name ) ) {
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
115
132
|
|
|
116
|
-
return
|
|
117
|
-
.some( node => blockElements.includes( node.name ) );
|
|
133
|
+
return false;
|
|
118
134
|
}
|
|
119
135
|
|
|
120
136
|
/**
|
|
@@ -10,7 +10,10 @@
|
|
|
10
10
|
import { Plugin } from 'ckeditor5/src/core';
|
|
11
11
|
|
|
12
12
|
import DataFilter from '../datafilter';
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
setViewAttributes,
|
|
15
|
+
updateViewAttributes
|
|
16
|
+
} from '../conversionutils.js';
|
|
14
17
|
|
|
15
18
|
/**
|
|
16
19
|
* Provides the General HTML Support integration with the {@link module:image/image~Image Image} feature.
|
|
@@ -25,6 +28,13 @@ export default class ImageElementSupport extends Plugin {
|
|
|
25
28
|
return [ DataFilter ];
|
|
26
29
|
}
|
|
27
30
|
|
|
31
|
+
/**
|
|
32
|
+
* @inheritDoc
|
|
33
|
+
*/
|
|
34
|
+
static get pluginName() {
|
|
35
|
+
return 'ImageElementSupport';
|
|
36
|
+
}
|
|
37
|
+
|
|
28
38
|
/**
|
|
29
39
|
* @inheritDoc
|
|
30
40
|
*/
|
|
@@ -40,6 +50,10 @@ export default class ImageElementSupport extends Plugin {
|
|
|
40
50
|
const conversion = editor.conversion;
|
|
41
51
|
const dataFilter = editor.plugins.get( DataFilter );
|
|
42
52
|
|
|
53
|
+
dataFilter.on( 'register:figure', () => {
|
|
54
|
+
conversion.for( 'upcast' ).add( viewToModelFigureAttributeConverter( dataFilter ) );
|
|
55
|
+
} );
|
|
56
|
+
|
|
43
57
|
dataFilter.on( 'register:img', ( evt, definition ) => {
|
|
44
58
|
if ( definition.model !== 'imageBlock' && definition.model !== 'imageInline' ) {
|
|
45
59
|
return;
|
|
@@ -84,36 +98,55 @@ export default class ImageElementSupport extends Plugin {
|
|
|
84
98
|
function viewToModelImageAttributeConverter( dataFilter ) {
|
|
85
99
|
return dispatcher => {
|
|
86
100
|
dispatcher.on( 'element:img', ( evt, data, conversionApi ) => {
|
|
101
|
+
if ( !data.modelRange ) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
87
105
|
const viewImageElement = data.viewItem;
|
|
88
106
|
const viewContainerElement = viewImageElement.parent;
|
|
89
107
|
|
|
90
108
|
preserveElementAttributes( viewImageElement, 'htmlAttributes' );
|
|
91
109
|
|
|
92
|
-
if ( viewContainerElement.is( 'element', '
|
|
93
|
-
preserveElementAttributes( viewContainerElement, 'htmlFigureAttributes' );
|
|
94
|
-
} else if ( viewContainerElement.is( 'element', 'a' ) ) {
|
|
110
|
+
if ( viewContainerElement.is( 'element', 'a' ) ) {
|
|
95
111
|
preserveLinkAttributes( viewContainerElement );
|
|
96
112
|
}
|
|
97
113
|
|
|
98
114
|
function preserveElementAttributes( viewElement, attributeName ) {
|
|
99
|
-
const viewAttributes = dataFilter.
|
|
115
|
+
const viewAttributes = dataFilter.processViewAttributes( viewElement, conversionApi );
|
|
100
116
|
|
|
101
117
|
if ( viewAttributes ) {
|
|
102
118
|
conversionApi.writer.setAttribute( attributeName, viewAttributes, data.modelRange );
|
|
103
119
|
}
|
|
104
120
|
}
|
|
105
121
|
|
|
106
|
-
// For a block image, we want to preserve the attributes on our own.
|
|
107
|
-
// The inline image attributes will be handled by the GHS automatically.
|
|
108
122
|
function preserveLinkAttributes( viewContainerElement ) {
|
|
109
123
|
if ( data.modelRange && data.modelRange.getContainedElement().is( 'element', 'imageBlock' ) ) {
|
|
110
124
|
preserveElementAttributes( viewContainerElement, 'htmlLinkAttributes' );
|
|
111
125
|
}
|
|
126
|
+
}
|
|
127
|
+
}, { priority: 'low' } );
|
|
128
|
+
};
|
|
129
|
+
}
|
|
112
130
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
131
|
+
// View-to-model conversion helper preserving allowed attributes on {@link module:image/image~Image Image}
|
|
132
|
+
// feature model element from figure view element.
|
|
133
|
+
//
|
|
134
|
+
// @private
|
|
135
|
+
// @param {module:html-support/datafilter~DataFilter} dataFilter
|
|
136
|
+
// @returns {Function} Returns a conversion callback.
|
|
137
|
+
function viewToModelFigureAttributeConverter( dataFilter ) {
|
|
138
|
+
return dispatcher => {
|
|
139
|
+
dispatcher.on( 'element:figure', ( evt, data, conversionApi ) => {
|
|
140
|
+
const viewFigureElement = data.viewItem;
|
|
141
|
+
|
|
142
|
+
if ( !data.modelRange || !viewFigureElement.hasClass( 'image' ) ) {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const viewAttributes = dataFilter.processViewAttributes( viewFigureElement, conversionApi );
|
|
147
|
+
|
|
148
|
+
if ( viewAttributes ) {
|
|
149
|
+
conversionApi.writer.setAttribute( 'htmlFigureAttributes', viewAttributes, data.modelRange );
|
|
117
150
|
}
|
|
118
151
|
}, { priority: 'low' } );
|
|
119
152
|
};
|
|
@@ -130,7 +163,7 @@ function modelToViewImageAttributeConverter() {
|
|
|
130
163
|
|
|
131
164
|
addBlockAttributeConversion( 'img', 'htmlAttributes' );
|
|
132
165
|
addBlockAttributeConversion( 'figure', 'htmlFigureAttributes' );
|
|
133
|
-
|
|
166
|
+
addBlockAttributeConversion( 'a', 'htmlLinkAttributes' );
|
|
134
167
|
|
|
135
168
|
function addInlineAttributeConversion( attributeName ) {
|
|
136
169
|
dispatcher.on( `attribute:${ attributeName }:imageInline`, ( evt, data, conversionApi ) => {
|
|
@@ -138,38 +171,42 @@ function modelToViewImageAttributeConverter() {
|
|
|
138
171
|
return;
|
|
139
172
|
}
|
|
140
173
|
|
|
174
|
+
const { attributeOldValue, attributeNewValue } = data;
|
|
141
175
|
const viewElement = conversionApi.mapper.toViewElement( data.item );
|
|
142
176
|
|
|
143
|
-
|
|
177
|
+
updateViewAttributes( conversionApi.writer, attributeOldValue, attributeNewValue, viewElement );
|
|
144
178
|
}, { priority: 'low' } );
|
|
145
179
|
}
|
|
146
180
|
|
|
147
181
|
function addBlockAttributeConversion( elementName, attributeName ) {
|
|
148
182
|
dispatcher.on( `attribute:${ attributeName }:imageBlock`, ( evt, data, conversionApi ) => {
|
|
149
|
-
if ( !conversionApi.consumable.
|
|
183
|
+
if ( !conversionApi.consumable.test( data.item, evt.name ) ) {
|
|
150
184
|
return;
|
|
151
185
|
}
|
|
152
186
|
|
|
187
|
+
const { attributeOldValue, attributeNewValue } = data;
|
|
153
188
|
const containerElement = conversionApi.mapper.toViewElement( data.item );
|
|
154
189
|
const viewElement = getDescendantElement( conversionApi.writer, containerElement, elementName );
|
|
155
190
|
|
|
156
|
-
|
|
191
|
+
if ( viewElement ) {
|
|
192
|
+
updateViewAttributes( conversionApi.writer, attributeOldValue, attributeNewValue, viewElement );
|
|
193
|
+
conversionApi.consumable.consume( data.item, evt.name );
|
|
194
|
+
}
|
|
157
195
|
}, { priority: 'low' } );
|
|
158
|
-
}
|
|
159
196
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
}
|
|
197
|
+
if ( elementName === 'a' ) {
|
|
198
|
+
// To have a link element in the view, we need to attach a converter to the `linkHref` attribute as well.
|
|
199
|
+
dispatcher.on( 'attribute:linkHref:imageBlock', ( evt, data, conversionApi ) => {
|
|
200
|
+
if ( !conversionApi.consumable.consume( data.item, 'attribute:htmlLinkAttributes:imageBlock' ) ) {
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
167
203
|
|
|
168
|
-
|
|
169
|
-
|
|
204
|
+
const containerElement = conversionApi.mapper.toViewElement( data.item );
|
|
205
|
+
const viewElement = getDescendantElement( conversionApi.writer, containerElement, 'a' );
|
|
170
206
|
|
|
171
|
-
|
|
172
|
-
|
|
207
|
+
setViewAttributes( conversionApi.writer, data.item.getAttribute( 'htmlLinkAttributes' ), viewElement );
|
|
208
|
+
}, { priority: 'low' } );
|
|
209
|
+
}
|
|
173
210
|
}
|
|
174
211
|
};
|
|
175
212
|
}
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
|
|
10
10
|
import { Plugin } from 'ckeditor5/src/core';
|
|
11
11
|
|
|
12
|
-
import { setViewAttributes } from '../conversionutils.js';
|
|
13
12
|
import DataFilter from '../datafilter';
|
|
14
13
|
import DataSchema from '../dataschema';
|
|
14
|
+
import { updateViewAttributes } from '../conversionutils.js';
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Provides the General HTML Support integration with {@link module:media-embed/mediaembed~MediaEmbed Media Embed} feature.
|
|
@@ -19,10 +19,23 @@ import DataSchema from '../dataschema';
|
|
|
19
19
|
* @extends module:core/plugin~Plugin
|
|
20
20
|
*/
|
|
21
21
|
export default class MediaEmbedElementSupport extends Plugin {
|
|
22
|
+
/**
|
|
23
|
+
* @inheritDoc
|
|
24
|
+
*/
|
|
22
25
|
static get requires() {
|
|
23
26
|
return [ DataFilter ];
|
|
24
27
|
}
|
|
25
28
|
|
|
29
|
+
/**
|
|
30
|
+
* @inheritDoc
|
|
31
|
+
*/
|
|
32
|
+
static get pluginName() {
|
|
33
|
+
return 'MediaEmbedElementSupport';
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @inheritDoc
|
|
38
|
+
*/
|
|
26
39
|
init() {
|
|
27
40
|
const editor = this.editor;
|
|
28
41
|
|
|
@@ -44,6 +57,10 @@ export default class MediaEmbedElementSupport extends Plugin {
|
|
|
44
57
|
view: mediaElementName
|
|
45
58
|
} );
|
|
46
59
|
|
|
60
|
+
dataFilter.on( 'register:figure', ( ) => {
|
|
61
|
+
conversion.for( 'upcast' ).add( viewToModelFigureAttributesConverter( dataFilter ) );
|
|
62
|
+
} );
|
|
63
|
+
|
|
47
64
|
dataFilter.on( `register:${ mediaElementName }`, ( evt, definition ) => {
|
|
48
65
|
if ( definition.model !== 'media' ) {
|
|
49
66
|
return;
|
|
@@ -71,16 +88,11 @@ function viewToModelMediaAttributesConverter( dataFilter, mediaElementName ) {
|
|
|
71
88
|
|
|
72
89
|
function upcastMedia( evt, data, conversionApi ) {
|
|
73
90
|
const viewMediaElement = data.viewItem;
|
|
74
|
-
const viewParent = viewMediaElement.parent;
|
|
75
91
|
|
|
76
92
|
preserveElementAttributes( viewMediaElement, 'htmlAttributes' );
|
|
77
93
|
|
|
78
|
-
if ( viewParent.is( 'element', 'figure' ) && viewParent.hasClass( 'media' ) ) {
|
|
79
|
-
preserveElementAttributes( viewParent, 'htmlFigureAttributes' );
|
|
80
|
-
}
|
|
81
|
-
|
|
82
94
|
function preserveElementAttributes( viewElement, attributeName ) {
|
|
83
|
-
const viewAttributes = dataFilter.
|
|
95
|
+
const viewAttributes = dataFilter.processViewAttributes( viewElement, conversionApi );
|
|
84
96
|
|
|
85
97
|
if ( viewAttributes ) {
|
|
86
98
|
conversionApi.writer.setAttribute( attributeName, viewAttributes, data.modelRange );
|
|
@@ -89,6 +101,30 @@ function viewToModelMediaAttributesConverter( dataFilter, mediaElementName ) {
|
|
|
89
101
|
}
|
|
90
102
|
}
|
|
91
103
|
|
|
104
|
+
// View-to-model conversion helper preserving allowed attributes on {@link module:media-embed/mediaembed~MediaEmbed MediaEmbed}
|
|
105
|
+
// feature model element from figure view element.
|
|
106
|
+
//
|
|
107
|
+
// @private
|
|
108
|
+
// @param {module:html-support/datafilter~DataFilter} dataFilter
|
|
109
|
+
// @returns {Function} Returns a conversion callback.
|
|
110
|
+
function viewToModelFigureAttributesConverter( dataFilter ) {
|
|
111
|
+
return dispatcher => {
|
|
112
|
+
dispatcher.on( 'element:figure', ( evt, data, conversionApi ) => {
|
|
113
|
+
const viewFigureElement = data.viewItem;
|
|
114
|
+
|
|
115
|
+
if ( !data.modelRange || !viewFigureElement.hasClass( 'media' ) ) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const viewAttributes = dataFilter.processViewAttributes( viewFigureElement, conversionApi );
|
|
120
|
+
|
|
121
|
+
if ( viewAttributes ) {
|
|
122
|
+
conversionApi.writer.setAttribute( 'htmlFigureAttributes', viewAttributes, data.modelRange );
|
|
123
|
+
}
|
|
124
|
+
}, { priority: 'low' } );
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
92
128
|
function modelToViewMediaAttributeConverter( mediaElementName ) {
|
|
93
129
|
return dispatcher => {
|
|
94
130
|
addAttributeConversionDispatcherHandler( mediaElementName, 'htmlAttributes' );
|
|
@@ -100,10 +136,11 @@ function modelToViewMediaAttributeConverter( mediaElementName ) {
|
|
|
100
136
|
return;
|
|
101
137
|
}
|
|
102
138
|
|
|
139
|
+
const { attributeOldValue, attributeNewValue } = data;
|
|
103
140
|
const containerElement = conversionApi.mapper.toViewElement( data.item );
|
|
104
141
|
const viewElement = getDescendantElement( conversionApi.writer, containerElement, elementName );
|
|
105
142
|
|
|
106
|
-
|
|
143
|
+
updateViewAttributes( conversionApi.writer, attributeOldValue, attributeNewValue, viewElement );
|
|
107
144
|
} );
|
|
108
145
|
}
|
|
109
146
|
};
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
|
|
10
10
|
import { Plugin } from 'ckeditor5/src/core';
|
|
11
11
|
import { setViewAttributes } from '../conversionutils.js';
|
|
12
|
-
|
|
13
12
|
import DataFilter from '../datafilter';
|
|
14
13
|
|
|
15
14
|
/**
|
|
@@ -25,6 +24,13 @@ export default class TableElementSupport extends Plugin {
|
|
|
25
24
|
return [ DataFilter ];
|
|
26
25
|
}
|
|
27
26
|
|
|
27
|
+
/**
|
|
28
|
+
* @inheritDoc
|
|
29
|
+
*/
|
|
30
|
+
static get pluginName() {
|
|
31
|
+
return 'TableElementSupport';
|
|
32
|
+
}
|
|
33
|
+
|
|
28
34
|
/**
|
|
29
35
|
* @inheritDoc
|
|
30
36
|
*/
|
|
@@ -39,6 +45,10 @@ export default class TableElementSupport extends Plugin {
|
|
|
39
45
|
const conversion = editor.conversion;
|
|
40
46
|
const dataFilter = editor.plugins.get( DataFilter );
|
|
41
47
|
|
|
48
|
+
dataFilter.on( 'register:figure', ( ) => {
|
|
49
|
+
conversion.for( 'upcast' ).add( viewToModelFigureAttributeConverter( dataFilter ) );
|
|
50
|
+
} );
|
|
51
|
+
|
|
42
52
|
dataFilter.on( 'register:table', ( evt, definition ) => {
|
|
43
53
|
if ( definition.model !== 'table' ) {
|
|
44
54
|
return;
|
|
@@ -74,11 +84,6 @@ function viewToModelTableAttributeConverter( dataFilter ) {
|
|
|
74
84
|
|
|
75
85
|
preserveElementAttributes( viewTableElement, 'htmlAttributes' );
|
|
76
86
|
|
|
77
|
-
const viewFigureElement = viewTableElement.parent;
|
|
78
|
-
if ( viewFigureElement.is( 'element', 'figure' ) ) {
|
|
79
|
-
preserveElementAttributes( viewFigureElement, 'htmlFigureAttributes' );
|
|
80
|
-
}
|
|
81
|
-
|
|
82
87
|
for ( const childNode of viewTableElement.getChildren() ) {
|
|
83
88
|
if ( childNode.is( 'element', 'thead' ) ) {
|
|
84
89
|
preserveElementAttributes( childNode, 'htmlTheadAttributes' );
|
|
@@ -90,12 +95,36 @@ function viewToModelTableAttributeConverter( dataFilter ) {
|
|
|
90
95
|
}
|
|
91
96
|
|
|
92
97
|
function preserveElementAttributes( viewElement, attributeName ) {
|
|
93
|
-
const viewAttributes = dataFilter.
|
|
98
|
+
const viewAttributes = dataFilter.processViewAttributes( viewElement, conversionApi );
|
|
94
99
|
|
|
95
100
|
if ( viewAttributes ) {
|
|
96
101
|
conversionApi.writer.setAttribute( attributeName, viewAttributes, data.modelRange );
|
|
97
102
|
}
|
|
98
103
|
}
|
|
104
|
+
} );
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// View-to-model conversion helper preserving allowed attributes on {@link module:table/table~Table Table}
|
|
109
|
+
// feature model element from figure view element.
|
|
110
|
+
//
|
|
111
|
+
// @private
|
|
112
|
+
// @param {module:html-support/datafilter~DataFilter} dataFilter
|
|
113
|
+
// @returns {Function} Returns a conversion callback.
|
|
114
|
+
function viewToModelFigureAttributeConverter( dataFilter ) {
|
|
115
|
+
return dispatcher => {
|
|
116
|
+
dispatcher.on( 'element:figure', ( evt, data, conversionApi ) => {
|
|
117
|
+
const viewFigureElement = data.viewItem;
|
|
118
|
+
|
|
119
|
+
if ( !data.modelRange || !viewFigureElement.hasClass( 'table' ) ) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const viewAttributes = dataFilter.processViewAttributes( viewFigureElement, conversionApi );
|
|
124
|
+
|
|
125
|
+
if ( viewAttributes ) {
|
|
126
|
+
conversionApi.writer.setAttribute( 'htmlFigureAttributes', viewAttributes, data.modelRange );
|
|
127
|
+
}
|
|
99
128
|
}, { priority: 'low' } );
|
|
100
129
|
};
|
|
101
130
|
}
|