2011-02-04 Jeremy Orlow <jorlow@chromium.org>
authorjorlow@chromium.org <jorlow@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 4 Feb 2011 22:38:12 +0000 (22:38 +0000)
committerjorlow@chromium.org <jorlow@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 4 Feb 2011 22:38:12 +0000 (22:38 +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: https://svn.webkit.org/repository/webkit/trunk@77679 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 224f750..ce3785c 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] Updated Win and Linux baselines after r77665.
index 8805c0e..a477a25 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 c3de434..852a7eb 100644 (file)
@@ -126,6 +126,7 @@ function deleteObject()
 function verifyObjectDeleted()
 {
     verifyErrorEvent(event);
+    evalAndLog("event.preventDefault()");
     done();
 }
 
index 87d3bca..4f2e659 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 edc01e7..0a80b84 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 e02ad64..876d412 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 68dfbde..b447505 100644 (file)
@@ -107,6 +107,7 @@ function logError()
 {
     debug("Error function called: (" + event.code + ") " + event.message);
     verifyErrorEvent(event);
+    evalAndLog("event.preventDefault()");
 }
 
 function testComplete()
index 8de488c..551b0bb 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 352367f..cdfdcaa 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 099dde3..d18a09a 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 d5eec0a..863566a 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 6a7c366..b8587a3 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 3084496..39cf8b5 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 5eef942..cfbdbbf 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 82854fc..deec7a3 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 7a590fe..d3abb5e 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  Dimitri Glazkov  <dglazkov@chromium.org>
 
         Reviewed by Csaba Osztrogon√°c.
index 21760f8..980d656 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 bdc2202..fc27989 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 f0ad9fc..20ee57a 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 c407096..c004a72 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 cba980d..e576fa8 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 f9f6060..a7f3db1 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 c44e449..d28885b 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 a3a04f2..f45c437 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 7a049ee..849eb9a 100644 (file)
@@ -41,6 +41,7 @@
 
 namespace WebCore {
 
+class IDBEvent;
 class IDBTransactionBackendInterface;
 
 class IDBRequest : public IDBCallbacks, public EventTarget, public ActiveDOMObject {
index 2dcd964..110b78b 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 3b0aed9..b9e0155 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 7a62e29..3fdb9e5 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 b47e760..1357838 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++;