How to make Web page to not wait for a response after sending a GET request - html

I am trying to make this web site that resides in Google Drive control a LED(on/off) via esp8266 and arduino. Partially i've succeded in doing what i want by sending to the IP of the module that communicates with the arduino a GET request witch parses it and acts accordingly. ie GET /?LED1=on HTTP/1.1
Problem is that whenever i press a button in the web site it sends the GET request and then it waits for a response from the other end (arduino),and the browser keeps loading until eather I close the connection from the arduino or I reply something like HTTP/1.1 200 OK and then close the conection.
In the first case browser shows the message that was unable to load the page and in second case it simply shows a blank page.
<DOCTYPE html>
<html>
<head>
<title>LED Control</title>
</head>
<body>
<button>LED 1 On</button>
</body>
</html>
I just want to send that LED1=on string somehow without causing the page attempt to load anything back.

A reusable solution
Modify your HTML to be something like this:
<button class="get" data-url="http://78.87.xxx.xx:333/?LED1=on">LED 1 On</button>
Now add this JavaScript:
window.onload = function () {
Array.prototype.forEach.call(document.querySelectorAll('.get'), function(el) {
el.onclick = function () {
// Use this trick to perform CORS requests too
var req = new Image();
req.src = this.dataset.url;
// The following 7 lines are completely optional
req.onload = function () {
// Was successful
};
req.onerror = function (error) {
// Encountered an error
alert('An error occurred while performing the request. + ' error);
};
};
});
};
Now any element with the class "get" when clicked, will send a request to the URL. This won't change the page either. If

Related

Chrome Push Notification: This site has been updated in the background

