Good question. I came up with a 'cave man' solution. Now apparently evergreen browsers will let you get access to the event.clipboardData data within a "copy" event attached to the document (this event is not supported on ie).
This means once you select the contents of an input via HTMLinputElement.select method, a "copy" event will be fired (provided that you attached it beforehand) which you can get access to event.clipboardData AND the setData method of it.
In the below example, watch out that the random number generation (I used 16 digits) might look wrong if the number notation defaults to scientific, you are better off with quartets. Also the example can be written much shorter if you have DOM manipulation library.
That being said, I will drop my cave man solution which I guess would work in older browsers (you can easily extend this to non input elements. For instance, attach a click event on a div with spans etc. Then get the textContent and modify and then proceed like below with the mockInput) :
<!DOCTYPE html>
<meta charset="utf-8">
<style>
</style>
<body>
<input id="someInput" type="text"></input>
<script id="mainScript" type="text/javascript">
!function(){
var someInput = document.getElementById("someInput"); //don't need to do this in chrome
/*generate an input with random hex*/
someInput.value = Number(Array.apply(null,Array(20))
.map(function(d,i){return ~~(Math.random()*16)})
.join(""))
.toString(16)
.slice(0,16)
.replace(
/(?:\w{4}(?=\w))/gi,
function(m,o,s){return m+"-"}
);
/*attach event handler*/
someInput.addEventListener("click",function(e){
/*if emtpy do nothing*/
if(!this.value){return}
/*create a dummy input element that will hold data
it needs to be part of the document so that we can
use copy command*/
var mockInput = document.createElement("input");
document.body.appendChild(mockInput);
/*making it 0 width/height or putting it inside
an invisible iframe or setting display none alerts
the browser to not execute copy, so best is to
copy and remove*/
mockInput.type = "text";
mockInput.value = this.value.replace(/\s|-/gi,"");
/*we will overlap it with the original element
and set the opacity to 0, at least the browser allows that*/
mockInput.style.opacity = 0;
mockInput.style.position = "absolute";
mockInput.style.top = someInput.offsetTop+"px";
mockInput.style.left = someInput.offsetLeft+"px";
mockInput.select();
document.execCommand("Copy");
alert("Copied to Clipboard");
/*remove once we are done*/
mockInput.parentNode.removeChild(mockInput);
},false)
}()
</script>
</body>
</html>
And here is a little function to generalize the use case:
node is the node to operate on, replacer is a function to be called and transform the contents of the node and shouldAlert will alert the user if set to true.
function copyContents(node,replacer,shouldAlert){
var contents = replacer(node.textContent || ("value" in node ? node.value : "")),
mockInput = node
.parentElement
.insertBefore(document.createElement("input"),node);
if(!contents){return}
copyContents._style = mockInput.style;
mockInput.type = "text";
mockInput.value = contents;
copyContents
._set("opacity",0)
._set("position","absolute")
._set("top",node.offsetTop+"px")
._set("left",node.offsetLeft+"px");
mockInput.select();
document.execCommand("Copy");
shouldAlert ? alert("Copied to Clipboard") : void(0);
mockInput.parentNode.removeChild(mockInput);
}
copyContents._set = function(prop,value){
this._style[prop] = value;
return this;
}
And the usage, try on google input :))
var input = document.getElementById("lst-ib")
input.addEventListener(
"mouseup",
function(e){
copyContents(
this,
function(x){return x.replace(/\s/gi,"")},
true
)
},
false
)