Detect-Nav

Detect url change on Chrome/Firefox (Greasemonkey, Firemonkey, Violentmonkey, Tampermonkey)

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Greasemonkey lub Violentmonkey.

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Violentmonkey.

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Violentmonkey.

Aby zainstalować ten skrypt, wymagana będzie instalacja rozszerzenia Tampermonkey lub Userscripts.

You will need to install an extension such as Tampermonkey to install this script.

Aby zainstalować ten skrypt, musisz zainstalować rozszerzenie menedżera skryptów użytkownika.

(Mam już menedżera skryptów użytkownika, pozwól mi to zainstalować!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Musisz zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

(Mam już menedżera stylów użytkownika, pozwól mi to zainstalować!)

// ==UserScript==
// @name         Detect-Nav
// @description  Detect url change on Chrome/Firefox (Greasemonkey, Firemonkey, Violentmonkey, Tampermonkey)
// @author       GTK
// @namespace    https://greasyfork.org/en/users/1352961-gtk
// @version      0.1
// @match        *://*/*
// @grant        none
// @run-at       document-start
// @noframes
// ==/UserScript==


// ============================================================
// `GMCompat` Compatibility shim
//  adapted from `https://github.com/chocolateboy/gm-compat`
// ============================================================

const $unsafeWindow = (typeof unsafeWindow !== 'undefined') ? unsafeWindow.wrappedJSObject || unsafeWindow : window;
const GMCompat = Object.freeze({
    unsafeWindow:  $unsafeWindow,

    CLONE_INTO_OPTIONS: {
        cloneFunctions: true,
        target: $unsafeWindow,
        wrapReflectors: true
    },

    EXPORT_FUNCTION_OPTIONS: {
        target: $unsafeWindow,
    },

    apply: function($this, fn, _args) {
        const args = [].slice.call(_args)
        return fn.apply($this, this.cloneInto(args))
    },

    call: function($this, fn, ..._args) {
        const args = this.cloneInto(_args)
        return fn.call($this, ...args)
    },

    cloneInto: function(object, _options) {
        const options = Object.assign({}, this.CLONE_INTO_OPTIONS, _options)
        const _cloneInto = (typeof cloneInto === 'function') ? cloneInto : object => object
        return _cloneInto(object, options.target, options)
    },

    export: function(value, options) {
        return (typeof value === 'function') ? this.exportFunction(value, options) : this.cloneInto(value, options)
    },

    exportFunction: function(fn, _options) {
        const options = Object.assign({}, this.EXPORT_FUNCTION_OPTIONS, _options)
        const _exportFunction = (typeof exportFunction === 'function') ? exportFunction : (fn, { defineAs, target = $unsafeWindow } = {}) => { return defineAs ? (target[defineAs] = fn) : fn }

        return _exportFunction(fn, options.target, options)
    },

    unwrap: function(value) {
        return value ? (value.wrappedJSObject || value) : value
    }
});


// ============================================================
//  Navigation detection & CustomEvent dispatch
// ============================================================

if (window.navigation) {
    console.info('Using Navigation API.');
    window.navigation.addEventListener('navigatesuccess', e => {
        notify(e.type, e.currentTarget.currentEntry.url);
    });

} else if (window.onurlchange === null) {
    console.info('Using window.onurlchange.');
    window.addEventListener('urlchange', e => {
        notify('urlchange', e.url);
    });

} else {
    console.info('Using patch.');
    (window.location.hostname === 'www.youtube.com' ? handleYoutube : patchHistory)();
}



let oldUrl;
function notify(method, url){
    const absUrl = new URL(url || window.location.href, window.location.origin).href;
    const detail = GMCompat.export({ method: method, oldUrl: oldUrl, newUrl: absUrl });
    const event = new CustomEvent('detectnavigate', { bubbles: true, detail: detail });
    document.dispatchEvent(event);
    oldUrl = absUrl;
}

function patchHistory(){
    ['pushState', 'replaceState'].forEach(method => {
        const original = GMCompat.unsafeWindow.history[method];
        const patched = function(){
            GMCompat.apply(this, original, arguments);
            notify(method, arguments[2]);
        };

        GMCompat.unsafeWindow.history[method] = GMCompat.export(patched);
    });

    window.addEventListener('popstate', e => {
        notify(e.type);
    });
}

function handleYoutube(){
    window.addEventListener('yt-navigate-finish', e => {
        notify(e.type, e.detail.response.url);
    });
}