Fix #11359: preserve contents for cloned scripts
[jquery.git] / src / support.js
blob291089e2c60335ce7f60664ff5cbdf96542e0052
1 (function( jQuery ) {
3 jQuery.support = (function() {
5         var support,
6                 all,
7                 a,
8                 select,
9                 opt,
10                 input,
11                 marginDiv,
12                 fragment,
13                 tds,
14                 events,
15                 eventName,
16                 i,
17                 isSupported,
18                 div = document.createElement( "div" ),
19                 documentElement = document.documentElement;
21         // Preliminary tests
22         div.setAttribute("className", "t");
23         div.innerHTML = "   <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
25         all = div.getElementsByTagName( "*" );
26         a = div.getElementsByTagName( "a" )[ 0 ];
28         // Can't get basic test support
29         if ( !all || !all.length || !a ) {
30                 return {};
31         }
33         // First batch of supports tests
34         select = document.createElement( "select" );
35         opt = select.appendChild( document.createElement("option") );
36         input = div.getElementsByTagName( "input" )[ 0 ];
38         support = {
39                 // IE strips leading whitespace when .innerHTML is used
40                 leadingWhitespace: ( div.firstChild.nodeType === 3 ),
42                 // Make sure that tbody elements aren't automatically inserted
43                 // IE will insert them into empty tables
44                 tbody: !div.getElementsByTagName("tbody").length,
46                 // Make sure that link elements get serialized correctly by innerHTML
47                 // This requires a wrapper element in IE
48                 htmlSerialize: !!div.getElementsByTagName("link").length,
50                 // Get the style information from getAttribute
51                 // (IE uses .cssText instead)
52                 style: /top/.test( a.getAttribute("style") ),
54                 // Make sure that URLs aren't manipulated
55                 // (IE normalizes it by default)
56                 hrefNormalized: ( a.getAttribute("href") === "/a" ),
58                 // Make sure that element opacity exists
59                 // (IE uses filter instead)
60                 // Use a regex to work around a WebKit issue. See #5145
61                 opacity: /^0.55/.test( a.style.opacity ),
63                 // Verify style float existence
64                 // (IE uses styleFloat instead of cssFloat)
65                 cssFloat: !!a.style.cssFloat,
67                 // Make sure that if no value is specified for a checkbox
68                 // that it defaults to "on".
69                 // (WebKit defaults to "" instead)
70                 checkOn: ( input.value === "on" ),
72                 // Make sure that a selected-by-default option has a working selected property.
73                 // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
74                 optSelected: opt.selected,
76                 // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
77                 getSetAttribute: div.className !== "t",
79                 // Tests for enctype support on a form(#6743)
80                 enctype: !!document.createElement("form").enctype,
82                 // Makes sure cloning an html5 element does not cause problems
83                 // Where outerHTML is undefined, this still works
84                 html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav></:nav>",
86                 // Will be defined later
87                 submitBubbles: true,
88                 changeBubbles: true,
89                 focusinBubbles: false,
90                 deleteExpando: true,
91                 noCloneEvent: true,
92                 inlineBlockNeedsLayout: false,
93                 shrinkWrapBlocks: false,
94                 reliableMarginRight: true,
95                 pixelMargin: true
96         };
98         // Make sure checked status is properly cloned
99         input.checked = true;
100         support.noCloneChecked = input.cloneNode( true ).checked;
102         // Make sure that the options inside disabled selects aren't marked as disabled
103         // (WebKit marks them as disabled)
104         select.disabled = true;
105         support.optDisabled = !opt.disabled;
107         // Test to see if it's possible to delete an expando from an element
108         // Fails in Internet Explorer
109         try {
110                 delete div.test;
111         } catch( e ) {
112                 support.deleteExpando = false;
113         }
115         if ( !div.addEventListener && div.attachEvent && div.fireEvent ) {
116                 div.attachEvent( "onclick", function() {
117                         // Cloning a node shouldn't copy over any
118                         // bound event handlers (IE does this)
119                         support.noCloneEvent = false;
120                 });
121                 div.cloneNode( true ).fireEvent( "onclick" );
122         }
124         // Check if a radio maintains its value
125         // after being appended to the DOM
126         input = document.createElement("input");
127         input.value = "t";
128         input.setAttribute("type", "radio");
129         support.radioValue = input.value === "t";
131         input.setAttribute("checked", "checked");
132         div.appendChild( input );
133         fragment = document.createDocumentFragment();
134         fragment.appendChild( div.lastChild );
136         // WebKit doesn't clone checked state correctly in fragments
137         support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
139         // Check if a disconnected checkbox will retain its checked
140         // value of true after appended to the DOM (IE6/7)
141         support.appendChecked = input.checked;
143         fragment.removeChild( input );
144         fragment.appendChild( div );
146         div.innerHTML = "";
148         // Check if div with explicit width and no margin-right incorrectly
149         // gets computed margin-right based on width of container. For more
150         // info see bug #3333
151         // Fails in WebKit before Feb 2011 nightlies
152         // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
153         if ( window.getComputedStyle ) {
154                 marginDiv = document.createElement( "div" );
155                 marginDiv.style.width = "0";
156                 marginDiv.style.marginRight = "0";
157                 div.style.width = "2px";
158                 div.appendChild( marginDiv );
159                 support.reliableMarginRight =
160                         ( parseInt( ( window.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0;
161         }
163         // Technique from Juriy Zaytsev
164         // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/
165         // We only care about the case where non-standard event systems
166         // are used, namely in IE. Short-circuiting here helps us to
167         // avoid an eval call (in setAttribute) which can cause CSP
168         // to go haywire. See: https://developer.mozilla.org/en/Security/CSP
169         if ( div.attachEvent ) {
170                 for ( i in {
171                         submit: 1,
172                         change: 1,
173                         focusin: 1
174                 }) {
175                         eventName = "on" + i;
176                         isSupported = ( eventName in div );
177                         if ( !isSupported ) {
178                                 div.setAttribute( eventName, "return;" );
179                                 isSupported = ( typeof div[ eventName ] === "function" );
180                         }
181                         support[ i + "Bubbles" ] = isSupported;
182                 }
183         }
185         fragment.removeChild( div );
187         // Null elements to avoid leaks in IE
188         fragment = select = opt = marginDiv = div = input = null;
190         // Run tests that need a body at doc ready
191         jQuery(function() {
192                 var container, outer, inner, table, td, offsetSupport,
193                         conMarginTop, ptlm, vb, style, html,
194                         body = document.getElementsByTagName("body")[0];
196                 if ( !body ) {
197                         // Return for frameset docs that don't have a body
198                         return;
199                 }
201                 conMarginTop = 1;
202                 ptlm = "position:absolute;top:0;left:0;width:1px;height:1px;margin:0;";
203                 vb = "visibility:hidden;border:0;";
204                 style = "style='" + ptlm + "border:5px solid #000;padding:0;'";
205                 html = "<div " + style + "><div></div></div>" +
206                         "<table " + style + " cellpadding='0' cellspacing='0'>" +
207                         "<tr><td></td></tr></table>";
209                 container = document.createElement("div");
210                 container.style.cssText = vb + "width:0;height:0;position:static;top:0;margin-top:" + conMarginTop + "px";
211                 body.insertBefore( container, body.firstChild );
213                 // Construct the test element
214                 div = document.createElement("div");
215                 container.appendChild( div );
217                 // Check if table cells still have offsetWidth/Height when they are set
218                 // to display:none and there are still other visible table cells in a
219                 // table row; if so, offsetWidth/Height are not reliable for use when
220                 // determining if an element has been hidden directly using
221                 // display:none (it is still safe to use offsets if a parent element is
222                 // hidden; don safety goggles and see bug #4512 for more information).
223                 // (only IE 8 fails this test)
224                 div.innerHTML = "<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>";
226                 tds = div.getElementsByTagName( "td" );
227                 isSupported = ( tds[ 0 ].offsetHeight === 0 );
229                 tds[ 0 ].style.display = "";
230                 tds[ 1 ].style.display = "none";
232                 // Check if empty table cells still have offsetWidth/Height
233                 // (IE <= 8 fail this test)
234                 support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
236                 // Figure out if the W3C box model works as expected
237                 div.innerHTML = "";
238                 div.style.width = div.style.paddingLeft = "1px";
239                 jQuery.boxModel = support.boxModel = div.offsetWidth === 2;
241                 if ( typeof div.style.zoom !== "undefined" ) {
242                         // Check if natively block-level elements act like inline-block
243                         // elements when setting their display to 'inline' and giving
244                         // them layout
245                         // (IE < 8 does this)
246                         div.style.display = "inline";
247                         div.style.zoom = 1;
248                         support.inlineBlockNeedsLayout = ( div.offsetWidth === 2 );
250                         // Check if elements with layout shrink-wrap their children
251                         // (IE 6 does this)
252                         div.style.display = "";
253                         div.innerHTML = "<div style='width:4px;'></div>";
254                         support.shrinkWrapBlocks = ( div.offsetWidth !== 2 );
255                 }
257                 div.style.cssText = ptlm + vb;
258                 div.innerHTML = html;
260                 outer = div.firstChild;
261                 inner = outer.firstChild;
262                 td = outer.nextSibling.firstChild.firstChild;
264                 offsetSupport = {
265                         doesNotAddBorder: ( inner.offsetTop !== 5 ),
266                         doesAddBorderForTableAndCells: ( td.offsetTop === 5 )
267                 };
269                 inner.style.position = "fixed";
270                 inner.style.top = "20px";
272                 // safari subtracts parent border width here which is 5px
273                 offsetSupport.fixedPosition = ( inner.offsetTop === 20 || inner.offsetTop === 15 );
274                 inner.style.position = inner.style.top = "";
276                 outer.style.overflow = "hidden";
277                 outer.style.position = "relative";
279                 offsetSupport.subtractsBorderForOverflowNotVisible = ( inner.offsetTop === -5 );
280                 offsetSupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== conMarginTop );
282                 if ( window.getComputedStyle ) {
283                         div.style.marginTop = "1%";
284                         support.pixelMargin = ( window.getComputedStyle( div, null ) || { marginTop: 0 } ).marginTop !== "1%";
285                 }
287                 if ( typeof container.style.zoom !== "undefined" ) {
288                         container.style.zoom = 1;
289                 }
291                 body.removeChild( container );
292                 div = container = null;
294                 jQuery.extend( support, offsetSupport );
295         });
297         return support;
298 })();
300 })( jQuery );