paste 이벤트와 클립보드 검사는 다른거다!
paste 이벤트에서 읽어온 클립보드 데이터 (pasteEvent.clipboardData)
- 웹에서 저장한 이미지의 이름은 무조건 name: "image.png"임. 크로 브라우저 기준으로, 이미지를 클립보드에 복사하면 이름은 무조건 image.png, MIME type도 image/png임.
- 반면 로컬에서 복사한 이미지들은 이름 그대로 잘 저장함.
특정 이벤트와 상관없이 클립보드에서 읽어온 데이터 (navigator.clipboard)
- 마찬가지로 웹에서 복사한 이미지는 image/png를 반환합니다. 단, paste 이벤트와 다른 점은 text/html과 image/png를 같이 반환한다는 것입니다.
- 자신의 로컬 환경에 있는 이미지 복사 => (text/html 형식으로 파일의 이름을 반환) 혹은 아무 것도 출력하지 않음. 파일 이름을 반환하는 점에서 착안해서 확장자를 정규식으로 발라내서 이미지인지 파악할 수 있겠지만 너무 위험함. 게다가 확장자가 없는 경우도 있음.
결론적으로
paste 이벤트와 관련없이 클립보드 정보를 확인하기 위해서는 유저의 권한을 받아야 하며, 받았다고 하더라도 접근할 수 있는 정보가 비교적 한정적임. 반면 paste 이벤트의 경우 유저가 명확한 의도를 가지고 클립보드의 정보를 붙여넣기 하겠다는 것이므로 클립보드 내부의 구체적인 정보를 확인할 수 있고, 조작할 수도 있음.
paste 이벤트에서 단순히 text 가져오기
- window.clipboardData.getData()는 최신 브라우저에서 보안상 이제 안됨. clipboard 읽는데 유저 permission이 필요함.
function handlePasteEvent (event) {
const clipboardData, pastedData;
// window.clipboardData는 IE 때 사용하던 거라던데 안 쓰려구요.
clipboardData = event.clipboardData;
pastedData = clipboardData.getData('Text'); //
console.log(pastedData);
}
document.addEventListener('paste', handlePasteEvent);
clipbard에 있는 내용을 가져오기
dnd api에서만 사용하는 줄 알았던 dataTransfer를 사용하게 되었다. paste event가 넘겨준 녀석을 File 객체로 만들기 위해서...
const handleClipboardPaste = async event => {
event.preventDefault()
const pasteData = event.clipboardData
for (const dataTransferItem of pasteData.items) {
if (dataTransferItem.type.match('^image/')) {
const file = dataTransferItem.getAsFile()
const maxFileSize = mb2byte(MAX_FILE_MB)
if (file.size > maxFileSize) {
return alert(`Only files under ${MAX_FILE_MB}mb can be uploaded.`)
}
const dataTransfer = new DataTransfer()
dataTransfer.items.add(file)
const fileList = dataTransfer.files
await addResourceCards({
type: 'file',
data: { files: fileList, folder: focusedItem }
})
}
if (dataTransferItem.type.match('^text/plain')) {
dataTransferItem.getAsString(async str => {
if (isValidUrl(str)) {
await addResourceCards({
type: 'url',
data: { url: str, folder: focusedItem }
})
}
})
}
}
}
특정 내용을 클립보드에 저장하기
const copyToClipboard = blob => {
if (blob) {
const { ClipboardItem } = window
const clipboardItem = new ClipboardItem({ [blob.type]: blob })
navigator.clipboard.write([clipboardItem])
}
}
const convertToPngAndCopyToClipboard = imgBlob => {
const imageUrl = window.URL.createObjectURL(imgBlob)
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
if (ctx) {
const imageEl = document.createElement('img')
imageEl.src = imageUrl
imageEl.onload = ({ target }) => {
const { width, height } = target
canvas.width = width
canvas.height = height
ctx.drawImage(target, 0, 0, width, height)
canvas.toBlob(copyToClipboard, 'image/png', 1)
}
}
}
const handleCopyURL = () => {
setIsClicked(true)
navigator.clipboard.writeText(data.data.url)
toolTipTimer()
}
const handleCopyImage = async () => {
try {
const response = await fetch(data.signedUrl)
const blob = await response.blob()
if (blob.type === 'image/png') {
copyToClipboard(blob)
} else {
convertToPngAndCopyToClipboard(blob)
}
} catch (e) {
console.error(e)
}
setIsClicked(true)
toolTipTimer()
}
export const isImageMimeType = mimeType => {
const filterImageMimeTypeList = [
'image/apng',
'image/avif',
'image/gif',
'image/jpeg',
'image/png',
'image/svg+xml',
'image/webp',
'image/bmp',
'image/tiff'
]
const filterMimeType = filterImageMimeTypeList.includes(mimeType)
? mimeType
: null
return isSupportedCopyToClipboardFromMimeType(filterMimeType)
}
const isSupportedCopyToClipboardFromMimeType = mimeType => {
const notSupportedImageMimeTypeList = [
'image/avif',
'image/bmp',
'image/tiff'
]
return notSupportedImageMimeTypeList.includes(mimeType) ? null : mimeType
}
그 외 자잘한 정보 및 reference
clipboard api : https://developer.mozilla.org/ko/docs/Web/API/Clipboard_API
clipboard 객체 : https://developer.mozilla.org/ko/docs/Web/API/Clipboard
const clipboard = navigator.clipboard // clipboard 객체 반환
clipboardItem : https://developer.mozilla.org/en-US/docs/Web/API/ClipboardItem
단순히 blob을 곧바로 clipboard에 넣는 것이 아니라, clipboardItem으로 변환 후 넣어야 합니다.
const { ClipboardItem } = window
const clipboardItem = new ClipboardItem({ [blob.type]: blob })
navigator.clipboard.write([clipboardItem])
blob과 file.
blob : https://developer.mozilla.org/ko/docs/Web/API/Blob
file: https://developer.mozilla.org/ko/docs/Web/API/File
'웹 전반, 브라우저 > Web API' 카테고리의 다른 글
IndexDB (2) : 좀 더 indexDB를 사용해보자. (0) | 2021.11.28 |
---|---|
IndexDB (1) : 간단한 개념을 알아보고 사용해보자 (0) | 2021.11.28 |
Gamepad API와, 게임 클라이언트 개발에서 웹개발의 역할 (0) | 2021.04.28 |
FileReader로 브라우저에서 file 다루기 (0) | 2021.02.09 |
Observer pattern, Observer API (0) | 2021.02.08 |