Как захватить события keybd на уровне документа, но позволить редактируемым полям иметь свои события? - PullRequest
0 голосов
/ 27 июня 2011

РЕДАКТИРОВАТЬ: Поскольку никто не ответил, я постараюсь изложить свой вопрос более кратко. При обработке нажатий клавиш на странице браузера (например, влево / вправо / пробел), как определить, будет ли нажатие клавиши обрабатываться элементом на странице браузера, который имеет фокус или будет ли не обрабатываться этим объектом, и будет ли нормально обрабатывать его глобально? В идеале вы должны позволить объекту фокусировки видеть нажатие клавиши и иметь возможность определить, обрабатывал ли он его или нет. Если нет, то вы можете обработать это самостоятельно. Если бы он обрабатывал это, вы бы ничего с этим не делали (предполагая, что объект фокусировки имеет более важное использование для нажатия клавиш).

Вот типичный пример не в браузере. Представьте, что у вас есть диалоговое окно Windows, в котором есть набор типичных элементов управления диалогового окна, пара кнопок и богатый элемент управления для редактирования. Если вы находитесь в типичном диалоговом окне, клавиша Enter на клавиатуре активирует кнопку OK в диалоговом окне и примет изменения в диалоговом окне. Если вы находитесь в элементе управления rich edit, клавиша Enter вводит новую строку. Диалоговое окно каким-то образом может сказать, хочет ли текущий элемент управления в диалоговом окне обработать клавишу ввода или он должен обрабатываться глобально.

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

Я понимаю, что могу посмотреть на исходную цель события и «попытаться» выяснить, способна ли эта цель обрабатывать стрелки влево / вправо (ввод, текстовое поле, contenteditable и т. Д.), Но я надеялся на более надежный метод. Есть ли способ обрабатывать нажатие клавиш на уровне документа ТОЛЬКО тогда, когда он не обрабатывается объектом на веб-странице. Теперь в моем обработчике клавиатуры YUI я получаю все события клавиатуры, даже те, которые фактически будут обрабатываться целевым объектом.

Вот как теперь выглядит мой код, и я ищу более элегантный способ сделать это, не требующий функции ObjectWantsKeys, которая является несколько хрупкой:

JF.Slideshow.prototype._HookupKeyNav = function () {
    var k = YAHOO.util.KeyListener;
    var key = k.KEY;
    // see if keyboard handling is enabled or not
    if (((this._config.keyboardNav == "auto") && (JF.SlideshowCnt <= 1)) || (this._config.keyboardNav == "on")) {
        this._keyListener = new YAHOO.util.KeyListener(
        document, {
            ctrl: false,
            shift: false,
            alt: false,
            keys: [key.LEFT, key.RIGHT, key.SPACE]
        }, {
            fn: this._HandleKeys,
            scope: this,
            correctScope: true
        });
        this._keyListener.enable();
    }
}
JF.Slideshow.prototype._HandleKeys = function (type, args, obj) {
    var keyCode = args[0];
    var event = args[1];
    var target = event.srcElement || event.target;
    if (JFL.ObjectWantsKeys(target)) return; // if the current focus object wants keystrokes, then we shouldn't process them
    var key = YAHOO.util.KeyListener.KEY;
    switch (keyCode) {
    case key.LEFT:
        this.Back();
        break;
    case key.RIGHT:
        this.Forward();
        break;
    case key.SPACE:
        this.StartStopToggle();
        break;
    default:
        break;
    }
}
JFL.ObjectWantsKeys = function (o) {
    // list of HTML object types that want the keystroke if they have focus
    var list = {
        "input": true,
        "textarea": true
    };
    try {
        // unfortunately o.contentEditable set to an empty string means it is editable so we need this more complicated comparision
        if ((typeof o.contentEditable !== "undefined") && (o.contentEditable === "true" || o.contentEditable === true || o.contentEditable === "")) {
            return (true); // focus object is editable
        }
        if (o.tagName && list[o.tagName.toLowerCase()]) {
            return (list[o.tagName.toLowerCase()]); // focus object can take keys
        }
    } catch (e) {}
    return (false);
}

1 Ответ

1 голос
/ 15 июля 2011

Я решил эту проблему, проверив тип элемента с фокусом:

var tag = document.activeElement.tagName;
if (tag == "INPUT" || tag == "TEXTAREA")
  return;

Это не было идеально, потому что я также не хотел, чтобы KeyListener обрабатывал нажатия клавиш, когда был YAHOO.widget.Dialogотображается (что даст имя тега "BODY").Мне пришлось что-то скинуть вместе, используя YAHOO.widget.OverlayManager и проверить активный диалог.Если оно пустое, я обрабатываю нажатие клавиши.

Это не элегантно, и я надеюсь на лучшее решение.Я разместил сообщение на форумах YUI:

http://yuilibrary.com/forum/viewtopic.php?p=26413

Если я получу ответ, он также может помочь вам.

...