dom wrapping a substring in textnode with a new span node - javascript

Suppose, I have this paragraph:
<p>this is a paragraph containing link to an image at http://lol/atme.png :)</p>
I want to replace http://lol/atme.png with an image element.
How do I do that?
Its like removing the text, but adding a image element in place of that text.
Help will be greatly appreciated.

There are two parts to this. The first is the extraction of the URLs from the text, which is a tricky issue I'm not that interested in. I would do some research before using this in production. For now, I'll use an extremely simple illustrative regex.
The second part is the code for doing the replacement within text nodes. I answered a related question the other day with some reusable code and now I'm getting to reuse it. Yay.
function createImage(matchedTextNode) {
var el = document.createElement("img");
el.src = matchedTextNode.data;
el.width = 30;
el.height = 20;
return el;
}
function surroundInElement(el, regex, surrounderCreateFunc) {
var child = el.lastChild;
while (child) {
if (child.nodeType == 1) {
surroundInElement(child, regex, createImage);
} else if (child.nodeType == 3) {
surroundMatchingText(child, regex, surrounderCreateFunc);
}
child = child.previousSibling;
}
}
function surroundMatchingText(textNode, regex, surrounderCreateFunc) {
var parent = textNode.parentNode;
var result, surroundingNode, matchedTextNode, matchLength, matchedText;
while ( textNode && (result = regex.exec(textNode.data)) ) {
matchedTextNode = textNode.splitText(result.index);
matchedText = result[0];
matchLength = matchedText.length;
textNode = (matchedTextNode.length > matchLength) ?
matchedTextNode.splitText(matchLength) : null;
surroundingNode = surrounderCreateFunc(matchedTextNode.cloneNode(true));
parent.insertBefore(surroundingNode, matchedTextNode);
parent.removeChild(matchedTextNode);
}
}
var urlRegex = /http(s?):\/\/($|[^\s]+)/;
function replaceImageUrls(el) {
surroundInElement(el, urlRegex, createImage);
}
<div id="s">One
http://www.google.co.uk/images/logos/ps_logo2.png
two
http://www.google.co.uk/images/logos/ps_logo2.png three</div>
<input type="button" onclick="replaceImageUrls(document.getElementById('s'))" value="replace">

i might misunderstand your question.
From what i understand, could use a div as a placeholder
//HTML
<p>
<div id="holder"><a>link to image</a></div></p>
//js
var h = document.getElementById("holder");
if(h)h.innerHTML = "<img.....>" //the image tag

Related

highlight the .replace() word in javascript

function handleTextNode(textNode) {
if(textNode.nodeName !== '#text'
|| textNode.parentNode.nodeName === 'SCRIPT'
|| textNode.parentNode.nodeName === 'STYLE'
) {
//Don't do anything except on text nodes, which are not children
// of or .
return;
}
var find = ["build", "add", "Fast"];
var replace = ["Develope", "add", "Fast"];
let origText = textNode.textContent;
let newHtml = origText.replace(new RegExp("(" + find.map(function(i){return i.replace(/[.?*+^$[\]\\(){}|-]/g, "\\$&")}).join("|") + ")", "g"),function(s){ return replace[ find.indexOf(s)]});
if( newHtml !== origText) {
let newSpan = document.createElement('span');
newSpan.innerHTML = newHtml;
textNode.parentNode.replaceChild(newSpan,textNode);
}
// <span title="Dyslexia is a learning disorder that involves difficulty reading due to problems identifying speech sounds. " style="background-color: yellow"></span>
}
let textNodes = [];
//Create a NodeIterator to get the text nodes in the body of the document
let nodeIter = document.createNodeIterator(document.body,NodeFilter.SHOW_TEXT);
let currentNode;
//Add the text nodes found to the list of text nodes to process.
while(currentNode = nodeIter.nextNode()) {
textNodes.push(currentNode);
}
//Process each text node
textNodes.forEach(function(el){
handleTextNode(el);
});
i want to make the replaced word highlighted. this code will run only for web pages. like i am building a adblocker with a functionality that help dyslexia Student. At the moment it only replace words correctly. can any body help?

Document evaluate doesn't work on 2 "line" string tag [duplicate]

