parsejs 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
 - data/.gitignore +18 -0
 - data/.rspec +1 -0
 - data/.travis.yml +9 -0
 - data/Gemfile +5 -0
 - data/README.markdown +85 -0
 - data/Rakefile +15 -0
 - data/lib/parsejs.rb +14 -0
 - data/lib/parsejs/ast.rb +84 -0
 - data/lib/parsejs/docs.rb +237 -0
 - data/lib/parsejs/grammar.kpeg +575 -0
 - data/lib/parsejs/grammar.kpeg.rb +9460 -0
 - data/lib/parsejs/scope.rb +183 -0
 - data/lib/parsejs/stringifier.rb +450 -0
 - data/lib/parsejs/version.rb +3 -0
 - data/lib/parsejs/visitor.rb +257 -0
 - data/parsejs.gemspec +24 -0
 - data/spec/fixtures/jquery-1.6.js +8982 -0
 - data/spec/fixtures/jquery-1.7.js +9289 -0
 - data/spec/fixtures/jquery-ajax.js +1000 -0
 - data/spec/fixtures/jquery-attributes.js +650 -0
 - data/spec/fixtures/jquery-traversing.js +330 -0
 - data/spec/fixtures/metamorph.js +324 -0
 - data/spec/fixtures/sizzle.js +1442 -0
 - data/spec/fixtures/sproutcore-core.js +195 -0
 - data/spec/fixtures/sproutcore-each-proxy.js +218 -0
 - data/spec/fixtures/sproutcore-native-array.js +139 -0
 - data/spec/fixtures/sproutcore.js +14319 -0
 - data/spec/scope_spec.rb +111 -0
 - data/spec/stringify_spec.rb +587 -0
 - data/test.rb +76 -0
 - metadata +145 -0
 
