@ckeditor/ckeditor5-paste-from-office 47.6.1 → 48.0.0-alpha.1

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.
Files changed (53) hide show
  1. package/ckeditor5-metadata.json +1 -1
  2. package/{src → dist}/filters/bookmark.d.ts +1 -1
  3. package/{src → dist}/filters/br.d.ts +1 -1
  4. package/{src → dist}/filters/image.d.ts +1 -1
  5. package/{src → dist}/filters/list.d.ts +1 -1
  6. package/{src → dist}/filters/parse.d.ts +1 -1
  7. package/{src → dist}/filters/removeboldwrapper.d.ts +1 -1
  8. package/{src → dist}/filters/removegooglesheetstag.d.ts +1 -1
  9. package/{src → dist}/filters/removeinvalidtablewidth.d.ts +1 -1
  10. package/{src → dist}/filters/removemsattributes.d.ts +1 -1
  11. package/{src → dist}/filters/removestyleblock.d.ts +1 -1
  12. package/{src → dist}/filters/removexmlns.d.ts +1 -1
  13. package/{src → dist}/filters/replacemsfootnotes.d.ts +1 -1
  14. package/{src → dist}/filters/replacetabswithinprewithspaces.d.ts +1 -1
  15. package/{src → dist}/filters/table.d.ts +2 -2
  16. package/dist/index.css +3 -0
  17. package/dist/index.css.map +1 -0
  18. package/dist/index.js +5 -8
  19. package/dist/index.js.map +1 -1
  20. package/{src → dist}/normalizer.d.ts +1 -1
  21. package/{src → dist}/normalizers/googledocsnormalizer.d.ts +1 -1
  22. package/{src → dist}/normalizers/googlesheetsnormalizer.d.ts +1 -1
  23. package/{src → dist}/normalizers/mswordnormalizer.d.ts +2 -3
  24. package/{src → dist}/pastefromoffice.d.ts +2 -2
  25. package/package.json +21 -43
  26. package/build/paste-from-office.js +0 -4
  27. package/src/augmentation.js +0 -5
  28. package/src/filters/bookmark.js +0 -25
  29. package/src/filters/br.js +0 -66
  30. package/src/filters/image.js +0 -263
  31. package/src/filters/list.js +0 -504
  32. package/src/filters/parse.js +0 -95
  33. package/src/filters/removeboldwrapper.js +0 -19
  34. package/src/filters/removegooglesheetstag.js +0 -19
  35. package/src/filters/removeinvalidtablewidth.js +0 -24
  36. package/src/filters/removemsattributes.js +0 -44
  37. package/src/filters/removestyleblock.js +0 -17
  38. package/src/filters/removexmlns.js +0 -17
  39. package/src/filters/replacemsfootnotes.js +0 -209
  40. package/src/filters/replacetabswithinprewithspaces.js +0 -63
  41. package/src/filters/space.js +0 -63
  42. package/src/filters/table.js +0 -77
  43. package/src/filters/utils.js +0 -52
  44. package/src/index.js +0 -26
  45. package/src/normalizer.js +0 -5
  46. package/src/normalizers/googledocsnormalizer.js +0 -47
  47. package/src/normalizers/googlesheetsnormalizer.js +0 -47
  48. package/src/normalizers/mswordnormalizer.js +0 -58
  49. package/src/pastefromoffice.js +0 -92
  50. /package/{src → dist}/augmentation.d.ts +0 -0
  51. /package/{src → dist}/filters/space.d.ts +0 -0
  52. /package/{src → dist}/filters/utils.d.ts +0 -0
  53. /package/{src → dist}/index.d.ts +0 -0
@@ -5,7 +5,7 @@
5
5
  /**
6
6
  * @module paste-from-office/normalizer
7
7
  */
8
- import type { ClipboardInputTransformationData } from 'ckeditor5/src/clipboard.js';
8
+ import type { ClipboardInputTransformationData } from '@ckeditor/ckeditor5-clipboard';
9
9
  import type { PasteOfficeHtmlParseResult } from './filters/parse.js';
10
10
  /**
11
11
  * Interface defining a content transformation pasted from an external editor.
@@ -5,7 +5,7 @@
5
5
  /**
6
6
  * @module paste-from-office/normalizers/googledocsnormalizer
7
7
  */
8
- import { type ViewDocument } from 'ckeditor5/src/engine.js';
8
+ import { type ViewDocument } from '@ckeditor/ckeditor5-engine';
9
9
  import type { PasteFromOfficeNormalizer, PasteFromOfficeNormalizerData } from '../normalizer.js';
10
10
  /**
11
11
  * Normalizer for the content pasted from Google Docs.
@@ -5,7 +5,7 @@
5
5
  /**
6
6
  * @module paste-from-office/normalizers/googlesheetsnormalizer
7
7
  */
8
- import { type ViewDocument } from 'ckeditor5/src/engine.js';
8
+ import { type ViewDocument } from '@ckeditor/ckeditor5-engine';
9
9
  import type { PasteFromOfficeNormalizer, PasteFromOfficeNormalizerData } from '../normalizer.js';
10
10
  /**
11
11
  * Normalizer for the content pasted from Google Sheets.
@@ -2,7 +2,7 @@
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 { type ViewDocument } from 'ckeditor5/src/engine.js';
5
+ import { type ViewDocument } from '@ckeditor/ckeditor5-engine';
6
6
  import type { PasteFromOfficeNormalizer, PasteFromOfficeNormalizerData } from '../normalizer.js';
7
7
  /**
8
8
  * Normalizer for the content pasted from Microsoft Word.
@@ -11,13 +11,12 @@ export declare class PasteFromOfficeMSWordNormalizer implements PasteFromOfficeN
11
11
  readonly document: ViewDocument;
12
12
  readonly hasMultiLevelListPlugin: boolean;
13
13
  readonly hasTablePropertiesPlugin: boolean;
14
- readonly hasExtendedTableBlockAlignment: boolean;
15
14
  /**
16
15
  * Creates a new `PasteFromOfficeMSWordNormalizer` instance.
17
16
  *
18
17
  * @param document View document.
19
18
  */
20
- constructor(document: ViewDocument, hasMultiLevelListPlugin?: boolean, hasTablePropertiesPlugin?: boolean, hasExtendedTableBlockAlignment?: boolean);
19
+ constructor(document: ViewDocument, hasMultiLevelListPlugin?: boolean, hasTablePropertiesPlugin?: boolean);
21
20
  /**
22
21
  * @inheritDoc
23
22
  */
