access custom dom function from firefox add-on - firefox-addon

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

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);
}
});

Listen to Firefox WebExtension sidebar closing

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
});

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;
}
});
});

Trigger.io load page dynamically

So I was using trigger.io to create a page where there's a custom menu at the bottom and each button loads an external HTML page into main container. I had to hack around to make this work so I was wondering if there's a better way of doing it.
I started using the $('.main').load('pages/test.html') and it doesn't work. Instead I had to do:
forge.file.getLocal('pages/test.html', function (file) {
forge.file.string(file, function (str) {
$('.main').html(str);
});
});
which is kinda messy.
Also if the str HTML content as a img tag, the img doesn't show since the src attribute gets messed up. So I had to do another hack:
forge.file.getLocal('pages/test.html', function (file) {
forge.file.string(file, function (str) {
var $main = $('.main');
$main.html(str);
//Hack to resolve img src
var imgPath;
$main.find('img').each(function () {
var $this = $(this);
// First 8 chars is "file:///"
imgPath = $this.prop('src').substr(8);
forge.file.getLocal(imgPath, function (file) {
$this.prop('src', file.uri);
});
});
});
});
Any better way of purely loading an external HTML page without all the hassle?
Thanks!
Testing with forge platform v1.4 (at the time of writing, v1.4.18) on Android 4.1 and iOS (both the iPhone simulator and an iPad), I seem to be able to use jQuery's load method without any extra effort. Here's the structure for my testcase:
src/
index.html
face.png
pages/
hello.html
Here's the contents of index.html
<!DOCTYPE html>
<html>
<head>
<script src="js/jquery-1.7.1.min.js"></script>
<script type="text/javascript">
$(function () {
$('.content').load('pages/hello.html');
});
</script>
</head>
<body>
<div class="content">
</div>
</body>
</html>
And pages/hello.html:
<b>hello world</b><img src="face.png">
Which resulted in this just after app launch:
One gotcha I can see with this approach is that the src attribute for the img tag had to be relative to index.html. If you're still having problems then a more specific testcase and/or details of forge platform version used as well as what devices/simulators you tested on might be useful.

Combining jQuery Mobile and MathJax on a mobile site?

There seems to be some issues when combining MathJax and jQuery Mobile on the same page. Sometimes the MathJax renders correctly and other times it does not - and this can happen to the same page.
The HTML that loads both of them looks like this:
<script type='text/javascript' src='http://code.jquery.com/jquery.min.js'>
</script>
<script type='text/javascript'
src='http://code.jquery.com/mobile/1.0a4.1/jquery.mobile-1.0a4.1.min.js'>
</script>
<link rel='stylesheet' type='text/css'
href='http://code.jquery.com/mobile/1.0a4.1/jquery.mobile-1.0a4.1.min.css' />
<script src='/beta/mathjax/MathJax.js'>
</script>
You can see an example page here: http://stackmobile.com/beta/math.stackexchange.com/questions/view/?id=47772
Edit: It seems to be a problem with MathJax not recognizing a new page being loaded via AJAX - here is an example that doesn't seem to work: http://stackmobile.com/beta/#/beta/physics.stackexchange.com/questions/view/?id=11678
Well I found a solution... and it goes something like this:
First assign unique numbers to the pages. Since these pages are generated in PHP, this can be accomplished by using uniqid().
Assign the following function the the pageshow event:
$('#page_id').live('pageshow', function(event, ui) {
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'path_to_mathjax/MathJax.js';
script.onload = callback;
document.getElementsByTagName('head')[0].appendChild(script);
});
This loads MathJax and inserts it into the DOM - this script should be included within the page element. Also note that we mention a 'callback'. This will be called when the script loads.
This function (the callback) needs to go outside of any pages. This will prevent it from being included twice after a new page is loaded.
var mathjax_loaded = false;
function callback()
{
if(mathjax_loaded)
MathJax.Hub.Queue(["Typeset", MathJax.Hub]);
else
{
MathJax.Hub.Startup.onload();
mathjax_loaded = true;
}
}
There's a lot here. First of all, we keep track of whether this callback has been called once before. If not, we tell MathJax to parse the page as if it were invoked from the window.onload event. If this has already happened (and we're on a new page) then we simply need to have MathJax run through the new page.
I'm probably missing something and there may be a better way of doing this. But I haven't found any other way that works.
Not sure if this is easier/better way to add a script but here is what I found:
http://api.jquery.com/jQuery.getScript/
Can't append <script> element
(Untested) Maybe (using your post: Combining jQuery Mobile and MathJax on a mobile site?)
$('#page_id').live('pageshow', function(event, ui) {
$.getScript('http://path_to_mathjax/MathJax.js', function() {
callback();
});
});
var mathjax_loaded = false;
function callback()
{
if(mathjax_loaded)
MathJax.Hub.Queue(["Typeset", MathJax.Hub]);
else
{
MathJax.Hub.Startup.onload();
mathjax_loaded = true;
}
}

Resources