Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Merge direct HTML siblings into one in jQuery

I need to merge direct html siblings into just one in page code including text nodes.

<div>some text 
<b>some text</b> som
e text <b>text</b><b> more text</b> some te
xt</div>

This is actualy output after editing the code using rangy and jQuery and i need to clear it after the editing so it will look like this:

<div>some text <b>some text</b> some text <b>text more text</b> some text</div>

I would like to use jQuery to do this. I am aware of functions unwrap() and wrapAll() but i cant combine them effectively. Thanks for any clue or help!

like image 375
Walaszka Avatar asked Feb 13 '14 16:02

Walaszka


3 Answers

You need to iterate over child nodes one by one; comparing nodes with previous one and combine if necessary. It can be as complicated as you want; but here is a start:

$("div").each(function (i) {
    $(this).find("*").each(function () {
        var that = this.previousSibling;
        if (that && that.nodeType === Node.ELEMENT_NODE && that.tagName === this.tagName) {
            var node = document.createElement(this.tagName);
            while (that.firstChild) {
                node.appendChild(that.firstChild);
            }
            while (this.firstChild) {
                node.appendChild(this.firstChild);
            }
            this.parentNode.insertBefore(node, this.nextSibling);
            that.parentNode.removeChild(that);
            this.parentNode.removeChild(this);
        }
    });
});

Demo here

like image 102
Salman A Avatar answered Sep 21 '22 16:09

Salman A


If i understood your question correctly, you wanted to combine elements that are next to each other of the same type.

var $div = $("#mydiv");
console.log($div.html());

$div.contents().each(function(){
    if (this.nodeType != 1) return;
    while (this.nextSibling && this.nextSibling.tagName == this.tagName) {
        this.innerHTML = (this.innerHTML + this.nextSibling.innerHTML);
        this.parentNode.removeChild(this.nextSibling);
    }
});

console.log($div.html());

http://jsfiddle.net/X8LYu/2/

If you also wanted to remove the new-line characters, it would change to this:

var $div = $("div");
console.log($div.html());

$div.contents().each(function(){
    if (this.nodeType == 3) {
        this.nodeValue = this.nodeValue.replace(/\n/g,"");
        return;
    }
    if (this.nodeType != 1) return;
    while (this.nextSibling && this.nextSibling.tagName == this.tagName) {
        this.innerHTML = (this.innerHTML + this.nextSibling.innerHTML).replace(/\n/g,"");
        this.parentNode.removeChild(this.nextSibling);
    }
});

console.log($div.html());

http://jsfiddle.net/X8LYu/3/

I don't write code in this way very often, so there might be better ways of handling this.

like image 31
Kevin B Avatar answered Sep 18 '22 16:09

Kevin B


$('div').html(function(_, oldHTML) {
   return oldHTML.replace(/\n/g, '');
}).children().filter(function () {
    return this.nextSibling 
           && this.nextSibling.nodeName === this.nodeName;
}).text(function (_, oldText) {
    return oldText + this.parentNode.removeChild(this.nextSibling).textContent;
});

http://jsfiddle.net/tVZJV/

like image 40
undefined Avatar answered Sep 20 '22 16:09

undefined