Временное удаление обработчика «onblur» в IE - PullRequest
1 голос
/ 10 марта 2011

Интересно, может ли кто-нибудь здесь помочь мне разобраться с этой проблемой.

Мне нужно временно отключить код в атрибуте «onblur» поля ввода, а затем снова включить его. Причина, по которой мне нужно это сделать, потому что мой рабочий процесс следующий:

1) Событие AJAX инициируется атрибутом «onblur» поля ввода, что является результатом того, что пользователь ушел с поля, чтобы перейти к следующему.
2) Страница обновлена, и мой код Javascript вызывается из ловушки " onafterajax ".
3) Мой код выполняет серьезную реорганизацию DOM, что приводит к потере фокуса на текущем поле ввода. Итак, я должен восстановить фокус вручную. Я подключил обработчик фокуса ко всем полям ввода, чтобы я мог отслеживать, какое поле имело фокус в последний раз, и поэтому я знаю, куда поместить фокус. 4) Я вызываю .focus () в правильном поле ввода, что по какой-то причине вызывает ' onblur ' в этом же поле ввода. Это происходит во всех браузерах. Это а) говорит о том, что поле все еще было в фокусе ?! и б) Создает бесконечный цикл, так как Шаг 1 выполняется снова ...

Чтобы избежать бесконечного цикла, я сделал следующее. Перед выполнением любых перестановок DOM я делаю это:

if ( window.currentFocusId ) {
   this.savedFocusId = currentFocusId;

   this.onblur_bak = $(this.savedFocusId).onblur;
   $(this.savedFocusId).onblur = null;
   LOG.warn(" --- Disabling blur on " + this.savedFocusId);
}

Затем, после того, как я завершил хакерство DOM, я делаю это:

setFocusAndRestoreBlur : function(req) {
    if ( this.savedFocusId ) {
      var focusElement = req.form.elements[this.savedFocusId];
      LOG.warn(" ------ Focusing on " + focusElement.id);
      if (focusElement) {
        focusElement.focus();
        if (focusElement.select) {
          focusElement.select();
        }
      }

      LOG.warn(" ---  Enabling blur on " + this.savedFocusId);
      $(this.savedFocusId).onblur = this.onblur_bak;

      delete this.onblur_bak;
      delete this.savedFocusId;
    }
}

Это хорошо работает во всех браузерах (FF, Chrome, Opera), кроме IE6.

В IE6 работает . Прежде всего, чтобы он вообще работал в IE, мне пришлось изменить вызов на « setFocusAndRestoreBlur », например, так:

setTimeout(function() {
  this.setFocusAndRestoreBlur(req);
}.bind(this), 0)

Это приводит к запуску кода после завершения текущего потока. По какой-то причине IE не учитывает тот факт, что я удалил обработчик onblur , если я пытаюсь установить фокус в том же потоке!

Итак, с этой модификацией, когда я впервые ввожу несколько чисел в несколько полей, все в порядке. Я получаю вывод журнала, который выглядит так:

Введите что-нибудь в j_id390 и выключите:

warn[16:35:33,091]: blur fired from statementProgramsDataTable:0:j_id390
warn[16:35:33,092]: --- Disabling blur on statementProgramsDataTable:0:j_id397
warn[16:35:33,225]: ------ Focusing on statementProgramsDataTable:0:j_id397
warn[16:35:33,225]: --- Enabling blur on statementProgramsDataTable:0:j_id397

Введите что-нибудь в j_id397 и выключите:

warn[16:35:38,259]: blur fired from statementProgramsDataTable:0:j_id397
warn[16:35:38,260]: --- Disabling blur on statementProgramsDataTable:0:j_id446
warn[16:35:38,390]: ------ Focusing on statementProgramsDataTable:0:j_id446
warn[16:35:38,390]: --- Enabling blur on statementProgramsDataTable:0:j_id446

Однако, когда я возвращаюсь к первому полю ввода, перезаписываю значение и убираю вкладку, я получаю это:

