How to show line numbers for a code block using JavaScript? - javascript

Here's the thing. I use 'Highlight.js' (a javascript-based automatic syntax highlighter) to syntax-highlight code on my website. But it doesn't support line numbers or zebra-striping (for alternate lines of code).
My code block is wrapped in <pre><code> blocks like this:
<pre><code>
<script type="text/javascript">
// Say hello world until the user starts questioning
// the meaningfulness of their existence.
function helloWorld(world) {
for (var i = 42; --i >= 0;) {
alert('Hello ' + String(world));
}
}
</script>
<style>
p { color: pink }
b { color: blue }
u { color: "umber" }
</style>
</code></pre>
And the output looks like this:
Now I want to show line numbers for the code block dynamically using JavaScript. How do I do that? (Also, if possible, how do I show zebra-striping?)
Thanks.
PS: I don't know JavaScript, so please try to be as clear as possible. I will try my best to understand. Thanks.

You could use an alternate framework such as http://alexgorbatchev.com/SyntaxHighlighter/
Or take a look here and find something that suites.
http://www.1stwebdesigner.com/css/16-free-javascript-code-syntax-highlighters-for-better-programming/

The basic steps would be:
Take the HTML inside the element.
Split by newline characters (\n).
For each string, add a number and a dot in front of it.
Combine the strings again with newline characters.
Set the string as the HTML of the element.
However, this would mess up the syntax highlighting of the syntax highlighter because it most likely won't recognize that the code has line numbers in front. So the syntax highlighter needs to provide the functionality of line numbers for you.

Adding a new answer to an old question.
I wanted to display line numbers in the left margin the way ace.js does.
My solution has some hacky details, but I wanted to share it anyway, because it turns out that absolute-positioned spans within relative-positioned spans work pretty well for this.
Encouraged by the above answers and this answer about relative positioning without taking up space, I used:
var line = 1;
code = code.replace(/^/gm, function() {
return '<span class="line-number-position">​<span class="line-number">' + line++ + '</span></span>';
});
The regular expression /^/gm "replaces" the beginning of each line with the span-within-span.
​ is a zero-width space, because apparently firefox seems to have trouble deciding whether to put a zero-height span at the top or the bottom of the character.
line-number-position and line-number are CSS classes like these:
.line-number-position {
position: relative;
top: 0;
}
.line-number {
position: absolute;
text-align: right;
right: 17px;
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace;
font-size: 12px;
}
Yes, there are some magic numbers in there to match ace formatting, but the point is to put a relative-positioned zero-sized span at the beginning of each line and use it as a reference point to add an absolute-positioned span out in the left margin.
Works on current Chrome, Safari, Firefox, and Opera.

Related

Show JS and CSS code in Angular application

