JavaScript: ошибка видимости в Internet Explorer при настройке фокуса на элемент ввода

Это может быть самая непонятная ошибка, с которой я столкнулся в течение многих лет работы с JavaScript и любой версией Internet Explorer. Мы используем YUI 2.7 для некоторых (не) удобных методов. Вздох, что бы я сделал для jQuery....

Это влияет на Internet Explorer 6 и Internet Explorer7. Internet Explorer 8 ведет себя правильно. Все остальные браузеры также ведут себя правильно.

Проблема: когда я устанавливаю фокус на определенный элемент, я получаю следующую ошибку:

Can't move focus to the control because it is invisible, not enabled, or of a type that does not accept focus.

Итак, у меня есть div, называемый add-comment-login-overlay, содержащий элемент ввода. Этот div является отображением: none, пока пользователь не нажмет один из нескольких ссылок, называемых "login".

Ниже приведен код JavaScript, который я использую, который выбирает ссылки "login", который перемещает позицию "add-comment-login-overlay" в DOM, устанавливает отображение: блок, а затем устанавливает фокус на 1-ое поле ввода в оверлее. Этот процесс установки фокуса вызывает ошибку, которую я написал выше.

//Get Login links in comment forms.
links = YAHOO.util.Dom.getElementsByClassName('addCommentLoginLink');

//Set click event for login links.
YAHOO.util.Event.addListener(links, "click", function(el){

    //Stop link.
    YAHOO.util.Event.preventDefault(el);

    //Move login overlay in DOM.
    if( el.srcElement ){
        var target = el.srcElement;
    }else{
        var target = el.currentTarget;
    }

    YAHOO.util.Dom.insertAfter( overlay, target.parentNode.parentNode.parentNode.parentNode );

    //Set to visible.
    YAHOO.util.Dom.setStyle( overlay,'display', 'block' );

    //Set focus to username field.
    document.getElementById('add-comment-login-overlay-username-input').focus();
});

Я могу абсолютно подтвердить, что оверлейный div полностью виден. Я могу посмотреть на это. Я добавил таймер setInterval для измерения того, что происходит, и это не влияет. В какой-то момент у меня было 10 секунд между временем, когда наложение было видимым, и когда focus() был вызван, и ошибка все еще происходит. Помимо ошибки, форма полностью функциональна, кроме этой ошибки.

Это упрощенная версия HTML-кода наложения в качестве ссылки.

<div id="add-comment-login-overlay" class="add-comment-login-overlay" style="display: block;">
    <div class="add-comment-login-overlay-content clearfix">
        <div class="add-comment-login-overlay-signin clearfix">
            <input type="text" tabindex="2001" id="add-comment-login-overlay-username-input"/>
            <input type="password" tabindex="2002" id="add-comment-login-overlay-password-input"/>
        </div>
    </div>
</div>

Ответы

Ответ 1

Это старая ошибка в IE (рада узнать, что она исправлена ​​в 8). Я не знаю официальной причины, но я считаю, что это связано с тем, что IE не перерисовывает DOM до тех пор, пока контекст выполнения не будет завершен, тем временем, попробовав focus() элемент, пока он думает, что он все еще скрыт:

function calledAtSomePoint() { // begin execution

    // ...

    element.style.display = ''; // show container
    input.focus(); // IE thinks element is hidden 

    // end of execution, IE repaints the DOM but it too late
} 

Решение заключается в использовании setTimeout:

setTimeout(function() {
    document.getElementById('add-comment-login-overlay-username-input').focus()
}, 0)

У меня это случалось много раз, в том числе с jQuery. Это не вина какой-либо библиотеки. setTimeout всегда работал вокруг него для меня.

Ответ 2

Задайте фокус в блоке try/catch.

Ответ 3

В предположении, я бы сказал, что вызов insertAfter путает IE DOM. Вы можете проверить код без вызова insertAfter? Это не так? Если нет, есть ли другой способ добиться такого же результата? Возможно, скопируйте узлы и удалите оригиналы вместо перемещения узлов?