Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
//<nowiki>
// !!!!!!!!!!!
//
// !!!!! you will need to click "notifs" under the More menu on a page to start receiving notifs
//
// !!!!!!!!!!!!!!!!
$( function () {

var existingIds = [];
var date = new Date(); 
var now_utc =  new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(),
 date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds()));
            var api = new mw.Api();

// Copied from https://stackoverflow.com/a/3177838/1757964
    function timeSince(date) {
        var seconds = Math.floor((new Date() - date) / 1000);
        var interval = Math.floor(seconds / 31536000);
        if (interval > 1) {
            return interval + " years";
        }
        interval = Math.floor(seconds / 2592000);
        if (interval > 1) {
            return interval + " months";
        }
        interval = Math.floor(seconds / 86400);
        if (interval > 1) {
            return interval + " days";
        }
        interval = Math.floor(seconds / 3600);
        if (interval > 1) {
            return interval + " hours";
        }
        interval = Math.floor(seconds / 60);
        if (interval > 1) {
            return interval + " minutes";
        }
        return Math.floor(seconds) + " seconds";
    }

    function wikilink( title ) {
        return "<a href='" + mw.util.getUrl( title ) + "'>" + title + "</a>";
    }

function notifToElement( notif ) {
        var timestamp = timeSince( new Date( notif.timestamp.utciso8601 ) ) + " ago";
        var userLink = "<a href='" + mw.util.getUrl( "User:" + notif.agent.name ) + "' "
            + ( ( notif.agent.name.length ) > 20 ? " style='font-size: 90%'" : "" )
            + ">" + notif.agent.name + "</a>";
        var newNotifDiv = $( "<div class='notif'>" );
        if( !notif.read ) newNotifDiv.append( "*" );
        if( notif.type === "mention" && notif.category === "mention" ) {
            newNotifDiv
                .append( "Mentioned " + timestamp + " by " + userLink + " on " )
                .append( wikilink( notif.title.full ) )
                .append( " in " )
                .append( "<a href='" + mw.util.getUrl( "Special:Diff/" + notif.revid ) + "'>this edit</a>" );
        }
        else if( notif.type === "emailuser" && notif.category === "emailuser" ) {
            newNotifDiv
                .append( "Emailed " + timestamp + " by " + userLink )
        } else if( notif.type === "edit-thank" && notif.category === "edit-thank" ) {
            newNotifDiv
                .append( "Thanked " + timestamp + " by " + userLink + " for " )
                .append( "<a href='" + mw.util.getUrl( "Special:Diff/" + notif.revid ) + "'>this edit</a>" )
                .append( " to " )
                .append( wikilink( notif.title.full ) );
        } else if( notif.type === "edit-user-talk" && notif.category === "edit-user-talk" ) {
            newNotifDiv
                .append( "Your user talk page changed " + timestamp + " by " + userLink )
                .append( " in " )
                .append( "<a href='" + mw.util.getUrl( "Special:Diff/" + notif.revid ) + "'>this edit</a>" );
        } else if( notif.type === "mention-success" && notif.category === "mention-success" ) {
            newNotifDiv
                .append( "Successfully mentioned someone " + timestamp + " on " )
                .append( wikilink( notif.title.full ) )
                .append( " with " )
                .append( "<a href='" + mw.util.getUrl( "Special:Diff/" + notif.revid ) + "'>this edit</a>" );
        } else if( notif.type === "mention-summary" && notif.category === "mention" ) {
            newNotifDiv
                .append( "Mentioned " + timestamp + " by " + userLink + " in the summary of " )
                .append( "<a href='" + mw.util.getUrl( "Special:Diff/" + notif.revid ) + "'>this edit</a>" );
        } else if( notif.type === "login-fail-known" && notif.category === "login-fail" ) {
            newNotifDiv
                .append( "There have been 1 or more unsuccessful attempts to log in to your account since the last time you logged in. If it wasn't you, please make sure your account has a strong password." );
        } else if( notif.type === "reverted" && notif.category === "reverted" ) {
            newNotifDiv
                .append( "Your edit to " + wikilink( notif.title.full ) + " was " )
                .append( "<a href='" + mw.util.getUrl( "Special:Diff/" + notif.revid ) + "'>reverted</a>" )
                .append( " by " + userLink );
        } else {
            newNotifDiv.text( JSON.stringify( notif ) );
        }

        return newNotifDiv;
    }

function refresh() {
        api.get ( {
            format: "json",
            action: "query",
            meta: "notifications",
            notunreadfirst: "true", // not is the notifications module, not the word "not"
            notlimit: 50,
            formatversion: 2,
        } ).then( function ( data ) {
            if( !data || !data.query || !data.query.notifications ||
                !data.query.notifications.list ) {
                console.error( "browser-notifs died ", data );
            }
            var notifs = data.query.notifications.list;
console.log(notifs,existingIds);
            notifs = notifs.filter( function ( x ) { console.log(x,!x.read,( x.timestamp.utcunix > now_utc.getTime()/1000 ),x.timestamp.utcunix - now_utc.getTime()/1000,( existingIds.indexOf( x.id ) < 0 ));
return !x.read && ( x.timestamp.utcunix > now_utc.getTime()/1000 ) && ( existingIds.indexOf( x.id ) < 0 ); } );
console.log(notifs);

notifs.forEach( function ( notif ) {

console.log(notifs)
    Notification.requestPermission().then(function (permission) {
      // If the user accepts, let's create a notification
      if (permission === "granted") {

var notification = new Notification(notifToElement(notif).get(0).textContent);
if( notif.title && notif.title.full) {
notification.onclick = function () { 
window.location.href = mw.util.getUrl( notif.title.full );
};
} else {
notification.onclick = function () { 
window.location.href = mw.util.getUrl( "Special:Notifications" );
};
}
      }
    });

existingIds.push(notif.id);
} ); // end forEach
} ); // end API callback
} // end refresh()




        mw.loader.using( [ "mediawiki.util", "mediawiki.api" ] ).then( function () {

        var link = mw.util.addPortletLink( "p-cactions", "#", "notifs", "pt-notifs" );
        if( link ) link.addEventListener( "click", function(){
Notification.requestPermission();
setInterval(function() {
refresh();
}, 2 * 60 * 1000);
} );
} );

} );
//</nowiki>