Обработайте фокус табуляции с перекрестным исходным кадром внутри модальной ловушки

#javascript #html #iframe

Вопрос:

Я пытаюсь решить проблему с вкладками внутри моего модала, когда присутствует перекрестное происхождение <iframe> .

Что я замечаю:

  1. Если iFrame не является первым или последним фокусируемым элементом в модале, нет необходимости устанавливать .focus() его с помощью javascript.
  2. Если iFrame является первым или последним фокусируемым элементом в модальном, мне нужно установить .focus() его с помощью javascript для обеспечения доступности клавиатуры.

.focus() ограничено в этом использовании. И поскольку я не могу установить фокус, ловушка для вкладок на модальной клавиатуре нарушена.

Кто-нибудь добился успеха в этой области?

Примеры HTML:

Работает (мне не нужно устанавливать фокус с помощью javascript на iframe)

 <input type="text" />
<iframe />
<input type="text" />
 

Если iframe является первым или последним фокусируемым элементом, мне нужно будет использовать javascript для установки фокуса, чтобы поддерживать модальную ловушку клавиатуры

 <input type="text" />
<iframe />
 

или

 <iframe />
<input type="text" />
 

язык JavaScript:

 var KEY = {
    TAB: 9,
  },
  allowedFocusableElements =
  'a[href], area[href], input:not([disabled]):not([type="hidden"]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, *[tabindex], *[contenteditable]';

function openDialog(e) {

  // Get focusable elements.
  dialogFocusableElements = dialog.querySelectorAll(allowedFocusableElements);
  dialogFirstElement = dialogFocusableElements[0];
  dialogLastElement = dialogFocusableElements[dialogFocusableElements.length - 1];

  document.addEventListener("keydown", processKeys);
}

function processKeys(event) {
  if (event.keyCode === KEY.TAB amp;amp; !event.shiftKey) {
    if (document.activeElement === dialogLastElement) {
      event.preventDefault();
      dialogFirstElement.focus();
    }
  } else if (event.keyCode === KEY.TAB amp;amp; event.shiftKey) {
    if (document.activeElement === dialogFirstElement) {
      event.preventDefault();
      dialogLastElement.focus();
    }
  }
}
 

Ответ №1:

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

Если iFrame является первым фокусируемым элементом, мы помещаем перед ним «псевдо» вкладываемый элемент, и аналогично, если это последний фокусируемый элемент, мы помещаем после него элемент с вкладками.

Вот этот конкретный фрагмент кода:

 var KEY = {
    TAB: 9,
  },
  allowedFocusableElements =
  'a[href], area[href], input:not([disabled]):not([type="hidden"]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, *[tabindex], *[contenteditable]';

function openDialog(e) {

  // Get focusable elements.
  dialogFocusableElements = dialog.querySelectorAll(allowedFocusableElements);
  dialogFirstElement = dialogFocusableElements[0];
  dialogLastElement = dialogFocusableElements[dialogFocusableElements.length - 1];

  // Tab helpers for iFrames.
  if (dialogFirstElement.tagName amp;amp; dialogFirstElement.tagName === "IFRAME") {
    iframeTabHelper = document.createElement("div");
    iframeTabHelper.setAttribute("tabindex", "0");
    iframeTabHelper.classList.add("iframe-helper-button");
    dialogFirstElement.parentNode.insertBefore(iframeTabHelper, dialogFirstElement);

    // Re-get focusable elements.
    dialogFocusableElements = dialog.querySelectorAll(
      allowedFocusableElements
    );
    dialogFirstElement = dialogFocusableElements[0];
  }

  if (dialogLastElement.tagName amp;amp; dialogLastElement.tagName === "IFRAME") {
    iframeTabHelper = document.createElement("div");
    iframeTabHelper.setAttribute("tabindex", "0");
    iframeTabHelper.classList.add("iframe-helper-button");
    dialogLastElement.parentNode.insertBefore(iframeTabHelper, dialogLastElement.nextSibling);

    // Re-get focusable elements.
    dialogFocusableElements = dialog.querySelectorAll(
      allowedFocusableElements
    );
    dialogLastElement = dialogFocusableElements[dialogFocusableElements.length - 1];
  }

  document.addEventListener("keydown", processKeys);
}

function processKeys(event) {
  if (event.keyCode === KEY.TAB amp;amp; !event.shiftKey) {
    if (document.activeElement === dialogLastElement) {
      event.preventDefault();
      dialogFirstElement.focus();
    }
  } else if (event.keyCode === KEY.TAB amp;amp; event.shiftKey) {
    if (document.activeElement === dialogFirstElement) {
      event.preventDefault();
      dialogLastElement.focus();
    }
  }
}
 

Не идеально, но поддерживает работу клавиатуры и функцию ловушки.

Вероятно, можно было бы добавить некоторые проверки, чтобы проверить , действительно ли iFrame имеет перекрестное происхождение, или, что еще лучше, переписать, чтобы проверить, есть ли какой-либо элемент, который ограничивает применение .focus() , а не только iFrames.