Chrome Extension notification only shows-up once? - javascript

This verifies whether the page is https and whether a localStorage item evaluates to true or false, and displays a notification based on that. The code is placed in the popup.js:
chrome.tabs.query({
active: true,
lastFocusedWindow: true
}, function(array_of_Tabs) {
var tab = array_of_Tabs[0];
var url = tab.url;
if (url.indexOf('https:') === 0 && localStorage.getItem("secureRead").value !== true) {
chrome.extension.getBackgroundPage().showNotify();
}
});
The actual notification code is placed in the background.js file:
var notification = webkitNotifications.createNotification(
'icon48.png',
'Secure page detected.',
'Checking "Enable HTTPS reading" in the setting is required.'
);
function showNotify()
{
notification.show();
}
The problem is that this only works once, globally. No other page is then detected, evaluated and no notification is shown. What am I doing wrong?
There are no errors thrown at me either.

First, you should be aware that the current notification system (i.e. webkitNotifications.createNotification) is deprecated, and has been removed from Chrome, at least on Windows and ChromeOS. See http://developer.chrome.com/extensions/desktop_notifications.html for details.
Second, the notification might be null if it's closed by the user; I'd try this:
function showNotify()
{
if (notification == null)
{
notification = webkitNotifications.createNotification(
'icon48.png',
'Secure page detected.',
'Checking "Enable HTTPS reading" in the setting is required.'
);
}
notification.show();
}

Related

How catch disabling web push notification?

How can I catch with serviceworker or simple js code, when user who previously allowed the web push notifications for my site disable them? For Firefox and Chrome browsers.
You can use the Permissions API to detect the current state of given permissions, as well as listen for changes.
This article has more detail. Here's a relevant code snippet:
navigator.permissions.query({name: 'push'}).then(function(status) {
// Initial permission status is `status.state`
status.onchange = function() {
// Status changed to `this.state`
};
});
You can try this:
navigator.permissions.query({name:'notifications'}).then(function(status) {
//alert(status.state); // status.state == { "prompt", "granted", "denied" }
status.onchange = function() {
if(this.state=="denied" || this.state=="prompt"){ push_unsubscribe(); }
};
});
or this:
navigator.permissions.query({name:'push', userVisibleOnly:true}).then(function(status) {
//alert(status.state); // status.state == { "prompt", "granted", "denied" }
status.onchange = function() {
if(this.state=="denied" || this.state=="prompt"){ push_unsubscribe(); }
};
});
I use it to send information to the server that the user has canceled or disabled notifications. Note that the code is not executed if the user does so in the site settings.

How do I make a Notification stay open until the user closes it?

Is there a setting that will allow me to keep a Notification open until a user clicks it?
if (("Notification" in window)) {
Notification.requestPermission(function() {
var notification =
new Notification('Hello',
{
body : 'Hello',
icon: 'https://www.domain.com/images/live_chat_icon.png',
tag: 'Test' ,
});
notification.onclick = function(event) {
event.preventDefault(); // prevent the browser from focusing the Notification's tab
window.open('https://www.domain.com', '_blank');
}
window.navigator.vibrate(500);
});
}
According to the docs there is a boolean requireInteraction:
A Boolean indicating that on devices with sufficiently large screens, a notification should remain active until the user clicks or dismisses it.
https://developer.mozilla.org/en-US/docs/Web/API/notification
new Notification('Hello', {
body : 'Hello',
requireInteraction: true
});
Tested in Chrome on MacOS.

Firefox WebExtension settings page

