Greasemonkey: WebExt: Skripte bei allen drei runAt-Zeiten ausführen

Erstellt am 27. Feb. 2017  ·  6Kommentare  ·  Quelle: greasemonkey/greasemonkey

Entwickeln Sie einen Arbeitsplan für die Ausführung von Benutzerskripten, die natürlich erst zur Laufzeit bekannt sind. Kompatibel mit allen drei RunAt-Zeiten - kritisch document_start .

Siehe https://github.com/arantius/greasemonkey/tree/8a255bde1aa6312715740fd0157d582a2d6cb183 für meine bisherigen Recherchen, wo der Ansatz ist:

  • Verwenden Sie ein Hintergrundskript. (Es hat Zugriff auf Speicher-APIs, auf denen die Skripte gespeichert sind, und kann so den Inhalt der auszuführenden Skripte kennen.)
  • Beobachte etwas ( was? ), um auszulösen..
  • .. rufen Sie tabs.executeScript() auf, um jedes Benutzerskript abzufeuern.

Dies "funktioniert", außer dass ich noch kein Ereignis gefunden habe, das für alle drei Laufzeiten funktioniert. Da ist webNavigation 's onBeforeNavigate was eigentlich zu früh ist , es feuert (wie der Name schon sagt) vor der Navigation, wenn das aktuelle Dokument noch aktiv ist. Aber der nächste Punkt ist onCommitted , und an diesem Punkt ist es zu spät für den Start, Inline-Skripte wurden bereits ausgeführt.

wontfix

Alle 6 Kommentare

Forschen:

  • Beobachte webRequest statt webNavigation . Gibt uns das einen Griff zur Startzeit?
  • Fügen Sie bei document_start für jede Seite ein Webext-Inhaltsskript ein. Haben Sie es irgendwie wissen, welche Skripte synchron ausgeführt werden sollen. (Weil alles, was asynchron ist, uns über die Startzeit hinausschieben würde.)

Betreff: https://bugzilla.mozilla.org/show_bug.cgi?id=1332273#c8

Ich möchte in der Lage sein, (im Hintergrund) einen Blob zu speichern, später (nur) seine URL zu erhalten und diese URL (synchron) an Inhaltsskripte weiterzugeben, aber ich kenne keine Möglichkeit, eines dieser Dinge zu tun.

Ich habe nicht alle Details selbst ausgearbeitet, aber ich denke, die Hintergrundseite könnte Blobs in IndexedDB speichern, sie dann zum Startzeitpunkt über URL.createObjectURL() in Blob-URIs konvertieren und sie an die hypothetische synchrone Konfigurations-API übergeben und dann vielleicht lade sie über

Ist IndexedDB im privaten Browsermodus deaktiviert ?

Ich glaube nicht, dass sich das auf die Hintergrundskripte auswirkt?

Dies ist möglich, indem Sie ein Inhaltsskript verwenden, das unter document_start und ungefähr so ​​​​aussieht: (funktioniert möglicherweise nicht für bereits geladene Tabs, verwenden Sie dafür jQuery)

// execute `document_start` scripts here...

document.addEventListener("DOMContentLoaded", event => {
    // execute `document_end` scripts here...
});

window.addEventListener("load", event => {
    // execute `document_idle` scripts here...
});

oder so ähnlich: (könnte fehleranfälliger sein)

let run = [false, false, false];

document_start();

if (document.readyState === "complete") {
    document_idle();
} else if (document.readyState === "interactive") {
    document_end();
}

document.onreadystatechange = () => {
    switch (document.readyState) {
        case "loading":     break;
        case "interactive": document_end();
        case "complete":    document_idle();
    }
};

function document_start() {
    if (run[0]) return;
    run[0] = true;

    // execute `document_start` scripts here...
}

function document_end() {
    if (!run[0]) document_start();
    if (run[1])  return;
    run[1] = true;

    // execute `document_end` scripts here...
}

function document_idle() {
    if (!run[1]) document_end();
    if (run[2])  return;
    run[2] = true;

    // execute `document_idle` scripts here...
}

Eine andere Möglichkeit besteht darin, drei separate Inhaltsskripte zu verwenden, von denen jedes zu einem anderen Zeitpunkt ausgeführt wird.
Dafür enthält das manifest.json folgendes: (funktioniert wahrscheinlich (kann eine Race-Bedingung haben))

"content_scripts": [
    {
        "matches": ["<all_urls>"],
        "run_at": "document_start",
        "js": ["document_start_handler.js"]
    },
    {
        "matches": ["<all_urls>"],
        "run_at": "document_end",
        "js": ["document_end_handler.js"]
    },
    {
        "matches": ["<all_urls>"],
        "run_at": "document_idle",
        "js": ["document_idle_handler.js"]
    }
]

Es ist auch möglich, jQuery zu verwenden, was möglicherweise der am wenigsten fehleranfällige Weg ist, aber dies alles erfordert umfangreiche Tests: (läuft wieder bei document_start , muss aber mit jQuery gebündelt werden)

function document_start() {
    // execute `document_start` scripts here...
}

function document_end() {
    // execute `document_end` scripts here...
}

function document_idle() {
    // execute `document_idle` scripts here...
}

// Use jQuery to execute all the functions:
document_start();

// `$(document).ready(document_end)` is deprecated since 3.0
$(document_end);

// jQuery used to have a method for this: `$(window).load(document_idle)`
if (document.readyState === "complete") {
    document_idle();
} else {
    $(window).on("load", document_idle);
}

Wie geschrieben, ist dieses Thema zu weit gefasst. Ich teile dies in separate Probleme auf, um leichter nachverfolgt zu werden:

2525, #2526

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen