Fossil SCM

Tweaks to the "Copy Button".

drh 2019-06-05 20:08 trunk merge
Commit 8ee5e55e3c2baac570baadc3d567fe0bac80b73782f93f92bd2ab389f3f42c34
+7 -5
--- src/copybtn.js
+++ src/copybtn.js
@@ -1,10 +1,11 @@
11
/* Manage "Copy Buttons" linked to target elements, to copy the text (or, parts
22
** thereof) of the target elements to the clipboard.
33
**
44
** Newly created buttons are <span> elements with an SVG background icon,
5
-** defined by the "copy-button" class in the default CSS style sheet.
5
+** defined by the "copy-button" class in the default CSS style sheet, and are
6
+** assigned the element ID "copy-<idTarget>".
67
**
78
** To simplify customization, the only properties modified for HTML-defined
89
** buttons are the "onclick" handler, and the "transition" and "opacity" styles
910
** (used for animation).
1011
**
@@ -17,17 +18,18 @@
1718
** <cchLength>, respectively. Set <cchLength> to "-1" to explicitly remove the
1819
** previous copy length limit.
1920
**
2021
** HTML snippet for statically created buttons:
2122
**
22
-** <span class="copy-button" id="idButton"
23
-** data-copytarget="idTarget" data-copylength="cchLength"></span>
23
+** <span class="copy-button" id="copy-<idTarget>"
24
+** data-copytarget="<idTarget>" data-copylength="<cchLength>"></span>
2425
*/
25
-function makeCopyButton(idButton,idTarget,cchLength){
26
+function makeCopyButton(idTarget,bFlipped,cchLength){
2627
var elButton = document.createElement("span");
2728
elButton.className = "copy-button";
28
- elButton.id = idButton;
29
+ if( bFlipped ) elButton.className += " copy-button-flipped";
30
+ elButton.id = "copy-" + idTarget;
2931
initCopyButton(elButton,idTarget,cchLength);
3032
return elButton;
3133
}
3234
function initCopyButtonById(idButton,idTarget,cchLength){
3335
var elButton = document.getElementById(idButton);
3436
--- src/copybtn.js
+++ src/copybtn.js
@@ -1,10 +1,11 @@
1 /* Manage "Copy Buttons" linked to target elements, to copy the text (or, parts
2 ** thereof) of the target elements to the clipboard.
3 **
4 ** Newly created buttons are <span> elements with an SVG background icon,
5 ** defined by the "copy-button" class in the default CSS style sheet.
 
6 **
7 ** To simplify customization, the only properties modified for HTML-defined
8 ** buttons are the "onclick" handler, and the "transition" and "opacity" styles
9 ** (used for animation).
10 **
@@ -17,17 +18,18 @@
17 ** <cchLength>, respectively. Set <cchLength> to "-1" to explicitly remove the
18 ** previous copy length limit.
19 **
20 ** HTML snippet for statically created buttons:
21 **
22 ** <span class="copy-button" id="idButton"
23 ** data-copytarget="idTarget" data-copylength="cchLength"></span>
24 */
25 function makeCopyButton(idButton,idTarget,cchLength){
26 var elButton = document.createElement("span");
27 elButton.className = "copy-button";
28 elButton.id = idButton;
 
29 initCopyButton(elButton,idTarget,cchLength);
30 return elButton;
31 }
32 function initCopyButtonById(idButton,idTarget,cchLength){
33 var elButton = document.getElementById(idButton);
34
--- src/copybtn.js
+++ src/copybtn.js
@@ -1,10 +1,11 @@
1 /* Manage "Copy Buttons" linked to target elements, to copy the text (or, parts
2 ** thereof) of the target elements to the clipboard.
3 **
4 ** Newly created buttons are <span> elements with an SVG background icon,
5 ** defined by the "copy-button" class in the default CSS style sheet, and are
6 ** assigned the element ID "copy-<idTarget>".
7 **
8 ** To simplify customization, the only properties modified for HTML-defined
9 ** buttons are the "onclick" handler, and the "transition" and "opacity" styles
10 ** (used for animation).
11 **
@@ -17,17 +18,18 @@
18 ** <cchLength>, respectively. Set <cchLength> to "-1" to explicitly remove the
19 ** previous copy length limit.
20 **
21 ** HTML snippet for statically created buttons:
22 **
23 ** <span class="copy-button" id="copy-<idTarget>"
24 ** data-copytarget="<idTarget>" data-copylength="<cchLength>"></span>
25 */
26 function makeCopyButton(idTarget,bFlipped,cchLength){
27 var elButton = document.createElement("span");
28 elButton.className = "copy-button";
29 if( bFlipped ) elButton.className += " copy-button-flipped";
30 elButton.id = "copy-" + idTarget;
31 initCopyButton(elButton,idTarget,cchLength);
32 return elButton;
33 }
34 function initCopyButtonById(idButton,idTarget,cchLength){
35 var elButton = document.getElementById(idButton);
36
--- src/default_css.txt
+++ src/default_css.txt
@@ -771,15 +771,21 @@
771771
}
772772
.copy-button {
773773
display: inline-block;
774774
width: 14px;
775775
height: 14px;
776
- margin: -2px 0 0 0;
776
+//Note: .24em is slightly smaller than the average width of a normal space.
777
+ margin: -2px .24em 0 0;
777778
padding: 0;
778779
border: 0;
779780
vertical-align: middle;
780781
//Note: the mkcss utility does not support line breaks in data URIs.
781782
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Cpath style='fill: black; opacity:0' d='M 14 14 H 0 V 0 h 14 v 14 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");
782783
background-repeat: no-repeat;
783784
background-position: center;
784785
cursor: pointer;
786
+}
787
+.copy-button-flipped {
788
+//Note: .16em is suitable for element grouping.
789
+ margin-left: .16em;
790
+ margin-right: 0;
785791
}
786792
--- src/default_css.txt
+++ src/default_css.txt
@@ -771,15 +771,21 @@
771 }
772 .copy-button {
773 display: inline-block;
774 width: 14px;
775 height: 14px;
776 margin: -2px 0 0 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 14'%3E%3Cpath style='fill: black; opacity:0' d='M 14 14 H 0 V 0 h 14 v 14 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
--- src/default_css.txt
+++ src/default_css.txt
@@ -771,15 +771,21 @@
771 }
772 .copy-button {
773 display: inline-block;
774 width: 14px;
775 height: 14px;
776 //Note: .24em is slightly smaller than the average width of a normal space.
777 margin: -2px .24em 0 0;
778 padding: 0;
779 border: 0;
780 vertical-align: middle;
781 //Note: the mkcss utility does not support line breaks in data URIs.
782 background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Cpath style='fill: black; opacity:0' d='M 14 14 H 0 V 0 h 14 v 14 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");
783 background-repeat: no-repeat;
784 background-position: center;
785 cursor: pointer;
786 }
787 .copy-button-flipped {
788 //Note: .16em is suitable for element grouping.
789 margin-left: .16em;
790 margin-right: 0;
791 }
792
+11 -3
--- src/graph.js
+++ src/graph.js
@@ -108,11 +108,19 @@
108108
nodeHover: null, /* Graph node under mouse when ixHover==-2 */
109109
posX: 0, posY: 0 /* The last mouse position. */
110110
};
111111
112112
/* Functions used to control the tooltip popup and its timer */
113
+function onKeyDown(event){
114
+ var key = event.which || event.keyCode;
115
+ if( key==27 ){
116
+ event.stopPropagation();
117
+ hideGraphTooltip();
118
+ }
119
+}
113120
function hideGraphTooltip(){
121
+ document.removeEventListener('keydown',onKeyDown,/* useCapture == */true);
114122
stopCloseTimer();
115123
tooltipObj.style.display = "none";
116124
tooltipInfo.ixActive = -1;
117125
}
118126
document.body.onunload = hideGraphTooltip
@@ -557,10 +565,11 @@
557565
var p = tx.rowinfo[parseInt(this.id.match(/\d+$/)[0], 10)-tx.iTopRow];
558566
window.location.href = tx.baseUrl+"/info/"+p.h
559567
e.stopPropagation()
560568
}
561569
function findTxIndex(e){
570
+ if( !tx.rowinfo ) return -1;
562571
/* Look at all the graph elements. If any graph elements that is near
563572
** the click-point "e" and has a "data-ix" attribute, then return
564573
** the value of that attribute. Otherwise return -1 */
565574
var x = e.clientX + window.pageXOffset - absoluteX(canvasDiv);
566575
var y = e.clientY + window.pageYOffset - absoluteY(canvasDiv);
@@ -628,13 +637,11 @@
628637
}
629638
tooltipObj.style.borderColor =
630639
tooltipObj.style.color = s.getPropertyValue('color')
631640
tooltipObj.style.visibility = "hidden"
632641
tooltipObj.innerHTML = html
633
- tooltipObj.appendChild(document.createTextNode(' '));
634
- tooltipObj.appendChild(
635
- makeCopyButton("tooltip-copybtn","tooltip-link",0));
642
+ tooltipObj.appendChild(makeCopyButton("tooltip-link",true,0));
636643
tooltipObj.style.display = "inline"
637644
tooltipObj.style.position = "absolute"
638645
var x = tooltipInfo.posX + 4 + window.pageXOffset
639646
- absoluteX(tooltipObj.offsetParent)
640647
tooltipObj.style.left = x+"px"
@@ -641,10 +648,11 @@
641648
var y = tooltipInfo.posY + window.pageYOffset
642649
- tooltipObj.clientHeight - 4
643650
- absoluteY(tooltipObj.offsetParent)
644651
tooltipObj.style.top = y+"px"
645652
tooltipObj.style.visibility = "visible"
653
+ document.addEventListener('keydown',onKeyDown,/* useCapture == */true);
646654
}else{
647655
hideGraphTooltip()
648656
}
649657
}
650658
function dblclickOnGraph(e){
651659
--- src/graph.js
+++ src/graph.js
@@ -108,11 +108,19 @@
108 nodeHover: null, /* Graph node under mouse when ixHover==-2 */
109 posX: 0, posY: 0 /* The last mouse position. */
110 };
111
112 /* Functions used to control the tooltip popup and its timer */
 
 
 
 
 
 
 
