difference between .textContent and .firstChild.data - javascript

assuming I have a html, with an h2, what's the difference between
document.querySelector('h2').textContent = 'abcdefg';
<h2>
</h2>
and
document.querySelector('h2').firstChild.data = 'abcdefg';
<h2>
</h2>
?
I'm mainly interested in knowing what this .data is, I didn't find the documentation for it

The first one will always work to set the text content of the element in question.
The second will only work if the element's first child is a text node (aka CharacterData).
For example, using .data has no observable change if the first-child is an Element.
document.querySelector('#no-text-children').firstChild.data = 'abcdefg';
document.querySelector('#only-text-children').firstChild.data = 'abcdefg';
<h2 id="no-text-children"><span>this is the span content</span></h2>
<h2 id="only-text-children">this is the h2 content</h2>
Using .textContent does not suffer from any such limitations
document.querySelector('#no-text-children').textContent = 'abcdefg';
document.querySelector('#only-text-children').textContent = 'abcdefg';
<h2 id="no-text-children"><span>this is the span content</span></h2>
<h2 id="only-text-children">this is the h2 content</h2>

Related

Insert a new h3 element before the first paragraph in the body using javascript

I want to insert a new h3 element having my name before the first paragraph in the HTML only by using javascript. I do not want to edit the HTML file or the CSS file for it.
I have tried this code in the javascript file
let h3e = document.createElement("h3");
h3e.textContent("Student Name");
document.body.insertBefore(h3e, document.body.firstChild);
But it is not working
let h3e = document.createElement("h3");
h3e.textContent("Student Name");
document.body.insertBefore(h3e, document.body.firstChild);
<body>
<header>
<h1>Bumblebee</h1>
</header>
<main>
<h2>General description</h2>
<figure><img src="bee1.jpg" />
<figcaption>A common bumblebee extending its tongue towards a Heuchera inflorescence.
</figcaption>
</figure>
<p>Bumblebees vary in o about 40 mm longginger beast".</p>
<h2>Distribution and habitat</h2>
<p>Test data</p>
</body>
To insert after the paragraph you need to call the insertBefore method on the immediate parent Node of the paragraph Node. So its not document you want to call it on but the main element. Note: in your example the main tag isn't closed. If you took away the main Node then you could use document.insertBefore as then document is the immediate parent of the paragraph.
So to do it with your above example, you could do it as shown below. I put in a time delay to show it before and after the element is inserted.
<html>
<body>
<header>
<h1>Bumblebee</h1>
</header>
<main>
<h2>General description</h2>
<figure><img src="https://upload.wikimedia.org/wikipedia/en/thumb/a/a8/Xylocopa_bee1.jpg/300px-Xylocopa_bee1.jpg" />
<figcaption>A common bumblebee extending its tongue towards a Heuchera inflorescence.
</figcaption>
</figure>
<p>Bumblebees vary in o about 40 mm longginger beast".</p>
<h2>Distribution and habitat</h2>
</main>
<p>Test data</p>
</body>
<script>
setTimeout(() => {
const h3e = document.createElement("h3");
h3e.textContent ="Student Name";
const mainElem = document.querySelector('main');
const paragraph = mainElem.querySelector("p");
mainElem.insertBefore(h3e, paragraph);
}, 1000);
</script>
</html>
You may want to look to the other answer wrt best practice for setting the text in the h3 node.
Another way to do it that is perhaps more robust is to call insertBefore on the parent of the paragraph node.
e.g.
paragraph.parentNode.insertBefore(h3e, paragraph);
Just Simply Do like that
let p = document.getElementsByTagName('p')[0]
p.outerHTML = '<h3>Student Name</h3>' + p.outerHTML
Your problem is here
h3e.textContent("Student Name");
// Error msg: "Uncaught TypeError: h3e.textContent is not a function",
Change to
var t = document.createTextNode("Student Name");
h3e.appendChild(t);
Or as #Paul Rooney's comment:
h3e.textContent ="Student Name";
Full code & demo here:
var h3e = document.createElement("H3");
var t = document.createTextNode("Student Name");
h3e.appendChild(t);
document.body.insertBefore(h3e, document.body.firstChild);
<body>
<header>
<h1>Bumblebee</h1>
</header>
<main>
<h2>General description</h2>
<figure><img src="bee1.jpg" />
<figcaption>A common bumblebee extending its tongue towards a Heuchera inflorescence.
</figcaption>
</figure>
<p>Bumblebees vary in o about 40 mm longginger beast".</p>
<h2>Distribution and habitat</h2>
<p>Test data</p>
</body>
Read this thread in more detail: TextNode or textContent?

Javascript: How to wrap selected text along multiple p tags into each content for each tag with span tag

