In my HTML source code, I have a code block like the following (I use showdown and highlight.js on this page):
double myNum
I just remove them manually before the highlighter starts.
const trimLine = node =>
node.firstChild.nodeValue = node.firstChild.nodeValue.replace(/^\n+|\n+$/g, "");
window.onload = function () {
Array.prototype.slice
.call(document.getElementsByTagName("code"), 0)
.map(trimLine);
hljs.initHighlightingOnLoad();
}
You could use this hack:
pre:first-line {
line-height: 0;
}
These functions use a class (added to the pre
) to remove leading and trailing whitespace
function removeWhitespace(indent) {
// Get a list of all elements that need whitespace removed by indent value (will have class `indent-X`)
// List may be 0 long - loop simply doesn't run
var preElements = document.getElementsByClassName('indent-'+indent);
for (i = 0; i < preElements.length; i++) {
preElements[i].innerHTML = preElements[i].innerHTML.split('\n'+' '.repeat(indent)).join('\n').split('\n'+' '.repeat(indent-2)+'</code>').join('</code>').split("\n").slice(1,-1).join("\n");
//split('\n'+' '.repeat(indent)).join('\n') -- Split at every newline followed by X spaces. Then join together with the newlines.
// .split('\n'+' '.repeat(indent-2)+'</code>').join('</code>') -- The lastline will have 2 less spaces, so remove those, and the newline at the end. Add the tag back in.
//.split("\n").slice(1,-2).join("\n"); -- Remove the first and last lines.
}
}
function removeWhitespaces() {
// Loop over all indents, 2 to 40
for (indent = 2; indent <= 40; indent+=2) {
removeWhitespace(indent);
}
}
Simply add the class indent-X
where X
is the amount of whitespace you want to remove to the pre
.
JSFiddle
function removeWhitespace(indent) {
// Get a list of all elements that need indent removed by indent value (will have class `indent-X`)
// List may be 0 long - loop simply doesn't run
var preElements = document.getElementsByClassName('indent-' + indent);
for (i = 0; i < preElements.length; i++) {
preElements[i].innerHTML = preElements[i].innerHTML.split('\n' + ' '.repeat(indent)).join('\n').split('\n' + ' '.repeat(indent - 2) + '</code>').join('</code>').split("\n").slice(1, -2).join("\n");
//split('\n'+' '.repeat(indent)).join('\n') -- Split at every newline followed by X spaces. Then join together with the newlines.
// .split('\n'+' '.repeat(indent-2)+'</code>').join('</code>') -- The lastline will have 2 less spaces, so remove those, and the newline at the end. Add the tag back in.
//.split("\n").slice(1,-1).join("\n"); -- Remove the first and last lines.
// Remove the clickme element.
document.getElementById('clickme').innerHTML = '';
}
}
function removeWhitespaces() {
// Loop over all indents, 2 to 40
for (indent = 2; indent <= 40; indent += 2) {
removeWhitespace(indent);
}
}
.indent-14 {
background-color: #ccc;
}
<body>
<div id="clickme" onclick="removeWhitespaces()">
Click Me
</div>
<pre class="indent-14">
<code>
function createCORSRequest(method, url) {
var request = new XMLHttpRequest();
if ('withCredentials' in request) {
request.open(method, url, true);
} else if (typeof XDomainRequest != 'undefined') {
request = new XDomainRequest();
request.open(method, url);
} else {
request = null;
}
return request;
}
</code>
</pre>
</body>
Here's another approach using Javascript that also solves the problem:
<script>
window.onload = function (){
// remove leading linebreaks from code blocks.
var pre = document.getElementsByTagName("code");
for (var i = 0, len = pre.length; i < len; i++) {
var text = pre[i].firstChild.nodeValue;
pre[i].firstChild.nodeValue = text.replace(/^\n+|\n+$/g, "");
}
}
</script>
Someone else posted this, then deleted their answer, but I thought it was worth preserving.
That's how pre
works by default: it honors line breaks and whitespace. If you don't want the newline to render, then you have to remove it. Either outright remove it from the source or comment it out if you care how the source looks.
http://jsfiddle.net/VL8tG/
<pre><code class="cpp"><!--
-->double myNumber = (double)4;<!--
--></code></pre>
Demo: http://jsfiddle.net/WjVVs/4/.
Tested with Chrome and FF on the PC. It does not work in IE 9 when the plugin is applied to a code
element (it appears to work fine when applied to a pre
element). I can't find a suitable workaround, but feel free to comment/update.
This is a modified version from another answer. This plugin attempts to remove extra indentation caused by the natural flow of the document. I've modified it to be smarter about leading whitespace.
If it works correctly, you should see something like:
$("code").prettyPre(); // any selector here
<div>
<pre><code class="cpp">
double myNumber = (double)4;
// another line
// another line
// this is purposely indented further
for( var i = 0; i < 100; i++ ){
}
</code></pre>
</div>
(function( $ ) {
$.fn.prettyPre = function( method ) {
var defaults = {
ignoreExpression: /\s/ // what should be ignored?
};
var methods = {
init: function( options ) {
this.each( function() {
var context = $.extend( {}, defaults, options );
var $obj = $( this );
var usingInnerText = true;
var text = $obj.get( 0 ).innerText;
// some browsers support innerText...some don't...some ONLY work with innerText.
if ( typeof text == "undefined" ) {
text = $obj.html();
usingInnerText = false;
}
// use the first line as a baseline for how many unwanted leading whitespace characters are present
var superfluousSpaceCount = 0;
var pos = 0;
var currentChar = text.substring( 0, 1 );
while ( context.ignoreExpression.test( currentChar ) ) {
if(currentChar !== "\n"){
superfluousSpaceCount++;
}else{
superfluousSpaceCount = 0;
}
currentChar = text.substring( ++pos, pos + 1 );
}
// split
var parts = text.split( "\n" );
var reformattedText = "";
// reconstruct
var length = parts.length;
for ( var i = 0; i < length; i++ ) {
// remove leading whitespace (represented by an empty string)
if(i === 0 && parts[0]=== ""){
continue;
}
// cleanup, and don't append a trailing newline if we are on the last line
reformattedText += parts[i].substring( superfluousSpaceCount ) + ( i == length - 1 ? "" : "\n" );
}
// modify original
if ( usingInnerText ) {
$obj.get( 0 ).innerText = reformattedText;
}
else {
// This does not appear to execute code in any browser but the onus is on the developer to not
// put raw input from a user anywhere on a page, even if it doesn't execute!
$obj.html( reformattedText );
}
} );
}
}
if ( methods[method] ) {
return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ) );
}
else if ( typeof method === "object" || !method ) {
return methods.init.apply( this, arguments );
}
else {
$.error( "Method " + method + " does not exist on jQuery.prettyPre." );
}
}
} )( jQuery );