Insert character at specific point but preserving tags?

后端 未结 2 860
無奈伤痛
無奈伤痛 2021-01-18 02:22

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 scenari

相关标签:
2条回答
  • 2021-01-18 02:55

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

    If .text looks like this:

    <p class="text">Line one
    <a class="space"></a>Line two
    <a class="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.

    0 讨论(0)
  • 2021-01-18 03:16

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

    HTML:

    <p class="text">
        First Line
        <a class="space"></a>
        <a class="space"></a>
        Second Line
        <span class="space"></span>
        Third Line
        <label class="space"></label>
        Forth Line
    </p>
    <ul class="output"></ul>
    

    CSS:

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

    JavaScript:

    var text,
        output,
        unwrapContents,
        mergeElements,
        clearSelection,
        clearHighlighting,
        mergeHighlighting,
        handleCopy;
    
    unwrapContents = function unwrapContents(element) {
        while(element.firstChild !== null) {
            element.parentNode.insertBefore(element.firstChild, element);
        }
        element.parentNode.removeChild(element);
    };
    
    mergeElements = function mergeElements(startElement, endElement) {
        var currentElement;
        endElement = endElement.nextSibling;
        while((currentElement = startElement.nextSibling) !== endElement) {
            startElement.appendChild(currentElement);
        }
    };
    
    clearSelection = function clearSelection() {
        if (document.selection) {
            document.selection.empty();
        } else if (window.getSelection) {
            window.getSelection().removeAllRanges();
        }
    };
    
    clearHighlighting = function clearHighlighting(target, exception) {
        $('.highlighting', target).each(function(index, highlighting) {
            if(highlighting !== exception) {
                unwrapContents(highlighting);
            }
        });
        target.normalize();
    };
    
    mergeHighlighting = function mergeHighlighting() {
        var i, j;
        // Remove internal highlights
        $('.highlighting', text).filter(function() {
            return this.parentNode.className === 'highlighting';
        }).each(function(index, highlighting) {
            unwrapContents(highlighting);
        });
        text.normalize();
        // Merge adjacent highlights
        first:
        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) {
                            case 1:
                                if(text.childNodes[j].className !== 'space') {
                                    continue first;
                                }
                                break;
                            case 3:
                                if(text.childNodes[j].textContent.trim() !== '') {
                                    continue first;
                                }
                                break;
                        }
                    }
                }
            }
        }
    };
    
    handleCopy = function handleCopy() {
        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);
    
        // Cleanup
        mergeHighlighting();
        clearSelection();
    };
    
    $(function(){
        text = $('.text')[0];
        output = $('.output')[0];
        $(text).on('copy', handleCopy);
    });
    

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

    0 讨论(0)
提交回复
热议问题