@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
package/src/conversionutils.js
CHANGED
|
@@ -10,12 +10,30 @@
|
|
|
10
10
|
import { cloneDeep } from 'lodash-es';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
* Helper function for downcast converter.
|
|
13
|
+
* Helper function for the downcast converter. Updates attributes on the given view element.
|
|
14
14
|
*
|
|
15
|
-
* @param {module:engine/view/downcastwriter~DowncastWriter} writer
|
|
16
|
-
* @param {Object}
|
|
17
|
-
* @param {
|
|
15
|
+
* @param {module:engine/view/downcastwriter~DowncastWriter} writer The view writer.
|
|
16
|
+
* @param {Object} oldViewAttributes The previous GHS attribute value.
|
|
17
|
+
* @param {Object} newViewAttributes The current GHS attribute value.
|
|
18
|
+
* @param {module:engine/view/element~Element} viewElement The view element to update.
|
|
18
19
|
*/
|
|
20
|
+
export function updateViewAttributes( writer, oldViewAttributes, newViewAttributes, viewElement ) {
|
|
21
|
+
if ( oldViewAttributes ) {
|
|
22
|
+
removeViewAttributes( writer, oldViewAttributes, viewElement );
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if ( newViewAttributes ) {
|
|
26
|
+
setViewAttributes( writer, newViewAttributes, viewElement );
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Helper function for the downcast converter. Sets attributes on the given view element.
|
|
32
|
+
*
|
|
33
|
+
* @param {module:engine/view/downcastwriter~DowncastWriter} writer The view writer.
|
|
34
|
+
* @param {Object} viewAttributes The GHS attribute value.
|
|
35
|
+
* @param {module:engine/view/element~Element} viewElement The view element to update.
|
|
36
|
+
*/
|
|
19
37
|
export function setViewAttributes( writer, viewAttributes, viewElement ) {
|
|
20
38
|
if ( viewAttributes.attributes ) {
|
|
21
39
|
for ( const [ key, value ] of Object.entries( viewAttributes.attributes ) ) {
|
|
@@ -32,6 +50,31 @@ export function setViewAttributes( writer, viewAttributes, viewElement ) {
|
|
|
32
50
|
}
|
|
33
51
|
}
|
|
34
52
|
|
|
53
|
+
/**
|
|
54
|
+
* Helper function for the downcast converter. Removes attributes on the given view element.
|
|
55
|
+
*
|
|
56
|
+
* @param {module:engine/view/downcastwriter~DowncastWriter} writer The view writer.
|
|
57
|
+
* @param {Object} viewAttributes The GHS attribute value.
|
|
58
|
+
* @param {module:engine/view/element~Element} viewElement The view element to update.
|
|
59
|
+
*/
|
|
60
|
+
export function removeViewAttributes( writer, viewAttributes, viewElement ) {
|
|
61
|
+
if ( viewAttributes.attributes ) {
|
|
62
|
+
for ( const [ key ] of Object.entries( viewAttributes.attributes ) ) {
|
|
63
|
+
writer.removeAttribute( key, viewElement );
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if ( viewAttributes.styles ) {
|
|
68
|
+
for ( const style of Object.keys( viewAttributes.styles ) ) {
|
|
69
|
+
writer.removeStyle( style, viewElement );
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if ( viewAttributes.classes ) {
|
|
74
|
+
writer.removeClass( viewAttributes.classes, viewElement );
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
35
78
|
/**
|
|
36
79
|
* Merges view element attribute objects.
|
|
37
80
|
*
|
|
@@ -45,7 +88,7 @@ export function mergeViewElementAttributes( target, source ) {
|
|
|
45
88
|
for ( const key in source ) {
|
|
46
89
|
// Merge classes.
|
|
47
90
|
if ( Array.isArray( source[ key ] ) ) {
|
|
48
|
-
result[ key ] = Array.from( new Set( [ ...target[ key ], ...source[ key ] ] ) );
|
|
91
|
+
result[ key ] = Array.from( new Set( [ ...( target[ key ] || [] ), ...source[ key ] ] ) );
|
|
49
92
|
}
|
|
50
93
|
|
|
51
94
|
// Merge attributes or styles.
|
package/src/converters.js
CHANGED
|
@@ -8,7 +8,11 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { toWidget } from 'ckeditor5/src/widget';
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
setViewAttributes,
|
|
13
|
+
mergeViewElementAttributes,
|
|
14
|
+
updateViewAttributes
|
|
15
|
+
} from './conversionutils';
|
|
12
16
|
|
|
13
17
|
/**
|
|
14
18
|
* View-to-model conversion helper for object elements.
|
|
@@ -28,7 +32,7 @@ export function viewToModelObjectConverter( { model: modelName } ) {
|
|
|
28
32
|
}
|
|
29
33
|
|
|
30
34
|
/**
|
|
31
|
-
* Conversion helper converting object element to HTML object widget.
|
|
35
|
+
* Conversion helper converting an object element to an HTML object widget.
|
|
32
36
|
*
|
|
33
37
|
* @param {module:core/editor/editor~Editor} editor
|
|
34
38
|
* @param {module:html-support/dataschema~DataSchemaInlineElementDefinition} definition
|
|
@@ -37,14 +41,15 @@ export function viewToModelObjectConverter( { model: modelName } ) {
|
|
|
37
41
|
export function toObjectWidgetConverter( editor, { view: viewName, isInline } ) {
|
|
38
42
|
const t = editor.t;
|
|
39
43
|
|
|
40
|
-
return ( modelElement, { writer
|
|
44
|
+
return ( modelElement, { writer } ) => {
|
|
41
45
|
const widgetLabel = t( 'HTML object' );
|
|
42
46
|
|
|
43
47
|
const viewElement = createObjectView( viewName, modelElement, writer );
|
|
48
|
+
const viewAttributes = modelElement.getAttribute( 'htmlAttributes' );
|
|
49
|
+
|
|
44
50
|
writer.addClass( 'html-object-embed__content', viewElement );
|
|
45
51
|
|
|
46
|
-
|
|
47
|
-
if ( viewAttributes && consumable.consume( modelElement, `attribute:htmlAttributes:${ modelElement.name }` ) ) {
|
|
52
|
+
if ( viewAttributes ) {
|
|
48
53
|
setViewAttributes( writer, viewAttributes, viewElement );
|
|
49
54
|
}
|
|
50
55
|
|
|
@@ -55,10 +60,7 @@ export function toObjectWidgetConverter( editor, { view: viewName, isInline } )
|
|
|
55
60
|
class: 'html-object-embed',
|
|
56
61
|
'data-html-object-embed-label': widgetLabel
|
|
57
62
|
},
|
|
58
|
-
viewElement
|
|
59
|
-
{
|
|
60
|
-
isAllowedInsideAttributeElement: isInline
|
|
61
|
-
}
|
|
63
|
+
viewElement
|
|
62
64
|
);
|
|
63
65
|
|
|
64
66
|
return toWidget( viewContainer, writer, { widgetLabel } );
|
|
@@ -89,7 +91,19 @@ export function createObjectView( viewName, modelElement, writer ) {
|
|
|
89
91
|
export function viewToAttributeInlineConverter( { view: viewName, model: attributeKey }, dataFilter ) {
|
|
90
92
|
return dispatcher => {
|
|
91
93
|
dispatcher.on( `element:${ viewName }`, ( evt, data, conversionApi ) => {
|
|
92
|
-
|
|
94
|
+
let viewAttributes = dataFilter.processViewAttributes( data.viewItem, conversionApi );
|
|
95
|
+
|
|
96
|
+
// Do not apply the attribute if the element itself is already consumed and there are no view attributes to store.
|
|
97
|
+
if ( !viewAttributes && !conversionApi.consumable.test( data.viewItem, { name: true } ) ) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Otherwise, we might need to convert it to an empty object just to preserve element itself,
|
|
102
|
+
// for example `<cite>` => <$text htmlCite="{}">.
|
|
103
|
+
viewAttributes = viewAttributes || {};
|
|
104
|
+
|
|
105
|
+
// Consume the element itself if it wasn't consumed by any other converter.
|
|
106
|
+
conversionApi.consumable.consume( data.viewItem, { name: true } );
|
|
93
107
|
|
|
94
108
|
// Since we are converting to attribute we need a range on which we will set the attribute.
|
|
95
109
|
// If the range is not created yet, we will create it.
|
|
@@ -103,7 +117,7 @@ export function viewToAttributeInlineConverter( { view: viewName, model: attribu
|
|
|
103
117
|
// Node's children are converted recursively, so node can already include model attribute.
|
|
104
118
|
// We want to extend it, not replace.
|
|
105
119
|
const nodeAttributes = node.getAttribute( attributeKey );
|
|
106
|
-
const attributesToAdd = mergeViewElementAttributes( viewAttributes
|
|
120
|
+
const attributesToAdd = mergeViewElementAttributes( viewAttributes, nodeAttributes || {} );
|
|
107
121
|
|
|
108
122
|
conversionApi.writer.setAttribute( attributeKey, attributesToAdd, node );
|
|
109
123
|
}
|
|
@@ -145,11 +159,15 @@ export function attributeToViewInlineConverter( { priority, view: viewName } ) {
|
|
|
145
159
|
export function viewToModelBlockAttributeConverter( { view: viewName }, dataFilter ) {
|
|
146
160
|
return dispatcher => {
|
|
147
161
|
dispatcher.on( `element:${ viewName }`, ( evt, data, conversionApi ) => {
|
|
148
|
-
|
|
162
|
+
// Converting an attribute of an element that has not been converted to anything does not make sense
|
|
163
|
+
// because there will be nowhere to set that attribute on. At this stage, the element should've already
|
|
164
|
+
// been converted. A collapsed range can show up in to-do lists (<input>) or complex widgets (e.g. table).
|
|
165
|
+
// (https://github.com/ckeditor/ckeditor5/issues/11000).
|
|
166
|
+
if ( !data.modelRange || data.modelRange.isCollapsed ) {
|
|
149
167
|
return;
|
|
150
168
|
}
|
|
151
169
|
|
|
152
|
-
const viewAttributes = dataFilter.
|
|
170
|
+
const viewAttributes = dataFilter.processViewAttributes( data.viewItem, conversionApi );
|
|
153
171
|
|
|
154
172
|
if ( viewAttributes ) {
|
|
155
173
|
conversionApi.writer.setAttribute( 'htmlAttributes', viewAttributes, data.modelRange );
|
|
@@ -168,16 +186,15 @@ export function viewToModelBlockAttributeConverter( { view: viewName }, dataFilt
|
|
|
168
186
|
export function modelToViewBlockAttributeConverter( { model: modelName } ) {
|
|
169
187
|
return dispatcher => {
|
|
170
188
|
dispatcher.on( `attribute:htmlAttributes:${ modelName }`, ( evt, data, conversionApi ) => {
|
|
171
|
-
const viewAttributes = data.attributeNewValue;
|
|
172
|
-
|
|
173
189
|
if ( !conversionApi.consumable.consume( data.item, evt.name ) ) {
|
|
174
190
|
return;
|
|
175
191
|
}
|
|
176
192
|
|
|
193
|
+
const { attributeOldValue, attributeNewValue } = data;
|
|
177
194
|
const viewWriter = conversionApi.writer;
|
|
178
195
|
const viewElement = conversionApi.mapper.toViewElement( data.item );
|
|
179
196
|
|
|
180
|
-
|
|
197
|
+
updateViewAttributes( viewWriter, attributeOldValue, attributeNewValue, viewElement );
|
|
181
198
|
} );
|
|
182
199
|
};
|
|
183
200
|
}
|
package/src/datafilter.js
CHANGED
|
@@ -53,6 +53,9 @@ import '../theme/datafilter.css';
|
|
|
53
53
|
* }
|
|
54
54
|
* } );
|
|
55
55
|
*
|
|
56
|
+
* To apply the information about allowed and disallowed attributes in custom integration plugin,
|
|
57
|
+
* use the {@link module:html-support/datafilter~DataFilter#processViewAttributes `processViewAttributes()`} method.
|
|
58
|
+
*
|
|
56
59
|
* @extends module:core/plugin~Plugin
|
|
57
60
|
*/
|
|
58
61
|
export default class DataFilter extends Plugin {
|
|
@@ -106,8 +109,18 @@ export default class DataFilter extends Plugin {
|
|
|
106
109
|
*/
|
|
107
110
|
this._dataInitialized = false;
|
|
108
111
|
|
|
112
|
+
/**
|
|
113
|
+
* Cached map of coupled attributes. Keys are the feature attributes names
|
|
114
|
+
* and values are arrays with coupled GHS attributes names.
|
|
115
|
+
*
|
|
116
|
+
* @private
|
|
117
|
+
* @member {Map.<String,Array>}
|
|
118
|
+
*/
|
|
119
|
+
this._coupledAttributes = null;
|
|
120
|
+
|
|
109
121
|
this._registerElementsAfterInit();
|
|
110
122
|
this._registerElementHandlers();
|
|
123
|
+
this._registerModelPostFixer();
|
|
111
124
|
}
|
|
112
125
|
|
|
113
126
|
/**
|
|
@@ -167,6 +180,9 @@ export default class DataFilter extends Plugin {
|
|
|
167
180
|
if ( this._dataInitialized ) {
|
|
168
181
|
this._fireRegisterEvent( definition );
|
|
169
182
|
}
|
|
183
|
+
|
|
184
|
+
// Reset cached map to recalculate it on the next usage.
|
|
185
|
+
this._coupledAttributes = null;
|
|
170
186
|
}
|
|
171
187
|
}
|
|
172
188
|
|
|
@@ -208,17 +224,30 @@ export default class DataFilter extends Plugin {
|
|
|
208
224
|
}
|
|
209
225
|
|
|
210
226
|
/**
|
|
211
|
-
*
|
|
227
|
+
* Processes all allowed and disallowed attributes on the view element by consuming them and returning the allowed ones.
|
|
212
228
|
*
|
|
213
|
-
* @
|
|
229
|
+
* This method applies the configuration set up by {@link #allowAttributes `allowAttributes()`}
|
|
230
|
+
* and {@link #disallowAttributes `disallowAttributes()`} over the given view element by consuming relevant attributes.
|
|
231
|
+
* It returns the allowed attributes that were found on the given view element for further processing by integration code.
|
|
232
|
+
*
|
|
233
|
+
* dispatcher.on( 'element:myElement', ( evt, data, conversionApi ) => {
|
|
234
|
+
* // Get rid of disallowed and extract all allowed attributes from a viewElement.
|
|
235
|
+
* const viewAttributes = dataFilter.processViewAttributes( data.viewItem, conversionApi );
|
|
236
|
+
* // Do something with them, i.e. store inside a model as a dictionary.
|
|
237
|
+
* if ( viewAttributes ) {
|
|
238
|
+
* conversionApi.writer.setAttribute( 'htmlAttributesOfMyElement', viewAttributes, data.modelRange );
|
|
239
|
+
* }
|
|
240
|
+
* } );
|
|
241
|
+
*
|
|
242
|
+
* @see module:engine/conversion/viewconsumable~ViewConsumable#consume
|
|
214
243
|
* @param {module:engine/view/element~Element} viewElement
|
|
215
|
-
* @param {module:engine/conversion/
|
|
244
|
+
* @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi
|
|
216
245
|
* @returns {Object} [result]
|
|
217
246
|
* @returns {Object} result.attributes Set with matched attribute names.
|
|
218
247
|
* @returns {Object} result.styles Set with matched style names.
|
|
219
248
|
* @returns {Array.<String>} result.classes Set with matched class names.
|
|
220
249
|
*/
|
|
221
|
-
|
|
250
|
+
processViewAttributes( viewElement, conversionApi ) {
|
|
222
251
|
// Make sure that the disabled attributes are handled before the allowed attributes are called.
|
|
223
252
|
// For example, for block images the <figure> converter triggers conversion for <img> first and then for other elements, i.e. <a>.
|
|
224
253
|
consumeAttributes( viewElement, conversionApi, this._disallowedAttributes );
|
|
@@ -288,6 +317,91 @@ export default class DataFilter extends Plugin {
|
|
|
288
317
|
}, { priority: 'lowest' } );
|
|
289
318
|
}
|
|
290
319
|
|
|
320
|
+
/**
|
|
321
|
+
* Registers a model post-fixer that is removing coupled GHS attributes of inline elements. Those attributes
|
|
322
|
+
* are removed if a coupled feature attribute is removed.
|
|
323
|
+
*
|
|
324
|
+
* For example, consider following HTML:
|
|
325
|
+
*
|
|
326
|
+
* <a href="foo.html" id="myId">bar</a>
|
|
327
|
+
*
|
|
328
|
+
* Which would be upcasted to following text node in the model:
|
|
329
|
+
*
|
|
330
|
+
* <$text linkHref="foo.html" htmlA="{ attributes: { id: 'myId' } }">bar</$text>
|
|
331
|
+
*
|
|
332
|
+
* When the user removes the link from that text (using UI), only `linkHref` attribute would be removed:
|
|
333
|
+
*
|
|
334
|
+
* <$text htmlA="{ attributes: { id: 'myId' } }">bar</$text>
|
|
335
|
+
*
|
|
336
|
+
* The `htmlA` attribute would stay in the model and would cause GHS to generate an `<a>` element.
|
|
337
|
+
* This is incorrect from UX point of view, as the user wanted to remove the whole link (not only `href`).
|
|
338
|
+
*
|
|
339
|
+
* @private
|
|
340
|
+
*/
|
|
341
|
+
_registerModelPostFixer() {
|
|
342
|
+
const model = this.editor.model;
|
|
343
|
+
|
|
344
|
+
model.document.registerPostFixer( writer => {
|
|
345
|
+
const changes = model.document.differ.getChanges();
|
|
346
|
+
let changed = false;
|
|
347
|
+
|
|
348
|
+
const coupledAttributes = this._getCoupledAttributesMap();
|
|
349
|
+
|
|
350
|
+
for ( const change of changes ) {
|
|
351
|
+
// Handle only attribute removals.
|
|
352
|
+
if ( change.type != 'attribute' || change.attributeNewValue !== null ) {
|
|
353
|
+
continue;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// Find a list of coupled GHS attributes.
|
|
357
|
+
const attributeKeys = coupledAttributes.get( change.attributeKey );
|
|
358
|
+
|
|
359
|
+
if ( !attributeKeys ) {
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// Remove the coupled GHS attributes on the same range as the feature attribute was removed.
|
|
364
|
+
for ( const { item } of change.range.getWalker( { shallow: true } ) ) {
|
|
365
|
+
for ( const attributeKey of attributeKeys ) {
|
|
366
|
+
if ( item.hasAttribute( attributeKey ) ) {
|
|
367
|
+
writer.removeAttribute( attributeKey, item );
|
|
368
|
+
changed = true;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
return changed;
|
|
375
|
+
} );
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Collects the map of coupled attributes. The returned map is keyed by the feature attribute name
|
|
380
|
+
* and coupled GHS attribute names are stored in the value array .
|
|
381
|
+
*
|
|
382
|
+
* @private
|
|
383
|
+
* @returns {Map.<String,Array>}
|
|
384
|
+
*/
|
|
385
|
+
_getCoupledAttributesMap() {
|
|
386
|
+
if ( this._coupledAttributes ) {
|
|
387
|
+
return this._coupledAttributes;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
this._coupledAttributes = new Map();
|
|
391
|
+
|
|
392
|
+
for ( const definition of this._allowedElements ) {
|
|
393
|
+
if ( definition.coupledAttribute && definition.model ) {
|
|
394
|
+
const attributeNames = this._coupledAttributes.get( definition.coupledAttribute );
|
|
395
|
+
|
|
396
|
+
if ( attributeNames ) {
|
|
397
|
+
attributeNames.push( definition.model );
|
|
398
|
+
} else {
|
|
399
|
+
this._coupledAttributes.set( definition.coupledAttribute, [ definition.model ] );
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
291
405
|
/**
|
|
292
406
|
* Fires `register` event for the given element definition.
|
|
293
407
|
*
|
|
@@ -312,6 +426,7 @@ export default class DataFilter extends Plugin {
|
|
|
312
426
|
|
|
313
427
|
schema.register( modelName, definition.modelSchema );
|
|
314
428
|
|
|
429
|
+
/* istanbul ignore next: paranoid check */
|
|
315
430
|
if ( !viewName ) {
|
|
316
431
|
return;
|
|
317
432
|
}
|
|
@@ -336,7 +451,12 @@ export default class DataFilter extends Plugin {
|
|
|
336
451
|
conversion.for( 'upcast' ).add( viewToModelBlockAttributeConverter( definition, this ) );
|
|
337
452
|
|
|
338
453
|
conversion.for( 'editingDowncast' ).elementToStructure( {
|
|
339
|
-
model:
|
|
454
|
+
model: {
|
|
455
|
+
name: modelName,
|
|
456
|
+
attributes: [
|
|
457
|
+
'htmlAttributes'
|
|
458
|
+
]
|
|
459
|
+
},
|
|
340
460
|
view: toObjectWidgetConverter( editor, definition )
|
|
341
461
|
} );
|
|
342
462
|
|
|
@@ -432,14 +552,14 @@ export default class DataFilter extends Plugin {
|
|
|
432
552
|
* as an event namespace, e.g. `register:span`.
|
|
433
553
|
*
|
|
434
554
|
* dataFilter.on( 'register', ( evt, definition ) => {
|
|
435
|
-
* editor.schema.register( definition.model, definition.modelSchema );
|
|
555
|
+
* editor.model.schema.register( definition.model, definition.modelSchema );
|
|
436
556
|
* editor.conversion.elementToElement( { model: definition.model, view: definition.view } );
|
|
437
557
|
*
|
|
438
558
|
* evt.stop();
|
|
439
559
|
* } );
|
|
440
560
|
*
|
|
441
561
|
* dataFilter.on( 'register:span', ( evt, definition ) => {
|
|
442
|
-
* editor.schema.extend( '$text', { allowAttributes: 'htmlSpan' } );
|
|
562
|
+
* editor.model.schema.extend( '$text', { allowAttributes: 'htmlSpan' } );
|
|
443
563
|
*
|
|
444
564
|
* editor.conversion.for( 'upcast' ).elementToAttribute( { view: 'span', model: 'htmlSpan' } );
|
|
445
565
|
* editor.conversion.for( 'downcast' ).attributeToElement( { view: 'span', model: 'htmlSpan' } );
|
|
@@ -456,7 +576,7 @@ export default class DataFilter extends Plugin {
|
|
|
456
576
|
//
|
|
457
577
|
// @private
|
|
458
578
|
// @param {module:engine/view/element~Element} viewElement
|
|
459
|
-
// @param {module:engine/conversion/
|
|
579
|
+
// @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi
|
|
460
580
|
// @param {module:engine/view/matcher~Matcher Matcher} matcher
|
|
461
581
|
// @returns {Object} [result]
|
|
462
582
|
// @returns {Object} result.attributes
|
|
@@ -490,7 +610,7 @@ function consumeAttributes( viewElement, conversionApi, matcher ) {
|
|
|
490
610
|
//
|
|
491
611
|
// @private
|
|
492
612
|
// @param {module:engine/view/element~Element} viewElement
|
|
493
|
-
// @param {module:engine/conversion/
|
|
613
|
+
// @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi
|
|
494
614
|
// @param {module:engine/view/matcher~Matcher Matcher} matcher
|
|
495
615
|
// @returns {Array.<Object>} Array with match information about found attributes.
|
|
496
616
|
function consumeAttributeMatches( viewElement, { consumable }, matcher ) {
|
|
@@ -503,9 +623,8 @@ function consumeAttributeMatches( viewElement, { consumable }, matcher ) {
|
|
|
503
623
|
// We only want to consume attributes, so element can be still processed by other converters.
|
|
504
624
|
delete match.match.name;
|
|
505
625
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
}
|
|
626
|
+
consumable.consume( viewElement, match.match );
|
|
627
|
+
consumedMatches.push( match );
|
|
509
628
|
}
|
|
510
629
|
|
|
511
630
|
return consumedMatches;
|
|
@@ -515,7 +634,7 @@ function consumeAttributeMatches( viewElement, { consumable }, matcher ) {
|
|
|
515
634
|
//
|
|
516
635
|
// @private
|
|
517
636
|
// @param {module:engine/view/element~Element} viewElement
|
|
518
|
-
// @param {module:engine/conversion/
|
|
637
|
+
// @param {module:engine/conversion/viewconsumable~ViewConsumable} consumable
|
|
519
638
|
// @param {Object} match
|
|
520
639
|
function removeConsumedAttributes( consumable, viewElement, match ) {
|
|
521
640
|
for ( const key of [ 'attributes', 'classes', 'styles' ] ) {
|
|
@@ -525,7 +644,8 @@ function removeConsumedAttributes( consumable, viewElement, match ) {
|
|
|
525
644
|
continue;
|
|
526
645
|
}
|
|
527
646
|
|
|
528
|
-
|
|
647
|
+
// Iterating over a copy of an array so removing items doesn't influence iteration.
|
|
648
|
+
for ( const value of Array.from( attributes ) ) {
|
|
529
649
|
if ( !consumable.test( viewElement, ( { [ key ]: [ value ] } ) ) ) {
|
|
530
650
|
removeItemFromArray( attributes, value );
|
|
531
651
|
}
|
package/src/dataschema.js
CHANGED
|
@@ -251,5 +251,8 @@ function testViewName( pattern, viewName ) {
|
|
|
251
251
|
* @property {Number} [priority] Element priority. Decides in what order elements are wrapped by
|
|
252
252
|
* {@link module:engine/view/downcastwriter~DowncastWriter}.
|
|
253
253
|
* Set by {@link module:html-support/dataschema~DataSchema#registerInlineElement} method.
|
|
254
|
+
* @property {String} [coupledAttribute] The name of the model attribute that generates the same view element. GHS inline attribute
|
|
255
|
+
* will be removed from the model tree as soon as the coupled attribute is removed. See
|
|
256
|
+
* {@link module:html-support/datafilter~DataFilter#_registerModelPostFixer GHS post-fixer} for more details.
|
|
254
257
|
* @extends module:html-support/dataschema~DataSchemaDefinition
|
|
255
258
|
*/
|