|
b699040…
|
drh
|
1 |
(function callee(arg){ |
|
b699040…
|
drh
|
2 |
/* |
|
b699040…
|
drh
|
3 |
JS counterpart of info.c:output_text_with_line_numbers() |
|
b699040…
|
drh
|
4 |
which ties an event handler to the line numbers to allow |
|
b699040…
|
drh
|
5 |
selection of individual lines or ranges. |
|
b699040…
|
drh
|
6 |
|
|
b699040…
|
drh
|
7 |
Requires: fossil.bootstrap, fossil.dom, fossil.popupwidget, |
|
b699040…
|
drh
|
8 |
fossil.copybutton |
|
b699040…
|
drh
|
9 |
*/ |
|
b699040…
|
drh
|
10 |
var tbl = arg || document.querySelectorAll('table.numbered-lines'); |
|
34f7fd7…
|
stephan
|
11 |
if(tbl && !arg){ |
|
b699040…
|
drh
|
12 |
if(tbl.length>1){ /* multiple query results: recurse */ |
|
b699040…
|
drh
|
13 |
tbl.forEach( (t)=>callee(t) ); |
|
b699040…
|
drh
|
14 |
return; |
|
b699040…
|
drh
|
15 |
}else{/* single query result */ |
|
b699040…
|
drh
|
16 |
tbl = tbl[0]; |
|
b699040…
|
drh
|
17 |
} |
|
b699040…
|
drh
|
18 |
} |
|
34f7fd7…
|
stephan
|
19 |
if(!tbl) return /* no matching elements */; |
|
b699040…
|
drh
|
20 |
const F = window.fossil, D = F.dom; |
|
b699040…
|
drh
|
21 |
const tdLn = tbl.querySelector('td.line-numbers'); |
|
8981518…
|
george
|
22 |
const urlArgsRaw = (window.location.search||'?') |
|
7c98df4…
|
stephan
|
23 |
.replace(/&?\budc=[^&]*/,'') /* "update display prefs cookie" */ |
|
7c98df4…
|
stephan
|
24 |
.replace(/&?\bln=[^&]*/,'') /* inbound line number/range */ |
|
8981518…
|
george
|
25 |
.replace('?&','?'); |
|
7641c82…
|
stephan
|
26 |
const lineState = { urlArgs: urlArgsRaw, start: 0, end: 0 }; |
|
0f03f78…
|
wyoung
|
27 |
const lineTip = new F.PopupWidget({ |
|
b699040…
|
drh
|
28 |
refresh: function(){ |
|
b699040…
|
drh
|
29 |
const link = this.state.link; |
|
b699040…
|
drh
|
30 |
D.clearElement(link); |
|
b699040…
|
drh
|
31 |
if(lineState.start){ |
|
b699040…
|
drh
|
32 |
const ls = [lineState.start]; |
|
b699040…
|
drh
|
33 |
if(lineState.end) ls.push(lineState.end); |
|
b699040…
|
drh
|
34 |
link.dataset.url = ( |
|
b699040…
|
drh
|
35 |
window.location.toString().split('?')[0] |
|
b699040…
|
drh
|
36 |
+ lineState.urlArgs + '&ln='+ls.join('-') |
|
b699040…
|
drh
|
37 |
); |
|
b699040…
|
drh
|
38 |
D.append( |
|
b699040…
|
drh
|
39 |
D.clearElement(link), |
|
7c98df4…
|
stephan
|
40 |
' Copy link to '+( |
|
7c98df4…
|
stephan
|
41 |
ls.length===1 ? 'line ' : 'lines ' |
|
7c98df4…
|
stephan
|
42 |
)+ls.join('-') |
|
b699040…
|
drh
|
43 |
); |
|
b699040…
|
drh
|
44 |
}else{ |
|
b699040…
|
drh
|
45 |
D.append(link, "No lines selected."); |
|
b699040…
|
drh
|
46 |
} |
|
b699040…
|
drh
|
47 |
}, |
|
b699040…
|
drh
|
48 |
init: function(){ |
|
b699040…
|
drh
|
49 |
const e = this.e; |
|
63712b6…
|
florian
|
50 |
const btnCopy = D.attr(D.button(), 'id', 'linenum-copy-button'); |
|
63712b6…
|
florian
|
51 |
link = D.label('linenum-copy-button'); |
|
b699040…
|
drh
|
52 |
this.state = {link}; |
|
b699040…
|
drh
|
53 |
F.copyButton(btnCopy,{ |
|
b699040…
|
drh
|
54 |
copyFromElement: link, |
|
b699040…
|
drh
|
55 |
extractText: ()=>link.dataset.url, |
|
b699040…
|
drh
|
56 |
oncopy: (ev)=>{ |
|
63712b6…
|
florian
|
57 |
setTimeout(()=>lineTip.hide(), 400); |
|
7c98df4…
|
stephan
|
58 |
// arguably too snazzy: F.toast.message("Copied link to clipboard."); |
|
b699040…
|
drh
|
59 |
} |
|
b699040…
|
drh
|
60 |
}); |
|
63712b6…
|
florian
|
61 |
D.append(this.e, btnCopy, link); |
|
b699040…
|
drh
|
62 |
} |
|
b699040…
|
drh
|
63 |
}); |
|
b699040…
|
drh
|
64 |
|
|
b699040…
|
drh
|
65 |
tbl.addEventListener('click', ()=>lineTip.hide(), true); |
|
b699040…
|
drh
|
66 |
|
|
b699040…
|
drh
|
67 |
tdLn.addEventListener('click', function f(ev){ |
|
b699040…
|
drh
|
68 |
if('SPAN'!==ev.target.tagName) return; |
|
b699040…
|
drh
|
69 |
else if('number' !== typeof f.mode){ |
|
b699040…
|
drh
|
70 |
f.mode = 0 /*0=none selected, 1=1 selected, 2=2 selected*/; |
|
b699040…
|
drh
|
71 |
f.spans = tdLn.querySelectorAll('span'); |
|
b699040…
|
drh
|
72 |
f.selected = tdLn.querySelectorAll('span.selected-line'); |
|
b699040…
|
drh
|
73 |
f.unselect = (e)=>D.removeClass(e, 'selected-line','start','end'); |
|
b699040…
|
drh
|
74 |
} |
|
b699040…
|
drh
|
75 |
ev.stopPropagation(); |
|
b699040…
|
drh
|
76 |
const ln = +ev.target.innerText; |
|
b699040…
|
drh
|
77 |
if(2===f.mode){/*Reset selection*/ |
|
b699040…
|
drh
|
78 |
f.mode = 0; |
|
b699040…
|
drh
|
79 |
} |
|
b699040…
|
drh
|
80 |
if(0===f.mode){/*Select single line*/ |
|
b699040…
|
drh
|
81 |
lineState.end = 0; |
|
b699040…
|
drh
|
82 |
lineState.start = ln; |
|
b699040…
|
drh
|
83 |
f.mode = 1; |
|
b699040…
|
drh
|
84 |
}else if(1===f.mode){ |
|
b699040…
|
drh
|
85 |
if(ln === lineState.start){/*Unselect line*/ |
|
b699040…
|
drh
|
86 |
lineState.start = 0; |
|
b699040…
|
drh
|
87 |
f.mode = 0; |
|
b699040…
|
drh
|
88 |
}else{/*Select range*/ |
|
b699040…
|
drh
|
89 |
if(ln<lineState.start){ |
|
b699040…
|
drh
|
90 |
lineState.end = lineState.start; |
|
b699040…
|
drh
|
91 |
lineState.start = ln; |
|
b699040…
|
drh
|
92 |
}else{ |
|
b699040…
|
drh
|
93 |
lineState.end = ln; |
|
b699040…
|
drh
|
94 |
} |
|
b699040…
|
drh
|
95 |
f.mode = 2; |
|
b699040…
|
drh
|
96 |
} |
|
b699040…
|
drh
|
97 |
} |
|
b699040…
|
drh
|
98 |
if(f.selected){/*Unmark previously-selected lines.*/ |
|
b699040…
|
drh
|
99 |
f.selected.forEach(f.unselect); |
|
b699040…
|
drh
|
100 |
f.selected = undefined; |
|
b699040…
|
drh
|
101 |
} |
|
b699040…
|
drh
|
102 |
if(0===f.mode){ |
|
b699040…
|
drh
|
103 |
lineTip.hide(); |
|
b699040…
|
drh
|
104 |
}else{/*Mark selected lines*/ |
|
b699040…
|
drh
|
105 |
const rect = ev.target.getBoundingClientRect(); |
|
b699040…
|
drh
|
106 |
f.selected = []; |
|
b699040…
|
drh
|
107 |
if(f.spans.length>=lineState.start){ |
|
b699040…
|
drh
|
108 |
let i = lineState.start, end = lineState.end || lineState.start, span = f.spans[i-1]; |
|
b699040…
|
drh
|
109 |
for( ; i<=end && span; span = f.spans[i++] ){ |
|
b699040…
|
drh
|
110 |
span.classList.add('selected-line'); |
|
b699040…
|
drh
|
111 |
f.selected.push(span); |
|
b699040…
|
drh
|
112 |
if(i===lineState.start) span.classList.add('start'); |
|
b699040…
|
drh
|
113 |
if(i===end) span.classList.add('end'); |
|
b699040…
|
drh
|
114 |
} |
|
b699040…
|
drh
|
115 |
} |
|
b699040…
|
drh
|
116 |
lineTip.refresh().show(rect.right+3, rect.top-4); |
|
b699040…
|
drh
|
117 |
} |
|
b699040…
|
drh
|
118 |
}, false); |
|
b699040…
|
drh
|
119 |
|
|
b699040…
|
drh
|
120 |
})(); |