Commit 1a697a6d authored by Vincent Tam's avatar Vincent Tam

Post finished: JS Copy Btn

parent f69c0320
Pipeline #58693206 passed with stages
in 36 seconds
title: "JavaScript Copy Button"
date: 2019-04-26T23:01:53+02:00
- technical support
- JavaScript
- Math.SE
draft: false
# Goal
To create a copy button for [my Math.SE comment template][1] in order to save
the trouble of copying and pasting.
# My first attempt
I put the boilerplate inside a Markdown codeblock to prevent them from getting
interpreted by [Hugo][8]'s Markdown parser. Under each codeblock, I placed the
copy button.
> ```
> Comment boilerplate goes here ...
> ```
> <button class="copyBtn">📝</button>
> ```
> Another comment boilerplate goes here ...
> ```
> <button class="copyBtn">📝</button>
> ...
[My page][1]'s original layout
{{< highlight js >}}
$(document).ready(function() {
$('.copyBtn').click(function() {
j });
function copy(selector) {
var screenTop = $(document).scrollTop();
var $temp = $("<div>");
$temp.attr("contenteditable", true)
.on("focus", function() { document.execCommand('selectAll',false,null) })
$('html, body').scrollTop(screenTop);
{{< /highlight >}}
`static/js/copyBtn.js` at Git tag `copyBtn0`
It worked fine in [Qutebrowser][2], but _not_ in [Firefox][3]. Since the later
is a popular web browser, I would like to fix my script so that it would
function in [Firefox][3].
# My second attempt
I tried simplifying the code by getting rid of [jQuery][4], after realising that
the JavaScript substitute for the function `$(document).ready()` _wasn't_ simple
at all.
Some Google search pointed me to the concept of [event delegation][5]. An event
listener _universal for all copy buttons_ had to invoke a `doCopy(target)`
method, where `target` is the HTML element containing the comment to be copied.
I personally find that [JavaScript Info's page][6] is much easier to read.
Nevertheless, once the model has been understood, the code written in
[David Walsh's page][5] is much easier to be maintained.
{{< highlight js >}}
document.getElementsByTagName("article")[0].addEventListener("click", function(e) {
if ( && == 'BUTTON') { // only act on buttons
function doCopy(target) {
var range = document.createRange();
s = window.getSelection();
// Reset selection
if (window.getSelection) {
if (window.getSelection().empty) { // Chrome
} else if (window.getSelection().removeAllRanges) { // Firefox
} else if (document.selection) { // IE?
{{< /highlight >}}
This version of `static/js/copyBtn.js` _did_ work in both [Qutebrowser][2] and
[Firefox][3]. However, sometimes, the _whole_ page was copied instead of the
`target`. I had tried resetting the selection, but that _didn't_ work. My
primitive debugging technique `console.log(range)` _didn't_ work: the _whole_
page could get copied while the `range` behaved normally.
# Back to basics
Finally, I have decided to convert the codeblocks into immutable `<textarea>`s
because [W3Schools's tutorial][7] only works for _HTML form elements_. To
prevent [Hugo][8] from parsing the contents inside the `<textarea>`s, they have
to be wrapped with a `<div>` block. This allows a significant simplification of
the script.
{{< highlight js "linenos=table,hl_lines=8-9" >}}
document.getElementsByTagName("article")[0].addEventListener("click", function(e) {
if ( && == 'BUTTON') {
function doCopy(target) {;
{{< /highlight >}}
Refined version of `static/js/copyBtn.js` at commit [4a4f46d1][9].
[1]: /page/math-se-comment-templates/
[2]: //
[3]: //
[4]: //
[5]: //
[6]: //
[7]: //
[8]: //
[9]: //
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment