Проблема с Google Chrome и Javascript.Гуру нужен! - PullRequest
0 голосов
/ 30 августа 2010

У меня странная проблема только в Chrome с использованием iframe, но работает во всех других распространенных браузерах.

проблема: если я наберу IFRAME и затем нажму кнопку отправки, все будет работать нормально, фокус снова вернется к IFRAME и курсор BLINK.

Но если я наберу и затем нажму ENTER, чтобы вызвать функцию обработчика событий, фокус вернется, но курсор исчезнет. И тогда, если вы идете в другое окно, а затем назад появляется курсор. Это происходит только в Chrome . Я сделал пример страницы, чтобы показать проблему в действии. Нажмите на ссылку ниже, чтобы увидеть.

ОБНОВЛЕНИЕ: я добавил код также здесь ниже

    var editorFrame = 'myEditor'

function addFrame() {

    var newFrame = new Element('iframe', {
        width: '520', 
        height: '100',
        id: editorFrame,
        name: editorFrame,
        src: 'blank.asp',
        class: 'myClass'
    });

    $('myArea').appendChild(newFrame);

    window.iframeLoaded = function() {
        // this is call-back from the iframe to be sure that is loaded, so can safety attach the event handler

        var iframeDoc, UNDEF = "undefined";
        if (typeof newFrame.contentDocument != UNDEF) {
            iframeDoc = newFrame.contentDocument;
        } else if (typeof newFrame.contentWindow != UNDEF) {
            iframeDoc = newFrame.contentWindow.document;
        }
        if (typeof iframeDoc.addEventListener != UNDEF) {
            iframeDoc.addEventListener('keydown', keyHandler, false);
        } else if (typeof iframeDoc.attachEvent != UNDEF) {
            iframeDoc.attachEvent('onkeydown', keyHandler);  
        }
    };
}

function resetContent() 
{   
    var myIFrame = $(editorFrame);

    if (myIFrame) myIFrame.contentWindow.document.body.innerHTML='';
}

function setEditFocus() 
{

    var iFrame = document.frames ? document.frames[editorFrame] : $(editorFrame);
    var ifWin = iFrame .contentWindow || iFrame;

    ifWin.focus();

}

function send()
{
    resetContent();
    setEditFocus(); 
}

function keyHandler (evt) {

    var myKey=(evt.which || evt.charCode || evt.keyCode)

    if (myKey==13)  {

        if (!evt) var evt = window.event;

        evt.returnValue = false;

        if (Prototype.Browser.IE) evt.keyCode = 0;

        evt.cancelBubble = true;

        if (evt.stopPropagation) evt.stopPropagation();

        if (evt.preventDefault) evt.preventDefault();

        send();

    }
}

На странице HTML

<body onload="addFrame()">

<div id="myArea"></div>
<input id="myButton" type="button" value="click me to send [case 1]" onclick="send()">

Чтобы упростить понимание проблемы, я создал специальную страницу для воспроизведения проблемы с полным примером и источником.

Вы можете просмотреть здесь с помощью Google Chrome: пример проблемы

Мне действительно нужна ваша помощь, потому что я пытался решить эту проблему в течение многих дней, но безуспешно. И все предложения, советы и обходные пути хорошо приняты.

Заранее спасибо.

Ответы [ 3 ]

3 голосов
/ 30 августа 2010

Я не совсем уверен, в чем причина проблемы, поскольку в некоторых случаях Chrome будет правильно фокусировать элемент, хотя в большинстве случаев это не так. Вам вообще не нужно запрашивать фокусировку, так как при нажатии клавиши фокус не теряется. Если вы пропустите вызов setEditFocus(), вы должны заметить, что он по-прежнему работает правильно во всем, кроме Chrome, который, очевидно, обижается, что вы удалили весь контент в теле.

Когда вы устанавливаете contenteditable, каждый браузер устанавливает innerHTML элемента body документа iframe на что-то другое:

Browser           | innerHTML
-----------------------------
Internet Explorer | ''
Opera             | '<br>\n'
Firefox           | '<br>'
Chrome/Safari     | '\n'

Если вы не ожидаете увидеть этот дополнительный материал при последующем анализе содержимого, вы можете удалить его заранее в addFrame().

Мне удалось «исправить» проблему, выполнив следующие действия:

Сначала обновите обработчик событий, чтобы мы могли вернуть в него false и запретили Opera генерировать HTML для удовольствия, когда мы вызываем getSelection() позже ...

function addFrame() {
    ...
    window.iframeloaded = function() {
       ...
       if (typeof iframeDoc.addEventListener != UNDEF) {
           iframeDoc.addEventListener('keypress', keyHandler, false);
       } else if (typeof iframeDoc.attachEvent != UNDEF) {
           iframeDoc.attachEvent('onkeypress', keyHandler);
       }
    }
}

Редактировать: Удалена оригинальная функция в пользу новой, включенной ниже

Наконец, верните false из обработчика нажатия клавиш, чтобы исправить проблему Opera, упомянутую выше.

function keyHandler (evt) {
    var myKey=(evt.which || evt.charCode || evt.keyCode)

    if (myKey==13) {
        ...
        return false;
    }
}

Изначально я делал то, что предлагал syockit , но обнаружил, что он делает странные вещи с размером каретки в Chrome, чего этот метод, похоже, избегает (хотя Firefox все еще немного отключен ...) , Если вам это безразлично, установка непустого значения innerHTML, вероятно, является более простым решением.

Также обратите внимание, что вы должны использовать className вместо class в объекте, который вы передаете new Element(), так как IE, кажется, считает его зарезервированным словом и говорит, что это синтаксическая ошибка.

Редактировать : Поэкспериментировав, кажется, следующая функция надежно работает в IE8 / Firefox / Chrome / Safari / Opera для более продвинутого теста. К сожалению, мне пришлось включить обнаружение браузера Prototype в учетную запись Opera, поскольку, хотя в отношении JavaScript все выглядит одинаково, для реального поведения требуется другой код, конфликтующий с другими браузерами, и я не смог найти лучший способ различать их.

Вот новая функция, которая фокусируется на редактируемом контенте iframe и гарантирует, что, если там уже есть контент, каретка перемещается в конец этого контента:

function focusEditableFrame(frame) {
    if (!frame)
        return;

    if (frame.contentWindow)
        frame = frame.contentWindow;

    if (!Prototype.Browser.Opera) {
        frame.focus();

        if (frame.getSelection) {
            if (frame.document.body.innerHTML == '')
                frame.getSelection().extend(frame.document.body, 0);
            else
                frame.getSelection().collapseToEnd();
        } else if (frame.document.body.createTextRange) {
            var range = frame.document.body.createTextRange();

            range.moveEnd('character', frame.document.body.innerHTML.length);
            range.collapse(false);
            range.select();
        }
    } else {
        frame.document.body.blur();
        frame.document.body.focus();
    }
}

Обновлено setEditFocus() (сейчас не обязательно, но так как оно у вас уже есть):

function setEditFocus()
{
    focusEditableFrame($(editorFrame));
}
1 голос
/ 30 августа 2010

Вы знаете, как я решил это? В resetContent() замените '' на ' ':

if (myIFrame) myIFrame.contentWindow.document.body.innerHTML=' ';

Если это работает, хорошо. Не спрашивайте, почему, хотя, это может быть один из тех глюков Webkit с объектом Range, если хотите, подайте ошибку

0 голосов
/ 30 августа 2010

Очень быстро, вы можете попробовать добавить точку с запятой в конец строк внутри вашей функции send ()?И посмотри, работает ли это.

function send() {
  resetContent();
  setEditFocus();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...