Limit cache length of chrome notifications when Windows is locked - javascript

Is there any sort of option in the Web API Notifications to allow a notification to not be displayed while the PC is locked?
I have setup a web application that displays Notifications when certain events happen. This is something I use at work to monitor different things so I leave it open nearly 24/7. Problem is that when the PC is locked, the notifications are saved until I unlock the PC. Then I get flooded with all the notifications that were triggered while the PC was locked.
I cannot use an sort of idle page script to only show notifications if the page was used or interacted with in the last X number of minutes because I don't actually want to have to look at the page to still allow the notifications.
// set title and message body
var title = 'Test message';
var message 'This is a test message that should only show when logged into the PC';
// setup some options
var options = {
// someOptionToDisableLockedNotificationsOnWindows?
body: message,
icon: 'assets/yukon_logo_small.png',
};
// create the notification using the above settings
var notification = new Notification( title, options );
// focus tab and close the notification on click
notification.addEventListener('click', function(e) {
window.focus();
e.target.close();
}, false);
I have tried to randomly set some options, don't remember them all but they didn't do anything or broke my code.
I was not able to find anything in the API:
https://developer.mozilla.org/en-US/docs/Web/API/Notifications_API

Related

Browser service worker - Unchecked runtime.lastError: listener indicated an asynchronous response by returning true but the message channel closed