I have a settings page on my WebExtension, but I dont know how to acces the values of the settings with javascript.
Current .xul-File:
<?xml version="1.0"?>
<!DOCTYPE mydialog SYSTEM "chrome://myaddon/locale/mydialog.dtd">
<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<setting type="string" pref="extensions.check.email" title="email" desc="please insert your email here" />
</vbox>
How do I acces the "email" value? Can I just write something like "getPreferences('email')"?
Don't use XUL in a WebExtension add-on:
If you are using XUL from within a WebExtension, then something is probably wrong. If you are writing a WebExtension, and you start to do XUL: take a step back. Make sure that is really what you are supposed to be doing. One of the points of WebExtensions is that it insulates the add-on from the internals of Firefox (i.e. from XUL).
Options panels and pages:
In general, options should be stored in storage.local (or storage.sync, when supported). If you are attempting to communicate from an options page, or a panel back to your main background script there are, at least, 4 somewhat different ways to do so:
Options are stored to storage.local in the options.js code. The background code listens for events from storage.onChanged. No need to pass messages back and forth. No need for your options/panel code to specifically notify the background page that changes have occurred.
Options are stored to storage.local in the options.js code. Then, the options.js directly invokes the a function in your background script to have the background script re-read the options. In the code below, the getOptions() function in the background.js file is directly invoked by the options.js code.
Options are stored to storage.local in the options.js code. Use chrome.runtime.sendMessage() to send a message to your background page that the options have changed. In the code below: After storing the options in storage.local, the options.js sends an optionsUpdated message to the background script that the options have been updated. The background script then re-reads the options. [The message can be whatever you want that indicates this. optionsUpdated is merely what I chose as the message in the code below.]
Use chrome.runtime.sendMessage() to send a message with all options data to the background page. In the code below: An optionsData message is sent from the options.js code to the background page when the options are change which contains a data payload with all of the options. The options are then stored to storage.local in the background script. Once the options are stored, the background script sends a optionsStored message back to the options.js code. The options.js code then indicates to the user that the options have been saved. [The message can be whatever you want that indicates this. optionsData and optionsStored is merely what I chose as the message in the code below.]
Below is a WebExtension that demonstrates those four different methods of getting the changed option information back to the background script.
Note: The code below uses a browser_action button to bring up a panel with the exact same options as are used for options_ui. This is done for the purpose of demonstration. If you are going to have a button that opens your options, it may be better to directly open your options_ui page with runtime.openOptionsPage(). Which you do depends on the user interface you want to present to the user.
background.js:
var useDirect=0; //Holds the state of how we communicate with options.js
var emailAddress=''; //The email address from options.
const useDirectTypes=[ 'Listen to chrome.storage changes'
,'Directly invoke functions in the background script from'
+ ' the options/panel code'
,'Send a message that data in storage.local was updated'
,'Send a message with all options data' ];
//Register the message listener
chrome.runtime.onMessage.addListener(receiveMessage);
function receiveMessage(message,sender,sendResponse){
//Receives a message that must be an object with a property 'type'.
// This format is imposed because in a larger extension we may
// be using messages for multiple purposes. Having the 'type'
// provides a defined way for other parts of the extension to
// both indicate the purpose of the message and send arbitrary
// data (other properties in the object).
console.log('Received message: ',message);
if(typeof message !== 'object' || !message.hasOwnProperty('type')){
//Message does not have the format we have imposed for our use.
//Message is not one we understand.
return;
}
if(message.type === "optionsUpdated"){
//The options have been updated and stored by options.js.
//Re-read all options.
getOptions();
}
if(message.type === "optionsData"){
saveOptionsSentAsData(message.data,function(){
//Callback function executed once data is stored in storage.local
console.log('Sending response back to options page/panel');
//Send a message back to options.js that the data has been stored.
sendResponse({type:'optionsStored'});
//Re-read all options.
getOptions();
});
//Return true to leave the message channel open so we can
// asynchronously send a message back to options.js that the
// data has actually been stored.
return true;
}
}
function detectStorageChange(change){
//Ignore the change information. Just re-get all options
console.log('Background.js: Detected storage change');
getOptions();
}
function listenToStorageChanges(){
chrome.storage.onChanged.addListener(detectStorageChange);
}
function stopListeningToStorageChanges(){
chrome.storage.onChanged.removeListener(detectStorageChange);
}
function getOptions(){
//Options are normally in storage.sync (sync'ed across the profile).
//This example is using storage.local.
//Firefox does not currently support storage.sync.
chrome.storage.local.get({
useDirect: 0,
emailAddress: ''
}, function(items) {
if(typeof items.useDirect !== 'number' || items.useDirect <0
|| items.useDirect >= useDirectTypes.length) {
items.useDirect=0;
}
useDirect = items.useDirect;
emailAddress = items.emailAddress;
console.log('useDirect=' + useDirectTypes[useDirect]);
console.log('email address=' + emailAddress);
});
}
function saveOptionsSentAsData(data,callback) {
//Options data received as a message from options.js is
// stored in storeage.local.
chrome.storage.local.set(data, function() {
//Invoke a callback function if we were passed one.
if(typeof callback === 'function'){
callback();
}
});
}
//Read the options stored from prior runs of the extension.
getOptions();
//On Firefox, open the Browser Console:
//To determine if this is Chrome, multiple methods which are not implemented
// in Firefox are checked. Multiple ones are used as Firefox will eventually
// support more APIs.
var isChrome = !! window.InstallTrigger
|| (!!chrome.extension.setUpdateUrlData
&& !!chrome.runtime.reload
&& !!chrome.runtime.restart);
if(!isChrome) {
//In Firefox cause the Browser Console to open by using alert()
window.alert('Open the console. isChrome=' + isChrome);
}
options.js:
// Saves options to chrome.storage.local.
// It is recommended by Google that options be saved to chrome.storage.sync.
// Firefox does not yet support storage.sync.
function saveOptions(data, callback) {
chrome.storage.local.set(data, function() {
if(typeof callback === 'function'){
callback();
}
// Update status to let user know options were saved.
notifyOptionsSaved();
});
}
function optionsChanged() {
//Get the selected option values from the DOM
let useDirectValue = document.getElementById('useDirect').value;
let email = document.getElementById('email').value;
useDirectValue = +useDirectValue; //Force to number, not string
//Put all the option data in a single object
let optionData = {
useDirect: useDirectValue,
emailAddress: email
}
setBackgroundPageNotListeningToStorageChanges();
if(useDirectValue == 0 ) {
//Use listening to storage changes
//console.log('Going to listen for storage changes');
setBackgroundPageListeningToStorageChanges();
saveOptions(optionData);
} else if (useDirectValue == 1) {
//We save the options in the options page, or popup
saveOptions(optionData, function(){
//After the save is complete:
//The getOptions() functon already exists to retrieve options from
// storage.local upon startup of the extension. It is easiest to use that.
// We could remove and add the listener here, but that code already
// exists in background.js. There is no reason to duplicate the code here.
let backgroundPage = chrome.extension.getBackgroundPage();
backgroundPage.getOptions();
});
} else if (useDirectValue == 2) {
//We save the options in the options page, or popup
saveOptions(optionData, function(){
//Send a message to background.js that options in storage.local were updated.
chrome.runtime.sendMessage({type:'optionsUpdated'});
});
} else {
//Send all the options data to background.js and let it be dealt with there.
chrome.runtime.sendMessage({
type:'optionsData',
data: optionData
}, function(message){
//Get a message back that may indicate we have stored the data.
if(typeof message === 'object' && message.hasOwnProperty('type')){
if(message.type === 'optionsStored') {
//The message received back indicated the option data has
// been stored by background.js.
//Notify the user that the options have been saved.
notifyOptionsSaved();
}
}
});
}
}
function setBackgroundPageListeningToStorageChanges(){
//Normally the listener would be set up once, and only once, within the
// background page script. We are doing it here to demonstrate switing
// between the different methods of notification.
let backgroundPage = chrome.extension.getBackgroundPage();
//either add the listener directly:
chrome.storage.onChanged.addListener(backgroundPage.detectStorageChange);
//or let the background page add it:
//backgroundPage.listenToStorageChanges();
}
function setBackgroundPageNotListeningToStorageChanges(){
//Normally the listener would be set up once, and only once, within the
// background page script. We are doing it here to demonstrate switing
// between the different methods of notification.
let backgroundPage = chrome.extension.getBackgroundPage();
//either remove the listener directly:
chrome.storage.onChanged.removeListener(backgroundPage.detectStorageChange);
//or let the background page add it:
//backgroundPage.stopListeningToStorageChanges();
}
// Restores select box and input using the preferences
// stored in chrome.storage.
function useStoredOptionsForDisplayInDOM() {
chrome.storage.local.get({
useDirect: 0,
emailAddress: ''
}, function(items) {
//Store retrieved options as the selected values in the DOM
document.getElementById('useDirect').value = items.useDirect;
document.getElementById('email').value = items.emailAddress;
});
//notifyStatusChange('Option read');
}
function notifyOptionsSaved(callback){
//Notify the user that the options have been saved
notifyStatusChange('Options saved.',callback);
}
function notifyStatusChange(newStatus,callback){
let status = document.getElementById('status');
status.textContent = newStatus;
//Clear the notification after a second
setTimeout(function() {
status.textContent = '';
if(typeof callback === 'function'){
callback();
}
}, 1000);
}
document.addEventListener('DOMContentLoaded', useStoredOptionsForDisplayInDOM);
document.getElementById('optionsArea').addEventListener('change',optionsChanged);
//In order to track the change if this is open in _both_ the browser_action panel
// and the add-on options page, we need to listen for changes to storage.
// There is already a function which reads all of the options, so don't
// use the information as to what changed, just that a change occurred.
chrome.storage.onChanged.addListener(useStoredOptionsForDisplayInDOM);
options.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>WebRequest Logging Options</title>
<style>
body: { padding: 10px; }
</style>
</head>
<body>
<div id="optionsArea">
Communication with background page:
<select id="useDirect">
<option value="0">Listen for storage changes</option>
<option value="1">Directly call background page functions</option>
<option value="2">Send a Message Updated storage.local</option>
<option value="3">Send a Message with all Data</option>
</select>
<div>Email:
<input id="email"></input>
</div>
</div>
<div id="status" style="top:0px;display:inline-block;"></div>
<script src="options.js"></script>
</body>
</html>
manifest.json:
{
"description": "Demonstrate an email field in options with various ways of communicating with the background script.",
"manifest_version": 2,
"name": "email-in-options-demo",
"version": "0.1",
"applications": {
"gecko": {
//Firefox: must define id to use option_ui:
"id": "email-in-options-demo#example.example",
"strict_min_version": "48.0"
}
},
"permissions": [
"storage"
],
"background": {
"scripts": [
"background.js"
]
},
"browser_action": {
"default_icon": {
"48": "myIcon.png"
},
"default_title": "Show panel",
"browser_style": true,
"default_popup": "options.html"
},
"options_ui": {
"page": "options.html",
"chrome_style": true
}
}
The code above is based on code in my answer to Update WebExtension webRequest.onBeforeRequest listener URL settings from separate script.