| 
         @@ -0,0 +1,330 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            (function( jQuery ) {
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            var runtil = /Until$/,
         
     | 
| 
      
 4 
     | 
    
         
            +
            	rparentsprev = /^(?:parents|prevUntil|prevAll)/,
         
     | 
| 
      
 5 
     | 
    
         
            +
            	// Note: This RegExp should be improved, or likely pulled from Sizzle
         
     | 
| 
      
 6 
     | 
    
         
            +
            	rmultiselector = /,/,
         
     | 
| 
      
 7 
     | 
    
         
            +
            	isSimple = /^.[^:#\[\.,]*$/,
         
     | 
| 
      
 8 
     | 
    
         
            +
            	slice = Array.prototype.slice,
         
     | 
| 
      
 9 
     | 
    
         
            +
            	POS = jQuery.expr.match.POS,
         
     | 
| 
      
 10 
     | 
    
         
            +
            	// methods guaranteed to produce a unique set when starting from a unique set
         
     | 
| 
      
 11 
     | 
    
         
            +
            	guaranteedUnique = {
         
     | 
| 
      
 12 
     | 
    
         
            +
            		children: true,
         
     | 
| 
      
 13 
     | 
    
         
            +
            		contents: true,
         
     | 
| 
      
 14 
     | 
    
         
            +
            		next: true,
         
     | 
| 
      
 15 
     | 
    
         
            +
            		prev: true
         
     | 
| 
      
 16 
     | 
    
         
            +
            	};
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
            jQuery.fn.extend({
         
     | 
| 
      
 19 
     | 
    
         
            +
            	find: function( selector ) {
         
     | 
| 
      
 20 
     | 
    
         
            +
            		var self = this,
         
     | 
| 
      
 21 
     | 
    
         
            +
            			i, l;
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            		if ( typeof selector !== "string" ) {
         
     | 
| 
      
 24 
     | 
    
         
            +
            			return jQuery( selector ).filter(function() {
         
     | 
| 
      
 25 
     | 
    
         
            +
            				for ( i = 0, l = self.length; i < l; i++ ) {
         
     | 
| 
      
 26 
     | 
    
         
            +
            					if ( jQuery.contains( self[ i ], this ) ) {
         
     | 
| 
      
 27 
     | 
    
         
            +
            						return true;
         
     | 
| 
      
 28 
     | 
    
         
            +
            					}
         
     | 
| 
      
 29 
     | 
    
         
            +
            				}
         
     | 
| 
      
 30 
     | 
    
         
            +
            			});
         
     | 
| 
      
 31 
     | 
    
         
            +
            		}
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
            		var ret = this.pushStack( "", "find", selector ),
         
     | 
| 
      
 34 
     | 
    
         
            +
            			length, n, r;
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
            		for ( i = 0, l = this.length; i < l; i++ ) {
         
     | 
| 
      
 37 
     | 
    
         
            +
            			length = ret.length;
         
     | 
| 
      
 38 
     | 
    
         
            +
            			jQuery.find( selector, this[i], ret );
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
            			if ( i > 0 ) {
         
     | 
| 
      
 41 
     | 
    
         
            +
            				// Make sure that the results are unique
         
     | 
| 
      
 42 
     | 
    
         
            +
            				for ( n = length; n < ret.length; n++ ) {
         
     | 
| 
      
 43 
     | 
    
         
            +
            					for ( r = 0; r < length; r++ ) {
         
     | 
| 
      
 44 
     | 
    
         
            +
            						if ( ret[r] === ret[n] ) {
         
     | 
| 
      
 45 
     | 
    
         
            +
            							ret.splice(n--, 1);
         
     | 
| 
      
 46 
     | 
    
         
            +
            							break;
         
     | 
| 
      
 47 
     | 
    
         
            +
            						}
         
     | 
| 
      
 48 
     | 
    
         
            +
            					}
         
     | 
| 
      
 49 
     | 
    
         
            +
            				}
         
     | 
| 
      
 50 
     | 
    
         
            +
            			}
         
     | 
| 
      
 51 
     | 
    
         
            +
            		}
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
            		return ret;
         
     | 
| 
      
 54 
     | 
    
         
            +
            	},
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
            	has: function( target ) {
         
     | 
| 
      
 57 
     | 
    
         
            +
            		var targets = jQuery( target );
         
     | 
| 
      
 58 
     | 
    
         
            +
            		return this.filter(function() {
         
     | 
| 
      
 59 
     | 
    
         
            +
            			for ( var i = 0, l = targets.length; i < l; i++ ) {
         
     | 
| 
      
 60 
     | 
    
         
            +
            				if ( jQuery.contains( this, targets[i] ) ) {
         
     | 
| 
      
 61 
     | 
    
         
            +
            					return true;
         
     | 
| 
      
 62 
     | 
    
         
            +
            				}
         
     | 
| 
      
 63 
     | 
    
         
            +
            			}
         
     | 
| 
      
 64 
     | 
    
         
            +
            		});
         
     | 
| 
      
 65 
     | 
    
         
            +
            	},
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
            	not: function( selector ) {
         
     | 
| 
      
 68 
     | 
    
         
            +
            		return this.pushStack( winnow(this, selector, false), "not", selector);
         
     | 
| 
      
 69 
     | 
    
         
            +
            	},
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
            	filter: function( selector ) {
         
     | 
| 
      
 72 
     | 
    
         
            +
            		return this.pushStack( winnow(this, selector, true), "filter", selector );
         
     | 
| 
      
 73 
     | 
    
         
            +
            	},
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
            	is: function( selector ) {
         
     | 
| 
      
 76 
     | 
    
         
            +
            		return !!selector && ( 
         
     | 
| 
      
 77 
     | 
    
         
            +
            			typeof selector === "string" ?
         
     | 
| 
      
 78 
     | 
    
         
            +
            				// If this is a positional selector, check membership in the returned set
         
     | 
| 
      
 79 
     | 
    
         
            +
            				// so $("p:first").is("p:last") won't return true for a doc with two "p".
         
     | 
| 
      
 80 
     | 
    
         
            +
            				POS.test( selector ) ? 
         
     | 
| 
      
 81 
     | 
    
         
            +
            					jQuery( selector, this.context ).index( this[0] ) >= 0 :
         
     | 
| 
      
 82 
     | 
    
         
            +
            					jQuery.filter( selector, this ).length > 0 :
         
     | 
| 
      
 83 
     | 
    
         
            +
            				this.filter( selector ).length > 0 );
         
     | 
| 
      
 84 
     | 
    
         
            +
            	},
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
            	closest: function( selectors, context ) {
         
     | 
| 
      
 87 
     | 
    
         
            +
            		var ret = [], i, l, cur = this[0];
         
     | 
| 
      
 88 
     | 
    
         
            +
            		
         
     | 
| 
      
 89 
     | 
    
         
            +
            		// Array (deprecated as of jQuery 1.7)
         
     | 
| 
      
 90 
     | 
    
         
            +
            		if ( jQuery.isArray( selectors ) ) {
         
     | 
| 
      
 91 
     | 
    
         
            +
            			var level = 1;
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
            			while ( cur && cur.ownerDocument && cur !== context ) {
         
     | 
| 
      
 94 
     | 
    
         
            +
            				for ( i = 0; i < selectors.length; i++ ) {
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
            					if ( jQuery( cur ).is( selectors[ i ] ) ) {
         
     | 
| 
      
 97 
     | 
    
         
            +
            						ret.push({ selector: selectors[ i ], elem: cur, level: level });
         
     | 
| 
      
 98 
     | 
    
         
            +
            					}
         
     | 
| 
      
 99 
     | 
    
         
            +
            				}
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
            				cur = cur.parentNode;
         
     | 
| 
      
 102 
     | 
    
         
            +
            				level++;
         
     | 
| 
      
 103 
     | 
    
         
            +
            			}
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
            			return ret;
         
     | 
| 
      
 106 
     | 
    
         
            +
            		}
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
            		// String
         
     | 
| 
      
 109 
     | 
    
         
            +
            		var pos = POS.test( selectors ) || typeof selectors !== "string" ?
         
     | 
| 
      
 110 
     | 
    
         
            +
            				jQuery( selectors, context || this.context ) :
         
     | 
| 
      
 111 
     | 
    
         
            +
            				0;
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
            		for ( i = 0, l = this.length; i < l; i++ ) {
         
     | 
| 
      
 114 
     | 
    
         
            +
            			cur = this[i];
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
            			while ( cur ) {
         
     | 
| 
      
 117 
     | 
    
         
            +
            				if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {
         
     | 
| 
      
 118 
     | 
    
         
            +
            					ret.push( cur );
         
     | 
| 
      
 119 
     | 
    
         
            +
            					break;
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
      
 121 
     | 
    
         
            +
            				} else {
         
     | 
| 
      
 122 
     | 
    
         
            +
            					cur = cur.parentNode;
         
     | 
| 
      
 123 
     | 
    
         
            +
            					if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) {
         
     | 
| 
      
 124 
     | 
    
         
            +
            						break;
         
     | 
| 
      
 125 
     | 
    
         
            +
            					}
         
     | 
| 
      
 126 
     | 
    
         
            +
            				}
         
     | 
| 
      
 127 
     | 
    
         
            +
            			}
         
     | 
| 
      
 128 
     | 
    
         
            +
            		}
         
     | 
| 
      
 129 
     | 
    
         
            +
             
     | 
| 
      
 130 
     | 
    
         
            +
            		ret = ret.length > 1 ? jQuery.unique( ret ) : ret;
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
      
 132 
     | 
    
         
            +
            		return this.pushStack( ret, "closest", selectors );
         
     | 
| 
      
 133 
     | 
    
         
            +
            	},
         
     | 
| 
      
 134 
     | 
    
         
            +
             
     | 
| 
      
 135 
     | 
    
         
            +
            	// Determine the position of an element within
         
     | 
| 
      
 136 
     | 
    
         
            +
            	// the matched set of elements
         
     | 
| 
      
 137 
     | 
    
         
            +
            	index: function( elem ) {
         
     | 
| 
      
 138 
     | 
    
         
            +
             
     | 
| 
      
 139 
     | 
    
         
            +
            		// No argument, return index in parent
         
     | 
| 
      
 140 
     | 
    
         
            +
            		if ( !elem ) {
         
     | 
| 
      
 141 
     | 
    
         
            +
            			return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1;
         
     | 
| 
      
 142 
     | 
    
         
            +
            		}
         
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
      
 144 
     | 
    
         
            +
            		// index in selector
         
     | 
| 
      
 145 
     | 
    
         
            +
            		if ( typeof elem === "string" ) {
         
     | 
| 
      
 146 
     | 
    
         
            +
            			return jQuery.inArray( this[0], jQuery( elem ) );
         
     | 
| 
      
 147 
     | 
    
         
            +
            		}
         
     | 
| 
      
 148 
     | 
    
         
            +
             
     | 
| 
      
 149 
     | 
    
         
            +
            		// Locate the position of the desired element
         
     | 
| 
      
 150 
     | 
    
         
            +
            		return jQuery.inArray(
         
     | 
| 
      
 151 
     | 
    
         
            +
            			// If it receives a jQuery object, the first element is used
         
     | 
| 
      
 152 
     | 
    
         
            +
            			elem.jquery ? elem[0] : elem, this );
         
     | 
| 
      
 153 
     | 
    
         
            +
            	},
         
     | 
| 
      
 154 
     | 
    
         
            +
             
     | 
| 
      
 155 
     | 
    
         
            +
            	add: function( selector, context ) {
         
     | 
| 
      
 156 
     | 
    
         
            +
            		var set = typeof selector === "string" ?
         
     | 
| 
      
 157 
     | 
    
         
            +
            				jQuery( selector, context ) :
         
     | 
| 
      
 158 
     | 
    
         
            +
            				jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
         
     | 
| 
      
 159 
     | 
    
         
            +
            			all = jQuery.merge( this.get(), set );
         
     | 
| 
      
 160 
     | 
    
         
            +
             
     | 
| 
      
 161 
     | 
    
         
            +
            		return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?
         
     | 
| 
      
 162 
     | 
    
         
            +
            			all :
         
     | 
| 
      
 163 
     | 
    
         
            +
            			jQuery.unique( all ) );
         
     | 
| 
      
 164 
     | 
    
         
            +
            	},
         
     | 
| 
      
 165 
     | 
    
         
            +
             
     | 
| 
      
 166 
     | 
    
         
            +
            	andSelf: function() {
         
     | 
| 
      
 167 
     | 
    
         
            +
            		return this.add( this.prevObject );
         
     | 
| 
      
 168 
     | 
    
         
            +
            	}
         
     | 
| 
      
 169 
     | 
    
         
            +
            });
         
     | 
| 
      
 170 
     | 
    
         
            +
             
     | 
| 
      
 171 
     | 
    
         
            +
            // A painfully simple check to see if an element is disconnected
         
     | 
| 
      
 172 
     | 
    
         
            +
            // from a document (should be improved, where feasible).
         
     | 
| 
      
 173 
     | 
    
         
            +
            function isDisconnected( node ) {
         
     | 
| 
      
 174 
     | 
    
         
            +
            	return !node || !node.parentNode || node.parentNode.nodeType === 11;
         
     | 
| 
      
 175 
     | 
    
         
            +
            }
         
     | 
| 
      
 176 
     | 
    
         
            +
             
     | 
| 
      
 177 
     | 
    
         
            +
            jQuery.each({
         
     | 
| 
      
 178 
     | 
    
         
            +
            	parent: function( elem ) {
         
     | 
| 
      
 179 
     | 
    
         
            +
            		var parent = elem.parentNode;
         
     | 
| 
      
 180 
     | 
    
         
            +
            		return parent && parent.nodeType !== 11 ? parent : null;
         
     | 
| 
      
 181 
     | 
    
         
            +
            	},
         
     | 
| 
      
 182 
     | 
    
         
            +
            	parents: function( elem ) {
         
     | 
| 
      
 183 
     | 
    
         
            +
            		return jQuery.dir( elem, "parentNode" );
         
     | 
| 
      
 184 
     | 
    
         
            +
            	},
         
     | 
| 
      
 185 
     | 
    
         
            +
            	parentsUntil: function( elem, i, until ) {
         
     | 
| 
      
 186 
     | 
    
         
            +
            		return jQuery.dir( elem, "parentNode", until );
         
     | 
| 
      
 187 
     | 
    
         
            +
            	},
         
     | 
| 
      
 188 
     | 
    
         
            +
            	next: function( elem ) {
         
     | 
| 
      
 189 
     | 
    
         
            +
            		return jQuery.nth( elem, 2, "nextSibling" );
         
     | 
| 
      
 190 
     | 
    
         
            +
            	},
         
     | 
| 
      
 191 
     | 
    
         
            +
            	prev: function( elem ) {
         
     | 
| 
      
 192 
     | 
    
         
            +
            		return jQuery.nth( elem, 2, "previousSibling" );
         
     | 
| 
      
 193 
     | 
    
         
            +
            	},
         
     | 
| 
      
 194 
     | 
    
         
            +
            	nextAll: function( elem ) {
         
     | 
| 
      
 195 
     | 
    
         
            +
            		return jQuery.dir( elem, "nextSibling" );
         
     | 
| 
      
 196 
     | 
    
         
            +
            	},
         
     | 
| 
      
 197 
     | 
    
         
            +
            	prevAll: function( elem ) {
         
     | 
| 
      
 198 
     | 
    
         
            +
            		return jQuery.dir( elem, "previousSibling" );
         
     | 
| 
      
 199 
     | 
    
         
            +
            	},
         
     | 
| 
      
 200 
     | 
    
         
            +
            	nextUntil: function( elem, i, until ) {
         
     | 
| 
      
 201 
     | 
    
         
            +
            		return jQuery.dir( elem, "nextSibling", until );
         
     | 
| 
      
 202 
     | 
    
         
            +
            	},
         
     | 
| 
      
 203 
     | 
    
         
            +
            	prevUntil: function( elem, i, until ) {
         
     | 
| 
      
 204 
     | 
    
         
            +
            		return jQuery.dir( elem, "previousSibling", until );
         
     | 
| 
      
 205 
     | 
    
         
            +
            	},
         
     | 
| 
      
 206 
     | 
    
         
            +
            	siblings: function( elem ) {
         
     | 
| 
      
 207 
     | 
    
         
            +
            		return jQuery.sibling( elem.parentNode.firstChild, elem );
         
     | 
| 
      
 208 
     | 
    
         
            +
            	},
         
     | 
| 
      
 209 
     | 
    
         
            +
            	children: function( elem ) {
         
     | 
| 
      
 210 
     | 
    
         
            +
            		return jQuery.sibling( elem.firstChild );
         
     | 
| 
      
 211 
     | 
    
         
            +
            	},
         
     | 
| 
      
 212 
     | 
    
         
            +
            	contents: function( elem ) {
         
     | 
| 
      
 213 
     | 
    
         
            +
            		return jQuery.nodeName( elem, "iframe" ) ?
         
     | 
| 
      
 214 
     | 
    
         
            +
            			elem.contentDocument || elem.contentWindow.document :
         
     | 
| 
      
 215 
     | 
    
         
            +
            			jQuery.makeArray( elem.childNodes );
         
     | 
| 
      
 216 
     | 
    
         
            +
            	}
         
     | 
| 
      
 217 
     | 
    
         
            +
            }, function( name, fn ) {
         
     | 
| 
      
 218 
     | 
    
         
            +
            	jQuery.fn[ name ] = function( until, selector ) {
         
     | 
| 
      
 219 
     | 
    
         
            +
            		var ret = jQuery.map( this, fn, until ),
         
     | 
| 
      
 220 
     | 
    
         
            +
            			// The variable 'args' was introduced in
         
     | 
| 
      
 221 
     | 
    
         
            +
            			// https://github.com/jquery/jquery/commit/52a0238
         
     | 
| 
      
 222 
     | 
    
         
            +
            			// to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed.
         
     | 
| 
      
 223 
     | 
    
         
            +
            			// http://code.google.com/p/v8/issues/detail?id=1050
         
     | 
| 
      
 224 
     | 
    
         
            +
            			args = slice.call(arguments);
         
     | 
| 
      
 225 
     | 
    
         
            +
             
     | 
| 
      
 226 
     | 
    
         
            +
            		if ( !runtil.test( name ) ) {
         
     | 
| 
      
 227 
     | 
    
         
            +
            			selector = until;
         
     | 
| 
      
 228 
     | 
    
         
            +
            		}
         
     | 
| 
      
 229 
     | 
    
         
            +
             
     | 
| 
      
 230 
     | 
    
         
            +
            		if ( selector && typeof selector === "string" ) {
         
     | 
| 
      
 231 
     | 
    
         
            +
            			ret = jQuery.filter( selector, ret );
         
     | 
| 
      
 232 
     | 
    
         
            +
            		}
         
     | 
| 
      
 233 
     | 
    
         
            +
             
     | 
| 
      
 234 
     | 
    
         
            +
            		ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
         
     | 
| 
      
 235 
     | 
    
         
            +
             
     | 
| 
      
 236 
     | 
    
         
            +
            		if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
         
     | 
| 
      
 237 
     | 
    
         
            +
            			ret = ret.reverse();
         
     | 
| 
      
 238 
     | 
    
         
            +
            		}
         
     | 
| 
      
 239 
     | 
    
         
            +
             
     | 
| 
      
 240 
     | 
    
         
            +
            		return this.pushStack( ret, name, args.join(",") );
         
     | 
| 
      
 241 
     | 
    
         
            +
            	};
         
     | 
| 
      
 242 
     | 
    
         
            +
            });
         
     | 
