How to use insertBefore to add a new element? - javascript

I'm trying to add text to a tag but I keep getting an error
NOT_FOUND_ERR: DOM Exception 8
Error: An attempt was made to reference a Node in a context where it does not exist.
Here's the javascript:
var getexp = document.getElementsByTagName("td")[219];
few lines of code here...
var fsptag = document.createElement('text');
fsptag.innerHTML = append1 +fspRound +append2 +ratioRound;
var fsptext = fsptag.innerHTML;
fsptag.appendChild(fsptext);
getexp.insertBefore(fsptag,getexp.childNodes[10]);
I'm new to this (only a few days). From what I understand getexp.childNodes[10] should be a child node of getexp. And it is a child node.
Any help here would be appreciated. Thanks.
EDIT: HTML
<td colspan=2> »
<b>Combat level: 20</b> (311855484) <font style='font-size:8px;color:#696156'>+13144516</font>
<BR><BR> »
<b>Troops ready:</b> 100%
<BR> »
<b>Mana:</b> 40 / 40<BR> »
<b>Location:</b> <a href=map.php?cx=50&cy=50>Empire Capital</a>
<BR><BR><BR><BR><BR>
<center><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,0,0" width="460" height="54" id="showarmy" align="middle">
The HTML looks something like this. It's from here (http://www.lordswm.com/pl_info.php?id=2255) in the source about line 204.
Edit:
var append1 = "<br><br> » <b>Total FSP: </b>";
var append2 = "<br> » <b>Ratio: </b>";
var fsptag = document.createElement('text');
fsptag.innerHTML = append1 +fspRound +append2 +ratioRound; //fspRound & ratioRound are numbers
Then when I use this: getexp.appendChild(fsptag); the appended text(html?) is created at the end i.e. after the <object> (last line in html code). I want it to appear in between the 5 <br> tags (line 8 of html code).
Sorry for delaying, I was trying to figure it out myself.

createElement(tag_name) creates a HTML element defined by tag_name. Afaik, <text> can appear only inside of a <svg>. Is your purpose to create a custom HTML tag? If so, you need to use some other name for it.
appendChild() takes an element as an argument, not a string. Also when an element once is appended, it's moved from it's original position, i.e. the value of the variable used in the appendChild's argument becomes null. This means, that if you want to insert a new element twice, you'll have to recreate it before inserting again.
In modern browsers the childNodes collection contains also white-spaces and new-lines between tags, so you maybe need to re-calculate the index for insertBefore().
EDIT
After you edited your post, it's more understandable. I've stored a simplified fiddle for you. It maybe close what you need?
The basic code in the fiddle is like this:
var getexp = document.getElementsByTagName("td")[219];
var fsptag = document.createElement('div');
fsptag.innerHTML = append1 + fspRound + append2 + ratioRound;
getexp.insertBefore(fsptag, getexp.childNodes[10]);

Related

How to remove content within the &lt and &gt javascript

I have a content that contains a string of elements along with images. ex:
var str= <p><img src=\"v\">fwefwefw</img></p><p><br></p><p><br></p>
the text that is within the &lt and &gt is a dirty tag and I would like to remove it along with the content that is within it. the tag is generated dynamically and hence could be any tag i.e <div>, <a>, <h1> etc....
the expected output : <p></p><p><br></p><p><br></p>
however with this code, im only able to remove the tags and not the content inside it.
str.replaceAll(/<.*?>/g, "");
it renders like this which is not what im looking for:
<p>fwefwefw</p><p><br></p><p><br></p><p><br></p>
how can I possibly remove the & tags along with the content so that I get rid of dirty tags and text inside it?
fiddle: https://jsfiddle.net/3rozjn8m/
thanks
A safe way is to use a DOM parser, visiting each text node, where then each text can be cleaned separately. This way you are certain the DOM structure is not altered; only the texts:
let str= "<p><img src=\"v\">fwefwefw</img></p><p><br></p><p><br></p>";
let doc = new DOMParser().parseFromString(str, "text/html");
let walk = doc.createTreeWalker(doc.body, 4, null, false);
let node = walk.nextNode();
while (node) {
node.nodeValue = node.nodeValue.replace(/<.*>/gs, "");
node = walk.nextNode();
}
let clean = doc.body.innerHTML;
console.log(clean);
This will also work when you have more than one <p> element that has such content.
Remove the question mark.
var str= "<p><img src=\"v\">fwefwefw</img></p><p><br></p><p><br></p>";
console.log(str.replaceAll(/<.*>/g, ""));

Get caret [start, end] position in HTML source code for an element that was clicked