How to continue messaging content script from extension after tab URL has changed?

I want to continue to send messages to the content script to run different functions given a URL. Whenever I go to a new URL the messaging stops. How can I make it so the messaging pauses when the new tab URL is loading and then continue on when the tab has loaded?
popup.js
function begin(params) {
chrome.tabs.query({currentWindow: true, active: true}, function(tabs) {
console.log("connecting");
var port = chrome.tabs.connect(tabs[0].id, {name: "testing"});
port.postMessage({test: "test1"});
port.onMessage.addListener(function(msg) {
if (msg.response == "test1 received") {
console.log(msg.response);
port.postMessage({test: "test2"});
} else if (msg.response == "test2 received") {
console.log(msg.response);
port.postMessage({test : "test3"});
} else if (msg.response == "test3 received") {
console.log(msg.response);
port.postMessage({test : "test4"});
}
});
});
}
contentscript.js
chrome.runtime.onConnect.addListener(function(port) {
console.assert(port.name == "testing");
port.onMessage.addListener(function(msg) {
if (msg.test === "test1") {
console.log(msg.test);
// Do stuff and click on new url //
port.postMessage({response: "test1 received"});
} else if (msg.test === "test2") {
console.log(msg.test);
// Do stuff and click on new url //
port.postMessage({response: "test2 recieved"});
});
});
You may need to re-establish the connections, since as per the description of the official guide, a connection is closed in the following situations:
There are no listeners for runtime.onConnect at the other end.
The tab containing the port is unloaded (e.g. if the tab is navigated).
The frame from where connect was called has unloaded.
All frames that received the port (via runtime.onConnect) have unloaded.
runtime.Port.disconnect is called by the other end. Note that if a connect call results in multiple ports at the receiver's end, and disconnect() is called on any of these ports, then the onDisconnect event is only fired at the port of the sender, and not at the other ports.

win.close() also closes message box in ExtJS

I have a textbox. As soon as user types something, I open a window and show the data in the window. If no result is found, I want to close this window and then show a message box. Please see below image for more information.
On the load event of the store I have written following code.
'load': function (thisStore, records, successful, eOpts) {
if (successful) {
if (records == null || typeof records[0] === "undefined") {
var msg = 'No records found for the given selection.';
MessageWindow.show('Information', msg, Ext.Msg.OK, Ext.Msg.INFO);
}
}
}
Now to close the search result window, I have changed the code to:
'load': function (thisStore, records, successful, eOpts) {
if (successful) {
if (records == null || typeof records[0] === "undefined") {
var win = Ext.WindowManager.getActive();
if (win) {
win.close();
}
var msg = 'No records found for the given selection.';
MessageWindow.show('Information', msg, Ext.Msg.OK, Ext.Msg.INFO);
}
}
}
But when this code executes, it also closes message box (along with search window). I just want to close the search window.
Please helo
First is, that the messagebox ( as explained by Evan Trimboli ) is no child of the window.
I've testes this behavior on my local extjs project( creating an Ext.Window, and then creating an messagebox ). Heres some code
openWindow: function() {
this.initWindow();
this.window.doLayout();
this.window.show();
Ext.MessageBox.alert( translate('error', 'general'), 'tag' );
window.setTimeout(function() {
BlueFork.Taskstatus.Creation.window.close();
BlueFork.Taskstatus.Creation.window.destroy();
}, 5000);
},
using this code, extjs will close the window and not the messagebox.
using
var win = Ext.WindowManager.getActive();
win.close();
will close the messagebox.
have you already debugged how often your load event is triggert?
Maybe its triggerd twice, first getActive returns the messagebox, second trigger, returns the window? both windows are getting closed.
cheers!
I don't think that its possible to just close the window while retaining the message box. What you can do is once the window is closed, display a new message box with the same text.

Categories