How to encode only part of this string and render html - javascript

I have a string myString="<pre class='ql-syntax'><code><html><body>Will this work?</body></html></code></pre>" which needs to be rendered in a webpage such that the content inside the <code> block is encoded so it shows up as is.
$('<div/>').html(htmlString).html() removes the html and body tags and outputs the following:
<pre class="ql-syntax"><code>Will this work?</code></pre>
What I want the output to be is:
<pre class="ql-syntax"><code><html>hello</html></code></pre>
so on the webpage, the entire content which is inside the code block renders.
How do I encode only the part of the myString which is between the <code> block?
I am fetching the myString from the database, so I don't have any control over how I construct the myString. I can manipulate it however I want to make sure the html inside the code block renders as is.

I suggest you want only
<code><html><body>Will this work?</body></html></code>
to be put to a pre. It's better you make a pre placeholder. Than just find it and set innerHtml. For example something like this:
<pre class="ql-syntax" id="code"></pre>
var pre = document.getElementById("code");
var codeLength = '<code>'.length;
var start = htmlString.indexOf('<code>');
var stop = htmlString.indexOf('</code>');
if (start != -1 && stop != -1 && stop > start)
pre.innerHtml = htmlString.substring(start+codeLength, stop-start-codeLength);

You can use String.prototype.match() with RegExp /(<pre?\s.+?>)|(<code>)|[^\1].+(?=<\/code>)/g to match "<pre" followed by space character followed by one or more characters followed by ">" or "<code>" or not previous capture group "<code>" followed by one or more characters followed by "</code>".
Create <div> element and append to document.body, call .shift() on array returned by .match() to get "<pre>", set div .innerHTML to result of .shift(); call .shift() to get "<code>" match, set as .innerHTML of div.firstChild : <pre>, call .shift(), set result as .textContent of div.firstChild.firstChild : <code>.
var str = `<pre class="ql-syntax"><code><html><body>Will this work?</body></html></code></pre>`;
var matches = str.match(/(<pre?\s.+?>)|(<code>)|[^\1].+(?=<\/code>)/g);
var div = document.createElement("div");
document.body.appendChild(div);
var pre = matches.shift();
div.innerHTML = pre;
var code = matches.shift();
div.firstChild.innerHTML = code;
var html = matches.shift();
div.firstChild.firstChild.textContent = html;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
</script>

If I understand your question, you need to HTML-encode the string within and including the <code> tags. See HTML-encoding lost when attribute read from input field
I'm not sure how you're constructing the string in the first place, but the code in the linked post should get you started. Perhaps something like this:
var newstring = "<pre class="ql-syntax">" + htmlEncode("<code><html><body>Will this work?</body></html></code>") + "</pre>";
Does this help?

Related

How to display html tag in string?

