Adding Line Numbers To Pre-formatted Text - javascript

I have a body of text that I show in a web page within some <pre> tags. I would like to add a column to the left of this text body to show the line number of the text.
The body of text is retrieved by using [PHP] file_get_contents() so I am just echo-ing a string within the <pre> tags.
I imagine this can be accomplished with JavaScript but I have yet to find a solution.
Solutions I have seen on here usually use a library or CSS. The CSS method would be great but this method seems to require that each line of the body text have its own corresponding tag (eg <p> or <span>).
// Example of CSS Solution
p:not(:first-child):before {
counter-increment: custom-counter+1;
content: counter(custom-counter)". ";
display: table-cell;
}
p:first-child:before {
display: table-cell;
content: '1. '
}
I would like to avoid having to create a DOM element (before load) line by line. That said, if that is the best solution I simply want to know the "preferred" way to go about this.
How could I accomplish this using JavaScript / jQuery?

One simple solution would be to split the string on "\n" with javascript to get each line append the line numbers then re-join them together. This will only work if you are using <pre> tags where newlines are literal newlines.
JsFiddle
let text = document.getElementById("test").innerHTML;
let lines = text.split("\n");
for (let i=0;i<lines.length;i++) {
lines[i] = (i+1)+" "+lines[i];
}
text = lines.join("\n");
document.getElementById("test").innerHTML = text;

Related

Textarea.value doesn't manipulate the HTML

Setting the value of the textarea, won't be reflected in the HTML.
For instance,
If you have <textarea></textarea> in your HTML, and set its value to 'Hello' the HTML will remain unchanged and not <textarea>Hello</textarea>
I think this is what you want, use this to your w3schools example
<script>
function myFunction() {
var x = document.getElementById("myTextarea").value;
document.getElementById("demo").innerHTML = x;
}
myTextarea.onkeyup=()=>myTextarea.innerText=myTextarea.value;
</script>
You seem to be working off some misconceptions. I take it you're expecting that line breaks in the text area will be reflected as line breaks in a paragraph if you insert it as the HTML of the paragraph. In HTML, all whitespace is collapsed into spaces, and line breaks in HTML source do not normally translate to breaks in HTML text flows. If you do want newlines to work in HTML, use a <pre></pre> element instead. Otherwise you'll need to convert newlines to <br> elements.
There's also the white-space CSS style that can change the way that whitespace is rendered.

HTML, CSS, JS in separate area not affecting entire website

