Заменить полный HTML на SDK дополнения mozilla

Есть ли способ заменить весь HTML и добавить дополнительные файлы javascript с помощью SDK надстроек Mozilla?

В Chrome это можно сделать, запустив скрипт в «document_start», остановив окно и заменив полный HTML-код ответом XHR. Я не понимаю, почему это так сложно, но я могу жить с этим. Насколько я понимаю, в дополнении SDK есть модуль page-mod, который предназначен для «запуска скриптов в контексте веб-страниц, URL-адрес которых соответствует заданному шаблону». Так что теоретически это должно быть сделано с помощью модуля page-mod, но я не нашел ни одного примера, который бы полностью переопределял весь HTML. Теоретически window.stop и полная замена HTML должны работать и здесь, но я не могу получить доступ к файлам аддона (бэкенда) из контекста веб-страницы (интерфейса). В Chrome это делается через «web_accessible_resources» в манифесте и chrome.extension.getURL. Через firefox я не могу использовать что-либо, связанное с аддоном SDK через интерфейс, поэтому self.data.url не работает...


person inf3rno    schedule 19.06.2015    source источник


Ответы (1)


Я попытался отправить содержимое файла таким образом (поскольку доступ к файлу аддона был запрещен firefox из внешнего интерфейса):

index.js

var pageMod = require("sdk/page-mod");
var data = require("sdk/self").data;

pageMod.PageMod({
    include: ["http://example.com/", "http://example.com/index.html"],
    contentScriptFile: "./inject.js",
    contentScriptWhen: "start",
    onAttach: function (worker){
        console.log("injector attached");
        worker.port.emit("inject", {
            "index.html": data.load("client/index.html"),
            "main.js": data.load("client/main.js")
        });
    }
});

inject.js

!function () {
    self.port.on("inject", function (files) {
        console.log("injector trigger");
        if (typeof hasRun == 'undefined') {
            console.log("injecting");
            hasRun = true;
            window.stop();
            var html = files["index.html"].replace("<script src=\"./main.js\"></script>", "<script>"+files["main.js"]+"</script>");
            document.documentElement.innerHTML = html;
        }
    });
}();

Если я заменю HTML на привет, мир, тогда это сработает. Таким образом, HTML-код кажется недействительным, но я не получил сообщения об ошибке, и консоль показывает пустой HTML-скелет (у меня есть пустая страница). Тот же код index.html и main.js работает с плагином Chrome, который я хочу использовать в Firefox. Единственная дополнительная вещь плагина Chrome, что некоторые js-файлы отменяются, поэтому они наверняка не загружаются до остановки окна. Пробовал делать так же, но может не получилось, не знаю.

index.js

let { Ci, Cu } = require('chrome');

Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");

var observer = {
    QueryInterface: XPCOMUtils.generateQI([
        Ci.nsIObserver,
        Ci.nsISupportsWeakReference
    ]),

    observe: function (subject, topic, data) {
        if (topic == "http-on-opening-request" &&
            subject instanceof Ci.nsIHttpChannel) {
            var uri = subject.URI;
            if (uri.host == "example.com" && /some\.js/.test(uri.path))
                subject.cancel();
        }
    }
};

Services.obs.addObserver(observer, "http-on-opening-request", true);

Subject.cancel() запускается файлом some.js. Если я добавлю ведение журнала:

            console.log("cancelling", uri.path);
            subject.cancel();
            console.log("cancelled");

Тогда в консоли не появляется «отменено», а только «отмена, /some.js». Я не знаю, нормально ли это, но я не получил сообщения об ошибке.

Попробовав это с обычной веб-страницей HTML

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
</head>
<body>
    <script>
    //<![CDATA[
        !function (){
            window.stop();
            var html = '<!DOCTYPE html>\n<html>\n<head>\n    <meta charset="utf-8">\n</head>\n<body>\n  <script>console.log("loaded");</script>\ntext\n</body>\n</html>';
            document.documentElement.innerHTML = html;
        }();
    //]]>
    </script>
</body>
</html>

Я получил синтаксическую ошибку незавершенного строкового литерала, что еще смешнее. Я предполагаю, что код инжектора почему-то не работает должным образом, если он содержит javascript, так что я думаю, что это не проблема, связанная с аддоном. Если я использую <\/script>, то все в порядке, но скрипт console.log("loaded"); не запускается. В хроме он работает, так что я думаю, что это проблема.

Я добавил jquery в «contentScriptFile» и использовал $("html").html(html) вместо document.documentElement.innerHTML = html. Теперь он запускает сценарии, но все еще не работает должным образом.

Добавлено исправление с помощью функции cancel():

let { Ci, Cu, Cr } = require('chrome');
//...
subject.cancel(Cr.NS_BINDING_ABORTED);

У отмены есть требуемый параметр состояния, но он молча терпит неудачу, когда не получает его. Теперь отмена файлов тоже работает, но плагин все равно где-то глючит. :С

Я думаю, что написанный мной инжектор работает отлично, и проблема заключается в инжектируемых файлах HTML и js. Я не собираюсь их отлаживать (поскольку $.load использует eval, так что это будет очень сложно), я отправил код разработчикам плагинов для chrome, может они как-то поправят.

person inf3rno    schedule 19.06.2015