Firefox Bootstrapped Add-On Injecting before load - firefox

Is it possible to add event listeners for a document before a page has been navigated to using a Bootstrapped add-on? I would like to see what page the user wants to navigate to as well as later after the page loads to inspect the DOM. I need to run code in the HTML content context.
In the past I used a toolbar XUL and included javascript within it and it would load before the HTML page loaded.

i looked into doing stuff before DOMContentLoaded sometime ago and found out there is a document inserted observer.
order of events after running research code at bottom
readystate changes to interactive (i think multiple times, not sure)
readystate changes to complete
DOMContentLoaded event fires
load event fires (Sometimes load doesnt fire, if you might have to change addEventListener with capture arugment (3rd argument) as false or true)
apparently there should be readystate loading before all of this but i can never catch it i dont know why.
after running the code in scratchpad, browser environemnt of course, then load a new page and watch the error console it will throw these reports in this order:
ready state changed! ("interactive") Scratchpad/4:18
02:28:07.873 ready state changed! ("complete") Scratchpad/4:18
02:28:07.874 DOMContentLoaded event fired! Scratchpad/4:53
02:28:07.938 Load event fired! Scratchpad/4:45
here is the research code. it adds a the listeners and observer to see whats firing.
var {classes: Cc, interfaces: Ci, utils: Cu} = Components;
var os = Cc['#mozilla.org/observer-service;1'].getService(Ci.nsIObserverService);
var LMObserver;
function myObserver() {
this.register();
}
myObserver.prototype = {
observe: function (subject, topic, data) {
//Cu.reportError(subject);
//Cu.reportError(data);
//i think subject is window element
subject.onreadystatechange = function () {
//loading
//interactive
//complete
Cu.reportError('ready state changed! ("' + subject.readyState + '")');
//var body = subject.documentElement.querySelector('body')
//you want to change title so you would do that here do something like: if (subject.readystate == 'complete') { subject.title = 'blah blah' }
//Cu.reportError('has body element: ' + body)
}
},
register: function () {
os.addObserver(this, 'document-element-inserted', false);
},
unregister: function () {
os.removeObserver(this, 'document-element-inserted', false);
}
};
//below this is the DOMContentLoaded thing i put this here so we can see what fires in what order
var pageLoad = function(event) {
var win = event.originalTarget.defaultView;
if (win && win.frameElement) {
return;
}
Cu.reportError('Load event fired!');
}
var pageDOMContentLoaded = function(event) {
var win = event.originalTarget.defaultView;
if (win && win.frameElement) {
return;
}
Cu.reportError('DOMContentLoaded event fired!');
}
LMObserver = new myObserver;
gBrowser.addEventListener("load", pageLoad, true);
gBrowser.addEventListener("DOMContentLoaded", pageDOMContentLoaded, true);
//gBrowser.removeEventListener("load", pageLoad, true);
//gBrowser.removeEventListener("DOMContentLoaded", pageDOMContentLoaded, true);
//LMObserver.unregister();
Here's some more indepth research on load events added with true or false as capture argument: https://github.com/Noitidart/event-listener-experiment-DOMC-and-load/blob/master/bootstrap.js

Related

Firefox Compile Simple Load Script - browser.xul

I'm trying to add a script tag to every dom page through privileged chrome, so far i'm able to get the first pageload of a tab, but after that, the script does nothing, I'm using Firefox Nightly 44.0. What am i doing wrong???
Documents I'm following:
https://developer.mozilla.org/en-US/Add-ons/Code_snippets/On_page_load
https://developer.mozilla.org/en-US/Add-ons/Overlay_Extensions/XUL_School/Intercepting_Page_Loads
mozilla-central/browser/base/content/browser.xul (line: 74)
<script type="application/x-javascript" src="chrome://browser/content/yyy/x.js" />
chrome://browser/content/yyy/x.js
var myExtension = {
init: function() {
// The event can be DOMContentLoaded, pageshow, pagehide, load or unload.
if(gBrowser) gBrowser.addEventListener("DOMContentLoaded", this.onPageLoad, false);
},
onPageLoad: function(aEvent) {
var doc = aEvent.originalTarget; // doc is document that triggered the event
var win = doc.defaultView; // win is the window for the doc
// test desired conditions and do something
// if (doc.nodeName != "#document") return; // only documents
// if (win != win.top) return; //only top window.
// if (win.frameElement) return; // skip iframes/frames
alert("page is loaded \n" +doc.location.href);
}
}
window.addEventListener("load", function load(event){
window.removeEventListener("load", load, false); //remove listener, no longer needed
myExtension.init();
},false);
mozilla-central/browser/base/jar.mn
content/browser/yyy/x.js (content/yyy/x.js)
You'll want to use loadFrameScript with argument of true to listen to future pages. Here are examples: https://github.com/mdn/e10s-example-addons/tree/master/run-script-in-all-pages
globalMM.loadFrameScript("chrome://modify-all-pages/content/frame-script.js", true);
This is documented here: https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface/nsIFrameScriptLoader#loadFrameScript%28%29
To stop it from loading in new tabs, then you have to use removeDelayedFrameScript
That github link also shows an example of how to do it with addon-sdk content-scripts.

