Your SlideShare is downloading. ×
0
The DOM is a Mess
                  John Resig
http://ejohn.org/ - http://twitter.com/jeresig/
A Tour of the DOM
    A messy DOM
✦

    Writing Cross-Browser Code
✦

    Common Features
✦
    ✦ CSS Selector Engine
   ...
Messy
    Nearly every DOM method is broken in
✦
    some way, in some browser.
    Some old:
✦
    ✦ getElementById
    ✦...
getElementById
    Likely the most commonly used DOM
✦
    method
    A couple weird bits:
✦
    ✦ IE and older versions o...
getElementsByTagName
    Likely tied for most-commonly-used
✦
    DOM method
    Riddled with bugs in IE:
✦
    ✦ “*” retu...
getElementsByClassName
    Landed in Firefox 3, Safari 3, Opera 9.6
✦

    A few knotty issues:
✦
    ✦ HTMLElement.protot...
querySelectorAll
    Find DOM elements using CSS selectors
✦

    In Firefox 3.1, Safari 3.1, Opera 10, IE 8
✦

    Birthi...
Moral
    If there’s a DOM method, there’s probably
✦
    a problem with it somewhere, in some
    capacity.
Cross-Browser Code
Strategies
    Pick your browsers
✦

    Know your enemies
✦

    Write your code
✦
Cost / Benefit




  IE 7     IE 6          FF 3    Safari 3   Opera 9.5
                  Cost          Benefit


        ...
Graded Support




   Yahoo Browser Compatibility
Browser Support Grid
           IE      Firefox   Safari   Opera Chrome


Previous   6.0       2.0      3.0      9.5


Cur...
Browser Support Grid
           IE        Firefox   Safari   Opera Chrome


Previous                        3.0      9.5
 ...
Know Your Enemies
          Points of Concern for JavaScript Code



                     Browser Bugs
                   ...
Know Your Enemies
          Points of Concern for JavaScript Code



                     Browser Bugs
                   ...
Browser Bugs
    Generally your primary concern
✦

    Your defense is a good test suite
✦
    ✦ Prevent library regressio...
Test, Test, Test


1446 Tests, 9 browsers
Know Your Enemies
          Points of Concern for JavaScript Code



                     Browser Bugs
                   ...
External Code
    Making your code resistant to any
✦
    environment
    ✦ Found through trial and error
    ✦ Integrate ...
Environment Testing
    100% Passing:
✦
    ✦ Standards Mode
    ✦ Quirks Mode
    ✦ Inline with Prototype + Scriptaculous...