This is quite a challenging problem. I haven't seen it solved anywhere on Stack Overflow. So I decided to post it.
0 ----17----+ +---30---
| | | +----47
| | | |
<div>ABC<b>B Elem<i>Italic</i>ent</b> DEF</div>
| |
+---8--- ---37--+
Action: Let's say Element <i> tag is clicked.
Problem: Create a function that returns coordinates [17,30]
Note: The coordinates are start and end caret position, represented as 0-based index, in original HTML source code, encompassing only the element that was clicked. May assume normalized HTML nodes as in id = "" becomes id="". (But extra credit, if it doesn't.)
Example 2: If <b> tag was clicked. The script should return [8, 37] because it is the start/end caret position encompassing the B tag.
Example 3: If ABC text or DEF text was clicked, return value is [0,47]
Walk the parent chain until you hit whatever tag you consider to be a container (<div> in your case, apparently).
Use the parent's childs to locate the particular child you're coming from, in case you have two or more identical childs, like in from <i>two</i> to <i>two</i> to <i>two</i> <i>two</i>.
That should give you the child offset within the parent. You can then cumulate the offsets until you hit the div tag or whatever other container element.
Ending position is just this offset plus the clicked element length.
And after two days of solving this, I am posting my own solution.
I tried to parse the DOM and count characters manually, at first. But that was more complicated than it had to be.
Credit: Thanks to kuroi neko, who suggested the end caret position is just start position + length of the HTML encompassing the clicked tag.
Note: I am manually removing <tbody> tags, before calculating caret values. This is because, even original HTML does not contain them, during normalization process (which takes place during innerHTML or outerHTML call,) they are auto-inserted. It's a personal preference, if you're building a text editor that needs this functionality -- to leave them alone and update original HTML.
On the other hand, if you prefer the purist approach, and want to consider the original HTML intact, as it was written by the author of said HTML, then you may want to remove <tbody> manually. This also assumes that you take responsibility for taking care of all other cases, similar to these. Whatever they might be. (Not included in the solution below.)
Solution: Considering textarea (HTML source editor) and #preview are two separate elements representing the same HTML.
$(document).ready(function() {
// Normalize source code
var normalized_html = document.getElementById("preview").innerHTML;
// Remove all TBODY tags (they are auto-inserted, even if not present in original HTML)
normalized_html = normalized_html.replace(/<tbody>/g, '');
$("#textarea").html(normalized_html);
$("#preview").on("click", function(event) {
// Get clicked tag HTML
var tag = event.target.outerHTML;
// Get original HTML before split character is inserted
var orig_html = document.getElementById("preview").innerHTML;//.replace(/<preview>/g, '').replace(/<\/preview>/g, '');
// Insert unique separator just before the tag that was clicked, to mark beginning
$(event.target).before("[*-*]");
// Get preview source code
var html = document.getElementById("preview").innerHTML;
// Remove line breaks
html = html.replace(/\r|\n/g, '');
// Remove tags that were auto-inserted by native normalization process that did not exist in original HTML.
html = html.replace(/<tbody>/g, '');
var before_split = html;
// Split HTML at the tag that was clicked
html = html.split("[*-*]")[0];
// Restore preview to original HTML
$("#preview")[0].innerHTML = orig_html;
// Get start and end of caret in source code
var caret_start = html.length;
var caret_end = caret_start + tag.length;
console.log("caret start = " + caret_start + " end = " + caret_end);
});
});
You achieve that by simply using Descop library.
// Get the source html code of target document
var html = yourFunctionToGetHTML();
// Get the target document itself
var dom = yourFunctionToGetDocument();
// Get the element you want to found in source code
var element = document.getElementById("target-element");
// Create an instance of Descop
var descop = new Descop();
// Connect document
descop.connectDocument(dom);
// Connect source code
descop.connectSource(html);
// Get element position in source code
var position = descop.getElementPosition(element);
// eg. position => { start: 320, end: 480 }

Get full (and original) text of an HTML element

Edit: It looks like we identified the solution to this problem via the comments -- which is achieved by getting value of the .outerHTML property. However, it still appears that at least Firefox and Chrome "normalize" original source code when outerHTML is used. For example, outerHTML of
<div id = "a"> <!-- string is 14 characters long //-->
still returns
<div id="a"> <!-- string is 12 characters long //-->
Apparently, the problem would be considered solved if the formatting of the resulting string would match that of the original HTML source code. Ah! Why must outerHTML adjust the original value?
--- Having said this: ---
I'm looking for a solution to get full text of a clicked HTML tag.
Starting point examples (note intentional, legal but mangled formatting):
<div id = "a" style ="color: blue ;">text</div>
// Returns: div
var doc = document.getElementById("id").tagName;
// Returns: array of attribute name/value pair (without = or ")
var attrs = document.getElementById("id").attributes;
How would we go about generating the following text string, when element #a is clicked:
<div id = "a" style= "color: blue ;">
I seem to have not found a solution for this as of yet.
What's this for?
Ultimately, the goal is to determine the length in characters of the arbitrary contents of a tag. Assuming it can be edited in any way that produces acceptable HTML output. For example, the two cases below should return:
<div id=a style="color:blue"> // 28
<div id = "a" style= "color: blue ;"> // 36
Counting is the easy part. It's getting the actual string of that tag, just as it appears in the source code, that is the problem.
Have you tried this?
document.getElementById('a').outerHTML
But this doesn't work in every browser i guess
Use outerHTML to get the full tag and then strip out everything after the open tag.
var openTag = document.getElementById("a").outerHTML.split(">")[0] + ">";
This seems to do what you want:
http://jsfiddle.net/abalter/c3eqnLrc/
html:
<div id="a" class="find-my-length" style="color:blue">First One</div>
<div id="a " class="find-my-length" style= "color: blue ; " > Second One </div >
JavaScript:
$('.find-my-length').on('click', function () {
var htmlString = $(this).prop('outerHTML');
alert(htmlString + " has " + htmlString.length + " characters.");
});
Note: The one thing that doesn't get counted is spaces between attributes. Spaces within attributes are counted.
From: Get selected element's outer HTML
What about: prop('outerHTML')?
var outerHTML_text = $('#item-to-be-selected').prop('outerHTML');
And to set:
$('#item-to-be-selected').prop('outerHTML', outerHTML_text);

Remove content of <p>-tags from string

My apologies if the question has been asked before, but so far my stackoverflow search didn't bring me quite the answer i needed.
At undetermined intervals my JavaScript is receiving a string containing HTML.
An simplistic example:
<p class='commentator'>Person A</p> Comment of Person A <br/> <p class='commentator'> Person B </p> Comment of person B
When some conditions are met then all the <p> tags and their content should be removed from the string. I know how to remove the <p> tags using the following code:
stringComments= stringComments.replace(/<\/?p[^>]*>/g, "");
How can i modify that regex to include the content of the <p> tags? (regex= .*?)
My expected output should be as follows:
Comment of Person A <br/> Comment of person B
Note: those referring to jQuery's remove(). That won't work, first of because its not part of DOM yet & secondly the changes must me limited to this string.
Use jQuery - don't try to parse HTML with regex, it'll give you no end of trouble. There are lots of ways to do it, but here's one way:
var s = "<p class='commentator'>Person A</p> Comment of Person A <br/> <p class='commentator'> Person B </p> Comment of person B";
var elem = $("<div>" + s + "</div>");
var p = elem.find("p");
p.remove();
console.log(elem[0].innerHTML);
Logs:
Comment of Person A <br> Comment of person B
http://jsfiddle.net/a565cowm/
You don't need to add something to the DOM for jQuery to work on it. jQuery can work with disconnected fragments of HTML.
To be safer, you might even want to use a selector to target the class rather than the <p> tag. That way, if it changes to some other tag, or <p> tags get added to the content you do want, you won't accidentally end up removing the wrong part.
var p = elem.find(".commentator");
Edit: For completeness, it should be noted that this isn't a trick limited to jQuery. You can do the same thing in vanilla JS (browser incompatibilities not withstanding):
var div = document.createElement("div");
div.innerHTML = s;
var p = div.getElementsByTagName("p"); // or getElementsByClassName if you prefer
while(p.length > 0) {
div.removeChild(p[0]);
}
console.log(div.innerHTML);
http://jsfiddle.net/a565cowm/1/

Find + replace content of an element without losing events

I have a function that reads the content of an element, replaces a word with a link and then rewrites the content back into the element. Obviously this means that all events that were previously set are lost.
Does anyone know of a function/method that could find and replace the content of an element without losing the events?
Edit: Without using a library
Here is my current code that does not destroy the events but turns <, for example, into <, so I can not append HTML. This is the closest I have got:
element.appendChild(document.createTextNode(content));
My original code worked but got rid of the events:
element.innerHTML += content;
By using jQuery you could do it with the text() method
var str = $('#element-id').text();
str = yourReplaceFunction(str);
$('#element-id').text(str);
Edit:
Another option would the innerHTML property. It's not very elegant but works nevertheless.
var strElem = document.getElementById('element-id');
var str = strElem.innerHTML;
str = yourReplaceFunction(str);
strElem.innerHTML = str;
Edit2:
Yet another option would be to wrap the text you want to replace inside of a separate tag, for example <span>.
<div id="container">
<a id="link-with-events">Link</a>
<span id="replaceable">The Text Gets Replaced</span>
<a id="more-links-with-events">Another Link</a>
</div>
Then you'd simply access and replace the contents of the span tag, leaving the surrounding elements untouched.
Assuming the tag contains just text (and not additional tags):
element.firstChild.nodeValue=content;
See https://jsfiddle.net/Abeeee/ubj6hte4/

Categories