HTML5 Web App Hackathon 
Ernest Delgado, Pete LePage, Boris Smus
Daniel Hermes, Mihai Ionescu, Nadim Ratani, Peng Ying
August 1-11, 2011 (NYC, CHI, KIR, MTV)
#HTML5Hack

Ernest Delgado, Pete LePage, Boris Smus
Daniel Hermes, Mihai Ionescu, Nadim Ratani, Peng Ying
August 1-11, 2011 (NYC, CHI, KIR, MTV)
#HTML5Hack
-moz-border-radius: 12px; /* FF1-3.6 */
-webkit-border-radius: 12px; /* Saf3-4, iOS 1-3.2, Android <1.6 */
border-radius: 12px; /* Opera 10.5, IE9, Saf5, Chrome,
FF4, iOS 4, Android 2.1+ */
@font-face {
font-family: 'WebFont';
src: url('myfont.eot?#') format('eot'), /* IE6–8 */
url('myfont.woff') format('woff'), /* FF3.6+, IE9, Chrome6+,
Saf5.1+*/
url('myfont.ttf') format('truetype'); /* Saf3—5, Chrome4+,
FF3.5, Opera 10+ */
}
Arial Comic Sans MS Courier New Georgia Impact Times New Roman Trebuchet MS Verdana
var el = document.querySelector('#main').classList;
el.add('highlight');
el.remove('shadow');
el.toggle('highlight');
<div id="out" data-id="good" data-name="joe"></div>
document.querySelector('#out').dataset['name'] // joe
var els = document.querySelectorAll("ul li:nth-child(odd)");
var tds = document.querySelectorAll("table.test > tr > td");
var el = document.querySelector("table.test > tr > td");
var els = document.getElementsByClassName('section');
.box {
display: -webkit-box;
-webkit-box-orient: ;
}
.box .one, .box .two {
-webkit-box-flex: 1;
}
.box .three {
-webkit-box-flex: 3;
}
addEvent(drop, 'dragover', cancel);
addEvent(drop, 'dragenter', cancel);
addEvent(drop, 'drop', function (event) {
// stops the browser from redirecting off to the text.
if (event.preventDefault) {
event.preventDefault();
}
this.innerHTML += '<p>' + event.dataTransfer.getData('Text') + '</p>';
return false;
});
function startSearch(event) {
if (event.target.results.length > 1) {
var second = event.target.results[1].utterance;
document.getElementById("second_best").value = second;
}
event.target.form.submit();
}
- Better Coded UIDrag and Drop + Speech Input + Rounded Corners + CSS Gradients + CSS Tranforms + CSS Transitions + etc
var socket = new WebSocket('ws://html5rocks.websocket.org/echo');
socket.onmessage = function(event) { console.log(event.data); };
- Socket.IO
var socket = io.connect('http://localhost');
socket.emit('message', {data: 'hello'})
socket.on('update', function(data) {
console.log(data);
});
var io = require('socket.io').listen(80);
io.sockets.on('message', function(socket) {
socket.emit('update', {messages: messageBuffer});
});
postMessageotherWindow.postMessage(message, targetOrigin);
window.addEventListener("message", function(event) {
if (event.origin != "http://myurl.com/foo") { /* do stuff */ }
}, false);
- postMessage
socket_.on('chat', function(data) {
window.parent.postMessage(data, document.location.origin);
}
window.addEventListener('message', function(e) {
document.querySelector('#dudes').append(createBubble(e.data));
});
<input type="file" accept="audio/*" multiple>
document.querySelector('input[type="file"]').onchange = function(e) {
var files = e.target.files; // FileList
for (var i = 0, f; f = files[i]; ++i) {
// f.name
// f.type // mimetype
// f.size // bytes
// f.lastModifiedDate.toLocaleDateString()
}
};
<input type="file" webkitdirectory />
FileList will have a webkitRelativePath propertyAsynchronously read binary data into memory:
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:
var blob = file.webkitSlice(startingByte, offset, opt_contentType); 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]);
};
function submitForm() {
var fd = new FormData(); // or prefill: FormData(window.myform)
fd.append("username", "Groucho");
fd.append("accountnum", 123456);
// Append File. Creates a multipart/form-data upload.
var file = document.querySelector('#afile').files[0];
if (file) {
fd.append('afile', file);
}
var xhr = new XMLHttpRequest();
xhr.open('POST', '/upload', true);
xhr.onload = function(e) { ... };
xhr.send(fd);
}
function upload(blob, opt_callback) {
var xhr = new XMLHttpRequest();
xhr.open('POST', '/upload', true);
if (opt_callback) {
xhr.onload = opt_callback;
}
xhr.send(blob);
}
window.BlobBuilder = window.BlobBuilder ||
window.WebKitBlobBuilder || window.MozBlobBuilder;
var bb = new BlobBuilder(); // Create a .txt file on the fly.
bb.append('Hello World');
uploadFile(bb.getBlob('text/plain'), function(e) {
console.log('upload complete');
});
- DJ uploads a song
uploadNextSong: function(el) {
if (USER_FILE_QUEUE.length) {
el.textContent = 'Uploading your file...';
var formData = new FormData();
formData.append('file', USER_FILE_QUEUE.shift());
var xhr = new XMLHttpRequest();
xhr.open('POST', '/upload', true);
xhr.onload = function(e) { el.textContent = 'Uploading complete.'; };
xhr.send(formData); // Upload entire song.
} else {
setTimeout(function() {
el.textContent = 'No songs selected! Skipping you.';
socket.json.emit('nextuser', {}); // Tell server to try next user.
}, 3000);
}
}
function download(url, callback) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'arraybuffer'; // A raw buffer of bytes.
xhr.onload = function(e) {
callback(this, this.response); // Note: not xhr.responseText
};
xhr.send();
}
download('song.mp3', function(xhr, arrayBuffer) {
// Create a file.
var bb = new BlobBuilder();
bb.append(arrayBuffer);
var blob = bb.getBlob('audio/mpeg');
});
- listeners sent a download msgstartsong event, connected listeners download the song using XHR2.
this.socket.on('startsong', function(file) {
...
fetchSong_(file.url, file.name);
});
var fetchSong_ = function(url, name) {
sm_ = new SoundManager();
sm_.load(url, function(audioBuffer, arrayBuffer) {
// Display song title, artist, year.
// Load audio buffer into visualizer, hit play, and start the visuals.
visualizer.audioPlayer.loadAudioBuffer(audioBuffer);
visualizer.audioPlayer.play();
visualizer.startVisuals();
});
};
ArrayBuffer - chunk of bytes in memory. Create "views" from it:
Int8Array, Uint8ArrayInt16Array, Uint16ArrayInt32Array, Uint32ArrayFloat32Array, Float64ArrayArrayBuffer source:
var uInt8Array = new Uint8Array(arrayBuffer); var byte3 = uInt8Array[4]; // byte at offset 4. var uInt32Array = new Uint32Array(arrayBuffer);
ArrayBufferView - view of a portion of an ArrayBufferDataView - an ArrayBufferView that understands endianness:
var data = new DataView(arrayBuffer); var byte3 = data.getUint8(4); var i = data.getInt32(0, false); // Big-endian
- displaying song's ID3v1 infoFileReader, and "parsed" used DataView
according to http://en.wikipedia.org/wiki/ID3.DataView
var dv = new jDataView(arrayBuffer);
// "TAG" starts at byte -128 from EOF.
if (dv.getString(3, dv.length - 128) == 'TAG') {
var title = dv.getString(30, dv.tell()).trim();
var artist = dv.getString(30, dv.tell()).trim();
var album = dv.getString(30, dv.tell()).trim();
var year = dv.getString(4, dv.tell()).trim();
boothHeader_.textContent = [
artist, '-', title, year ? '(' + year + ')' : ''].join(' ');
} else {
boothHeader_.textContent = name; // Just use filename.
}
context = new webkitAudioContext(); source = context.createBufferSource(); analyser = context.createAnalyser(); source.connect(analyser); analyser.connect(context.destination);
- playing tunes
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.responseType = "arraybuffer";
xhr.addEventListener('load', function() {
var buffer = context.createBuffer(xhr.response, false);
});
xhr.send();
analyser.getByteFrequencyData(freqs);
var canvas = document.getElementById('a');
var context = canvas.getContext('2d');
context.fillRect(50, 25, 150, 100);
Use requestAnimationFrame for render callbacks:
window.requestAnimationFrame = window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame; window.requestAnimationFrame(animate, opt_elem /* bounding elem */);
- visualization
for (var i = 0; i < NUM_BINS + 1; ++i) {
var value = freqs[i * width];
var percent = value / 256;
var height = NUM_BINS * percent;
drawContext.fillStyle = 'hsl(' + computedColor + ', 100%, 50%)';
drawContext.fillRect(...);
}
- beat detection
this.dancingImages[i].style.webkitTransform =
'scale(' + scaleX + ',' + scaleY + ') skewX(' + skewAngle + 'rad)';
Play 23% more and spend 147% more
100% more engagement
{ "app": {
"launch": {
"urls": ["https://chrome.google.com/webstore"],
"web_url": "https://chrome.google.com/webstore",
"container": "tab"
}
},
"permissions": [],
"icons": {
"16": "16.png",
"128": "128.png"
},
"name": "Chrome Web Store - Apps, Extensions and Themes",
"description": "Discover great apps, games, extensions and...
themes for Google Chrome.",
"version": "1.0."
}
* but highly recommended!
|
|
Developers
|
Buyers
|
|
|
|
{
"iss" : "1337133713371337",
"aud" : "Google",
"typ" : "google/payments/inapp/item/v1",
"exp" : "1392348430",
"iat" : "1392282180",
"request" :{
"name" : "Piece of Cake",
"description" : "Virtual chocolate cake to fill your virtual tummy",
"price" : "10.50",
"currencyCode" : "USD",
"sellerData" : "user_id:1224245,offer_code:3098576987"
}
}
Python:
cakeJwt = jwt.encode(item, "1ZRJNFIOSJSIDFJNVHF");
Ruby:
@cakeJwt = JWT.encode(item, "1ZRJNFIOSJSIDFJNVHF")
<script type="text/javascript" src="//www.google.com/jsapi"></script>
<script>
google.load('payments', '1.0', {
'packages': ['sandbox_config']
});
</script>
function purchase() {
...
goog.payments.inapp.buy({
'jwt' : cakeJwt,
'success' : successHandler,
'failure' : failureHandler
});
}
Create purchase button
<button onclick="purchase()">Buy</button>
Python:
def post(self):
encoded_jwt = self.request.get('jwt', None)
if encoded_jwt is not None:
decoded_jwt = jwt.decode(str(encoded_jwt), SELLER_SECRET)
order_id = decoded_jwt['response']['orderId']
self.response.out.write(order_id)
- IAP
context.buy = function (item){
xhr.open('POST', window.location.href + 'buy', true);
xhr.onreadystatechange = function(jwt){
if(xhr.readyState == 4){
if(xhr.status == 200){
goog.payments.inapp.buy({
'jwt' : xhr.responseText,
'success' : successHandler,
'failure' : failureHandler
});
}
else{
console.log("error" + xhr.status)
}
}
}
Feedback: goo.gl/oTflp