@@ -5,8 +5,8 @@
5
5
  /**
6
6
  * @module paste-from-office/pastefromoffice
7
7
  */
8
- import { Plugin } from 'ckeditor5/src/core.js';
9
- import { ClipboardPipeline } from 'ckeditor5/src/clipboard.js';
8
+ import { Plugin } from '@ckeditor/ckeditor5-core';
9
+ import { ClipboardPipeline } from '@ckeditor/ckeditor5-clipboard';
10
10
  /**
11
11
  * The Paste from Office plugin.
12
12
  *
package/package.json CHANGED
@@ -1,61 +1,39 @@
1
1
  {
2
2
  "name": "@ckeditor/ckeditor5-paste-from-office",
3
- "version": "47.6.1",
3
+ "version": "48.0.0-alpha.1",
4
4
  "description": "Paste from Office feature for CKEditor 5.",
5
+ "license": "SEE LICENSE IN LICENSE.md",
6
+ "author": "CKSource (http://cksource.com/)",
7
+ "homepage": "https://ckeditor.com/ckeditor-5",
8
+ "bugs": "https://github.com/ckeditor/ckeditor5/issues",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://github.com/ckeditor/ckeditor5.git",
12
+ "directory": "packages/ckeditor5-paste-from-office"
13
+ },
5
14
  "keywords": [
6
15
  "ckeditor",
7
16
  "ckeditor5",
8
17
  "ckeditor 5",
9
18
  "ckeditor5-feature",
10
- "ckeditor5-plugin",
11
- "ckeditor5-dll"
19
+ "ckeditor5-plugin"
12
20
  ],
13
21
  "type": "module",
14
- "main": "src/index.js",
15
- "dependencies": {
16
- "@ckeditor/ckeditor5-clipboard": "47.6.1",
17
- "@ckeditor/ckeditor5-core": "47.6.1",
18
- "@ckeditor/ckeditor5-engine": "47.6.1",
19
- "ckeditor5": "47.6.1"
22
+ "main": "./dist/index.js",
23
+ "exports": {
24
+ ".": "./dist/index.js",
25
+ "./dist/*": "./dist/*",
26
+ "./package.json": "./package.json"
20
27
  },
21
- "author": "CKSource (http://cksource.com/)",
22
- "license": "SEE LICENSE IN LICENSE.md",
23
- "homepage": "https://ckeditor.com/ckeditor-5",
24
- "bugs": "https://github.com/ckeditor/ckeditor5/issues",
25
- "repository": {
26
- "type": "git",
27
- "url": "https://github.com/ckeditor/ckeditor5.git",
28
- "directory": "packages/ckeditor5-paste-from-office"
28
+ "dependencies": {
29
+ "@ckeditor/ckeditor5-clipboard": "48.0.0-alpha.1",
30
+ "@ckeditor/ckeditor5-core": "48.0.0-alpha.1",
31
+ "@ckeditor/ckeditor5-engine": "48.0.0-alpha.1"
29
32
  },
30
33
  "files": [
31
34
  "dist",
32
- "lang",
33
- "src/**/*.js",
34
- "src/**/*.d.ts",
35
- "theme",
36
- "build",
37
35
  "ckeditor5-metadata.json",
38
36
  "CHANGELOG.md"
39
37
  ],
40
- "types": "src/index.d.ts",
41
- "exports": {
42
- ".": {
43
- "types": "./src/index.d.ts",
44
- "import": "./src/index.js",
45
- "default": "./src/index.js"
46
- },
47
- "./dist/*": {
48
- "types": "./src/index.d.ts",
49
- "import": "./dist/*",
50
- "default": "./dist/*"
51
- },
52
- "./src/*": {
53
- "types": "./src/*.d.ts",
54
- "import": "./src/*",
55
- "default": "./src/*"
56
- },
57
- "./build/*": "./build/*",
58
- "./ckeditor5-metadata.json": "./ckeditor5-metadata.json",
59
- "./package.json": "./package.json"
60
- }
38
+ "types": "./dist/index.d.ts"
61
39
  }
