mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 05:41:12 +00:00
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 --HG-- extra : transplant_source : 0%B6%F4DE%80%B6%CA%9B%09%81%1C%16%96%F6%C0%1FC%B0%F9
This commit is contained in:
parent
d7b2387a81
commit
94d2a46537
@ -18,6 +18,60 @@ var {
|
||||
runSafe,
|
||||
} = ExtensionUtils;
|
||||
|
||||
const defaultTransitionTypes = {
|
||||
topFrame: "link",
|
||||
subFrame: "auto_subframe",
|
||||
};
|
||||
|
||||
const frameTransitions = {
|
||||
anyFrame: {
|
||||
qualifiers: ["server_redirect", "client_redirect", "forward_back"],
|
||||
},
|
||||
topFrame: {
|
||||
types: ["reload", "form_submit"],
|
||||
},
|
||||
};
|
||||
|
||||
function isTopLevelFrame({frameId, parentFrameId}) {
|
||||
return frameId == 0 && parentFrameId == -1;
|
||||
}
|
||||
|
||||
function fillTransitionProperties(eventName, src, dst) {
|
||||
if (eventName == "onCommitted" || eventName == "onHistoryStateUpdated") {
|
||||
let frameTransitionData = src.frameTransitionData || {};
|
||||
|
||||
let transitionType, transitionQualifiers = [];
|
||||
|
||||
// Fill transition properties for any frame.
|
||||
for (let qualifier of frameTransitions.anyFrame.qualifiers) {
|
||||
if (frameTransitionData[qualifier]) {
|
||||
transitionQualifiers.push(qualifier);
|
||||
}
|
||||
}
|
||||
|
||||
if (isTopLevelFrame(dst)) {
|
||||
for (let type of frameTransitions.topFrame.types) {
|
||||
if (frameTransitionData[type]) {
|
||||
transitionType = type;
|
||||
}
|
||||
}
|
||||
|
||||
// If transitionType is not defined, defaults it to "link".
|
||||
if (!transitionType) {
|
||||
transitionType = defaultTransitionTypes.topFrame;
|
||||
}
|
||||
} else {
|
||||
// If it is sub-frame, transitionType defaults it to "auto_subframe",
|
||||
// "manual_subframe" is set only in case of a recent user interaction.
|
||||
transitionType = defaultTransitionTypes.subFrame;
|
||||
}
|
||||
|
||||
// Fill the transition properties in the webNavigation event object.
|
||||
dst.transitionType = transitionType;
|
||||
dst.transitionQualifiers = transitionQualifiers;
|
||||
}
|
||||
}
|
||||
|
||||
// Similar to WebRequestEventManager but for WebNavigation.
|
||||
function WebNavigationEventManager(context, eventName) {
|
||||
let name = `webNavigation.${eventName}`;
|
||||
@ -46,6 +100,8 @@ function WebNavigationEventManager(context, eventName) {
|
||||
return;
|
||||
}
|
||||
|
||||
fillTransitionProperties(eventName, data, data2);
|
||||
|
||||
runSafe(context, callback, data2);
|
||||
};
|
||||
|
||||
|
@ -70,6 +70,8 @@ const URL = BASE + "/file_WebNavigation_page1.html";
|
||||
const FRAME = BASE + "/file_WebNavigation_page2.html";
|
||||
const FRAME2 = BASE + "/file_WebNavigation_page3.html";
|
||||
const FRAME_PUSHSTATE = BASE + "/file_WebNavigation_page3_pushState.html";
|
||||
const REDIRECT = BASE + "/redirection.sjs";
|
||||
const REDIRECTED = BASE + "/dummy_page.html";
|
||||
|
||||
const REQUIRED = [
|
||||
"onBeforeNavigate",
|
||||
@ -91,6 +93,120 @@ function loadAndWait(win, event, url, script) {
|
||||
return new Promise(resolve => { completedResolve = resolve; });
|
||||
}
|
||||
|
||||
add_task(function* webnav_transitions_props() {
|
||||
function backgroundScriptTransitions() {
|
||||
const EVENTS = [
|
||||
"onCommitted",
|
||||
"onCompleted",
|
||||
];
|
||||
|
||||
function gotEvent(event, details) {
|
||||
browser.test.log(`Got ${event} ${details.url} ${details.transitionType}`);
|
||||
|
||||
browser.test.sendMessage("received", {url: details.url, details, event});
|
||||
}
|
||||
|
||||
let listeners = {};
|
||||
for (let event of EVENTS) {
|
||||
listeners[event] = gotEvent.bind(null, event);
|
||||
browser.webNavigation[event].addListener(listeners[event]);
|
||||
}
|
||||
|
||||
browser.test.sendMessage("ready");
|
||||
}
|
||||
|
||||
let extensionData = {
|
||||
manifest: {
|
||||
permissions: [
|
||||
"webNavigation",
|
||||
],
|
||||
},
|
||||
background: `(${backgroundScriptTransitions})()`,
|
||||
};
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
|
||||
extension.onMessage("received", ({url, event, details}) => {
|
||||
received.push({url, event, details});
|
||||
|
||||
if (event == waitingEvent && url == waitingURL) {
|
||||
completedResolve();
|
||||
}
|
||||
});
|
||||
|
||||
yield Promise.all([extension.startup(), extension.awaitMessage("ready")]);
|
||||
info("webnavigation extension loaded");
|
||||
|
||||
let win = window.open();
|
||||
|
||||
yield loadAndWait(win, "onCompleted", URL, () => { win.location = URL; });
|
||||
|
||||
// transitionType: reload
|
||||
received = [];
|
||||
yield loadAndWait(win, "onCompleted", URL, () => { win.location.reload(); });
|
||||
|
||||
let found = received.find((data) => (data.event == "onCommitted" && data.url == URL));
|
||||
|
||||
ok(found, "Got the onCommitted event");
|
||||
|
||||
if (found) {
|
||||
is(found.details.transitionType, "reload",
|
||||
"Got the expected 'reload' transitionType in the OnCommitted event");
|
||||
ok(Array.isArray(found.details.transitionQualifiers),
|
||||
"transitionQualifiers found in the OnCommitted events");
|
||||
}
|
||||
|
||||
// transitionType: auto_subframe
|
||||
found = received.find((data) => (data.event == "onCommitted" && data.url == FRAME));
|
||||
|
||||
ok(found, "Got the sub-frame onCommitted event");
|
||||
|
||||
if (found) {
|
||||
is(found.details.transitionType, "auto_subframe",
|
||||
"Got the expected 'auto_subframe' transitionType in the OnCommitted event");
|
||||
ok(Array.isArray(found.details.transitionQualifiers),
|
||||
"transitionQualifiers found in the OnCommitted events");
|
||||
}
|
||||
|
||||
// transitionQualifier: server_redirect
|
||||
received = [];
|
||||
yield loadAndWait(win, "onCompleted", REDIRECTED, () => { win.location = REDIRECT; });
|
||||
|
||||
found = received.find((data) => (data.event == "onCommitted" && data.url == REDIRECTED));
|
||||
|
||||
ok(found, "Got the onCommitted event");
|
||||
|
||||
if (found) {
|
||||
is(found.details.transitionType, "link",
|
||||
"Got the expected 'link' transitionType in the OnCommitted event");
|
||||
ok(Array.isArray(found.details.transitionQualifiers) &&
|
||||
found.details.transitionQualifiers.find((q) => q == "server_redirect"),
|
||||
"Got the expected 'server_redirect' transitionQualifiers in the OnCommitted events");
|
||||
}
|
||||
|
||||
// transitionQualifier: forward_back
|
||||
received = [];
|
||||
yield loadAndWait(win, "onCompleted", URL, () => { win.history.back(); });
|
||||
|
||||
found = received.find((data) => (data.event == "onCommitted" && data.url == URL));
|
||||
|
||||
ok(found, "Got the onCommitted event");
|
||||
|
||||
if (found) {
|
||||
is(found.details.transitionType, "link",
|
||||
"Got the expected 'link' transitionType in the OnCommitted event");
|
||||
ok(Array.isArray(found.details.transitionQualifiers) &&
|
||||
found.details.transitionQualifiers.find((q) => q == "forward_back"),
|
||||
"Got the expected 'forward_back' transitionQualifiers in the OnCommitted events");
|
||||
}
|
||||
|
||||
// cleanup phase
|
||||
win.close();
|
||||
|
||||
yield extension.unload();
|
||||
info("webnavigation extension unloaded");
|
||||
});
|
||||
|
||||
add_task(function* webnav_ordering() {
|
||||
let extensionData = {
|
||||
manifest: {
|
||||
|
@ -14,10 +14,7 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
// TODO:
|
||||
// Transition types and qualifiers
|
||||
// onReferenceFragmentUpdated also triggers for pushState
|
||||
// getFrames, getAllFrames
|
||||
// onCreatedNavigationTarget, onHistoryStateUpdated
|
||||
// onCreatedNavigationTarget
|
||||
|
||||
var Manager = {
|
||||
listeners: new Map(),
|
||||
@ -104,18 +101,26 @@ var Manager = {
|
||||
},
|
||||
|
||||
onDocumentChange(browser, data) {
|
||||
let url = data.location;
|
||||
let extra = {
|
||||
url: data.location,
|
||||
// Transition data which is coming from the content process.
|
||||
frameTransitionData: data.frameTransitionData,
|
||||
};
|
||||
|
||||
this.fire("onCommitted", browser, data, {url});
|
||||
this.fire("onCommitted", browser, data, extra);
|
||||
},
|
||||
|
||||
onHistoryChange(browser, data) {
|
||||
let url = data.location;
|
||||
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, {url});
|
||||
this.fire("onReferenceFragmentUpdated", browser, data, extra);
|
||||
} else if (data.isHistoryStateUpdated) {
|
||||
this.fire("onHistoryStateUpdated", browser, data, {url});
|
||||
this.fire("onHistoryStateUpdated", browser, data, extra);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -81,7 +81,7 @@ var WebProgressListener = {
|
||||
// (see Bug 1264936 and Bug 125662 for rationale)
|
||||
if ((webProgress.DOMWindow.top != webProgress.DOMWindow) &&
|
||||
(stateFlags & Ci.nsIWebProgressListener.STATE_IS_DOCUMENT)) {
|
||||
this.sendDocumentChange({webProgress, locationURI});
|
||||
this.sendDocumentChange({webProgress, locationURI, request});
|
||||
}
|
||||
},
|
||||
|
||||
@ -103,7 +103,7 @@ var WebProgressListener = {
|
||||
// an "Extension:HistoryChange" to the main process, where it will be turned
|
||||
// into a webNavigation.onHistoryStateUpdated/onReferenceFragmentUpdated event.
|
||||
if (isSameDocument) {
|
||||
this.sendHistoryChange({webProgress, previousURI, locationURI});
|
||||
this.sendHistoryChange({webProgress, previousURI, locationURI, request});
|
||||
} else if (webProgress.DOMWindow.top == webProgress.DOMWindow) {
|
||||
// We have to catch the document changes from top level frames here,
|
||||
// where we can detect the "server redirect" transition.
|
||||
@ -124,8 +124,12 @@ var WebProgressListener = {
|
||||
sendAsyncMessage("Extension:StateChange", data);
|
||||
},
|
||||
|
||||
sendDocumentChange({webProgress, locationURI}) {
|
||||
sendDocumentChange({webProgress, locationURI, request}) {
|
||||
let {loadType} = webProgress;
|
||||
let frameTransitionData = this.getFrameTransitionData({loadType, request});
|
||||
|
||||
let data = {
|
||||
frameTransitionData,
|
||||
location: locationURI ? locationURI.spec : "",
|
||||
windowId: webProgress.DOMWindowID,
|
||||
parentWindowId: WebNavigationFrames.getParentWindowId(webProgress.DOMWindow),
|
||||
@ -134,7 +138,7 @@ var WebProgressListener = {
|
||||
sendAsyncMessage("Extension:DocumentChange", data);
|
||||
},
|
||||
|
||||
sendHistoryChange({webProgress, previousURI, locationURI}) {
|
||||
sendHistoryChange({webProgress, previousURI, locationURI, request}) {
|
||||
let {loadType} = webProgress;
|
||||
|
||||
let isHistoryStateUpdated = false;
|
||||
@ -159,7 +163,10 @@ var WebProgressListener = {
|
||||
}
|
||||
|
||||
if (isHistoryStateUpdated || isReferenceFragmentUpdated) {
|
||||
let frameTransitionData = this.getFrameTransitionData({loadType, request});
|
||||
|
||||
let data = {
|
||||
frameTransitionData,
|
||||
isHistoryStateUpdated, isReferenceFragmentUpdated,
|
||||
location: locationURI ? locationURI.spec : "",
|
||||
windowId: webProgress.DOMWindowID,
|
||||
@ -170,6 +177,27 @@ var WebProgressListener = {
|
||||
}
|
||||
},
|
||||
|
||||
getFrameTransitionData({loadType, request}) {
|
||||
let frameTransitionData = {};
|
||||
|
||||
if (loadType & Ci.nsIDocShell.LOAD_CMD_HISTORY) {
|
||||
frameTransitionData.forward_back = true;
|
||||
}
|
||||
|
||||
if (loadType & Ci.nsIDocShell.LOAD_CMD_RELOAD) {
|
||||
frameTransitionData.reload = true;
|
||||
}
|
||||
|
||||
if (request instanceof Ci.nsIChannel) {
|
||||
if (request.loadInfo.redirectChain.length) {
|
||||
frameTransitionData.server_redirect = true;
|
||||
}
|
||||
}
|
||||
|
||||
return frameTransitionData;
|
||||
},
|
||||
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener, Ci.nsISupportsWeakReference]),
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user