I want to put up tutorials on my website. In order for the user to see some examples I want to output the code (HTML, CSS, JavaScript) plus the result.
So my markup for a the code box, including a little example, looks like the following:
<div class="code-box">
<code class="code-section lang-html">
<!-- Example HTML code -->
<div> <span>This</span> is an example </div>
</code>
<code class="code-section lang-css">
/* Example CSS code */
div{
font-size: 120%;
}
div span{
font-size: 130%;
}
</code>
<code class="code-section lang-js">
/* Example jQuery code */
$("div").hover(function(){
$(this).find("span").css("fontSize", "140%");
}, function(){
$(this).find("span").css("fontSize", "130%");
});
</code>
<code class="code-section lang-result">
<!-- Example result -->
</code>
</div>
Via JavaScript/jQuery I escape necessary characters like "<" that are inside the code tags, so that the actual code is printed as text, and not evaluated as eg HTML.
No problems so far.
My problem arises when it comes to the "result" part, where I actually want the written code to be evaluated as code. So far I got it to work with jQuery:
Unescaping the HTML characters, putting the css stuff inside a tag, and the JS inside a tag. The problem now being that the "new" Css and JS will also apply to the rest of the website <-- definitely not what I want. But whats the solution?
I found an article about "scoped css":
Putting your css inside a tag will make the css apply to only the parent and its children elements. But support is low and this would only help the CSS, not the JS.
Givng my example code an id or class is simple, but not something desirable for each tutorial I wanna put up there, neither for writing nor for reading.
I would need to wrap that tutorial-code in a bubble, separated from my website's code. Kind of like an iframe or such. I would really appreciate any ideas or comments on this.
Thanks in advance.
Seems to me you are tryingf to achieve something like this.
var parent = $(".code-box.example-1"),
parentC = parent.attr("class").match(/example-\d+/),
htmlSnip = parent.find(".lang-html > pre").text().replace("<", "<").replace(">", ">"),
cssSnip = parent.find(".lang-css > pre").html().replace(/(\/\*.*\*\/\n)|(^\s*)/gm, "").replace(/^([^{\n]+)(?={$)/gm, "." + parentC + " .lang-result " + "$1"),
jsSnip = parent.find(".lang-js > pre").html().replace(/(\/\*.*\*\/\n)|(^\s*)/gm, "").replace(/(\$\(")([^"]+)("\))/gm, "$1." + parentC + " .lang-result " + "$2 $3");
parent.find(".lang-result").html(htmlSnip).prepend("<style>" + cssSnip + "</style>" + "<script>" + jsSnip + "<\/script>");
If this is what you are looking for and you require additiional information, let me know. The key is to add a class per code example you are using, here .example-1.
For some regex explanations, I refer you to regex101. It's a great tool with a very good explanation of all code in the right window. As you may know, you can use RegEx to match, but also to substitute. In the tool, at the bottom of the window, there's "Substitution". Click on it, to open the window. The Regex at the top of the page will evaluate the "Test string", and substitute that string with your input in "Substitution". The result is in the bottom most field.
CSS substitution:
First, let's remove the CSS comment AND all spatial characters that might be in our way (removing means "replace by an empty string") - example: https://regex101.com/r/cL0hL3/2
The result will be something like this:
div{
font-size: 120%;
}
div span{
font-size: 130%;
}
But we want to make this style more specific. We want it to only apply to the div that's inside .lang-result which, in turn, is part of the parent container .example-1. Therefore we need to add some things to the CSS. A useful thing to use is the dollar sign $1 which in substitution will return the captured group (which in regex is in parentheses). $1 returns the first captured group, $2 the second one and so on. Here's an example: https://regex101.com/r/cL0hL3/3. The result will then look how we want:
.parent-class .lang-result div{
font-size: 120%;
}
.parent-class .lang-result div span{
font-size: 130%;
}
JS substitution: the first part is identical to the CSS regex: remove the comment (doesn't work with // comments only with /*...*/). That will lead to:
$("div").hover(function(){
$(this).find("span").css("fontSize", "140%");
}, function(){
$(this).find("span").css("fontSize", "130%");
});
Then we'll have to change the base selector (the div) the only the div in our result (smilar to what we did in the case for CSS). This is a good time to show what capturing groups do (you can do this without using three groups, but it's a good way to illustrate its possibilities:
We replace this
(\$\(")([^"]+)("\))
with this
$1.parent-class $2$3
It's crucial to see how $1 is the first group (\$\(") (literally $(", $2 is whichever selector was already there, and $3 is literally "). Put that all together, and you have a new jQuery object.
See it in action here. https://regex101.com/r/cL0hL3/4
Again there are many other ways to do that in regex, probably more efficient as well, but it's a good showcase. I didn't go into too much detail, but you can take the right window of the website as an explanation for what your regular expression does.
If you want to apply this to multiple elements without manually added classes, you can do it like so: http://jsfiddle.net/0c1np9uL/2/
$(".code-box").each(function () {
var parent = $(this);
parent.addClass("example-" + parent.index());
var parentC = parent.attr("class").match(/example-\d+/),
htmlSnip = parent.find(".lang-html > pre").text().replace("<", "<").replace(">", ">"),
cssSnip = parent.find(".lang-css > pre").html().replace(/(\/\*.*\*\/\n)|(^\s*)/gm, "").replace(/^([^{\n]+)(?={$)/gm, "." + parentC + " .lang-result " + "$1"),
jsSnip = parent.find(".lang-js > pre").html().replace(/(\/\*.*\*\/\n)|(^\s*)/gm, "").replace(/(\$\(")([^"]+)("\))/gm, "$1." + parentC + " .lang-result " + "$2 $3");
parent.find(".lang-result").html(htmlSnip).prepend("<style>" + cssSnip + "</style>" + "<script>" + jsSnip + "<\/script>");
});
Be more specific with your selections, instead of having $("div") use $("#result div"), also a nice thing you can do with jQuery instead of wraping it, you can use if so: if($("#result div").attr("on") == "on") {//do stuff}
You can use textareas to display your code. As for the "results" section, an iframe is probably your best bet.
.code{
border:0;
resize: none;
height:100px;
width:300px;
overflow:hidden;
}
<textarea class="code">
<!-- Example HTML code -->
<div> <span>This</span> is an example </div>
</textarea><br>
<textarea class="code">
/* Example CSS code */
div{
font-size: 120%;
}
div span{
font-size: 130%;
}
</textarea><br>
<textarea class="code">
/* Example jQuery code */
$("div").hover(function(){
$(this).find("span").css("fontSize", "140%");
}, function(){
$(this).find("span").css("fontSize", "130%");
});
</textarea>

How can I Strip all regular html tags except <a></a>, <img>(attributes inside) and <br> with javascript?

When a user create a message there is a multibox and this multibox is connected to a design panel which lets users change fonts, color, size etc.. When the message is submited the message will be displayed with html tags if the user have changed color, size etc on the font.
Note: I need the design panel, I know its possible to remove it but this is not the case :)
It's a Sharepoint standard, The only solution I have is to use javascript to strip these tags when it displayed. The user should only be able to insert links, images and add linebreaks.
Which means that all html tags should be stripped except <a></a>, <img> and <br> tags.
Its also important that the attributes inside the the <img> tag that wont be removed. It could be isplayed like this:
<img src="/image/Penguins.jpg" alt="Penguins.jpg" style="margin:5px;width:331px;">
How can I accomplish this with javascript?
I used to use this following codebehind C# code which worked perfectly but it would strip all html tags except <br> tag only.
public string Strip(string text)
{
return Regex.Replace(text, #"<(?!br[\x20/>])[^<>]+>", string.Empty);
}
Any kind of help is appreciated alot
Does this do what you want? http://jsfiddle.net/smerny/r7vhd/
$("body").find("*").not("a,img,br").each(function() {
$(this).replaceWith(this.innerHTML);
});
Basically select everything except a, img, br and replace them with their content.
Smerny's answer is working well except that the HTML structure is like:
var s = '<div><div>Link<span> Span</span><li></li></div></div>';
var $s = $(s);
$s.find("*").not("a,img,br").each(function() {
$(this).replaceWith(this.innerHTML);
});
console.log($s.html());
The live code is here: http://jsfiddle.net/btvuut55/1/
This happens when there are more than two wrapper outside (two divs in the example above).
Because jQuery reaches the most outside div first, and its innerHTML, which contains span has been retained.
This answer $('#container').find('*:not(br,a,img)').contents().unwrap() fails to deal with tags with empty content.
A working solution is simple: loop from the most inner element towards outside:
var $elements = $s.find("*").not("a,img,br");
for (var i = $elements.length - 1; i >= 0; i--) {
var e = $elements[i];
$(e).replaceWith(e.innerHTML);
}
The working copy is: http://jsfiddle.net/btvuut55/3/
with jQuery you can find all the elements you don't want - then use unwrap to strip the tags
$('#container').find('*:not(br,a,img)').contents().unwrap()
FIDDLE
I think it would be better to extract to good tags. It is easy to match a few tags than to remove the rest of the element and all html possibilities. Try something like this, I tested it and it works fine:
// the following regex matches the good tags with attrinutes an inner content
var ptt = new RegExp("<(?:img|a|br){1}.*/?>(?:(?:.|\n)*</(?:img|a|br){1}>)?", "g");
var input = "<this string would contain the html input to clean>";
var result = "";
var match = ptt.exec(input);
while (match) {
result += match;
match = ptt.exec(input);
}
// result will contain the clean HTML with only the good tags
console.log(result);

Javascript - Get a formated preview of files read with FileReader()?

I tryed to implement a drag file functionality. I need a preview with the text of the file, in this case an HTML file. But when I insert the result of FileReader into the DOM, the preview loses all the line breaks and text-indent.
I tryed using jQuery .split() and inserting a <br/>, but still the text loses all the indentation.
for(var i = 0; i <files.length; i++){
reader = new FileReader();
reader.onload = function(evt){
var r = evt.target.result;
r = r.replace(/>/g,'> >');
r = r.replace(/</g,'<');
r = r.split('>')
var text="";
for(var i =0; i<r.length; i++){
r[i] = $.trim(r[i]);
text += r[i]+'<br/>';
}
$('.drop-area').html(text);
}
reader.readAsText(files[i]);
}
Try dragging an HTML file here http://jsfiddle.net/gVZRU/2/
Is possible to solve that? Is there any other approach I can take to have this functionality?
You simply need to add white-space: pre-wrap; to the style of the display box.
Multiple successive whitespace in an HTML source is always collapsed into a single output whitespace in the rendered content. The white-space CSS properties allows you to change this behavior, and the pre value says to treat whitespace as the <pre> tag does (i.e., show all whitespace in the rendered result). pre-wrap is just like pre, but allows wrapping of the text.
Use the .text method to insert text. No need for escaping manually. To fix the display issue, don't try to insert <br> tags after every closing tag but just use appropriate CSS: white-space: pre-wrap;.

turn <br> into line breaks using javascript (not php)

I need to extract the text from a div with paragraphs and spans and other things and put it into a textarea. I need to load just the text, not the HTML.
For that, I can use:
loadtext = $('#mydiv').text();
However, I DO need to retain the line breaks.
For that, I'm doing:
loadtext = $('#mydiv').text().replace(/<br>/gm, '\r\n');
But it doesn't seem to be working, because when I load that text into a textarea, it's all flat with no line breaks. Am I doing something wrong?
$('#mydiv').text() has already been stripped of all HTML, including<br> elements, so this will not work. You need to modify the HTML of the #mydiv element and replace all <br/> elements, then retrieve the text.
$('#mydiv').find('br').each(function(){
$(this).after("\n")
.remove();
});
var loadtext = $("#mydiv").text();
An alternate solution is to use an intermediate element that's never added to the document.
var html = $('#mydiv').html(); // e.g. '<p>line 1</p><br><br><p>line 2</p>'
var text = $('<div>').html(html.replace(/<br\/?>/g, '\n')).text();
/* text =
"line 1
line 2"
*/
$('#mytextarea').text(text);
This supports <br> (HTML) and <br/>(XHTML).

Categories