@opentiny/fluent-editor 3.25.11 → 3.25.12

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.
@@ -55,12 +55,53 @@ function omit(obj, uselessKeys) {
55
55
  return uselessKeys.includes(key) ? acc : { ...acc, [key]: obj[key] };
56
56
  }, {});
57
57
  }
58
+ function getPasteImageSrc(image) {
59
+ if (!image) return "";
60
+ return typeof image === "string" ? image : image.src || "";
61
+ }
62
+ function isInvalidPasteImageSrc(src) {
63
+ if (!src) return true;
64
+ return src === "//:0" || /^file:/i.test(src) || /^cid:/i.test(src);
65
+ }
66
+ function normalizeOutlookPasteImages(delta) {
67
+ let prevWasInvalidImage = false;
68
+ return delta.reduce((newDelta, op) => {
69
+ var _a;
70
+ if (!((_a = op.insert) == null ? void 0 : _a.image) || op.insert.image.hasExisted) {
71
+ newDelta.insert(op.insert, op.attributes);
72
+ prevWasInvalidImage = false;
73
+ return newDelta;
74
+ }
75
+ const src = getPasteImageSrc(op.insert.image);
76
+ const invalid = isInvalidPasteImageSrc(src);
77
+ if (invalid && prevWasInvalidImage) {
78
+ return newDelta;
79
+ }
80
+ let attributes = op.attributes;
81
+ if ((attributes == null ? void 0 : attributes.alt) === "image") {
82
+ attributes = { ...attributes };
83
+ delete attributes.alt;
84
+ }
85
+ newDelta.insert(op.insert, attributes);
86
+ prevWasInvalidImage = invalid;
87
+ return newDelta;
88
+ }, new Delta());
89
+ }
58
90
  function replaceDeltaImage(delta, imageUrls, imagePlaceholder) {
59
91
  let imageIndex = 0;
60
92
  return delta.reduce((newDelta, op) => {
61
93
  if (op.insert.image && !op.insert.image.hasExisted) {
62
- const attributes = imagePlaceholder[imageIndex] ? { ...op.attributes, width: "auto", height: 225 } : op.attributes;
63
- newDelta.insert({ image: imageUrls[imageIndex] }, attributes);
94
+ const imageUrl = imageUrls[imageIndex];
95
+ if (!imageUrl && isInvalidPasteImageSrc(getPasteImageSrc(op.insert.image))) {
96
+ imageIndex++;
97
+ return newDelta;
98
+ }
99
+ let attributes = imagePlaceholder[imageIndex] ? { ...op.attributes, width: "auto", height: 225 } : op.attributes;
100
+ if ((attributes == null ? void 0 : attributes.alt) === "image") {
101
+ attributes = { ...attributes };
102
+ delete attributes.alt;
103
+ }
104
+ newDelta.insert({ image: imageUrl }, attributes);
64
105
  imageIndex++;
65
106
  } else {
66
107
  newDelta.insert(op.insert, op.attributes);
@@ -138,15 +179,18 @@ const isOutlookDesktop = (e) => {
138
179
  };
139
180
  export {
140
181
  getEventComposedPath,
182
+ getPasteImageSrc,
141
183
  hadProtocol,
142
184
  hexToRgbA,
143
185
  imageFileToUrl,
144
186
  imageUrlToFile,
145
187
  insideTable,
146
188
  isInside,
189
+ isInvalidPasteImageSrc,
147
190
  isNullOrUndefined,
148
191
  isOutlookDesktop,
149
192
  isPureIE,
193
+ normalizeOutlookPasteImages,
150
194
  omit,
151
195
  replaceDeltaImage,
152
196
  sanitize,
@@ -1 +1 @@
1
- {"version":3,"file":"editor.utils.es.js","sources":["../../../src/config/editor.utils.ts"],"sourcesContent":["import Quill from 'quill'\n\nconst Delta = Quill.import('delta')\n\n// color hex to rgba\nexport function hexToRgbA(hex: string) {\n let color\n if (/^#([A-Fa-f0-9]{3}){1,2}$/.test(hex)) {\n color = hex.substring(1).split('')\n if (color.length === 3) {\n color = [color[0], color[0], color[1], color[1], color[2], color[2]]\n }\n color = `0x${color.join('')}`\n return (\n `rgba(${\n [(color >> 16) & 255, (color >> 8) & 255, color & 255].join(',')\n },1)`\n )\n }\n}\n\n/**\n * 将File格式的图片转换成Url格式\n * @param imageFile File格式的图片\n */\nexport function imageFileToUrl(imageFile) {\n return new Promise((resolve, reject) => {\n const reader = new FileReader()\n reader.readAsDataURL(imageFile)\n reader.onload = function (e) {\n resolve(e.target.result)\n }\n reader.onerror = reject\n }).catch((error) => {\n console.error('Error reading file:', error)\n })\n}\n\n/**\n * 将Url格式的图片转换成File格式\n * @param imageUrl 图片的URL\n */\nexport function imageUrlToFile(imageUrl, isErrorImage?: boolean) {\n return new Promise((resolve, reject) => {\n fetch(imageUrl, {\n method: 'get',\n mode: 'no-cors',\n })\n .then(res => res.blob())\n .then((blob) => {\n if (!blob.type.includes('image') || !blob.type) {\n return reject()\n }\n const fileType = blob.type.replace(/^.*\\//, '')\n const fileName = isErrorImage\n ? 'editorx-error-image.png'\n : `image-${new Date().getTime()}.${fileType}`\n const file = new File([blob], fileName, blob)\n resolve(file)\n })\n .catch(reject)\n })\n}\n\nexport function insideTable(range = null, quill = this.quill) {\n let currentRange = range\n if (!currentRange) {\n currentRange = quill.getSelection()\n }\n // fix: 原有formats方法无法判断表格内的list和head附近粘贴\n const [line] = quill.getLine(currentRange.index)\n return line && !!line.domNode.closest('table.quill-better-table')\n}\n\nexport function isNullOrUndefined(param) {\n return param === null || param === undefined\n}\n\n/**\n * omit\n * @param obj target Object\n * @param uselessKeys keys of removed properties\n * @return new Object without useless properties\n */\nexport function omit(obj, uselessKeys) {\n return (\n obj\n && Object.keys(obj).reduce((acc, key) => {\n return uselessKeys.includes(key) ? acc : { ...acc, [key]: obj[key] }\n }, {})\n )\n}\n\n/**\n * 将delta中的图片替换成制定的图片数组,用于图片上传到服务器的场景\n * @param delta 原始delta\n * @param imageUrls 图片数组\n * @param imagePlaceholder 标识是否是占位图的数组,与图片数组一一对应\n * @return 替换之后的delta\n */\nexport function replaceDeltaImage(delta, imageUrls, imagePlaceholder) {\n let imageIndex = 0\n return delta.reduce((newDelta, op) => {\n if (op.insert.image && !op.insert.image.hasExisted) {\n const attributes = imagePlaceholder[imageIndex]\n ? { ...op.attributes, width: 'auto', height: 225 } // 占位图片应该固定大小\n : op.attributes\n newDelta.insert({ image: imageUrls[imageIndex] }, attributes)\n imageIndex++\n }\n else {\n newDelta.insert(op.insert, op.attributes)\n }\n return newDelta\n }, new Delta())\n}\n\nexport function splitWithBreak(insertContent: string) {\n const lines = []\n const insertStr = insertContent\n let start = 0\n for (let i = 0; i < insertContent.length; i++) {\n if (insertStr.charAt(i) === '\\n') {\n if (i === 0) {\n lines.push('\\n')\n }\n else {\n lines.push(insertStr.substring(start, i))\n lines.push('\\n')\n }\n start = i + 1\n }\n }\n\n const tailStr = insertStr.substring(start)\n if (tailStr) {\n lines.push(tailStr)\n }\n\n return lines\n}\n\n/**\n * getEventComposedPath\n * compatibility fixed for Event.path/Event.composedPath\n * Event.path is only for chrome/opera\n * Event.composedPath is for Safari, FF\n * Neither for Micro Edge\n * @return an array of event.path\n */\nexport function getEventComposedPath(evt) {\n let path\n // chrome, opera, safari, firefox\n path = evt.path || (evt.composedPath && evt.composedPath())\n\n // other: edge\n if (path === undefined && evt.target) {\n path = []\n let target = evt.target\n path.push(target)\n\n while (target && target.parentNode) {\n target = target.parentNode\n path.push(target)\n }\n }\n\n return path\n}\n\nexport function sanitize(url, protocols) {\n const anchor = document.createElement('a')\n anchor.href = url\n const protocol = anchor.href.slice(0, anchor.href.indexOf(':'))\n return protocols.includes(protocol)\n}\n\nexport function hadProtocol(url: string) {\n if (!url || !/^(?:f|ht)tps?\\:\\/\\//.test(url)) {\n return false\n }\n return true\n}\n\nexport function isInside(position, dom) {\n const areaPosition = dom.getBoundingClientRect()\n const { pageX, pageY } = position\n // getBoundingClientRect是不考虑窗口滚动的\n const left = pageX - window.scrollX\n const top = pageY - window.scrollY\n const {\n left: areaLeft,\n top: areaTop,\n width: areaWidth,\n height: areaHeight,\n } = areaPosition\n const inside\n = left > areaLeft\n && left < areaLeft + areaWidth\n && top > areaTop\n && top < areaTop + areaHeight\n return inside\n}\n\n// Internet Explorer 6-11\nexport const isPureIE = !!document.documentMode\n\n/**\n* 检测剪贴板数据是否来自 Outlook 客户端\n*/\nexport const isOutlookDesktop = (e) => {\n const types = e.clipboardData?.types || [];\n const html = e.clipboardData?.getData('text/html') || '';\n\n // RTF + Office 命名空间 或 RTF + Mso 样式类\n return types.includes('text/rtf') && (/schemas-microsoft-com:office/.test(html) || /class=\"?Mso\\w+/i.test(html));\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"editor.utils.es.js","sources":["../../../src/config/editor.utils.ts"],"sourcesContent":["import Quill from 'quill'\n\nconst Delta = Quill.import('delta')\n\n// color hex to rgba\nexport function hexToRgbA(hex: string) {\n let color\n if (/^#([A-Fa-f0-9]{3}){1,2}$/.test(hex)) {\n color = hex.substring(1).split('')\n if (color.length === 3) {\n color = [color[0], color[0], color[1], color[1], color[2], color[2]]\n }\n color = `0x${color.join('')}`\n return (\n `rgba(${\n [(color >> 16) & 255, (color >> 8) & 255, color & 255].join(',')\n },1)`\n )\n }\n}\n\n/**\n * 将File格式的图片转换成Url格式\n * @param imageFile File格式的图片\n */\nexport function imageFileToUrl(imageFile) {\n return new Promise((resolve, reject) => {\n const reader = new FileReader()\n reader.readAsDataURL(imageFile)\n reader.onload = function (e) {\n resolve(e.target.result)\n }\n reader.onerror = reject\n }).catch((error) => {\n console.error('Error reading file:', error)\n })\n}\n\n/**\n * 将Url格式的图片转换成File格式\n * @param imageUrl 图片的URL\n */\nexport function imageUrlToFile(imageUrl, isErrorImage?: boolean) {\n return new Promise((resolve, reject) => {\n fetch(imageUrl, {\n method: 'get',\n mode: 'no-cors',\n })\n .then(res => res.blob())\n .then((blob) => {\n if (!blob.type.includes('image') || !blob.type) {\n return reject()\n }\n const fileType = blob.type.replace(/^.*\\//, '')\n const fileName = isErrorImage\n ? 'editorx-error-image.png'\n : `image-${new Date().getTime()}.${fileType}`\n const file = new File([blob], fileName, blob)\n resolve(file)\n })\n .catch(reject)\n })\n}\n\nexport function insideTable(range = null, quill = this.quill) {\n let currentRange = range\n if (!currentRange) {\n currentRange = quill.getSelection()\n }\n // fix: 原有formats方法无法判断表格内的list和head附近粘贴\n const [line] = quill.getLine(currentRange.index)\n return line && !!line.domNode.closest('table.quill-better-table')\n}\n\nexport function isNullOrUndefined(param) {\n return param === null || param === undefined\n}\n\n/**\n * omit\n * @param obj target Object\n * @param uselessKeys keys of removed properties\n * @return new Object without useless properties\n */\nexport function omit(obj, uselessKeys) {\n return (\n obj\n && Object.keys(obj).reduce((acc, key) => {\n return uselessKeys.includes(key) ? acc : { ...acc, [key]: obj[key] }\n }, {})\n )\n}\n\nexport function getPasteImageSrc(image) {\n if (!image) return ''\n return typeof image === 'string' ? image : (image.src || '')\n}\n\n/**\n * Outlook/Word 粘贴图常见无效 src:file://、cid:、sanitize 后的 //:0\n */\nexport function isInvalidPasteImageSrc(src) {\n if (!src) return true\n return src === '//:0' || /^file:/i.test(src) || /^cid:/i.test(src)\n}\n\n/**\n * Outlook 粘贴时 v:imagedata 与 <img alt=image> 常成对出现,\n * 去掉连续的无效重复图,并清除无意义的 alt=\"image\"。\n */\nexport function normalizeOutlookPasteImages(delta) {\n let prevWasInvalidImage = false\n return delta.reduce((newDelta, op) => {\n if (!op.insert?.image || op.insert.image.hasExisted) {\n newDelta.insert(op.insert, op.attributes)\n prevWasInvalidImage = false\n return newDelta\n }\n\n const src = getPasteImageSrc(op.insert.image)\n const invalid = isInvalidPasteImageSrc(src)\n // 连续无效图视为 Outlook 的 v:imagedata + img 重复,丢弃后者\n if (invalid && prevWasInvalidImage) {\n return newDelta\n }\n\n let attributes = op.attributes\n if (attributes?.alt === 'image') {\n attributes = { ...attributes }\n delete attributes.alt\n }\n newDelta.insert(op.insert, attributes)\n prevWasInvalidImage = invalid\n return newDelta\n }, new Delta())\n}\n\n/**\n * 将delta中的图片替换成制定的图片数组,用于图片上传到服务器的场景\n * @param delta 原始delta\n * @param imageUrls 图片数组\n * @param imagePlaceholder 标识是否是占位图的数组,与图片数组一一对应\n * @return 替换之后的delta\n */\nexport function replaceDeltaImage(delta, imageUrls, imagePlaceholder) {\n let imageIndex = 0\n return delta.reduce((newDelta, op) => {\n if (op.insert.image && !op.insert.image.hasExisted) {\n const imageUrl = imageUrls[imageIndex]\n // 替换失败时丢弃无效占位图,避免留下 //:0 + alt=image\n if (!imageUrl && isInvalidPasteImageSrc(getPasteImageSrc(op.insert.image))) {\n imageIndex++\n return newDelta\n }\n let attributes = imagePlaceholder[imageIndex]\n ? { ...op.attributes, width: 'auto', height: 225 } // 占位图片应该固定大小\n : op.attributes\n if (attributes?.alt === 'image') {\n attributes = { ...attributes }\n delete attributes.alt\n }\n newDelta.insert({ image: imageUrl }, attributes)\n imageIndex++\n }\n else {\n newDelta.insert(op.insert, op.attributes)\n }\n return newDelta\n }, new Delta())\n}\n\nexport function splitWithBreak(insertContent: string) {\n const lines = []\n const insertStr = insertContent\n let start = 0\n for (let i = 0; i < insertContent.length; i++) {\n if (insertStr.charAt(i) === '\\n') {\n if (i === 0) {\n lines.push('\\n')\n }\n else {\n lines.push(insertStr.substring(start, i))\n lines.push('\\n')\n }\n start = i + 1\n }\n }\n\n const tailStr = insertStr.substring(start)\n if (tailStr) {\n lines.push(tailStr)\n }\n\n return lines\n}\n\n/**\n * getEventComposedPath\n * compatibility fixed for Event.path/Event.composedPath\n * Event.path is only for chrome/opera\n * Event.composedPath is for Safari, FF\n * Neither for Micro Edge\n * @return an array of event.path\n */\nexport function getEventComposedPath(evt) {\n let path\n // chrome, opera, safari, firefox\n path = evt.path || (evt.composedPath && evt.composedPath())\n\n // other: edge\n if (path === undefined && evt.target) {\n path = []\n let target = evt.target\n path.push(target)\n\n while (target && target.parentNode) {\n target = target.parentNode\n path.push(target)\n }\n }\n\n return path\n}\n\nexport function sanitize(url, protocols) {\n const anchor = document.createElement('a')\n anchor.href = url\n const protocol = anchor.href.slice(0, anchor.href.indexOf(':'))\n return protocols.includes(protocol)\n}\n\nexport function hadProtocol(url: string) {\n if (!url || !/^(?:f|ht)tps?\\:\\/\\//.test(url)) {\n return false\n }\n return true\n}\n\nexport function isInside(position, dom) {\n const areaPosition = dom.getBoundingClientRect()\n const { pageX, pageY } = position\n // getBoundingClientRect是不考虑窗口滚动的\n const left = pageX - window.scrollX\n const top = pageY - window.scrollY\n const {\n left: areaLeft,\n top: areaTop,\n width: areaWidth,\n height: areaHeight,\n } = areaPosition\n const inside\n = left > areaLeft\n && left < areaLeft + areaWidth\n && top > areaTop\n && top < areaTop + areaHeight\n return inside\n}\n\n// Internet Explorer 6-11\nexport const isPureIE = !!document.documentMode\n\n/**\n* 检测剪贴板数据是否来自 Outlook 客户端\n*/\nexport const isOutlookDesktop = (e) => {\n const types = e.clipboardData?.types || [];\n const html = e.clipboardData?.getData('text/html') || '';\n\n // RTF + Office 命名空间 或 RTF + Mso 样式类\n return types.includes('text/rtf') && (/schemas-microsoft-com:office/.test(html) || /class=\"?Mso\\w+/i.test(html));\n}\n"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { isNullOrUndefined } from "./editor.utils.es.js";
2
- import { getEventComposedPath, hadProtocol, hexToRgbA, imageFileToUrl, imageUrlToFile, insideTable, isInside, isOutlookDesktop, isPureIE, omit, replaceDeltaImage, sanitize, splitWithBreak } from "./editor.utils.es.js";
2
+ import { getEventComposedPath, getPasteImageSrc, hadProtocol, hexToRgbA, imageFileToUrl, imageUrlToFile, insideTable, isInside, isInvalidPasteImageSrc, isOutlookDesktop, isPureIE, normalizeOutlookPasteImages, omit, replaceDeltaImage, sanitize, splitWithBreak } from "./editor.utils.es.js";
3
3
  import { AUDIO_VIDEO_UPLOADER_MIME_TYPES, BIG_DELTA_LIMIT, CHANGE_LANGUAGE_EVENT, COMPRESSED_UPLOADER_MIME_TYPES, DOC_UPLOADER_MIME_TYPES, FILE_UPLOADER_MIME_TYPES, IMAGE_UPLOADER_MIME_TYPES, LANG_CONF, OTHER_FILE_UPLOADER_MIME_TYPES, PPT_UPLOADER_MIME_TYPES, XSL_UPLOADER_MIME_TYPES, defaultLanguage } from "./editor.config.es.js";
4
4
  function inputFile(type, accept) {
5
5
  var _a, _b, _c;
@@ -53,6 +53,7 @@ export {
53
53
  defaultLanguage,
54
54
  getEventComposedPath,
55
55
  getListValue,
56
+ getPasteImageSrc,
56
57
  hadProtocol,
57
58
  hexToRgbA,
58
59
  imageFileToUrl,
@@ -60,10 +61,12 @@ export {
60
61
  inputFile,
61
62
  insideTable,
62
63
  isInside,
64
+ isInvalidPasteImageSrc,
63
65
  isNullOrUndefined,
64
66
  isOutlookDesktop,
65
67
  isPureIE,
66
68
  namespace,
69
+ normalizeOutlookPasteImages,
67
70
  omit,
68
71
  replaceDeltaImage,
69
72
  sanitize,
package/es/index.es.js CHANGED
@@ -3,7 +3,7 @@ import { getListValue, inputFile, namespace } from "./config/index.es.js";
3
3
  import { generateToolbarTip } from "./modules/toolbar/toolbar-tip.es.js";
4
4
  import FluentEditor from "./core/fluent-editor.es.js";
5
5
  import { AUDIO_VIDEO_UPLOADER_MIME_TYPES, BIG_DELTA_LIMIT, CHANGE_LANGUAGE_EVENT, COMPRESSED_UPLOADER_MIME_TYPES, DOC_UPLOADER_MIME_TYPES, FILE_UPLOADER_MIME_TYPES, IMAGE_UPLOADER_MIME_TYPES, LANG_CONF, OTHER_FILE_UPLOADER_MIME_TYPES, PPT_UPLOADER_MIME_TYPES, XSL_UPLOADER_MIME_TYPES, defaultLanguage } from "./config/editor.config.es.js";
6
- import { getEventComposedPath, hadProtocol, hexToRgbA, imageFileToUrl, imageUrlToFile, insideTable, isInside, isNullOrUndefined, isOutlookDesktop, isPureIE, omit, replaceDeltaImage, sanitize, splitWithBreak } from "./config/editor.utils.es.js";
6
+ import { getEventComposedPath, getPasteImageSrc, hadProtocol, hexToRgbA, imageFileToUrl, imageUrlToFile, insideTable, isInside, isInvalidPasteImageSrc, isNullOrUndefined, isOutlookDesktop, isPureIE, normalizeOutlookPasteImages, omit, replaceDeltaImage, sanitize, splitWithBreak } from "./config/editor.utils.es.js";
7
7
  export {
8
8
  AUDIO_VIDEO_UPLOADER_MIME_TYPES,
9
9
  BIG_DELTA_LIMIT,
@@ -21,6 +21,7 @@ export {
21
21
  generateToolbarTip,
22
22
  getEventComposedPath,
23
23
  getListValue,
24
+ getPasteImageSrc,
24
25
  hadProtocol,
25
26
  hexToRgbA,
26
27
  imageFileToUrl,
@@ -28,10 +29,12 @@ export {
28
29
  inputFile,
29
30
  insideTable,
30
31
  isInside,
32
+ isInvalidPasteImageSrc,
31
33
  isNullOrUndefined,
32
34
  isOutlookDesktop,
33
35
  isPureIE,
34
36
  namespace,
37
+ normalizeOutlookPasteImages,
35
38
  omit,
36
39
  replaceDeltaImage,
37
40
  sanitize,
@@ -1,7 +1,7 @@
1
1
  import Quill from "quill";
2
2
  import { ERROR_IMAGE_PLACEHOLDER_EN, ERROR_IMAGE_PLACEHOLDER_CN } from "../config/base64-image.es.js";
3
3
  import { BIG_DELTA_LIMIT } from "../config/editor.config.es.js";
4
- import { isNullOrUndefined, isOutlookDesktop, insideTable, replaceDeltaImage, imageFileToUrl, imageUrlToFile, splitWithBreak, omit, hexToRgbA } from "../config/editor.utils.es.js";
4
+ import { isNullOrUndefined, isOutlookDesktop, normalizeOutlookPasteImages, insideTable, replaceDeltaImage, imageFileToUrl, imageUrlToFile, splitWithBreak, omit, hexToRgbA } from "../config/editor.utils.es.js";
5
5
  const Clipboard = Quill.import("modules/clipboard");
6
6
  const Delta = Quill.import("delta");
7
7
  class CustomClipboard extends Clipboard {
@@ -92,7 +92,7 @@ class CustomClipboard extends Clipboard {
92
92
  if (html.search(msExcelCheck) !== -1) {
93
93
  result.html = renderStyles(html);
94
94
  }
95
- if (msWordCheck1.test(html) || msWordCheck2.test(html)) {
95
+ if (msWordCheck1.test(html) || msWordCheck2.test(html) || isOutlookDesktop(e)) {
96
96
  result.rtf = e.clipboardData.getData("text/rtf");
97
97
  }
98
98
  this.onPaste(range, result);
@@ -104,6 +104,7 @@ class CustomClipboard extends Clipboard {
104
104
  const formats = this.quill.getFormat(range.index);
105
105
  let pastedDelta = this.convert({ text, html }, formats);
106
106
  pastedDelta = replaceDeltaWhiteSpace(pastedDelta, rootBgColor);
107
+ pastedDelta = normalizeOutlookPasteImages(pastedDelta);
107
108
  const deltaLength = pastedDelta.ops.length;
108
109
  let loadingTipsContainer;
109
110
  if (deltaLength > BIG_DELTA_LIMIT) {
@@ -174,10 +175,8 @@ class CustomClipboard extends Clipboard {
174
175
  const delta = oldDelta.concat(pastedContent);
175
176
  setTimeout(() => {
176
177
  this.quill.updateContents(delta, Quill.sources.USER);
177
- this.quill.setSelection(
178
- delta.length() - linePos.length - linePos.fix,
179
- Quill.sources.SILENT
180
- );
178
+ const newSelectionIndex = linePos.index + (pastedContent.length ? pastedContent.length() : 0);
179
+ this.quill.setSelection(newSelectionIndex, Quill.sources.SILENT);
181
180
  this.quill.scrollIntoView();
182
181
  if (loadingTipsContainer) {
183
182
  loadingTipsContainer.remove();
@@ -250,8 +249,7 @@ class CustomClipboard extends Clipboard {
250
249
  resolve(originalUrls[index]);
251
250
  });
252
251
  } else if ((_c = this.quill.options.uploadOption) == null ? void 0 : _c.imageUploadToServer) {
253
- const range = this.getImgSelection(pastedDelta, imageIndexs[index]);
254
- this.quill.uploader.upload(range, [imageFile]);
252
+ return imageFileToUrl(imageFile);
255
253
  } else {
256
254
  return imageFileToUrl(imageFile);
257
255
  }
@@ -337,7 +335,7 @@ class CustomClipboard extends Clipboard {
337
335
  file = await imageUrlToFile(newImage || image.src || image);
338
336
  } catch (_err) {
339
337
  if (clipboardFiles.length !== 0) {
340
- const clipboardFile = clipboardFiles[0];
338
+ const clipboardFile = clipboardFiles.shift();
341
339
  const imageType = ((_a = clipboardFile.type) == null ? void 0 : _a.indexOf("image")) === -1 ? "image/png" : clipboardFile.type;
342
340
  const blob = clipboardFile.slice(0, clipboardFile.size, imageType);
343
341
  file = new File([blob], `image-CORS-${(/* @__PURE__ */ new Date()).getTime()}.png`, {
@@ -362,6 +360,8 @@ class CustomClipboard extends Clipboard {
362
360
  }
363
361
  if (typeof op.insert === "string") {
364
362
  length += op.insert.length;
363
+ } else if (typeof op.insert === "object") {
364
+ length += 1;
365
365
  }
366
366
  return true;
367
367
  });
@@ -1 +1 @@
1
- {"version":3,"file":"custom-clipboard.es.js","sources":["../../../src/modules/custom-clipboard.ts"],"sourcesContent":["import type { Parchment as TypeParchment } from 'quill'\nimport type TypeBlock from 'quill/blots/block'\nimport type TypeClipboard from 'quill/modules/clipboard'\nimport type FluentEditor from '../fluent-editor'\nimport Quill from 'quill'\nimport {\n ERROR_IMAGE_PLACEHOLDER_CN,\n ERROR_IMAGE_PLACEHOLDER_EN,\n} from '../config/base64-image'\nimport { BIG_DELTA_LIMIT } from '../config/editor.config'\nimport {\n hexToRgbA,\n imageFileToUrl,\n imageUrlToFile,\n insideTable,\n isNullOrUndefined,\n isOutlookDesktop,\n omit,\n replaceDeltaImage,\n splitWithBreak,\n} from '../config/editor.utils'\n\nconst Clipboard = Quill.import('modules/clipboard') as typeof TypeClipboard\nconst Delta = Quill.import('delta')\n\nclass CustomClipboard extends Clipboard {\n quill: FluentEditor\n convert\n onCopy\n matchers\n\n prepareMatching(container, nodeMatches) {\n const elementMatchers = []\n const textMatchers = []\n this.matchers.forEach((pair) => {\n const [selector, matcher] = pair\n switch (selector) {\n case Node.TEXT_NODE:\n textMatchers.push(matcher)\n break\n case Node.ELEMENT_NODE:\n elementMatchers.push(matcher)\n break\n default: {\n // word 的 v:shape 系列标签只能通过 getElementsByTagName 获取\n const vRegex = /v:(.+)/\n const nodeList = vRegex.test(selector)\n ? Array.from(container.getElementsByTagName(selector))\n : Array.from(container.querySelectorAll(selector))\n nodeList.forEach((node) => {\n if (nodeMatches.has(node)) {\n const matches = nodeMatches.get(node)\n matches.push(matcher)\n }\n else {\n nodeMatches.set(node, [matcher])\n }\n })\n break\n }\n }\n })\n return [elementMatchers, textMatchers]\n }\n\n onCaptureCopy(e, isCut = false) {\n if (e.defaultPrevented) {\n return\n }\n e.preventDefault()\n const [range] = this.quill.selection.getRange()\n if (isNullOrUndefined(range)) {\n return\n }\n const { html, text } = this.onCopy(range, isCut)\n\n // 兼容IE11浏览器`\n if (!e.clipboardData) {\n e.clipboardData = {\n types: 'text/plain',\n setData: (_type, value) => {\n // @ts-ignore\n return window.clipboardData.setData('Text', value)\n },\n }\n }\n\n // 复制代码时移除utf8中产生的不间断空格\\u00A0\n let plainText = text\n if (html.startsWith('<pre>')) {\n plainText = text.replace(/\\u00A0/g, ' ')\n }\n\n e.clipboardData.setData('text/html', html)\n e.clipboardData.setData('text/plain', plainText)\n if (isCut) {\n this.quill.deleteText(range, Quill.sources.USER)\n }\n }\n\n onCapturePaste(e: ClipboardEvent) {\n if (e.defaultPrevented || !this.quill.isEnabled()) {\n return\n }\n e.preventDefault()\n const range = this.quill.getSelection(true)\n if (isNullOrUndefined(range)) {\n return\n }\n\n // 兼容IE11浏览器\n if (!e.clipboardData) {\n // @ts-ignore\n e.clipboardData = {\n types: 'text/plain',\n getData: () => {\n // @ts-ignore\n return window.clipboardData.getData('Text')\n },\n }\n }\n\n const html = e.clipboardData.getData('text/html')\n const text = e.clipboardData.getData('text/plain')\n const files = Array.from(e.clipboardData.files || [])\n const msExcelCheck = /<meta.*?Microsoft Excel\\s[\\d].*?>/\n\n if (html.search(msExcelCheck) === -1 && files.length > 0 && !isOutlookDesktop(e)) {\n this.quill.uploader.upload(range, files)\n }\n else {\n const msWordCheck1\n = /<meta\\s*name=\"?generator\"?\\s*content=\"?microsoft\\s*word\\s*\\d+\"?\\/?>/i\n const msWordCheck2 = /xmlns:o=\"urn:schemas-microsoft-com/i\n const result = { html, text, files, rtf: null }\n if (html.search(msExcelCheck) !== -1) {\n result.html = renderStyles(html)\n }\n if (msWordCheck1.test(html) || msWordCheck2.test(html)) {\n // TODO: 当word文档包含heading时text/rtf读取为空,无法获取hex图片,待修复。可参考ckeditor5/issues/2493\n result.rtf = e.clipboardData.getData('text/rtf')\n }\n this.onPaste(range, result)\n }\n }\n\n onPaste(range, { html, text, files: clipboardFiles, rtf }) {\n const hexImages = this.extractImageDataFromRtf(rtf)\n const rootBgColor = getComputedStyle(this.quill.root).backgroundColor\n const formats = this.quill.getFormat(range.index)\n let pastedDelta = this.convert({ text, html }, formats)\n pastedDelta = replaceDeltaWhiteSpace(pastedDelta, rootBgColor)\n const deltaLength = pastedDelta.ops.length\n\n let loadingTipsContainer\n if (deltaLength > BIG_DELTA_LIMIT) {\n loadingTipsContainer = this.quill.addContainer('ql-loading-tips')\n loadingTipsContainer.innerHTML = this.quill.getLangText('pasting')\n }\n\n const linePos = { index: range.index, length: range.length, fix: 0 }\n const [line, offset] = this.quill.getLine(range.index)\n const isInsideTable = insideTable.call(this)\n\n const handlePasteContent = (content: any) => {\n let pastedContent = content\n // fix: 阻止粘贴代码块和引用导致表格断裂\n const tableBreaker = pastedContent.ops.find((op) => {\n return (\n op.attributes\n && (op.attributes.blockquote || op.attributes['code-block'])\n )\n })\n if (isInsideTable) {\n // fix: 阻止带有表格内容粘贴在表格里\n const table = line.domNode.closest('table.quill-better-table')\n const tableBlot = Quill.find(table) as TypeParchment.Blot\n const tableIndex = this.quill.getIndex(tableBlot)\n const tableLength = tableBlot.length()\n const tableEndPos = tableIndex + tableLength\n const anchorNode = getSelection().anchorNode\n if (tableBreaker) {\n return\n }\n if (formats['table-col']) {\n // fix: 光标在表格前端的table-col处时,获取整个表格的index后以此为基准向前移动一位插入粘贴内容且不删除任何内容\n linePos.index = tableIndex - 1\n linePos.length = 0\n }\n else if (\n range.index === tableEndPos - 1\n && anchorNode instanceof HTMLDivElement\n && anchorNode.classList.contains('quill-better-table-wrapper')\n ) {\n const list = pastedContent.filter(\n op => op.attributes && op.attributes.list,\n )\n if (list && list.length) {\n return\n }\n // fix: 光标在表格末端时,向后移动一位插入粘贴内容且不删除任何内容\n // TODO\n // 当表格最后一格有内容时,没法区分在表格最后一格最末尾和光标在表格后这两种情况,它们的 range 是一样\n // 这会导致在这两处粘贴表格内容都会将该内容粘贴到表格下一行中\n linePos.index = tableEndPos\n linePos.length = 0\n }\n else {\n if (!formats['table-cell-line']) {\n return\n }\n // fix: 解决表格内粘贴问题\n // 缺陷描述:将表格内的换行文本复制粘贴到别的单元格,会导致表格断开\n // 原因是:换行的文本delta对象有问题,delta对象前面多了一个纯换行和表格控制头(table-col)\n // 解决方法:将多余的delta项移除\n pastedContent = {\n ops: pastedContent.filter((op, index) => {\n const regexp = /^[\\n\\r]+$/\n const isString = op.insert && typeof op.insert === 'string'\n const isLine = isString && regexp.test(op.insert)\n const isCellLine\n = isLine && op.attributes && op.attributes['table-cell-line']\n const isList = isLine && op.attributes && op.attributes.list\n const isPureLine = isLine && !isCellLine && !isList\n const isTableCol\n = isLine && op.attributes && op.attributes['table-col']\n const isLastCellLine = isCellLine && index === deltaLength - 1\n return !isPureLine && !isTableCol && !isLastCellLine\n }),\n }\n // fix: 解决从表格外粘贴多行文本导致表格断开的问题\n pastedContent = rebuildDelta(\n new Delta(pastedContent.ops),\n formats['table-cell-line'],\n )\n }\n }\n\n // fix: 粘贴内容末尾为List,且粘贴位置的block或table-cell-line无内容则删除该block或table-cell-line\n // TODO 这里的lastChild如果不存在,则可能报错\n const lastChild = pastedContent.ops[pastedContent.ops.length - 1]\n const hasList\n = lastChild && lastChild.attributes && lastChild.attributes.list\n if (\n hasList\n && offset === 0\n && line\n && (line as TypeBlock).cache.length === 1\n && (line.statics.blotName === 'block'\n || line.statics.blotName === 'table-cell-line')\n && (!line.next || line.next.statics.blotName !== 'table-view')\n ) {\n linePos.index = this.quill.getIndex(line)\n linePos.length = line.length()\n linePos.fix = 1\n }\n\n const oldDelta = new Delta().retain(linePos.index).delete(linePos.length)\n const delta = oldDelta.concat(pastedContent)\n\n setTimeout(() => {\n this.quill.updateContents(delta, Quill.sources.USER)\n this.quill.setSelection(\n delta.length() - linePos.length - linePos.fix,\n Quill.sources.SILENT,\n )\n this.quill.scrollIntoView()\n if (loadingTipsContainer) {\n loadingTipsContainer.remove()\n }\n })\n }\n\n ;(async () => {\n try {\n const [files, placeholders, originalUrls, imageIndexs] = this.flipFilesArray(\n await this.extractFilesFromDelta(\n pastedDelta,\n clipboardFiles,\n hexImages,\n ),\n )\n\n if (files.length === 0) {\n handlePasteContent(pastedDelta)\n }\n else {\n if (this.quill.options.editorPaste && this.quill.options.editorPaste.observers.length !== 0) {\n // 设置editorPaste回调的情况\n this.quill.options.editorPaste.emit({\n files,\n callback: ({ code, message, data }) => {\n if (code === 0) {\n const { imageUrls } = data\n pastedDelta = replaceDeltaImage(\n pastedDelta,\n imageUrls,\n placeholders,\n )\n handlePasteContent(pastedDelta)\n }\n else {\n console.error('error message:', message)\n }\n },\n })\n }\n else {\n // 没有originalUrls 也没有文件粘贴\n if (files[0] !== undefined || originalUrls.length === 0) {\n // 没有设置editorPaste回调的情况下,File格式的占位图需要手动转换成url格式,插入到编辑器中\n const imageUrls = await this.files2urls(\n files,\n placeholders,\n originalUrls,\n pastedDelta,\n imageIndexs,\n )\n pastedDelta = replaceDeltaImage(\n pastedDelta,\n imageUrls,\n placeholders,\n )\n }\n handlePasteContent(pastedDelta)\n }\n }\n }\n catch (_e) {\n throw new Error('Paste failed.')\n }\n })()\n }\n\n files2urls(files, placeholders, originalUrls, pastedDelta, imageIndexs) {\n return Promise.all(\n files.map(async (imageFile, index) => {\n const netImgExp = /^((http|https)\\:)?\\/\\/([\\s\\S]+)$/\n let imageUrl = originalUrls[index]\n // 粘贴 Outlook 中的网络图\n if (originalUrls[index]?.src && originalUrls[index]?.src !== '//:0') {\n imageUrl = originalUrls[index].src\n }\n if (\n !placeholders[index]\n && originalUrls[index]\n && netImgExp.test(imageUrl)\n ) {\n // 不是占位图的普通url图片直接返回url\n return new Promise((resolve) => {\n resolve(originalUrls[index])\n })\n }\n else if (this.quill.options.uploadOption?.imageUploadToServer) {\n const range = this.getImgSelection(pastedDelta, imageIndexs[index])\n this.quill.uploader.upload(range, [imageFile])\n }\n else {\n // 占位图或者跨域图或 Outlook 中的本地图需要手动转换成url格式\n return imageFileToUrl(imageFile)\n }\n }),\n )\n }\n\n flipFilesArray(filesArr) {\n const files = []\n const placeholders = []\n const originalUrls = []\n const imageIndexs = []\n filesArr.forEach((item: any) => {\n if (item) {\n const [file, placeholder, originalUrl, imageIndex] = item\n files.push(file)\n placeholders.push(placeholder)\n originalUrls.push(originalUrl)\n if (imageIndex === 0 || imageIndex) {\n imageIndexs.push(imageIndex)\n }\n }\n })\n return [files, placeholders, originalUrls, imageIndexs]\n }\n\n // 将图片从hex转为base64\n convertHexToBase64(hexString) {\n return btoa(\n hexString\n .match(/\\w{2}/g)\n .map((char) => {\n return String.fromCharCode(Number.parseInt(char, 16))\n })\n .join(''),\n )\n }\n\n // 匹配rtf中的图片,存储为{hex, type}对象数组\n extractImageDataFromRtf(rtfData) {\n if (!rtfData) {\n return []\n }\n\n const regexPictureHeader\n = /{\\\\pict[\\s\\S]+?\\\\bliptag-?\\d+(\\\\blipupi-?\\d+)?({\\\\\\*\\\\blipuid\\s?[\\da-fA-F]+)?[\\s}]*?/\n const regexPicture = new RegExp(\n `(?:(${regexPictureHeader.source}))([\\\\da-fA-F\\\\s]+?)\\\\}`, // 非贪婪匹配\n 'g',\n )\n const images = rtfData.match(regexPicture)\n const result = []\n\n if (images) {\n for (const image of images) {\n let imageType = ''\n\n if (image.includes('\\\\pngblip')) {\n imageType = 'image/png'\n }\n else if (image.includes('\\\\jpegblip')) {\n imageType = 'image/jpeg'\n }\n\n if (imageType) {\n result.push({\n hex: image\n .replace(regexPictureHeader, '')\n .replace(/[^\\da-fA-F]/g, ''),\n type: imageType,\n })\n }\n }\n }\n\n return result\n }\n\n extractFilesFromDelta(delta, clipboardFiles, hexImages?) {\n let index = -1\n return Promise.all(\n delta.map(async (op) => {\n index++\n const image = op.insert.image\n if (!image || image.hasExisted) {\n return\n }\n\n let file\n let isPlaceholderImage = false\n let imageIndex\n try {\n // hex 图片存在则为 file:/// 协议本地图片,使用 hex 图片转为 base64 读取\n const hexImage = hexImages.length && hexImages.shift()\n const newImage\n = hexImage\n && `data:${hexImage.type};base64,${this.convertHexToBase64(\n hexImage.hex,\n )}`\n imageIndex = index\n file = await imageUrlToFile(newImage || image.src || image)\n }\n catch (_err) {\n if (clipboardFiles.length !== 0) {\n // 跨域获取图片失败时从剪切板获取图片\n const clipboardFile = clipboardFiles[0]\n const imageType\n = clipboardFile.type?.indexOf('image') === -1\n ? 'image/png'\n : clipboardFile.type\n const blob = clipboardFile.slice(0, clipboardFile.size, imageType)\n file = new File([blob], `image-CORS-${new Date().getTime()}.png`, {\n type: imageType,\n })\n }\n else if (image.src.startsWith('http')) {\n // 什么都不做\n }\n else {\n // 剪切板中无图片,用失败占位图替换\n const errorImagePlaceholderJpg\n = this.quill.getLangText('img-error') === 'Image Copy Error'\n ? ERROR_IMAGE_PLACEHOLDER_EN\n : ERROR_IMAGE_PLACEHOLDER_CN\n file = await imageUrlToFile(errorImagePlaceholderJpg, true)\n isPlaceholderImage = true\n }\n }\n\n return [file, isPlaceholderImage, image, imageIndex]\n }),\n )\n }\n\n getImgSelection(delta, imageIndex) {\n let length = 0\n delta.ops.every((op, index) => {\n if (index === imageIndex) {\n return false\n }\n if (typeof op.insert === 'string') {\n length += op.insert.length\n }\n return true\n })\n const range = {\n index: length,\n length: 0,\n }\n return range\n }\n}\n\nfunction rebuildDelta(delta, cellLine) {\n const { cell: cellId, colspan, row: rowId, rowspan } = cellLine\n const buildedDelta = delta.reduce((newDelta, op) => {\n if (op.insert && typeof op.insert === 'string') {\n const lines = splitWithBreak(op.insert)\n\n lines.forEach((text) => {\n if (text === '\\n') {\n // 对换行增加 table-cell-line 格式,以避免表格断开\n newDelta.insert('\\n', {\n ...op.attributes,\n 'table-cell-line': { row: rowId, cell: cellId, rowspan, colspan },\n })\n }\n else {\n text = text.endsWith('\\r') ? text.slice(0, -1) : text\n newDelta.insert(\n text,\n omit(op.attributes, ['table', 'table-cell-line']),\n )\n }\n })\n }\n else {\n newDelta.insert(op.insert, op.attributes)\n }\n\n return newDelta\n }, new Delta())\n\n return buildedDelta\n}\n\nfunction replaceStrWhiteSpace(str) {\n const isWhiteSpace = value => /^(\\u3000|\\u0020){1}$/.test(value) // 空白字符\n let textWithWhiteSpace = ''\n let beginHasChar = false\n for (const char of str) {\n if (isWhiteSpace(char) && !beginHasChar) {\n textWithWhiteSpace += '\\u00A0'\n }\n else {\n textWithWhiteSpace += char\n beginHasChar = true\n }\n }\n return textWithWhiteSpace\n}\n\nfunction replaceDeltaWhiteSpace(delta, rootBgColor?) {\n return delta.reduce((newDelta, op) => {\n // fix: 当粘贴文字颜色和编辑器背景色一致且自身无背景色的情况下移除文字颜色样式,避免误导用户粘贴无效\n if (\n rootBgColor\n && op.attributes\n && op.attributes.color\n && !op.attributes.background\n ) {\n const originColor = op.attributes.color\n const fontColor\n = originColor.indexOf('#') === 0 ? hexToRgbA(originColor) : originColor\n if (\n fontColor === rootBgColor\n || (fontColor === 'rgba(255,255,255,1)'\n && rootBgColor === 'rgba(0, 0, 0, 0)')\n ) {\n delete op.attributes.color\n }\n }\n if (op.insert && typeof op.insert === 'string') {\n const lines = splitWithBreak(op.insert)\n let insertWithWhiteSpace = ''\n lines.forEach((text) => {\n insertWithWhiteSpace += replaceStrWhiteSpace(text)\n })\n newDelta.insert(insertWithWhiteSpace, op.attributes)\n }\n else {\n newDelta.insert(op.insert, op.attributes)\n }\n return newDelta\n }, new Delta())\n}\n\nfunction renderStyles(html) {\n let htmlString = html\n // Trim unnecessary parts.\n htmlString = htmlString.substring(\n htmlString.indexOf('<html '),\n htmlString.length,\n )\n htmlString = htmlString.substring(\n 0,\n htmlString.lastIndexOf('</html>') + '</html>'.length,\n )\n\n // Add temporary iframe.\n const iframe = document.createElement('iframe')\n iframe.style.display = 'none'\n document.body.appendChild(iframe)\n\n const iframeDoc = iframe.contentDocument || iframe.contentWindow.document\n iframeDoc.open()\n iframeDoc.write(htmlString)\n iframeDoc.close()\n\n let collection\n let pointer\n const rules\n = iframeDoc.styleSheets[iframeDoc.styleSheets.length - 1].cssRules\n\n // Convert internal styles to inline style of respective node.\n for (let idx = 0; idx < rules.length; idx++) {\n if ((rules[idx] as CSSStyleRule).selectorText === '') {\n continue\n }\n collection = iframeDoc.body.querySelectorAll(\n (rules[idx] as CSSStyleRule).selectorText,\n )\n\n for (pointer = 0; pointer < collection.length; pointer++) {\n collection[pointer].style.cssText += (\n rules[idx] as CSSStyleRule\n ).style.cssText\n }\n }\n\n // @ts-ignore\n const convertedString = iframeDoc.firstChild.outerHTML\n // Remove temporary iframe.\n iframe.parentNode.removeChild(iframe)\n\n return convertedString\n}\n\nexport default CustomClipboard\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"custom-clipboard.es.js","sources":["../../../src/modules/custom-clipboard.ts"],"sourcesContent":["import type { Parchment as TypeParchment } from 'quill'\nimport type TypeBlock from 'quill/blots/block'\nimport type TypeClipboard from 'quill/modules/clipboard'\nimport type FluentEditor from '../fluent-editor'\nimport Quill from 'quill'\nimport {\n ERROR_IMAGE_PLACEHOLDER_CN,\n ERROR_IMAGE_PLACEHOLDER_EN,\n} from '../config/base64-image'\nimport { BIG_DELTA_LIMIT } from '../config/editor.config'\nimport {\n hexToRgbA,\n imageFileToUrl,\n imageUrlToFile,\n insideTable,\n isNullOrUndefined,\n isOutlookDesktop,\n normalizeOutlookPasteImages,\n omit,\n replaceDeltaImage,\n splitWithBreak,\n} from '../config/editor.utils'\n\nconst Clipboard = Quill.import('modules/clipboard') as typeof TypeClipboard\nconst Delta = Quill.import('delta')\n\nclass CustomClipboard extends Clipboard {\n quill: FluentEditor\n convert\n onCopy\n matchers\n\n prepareMatching(container, nodeMatches) {\n const elementMatchers = []\n const textMatchers = []\n this.matchers.forEach((pair) => {\n const [selector, matcher] = pair\n switch (selector) {\n case Node.TEXT_NODE:\n textMatchers.push(matcher)\n break\n case Node.ELEMENT_NODE:\n elementMatchers.push(matcher)\n break\n default: {\n // word 的 v:shape 系列标签只能通过 getElementsByTagName 获取\n const vRegex = /v:(.+)/\n const nodeList = vRegex.test(selector)\n ? Array.from(container.getElementsByTagName(selector))\n : Array.from(container.querySelectorAll(selector))\n nodeList.forEach((node) => {\n if (nodeMatches.has(node)) {\n const matches = nodeMatches.get(node)\n matches.push(matcher)\n }\n else {\n nodeMatches.set(node, [matcher])\n }\n })\n break\n }\n }\n })\n return [elementMatchers, textMatchers]\n }\n\n onCaptureCopy(e, isCut = false) {\n if (e.defaultPrevented) {\n return\n }\n e.preventDefault()\n const [range] = this.quill.selection.getRange()\n if (isNullOrUndefined(range)) {\n return\n }\n const { html, text } = this.onCopy(range, isCut)\n\n // 兼容IE11浏览器`\n if (!e.clipboardData) {\n e.clipboardData = {\n types: 'text/plain',\n setData: (_type, value) => {\n // @ts-ignore\n return window.clipboardData.setData('Text', value)\n },\n }\n }\n\n // 复制代码时移除utf8中产生的不间断空格\\u00A0\n let plainText = text\n if (html.startsWith('<pre>')) {\n plainText = text.replace(/\\u00A0/g, ' ')\n }\n\n e.clipboardData.setData('text/html', html)\n e.clipboardData.setData('text/plain', plainText)\n if (isCut) {\n this.quill.deleteText(range, Quill.sources.USER)\n }\n }\n\n onCapturePaste(e: ClipboardEvent) {\n if (e.defaultPrevented || !this.quill.isEnabled()) {\n return\n }\n e.preventDefault()\n const range = this.quill.getSelection(true)\n if (isNullOrUndefined(range)) {\n return\n }\n\n // 兼容IE11浏览器\n if (!e.clipboardData) {\n // @ts-ignore\n e.clipboardData = {\n types: 'text/plain',\n getData: () => {\n // @ts-ignore\n return window.clipboardData.getData('Text')\n },\n }\n }\n\n const html = e.clipboardData.getData('text/html')\n const text = e.clipboardData.getData('text/plain')\n const files = Array.from(e.clipboardData.files || [])\n const msExcelCheck = /<meta.*?Microsoft Excel\\s[\\d].*?>/\n\n if (html.search(msExcelCheck) === -1 && files.length > 0 && !isOutlookDesktop(e)) {\n this.quill.uploader.upload(range, files)\n }\n else {\n const msWordCheck1\n = /<meta\\s*name=\"?generator\"?\\s*content=\"?microsoft\\s*word\\s*\\d+\"?\\/?>/i\n const msWordCheck2 = /xmlns:o=\"urn:schemas-microsoft-com/i\n const result = { html, text, files, rtf: null }\n if (html.search(msExcelCheck) !== -1) {\n result.html = renderStyles(html)\n }\n if (msWordCheck1.test(html) || msWordCheck2.test(html) || isOutlookDesktop(e)) {\n // TODO: 当word文档包含heading时text/rtf读取为空,无法获取hex图片,待修复。可参考ckeditor5/issues/2493\n result.rtf = e.clipboardData.getData('text/rtf')\n }\n this.onPaste(range, result)\n }\n }\n\n onPaste(range, { html, text, files: clipboardFiles, rtf }) {\n const hexImages = this.extractImageDataFromRtf(rtf)\n const rootBgColor = getComputedStyle(this.quill.root).backgroundColor\n const formats = this.quill.getFormat(range.index)\n let pastedDelta = this.convert({ text, html }, formats)\n pastedDelta = replaceDeltaWhiteSpace(pastedDelta, rootBgColor)\n // Outlook:v:imagedata 与 <img alt=image> 会生成重复图片,需先去重\n pastedDelta = normalizeOutlookPasteImages(pastedDelta)\n const deltaLength = pastedDelta.ops.length\n\n let loadingTipsContainer\n if (deltaLength > BIG_DELTA_LIMIT) {\n loadingTipsContainer = this.quill.addContainer('ql-loading-tips')\n loadingTipsContainer.innerHTML = this.quill.getLangText('pasting')\n }\n\n const linePos = { index: range.index, length: range.length, fix: 0 }\n const [line, offset] = this.quill.getLine(range.index)\n const isInsideTable = insideTable.call(this)\n\n const handlePasteContent = (content: any) => {\n let pastedContent = content\n // fix: 阻止粘贴代码块和引用导致表格断裂\n const tableBreaker = pastedContent.ops.find((op) => {\n return (\n op.attributes\n && (op.attributes.blockquote || op.attributes['code-block'])\n )\n })\n if (isInsideTable) {\n // fix: 阻止带有表格内容粘贴在表格里\n const table = line.domNode.closest('table.quill-better-table')\n const tableBlot = Quill.find(table) as TypeParchment.Blot\n const tableIndex = this.quill.getIndex(tableBlot)\n const tableLength = tableBlot.length()\n const tableEndPos = tableIndex + tableLength\n const anchorNode = getSelection().anchorNode\n if (tableBreaker) {\n return\n }\n if (formats['table-col']) {\n // fix: 光标在表格前端的table-col处时,获取整个表格的index后以此为基准向前移动一位插入粘贴内容且不删除任何内容\n linePos.index = tableIndex - 1\n linePos.length = 0\n }\n else if (\n range.index === tableEndPos - 1\n && anchorNode instanceof HTMLDivElement\n && anchorNode.classList.contains('quill-better-table-wrapper')\n ) {\n const list = pastedContent.filter(\n op => op.attributes && op.attributes.list,\n )\n if (list && list.length) {\n return\n }\n // fix: 光标在表格末端时,向后移动一位插入粘贴内容且不删除任何内容\n // TODO\n // 当表格最后一格有内容时,没法区分在表格最后一格最末尾和光标在表格后这两种情况,它们的 range 是一样\n // 这会导致在这两处粘贴表格内容都会将该内容粘贴到表格下一行中\n linePos.index = tableEndPos\n linePos.length = 0\n }\n else {\n if (!formats['table-cell-line']) {\n return\n }\n // fix: 解决表格内粘贴问题\n // 缺陷描述:将表格内的换行文本复制粘贴到别的单元格,会导致表格断开\n // 原因是:换行的文本delta对象有问题,delta对象前面多了一个纯换行和表格控制头(table-col)\n // 解决方法:将多余的delta项移除\n pastedContent = {\n ops: pastedContent.filter((op, index) => {\n const regexp = /^[\\n\\r]+$/\n const isString = op.insert && typeof op.insert === 'string'\n const isLine = isString && regexp.test(op.insert)\n const isCellLine\n = isLine && op.attributes && op.attributes['table-cell-line']\n const isList = isLine && op.attributes && op.attributes.list\n const isPureLine = isLine && !isCellLine && !isList\n const isTableCol\n = isLine && op.attributes && op.attributes['table-col']\n const isLastCellLine = isCellLine && index === deltaLength - 1\n return !isPureLine && !isTableCol && !isLastCellLine\n }),\n }\n // fix: 解决从表格外粘贴多行文本导致表格断开的问题\n pastedContent = rebuildDelta(\n new Delta(pastedContent.ops),\n formats['table-cell-line'],\n )\n }\n }\n\n // fix: 粘贴内容末尾为List,且粘贴位置的block或table-cell-line无内容则删除该block或table-cell-line\n // TODO 这里的lastChild如果不存在,则可能报错\n const lastChild = pastedContent.ops[pastedContent.ops.length - 1]\n const hasList\n = lastChild && lastChild.attributes && lastChild.attributes.list\n if (\n hasList\n && offset === 0\n && line\n && (line as TypeBlock).cache.length === 1\n && (line.statics.blotName === 'block'\n || line.statics.blotName === 'table-cell-line')\n && (!line.next || line.next.statics.blotName !== 'table-view')\n ) {\n linePos.index = this.quill.getIndex(line)\n linePos.length = line.length()\n linePos.fix = 1\n }\n\n const oldDelta = new Delta().retain(linePos.index).delete(linePos.length)\n const delta = oldDelta.concat(pastedContent)\n\n setTimeout(() => {\n this.quill.updateContents(delta, Quill.sources.USER)\n // 光标应落在粘贴内容之后:原位置 + 粘贴内容长度\n const newSelectionIndex = linePos.index + (pastedContent.length ? pastedContent.length() : 0)\n this.quill.setSelection(newSelectionIndex, Quill.sources.SILENT)\n this.quill.scrollIntoView()\n if (loadingTipsContainer) {\n loadingTipsContainer.remove()\n }\n })\n }\n\n ;(async () => {\n try {\n const [files, placeholders, originalUrls, imageIndexs] = this.flipFilesArray(\n await this.extractFilesFromDelta(\n pastedDelta,\n clipboardFiles,\n hexImages,\n ),\n )\n\n if (files.length === 0) {\n handlePasteContent(pastedDelta)\n }\n else {\n if (this.quill.options.editorPaste && this.quill.options.editorPaste.observers.length !== 0) {\n // 设置editorPaste回调的情况\n this.quill.options.editorPaste.emit({\n files,\n callback: ({ code, message, data }) => {\n if (code === 0) {\n const { imageUrls } = data\n pastedDelta = replaceDeltaImage(\n pastedDelta,\n imageUrls,\n placeholders,\n )\n handlePasteContent(pastedDelta)\n }\n else {\n console.error('error message:', message)\n }\n },\n })\n }\n else {\n // 没有originalUrls 也没有文件粘贴\n if (files[0] !== undefined || originalUrls.length === 0) {\n // 没有设置editorPaste回调的情况下,File格式的占位图需要手动转换成url格式,插入到编辑器中\n const imageUrls = await this.files2urls(\n files,\n placeholders,\n originalUrls,\n pastedDelta,\n imageIndexs,\n )\n pastedDelta = replaceDeltaImage(\n pastedDelta,\n imageUrls,\n placeholders,\n )\n }\n handlePasteContent(pastedDelta)\n }\n }\n }\n catch (_e) {\n throw new Error('Paste failed.')\n }\n })()\n }\n\n files2urls(files, placeholders, originalUrls, pastedDelta, imageIndexs) {\n return Promise.all(\n files.map(async (imageFile, index) => {\n const netImgExp = /^((http|https)\\:)?\\/\\/([\\s\\S]+)$/\n let imageUrl = originalUrls[index]\n // 粘贴 Outlook 中的网络图\n if (originalUrls[index]?.src && originalUrls[index]?.src !== '//:0') {\n imageUrl = originalUrls[index].src\n }\n if (\n !placeholders[index]\n && originalUrls[index]\n && netImgExp.test(imageUrl)\n ) {\n // 不是占位图的普通url图片直接返回url\n return new Promise((resolve) => {\n resolve(originalUrls[index])\n })\n }\n else if (this.quill.options.uploadOption?.imageUploadToServer) {\n // 粘贴场景只替换 delta 中的图片地址,避免再走 uploader.upload 插入第二张图\n return imageFileToUrl(imageFile)\n }\n else {\n // 占位图或者跨域图或 Outlook 中的本地图需要手动转换成url格式\n return imageFileToUrl(imageFile)\n }\n }),\n )\n }\n\n flipFilesArray(filesArr) {\n const files = []\n const placeholders = []\n const originalUrls = []\n const imageIndexs = []\n filesArr.forEach((item: any) => {\n if (item) {\n const [file, placeholder, originalUrl, imageIndex] = item\n files.push(file)\n placeholders.push(placeholder)\n originalUrls.push(originalUrl)\n if (imageIndex === 0 || imageIndex) {\n imageIndexs.push(imageIndex)\n }\n }\n })\n return [files, placeholders, originalUrls, imageIndexs]\n }\n\n // 将图片从hex转为base64\n convertHexToBase64(hexString) {\n return btoa(\n hexString\n .match(/\\w{2}/g)\n .map((char) => {\n return String.fromCharCode(Number.parseInt(char, 16))\n })\n .join(''),\n )\n }\n\n // 匹配rtf中的图片,存储为{hex, type}对象数组\n extractImageDataFromRtf(rtfData) {\n if (!rtfData) {\n return []\n }\n\n const regexPictureHeader\n = /{\\\\pict[\\s\\S]+?\\\\bliptag-?\\d+(\\\\blipupi-?\\d+)?({\\\\\\*\\\\blipuid\\s?[\\da-fA-F]+)?[\\s}]*?/\n const regexPicture = new RegExp(\n `(?:(${regexPictureHeader.source}))([\\\\da-fA-F\\\\s]+?)\\\\}`, // 非贪婪匹配\n 'g',\n )\n const images = rtfData.match(regexPicture)\n const result = []\n\n if (images) {\n for (const image of images) {\n let imageType = ''\n\n if (image.includes('\\\\pngblip')) {\n imageType = 'image/png'\n }\n else if (image.includes('\\\\jpegblip')) {\n imageType = 'image/jpeg'\n }\n\n if (imageType) {\n result.push({\n hex: image\n .replace(regexPictureHeader, '')\n .replace(/[^\\da-fA-F]/g, ''),\n type: imageType,\n })\n }\n }\n }\n\n return result\n }\n\n extractFilesFromDelta(delta, clipboardFiles, hexImages?) {\n let index = -1\n return Promise.all(\n delta.map(async (op) => {\n index++\n const image = op.insert.image\n if (!image || image.hasExisted) {\n return\n }\n\n let file\n let isPlaceholderImage = false\n let imageIndex\n try {\n // hex 图片存在则为 file:/// 协议本地图片,使用 hex 图片转为 base64 读取\n const hexImage = hexImages.length && hexImages.shift()\n const newImage\n = hexImage\n && `data:${hexImage.type};base64,${this.convertHexToBase64(\n hexImage.hex,\n )}`\n imageIndex = index\n file = await imageUrlToFile(newImage || image.src || image)\n }\n catch (_err) {\n if (clipboardFiles.length !== 0) {\n // 跨域获取图片失败时从剪切板获取图片\n const clipboardFile = clipboardFiles.shift()\n const imageType\n = clipboardFile.type?.indexOf('image') === -1\n ? 'image/png'\n : clipboardFile.type\n const blob = clipboardFile.slice(0, clipboardFile.size, imageType)\n file = new File([blob], `image-CORS-${new Date().getTime()}.png`, {\n type: imageType,\n })\n }\n else if (image.src.startsWith('http')) {\n // 什么都不做\n }\n else {\n // 剪切板中无图片,用失败占位图替换\n const errorImagePlaceholderJpg\n = this.quill.getLangText('img-error') === 'Image Copy Error'\n ? ERROR_IMAGE_PLACEHOLDER_EN\n : ERROR_IMAGE_PLACEHOLDER_CN\n file = await imageUrlToFile(errorImagePlaceholderJpg, true)\n isPlaceholderImage = true\n }\n }\n\n return [file, isPlaceholderImage, image, imageIndex]\n }),\n )\n }\n\n getImgSelection(delta, imageIndex) {\n let length = 0\n delta.ops.every((op, index) => {\n if (index === imageIndex) {\n return false\n }\n if (typeof op.insert === 'string') {\n length += op.insert.length\n }\n else if (typeof op.insert === 'object') {\n // 图片、提及等 embed 长度为 1\n length += 1\n }\n return true\n })\n const range = {\n index: length,\n length: 0,\n }\n return range\n }\n}\n\nfunction rebuildDelta(delta, cellLine) {\n const { cell: cellId, colspan, row: rowId, rowspan } = cellLine\n const buildedDelta = delta.reduce((newDelta, op) => {\n if (op.insert && typeof op.insert === 'string') {\n const lines = splitWithBreak(op.insert)\n\n lines.forEach((text) => {\n if (text === '\\n') {\n // 对换行增加 table-cell-line 格式,以避免表格断开\n newDelta.insert('\\n', {\n ...op.attributes,\n 'table-cell-line': { row: rowId, cell: cellId, rowspan, colspan },\n })\n }\n else {\n text = text.endsWith('\\r') ? text.slice(0, -1) : text\n newDelta.insert(\n text,\n omit(op.attributes, ['table', 'table-cell-line']),\n )\n }\n })\n }\n else {\n newDelta.insert(op.insert, op.attributes)\n }\n\n return newDelta\n }, new Delta())\n\n return buildedDelta\n}\n\nfunction replaceStrWhiteSpace(str) {\n const isWhiteSpace = value => /^(\\u3000|\\u0020){1}$/.test(value) // 空白字符\n let textWithWhiteSpace = ''\n let beginHasChar = false\n for (const char of str) {\n if (isWhiteSpace(char) && !beginHasChar) {\n textWithWhiteSpace += '\\u00A0'\n }\n else {\n textWithWhiteSpace += char\n beginHasChar = true\n }\n }\n return textWithWhiteSpace\n}\n\nfunction replaceDeltaWhiteSpace(delta, rootBgColor?) {\n return delta.reduce((newDelta, op) => {\n // fix: 当粘贴文字颜色和编辑器背景色一致且自身无背景色的情况下移除文字颜色样式,避免误导用户粘贴无效\n if (\n rootBgColor\n && op.attributes\n && op.attributes.color\n && !op.attributes.background\n ) {\n const originColor = op.attributes.color\n const fontColor\n = originColor.indexOf('#') === 0 ? hexToRgbA(originColor) : originColor\n if (\n fontColor === rootBgColor\n || (fontColor === 'rgba(255,255,255,1)'\n && rootBgColor === 'rgba(0, 0, 0, 0)')\n ) {\n delete op.attributes.color\n }\n }\n if (op.insert && typeof op.insert === 'string') {\n const lines = splitWithBreak(op.insert)\n let insertWithWhiteSpace = ''\n lines.forEach((text) => {\n insertWithWhiteSpace += replaceStrWhiteSpace(text)\n })\n newDelta.insert(insertWithWhiteSpace, op.attributes)\n }\n else {\n newDelta.insert(op.insert, op.attributes)\n }\n return newDelta\n }, new Delta())\n}\n\nfunction renderStyles(html) {\n let htmlString = html\n // Trim unnecessary parts.\n htmlString = htmlString.substring(\n htmlString.indexOf('<html '),\n htmlString.length,\n )\n htmlString = htmlString.substring(\n 0,\n htmlString.lastIndexOf('</html>') + '</html>'.length,\n )\n\n // Add temporary iframe.\n const iframe = document.createElement('iframe')\n iframe.style.display = 'none'\n document.body.appendChild(iframe)\n\n const iframeDoc = iframe.contentDocument || iframe.contentWindow.document\n iframeDoc.open()\n iframeDoc.write(htmlString)\n iframeDoc.close()\n\n let collection\n let pointer\n const rules\n = iframeDoc.styleSheets[iframeDoc.styleSheets.length - 1].cssRules\n\n // Convert internal styles to inline style of respective node.\n for (let idx = 0; idx < rules.length; idx++) {\n if ((rules[idx] as CSSStyleRule).selectorText === '') {\n continue\n }\n collection = iframeDoc.body.querySelectorAll(\n (rules[idx] as CSSStyleRule).selectorText,\n )\n\n for (pointer = 0; pointer < collection.length; pointer++) {\n collection[pointer].style.cssText += (\n rules[idx] as CSSStyleRule\n ).style.cssText\n }\n }\n\n // @ts-ignore\n const convertedString = iframeDoc.firstChild.outerHTML\n // Remove temporary iframe.\n iframe.parentNode.removeChild(iframe)\n\n return convertedString\n}\n\nexport default CustomClipboard\n"],"names":[],"mappings":"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"}
@@ -258,6 +258,9 @@ function matchWordShapeImage(node, delta) {
258
258
  var _a;
259
259
  if (node) {
260
260
  const imageUrl = (_a = node.attributes.src) == null ? void 0 : _a.nodeValue;
261
+ if (!imageUrl) {
262
+ return delta;
263
+ }
261
264
  delta = new Delta().insert({ image: imageUrl });
262
265
  }
263
266
  return delta;
@@ -1 +1 @@
1
- {"version":3,"file":"node-matchers.es.js","sources":["../../../../../src/modules/table/utils/node-matchers.ts"],"sourcesContent":["import Quill from 'quill'\nimport { omit, splitWithBreak } from '../../../config/editor.utils'\nimport { cellId as tableCellId, rowId as tableRowId, TableViewWrapper } from '../formats/table'\nimport { CELL_MIN_WIDTH } from '../table-config'\n\nconst Delta = Quill.imports.delta\nconst InlineBlot = Quill.imports.parchment.InlineBlot\n\n// rebuild delta\nexport function matchTableCell(node, delta) {\n // fix: 移除旧数据中的pt高度,避免由于高度平均分导致无法插入行\n if (node.style.height.indexOf('pt')) {\n node.removeAttribute('style')\n }\n\n const row = node.parentNode\n let rowId = row.dataset.row\n if (!rowId) {\n rowId = row.dataset.row = tableRowId()\n }\n let cellId = node.dataset.cell\n // fix: dataset.cell in td will be 'undefined' when insert row/column\n if (!cellId || cellId === 'undefined') {\n cellId = tableCellId()\n }\n const colspan = node.getAttribute('colspan') || 1\n const rowspan = node.getAttribute('rowspan') || 1\n\n // fix: empty table cells copied from other place will be removed unexpectedly\n if (delta.length() === 0) {\n delta = new Delta().insert('\\n', {\n 'table-cell-line': { row: rowId, cell: cellId, rowspan, colspan },\n })\n return delta\n }\n\n delta = delta.reduce((newDelta, op) => {\n if (op.insert && typeof op.insert === 'string') {\n const lines = splitWithBreak(op.insert)\n\n lines.forEach((text) => {\n if (text === '\\n') {\n let attributes = {}\n const cellAttributes = {\n row: rowId,\n cell: cellId,\n rowspan,\n colspan,\n }\n if (op.attributes.table) {\n delete op.attributes.table\n }\n switch (true) {\n case !!op.attributes.header:\n attributes = Object.assign(op.attributes.header, cellAttributes)\n break\n case !!op.attributes.list:\n attributes = { list: Object.assign(op.attributes.list, cellAttributes) }\n break\n default:\n attributes = { 'table-cell-line': cellAttributes }\n }\n // fix: when td has background-color, quill can't set it to table-cell bolt\n if (op.attributes.background && attributes['table-cell-line']) {\n attributes['table-cell-line'].tdBgColor = op.attributes.background\n }\n newDelta.insert('\\n', Object.assign(op.attributes, attributes))\n }\n else {\n newDelta.insert(text, omit(op.attributes, ['table', 'table-cell-line', 'header', 'list']))\n }\n })\n }\n else {\n newDelta.insert(op.insert, op.attributes)\n }\n\n return newDelta\n }, new Delta())\n\n // fix: table cell height becomes larger(because insert unnecessary <div> on both sides of cell) when init table ngModel\n const regexp = /^[\\n]+$/\n const firstDelta = delta.ops[0]\n if (delta.ops.length >= 3) {\n const lastDelta = delta.ops[delta.ops.length - 1]\n if (regexp.test(firstDelta.insert) && firstDelta.attributes['table-cell-line']) {\n delta.ops.splice(0, 1)\n }\n if (regexp.test(lastDelta.insert) && lastDelta.attributes['table-cell-line']) {\n delta.ops[delta.ops.length - 1].insert = '\\n'\n }\n }\n else if (delta.ops.length === 1 && regexp.test(firstDelta.insert) && firstDelta.attributes['table-cell-line']) {\n delta.ops[0].insert = '\\n'\n }\n\n return delta\n}\n\n// replace th tag with td tag\nexport function matchTableHeader(node, delta, _scroll) {\n const row = node.parentNode\n const cells = Array.from(row.querySelectorAll('th'))\n let rowId = row.dataset.row\n if (!rowId) {\n rowId = row.dataset.row = tableRowId()\n }\n const cellId = cells.indexOf(node) + 1\n const colspan = node.getAttribute('colspan') || false\n const rowspan = node.getAttribute('rowspan') || false\n\n // fix: empty table cells copied from other place will be removed unexpectedly\n if (delta.length() === 0) {\n delta = new Delta().insert('\\n', {\n 'table-cell-line': { row: rowId, cell: cellId, rowspan, colspan },\n })\n return delta\n }\n\n delta = delta.reduce((newDelta, op) => {\n if (op.insert && typeof op.insert === 'string') {\n const lines = splitWithBreak(op.insert)\n\n // fix: no '\\n' in the end of op.insert, push a '\\n' to lines\n if (lines[lines.length - 1] !== '\\n') {\n lines.push('\\n')\n }\n\n lines.forEach((text) => {\n text === '\\n'\n ? newDelta.insert('\\n', { 'table-cell-line': { row: rowId, cell: cellId, rowspan, colspan } })\n : newDelta.insert(text, op.attributes)\n })\n }\n else {\n newDelta.insert(op.insert, op.attributes)\n }\n\n return newDelta\n }, new Delta())\n\n delta = delta.reduce((newDelta, op) => {\n if (op.insert && typeof op.insert === 'string' && op.insert.startsWith('\\n')) {\n newDelta.insert(op.insert, { 'table-cell-line': { row: rowId, cell: cellId, rowspan, colspan } })\n }\n else {\n newDelta.insert(op.insert, { ...omit(op.attributes, ['table', 'table-cell-line']) })\n }\n\n return newDelta\n }, new Delta())\n\n return delta\n}\n\n// supplement colgroup and col\nexport function matchTable(node, delta, scroll) {\n const isWordTable = node.children.length === 1\n if (!(node instanceof Element)) {\n return\n }\n const getMaxColNumber = (tds) => {\n if (isWordTable) {\n return tds.length\n }\n let colsNumber = 0\n tds.forEach((td) => {\n colsNumber += td.colSpan\n })\n return Math.max(tds.length, colsNumber)\n }\n\n const checkMinWidth = (width) => {\n if (Number.isNaN(width)) {\n // 无指定值时默认为auto,待渲染后修正\n return { 'table-col': { width: 'auto' } }\n }\n else if (width < CELL_MIN_WIDTH) {\n // 当列宽度小于默认宽度时取默认宽度\n return { 'table-col': true }\n }\n else {\n // 大于默认值取实际指定值\n return { 'table-col': { width } }\n }\n }\n\n // fix: a table with an empty tr is invalid, should not be displayed\n const rows = node.querySelectorAll('tr')\n const topRow = rows[0]\n const onlyEmptyTr = rows.length === 1 && !topRow.querySelector('td')\n\n // fix: empty table will return empty delta\n if (!topRow || onlyEmptyTr) {\n return new Delta().insert('\\n')\n }\n\n const colsNumber = node.querySelectorAll('col').length\n let maxCellsNumber = 0\n let maxCells\n // 遍历行获取最大列数和该行的所有单元格\n Array.prototype.slice.call(rows).forEach((row) => {\n const tds = row.querySelectorAll('td')\n maxCellsNumber = Math.max(getMaxColNumber(tds), maxCellsNumber)\n maxCells = tds\n })\n\n // 列的累计器\n let colCount = 0\n delta = delta.reduce((newDelta, op) => {\n // 当colCount与colsNumber相等时,则补充相差列\n if (colCount === colsNumber) {\n const fillNumber = maxCellsNumber - colCount\n const outset = colCount\n // index为差值列索引,通过遍历差值得到mexCells行中对应索引的单元格宽度\n for (let i = 0; i < fillNumber; i++) {\n const index = outset + i\n const colWidth = Number.parseInt(\n index < maxCells.length\n ? maxCells[index].width\n // maxCells[index].style && maxCells[index].style.width ? maxCells[index].style.width :\n : maxCells[maxCells.length - 1].width,\n 10,\n )\n newDelta.insert('\\n', checkMinWidth(colWidth))\n colCount++\n }\n }\n const attr = op.attributes || {}\n switch (true) {\n case !!attr['table-col']:\n // 只有当前列数小于实际总列数才操作,所以不存在大于的情况\n if (colCount < maxCellsNumber) {\n // 当table-col宽度一致时会合并为单一insert,insert长度大于1,截取符合实际总列数的长度来插入\n const insert = op.insert.slice(0, maxCellsNumber)\n const colWidth = Number.parseInt(attr['table-col'].width, 10)\n newDelta.insert(insert, checkMinWidth(colWidth))\n colCount += insert.length\n }\n break\n case !!attr.notFilled:\n { // 将标记的空tr填充对应列数的单元格\n const rowId = tableRowId()\n for (let x = 0; x < maxCellsNumber; x++) {\n newDelta.insert('\\n', { 'table-cell-line': { row: rowId, cell: tableCellId(), rowspan: 1, colspan: 1 } })\n }\n break }\n default:\n newDelta.insert(op.insert, op.attributes)\n }\n return newDelta\n }, new Delta())\n\n const tableItem = node.closest('.quill-better-table-wrapper') || node\n const prevBlot = tableItem.previousElementSibling && scroll.query(tableItem.previousElementSibling)\n const nextBlot = tableItem.nextElementSibling && scroll.query(tableItem.nextElementSibling)\n // fix: prevent two adjacent tables from sticking together\n if (!nextBlot || nextBlot.prototype instanceof InlineBlot) {\n delta = delta.insert('\\n')\n }\n // fix: When there is no line break in front of the table, pressing the Enter key will cause a problem with the table.\n if (!prevBlot || prevBlot.prototype instanceof InlineBlot) {\n const newLine = new Delta().insert('\\n')\n delta = newLine.concat(delta)\n }\n if (nextBlot === TableViewWrapper) {\n delta = delta.insert('\\n')\n }\n\n return delta\n}\n\nexport function matchTableRow(_node, delta) {\n // fix: 处理空<tr>标签被忽略的情况\n if (delta.ops.length === 1 && !delta.ops[0].attributes) {\n delta = new Delta().insert('\\n', { notFilled: true })\n }\n return delta\n}\n\n// match h tags, distinguish between headers in the table and headers outside the table\nexport function matchHeader(node, delta) {\n const newDelta = new Delta()\n const fontSize = node.style.fontSize\n delta.forEach((op) => {\n newDelta.insert(\n op.insert,\n Object.assign({}, op.attributes, {\n size: fontSize,\n }),\n )\n })\n return newDelta\n}\n\nexport function matchList(node, delta) {\n const value = node.tagName === 'UL' ? 'bullet' : 'ordered'\n delta.forEach((op) => {\n if (typeof op.attributes.list === 'string') {\n delete op.attributes.list\n }\n else if (typeof op.attributes.list === 'object' && !op.attributes.list.value) {\n op.attributes.list.value = value\n }\n })\n return delta\n}\n\nexport function matchInline(node, delta, scroll) {\n const quill = Quill.find(scroll.domNode.parentNode)\n const currentRange = quill.getSelection()\n const formats = currentRange && quill.getFormat(currentRange)\n if (\n formats\n && formats['table-cell-line'] // 当前光标节点在表格内,否则不操作delta\n && node.nextElementSibling\n ) {\n // 插入节点是否存在下一个兄弟元素\n const match = scroll.query(node)\n const nodeHtml = node.nextElementSibling.innerHTML\n const nodeText = node.nextElementSibling.textContent\n if (\n (match && match.prototype instanceof InlineBlot) // 判断当前节点是否为内联\n || (node.tagName === 'P' && nodeHtml !== nodeText)\n ) {\n // 非内联时如果为P且下一个不为text节点\n delta.forEach((op) => {\n op.insert += '\\n'\n })\n }\n }\n return delta\n}\n\n// 匹配 word 自带的 v:shape 标签中的图片 v:imageData\nexport function matchWordShapeImage(node, delta) {\n if (node) {\n const imageUrl = node.attributes.src?.nodeValue\n delta = new Delta().insert({ image: imageUrl })\n }\n return delta\n}\n\nexport function matchMentionLink(node, delta, scroll) {\n const name = node.dataset.mentionId\n if (name) {\n const quill = Quill.find(scroll.domNode.parentNode)\n const mention = quill.getModule('mention')\n if (mention) {\n mention.options.search(name).then((res) => {\n const [item] = res\n if (item) {\n mention.options.select(item)\n }\n })\n }\n }\n return delta\n}\n"],"names":["rowId","tableRowId","cellId","tableCellId","colsNumber"],"mappings":"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"}
1
+ {"version":3,"file":"node-matchers.es.js","sources":["../../../../../src/modules/table/utils/node-matchers.ts"],"sourcesContent":["import Quill from 'quill'\nimport { omit, splitWithBreak } from '../../../config/editor.utils'\nimport { cellId as tableCellId, rowId as tableRowId, TableViewWrapper } from '../formats/table'\nimport { CELL_MIN_WIDTH } from '../table-config'\n\nconst Delta = Quill.imports.delta\nconst InlineBlot = Quill.imports.parchment.InlineBlot\n\n// rebuild delta\nexport function matchTableCell(node, delta) {\n // fix: 移除旧数据中的pt高度,避免由于高度平均分导致无法插入行\n if (node.style.height.indexOf('pt')) {\n node.removeAttribute('style')\n }\n\n const row = node.parentNode\n let rowId = row.dataset.row\n if (!rowId) {\n rowId = row.dataset.row = tableRowId()\n }\n let cellId = node.dataset.cell\n // fix: dataset.cell in td will be 'undefined' when insert row/column\n if (!cellId || cellId === 'undefined') {\n cellId = tableCellId()\n }\n const colspan = node.getAttribute('colspan') || 1\n const rowspan = node.getAttribute('rowspan') || 1\n\n // fix: empty table cells copied from other place will be removed unexpectedly\n if (delta.length() === 0) {\n delta = new Delta().insert('\\n', {\n 'table-cell-line': { row: rowId, cell: cellId, rowspan, colspan },\n })\n return delta\n }\n\n delta = delta.reduce((newDelta, op) => {\n if (op.insert && typeof op.insert === 'string') {\n const lines = splitWithBreak(op.insert)\n\n lines.forEach((text) => {\n if (text === '\\n') {\n let attributes = {}\n const cellAttributes = {\n row: rowId,\n cell: cellId,\n rowspan,\n colspan,\n }\n if (op.attributes.table) {\n delete op.attributes.table\n }\n switch (true) {\n case !!op.attributes.header:\n attributes = Object.assign(op.attributes.header, cellAttributes)\n break\n case !!op.attributes.list:\n attributes = { list: Object.assign(op.attributes.list, cellAttributes) }\n break\n default:\n attributes = { 'table-cell-line': cellAttributes }\n }\n // fix: when td has background-color, quill can't set it to table-cell bolt\n if (op.attributes.background && attributes['table-cell-line']) {\n attributes['table-cell-line'].tdBgColor = op.attributes.background\n }\n newDelta.insert('\\n', Object.assign(op.attributes, attributes))\n }\n else {\n newDelta.insert(text, omit(op.attributes, ['table', 'table-cell-line', 'header', 'list']))\n }\n })\n }\n else {\n newDelta.insert(op.insert, op.attributes)\n }\n\n return newDelta\n }, new Delta())\n\n // fix: table cell height becomes larger(because insert unnecessary <div> on both sides of cell) when init table ngModel\n const regexp = /^[\\n]+$/\n const firstDelta = delta.ops[0]\n if (delta.ops.length >= 3) {\n const lastDelta = delta.ops[delta.ops.length - 1]\n if (regexp.test(firstDelta.insert) && firstDelta.attributes['table-cell-line']) {\n delta.ops.splice(0, 1)\n }\n if (regexp.test(lastDelta.insert) && lastDelta.attributes['table-cell-line']) {\n delta.ops[delta.ops.length - 1].insert = '\\n'\n }\n }\n else if (delta.ops.length === 1 && regexp.test(firstDelta.insert) && firstDelta.attributes['table-cell-line']) {\n delta.ops[0].insert = '\\n'\n }\n\n return delta\n}\n\n// replace th tag with td tag\nexport function matchTableHeader(node, delta, _scroll) {\n const row = node.parentNode\n const cells = Array.from(row.querySelectorAll('th'))\n let rowId = row.dataset.row\n if (!rowId) {\n rowId = row.dataset.row = tableRowId()\n }\n const cellId = cells.indexOf(node) + 1\n const colspan = node.getAttribute('colspan') || false\n const rowspan = node.getAttribute('rowspan') || false\n\n // fix: empty table cells copied from other place will be removed unexpectedly\n if (delta.length() === 0) {\n delta = new Delta().insert('\\n', {\n 'table-cell-line': { row: rowId, cell: cellId, rowspan, colspan },\n })\n return delta\n }\n\n delta = delta.reduce((newDelta, op) => {\n if (op.insert && typeof op.insert === 'string') {\n const lines = splitWithBreak(op.insert)\n\n // fix: no '\\n' in the end of op.insert, push a '\\n' to lines\n if (lines[lines.length - 1] !== '\\n') {\n lines.push('\\n')\n }\n\n lines.forEach((text) => {\n text === '\\n'\n ? newDelta.insert('\\n', { 'table-cell-line': { row: rowId, cell: cellId, rowspan, colspan } })\n : newDelta.insert(text, op.attributes)\n })\n }\n else {\n newDelta.insert(op.insert, op.attributes)\n }\n\n return newDelta\n }, new Delta())\n\n delta = delta.reduce((newDelta, op) => {\n if (op.insert && typeof op.insert === 'string' && op.insert.startsWith('\\n')) {\n newDelta.insert(op.insert, { 'table-cell-line': { row: rowId, cell: cellId, rowspan, colspan } })\n }\n else {\n newDelta.insert(op.insert, { ...omit(op.attributes, ['table', 'table-cell-line']) })\n }\n\n return newDelta\n }, new Delta())\n\n return delta\n}\n\n// supplement colgroup and col\nexport function matchTable(node, delta, scroll) {\n const isWordTable = node.children.length === 1\n if (!(node instanceof Element)) {\n return\n }\n const getMaxColNumber = (tds) => {\n if (isWordTable) {\n return tds.length\n }\n let colsNumber = 0\n tds.forEach((td) => {\n colsNumber += td.colSpan\n })\n return Math.max(tds.length, colsNumber)\n }\n\n const checkMinWidth = (width) => {\n if (Number.isNaN(width)) {\n // 无指定值时默认为auto,待渲染后修正\n return { 'table-col': { width: 'auto' } }\n }\n else if (width < CELL_MIN_WIDTH) {\n // 当列宽度小于默认宽度时取默认宽度\n return { 'table-col': true }\n }\n else {\n // 大于默认值取实际指定值\n return { 'table-col': { width } }\n }\n }\n\n // fix: a table with an empty tr is invalid, should not be displayed\n const rows = node.querySelectorAll('tr')\n const topRow = rows[0]\n const onlyEmptyTr = rows.length === 1 && !topRow.querySelector('td')\n\n // fix: empty table will return empty delta\n if (!topRow || onlyEmptyTr) {\n return new Delta().insert('\\n')\n }\n\n const colsNumber = node.querySelectorAll('col').length\n let maxCellsNumber = 0\n let maxCells\n // 遍历行获取最大列数和该行的所有单元格\n Array.prototype.slice.call(rows).forEach((row) => {\n const tds = row.querySelectorAll('td')\n maxCellsNumber = Math.max(getMaxColNumber(tds), maxCellsNumber)\n maxCells = tds\n })\n\n // 列的累计器\n let colCount = 0\n delta = delta.reduce((newDelta, op) => {\n // 当colCount与colsNumber相等时,则补充相差列\n if (colCount === colsNumber) {\n const fillNumber = maxCellsNumber - colCount\n const outset = colCount\n // index为差值列索引,通过遍历差值得到mexCells行中对应索引的单元格宽度\n for (let i = 0; i < fillNumber; i++) {\n const index = outset + i\n const colWidth = Number.parseInt(\n index < maxCells.length\n ? maxCells[index].width\n // maxCells[index].style && maxCells[index].style.width ? maxCells[index].style.width :\n : maxCells[maxCells.length - 1].width,\n 10,\n )\n newDelta.insert('\\n', checkMinWidth(colWidth))\n colCount++\n }\n }\n const attr = op.attributes || {}\n switch (true) {\n case !!attr['table-col']:\n // 只有当前列数小于实际总列数才操作,所以不存在大于的情况\n if (colCount < maxCellsNumber) {\n // 当table-col宽度一致时会合并为单一insert,insert长度大于1,截取符合实际总列数的长度来插入\n const insert = op.insert.slice(0, maxCellsNumber)\n const colWidth = Number.parseInt(attr['table-col'].width, 10)\n newDelta.insert(insert, checkMinWidth(colWidth))\n colCount += insert.length\n }\n break\n case !!attr.notFilled:\n { // 将标记的空tr填充对应列数的单元格\n const rowId = tableRowId()\n for (let x = 0; x < maxCellsNumber; x++) {\n newDelta.insert('\\n', { 'table-cell-line': { row: rowId, cell: tableCellId(), rowspan: 1, colspan: 1 } })\n }\n break }\n default:\n newDelta.insert(op.insert, op.attributes)\n }\n return newDelta\n }, new Delta())\n\n const tableItem = node.closest('.quill-better-table-wrapper') || node\n const prevBlot = tableItem.previousElementSibling && scroll.query(tableItem.previousElementSibling)\n const nextBlot = tableItem.nextElementSibling && scroll.query(tableItem.nextElementSibling)\n // fix: prevent two adjacent tables from sticking together\n if (!nextBlot || nextBlot.prototype instanceof InlineBlot) {\n delta = delta.insert('\\n')\n }\n // fix: When there is no line break in front of the table, pressing the Enter key will cause a problem with the table.\n if (!prevBlot || prevBlot.prototype instanceof InlineBlot) {\n const newLine = new Delta().insert('\\n')\n delta = newLine.concat(delta)\n }\n if (nextBlot === TableViewWrapper) {\n delta = delta.insert('\\n')\n }\n\n return delta\n}\n\nexport function matchTableRow(_node, delta) {\n // fix: 处理空<tr>标签被忽略的情况\n if (delta.ops.length === 1 && !delta.ops[0].attributes) {\n delta = new Delta().insert('\\n', { notFilled: true })\n }\n return delta\n}\n\n// match h tags, distinguish between headers in the table and headers outside the table\nexport function matchHeader(node, delta) {\n const newDelta = new Delta()\n const fontSize = node.style.fontSize\n delta.forEach((op) => {\n newDelta.insert(\n op.insert,\n Object.assign({}, op.attributes, {\n size: fontSize,\n }),\n )\n })\n return newDelta\n}\n\nexport function matchList(node, delta) {\n const value = node.tagName === 'UL' ? 'bullet' : 'ordered'\n delta.forEach((op) => {\n if (typeof op.attributes.list === 'string') {\n delete op.attributes.list\n }\n else if (typeof op.attributes.list === 'object' && !op.attributes.list.value) {\n op.attributes.list.value = value\n }\n })\n return delta\n}\n\nexport function matchInline(node, delta, scroll) {\n const quill = Quill.find(scroll.domNode.parentNode)\n const currentRange = quill.getSelection()\n const formats = currentRange && quill.getFormat(currentRange)\n if (\n formats\n && formats['table-cell-line'] // 当前光标节点在表格内,否则不操作delta\n && node.nextElementSibling\n ) {\n // 插入节点是否存在下一个兄弟元素\n const match = scroll.query(node)\n const nodeHtml = node.nextElementSibling.innerHTML\n const nodeText = node.nextElementSibling.textContent\n if (\n (match && match.prototype instanceof InlineBlot) // 判断当前节点是否为内联\n || (node.tagName === 'P' && nodeHtml !== nodeText)\n ) {\n // 非内联时如果为P且下一个不为text节点\n delta.forEach((op) => {\n op.insert += '\\n'\n })\n }\n }\n return delta\n}\n\n// 匹配 word 自带的 v:shape 标签中的图片 v:imageData\nexport function matchWordShapeImage(node, delta) {\n if (node) {\n const imageUrl = node.attributes.src?.nodeValue\n // 无有效地址时不插入,避免与 <img> 重复生成空图\n if (!imageUrl) {\n return delta\n }\n delta = new Delta().insert({ image: imageUrl })\n }\n return delta\n}\n\nexport function matchMentionLink(node, delta, scroll) {\n const name = node.dataset.mentionId\n if (name) {\n const quill = Quill.find(scroll.domNode.parentNode)\n const mention = quill.getModule('mention')\n if (mention) {\n mention.options.search(name).then((res) => {\n const [item] = res\n if (item) {\n mention.options.select(item)\n }\n })\n }\n }\n return delta\n}\n"],"names":["rowId","tableRowId","cellId","tableCellId","colsNumber"],"mappings":"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"}
@@ -57,12 +57,53 @@ function omit(obj, uselessKeys) {
57
57
  return uselessKeys.includes(key) ? acc : { ...acc, [key]: obj[key] };
58
58
  }, {});
59
59
  }
60
+ function getPasteImageSrc(image) {
61
+ if (!image) return "";
62
+ return typeof image === "string" ? image : image.src || "";
63
+ }
64
+ function isInvalidPasteImageSrc(src) {
65
+ if (!src) return true;
66
+ return src === "//:0" || /^file:/i.test(src) || /^cid:/i.test(src);
67
+ }
68
+ function normalizeOutlookPasteImages(delta) {
69
+ let prevWasInvalidImage = false;
70
+ return delta.reduce((newDelta, op) => {
71
+ var _a;
72
+ if (!((_a = op.insert) == null ? void 0 : _a.image) || op.insert.image.hasExisted) {
73
+ newDelta.insert(op.insert, op.attributes);
74
+ prevWasInvalidImage = false;
75
+ return newDelta;
76
+ }
77
+ const src = getPasteImageSrc(op.insert.image);
78
+ const invalid = isInvalidPasteImageSrc(src);
79
+ if (invalid && prevWasInvalidImage) {
80
+ return newDelta;
81
+ }
82
+ let attributes = op.attributes;
83
+ if ((attributes == null ? void 0 : attributes.alt) === "image") {
84
+ attributes = { ...attributes };
85
+ delete attributes.alt;
86
+ }
87
+ newDelta.insert(op.insert, attributes);
88
+ prevWasInvalidImage = invalid;
89
+ return newDelta;
90
+ }, new Delta());
91
+ }
60
92
  function replaceDeltaImage(delta, imageUrls, imagePlaceholder) {
61
93
  let imageIndex = 0;
62
94
  return delta.reduce((newDelta, op) => {
63
95
  if (op.insert.image && !op.insert.image.hasExisted) {
64
- const attributes = imagePlaceholder[imageIndex] ? { ...op.attributes, width: "auto", height: 225 } : op.attributes;
65
- newDelta.insert({ image: imageUrls[imageIndex] }, attributes);
96
+ const imageUrl = imageUrls[imageIndex];
97
+ if (!imageUrl && isInvalidPasteImageSrc(getPasteImageSrc(op.insert.image))) {
98
+ imageIndex++;
99
+ return newDelta;
100
+ }
101
+ let attributes = imagePlaceholder[imageIndex] ? { ...op.attributes, width: "auto", height: 225 } : op.attributes;
102
+ if ((attributes == null ? void 0 : attributes.alt) === "image") {
103
+ attributes = { ...attributes };
104
+ delete attributes.alt;
105
+ }
106
+ newDelta.insert({ image: imageUrl }, attributes);
66
107
  imageIndex++;
67
108
  } else {
68
109
  newDelta.insert(op.insert, op.attributes);
@@ -139,15 +180,18 @@ const isOutlookDesktop = (e) => {
139
180
  return types.includes("text/rtf") && (/schemas-microsoft-com:office/.test(html) || /class="?Mso\w+/i.test(html));
140
181
  };
141
182
  exports.getEventComposedPath = getEventComposedPath;
183
+ exports.getPasteImageSrc = getPasteImageSrc;
142
184
  exports.hadProtocol = hadProtocol;
143
185
  exports.hexToRgbA = hexToRgbA;
144
186
  exports.imageFileToUrl = imageFileToUrl;
145
187
  exports.imageUrlToFile = imageUrlToFile;
146
188
  exports.insideTable = insideTable;
147
189
  exports.isInside = isInside;
190
+ exports.isInvalidPasteImageSrc = isInvalidPasteImageSrc;
148
191
  exports.isNullOrUndefined = isNullOrUndefined;
149
192
  exports.isOutlookDesktop = isOutlookDesktop;
150
193
  exports.isPureIE = isPureIE;
194
+ exports.normalizeOutlookPasteImages = normalizeOutlookPasteImages;
151
195
  exports.omit = omit;
152
196
  exports.replaceDeltaImage = replaceDeltaImage;
153
197
  exports.sanitize = sanitize;
@@ -1 +1 @@
1
- {"version":3,"file":"editor.utils.cjs.js","sources":["../../../src/config/editor.utils.ts"],"sourcesContent":["import Quill from 'quill'\n\nconst Delta = Quill.import('delta')\n\n// color hex to rgba\nexport function hexToRgbA(hex: string) {\n let color\n if (/^#([A-Fa-f0-9]{3}){1,2}$/.test(hex)) {\n color = hex.substring(1).split('')\n if (color.length === 3) {\n color = [color[0], color[0], color[1], color[1], color[2], color[2]]\n }\n color = `0x${color.join('')}`\n return (\n `rgba(${\n [(color >> 16) & 255, (color >> 8) & 255, color & 255].join(',')\n },1)`\n )\n }\n}\n\n/**\n * 将File格式的图片转换成Url格式\n * @param imageFile File格式的图片\n */\nexport function imageFileToUrl(imageFile) {\n return new Promise((resolve, reject) => {\n const reader = new FileReader()\n reader.readAsDataURL(imageFile)\n reader.onload = function (e) {\n resolve(e.target.result)\n }\n reader.onerror = reject\n }).catch((error) => {\n console.error('Error reading file:', error)\n })\n}\n\n/**\n * 将Url格式的图片转换成File格式\n * @param imageUrl 图片的URL\n */\nexport function imageUrlToFile(imageUrl, isErrorImage?: boolean) {\n return new Promise((resolve, reject) => {\n fetch(imageUrl, {\n method: 'get',\n mode: 'no-cors',\n })\n .then(res => res.blob())\n .then((blob) => {\n if (!blob.type.includes('image') || !blob.type) {\n return reject()\n }\n const fileType = blob.type.replace(/^.*\\//, '')\n const fileName = isErrorImage\n ? 'editorx-error-image.png'\n : `image-${new Date().getTime()}.${fileType}`\n const file = new File([blob], fileName, blob)\n resolve(file)\n })\n .catch(reject)\n })\n}\n\nexport function insideTable(range = null, quill = this.quill) {\n let currentRange = range\n if (!currentRange) {\n currentRange = quill.getSelection()\n }\n // fix: 原有formats方法无法判断表格内的list和head附近粘贴\n const [line] = quill.getLine(currentRange.index)\n return line && !!line.domNode.closest('table.quill-better-table')\n}\n\nexport function isNullOrUndefined(param) {\n return param === null || param === undefined\n}\n\n/**\n * omit\n * @param obj target Object\n * @param uselessKeys keys of removed properties\n * @return new Object without useless properties\n */\nexport function omit(obj, uselessKeys) {\n return (\n obj\n && Object.keys(obj).reduce((acc, key) => {\n return uselessKeys.includes(key) ? acc : { ...acc, [key]: obj[key] }\n }, {})\n )\n}\n\n/**\n * 将delta中的图片替换成制定的图片数组,用于图片上传到服务器的场景\n * @param delta 原始delta\n * @param imageUrls 图片数组\n * @param imagePlaceholder 标识是否是占位图的数组,与图片数组一一对应\n * @return 替换之后的delta\n */\nexport function replaceDeltaImage(delta, imageUrls, imagePlaceholder) {\n let imageIndex = 0\n return delta.reduce((newDelta, op) => {\n if (op.insert.image && !op.insert.image.hasExisted) {\n const attributes = imagePlaceholder[imageIndex]\n ? { ...op.attributes, width: 'auto', height: 225 } // 占位图片应该固定大小\n : op.attributes\n newDelta.insert({ image: imageUrls[imageIndex] }, attributes)\n imageIndex++\n }\n else {\n newDelta.insert(op.insert, op.attributes)\n }\n return newDelta\n }, new Delta())\n}\n\nexport function splitWithBreak(insertContent: string) {\n const lines = []\n const insertStr = insertContent\n let start = 0\n for (let i = 0; i < insertContent.length; i++) {\n if (insertStr.charAt(i) === '\\n') {\n if (i === 0) {\n lines.push('\\n')\n }\n else {\n lines.push(insertStr.substring(start, i))\n lines.push('\\n')\n }\n start = i + 1\n }\n }\n\n const tailStr = insertStr.substring(start)\n if (tailStr) {\n lines.push(tailStr)\n }\n\n return lines\n}\n\n/**\n * getEventComposedPath\n * compatibility fixed for Event.path/Event.composedPath\n * Event.path is only for chrome/opera\n * Event.composedPath is for Safari, FF\n * Neither for Micro Edge\n * @return an array of event.path\n */\nexport function getEventComposedPath(evt) {\n let path\n // chrome, opera, safari, firefox\n path = evt.path || (evt.composedPath && evt.composedPath())\n\n // other: edge\n if (path === undefined && evt.target) {\n path = []\n let target = evt.target\n path.push(target)\n\n while (target && target.parentNode) {\n target = target.parentNode\n path.push(target)\n }\n }\n\n return path\n}\n\nexport function sanitize(url, protocols) {\n const anchor = document.createElement('a')\n anchor.href = url\n const protocol = anchor.href.slice(0, anchor.href.indexOf(':'))\n return protocols.includes(protocol)\n}\n\nexport function hadProtocol(url: string) {\n if (!url || !/^(?:f|ht)tps?\\:\\/\\//.test(url)) {\n return false\n }\n return true\n}\n\nexport function isInside(position, dom) {\n const areaPosition = dom.getBoundingClientRect()\n const { pageX, pageY } = position\n // getBoundingClientRect是不考虑窗口滚动的\n const left = pageX - window.scrollX\n const top = pageY - window.scrollY\n const {\n left: areaLeft,\n top: areaTop,\n width: areaWidth,\n height: areaHeight,\n } = areaPosition\n const inside\n = left > areaLeft\n && left < areaLeft + areaWidth\n && top > areaTop\n && top < areaTop + areaHeight\n return inside\n}\n\n// Internet Explorer 6-11\nexport const isPureIE = !!document.documentMode\n\n/**\n* 检测剪贴板数据是否来自 Outlook 客户端\n*/\nexport const isOutlookDesktop = (e) => {\n const types = e.clipboardData?.types || [];\n const html = e.clipboardData?.getData('text/html') || '';\n\n // RTF + Office 命名空间 或 RTF + Mso 样式类\n return types.includes('text/rtf') && (/schemas-microsoft-com:office/.test(html) || /class=\"?Mso\\w+/i.test(html));\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"editor.utils.cjs.js","sources":["../../../src/config/editor.utils.ts"],"sourcesContent":["import Quill from 'quill'\n\nconst Delta = Quill.import('delta')\n\n// color hex to rgba\nexport function hexToRgbA(hex: string) {\n let color\n if (/^#([A-Fa-f0-9]{3}){1,2}$/.test(hex)) {\n color = hex.substring(1).split('')\n if (color.length === 3) {\n color = [color[0], color[0], color[1], color[1], color[2], color[2]]\n }\n color = `0x${color.join('')}`\n return (\n `rgba(${\n [(color >> 16) & 255, (color >> 8) & 255, color & 255].join(',')\n },1)`\n )\n }\n}\n\n/**\n * 将File格式的图片转换成Url格式\n * @param imageFile File格式的图片\n */\nexport function imageFileToUrl(imageFile) {\n return new Promise((resolve, reject) => {\n const reader = new FileReader()\n reader.readAsDataURL(imageFile)\n reader.onload = function (e) {\n resolve(e.target.result)\n }\n reader.onerror = reject\n }).catch((error) => {\n console.error('Error reading file:', error)\n })\n}\n\n/**\n * 将Url格式的图片转换成File格式\n * @param imageUrl 图片的URL\n */\nexport function imageUrlToFile(imageUrl, isErrorImage?: boolean) {\n return new Promise((resolve, reject) => {\n fetch(imageUrl, {\n method: 'get',\n mode: 'no-cors',\n })\n .then(res => res.blob())\n .then((blob) => {\n if (!blob.type.includes('image') || !blob.type) {\n return reject()\n }\n const fileType = blob.type.replace(/^.*\\//, '')\n const fileName = isErrorImage\n ? 'editorx-error-image.png'\n : `image-${new Date().getTime()}.${fileType}`\n const file = new File([blob], fileName, blob)\n resolve(file)\n })\n .catch(reject)\n })\n}\n\nexport function insideTable(range = null, quill = this.quill) {\n let currentRange = range\n if (!currentRange) {\n currentRange = quill.getSelection()\n }\n // fix: 原有formats方法无法判断表格内的list和head附近粘贴\n const [line] = quill.getLine(currentRange.index)\n return line && !!line.domNode.closest('table.quill-better-table')\n}\n\nexport function isNullOrUndefined(param) {\n return param === null || param === undefined\n}\n\n/**\n * omit\n * @param obj target Object\n * @param uselessKeys keys of removed properties\n * @return new Object without useless properties\n */\nexport function omit(obj, uselessKeys) {\n return (\n obj\n && Object.keys(obj).reduce((acc, key) => {\n return uselessKeys.includes(key) ? acc : { ...acc, [key]: obj[key] }\n }, {})\n )\n}\n\nexport function getPasteImageSrc(image) {\n if (!image) return ''\n return typeof image === 'string' ? image : (image.src || '')\n}\n\n/**\n * Outlook/Word 粘贴图常见无效 src:file://、cid:、sanitize 后的 //:0\n */\nexport function isInvalidPasteImageSrc(src) {\n if (!src) return true\n return src === '//:0' || /^file:/i.test(src) || /^cid:/i.test(src)\n}\n\n/**\n * Outlook 粘贴时 v:imagedata 与 <img alt=image> 常成对出现,\n * 去掉连续的无效重复图,并清除无意义的 alt=\"image\"。\n */\nexport function normalizeOutlookPasteImages(delta) {\n let prevWasInvalidImage = false\n return delta.reduce((newDelta, op) => {\n if (!op.insert?.image || op.insert.image.hasExisted) {\n newDelta.insert(op.insert, op.attributes)\n prevWasInvalidImage = false\n return newDelta\n }\n\n const src = getPasteImageSrc(op.insert.image)\n const invalid = isInvalidPasteImageSrc(src)\n // 连续无效图视为 Outlook 的 v:imagedata + img 重复,丢弃后者\n if (invalid && prevWasInvalidImage) {\n return newDelta\n }\n\n let attributes = op.attributes\n if (attributes?.alt === 'image') {\n attributes = { ...attributes }\n delete attributes.alt\n }\n newDelta.insert(op.insert, attributes)\n prevWasInvalidImage = invalid\n return newDelta\n }, new Delta())\n}\n\n/**\n * 将delta中的图片替换成制定的图片数组,用于图片上传到服务器的场景\n * @param delta 原始delta\n * @param imageUrls 图片数组\n * @param imagePlaceholder 标识是否是占位图的数组,与图片数组一一对应\n * @return 替换之后的delta\n */\nexport function replaceDeltaImage(delta, imageUrls, imagePlaceholder) {\n let imageIndex = 0\n return delta.reduce((newDelta, op) => {\n if (op.insert.image && !op.insert.image.hasExisted) {\n const imageUrl = imageUrls[imageIndex]\n // 替换失败时丢弃无效占位图,避免留下 //:0 + alt=image\n if (!imageUrl && isInvalidPasteImageSrc(getPasteImageSrc(op.insert.image))) {\n imageIndex++\n return newDelta\n }\n let attributes = imagePlaceholder[imageIndex]\n ? { ...op.attributes, width: 'auto', height: 225 } // 占位图片应该固定大小\n : op.attributes\n if (attributes?.alt === 'image') {\n attributes = { ...attributes }\n delete attributes.alt\n }\n newDelta.insert({ image: imageUrl }, attributes)\n imageIndex++\n }\n else {\n newDelta.insert(op.insert, op.attributes)\n }\n return newDelta\n }, new Delta())\n}\n\nexport function splitWithBreak(insertContent: string) {\n const lines = []\n const insertStr = insertContent\n let start = 0\n for (let i = 0; i < insertContent.length; i++) {\n if (insertStr.charAt(i) === '\\n') {\n if (i === 0) {\n lines.push('\\n')\n }\n else {\n lines.push(insertStr.substring(start, i))\n lines.push('\\n')\n }\n start = i + 1\n }\n }\n\n const tailStr = insertStr.substring(start)\n if (tailStr) {\n lines.push(tailStr)\n }\n\n return lines\n}\n\n/**\n * getEventComposedPath\n * compatibility fixed for Event.path/Event.composedPath\n * Event.path is only for chrome/opera\n * Event.composedPath is for Safari, FF\n * Neither for Micro Edge\n * @return an array of event.path\n */\nexport function getEventComposedPath(evt) {\n let path\n // chrome, opera, safari, firefox\n path = evt.path || (evt.composedPath && evt.composedPath())\n\n // other: edge\n if (path === undefined && evt.target) {\n path = []\n let target = evt.target\n path.push(target)\n\n while (target && target.parentNode) {\n target = target.parentNode\n path.push(target)\n }\n }\n\n return path\n}\n\nexport function sanitize(url, protocols) {\n const anchor = document.createElement('a')\n anchor.href = url\n const protocol = anchor.href.slice(0, anchor.href.indexOf(':'))\n return protocols.includes(protocol)\n}\n\nexport function hadProtocol(url: string) {\n if (!url || !/^(?:f|ht)tps?\\:\\/\\//.test(url)) {\n return false\n }\n return true\n}\n\nexport function isInside(position, dom) {\n const areaPosition = dom.getBoundingClientRect()\n const { pageX, pageY } = position\n // getBoundingClientRect是不考虑窗口滚动的\n const left = pageX - window.scrollX\n const top = pageY - window.scrollY\n const {\n left: areaLeft,\n top: areaTop,\n width: areaWidth,\n height: areaHeight,\n } = areaPosition\n const inside\n = left > areaLeft\n && left < areaLeft + areaWidth\n && top > areaTop\n && top < areaTop + areaHeight\n return inside\n}\n\n// Internet Explorer 6-11\nexport const isPureIE = !!document.documentMode\n\n/**\n* 检测剪贴板数据是否来自 Outlook 客户端\n*/\nexport const isOutlookDesktop = (e) => {\n const types = e.clipboardData?.types || [];\n const html = e.clipboardData?.getData('text/html') || '';\n\n // RTF + Office 命名空间 或 RTF + Mso 样式类\n return types.includes('text/rtf') && (/schemas-microsoft-com:office/.test(html) || /class=\"?Mso\\w+/i.test(html));\n}\n"],"names":[],"mappings":"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"}
@@ -40,15 +40,18 @@ function getListValue(value, preListValue) {
40
40
  }
41
41
  const namespace = "fe";
42
42
  exports.getEventComposedPath = editor_utils.getEventComposedPath;
43
+ exports.getPasteImageSrc = editor_utils.getPasteImageSrc;
43
44
  exports.hadProtocol = editor_utils.hadProtocol;
44
45
  exports.hexToRgbA = editor_utils.hexToRgbA;
45
46
  exports.imageFileToUrl = editor_utils.imageFileToUrl;
46
47
  exports.imageUrlToFile = editor_utils.imageUrlToFile;
47
48
  exports.insideTable = editor_utils.insideTable;
48
49
  exports.isInside = editor_utils.isInside;
50
+ exports.isInvalidPasteImageSrc = editor_utils.isInvalidPasteImageSrc;
49
51
  exports.isNullOrUndefined = editor_utils.isNullOrUndefined;
50
52
  exports.isOutlookDesktop = editor_utils.isOutlookDesktop;
51
53
  exports.isPureIE = editor_utils.isPureIE;
54
+ exports.normalizeOutlookPasteImages = editor_utils.normalizeOutlookPasteImages;
52
55
  exports.omit = editor_utils.omit;
53
56
  exports.replaceDeltaImage = editor_utils.replaceDeltaImage;
54
57
  exports.sanitize = editor_utils.sanitize;
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs.js","sources":["../../../src/config/index.ts"],"sourcesContent":["import { isNullOrUndefined } from './editor.utils'\n\nexport * from './editor.config'\nexport * from './editor.utils'\n\n// 触发上传\nexport function inputFile(type, accept) {\n const defaultMIMETypes = this.quill.uploader.options[type].join(', ')\n const mimeTypes = accept || defaultMIMETypes\n let fileInput = this.container.querySelector(`input.ql-${type}[type=file]`)\n this.quill.uploader.options.enableMultiUpload = this.quill.options.uploadOption?.multiple\n if (isNullOrUndefined(fileInput)) {\n fileInput = document.createElement('input')\n fileInput.classList.add(`ql-${type}`)\n fileInput.setAttribute('type', 'file')\n fileInput.setAttribute('accept', mimeTypes)\n if (\n this.quill.uploader.options.enableMultiUpload === true\n || (this.quill.uploader.options.enableMultiUpload?.file && type === 'file')\n || (this.quill.uploader.options.enableMultiUpload?.image && type === 'image')\n ) {\n fileInput.setAttribute('multiple', '')\n }\n fileInput.addEventListener('change', () => {\n const range = this.quill.getSelection(true)\n this.quill.uploader.upload(range, fileInput.files, type === 'file')\n fileInput.value = ''\n })\n this.container.appendChild(fileInput)\n }\n fileInput.click()\n}\n\nexport function getListValue(value, preListValue) {\n let curListValue = value\n if (preListValue && preListValue === value) {\n curListValue = false\n }\n else if (value === 'check') {\n if (preListValue === 'checked' || preListValue === 'unchecked') {\n curListValue = false\n }\n else {\n curListValue = 'unchecked'\n }\n }\n return curListValue\n}\n/** css namespace */\nexport const namespace = 'fe'\n"],"names":["isNullOrUndefined"],"mappings":";;;;AAMgB,SAAA,UAAU,MAAM,QAAQ;;AAChC,QAAA,mBAAmB,KAAK,MAAM,SAAS,QAAQ,IAAI,EAAE,KAAK,IAAI;AACpE,QAAM,YAAY,UAAU;AAC5B,MAAI,YAAY,KAAK,UAAU,cAAc,YAAY,IAAI,aAAa;AAC1E,OAAK,MAAM,SAAS,QAAQ,qBAAoB,UAAK,MAAM,QAAQ,iBAAnB,mBAAiC;AAC7E,MAAAA,aAAAA,kBAAkB,SAAS,GAAG;AACpB,gBAAA,SAAS,cAAc,OAAO;AAC1C,cAAU,UAAU,IAAI,MAAM,IAAI,EAAE;AAC1B,cAAA,aAAa,QAAQ,MAAM;AAC3B,cAAA,aAAa,UAAU,SAAS;AAExC,QAAA,KAAK,MAAM,SAAS,QAAQ,sBAAsB,UAC9C,UAAK,MAAM,SAAS,QAAQ,sBAA5B,mBAA+C,SAAQ,SAAS,YAChE,UAAK,MAAM,SAAS,QAAQ,sBAA5B,mBAA+C,UAAS,SAAS,SACrE;AACU,gBAAA,aAAa,YAAY,EAAE;AAAA,IAAA;AAE7B,cAAA,iBAAiB,UAAU,MAAM;AACzC,YAAM,QAAQ,KAAK,MAAM,aAAa,IAAI;AAC1C,WAAK,MAAM,SAAS,OAAO,OAAO,UAAU,OAAO,SAAS,MAAM;AAClE,gBAAU,QAAQ;AAAA,IAAA,CACnB;AACI,SAAA,UAAU,YAAY,SAAS;AAAA,EAAA;AAEtC,YAAU,MAAM;AAClB;AAEgB,SAAA,aAAa,OAAO,cAAc;AAChD,MAAI,eAAe;AACf,MAAA,gBAAgB,iBAAiB,OAAO;AAC3B,mBAAA;AAAA,EAAA,WAER,UAAU,SAAS;AACtB,QAAA,iBAAiB,aAAa,iBAAiB,aAAa;AAC/C,qBAAA;AAAA,IAAA,OAEZ;AACY,qBAAA;AAAA,IAAA;AAAA,EACjB;AAEK,SAAA;AACT;AAEO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.cjs.js","sources":["../../../src/config/index.ts"],"sourcesContent":["import { isNullOrUndefined } from './editor.utils'\n\nexport * from './editor.config'\nexport * from './editor.utils'\n\n// 触发上传\nexport function inputFile(type, accept) {\n const defaultMIMETypes = this.quill.uploader.options[type].join(', ')\n const mimeTypes = accept || defaultMIMETypes\n let fileInput = this.container.querySelector(`input.ql-${type}[type=file]`)\n this.quill.uploader.options.enableMultiUpload = this.quill.options.uploadOption?.multiple\n if (isNullOrUndefined(fileInput)) {\n fileInput = document.createElement('input')\n fileInput.classList.add(`ql-${type}`)\n fileInput.setAttribute('type', 'file')\n fileInput.setAttribute('accept', mimeTypes)\n if (\n this.quill.uploader.options.enableMultiUpload === true\n || (this.quill.uploader.options.enableMultiUpload?.file && type === 'file')\n || (this.quill.uploader.options.enableMultiUpload?.image && type === 'image')\n ) {\n fileInput.setAttribute('multiple', '')\n }\n fileInput.addEventListener('change', () => {\n const range = this.quill.getSelection(true)\n this.quill.uploader.upload(range, fileInput.files, type === 'file')\n fileInput.value = ''\n })\n this.container.appendChild(fileInput)\n }\n fileInput.click()\n}\n\nexport function getListValue(value, preListValue) {\n let curListValue = value\n if (preListValue && preListValue === value) {\n curListValue = false\n }\n else if (value === 'check') {\n if (preListValue === 'checked' || preListValue === 'unchecked') {\n curListValue = false\n }\n else {\n curListValue = 'unchecked'\n }\n }\n return curListValue\n}\n/** css namespace */\nexport const namespace = 'fe'\n"],"names":["isNullOrUndefined"],"mappings":";;;;AAMgB,SAAA,UAAU,MAAM,QAAQ;;AAChC,QAAA,mBAAmB,KAAK,MAAM,SAAS,QAAQ,IAAI,EAAE,KAAK,IAAI;AACpE,QAAM,YAAY,UAAU;AAC5B,MAAI,YAAY,KAAK,UAAU,cAAc,YAAY,IAAI,aAAa;AAC1E,OAAK,MAAM,SAAS,QAAQ,qBAAoB,UAAK,MAAM,QAAQ,iBAAnB,mBAAiC;AAC7E,MAAAA,aAAAA,kBAAkB,SAAS,GAAG;AACpB,gBAAA,SAAS,cAAc,OAAO;AAC1C,cAAU,UAAU,IAAI,MAAM,IAAI,EAAE;AAC1B,cAAA,aAAa,QAAQ,MAAM;AAC3B,cAAA,aAAa,UAAU,SAAS;AAExC,QAAA,KAAK,MAAM,SAAS,QAAQ,sBAAsB,UAC9C,UAAK,MAAM,SAAS,QAAQ,sBAA5B,mBAA+C,SAAQ,SAAS,YAChE,UAAK,MAAM,SAAS,QAAQ,sBAA5B,mBAA+C,UAAS,SAAS,SACrE;AACU,gBAAA,aAAa,YAAY,EAAE;AAAA,IAAA;AAE7B,cAAA,iBAAiB,UAAU,MAAM;AACzC,YAAM,QAAQ,KAAK,MAAM,aAAa,IAAI;AAC1C,WAAK,MAAM,SAAS,OAAO,OAAO,UAAU,OAAO,SAAS,MAAM;AAClE,gBAAU,QAAQ;AAAA,IAAA,CACnB;AACI,SAAA,UAAU,YAAY,SAAS;AAAA,EAAA;AAEtC,YAAU,MAAM;AAClB;AAEgB,SAAA,aAAa,OAAO,cAAc;AAChD,MAAI,eAAe;AACf,MAAA,gBAAgB,iBAAiB,OAAO;AAC3B,mBAAA;AAAA,EAAA,WAER,UAAU,SAAS;AACtB,QAAA,iBAAiB,aAAa,iBAAiB,aAAa;AAC/C,qBAAA;AAAA,IAAA,OAEZ;AACY,qBAAA;AAAA,IAAA;AAAA,EACjB;AAEK,SAAA;AACT;AAEO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/lib/index.cjs.js CHANGED
@@ -24,15 +24,18 @@ exports.PPT_UPLOADER_MIME_TYPES = editor_config.PPT_UPLOADER_MIME_TYPES;
24
24
  exports.XSL_UPLOADER_MIME_TYPES = editor_config.XSL_UPLOADER_MIME_TYPES;
25
25
  exports.defaultLanguage = editor_config.defaultLanguage;
26
26
  exports.getEventComposedPath = editor_utils.getEventComposedPath;
27
+ exports.getPasteImageSrc = editor_utils.getPasteImageSrc;
27
28
  exports.hadProtocol = editor_utils.hadProtocol;
28
29
  exports.hexToRgbA = editor_utils.hexToRgbA;
29
30
  exports.imageFileToUrl = editor_utils.imageFileToUrl;
30
31
  exports.imageUrlToFile = editor_utils.imageUrlToFile;
31
32
  exports.insideTable = editor_utils.insideTable;
32
33
  exports.isInside = editor_utils.isInside;
34
+ exports.isInvalidPasteImageSrc = editor_utils.isInvalidPasteImageSrc;
33
35
  exports.isNullOrUndefined = editor_utils.isNullOrUndefined;
34
36
  exports.isOutlookDesktop = editor_utils.isOutlookDesktop;
35
37
  exports.isPureIE = editor_utils.isPureIE;
38
+ exports.normalizeOutlookPasteImages = editor_utils.normalizeOutlookPasteImages;
36
39
  exports.omit = editor_utils.omit;
37
40
  exports.replaceDeltaImage = editor_utils.replaceDeltaImage;
38
41
  exports.sanitize = editor_utils.sanitize;
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -94,7 +94,7 @@ class CustomClipboard extends Clipboard {
94
94
  if (html.search(msExcelCheck) !== -1) {
95
95
  result.html = renderStyles(html);
96
96
  }
97
- if (msWordCheck1.test(html) || msWordCheck2.test(html)) {
97
+ if (msWordCheck1.test(html) || msWordCheck2.test(html) || editor_utils.isOutlookDesktop(e)) {
98
98
  result.rtf = e.clipboardData.getData("text/rtf");
99
99
  }
100
100
  this.onPaste(range, result);
@@ -106,6 +106,7 @@ class CustomClipboard extends Clipboard {
106
106
  const formats = this.quill.getFormat(range.index);
107
107
  let pastedDelta = this.convert({ text, html }, formats);
108
108
  pastedDelta = replaceDeltaWhiteSpace(pastedDelta, rootBgColor);
109
+ pastedDelta = editor_utils.normalizeOutlookPasteImages(pastedDelta);
109
110
  const deltaLength = pastedDelta.ops.length;
110
111
  let loadingTipsContainer;
111
112
  if (deltaLength > editor_config.BIG_DELTA_LIMIT) {
@@ -176,10 +177,8 @@ class CustomClipboard extends Clipboard {
176
177
  const delta = oldDelta.concat(pastedContent);
177
178
  setTimeout(() => {
178
179
  this.quill.updateContents(delta, Quill.sources.USER);
179
- this.quill.setSelection(
180
- delta.length() - linePos.length - linePos.fix,
181
- Quill.sources.SILENT
182
- );
180
+ const newSelectionIndex = linePos.index + (pastedContent.length ? pastedContent.length() : 0);
181
+ this.quill.setSelection(newSelectionIndex, Quill.sources.SILENT);
183
182
  this.quill.scrollIntoView();
184
183
  if (loadingTipsContainer) {
185
184
  loadingTipsContainer.remove();
@@ -252,8 +251,7 @@ class CustomClipboard extends Clipboard {
252
251
  resolve(originalUrls[index]);
253
252
  });
254
253
  } else if ((_c = this.quill.options.uploadOption) == null ? void 0 : _c.imageUploadToServer) {
255
- const range = this.getImgSelection(pastedDelta, imageIndexs[index]);
256
- this.quill.uploader.upload(range, [imageFile]);
254
+ return editor_utils.imageFileToUrl(imageFile);
257
255
  } else {
258
256
  return editor_utils.imageFileToUrl(imageFile);
259
257
  }
@@ -339,7 +337,7 @@ class CustomClipboard extends Clipboard {
339
337
  file = await editor_utils.imageUrlToFile(newImage || image.src || image);
340
338
  } catch (_err) {
341
339
  if (clipboardFiles.length !== 0) {
342
- const clipboardFile = clipboardFiles[0];
340
+ const clipboardFile = clipboardFiles.shift();
343
341
  const imageType = ((_a = clipboardFile.type) == null ? void 0 : _a.indexOf("image")) === -1 ? "image/png" : clipboardFile.type;
344
342
  const blob = clipboardFile.slice(0, clipboardFile.size, imageType);
345
343
  file = new File([blob], `image-CORS-${(/* @__PURE__ */ new Date()).getTime()}.png`, {
@@ -364,6 +362,8 @@ class CustomClipboard extends Clipboard {
364
362
  }
365
363
  if (typeof op.insert === "string") {
366
364
  length += op.insert.length;
365
+ } else if (typeof op.insert === "object") {
366
+ length += 1;
367
367
  }
368
368
  return true;
369
369
  });
@@ -1 +1 @@
1
- {"version":3,"file":"custom-clipboard.cjs.js","sources":["../../../src/modules/custom-clipboard.ts"],"sourcesContent":["import type { Parchment as TypeParchment } from 'quill'\nimport type TypeBlock from 'quill/blots/block'\nimport type TypeClipboard from 'quill/modules/clipboard'\nimport type FluentEditor from '../fluent-editor'\nimport Quill from 'quill'\nimport {\n ERROR_IMAGE_PLACEHOLDER_CN,\n ERROR_IMAGE_PLACEHOLDER_EN,\n} from '../config/base64-image'\nimport { BIG_DELTA_LIMIT } from '../config/editor.config'\nimport {\n hexToRgbA,\n imageFileToUrl,\n imageUrlToFile,\n insideTable,\n isNullOrUndefined,\n isOutlookDesktop,\n omit,\n replaceDeltaImage,\n splitWithBreak,\n} from '../config/editor.utils'\n\nconst Clipboard = Quill.import('modules/clipboard') as typeof TypeClipboard\nconst Delta = Quill.import('delta')\n\nclass CustomClipboard extends Clipboard {\n quill: FluentEditor\n convert\n onCopy\n matchers\n\n prepareMatching(container, nodeMatches) {\n const elementMatchers = []\n const textMatchers = []\n this.matchers.forEach((pair) => {\n const [selector, matcher] = pair\n switch (selector) {\n case Node.TEXT_NODE:\n textMatchers.push(matcher)\n break\n case Node.ELEMENT_NODE:\n elementMatchers.push(matcher)\n break\n default: {\n // word 的 v:shape 系列标签只能通过 getElementsByTagName 获取\n const vRegex = /v:(.+)/\n const nodeList = vRegex.test(selector)\n ? Array.from(container.getElementsByTagName(selector))\n : Array.from(container.querySelectorAll(selector))\n nodeList.forEach((node) => {\n if (nodeMatches.has(node)) {\n const matches = nodeMatches.get(node)\n matches.push(matcher)\n }\n else {\n nodeMatches.set(node, [matcher])\n }\n })\n break\n }\n }\n })\n return [elementMatchers, textMatchers]\n }\n\n onCaptureCopy(e, isCut = false) {\n if (e.defaultPrevented) {\n return\n }\n e.preventDefault()\n const [range] = this.quill.selection.getRange()\n if (isNullOrUndefined(range)) {\n return\n }\n const { html, text } = this.onCopy(range, isCut)\n\n // 兼容IE11浏览器`\n if (!e.clipboardData) {\n e.clipboardData = {\n types: 'text/plain',\n setData: (_type, value) => {\n // @ts-ignore\n return window.clipboardData.setData('Text', value)\n },\n }\n }\n\n // 复制代码时移除utf8中产生的不间断空格\\u00A0\n let plainText = text\n if (html.startsWith('<pre>')) {\n plainText = text.replace(/\\u00A0/g, ' ')\n }\n\n e.clipboardData.setData('text/html', html)\n e.clipboardData.setData('text/plain', plainText)\n if (isCut) {\n this.quill.deleteText(range, Quill.sources.USER)\n }\n }\n\n onCapturePaste(e: ClipboardEvent) {\n if (e.defaultPrevented || !this.quill.isEnabled()) {\n return\n }\n e.preventDefault()\n const range = this.quill.getSelection(true)\n if (isNullOrUndefined(range)) {\n return\n }\n\n // 兼容IE11浏览器\n if (!e.clipboardData) {\n // @ts-ignore\n e.clipboardData = {\n types: 'text/plain',\n getData: () => {\n // @ts-ignore\n return window.clipboardData.getData('Text')\n },\n }\n }\n\n const html = e.clipboardData.getData('text/html')\n const text = e.clipboardData.getData('text/plain')\n const files = Array.from(e.clipboardData.files || [])\n const msExcelCheck = /<meta.*?Microsoft Excel\\s[\\d].*?>/\n\n if (html.search(msExcelCheck) === -1 && files.length > 0 && !isOutlookDesktop(e)) {\n this.quill.uploader.upload(range, files)\n }\n else {\n const msWordCheck1\n = /<meta\\s*name=\"?generator\"?\\s*content=\"?microsoft\\s*word\\s*\\d+\"?\\/?>/i\n const msWordCheck2 = /xmlns:o=\"urn:schemas-microsoft-com/i\n const result = { html, text, files, rtf: null }\n if (html.search(msExcelCheck) !== -1) {\n result.html = renderStyles(html)\n }\n if (msWordCheck1.test(html) || msWordCheck2.test(html)) {\n // TODO: 当word文档包含heading时text/rtf读取为空,无法获取hex图片,待修复。可参考ckeditor5/issues/2493\n result.rtf = e.clipboardData.getData('text/rtf')\n }\n this.onPaste(range, result)\n }\n }\n\n onPaste(range, { html, text, files: clipboardFiles, rtf }) {\n const hexImages = this.extractImageDataFromRtf(rtf)\n const rootBgColor = getComputedStyle(this.quill.root).backgroundColor\n const formats = this.quill.getFormat(range.index)\n let pastedDelta = this.convert({ text, html }, formats)\n pastedDelta = replaceDeltaWhiteSpace(pastedDelta, rootBgColor)\n const deltaLength = pastedDelta.ops.length\n\n let loadingTipsContainer\n if (deltaLength > BIG_DELTA_LIMIT) {\n loadingTipsContainer = this.quill.addContainer('ql-loading-tips')\n loadingTipsContainer.innerHTML = this.quill.getLangText('pasting')\n }\n\n const linePos = { index: range.index, length: range.length, fix: 0 }\n const [line, offset] = this.quill.getLine(range.index)\n const isInsideTable = insideTable.call(this)\n\n const handlePasteContent = (content: any) => {\n let pastedContent = content\n // fix: 阻止粘贴代码块和引用导致表格断裂\n const tableBreaker = pastedContent.ops.find((op) => {\n return (\n op.attributes\n && (op.attributes.blockquote || op.attributes['code-block'])\n )\n })\n if (isInsideTable) {\n // fix: 阻止带有表格内容粘贴在表格里\n const table = line.domNode.closest('table.quill-better-table')\n const tableBlot = Quill.find(table) as TypeParchment.Blot\n const tableIndex = this.quill.getIndex(tableBlot)\n const tableLength = tableBlot.length()\n const tableEndPos = tableIndex + tableLength\n const anchorNode = getSelection().anchorNode\n if (tableBreaker) {\n return\n }\n if (formats['table-col']) {\n // fix: 光标在表格前端的table-col处时,获取整个表格的index后以此为基准向前移动一位插入粘贴内容且不删除任何内容\n linePos.index = tableIndex - 1\n linePos.length = 0\n }\n else if (\n range.index === tableEndPos - 1\n && anchorNode instanceof HTMLDivElement\n && anchorNode.classList.contains('quill-better-table-wrapper')\n ) {\n const list = pastedContent.filter(\n op => op.attributes && op.attributes.list,\n )\n if (list && list.length) {\n return\n }\n // fix: 光标在表格末端时,向后移动一位插入粘贴内容且不删除任何内容\n // TODO\n // 当表格最后一格有内容时,没法区分在表格最后一格最末尾和光标在表格后这两种情况,它们的 range 是一样\n // 这会导致在这两处粘贴表格内容都会将该内容粘贴到表格下一行中\n linePos.index = tableEndPos\n linePos.length = 0\n }\n else {\n if (!formats['table-cell-line']) {\n return\n }\n // fix: 解决表格内粘贴问题\n // 缺陷描述:将表格内的换行文本复制粘贴到别的单元格,会导致表格断开\n // 原因是:换行的文本delta对象有问题,delta对象前面多了一个纯换行和表格控制头(table-col)\n // 解决方法:将多余的delta项移除\n pastedContent = {\n ops: pastedContent.filter((op, index) => {\n const regexp = /^[\\n\\r]+$/\n const isString = op.insert && typeof op.insert === 'string'\n const isLine = isString && regexp.test(op.insert)\n const isCellLine\n = isLine && op.attributes && op.attributes['table-cell-line']\n const isList = isLine && op.attributes && op.attributes.list\n const isPureLine = isLine && !isCellLine && !isList\n const isTableCol\n = isLine && op.attributes && op.attributes['table-col']\n const isLastCellLine = isCellLine && index === deltaLength - 1\n return !isPureLine && !isTableCol && !isLastCellLine\n }),\n }\n // fix: 解决从表格外粘贴多行文本导致表格断开的问题\n pastedContent = rebuildDelta(\n new Delta(pastedContent.ops),\n formats['table-cell-line'],\n )\n }\n }\n\n // fix: 粘贴内容末尾为List,且粘贴位置的block或table-cell-line无内容则删除该block或table-cell-line\n // TODO 这里的lastChild如果不存在,则可能报错\n const lastChild = pastedContent.ops[pastedContent.ops.length - 1]\n const hasList\n = lastChild && lastChild.attributes && lastChild.attributes.list\n if (\n hasList\n && offset === 0\n && line\n && (line as TypeBlock).cache.length === 1\n && (line.statics.blotName === 'block'\n || line.statics.blotName === 'table-cell-line')\n && (!line.next || line.next.statics.blotName !== 'table-view')\n ) {\n linePos.index = this.quill.getIndex(line)\n linePos.length = line.length()\n linePos.fix = 1\n }\n\n const oldDelta = new Delta().retain(linePos.index).delete(linePos.length)\n const delta = oldDelta.concat(pastedContent)\n\n setTimeout(() => {\n this.quill.updateContents(delta, Quill.sources.USER)\n this.quill.setSelection(\n delta.length() - linePos.length - linePos.fix,\n Quill.sources.SILENT,\n )\n this.quill.scrollIntoView()\n if (loadingTipsContainer) {\n loadingTipsContainer.remove()\n }\n })\n }\n\n ;(async () => {\n try {\n const [files, placeholders, originalUrls, imageIndexs] = this.flipFilesArray(\n await this.extractFilesFromDelta(\n pastedDelta,\n clipboardFiles,\n hexImages,\n ),\n )\n\n if (files.length === 0) {\n handlePasteContent(pastedDelta)\n }\n else {\n if (this.quill.options.editorPaste && this.quill.options.editorPaste.observers.length !== 0) {\n // 设置editorPaste回调的情况\n this.quill.options.editorPaste.emit({\n files,\n callback: ({ code, message, data }) => {\n if (code === 0) {\n const { imageUrls } = data\n pastedDelta = replaceDeltaImage(\n pastedDelta,\n imageUrls,\n placeholders,\n )\n handlePasteContent(pastedDelta)\n }\n else {\n console.error('error message:', message)\n }\n },\n })\n }\n else {\n // 没有originalUrls 也没有文件粘贴\n if (files[0] !== undefined || originalUrls.length === 0) {\n // 没有设置editorPaste回调的情况下,File格式的占位图需要手动转换成url格式,插入到编辑器中\n const imageUrls = await this.files2urls(\n files,\n placeholders,\n originalUrls,\n pastedDelta,\n imageIndexs,\n )\n pastedDelta = replaceDeltaImage(\n pastedDelta,\n imageUrls,\n placeholders,\n )\n }\n handlePasteContent(pastedDelta)\n }\n }\n }\n catch (_e) {\n throw new Error('Paste failed.')\n }\n })()\n }\n\n files2urls(files, placeholders, originalUrls, pastedDelta, imageIndexs) {\n return Promise.all(\n files.map(async (imageFile, index) => {\n const netImgExp = /^((http|https)\\:)?\\/\\/([\\s\\S]+)$/\n let imageUrl = originalUrls[index]\n // 粘贴 Outlook 中的网络图\n if (originalUrls[index]?.src && originalUrls[index]?.src !== '//:0') {\n imageUrl = originalUrls[index].src\n }\n if (\n !placeholders[index]\n && originalUrls[index]\n && netImgExp.test(imageUrl)\n ) {\n // 不是占位图的普通url图片直接返回url\n return new Promise((resolve) => {\n resolve(originalUrls[index])\n })\n }\n else if (this.quill.options.uploadOption?.imageUploadToServer) {\n const range = this.getImgSelection(pastedDelta, imageIndexs[index])\n this.quill.uploader.upload(range, [imageFile])\n }\n else {\n // 占位图或者跨域图或 Outlook 中的本地图需要手动转换成url格式\n return imageFileToUrl(imageFile)\n }\n }),\n )\n }\n\n flipFilesArray(filesArr) {\n const files = []\n const placeholders = []\n const originalUrls = []\n const imageIndexs = []\n filesArr.forEach((item: any) => {\n if (item) {\n const [file, placeholder, originalUrl, imageIndex] = item\n files.push(file)\n placeholders.push(placeholder)\n originalUrls.push(originalUrl)\n if (imageIndex === 0 || imageIndex) {\n imageIndexs.push(imageIndex)\n }\n }\n })\n return [files, placeholders, originalUrls, imageIndexs]\n }\n\n // 将图片从hex转为base64\n convertHexToBase64(hexString) {\n return btoa(\n hexString\n .match(/\\w{2}/g)\n .map((char) => {\n return String.fromCharCode(Number.parseInt(char, 16))\n })\n .join(''),\n )\n }\n\n // 匹配rtf中的图片,存储为{hex, type}对象数组\n extractImageDataFromRtf(rtfData) {\n if (!rtfData) {\n return []\n }\n\n const regexPictureHeader\n = /{\\\\pict[\\s\\S]+?\\\\bliptag-?\\d+(\\\\blipupi-?\\d+)?({\\\\\\*\\\\blipuid\\s?[\\da-fA-F]+)?[\\s}]*?/\n const regexPicture = new RegExp(\n `(?:(${regexPictureHeader.source}))([\\\\da-fA-F\\\\s]+?)\\\\}`, // 非贪婪匹配\n 'g',\n )\n const images = rtfData.match(regexPicture)\n const result = []\n\n if (images) {\n for (const image of images) {\n let imageType = ''\n\n if (image.includes('\\\\pngblip')) {\n imageType = 'image/png'\n }\n else if (image.includes('\\\\jpegblip')) {\n imageType = 'image/jpeg'\n }\n\n if (imageType) {\n result.push({\n hex: image\n .replace(regexPictureHeader, '')\n .replace(/[^\\da-fA-F]/g, ''),\n type: imageType,\n })\n }\n }\n }\n\n return result\n }\n\n extractFilesFromDelta(delta, clipboardFiles, hexImages?) {\n let index = -1\n return Promise.all(\n delta.map(async (op) => {\n index++\n const image = op.insert.image\n if (!image || image.hasExisted) {\n return\n }\n\n let file\n let isPlaceholderImage = false\n let imageIndex\n try {\n // hex 图片存在则为 file:/// 协议本地图片,使用 hex 图片转为 base64 读取\n const hexImage = hexImages.length && hexImages.shift()\n const newImage\n = hexImage\n && `data:${hexImage.type};base64,${this.convertHexToBase64(\n hexImage.hex,\n )}`\n imageIndex = index\n file = await imageUrlToFile(newImage || image.src || image)\n }\n catch (_err) {\n if (clipboardFiles.length !== 0) {\n // 跨域获取图片失败时从剪切板获取图片\n const clipboardFile = clipboardFiles[0]\n const imageType\n = clipboardFile.type?.indexOf('image') === -1\n ? 'image/png'\n : clipboardFile.type\n const blob = clipboardFile.slice(0, clipboardFile.size, imageType)\n file = new File([blob], `image-CORS-${new Date().getTime()}.png`, {\n type: imageType,\n })\n }\n else if (image.src.startsWith('http')) {\n // 什么都不做\n }\n else {\n // 剪切板中无图片,用失败占位图替换\n const errorImagePlaceholderJpg\n = this.quill.getLangText('img-error') === 'Image Copy Error'\n ? ERROR_IMAGE_PLACEHOLDER_EN\n : ERROR_IMAGE_PLACEHOLDER_CN\n file = await imageUrlToFile(errorImagePlaceholderJpg, true)\n isPlaceholderImage = true\n }\n }\n\n return [file, isPlaceholderImage, image, imageIndex]\n }),\n )\n }\n\n getImgSelection(delta, imageIndex) {\n let length = 0\n delta.ops.every((op, index) => {\n if (index === imageIndex) {\n return false\n }\n if (typeof op.insert === 'string') {\n length += op.insert.length\n }\n return true\n })\n const range = {\n index: length,\n length: 0,\n }\n return range\n }\n}\n\nfunction rebuildDelta(delta, cellLine) {\n const { cell: cellId, colspan, row: rowId, rowspan } = cellLine\n const buildedDelta = delta.reduce((newDelta, op) => {\n if (op.insert && typeof op.insert === 'string') {\n const lines = splitWithBreak(op.insert)\n\n lines.forEach((text) => {\n if (text === '\\n') {\n // 对换行增加 table-cell-line 格式,以避免表格断开\n newDelta.insert('\\n', {\n ...op.attributes,\n 'table-cell-line': { row: rowId, cell: cellId, rowspan, colspan },\n })\n }\n else {\n text = text.endsWith('\\r') ? text.slice(0, -1) : text\n newDelta.insert(\n text,\n omit(op.attributes, ['table', 'table-cell-line']),\n )\n }\n })\n }\n else {\n newDelta.insert(op.insert, op.attributes)\n }\n\n return newDelta\n }, new Delta())\n\n return buildedDelta\n}\n\nfunction replaceStrWhiteSpace(str) {\n const isWhiteSpace = value => /^(\\u3000|\\u0020){1}$/.test(value) // 空白字符\n let textWithWhiteSpace = ''\n let beginHasChar = false\n for (const char of str) {\n if (isWhiteSpace(char) && !beginHasChar) {\n textWithWhiteSpace += '\\u00A0'\n }\n else {\n textWithWhiteSpace += char\n beginHasChar = true\n }\n }\n return textWithWhiteSpace\n}\n\nfunction replaceDeltaWhiteSpace(delta, rootBgColor?) {\n return delta.reduce((newDelta, op) => {\n // fix: 当粘贴文字颜色和编辑器背景色一致且自身无背景色的情况下移除文字颜色样式,避免误导用户粘贴无效\n if (\n rootBgColor\n && op.attributes\n && op.attributes.color\n && !op.attributes.background\n ) {\n const originColor = op.attributes.color\n const fontColor\n = originColor.indexOf('#') === 0 ? hexToRgbA(originColor) : originColor\n if (\n fontColor === rootBgColor\n || (fontColor === 'rgba(255,255,255,1)'\n && rootBgColor === 'rgba(0, 0, 0, 0)')\n ) {\n delete op.attributes.color\n }\n }\n if (op.insert && typeof op.insert === 'string') {\n const lines = splitWithBreak(op.insert)\n let insertWithWhiteSpace = ''\n lines.forEach((text) => {\n insertWithWhiteSpace += replaceStrWhiteSpace(text)\n })\n newDelta.insert(insertWithWhiteSpace, op.attributes)\n }\n else {\n newDelta.insert(op.insert, op.attributes)\n }\n return newDelta\n }, new Delta())\n}\n\nfunction renderStyles(html) {\n let htmlString = html\n // Trim unnecessary parts.\n htmlString = htmlString.substring(\n htmlString.indexOf('<html '),\n htmlString.length,\n )\n htmlString = htmlString.substring(\n 0,\n htmlString.lastIndexOf('</html>') + '</html>'.length,\n )\n\n // Add temporary iframe.\n const iframe = document.createElement('iframe')\n iframe.style.display = 'none'\n document.body.appendChild(iframe)\n\n const iframeDoc = iframe.contentDocument || iframe.contentWindow.document\n iframeDoc.open()\n iframeDoc.write(htmlString)\n iframeDoc.close()\n\n let collection\n let pointer\n const rules\n = iframeDoc.styleSheets[iframeDoc.styleSheets.length - 1].cssRules\n\n // Convert internal styles to inline style of respective node.\n for (let idx = 0; idx < rules.length; idx++) {\n if ((rules[idx] as CSSStyleRule).selectorText === '') {\n continue\n }\n collection = iframeDoc.body.querySelectorAll(\n (rules[idx] as CSSStyleRule).selectorText,\n )\n\n for (pointer = 0; pointer < collection.length; pointer++) {\n collection[pointer].style.cssText += (\n rules[idx] as CSSStyleRule\n ).style.cssText\n }\n }\n\n // @ts-ignore\n const convertedString = iframeDoc.firstChild.outerHTML\n // Remove temporary iframe.\n iframe.parentNode.removeChild(iframe)\n\n return convertedString\n}\n\nexport default CustomClipboard\n"],"names":["isNullOrUndefined","isOutlookDesktop","BIG_DELTA_LIMIT","insideTable","replaceDeltaImage","imageFileToUrl","imageUrlToFile","ERROR_IMAGE_PLACEHOLDER_EN","ERROR_IMAGE_PLACEHOLDER_CN","splitWithBreak","omit","hexToRgbA"],"mappings":"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"}
1
+ {"version":3,"file":"custom-clipboard.cjs.js","sources":["../../../src/modules/custom-clipboard.ts"],"sourcesContent":["import type { Parchment as TypeParchment } from 'quill'\nimport type TypeBlock from 'quill/blots/block'\nimport type TypeClipboard from 'quill/modules/clipboard'\nimport type FluentEditor from '../fluent-editor'\nimport Quill from 'quill'\nimport {\n ERROR_IMAGE_PLACEHOLDER_CN,\n ERROR_IMAGE_PLACEHOLDER_EN,\n} from '../config/base64-image'\nimport { BIG_DELTA_LIMIT } from '../config/editor.config'\nimport {\n hexToRgbA,\n imageFileToUrl,\n imageUrlToFile,\n insideTable,\n isNullOrUndefined,\n isOutlookDesktop,\n normalizeOutlookPasteImages,\n omit,\n replaceDeltaImage,\n splitWithBreak,\n} from '../config/editor.utils'\n\nconst Clipboard = Quill.import('modules/clipboard') as typeof TypeClipboard\nconst Delta = Quill.import('delta')\n\nclass CustomClipboard extends Clipboard {\n quill: FluentEditor\n convert\n onCopy\n matchers\n\n prepareMatching(container, nodeMatches) {\n const elementMatchers = []\n const textMatchers = []\n this.matchers.forEach((pair) => {\n const [selector, matcher] = pair\n switch (selector) {\n case Node.TEXT_NODE:\n textMatchers.push(matcher)\n break\n case Node.ELEMENT_NODE:\n elementMatchers.push(matcher)\n break\n default: {\n // word 的 v:shape 系列标签只能通过 getElementsByTagName 获取\n const vRegex = /v:(.+)/\n const nodeList = vRegex.test(selector)\n ? Array.from(container.getElementsByTagName(selector))\n : Array.from(container.querySelectorAll(selector))\n nodeList.forEach((node) => {\n if (nodeMatches.has(node)) {\n const matches = nodeMatches.get(node)\n matches.push(matcher)\n }\n else {\n nodeMatches.set(node, [matcher])\n }\n })\n break\n }\n }\n })\n return [elementMatchers, textMatchers]\n }\n\n onCaptureCopy(e, isCut = false) {\n if (e.defaultPrevented) {\n return\n }\n e.preventDefault()\n const [range] = this.quill.selection.getRange()\n if (isNullOrUndefined(range)) {\n return\n }\n const { html, text } = this.onCopy(range, isCut)\n\n // 兼容IE11浏览器`\n if (!e.clipboardData) {\n e.clipboardData = {\n types: 'text/plain',\n setData: (_type, value) => {\n // @ts-ignore\n return window.clipboardData.setData('Text', value)\n },\n }\n }\n\n // 复制代码时移除utf8中产生的不间断空格\\u00A0\n let plainText = text\n if (html.startsWith('<pre>')) {\n plainText = text.replace(/\\u00A0/g, ' ')\n }\n\n e.clipboardData.setData('text/html', html)\n e.clipboardData.setData('text/plain', plainText)\n if (isCut) {\n this.quill.deleteText(range, Quill.sources.USER)\n }\n }\n\n onCapturePaste(e: ClipboardEvent) {\n if (e.defaultPrevented || !this.quill.isEnabled()) {\n return\n }\n e.preventDefault()\n const range = this.quill.getSelection(true)\n if (isNullOrUndefined(range)) {\n return\n }\n\n // 兼容IE11浏览器\n if (!e.clipboardData) {\n // @ts-ignore\n e.clipboardData = {\n types: 'text/plain',\n getData: () => {\n // @ts-ignore\n return window.clipboardData.getData('Text')\n },\n }\n }\n\n const html = e.clipboardData.getData('text/html')\n const text = e.clipboardData.getData('text/plain')\n const files = Array.from(e.clipboardData.files || [])\n const msExcelCheck = /<meta.*?Microsoft Excel\\s[\\d].*?>/\n\n if (html.search(msExcelCheck) === -1 && files.length > 0 && !isOutlookDesktop(e)) {\n this.quill.uploader.upload(range, files)\n }\n else {\n const msWordCheck1\n = /<meta\\s*name=\"?generator\"?\\s*content=\"?microsoft\\s*word\\s*\\d+\"?\\/?>/i\n const msWordCheck2 = /xmlns:o=\"urn:schemas-microsoft-com/i\n const result = { html, text, files, rtf: null }\n if (html.search(msExcelCheck) !== -1) {\n result.html = renderStyles(html)\n }\n if (msWordCheck1.test(html) || msWordCheck2.test(html) || isOutlookDesktop(e)) {\n // TODO: 当word文档包含heading时text/rtf读取为空,无法获取hex图片,待修复。可参考ckeditor5/issues/2493\n result.rtf = e.clipboardData.getData('text/rtf')\n }\n this.onPaste(range, result)\n }\n }\n\n onPaste(range, { html, text, files: clipboardFiles, rtf }) {\n const hexImages = this.extractImageDataFromRtf(rtf)\n const rootBgColor = getComputedStyle(this.quill.root).backgroundColor\n const formats = this.quill.getFormat(range.index)\n let pastedDelta = this.convert({ text, html }, formats)\n pastedDelta = replaceDeltaWhiteSpace(pastedDelta, rootBgColor)\n // Outlook:v:imagedata 与 <img alt=image> 会生成重复图片,需先去重\n pastedDelta = normalizeOutlookPasteImages(pastedDelta)\n const deltaLength = pastedDelta.ops.length\n\n let loadingTipsContainer\n if (deltaLength > BIG_DELTA_LIMIT) {\n loadingTipsContainer = this.quill.addContainer('ql-loading-tips')\n loadingTipsContainer.innerHTML = this.quill.getLangText('pasting')\n }\n\n const linePos = { index: range.index, length: range.length, fix: 0 }\n const [line, offset] = this.quill.getLine(range.index)\n const isInsideTable = insideTable.call(this)\n\n const handlePasteContent = (content: any) => {\n let pastedContent = content\n // fix: 阻止粘贴代码块和引用导致表格断裂\n const tableBreaker = pastedContent.ops.find((op) => {\n return (\n op.attributes\n && (op.attributes.blockquote || op.attributes['code-block'])\n )\n })\n if (isInsideTable) {\n // fix: 阻止带有表格内容粘贴在表格里\n const table = line.domNode.closest('table.quill-better-table')\n const tableBlot = Quill.find(table) as TypeParchment.Blot\n const tableIndex = this.quill.getIndex(tableBlot)\n const tableLength = tableBlot.length()\n const tableEndPos = tableIndex + tableLength\n const anchorNode = getSelection().anchorNode\n if (tableBreaker) {\n return\n }\n if (formats['table-col']) {\n // fix: 光标在表格前端的table-col处时,获取整个表格的index后以此为基准向前移动一位插入粘贴内容且不删除任何内容\n linePos.index = tableIndex - 1\n linePos.length = 0\n }\n else if (\n range.index === tableEndPos - 1\n && anchorNode instanceof HTMLDivElement\n && anchorNode.classList.contains('quill-better-table-wrapper')\n ) {\n const list = pastedContent.filter(\n op => op.attributes && op.attributes.list,\n )\n if (list && list.length) {\n return\n }\n // fix: 光标在表格末端时,向后移动一位插入粘贴内容且不删除任何内容\n // TODO\n // 当表格最后一格有内容时,没法区分在表格最后一格最末尾和光标在表格后这两种情况,它们的 range 是一样\n // 这会导致在这两处粘贴表格内容都会将该内容粘贴到表格下一行中\n linePos.index = tableEndPos\n linePos.length = 0\n }\n else {\n if (!formats['table-cell-line']) {\n return\n }\n // fix: 解决表格内粘贴问题\n // 缺陷描述:将表格内的换行文本复制粘贴到别的单元格,会导致表格断开\n // 原因是:换行的文本delta对象有问题,delta对象前面多了一个纯换行和表格控制头(table-col)\n // 解决方法:将多余的delta项移除\n pastedContent = {\n ops: pastedContent.filter((op, index) => {\n const regexp = /^[\\n\\r]+$/\n const isString = op.insert && typeof op.insert === 'string'\n const isLine = isString && regexp.test(op.insert)\n const isCellLine\n = isLine && op.attributes && op.attributes['table-cell-line']\n const isList = isLine && op.attributes && op.attributes.list\n const isPureLine = isLine && !isCellLine && !isList\n const isTableCol\n = isLine && op.attributes && op.attributes['table-col']\n const isLastCellLine = isCellLine && index === deltaLength - 1\n return !isPureLine && !isTableCol && !isLastCellLine\n }),\n }\n // fix: 解决从表格外粘贴多行文本导致表格断开的问题\n pastedContent = rebuildDelta(\n new Delta(pastedContent.ops),\n formats['table-cell-line'],\n )\n }\n }\n\n // fix: 粘贴内容末尾为List,且粘贴位置的block或table-cell-line无内容则删除该block或table-cell-line\n // TODO 这里的lastChild如果不存在,则可能报错\n const lastChild = pastedContent.ops[pastedContent.ops.length - 1]\n const hasList\n = lastChild && lastChild.attributes && lastChild.attributes.list\n if (\n hasList\n && offset === 0\n && line\n && (line as TypeBlock).cache.length === 1\n && (line.statics.blotName === 'block'\n || line.statics.blotName === 'table-cell-line')\n && (!line.next || line.next.statics.blotName !== 'table-view')\n ) {\n linePos.index = this.quill.getIndex(line)\n linePos.length = line.length()\n linePos.fix = 1\n }\n\n const oldDelta = new Delta().retain(linePos.index).delete(linePos.length)\n const delta = oldDelta.concat(pastedContent)\n\n setTimeout(() => {\n this.quill.updateContents(delta, Quill.sources.USER)\n // 光标应落在粘贴内容之后:原位置 + 粘贴内容长度\n const newSelectionIndex = linePos.index + (pastedContent.length ? pastedContent.length() : 0)\n this.quill.setSelection(newSelectionIndex, Quill.sources.SILENT)\n this.quill.scrollIntoView()\n if (loadingTipsContainer) {\n loadingTipsContainer.remove()\n }\n })\n }\n\n ;(async () => {\n try {\n const [files, placeholders, originalUrls, imageIndexs] = this.flipFilesArray(\n await this.extractFilesFromDelta(\n pastedDelta,\n clipboardFiles,\n hexImages,\n ),\n )\n\n if (files.length === 0) {\n handlePasteContent(pastedDelta)\n }\n else {\n if (this.quill.options.editorPaste && this.quill.options.editorPaste.observers.length !== 0) {\n // 设置editorPaste回调的情况\n this.quill.options.editorPaste.emit({\n files,\n callback: ({ code, message, data }) => {\n if (code === 0) {\n const { imageUrls } = data\n pastedDelta = replaceDeltaImage(\n pastedDelta,\n imageUrls,\n placeholders,\n )\n handlePasteContent(pastedDelta)\n }\n else {\n console.error('error message:', message)\n }\n },\n })\n }\n else {\n // 没有originalUrls 也没有文件粘贴\n if (files[0] !== undefined || originalUrls.length === 0) {\n // 没有设置editorPaste回调的情况下,File格式的占位图需要手动转换成url格式,插入到编辑器中\n const imageUrls = await this.files2urls(\n files,\n placeholders,\n originalUrls,\n pastedDelta,\n imageIndexs,\n )\n pastedDelta = replaceDeltaImage(\n pastedDelta,\n imageUrls,\n placeholders,\n )\n }\n handlePasteContent(pastedDelta)\n }\n }\n }\n catch (_e) {\n throw new Error('Paste failed.')\n }\n })()\n }\n\n files2urls(files, placeholders, originalUrls, pastedDelta, imageIndexs) {\n return Promise.all(\n files.map(async (imageFile, index) => {\n const netImgExp = /^((http|https)\\:)?\\/\\/([\\s\\S]+)$/\n let imageUrl = originalUrls[index]\n // 粘贴 Outlook 中的网络图\n if (originalUrls[index]?.src && originalUrls[index]?.src !== '//:0') {\n imageUrl = originalUrls[index].src\n }\n if (\n !placeholders[index]\n && originalUrls[index]\n && netImgExp.test(imageUrl)\n ) {\n // 不是占位图的普通url图片直接返回url\n return new Promise((resolve) => {\n resolve(originalUrls[index])\n })\n }\n else if (this.quill.options.uploadOption?.imageUploadToServer) {\n // 粘贴场景只替换 delta 中的图片地址,避免再走 uploader.upload 插入第二张图\n return imageFileToUrl(imageFile)\n }\n else {\n // 占位图或者跨域图或 Outlook 中的本地图需要手动转换成url格式\n return imageFileToUrl(imageFile)\n }\n }),\n )\n }\n\n flipFilesArray(filesArr) {\n const files = []\n const placeholders = []\n const originalUrls = []\n const imageIndexs = []\n filesArr.forEach((item: any) => {\n if (item) {\n const [file, placeholder, originalUrl, imageIndex] = item\n files.push(file)\n placeholders.push(placeholder)\n originalUrls.push(originalUrl)\n if (imageIndex === 0 || imageIndex) {\n imageIndexs.push(imageIndex)\n }\n }\n })\n return [files, placeholders, originalUrls, imageIndexs]\n }\n\n // 将图片从hex转为base64\n convertHexToBase64(hexString) {\n return btoa(\n hexString\n .match(/\\w{2}/g)\n .map((char) => {\n return String.fromCharCode(Number.parseInt(char, 16))\n })\n .join(''),\n )\n }\n\n // 匹配rtf中的图片,存储为{hex, type}对象数组\n extractImageDataFromRtf(rtfData) {\n if (!rtfData) {\n return []\n }\n\n const regexPictureHeader\n = /{\\\\pict[\\s\\S]+?\\\\bliptag-?\\d+(\\\\blipupi-?\\d+)?({\\\\\\*\\\\blipuid\\s?[\\da-fA-F]+)?[\\s}]*?/\n const regexPicture = new RegExp(\n `(?:(${regexPictureHeader.source}))([\\\\da-fA-F\\\\s]+?)\\\\}`, // 非贪婪匹配\n 'g',\n )\n const images = rtfData.match(regexPicture)\n const result = []\n\n if (images) {\n for (const image of images) {\n let imageType = ''\n\n if (image.includes('\\\\pngblip')) {\n imageType = 'image/png'\n }\n else if (image.includes('\\\\jpegblip')) {\n imageType = 'image/jpeg'\n }\n\n if (imageType) {\n result.push({\n hex: image\n .replace(regexPictureHeader, '')\n .replace(/[^\\da-fA-F]/g, ''),\n type: imageType,\n })\n }\n }\n }\n\n return result\n }\n\n extractFilesFromDelta(delta, clipboardFiles, hexImages?) {\n let index = -1\n return Promise.all(\n delta.map(async (op) => {\n index++\n const image = op.insert.image\n if (!image || image.hasExisted) {\n return\n }\n\n let file\n let isPlaceholderImage = false\n let imageIndex\n try {\n // hex 图片存在则为 file:/// 协议本地图片,使用 hex 图片转为 base64 读取\n const hexImage = hexImages.length && hexImages.shift()\n const newImage\n = hexImage\n && `data:${hexImage.type};base64,${this.convertHexToBase64(\n hexImage.hex,\n )}`\n imageIndex = index\n file = await imageUrlToFile(newImage || image.src || image)\n }\n catch (_err) {\n if (clipboardFiles.length !== 0) {\n // 跨域获取图片失败时从剪切板获取图片\n const clipboardFile = clipboardFiles.shift()\n const imageType\n = clipboardFile.type?.indexOf('image') === -1\n ? 'image/png'\n : clipboardFile.type\n const blob = clipboardFile.slice(0, clipboardFile.size, imageType)\n file = new File([blob], `image-CORS-${new Date().getTime()}.png`, {\n type: imageType,\n })\n }\n else if (image.src.startsWith('http')) {\n // 什么都不做\n }\n else {\n // 剪切板中无图片,用失败占位图替换\n const errorImagePlaceholderJpg\n = this.quill.getLangText('img-error') === 'Image Copy Error'\n ? ERROR_IMAGE_PLACEHOLDER_EN\n : ERROR_IMAGE_PLACEHOLDER_CN\n file = await imageUrlToFile(errorImagePlaceholderJpg, true)\n isPlaceholderImage = true\n }\n }\n\n return [file, isPlaceholderImage, image, imageIndex]\n }),\n )\n }\n\n getImgSelection(delta, imageIndex) {\n let length = 0\n delta.ops.every((op, index) => {\n if (index === imageIndex) {\n return false\n }\n if (typeof op.insert === 'string') {\n length += op.insert.length\n }\n else if (typeof op.insert === 'object') {\n // 图片、提及等 embed 长度为 1\n length += 1\n }\n return true\n })\n const range = {\n index: length,\n length: 0,\n }\n return range\n }\n}\n\nfunction rebuildDelta(delta, cellLine) {\n const { cell: cellId, colspan, row: rowId, rowspan } = cellLine\n const buildedDelta = delta.reduce((newDelta, op) => {\n if (op.insert && typeof op.insert === 'string') {\n const lines = splitWithBreak(op.insert)\n\n lines.forEach((text) => {\n if (text === '\\n') {\n // 对换行增加 table-cell-line 格式,以避免表格断开\n newDelta.insert('\\n', {\n ...op.attributes,\n 'table-cell-line': { row: rowId, cell: cellId, rowspan, colspan },\n })\n }\n else {\n text = text.endsWith('\\r') ? text.slice(0, -1) : text\n newDelta.insert(\n text,\n omit(op.attributes, ['table', 'table-cell-line']),\n )\n }\n })\n }\n else {\n newDelta.insert(op.insert, op.attributes)\n }\n\n return newDelta\n }, new Delta())\n\n return buildedDelta\n}\n\nfunction replaceStrWhiteSpace(str) {\n const isWhiteSpace = value => /^(\\u3000|\\u0020){1}$/.test(value) // 空白字符\n let textWithWhiteSpace = ''\n let beginHasChar = false\n for (const char of str) {\n if (isWhiteSpace(char) && !beginHasChar) {\n textWithWhiteSpace += '\\u00A0'\n }\n else {\n textWithWhiteSpace += char\n beginHasChar = true\n }\n }\n return textWithWhiteSpace\n}\n\nfunction replaceDeltaWhiteSpace(delta, rootBgColor?) {\n return delta.reduce((newDelta, op) => {\n // fix: 当粘贴文字颜色和编辑器背景色一致且自身无背景色的情况下移除文字颜色样式,避免误导用户粘贴无效\n if (\n rootBgColor\n && op.attributes\n && op.attributes.color\n && !op.attributes.background\n ) {\n const originColor = op.attributes.color\n const fontColor\n = originColor.indexOf('#') === 0 ? hexToRgbA(originColor) : originColor\n if (\n fontColor === rootBgColor\n || (fontColor === 'rgba(255,255,255,1)'\n && rootBgColor === 'rgba(0, 0, 0, 0)')\n ) {\n delete op.attributes.color\n }\n }\n if (op.insert && typeof op.insert === 'string') {\n const lines = splitWithBreak(op.insert)\n let insertWithWhiteSpace = ''\n lines.forEach((text) => {\n insertWithWhiteSpace += replaceStrWhiteSpace(text)\n })\n newDelta.insert(insertWithWhiteSpace, op.attributes)\n }\n else {\n newDelta.insert(op.insert, op.attributes)\n }\n return newDelta\n }, new Delta())\n}\n\nfunction renderStyles(html) {\n let htmlString = html\n // Trim unnecessary parts.\n htmlString = htmlString.substring(\n htmlString.indexOf('<html '),\n htmlString.length,\n )\n htmlString = htmlString.substring(\n 0,\n htmlString.lastIndexOf('</html>') + '</html>'.length,\n )\n\n // Add temporary iframe.\n const iframe = document.createElement('iframe')\n iframe.style.display = 'none'\n document.body.appendChild(iframe)\n\n const iframeDoc = iframe.contentDocument || iframe.contentWindow.document\n iframeDoc.open()\n iframeDoc.write(htmlString)\n iframeDoc.close()\n\n let collection\n let pointer\n const rules\n = iframeDoc.styleSheets[iframeDoc.styleSheets.length - 1].cssRules\n\n // Convert internal styles to inline style of respective node.\n for (let idx = 0; idx < rules.length; idx++) {\n if ((rules[idx] as CSSStyleRule).selectorText === '') {\n continue\n }\n collection = iframeDoc.body.querySelectorAll(\n (rules[idx] as CSSStyleRule).selectorText,\n )\n\n for (pointer = 0; pointer < collection.length; pointer++) {\n collection[pointer].style.cssText += (\n rules[idx] as CSSStyleRule\n ).style.cssText\n }\n }\n\n // @ts-ignore\n const convertedString = iframeDoc.firstChild.outerHTML\n // Remove temporary iframe.\n iframe.parentNode.removeChild(iframe)\n\n return convertedString\n}\n\nexport default CustomClipboard\n"],"names":["isNullOrUndefined","isOutlookDesktop","normalizeOutlookPasteImages","BIG_DELTA_LIMIT","insideTable","replaceDeltaImage","imageFileToUrl","imageUrlToFile","ERROR_IMAGE_PLACEHOLDER_EN","ERROR_IMAGE_PLACEHOLDER_CN","splitWithBreak","omit","hexToRgbA"],"mappings":"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"}
@@ -260,6 +260,9 @@ function matchWordShapeImage(node, delta) {
260
260
  var _a;
261
261
  if (node) {
262
262
  const imageUrl = (_a = node.attributes.src) == null ? void 0 : _a.nodeValue;
263
+ if (!imageUrl) {
264
+ return delta;
265
+ }
263
266
  delta = new Delta().insert({ image: imageUrl });
264
267
  }
265
268
  return delta;
@@ -1 +1 @@
1
- {"version":3,"file":"node-matchers.cjs.js","sources":["../../../../../src/modules/table/utils/node-matchers.ts"],"sourcesContent":["import Quill from 'quill'\nimport { omit, splitWithBreak } from '../../../config/editor.utils'\nimport { cellId as tableCellId, rowId as tableRowId, TableViewWrapper } from '../formats/table'\nimport { CELL_MIN_WIDTH } from '../table-config'\n\nconst Delta = Quill.imports.delta\nconst InlineBlot = Quill.imports.parchment.InlineBlot\n\n// rebuild delta\nexport function matchTableCell(node, delta) {\n // fix: 移除旧数据中的pt高度,避免由于高度平均分导致无法插入行\n if (node.style.height.indexOf('pt')) {\n node.removeAttribute('style')\n }\n\n const row = node.parentNode\n let rowId = row.dataset.row\n if (!rowId) {\n rowId = row.dataset.row = tableRowId()\n }\n let cellId = node.dataset.cell\n // fix: dataset.cell in td will be 'undefined' when insert row/column\n if (!cellId || cellId === 'undefined') {\n cellId = tableCellId()\n }\n const colspan = node.getAttribute('colspan') || 1\n const rowspan = node.getAttribute('rowspan') || 1\n\n // fix: empty table cells copied from other place will be removed unexpectedly\n if (delta.length() === 0) {\n delta = new Delta().insert('\\n', {\n 'table-cell-line': { row: rowId, cell: cellId, rowspan, colspan },\n })\n return delta\n }\n\n delta = delta.reduce((newDelta, op) => {\n if (op.insert && typeof op.insert === 'string') {\n const lines = splitWithBreak(op.insert)\n\n lines.forEach((text) => {\n if (text === '\\n') {\n let attributes = {}\n const cellAttributes = {\n row: rowId,\n cell: cellId,\n rowspan,\n colspan,\n }\n if (op.attributes.table) {\n delete op.attributes.table\n }\n switch (true) {\n case !!op.attributes.header:\n attributes = Object.assign(op.attributes.header, cellAttributes)\n break\n case !!op.attributes.list:\n attributes = { list: Object.assign(op.attributes.list, cellAttributes) }\n break\n default:\n attributes = { 'table-cell-line': cellAttributes }\n }\n // fix: when td has background-color, quill can't set it to table-cell bolt\n if (op.attributes.background && attributes['table-cell-line']) {\n attributes['table-cell-line'].tdBgColor = op.attributes.background\n }\n newDelta.insert('\\n', Object.assign(op.attributes, attributes))\n }\n else {\n newDelta.insert(text, omit(op.attributes, ['table', 'table-cell-line', 'header', 'list']))\n }\n })\n }\n else {\n newDelta.insert(op.insert, op.attributes)\n }\n\n return newDelta\n }, new Delta())\n\n // fix: table cell height becomes larger(because insert unnecessary <div> on both sides of cell) when init table ngModel\n const regexp = /^[\\n]+$/\n const firstDelta = delta.ops[0]\n if (delta.ops.length >= 3) {\n const lastDelta = delta.ops[delta.ops.length - 1]\n if (regexp.test(firstDelta.insert) && firstDelta.attributes['table-cell-line']) {\n delta.ops.splice(0, 1)\n }\n if (regexp.test(lastDelta.insert) && lastDelta.attributes['table-cell-line']) {\n delta.ops[delta.ops.length - 1].insert = '\\n'\n }\n }\n else if (delta.ops.length === 1 && regexp.test(firstDelta.insert) && firstDelta.attributes['table-cell-line']) {\n delta.ops[0].insert = '\\n'\n }\n\n return delta\n}\n\n// replace th tag with td tag\nexport function matchTableHeader(node, delta, _scroll) {\n const row = node.parentNode\n const cells = Array.from(row.querySelectorAll('th'))\n let rowId = row.dataset.row\n if (!rowId) {\n rowId = row.dataset.row = tableRowId()\n }\n const cellId = cells.indexOf(node) + 1\n const colspan = node.getAttribute('colspan') || false\n const rowspan = node.getAttribute('rowspan') || false\n\n // fix: empty table cells copied from other place will be removed unexpectedly\n if (delta.length() === 0) {\n delta = new Delta().insert('\\n', {\n 'table-cell-line': { row: rowId, cell: cellId, rowspan, colspan },\n })\n return delta\n }\n\n delta = delta.reduce((newDelta, op) => {\n if (op.insert && typeof op.insert === 'string') {\n const lines = splitWithBreak(op.insert)\n\n // fix: no '\\n' in the end of op.insert, push a '\\n' to lines\n if (lines[lines.length - 1] !== '\\n') {\n lines.push('\\n')\n }\n\n lines.forEach((text) => {\n text === '\\n'\n ? newDelta.insert('\\n', { 'table-cell-line': { row: rowId, cell: cellId, rowspan, colspan } })\n : newDelta.insert(text, op.attributes)\n })\n }\n else {\n newDelta.insert(op.insert, op.attributes)\n }\n\n return newDelta\n }, new Delta())\n\n delta = delta.reduce((newDelta, op) => {\n if (op.insert && typeof op.insert === 'string' && op.insert.startsWith('\\n')) {\n newDelta.insert(op.insert, { 'table-cell-line': { row: rowId, cell: cellId, rowspan, colspan } })\n }\n else {\n newDelta.insert(op.insert, { ...omit(op.attributes, ['table', 'table-cell-line']) })\n }\n\n return newDelta\n }, new Delta())\n\n return delta\n}\n\n// supplement colgroup and col\nexport function matchTable(node, delta, scroll) {\n const isWordTable = node.children.length === 1\n if (!(node instanceof Element)) {\n return\n }\n const getMaxColNumber = (tds) => {\n if (isWordTable) {\n return tds.length\n }\n let colsNumber = 0\n tds.forEach((td) => {\n colsNumber += td.colSpan\n })\n return Math.max(tds.length, colsNumber)\n }\n\n const checkMinWidth = (width) => {\n if (Number.isNaN(width)) {\n // 无指定值时默认为auto,待渲染后修正\n return { 'table-col': { width: 'auto' } }\n }\n else if (width < CELL_MIN_WIDTH) {\n // 当列宽度小于默认宽度时取默认宽度\n return { 'table-col': true }\n }\n else {\n // 大于默认值取实际指定值\n return { 'table-col': { width } }\n }\n }\n\n // fix: a table with an empty tr is invalid, should not be displayed\n const rows = node.querySelectorAll('tr')\n const topRow = rows[0]\n const onlyEmptyTr = rows.length === 1 && !topRow.querySelector('td')\n\n // fix: empty table will return empty delta\n if (!topRow || onlyEmptyTr) {\n return new Delta().insert('\\n')\n }\n\n const colsNumber = node.querySelectorAll('col').length\n let maxCellsNumber = 0\n let maxCells\n // 遍历行获取最大列数和该行的所有单元格\n Array.prototype.slice.call(rows).forEach((row) => {\n const tds = row.querySelectorAll('td')\n maxCellsNumber = Math.max(getMaxColNumber(tds), maxCellsNumber)\n maxCells = tds\n })\n\n // 列的累计器\n let colCount = 0\n delta = delta.reduce((newDelta, op) => {\n // 当colCount与colsNumber相等时,则补充相差列\n if (colCount === colsNumber) {\n const fillNumber = maxCellsNumber - colCount\n const outset = colCount\n // index为差值列索引,通过遍历差值得到mexCells行中对应索引的单元格宽度\n for (let i = 0; i < fillNumber; i++) {\n const index = outset + i\n const colWidth = Number.parseInt(\n index < maxCells.length\n ? maxCells[index].width\n // maxCells[index].style && maxCells[index].style.width ? maxCells[index].style.width :\n : maxCells[maxCells.length - 1].width,\n 10,\n )\n newDelta.insert('\\n', checkMinWidth(colWidth))\n colCount++\n }\n }\n const attr = op.attributes || {}\n switch (true) {\n case !!attr['table-col']:\n // 只有当前列数小于实际总列数才操作,所以不存在大于的情况\n if (colCount < maxCellsNumber) {\n // 当table-col宽度一致时会合并为单一insert,insert长度大于1,截取符合实际总列数的长度来插入\n const insert = op.insert.slice(0, maxCellsNumber)\n const colWidth = Number.parseInt(attr['table-col'].width, 10)\n newDelta.insert(insert, checkMinWidth(colWidth))\n colCount += insert.length\n }\n break\n case !!attr.notFilled:\n { // 将标记的空tr填充对应列数的单元格\n const rowId = tableRowId()\n for (let x = 0; x < maxCellsNumber; x++) {\n newDelta.insert('\\n', { 'table-cell-line': { row: rowId, cell: tableCellId(), rowspan: 1, colspan: 1 } })\n }\n break }\n default:\n newDelta.insert(op.insert, op.attributes)\n }\n return newDelta\n }, new Delta())\n\n const tableItem = node.closest('.quill-better-table-wrapper') || node\n const prevBlot = tableItem.previousElementSibling && scroll.query(tableItem.previousElementSibling)\n const nextBlot = tableItem.nextElementSibling && scroll.query(tableItem.nextElementSibling)\n // fix: prevent two adjacent tables from sticking together\n if (!nextBlot || nextBlot.prototype instanceof InlineBlot) {\n delta = delta.insert('\\n')\n }\n // fix: When there is no line break in front of the table, pressing the Enter key will cause a problem with the table.\n if (!prevBlot || prevBlot.prototype instanceof InlineBlot) {\n const newLine = new Delta().insert('\\n')\n delta = newLine.concat(delta)\n }\n if (nextBlot === TableViewWrapper) {\n delta = delta.insert('\\n')\n }\n\n return delta\n}\n\nexport function matchTableRow(_node, delta) {\n // fix: 处理空<tr>标签被忽略的情况\n if (delta.ops.length === 1 && !delta.ops[0].attributes) {\n delta = new Delta().insert('\\n', { notFilled: true })\n }\n return delta\n}\n\n// match h tags, distinguish between headers in the table and headers outside the table\nexport function matchHeader(node, delta) {\n const newDelta = new Delta()\n const fontSize = node.style.fontSize\n delta.forEach((op) => {\n newDelta.insert(\n op.insert,\n Object.assign({}, op.attributes, {\n size: fontSize,\n }),\n )\n })\n return newDelta\n}\n\nexport function matchList(node, delta) {\n const value = node.tagName === 'UL' ? 'bullet' : 'ordered'\n delta.forEach((op) => {\n if (typeof op.attributes.list === 'string') {\n delete op.attributes.list\n }\n else if (typeof op.attributes.list === 'object' && !op.attributes.list.value) {\n op.attributes.list.value = value\n }\n })\n return delta\n}\n\nexport function matchInline(node, delta, scroll) {\n const quill = Quill.find(scroll.domNode.parentNode)\n const currentRange = quill.getSelection()\n const formats = currentRange && quill.getFormat(currentRange)\n if (\n formats\n && formats['table-cell-line'] // 当前光标节点在表格内,否则不操作delta\n && node.nextElementSibling\n ) {\n // 插入节点是否存在下一个兄弟元素\n const match = scroll.query(node)\n const nodeHtml = node.nextElementSibling.innerHTML\n const nodeText = node.nextElementSibling.textContent\n if (\n (match && match.prototype instanceof InlineBlot) // 判断当前节点是否为内联\n || (node.tagName === 'P' && nodeHtml !== nodeText)\n ) {\n // 非内联时如果为P且下一个不为text节点\n delta.forEach((op) => {\n op.insert += '\\n'\n })\n }\n }\n return delta\n}\n\n// 匹配 word 自带的 v:shape 标签中的图片 v:imageData\nexport function matchWordShapeImage(node, delta) {\n if (node) {\n const imageUrl = node.attributes.src?.nodeValue\n delta = new Delta().insert({ image: imageUrl })\n }\n return delta\n}\n\nexport function matchMentionLink(node, delta, scroll) {\n const name = node.dataset.mentionId\n if (name) {\n const quill = Quill.find(scroll.domNode.parentNode)\n const mention = quill.getModule('mention')\n if (mention) {\n mention.options.search(name).then((res) => {\n const [item] = res\n if (item) {\n mention.options.select(item)\n }\n })\n }\n }\n return delta\n}\n"],"names":["tableRowId","tableCellId","splitWithBreak","omit","colsNumber","CELL_MIN_WIDTH","TableViewWrapper"],"mappings":"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"}
1
+ {"version":3,"file":"node-matchers.cjs.js","sources":["../../../../../src/modules/table/utils/node-matchers.ts"],"sourcesContent":["import Quill from 'quill'\nimport { omit, splitWithBreak } from '../../../config/editor.utils'\nimport { cellId as tableCellId, rowId as tableRowId, TableViewWrapper } from '../formats/table'\nimport { CELL_MIN_WIDTH } from '../table-config'\n\nconst Delta = Quill.imports.delta\nconst InlineBlot = Quill.imports.parchment.InlineBlot\n\n// rebuild delta\nexport function matchTableCell(node, delta) {\n // fix: 移除旧数据中的pt高度,避免由于高度平均分导致无法插入行\n if (node.style.height.indexOf('pt')) {\n node.removeAttribute('style')\n }\n\n const row = node.parentNode\n let rowId = row.dataset.row\n if (!rowId) {\n rowId = row.dataset.row = tableRowId()\n }\n let cellId = node.dataset.cell\n // fix: dataset.cell in td will be 'undefined' when insert row/column\n if (!cellId || cellId === 'undefined') {\n cellId = tableCellId()\n }\n const colspan = node.getAttribute('colspan') || 1\n const rowspan = node.getAttribute('rowspan') || 1\n\n // fix: empty table cells copied from other place will be removed unexpectedly\n if (delta.length() === 0) {\n delta = new Delta().insert('\\n', {\n 'table-cell-line': { row: rowId, cell: cellId, rowspan, colspan },\n })\n return delta\n }\n\n delta = delta.reduce((newDelta, op) => {\n if (op.insert && typeof op.insert === 'string') {\n const lines = splitWithBreak(op.insert)\n\n lines.forEach((text) => {\n if (text === '\\n') {\n let attributes = {}\n const cellAttributes = {\n row: rowId,\n cell: cellId,\n rowspan,\n colspan,\n }\n if (op.attributes.table) {\n delete op.attributes.table\n }\n switch (true) {\n case !!op.attributes.header:\n attributes = Object.assign(op.attributes.header, cellAttributes)\n break\n case !!op.attributes.list:\n attributes = { list: Object.assign(op.attributes.list, cellAttributes) }\n break\n default:\n attributes = { 'table-cell-line': cellAttributes }\n }\n // fix: when td has background-color, quill can't set it to table-cell bolt\n if (op.attributes.background && attributes['table-cell-line']) {\n attributes['table-cell-line'].tdBgColor = op.attributes.background\n }\n newDelta.insert('\\n', Object.assign(op.attributes, attributes))\n }\n else {\n newDelta.insert(text, omit(op.attributes, ['table', 'table-cell-line', 'header', 'list']))\n }\n })\n }\n else {\n newDelta.insert(op.insert, op.attributes)\n }\n\n return newDelta\n }, new Delta())\n\n // fix: table cell height becomes larger(because insert unnecessary <div> on both sides of cell) when init table ngModel\n const regexp = /^[\\n]+$/\n const firstDelta = delta.ops[0]\n if (delta.ops.length >= 3) {\n const lastDelta = delta.ops[delta.ops.length - 1]\n if (regexp.test(firstDelta.insert) && firstDelta.attributes['table-cell-line']) {\n delta.ops.splice(0, 1)\n }\n if (regexp.test(lastDelta.insert) && lastDelta.attributes['table-cell-line']) {\n delta.ops[delta.ops.length - 1].insert = '\\n'\n }\n }\n else if (delta.ops.length === 1 && regexp.test(firstDelta.insert) && firstDelta.attributes['table-cell-line']) {\n delta.ops[0].insert = '\\n'\n }\n\n return delta\n}\n\n// replace th tag with td tag\nexport function matchTableHeader(node, delta, _scroll) {\n const row = node.parentNode\n const cells = Array.from(row.querySelectorAll('th'))\n let rowId = row.dataset.row\n if (!rowId) {\n rowId = row.dataset.row = tableRowId()\n }\n const cellId = cells.indexOf(node) + 1\n const colspan = node.getAttribute('colspan') || false\n const rowspan = node.getAttribute('rowspan') || false\n\n // fix: empty table cells copied from other place will be removed unexpectedly\n if (delta.length() === 0) {\n delta = new Delta().insert('\\n', {\n 'table-cell-line': { row: rowId, cell: cellId, rowspan, colspan },\n })\n return delta\n }\n\n delta = delta.reduce((newDelta, op) => {\n if (op.insert && typeof op.insert === 'string') {\n const lines = splitWithBreak(op.insert)\n\n // fix: no '\\n' in the end of op.insert, push a '\\n' to lines\n if (lines[lines.length - 1] !== '\\n') {\n lines.push('\\n')\n }\n\n lines.forEach((text) => {\n text === '\\n'\n ? newDelta.insert('\\n', { 'table-cell-line': { row: rowId, cell: cellId, rowspan, colspan } })\n : newDelta.insert(text, op.attributes)\n })\n }\n else {\n newDelta.insert(op.insert, op.attributes)\n }\n\n return newDelta\n }, new Delta())\n\n delta = delta.reduce((newDelta, op) => {\n if (op.insert && typeof op.insert === 'string' && op.insert.startsWith('\\n')) {\n newDelta.insert(op.insert, { 'table-cell-line': { row: rowId, cell: cellId, rowspan, colspan } })\n }\n else {\n newDelta.insert(op.insert, { ...omit(op.attributes, ['table', 'table-cell-line']) })\n }\n\n return newDelta\n }, new Delta())\n\n return delta\n}\n\n// supplement colgroup and col\nexport function matchTable(node, delta, scroll) {\n const isWordTable = node.children.length === 1\n if (!(node instanceof Element)) {\n return\n }\n const getMaxColNumber = (tds) => {\n if (isWordTable) {\n return tds.length\n }\n let colsNumber = 0\n tds.forEach((td) => {\n colsNumber += td.colSpan\n })\n return Math.max(tds.length, colsNumber)\n }\n\n const checkMinWidth = (width) => {\n if (Number.isNaN(width)) {\n // 无指定值时默认为auto,待渲染后修正\n return { 'table-col': { width: 'auto' } }\n }\n else if (width < CELL_MIN_WIDTH) {\n // 当列宽度小于默认宽度时取默认宽度\n return { 'table-col': true }\n }\n else {\n // 大于默认值取实际指定值\n return { 'table-col': { width } }\n }\n }\n\n // fix: a table with an empty tr is invalid, should not be displayed\n const rows = node.querySelectorAll('tr')\n const topRow = rows[0]\n const onlyEmptyTr = rows.length === 1 && !topRow.querySelector('td')\n\n // fix: empty table will return empty delta\n if (!topRow || onlyEmptyTr) {\n return new Delta().insert('\\n')\n }\n\n const colsNumber = node.querySelectorAll('col').length\n let maxCellsNumber = 0\n let maxCells\n // 遍历行获取最大列数和该行的所有单元格\n Array.prototype.slice.call(rows).forEach((row) => {\n const tds = row.querySelectorAll('td')\n maxCellsNumber = Math.max(getMaxColNumber(tds), maxCellsNumber)\n maxCells = tds\n })\n\n // 列的累计器\n let colCount = 0\n delta = delta.reduce((newDelta, op) => {\n // 当colCount与colsNumber相等时,则补充相差列\n if (colCount === colsNumber) {\n const fillNumber = maxCellsNumber - colCount\n const outset = colCount\n // index为差值列索引,通过遍历差值得到mexCells行中对应索引的单元格宽度\n for (let i = 0; i < fillNumber; i++) {\n const index = outset + i\n const colWidth = Number.parseInt(\n index < maxCells.length\n ? maxCells[index].width\n // maxCells[index].style && maxCells[index].style.width ? maxCells[index].style.width :\n : maxCells[maxCells.length - 1].width,\n 10,\n )\n newDelta.insert('\\n', checkMinWidth(colWidth))\n colCount++\n }\n }\n const attr = op.attributes || {}\n switch (true) {\n case !!attr['table-col']:\n // 只有当前列数小于实际总列数才操作,所以不存在大于的情况\n if (colCount < maxCellsNumber) {\n // 当table-col宽度一致时会合并为单一insert,insert长度大于1,截取符合实际总列数的长度来插入\n const insert = op.insert.slice(0, maxCellsNumber)\n const colWidth = Number.parseInt(attr['table-col'].width, 10)\n newDelta.insert(insert, checkMinWidth(colWidth))\n colCount += insert.length\n }\n break\n case !!attr.notFilled:\n { // 将标记的空tr填充对应列数的单元格\n const rowId = tableRowId()\n for (let x = 0; x < maxCellsNumber; x++) {\n newDelta.insert('\\n', { 'table-cell-line': { row: rowId, cell: tableCellId(), rowspan: 1, colspan: 1 } })\n }\n break }\n default:\n newDelta.insert(op.insert, op.attributes)\n }\n return newDelta\n }, new Delta())\n\n const tableItem = node.closest('.quill-better-table-wrapper') || node\n const prevBlot = tableItem.previousElementSibling && scroll.query(tableItem.previousElementSibling)\n const nextBlot = tableItem.nextElementSibling && scroll.query(tableItem.nextElementSibling)\n // fix: prevent two adjacent tables from sticking together\n if (!nextBlot || nextBlot.prototype instanceof InlineBlot) {\n delta = delta.insert('\\n')\n }\n // fix: When there is no line break in front of the table, pressing the Enter key will cause a problem with the table.\n if (!prevBlot || prevBlot.prototype instanceof InlineBlot) {\n const newLine = new Delta().insert('\\n')\n delta = newLine.concat(delta)\n }\n if (nextBlot === TableViewWrapper) {\n delta = delta.insert('\\n')\n }\n\n return delta\n}\n\nexport function matchTableRow(_node, delta) {\n // fix: 处理空<tr>标签被忽略的情况\n if (delta.ops.length === 1 && !delta.ops[0].attributes) {\n delta = new Delta().insert('\\n', { notFilled: true })\n }\n return delta\n}\n\n// match h tags, distinguish between headers in the table and headers outside the table\nexport function matchHeader(node, delta) {\n const newDelta = new Delta()\n const fontSize = node.style.fontSize\n delta.forEach((op) => {\n newDelta.insert(\n op.insert,\n Object.assign({}, op.attributes, {\n size: fontSize,\n }),\n )\n })\n return newDelta\n}\n\nexport function matchList(node, delta) {\n const value = node.tagName === 'UL' ? 'bullet' : 'ordered'\n delta.forEach((op) => {\n if (typeof op.attributes.list === 'string') {\n delete op.attributes.list\n }\n else if (typeof op.attributes.list === 'object' && !op.attributes.list.value) {\n op.attributes.list.value = value\n }\n })\n return delta\n}\n\nexport function matchInline(node, delta, scroll) {\n const quill = Quill.find(scroll.domNode.parentNode)\n const currentRange = quill.getSelection()\n const formats = currentRange && quill.getFormat(currentRange)\n if (\n formats\n && formats['table-cell-line'] // 当前光标节点在表格内,否则不操作delta\n && node.nextElementSibling\n ) {\n // 插入节点是否存在下一个兄弟元素\n const match = scroll.query(node)\n const nodeHtml = node.nextElementSibling.innerHTML\n const nodeText = node.nextElementSibling.textContent\n if (\n (match && match.prototype instanceof InlineBlot) // 判断当前节点是否为内联\n || (node.tagName === 'P' && nodeHtml !== nodeText)\n ) {\n // 非内联时如果为P且下一个不为text节点\n delta.forEach((op) => {\n op.insert += '\\n'\n })\n }\n }\n return delta\n}\n\n// 匹配 word 自带的 v:shape 标签中的图片 v:imageData\nexport function matchWordShapeImage(node, delta) {\n if (node) {\n const imageUrl = node.attributes.src?.nodeValue\n // 无有效地址时不插入,避免与 <img> 重复生成空图\n if (!imageUrl) {\n return delta\n }\n delta = new Delta().insert({ image: imageUrl })\n }\n return delta\n}\n\nexport function matchMentionLink(node, delta, scroll) {\n const name = node.dataset.mentionId\n if (name) {\n const quill = Quill.find(scroll.domNode.parentNode)\n const mention = quill.getModule('mention')\n if (mention) {\n mention.options.search(name).then((res) => {\n const [item] = res\n if (item) {\n mention.options.select(item)\n }\n })\n }\n }\n return delta\n}\n"],"names":["tableRowId","tableCellId","splitWithBreak","omit","colsNumber","CELL_MIN_WIDTH","TableViewWrapper"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@opentiny/fluent-editor",
3
3
  "type": "module",
4
- "version": "3.25.11",
4
+ "version": "3.25.12",
5
5
  "description": "A rich text editor based on Quill 2.0, which extends rich modules and formats on the basis of Quill. It's powerful and out-of-the-box.",
6
6
  "author": "OpenTiny Team",
7
7
  "license": "MIT",
@@ -18,6 +18,16 @@ export declare function isNullOrUndefined(param: any): boolean;
18
18
  * @return new Object without useless properties
19
19
  */
20
20
  export declare function omit(obj: any, uselessKeys: any): {};
21
+ export declare function getPasteImageSrc(image: any): any;
22
+ /**
23
+ * Outlook/Word 粘贴图常见无效 src:file://、cid:、sanitize 后的 //:0
24
+ */
25
+ export declare function isInvalidPasteImageSrc(src: any): boolean;
26
+ /**
27
+ * Outlook 粘贴时 v:imagedata 与 <img alt=image> 常成对出现,
28
+ * 去掉连续的无效重复图,并清除无意义的 alt="image"。
29
+ */
30
+ export declare function normalizeOutlookPasteImages(delta: any): any;
21
31
  /**
22
32
  * 将delta中的图片替换成制定的图片数组,用于图片上传到服务器的场景
23
33
  * @param delta 原始delta