Suppose I have a sentence in the webpage DOM that when I examine it, consists of 3 text nodes followed by perhaps some element like BOLD or ITALIC. I want to merge the text nodes into one text node, since having adjacent text nodes is meaningless - there is no reason to have them. Is there a way to merge them easily?
Thanks
It seems that Node.normalize() is doing exactly what you want.
You can refer to: Node.normalize()
Maybe this will help you:
var parentNode = document.getElementById('pelements');
var textNode = document.createElement('p');
while (parentNode.firstChild) {
textNode.textContent += parentNode.firstChild.textContent;
parentNode.removeChild(parentNode.firstChild);
}
parentNode.appendChild(textNode);
<div id="pelements">
<p>A</p>
<p>B</p>
<p>C</p>
</div>
It is possible, but you need to specify the parent element. It should be possible to traverse the whole DOM and every node, but if you can avoid that, it would be better.
nodes = document.body.childNodes;
nodesToDelete = [];
function combineTextNodes(node, prevText) {
if (node.nextSibling && node.nextSibling.nodeType == 3) {
nodesToDelete.push(node.nextSibling);
return combineTextNodes(node.nextSibling, prevText + node.nodeValue);
} else {
return prevText + node.nodeValue;
}
}
for (i = 0; i < nodes.length; i++) {
if (nodes[i].nodeType == 3) {
nodes[i].nodeValue = combineTextNodes(nodes[i], '');
}
}
for (i = 0; i < nodesToDelete.length; i++) {
console.log(nodesToDelete[i]);
nodesToDelete[i].remove();
}

Get text from HTML with appropriate whitespace

It is easy to extract the text from HTML using the jQuery .text() method...
$("<p>This <b>That</b> Other</p>").text() == "This That Other"
But if there is no whitespace between the words/elements, then text becomes concatenated...
$("<p>This <b>That</b><br/>Other</p>").text() == "This ThatOther"
Desired: "This That Other"
$("<div><h1>Title</h1><p>Text</p></div>").text() == "TitleText"
Desired: "Title Text"
Is there any way to get all the text from the HTML (either using .text() or other methods) which would mean that the above examples would come out as desired?
You can traverse the DOM tree looking for a node with a nodeType of 3 (text node). When you find one, add it to an array. If you find a non-text node, you can pass it back into the function to keep looking.
function innerText(element) {
function getTextLoop(element) {
const texts = [];
Array.from(element.childNodes).forEach(node => {
if (node.nodeType === 3) {
texts.push(node.textContent.trim());
} else {
texts.push(...getTextLoop(node));
}
});
return texts;
}
return getTextLoop(element).join(' ');
}
/* EXAMPLES */
const div = document.createElement('div');
div.innerHTML = `<p>This <b>That</b><br/>Other</p>`;
console.log(innerText(div));
const div2 = document.createElement('div');
div2.innerHTML = `<div><h1>Title</h1><p>Text</p></div>`;
console.log(innerText(div2));
If you are just worried about br tags, you can replace them with a text node.
var elem = document.querySelector("#text")
var clone = elem.cloneNode(true)
clone.querySelectorAll("br").forEach( function (br) {
var space = document.createTextNode(' ')
br.replaceWith(space)
})
var cleanedText = clone.textContent.trim().replace(/\s+/,' ');
console.log(cleanedText)
<div id="text">
<p>This <b>That</br>Other</p>
</div>

Split SPAN when Inserting HTML Inside of it