When I select text along multiple p tags, I obtain each content for each tag, which was answered in Javascript: How to divide selected text along multiple p tags into each content for each tag.
For example,
<p>I am (selection start)a boy</p>
<p>You are a girl</p>
<p>We are(selection end) friends</p>
Now, I can obtain three elements, "a boy", "You are a girl", "We are".
Then, how to wrap each element by span tag and change its style? For example,
<p>I am (selection start) <span style ="font-weight:bold">a boy</span></p>
<p><span style ="font-style:italic">You are a girl</span></p>
<p><span style ="font-decoration:underline">We are</span> (selection end) friends</p>
I tried this using jquery wrapinner method, filter, contain and so on, but I could not figure it out.
Thank you for your time.
Try this code :
var elems = document.querySelectorAll('p');
for(var i=0;i<elems.length;i++){
elems[i].innerHTML = elems[i].innerHTML.replace('a boy','<span style="font-weight: bold">a boy</span>');
elems[i].innerHTML = elems[i].innerHTML.replace('You are a girl','<span style="font-weight: bold">You are a girl</span>');
elems[i].innerHTML = elems[i].innerHTML.replace('We are','<span style="font-weight: bold">We are</span>');
}
<p>I am a boy</p>
<p>You are a girl</p>
<p>We are friends</p>
I don't know what's your validation to choose where to add your span, but since you can use Jquery you can get your solution with this code:
$("#p1").html($("#p1").html().replace("a boy", '<span style ="font-weight:bold">$&</span>'));
$("#p2").html($("#p2").html().replace("You are a girl", '<span style ="font-style:italic">$&</span>'));
$("#p3").html($("#p3").html().replace("We are", '<span style ="text-decoration:underline">$&</span>'));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p id="p1">I am (selection start)a boy</p>
<p id="p2">You are a girl</p>
<p id="p3">We are(selection end) friends</p>
Note: Also its not font-decoration:underline its text-decoration:underline
Let's say you have 3 paragraph like below :
<p id="p1">I am (selection start)a boy</p>
<p id="p2">You are a girl</p>
<p id="p3">We are(selection end) friends</p>
Then you can change style and wrap with any html tag like this :
let p1 = document.getElementById("p1").innerHTML;
let p2 = document.getElementById("p2").innerHTML;
let p3 = document.getElementById("p3").innerHTML;
document.getElementById("p1").innerHTML = `<span style='color:blue'>${p1}</span>`
document.getElementById("p2").innerHTML = `<span style='color:green'>${p2}</span>`
document.getElementById("p3").innerHTML = `<span style='color:darkGray'>${p3}</span>`
https://jsfiddle.net/emilvr/5Lonrk0f/4/

How parse DOM to get emails Javascript

