@ckeditor/ckeditor5-paste-from-office 46.0.2 → 46.1.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/build/paste-from-office.js +1 -1
- package/dist/index.js +63 -0
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
- package/src/filters/replacetabswithinprewithspaces.d.ts +24 -0
- package/src/filters/replacetabswithinprewithspaces.js +63 -0
- package/src/normalizers/googledocsnormalizer.js +2 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ckeditor/ckeditor5-paste-from-office",
|
|
3
|
-
"version": "46.0.
|
|
3
|
+
"version": "46.1.0-alpha.0",
|
|
4
4
|
"description": "Paste from Office feature for CKEditor 5.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ckeditor",
|
|
@@ -13,10 +13,10 @@
|
|
|
13
13
|
"type": "module",
|
|
14
14
|
"main": "src/index.js",
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@ckeditor/ckeditor5-clipboard": "46.0.
|
|
17
|
-
"@ckeditor/ckeditor5-core": "46.0.
|
|
18
|
-
"@ckeditor/ckeditor5-engine": "46.0.
|
|
19
|
-
"ckeditor5": "46.0.
|
|
16
|
+
"@ckeditor/ckeditor5-clipboard": "46.1.0-alpha.0",
|
|
17
|
+
"@ckeditor/ckeditor5-core": "46.1.0-alpha.0",
|
|
18
|
+
"@ckeditor/ckeditor5-engine": "46.1.0-alpha.0",
|
|
19
|
+
"ckeditor5": "46.1.0-alpha.0"
|
|
20
20
|
},
|
|
21
21
|
"author": "CKSource (http://cksource.com/)",
|
|
22
22
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* @module paste-from-office/filters/replacetabswithinprewithspaces
|
|
7
|
+
*/
|
|
8
|
+
import type { ViewDocumentFragment, ViewUpcastWriter } from 'ckeditor5/src/engine.js';
|
|
9
|
+
/**
|
|
10
|
+
* Replaces tab characters with spaces in text nodes that are inside elements styled with `white-space: pre-wrap`.
|
|
11
|
+
*
|
|
12
|
+
* This is a workaround for incorrect detection of pre-like formatting in the DOM converter for pasted Google Docs documents.
|
|
13
|
+
* When an element uses `white-space: pre-wrap`, the editor reduces tab characters to a single space, causing
|
|
14
|
+
* inconsistent spacing in pasted content. This function replaces tabs with spaces to ensure visual consistency.
|
|
15
|
+
* This is intended as a temporary solution.
|
|
16
|
+
*
|
|
17
|
+
* See: https://github.com/ckeditor/ckeditor5/issues/18995
|
|
18
|
+
*
|
|
19
|
+
* @param documentFragment The `data.content` element obtained from the clipboard.
|
|
20
|
+
* @param writer The upcast writer used to manipulate the view structure.
|
|
21
|
+
* @param tabWidth The number of spaces to replace each tab with. Defaults to 8.
|
|
22
|
+
* @internal
|
|
23
|
+
*/
|
|
24
|
+
export declare function replaceTabsWithinPreWithSpaces(documentFragment: ViewDocumentFragment, writer: ViewUpcastWriter, tabWidth: number): void;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Replaces tab characters with spaces in text nodes that are inside elements styled with `white-space: pre-wrap`.
|
|
7
|
+
*
|
|
8
|
+
* This is a workaround for incorrect detection of pre-like formatting in the DOM converter for pasted Google Docs documents.
|
|
9
|
+
* When an element uses `white-space: pre-wrap`, the editor reduces tab characters to a single space, causing
|
|
10
|
+
* inconsistent spacing in pasted content. This function replaces tabs with spaces to ensure visual consistency.
|
|
11
|
+
* This is intended as a temporary solution.
|
|
12
|
+
*
|
|
13
|
+
* See: https://github.com/ckeditor/ckeditor5/issues/18995
|
|
14
|
+
*
|
|
15
|
+
* @param documentFragment The `data.content` element obtained from the clipboard.
|
|
16
|
+
* @param writer The upcast writer used to manipulate the view structure.
|
|
17
|
+
* @param tabWidth The number of spaces to replace each tab with. Defaults to 8.
|
|
18
|
+
* @internal
|
|
19
|
+
*/
|
|
20
|
+
export function replaceTabsWithinPreWithSpaces(documentFragment, writer, tabWidth) {
|
|
21
|
+
// Collect all text nodes with tabs that are inside pre-wrap elements.
|
|
22
|
+
const textNodesToReplace = new Set();
|
|
23
|
+
for (const child of writer.createRangeIn(documentFragment).getItems()) {
|
|
24
|
+
if (!child.is('view:$textProxy') || !child.data.includes('\t')) {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
// Check if any parent has `white-space: pre-wrap`.
|
|
28
|
+
if (hasPreWrapParent(child.parent)) {
|
|
29
|
+
textNodesToReplace.add(child.textNode);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// Replace tabs in each collected text node.
|
|
33
|
+
for (const textNode of textNodesToReplace) {
|
|
34
|
+
replaceTabsInTextNode(textNode, writer, tabWidth);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Checks if element or any of its parents has `white-space: pre-wrap` style.
|
|
39
|
+
*/
|
|
40
|
+
function hasPreWrapParent(element) {
|
|
41
|
+
let parent = element;
|
|
42
|
+
while (parent) {
|
|
43
|
+
if (parent.is('element')) {
|
|
44
|
+
const whiteSpace = parent.getStyle?.('white-space');
|
|
45
|
+
if (whiteSpace === 'pre-wrap') {
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
parent = parent.parent;
|
|
50
|
+
}
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Replaces all tabs with spaces in the given text node.
|
|
55
|
+
*/
|
|
56
|
+
function replaceTabsInTextNode(textNode, writer, tabWidth) {
|
|
57
|
+
const { parent, data } = textNode;
|
|
58
|
+
const replacedData = data.replaceAll('\t', ' '.repeat(tabWidth));
|
|
59
|
+
const index = parent.getChildIndex(textNode);
|
|
60
|
+
// Remove old node and insert new one with replaced tabs.
|
|
61
|
+
writer.remove(textNode);
|
|
62
|
+
writer.insertChild(index, writer.createText(replacedData), parent);
|
|
63
|
+
}
|
|
@@ -9,6 +9,7 @@ import { ViewUpcastWriter } from 'ckeditor5/src/engine.js';
|
|
|
9
9
|
import { removeBoldWrapper } from '../filters/removeboldwrapper.js';
|
|
10
10
|
import { transformBlockBrsToParagraphs } from '../filters/br.js';
|
|
11
11
|
import { unwrapParagraphInListItem } from '../filters/list.js';
|
|
12
|
+
import { replaceTabsWithinPreWithSpaces } from '../filters/replacetabswithinprewithspaces.js';
|
|
12
13
|
const googleDocsMatch = /id=("|')docs-internal-guid-[-0-9a-f]+("|')/i;
|
|
13
14
|
/**
|
|
14
15
|
* Normalizer for the content pasted from Google Docs.
|
|
@@ -40,6 +41,7 @@ export class GoogleDocsNormalizer {
|
|
|
40
41
|
removeBoldWrapper(documentFragment, writer);
|
|
41
42
|
unwrapParagraphInListItem(documentFragment, writer);
|
|
42
43
|
transformBlockBrsToParagraphs(documentFragment, writer);
|
|
44
|
+
replaceTabsWithinPreWithSpaces(documentFragment, writer, 8);
|
|
43
45
|
data.content = documentFragment;
|
|
44
46
|
}
|
|
45
47
|
}
|