113 function hideGraphTooltip(){
 
114 stopCloseTimer();
115 tooltipObj.style.display = "none";
116 tooltipInfo.ixActive = -1;
117 }
118 document.body.onunload = hideGraphTooltip
@@ -557,10 +565,11 @@
557 var p = tx.rowinfo[parseInt(this.id.match(/\d+$/)[0], 10)-tx.iTopRow];
558 window.location.href = tx.baseUrl+"/info/"+p.h
559 e.stopPropagation()
560 }
561 function findTxIndex(e){
 
562 /* Look at all the graph elements. If any graph elements that is near
563 ** the click-point "e" and has a "data-ix" attribute, then return
564 ** the value of that attribute. Otherwise return -1 */
565 var x = e.clientX + window.pageXOffset - absoluteX(canvasDiv);
566 var y = e.clientY + window.pageYOffset - absoluteY(canvasDiv);
@@ -628,13 +637,11 @@
628 }
629 tooltipObj.style.borderColor =
630 tooltipObj.style.color = s.getPropertyValue('color')
631 tooltipObj.style.visibility = "hidden"
632 tooltipObj.innerHTML = html
633 tooltipObj.appendChild(document.createTextNode(' '));
634 tooltipObj.appendChild(
635 makeCopyButton("tooltip-copybtn","tooltip-link",0));
636 tooltipObj.style.display = "inline"
637 tooltipObj.style.position = "absolute"
638 var x = tooltipInfo.posX + 4 + window.pageXOffset
639 - absoluteX(tooltipObj.offsetParent)
640 tooltipObj.style.left = x+"px"
@@ -641,10 +648,11 @@
641 var y = tooltipInfo.posY + window.pageYOffset
642 - tooltipObj.clientHeight - 4
643 - absoluteY(tooltipObj.offsetParent)
644 tooltipObj.style.top = y+"px"
645 tooltipObj.style.visibility = "visible"
 