Object.prototype
 Object.prototype.otherKey = quot;otherValuequot;; 
  
 var obj = { key: quot;valuequot; }; 
 for ( var p...
Greedy IDs
 <form id=quot;formquot;> 
   <input type=quot;textquot; id=quot;lengthquot;/> 
   <input type=quot;submitquot;...
Order of Stylesheets
    Putting stylesheets before code guarantees
✦
    that they’ll load before the code runs.
    Putt...
Pollution
    Make sure your code doesn’t break
✦
    outside code
    ✦ Use strict code namespacing
    ✦ Don’t extend ou...
Pollution




            http://mankz.com/code/
               GlobalCheck.htm
Know Your Enemies
          Points of Concern for JavaScript Code



                     Browser Bugs
                   ...
Missing Features
    Typically older browsers missing specific
✦
    features
    Optimal solution is to gracefully
✦
    d...
Object Detection
    Check to see if an object or property
✦
    exists
    Useful for detecting an APIs existence
✦

    ...
Event Binding
 function attachEvent( elem, type, handle ) { 
   // bind event using proper DOM means 
   if ( elem.addEven...
Fallback Detection
 if ( typeof document !== quot;undefinedquot; &&  
      (document.addEventListener 
       || document...
Fallback
    Figure out a way to reduce the
✦
    experience
    Opt to not execute any JavaScript
✦
    ✦ Guarantee no pa...
Know Your Enemies
          Points of Concern for JavaScript Code



                     Browser Bugs
                   ...
Bug Fixes
    Don’t make assumptions about browser
✦
    bugs.
    ✦ Assuming that a browser will always
      have a bug ...
Failed Bug Fix in FF 3
 // Shouldn't work 
 var node = documentA.createElement(quot;divquot;); 
 documentB.documentElement...
Feature Simulation
    More advanced than object detection
✦

    Make sure an API works as advertised
✦

    Able to capt...
Verify API
 // Run once, at the beginning of the program 
 var ELEMENTS_ONLY = (function(){ 
   var div = document.createE...
Figure Out Naming
 <div id=quot;testquot; style=quot;color:red;quot;></div> 
 <div id=quot;test2quot;></div> 
 <script> 
 ...
Know Your Enemies
          Points of Concern for JavaScript Code



                     Browser Bugs
                   ...
Regressions
    Removing or changing unspecified APIs
✦

    Object detection helps here
✦

    Monitor upcoming browser re...
Object Failover
 function attachEvent( elem, type, handle ) { 
   // bind event using proper DOM means 
   if ( elem.addEv...
Safe Cross-Browser Fixes
    The easiest form of fix
✦

    Unifies an API across browsers
✦

    Implementation is painless...
Unify Dimensions
 // ignore negative width and height values 
 if ( (key == 'width' || key == 'height') && 
      parseFlo...
Prevent Breakage
 if ( name == quot;typequot; && elem.nodeName.toLowerCase() 
       == quot;inputquot; && elem.parentNode...
Untestable Problems
    Has an event handler been bound?
✦

    Will an event fire?
✦

    Do CSS properties like color or ...
Impractical to Test
    Performance-related issues
✦

    Determining if Ajax requests will work
✦
Battle of Assumptions
    Cross-browser development is all about
✦
    reducing the number of assumptions
    No assumptio...
DOM Traversal
    Many methods of DOM traversal
✦

    One unanimous solution:
✦
    ✦ CSS Selector Engine
Traditional DOM
    getElementsByTagName
✦

    getElementById
✦

    getElementsByClassName
✦
    ✦ in FF3, Safari 3, Ope...
Top-Down CSS Selector
    Traditional style of traversal
✦
    ✦ Used by all major libraries

    Work from left-to-right
...
   function find(selector, root){ 
     root = root || document; 
                                     
     var parts = s...
 (function(){ 
   var run = 0; 
                                     
   this.unique = function( array ) { 
     var ret =...
Bottom-Up
    Work from right-to-left
✦
    ✦ (How CSS Engines work in browsers.)

    “div p”
✦
    ✦ Find all paragraphs...
Bottom-Up
    Some nice features:
✦
    ✦ Only one DOM query
    ✦ No merge/unique required (except for
      “div, span”)...
   function find(selector, root){ 
     root = root || document; 
                                            
     var pa...
CSS to XPath
    Browsers provide XPath functionality
✦

    Collect elements from a document
✦

    Works in all browsers...
 if ( typeof document.evaluate === quot;functionquot; ) { 
   function getElementsByXPath(expression, parentElement) { 
  ...
Goal                        CSS 3                 XPath

All Elements                 *                   //*

All P Eleme...
querySelectorAll
    The Selectors API spec from the W3C
✦

    Two methods:
✦
    ✦ querySelector (first element)
    ✦ qu...
 <div id=quot;testquot;> 
   <b>Hello</b>, I'm a ninja! 
 </div> 
 <div id=quot;test2quot;></div> 
 <script> 
 window.onlo...
 <div id=quot;testquot;> 
   <b>Hello</b>, I'm a ninja! 
 </div> 
 <script> 
 window.onload = function(){ 
   var b = docu...
DOM Modification
    Injecting HTML
✦

    Removing Elements
✦
Injecting HTML
    HTML 5:
✦
    insertAdjacentHTML
    Already in IE, dicey support, at best
✦

    What can we use inste...
 function getNodes(htmlString){ 
   var map = { 
     quot;<tdquot;: [3, quot;<table><tbody><tr>quot;, quot;</tr></tbody><...
Element Mappings
    option and optgroup need to be contained in a
✦
       <select multiple=quot;multiplequot;>...</selec...
DocumentFragment
    Fragments can collect nodes
✦

    Can be appended or cloned in bulk
✦

    Super-fast (2-3x faster t...
   function insert(elems, args, callback){ 
     if ( elems.length ) { 
       var doc = elems[0].ownerDocument || elems[0...
Inline Script Execution
    .append(“<script>var foo = 5;</script>”);
✦

    Must execute scripts globally
✦

    window.e...
 function globalEval( data ) { 
   data = data.replace(/^s+|s+$/g, quot;quot;); 
                                         ...
Removing Elements
    Have to clean up bound events
✦
    ✦ IE memory leaks

    Easy to do if it’s managed.
✦
Events
    Three big problems with Events:
✦
    ✦ Memory Leaks (in IE)
    ✦ Maintaining ‘this’ (in IE)
    ✦ Fixing even...
Leaks
    Internet Explorer 6 leaks horribly
✦
    ✦ Other IEs still leak, not so badly

    Attaching functions (that hav...
‘this’
    Users like having their ‘this’ refer to the
✦
    target element
    Not the case in IE
✦

    What’s the solut...
Single Handler
    Bind a single handler to an event
✦

    Call each bound function individually
✦

    Can fix ‘this’ and...
Central Data Store
    Store all bound event handlers in a central
✦
    object
    Link elements to handlers
✦

    Keep ...
Central Data Store
                   Events                Data
Element            function click(){}

          #43
    ...
Multiple Stores
Element
           #43
                  Library A
Element
            #67
Element

Element
          #37
...
Unique Element ID
    The structure must hook to an element
✦

    Elements don’t have unique IDs
✦

    Must generate the...
Questions?
    http://ejohn.org/
✦

    http://twitter.com/jeresig/
✦
Upcoming SlideShare
Loading in...5
×

The DOM is a Mess @ Yahoo

46,715

Published on

A talk that I gave at Yahoo, in January 2009, about the DOM.

Published in: Technology
7 Comments
86 Likes
Statistics
Notes
  • dom
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • That's really amazing.

    Stulangperdana
    www.mdamin76.com/
    www.sprintringtones.org/
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • i really liked those! they were easy, convenient, and intuitive

    Regards
    Teisha
    http://winkhealth.com
    http://financewink.com
    http://www.fakhriramley.com
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • *cough* Yahoo has messed up DOM?
    I suggest your title could use some clarification. Given how we use Twitter there's nothing atoub '@yahoo' that suggests this was a presentation given at Yahoo ... if that is indeed what it means.
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • This stuff rocks, but just some questions:
    When a browser is released this bugs are caused due to bad reverse engeneering?
    I can't understand why the guys change de default behavior of javascript.
    Let's take PHP as an example, it's the same over all servers.
    Why is that so diferent from javascript or DOM on browers?
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total Views
46,715
On Slideshare
0
From Embeds
0
Number of Embeds
17
Actions
Shares
0
Downloads
1,084
Comments
7
Likes
86
Embeds 0
No embeds

No notes for slide

Transcript of "The DOM is a Mess @ Yahoo"

  1. 1. The DOM is a Mess John Resig http://ejohn.org/ - http://twitter.com/jeresig/
  2. 2. A Tour of the DOM A messy DOM ✦ Writing Cross-Browser Code ✦ Common Features ✦ ✦ CSS Selector Engine ✦ DOM Modification ✦ Events
  3. 3. Messy Nearly every DOM method is broken in ✦ some way, in some browser. Some old: ✦ ✦ getElementById ✦ getElementsByTagName Some new: ✦ ✦ getElementsByClassName ✦ querySelectorAll
  4. 4. getElementById Likely the most commonly used DOM ✦ method A couple weird bits: ✦ ✦ IE and older versions of Opera returning elements with a name == id ✦ Does not easily work in XML documents
  5. 5. getElementsByTagName Likely tied for most-commonly-used ✦ DOM method Riddled with bugs in IE: ✦ ✦ “*” returns no elements in IE 5.5 ✦ “*” returns no elements on <object> elements in IE 7 ✦ .length gets overwritten in IE if an element with an ID=”length” is found
  6. 6. getElementsByClassName Landed in Firefox 3, Safari 3, Opera 9.6 ✦ A few knotty issues: ✦ ✦ HTMLElement.prototype .getElementsByClassName couldn’t be overwritten in Firefox ✦ Opera doesn’t match a second-specified class (e.g. class=”a b”, b isn’t found)
  7. 7. querySelectorAll Find DOM elements using CSS selectors ✦ In Firefox 3.1, Safari 3.1, Opera 10, IE 8 ✦ Birthing pains: ✦ ✦ Doesn’t exist in quirks mode, in IE 8 ✦ Safari 3.1 had memory out of bounds problems ✦ Safari 3.2 can’t match uppercase characters in quirks mode ✦ #id doesn’t match in XML documents
  8. 8. Moral If there’s a DOM method, there’s probably ✦ a problem with it somewhere, in some capacity.
  9. 9. Cross-Browser Code
  10. 10. Strategies Pick your browsers ✦ Know your enemies ✦ Write your code ✦
  11. 11. Cost / Benefit IE 7 IE 6 FF 3 Safari 3 Opera 9.5 Cost Benefit Draw a line in the sand.
  12. 12. Graded Support Yahoo Browser Compatibility
  13. 13. Browser Support Grid IE Firefox Safari Opera Chrome Previous 6.0 2.0 3.0 9.5 Current 7.0 3.0 3.2 9.6 Current Next 8.0 3.1 4.0 10.0 jQuery Browser Support
  14. 14. Browser Support Grid IE Firefox Safari Opera Chrome Previous 3.0 9.5 6.0 2.0 Current 7.0 3.0 3.2 9.6 Current Next 3.1 4.0 8.0 10.0 jQuery 1.3 Browser Support
  15. 15. Know Your Enemies Points of Concern for JavaScript Code Browser Bugs Regressions Missing Features JavaScript Code Bug Fixes External Code, Markup
  16. 16. Know Your Enemies Points of Concern for JavaScript Code Browser Bugs Regressions Missing Features JavaScript Code Bug Fixes External Code, Markup
  17. 17. Browser Bugs Generally your primary concern ✦ Your defense is a good test suite ✦ ✦ Prevent library regressions ✦ Analyze upcoming browser releases Your offense is feature simulation ✦ What is a bug? ✦ ✦ Is unspecified, undocumented, behavior capable of being buggy?
  18. 18. Test, Test, Test 1446 Tests, 9 browsers
  19. 19. Know Your Enemies Points of Concern for JavaScript Code Browser Bugs Regressions Missing Features JavaScript Code Bug Fixes External Code, Markup
  20. 20. External Code Making your code resistant to any ✦ environment ✦ Found through trial and error ✦ Integrate into your test suite ✦ Other libraries ✦ Strange code uses
  21. 21. Environment Testing 100% Passing: ✦ ✦ Standards Mode ✦ Quirks Mode ✦ Inline with Prototype + Scriptaculous ✦ Inline with MooTools Work in Progress: ✦ ✦ XHTML w/ correct mimetype ✦ With Object.prototype ✦ In XUL (Firefox Extensions) ✦ In Rhino (with Env.js)
  22. 22. Object.prototype  Object.prototype.otherKey = quot;otherValuequot;;      var obj = { key: quot;valuequot; };   for ( var prop in object ) {     if ( object.hasOwnProperty( prop ) ) {       assert( prop, quot;keyquot;,  quot;There should only be one iterated property.quot; );     }   } 
  23. 23. Greedy IDs  <form id=quot;formquot;>     <input type=quot;textquot; id=quot;lengthquot;/>     <input type=quot;submitquot; id=quot;submitquot;/>   </form>  document.getElementsByTagName(quot;inputquot;).length
  24. 24. Order of Stylesheets Putting stylesheets before code guarantees ✦ that they’ll load before the code runs. Putting them after can create an ✦ indeterminate situation.
  25. 25. Pollution Make sure your code doesn’t break ✦ outside code ✦ Use strict code namespacing ✦ Don’t extend outside objects, elements Bad: ✦ ✦ Introducing global variables ✦ Extending native objects (Array, Object) ✦ Extending DOM natives
  26. 26. Pollution http://mankz.com/code/ GlobalCheck.htm
  27. 27. Know Your Enemies Points of Concern for JavaScript Code Browser Bugs Regressions Missing Features JavaScript Code Bug Fixes External Code, Markup
  28. 28. Missing Features Typically older browsers missing specific ✦ features Optimal solution is to gracefully ✦ degrade ✦ Fall back to a simplified page Can’t make assumptions about ✦ browsers that you can’t support ✦ If it’s impossible to test them, you must provide a graceful fallback Object detection works well here. ✦
  29. 29. Object Detection Check to see if an object or property ✦ exists Useful for detecting an APIs existence ✦ Doesn’t test the compatibility of an API ✦ ✦ Bugs can still exist - need to test those separately with feature simulation
  30. 30. Event Binding  function attachEvent( elem, type, handle ) {     // bind event using proper DOM means     if ( elem.addEventListener )       elem.addEventListener(type, handle, false);            // use the Internet Explorer API     else if ( elem.attachEvent )       elem.attachEvent(quot;onquot; + type, handle);   } 
  31. 31. Fallback Detection  if ( typeof document !== quot;undefinedquot; &&         (document.addEventListener  || document.attachEvent) &&        document.getElementsByTagName &&  document.getElementById ) {     // We have enough of an API to  // work with to build our application   } else {     // Provide Fallback   }
  32. 32. Fallback Figure out a way to reduce the ✦ experience Opt to not execute any JavaScript ✦ ✦ Guarantee no partial API ✦ (e.g. DOM traversal, but no Events) Redirect to another page, or just work ✦ unobtrusively Working on a ready() fallback for jQuery ✦
  33. 33. Know Your Enemies Points of Concern for JavaScript Code Browser Bugs Regressions Missing Features JavaScript Code Bug Fixes External Code, Markup
  34. 34. Bug Fixes Don’t make assumptions about browser ✦ bugs. ✦ Assuming that a browser will always have a bug is foolhardy ✦ You will become susceptible to fixes ✦ Browsers will become less inclined to fix bugs Look to standards to make decisions about ✦ what are bugs
  35. 35. Failed Bug Fix in FF 3  // Shouldn't work   var node = documentA.createElement(quot;divquot;);   documentB.documentElement.appendChild( node );      // Proper way   var node = documentA.createElement(quot;divquot;);   documentB.adoptNode( node );   documentB.documentElement.appendChild( node ); 
  36. 36. Feature Simulation More advanced than object detection ✦ Make sure an API works as advertised ✦ Able to capture bug fixes gracefully ✦
  37. 37. Verify API  // Run once, at the beginning of the program   var ELEMENTS_ONLY = (function(){     var div = document.createElement(quot;divquot;);     div.appendChild( document.createComment(quot;testquot; ) );     return div.getElementsByTagName(quot;*quot;).length === 0;   })();      // Later on:   var all = document.getElementsByTagName(quot;*quot;);      if ( ELEMENTS_ONLY ) {     for ( var i = 0; i < all.length; i++ ) {       action( all[i] );     }   } else {     for ( var i = 0; i < all.length; i++ ) {       if ( all[i].nodeType === 1 ) {         action( all[i] );       }     }   } 
  38. 38. Figure Out Naming  <div id=quot;testquot; style=quot;color:red;quot;></div>   <div id=quot;test2quot;></div>   <script>   // Perform the initial attribute check   var STYLE_NAME = (function(){     var div = document.createElement(quot;divquot;);     div.style.color = quot;redquot;;          if ( div.getAttribute(quot;stylequot;) )       return quot;stylequot;;          if ( div.getAttribute(quot;cssTextquot;) )       return quot;cssTextquot;;   })();      // Later on:   window.onload = function(){     document.getElementsById(quot;test2quot;).setAttribute( STYLE_NAME,         document.getElementById(quot;testquot;).getAttribute( STYLE_NAME ) );   };   </script> 
  39. 39. Know Your Enemies Points of Concern for JavaScript Code Browser Bugs Regressions Missing Features JavaScript Code Bug Fixes External Code, Markup
  40. 40. Regressions Removing or changing unspecified APIs ✦ Object detection helps here ✦ Monitor upcoming browser releases ✦ ✦ All vendors provide access to beta releases ✦ Diligence! Example: IE 7 introduced ✦ XMLHttpRequest with file:// bug Test Suite Integration ✦
  41. 41. Object Failover  function attachEvent( elem, type, handle ) {     // bind event using proper DOM means     if ( elem.addEventListener )       elem.addEventListener(type, handle, false);            // use the Internet Explorer API     else if ( elem.attachEvent )       elem.attachEvent(quot;onquot; + type, handle);   } 
  42. 42. Safe Cross-Browser Fixes The easiest form of fix ✦ Unifies an API across browsers ✦ Implementation is painless ✦
  43. 43. Unify Dimensions  // ignore negative width and height values   if ( (key == 'width' || key == 'height') &&  parseFloat(value) < 0 )     value = undefined; 
  44. 44. Prevent Breakage  if ( name == quot;typequot; && elem.nodeName.toLowerCase()  == quot;inputquot; && elem.parentNode )     throw quot;type attribute can't be changedquot;; 
  45. 45. Untestable Problems Has an event handler been bound? ✦ Will an event fire? ✦ Do CSS properties like color or opacity ✦ actually affect the display? Problems that cause a browser crash. ✦ Problems that cause an incongruous API. ✦
  46. 46. Impractical to Test Performance-related issues ✦ Determining if Ajax requests will work ✦
  47. 47. Battle of Assumptions Cross-browser development is all about ✦ reducing the number of assumptions No assumptions indicates perfect code ✦ ✦ Unfortunately that’s an unobtainable goal ✦ Prohibitively expensive to write Have to draw a line at some point ✦
  48. 48. DOM Traversal Many methods of DOM traversal ✦ One unanimous solution: ✦ ✦ CSS Selector Engine
  49. 49. Traditional DOM getElementsByTagName ✦ getElementById ✦ getElementsByClassName ✦ ✦ in FF3, Safari 3, Opera 9.6 .children ✦ ✦ only returns elements (in all, and FF 3.1) getElementsByName ✦ .all[id] ✦ ✦ Match multiple elements by ID
  50. 50. Top-Down CSS Selector Traditional style of traversal ✦ ✦ Used by all major libraries Work from left-to-right ✦ “div p” ✦ ✦ Find all divs, find paragraphs inside Requires a lot of result merging ✦ And removal of duplicates ✦
  51. 51.    function find(selector, root){       root = root || document;              var parts = selector.split(quot; quot;),         query = parts[0],         rest = parts.slice(1).join(quot; quot;),         elems = root.getElementsByTagName( query ),         results = [];              for ( var i = 0; i < elems.length; i++ ) {         if ( rest ) {           results = results.concat( find(rest, elems[i]) );         } else {           results.push( elems[i] );         }       }              return results;     } 
  52. 52.  (function(){     var run = 0;          this.unique = function( array ) {       var ret = [];              run++;          for ( var i = 0, length = array.length; i < length; i++ ) {         var elem = array[ i ];            if ( elem.uniqueID !== run ) {           elem.uniqueID = run;           ret.push( array[ i ] );         }       }          return ret;     };   })(); 
  53. 53. Bottom-Up Work from right-to-left ✦ ✦ (How CSS Engines work in browsers.) “div p” ✦ ✦ Find all paragraphs, see if they have a div ancestor, etc. Fast for specific queries ✦ ✦ “div #foo” Deep queries get slow (in comparison) ✦ ✦ “#foo p”
  54. 54. Bottom-Up Some nice features: ✦ ✦ Only one DOM query ✦ No merge/unique required (except for “div, span”) ✦ Everything is a process of filtering
  55. 55.    function find(selector, root){       root = root || document;              var parts = selector.split(quot; quot;),         query = parts[parts.length - 1],         rest = parts.slice(0,-1).join(quot;quot;).toUpperCase(),         elems = root.getElementsByTagName( query ),         results = [];              for ( var i = 0; i < elems.length; i++ ) {         if ( rest ) {           var parent = elems[i].parentNode;           while ( parent && parent.nodeName != rest ) {             parent = parent.parentNode;           }                      if ( parent ) {             results.push( elems[i] );           }         } else {           results.push( elems[i] );         }       }              return results;     } 
  56. 56. CSS to XPath Browsers provide XPath functionality ✦ Collect elements from a document ✦ Works in all browsers ✦ ✦ In IE it only works on HTML documents Fast for a number of selectors (.class, “div ✦ div div”) ✦ Slow for some others: #id Currently used by Dojo and Prototype ✦
  57. 57.  if ( typeof document.evaluate === quot;functionquot; ) {     function getElementsByXPath(expression, parentElement) {       var results = [];       var query = document.evaluate(expression, parentElement || document,         null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);       for (var i = 0, length = query.snapshotLength; i < length; i++)         results.push(query.snapshotItem(i));       return results;     }   } 
  58. 58. Goal CSS 3 XPath All Elements * //* All P Elements p //p All Child Elements p>* //p/* Element By ID #foo //*[@id='foo'] //*[contains(concat(quot; quot;, Element By Class .foo @class, quot; quot;),quot; foo quot;)] Element With Attribute *[title] //*[@title] First Child of All P p > *:first-child //p/*[0] All P with an A descendant //p[a] Not possible Next Element p+* //p/following-sibling::*[0]
  59. 59. querySelectorAll The Selectors API spec from the W3C ✦ Two methods: ✦ ✦ querySelector (first element) ✦ querySelectorAll (all elements) Works on: ✦ ✦ document ✦ elements ✦ DocumentFragments Implemented in: ✦ ✦ Firefox 3.1, Safari 3, Opera 10, IE 8
  60. 60.  <div id=quot;testquot;>     <b>Hello</b>, I'm a ninja!   </div>   <div id=quot;test2quot;></div>   <script>   window.onload = function(){     var divs = document.querySelectorAll(quot;body > divquot;);     assert( divs.length === 2, quot;Two divs found using a CSS selector.quot; );          var b = document.getElementById(quot;testquot;).querySelector(quot;b:only-childquot;);     assert( b, quot;The bold element was found relative to another element.quot; );  };   </script> 
  61. 61.  <div id=quot;testquot;>     <b>Hello</b>, I'm a ninja!   </div>   <script>   window.onload = function(){     var b = document.getElementById(quot;testquot;).querySelector(quot;div bquot;);     assert( b, quot;Only the last part of the selector matters.quot; );  };   </script> 
  62. 62. DOM Modification Injecting HTML ✦ Removing Elements ✦
  63. 63. Injecting HTML HTML 5: ✦ insertAdjacentHTML Already in IE, dicey support, at best ✦ What can we use instead? ✦ ✦ We must generate our own HTML injection ✦ Use innerHTML to generate a DOM
  64. 64.  function getNodes(htmlString){     var map = {       quot;<tdquot;: [3, quot;<table><tbody><tr>quot;, quot;</tr></tbody></table>quot;],       quot;<optionquot;: [1, quot;<select multiple='multiple'>quot;, quot;</select>quot;]       // a full list of all element fixes     };          var name = htmlString.match(/<w+/),       node = name ? map[ name[0] ] || [0, quot;quot;, quot;quot;];          var div = document.createElement(quot;divquot;);     div.innerHTML = node[1] + htmlString + node[2];          while ( node[0]-- )       div = div.lastChild;          return div.childNodes;   }      assert( getNodes(quot;<td>test</td><td>test2</td>quot;).length === 2,     quot;Get two nodes back from the method.quot; );   assert( getNodes(quot;<td>test</td>quot;).nodeName === quot;TDquot;,     quot;Verify that we're getting the right node.quot; ); 
  65. 65. Element Mappings option and optgroup need to be contained in a ✦ <select multiple=quot;multiplequot;>...</select> legend need to be contained in a ✦ <fieldset>...</fieldset> thead, tbody, tfoot, colgroup, and caption need to be ✦ contained in a <table>...</table> tr need to be in a ✦ <table><thead>...</thead></table>, <table><tbody>...</tbody></table>, or a <table><tfoot>...</tfoot></table> td and th need to be in a ✦ <table><tbody><tr>...</tr></tbody></table> col in a ✦ <table><tbody></tbody><colgroup>...</ colgroup></table> link and script need to be in a ✦ div<div>...</div>
  66. 66. DocumentFragment Fragments can collect nodes ✦ Can be appended or cloned in bulk ✦ Super-fast (2-3x faster than normal) ✦
  67. 67.    function insert(elems, args, callback){       if ( elems.length ) {         var doc = elems[0].ownerDocument || elems[0],           fragment = doc.createDocumentFragment(),           scripts = getNodes( args, doc, fragment ),           first = fragment.firstChild;                if ( first ) {           for ( var i = 0; elems[i]; i++ ) {             callback.call( root(elems[i], first),                i > 0 ? fragment.cloneNode(true) : fragment );           }         }       }     }          var divs = document.getElementsByTagName(quot;divquot;);          insert(divs, [quot;Name:quot;], function(fragment){       this.appendChild( fragment );     });          insert(divs, [quot;First Lastquot;], function(fragment){       this.parentNode.insertBefore( fragment, this );     }); 
  68. 68. Inline Script Execution .append(“<script>var foo = 5;</script>”); ✦ Must execute scripts globally ✦ window.execScript() (for IE) ✦ eval.call( window, “var foo = 5;” ); ✦ Cross-browser way is to build a script ✦ element then inject it ✦ Executes globally
  69. 69.  function globalEval( data ) {     data = data.replace(/^s+|s+$/g, quot;quot;);          if ( data ) {       var head = document.getElementsByTagName(quot;headquot;)[0] || document.documentElement,         script = document.createElement(quot;scriptquot;);              script.type = quot;text/javascriptquot;;       script.text = data;              head.insertBefore( script, head.firstChild );       head.removeChild( script );     }   } 
  70. 70. Removing Elements Have to clean up bound events ✦ ✦ IE memory leaks Easy to do if it’s managed. ✦
  71. 71. Events Three big problems with Events: ✦ ✦ Memory Leaks (in IE) ✦ Maintaining ‘this’ (in IE) ✦ Fixing event object inconsistencies
  72. 72. Leaks Internet Explorer 6 leaks horribly ✦ ✦ Other IEs still leak, not so badly Attaching functions (that have a closure to ✦ another node) as properties Makes a leak: ✦ elem.test = function(){ anotherElem.className = “foo”; };
  73. 73. ‘this’ Users like having their ‘this’ refer to the ✦ target element Not the case in IE ✦ What’s the solution? ✦
  74. 74. Single Handler Bind a single handler to an event ✦ Call each bound function individually ✦ Can fix ‘this’ and event object ✦ How do we store the bound functions in a ✦ way that won’t leak?
  75. 75. Central Data Store Store all bound event handlers in a central ✦ object Link elements to handlers ✦ Keep good separation ✦ One data store per library instance ✦ Easy to manipulate later ✦ ✦ Trigger individual handlers ✦ Easy to remove again, later
  76. 76. Central Data Store Events Data Element function click(){} #43 function mouseover(){} Element Data Element #67 Element Events Element function click(){} #22 function click(){} Data Store
  77. 77. Multiple Stores Element #43 Library A Element #67 Element Element #37 Element #22 Library B
  78. 78. Unique Element ID The structure must hook to an element ✦ Elements don’t have unique IDs ✦ Must generate them and manage them ✦ jQuery.data( elem, “events” ); ✦ Unique attribute name: ✦ ✦ elem.jQuery123456789 = 45; ✦ Prevents collisions with other libraries We can store all sorts of data in here ✦
  79. 79. Questions? http://ejohn.org/ ✦ http://twitter.com/jeresig/ ✦
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×