When you want to display code, you are probably using PRE
elements. The fact that these elements can contain markup makes them perfectly suited for syntax highlighting. Some plugins make it easier to copy the code using a button. Google Prettify has no such option. Let's see if we can make copying easier by providing a "double click to select all"-feature to our pre fields.
Getting a parent - the native way
In the past, I've used jQuery to do the heavy lifting in JavaScript. As browsers got better support for standard JavaScript API's this is often no longer needed. I'm a big fan of the closest
function, so let's implement it in native JavaScript:
function getClosest(el, tagName) {
tagName = tagName && tagName.toUpperCase();
if (!tagName || !el)
return null;
do
if (el.nodeName === tagName)
return el;
while (el = el.parentNode);
return null;
}
Select All on Double Click
Let's use Range
and document.getSelection
to select all the text of the PRE
element. On my site all elements contain CODE
and SPAN
elements that are needed for highlighting, so we use our getClosest
function to find the PRE
-parent:
document.addEventListener('dblclick', e => {
let pre = getClosest(e.target, "PRE");
if (pre) {
let range = new Range();
range.setStart(pre, 0);
range.setEnd(pre, 1);
document.getSelection().removeAllRanges();
document.getSelection().addRange(range);
}
});
The Range
API has partial support in IE11.
Need something smaller?
The code above is pretty small -- only 504 bytes. But if you are really set on something smaller, you could minify it further to 327 bytes by applying UglifyJS on it:
!function(){let e=document;e.addEventListener("dblclick",t=>{let n=function(e,t){if(!(t=t&&t.toUpperCase())||!e)return null;do{if(e.nodeName===t)return e}while(e=e.parentNode);return null}(t.target,"PRE");if(n){let t=new Range;t.setStart(n,0),t.setEnd(n,1),e.getSelection().removeAllRanges(),e.getSelection().addRange(t)}})}();
It gets somewhat smaller, but it does not get more readable! 😀 Check how minification got rit of the getClosest
method and just evaluates the result. Pretty neat!
Styling the selection
You might want to add some extra styling to the selection using CSS. The following CSS will add a gray background to the selection and keep the colors produced by the syntax highlighting:
pre::selection,
pre *::selection {
background-color: #999;
}
pre::selection,
pre *::-moz-selection {
background-color: #999;
}
Further reading
- In-depth study of
Range
by JavaScript.info: Selection and Range - CSS Tricks: Overriding The Default Text Selection Color With CSS
Improvements
2020-07-21: removed the jQuery dependency of the code and introduced the modern Range
API.
2020-04-22: the original article was written. It can be found here in the Internet Archive or here.