зеркало из https://github.com/mozilla/gecko-dev.git
Bug 634435: Add a property to expose the current pushState-state. r=jlebar a=beltzner
This commit is contained in:
Родитель
39318298b6
Коммит
8147551d23
|
@ -55,6 +55,7 @@
|
|||
#include "nsHashKeys.h"
|
||||
#include "nsNodeInfoManager.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsIVariant.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
@ -1422,26 +1423,13 @@ public:
|
|||
Doc_Theme_Bright
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the document's pending state object (serialized to JSON), or the
|
||||
* empty string if one doesn't exist.
|
||||
*
|
||||
* This field serves as a waiting place for the history entry's state object:
|
||||
* We set the field's value to the history entry's state object early on in
|
||||
* the load, then after we fire onload we deserialize the field's value and
|
||||
* fire a popstate event containing the resulting object.
|
||||
*/
|
||||
nsAString& GetPendingStateObject()
|
||||
{
|
||||
return mPendingStateObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the document's pending state object (as serialized to JSON).
|
||||
*/
|
||||
void SetPendingStateObject(nsAString &obj)
|
||||
void SetCurrentStateObject(nsAString &obj)
|
||||
{
|
||||
mPendingStateObject.Assign(obj);
|
||||
mCurrentStateObject.Assign(obj);
|
||||
mCurrentStateObjectCached = nsnull;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1736,7 +1724,7 @@ protected:
|
|||
*/
|
||||
PRUint32 mExternalScriptsBeingEvaluated;
|
||||
|
||||
nsString mPendingStateObject;
|
||||
nsString mCurrentStateObject;
|
||||
|
||||
// Weak reference to mScriptGlobalObject QI:d to nsPIDOMWindow,
|
||||
// updated on every set of mSecriptGlobalObject.
|
||||
|
@ -1752,6 +1740,8 @@ protected:
|
|||
|
||||
// Our base target.
|
||||
nsString mBaseTarget;
|
||||
|
||||
nsCOMPtr<nsIVariant> mCurrentStateObjectCached;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocument, NS_IDOCUMENT_IID)
|
||||
|
|
|
@ -104,6 +104,7 @@
|
|||
#include "nsDOMError.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsIJSON.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsNodeInfoManager.h"
|
||||
#include "nsIXBLService.h"
|
||||
|
@ -1726,6 +1727,7 @@ NS_INTERFACE_TABLE_HEAD(nsDocument)
|
|||
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIRadioGroupContainer)
|
||||
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIMutationObserver)
|
||||
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIApplicationCacheContainer)
|
||||
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMNSDocument_MOZILLA_2_0_BRANCH)
|
||||
NS_OFFSET_AND_INTERFACE_TABLE_END
|
||||
NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE
|
||||
NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsDocument)
|
||||
|
@ -1905,6 +1907,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsDocument)
|
|||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDOMImplementation)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOriginalDocument)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mCachedEncoder)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mCurrentStateObjectCached)
|
||||
|
||||
// Traverse all our nsCOMArrays.
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mStyleSheets)
|
||||
|
@ -8122,6 +8125,52 @@ nsIDocument::ScheduleBeforePaintEvent(nsIAnimationFrameListener* aListener)
|
|||
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocument::GetMozCurrentStateObject(nsIVariant** aState)
|
||||
{
|
||||
// Get the document's current state object. This is the object returned form
|
||||
// both document.mozCurrentStateObject as well as popStateEvent.state
|
||||
|
||||
nsCOMPtr<nsIVariant> stateObj;
|
||||
// Parse the JSON, if there's any to parse.
|
||||
if (!mCurrentStateObjectCached && !mCurrentStateObject.IsEmpty()) {
|
||||
// Get the JSContext associated with this document. We need this for
|
||||
// deserialization.
|
||||
nsIScriptGlobalObject *sgo = GetScopeObject();
|
||||
NS_ENSURE_TRUE(sgo, NS_ERROR_FAILURE);
|
||||
|
||||
nsIScriptContext *scx = sgo->GetContext();
|
||||
NS_ENSURE_TRUE(scx, NS_ERROR_FAILURE);
|
||||
|
||||
JSContext *cx = (JSContext*) scx->GetNativeContext();
|
||||
|
||||
// Make sure we in the request while we have jsval on the native stack.
|
||||
JSAutoRequest ar(cx);
|
||||
|
||||
// If our json call triggers a JS-to-C++ call, we want that call to use cx
|
||||
// as the context. So we push cx onto the context stack.
|
||||
nsCxPusher cxPusher;
|
||||
|
||||
jsval jsStateObj = JSVAL_NULL;
|
||||
|
||||
// Deserialize the state object into an nsIVariant.
|
||||
nsCOMPtr<nsIJSON> json = do_GetService("@mozilla.org/dom/json;1");
|
||||
NS_ENSURE_TRUE(cxPusher.Push(cx), NS_ERROR_FAILURE);
|
||||
nsresult rv = json->DecodeToJSVal(mCurrentStateObject, cx, &jsStateObj);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
cxPusher.Pop();
|
||||
|
||||
nsCOMPtr<nsIXPConnect> xpconnect = do_GetService(nsIXPConnect::GetCID());
|
||||
NS_ENSURE_TRUE(xpconnect, NS_ERROR_FAILURE);
|
||||
rv = xpconnect->JSValToVariant(cx, &jsStateObj, getter_AddRefs(mCurrentStateObjectCached));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
NS_IF_ADDREF(*aState = mCurrentStateObjectCached);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDocument::AddImage(imgIRequest* aImage)
|
||||
{
|
||||
|
|
|
@ -517,7 +517,8 @@ class nsDocument : public nsIDocument,
|
|||
public nsIScriptObjectPrincipal,
|
||||
public nsIRadioGroupContainer,
|
||||
public nsIApplicationCacheContainer,
|
||||
public nsStubMutationObserver
|
||||
public nsStubMutationObserver,
|
||||
public nsIDOMNSDocument_MOZILLA_2_0_BRANCH
|
||||
{
|
||||
public:
|
||||
typedef mozilla::dom::Element Element;
|
||||
|
@ -808,6 +809,7 @@ public:
|
|||
|
||||
// nsIDOMNSDocument
|
||||
NS_DECL_NSIDOMNSDOCUMENT
|
||||
NS_DECL_NSIDOMNSDOCUMENT_MOZILLA_2_0_BRANCH
|
||||
|
||||
// nsIDOMDocumentEvent
|
||||
NS_DECL_NSIDOMDOCUMENTEVENT
|
||||
|
|
|
@ -6074,7 +6074,7 @@ nsDocShell::EndPageLoad(nsIWebProgress * aProgress,
|
|||
if (!mEODForCurrentDocument && mContentViewer) {
|
||||
// Set the pending state object which will be returned to the page in
|
||||
// the popstate event.
|
||||
SetDocPendingStateObj(mLSHE);
|
||||
SetDocCurrentStateObj(mLSHE);
|
||||
|
||||
mIsExecutingOnLoadHandler = PR_TRUE;
|
||||
rv = mContentViewer->LoadComplete(aStatus);
|
||||
|
@ -7766,7 +7766,7 @@ nsDocShell::SetupNewViewer(nsIContentViewer * aNewViewer)
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsDocShell::SetDocPendingStateObj(nsISHEntry *shEntry)
|
||||
nsDocShell::SetDocCurrentStateObj(nsISHEntry *shEntry)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
|
@ -7782,7 +7782,7 @@ nsDocShell::SetDocPendingStateObj(nsISHEntry *shEntry)
|
|||
// empty string.
|
||||
}
|
||||
|
||||
document->SetPendingStateObject(stateData);
|
||||
document->SetCurrentStateObject(stateData);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -8432,7 +8432,7 @@ nsDocShell::InternalLoad(nsIURI * aURI,
|
|||
doc->SetDocumentURI(newURI);
|
||||
}
|
||||
|
||||
SetDocPendingStateObj(mOSHE);
|
||||
SetDocCurrentStateObj(mOSHE);
|
||||
|
||||
// Dispatch the popstate and hashchange events, as appropriate.
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(mScriptGlobal);
|
||||
|
|
|
@ -564,10 +564,10 @@ protected:
|
|||
nsIChannel * aChannel,
|
||||
nsresult aResult);
|
||||
|
||||
// Sets the current document's pending state object to the given SHEntry's
|
||||
// state object. The pending state object is eventually given to the page
|
||||
// Sets the current document's current state object to the given SHEntry's
|
||||
// state object. The current state object is eventually given to the page
|
||||
// in the PopState event.
|
||||
nsresult SetDocPendingStateObj(nsISHEntry *shEntry);
|
||||
nsresult SetDocCurrentStateObj(nsISHEntry *shEntry);
|
||||
|
||||
nsresult CheckLoadingPermissions();
|
||||
|
||||
|
|
|
@ -2193,7 +2193,8 @@ nsDOMClassInfo::WrapNativeParent(JSContext *cx, JSObject *scope,
|
|||
DOM_CLASSINFO_MAP_ENTRY(nsIDOM3Document) \
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOM3Node) \
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMXPathEvaluator) \
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNodeSelector)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNodeSelector) \
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSDocument_MOZILLA_2_0_BRANCH)
|
||||
|
||||
|
||||
#define DOM_CLASSINFO_GENERIC_HTML_MAP_ENTRIES \
|
||||
|
|
|
@ -183,7 +183,6 @@
|
|||
#include "nsIXULAppInfo.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsFocusManager.h"
|
||||
#include "nsIJSON.h"
|
||||
#include "nsIXULWindow.h"
|
||||
#include "nsEventStateManager.h"
|
||||
#ifdef MOZ_XUL
|
||||
|
@ -7717,61 +7716,18 @@ nsGlobalWindow::DispatchSyncPopState(PRBool aIsInitial)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// Bail if there's no document or the document's readystate isn't "complete".
|
||||
if (!mDoc) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIDocument::ReadyState readyState = mDoc->GetReadyStateEnum();
|
||||
if (readyState != nsIDocument::READYSTATE_COMPLETE) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Get the document's pending state object -- it contains the data we're
|
||||
// going to send along with the popstate event. The object is serialized as
|
||||
// JSON.
|
||||
nsAString& stateObjJSON = mDoc->GetPendingStateObject();
|
||||
|
||||
nsCOMPtr<nsIVariant> stateObj;
|
||||
// Parse the JSON, if there's any to parse.
|
||||
if (!stateObjJSON.IsEmpty()) {
|
||||
// Get the JSContext associated with our document. We need this for
|
||||
// deserialization.
|
||||
nsCOMPtr<nsIDocument> document = do_QueryInterface(mDocument);
|
||||
NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
|
||||
|
||||
// Get the JSContext from the document, like we do in
|
||||
// nsContentUtils::GetContextFromDocument().
|
||||
nsIScriptGlobalObject *sgo = document->GetScopeObject();
|
||||
NS_ENSURE_TRUE(sgo, NS_ERROR_FAILURE);
|
||||
|
||||
nsIScriptContext *scx = sgo->GetContext();
|
||||
NS_ENSURE_TRUE(scx, NS_ERROR_FAILURE);
|
||||
|
||||
JSContext *cx = (JSContext*) scx->GetNativeContext();
|
||||
|
||||
// Make sure we in the request while we have jsval on the native stack.
|
||||
JSAutoRequest ar(cx);
|
||||
|
||||
// If our json call triggers a JS-to-C++ call, we want that call to use cx
|
||||
// as the context. So we push cx onto the context stack.
|
||||
nsCxPusher cxPusher;
|
||||
|
||||
jsval jsStateObj = JSVAL_NULL;
|
||||
|
||||
// Deserialize the state object into an nsIVariant.
|
||||
nsCOMPtr<nsIJSON> json = do_GetService("@mozilla.org/dom/json;1");
|
||||
NS_ENSURE_TRUE(cxPusher.Push(cx), NS_ERROR_FAILURE);
|
||||
rv = json->DecodeToJSVal(stateObjJSON, cx, &jsStateObj);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
cxPusher.Pop();
|
||||
|
||||
nsCOMPtr<nsIXPConnect> xpconnect = do_GetService(nsIXPConnect::GetCID());
|
||||
NS_ENSURE_TRUE(xpconnect, NS_ERROR_FAILURE);
|
||||
rv = xpconnect->JSValToVariant(cx, &jsStateObj, getter_AddRefs(stateObj));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIDOMNSDocument_MOZILLA_2_0_BRANCH> doc2 = do_QueryInterface(mDoc);
|
||||
if (!doc2) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
rv = doc2->GetMozCurrentStateObject(getter_AddRefs(stateObj));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Obtain a presentation shell for use in creating a popstate event.
|
||||
nsIPresShell *shell = mDoc->GetShell();
|
||||
nsRefPtr<nsPresContext> presContext;
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
|
||||
interface nsIBoxObject;
|
||||
interface nsIDOMLocation;
|
||||
interface nsIVariant;
|
||||
|
||||
[scriptable, uuid(92f2c6f8-3668-4a47-8251-2a900afe11fa)]
|
||||
interface nsIDOMNSDocument : nsISupports
|
||||
|
@ -129,3 +130,9 @@ interface nsIDOMNSDocument : nsISupports
|
|||
void mozSetImageElement(in DOMString aImageElementId,
|
||||
in nsIDOMElement aImageElement);
|
||||
};
|
||||
|
||||
[scriptable, uuid(fee67aed-3b94-4136-ad7d-fb88ef23f45f)]
|
||||
interface nsIDOMNSDocument_MOZILLA_2_0_BRANCH : nsISupports
|
||||
{
|
||||
readonly attribute nsIVariant mozCurrentStateObject;
|
||||
};
|
||||
|
|
|
@ -222,6 +222,8 @@ function runTest() {
|
|||
popstateExpected("Going back to page 1 should trigger a popstate.");
|
||||
is(JSON.stringify(gLastPopStateEvent.state), JSON.stringify(testObj1),
|
||||
"Wrong state object popped after going back to page 1.");
|
||||
ok(gLastPopStateEvent.state === iframeCw.document.mozCurrentStateObject,
|
||||
"Wrong state object in document after going back to page 1.");
|
||||
ok(iframeCw.location.toString().match(/file_bug500328_1.html$/),
|
||||
"Going back to page 1 hould take us to original page.");
|
||||
|
||||
|
@ -229,6 +231,8 @@ function runTest() {
|
|||
popstateExpected("Going back to page 0 should trigger a popstate.");
|
||||
is(gLastPopStateEvent.state, null,
|
||||
"Going back to page 0 should pop a null state.");
|
||||
is(iframeCw.document.mozCurrentStateObject, null,
|
||||
"Going back to page 0 should pop a null state.");
|
||||
is(iframeCw.location.search, "",
|
||||
"Going back to page 0 should clear the querystring.");
|
||||
|
||||
|
@ -236,6 +240,8 @@ function runTest() {
|
|||
popstateExpected("Going forward to page 1 should trigger a popstate.");
|
||||
is(JSON.stringify(gLastPopStateEvent.state), JSON.stringify(testObj1),
|
||||
"Wrong state object popped after going forward to page 1.");
|
||||
ok(gLastPopStateEvent.state === iframeCw.document.mozCurrentStateObject,
|
||||
"Wrong state object in document after going forward to page 1.");
|
||||
ok(iframeCw.location.toString().match(/file_bug500328_1.html$/),
|
||||
"Going forward to page 1 should leave us at original page.");
|
||||
|
||||
|
@ -246,6 +252,8 @@ function runTest() {
|
|||
popstateExpected("Going forward to page 2 should trigger a popstate.");
|
||||
is(JSON.stringify(gLastPopStateEvent.state), JSON.stringify(testObj2),
|
||||
"Wrong state object popped after going forward to page 2.");
|
||||
ok(iframeCw.document.mozCurrentStateObject === gLastPopStateEvent.state,
|
||||
"Wrong state object in document after going forward to page 2.");
|
||||
ok(iframeCw.location.toString().match(/file_bug500328_1.html\?test1#foo$/),
|
||||
"Going forward to page 2 took us to " + iframeCw.location.toString());
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче