Looking for help with a javascript reg ex replacement. What I need, is to replace all instances of
width="100">
With
style="width: 100px;"
But the actual px value is variable which is what is causing issues for me. I know reg expression is the way to go but I dont quite understand it.
This is a similar question but doesn't solve the issue for me:
JavaScript Regex Replace Width Attribute Matching
The reason this is a problem is because of the HTML generated by TinyMce...
Two options:
Using a regular expression
Parsing the HTML and working with the DOM (preferred)
Using a regular expression
The expression is fairly straightforward:
str = str.replace(/\bwidth="(\d+)"/g, 'style="width: $1px"');
The $1 in the replacement string is filled in with the content of the first capture group.
Example:
var str = '<div width="100">Stuff here</div><div width="240">More stuff here</div>';
display("Before: '" + str + "'");
str = str.replace(/\bwidth="(\d+)"/g, 'style="width: $1px"');
display("After: '" + str + "'");
function display(msg) {
document.body.insertAdjacentHTML(
"beforeend",
"<p>" +
String(msg)
.replace(/&/g, "&")
.replace(/</g, "<") +
"</p>"
);
}
But note that that will:
Replace width="nnn" everywhere in the string, even if not inside a start tag
End up adding a second style attribute to a tag that already has one
If that's okay, great; if not, you might want to parse the HTML, process the resulting parsed DOM nodes, and then serialize it again.
Parsing the HTML and working with the DOM
A better option is to parse the HTML and work with the DOM. You've said that the HTML will be for a div, so we don't have to worry about things like standalone table cells, etc.
Here's a simple parsing and updating example:
var str = '<div width="100">Stuff here</div><div width="240">More stuff here</div>';
var div = document.createElement('div');
div.innerHTML = str;
update(div.childNodes);
display("Before: '" + str + "'");
str = div.innerHTML;
display("After: '" + str + "'");
function update(nodes) {
Array.prototype.forEach.call(nodes, function(node) {
var width;
if (node.nodeType === 1) { // An element
width = node.getAttribute("width");
if (width) {
node.removeAttribute("width");
node.style.width = width + "px";
}
update(node.childNodes);
}
});
}
function display(msg) {
document.body.insertAdjacentHTML(
"beforeend",
"<p>" +
String(msg)
.replace(/&/g, "&")
.replace(/</g, "<") +
"</p>"
);
}
My first thought also was to work with the DOM instead of using RegEx. Instead of iterating over all the elements, we could just use querySelector, which supports attribute selectors.
var html = '<img src="//placehold.it/100x100" alt="" style="100px;">'+
'<img src="//placehold.it/120x120" alt="" width="120" style="border: 2px solid steelblue;">'+
'<img src="//placehold.it/140x140" alt="" width="140">',
wrap = document.createElement('div'),
nodes;
wrap.innerHTML = html;
nodes = wrap.querySelectorAll('[width]');
Array.prototype.forEach.call(nodes, function(el) {
var width = el.getAttribute('width');
if(width) {
el.removeAttribute('width');
el.style.width = width+'px';
}
});
Related
I am new to JavaScript and I am currently stuck on an issue. Basically, I using an API to search for anime, get the html image, synopsis, and name and put them in a table. That works fine. What I am trying to do is add an onlick for each name in the table to perform a function using the name of the anime as an argument. I have tried using "\'", the escape character, and it didn't work. Here is my code for each row:
nameAndSynopsis.innerHTML = "<table style='border: 1px solid black'><tr><td style='color:blue' onclick='getEpisodes(\'" + anime_name + "\')'>" + anime_name + "</td></tr><br><br><br><tr><td>" + anime_synopsis + "</td></tr></table>";`
When I run my code, the console says Unexpected end of input and here are the results from the source tab when I use inspect on my web page
`getEpisodes(`
Any help would be greatly appreciated.
If you have to use quotes, here how you will do it:
var functionname = "getEpisodes('" + anime_name + "')";
nameAndSynopsis.innerHTML = '<table style="border: 1px solid black"><tr><td style="color:blue" onclick="' +functionname+ '">' + anime_name + '</td></tr><br><br><br><tr><td>' + anime_synopsis + '</td></tr></table>';
I have added functionname in separate line to simply it. It can be done in single line as well.
<div id="nameAndSynopsis"></div>
<script>
function getEpisodes(something) {
console.log("ok.........");
}
var nameAndSynopsis = document.getElementById("nameAndSynopsis");
var anime_name = "anime_name";
var anime_synopsis = "anime_synopsis";
var functionname = "getEpisodes('" + anime_name + "')";
nameAndSynopsis.innerHTML = '<table style="border: 1px solid black"><tr><td style="color:blue" onclick="' + functionname + '">' + anime_name + '</td></tr><br><br><br><tr><td>' + anime_synopsis + '</td></tr></table>';
</script>
Try using template literals instead of all the quotes like this.
nameAndSynopsis.innerHTML = `<table style='border: 1px solid black'><tr><td style='color:blue' onclick=getEpisodes(${anime_name})> ${anime_name} </td></tr><br><br><br><tr><td>${anime_synopsis}</td></tr></table>`
You are using single-quote around the attribute value onclick=' <-- '
Then you are escaping the single quote, so it comes out like this ..
onclick='getEpisodes('yourAnimeName')'
Which sets your onclick attribute to getEpisodes(
This may not make sense and you may be asking, how does it end up like that, didn't i just ESCAPE those quotes?
Well, yes and no, you escaped them in the current javascript context. But since that is then inserted into the DOM as html, the html parser won't see those single-quotes as being escaped.
Try using double-quotes instead.
onclick='getEpisodes(\""+anime_name+"\")'
or
onclick=\"getEpisodes('"+anime_name+"')\"
Your code is ending with an unkown string there, right at the end
</table>";` <---- remove this last string
It should be ending like this
</table>";
I have this script that gets all the attributes and its values and outputs them on the page. The problem I am having is it's currently working with document.write but I want to put the results inside a p tag. When I try to do that it only shows one attribute and its value. How can I output all the attributes and its values inside the targeted p tag?
My code
var foo = document.getElementById('foo'),
attrs = foo.attributes,
i = attrs.length,
attr;
while (i--)
{
attr = attrs[i];
document.write(attr.name + '="' + attr.value + '"');
/*document.querySelector('p').innerHTML= attr.name + '="' + attr.value + '"'; <-- This method only shows one attribute and its value :(*/
}
<div id="foo" class="bar baz" style="margin-left: 2px; height: 10px;"></div>
<p></p>
You should construct whole string and write to <p> once.
var content = [];
while (i--)
{
attr = attrs[i];
content.push(attr.name + '="' + attr.value + '"');
}
document.querySelector("p").innerHTML = content.join(" ")
You have to build a string inside the while loop and assign that string to innerHTML after the loop.
I have an xml String as:
var txt, parser, xmlDoc;
txt = "<Employees xmlns:xlink=\"http://www.w3.org/1999/xlink\"><Employee>"
+ "<ID xlink:type=\"simple\">1</ID>"
+ "<Name>Employee1</Name>"
+ "<Description>Employee1 Description</Description>"
+ "</Employee>"
+ "<Employee>"
+ "<ID xlink:type=\"simple\">2</ID>"
+ "<Name>Employee2</Name>"
+ "<Description>Employee2 Description</Description>"
+ "</Employee></Employees>";
var htmlString = htmlEntities(txt);
document.getElementById('empDetails').innerHTML = htmlString;
alert("HTML formatted display: \n" + htmlString);
function htmlEntities(str) {
var htmlString = String(str).replace(/&/g, '&').replace(/</g,
'<').replace(/>/g, '>').replace(/"/g, '"');
return htmlString;
}
Where my empDetails is a p tag as:
<p id="empDetails"></p>
now i am able to show xml inside this p tag.
The problem is that i want to show a hyperlink on the id's of the printed xml.
So when the xml is printed in the p tag it should show a hyperlink on the id node. i tried using xlink as you can see but it's of no use.
How to achieve this. Looking forward to your answers. Thanks in advance.
y don't you provide the xlink:href attribute in the ID tag?
I have coded a Javascript bbcode similar to the one I'm using to write this message. It also incorporates a live preview box like the one I see below. The only problem I'm facing at the moment is that some nested bbcode is not parsing.
For example:
[quote]
[quote][/quote]
[/quote]
Is not parsing correctly.
This is my Javascript currently.
function preview() {
var txt = $('#editor').val();
txt = txt.replace(/</g,'<');
txt = txt.replace(/>/g,'>');
txt = txt.replace(/[\r\n]/g,'%lb%');
var find = [
/\[quote\](.*?)\[\/quote\]/gi,
/\[quote author="(.*?)" date="(.*?)"\](.*?)\[\/quote\]/gi,
/\[b\](.*?)\[\/b\]/gi,
/\[i\](.*?)\[\/i\]/gi,
/\[u\](.*?)\[\/u\]/gi,
/\[left\](.*?)\[\/left\]/gi,
/\[center\](.*?)\[\/center\]/gi,
/\[right\](.*?)\[\/right\]/gi,
/\[size=(10|12|24|30)](.*?)\[\/size\]/gi,
/\[font=(.*?)](.*?)\[\/font\]/gi,
/\[color=(.*?)](.*?)\[\/color\]/gi,
/\[url(?:\=?)(.*?)\](.*?)\[\/url\]/gi,
/\[email=(.*?)\](.*?)\[\/email\]/gi,
/\[email\](.*?)\[\/email\]/gi,
/\[img(.*?)\](.*?)\[\/img\]/gi,
/(?:%lb%|\s)*\[code(?:\=?)(?:.*?)\](?:%lb%|\s)*(.*?)(?:%lb%|\s)*\[\/code\](?:%lb%|\s)*/gi,
/\[list(.*?)\](.*?)\[\*\](.*?)(?:%lb%|\s)*(\[\*\].*?\[\/list\]|\[\/list\])/i,
/(?:%lb%|\s)*\[list\](?:%lb%|\s)*(.*?)(?:%lb%|\s)*\[\/list\](?:%lb%|\s)*/gi,
/(?:%lb%|\s)*\[list=(\d)\](?:%lb%|\s)*(.*?)(?:%lb%|\s)*\[\/list\](?:%lb%|\s)*/gi,
/(?:%lb%){3,}/g
];
var replace = [
'<blockquote><div class="quote"><div class="quote_body">$1</div></div></blockquote>',
'<blockquote><div class="quote"><div class="quote_author"><span class="quote_from">Quote from</span> <span class="author">$1</span> on <span class="date">$2</span></div><div class="quote_body">$3</div></div></blockquote>',
'<b>$1<\/b>',
'<i>$1<\/i>',
'<u>$1<\/u>',
'<div class="align_left">$1<\/div>',
'<div class="align_center">$1<\/div>',
'<div class="align_right">$1<\/div>',
'<span style="font-size:$1px;">$2</span>',
'<span style="font-family:$1;">$2</span>',
'<span style="color:$1;">$2</span>',
'$2',
'$2',
'$1',
'<img $1 src="$2" />',
'<pre><code>$1</code></pre>',
'[list$1]$2<li>$3</li>$4',
'<ul>$1</ul>',
'<ol start=$1>$2</ol>',
'%lb%%lb%'
];
// fix [*] so that they only work inside [/list]
for(var i in find)
{
txt = txt.replace(find[i],replace[i]);
if(i == 17) while(txt.match(find[i],replace[i])) txt = txt.replace(find[i],replace[i]);
}
// Fix Smilies
txt = txt.replace(/%lb%/g,'<br />');
txt = txt.replace(/\:\)/g, '<img class="smiley" src="/img/smilies/smile.gif">');
txt = txt.replace(/\:-\)/g, '<img class="smiley" src="/img/smilies/happy.gif">');
txt = txt.replace(/\:D/g, '<img class="smiley" src="/img/smilies/biggrin.gif">');
txt = txt.replace(/\:\(/g, '<img class="smiley" src="/img/smilies/sad.gif">');
txt = txt.replace(/8\)/g, '<img class="smiley" src="/img/smilies/cool.gif">');
txt = txt.replace(/=O/g, '<img class="smiley" src="/img/smilies/surprised.gif">');
txt = txt.replace(/\:-\|\|/g, '<img class="smiley" src="/img/smilies/mad.gif">');
txt = txt.replace(/\:P/g, '<img class="smiley" src="/img/smilies/stongue.gif">');
txt = txt.replace(/\}\-\(/g, '<img class="smiley" src="/img/smilies/confused.gif">');
// Format Dates
txt = txt.replace(/\d{10}/g, function($0) {
var d = new Date($0*1000);
var months = new Array('January','February','March','April','May','June','July','August','September','October','November','December');
return "" + months[d.getMonth()] + " " + d.getDate() + ", " + d.getFullYear() + ", " + (d.getHours()%12) + ":" + d.getMinutes() + " " + (d.getHours()<12 ? 'AM' : 'PM');
});
// Update the preview box
$('.preview').html(txt);
}
This flips most all my bbcode tags. The quote tag is problematic in that it sometimes does not flip nested quote tags or parse the contents of the inner quote tags.
If anyone is able to offer a solution I would be very grateful. Thank you!
Three solutions:
Write a parser. This will produce the best solution but takes a non-trivial amount of effort.
Find a BBCode parsing library. Probably as good as #1 in quality and substantially easier.
Add a negative lookahead to the inside of each tag regex and continuously apply until no match. E.g.:
\[quote\]((?:[^](?!\[quote\]))*?)\[\/quote\]
This will capture the inner quote, then once its replaced, the outer one. Not nearly as clean as the other two but probably the quickest fix.
var text_source="<a href='c:/exam_file.xls' target='_blank'>file downdload</a>";
text_search="file";
text_source.replace(new RegExp(text_search, 'gi'),
"<span style='font-weight:bold'>" +
text.toLowerCase() + "</span>");
The "a tag" link address has also changed:
<span style='font-weight:bold'>file</span> download
But, It should look like this. I have to change the text value in the "a tag".
<span style='font-weight:bold'>file</span> download
I will address what I said in a second, but you can do this without a loop with just pure regex. Below is how I accomplished this:
var text_source = "<a href='c:/bilmem_ne_dosyasi.xls' target='_blank'>Dosya Downdload</a>";
text_search = "dosya";
var patt = new RegExp("(<a .*?>)(" + text_search + ")(.*?</a>)","gi");
var text_source = text_source.replace(patt, function(match, $1, $2, $3) {
return $1 + "<span style='font-weight:bold'>" + $2.toLowerCase() + "</span>" + $3;
});
document.write(text_source);
DEMO
Getting back to what I said earlier, however, html can be a very, very complex language, and although regex can be used to parse it, partially, it should not be used for large quantities of data. Some patterns are too intricate to match against.
To ensure that your RegExp runs only against the content of the elements, you will need to select all of the elements that you want to manipulate and check their contents.
As an example:
var regExp = /dosya/ig;
[].slice.call(document.getElementsByTagName('a'), 0).forEach(function(element) {
if(regExp.test(element.textContent)) {
element.innerHTML = element.textContent.replace(regExp, function(text) {
return '<span style="font-weight: bold">' + text.toLowerCase() + '</span>';
})
}
});
There is also a jQuery pseudo selector :contains that does a similar thing.
Whilst the replies about not using regexes with HTML or XML are on the whole, correct, you could use the following for simple cases where you don't have too many nested tags:
var text_source="<a href='c:/bilmem_ne_dosyasi.xls' target='_blank'>Dosya Downdload</a>";
text_search="(<[^>]*>[^<]*)(dosya)([^<]*<[^>]*>)";
var replaced = text_source.replace(new RegExp(text_search, 'gi'), "$1<span style='font-weight:bold'>$2</span>$3");