The document discusses the messy and buggy state of the DOM across browsers and strategies for writing cross-browser JavaScript code. It notes that nearly every DOM method has bugs or inconsistencies in some browsers. It then covers strategies like feature detection, graceful fallback for missing features, simulating features via workarounds, monitoring for regressions, and having a robust test suite to prevent regressions in one's own code. The overall message is that the DOM is messy and one needs to "know your enemies" by thoroughly testing code in all target browsers.
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
The DOM is a Mess @ Yahoo
1. The DOM is a Mess
John Resig
http://ejohn.org/ - http://twitter.com/jeresig/
2. A Tour of the DOM
A messy DOM
✦
Writing Cross-Browser Code
✦
Common Features
✦
✦ CSS Selector Engine
✦ DOM Modification
✦ Events
3. Messy
Nearly every DOM method is broken in
✦
some way, in some browser.
Some old:
✦
✦ getElementById
✦ getElementsByTagName
Some new:
✦
✦ getElementsByClassName
✦ querySelectorAll
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. 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. 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. 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. Moral
If there’s a DOM method, there’s probably
✦
a problem with it somewhere, in some
capacity.
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. 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. Know Your Enemies
Points of Concern for JavaScript Code
Browser Bugs
Regressions
Missing Features JavaScript Code
Bug Fixes
External
Code, Markup
16. Know Your Enemies
Points of Concern for JavaScript Code
Browser Bugs
Regressions
Missing Features JavaScript Code
Bug Fixes
External
Code, Markup
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?
19. Know Your Enemies
Points of Concern for JavaScript Code
Browser Bugs
Regressions
Missing Features JavaScript Code
Bug Fixes
External
Code, Markup
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. 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)
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. 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
27. Know Your Enemies
Points of Concern for JavaScript Code
Browser Bugs
Regressions
Missing Features JavaScript Code
Bug Fixes
External
Code, Markup
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. 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
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. Know Your Enemies
Points of Concern for JavaScript Code
Browser Bugs
Regressions
Missing Features JavaScript Code
Bug Fixes
External
Code, Markup
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. 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. Feature Simulation
More advanced than object detection
✦
Make sure an API works as advertised
✦
Able to capture bug fixes gracefully
✦
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. Impractical to Test
Performance-related issues
✦
Determining if Ajax requests will work
✦
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. DOM Traversal
Many methods of DOM traversal
✦
One unanimous solution:
✦
✦ CSS Selector Engine
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. 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. 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. (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. 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. Bottom-Up
Some nice features:
✦
✦ Only one DOM query
✦ No merge/unique required (except for
“div, span”)
✦ Everything is a process of filtering
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. 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
✦
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. 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
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
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. DocumentFragment
Fragments can collect nodes
✦
Can be appended or cloned in bulk
✦
Super-fast (2-3x faster than normal)
✦
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. 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. Removing Elements
Have to clean up bound events
✦
✦ IE memory leaks
Easy to do if it’s managed.
✦
71. Events
Three big problems with Events:
✦
✦ Memory Leaks (in IE)
✦ Maintaining ‘this’ (in IE)
✦ Fixing event object inconsistencies
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. ‘this’
Users like having their ‘this’ refer to the
✦
target element
Not the case in IE
✦
What’s the solution?
✦
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. 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. 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
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
✦