[SCM] WebKit Debian packaging branch, debian/experimental, updated. upstream/1.3.3-9427-gc2be6fc

jorlow at chromium.org jorlow at chromium.org
Wed Dec 22 14:57:41 UTC 2010


The following commit has been merged in the debian/experimental branch:
commit 63d9503794acbebee8db9d07ae19b24c8497d135
Author: jorlow at chromium.org <jorlow at chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Tue Oct 26 15:19:12 2010 +0000

    2010-10-26  Jeremy Orlow  <jorlow at chromium.org>
    
            Reviewed by Steve Block.
    
            Add IndexedDB test/tutorial
            https://bugs.webkit.org/show_bug.cgi?id=48067
    
            This document is useful in terms of demonstrating IndexedDB and
            documenting what we do and don't support currently, since I'll be
            maintaining it for at least some time.
    
            * storage/indexeddb/tutorial-expected.txt: Added.
            * storage/indexeddb/tutorial.html: Added.
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@70521 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 0d0dbcd..6ca1752 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,17 @@
+2010-10-26  Jeremy Orlow  <jorlow at chromium.org>
+
+        Reviewed by Steve Block.
+
+        Add IndexedDB test/tutorial
+        https://bugs.webkit.org/show_bug.cgi?id=48067
+
+        This document is useful in terms of demonstrating IndexedDB and
+        documenting what we do and don't support currently, since I'll be
+        maintaining it for at least some time.
+
+        * storage/indexeddb/tutorial-expected.txt: Added.
+        * storage/indexeddb/tutorial.html: Added.
+
 2010-10-26  Pavel Feldman  <pfeldman at chromium.org>
 
         Reviewed by Timothy Hatcher.
