Skip to content

Commit 7a92d03

Browse files
committed
syntaxhighlight: allow for wrapping #569
- currently the only option until matcornic#169 is implemented - also mandatory for printing
1 parent d62e47f commit 7a92d03

File tree

2 files changed

+110
-14
lines changed

2 files changed

+110
-14
lines changed

static/css/theme.css

+24-1
Original file line numberDiff line numberDiff line change
@@ -1976,11 +1976,34 @@ html[dir="rtl"] #sidebar ul.collapsible-menu > li > label > i.fa-chevron-right {
19761976
}
19771977

19781978
/* remove border from code block if single in tab */
1979+
#body .tab-content-text > div.highlight.wrapfix:only-child tbody,
19791980
#body .tab-content-text > div.highlight:only-child pre,
19801981
#body .tab-content-text > pre.pre-code:only-child{
19811982
border-width: 0;
19821983
}
1983-
/* re-add border on code column if a single in tab and highlight shortcode was used in table lineno mode */
1984+
/* re-add border on code column if single in tab and highlight shortcode was used in table lineno mode */
19841985
#body .tab-content-text > div.highlight:only-child td:nth-child(2) pre {
19851986
border-left-width: 1px;
19861987
}
1988+
1989+
/* we may have special treatment if highlight shortcode was used in table lineno mode and
1990+
we want to apply feasible wrapping for long code lines instead of scrolling */
1991+
div.highlight.wrapfix tbody{
1992+
background-color: var(--INTERNAL-CODE-BLOCK-BG-color);
1993+
border: 1px solid var(--INTERNAL-CODE-BLOCK-BORDER-color);
1994+
}
1995+
div.highlight.wrapfix tbody tr:not(:first-child) pre{
1996+
padding-top: 0;
1997+
}
1998+
div.highlight.wrapfix tbody tr:not(:last-child) pre{
1999+
padding-bottom: 0;
2000+
}
2001+
div.highlight.wrapfix tbody td:first-child:not(last-child){
2002+
user-select: none;
2003+
}
2004+
div.highlight.wrapfix tbody td:not(:first-child):last-child{
2005+
border-left: 1px solid var(--INTERNAL-CODE-BLOCK-BORDER-color);
2006+
}
2007+
div.highlight.wrapfix tbody td pre{
2008+
border: 0;
2009+
}

static/js/theme.js

+86-13
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,16 @@ function initAnchorClipboard(){
483483
}
484484

