Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to prevent a contentEditable element from scrolling when the cursor reaches the bottom?

For example, I have a contentEditable div and I can type in it. When the text reaches the bottom of the div, the browser automatically scrolls the div so that the end of the text and the cursor are still visible.

How do I prevent the div from scrolling so that the inputted text goes past the bottom of the div and so that you can no longer see the cursor while you type?

The behavior I'm trying to achieve is like in Photoshop: when you make a text box, and type too much, the cursor continues past the bottom of the box and you can't see what you are typing. If you expand the box, you'll see all the hidden text.

EDIT 2/7/2012 9:27am: This is what I have right now, but it looks glitchy because the scroll position is adjusted AFTER the keyup event: http://jsfiddle.net/trusktr/hgkak/6/ So before the keyup event, the cursor gets temporarily placed into view (for each keystroke). I'd like there to be no jumping, and for the cursor to remain below the end of the green div when there is excess text without the view jumping around (the jumping seems like an amateur hack on my part :D)

like image 964
trusktr Avatar asked Feb 04 '12 21:02

trusktr


People also ask

How do you make a Div Contenteditable?

Answer: Use the HTML5 contenteditable Attribute You can set the HTML5 contenteditable attribute with the value true (i.e. contentEditable="true" ) to make an element editable in HTML, such as <div> or <p> element.


2 Answers

Let's try a hack:

  • first we try to prevent or revert any scrolling
  • whenever the user presses a key we turn the element's overflow property to visible to avoid scrolling of the content, but hide the element at the same time by setting its opacity to 0. Immediately afterwards we switch overflow back to hidden and show the element again.
  • to avoid flickering we create a clone of the editable element (with overflow: hidden) and show this element while the original one is hidden.

Here we go (uses jQuery for DOM convenience):

$(function() {

    var editableElement = $('#editable'), clonedElement;

    // Revert any scrolling                    
    editableElement.on("scroll", function(event) {
        editableElement.scrollTop(0);

        // Try to prevent scrolling completely (doesn't seem to work)
        event.preventDefault();
        return false;
    });

    // Switch overflow visibility on and off again on each keystroke.
    // To avoid flickering, a cloned element is positioned below the input area
    // and switched on while we hide the overflowing element.
    editableElement.on("keydown", function() {

        // Create a cloned input element below the original one
        if (!clonedElement) {
            var zIndex = editableElement.css('zIndex');
            if (isNaN(parseInt(zIndex, 10))) {
                zIndex = 10;
                editableElement.css({zIndex: zIndex});
            }    

            clonedElement = editableElement.clone();
            clonedElement.css({
                zIndex: zIndex-1,
                position: 'absolute',
                top: editableElement.offset().top,
                left: editableElement.offset().left,
                overflow: 'hidden',
                // Set pseudo focus highlighting for webkit
                // (needs to be adapted for other browsers)
                outline: 'auto 5px -webkit-focus-ring-color'
            });
            editableElement.before(clonedElement);
        } else {
            // Update contents of the cloned element from the original one
            clonedElement.html(editableElement.html());
        }

        // Here comes the hack:
        //   - set overflow visible but hide element via opactity.
        //   - show cloned element in the meantime
        clonedElement.css({opacity: 1});
        editableElement.css({overflow: 'visible', opacity: 0});

        // Immediately turn of overflow and show element again.
        setTimeout(function() {
            editableElement.css({overflow: 'hidden', opacity: 1});
            clonedElement.css({opacity: 0});
        }, 10);

    });
});

Check this jsFiddle to play with the above code.

Note that this may not be a complete solution (I have only tried it with Safari, Chrome and Firefox yet), but for the tested browsers it seems to work. You may want to fine-tune and polish your implementation (e.g. focus highlighting). In the jsFiddle example I have also turned off spell checking to avoid flickering markings.

like image 153
Julian D. Avatar answered Sep 22 '22 06:09

Julian D.


You need to have parent div (A) with overflow:hidden;position:relative and static height or min-height.

Inside this parent you have children div (B) with contenteditable="true" and style="position:absolute;width:100%;left:0;top:0"

Height of div A must be like integer * line-height of div B


After that you need to include rangy and jQuery library

Bind on div B keyup event function{

Use rangy for create in current cursor place empty span.

Get offset().top from this span and compare it with offset().top +outerHeight() from div A. If first is large then second -> you need to scroll down div B.

To scroll down just change current css top on += line-height of div B

Destroy empty span.

(if cursor position fails -> you need to previously save it before creating span and restore cursor position after destroying span)

}


Also you need to emulate all with arrow keys. In that case you need to create switch selector with event.which on keyup in div B. Keycodes are here.

Scroll if cursor position is out from visible range in div A (algorithm similar to what I wrote above)


Yes, this is not an easy way, but it works

like image 3
Rustam Avatar answered Sep 24 '22 06:09

Rustam