JSFiddle - React, Tailwind, and code Playground

by timdown

HTML

<p>Magna pariatur eu culpa elit, beef id sunt duis pancetta. Excepteur tempor jerky beef ribs, pork rump filet mignon culpa consequat shank boudin ex voluptate turducken. Cow qui ground round enim non. <img src="http://jsfiddle.net/img/logo.png" width="100" height="50">Consectetur corned beef consequat biltong exercitation proident. In pork chop andouille filet mignon sint ribeye, short ribs beef ribs enim. Laborum do leberkas, id hamburger in ball tip incididunt.</p>

<p>Dolor fatback andouille tongue pastrami. Dolor sunt veniam sirloin, speck bresaola velit jerky ham rump ut biltong meatball consequat. Pork belly exercitation ham hock shankle adipisicing shank, cow fatback brisket quis nostrud. Labore commodo veniam culpa, tongue sausage eu tail capicola magna swine. Beef ribs salami quis in ad kielbasa, in shank tenderloin officia adipisicing pancetta sunt.</p>

<p>Magna deserunt beef short ribs, tail sed shoulder laborum commodo chuck. Deserunt in cillum qui corned beef. Labore cow nisi, leberkas jerky eu commodo fatback beef shankle. Deserunt ea fugiat ribeye, fatback strip steak turkey flank.</p>

<p>Ex incididunt speck, do swine elit aliquip laborum ham sed. Hamburger jowl est corned beef. Pariatur commodo ut voluptate, short loin brisket ground round ea laborum t-bone duis fugiat nulla irure. Nisi ex frankfurter excepteur pariatur short ribs sint, anim nulla swine. Jowl nostrud officia rump ball tip. Nostrud meatball capicola fatback qui, sint in duis minim.</p>

<p>Adipisicing ribeye fugiat, brisket cillum deserunt shank speck velit pork loin. Reprehenderit ex laborum spare ribs pork belly, short ribs frankfurter anim enim speck adipisicing rump incididunt. Ullamco ham hock shoulder ball tip irure. Drumstick ut brisket dolore, hamburger swine esse pig fatback eiusmod beef. Shoulder venison dolore turducken.</p>

CSS

p {
    /*font-size: 400%;*/
}

JavaScript

function getNodeIndex(node) {
    var i = 0;
    while( (node = node.previousSibling) ) {
        i++;
    }
    return i;
}

function getLastRangeRect(range) {
    var rects = range.getClientRects();
    return (rects.length > 0) ? rects[rects.length - 1] : null;
}

function pointIsInOrAboveRect(x, y, rect) {
    return y < rect.bottom && x >= rect.left && x <= rect.right;
}

function positionFromPoint(doc, x, y, favourPrecedingPosition) {
    var el = doc.elementFromPoint(x, y);
    
    var range = doc.createRange();
    range.selectNodeContents(el);
    range.collapse(true);
    
    var offsetNode = el.firstChild, offset, position, rect;
    
    if (!offsetNode) {
        offsetNode = el.parentNode;
        offset = getNodeIndex(el);
        if (!favourPrecedingPosition) {
            ++offset;
        }
    } else {
        // Search through the text node children of el
        main: while (offsetNode) {
            if (offsetNode.nodeType == 3) {
                // Go through the text node character by character
                for (offset = 0, textLen = offsetNode.length; offset <= textLen; ++offset) {
                    range.setEnd(offsetNode, offset);
                    rect = getLastRangeRect(range);
                    if (rect && pointIsInOrAboveRect(x, y, rect)) {
                        // We've gone past the point. Now we check which side (left or right) of the character the point is nearer to
                        if (rect.right - x > x - rect.left) {
                            --offset;
                        }
                        break main;
                    }
                }
            } else {
                // Handle elements
                range.setEndAfter(offsetNode);
                rect = getLastRangeRect(range);
                if (rect && pointIsInOrAboveRect(x, y, rect)) {
                    offset = getNodeIndex(offsetNode);
                    offsetNode = el.parentNode;
                    if...