Dirk Harriman Banner Image

 

Displaying Line Numbered Code

I created a way to display your source code in a mono type font with line numbers on the left side. The numbering can be set to start from any integer using a data property called data-start-num. I'm using a p tag instead of a pre tag. On top of the code listing is a copy button that allows the user to copy the code in the code listing.

<p class="code_text"></p> <p class="code_text" data-start-num="23"></p> <p class="code_text" data-start-num="23" data-code-title="Syntax"></p> <p class="code_text" data-start-num="23" data-code-title="Syntax" data-hide-copy="false"></p> <p class="code_text" data-start-num="23" data-code-title="Syntax" data-hide-copy="false" data-code-type="script"></p>

Parameter Description
data-start-num The start numbering
data-code-title A text title displayed in the top border.
data-hide-copy Boolean for displaying the copy button.
data-code-type Determines if code is filtered to convert escape sequences.

The CSS

// NUMBERED CODE TEXT p.code_text { font:600 1.0rem/1.2rem 'Courier New',Courier,Monospace; margin:0rem 0rem 1rem 0rem; padding:0.5rem 1rem; background-color:#000; color:#fff; opacity:1; white-space: pre; } p.code_text .line-number { font:600 1.0rem/1.2rem 'Courier New',Courier,Monospace; color:#fff; display:block; } p.code_text .line-number { float:left; margin:0 1em 0 -1em; border-right:1px solid; text-align:right; } p.code_text .line-number span { display:block; padding:0 .5em 0 1em; } p.code_text .cl { display:block;clear:both; } // NUMBERED FILE TEXT p.file_text { font:700 1.0rem/1.25rem 'Courier New',Courier,Monospace; margin:0rem 0rem 1rem 0rem; padding:0.5rem 1rem; background-color:#eee; color:#333; opacity:1; white-space: pre; } p.file_text .line-number { font:700 1rem/1.25rem 'Courier New',Courier,Monospace; color:$blue; display:block; } p.file_text .line-number { float:left; margin:0 1em 0 -1em; border-right:2px solid $blue; text-align:right; } p.file_text .line-number span { display:block; padding:0 .5em 0 1em; } p.file_text .cl { display:block; clear:both; }


 

The Javascript

Note that this should be placed at the bottom of the page.