| 
      
 243 
     | 
    
         
            +
             
     | 
| 
      
 244 
     | 
    
         
            +
            jQuery.extend({
         
     | 
| 
      
 245 
     | 
    
         
            +
            	filter: function( expr, elems, not ) {
         
     | 
| 
      
 246 
     | 
    
         
            +
            		if ( not ) {
         
     | 
| 
      
 247 
     | 
    
         
            +
            			expr = ":not(" + expr + ")";
         
     | 
| 
      
 248 
     | 
    
         
            +
            		}
         
     | 
| 
      
 249 
     | 
    
         
            +
             
     | 
| 
      
 250 
     | 
    
         
            +
            		return elems.length === 1 ?
         
     | 
| 
      
 251 
     | 
    
         
            +
            			jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :
         
     | 
| 
      
 252 
     | 
    
         
            +
            			jQuery.find.matches(expr, elems);
         
     | 
| 
      
 253 
     | 
    
         
            +
            	},
         
     | 
| 
      
 254 
     | 
    
         
            +
             
     | 
| 
      
 255 
     | 
    
         
            +
            	dir: function( elem, dir, until ) {
         
     | 
| 
      
 256 
     | 
    
         
            +
            		var matched = [],
         
     | 
| 
      
 257 
     | 
    
         
            +
            			cur = elem[ dir ];
         
     | 
| 
      
 258 
     | 
    
         
            +
             
     | 
| 
      
 259 
     | 
    
         
            +
            		while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
         
     | 
| 
      
 260 
     | 
    
         
            +
            			if ( cur.nodeType === 1 ) {
         
     | 
| 
      
 261 
     | 
    
         
            +
            				matched.push( cur );
         
     | 
| 
      
 262 
     | 
    
         
            +
            			}
         
     | 
| 
      
 263 
     | 
    
         
            +
            			cur = cur[dir];
         
     | 
| 
      
 264 
     | 
    
         
            +
            		}
         
     | 
| 
      
 265 
     | 
    
         
            +
            		return matched;
         
     | 
| 
      
 266 
     | 
    
         
            +
            	},
         
     | 
| 
      
 267 
     | 
    
         
            +
             
     | 
| 
      
 268 
     | 
    
         
            +
            	nth: function( cur, result, dir, elem ) {
         
     | 
| 
      
 269 
     | 
    
         
            +
            		result = result || 1;
         
     | 
| 
      
 270 
     | 
    
         
            +
            		var num = 0;
         
     | 
| 
      
 271 
     | 
    
         
            +
             
     | 
| 
      
 272 
     | 
    
         
            +
            		for ( ; cur; cur = cur[dir] ) {
         
     | 
| 
      
 273 
     | 
    
         
            +
            			if ( cur.nodeType === 1 && ++num === result ) {
         
     | 
| 
      
 274 
     | 
    
         
            +
            				break;
         
     | 
| 
      
 275 
     | 
    
         
            +
            			}
         
     | 
| 
      
 276 
     | 
    
         
            +
            		}
         
     | 
| 
      
 277 
     | 
    
         
            +
             
     | 
| 
      
 278 
     | 
    
         
            +
            		return cur;
         
     | 
| 
      
 279 
     | 
    
         
            +
            	},
         
     | 
| 
      
 280 
     | 
    
         
            +
             
     | 
| 
      
 281 
     | 
    
         
            +
            	sibling: function( n, elem ) {
         
     | 
| 
      
 282 
     | 
    
         
            +
            		var r = [];
         
     | 
| 
      
 283 
     | 
    
         
            +
             
     | 
| 
      
 284 
     | 
    
         
            +
            		for ( ; n; n = n.nextSibling ) {
         
     | 
| 
      
 285 
     | 
    
         
            +
            			if ( n.nodeType === 1 && n !== elem ) {
         
     | 
| 
      
 286 
     | 
    
         
            +
            				r.push( n );
         
     | 
| 
      
 287 
     | 
    
         
            +
            			}
         
     | 
| 
      
 288 
     | 
    
         
            +
            		}
         
     | 
| 
      
 289 
     | 
    
         
            +
             
     | 
| 
      
 290 
     | 
    
         
            +
            		return r;
         
     | 
| 
      
 291 
     | 
    
         
            +
            	}
         
     | 
| 
      
 292 
     | 
    
         
            +
            });
         
     | 
