I'm developing a Firefox extension and need to do the following:
load a page
get an element from this page
modify the attributes from this element
The code I would like to work looks like this:
gBrowser.loadURI("chrome://myExtension/content/myPage.xul");
let button = content.document.getElementById("myExtension-theButton");
button.setAttribute("oncommand", "myFunction(withParams)");
But when I run this, button is null. (Maybe loadURI returns too early and the document isn't fully loaded, yet.)
add to that gBrowser:
gBrowser.addEventListener('DOMContentLoaded', dofunc, false);
function dofunc(e) {
var win = event.originalTarget.defaultView;
var doc = win.document;
if (doc.location == 'chrome://myExtension/content/myPage.xul') {
let button = content.document.getElementById("myExtension-theButton");
button.setAttribute("oncommand", "myFunction(withParams)");
gBrowser.removeEventListener('DOMCOntentLoaded', dofunc, false);
}
}
Related
I'm trying to dynamically preload list of files which may be anything between images and JavaScript files. Everything is going supersmooth with Chrome and Firefox, but failing when I'm trying to preload JavaScript files with Edge. Edge still can handle images for example but no js files. And yes I've tried with addEventListener, it's not working either.
Edge doesn't give me any errors.
var object = {};
object = document.createElement('object');
object.width = object.height = 0;
object.data = path/to/javascriptfile.js
body.appendChild(object);
object.onload = function(){
console.log('hello world')
//not firing with edge
}
Anything relevant I'm missing?
UPDATE: Didn't get any success after the day. Will probably leave it for now and just skip preloading script files with edge until i find a solution.
Perhaps worth a check - from msdn:
The client loads applications, embedded objects, and images as soon as
it encounters the applet, embed, and img objects during parsing.
Consequently, the onload event for these objects occurs before the
client parses any subsequent objects. To ensure that an event handler
receives the onload event for these objects, place the script object
that defines the event handler before the object and use the onload
attribute in the object to set the handler.
https://msdn.microsoft.com/en-us/library/windows/apps/hh465984.aspx
Edit, a clarification:
You should attach the event listener before the element is added to the page.
Even doing that I'm not sure if it'll work or not though. But to make sure you've exhausted all options try the example below:
function doLoad() {
console.log('The load event is executing');
}
var object = {};
object = document.createElement('object');
object.width = object.height = 0;
object.data = 'path/to/javascriptfile.js';
object.onreadystatechange = function () {
if (object.readyState === 'loaded' || object.readyState === 'complete') doLoad();
console.log('onreadystatechange');
}
if (object.addEventListener) {
object.addEventListener( "load", doLoad, false );
console.log('addEventListener');
}
else
{
if (object.attachEvent) {
object.attachEvent( "onload", doLoad );
console.log('attachEvent');
} else if (object.onLoad) {
object.onload = doLoad;
console.log('onload');
}
}
var body = document.getElementsByTagName("body")[0];
body.appendChild(object);
If this doesn't work, you could perhaps preload using "image" instead of "object" in IE: https://stackoverflow.com/a/11103087/1996783
Working temporary solution is to put onload event directly to script element instead of object. It's sad since it works like a charm in Chrome & FF.
It turns out, object.data with css source did not load either. I don't know if it's a bug since it still can load image from to object.data.
But show must go on.
Cheers, eljuko
I have an iframe that's supposed to load different modules of a web application.
When the user clicks a navigation menu in the top window, it's passes a new url to the iframe. The trouble is, the new url doesn't actually point to a new page, it only uses a changed hash.
i.e.:
User clicks "dashboard", iframe src set to application.html#/dashboard
User clicks "history", iframe src set to application.html#/history
This means that the iframe does not actually load the src url again because hash changes don't require it to. The application inside the iframe is an angular app which loads the required modules dynamically using requireJS. We need this functionality to remain.
I need to force the frame source to load again even though only the hash changed. It's possible that I instead find a way to rewrite our angular app to dynamically unload/load the modules on push state events but that introduces several layers of issues for the app, plus some IE trouble.
I've tried:
Setting iframe src and calling it's location.reload, but that reloads the originally loaded url
Setting the iframe location.href/hash and calling reload, same issue
Blanking the src attribute and then setting the new url - no effect
The only solution I can find is to set the src to a blank screen, then onload set it to the new url:
var appIFrame = document.getElementById('appIFrame');
appIFrame.src = 'about:blank';
appIFrame.onload = function(){
appIFrame.src = '// set the real source here';
appIFrame.onload = false;
}
This works, yet it seems inefficient because there's an extra step.
Maybe add a dynamic GET parameter – f.e. the current timestamp, which you can get from the JavaScript Date object – to the iframe URL.
Instead of assigning application.html#/dashboard as src value, assign application.html?1234567890#/dashboard from your outside page (with 1234567890 replaced by the current timestamp, obviously).
I don't have a specific answer for you. However, the following script may proved useful (I wrote this about a year or so ago). The following script deals with re-adjusting iframe height when the document changes. This script was tested cross-browser. It does deal with the issues you're experience but indirectly. There is a lot of commenting with the Gist:
https://gist.github.com/say2joe/4694780
Here my solution (based on this stackoverflow answer):
var $ = function(id) { return document.getElementById(id); };
var hashChangeDetector = function(frame, callback) {
var frameWindow = frame.contentWindow || frame.contentDocument;
// 'old' browser
if (! "onhashchange" in window) {
var detecter = function(callback) {
var previousHash = frameWindow.location.hash;
window.setTimeout(function() {
if (frameWindow.location.hash != previousHash) {
previousHash = frameWindow.location.hash;
callback(previousHash);
}
}, 100);
};
}
else // modern browser ?
{
var detecter = function(callback) {
frameWindow.onhashchange = function () {
callback(frameWindow.location.hash);
}
};
}
detecter(callback);
};
hashChangeDetector($('myframe'), function(hash) {
alert ('detecting hash change: ' + hash);
});
You can test this here: http://paulrad.com/stackoverflow/iframe-hash-detection.html
I am not an expert JavaScript user and I am having difficulty with addEventListener.
var appcontent = document.getElementById("appcontent");
appcontent.addEventListener("DOMContentLoaded", load, true);
function load(aEvent) {
var doc = aEvent.originalTarget;
alert(doc.location.host);
}
In an add-on this code will alert the location.host of the appcontent. My problem is that I don't need an event listener and want to call load like a normal function:
var appcontent = document.getElementById("appcontent");
load(appcontent);
function load(aEvent) {
var doc = aEvent.originalTarget;
alert(doc.location.host);
}
This is what I was trying to do but it doesn't work.
Your load() function still expects an event but you are now passing the actual element to it. Also, which location do you want to know, that of the currently selected tab? Then you can use the global content variable, it is pointing to the window object of the current tab. So changing the load() function into something like this should work:
function load() {
alert(content.location.host);
}
Use Ctrl+Shift+J to open JavaScript Console and to check the errors for your extension - it should help you find our what the issue is.
I have a page that loads another window on button click. The loaded page has silverlight control on it, so it takes some time to load and get prepared before it can receive javascript calls.
What I need to do is to call a particular method of silverlight object right after the silverlight plugin gets loaded and is ready to interact with me.
Now, if the pop-up page was already opened then the code would be like that:
var slWin = window.open('PopupPage.html', 'WindowName');
var elem = slWin.document.getElementById('slControl');
elem.Content.SlObject.MethodA();
This works when the window is already opened because the control is already loaded and ready. I need to modify this code to handle the situation when the elem need some time to be prepared.
I tried to use jQuery's ready and load methods to add handlers to corresponding events, but with no particular lack. Here's the full snippet:
var slWin = window.open('', 'WindowName');
var elem = slWin.document.getElementById('slControl');
if (elem == null) {
slWin.location.href = 'PopupPage.aspx';
// this branch doesn't work
$(slWin).load(function () {
elem = slWin.document.getElementById('slControl');
elem.Content.SlObject.MethodA();
});
}
else {
// this branch works fine
elem.Content.SlObject.MethodA();
}
How do I solve this issue? I don't mind jQuery solutions.
This error is happening because the Silverlight object is not fully loaded when you are trying to access it.
Try to use the "onload" event of the silverlight object to dectect when it's ready to use. Here you have a link to the MSDN documentation:
http://msdn.microsoft.com/en-us/library/cc838107(v=vs.95).aspx
Hope it helps. :)
I have several iframes on a page that display ads unicorns/bacon to users. Because its not possible to detect an iframe's domready event via the parent (please let me know if this isn't true) I have some initialization-code in each iframe like this:
<body data-controller="unicorn">
<!-- content -->
<script>
var $ = parent.jQuery;
if($ && $.frameReady){
$(document).ready(function(){
$.frameReady(document);
});
}
</script>
</body>
The parent document has code very similar to the following (about this technique via #Paul Irish):
var frames = {
// the following is irrelevant to my question but awesome.
"unicorn": function (document) {
var script = document.createElement("script"),
element = document.getElementsByTagName("script")[0];
script.src = "http://www.cornify.com/js/cornify.js";
script.onload = function () {
// defaultView is the DOMWindow.
document.defaultView.cornify_add();
$(document).click(document.defaultView.cornify_add);
script.parentNode.removeChild(script);
};
element.parentNode.appendChild(script, element);
},
"bacon" : function(document) { /** mmm, bacon **/ }
};
// relevant but boring...
$.frameReady = function(document){
var controller = $(document.body).data("controller");
controller && frames[controller] && frames[controller](document);
};
Here is an example in jsfiddle (you can edit it here). It works great (at least it does in Chrome dev).
Now what I would LIKE to do is get rid of the data-controller bit in the iframe and instead use the id (or data-* or whatever) of the actual iframe element that is in the parent document to initialize the code.
If I could query the DOM via DOMWindow it would look like this:
$.frameReady = function(document){
var iframe = $("body").find(document.defaultView),
controller = iframe.data("controller");
controller && frames[controller] && frames[controller](document);
};
Luckily, I only need this to run on webkit based browsers, Adobe Air 2.5 actually (but I'm testing in Chrome ATM).
Because S.O. answerers like it when a Question has a question here it is:
Is there any (efficient) ways to query the DOM via document or window in webkit-based browsers - including Adobe Air 2.5?
I have now found that one iframe containing the unicorn for you
console.log(
$("iframe").contents().filter( function(){
return this == document
}).length
);