// Now write the blob to the file
writer.write(blob);
writer.onerror = logerr;  // Log errors from write()
if (callback)             // If there is a callback
writer.onwrite = callback; // call it on success
},
logerr);     // Log errors from createWriter()
},
logerr);             // Log errors from getFile()
}
// Delete the named file, calling the optional callback when done
function deleteFile(name, callback) {
filesystem.root.getFile(name, {},          // Get FileEntry for named file
function(entry) {  // Pass the FileEntry here
entry.remove(callback, // Delete the FileEntry
logerr);  // Or log remove() error
},
logerr);           // Log a getFile() error
}
// Create a new directory with the specified name
function makeDirectory(name, callback) {
filesystem.root.getDirectory(name,           // Name of directory to create
              // Options
create: true,  // Create, if doesn't exist
exclusive:true // Error if it does exist
},
callback,       // Call this when done
logerr);        // Log any errors
}
// Read the contents of the specified directory, and pass them, as an array
// of strings, to the specified callback function
function listFiles(path, callback) {
// If no directory specified, list the root directory. Otherwise, look up
// the named directory and list it (or log an error looking it up).
if (!path) getFiles(filesystem.root);
else filesystem.root.getDirectory(path, {}, getFiles, logerr);
function getFiles(dir) {               // This function is used above
var reader = dir.createReader();   // A DirectoryReader object
var list = [];                     // Where we store filenames
reader.readEntries(handleEntries,  // Pass entries to function below
logerr);        // or log an error.
// Reading directories can be a multistep process. We have to keep
// calling readEntries() until we get an empty array. Then we're done
// and we can pass the full list to the user's callback function.
function handleEntries(entries) {
if (entries.length == 0) callback(list);  // We're done
else {
// Otherwise, add these entries to the list and ask for more
// The array-like object contains FileEntry objects and
// we need to get the name of each one.
for(var i = 0; i < entries.length; i++) {
22.7  The Filesystem API | 703
Client-Side
JavaScript
Pdf link to specific page - insert, remove PDF links in C#.net, ASP.NET, MVC, Ajax, WinForms, WPF
Free C# example code is offered for users to edit PDF document hyperlink (url), like inserting and deleting
add links to pdf in acrobat; add links to pdf acrobat
Pdf link to specific page - VB.NET PDF url edit library: insert, remove PDF links in vb.net, ASP.NET, MVC, Ajax, WinForms, WPF
Help to Insert a Hyperlink to Specified PDF Document Page
pdf link to email; change link in pdf file
var name = entries[i].name;              // Get entry name
if (entries[i].isDirectory) name += "/"; // Mark directories
list.push(name);                         // Add to list
}
// Now get the next batch of entries
reader.readEntries(handleEntries, logerr);
}
}
}
}
Working with files and the filesystem is quite a bit easier in worker threads, where it is
okay to make blocking calls and we can use the synchronous API. Example 22-14 de-
fines the same filesystem utility functions as Example 22-13 does, but it uses the syn-
chronous API and is quite a bit shorter.
Example 22-14. The synchronous filesystem API
// Filesystem utilities using the synchronous API in a worker thread
var filesystem = requestFileSystemSync(PERSISTENT, 10*1024*1024);
function readTextFile(name) {
// Get a File from a FileEntry from the root DirectoryEntry
var file = filesystem.root.getFile(name).file();
// Use the synchronous FileReader API to read it 
return new FileReaderSync().readAsText(file);
}
function appendToFile(name, contents) {
// Get a FileWriter from a FileEntry from the root DirectoryEntry
var writer = filesystem.root.getFile(name, {create:true}).createWriter();
writer.seek(writer.length);  // Start at the end of the file
var bb = new BlobBuilder()   // Build the file contents into a Blob
bb.append(contents);
writer.write(bb.getBlob());   // Now write the blob to the file
}
function deleteFile(name) {
filesystem.root.getFile(name).remove();
}
function makeDirectory(name) {
filesystem.root.getDirectory(name, { create: true, exclusive:true });
}
function listFiles(path) {
var dir = filesystem.root;
if (path) dir = dir.getDirectory(path);
var lister = dir.createReader();
var list = [];
do {
var entries = lister.readEntries();
for(var i = 0; i < entries.length; i++) {
var name = entries[i].name;
704 | Chapter 22: HTML5 APIs
C# PDF File & Page Process Library SDK for C#.net, ASP.NET, MVC
Image: Copy, Paste, Cut Image in Page. Link: Edit URL. XDoc.PDF allows you to easily move PDF document pages specific APIs to copy and get a specific page of PDF
pdf link open in new window; add links to pdf
VB.NET PDF File & Page Process Library SDK for vb.net, ASP.NET
By referring to this VB.NET guide, you can use specific APIs to copy and get a specific page of PDF file; you are also able to copy and paste pages from a PDF
accessible links in pdf; convert a word document to pdf with hyperlinks
if (entries[i].isDirectory) name += "/";
list.push(name);
}
} while(entries.length > 0);
return list;
}
// Allow the main thread to use these utilities by sending a message
onmessage = function(e) {
// We expect the message to be an object like this:
// { function: "appendToFile", args: ["test", "testing, testing"]}
// We invoke the specified function with the specified args and
// post the message back 
var f = self[e.data.function];
var result = f.apply(null, e.data.args);
postMessage(result);
};
22.8  Client-Side Databases
Web application architecture has traditionally featured HTML, CSS, and JavaScript on
the client and a database on the server. Among the most surprising HTML5 APIs,
therefore, are client-side databases. These are not just client-side APIs for accessing
database servers across the network, but actual client-side databases stored on the
user’s computer and directly accessed by JavaScript code in the browser.
The Web Storage API described in §20.1 can be thought of as a particularly simple kind
of database that persists simple key/value pairs. But in addition, there are two client-
side database APIs that are “real” databases. One, known as Web SQL Database, is a
simple relational database that supports basic SQL queries. Chrome, Safari, and Opera
implemented this API, but Firefox and IE have not, and likely never will. Work on the
official specification of this API has stopped and this full-featured SQL database will
probably never become an official standard nor an unofficial but interoperable feature
of the web platform.
Standardization  efforts are now  focused  on  another database API, known as
IndexedDB. It is too early to document this API in any detail (it is not covered in Part
IV), but Firefox 4 and Chrome 11 include implementations, and this section includes
a working example that demonstrates some of the most important features of the
IndexedDB API.
IndexedDB is an object database, not a relational database, and it is much simpler than
databases that support SQL queries. It is more powerful, efficient, and robust than the
key/value storage provided by the Web Storage API, however. Like the Web Storage
and the Filesystem API, IndexedDB databases are scoped to the origin of the containing
document: two web pages with the same origin can access each other’s data, but web
pages from different origins cannot.
22.8  Client-Side Databases | 705
Client-Side
JavaScript
VB.NET PDF Page Insert Library: insert pages into PDF file in vb.
Add and Insert Blank Page to PDF File Using VB. This demo explains how to use VB to insert an empty page to a specific location of current PDF file .
add a link to a pdf file; add hyperlinks to pdf
C# PDF Page Insert Library: insert pages into PDF file in C#.net
Add and Insert Blank Page to PDF File in C#.NET. This C# demo explains how to insert an empty page to a specific location of current PDF file.
clickable links in pdf files; adding links to pdf document
Each origin can have any number of IndexedDB databases. Each one has a name that
must be unique within the origin. In the IndexedDB API, a database is simply a col-
lection of named object stores. As the name implies, an object store stores objects (or
any value that can be cloned—see “Structured Clones” on page 672). Each object must
have a key by which it can be sorted and retrieved from the store. Keys must be unique—
two objects in the same store may not have the same key—and they must have a natural
ordering so that they can be sorted. JavaScript strings, numbers, and Date objects are
valid keys. An IndexedDB database can automatically generate a unique key for each
object you insert into the database. Often, though, the objects you insert into an object
store will already have a property that is suitable for use as a key. In this case, you specify
a “key path” for that property when you create the object store. Conceptually, a key
path is a value that tells the database how to extract an object’s key from the object.
In addition to retrieving objects from an object store by their primary key value, you
may want to be able to search based on the value of other properties in the object. In
order to be able to do this, you can define any number of indexes on the object store.
(The ability to index an object store explains the name “IndexedDB.”) Each index
defines a secondary key for the stored objects. These indexes are not generally unique
and multiple objects may match a single key value. So when querying an object store
via an index, you generally use a cursor, which defines an API for retrieving streaming
query results one at a time. Cursors can also be used when querying an object store (or
index) for a range of keys, and the IndexedDB API includes an object for describing
ranges (upper-bounded and/or lower-bounded, inclusive bounds or exclusive bounds)
of keys.
IndexedDB provides atomicity guarantees: queries and updates to the database are
grouped within a transaction so that they all succeed together or all fail together and
never leave the database in an undefined partially updated state. Transactions in
IndexedDB are simpler than in many database APIs; we’ll mention them again below.
Conceptually, the IndexedDB API is quite simple. To query or update a database, you
first open the database you want (specifying it by name). Next, you create a transaction
object and use that object to look up the desired object store within the database, also
by name. Finally, you look up an object by calling the 
get()
method of the object store
or store a new object by calling 
put()
. (Or by calling 
add()
, if you want to avoid over-
writing existing objects.) If you want to look up the objects for a range of keys, you
create an IDBRange object and pass it to the 
openCursor()
method of the object store.
Or, if you want to make a query using a secondary key, you look up the named index
of the object store, and then call the 
get()
or 
openCursor()
method of the index object.
This conceptual simplicity is complicated, however, by the fact that the API must be
asynchronous so that web apps can use it without blocking the browser’s main UI
thread. (The IndexedDB specification defines a synchronous version of the API for use
by worker threads, but at the time of this writing, no browser has yet implemented that
version of the API, so it is not covered here.) Creating transactions and looking up
object stores and indexes are easy synchronous operations. But opening a database,
706 | Chapter 22: HTML5 APIs
VB.NET PDF - Annotate PDF Online with VB.NET HTML5 PDF Viewer
Click to add a text box to specific location on PDF page. Outline width, outline color, fill color and transparency are all can be altered in properties.
pdf link to attached file; add hyperlink pdf document
C# HTML5 PDF Viewer SDK to annotate PDF document online in C#.NET
Click to add a text box to specific location on PDF page. Outline width, outline color, fill color and transparency are all can be altered in properties.
add link to pdf; add url to pdf
updating an object store with 
put()
, and querying a store or index with 
get()
or 
open
Cursor()
are all asynchronous operations. These asynchronous methods all immedi-
ately return a request object. The browser triggers a success or error event on the request
object when the request succeeds or fails, and you can define handlers with the
onsuccess
and 
onerror
properties. Inside an 
onsuccess
handler, the result of the oper-
ation is available as the 
result
property of the request object.
One convenient feature of this asynchronous API is that it simplifies transaction man-
agement. In a typical use of the IndexedDB API, you first open the database. This is an
asynchronous operation, so it triggers an onsuccess handler. In that event handler, you
create a transaction object, and then use that transaction object to look up the object
store or stores you’ll be using. Then you make any number of 
get()
and 
put()
calls on
the object stores. They are asynchronous, so nothing happens right away, but the re-
quests generated by those 
get()
and 
put()
calls are automatically associated with the
transaction object. If you need to, you can cancel all the pending operations (and undo
any that have already completed) in the transaction by calling the 
abort()
method of
the transaction object. In many other database APIs, you’d expect the transaction object
to have a 
commit()
method to finalize the transaction. In IndexedDB, however, the
transaction is committed after the original onsuccess event handler that created the
transaction exits and the browser returns to its event loop and after all the operations
pending on that transaction complete (without starting any new operations in their
callback functions). This sounds complicated, but in practice, it is straightforward. The
IndexedDB API forces you to create transaction objects in order to look up object stores,
but in common use cases, you really don’t have to think about the transactions very
much.
Finally, there is one special kind of transaction that enables a very important part of
the IndexedDB API. Creating a new database in the IndexedDB API is easy: you just
pick a name and request that that database be opened. But a new database is completely
empty, and it is useless unless you add one or more object stores (and possibly some
indexes as well) to it. The only way to create object stores and indexes is within the
onsuccess event handler of the request object returned by a call to the 
setVersion()
method of the database object. Calling 
setVersion()
allows you to specify a version
number for the database—in typical usage, you update the version number each time
you alter the structure of the database. More importantly, however, 
setVersion()
im-
plicitly begins a special kind of transaction that enables you to call the 
createObject
Store()
method of the database object and the 
createIndex()
method of an object store.
With this high-level overview of IndexedDB in mind, you should now be able to un-
derstand Example 22-15. That example uses IndexedDB to create and query a database
that maps US postal codes (zipcodes) to US cities. It demonstrates many, but not all,
of the basic features of IndexedDB. At the time of this writing, the example works in
Firefox 4 and Chrome 11, but because the specification is still in flux and implemen-
tations are still quite preliminary, there is a chance that it won’t work exactly as written
when you read this. Nevertheless, the overall structure of the example should still be
22.8  Client-Side Databases | 707
Client-Side
JavaScript
C# PDF remove image library: remove, delete images from PDF in C#.
Image: Copy, Paste, Cut Image in Page. Link: Edit URL. Bookmark: Edit Bookmark. Metadata: Edit Delete and remove all image objects contained in a specific PDF page
convert doc to pdf with hyperlinks; adding an email link to a pdf
C# PDF Image Extract Library: Select, copy, paste PDF images in C#
C#: Select All Images from One PDF Page. C# programming sample for extracting all images from a specific PDF page. // Open a document.
chrome pdf from link; adding hyperlinks to pdf files
useful to you. Example 22-15 is long, but it has lots of comments that make it easy to
understand.
Example 22-15. A IndexedDB database of US postal codes
<!DOCTYPE html>
<html>
<head>
<title>Zipcode Database</title>
<script>
// IndexedDB implementations still use API prefixes
var indexedDB = window.indexedDB ||    // Use the standard DB API
window.mozIndexedDB ||             // Or Firefox's early version of it
window.webkitIndexedDB;            // Or Chrome's early version
// Firefox does not prefix these two:
var IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction;
var IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange;
// We'll use this function to log any database errors that occur
function logerr(e) {
console.log("IndexedDB error" + e.code + ": " + e.message);
// This function asynchronously obtains the database object (creating and
// initializing the database if necessary) and passes it to the function f().
function withDB(f) {
var request = indexedDB.open("zipcodes"); // Request the zipcode database
request.onerror = logerr;                 // Log any errors
request.onsuccess = function() {          // Or call this when done
var db = request.result;  // The result of the request is the database
// You can always open a database, even if it doesn't exist.
// We check the version to find out whether the DB has been created and
// initialized yet.  If not, we have to go do that. But if the db is
// already set up, we just pass it to the callback function f().
if (db.version === "1") f(db);   // If db is inited, pass it to f()
else initdb(db,f);               // Otherwise initialize it first
}
}
// Given a zip code, find out what city it belongs to and asynchronously 
// pass the name of that city to the specified callback function.
function lookupCity(zip, callback) {
withDB(function(db) {
// Create a transaction object for this query
var transaction = db.transaction(["zipcodes"],  // Object stores we need
IDBTransaction.READ_ONLY, // No updates
0);            // No timeout
// Get the object store from the transaction
var objects = transaction.objectStore("zipcodes");
// Now request the object that matches the specified zipcode key.
// The lines above were synchronous, but this one is async
var request = objects.get(zip);
708 | Chapter 22: HTML5 APIs
request.onerror = logerr;          // Log any errors that occur
request.onsuccess = function() {   // Pass the result to this function
// The result object is now in the request.result
var object = request.result;
if (object)  // If we found a match, pass city and state to callback
callback(object.city + ", " + object.state);
else         // Otherwise, tell the callback that we failed
callback("Unknown zip code");
}
});
}
// Given the name of a city find all zipcodes for all cities (in any state)
// with that name (case-sensitive).  Asynchronously pass the results, one at
// a time, to the specified callback function
function lookupZipcodes(city, callback) {
withDB(function(db) {
// As above, we create a transaction and get the object store
var transaction = db.transaction(["zipcodes"],
IDBTransaction.READ_ONLY, 0);
var store = transaction.objectStore("zipcodes");
// This time we get the city index of the object store
var index = store.index("cities");
// This query is likely to have many results, so we have to use a 
// cursor object to retrieve them all. To create a cursor, we need 
// a range object that represents the range of keys
var range = new IDBKeyRange.only(city);  // A range with only() one key
// Everything above has been synchronous. 
// Now we request a cursor, which will be returned asynchronously.
var request = index.openCursor(range);   // Request the cursor
request.onerror = logerr;                // Log errors
request.onsuccess = function() {         // Pass cursor to this function
// This event handler will be invoked multiple times, once
// for each record that matches the query, and then once more
// with a null cursor to indicate that we're done.
var cursor = request.result    // The cursor is in request.result
if (!cursor) return;           // No cursor means no more results
var object = cursor.value      // Get the matching record
callback(object);              // Pass it to the callback
cursor.continue();             // Ask for the next matching record
};
});
}
// This function is used by an onchange callback in the document below
// It makes a DB request and displays the result
function displayCity(zip) {
lookupCity(zip, function(s) { document.getElementById('city').value = s; });
}
// This is another onchange callback used in the document below.
// It makes a DB request and displays the results
function displayZipcodes(city) {
var output = document.getElementById("zipcodes");
22.8  Client-Side Databases | 709
Client-Side
JavaScript
Download from Wow! eBook <www.wowebook.com>
output.innerHTML = "Matching zipcodes:";
lookupZipcodes(city, function(o) {
var div = document.createElement("div");
var text = o.zipcode + ": " + o.city + ", " + o.state;
div.appendChild(document.createTextNode(text));
output.appendChild(div);
});
}
// Set up the structure of the database and populate it with data, then pass
// the database to the function f(). withDB() calls this function if the 
// database has not been initialized yet. This is the trickiest part of the
// program, so we've saved it for last.
function initdb(db, f) {
// Downloading zipcode data and storing it in the database can take
// a while the first time a user runs this application.  So we have to
// provide notification while that is going on.
var statusline = document.createElement("div");
statusline.style.cssText =
"position:fixed; left:0px; top:0px; width:100%;" +
"color:white; background-color: black; font: bold 18pt sans-serif;" +
"padding: 10px; ";
document.body.appendChild(statusline);
function status(msg) { statusline.innerHTML = msg.toString(); };
status("Initializing zipcode database");
// The only time you can define or alter the structure of an IndexedDB 
// database is in the onsucess handler of a setVersion request.
var request = db.setVersion("1");       // Try to update the DB version
request.onerror = status;               // Display status on fail
request.onsuccess  = function() {       // Otherwise call this function
// Our zipcode database includes only one object store.  
// It will hold objects that look like this: {
//    zipcode: "02134",   // send it to Zoom! :-)
//    city: "Allston",
//    state: "MA",
//    latitude: "42.355147",
//    longitude: "-71.13164"
// }
// 
// We'll use the "zipcode" property as the database key
// And we'll also create an index using the city name
// Create the object store, specifying a name for the store and
// an options object that includes the "key path" specifying the
// property name of the key field for this store. (If we omit the 
// key path, IndexedDB will define its own unique integer key.)
var store = db.createObjectStore("zipcodes", // store name
{ keyPath: "zipcode" });
// Now index the object store by city name as well as by zipcode.
// With this method the key path string is passed directly as a
// required argument rather than as part of an options object.
store.createIndex("cities", "city");
710 | Chapter 22: HTML5 APIs
// Now we need to download our zipcode data, parse it into objects
// and store those objects in object store we created above.
// 
// Our file of raw data contains lines formatted like this:
// 
//   02130,Jamaica Plain,MA,42.309998,-71.11171
//   02131,Roslindale,MA,42.284678,-71.13052
//   02132,West Roxbury,MA,42.279432,-71.1598
//   02133,Boston,MA,42.338947,-70.919635
//   02134,Allston,MA,42.355147,-71.13164
//
// Surprisingly, the US Postal Service does not make this data freely
// available, so we use out-of-date census-based zipcode data from:
// http://mappinghacks.com/2008/04/28/civicspace-zip-code-database/
// We use XMLHttpRequest to download the data.  But use the new XHR2
// onload and onprogress events to process it as it arrives
var xhr = new XMLHttpRequest();   // An XHR to download the data
xhr.open("GET", "zipcodes.csv");  // HTTP GET for this URL
xhr.send();                       // Start right away
xhr.onerror = status;             // Display any error codes
var lastChar = 0, numlines = 0;   // How much have we already processed?
// Handle the database file in chunks as it arrives
xhr.onprogress = xhr.onload = function(e) {  // Two handlers in one!
// We'll process the chunk between lastChar and the last newline
// that we've received.  (We need to look for newlines so we don't
// process partial records)
var lastNewline = xhr.responseText.lastIndexOf("\n");
if (lastNewline > lastChar) {
var chunk = xhr.responseText.substring(lastChar, lastNewline)
lastChar = lastNewline + 1;   // Where to start next time
// Now break the new chunk of data into individual lines
var lines = chunk.split("\n");
numlines += lines.length;
// In order to insert zipcode data into the database we need a
// transaction object. All the database insertions we make
// using this object will be commited to the database when this
// function returns and the browser goes back to the event
// loop.  To create our transaction object, we need to specify
// which object stores we'll be using (we only have one) and we
// need to tell it that we'll be doing writes to the database,
// not just reads:
var transaction = db.transaction(["zipcodes"], // object stores
IDBTransaction.READ_WRITE);
// Get our object store from the transaction
var store = transaction.objectStore("zipcodes");
// Now loop through the lines of the zipcode file, create
// objects for them, and add them to the object store.
for(var i = 0; i < lines.length; i++) {
var fields = lines[i].split(","); // Comma-separated values
var record = {           // This is the object we'll store
22.8  Client-Side Databases | 711
Client-Side
JavaScript
zipcode: fields[0],  // All properties are string
city: fields[1], 
state: fields[2],
latitude: fields[3], 
longitude: fields[4]
};
// The best part about the IndexedDB API is that object
// stores are *really* simple.  Here's how we add a record:
store.put(record);   // Or use add() to avoid overwriting
}
status("Initializing zipcode database: loaded "
+ numlines + " records.");
}
if (e.type == "load") { 
// If this was the final load event, then we've sent all our
// zipcode data to the database.  But since we've just blasted
// it with some 40,000 records, it may still be processing.
// So we'll make a simple query. When it succeeds, we know
// that the database is ready to go, and we can then remove
// the status line and finally call the function f() that was
// passed to withDB() so long ago
lookupCity("02134", function(s) {  // Allston, MA
document.body.removeChild(statusline);
withDB(f);
});
}
}
}
}
</script>
</head>
<body>
<p>Enter a zip code to find its city:</p>
Zipcode: <input onchange="displayCity(this.value)"></input>
City: <output id="city"></output>
</div>
<div>
<p>Enter a city name (case sensitive, without state) to find cities and their zipcodes:</p>
City: <input onchange="displayZipcodes(this.value)"></input>
<div id="zipcodes"></div>
</div>
<p><i>This example is only known to work in Firefox 4 and Chrome 11.</i></p>
<p><i>Your first query may take a very long time to complete.</i></p>
<p><i>You may need to start Chrome with --unlimited-quota-for-indexeddb</i></p>
</body>
</html>
22.9  Web Sockets
Chapter 18 showed how client-side JavaScript code can communicate over the net-
work. The examples in that chapter all used HTTP, which means that they were all
712 | Chapter 22: HTML5 APIs
Documents you may be interested
Documents you may be interested