Ian Y.
Ian Y.

Reputation: 2457

Javascript - How to replace white spaces which are not in HTML tags?

The following codes doesn't work and the result is broken because there are white spaces in a HTML tag.

HTML:

<div>Lorem ipsum <a id="demo" href="demo" rel="demo">dolor sit amet</a>, consectetur adipiscing elit.</div>

Javascript:

var div = document.getElementsByTagName('div')[0];
div.innerHTML = div.innerHTML.replace(/\s/g, '<span class="space"> </span>');


How to replace replace white spaces which are not in HTML tags?

Upvotes: 2

Views: 910

Answers (3)

scessor
scessor

Reputation: 16125

First split the string at every occurrence of > or <. Then fit together all parts to a string again by replacing spaces only at the even parts:

var div = document.getElementsByTagName('div')[0];
var parts = div.innerHTML.split(/[<>]/g);
var newHtml = '';
for (var i = 0; i < parts.length; i++) {
    newHtml += (i % 2 == 0 ? parts[i].replace(/\s/g, '<span class="space"> </span>') : '<' + parts[i] + '>');
}
div.innerHTML = newHtml;

Also see this example.

=== UPDATE ===

Ok, the result of th IE split can be different then the result of split of all other browsers. With following workaround it should work:

var div = document.getElementsByTagName('div')[0];
var sHtml = ' ' + div.innerHTML;
var sHtml = sHtml.replace(/\>\</g, '> <');
var parts = sHtml.split(/[<>]/g);
var newHtml = '';
for (var i = 0; i < parts.length; i++) {
    if (i == 0) {
        parts[i] = parts[i].substr(1);
    }
    newHtml += (
        i % 2 == 0 ? 
        parts[i].replace(/\s/g, '<span class="space"> </span>') : 
        '<' + parts[i] + '>'
    );
}
div.innerHTML = newHtml;

Also see this updated example.

=== UPDATE ===

Ok, I have completly changed my script. It's tested with IE8 and current firefox.

function parseNodes(oElement) {
    for (var i = oElement.childNodes.length - 1; i >= 0; i--) {
        var oCurrent = oElement.childNodes[i];
        if (oCurrent.nodeType != 3) {
            parseNodes(oElement.childNodes[i]);
        } else {
            var sText = (typeof oCurrent.nodeValue != 'undefined' ? oCurrent.nodeValue : oCurrent.textContent);
            var aParts = sText.split(/\s+/g);
            for (var j = 0; j < aParts.length; j++) {
                var oNew = document.createTextNode(aParts[j]);
                oElement.insertBefore(oNew, oCurrent);
                if (j < aParts.length - 1) {
                    var oSpan = document.createElement('span');
                    oSpan.className = 'space';
                    oElement.insertBefore(oSpan, oCurrent);
                    var oNew = document.createTextNode(' ');
                    oSpan.appendChild(oNew);
                }
            }
            oElement.removeChild(oCurrent);
        }
    }
}

var div = document.getElementsByTagName('div')[0];
parseNodes(div);

Also see the new example.

Upvotes: 0

pimvdb
pimvdb

Reputation: 154948

It would be a better idea to actually use the DOM functions rather than some unreliable string manipulation using a regexp. splitText is a function of text nodes that allows you to split text nodes. It comes in handy here as it allows you to split at spaces and insert a <span> element between them. Here is a demo: http://jsfiddle.net/m5Qe8/2/.

var div = document.querySelector("div");

// generates a space span element
function space() {
    var elem = document.createElement("span");
    elem.className = "space";
    elem.textContent = " ";
    return elem;
}

// this function iterates over all nodes, replacing spaces
// with space span elements
function replace(elem) {
    for(var i = 0; i < elem.childNodes.length; i++) {
        var node = elem.childNodes[i];
        if(node.nodeType === 1) {
            // it's an element node, so call recursively
            // (e.g. the <a> element)
            replace(node);
        } else {
            var current = node;
            var pos;
            while(~(pos = current.nodeValue.indexOf(" "))) {
                var next = current.splitText(pos + 1);
                current.nodeValue = current.nodeValue.slice(0, -1);
                current.parentNode.insertBefore(space(), next);
                current = next;
                i += 2;  // childNodes is a live array-like object
                         // so it's necessary to advance the loop
                         // cursor as well
            }
        }
    }
}

Upvotes: 1

kennebec
kennebec

Reputation: 104840

You can deal with the text content of the container, and ignore the markup.

var div = document.getElementsByTagName('div')[0];
if(div.textContent){
    div.textContent=div.textContent.replace(/(\s+)/g,'<span class="space"> </span>';
}
else if(div.innerText){
    div.innerText=div.innerText.replace(/(\s+)/g,'<span class="space"> </span>';
}

Upvotes: 0

Related Questions