Listen to Firefox WebExtension sidebar closing - addeventlistener

I am working on a WebExtension using the sidebar.
When the sidebar is open, the extension performs some operations on the current tab. When it is closed, I want to revert these operations.
Is this possible? I didn't see methods like browser.sidebarAction.addEventListener.

I adapted GnxR's idea in the following:
extension/page/sidebar.html:
<!DOCTYPE html>
<html>
<body>
<div id="panel"></div>
<script src="static.js"></script>
</body>
</html>
extension/page/static.js:
window.addEventListener('beforeunload', (event) => {
console.log('Sidebar will be closed!');
// Do stuff
});
window.addEventListener('pagehide', (event) => {
console.log('Sidebar is hidden!');
// Do stuff
});
window.addEventListener('unload', (event) => {
console.log('Sidebar is unloaded!');
// Do stuff
});
When closing the extension (both from the cross bar and programmatically), I get the following in the browser console:
Sidebar is hiding! static.js:6:3
Sidebar is unloaded! static.js:10:3
Therefore it seems that both pagehide and unload events can be used,
but that beforeunload is never fired.

The sidebar is an alsmot-regular independent webpage, in which you can listen to usual JS events. In order to know when the sidebar is closing, you can use beforeunload in the sidebar's JavaScript:
window.addEventListener('beforeunload', (event) => {
console.log('Sidebar is closing!');
// Do stuff
});

Related

navigator.sendBeacon not called from unload

According to MDN and the specs, navigator.sendBeacon is intended to be called from window unload.
Now, it does not seem to work anymore if you close the last tab of your browser, or your entire browser window.
Can anyone confirm if this is by design? If so, is there a workaround to send lastminute data on unload?
I tested with this sample file, in Firefox 74 and Chrome 81, looking for calls with Fiddler.
<html>
<head>
<title>unload test page</title>
<script>
window.addEventListener("unload", function () {
navigator.sendBeacon('https://developer.mozilla.org/en-US/docs/Web/API/Navigator/sendBeacon');
});
</script>
</head>
<body>
<p><div>unload test page</div></p>
</body>
</html>
MDN states (as of 1/12/2021):
It’s intended to be used in combination with the visibilitychange
event (but not with the unload and beforeunload events)
When visibilitychange transitions to hidden, you can treat that as when the tab/browser is closing and use sendBeacon then.
Example code from MDN:
document.addEventListener('visibilitychange', function logData() {
if (document.visibilityState === 'hidden') {
navigator.sendBeacon('/log', analyticsData);
}
});

Making offline.js work with turbolinks

I am using offline.js with turbolinks and on initial page load it works fine. But if I click another links then this wont work until I refresh the page. I can see the Offline.state is down but still the view is not showing. Is there any way to manually trigger the popup window?
Update
Other than the offline.js file the only js I have is this
var
$online = $('.online'),
$offline = $('.offline');
Offline.on('confirmed-down', function () {
$online.fadeOut(function () {
$offline.fadeIn();
});
});
Offline.on('confirmed-up', function () {
$offline.fadeOut(function () {
$online.fadeIn();
});
});
This is an old question, but I ran into the same problem, maybe it can help someone.
offline.js creating these dom elements on page load inside the body HTML
<div class="offline-ui offline-ui-up">
<div class="offline-ui-content"></div>
</div>
The reason why offline.js not working after page change is that on-page change the body HTML replaced with the new content returned by the server and the code above removed.
This is how Turbolinks works, so page load will be not triggered and the offline.js dom elements will be not created.
One solution will be to warp the offline.js inside a function and call it on every page change, but it will cause eventually memory leak (as "offline" and "online" event listener will be added to 'window' on each change)
Other solution will be to save the 'offline-ui' HTML before the new page loaded and bring it back after load:
# will fire before page change and save offline.js UI
document.addEventListener("turbolinks:before-render", function() {
if (!document.offlineHtml) {
document.offlineHtml = $('.offline-ui');
}
});
# will fire afterload and will check if there is a UI to append to the body
document.addEventListener("turbolinks:load", function() {
if (document.offlineHtml) {
$(document.body).append(document.offlineHtml);
}
});
At the moment this is the best way that I could find to fix that.
This could be a turbolinks issue. In app/assets/javascripts/application.js, wrap your javascript code within:
$(document).on('turbolinks:load', function() {
// your code
});

