@ckeditor/ckeditor5-engine 35.0.1 → 35.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/CHANGELOG.md +4 -4
- package/package.json +30 -24
- package/src/controller/datacontroller.js +467 -561
- package/src/controller/editingcontroller.js +168 -204
- package/src/conversion/conversion.js +541 -565
- package/src/conversion/conversionhelpers.js +24 -28
- package/src/conversion/downcastdispatcher.js +457 -686
- package/src/conversion/downcasthelpers.js +1583 -1965
- package/src/conversion/mapper.js +518 -707
- package/src/conversion/modelconsumable.js +240 -283
- package/src/conversion/upcastdispatcher.js +372 -718
- package/src/conversion/upcasthelpers.js +707 -818
- package/src/conversion/viewconsumable.js +524 -581
- package/src/dataprocessor/basichtmlwriter.js +12 -16
- package/src/dataprocessor/dataprocessor.js +5 -0
- package/src/dataprocessor/htmldataprocessor.js +100 -116
- package/src/dataprocessor/htmlwriter.js +1 -18
- package/src/dataprocessor/xmldataprocessor.js +116 -137
- package/src/dev-utils/model.js +260 -352
- package/src/dev-utils/operationreplayer.js +106 -126
- package/src/dev-utils/utils.js +34 -51
- package/src/dev-utils/view.js +632 -753
- package/src/index.js +0 -11
- package/src/model/batch.js +111 -127
- package/src/model/differ.js +988 -1233
- package/src/model/document.js +340 -449
- package/src/model/documentfragment.js +327 -364
- package/src/model/documentselection.js +996 -1189
- package/src/model/element.js +306 -410
- package/src/model/history.js +224 -262
- package/src/model/item.js +5 -0
- package/src/model/liveposition.js +84 -145
- package/src/model/liverange.js +108 -185
- package/src/model/markercollection.js +379 -480
- package/src/model/model.js +883 -1034
- package/src/model/node.js +419 -463
- package/src/model/nodelist.js +176 -201
- package/src/model/operation/attributeoperation.js +153 -182
- package/src/model/operation/detachoperation.js +64 -83
- package/src/model/operation/insertoperation.js +135 -166
- package/src/model/operation/markeroperation.js +114 -140
- package/src/model/operation/mergeoperation.js +163 -191
- package/src/model/operation/moveoperation.js +157 -187
- package/src/model/operation/nooperation.js +28 -38
- package/src/model/operation/operation.js +106 -125
- package/src/model/operation/operationfactory.js +30 -34
- package/src/model/operation/renameoperation.js +109 -135
- package/src/model/operation/rootattributeoperation.js +155 -188
- package/src/model/operation/splitoperation.js +196 -232
- package/src/model/operation/transform.js +1833 -2204
- package/src/model/operation/utils.js +140 -204
- package/src/model/position.js +980 -1053
- package/src/model/range.js +910 -1028
- package/src/model/rootelement.js +77 -97
- package/src/model/schema.js +1189 -1835
- package/src/model/selection.js +745 -862
- package/src/model/text.js +90 -114
- package/src/model/textproxy.js +204 -240
- package/src/model/treewalker.js +316 -397
- package/src/model/typecheckable.js +16 -0
- package/src/model/utils/autoparagraphing.js +32 -44
- package/src/model/utils/deletecontent.js +334 -418
- package/src/model/utils/findoptimalinsertionrange.js +25 -36
- package/src/model/utils/getselectedcontent.js +96 -118
- package/src/model/utils/insertcontent.js +757 -773
- package/src/model/utils/insertobject.js +96 -119
- package/src/model/utils/modifyselection.js +120 -158
- package/src/model/utils/selection-post-fixer.js +153 -201
- package/src/model/writer.js +1305 -1474
- package/src/view/attributeelement.js +189 -225
- package/src/view/containerelement.js +75 -85
- package/src/view/document.js +172 -215
- package/src/view/documentfragment.js +200 -249
- package/src/view/documentselection.js +338 -367
- package/src/view/domconverter.js +1370 -1617
- package/src/view/downcastwriter.js +1747 -2076
- package/src/view/editableelement.js +81 -97
- package/src/view/element.js +739 -890
- package/src/view/elementdefinition.js +5 -0
- package/src/view/emptyelement.js +82 -92
- package/src/view/filler.js +35 -50
- package/src/view/item.js +5 -0
- package/src/view/matcher.js +260 -559
- package/src/view/node.js +274 -360
- package/src/view/observer/arrowkeysobserver.js +19 -28
- package/src/view/observer/bubblingemittermixin.js +120 -263
- package/src/view/observer/bubblingeventinfo.js +47 -55
- package/src/view/observer/clickobserver.js +7 -13
- package/src/view/observer/compositionobserver.js +14 -24
- package/src/view/observer/domeventdata.js +57 -67
- package/src/view/observer/domeventobserver.js +40 -64
- package/src/view/observer/fakeselectionobserver.js +81 -96
- package/src/view/observer/focusobserver.js +45 -61
- package/src/view/observer/inputobserver.js +7 -13
- package/src/view/observer/keyobserver.js +17 -27
- package/src/view/observer/mouseobserver.js +7 -14
- package/src/view/observer/mutationobserver.js +220 -315
- package/src/view/observer/observer.js +81 -102
- package/src/view/observer/selectionobserver.js +199 -246
- package/src/view/observer/tabobserver.js +23 -36
- package/src/view/placeholder.js +128 -173
- package/src/view/position.js +350 -401
- package/src/view/range.js +453 -513
- package/src/view/rawelement.js +85 -112
- package/src/view/renderer.js +874 -1018
- package/src/view/rooteditableelement.js +80 -90
- package/src/view/selection.js +608 -689
- package/src/view/styles/background.js +43 -44
- package/src/view/styles/border.js +220 -276
- package/src/view/styles/margin.js +8 -17
- package/src/view/styles/padding.js +8 -16
- package/src/view/styles/utils.js +127 -160
- package/src/view/stylesmap.js +728 -905
- package/src/view/text.js +102 -126
- package/src/view/textproxy.js +144 -170
- package/src/view/treewalker.js +383 -479
- package/src/view/typecheckable.js +19 -0
- package/src/view/uielement.js +166 -187
- package/src/view/upcastwriter.js +395 -449
- package/src/view/view.js +569 -664
- package/src/dataprocessor/dataprocessor.jsdoc +0 -64
- package/src/model/item.jsdoc +0 -14
- package/src/view/elementdefinition.jsdoc +0 -59
- package/src/view/item.jsdoc +0 -14
package/src/view/matcher.js
CHANGED
|
@@ -2,245 +2,212 @@
|
|
|
2
2
|
* @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
3
|
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
|
4
4
|
*/
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* @module engine/view/matcher
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
5
|
import { isPlainObject } from 'lodash-es';
|
|
11
|
-
|
|
12
6
|
import { logWarning } from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
|
|
13
|
-
|
|
14
7
|
/**
|
|
15
8
|
* View matcher class.
|
|
16
9
|
* Instance of this class can be used to find {@link module:engine/view/element~Element elements} that match given pattern.
|
|
17
10
|
*/
|
|
18
11
|
export default class Matcher {
|
|
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
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
*
|
|
164
|
-
* @returns {String|null} Element name trying to match.
|
|
165
|
-
*/
|
|
166
|
-
getElementName() {
|
|
167
|
-
if ( this._patterns.length !== 1 ) {
|
|
168
|
-
return null;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
const pattern = this._patterns[ 0 ];
|
|
172
|
-
const name = pattern.name;
|
|
173
|
-
|
|
174
|
-
return ( typeof pattern != 'function' && name && !( name instanceof RegExp ) ) ? name : null;
|
|
175
|
-
}
|
|
12
|
+
/**
|
|
13
|
+
* Creates new instance of Matcher.
|
|
14
|
+
*
|
|
15
|
+
* @param {String|RegExp|Object|Function} [pattern] Match patterns. See {@link module:engine/view/matcher~Matcher#add add method} for
|
|
16
|
+
* more information.
|
|
17
|
+
*/
|
|
18
|
+
constructor(...pattern) {
|
|
19
|
+
/**
|
|
20
|
+
* @private
|
|
21
|
+
* @type {Array<Object|Function>}
|
|
22
|
+
*/
|
|
23
|
+
this._patterns = [];
|
|
24
|
+
this.add(...pattern);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Adds pattern or patterns to matcher instance.
|
|
28
|
+
*
|
|
29
|
+
* // String.
|
|
30
|
+
* matcher.add( 'div' );
|
|
31
|
+
*
|
|
32
|
+
* // Regular expression.
|
|
33
|
+
* matcher.add( /^\w/ );
|
|
34
|
+
*
|
|
35
|
+
* // Single class.
|
|
36
|
+
* matcher.add( {
|
|
37
|
+
* classes: 'foobar'
|
|
38
|
+
* } );
|
|
39
|
+
*
|
|
40
|
+
* See {@link module:engine/view/matcher~MatcherPattern} for more examples.
|
|
41
|
+
*
|
|
42
|
+
* Multiple patterns can be added in one call:
|
|
43
|
+
*
|
|
44
|
+
* matcher.add( 'div', { classes: 'foobar' } );
|
|
45
|
+
*
|
|
46
|
+
* @param {Object|String|RegExp|Function} pattern Object describing pattern details. If string or regular expression
|
|
47
|
+
* is provided it will be used to match element's name. Pattern can be also provided in a form
|
|
48
|
+
* of a function - then this function will be called with each {@link module:engine/view/element~Element element} as a parameter.
|
|
49
|
+
* Function's return value will be stored under `match` key of the object returned from
|
|
50
|
+
* {@link module:engine/view/matcher~Matcher#match match} or {@link module:engine/view/matcher~Matcher#matchAll matchAll} methods.
|
|
51
|
+
* @param {String|RegExp} [pattern.name] Name or regular expression to match element's name.
|
|
52
|
+
* @param {Object} [pattern.attributes] Object with key-value pairs representing attributes to match. Each object key
|
|
53
|
+
* represents attribute name. Value under that key can be either:
|
|
54
|
+
* * `true` - then attribute is just required (can be empty),
|
|
55
|
+
* * a string - then attribute has to be equal, or
|
|
56
|
+
* * a regular expression - then attribute has to match the expression.
|
|
57
|
+
* @param {String|RegExp|Array} [pattern.classes] Class name or array of class names to match. Each name can be
|
|
58
|
+
* provided in a form of string or regular expression.
|
|
59
|
+
* @param {Object} [pattern.styles] Object with key-value pairs representing styles to match. Each object key
|
|
60
|
+
* represents style name. Value under that key can be either a string or a regular expression and it will be used
|
|
61
|
+
* to match style value.
|
|
62
|
+
*/
|
|
63
|
+
add(...pattern) {
|
|
64
|
+
for (let item of pattern) {
|
|
65
|
+
// String or RegExp pattern is used as element's name.
|
|
66
|
+
if (typeof item == 'string' || item instanceof RegExp) {
|
|
67
|
+
item = { name: item };
|
|
68
|
+
}
|
|
69
|
+
this._patterns.push(item);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Matches elements for currently stored patterns. Returns match information about first found
|
|
74
|
+
* {@link module:engine/view/element~Element element}, otherwise returns `null`.
|
|
75
|
+
*
|
|
76
|
+
* Example of returned object:
|
|
77
|
+
*
|
|
78
|
+
* {
|
|
79
|
+
* element: <instance of found element>,
|
|
80
|
+
* pattern: <pattern used to match found element>,
|
|
81
|
+
* match: {
|
|
82
|
+
* name: true,
|
|
83
|
+
* attributes: [ 'title', 'href' ],
|
|
84
|
+
* classes: [ 'foo' ],
|
|
85
|
+
* styles: [ 'color', 'position' ]
|
|
86
|
+
* }
|
|
87
|
+
* }
|
|
88
|
+
*
|
|
89
|
+
* @see module:engine/view/matcher~Matcher#add
|
|
90
|
+
* @see module:engine/view/matcher~Matcher#matchAll
|
|
91
|
+
* @param {...module:engine/view/element~Element} element View element to match against stored patterns.
|
|
92
|
+
* @returns {Object|null} result
|
|
93
|
+
* @returns {module:engine/view/element~Element} result.element Matched view element.
|
|
94
|
+
* @returns {Object|String|RegExp|Function} result.pattern Pattern that was used to find matched element.
|
|
95
|
+
* @returns {Object} result.match Object representing matched element parts.
|
|
96
|
+
* @returns {Boolean} [result.match.name] True if name of the element was matched.
|
|
97
|
+
* @returns {Array} [result.match.attributes] Array with matched attribute names.
|
|
98
|
+
* @returns {Array} [result.match.classes] Array with matched class names.
|
|
99
|
+
* @returns {Array} [result.match.styles] Array with matched style names.
|
|
100
|
+
*/
|
|
101
|
+
match(...element) {
|
|
102
|
+
for (const singleElement of element) {
|
|
103
|
+
for (const pattern of this._patterns) {
|
|
104
|
+
const match = isElementMatching(singleElement, pattern);
|
|
105
|
+
if (match) {
|
|
106
|
+
return {
|
|
107
|
+
element: singleElement,
|
|
108
|
+
pattern,
|
|
109
|
+
match
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Matches elements for currently stored patterns. Returns array of match information with all found
|
|
118
|
+
* {@link module:engine/view/element~Element elements}. If no element is found - returns `null`.
|
|
119
|
+
*
|
|
120
|
+
* @see module:engine/view/matcher~Matcher#add
|
|
121
|
+
* @see module:engine/view/matcher~Matcher#match
|
|
122
|
+
* @param {...module:engine/view/element~Element} element View element to match against stored patterns.
|
|
123
|
+
* @returns {Array.<Object>|null} Array with match information about found elements or `null`. For more information
|
|
124
|
+
* see {@link module:engine/view/matcher~Matcher#match match method} description.
|
|
125
|
+
*/
|
|
126
|
+
matchAll(...element) {
|
|
127
|
+
const results = [];
|
|
128
|
+
for (const singleElement of element) {
|
|
129
|
+
for (const pattern of this._patterns) {
|
|
130
|
+
const match = isElementMatching(singleElement, pattern);
|
|
131
|
+
if (match) {
|
|
132
|
+
results.push({
|
|
133
|
+
element: singleElement,
|
|
134
|
+
pattern,
|
|
135
|
+
match
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return results.length > 0 ? results : null;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Returns the name of the element to match if there is exactly one pattern added to the matcher instance
|
|
144
|
+
* and it matches element name defined by `string` (not `RegExp`). Otherwise, returns `null`.
|
|
145
|
+
*
|
|
146
|
+
* @returns {String|null} Element name trying to match.
|
|
147
|
+
*/
|
|
148
|
+
getElementName() {
|
|
149
|
+
if (this._patterns.length !== 1) {
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
const pattern = this._patterns[0];
|
|
153
|
+
const name = pattern.name;
|
|
154
|
+
return (typeof pattern != 'function' && name && !(name instanceof RegExp)) ? name : null;
|
|
155
|
+
}
|
|
176
156
|
}
|
|
177
|
-
|
|
178
157
|
// Returns match information if {@link module:engine/view/element~Element element} is matching provided pattern.
|
|
179
158
|
// If element cannot be matched to provided pattern - returns `null`.
|
|
180
159
|
//
|
|
181
160
|
// @param {module:engine/view/element~Element} element
|
|
182
161
|
// @param {Object|String|RegExp|Function} pattern
|
|
183
162
|
// @returns {Object|null} Returns object with match information or null if element is not matching.
|
|
184
|
-
function isElementMatching(
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
if ( pattern.styles ) {
|
|
220
|
-
match.styles = matchStyles( pattern.styles, element );
|
|
221
|
-
|
|
222
|
-
if ( !match.styles ) {
|
|
223
|
-
return false;
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
return match;
|
|
163
|
+
function isElementMatching(element, pattern) {
|
|
164
|
+
// If pattern is provided as function - return result of that function;
|
|
165
|
+
if (typeof pattern == 'function') {
|
|
166
|
+
return pattern(element);
|
|
167
|
+
}
|
|
168
|
+
const match = {};
|
|
169
|
+
// Check element's name.
|
|
170
|
+
if (pattern.name) {
|
|
171
|
+
match.name = matchName(pattern.name, element.name);
|
|
172
|
+
if (!match.name) {
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// Check element's attributes.
|
|
177
|
+
if (pattern.attributes) {
|
|
178
|
+
match.attributes = matchAttributes(pattern.attributes, element);
|
|
179
|
+
if (!match.attributes) {
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
// Check element's classes.
|
|
184
|
+
if (pattern.classes) {
|
|
185
|
+
match.classes = matchClasses(pattern.classes, element);
|
|
186
|
+
if (!match.classes) {
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// Check element's styles.
|
|
191
|
+
if (pattern.styles) {
|
|
192
|
+
match.styles = matchStyles(pattern.styles, element);
|
|
193
|
+
if (!match.styles) {
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return match;
|
|
228
198
|
}
|
|
229
|
-
|
|
230
199
|
// Checks if name can be matched by provided pattern.
|
|
231
200
|
//
|
|
232
201
|
// @param {String|RegExp} pattern
|
|
233
202
|
// @param {String} name
|
|
234
203
|
// @returns {Boolean} Returns `true` if name can be matched, `false` otherwise.
|
|
235
|
-
function matchName(
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
return pattern === name;
|
|
204
|
+
function matchName(pattern, name) {
|
|
205
|
+
// If pattern is provided as RegExp - test against this regexp.
|
|
206
|
+
if (pattern instanceof RegExp) {
|
|
207
|
+
return !!name.match(pattern);
|
|
208
|
+
}
|
|
209
|
+
return pattern === name;
|
|
242
210
|
}
|
|
243
|
-
|
|
244
211
|
// Checks if an array of key/value pairs can be matched against provided patterns.
|
|
245
212
|
//
|
|
246
213
|
// Patterns can be provided in a following ways:
|
|
@@ -291,31 +258,25 @@ function matchName( pattern, name ) {
|
|
|
291
258
|
// @param {Iterable.<String>} keys Attribute, style or class keys.
|
|
292
259
|
// @param {Function} valueGetter A function providing value for a given item key.
|
|
293
260
|
// @returns {Array|null} Returns array with matched attribute names or `null` if no attributes were matched.
|
|
294
|
-
function matchPatterns(
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
if ( !normalizedPatterns.length || match.length < normalizedPatterns.length ) {
|
|
313
|
-
return null;
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
return match;
|
|
261
|
+
function matchPatterns(patterns, keys, valueGetter) {
|
|
262
|
+
const normalizedPatterns = normalizePatterns(patterns);
|
|
263
|
+
const normalizedItems = Array.from(keys);
|
|
264
|
+
const match = [];
|
|
265
|
+
normalizedPatterns.forEach(([patternKey, patternValue]) => {
|
|
266
|
+
normalizedItems.forEach(itemKey => {
|
|
267
|
+
if (isKeyMatched(patternKey, itemKey) &&
|
|
268
|
+
isValueMatched(patternValue, itemKey, valueGetter)) {
|
|
269
|
+
match.push(itemKey);
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
// Return matches only if there are at least as many of them as there are patterns.
|
|
274
|
+
// The RegExp pattern can match more than one item.
|
|
275
|
+
if (!normalizedPatterns.length || match.length < normalizedPatterns.length) {
|
|
276
|
+
return undefined;
|
|
277
|
+
}
|
|
278
|
+
return match;
|
|
317
279
|
}
|
|
318
|
-
|
|
319
280
|
// Bring all the possible pattern forms to an array of arrays where first item is a key and second is a value.
|
|
320
281
|
//
|
|
321
282
|
// Examples:
|
|
@@ -363,351 +324,93 @@ function matchPatterns( patterns, keys, valueGetter ) {
|
|
|
363
324
|
//
|
|
364
325
|
// @param {Object|Array} patterns
|
|
365
326
|
// @returns {Array|null} Returns an array of objects or null if provided patterns were not in an expected form.
|
|
366
|
-
function normalizePatterns(
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
// Other cases (true, string or regexp).
|
|
388
|
-
return [ [ patterns, true ] ];
|
|
327
|
+
function normalizePatterns(patterns) {
|
|
328
|
+
if (Array.isArray(patterns)) {
|
|
329
|
+
return patterns.map((pattern) => {
|
|
330
|
+
if (isPlainObject(pattern)) {
|
|
331
|
+
if (pattern.key === undefined || pattern.value === undefined) {
|
|
332
|
+
// Documented at the end of matcher.js.
|
|
333
|
+
logWarning('matcher-pattern-missing-key-or-value', pattern);
|
|
334
|
+
}
|
|
335
|
+
return [pattern.key, pattern.value];
|
|
336
|
+
}
|
|
337
|
+
// Assume the pattern is either String or RegExp.
|
|
338
|
+
return [pattern, true];
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
if (isPlainObject(patterns)) {
|
|
342
|
+
return Object.entries(patterns);
|
|
343
|
+
}
|
|
344
|
+
// Other cases (true, string or regexp).
|
|
345
|
+
return [[patterns, true]];
|
|
389
346
|
}
|
|
390
|
-
|
|
391
347
|
// @param {String|RegExp} patternKey A pattern representing a key we want to match.
|
|
392
348
|
// @param {String} itemKey An actual item key (e.g. `'src'`, `'background-color'`, `'ck-widget'`) we're testing against pattern.
|
|
393
349
|
// @returns {Boolean}
|
|
394
|
-
function isKeyMatched(
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
350
|
+
function isKeyMatched(patternKey, itemKey) {
|
|
351
|
+
return patternKey === true ||
|
|
352
|
+
patternKey === itemKey ||
|
|
353
|
+
patternKey instanceof RegExp && itemKey.match(patternKey);
|
|
398
354
|
}
|
|
399
|
-
|
|
400
355
|
// @param {String|RegExp} patternValue A pattern representing a value we want to match.
|
|
401
356
|
// @param {String} itemKey An item key, e.g. `background`, `href`, 'rel', etc.
|
|
402
357
|
// @param {Function} valueGetter A function used to provide a value for a given `itemKey`.
|
|
403
358
|
// @returns {Boolean}
|
|
404
|
-
function isValueMatched(
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
return patternValue === itemValue ||
|
|
415
|
-
patternValue instanceof RegExp && !!String( itemValue ).match( patternValue );
|
|
359
|
+
function isValueMatched(patternValue, itemKey, valueGetter) {
|
|
360
|
+
if (patternValue === true) {
|
|
361
|
+
return true;
|
|
362
|
+
}
|
|
363
|
+
const itemValue = valueGetter(itemKey);
|
|
364
|
+
// For now, the reducers are not returning the full tree of properties.
|
|
365
|
+
// Casting to string preserves the old behavior until the root cause is fixed.
|
|
366
|
+
// More can be found in https://github.com/ckeditor/ckeditor5/issues/10399.
|
|
367
|
+
return patternValue === itemValue ||
|
|
368
|
+
patternValue instanceof RegExp && !!String(itemValue).match(patternValue);
|
|
416
369
|
}
|
|
417
|
-
|
|
418
370
|
// Checks if attributes of provided element can be matched against provided patterns.
|
|
419
371
|
//
|
|
420
372
|
// @param {Object} patterns Object with information about attributes to match. Each key of the object will be
|
|
421
373
|
// used as attribute name. Value of each key can be a string or regular expression to match against attribute value.
|
|
422
374
|
// @param {module:engine/view/element~Element} element Element which attributes will be tested.
|
|
423
375
|
// @returns {Array|null} Returns array with matched attribute names or `null` if no attributes were matched.
|
|
424
|
-
function matchAttributes(
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
return matchPatterns( patterns, attributeKeys, key => element.getAttribute( key ) );
|
|
376
|
+
function matchAttributes(patterns, element) {
|
|
377
|
+
const attributeKeys = new Set(element.getAttributeKeys());
|
|
378
|
+
// `style` and `class` attribute keys are deprecated. Only allow them in object pattern
|
|
379
|
+
// for backward compatibility.
|
|
380
|
+
if (isPlainObject(patterns)) {
|
|
381
|
+
if (patterns.style !== undefined) {
|
|
382
|
+
// Documented at the end of matcher.js.
|
|
383
|
+
logWarning('matcher-pattern-deprecated-attributes-style-key', patterns);
|
|
384
|
+
}
|
|
385
|
+
if (patterns.class !== undefined) {
|
|
386
|
+
// Documented at the end of matcher.js.
|
|
387
|
+
logWarning('matcher-pattern-deprecated-attributes-class-key', patterns);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
else {
|
|
391
|
+
attributeKeys.delete('style');
|
|
392
|
+
attributeKeys.delete('class');
|
|
393
|
+
}
|
|
394
|
+
return matchPatterns(patterns, attributeKeys, key => element.getAttribute(key));
|
|
444
395
|
}
|
|
445
|
-
|
|
446
396
|
// Checks if classes of provided element can be matched against provided patterns.
|
|
447
397
|
//
|
|
448
398
|
// @param {Array.<String|RegExp>} patterns Array of strings or regular expressions to match against element's classes.
|
|
449
399
|
// @param {module:engine/view/element~Element} element Element which classes will be tested.
|
|
450
400
|
// @returns {Array|null} Returns array with matched class names or `null` if no classes were matched.
|
|
451
|
-
function matchClasses(
|
|
452
|
-
|
|
453
|
-
|
|
401
|
+
function matchClasses(patterns, element) {
|
|
402
|
+
// We don't need `getter` here because patterns for classes are always normalized to `[ className, true ]`.
|
|
403
|
+
return matchPatterns(patterns, element.getClassNames(), /* istanbul ignore next */ () => { });
|
|
454
404
|
}
|
|
455
|
-
|
|
456
405
|
// Checks if styles of provided element can be matched against provided patterns.
|
|
457
406
|
//
|
|
458
407
|
// @param {Object} patterns Object with information about styles to match. Each key of the object will be
|
|
459
408
|
// used as style name. Value of each key can be a string or regular expression to match against style value.
|
|
460
409
|
// @param {module:engine/view/element~Element} element Element which styles will be tested.
|
|
461
410
|
// @returns {Array|null} Returns array with matched style names or `null` if no styles were matched.
|
|
462
|
-
function matchStyles(
|
|
463
|
-
|
|
411
|
+
function matchStyles(patterns, element) {
|
|
412
|
+
return matchPatterns(patterns, element.getStyleNames(true), key => element.getStyle(key));
|
|
464
413
|
}
|
|
465
|
-
|
|
466
|
-
/**
|
|
467
|
-
* An entity that is a valid pattern recognized by a matcher. `MatcherPattern` is used by {@link ~Matcher} to recognize
|
|
468
|
-
* if a view element fits in a group of view elements described by the pattern.
|
|
469
|
-
*
|
|
470
|
-
* `MatcherPattern` can be given as a `String`, a `RegExp`, an `Object` or a `Function`.
|
|
471
|
-
*
|
|
472
|
-
* If `MatcherPattern` is given as a `String` or `RegExp`, it will match any view element that has a matching name:
|
|
473
|
-
*
|
|
474
|
-
* // Match any element with name equal to 'div'.
|
|
475
|
-
* const pattern = 'div';
|
|
476
|
-
*
|
|
477
|
-
* // Match any element which name starts on 'p'.
|
|
478
|
-
* const pattern = /^p/;
|
|
479
|
-
*
|
|
480
|
-
* If `MatcherPattern` is given as an `Object`, all the object's properties will be matched with view element properties.
|
|
481
|
-
* If the view element does not meet all of the object's pattern properties, the match will not happen.
|
|
482
|
-
* Available `Object` matching properties:
|
|
483
|
-
*
|
|
484
|
-
* Matching view element:
|
|
485
|
-
*
|
|
486
|
-
* // Match view element's name using String:
|
|
487
|
-
* const pattern = { name: 'p' };
|
|
488
|
-
*
|
|
489
|
-
* // or by providing RegExp:
|
|
490
|
-
* const pattern = { name: /^(ul|ol)$/ };
|
|
491
|
-
*
|
|
492
|
-
* // The name can also be skipped to match any view element with matching attributes:
|
|
493
|
-
* const pattern = {
|
|
494
|
-
* attributes: {
|
|
495
|
-
* 'title': true
|
|
496
|
-
* }
|
|
497
|
-
* };
|
|
498
|
-
*
|
|
499
|
-
* Matching view element attributes:
|
|
500
|
-
*
|
|
501
|
-
* // Match view element with any attribute value.
|
|
502
|
-
* const pattern = {
|
|
503
|
-
* name: 'p',
|
|
504
|
-
* attributes: true
|
|
505
|
-
* };
|
|
506
|
-
*
|
|
507
|
-
* // Match view element which has matching attributes (String).
|
|
508
|
-
* const pattern = {
|
|
509
|
-
* name: 'figure',
|
|
510
|
-
* attributes: 'title' // Match title attribute (can be empty).
|
|
511
|
-
* };
|
|
512
|
-
*
|
|
513
|
-
* // Match view element which has matching attributes (RegExp).
|
|
514
|
-
* const pattern = {
|
|
515
|
-
* name: 'figure',
|
|
516
|
-
* attributes: /^data-.*$/ // Match attributes starting with `data-` e.g. `data-foo` with any value (can be empty).
|
|
517
|
-
* };
|
|
518
|
-
*
|
|
519
|
-
* // Match view element which has matching attributes (Object).
|
|
520
|
-
* const pattern = {
|
|
521
|
-
* name: 'figure',
|
|
522
|
-
* attributes: {
|
|
523
|
-
* title: 'foobar', // Match `title` attribute with 'foobar' value.
|
|
524
|
-
* alt: true, // Match `alt` attribute with any value (can be empty).
|
|
525
|
-
* 'data-type': /^(jpg|png)$/ // Match `data-type` attribute with `jpg` or `png` value.
|
|
526
|
-
* }
|
|
527
|
-
* };
|
|
528
|
-
*
|
|
529
|
-
* // Match view element which has matching attributes (Array).
|
|
530
|
-
* const pattern = {
|
|
531
|
-
* name: 'figure',
|
|
532
|
-
* attributes: [
|
|
533
|
-
* 'title', // Match `title` attribute (can be empty).
|
|
534
|
-
* /^data-*$/ // Match attributes starting with `data-` e.g. `data-foo` with any value (can be empty).
|
|
535
|
-
* ]
|
|
536
|
-
* };
|
|
537
|
-
*
|
|
538
|
-
* // Match view element which has matching attributes (key-value pairs).
|
|
539
|
-
* const pattern = {
|
|
540
|
-
* name: 'input',
|
|
541
|
-
* attributes: [
|
|
542
|
-
* {
|
|
543
|
-
* key: 'type', // Match `type` as an attribute key.
|
|
544
|
-
* value: /^(text|number|date)$/ // Match `text`, `number` or `date` values.
|
|
545
|
-
* },
|
|
546
|
-
* {
|
|
547
|
-
* key: /^data-.*$/, // Match attributes starting with `data-` e.g. `data-foo`.
|
|
548
|
-
* value: true // Match any value (can be empty).
|
|
549
|
-
* }
|
|
550
|
-
* ]
|
|
551
|
-
* };
|
|
552
|
-
*
|
|
553
|
-
* Matching view element styles:
|
|
554
|
-
*
|
|
555
|
-
* // Match view element with any style.
|
|
556
|
-
* const pattern = {
|
|
557
|
-
* name: 'p',
|
|
558
|
-
* styles: true
|
|
559
|
-
* };
|
|
560
|
-
*
|
|
561
|
-
* // Match view element which has matching styles (String).
|
|
562
|
-
* const pattern = {
|
|
563
|
-
* name: 'p',
|
|
564
|
-
* styles: 'color' // Match attributes with `color` style.
|
|
565
|
-
* };
|
|
566
|
-
*
|
|
567
|
-
* // Match view element which has matching styles (RegExp).
|
|
568
|
-
* const pattern = {
|
|
569
|
-
* name: 'p',
|
|
570
|
-
* styles: /^border.*$/ // Match view element with any border style.
|
|
571
|
-
* };
|
|
572
|
-
*
|
|
573
|
-
* // Match view element which has matching styles (Object).
|
|
574
|
-
* const pattern = {
|
|
575
|
-
* name: 'p',
|
|
576
|
-
* styles: {
|
|
577
|
-
* color: /rgb\((\d{1,3}), (\d{1,3}), (\d{1,3})\)/, // Match `color` in RGB format only.
|
|
578
|
-
* 'font-weight': 600, // Match `font-weight` only if it's `600`.
|
|
579
|
-
* 'text-decoration': true // Match any text decoration.
|
|
580
|
-
* }
|
|
581
|
-
* };
|
|
582
|
-
*
|
|
583
|
-
* // Match view element which has matching styles (Array).
|
|
584
|
-
* const pattern = {
|
|
585
|
-
* name: 'p',
|
|
586
|
-
* styles: [
|
|
587
|
-
* 'color', // Match `color` with any value.
|
|
588
|
-
* /^border.*$/ // Match all border properties.
|
|
589
|
-
* ]
|
|
590
|
-
* };
|
|
591
|
-
*
|
|
592
|
-
* // Match view element which has matching styles (key-value pairs).
|
|
593
|
-
* const pattern = {
|
|
594
|
-
* name: 'p',
|
|
595
|
-
* styles: [
|
|
596
|
-
* {
|
|
597
|
-
* key: 'color', // Match `color` as an property key.
|
|
598
|
-
* value: /rgb\((\d{1,3}), (\d{1,3}), (\d{1,3})\)/ // Match RGB format only.
|
|
599
|
-
* },
|
|
600
|
-
* {
|
|
601
|
-
* key: /^border.*$/, // Match any border style.
|
|
602
|
-
* value: true // Match any value.
|
|
603
|
-
* }
|
|
604
|
-
* ]
|
|
605
|
-
* };
|
|
606
|
-
*
|
|
607
|
-
* Matching view element classes:
|
|
608
|
-
*
|
|
609
|
-
* // Match view element with any class.
|
|
610
|
-
* const pattern = {
|
|
611
|
-
* name: 'p',
|
|
612
|
-
* classes: true
|
|
613
|
-
* };
|
|
614
|
-
*
|
|
615
|
-
* // Match view element which has matching class (String).
|
|
616
|
-
* const pattern = {
|
|
617
|
-
* name: 'p',
|
|
618
|
-
* classes: 'highlighted' // Match `highlighted` class.
|
|
619
|
-
* };
|
|
620
|
-
*
|
|
621
|
-
* // Match view element which has matching classes (RegExp).
|
|
622
|
-
* const pattern = {
|
|
623
|
-
* name: 'figure',
|
|
624
|
-
* classes: /^image-side-(left|right)$/ // Match `image-side-left` or `image-side-right` class.
|
|
625
|
-
* };
|
|
626
|
-
*
|
|
627
|
-
* // Match view element which has matching classes (Object).
|
|
628
|
-
* const pattern = {
|
|
629
|
-
* name: 'p',
|
|
630
|
-
* classes: {
|
|
631
|
-
* highlighted: true, // Match `highlighted` class.
|
|
632
|
-
* marker: true // Match `marker` class.
|
|
633
|
-
* }
|
|
634
|
-
* };
|
|
635
|
-
*
|
|
636
|
-
* // Match view element which has matching classes (Array).
|
|
637
|
-
* const pattern = {
|
|
638
|
-
* name: 'figure',
|
|
639
|
-
* classes: [
|
|
640
|
-
* 'image', // Match `image` class.
|
|
641
|
-
* /^image-side-(left|right)$/ // Match `image-side-left` or `image-side-right` class.
|
|
642
|
-
* ]
|
|
643
|
-
* };
|
|
644
|
-
*
|
|
645
|
-
* // Match view element which has matching classes (key-value pairs).
|
|
646
|
-
* const pattern = {
|
|
647
|
-
* name: 'figure',
|
|
648
|
-
* classes: [
|
|
649
|
-
* {
|
|
650
|
-
* key: 'image', // Match `image` class.
|
|
651
|
-
* value: true
|
|
652
|
-
* },
|
|
653
|
-
* {
|
|
654
|
-
* key: /^image-side-(left|right)$/, // Match `image-side-left` or `image-side-right` class.
|
|
655
|
-
* value: true
|
|
656
|
-
* }
|
|
657
|
-
* ]
|
|
658
|
-
* };
|
|
659
|
-
*
|
|
660
|
-
* Pattern can combine multiple properties allowing for more complex view element matching:
|
|
661
|
-
*
|
|
662
|
-
* const pattern = {
|
|
663
|
-
* name: 'span',
|
|
664
|
-
* attributes: [ 'title' ],
|
|
665
|
-
* styles: {
|
|
666
|
-
* 'font-weight': 'bold'
|
|
667
|
-
* },
|
|
668
|
-
* classes: 'highlighted'
|
|
669
|
-
* };
|
|
670
|
-
*
|
|
671
|
-
* If `MatcherPattern` is given as a `Function`, the function takes a view element as a first and only parameter and
|
|
672
|
-
* the function should decide whether that element matches. If so, it should return what part of the view element has been matched.
|
|
673
|
-
* Otherwise, the function should return `null`. The returned result will be included in `match` property of the object
|
|
674
|
-
* returned by {@link ~Matcher#match} call.
|
|
675
|
-
*
|
|
676
|
-
* // Match an empty <div> element.
|
|
677
|
-
* const pattern = element => {
|
|
678
|
-
* if ( element.name == 'div' && element.childCount > 0 ) {
|
|
679
|
-
* // Return which part of the element was matched.
|
|
680
|
-
* return { name: true };
|
|
681
|
-
* }
|
|
682
|
-
*
|
|
683
|
-
* return null;
|
|
684
|
-
* };
|
|
685
|
-
*
|
|
686
|
-
* // Match a <p> element with big font ("heading-like" element).
|
|
687
|
-
* const pattern = element => {
|
|
688
|
-
* if ( element.name == 'p' ) {
|
|
689
|
-
* const fontSize = element.getStyle( 'font-size' );
|
|
690
|
-
* const size = fontSize.match( /(\d+)/px );
|
|
691
|
-
*
|
|
692
|
-
* if ( size && Number( size[ 1 ] ) > 26 ) {
|
|
693
|
-
* return { name: true, attribute: [ 'font-size' ] };
|
|
694
|
-
* }
|
|
695
|
-
* }
|
|
696
|
-
*
|
|
697
|
-
* return null;
|
|
698
|
-
* };
|
|
699
|
-
*
|
|
700
|
-
* `MatcherPattern` is defined in a way that it is a superset of {@link module:engine/view/elementdefinition~ElementDefinition},
|
|
701
|
-
* that is, every `ElementDefinition` also can be used as a `MatcherPattern`.
|
|
702
|
-
*
|
|
703
|
-
* @typedef {String|RegExp|Object|Function} module:engine/view/matcher~MatcherPattern
|
|
704
|
-
*
|
|
705
|
-
* @property {String|RegExp} [name] View element name to match.
|
|
706
|
-
* @property {Boolean|String|RegExp|Object|Array.<String|RegExp|Object>} [classes] View element's classes to match.
|
|
707
|
-
* @property {Boolean|String|RegExp|Object|Array.<String|RegExp|Object>} [styles] View element's styles to match.
|
|
708
|
-
* @property {Boolean|String|RegExp|Object|Array.<String|RegExp|Object>} [attributes] View element's attributes to match.
|
|
709
|
-
*/
|
|
710
|
-
|
|
711
414
|
/**
|
|
712
415
|
* The key-value matcher pattern is missing key or value. Both must be present.
|
|
713
416
|
* Refer the documentation: {@link module:engine/view/matcher~MatcherPattern}.
|
|
@@ -715,7 +418,6 @@ function matchStyles( patterns, element ) {
|
|
|
715
418
|
* @param {Object} pattern Pattern with missing properties.
|
|
716
419
|
* @error matcher-pattern-missing-key-or-value
|
|
717
420
|
*/
|
|
718
|
-
|
|
719
421
|
/**
|
|
720
422
|
* The key-value matcher pattern for `attributes` option is using deprecated `style` key.
|
|
721
423
|
*
|
|
@@ -745,7 +447,6 @@ function matchStyles( patterns, element ) {
|
|
|
745
447
|
* @param {Object} pattern Pattern with missing properties.
|
|
746
448
|
* @error matcher-pattern-deprecated-attributes-style-key
|
|
747
449
|
*/
|
|
748
|
-
|
|
749
450
|
/**
|
|
750
451
|
* The key-value matcher pattern for `attributes` option is using deprecated `class` key.
|
|
751
452
|
*
|