Async document.write – костыль, или меняем код on-the-fly

Я не знаю, почему этот пост будет отнесен к категории “Сисадминство”, но категории “программирование” у меня тут нет. Мне просто лень открыть страницу и создать ее, распространяя хаос на этот блог. Давайте держать все организованным, хоть и не там, где надо.

Итак. Я реализую один очень интересный™ проект, и там встала проблема – скрипт загрузчика капчи надо грузить асинхронно через XMLHttpRequest, а в этом скрипте говнокод. А именно – document.write, чтобы размещали его просто в странице. Этот скрипт также вызывает уже саму капчу где, что бы вы думали? Тоже document.write!

Ну я конечно попробовал, но вот хуй там. Если раньше document.write из асинхронного запроса просто ломал DOM, то теперь нам вежливо намекают, что ты мудак:

Failed to execute ‘write’ on ‘Document’: It isn’t possible to write into a document from an asynchronously-loaded external script unless it is explicitly opened

Такие вот дела.

Что же делать? Ну первая мысль была о том, чтобы попробовать загрузить src скрипта асинхронно, поменять код и затем выполнить eval. Но нет, так нельзя, все бьется о Same-Origin-Policy.

Что же делать? А давайте вспомним величайшие возможности javascript по изменению всего и вся и переназначем функцию document.write.

Наверное на этом моменте я ***нулся.

document.write = function (text) {
    if (text.match(/_puzzle/)) {

        document.querySelector('#_scriptloader').innerHTML = (text);
        var script = document.createElement("script");

        script.type = "text/javascript";
        script.src = (document.querySelector("#_scriptloader script").src);
        document.querySelector('#_captcha').appendChild(script);
    } else {
        document.querySelector('#_captcha').innerHTML = (text)
    }
}

Просто берем и пишем в какой-либо div-плейсхолдер. Потом из этого дива берем src (ведь тупо вставкой кода в html асинхронно-загруженный html-код скрипта не выполнится, вы же помните это), создаем новый dom-объект script, и спокойно вставляем его в шапку или куда еще.

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

Итого, алгоритм следующий:

  1. Переопределить функцию document.write, чтобы она писала в какой-то скрытый div.
  2. Запросить target-страницу с <script src=blabla> с document.write.
  3. Вставить полученный <script src=blabla> в скрытый div.
  4. Создать пустой DOM-элемент script, установить ему src из div->script->src
  5. Добавить его в шапку или на страницу, он исполнится, вызывая переопреледенную document.write.
  6. Проверить, что там пришло в измененную функцию, и в зависимости от данных делать с ними что-либо.
  7. Начать сначала.

В п***у программирование, пойду выпью пива.

Leave a Reply

Your email address will not be published. Required fields are marked *