I have a setup where I have a large amount of text that is formatted HTML (containing headings and paragraphs)–all inside of a contenteditable div. I've setup a function to insert a custom html entity: <newnote> into the editable div upon clicking a button. This works great except that when inserting the note inside of a span I need to split the span in two and place the <newnote> in between them.
I've looked at lots of functions around the web for inserting text into a DIV, and since it is a requirement that I be inserting HTML it seems like document.createTextNode() is my only choice.
So here is what I've setup thus far, it checks if the parent is a SPAN and then places different content based on that if statement.
function insertNodeAtRange() {
var newRange = rangy.getSelection().getRangeAt(0);
var parentElement = newRange.commonAncestorContainer;
if (parentElement.nodeType == 3) {
parentElement = parentElement.parentNode;
}
var el = document.createElement('newnote');
el.className = "bold";
if (parentElement.tagName == 'SPAN') {
el.appendChild(document.createTextNode(" </span>Test<span> "));
} else {
el.appendChild(document.createTextNode(" Test "));
}
newRange.insertNode(el);
}
Here is what I have sofar
Thanks in advance for any help...
The main problem with your code is that you were trying to make/modify html by creating a text node. Text nodes do not get parsed as dom.
This should work for you:
JSFiddle
function insertNodeAtRange() {
var newRange = rangy.getSelection().getRangeAt(0);
var parentElement = newRange.commonAncestorContainer;
if (parentElement.nodeType == 3) {
parentElement = parentElement.parentNode;
}
var el = document.createElement('newnote');
el.className = "bold";
el.appendChild(document.createTextNode(" Test "));
newRange.insertNode(el);
if (parentElement.tagName == 'SPAN') {
var $newnote = $(el);
var $span1 = $("<span>");
var $span2 = $("<span>");
var left = true;
$parentElement = $(parentElement);
$parentElement.contents().each(function (i, node) {
if (node.isSameNode(el)) {
left = false;
} else if (left) {
$span1.append(node);
} else {
$span2.append(node);
}
});
$parentElement.replaceWith($newnote);
$span1.insertBefore($newnote);
$span2.insertAfter($newnote);
}
}
I just went ahead and inserted the newnote element right away, then got the stuff before that and put it into span1, got the stuff after it and put it into span2, replaced the existing span with newnote and positioned the new spans around newnote.

CreateElement with id?

I'm trying to modify this code to also give this div item an ID, however I have not found anything on google, and idName does not work. I read something about append, however it seems pretty complicated for a task that seems pretty simple, so is there an alternative? Thanks :)
g=document.createElement('div'); g.className='tclose'; g.v=0;
You should use the .setAttribute() method:
g = document.createElement('div');
g.setAttribute("id", "Div1");
You can use g.id = 'desiredId' from your example to set the id of the element you've created.
var g = document.createElement('div');
g.id = 'someId';
You can use Element.setAttribute
Examples:
g.setAttribute("id","yourId")
g.setAttribute("class","tclose")
Here's my function for doing this better:
function createElement(element, attribute, inner) {
if (typeof(element) === "undefined") {
return false;
}
if (typeof(inner) === "undefined") {
inner = "";
}
var el = document.createElement(element);
if (typeof(attribute) === 'object') {
for (var key in attribute) {
el.setAttribute(key, attribute[key]);
}
}
if (!Array.isArray(inner)) {
inner = [inner];
}
for (var k = 0; k < inner.length; k++) {
if (inner[k].tagName) {
el.appendChild(inner[k]);
} else {
el.appendChild(document.createTextNode(inner[k]));
}
}
return el;
}
Example 1:
createElement("div");
will return this:
<div></div>
Example 2:
createElement("a",{"href":"http://google.com","style":"color:#FFF;background:#333;"},"google");`
will return this:
google
Example 3:
var google = createElement("a",{"href":"http://google.com"},"google"),
youtube = createElement("a",{"href":"http://youtube.com"},"youtube"),
facebook = createElement("a",{"href":"http://facebook.com"},"facebook"),
links_conteiner = createElement("div",{"id":"links"},[google,youtube,facebook]);
will return this:
<div id="links">
google
youtube
facebook
</div>
You can create new elements and set attribute(s) and append child(s)
createElement("tag",{attr:val,attr:val},[element1,"some text",element2,element3,"or some text again :)"]);
There is no limit for attr or child element(s)
Why not do this with jQuery?
var newDiv= $('<div/>', { id: 'foo', class: 'tclose'})
var element = document.createElement('tagname');
element.className= "classname";
element.id= "id";
try this you want.
that is simple, just to make a new element with an id :
var myCreatedElement = document.createElement("div");
var myContainer = document.getElementById("container");
//setAttribute() is used to create attributes or change it:
myCreatedElement.setAttribute("id","myId");
//here you add the element you created using appendChild()
myContainer.appendChild(myCreatedElement);
that is all
I'm not sure if you are trying to set an ID so you can style it in CSS but if that's the case what you can also try:
var g = document.createElement('div');
g.className= "g";
and that will name your div so you can target it.
window.addEventListener('DOMContentLoaded', (event) => {
var g = document.createElement('div');
g.setAttribute("id", "google_translate_elementMobile");
document.querySelector('Selector will here').appendChild(g);
});

Categories