Add style support for copy button highlighting (#372)

This commit is contained in:
Pete Lumbis 2023-03-01 14:04:37 -05:00 committed by GitHub
parent 310b53f197
commit dad3573e2e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 101 additions and 48 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,12 +1,15 @@
@mixin code-theme-base {
// code.language-shell::before {
// content: "$ ";
// }
.language-shell :first-child .cl::before{
content: "$ "
}
// Style for highlighted lines when hovering over copy button
.copyHover {
background-color: #e9ecef;
color: black;
}
// Code box div
.highlight {
overflow-x: auto;

View File

@ -1,8 +1,8 @@
{
"main.js": {
"src": "js/main-4ff1a43b.bundle.min.js"
"src": "js/main-3dea9eee.bundle.min.js"
},
"main-4ff1a43b.bundle.min.js.map": {
"src": "js/main-4ff1a43b.bundle.min.js.map"
"main-3dea9eee.bundle.min.js.map": {
"src": "js/main-3dea9eee.bundle.min.js.map"
}
}

View File

@ -5,21 +5,24 @@ import * as ClipboardJS from 'clipboard';
// https://github.com/twbs/bootstrap/blob/main/site/assets/js/code-examples.js
const btnHtml = [
' <div class="bd-clipboard">',
' <button type="button" class="btn-clipboard">',
' <button type="button" class="btn-clipboard" title="Copy">',
' <svg class="bi" role="img" title="Copy" aria-label="Copy"><use xlink:href="#clipboard"/></svg>',
' </button>',
' </div>'
].join('')
// wrap programmatically code blocks and add copy btn.
document.querySelectorAll('.highlight')
.forEach(element => {
element.insertAdjacentHTML('beforeend', btnHtml)
})
var codeBlocks = document.querySelectorAll('.highlight')
// use .parentNode.parentNode because the trigger is the <button> element.
// first parent is the .bd-clipboard div
// second parent is the .hightlight div
for (var i = 0; i < codeBlocks.length; i++){
var copyLines = getLines(codeBlocks[i])
setHighlight(codeBlocks[i], copyLines)
codeBlocks[i].insertAdjacentHTML('beforeend', btnHtml)
}
// use .parentNode.parentNode because the trigger is the <button> element.
// first parent is the .bd-clipboard div
// second parent is the .hightlight div
const clipboard = new ClipboardJS('.btn-clipboard', {
target: trigger => trigger.parentNode.parentNode,
text: trigger => getText(trigger.parentNode.parentNode)
@ -55,44 +58,91 @@ function getText(highlightDiv){
var codeLines = highlightDiv.getElementsByClassName("cl")
var codeText = []
// Get every line of code without markup
for (var i = 0; i < codeLines.length; i++){
codeText.push(codeLines[i].innerText)
}
// default is only copy line 1
var startLines = 1
var endLines = codeText.length
var startEnd = getLines(highlightDiv)
// did they set the "copy-lines" value in the code box to identify what to copy?
if("copy-lines" in highlightDiv.attributes){
return codeText.slice((startEnd[0] - 1), startEnd[1]).join('')
var copyVal = highlightDiv.attributes["copy-lines"].value
}
// if it's a single digit then start == end
if(copyVal.length === 1){
startLines = parseInt(copyVal, 10)
endLines = parseInt(copyVal, 10)
}
// If the default copy is 1 instead of all, the following is required.
// else if(copyVal.localeCompare("all") === 0){
// endLines = codeContent.length
// }
else {
// look for a value like 1-10. Split on the dash.
var startendLines = copyVal.split("-")
startLines = parseInt(startendLines[0], 10)
endLines = parseInt(startendLines[1], 10)
}
// Parse the highlight div element and look for the "copy-lines" data attribute
// Return an array of [starting line number, ending line number]
function getLines(highlightDiv){
if(startLines <= 0 || isNaN(startLines)) {
startLines = 1
}
if(endLines <= 0 || endLines > codeText.length - 1 || isNaN(endLines)){
endLines = codeText.length
}
var codeLinesLength = highlightDiv.getElementsByClassName("cl").length
var startEnd = [1, codeLinesLength]
}
// did they set the "copy-lines" value in the code box to identify what to copy?
// if not, just return the first and last lines.
if(!("copy-lines" in highlightDiv.attributes)){
return startEnd
}
return codeText.slice((startLines - 1), endLines).join('')
var copyVal = highlightDiv.attributes["copy-lines"].value
var startLines = 1
var endLines = codeLinesLength
}
// if it's a single digit then start == end
if(copyVal.length === 1){
startLines = parseInt(copyVal, 10)
endLines = parseInt(copyVal, 10)
}
// If the default copy is 1 instead of all, the following is required.
// else if(copyVal.localeCompare("all") === 0){
// endLines = codeContent.length
// }
else {
// look for a value like 1-10. Split on the dash.
var startendLines = copyVal.split("-")
startLines = parseInt(startendLines[0], 10)
endLines = parseInt(startendLines[1], 10)
}
if(startLines <= 0 || isNaN(startLines)) {
startLines = 1
}
if(endLines <= 0 || endLines > codeLinesLength - 1 || isNaN(endLines)){
endLines = codeLinesLength
}
return [startLines, endLines]
}
// For each line that matches the defined "copy-lines" set class "copyHighlight"
// This makes finding these lines later much easier.
function setHighlight(highlightDiv, lineRange){
var lines = highlightDiv.querySelectorAll('.line')
var start = lineRange[0] - 1
var end = lineRange[1] - 1
for (var i = start ; i <= end; i++){
lines[i].classList.add("copyHighlight")
}
}
// For each "copyHighlight" line, toggle class "copyHover"
// This function is unique from setHighlight because it's called when the
// eventListener fires.
function copyHoverHighlight(clipboardElement){
var codeblock = clipboardElement.parentNode
var lines = codeblock.getElementsByClassName("copyHighlight")
for (var j = 0 ; j < lines.length ; j++){
lines[j].classList.toggle("copyHover")
}
}
// Creates mouse over and mouse out event listeners on each clipboard element.
function build_eventlistener(){
var clipboards = document.getElementsByClassName("bd-clipboard")
for (var i = 0 ; i < clipboards.length ; i++){
clipboards[i].addEventListener("mouseover", function(){ copyHoverHighlight(this) }, true)
clipboards[i].addEventListener("mouseout", function(){ copyHoverHighlight(this) }, true)
}
}
window.onload = build_eventlistener();