Firefox extension development: load event only once

I'm developing a kind of kiosk system for firefox. Therefore I need to listen to the load event, everytime a link is clicked and a new page / document is loaded. I used this in the js file to accomplish that:
window.addEventListener('load', function () {
gBrowser.addEventListener('DOMContentLoaded', function () {
alert("load");
}, false);
}, false);
But the event is only fired if i open the new browser window but not on reload or loading another content.
What could I do?
You should probably use nsIWindowWatcher service to do this:
let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
function windowObserver(aSubject, aTopic, aData) {
if (aTopic == "domwindowopened") {
let win = aSubject.QueryInterface(Ci.nsIDOMWindow);
// Do stuff here
}
}
// To start watching windows do this
Services.ww.registerNotification(windowObserver);
// To stop watching windows do this
Services.ww.unregisterNotification(windowObserver);

Prototype.js event observe click intercept and stop propagation

I have a page that is built around a wrapper with some very defined logic. There is a Save button on the bottom of the wrapped form that looks like this:
<form>
... my page goes here...
<input id="submitBtnSaveId" type="button" onclick="submitPage('save', 'auto', event)" value="Save">
</form>
This cannot change...
Now, I'm writing some javascript into the page that gets loaded in "...my page goes here...". The code loads great and runs as expected. It does some work around the form elements and I've even injected some on-page validation. This is where I'm stuck. I'm trying to "intercept" the onclick and stop the page from calling "submitPage()" if the validation fails. I'm using prototype.js, so I've tried all variations and combinations like this:
document.observe("dom:loaded", function() {
Element.observe('submitBtnSaveId', 'click', function (e) {
console.log('Noticed a submit taking place... please make it stop!');
//validateForm(e);
Event.stop(e);
e.stopPropagation();
e.cancelBubble = true;
console.log(e);
alert('Stop the default submit!');
return false;
}, false);
});
Nothing stops the "submitPage()" from being called! The observe actually works and triggers the console message and shows the alert for a second. Then the "submitPage()" kicks in and everything goes bye-bye. I've removed the onclick attached to the button in Firebug, and my validation and alert all work as intended, so it leads me to think that the propagation isn't really being stopped for the onclick?
What am I missing?
So based on the fact that you can't change the HTML - here's an idea.
leave your current javascript as is to catch the click event - but add this to the dom:loaded event
$('submitBtnSaveId').writeAttribute('onclick',null);
this will remove the onclick attribute so hopefully the event wont be called
so your javascript will look like this
document.observe("dom:loaded", function() {
$('submitBtnSaveId').writeAttribute('onclick',null);
Element.observe('submitBtnSaveId', 'click', function (e) {
console.log('Noticed a submit taking place... please make it stop!');
//validateForm(e);
Event.stop(e);
e.stopPropagation();
e.cancelBubble = true;
console.log(e);
alert('Stop the default submit!');
return false;
submitPage('save', 'auto', e);
//run submitPage() if all is good
}, false);
});
I took the idea presented by Geek Num 88 and extended it to fully meet my need. I didn't know about the ability to overwrite the attribute, which was great! The problem continued to be that I needed to run submitPage() if all is good, and that method's parameters and call could be different per page. That ended up being trickier than just a simple call on success. Here's my final code:
document.observe("dom:loaded", function() {
var allButtons = $$('input[type=button]');
allButtons.each(function (oneButton) {
if (oneButton.value === 'Save') {
var originalSubmit = oneButton.readAttribute('onclick');
var originalMethod = getMethodName(originalSubmit);
var originalParameters = getMethodParameters(originalSubmit);
oneButton.writeAttribute('onclick', null);
Element.observe(oneButton, 'click', function (e) {
if (validateForm(e)) {
return window[originalMethod].apply(this, originalParameters || []);
}
}, false);
}
});
});
function getMethodName(theMethod) {
return theMethod.substring(0, theMethod.indexOf('('))
}
function getMethodParameters(theMethod) {
var parameterCommaDelimited = theMethod.substring(theMethod.indexOf('(') + 1, theMethod.indexOf(')'));
var parameterArray = parameterCommaDelimited.split(",");
var finalParamArray = [];
parameterArray.forEach(function(oneParam) {
finalParamArray.push(oneParam.trim().replace("'","", 'g'));
});
return finalParamArray;
}

