Why does .text().replace() delete my html? - javascript

FIDDLE UPDATED TO CLASSES
<p id="boohoo"><b id="why did all this disappear">Old Text</b></p>
<p id="boohoo"><h4 id="why did this not work">Old Text</h4></p>
var x = $('#boohoo').text().replace('Old', 'New');
function whyNotBold() {
$('#boohoo').text(x);
}
Why is there a difference between <b> and <h4>? And how can I have the the former <b id="... html not disappear when I insert the text? I would think .text().replace(... would only replace text and not affect the html, but that doesnt seem to be the case here since it's deleting it.

Firt of all you have 2 element with the same id, this is wrong. So your replacement work with the first element only.
The second is text() function strips tags and return only text content of your first node which is: Old Text. When you use text() func to set the text, jquery thinks you want your node <p id="boohoo"> contains text ONLY and it makes this:
<p id="boohoo">New Text</p>
Becase text() func resonsible for text nodes
EDIT:
In your case, you can do what you want like this:
var x = $('b').text().replace('Old', 'New');
function whyNotBold() {
$('b').text(x);
$('h4').text(x);
}
setTimeout(whyNotBold, 300);
Demo

Related

adding tags to text inside a tag

I have the following html document that is auto generated by a third party :
<body>
<pre>
<b>Field1</b> something
<b>Field2</b> something else
...
</pre>
</body>
I want to eventually highlight the text that comes after the text that is bolded under certain circumstances, so I opted to use greasemonkey for that.
Since that text doesn't have any id associated with it, I was thinking of recreating the page and between</b> and <b> I will surround all the text with a mark tag with the ID being the text of the field before it, like so:
<body>
<pre>
<b>Field1</b> <mark id=Field1>something </mark>
<b>Field2</b> <mark id=Field2>something else </mark>
...
</pre>
</body>
Is there an easy way to achieve this without having to recreate the page? e.g inserting elements after each of the tags?
Using plain JS, you can select all the b nodes, loop over it, and in each iteration, replace the sibling text node with new mark node.
Check the working example below:
document.querySelectorAll('b').forEach(b => {
let textNode = b.nextSibling;
let newNode = document.createElement('mark');
newNode.id = b.innerText;
newNode.innerHTML = textNode.textContent;
textNode.replaceWith(newNode);
})
<pre>
<b>Field1</b> something
<b>Field2</b> something else
</pre>
If you don't have any other bold elements on that particular page, and assuming you're using a text editor, you could do a "Replace" (Ctrl + h in Sublime Text and VS) do a search for , in the replace section put back the closing tag and add the additional edit "<"Element, DIV, Class, ID etc>", and click replace all.

Parsing custom text tags using JS or jQuery

