summaryrefslogtreecommitdiff
path: root/src/copybtn.js
blob: 869e3185668ce027536879b38e23f203808fe5b9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
/* Manage "Copy Buttons" linked to target elements, to copy the text (or, parts
** thereof) of the target elements to the clipboard.
**
** Newly created buttons are <button> elements plus a nested <span> element with
** an SVG background icon, defined by the "copy-button" class in the default CSS
** style sheet, and are assigned the element ID "copy-<idTarget>".
**
** For HTML-defined buttons, either initCopyButtonById(), or initCopyButton(),
** needs to be called to attach the "onclick" handler (done automatically from
** a handler attached to the "DOMContentLoaded" event). These functions create
** the nested <span> element if the <button> element has no child nodes. Using
** static HTML for the <span> element ensures the buttons are visible if there
** are script errors, which may be useful for Fossil JS hackers (as good parts
** of the Fossil web UI come down on JS errors, anyway).
**
** The initialization functions do not overwrite the "data-copytarget" and
** "data-copylength" attributes with empty or null values for <idTarget> and
** <cchLength>, respectively. Set <cchLength> to "-1" to explicitly remove the
** previous copy length limit.
**
** HTML snippet for statically created buttons:
**
**    <button
**       class="copy-button"
**       id="copy-<idTarget>"
**       data-copytarget="<idTarget>"
**       data-copylength="<cchLength>"
**       data-content="<content>">
**       <span></span>
**    </button>
*/
function makeCopyButton(idTarget,bFlipped,cchLength){
  var elButton = document.createElement("button");
  elButton.className = "copy-button";
  if( bFlipped ) elButton.className += " copy-button-flipped";
  elButton.id = "copy-" + idTarget;
  initCopyButton(elButton,idTarget,cchLength);
  return elButton;
}
function initCopyButtonById(idButton,idTarget,cchLength){
  idButton = idButton || "copy-" + idTarget;
  var elButton = document.getElementById(idButton);
  if( elButton ) initCopyButton(elButton,idTarget,cchLength);
  return elButton;
}
function initCopyButton(elButton,idTarget,cchLength){
  if( idTarget ) elButton.setAttribute("data-copytarget",idTarget);
  if( cchLength ) elButton.setAttribute("data-copylength",cchLength);
  elButton.onclick = clickCopyButton;
  /* Make sure the <button> contains a single nested <span>. */
  if( elButton.childElementCount!=1 || elButton.firstChild.tagName!="SPAN" ){
    while( elButton.firstChild ) elButton.removeChild(elButton.lastChild);
    elButton.appendChild(document.createElement("span"));
  }
  return elButton;
}
setTimeout(function(){
  var elButtons = document.getElementsByClassName("copy-button");
  for ( var i=0; i<elButtons.length; i++ ){
    initCopyButton(elButtons[i],0,0);
  }
},1);
/* The onclick handler for the "Copy Button". */
function clickCopyButton(e){
  e.preventDefault();   /* Mandatory for <a> and <button>. */
  e.stopPropagation();
  if( this.disabled ) return;   /* This check is probably redundant. */
  var idTarget = this.getAttribute("data-copytarget");
  var elTarget = document.getElementById(idTarget);
  if( elTarget ){
    var text = this.getAttribute("data-content");
    if( !text ){
      text = elTarget.innerText.replace(/^\s+|\s+$/g,"");
      var cchLength = parseInt(this.getAttribute("data-copylength"));
      if( !isNaN(cchLength) && cchLength>0 ){
        text = text.slice(0,cchLength);   /* Assume single-byte chars. */
      }
    }
    copyTextToClipboard(text);
  }
}
/* Create a temporary <textarea> element and copy the contents to clipboard. */
function copyTextToClipboard(text){
  if( window.clipboardData && window.clipboardData.setData ){
    window.clipboardData.setData("Text",text);
  }else{
    var elTextarea = document.createElement("textarea");
    elTextarea.style.position = "fixed";
    elTextarea.value = text;
    document.body.appendChild(elTextarea);
    elTextarea.select();
    try{
      document.execCommand("copy");
    }catch(err){
    }finally{
      document.body.removeChild(elTextarea);
    }
  }
}