Remove last x characters before carret position

2019-06-19 00:55发布

问题:

Short version:

I have a contenteditable div. I want to remove the last x chars before carret postion.

Long version:

If someone types a [ in the contenteditable div there should appear an autosuggest list, filled by an ajax call. This is allready working. I can also insert the selected suggestion at carret position and add a ]. But the chars, already typed by the user, should be deleted before appending the suggestion. The bracket [ is not only the "trigger-char" but also a markdown-like format element.

Example:

Text in the div ("|" stands for carret): Lorem ipsum| sit lorem ipsum dolor

User now types [do to start auto suggestion: Lorem ipsum [do| sit lorem ipsum dolor

dolor is suggested and inserted after carret: Lorem ipsum [do|dolor sit lorem ipsum dolor

Problem: the allready typed chars do should be removed before inserting the suggestion

Desired behaviour: Lorem ipsum [dolor] sit lorem ipsum dolor

Attempted Solutions:

Insert text at cursor in a content editable div - working but i can't remove the last chars https://developer.mozilla.org/en-US/docs/Web/API/Selection - tried to get some ideas from MDN, but no idea how to change the selection's textNode's content

Code:

Extract the string between last "[" and carret to search for suggestions in DB:

var sel = window.getSelection();
var cords = getCaretCoords();
var searchQuery = extractSearchQuery(sel.anchorNode.data, sel.anchorOffset, "[");

function extractSearchQuery(searchString, caretPos, triggerString) {
    //cut everything after carret
    searchString = searchString.slice(searchString.lastIndexOf(triggerString) + 1, caretPos);
    return searchString;
}

Insert the suggestion after carret:

function insertTextAtCursor(text) {
    var sel, range, html;
    if (window.getSelection) {
        sel = window.getSelection();
        if (sel.getRangeAt && sel.rangeCount) {
            range = sel.getRangeAt(0);
            range.deleteContents();
            var newTextNode = document.createTextNode(text);
            range.insertNode(newTextNode);
        }
    } else if (document.selection && document.selection.createRange) {
        document.selection.createRange().text = text;
    }
}

回答1:

With the following assumptions and definitions:

  • You know the location of the "[" as this triggers the auto-suggest to start working after all. Let's call this indexbracket
  • You know what text has been typed after the bracket as you used that for the auto-suggestion. Let's call this lookupstring

Then you should replace the content of your div by:

divtext = divtext.substring(0, indexbracket) + divtext.substring(indexbracket + lookupstring.length + 1);

Example: (in which I used different methods to find indexbracket etc. than you probably used)

var divtext = "Lorum ipsum [doAUTOSUGGESTEDTEXT sit";
var indexbracket = divtext.indexOf('[');
var lookupstring = "do";
divtext = divtext.substring(0, indexbracket) + divtext.substring(indexbracket+lookupstring.length+1);
console.log(divtext);

Update after edit of post Given your need for the position of the caret, you could opt to "manually" reset the location of the caret after replacing the text, see this excellent answer here: https://stackoverflow.com/a/512542/3000771



回答2:

You are already using window.getSelection(), which is correct. Using window.getSelection().baseOffset gives you the index you are at. From here, provided that you know where your selection starts in comparison to the starting position of the chunk to replace, you will be able to compute its starting index. You know the length as well, so you will need to get the starting substring and the ending substring of your content (omit the chunk to be replaced) and concatenate between them the new content.



回答3:

Thanks for all advices.

My solution is now working similiar to that answer: https://stackoverflow.com/a/11248187/8622487

var length = lookupstring.length; //length of the allready typed string
var sel = window.getSelection();
sel.collapseToStart();
for (var i = 0; i < length; i++) {
    sel.modify("move", "backward", "character");
}
for (var i = 0; i < length; i++) {
    sel.modify("extend", "forward", "character");
}

This selects the allready typed chars. When inserting the matching keyword this is overwritten.

I know this is quick and dirty, but it works (in Firefox and Chrome)