Skip to content

Commit

Permalink
Prevent duplicate file pastes
Browse files Browse the repository at this point in the history
This change prevents duplicate file pastes by checking if the paste event
is a file paste before handling it. This is necessary because Safari
doesn't support `beforeinput.insertFromPaste` for files, so we are handling
file pastes in the paste event handler too.

We need to check in the `beforeinput.insertFromPaste` event handler if the
event will be also handled by the paste event handler, to avoid duplicate
file pastes.
  • Loading branch information
afcapel committed May 1, 2024
1 parent 39d059b commit 2651ea1
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 5 deletions.
17 changes: 13 additions & 4 deletions src/trix/controllers/level_2_input_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,6 @@ export default class Level2InputController extends InputController {

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

if (href) {
let string
Expand Down Expand Up @@ -394,9 +393,9 @@ export default class Level2InputController extends InputController {
this.afterRender = () => {
return this.delegate?.inputControllerDidPaste(paste)
}
} else if (file && !dataTransferIsMsOfficePaste(dataTransfer)) {
} else if (processableFilePaste(this.event)) {
paste.type = "File"
paste.file = file
paste.file = dataTransfer.files[0]
this.delegate?.inputControllerWillPaste(paste)
this.withTargetDOMRange(function() {
return this.responder?.insertFile(paste.file)
Expand Down Expand Up @@ -582,10 +581,20 @@ const staticRangeToRange = function(staticRange) {

const dragEventHasFiles = (event) => Array.from(event.dataTransfer?.types || []).includes("Files")

const processableFilePaste = (event) => {
// Paste events that only have files are handled by the paste event handler,
// to work around Safari not supporting beforeinput.insertFromPaste for files.

// MS Office text pastes include a file with a screenshot of the text, but we should
// handle them as text pastes.
return event.dataTransfer.files?.[0] && !pasteEventHasFilesOnly(event) && !dataTransferIsMsOfficePaste(event)
}

const pasteEventHasFilesOnly = function(event) {
const clipboard = event.clipboardData
if (clipboard) {
return clipboard.types.includes("Files") && clipboard.types.length === 1 && clipboard.files.length >= 1
const fileTypes = Array.from(clipboard.types).filter((type) => type.match(/file/i)) // "Files", "application/x-moz-file"
return fileTypes.length === clipboard.types.length && clipboard.files.length >= 1
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/trix/core/helpers/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const dataTransferIsPlainText = function(dataTransfer) {
}
}

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

0 comments on commit 2651ea1

Please sign in to comment.