1+ const codeBlockButtonPairs = [ ] ;
2+
3+ function addCopyButtons ( clipboard ) {
4+ document . querySelectorAll ( 'pre > code' ) . forEach ( function ( codeBlock ) {
5+ var button = document . createElement ( 'button' ) ;
6+ button . className = 'copy-code-button' ;
7+ button . type = 'button' ;
8+ button . innerText = 'Copy code' ;
9+
10+ button . style . position = 'absolute' ;
11+
12+ button . addEventListener ( 'click' , function ( ) {
13+ clipboard . writeText ( codeBlock . textContent ) . then ( function ( ) {
14+ /* Chrome doesn't seem to blur automatically,
15+ leaving the button in a focused state. */
16+ button . blur ( ) ;
17+
18+ button . innerText = 'Copied!' ;
19+
20+ setTimeout ( function ( ) {
21+ button . innerText = 'Copy code' ;
22+ } , 2000 ) ;
23+ } , function ( error ) {
24+ button . innerText = 'Error' ;
25+ } ) ;
26+ } ) ;
27+
28+ var pre = codeBlock . parentNode ;
29+ if ( pre . parentNode . classList . contains ( 'highlight' ) ) {
30+ var highlight = pre . parentNode ;
31+ highlight . parentNode . insertBefore ( button , highlight ) ;
32+ } else {
33+ pre . parentNode . insertBefore ( button , pre ) ;
34+ }
35+
36+ codeBlockButtonPairs . push ( { codeBlock, button} ) ;
37+ } ) ;
38+ }
39+
40+ if ( navigator && navigator . clipboard ) {
41+ addCopyButtons ( navigator . clipboard ) ;
42+ } else {
43+ var script = document . createElement ( 'script' ) ;
44+ script . src = 'https://cdnjs.cloudflare.com/ajax/libs/clipboard-polyfill/2.7.0/clipboard-polyfill.promise.js' ;
45+ script . integrity = 'sha256-waClS2re9NUbXRsryKoof+F9qc1gjjIhc2eT7ZbIv94=' ;
46+ script . crossOrigin = 'anonymous' ;
47+ script . onload = function ( ) {
48+ addCopyButtons ( clipboard ) ;
49+ } ;
50+
51+ document . body . appendChild ( script ) ;
52+ }
53+
54+ function positionButtons ( ) {
55+ codeBlockButtonPairs . forEach ( ( { codeBlock, button } ) => {
56+ const rect = codeBlock . getBoundingClientRect ( ) ;
57+ const codeBlockStyle = window . getComputedStyle ( codeBlock . parentNode ) ;
58+ const buttonStyle = window . getComputedStyle ( button ) ;
59+ const articleStyle = window . getComputedStyle ( document . querySelector ( 'article' ) ) ;
60+
61+ const horizontalShift = parseFloat ( codeBlockStyle . getPropertyValue ( 'padding-left' ) . slice ( 0 , - 2 ) ) +
62+ parseFloat ( buttonStyle . getPropertyValue ( 'width' ) . slice ( 0 , - 2 ) ) +
63+ 2 * parseFloat ( articleStyle . getPropertyValue ( 'padding-left' ) . slice ( 0 , - 2 ) ) +
64+ - 0.8 ; // Weird correction term, not sure what's up with this.
65+ console . log ( `horizontalShift: ${ horizontalShift } ` ) ;
66+ button . style . top = `${ window . scrollY + rect . top - 20.3 } px` ;
67+ button . style . left = `${ window . scrollX + rect . left - horizontalShift } px` ;
68+ } ) ;
69+ }
70+
71+ // Initial placement
72+ positionButtons ( ) ;
73+
74+ // Re-position when scrolling or resizing
75+ window . addEventListener ( "resize" , positionButtons ) ;
76+ window . addEventListener ( "scroll" , positionButtons ) ;
0 commit comments