@ckeditor/ckeditor5-html-support 37.1.0 → 38.0.0-rc.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/build/html-support.js +1 -1
- package/lang/translations/ar.po +1 -1
- package/lang/translations/bg.po +1 -1
- package/lang/translations/bn.po +1 -1
- package/lang/translations/ca.po +1 -1
- package/lang/translations/cs.po +1 -1
- package/lang/translations/da.po +1 -1
- package/lang/translations/de.po +1 -1
- package/lang/translations/el.po +1 -1
- package/lang/translations/en-au.po +1 -1
- package/lang/translations/es.po +1 -1
- package/lang/translations/et.po +1 -1
- package/lang/translations/fi.po +1 -1
- package/lang/translations/fr.po +1 -1
- package/lang/translations/gl.po +1 -1
- package/lang/translations/he.po +1 -1
- package/lang/translations/hi.po +1 -1
- package/lang/translations/hr.po +1 -1
- package/lang/translations/hu.po +1 -1
- package/lang/translations/id.po +1 -1
- package/lang/translations/it.po +1 -1
- package/lang/translations/ja.po +1 -1
- package/lang/translations/jv.po +1 -1
- package/lang/translations/ko.po +1 -1
- package/lang/translations/lt.po +1 -1
- package/lang/translations/lv.po +1 -1
- package/lang/translations/ms.po +1 -1
- package/lang/translations/nl.po +1 -1
- package/lang/translations/no.po +1 -1
- package/lang/translations/pl.po +1 -1
- package/lang/translations/pt-br.po +1 -1
- package/lang/translations/pt.po +1 -1
- package/lang/translations/ro.po +1 -1
- package/lang/translations/ru.po +1 -1
- package/lang/translations/sk.po +1 -1
- package/lang/translations/sr-latn.po +1 -1
- package/lang/translations/sr.po +1 -1
- package/lang/translations/sv.po +1 -1
- package/lang/translations/th.po +1 -1
- package/lang/translations/tr.po +1 -1
- package/lang/translations/uk.po +1 -1
- package/lang/translations/ur.po +1 -1
- package/lang/translations/vi.po +1 -1
- package/lang/translations/zh-cn.po +1 -1
- package/lang/translations/zh.po +1 -1
- package/package.json +34 -33
- package/src/converters.js +1 -1
- package/src/datafilter.d.ts +5 -1
- package/src/datafilter.js +38 -33
- package/src/dataschema.d.ts +12 -2
- package/src/dataschema.js +47 -23
- package/src/generalhtmlsupport.d.ts +5 -6
- package/src/generalhtmlsupport.js +13 -54
- package/src/integrations/codeblock.js +1 -1
- package/src/integrations/customelement.js +1 -1
- package/src/integrations/documentlist.js +1 -1
- package/src/integrations/heading.d.ts +10 -1
- package/src/integrations/heading.js +24 -4
- package/src/integrations/image.js +1 -1
- package/src/integrations/mediaembed.js +1 -1
- package/src/integrations/table.js +38 -3
- package/src/schemadefinitions.js +82 -24
- package/src/{conversionutils.d.ts → utils.d.ts} +21 -2
- package/src/{conversionutils.js → utils.js} +43 -0
|
@@ -18,6 +18,7 @@ import TableElementSupport from './integrations/table';
|
|
|
18
18
|
import StyleElementSupport from './integrations/style';
|
|
19
19
|
import DocumentListElementSupport from './integrations/documentlist';
|
|
20
20
|
import CustomElementSupport from './integrations/customelement';
|
|
21
|
+
import { modifyGhsAttribute } from './utils';
|
|
21
22
|
/**
|
|
22
23
|
* The General HTML Support feature.
|
|
23
24
|
*
|
|
@@ -62,16 +63,15 @@ export default class GeneralHtmlSupport extends Plugin {
|
|
|
62
63
|
/**
|
|
63
64
|
* Returns a GHS model attribute name related to a given view element name.
|
|
64
65
|
*
|
|
66
|
+
* @internal
|
|
65
67
|
* @param viewElementName A view element name.
|
|
66
68
|
*/
|
|
67
69
|
getGhsAttributeNameForElement(viewElementName) {
|
|
68
70
|
const dataSchema = this.editor.plugins.get('DataSchema');
|
|
69
71
|
const definitions = Array.from(dataSchema.getDefinitionsForView(viewElementName, false));
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
!definitions[0].isObject) {
|
|
74
|
-
return definitions[0].model;
|
|
72
|
+
const inlineDefinition = definitions.find(definition => (definition.isInline && !definitions[0].isObject));
|
|
73
|
+
if (inlineDefinition) {
|
|
74
|
+
return inlineDefinition.model;
|
|
75
75
|
}
|
|
76
76
|
return 'htmlAttributes';
|
|
77
77
|
}
|
|
@@ -202,7 +202,10 @@ export default class GeneralHtmlSupport extends Plugin {
|
|
|
202
202
|
* Returns an iterator over an items in the selectable that accept given GHS attribute.
|
|
203
203
|
*/
|
|
204
204
|
function* getItemsToUpdateGhsAttribute(model, selectable, ghsAttributeName) {
|
|
205
|
-
if (selectable
|
|
205
|
+
if (!selectable) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
if (!(Symbol.iterator in selectable) && selectable.is('documentSelection') && selectable.isCollapsed) {
|
|
206
209
|
if (model.schema.checkAttributeInSelection(selectable, ghsAttributeName)) {
|
|
207
210
|
yield selectable;
|
|
208
211
|
}
|
|
@@ -217,7 +220,10 @@ function* getItemsToUpdateGhsAttribute(model, selectable, ghsAttributeName) {
|
|
|
217
220
|
* Translates a given selectable to an iterable of ranges.
|
|
218
221
|
*/
|
|
219
222
|
function getValidRangesForSelectable(model, selectable, ghsAttributeName) {
|
|
220
|
-
if (
|
|
223
|
+
if (!(Symbol.iterator in selectable) &&
|
|
224
|
+
(selectable.is('node') ||
|
|
225
|
+
selectable.is('$text') ||
|
|
226
|
+
selectable.is('$textProxy'))) {
|
|
221
227
|
if (model.schema.checkAttribute(selectable, ghsAttributeName)) {
|
|
222
228
|
return [model.createRangeOn(selectable)];
|
|
223
229
|
}
|
|
@@ -229,50 +235,3 @@ function getValidRangesForSelectable(model, selectable, ghsAttributeName) {
|
|
|
229
235
|
return model.schema.getValidRanges(model.createSelection(selectable).getRanges(), ghsAttributeName);
|
|
230
236
|
}
|
|
231
237
|
}
|
|
232
|
-
/**
|
|
233
|
-
* Updates a GHS attribute on a specified item.
|
|
234
|
-
* @param callback That receives a map or set as an argument and should modify it (add or remove entries).
|
|
235
|
-
*/
|
|
236
|
-
function modifyGhsAttribute(writer, item, ghsAttributeName, subject, callback) {
|
|
237
|
-
const oldValue = item.getAttribute(ghsAttributeName);
|
|
238
|
-
const newValue = {};
|
|
239
|
-
for (const kind of ['attributes', 'styles', 'classes']) {
|
|
240
|
-
// Properties other than `subject` should be assigned from `oldValue`.
|
|
241
|
-
if (kind != subject) {
|
|
242
|
-
if (oldValue && oldValue[kind]) {
|
|
243
|
-
newValue[kind] = oldValue[kind];
|
|
244
|
-
}
|
|
245
|
-
continue;
|
|
246
|
-
}
|
|
247
|
-
// `callback` should be applied on property [`subject`].
|
|
248
|
-
if (subject == 'classes') {
|
|
249
|
-
const values = new Set(oldValue && oldValue.classes || []);
|
|
250
|
-
callback(values);
|
|
251
|
-
if (values.size) {
|
|
252
|
-
newValue[kind] = Array.from(values);
|
|
253
|
-
}
|
|
254
|
-
continue;
|
|
255
|
-
}
|
|
256
|
-
const values = new Map(Object.entries(oldValue && oldValue[kind] || {}));
|
|
257
|
-
callback(values);
|
|
258
|
-
if (values.size) {
|
|
259
|
-
newValue[kind] = Object.fromEntries(values);
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
if (Object.keys(newValue).length) {
|
|
263
|
-
if (item.is('documentSelection')) {
|
|
264
|
-
writer.setSelectionAttribute(ghsAttributeName, newValue);
|
|
265
|
-
}
|
|
266
|
-
else {
|
|
267
|
-
writer.setAttribute(ghsAttributeName, newValue, item);
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
else if (oldValue) {
|
|
271
|
-
if (item.is('documentSelection')) {
|
|
272
|
-
writer.removeSelectionAttribute(ghsAttributeName);
|
|
273
|
-
}
|
|
274
|
-
else {
|
|
275
|
-
writer.removeAttribute(ghsAttributeName, item);
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
|
4
4
|
*/
|
|
5
5
|
import { Plugin } from 'ckeditor5/src/core';
|
|
6
|
-
import { updateViewAttributes } from '../
|
|
6
|
+
import { updateViewAttributes } from '../utils';
|
|
7
7
|
import DataFilter from '../datafilter';
|
|
8
8
|
/**
|
|
9
9
|
* Provides the General HTML Support integration with {@link module:code-block/codeblock~CodeBlock Code Block} feature.
|
|
@@ -10,7 +10,7 @@ import { Plugin } from 'ckeditor5/src/core';
|
|
|
10
10
|
import { UpcastWriter } from 'ckeditor5/src/engine';
|
|
11
11
|
import DataSchema from '../dataschema';
|
|
12
12
|
import DataFilter from '../datafilter';
|
|
13
|
-
import { setViewAttributes } from '../
|
|
13
|
+
import { setViewAttributes } from '../utils';
|
|
14
14
|
/**
|
|
15
15
|
* Provides the General HTML Support for custom elements (not registered in the {@link module:html-support/dataschema~DataSchema}).
|
|
16
16
|
*/
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { isEqual } from 'lodash-es';
|
|
9
9
|
import { Plugin } from 'ckeditor5/src/core';
|
|
10
|
-
import { setViewAttributes } from '../
|
|
10
|
+
import { setViewAttributes } from '../utils';
|
|
11
11
|
import DataFilter from '../datafilter';
|
|
12
12
|
/**
|
|
13
13
|
* Provides the General HTML Support integration with the {@link module:list/documentlist~DocumentList Document List} feature.
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* @module html-support/integrations/heading
|
|
7
7
|
*/
|
|
8
8
|
import { Plugin } from 'ckeditor5/src/core';
|
|
9
|
+
import { Enter } from 'ckeditor5/src/enter';
|
|
9
10
|
import DataSchema from '../dataschema';
|
|
10
11
|
/**
|
|
11
12
|
* Provides the General HTML Support integration with {@link module:heading/heading~Heading Heading} feature.
|
|
@@ -14,7 +15,7 @@ export default class HeadingElementSupport extends Plugin {
|
|
|
14
15
|
/**
|
|
15
16
|
* @inheritDoc
|
|
16
17
|
*/
|
|
17
|
-
static get requires(): readonly [typeof DataSchema];
|
|
18
|
+
static get requires(): readonly [typeof DataSchema, typeof Enter];
|
|
18
19
|
/**
|
|
19
20
|
* @inheritDoc
|
|
20
21
|
*/
|
|
@@ -23,4 +24,12 @@ export default class HeadingElementSupport extends Plugin {
|
|
|
23
24
|
* @inheritDoc
|
|
24
25
|
*/
|
|
25
26
|
init(): void;
|
|
27
|
+
/**
|
|
28
|
+
* Registers all elements supported by HeadingEditing to enable custom attributes for those elements.
|
|
29
|
+
*/
|
|
30
|
+
private registerHeadingElements;
|
|
31
|
+
/**
|
|
32
|
+
* Removes css classes from "htmlAttributes" of new paragraph created when hitting "enter" in heading.
|
|
33
|
+
*/
|
|
34
|
+
private removeClassesOnEnter;
|
|
26
35
|
}
|
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
* @module html-support/integrations/heading
|
|
7
7
|
*/
|
|
8
8
|
import { Plugin } from 'ckeditor5/src/core';
|
|
9
|
+
import { Enter } from 'ckeditor5/src/enter';
|
|
9
10
|
import DataSchema from '../dataschema';
|
|
11
|
+
import { modifyGhsAttribute } from '../utils';
|
|
10
12
|
/**
|
|
11
13
|
* Provides the General HTML Support integration with {@link module:heading/heading~Heading Heading} feature.
|
|
12
14
|
*/
|
|
@@ -15,7 +17,7 @@ export default class HeadingElementSupport extends Plugin {
|
|
|
15
17
|
* @inheritDoc
|
|
16
18
|
*/
|
|
17
19
|
static get requires() {
|
|
18
|
-
return [DataSchema];
|
|
20
|
+
return [DataSchema, Enter];
|
|
19
21
|
}
|
|
20
22
|
/**
|
|
21
23
|
* @inheritDoc
|
|
@@ -31,11 +33,16 @@ export default class HeadingElementSupport extends Plugin {
|
|
|
31
33
|
if (!editor.plugins.has('HeadingEditing')) {
|
|
32
34
|
return;
|
|
33
35
|
}
|
|
34
|
-
const dataSchema = editor.plugins.get(DataSchema);
|
|
35
36
|
const options = editor.config.get('heading.options');
|
|
37
|
+
this.registerHeadingElements(editor, options);
|
|
38
|
+
this.removeClassesOnEnter(editor, options);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Registers all elements supported by HeadingEditing to enable custom attributes for those elements.
|
|
42
|
+
*/
|
|
43
|
+
registerHeadingElements(editor, options) {
|
|
44
|
+
const dataSchema = editor.plugins.get(DataSchema);
|
|
36
45
|
const headerModels = [];
|
|
37
|
-
// We are registering all elements supported by HeadingEditing
|
|
38
|
-
// to enable custom attributes for those elements.
|
|
39
46
|
for (const option of options) {
|
|
40
47
|
if ('model' in option && 'view' in option) {
|
|
41
48
|
dataSchema.registerBlockElement({
|
|
@@ -52,4 +59,17 @@ export default class HeadingElementSupport extends Plugin {
|
|
|
52
59
|
}
|
|
53
60
|
});
|
|
54
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Removes css classes from "htmlAttributes" of new paragraph created when hitting "enter" in heading.
|
|
64
|
+
*/
|
|
65
|
+
removeClassesOnEnter(editor, options) {
|
|
66
|
+
const enterCommand = editor.commands.get('enter');
|
|
67
|
+
this.listenTo(enterCommand, 'afterExecute', (evt, data) => {
|
|
68
|
+
const positionParent = editor.model.document.selection.getFirstPosition().parent;
|
|
69
|
+
const isHeading = options.some(option => positionParent.is('element', option.model));
|
|
70
|
+
if (isHeading && positionParent.childCount === 0) {
|
|
71
|
+
modifyGhsAttribute(data.writer, positionParent, 'htmlAttributes', 'classes', classes => classes.clear());
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
55
75
|
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { Plugin } from 'ckeditor5/src/core';
|
|
9
9
|
import DataFilter from '../datafilter';
|
|
10
|
-
import { setViewAttributes, updateViewAttributes } from '../
|
|
10
|
+
import { setViewAttributes, updateViewAttributes } from '../utils';
|
|
11
11
|
import { getDescendantElement } from './integrationutils';
|
|
12
12
|
/**
|
|
13
13
|
* Provides the General HTML Support integration with the {@link module:image/image~Image Image} feature.
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import { Plugin } from 'ckeditor5/src/core';
|
|
9
9
|
import DataFilter from '../datafilter';
|
|
10
10
|
import DataSchema from '../dataschema';
|
|
11
|
-
import { updateViewAttributes } from '../
|
|
11
|
+
import { updateViewAttributes } from '../utils';
|
|
12
12
|
import { getDescendantElement } from './integrationutils';
|
|
13
13
|
/**
|
|
14
14
|
* Provides the General HTML Support integration with {@link module:media-embed/mediaembed~MediaEmbed Media Embed} feature.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
|
4
4
|
*/
|
|
5
5
|
import { Plugin } from 'ckeditor5/src/core';
|
|
6
|
-
import {
|
|
6
|
+
import { updateViewAttributes } from '../utils';
|
|
7
7
|
import DataFilter from '../datafilter';
|
|
8
8
|
import { getDescendantElement } from './integrationutils';
|
|
9
9
|
/**
|
|
@@ -33,6 +33,7 @@ export default class TableElementSupport extends Plugin {
|
|
|
33
33
|
const schema = editor.model.schema;
|
|
34
34
|
const conversion = editor.conversion;
|
|
35
35
|
const dataFilter = editor.plugins.get(DataFilter);
|
|
36
|
+
const tableUtils = editor.plugins.get('TableUtils');
|
|
36
37
|
dataFilter.on('register:figure', () => {
|
|
37
38
|
conversion.for('upcast').add(viewToModelFigureAttributeConverter(dataFilter));
|
|
38
39
|
});
|
|
@@ -50,10 +51,37 @@ export default class TableElementSupport extends Plugin {
|
|
|
50
51
|
});
|
|
51
52
|
conversion.for('upcast').add(viewToModelTableAttributeConverter(dataFilter));
|
|
52
53
|
conversion.for('downcast').add(modelToViewTableAttributeConverter());
|
|
54
|
+
editor.model.document.registerPostFixer(createHeadingRowsPostFixer(editor.model, tableUtils));
|
|
53
55
|
evt.stop();
|
|
54
56
|
});
|
|
55
57
|
}
|
|
56
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* Creates a model post-fixer for thead and tbody GHS related attributes.
|
|
61
|
+
*/
|
|
62
|
+
function createHeadingRowsPostFixer(model, tableUtils) {
|
|
63
|
+
return writer => {
|
|
64
|
+
const changes = model.document.differ.getChanges();
|
|
65
|
+
let wasFixed = false;
|
|
66
|
+
for (const change of changes) {
|
|
67
|
+
if (change.type != 'attribute' || change.attributeKey != 'headingRows') {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
const table = change.range.start.nodeAfter;
|
|
71
|
+
const hasTHeadAttributes = table.getAttribute('htmlTheadAttributes');
|
|
72
|
+
const hasTBodyAttributes = table.getAttribute('htmlTbodyAttributes');
|
|
73
|
+
if (hasTHeadAttributes && !change.attributeNewValue) {
|
|
74
|
+
writer.removeAttribute('htmlTheadAttributes', table);
|
|
75
|
+
wasFixed = true;
|
|
76
|
+
}
|
|
77
|
+
else if (hasTBodyAttributes && change.attributeNewValue == tableUtils.getRows(table)) {
|
|
78
|
+
writer.removeAttribute('htmlTbodyAttributes', table);
|
|
79
|
+
wasFixed = true;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return wasFixed;
|
|
83
|
+
};
|
|
84
|
+
}
|
|
57
85
|
/**
|
|
58
86
|
* View-to-model conversion helper preserving allowed attributes on {@link module:table/table~Table Table}
|
|
59
87
|
* feature model element.
|
|
@@ -63,6 +91,9 @@ export default class TableElementSupport extends Plugin {
|
|
|
63
91
|
function viewToModelTableAttributeConverter(dataFilter) {
|
|
64
92
|
return (dispatcher) => {
|
|
65
93
|
dispatcher.on('element:table', (evt, data, conversionApi) => {
|
|
94
|
+
if (!data.modelRange) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
66
97
|
const viewTableElement = data.viewItem;
|
|
67
98
|
preserveElementAttributes(viewTableElement, 'htmlAttributes');
|
|
68
99
|
for (const childNode of viewTableElement.getChildren()) {
|
|
@@ -116,12 +147,16 @@ function modelToViewTableAttributeConverter() {
|
|
|
116
147
|
addAttributeConversionDispatcherHandler('tbody', 'htmlTbodyAttributes');
|
|
117
148
|
function addAttributeConversionDispatcherHandler(elementName, attributeName) {
|
|
118
149
|
dispatcher.on(`attribute:${attributeName}:table`, (evt, data, conversionApi) => {
|
|
119
|
-
if (!conversionApi.consumable.
|
|
150
|
+
if (!conversionApi.consumable.test(data.item, evt.name)) {
|
|
120
151
|
return;
|
|
121
152
|
}
|
|
122
153
|
const containerElement = conversionApi.mapper.toViewElement(data.item);
|
|
123
154
|
const viewElement = getDescendantElement(conversionApi.writer, containerElement, elementName);
|
|
124
|
-
|
|
155
|
+
if (!viewElement) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
conversionApi.consumable.consume(data.item, evt.name);
|
|
159
|
+
updateViewAttributes(conversionApi.writer, data.attributeOldValue, data.attributeNewValue, viewElement);
|
|
125
160
|
});
|
|
126
161
|
}
|
|
127
162
|
};
|
package/src/schemadefinitions.js
CHANGED
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
// noscript
|
|
47
47
|
export default {
|
|
48
48
|
block: [
|
|
49
|
-
// Existing features
|
|
49
|
+
// Existing features.
|
|
50
50
|
{
|
|
51
51
|
model: 'codeBlock',
|
|
52
52
|
view: 'pre'
|
|
@@ -111,7 +111,7 @@ export default {
|
|
|
111
111
|
model: 'imageInline',
|
|
112
112
|
view: 'img'
|
|
113
113
|
},
|
|
114
|
-
// Compatibility features
|
|
114
|
+
// Compatibility features.
|
|
115
115
|
{
|
|
116
116
|
model: 'htmlP',
|
|
117
117
|
view: 'p',
|
|
@@ -509,102 +509,153 @@ export default {
|
|
|
509
509
|
}
|
|
510
510
|
],
|
|
511
511
|
inline: [
|
|
512
|
+
// Existing features (attribute set on an existing model element).
|
|
513
|
+
{
|
|
514
|
+
model: 'htmlLiAttributes',
|
|
515
|
+
view: 'li',
|
|
516
|
+
appliesToBlock: true
|
|
517
|
+
},
|
|
518
|
+
{
|
|
519
|
+
model: 'htmlListAttributes',
|
|
520
|
+
view: 'ol',
|
|
521
|
+
appliesToBlock: true
|
|
522
|
+
},
|
|
523
|
+
{
|
|
524
|
+
model: 'htmlListAttributes',
|
|
525
|
+
view: 'ul',
|
|
526
|
+
appliesToBlock: true
|
|
527
|
+
},
|
|
528
|
+
{
|
|
529
|
+
model: 'htmlFigureAttributes',
|
|
530
|
+
view: 'figure',
|
|
531
|
+
appliesToBlock: 'table'
|
|
532
|
+
},
|
|
533
|
+
{
|
|
534
|
+
model: 'htmlTheadAttributes',
|
|
535
|
+
view: 'thead',
|
|
536
|
+
appliesToBlock: 'table'
|
|
537
|
+
},
|
|
538
|
+
{
|
|
539
|
+
model: 'htmlTbodyAttributes',
|
|
540
|
+
view: 'tbody',
|
|
541
|
+
appliesToBlock: 'table'
|
|
542
|
+
},
|
|
543
|
+
{
|
|
544
|
+
model: 'htmlFigureAttributes',
|
|
545
|
+
view: 'figure',
|
|
546
|
+
appliesToBlock: 'imageBlock'
|
|
547
|
+
},
|
|
548
|
+
// Compatibility features.
|
|
512
549
|
{
|
|
513
550
|
model: 'htmlAcronym',
|
|
514
551
|
view: 'acronym',
|
|
515
552
|
attributeProperties: {
|
|
516
|
-
copyOnEnter: true
|
|
553
|
+
copyOnEnter: true,
|
|
554
|
+
isFormatting: true
|
|
517
555
|
}
|
|
518
556
|
},
|
|
519
557
|
{
|
|
520
558
|
model: 'htmlTt',
|
|
521
559
|
view: 'tt',
|
|
522
560
|
attributeProperties: {
|
|
523
|
-
copyOnEnter: true
|
|
561
|
+
copyOnEnter: true,
|
|
562
|
+
isFormatting: true
|
|
524
563
|
}
|
|
525
564
|
},
|
|
526
565
|
{
|
|
527
566
|
model: 'htmlFont',
|
|
528
567
|
view: 'font',
|
|
529
568
|
attributeProperties: {
|
|
530
|
-
copyOnEnter: true
|
|
569
|
+
copyOnEnter: true,
|
|
570
|
+
isFormatting: true
|
|
531
571
|
}
|
|
532
572
|
},
|
|
533
573
|
{
|
|
534
574
|
model: 'htmlTime',
|
|
535
575
|
view: 'time',
|
|
536
576
|
attributeProperties: {
|
|
537
|
-
copyOnEnter: true
|
|
577
|
+
copyOnEnter: true,
|
|
578
|
+
isFormatting: true
|
|
538
579
|
}
|
|
539
580
|
},
|
|
540
581
|
{
|
|
541
582
|
model: 'htmlVar',
|
|
542
583
|
view: 'var',
|
|
543
584
|
attributeProperties: {
|
|
544
|
-
copyOnEnter: true
|
|
585
|
+
copyOnEnter: true,
|
|
586
|
+
isFormatting: true
|
|
545
587
|
}
|
|
546
588
|
},
|
|
547
589
|
{
|
|
548
590
|
model: 'htmlBig',
|
|
549
591
|
view: 'big',
|
|
550
592
|
attributeProperties: {
|
|
551
|
-
copyOnEnter: true
|
|
593
|
+
copyOnEnter: true,
|
|
594
|
+
isFormatting: true
|
|
552
595
|
}
|
|
553
596
|
},
|
|
554
597
|
{
|
|
555
598
|
model: 'htmlSmall',
|
|
556
599
|
view: 'small',
|
|
557
600
|
attributeProperties: {
|
|
558
|
-
copyOnEnter: true
|
|
601
|
+
copyOnEnter: true,
|
|
602
|
+
isFormatting: true
|
|
559
603
|
}
|
|
560
604
|
},
|
|
561
605
|
{
|
|
562
606
|
model: 'htmlSamp',
|
|
563
607
|
view: 'samp',
|
|
564
608
|
attributeProperties: {
|
|
565
|
-
copyOnEnter: true
|
|
609
|
+
copyOnEnter: true,
|
|
610
|
+
isFormatting: true
|
|
566
611
|
}
|
|
567
612
|
},
|
|
568
613
|
{
|
|
569
614
|
model: 'htmlQ',
|
|
570
615
|
view: 'q',
|
|
571
616
|
attributeProperties: {
|
|
572
|
-
copyOnEnter: true
|
|
617
|
+
copyOnEnter: true,
|
|
618
|
+
isFormatting: true
|
|
573
619
|
}
|
|
574
620
|
},
|
|
575
621
|
{
|
|
576
622
|
model: 'htmlOutput',
|
|
577
623
|
view: 'output',
|
|
578
624
|
attributeProperties: {
|
|
579
|
-
copyOnEnter: true
|
|
625
|
+
copyOnEnter: true,
|
|
626
|
+
isFormatting: true
|
|
580
627
|
}
|
|
581
628
|
},
|
|
582
629
|
{
|
|
583
630
|
model: 'htmlKbd',
|
|
584
631
|
view: 'kbd',
|
|
585
632
|
attributeProperties: {
|
|
586
|
-
copyOnEnter: true
|
|
633
|
+
copyOnEnter: true,
|
|
634
|
+
isFormatting: true
|
|
587
635
|
}
|
|
588
636
|
},
|
|
589
637
|
{
|
|
590
638
|
model: 'htmlBdi',
|
|
591
639
|
view: 'bdi',
|
|
592
640
|
attributeProperties: {
|
|
593
|
-
copyOnEnter: true
|
|
641
|
+
copyOnEnter: true,
|
|
642
|
+
isFormatting: true
|
|
594
643
|
}
|
|
595
644
|
},
|
|
596
645
|
{
|
|
597
646
|
model: 'htmlBdo',
|
|
598
647
|
view: 'bdo',
|
|
599
648
|
attributeProperties: {
|
|
600
|
-
copyOnEnter: true
|
|
649
|
+
copyOnEnter: true,
|
|
650
|
+
isFormatting: true
|
|
601
651
|
}
|
|
602
652
|
},
|
|
603
653
|
{
|
|
604
654
|
model: 'htmlAbbr',
|
|
605
655
|
view: 'abbr',
|
|
606
656
|
attributeProperties: {
|
|
607
|
-
copyOnEnter: true
|
|
657
|
+
copyOnEnter: true,
|
|
658
|
+
isFormatting: true
|
|
608
659
|
}
|
|
609
660
|
},
|
|
610
661
|
{
|
|
@@ -667,7 +718,8 @@ export default {
|
|
|
667
718
|
view: 'del',
|
|
668
719
|
coupledAttribute: 'strikethrough',
|
|
669
720
|
attributeProperties: {
|
|
670
|
-
copyOnEnter: true
|
|
721
|
+
copyOnEnter: true,
|
|
722
|
+
isFormatting: true
|
|
671
723
|
}
|
|
672
724
|
},
|
|
673
725
|
// TODO According to HTML-spec can behave as div-like element, although CKE4 only handles it as an inline element.
|
|
@@ -675,7 +727,8 @@ export default {
|
|
|
675
727
|
model: 'htmlIns',
|
|
676
728
|
view: 'ins',
|
|
677
729
|
attributeProperties: {
|
|
678
|
-
copyOnEnter: true
|
|
730
|
+
copyOnEnter: true,
|
|
731
|
+
isFormatting: true
|
|
679
732
|
}
|
|
680
733
|
},
|
|
681
734
|
{
|
|
@@ -718,38 +771,43 @@ export default {
|
|
|
718
771
|
model: 'htmlMark',
|
|
719
772
|
view: 'mark',
|
|
720
773
|
attributeProperties: {
|
|
721
|
-
copyOnEnter: true
|
|
774
|
+
copyOnEnter: true,
|
|
775
|
+
isFormatting: true
|
|
722
776
|
}
|
|
723
777
|
},
|
|
724
778
|
{
|
|
725
779
|
model: 'htmlSpan',
|
|
726
780
|
view: 'span',
|
|
727
781
|
attributeProperties: {
|
|
728
|
-
copyOnEnter: true
|
|
782
|
+
copyOnEnter: true,
|
|
783
|
+
isFormatting: true
|
|
729
784
|
}
|
|
730
785
|
},
|
|
731
786
|
{
|
|
732
787
|
model: 'htmlCite',
|
|
733
788
|
view: 'cite',
|
|
734
789
|
attributeProperties: {
|
|
735
|
-
copyOnEnter: true
|
|
790
|
+
copyOnEnter: true,
|
|
791
|
+
isFormatting: true
|
|
736
792
|
}
|
|
737
793
|
},
|
|
738
794
|
{
|
|
739
795
|
model: 'htmlLabel',
|
|
740
796
|
view: 'label',
|
|
741
797
|
attributeProperties: {
|
|
742
|
-
copyOnEnter: true
|
|
798
|
+
copyOnEnter: true,
|
|
799
|
+
isFormatting: true
|
|
743
800
|
}
|
|
744
801
|
},
|
|
745
802
|
{
|
|
746
803
|
model: 'htmlDfn',
|
|
747
804
|
view: 'dfn',
|
|
748
805
|
attributeProperties: {
|
|
749
|
-
copyOnEnter: true
|
|
806
|
+
copyOnEnter: true,
|
|
807
|
+
isFormatting: true
|
|
750
808
|
}
|
|
751
809
|
},
|
|
752
|
-
// Objects
|
|
810
|
+
// Objects.
|
|
753
811
|
{
|
|
754
812
|
model: 'htmlObject',
|
|
755
813
|
view: 'object',
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
|
4
4
|
*/
|
|
5
5
|
/**
|
|
6
|
-
* @module html-support/
|
|
6
|
+
* @module html-support/utils
|
|
7
7
|
*/
|
|
8
|
-
import type { DowncastWriter, ViewElement } from 'ckeditor5/src/engine';
|
|
8
|
+
import type { DocumentSelection, DowncastWriter, Item, ViewElement, Writer } from 'ckeditor5/src/engine';
|
|
9
9
|
export interface GHSViewAttributes {
|
|
10
10
|
attributes?: Record<string, unknown>;
|
|
11
11
|
classes?: Array<string>;
|
|
@@ -40,3 +40,22 @@ export declare function removeViewAttributes(writer: DowncastWriter, viewAttribu
|
|
|
40
40
|
* Merges view element attribute objects.
|
|
41
41
|
*/
|
|
42
42
|
export declare function mergeViewElementAttributes(target: GHSViewAttributes, source: GHSViewAttributes): GHSViewAttributes;
|
|
43
|
+
type ModifyGhsAttributesCallback = (t: Map<string, unknown>) => void;
|
|
44
|
+
type ModifyGhsClassesCallback = (t: Set<string>) => void;
|
|
45
|
+
type ModifyGhsStylesCallback = (t: Map<string, string>) => void;
|
|
46
|
+
/**
|
|
47
|
+
* Updates a GHS attribute on a specified item.
|
|
48
|
+
* @param callback That receives a map as an argument and should modify it (add or remove entries).
|
|
49
|
+
*/
|
|
50
|
+
export declare function modifyGhsAttribute(writer: Writer, item: Item | DocumentSelection, ghsAttributeName: string, subject: 'attributes', callback: ModifyGhsAttributesCallback): void;
|
|
51
|
+
/**
|
|
52
|
+
* Updates a GHS attribute on a specified item.
|
|
53
|
+
* @param callback That receives a set as an argument and should modify it (add or remove entries).
|
|
54
|
+
*/
|
|
55
|
+
export declare function modifyGhsAttribute(writer: Writer, item: Item | DocumentSelection, ghsAttributeName: string, subject: 'classes', callback: ModifyGhsClassesCallback): void;
|
|
56
|
+
/**
|
|
57
|
+
* Updates a GHS attribute on a specified item.
|
|
58
|
+
* @param callback That receives a map as an argument and should modify it (add or remove entries).
|
|
59
|
+
*/
|
|
60
|
+
export declare function modifyGhsAttribute(writer: Writer, item: Item | DocumentSelection, ghsAttributeName: string, subject: 'styles', callback: ModifyGhsStylesCallback): void;
|
|
61
|
+
export {};
|
|
@@ -79,3 +79,46 @@ export function mergeViewElementAttributes(target, source) {
|
|
|
79
79
|
}
|
|
80
80
|
return result;
|
|
81
81
|
}
|
|
82
|
+
export function modifyGhsAttribute(writer, item, ghsAttributeName, subject, callback) {
|
|
83
|
+
const oldValue = item.getAttribute(ghsAttributeName);
|
|
84
|
+
const newValue = {};
|
|
85
|
+
for (const kind of ['attributes', 'styles', 'classes']) {
|
|
86
|
+
// Properties other than `subject` should be assigned from `oldValue`.
|
|
87
|
+
if (kind != subject) {
|
|
88
|
+
if (oldValue && oldValue[kind]) {
|
|
89
|
+
newValue[kind] = oldValue[kind];
|
|
90
|
+
}
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
// `callback` should be applied on property [`subject`].
|
|
94
|
+
if (subject == 'classes') {
|
|
95
|
+
const values = new Set(oldValue && oldValue.classes || []);
|
|
96
|
+
callback(values);
|
|
97
|
+
if (values.size) {
|
|
98
|
+
newValue[kind] = Array.from(values);
|
|
99
|
+
}
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
const values = new Map(Object.entries(oldValue && oldValue[kind] || {}));
|
|
103
|
+
callback(values);
|
|
104
|
+
if (values.size) {
|
|
105
|
+
newValue[kind] = Object.fromEntries(values);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (Object.keys(newValue).length) {
|
|
109
|
+
if (item.is('documentSelection')) {
|
|
110
|
+
writer.setSelectionAttribute(ghsAttributeName, newValue);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
writer.setAttribute(ghsAttributeName, newValue, item);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
else if (oldValue) {
|
|
117
|
+
if (item.is('documentSelection')) {
|
|
118
|
+
writer.removeSelectionAttribute(ghsAttributeName);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
writer.removeAttribute(ghsAttributeName, item);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|