I am creating a push notification system for browsers.
What works...
If the corresponding website is loaded in the browser and if the browser is in the BACKGROUND the service worker correctly receives the information and pops up the message in the system tray. On clicking a button in that message, it brings the browser window back to focus and performs the action I want.
What doesn't work...
If the browser is closed OR the browser is open but the website is not loaded in any of the tabs, the service worker correctly receives the information and pops up the message in the system tray. However on clicking a button in that message, nothing happens :(
I tried to debug by closing the browser, sending the message, on receipt of message in system tray I manually loaded up the browser to the website and view console debug. When I then click the button in system try message nothing happened but I received the following message in the browser:
service worker message Unchecked runtime.lastError: A listener indicated an asynchronous response by returning true, but the message channel closed before a response was received
Could anyone give me any pointers. I've enclosed below the portion of service worker code that is called when a button on the system tray message is clicked...
//If a browser window is in background, and the domain of this project is loaded in to it,
//we force that window back in to the foreground (and re-display the message in the browser again via the postMessage function)
//However this isn't working if browser is closed at point of system tray message receipt...
function returnWindowToForeground(event,_action) {
event.waitUntil(
clients.matchAll(
{ type: 'window', includeUncontrolled: true }
)
.then(
(clientList) => {
var windowWithDomain = clientList.some((windowClient) => {
var found = -1;
let url = windowClient.url;
if( websiteurl == url.slice(0, websiteurl.length) ) {
found = i;
windowClient.focus(); //Go back to website in browser
windowClient.postMessage([currpayload,_action]); //Post message to browser window
}
return found;
});
//If not found, spawn a new browser tab, load url and post message
if (windowWithDomain== -1 && clients.openWindow)
{
clients.openWindow(websiteurl)
.then((windowClient) => (windowClient) ? windowClient.postMessage([currpayload,_action]) : null;
}
)
);
}
Thanks for your help, sorry it's a bit long.

Run notification script only once, even though script runs on multiple tabs

I use the following code inside a Tampermonkey script.
function scriptMain () {
setTimeout(function(){
GM_notification ( {
title: 'Refresh Business Manager', text: 'Your about to be logged out of staging, click here to refresh your login.', image: 'https://i.stack.imgur.com/geLPT.png',
onclick: () => {
console.log ("My notice was clicked.");
location.reload();
}
} );
}, 5*1000);
console.log ("Script main code ran.");
}
The code shows a notification whenever a browser tab is open for more than 5 seconds which includes a button to refresh the current browser tab. I wanna use this script to alert me every 20 minutes or so, that one of the logins in the browser is about to auto-logout.
The functionality works as expected, but if I have 5 tabs open from the site where im logged in, I will get 5 notifications when the page is about to run out. I would love to be able to tell from within the Tampermonkey script if this script is already running on another tab, to not execute or to maybe just be able to only show the notification once.
I have been looking into the Tampermonkey documentation for the following Grants:
GM_getTab(callback)
GM_saveTab(tab)
GM_getTabs(callback)
But I dont seem to be able to work out if this functionality would be possible or not.
Can someone help me shine some light on this topic, or perhaps share a solution?
On modern spec-compliant browsers, you can use BroadcastChannel inside the userscript to communicate with other tabs on the same domain. Make the timeout slightly random - add or subtract a few seconds to allow for all the open tabs to coordinate. When sending a notification, also send a message in the BroadcastChannel telling other instances of the userscript to reset their timers as well.
const channel = new BroadcastChannel('logout-notify');
let timeoutId;
function makeTimeout() {
clearTimeout(timeoutId);
timeoutId = setTimeout(function () {
GM_notification({
title: 'Refresh Business Manager', text: 'Your about to be logged out of staging, click here to refresh your login.', image: 'https://i.stack.imgur.com/geLPT.png',
onclick: () => {
console.log("My notice was clicked.");
location.reload();
}
});
channel.postMessage('notified');
}, 1000 * 60 * 20 + (Math.random() * 10000)); // 20 minutes plus up to 10 seconds
}
// When below runs, another tab created a notification
// reset the timeout for this tab, schedule another one for 20ish minutes from now
channel.onmessage = makeTimeout;
// initialize timeout on pageload?
makeTimeout();
This code will result in alerts being shown only once every 20 minutes at most. If you close one tab you were working on, other tabs will take up the slack without interruption.

Detect notification popup using JavaScript

I am creating userscript for messenger site I use. Is it possible to detect when site create notification pop up(usually on right bottom of screen) and get content of notification?
document.addEventListener('???', function(e) { // when I get notification popup(get message)
// and get content of notification
});
In websites I believe there's a Notifications API in which you can check here:
https://developer.mozilla.org/en-US/docs/Web/API/Notifications_API
It has all functions to request permissions, detect & listen to notifications on in websites. For example:
btn.addEventListener('click', function() {
let promise = Notification.requestPermission();
// wait for permission
})

iframe content doesn't always load

So I have a system that essentially enabled communication between two computers, and uses a WebRTC framework to achieve this:
"The Host": This is the control computer, and clients connect to this. They control the clients window.
"The Client": The is the user on the other end. They are having their window controlled by the server.
What I mean by control, is that the host can:
change CSS on the clients open window.
control the URL of an iframe on the clients open window
There are variations on these but essentially thats the amount of control there is.
When "the client" logs in, the host sends a web address to the client. This web address will then be displayed in an iframe, as such:
$('#iframe_id').attr("src", URL);
there is also the ability to send a new web address to the client, in the form of a message. The same code is used above in order to navigate to that URL.
The problem I am having is that on, roughly 1 in 4 computers the iframe doesn't actually load. It either displays a white screen, or it shows the little "page could not be displayed" icon:
I have been unable to reliably duplicate this bug
I have not seen a clear pattern between computers that can and cannot view the iframe content.
All clients are running google chrome, most on an apple powermac. The only semi-link I have made is that windows computers seem slightly more susceptible to it, but not in a way I can reproduce. Sometimes refreshing the page works...
Are there any known bugs that could possibly cause this to happen? I have read about iframe white flashes but I am confident it isn't that issue. I am confident it isn't a problem with jQuery loading because that produces issues before this and would be easy to spot.
Thanks so much.
Alex
edit: Ok so here is the code that is collecting data from the server. Upon inspection the data being received is correct.
conn.on('data', function(data) {
var data_array = JSON.parse(data);
console.log(data_array);
// initialisation
if(data_array.type=='init' && inititated === false) {
if(data_array.duration > 0) {
set_timeleft(data_array.duration); // how long is the exam? (minutes)
} else {
$('#connection_remainingtime').html('No limits');
}
$('#content_frame').attr("src", data_array.uri); // url to navigate to
//timestarted = data_array.start.replace(/ /g,''); // start time
ob = data_array.ob; // is it open book? Doesnt do anything really... why use it if it isnt open book?
snd = data_array.snd; // is sound allowed?
inititated = true;
}
}
It is definitele trying to make the iframe navigate somewhere as when the client launches the iframe changes - its trying to load something but failing.
EDIT: Update on this issue: It does actually work, just not with google forms. And again it isn't everybody's computers, it is only a few people. If they navigate elsewhere (http://www.bit-tech.net for example) then it works just fine.
** FURTHER UPDATE **: It seems on the ones that fail, there is an 'X-Frames-Origin' issue, in that its set the 'SAMEORIGIN'. I dont understand why some students would get this problem and some wouldn't... surely it depends upon the page you are navigating to, and if one person can get it all should be able to?
So the problem here was that the students were trying to load this behind a proxy server which has an issue with cookies. Although the site does not use cookies, the proxy does, and when the student had blocked "third party cookies" in their settings then the proxy was not allowing the site to load.
Simply allowed cookies and it worked :)
iframes are one of the last things to load in the DOM, so wrap your iframe dependent code in this:
document.getElementById('content_frame').onload = function() {...}
If that doesn't work then it's the document within the iframe. If you own the page inside the iframe then you have options. If not...setTimeout? Or window.onload...?
SNIPPET
conn.on('data', function(data) {
var data_array = JSON.parse(data);
console.log(data_array);
// initialisation
if (data_array.type == 'init' && inititated === false) {
if (data_array.duration > 0) {
set_timeleft(data_array.duration); // how long is the exam? (minutes)
} else {
$('#connection_remainingtime').html('No limits');
}
document.getElementById('content_frame').onload = function() {
$('#content_frame').attr("src", data_array.uri); // url to navigate to
//timestarted = data_array.start.replace(/ /g,''); // start time
ob = data_array.ob; // is it open book? Doesnt do anything really... why use it if it isnt open book?
snd = data_array.snd; // is sound allowed?
inititated = true;
}
}
}

how to send message "page will close" from browser to server?

I want to add a script (JavaScript) to each html-document, that sends two messages to the server:
page did open
page will close (this message contains how long the page was open)
The open-message should be sent when the document is loading (or when it finished loading). This is the easy part.
The close-message should de sent when the document is unloaded from the browser's viewport. (User clicks on a link that has not target="_blank"; User closes the browser tab/window; User reloads the page; User quits the browser; anything else that makes the page disappear)
I tried it this way:
//================================================================================
//Global Variables
//================================================================================
gl = {}; //container for global variables (1 scalar and 1 function)
gl.start = Math.floor(Date.now()); //timestamp of page-loading
//================================================================================
//function: Send message to server
//================================================================================
gl.sendData = function (action) {
var message = {
'href' : window.location.href,
'height' : $(window).height(),
'width' : $(window).width(),
'action' : action, //can be 'open' or 'close' (i.e. 'load' and 'unload')
'rand' : Math.random() //random number to outwit cache
};
if (action == 'close') {
//how long was the page open? [milliseconds]
message.duration = Math.floor(Date.now()) - gl.start;
};
window.alert(action); //debugging: show if gl.sendData is executed
$.ajax({
'url' : 'http://' + window.location.hostname + '/path/to/script.pl',
'data' : message,
'success' : function(){}, //not interested in server's answer
'error' : function(){} //errors will be ignored
});
};
//================================================================================
//Things to do as soon as page load is complete
//================================================================================
$(document).ready(function(){
//send message "page did open"
gl.sendData('open');
//add event-handler to send the message "page will close" when the page is closing
$(window).on("unload", function() {
gl.sendData('close');
});
});
Sending a message when the page did open is working perfectly fine. But the browser doesn't send the close-message.
I found out this facts:
"unload" seems to be the correct event. The alert-message pops up when the page is closing.
"beforeunload" doesn't work because it is not fired (Safari on Mac, when clicking on a link that navigates to another page)
the ajax-request is sent when the page is loading, so it seems to be ok.
the ajax-request doesn't send data to the server when the page is closing.
my Question:
Is there a way to send a massage to the server in the moment when a document is unloaded from the browser?
I want to send the duration of the page beeing displayed to the server. Is there another way to do this?
There is no 100% reliable way to send data to a server when the page is closing that works in all browsers.
With the advent and general availability of webSockets in browsers, there are some who are using a webSocket connection from client to server as a means of tracking this. When the page is opened, it makes a webSocket (or socket.io) connection to the server. This connection is kept open for the duration of the page. When the user leaves the page or closes the browser, the webSocket will get closed by the browser. The server can then see that the webSocket has been closed and can mark that as the time that the page was closed.
One other possibility that is less efficient than the webSocket connection is for the open webpage to regularly poll the server via Ajax (say every 30 seconds or so to announce that the page is still open). When the server sees the polling stop, it assumes that page has been closed.
Both of these techniques require regular connectivity with the server in order to do this tracking (e.g. can't be used to track offline usage).

Categories