Commit 08c61758 authored by beidson@apple.com's avatar beidson@apple.com

<rdar://problem/7214236> and http://webkit.org/b/32052 - Implement HTML5 state object history API

Reviewed by Sam Weinig.

WebCore: 

Tests: fast/loader/stateobjects/document-destroyed-navigate-back.html
       fast/loader/stateobjects/document-destroyed-navigate-back-with-fragment-scroll.html
       fast/loader/stateobjects/popstate-after-load-complete-addeventlistener.html
       fast/loader/stateobjects/popstate-after-load-complete-body-attribute.html
       fast/loader/stateobjects/popstate-after-load-complete-window-attribute.html
       fast/loader/stateobjects/pushstate-object-types.html
       fast/loader/stateobjects/pushstate-then-replacestate.html
       fast/loader/stateobjects/pushstate-with-fragment-urls-and-hashchange.html
       fast/loader/stateobjects/replacestate-then-pushstate.html
       http/tests/loading/state-object-security-exception.html

Derived sources and project file changes:
* DerivedSources.cpp:
* DerivedSources.make:
* GNUmakefile.am
* WebCore.pro
* WebCore.vcproj/WebCore.vcproj:
* WebCore.xcodeproj/project.pbxproj:

Add the new PopStateEvent:
* dom/PopStateEvent.cpp: Added.
(WebCore::PopStateEvent::PopStateEvent):
(WebCore::PopStateEvent::initPopStateEvent):
* dom/PopStateEvent.h: Added.
(WebCore::PopStateEvent::create):
(WebCore::PopStateEvent::isPopStateEvent):
(WebCore::PopStateEvent::state):
* dom/PopStateEvent.idl: Added.
* bindings/js/JSPopStateEventCustom.cpp: Added.
(WebCore::JSPopStateEvent::initPopStateEvent):
(WebCore::JSPopStateEvent::state):
* bindings/js/JSEventCustom.cpp:
(WebCore::toJS):
* dom/Event.cpp:
(WebCore::Event::isPopStateEvent):
* dom/Event.h:
* dom/EventNames.h:

Add the "onpopstate" attribute:
* html/HTMLAttributeNames.in:
* html/HTMLBodyElement.cpp:
(WebCore::HTMLBodyElement::parseMappedAttribute):
* html/HTMLBodyElement.idl:
* html/HTMLFrameSetElement.cpp:
(WebCore::HTMLFrameSetElement::parseMappedAttribute):
* html/HTMLFrameSetElement.h:
* html/HTMLFrameSetElement.idl:
* page/DOMWindow.h:
* page/DOMWindow.idl:

Add pushState and replaceState management to the loader and history machinery:
* bindings/js/JSHistoryCustom.cpp:
(WebCore::JSHistory::pushState):
(WebCore::JSHistory::replaceState):
* loader/HistoryController.cpp:
(WebCore::HistoryController::updateForSameDocumentNavigation): Augmented from "scrollToAnchor()", combining
  both the same-document fragment scroll case with the new same-document state object activation case.
(WebCore::HistoryController::pushState):
(WebCore::HistoryController::replaceState):
* loader/HistoryController.h:
* history/BackForwardList.cpp:
(WebCore::BackForwardList::addItem): Use insertItemAfterCurrent.
(WebCore::BackForwardList::insertItemAfterCurrent): Optionally insert the item without clearing the forward
  list, as pushStateItem might've selectively cleared only certain items, with the bulk of the forward list
  meant to remain.
(WebCore::BackForwardList::pushStateItem): Clear the forward list *only* for the state item's document, then 
  insert the new item.
(WebCore::BackForwardList::removeItem):
* history/BackForwardList.h:
* page/History.cpp:
(WebCore::History::urlForState):
(WebCore::History::stateObjectAdded):
* page/History.h:
* page/History.idl:

Let HistoryItems and Documents associate with each other, as well as letting HistoryItems contain state objects:
* history/HistoryItem.cpp:
(WebCore::HistoryItem::HistoryItem):
(WebCore::HistoryItem::~HistoryItem):
(WebCore::HistoryItem::setStateObject):
(WebCore::HistoryItem::setDocument):
(WebCore::HistoryItem::documentDetached):
* history/HistoryItem.h:
(WebCore::HistoryItem::stateObject):
(WebCore::HistoryItem::document):
* dom/Document.cpp:
(WebCore::Document::detach): Notify all back/forward history items owned by this Document that it
  is going away.
