--enable-webgl flag.
File, FileList, FileReader.
FileSystem APIs for
reading/writing files and directories. If using Google Chrome, you will likely
need to run the Chrome executable using the --unlimited-quota-for-files flag.
window.name ( hack )localStorage / sessionStoragelocalStorage / sessionStorage
localStoragewindow.localStorage
localStorage.setItem('someKey', someValue);
localStorage.getItem('someKey'); // value
// Can also access as a property, but not recommended.
localStorage.someKey = someValue;
localStorage.setItem('dateOfBirth', '1984-07-22');
localStorage.getItem('dateOfBirth'); // '1984-07-22'
localStorage.length // num of items stored
localStorage.key(0); // 'dateOfBirth'
localStorage.removeItem('dateOfBirth');
localStorage.clear();
http://example.com:80/
\ \ \_ port
\ \_ domain
\_ scheme
sessionStoragewindow.sessionStoragelocalStorage but...
Solution:
localStorage.setItem('user', JSON.stringify({user: 'john', id: 10}));
var user = JSON.parse(localStorage.getItem('user'));
<textarea id="ta" placeholder="Start typing..."></textarea>
document.querySelector('#ta').addEventListener('keyup', function(e) {
localStorage.setItem('value', this.value);
localStorage.setItem('timestamp', (new Date()).getTime());
}, false);
var db = window.openDatabase(
'MyDB', // dbName
'1.0', // version
'test database', // description
2 * 1024 * 1024, // estimatedSize in bytes
function(db) {} // optional creationCallback
);
db.changeVersion('', '1.0', function (tx) { // opt
// TODO: create schema
}, opt_errorCallback, opt_successCallback);
null if creation is unsuccessfulreadTransaction
db.readTransaction(function(tx) {
// executeSql
}, opt_errorCallback, opt_successCallback);
transaction
db.transaction(function(tx) {
// executeSql
}, opt_errorCallback, opt_successCallback);
executeSql();tx.executeSql(sqlStatement, opt_arguments, opt_callback, opt_errorCb);
Create:
tx.executeSql('CREATE TABLE IF NOT EXISTS ' +
'todo(id INTEGER PRIMARY KEY ASC, task TEXT, added_on DATETIME)');
Insert:
var taskText = 'buy groceries'; tx.executeSql( 'INSERT INTO todo(task, added_on) VALUES (?,?)', [taskText, new Date()], renderFunc, onError);
Delete:
tx.executeSql('DELETE FROM todo WHERE id=?', [id], renderFunc, onError);
executeSql();tx.executeSql(sqlStatement, opt_arguments, opt_callback, opt_errorCb);
Query:
function renderFunc(tx, results) {
// results.insertId: last row inserted in db.
// results.rowsAffected: num of rows changed by the SQL statement.
var len = results.rows.length;
for (var i = 0; i < len; ++i) {
var row = results.rows.item(i);
console.log(row.task, row.added_on.toJSON());
}
}
tx.executeSql('SELECT * FROM todo', [], renderFunc, onError);
See the generated database:
Developer > Developer Tools > Resources
window.indexedDBlocalStorage/sessionStorage and Web SQL DB:
var db = window.indexedDB.open('FriendDB', 'My Friends!');
if (db.version != '1') {
// User's first visit, initialize database.
db.createObjectStore('Friends', // name of new object store
'id', // key path
true); // auto increment?
db.setVersion('1');
} else {
// DB already initialized.
}
var store = db.openObjectStore('Friends');
var user = store.put({name: 'Eric',
gender: 'male',
likes: 'html5'});
console.log(user.id); // Expect 1
Retrieving by key ( indexes ):
db.createIndex(indexName, keyPath, unique?);
// db.createObjectStore("Friend", "id", true);
db.createIndex("FriendNames", "name", false);
var index = db.openIndex('FriendNames');
var id = index.get('Eric');
Querying ( cursors ):
// Restrict to names beginning A-E
var range = new KeyRange.bound('A', 'E');
var cursor = index.openObjectCursor(range);
while (cursor.continue()) {
console.log(cursor.value.name);
}
var idbRequest = window.indexedDB.open('Database Name');
idbRequest.onsuccess = function(e) {
var db = this.result;
var transaction = db.transaction(
['ObjectStoreName'],IDBTransaction.READ_ONLY);
var curRequest = transaction.objectStore('ObjectStoreName').openCursor();
curRequest.onsuccess = ...;
};
<html manifest="example.appcache">... </html>
CACHE MANIFEST # 2010-11-17-v0.0.1 # Explicitly cached entries CACHE: index.html stylesheet.css images/logo.png http://img.example.com/logo2.png scripts/main.js # static.html will be served if the user is offline FALLBACK: / /static.html # Resources that require the user to be online. NETWORK: * # login.php, http://api.twitter.com, etc.
Server with mime-type: text/cache-manifest
var cache = window.applicationCache;
cache.addEventListener('cached', handleCacheEvent, false);
cache.addEventListener('checking', handleCacheEvent, false);
cache.addEventListener('downloading', handleCacheEvent, false);
cache.addEventListener('error', handleCacheError, false);
cache.addEventListener('noupdate', handleCacheEvent, false);
cache.addEventListener('obsolete', handleCacheEvent, false);
cache.addEventListener('progress', handleCacheEvent, false);
cache.addEventListener('updateready', handleCacheEvent, false);
// When a new manifest is successfully downloaded, swap the new cache and reload page.
cache.addEventListener('updateready', function(e) {
if (cache.status == cache.UPDATEREADY) {
cache.swapCache();
if (confirm('A new version of this site is available. Load it?')) {
window.location.reload();
}
}
}, false);
about:appcache-internals
File / Blob, FileList, FileReaderBlobBuilder, FileWriter, FileSaverFile / FileList<input type="file" id="files" name="files[]" multiple /> <output id="list"></output>
document.querySelector('#files').onchange = function(e) {
var files = e.target.files; // FileList
var output = [];
for (var i = 0, f; f = files[i]; ++i) {
output.push('<li><b>', f.name, '</b> (', f.type || 'n/a',
') - ', f.size, ' bytes, last modified: ',
f.lastModifiedDate.toLocaleDateString(), '</li>');
}
document.querySelector('#list').innerHTML =
'<ul>' + output.join('') + '</ul>';
};
<input type="file" webkitdirectory />
FileList will have a webkitRelativePath property
FileReaderAsynchronously read binary data into memory: Demo
var reader = new FileReader(); reader.readAsBinaryString(File|Blob); reader.readAsText(File|Blob, opt_encoding); // default UTF-8 reader.readAsDataURL(Blob|File); reader.readAsArrayBuffer(Blob|File);
Reading byte ranges: Demo
var blob = file.slice(startingByte, length); // Blob reader.readAsBinaryString(blob);
var reader = new FileReader();
reader.onload = function(e) {
document.querySelector('img').src = e.target.result;
};
function onDrop(e) {
reader.readAsDataURL(e.dataTransfer.files[0]);
};
reader.onerror = errorHandler;
reader.onprogress = updateProgress;
reader.onabort = cancelRead;
reader.onloadstart = updateProgress;
reader.onloadend = function(e) {
// e.target.readyState == FileReader.DONE == 2
};
reader.onload = readFile;
if (file.type.match(/image.*/)) {
var blobURL = window.URL.createObjectURL(file);
var img = document.createElement('img');
img.src = blobURL; // blob:blobinternal:///d8c2c85e-ab1b-4b7b3d37bff6
thumbnails.appendChild(img);
// Clean-up: window.URL.revokeObjectURL(img.src);
}
var bb = new BlobBuilder();
bb.append('<marquee>Flashy Lights!!!</marquee>');
var iframe = document.createElement('iframe');
iframe.src = window.URL.createObjectURL(bb.getBlob('text/html'));
document.body.appendChild(iframe);
<!DOCTYPE html>
<html>
<body>
<script id="worker1" type="text/plain">
onmessage = function(e) {
...
};
</script>
<script>
var bb = new BlobBuilder();
bb.append(document.querySelector('#worker1').textContent);
var worker = new Worker(
window.URL.createObjectURL(bb.getBlob()));
worker.onmessage = function(e) {
...
};
worker.postMessage(); // Start the worker.
</script>
</body>
</html>
requestFileSystem();window.requestFileSystem( TEMPORARY, // persistent vs. temporary storage 1024 * 1024, // size (bytes) of needed space initFs, // success callback opt_errorHandler // opt. error callback, denial of access );
TEMPORARY storage
PERSISTENT storage
function initFs(fs) {
fs.root.getFile('logFile.txt', {create: true}, function(fileEntry) {
// fileEntry.isFile == true
// fileEntry.name == 'logFile.txt'
// fileEntry.fullPath == '/logFile.txt'
// Get a File obj
fileEntry.file(function(file) { /* TODO: Use FileReader */ }, errorHandler);
// fileEntry.remove(function() {}, errorHandler);
// fileEntry.moveTo(...);
// fileEntry.copyTo(...);
// fileEntry.getParent(function(dirEntry) {}, errorHandler);
}, errorHandler);
}
function initFs(fs) {
fs.root.getDirectory('myFolder', {create: true, exclusive: true},
function (dirEntry) {
// dirEntry.isDirectory == true
// Remove the directory
dirEntry.removeRecursively(function() {
console.log('Well, that was pointless!');
}, errorHandler);
// dirEntry.getFile(...);
// dirEntry.getDirectory(...);
}, errorHandler);
}
function initFs(fs) {
var root = fs.root; // A DirectoryEntry itself
var dirReader = root.createReader(); // DirectoryReader
dirReader.readEntries(function(entries) {
for (var i = 0, entry; entry = entries[i]; ++i) {
console.log(entry.name, entry.isFile, entry.isDirectory);
}
}, errorHandler);
}
FileWriter )
function initFs(fs) {
fs.root.getFile('logFile.txt', {create: true}, function(fileEntry) {
fileEntry.createWriter(function(writer) { // FileWriter
writer.onwrite = function(e) {
console.log('Write completed.');
};
writer.onerror = function(e) {
console.log('Write failed: ' + e);
};
var bb = new BlobBuilder();
bb.append('Lorem ipsum');
writer.write(bb.getBlob('text/plain'));
}, errorHandler);
}
}

<meta http-equiv="X-UA-Compatible" content="chrome=1">
X-UA-Compatible: chrome=1
if (Modernizr.localstorage) { ... }
if (Modernizr.sessionstorage) { ... }
if (Modernizr.websqldatabase) { ... }
if (Modernizr.indexeddb) { ... }
if (Modernizr.applicationcache) { ... }
Modernizr.addTest('file', function() {
return !!window.File && !!window.FileList;
});
Modernizr.addTest('filereader', function() {
return !!window.FileReader;
});
Modernizr.addTest('blob', function() {
return !!window.Blob && !!window.BlobBuilder &&
!!window.URL.createObjectURL;
});
Modernizr.addTest('filesystem', function() {
return !!window.requestFileSystem;
});
Questions?