Maybe this is a basic question, but I should stress I know very little about these things. Essentially, in my page I have something like:
<h2>Some text there</h2>
<h2>Other text there</h2>
And I would like to make it simply into:
Some text there
Other text here
I mean, essentially, I want to remove the H2 surrounding the text. It'd be super easy to just delete it, but unfortunately I only have indirect access to the code. Is there any way to remove this dynamically using Javascript?
You can loop through all h2 elements and replace each element with a text node of the element's textContent (with document.createTextNode):
document.querySelectorAll('h2').forEach(e => e.parentNode.replaceChild(document.createTextNode(e.textContent), e))
<h2>Some text there</h2>
<br/>
<h2>Other text there</h2>
Eventually, I found this solution, which was perfect for my case, but I'd also want to thank everyone who posted here!
document.addEventListener('DOMContentLoaded', e => {
const h2s = document.querySelectorAll("h2")
h2s[0].outerHTML = h2s[0].innerHTML
h2s[1].outerHTML = h2s[1].innerHTML
})
Related
[EDIT] First of all: I am aware that by DOM manipulation tools you can easily modify DOM structures. (These are available in every browser and even in Node by third party libraries.)
The goal of his question is if someone can come up with a clever idea if this problem can be solved by Regexp in JavaScript without DOM.
Thank you![End of EDIT]
Let's say I have the following HTML snippet as a string:
<p>
<div class="something">
<span>
<div class="else">My precious text.</div>
</span>
</div>
</p>
I wish to get rid of the <div class="something"> tags with RegExp in order to get something like this (indentation does not matter):
<p>
<span>
<div class="else">My precious text.</div>
</span>
</p>
So, my attempt was:
htmlString.replace(/<div class="something">([\s\S]+?)<\/div>/gi, "$1");
But it will match for the closing tag of <div class="else"> of course.
How can I do it properly using just vanilla JS and by not using the DOM manipulation tools of the browser? (i.e. in Node)
Regex isn't the best option for this. You're better off using the querying abilities of JS if it's HTML you're dealing with, here's a quick example of what you could do (oversimplified for explanation purposes):
var htmlString = '<p><div class="something"><span><div class="else">My precious text.</div></span></div></p>';
//Create a DOM element so you can query what you need and manipulate it
var newElement = document.createElement("p");
newElement.innerHTML = htmlString;
//Find what you need to remove
var toRemove = newElement.getElementsByClassName("something")[0];
//Grab what you need to keep
var toKeep = toRemove.firstChild;
//Remove the unwanted element
newElement.removeChild(toRemove);
//Append the old child
newElement.appendChild(toKeep);
//If you really want it back as a string
newElement.outerHTML;
PS: It's not valid to have a div inside a paragraph element, so you're going to get unpredictable results.
I have this HTML code with pre-written message. My goal is to highlight text between [quote] [/quote] in a yellow background once I focus/click on the text area.
<textarea>
This is a test message.
[quote]Wise man said he is wise.[/quote] There could be more quotes too:
[quote]this is second quote [/quote]
He is correct.
</textarea>
Is it possible to do it with pure Javascript? I think it should be something like:
textarea onfocus="function()">
find text between [quote][/quote]
apply yellow background to found text: background Color='#ffc'
....
(and if there is no [quote] [/quote] found then it should do nothing, ie. no warnings).
Since you cannot do that using <textatea> i'd suggest to take a look at
<div contenteditable>
</div>
here's an example:
var area = document.getElementById("area");
var text = area.innerHTML;
area.innerHTML = text.replace(/\[\s*quote.*\](.*)[^[]*\[\s*\/quote.*\]/ig, "<span>$1</span>");
[contenteditable]{
white-space:pre-wrap;
}
[contenteditable] span{
background:#ffc;
}
<div id="area" contenteditable>
This is a test message.
[quote]Wise man said he is wise.[/quote] There could be more quotes too:
[quote]this is second quote [/quote]
He is correct.
</div>
Otherwise, since you cannot treat HTML elements inside a textarea like actual HTML elements in order to highlight them → you should create an in-memory element with the same size (font-size etc) of your textarea, do the above, calculate the positions of the generated span elements, than apply some higlight overlays over the respective positions over your textarea, take care that they "follow-up" if the window resizes... and the story goes...
Here's a jQuery plugin to achieve the above-mentioned:
http://mistic100.github.io/jquery-highlighttextarea/
Currently I'm investigating two approaches: Highlight Text Inside a Textarea, which describes how this plugin is done: https://github.com/lonekorean/highlight-within-textarea
And syntax higlighter for MediaWiki: source, description of approach.
Both of them use additional element behind textarea with the same font and positioning to show background colors. Textarea background is made transparent. Then on edit and scroll you sync contents and scroll between textarea and element behind.
Here is my simplified code for it: https://codepen.io/bunyk-1472854887/full/RLJbNq/
Core logic of the highlighter is like this (some details skipped):
textarea.addEventListener('keyup', textUpdate);
textarea.addEventListener('scroll', scrollUpdate);
function textUpdate() {
var html = html_escape(textarea.value);
enter code here
html = html.replace(/\[quote\](.*?)\[\/quote\]/g, '[quote]<span class="quote">$1</span>[/quote]');
background.innerHTML = html;
}
function scrollUpdate() {
background.scrollTop = textarea.scrollTop;
};
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>");
}
I have the following HTML code:
<p> hello every body, to day is a sunny day</p>
I have use wrap() method to wrap element with <em> tag like the following:
<p> hello every body, to day is <em>a sunny day<em></p>
When I finished my test, I use $("em").contents().unwrap() to unwrap all <em> tag:
I make a loop for all elements in my page
So I found that
-----hello every body, to day is a----
and
-----a sunny day-----
are 2 seperated text nodes,
How can I use wrap() and unwrap(), so my text won't be splited like that?
I'm afraid, you cannot use .wrap() and .unwrap() to do what I think you intend to do. .unwrap() calls replaceWith() in jQuery code which eventually calls .replaceChild(). The replaceChild() method in JS, replaces one DOM child node, with another. The use of .contents() is creating a text node.
This updates the render tree in the browser, which in turn updates the markup you see in a developer tool. The nodes in a render tree are placed on their own lines for the markup... not to be confused with what actually ends up being displayed: since \n is a whitespace character, the text nodes will show in one line on the screen.
If you need the actual text (innerHTML) to not be broken up as textNodes you will have to resort to somewhat drastic, measures:
$(document).ready(function () {
var _childContent = $('em').contents()[0].data,
_childIndex = $('p')[0].innerHTML.indexOf('<em>'),
_parentText;
$('em').remove();
_parentText = $('p')[0].innerHTML;
$('p')[0].innerHTML = _parentText.substr(0, _childIndex) +
_childContent +
_parentText.substr(_childIndex + 1, _parentText.length);
});
Due to having to take such measures, I would agree with grmmph's comment about if it is an issue of styling, then take the addClass() approach.
However, if what you want is to have all the text between the <p> and </p> tags appear on one line instead of being treated as textNodes, then the above works (at least in IE 10 when viewed in the developer tool).
This question goes back a while, so my answer may only be of use to people in the future facing similar problems to the OP (as I was myself).
A neat way to re-combine the unwrapped text nodes is by resetting the innerHtml of the span's parent element using $.html()
HTML
<p>Lorem ipsum <span>dolor sit</span> amet.</p>
JS
function reset () {
var parent = $('span').parent();
$('span').contents().unwrap();
parent.html(function(i, html) {
return html;
});
}
This has been asked so long ago, but because an answer hasn't been marked yet, I'll post an answer. I'm not sure if you wanted those text nodes split or not, but both ways can be done like this (run snippets to see it work):
The vanilla Javascript way (found here):
function unwrapElement () {
var el = document.querySelector('em')
var parent = el.parentNode
while (el.firstChild) parent.insertBefore(el.firstChild, el)
parent.removeChild(el)
}
<p>Hello every body, to day is <em>a sunny day<em></p>
<button onclick="unwrapElement()">Do unwrap</button>
The JQuery way (similar to #StevieP's way):
function unwrapElement() {
$('em').contents().unwrap()
$('em').parent().html((i, html) => html) // if you remove this, then the text will be split
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>Hello every body, to day is <em>a sunny day<em></p>
<button onclick="unwrapElement()">Do unwrap</button>
I am struggling with this one.
How can I wrap a new <div> element around text that does not have any class or ID?
Below is the scenario:
<div class="ContentDiv">.....</div>
Share your knowledge. Be the first to write a review »
I need the new div to wrap around "Share your knowledge. Be the first to write a review »"
I have tried the following:
$(document).ready(function() {
$('.ContentDiv').each(function() {
$(this).add($(this).next()).wrapAll('<div class="NewDiv"></div>');
})
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="ContentDiv">.....</div>
Share your knowledge. Be the first to write a review »
but it is not working because it wraps around the <a> element only and leaves the text below it. I need the rest of the text in there as well.
You need to get the next textnode after .ContentDiv and wrap that:
$('.ContentDiv').each(function() {
$(this).next('a').add(this.nextSibling).wrapAll('<div class="NewDiv"></div>');
});
FIDDLE
Since jQuery does'nt really get textnodes, the native nextSibling should work.
For this you can add a div after $('.ContentDiv') and then add the html to it.
$("<div id='new_div'></div").insertAfter($('.ContentDiv')).html("Share your knowledge. <a href='URL'>Be the first to write a review »</a>");