From 55630cc5eae5534f76cc585d54518315f20bad7e Mon Sep 17 00:00:00 2001 From: Siddharth VP Date: Wed, 11 Sep 2024 00:49:06 +0530 Subject: [PATCH] Implement copy buttons for code blocks blocks with a boolean "copy" param will now have a button next to them for copying the code to the clipboard. Not applicable for inline code blocks. Adapted from the mediawiki.org gadget written by Krinkle. Bug: T40932 Change-Id: Ic8ef030514c3b6dd2cb9b137f032588869ab3762 --- extension.json | 10 +++++++++- i18n/en.json | 4 +++- i18n/qqq.json | 4 +++- includes/SyntaxHighlight.php | 4 ++++ modules/pygments.copy.css | 38 ++++++++++++++++++++++++++++++++++++ modules/pygments.copy.js | 35 +++++++++++++++++++++++++++++++++ 6 files changed, 92 insertions(+), 3 deletions(-) create mode 100644 modules/pygments.copy.css create mode 100644 modules/pygments.copy.js diff --git a/extension.json b/extension.json index 11e47592..016d3869 100644 --- a/extension.json +++ b/extension.json @@ -41,7 +41,15 @@ "ext.pygments.view": { "scripts": [ "pygments.linenumbers.js", - "pygments.links.js" + "pygments.links.js", + "pygments.copy.js" + ], + "styles": [ + "pygments.copy.css" + ], + "messages": [ + "syntaxhighlight-button-copy", + "syntaxhighlight-button-copied" ], "dependencies": [ "mediawiki.util" diff --git a/i18n/en.json b/i18n/en.json index c86e803a..b15c2c4f 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -20,5 +20,7 @@ "syntaxhighlight-visualeditor-mwsyntaxhighlightinspector-title": "Code block", "syntaxhighlight-error-pygments-invocation-failure": "Failed to invoke Pygments", "syntaxhighlight-error-unknown-language": "Unknown language \"$1\"", - "syntaxhighlight-error-exceeds-size-limit": "Code size of $1 {{PLURAL:$1|bytes}} exceeds allowed maximum of $2 {{PLURAL:$2|bytes}}" + "syntaxhighlight-error-exceeds-size-limit": "Code size of $1 {{PLURAL:$1|bytes}} exceeds allowed maximum of $2 {{PLURAL:$2|bytes}}", + "syntaxhighlight-button-copy": "Copy", + "syntaxhighlight-button-copied": "Copied!" } diff --git a/i18n/qqq.json b/i18n/qqq.json index f7bd1fd0..3a5eea28 100644 --- a/i18n/qqq.json +++ b/i18n/qqq.json @@ -29,5 +29,7 @@ "syntaxhighlight-visualeditor-mwsyntaxhighlightinspector-title": "Title for the VisualEditor syntax highlighter inspector, above the text area for the code", "syntaxhighlight-error-pygments-invocation-failure": "Error message shown when the syntax highlighting library failed with an unspecified error", "syntaxhighlight-error-unknown-language": "Error message shown when the programming language name was not recognized by the syntax highlighting library. Parameters:\n* $1 - the language name", - "syntaxhighlight-error-exceeds-size-limit": "Error message shown when the block of code to be highlighted exceeds the size limit. Parameters:\n* $1 - the size of the code block, in bytes\n* $2 - the maximum size allowed, in bytes." + "syntaxhighlight-error-exceeds-size-limit": "Error message shown when the block of code to be highlighted exceeds the size limit. Parameters:\n* $1 - the size of the code block, in bytes\n* $2 - the maximum size allowed, in bytes.", + "syntaxhighlight-button-copy": "Label for button to copy the highlighted code", + "syntaxhighlight-button-copied": "Label shown when the highlighted code has been copied" } diff --git a/includes/SyntaxHighlight.php b/includes/SyntaxHighlight.php index 3a95ffd6..f396b5be 100644 --- a/includes/SyntaxHighlight.php +++ b/includes/SyntaxHighlight.php @@ -387,6 +387,7 @@ class SyntaxHighlight extends ExtensionTagHandler implements * If it contains a 'inline' key, the output will not be wrapped in `
`. * If it contains a 'linelinks' key, lines will have links and anchors with a prefix * of the value. Similar to the lineanchors+linespans features in Pygments. + * If it contains a 'copy' key, a link will be shown for copying content to the clipboard. * @param Parser|null $parser Parser, if generating content to be parsed. * @return Status Status object, with HTML representing the highlighted * code as its value. @@ -440,6 +441,9 @@ class SyntaxHighlight extends ExtensionTagHandler implements if ( $showLines ) { $classList[] = self::HIGHLIGHT_CSS_CLASS . '-lines'; } + if ( !$isInline && isset( $args['copy'] ) ) { + $classList[] = 'mw-highlight-copy'; + } $htmlAttribs['class'] = implode( ' ', $classList ); $htmlAttribs['dir'] = $dir; '@phan-var array{class:string,dir:string} $htmlAttribs'; diff --git a/modules/pygments.copy.css b/modules/pygments.copy.css new file mode 100644 index 00000000..a5cabe4d --- /dev/null +++ b/modules/pygments.copy.css @@ -0,0 +1,38 @@ +/** + * Adapted from https://www.mediawiki.org/wiki/MediaWiki:Gadget-site-tpl-copy.css + * Original author: Krinkle + */ + +.mw-highlight-copy { + position: relative; + min-width: 40%; + max-width: max-content; +} + +/** + * https://doc.wikimedia.org/oojs-ui/master/demos/ (2023-11-13) + * https://design.wikimedia.org/style-guide/components/buttons.html + */ +.mw-highlight-copy--bound button { + position: absolute; + top: -1em; + right: -0.9em; + box-sizing: border-box; + padding: 5px 7px; + border-radius: 2px; + background: #fff; + color: #36c; + border: 1px solid #eaecf0; +} + +.mw-highlight-copy--bound button:hover { + cursor: pointer; + background: #fff; + border: 1px solid #447ff5; +} + +.mw-highlight-copy--bound button:active { + background: #eff3fa; + color: #2a4b8d; + border-color: #2a4b8d; +} diff --git a/modules/pygments.copy.js b/modules/pygments.copy.js new file mode 100644 index 00000000..1a5b5d3c --- /dev/null +++ b/modules/pygments.copy.js @@ -0,0 +1,35 @@ +/** + * Adapted from https://www.mediawiki.org/wiki/MediaWiki:Gadget-site-tpl-copy.js + * Original author: Krinkle + */ + +// eslint-disable-next-line compat/compat +const hasFeature = navigator.clipboard && 'writeText' in navigator.clipboard; +if ( hasFeature ) { + // Add type=button to avoid form submission in preview + const $btn = $( '