diff --git a/LayoutTests/storage/indexeddb/tutorial-expected.txt b/LayoutTests/storage/indexeddb/tutorial-expected.txt
new file mode 100644
index 0000000..1e424ef
--- /dev/null
+++ b/LayoutTests/storage/indexeddb/tutorial-expected.txt
@@ -0,0 +1,2 @@
+All done!
+
diff --git a/LayoutTests/storage/indexeddb/tutorial.html b/LayoutTests/storage/indexeddb/tutorial.html
new file mode 100644
index 0000000..2e7e41f
--- /dev/null
+++ b/LayoutTests/storage/indexeddb/tutorial.html
@@ -0,0 +1,433 @@
+<html><title>IndexedDB Tutorial</title>
+<script>
+
+// This is a tutorial that highlights many of the features of IndexedDB along witha number of
+// caveats that currently exist in Chromium/WebKit but which will hopefully be improved upon
+// over time.
+//
+// The latest version of the spec can be found here:
+// http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html but note that there are quite a
+// few bugs currently opened against it and some major unresolved issues (like whether dynamic
+// transactions should be in for v1). Many of the bugs are filed here:
+// http://www.w3.org/Bugs/Public/buglist.cgi?query_format=advanced&short_desc_type=allwordssubstr&short_desc=&component=Indexed+Database+API&longdesc_type=allwordssubstr&longdesc=&bug_file_loc_type=allwordssubstr&bug_file_loc=&status_whiteboard_type=allwordssubstr&status_whiteboard=&keywords_type=allwords&keywords=&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&emailtype1=substring&email1=&emailtype2=substring&email2=&bug_id_type=anyexact&bug_id=&votes=&chfieldfrom=&chfieldto=Now&chfieldvalue=&cmdtype=doit&order=Reuse+same+sort+as+last+time&known_name=IndexedDB&query_based_on=IndexedDB&field0-0-0=noop&type0-0-0=noop&value0-0-0=
+// Discussion happens on public-webapps at w3.org
+//
+// Although not user friendly, additional capabilities and example code can be found in the
+// tests for IndexedDB which are here:
+// http://trac.webkit.org/browser/trunk/LayoutTests/storage/indexeddb
+//
+// This document is currently maintained by Jeremy Orlow <jorlow at chromium.org>
+
+
+// This is not an ideal layout test since it doesn't verify things as thoroughly as it could,
+// but adding such content would make it much more cluttered and thus wouldn't serve its primary
+// goal of teaching people IndexedDB. That said, it does have a good amount of coverage and
+// serves as a living document describing what's expected to work and how within WebKit so it
+// seems well worth having checked in.
+if (window.layoutTestController)
+    layoutTestController.dumpAsText(true);
+
+
+function setup()
+{
+    // As this API is still experimental, it's being shipped behind vendor specific prefixes.
+    if ('webkitIndexedDB' in window) {
+        indexedDB = webkitIndexedDB;
+        IDBCursor = webkitIDBCursor;
+        IDBKeyRange = webkitIDBKeyRange;
+        IDBTransaction = webkitIDBTransaction;
+    }
+
+    // This tutorial assumes that Mozilla and WebKit match each other which isn't true at the
+    // moment, but we can hope it'll become true over time.
+    if ('moz_indexedDB' in window) {
+        indexedDB = moz_indexedDB;
+        // Not implemented by them yet. I'm just guessing what they'll be.
+        IDBCursor = moz_IDBCursor;
+        IDBKeyRange = moz_IDBKeyRange;
+        IDBTransaction = moz_IDBTransaction;
+    }
+}
+
+function log(txt)
+{
+    document.write(txt + "<br>");
+}
+
+function logError(txt)
+{
+    log("<font color=red>" + txt + "</font>");
+}
+
+function start()
+{
+    setup();
+
+    // This is an example of one of the many asynchronous commands in IndexedDB's async interface.
+    // Each returns an IDBRequest object which has "success" and "error" event handlers. You can use
+    // "addEventListener" if you'd like, but I'm using the simpler = syntax. Only one or the other
+    // will fire. You're guaranteed that they won't fire until control is returned from JavaScript
+    // execution.
+    var request = indexedDB.open("myDB", "This is a description of the database."); // Chromium/WebKit doesn't yet require the description, but it will soon.
+    request.onsuccess = onOpen;
+    request.onerror = unexpectedError;
+}
+
+function unexpectedError()
+{
+    // If an asynchronous call results in an error, an "error" event will fire on the IDBRequest
+    // object that was returned and the event's code and message attributes will be populated with
+    // the correct values.
+    logError("Error " + event.code + ": " + event.message);
+
+    // Unfortunately, Chromium/WebKit do not implicitly abort a transaction when an error occurs
+    // within one of its async operations. In the future, when an error occurs and the event is
+    // not canceled, the transaction will be aborted.
+    if (currentTransaction)
+        currentTransaction.abort();
+}
+
+function onOpen()
+{
+    // If an asynchronous call results in success, a "success" event will fire on the IDBRequest
+    // object that was returned and the call's result will be placed in the event's "result"
+    // attribute. In some cases, the expected result will be null.
+    window.db = event.result;
+
+    // The IDBDatabase object has a "version" attribute. This can only be set by calling
+    // "setVersion" on the database and supplying a new version. This also starts a new
+    // transaction which is very special. There are many details and gotchas surrounding
+    // setVersion which we'll get into later.
+    if (db.version == "1.0") {
+        // We could skip setting up the object stores and indexes if this were a real application
+        // that wasn't going to change things without changing the version number. But since this
+        // is both a tutorial and a living document, we'll go on and set things up every time we run.
+    }
+    var request = db.setVersion("1.0");
+    request.onsuccess = onSetVersion;
+    request.onerror = unexpectedError;
+}
+
+function onSetVersion()
+{
+    // We are now in a setVersion transaction. Such a transaction is the only place where one
+    // can add or remove indexes and objectStores. The result (property of event) is an
+    // IDBTransaction object that has "complete", "abort", and "timeout" event handlers which tell
+    // us when the transaction has committed, aborted, or timed out.
+    window.currentTransaction = event.result;
+    currentTransaction.oncomplete = onSetVersionComplete;
+    currentTransaction.onabort = unexpectedAbort;
+
+    // Delete existing object stores.
+    while (db.objectStores.length)
+        db.removeObjectStore(db.objectStores[0]);
+
+    // Now that we have a blank slate, let's create an objectStore. An objectStore is simply an
+    // ordered mapping of keys to values. We can iterate through ranges of keys or do individual
+    // lookups. ObjectStores don't have any schema.
+    //
+    // Keys can be integers, strings, or null. (The spec also defines dates and there's talk of
+    // handling arrays, but these are not implemented yet in Chromium/WebKit.) Values can be
+    // anything supported by the structured clone algorithm
+    // (http://dev.w3.org/html5/spec/Overview.html#internal-structured-cloning-algorithm) which
+    // is a superset of what can be expressed in JSON. (Note that Chromium/WebKit does not fully
+    // implement the structured clone algorithm yet, but it definitely handles anything JSON
+    // serializable.)
+    //
+    // There are two types of objectStores: ones where the path is supplied manually every time a
+    // value is inserted and those with a "key path". A keyPath is essentially a JavaScript
+    // expression that is evaluated on every value to extract a key. For example, if you pass in
+    // the value of "{fname: 'john', lname: 'doe', address: {street: 'Buckingham Palace", number:
+    // 76}, siblings: ["Nancy", "Marcus"], id: 22}" and an objectStore has a keyPath of "id" then
+    // 22 will be the key for this value. In objectStores, each key must be unique.
+    //
+    // Note that the exact syntax allowed for keyPaths is not yet well specified, but
+    // Chromium/WebKit currently allows paths that are multiple levels deep within an object and
+    // allows that to be intermixed with array dereferences. So, for example, a key path of
+    // "address.number" or "siblings[0]" would be legal (provided every entry had an address with
+    // a number attribute and at least one sibling). You can even go wild and say
+    // "foo[0][2].bar[0].baz.test[1][2][3]". It's possible this will change in the future though.
+    //
+    // If you set autoIncrement (the third optional parameter), IndexedDB will generate a key
+    // for your entry automatically. And if you have a keyPath set, it'll set the value at
+    // the location of the keyPath _in the database_ (i.e. it will not modify the value you pass
+    // in to put/add). Unfortunately autoIncrement is not yet implemented in Chromium/WebKit.
+    //
+    // Let's now create an objectStore for people. We'll supply a key path in this case.
+    var objectStore = db.createObjectStore("people", "id");
+
+    // Notice that it returned synchronously. The rule of thumb is that any call that touches (in
+    // any way) keys or values is asynchronous and any other call (besides setVersion and open) are
+    // asynchronous.
+    //
+    // Now let's create some indexes. Indexes allow you to create other keys via key paths which
+    // will also point to a particular value in an objectStore. In this example, we'll create
+    // indexes for a persons first and last name. Indexes can optionally be specified to not be
+    // unique, which is good in the case of names. The first parameter is the name of the index.
+    // Second is the key path. The third specifies uniqueness.
+    var fname = objectStore.createIndex("fname", "fname", false);
+    var lname = objectStore.createIndex("lname", "lname", false);
+
+    // Note that if you wanted to delete these indexes, you can either call objectStore.removeIndex
+    // or simply delete the objectStores that own the indexes. (Note that removeObjectStore and
+    // removeIndex may be changed to deleteObjectStore and deleteIndex in the future.)
+    //
+    // If we wanted to, we could populate the objectStore with some data here or do anything else
+    // allowed in a normal (i.e. non-setVersion) transaction. This is useful so that data migrations
+    // can be atomic with changes to the objectStores/indexes.
+    //    
+    // Because we haven't actually made any new asynchronous requests, this transaction will
+    // start committing as soon as we leave this function. This will cause oncomplete event handler
+    // for the transaction will fire shortly after. IndexedDB transactions commit whenever control is
+    // returned from JavaScript with no further work being queued up against the transaction. This
+    // means one cannot call setTimeout, do an XHR, or anything like that and expect my transaction
+    // to still be around when that completes.
+    
+}
+
+function unexpectedAbort()
+{
+    logError("A transaction aborted unexpectedly!");
+}
+
+function onSetVersionComplete()
+{
+    // Lets create a new transaction and then not schedule any work on it to watch it abort itself.
+    // Transactions (besides those created with setVersion) are created synchronously. All three
+    // parameters are optional for transaction.
+    //
+    // The first specifies which object stores to lock. The spec specifies "dynamic transactions"
+    // which don't require this and which have finer grained locks, but no one yet supports this and
+    // it may even be dropped from the first version of the spec, so I don't suggest you rely on it.
+    // Chromium/WebKit also does not yet support anything finer grained than database level locking,
+    // so in this tutorial we'll just pass in the empty array which means "lock the world".
+    //
+    // The second parameter specifies the locking mode. The default is READ_ONLY (i.e. a shared lock).
+    // That's fine for this case, but later we'll ask for IDBTransaction.READ_WRITE. At the moment,
+    // Chromium/WebKit pretends every transaction is READ_WRITE, which is kind of bad. (Note that
+    // SNAPSHOT_READ will soon be removed from the spec.)
+    //
+    // The last parameter is the timeout length. At the moment, Chromium/WebKit defaults to 0 which
+    // means never, but it's possible we'll change this in the future, so set it if you really care.
+    window.currentTransaction = db.transaction([], IDBTransaction.READ_WRITE, 0);
+    currentTransaction.oncomplete = unexpectedComplete;
+    currentTransaction.onabort = onTransactionAborted;
+
+    // Verify that "people" is the only object store in existance. The objectStores attribute is
+    // a DOMStringList which is somewhat like an array.
+    var objectStoreList = db.objectStores;
+    if (objectStoreList.length != 1
+        || !objectStoreList.contains("people")
+        || objectStoreList.item(0) != "people"
+        || objectStoreList[0] != "people") {
+        logError("Something went wrong.");
+    }
+
+    // Let's grab a handle to the objectStore. This handle is tied to the transaction that creates
+    // it and thus becomes invalid once this transaction completes.
+    var objectStore = currentTransaction.objectStore("people");
+    if (!objectStore)
+        logError("Something went wrong.");
+
+    // If we try to grab an objectStore that doesn't exist, IndexedDB throws an exception.
+    try {
+        currentTransaction.objectStore("x");
+        logError("Something went wrong.");
+    } catch (e) {
+        // Note that the error messages in exceptions are mostly lies at the moment. The reason is
+        // that the spec re-uses exception codes for existing exceptions and there's no way we can
+        // disambiguate between the two. The best work-around at the moment is to look at
+        // http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#the-idbdatabaseexception-interface
+        // to figure out what the number corresponds to. We will try to resolve this soon in spec-land.
+    }
+
+    // Verify that fname and lname are the only indexes in existance.
+    if (objectStore.indexNames.length != 2)
+        logError("Something went wrong.");
+
+    // Note that no async actions were ever queued up agianst our transaction, so it'll abort once
+    // we leave this context.
+}
+
+function unexpectedComplete()
+{
+    logError("A transaction committed unexpectedly!");
+}
+
+function onTransactionAborted()
+{
+    // Now let's make a real transaction and a person to our objectStore.
+    window.currentTransaction = db.transaction(["people"], IDBTransaction.READ_WRITE, 0);
+    currentTransaction.onabort = unexpectedAbort;
+
+    var people = currentTransaction.objectStore("people");
+    var request = people.put({fname: 'John', lname: 'Doe', id: 1}); // If our objectStore didn't have a key path, the second parameter would have been the key.
+    request.onsuccess = onPutSuccess;
+    request.onerror = unexpectedError;
+
+    // While we're at it, why not add a few more? Multiple queued up async commands will be executed
+    // sequentially (though there is talk of prioritizing cursor.continue--see discussion below). Since
+    // we don't care about the individual commands' successes, we'll only bother with on error handlers.
+    //
+    // Remember that our implementation of unexpectedError should abort the "currentTransaction" in the
+    // case of an error. (Though no error should occur in this case.)
+    people.put({fname: 'Jane', lname: 'Doe', id: 2}).onerror = unexpectedError;
+    people.put({fname: 'Philip', lname: 'Fry', id: 3}).onerror = unexpectedError;
+
+    // Not shown here are the .remove method (which is soon to be renamed .delete) and .add (which is
+    // like .put except that it fires an onerror if the element already exists).
+}
+
+function onPutSuccess()
+{
+    // Result is the key used for the put.
+    if (event.result !== 1)
+        logError("Something went wrong.");
+
+    // We should be able to request the transaction via event.transaction from within any event handler
+    // (like this one) but this is not yet implemented in Chromium/WebKit. As a work-around, we use the
+    // global "currentTransaction" variable we set above.
+    currentTransaction.oncomplete = onPutTransactionComplete;
+}
+
+function onPutTransactionComplete()
+{
+    // OK, now let's query the people objectStore in a couple different ways. First up, let's try get.
+    // It simply takes in a key and returns a request whose result will be the value.
+    window.currentTransaction = db.transaction(["people"], IDBTransaction.READ_WRITE, 0);
+    currentTransaction.onabort = unexpectedAbort;
+
+    var people = currentTransaction.objectStore("people");
+    var request = people.get(1);
+    request.onsuccess = onGetSuccess;
+    request.onerror = unexpectedError;
+
+    // Note that multiple objectStore (or index) method calls will return different objects (that still
+    // refer to the same objectStore/index on disk).
+    people.someProperty = true;
+    if (currentTransaction.objectStore("people").someProperty)
+        logError("Something went wrong.");
+}
+
+function onGetSuccess()
+{
+    if (event.result.fname !== "John")
+        logError("Something went wrong.");
+
+    // Events have a .source attribute which is the object that fired the event. In this case, it's our
+    // "people" objectStore object.
+    var people = event.source;
+
+    // Now let's try opening a cursor from id 1 (exclusive/open) to id 3 (inclusive/closed). This means
+    // we'll get the objects for ids 2 and 3. You can also create cursors that are only right or only
+    // left bounded or ommit the bound in order to grab all objects. You can also specify a direction
+    // which can be IDBCursor.NEXT (default) for the cursor to move forward, NEXT_NO_DUPLICATE to only
+    // return unique entires (only applies to indexes with unique set to false), PREV to move backwards,
+    // and PREV_NO_DUPLICATE.
+    var keyRange = IDBKeyRange.bound(1, 3, true, false);
+    var request = people.openCursor(keyRange, IDBCursor.NEXT);
+    request.onsuccess = onObjectStoreCursor;
+    request.onerror = unexpectedError;
+}
+
+function onObjectStoreCursor()
+{
+    // The result of openCursor is an IDBCursor object or null if there are no (more--see below)
+    // records left.
+    var cursor = event.result;
+    if (cursor === null) {
+        cursorComplete(event.source); // The soruce is still an objectStore.
+        return;
+    }
+
+    // We could use these values if we wanted to.
+    var key = cursor.key;
+    var value = cursor.value;
+
+    // cursor.count is probably going to be removed.
+    // cursor.update and .remove are not yet implemented in Chromium/WebKit.
+
+    // cursor.continue will reuse the same request object as what openCursor returned. In the future,
+    // we MAY prioritize .continue() calls ahead of all other async operations queued up. This will
+    // introduce a level of non-determinism but should speed things up. Mozilla has already implemented
+    // this non-standard behavior, from what I've head.
+    event.result.continue();
+}
+
+function cursorComplete(objectStore)
+{
+    // While still in the same transaction, let's now do a lookup on the lname index.
+    var lname = objectStore.index("lname");
+
+    // Note that the spec has not been updated yet, but instead of get and getObject, we now
+    // have getKey and get. The former returns the objectStore's key that corresponds to the key
+    // in the index. get returns the objectStore's value that corresponds to the key in the
+    // index.
+    var request = lname.getKey("Doe");
+    request.onsuccess = onIndexGetSuccess;
+    request.onerror = unexpectedError;
+}
+
+function onIndexGetSuccess()
+{
+    // Because we did "getKey" the result is the objectStore's key.
+    if (event.result !== 1)
+        logError("Something went wrong.");
+
+    // Similarly, indexes have openCursor and openKeyCursor. We'll try a few of them with various
+    // different IDBKeyRanges just to demonstrate how to use them, but we won't bother to handle
+    // the onsuccess conditions.
+    var lname = event.source;
+    lname.openCursor(IDBKeyRange.leftBound("Doe", false), IDBCursor.NEXT_NO_DUPLICATE);
+    lname.openCursor(null, IDBCursor.PREV_NO_DUPLICATE);
+    lname.openCursor(IDBKeyRange.rightBound("ZZZZ"));
+    lname.openCursor(IDBKeyRange.only("Doe"), IDBCursor.PREV);
+    lname.openCursor();
+    lname.openKeyCursor();
+
+    // We should be able to request the transaction via event.transaction from within any event handler
+    // (like this one) but this is not yet implemented in Chromium/WebKit. As a work-around, we use the
+    // global "currentTransaction" variable we set above.
+    currentTransaction.oncomplete = onAllDone;
+}
+
+function onAllDone()
+{
+    log("Everything worked!");
+}
+
+// The way setVersion is supposed to work:
+//   To keep things simple to begin with, objectStores and indexes can only be created in a setVersion
+// transaction and one can only run if no other connections are open to the database. This is designed
+// to save app developers from having an older verison of a web page that expects a certain set of
+// objectStores and indexes from breaking in odd ways when things get changed out from underneith it.
+// In the future, we'll probably add a more advanced mechanism, but this is it for now.
+//   Because a setVersion transaction could stall out nearly forever until the user closes windows,
+// we've added a "blocked" event to the request object returned by setVersion. This will fire if the
+// setVersion transaction can't begin because other windows have an open connection. The app can then
+// either pop something up telling the user to close windows or it can tell the other windows to call
+// .close() on their database handle. .close() halts any new transactions from starting and waits for
+// the existing ones to finish. It then closes the connection and any indexedDB calls afterwards are
+// invalid (they'll probably throw, but this isn't specified yet). We may specify .close() to return
+// an IDBRequest object so that we can fire the onsuccess when the close completes.
+//   Once inside a setVersion transaction, you can do anything you'd like. The one connection which
+// was allowed to stay open to complete the setVersion transaction will stay alive. Multiple
+// setVersion transactions can be queued up at once and will fire in the order queued (though
+// this obviously only works if they're queued in the same page).
+//
+// The current status of setVersion in Chromium/WebKit:
+//   In Chromium/WebKit we currently don't enforce the "all connections must be closed before a
+// setVersion transaction starts" rule. We also don't implement database.close() or have a blocked
+// event on the request .setVersion() returns.
+//
+// The current status of workers:
+//   Chromium/WebKit do not yet support workers using IndexedDB. Support for the async interface
+// will likely come before the sync interface. For now, a work-around is using postMessage to tell
+// the page what to do on the worker's behalf in an ad-hoc manner. Anything that can be serialized
+// to disk can be serialized for postMessage.
+
+</script>
+<body onload="start()">
+Please view source for more information on what this is doing and why...<br><br>
+</body>
+</html>

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list