access custom dom function from firefox add-on

I am working on a Firefox Add, using the newest SDK. The problem I am having, is that when ever I try to run a custom dom function it doesn't work.
Scenario:
The firefox add-on must be able to loop through all tabs, and if the correct one is open based on the title, run a specific function, like: mydom.checkIt();
<!DOCTYPE html>
<html>
<head>
<title>My Web</title>
</head>
<body>
<script>
mydom = {};
mydom.checkIt = function (){
alert('Hi');
};
</script>
</body>
</html>
Then the add-on source code would be something like:
var tabs = require('sdk/tabs');
for (let tab of tabs)
{
if(tab.title=='My Web')
{
tab.activate();
}
}
tabs.on('activate', function(tab) {
tab.attach({
contentScript: "if(typeof(mydom)!=='undefined')mydom.checkIt();else console.log('no defined');"
});
});
But this doesn't work and it says always: "no defined"
Any ideas?
You have to get into the dom js scope with unsafeWindow or wrappedJSObject. So contentWindow.wrappedJSOBject.checkIt() works from bootstrap addon (not sure about sdk)
Warning though, this may not be e10s friendly and we should find a way to support that

jQuery UI tabs: How do I load a specific element from a different page?

I have jQuery UI tabs set up, but a problem that I'm having with links to different pages is that they load all contents of the page into the tab. This includes the footer, header, and other navbars that I don't want in the tab. What if I would only like to load a single ID from that page?
My tabs are set up this way:
<div id="mytabs">
<ul>
<li>Awesome page</li>
<li>Foo</li>
</ul>
</div>
Nothing much going on in the jQuery...
$(function() {
$( "#mytabs" ).tabs();
});
Let's say this is the html of "awesomepage" (that the first link targets):
<html>
<head>
<title>awesome page</title>
</head>
<body>
<div id="header">bla</div>
<div id="awesomeness">awesomeness!</div>
<div id="footer">fdsfd</div>
</body>
</html>
...And I only want the tab to load #awesomeness from the page. How would I go about doing this? I've read into some guides that do that by adding a data-target="#youridhere" attribute to the HTML, but I'm still confused on how to implement the javascript. It seems like this is a convenient solution, as I won't be targeting the same ID in every page. Any clues on how to get the javascript working?
Thanks in advance!
The function that allow to load partial code of the response is the $.load() function.
Unfortunately, the tabs() feature does not use this function but use $.ajax instead.
You can try this solution:
You can try to stop the default processing on the beforeLoad callback and manage your ajax call with the $.load() method.
(base on the 1.9 documentation, you may should adapt)
$('#tabs').tabs({
// Callback run when selecting a tab
beforeLoad: function(event, ui) {
// If the panel is already populated do nothing
if (ui.panel.children().size() > 0)
return false;
// Make your own ajax load (with fragment feature)
ui.panel.load(ui.tab.attr('href') + ' #yourFragment');
// stop the default process (default ajax call should not be launched)
return false;
});
NOTICE: I'm not sure about extracting the URL with ui.tab.attr('href'), check before what object is ui.tab, but it should be easy to retrieve the href parameter.
Good luck
Got the solution :) Using one of the answers as a reference point, the tabs can now load a single element specified in the data-target attribute. Here is the modified version:
$(function() {
$('#tabs').tabs(
{
beforeLoad: function(event, ui) {
if (ui.panel.children().size() > 0)
return false;
ui.panel.load($('a', ui.tab).attr('href') + $('a', ui.tab).attr('data-target'));
return false;
}
});
});

Opening dialog programmatically causes pageInit event to fire

I'm opening a dialog programmatically with this piece of code:
$.mobile.changePage('#about', {
transition: 'pop',
changeHash: false
});
#about block is on the same page:
<div id="about" data-role="dialog">
<!-- -->
</div>
But every time I do that, pageInit event is called, which is a very unwanted behavior.
Is there any way around this?
I'm not sure what you mean by "which is a very unwanted behavior" but if you want to only run code once for a dialog then add a check to see if it has been initialized yet:
$(document).delegate('#about', 'pageinit', function () {
if ($(this).hasClass('ui-dialog') === false) {
//code in here will only run once per page load/refresh
}
});
jQuery Mobile adds classes to each of the widgets it initializes, you can check the widgets for these classes to test if they have been initialized yet or not.

Resources