Select cross boundries

Selection and wrapping around elements cross elements

by Mayank Dixit

HTML

<button id="surround">Make selected text bold</button>

<h1>Title 01 Heading</h1>
		<hr />
		<h2>Level 02 Heading</h2>
		<p>Lorem ipsum <em>emphasised text</em> dolor sit amet, <strong>strong text</strong> consectetur
			adipisicing elit, <abbr title="">abbreviated text</abbr> sed do eiusmod tempor incididunt
			ut labore et dolore magna aliqua. Ut
			<q>quoted text</q> enim ad minim veniam, quis nostrud exercitation <a href="/">link text</a> ullamco
			laboris nisi ut aliquip ex ea commodo consequat. Duis aute
			<ins>inserted text</ins> irure dolor <u>root <i>first <em>second</em></i></u> in reprehenderit in voluptate velit esse cillum
			dolore eu fugiat nulla pariatur. Excepteur sint occaecat <code>code text</code> cupidatat
			non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>

		<p>
			Suspendisse rhoncus, est ac sollicitudin viverra, leo orci sagittis massa, sed condimentum
			<acronym
			title="">acronym text</acronym>est tortor a lectus. Curabitur porta feugiat ullamcorper.
				Integer lacinia mi id odio faucibus eget tincidunt nisl iaculis. Nam adipiscing
				hendrerit turpis, et porttitor felis sollicitudin et. Donec dictum massa ac neque
				accumsan tempor. Cras aliquam, ipsum sit amet laoreet hendrerit, purus <del>deleted text</del> sapien
				convallis dui, et porta leo ipsum ac nunc. Nullam ornare porta dui ac semper.
				Cras aliquam laoreet hendrerit. Quisque vulputate dolor eget mi porta vel porta
				nisl pretium. Vivamus non leo magna, quis imperdiet risus. Morbi tempor risus
				placerat tellus imperdiet fringilla.
		</p>

		<blockquote>
			<p>I am not one who was born in the <i>possession of <u>knowledge</u></i>; I am one who is fond
				of antiquity, and earnest in seeking it there.</p>
		</blockquote>

		<p><cite><a href="/">Confucius, The Confucian Analects</a></cite>, (551 BC - 479 BC)</p>

		<h3>Level 03 Heading</h3>

		<p>Extended paragraph. <a href="">Lorem ipsum</a> dolor sit amet, consectetur...

CSS

#surround {
    position: fixed;
}

h1 {
    padding-top: 50px; 
}

JavaScript

document.getElementById('surround').onclick = function(){
    surroundSelection('b');
};

function surroundSelection(elementType) {
    function getAllDescendants (node, callback) {
        
        for (var i = 0; i < node.childNodes.length; i++) {
            var child = node.childNodes[i];
            getAllDescendants(child, callback);
            callback(child);
        }
        
    }
    
    function glueSplitElements (firstEl, secondEl){

        var done = false,
            result = [];
        
        if(firstEl === undefined || secondEl === undefined){
            return false;
        }
        
        if(firstEl.nodeName === secondEl.nodeName){
            result.push([firstEl, secondEl]);
            
            while(!done){
                firstEl = firstEl.childNodes[firstEl.childNodes.length - 1];
                secondEl = secondEl.childNodes[0];
                
                if(firstEl === undefined || secondEl === undefined){
                    break;
                }
                
                if(firstEl.nodeName !== secondEl.nodeName){
                    done = true;
                } else {
                    result.push([firstEl, secondEl]);
                }
            }
        }
        
        for(var i = result.length - 1; i >= 0; i--){
            var elements = result[i];
            while(elements[1].childNodes.length > 0){
                elements[0].appendChild(elements[1].childNodes[0]);
            }
            elements[1].parentNode.removeChild(elements[1]);
        }
        
    }
    
    // abort in case the given elemenType doesn't exist.
    try {
        document.createElement(elementType);
    } catch (e){
        return false;
    }
    
    var selection = getSelection();
    
    if(selection.rangeCount > 0){
        var range = selection.getRangeAt(0),
            rangeContents = range.extractContents(),
            nodesInRange  = rangeContents.childNodes,
            nodesToWrap   = [];
  ...