<script> /***********************************************************/ function fallbackCopyTextToClipboard(text) { var textArea = document.createElement("textarea"); textArea.value = text; // AVOID SCROLLING TO BOTTOM textArea.style.top = "0"; textArea.style.left = "0"; textArea.style.position = "fixed"; document.body.appendChild(textArea); textArea.focus(); textArea.select(); try { var successful = document.execCommand('copy'); var msg = successful ? 'successful' : 'unsuccessful'; alert('Fallback: Copying text command was ' + msg); } catch (err) { alert('Fallback: Oops, unable to copy', err); } document.body.removeChild(textArea); } /***********************************************************/ function copyTextToClipboard(text) { if (!navigator.clipboard) { fallbackCopyTextToClipboard(text); return; } navigator.clipboard.writeText(text).then(function() { alert('Async: Copying to clipboard was successful!'); }, function(err) { alert('Async: Could not copy text: ', err); }); } /***********************************************************/ /* * codeType Values Action * ----------------------------------------- * script (default) Nothing * html Convert escaped characters * mixed Convert escaped characters outside of <script> tags */ function copy_code(idNum, codeType) { var copy_source = document.getElementById(idNum); var copy_val = ""; switch(codeType) { case "script" : // DEFAULT - DO NOTHING copy_val = copy_source.innerHTML; break; case "html" : // REPLACE ESCAPED TAGS copy_val = filter_code(copy_source.innerHTML); break; case "mixed" : // REPLACE ESCAPED TAGS copy_val = filter_code(copy_source.innerHTML); break; default: // DO NOTHING copy_val = copy_source.innerHTML; break; } copyTextToClipboard(copy_val); } /***********************************************************/ function filter_code(txtcode) { var rtncode = ""; const re_lt = /</g; const re_gt = />/g; rtncode = txtcode.replace(re_lt, '<').replace(re_gt, '>'); return rtncode; } /***********************************************************/ (function() { /* CODE TEXT: DISPLAYS CODE IN A PARAGRAPH TAG PARAMETERS DEFAULT DESCRIPTION data-start-num 0 ALLOWS FOR SPECIFIED START NUMBER data-code-title '' PLACES TEXT IN THE TOP BORDER data-hide-copy false DETERMINES WHETHER COPY BUTTON IS VISIBLE data-code-type script DETERMINES HOW COPY WORKS. VALUES: script | html | mixed cdtxt = A LIST OF ELEMENTS WITH THE CLASS NAME "code_text" */ var cdtxt = document.getElementsByClassName('code_text'); var fltxt = document.getElementsByClassName('file_text'); var startNum=1; var content_type = "script"; var hideCopy = false; var codeTitle = ""; var newId; if (cdtxt !== null) { // LOOP THROUGH ALL OF THE CODE_TEXT ITEMS for (var i = 0; i < cdtxt.length; i++) { newId = 'codeText'+i; // SET DEFAULTS codeTitle = ""; // SET DEFAULT CODE TITLE hideCopy = false; // SET DEFAULT COPY BEHAVIOUR // GET THE data-start-num DATA ATTRIBUTE FOR THIS PARTICULAR ITEM if ('startNum' in cdtxt[i].dataset) { startNum = cdtxt[i].dataset.startNum; } // GET THE data-code-title DATA ATTRIBUTE FOR THIS PARTICULAR ITEM if ('codeTitle' in cdtxt[i].dataset) { codeTitle = cdtxt[i].dataset.codeTitle; } // GET THE data-hide-copy DATA ATTRIBUTE FOR THIS PARTICULAR ITEM if ('hideCopy' in cdtxt[i].dataset) { hideCopy = (cdtxt[i].dataset.hideCopy === 'true'); } // GET THE data-code-type DATA ATTRIBUTE FOR THIS PARTICULAR ITEM if ('codeType' in cdtxt[i].dataset) { content_type = cdtxt[i].dataset.codeType; } if (hideCopy == false) { // ADD A DIV ON TOP OF THIS ELEMENT WITH A BUTTON TO COPY THE CONTENTS cdtxt[i].outerHTML = "<div class=\"copy-code\">"; cdtxt[i].outerHTML += "<div class=\"code-title\">"+ codeTitle +"</div>"; cdtxt[i].outerHTML += "<button type=\"button\" class=\"btn btn-bs-primary\" "; cdtxt[i].outerHTML += "onclick=\"copy_code('"+ newId +"','"+ content_type +"')\">Copy</button>"; cdtxt[i].outerHTML += "</div>" + cdtxt[i].outerHTML; } else { if (codeTitle != ""){ cdtxt[i].outerHTML = "<div class=\"copy-code\">"; cdtxt[i].outerHTML += "<div class=\"code-title\">"+ codeTitle +"</div>"; cdtxt[i].outerHTML += "</div>" + cdtxt[i].outerHTML; } } // WRAP THE INNER HTML WITH SOME SPAN ELEMENTS cdtxt[i].innerHTML = "<span class=\"line-number\"></span>"; cdtxt[i].innerHTML += "<div id=\""+ newId +"\">" + cdtxt[i].innerHTML + "</div>"; cdtxt[i].innerHTML += "<span class=\"cl\"></span>"; // GET THE NUMBER OF LINES IN THE INNER HTML var num = cdtxt[i].innerHTML.split(/\n/).length; // LOOP THROUGH THE LINES IN THE INNER HTML for (var j = 0; j < num; j++) { // THE VARIABLE line_num IS EQUAL TO THE FIRST SPAN ELEMENT var line_num = cdtxt[i].getElementsByTagName('span')[0]; // INSERT A NUMBER BETWEEN A COUPLE OF SPAN TAGS line_num.innerHTML += '<span>' + (eval(startNum) + j) + '</span>'; } } } if (fltxt !== null) { for (var i = 0; i < fltxt.length; i++) { if ('startNum' in fltxt[i].dataset) { startNum = fltxt[i].dataset.startNum; } fltxt[i].innerHTML = '<span class="line-number"></span>' + fltxt[i].innerHTML + '<span class="cl"></span>'; var num = fltxt[i].innerHTML.split(/\n/).length; for (var j = 0; j < num; j++) { var line_num = fltxt[i].getElementsByTagName('span')[0]; line_num.innerHTML += '<span>' + (eval(startNum) + j) + '</span>'; } } } })(); </script>