how to get the <a>under the <p> - javascript

I'm trying to get the a tag under the specific p tag.
I have tried this but is not working. I am trying to change the CSS style of the link part to red color and came with a red dot line when hovering the line will become solid.
var font_8 = document.getElementsByClassName('font_8');var elements = font_8.getElementsByTagName('a');
html:
<p class="font_7" style="font-size:16px">text text text text<br>
<span style="text-decoration:underline">link link link</span>(text)</p>
<p class="font_8" style="font-size:16px">text text text text<br>
<span style="text-decoration:underline">link link link</span>(text)</p>
js:
<script>
const styles = {
textDecoration: 'none',
color: 'red',
borderBottom: '2px dotted currentColor',
}
function getElements() {
var font_8 = document.getElementsByClassName('font_8');var elements = font_8.getElementsByTagName('a');
var len = elements.length;
for (let i = 0; i < len; i++) {
Object.keys(styles).forEach((key)=>{
elements[i].style[key]=styles[key]
})
}
for (let i = 0; i < len; i++){
elements[i].addEventListener('mouseover', function() {
elements[i].style.borderBottom= '2px solid currentColor';
})
elements[i].addEventListener('mouseout', function() {
Object.keys(styles).forEach((key)=>{
elements[i].style[key]=styles[key]
})
})
}
}
getElements()
</script>

Using JavaScript just to learn, this is my solution with a query selector:
const styles = {
textDecoration: 'none',
color: 'red',
borderBottom: '2px dotted currentColor',
}
const normalStyle = 'dotted'
const hoverStyle = 'solid'
function applyStylesAndHover() {
// querySelectorAll allows you to basically use a CSS selector in your JS
const elements = document.querySelectorAll('.font_8 a');
elements.forEach((element) => {
Object.keys(styles).forEach((key) => {
element.style[key] = styles[key]
})
element.addEventListener('mouseover', function() {
element.style.borderBottomStyle = normalStyle;
})
element.addEventListener('mouseout', function() {
element.style.borderBottomStyle = hoverStyle;
})
})
}
applyStylesAndHover()
<p class="font_7" style="font-size:16px">
text text text text
<br>
<span style="text-decoration:underline">
link
</span>(text)
</p>
<p class="font_8" style="font-size:16px">
text text text text
<br>
<span>
link
</span>(text)
</p>
Although To style the <a> on hover you do not need JavaScript.
CSS is perfect for this:
.font_8 a { /* An <a> inside of an element with the class of font_8 */
color: red;
text-decoration: none;
border-bottom: 2px solid red;
}
.font_8 a:hover { /* An <a> that is being hovered inside of an element with the class of font_8 */
border-bottom-style: dotted;
}
<p class="font_7" style="font-size:16px">
text text text text
<br>
<span style="text-decoration:underline">
link
</span>(text)
</p>
<p class="font_8" style="font-size:16px">
text text text text
<br>
<span>
link
</span>(text)
</p>

One problem i found here is you are tring to get <a> using font_8.getElementsByTagName('a'); which will not work. u will need to assign id to the a tag and get it by using
var element = document..getElementsById('myAncor');
and To move it inside p tag u will need to append the element to font_8 using .appenChild().
edit:
sry i misunderstood ur question.
to do this with JS use
var element= font_8[0].children[1].children[0];
element.addEventListener(
// your core
)
or
var elements= document.querySelectorAll('.font_8 a');
//Your code
elements[i].addEventListener(
// your core
)

Related

How to replace nested span to div element in JQuery?

