I have an app that allows user to generate text with HTML code in the following format:
<h2>User generated Dynamic Data 1</h2>
<h3>User generated text 1.1</h3>
<h3>User generated text 1.2</h3>
<h2>User generated Dynamic Data 2</h2>
<h3>User generated text 2.1</h3>
<h3>User generated text 2.2</h3>
<h3>User generated text 2.3</h3>
<h2>User generated Dynamic Data 3</h2>
<h3>User generated text 3.1</h3>
<h3>User generated text 3.2</h3>
This is how it looks like in a browser:
Is there any way to replace what user generated with the one below, using javascript?
<h2>User generated Dynamic Data 1 <button class="something" onclick="bubble_fn_add_headers({output1: 'User generated Dynamic Data 1', output2: 'User generated text 1.1\nUser generated text 1.2'});">Save</button></h2>
<h3>User generated text 1.1</h3>
<h3>User generated text 1.2</h3>
<h2>User generated Dynamic Data 2 <button class="something" onclick="bubble_fn_add_headers({output1: 'User generated Dynamic Data 2', output2: 'User generated text 2.1\nUser generated text 2.2\nUser generated text 2.3'});">Save</button></h2>
<h3>User generated text 2.1</h3>
<h3>User generated text 2.2</h3>
<h3>User generated text 2.3</h3>
<h2>User generated Dynamic Data 3 <button class="something" onclick="bubble_fn_add_headers({output1: 'User generated Dynamic Data 3', output2: 'User generated text 3.1\nUser generated text 2.2'});">Save</button></h2>
<h3>User generated text 3.1</h3>
<h3>User generated text 3.2</h3>
This is how the above would look like in a browser:
The situation is very trickey because:
<h2></h2>
and <h3></h3>
tags are user generated.<h2>
Texts followed by any or even zero number of <h3>
texts.Can you guys suggest any work around this using javascript?
Thanks
I would have tried
s.replace('<h2>', '<h2>User generated Dynamic Data 1 <button class="something" onclick="bubble_fn_add_headers({output1: 'User generated Dynamic Data 1', output2: 'User generated text 1.1\nUser generated text 1.2'});">Save</button></h2>')
But it just isn't possible because the texts are dynamically generated and are unique each time.
Don't use regex or replace to change HTML.
Just use DOM access
Here is the minimum safe way to create the object and embed it in a button
const nextUntil = (element, selectors, filter = "*") => {
const siblings = [element];
let next = element.nextElementSibling;
while (next && !next.matches(selectors)) {
if (next.matches(filter))
siblings.push(next);
next = next.nextElementSibling;
}
return siblings;
};
document.querySelectorAll('h2').forEach(header => {
const subs = nextUntil(header,'h2','h3')
//console.log(subs)
const object = {output1: subs[0].textContent,output2: subs.slice(1).map(ele => ele.textContent).join('\n')}
header.innerHTML = `${header.textContent}
<button class="something"
onclick='bubble_fn_add_headers(${JSON.stringify(object)})'>Save</button>`;
})
const bubble_fn_add_headers = obj => console.log(obj);
/* I recommend the following instead of inline onclick
document.body.addEventListener('click', (e) => {
const tgt = e.target.closest('button.something');
if (!tgt) return;
bubble_fn_add_headers(tgt.dataset.content)
})
using this code for the data-attribute
data-content='${
JSON.stringify({
"output1": subs[0].textContent,
"output2": subs.slice(1).map(ele => ele.textContent).join('\n')
})}'
*/
<h2>User generated Dynamic Data 1</h2>
<h3>User generated text 1.1</h3>
<h3>User generated text 1.2</h3>
<h2>User generated Dynamic Data 2</h2>
<h3>User generated text 2.1</h3>
<h3>User generated text 2.2</h3>
<h3>User generated text 2.3</h3>
<h2>User generated Dynamic Data 3</h2>
<h3>User generated text 3.1</h3>
<h3>User generated text 3.2</h3>
Here is what you asked for. It is VERY BRITTLE and will blow up the first time a user enters a quote or a double quote
const nextUntil = (element, selectors, filter = "*") => {
const siblings = [element];
let next = element.nextElementSibling;
while (next && !next.matches(selectors)) {
if (next.matches(filter))
siblings.push(next);
next = next.nextElementSibling;
}
return siblings;
};
document.querySelectorAll('h2').forEach(header => {
const subs = nextUntil(header,'h2','h3')
//console.log(subs)
const string = `{output1: '${subs[0].textContent}, output2: '${subs.slice(1).map(ele => ele.textContent).join('\\n')}`
header.innerHTML = `${header.textContent}
<button class="something"
onclick="bubble_fn_add_headers('${string}')">Save</button>`;
})
const bubble_fn_add_headers = obj => console.log(obj);
/* I recommend the following instead of inline onclick
document.body.addEventListener('click', (e) => {
const tgt = e.target.closest('button.something');
if (!tgt) return;
bubble_fn_add_headers(tgt.dataset.content)
})
using this code for the data-attribute
data-content='${
JSON.stringify({
"output1": subs[0].textContent,
"output2": subs.slice(1).map(ele => ele.textContent).join('\n')
})}'
*/
<h2>User generated Dynamic Data 1</h2>
<h3>User generated text 1.1</h3>
<h3>User generated text 1.2</h3>
<h2>User generated Dynamic Data 2</h2>
<h3>User generated text 2.1</h3>
<h3>User generated text 2.2</h3>
<h3>User generated text 2.3</h3>
<h2>User generated Dynamic Data 3</h2>
<h3>User generated text 3.1</h3>
<h3>User generated text 3.2</h3>