warn[17:18:15,454]: blur fired from statementProgramsDataTable:0:j_id390
warn[17:18:15,469]:  --- Disabling blur on statementProgramsDataTable:0:j_id397
warn[17:18:16,870]:  ------ Focusing on statementProgramsDataTable:0:j_id397
warn[17:18:16,874]:  ---  Enabling blur on statementProgramsDataTable:0:j_id397
warn[17:18:18,097]: blur fired from statementProgramsDataTable:0:j_id397
warn[17:18:18,112]:  --- Disabling blur on statementProgramsDataTable:0:j_id397
warn[17:18:19,550]:  ------ Focusing on statementProgramsDataTable:0:j_id397
warn[17:18:19,555]:  ---  Enabling blur on statementProgramsDataTable:0:j_id397
warn[17:18:24,492]: blur fired from statementProgramsDataTable:0:j_id397 
warn[17:18:24,187]:  --- Disabling blur on statementProgramsDataTable:0:j_id397
warn[17:18:24,531]:  ------ Focusing on statementProgramsDataTable:0:j_id397
warn[17:18:24,545]:  ---  Enabling blur on statementProgramsDataTable:0:j_id397

Большую часть времени этот цикл продолжается для переменного числа итераций и затем останавливается с правильно сфокусированным полем ввода. Я видел несколько раз, когда цикл казался бесконечным.

Похоже, IE опять не уважает отсутствие обработчика onblur ? Но только иногда?!

Итак, вот где я запутался. Почему IE ведет себя непоследовательно? Что я делаю неправильно? Есть ли лучший способ?

Любые идеи приветствуются.

Val

РЕДАКТИРОВАТЬ:

Я попробовал подход, предложенный JeanK. Это все еще не работает, но я узнал кое-что потенциально полезное из этой попытки.

Я обертываю оригинальную функцию onblur с прокси, как это:

this.allowBlur = false;
if ( !this._functionsEqual($(this.savedFocusId).onblur, this._proxiedBlur) ) {
  $(this.savedFocusId).onblur = this.proxyOnBlur($(this.savedFocusId).onblur);
}

И сама функция прокси:

proxyOnBlur : function(method) {
  var object = this;

  this._proxiedBlur = function(event) {
    if ( object.allowBlur ) {
      return method.apply(this, [event || window.event])
    }
  };

  return this._proxiedBlur;
},

Теперь все, что мне нужно сделать, это установить this.allowBlur в качестве самой последней вещи , и я должен быть в порядке. И в этом заключается проблема. Во всех других браузерах событие onblur вызывается при изменении дерева DOM, поэтому оно корректно блокируется. Но в IE6, что бы я ни делал, он запускает событие onblur после всего моего кода. Я даже попробовал это:

setTimeout(function() {
  this.allowBlur = true;
}.bind(this), 2)

и мой this._proxiedBlur по-прежнему вызывается после того, как я установил флаг в true!

Итак, возникает вопрос - Куда мне нужно поместить сброс флага, чтобы он выполнялся после того, как IE6 отреагирует на изменения DOM?

Ответы [ 2 ]

1 голос
/ 12 марта 2011

хорошо, я понял это.Хитрость заключалась в том, чтобы установить фокус в отдельном потоке:

                setTimeout(function() {
                    this.setFocusAndRestoreBlur(req);
                }.bind(this), 0)

, а затем сбросить флаг с помощью другого вложенного setTimeout () .Это похоже на правильную последовательность событий в IE6:

setFocusAndRestoreBlur : function(req) {
  setFocus(req);

  setTimeout(function() {
    this.allowBlur = true;
  }.bind(this), 0)
}
0 голосов
/ 10 марта 2011

Я предлагаю отключить размытие логическим способом.

Я имею в виду, что-то вроде этого:

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

function myOnBlur() {
  if (ableToExecute) {
    executeWhatYouNeed();
  }
}

Итак, когда вы выполняете запрос, вы устанавливаете флаг в значение false, а затем после ответа и необходимой обработки вы сбрасываете квартиру в значение true, чтобы ваше событие onblur могло снова инициировать ваш запрос.

Я не знаю, может ли этот простой элемент управления помочь вам, но вы можете попробовать его.

...