Created
May 20, 2016 11:11
-
-
Save spiralx/1eeeaa3b4da220f8e6a99147c2af50a8 to your computer and use it in GitHub Desktop.
An ES6 class for auto-copying text content to the clipboard when particular elements are clicked
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* jshint asi: true, esnext: true */ | |
; (function() { | |
'use strict' | |
/* | |
Iterator for a selection's range objects e.g. | |
const r = [...ranges()] | |
*/ | |
function* ranges(sel=window.getSelection()) { | |
for (let i = 0; i < sel.rangeCount; i++) { | |
yield sel.getRangeAt(i) | |
} | |
} | |
// ---------------------------------------------------------------------------- | |
/* | |
Replace current selection with a single node. | |
*/ | |
function selectNode(sel, node) { | |
const r = document.createRange() | |
r.selectNode(node) | |
sel.removeAllRanges() | |
sel.addRange(r) | |
return sel | |
} | |
// ---------------------------------------------------------------------------- | |
/* | |
Wrap a function so that any changes it makes to the current | |
selection are reversed after it finishes e.g. | |
restoreSelection(sel => { | |
selectNode(sel, document.body) | |
document.execCommand('copy') | |
}) | |
would copy the contents of the document to the clipboard and | |
then restore the original selection. | |
*/ | |
function restoreSelection(fn) { | |
const selection = window.getSelection() | |
const savedRanges = [...ranges(selection)] | |
try { | |
return fn(selection) | |
} | |
finally { | |
selection.removeAllRanges() | |
for (const r of savedRanges) { | |
selection.addRange(r) | |
} | |
} | |
} | |
// ---------------------------------------------------------------------------- | |
class CopyOnClick { | |
constructor(...selectors) { | |
this.selectors = new Set() | |
this._listener = null | |
this._css = document.createElement('style') | |
this._css.type = 'text/css' | |
this.attach(...selectors) | |
} | |
get listening() { | |
return !!this._listener | |
} | |
attach(...selectors) { | |
const num_selectors = this.selectors.size | |
for (const sel of selectors) { | |
this.selectors.add(sel) | |
} | |
this._css.innerHTML = this.styles() | |
if (num_selectors === 0 && this.selectors.size > 0) { | |
this.on() | |
} | |
} | |
detach(...selectors) { | |
if (this.selectors.size > 0) { | |
for (const sel of selectors) { | |
this.selectors.remove(sel) | |
} | |
this._css.innerHTML = this.styles() | |
if (this.selectors.size === 0) { | |
this.off() | |
} | |
} | |
} | |
on() { | |
if (!this._listener && this.selectors.size > 0) { | |
this._listener = this.listener.bind(this) | |
document.body.addEventListener('click', this._listener) | |
document.body.appendChild(this._css) | |
console.info(`Listening for click events matching: ${this.selector()}`) | |
} | |
} | |
off() { | |
if (this._listener) { | |
document.body.removeChild(this._css) | |
document.body.removeEventListener('click', this._listener) | |
this._listener = null | |
console.info(`Stopped listening for click events`) | |
} | |
} | |
selector(suffix='') { | |
return [...this.selectors].map(s => s + suffix).sort().join(', ') | |
} | |
styles() { | |
return `${this.selector()} { cursor: pointer } ${this.selector(':hover')} { outline: solid 2px rgba(255, 255, 128, 0.4) }` | |
} | |
listener(event) { | |
const target = event.target | |
if (!target.matches(this.selector())) return | |
restoreSelection(sel => { | |
selectNode(sel, target) | |
try { | |
// Now that we've selected the anchor text, execute the copy command | |
const successful = document.execCommand('copy') | |
console.log(`Copy command was ${successful ? 'successful' : 'unsuccessful'}`) | |
return successful | |
} catch(err) { | |
console.log('Unable to copy: ${err}') | |
return false | |
} | |
}) | |
} | |
toString() { | |
return `CopyOnClick(${this.listening ? 'ON' : 'OFF'}, targets: ${this.selector()})` | |
} | |
} | |
// ---------------------------------------------------------------------------- | |
// Example for e.g. GitHub pages. | |
// window.copier = new CopyOnClick('code') | |
})() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment