Skip to content Skip to sidebar Skip to footer

Insert Character At Specific Point But Preserving Tags?

Update #2 Okay, more testing ensues. It looks like the code works fine when I use a faux spacer, but the regex eventually fails. Specifically, the following scenarios work: Select

Solution 1:

Here is a solution that supports all the features from your requirements:

HTML:

<pclass="text">
    First Line
    <aclass="space"></a><aclass="space"></a>
    Second Line
    <spanclass="space"></span>
    Third Line
    <labelclass="space"></label>
    Forth Line
</p><ulclass="output"></ul>

CSS:

.space {
    display: inline-block;
    width: 100%;
}
.highlighting {
    background-color: green;
}

JavaScript:

var text,
    output,
    unwrapContents,
    mergeElements,
    clearSelection,
    clearHighlighting,
    mergeHighlighting,
    handleCopy;

unwrapContents = functionunwrapContents(element) {
    while(element.firstChild !== null) {
        element.parentNode.insertBefore(element.firstChild, element);
    }
    element.parentNode.removeChild(element);
};

mergeElements = functionmergeElements(startElement, endElement) {
    var currentElement;
    endElement = endElement.nextSibling;
    while((currentElement = startElement.nextSibling) !== endElement) {
        startElement.appendChild(currentElement);
    }
};

clearSelection = functionclearSelection() {
    if (document.selection) {
        document.selection.empty();
    } elseif (window.getSelection) {
        window.getSelection().removeAllRanges();
    }
};

clearHighlighting = functionclearHighlighting(target, exception) {
    $('.highlighting', target).each(function(index, highlighting) {
        if(highlighting !== exception) {
            unwrapContents(highlighting);
        }
    });
    target.normalize();
};

mergeHighlighting = functionmergeHighlighting() {
    var i, j;
    // Remove internal highlights
    $('.highlighting', text).filter(function() {
        returnthis.parentNode.className === 'highlighting';
    }).each(function(index, highlighting) {
        unwrapContents(highlighting);
    });
    text.normalize();
    // Merge adjacent highlightsfirst:
    for(i=0; i<text.childNodes.length-1; i++) {
        if(text.childNodes[i].className === 'highlighting') {
            for(j=i+1; j<text.childNodes.length; j++) {
                if(text.childNodes[j].className === 'highlighting') {
                    mergeElements(text.childNodes[i], text.childNodes[j--]);
                    unwrapContents(text.childNodes[i].lastChild);
                } else {
                    switch(text.childNodes[j].nodeType) {
                        case1:
                            if(text.childNodes[j].className !== 'space') {
                                continue first;
                            }
                            break;
                        case3:
                            if(text.childNodes[j].textContent.trim() !== '') {
                                continue first;
                            }
                            break;
                    }
                }
            }
        }
    }
};

handleCopy = functionhandleCopy() {
    var range,
        highlighting,
        item;

    // Highlighting
    range = window.getSelection().getRangeAt(0);
    highlighting = document.createElement('span');
    highlighting.className = 'highlighting';
    highlighting.appendChild(range.cloneContents());
    range.deleteContents();
    range.insertNode(highlighting);

    // Output
    item = document.createElement('li');
    item.innerHTML = highlighting.innerHTML;
    clearHighlighting(item);
    output.appendChild(item);

    // CleanupmergeHighlighting();
    clearSelection();
};

$(function(){
    text = $('.text')[0];
    output = $('.output')[0];
    $(text).on('copy', handleCopy);
});

Here is a working example http://jsbin.com/efohit/3/edit

Solution 2:

Well, I came up with a solution, rather straightforward as well.

If .text looks like this:

<pclass="text">Line one
<aclass="space"></a>Line two
<aclass="space"></a>Line three</p>

With the exact markup and line breaks as above, then I can find each \n and replace it with a spacer element.

if (textStr.indexOf("\n") >= 0) {
    textStr = textStr.replace(/\n/g, "\n<a class='space'></a>");
}

This isn't versatile at all, and will fail if there are more than one line breaks, if the tags are different, etc. So, I encourage anyone who has a better method to answer the question! It can't be that hard, I figured it out.

Post a Comment for "Insert Character At Specific Point But Preserving Tags?"