I'm trying to check whether the given htmlData has nested(parent,child not siblings) span elements with attribute name data-fact or not.
if it does then replace it with span to div with class='inline-span' pass all the attributes with it.
else just return the htmlData
var htmlData = `<p style="font: 10pt Times New Roman, Times, Serif; margin: 0pt 0;" xvid="f5ea22ec52553bc61525766b631e126f">
<span xvid="2b80c95cd4b851345ba4c3fe6937d30b" conceptid="619959bc062c677faebd7a6f" xbrlid="rr:ProspectusDate" class="manual-map" data-fact="619959c0062c677faebd7b55">
<span xvid="ca5635a4e4de332d7dc3036a68e57009" class="wrapped manual-map" data-fact="619959c0062c677faebd7b57">November 1, 2021</span>
</span>
</p>
`
replaceTags(htmlData)
function replaceTags (htmlData) {
var $elm = $(htmlData).find("span[data-fact]");
var $nestedElm = $elm.children().length > 1;
if($nestedElm){
htmlData = htmlData.replace(/<span/g, '<div class="inline-span" ');
htmlData = htmlData.replace(/<\/span>/g, '<\/div>');
}else{
return htmlData;
}
},
The output htmlData i want is something like this
<p style="font: 10pt Times New Roman, Times, Serif; margin: 0pt 0;" xvid="f5ea22ec52553bc61525766b631e126f">
<div class='inline-span' xvid="2b80c95cd4b851345ba4c3fe6937d30b" conceptid="619959bc062c677faebd7a6f" xbrlid="rr:ProspectusDate" class="manual-map" data-fact="619959c0062c677faebd7b55">
<div class='inline-span' xvid="ca5635a4e4de332d7dc3036a68e57009" class="wrapped manual-map" data-fact="619959c0062c677faebd7b57">November 1, 2021</div>
</div>
</p>
Here i'm not able to find is the span element is nested or not and then the conversion of how can i pass the class='inline-span' with all the previous attributes to the div.
PS: answer i want is in JQuery
It is typically a bad idea to do string replacement to change HTML. You should instead use the tools of jquery to manipulate the DOM. Which is safer and less error prone.
const replaceTags = ($tagToReplace) => {
// create a copy of the htmlData
const $cloned = $tagToReplace.clone();
// While there are still more span's in the p
while ($cloned.find('span[data-fact]').length > 0) {
// get the next span to replace with a div
const $span = $($cloned.find('span[data-fact]')[0]);
// create the new div
const $newDiv = $('<div>');
// copy the span's html into the div
$newDiv.html($span.html());
// For each attribute in the span ...
$.each($span[0].attributes, (_ , attr) => {
// ... set the new div to have the span's attribute.
$newDiv.attr(attr.name, attr.value);
});
// new div needs 'inline-span' property.
$newDiv.addClass('inline-span');
// finally replace the span with the new div
$span.replaceWith($newDiv);
}
return $cloned;
}
// select tag to replace
const $tagToReplace = $('p');
// get the new cloned tag
const $newHtmlData = replaceTags($tagToReplace);
// add the cloned to the body
$('body').append($newHtmlData);
// print that new elements html
console.log($newHtmlData[0].outerHTML);
p {
padding: 8px;
border: 1px dashed green;
}
span[data-fact] {
border: 1px solid red;
padding: 3px;
}
div[data-fact] {
border: 1px solid blue;
padding: 3px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p style="font: 10pt Times New Roman, Times, Serif; margin: 0pt 0;" xvid="f5ea22ec52553bc61525766b631e126f">
<span xvid="2b80c95cd4b851345ba4c3fe6937d30b" conceptid="619959bc062c677faebd7a6f" xbrlid="rr:ProspectusDate" class="manual-map" data-fact="619959c0062c677faebd7b55">
<span xvid="ca5635a4e4de332d7dc3036a68e57009" class="wrapped manual-map" data-fact="619959c0062c677faebd7b57">November 1, 2021</span>
</span>
</p>
NOTE: it is invalid HTML to have div tag inside p so one should probably replace the p tag too.
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script> var htmlData = `<p style="font: 10pt Times New Roman, Times, Serif; margin: 0pt 0;" xvid="f5ea22ec52553bc61525766b631e126f">
<span xvid="2b80c95cd4b851345ba4c3fe6937d30b" conceptid="619959bc062c677faebd7a6f" xbrlid="rr:ProspectusDate" class="manual-map" data-fact="619959c0062c677faebd7b55">
<span xvid="ca5635a4e4de332d7dc3036a68e57009" class="wrapped manual-map" data-fact="619959c0062c677faebd7b57">November 1, 2021</span>
</span>
</p>
`
console.log(replaceTags(htmlData, "span span[data-fact]","div"));
//a very handy function from Matt Basta to rplace tag names cannot be done on the fly without such functions
function replaceElement(source, newType) {
// Create the document fragment
const frag = document.createDocumentFragment();
// Fill it with what's in the source element
while (source.firstChild) {
frag.appendChild(source.firstChild);
}
// Create the new element
const newElem = document.createElement(newType);
// Empty the document fragment into it
newElem.appendChild(frag);
// Replace the source element with the new element on the page
source.parentNode.replaceChild(newElem, source);
}
//we now use our function as warper on above function.
function replaceTags (htmlData,whatToChange,withWhat) {
var fragment = document.createElement('just');
fragment.innerHTML=htmlData;
var found = fragment.querySelector(whatToChange);
if(found){
replaceElement(fragment.querySelector(whatToChange), withWhat);}
return fragment.innerHTML;
}
</script>
Getting as to what you want here is more logical solution that mixes bunch of search logics to do the job. Not perfect but its close
I did some changes related to Find in HTML element and in replace jquery code here is a working demo hope it will be helpful for you.
you can direcatly replace all html with like
htmlData = htmlData.replace($factElem[0].outerHTML, 'div html');
using $factElem[0].outerHTML you can find element containing [data-fact] html.
yes you can check only using data-fact and replace it with div there is no span needed
I updated Code Please check now.
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
$(document).ready(function () {
$("button").click(function () {
var htmlData = '<p style="font: 10pt Times New Roman, Times, Serif; margin: 0pt 0;" xvid="f5ea22ec52553bc61525766b631e126f"><span xvid="2b80c95cd4b851345ba4c3fe6937d30b" conceptid="619959bc062c677faebd7a6f" xbrlid="rr:ProspectusDate" class="manual-map" data-fact="619959c0062c677faebd7b55"><span xvid="ca5635a4e4de332d7dc3036a68e57009" class="wrapped manual-map" data-fact="619959c0062c677faebd7b57">November 1, 2021</span></span></p>'
replaceTags(htmlData);
});
});
function replaceTags(htmlData) {
var $factElem = $(htmlData).find('[data-fact]');
if ($factElem) {
htmlData = htmlData.replace($factElem[0].outerHTML, '<div class="inline-span" xvid="2b80c95cd4b851345ba4c3fe6937d30b" conceptid="619959bc062c677faebd7a6f" xbrlid="rr:ProspectusDate" class="manual-map" data-fact="619959c0062c677faebd7b55"><div class="inline-span" xvid="ca5635a4e4de332d7dc3036a68e57009" class="wrapped manual-map" data-fact="619959c0062c677faebd7b57">November 1, 2021</div></div>');
$("#append").empty().append(htmlData);
alert(htmlData);
} else {
$("#append").empty().append(htmlData);
}
}
</script>
</head>
<body>
<div id="append"></div>
<button>Click me to Replace!!</button>
</body>
</html>

How can i get HTML Formated text in this popup box Like: <li> _ _ _ _</li> <br> <h1> _ _ _ _</h1>etc

at this time When text select, The popup show all selected text as in simple format, Like one paragraph. But i want that, the popup should use complete html tag when showing selected text. Like
<li> _ _ _ _</li> <br> <h1> _ _ _ _</h1>etc...
see my code:
const container = document.querySelector('.storypara');
const popupContainer = document.querySelector('.popupContainer');
container.addEventListener('mouseup', (e) => {
const selectedText = window.getSelection().toString();
if (selectedText) {
showPopup(selectedText);
}
});
popupContainer.addEventListener('click', (event) => {
if (event.target.matches('.popupContainer')) {
popupContainer.classList.remove('show');
}
});
function showPopup(selectedText) {
// set the selected text as html inside popup element
document.querySelector('.popup').innerHTML = selectedText;
popupContainer.classList.add('show');
}
body {
margin: 0;
}
.popupContainer {
position: fixed;
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.7);
top: 0;
display: none;
align-items: center;
justify-content: center;
color: red;
}
.show {
display: flex;
}
.popup {
background: #fff;
padding: 10px;
border-radius: 3px;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
width: 80%;
}
<div class="storypara">
<p><strong>A Bold example Line</strong><br>
Here are some examples of paragraphs. Here are some examples of paragraphs. Here are some examples of paragraphs. Here are some examples of paragraphs. Here are some examples of paragraphs. </p>
<h2>An Unordered HTML List</h2>
<ul>
<li>Coffee</li>
<li>Tea</li>
<li>Milk</li>
</ul>
<h2>An Ordered HTML List</h2>
<ol>
<li>Coffee</li>
<li>Tea</li>
<li>Milk</li>
</ol>
<p>Here are some examples of paragraphs. Here are some examples of paragraphs. Here are some examples of paragraphs. Here are some examples of paragraphs. Here are some examples of paragraphs. Here are some examples of paragraphs. </p>
</div>
<div class="popupContainer">
<div class="popup"></div>
</div>
How can i get this plz help me. my main purpose
at this time When text select, The popup show all selected text as in simple format, Like one paragraph. But i want that, the popup should use complete html tag when showing selected text. Like
<li> _ _ _ _</li> <br> <h1> _ _ _ _</h1>etc...
Thanks in advance.
Well, not quite what you want, but a lot closer to what you are asking for. Here it goes:
Update your script to be as follows:
<script>
const container = document.querySelector('.storypara');
const popupContainer = document.querySelector('.popupContainer');
// this method is added
// It gives the text of HTML of selected text :)
function getHTMLOfSelection () {
var range;
if (document.selection && document.selection.createRange) {
range = document.selection.createRange();
return range.htmlText;
}
else if (window.getSelection) {
var selection = window.getSelection();
if (selection.rangeCount > 0) {
range = selection.getRangeAt(0);
var clonedSelection = range.cloneContents();
var div = document.createElement('div');
div.appendChild(clonedSelection);
return div.innerHTML;
}
else {
return '';
}
}
else {
return '';
}
}
container.addEventListener('mouseup', (e) => {
const selectedText = getHTMLOfSelection(); // First get the raw HTML text
if (selectedText) {
//selectedText.split("<").join("&lt"); // Now replacing the < so that browser don't render it
//selectedText.split(">").join("&gt"); // Also replacing the > so that browser don't render it
//console.log(selectedText);
showPopup(selectedText); // using the 'xmp' tags around the text, to show the html as it is
}
});
popupContainer.addEventListener('click', (event) => {
if (event.target.matches('.popupContainer')) {
popupContainer.classList.remove('show');
}
});
function showPopup(selectedText) {
// set the selected text as html inside popup element
document.querySelector('.popup').innerHTML = selectedText;
popupContainer.classList.add('show');
}
</script>
I've added a function, which gives you the HTML of the selected text.
This is all you can do to show the HTML to the user. Hope it helps.
Let me know please if it don't work at your end :) Will be happy to help

