Index: src/copybtn.js
==================================================================
--- src/copybtn.js
+++ src/copybtn.js
@@ -58,11 +58,11 @@
this.style.transition = "opacity 400ms ease-in-out";
this.style.opacity = 0;
var idTarget = this.getAttribute("data-copytarget");
var elTarget = document.getElementById(idTarget);
if( elTarget ){
- var text = elTarget.innerText;
+ var 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);
Index: src/graph.js
==================================================================
--- src/graph.js
+++ src/graph.js
@@ -19,11 +19,11 @@
** "scrollToSelect": BOOLEAN, // Scroll to selection on first render
** "nrail": INTEGER, // Number of vertical "rails"
** "baseUrl": TEXT, // Top-level URL
** "dwellTimeout": INTEGER, // Tooltip show delay in milliseconds
** "closeTimeout": INTEGER, // Tooltip close delay in milliseconds
-** "digitHuman": INTEGER, // Limit of tooltip hashes ("hash-digits")
+** "hashDigits": INTEGER, // Limit of tooltip hashes ("hash-digits")
** "rowinfo": ROWINFO-ARRAY }
**
** The rowinfo field is an array of structures, one per entry in the timeline,
** where each structure has the following fields:
**
@@ -98,11 +98,11 @@
/* State information for the tooltip popup and its timers */
window.tooltipInfo = {
dwellTimeout: 250, /* The tooltip dwell timeout. */
closeTimeout: 3000, /* The tooltip close timeout. */
- digitHuman: 10, /* Limit of tooltip hashes ("hash-digits"). */
+ hashDigits: 16, /* Limit of tooltip hashes ("hash-digits"). */
idTimer: 0, /* The tooltip dwell timer id. */
idTimerClose: 0, /* The tooltip close timer id. */
ixHover: -1, /* The id of the element with the mouse. */
ixActive: -1, /* The id of the element with the tooltip. */
nodeHover: null, /* Graph node under mouse when ixHover==-2 */
@@ -143,11 +143,11 @@
function TimelineGraph(tx){
var topObj = document.getElementById("timelineTable"+tx.iTableId);
amendCss(tx.circleNodes, tx.showArrowheads);
tooltipInfo.dwellTimeout = tx.dwellTimeout
tooltipInfo.closeTimeout = tx.closeTimeout
- tooltipInfo.digitHuman = tx.digitHuman
+ tooltipInfo.hashDigits = tx.hashDigits
topObj.onclick = clickOnGraph
topObj.ondblclick = dblclickOnGraph
topObj.onmousemove = function(e) {
var ix = findTxIndex(e);
topObj.style.cursor = (ix<0) ? "" : "pointer"
@@ -597,11 +597,11 @@
var ix = -1
if( tooltipInfo.ixHover==-2 ){
ix = parseInt(tooltipInfo.nodeHover.id.match(/\d+$/)[0],10)-tx.iTopRow
var h = tx.rowinfo[ix].h
var dest = tx.baseUrl + "/info/" + h
- h = h.slice(0,tooltipInfo.digitHuman); // Assume single-byte characters.
+ h = h.slice(0,tooltipInfo.hashDigits); // Assume single-byte characters.
if( tx.fileDiff ){
html = "artifact "+h+""
}else{
html = "check-in "+h+""
}
Index: src/info.c
==================================================================
--- src/info.c
+++ src/info.c
@@ -763,11 +763,14 @@
" AND tag.tagid=tagxref.tagid "
" AND +tag.tagname GLOB 'sym-*'", rid);
while( db_step(&q2)==SQLITE_ROW ){
const char *zTagName = db_column_text(&q2, 0);
if( fossil_strcmp(zTagName,zBrName)==0 ){
- @ | %z(href("%R/timeline?r=%T&unhide",zTagName))%h(zTagName)
+ @ |
+ @
+ @ %z(href("%R/timeline?r=%T&unhide",zTagName))%h(zTagName)
if( wiki_tagid2("branch",zTagName)!=0 ){
blob_appendf(&wiki_read_links, " | %z%h",
href("%R/wiki?name=branch/%h",zTagName), zTagName);
}else if( g.perm.Write && g.perm.WrWiki ){
blob_appendf(&wiki_add_links, " | %z%h",
@@ -793,11 +796,14 @@
@ | %z(href("%R/fileage?name=%!S",zUuid))file ages
@ | %z(href("%R/tree?nofiles&type=tree&ci=%!S",zUuid))folders
@
@
- @
| %s(hname_alg(nUuid)): | %.32s(zUuid)%s(zUuid+32)
+ @ | %s(hname_alg(nUuid)): |
+ @
+ @ %.32s(zUuid)%s(zUuid+32)
if( g.perm.Setup ){
@ (Record ID: %d(rid))
}
@ |
@ | User & Date: |
@@ -2181,14 +2187,20 @@
}
zUuid = db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid);
if( isFile ){
@ Latest version of file '%h(zName)':
style_submenu_element("Artifact", "%R/artifact/%S", zUuid);
- }else if( g.perm.Setup ){
- @ Artifact %s(zUuid) (%d(rid)):
}else{
- @ Artifact %s(zUuid):
+ style_copy_button();
+ @ Artifact
+ @
+ if( g.perm.Setup ){
+ @ %s(zUuid) (%d(rid)):
+ }else{
+ @ %s(zUuid):
+ }
}
blob_zero(&downloadName);
asText = P("txt")!=0;
if( asText ) objdescFlags &= ~OBJDESC_BASE;
objType = object_description(rid, objdescFlags, &downloadName);
Index: src/printf.c
==================================================================
--- src/printf.c
+++ src/printf.c
@@ -48,11 +48,11 @@
/*
** Return the number of artifact hash digits to display. The number is for
** human output if the bForUrl is false and is destined for a URL if
** bForUrl is false.
*/
-static int hashDigits(int bForUrl){
+int hash_digits(int bForUrl){
static int nDigitHuman = 0;
static int nDigitUrl = 0;
if( nDigitHuman==0 ){
nDigitHuman = db_get_int("hash-digits", FOSSIL_HASH_DIGITS);
if( nDigitHuman < 6 ) nDigitHuman = 6;
@@ -66,11 +66,11 @@
/*
** Return the number of characters in a %S output.
*/
int length_of_S_display(void){
- return hashDigits(0);
+ return hash_digits(0);
}
/*
** Conversion types fall into various categories as defined by the
** following enumeration.
@@ -679,11 +679,11 @@
if( bufpt==0 ){
bufpt = "";
}else if( xtype==etDYNSTRING ){
zExtra = bufpt;
}else if( xtype==etSTRINGID ){
- precision = hashDigits(flag_altform2);
+ precision = hash_digits(flag_altform2);
}
length = StrNLen32(bufpt, limit);
if( precision>=0 && precision", -1, 0);
Th_Free(interp, azElem);
}
return TH_OK;
}
+
+/*
+** TH1 command: copybtn TARGETID TEXT ?COPYLENGTH?
+**
+** Output TEXT with a click-to-copy button next to it. Loads the copybtn.js
+** Javascript module, and generates HTML elements with the following IDs:
+**
+** TARGETID: The wrapper around TEXT.
+** copy-TARGETID: The for the copy button.
+**
+** The optional COPYLENGTH argument defines the length of the substring of TEXT
+** copied to clipboard:
+**
+** <= 0: No limit (default if the argument is omitted).
+** >= 3: Truncate TEXT after COPYLENGTH (single-byte) characters.
+** 1: Use the "hash-digits" setting as the limit.
+** 2: Use the length appropriate for URLs as the limit (defined at
+** compile-time by FOSSIL_HASH_DIGITS_URL, defaults to 16).
+*/
+static int copybtnCmd(
+ Th_Interp *interp,
+ void *p,
+ int argc,
+ const char **argv,
+ int *argl
+){
+ if( argc!=3 && argc!=4 ){
+ return Th_WrongNumArgs(interp, "copybtn TARGETID TEXT COPYLENGTH");
+ }
+ if( enableOutput ){
+ int copylength = 0;
+ char *zTargetId, *zText, *zResult;
+ if( argc==4 && Th_ToInt(interp, argv[3], argl[3], ©length) ){
+ return TH_ERROR;
+ }
+ if( copylength==1 ) copylength = hash_digits(0);
+ else if( copylength==2 ) copylength = hash_digits(1);
+ zTargetId = htmlize((char*)argv[1], argl[1]);
+ zText = htmlize((char*)argv[2], argl[2]);
+ zResult = mprintf(
+ ""
+ ""
+ " "
+ ""
+ "%s"
+ "",
+ zTargetId, zTargetId, copylength, zTargetId, zText);
+ free(zTargetId);
+ free(zText);
+ style_copy_button();
+ sendText(zResult, -1, 0);
+ free(zResult);
+ }
+ return TH_OK;
+}
/*
** TH1 command: linecount STRING MAX MIN
**
** Return one more than the number of \n characters in STRING. But
@@ -2024,10 +2083,11 @@
{"anycap", anycapCmd, 0},
{"artifact", artifactCmd, 0},
{"cgiHeaderLine", cgiHeaderLineCmd, 0},
{"checkout", checkoutCmd, 0},
{"combobox", comboboxCmd, 0},
+ {"copybtn", copybtnCmd, 0},
{"date", dateCmd, 0},
{"decorate", wikiCmd, (void*)&aFlags[2]},
{"dir", dirCmd, 0},
{"enable_output", enableOutputCmd, 0},
{"encode64", encode64Cmd, 0},
Index: src/timeline.c
==================================================================
--- src/timeline.c
+++ src/timeline.c
@@ -832,11 +832,10 @@
int fileDiff; /* True for file diff. False for check-in diff */
int omitDescenders; /* True to omit descenders */
int scrollToSelect; /* True to scroll to the selection */
int dwellTimeout; /* Milliseconds to wait for tooltips to show */
int closeTimeout; /* Milliseconds to wait for tooltips to close */
- int nDigitHuman; /* The "hash-digits" limit for tooltip hash prefixes */
u8 *aiMap; /* The rail map */
iRailPitch = atoi(PD("railpitch","0"));
showArrowheads = skin_detail_boolean("timeline-arrowheads");
circleNodes = skin_detail_boolean("timeline-circle-nodes");
@@ -845,15 +844,10 @@
omitDescenders = (tmFlags & TIMELINE_DISJOINT)!=0;
fileDiff = (tmFlags & TIMELINE_FILEDIFF)!=0;
scrollToSelect = (tmFlags & TIMELINE_NOSCROLL)==0;
dwellTimeout = atoi(db_get("timeline-dwelltime","100"));
closeTimeout = atoi(db_get("timeline-closetime","250"));
-/* Preprocessor definitions copied from src\printf.c. */
-#ifndef FOSSIL_HASH_DIGITS
-# define FOSSIL_HASH_DIGITS 10
-#endif
- nDigitHuman = db_get_int("hash-digits", FOSSIL_HASH_DIGITS);
@ |
|---|
|
|---|