There is a requirement that retrieving some msg including HTML tag from the back-end, how to rightly display HTML tag but not original tag character.
msg like below ( displays in quotation marks ) :
"This is a link, for a test."
right display:
"This is a link, for a test."
It seems you want display string as html. You just need to add it as innerHTML. Not innerText or textContent
Wrong Display
let str = `This is a link, for a test.`
document.body.innerText += str;
Right Display
let str = `This is a link, for a test.`
document.body.innerHTML += str;
If you want quotes around string use Template Strings
let str = `"This is a link, for a test."`
document.body.innerHTML += str;
You can render HTML using document.write()
document.write(`This is a link, for a test.`);`
But to append existing HTML string, you need to get the id of the node/tag under which you want to insert your HTML string.
There are two ways by which you can possibly achieve this:
Using DOM -
var tag_id = document.getElementById('tagid');
var newNode = document.createElement('p');
newNode.appendChild(document.createTextNode(`This is a link, for a test.`));
node.appendChild(newNode);
Using innerHTML -
var tag_id = document.getElementById('tagid');
tag_id.innerHTML(`This is a link, for a test.`);
Also You can use jQuery html parser to do that like this:
var html = `This is a link, for a test.`;
html = $.parseHTML( html);
$("#tagId").append(html);
I hope this would help you. Thanks
Escaping -
You should escape any quotes found within your string. Place the \ in front of them to escape.
console.log("This is my string with quotes \" \" ")
You can use innerHTML for this.
Example:
document.getElementById(id).innerHTML = yourTextWithHtml

Why does getting value from data-attribute affect the text

I'm struggling with some syntax, mostly why the data-attribute(HTML5) is affecting the text in the way it is.
Please consider this example which does what is expected
<div id="s"></div>
<script>
var ele = document.getElementById("s");
var txt = "this is it \n and done";
ele.innerText = txt;
</script>
The result is I see 2 lines in HTML due to the \n. This is expected
The task means I need to change the way we work into
<div id="s" data-txt="this is it\nand done"></div>
<script>
var ele = document.getElementById("s");
var txt = ele.getAttribute("data-txt");
ele.innerText = txt;
</script>
Note we're now using the data attribute of data-txt. The issue is this renders the text verbatim, meaning I see 1 line: this is it\nand done
https://jsfiddle.net/he4ydvva/
The fact I can't even use replace (ele.getAttribute("data-txt").replace('\n','blah');) suggests that although I see \n, the computer is reading something different (maybe the charcode value or similar)
Why does this happen and how do I prevent it?
Edit
I have seen How can I insert new line/carriage returns into an element.textContent? but this won't suffice as I need the string to exist within the data-txt and concatenating as "this is " + String.fromCharCode(13) + " is not valid for HTML5
You are confusing HTML with JavaScript.
\n is a JavaScript character. data-* attributes are HTML. For inserting newline in HTML, you should use the HTML entity
(Newline) or 
 (carriage return) or their combination.
HTML doesn't understand \n, \r and so on.
Also note,
<div>This is a line \n Another one</div>
This won't insert newline but the code below will:
<div>This is a line
Another one</div>
Check out the full list of HTML entities
Here's what you should use:
ele = document.getElementById("t");
txt = ele.getAttribute("data-txt").replace(/\\n/g,'<br>');
ele.innerHTML = txt;
Explanation:
The \ char is an escape character and so to specify a new line, you need to use two \\ so that the 1st one escapes the meaning of the second. The second one is then treated as a normal char and is read together with the n as \n.
Further, you must replace that with a <br> because a browser will not respect CRLF chars.
Here is your example on jsfiddle fixed: https://jsfiddle.net/4eurrzgx/
var ele = document.getElementById("s");
var txt = "this is it \n and done";
ele.innerText = txt;
ele = document.getElementById("t");
txt = ele.getAttribute("data-txt").replace(/\\n/,'<br>');
ele.innerHTML = txt;
<div id="s"></div>
<p>
***
</p>
<div id="t" data-txt="this is it\nand done"></div>

Replace with RegExp only outside tags in the string

I have a strings where some html tags could present, like
this is a nice day for bowling <b>bbbb</b>
how can I replace with RegExp all b symbols, for example, with :blablabla: (for example) but ONLY outside html tags?
So in that case the resulting string should become
this is a nice day for :blablabla:owling <b>bbbb</b>
EDIT: I would like to be more specific, based on the answers I have received. So first of all I have just a string, not DOM element, or anything else. The string may or may not contain tags (opening and closing). The main idea is to be able to replace anywhere in the text except inside tags. For example if I have a string like
not feeling well today :/ check out this link http://example.com
the regexp should replace only first :/ with real smiley image, but should not replace second and third, because they are inside (and part of) tag. Here's an example snippet using the regexp from one of the answer.
var s = 'not feeling well today :/ check out this link http://example.com';
var replaced = s.replace(/(?:<[^\/]*?.*?<\/.*?>)|(:\/)/g, "smiley_image_here");
document.querySelector("pre").textContent = replaced;
<pre></pre>
It is strange but the DEMO shows that it captured the correct group, but the same regexp in replace function seem not to be working.
The regex itself to replace all bs with :blablabla: is not that hard:
.replace(/b/g, ":blablabla:")
It is a bit tricky to get the text nodes where we need to perform search and replace.
Here is a DOM-based example:
function replaceTextOutsideTags(input) {
var doc = document.createDocumentFragment();
var wrapper = document.createElement('myelt');
wrapper.innerHTML = input;
doc.appendChild( wrapper );
return textNodesUnder(doc);
}
function textNodesUnder(el){
var n, walk=document.createTreeWalker(el,NodeFilter.SHOW_TEXT,null,false);
while(n=walk.nextNode())
{
if (n.parentNode.nodeName.toLowerCase() === 'myelt')
n.nodeValue = n.nodeValue.replace(/:\/(?!\/)/g, "smiley_here");
}
return el.firstChild.innerHTML;
}
var s = 'not feeling well today :/ check out this link http://example.com';
console.log(replaceTextOutsideTags(s));
Here, we only modify the text nodes that are direct children of the custom-created element named myelt.
Result:
not feeling well today smiley_here check out this link http://example.com
var input = "this is a nice day for bowling <b>bbbb</b>";
var result = input.replace(/(^|>)([^<]*)(<|$)/g, function(_,a,b,c){
return a
+ b.replace(/b/g, ':blablabla:')
+ c;
});
document.querySelector("pre").textContent = result;
<pre></pre>
You can do this:
var result = input.replace(/(^|>)([^<]*)(<|$)/g, function(_,a,b,c){
return a
+ b.replace(/b/g, ':blablabla:') // you may do something else here
+ c;
});
Note that in most (no all but most) real complex use cases, it's much more convenient to manipulate a parsed DOM rather than just a string. If you're starting with a HTML page, you might use a library (some, like my one, accept regexes to do so).
I think you can use a regex like this : (Just for a simple data not a nested one)
/<[^\/]*?b.*?<\/.*?>|(b)/ig
[Regex Demo]
If you wanna use a regex I can suggest you use below regex to remove all tags recursively until all tags removed:
/<[^\/][^<]*>[^<]*<\/.*?>/g
then use a replace for finding any b.

regex replace characters within tags

I'm already using a html parser, but I need to create a regex that will select the < and > symbols within the first instance of <code> tags - in this case, the one with the class "html".
<code class="html">
<b>test</b><script>lol</script>
<code>test</code> <b> test </b>
<lol>
</lol>
<test>
</code>
So every < or > within the indented area starting from <b> to the start of the last </code> should be replaced, leaving the outer <code> tags alone.
I'm using javascript's .replace method and would like all < and > symbols within the code area to turn into ascii < and >.
I imagine its best to use a look forward/back regex using $1 etc. but can't figure out where to begin, so any help would be much appreciated.
How about something like this? In this example I'm creating a variable and populating the variable with html, just to get things started
var doc = document.createElement( 'div' );
doc.innerHTML = ---your input html here
Here I'm pulling the code tag
var string = doc.getElementsByTagName( 'code' ).innerHTML;
Once you have the string then simply replace the desired brackets with
var string = string .replace(/[<]/, "<)
var string = string .replace(/[>]/, ">)
then just reinsert the replaced value back into your source html
The easy way:
var elem = $('.html');
elem.text(elem.html());
This will not necessarily use literally < for escaping; if you're fine with a different escape, it's much simpler than anything else you can do, though.
If you have multiple elements like that, you might need to wrap the second line in an elem.each(); otherwise the html() method will probably just concatenate the content from all elements or something similarly pointless.

javascript dynamic css styling

I'm trying to get all characters after "."(dot) and set some styling to them with JavaScript.
Example: $10.12 . I want to set some styling to numbers "12".
I have this number dynamically created in phtml file inside span.
I tried something like this, but without success:
var aa = document.getElementById('testdiv').innerHTML; // gets my span
var bb = aa.toString().split(".")[1]; // gets all numbers after "."
bb.setAttribute("style","width: 500px;");
Thanks to everyone! You really helped me. I would vote for every answer, but unfortunately I can't vote yet.
Your mistake begins here:
var aa = document.getElementById('testdiv').innerHTML; // gets my span
That's not your span, but its HTML contents. To take care of setting the width, you need something like this instead:
var aa = document.getElementById('testdiv'); // gets my span
aa.style.width = "500px";
You can only apply styling to HTML elements, not text nodes.
Try this instead:
var elem = document.getElementById('testdiv');
var parts = elem.innerHTML.toString().split(".");
parts[1] = "<div style=\"width: 500px\">" + parts[1] + "</div>";
elem.innerHTML = parts.join(".");
I've used because it's immediately apparent that a style has been applied, but if you want the number to appear consistent, as in "$10.12" without the "12" on a new line, you will probably need to apply additional styles or rethink how you're outputting the HTML.
You cannot set style to the textNode, the work around is to create an element to wrap the character after "." by using span. The idea is simple. First split it by "." and check if it has "." inside, if yes, create an element to wrap it and set style. Finally, join it back by "."
var inner = document.getElementById('testdiv').innerHTML;
var arr = inner.toString().split(".");
if(arr.length > 1)
{
arr[1] = '<span style="display: inline-block; width: 500px;">' + arr[1] + '</span>';
}
newContent = arr.join(".");
document.getElementById('testdiv').innerHTML = newContent;
You could do something like this:
document.getElementById('testdiv').innerHTML = document.getElementById('testdiv').innerHTML.replace( /(\d+).(\d+)/, '$1.<span id="end">$2</span>' );
document.getElementById('end').style.fontWeight = 'bold';
jsFiddle example
Your example fails at bb.setAttribute since you're trying to set an attribute on a string instead of a node. What you need to do is essentially rebuild the 10.12 with <span> elements surrounding the text you want to alter, and then you can use other JavaScript methods to modify the styling. The method you were using was almost correct, except the last part won't work because the split() method returns a string, not a node.
You can do this with regexp:
onlyDigitsText = text.replace(/\.([0-9]*)/g, ".<span class='highlighted'>$1</span>");
JsFiddle example
Try
var elem = document.getElementById('testdiv');
elem.innerHTML = elem.innerHTML.replace( /(\d+)\.(\d+)/g, '$1.<span class="decimalPart">$2</span>' );
// (\d+) one or more digits
// \. a dot character. Must be escaped otherwise it means ANY character
// (\d+) one or more digits
// g regex flag to replace all instances, not just one.
Then in your css add styling for the decimalPart class
.decimalPart {
width: 500px;
}
This has the added advantage of separating your styles from your html.
UPDATE
Following your comment to get the character just before the number use
elem.innerHTML.replace( /(\s)([^\s\d]*?)(\d+)\.(\d+)/g, '$1<span class="currencySymbol">$2</span>$3.<span class="decimalPart">$4</span>' );
// (\s) space, tab, carriage return, new line, vertical tab, form feed
// ([\s\d]*?) any set of characters that are not a digit or the above zero or more times
// (\d+) one or more digits
// \. a dot character. Must be escaped otherwise it means ANY character
// (\d+) one or more digits
// g regex flag to replace all instances, not just one.
Please note I have made an allowance for currency symbols that take up more than a single character.

Categories

Resources