зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1239349 - Implement webNavigation.onHistoryStateUpdated. r=kmag
MozReview-Commit-ID: FvtkZpcJYCU --HG-- extra : transplant_source : %0B%CA%07NX7d%17W%D5%A0P%7D%0B%A8yG%E4l%CE
This commit is contained in:
Родитель
497853f641
Коммит
c56fcca8c3
|
@ -79,6 +79,7 @@ extensions.registerSchemaAPI("webNavigation", "webNavigation", (extension, conte
|
|||
onCompleted: new WebNavigationEventManager(context, "onCompleted").api(),
|
||||
onErrorOccurred: new WebNavigationEventManager(context, "onErrorOccurred").api(),
|
||||
onReferenceFragmentUpdated: new WebNavigationEventManager(context, "onReferenceFragmentUpdated").api(),
|
||||
onHistoryStateUpdated: new WebNavigationEventManager(context, "onHistoryStateUpdated").api(),
|
||||
onCreatedNavigationTarget: ignoreEvent(context, "webNavigation.onCreatedNavigationTarget"),
|
||||
getAllFrames(details) {
|
||||
let tab = TabManager.getTab(details.tabId);
|
||||
|
|
|
@ -345,7 +345,6 @@
|
|||
},
|
||||
{
|
||||
"name": "onHistoryStateUpdated",
|
||||
"unsupported": true,
|
||||
"type": "function",
|
||||
"description": "Fired when the frame's history was updated to a new URL. All future events for that frame will use the updated URL.",
|
||||
"filters": [
|
||||
|
|
|
@ -24,6 +24,7 @@ function backgroundScript() {
|
|||
"onCompleted",
|
||||
"onErrorOccurred",
|
||||
"onReferenceFragmentUpdated",
|
||||
"onHistoryStateUpdated",
|
||||
];
|
||||
|
||||
let expectedTabId = -1;
|
||||
|
@ -68,6 +69,7 @@ const BASE = "http://mochi.test:8888/tests/toolkit/components/extensions/test/mo
|
|||
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 REQUIRED = [
|
||||
"onBeforeNavigate",
|
||||
|
@ -155,10 +157,71 @@ add_task(function* webnav_ordering() {
|
|||
|
||||
checkRequired(FRAME2);
|
||||
|
||||
yield loadAndWait(win, "onReferenceFragmentUpdated", FRAME2 + "#ref",
|
||||
() => { win.frames[0].document.getElementById("elt").click(); });
|
||||
let navigationSequence = [
|
||||
{
|
||||
action: () => { win.frames[0].document.getElementById("elt").click(); },
|
||||
waitURL: `${FRAME2}#ref`,
|
||||
expectedEvent: "onReferenceFragmentUpdated",
|
||||
description: "clicked an anchor link",
|
||||
},
|
||||
{
|
||||
action: () => { win.frames[0].history.pushState({}, "History PushState", `${FRAME2}#ref2`); },
|
||||
waitURL: `${FRAME2}#ref2`,
|
||||
expectedEvent: "onReferenceFragmentUpdated",
|
||||
description: "history.pushState, same pathname, different hash",
|
||||
},
|
||||
{
|
||||
action: () => { win.frames[0].history.pushState({}, "History PushState", `${FRAME2}#ref2`); },
|
||||
waitURL: `${FRAME2}#ref2`,
|
||||
expectedEvent: "onHistoryStateUpdated",
|
||||
description: "history.pushState, same pathname, same hash",
|
||||
},
|
||||
{
|
||||
action: () => {
|
||||
win.frames[0].history.pushState({}, "History PushState", `${FRAME2}?query_param1=value#ref2`);
|
||||
},
|
||||
waitURL: `${FRAME2}?query_param1=value#ref2`,
|
||||
expectedEvent: "onHistoryStateUpdated",
|
||||
description: "history.pushState, same pathname, same hash, different query params",
|
||||
},
|
||||
{
|
||||
action: () => {
|
||||
win.frames[0].history.pushState({}, "History PushState", `${FRAME2}?query_param2=value#ref3`);
|
||||
},
|
||||
waitURL: `${FRAME2}?query_param2=value#ref3`,
|
||||
expectedEvent: "onHistoryStateUpdated",
|
||||
description: "history.pushState, same pathname, different hash, different query params",
|
||||
},
|
||||
{
|
||||
action: () => { win.frames[0].history.pushState(null, "History PushState", FRAME_PUSHSTATE); },
|
||||
waitURL: FRAME_PUSHSTATE,
|
||||
expectedEvent: "onHistoryStateUpdated",
|
||||
description: "history.pushState, different pathname",
|
||||
},
|
||||
];
|
||||
|
||||
info("Received onReferenceFragmentUpdated from FRAME2");
|
||||
for (let navigation of navigationSequence) {
|
||||
let {expectedEvent, waitURL, action, description} = navigation;
|
||||
info(`Waiting ${expectedEvent} from ${waitURL} - ${description}`);
|
||||
yield loadAndWait(win, expectedEvent, waitURL, action);
|
||||
info(`Received ${expectedEvent} from ${waitURL} - ${description}`);
|
||||
}
|
||||
|
||||
for (let i = navigationSequence.length - 1; i > 0; i--) {
|
||||
let {waitURL: fromURL, expectedEvent} = navigationSequence[i];
|
||||
let {waitURL} = navigationSequence[i - 1];
|
||||
info(`Waiting ${expectedEvent} from ${waitURL} - history.back() from ${fromURL} to ${waitURL}`);
|
||||
yield loadAndWait(win, expectedEvent, waitURL, () => { win.frames[0].history.back(); });
|
||||
info(`Received ${expectedEvent} from ${waitURL} - history.back() from ${fromURL} to ${waitURL}`);
|
||||
}
|
||||
|
||||
for (let i = 0; i < navigationSequence.length - 1; i++) {
|
||||
let {waitURL: fromURL} = navigationSequence[i];
|
||||
let {waitURL, expectedEvent} = navigationSequence[i + 1];
|
||||
info(`Waiting ${expectedEvent} from ${waitURL} - history.forward() from ${fromURL} to ${waitURL}`);
|
||||
yield loadAndWait(win, expectedEvent, waitURL, () => { win.frames[0].history.forward(); });
|
||||
info(`Received ${expectedEvent} from ${waitURL} - history.forward() from ${fromURL} to ${waitURL}`);
|
||||
}
|
||||
|
||||
win.close();
|
||||
|
||||
|
|
|
@ -99,8 +99,11 @@ var Manager = {
|
|||
|
||||
onLocationChange(browser, data) {
|
||||
let url = data.location;
|
||||
if (data.flags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT) {
|
||||
|
||||
if (data.isReferenceFragmentUpdated) {
|
||||
this.fire("onReferenceFragmentUpdated", browser, data, {url});
|
||||
} else if (data.isHistoryStateUpdated) {
|
||||
this.fire("onHistoryStateUpdated", browser, data, {url});
|
||||
} else {
|
||||
this.fire("onCommitted", browser, data, {url});
|
||||
}
|
||||
|
@ -142,9 +145,8 @@ const EVENTS = [
|
|||
"onCompleted",
|
||||
"onErrorOccurred",
|
||||
"onReferenceFragmentUpdated",
|
||||
|
||||
"onHistoryStateUpdated",
|
||||
// "onCreatedNavigationTarget",
|
||||
// "onHistoryStateUpdated",
|
||||
];
|
||||
|
||||
var WebNavigation = {};
|
||||
|
|
|
@ -25,6 +25,19 @@ addMessageListener("Extension:DisableWebNavigation", () => {
|
|||
|
||||
var WebProgressListener = {
|
||||
init: function() {
|
||||
// This WeakMap (DOMWindow -> nsIURI) keeps track of the pathname and hash
|
||||
// of the previous location for all the existent docShells.
|
||||
this.previousURIMap = new WeakMap();
|
||||
|
||||
// Populate the above previousURIMap by iterating over the docShells tree.
|
||||
for (let currentDocShell of WebNavigationFrames.iterateDocShellTree(docShell)) {
|
||||
let win = currentDocShell.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindow);
|
||||
let {currentURI} = currentDocShell.QueryInterface(Ci.nsIWebNavigation);
|
||||
|
||||
this.previousURIMap.set(win, currentURI);
|
||||
}
|
||||
|
||||
let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebProgress);
|
||||
webProgress.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_STATE_WINDOW |
|
||||
|
@ -48,6 +61,7 @@ var WebProgressListener = {
|
|||
status,
|
||||
stateFlags,
|
||||
};
|
||||
|
||||
sendAsyncMessage("Extension:StateChange", data);
|
||||
|
||||
if (webProgress.DOMWindow.top != webProgress.DOMWindow) {
|
||||
|
@ -56,24 +70,51 @@ var WebProgressListener = {
|
|||
// For some reason we don't fire onLocationChange for the
|
||||
// initial navigation of a sub-frame. So we need to simulate
|
||||
// it here.
|
||||
let data = {
|
||||
location: request.QueryInterface(Ci.nsIChannel).URI.spec,
|
||||
windowId: webProgress.DOMWindowID,
|
||||
parentWindowId: WebNavigationFrames.getParentWindowId(webProgress.DOMWindow),
|
||||
flags: 0,
|
||||
};
|
||||
sendAsyncMessage("Extension:LocationChange", data);
|
||||
this.onLocationChange(webProgress, request, request.QueryInterface(Ci.nsIChannel).URI, 0);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onLocationChange: function onLocationChange(webProgress, request, locationURI, flags) {
|
||||
let {DOMWindow, loadType} = webProgress;
|
||||
|
||||
// Get the previous URI loaded in the DOMWindow.
|
||||
let previousURI = this.previousURIMap.get(DOMWindow);
|
||||
|
||||
// Update the URI in the map with the new locationURI.
|
||||
this.previousURIMap.set(DOMWindow, locationURI);
|
||||
|
||||
let isSameDocument = (flags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT);
|
||||
let isHistoryStateUpdated = false;
|
||||
let isReferenceFragmentUpdated = false;
|
||||
|
||||
if (isSameDocument) {
|
||||
let pathChanged = !(previousURI && locationURI.equalsExceptRef(previousURI));
|
||||
let hashChanged = !(previousURI && previousURI.ref == locationURI.ref);
|
||||
|
||||
// When the location changes but the document is the same:
|
||||
// - path not changed and hash changed -> |onReferenceFragmentUpdated|
|
||||
// (even if it changed using |history.pushState|)
|
||||
// - path not changed and hash not changed -> |onHistoryStateUpdated|
|
||||
// (only if it changes using |history.pushState|)
|
||||
// - path changed -> |onHistoryStateUpdated|
|
||||
|
||||
if (!pathChanged && hashChanged) {
|
||||
isReferenceFragmentUpdated = true;
|
||||
} else if (loadType & Ci.nsIDocShell.LOAD_CMD_PUSHSTATE) {
|
||||
isHistoryStateUpdated = true;
|
||||
} else if (loadType & Ci.nsIDocShell.LOAD_CMD_HISTORY) {
|
||||
isHistoryStateUpdated = true;
|
||||
}
|
||||
}
|
||||
|
||||
let data = {
|
||||
isHistoryStateUpdated, isReferenceFragmentUpdated,
|
||||
location: locationURI ? locationURI.spec : "",
|
||||
windowId: webProgress.DOMWindowID,
|
||||
parentWindowId: WebNavigationFrames.getParentWindowId(webProgress.DOMWindow),
|
||||
flags,
|
||||
};
|
||||
|
||||
sendAsyncMessage("Extension:LocationChange", data);
|
||||
},
|
||||
|
||||
|
|
|
@ -97,6 +97,8 @@ function findFrame(windowId, rootDocShell) {
|
|||
}
|
||||
|
||||
var WebNavigationFrames = {
|
||||
iterateDocShellTree,
|
||||
|
||||
getFrame(docShell, frameId) {
|
||||
if (frameId == 0) {
|
||||
return convertDocShellToFrameDetail(docShell);
|
||||
|
|
Загрузка…
Ссылка в новой задаче