In my Angular 1.x application (using ES5) I need to show the user the sample of formatted css and js code on the UI (with indentations, line-breaks, etc.), which the the user will need to copy and paste into his own html file. The sample of code:
<style type='text/css'> html, body { margin: 0 }
.banner {
display: block;
position: absolute;
</style>
<script>
window.showSmth = function(item) {
// some logic here
}
</script>
I've tried to search for some 3rd parties, but no results so far, could someone advice me on this?
In HTML proper, there’s no way short of escaping the characters.
The only solution guaranteed to work everywhere is to escape the code (< and & as < and &, respectively) manually.
Replace the & character with &
Replace the < character with <
Replace the > character with >
Optionally surround your HTML sample with <pre> and/or <code> tags.
Syntax highlighting sites:
rainbows (very Perfect)
prettify
syntaxhighlighter
highlight
JSHighlighter

Wrapping a text on arbitrary non-whitespace characters

I have long namespaces to be displayed in my articles (like MyProject\Sub\Level) and I want them to be wrapped on a backslash character (\) if the window width is insufficient. How can I implement this using CSS or JS/jQuery?
To tell browsers that a line break is permitted after a character, insert the ZERO WIDTH SPACE (ZWSP) character, U+200B, after the character. In HTML markup, you can use the character reference `​', e.g.
MyProject\​Sub\​Level
If you add the characters via scripting, you can enter the character itself, using the string literal \u200b.
Some old browsers (IE 6) used to have problems with this, but now this approach seems to work better than the alternative, the old <wbr> tag (which was well-supported but has now been messed up in new versions of IE).
Use the following css in the element that contains the text:
word-wrap: break-word;
It's a css3 property supported in modern browsers: Google Chrome 6, Internet Explorer 8, Firefox 3, Opera 10 y Safari 5.
Acclaration: It won't break on / character only, it could break on any character of the word according to the stretching of container.
One option is to use the soft-hyphen (­) around the \ characters; the soft-hyphen allows a word to break at a given point, appearing only if the word does, in fact, break at that point.
It also doesn't appear in the text if it's copied and pasted (tested in Chromium 19/Ubuntu 11.04); this approach uses replace() and jQuery's html() method with the following HTML:
<ul>
<li>\some\text\possibly\a\path</li>
<li>\another\path</li>
<li>\something\else\also\quite\long</li>
</ul>​
And CSS:
li {
width: 8em;
border: 1px solid #000;
}​
jQuery:
$('li').html(function(i, h) {
return h.replace(/(\\)/g, '­$1­')
});​
JS Fiddle demo.
Obviously, you don't need to use the soft-hyphen on both sides of the \ character, that was just a demonstration for how it might be used.
An alternative, if you'd rather avoid the appearance of - characters at the break-point, is to use the same approach as above, but instead insert an empty span element, and give it the style display: inline-block;:
jQuery:
$('li').html(function(i, h) {
return h.replace(/(\\)/g, '$1<span></span>')
});​
CSS:
li {
width: 8em;
border: 1px solid #000;
}
li span {
display: inline-block;
}
JS Fiddle demo.
References:
html().
replace().
You could probably follow the example on jQuery - Find and replace text, after body was loaded and have it insert a break following every slash

Making line numbers uncopyable

I'm working on adding line number support to Rainbow, a syntax highlighter, but I can't figure out how to make the line numbers uncopyable.
Disabling selection via user-select: none; makes an element unhighlightable, but you can still copy its text by highlighting around it and then copying, which ends up copying the line numbers along with code.
Here is a working example of the problem: http://jsfiddle.net/CjJLv/8/
Any help would be appreciated. Thanks!
Okay, the easiest way in compliant browsers, and, sadly, not reliable cross-browser, is to use generated content (I've removed the various parts where index was being added to textual content in the plug-in, and used the following (at the end of the CSS) to implement un-copyable text:
table.rainbow {
counter-reset: line;
}
table.rainbow tbody tr td:first-child {
counter-increment: line;
}
table.rainbow tr td:first-child::before {
content: counter(line);
}
JS Fiddle demo.
This does, though, have some rather large flaws (the cross-browser unfriendly approach being the biggest), so I'll try for something better...
I would just add a regular list.
if (window.Rainbow) window.Rainbow.linecount = (function(Rainbow) {
Rainbow.onHighlight(function(block) {
var lines = $(block).text().split('\n');
var $lines = $('<ul class="lines"/>');
for (var i = 0, len = lines.length; i < len; i++) {
$lines.append('<li class="line"'+ i +'>'+ i +'</li>');
}
$(block).before($lines);
});
})(window.Rainbow);​
And CSS:
.lines {
float: left;
padding-right: 1.5em;
padding-left: .5em;
}
So now you can select just the code if you highlight carefully.
Demo: http://jsfiddle.net/elclanrs/CjJLv/18/
David Thomas's answer is perfect for line numbers. More generally, if you have other text you don't want to be copied, you can have it as generated content:
<style>#uniqueid::before { content: 'TEXT GOES HERE'; }</style>
<span id="uniqueid"></span>
But it's ugly to have to embed text in your CSS, so you can refine this using CSS attr() to read the text from an attribute in the HTML (as suggested by pimvdb):
<style>[data-nocopy]::before { content: attr(data-nocopy); }</style>
<span data-nocopy="TEXT GOES HERE"></span>
<span data-nocopy="AND HERE"></span>
Demo: http://jsbin.com/fob/1/edit
This works in Firefox, Safari, and Chrome due to 21-year-old(!) bugs in selecting generated content:
https://bugzilla.mozilla.org/show_bug.cgi?id=12460
https://bugs.webkit.org/show_bug.cgi?id=7562
https://bugs.chromium.org/p/chromium/issues/detail?id=80466
But in old IE (< 8) the text will be completely invisible; in newer IE it should be visible but may well be copyable. In general don't use this technique for anything critical, as these bugs might get fixed one day...
And use sparingly, as this can be very user-hostile.
You could display each line number as a sequence of <img>s.

JS/CSS/XHTML: Don't copy specific text during copy events

I'm looking for a way to disable the copying of a specific area of text when you use Ctrl + C, etc. Whether I have to write the text a different way or not.
http://gyazo.com/721a0a5b5af173beb1ad3305633beafb.png
Above is what this is for. It's a syntax highlighter I have been working on (3 languages supported so far). When the user selects ANY text in any way, I don't want the line numbers to be copied.
I can't think of a way to display line numbers, without them actually being there.
As long as the line numbers and the source code are mixed together, this is going to be tough to prevent programmatically, if not impossible.
The ideal way would be having the source code in an actual container of its own.
Open a document inspector and look at how Github do it, for example: https://github.com/jbrisbin/riak-exchange/blob/master/Makefile
they have a separate <pre> element containing the line numbers, and a <table> cell containing the code. (I assume selecting is a reason why they use tables here, but I do not know for sure.)
Give this a try...
Demo: http://jsfiddle.net/wdm954/UD8Dq/7
I layered the div so the code div is on top and the numbers are behind. When you copy and paste you should just get the code.
.lines {
position: absolute;
width: 80%;
color: #666;
}
.lines pre:nth-child(odd) {
background-color: #EEE;
}
.code {
position: absolute;
z-index: 2;
padding-left: 5%;
width: 80%;
}
<div class="box">
<div class="lines">
<pre>1</pre>
<pre>2</pre>
<pre>3</pre>
<pre>4</pre>
</div>
<div class="code">
<pre>
code
code
code
code
</pre>
</div>
</div>
Setting user-select, -moz-user-select, and -webkit-user-select to none might work. For IE, you will need to handle onselectstart and return false.
This will prevent people from selecting the text, but I don't know what happens when it's beside other text that you attempt to copy.
I know that this question is three years old, but with HTML5 you can store line numbers in a data attributes and use CSS2 to display the text. This should prevent line numbers from being copied.
HTML
<span data-line-number='1' class='line'></span>
CSS
.line:before {
content: attr(data-line-number);
}

sIFR 3 Leading and Kerning

I am trying to get leading and kerning to work on some sIFR 3 type on a site I'm working on (as described in the wiki: http://wiki.novemberborn.net/sifr3/Styling), but these two parameters seem to have no effect no matter what I do.
I am not using intergers (no 'px' or 'em') just as it requires. I've also tried several different font swf files, just to make sure it's not the font. I don't know why it doesn't work. All of the other css parameters that I assign to .sIFR-root work just fine. Here's a sample of my code using 'leading'.
In sifr_config.js:
sIFR.replace(snl, {
selector: '.section-title h1',
css: ['.sIFR-root { color: #FFFFFF; text-align: center; leading:2; }'],
wmode: 'transparent'
});
In the HTML doc:
<div class="section-title">
<h1>sIFR Text</h1>
</div>
(I've also tried the css code with and without the square brackets, as I've seen it done both ways. Doesn't seem to make a difference).
What am I doing wrong? Any help would be greatly appreciated; thanks!
ETA: Found an less hackish way:
line-height seems to work when added to the CSS for the replaced element (in my example that'd be: .sIFR-active .section-title h1). So I was able to use regular old line-height to fake a margin.
All righty—since this one left everyone speechless, here's what I discovered:
Originally, there were many suggestions for using leading as a replacment for margin-top or padding-top since these will not work with sIFR. This is what I was trying to use it for. I had a single line of text and needed to give it some space up top, so I was trying to do this by increasing the leading (line height) to no avail. I think this worked at one point, but then as I was looking at the change logs for all the revisions of sIFR, I found a note about a "fix" to leading. Apparently the developer considered leading being recognized on single-line text as a bug, so "fixed" it so that leading is only applied when the text is multiple lines. I tested by putting a line-break before my text, and sure enough, leading started to work!
So it seems that now, in order to achieve a top margin on my sIFR header, I have to add unneccessary code one way or another—by wrapping it in a div or span with a top margin, or by adding a line break and using negative leading.
I still have no idea about the kerning, but letter-spacing seems to be working, so…
If anyone has any additional insight to offer, I'm all ears!
Here's what works for me, using sIFR 3 to get a h2 with Serifa font in red with minimal letter spacing and leading. The actual sIFR swf is nothing special, simply created as per the sIFR documentation. As mentioned above, offsetTop and tuneHeight also work for adjusting positioning (shown below although I haven't used them so set to 0).
In sifr.css
.sIFR-active h2.replace {
color: #FF0000;
visibility: hidden;
font-family: arial,helvetica,clean,sans-serif;
font-size: 2.5em;
text-transform:uppercase;
}
in sifr-config.js
sIFR.replace(serifa, {
selector: 'h2.replace',
css: ['.sIFR-root { letter-spacing: -2; leading: -15; kerning:true; color:#FF0000; text-transform:uppercase; font-size:2.5em; }' ],
tuneWidth: '0' , tuneHeight: '0' , offsetTop: '0' });
In html page (for example):
<div class="column grid_4">
<h2 class="replace">Title here</h2>
</div>

Categories

Resources