The demos and segments of this talk are:
<video>
(00:35)
postMessage()
(05:40)
localStorage
(15:20)
sessionStorage
(21:00)
onhashchange
(37:30)
<canvas>
(56:55)
The notes were:
HTML5 DEMOS =========== This is a series of demos intended for showing implementations of HTML5 in (non-final) browsers available in September 2008. Configuration: - Open Terminal in Presentation mode - Hide dock - Open Opera, Firefox, Safari, VMWare with IE, Chrome - Clear all their caches, form autofill, history, download history. 1. <video> Scenario: Embedding a video <video src="firefox.ogg" controls></video> To make it autoplay: <video src="firefox.ogg" controls autoplay></video> Remove controls and add script: <script> var video = document.getElementsByTagName('video')[0]; </script> <p> <input type=button value="◼" onclick="video.pause();"> <input type=button value="▶" onclick="video.play();"> </p> Replace buttons with one button: <input type=button value="█ █" onclick="if (video.paused) video.play(); else video.pause();"> Works in Firefox. 2. postMessage() Scenario: Gadget from damowmow.com hosted in site on whatwg.org. The site knows, or can ask for, the user's nickname, and the gadget wants to show the nickname in its UI. http://www.whatwg.org/demos/2008-sept/gadget-host/host.html <iframe src="http://damowmow.com/playground/demos/gadget/gadget.html"> </iframe> <p> <label> Nick: <input type="text" name="nick" onkeyup="updateNick(value)"> </label> </p> <script> function updateNick(nick) { frames[0].postMessage('nick=' + nick, 'http://damowmow.com/playground/demos/gadget/gadget.html'); } </script> http://damowmow.com/playground/demos/gadget/gadget.html <p>Hello <span id=nick>Sir</span>!</p> <script> addEventListener('message', function (e) { if (e.origin == "http://www.whatwg.org" && e.data.substr(0,5) == "nick=") document.getElementById('nick').firstChild.data = e.data.substr(5); }, false); </script> Works in Safari, Firefox. Internet Explorer doesn't support DOM Events. But we can work around this by adding a shim, so that we can make this work in IE too: if (!window.addEventListener) window.addEventListener = function (n, f, c) { attachEvent('on' + n, function () { f(event) }); }; Works in IE. 3. localStorage Scenario: A text editor that stores the user's files client-side. Start with a simple text editor: <form name=editor> <p><textarea name=data></textarea></p> </form> Then add Open and Save buttons: <p> <label>Filename: <input name=filename></label> <input type=button value="Open" onclick="doOpen()"> <input type=button value="Save" onclick="doSave()"> </p> Saving: <script> function doSave() { var filename = document.forms.editor.filename.value; var data = document.forms.editor.data.value; localStorage.setItem('file-' + filename, data); } </script> Opening: function doOpen() { var filename = document.forms.editor.filename.value; document.forms.editor.data.value = localStorage.getItem('file-' + filename); } Works in IE and Safari. Demo: 1. filename = first.txt 2. data = Hello World! 3. save 4. open "earlier.txt" 5. open "first.txt" 4. sessionStorage Scenario: Multi-page form that doesn't involve server-side state until the last page. Let's say, a kind of madlibs wizard. Let's create a form for the first step: <form action="step2.html" method=post> <p> <label> Noun: <input name=n1> </label> </p> <p> <input type="submit" value="Next..."> </form> But we don't want to rely on the server, so we have to save the data: onsubmit="save(n1)" We'll put the script in an external file so that each step of the wizard can reuse it: <script src="script.js"></script> The script is just: function save(element) { localStorage.setItem(element.name, element.value); } Steps 2 and 3 and the final page of the wizard which uses the data were prepared earlier, but are basically the same. Try it in Safari (face red pepper). Now try it in two windows at once (date, ugly, insult; volume, down, geezer, then click next on the first, then on the second). To fix this we use sessionStorage instead of localStorage. Fix script.js and end.html. Now try it in two windows again (cheese blue mould; mood up demo). Works in IE, Firefox, Safari. (opinion around argument; frown upside-down joke) 5. Drag and Drop Scenario: Dragging icons around. I have three images: <style> img { height: 4em; } </style> <p> <img src="spam.gif" id=spam alt="Spam"> <img src="egg.gif" id=egg alt="Egg"> <img src="cat.gif" id=cat alt="Cat"> </p> To each image we add: ondragstart="drag(this, event)" ...with: <script> function drag(target, e) { e.dataTransfer.setData('Text', target.id); } </script> Now we need somewhere to drag them to: <style> div { margin: 1em 2em; border: solid black; text-align: center; height: 9em; width: 12em; float: left; } p { clear: both; margin: 1em 3em; } </style> ... <div> <p>Good</p> </div> <div> <p>Bad</p> </div> ... To make them drag targets, we add the following to each <div>: ondragenter="return false" ondragover="return false" ondrop="drop(this, event)" ...with: <script> function drop(target, e) { target.appendChild(document.getElementById(e.dataTransfer.getData('Text'))); e.preventDefault(); } </script> Works in IE, Safari, Firefox. 6. onhashchange Scenario: Reacting to changes in the fragment identifier so that you can use normal links to affect the application view, just like scrolling in a document. <p><a href="#a">A</a> <a href="#b">B</a></p> <p id="message">None</p> onload="update()" onhashchange="update()" <script> function update() { if (location.hash) { var msg = document.getElementById('message'); msg.firstChild.data = location.hash.substr(1); } } </script> Works in IE. 7. New widgets Scenario: Creating user interfaces more expressive than HTML4 allowed, without thousands of lines of JavaScript. Range control. <input type="range"> <div>HTML5</div> oninput="document.getElementsByTagName('div')[0].style.fontSize = value + 'px'"> Works in Opera, Safari. Or you could change the contents: <p>HTML5 will be ready in the year <span></span></p> oninput="document.getElementsByTagName('span')[0].textContent = value"> Works in Opera, Safari. Of course we need to tweak the range to make this work: min=2000 max=2050 value=2008 Works in Opera, Safari. Now the script here is kind of a pain, so we've introduced something that will make that easier too: Wrap: <form> ... </form> Replace <span> with: <output output=year> ... </output> oninput="year.value = value"> Works in Opera. Of course if we're picking a date, we should be using a date picker, not a range control. HTML5 has that too: <input type=date oninput="year.value = value"> Works in Opera. That shows the whole date selected, but we can pick out the year: <input type=date oninput="year.value = valueAsDate.getYear()"> The valueAsDate value returns a Date object. Works in Opera. We also have other controls: <p><label> URL: <input type="url"></label></p> <p><label> E-mail: <input type="email"></label></p> Works in Opera. (demo URL autocompletion with whatwg.org) The controls can be used with CSS: <style> :invalid { background: red; color: white; } </style> Works in Opera. (demo e-mail with user@example.com) (Delete those controls.) We also have combo-box controls: <p><label> Favorite Color: <input list=colors></label></p> <datalist id=colors> <option>Red <option>Orange <option>Yellow <option>Green <option>Blue <option>Violet </datalist> Works in Opera. (demo with selecting Orange then typing Indigo) (Delete those controls.) You can also mark a control as required, so that when you submit the form, if it's not selected, the browser will complain: <p><label> Query: <input name=q required></label></p> <p><input type=submit></p> Works in Opera. (demo with selecting Orange then typing Indigo) Notice how it is red straight away because it's required but not yet filled in, and thus invalid. Demo trying to submit without typing a value. (Delete the style element, delete the required attribute, switch to Safari.) Should just be: <form> <p><label> Query: <input name=q autofocus></label></p> <p><input type=submit></p> </form> Reload, showing that the control isn't focused by default. We can autofocus: ... autofocus Works in Safari. (demo by reloading again) 9. <canvas> Scenario: A trippy graphical display. Start with a canvas: <canvas width="800" height="450"></canvas> Then add script: <script> var context = document.getElementsByTagName('canvas')[0].getContext('2d'); context.beginPath(); context.moveTo(context.canvas.width * Math.random(), context.canvas.height * Math.random()); context.lineTo(context.canvas.width * Math.random(), context.canvas.height * Math.random()); context.stroke(); </script> function line() { // current code } setInterval(line, 50); function blank() { context.fillStyle = 'rgba(0,0,0,0.1)'; context.fillRect(0, 0, context.canvas.width, context.canvas.height); } setInterval(blank, 40); context.strokeStyle = 'white'; context.lineWidth = 5 + Math.random() * 10; // remove moveTo()/lineTo() var lastX = 0; var lastY = 0; ... context.moveTo(lastX, lastY); lastX = context.canvas.width * Math.random(); lastY = context.canvas.height * Math.random(); context.bezierCurveTo(context.canvas.width * Math.random(), context.canvas.height * Math.random(), context.canvas.width * Math.random(), context.canvas.height * Math.random(), lastX, lastY); var hue = 0; ... hue = hue + 10*Math.random(); context.strokeStyle = 'hsl(' + hue + ', 50%, 50%)'; context.save(); context.translate(context.canvas.width/2, context.canvas.height/2); context.scale(0.9, 0.9); context.translate(-context.canvas.width/2, -context.canvas.height/2); ... context.restore(); Works in Safari, Opera, Chrome, Firefox. context.shadowColor = 'white'; context.shadowBlur = 10; Works in Safari. 10. Validation HTML5 also drops all the presentational attributes and tightens a lot of things up that HTML4 left vague. Google has started using HTML5 on some pages, for example: http://www.google.com/privacy Show View Source in Firefox, zoomed in. Show DOCTYPE. Show <meta charset>. Click Privacy Policy, show the source again. There is a validator available if you want to validate documents. http://html5.validator.nu/ Validate the privacy policy.