Довольно часто я сталкиваюсь с тем, что сторонние сайты работают не совсем так, как я бы хотел. И будучи web-программистом я пытаюсь на это дело как-то повлиять. Но одно дело, скажем, стили сайту подправить, и совсем другое вмешаться в его работу JavaScript
-ом. Эта заметка о втором.
Итак. На этот раз жертвой пал puzzle-english
. Ресурс для изучения английского. Среди прочего там есть возможно уникальная возможность тренировать аудирование на небольших заранее заготовленных фразах, записанных от нескольких дикторов. Предлагается на выбор по 3-5 слов на каждое произнесённое слово. Итого ты или кликаешь по кнопкам мышью, собирая фразу, или с клавиатуры клавишами цифр. Всё бы ничего, если бы не отсутствие поддержки чисел с num-панели
. Поддерживаются только те, что над буквами. Что, лично для меня, страшно неудобно. Ну что ж, приступим.
Для начала я решил узнать как оно там вообще работает. Посмотрел все eventListener
-ы на document
и нашёл нужный методом перебора при debug-е.
Он слушает keydown
и несколько неуклюже обрабатывает event.which
, поддерживая только один диапазон для чисел. Поиграл с ним и понял, что при “патченном” which num-цифры работают прекрасно. Написал небольшой скрипт в консоли примерно следующего толку и решил что дело в шляпе:
document.addEventListener('keydown', evt => { if(evt.which > 96 && evt.which < 105) { const which = evt.which - 48; $.event.trigger( { type: 'keydown', which, originalEvent: { target: document.body } }); } });
Забыл упомянуть, puzzle-english
агрессивно использует jQuery
. Чем я не применул воспользоваться. Там ведь свои обёртки и свои рецепты. Обернул этот код расширением и… Обломался. Chrome
не позволяет использовать со страницы жертвы ничего кроме DOM
. Т.е. доступа к jQuery
нет, доступа к любым кастомным window-полям
тоже нет. Ничего нет.
Ну не беда, подумал я и решил организовать keydown
средствами браузера. Что у нас там есть? document.createEvent
и initKeyboardEvent
. Поковырялся — работает плохо. Да ещё и deprecated
. Ок, а как ещё можно? Ага, у нас есть класс KeyboadEvent
. Ok:
new KeyboardEvent('keydown', { which: 50 });
Ага. Нифига. В документации одно, в браузере другое. Плевал он на which
и прочие поля. Что пишут нам интернеты? Ух, дичь какая… Зато работает:
window.evt = evt = document.createEvent("KeyboardEvent"); evt.initKeyboardEvent('keydown', true, false, null, 0, false, 0, false, which, 0); evt.__defineGetter__('which', () => which); document.dispatchEvent(evt);
Правда только из консоли. Почему? Потому что браузер заменяет отправленные из расширения события их копиями в основной тред. В целях безопасности. И того мы снова теряем which
.
Что в итоге? В итоге вспомнил, что там ещё мышью можно было кликать. Стало быть можно эмулировать клик. Просто вызвав у DOMElement
-а метод click
. С этим уже граблей не было.
В общем мораль такова: расширения скованы цепями. Попытки сделать что-то просто — могут упереться в открытые баги или просто запреты. Так и живём ;)