| 
      
 293 
     | 
    
         
            +
             
     | 
| 
      
 294 
     | 
    
         
            +
            // Implement the identical functionality for filter and not
         
     | 
| 
      
 295 
     | 
    
         
            +
            function winnow( elements, qualifier, keep ) {
         
     | 
| 
      
 296 
     | 
    
         
            +
             
     | 
| 
      
 297 
     | 
    
         
            +
            	// Can't pass null or undefined to indexOf in Firefox 4
         
     | 
| 
      
 298 
     | 
    
         
            +
            	// Set to 0 to skip string check
         
     | 
| 
      
 299 
     | 
    
         
            +
            	qualifier = qualifier || 0;
         
     | 
| 
      
 300 
     | 
    
         
            +
             
     | 
| 
      
 301 
     | 
    
         
            +
            	if ( jQuery.isFunction( qualifier ) ) {
         
     | 
| 
      
 302 
     | 
    
         
            +
            		return jQuery.grep(elements, function( elem, i ) {
         
     | 
| 
      
 303 
     | 
    
         
            +
            			var retVal = !!qualifier.call( elem, i, elem );
         
     | 
| 
      
 304 
     | 
    
         
            +
            			return retVal === keep;
         
     | 
| 
      
 305 
     | 
    
         
            +
            		});
         
     | 
| 
      
 306 
     | 
    
         
            +
             
     | 
| 
      
 307 
     | 
    
         
            +
            	} else if ( qualifier.nodeType ) {
         
     | 
| 
      
 308 
     | 
    
         
            +
            		return jQuery.grep(elements, function( elem, i ) {
         
     | 
| 
      
 309 
     | 
    
         
            +
            			return (elem === qualifier) === keep;
         
     | 
| 
      
 310 
     | 
    
         
            +
            		});
         
     | 
| 
      
 311 
     | 
    
         
            +
             
     | 
| 
      
 312 
     | 
    
         
            +
            	} else if ( typeof qualifier === "string" ) {
         
     | 
| 
      
 313 
     | 
    
         
            +
            		var filtered = jQuery.grep(elements, function( elem ) {
         
     | 
| 
      
 314 
     | 
    
         
            +
            			return elem.nodeType === 1;
         
     | 
| 
      
 315 
     | 
    
         
            +
            		});
         
     | 
| 
      
 316 
     | 
    
         
            +
             
     | 
| 
      
 317 
     | 
    
         
            +
            		if ( isSimple.test( qualifier ) ) {
         
     | 
| 
      
 318 
     | 
    
         
            +
            			return jQuery.filter(qualifier, filtered, !keep);
         
     | 
| 
      
 319 
     | 
    
         
            +
            		} else {
         
     | 
| 
      
 320 
     | 
    
         
            +
            			qualifier = jQuery.filter( qualifier, filtered );
         
     | 
| 
      
 321 
     | 
    
         
            +
            		}
         
     | 
| 
      
 322 
     | 
    
         
            +
            	}
         
     | 
| 
      
 323 
     | 
    
         
            +
             
     | 
| 
      
 324 
     | 
    
         
            +
            	return jQuery.grep(elements, function( elem, i ) {
         
     | 
| 
      
 325 
     | 
    
         
            +
            		return (jQuery.inArray( elem, qualifier ) >= 0) === keep;
         
     | 
| 
      
 326 
     | 
    
         
            +
            	});
         
     | 
| 
      
 327 
     | 
    
         
            +
            }
         
     | 
