It's possible to detect if a Microsoft Office application is the clipboard source
Taken from Pasting from Microsoft Excel defaults to pasting an image via the Uploader™ I looked into how you might fix this:
Converting tables to images is the opposite of what I normally want to do in an edit (image to markdown table!). There's a related bug where isn't not clear what you want paste: Copying text from OneNote and pasting creates an image instead of text but as you should never be pasting an image of a table in, we should actually fix this one!
If the devs can see a `text/HTML' data type on the clipboard event, and then interrogate the html returned you can detect where it's come from:
arguments[0].clipboardData.getData('text/HTML') `<html xmlns:v="urn:schemas-microsoft-com:vml"\r\nxmlns:o="urn:schemas-microsoft-com:office:office"\r\nxmlns:x="urn:schemas-microsoft-com:office:excel"\r\nxmlns="http://www.w3.org/TR/REC-html40">\r\n\r\n<head>\r\n<meta http-equiv=Content-Type content="text/html; charset=utf-8">\r\n<meta name=ProgId content=Excel.Sheet>\r\n<meta name=Generator content="Microsoft Excel 15">Which reveals
xmlns:x="urn:schemas-microsoft-com:office:excel"i.e. it's from Excel!Which presumably means you could change behaviour based on where the content is pasted from, and paste plain text?
This possibly explains why it's only on Windows.
Below is a small snippet that shows it's possible to detect and work around this bug:
function handlePaste(e) {
let clipboardData;
let htmlData;
let textData;
// Get pasted data via clipboard API
clipboardData = e.clipboardData || window.clipboardData;
htmlData = clipboardData.getData('text/HTML');
if (htmlData) {
parser = new DOMParser();
domData = parser.parseFromString(htmlData, 'text/html');
// 'urn:schemas-microsoft-com:office:excel'
let {
length,
[length - 1]: officeApp
} = domData?.querySelector('html')?.getAttribute('xmlns:x')?.split(':') ?? [];
if (officeApp === 'excel') {
console.log('found Excel Data')
textData = clipboardData.getData('Text');
const selection = window.getSelection();
if (!selection.rangeCount) return false;
selection.deleteFromDocument();
selection.getRangeAt(0).insertNode(document.createTextNode(textData));
event.preventDefault();
}
}
}
document.getElementById('editableDiv').addEventListener('paste', handlePaste);
<div id='editableDiv' contenteditable='true'>Paste<contenteditable='true' style="border: 1px solid lightgrey;">Paste Excel data here</div>