Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
756 views
in Technique[技术] by (71.8m points)

jquery - Cursor moves to beginning of text when I update text with javascript

I'm using contenteditable to allow users to edit information on the webpage, but some fields have a length requirement, and I want them to know when they've hit that requirement, so I change the color of the text that will be chopped off when they hit return to red.

The issue is that when the text is changed with JavaScript, the browser moves the cursor to the front of the string. Does anyone know of a way I can prevent this behavior? As far as I can tell this this is an issue in all browsers.

Here's a JSFiddle.

$(element).keypress(function (event) {
    if ($(element).text().trim().length > maxChars) {
        $(element).html($(element).text().trim().substr(0, maxChars) +
            "<span class=red>" + $(element).text().trim().substr(maxChars) + "</span>");
    }
});
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Thanks to harsha and Tim Down I finally got this to work and also fixed the issue where Firefox doesn't allow spaces, and it works quite well. The only non-expected behavior I could find was that it messes up the browser's undo history but other than that it works very well.

I've tested in every browser but IE, but I don't see why it wouldn't work in newer IE versions also. It requires use of the input event though, so it wouldn't work in older browsers. I also don't know how it handles line breaks because I strip them in my app.

First, you need this code written by Tim Down somewhere in your file.

var saveSelection, restoreSelection;
var endSpaceIndex = -1;

if (window.getSelection && document.createRange) {
    saveSelection = function(containerEl) {
        var range = window.getSelection().getRangeAt(0);
        var preSelectionRange = range.cloneRange();
        preSelectionRange.selectNodeContents(containerEl);
        preSelectionRange.setEnd(range.startContainer, range.startOffset);
        var start = preSelectionRange.toString().length;

        return {
            start: start,
            end: start + range.toString().length
        }
    };

    restoreSelection = function(containerEl, savedSel) {
        var charIndex = 0, range = document.createRange();
        range.setStart(containerEl, 0);
        range.collapse(true);
        var nodeStack = [containerEl], node, foundStart = false, stop = false;

        while (!stop && (node = nodeStack.pop())) {
            if (node.nodeType == 3) {
                var nextCharIndex = charIndex + node.length;
                if (!foundStart && savedSel.start >= charIndex && savedSel.start <= nextCharIndex) {
                    range.setStart(node, savedSel.start - charIndex);
                    foundStart = true;
                }
                if (foundStart && savedSel.end >= charIndex && savedSel.end <= nextCharIndex) {
                    range.setEnd(node, savedSel.end - charIndex);
                    stop = true;
                }
                charIndex = nextCharIndex;
            } else {
                var i = node.childNodes.length;
                while (i--) {
                    nodeStack.push(node.childNodes[i]);
                }
            }
        }

        var sel = window.getSelection();
        sel.removeAllRanges();
        sel.addRange(range);
    }
} else if (document.selection) {
    saveSelection = function(containerEl) {
        var selectedTextRange = document.selection.createRange();
        var preSelectionTextRange = document.body.createTextRange();
        preSelectionTextRange.moveToElementText(containerEl);
        preSelectionTextRange.setEndPoint("EndToStart", selectedTextRange);
        var start = preSelectionTextRange.text.length;

        return {
            start: start,
            end: start + selectedTextRange.text.length
        }
    };

    restoreSelection = function(containerEl, savedSel) {
        var textRange = document.body.createTextRange();
        textRange.moveToElementText(containerEl);
        textRange.collapse(true);
        textRange.moveEnd("character", savedSel.end);
        textRange.moveStart("character", savedSel.start);
        textRange.select();
    };
}

Somewhere you also need the following code. It uses jQuery, so if you don't have that you'll have to get rid of the jQuery in the example below. This needs to be bound to the input event, as Firefox is very inconsistent with when it calls keyup and keypress. This is what fixes the issue with Firefox not allowing spaces. It's pretty messy. But then again, apparently so is browser support for contenteditable.

// Provided `element` is the element that you want to modify while the user changes it.
$(element).bind('input', function() {
    var savedSel = saveSelection(element);
    if (endSpaceIndex > -1 && $(element).text().substr(endSpaceIndex) != " " 
        && savedSel.end == $(element).text().length && savedSel.end == savedSel.start) {
            $(element).html($(element).text().substr(0, endSpaceIndex) + " " + $(element).text().substr(endSpaceIndex));
            endSpaceIndex = -1;
            savedSel.end = savedSel.start = $(element).text().length;
    }

    // Here, change the element however you want to. 
    // For example, I add a 'red' class around the text that will be chopped off

    restoreSelection(element, savedSel);
    var fullText = $(element).text();
    if (fullText.substr(fullText.length - 1) == " ") {
        endSpaceIndex = fullText.length - 1;
    }
}

Also I originally marked this as a duplicate, but I no longer think it's a duplicate because it fixes this issue with Firefox not allowing spaces. Hope this helps someone else!


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...