2011-02-04 Jeremy Orlow <jorlow@chromium.org>
authorjorlow@chromium.org <jorlow@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 4 Feb 2011 23:43:19 +0000 (23:43 +0000)
committerjorlow@chromium.org <jorlow@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 4 Feb 2011 23:43:19 +0000 (23:43 +0000)
        Reviewed by Nate Chapin.

        First step towards event propogation within IndexedDB
        https://bugs.webkit.org/show_bug.cgi?id=53795

        This is the first step towards implementing
        http://www.w3.org/Bugs/Public/show_bug.cgi?id=11348
        within IndexedDB. I've created a method that knows how
        to capture and bubble (based on Node's dispatchGenericEvent).
        I've then changed IDBRequest to use it.

        The only functional change is that preventDefault now must
        be called in error events to prevent the transaction from
        being aborted. The tests reflect this change and there's one
        specific test to look at this behavior.

        * storage/indexeddb/cursor-index-delete-expected.txt:
        * storage/indexeddb/cursor-index-delete.html:
        * storage/indexeddb/database-quota-expected.txt:
        * storage/indexeddb/database-quota.html:
        * storage/indexeddb/duplicates-expected.txt:
        * storage/indexeddb/duplicates.html:
        * storage/indexeddb/error-causes-abort-by-default-expected.txt: Copied from LayoutTests/storage/indexeddb/cursor-index-delete-expected.txt.
        * storage/indexeddb/error-causes-abort-by-default.html: Added.
        * storage/indexeddb/index-basics-expected.txt:
        * storage/indexeddb/index-basics.html:
        * storage/indexeddb/objectstore-autoincrement-expected.txt:
        * storage/indexeddb/objectstore-autoincrement.html:
        * storage/indexeddb/objectstore-basics-expected.txt:
        * storage/indexeddb/objectstore-basics.html:
2011-02-04  Jeremy Orlow  <jorlow@chromium.org>

        Reviewed by Nate Chapin.

        First step towards event propogation within IndexedDB
        https://bugs.webkit.org/show_bug.cgi?id=53795

        This is the first step towards implementing
        http://www.w3.org/Bugs/Public/show_bug.cgi?id=11348
        within IndexedDB. I've created a method that knows how
        to capture and bubble (based on Node's dispatchGenericEvent).
        I've then changed IDBRequest to use it.

        The only functional change is that preventDefault now must
        be called in error events to prevent the transaction from
        being aborted. The tests reflect this change and there's one
        specific test to look at this behavior.

        Test: storage/indexeddb/error-causes-abort-by-default.html

        * storage/IDBAbortEvent.cpp:
        (WebCore::IDBAbortEvent::create):
        (WebCore::IDBAbortEvent::IDBAbortEvent):
        * storage/IDBAbortEvent.h:
        * storage/IDBCompleteEvent.cpp:
        (WebCore::IDBCompleteEvent::create):
        (WebCore::IDBCompleteEvent::IDBCompleteEvent):
        * storage/IDBCompleteEvent.h:
        * storage/IDBErrorEvent.cpp:
        (WebCore::IDBErrorEvent::IDBErrorEvent):
        * storage/IDBEvent.cpp:
        (WebCore::IDBEvent::IDBEvent):
        (WebCore::IDBEvent::dispatch):
        * storage/IDBEvent.h:
        * storage/IDBRequest.cpp:
        (WebCore::IDBRequest::dispatchEvent):
        * storage/IDBRequest.h:
        * storage/IDBSuccessEvent.cpp:
        (WebCore::IDBSuccessEvent::IDBSuccessEvent):
        * storage/IDBTransaction.cpp:
        (WebCore::IDBTransaction::onAbort):
        (WebCore::IDBTransaction::onComplete):
        * storage/IDBTransaction.h:
        (WebCore::IDBTransaction::backend):
        * storage/IDBTransactionBackendImpl.cpp:
        (WebCore::IDBTransactionBackendImpl::taskTimerFired):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@77688 268f45cc-cd09-0410-ab3c-d52691b4dbfc

31 files changed:
LayoutTests/ChangeLog
LayoutTests/storage/indexeddb/cursor-index-delete-expected.txt
LayoutTests/storage/indexeddb/cursor-index-delete.html
LayoutTests/storage/indexeddb/cursor-update-expected.txt
LayoutTests/storage/indexeddb/cursor-update.html
LayoutTests/storage/indexeddb/database-quota-expected.txt
LayoutTests/storage/indexeddb/database-quota.html
LayoutTests/storage/indexeddb/duplicates-expected.txt
LayoutTests/storage/indexeddb/duplicates.html
LayoutTests/storage/indexeddb/error-causes-abort-by-default-expected.txt [new file with mode: 0644]
LayoutTests/storage/indexeddb/error-causes-abort-by-default.html [new file with mode: 0644]
LayoutTests/storage/indexeddb/index-basics-expected.txt
LayoutTests/storage/indexeddb/index-basics.html
LayoutTests/storage/indexeddb/objectstore-autoincrement-expected.txt
LayoutTests/storage/indexeddb/objectstore-autoincrement.html
LayoutTests/storage/indexeddb/objectstore-basics-expected.txt
LayoutTests/storage/indexeddb/objectstore-basics.html
Source/WebCore/ChangeLog
Source/WebCore/storage/IDBAbortEvent.cpp
Source/WebCore/storage/IDBAbortEvent.h
Source/WebCore/storage/IDBCompleteEvent.cpp
Source/WebCore/storage/IDBCompleteEvent.h
Source/WebCore/storage/IDBErrorEvent.cpp
Source/WebCore/storage/IDBEvent.cpp
Source/WebCore/storage/IDBEvent.h
Source/WebCore/storage/IDBRequest.cpp
Source/WebCore/storage/IDBRequest.h
Source/WebCore/storage/IDBSuccessEvent.cpp
Source/WebCore/storage/IDBTransaction.cpp
Source/WebCore/storage/IDBTransaction.h
Source/WebCore/storage/IDBTransactionBackendImpl.cpp

index 9aae4649de287971370f83bf7e3f2d7cc0fc54ea..e3aaa743d210670d00f508c2c3419f8ae132844f 100644 (file)
@@ -1,3 +1,36 @@
+2011-02-04  Jeremy Orlow  <jorlow@chromium.org>
+
+        Reviewed by Nate Chapin.
+
+        First step towards event propogation within IndexedDB
+        https://bugs.webkit.org/show_bug.cgi?id=53795
+
+        This is the first step towards implementing
+        http://www.w3.org/Bugs/Public/show_bug.cgi?id=11348
+        within IndexedDB. I've created a method that knows how
+        to capture and bubble (based on Node's dispatchGenericEvent).
+        I've then changed IDBRequest to use it.
+
+        The only functional change is that preventDefault now must
+        be called in error events to prevent the transaction from
+        being aborted. The tests reflect this change and there's one
+        specific test to look at this behavior.
+
+        * storage/indexeddb/cursor-index-delete-expected.txt:
+        * storage/indexeddb/cursor-index-delete.html:
+        * storage/indexeddb/database-quota-expected.txt:
+        * storage/indexeddb/database-quota.html:
+        * storage/indexeddb/duplicates-expected.txt:
+        * storage/indexeddb/duplicates.html:
+        * storage/indexeddb/error-causes-abort-by-default-expected.txt: Copied from LayoutTests/storage/indexeddb/cursor-index-delete-expected.txt.
+        * storage/indexeddb/error-causes-abort-by-default.html: Added.
+        * storage/indexeddb/index-basics-expected.txt:
+        * storage/indexeddb/index-basics.html:
+        * storage/indexeddb/objectstore-autoincrement-expected.txt:
+        * storage/indexeddb/objectstore-autoincrement.html:
+        * storage/indexeddb/objectstore-basics-expected.txt:
+        * storage/indexeddb/objectstore-basics.html:
+
 2011-02-04  Dimitri Glazkov  <dglazkov@chromium.org>
 
         [Chromium] Remove Chromium-specific baselines that we no longer need.
index 8805c0eaa0b732cb9e88610eec2c73419cecddba..a477a2589e641574a831b781659f31b0c9372d63 100644 (file)
@@ -128,6 +128,7 @@ PASS 'onerror' in event.target is true
 PASS 'readyState' in event.target is true
 PASS event.target.readyState is event.target.DONE
 
+event.preventDefault()
 PASS successfullyParsed is true
 
 TEST COMPLETE
index c3de434dc1aed6909c80bb2048c1bafc188132bb..852a7eb1d95d158789aaac160b44d55163ffab82 100644 (file)
@@ -126,6 +126,7 @@ function deleteObject()
 function verifyObjectDeleted()
 {
     verifyErrorEvent(event);
+    evalAndLog("event.preventDefault()");
     done();
 }
 
index 87d3bca30a50c07bf744dfb5df244275f81cb2c2..4f2e659a4b279bef08f95b6b489e46ea49f223e1 100644 (file)
@@ -169,6 +169,7 @@ PASS 'readyState' in event.target is true
 PASS event.target.readyState is event.target.DONE
 
 PASS event.code is webkitIDBDatabaseException.DATA_ERR
+event.preventDefault()
 event.source.update({id: counter, number: 100 + counter++})
 event.source.continue()
 keyPathUpdateCursor()
@@ -185,6 +186,7 @@ PASS 'readyState' in event.target is true
 PASS event.target.readyState is event.target.DONE
 
 PASS event.code is webkitIDBDatabaseException.DATA_ERR
+event.preventDefault()
 event.source.update({id: counter, number: 100 + counter++})
 event.source.continue()
 keyPathUpdateCursor()
@@ -201,6 +203,7 @@ PASS 'readyState' in event.target is true
 PASS event.target.readyState is event.target.DONE
 
 PASS event.code is webkitIDBDatabaseException.DATA_ERR
+event.preventDefault()
 event.source.update({id: counter, number: 100 + counter++})
 event.source.continue()
 keyPathUpdateCursor()
@@ -217,6 +220,7 @@ PASS 'readyState' in event.target is true
 PASS event.target.readyState is event.target.DONE
 
 PASS event.code is webkitIDBDatabaseException.DATA_ERR
+event.preventDefault()
 event.source.update({id: counter, number: 100 + counter++})
 event.source.continue()
 keyPathUpdateCursor()
index edc01e7e5c1dc3a1e2b0158872157a9cef94ec6c..0a80b849d0581921e34a93900d4758dbf3443457 100644 (file)
@@ -183,6 +183,8 @@ function keyPathUpdateCursor()
         verifyErrorEvent(event);
         shouldBe("event.code", "webkitIDBDatabaseException.DATA_ERR");
 
+        evalAndLog("event.preventDefault()");
+
         result = evalAndLog("event.source.update({id: counter, number: 100 + counter++})");
         result.onsuccess = function() { evalAndLog("event.source.continue()") };
         result.onerror = unexpectedErrorCallback;
index e02ad64f95dcd3fd95b6525b5a150beeceacddfd..876d4129aba13e56115cbef84ed7dc028aa7a1fc 100644 (file)
@@ -80,6 +80,7 @@ PASS 'onerror' in event.target is true
 PASS 'readyState' in event.target is true
 PASS event.target.readyState is event.target.DONE
 
+event.preventDefault()
 PASS Adding data failed due to quota error. Data added was about 5 MB
 PASS successfullyParsed is true
 
index 68dfbded7c44c98fc275e45d45d4fbed093f185c..b447505c3aff049973d7dc6021917fb17b2977b3 100644 (file)
@@ -107,6 +107,7 @@ function logError()
 {
     debug("Error function called: (" + event.code + ") " + event.message);
     verifyErrorEvent(event);
+    evalAndLog("event.preventDefault()");
 }
 
 function testComplete()
index 8de488c7f84955dbf49b926f77f183d0beaca6f7..551b0bb9d8c939b0da4579788a5ae46da8457497 100644 (file)
@@ -133,6 +133,7 @@ PASS 'readyState' in event.target is true
 PASS event.target.readyState is event.target.DONE
 
 PASS event.code is webkitIDBDatabaseException.NOT_FOUND_ERR
+event.preventDefault()
 indexObject.get('does not exist')
 PASS 'onsuccess' in result is true
 PASS 'onerror' in result is true
@@ -151,6 +152,7 @@ PASS 'readyState' in event.target is true
 PASS event.target.readyState is event.target.DONE
 
 PASS event.code is webkitIDBDatabaseException.NOT_FOUND_ERR
+event.preventDefault()
 indexObject.openKeyCursor()
 PASS 'onsuccess' in result is true
 PASS 'onerror' in result is true
@@ -399,6 +401,7 @@ PASS 'readyState' in event.target is true
 PASS event.target.readyState is event.target.DONE
 
 PASS event.code is webkitIDBDatabaseException.NOT_FOUND_ERR
+event.preventDefault()
 indexObject.get('does not exist')
 PASS 'onsuccess' in result is true
 PASS 'onerror' in result is true
@@ -417,6 +420,7 @@ PASS 'readyState' in event.target is true
 PASS event.target.readyState is event.target.DONE
 
 PASS event.code is webkitIDBDatabaseException.NOT_FOUND_ERR
+event.preventDefault()
 indexObject.openKeyCursor()
 PASS 'onsuccess' in result is true
 PASS 'onerror' in result is true
index 352367fe218b18beff451b36a4d3c132b8b1ad21..cdfdcaa1758a7bea293f99d8e2306b8353430a6a 100644 (file)
@@ -111,6 +111,8 @@ function getObjectDataFail()
     verifyErrorEvent(event);
     shouldBe("event.code", "webkitIDBDatabaseException.NOT_FOUND_ERR");
 
+    evalAndLog("event.preventDefault()");
+
     result = evalAndLog("indexObject.get('does not exist')");
     verifyResult(result);
     result.onsuccess = unexpectedSuccessCallback;
@@ -122,6 +124,8 @@ function openKeyCursor()
     verifyErrorEvent(event);
     shouldBe("event.code", "webkitIDBDatabaseException.NOT_FOUND_ERR");
 
+    evalAndLog("event.preventDefault()");
+
     window.result = evalAndLog("indexObject.openKeyCursor()");
     verifyResult(result);
     result.onsuccess = cursor1Continue;
diff --git a/LayoutTests/storage/indexeddb/error-causes-abort-by-default-expected.txt b/LayoutTests/storage/indexeddb/error-causes-abort-by-default-expected.txt
new file mode 100644 (file)
index 0000000..dd8fd61
--- /dev/null
@@ -0,0 +1,107 @@
+Verify that a transaction with an error aborts unless preventDefault() is called.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+webkitIndexedDB.open('name')
+PASS 'onsuccess' in result is true
+PASS 'onerror' in result is true
+PASS 'readyState' in result is true
+An event should fire shortly...
+
+Success event fired:
+PASS 'result' in event is true
+PASS 'code' in event is false
+PASS 'message' in event is false
+PASS 'source' in event is true
+PASS event.source != null is true
+PASS 'onsuccess' in event.target is true
+PASS 'onerror' in event.target is true
+PASS 'readyState' in event.target is true
+PASS event.target.readyState is event.target.DONE
+
+db = event.result
+db.setVersion('new version')
+PASS 'onsuccess' in result is true
+PASS 'onerror' in result is true
+PASS 'readyState' in result is true
+An event should fire shortly...
+
+setVersionSuccess():
+Success event fired:
+PASS 'result' in event is true
+PASS 'code' in event is false
+PASS 'message' in event is false
+PASS 'source' in event is true
+PASS event.source != null is true
+PASS 'onsuccess' in event.target is true
+PASS 'onerror' in event.target is true
+PASS 'readyState' in event.target is true
+PASS event.target.readyState is event.target.DONE
+
+trans = event.result
+PASS trans !== null is true
+trans.oncomplete = addData
+Deleted all object stores.
+db.createObjectStore('storeName', null)
+trans = db.transaction([], webkitIDBTransaction.READ_WRITE)
+trans.onabort = unexpectedAbortCallback
+trans.oncomplete = transactionCompleted
+store = trans.objectStore('storeName')
+store.add({x: 'value', y: 'zzz'}, 'key')
+PASS 'onsuccess' in result is true
+PASS 'onerror' in result is true
+PASS 'readyState' in result is true
+An event should fire shortly...
+
+Success event fired:
+PASS 'result' in event is true
+PASS 'code' in event is false
+PASS 'message' in event is false
+PASS 'source' in event is true
+PASS event.source != null is true
+PASS 'onsuccess' in event.target is true
+PASS 'onerror' in event.target is true
+PASS 'readyState' in event.target is true
+PASS event.target.readyState is event.target.DONE
+
+event.source.add({x: 'value', y: 'zzz'}, 'key')
+PASS 'onsuccess' in result is true
+PASS 'onerror' in result is true
+PASS 'readyState' in result is true
+An event should fire shortly...
+
+event.preventDefault()
+PASS Transaction completed
+
+
+trans = db.transaction([], webkitIDBTransaction.READ_WRITE)
+trans.onabort = transactionAborted1
+trans.oncomplete = unexpectedCompleteCallback
+store = trans.objectStore('storeName')
+store.add({x: 'value', y: 'zzz'}, 'key')
+PASS 'onsuccess' in result is true
+PASS 'onerror' in result is true
+PASS 'readyState' in result is true
+An event should fire shortly...
+
+Doing nothing to prevent the default action...
+PASS Transaction aborted
+
+
+trans = db.transaction([], webkitIDBTransaction.READ_WRITE)
+trans.onabort = transactionAborted2
+trans.oncomplete = unexpectedCompleteCallback
+store = trans.objectStore('storeName')
+store.add({x: 'value', y: 'zzz'}, 'key')
+PASS 'onsuccess' in result is true
+PASS 'onerror' in result is true
+PASS 'readyState' in result is true
+An event should fire shortly...
+
+Omitting an onerror handler
+PASS Transaction aborted
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/storage/indexeddb/error-causes-abort-by-default.html b/LayoutTests/storage/indexeddb/error-causes-abort-by-default.html
new file mode 100644 (file)
index 0000000..ab4c58a
--- /dev/null
@@ -0,0 +1,127 @@
+<html>
+<head>
+<link rel="stylesheet" href="../../fast/js/resources/js-test-style.css">
+<script src="../../fast/js/resources/js-test-pre.js"></script>
+<script src="../../fast/js/resources/js-test-post-function.js"></script>
+<script src="resources/shared.js"></script>
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<script>
+
+description("Verify that a transaction with an error aborts unless preventDefault() is called.");
+if (window.layoutTestController) 
+    layoutTestController.waitUntilDone();
+
+function test()
+{
+    result = evalAndLog("webkitIndexedDB.open('name')");
+    verifyResult(result);
+    result.onsuccess = setVersion;
+    result.onerror = unexpectedErrorCallback;
+}
+
+function setVersion()
+{
+    verifySuccessEvent(event);
+    db = evalAndLog("db = event.result");
+
+    result = evalAndLog("db.setVersion('new version')");
+    verifyResult(result);
+    result.onsuccess = deleteExisting;
+    result.onerror = unexpectedErrorCallback;
+}
+
+function deleteExisting()
+{
+    debug("setVersionSuccess():");
+    verifySuccessEvent(event);
+    window.trans = evalAndLog("trans = event.result");
+    shouldBeTrue("trans !== null");
+    trans.onabort = unexpectedAbortCallback;
+    evalAndLog("trans.oncomplete = addData");
+
+    deleteAllObjectStores(db, createObjectStore);
+}
+
+function createObjectStore()
+{
+    evalAndLog("db.createObjectStore('storeName', null)");
+}
+
+function addData()
+{
+    trans = evalAndLog("trans = db.transaction([], webkitIDBTransaction.READ_WRITE)");
+    evalAndLog("trans.onabort = unexpectedAbortCallback");
+    evalAndLog("trans.oncomplete = transactionCompleted");
+    store = evalAndLog("store = trans.objectStore('storeName')");
+    result = evalAndLog("store.add({x: 'value', y: 'zzz'}, 'key')");
+    verifyResult(result);
+    result.onsuccess = addMore;
+    result.onerror = unexpectedErrorCallback;
+}
+
+function addMore()
+{
+    verifySuccessEvent(event);
+
+    result = evalAndLog("event.source.add({x: 'value', y: 'zzz'}, 'key')");
+    verifyResult(result);
+    result.onsuccess = unexpectedSuccessCallback;
+    result.addEventListener("error", preventTheDefault);
+}
+
+function preventTheDefault()
+{
+    evalAndLog("event.preventDefault()");
+}
+
+function transactionCompleted()
+{
+    testPassed("Transaction completed");
+    debug("");
+    debug("");
+    trans = evalAndLog("trans = db.transaction([], webkitIDBTransaction.READ_WRITE)");
+    evalAndLog("trans.onabort = transactionAborted1");
+    evalAndLog("trans.oncomplete = unexpectedCompleteCallback");
+    store = evalAndLog("store = trans.objectStore('storeName')");
+    result = evalAndLog("store.add({x: 'value', y: 'zzz'}, 'key')");
+    verifyResult(result);
+    result.onsuccess = unexpectedSuccessCallback;
+    result.onerror = allowDefault;
+}
+
+function allowDefault()
+{
+    debug("Doing nothing to prevent the default action...");
+}
+
+function transactionAborted1()
+{
+    testPassed("Transaction aborted");
+    debug("");
+    debug("");
+    trans = evalAndLog("trans = db.transaction([], webkitIDBTransaction.READ_WRITE)");
+    evalAndLog("trans.onabort = transactionAborted2");
+    evalAndLog("trans.oncomplete = unexpectedCompleteCallback");
+    store = evalAndLog("store = trans.objectStore('storeName')");
+    result = evalAndLog("store.add({x: 'value', y: 'zzz'}, 'key')");
+    verifyResult(result);
+    result.onsuccess = unexpectedSuccessCallback;
+    debug("Omitting an onerror handler");
+}
+
+function transactionAborted2()
+{
+    testPassed("Transaction aborted");
+    done();
+}
+
+test();
+
+var successfullyParsed = true;
+
+</script>
+</body>
+</html>
index 099dde31c445aa78799d84633e5a9f4645aa0237..d18a09aa7b0e605083c896c6983da49e85e01d22 100644 (file)
@@ -183,6 +183,7 @@ PASS 'readyState' in event.target is true
 PASS event.target.readyState is event.target.DONE
 
 PASS event.code is webkitIDBDatabaseException.NOT_FOUND_ERR
+event.preventDefault()
 indexObject.get('does not exist')
 PASS 'onsuccess' in result is true
 PASS 'onerror' in result is true
@@ -201,6 +202,7 @@ PASS 'readyState' in event.target is true
 PASS event.target.readyState is event.target.DONE
 
 PASS event.code is webkitIDBDatabaseException.NOT_FOUND_ERR
+event.preventDefault()
 indexObject.openKeyCursor()
 PASS 'onsuccess' in result is true
 PASS 'onerror' in result is true
index d5eec0a6d775ed4363978c2082572a71cc77108b..863566ac2997bbe51dc1ba1a40da33e2a21acb69 100644 (file)
@@ -144,6 +144,8 @@ function getObjectDataFail()
     verifyErrorEvent(event);
     shouldBe("event.code", "webkitIDBDatabaseException.NOT_FOUND_ERR");
 
+    evalAndLog("event.preventDefault()");
+
     result = evalAndLog("indexObject.get('does not exist')");
     verifyResult(result);
     result.onsuccess = unexpectedSuccessCallback;
@@ -155,6 +157,8 @@ function openKeyCursor()
     verifyErrorEvent(event);
     shouldBe("event.code", "webkitIDBDatabaseException.NOT_FOUND_ERR");
 
+    evalAndLog("event.preventDefault()");
+
     window.result = evalAndLog("indexObject.openKeyCursor()");
     verifyResult(result);
     result.onsuccess = cursor1Continue;
index 6a7c366ac6fa12f7ed8b8e25b98536fb98552e85..b8587a31fe8051c36fe5c3a236adf79778df502d 100644 (file)
@@ -72,6 +72,7 @@ PASS 'readyState' in event.target is true
 PASS event.target.readyState is event.target.DONE
 
 PASS event.code is webkitIDBDatabaseException.UNKNOWN_ERR
+event.preventDefault()
 store = trans.objectStore('StoreWithAutoIncrement')
 Insert into object store with key gen using explicit key
 store.add({name: 'Lincoln'}, 1)
@@ -88,6 +89,7 @@ PASS 'readyState' in event.target is true
 PASS event.target.readyState is event.target.DONE
 
 PASS event.code is webkitIDBDatabaseException.DATA_ERR
+event.preventDefault()
 Insert into object store with key gen and no key path
 store.add({name: 'Lincoln', number: '7012'})
 addLincolnSuccess():
@@ -163,6 +165,7 @@ PASS 'readyState' in event.target is true
 PASS event.target.readyState is event.target.DONE
 
 PASS event.code is webkitIDBDatabaseException.DATA_ERR
+event.preventDefault()
 store.add({name: 'Adam'}, 1)
 addAdamSuccess():
 Success event fired:
index 3084496acc141eb98a946a2dbbd2cb2e1b44659f..39cf8b5b106f777e9f659068eef382b8408709c8 100644 (file)
@@ -87,6 +87,8 @@ function addLincolnError()
     // FIXME: This should be implemented, but we make it an error for now.
     shouldBe("event.code", "webkitIDBDatabaseException.UNKNOWN_ERR");
 
+    evalAndLog("event.preventDefault()");
+
     window.store = evalAndLog("store = trans.objectStore('StoreWithAutoIncrement')");
     debug("Insert into object store with key gen using explicit key");
     result = evalAndLog("store.add({name: 'Lincoln'}, 1)");
@@ -100,6 +102,8 @@ function addWithExplicitKeyError()
     verifyErrorEvent(event);
     shouldBe("event.code", "webkitIDBDatabaseException.DATA_ERR");
 
+    evalAndLog("event.preventDefault()");
+
     debug("Insert into object store with key gen and no key path");
     result = evalAndLog("store.add({name: 'Lincoln', number: '7012'})");
     result.onsuccess = addLincolnSuccess;
@@ -160,6 +164,8 @@ function addAdamError()
     verifyErrorEvent(event);
     shouldBe("event.code", "webkitIDBDatabaseException.DATA_ERR");
 
+    evalAndLog("event.preventDefault()");
+
     result = evalAndLog("store.add({name: 'Adam'}, 1)");
     result.onsuccess = addAdamSuccess;
     result.onerror = unexpectedErrorCallback;
index 5eef942fffcf1f80579bbca49bb15f1b708920b4..cfbdbbfb068000cb2ccad3b1a61e458512e457d8 100644 (file)
@@ -137,6 +137,7 @@ PASS 'readyState' in event.target is true
 PASS event.target.readyState is event.target.DONE
 
 PASS event.code is webkitIDBDatabaseException.UNKNOWN_ERR
+event.preventDefault()
 db.transaction([], webkitIDBTransaction.READ_WRITE)
 store = transaction.objectStore('storeName')
 store.add({x: 'othervalue'}, null)
@@ -158,6 +159,7 @@ PASS 'readyState' in event.target is true
 PASS event.target.readyState is event.target.DONE
 
 PASS event.code is webkitIDBDatabaseException.DATA_ERR
+event.preventDefault()
 db.transaction([], webkitIDBTransaction.READ_WRITE)
 store = transaction.objectStore('storeName')
 store.add({x: null}, 'validkey')
@@ -179,6 +181,7 @@ PASS 'readyState' in event.target is true
 PASS event.target.readyState is event.target.DONE
 
 PASS event.code is webkitIDBDatabaseException.DATA_ERR
+event.preventDefault()
 db.transaction([], webkitIDBTransaction.READ_WRITE)
 store = transaction.objectStore('storeName')
 store.get('key')
index 82854fce5190aadf6143a5e095a5ee9fdcae7caf..deec7a3160c4b0c080254a109f66ff97f12d3148 100644 (file)
@@ -189,6 +189,8 @@ function addAgainFailure()
     // FIXME: This error code needs to be specced.
     shouldBe("event.code", "webkitIDBDatabaseException.UNKNOWN_ERR");
 
+    evalAndLog("event.preventDefault()");
+
     transaction = evalAndLog("db.transaction([], webkitIDBTransaction.READ_WRITE)");
     transaction.onabort = unexpectedErrorCallback;
     var store = evalAndLog("store = transaction.objectStore('storeName')");
@@ -205,6 +207,8 @@ function addWithNullKeyFailure()
     verifyErrorEvent(event);
     shouldBe("event.code", "webkitIDBDatabaseException.DATA_ERR");
 
+    evalAndLog("event.preventDefault()");
+
     transaction = evalAndLog("db.transaction([], webkitIDBTransaction.READ_WRITE)");
     transaction.onabort = unexpectedErrorCallback;
     var store = evalAndLog("store = transaction.objectStore('storeName')");
@@ -221,6 +225,8 @@ function addWithNullIndexFailure()
     verifyErrorEvent(event);
     shouldBe("event.code", "webkitIDBDatabaseException.DATA_ERR");
 
+    evalAndLog("event.preventDefault()");
+
     transaction = evalAndLog("db.transaction([], webkitIDBTransaction.READ_WRITE)");
     transaction.onabort = unexpectedErrorCallback;
     var store = evalAndLog("store = transaction.objectStore('storeName')");
index c530db6c5d88559d17f21300634dd702450dae7f..3a91e2d903adaaa637ab1fbafe3e6bd3c805a616 100644 (file)
@@ -1,3 +1,50 @@
+2011-02-04  Jeremy Orlow  <jorlow@chromium.org>
+
+        Reviewed by Nate Chapin.
+
+        First step towards event propogation within IndexedDB
+        https://bugs.webkit.org/show_bug.cgi?id=53795
+
+        This is the first step towards implementing
+        http://www.w3.org/Bugs/Public/show_bug.cgi?id=11348
+        within IndexedDB. I've created a method that knows how
+        to capture and bubble (based on Node's dispatchGenericEvent).
+        I've then changed IDBRequest to use it.
+
+        The only functional change is that preventDefault now must
+        be called in error events to prevent the transaction from
+        being aborted. The tests reflect this change and there's one
+        specific test to look at this behavior.
+
+        Test: storage/indexeddb/error-causes-abort-by-default.html
+
+        * storage/IDBAbortEvent.cpp:
+        (WebCore::IDBAbortEvent::create):
+        (WebCore::IDBAbortEvent::IDBAbortEvent):
+        * storage/IDBAbortEvent.h:
+        * storage/IDBCompleteEvent.cpp:
+        (WebCore::IDBCompleteEvent::create):
+        (WebCore::IDBCompleteEvent::IDBCompleteEvent):
+        * storage/IDBCompleteEvent.h:
+        * storage/IDBErrorEvent.cpp:
+        (WebCore::IDBErrorEvent::IDBErrorEvent):
+        * storage/IDBEvent.cpp:
+        (WebCore::IDBEvent::IDBEvent):
+        (WebCore::IDBEvent::dispatch):
+        * storage/IDBEvent.h:
+        * storage/IDBRequest.cpp:
+        (WebCore::IDBRequest::dispatchEvent):
+        * storage/IDBRequest.h:
+        * storage/IDBSuccessEvent.cpp:
+        (WebCore::IDBSuccessEvent::IDBSuccessEvent):
+        * storage/IDBTransaction.cpp:
+        (WebCore::IDBTransaction::onAbort):
+        (WebCore::IDBTransaction::onComplete):
+        * storage/IDBTransaction.h:
+        (WebCore::IDBTransaction::backend):
+        * storage/IDBTransactionBackendImpl.cpp:
+        (WebCore::IDBTransactionBackendImpl::taskTimerFired):
+
 2011-02-04  Daniel Cheng  <dcheng@chromium.org>
 
         Reviewed by Dmitry Titov.
index 21760f893f0739a3c27278abd9e612b910bd1598..980d656f35ce731b7e8f89f821f2fea57c51795d 100644 (file)
 
 namespace WebCore {
 
-PassRefPtr<IDBAbortEvent> IDBAbortEvent::create()
+PassRefPtr<IDBAbortEvent> IDBAbortEvent::create(PassRefPtr<IDBAny> source)
 {
-    return adoptRef(new IDBAbortEvent());
+    return adoptRef(new IDBAbortEvent(source));
 }
 
-IDBAbortEvent::IDBAbortEvent()
-    : IDBEvent(eventNames().abortEvent, 0) // FIXME: set the source to the transaction
+IDBAbortEvent::IDBAbortEvent(PassRefPtr<IDBAny> source)
+    : IDBEvent(eventNames().abortEvent, source, true)
 {
 }
 
index bdc22024396a850ec0d50ebbea9c47e20005113d..fc27989c0acb33f9a46c0c705ca9afd82188bcc1 100644 (file)
@@ -40,14 +40,14 @@ namespace WebCore {
 
 class IDBAbortEvent : public IDBEvent {
 public:
-    static PassRefPtr<IDBAbortEvent> create();
+    static PassRefPtr<IDBAbortEvent> create(PassRefPtr<IDBAny> source);
     // FIXME: Need to allow creation of these events from JS.
     virtual ~IDBAbortEvent();
 
     virtual bool isIDBAbortEvent() const { return true; }
 
 private:
-    IDBAbortEvent();
+    IDBAbortEvent(PassRefPtr<IDBAny> source);
 };
 
 } // namespace WebCore
index f0ad9fc518dfbb0a5b6833d11934de2e6e793d40..20ee57adf78ffbb2c3f730402e190a37744d4680 100644 (file)
 
 namespace WebCore {
 
-PassRefPtr<IDBCompleteEvent> IDBCompleteEvent::create()
+PassRefPtr<IDBCompleteEvent> IDBCompleteEvent::create(PassRefPtr<IDBAny> source)
 {
-    return adoptRef(new IDBCompleteEvent());
+    return adoptRef(new IDBCompleteEvent(source));
 }
 
-IDBCompleteEvent::IDBCompleteEvent()
-    : IDBEvent(eventNames().completeEvent, 0) // FIXME: set the source to the transaction
+IDBCompleteEvent::IDBCompleteEvent(PassRefPtr<IDBAny> source)
+    : IDBEvent(eventNames().completeEvent, source, false)
 {
 }
 
index c407096b7c0b6abcc3f66aee4670d0606df27ac5..c004a72d0c179cccc3e9664c4c46532f9efe705a 100644 (file)
@@ -40,14 +40,14 @@ namespace WebCore {
 
 class IDBCompleteEvent : public IDBEvent {
 public:
-    static PassRefPtr<IDBCompleteEvent> create();
+    static PassRefPtr<IDBCompleteEvent> create(PassRefPtr<IDBAny> source);
     // FIXME: Need to allow creation of these events from JS.
     virtual ~IDBCompleteEvent();
 
     virtual bool isIDBCompleteEvent() const { return true; }
 
 private:
-    IDBCompleteEvent();
+    IDBCompleteEvent(PassRefPtr<IDBAny> source);
 };
 
 } // namespace WebCore
index cba980d69962f22081eca122be6a4a1cc8e96069..e576fa87fdd6534ae630e600ed12cd164df8e1ea 100644 (file)
@@ -43,7 +43,7 @@ PassRefPtr<IDBErrorEvent> IDBErrorEvent::create(PassRefPtr<IDBAny> source, const
 }
 
 IDBErrorEvent::IDBErrorEvent(PassRefPtr<IDBAny> source, const IDBDatabaseError& error)
-    : IDBEvent(eventNames().errorEvent, source)
+    : IDBEvent(eventNames().errorEvent, source, true)
     , m_code(error.code())
     , m_message(error.message())
 {
index f9f60606a14739ebd66565d37a9a626f817247d3..a7f3db107c125cde03ef78ac34e2624050303f04 100644 (file)
@@ -35,8 +35,8 @@
 
 namespace WebCore {
 
-IDBEvent::IDBEvent(const AtomicString& type, PassRefPtr<IDBAny> source)
-    : Event(type, false, false)
+IDBEvent::IDBEvent(const AtomicString& type, PassRefPtr<IDBAny> source, bool canBubble)
+    : Event(type, canBubble, true)
     , m_source(source)
 {
 }
@@ -50,6 +50,57 @@ PassRefPtr<IDBAny> IDBEvent::source()
     return m_source;
 }
 
+bool IDBEvent::dispatch(Vector<RefPtr<EventTarget> >& eventTargets)
+{
+    size_t size = eventTargets.size();
+    ASSERT(size);
+
+    setEventPhase(Event::CAPTURING_PHASE);
+    for (size_t i = size - 1; i; --i) { // Don't do the first element.
+        setCurrentTarget(eventTargets[i].get());
+        eventTargets[i]->fireEventListeners(this);
+        if (propagationStopped())
+            goto doneDispatching;
+    }
+
+    setEventPhase(Event::AT_TARGET);
+    setCurrentTarget(eventTargets[0].get());
+    eventTargets[0]->fireEventListeners(this);
+    if (propagationStopped() || !bubbles() || cancelBubble())
+        goto doneDispatching;
+
+    setEventPhase(Event::BUBBLING_PHASE);
+    for (size_t i = 1; i < size; ++i) { // Don't do the first element.
+        setCurrentTarget(eventTargets[i].get());
+        eventTargets[i]->fireEventListeners(this);
+        if (propagationStopped() || cancelBubble())
+            goto doneDispatching;
+    }
+
+    // FIXME: "...However, we also wanted to integrate the window.onerror feature in
+    //        HTML5. So after we've fired an "error" event, if .preventDefault() was
+    //        never called on the event, we fire an error event on the window (can't
+    //        remember if this happens before or after we abort the transaction).
+    //        This is a separate event, which for example means that even if you
+    //        attach a capturing "error" handler on window, you won't see any events
+    //        unless an error really went unhandled. And you also can't call
+    //        .preventDefault on the error event fired on the window in order to
+    //        prevent the transaction from being aborted. It's purely there for
+    //        error reporting and distinctly different from the event propagating to
+    //        the window.
+    //        
+    //        This is similar to how "error" events are handled in workers.
+    //        
+    //        (I think that so far webkit hasn't implemented the window.onerror
+    //        feature yet, so you probably don't want to fire the separate error
+    //        event on the window until that has been implemented)."
+
+doneDispatching:
+    setCurrentTarget(0);
+    setEventPhase(0);
+    return !defaultPrevented();
+}
+
 } // namespace WebCore
 
 #endif
index c44e449a5f28727781a48e8fa78733f593d41cef..d28885be5ca398eac8fca54fc386aa4dd99d02a3 100644 (file)
 #if ENABLE(INDEXED_DATABASE)
 
 #include "Event.h"
+#include "EventTarget.h"
 #include <wtf/PassRefPtr.h>
 #include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
 
 namespace WebCore {
 
@@ -44,9 +46,10 @@ public:
     virtual ~IDBEvent();
 
     PassRefPtr<IDBAny> source();
+    bool dispatch(Vector<RefPtr<EventTarget> >&); // The target first and then its ancestors in order of how the event bubbles.
 
 protected:
-    IDBEvent(const AtomicString& type, PassRefPtr<IDBAny> source);
+    IDBEvent(const AtomicString& type, PassRefPtr<IDBAny> source, bool canBubble);
 
 private:
     RefPtr<IDBAny> m_source;
index a3a04f26ff0a921819d3269a144436bba2292442..f45c43734022d9adeacbe2155bd077de8b377fbb 100644 (file)
@@ -139,12 +139,19 @@ bool IDBRequest::dispatchEvent(PassRefPtr<Event> event)
     ASSERT(m_readyState < DONE);
     m_readyState = DONE;
 
-    bool ret = EventTarget::dispatchEvent(event);
-
-    if (m_transaction)
+    Vector<RefPtr<EventTarget> > targets;
+    targets.append(this);
+    ASSERT(event->target() == this);
+    ASSERT(event->isIDBErrorEvent() || event->isIDBSuccessEvent());
+    bool dontPreventDefault = static_cast<IDBEvent*>(event.get())->dispatch(targets);
+
+    if (m_transaction) {
+        if (dontPreventDefault && event->isIDBErrorEvent())
+            m_transaction->abort();
         m_transaction->didCompleteTaskEvents();
+    }
 
-    return ret;
+    return dontPreventDefault;
 }
 
 void IDBRequest::enqueueEvent(PassRefPtr<Event> event)
index 7a049eea5d67b4427e9d2730214149e595b5fd9f..849eb9ad1e4ceafb3df1c7984b0038bced5f51c3 100644 (file)
@@ -41,6 +41,7 @@
 
 namespace WebCore {
 
+class IDBEvent;
 class IDBTransactionBackendInterface;
 
 class IDBRequest : public IDBCallbacks, public EventTarget, public ActiveDOMObject {
index 2dcd964bab0d048c18f2448db94b6e4d5e60f972..110b78b094c3219227a0f19daab7fb12fe07cfc9 100644 (file)
@@ -42,7 +42,7 @@ PassRefPtr<IDBSuccessEvent> IDBSuccessEvent::create(PassRefPtr<IDBAny> source, P
 }
 
 IDBSuccessEvent::IDBSuccessEvent(PassRefPtr<IDBAny> source, PassRefPtr<IDBAny> result)
-    : IDBEvent(eventNames().successEvent, source)
+    : IDBEvent(eventNames().successEvent, source, false)
     , m_result(result)
 {
 }
index 3b0aed9e0797430f7aae812075326f46dba8baea..b9e015503233a1cd6b920199fd9ca396fb05f57b 100644 (file)
@@ -100,12 +100,12 @@ ScriptExecutionContext* IDBTransaction::scriptExecutionContext() const
 
 void IDBTransaction::onAbort()
 {
-    enqueueEvent(IDBAbortEvent::create());
+    enqueueEvent(IDBAbortEvent::create(IDBAny::create(this)));
 }
 
 void IDBTransaction::onComplete()
 {
-    enqueueEvent(IDBCompleteEvent::create());
+    enqueueEvent(IDBCompleteEvent::create(IDBAny::create(this)));
 }
 
 bool IDBTransaction::canSuspend() const
index 7a62e29b7f83b289f8ada9b7cf879224cccc5290..3fdb9e52000c6c0d705119e551340e5711b7564c 100644 (file)
@@ -53,6 +53,8 @@ public:
         VERSION_CHANGE = 2
     };
 
+    IDBTransactionBackendInterface* backend() const { return m_backend.get(); }
+
     unsigned short mode() const;
     IDBDatabase* db();
     PassRefPtr<IDBObjectStore> objectStore(const String& name, ExceptionCode&);
index b47e7609f3a094c325298a4af951eb06ef60878a..1357838073dcfbf8e3ba64ed9a00a1ecc8eab3b8 100644 (file)
@@ -179,12 +179,12 @@ void IDBTransactionBackendImpl::taskTimerFired(Timer<IDBTransactionBackendImpl>*
     if (m_state == StartPending) {
         m_transaction->begin();
         m_state = Running;
-    } else
-        ASSERT(m_state == Running);
+    }
 
     TaskQueue queue;
     queue.swap(m_taskQueue);
     while (!queue.isEmpty() && m_state != Finished) {
+        ASSERT(m_state == Running);
         OwnPtr<ScriptExecutionContext::Task> task(queue.first().release());
         queue.removeFirst();
         m_pendingEvents++;