From adf4c39caf9db139241b7ca19031eb8d78ca45ba Mon Sep 17 00:00:00 2001 From: siam <31573022+siam-ese@users.noreply.github.com> Date: Thu, 23 Jan 2025 16:45:21 +0800 Subject: [PATCH] feat: paste image if no excel html (#4558) --- .../services/clipboard/clipboard.service.ts | 18 ++++++------ .../sheets-ui/src/services/clipboard/utils.ts | 28 ++++++++++++++----- 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/packages/sheets-ui/src/services/clipboard/clipboard.service.ts b/packages/sheets-ui/src/services/clipboard/clipboard.service.ts index d38a508cd3c..7e85426ec0b 100644 --- a/packages/sheets-ui/src/services/clipboard/clipboard.service.ts +++ b/packages/sheets-ui/src/services/clipboard/clipboard.service.ts @@ -75,7 +75,7 @@ import { UniverPastePlugin } from './html-to-usm/paste-plugins/plugin-univer'; import { WordPastePlugin } from './html-to-usm/paste-plugins/plugin-word'; import { COPY_TYPE } from './type'; import { USMToHtmlService } from './usm-to-html/convertor'; -import { clipboardItemIsFromExcel, convertTextToTable, discreteRangeContainsRange, mergeSetRangeValues, rangeIntersectWithDiscreteRange } from './utils'; +import { convertTextToTable, discreteRangeContainsRange, htmlIsFromExcel, mergeSetRangeValues, rangeIntersectWithDiscreteRange } from './utils'; export const PREDEFINED_HOOK_NAME = { DEFAULT_COPY: 'default-copy', @@ -259,9 +259,11 @@ export class SheetClipboardService extends Disposable implements ISheetClipboard ? await item.getType(HTML_CLIPBOARD_MIME_TYPE).then((blob) => blob && blob.text()) : ''; - const imageIndex = types.findIndex((type) => imageMimeTypeSet.has(type)); + const isFromExcel = htmlIsFromExcel(html); - if (imageIndex !== -1) { + // clipboard item from excel may contain image, so we need to check if the clipboard item is from excel + const imageIndex = types.findIndex((type) => imageMimeTypeSet.has(type)); + if (imageIndex !== -1 && !isFromExcel) { const imageMimeType = types[imageIndex]!; const imageBlob = await item.getType(imageMimeType); @@ -277,7 +279,7 @@ export class SheetClipboardService extends Disposable implements ISheetClipboard if (html) { // Firstly see if the html content is from Excel - if (this._platformService.isWindows && (await clipboardItemIsFromExcel(html))) { + if (this._platformService.isWindows && isFromExcel) { this._notificationService.show({ type: 'warning', title: this._localeService.t('clipboard.shortCutNotify.title'), @@ -299,8 +301,10 @@ export class SheetClipboardService extends Disposable implements ISheetClipboard return false; } - legacyPaste(html?: string, text?: string, files?: File[]): Promise { - if (files) { + async legacyPaste(html?: string, text?: string, files?: File[]): Promise { + const isFromExcel = htmlIsFromExcel(html ?? ''); + + if (files && !isFromExcel) { return this._pasteFiles(files, PREDEFINED_HOOK_NAME.DEFAULT_PASTE); } else if (html) { return this._pasteHTML(html, PREDEFINED_HOOK_NAME.DEFAULT_PASTE); @@ -314,8 +318,6 @@ export class SheetClipboardService extends Disposable implements ISheetClipboard } else { return this._pasteUnrecognized(); } - - // return Promise.resolve(false); } rePasteWithPasteType(type: IPasteHookKeyType): boolean { diff --git a/packages/sheets-ui/src/services/clipboard/utils.ts b/packages/sheets-ui/src/services/clipboard/utils.ts index b2b03e26f5d..d56c4a6a85a 100644 --- a/packages/sheets-ui/src/services/clipboard/utils.ts +++ b/packages/sheets-ui/src/services/clipboard/utils.ts @@ -14,11 +14,11 @@ * limitations under the License. */ -import { ObjectMatrix } from '@univerjs/core'; -import { SetRangeValuesMutation } from '@univerjs/sheets'; import type { ICellData, IMutationInfo, IObjectMatrixPrimitiveType, IRange, Nullable } from '@univerjs/core'; import type { ISetRangeValuesMutationParams } from '@univerjs/sheets'; import type { IDiscreteRange } from '../../controllers/utils/range-tools'; +import { ObjectMatrix } from '@univerjs/core'; +import { SetRangeValuesMutation } from '@univerjs/sheets'; /** * @@ -95,13 +95,27 @@ export const getRepeatRange = (sourceRange: IRange, targetRange: IRange, isStric return repeatList; }; -export async function clipboardItemIsFromExcel(html: string): Promise { - if (html) { - const regex = /]*class=".*?xl.*?"[^>]*>.*?<\/td>/; - return regex.test(html); +export function htmlIsFromExcel(html: string): boolean { + if (!html) { + return false; } - return false; + const excelMarkers = [ + // Excel class names + /]*class=".*?xl.*?"[^>]*>/i, + // Excel namespace + /xmlns:x="urn:schemas-microsoft-com:office:excel"/i, + // Excel ProgID + /ProgId="Excel.Sheet"/i, + // Office specific namespace + /xmlns:o="urn:schemas-microsoft-com:office:office"/i, + // Excel specific style markers + /@mso-|mso-excel/i, + // Excel workbook metadata + //i, + ]; + + return excelMarkers.some((marker) => marker.test(html)); } export function mergeCellValues(...cellValues: IObjectMatrixPrimitiveType>[]) {