Copy rich text
Copy formatted contents from given HTML with JavaScript
by Loilo
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.28.0/codemirror.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.28.0/codemirror.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.28.0/mode/xml/xml.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.28.0/mode/css/css.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.28.0/mode/htmlmixed/htmlmixed.min.js"></script>
<textarea id="html"><!-- The HTML you want to copy -->
Hello <b>jsFiddle</b> user!
</textarea>
<button><svg fill="#FFFFFF" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z" fill="none"/><path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"/></svg></button>
CSS
html, body {
margin: 0;
height: 100%;
}
.CodeMirror {
height: 100%;
box-sizing: border-box;
}
.CodeMirror pre {
font-family: 'Roboto Mono', Monaco, Menlo, Consolas, monospace;
font-weight: inherit;
font-size: 15px;
line-height: 1.6;
}
.CodeMirror-focused .CodeMirror-selected,
.CodeMirror-line::selection,
.CodeMirror-line>span::selection,
.CodeMirror-line>span>span::selection {
background: #c7e6ff;
}
button {
position: fixed;
width: 3.6em;
height: 3.6em;
top: 2em;
right: 2em;
box-sizing: border-box;
z-index: 99;
text-align: center;
line-height: 1;
background-color: #1c90f3;
border: 0.2em solid white;
border-radius: 50%;
cursor: pointer;
}
button:focus {
outline: none;
border-color: #89c9ff;
}
button svg {
position: absolute;
left: 50%;
top: 50%;
margin: -12px 0 0 -12px;
}
@keyframes fading {
from {
opacity: 1;
transform: scale(1.1);
}
to {
opacity: 0;
transform: scale(1.5);
}
}
button.fading {
animation: fading 0.5s;
pointer-events: none;
}
JavaScript
// This is the actual copy function.
// It expects an HTML string to copy as rich text.
function copyFormatted (html) {
// Create an iframe (isolated container) for the HTML
var container = document.createElement('div')
container.innerHTML = html
// Hide element
container.style.position = 'fixed'
container.style.pointerEvents = 'none'
container.style.opacity = 0
// Detect all style sheets of the page
var activeSheets = Array.prototype.slice.call(document.styleSheets)
.filter(function (sheet) {
return !sheet.disabled
})
// Mount the iframe to the DOM to make `contentWindow` available
document.body.appendChild(container)
// Copy to clipboard
window.getSelection().removeAllRanges()
var range = document.createRange()
range.selectNode(container)
window.getSelection().addRange(range)
document.execCommand('copy')
for (var i = 0; i < activeSheets.length; i++) activeSheets[i].disabled = true
document.execCommand('copy')
for (var i = 0; i < activeSheets.length; i++) activeSheets[i].disabled = false
// Remove the iframe
document.body.removeChild(container)
}
// Below is some setup for this fiddle. It's not relevant for the actual <copy function.
// Set up CodeMirror editors
var htmlEditor = CodeMirror.fromTextArea(html, {
mode: 'text/html'
})
// Create nice animation on copy button click
document.querySelector('button').onclick = function () {
var animatedClone = this.cloneNode(true)
animatedClone.classList.add('fading')
animatedClone.addEventListener('animationend', function () {
animatedClone.parentNode.removeChild(animatedClone)
})
this.parentNode.appendChild(animatedClone)
// Do the copy!
console.log(htmlEditor.getValue())
copyFormatted(htmlEditor.getValue())
}