简体   繁体   中英

Javascript: Unitentional Focus Blur

In my endeavor to learn Javascript, I've been trying to implement a WYSIWYG code editor. Instead of implementing a content-editable div or a textarea , I took a leaf (rather, a lot of leaves) out of Ajax.org's ACE's book.

I have a listener div with tabIndex set to 0, to handle all input events. All the components of the editor, like the text area, cursor and gutter, are children to this listener. Since implementing mouse event handlers, I have been having a problem of the focus being lost on mousedown events. Apparently, the blur event is being fired even when the mousedown event occurs in the listener.

After commenting out certain method calls and trying to see exactly what was causing the problem, I noticed that the culprit was the render method. Now, I call this method after every input, so it is very strange for the focus to be lost particularly when I call it for the mousedown event. On commenting out the render method, blur event is not fired when there is a mousedown event.

Going in further, it turns out that on commenting out the part where I replace the innerHTML of my text container, the problem disappears. This, again, is very odd since I use the replaceInnerHTML function at various places in the render function, but the problem seems to arise only from particularly updating the text div .

This is the replaceInnerHTML method (which I discovered here ):

function replaceInnerHTML(el, html) {
    var newEl = el.cloneNode(false);

    newEl.innerHTML = html;

    el.parentNode.replaceChild(newEl, el);

    return newEl;
}

And this is the update function for the text layer, on omitting which this problem does not occur:

TextLayer.prototype.update = function(config) {
    html = [];

    var top = config.topRow;
    var last = config.lastRow;

    for(var i=top; i<=last; i++) {
        var line = this._session.getLine(i);
        if(line) {
            html.push('<div class="line" style="height:'+this.$characterSize.height+'px;">');
            this.renderLine(html, line);
            html.push('</div>');
        }       
    }   

    this._text = replaceInnerHTML(this._text, html.join(''));
    this.setSize(config.totalWidth, config.scrollHeight);
};

Why would the focus get blurred only due to replacing the innerHTML of a particular node, and that too only when it is called in case of a mousedown event?

Or am I going in a completely wrong direction in trying to debug this, and this problem is due to something else?

EDIT:

Thanks to pimvdb, here is a fiddle reproducing the problem. http://jsfiddle.net/wG4Yy/39/

The blur event seems to fire due to restructuring the nodes on the mousedown event. I do not know how to solve problem. I have tried using a document fragment instead of innerHTML, and I have also tried scheduling the update with setTimeout , but neither attempt worked.

What should I do to resolve the issue?

When you want an element to get focus, it seems like the you have to click on an element that stays there. If you replace it with another element, the browser is apparently not tricked into focusing that element.

What you can do is letting the browser finish its mousedown/focus etc. process, and focus the element manually afterwards. This can be accomplished with a setTimeout(..., 0) call: http://jsfiddle.net/wG4Yy/41/ .

setTimeout(function() {
    wrapper.focus();
}, 0);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM