If I have two elements :
Element A :
<div id="myID">
<div id="a"></div>
<div id="b"><div id="ba"></div></div>
<div id="c"><span id="ca"></span></div>
</div>
and Element B :
<div id="myID">
<div id="a"></div>
<div id="b"><div id="ba"></div></div>
<div id="c"><span id="ca"></span></div>
<div id="d"></div>
</div>
Is it possible to find out that Element B has more children than Element A, then find where is additional element and create it in Element A?
P.S: In real code new element is loaded with Ajax Request, but I don't want to replace all content with loaded content, I need to add only new content and skip existing one.
P.S.S : In my current code I have Md5 checksum to check if new content is not the same as existing, but if new content have only little changes it replaces all content and this is the problem for me.
A piece of my current code :
window.processResponse = function(data) {
// Note : "data" is Ajax responseText;
if(!data) return false;
var $data = document.createElement("div");
$data.innerHTML = data;
var em = $data.getElementsByTagName("*");
for(var i = 0; i < em.length; i++)
{
var parent = sget(em[i].id); // sget function is : document.getElementById
if(parent)
{
var html = em[i].innerHTML.replace(/(\s)+/gim, "").replace(/(\n|\r\n)+/gim, "");
var id = em[i].id;
savedPages[id] = savedPages[id] || [];
var _md5 = md5(html);
if(savedPages[id][0] == _md5) continue;
savedPages[id] = [_md5, getTime()];
parent.innerHTML = em[i].innerHTML;
}
if(em[i].tagName === "SCRIPT")
{
var code = em[i].innerHTML.replace(/(\s)+/gim, "").replace(/(\n|\r\n)+/gim, "");
var id = em[i].id;
savedPages[id] = savedPages[id] || [];
var _md5 = md5(code);
if(savedPages[id][0] == _md5) continue;
savedPages[id] = [_md5, getTime()];
try{eval(em[i].innerHTML)}catch(ex){log(ex)};
}
}
};
So, you can optimize it but it depends also in which browser are you running this code.
I assumed the follows:
All IDs are unique, and you rely on that. You want to compare basically elements that have the same ID, not the same structure.
As you said, all children have IDs, and you want to compare only children – not nested node
The elements received from the server have only additional children not less. For removing children, you have to add some other code.
Therefore, if you have the same number of children, we assume they're the same (to optimize). If this is not true, then you have to implement the removal of children as well
Said that, I believe that this kind of stuff is more suitable on server side, that should send to the client only the part that are actually modified. That what we do usually – or, if we don't care, replace everything.
var div = document.createElement('div');
div.innerHTML = s;
var root = div.firstChild;
var children = root.children;
var documentRoot = document.getElementById(root.id);
if (documentRoot && documentRoot.children.length < children.length) {
var node = null;
var previousNode = null;
var index = 0;
while ( node = children[index++] ) {
var documentNode = document.getElementById(node.id);
if (!documentNode) {
if (previousNode)
documentRoot.insertBefore(node, previousNode.nextSibling);
else
documentRoot.insertBefore(node, documentRoot.firstChild);
documentNode = node;
}
previousNode = documentNode;
}
previousNode = null;
} else {
// probably append as is somewhere
}
The solution is not so simple. What if the parent, myID, did not exist in sample A but the child nodes were in both samples indicating 3 layers in the DOM that need to be compared and adjusted? How would you compare this:
<div id="papa">
<div id="myID">
<div id="a"></div>
<div id="b">
<div id="ba"></div>
</div>
<div id="c">
<span id="ca"></span>
</div>
</div>
</div>
vs
<div id="papa">
<div id="a"></div>
<div id="b">
<div id="ba"></div>
</div>
<div id="c">
<span id="ca"></span>
</div>
</div>
In this case the comparison becomes more complicated. You will actually need a fully fleshed out XML/HTML language aware diff utility with a merge function. You can play around with Pretty Diff to demonstrate just how complicated this can get, but unfortunately it does not have a merge function so it cannot be a fully automated solution to your problem.
Related
I have a form that has multiple fields all with the same class. These are populated with URL's that follow the same structure. I am trying to extract the same section from each URL. So far var res = x.split('/')[5]; will achieve this but only for the first URL. I can also use var x = document.querySelectorAll(".example") to change all the url's but I cannot find the correct way to combine both of these function. so far my code looks like this:
script>
function myFunction() {
var x = document.querySelectorAll(".example").innerHTML;
var res = x.split('/')[5];
var i;
for (i = 0; i < x.length; i++) {
x[i].innerHTML = res;
}
}
</script>
I have looked around but can't find a solution that fits. Thanks in advance for your help.
So loop over the HTML Collection, this is making assumptions based on code.
// Find all the elements
var elems = document.querySelectorAll(".example")
// loop over the collection
elems.forEach(function (elem) {
// reference the text of the element and split it
var txt = elem.innerHTML.split("/")[5]
// replace the text
elem.innerHTML = txt
})
<div class="example">1/2/3/4/5/a</div>
<div class="example">1/2/3/4/5/b</div>
<div class="example">1/2/3/4/5/c</div>
<div class="example">1/2/3/4/5/d</div>
<div class="example">1/2/3/4/5/e</div>
<div class="example">1/2/3/4/5/f</div>
I'm trying to remove the excessive closing tags in javascript and anything that follows after that.
Here is a possible sample:
<div class="dummy">
<div class="main">
<div></div>
<img src="a.jpg">
<br>
<img src="b.jpg />
<strong>
<span>text</span>
</strong>
</div>
</div>
***excessive tags below***
</div>
</div>
<div class="footer">
text
</div>
</body>
</html>
Any ideas about how to do it efficiently?
The part I want to extract is always a div, but the problem is that it may have as many nested divs, and I'm not sure how to deal with this scenario.
If it can be done in multiple steps or with callbacks is also fine, as long as it works.
Edit
My question is actually easier than it seems.
The sample always starts with the div that I want to extract.
So all I need is to find the matching closing tag, and filter anything that follows.
Don't care about any other tags...
Don't use regex, from my understanding, you want to retain the dummy class div and the footer class div so why not replace the body with that?
E.g.
var dummy = document.getElementsByClassName('dummy')[0];
var footer = document.getElementsByClassName('footer')[0]
var body = document.getElementsByTagName('body')[0];
body.innerHTML = '';
body.appendChild(dummy);
body.appendChild(footer);
https://jsfiddle.net/1kq11ry2/
data='<div class="dummy"><div class="main"><div></div><img src="a.jpg"><br><div></div><img src="b.jpg /><strong><span>text</span> </strong></div><div><div></div></div><div><div></div></div></div>***excessive tags below***</div></div><div class="footer">text</div></body></html>';
var starting_tags = [];
var closing_tags = [];
var startIndex, index=0;
var searchStrLen = 4;
while ((index = data.indexOf('<div', startIndex)) > -1) {
starting_tags.push(index);
startIndex = index + searchStrLen;
}
index,startIndex=0;
searchStrLen = 6;
while ((index = data.indexOf('</div>', startIndex)) > -1) {
closing_tags.push(index);
startIndex = index + searchStrLen;
}
var nest_level=0;
for (var i=0; i<closing_tags.length && nest_level<closing_tags.length && nest_level<=closing_tags.length; ++i) {
for (var j=0+nest_level; j<starting_tags.length; ++j) {
if (starting_tags[j]<closing_tags[nest_level])
nest_level++;
}
}
result = data.substr(startIndex[starting_tags], closing_tags[nest_level-1]+6);
console.log(nest_level);
console.log(starting_tags);
console.log(closing_tags);
console.log(result);
I was able to solve it. The code above calculates the level of div nesting, and then chops it off if it finds excessive closing tags.
https://jsfiddle.net/89j7yakz/2/
I have a text in the following format:
<div id="text">
<div>Hello world</div>
<div>How are you</div>
</div>
User selects the "w" of world:
So I get the selection and can insert the span:
var selection = window.getSelection();
var startNode = $(selection.anchorNode.parentElement);
var endNode = $(selection.focusNode.parentElement);
var startIndex = startNode.index();
var endIndex = endNode.index();
var startOffset = selection.anchorOffset;
var endOffset = selection.focusOffset;
Result:
<div id="test">
<div>Hello <span class="id1">w</span>orld</div>
<div>How are you</div>
</div>
id1.startNode = 0
id1.endNode = 0
id1.startOffset = 6
id1.endOffset = 7
The user user now selects "d Ho" of the text. This is how it should look like:
<div id="test">
<div>Hello <span class="id1">w</span>orl<span class="id2">d</span></div>
<div><span class="id2">Ho</span>w are you</div>
</div>
id2.startNode = 0
id2.endNode = 1
id2.startOffset = 9
id2.endOffset = 2
But using the method from before selection.anchorOffset yields me the index relative to the new created text nodes which are now "Hello ", "w" and "orld" which means I get an index of 3 instead of 10.
I use the following code to get the offset that was created:
var offs = 0;
if(startNode.context.innerHTML.length > startNode.context.innerText.length) {
var n = startNode.context.childNodes;
for (var i = 0; i < n.length; i++) {
if(n[i].textContent === selection.anchorNode.textContent) {
break;
}
else {
offs += n[i].textContent.length;
}
}
}
console.log(offs);
I can now add the offset to the start and end but this kind of breaks when the selection goes over different nodes or contains a selection inside of it. I also have no idea how to generate the spans with those offsets. There are also way to many cases that I have to consider like startNode === endNode or if a selection contains a span fully or partly.
Are there any common approaches or frameworks for stuff like this? I would rather just work with pure text indices instead of html tags inside and let something else handle the proper formatting.
At the risk of self-promotion, my Rangy library has a Class Applier module specifically for this.
I need to use pure Javascript for the first time in a long while, and having gotten used to the comfy mattress of jQuery, all the important stuff is escaping me.
I need to select a bunch of divs on regular expression. So I have stuff like this;
<div id="id_123456_7890123"> .. </div>
<div id="id_123456_1120092"> .. </div>
<div id="id_555222_1200192"> .. </div>
<div id="id_123456_9882311"> .. </div>
And I'd need to create a loop that goes through all the divs with an id that begins with id_123456_. How would I go about doing that?
I used jQuery with the :regex filter plugin before, but looking at it, it doesn't seem like there's much I could salvage in a pure javascript rewrite.
In plain javascript, you could do this generic search which should work in every browser:
var divs = document.getElementsByTagName("div"), item;
for (var i = 0, len = divs.length; i < len; i++) {
item = divs[i];
if (item.id && item.id.indexOf("id_123456_") == 0) {
// item.id starts with id_123456_
}
}
Working example: http://jsfiddle.net/jfriend00/pYSCq/
HTML DOM querySelectorAll() method will work here.
document.querySelectorAll('[id^="id_"]');
Borrowed from StackOverFlow here
This works by recursively traversing the whole DOM.
It's possibly not the most efficient, but should work on every browser.
function find_by_id(el, re, s) {
s = s || [];
if (el.tagName === 'DIV' && re.exec(el.id) !== null) {
s.push(el);
}
var c = el.firstChild;
while (c) {
find_by_id(c, re, s);
c = c.nextSibling;
}
return s;
}
var d = find_by_id(document.body, /^id_123456_/);
See http://jsfiddle.net/alnitak/fgSph/
Here you are: http://jsfiddle.net/howderek/L4z9Z/
HTML:
<div id="nums">
<div id="id_123456_7890123">Hey</div>
<div id="id_123456_1120092">Hello</div>
<div id="id_555222_1200192">Sup</div>
<div id="id_123456_9882311">Boom</div>
</div>
<br/>
<br/>
<div id="result"></div>
Javascript:
divs = document.getElementsByTagName("div");
divsWith123456 = new Array();
for (var i = 0;i < divs.length;i++) {
if (divs[i].id.match("id_123456") != null) {
divsWith123456.push(divs[i]);
document.getElementById("result").innerHTML += "Found: divs[" + i + "] id contains id_123456, its content is \"" + divs[i].innerHTML + "\"<br/><br/>";
}
}
Goal:
If there are any html syntax code or data inside of
<div id="feedEntries"></div>
Then everything should be removed and be contained empty only.
Problem:
What syntax do I need in order to remove every code and data inside of
<div id="feedEntries"></div>
Please remember that i don't want to add any class or id inside of "feedEntries"
<h3>Search</h3>
<div class="content">
<form>
<input type="text" width="15" value="searchword" id="searchTermTextField"><input type="button" name="some_name" value="Sök" id="searchButton">
</form>
<div id="feedEntries">
</div>
</div>
function fetchSearchResults(json) {
var feedEntriesDivElement = document.getElementById('feedEntries');
var ulElement = document.createElement('ul');
if (feedEntriesDivElement.children.length >= 0)
{
// Syntax code to remove the code/data
}
for (var i = 0; i < json.responseData.results.length; i++)
{
var liElement = document.createElement('li');
var personText = document.createTextNode(json.responseData.results[i].titleNoFormatting);
var newlink = document.createElement('a');
newlink.setAttribute('href', json.responseData.results[i].url );
newlink.appendChild(personText);
liElement.appendChild(newlink);
ulElement.appendChild(liElement);
}
feedEntriesDivElement.appendChild(ulElement);
}
Using pure DOM and Javascript (sometimes considered better than altering innerHTML):
if ( feedEntriesDivElement.hasChildNodes() )
{
while ( feedEntriesDivElement.childNodes.length >= 1 )
{
feedEntriesDivElement.removeChild( feedEntriesDivElement.firstChild );
}
}
feedEntriesDivElement.innerHTML = ''; should do the trick.
you can use jquery like this $('#feedEntries').empty()
to remove from javascript please check the post
document.getElementByIf('feedEntries').innerHTML = ''