Измените код страницы javascript (TamperMonkey), чтобы отправлять нажатия клавиш на родительский DOM - PullRequest
1 голос
/ 06 апреля 2020

У меня есть страница, которая использует виджет TradingView, в котором вы можете ввести любую клавишу на клавиатуре, чтобы запустить поиск символов. Я использовал отладчик Chrome для точки останова и точно знал, какая строка кода это делает. Я хочу, чтобы ключевое событие передавалось в общую DOM для обработки моей собственной пользовательской функцией.

Как это сделать? Любой пример кода будет оценен. Вот фрагмент кода из TradingView ('t' - ключевое событие):

            a || (o.handle = a = function(t) {
                return s === Te || t && Te.event.triggered === t.type ? s : Te.event.dispatch.apply(a.elem, arguments)
            }

Поэтому вместо оператора return я хочу отправить это ключевое событие моей собственной функции. Полный код TradingView, где этот код: https://static.bitmex.com/assets/tradingView/static/tv-chart.min-6ce28e05fd34b9cf06a4e63b29980a72.js

1 Ответ

1 голос
/ 06 апреля 2020

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

document.body.addEventListener('keypress', fn);

do

document.body.addEventListener('keypress', fn, true);

он будет запущен до того, как событие переместится на внутренний элемент.

Если прослушиватель страницы включен внутренний элемент должен быть завершен до запуска fn, вы можете вызвать fn после небольшого setTimeout:

document.body.addEventListener('keypress', () => setTimeout(fn), true);

Если вы также хотите предотвратить запуск кода виджета, убедитесь, что чтобы вызвать stopPropagation в прослушивателе захвата, чтобы событие не переместилось в виджет:

const fn = (event) => {
  event.stopPropagation();
  // rest of code
};

Если контейнер, в который вы отправляете ключевое событие, находится внутри iframe, родительское окно выиграло вообще не видите событие из-за проблем безопасности.

На большинстве страниц вы сможете сообщить о событии родителю с помощью postMessage, например:

// ==UserScript==
// @name             0 New Userscript
// @include          https://www.bitmex.com/app/trade/XBTUSD
// @include          https://static.bitmex.com/chartEmbed*
// @grant            GM_getValue
// @run-at document-start
// ==/UserScript==

if (window.location.host === 'www.bitmex.com') {
  const mainFn = () => {
    console.log('b');
  };
  // We're on the top level
  const keydown = (e) => {
    e.stopPropagation();
    if (!e.altKey && e.key === 'b') {
      mainFn();
    }
  };
  window.addEventListener('keydown', keydown, true);
  window.addEventListener('message', (e) => {
    if (e.origin === 'https://static.bitmex.com' && e.data === 'keydown inside iframe') {
      mainFn();
    }
  });
} else {
  // We're in the iframe
  // When a keypress is detected, message the parent window
  const keydown = (e) => {
    console.log('iframe kd');
    e.stopPropagation();
    if (!e.altKey && e.key === 'b') {
      window.top.postMessage('keydown inside iframe', '*');
    }
  };
  window.addEventListener('click', keydown, true);
}

@run-at document-start необходим, потому что у iframe есть CSP, который запрещает запуск пользовательских скриптов без него .

Но, к сожалению, есть еще одна проблема: в этом В конкретном случае окно iframe также перезаписывает EventTarget.prototype.addEventListener на странице объявление, прежде чем пользовательский скрипт сможет запустить. Хотя вы можете обычно использовать // @run-at document-start, чтобы сохранить ссылку на переменную до того, как сценарий страницы перезапишет ее, в iframe это невозможно; Chrome usercripts в iframes не может работать в самом начале загрузки страницы.

Без ссылки на EventTarget.addEventListener (или EventTarget.prototype.onclick или EventTarget.prototype.onkeydown setters, et c) нет способа получить доступ к API уровня браузера, который регистрирует действия пользователя.

Я не думаю, что то, что вы ищете, возможно в Tampermonkey.

...