485485
function initCodeClipboard(){
486+
function getCodeText( node ){
487+
var text = node.textContent;
488+
// remove a trailing line break, this may most likely
489+
// come from the browser / Hugo transformation
490+
text = text.replace( /\n$/, '' );
491+
// removes leading $ signs from text in an assumption
492+
// that this has to be the unix prompt marker - weird
493+
return text.replace( /^\$\s/gm, '' );
494+
}
495+
486496
function fallbackMessage( action ){
487497
var actionMsg = '';
488498
var actionKey = (action === 'cut' ? 'X' : 'C');
@@ -498,34 +508,97 @@ function initCodeClipboard(){
498508
return actionMsg;
499509
}
500510

501-
var codeElements = document.querySelectorAll( 'code' );
511+
if( !window.disableHighlightWrapFix ){
512+
// if the highlight shortcode was used with table lineno mode, the generated DOM
513+
// is a table, containg exactly one row with two cells, the first cell for all linenos
514+
// the second with the code;
515+
// this does not look nice if the code gets wrapped around, so we reformat the table
516+
// by creating a row for each line, containing the two cells but with only the content of
517+
// one line
518+
var codeTables = Array.from( document.querySelectorAll( 'code' ) ).reduce( function(a, code){
519+
// collect all tbody's without duplicates that need our treatment
520+
if( code.parentNode.tagName.toLowerCase() == 'pre' &&
521+
code.parentNode.parentNode.tagName.toLowerCase() == 'td' &&
522+
code.parentNode.parentNode.parentNode.tagName.toLowerCase() == 'tr' &&
523+
code.parentNode.parentNode.parentNode.parentNode.tagName.toLowerCase() == 'tbody' &&
524+
code.parentNode.parentNode.parentNode.querySelector( 'td:first-child > pre > code' ) == code &&
525+
( !a.length || a[a.length-1] != code.parentNode.parentNode.parentNode.parentNode ) ){
526+
var table = code.parentNode.parentNode.parentNode.parentNode;
527+
a.push( table );
528+
}
529+
return a;
530+
}, [] );
531+
for( var i = 0; i < codeTables.length; i++ ){
532+
// now treat the table (tbody);
533+
// first we collect some data, setting up our row template and collect the text
534+
// representation of the code for later usage with copy-to-clipboard
535+
var table = codeTables[i];
536+
var text = getCodeText( table.querySelector( 'td:last-child code' ) );
537+
var tr = table.querySelector( 'tr' ).cloneNode();
538+
tr.appendChild( table.querySelector( 'td:first-child' ).cloneNode() )
539+
.appendChild( table.querySelector( 'td:first-child pre' ).cloneNode() )
540+
.appendChild( table.querySelector( 'td:first-child code' ).cloneNode() )
541+
.classList.add( 'nocode' );
542+
tr.appendChild( table.querySelector( 'td:last-child' ).cloneNode() )
543+
.appendChild( table.querySelector( 'td:last-child pre' ).cloneNode() )
544+
.appendChild( table.querySelector( 'td:last-child code' ).cloneNode() )
545+
.classList.add( 'nocode' );
546+
547+
// select lineno and code cell of first line that contains all the content
548+
var linenums = table.querySelectorAll( 'td:first-child code > span' );
549+
var codes = table.querySelectorAll( 'td:last-child code > span' );
550+
for( var j = 0; j < linenums.length; j++ ){
551+
// now create a new table row by cloning our template
552+
// and transfering the original content
553+
var clonedTr = tr.cloneNode(true);
554+
var code1 = clonedTr.querySelector( 'td:first-child code' );
555+
var code2 = clonedTr.querySelector( 'td:last-child code' );
556+
code1.appendChild( linenums[j] );
557+
code2.appendChild( codes[j] );
558+
table.appendChild( clonedTr );
559+
}
560+
// in the end we have an empty first row, that needs to be deleted
561+
table.querySelector( 'tr:first-child' ).remove();
562+
// we delete the reformat marker of the first code cell to allow the
563+
// copy-to-clipboard functionality
564+
table.querySelector( 'tr:first-child td:last-child code' ).classList.remove( 'nocode' );
565+
// put the text representation into a data attribute
566+
table.querySelector( 'tr:first-child td:last-child code' ).dataset[ 'code' ] = text;
567+
// finally mark our tbody to apply special CSS styling
568+
table.parentNode.parentNode.parentNode.classList.add( 'wrapfix' );
569+
}
570+
}
571+
572+
var codeElements = document.querySelectorAll( 'code:not(.nocode)' );
502573
for( var i = 0; i < codeElements.length; i++ ){
503574
var code = codeElements[i];
504575
var text = code.textContent;
505576
var inPre = code.parentNode.tagName.toLowerCase() == 'pre';
506577
// avoid copy-to-clipboard for highlight shortcode in table lineno mode
507-
var isLineCell = inPre &&
578+
var isFirstLineCell = inPre &&
508579
code.parentNode.parentNode.tagName.toLowerCase() == 'td' &&
509-
code.parentNode.parentNode.parentNode.querySelector( 'td:nth-child(1) > pre > code' ) == code;
580+
code.parentNode.parentNode.parentNode.querySelector( 'td:first-child > pre > code' ) == code;
510581

511-
if( !isLineCell && ( inPre || text.length > 5 ) ){
582+
if( !isFirstLineCell && ( inPre || text.length > 5 ) ){
512583
var clip = new ClipboardJS( '.copy-to-clipboard-button', {
513584
text: function( trigger ){
514585
if( !( trigger.previousElementSibling && trigger.previousElementSibling.matches( 'code' ) ) ){
515586
return '';
516587
}
588+
// if we already have a text representation, return it
589+
var code = trigger.previousElementSibling;
590+
if( code.dataset.code ){
591+
return code.dataset.code;
592+
}
517593
// if highlight shortcode used in inline lineno mode, remove lineno nodes before generating text
518-
var code = trigger.previousElementSibling.cloneNode( true );
519-
Array.from( code.querySelectorAll( '*:scope > span > span:nth-child(1):not(:last-child)' ) ).forEach( function( lineno ){
594+
code = code.cloneNode( true );
595+
Array.from( code.querySelectorAll( '*:scope > span > span:first-child:not(:last-child)' ) ).forEach( function( lineno ){
520596
lineno.remove();
521597
});
522-
var text = code.textContent;
523-
// remove a trailing line break, this may most likely
524-
// come from the browser / Hugo transformation
525-
text = text.replace( /\n$/, '' );
526-
// removes leading $ signs from text in an assumption
527-
// that this has to be the unix prompt marker - weird
528-
return text.replace( /^\$\s/gm, '' );
598+
// generate and save generated text for repeated usage
599+
var text = getCodeText( code );
600+
trigger.previousElementSibling.dataset[ 'code' ] = text;
601+
return text;
529602
}
530603
});
531604

0 commit comments

Comments
 (0)