Skip to content

Instantly share code, notes, and snippets.

@olemak
Last active May 20, 2016 10:32
Show Gist options
  • Save olemak/8ed80c649ba81afa91aa516e5692c6cb to your computer and use it in GitHub Desktop.
Save olemak/8ed80c649ba81afa91aa516e5692c6cb to your computer and use it in GitHub Desktop.
Adds a copy button after the tags you define (like code or pre). Clicking the button copies the preceeding element/tag text content to the OS clipboard.
function reactionaryCopybutton() {
var container = arguments.length <= 0 || arguments[0] === undefined ? document.getElementsByTagName('body')[0] : arguments[0];
var tags = arguments.length <= 1 || arguments[1] === undefined ? ['blockquote', 'pre', 'code'] : arguments[1];
var errorExplanation = 'Try to invoke reactionaryCopybutton() without parameters, or write something like this:';
var codesuggestion = '\tvar main = document.getElementById(\'#yourContentContainer\');\n\tvar tags = [\'pre\'];\n\treactionaryCopybutton(main, tags);';
try {
container.nodeType !== 1;
container['typeof'] !== 'undefined';
container !== 'NULL';
} catch (err) {
console.error(err + ' \n%cFirst argument must be a DOM node (or undefined).', 'font-weight: bold');
console.info(errorExplanation + '\n %c' + codesuggestion, 'color: #ababab');
};
try {
if (!Array.isArray(tags)) {
throw 'Tags is not an array';
};
} catch (err) {
console.error(err + ' \n%cSecond argument must be an Array of HTML tags (or empty)', 'font-weight: bold');
console.info(errorExplanation + '\n %c' + codesuggestion, 'color: #ababab');
};
if (document.execCommand) {
var hiddenCopyContainer = document.createElement('TEXTAREA');
hiddenCopyContainer.style.position = 'absolute';
hiddenCopyContainer.style.left = '-200vw';
hiddenCopyContainer.id = 'hiddenCopyContainer';
window.body.appendChild(hiddenCopyContainer);
var blocks = container.querySelectorAll(tags.join());
if (blocks.length > 0) {
for (var i = 0; i < blocks.length; i++) {
var copyButton = document.createElement('BUTTON');
copyButton.className = 'reactionary-copy-button';
copyButton.innerHTML = '<h5>Copy</h5>';
copyButton.addEventListener('click', reactionaryCopyClickListener.bind(null, blocks[i].innerText));
blocks[i].appendChild(copyButton);
}
}
}
}
function reactionaryCopyClickListener(textToCopy) {
var hiddenCopyContainer = document.getElementById('hiddenCopyContainer');
hiddenCopyContainer.value = textToCopy;
hiddenCopyContainer.select();
document.execCommand('copy');
}
@olemak
Copy link
Author

olemak commented May 19, 2016

Works in everything except IE<9, which is pretty good, and Safari.
If it does not work, no copy button(s) are displayed, so no loss.

IE and Edge has a "skipping bug"; it scrolls to the bottom of the page when a copy button is clicked. This is related to the position of hiddenCopyContainer (IE scrolls to the position of the selected input element, and in this case it's positioned at the bottom of the page (and off to the left a good ways).

Buttons are unstyled, but can be access bu the CSS class .reactionary-copy-button

@olemak
Copy link
Author

olemak commented May 20, 2016

Updated:
The first version was in EcmaScript 2015, so I figured it was a good idea to transpile it before sharing :)
Also added arguments, so rather than changing settings inside the function, it now accepts arguments.
And now that it accepts arguments, it needed to vet those arguments, so there are now tests for each of the arguments!

The two arguments are:
1: container - A DOM element. Limits the part of the document that the function affects. Default is the body node.
2: tags - An array of tag names that determines what element types (inside "container") that will receive copy buttons. Default is ['pre','code','blockquote'].

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment