Store data when popup loses focus - javascript

I'm developing a Chrome extension and I would like to preserve user input data when user closes the extension's popup. Is there any reliable way to do this using local storage when the extension popup loses focus?

I managed to figure that one out. When I was calling store functions directly from popup unload callback (detecting lost focus) it didn't work. Managed to do that when I was doing the storage in background page. Sample code below:
Background script:
function storeFormDataLocally(someData) {
if (someData != null) {
chrome.storage.local.set({
'someDataKey': someData
}, function() {
console.log("data saved: " + someData)
});
}
}
Popup:
addEventListener("unload", function(event) {
var background = chrome.extension.getBackgroundPage();
var someData = "My data to store";
background.storeFormDataLocally(someData);
}, true);

Related

How to prevent popup from showing up again once user has dismissed it?

I have a modal that triggers different on mobile vs. desktop. Mobile's popup is triggered by an inactive mouse for more than 10 seconds, and desktop's popup is triggered by the mouse leaving the page (mouseleave). However when I dismiss the modal on both devices, it reappears after the user does the triggered action again. How do I get the popup to only pop up once and not display again once the user dismisses it?
Here is my code:
Dismiss popup by adding class "hidden" on the modal, called #abandon-cart-message:
//Dismiss popup
function dismissModal() {
const dismissSelectors = [
"#abandon-cart-message .evg-btn-dismissal",
"#abandon-cart-message .button-cta",
];
Evergage.cashDom(dismissSelectors.join(",")).on("click", () => {
const dismissPopup = document.querySelector("#abandon-cart-message");
dismissPopup.classList.add("hidden");
});
}
Display popup function for inactive users, used for mobile
//display popup for inactive users
const inactiveUserMessage = () => {
//code for displaying the popup is tool specific so not showing code
console.log("popup displayed");
return dismissModal();
};
Display popup function for users when their mouse leaves the page, used for desktop
function exitUserMessage() {
//code for displaying the popup is tool specific so not showing code
console.log("popup displayed");
return dismissModal();
}
Trigger the actual popup
// Trigger popup for mobile
if (width <= 480) {
document.addEventListener("mousemove", debounce(inactiveUserMessage, 10000), timer);
} else {
// Trigger popup for desktop
document.addEventListener("mouseleave", (e) => {
return exitUserMessage();
});
}
Debounce function, stored as a module from another file and pulled in:
export function debounce(func, timeout, timer) {
return (...args) => {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
func.apply(this, args);
}, timeout);
};
}
Any ideas?
I tried to trigger a popup on mobile and desktop with both being triggered by different actions. However they are both reappearing after the user performs the same actions but I only want it to show one time once - if the user dismisses the popup it doesn't show again.
For JavaScript, you can use two ways two ways, Local Storage and Session Storage.
Local Storage
localStorage store during sessions (after closing the browser the data remains)
To use it:
// Get value
const userDismissed = localStorage.get('dismissed');
// Check if is already dismissed
if( userDismissed && userDismissed === 'yes' ){
// Don't trigger
}
And to your dismiss function, define the localStorage
localStorage.setItem('dismissed', 'yes');
In case you need to reset the values
localStorage.clear(); // Remove all
localStorage.removeItem('dismissed'); // Remove just one item
Session Storage
sessionStorage stores during the session is active (it resets when browser is closed)
To use it, it works same way than localStorage above, just use sessionStorage instead.

Chrome Extension - ContextMenu listener not working after few minutes

I'm trying to create a Chrome Extension which can dynamically create ContextMenu based on storage info. Each created menu has its owned key and will do some actions then send message to Content.js to show info box on page if it is clicked.
The menu will be updated if user select some options in Options page. The Options.js will send out a message to background.js, background.js update the storage then refresh menu.
The menu behavior works fine after extension was loaded. But no longer work after few minutes. If I open a console of service worker then it can stay longer, but it eventually no response when i click menu button. Further more, if i trigger the menu updating from Option page, the button back to live. But still failed after few minutes.
I made some research and found out seems background.js will be terminated very soon after it was loaded. So i doubt that cause this issue. But how com the added menu listener not working after that? The listener should already be added, isn't it?
Background.js
function eventListener(message, sender, sendResponse) {
if (message.event === "updateMenu") {
updateMenu();
sendResponse({ result: "update menu completed" });
}
}
function updateMenu() {
chrome.storage.local.get("currencyMappings", function (result) {
prepareContextMenuBySetting(result.currencyMappings);
});
}
function prepareContextMenuBySetting(mappings) {
chrome.contextMenus.removeAll();
chrome.contextMenus.create(
{ id: "rootMenu", title: "%s", contexts: ["selection"] },
function () {
if (chrome.extension.lastError) {
console.log("Got expected error: " + chrome.extension.lastError.message);
}
});
mappings.forEach(map => {
currencies = map.split("|");
chrome.contextMenus.create(
{ id: `${currencies[0]}to${currencies[1]}`, title: `${currencies[0]} => ${currencies[1]}`, type: "normal", parentId: "rootMenu", contexts: ["selection"] });
})
chrome.contextMenus.onClicked.addListener(
(info, tab) => {
let rate = null;
rateKey = info.menuItemId.split("to");
makeExchange(rateKey, info)
}
);
}
Update:
Log will display when the function is working. But there was no any log in console when the button action is not working. Event both Server Worker and page console.
I figure out the possible reason. According to https://developer.chrome.com/docs/extensions/mv2/background_pages/#listeners
adding listener in listener function may not working.
The root cause is that the backgound.js will be terminated in short time. Only keep the root listener. After backgound.js is terminated, the listener in my menu button not working anymore.
Further more, the background.js actually back to live if the root listener get called.
Ex.
chrome.runtime.onMessage.addListener(eventListener);
i added a console.log() at the top of background.js and monitor the console. After the Service Worker display unavailable, which means the backgroud.js is shut down, then I fire a message to background.js. The console.log() will be triggerd.
The solution of my issue is moving adding listener of menu to root level.
chrome.contextMenus.onClicked.addListener(
(info, tab) => {
console.log("item clicked");
let rateKey = info.menuItemId.split("to");
makeExchange(rateKey, info)
}
);
Then once background.js is wake up, the button listener will be set.

Onclick change url to previous url

So I have a page, with a link on it that opens a custom modal window that I built. I created an onclick method to handle a url change so that a user can save the url and open the modal page directly if they want. And then the idea would be when you close the modal, it returns to it's previous url.
HTML
<div onclick="ChangeUrl('Case study 5', 'BASEURL/case_studies=case-study-5');" ></div>
JS
function ChangeUrl(title, url) {
var address = window.location.href;
alert(address);
if (typeof (history.pushState) != "undefined") {
var obj = { Title: title, Url: url };
history.pushState(obj, obj.Title, obj.Url);
} else {
alert("Your Browser does not support HTML5. Please update your browser
to get the full experience of our website.");
}
This works great, but the problem is I am using the same onclick method to change the url when the modal is closed. Which would be fine if I was only doing this from one main page, but the modal window php file is being accessed from multiple pages to use as a modal, so I need some dynamic way to change the url back to the previous page's url. Is there any way to grab the url and put it into the onclick method in my modal php so that it will return to the previous page?
EDIT
On robmarston's advice I changed my modal html to include a data attribute called modalstate, which is set to open.
I then updated the JS to take into account the state of the attribute like so.
JS
function ChangeUrl(title, url) {
if (typeof (history.pushState) != "undefined") {
console.log($('.js-post-close').data('modalstate'));
if($('.js-post-close').data('modalState') == "open"){
var obj = { Title: "blueleaf", Url: address};
history.pushState(obj, obj.Title, obj.Url);
}
else {
address = window.location.href;
var obj = { Title: title, Url: url };
history.pushState(obj, obj.Title, obj.Url);
}
} else {
alert("Your Browser does not support HTML5. Please update your browser to get the full experience of our website.");
}
console.log(address);
}
This does not work, even thought the console will log "open" whenever I click to close the window. I also tried using $('.js-post-close').data('modalState') != undefined), but with the same result. The page will not enter the appropriate logic to change the url back to address.
You could always add an attribute to the div to specify which state the modal is in, something like:
<div data-modalstate="open" onclick="ChangeUrl('Case study 5','BASEURL/case_studies=case-study-5');"></div>
Then your function could simply assets the modalstate and take the appropriate action.

How can I get different badge value for every tab on chrome?

I'm trying to do something like adblock does. Adblock counts number of "ads" and update badge value. For now, I tried to do something with 'background pages', but they are run only one time and badge value is the same for all tabs. I can't use browser action popup.html, because it triggers only after the click.
So I need something which takes current tab, is able to read current DOM of tab and after all update badge value. But also after I click on different tab I need to compute new badge value.
Thanks in advance
The badge text is stored for each tab independently provided you specify tabId parameter, you don't have to update it manually after the user switches tabs if you already have set the value.
So if your extension processes the pages immediately after loading, call chrome.browserAction.setBadgeText once. You can do it e.g. by sending a message from your content script to your background/event page which will invoke setBadgeText with the sender tab's id (this parameter is what makes the text unique to a tab).
content script:
chrome.runtime.sendMessage({badgeText: "123"});
background/event script:
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.badgeText != null) {
chrome.browserAction.setBadgeText({
tabId: sender.tab.id,
text: message.badgeText,
}, () => chrome.runtime.lastError); // ignore errors due to closed/prerendered tabs
}
});
You can listen to the Chrome tab events in your background/event page. The following code helped me to solve the same problem:
// fires when tab is updated
chrome.tabs.onUpdated.addListener(updateBadge);
// fires when active tab changes
chrome.tabs.onActivated.addListener(updateBadge);
function updateBadge() {
// get active tab on current window
chrome.tabs.query({active: true, currentWindow: true}, function(arrayOfTabs) {
// the return value is an array
var activeTab = arrayOfTabs[0];
if (!activeTab) return;
// compute number for badge for current tab's url
var count = getCount(activeTab.url);
chrome.browserAction.setBadgeText({
text: count.toString()
});
});
}
function getCount(currentUrl) {
// your logic, e.g., return 42
}
You can write an "onActiveChanged" listener and call your updateBadge function and pass the tabId. Hope it helped.
chrome.tabs.onActiveChanged.addListener(function (tabId, changeInfo, tab) {
updateBadge(tabId);
});
function updateBadge(tabId) {
...
}

Firefox extension open an HTML options page

I have an options page for my extension that is made with HTML and javascript tio be activated when options are selected. The extension is a window that hovers over the web page, and it has an "Options" button in it already.
I need to have the options page be opened in a separate tab in the browser when the button is clicked.
What I have so far is:
mainPanel.port.on("options", function () {
currentUser=null;
mainPanel.hide();
var url = serverURL+"/options.html";
tabs.open(url);
});
options.html is stored in the main file for the extension, and serverURL refers to the main server that the extension contacts for information.
In this case you need to use Port.on()/Port.emit() to send a controll option from options.html, like click on setting button.
options.html
var panelIsOpen = 0;
$('#settings').click(function() {
self.port.emit("statusoptions", {optionsIsOpen:1});
});
popup.html
Panel.port.on("statusoptions", function (panda) {
if(panda.optionsIsOpen === 1){
Panel.hide();
tabs.open({
url: "options.html",
onReady: function onReady(tab) {
Panel.hide();
},
contentScriptFile: [
data.url("js/jquery-2.0.0.min.js"),
data.url("js/options.js")],
});
}
});

Categories