Save 37% off PRO during our Black Friday Sale! »

HTML5 Outliers

HTML5 Outliers

HTML5 isn't just video and canvas! There's a lot of clever related technology tucked away inside the mass of JavaScript specifications that aren't quite as sexy as a web socket making love to a canvas - but without a doubt, still useful and important to building web applications.This session will introduce you to some of those outliers, show you how they can be used and prepare you for making the most of what the browsers today can offer you.

C8b387c489181844b3ffc704fadc0f14?s=128

Remy Sharp

June 06, 2012
Tweet

Transcript

  1. HTML5 OUTLIERS REMY SHARP / @REM

  2. http://www.flickr.com/photos/12173213@N00/6410825167 I wanted to build apps that worked without the

    ball ache. Is that so unreasonable?
  3. '97 Yeah, I used to be thinner :(

  4. ๏JavaScript in the browser ๏Browser came preinstalled ๏Also discovered WSH

    / .hta ๏Made apps: wallpaper changer http://www.flickr.com/photos/43805896@N00/3657783366/
  5. ๏Data storage ๏Real-time notifications ๏Desktop integration ๏Access to hardware ๏Local

    "install" ๏Go naked http://www.flickr.com/photos/21966325@N00/537474857/
  6. caniuse.com

  7. STUFF YOU SHOULD DO TODAY AKA PROGRESSIVE ENHANCEMENT

  8. <!DOCTYPE html>

  9. JSON parsing

  10. Web Storage

  11. sessionStorage.state = ↵ JSON.stringify(app.state); localStorage.lastLogin; delete localStorage.user;

  12. http://www.flickr.com/photos/redux/6188900810 "we have to stop advocating localStorage as a great

    opportunity for storing data as it performs badly" http://rem.io/link/182
  13. Be sensible. Think: cookie killer. http://flickr.com/photos/41214178@N00/2822774896/

  14. Events!!! window.addEventListener('storage', sync);

  15. Web Forms

  16. /([\w-\.]+)@((?:[\w]+\.)+)([a-z]{2,4})/gi /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA- Valid email anyone?

  17. (\x22)))@((([a-z]|\d|[\u00A0-\uD7FF \uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d| [\u00A0-\uD7FF\uF900-\uFDCF\uFDF0- \uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF \uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d| [\u00A0-\uD7FF\uF900-\uFDCF\uFDF0- \uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF \uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]| [\u00A0-\uD7FF\uF900-\uFDCF\uFDF0- \uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF

    \uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]| [\u00A0-\uD7FF\uF900-\uFDCF\uFDF0- \uFFEF])))\.?$/ Valid email anyone?
  18. Valid email anyone? '@[10.10.10.10] user@[IPv6:2001:db8:1ff::a0b:dbd 0] "much.more\ unusual"@example.com "very.unusual.@.unusual.com"@exa mple.com

    "very.(),:;<>[]\".VERY.\"very@\\ \ \"very \".unusual"@strange.example.com 0@a !#$%&'*+-/=?^_`{}|~@example.org "()<>[]:;@,\\\"!#$%&'*+-/=? ^_`{}|\ \ \ \ \ ~\ \ \ \ \ \ \ ? \ \ \ \ \ \ \ \ \ \ \ \ ^_`{}| ~.a"@example.org ""@example.org postbox@com
  19. Valid email anyone? <input type=email>

  20. Make use of free validation

  21. History API

  22. None
  23. $('a[href^="/"]').click(function(e) { var target = e.currentTarget; if (!e.altKey && !e.ctrlKey

    && !e.metaKey && !e.shiftKey) { e.preventDefault(); url = target.pathname; navigate(url, { triggered: true }); } }); function navigate(url, data) { history.pushState(data, '', url); } window.onpopstate = function (event) { if (event.state.triggered) { ajaxLoad(location.pathname); } }
  24. $('a[href^="/"]').click(function(e) { var target = e.currentTarget; if (!e.altKey && !e.ctrlKey

    && !e.metaKey && !e.shiftKey) { e.preventDefault(); url = target.pathname; navigate(url, { triggered: true }); } }); function navigate(url, data) { history.pushState(data, '', url); } window.onpopstate = function (event) { if (event.state.triggered) { ajaxLoad(location.pathname); } } Select all internal links
  25. $('a[href^="/"]').click(function(e) { var target = e.currentTarget; if (!e.altKey && !e.ctrlKey

    && !e.metaKey && !e.shiftKey) { e.preventDefault(); url = target.pathname; navigate(url, { triggered: true }); } }); function navigate(url, data) { history.pushState(data, '', url); } window.onpopstate = function (event) { if (event.state.triggered) { ajaxLoad(location.pathname); } } If the user only clicked, ignore new tab clicks
  26. $('a[href^="/"]').click(function(e) { var target = e.currentTarget; if (!e.altKey && !e.ctrlKey

    && !e.metaKey && !e.shiftKey) { e.preventDefault(); url = target.pathname; navigate(url, { triggered: true }); } }); function navigate(url, data) { history.pushState(data, '', url); } window.onpopstate = function (event) { if (event.state.triggered) { ajaxLoad(location.pathname); } } Send the url path to our pushState function
  27. $('a[href^="/"]').click(function(e) { var target = e.currentTarget; if (!e.altKey && !e.ctrlKey

    && !e.metaKey && !e.shiftKey) { e.preventDefault(); url = target.pathname; navigate(url, { triggered: true }); } }); function navigate(url, data) { history.pushState(data, '', url); } window.onpopstate = function (event) { if (event.state.triggered) { ajaxLoad(location.pathname); } } Update window location and save the state data
  28. $(document).on('click', 'a[href^="/"]', function(e) { var target = e.currentTarget; if (!e.altKey

    && !e.ctrlKey && !e.metaKey && !e.shiftKey) { e.preventDefault(); url = target.pathname; navigate(url, { triggered: true }); } }); function navigate(url, data) { history.pushState(data, '', url); } window.onpopstate = function (event) { if (event.state.triggered) { ajaxLoad(location.pathname); } } Now when the user navigates to a url, or we manually push a new url (pushState), it fires popstate, and we ajaxLoad new content.
  29. ๏Build non-JS version ๏Detect history.pushState support ๏Progressively enhance ๏Pat yourself

    on the back
  30. EventSource

  31. EventSource ๏ Events emit from server ๏ Read only stream

    ๏ Simple API ๏ Possible to polyfill (so IE support)
  32. EventSource ๏Supports connection dropping and resuming with Last-Event-ID ๏Supports bespoke

    events other than `message` ๏CORS is coming (x-domain SSE)
  33. None
  34. var es = new EventSource('/console'); es.onmessage = function (event) {

    var data = JSON.parse(event.data); execute(data.command); };
  35. var es = new EventSource('/console'); es.onmessage = function (event) {

    var data = JSON.parse(event.data); execute(data.command); }; // custom message type es.addEventListener('reload',function() { reloadData(); });
  36. Dnd / File API for uploads

  37. None
  38. None
  39. "HTML5 drag and drop module is not just a disaster

    it’s a fucking disaster" http://rem.io/link/228 http://www.flickr.com/photos/redux/4640052438/
  40. var root = document.documentElement; root.addEventListener('dragover', cancel, false); root.addEventListener('dragend', cancel, false);

    root.addEventListener('drop', drop, false); function cancel(event) { event.preventDefault(); } function drop(event) { cancel(event); readFiles(event.dataTransfer.files); }
  41. var root = document.documentElement; root.addEventListener('dragover', cancel, false); root.addEventListener('dragend', cancel, false);

    root.addEventListener('drop', drop, false); function cancel(event) { event.preventDefault(); } function drop(event) { cancel(event); readFiles(event.dataTransfer.files); }
  42. var root = document.documentElement; root.addEventListener('dragover', cancel, false); root.addEventListener('dragend', cancel, false);

    root.addEventListener('drop', drop, false); function cancel(event) { event.preventDefault(); } function drop(event) { cancel(event); readFiles(event.dataTransfer.files); }
  43. var root = document.documentElement; root.addEventListener('dragover', cancel, false); root.addEventListener('dragend', cancel, false);

    root.addEventListener('drop', drop, false); function cancel(event) { event.preventDefault(); } function drop(event) { cancel(event); readFiles(event.dataTransfer.files); }
  44. Step #2 File API http://www.flickr.com/photos/98411817@N00/231524220/

  45. function readFiles(files) { for (var i = 0; i <

    files.length; i++) { preview(files[i]); } } function preview(file) { var reader = new FileReader(); reader.onload = function (event) { var image = new Image(); image.src = event.target.result; holder.appendChild(image); }; reader.readAsDataURL(file); }
  46. function readFiles(files) { for (var i = 0; i <

    files.length; i++) { preview(files[i]); } } function preview(file) { var reader = new FileReader(); reader.onload = function (event) { var image = new Image(); image.src = event.target.result; holder.appendChild(image); }; reader.readAsDataURL(file); }
  47. function readFiles(files) { for (var i = 0; i <

    files.length; i++) { preview(files[i]); } } function preview(file) { var reader = new FileReader(); reader.onload = function (event) { var image = new Image(); image.src = event.target.result; holder.appendChild(image); }; reader.readAsDataURL(file); }
  48. upload!!!

  49. var formData = new FormData();

  50. var formData = new FormData(); for (var i = 0;

    i < files.length; i++) { formData.append('file', files[i]); }
  51. var formData = new FormData(); for (var i = 0;

    i < files.length; i++) { formData.append('file', files[i]); } // now post a new XHR request var xhr = new XMLHttpRequest(); xhr.open('POST', url);
  52. var formData = new FormData(); for (var i = 0;

    i < files.length; i++) { formData.append('file', files[i]); } // now post a new XHR request var xhr = new XMLHttpRequest(); xhr.open('POST', url); xhr.upload.onprogress = function (event) { if (event.lengthComputable) { var complete = (event.loaded / event.total ⏎ * 100 | 0); progress.value = complete; } }
  53. var formData = new FormData(); for (var i = 0;

    i < files.length; i++) { formData.append('file', files[i]); } // now post a new XHR request var xhr = new XMLHttpRequest(); xhr.open('POST', url); xhr.upload.onprogress = function (event) { if (event.lengthComputable) { var complete = (event.loaded / event.total ⏎ * 100 | 0); progress.value = complete; } } xhr.send(formData);
  54. None
  55. TOMORROW http://www.flickr.com/photos/nasamarshall/5654415647

  56. dataset & classList

  57. <img class="boss-baddie" data-health="13" data-damage="5" src="..."> <script> var boss = document.getElementsByClassName('boss-baddie');

    if (gotHit) { me.health -= boss.dataset.damage; } else if (hitBaddie) { boss.dataset.health -= 1; if (boss.dataset.health === 0) { boss.classList.add('dead'); } } </script>
  58. <img class="boss-baddie" data-health="13" data-damage="5" src="..."> <script> var boss = document.getElementsByClassName('boss-baddie');

    if (gotHit) { me.health -= boss.dataset.damage; } else if (hitBaddie) { boss.dataset.health -= 1; if (boss.dataset.health === 0) { boss.classList.add('dead'); } } </script> element.dataset
  59. <img class="boss-baddie" data-health="13" data-damage="5" src="..."> <script> var boss = document.getElementsByClassName('boss-baddie');

    if (gotHit) { me.health -= boss.dataset.damage; } else if (hitBaddie) { boss.dataset.health -= 1; if (boss.dataset.health === 0) { boss.classList.add('dead'); } } </script> element.classList
  60. element.classList querySelectorAll == jQuery? +

  61. http://www.flickr.com/photos/ilmatte81/4052670882/ Fullscreen

  62. None
  63. ๏ requestAnimationFrame ๏ WebGL ๏ Blobs (with urls) ๏ <datalist>

  64. SOOOOOOOOOOOOON http://www.flickr.com/photos/altoexyl/3840879992

  65. REAL-TIME COMMUNICATION

  66. None
  67. None
  68. ๏ WebRTC - audio ๏ Web Audio/Audio Data ๏ WebGL

    ๏ Full Screen
  69. CHROMELESS http://www.flickr.com/photos/daveynin/4899888908

  70. None
  71. ๏Not headless ๏Not just fullscreen ๏Sans-chrome ๏Installable ๏Business as usual:

    HTML, CSS, JS
  72. Windows: .hta IE7 FTW!!!

  73. Chrome: app shortcuts http://rem.io/link/185

  74. Opera Widgets

  75. Windows 8

  76. WebRT http://rem.io/link/186 http://rem.io/link/187 navigator.mozApps.install { "version": "1.0", "name": "ABBAInfo",

  77. .webapp?

  78. DO NOT UNDERESTIMATE USER EXPERIENCE. GOOD WEB SITES DO NOT

    AUTOMATICALLY MAKE GOOD APPLICATIONS.
  79. PARTING THOUGHTS 1. START USING TECHNOLOGY AVAILABLE TO YOU 2.

    VIABILITY COMES FROM MULTIPLE IMPLEMENTATIONS 3. DEMAND MORE ACCESS TO APIS 4. HTML5 = JAVASCRIPT
  80. OTHERWISE: ROCK ON. @REM LEFTLOGIC.COM