I have a chrome extension that creates popups in a static location. However, if the user moves the popup and then closes it. I'd like to set the next popup to open in the same location the previous one was closed.
My background page is already listening for onRemoved and onFocusedChanged, but those only return the Window ID.
Is there a way to get the last top and left locations of a popup window after a user moves it, and on or before it is closed?
We can use beforeunload event and we need a synchronous method of saving data in order to guarantee it successfully completes before the execution context of the page is destroyed.
If the popup runs your extension page.
Popup's page script can save the size in the synchronous localStorage shared between all your extension pages, including the background script where you can use the saved value next time to create the popup window.
window.addEventListener('beforeunload', () => {
localStorage.windowSize = JSON.stringify({
left: window.screenX,
top: window.screenY,
width: window.outerWidth,
height: window.outerHeight,
});
});
If the popup runs a web URL.
We'll have to use a content script where we can abuse chrome.runtime.connect to pass the data synchronously in the port name to the background script which will parse and save the data in chrome.storage.local. Of course you can use this approach for the first case as well.
content script:
window.addEventListener('beforeunload', () => {
chrome.runtime.connect({
name: 'windowSize:' + JSON.stringify({
left: window.screenX,
top: window.screenY,
width: window.outerWidth,
height: window.outerHeight,
})
});
});
Make sure the content script runs inside the popup, for example, via chrome.tabs.executeScript in your background script right after creating the popup window.
background script:
chrome.runtime.onConnect.addListener(port => {
if (port.name.startsWith('windowSize:')) {
const windowSize = JSON.parse(port.name.slice('windowSize:'.length));
chrome.storage.local.set({windowSize});
}
});
Related
Use case:
website opens an extension popup window when a user clicks on a button
user performs some actions in the extension popup
a result of that action is sent back to the browser tab which initially opened the extension
Approach
(1) window.postMessage(data): Send a message to the content script where window.addEventListener("message", (event) => {...} is receiving the message event.
(2) chrome.runtime.sendMessage(event.data, function(response) {...}: This functionality is in the listener above and forwards the message to the background script where chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {...}) is receiving the message.
(3) Background scripts opens the extension as a dedicated popup window:
chrome.windows.getLastFocused().then((window) => {
const width = 600 + 100;
const height = 400 + 100;
const left = window.width - width;
chrome.windows.create({url: path, type: "popup", height: height, width: width, left: left, focused: true});
});
(4) After having processed some user actions within the extension popup a response message should be returned to the content script:
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {...})}
Problem
Everything works fine up to step (4). Because the extension popup has been opened programmatically as a dedicated popup window tabs[0].id contains a tab id from the extension popup window instead of the browser window which triggered the whole flow and where the content script runs.
How can the correct tab id be determined or forwarded along the chain to the popup?
Is this messaging scenario the right approach for my requirements?
Any feedback is very much appreciated!
After a lot of times spend to find the solution, i'm here to ask your help.
I have a simple chrome extension, and what I try to do is simple:
Detect on the page when a button is clicked, then, open the extension popup.html.
A good example is MetaMask, the html page can open the popup to connect the wallet, send transaction ...
Thank you !
Run a content script on the page and send a message to the background when the button is clicked.
// Content Script
button.addEventListener("click", () => {
chrome.runtime.sendMessage("OpenPopup")
})
Catch the message in the background and create a window with your popup URL. Provide a "top" and a "left" value to place it at the top right of the users' screen. Use the type "popup" to get rid of the stuff that is usually at the top of a window. Read more about the chrome.windows.create method here.
// Background Script
chrome.runtime.onMessage.addListener(request => {
if (request == "OpenPopup") {
chrome.windows.create({
url: "popup.html",
type: "popup",
focused: true,
width: 400,
height: 600,
top: 0,
left: screen.width - 400,
}, () => {
console.log("Opened popup!")
})
}
})
I am currently writing a Firefox extension that opens a new window in my background script. When a user clicks a button on a page the background script executes and opens the window.
So far I have:
// content script
downloadMod(linkToOpen); //button clicked
function downloadMod(url) {
// var test = window.open(url, '_blank');
var myPort = browser.runtime.connect({ name: "cac410c4672fff93bf0d3186636d8876de3dfeb6#temporary-addon"});
myPort.postMessage({ greeting: url });
}
In my background script (the script the above code connects too) I have:
//background script
portFromCS.onMessage.addListener(function (m) {
var test = browser.windows.create({
url: m.greeting,
allowScriptsToClose: true,
});
NOTE: all the code works as expected. However, the trouble comes when closing the window.
I have tried variations of self.close(), window.close(). I even created a function to wait 5 seconds to load the newly created window and then close the page to no avail. All of my attempts come back with the error:
Scripts may not close windows that were not opened by script.
I thought this error was supposed to be removed with the allowScriptsToClose flag?
To close a window you created with browser.windows.create, you need to use browser.windows.remove.
So:
let windowId;
browser.windows.create({url: "http://google.be"}).then((data) => {
windowId = data.id;
});
// Sometime later, use windowId to close the window
setTimeout(function(){
browser.windows.remove(windowId);
}, 5000);
I'm using ajax for some function for my website, in success function I write some code:
success: function(html) {
window.open("http://localhost/demo/index.php",'name','height=243,width=800');
}
There are some problems I met:
This page (popup window) can not load css
I can disable main browser
I want to redirect main window after popup window is closed
How can I do that?
P/S: If I can't do that, how do I display popup when success function is called?
1. This page (popup window) can not load css
There might be some problem with your style urls. Check them in browser console.
2. I can disable main browser
You can't disable main browser, but As per my understanding you are trying to block page elements. So block UI can help. Use block UI to block your page contents and it will be automatically removed when you will redirect your main page.
3. I want to redirect main window after popup window is closed
You need to bind a custom redirect method to your window close to redirect your main page when window is closed.
success: function (html) {
myWindow = window.open("http://localhost/demo/index.php", 'name', 'height=243,width=800');
myWindow.onbeforeunload = function () {
return RedirectPage();
}
function RedirectPage() {
window.location.location.href = "http://www.yoursite.com";
}
You can redirect main window using:
window.parent.location.href = "http://www.site.com";
Regarding popup window not loading css, it might be issue with improper CSS include URL's in popup page html.
I did a simple auto form filler, by sending info from a created html to the background and then the content script, so the injected script can change the info on the form.
I know the content script run once the page is load. I want to know if I can run the content script again, without the need of reloading the page.
I got sendRequest function in the content script, that I use to make sure it gets the info, only when the page is ready. It then add the info to the form, and wait for me to send it.
In the content script, I added a onRequest and it works (it get the info). but, I don't see the changes on the form, unless I am realoding the page.
I want to know if it is possible to do and if it does what subjects should I learn to implent this.
I am new to chrome extentions and I am still learning :)
in 1 of the pages, I use jQuery, so an answer with jQuery would be good too.
i found out that if we create a chrome.tabs.sendRequest from background we can use chrome.extestion.onRequest from content script and it will execute every time becuse they both run allmost in the same time.
so i did from background:
chrome.tabs.query({}, function (tabs) {
for (var i = 0; i < tabs.length; i++) {
chrome.tabs.sendRequest(tabs[i].id, {...requests u want to send }, function (response) {
});
}
});
from content script:
chrome.extension.onRequest.addListener(function (request, sender, sendRespons) {
//get requested info here
//call functions.
sendResponse({}); //send info back to background page.
});
form's target could be an iframe which would avoid page reload. not sure how useful it'd be.
The correct way to execute a content script again is by using the chrome.tabs.executeScript method. It receives two arguments. The first argument is the tabId, which can be obtained in many ways, such as one of the chrome.tabs events. Use null to execute the content script in the currently selected tab (caution: this may also be an active dev tools window!).
Examples:
// Reloads the current tab
chrome.tabs.executeScript(null, {code:'location.reload();'});
// Executes contentscript.js in the current tab
chrome.tabs.executeScript(null, {file:'contentscript.js'});
// Executes contentscript.js in all frames in the current tab
chrome.tabs.executeScript(null, {file:'contentscript.js', allFrames: true});
// Receives message from content script, and execute a content script:
chrome.extension.onMessage.addListener(function(details) {
if (details.message === 'load a content script') {
chrome.tabs.executeScript(details.sender.tab.id, {file: 'a_script.js'});
}
});
// The previous one is activated from a content script, as follows:
chrome.extension.sendMessage('load a content script');
(onMessage and sendMessage have to be used instead of onRequest and sendRequest, since Chrome 20)