@ckeditor/ckeditor5-style 48.2.0-alpha.7 → 48.3.0-alpha.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/dist/augmentation.d.ts +22 -22
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +21 -21
- package/dist/index.js +1225 -1308
- package/dist/index.js.map +1 -1
- package/dist/integrations/link.d.ts +38 -38
- package/dist/integrations/list.d.ts +43 -43
- package/dist/integrations/table.d.ts +49 -49
- package/dist/style.d.ts +25 -25
- package/dist/stylecommand.d.ts +78 -78
- package/dist/styleconfig.d.ts +79 -79
- package/dist/styleediting.d.ts +33 -33
- package/dist/styleui.d.ts +29 -29
- package/dist/styleutils.d.ts +131 -131
- package/dist/ui/stylegridbuttonview.d.ts +31 -31
- package/dist/ui/stylegridview.d.ts +66 -66
- package/dist/ui/stylegroupview.d.ts +32 -32
- package/dist/ui/stylepanelview.d.ts +83 -83
- package/package.json +9 -9
package/dist/index.js
CHANGED
|
@@ -2,1351 +2,1268 @@
|
|
|
2
2
|
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
3
|
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
4
4
|
*/
|
|
5
|
-
import {
|
|
6
|
-
import { ButtonView,
|
|
7
|
-
import { FocusTracker, KeystrokeHandler, first, logWarning } from
|
|
8
|
-
import { isObject } from
|
|
9
|
-
import { GeneralHtmlSupport } from
|
|
10
|
-
import { findAttributeRange, findAttributeRangeBound } from
|
|
5
|
+
import { Command, Plugin } from "@ckeditor/ckeditor5-core";
|
|
6
|
+
import { ButtonView, FocusCycler, LabelView, View, ViewCollection, addKeyboardHandlingForGrid, createDropdown } from "@ckeditor/ckeditor5-ui";
|
|
7
|
+
import { FocusTracker, KeystrokeHandler, first, logWarning } from "@ckeditor/ckeditor5-utils";
|
|
8
|
+
import { isObject } from "es-toolkit/compat";
|
|
9
|
+
import { GeneralHtmlSupport } from "@ckeditor/ckeditor5-html-support";
|
|
10
|
+
import { findAttributeRange, findAttributeRangeBound } from "@ckeditor/ckeditor5-typing";
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
13
|
+
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
|
|
14
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* A class representing an individual button (style) in the grid. Renders a rich preview of the style.
|
|
18
|
+
*
|
|
19
|
+
* @internal
|
|
20
|
+
*/
|
|
21
|
+
var StyleGridButtonView = class extends ButtonView {
|
|
22
|
+
/**
|
|
23
|
+
* Definition of the style the button will apply when executed.
|
|
24
|
+
*/
|
|
25
|
+
styleDefinition;
|
|
26
|
+
/**
|
|
27
|
+
* The view rendering the preview of the style.
|
|
28
|
+
*/
|
|
29
|
+
previewView;
|
|
30
|
+
/**
|
|
31
|
+
* Creates an instance of the {@link module:style/ui/stylegridbuttonview~StyleGridButtonView} class.
|
|
32
|
+
*
|
|
33
|
+
* @param locale The localization services instance.
|
|
34
|
+
* @param styleDefinition Definition of the style.
|
|
35
|
+
*/
|
|
36
|
+
constructor(locale, styleDefinition) {
|
|
37
|
+
super(locale);
|
|
38
|
+
this.styleDefinition = styleDefinition;
|
|
39
|
+
this.previewView = this._createPreview();
|
|
40
|
+
this.set({
|
|
41
|
+
label: styleDefinition.name,
|
|
42
|
+
class: "ck-style-grid__button",
|
|
43
|
+
withText: true
|
|
44
|
+
});
|
|
45
|
+
this.extendTemplate({ attributes: { role: "option" } });
|
|
46
|
+
this.children.add(this.previewView, 0);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Creates the view representing the preview of the style.
|
|
50
|
+
*/
|
|
51
|
+
_createPreview() {
|
|
52
|
+
const previewView = new View(this.locale);
|
|
53
|
+
previewView.setTemplate({
|
|
54
|
+
tag: "div",
|
|
55
|
+
attributes: {
|
|
56
|
+
class: [
|
|
57
|
+
"ck",
|
|
58
|
+
"ck-reset_all-excluded",
|
|
59
|
+
"ck-style-grid__button__preview",
|
|
60
|
+
"ck-content"
|
|
61
|
+
],
|
|
62
|
+
"aria-hidden": "true"
|
|
63
|
+
},
|
|
64
|
+
children: [this.styleDefinition.previewTemplate]
|
|
65
|
+
});
|
|
66
|
+
return previewView;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
67
69
|
|
|
68
70
|
/**
|
|
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
|
-
|
|
71
|
+
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
|
|
72
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
73
|
+
*/
|
|
74
|
+
/**
|
|
75
|
+
* @module style/ui/stylegridview
|
|
76
|
+
*/
|
|
77
|
+
/**
|
|
78
|
+
* A class representing a grid of styles ({@link module:style/ui/stylegridbuttonview~StyleGridButtonView buttons}).
|
|
79
|
+
* Allows users to select a style.
|
|
80
|
+
*
|
|
81
|
+
* @internal
|
|
82
|
+
*/
|
|
83
|
+
var StyleGridView = class extends View {
|
|
84
|
+
/**
|
|
85
|
+
* Tracks information about the DOM focus in the view.
|
|
86
|
+
*/
|
|
87
|
+
focusTracker;
|
|
88
|
+
/**
|
|
89
|
+
* An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}.
|
|
90
|
+
*/
|
|
91
|
+
keystrokes;
|
|
92
|
+
/**
|
|
93
|
+
* A collection of style {@link module:style/ui/stylegridbuttonview~StyleGridButtonView buttons}.
|
|
94
|
+
*/
|
|
95
|
+
children;
|
|
96
|
+
/**
|
|
97
|
+
* Creates an instance of the {@link module:style/ui/stylegridview~StyleGridView} class.
|
|
98
|
+
*
|
|
99
|
+
* @param locale The localization services instance.
|
|
100
|
+
* @param styleDefinitions Definitions of the styles.
|
|
101
|
+
*/
|
|
102
|
+
constructor(locale, styleDefinitions) {
|
|
103
|
+
super(locale);
|
|
104
|
+
this.focusTracker = new FocusTracker();
|
|
105
|
+
this.keystrokes = new KeystrokeHandler();
|
|
106
|
+
this.set("activeStyles", []);
|
|
107
|
+
this.set("enabledStyles", []);
|
|
108
|
+
this.children = this.createCollection();
|
|
109
|
+
this.children.delegate("execute").to(this);
|
|
110
|
+
for (const definition of styleDefinitions) {
|
|
111
|
+
const gridTileView = new StyleGridButtonView(locale, definition);
|
|
112
|
+
this.children.add(gridTileView);
|
|
113
|
+
}
|
|
114
|
+
this.on("change:activeStyles", () => {
|
|
115
|
+
for (const child of this.children) child.isOn = this.activeStyles.includes(child.styleDefinition.name);
|
|
116
|
+
});
|
|
117
|
+
this.on("change:enabledStyles", () => {
|
|
118
|
+
for (const child of this.children) child.isEnabled = this.enabledStyles.includes(child.styleDefinition.name);
|
|
119
|
+
});
|
|
120
|
+
this.setTemplate({
|
|
121
|
+
tag: "div",
|
|
122
|
+
attributes: {
|
|
123
|
+
class: ["ck", "ck-style-grid"],
|
|
124
|
+
role: "listbox"
|
|
125
|
+
},
|
|
126
|
+
children: this.children
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* @inheritDoc
|
|
131
|
+
*/
|
|
132
|
+
render() {
|
|
133
|
+
super.render();
|
|
134
|
+
for (const child of this.children) this.focusTracker.add(child.element);
|
|
135
|
+
addKeyboardHandlingForGrid({
|
|
136
|
+
keystrokeHandler: this.keystrokes,
|
|
137
|
+
focusTracker: this.focusTracker,
|
|
138
|
+
gridItems: this.children,
|
|
139
|
+
numberOfColumns: 3,
|
|
140
|
+
uiLanguageDirection: this.locale && this.locale.uiLanguageDirection
|
|
141
|
+
});
|
|
142
|
+
this.keystrokes.listenTo(this.element);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Focuses the first style button in the grid.
|
|
146
|
+
*/
|
|
147
|
+
focus() {
|
|
148
|
+
this.children.first.focus();
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* @inheritDoc
|
|
152
|
+
*/
|
|
153
|
+
destroy() {
|
|
154
|
+
super.destroy();
|
|
155
|
+
this.focusTracker.destroy();
|
|
156
|
+
this.keystrokes.destroy();
|
|
157
|
+
}
|
|
158
|
+
};
|
|
152
159
|
|
|
153
160
|
/**
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
161
|
+
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
|
|
162
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
163
|
+
*/
|
|
164
|
+
/**
|
|
165
|
+
* @module style/ui/stylegroupview
|
|
166
|
+
*/
|
|
167
|
+
/**
|
|
168
|
+
* A class representing a group of styles (e.g. "block" or "inline").
|
|
169
|
+
*
|
|
170
|
+
* Renders a {@link module:style/ui/stylegridview~StyleGridView style grid} and a label.
|
|
171
|
+
*
|
|
172
|
+
* @internal
|
|
173
|
+
*/
|
|
174
|
+
var StyleGroupView = class extends View {
|
|
175
|
+
/**
|
|
176
|
+
* The styles grid of the group.
|
|
177
|
+
*/
|
|
178
|
+
gridView;
|
|
179
|
+
/**
|
|
180
|
+
* The label of the group.
|
|
181
|
+
*/
|
|
182
|
+
labelView;
|
|
183
|
+
/**
|
|
184
|
+
* Creates an instance of the {@link module:style/ui/stylegroupview~StyleGroupView} class.
|
|
185
|
+
*
|
|
186
|
+
* @param locale The localization services instance.
|
|
187
|
+
* @param label The localized label of the group.
|
|
188
|
+
* @param styleDefinitions Definitions of the styles in the group.
|
|
189
|
+
*/
|
|
190
|
+
constructor(locale, label, styleDefinitions) {
|
|
191
|
+
super(locale);
|
|
192
|
+
this.labelView = new LabelView(locale);
|
|
193
|
+
this.labelView.text = label;
|
|
194
|
+
this.gridView = new StyleGridView(locale, styleDefinitions);
|
|
195
|
+
this.setTemplate({
|
|
196
|
+
tag: "div",
|
|
197
|
+
attributes: {
|
|
198
|
+
class: ["ck", "ck-style-panel__style-group"],
|
|
199
|
+
role: "group",
|
|
200
|
+
"aria-labelledby": this.labelView.id
|
|
201
|
+
},
|
|
202
|
+
children: [this.labelView, this.gridView]
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
};
|
|
194
206
|
|
|
195
207
|
/**
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
208
|
+
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
|
|
209
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
210
|
+
*/
|
|
211
|
+
/**
|
|
212
|
+
* @module style/ui/stylepanelview
|
|
213
|
+
*/
|
|
214
|
+
/**
|
|
215
|
+
* A class representing a panel with available content styles. It renders styles in button grids, grouped
|
|
216
|
+
* in categories.
|
|
217
|
+
*
|
|
218
|
+
* @internal
|
|
219
|
+
*/
|
|
220
|
+
var StylePanelView = class extends View {
|
|
221
|
+
/**
|
|
222
|
+
* Tracks information about DOM focus in the panel.
|
|
223
|
+
*/
|
|
224
|
+
focusTracker;
|
|
225
|
+
/**
|
|
226
|
+
* An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}.
|
|
227
|
+
*/
|
|
228
|
+
keystrokes;
|
|
229
|
+
/**
|
|
230
|
+
* A collection of panel children.
|
|
231
|
+
*/
|
|
232
|
+
children;
|
|
233
|
+
/**
|
|
234
|
+
* A view representing block styles group.
|
|
235
|
+
*/
|
|
236
|
+
blockStylesGroupView;
|
|
237
|
+
/**
|
|
238
|
+
* A view representing inline styles group
|
|
239
|
+
*/
|
|
240
|
+
inlineStylesGroupView;
|
|
241
|
+
/**
|
|
242
|
+
* A collection of views that can be focused in the panel.
|
|
243
|
+
*/
|
|
244
|
+
_focusables;
|
|
245
|
+
/**
|
|
246
|
+
* Helps cycling over {@link #_focusables} in the panel.
|
|
247
|
+
*/
|
|
248
|
+
_focusCycler;
|
|
249
|
+
/**
|
|
250
|
+
* Creates an instance of the {@link module:style/ui/stylegroupview~StyleGroupView} class.
|
|
251
|
+
*
|
|
252
|
+
* @param locale The localization services instance.
|
|
253
|
+
* @param styleDefinitions Normalized definitions of the styles.
|
|
254
|
+
*/
|
|
255
|
+
constructor(locale, styleDefinitions) {
|
|
256
|
+
super(locale);
|
|
257
|
+
const t = locale.t;
|
|
258
|
+
this.focusTracker = new FocusTracker();
|
|
259
|
+
this.keystrokes = new KeystrokeHandler();
|
|
260
|
+
this.children = this.createCollection();
|
|
261
|
+
this.blockStylesGroupView = new StyleGroupView(locale, t("Block styles"), styleDefinitions.block);
|
|
262
|
+
this.inlineStylesGroupView = new StyleGroupView(locale, t("Text styles"), styleDefinitions.inline);
|
|
263
|
+
this.set("activeStyles", []);
|
|
264
|
+
this.set("enabledStyles", []);
|
|
265
|
+
this._focusables = new ViewCollection();
|
|
266
|
+
this._focusCycler = new FocusCycler({
|
|
267
|
+
focusables: this._focusables,
|
|
268
|
+
focusTracker: this.focusTracker,
|
|
269
|
+
keystrokeHandler: this.keystrokes,
|
|
270
|
+
actions: {
|
|
271
|
+
focusPrevious: ["shift + tab"],
|
|
272
|
+
focusNext: ["tab"]
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
if (styleDefinitions.block.length) this.children.add(this.blockStylesGroupView);
|
|
276
|
+
if (styleDefinitions.inline.length) this.children.add(this.inlineStylesGroupView);
|
|
277
|
+
this.blockStylesGroupView.gridView.delegate("execute").to(this);
|
|
278
|
+
this.inlineStylesGroupView.gridView.delegate("execute").to(this);
|
|
279
|
+
this.blockStylesGroupView.gridView.bind("activeStyles", "enabledStyles").to(this, "activeStyles", "enabledStyles");
|
|
280
|
+
this.inlineStylesGroupView.gridView.bind("activeStyles", "enabledStyles").to(this, "activeStyles", "enabledStyles");
|
|
281
|
+
this.setTemplate({
|
|
282
|
+
tag: "div",
|
|
283
|
+
attributes: { class: ["ck", "ck-style-panel"] },
|
|
284
|
+
children: this.children
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* @inheritDoc
|
|
289
|
+
*/
|
|
290
|
+
render() {
|
|
291
|
+
super.render();
|
|
292
|
+
this._focusables.add(this.blockStylesGroupView.gridView);
|
|
293
|
+
this._focusables.add(this.inlineStylesGroupView.gridView);
|
|
294
|
+
this.focusTracker.add(this.blockStylesGroupView.gridView.element);
|
|
295
|
+
this.focusTracker.add(this.inlineStylesGroupView.gridView.element);
|
|
296
|
+
this.keystrokes.listenTo(this.element);
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Focuses the first focusable element in the panel.
|
|
300
|
+
*/
|
|
301
|
+
focus() {
|
|
302
|
+
this._focusCycler.focusFirst();
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Focuses the last focusable element in the panel.
|
|
306
|
+
*/
|
|
307
|
+
focusLast() {
|
|
308
|
+
this._focusCycler.focusLast();
|
|
309
|
+
}
|
|
310
|
+
};
|
|
297
311
|
|
|
298
|
-
|
|
312
|
+
/**
|
|
313
|
+
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
|
|
314
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
315
|
+
*/
|
|
316
|
+
/**
|
|
317
|
+
* @module style/styleutils
|
|
318
|
+
*/
|
|
299
319
|
const NON_PREVIEWABLE_ELEMENT_NAMES = [
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
320
|
+
"caption",
|
|
321
|
+
"colgroup",
|
|
322
|
+
"dd",
|
|
323
|
+
"dt",
|
|
324
|
+
"figcaption",
|
|
325
|
+
"legend",
|
|
326
|
+
"li",
|
|
327
|
+
"optgroup",
|
|
328
|
+
"option",
|
|
329
|
+
"rp",
|
|
330
|
+
"rt",
|
|
331
|
+
"summary",
|
|
332
|
+
"tbody",
|
|
333
|
+
"td",
|
|
334
|
+
"tfoot",
|
|
335
|
+
"th",
|
|
336
|
+
"thead",
|
|
337
|
+
"tr"
|
|
318
338
|
];
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
*
|
|
518
|
-
* @param selection The document selection.
|
|
519
|
-
* @param attributeName Name of the GHS attribute.
|
|
520
|
-
* @returns The attribute value.
|
|
521
|
-
*/ _getValueFromFirstAllowedNode(selection, attributeName) {
|
|
522
|
-
const model = this.editor.model;
|
|
523
|
-
const schema = model.schema;
|
|
524
|
-
if (selection.isCollapsed) {
|
|
525
|
-
return selection.getAttribute(attributeName);
|
|
526
|
-
}
|
|
527
|
-
for (const range of selection.getRanges()){
|
|
528
|
-
for (const item of range.getItems()){
|
|
529
|
-
if (schema.checkAttribute(item, attributeName)) {
|
|
530
|
-
return item.getAttribute(attributeName);
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
return null;
|
|
535
|
-
}
|
|
536
|
-
}
|
|
339
|
+
var StyleUtils = class extends Plugin {
|
|
340
|
+
_htmlSupport;
|
|
341
|
+
/**
|
|
342
|
+
* @inheritDoc
|
|
343
|
+
*/
|
|
344
|
+
static get pluginName() {
|
|
345
|
+
return "StyleUtils";
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* @inheritDoc
|
|
349
|
+
*/
|
|
350
|
+
static get isOfficialPlugin() {
|
|
351
|
+
return true;
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* @inheritDoc
|
|
355
|
+
*/
|
|
356
|
+
constructor(editor) {
|
|
357
|
+
super(editor);
|
|
358
|
+
this.decorate("isStyleEnabledForBlock");
|
|
359
|
+
this.decorate("isStyleActiveForBlock");
|
|
360
|
+
this.decorate("getAffectedBlocks");
|
|
361
|
+
this.decorate("isStyleEnabledForInlineSelection");
|
|
362
|
+
this.decorate("isStyleActiveForInlineSelection");
|
|
363
|
+
this.decorate("getAffectedInlineSelectable");
|
|
364
|
+
this.decorate("getStylePreview");
|
|
365
|
+
this.decorate("configureGHSDataFilter");
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* @inheritDoc
|
|
369
|
+
*/
|
|
370
|
+
init() {
|
|
371
|
+
this._htmlSupport = this.editor.plugins.get("GeneralHtmlSupport");
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Normalizes {@link module:style/styleconfig~StyleConfig#definitions} in the configuration of the styles feature.
|
|
375
|
+
* The structure of normalized styles looks as follows:
|
|
376
|
+
*
|
|
377
|
+
* ```ts
|
|
378
|
+
* {
|
|
379
|
+
* block: [
|
|
380
|
+
* <module:style/style~StyleDefinition>,
|
|
381
|
+
* <module:style/style~StyleDefinition>,
|
|
382
|
+
* ...
|
|
383
|
+
* ],
|
|
384
|
+
* inline: [
|
|
385
|
+
* <module:style/style~StyleDefinition>,
|
|
386
|
+
* <module:style/style~StyleDefinition>,
|
|
387
|
+
* ...
|
|
388
|
+
* ]
|
|
389
|
+
* }
|
|
390
|
+
* ```
|
|
391
|
+
*
|
|
392
|
+
* @returns An object with normalized style definitions grouped into `block` and `inline` categories (arrays).
|
|
393
|
+
*/
|
|
394
|
+
normalizeConfig(dataSchema, styleDefinitions = []) {
|
|
395
|
+
const normalizedDefinitions = {
|
|
396
|
+
block: [],
|
|
397
|
+
inline: []
|
|
398
|
+
};
|
|
399
|
+
for (const definition of styleDefinitions) {
|
|
400
|
+
const modelElements = [];
|
|
401
|
+
const ghsAttributes = [];
|
|
402
|
+
for (const ghsDefinition of dataSchema.getDefinitionsForView(definition.element)) {
|
|
403
|
+
const appliesToBlock = "appliesToBlock" in ghsDefinition ? ghsDefinition.appliesToBlock : false;
|
|
404
|
+
if (ghsDefinition.isBlock || appliesToBlock) {
|
|
405
|
+
if (typeof appliesToBlock == "string") modelElements.push(appliesToBlock);
|
|
406
|
+
else if (ghsDefinition.isBlock) {
|
|
407
|
+
const ghsBlockDefinition = ghsDefinition;
|
|
408
|
+
modelElements.push(ghsDefinition.model);
|
|
409
|
+
if (ghsBlockDefinition.paragraphLikeModel) modelElements.push(ghsBlockDefinition.paragraphLikeModel);
|
|
410
|
+
}
|
|
411
|
+
} else ghsAttributes.push(ghsDefinition.model);
|
|
412
|
+
}
|
|
413
|
+
const previewTemplate = this.getStylePreview(definition, [{ text: "AaBbCcDdEeFfGgHhIiJj" }]);
|
|
414
|
+
if (modelElements.length) normalizedDefinitions.block.push({
|
|
415
|
+
...definition,
|
|
416
|
+
previewTemplate,
|
|
417
|
+
modelElements,
|
|
418
|
+
isBlock: true
|
|
419
|
+
});
|
|
420
|
+
else normalizedDefinitions.inline.push({
|
|
421
|
+
...definition,
|
|
422
|
+
previewTemplate,
|
|
423
|
+
ghsAttributes
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
return normalizedDefinitions;
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* Verifies if the given style is applicable to the provided block element.
|
|
430
|
+
*
|
|
431
|
+
* @internal
|
|
432
|
+
*/
|
|
433
|
+
isStyleEnabledForBlock(definition, block) {
|
|
434
|
+
const model = this.editor.model;
|
|
435
|
+
const attributeName = this._htmlSupport.getGhsAttributeNameForElement(definition.element);
|
|
436
|
+
if (!model.schema.checkAttribute(block, attributeName)) return false;
|
|
437
|
+
return definition.modelElements.includes(block.name);
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* Returns true if the given style is applied to the specified block element.
|
|
441
|
+
*
|
|
442
|
+
* @internal
|
|
443
|
+
*/
|
|
444
|
+
isStyleActiveForBlock(definition, block) {
|
|
445
|
+
const attributeName = this._htmlSupport.getGhsAttributeNameForElement(definition.element);
|
|
446
|
+
const ghsAttributeValue = block.getAttribute(attributeName);
|
|
447
|
+
return this.hasAllClasses(ghsAttributeValue, definition.classes);
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* Returns an array of block elements that style should be applied to.
|
|
451
|
+
*
|
|
452
|
+
* @internal
|
|
453
|
+
*/
|
|
454
|
+
getAffectedBlocks(definition, block) {
|
|
455
|
+
if (definition.modelElements.includes(block.name)) return [block];
|
|
456
|
+
return null;
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* Verifies if the given style is applicable to the provided document selection.
|
|
460
|
+
*
|
|
461
|
+
* @internal
|
|
462
|
+
*/
|
|
463
|
+
isStyleEnabledForInlineSelection(definition, selection) {
|
|
464
|
+
const model = this.editor.model;
|
|
465
|
+
for (const ghsAttributeName of definition.ghsAttributes) if (model.schema.checkAttributeInSelection(selection, ghsAttributeName)) return true;
|
|
466
|
+
return false;
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* Returns true if the given style is applied to the specified document selection.
|
|
470
|
+
*
|
|
471
|
+
* @internal
|
|
472
|
+
*/
|
|
473
|
+
isStyleActiveForInlineSelection(definition, selection) {
|
|
474
|
+
for (const ghsAttributeName of definition.ghsAttributes) {
|
|
475
|
+
const ghsAttributeValue = this._getValueFromFirstAllowedNode(selection, ghsAttributeName);
|
|
476
|
+
if (this.hasAllClasses(ghsAttributeValue, definition.classes)) return true;
|
|
477
|
+
}
|
|
478
|
+
return false;
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Returns a selectable that given style should be applied to.
|
|
482
|
+
*
|
|
483
|
+
* @internal
|
|
484
|
+
*/
|
|
485
|
+
getAffectedInlineSelectable(definition, selection) {
|
|
486
|
+
return selection;
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* Returns the `TemplateDefinition` used by styles dropdown to render style preview.
|
|
490
|
+
*
|
|
491
|
+
* @internal
|
|
492
|
+
*/
|
|
493
|
+
getStylePreview(definition, children) {
|
|
494
|
+
const { element, classes } = definition;
|
|
495
|
+
return {
|
|
496
|
+
tag: isPreviewable(element) ? element : "div",
|
|
497
|
+
attributes: { class: classes },
|
|
498
|
+
children
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* Verifies if all classes are present in the given GHS attribute.
|
|
503
|
+
*
|
|
504
|
+
* @internal
|
|
505
|
+
*/
|
|
506
|
+
hasAllClasses(ghsAttributeValue, classes) {
|
|
507
|
+
return isObject(ghsAttributeValue) && hasClassesProperty(ghsAttributeValue) && classes.every((className) => ghsAttributeValue.classes.includes(className));
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* This is where the styles feature configures the GHS feature. This method translates normalized
|
|
511
|
+
* {@link module:style/styleconfig~StyleDefinition style definitions} to
|
|
512
|
+
* {@link module:engine/view/matcher~MatcherObjectPattern matcher patterns} and feeds them to the GHS
|
|
513
|
+
* {@link module:html-support/datafilter~DataFilter} plugin.
|
|
514
|
+
*
|
|
515
|
+
* @internal
|
|
516
|
+
*/
|
|
517
|
+
configureGHSDataFilter({ block, inline }) {
|
|
518
|
+
const ghsDataFilter = this.editor.plugins.get("DataFilter");
|
|
519
|
+
ghsDataFilter.loadAllowedConfig(block.map(normalizedStyleDefinitionToMatcherPattern));
|
|
520
|
+
ghsDataFilter.loadAllowedConfig(inline.map(normalizedStyleDefinitionToMatcherPattern));
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Checks the attribute value of the first node in the selection that allows the attribute.
|
|
524
|
+
* For the collapsed selection, returns the selection attribute.
|
|
525
|
+
*
|
|
526
|
+
* @param selection The document selection.
|
|
527
|
+
* @param attributeName Name of the GHS attribute.
|
|
528
|
+
* @returns The attribute value.
|
|
529
|
+
*/
|
|
530
|
+
_getValueFromFirstAllowedNode(selection, attributeName) {
|
|
531
|
+
const schema = this.editor.model.schema;
|
|
532
|
+
if (selection.isCollapsed) return selection.getAttribute(attributeName);
|
|
533
|
+
for (const range of selection.getRanges()) for (const item of range.getItems()) if (schema.checkAttribute(item, attributeName)) return item.getAttribute(attributeName);
|
|
534
|
+
return null;
|
|
535
|
+
}
|
|
536
|
+
};
|
|
537
537
|
/**
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
538
|
+
* Checks if given object has `classes` property which is an array.
|
|
539
|
+
*
|
|
540
|
+
* @param obj Object to check.
|
|
541
|
+
*/
|
|
542
|
+
function hasClassesProperty(obj) {
|
|
543
|
+
return Boolean(obj.classes) && Array.isArray(obj.classes);
|
|
543
544
|
}
|
|
544
545
|
/**
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
546
|
+
* Decides whether an element should be created in the preview or a substitute `<div>` should
|
|
547
|
+
* be used instead. This avoids previewing a standalone `<td>`, `<li>`, etc. without a parent.
|
|
548
|
+
*
|
|
549
|
+
* @param elementName Name of the element
|
|
550
|
+
* @returns Boolean indicating whether the element can be rendered.
|
|
551
|
+
*/
|
|
552
|
+
function isPreviewable(elementName) {
|
|
553
|
+
return !NON_PREVIEWABLE_ELEMENT_NAMES.includes(elementName);
|
|
552
554
|
}
|
|
553
555
|
/**
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
556
|
+
* Translates a normalized style definition to a view matcher pattern.
|
|
557
|
+
*/
|
|
558
|
+
function normalizedStyleDefinitionToMatcherPattern({ element, classes }) {
|
|
559
|
+
return {
|
|
560
|
+
name: element,
|
|
561
|
+
classes
|
|
562
|
+
};
|
|
560
563
|
}
|
|
561
564
|
|
|
562
565
|
/**
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
// Execute the command when a style is selected in the styles panel.
|
|
635
|
-
// Also focus the editable after executing the command.
|
|
636
|
-
// It overrides a default behaviour where the focus is moved to the dropdown button.
|
|
637
|
-
// See https://github.com/ckeditor/ckeditor5/issues/12125.
|
|
638
|
-
dropdown.on('execute', (evt)=>{
|
|
639
|
-
editor.execute('style', {
|
|
640
|
-
styleName: evt.source.styleDefinition.name
|
|
641
|
-
});
|
|
642
|
-
editor.editing.view.focus();
|
|
643
|
-
});
|
|
644
|
-
return dropdown;
|
|
645
|
-
});
|
|
646
|
-
}
|
|
647
|
-
}
|
|
566
|
+
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
|
|
567
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
568
|
+
*/
|
|
569
|
+
/**
|
|
570
|
+
* @module style/styleui
|
|
571
|
+
*/
|
|
572
|
+
/**
|
|
573
|
+
* The UI plugin of the style feature .
|
|
574
|
+
*
|
|
575
|
+
* It registers the `'style'` UI dropdown in the editor's {@link module:ui/componentfactory~ComponentFactory component factory}
|
|
576
|
+
* that displays a grid of styles and allows changing styles of the content.
|
|
577
|
+
*/
|
|
578
|
+
var StyleUI = class extends Plugin {
|
|
579
|
+
/**
|
|
580
|
+
* @inheritDoc
|
|
581
|
+
*/
|
|
582
|
+
static get pluginName() {
|
|
583
|
+
return "StyleUI";
|
|
584
|
+
}
|
|
585
|
+
/**
|
|
586
|
+
* @inheritDoc
|
|
587
|
+
*/
|
|
588
|
+
static get isOfficialPlugin() {
|
|
589
|
+
return true;
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
592
|
+
* @inheritDoc
|
|
593
|
+
*/
|
|
594
|
+
static get requires() {
|
|
595
|
+
return [StyleUtils];
|
|
596
|
+
}
|
|
597
|
+
/**
|
|
598
|
+
* @inheritDoc
|
|
599
|
+
*/
|
|
600
|
+
init() {
|
|
601
|
+
const editor = this.editor;
|
|
602
|
+
const dataSchema = editor.plugins.get("DataSchema");
|
|
603
|
+
const styleUtils = editor.plugins.get("StyleUtils");
|
|
604
|
+
const styleDefinitions = editor.config.get("style.definitions");
|
|
605
|
+
const normalizedStyleDefinitions = styleUtils.normalizeConfig(dataSchema, styleDefinitions);
|
|
606
|
+
editor.ui.componentFactory.add("style", (locale) => {
|
|
607
|
+
const t = locale.t;
|
|
608
|
+
const dropdown = createDropdown(locale);
|
|
609
|
+
const styleCommand = editor.commands.get("style");
|
|
610
|
+
dropdown.once("change:isOpen", () => {
|
|
611
|
+
const panelView = new StylePanelView(locale, normalizedStyleDefinitions);
|
|
612
|
+
dropdown.panelView.children.add(panelView);
|
|
613
|
+
panelView.delegate("execute").to(dropdown);
|
|
614
|
+
panelView.bind("activeStyles").to(styleCommand, "value");
|
|
615
|
+
panelView.bind("enabledStyles").to(styleCommand, "enabledStyles");
|
|
616
|
+
});
|
|
617
|
+
dropdown.bind("isEnabled").to(styleCommand);
|
|
618
|
+
dropdown.buttonView.withText = true;
|
|
619
|
+
dropdown.buttonView.bind("label").to(styleCommand, "value", (value) => {
|
|
620
|
+
if (value.length > 1) return t("Multiple styles");
|
|
621
|
+
else if (value.length === 1) return value[0];
|
|
622
|
+
else return t("Styles");
|
|
623
|
+
});
|
|
624
|
+
dropdown.bind("class").to(styleCommand, "value", (value) => {
|
|
625
|
+
const classes = ["ck-style-dropdown"];
|
|
626
|
+
if (value.length > 1) classes.push("ck-style-dropdown_multiple-active");
|
|
627
|
+
return classes.join(" ");
|
|
628
|
+
});
|
|
629
|
+
dropdown.on("execute", (evt) => {
|
|
630
|
+
editor.execute("style", { styleName: evt.source.styleDefinition.name });
|
|
631
|
+
editor.editing.view.focus();
|
|
632
|
+
});
|
|
633
|
+
return dropdown;
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
};
|
|
648
637
|
|
|
649
638
|
/**
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
*/ class StyleCommand extends Command {
|
|
654
|
-
/**
|
|
655
|
-
* Normalized definitions of the styles.
|
|
656
|
-
*/ _styleDefinitions;
|
|
657
|
-
/**
|
|
658
|
-
* The StyleUtils plugin.
|
|
659
|
-
*/ _styleUtils;
|
|
660
|
-
/**
|
|
661
|
-
* Creates an instance of the command.
|
|
662
|
-
*
|
|
663
|
-
* @param editor Editor on which this command will be used.
|
|
664
|
-
* @param styleDefinitions Normalized definitions of the styles.
|
|
665
|
-
*/ constructor(editor, styleDefinitions){
|
|
666
|
-
super(editor);
|
|
667
|
-
this.set('value', []);
|
|
668
|
-
this.set('enabledStyles', []);
|
|
669
|
-
this._styleDefinitions = styleDefinitions;
|
|
670
|
-
this._styleUtils = this.editor.plugins.get(StyleUtils);
|
|
671
|
-
}
|
|
672
|
-
/**
|
|
673
|
-
* @inheritDoc
|
|
674
|
-
*/ refresh() {
|
|
675
|
-
const model = this.editor.model;
|
|
676
|
-
const selection = model.document.selection;
|
|
677
|
-
const value = new Set();
|
|
678
|
-
const enabledStyles = new Set();
|
|
679
|
-
// Inline styles.
|
|
680
|
-
for (const definition of this._styleDefinitions.inline){
|
|
681
|
-
// Check if this inline style is enabled.
|
|
682
|
-
if (this._styleUtils.isStyleEnabledForInlineSelection(definition, selection)) {
|
|
683
|
-
enabledStyles.add(definition.name);
|
|
684
|
-
}
|
|
685
|
-
// Check if this inline style is active.
|
|
686
|
-
if (this._styleUtils.isStyleActiveForInlineSelection(definition, selection)) {
|
|
687
|
-
value.add(definition.name);
|
|
688
|
-
}
|
|
689
|
-
}
|
|
690
|
-
// Block styles.
|
|
691
|
-
const firstBlock = first(selection.getSelectedBlocks()) || selection.getFirstPosition().parent;
|
|
692
|
-
if (firstBlock) {
|
|
693
|
-
const ancestorBlocks = firstBlock.getAncestors({
|
|
694
|
-
includeSelf: true,
|
|
695
|
-
parentFirst: true
|
|
696
|
-
});
|
|
697
|
-
for (const block of ancestorBlocks){
|
|
698
|
-
if (block.is('rootElement')) {
|
|
699
|
-
break;
|
|
700
|
-
}
|
|
701
|
-
for (const definition of this._styleDefinitions.block){
|
|
702
|
-
// Check if this block style is enabled.
|
|
703
|
-
if (!this._styleUtils.isStyleEnabledForBlock(definition, block)) {
|
|
704
|
-
continue;
|
|
705
|
-
}
|
|
706
|
-
enabledStyles.add(definition.name);
|
|
707
|
-
// Check if this block style is active.
|
|
708
|
-
if (this._styleUtils.isStyleActiveForBlock(definition, block)) {
|
|
709
|
-
value.add(definition.name);
|
|
710
|
-
}
|
|
711
|
-
}
|
|
712
|
-
// E.g. reached a model table when the selection is in a cell. The command should not modify
|
|
713
|
-
// ancestors of a table.
|
|
714
|
-
if (model.schema.isObject(block)) {
|
|
715
|
-
break;
|
|
716
|
-
}
|
|
717
|
-
}
|
|
718
|
-
}
|
|
719
|
-
this.enabledStyles = Array.from(enabledStyles).sort();
|
|
720
|
-
this.isEnabled = this.enabledStyles.length > 0;
|
|
721
|
-
this.value = this.isEnabled ? Array.from(value).sort() : [];
|
|
722
|
-
}
|
|
723
|
-
/**
|
|
724
|
-
* Executes the command – applies the style classes to the selection or removes it from the selection.
|
|
725
|
-
*
|
|
726
|
-
* If the command value already contains the requested style, it will remove the style classes. Otherwise, it will set it.
|
|
727
|
-
*
|
|
728
|
-
* The execution result differs, depending on the {@link module:engine/model/document~ModelDocument#selection} and the
|
|
729
|
-
* style type (inline or block):
|
|
730
|
-
*
|
|
731
|
-
* * When applying inline styles:
|
|
732
|
-
* * If the selection is on a range, the command applies the style classes to all nodes in that range.
|
|
733
|
-
* * If the selection is collapsed in a non-empty node, the command applies the style classes to the
|
|
734
|
-
* {@link module:engine/model/document~ModelDocument#selection}.
|
|
735
|
-
*
|
|
736
|
-
* * When applying block styles:
|
|
737
|
-
* * If the selection is on a range, the command applies the style classes to the nearest block parent element.
|
|
738
|
-
*
|
|
739
|
-
* @fires execute
|
|
740
|
-
* @param options Command options.
|
|
741
|
-
* @param options.styleName Style name matching the one defined in the
|
|
742
|
-
* {@link module:style/styleconfig~StyleConfig#definitions configuration}.
|
|
743
|
-
* @param options.forceValue Whether the command should add given style (`true`) or remove it (`false`) from the selection.
|
|
744
|
-
* If not set (default), the command will toggle the style basing on the first selected node. Note, that this will not force
|
|
745
|
-
* setting a style on an element that cannot receive given style.
|
|
746
|
-
*/ execute({ styleName, forceValue }) {
|
|
747
|
-
if (!this.enabledStyles.includes(styleName)) {
|
|
748
|
-
/**
|
|
749
|
-
* Style command can be executed only with a correct style name.
|
|
750
|
-
*
|
|
751
|
-
* This warning may be caused by:
|
|
752
|
-
*
|
|
753
|
-
* * passing a name that is not specified in the {@link module:style/styleconfig~StyleConfig#definitions configuration}
|
|
754
|
-
* (e.g. a CSS class name),
|
|
755
|
-
* * when trying to apply a style that is not allowed on a given element.
|
|
756
|
-
*
|
|
757
|
-
* @error style-command-executed-with-incorrect-style-name
|
|
758
|
-
*/ logWarning('style-command-executed-with-incorrect-style-name');
|
|
759
|
-
return;
|
|
760
|
-
}
|
|
761
|
-
const model = this.editor.model;
|
|
762
|
-
const selection = model.document.selection;
|
|
763
|
-
const htmlSupport = this.editor.plugins.get('GeneralHtmlSupport');
|
|
764
|
-
const allDefinitions = [
|
|
765
|
-
...this._styleDefinitions.inline,
|
|
766
|
-
...this._styleDefinitions.block
|
|
767
|
-
];
|
|
768
|
-
const activeDefinitions = allDefinitions.filter(({ name })=>this.value.includes(name));
|
|
769
|
-
const definition = allDefinitions.find(({ name })=>name == styleName);
|
|
770
|
-
const shouldAddStyle = forceValue === undefined ? !this.value.includes(definition.name) : forceValue;
|
|
771
|
-
model.change(()=>{
|
|
772
|
-
let selectables;
|
|
773
|
-
if (isBlockStyleDefinition(definition)) {
|
|
774
|
-
selectables = this._findAffectedBlocks(getBlocksFromSelection(selection), definition);
|
|
775
|
-
} else {
|
|
776
|
-
selectables = [
|
|
777
|
-
this._styleUtils.getAffectedInlineSelectable(definition, selection)
|
|
778
|
-
];
|
|
779
|
-
}
|
|
780
|
-
for (const selectable of selectables){
|
|
781
|
-
if (shouldAddStyle) {
|
|
782
|
-
htmlSupport.addModelHtmlClass(definition.element, definition.classes, selectable);
|
|
783
|
-
} else {
|
|
784
|
-
htmlSupport.removeModelHtmlClass(definition.element, getDefinitionExclusiveClasses(activeDefinitions, definition), selectable);
|
|
785
|
-
}
|
|
786
|
-
}
|
|
787
|
-
});
|
|
788
|
-
}
|
|
789
|
-
/**
|
|
790
|
-
* Returns a set of elements that should be affected by the block-style change.
|
|
791
|
-
*/ _findAffectedBlocks(selectedBlocks, definition) {
|
|
792
|
-
const blocks = new Set();
|
|
793
|
-
for (const selectedBlock of selectedBlocks){
|
|
794
|
-
const ancestorBlocks = selectedBlock.getAncestors({
|
|
795
|
-
includeSelf: true,
|
|
796
|
-
parentFirst: true
|
|
797
|
-
});
|
|
798
|
-
for (const block of ancestorBlocks){
|
|
799
|
-
if (block.is('rootElement')) {
|
|
800
|
-
break;
|
|
801
|
-
}
|
|
802
|
-
const affectedBlocks = this._styleUtils.getAffectedBlocks(definition, block);
|
|
803
|
-
if (affectedBlocks) {
|
|
804
|
-
for (const affectedBlock of affectedBlocks){
|
|
805
|
-
blocks.add(affectedBlock);
|
|
806
|
-
}
|
|
807
|
-
break;
|
|
808
|
-
}
|
|
809
|
-
}
|
|
810
|
-
}
|
|
811
|
-
return blocks;
|
|
812
|
-
}
|
|
813
|
-
}
|
|
639
|
+
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
|
|
640
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
641
|
+
*/
|
|
814
642
|
/**
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
643
|
+
* Style command.
|
|
644
|
+
*
|
|
645
|
+
* Applies and removes styles from selection and elements.
|
|
646
|
+
*/
|
|
647
|
+
var StyleCommand = class extends Command {
|
|
648
|
+
/**
|
|
649
|
+
* Normalized definitions of the styles.
|
|
650
|
+
*/
|
|
651
|
+
_styleDefinitions;
|
|
652
|
+
/**
|
|
653
|
+
* The StyleUtils plugin.
|
|
654
|
+
*/
|
|
655
|
+
_styleUtils;
|
|
656
|
+
/**
|
|
657
|
+
* Creates an instance of the command.
|
|
658
|
+
*
|
|
659
|
+
* @param editor Editor on which this command will be used.
|
|
660
|
+
* @param styleDefinitions Normalized definitions of the styles.
|
|
661
|
+
*/
|
|
662
|
+
constructor(editor, styleDefinitions) {
|
|
663
|
+
super(editor);
|
|
664
|
+
this.set("value", []);
|
|
665
|
+
this.set("enabledStyles", []);
|
|
666
|
+
this._styleDefinitions = styleDefinitions;
|
|
667
|
+
this._styleUtils = this.editor.plugins.get(StyleUtils);
|
|
668
|
+
}
|
|
669
|
+
/**
|
|
670
|
+
* @inheritDoc
|
|
671
|
+
*/
|
|
672
|
+
refresh() {
|
|
673
|
+
const model = this.editor.model;
|
|
674
|
+
const selection = model.document.selection;
|
|
675
|
+
const value = /* @__PURE__ */ new Set();
|
|
676
|
+
const enabledStyles = /* @__PURE__ */ new Set();
|
|
677
|
+
for (const definition of this._styleDefinitions.inline) {
|
|
678
|
+
if (this._styleUtils.isStyleEnabledForInlineSelection(definition, selection)) enabledStyles.add(definition.name);
|
|
679
|
+
if (this._styleUtils.isStyleActiveForInlineSelection(definition, selection)) value.add(definition.name);
|
|
680
|
+
}
|
|
681
|
+
const firstBlock = first(selection.getSelectedBlocks()) || selection.getFirstPosition().parent;
|
|
682
|
+
/* v8 ignore else -- @preserve */
|
|
683
|
+
if (firstBlock) {
|
|
684
|
+
const ancestorBlocks = firstBlock.getAncestors({
|
|
685
|
+
includeSelf: true,
|
|
686
|
+
parentFirst: true
|
|
687
|
+
});
|
|
688
|
+
for (const block of ancestorBlocks) {
|
|
689
|
+
if (block.is("rootElement")) break;
|
|
690
|
+
for (const definition of this._styleDefinitions.block) {
|
|
691
|
+
if (!this._styleUtils.isStyleEnabledForBlock(definition, block)) continue;
|
|
692
|
+
enabledStyles.add(definition.name);
|
|
693
|
+
if (this._styleUtils.isStyleActiveForBlock(definition, block)) value.add(definition.name);
|
|
694
|
+
}
|
|
695
|
+
if (model.schema.isObject(block)) break;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
this.enabledStyles = Array.from(enabledStyles).sort();
|
|
699
|
+
this.isEnabled = this.enabledStyles.length > 0;
|
|
700
|
+
this.value = this.isEnabled ? Array.from(value).sort() : [];
|
|
701
|
+
}
|
|
702
|
+
/**
|
|
703
|
+
* Executes the command – applies the style classes to the selection or removes it from the selection.
|
|
704
|
+
*
|
|
705
|
+
* If the command value already contains the requested style, it will remove the style classes. Otherwise, it will set it.
|
|
706
|
+
*
|
|
707
|
+
* The execution result differs, depending on the {@link module:engine/model/document~ModelDocument#selection} and the
|
|
708
|
+
* style type (inline or block):
|
|
709
|
+
*
|
|
710
|
+
* * When applying inline styles:
|
|
711
|
+
* * If the selection is on a range, the command applies the style classes to all nodes in that range.
|
|
712
|
+
* * If the selection is collapsed in a non-empty node, the command applies the style classes to the
|
|
713
|
+
* {@link module:engine/model/document~ModelDocument#selection}.
|
|
714
|
+
*
|
|
715
|
+
* * When applying block styles:
|
|
716
|
+
* * If the selection is on a range, the command applies the style classes to the nearest block parent element.
|
|
717
|
+
*
|
|
718
|
+
* @fires execute
|
|
719
|
+
* @param options Command options.
|
|
720
|
+
* @param options.styleName Style name matching the one defined in the
|
|
721
|
+
* {@link module:style/styleconfig~StyleConfig#definitions configuration}.
|
|
722
|
+
* @param options.forceValue Whether the command should add given style (`true`) or remove it (`false`) from the selection.
|
|
723
|
+
* If not set (default), the command will toggle the style basing on the first selected node. Note, that this will not force
|
|
724
|
+
* setting a style on an element that cannot receive given style.
|
|
725
|
+
*/
|
|
726
|
+
execute({ styleName, forceValue }) {
|
|
727
|
+
if (!this.enabledStyles.includes(styleName)) {
|
|
728
|
+
/**
|
|
729
|
+
* Style command can be executed only with a correct style name.
|
|
730
|
+
*
|
|
731
|
+
* This warning may be caused by:
|
|
732
|
+
*
|
|
733
|
+
* * passing a name that is not specified in the {@link module:style/styleconfig~StyleConfig#definitions configuration}
|
|
734
|
+
* (e.g. a CSS class name),
|
|
735
|
+
* * when trying to apply a style that is not allowed on a given element.
|
|
736
|
+
*
|
|
737
|
+
* @error style-command-executed-with-incorrect-style-name
|
|
738
|
+
*/
|
|
739
|
+
logWarning("style-command-executed-with-incorrect-style-name");
|
|
740
|
+
return;
|
|
741
|
+
}
|
|
742
|
+
const model = this.editor.model;
|
|
743
|
+
const selection = model.document.selection;
|
|
744
|
+
const htmlSupport = this.editor.plugins.get("GeneralHtmlSupport");
|
|
745
|
+
const allDefinitions = [...this._styleDefinitions.inline, ...this._styleDefinitions.block];
|
|
746
|
+
const activeDefinitions = allDefinitions.filter(({ name }) => this.value.includes(name));
|
|
747
|
+
const definition = allDefinitions.find(({ name }) => name == styleName);
|
|
748
|
+
const shouldAddStyle = forceValue === void 0 ? !this.value.includes(definition.name) : forceValue;
|
|
749
|
+
model.change(() => {
|
|
750
|
+
let selectables;
|
|
751
|
+
if (isBlockStyleDefinition(definition)) selectables = this._findAffectedBlocks(getBlocksFromSelection(selection), definition);
|
|
752
|
+
else selectables = [this._styleUtils.getAffectedInlineSelectable(definition, selection)];
|
|
753
|
+
for (const selectable of selectables) if (shouldAddStyle) htmlSupport.addModelHtmlClass(definition.element, definition.classes, selectable);
|
|
754
|
+
else htmlSupport.removeModelHtmlClass(definition.element, getDefinitionExclusiveClasses(activeDefinitions, definition), selectable);
|
|
755
|
+
});
|
|
756
|
+
}
|
|
757
|
+
/**
|
|
758
|
+
* Returns a set of elements that should be affected by the block-style change.
|
|
759
|
+
*/
|
|
760
|
+
_findAffectedBlocks(selectedBlocks, definition) {
|
|
761
|
+
const blocks = /* @__PURE__ */ new Set();
|
|
762
|
+
for (const selectedBlock of selectedBlocks) {
|
|
763
|
+
const ancestorBlocks = selectedBlock.getAncestors({
|
|
764
|
+
includeSelf: true,
|
|
765
|
+
parentFirst: true
|
|
766
|
+
});
|
|
767
|
+
for (const block of ancestorBlocks) {
|
|
768
|
+
if (block.is("rootElement")) break;
|
|
769
|
+
const affectedBlocks = this._styleUtils.getAffectedBlocks(definition, block);
|
|
770
|
+
if (affectedBlocks) {
|
|
771
|
+
for (const affectedBlock of affectedBlocks) blocks.add(affectedBlock);
|
|
772
|
+
break;
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
return blocks;
|
|
777
|
+
}
|
|
778
|
+
};
|
|
779
|
+
/**
|
|
780
|
+
* Returns classes that are defined only in the supplied definition and not in any other active definition. It's used
|
|
781
|
+
* to ensure that classes used by other definitions are preserved when a style is removed.
|
|
782
|
+
* See https://github.com/ckeditor/ckeditor5/issues/11748.
|
|
783
|
+
*
|
|
784
|
+
* @param activeDefinitions All currently active definitions affecting selected element(s).
|
|
785
|
+
* @param definition Definition whose classes will be compared with all other active definition classes.
|
|
786
|
+
* @returns Array of classes exclusive to the supplied definition.
|
|
787
|
+
*/
|
|
788
|
+
function getDefinitionExclusiveClasses(activeDefinitions, definition) {
|
|
789
|
+
return activeDefinitions.reduce((classes, currentDefinition) => {
|
|
790
|
+
if (currentDefinition.name === definition.name) return classes;
|
|
791
|
+
return classes.filter((className) => !currentDefinition.classes.includes(className));
|
|
792
|
+
}, definition.classes);
|
|
829
793
|
}
|
|
830
794
|
/**
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
795
|
+
* Checks if provided style definition is of type block.
|
|
796
|
+
*/
|
|
797
|
+
function isBlockStyleDefinition(definition) {
|
|
798
|
+
return "isBlock" in definition;
|
|
834
799
|
}
|
|
835
800
|
/**
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
return [
|
|
845
|
-
selection.getFirstPosition().parent
|
|
846
|
-
];
|
|
801
|
+
* Gets block elements from selection. If there are none, returns first selected element.
|
|
802
|
+
* @param selection Current document's selection.
|
|
803
|
+
* @returns Selected blocks if there are any, first selected element otherwise.
|
|
804
|
+
*/
|
|
805
|
+
function getBlocksFromSelection(selection) {
|
|
806
|
+
const blocks = Array.from(selection.getSelectedBlocks());
|
|
807
|
+
if (blocks.length) return blocks;
|
|
808
|
+
return [selection.getFirstPosition().parent];
|
|
847
809
|
}
|
|
848
810
|
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
},
|
|
973
|
-
children: [
|
|
974
|
-
{
|
|
975
|
-
tag: 'li',
|
|
976
|
-
children
|
|
977
|
-
}
|
|
978
|
-
]
|
|
979
|
-
};
|
|
980
|
-
} else if (element == 'li') {
|
|
981
|
-
return {
|
|
982
|
-
tag: 'ol',
|
|
983
|
-
children: [
|
|
984
|
-
{
|
|
985
|
-
tag: element,
|
|
986
|
-
attributes: {
|
|
987
|
-
class: classes
|
|
988
|
-
},
|
|
989
|
-
children
|
|
990
|
-
}
|
|
991
|
-
]
|
|
992
|
-
};
|
|
993
|
-
}
|
|
994
|
-
return null;
|
|
995
|
-
}
|
|
996
|
-
}
|
|
811
|
+
/**
|
|
812
|
+
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
|
|
813
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
814
|
+
*/
|
|
815
|
+
/**
|
|
816
|
+
* @module style/integrations/list
|
|
817
|
+
*/
|
|
818
|
+
var ListStyleSupport = class extends Plugin {
|
|
819
|
+
_listUtils;
|
|
820
|
+
_styleUtils;
|
|
821
|
+
_htmlSupport;
|
|
822
|
+
/**
|
|
823
|
+
* @inheritDoc
|
|
824
|
+
*/
|
|
825
|
+
static get pluginName() {
|
|
826
|
+
return "ListStyleSupport";
|
|
827
|
+
}
|
|
828
|
+
/**
|
|
829
|
+
* @inheritDoc
|
|
830
|
+
*/
|
|
831
|
+
static get isOfficialPlugin() {
|
|
832
|
+
return true;
|
|
833
|
+
}
|
|
834
|
+
/**
|
|
835
|
+
* @inheritDoc
|
|
836
|
+
*/
|
|
837
|
+
static get requires() {
|
|
838
|
+
return [StyleUtils, GeneralHtmlSupport];
|
|
839
|
+
}
|
|
840
|
+
/**
|
|
841
|
+
* @inheritDoc
|
|
842
|
+
*/
|
|
843
|
+
init() {
|
|
844
|
+
const editor = this.editor;
|
|
845
|
+
if (!editor.plugins.has("ListEditing")) return;
|
|
846
|
+
this._styleUtils = editor.plugins.get(StyleUtils);
|
|
847
|
+
this._listUtils = this.editor.plugins.get("ListUtils");
|
|
848
|
+
this._htmlSupport = this.editor.plugins.get(GeneralHtmlSupport);
|
|
849
|
+
this.listenTo(this._styleUtils, "isStyleEnabledForBlock", (evt, [definition, block]) => {
|
|
850
|
+
if (this._isStyleEnabledForBlock(definition, block)) {
|
|
851
|
+
evt.return = true;
|
|
852
|
+
evt.stop();
|
|
853
|
+
}
|
|
854
|
+
}, { priority: "high" });
|
|
855
|
+
this.listenTo(this._styleUtils, "isStyleActiveForBlock", (evt, [definition, block]) => {
|
|
856
|
+
if (this._isStyleActiveForBlock(definition, block)) {
|
|
857
|
+
evt.return = true;
|
|
858
|
+
evt.stop();
|
|
859
|
+
}
|
|
860
|
+
}, { priority: "high" });
|
|
861
|
+
this.listenTo(this._styleUtils, "getAffectedBlocks", (evt, [definition, block]) => {
|
|
862
|
+
const blocks = this._getAffectedBlocks(definition, block);
|
|
863
|
+
if (blocks) {
|
|
864
|
+
evt.return = blocks;
|
|
865
|
+
evt.stop();
|
|
866
|
+
}
|
|
867
|
+
}, { priority: "high" });
|
|
868
|
+
this.listenTo(this._styleUtils, "getStylePreview", (evt, [definition, children]) => {
|
|
869
|
+
const templateDefinition = this._getStylePreview(definition, children);
|
|
870
|
+
if (templateDefinition) {
|
|
871
|
+
evt.return = templateDefinition;
|
|
872
|
+
evt.stop();
|
|
873
|
+
}
|
|
874
|
+
}, { priority: "high" });
|
|
875
|
+
}
|
|
876
|
+
/**
|
|
877
|
+
* Verifies if the given style is applicable to the provided block element.
|
|
878
|
+
*/
|
|
879
|
+
_isStyleEnabledForBlock(definition, block) {
|
|
880
|
+
const model = this.editor.model;
|
|
881
|
+
if (![
|
|
882
|
+
"ol",
|
|
883
|
+
"ul",
|
|
884
|
+
"li"
|
|
885
|
+
].includes(definition.element)) return false;
|
|
886
|
+
if (!this._listUtils.isListItemBlock(block)) return false;
|
|
887
|
+
const attributeName = this._htmlSupport.getGhsAttributeNameForElement(definition.element);
|
|
888
|
+
if (definition.element == "ol" || definition.element == "ul") {
|
|
889
|
+
if (!model.schema.checkAttribute(block, attributeName)) return false;
|
|
890
|
+
const viewElementName = this._listUtils.isNumberedListType(block.getAttribute("listType")) ? "ol" : "ul";
|
|
891
|
+
return definition.element == viewElementName;
|
|
892
|
+
} else return model.schema.checkAttribute(block, attributeName);
|
|
893
|
+
}
|
|
894
|
+
/**
|
|
895
|
+
* Returns true if the given style is applied to the specified block element.
|
|
896
|
+
*/
|
|
897
|
+
_isStyleActiveForBlock(definition, block) {
|
|
898
|
+
const attributeName = this._htmlSupport.getGhsAttributeNameForElement(definition.element);
|
|
899
|
+
const ghsAttributeValue = block.getAttribute(attributeName);
|
|
900
|
+
return this._styleUtils.hasAllClasses(ghsAttributeValue, definition.classes);
|
|
901
|
+
}
|
|
902
|
+
/**
|
|
903
|
+
* Returns an array of block elements that style should be applied to.
|
|
904
|
+
*/
|
|
905
|
+
_getAffectedBlocks(definition, block) {
|
|
906
|
+
if (!this._isStyleEnabledForBlock(definition, block)) return null;
|
|
907
|
+
if (definition.element == "li") return this._listUtils.expandListBlocksToCompleteItems(block, { withNested: false });
|
|
908
|
+
else return this._listUtils.expandListBlocksToCompleteList(block);
|
|
909
|
+
}
|
|
910
|
+
/**
|
|
911
|
+
* Returns a view template definition for the style preview.
|
|
912
|
+
*/
|
|
913
|
+
_getStylePreview(definition, children) {
|
|
914
|
+
const { element, classes } = definition;
|
|
915
|
+
if (element == "ol" || element == "ul") return {
|
|
916
|
+
tag: element,
|
|
917
|
+
attributes: { class: classes },
|
|
918
|
+
children: [{
|
|
919
|
+
tag: "li",
|
|
920
|
+
children
|
|
921
|
+
}]
|
|
922
|
+
};
|
|
923
|
+
else if (element == "li") return {
|
|
924
|
+
tag: "ol",
|
|
925
|
+
children: [{
|
|
926
|
+
tag: element,
|
|
927
|
+
attributes: { class: classes },
|
|
928
|
+
children
|
|
929
|
+
}]
|
|
930
|
+
};
|
|
931
|
+
return null;
|
|
932
|
+
}
|
|
933
|
+
};
|
|
997
934
|
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
/**
|
|
1114
|
-
* Gets all blocks that the style should be applied to.
|
|
1115
|
-
*
|
|
1116
|
-
* @param definition Style definition that is being considered.
|
|
1117
|
-
* @param block A block element from selection.
|
|
1118
|
-
* @returns An array with the block that was passed as an argument if meets the criteria, null otherwise.
|
|
1119
|
-
*/ _getAffectedBlocks(definition, block) {
|
|
1120
|
-
if (!this._isStyleEnabledForBlock(definition, block)) {
|
|
1121
|
-
return null;
|
|
1122
|
-
}
|
|
1123
|
-
return [
|
|
1124
|
-
block
|
|
1125
|
-
];
|
|
1126
|
-
}
|
|
1127
|
-
}
|
|
935
|
+
/**
|
|
936
|
+
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
|
|
937
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
938
|
+
*/
|
|
939
|
+
/**
|
|
940
|
+
* @module style/integrations/table
|
|
941
|
+
*/
|
|
942
|
+
var TableStyleSupport = class extends Plugin {
|
|
943
|
+
_tableUtils;
|
|
944
|
+
_styleUtils;
|
|
945
|
+
/**
|
|
946
|
+
* @inheritDoc
|
|
947
|
+
*/
|
|
948
|
+
static get pluginName() {
|
|
949
|
+
return "TableStyleSupport";
|
|
950
|
+
}
|
|
951
|
+
/**
|
|
952
|
+
* @inheritDoc
|
|
953
|
+
*/
|
|
954
|
+
static get isOfficialPlugin() {
|
|
955
|
+
return true;
|
|
956
|
+
}
|
|
957
|
+
/**
|
|
958
|
+
* @inheritDoc
|
|
959
|
+
*/
|
|
960
|
+
static get requires() {
|
|
961
|
+
return [StyleUtils];
|
|
962
|
+
}
|
|
963
|
+
/**
|
|
964
|
+
* @inheritDoc
|
|
965
|
+
*/
|
|
966
|
+
init() {
|
|
967
|
+
const editor = this.editor;
|
|
968
|
+
if (!editor.plugins.has("TableEditing")) return;
|
|
969
|
+
this._styleUtils = editor.plugins.get(StyleUtils);
|
|
970
|
+
this._tableUtils = this.editor.plugins.get("TableUtils");
|
|
971
|
+
this.listenTo(this._styleUtils, "isStyleEnabledForBlock", (evt, [definition, block]) => {
|
|
972
|
+
if (this._isApplicable(definition, block)) {
|
|
973
|
+
evt.return = this._isStyleEnabledForBlock(definition, block);
|
|
974
|
+
evt.stop();
|
|
975
|
+
}
|
|
976
|
+
}, { priority: "high" });
|
|
977
|
+
this.listenTo(this._styleUtils, "getAffectedBlocks", (evt, [definition, block]) => {
|
|
978
|
+
if (this._isApplicable(definition, block)) {
|
|
979
|
+
evt.return = this._getAffectedBlocks(definition, block);
|
|
980
|
+
evt.stop();
|
|
981
|
+
}
|
|
982
|
+
}, { priority: "high" });
|
|
983
|
+
this.listenTo(this._styleUtils, "configureGHSDataFilter", (evt, [{ block }]) => {
|
|
984
|
+
this.editor.plugins.get("DataFilter").loadAllowedConfig(block.filter((definition) => definition.element == "figcaption").map((definition) => ({
|
|
985
|
+
name: "caption",
|
|
986
|
+
classes: definition.classes
|
|
987
|
+
})));
|
|
988
|
+
});
|
|
989
|
+
}
|
|
990
|
+
/**
|
|
991
|
+
* Checks if this plugin's custom logic should be applied for defintion-block pair.
|
|
992
|
+
*
|
|
993
|
+
* @param definition Style definition that is being considered.
|
|
994
|
+
* @param block Block element to check if should be styled.
|
|
995
|
+
* @returns True if the defintion-block pair meet the plugin criteria, false otherwise.
|
|
996
|
+
*/
|
|
997
|
+
_isApplicable(definition, block) {
|
|
998
|
+
if (["td", "th"].includes(definition.element)) return block.name == "tableCell";
|
|
999
|
+
if ([
|
|
1000
|
+
"thead",
|
|
1001
|
+
"tbody",
|
|
1002
|
+
"tfoot"
|
|
1003
|
+
].includes(definition.element)) return block.name == "table";
|
|
1004
|
+
return false;
|
|
1005
|
+
}
|
|
1006
|
+
/**
|
|
1007
|
+
* Checks if the style definition should be applied to selected block.
|
|
1008
|
+
*
|
|
1009
|
+
* @param definition Style definition that is being considered.
|
|
1010
|
+
* @param block Block element to check if should be styled.
|
|
1011
|
+
* @returns True if the block should be style with the style description, false otherwise.
|
|
1012
|
+
*/
|
|
1013
|
+
_isStyleEnabledForBlock(definition, block) {
|
|
1014
|
+
if (["td", "th"].includes(definition.element)) {
|
|
1015
|
+
const location = this._tableUtils.getCellLocation(block);
|
|
1016
|
+
const table = block.parent.parent;
|
|
1017
|
+
const headingRows = table.getAttribute("headingRows") || 0;
|
|
1018
|
+
const headingColumns = table.getAttribute("headingColumns") || 0;
|
|
1019
|
+
const isHeadingCell = location.row < headingRows || location.column < headingColumns;
|
|
1020
|
+
if (definition.element == "th") return isHeadingCell;
|
|
1021
|
+
else return !isHeadingCell;
|
|
1022
|
+
}
|
|
1023
|
+
/* v8 ignore else -- @preserve */
|
|
1024
|
+
if ([
|
|
1025
|
+
"thead",
|
|
1026
|
+
"tbody",
|
|
1027
|
+
"tfoot"
|
|
1028
|
+
].includes(definition.element)) {
|
|
1029
|
+
const headingRows = block.getAttribute("headingRows") || 0;
|
|
1030
|
+
const footerRows = block.getAttribute("footerRows") || 0;
|
|
1031
|
+
if (definition.element == "thead") return headingRows > 0;
|
|
1032
|
+
else if (definition.element == "tfoot") return footerRows > 0;
|
|
1033
|
+
else return headingRows + footerRows < this._tableUtils.getRows(block);
|
|
1034
|
+
}
|
|
1035
|
+
/* v8 ignore next -- @preserve */
|
|
1036
|
+
return false;
|
|
1037
|
+
}
|
|
1038
|
+
/**
|
|
1039
|
+
* Gets all blocks that the style should be applied to.
|
|
1040
|
+
*
|
|
1041
|
+
* @param definition Style definition that is being considered.
|
|
1042
|
+
* @param block A block element from selection.
|
|
1043
|
+
* @returns An array with the block that was passed as an argument if meets the criteria, null otherwise.
|
|
1044
|
+
*/
|
|
1045
|
+
_getAffectedBlocks(definition, block) {
|
|
1046
|
+
if (!this._isStyleEnabledForBlock(definition, block)) return null;
|
|
1047
|
+
return [block];
|
|
1048
|
+
}
|
|
1049
|
+
};
|
|
1128
1050
|
|
|
1129
|
-
class LinkStyleSupport extends Plugin {
|
|
1130
|
-
_styleUtils;
|
|
1131
|
-
_htmlSupport;
|
|
1132
|
-
/**
|
|
1133
|
-
* @inheritDoc
|
|
1134
|
-
*/ static get pluginName() {
|
|
1135
|
-
return 'LinkStyleSupport';
|
|
1136
|
-
}
|
|
1137
|
-
/**
|
|
1138
|
-
* @inheritDoc
|
|
1139
|
-
*/ static get isOfficialPlugin() {
|
|
1140
|
-
return true;
|
|
1141
|
-
}
|
|
1142
|
-
/**
|
|
1143
|
-
* @inheritDoc
|
|
1144
|
-
*/ static get requires() {
|
|
1145
|
-
return [
|
|
1146
|
-
StyleUtils,
|
|
1147
|
-
GeneralHtmlSupport
|
|
1148
|
-
];
|
|
1149
|
-
}
|
|
1150
|
-
/**
|
|
1151
|
-
* @inheritDoc
|
|
1152
|
-
*/ init() {
|
|
1153
|
-
const editor = this.editor;
|
|
1154
|
-
if (!editor.plugins.has('LinkEditing')) {
|
|
1155
|
-
return;
|
|
1156
|
-
}
|
|
1157
|
-
this._styleUtils = editor.plugins.get(StyleUtils);
|
|
1158
|
-
this._htmlSupport = this.editor.plugins.get(GeneralHtmlSupport);
|
|
1159
|
-
this.listenTo(this._styleUtils, 'isStyleEnabledForInlineSelection', (evt, [definition, selection])=>{
|
|
1160
|
-
if (definition.element == 'a') {
|
|
1161
|
-
evt.return = this._isStyleEnabled(definition, selection);
|
|
1162
|
-
evt.stop();
|
|
1163
|
-
}
|
|
1164
|
-
}, {
|
|
1165
|
-
priority: 'high'
|
|
1166
|
-
});
|
|
1167
|
-
this.listenTo(this._styleUtils, 'isStyleActiveForInlineSelection', (evt, [definition, selection])=>{
|
|
1168
|
-
if (definition.element == 'a') {
|
|
1169
|
-
evt.return = this._isStyleActive(definition, selection);
|
|
1170
|
-
evt.stop();
|
|
1171
|
-
}
|
|
1172
|
-
}, {
|
|
1173
|
-
priority: 'high'
|
|
1174
|
-
});
|
|
1175
|
-
this.listenTo(this._styleUtils, 'getAffectedInlineSelectable', (evt, [definition, selection])=>{
|
|
1176
|
-
if (definition.element != 'a') {
|
|
1177
|
-
return;
|
|
1178
|
-
}
|
|
1179
|
-
const selectable = this._getAffectedSelectable(definition, selection);
|
|
1180
|
-
if (selectable) {
|
|
1181
|
-
evt.return = selectable;
|
|
1182
|
-
evt.stop();
|
|
1183
|
-
}
|
|
1184
|
-
}, {
|
|
1185
|
-
priority: 'high'
|
|
1186
|
-
});
|
|
1187
|
-
}
|
|
1188
|
-
/**
|
|
1189
|
-
* Verifies if the given style is applicable to the provided document selection.
|
|
1190
|
-
*/ _isStyleEnabled(definition, selection) {
|
|
1191
|
-
const model = this.editor.model;
|
|
1192
|
-
// Handle collapsed selection.
|
|
1193
|
-
if (selection.isCollapsed) {
|
|
1194
|
-
return selection.hasAttribute('linkHref');
|
|
1195
|
-
}
|
|
1196
|
-
// Non-collapsed selection.
|
|
1197
|
-
for (const range of selection.getRanges()){
|
|
1198
|
-
for (const item of range.getItems()){
|
|
1199
|
-
if ((item.is('$textProxy') || model.schema.isInline(item)) && item.hasAttribute('linkHref')) {
|
|
1200
|
-
return true;
|
|
1201
|
-
}
|
|
1202
|
-
}
|
|
1203
|
-
}
|
|
1204
|
-
return false;
|
|
1205
|
-
}
|
|
1206
|
-
/**
|
|
1207
|
-
* Returns true if the given style is applied to the specified document selection.
|
|
1208
|
-
*/ _isStyleActive(definition, selection) {
|
|
1209
|
-
const model = this.editor.model;
|
|
1210
|
-
const attributeName = this._htmlSupport.getGhsAttributeNameForElement(definition.element);
|
|
1211
|
-
// Handle collapsed selection.
|
|
1212
|
-
if (selection.isCollapsed) {
|
|
1213
|
-
if (selection.hasAttribute('linkHref')) {
|
|
1214
|
-
const ghsAttributeValue = selection.getAttribute(attributeName);
|
|
1215
|
-
if (this._styleUtils.hasAllClasses(ghsAttributeValue, definition.classes)) {
|
|
1216
|
-
return true;
|
|
1217
|
-
}
|
|
1218
|
-
}
|
|
1219
|
-
return false;
|
|
1220
|
-
}
|
|
1221
|
-
// Non-collapsed selection.
|
|
1222
|
-
for (const range of selection.getRanges()){
|
|
1223
|
-
for (const item of range.getItems()){
|
|
1224
|
-
if ((item.is('$textProxy') || model.schema.isInline(item)) && item.hasAttribute('linkHref')) {
|
|
1225
|
-
const ghsAttributeValue = item.getAttribute(attributeName);
|
|
1226
|
-
return this._styleUtils.hasAllClasses(ghsAttributeValue, definition.classes);
|
|
1227
|
-
}
|
|
1228
|
-
}
|
|
1229
|
-
}
|
|
1230
|
-
return false;
|
|
1231
|
-
}
|
|
1232
|
-
/**
|
|
1233
|
-
* Returns a selectable that given style should be applied to.
|
|
1234
|
-
*/ _getAffectedSelectable(definition, selection) {
|
|
1235
|
-
const model = this.editor.model;
|
|
1236
|
-
// Handle collapsed selection.
|
|
1237
|
-
if (selection.isCollapsed) {
|
|
1238
|
-
const linkHref = selection.getAttribute('linkHref');
|
|
1239
|
-
return findAttributeRange(selection.getFirstPosition(), 'linkHref', linkHref, model);
|
|
1240
|
-
}
|
|
1241
|
-
// Non-collapsed selection.
|
|
1242
|
-
const ranges = [];
|
|
1243
|
-
for (const range of selection.getRanges()){
|
|
1244
|
-
// First expand range to include the whole link.
|
|
1245
|
-
const expandedRange = model.createRange(expandAttributePosition(range.start, 'linkHref', true, model), expandAttributePosition(range.end, 'linkHref', false, model));
|
|
1246
|
-
// Pick only ranges on links.
|
|
1247
|
-
for (const item of expandedRange.getItems()){
|
|
1248
|
-
if ((item.is('$textProxy') || model.schema.isInline(item)) && item.hasAttribute('linkHref')) {
|
|
1249
|
-
ranges.push(this.editor.model.createRangeOn(item));
|
|
1250
|
-
}
|
|
1251
|
-
}
|
|
1252
|
-
}
|
|
1253
|
-
// Make sure that we have a continuous range on a link
|
|
1254
|
-
// (not split between text nodes with mixed attributes like bold etc.)
|
|
1255
|
-
return normalizeRanges(ranges);
|
|
1256
|
-
}
|
|
1257
|
-
}
|
|
1258
1051
|
/**
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1052
|
+
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
|
|
1053
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
1054
|
+
*/
|
|
1055
|
+
/**
|
|
1056
|
+
* @module style/integrations/link
|
|
1057
|
+
*/
|
|
1058
|
+
var LinkStyleSupport = class extends Plugin {
|
|
1059
|
+
_styleUtils;
|
|
1060
|
+
_htmlSupport;
|
|
1061
|
+
/**
|
|
1062
|
+
* @inheritDoc
|
|
1063
|
+
*/
|
|
1064
|
+
static get pluginName() {
|
|
1065
|
+
return "LinkStyleSupport";
|
|
1066
|
+
}
|
|
1067
|
+
/**
|
|
1068
|
+
* @inheritDoc
|
|
1069
|
+
*/
|
|
1070
|
+
static get isOfficialPlugin() {
|
|
1071
|
+
return true;
|
|
1072
|
+
}
|
|
1073
|
+
/**
|
|
1074
|
+
* @inheritDoc
|
|
1075
|
+
*/
|
|
1076
|
+
static get requires() {
|
|
1077
|
+
return [StyleUtils, GeneralHtmlSupport];
|
|
1078
|
+
}
|
|
1079
|
+
/**
|
|
1080
|
+
* @inheritDoc
|
|
1081
|
+
*/
|
|
1082
|
+
init() {
|
|
1083
|
+
const editor = this.editor;
|
|
1084
|
+
if (!editor.plugins.has("LinkEditing")) return;
|
|
1085
|
+
this._styleUtils = editor.plugins.get(StyleUtils);
|
|
1086
|
+
this._htmlSupport = this.editor.plugins.get(GeneralHtmlSupport);
|
|
1087
|
+
this.listenTo(this._styleUtils, "isStyleEnabledForInlineSelection", (evt, [definition, selection]) => {
|
|
1088
|
+
if (definition.element == "a") {
|
|
1089
|
+
evt.return = this._isStyleEnabled(definition, selection);
|
|
1090
|
+
evt.stop();
|
|
1091
|
+
}
|
|
1092
|
+
}, { priority: "high" });
|
|
1093
|
+
this.listenTo(this._styleUtils, "isStyleActiveForInlineSelection", (evt, [definition, selection]) => {
|
|
1094
|
+
if (definition.element == "a") {
|
|
1095
|
+
evt.return = this._isStyleActive(definition, selection);
|
|
1096
|
+
evt.stop();
|
|
1097
|
+
}
|
|
1098
|
+
}, { priority: "high" });
|
|
1099
|
+
this.listenTo(this._styleUtils, "getAffectedInlineSelectable", (evt, [definition, selection]) => {
|
|
1100
|
+
if (definition.element != "a") return;
|
|
1101
|
+
const selectable = this._getAffectedSelectable(definition, selection);
|
|
1102
|
+
/* v8 ignore else -- @preserve */
|
|
1103
|
+
if (selectable) {
|
|
1104
|
+
evt.return = selectable;
|
|
1105
|
+
evt.stop();
|
|
1106
|
+
}
|
|
1107
|
+
}, { priority: "high" });
|
|
1108
|
+
}
|
|
1109
|
+
/**
|
|
1110
|
+
* Verifies if the given style is applicable to the provided document selection.
|
|
1111
|
+
*/
|
|
1112
|
+
_isStyleEnabled(definition, selection) {
|
|
1113
|
+
const model = this.editor.model;
|
|
1114
|
+
if (selection.isCollapsed) return selection.hasAttribute("linkHref");
|
|
1115
|
+
for (const range of selection.getRanges()) for (const item of range.getItems()) if ((item.is("$textProxy") || model.schema.isInline(item)) && item.hasAttribute("linkHref")) return true;
|
|
1116
|
+
return false;
|
|
1117
|
+
}
|
|
1118
|
+
/**
|
|
1119
|
+
* Returns true if the given style is applied to the specified document selection.
|
|
1120
|
+
*/
|
|
1121
|
+
_isStyleActive(definition, selection) {
|
|
1122
|
+
const model = this.editor.model;
|
|
1123
|
+
const attributeName = this._htmlSupport.getGhsAttributeNameForElement(definition.element);
|
|
1124
|
+
if (selection.isCollapsed) {
|
|
1125
|
+
if (selection.hasAttribute("linkHref")) {
|
|
1126
|
+
const ghsAttributeValue = selection.getAttribute(attributeName);
|
|
1127
|
+
if (this._styleUtils.hasAllClasses(ghsAttributeValue, definition.classes)) return true;
|
|
1128
|
+
}
|
|
1129
|
+
return false;
|
|
1130
|
+
}
|
|
1131
|
+
for (const range of selection.getRanges()) for (const item of range.getItems()) if ((item.is("$textProxy") || model.schema.isInline(item)) && item.hasAttribute("linkHref")) {
|
|
1132
|
+
const ghsAttributeValue = item.getAttribute(attributeName);
|
|
1133
|
+
return this._styleUtils.hasAllClasses(ghsAttributeValue, definition.classes);
|
|
1134
|
+
}
|
|
1135
|
+
return false;
|
|
1136
|
+
}
|
|
1137
|
+
/**
|
|
1138
|
+
* Returns a selectable that given style should be applied to.
|
|
1139
|
+
*/
|
|
1140
|
+
_getAffectedSelectable(definition, selection) {
|
|
1141
|
+
const model = this.editor.model;
|
|
1142
|
+
if (selection.isCollapsed) {
|
|
1143
|
+
const linkHref = selection.getAttribute("linkHref");
|
|
1144
|
+
return findAttributeRange(selection.getFirstPosition(), "linkHref", linkHref, model);
|
|
1145
|
+
}
|
|
1146
|
+
const ranges = [];
|
|
1147
|
+
for (const range of selection.getRanges()) {
|
|
1148
|
+
const expandedRange = model.createRange(expandAttributePosition(range.start, "linkHref", true, model), expandAttributePosition(range.end, "linkHref", false, model));
|
|
1149
|
+
for (const item of expandedRange.getItems()) if ((item.is("$textProxy") || model.schema.isInline(item)) && item.hasAttribute("linkHref")) ranges.push(this.editor.model.createRangeOn(item));
|
|
1150
|
+
}
|
|
1151
|
+
return normalizeRanges(ranges);
|
|
1152
|
+
}
|
|
1153
|
+
};
|
|
1154
|
+
/**
|
|
1155
|
+
* Walks forward or backward (depends on the `lookBack` flag), node by node, as long as they have the same attribute value
|
|
1156
|
+
* and returns a position just before or after (depends on the `lookBack` flag) the last matched node.
|
|
1157
|
+
*/
|
|
1158
|
+
function expandAttributePosition(position, attributeName, lookBack, model) {
|
|
1159
|
+
const referenceNode = position.textNode || (lookBack ? position.nodeAfter : position.nodeBefore);
|
|
1160
|
+
if (!referenceNode || !referenceNode.hasAttribute(attributeName)) return position;
|
|
1161
|
+
return findAttributeRangeBound(position, attributeName, referenceNode.getAttribute(attributeName), lookBack, model);
|
|
1268
1162
|
}
|
|
1269
1163
|
/**
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
}
|
|
1281
|
-
return ranges;
|
|
1164
|
+
* Normalizes list of ranges by joining intersecting or "touching" ranges.
|
|
1165
|
+
*
|
|
1166
|
+
* Note: It assumes that ranges are sorted.
|
|
1167
|
+
*/
|
|
1168
|
+
function normalizeRanges(ranges) {
|
|
1169
|
+
for (let i = 1; i < ranges.length; i++) {
|
|
1170
|
+
const joinedRange = ranges[i - 1].getJoined(ranges[i]);
|
|
1171
|
+
if (joinedRange) ranges.splice(--i, 2, joinedRange);
|
|
1172
|
+
}
|
|
1173
|
+
return ranges;
|
|
1282
1174
|
}
|
|
1283
1175
|
|
|
1284
1176
|
/**
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1177
|
+
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
|
|
1178
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
1179
|
+
*/
|
|
1180
|
+
/**
|
|
1181
|
+
* @module style/styleediting
|
|
1182
|
+
*/
|
|
1183
|
+
/**
|
|
1184
|
+
* The style engine feature.
|
|
1185
|
+
*
|
|
1186
|
+
* It configures the {@glink features/html/general-html-support General HTML Support feature} based on
|
|
1187
|
+
* {@link module:style/styleconfig~StyleConfig#definitions configured style definitions} and introduces the
|
|
1188
|
+
* {@link module:style/stylecommand~StyleCommand style command} that applies styles to the content of the document.
|
|
1189
|
+
*/
|
|
1190
|
+
var StyleEditing = class extends Plugin {
|
|
1191
|
+
/**
|
|
1192
|
+
* @inheritDoc
|
|
1193
|
+
*/
|
|
1194
|
+
static get pluginName() {
|
|
1195
|
+
return "StyleEditing";
|
|
1196
|
+
}
|
|
1197
|
+
/**
|
|
1198
|
+
* @inheritDoc
|
|
1199
|
+
*/
|
|
1200
|
+
static get isOfficialPlugin() {
|
|
1201
|
+
return true;
|
|
1202
|
+
}
|
|
1203
|
+
/**
|
|
1204
|
+
* @inheritDoc
|
|
1205
|
+
*/
|
|
1206
|
+
static get requires() {
|
|
1207
|
+
return [
|
|
1208
|
+
GeneralHtmlSupport,
|
|
1209
|
+
StyleUtils,
|
|
1210
|
+
ListStyleSupport,
|
|
1211
|
+
TableStyleSupport,
|
|
1212
|
+
LinkStyleSupport
|
|
1213
|
+
];
|
|
1214
|
+
}
|
|
1215
|
+
/**
|
|
1216
|
+
* @inheritDoc
|
|
1217
|
+
*/
|
|
1218
|
+
init() {
|
|
1219
|
+
const editor = this.editor;
|
|
1220
|
+
const dataSchema = editor.plugins.get("DataSchema");
|
|
1221
|
+
const styleUtils = editor.plugins.get("StyleUtils");
|
|
1222
|
+
const styleDefinitions = editor.config.get("style.definitions");
|
|
1223
|
+
const normalizedStyleDefinitions = styleUtils.normalizeConfig(dataSchema, styleDefinitions);
|
|
1224
|
+
editor.commands.add("style", new StyleCommand(editor, normalizedStyleDefinitions));
|
|
1225
|
+
styleUtils.configureGHSDataFilter(normalizedStyleDefinitions);
|
|
1226
|
+
}
|
|
1227
|
+
};
|
|
1324
1228
|
|
|
1325
1229
|
/**
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1230
|
+
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
|
|
1231
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
1232
|
+
*/
|
|
1233
|
+
/**
|
|
1234
|
+
* @module style/style
|
|
1235
|
+
*/
|
|
1236
|
+
/**
|
|
1237
|
+
* The style plugin.
|
|
1238
|
+
*
|
|
1239
|
+
* This is a "glue" plugin that loads the {@link module:style/styleediting~StyleEditing style editing feature}
|
|
1240
|
+
* and {@link module:style/styleui~StyleUI style UI feature}.
|
|
1241
|
+
*/
|
|
1242
|
+
var Style = class extends Plugin {
|
|
1243
|
+
/**
|
|
1244
|
+
* @inheritDoc
|
|
1245
|
+
*/
|
|
1246
|
+
static get pluginName() {
|
|
1247
|
+
return "Style";
|
|
1248
|
+
}
|
|
1249
|
+
/**
|
|
1250
|
+
* @inheritDoc
|
|
1251
|
+
*/
|
|
1252
|
+
static get isOfficialPlugin() {
|
|
1253
|
+
return true;
|
|
1254
|
+
}
|
|
1255
|
+
/**
|
|
1256
|
+
* @inheritDoc
|
|
1257
|
+
*/
|
|
1258
|
+
static get requires() {
|
|
1259
|
+
return [StyleEditing, StyleUI];
|
|
1260
|
+
}
|
|
1261
|
+
};
|
|
1262
|
+
|
|
1263
|
+
/**
|
|
1264
|
+
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
|
|
1265
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
1266
|
+
*/
|
|
1350
1267
|
|
|
1351
1268
|
export { LinkStyleSupport, ListStyleSupport, Style, StyleCommand, StyleEditing, StyleUI, StyleUtils, TableStyleSupport, StyleGridButtonView as _StyleGridButtonView, StyleGridView as _StyleGridView, StyleGroupView as _StyleGroupView, StylePanelView as _StylePanelView };
|
|
1352
|
-
//# sourceMappingURL=index.js.map
|
|
1269
|
+
//# sourceMappingURL=index.js.map
|