@ckeditor/ckeditor5-minimap 48.2.0 → 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 +16 -16
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +12 -12
- package/dist/index.js +505 -490
- package/dist/index.js.map +1 -1
- package/dist/minimap.d.ts +53 -53
- package/dist/minimapconfig.d.ts +81 -81
- package/dist/minimapiframeview.d.ts +49 -49
- package/dist/minimappositiontrackerview.d.ts +53 -53
- package/dist/minimapview.d.ts +100 -100
- package/dist/utils.d.ts +48 -48
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -2,66 +2,76 @@
|
|
|
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 { Plugin } from
|
|
6
|
-
import {
|
|
7
|
-
import { IframeView, View } from
|
|
8
|
-
import { ViewDomConverter, ViewRenderer } from
|
|
5
|
+
import { Plugin } from "@ckeditor/ckeditor5-core";
|
|
6
|
+
import { Rect, findClosestScrollableAncestor, global, toUnit } from "@ckeditor/ckeditor5-utils";
|
|
7
|
+
import { IframeView, View } from "@ckeditor/ckeditor5-ui";
|
|
8
|
+
import { ViewDomConverter, ViewRenderer } from "@ckeditor/ckeditor5-engine";
|
|
9
9
|
|
|
10
|
-
const toPx$1 = /* #__PURE__ */ toUnit('px');
|
|
11
10
|
/**
|
|
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
|
-
|
|
11
|
+
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
|
|
12
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* @module minimap/minimapiframeview
|
|
16
|
+
*/
|
|
17
|
+
const toPx$1 = /* #__PURE__ */ toUnit("px");
|
|
18
|
+
/**
|
|
19
|
+
* The internal `<iframe>` view that hosts the minimap content.
|
|
20
|
+
*
|
|
21
|
+
* @internal
|
|
22
|
+
*/
|
|
23
|
+
var MinimapIframeView = class extends IframeView {
|
|
24
|
+
/**
|
|
25
|
+
* Cached view constructor options for re-use in other methods.
|
|
26
|
+
*/
|
|
27
|
+
_options;
|
|
28
|
+
/**
|
|
29
|
+
* Creates an instance of the internal minimap iframe.
|
|
30
|
+
*/
|
|
31
|
+
constructor(locale, options) {
|
|
32
|
+
super(locale);
|
|
33
|
+
const bind = this.bindTemplate;
|
|
34
|
+
this.set("top", 0);
|
|
35
|
+
this.set("height", 0);
|
|
36
|
+
this._options = options;
|
|
37
|
+
this.extendTemplate({ attributes: {
|
|
38
|
+
tabindex: -1,
|
|
39
|
+
"aria-hidden": "true",
|
|
40
|
+
class: ["ck-minimap__iframe"],
|
|
41
|
+
style: {
|
|
42
|
+
top: bind.to("top", (top) => toPx$1(top)),
|
|
43
|
+
height: bind.to("height", (height) => toPx$1(height))
|
|
44
|
+
}
|
|
45
|
+
} });
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* @inheritDoc
|
|
49
|
+
*/
|
|
50
|
+
render() {
|
|
51
|
+
return super.render().then(() => {
|
|
52
|
+
this._prepareDocument();
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Sets the new height of the iframe.
|
|
57
|
+
*/
|
|
58
|
+
setHeight(newHeight) {
|
|
59
|
+
this.height = newHeight;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Sets the top offset of the iframe to move it around vertically.
|
|
63
|
+
*/
|
|
64
|
+
setTopOffset(newOffset) {
|
|
65
|
+
this.top = newOffset;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Sets the internal structure of the `<iframe>` readying it to display the
|
|
69
|
+
* minimap element.
|
|
70
|
+
*/
|
|
71
|
+
_prepareDocument() {
|
|
72
|
+
const iframeDocument = this.element.contentWindow.document;
|
|
73
|
+
const domRootClone = iframeDocument.adoptNode(this._options.domRootClone);
|
|
74
|
+
const boxStyles = this._options.useSimplePreview ? `
|
|
65
75
|
.ck.ck-editor__editable_inline img {
|
|
66
76
|
filter: contrast( 0 );
|
|
67
77
|
}
|
|
@@ -75,19 +85,15 @@ const toPx$1 = /* #__PURE__ */ toUnit('px');
|
|
|
75
85
|
background: hsl(0, 0%, 60%) !important;
|
|
76
86
|
color: hsl(0, 0%, 60%) !important;
|
|
77
87
|
}
|
|
78
|
-
` :
|
|
79
|
-
|
|
80
|
-
if (typeof definition === 'string') {
|
|
81
|
-
return `<style>${definition}</style>`;
|
|
82
|
-
} else {
|
|
83
|
-
return `<link rel="stylesheet" type="text/css" href="${definition.href}">`;
|
|
84
|
-
}
|
|
85
|
-
}).join('\n');
|
|
86
|
-
const html = `<!DOCTYPE html><html lang="en">
|
|
88
|
+
` : "";
|
|
89
|
+
const html = `<!DOCTYPE html><html lang="en">
|
|
87
90
|
<head>
|
|
88
91
|
<meta charset="utf-8">
|
|
89
92
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
90
|
-
${pageStyles
|
|
93
|
+
${this._options.pageStyles.map((definition) => {
|
|
94
|
+
if (typeof definition === "string") return `<style>${definition}</style>`;
|
|
95
|
+
else return `<link rel="stylesheet" type="text/css" href="${definition.href}">`;
|
|
96
|
+
}).join("\n")}
|
|
91
97
|
<style>
|
|
92
98
|
html, body {
|
|
93
99
|
margin: 0 !important;
|
|
@@ -118,445 +124,454 @@ const toPx$1 = /* #__PURE__ */ toUnit('px');
|
|
|
118
124
|
${boxStyles}
|
|
119
125
|
</style>
|
|
120
126
|
</head>
|
|
121
|
-
<body class="${this._options.extraClasses ||
|
|
127
|
+
<body class="${this._options.extraClasses || ""}"></body>
|
|
122
128
|
</html>`;
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
+
iframeDocument.open();
|
|
130
|
+
iframeDocument.write(html);
|
|
131
|
+
iframeDocument.close();
|
|
132
|
+
iframeDocument.body.appendChild(domRootClone);
|
|
133
|
+
}
|
|
134
|
+
};
|
|
129
135
|
|
|
130
|
-
const toPx = /* #__PURE__ */ toUnit('px');
|
|
131
136
|
/**
|
|
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
|
-
|
|
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
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
137
|
+
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
|
|
138
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
139
|
+
*/
|
|
140
|
+
/**
|
|
141
|
+
* @module minimap/minimappositiontrackerview
|
|
142
|
+
*/
|
|
143
|
+
const toPx = /* #__PURE__ */ toUnit("px");
|
|
144
|
+
/**
|
|
145
|
+
* The position tracker visualizing the visible subset of the content. Displayed over the minimap.
|
|
146
|
+
*
|
|
147
|
+
* @internal
|
|
148
|
+
*/
|
|
149
|
+
var MinimapPositionTrackerView = class extends View {
|
|
150
|
+
constructor(locale) {
|
|
151
|
+
super(locale);
|
|
152
|
+
const bind = this.bindTemplate;
|
|
153
|
+
this.set("height", 0);
|
|
154
|
+
this.set("top", 0);
|
|
155
|
+
this.set("scrollProgress", 0);
|
|
156
|
+
this.set("_isDragging", false);
|
|
157
|
+
this.setTemplate({
|
|
158
|
+
tag: "div",
|
|
159
|
+
attributes: {
|
|
160
|
+
class: [
|
|
161
|
+
"ck",
|
|
162
|
+
"ck-minimap__position-tracker",
|
|
163
|
+
bind.if("_isDragging", "ck-minimap__position-tracker_dragging")
|
|
164
|
+
],
|
|
165
|
+
style: {
|
|
166
|
+
top: bind.to("top", (top) => toPx(top)),
|
|
167
|
+
height: bind.to("height", (height) => toPx(height))
|
|
168
|
+
},
|
|
169
|
+
"data-progress": bind.to("scrollProgress")
|
|
170
|
+
},
|
|
171
|
+
on: { mousedown: bind.to(() => {
|
|
172
|
+
this._isDragging = true;
|
|
173
|
+
}) }
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* @inheritDoc
|
|
178
|
+
*/
|
|
179
|
+
render() {
|
|
180
|
+
super.render();
|
|
181
|
+
this.listenTo(global.document, "mousemove", (evt, data) => {
|
|
182
|
+
if (!this._isDragging) return;
|
|
183
|
+
this.fire("drag", data.movementY);
|
|
184
|
+
}, { useCapture: true });
|
|
185
|
+
this.listenTo(global.document, "mouseup", () => {
|
|
186
|
+
this._isDragging = false;
|
|
187
|
+
}, { useCapture: true });
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Sets the new height of the tracker to visualize the subset of the content visible to the user.
|
|
191
|
+
*/
|
|
192
|
+
setHeight(newHeight) {
|
|
193
|
+
this.height = newHeight;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Sets the top offset of the tracker to move it around vertically.
|
|
197
|
+
*/
|
|
198
|
+
setTopOffset(newOffset) {
|
|
199
|
+
this.top = newOffset;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Sets the scroll progress (in %) to inform the user using a label when the tracker is being dragged.
|
|
203
|
+
*/
|
|
204
|
+
setScrollProgress(newProgress) {
|
|
205
|
+
this.scrollProgress = newProgress;
|
|
206
|
+
}
|
|
207
|
+
};
|
|
198
208
|
|
|
199
209
|
/**
|
|
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
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
210
|
+
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
|
|
211
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
212
|
+
*/
|
|
213
|
+
/**
|
|
214
|
+
* @module minimap/minimapview
|
|
215
|
+
*/
|
|
216
|
+
/**
|
|
217
|
+
* The main view of the minimap. It renders the original content but scaled down with a tracker element
|
|
218
|
+
* visualizing the subset of the content visible to the user and allowing interactions (scrolling, dragging).
|
|
219
|
+
*
|
|
220
|
+
* @internal
|
|
221
|
+
*/
|
|
222
|
+
var MinimapView = class extends View {
|
|
223
|
+
/**
|
|
224
|
+
* An instance of the tracker view displayed over the minimap.
|
|
225
|
+
*/
|
|
226
|
+
_positionTrackerView;
|
|
227
|
+
/**
|
|
228
|
+
* The scale ratio of the minimap relative to the original editing DOM root with the content.
|
|
229
|
+
*/
|
|
230
|
+
_scaleRatio;
|
|
231
|
+
/**
|
|
232
|
+
* An instance of the iframe view that hosts the minimap.
|
|
233
|
+
*/
|
|
234
|
+
_minimapIframeView;
|
|
235
|
+
/**
|
|
236
|
+
* Creates an instance of the minimap view.
|
|
237
|
+
*/
|
|
238
|
+
constructor({ locale, scaleRatio, pageStyles, extraClasses, useSimplePreview, domRootClone }) {
|
|
239
|
+
super(locale);
|
|
240
|
+
const bind = this.bindTemplate;
|
|
241
|
+
this._positionTrackerView = new MinimapPositionTrackerView(locale);
|
|
242
|
+
this._positionTrackerView.delegate("drag").to(this);
|
|
243
|
+
this._scaleRatio = scaleRatio;
|
|
244
|
+
this._minimapIframeView = new MinimapIframeView(locale, {
|
|
245
|
+
useSimplePreview,
|
|
246
|
+
pageStyles,
|
|
247
|
+
extraClasses,
|
|
248
|
+
scaleRatio,
|
|
249
|
+
domRootClone
|
|
250
|
+
});
|
|
251
|
+
this.setTemplate({
|
|
252
|
+
tag: "div",
|
|
253
|
+
attributes: { class: ["ck", "ck-minimap"] },
|
|
254
|
+
children: [this._positionTrackerView],
|
|
255
|
+
on: {
|
|
256
|
+
click: bind.to(this._handleMinimapClick.bind(this)),
|
|
257
|
+
wheel: bind.to(this._handleMinimapMouseWheel.bind(this))
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* @inheritDoc
|
|
263
|
+
*/
|
|
264
|
+
destroy() {
|
|
265
|
+
this._minimapIframeView.destroy();
|
|
266
|
+
super.destroy();
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Returns the DOM {@link module:utils/dom/rect~Rect} height of the minimap.
|
|
270
|
+
*/
|
|
271
|
+
get height() {
|
|
272
|
+
return new Rect(this.element).height;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Returns the number of available space (pixels) the position tracker (visible subset of the content) can use to scroll vertically.
|
|
276
|
+
*/
|
|
277
|
+
get scrollHeight() {
|
|
278
|
+
return Math.max(0, Math.min(this.height, this._minimapIframeView.height) - this._positionTrackerView.height);
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* @inheritDoc
|
|
282
|
+
*/
|
|
283
|
+
render() {
|
|
284
|
+
super.render();
|
|
285
|
+
this._minimapIframeView.render();
|
|
286
|
+
this.element.appendChild(this._minimapIframeView.element);
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Sets the new height of the minimap (in px) to respond to the changes in the original editing DOM root.
|
|
290
|
+
*
|
|
291
|
+
* **Note**:The provided value should be the `offsetHeight` of the original editing DOM root.
|
|
292
|
+
*/
|
|
293
|
+
setContentHeight(newHeight) {
|
|
294
|
+
this._minimapIframeView.setHeight(newHeight * this._scaleRatio);
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Sets the minimap scroll progress.
|
|
298
|
+
*
|
|
299
|
+
* The minimap scroll progress is linked to the original editing DOM root and its scrollable container (ancestor).
|
|
300
|
+
* Changing the progress will alter the vertical position of the minimap (and its position tracker) and give the user an accurate
|
|
301
|
+
* overview of the visible document.
|
|
302
|
+
*
|
|
303
|
+
* **Note**: The value should be between 0 and 1. 0 when the DOM root has not been scrolled, 1 when the
|
|
304
|
+
* scrolling has reached the end.
|
|
305
|
+
*/
|
|
306
|
+
setScrollProgress(newScrollProgress) {
|
|
307
|
+
const iframeView = this._minimapIframeView;
|
|
308
|
+
const positionTrackerView = this._positionTrackerView;
|
|
309
|
+
if (iframeView.height < this.height) {
|
|
310
|
+
iframeView.setTopOffset(0);
|
|
311
|
+
positionTrackerView.setTopOffset((iframeView.height - positionTrackerView.height) * newScrollProgress);
|
|
312
|
+
} else {
|
|
313
|
+
const totalOffset = iframeView.height - this.height;
|
|
314
|
+
iframeView.setTopOffset(-totalOffset * newScrollProgress);
|
|
315
|
+
positionTrackerView.setTopOffset((this.height - positionTrackerView.height) * newScrollProgress);
|
|
316
|
+
}
|
|
317
|
+
positionTrackerView.setScrollProgress(Math.round(newScrollProgress * 100));
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Sets the new height of the tracker (in px) to visualize the subset of the content visible to the user.
|
|
321
|
+
*/
|
|
322
|
+
setPositionTrackerHeight(trackerHeight) {
|
|
323
|
+
this._positionTrackerView.setHeight(trackerHeight * this._scaleRatio);
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* @param data DOM event data
|
|
327
|
+
*/
|
|
328
|
+
_handleMinimapClick(data) {
|
|
329
|
+
const positionTrackerView = this._positionTrackerView;
|
|
330
|
+
if (data.target === positionTrackerView.element) return;
|
|
331
|
+
const trackerViewRect = new Rect(positionTrackerView.element);
|
|
332
|
+
const percentage = (data.clientY - trackerViewRect.top - trackerViewRect.height / 2) / this._minimapIframeView.height;
|
|
333
|
+
this.fire("click", percentage);
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* @param data DOM event data
|
|
337
|
+
*/
|
|
338
|
+
_handleMinimapMouseWheel(data) {
|
|
339
|
+
this.fire("drag", data.deltaY * this._scaleRatio);
|
|
340
|
+
}
|
|
341
|
+
};
|
|
322
342
|
|
|
323
343
|
/**
|
|
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
|
-
|
|
344
|
+
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
|
|
345
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
346
|
+
*/
|
|
347
|
+
/**
|
|
348
|
+
* @module minimap/utils
|
|
349
|
+
*/
|
|
350
|
+
/**
|
|
351
|
+
* Clones the editing view DOM root by using a dedicated pair of {@link module:engine/view/renderer~ViewRenderer} and
|
|
352
|
+
* {@link module:engine/view/domconverter~ViewDomConverter}. The DOM root clone updates incrementally to stay in sync with the
|
|
353
|
+
* source root.
|
|
354
|
+
*
|
|
355
|
+
* @internal
|
|
356
|
+
* @param editor The editor instance the original editing root belongs to.
|
|
357
|
+
* @param rootName The name of the root to clone.
|
|
358
|
+
* @returns The editing root DOM clone element.
|
|
359
|
+
*/
|
|
360
|
+
function cloneEditingViewDomRoot(editor, rootName) {
|
|
361
|
+
const viewDocument = editor.editing.view.document;
|
|
362
|
+
const viewRoot = viewDocument.getRoot(rootName);
|
|
363
|
+
const domConverter = new ViewDomConverter(viewDocument);
|
|
364
|
+
const renderer = new ViewRenderer(domConverter, viewDocument.selection);
|
|
365
|
+
const domRootClone = editor.editing.view.getDomRoot().cloneNode();
|
|
366
|
+
domConverter.bindElements(domRootClone, viewRoot);
|
|
367
|
+
renderer.markToSync("children", viewRoot);
|
|
368
|
+
renderer.markToSync("attributes", viewRoot);
|
|
369
|
+
viewRoot.on("change:children", (evt, node) => renderer.markToSync("children", node));
|
|
370
|
+
viewRoot.on("change:attributes", (evt, node) => renderer.markToSync("attributes", node));
|
|
371
|
+
viewRoot.on("change:text", (evt, node) => renderer.markToSync("text", node));
|
|
372
|
+
renderer.render();
|
|
373
|
+
editor.editing.view.on("render", () => renderer.render());
|
|
374
|
+
editor.on("destroy", () => {
|
|
375
|
+
domConverter.unbindDomElement(domRootClone);
|
|
376
|
+
});
|
|
377
|
+
return domRootClone;
|
|
351
378
|
}
|
|
352
379
|
/**
|
|
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
|
-
return Array.from(styleSheet.cssRules).filter((rule)=>!(rule instanceof CSSMediaRule)).map((rule)=>rule.cssText).join(' \n');
|
|
380
|
-
});
|
|
380
|
+
* Harvests all web page styles, for instance, to allow re-using them in an `<iframe>` preserving the look of the content.
|
|
381
|
+
*
|
|
382
|
+
* The returned data format is as follows:
|
|
383
|
+
*
|
|
384
|
+
* ```ts
|
|
385
|
+
* [
|
|
386
|
+
* 'p { color: red; ... } h2 { font-size: 2em; ... } ...',
|
|
387
|
+
* '.spacing { padding: 1em; ... }; ...',
|
|
388
|
+
* '...',
|
|
389
|
+
* { href: 'http://link.to.external.stylesheet' },
|
|
390
|
+
* { href: '...' }
|
|
391
|
+
* ]
|
|
392
|
+
* ```
|
|
393
|
+
*
|
|
394
|
+
* **Note**: For stylesheets with `href` different than window origin, an object is returned because
|
|
395
|
+
* accessing rules of these styles may cause CORS errors (depending on the configuration of the web page).
|
|
396
|
+
*
|
|
397
|
+
* @internal
|
|
398
|
+
*/
|
|
399
|
+
function getPageStyles() {
|
|
400
|
+
return Array.from(global.document.styleSheets).map((styleSheet) => {
|
|
401
|
+
if (styleSheet.href && !styleSheet.href.startsWith(global.window.location.origin)) return { href: styleSheet.href };
|
|
402
|
+
return Array.from(styleSheet.cssRules).filter((rule) => !(rule instanceof CSSMediaRule)).map((rule) => rule.cssText).join(" \n");
|
|
403
|
+
});
|
|
381
404
|
}
|
|
382
405
|
/**
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
406
|
+
* Gets dimensions rectangle according to passed DOM element. Returns whole window's size for `body` element.
|
|
407
|
+
*
|
|
408
|
+
* @internal
|
|
409
|
+
*/
|
|
410
|
+
function getDomElementRect(domElement) {
|
|
411
|
+
return new Rect(domElement === global.document.body ? global.window : domElement);
|
|
388
412
|
}
|
|
389
413
|
/**
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
414
|
+
* Gets client height according to passed DOM element. Returns window's height for `body` element.
|
|
415
|
+
*
|
|
416
|
+
* @internal
|
|
417
|
+
*/
|
|
418
|
+
function getClientHeight(domElement) {
|
|
419
|
+
return domElement === global.document.body ? global.window.innerHeight : domElement.clientHeight;
|
|
395
420
|
}
|
|
396
421
|
/**
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
422
|
+
* Returns the DOM element itself if it's not a `body` element, whole window otherwise.
|
|
423
|
+
*
|
|
424
|
+
* @internal
|
|
425
|
+
*/
|
|
426
|
+
function getScrollable(domElement) {
|
|
427
|
+
return domElement === global.document.body ? global.window : domElement;
|
|
402
428
|
}
|
|
403
429
|
|
|
404
430
|
/**
|
|
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
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
} else {
|
|
550
|
-
scrollProgress = (editingRootRect.top - scrollableRootAncestorRect.top) / (scrollableRootAncestorRect.height - editingRootRect.height);
|
|
551
|
-
scrollProgress = Math.max(0, Math.min(scrollProgress, 1));
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
// The intersection helps to change the tracker height when there is a lot of padding around the root.
|
|
555
|
-
// Note: It is **essential** that the height is set first because the progress depends on the correct tracker height.
|
|
556
|
-
minimapView.setPositionTrackerHeight(scrollableRootAncestorRect.getIntersection(editingRootRect).height);
|
|
557
|
-
minimapView.setScrollProgress(scrollProgress);
|
|
558
|
-
}
|
|
559
|
-
}
|
|
431
|
+
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
|
|
432
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
433
|
+
*/
|
|
434
|
+
/**
|
|
435
|
+
* @module minimap/minimap
|
|
436
|
+
*/
|
|
437
|
+
/**
|
|
438
|
+
* The content minimap feature.
|
|
439
|
+
*/
|
|
440
|
+
var Minimap = class extends Plugin {
|
|
441
|
+
/**
|
|
442
|
+
* @inheritDoc
|
|
443
|
+
*/
|
|
444
|
+
static get pluginName() {
|
|
445
|
+
return "Minimap";
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* @inheritDoc
|
|
449
|
+
*/
|
|
450
|
+
static get isOfficialPlugin() {
|
|
451
|
+
return true;
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
* The reference to the view of the minimap.
|
|
455
|
+
*/
|
|
456
|
+
_minimapView;
|
|
457
|
+
/**
|
|
458
|
+
* The DOM element closest to the editable element of the editor as returned
|
|
459
|
+
* by {@link module:ui/editorui/editorui~EditorUI#getEditableElement}.
|
|
460
|
+
*/
|
|
461
|
+
_scrollableRootAncestor;
|
|
462
|
+
/**
|
|
463
|
+
* The DOM element closest to the editable element of the editor as returned
|
|
464
|
+
* by {@link module:ui/editorui/editorui~EditorUI#getEditableElement}.
|
|
465
|
+
*/
|
|
466
|
+
_editingRootElement;
|
|
467
|
+
/**
|
|
468
|
+
* @inheritDoc
|
|
469
|
+
*/
|
|
470
|
+
init() {
|
|
471
|
+
const editor = this.editor;
|
|
472
|
+
this._minimapView = null;
|
|
473
|
+
this._scrollableRootAncestor = null;
|
|
474
|
+
this.listenTo(editor.ui, "ready", this._onUiReady.bind(this));
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* @inheritDoc
|
|
478
|
+
*/
|
|
479
|
+
destroy() {
|
|
480
|
+
super.destroy();
|
|
481
|
+
this._minimapView.destroy();
|
|
482
|
+
this._minimapView.element.remove();
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* Initializes the minimap view element and starts the layout synchronization
|
|
486
|
+
* on the editing view `render` event.
|
|
487
|
+
*/
|
|
488
|
+
_onUiReady() {
|
|
489
|
+
const editor = this.editor;
|
|
490
|
+
const editingRootElement = this._editingRootElement = editor.ui.getEditableElement();
|
|
491
|
+
this._scrollableRootAncestor = findClosestScrollableAncestor(editingRootElement);
|
|
492
|
+
if (!editingRootElement.ownerDocument.body.contains(editingRootElement)) {
|
|
493
|
+
editor.ui.once("update", this._onUiReady.bind(this));
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
this._initializeMinimapView();
|
|
497
|
+
this.listenTo(editor.editing.view, "render", () => {
|
|
498
|
+
if (editor.state !== "ready") return;
|
|
499
|
+
this._syncMinimapToEditingRootScrollPosition();
|
|
500
|
+
});
|
|
501
|
+
this._syncMinimapToEditingRootScrollPosition();
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* Initializes the minimap view and attaches listeners that make it responsive to the environment (document)
|
|
505
|
+
* but also allow the minimap to control the document (scroll position).
|
|
506
|
+
*/
|
|
507
|
+
_initializeMinimapView() {
|
|
508
|
+
const editor = this.editor;
|
|
509
|
+
const locale = editor.locale;
|
|
510
|
+
const useSimplePreview = editor.config.get("minimap.useSimplePreview");
|
|
511
|
+
const minimapContainerElement = editor.config.get("minimap.container");
|
|
512
|
+
const scrollableRootAncestor = this._scrollableRootAncestor;
|
|
513
|
+
const editingRootElementWidth = getDomElementRect(this._editingRootElement).width;
|
|
514
|
+
const minimapScaleRatio = getDomElementRect(minimapContainerElement).width / editingRootElementWidth;
|
|
515
|
+
const minimapView = this._minimapView = new MinimapView({
|
|
516
|
+
locale,
|
|
517
|
+
scaleRatio: minimapScaleRatio,
|
|
518
|
+
pageStyles: getPageStyles(),
|
|
519
|
+
extraClasses: editor.config.get("minimap.extraClasses"),
|
|
520
|
+
useSimplePreview,
|
|
521
|
+
domRootClone: cloneEditingViewDomRoot(editor)
|
|
522
|
+
});
|
|
523
|
+
minimapView.render();
|
|
524
|
+
minimapView.listenTo(global.document, "scroll", (evt, data) => {
|
|
525
|
+
if (scrollableRootAncestor === global.document.body) {
|
|
526
|
+
if (data.target !== global.document) return;
|
|
527
|
+
} else if (data.target !== scrollableRootAncestor) return;
|
|
528
|
+
this._syncMinimapToEditingRootScrollPosition();
|
|
529
|
+
}, {
|
|
530
|
+
useCapture: true,
|
|
531
|
+
usePassive: true
|
|
532
|
+
});
|
|
533
|
+
minimapView.listenTo(global.window, "resize", () => {
|
|
534
|
+
this._syncMinimapToEditingRootScrollPosition();
|
|
535
|
+
});
|
|
536
|
+
minimapView.on("drag", (evt, movementY) => {
|
|
537
|
+
let movementYPercentage;
|
|
538
|
+
if (minimapView.scrollHeight === 0) movementYPercentage = 0;
|
|
539
|
+
else movementYPercentage = movementY / minimapView.scrollHeight;
|
|
540
|
+
const absoluteScrollProgress = movementYPercentage * (scrollableRootAncestor.scrollHeight - getClientHeight(scrollableRootAncestor));
|
|
541
|
+
getScrollable(scrollableRootAncestor).scrollBy(0, Math.round(absoluteScrollProgress));
|
|
542
|
+
});
|
|
543
|
+
minimapView.on("click", (evt, percentage) => {
|
|
544
|
+
const absoluteScrollProgress = percentage * scrollableRootAncestor.scrollHeight;
|
|
545
|
+
getScrollable(scrollableRootAncestor).scrollBy(0, Math.round(absoluteScrollProgress));
|
|
546
|
+
});
|
|
547
|
+
minimapContainerElement.appendChild(minimapView.element);
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* @private
|
|
551
|
+
*/
|
|
552
|
+
_syncMinimapToEditingRootScrollPosition() {
|
|
553
|
+
const editingRootElement = this._editingRootElement;
|
|
554
|
+
const minimapView = this._minimapView;
|
|
555
|
+
minimapView.setContentHeight(editingRootElement.offsetHeight);
|
|
556
|
+
const editingRootRect = getDomElementRect(editingRootElement);
|
|
557
|
+
const scrollableRootAncestorRect = getDomElementRect(this._scrollableRootAncestor);
|
|
558
|
+
let scrollProgress;
|
|
559
|
+
if (!scrollableRootAncestorRect.getIntersection(editingRootRect)) return;
|
|
560
|
+
if (scrollableRootAncestorRect.contains(editingRootRect)) scrollProgress = 0;
|
|
561
|
+
else if (editingRootRect.top > scrollableRootAncestorRect.top) scrollProgress = 0;
|
|
562
|
+
else {
|
|
563
|
+
scrollProgress = (editingRootRect.top - scrollableRootAncestorRect.top) / (scrollableRootAncestorRect.height - editingRootRect.height);
|
|
564
|
+
scrollProgress = Math.max(0, Math.min(scrollProgress, 1));
|
|
565
|
+
}
|
|
566
|
+
minimapView.setPositionTrackerHeight(scrollableRootAncestorRect.getIntersection(editingRootRect).height);
|
|
567
|
+
minimapView.setScrollProgress(scrollProgress);
|
|
568
|
+
}
|
|
569
|
+
};
|
|
570
|
+
|
|
571
|
+
/**
|
|
572
|
+
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
|
|
573
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
574
|
+
*/
|
|
560
575
|
|
|
561
576
|
export { Minimap, MinimapIframeView as _MinimapIframeView, MinimapPositionTrackerView as _MinimapPositionTrackerView, MinimapView as _MinimapView, cloneEditingViewDomRoot as _cloneMinimapEditingViewDomRoot, getClientHeight as _getMinimapClientHeight, getDomElementRect as _getMinimapDomElementRect, getPageStyles as _getMinimapPageStyles, getScrollable as _getMinimapScrollable };
|
|
562
|
-
//# sourceMappingURL=index.js.map
|
|
577
|
+
//# sourceMappingURL=index.js.map
|