Fossil SCM

Introduce the "copy-button" CSS class with the SVG icon as the background image, to simplify the Javascript part.

florian 2019-05-29 12:39 tooltip-copyhash
Commit b0795ff6209e474be9d0fc14ef68df1ae9be1cc13568c097b1f3c1915bf7b5ab
2 files changed +14 +38 -49
--- src/default_css.txt
+++ src/default_css.txt
@@ -767,5 +767,19 @@
767767
background-color: #ffb;
768768
}
769769
label {
770770
white-space: nowrap;
771771
}
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
+}
772786
--- 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 @@
102102
idTimer: 0, /* The tooltip dwell timer id. */
103103
idTimerClose: 0, /* The tooltip close timer id. */
104104
ixHover: -1, /* The id of the element with the mouse. */
105105
ixActive: -1, /* The id of the element with the tooltip. */
106106
nodeHover: null, /* Graph node under mouse when ixHover==-2 */
107
- imgCopy: null, /* The image for the "Copy Hash" icon. */
108107
posX: 0, posY: 0 /* The last mouse position. */
109108
};
110109
111110
/* Functions used to control the tooltip popup and its timer */
112111
function hideGraphTooltip(){
@@ -596,13 +595,13 @@
596595
if( tooltipInfo.ixHover==-2 ){
597596
ix = parseInt(tooltipInfo.nodeHover.id.match(/\d+$/)[0],10)-tx.iTopRow
598597
var h = tx.rowinfo[ix].h
599598
var dest = tx.baseUrl + "/info/" + h
600599
if( tx.fileDiff ){
601
- html = "artifact <a id=\"copyhash\" href=\""+dest+"\">"+h+"</a>"
600
+ html = "artifact <a id=\"tooltip-link\" href=\""+dest+"\">"+h+"</a>"
602601
}else{
603
- html = "check-in <a id=\"copyhash\" href=\""+dest+"\">"+h+"</a>"
602
+ html = "check-in <a id=\"tooltip-link\" href=\""+dest+"\">"+h+"</a>"
604603
}
605604
tooltipInfo.ixActive = -2;
606605
}else if( tooltipInfo.ixHover>=0 ){
607606
ix = tooltipInfo.ixHover
608607
var br = tx.rowinfo[ix].br
@@ -610,11 +609,11 @@
610609
var hbr = br.replace(/&/g, "&amp;")
611610
.replace(/</g, "&lt;")
612611
.replace(/>/g, "&gt;")
613612
.replace(/"/g, "&quot;")
614613
.replace(/'/g, "&#039;");
615
- html = "branch <a id=\"copyhash\" href=\""+dest+"\">"+hbr+"</a>"
614
+ html = "branch <a id=\"tooltip-link\" href=\""+dest+"\">"+hbr+"</a>"
616615
tooltipInfo.ixActive = ix;
617616
}
618617
if( html ){
619618
/* Setup while hidden, to ensure proper dimensions. */
620619
var s = getComputedStyle(document.body)
@@ -625,15 +624,12 @@
625624
}
626625
tooltipObj.style.borderColor =
627626
tooltipObj.style.color = s.getPropertyValue('color')
628627
tooltipObj.style.visibility = "hidden"
629628
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. */
632629
tooltipObj.appendChild(document.createTextNode(' '));
633
- tooltipInfo.imgCopy = createCopyHashImg(tooltipInfo.imgCopy,"copyhash");
634
- tooltipObj.appendChild(tooltipInfo.imgCopy);
630
+ tooltipObj.appendChild(makeCopyButton(null,"tooltip-link"));
635631
tooltipObj.style.display = "inline"
636632
tooltipObj.style.position = "absolute"
637633
var x = tooltipInfo.posX + 4 + window.pageXOffset
638634
- absoluteX(tooltipObj.offsetParent)
639635
tooltipObj.style.left = x+"px"
@@ -751,51 +747,44 @@
751747
var tx = JSON.parse(txJson);
752748
TimelineGraph(tx);
753749
}
754750
}())
755751
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;
797786
}
798787
/* Create a temporary <textarea> element and copy the contents to clipboard. */
799788
function copyTextToClipboard(text){
800789
var textArea = document.createElement("textarea");
801790
textArea.style.position = 'fixed';
802791
--- 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, "&amp;")
611 .replace(/</g, "&lt;")
612 .replace(/>/g, "&gt;")
613 .replace(/"/g, "&quot;")
614 .replace(/'/g, "&#039;");
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, "&amp;")
610 .replace(/</g, "&lt;")
611 .replace(/>/g, "&gt;")
612 .replace(/"/g, "&quot;")
613 .replace(/'/g, "&#039;");
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

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button