646 }else{
647 hideGraphTooltip()
648 }
649 }
650 function dblclickOnGraph(e){
651
--- src/graph.js
+++ src/graph.js
@@ -108,11 +108,19 @@
108 nodeHover: null, /* Graph node under mouse when ixHover==-2 */
109 posX: 0, posY: 0 /* The last mouse position. */
110 };
111
112 /* Functions used to control the tooltip popup and its timer */
113 function onKeyDown(event){
114 var key = event.which || event.keyCode;
115 if( key==27 ){
116 event.stopPropagation();
117 hideGraphTooltip();
118 }
119 }
120 function hideGraphTooltip(){
121 document.removeEventListener('keydown',onKeyDown,/* useCapture == */true);
122 stopCloseTimer();
123 tooltipObj.style.display = "none";
124 tooltipInfo.ixActive = -1;
125 }
126 document.body.onunload = hideGraphTooltip
@@ -557,10 +565,11 @@
565 var p = tx.rowinfo[parseInt(this.id.match(/\d+$/)[0], 10)-tx.iTopRow];
566 window.location.href = tx.baseUrl+"/info/"+p.h
567 e.stopPropagation()
568 }
569 function findTxIndex(e){
570 if( !tx.rowinfo ) return -1;
571 /* Look at all the graph elements. If any graph elements that is near
572 ** the click-point "e" and has a "data-ix" attribute, then return
573 ** the value of that attribute. Otherwise return -1 */
574 var x = e.clientX + window.pageXOffset - absoluteX(canvasDiv);
575 var y = e.clientY + window.pageYOffset - absoluteY(canvasDiv);
@@ -628,13 +637,11 @@
637 }
638 tooltipObj.style.borderColor =
639 tooltipObj.style.color = s.getPropertyValue('color')
640 tooltipObj.style.visibility = "hidden"
641 tooltipObj.innerHTML = html
642 tooltipObj.appendChild(makeCopyButton("tooltip-link",true,0));
 
 
643 tooltipObj.style.display = "inline"
644 tooltipObj.style.position = "absolute"
645 var x = tooltipInfo.posX + 4 + window.pageXOffset
646 - absoluteX(tooltipObj.offsetParent)
647 tooltipObj.style.left = x+"px"
@@ -641,10 +648,11 @@
648 var y = tooltipInfo.posY + window.pageYOffset
649 - tooltipObj.clientHeight - 4
650 - absoluteY(tooltipObj.offsetParent)
651 tooltipObj.style.top = y+"px"
652 tooltipObj.style.visibility = "visible"
653 document.addEventListener('keydown',onKeyDown,/* useCapture == */true);
654 }else{
655 hideGraphTooltip()
656 }
657 }
658 function dblclickOnGraph(e){
659
+17 -13
--- src/info.c
+++ src/info.c
@@ -763,14 +763,14 @@
763763
" AND tag.tagid=tagxref.tagid "
764764
" AND +tag.tagname GLOB 'sym-*'", rid);
765765
while( db_step(&q2)==SQLITE_ROW ){
766766
const char *zTagName = db_column_text(&q2, 0);
767767
if( fossil_strcmp(zTagName,zBrName)==0 ){
768
- @ | <span class="copy-button" id="copy-br0"
769
- @ data-copytarget="br0" data-copylength="0">
770
- @ </span>&nbsp;<span
771
- @ id="br0">%z(href("%R/timeline?r=%T&unhide",zTagName))%h(zTagName)</a>
768
+ @ | <span class="copy-button" id="copy-name-br"
769
+ @ data-copytarget="name-br" data-copylength="0">
770
+ @ </span><span id="name-br"><!--
771
+ @ -->%z(href("%R/timeline?r=%T&unhide",zTagName))%h(zTagName)</a>
772772
@ </span>
773773
if( wiki_tagid2("branch",zTagName)!=0 ){
774774
blob_appendf(&wiki_read_links, " | %z%h</a>",
775775
href("%R/wiki?name=branch/%h",zTagName), zTagName);
776776
}else if( g.perm.Write && g.perm.WrWiki ){
@@ -798,13 +798,13 @@
798798
@ | %z(href("%R/tree?nofiles&type=tree&ci=%!S",zUuid))folders</a>
799799
@ </td>
800800
@ </tr>
801801
802802
@ <tr><th>%s(hname_alg(nUuid)):</th><td>
803
- @ <span class="copy-button" id="copy-fullhash"
804
- @ data-copytarget="fullhash" data-copylength="%d(hash_digits(1))">
805
- @ </span>&nbsp;<span id="fullhash">%.32s(zUuid)<wbr>%s(zUuid+32)</span>
803
+ @ <span class="copy-button" id="copy-hash-ci"
804
+ @ data-copytarget="hash-ci" data-copylength="%d(hash_digits(1))">
805
+ @ </span><span id="hash-ci">%.32s(zUuid)<wbr>%s(zUuid+32)</span>
806806
if( g.perm.Setup ){
807807
@ (Record ID: %d(rid))
808808
}
809809
@ </td></tr>
810810
@ <tr><th>User&nbsp;&amp;&nbsp;Date:</th><td>
@@ -1919,15 +1919,19 @@
19191919
}else{
19201920
style_submenu_element("Shun", "%s/shun?shun=%s#addshun", g.zTop, zUuid);
19211921
}
19221922
}
19231923
style_header("Hex Artifact Content");
1924
+ style_copy_button();
19241925
zUuid = db_text("?","SELECT uuid FROM blob WHERE rid=%d", rid);
1926
+ @ <h2>Artifact
1927
+ @ <span class="copy-button" id="copy-hash-ar"
1928
+ @ data-copytarget="hash-ar" data-copylength="%d(hash_digits(1))">
19251929
if( g.perm.Setup ){
1926
- @ <h2>Artifact %s(zUuid) (%d(rid)):</h2>
1930
+ @ </span><span id="hash-ar">%s(zUuid)</span> (%d(rid)):</h2>
19271931
}else{
1928
- @ <h2>Artifact %s(zUuid):</h2>
1932
+ @ </span><span id="hash-ar">%s(zUuid)</span>:</h2>
19291933
}
19301934
blob_zero(&downloadName);
19311935
if( P("verbose")!=0 ) objdescFlags |= OBJDESC_DETAIL;
19321936
object_description(rid, objdescFlags, &downloadName);
19331937
style_submenu_element("Download", "%s/raw/%T?name=%s",
@@ -2192,16 +2196,16 @@
21922196
@ <h2>Latest version of file '%h(zName)':</h2>
21932197
style_submenu_element("Artifact", "%R/artifact/%S", zUuid);
21942198
}else{
21952199
style_copy_button();
21962200
@ <h2>Artifact
2197
- @ <span class="copy-button" id="copy-artifacthash"
2198
- @ data-copytarget="artifacthash" data-copylength="%d(hash_digits(1))">
2201
+ @ <span class="copy-button" id="copy-hash-ar"
2202
+ @ data-copytarget="hash-ar" data-copylength="%d(hash_digits(1))">
21992203
if( g.perm.Setup ){
2200
- @ </span>&nbsp;<span id="artifacthash">%s(zUuid)</span> (%d(rid)):</h2>
2204
+ @ </span><span id="hash-ar">%s(zUuid)</span> (%d(rid)):</h2>
22012205
}else{
2202
- @ </span>&nbsp;<span id="artifacthash">%s(zUuid)</span>:</h2>
2206
+ @ </span><span id="hash-ar">%s(zUuid)</span>:</h2>
22032207
}
22042208
}
22052209
blob_zero(&downloadName);
22062210
asText = P("txt")!=0;
22072211
if( asText ) objdescFlags &= ~OBJDESC_BASE;
22082212
--- src/info.c
+++ src/info.c
@@ -763,14 +763,14 @@
763 " AND tag.tagid=tagxref.tagid "
764 " AND +tag.tagname GLOB 'sym-*'", rid);
765 while( db_step(&q2)==SQLITE_ROW ){
766 const char *zTagName = db_column_text(&q2, 0);
767 if( fossil_strcmp(zTagName,zBrName)==0 ){
768 @ | <span class="copy-button" id="copy-br0"
769 @ data-copytarget="br0" data-copylength="0">
770 @ </span>&nbsp;<span
771 @ id="br0">%z(href("%R/timeline?r=%T&unhide",zTagName))%h(zTagName)</a>
772 @ </span>
773 if( wiki_tagid2("branch",zTagName)!=0 ){
774 blob_appendf(&wiki_read_links, " | %z%h</a>",
775 href("%R/wiki?name=branch/%h",zTagName), zTagName);
776 }else if( g.perm.Write && g.perm.WrWiki ){
@@ -798,13 +798,13 @@
798 @ | %z(href("%R/tree?nofiles&type=tree&ci=%!S",zUuid))folders</a>
799 @ </td>
800 @ </tr>
801
802 @ <tr><th>%s(hname_alg(nUuid)):</th><td>
803 @ <span class="copy-button" id="copy-fullhash"
804 @ data-copytarget="fullhash" data-copylength="%d(hash_digits(1))">
805 @ </span>&nbsp;<span id="fullhash">%.32s(zUuid)<wbr>%s(zUuid+32)</span>
806 if( g.perm.Setup ){
807 @ (Record ID: %d(rid))
808 }
809 @ </td></tr>
810 @ <tr><th>User&nbsp;&amp;&nbsp;Date:</th><td>
@@ -1919,15 +1919,19 @@
1919 }else{
1920 style_submenu_element("Shun", "%s/shun?shun=%s#addshun", g.zTop, zUuid);
1921 }
1922 }
1923 style_header("Hex Artifact Content");
 
1924 zUuid = db_text("?","SELECT uuid FROM blob WHERE rid=%d", rid);
 
 
 
1925 if( g.perm.Setup ){
1926 @ <h2>Artifact %s(zUuid) (%d(rid)):</h2>
1927 }else{
1928 @ <h2>Artifact %s(zUuid):</h2>
1929 }
1930 blob_zero(&downloadName);
1931 if( P("verbose")!=0 ) objdescFlags |= OBJDESC_DETAIL;
1932 object_description(rid, objdescFlags, &downloadName);
1933 style_submenu_element("Download", "%s/raw/%T?name=%s",
@@ -2192,16 +2196,16 @@
2192 @ <h2>Latest version of file '%h(zName)':</h2>
2193 style_submenu_element("Artifact", "%R/artifact/%S", zUuid);
2194 }else{
2195 style_copy_button();
2196 @ <h2>Artifact
2197 @ <span class="copy-button" id="copy-artifacthash"
2198 @ data-copytarget="artifacthash" data-copylength="%d(hash_digits(1))">
2199 if( g.perm.Setup ){
2200 @ </span>&nbsp;<span id="artifacthash">%s(zUuid)</span> (%d(rid)):</h2>
2201 }else{
2202 @ </span>&nbsp;<span id="artifacthash">%s(zUuid)</span>:</h2>
2203 }
2204 }
2205 blob_zero(&downloadName);
2206 asText = P("txt")!=0;
2207 if( asText ) objdescFlags &= ~OBJDESC_BASE;
2208
--- src/info.c
+++ src/info.c
@@ -763,14 +763,14 @@
763 " AND tag.tagid=tagxref.tagid "
764 " AND +tag.tagname GLOB 'sym-*'", rid);
765 while( db_step(&q2)==SQLITE_ROW ){
766 const char *zTagName = db_column_text(&q2, 0);
767 if( fossil_strcmp(zTagName,zBrName)==0 ){
768 @ | <span class="copy-button" id="copy-name-br"
769 @ data-copytarget="name-br" data-copylength="0">
770 @ </span><span id="name-br"><!--
771 @ -->%z(href("%R/timeline?r=%T&unhide",zTagName))%h(zTagName)</a>
772 @ </span>
773 if( wiki_tagid2("branch",zTagName)!=0 ){
774 blob_appendf(&wiki_read_links, " | %z%h</a>",
775 href("%R/wiki?name=branch/%h",zTagName), zTagName);
776 }else if( g.perm.Write && g.perm.WrWiki ){
@@ -798,13 +798,13 @@
798 @ | %z(href("%R/tree?nofiles&type=tree&ci=%!S",zUuid))folders</a>
799 @ </td>
800 @ </tr>
801
802 @ <tr><th>%s(hname_alg(nUuid)):</th><td>
803 @ <span class="copy-button" id="copy-hash-ci"
804 @ data-copytarget="hash-ci" data-copylength="%d(hash_digits(1))">
805 @ </span><span id="hash-ci">%.32s(zUuid)<wbr>%s(zUuid+32)</span>
806 if( g.perm.Setup ){
807 @ (Record ID: %d(rid))
808 }
809 @ </td></tr>
810 @ <tr><th>User&nbsp;&amp;&nbsp;Date:</th><td>
@@ -1919,15 +1919,19 @@
1919 }else{
1920 style_submenu_element("Shun", "%s/shun?shun=%s#addshun", g.zTop, zUuid);
1921 }
1922 }
1923 style_header("Hex Artifact Content");
1924 style_copy_button();
1925 zUuid = db_text("?","SELECT uuid FROM blob WHERE rid=%d", rid);
1926 @ <h2>Artifact
1927 @ <span class="copy-button" id="copy-hash-ar"
1928 @ data-copytarget="hash-ar" data-copylength="%d(hash_digits(1))">
1929 if( g.perm.Setup ){
1930 @ </span><span id="hash-ar">%s(zUuid)</span> (%d(rid)):</h2>
1931 }else{
1932 @ </span><span id="hash-ar">%s(zUuid)</span>:</h2>
1933 }
1934 blob_zero(&downloadName);
1935 if( P("verbose")!=0 ) objdescFlags |= OBJDESC_DETAIL;
1936 object_description(rid, objdescFlags, &downloadName);
1937 style_submenu_element("Download", "%s/raw/%T?name=%s",
@@ -2192,16 +2196,16 @@
2196 @ <h2>Latest version of file '%h(zName)':</h2>
2197 style_submenu_element("Artifact", "%R/artifact/%S", zUuid);
2198 }else{
2199 style_copy_button();
2200 @ <h2>Artifact
2201 @ <span class="copy-button" id="copy-hash-ar"
2202 @ data-copytarget="hash-ar" data-copylength="%d(hash_digits(1))">
2203 if( g.perm.Setup ){
2204 @ </span><span id="hash-ar">%s(zUuid)</span> (%d(rid)):</h2>
2205 }else{
2206 @ </span><span id="hash-ar">%s(zUuid)</span>:</h2>
2207 }
2208 }
2209 blob_zero(&downloadName);
2210 asText = P("txt")!=0;
2211 if( asText ) objdescFlags &= ~OBJDESC_BASE;
2212
+36 -18
--- src/th_main.c
+++ src/th_main.c
@@ -992,17 +992,19 @@
992992
}
993993
return TH_OK;
994994
}
995995
996996
/*
997
-** TH1 command: copybtn TARGETID TEXT ?COPYLENGTH?
997
+** TH1 command: copybtn TARGETID FLIPPED TEXT ?COPYLENGTH?
998998
**
999999
** Output TEXT with a click-to-copy button next to it. Loads the copybtn.js
10001000
** Javascript module, and generates HTML elements with the following IDs:
10011001
**
10021002
** TARGETID: The <span> wrapper around TEXT.
10031003
** copy-TARGETID: The <span> for the copy button.
1004
+**
1005
+** If the FLIPPED argument is non-zero, the copy button is displayed after TEXT.
10041006
**
10051007
** The optional COPYLENGTH argument defines the length of the substring of TEXT
10061008
** copied to clipboard:
10071009
**
10081010
** <= 0: No limit (default if the argument is omitted).
@@ -1016,35 +1018,51 @@
10161018
void *p,
10171019
int argc,
10181020
const char **argv,
10191021
int *argl
10201022
){
1021
- if( argc!=3 && argc!=4 ){
1022
- return Th_WrongNumArgs(interp, "copybtn TARGETID TEXT COPYLENGTH");
1023
+ if( argc!=4 && argc!=5 ){
1024
+ return Th_WrongNumArgs(interp,
1025
+ "copybtn TARGETID FLIPPED TEXT ?COPYLENGTH?");
10231026
}
10241027
if( enableOutput ){
1028
+ int flipped = 0;
10251029
int copylength = 0;
10261030
char *zTargetId, *zText, *zResult;
1027
- if( argc==4 && Th_ToInt(interp, argv[3], argl[3], &copylength) ){
1028
- return TH_ERROR;
1031
+ if( Th_ToInt(interp, argv[2], argl[2], &flipped) ) return TH_ERROR;
1032
+ if( argc==5 ){
1033
+ if( Th_ToInt(interp, argv[4], argl[4], &copylength) ) return TH_ERROR;
10291034
}
10301035
if( copylength==1 ) copylength = hash_digits(0);
10311036
else if( copylength==2 ) copylength = hash_digits(1);
10321037
zTargetId = htmlize((char*)argv[1], argl[1]);
1033
- zText = htmlize((char*)argv[2], argl[2]);
1034
- zResult = mprintf(
1035
- "<span "
1036
- "class=\"copy-button\" "
1037
- "id=\"copy-%s\" "
1038
- "data-copytarget=\"%s\" "
1039
- "data-copylength=\"%d\">"
1040
- "</span>"
1041
- "&nbsp;"
1042
- "<span id=\"%s\">"
1043
- "%s"
1044
- "</span>",
1045
- zTargetId, zTargetId, copylength, zTargetId, zText);
1038
+ zText = htmlize((char*)argv[3], argl[3]);
1039
+ if( !flipped ){
1040
+ zResult = mprintf(
1041
+ "<span "
1042
+ "class=\"copy-button\" "
1043
+ "id=\"copy-%s\" "
1044
+ "data-copytarget=\"%s\" "
1045
+ "data-copylength=\"%d\">"
1046
+ "</span>"
1047
+ "<span id=\"%s\">"
1048
+ "%s"
1049
+ "</span>",
1050
+ zTargetId, zTargetId, copylength, zTargetId, zText);
1051
+ }else{
1052
+ zResult = mprintf(
1053
+ "<span id=\"%s\">"
1054
+ "%s"
1055
+ "</span>"
1056
+ "<span "
1057
+ "class=\"copy-button copy-button-flipped\" "
1058
+ "id=\"copy-%s\" "
1059
+ "data-copytarget=\"%s\" "
1060
+ "data-copylength=\"%d\">"
1061
+ "</span>",
1062
+ zTargetId, zText, zTargetId, zTargetId, copylength);
1063
+ }
10461064
free(zTargetId);
10471065
free(zText);
10481066
style_copy_button();
10491067
sendText(zResult, -1, 0);
10501068
free(zResult);
10511069
--- src/th_main.c
+++ src/th_main.c
@@ -992,17 +992,19 @@
992 }
993 return TH_OK;
994 }
995
996 /*
997 ** TH1 command: copybtn TARGETID TEXT ?COPYLENGTH?
998 **
999 ** Output TEXT with a click-to-copy button next to it. Loads the copybtn.js
1000 ** Javascript module, and generates HTML elements with the following IDs:
1001 **
1002 ** TARGETID: The <span> wrapper around TEXT.
1003 ** copy-TARGETID: The <span> for the copy button.
 
 
1004 **
1005 ** The optional COPYLENGTH argument defines the length of the substring of TEXT
1006 ** copied to clipboard:
1007 **
1008 ** <= 0: No limit (default if the argument is omitted).
@@ -1016,35 +1018,51 @@
1016 void *p,
1017 int argc,
1018 const char **argv,
1019 int *argl
1020 ){
1021 if( argc!=3 && argc!=4 ){
1022 return Th_WrongNumArgs(interp, "copybtn TARGETID TEXT COPYLENGTH");
 
1023 }
1024 if( enableOutput ){
 
1025 int copylength = 0;
1026 char *zTargetId, *zText, *zResult;
1027 if( argc==4 && Th_ToInt(interp, argv[3], argl[3], &copylength) ){
1028 return TH_ERROR;
 
1029 }
1030 if( copylength==1 ) copylength = hash_digits(0);
1031 else if( copylength==2 ) copylength = hash_digits(1);
1032 zTargetId = htmlize((char*)argv[1], argl[1]);
1033 zText = htmlize((char*)argv[2], argl[2]);
1034 zResult = mprintf(
1035 "<span "
1036 "class=\"copy-button\" "
1037 "id=\"copy-%s\" "
1038 "data-copytarget=\"%s\" "
1039 "data-copylength=\"%d\">"
1040 "</span>"
1041 "&nbsp;"
1042 "<span id=\"%s\">"
1043 "%s"
1044 "</span>",
1045 zTargetId, zTargetId, copylength, zTargetId, zText);
 
 
 
 
 
 
 
 
 
 
 
 
 
1046 free(zTargetId);
1047 free(zText);
1048 style_copy_button();
1049 sendText(zResult, -1, 0);
1050 free(zResult);
1051
--- src/th_main.c
+++ src/th_main.c
@@ -992,17 +992,19 @@
992 }
993 return TH_OK;
994 }
995
996 /*
997 ** TH1 command: copybtn TARGETID FLIPPED TEXT ?COPYLENGTH?
998 **
999 ** Output TEXT with a click-to-copy button next to it. Loads the copybtn.js
1000 ** Javascript module, and generates HTML elements with the following IDs:
1001 **
1002 ** TARGETID: The <span> wrapper around TEXT.
1003 ** copy-TARGETID: The <span> for the copy button.
1004 **
1005 ** If the FLIPPED argument is non-zero, the copy button is displayed after TEXT.
1006 **
1007 ** The optional COPYLENGTH argument defines the length of the substring of TEXT
1008 ** copied to clipboard:
1009 **
1010 ** <= 0: No limit (default if the argument is omitted).
@@ -1016,35 +1018,51 @@
1018 void *p,
1019 int argc,
1020 const char **argv,
1021 int *argl
1022 ){
1023 if( argc!=4 && argc!=5 ){
1024 return Th_WrongNumArgs(interp,
1025 "copybtn TARGETID FLIPPED TEXT ?COPYLENGTH?");
1026 }
1027 if( enableOutput ){
1028 int flipped = 0;
1029 int copylength = 0;
1030 char *zTargetId, *zText, *zResult;
1031 if( Th_ToInt(interp, argv[2], argl[2], &flipped) ) return TH_ERROR;
1032 if( argc==5 ){
1033 if( Th_ToInt(interp, argv[4], argl[4], &copylength) ) return TH_ERROR;
1034 }
1035 if( copylength==1 ) copylength = hash_digits(0);
1036 else if( copylength==2 ) copylength = hash_digits(1);
1037 zTargetId = htmlize((char*)argv[1], argl[1]);
1038 zText = htmlize((char*)argv[3], argl[3]);
1039 if( !flipped ){
1040 zResult = mprintf(
1041 "<span "
1042 "class=\"copy-button\" "
1043 "id=\"copy-%s\" "
1044 "data-copytarget=\"%s\" "
1045 "data-copylength=\"%d\">"
1046 "</span>"
1047 "<span id=\"%s\">"
1048 "%s"
1049 "</span>",
1050 zTargetId, zTargetId, copylength, zTargetId, zText);
1051 }else{
1052 zResult = mprintf(
1053 "<span id=\"%s\">"
1054 "%s"
1055 "</span>"
1056 "<span "
1057 "class=\"copy-button copy-button-flipped\" "
1058 "id=\"copy-%s\" "
1059 "data-copytarget=\"%s\" "
1060 "data-copylength=\"%d\">"
1061 "</span>",
1062 zTargetId, zText, zTargetId, zTargetId, copylength);
1063 }
1064 free(zTargetId);
1065 free(zText);
1066 style_copy_button();
1067 sendText(zResult, -1, 0);
1068 free(zResult);
1069
+1 -1
--- src/tktsetup.c
+++ src/tktsetup.c
@@ -447,11 +447,11 @@
447447
@ <table cellpadding="5">
448448
@ <tr><td class="tktDspLabel">Ticket&nbsp;UUID:</td>
449449
@ <th1>
450450
@ if {[info exists tkt_uuid]} {
451451
@ html "<td class='tktDspValue' colspan='3'>"
452
-@ copybtn tkt_uuid $tkt_uuid 1
452
+@ copybtn hash-tk 0 $tkt_uuid 1
453453
@ if {[hascap s]} {
454454
@ html " ($tkt_id)"
455455
@ }
456456
@ html "</td></tr>\n"
457457
@ } else {
458458
--- src/tktsetup.c
+++ src/tktsetup.c
@@ -447,11 +447,11 @@
447 @ <table cellpadding="5">
448 @ <tr><td class="tktDspLabel">Ticket&nbsp;UUID:</td>
449 @ <th1>
450 @ if {[info exists tkt_uuid]} {
451 @ html "<td class='tktDspValue' colspan='3'>"
452 @ copybtn tkt_uuid $tkt_uuid 1
453 @ if {[hascap s]} {
454 @ html " ($tkt_id)"
455 @ }
456 @ html "</td></tr>\n"
457 @ } else {
458
--- src/tktsetup.c
+++ src/tktsetup.c
@@ -447,11 +447,11 @@
447 @ <table cellpadding="5">
448 @ <tr><td class="tktDspLabel">Ticket&nbsp;UUID:</td>
449 @ <th1>
450 @ if {[info exists tkt_uuid]} {
451 @ html "<td class='tktDspValue' colspan='3'>"
452 @ copybtn hash-tk 0 $tkt_uuid 1
453 @ if {[hascap s]} {
454 @ html " ($tkt_id)"
455 @ }
456 @ html "</td></tr>\n"
457 @ } else {
458
+3 -1
--- www/th1.md
+++ www/th1.md
@@ -281,17 +281,19 @@
281281
than one then the display is a listbox with the number of lines given.
282282
283283
<a name="copybtn"></a>TH1 copybtn Command
284284
-----------------------------------------
285285
286
- * copybtn TARGETID TEXT ?COPYLENGTH?
286
+ * copybtn TARGETID FLIPPED TEXT ?COPYLENGTH?
287287
288288
Output TEXT with a click-to-copy button next to it. Loads the copybtn.js
289289
Javascript module, and generates HTML elements with the following IDs:
290290
291291
* TARGETID: The `<span>` wrapper around TEXT.
292292
* copy-TARGETID: The `<span>` for the copy button.
293
+
294
+If the FLIPPED argument is non-zero, the copy button is displayed after TEXT.
293295
294296
The optional COPYLENGTH argument defines the length of the substring of TEXT
295297
copied to clipboard:
296298
297299
* <= 0: No limit (default if the argument is omitted).
298300
--- www/th1.md
+++ www/th1.md
@@ -281,17 +281,19 @@
281 than one then the display is a listbox with the number of lines given.
282
283 <a name="copybtn"></a>TH1 copybtn Command
284 -----------------------------------------
285
286 * copybtn TARGETID TEXT ?COPYLENGTH?
287
288 Output TEXT with a click-to-copy button next to it. Loads the copybtn.js
289 Javascript module, and generates HTML elements with the following IDs:
290
291 * TARGETID: The `<span>` wrapper around TEXT.
292 * copy-TARGETID: The `<span>` for the copy button.
 
 
293
294 The optional COPYLENGTH argument defines the length of the substring of TEXT
295 copied to clipboard:
296
297 * <= 0: No limit (default if the argument is omitted).
298
--- www/th1.md
+++ www/th1.md
@@ -281,17 +281,19 @@
281 than one then the display is a listbox with the number of lines given.
282
283 <a name="copybtn"></a>TH1 copybtn Command
284 -----------------------------------------
285
286 * copybtn TARGETID FLIPPED TEXT ?COPYLENGTH?
287
288 Output TEXT with a click-to-copy button next to it. Loads the copybtn.js
289 Javascript module, and generates HTML elements with the following IDs:
290
291 * TARGETID: The `<span>` wrapper around TEXT.
292 * copy-TARGETID: The `<span>` for the copy button.
293
294 If the FLIPPED argument is non-zero, the copy button is displayed after TEXT.
295
296 The optional COPYLENGTH argument defines the length of the substring of TEXT
297 copied to clipboard:
298
299 * <= 0: No limit (default if the argument is omitted).
300

Keyboard Shortcuts

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