1
- // ``function*`` denotes a generator in JavaScript, see
2
- // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*
3
- function * getHideableCopyButtonElements ( rootElement ) {
4
- // yield all elements with the "go" (Generic.Output),
5
- // "gp" (Generic.Prompt), or "gt" (Generic.Traceback) CSS class
6
- for ( const el of rootElement . querySelectorAll ( '.go, .gp, .gt' ) ) {
7
- yield el
8
- }
9
- // tracebacks (.gt) contain bare text elements that need to be
10
- // wrapped in a span to hide or show the element
11
- for ( let el of rootElement . querySelectorAll ( '.gt' ) ) {
12
- while ( ( el = el . nextSibling ) && el . nodeType !== Node . DOCUMENT_NODE ) {
13
- // stop wrapping text nodes when we hit the next output or
14
- // prompt element
15
- if ( el . nodeType === Node . ELEMENT_NODE && el . matches ( ".gp, .go" ) ) {
16
- break
17
- }
18
- // if the node is a text node with content, wrap it in a
19
- // span element so that we can control visibility
20
- if ( el . nodeType === Node . TEXT_NODE && el . textContent . trim ( ) ) {
21
- const wrapper = document . createElement ( "span" )
22
- el . after ( wrapper )
23
- wrapper . appendChild ( el )
24
- el = wrapper
25
- }
26
- yield el
1
+ // Extract copyable text from the code block ignoring the
2
+ // prompts and output.
3
+ function getCopyableText ( rootElement ) {
4
+ rootElement = rootElement . cloneNode ( true )
5
+ // tracebacks (.gt) contain bare text elements that
6
+ // need to be removed
7
+ const tracebacks = rootElement . querySelectorAll ( ".gt" )
8
+ for ( const el of tracebacks ) {
9
+ while (
10
+ el . nextSibling &&
11
+ ( el . nextSibling . nodeType !== Node . DOCUMENT_NODE ||
12
+ ! el . nextSibling . matches ( ".gp, .go" ) )
13
+ ) {
14
+ el . nextSibling . remove ( )
27
15
}
28
16
}
17
+ // Remove all elements with the "go" (Generic.Output),
18
+ // "gp" (Generic.Prompt), or "gt" (Generic.Traceback) CSS class
19
+ const elements = rootElement . querySelectorAll ( ".gp, .go, .gt" )
20
+ for ( const el of elements ) {
21
+ el . remove ( )
22
+ }
23
+ return rootElement . innerText . trim ( )
29
24
}
30
25
31
-
32
26
const loadCopyButton = ( ) => {
33
- /* Add a [>>>] button in the top-right corner of code samples to hide
34
- * the >>> and ... prompts and the output and thus make the code
35
- * copyable. */
36
- const hide_text = _ ( "Hide the prompts and output" )
37
- const show_text = _ ( "Show the prompts and output" )
38
-
39
- const button = document . createElement ( "span" )
27
+ const button = document . createElement ( "button" )
40
28
button . classList . add ( "copybutton" )
41
- button . innerText = ">>>"
42
- button . title = hide_text
43
- button . dataset . hidden = "false"
29
+ button . type = "button"
30
+ button . innerText = _ ( "Copy" )
31
+ button . title = _ ( "Copy to clipboard" )
32
+
33
+ let timeout
44
34
const buttonClick = event => {
45
35
// define the behavior of the button when it's clicked
46
- event . preventDefault ( )
36
+ clearTimeout ( timeout )
47
37
const buttonEl = event . currentTarget
48
38
const codeEl = buttonEl . nextElementSibling
49
- if ( buttonEl . dataset . hidden === "false" ) {
50
- // hide the code output
51
- for ( const el of getHideableCopyButtonElements ( codeEl ) ) {
52
- el . hidden = true
53
- }
54
- buttonEl . title = show_text
55
- buttonEl . dataset . hidden = "true"
56
- } else {
57
- // show the code output
58
- for ( const el of getHideableCopyButtonElements ( codeEl ) ) {
59
- el . hidden = false
60
- }
61
- buttonEl . title = hide_text
62
- buttonEl . dataset . hidden = "false"
63
- }
39
+ navigator . clipboard . writeText ( getCopyableText ( codeEl ) )
40
+ buttonEl . innerText = _ ( "Copied!" )
41
+ timeout = setTimeout ( ( ) => {
42
+ buttonEl . innerText = _ ( "Copy" )
43
+ } , 1500 )
64
44
}
65
45
66
46
const highlightedElements = document . querySelectorAll (
67
- ".highlight-python .highlight,"
68
- + ".highlight-python3 .highlight,"
69
- + ".highlight-pycon .highlight,"
70
- + ".highlight-pycon3 .highlight,"
71
- + ".highlight-default .highlight"
47
+ ".highlight-python .highlight," +
48
+ ".highlight-python3 .highlight," +
49
+ ".highlight-pycon .highlight," +
50
+ ".highlight-pycon3 .highlight," +
51
+ ".highlight-default .highlight"
72
52
)
73
53
74
54
// create and add the button to all the code blocks that contain >>>
@@ -79,9 +59,7 @@ const loadCopyButton = () => {
79
59
const clonedButton = button . cloneNode ( true )
80
60
// the onclick attribute is not cloned, set it on the new element
81
61
clonedButton . onclick = buttonClick
82
- if ( el . querySelector ( ".gp" ) !== null ) {
83
- el . prepend ( clonedButton )
84
- }
62
+ el . prepend ( clonedButton )
85
63
} )
86
64
}
87
65
0 commit comments