We open a Facebook window for authentication using,
let fbWindow = window.open(ourUrl);
// ourUrl redirects to Facebook login
and subscribe to message event, using:
let source = Observable.fromEvent(window, 'message');
var subscription = source.subscribe(
function (e) {
console.log('data', e);
},
function (err) {
console.log('Error: %s', err);
},
function () {
console.log('Completed');
});
return subscription;
The message event is never received. The same code in AngularJS 1 using
window.addEventListener('message', function(e) {});
Always receives the message event once the Facebook authentication is successful.
What's the difference, fromEvent is supposed to mimic event listeners on document events.
Related
I'm trying some basic service workers. The service worker itself will work normally the first time the service worker is registered. The problem I always get is once the person revisits the website in the future (e.g. the following day) and tries to access a .htaccess/.htpasswd protected directory. Instead of getting the dialog box, as normal, they go straight to a 401 error.
This is how I am registering the service worker in script tags in the HTML.
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('/sw.js').then(function(registration) {
// Registration was successful
console.log('ServiceWorker registration successful with scope: ', registration.scope);
}, function(err) {
// registration failed :(
console.log('ServiceWorker registration failed: ', err);
});
});
}
I have tried a couple of different methods in the sw.js itself and every time I get the same error. This is one from the Google airhorner example, I believe...
self.addEventListener('install', e => {
const timeStamp = Date.now();
e.waitUntil(
caches.open('somename').then(cache => {
return cache.addAll([
`/`,
`/index.html`,
`/css/tour-2.css`
])
.then(() => self.skipWaiting());
})
);
});
self.addEventListener('activate', event => {
event.waitUntil(self.clients.claim());
});
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request, {ignoreSearch: true}).then(response => {
return response || fetch(event.request);
})
);
});
Does anyone know if it is possible to use service workers with websites with .htaccess protected directories?
Thanks.
One way to cure is:
self.addEventListener('fetch', event => {
// Exclude admin panel.
if (0 === event.request.url.indexOf("https://www.my-site.com/my-protected-area")) {
return;
}
It should help.
Source: TIV.NET
In my calendar application I want to send notifications X minutes before events.
I used the notification API with service worker as follow :
I register the service worker in my index.html.
// Registering my service worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js', {
scope: '/'
})
.then(function(reg) {
window.swReg = reg;
console.log('registration succeed');
}).catch(function(error) {
console.log('Registration failed with ' + error);
});
}
Elsewhere in my app, I used a setTimeout to trigger the notification :
// Show notification at next event
setTimeout(() => {
swReg.showNotification('Your event starts in 5mn!')
.then(ev => {
console.log(ev); // <= got undefined!
});
}, delayBeforeNextEvent);
Regarding of the specifications, MDN/showNotification#Syntax I should be able to access the NotificationEvent through the ev parameter of the resolved promise.
But the promise is resolved immediately and ev is undefined.
For the instance I have to define an event listener inside my service-worker.js to get it working but I want to keep this logic next to the code above.
self.addEventListener('notificationclick', ev => {
ev.notification.close();
});
Any ideas ?
I'm using FCM web notification service, when I am calling the register function:
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('/sw.js').then(function(registration) {
// Registration was successful
console.log('ServiceWorker registration successful with scope: ', registration.scope);
}).catch(function(err) {
// registration failed :(
console.log('ServiceWorker registration failed: ', err);
});
});
}
The service worker is registered twice, one because of this function, and one by the FCM script. This is my service worker code:
importScripts('https://www.gstatic.com/firebasejs/3.5.2/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/3.5.2/firebase-messaging.js');
'messagingSenderId': '<my senderid>'
});
const messaging = firebase.messaging();
messaging.setBackgroundMessageHandler(function (payload) {
self.addEventListener('notificationclick', function (event) {
event.notification.close();
var promise = new Promise(function (resolve) {
setTimeout(resolve, 1000);
}).then(function () {
return clients.openWindow(payload.data.locator);
});
event.waitUntil(promise);
});
var notificationTitle = payload.data.title;
var notificationOptions = {
body: payload.data.body,
icon: payload.data.icon
};
return self.registration.showNotification(notificationTitle,
notificationOptions);
});
One more thing, when I send test notifications, and I click the first message and it opens the URL correctly, but in the same instance of Chrome, all other messages I click open the URL of the first message. This problem does not happen on Firefox, just Chrome. I am using chrome version 55
With the firebase messaging SDK you don't need to call register.
If you call register, you can make the SDK use your service worker by calling useServiceWorker() (See: https://firebase.google.com/docs/reference/js/firebase.messaging.Messaging#useServiceWorker)
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('/sw.js')
.then(function(registration) {
messaging.useServiceWorker(registration);
});
});
}
The reason the SDK registers the service worker for you is that it sets a scope that will prevent it from interfering with any other service workers you might have.
Regarding your second issue, are you sending different URLs or are they the same URLs?
I work with angularjs and use service worker to receive push notification.
but navigator.serviceWorker.controller is null until page refresh,and I don't know how to do to solve this problem
some code of serviceworker :
self.addEventListener('push', pwServiceWorker.pushReceived);
self.addEventListener('notificationclick', pwServiceWorker.notificationClicked);
// refresh caches
self.addEventListener('activate', function (event)
{
event.waitUntil(
caches.keys().then(function (cacheNames)
{
return Promise.all(
cacheNames.map(function (cacheName)
{
return caches.delete(cacheName);
})
);
})
);
});
and send message to the client in serviceworker when push received :
self.clients.matchAll().then(function(all) {
console.log(all);
all.forEach(function(client) {
client.postMessage(data);
});
});
in mainController.js give message like this :
if (!navigator.serviceWorker || !navigator.serviceWorker.register) {
console.log("This browser doesn't support service workers");
return;
}
// Listen to messages from service workers.
navigator.serviceWorker.addEventListener('message', function(event) {
console.log("Got reply from service worker: " + event.data);
});
// Are we being controlled?
if (navigator.serviceWorker.controller) {
// Yes, send our controller a message.
console.log("Sending 'hi' to controller");
navigator.serviceWorker.controller.postMessage("hi");
} else {
// No, register a service worker to control pages like us.
// Note that it won't control this instance of this page, it only takes effect
// for pages in its scope loaded *after* it's installed.
navigator.serviceWorker.register("service-worker.js")
.then(function(registration) {
console.log("Service worker registered, scope: " + registration.scope);
console.log("Refresh the page to talk to it.");
// If we want to, we might do `location.reload();` so that we'd be controlled by it
})
.catch(function(error) {
console.log("Service worker registration failed: " + error.message);
});
}
This is expected behavior. To take control over all open pages without waiting for refresh/reopen, you have to add these commands to your Service Worker:
self.addEventListener('install', function(event) {
event.waitUntil(self.skipWaiting()); // Activate worker immediately
});
self.addEventListener('activate', function(event) {
event.waitUntil(self.clients.claim()); // Become available to all pages
});
You can read more about them in skipWaiting() docs and clients.claim() docs.
Make sure the scope of your service worker includes the url in question.
Am using FCM to handle notifications, it works fine up until when I need to update my UI from the firebase-messaging-sw.js when my web app is in the background.
My first question is: is it possible to update my web app UI in the background (When user is not focused on the web app) through a service worker
Secondly, if so, how? because I tried a couple of things and its not working, obviously am doing something wrong and when it does work, my web app is in the foreground. What am I doing wrong?
My codes are below.
my-firebase-service-sw.js
// [START initialize_firebase_in_sw]
// Give the service worker access to Firebase Messaging.
// Note that you can only use Firebase Messaging here, other Firebase
libraries
// are not available in the service worker.
importScripts('https://www.gstatic.com/firebasejs/4.1.1/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/4.1.1/firebase-messaging.js');
// My Custom Service Worker Codes
var CACHE_NAME = 'assembly-v0.1.3.1';
var urlsToCache = [
'/',
'lib/vendors/bower_components/animate.css/animate.min.css',
'lib/vendors/bower_components/sweetalert/dist/sweetalert.css',
'lib/css/app_1.min.css',
'lib/css/app_2.min.css',
'lib/css/design.css'
];
var myserviceWorker;
var servicePort;
// Install Service Worker
self.addEventListener('install', function (event) {
console.log('installing...');
// Perform install steps
event.waitUntil(
caches.open(CACHE_NAME)
.then(function (cache) {
console.log('Opened cache');
return cache.addAll(urlsToCache);
})
);
console.log('installed...');
});
// Service Worker Active
self.addEventListener('activate', function (event) {
console.log('activated!');
// here you can run cache management
var cacheWhitelist = [CACHE_NAME];
event.waitUntil(
caches.keys().then(function (cacheNames) {
return Promise.all(
cacheNames.map(function (cacheName) {
if (cacheWhitelist.indexOf(cacheName) === -1) {
return caches.delete(cacheName);
}
})
);
})
);
});
self.addEventListener('fetch', function (event) {
event.respondWith(
caches.match(event.request)
.then(function (response) {
// Cache hit - return response
if (response) {
return response;
}
// IMPORTANT: Clone the request. A request is a stream and
// can only be consumed once. Since we are consuming this
// once by cache and once by the browser for fetch, we need
// to clone the response.
var fetchRequest = event.request.clone();
return fetch(fetchRequest).then(
function (response) {
// Check if we received a valid response
if (!response || response.status !== 200 || response.type !== 'basic') {
return response;
}
// IMPORTANT: Clone the response. A response is a stream
// and because we want the browser to consume the response
// as well as the cache consuming the response, we need
// to clone it so we have two streams.
var responseToCache = response.clone();
caches.open(CACHE_NAME)
.then(function (cache) {
cache.put(event.request, responseToCache);
});
return response;
}
);
})
);
});
self.addEventListener('message', function (event) {
console.log("SW Received Message: " + event.data);
// servicePort = event;
event.ports[0].postMessage("SW Replying Test Testing 4567!");
});
myserviceWorker = self;
// Initialize the Firebase app in the service worker by passing in the
// messagingSenderId.
firebase.initializeApp({
'messagingSenderId': '393093818386'
});
// Retrieve an instance of Firebase Messaging so that it can handle background
// messages.
const messaging = firebase.messaging();
// [END initialize_firebase_in_sw]
// If you would like to customize notifications that are received in the
// background (Web app is closed or not in browser focus) then you should
// implement this optional method.
// [START background_handler]
messaging.setBackgroundMessageHandler(function (payload) {
console.log('[firebase-messaging-sw.js] Received background message ', payload);
// Customize notification here
// send to client
console.log('Sending data to notification');
try {
myserviceWorker.clients.matchAll().then(function (clients) {
clients.forEach(function (client) {
console.log('sending to client ' + client);
client.postMessage({
"msg": "401",
"dta": payload.data
});
})
});
} catch (e) {
console.log(e);
}
const notificationTitle = payload.data.title;;
const notificationOptions = {
body: payload.data.body,
icon: payload.data.icon,
click_action: "value"
};
return self.registration.showNotification(notificationTitle,
notificationOptions);
});
// [END background_handler]
In my main javascript file, which receives the payload. it receives it when the application is in the foreground. My major concern and problem is receiving payload when the application is in the background, all activities on foreground works just fine.
It is possible to update the UI even your website is opening but unfocused.
Just add enable option includeUncontrolled when you get all client list.
Example:
messaging.setBackgroundMessageHandler(function (payload) {
console.log('[firebase-messaging-sw.js] Received background message ', payload);
self.clients.matchAll({includeUncontrolled: true}).then(function (clients) {
console.log(clients);
//you can see your main window client in this list.
clients.forEach(function(client) {
client.postMessage('YOUR_MESSAGE_HERE');
})
})
});
In your main page, just add listener for message from service worker.
Ex:
navigator.serviceWorker.addEventListener('message', function (event) {
console.log('event listener', event);
});
See Clients.matchAll() for more details.