HTML - How do I insert a <span></span> tag into each line of a <pre></pre> block without hard coding?

I was just trying to add line numbers at the beginning of source code using CSS.
I realized the effect I wanted, as follows:
However, the HTML code required continual use of <span>...</span> tags:
<pre class="code">
<span>var links = document.getElementsByClassName("link");</span>
<span>for(var i = 0; i < links.length; i++){</span>
<span> links[i].onclick=function(){</span>
<span> alert(i+1);</span>
<span> };</span>
<span>}</span>
</pre>
With the span tags positioned at home/end of lines I can let the line numbers show as expected.
But I think there must be another better solution to prevent me adding all these span tags hard-coded, maybe using Javascript, or jQuery I don't mind but don't know how. Please help.
NOTE:
My problem is not how to display line numbers when the <span> tags are already there. Instead, I wanted to know if the origin HTML code contains NO <span> tags, how can I automatically add them into the suitable places and so I can apply the CSS styles.
This can be achieved by using CSS counters
This does not require any JavaScript (or jQuery) which means no need for each libraries or scripts and was introduced way back in CSS 2.1 so has great browser support across the board.
pre {
background: #eee;
counter-reset: section; /* Reset the counter to 0 for each new pre */
}
pre span:before {
counter-increment: section; /* Increment the section counter*/
content: counter(section); /* Display the counter */
padding: 0 5px;
border-right: 1px solid #777;
margin-right: 5px;
color: #777
}
<pre class="code">
<span>var links = document.getElementsByClassName("link");</span>
<span>for(var i = 0; i < links.length; i++){</span>
<span> links[i].onclick=function(){</span>
<span> alert(i+1);</span>
<span> };</span>
<span>}</span>
</pre>
<pre class="code">
<span>var links = document.getElementsByClassName("link");</span>
<span>for(var i = 0; i < links.length; i++){</span>
<span> links[i].onclick=function(){</span>
<span> alert(i+1);</span>
<span> };</span>
<span>}</span>
</pre>
I have combined #Stewartside answer with what you have actually asked for.
Below you can see a simple plain JavaScript to replace any line in element with code class to be wrapped in span which applies #Stewartside css.
var codeElement = document.getElementsByClassName("code"); //array of code blocks
var formattedCode = codeElement[0].textContent.replace("\r\n", "\n").split("\n");
var codeLength = formattedCode.length;
formattedCode.forEach(function(line, index, array) {
if (codeLength - 1 == index) return;
array[index] = "<span>" + line + "</span>";
});
codeElement[0].innerHTML = formattedCode.join("\n");
$(".code-jquery").each(function(index, codeElement) {
var formattedCode = $(codeElement).html().replace("\r\n", "\n").split("\n");
var codeLength = formattedCode.length;
$(codeElement).text("");
$.each(formattedCode, function(index, line) {
if (codeLength - 1 == index) return;
$(codeElement).append("<span>" + line + "</span>\n")
});
});
pre {
background: #eee;
counter-reset: section; /* Reset the counter to 0 for each new pre */
}
pre span:before {
counter-increment: section; /* Increment the section counter*/
content: counter(section); /* Display the counter */
padding: 0 5px;
border-right: 1px solid #777;
margin-right: 5px;
color: #777
}
pre.code-jquery span {
color: green;
}
<pre class="code">
var links = document.getElementsByClassName("link");
for(var i = 0; i < links.length; i++) {
links[i].onclick = function() {
alert(i+1);
};
}
</pre>
//jQuery version
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<pre class="code-jquery">
var links = document.getElementsByClassName("link");
for(var i = 0; i < links.length; i++) {
links[i].onclick = function() {
alert(i+1);
};
}
</pre>
So you basically need to append a span before each line. Here is the codepen link. I am currently using jQuery's insertBefore() method for it.
See below for the explanation of the code :-
$('.code') will give you the pre tag. Now the jQuery .find() method will give you all the spans inside the pre tag. Now jQuery .each() function is basically a for loop ( in simple terms ) which will loop for all the span tags inside the pre tag.
.insertBefore() function simply inserts whatever there is in the selector to the element mentioned inside the function.
var iCount = 1;
$('.code').find('span').each(function(){
$( "<span>"+iCount+"| </span>" ).insertBefore( this);
iCount++;
});
pre{
background: #eee
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<pre class="code">
<span>var links = document.getElementsByClassName("link");</span>
<span>for(var i = 0; i < links.length; i++){</span>
<span> links[i].onclick=function(){</span>
<span> alert(i+1);</span>
<span> };</span>
<span>}</span>
</pre>

Get all 4-lettered words Regex

To get all 4 lettered words delimited by any I have written the following code:
function select() {
var html = document.getElementById('p').innerHTML;
var fourLettered = html.match(/[^a-zA-Z|^$][a-zA-Z]{4}[^a-zA-Z|^$]/g) || [];
document.getElementById('other').innerHTML = fourLettered.join('<br>');
}
p {
background-color: #eee;
}
.red {
color: red;
}
<p id="p" contenteditable="true">This is <i>a</i> <span class="red">paragraph</span> <b>with</b> lots of markup and-lots-of letters;with?four char</p>
<p id="other"></p>
<button onclick="select()">SELECT</button>
However, I am unable to get the 4 letter words at the start or end of the p tag i.e. This & char in this case.
Also the markup /span> is getting selected.
How can this problem be solved?
Try this:
function select() {
var html = document.getElementById('p').textContent;
var fourLettered = html.match(/\b[a-zA-Z]{4}\b/g) || [];
document.getElementById('other').innerHTML = fourLettered.join('<br>');
}
p {
background-color: #eee;
}
.red {
color: red;
}
<p id="p" contenteditable="true">This is <i>a</i> <span class="red">paragraph</span> <b>with</b> lots of markup and-lots-of letters;with?four char</p>
<p id="other"></p>
<button onclick="select()">SELECT</button>

How to get elements with certain style

So say I have this in my body:
<body>
<h1>Hello world!</h1>
<h2 style="color: Blue;">This is my webpage</h2>
<a style="color: Blue;" onClick="changeElem();">Welcome!</a><br>
<h3>Goodbye</h3>
</body>
I want to create function changeElem() such that it will change the content that is blue to black. So this is the result I want to get after using this function:
<h1>Hello world!</h1>
<h2 style="color: Black;">This is my webpage</h2>
<a style="color: Black;" onClick="changeElem();">Welcome!</a><br>
<h3>Goodbye</h3>
How can this be done?
You're much better off doing this with CSS, not inline styles.
<head>
<style>
/* By default, elements with class="some-class" are blue */
.some-class {
color: blue;
}
/* But if body has the class "updated", they turn black */
body.updated .some-class {
color: black;
}
</style>
<h1>Hello world!</h1>
<h2 class="some-class">This is my webpage</h2>
<a class="some-class" onClick="changeElem();">Welcome!</a><br>
<h3>Goodbye</h3>
</body>
...where changeElem is:
function changeElem() {
document.body.className += " updated";
}
Live Example | Live Source
If you're dead set on using inline styles, which is not a good idea, you can still do it easily enough:
function changeElem() {
var div, colorValue, list, index, element;
// Figure out what this browser returns for `color: Blue`
// (it might be "Blue", "blue", "rgb(0, 0, 255)",
// "rgba(0, 0, 255, 0)", "#0000FF", "#0000ff",
// or possibly others)
div = document.createElement('div');
document.body.appendChild(div);
div.innerHTML = '<span style="color: Blue;"></span>';
colorValue = div.firstChild.style.color;
document.body.removeChild(div);
// Get list of all elements that have any `style` attribute at all
list = document.querySelectorAll('[style]');
// Loop through looking for our target color
for (index = 0; index < list.length; ++index) {
element = list[index];
if (element.style.color === colorValue) {
element.style.color = "black";
}
}
}
Live Example | Live Source
I suggest working with Class Selectors.
<body onLoad="getElem();">
<h1>Hello world!</h1>
<h2 class="blue">This is my webpage</h2>
<a class="blue">Welcome!</a><br>
<h3>Goodbye</h3>
</body>
Then you could easily select all Elements with a common class via document.querySelectorAll():
document.querySelectorAll(".blue")
for all Elements with the class blue (e.g.)
Then you could set the class of each element simply to black.
function getElem(){
var items = document.body.getElementsByTagName("*");
for (var i = items.length; i--;) {
style = window.getComputedStyle(items[i].innerHTML);
color = style.getPropertyValue('color');
if(color =="rgb(0,0,255)"){
items[i].style.color="black";
}
}
}

Categories