(WebCore::Document::registerHistoryItem): Manage the list of back/forward history items this document owns.
(WebCore::Document::unregisterHistoryItem): Ditto.
* dom/Document.h:

Add the ability for Documents, DocumentLoaders, and FrameLoaderClients to be notified when a Documents
URL changes as the result of pushState(), replaceState(), or a popstate navigation:
* dom/Document.cpp:
(WebCore::Document::implicitClose): If there's a pending state object, dispatch the popstate event.
(WebCore::Document::updateURLForPushOrReplaceState):
(WebCore::Document::statePopped): If loading is complete, dispatch the popstate event. Otherwise, set 
  the pending state object.
* loader/DocumentLoader.cpp:
(WebCore::DocumentLoader::replaceRequestURLForSameDocumentNavigation):
* loader/DocumentLoader.h:
* loader/FrameLoaderClient.h:
* loader/EmptyClients.h:
(WebCore::EmptyFrameLoaderClient::dispatchDidChangeStateObjectForPageForFrame):

Change handling of "loading a HistoryItem" to distinguish between new-Document navigations and same-Document
navigations, combining the old concept of anchor scrolls with the new concept of state object navigations:
* loader/FrameLoader.cpp:
(WebCore::FrameLoader::loadInSameDocument):
(WebCore::FrameLoader::continueFragmentScrollAfterNavigationPolicy):
(WebCore::FrameLoader::navigateWithinDocument):
(WebCore::FrameLoader::navigateToDifferentDocument):
(WebCore::FrameLoader::loadItem):
* loader/FrameLoader.h:
* page/Page.cpp:
(WebCore::Page::goToItem): Changed to allow state object activations to pass through without the load stopping.

WebKit/chromium: 

* src/FrameLoaderClientImpl.cpp:
(WebKit::FrameLoaderClientImpl::dispatchDidPushStateWithinPage):
(WebKit::FrameLoaderClientImpl::dispatchDidReplaceStateWithinPage):
(WebKit::FrameLoaderClientImpl::dispatchDidPopStateWithinPage):
* src/FrameLoaderClientImpl.h:

WebKit/gtk: 

* WebCoreSupport/FrameLoaderClientGtk.cpp:
(WebKit::FrameLoaderClient::dispatchDidPushStateWithinPage):
(WebKit::FrameLoaderClient::dispatchDidReplaceStateWithinPage):
(WebKit::FrameLoaderClient::dispatchDidPopStateWithinPage):
* WebCoreSupport/FrameLoaderClientGtk.h:

WebKit/mac: 

* WebCoreSupport/WebFrameLoaderClient.h:
* WebCoreSupport/WebFrameLoaderClient.mm:
(WebFrameLoaderClient::dispatchDidPushStateWithinPage):
(WebFrameLoaderClient::dispatchDidReplaceStateWithinPage):
(WebFrameLoaderClient::dispatchDidPopStateWithinPage):
* WebView/WebDelegateImplementationCaching.h:
* WebView/WebFrameLoadDelegatePrivate.h:
* WebView/WebView.mm:
(-[WebView _cacheFrameLoadDelegateImplementations]):

WebKit/qt: 

* WebCoreSupport/FrameLoaderClientQt.cpp:
(WebCore::FrameLoaderClientQt::dispatchDidPushStateWithinPage):
(WebCore::FrameLoaderClientQt::dispatchDidReplaceStateWithinPage):
(WebCore::FrameLoaderClientQt::dispatchDidPopStateWithinPage):
* WebCoreSupport/FrameLoaderClientQt.h:

WebKit/win: 

* Interfaces/IWebFrameLoadDelegatePrivate2.idl:
* WebCoreSupport/WebFrameLoaderClient.cpp:
(WebFrameLoaderClient::dispatchDidPushStateWithinPage):
(WebFrameLoaderClient::dispatchDidReplaceStateWithinPage):
(WebFrameLoaderClient::dispatchDidPopStateWithinPage):
* WebCoreSupport/WebFrameLoaderClient.h:

WebKit/wx: 

* WebKitSupport/FrameLoaderClientWx.cpp:
(WebCore::FrameLoaderClientWx::dispatchDidPushStateWithinPage):
(WebCore::FrameLoaderClientWx::dispatchDidReplaceStateWithinPage):
(WebCore::FrameLoaderClientWx::dispatchDidPopStateWithinPage):
* WebKitSupport/FrameLoaderClientWx.h:

WebKitTools: 

Keep DRT-win building...

* DumpRenderTree/win/FrameLoadDelegate.h:
(FrameLoadDelegate::didPushStateWithinPageForFrame):
(FrameLoadDelegate::didReplaceStateWithinPageForFrame):
(FrameLoadDelegate::didPopStateWithinPageForFrame):

LayoutTests: 

Update expected results of old tests:
* fast/dom/Window/window-appendages-cleared-expected.txt:
* fast/dom/Window/window-properties-expected.txt:
* http/tests/security/cross-frame-access-enumeration-expected.txt:

New tests:
* fast/loader/stateobjects: Added.
* fast/loader/stateobjects/document-destroyed-navigate-back-expected.txt: Added.
* fast/loader/stateobjects/document-destroyed-navigate-back-with-fragment-scroll-expected.txt: Added.
* fast/loader/stateobjects/document-destroyed-navigate-back-with-fragment-scroll.html: Added.
* fast/loader/stateobjects/document-destroyed-navigate-back.html: Added.
* fast/loader/stateobjects/popstate-after-load-complete-addeventlistener-expected.txt: Added.
* fast/loader/stateobjects/popstate-after-load-complete-addeventlistener.html: Added.
* fast/loader/stateobjects/popstate-after-load-complete-body-attribute-expected.txt: Added.
* fast/loader/stateobjects/popstate-after-load-complete-body-attribute.html: Added.
* fast/loader/stateobjects/popstate-after-load-complete-body-inline-attribute-expected.txt: Added.
* fast/loader/stateobjects/popstate-after-load-complete-body-inline-attribute.html: Added.
* fast/loader/stateobjects/popstate-after-load-complete-window-attribute-expected.txt: Added.
* fast/loader/stateobjects/popstate-after-load-complete-window-attribute.html: Added.
* fast/loader/stateobjects/pushstate-object-types-expected.txt: Added.
* fast/loader/stateobjects/pushstate-object-types.html: Added.
* fast/loader/stateobjects/pushstate-then-replacestate-expected.txt: Added.
* fast/loader/stateobjects/pushstate-then-replacestate.html: Added.
* fast/loader/stateobjects/pushstate-with-fragment-urls-and-hashchange-expected.txt: Added.
* fast/loader/stateobjects/pushstate-with-fragment-urls-and-hashchange.html: Added.
* fast/loader/stateobjects/replacestate-then-pushstate-expected.txt: Added.
* fast/loader/stateobjects/replacestate-then-pushstate.html: Added.
* fast/loader/stateobjects/resources: Added.
* fast/loader/stateobjects/resources/navigate-back.html: Added.
* http/tests/loading/state-object-security-exception-expected.txt: Added.
* http/tests/loading/state-object-security-exception.html: Added.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@51644 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent a88b9872
2009-12-03 Brady Eidson <beidson@apple.com>
Reviewed by Sam Weinig.
<rdar://problem/7214236> and http://webkit.org/b/32052 - Implement HTML5 state object history API
Update expected results of old tests:
* fast/dom/Window/window-appendages-cleared-expected.txt:
* fast/dom/Window/window-properties-expected.txt:
* http/tests/security/cross-frame-access-enumeration-expected.txt:
New tests:
* fast/loader/stateobjects: Added.
* fast/loader/stateobjects/document-destroyed-navigate-back-expected.txt: Added.
* fast/loader/stateobjects/document-destroyed-navigate-back-with-fragment-scroll-expected.txt: Added.
* fast/loader/stateobjects/document-destroyed-navigate-back-with-fragment-scroll.html: Added.
* fast/loader/stateobjects/document-destroyed-navigate-back.html: Added.
* fast/loader/stateobjects/popstate-after-load-complete-addeventlistener-expected.txt: Added.
* fast/loader/stateobjects/popstate-after-load-complete-addeventlistener.html: Added.
* fast/loader/stateobjects/popstate-after-load-complete-body-attribute-expected.txt: Added.
* fast/loader/stateobjects/popstate-after-load-complete-body-attribute.html: Added.
* fast/loader/stateobjects/popstate-after-load-complete-body-inline-attribute-expected.txt: Added.
* fast/loader/stateobjects/popstate-after-load-complete-body-inline-attribute.html: Added.
* fast/loader/stateobjects/popstate-after-load-complete-window-attribute-expected.txt: Added.
* fast/loader/stateobjects/popstate-after-load-complete-window-attribute.html: Added.
* fast/loader/stateobjects/pushstate-object-types-expected.txt: Added.
* fast/loader/stateobjects/pushstate-object-types.html: Added.
* fast/loader/stateobjects/pushstate-then-replacestate-expected.txt: Added.
* fast/loader/stateobjects/pushstate-then-replacestate.html: Added.
* fast/loader/stateobjects/pushstate-with-fragment-urls-and-hashchange-expected.txt: Added.
* fast/loader/stateobjects/pushstate-with-fragment-urls-and-hashchange.html: Added.
* fast/loader/stateobjects/replacestate-then-pushstate-expected.txt: Added.
* fast/loader/stateobjects/replacestate-then-pushstate.html: Added.
* fast/loader/stateobjects/resources: Added.
* fast/loader/stateobjects/resources/navigate-back.html: Added.
* http/tests/loading/state-object-security-exception-expected.txt: Added.
* http/tests/loading/state-object-security-exception.html: Added.
2009-12-03 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk>
Reviewed by Xan Lopez.
......@@ -2,6 +2,8 @@ PASS history.back == "LEFTOVER" is false
PASS history.forward == "LEFTOVER" is false
PASS history.go == "LEFTOVER" is false
PASS history.length == "LEFTOVER" is false
PASS history.pushState == "LEFTOVER" is false
PASS history.replaceState == "LEFTOVER" is false
PASS location.assign == "LEFTOVER" is false
PASS location.hash == "LEFTOVER" is false
PASS location.host == "LEFTOVER" is false
......
......@@ -1737,6 +1737,8 @@ window.history.back [function]
window.history.forward [function]
window.history.go [function]
window.history.length [number]
window.history.pushState [function]
window.history.replaceState [function]
window.innerHeight [number]
window.innerWidth [number]
window.length [number]
......@@ -1813,6 +1815,7 @@ window.onpageshow [null]
window.onpause [null]
window.onplay [null]
window.onplaying [null]
window.onpopstate [null]
window.onprogress [null]
window.onratechange [null]
window.onreset [null]
......
main frame - has 1 onunload handler(s)
ALERT: History length is 2
ALERT: State popped - FirstEntry (type string)
ALERT: State popped - SecondEntry (type string)
ALERT: Navigating back...
main frame - has 1 onunload handler(s)
ALERT: History length is 2
ALERT: window.location is file:///Volumes/Data/svn/OpenSource/LayoutTests/fast/loader/stateobjects/document-destroyed-navigate-back.html?SecondEntryShouldNeverBeReactivated
main frame - has 1 onunload handler(s)
ALERT: History length is 1
ALERT: window.location is file:///Volumes/Data/svn/OpenSource/LayoutTests/fast/loader/stateobjects/document-destroyed-navigate-back.html?FirstEntryShouldNeverBeReactivated
ALERT: Test completed
This test:
-Builds up a list of state object entries.
-Navigates through them to verify that the popstate event is fired.
-Navigates away to a new document, with the old document being destroyed.
-Navigates back to the state object entries and verifies the popstate event is not fired.
History length is 1
window.location is file:///Volumes/Data/svn/OpenSource/LayoutTests/fast/loader/stateobjects/document-destroyed-navigate-back.html?FirstEntryShouldNeverBeReactivated
Test completed
main frame - has 1 onunload handler(s)
ALERT: History length is 2
ALERT: State popped - FirstEntry (type string)
ALERT: hashChanged - location is file:///Volumes/Data/svn/OpenSource/LayoutTests/fast/loader/stateobjects/document-destroyed-navigate-back-with-fragment-scroll.html#FirstEntry
ALERT: State popped - SecondEntry (type string)
ALERT: hashChanged - location is file:///Volumes/Data/svn/OpenSource/LayoutTests/fast/loader/stateobjects/document-destroyed-navigate-back-with-fragment-scroll.html#SecondEntry
ALERT: Navigating back...
main frame - has 1 onunload handler(s)
ALERT: History length is 2
ALERT: window.location is file:///Volumes/Data/svn/OpenSource/LayoutTests/fast/loader/stateobjects/document-destroyed-navigate-back-with-fragment-scroll.html#SecondEntryShouldNeverBeReactivated
ALERT: hashChanged - location is file:///Volumes/Data/svn/OpenSource/LayoutTests/fast/loader/stateobjects/document-destroyed-navigate-back-with-fragment-scroll.html#FirstEntryShouldNeverBeReactivated
ALERT: Test completed
This test:
-Builds up a list of state object entries with fragment URL.
-Navigates through them to verify that the popstate and hashchanged events are fired.
-Navigates away to a new document, with the old document being destroyed.
-Navigates back to the state object entries and verifies the popstate event is not fired.
History length is 2
window.location is file:///Volumes/Data/svn/OpenSource/LayoutTests/fast/loader/stateobjects/document-destroyed-navigate-back-with-fragment-scroll.html#SecondEntryShouldNeverBeReactivated
hashChanged - location is file:///Volumes/Data/svn/OpenSource/LayoutTests/fast/loader/stateobjects/document-destroyed-navigate-back-with-fragment-scroll.html#FirstEntryShouldNeverBeReactivated
Test completed
<html>
<head>
<script>
if (window.layoutTestController) {
if (!sessionStorage.stage)
layoutTestController.clearBackForwardList();
layoutTestController.dumpAsText();
layoutTestController.waitUntilDone();
}
function log(txt)
{
document.getElementById("logger").innerText += txt + "\n";
// alert the messages also so DumpRenderTree can capture and log messages across multiple documents.
alert(txt);
}
function endTest(msg)
{
log(msg);
sessionStorage.clear();
if (window.layoutTestController)
layoutTestController.notifyDone();
}
function runSecondStageOfTest()
{
log("History length is " + history.length);
log("window.location is " + window.location);
sessionStorage.stage = 3;
history.back();
}
function runThirdStageOfTest()
{
log("History length is " + history.length);
log("window.location is " + window.location);
endTest("Test completed");
}
function loaded()
{
if (sessionStorage.stage) {
if (sessionStorage.stage == 2)
runSecondStageOfTest();
else if (sessionStorage.stage == 3)
endTest("Shouldn't reach this case when doing fragment scrolls");
else
endTest("Unexpected stage value");
} else
runFirstStageOfTest();
}
function runFirstStageOfTest()
{
history.replaceState("FirstEntry", null, "#FirstEntry");
history.pushState("SecondEntry", null, "#SecondEntry");
log("History length is " + history.length);
history.back();
}
function statePopped()
{
log("State popped - " + event.state + " (type " + typeof event.state + ")");
if (event.state == "FirstEntry") {
history.replaceState("FirstEntryShouldNeverBeReactivated", null, "#FirstEntryShouldNeverBeReactivated");
history.forward();
} else if (event.state == "SecondEntry") {
history.replaceState("SecondEntryShouldNeverBeReactivated", null, "#SecondEntryShouldNeverBeReactivated");
window.location = "resources/navigate-back.html";
} else
endTest("Unexpected state popped - " + event.state);
}
function hashChanged()
{
log("hashChanged - location is " + window.location);
if (window.location.hash == "#FirstEntryShouldNeverBeReactivated")
endTest("Test completed");
}
</script>
<body onload="loaded();" onpopstate="statePopped();" onhashchange="hashChanged();" onunload="/* disable page cache */">
<pre>
This test:
-Builds up a list of state object entries with fragment URL.
-Navigates through them to verify that the popstate and hashchanged events are fired.
-Navigates away to a new document, with the old document being destroyed.
-Navigates back to the state object entries and verifies the popstate event is not fired.
</pre><br>
<pre id="logger"></pre>
</body>
</html>
<html>
<head>
<script>
if (window.layoutTestController) {
if (!sessionStorage.stage)
layoutTestController.clearBackForwardList();
layoutTestController.dumpAsText();
layoutTestController.waitUntilDone();
}
function log(txt)
{
document.getElementById("logger").innerText += txt + "\n";
// alert the messages also so DumpRenderTree can capture and log messages across multiple documents.
alert(txt);
}
function endTest(msg)
{
log(msg);
sessionStorage.clear();
if (window.layoutTestController)
layoutTestController.notifyDone();
}
function runSecondStageOfTest()
{
log("History length is " + history.length);
log("window.location is " + window.location);
sessionStorage.stage = 3;
history.back();
}
function runThirdStageOfTest()
{
log("History length is " + history.length);
log("window.location is " + window.location);
endTest("Test completed");
}
function loaded()
{
if (sessionStorage.stage) {
if (sessionStorage.stage == 2)
runSecondStageOfTest();
else if (sessionStorage.stage == 3)
runThirdStageOfTest();
else
endTest("Unexpected stage value");
} else
runFirstStageOfTest();
}
function runFirstStageOfTest()
{
history.replaceState("FirstEntry", null, "?FirstEntry");
history.pushState("SecondEntry", null, "?SecondEntry");
log("History length is " + history.length);
history.back();
}
function statePopped()
{
log("State popped - " + event.state + " (type " + typeof event.state + ")");
if (event.state == "FirstEntry") {
history.replaceState("FirstEntryShouldNeverBeReactivated", null, "?FirstEntryShouldNeverBeReactivated");
history.forward();
} else if (event.state == "SecondEntry") {
history.replaceState("SecondEntryShouldNeverBeReactivated", null, "?SecondEntryShouldNeverBeReactivated");
window.location = "resources/navigate-back.html";
} else
endTest("Unexpected state popped - " + event.state);
}
</script>
<body onload="loaded();" onpopstate="statePopped();" onunload="/* disable page cache */">
<pre>
This test:
-Builds up a list of state object entries.
-Navigates through them to verify that the popstate event is fired.
-Navigates away to a new document, with the old document being destroyed.
-Navigates back to the state object entries and verifies the popstate event is not fired.
</pre><br>
<pre id="logger"></pre>
</body>
</html>
This test does the following:
-Listens for the popstate event using addEventListener
-Makes a call to pushState()
-Makes sure the history length is correct
-Goes back, and makes sure the popstate event is correct
-Goes forward, and makes sure the popstate event is correct
History length is 2
State popped - null (type object)
State popped - StateStringData (type string)
<html>
<head>
<script>
if (window.layoutTestController) {
layoutTestController.clearBackForwardList();
layoutTestController.dumpAsText();
layoutTestController.waitUntilDone();
}
function log(txt)
{
document.getElementById("logger").innerText += txt + "\n";
}
function runTest()
{
history.pushState("StateStringData", "New title");
log("History length is " + history.length);
history.back();
}
function statePopped()
{
log("State popped - " + event.state + " (type " + typeof event.state + ")");
if (event.state == null)
history.forward();
else if (window.layoutTestController)
layoutTestController.notifyDone();
}
window.addEventListener("popstate", statePopped);
</script>
<body onload="runTest();">
<pre>
This test does the following:
-Listens for the popstate event using addEventListener
-Makes a call to pushState()
-Makes sure the history length is correct
-Goes back, and makes sure the popstate event is correct
-Goes forward, and makes sure the popstate event is correct
</pre><br>
<pre id="logger"></pre>
</body>
</html>
This test does the following:
-Uses body.onpopstate to add a popstate handler (both by using the inline attribute and a script-assigned attribute)
-Makes a call to pushState()
-Makes sure the history length is correct
-Goes back, and makes sure the popstate event is correct
-Goes forward, and makes sure the popstate event is correct
History length is 2
State popped - null (type object)
State popped - StateStringData (type string)
<html>
<head>
<script>
if (window.layoutTestController) {
layoutTestController.clearBackForwardList();
layoutTestController.dumpAsText();
layoutTestController.waitUntilDone();
}
function log(txt)
{
document.getElementById("logger").innerText += txt + "\n";
}
function runTest()
{
history.pushState("StateStringData", "New title");
log("History length is " + history.length);
history.back();
}
function statePopped()
{
log("State popped - " + event.state + " (type " + typeof event.state + ")");
if (event.state == null) {
document.body.onpopstate = statePopped;
history.forward();
} else if (window.layoutTestController)
layoutTestController.notifyDone();
}
</script>
<body onload="runTest();">
<pre>
This test does the following:
-Uses body.onpopstate to add a popstate handler (both by using the inline attribute and a script-assigned attribute)
-Makes a call to pushState()
-Makes sure the history length is correct
-Goes back, and makes sure the popstate event is correct
-Goes forward, and makes sure the popstate event is correct
</pre><br>
<pre id="logger"></pre>
</body>
<script>
document.body.onpopstate = statePopped;
</script>
</html>
This test does the following:
-Uses body.onpopstate to add a popstate handler (both by using the inline attribute and a script-assigned attribute)
-Makes a call to pushState()
-Makes sure the history length is correct
-Goes back, and makes sure the popstate event is correct
-Goes forward, and makes sure the popstate event is correct
History length is 2
State popped - null (type object)
State popped - StateStringData (type string)
<html>
<head>
<script>
if (window.layoutTestController) {
layoutTestController.clearBackForwardList();
layoutTestController.dumpAsText();
layoutTestController.waitUntilDone();
}
function log(txt)
{
document.getElementById("logger").innerText += txt + "\n";
}
function runTest()
{
history.pushState("StateStringData", "New title");
log("History length is " + history.length);
history.back();
}
function statePopped()
{
log("State popped - " + event.state + " (type " + typeof event.state + ")");
if (event.state == null) {
document.body.onpopstate = statePopped;
history.forward();
} else if (window.layoutTestController)
layoutTestController.notifyDone();
}
</script>
<body onload="runTest();" onpopstate="statePopped();">
<pre>
This test does the following:
-Uses body.onpopstate to add a popstate handler (both by using the inline attribute and a script-assigned attribute)
-Makes a call to pushState()
-Makes sure the history length is correct
-Goes back, and makes sure the popstate event is correct
-Goes forward, and makes sure the popstate event is correct
</pre><br>
<pre id="logger"></pre>
</body>
</html>
This test does the following:
-Uses window.onpopstate to add a popstate handler
-Makes a call to pushState()
-Makes sure the history length is correct
-Goes back, and makes sure the popstate event is correct
-Goes forward, and makes sure the popstate event is correct
History length is 2
State popped - null (type object)
State popped - StateStringData (type string)
<html>
<head>
<script>
if (window.layoutTestController) {
layoutTestController.clearBackForwardList();
layoutTestController.dumpAsText();
layoutTestController.waitUntilDone();
}
function log(txt)
{
document.getElementById("logger").innerText += txt + "\n";
}
function runTest()
{
history.pushState("StateStringData", "New title");
log("History length is " + history.length);
history.back();
}
function statePopped()
{
log("State popped - " + event.state + " (type " + typeof event.state + ")");
if (event.state == null)
history.forward();
else if (window.layoutTestController)
layoutTestController.notifyDone();
}
window.onpopstate = statePopped;
</script>
<body onload="runTest();">
<pre>
This test does the following:
-Uses window.onpopstate to add a popstate handler
-Makes a call to pushState()
-Makes sure the history length is correct
-Goes back, and makes sure the popstate event is correct
-Goes forward, and makes sure the popstate event is correct
</pre><br>
<pre id="logger"></pre>
</body>
</html>
This test calls pushState with state objects of all the different object types supported by the HTML5 "internal structured cloning algorithm" and makes sure the events contain the expected objects when the states are popped.
State popped - [object Object] (type object)
State popped - [object Object] (type object)
State popped - (type object)
State popped - null (type object)
State popped - Wed Dec 31 1969 16:00:00 GMT-0800 (PST) (type object)
State popped - String (type string)
State popped - 42 (type number)
State popped - true (type boolean)
State popped - false (type boolean)
State popped - null (type object)
State popped - undefined (type undefined)
State popped - FirstEntry (type string)
<html>
<head>
<script>
if (window.layoutTestController) {
layoutTestController.clearBackForwardList();
layoutTestController.dumpAsText();
layoutTestController.waitUntilDone();
}
function log(txt)
{
document.getElementById("logger").innerText += txt + "\n";
}
function runTest()
{
history.replaceState("FirstEntry", "Initial entry");
history.pushState(undefined, "undefined entry");
history.pushState(null, "null entry");
history.pushState(false, "false entry");
history.pushState(true, "true entry");
history.pushState(42, "Number entry");
history.pushState("String", "String entry");
history.pushState(new Date(0), "Date entry");
history.pushState(new RegExp, "RegExp entry");
history.pushState(new Array, "Array entry");
history.pushState(new Object, "Object entry");
history.pushState(new Error, "Error entry");
/* The following are not yet well enough supported in WebKit to meaningfully test here:
history.pushState([ImageData], "ImageData entry");
history.pushState([Blob], "Blob entry");
history.pushState([File], "File entry");
history.pushState([FileList], "FileList entry");
*/
history.pushState("BufferEntry", "Last entry");
history.back();
}