Skip to content

Commit

Permalink
Prioritize pasting files over pasting HTML content
Browse files Browse the repository at this point in the history
When right clicking and pasting an image the dataTransfer object
contains a file and text/html. If we paste the HTML content, the result
is often a broken image. This change prioritizes pasting the file over
pasting the HTML content.

The gotcha is that when pasting text from MS Word, the dataTransfer object
contains a File with a screenshot of the text and text/html with the
actual text. We need to check if the paste is from MS Word and if so,
we should paste the text instead of the screenshot.
  • Loading branch information
afcapel committed May 1, 2024
1 parent 968ceda commit 39d059b
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 13 deletions.
9 changes: 8 additions & 1 deletion src/test/system/level_2_input_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,14 @@ testGroup("Level 2 Input", testOptions, () => {
test("pasting text from MS Word", async () => {
const file = await createFile()
const dataTransfer = createDataTransfer({
"text/html": "<span class=\"MsoNormal\">abc</span>",
"text/html": `<html xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:w="urn:schemas-microsoft-com:office:word"
xmlns:m="http://schemas.microsoft.com/office/2004/12/omml"
xmlns="http://www.w3.org/TR/REC-html40">
<body>
<span class="MsoNormal">abc</span>
</body>
</html>`,
"text/plain": "abc",
Files: [ file ],
})
Expand Down
24 changes: 12 additions & 12 deletions src/trix/controllers/level_2_input_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { getAllAttributeNames, squishBreakableWhitespace } from "trix/core/helpe
import InputController from "trix/controllers/input_controller"
import * as config from "trix/config"

import { dataTransferIsPlainText, keyEventIsKeyboardCommand, objectsAreEqual } from "trix/core/helpers"
import { dataTransferIsMsOfficePaste, dataTransferIsPlainText, keyEventIsKeyboardCommand, objectsAreEqual } from "trix/core/helpers"

import { selectionChangeObserver } from "trix/observers/selection_change_observer"

Expand Down Expand Up @@ -360,8 +360,10 @@ export default class Level2InputController extends InputController {
insertFromPaste() {
const { dataTransfer } = this.event
const paste = { dataTransfer }

const href = dataTransfer.getData("URL")
const html = dataTransfer.getData("text/html")
const file = dataTransfer.files?.[0]

if (href) {
let string
Expand All @@ -378,7 +380,6 @@ export default class Level2InputController extends InputController {
this.withTargetDOMRange(function() {
return this.responder?.insertHTML(paste.html)
})

this.afterRender = () => {
return this.delegate?.inputControllerDidPaste(paste)
}
Expand All @@ -393,26 +394,25 @@ export default class Level2InputController extends InputController {
this.afterRender = () => {
return this.delegate?.inputControllerDidPaste(paste)
}
} else if (html) {
this.event.preventDefault()
paste.type = "text/html"
paste.html = html
} else if (file && !dataTransferIsMsOfficePaste(dataTransfer)) {
paste.type = "File"
paste.file = file
this.delegate?.inputControllerWillPaste(paste)
this.withTargetDOMRange(function() {
return this.responder?.insertHTML(paste.html)
return this.responder?.insertFile(paste.file)
})

this.afterRender = () => {
return this.delegate?.inputControllerDidPaste(paste)
}
} else if (dataTransfer.files?.length) {
paste.type = "File"
paste.file = dataTransfer.files[0]
} else if (html) {
this.event.preventDefault()
paste.type = "text/html"
paste.html = html
this.delegate?.inputControllerWillPaste(paste)
this.withTargetDOMRange(function() {
return this.responder?.insertFile(paste.file)
return this.responder?.insertHTML(paste.html)
})

this.afterRender = () => {
return this.delegate?.inputControllerDidPaste(paste)
}
Expand Down
6 changes: 6 additions & 0 deletions src/trix/core/helpers/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ export const dataTransferIsPlainText = function(dataTransfer) {
}
}

export const dataTransferIsMsOfficePaste = function(dataTransfer) {
return dataTransfer.types.includes("Files") &&
dataTransfer.types.includes("text/html") &&
dataTransfer.getData("text/html").includes("urn:schemas-microsoft-com:office:office")
}

export const dataTransferIsWritable = function(dataTransfer) {
if (!dataTransfer?.setData) return false

Expand Down

0 comments on commit 39d059b

Please sign in to comment.