requirejs on a windows phone 7

So I asked a question earlier about windows phone 7 with backbone and jquery and require.
I carried on investigating this and stripped it down to the bare minimum
and index page that just has
<script data-main="js/main" src="js/vendor/require/requireNew.js"></script>
and then a main.js that just has one path to jQuery
require.config({
//path mappings for module names not found directly under baseUrl
paths: {
jquery: 'vendor/jqm/jquery_1.7_min'
}
});
alert('why');
$(document).ready(function() {
alert('DOM IS READY ');
});
in windows 7 it will show the alert why - but not DOM is here...
it will do this on every other browser including ie7!!
Can anyone help?
Not sure if you are using Phonegap or not, if not you should be (or an equivalent framework).
If you follow the instructions here enter link description here
You will be able to build a default phonegap WP7 application when you have that take a look at the generated index.js
var app = {
// Application Constructor
initialize: function() {
this.bindEvents();
},
// Bind Event Listeners
//
// Bind any events that are required on startup. Common events are:
// `load`, `deviceready`, `offline`, and `online`.
bindEvents: function() {
document.addEventListener('deviceready', this.onDeviceReady, false);
},
// deviceready Event Handler
//
// The scope of `this` is the event. In order to call the `receivedEvent`
// function, we must explicity call `app.receivedEvent(...);`
onDeviceReady: function() {
app.receivedEvent('deviceready');
},
// Update DOM on a Received Event
receivedEvent: function(id) {
var parentElement = document.getElementById(id);
var listeningElement = parentElement.querySelector('.listening');
var receivedElement = parentElement.querySelector('.received');
listeningElement.setAttribute('style', 'display:none;');
receivedElement.setAttribute('style', 'display:block;');
console.log('Received Event: ' + id);
}
};
It's a bit more complicated on mobile devices as you first must wait for the "device ready" event before you can get a "dom ready" event

Firefox extension:adding a new tab,but addEventListener not working

There is a dialog, and I define a function OnAccept() and call it like this: ondialogaccept:ondialogaccept="OnAccept()".
OnAccept():
function OnAccept() {
var windowManager = Components.classes["#mozilla.org/appshell/window-mediator;1"].getService();
var windowManagerInterface = windowManager.QueryInterface( Components.interfaces.nsIWindowMediator );
var topWindow = windowManagerInterface.getMostRecentWindow( "navigator:browser" );
if(topWindow)
{
var web = topWindow.document.getElementById("content");
web.selectedTab = web.addTab("http://www.google.com");
var newBrowserHandle = web.getBrowserForTab(web.selectedTab);
newBrowserHandle.addEventListener("load", function() { alert("111"); }, true);
}
}
But the addEventListener doesn't work. I don't know why.
There are some issues in your code that are probably just bad copy&paste: ondialogaccept:ondialogaccept="OnAccept()" should be ondialogaccept="OnAccept()" and OnAccept(): should be OnAccept: (without parentheses).
The main issue: the load event listener doesn't get propagated from content to chrome, you would need progress listeners to get that event. You can listen to the DOMContentLoaded event however, that one can be caught on the browser element. This event will fire when only the document content is loaded, not images and such - but maybe that's ok for you.

Resources