Fossil SCM
Introduce the "copy-button" CSS class with the SVG icon as the background image, to simplify the Javascript part.
Commit
b0795ff6209e474be9d0fc14ef68df1ae9be1cc13568c097b1f3c1915bf7b5ab
Parent
3b5e74c4ca657d3…
2 files changed
+14
+38
-49
+14
| --- src/default_css.txt | ||
| +++ src/default_css.txt | ||
| @@ -767,5 +767,19 @@ | ||
| 767 | 767 | background-color: #ffb; |
| 768 | 768 | } |
| 769 | 769 | label { |
| 770 | 770 | white-space: nowrap; |
| 771 | 771 | } |
| 772 | +.copy-button { | |
| 773 | + display: inline-block; | |
| 774 | + width: 14px; | |
| 775 | + height: 16px; | |
| 776 | + margin: 0; | |
| 777 | + padding: 0; | |
| 778 | + border: 0; | |
| 779 | + vertical-align: middle; | |
| 780 | +//Note: the mkcss utility does not support line breaks in data URIs. | |
| 781 | + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 16'%3E%3Cpath style='fill: black; opacity:0' d='M 14 16 H 0 V 0 h 14 v 16 z'/%3E%3Cpath style='fill:rgb(240,240,240)' d='M 1 0 h 6.6 l 2 2 h 1 l 3.4 3.4 v 8.6 h -10 v -2 h -3 z'/%3E%3Cpath style='fill:rgb(64,64,64)' d='M 2 1 h 5 l 3 3 v 7 h -8 z'/%3E%3Cpath style='fill:rgb(248,248,248)' d='M 3 2 h 3.6 l 2.4 2.4 v 5.6 h -6 z'/%3E%3Cpath style='fill:rgb(80,128,208)' d='M 4 5 h 4 v 1 h -4 z m 0 2 h 4 v 1 h -4 z'/%3E%3Cpath style='fill:rgb(64,64,64)' d='M 5 3 h 5 l 3 3 v 7 h -8 z'/%3E%3Cpath style='fill:rgb(248,248,248)' d='M 10 4.4 v 1.6 h 1.6 z m -4 -0.6 h 3 v 3 h -3 z m 0 3 h 6 v 5.4 h -6 z'/%3E%3Cpath style='fill:rgb(80,128,208)' d='M 7 8 h 4 v 1 h -4 z m 0 2 h 4 v 1 h -4 z'/%3E%3C/svg%3E"); | |
| 782 | + background-repeat: no-repeat; | |
| 783 | + background-position: center; | |
| 784 | + cursor: pointer; | |
| 785 | +} | |
| 772 | 786 |
| --- src/default_css.txt | |
| +++ src/default_css.txt | |
| @@ -767,5 +767,19 @@ | |
| 767 | background-color: #ffb; |
| 768 | } |
| 769 | label { |
| 770 | white-space: nowrap; |
| 771 | } |
| 772 |
| --- src/default_css.txt | |
| +++ src/default_css.txt | |
| @@ -767,5 +767,19 @@ | |
| 767 | background-color: #ffb; |
| 768 | } |
| 769 | label { |
| 770 | white-space: nowrap; |
| 771 | } |
| 772 | .copy-button { |
| 773 | display: inline-block; |
| 774 | width: 14px; |
| 775 | height: 16px; |
| 776 | margin: 0; |
| 777 | padding: 0; |
| 778 | border: 0; |
| 779 | vertical-align: middle; |
| 780 | //Note: the mkcss utility does not support line breaks in data URIs. |
| 781 | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 16'%3E%3Cpath style='fill: black; opacity:0' d='M 14 16 H 0 V 0 h 14 v 16 z'/%3E%3Cpath style='fill:rgb(240,240,240)' d='M 1 0 h 6.6 l 2 2 h 1 l 3.4 3.4 v 8.6 h -10 v -2 h -3 z'/%3E%3Cpath style='fill:rgb(64,64,64)' d='M 2 1 h 5 l 3 3 v 7 h -8 z'/%3E%3Cpath style='fill:rgb(248,248,248)' d='M 3 2 h 3.6 l 2.4 2.4 v 5.6 h -6 z'/%3E%3Cpath style='fill:rgb(80,128,208)' d='M 4 5 h 4 v 1 h -4 z m 0 2 h 4 v 1 h -4 z'/%3E%3Cpath style='fill:rgb(64,64,64)' d='M 5 3 h 5 l 3 3 v 7 h -8 z'/%3E%3Cpath style='fill:rgb(248,248,248)' d='M 10 4.4 v 1.6 h 1.6 z m -4 -0.6 h 3 v 3 h -3 z m 0 3 h 6 v 5.4 h -6 z'/%3E%3Cpath style='fill:rgb(80,128,208)' d='M 7 8 h 4 v 1 h -4 z m 0 2 h 4 v 1 h -4 z'/%3E%3C/svg%3E"); |
| 782 | background-repeat: no-repeat; |
| 783 | background-position: center; |
| 784 | cursor: pointer; |
| 785 | } |
| 786 |
+38
-49
| --- src/graph.js | ||
| +++ src/graph.js | ||
| @@ -102,11 +102,10 @@ | ||
| 102 | 102 | idTimer: 0, /* The tooltip dwell timer id. */ |
| 103 | 103 | idTimerClose: 0, /* The tooltip close timer id. */ |
| 104 | 104 | ixHover: -1, /* The id of the element with the mouse. */ |
| 105 | 105 | ixActive: -1, /* The id of the element with the tooltip. */ |
| 106 | 106 | nodeHover: null, /* Graph node under mouse when ixHover==-2 */ |
| 107 | - imgCopy: null, /* The image for the "Copy Hash" icon. */ | |
| 108 | 107 | posX: 0, posY: 0 /* The last mouse position. */ |
| 109 | 108 | }; |
| 110 | 109 | |
| 111 | 110 | /* Functions used to control the tooltip popup and its timer */ |
| 112 | 111 | function hideGraphTooltip(){ |
| @@ -596,13 +595,13 @@ | ||
| 596 | 595 | if( tooltipInfo.ixHover==-2 ){ |
| 597 | 596 | ix = parseInt(tooltipInfo.nodeHover.id.match(/\d+$/)[0],10)-tx.iTopRow |
| 598 | 597 | var h = tx.rowinfo[ix].h |
| 599 | 598 | var dest = tx.baseUrl + "/info/" + h |
| 600 | 599 | if( tx.fileDiff ){ |
| 601 | - html = "artifact <a id=\"copyhash\" href=\""+dest+"\">"+h+"</a>" | |
| 600 | + html = "artifact <a id=\"tooltip-link\" href=\""+dest+"\">"+h+"</a>" | |
| 602 | 601 | }else{ |
| 603 | - html = "check-in <a id=\"copyhash\" href=\""+dest+"\">"+h+"</a>" | |
| 602 | + html = "check-in <a id=\"tooltip-link\" href=\""+dest+"\">"+h+"</a>" | |
| 604 | 603 | } |
| 605 | 604 | tooltipInfo.ixActive = -2; |
| 606 | 605 | }else if( tooltipInfo.ixHover>=0 ){ |
| 607 | 606 | ix = tooltipInfo.ixHover |
| 608 | 607 | var br = tx.rowinfo[ix].br |
| @@ -610,11 +609,11 @@ | ||
| 610 | 609 | var hbr = br.replace(/&/g, "&") |
| 611 | 610 | .replace(/</g, "<") |
| 612 | 611 | .replace(/>/g, ">") |
| 613 | 612 | .replace(/"/g, """) |
| 614 | 613 | .replace(/'/g, "'"); |
| 615 | - html = "branch <a id=\"copyhash\" href=\""+dest+"\">"+hbr+"</a>" | |
| 614 | + html = "branch <a id=\"tooltip-link\" href=\""+dest+"\">"+hbr+"</a>" | |
| 616 | 615 | tooltipInfo.ixActive = ix; |
| 617 | 616 | } |
| 618 | 617 | if( html ){ |
| 619 | 618 | /* Setup while hidden, to ensure proper dimensions. */ |
| 620 | 619 | var s = getComputedStyle(document.body) |
| @@ -625,15 +624,12 @@ | ||
| 625 | 624 | } |
| 626 | 625 | tooltipObj.style.borderColor = |
| 627 | 626 | tooltipObj.style.color = s.getPropertyValue('color') |
| 628 | 627 | tooltipObj.style.visibility = "hidden" |
| 629 | 628 | tooltipObj.innerHTML = html |
| 630 | - /* The "Copy Hash" icon is not added via tooltipObj.innerHTML, to allow | |
| 631 | - ** for the image to be cached during the lifetime of the current page. */ | |
| 632 | 629 | tooltipObj.appendChild(document.createTextNode(' ')); |
| 633 | - tooltipInfo.imgCopy = createCopyHashImg(tooltipInfo.imgCopy,"copyhash"); | |
| 634 | - tooltipObj.appendChild(tooltipInfo.imgCopy); | |
| 630 | + tooltipObj.appendChild(makeCopyButton(null,"tooltip-link")); | |
| 635 | 631 | tooltipObj.style.display = "inline" |
| 636 | 632 | tooltipObj.style.position = "absolute" |
| 637 | 633 | var x = tooltipInfo.posX + 4 + window.pageXOffset |
| 638 | 634 | - absoluteX(tooltipObj.offsetParent) |
| 639 | 635 | tooltipObj.style.left = x+"px" |
| @@ -751,51 +747,44 @@ | ||
| 751 | 747 | var tx = JSON.parse(txJson); |
| 752 | 748 | TimelineGraph(tx); |
| 753 | 749 | } |
| 754 | 750 | }()) |
| 755 | 751 | |
| 756 | -/* Create the image for the "Copy Hash" icon. */ | |
| 757 | -function createCopyHashImg(imgRecycled,idCopyTarget){ | |
| 758 | - var img = imgRecycled; | |
| 759 | - if( img==null ){ | |
| 760 | - img = document.createElement("img"); | |
| 761 | - img.src = | |
| 762 | -"data:image/svg+xml,"+ | |
| 763 | -"%3Csvg xmlns='http:"+"/"+"/www.w3.org/2000/svg' viewBox='0 0 14 16'%3E"+ | |
| 764 | -"%3Cpath style='fill: black; opacity:0' d='M 14 16 H 0 V 0 h 14 v 16 z'/%3E"+ | |
| 765 | -"%3Cpath style='fill:rgb(240,240,240)' d='M 1 0 h 6.6 l 2 2 h 1 l 3.4 3.4 v "+ | |
| 766 | -"8.6 h -10 v -2 h -3 z'/%3E%3Cpath style='fill:rgb(64,64,64)' d='M 2 1 h 5 l "+ | |
| 767 | -"3 3 v 7 h -8 z'/%3E%3Cpath style='fill:rgb(248,248,248)' d='M 3 2 h 3.6 l "+ | |
| 768 | -"2.4 2.4 v 5.6 h -6 z'/%3E%3Cpath style='fill:rgb(80,128,208)' d='M 4 5 h 4 v "+ | |
| 769 | -"1 h -4 z m 0 2 h 4 v 1 h -4 z'/%3E%3Cpath style='fill:rgb(64,64,64)' d='M 5 "+ | |
| 770 | -"3 h 5 l 3 3 v 7 h -8 z'/%3E%3Cpath style='fill:rgb(248,248,248)' d='M 10 4.4 "+ | |
| 771 | -"v 1.6 h 1.6 z m -4 -0.6 h 3 v 3 h -3 z m 0 3 h 6 v 5.4 h -6 z'/%3E%3Cpath "+ | |
| 772 | -"style= 'fill:rgb(80,128,208)' d='M 7 8 h 4 v 1 h -4 z m 0 2 h 4 v 1 h -4 "+ | |
| 773 | -"z'/%3E%3C/svg%3E"; | |
| 774 | - img.width = 14; | |
| 775 | - img.height = 16; | |
| 776 | - } | |
| 777 | - img.style.verticalAlign = "middle"; | |
| 778 | - img.style.cursor = "pointer"; | |
| 779 | - img.setAttribute("data-copytarget",idCopyTarget); | |
| 780 | - img.onclick = clickCopyHash; | |
| 781 | - return img; | |
| 782 | -} | |
| 783 | -/* The onclick handler for the "Copy Hash" icon on the tooltip. */ | |
| 784 | -var lockCopyHash = false; | |
| 785 | -function clickCopyHash(e){ | |
| 786 | - //e.preventDefault(); | |
| 787 | - e.stopPropagation(); | |
| 788 | - if( lockCopyHash ) return; | |
| 789 | - lockCopyHash = true; | |
| 790 | - var idCopyTarget = this.getAttribute("data-copytarget"); | |
| 791 | - var elCopyTarget = document.getElementById(idCopyTarget); | |
| 792 | - if( elCopyTarget ){ | |
| 793 | - var hash = elCopyTarget.innerText; | |
| 794 | - copyTextToClipboard(hash); | |
| 795 | - } | |
| 796 | - lockCopyHash = false; | |
| 752 | +/* Create (if necessary) and initialize a "Copy Text" button <idButton> linked | |
| 753 | +** to the target element <idTarget>. | |
| 754 | +** | |
| 755 | +** HTML snippet for statically created buttons: | |
| 756 | +** <span class="copy-button" id="idButton" data-copytarget="idTarget"></span> | |
| 757 | +** | |
| 758 | +** Note: <idTarget> can be set statically or dynamically, this function does not | |
| 759 | +** overwrite "data-copytarget" attributes with empty values. | |
| 760 | +*/ | |
| 761 | +function makeCopyButton(idButton,idTarget){ | |
| 762 | + var button = document.getElementById(idButton); | |
| 763 | + if( !button ){ | |
| 764 | + button = document.createElement("span"); | |
| 765 | + button.className = "copy-button"; | |
| 766 | + button.id = idButton; | |
| 767 | + } | |
| 768 | + if( idTarget ) button.setAttribute("data-copytarget",idTarget); | |
| 769 | + button.onclick = clickCopyButton; | |
| 770 | + return button; | |
| 771 | +} | |
| 772 | +/* The onclick handler for the "Copy Text" button. */ | |
| 773 | +var lockCopyText = false; | |
| 774 | +function clickCopyButton(e){ | |
| 775 | + e.preventDefault(); /* Mandatory for <a> and <button>. */ | |
| 776 | + e.stopPropagation(); | |
| 777 | + if( lockCopyText ) return; | |
| 778 | + lockCopyText = true; | |
| 779 | + var idTarget = this.getAttribute("data-copytarget"); | |
| 780 | + var elTarget = document.getElementById(idTarget); | |
| 781 | + if( elTarget ){ | |
| 782 | + var text = elTarget.innerText; | |
| 783 | + copyTextToClipboard(text); | |
| 784 | + } | |
| 785 | + lockCopyText = false; | |
| 797 | 786 | } |
| 798 | 787 | /* Create a temporary <textarea> element and copy the contents to clipboard. */ |
| 799 | 788 | function copyTextToClipboard(text){ |
| 800 | 789 | var textArea = document.createElement("textarea"); |
| 801 | 790 | textArea.style.position = 'fixed'; |
| 802 | 791 |
| --- src/graph.js | |
| +++ src/graph.js | |
| @@ -102,11 +102,10 @@ | |
| 102 | idTimer: 0, /* The tooltip dwell timer id. */ |
| 103 | idTimerClose: 0, /* The tooltip close timer id. */ |
| 104 | ixHover: -1, /* The id of the element with the mouse. */ |
| 105 | ixActive: -1, /* The id of the element with the tooltip. */ |
| 106 | nodeHover: null, /* Graph node under mouse when ixHover==-2 */ |
| 107 | imgCopy: null, /* The image for the "Copy Hash" icon. */ |
| 108 | posX: 0, posY: 0 /* The last mouse position. */ |
| 109 | }; |
| 110 | |
| 111 | /* Functions used to control the tooltip popup and its timer */ |
| 112 | function hideGraphTooltip(){ |
| @@ -596,13 +595,13 @@ | |
| 596 | if( tooltipInfo.ixHover==-2 ){ |
| 597 | ix = parseInt(tooltipInfo.nodeHover.id.match(/\d+$/)[0],10)-tx.iTopRow |
| 598 | var h = tx.rowinfo[ix].h |
| 599 | var dest = tx.baseUrl + "/info/" + h |
| 600 | if( tx.fileDiff ){ |
| 601 | html = "artifact <a id=\"copyhash\" href=\""+dest+"\">"+h+"</a>" |
| 602 | }else{ |
| 603 | html = "check-in <a id=\"copyhash\" href=\""+dest+"\">"+h+"</a>" |
| 604 | } |
| 605 | tooltipInfo.ixActive = -2; |
| 606 | }else if( tooltipInfo.ixHover>=0 ){ |
| 607 | ix = tooltipInfo.ixHover |
| 608 | var br = tx.rowinfo[ix].br |
| @@ -610,11 +609,11 @@ | |
| 610 | var hbr = br.replace(/&/g, "&") |
| 611 | .replace(/</g, "<") |
| 612 | .replace(/>/g, ">") |
| 613 | .replace(/"/g, """) |
| 614 | .replace(/'/g, "'"); |
| 615 | html = "branch <a id=\"copyhash\" href=\""+dest+"\">"+hbr+"</a>" |
| 616 | tooltipInfo.ixActive = ix; |
| 617 | } |
| 618 | if( html ){ |
| 619 | /* Setup while hidden, to ensure proper dimensions. */ |
| 620 | var s = getComputedStyle(document.body) |
| @@ -625,15 +624,12 @@ | |
| 625 | } |
| 626 | tooltipObj.style.borderColor = |
| 627 | tooltipObj.style.color = s.getPropertyValue('color') |
| 628 | tooltipObj.style.visibility = "hidden" |
| 629 | tooltipObj.innerHTML = html |
| 630 | /* The "Copy Hash" icon is not added via tooltipObj.innerHTML, to allow |
| 631 | ** for the image to be cached during the lifetime of the current page. */ |
| 632 | tooltipObj.appendChild(document.createTextNode(' ')); |
| 633 | tooltipInfo.imgCopy = createCopyHashImg(tooltipInfo.imgCopy,"copyhash"); |
| 634 | tooltipObj.appendChild(tooltipInfo.imgCopy); |
| 635 | tooltipObj.style.display = "inline" |
| 636 | tooltipObj.style.position = "absolute" |
| 637 | var x = tooltipInfo.posX + 4 + window.pageXOffset |
| 638 | - absoluteX(tooltipObj.offsetParent) |
| 639 | tooltipObj.style.left = x+"px" |
| @@ -751,51 +747,44 @@ | |
| 751 | var tx = JSON.parse(txJson); |
| 752 | TimelineGraph(tx); |
| 753 | } |
| 754 | }()) |
| 755 | |
| 756 | /* Create the image for the "Copy Hash" icon. */ |
| 757 | function createCopyHashImg(imgRecycled,idCopyTarget){ |
| 758 | var img = imgRecycled; |
| 759 | if( img==null ){ |
| 760 | img = document.createElement("img"); |
| 761 | img.src = |
| 762 | "data:image/svg+xml,"+ |
| 763 | "%3Csvg xmlns='http:"+"/"+"/www.w3.org/2000/svg' viewBox='0 0 14 16'%3E"+ |
| 764 | "%3Cpath style='fill: black; opacity:0' d='M 14 16 H 0 V 0 h 14 v 16 z'/%3E"+ |
| 765 | "%3Cpath style='fill:rgb(240,240,240)' d='M 1 0 h 6.6 l 2 2 h 1 l 3.4 3.4 v "+ |
| 766 | "8.6 h -10 v -2 h -3 z'/%3E%3Cpath style='fill:rgb(64,64,64)' d='M 2 1 h 5 l "+ |
| 767 | "3 3 v 7 h -8 z'/%3E%3Cpath style='fill:rgb(248,248,248)' d='M 3 2 h 3.6 l "+ |
| 768 | "2.4 2.4 v 5.6 h -6 z'/%3E%3Cpath style='fill:rgb(80,128,208)' d='M 4 5 h 4 v "+ |
| 769 | "1 h -4 z m 0 2 h 4 v 1 h -4 z'/%3E%3Cpath style='fill:rgb(64,64,64)' d='M 5 "+ |
| 770 | "3 h 5 l 3 3 v 7 h -8 z'/%3E%3Cpath style='fill:rgb(248,248,248)' d='M 10 4.4 "+ |
| 771 | "v 1.6 h 1.6 z m -4 -0.6 h 3 v 3 h -3 z m 0 3 h 6 v 5.4 h -6 z'/%3E%3Cpath "+ |
| 772 | "style= 'fill:rgb(80,128,208)' d='M 7 8 h 4 v 1 h -4 z m 0 2 h 4 v 1 h -4 "+ |
| 773 | "z'/%3E%3C/svg%3E"; |
| 774 | img.width = 14; |
| 775 | img.height = 16; |
| 776 | } |
| 777 | img.style.verticalAlign = "middle"; |
| 778 | img.style.cursor = "pointer"; |
| 779 | img.setAttribute("data-copytarget",idCopyTarget); |
| 780 | img.onclick = clickCopyHash; |
| 781 | return img; |
| 782 | } |
| 783 | /* The onclick handler for the "Copy Hash" icon on the tooltip. */ |
| 784 | var lockCopyHash = false; |
| 785 | function clickCopyHash(e){ |
| 786 | //e.preventDefault(); |
| 787 | e.stopPropagation(); |
| 788 | if( lockCopyHash ) return; |
| 789 | lockCopyHash = true; |
| 790 | var idCopyTarget = this.getAttribute("data-copytarget"); |
| 791 | var elCopyTarget = document.getElementById(idCopyTarget); |
| 792 | if( elCopyTarget ){ |
| 793 | var hash = elCopyTarget.innerText; |
| 794 | copyTextToClipboard(hash); |
| 795 | } |
| 796 | lockCopyHash = false; |
| 797 | } |
| 798 | /* Create a temporary <textarea> element and copy the contents to clipboard. */ |
| 799 | function copyTextToClipboard(text){ |
| 800 | var textArea = document.createElement("textarea"); |
| 801 | textArea.style.position = 'fixed'; |
| 802 |
| --- src/graph.js | |
| +++ src/graph.js | |
| @@ -102,11 +102,10 @@ | |
| 102 | idTimer: 0, /* The tooltip dwell timer id. */ |
| 103 | idTimerClose: 0, /* The tooltip close timer id. */ |
| 104 | ixHover: -1, /* The id of the element with the mouse. */ |
| 105 | ixActive: -1, /* The id of the element with the tooltip. */ |
| 106 | nodeHover: null, /* Graph node under mouse when ixHover==-2 */ |
| 107 | posX: 0, posY: 0 /* The last mouse position. */ |
| 108 | }; |
| 109 | |
| 110 | /* Functions used to control the tooltip popup and its timer */ |
| 111 | function hideGraphTooltip(){ |
| @@ -596,13 +595,13 @@ | |
| 595 | if( tooltipInfo.ixHover==-2 ){ |
| 596 | ix = parseInt(tooltipInfo.nodeHover.id.match(/\d+$/)[0],10)-tx.iTopRow |
| 597 | var h = tx.rowinfo[ix].h |
| 598 | var dest = tx.baseUrl + "/info/" + h |
| 599 | if( tx.fileDiff ){ |
| 600 | html = "artifact <a id=\"tooltip-link\" href=\""+dest+"\">"+h+"</a>" |
| 601 | }else{ |
| 602 | html = "check-in <a id=\"tooltip-link\" href=\""+dest+"\">"+h+"</a>" |
| 603 | } |
| 604 | tooltipInfo.ixActive = -2; |
| 605 | }else if( tooltipInfo.ixHover>=0 ){ |
| 606 | ix = tooltipInfo.ixHover |
| 607 | var br = tx.rowinfo[ix].br |
| @@ -610,11 +609,11 @@ | |
| 609 | var hbr = br.replace(/&/g, "&") |
| 610 | .replace(/</g, "<") |
| 611 | .replace(/>/g, ">") |
| 612 | .replace(/"/g, """) |
| 613 | .replace(/'/g, "'"); |
| 614 | html = "branch <a id=\"tooltip-link\" href=\""+dest+"\">"+hbr+"</a>" |
| 615 | tooltipInfo.ixActive = ix; |
| 616 | } |
| 617 | if( html ){ |
| 618 | /* Setup while hidden, to ensure proper dimensions. */ |
| 619 | var s = getComputedStyle(document.body) |
| @@ -625,15 +624,12 @@ | |
| 624 | } |
| 625 | tooltipObj.style.borderColor = |
| 626 | tooltipObj.style.color = s.getPropertyValue('color') |
| 627 | tooltipObj.style.visibility = "hidden" |
| 628 | tooltipObj.innerHTML = html |
| 629 | tooltipObj.appendChild(document.createTextNode(' ')); |
| 630 | tooltipObj.appendChild(makeCopyButton(null,"tooltip-link")); |
| 631 | tooltipObj.style.display = "inline" |
| 632 | tooltipObj.style.position = "absolute" |
| 633 | var x = tooltipInfo.posX + 4 + window.pageXOffset |
| 634 | - absoluteX(tooltipObj.offsetParent) |
| 635 | tooltipObj.style.left = x+"px" |
| @@ -751,51 +747,44 @@ | |
| 747 | var tx = JSON.parse(txJson); |
| 748 | TimelineGraph(tx); |
| 749 | } |
| 750 | }()) |
| 751 | |
| 752 | /* Create (if necessary) and initialize a "Copy Text" button <idButton> linked |
| 753 | ** to the target element <idTarget>. |
| 754 | ** |
| 755 | ** HTML snippet for statically created buttons: |
| 756 | ** <span class="copy-button" id="idButton" data-copytarget="idTarget"></span> |
| 757 | ** |
| 758 | ** Note: <idTarget> can be set statically or dynamically, this function does not |
| 759 | ** overwrite "data-copytarget" attributes with empty values. |
| 760 | */ |
| 761 | function makeCopyButton(idButton,idTarget){ |
| 762 | var button = document.getElementById(idButton); |
| 763 | if( !button ){ |
| 764 | button = document.createElement("span"); |
| 765 | button.className = "copy-button"; |
| 766 | button.id = idButton; |
| 767 | } |
| 768 | if( idTarget ) button.setAttribute("data-copytarget",idTarget); |
| 769 | button.onclick = clickCopyButton; |
| 770 | return button; |
| 771 | } |
| 772 | /* The onclick handler for the "Copy Text" button. */ |
| 773 | var lockCopyText = false; |
| 774 | function clickCopyButton(e){ |
| 775 | e.preventDefault(); /* Mandatory for <a> and <button>. */ |
| 776 | e.stopPropagation(); |
| 777 | if( lockCopyText ) return; |
| 778 | lockCopyText = true; |
| 779 | var idTarget = this.getAttribute("data-copytarget"); |
| 780 | var elTarget = document.getElementById(idTarget); |
| 781 | if( elTarget ){ |
| 782 | var text = elTarget.innerText; |
| 783 | copyTextToClipboard(text); |
| 784 | } |
| 785 | lockCopyText = false; |
| 786 | } |
| 787 | /* Create a temporary <textarea> element and copy the contents to clipboard. */ |
| 788 | function copyTextToClipboard(text){ |
| 789 | var textArea = document.createElement("textarea"); |
| 790 | textArea.style.position = 'fixed'; |
| 791 |