You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
docuseal/app/javascript/elements/clipboard_copy.js

153 lines
3.2 KiB

// Source: https://github.com/github/clipboard-copy-element
// License: MIT
export default class extends HTMLElement {
constructor () {
super()
this.addEventListener('click', clicked)
this.addEventListener('focus', focused)
this.addEventListener('blur', blurred)
}
connectedCallback () {
if (!this.hasAttribute('tabindex')) {
this.setAttribute('tabindex', '0')
}
if (!this.hasAttribute('role')) {
this.setAttribute('role', 'button')
}
}
get value () {
return this.getAttribute('value') || ''
}
set value (text) {
this.setAttribute('value', text)
}
}
function createNode (text) {
const node = document.createElement('pre')
node.style.width = '1px'
node.style.height = '1px'
node.style.position = 'fixed'
node.style.top = '5px'
node.textContent = text
return node
}
function copyNode (node) {
if ('clipboard' in navigator) {
return navigator.clipboard.writeText(node.textContent || '')
}
const selection = getSelection()
if (selection == null) {
return Promise.reject(new Error())
}
selection.removeAllRanges()
const range = document.createRange()
range.selectNodeContents(node)
selection.addRange(range)
document.execCommand('copy')
selection.removeAllRanges()
return Promise.resolve()
}
function copyText (text) {
if ('clipboard' in navigator) {
return navigator.clipboard.writeText(text)
}
const body = document.body
if (!body) {
return Promise.reject(new Error())
}
const node = createNode(text)
body.appendChild(node)
copyNode(node)
body.removeChild(node)
return Promise.resolve()
}
function copyTarget (content) {
if (
content instanceof HTMLInputElement ||
content instanceof HTMLTextAreaElement
) {
return copyText(content.value)
} else if (
content instanceof HTMLAnchorElement &&
content.hasAttribute('href')
) {
return copyText(content.href)
} else {
return copyNode(content)
}
}
async function copy (button) {
const id = button.getAttribute('for')
const text = button.getAttribute('value')
function trigger () {
button.dispatchEvent(new CustomEvent('clipboard-copy', { bubbles: true }))
}
function toggleActiveIcon () {
if (button.classList.contains('swap')) {
button.classList.toggle('swap-active')
}
}
if (text) {
await copyText(text)
trigger()
toggleActiveIcon()
} else if (id) {
const root = 'getRootNode' in Element.prototype ? button.getRootNode() : button.ownerDocument
if (!(root instanceof Document || ('ShadowRoot' in window && root instanceof ShadowRoot))) return
const node = root.getElementById(id)
if (node) {
await copyTarget(node)
trigger()
toggleActiveIcon()
}
}
}
function clicked (event) {
const button = event.currentTarget
if (button instanceof HTMLElement) {
copy(button)
}
}
function keydown (event) {
if (event.key === ' ' || event.key === 'Enter') {
const button = event.currentTarget
if (button instanceof HTMLElement) {
event.preventDefault()
copy(button)
}
}
}
function focused (event) {
event.currentTarget.addEventListener('keydown', keydown)
}
function blurred (event) {
event.currentTarget.removeEventListener('keydown', keydown)
}