While implementing the chrome push notification, we were fetching the latest change from our server. While doing so, the service-worker is showing an extra notification with the message
This site has been updated in the background
Already tried with the suggestion posted here
https://disqus.com/home/discussion/html5rocks/push_notifications_on_the_open_web/
But could not find anything useful till now. Is there any suggestion ?
Short Answer: You should use event.waitUntil and pass a promise to it, which returns showNotification eventually. (if you have any other nested promises, you should also return them.)
I was expriencing the same issue but after a long research I got to know that this is because delay happen between PUSH event and self.registration.showNotification(). I only missed return keyword before self.registration.showNotification()`
So you need to implement following code structure to get notification:
var APILINK = "https://xxxx.com";
self.addEventListener('push', function(event) {
event.waitUntil(
fetch(APILINK).then(function(response) {
return response.json().then(function(data) {
console.log(data);
var title = data.title;
var body = data.message;
var icon = data.image;
var tag = 'temp-tag';
var urlOpen = data.URL;
return self.registration.showNotification(title, {
body: body,
icon: icon,
tag: tag
})
});
})
);
});
Minimal senario:
self.addEventListener('push', event => {
const data = event.data.json();
event.waitUntil(
// in here we pass showNotification, but if you pass a promise, like fetch,
// then you should return showNotification inside of it. like above example.
self.registration.showNotification(data.title, {
body: data.content
})
);
});
I've run into this issue in the past. In my experience the cause is generally one of three issues:
You're not showing a notification in response to the push
message. Every time you receive a push message on the device, when
you finish handling the event a notification must be left visible on
the device. This is due to subscribing with the userVisibleOnly:
true option (although note this is not optional, and not setting it
will cause the subscription to fail.
You're not calling event.waitUntil() in response to handling the event. A promise should be passed into this function to indicate to the browser that it should wait for the promise to resolve before checking whether a notification is left showing.
For some reason you're resolving the promise passed to event.waitUntil before a notification has been shown. Note that self.registration.showNotification is a promise and async so you should be sure it has resolved before the promise passed to event.waitUntil resolves.
Generally as soon as you receive a push message from GCM (Google Cloud Messaging) you have to show a push notification in the browser. This is mentioned on the 3rd point in here:
https://developers.google.com/web/updates/2015/03/push-notificatons-on-the-open-web#what-are-the-limitations-of-push-messaging-in-chrome-42
So it might happen that somehow you are skipping the push notification though you got a push message from GCM and you are getting a push notification with some default message like "This site has been updated in the background".
This works, just copy/paste/modify. Replace the "return self.registration.showNotification()" with the below code. The first part is to handle the notification, the second part is to handle the notification's click. But don't thank me, unless you're thanking my hours of googling for answers.
Seriously though, all thanks go to Matt Gaunt over at developers.google.com
self.addEventListener('push', function(event) {
console.log('Received a push message', event);
var title = 'Yay a message.';
var body = 'We have received a push message.';
var icon = 'YOUR_ICON';
var tag = 'simple-push-demo-notification-tag';
var data = {
doge: {
wow: 'such amaze notification data'
}
};
event.waitUntil(
self.registration.showNotification(title, {
body: body,
icon: icon,
tag: tag,
data: data
})
);
});
self.addEventListener('notificationclick', function(event) {
var doge = event.notification.data.doge;
console.log(doge.wow);
});
I was trying to understand why Chrome has this requirement that the service worker must display a notification when a push notification is received. I believe the reason is that push notification service workers continue to run in the background even after a user closes the tabs for the website. So in order to prevent websites from secretly running code in the background, Chrome requires that they display some message.
What are the limitations of push messaging in Chrome?
...
You have to show a notification when you receive a push message.
...
and
Why not use Web Sockets or Server-Sent Events (EventSource)?
The advantage of using push messages is that even if your page is closed, your service worker will be woken up and be able to show a notification. Web Sockets and EventSource have their connection closed when the page or browser is closed.
If you need more things to happen at the time of receiving the push notification event, the showNotification() is returning a Promise. So you can use the classic chaining.
const itsGonnaBeLegendary = new Promise((resolve, reject) => {
self.registration.showNotification(title, options)
.then(() => {
console.log("other stuff to do");
resolve();
});
});
event.waitUntil(itsGonnaBeLegendary);
i was pushing notification twice, once in the FCM's onBackgroundMessage()
click_action: "http://localhost:3000/"
and once in self.addEventListener('notificationclick',...
event.waitUntil(clients.matchAll({
type: "window"
}).then...
so i commented click_action, ctrl+f5 to refresh browsers and now it works normal

Chrome Extension: Insert a clickable image using a content script

I know hat it is possible, but I am not quite sure how to do it the 'right' way, as to ensure there are no conflicts.
I came across this question: Cannot call functions to content scripts by clicking on image . But it is so convoluted with random comments that it's hard to understand what the corrected way was.
Use case:
Html pages have a div on the page where they expect anyone using the Chrome extension to inject a picture. When users click on he picture, I want to somehow notify an event script. So I know I need to register a listener so the code inserted messages the event script.
Can I get some indication on what code to inject through the content script? I saw that sometimes injecting jquery directly is advised.
I am trying to avoid having the html page to post a message to itself so it can be intercepted. Thanks
With the help of Jquery something like this would capture the image onclick event and allow you to pass a message to a background page in the Chrome Extension:
$("img").click(function(){
var imageSrc = $(this).attr("src");
//Post to a background page in the Chrome Extension
chrome.extension.sendMessage({ cmd: "postImage", data: { imgSrc: imageSrc } }, function (response) {
return response;
});
});
Then in your background.js create a listener for the message:
chrome.extension.onMessage.addListener(
function (request, sender, sendResponse) {
if (request.cmd == "postImage") {
var imageSrc = request.data.imgSrc;
}
});

Chrome addon with my server interaction

its many days reading hundreds of ways to help me make what I really need. No success at all.
What I need is this:
1) Having a button which only works when the tab has a certain url.
2) After clicking it, must read page's source and then get some pieces of it to send them to my server page in order to check my database for recordcounts (I assume with AJAX & javascript). Then this page should send back to the extension its responses and populate the popup html.
Looks easy I know, but please I need the workflow if not the required codes for the extension.
Thank you so much!
ok so you can chceck selected tab and it's url with:
chrome.tabs.getSelected(null,function(tab) {
workWithUrl(tab.url);
});
...
function workWithUrl(url){
if (url == ...
...
}
To be able to chceck this you need to add permission for "tabs"
To process page source code, send it to web service and change popup.html:
var xhr = new XMLHttpRequest();
xhr.open("POST", "__server adress___", true);
//headers
xhr.setRequestHeader("Content-Type", "application/json");
//response
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
//response from service to popup.html
document.body.innerHTML = xhr.responseText;
}
}
//process page here
xhr.send(pageText);
You have to add permission for server adress to manifest as well and everything should be executed from popup.js (or html).

Chrome Devpanel Extension Communicating with Background Page

I have an extension to the chrome devtools panel. I can send messages to the page using chrome.devtools.inspectedWindow.eval ... but how do I receive messages in the dev panel? Specifically, I need my devpanel to hook into events that happen on the page. I can't get it to listen to events on my content script, nor the background page.
I've tried chrome.extension.sendMessage in the content script, along with chrome.extension.onMessage.addListener in the dev panel script. But sendMessage complains with Port error: Could not establish connection. Receiving end does not exist.
The issue persists with long-lived connections:
In content script or background page:
var port = chrome.extension.connect({name: "test"});
port.postMessage({msg: "testing"});
In dev tools panel javascript:
chrome.extension.onConnect.addListener(function(port) {
port.onMessage.addListener(function(msg) {
// never gets here
});
});
How can I listen for events that are triggered in my content script-- in my dev tool panel? A diagram like this from Firefox's Add-On SDK would be great: https://addons.mozilla.org/en-US/developers/docs/sdk/latest/static-files/media/content-scripting-overview.png
The goal is to create a channel ("port") for communication. It does not matter how the port is created, as long as the connection is correctly maintained.
The devtools script has to initiate the port, because the background script does not know when a devtools panel is created.
Here's a basic example, which shows a bidirectional communication method:
devtools.js
chrome.devtools.panels.create('Test', '/icon.png', '/panel.html', function(extensionPanel) {
var _window; // Going to hold the reference to panel.html's `window`
var data = [];
var port = chrome.runtime.connect({name: 'devtools'});
port.onMessage.addListener(function(msg) {
// Write information to the panel, if exists.
// If we don't have a panel reference (yet), queue the data.
if (_window) {
_window.do_something(msg);
} else {
data.push(msg);
}
});
extensionPanel.onShown.addListener(function tmp(panelWindow) {
extensionPanel.onShown.removeListener(tmp); // Run once only
_window = panelWindow;
// Release queued data
var msg;
while (msg = data.shift())
_window.do_something(msg);
// Just to show that it's easy to talk to pass a message back:
_window.respond = function(msg) {
port.postMessage(msg);
};
});
});
Now, the panel is capable of sending/receiving messages over a port. The panel's script (external script file, because of the CSP) may look like:
panel.js
function do_something(msg) {
document.body.textContent += '\n' + msg; // Stupid example, PoC
}
document.documentElement.onclick = function() {
// No need to check for the existence of `respond`, because
// the panel can only be clicked when it's visible...
respond('Another stupid example!');
};
Now, the background page's script:
background.js
var ports = [];
chrome.runtime.onConnect.addListener(function(port) {
if (port.name !== "devtools") return;
ports.push(port);
// Remove port when destroyed (eg when devtools instance is closed)
port.onDisconnect.addListener(function() {
var i = ports.indexOf(port);
if (i !== -1) ports.splice(i, 1);
});
port.onMessage.addListener(function(msg) {
// Received message from devtools. Do something:
console.log('Received message from devtools page', msg);
});
});
// Function to send a message to all devtools.html views:
function notifyDevtools(msg) {
ports.forEach(function(port) {
port.postMessage(msg);
});
}
To test, simply run notifyDevtools('Foo'); on the background page (e.g. via the console). In this demo, the message will be sent to all devtools. Upon receipt, the devtools panel will contain the received message.
Put the extension together using:
manifest.json
{
"name": "Test",
"manifest_version": 2,
"version": "1",
"devtools_page": "devtools.html",
"background":{"scripts":["background.js"]}
}
panel.html
<script src="panel.js"></script> <!-- Doctype etc not added for conciseness-->
devtools.html
<script src="devtools.js"></script>
See also
How to modify content under a devtools panel in a Chrome extension?
chrome.devtools API
Message passing: Long-lived connections
Content Security Policy in Chrome extensions ("Inline JavaScript (...) will not be executed. This restriction bans both inline <script> blocks and inline event handlers.")

how to communicate between a options page and background page of chrome extension

I face a problem. Through message passing I transferred DOM data from content script to background page. What i would like to know is how you can establish a communication channel between Options page and background page. The API chrome.extension.getBackgroundPage() is not useful. Nor is traditional message passing through sendRequest and addlistener working . How do i transfer this data from background page to the options page? Could someone provide a tested snippet to explain?
this is what i have been trying .
In my contentscript.js
<script>
var selected_Text ="";
window.addEventListener("dblclick",function(event){
selected_Text = String(window.getSelection());
chrome.extension.sendRequest({greeting: "maprender",name:selected_Text}, function(response) {
alert("reached here")
console.log(response.farewell);
});
//i am to then load options.html on DOM like this
var Div = document.createElement("iframe");
Div.setAttribute('src', chrome.extension.getURL('options.html'));
Div.setAttribute("style","width:130px;height:80px;position:absolute;left:10px;");
Div.setAttribute("id","xyz");
document.body.appendChild(Div);
</script>
I retreive the selected_Text at background.html like this
<script>
var Addr_details={
place:null
};
chrome.extension.onRequest.addListener(
function(request, sender, sendResponse) {
if (request.greeting == "maprender")
{
alert("reached here sendin resp"+request.name);
Addr_details.place = request.name;
sendResponse({farewell: "goodbye"});
}
else
sendResponse({}); // snub them.
});
</script>
Now to access the value of this text at the options page options.html i tried 2 methods
One was to use chrome.extension.getBackgroundPage() like this:
<script>
function init(){
var bkg = chrome.extension.getBackgroundPage();
alert("the selected text is "+bkg.Addr_details.place);
}
</script>
init is onload of options.html .This does not give me the value . infact it just terminates at initialization of chrome.extension.backgroundPage.
Another approach i tried was to create a similar request(like the one already present at contentscript.js) from contentscript.js with a different greeting and add a listener to it at options.html .That doesnt seem to work either at the receiver side(options page) because i get the callback at the contentscript after the request.I am surely doing something wrong , amnt I ?Please help.
It makes sense for the second approach not work. Options.html is not "alive" all of the time, only when the options page is up. Hence, it cannot listen to requests from the content script.
That's exactly what "background" is for.
As for the first approach (using getBackgroundPage()), I never used this method myself, but it seems to bring back only the DOM of the background page, and therefore you cannot access the variables in the background js.
Your best shot should be to send a request from the options page to the background page, asking for this value, e.g.:
Content script:
chrome.extension.sendRequest({greeting: "retrieveAddr"}, function(response) {
// do something with response.addr...
});
Background page:
chrome.extension.onRequest.addListener(
function(request, sender, sendResponse) {
switch (request.greeting) {
case "maprender"):
alert("reached here sendin resp"+request.name);
Addr_details.place = request.name;
sendResponse({farewell: "goodbye"});
break;
case "retrieveAddr":
sendResponse({addr: Addr_details});
default:
sendResponse({}); // snub them.
});
});
Another, easier but hackier solution is to use localStorage to pass info between the options and background pages, as they both share the same one.