I'am building a Chrome extension that parses the entire DOM/HTML and replace any found email(multiple emails) with the following div:
<div class="email_tmp"> found_email <span>SAVE EMAIL</span></div>
EXAMPLE:
<body>
<div>Some Text...</div>
<div>text a#a.com text</div>
<div>Some Text...</div>
<p>More Text</p>
<div><div><span>text b#b.com text</span></div></div>
<span>Last text</span>
</body>
replaced to:
<body>
<div>Some Text...</div>
<div>text <div class="email_tmp"> a#a.com <span>SAVE EMAIL</span></div> text</div>
<div>Some Text...</div>
<p>More Text</p>
<div><div><span>text <div class="email_tmp"> b#b.com <span>SAVE EMAIL</span></div> text</span></div></div>
<span>Last text</span>
</body>
How can I search and replace the found email by the entire div and the string found_email by the email too?
I want to replace only the found email(s) string, nothing more...
I really appreciate any help.
Here is the total solution for what your looking for
HTML
<div id="main">
sdfsdsdfsdfsdf a#a.com sdfsdfsdfsdfsdfsdf
</div>
JavaScript
var page_content = document.getElementById('main').innerHTML;
var found_email = "<div class='email_tmp'> found_email <span>SAVE EMAIL</span></div>";
//gives an array of the emails
var email = page_content.match(/([a-zA-Z0-9._-]+#[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+)/gi);
//replaces the emails to your desired content
var result = page_content.replace(email, found_email);
//replaces the changed HTML back to the 'main' div
document.getElementById('main').innerHTML = result;
Here is the Fiddle
Update:
If you want to replace only the text without adding any class or tags to the content of the HTML, then it gets real complicated to write a vanilla script for the same. In that case I would highly suggest you to use this library which I found to be the perfect solution for your problem.
Its a library called findAndReplaceDOMText which uses inbuilt methods to solve the purpose. You just need to give the find(what to find) and replace(replacing HTML) like so,
findAndReplaceDOMText(document.getElementById('t'), {
find: /([a-zA-Z0-9._-]+#[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+)/gi,
replace: '<div class='email_tmp'> found_email <span>SAVE EMAIL</span></div>'
});
You can obviously revert if you face any problems in implementing this library.
Also this a must read article for you - replacing-text-in-the-dom-solved
Slight update on #NikhilNanjappa 's original answer: my version is less efficient, but it will keep the actual email address and prepend the div and append the span and closing tags, based on the original answer.
var save_email_beg = "<div class='email_tmp'> ";
var save_email_end = " <span>SAVE EMAIL</span></div>";
var i = 0;
for (; i < email.length; i++) {
var new_string = save_email_beg + email[i] + save_email_end;
page_content = page_content.replace(email[i], new_string);
}
document.getElementById('main').innerHTML = page_content;

Javascript split by spaces, but not within html-tags

My first goal is to split a string by spaces, but not the ones within html-tags.
I've tried to rewrite the following, unsuccessfully: Javascript split by spaces but not those in quotes
What would the regex look like in:
arr = fullHtmlString.split(?);
?
My main goal is to shift an IMG-tag by one space at a time.
After that I'll iterate over the array, search for the img-tag, remove it, and add it the next item, and finally join the array.
The code I use at the moment is quite comprehensive and use jQuery extensively to achive the goal.
Input:
<div>
<p><img class=something>Some text.</p>
<p>Some more text.</p>
</div>
Deisred output first time:
<div>
<p>Some<img class=something> text.</p>
<p>Some more text.</p>
</div>
...second time:
<div>
<p>Some text.<img class=something></p>
<p>Some more text.</p>
</div>
...third time:
<div>
<p>Some text.</p>
<p><img class=something>Some more text.</p>
</div>
You should not try to do this with a regular expression, why explained here.
You can use DOM properties and methods though
function run(){
var img = document.querySelector(".something"),
sibling = img,
parent = img.parentNode,
next = parent.nextElementSibling;
//Search for the next textNode
while((sibling = sibling.nextSibling) && sibling.nodeType !=3);
if(sibling) {
//split the text only once,
//so "some more text" becomes ["some","more text"]
var textParts = sibling.textContent.split(/ (.*)?/,2);
//put the first split item before the sibling
parent.insertBefore(document.createTextNode(textParts[0]+" "),sibling);
//replace the sibling with the img element
parent.replaceChild(img,sibling);
//finally if there was more text insert it after the img
textParts[1] && parent.insertBefore(document.createTextNode(textParts[1]),img.nextSibling);
} else if(!sibling && next) {
//no sibling in the current parent,
//so prepend it to the next available element in parent
next.insertBefore(img,next.firstChild);
} else {
clearInterval(timer);
}
}
var timer = setInterval(run,2000);
<div>
<p><img class="something" src="http://placehold.it/10x10">Some text.</p>
<p>Some <span>skip me</span> more text.</p>
</div>

How to wrap a group of HTML tags into a containing tag using javascript?

I've run into a problem that I don't know how to solve.
I need to wrap each grouping of <h2> and <p> tags with a containing <article> tag.
My current HTML looks something like this:
<h2 category="someCategory">
<p>text text text<p>
<h2 category="anotherCategory">
<p>text text text<p>
<p>text text text<p>
I need to use javascript to make it look like this:
<article>
<h2 category="someCategory">
<p>text text text<p>
</article>
<article>
<h2 category="anotherCategory">
<p>text text text<p>
<p>text text text<p>
</article>
Somehow the javascript needs to figure out that each new <h2> tag is the start of a new article element. And then that and the last <p> tag before the next <h2> tag will be end of the article.
(The bigger picture is that I'm parsing a markdown document and need the <article> tags as css hooks for layout.)
I have no idea how to begin solving this problem, so I would be grateful of any help!!
d13
UPDATE: Thank you!! I've tried both answers and they both work perfectly!
This will also remove the old HTML tags.
var articles = [], article, sibling, toDelete = [];
var h2s = document.getElementsByTagName("H2");
for(var i = 0, h2; h2 = h2s[i++];){
article = document.createElement("article");
sibling = h2.nextElementSibling;
article.appendChild(h2.cloneNode(true));
while(sibling && sibling.tagName !== "H2"){
if(sibling.tagName === "P"){
article.appendChild(sibling.cloneNode(true));
toDelete.push(sibling);
}
sibling = sibling.nextElementSibling;
}
articles.push(article);
}
while(toDelete.length > 0){
toDelete[toDelete.length-1].parentNode.removeChild(toDelete[toDelete.length-1]);
toDelete.pop();
}
while(h2s.length > 0){
h2s[0].parentNode.removeChild(h2s[0]);
}
for(i = 0, article; article = articles[i++];){
document.body.appendChild(article);
}

Categories

Resources