1+ // Localization support
2+ const messages = {
3+ 'en' : {
4+ 'copy' : 'Copy' ,
5+ 'copy_to_clipboard' : 'Copy to clipboard' ,
6+ 'copy_success' : 'Copied!' ,
7+ 'copy_failure' : 'Failed to copy' ,
8+ } ,
9+ 'es' : {
10+ 'copy' : 'Copiar' ,
11+ 'copy_to_clipboard' : 'Copiar al portapapeles' ,
12+ 'copy_success' : '¡Copiado!' ,
13+ 'copy_failure' : 'Error al copiar' ,
14+ } ,
15+ 'de' : {
16+ 'copy' : 'Kopieren' ,
17+ 'copy_to_clipboard' : 'In die Zwischenablage kopieren' ,
18+ 'copy_success' : 'Kopiert!' ,
19+ 'copy_failure' : 'Fehler beim Kopieren' ,
20+ }
21+ }
22+
23+ let locale = 'en'
24+ if ( document . documentElement . lang !== undefined
25+ && messages [ document . documentElement . lang ] !== undefined ) {
26+ locale = document . documentElement . lang
27+ }
28+
29+ /**
30+ * Set up copy/paste for code blocks
31+ */
32+
33+ const runWhenDOMLoaded = cb => {
34+ if ( document . readyState != 'loading' ) {
35+ cb ( )
36+ } else if ( document . addEventListener ) {
37+ document . addEventListener ( 'DOMContentLoaded' , cb )
38+ } else {
39+ document . attachEvent ( 'onreadystatechange' , function ( ) {
40+ if ( document . readyState == 'complete' ) cb ( )
41+ } )
42+ }
43+ }
44+
45+ const codeCellId = index => `codecell${ index } `
46+
47+ // Clears selected text since ClipboardJS will select the text when copying
48+ const clearSelection = ( ) => {
49+ if ( window . getSelection ) {
50+ window . getSelection ( ) . removeAllRanges ( )
51+ } else if ( document . selection ) {
52+ document . selection . empty ( )
53+ }
54+ }
55+
56+ // Changes tooltip text for two seconds, then changes it back
57+ const temporarilyChangeTooltip = ( el , newText ) => {
58+ const oldText = el . getAttribute ( 'data-tooltip' )
59+ el . setAttribute ( 'data-tooltip' , newText )
60+ setTimeout ( ( ) => el . setAttribute ( 'data-tooltip' , oldText ) , 2000 )
61+ }
62+
63+ const addCopyButtonToCodeCells = ( ) => {
64+ // If ClipboardJS hasn't loaded, wait a bit and try again. This
65+ // happens because we load ClipboardJS asynchronously.
66+ if ( window . ClipboardJS === undefined ) {
67+ setTimeout ( addCopyButtonToCodeCells , 250 )
68+ return
69+ }
70+
71+ // Add copybuttons to all of our code cells
72+ const codeCells = document . querySelectorAll ( 'div.highlight pre' )
73+ codeCells . forEach ( ( codeCell , index ) => {
74+ const id = codeCellId ( index )
75+ codeCell . setAttribute ( 'id' , id )
76+ const pre_bg = getComputedStyle ( codeCell ) . backgroundColor ;
77+
78+ const clipboardButton = id =>
79+ `<a class="copybtn o-tooltip--left" style="background-color: ${ pre_bg } " data-tooltip="${ messages [ locale ] [ 'copy' ] } " data-clipboard-target="#${ id } ">
80+ <img src="${ DOCUMENTATION_OPTIONS . URL_ROOT } _static/copy-button.svg" alt="${ messages [ locale ] [ 'copy_to_clipboard' ] } ">
81+ </a>`
82+ codeCell . insertAdjacentHTML ( 'afterend' , clipboardButton ( id ) )
83+ } )
84+
85+ function escapeRegExp ( string ) {
86+ return string . replace ( / [ . * + ? ^ $ { } ( ) | [ \] \\ ] / g, '\\$&' ) ; // $& means the whole matched string
87+ }
88+
89+ // Callback when a copy button is clicked. Will be passed the node that was clicked
90+ // should then grab the text and replace pieces of text that shouldn't be used in output
91+ function formatCopyText ( textContent , copybuttonPromptText , isRegexp = false , onlyCopyPromptLines = true , removePrompts = true ) {
92+
93+ var regexp ;
94+ var match ;
95+
96+ // create regexp to capture prompt and remaining line
97+ if ( isRegexp ) {
98+ regexp = new RegExp ( '^(' + copybuttonPromptText + ')(.*)' )
99+ } else {
100+ regexp = new RegExp ( '^(' + escapeRegExp ( copybuttonPromptText ) + ')(.*)' )
101+ }
102+
103+ const outputLines = [ ] ;
104+ var promptFound = false ;
105+ for ( const line of textContent . split ( '\n' ) ) {
106+ match = line . match ( regexp )
107+ if ( match ) {
108+ promptFound = true
109+ if ( removePrompts ) {
110+ outputLines . push ( match [ 2 ] )
111+ } else {
112+ outputLines . push ( line )
113+ }
114+ } else {
115+ if ( ! onlyCopyPromptLines ) {
116+ outputLines . push ( line )
117+ }
118+ }
119+ }
120+
121+ // If no lines with the prompt were found then just use original lines
122+ if ( promptFound ) {
123+ textContent = outputLines . join ( '\n' ) ;
124+ }
125+
126+ // Remove a trailing newline to avoid auto-running when pasting
127+ if ( textContent . endsWith ( "\n" ) ) {
128+ textContent = textContent . slice ( 0 , - 1 )
129+ }
130+ return textContent
131+ }
132+
133+
134+ var copyTargetText = ( trigger ) => {
135+ var target = document . querySelector ( trigger . attributes [ 'data-clipboard-target' ] . value ) ;
136+ return formatCopyText ( target . innerText , '$ ' , false , true , true )
137+ }
138+
139+ // Initialize with a callback so we can modify the text before copy
140+ const clipboard = new ClipboardJS ( '.copybtn' , { text : copyTargetText } )
141+
142+ // Update UI with error/success messages
143+ clipboard . on ( 'success' , event => {
144+ clearSelection ( )
145+ temporarilyChangeTooltip ( event . trigger , messages [ locale ] [ 'copy_success' ] )
146+ } )
147+
148+ clipboard . on ( 'error' , event => {
149+ temporarilyChangeTooltip ( event . trigger , messages [ locale ] [ 'copy_failure' ] )
150+ } )
151+ }
152+
153+ runWhenDOMLoaded ( addCopyButtonToCodeCells )
0 commit comments