Files
tubestation/toolkit/modules/addons/WebNavigation.jsm
Luca Greco 9f864a0e47 Bug 1256652 - [webext] Initial support of webNavigation transition types and qualifiers. r=krizsa
- transition types: reload, link, auto_subframe
- transition qualifiers: forward_back, server_redirect

MozReview-Commit-ID: Bx3oG2fuWuv
2016-04-15 14:49:13 +02:00

175 lines
4.6 KiB
JavaScript

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const EXPORTED_SYMBOLS = ["WebNavigation"];
const Ci = Components.interfaces;
const Cc = Components.classes;
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
// TODO:
// onCreatedNavigationTarget
var Manager = {
listeners: new Map(),
init() {
Services.mm.addMessageListener("Extension:DOMContentLoaded", this);
Services.mm.addMessageListener("Extension:StateChange", this);
Services.mm.addMessageListener("Extension:DocumentChange", this);
Services.mm.addMessageListener("Extension:HistoryChange", this);
Services.mm.loadFrameScript("resource://gre/modules/WebNavigationContent.js", true);
},
uninit() {
Services.mm.removeMessageListener("Extension:StateChange", this);
Services.mm.removeMessageListener("Extension:DocumentChange", this);
Services.mm.removeMessageListener("Extension:HistoryChange", this);
Services.mm.removeMessageListener("Extension:DOMContentLoaded", this);
Services.mm.removeDelayedFrameScript("resource://gre/modules/WebNavigationContent.js");
Services.mm.broadcastAsyncMessage("Extension:DisableWebNavigation");
},
addListener(type, listener) {
if (this.listeners.size == 0) {
this.init();
}
if (!this.listeners.has(type)) {
this.listeners.set(type, new Set());
}
let listeners = this.listeners.get(type);
listeners.add(listener);
},
removeListener(type, listener) {
let listeners = this.listeners.get(type);
if (!listeners) {
return;
}
listeners.delete(listener);
if (listeners.size == 0) {
this.listeners.delete(type);
}
if (this.listeners.size == 0) {
this.uninit();
}
},
receiveMessage({name, data, target}) {
switch (name) {
case "Extension:StateChange":
this.onStateChange(target, data);
break;
case "Extension:DocumentChange":
this.onDocumentChange(target, data);
break;
case "Extension:HistoryChange":
this.onHistoryChange(target, data);
break;
case "Extension:DOMContentLoaded":
this.onLoad(target, data);
break;
}
},
onStateChange(browser, data) {
let stateFlags = data.stateFlags;
if (stateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW) {
let url = data.requestURL;
if (stateFlags & Ci.nsIWebProgressListener.STATE_START) {
this.fire("onBeforeNavigate", browser, data, {url});
} else if (stateFlags & Ci.nsIWebProgressListener.STATE_STOP) {
if (Components.isSuccessCode(data.status)) {
this.fire("onCompleted", browser, data, {url});
} else {
let error = `Error code ${data.status}`;
this.fire("onErrorOccurred", browser, data, {error, url});
}
}
}
},
onDocumentChange(browser, data) {
let extra = {
url: data.location,
// Transition data which is coming from the content process.
frameTransitionData: data.frameTransitionData,
};
this.fire("onCommitted", browser, data, extra);
},
onHistoryChange(browser, data) {
let extra = {
url: data.location,
// Transition data which is coming from the content process.
frameTransitionData: data.frameTransitionData,
};
if (data.isReferenceFragmentUpdated) {
this.fire("onReferenceFragmentUpdated", browser, data, extra);
} else if (data.isHistoryStateUpdated) {
this.fire("onHistoryStateUpdated", browser, data, extra);
}
},
onLoad(browser, data) {
this.fire("onDOMContentLoaded", browser, data, {url: data.url});
},
fire(type, browser, data, extra) {
let listeners = this.listeners.get(type);
if (!listeners) {
return;
}
let details = {
browser,
windowId: data.windowId,
};
if (data.parentWindowId) {
details.parentWindowId = data.parentWindowId;
}
for (let prop in extra) {
details[prop] = extra[prop];
}
for (let listener of listeners) {
listener(details);
}
},
};
const EVENTS = [
"onBeforeNavigate",
"onCommitted",
"onDOMContentLoaded",
"onCompleted",
"onErrorOccurred",
"onReferenceFragmentUpdated",
"onHistoryStateUpdated",
// "onCreatedNavigationTarget",
];
var WebNavigation = {};
for (let event of EVENTS) {
WebNavigation[event] = {
addListener: Manager.addListener.bind(Manager, event),
removeListener: Manager.removeListener.bind(Manager, event),
};
}