Upgrade to Pro — share decks privately, control downloads, hide ads and more …

HTML5 Workshop - PHP|Tek

HTML5 Workshop - PHP|Tek

With the rise of advanced desktop and mobile browsers, high performance javascript engines, and ever increasing networking bandwidth, traditionally ‘frontend’ skills are in more demand than ever. PHP developers are increasingly finding themselves needing these skills more and more to remain competitive. This workshop will cover new features introduced in HTML5 and CSS3, how to use them today with modern browsers (and fallbacks), as well as tips and tricks to save time and do amazing things. It will also cover a refresher on JavaScript basics and dive into recent advances in libraries and coding techniques that power modern interactive web applications. The workshop will walk through from start to finish a simple web application utilizing as many HTML5, CSS3, and JavaScript techniques as possible. By the end the attendees can expect to have a grasp on things ranging from new tags, new style properties, advanced selectors, event-driven asynchronous JavaScript programming, new services such as GeoLocation, and much more.

jakefolio

May 22, 2012
Tweet

More Decks by jakefolio

Other Decks in Programming

Transcript

  1. HTML Working Group Created World Wide Web Consortium (W3C) Created

    CSS 1.0 Introduced HTML 3.2 and 4.0 release XHTML 1.0 released 1994 1997 1999 Tuesday, May 22, 12
  2. First draft of HTML5 Released Apple, Mozilla, and Opera form

    WHATWG Web Hypertext Application Technology Working Group 2004 2008 Tuesday, May 22, 12
  3. • article • aside • audio • canvas • command

    • datalist • details • embed • figcaption • figure • footer • header • hgroup • keygen • mark • meter • nav • output • progress • rp • rt • ruby • section • source • summary • time • video • wbr New HTML Elements Tuesday, May 22, 12
  4. • article • aside • audio • canvas • command

    • datalist • details • embed • figcaption • figure • footer • header • hgroup • keygen • mark • meter • nav • output • progress • rp • rt • ruby • section • source • summary • time • video • wbr New HTML Elements Tuesday, May 22, 12
  5. LONG LIVE THE DIV! An article element is "independent" in

    that its contents could stand alone, for example in syndication. However, the element is still associated with its ancestors; for instance, contact information that applies to a parent body element still covers the article as well. Tuesday, May 22, 12
  6. figure/figcaption <figure> <img src="/some/photo.jpg" alt="This Photo Blows Your Mind!"> <figcaption>Explaining

    the awesomeness of this photo</figcaption> </figure> Tuesday, May 22, 12
  7. hgroup <hgroup> <h1>Welcome to HTML5 at PHP Tek</h1> <h3>Prepare for

    Awesomeness</h3> </hgroup> Tuesday, May 22, 12
  8. meter/progress <meter min="0" max="20" value="3" low="5" high="15">Question 3</meter> <meter min="0"

    max="20" value="6" low="5" high="15">Question 6</meter> <meter min="0" max="20" value="16" low="5" high="15">Question 16</meter> <progress max="100" min="0" value="25">25%</progress> <progress max="100" min="0">Loading</progress> Tuesday, May 22, 12
  9. • tabindex • hidden • contextMenu • spellCheck • data-*

    • ContentEditable • draggable • dropzone • microdata attributes • ARIA New HTML Attributes Tuesday, May 22, 12
  10. New HTML Attributes • tabindex • hidden • contextMenu •

    spellCheck • data-* • ContentEditable • draggable • dropzone • microdata attributes • ARIA Tuesday, May 22, 12
  11. Tabindex <input type="input" name="first_name" placeholder="First Name" tabindex="2" /> <input type="input"

    name="last_name" placeholder="Last Name" tabindex="3" /> <input type="email" name="email" placeholder="[email protected]" tabindex="1" /> <a href="#" tabindex="-1" class="screen-reader">Only for screen readers</a> <style> .screen-reader { display: inline-block; overflow:hidden; text-indent: 100%; white-space: nowrap; } </style> Tuesday, May 22, 12
  12. data-* <img src="some-profile.jpg" data-id="35123" data-category="mobile" data-caption="Hello form Tek!" id="img-profile-35123"> <script>

    var pic = document.getElementById('img-profile-35123'); console.log('CAPTION: ' + pic.dataset.caption); </script> Tuesday, May 22, 12
  13. ContentEditable <h1>To Do List</h1> <ul contenteditable> <li>Get Badge from Keith</li>

    <li>Show up Daniel in Javascript</li> <li>MOAR COFFEE</li> <ul> Tuesday, May 22, 12
  14. Draggable <div id="region"></div> <div draggable="true" class="dragme">Hello</div> <div draggable="true" class="dragme">World</div> <script>

    var region = document.getElementById('region'); var draggables = document.querySelectorAll('div[draggable]'); for (var i = 0; i <= draggables.length-1; i++) { draggables[i].addEventListener('dragstart', function(e) { this.style.opacity = 0.4; }); draggables[i].addEventListener('dragend', function(e) { this.style.opacity = 1; }); } </script> Tuesday, May 22, 12
  15. • email • tel • url • search • color

    • number • range • date New Form Inputs Tuesday, May 22, 12
  16. • email • tel • url • search • color

    • number • range • date New Form Inputs Tuesday, May 22, 12
  17. Range/Number <input type="range" name="budget" value="3" min="0" max="5" step="1" /> <input

    type="number" name="budget" value="3" min="0" max="5" step="1"> Tuesday, May 22, 12
  18. • placeholder • autofocus • autocomplete • spellcheck • maxlength

    • required • pattern • novalidate • formaction • formmethod • formtarget • form • accept • multiple Attributes Validation Overrides Files New Form Attributes Tuesday, May 22, 12
  19. Create Basic Video <video id="nyan-player" width="320" height="240" poster="images/nyan-thumb.png" autoplay controls

    loop preload> <source src="videos/nyan-cat.mp4" type="video/mp4"></source> <source src="vidoes/nyan-cat.ogv" type="video/ogg"></source> <source src="videos/nyan-cat.webm" type="video/webm"></source> <!-- Optional: Add subtitles for each language --> <track kind="subtitles" src="subtitles.srt" srclang="en" /> <!-- Optional: Add chapters --> <track kind="chapters" src="chapters.srt" srclang="en" /> <!-- Flash fallback goes here --> </video> Tuesday, May 22, 12
  20. h.264 OGG/OGV WEBM WMV MP3 Safari X X X Chrome

    X X X X Firefox X X IE (9+) X X X X Opera X X IOS X X Audio/Video Attributes Tuesday, May 22, 12
  21. Audio/Video API Audio/Video Events canplay, canplaythrough, playing, waiting, loadedmetadata, loadeddata

    play/pause volume currentTime/duration canPlayType muted/paused Tuesday, May 22, 12
  22. Audio/Video API var player = document.getElementById('nyan-player'); player.addEventListener('canplay', function() { this.volume

    = 0.7; this.play(); }); function rewind() { player.currentTime -= 15; } function fastForward() { player.currentTime += 15; } function togglePlay(e) { if (player.readyState <= 1) return false; if(player.paused) { player.play(); e.target.innerText = 'Pause'; } else { player.pause(); e.target.innerText = 'Play'; } } Tuesday, May 22, 12
  23. #CSS .menu li a { color: blue; } <ul class="menu">

    <li><a href="#">Drop Down</a> <ul> <li><a href="#">Sub #1</a></li> <li><a href="#">Sub #2</a></li> </ul> </li> </ul> Select all the descendants of the specified element Descendant Selector Tuesday, May 22, 12
  24. #CSS ul li { color: green; } ul > li

    { color: red; } <ul> <li>Top Level</li> <li>Top Level <ol> <li>Sub Level</li> <li>Sub Level</li> </ol> </li> </ul> This selector matches all elements that are the immediate children of a specified element. * Only the “sub level” text will be red. Child Combinator Selector Tuesday, May 22, 12
  25. #CSS .module { margin: 0; } .module + .module {

    margin-left: 25px; } <div class="module"> <h2>Module</h2> </div> <div class="module"> <h2>Module #2</h2> </div> <div class="module"> <h2>Module #3</h2> </div> The adjacent sibling selector selects all elements that are the adjacent siblings of a specified element. * Module #2 and #3 will have margin applied. Adjacent Sibling Selector Tuesday, May 22, 12
  26. #CSS h2 ~ p { color: red; } <h1>Primary Headline</h1>

    <p>General Paragraph - Not Selected</p> <h2>Secondary Headline</h2> <p>Will be Selected</p> <p>Will be Selected</p> <div>Extra Content</div> <p>Will be Selected</p> The selector matches elements that are siblings of a given element. * Every element after the h2 will be selected CSS3 General Sibling Tuesday, May 22, 12
  27. It’s a numbers game. 100 #header .my-class [alt] div 10

    1 Points Per Selector :after CSS Specificity Tuesday, May 22, 12
  28. Who Wins?? ? WINNER #1 #slider #2 .two-col .container .primary

    .content ul CSS Face Off Tuesday, May 22, 12
  29. Who Wins?? 1 WINNER #1 #slider 100 Points #2 .two-col

    .container .primary .content ul 41 Points CSS Face Off Tuesday, May 22, 12
  30. Let’s make it more challenging! ? WINNER #1 .container .external

    #2 .container a[rel="external"] CSS Face Off Tuesday, May 22, 12
  31. Who Wins?? 2 WINNER #1 .container .external 020 Points #2

    .container a[rel="external"] 021 Points CSS Face Off Tuesday, May 22, 12
  32. #CSS body.two-col { ... } body.two-col .container { ... }

    body.two-col .container .primary { ... } Do NOT write your css like you’re following your HTML structure! Selector Flow Tuesday, May 22, 12
  33. #CSS img[alt] { border: 1px green solid; } <img src="images/random.jpg"

    alt="Look At Me"> <img src="images/bad.jpg"> Check if attribute exists. Attribute Selector Tuesday, May 22, 12
  34. #CSS div[class|="widget"] { ... } <div class="page"> <div class="homepage-widget-24"></div> <div

    class="homepage-widget-1" data-id="1"> Widget id of 1 </div> </div> “Slug” selector * All “widgets” will be selected Child Selectors Tuesday, May 22, 12
  35. #CSS div[class|="widget"] { ... } <div class="page"> <div class="homepage-widget-24"></div> <div

    class="homepage-widget-1" data-id="1"> Widget id of 1 </div> </div> “Slug” selector * All “widgets” will be selected Child Selectors Tuesday, May 22, 12
  36. #CSS div[class*="foo"] { color: red; } <div class="foobar"> Apply to

    this div </div> “Contains” selector CSS3 Attribute Selector Tuesday, May 22, 12
  37. #CSS a[href^="mailto:"] { background: url(/images/icn-email.gif); } <a href="/portfolio">Portfolio</a> <a href="/faq">FAQ</a>

    <a href="mailto:[email protected]">Contact</a> “Begins” with selector CSS3 Child Selectors Tuesday, May 22, 12
  38. #CSS [class$="right"] { _display: inline; } *[class$="right"] { _display: inline;

    } Anti-pattern * Universal selector will be used. Attribute Selectors Tuesday, May 22, 12
  39. #CSS div p:first-child { color: #333; font-size: 14px; } <div>

    <p>Important Intro</p> <p>Regular Content</p> </div> :first-child, :last-child and :only-child :first-child Tuesday, May 22, 12
  40. #CSS .menu li { border-bottom: 1px solid #ccc; } .menu

    li:last-child { border: 0; } <ul class="menu"> <li>First Menu element</li> <li>Menu element</li> <li>Last Menu element</li> </ul> :first-child, :last-child and :only-child CSS3 :last-child Tuesday, May 22, 12
  41. #CSS tr:nth-child(odd) { background: #ccc; } <table> <tr> <td>First Row</td>

    </tr> <tr> <td>Second Row</td> </tr> </table> :nth-* accepts 3 types of parameters: odd, even and equation(3n/3) CSS3 :nth-child/:nth-type Tuesday, May 22, 12
  42. :nth-* equation explained 3n (3x0) = 0 (no select) (3x1)

    = 3 (3x2) = 6 3n+1 (3x0) + 1 = 1 (3x1) + 1 = 4 (3x2) + 1 = 7 n+5 0 + 5 = 5 1 + 5 = 6 2 + 5 = 7 3n-1 (3x0) - 1= 0 (3x1) - 1= 2 (3x2) - 1= 5 :nth-child/:nth-type Tuesday, May 22, 12
  43. :nth-* equation examples odd 3 3n 3n+1 3n-1 n+3 1

    X X 2 X 3 X X X X 4 X X 5 X X X 6 X X 7 X X X 8 X X :nth-child/:nth-type Tuesday, May 22, 12
  44. #CSS div:nth-child(3n) { background: #ccc; } <div class="container"> <div class="widget"></div>

    <div class="widget"></div> <div class="widget">3n</div> <div class="widget"></div> <div class="widget"></div> <div class="widget">3n</div> </div> CSS3 :nth-child/:nth-type Tuesday, May 22, 12
  45. #CSS .widget:nth-last-child(3n) { background: #ccc; } <div class="container"> <div class="widget"></div>

    <div class="widget"></div> <div class="widget">3n</div> <div class="widget"></div> <div class="widget"></div> <div class="widget">3n</div> <div class="widget"></div> <div class="widget"></div> </div> :nth-last-child and :nth-last-of-type both start from the last element and move up. CSS3 :nth-child/:nth-type Tuesday, May 22, 12
  46. #CSS .widget:nth-child(3n) { background: #ccc; } <div class="container"> <div class="widget"></div>

    <p>Side Note</p> <p>Side Note</p> <div class="widget"></div> <div class="widget"></div> <p>Side Note</p> <div class="widget"></div> <p>Side Note</p> <div class="widget">3n</div> <div class="widget"></div> </div> Let’s mix it up! CSS3 :nth-child/:nth-type Tuesday, May 22, 12
  47. #CSS div:nth-of-type(3n) { background: #ccc; } <div class="container"> <div class="widget"></div>

    <p>Side Note</p> <p>Side Note</p> <div class="widget"></div> <div class="widget">3n</div> <p>Side Note</p> <div class="widget"></div> <p>Side Note</p> <div class="widget"></div> <div class="widget">3n</div> </div> Now with :nth-of-type CSS3 :nth-child/:nth-type Tuesday, May 22, 12
  48. #CSS input:not([type="radio"]):not([type="checkbox"]):not([type="submit"]): not([type="button"]):not([type="image"]) { border: 1px solid #ccc; border-radius: 5px;

    } <form action="/" method="post"> <p><label>Full Name:</label><input type="text" name="name" size="30"></p> <p><label>Opt-in:</label><input type="checkbox" name="optin" value="yes"></p> <p><input type="submit" name="frmSubmit"></p> </form> :not() - negation selector CSS3 Pseudo Selectors Tuesday, May 22, 12
  49. #CSS input:checked + label { border: 1px dashed #ccc; }

    input[type="text"]:disabled { background: rgba(10, 10, 10, 0.7); } input:required { font-weight: bold; } input:optional { color: green; } input:valid { box-shadow: 0 0 5px rgba(0, 0, 0, 0.4); } input:invalid { box-shadow: 0 0 5px red; } Form based selectors CSS3 Pseudo Selectors Tuesday, May 22, 12
  50. A pseudo-element is identified by using two colons (::). Available

    pseudo-elements: ::first-line, ::first-letter, ::before and ::after For compatibility purposes the the single colon (:) notation has been accepted. All new CSS3 only pseudo-elements, ::selection, are required to use double colon (::). Pseudo Elements Tuesday, May 22, 12
  51. #CSS .top { ... } .top:before { content: ""; display:

    block; position: absolute; bottom: -10px; left: 0; } .top:after { content: ""; display: block; position: absolute; bottom: -10px; right: 0; } :before and :after This is how CSS ribbons are created. Pseudo Elements Tuesday, May 22, 12
  52. #CSS ::-webkit-validation-bubble { ... } ::-webkit-validation-bubble-top-outer-arrow { ... } ::-webkit-validation-bubble-top-inner-arrow

    { ... } ::-webkit-validation-bubble-message { ... } Style form validation messages (webkit) CSS3 Pseudo Elements Tuesday, May 22, 12
  53. @font-face { font-family: 'ClarendonLTStdLight'; src: url('clarendonltstd-light-webfont.eot'); src: url('clarendonltstd-light-webfont.eot?#iefix') format('embedded-opentype'), url('clarendonltstd-light-webfont.woff')

    format('woff'), url('clarendonltstd-light-webfont.ttf') format('truetype'), url('clarendonltstd-light-webfont.svg#ClarendonLTStdLight') format('svg'); font-weight: normal; font-style: normal; } h1, h2, h3 { color: #2a2b2b; letter-spacing: 1px; line-height: 1.2em; font-family: 'ClarendonLTStdLight', Palatino, georgia, serif; margin-bottom: 8px; padding-bottom: 5px; } @font-face Example Tuesday, May 22, 12
  54. WOFF TTF OTF EOT SVG Safari X X X Chrome

    X X X Firefox X X X IE X X Opera X X X IOS X Font Support Tuesday, May 22, 12
  55. @font-face Gotchas Licensing is still a concern Rendering engines are

    inconsistent (ClearType) Tuesday, May 22, 12
  56. Spectrum Gradient .spectrum-solid { background: -webkit-linear-gradient(left, red 20%, blue 20%,

    blue 40%, green 40%, green 60%, yellow 60%, yellow 80%, orange 80% ); } Tuesday, May 22, 12
  57. Create a circle Defined Height and Width Border Radius of

    1/2 Height/Width .blog-posts .entry-date { background: #89897a; height: 70px; padding-top: 3px; text-align: center; width: 70px; border-radius: 35px; } Tuesday, May 22, 12
  58. Multiple Shadows Use keyword inset for inner shadows Comma separate

    multiple shadows Last shadow defined is the “lowest layer” .btn { box-shadow: inset 0 1px 0 rgba(255,255,255,.2), inset 0 -1px 0 rgba(0,0,0,.2), 0 1px 2px rgba(0,0,0,.25); } Tuesday, May 22, 12
  59. First seen in Firefox 4 was transforms. Transforms are often

    used in transitions. There are four different types of transforms: scale, rotate, skew and translate. transform: translate(-100px, -100px); transform: rotate(45deg); transform: scale(2); Tuesday, May 22, 12
  60. .button { background: #fff; color: #ee8637; font-size: 10px; opacity: 0.5;

    position: absolute; bottom: 5px; right: 10px; -webkit-transition: opacity 0.4s ease-in-out; } .button:hover { opacity: 0.8; } Basic Transition Tuesday, May 22, 12
  61. .speaker { background-color: rgba(241, 241, 235, 0.8); border: 6px solid

    #fafaf5; font: 30px "SteelfishExtraBold", "Lucida Grande", arial; overflow: hidden; text-indent: -9999px; text-shadow: 2px 1px 0 #8f2d0e; width: 216px; box-shadow: inset 0 0 15px rgba(0, 0, 0, 0.4); transition: all 0.5s ease-out; } Pseudo Elements .speaker:hover { text-indent: 0; box-shadow: inset 0 0 25px rgba(0, 0, 0, 0.8); } Tuesday, May 22, 12
  62. @-webkit-keyframes bounce { from, to { -webkit-animation-timing-function: ease-out; } 50%

    { bottom: 220px; -webkit-animation-timing-function: ease-in; } } Tuesday, May 22, 12
  63. @-webkit-keyframes spin { 0% { transform: rotate(45deg); -webkit-animation-timing-function: ease-out; }

    50% { transform: rotate(45deg); -webkit-animation-timing-function: ease-in; } 100% { transform: rotate(90deg); -webkit-animation-timing-function: ease-in-out; } } Tuesday, May 22, 12
  64. @media print { h1 { color: #000; } h2 {

    color: #333; } h3 { color: #666; } .sidebar { display: none; } } Print Media Query <link media="only print" rel="stylesheet" href="css/print.css"> Tuesday, May 22, 12
  65. <link media="only screen and (min-width:480px)" rel="stylesheet" href="css/small.css"> @media only screen

    and (min-width: 480px) { /* Style adjustments for viewports 480px and over */ } Using Media Queries Tuesday, May 22, 12
  66. Add Orientation @media only screen and (device-width: 320px) and (orientation:

    portrait) { /* Style adjustments for smartphones in portrait */ } @media only screen and (device-width: 480px) and (orientation: landscape) { /* Style adjustments for smartphones in portrait */ } Tuesday, May 22, 12
  67. This example targets retina display (iphone 4). The iphone 4

    will automatically scale your images in the background size specified. This leads to fuzzy images. @media -webkit-pixel-ratio: 2 { /* Style adjustments for retina display */ h1 { background-image: url(logo-highres.png); background-size: 300px 85px; } } Tuesday, May 22, 12
  68. Ethan Marcotte first proposed the idea of responsive design with

    his article “Fluid Grids” on A list Apart iphone released Ethan Marcotte officially names his concept as “Responsive Design” 2007 2009 2010 Tuesday, May 22, 12
  69. It’s impossible to know all of the devices our content

    is displayed on. Sites should be built with content in mind and not the medium. Tuesday, May 22, 12
  70. https://speakerdeck.com/u/malarkey/p/fashionably-flexible- responsive-web-design-full-day-workshop-1 320 720 1024 Popular tablets and desktops iPhone,

    android and other smartphones Netbooks and tablet orientations Major Breakpoints Tuesday, May 22, 12
  71. var items = document.querySelectorAll('.menu li'); var items = $('.menu li');

    var subItems = items[0].querySelectorAll('li'); var subItems = $('.menu li').find('li'); Tuesday, May 22, 12
  72. // Find the latest tweet var latestTweet = document.querySelector('#latest-tweet'); //

    jQuery version: $('#latest-tweet').first(); for item in items { // Log the content of element console.log(item.innerHTML); // Output the style object console.log(item.style); } Tuesday, May 22, 12
  73. // Check if localStorage is available if (typeof window.localStorage ==

    'object' && window.localStorage != null) { var store = window.localStorage; try { store.setItem('cow', 'moo'); } catch(e) { // Out of storage space? if (e == QUOTA_EXCEEDED_ERR) { console.log('ERROR: Local Storage is out of space!'); } } } Tuesday, May 22, 12
  74. var status = document.getElementById('status'); // Change status text status.innerText =

    store.getItem('cow'); status.innerText = store['cow']; status.innerText = store.cow; delete store['cow']; // Delete all of localstorage store.clear(); Tuesday, May 22, 12
  75. LocalStorage Gotchas - HTTP vs. HTTPS localstorage - store seperately

    (including incognito for chrome) - No default expiration. - Only support strings as values - SUPPORT: All modern browsers and IE8+ - POLYFILL: Use lawnchair for storage. Tuesday, May 22, 12
  76. // Check if geolocation is supported if (navigator.geolocation) { //

    Geolocation Supported! } else { // Geolocation not supported } Tuesday, May 22, 12
  77. var geolocWatch = geoloc.watchPosition(function(pos) { // Successfully changed position position

    = [pos.coords.latitude, pos.coords.longitude]; } errorHandler, // Options { enableHighAccuracy: true, maximumAge: 30000, timeout: 27000 } ); var geoloc = navigator.geolocation; Tuesday, May 22, 12
  78. var ws = new WebSocket('ws://html5rocks.websocket.org/echo'); // Show current Ready State

    console.log(ws.readyState); CONSTANTS: CONNECTING = 0 OPEN = 1 CLOSING = 2 CLOSED = 3 Tuesday, May 22, 12
  79. // When the connection is open, send data to the

    server ws.onopen = function () { ws.send('Ping'); // Send the message 'Ping' to server }; // Log errors ws.onerror = function (error) { console.log('WebSocket Error ' + error); }; // Log messages from the server ws.onmessage = function (e) { console.log('Server: ' + e.data); }; Tuesday, May 22, 12
  80. if (window.WebSocket) { // Supported var ws = new WebSocket('ws://html5rocks.websocket.org/echo');

    // Show current Ready State console.log(ws.readyState); // When the connection is open, send some data to the server ws.onopen = function () { ws.send('Ping'); // Send the message 'Ping' to the server }; // Log errors ws.onerror = function (error) { console.log('WebSocket Error ' + error); }; // Log messages from the server ws.onmessage = function (e) { console.log('Server: ' + e.data); }; // Say hello ws.send('Hello World'); // Close the connection ws.close(); } Tuesday, May 22, 12
  81. • caniuse.com/ - Browser Support • html5please.com/ - Responsibly Use

    HTML5 • http://wufoo.com/html5 - HTML5 Forms • http://diveintohtml5.info - De Facto HTML5 starter guide Great Resources Tuesday, May 22, 12
  82. • Photoshop Style Editor: http://layerstyles.org/ builder.html • Button Generator: http://css3button.net/

    • Gradient Generator: http://gradients.glrzad.com/ • CSS3 Tool (all in one): http://css3generator.com/ • Browser Prefixer: http://prefixr.com/ Generators/Tools Tuesday, May 22, 12
  83. "Foo" + "Bar"; //"FooBar" var str = "Lorem Ipsum Dolor

    Sit Amet"; str.toLowerCase(); //"lorem ipsum dolor sit amet" str.toUpperCase(); //"LOREM IPSUM DOLOR SIT AMET" str.split(" "); //["Lorem", "Ispum", "Dolor", "Sit", "Amet"] str.substring(6,9); //"Ips" new String("Lorem Ipsum Dolor Sit Amet") == str; //true Strings Tuesday, May 22, 12
  84. parseInt("56"); //56 parseInt("42.567"); //42 parseInt("asdf"); //NaN parseInt("5a6"); //5 parseFloat("24.68"); //24.68

    parseFloat("asdf"); //NaN parseFloat("24a"); //24 String to Number Tuesday, May 22, 12
  85. Objects •“Dictionary” / “Associative Array” •Key: Value or 'Key': Value

    •Without ': A-Z0-9 only •Does not keep intrinsic ordering •Accessed keys using . (dot) or [] notation Tuesday, May 22, 12
  86. var object = { foo: 'value', 'complex key': 0, bar:

    { nested: true } }; object.foo; //'value' object.['complex key']; //0 object.bar.nested; //true object.bar['nested']; //true object['bar'].nested; //true object['bar']['nested']; //true Objects Tuesday, May 22, 12
  87. in or hasOwnProperty() •Tough call: •.hasOwnProperty() more consistent •in checks

    inherited properties •Used in for loop Tuesday, May 22, 12
  88. var test = { foo: 'value', bar: 'value', baz: 'value'

    } for (var key in test) { console.log(key + ": " + test[key]); } //PRINTS: //foo: value //bar: value //baz: value in Tuesday, May 22, 12
  89. Arrays •Special object •Numerical keys only •Keeps intrinsic ordering •Short

    ([]) and Long (new Array()) syntax Tuesday, May 22, 12
  90. var arrayShort = [ 'one', 'two' ]; arrayShort[2] = 'three';

    var arrayLong = new Array(); arrayLong[0] = 'one'; arrayLong[1] = 'two'; arrayLong[2] = 'three'; //arrayShort: ["one", "two", "three"] //arrayLong: ["one", "two", "three"] Arrays Tuesday, May 22, 12
  91. var arr = [1,2,3,4,6]; arr.indexOf(2); //1 arr.join(':'); //"1:2:3:4:6" arr.pop(); //6

    //[1,2,3,4] arr.push(7); //5 //[1,2,3,4,7] arr.reverse(); //[7,4,3,2,1] arr.shift(); //1 //[2,3,4,7] arr.unshift(8); //5 //[8,2,3,4,7] arr.slice(1); //[2,3,4,7] arr.slice(1,3); //[2,3] arr.slice(-3); //[3,4,7] arr.slice(-3,-1); //[3,4] Arrays Tuesday, May 22, 12
  92. delete •Removes element from an object •“Removes element from an

    array” •Not really, just sets it to undefined Tuesday, May 22, 12
  93. Functions •Are Objects as well •“Elevated” •You can use a

    named function before it is defined in code •Function definitions are elevated to the top Tuesday, May 22, 12
  94. function Foo() { //... } Foo(); //valid Bar(); //valid function

    Bar() { //... } Functions Tuesday, May 22, 12
  95. function Foo() { } Foo.bar = "value"; 'bar' in Foo;

    //true Foo.bar == "value"; //true Functions Tuesday, May 22, 12
  96. Function Arguments •No way to assign default arguments •But arguments

    are not required •If an argument is not specified, it is set to undefined Tuesday, May 22, 12
  97. arguments •A special variable found inside a function •A not-quite

    array object containing all the function arguments Tuesday, May 22, 12
  98. function sum() { var x = 0; for (var i

    = 0; i < arguments.length; ++i) { x += arguments[i]; } return x; } sum(1, 2, 3); //6 arguments Tuesday, May 22, 12
  99. typeof true; //"boolean" typeof 12; //"number" typeof "string"; //"string" typeof

    []; //"object" typeof {}; //"object" typeof NaN; //"number" typeof null; //"object" typeof undefined; //"undefined" function Foo() {} typeof Foo; //"function" typeof Tuesday, May 22, 12
  100. Comparison •a == b / a != b •A and

    B compared by value alone •1 == “1” evaluates to true •a === b / a !== b •A and B compared by value and by type •1 === “1” evaluates to false Tuesday, May 22, 12
  101. window, document •Built in, global, Objects •window •Provides access to

    the browser window •The “global” object: foo === window.foo •Things like window.location.href, etc •document •Provides access to the current DOM Tuesday, May 22, 12
  102. Closures •First-Class •Can assign functions to variables, pass as arguments

    and return as values •Anonymous •Not required to have a name •A function that “closes over” variables defined outside itself Tuesday, May 22, 12
  103. function Foo() { var count = 0; return function() {

    count = count + 1; return count; }; } var bar = Foo(); bar(); //1 bar(); //2 bar(); //3 Closures Tuesday, May 22, 12
  104. function createAdder(amount) { return function(input) { return input + amount;

    }; } var add2 = createAdder(2); add2(2); //4 add2(8); //10 var add3 = createAdder(3); add3(3); //6 add3(7); //10 Closures Tuesday, May 22, 12
  105. (function(exports, undefined){ //ALL your code here var localVar = "bar"

    globalVar = "baz"; exports.foo = "bat"; })(window); alert(localVar); //error alert(globalVar); //"baz" alert(window.globalVar); //"baz" alert(foo); //"bat" alert(window.foo); //"bat" Module Pattern BEWARE: export (singular) is a reserved word in Safari Tuesday, May 22, 12
  106. Global & Local •Functions are the only way to create

    new scopes •Variables defined with var are local •Variables defined without var are global •Global variables are members of window Tuesday, May 22, 12
  107. var outerScope = 10; var outerScope2 = 10; function Foo()

    { var outerScope = 20; var innerScope = 20; globalVariable = 30; outerScope2 = 40; } Foo(); alert(outerScope); //10 alert(outerScope2); //40 alert(innerScope); //error alert(globalVariable); //30 Global & Local Tuesday, May 22, 12
  108. function Foo() { var baz = 1; function Bar() {

    return baz; } return Bar(); } Foo(); //1 Lexical Scoping function Foo() { var baz = 1; return Bar(); } function Bar() { return baz; } Foo(); //baz is not defined Tuesday, May 22, 12
  109. Named functions are parsed and made available before general evaluation

    (thus “hoisted” to the top of the file). Anonymous functions, or functions assigned to variables, require evaluation before they become available foo(); //called foo! function foo() { console.log('called foo!'); } foo(); //called foo! bar(); //undefined is not a function var bar = function() { console.log('called bar!'); } bar(); //called bar! Hoisting Tuesday, May 22, 12
  110. function makeAdder(a) { return function(b) { return a+b; } }

    var two = makeAdder(2); two(1); //3 two(2); //4 two(3); //5 Practical: Currying Tuesday, May 22, 12
  111. this •Trips everyone up •Special variable used within a function

    •Refers to the “contextual object” •Changes based on where a function executes Tuesday, May 22, 12
  112. var Foo = { bar: "bar", baz: function() { return

    this.bar; } }; Foo.baz(); //"bar" Foo.bar = "bat"; Foo.baz(); //"bat" var baz = Foo.baz; baz(); //undefined this Tuesday, May 22, 12
  113. var Foo = { bar: "bar", baz: function() { return

    this.bar; } }; Foo.bat = function() { return this.bar + "bat"; }; Foo.bat(); //"barbat" this Tuesday, May 22, 12
  114. call & apply •Methods in the function prototype •Change the

    context in which a function executes! Tuesday, May 22, 12
  115. var Foo = { bar: "bar", baz = function(param1, param2)

    { return this.bar + param1 + param2; } }; var Foo2 = { bar: "123" }; Foo.baz("baz", "bat"); //"barbazbat" Foo.baz.apply(Foo2, "baz", "bat"); //"123bazbat" Foo.baz.call(Foo2, ["baz", "bat"]); //"123bazbat" call & apply Tuesday, May 22, 12
  116. try { funcDoesNotExist(); } catch (e) { alert(e); //ReferenceError: funcDoesNotExist

    is not defined } finally { //Always Executes } Exceptions Tuesday, May 22, 12
  117. function Foo() { throw new Error("Message"); } function Bar() {

    throw "Message"; } try { Foo(); } catch (e) { e.message == "Message"; //true } try { Bar(); } catch (e) { e == "Message"; //true } Exceptions Tuesday, May 22, 12
  118. OOP... Kinda... •Almost no real difference between a dictionary and

    an object •Named Functions double as object constructors •Function objects contain a prototype dictionary that is copied to instance when using new Tuesday, May 22, 12
  119. Foo ‣ bar ‣ prototype ‣ baz ‣ constructor ‣

    __proto__ function Foo() { //The "Constructor" } Foo.bar = function() { //A "Static" Function } Foo.prototype.baz = function() { //A "Method" }; OOP... Kinda... Tuesday, May 22, 12
  120. instance ‣ __proto__ ‣ baz ‣ constructor ‣ __proto__ ‣

    ... var instance = new Foo(); instance.baz(); //works instance.bar(); //error Foo.bar(); //works Foo.baz(); //error Foo.prototype.baz(); //works new Tuesday, May 22, 12
  121. instance ‣ bat ‣ __proto__ ‣ baz ‣ constructor ‣

    __proto__ ‣ ... instance.bat = function() { /* ... */ } instance.bat(); //works Foo.bat(); //error Foo.prototype.bat(); //error new Tuesday, May 22, 12
  122. function Foo(baz) { this.baz = baz; } Foo.prototype.bar = function()

    { return this.baz; }; var foo1 = new Foo(1); var foo2 = new Foo(2); foo1.bar(); //1 foo2.bar(); //2 Foo.prototype.bar = function() { return this.baz * 2; }; foo1.bar(); //2 foo2.bar(); //4 Overriding Prototype Tuesday, May 22, 12
  123. var id = setInterval(function() { //Code to execute every 1000

    milliseconds }, 1000); //clearInterval(id); to stop setInterval Tuesday, May 22, 12
  124. var id = setTimeout(function() { //Code to execute after 1000

    milliseconds have passed }, 1000); //clearTimeout(id); to cancel setTimeout Tuesday, May 22, 12
  125. setTimeout(function() { //Code to run in parallel //while the code

    after is //executed. }, 1); //Code here will execute immediately //without waiting on the above Nifty Trick Tuesday, May 22, 12
  126. Basic selection methods in native DOM document .getElementById('foo'); document .getElementsByClassName('.bar');

    document .getElementsByTagName('script'); DOM: Selection Tuesday, May 22, 12
  127. var paragraph = document.createElement('p'); var content = document.createTextNode("Lorem Ipsum"); paragraph.appendChild(content);

    paragraph.classList.add('my-class'); document.getElementsByTagName('body')[0].appendChild(paragraph); DOM: Creation Tuesday, May 22, 12
  128. Creates a script element, set its src and async properties

    Insert the script before the first script tag in the body of the document var script = document.createElement('script'); script.src = "http://path.to/script.js"; script.async = true; var s = document .getElementsByTagName('script')[0]; s.parentNode .insertBefore(script, s); Async Script Loading Tuesday, May 22, 12
  129. Console •Provided by major browser vendors •Useful for viewing logs,

    exceptions, real-time data dumping, and code execution within the current context •Your best friend •Though older IEs FREAK OUT when you leave it in, remove before deploy! Tuesday, May 22, 12
  130. console •Ditch alert(), this is your var_dump() •console.log(arg1, arg2, ...)

    •console.info Same as log •console.warn Icon indicator •console.error Stack trace Tuesday, May 22, 12
  131. BEWARE •console.log is not blocking •In heavily asynchronous applications, sometimes

    value displayed is not value at the moment of the call •Your if/else conditionals will work yet console.log will return something that should cause them to fail Tuesday, May 22, 12
  132. Network •Display all network requests via a gantt-like graph •Shows

    browser-initiated (css, images, etc) and script initiated (ajax) alike •Along with both request and response headers Tuesday, May 22, 12
  133. Coding Styles •Mostly your standard C based style techniques •Special

    considerations •Semi-colons? No semi-colons? •Leading , ? •Prototype Definition? Tuesday, May 22, 12
  134. var dict = { foo: 'bar', baz: 'bat' }; var

    dict = { foo: 'bar' , baz: 'bat' }; Comma Style Tuesday, May 22, 12
  135. var foo; var bar; var baz; var foo , bar

    , baz; var Declaration Style Tuesday, May 22, 12
  136. function Foo() { } Foo.prototype.bar = function(){ }; Prototype Style

    function Foo() { } Foo.prototype = { bar: function() { } } Tuesday, May 22, 12
  137. Code Quality Tools •JSLint http://www.jslint.com/ •By Crockford, extremely strict and

    inflexible. Code like Crockford! •JSHint http://www.jshint.com/ •Fork, more flexible according to your own rules and preferences Tuesday, May 22, 12
  138. Grab global App dictionary, or create if not found Add

    a function utility, is now globally accessible without fearing collision with other functioned similarly named App = window.App || {}; App.utility = function() { //Globally available, no //conflicts }; Safe Extension Tuesday, May 22, 12
  139. Immediately Invoked Function Expression Function is defined then immediately invoked.

    Closest thing to a namespace/module system. Prevents variable leakage into outer scopes (function(exports){ exports.foo = function() { }; var bar = function() { }; })(window); foo(); //success bar(); //not found! IIFE Tuesday, May 22, 12
  140. Pro-Tip •Create an application namespace as a dictionary in the

    global scope •Add in any global level configuration values Tuesday, May 22, 12
  141. JSON •JavaScript Object Notation •Serialization format that is basically JavaScript

    code minus comments •Can be eval()’ed •But don’t! Use JSON2.js or equivalent •Minimal overhead compared to XML •No parsers required, native mapping Tuesday, May 22, 12
  142. {"menu": { "id": "file", "value": "File", "popup": { "menuitem": [

    {"value": "New", "onclick": "CreateNewDoc()"}, {"value": "Open", "onclick": "OpenDoc()"}, {"value": "Close", "onclick": "CloseDoc()"} ] } }} JSON <menu id="file" value="File"> <popup> <menuitem value="New" onclick="CreateNewDoc()" /> <menuitem value="Open" onclick="OpenDoc()" /> <menuitem value="Close" onclick="CloseDoc()" /> </popup> </menu> Tuesday, May 22, 12
  143. jQuery •Cross-browser JavaScript library •Simplifies and normalizes DOM, AJAX, etc.

    •Centers around using extended CSS selectors to grab an element(s) Tuesday, May 22, 12
  144. Selectors •$('selector') returns jQuery object for chaining purposes •Chained methods

    will apply to all results if selector matches multiple elements Tuesday, May 22, 12
  145. Finds all p tags that do not have the class

    special, and adds the class semi-special $("p:not(.special)") .addClass("semi-special"); Selectors Tuesday, May 22, 12
  146. Gets the value of the selected option in a select

    box $('select option:selected').val(); Selectors Tuesday, May 22, 12
  147. Tests matched element against selector, in this case the jQuery

    ‘visible’ selector $('.foo').is(':visible'); Testing Elements Tuesday, May 22, 12
  148. Custom Filters •jQuery provides the ability to create custom filters

    •:radio, :hidden, etc are custom filters provided by default Tuesday, May 22, 12
  149. Chaining •Most all jQuery methods are chain-able •If $() returns

    > 1 element, methods invoked will apply to all matched Tuesday, May 22, 12
  150. Find all ul with class first Find elements of class

    foo that are children of the top level matched set Apply the css style of color:red; Pop the matching of .foo off the jQuery object Find elements of class bar that are children of the top level matched set (ul.first) Apply the css style of color:blue; $('ul.first') .find('.foo') .css('color', 'red') .end().find('.bar') .css('color', 'blue') .end(); Chaining Tuesday, May 22, 12
  151. Events •jQuery wraps an event handling system •Handles browser events,

    AJAX events, and custom events Tuesday, May 22, 12
  152. $(document).ready(function() { //Only execute when the document fires //its onready

    event (page is done loading) }); $(document).bind('ready', function() { //Equivalent to the above }); $(function() { //Shortcut, equivalent to the above }); Events Tuesday, May 22, 12
  153. Listen for click on a.foo this will be the specific

    a.foo element that was clicked $('a.foo').click(function(){ var $this = $(this) , href = $this.href(); //href will be the clicked //links href }); jQuery Tuesday, May 22, 12
  154. Live Events •Events using .bind are bound to the specific

    element at the specific point in time it was bound • New elements that match will not be included •Using .on or .off produces a delegate listener that scans for bubbled events that match a selector • New elements that match said selector WILL be included Tuesday, May 22, 12
  155. All a tags that exist at some point as a

    descendant of .grandparent will trigger this event on click Any future a tags that are added as a descendant of .grandparent will trigger this event on click $('.grandparent') .on('click', 'a', function(e){ var $target = $(e.target); //$target will *usually* //be the a tag, though //sometimes it will be a //nested tag }); Live Events Tuesday, May 22, 12
  156. Create a Prototype object for example purposes, then create new

    instance. The first click handler will fail. The keyword this will not be a reference to the instance of Foo as expected, but a reference to the matched DOM element that was clicked. jQuery.proxy() will wrap your function such that further invocations will use the context you set for this function Foo() {} Foo.prototype.baz = function() {}; Foo.prototype.bar = function() { this.baz(); }; var instance = new Foo(); $('element').click(instance.bar); $('element').click( jQuery.proxy( instance.bar, instance ); ); Proxy Tuesday, May 22, 12
  157. When .button is clicked, fade out img.preview over 600 milliseconds

    and then remove it from the DOM $('.button').click(function(){ $('img.preview') .fadeOut(600, function() { $(this).remove(); }); }); Animation Tuesday, May 22, 12
  158. Animate the following attributes over the course of 5 seconds:

    opacity to 25% move to the right 50px toggle height $('#book').animate({ opacity: 0.25, left: '+=50', height: 'toggle' }, 5000, function() { // Animation complete. } ); animate Tuesday, May 22, 12
  159. DOM Creation / Insertion •Super easy! Provide html tag to

    $() and jQuery will create the element and return it wrapped in jQuery •Second parameter is dictionary for properties •Then use methods like .append() to insert Tuesday, May 22, 12
  160. Creates a DIV tag Creates an input (text) tag Creates

    a span with the class of foo $('<div>'); $('<input type="text" />'); $('<span>', { 'class': 'foo' }); DOM Creation Tuesday, May 22, 12
  161. Replaces the content of #foo with: Testing Replaces the content

    of #bar with: <strong>Testing</strong> $('#foo') .html("<strong>Testing</strong>"); $('#bar') .text("<strong>Testing</strong>"); DOM Override Tuesday, May 22, 12
  162. Insertion (inside): -append -appendTo -html -prepend -prependTo -text Insertion (outside):

    -after -before -insertAfter -insertBefore $('<div>') .appendTo($('#foo')); $('#foo') .append($('<span>')); $('<div>') .prependTo($('#bar')); $('#baz') .after($('<span>')); $('<div>') .insertBefore($('#baz')); DOM Insertion Tuesday, May 22, 12
  163. AJAX •Asynchronous JavaScript And XML •Though never use XML, use

    JSON •jQuery has an AJAX library •Wraps all the different browser quirks •IE is weird Tuesday, May 22, 12
  164. Cross-Domain •Browser will not fire AJAX requests to a domain

    outside the one said JavaScript was loaded from •If you include http://sub.domain.tld/file.js, it cannot make AJAX requests to http:// another.tld/ •It can make requests to http://domain.tld/ Tuesday, May 22, 12
  165. JSONp •Workaround to cross-domain •Load like it is a javascript

    file (create an inject a script tag into the DOM) •Response is a function (defined by a callback GET parameter) that executes and returns value Tuesday, May 22, 12
  166. $.ajax({ dataType: 'jsonp' , url: 'http://search.twitter.com/search.json' , data: { q:

    "#tek12" } , success: function(resp) { jQuery.each(resp.results, function(id, tweet){ $('<div>', { 'class': 'tweet' }) .append($('<strong>', { 'class': 'user' , text: '@' + tweet.from_user })) .append($('<span>',{ 'class': 'text' , text: tweet.text })) .appendTo($('#tweets')); }); } }); JSONp Tuesday, May 22, 12
  167. Create new :inline filter (checks if display is set to

    inline) Works like any other native inline $.expr[':'].inline = function(elem){ var $elem = $(elem) , disp = $elem.css('display'); return disp === 'inline'; }; $('div a:inline') .css('color', 'red'); $('span:not(:inline)') .css('color', 'blue') Extending: Custom Filters Tuesday, May 22, 12
  168. (function($, global, undefined){ var defaults = { foo: "bar" };

    var methods = { init: function(options) { // Merge user defined options options = $.extend(true, {}, defaults, options); return this; }, method: function() { }, } $.fn.foo = function(method) { if( methods[method] ) { return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); } else if (typeof method == 'object' || !method) { return methods.init.apply(this, arguments); } else { $.error('Method ' + method + ' does not exist'); return undefined; } } })(jQuery, window); Tuesday, May 22, 12
  169. Functional Programming •Functions are mappings between input and output •No

    side-effects •Input A always results in output B •No OOP •LISP, Haskell, Erlang Tuesday, May 22, 12
  170. Underscore.js Collections •each •map •reduce •reduceRight •find •filter •reject •all

    •any •include •invoke •pluck •max •min •sortBy •groupBy •sortedIndex •shuffle •toArray •size Arrays •first •initial •last •rest •compact •flatten •without •union •intersection •difference •uniq •zip •indexOf •lastIndexOf •range Functions •bind •bindAll •memoize •delay •defer •throttle •debounce •once •after •wrap •compose Objects •keys •values •functions •extend •pick •defaults •clone •tap •has •isEqual •isEmpty •isElement •isArray •isObject •isArguments •isFunction •isString •isNumber •isFinite •isBoolean •isDate •isRegExp •isNaN •isNull •isUndefined Utility •noConflict •identity •times •mixin •uniqueId •escape •result •template Chaining •chain •value Tuesday, May 22, 12
  171. Maps function to each element in the input collection var

    inp = [1, 2, 3] , out = _.map(inp, function(n){ return n*2; }); //out = [2, 4, 6] Map Tuesday, May 22, 12
  172. Reduces collection to a single value. mem is the initial

    state, each successive iteration must be returned var inp = [1, 2, 3]; _(inp).reduce(function(mem, n){ return mem + n; }); //Iter 0: mem = 1 | n = 2 //Iter 1: mem = 3 | n = 3 //Returns: 6 Reduce Tuesday, May 22, 12
  173. Iterates over a collection and extracts the values for the

    input key (assumes all elements in the collection are objects/arrays) var stooges = [ {name: 'moe', age: 40} , {name: 'larry', age: 50} , {name: 'curly', age: 60} ]; _.pluck(stooges, 'name'); //Returns ["moe", "larry", "curly"] Pluck Tuesday, May 22, 12
  174. Returns the max item in a collection. If second argument

    (iterator) provided, will use to produce the value to be compared var stooges = [ {name: 'moe', age: 40} , {name: 'larry', age: 50} , {name: 'curly', age: 60} ]; _.max(stooges, function(s){ return s.age; }); //Returns {name: 'curly', age: 60} Max (Min) Tuesday, May 22, 12
  175. Returns the keys from a dictionary as an array _.keys({

    one: 1, two: 2, three: 3 }); //Returns ["one", "two", "three"] Keys Tuesday, May 22, 12
  176. Maps a duplicate input dictionary on top of a predefined

    “default” dictionary var iceCream = { flavor: "chocolate" }; _.defaults(iceCream, { flavor: "vanilla" , sprinkles: "lots" }); //Returns {flavor : "chocolate", sprinkles : "lots"} Defaults Tuesday, May 22, 12
  177. When chain is initiated, method return a self-reference back to

    underscore but with the value attached [similar to opening with _(val)]. The chain continues until the value is extracted using .value() var stooges = [ {name : 'curly', age : 25}, {name : 'moe', age : 21}, {name : 'larry', age : 23} ]; var youngest = _.chain(stooges) .sortBy(function(s){ return s.age; }) .map(function(s){ return s.name + ' is ' + s.age; }) .first() .value(); //Returns "moe is 21" Chaining Tuesday, May 22, 12
  178. chain: begins a chain map: takes dictionary and maps to

    a nested array [[key, val], [key, val], ..] sortBy: sorts array returned by map by key (first element) reduce: reforms an object using the nested list, [0] as key and [1] as value value: spits out the value an ends the chain _(request.params).chain() .map(function(v, k) { return [k,v]; }) .sortBy(function(a) { return a[0]; }) .reduce(function(s, v){ s[v[0]] = v[1]; return s; }, {}) .value(); Chain: FUN! Tuesday, May 22, 12
  179. Backbone.js •Micro application framework •Relies on jQuery/Zepto and Underscore.js •Provides

    Views, Models, Collections, and Router •If standard REST, default sync will work out of box Tuesday, May 22, 12
  180. View •Creates own DOM object (or utilizes existing one) •Easy

    event delegation/undelegation Tuesday, May 22, 12
  181. Lawnchair •HTML5 localstorage abstraction •Good suite of storage adapaters •DOM,

    webkit-sqlite, etc http://brian.io/lawnchair Tuesday, May 22, 12
  182. Moment.js •Date/Time library •Finally! Almost as easy as \DateTime and

    strtotime() http://momentjs.com/ Tuesday, May 22, 12
  183. Enyo •Application Framework •Developed for the HP/Palm TouchPad •Now open-source

    •Designed for nested views and complex, finger-based UI http://enyojs.com/ Tuesday, May 22, 12