Add html tags around highligted text in contentedi

2019-08-26 08:26发布

问题:

I have a contenteditable div and i would like to add some html tags around highlighted text, after user select the text and click the button..

Here is the sample code. It has some javascript codes but i couldnt make it work as desired. And i played with a lot actually.

https://codepen.io/anon/pen/ybzzXZ

P.S. I'm going to add , or like html tags after when we solve the how to add html tags around it.

Some of that js codes which i found in stackoverflow.

function getSelectionText() {
    var text = "";
    if (window.getSelection) {
        text = window.getSelection().text;
    } else if (document.selection && document.selection.type != "Control") {
        text = document.selection.createRange().text;
    }
    return text;
}

and the other one is

function replaceSelectionWithHtml(html) {
    var range;
    if (window.getSelection && window.getSelection().getRangeAt) {
        range = window.getSelection().getRangeAt(0);
        range.deleteContents();
        var div = document.createElement("div");
        div.innerHTML = html;
        var frag = document.createDocumentFragment(), child;
        while ( (child = div.firstChild) ) {
            frag.appendChild(child);
        }
        range.insertNode(frag);
    } else if (document.selection && document.selection.createRange) {
        range = document.selection.createRange();
        range.pasteHTML(html);
    }
}

回答1:

There are several challenges with the problem you present.

First off you need to gather the selected text value. You have posted some examples of that - that is fairly well documented elsewhere so I will leave that up to you to isolate that issue.

Next you need to highlight the selected text. Often to highlight something in HTML we wrap that text that we wish to highlight in a simple element such as a span, then give that span some class - for example often this is used to give a background color to some text. <span style='background-color:yellow'>some text</span> - not so difficult to understand that portion.

The challenge with this then is to combine your "discovered text" with the highlight. Pretty easy to wrap that text as in the span example provided earlier. One issue however is that if that text is previously within some other HTML elements, we need to ensure that the text choice in the discovery is for example not contained within another element AND if so, handle that issue. Let's illustrate that with this span: Howdy <span style='background-color:yellow'>some text</span> Some more.

Now for this example suppose we wish to highlight the text "Howdy some" - a portion of that text is previously within a span with our desired markup, thus we must first extract that, remove that "highlight" and henceforth highlight the new text "choice" of "Howdy some".

To provide an illustration of that. Type the words "This I want" into the text box and see how it gets highlighted.

This is not exactly your problem however it provides the "highlight" which you could potentially combine with your selector. I have NOT fully vetted this for bugs such as typing in HTML in to "highlight".

/* highlight words */
function findStringLimit(searchChar, searchCharIndex, searchedString) {
    return searchedString.substring(0, searchedString.lastIndexOf(searchChar, searchCharIndex));
};

function highlightWords(wordsy, text) { /* eliminate a bug with parenthesis */
    wordsy = wordsy.replace("(", "");
    wordsy = wordsy.replace(")", ""); /* escape other characters for bug */
    text = text.replace(";", "");
    text = text.replace("'", "&#39;");
    text = text.replace("<", "&lt;");
    text = text.replace(">", "&gt;");
    text = text.replace("&lt;span", "<span");
    text = text.replace('autoCompleteWord"&gt;', 'autoCompleteWord">');
    text = text.replace("&lt;/span", "</span");
    text = text.replace('span&gt;', 'span>');

    var re = '(' + wordsy + ')(?![^<]*(?:<\/span class=\"autoCompleteWord\"|>))';

    var regExp = new RegExp(re, 'ig');
    var sTag = '<span class="autoCompleteWord">';
    var eTag = "</span>";
    return text.replace(regExp, sTag + '$&' + eTag);
};

function parseAndHighlight(wordstring, htmlString) {
    var htmlStringUn = htmlString;

    var found = htmlStringUn.toLowerCase().indexOf(wordstring.toLowerCase(), 0);
    if (found >= 0) {
        htmlStringUn = highlightWords(wordstring, htmlStringUn);
    }
    else {
        //split and parse the beast
        var words = wordstring.split(/\W+/);

        var allPhrases = [];
        allPhrases.push(wordstring);
        var i = 0;
        i = words.length;
        while (i--) {
            allPhrases.push(findStringLimit(" ", allPhrases[(words.length - i) - 1].length, allPhrases[(words.length - i) - 1]));
        };

        i = allPhrases.length;
        while (i--) {
            if (allPhrases[i] != "") words = words.concat(allPhrases[i]);
        };
        i = words.length;
        while (i--) {
            htmlStringUn = highlightWords(words[i], htmlStringUn);
        };
    };
    return htmlStringUn;
}

$(document).on('change', '#myInput', function() {
    var myValue = $('#myInput').val(); //get what was typed
    $('#found').text(myValue);
    myValue = myValue.replace(/^\s+|\s+$/g, ""); //strip whitespace on ends
    $('#found').text(myValue + ':stripped:');
    var showText = $('#origshower').text();
    var newShowString = parseAndHighlight(myValue, showText); //my original highlighter
    $('#shower').html(newShowString);
});
#holder{border:red solid 2px; padding: 5px;}
#myInput{width:200px; background-color: aqua;}
span.autoCompleteWord /* this is the word(s) found */
{
    font-weight: bold;
    background-color: yellow;
    
}
#shower{border:lime 2px solid;}
<script
  src="https://code.jquery.com/jquery-1.12.4.min.js"
  integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ="
  crossorigin="anonymous"></script>

<div id='holder'>
    <input id='myInput' type='text' cols='60' rows='2' />Enter Text to match
</div>
<div id='origshower'>This is the span thistle with the whistle that I want matched is this neat</div>
<div id='shower'>none</div>
<div id='found'>enter</div>



回答2:

You can just call executeCommand with formatBlock. You can find more information here: https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand