@ckeditor/ckeditor5-minimap 0.0.0-internal-20241017.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.
@@ -0,0 +1,65 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ /**
6
+ * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
7
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
8
+ */
9
+ /**
10
+ * @module minimap/utils
11
+ */
12
+ import { Rect } from 'ckeditor5/src/utils.js';
13
+ import type { Editor } from 'ckeditor5/src/core.js';
14
+ /**
15
+ * Clones the editing view DOM root by using a dedicated pair of {@link module:engine/view/renderer~Renderer} and
16
+ * {@link module:engine/view/domconverter~DomConverter}. The DOM root clone updates incrementally to stay in sync with the
17
+ * source root.
18
+ *
19
+ * @internal
20
+ * @param editor The editor instance the original editing root belongs to.
21
+ * @param rootName The name of the root to clone.
22
+ * @returns The editing root DOM clone element.
23
+ */
24
+ export declare function cloneEditingViewDomRoot(editor: Editor, rootName?: string): HTMLElement;
25
+ /**
26
+ * Harvests all web page styles, for instance, to allow re-using them in an `<iframe>` preserving the look of the content.
27
+ *
28
+ * The returned data format is as follows:
29
+ *
30
+ * ```ts
31
+ * [
32
+ * 'p { color: red; ... } h2 { font-size: 2em; ... } ...',
33
+ * '.spacing { padding: 1em; ... }; ...',
34
+ * '...',
35
+ * { href: 'http://link.to.external.stylesheet' },
36
+ * { href: '...' }
37
+ * ]
38
+ * ```
39
+ *
40
+ * **Note**: For stylesheets with `href` different than window origin, an object is returned because
41
+ * accessing rules of these styles may cause CORS errors (depending on the configuration of the web page).
42
+ *
43
+ * @internal
44
+ */
45
+ export declare function getPageStyles(): Array<string | {
46
+ href: string;
47
+ }>;
48
+ /**
49
+ * Gets dimensions rectangle according to passed DOM element. Returns whole window's size for `body` element.
50
+ *
51
+ * @internal
52
+ */
53
+ export declare function getDomElementRect(domElement: HTMLElement): Rect;
54
+ /**
55
+ * Gets client height according to passed DOM element. Returns window's height for `body` element.
56
+ *
57
+ * @internal
58
+ */
59
+ export declare function getClientHeight(domElement: HTMLElement): number;
60
+ /**
61
+ * Returns the DOM element itself if it's not a `body` element, whole window otherwise.
62
+ *
63
+ * @internal
64
+ */
65
+ export declare function getScrollable(domElement: HTMLElement): Window | HTMLElement;
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@ckeditor/ckeditor5-minimap",
3
+ "version": "0.0.0-internal-20241017.0",
4
+ "description": "Content minimap feature for CKEditor 5.",
5
+ "keywords": [
6
+ "ckeditor",
7
+ "ckeditor5",
8
+ "ckeditor 5",
9
+ "ckeditor5-feature",
10
+ "ckeditor5-plugin",
11
+ "ckeditor5-dll"
12
+ ],
13
+ "type": "module",
14
+ "main": "src/index.js",
15
+ "dependencies": {
16
+ "@ckeditor/ckeditor5-core": "0.0.0-internal-20241017.0",
17
+ "@ckeditor/ckeditor5-engine": "0.0.0-internal-20241017.0",
18
+ "@ckeditor/ckeditor5-ui": "0.0.0-internal-20241017.0",
19
+ "@ckeditor/ckeditor5-utils": "0.0.0-internal-20241017.0",
20
+ "ckeditor5": "0.0.0-internal-20241017.0"
21
+ },
22
+ "author": "CKSource (http://cksource.com/)",
23
+ "license": "GPL-2.0-or-later",
24
+ "homepage": "https://ckeditor.com/ckeditor-5",
25
+ "bugs": "https://github.com/ckeditor/ckeditor5/issues",
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "https://github.com/ckeditor/ckeditor5.git",
29
+ "directory": "packages/ckeditor5-minimap"
30
+ },
31
+ "files": [
32
+ "dist",
33
+ "lang",
34
+ "src/**/*.js",
35
+ "src/**/*.d.ts",
36
+ "theme",
37
+ "build",
38
+ "ckeditor5-metadata.json",
39
+ "CHANGELOG.md"
40
+ ],
41
+ "types": "src/index.d.ts"
42
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ import type { MinimapConfig, Minimap } from './index.js';
6
+ declare module '@ckeditor/ckeditor5-core' {
7
+ interface EditorConfig {
8
+ /**
9
+ * The configuration of the minimap feature. Introduced by the {@link module:minimap/minimap~Minimap} feature.
10
+ *
11
+ * Read more in {@link module:minimap/minimapconfig~MinimapConfig}.
12
+ */
13
+ minimap?: MinimapConfig;
14
+ }
15
+ interface PluginsMap {
16
+ [Minimap.pluginName]: Minimap;
17
+ }
18
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ export {};
package/src/index.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ /**
6
+ * @module minimap
7
+ */
8
+ export { default as Minimap } from './minimap.js';
9
+ export type { MinimapConfig } from './minimapconfig.js';
10
+ import './augmentation.js';
package/src/index.js ADDED
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ /**
6
+ * @module minimap
7
+ */
8
+ export { default as Minimap } from './minimap.js';
9
+ import './augmentation.js';
@@ -0,0 +1,58 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ /**
6
+ * @module minimap/minimap
7
+ */
8
+ import { Plugin } from 'ckeditor5/src/core.js';
9
+ import '../theme/minimap.css';
10
+ /**
11
+ * The content minimap feature.
12
+ */
13
+ export default class Minimap extends Plugin {
14
+ /**
15
+ * @inheritDoc
16
+ */
17
+ static get pluginName(): "Minimap";
18
+ /**
19
+ * @inheritDoc
20
+ */
21
+ static get isOfficialPlugin(): true;
22
+ /**
23
+ * The reference to the view of the minimap.
24
+ */
25
+ private _minimapView;
26
+ /**
27
+ * The DOM element closest to the editable element of the editor as returned
28
+ * by {@link module:ui/editorui/editorui~EditorUI#getEditableElement}.
29
+ */
30
+ private _scrollableRootAncestor;
31
+ /**
32
+ * The DOM element closest to the editable element of the editor as returned
33
+ * by {@link module:ui/editorui/editorui~EditorUI#getEditableElement}.
34
+ */
35
+ private _editingRootElement?;
36
+ /**
37
+ * @inheritDoc
38
+ */
39
+ init(): void;
40
+ /**
41
+ * @inheritDoc
42
+ */
43
+ destroy(): void;
44
+ /**
45
+ * Initializes the minimap view element and starts the layout synchronization
46
+ * on the editing view `render` event.
47
+ */
48
+ private _onUiReady;
49
+ /**
50
+ * Initializes the minimap view and attaches listeners that make it responsive to the environment (document)
51
+ * but also allow the minimap to control the document (scroll position).
52
+ */
53
+ private _initializeMinimapView;
54
+ /**
55
+ * @private
56
+ */
57
+ private _syncMinimapToEditingRootScrollPosition;
58
+ }
package/src/minimap.js ADDED
@@ -0,0 +1,164 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ /**
6
+ * @module minimap/minimap
7
+ */
8
+ import { Plugin } from 'ckeditor5/src/core.js';
9
+ import { findClosestScrollableAncestor, global } from 'ckeditor5/src/utils.js';
10
+ import MinimapView from './minimapview.js';
11
+ import { cloneEditingViewDomRoot, getClientHeight, getDomElementRect, getPageStyles, getScrollable } from './utils.js';
12
+ // @if CK_DEBUG_MINIMAP // const RectDrawer = require( '@ckeditor/ckeditor5-utils/tests/_utils/rectdrawer' ).default;
13
+ import '../theme/minimap.css';
14
+ /**
15
+ * The content minimap feature.
16
+ */
17
+ export default class Minimap extends Plugin {
18
+ /**
19
+ * @inheritDoc
20
+ */
21
+ static get pluginName() {
22
+ return 'Minimap';
23
+ }
24
+ /**
25
+ * @inheritDoc
26
+ */
27
+ static get isOfficialPlugin() {
28
+ return true;
29
+ }
30
+ /**
31
+ * @inheritDoc
32
+ */
33
+ init() {
34
+ const editor = this.editor;
35
+ this._minimapView = null;
36
+ this._scrollableRootAncestor = null;
37
+ this.listenTo(editor.ui, 'ready', this._onUiReady.bind(this));
38
+ }
39
+ /**
40
+ * @inheritDoc
41
+ */
42
+ destroy() {
43
+ super.destroy();
44
+ this._minimapView.destroy();
45
+ this._minimapView.element.remove();
46
+ }
47
+ /**
48
+ * Initializes the minimap view element and starts the layout synchronization
49
+ * on the editing view `render` event.
50
+ */
51
+ _onUiReady() {
52
+ const editor = this.editor;
53
+ // TODO: This will not work with the multi-root editor.
54
+ const editingRootElement = this._editingRootElement = editor.ui.getEditableElement();
55
+ this._scrollableRootAncestor = findClosestScrollableAncestor(editingRootElement);
56
+ // DOM root element is not yet attached to the document.
57
+ if (!editingRootElement.ownerDocument.body.contains(editingRootElement)) {
58
+ editor.ui.once('update', this._onUiReady.bind(this));
59
+ return;
60
+ }
61
+ this._initializeMinimapView();
62
+ this.listenTo(editor.editing.view, 'render', () => {
63
+ if (editor.state !== 'ready') {
64
+ return;
65
+ }
66
+ this._syncMinimapToEditingRootScrollPosition();
67
+ });
68
+ this._syncMinimapToEditingRootScrollPosition();
69
+ }
70
+ /**
71
+ * Initializes the minimap view and attaches listeners that make it responsive to the environment (document)
72
+ * but also allow the minimap to control the document (scroll position).
73
+ */
74
+ _initializeMinimapView() {
75
+ const editor = this.editor;
76
+ const locale = editor.locale;
77
+ const useSimplePreview = editor.config.get('minimap.useSimplePreview');
78
+ // TODO: Throw an error if there is no `minimap` in config.
79
+ const minimapContainerElement = editor.config.get('minimap.container');
80
+ const scrollableRootAncestor = this._scrollableRootAncestor;
81
+ // TODO: This should be dynamic, the root width could change as the viewport scales if not fixed unit.
82
+ const editingRootElementWidth = getDomElementRect(this._editingRootElement).width;
83
+ const minimapContainerWidth = getDomElementRect(minimapContainerElement).width;
84
+ const minimapScaleRatio = minimapContainerWidth / editingRootElementWidth;
85
+ const minimapView = this._minimapView = new MinimapView({
86
+ locale,
87
+ scaleRatio: minimapScaleRatio,
88
+ pageStyles: getPageStyles(),
89
+ extraClasses: editor.config.get('minimap.extraClasses'),
90
+ useSimplePreview,
91
+ domRootClone: cloneEditingViewDomRoot(editor)
92
+ });
93
+ minimapView.render();
94
+ // Scrollable ancestor scroll -> minimap position update.
95
+ minimapView.listenTo(global.document, 'scroll', (evt, data) => {
96
+ if (scrollableRootAncestor === global.document.body) {
97
+ if (data.target !== global.document) {
98
+ return;
99
+ }
100
+ }
101
+ else if (data.target !== scrollableRootAncestor) {
102
+ return;
103
+ }
104
+ this._syncMinimapToEditingRootScrollPosition();
105
+ }, { useCapture: true, usePassive: true });
106
+ // Viewport resize -> minimap position update.
107
+ minimapView.listenTo(global.window, 'resize', () => {
108
+ this._syncMinimapToEditingRootScrollPosition();
109
+ });
110
+ // Dragging the visible content area -> document (scrollable) position update.
111
+ minimapView.on('drag', (evt, movementY) => {
112
+ let movementYPercentage;
113
+ if (minimapView.scrollHeight === 0) {
114
+ movementYPercentage = 0;
115
+ }
116
+ else {
117
+ movementYPercentage = movementY / minimapView.scrollHeight;
118
+ }
119
+ const absoluteScrollProgress = movementYPercentage *
120
+ (scrollableRootAncestor.scrollHeight - getClientHeight(scrollableRootAncestor));
121
+ const scrollable = getScrollable(scrollableRootAncestor);
122
+ scrollable.scrollBy(0, Math.round(absoluteScrollProgress));
123
+ });
124
+ // Clicking the minimap -> center the document (scrollable) to the corresponding position.
125
+ minimapView.on('click', (evt, percentage) => {
126
+ const absoluteScrollProgress = percentage * scrollableRootAncestor.scrollHeight;
127
+ const scrollable = getScrollable(scrollableRootAncestor);
128
+ scrollable.scrollBy(0, Math.round(absoluteScrollProgress));
129
+ });
130
+ minimapContainerElement.appendChild(minimapView.element);
131
+ }
132
+ /**
133
+ * @private
134
+ */
135
+ _syncMinimapToEditingRootScrollPosition() {
136
+ const editingRootElement = this._editingRootElement;
137
+ const minimapView = this._minimapView;
138
+ minimapView.setContentHeight(editingRootElement.offsetHeight);
139
+ const editingRootRect = getDomElementRect(editingRootElement);
140
+ const scrollableRootAncestorRect = getDomElementRect(this._scrollableRootAncestor);
141
+ let scrollProgress;
142
+ // @if CK_DEBUG_MINIMAP // RectDrawer.clear();
143
+ // @if CK_DEBUG_MINIMAP // RectDrawer.draw( scrollableRootAncestorRect, { outlineColor: 'red' }, 'scrollableRootAncestor' );
144
+ // @if CK_DEBUG_MINIMAP // RectDrawer.draw( editingRootRect, { outlineColor: 'green' }, 'editingRoot' );
145
+ // The root is completely visible in the scrollable ancestor.
146
+ if (scrollableRootAncestorRect.contains(editingRootRect)) {
147
+ scrollProgress = 0;
148
+ }
149
+ else {
150
+ if (editingRootRect.top > scrollableRootAncestorRect.top) {
151
+ scrollProgress = 0;
152
+ }
153
+ else {
154
+ scrollProgress = (editingRootRect.top - scrollableRootAncestorRect.top) /
155
+ (scrollableRootAncestorRect.height - editingRootRect.height);
156
+ scrollProgress = Math.max(0, Math.min(scrollProgress, 1));
157
+ }
158
+ }
159
+ // The intersection helps to change the tracker height when there is a lot of padding around the root.
160
+ // Note: It is **essential** that the height is set first because the progress depends on the correct tracker height.
161
+ minimapView.setPositionTrackerHeight(scrollableRootAncestorRect.getIntersection(editingRootRect).height);
162
+ minimapView.setScrollProgress(scrollProgress);
163
+ }
164
+ }
@@ -0,0 +1,85 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ /**
6
+ * @module minimap/minimapconfig
7
+ */
8
+ /**
9
+ * The configuration of the {@link module:minimap/minimap~Minimap} feature.
10
+ *
11
+ * ```ts
12
+ * ClassicEditor
13
+ * .create( {
14
+ * minimap: ... // Minimap feature config.
15
+ * } )
16
+ * .then( ... )
17
+ * .catch( ... );
18
+ * ```
19
+ *
20
+ * See {@link module:core/editor/editorconfig~EditorConfig all editor options}.
21
+ */
22
+ export interface MinimapConfig {
23
+ /**
24
+ * The DOM element container for the minimap.
25
+ *
26
+ * **Note**: The container must have a fixed `width` and `overflow: hidden` for the minimap to work correctly.
27
+ */
28
+ container: HTMLElement;
29
+ /**
30
+ * When set to `true`, the minimap will render content as simple boxes instead of replicating the look of the content (default).
31
+ */
32
+ useSimplePreview?: boolean;
33
+ /**
34
+ * Extra CSS class (or classes) that will be set internally on the `<body>` element of the `<iframe>` enclosing the minimap.
35
+ *
36
+ * By default, the minimap feature will attempt to clone all website styles and re-apply them in the `<iframe>` for the best accuracy.
37
+ * However, this may not work if the content of your editor inherits the styles from parent containers, resulting in inconsistent
38
+ * look and imprecise scrolling of the minimap.
39
+ *
40
+ * This optional configuration can address these issues by ensuring the same CSS rules apply to the content of the minimap
41
+ * and the original content of the editor.
42
+ *
43
+ * For instance, consider the following DOM structure:
44
+ *
45
+ * ```html
46
+ * <div class="website">
47
+ * <!-- ... -->
48
+ * <div class="styled-container">
49
+ * <!-- ... -->
50
+ * <div id="editor">
51
+ * <!-- content of the editor -->
52
+ * </div>
53
+ * </div>
54
+ * <!-- ... -->
55
+ * </div>
56
+ * ```
57
+ *
58
+ * and the following CSS styles:
59
+ *
60
+ * ```css
61
+ * .website p {
62
+ * font-size: 13px;
63
+ * }
64
+ *
65
+ * .styled-container p {
66
+ * color: #ccc;
67
+ * }
68
+ * ```
69
+ *
70
+ * To maintain the consistency of styling (`font-size` and `color` of paragraphs), you will need to pass the CSS class names
71
+ * of these containers:
72
+ *
73
+ * ```ts
74
+ * ClassicEditor
75
+ * .create( document.getElementById( 'editor' ), {
76
+ * minimap: {
77
+ * extraClasses: 'website styled-container'
78
+ * }
79
+ * } )
80
+ * .then( ... )
81
+ * .catch( ... );
82
+ * ```
83
+ */
84
+ extraClasses?: string;
85
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ export {};
@@ -0,0 +1,54 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ /**
6
+ * @module minimap/minimapiframeview
7
+ */
8
+ import { IframeView } from 'ckeditor5/src/ui.js';
9
+ import { type Locale } from 'ckeditor5/src/utils.js';
10
+ import type { MinimapViewOptions } from './minimapview.js';
11
+ /**
12
+ * The internal `<iframe>` view that hosts the minimap content.
13
+ *
14
+ * @internal
15
+ */
16
+ export default class MinimapIframeView extends IframeView {
17
+ /**
18
+ * The CSS `top` used to scroll the minimap.
19
+ *
20
+ * @readonly
21
+ */
22
+ top: number;
23
+ /**
24
+ * The CSS `height` of the iframe.
25
+ *
26
+ * @readonly
27
+ */
28
+ height: number;
29
+ /**
30
+ * Cached view constructor options for re-use in other methods.
31
+ */
32
+ private readonly _options;
33
+ /**
34
+ * Creates an instance of the internal minimap iframe.
35
+ */
36
+ constructor(locale: Locale, options: MinimapViewOptions);
37
+ /**
38
+ * @inheritDoc
39
+ */
40
+ render(): Promise<unknown>;
41
+ /**
42
+ * Sets the new height of the iframe.
43
+ */
44
+ setHeight(newHeight: number): void;
45
+ /**
46
+ * Sets the top offset of the iframe to move it around vertically.
47
+ */
48
+ setTopOffset(newOffset: number): void;
49
+ /**
50
+ * Sets the internal structure of the `<iframe>` readying it to display the
51
+ * minimap element.
52
+ */
53
+ private _prepareDocument;
54
+ }
@@ -0,0 +1,132 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ /**
6
+ * @module minimap/minimapiframeview
7
+ */
8
+ import { IframeView } from 'ckeditor5/src/ui.js';
9
+ import { toUnit } from 'ckeditor5/src/utils.js';
10
+ const toPx = /* #__PURE__ */ toUnit('px');
11
+ /**
12
+ * The internal `<iframe>` view that hosts the minimap content.
13
+ *
14
+ * @internal
15
+ */
16
+ export default class MinimapIframeView extends IframeView {
17
+ /**
18
+ * Creates an instance of the internal minimap iframe.
19
+ */
20
+ constructor(locale, options) {
21
+ super(locale);
22
+ const bind = this.bindTemplate;
23
+ this.set('top', 0);
24
+ this.set('height', 0);
25
+ this._options = options;
26
+ this.extendTemplate({
27
+ attributes: {
28
+ tabindex: -1,
29
+ 'aria-hidden': 'true',
30
+ class: [
31
+ 'ck-minimap__iframe'
32
+ ],
33
+ style: {
34
+ top: bind.to('top', top => toPx(top)),
35
+ height: bind.to('height', height => toPx(height))
36
+ }
37
+ }
38
+ });
39
+ }
40
+ /**
41
+ * @inheritDoc
42
+ */
43
+ render() {
44
+ return super.render().then(() => {
45
+ this._prepareDocument();
46
+ });
47
+ }
48
+ /**
49
+ * Sets the new height of the iframe.
50
+ */
51
+ setHeight(newHeight) {
52
+ this.height = newHeight;
53
+ }
54
+ /**
55
+ * Sets the top offset of the iframe to move it around vertically.
56
+ */
57
+ setTopOffset(newOffset) {
58
+ this.top = newOffset;
59
+ }
60
+ /**
61
+ * Sets the internal structure of the `<iframe>` readying it to display the
62
+ * minimap element.
63
+ */
64
+ _prepareDocument() {
65
+ const iframeDocument = this.element.contentWindow.document;
66
+ const domRootClone = iframeDocument.adoptNode(this._options.domRootClone);
67
+ const boxStyles = this._options.useSimplePreview ? `
68
+ .ck.ck-editor__editable_inline img {
69
+ filter: contrast( 0 );
70
+ }
71
+
72
+ p, li, a, figcaption, span {
73
+ background: hsl(0, 0%, 80%) !important;
74
+ color: hsl(0, 0%, 80%) !important;
75
+ }
76
+
77
+ h1, h2, h3, h4 {
78
+ background: hsl(0, 0%, 60%) !important;
79
+ color: hsl(0, 0%, 60%) !important;
80
+ }
81
+ ` : '';
82
+ const pageStyles = this._options.pageStyles.map(definition => {
83
+ if (typeof definition === 'string') {
84
+ return `<style>${definition}</style>`;
85
+ }
86
+ else {
87
+ return `<link rel="stylesheet" type="text/css" href="${definition.href}">`;
88
+ }
89
+ }).join('\n');
90
+ const html = `<!DOCTYPE html><html lang="en">
91
+ <head>
92
+ <meta charset="utf-8">
93
+ <meta name="viewport" content="width=device-width, initial-scale=1">
94
+ ${pageStyles}
95
+ <style>
96
+ html, body {
97
+ margin: 0 !important;
98
+ padding: 0 !important;
99
+ }
100
+
101
+ html {
102
+ overflow: hidden;
103
+ }
104
+
105
+ body {
106
+ transform: scale( ${this._options.scaleRatio} );
107
+ transform-origin: 0 0;
108
+ overflow: visible;
109
+ }
110
+
111
+ .ck.ck-editor__editable_inline {
112
+ margin: 0 !important;
113
+ border-color: transparent !important;
114
+ outline-color: transparent !important;
115
+ box-shadow: none !important;
116
+ }
117
+
118
+ .ck.ck-content {
119
+ background: white;
120
+ }
121
+
122
+ ${boxStyles}
123
+ </style>
124
+ </head>
125
+ <body class="${this._options.extraClasses || ''}"></body>
126
+ </html>`;
127
+ iframeDocument.open();
128
+ iframeDocument.write(html);
129
+ iframeDocument.close();
130
+ iframeDocument.body.appendChild(domRootClone);
131
+ }
132
+ }