| 
      
 328 
     | 
    
         
            +
             
     | 
| 
      
 329 
     | 
    
         
            +
            })( jQuery );
         
     | 
| 
      
 330 
     | 
    
         
            +
             
     | 
| 
         @@ -0,0 +1,324 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            // ==========================================================================
         
     | 
| 
      
 2 
     | 
    
         
            +
            // Project:   metamorph
         
     | 
| 
      
 3 
     | 
    
         
            +
            // Copyright: ©2011 My Company Inc. All rights reserved.
         
     | 
| 
      
 4 
     | 
    
         
            +
            // ==========================================================================
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            (function(window) {
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
              var K = function(){},
         
     | 
| 
      
 9 
     | 
    
         
            +
                  guid = 0,
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                  // Feature-detect the W3C range API
         
     | 
| 
      
 12 
     | 
    
         
            +
                  supportsRange = ('createRange' in document);
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
              // Constructor that supports either Metamorph('foo') or new
         
     | 
| 
      
 15 
     | 
    
         
            +
              // Metamorph('foo');
         
     | 
| 
      
 16 
     | 
    
         
            +
              // 
         
     | 
| 
      
 17 
     | 
    
         
            +
              // Takes a string of HTML as the argument.
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
              var Metamorph = function(html) {
         
     | 
| 
      
 20 
     | 
    
         
            +
                var self;
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                if (this instanceof Metamorph) {
         
     | 
| 
      
 23 
     | 
    
         
            +
                  self = this;
         
     | 
| 
      
 24 
     | 
    
         
            +
                } else {
         
     | 
| 
      
 25 
     | 
    
         
            +
                  self = new K;
         
     | 
| 
      
 26 
     | 
    
         
            +
                }
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                self.innerHTML = html;
         
     | 
| 
      
 29 
     | 
    
         
            +
                var myGuid = 'metamorph-'+(guid++);
         
     | 
| 
      
 30 
     | 
    
         
            +
                self.start = myGuid + '-start';
         
     | 
| 
      
 31 
     | 
    
         
            +
                self.end = myGuid + '-end';
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                return self;
         
     | 
| 
      
 34 
     | 
    
         
            +
              };
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
              K.prototype = Metamorph.prototype;
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
              var rangeFor, htmlFunc, removeFunc, outerHTMLFunc, appendToFunc, startTagFunc, endTagFunc;
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
              // create the outer HTML for the current metamorph. this function will be
         
     | 
| 
      
 41 
     | 
    
         
            +
              // extended by the Internet Explorer version to work around a bug.
         
     | 
| 
      
 42 
     | 
    
         
            +
              outerHTMLFunc = function() {
         
     | 
| 
      
 43 
     | 
    
         
            +
                return this.startTag() + this.innerHTML + this.endTag();
         
     | 
| 
      
 44 
     | 
    
         
            +
              };
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
              startTagFunc = function() {
         
     | 
| 
      
 47 
     | 
    
         
            +
                return "<script id='" + this.start + "' type='text/x-placeholder'></script>";
         
     | 
| 
      
 48 
     | 
    
         
            +
              };
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
              endTagFunc = function() {
         
     | 
| 
      
 51 
     | 
    
         
            +
                return "<script id='" + this.end + "' type='text/x-placeholder'></script>";
         
     | 
| 
      
 52 
     | 
    
         
            +
              };
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
              // If we have the W3C range API, this process is relatively straight forward.
         
     | 
| 
      
 55 
     | 
    
         
            +
              if (supportsRange) {
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                // Get a range for the current morph. Optionally include the starting and
         
     | 
| 
      
 58 
     | 
    
         
            +
                // ending placeholders.
         
     | 
| 
      
 59 
     | 
    
         
            +
                rangeFor = function(morph, outerToo) {
         
     | 
| 
      
 60 
     | 
    
         
            +
                  var range = document.createRange();
         
     | 
| 
      
 61 
     | 
    
         
            +
                  var before = document.getElementById(morph.start);
         
     | 
| 
      
 62 
     | 
    
         
            +
                  var after = document.getElementById(morph.end);
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                  if (outerToo) {
         
     | 
| 
      
 65 
     | 
    
         
            +
                    range.setStartBefore(before);
         
     | 
| 
      
 66 
     | 
    
         
            +
                    range.setEndAfter(after);
         
     | 
| 
      
 67 
     | 
    
         
            +
                  } else {
         
     | 
| 
      
 68 
     | 
    
         
            +
                    range.setStartAfter(before);
         
     | 
| 
      
 69 
     | 
    
         
            +
                    range.setEndBefore(after);
         
     | 
| 
      
 70 
     | 
    
         
            +
                  }
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                  return range;
         
     | 
| 
      
 73 
     | 
    
         
            +
                };
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                htmlFunc = function(html, outerToo) {
         
     | 
| 
      
 76 
     | 
    
         
            +
                  // get a range for the current metamorph object
         
     | 
| 
      
 77 
     | 
    
         
            +
                  var range = rangeFor(this, outerToo);
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                  // delete the contents of the range, which will be the
         
     | 
| 
      
 80 
     | 
    
         
            +
                  // nodes between the starting and ending placeholder.
         
     | 
| 
      
 81 
     | 
    
         
            +
                  range.deleteContents();
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                  // create a new document fragment for the HTML
         
     | 
| 
      
 84 
     | 
    
         
            +
                  var fragment = range.createContextualFragment(html);
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                  // inser the fragment into the range
         
     | 
| 
      
 87 
     | 
    
         
            +
                  range.insertNode(fragment);
         
     | 
| 
      
 88 
     | 
    
         
            +
                };
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                removeFunc = function() {
         
     | 
| 
      
 91 
     | 
    
         
            +
                  // get a range for the current metamorph object including
         
     | 
| 
      
 92 
     | 
    
         
            +
                  // the starting and ending placeholders.
         
     | 
| 
      
 93 
     | 
    
         
            +
                  var range = rangeFor(this, true);
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
                  // delete the entire range.
         
     | 
| 
      
 96 
     | 
    
         
            +
                  range.deleteContents();
         
     | 
| 
      
 97 
     | 
    
         
            +
                };
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                appendToFunc = function(node) {
         
     | 
| 
      
 100 
     | 
    
         
            +
                  var range = document.createRange();
         
     | 
| 
      
 101 
     | 
    
         
            +
                  range.setStart(node);
         
     | 
| 
      
 102 
     | 
    
         
            +
                  range.collapse(false);
         
     | 
| 
      
 103 
     | 
    
         
            +
                  var frag = range.createContextualFragment(this.outerHTML());
         
     | 
| 
      
 104 
     | 
    
         
            +
                  node.appendChild(frag);
         
     | 
| 
      
 105 
     | 
    
         
            +
                };
         
     | 
| 
      
 106 
     | 
    
         
            +
              } else {
         
     | 
| 
      
 107 
     | 
    
         
            +
                /**
         
     | 
| 
      
 108 
     | 
    
         
            +
                 * This code is mostly taken from jQuery, with one exception. In jQuery's case, we
         
     | 
| 
      
 109 
     | 
    
         
            +
                 * have some HTML and we need to figure out how to convert it into some nodes.
         
     | 
| 
      
 110 
     | 
    
         
            +
                 *
         
     | 
| 
      
 111 
     | 
    
         
            +
                 * In this case, jQuery needs to scan the HTML looking for an opening tag and use
         
     | 
| 
      
 112 
     | 
    
         
            +
                 * that as the key for the wrap map. In our case, we know the parent node, and
         
     | 
| 
      
 113 
     | 
    
         
            +
                 * can use its type as the key for the wrap map.
         
     | 
| 
      
 114 
     | 
    
         
            +
                 **/
         
     | 
| 
      
 115 
     | 
    
         
            +
                var wrapMap = {
         
     | 
| 
      
 116 
     | 
    
         
            +
                  select: [ 1, "<select multiple='multiple'>", "</select>" ],
         
     | 
| 
      
 117 
     | 
    
         
            +
                  fieldset: [ 1, "<fieldset>", "</fieldset>" ],
         
     | 
| 
      
 118 
     | 
    
         
            +
                  table: [ 1, "<table>", "</table>" ],
         
     | 
| 
      
 119 
     | 
    
         
            +
                  tbody: [ 2, "<table><tbody>", "</tbody></table>" ],
         
     | 
| 
      
 120 
     | 
    
         
            +
                  tr: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
         
     | 
| 
      
 121 
     | 
    
         
            +
                  colgroup: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
         
     | 
| 
      
 122 
     | 
    
         
            +
                  map: [ 1, "<map>", "</map>" ],
         
     | 
| 
      
 123 
     | 
    
         
            +
                  _default: [ 0, "", "" ]
         
     | 
| 
      
 124 
     | 
    
         
            +
                };
         
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
      
 126 
     | 
    
         
            +
                /**
         
     | 
| 
      
 127 
     | 
    
         
            +
                 * Given a parent node and some HTML, generate a set of nodes. Return the first
         
     | 
| 
      
 128 
     | 
    
         
            +
                 * node, which will allow us to traverse the rest using nextSibling.
         
     | 
| 
      
 129 
     | 
    
         
            +
                 *
         
     | 
| 
      
 130 
     | 
    
         
            +
                 * We need to do this because innerHTML in IE does not really parse the nodes.
         
     | 
| 
      
 131 
     | 
    
         
            +
                 **/
         
     | 
| 
      
 132 
     | 
    
         
            +
                function firstNodeFor(parentNode, html) {
         
     | 
| 
      
 133 
     | 
    
         
            +
                  var arr = wrapMap[parentNode.tagName.toLowerCase()] || wrapMap._default;
         
     | 
| 
      
 134 
     | 
    
         
            +
                  var depth = arr[0], start = arr[1], end = arr[2];
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
                  var element = document.createElement('div');
         
     | 
| 
      
 137 
     | 
    
         
            +
                  element.innerHTML = start + html + end;
         
     | 
| 
      
 138 
     | 
    
         
            +
             
     | 
| 
      
 139 
     | 
    
         
            +
                  for (var i=0; i<=depth; i++) {
         
     | 
| 
      
 140 
     | 
    
         
            +
                    element = element.firstChild;
         
     | 
| 
      
 141 
     | 
    
         
            +
                  }
         
     | 
| 
      
 142 
     | 
    
         
            +
             
     | 
| 
      
 143 
     | 
    
         
            +
                  return element;
         
     | 
| 
      
 144 
     | 
    
         
            +
                }
         
     | 
| 
      
 145 
     | 
    
         
            +
             
     | 
| 
      
 146 
     | 
    
         
            +
                /**
         
     | 
| 
      
 147 
     | 
    
         
            +
                 * Internet Explorer does not allow setting innerHTML if the first element
         
     | 
| 
      
 148 
     | 
    
         
            +
                 * is a "zero-scope" element. This problem can be worked around by making
         
     | 
| 
      
 149 
     | 
    
         
            +
                 * the first node an invisible text node. We, like Modernizr, use ­
         
     | 
| 
      
 150 
     | 
    
         
            +
                 **/
         
     | 
| 
      
 151 
     | 
    
         
            +
                var startTagFuncWithoutShy = startTagFunc;
         
     | 
| 
      
 152 
     | 
    
         
            +
             
     | 
| 
      
 153 
     | 
    
         
            +
                startTagFunc = function() {
         
     | 
| 
      
 154 
     | 
    
         
            +
                  return "­" + startTagFuncWithoutShy.call(this);
         
     | 
| 
      
 155 
     | 
    
         
            +
                };
         
     | 
| 
      
 156 
     | 
    
         
            +
             
     | 
| 
      
 157 
     | 
    
         
            +
                /**
         
     | 
| 
      
 158 
     | 
    
         
            +
                 * In some cases, Internet Explorer can create an anonymous node in
         
     | 
| 
      
 159 
     | 
    
         
            +
                 * the hierarchy with no tagName. You can create this scenario via:
         
     | 
| 
      
 160 
     | 
    
         
            +
                 *
         
     | 
| 
      
 161 
     | 
    
         
            +
                 *     div = document.createElement("div");
         
     | 
| 
      
 162 
     | 
    
         
            +
                 *     div.innerHTML = "<table>­<script></script><tr><td>hi</td></tr></table>";
         
     | 
| 
      
 163 
     | 
    
         
            +
                 *     div.firstChild.firstChild.tagName //=> ""
         
     | 
| 
      
 164 
     | 
    
         
            +
                 *
         
     | 
| 
      
 165 
     | 
    
         
            +
                 * If our script markers are inside such a node, we need to find that
         
     | 
| 
      
 166 
     | 
    
         
            +
                 * node and use *it* as the marker.
         
     | 
| 
      
 167 
     | 
    
         
            +
                 **/
         
     | 
| 
      
 168 
     | 
    
         
            +
                var realNode = function(start) {
         
     | 
| 
      
 169 
     | 
    
         
            +
                  while (start.parentNode.tagName == "") {
         
     | 
| 
      
 170 
     | 
    
         
            +
                    start = start.parentNode;
         
     | 
| 
      
 171 
     | 
    
         
            +
                  }
         
     | 
| 
      
 172 
     | 
    
         
            +
             
     | 
| 
      
 173 
     | 
    
         
            +
                  return start;
         
     | 
| 
      
 174 
     | 
    
         
            +
                };
         
     | 
| 
      
 175 
     | 
    
         
            +
             
     | 
| 
      
 176 
     | 
    
         
            +
                /**
         
     | 
| 
      
 177 
     | 
    
         
            +
                 * When automatically adding a tbody, Internet Explorer inserts the
         
     | 
| 
      
 178 
     | 
    
         
            +
                 * tbody immediately before the first <tr>. Other browsers create it
         
     | 
| 
      
 179 
     | 
    
         
            +
                 * before the first node, no matter what.
         
     | 
| 
      
 180 
     | 
    
         
            +
                 *
         
     | 
| 
      
 181 
     | 
    
         
            +
                 * This means the the following code:
         
     | 
| 
      
 182 
     | 
    
         
            +
                 *
         
     | 
| 
      
 183 
     | 
    
         
            +
                 *     div = document.createElement("div");
         
     | 
| 
      
 184 
     | 
    
         
            +
                 *     div.innerHTML = "<table><script id='first'></script><tr><td>hi</td></tr><script id='last'></script></table>
         
     | 
| 
      
 185 
     | 
    
         
            +
                 *
         
     | 
| 
      
 186 
     | 
    
         
            +
                 * Generates the following DOM in IE:
         
     | 
| 
      
 187 
     | 
    
         
            +
                 *
         
     | 
| 
      
 188 
     | 
    
         
            +
                 *     + div
         
     | 
| 
      
 189 
     | 
    
         
            +
                 *       + table
         
     | 
| 
      
 190 
     | 
    
         
            +
                 *         - script id='first'
         
     | 
| 
      
 191 
     | 
    
         
            +
                 *         + tbody
         
     | 
| 
      
 192 
     | 
    
         
            +
                 *           + tr
         
     | 
| 
      
 193 
     | 
    
         
            +
                 *             + td
         
     | 
| 
      
 194 
     | 
    
         
            +
                 *               - "hi"
         
     | 
| 
      
 195 
     | 
    
         
            +
                 *           - script id='last'
         
     | 
| 
      
 196 
     | 
    
         
            +
                 *
         
     | 
| 
      
 197 
     | 
    
         
            +
                 * Which means that the two script tags, even though they were
         
     | 
| 
      
 198 
     | 
    
         
            +
                 * inserted at the same point in the hierarchy in the original
         
     | 
| 
      
 199 
     | 
    
         
            +
                 * HTML, now have different parents.
         
     | 
| 
      
 200 
     | 
    
         
            +
                 *
         
     | 
| 
      
 201 
     | 
    
         
            +
                 * This code reparents the first script tag by making it the tbody's
         
     | 
| 
      
 202 
     | 
    
         
            +
                 * first child.
         
     | 
| 
      
 203 
     | 
    
         
            +
                 **/
         
     | 
| 
      
 204 
     | 
    
         
            +
                var fixParentage = function(start, end) {
         
     | 
| 
      
 205 
     | 
    
         
            +
                  if (start.parentNode !== end.parentNode) {
         
     | 
| 
      
 206 
     | 
    
         
            +
                    end.parentNode.insertBefore(start, end.parentNode.firstChild);
         
     | 
| 
      
 207 
     | 
    
         
            +
                  }
         
     | 
| 
      
 208 
     | 
    
         
            +
                };
         
     | 
| 
      
 209 
     | 
    
         
            +
             
     | 
| 
      
 210 
     | 
    
         
            +
                htmlFunc = function(html, outerToo) {
         
     | 
| 
      
 211 
     | 
    
         
            +
                  // get the real starting node. see realNode for details.
         
     | 
| 
      
 212 
     | 
    
         
            +
                  var start = realNode(document.getElementById(this.start));
         
     | 
| 
      
 213 
     | 
    
         
            +
                  var end = document.getElementById(this.end);
         
     | 
| 
      
 214 
     | 
    
         
            +
                  var parentNode = end.parentNode;
         
     | 
| 
      
 215 
     | 
    
         
            +
                  var nextSibling, last;
         
     | 
| 
      
 216 
     | 
    
         
            +
             
     | 
| 
      
 217 
     | 
    
         
            +
                  // make sure that the start and end nodes share the same
         
     | 
| 
      
 218 
     | 
    
         
            +
                  // parent. If not, fix it.
         
     | 
| 
      
 219 
     | 
    
         
            +
                  fixParentage(start, end);
         
     | 
| 
      
 220 
     | 
    
         
            +
             
     | 
| 
      
 221 
     | 
    
         
            +
                  var node = start;
         
     | 
| 
      
 222 
     | 
    
         
            +
                  if (!outerToo) { node = node.nextSibling; }
         
     | 
| 
      
 223 
     | 
    
         
            +
             
     | 
| 
      
 224 
     | 
    
         
            +
                  // remove all of the nodes after the starting placeholder and
         
     | 
| 
      
 225 
     | 
    
         
            +
                  // before the ending placeholder.
         
     | 
| 
      
 226 
     | 
    
         
            +
                  while (node) {
         
     | 
| 
      
 227 
     | 
    
         
            +
                    nextSibling = node.nextSibling;
         
     | 
| 
      
 228 
     | 
    
         
            +
                    last = node === end;
         
     | 
| 
      
 229 
     | 
    
         
            +
             
     | 
| 
      
 230 
     | 
    
         
            +
                    // if this is the last node, and we want to remove it as well,
         
     | 
| 
      
 231 
     | 
    
         
            +
                    // set the `end` node to the next sibling. This is because
         
     | 
| 
      
 232 
     | 
    
         
            +
                    // for the rest of the function, we insert the new nodes
         
     | 
| 
      
 233 
     | 
    
         
            +
                    // before the end (note that insertBefore(node, null) is
         
     | 
| 
      
 234 
     | 
    
         
            +
                    // the same as appendChild(node)).
         
     | 
| 
      
 235 
     | 
    
         
            +
                    //
         
     | 
| 
      
 236 
     | 
    
         
            +
                    // if we do not want to remove it, just break.
         
     | 
| 
      
 237 
     | 
    
         
            +
                    if (last) {
         
     | 
| 
      
 238 
     | 
    
         
            +
                      if (outerToo) { end = node.nextSibling; } else { break; }
         
     | 
| 
      
 239 
     | 
    
         
            +
                    }
         
     | 
| 
      
 240 
     | 
    
         
            +
             
     | 
| 
      
 241 
     | 
    
         
            +
                    node.parentNode.removeChild(node);
         
     | 
| 
      
 242 
     | 
    
         
            +
             
     | 
| 
      
 243 
     | 
    
         
            +
                    // if this is the last node and we didn't break before
         
     | 
| 
      
 244 
     | 
    
         
            +
                    // (because we wanted to remove the outer nodes), break
         
     | 
| 
      
 245 
     | 
    
         
            +
                    // now.
         
     | 
| 
      
 246 
     | 
    
         
            +
                    if (last) { break; }
         
     | 
| 
      
 247 
     | 
    
         
            +
             
     | 
| 
      
 248 
     | 
    
         
            +
                    node = nextSibling;
         
     | 
| 
      
 249 
     | 
    
         
            +
                  }
         
     | 
| 
      
 250 
     | 
    
         
            +
             
     | 
| 
      
 251 
     | 
    
         
            +
                  // get the first node for the HTML string, even in cases like
         
     | 
| 
      
 252 
     | 
    
         
            +
                  // tables and lists where a simple innerHTML on a div would
         
     | 
| 
      
 253 
     | 
    
         
            +
                  // swallow some of the content.
         
     | 
| 
      
 254 
     | 
    
         
            +
                  node = firstNodeFor(start.parentNode, html);
         
     | 
| 
      
 255 
     | 
    
         
            +
             
     | 
| 
      
 256 
     | 
    
         
            +
                  // copy the nodes for the HTML between the starting and ending
         
     | 
| 
      
 257 
     | 
    
         
            +
                  // placeholder.
         
     | 
| 
      
 258 
     | 
    
         
            +
                  while (node) {
         
     | 
| 
      
 259 
     | 
    
         
            +
                    nextSibling = node.nextSibling;
         
     | 
| 
      
 260 
     | 
    
         
            +
                    parentNode.insertBefore(node, end);
         
     | 
| 
      
 261 
     | 
    
         
            +
                    node = nextSibling;
         
     | 
| 
      
 262 
     | 
    
         
            +
                  }
         
     | 
| 
      
 263 
     | 
    
         
            +
                };
         
     | 
| 
      
 264 
     | 
    
         
            +
             
     | 
| 
      
 265 
     | 
    
         
            +
                // remove the nodes in the DOM representing this metamorph.
         
     | 
| 
      
 266 
     | 
    
         
            +
                //
         
     | 
| 
      
 267 
     | 
    
         
            +
                // this includes the starting and ending placeholders.
         
     | 
| 
      
 268 
     | 
    
         
            +
                removeFunc = function() {
         
     | 
| 
      
 269 
     | 
    
         
            +
                  var start = realNode(document.getElementById(this.start));
         
     | 
| 
      
 270 
     | 
    
         
            +
                  var end = document.getElementById(this.end);
         
     | 
| 
      
 271 
     | 
    
         
            +
             
     | 
| 
      
 272 
     | 
    
         
            +
                  this.html('');
         
     | 
| 
      
 273 
     | 
    
         
            +
                  start.parentNode.removeChild(start);
         
     | 
| 
      
 274 
     | 
    
         
            +
                  end.parentNode.removeChild(end);
         
     | 
| 
      
 275 
     | 
    
         
            +
                };
         
     | 
| 
      
 276 
     | 
    
         
            +
             
     | 
| 
      
 277 
     | 
    
         
            +
                appendToFunc = function(parentNode) {
         
     | 
| 
      
 278 
     | 
    
         
            +
                  var node = firstNodeFor(parentNode, this.outerHTML());
         
     | 
| 
      
 279 
     | 
    
         
            +
             
     | 
| 
      
 280 
     | 
    
         
            +
                  while (node) {
         
     | 
| 
      
 281 
     | 
    
         
            +
                    nextSibling = node.nextSibling;
         
     | 
| 
      
 282 
     | 
    
         
            +
                    parentNode.appendChild(node);
         
     | 
| 
      
 283 
     | 
    
         
            +
                    node = nextSibling;
         
     | 
| 
      
 284 
     | 
    
         
            +
                  }
         
     | 
| 
      
 285 
     | 
    
         
            +
                };
         
     | 
| 
      
 286 
     | 
    
         
            +
              }
         
     | 
| 
      
 287 
     | 
    
         
            +
             
     | 
| 
      
 288 
     | 
    
         
            +
              Metamorph.prototype.html = function(html) {
         
     | 
| 
      
 289 
     | 
    
         
            +
                this.checkRemoved();
         
     | 
| 
      
 290 
     | 
    
         
            +
                if (html === undefined) { return this.innerHTML; }
         
     | 
| 
      
 291 
     | 
    
         
            +
             
     | 
| 
      
 292 
     | 
    
         
            +
                htmlFunc.call(this, html);
         
     | 
| 
      
 293 
     | 
    
         
            +
             
     | 
| 
      
 294 
     | 
    
         
            +
                this.innerHTML = html;
         
     | 
| 
      
 295 
     | 
    
         
            +
              };
         
     | 
| 
      
 296 
     | 
    
         
            +
             
     | 
| 
      
 297 
     | 
    
         
            +
              Metamorph.prototype.replaceWith = function(html) {
         
     | 
| 
      
 298 
     | 
    
         
            +
                this.checkRemoved();
         
     | 
| 
      
 299 
     | 
    
         
            +
                htmlFunc.call(this, html, true);
         
     | 
| 
      
 300 
     | 
    
         
            +
              };
         
     | 
| 
      
 301 
     | 
    
         
            +
             
     | 
| 
      
 302 
     | 
    
         
            +
              Metamorph.prototype.remove = removeFunc;
         
     | 
| 
      
 303 
     | 
    
         
            +
              Metamorph.prototype.outerHTML = outerHTMLFunc;
         
     | 
| 
      
 304 
     | 
    
         
            +
              Metamorph.prototype.appendTo = appendToFunc;
         
     | 
| 
      
 305 
     | 
    
         
            +
              Metamorph.prototype.startTag = startTagFunc;
         
     | 
| 
      
 306 
     | 
    
         
            +
              Metamorph.prototype.endTag = endTagFunc;
         
     | 
| 
      
 307 
     | 
    
         
            +
             
     | 
| 
      
 308 
     | 
    
         
            +
              Metamorph.prototype.isRemoved = function() {
         
     | 
| 
      
 309 
     | 
    
         
            +
                var before = document.getElementById(this.start);
         
     | 
| 
      
 310 
     | 
    
         
            +
                var after = document.getElementById(this.end);
         
     | 
| 
      
 311 
     | 
    
         
            +
             
     | 
| 
      
 312 
     | 
    
         
            +
                return !before || !after;
         
     | 
| 
      
 313 
     | 
    
         
            +
              };
         
     | 
| 
      
 314 
     | 
    
         
            +
             
     | 
| 
      
 315 
     | 
    
         
            +
              Metamorph.prototype.checkRemoved = function() {
         
     | 
| 
      
 316 
     | 
    
         
            +
                if (this.isRemoved()) {
         
     | 
| 
      
 317 
     | 
    
         
            +
                  throw new Error("Cannot perform operations on a Metamorph that is not in the DOM.");
         
     | 
| 
      
 318 
     | 
    
         
            +
                }
         
     | 
| 
      
 319 
     | 
    
         
            +
              };
         
     | 
| 
      
 320 
     | 
    
         
            +
             
     | 
| 
      
 321 
     | 
    
         
            +
              window.Metamorph = Metamorph;
         
     | 
| 
      
 322 
     | 
    
         
            +
            })(this);
         
     | 
| 
      
 323 
     | 
    
         
            +
             
     | 
| 
      
 324 
     | 
    
         
            +
             
     |