I need to search a <div> of a specific class for a simple text system, then store the text.
Basically, there will be a div, and inside the div there might be some text like:
[ALERT](TEXT TO STORE HERE)
I'd like to search a div for the ALERT tag, then store any text inside the () under a variable if it exists, and push an alert to the console if it's found.
However, while I can easily find the first part, [ALERT], I cannot figure out how to find the whole string, or store the containing text. I think it should end up something like:
var alerttext = $("#result").find("[ALERT](.)")=(function()
{
return $(this).html();
}).get();
However, that seems pretty far off, and definitely isn't working.
Edit: The html would resemble:
<div id="bbb" class=""><p id="aaa">text test text
[ALERT](TEXT TO STORE HERE)
More text down here
</p></div>
Try using .text() , String.prototype.replace() with RegExp /(\n.+\()|(\).+\n+\s+$)/g to replace input string up to ( , from ) to end of input , remove newline, space characters at beginning and end of matched string
var arr = [];
$("#bbb").text(function(i, text) {
if (text.indexOf("[ALERT]") >= 0) {
var match = text.replace(/(\n.+\()|(\).+\n+\s+$)/g, "");
arr.push(match);
console.log(arr);
};
return text
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<div id="bbb" class="">
<p id="aaa">text test text [ALERT](TEXT TO STORE HERE) More text down here
</p>
</div>

HTML DOM manipulation : properly replace tag by heading tag

I want to replace some tag-inside-a-paragraph-tag by a heading-tag-enclosed-by-a-paragraph tag. This would result in proper W3C coding, but it seems that jQuery is not able to manipulate the DOM in the right way!? I tried several ways of (jQuery) coding, but i can't get it to work ..
Original code:
<p>some text <span>replace me</span> some more text</p>
Desired code:
<p>some text</p><h2>my heading</h2><p>some more text</p>
Resulting code by jQuery replaceWith():
<p>some text<p></p><h2>my heading</h2><p></p>some more text</p>
Demo: http://jsfiddle.net/foleox/J43rN/4/
In this demo, look at "make H2 custom" : i expect this to work (it's a logical replace statement), but it results in adding two empty p-tags .. The other 2 functions ("make code" and "make H2 pure") are for reference.
Officially the W3C definition states that any heading tag should not be inside a paragraph tag - you can check this by doing a W3C validation. So, why does jQuery add empty paragraph tags? Does anybody know a way to achieve this? Am i mistaken somehow?
You can achieve this with this code. However it's pretty ugly:
$('.replaceMe').each(function() {
var $parent = $(this).parent(),
$h2 = $(this).before('$sep$').wrap('<h2>').parent().insertAfter($parent);
var split = $parent.html().split('$sep$');
$parent.before('<p>' + split[0] + '</p>');
$h2.after('<p>' + split[1] + '</p>');
$parent.remove();
});
http://jsfiddle.net/J43rN/5/
If you read the jQuery docs, you will find:
When the parameter has a single tag (with optional closing tag or
quick-closing) — $("<img />") or $("<img>"), $("<a></a>") or $("<a>")
— jQuery creates the element using the native JavaScript
createElement() function.
So that is exactly what it is doing. And as I said in my comment, you can't change a parent node from a child node, you're altering the DOM here, not HTML code. So you'll need to either use replaceWith on the parent node and replace everything or use something like remove and append to split it up in multiple elements which you append after each other.
Try this:
var temp = "<p>some text <span>replace me</span> some more text</p>";
temp.replace(/(\<span\>replace me\<\/span\>)/gi, '</p><h2>my heading</h2><p>');
This will do a case insensitive replace for multiple occurences as well.
Read more about capturing groups here
Original credit to this question!
Please try this I have updated the http://jsfiddle.net/J43rN/6/ example by the below java script function please check I hope it will work for you
function fnMakeCode() {
$('#myP #replaceMe').html("<code id='replaceMe'>My Code</code>");
}
function fnMakeH2pure() {
$('#myP #replaceMe').html("<h2 id='replaceMe'>My H2 pure</h2>");
}
function fnMakeH2custom() {
$('#replaceMe').html("<p></p>").html("<h2>My H2 custom</h2>");
}

Change background color of arbitrary text with javascript

Is there an easy way to wrap spans around arbitrary text within an html paragraph? For example, given the following original html:
<p>Here is a dandy block of text to color up</p>
<p> WHOAH another paragraph</p>
I'd like to wrap arbitrary portions of the text based on user input. So one set of input might transform this into
<p>Here is a <span style="background:yellow">dandy block</span> of text to color up</p>
<p> WHOAH <span style="background:green">another paragraph</span></p>
While another set of input might create
<p>Here is a<span style="background:yellow">a dandy block</span> of text to color up</p>
<p> WHOAH <span style="background:green">another</span> paragraph</p>
This problem is related to this one and this one, however, the main difference with my goal is that I want the highlights to be permanent, not just temporary selections and I'd also like this to work within p elements rather than textareas.
If it's possible, I imagine it would look something like using jQuery
var innerText = $('p')[p_index].slice(char_start, char_end).text();
$('p')[p_index].slice(char_start, char_end).html(
"<span style=\"background:yellow\">"+
innerText +
"</span>");
This would (in theory) select the p_index paragraph, grab the range between the given indices and replace it with a newly created span which has the original text nested inside of it. This clearly doesn't work since subscripting on the jQuery object does not return another inner jQuery object. Though
$("p").slice(0, 1).html("<span style=\"background: blue\">" +
$("p").slice(0, 1).text() +
"</span>");
Does exactly what I want on a paragraph level, but not on the within text level. I could use this approach to do the replacement by totally writing each paragraph given the character ranges I have, but if there's an easy way, I'd greatly appreciate suggestions.
$("p")[p_index]
gives you the actual DOM element that is that paragraph at p_index, so to get the contents of the paragraph you'd need to use:
$("p")[p_index].innerHTML
// OR
$("p")[p_index].textContent
Using jQuery would be easier though. You wouldn't use the jQuery slice() method to reduce the range to a single element, you'd use the .eq() method. Try something like this:
$('p').eq(p_index).html(function(i,currentText) {
return currentText.substring(0, char_start) +
"<span style=\"background:yellow\">" +
currentText.substring(char_start, char_end) +
"</span>" +
currentText.substring(char_end);
});
When you pass a function to the .html() method, jQuery sets the html to whatever you return from the function. jQuery passes the function the current (inner) html of the element so you can process it. (If you do this on a jQuery object containing more than one element your function is called once for each element so they can be processed individually.)
Demo: http://jsfiddle.net/62HHk/
I've used this plugin in the past with nice results.
Try this:
$('input[type=text]').keyup(function() {
var val = $.trim(this.value);
var text = $('p').text().split(' ')
$.each(text, function(i, v) {
if (v == val) {
text[i] = '<span>'+v+'</span>';
}
})
$('p').html(text.join(' '))
})
Fiddle
This should work. It can easily be turned into a function that takes the word you're looking for as a parameter.
jQuery.textReplace by Ben Alman
$('.text').replaceText( /hello/g, '<span classs="interesting">hello</span>' );

JS - Remove a tag without deleting content

I am wondering if it is possible to remove a tag but leave the content in tact? For example, is it possible to remove the SPAN tag but leave SPAN's content there?
<p>The weather is sure <span>sunny</span> today</p> //original
<p>The weather is sure sunny today</p> //turn it into this
I have tried using this method of using replaceWith(), but it it turned the HTML into
<p>
"The weather is sure "
"sunny"
" today"
</p>
EDIT : After testing all of your answers, I realized that my code is at fault. The reason why I keep getting three split text nodes is due to the insertion of the SPAN tag. I'll create another question to try to fix my problem.
<p>The weather is sure <span>sunny</span> today</p>;
var span=document.getElementsByTagName('span')[0]; // get the span
var pa=span.parentNode;
while(span.firstChild) pa.insertBefore(span.firstChild, span);
pa.removeChild(span);
jQuery has easier ways:
var spans = $('span');
spans.contents().unwrap();
With different selector methods, it is possible to remove deeply nested spans or just direct children spans of an element.
There are several ways to do it. Jquery is the most easy way:
//grab and store inner span html
var content = $('p span').html;
//"Re"set inner p html
$('p').html(content);
Javascript can do the same using element.replace. (I don't remember the regex to do the replace in one stroke, but this is the easy way)
paragraphElement.replace("<span>", "");
paragraphElement.replace("</span>", "");
It's just three text nodes instead of one. It doesn't make a visible difference does it?
If it's a problem, use the DOM normalize method to combine them:
$(...)[0].normalize();
$(function(){
var newLbl=$("p").clone().find("span").remove().end().html();
alert(newLbl);
});​
Example : http://jsfiddle.net/7gWdM/6/
If you're not looking for a jQuery solution, here something that's a little more lightweight and focused on your scenario.
I created a function called getText() and I used it recursively. In short, you can get the child nodes of your p element and retrieve all the text nodes within that p node.
Just about everything in the DOM is a node of some sort. Looking up at the following links I found that text nodes have a numerical nodeType value of 3, and when you identify where your text nodes are, you get their nodeValueand return it to be concatenated to the entire, non-text-node-free value.
https://developer.mozilla.org/en/nodeType
https://developer.mozilla.org/En/DOM/Node.nodeValue
var para = document.getElementById('p1') // get your paragraphe
var texttext = getText(para); // pass the paragraph to the function
para.innerHTML = texttext // set the paragraph with the new text
function getText(pNode) {
if (pNode.nodeType == 3) return pNode.nodeValue;
var pNodes = pNode.childNodes // get the child nodes of the passed element
var nLen = pNodes.length // count how many there are
var text = "";
for (var idx=0; idx < nLen; idx++) { // loop through the child nodes
if (pNodes[idx].nodeType != 3 ) { // if the child not isn't a text node
text += getText(pNodes[idx]); // pass it to the function again and
// concatenate it's value to your text string
} else {
text += pNodes[idx].nodeValue // otherwise concatenate the value of the text
// to the entire text
}
}
return text
}
I haven't tested this for all scenarios, but it will do for what you're doing at the moment. It's a little more complex than a replace string since you're looking for the text node and not hardcoding to remove specific tags.
Good Luck.
If someone is still looking for that, the complete solution that has worked for me is:
Assuming we have:
<p>hello this is the <span class="highlight">text to unwrap</span></p>
the js is:
// get the parent
var parentElem = $(".highlight").parent();
// replacing with the same contents
$(".highlight").replaceWith(
function() {
return $(this).contents();
}
);
// normalize parent to strip extra text nodes
parentElem.each(function(element,index){
$(this)[0].normalize();
});
If it’s the only child span inside the parent, you could do something like this:
HTML:
<p class="parent">The weather is sure <span>sunny</span> today</p>;
JavaScript:
parent = document.querySelector('.parent');
parent.innerHTML = parent.innerText;
So just replace the HTML of the element with its text.
You can remove the span element and keep the HTML content or internal text intact. With jQuery’s unwrap() method.
<html>
<head>
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$("button").click(function(){
$("p").find("span").contents().unwrap();
});
});
</script>
</head>
<body>
<p>The weather is sure <span style="background-color:blue">sunny</span> today</p>
<button type="button">Remove span</button>
</body>
</html>
You can see an example here: How to remove a tag without deleting its content with jQuery

Categories