@@ -1,4 +0,0 @@
1
- /*!
2
- * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
3
- * For licensing, see LICENSE.md.
4
- */(()=>{var e={237:e=>{"use strict";e.exports=CKEditor5.dll},331:(e,t,n)=>{e.exports=n(237)("./src/clipboard.js")},782:(e,t,n)=>{e.exports=n(237)("./src/core.js")},783:(e,t,n)=>{e.exports=n(237)("./src/engine.js")}},t={};function n(i){var s=t[i];if(void 0!==s)return s.exports;var r=t[i]={exports:{}};return e[i](r,r.exports,n),r.exports}n.d=(e,t)=>{for(var i in t)n.o(t,i)&&!n.o(e,i)&&Object.defineProperty(e,i,{enumerable:!0,get:t[i]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var i={};(()=>{"use strict";n.r(i),n.d(i,{PasteFromOffice:()=>J,PasteFromOfficeGoogleDocsNormalizer:()=>D,PasteFromOfficeGoogleSheetsNormalizer:()=>q,PasteFromOfficeMSWordNormalizer:()=>_,_convertHexToBase64:()=>C,_convertPasteOfficeCssLengthToPx:()=>o,_isPasteOfficePxValue:()=>l,_normalizePasteOfficeSpaceRunSpans:()=>G,_normalizePasteOfficeSpacing:()=>H,_removePasteGoogleOfficeSheetsTag:()=>N,_removePasteMSOfficeAttributes:()=>A,_removePasteOfficeBoldWrapper:()=>$,_removePasteOfficeInvalidTableWidths:()=>I,_removePasteOfficeStyleBlock:()=>z,_removePasteOfficeXmlnsAttributes:()=>V,_replacePasteOfficeImagesSourceWithBase64:()=>w,_toPasteOfficePxValue:()=>a,_transformPasteOfficeBlockBrsToParagraphs:()=>R,_transformPasteOfficeBookmarks:()=>s,_transformPasteOfficeListItemLikeElementsIntoLists:()=>c,_transformPasteOfficeTables:()=>P,_unwrapPasteOfficeParagraphInListItem:()=>d,parsePasteOfficeHtml:()=>X});var e=n(782),t=n(331);function s(e,t){const n=[];for(const i of t.createRangeIn(e)){const e=i.item;e.is("element","a")&&!e.hasAttribute("href")&&(e.hasAttribute("id")||e.hasAttribute("name"))&&n.push(e)}for(const e of n){const n=e.parent.getChildIndex(e)+1,i=e.getChildren();t.insertChild(n,i,e.parent)}}var r=n(783);function o(e){const t=parseFloat(e);return e.endsWith("pt")?a(96*t/72):e.endsWith("pc")?a(12*t*96/72):e.endsWith("in")?a(96*t):e.endsWith("cm")?a(96*t/2.54):e.endsWith("mm")?a(t/10*96/2.54):e}function l(e){return void 0!==e&&e.endsWith("px")}function a(e){return Math.round(e)+"px"}function c(e,t,n){if(!e.childCount)return;const i=new r.ViewUpcastWriter(e.document),s=function(e,t){const n=t.createRangeIn(e),i=[],s=new Set;for(const e of n.getItems()){if(!e.is("element")||!e.name.match(/^(p|h\d+|li|div)$/))continue;let t=S(e);if(void 0===t||0!=parseFloat(t)||Array.from(e.getClassNames()).find(e=>e.startsWith("MsoList"))||(t=void 0),e.hasStyle("mso-list")&&"none"!==e.getStyle("mso-list")||void 0!==t&&s.has(t)){const n=v(e);i.push({element:e,id:n.id,order:n.order,indent:n.indent,marginLeft:t}),void 0!==t&&s.add(t)}else s.clear()}return i}(e,i);if(!s.length)return;const o={},l=[];let a=m();for(const e of s)if(void 0!==e.indent){g(e)||(u(i,l,a),a=m(),l.length=0);const s=`${e.id}:${e.indent}`,r=Math.min(e.indent-1,l.length);if(r<l.length&&l[r].id!==e.id&&(l.length=r),r<l.length-1)l.length=r+1;else{const a=h(e,t);if(r>l.length-1||l[r].listElement.name!=a.type){0==r&&"ol"==a.type&&void 0!==e.id&&o[s]&&(a.startIndex=o[s]);const t=b(a,i,n);if(0==l.length){const n=e.element.parent,s=n.getChildIndex(e.element)+1;i.insertChild(s,t,n)}else{const e=l[r-1].listItemElements;i.appendChild(t,e[e.length-1])}l[r]={...e,listElement:t,listItemElements:[]},0==r&&void 0!==e.id&&(o[s]=a.startIndex||1)}}const c="li"==e.element.name?e.element:i.createElement("li");f(i,l,a,e,c,r),i.appendChild(c,l[r].listElement),l[r].listItemElements.push(c),0==r&&void 0!==e.id&&o[s]++,e.element!=c&&i.appendChild(e.element,c),x(e.element,i),i.removeStyle("text-indent",e.element),i.removeStyle("margin-left",e.element)}else{const t=l.find(t=>t.marginLeft==e.marginLeft);if(t){const n=t.listItemElements;i.appendChild(e.element,n[n.length-1]),i.removeStyle("margin-left",e.element)}else l.length=0}u(i,l,a)}function f(e,t,n,i,s,r){if(void 0===i.marginLeft)return void(0==r&&(n.canApplyMarginOnList=!1));const o=parseFloat(i.marginLeft);let l=0;if(t.length>1){const e=t[t.length-2].listItemElements;if(e.length>0){const t=e[e.length-1].getStyle("margin-left");void 0!==t&&(l+=parseFloat(t))}}l+=40*t.length;const c=o-l,f=0!==c?a(c):void 0;f&&(e.setStyle("margin-left",f,s),0==r&&n.canApplyMarginOnList&&(void 0===n.marginLeft&&(n.marginLeft=f),f!==n.marginLeft&&(n.canApplyMarginOnList=!1),n.topLevelListItemElements.push(s)))}function m(){return{marginLeft:void 0,canApplyMarginOnList:!0,topLevelListItemElements:[]}}function u(e,t,n){if(n.canApplyMarginOnList&&n.marginLeft&&n.topLevelListItemElements.length>0){e.setStyle("margin-left",n.marginLeft,t[0].listElement);for(const t of n.topLevelListItemElements)e.removeStyle("margin-left",t)}}function d(e,t){for(const n of t.createRangeIn(e)){const e=n.item;if(e.is("element","li")){const n=e.getChild(0);n&&n.is("element","p")&&t.unwrapElement(n)}}}function g(e){const t=e.element.previousSibling;if(!t){const t=e.element.parent;return p(t)&&(!t.previousSibling||p(t.previousSibling))}return p(t)}function p(e){return e.is("element","ol")||e.is("element","ul")}function h(e,t){const n=new RegExp(`@list l${e.id}:level${e.indent}\\s*({[^}]*)`,"gi"),i=/mso-level-number-format:([^;]{0,100});/gi,s=/mso-level-start-at:\s{0,100}([0-9]{0,10})\s{0,100};/gi,r=new RegExp(`@list\\s+l${e.id}:level\\d\\s*{[^{]*mso-level-text:"%\\d\\\\.`,"gi"),o=new RegExp(`@list l${e.id}:level\\d\\s*{[^{]*mso-level-number-format:`,"gi"),l=r.exec(t),a=o.exec(t),c=l&&!a,f=n.exec(t);let m="decimal",u="ol",d=null;if(f&&f[1]){const t=i.exec(f[1]);if(t&&t[1]&&(m=t[1].trim(),u="bullet"!==m&&"image"!==m?"ol":"ul"),"bullet"===m){const t=function(e){if("li"==e.name&&"ul"==e.parent.name&&e.parent.hasAttribute("type"))return e.parent.getAttribute("type");const t=function(e){if(e.getChild(0).is("$text"))return null;for(const t of e.getChildren()){if(!t.is("element","span"))continue;const e=t.getChild(0);if(e)return e.is("$text")?e:e.getChild(0)}return null}(e);if(!t)return null;const n=t._data;if("o"===n)return"circle";if("·"===n)return"disc";if("§"===n)return"square";return null}(e.element);t&&(m=t)}else{const e=s.exec(f[1]);e&&e[1]&&(d=parseInt(e[1]))}c&&(u="ol")}return{type:u,startIndex:d,style:y(m),isLegalStyleList:c}}function y(e){if(e.startsWith("arabic-leading-zero"))return"decimal-leading-zero";switch(e){case"alpha-upper":return"upper-alpha";case"alpha-lower":return"lower-alpha";case"roman-upper":return"upper-roman";case"roman-lower":return"lower-roman";case"circle":case"disc":case"square":return e;default:return null}}function b(e,t,n){const i=t.createElement(e.type);return e.style&&t.setStyle("list-style-type",e.style,i),e.startIndex&&e.startIndex>1&&t.setAttribute("start",e.startIndex,i),e.isLegalStyleList&&n&&t.addClass("legal-list",i),i}function v(e){const t=e.getStyle("mso-list");if(void 0===t)return{};const n=t.match(/(^|\s{1,100})l(\d+)/i),i=t.match(/\s{0,100}lfo(\d+)/i),s=t.match(/\s{0,100}level(\d+)/i);return n&&i&&s?{id:n[2],order:i[1],indent:parseInt(s[1])}:{indent:1}}function x(e,t){const n=new r.Matcher({name:"span",styles:{"mso-list":"Ignore"}}),i=t.createRangeIn(e);for(const e of i)"elementStart"===e.type&&n.match(e.item)&&t.remove(e.item)}function S(e){const t=e.getStyle("margin-left");return void 0===t||t.endsWith("px")?t:o(t)}function w(e,t){if(!e.childCount)return;const n=new r.ViewUpcastWriter(e.document),i=function(e,t){const n=t.createRangeIn(e),i=new r.Matcher({name:/v:(.+)/}),s=[];for(const e of n){if("elementStart"!=e.type)continue;const t=e.item,n=t.previousSibling,r=n&&n.is("element")?n.name:null,o=["Chart"],l=i.match(t),a=t.getAttribute("o:gfxdata"),c="v:shapetype"===r,f=a&&o.some(e=>t.getAttribute("id").includes(e));l&&a&&!c&&!f&&s.push(e.item.getAttribute("id"))}return s}(e,n);!function(e,t,n){const i=n.createRangeIn(t),s=new r.Matcher({name:"img"}),o=[];for(const t of i)if(t.item.is("element")&&s.match(t.item)){const n=t.item,i=n.getAttribute("v:shapes")?n.getAttribute("v:shapes").split(" "):[];i.length&&i.every(t=>e.indexOf(t)>-1)?o.push(n):n.getAttribute("src")||o.push(n)}for(const e of o)n.remove(e)}(i,e,n),function(e,t,n){const i=n.createRangeIn(t),s=[];for(const t of i)if("elementStart"==t.type&&t.item.is("element","v:shape")){const n=t.item.getAttribute("id");if(e.includes(n))continue;r(t.item.parent.getChildren(),n)||s.push(t.item)}for(const e of s){const t={src:o(e)};e.hasAttribute("alt")&&(t.alt=e.getAttribute("alt"));const i=n.createElement("img",t);n.insertChild(e.index+1,i,e.parent)}function r(e,t){for(const n of e)if(n.is("element")){if("img"==n.name&&n.getAttribute("v:shapes")==t)return!0;if(r(n.getChildren(),t))return!0}return!1}function o(e){for(const t of e.getChildren())if(t.is("element")&&t.getAttribute("src"))return t.getAttribute("src")}}(i,e,n),function(e,t){const n=t.createRangeIn(e),i=new r.Matcher({name:/v:(.+)/}),s=[];for(const e of n)"elementStart"==e.type&&i.match(e.item)&&s.push(e.item);for(const e of s)t.remove(e)}(e,n);const s=function(e,t){const n=t.createRangeIn(e),i=new r.Matcher({name:"img"}),s=[];let o=0;for(const e of n)e.item.is("element")&&i.match(e.item)&&(e.item.getAttribute("src").startsWith("file://")&&s.push({element:e.item,imageIndex:o}),o++);return s}(e,n);s.length&&function(e,t,n){for(let i=0;i<e.length;i++){const{element:s,imageIndex:r}=e[i],o=t[r];if(o){const e=`data:${o.type};base64,${C(o.hex)}`;n.setAttribute("src",e,s)}}}(s,function(e){if(!e)return[];const t=/{\\pict[\s\S]+?\\bliptag-?\d+(\\blipupi-?\d+)?({\\\*\\blipuid\s?[\da-fA-F]+)?[\s}]*?/,n=new RegExp("(?:("+t.source+"))([\\da-fA-F\\s]+)\\}","g"),i=e.match(n),s=[];if(i)for(const e of i){let n=!1;e.includes("\\pngblip")?n="image/png":e.includes("\\jpegblip")&&(n="image/jpeg"),n&&s.push({hex:e.replace(t,"").replace(/[^\da-fA-F]/g,""),type:n})}return s}(t),n)}function C(e){return btoa(e.match(/\w{2}/g).map(e=>String.fromCharCode(parseInt(e,16))).join(""))}function A(e){const t=[],n=new r.ViewUpcastWriter(e.document);for(const{item:i}of n.createRangeIn(e))if(i.is("element")){for(const e of i.getClassNames())/\bmso/gi.exec(e)&&n.removeClass(e,i);for(const e of i.getStyleNames())/\bmso/gi.exec(e)&&n.removeStyle(e,i);(i.is("element","w:sdt")||i.is("element","w:sdtpr")&&i.isEmpty||i.is("element","o:p")&&i.isEmpty)&&t.push(i)}for(const e of t){const t=e.parent,i=t.getChildIndex(e);n.insertChild(i,e.getChildren(),t),n.remove(e)}}function P(e,t,n=!1,i=!1){for(const s of t.createRangeIn(e).getItems()){if(!s.is("element","table")&&!s.is("element","td")&&!s.is("element","th"))continue;if(n&&i&&s.is("element","table")){const e=s.parent?.is("element","div")?s.parent:null,n=s.parent?.parent?.is("element","div")?s.parent.parent:null,i=e??n;i&&"center"===i.getAttribute("align")&&!s.getAttribute("align")?(t.setStyle("margin-left","auto",s),t.setStyle("margin-right","auto",s)):i&&"right"===i.getAttribute("align")&&!s.getAttribute("align")?(t.setStyle("margin-left","auto",s),t.setStyle("margin-right","0",s)):i||s.getAttribute("align")||(t.setStyle("margin-left","0",s),t.setStyle("margin-right","auto",s))}const e=["left","top","right","bottom"];if(e.every(e=>!s.hasStyle(`border-${e}-style`)))t.setStyle("border-style","none",s);else for(const n of e)s.hasStyle(`border-${n}-style`)||t.setStyle(`border-${n}-style`,"none",s);const r=["width","height",...e.map(e=>`border-${e}-width`),...e.map(e=>`padding-${e}`)];for(const e of r)s.hasStyle(e)&&t.setStyle(e,o(s.getStyle(e)),s)}}function I(e,t){for(const n of t.createRangeIn(e).getItems())n.is("element","table")&&("0px"===n.getStyle("width")&&t.removeStyle("width",n),"0"===n.getAttribute("width")&&t.removeAttribute("width",n))}function E(e,t){const n=[],i=[];for(const{item:s}of e.createRangeIn(t))if(s.is("element")&&s.getStyle("mso-footnote-id")){n.unshift(s);const{nextSibling:e}=s;e?.is("$text")&&e.data.startsWith(" ")&&i.unshift(e)}for(const t of n)e.remove(t);for(const t of i){const n=t.data.substring(1);if(n.length>0){const i=t.parent,s=i.getChildIndex(t),r=e.createText(n);e.remove(t),e.insertChild(s,r,i)}else e.remove(t)}return t}function O(e,t){const n=e.createElement("sup",{class:"footnote"}),i=e.createElement("a",{id:`ref-${t}`,href:`#${t}`});return e.appendChild(i,n),n}function L(e,t){const n=e.createElement("li",{id:t,class:"footnote-definition"}),i=e.createElement("a",{href:`#ref-${t}`,class:"footnote-backlink"}),s=e.createElement("div",{class:"footnote-content"});return e.appendChild(e.createText("^"),i),e.appendChild(i,n),e.appendChild(s,n),{listItem:n,content:s}}const T=/<meta\s*name="?generator"?\s*content="?microsoft\s*word\s*\d+"?\/?>/i,M=/xmlns:o="urn:schemas-microsoft-com/i;class _{document;hasMultiLevelListPlugin;hasTablePropertiesPlugin;hasExtendedTableBlockAlignment;constructor(e,t=!1,n=!1,i=!1){this.document=e,this.hasMultiLevelListPlugin=t,this.hasTablePropertiesPlugin=n,this.hasExtendedTableBlockAlignment=i}isActive(e){return T.test(e)||M.test(e)}execute(e){const t=new r.ViewUpcastWriter(this.document),{body:n,stylesString:i}=e._parsedData;s(n,t),c(n,i,this.hasMultiLevelListPlugin),w(n,e.dataTransfer.getData("text/rtf")),P(n,t,this.hasTablePropertiesPlugin,this.hasExtendedTableBlockAlignment),I(n,t),function(e,t){const n=new Map,i=new Map;let s=null;for(const{item:r}of t.createRangeIn(e))if(r.is("element"))if("footnote-list"!==r.getStyle("mso-element")){if(r.hasStyle("mso-footnote-id")){const e=r.findAncestor("element",e=>"footnote"===e.getStyle("mso-element"));if(e){const t=e.getAttribute("id");i.set(t,e)}else{const e=r.getStyle("mso-footnote-id");n.set(e,r)}continue}}else s=r;if(!n.size||!s)return;const r=function(e){return e.createElement("ol",{class:"footnotes"})}(t);t.replace(s,r);for(const[e,s]of n){const n=i.get(e);if(!n)continue;t.replace(s,O(t,e));const o=L(t,e);E(t,n);for(const e of n.getChildren()){let n=e;e.is("element")&&(n=t.clone(e,!0)),t.appendChild(n,o.content)}t.appendChild(o.listItem,r)}}(n,t),A(n),e.content=n}}function $(e,t){for(const n of e.getChildren())if(n.is("element","b")&&"normal"===n.getStyle("font-weight")){const i=e.getChildIndex(n);t.remove(n),t.insertChild(i,n.getChildren(),e)}}function R(e,t){const n=new r.ViewDocument(t.document.stylesProcessor),i=new r.ViewDomConverter(n,{renderingMode:"data"}),s=i.blockElements,o=i.inlineObjectElements,l=[];for(const n of t.createRangeIn(e)){const e=n.item;if(e.is("element","br")){const n=W(e,"forward",t,{blockElements:s,inlineObjectElements:o}),i=W(e,"backward",t,{blockElements:s,inlineObjectElements:o}),r=F(n,s);(F(i,s)||r)&&l.push(e)}}for(const e of l)e.hasClass("Apple-interchange-newline")?t.remove(e):t.replace(e,t.createElement("p"))}function W(e,t,n,{blockElements:i,inlineObjectElements:s}){let r=n.createPositionAt(e,"forward"==t?"after":"before");return r=r.getLastMatchingPosition(({item:e})=>e.is("element")&&!i.includes(e.name)&&!s.includes(e.name),{direction:t}),"forward"==t?r.nodeAfter:r.nodeBefore}function F(e,t){return!!e&&e.is("element")&&t.includes(e.name)}function k(e){let t=e;for(;t;){if(t.is("element")){const e=t.getStyle?.("white-space");if("pre-wrap"===e)return!0}t=t.parent}return!1}function j(e,t,n){const{parent:i,data:s}=e,r=s.replaceAll("\t"," ".repeat(n)),o=i.getChildIndex(e);t.remove(e),t.insertChild(o,t.createText(r),i)}const B=/id=("|')docs-internal-guid-[-0-9a-f]+("|')/i;class D{document;constructor(e){this.document=e}isActive(e){return B.test(e)}execute(e){const t=new r.ViewUpcastWriter(this.document),{body:n}=e._parsedData;$(n,t),d(n,t),R(n,t),function(e,t,n){const i=new Set;for(const n of t.createRangeIn(e).getItems())n.is("view:$textProxy")&&n.data.includes("\t")&&k(n.parent)&&i.add(n.textNode);for(const e of i)j(e,t,n)}(n,t,8),e.content=n}}function V(e,t){for(const n of e.getChildren())n.is("element","table")&&n.hasAttribute("xmlns")&&t.removeAttribute("xmlns",n)}function N(e,t){for(const n of e.getChildren())if(n.is("element","google-sheets-html-origin")){const i=e.getChildIndex(n);t.remove(n),t.insertChild(i,n.getChildren(),e)}}function z(e,t){for(const n of Array.from(e.getChildren()))n.is("element","style")&&t.remove(n)}const U=/<google-sheets-html-origin/i;class q{document;constructor(e){this.document=e}isActive(e){return U.test(e)}execute(e){const t=new r.ViewUpcastWriter(this.document),{body:n}=e._parsedData;N(n,t),V(n,t),I(n,t),z(n,t),e.content=n}}function H(e){return K(K(e)).replace(/(<span\s+style=['"]mso-spacerun:yes['"]>[^\S\r\n]*?)[\r\n]+([^\S\r\n]*<\/span>)/g,"$1$2").replace(/<span\s+style=['"]mso-spacerun:yes['"]><\/span>/g,"").replace(/(<span\s+style=['"]letter-spacing:[^'"]+?['"]>)[\r\n]+(<\/span>)/g,"$1 $2").replace(/ <\//g," </").replace(/ <o:p><\/o:p>/g," <o:p></o:p>").replace(/<o:p>(&nbsp;|\u00A0)<\/o:p>/g,"").replace(/>([^\S\r\n]*[\r\n]\s*)</g,"><")}function G(e){e.querySelectorAll("span[style*=spacerun]").forEach(e=>{const t=e,n=t.innerText.length||0;t.innerText=Array(n+1).join("  ").substr(0,n)})}function K(e){return e.replace(/<span(?: class="Apple-converted-space"|)>(\s+)<\/span>/g,(e,t)=>1===t.length?" ":Array(t.length+1).join("  ").substr(0,t.length))}function X(e,t){const n=new DOMParser,i=H(function(e){const t="</body>",n="</html>",i=e.indexOf(t);if(i<0)return e;const s=e.indexOf(n,i+t.length);return e.substring(0,i+t.length)+(s>=0?e.substring(s):"")}(e=(e=e.replace(/<!--\[if gte vml 1]>/g,"")).replace(/<o:SmartTagType(?:\s+[^\s>=]+(?:="[^"]*")?)*\s*\/?>/gi,""))),s=n.parseFromString(i,"text/html");G(s);const o=s.body.innerHTML,l=function(e,t){const n=new r.ViewDocument(t),i=new r.ViewDomConverter(n,{renderingMode:"data"}),s=e.createDocumentFragment(),o=e.body.childNodes;for(;o.length>0;)s.appendChild(o[0]);return i.domToView(s,{skipComments:!0})}(s,t),a=function(e){const t=[],n=[],i=Array.from(e.getElementsByTagName("style"));for(const e of i)e.sheet&&e.sheet.cssRules&&e.sheet.cssRules.length&&(t.push(e.sheet),n.push(e.innerHTML));return{styles:t,stylesString:n.join(" ")}}(s);return{body:l,bodyString:o,styles:a.styles,stylesString:a.stylesString}}class J extends e.Plugin{static get pluginName(){return"PasteFromOffice"}static get licenseFeatureCode(){return"PFO"}static get isOfficialPlugin(){return!0}static get isPremiumPlugin(){return!0}static get requires(){return[t.ClipboardPipeline]}init(){const e=this.editor,t=e.plugins.get("ClipboardPipeline"),n=e.editing.view.document,i=[],s=this.editor.plugins.has("MultiLevelListEditing"),r=this.editor.plugins.has("TablePropertiesEditing"),o=!!this.editor.config.get("experimentalFlags.useExtendedTableBlockAlignment");i.push(new _(n,s,r,o)),i.push(new D(n)),i.push(new q(n)),t.on("inputTransformation",(t,s)=>{if(s._isTransformedWithPasteFromOffice)return;if(e.model.document.selection.getFirstPosition().parent.is("element","codeBlock"))return;const r=s.dataTransfer.getData("text/html"),o=i.find(e=>e.isActive(r));o&&(s._parsedData||(s._parsedData=X(r,n.stylesProcessor)),o.execute(s),s._isTransformedWithPasteFromOffice=!0)},{priority:"high"})}}})(),(window.CKEditor5=window.CKEditor5||{}).pasteFromOffice=i})();
@@ -1,5 +0,0 @@
1
- /**
2
- * @license Copyright (c) 2003-2026, 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
- export {};
@@ -1,25 +0,0 @@
1
- /**
2
- * @license Copyright (c) 2003-2026, 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
- * Transforms `<a>` elements which are bookmarks by moving their children after the element.
7
- *
8
- * @internal
9
- */
10
- export function transformBookmarks(documentFragment, writer) {
11
- const elementsToChange = [];
12
- for (const value of writer.createRangeIn(documentFragment)) {
13
- const element = value.item;
14
- if (element.is('element', 'a') &&
15
- !element.hasAttribute('href') &&
16
- (element.hasAttribute('id') || element.hasAttribute('name'))) {
17
- elementsToChange.push(element);
18
- }
19
- }
20
- for (const element of elementsToChange) {
21
- const index = element.parent.getChildIndex(element) + 1;
22
- const children = element.getChildren();
23
- writer.insertChild(index, children, element.parent);
24
- }
25
- }
package/src/filters/br.js DELETED
@@ -1,66 +0,0 @@
1
- /**
2
- * @license Copyright (c) 2003-2026, 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/br
7
- */
8
- import { ViewDomConverter, ViewDocument } from 'ckeditor5/src/engine.js';
9
- /**
10
- * Transforms `<br>` elements that are siblings to some block element into a paragraphs.
11
- *
12
- * @param documentFragment The view structure to be transformed.
13
- * @internal
14
- */
15
- export function transformBlockBrsToParagraphs(documentFragment, writer) {
16
- const viewDocument = new ViewDocument(writer.document.stylesProcessor);
17
- const domConverter = new ViewDomConverter(viewDocument, { renderingMode: 'data' });
18
- const blockElements = domConverter.blockElements;
19
- const inlineObjectElements = domConverter.inlineObjectElements;
20
- const elementsToReplace = [];
21
- for (const value of writer.createRangeIn(documentFragment)) {
22
- const element = value.item;
23
- if (element.is('element', 'br')) {
24
- const nextSibling = findSibling(element, 'forward', writer, { blockElements, inlineObjectElements });
25
- const previousSibling = findSibling(element, 'backward', writer, { blockElements, inlineObjectElements });
26
- const nextSiblingIsBlock = isBlockViewElement(nextSibling, blockElements);
27
- const previousSiblingIsBlock = isBlockViewElement(previousSibling, blockElements);
28
- // If the <br> is surrounded by blocks then convert it to a paragraph:
29
- // * <p>foo</p>[<br>]<p>bar</p> -> <p>foo</p>[<p></p>]<p>bar</p>
30
- // * <p>foo</p>[<br>] -> <p>foo</p>[<p></p>]
31
- // * [<br>]<p>foo</p> -> [<p></p>]<p>foo</p>
32
- if (previousSiblingIsBlock || nextSiblingIsBlock) {
33
- elementsToReplace.push(element);
34
- }
35
- }
36
- }
37
- for (const element of elementsToReplace) {
38
- if (element.hasClass('Apple-interchange-newline')) {
39
- writer.remove(element);
40
- }
41
- else {
42
- writer.replace(element, writer.createElement('p'));
43
- }
44
- }
45
- }
46
- /**
47
- * Returns sibling node, threats inline elements as transparent (but should stop on an inline objects).
48
- */
49
- function findSibling(viewElement, direction, writer, { blockElements, inlineObjectElements }) {
50
- let position = writer.createPositionAt(viewElement, direction == 'forward' ? 'after' : 'before');
51
- // Find first position that is just before a first:
52
- // * text node,
53
- // * block element,
54
- // * inline object element.
55
- // It's ignoring any inline (non-object) elements like span, strong, etc.
56
- position = position.getLastMatchingPosition(({ item }) => (item.is('element') &&
57
- !blockElements.includes(item.name) &&
58
- !inlineObjectElements.includes(item.name)), { direction });
59
- return direction == 'forward' ? position.nodeAfter : position.nodeBefore;
60
- }
61
- /**
62
- * Returns true for view elements that are listed as block view elements.
63
- */
64
- function isBlockViewElement(node, blockElements) {
65
- return !!node && node.is('element') && blockElements.includes(node.name);
66
- }
@@ -1,263 +0,0 @@
1
- /**
2
- * @license Copyright (c) 2003-2026, 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/image
7
- */
8
- import { Matcher, ViewUpcastWriter } from 'ckeditor5/src/engine.js';
9
- /**
10
- * Replaces source attribute of all `<img>` elements representing regular
11
- * images (not the Word shapes) with inlined base64 image representation extracted from RTF or Blob data.
12
- *
13
- * @param documentFragment Document fragment on which transform images.
14
- * @param rtfData The RTF data from which images representation will be used.
15
- * @internal
16
- */
17
- export function replaceImagesSourceWithBase64(documentFragment, rtfData) {
18
- if (!documentFragment.childCount) {
19
- return;
20
- }
21
- const upcastWriter = new ViewUpcastWriter(documentFragment.document);
22
- const shapesIds = findAllShapesIds(documentFragment, upcastWriter);
23
- removeAllImgElementsRepresentingShapes(shapesIds, documentFragment, upcastWriter);
24
- insertMissingImgs(shapesIds, documentFragment, upcastWriter);
25
- removeAllShapeElements(documentFragment, upcastWriter);
26
- const images = findAllImageElementsWithLocalSource(documentFragment, upcastWriter);
27
- if (images.length) {
28
- replaceImagesFileSourceWithInlineRepresentation(images, extractImageDataFromRtf(rtfData), upcastWriter);
29
- }
30
- }
31
- /**
32
- * Converts given HEX string to base64 representation.
33
- *
34
- * @internal
35
- * @param hexString The HEX string to be converted.
36
- * @returns Base64 representation of a given HEX string.
37
- */
38
- export function _convertHexToBase64(hexString) {
39
- return btoa(hexString.match(/\w{2}/g).map(char => {
40
- return String.fromCharCode(parseInt(char, 16));
41
- }).join(''));
42
- }
43
- /**
44
- * Finds all shapes (`<v:*>...</v:*>`) ids. Shapes can represent images (canvas)
45
- * or Word shapes (which does not have RTF or Blob representation).
46
- *
47
- * @param documentFragment Document fragment from which to extract shape ids.
48
- * @returns Array of shape ids.
49
- */
50
- function findAllShapesIds(documentFragment, writer) {
51
- const range = writer.createRangeIn(documentFragment);
52
- const shapeElementsMatcher = new Matcher({
53
- name: /v:(.+)/
54
- });
55
- const shapesIds = [];
56
- for (const value of range) {
57
- if (value.type != 'elementStart') {
58
- continue;
59
- }
60
- const el = value.item;
61
- const previousSibling = el.previousSibling;
62
- const prevSiblingName = previousSibling && previousSibling.is('element') ? previousSibling.name : null;
63
- // List of ids which should not be considered as shapes.
64
- // https://github.com/ckeditor/ckeditor5/pull/15847#issuecomment-1941543983
65
- const exceptionIds = ['Chart'];
66
- const isElementAShape = shapeElementsMatcher.match(el);
67
- const hasElementGfxdataAttribute = el.getAttribute('o:gfxdata');
68
- const isPreviousSiblingAShapeType = prevSiblingName === 'v:shapetype';
69
- const isElementIdInExceptionsArray = hasElementGfxdataAttribute &&
70
- exceptionIds.some(item => el.getAttribute('id').includes(item));
71
- // If shape element has 'o:gfxdata' attribute and is not directly before
72
- // `<v:shapetype>` element it means that it represents a Word shape.
73
- if (isElementAShape &&
74
- hasElementGfxdataAttribute &&
75
- !isPreviousSiblingAShapeType &&
76
- !isElementIdInExceptionsArray) {
77
- shapesIds.push(value.item.getAttribute('id'));
78
- }
79
- }
80
- return shapesIds;
81
- }
82
- /**
83
- * Removes all `<img>` elements which represents Word shapes and not regular images.
84
- *
85
- * @param shapesIds Shape ids which will be checked against `<img>` elements.
86
- * @param documentFragment Document fragment from which to remove `<img>` elements.
87
- */
88
- function removeAllImgElementsRepresentingShapes(shapesIds, documentFragment, writer) {
89
- const range = writer.createRangeIn(documentFragment);
90
- const imageElementsMatcher = new Matcher({
91
- name: 'img'
92
- });
93
- const imgs = [];
94
- for (const value of range) {
95
- if (value.item.is('element') && imageElementsMatcher.match(value.item)) {
96
- const el = value.item;
97
- const shapes = el.getAttribute('v:shapes') ? el.getAttribute('v:shapes').split(' ') : [];
98
- if (shapes.length && shapes.every(shape => shapesIds.indexOf(shape) > -1)) {
99
- imgs.push(el);
100
- // Shapes may also have empty source while content is paste in some browsers (Safari).
101
- }
102
- else if (!el.getAttribute('src')) {
103
- imgs.push(el);
104
- }
105
- }
106
- }
107
- for (const img of imgs) {
108
- writer.remove(img);
109
- }
110
- }
111
- /**
112
- * Removes all shape elements (`<v:*>...</v:*>`) so they do not pollute the output structure.
113
- *
114
- * @param documentFragment Document fragment from which to remove shape elements.
115
- */
116
- function removeAllShapeElements(documentFragment, writer) {
117
- const range = writer.createRangeIn(documentFragment);
118
- const shapeElementsMatcher = new Matcher({
119
- name: /v:(.+)/
120
- });
121
- const shapes = [];
122
- for (const value of range) {
123
- if (value.type == 'elementStart' && shapeElementsMatcher.match(value.item)) {
124
- shapes.push(value.item);
125
- }
126
- }
127
- for (const shape of shapes) {
128
- writer.remove(shape);
129
- }
130
- }
131
- /**
132
- * Inserts `img` tags if there is none after a shape.
133
- */
134
- function insertMissingImgs(shapeIds, documentFragment, writer) {
135
- const range = writer.createRangeIn(documentFragment);
136
- const shapes = [];
137
- for (const value of range) {
138
- if (value.type == 'elementStart' && value.item.is('element', 'v:shape')) {
139
- const id = value.item.getAttribute('id');
140
- if (shapeIds.includes(id)) {
141
- continue;
142
- }
143
- if (!containsMatchingImg(value.item.parent.getChildren(), id)) {
144
- shapes.push(value.item);
145
- }
146
- }
147
- }
148
- for (const shape of shapes) {
149
- const attrs = {
150
- src: findSrc(shape)
151
- };
152
- if (shape.hasAttribute('alt')) {
153
- attrs.alt = shape.getAttribute('alt');
154
- }
155
- const img = writer.createElement('img', attrs);
156
- writer.insertChild(shape.index + 1, img, shape.parent);
157
- }
158
- function containsMatchingImg(nodes, id) {
159
- for (const node of nodes) {
160
- /* istanbul ignore else -- @preserve */
161
- if (node.is('element')) {
162
- if (node.name == 'img' && node.getAttribute('v:shapes') == id) {
163
- return true;
164
- }
165
- if (containsMatchingImg(node.getChildren(), id)) {
166
- return true;
167
- }
168
- }
169
- }
170
- return false;
171
- }
172
- function findSrc(shape) {
173
- for (const child of shape.getChildren()) {
174
- /* istanbul ignore else -- @preserve */
175
- if (child.is('element') && child.getAttribute('src')) {
176
- return child.getAttribute('src');
177
- }
178
- }
179
- }
180
- }
181
- /**
182
- * Finds all `<img>` elements in a given document fragment which have source pointing to local `file://` resource.
183
- * This function also tracks the index position of each image in the document, which is essential for
184
- * precise matching with hexadecimal representations in RTF data.
185
- *
186
- * @param documentFragment Document fragment in which to look for `<img>` elements.
187
- * @returns Array of found images along with their position index in the document.
188
- */
189
- function findAllImageElementsWithLocalSource(documentFragment, writer) {
190
- const range = writer.createRangeIn(documentFragment);
191
- const imageElementsMatcher = new Matcher({
192
- name: 'img'
193
- });
194
- const imgs = [];
195
- let currentImageIndex = 0;
196
- for (const value of range) {
197
- if (value.item.is('element') && imageElementsMatcher.match(value.item)) {
198
- if (value.item.getAttribute('src').startsWith('file://')) {
199
- imgs.push({
200
- element: value.item,
201
- imageIndex: currentImageIndex
202
- });
203
- }
204
- currentImageIndex++;
205
- }
206
- }
207
- return imgs;
208
- }
209
- /**
210
- * Extracts all images HEX representations from a given RTF data.
211
- *
212
- * @param rtfData The RTF data from which to extract images HEX representation.
213
- * @returns Array of found HEX representations. Each array item is an object containing:
214
- *
215
- * * hex Image representation in HEX format.
216
- * * type Type of image, `image/png` or `image/jpeg`.
217
- */
218
- function extractImageDataFromRtf(rtfData) {
219
- if (!rtfData) {
220
- return [];
221
- }
222
- const regexPictureHeader = /{\\pict[\s\S]+?\\bliptag-?\d+(\\blipupi-?\d+)?({\\\*\\blipuid\s?[\da-fA-F]+)?[\s}]*?/;
223
- const regexPicture = new RegExp('(?:(' + regexPictureHeader.source + '))([\\da-fA-F\\s]+)\\}', 'g');
224
- const images = rtfData.match(regexPicture);
225
- const result = [];
226
- if (images) {
227
- for (const image of images) {
228
- let imageType = false;
229
- if (image.includes('\\pngblip')) {
230
- imageType = 'image/png';
231
- }
232
- else if (image.includes('\\jpegblip')) {
233
- imageType = 'image/jpeg';
234
- }
235
- if (imageType) {
236
- result.push({
237
- hex: image.replace(regexPictureHeader, '').replace(/[^\da-fA-F]/g, ''),
238
- type: imageType
239
- });
240
- }
241
- }
242
- }
243
- return result;
244
- }
245
- /**
246
- * Replaces `src` attribute value of all given images with the corresponding base64 image representation.
247
- * Uses the image index to precisely match with the correct hexadecimal representation from RTF data.
248
- *
249
- * @param imageElements Array of image elements along with their indices which will have their sources replaced.
250
- * @param imagesHexSources Array of images hex sources (usually the result of `extractImageDataFromRtf()` function).
251
- * Contains hexadecimal representations of ALL images in the document, not just those with `file://` URLs.
252
- * In XML documents, the same image might be defined both as base64 in HTML and as hexadecimal in RTF data.
253
- */
254
- function replaceImagesFileSourceWithInlineRepresentation(imageElements, imagesHexSources, writer) {
255
- for (let i = 0; i < imageElements.length; i++) {
256
- const { element, imageIndex } = imageElements[i];
257
- const rtfHexSource = imagesHexSources[imageIndex];
258
- if (rtfHexSource) {
259
- const newSrc = `data:${rtfHexSource.type};base64,${_convertHexToBase64(rtfHexSource.hex)}`;
260
- writer.setAttribute('src', newSrc, element);
261
- }
262
- }
263
- }