[8384] | 1 | /*! |
---|
[9582] | 2 | * Modernizr v1.7 |
---|
| 3 | * http://www.modernizr.com |
---|
| 4 | * |
---|
| 5 | * Developed by: |
---|
| 6 | * - Faruk Ates http://farukat.es/ |
---|
| 7 | * - Paul Irish http://paulirish.com/ |
---|
| 8 | * |
---|
| 9 | * Copyright (c) 2009-2011 |
---|
| 10 | * Dual-licensed under the BSD or MIT licenses. |
---|
| 11 | * http://www.modernizr.com/license/ |
---|
| 12 | */ |
---|
[8384] | 13 | |
---|
| 14 | |
---|
| 15 | /* |
---|
| 16 | * Modernizr is a script that detects native CSS3 and HTML5 features |
---|
| 17 | * available in the current UA and provides an object containing all |
---|
| 18 | * features with a true/false value, depending on whether the UA has |
---|
| 19 | * native support for it or not. |
---|
| 20 | * |
---|
| 21 | * Modernizr will also add classes to the <html> element of the page, |
---|
| 22 | * one for each feature it detects. If the UA supports it, a class |
---|
| 23 | * like "cssgradients" will be added. If not, the class name will be |
---|
| 24 | * "no-cssgradients". This allows for simple if-conditionals in your |
---|
| 25 | * CSS, giving you fine control over the look & feel of your website. |
---|
| 26 | * |
---|
| 27 | * @author Faruk Ates |
---|
| 28 | * @author Paul Irish |
---|
| 29 | * @copyright (c) 2009-2011 Faruk Ates. |
---|
| 30 | * @contributor Ben Alman |
---|
| 31 | */ |
---|
| 32 | |
---|
| 33 | window.Modernizr = (function(window,document,undefined){ |
---|
| 34 | |
---|
| 35 | var version = '1.7', |
---|
| 36 | |
---|
| 37 | ret = {}, |
---|
| 38 | |
---|
| 39 | /** |
---|
| 40 | * !! DEPRECATED !! |
---|
| 41 | * |
---|
| 42 | * enableHTML5 is a private property for advanced use only. If enabled, |
---|
| 43 | * it will make Modernizr.init() run through a brief while() loop in |
---|
| 44 | * which it will create all HTML5 elements in the DOM to allow for |
---|
| 45 | * styling them in Internet Explorer, which does not recognize any |
---|
| 46 | * non-HTML4 elements unless created in the DOM this way. |
---|
| 47 | * |
---|
| 48 | * enableHTML5 is ON by default. |
---|
| 49 | * |
---|
| 50 | * The enableHTML5 toggle option is DEPRECATED as per 1.6, and will be |
---|
| 51 | * replaced in 2.0 in lieu of the modular, configurable nature of 2.0. |
---|
| 52 | */ |
---|
| 53 | enableHTML5 = true, |
---|
| 54 | |
---|
| 55 | |
---|
| 56 | docElement = document.documentElement, |
---|
| 57 | docHead = document.head || document.getElementsByTagName('head')[0], |
---|
| 58 | |
---|
| 59 | /** |
---|
| 60 | * Create our "modernizr" element that we do most feature tests on. |
---|
| 61 | */ |
---|
| 62 | mod = 'modernizr', |
---|
| 63 | modElem = document.createElement( mod ), |
---|
| 64 | m_style = modElem.style, |
---|
| 65 | |
---|
| 66 | /** |
---|
| 67 | * Create the input element for various Web Forms feature tests. |
---|
| 68 | */ |
---|
| 69 | inputElem = document.createElement( 'input' ), |
---|
| 70 | |
---|
| 71 | smile = ':)', |
---|
| 72 | |
---|
| 73 | tostring = Object.prototype.toString, |
---|
| 74 | |
---|
| 75 | // List of property values to set for css tests. See ticket #21 |
---|
| 76 | prefixes = ' -webkit- -moz- -o- -ms- -khtml- '.split(' '), |
---|
| 77 | |
---|
| 78 | // Following spec is to expose vendor-specific style properties as: |
---|
| 79 | // elem.style.WebkitBorderRadius |
---|
| 80 | // and the following would be incorrect: |
---|
| 81 | // elem.style.webkitBorderRadius |
---|
| 82 | |
---|
| 83 | // Webkit ghosts their properties in lowercase but Opera & Moz do not. |
---|
| 84 | // Microsoft foregoes prefixes entirely <= IE8, but appears to |
---|
| 85 | // use a lowercase `ms` instead of the correct `Ms` in IE9 |
---|
| 86 | |
---|
| 87 | // More here: http://github.com/Modernizr/Modernizr/issues/issue/21 |
---|
| 88 | domPrefixes = 'Webkit Moz O ms Khtml'.split(' '), |
---|
| 89 | |
---|
| 90 | ns = {'svg': 'http://www.w3.org/2000/svg'}, |
---|
| 91 | |
---|
| 92 | tests = {}, |
---|
| 93 | inputs = {}, |
---|
| 94 | attrs = {}, |
---|
| 95 | |
---|
| 96 | classes = [], |
---|
| 97 | |
---|
| 98 | featurename, // used in testing loop |
---|
| 99 | |
---|
| 100 | |
---|
| 101 | |
---|
| 102 | // todo: consider using http://javascript.nwbox.com/CSSSupport/css-support.js instead |
---|
| 103 | testMediaQuery = function(mq){ |
---|
| 104 | |
---|
| 105 | var st = document.createElement('style'), |
---|
| 106 | div = document.createElement('div'), |
---|
| 107 | ret; |
---|
| 108 | |
---|
| 109 | st.textContent = mq + '{#modernizr{height:3px}}'; |
---|
| 110 | docHead.appendChild(st); |
---|
| 111 | div.id = 'modernizr'; |
---|
| 112 | docElement.appendChild(div); |
---|
| 113 | |
---|
| 114 | ret = div.offsetHeight === 3; |
---|
| 115 | |
---|
| 116 | st.parentNode.removeChild(st); |
---|
| 117 | div.parentNode.removeChild(div); |
---|
| 118 | |
---|
| 119 | return !!ret; |
---|
| 120 | |
---|
| 121 | }, |
---|
| 122 | |
---|
| 123 | |
---|
| 124 | /** |
---|
| 125 | * isEventSupported determines if a given element supports the given event |
---|
| 126 | * function from http://yura.thinkweb2.com/isEventSupported/ |
---|
| 127 | */ |
---|
| 128 | isEventSupported = (function(){ |
---|
| 129 | |
---|
| 130 | var TAGNAMES = { |
---|
| 131 | 'select':'input','change':'input', |
---|
| 132 | 'submit':'form','reset':'form', |
---|
| 133 | 'error':'img','load':'img','abort':'img' |
---|
| 134 | }; |
---|
| 135 | |
---|
| 136 | function isEventSupported(eventName, element) { |
---|
| 137 | |
---|
| 138 | element = element || document.createElement(TAGNAMES[eventName] || 'div'); |
---|
| 139 | eventName = 'on' + eventName; |
---|
| 140 | |
---|
| 141 | // When using `setAttribute`, IE skips "unload", WebKit skips "unload" and "resize", whereas `in` "catches" those |
---|
| 142 | var isSupported = (eventName in element); |
---|
| 143 | |
---|
| 144 | if (!isSupported) { |
---|
| 145 | // If it has no `setAttribute` (i.e. doesn't implement Node interface), try generic element |
---|
| 146 | if (!element.setAttribute) { |
---|
| 147 | element = document.createElement('div'); |
---|
| 148 | } |
---|
| 149 | if (element.setAttribute && element.removeAttribute) { |
---|
| 150 | element.setAttribute(eventName, ''); |
---|
| 151 | isSupported = is(element[eventName], 'function'); |
---|
| 152 | |
---|
| 153 | // If property was created, "remove it" (by setting value to `undefined`) |
---|
| 154 | if (!is(element[eventName], undefined)) { |
---|
| 155 | element[eventName] = undefined; |
---|
| 156 | } |
---|
| 157 | element.removeAttribute(eventName); |
---|
| 158 | } |
---|
| 159 | } |
---|
| 160 | |
---|
| 161 | element = null; |
---|
| 162 | return isSupported; |
---|
| 163 | } |
---|
| 164 | return isEventSupported; |
---|
| 165 | })(); |
---|
| 166 | |
---|
| 167 | |
---|
| 168 | // hasOwnProperty shim by kangax needed for Safari 2.0 support |
---|
| 169 | var _hasOwnProperty = ({}).hasOwnProperty, hasOwnProperty; |
---|
| 170 | if (!is(_hasOwnProperty, undefined) && !is(_hasOwnProperty.call, undefined)) { |
---|
| 171 | hasOwnProperty = function (object, property) { |
---|
| 172 | return _hasOwnProperty.call(object, property); |
---|
| 173 | }; |
---|
| 174 | } |
---|
| 175 | else { |
---|
| 176 | hasOwnProperty = function (object, property) { /* yes, this can give false positives/negatives, but most of the time we don't care about those */ |
---|
| 177 | return ((property in object) && is(object.constructor.prototype[property], undefined)); |
---|
| 178 | }; |
---|
| 179 | } |
---|
| 180 | |
---|
| 181 | /** |
---|
| 182 | * set_css applies given styles to the Modernizr DOM node. |
---|
| 183 | */ |
---|
| 184 | function set_css( str ) { |
---|
| 185 | m_style.cssText = str; |
---|
| 186 | } |
---|
| 187 | |
---|
| 188 | /** |
---|
| 189 | * set_css_all extrapolates all vendor-specific css strings. |
---|
| 190 | */ |
---|
| 191 | function set_css_all( str1, str2 ) { |
---|
| 192 | return set_css(prefixes.join(str1 + ';') + ( str2 || '' )); |
---|
| 193 | } |
---|
| 194 | |
---|
| 195 | /** |
---|
| 196 | * is returns a boolean for if typeof obj is exactly type. |
---|
| 197 | */ |
---|
| 198 | function is( obj, type ) { |
---|
| 199 | return typeof obj === type; |
---|
| 200 | } |
---|
| 201 | |
---|
| 202 | /** |
---|
| 203 | * contains returns a boolean for if substr is found within str. |
---|
| 204 | */ |
---|
| 205 | function contains( str, substr ) { |
---|
| 206 | return (''+str).indexOf( substr ) !== -1; |
---|
| 207 | } |
---|
| 208 | |
---|
| 209 | /** |
---|
| 210 | * test_props is a generic CSS / DOM property test; if a browser supports |
---|
| 211 | * a certain property, it won't return undefined for it. |
---|
| 212 | * A supported CSS property returns empty string when its not yet set. |
---|
| 213 | */ |
---|
| 214 | function test_props( props, callback ) { |
---|
| 215 | for ( var i in props ) { |
---|
| 216 | if ( m_style[ props[i] ] !== undefined && ( !callback || callback( props[i], modElem ) ) ) { |
---|
| 217 | return true; |
---|
| 218 | } |
---|
| 219 | } |
---|
| 220 | } |
---|
| 221 | |
---|
| 222 | /** |
---|
| 223 | * test_props_all tests a list of DOM properties we want to check against. |
---|
| 224 | * We specify literally ALL possible (known and/or likely) properties on |
---|
| 225 | * the element including the non-vendor prefixed one, for forward- |
---|
| 226 | * compatibility. |
---|
| 227 | */ |
---|
| 228 | function test_props_all( prop, callback ) { |
---|
| 229 | |
---|
| 230 | var uc_prop = prop.charAt(0).toUpperCase() + prop.substr(1), |
---|
| 231 | props = (prop + ' ' + domPrefixes.join(uc_prop + ' ') + uc_prop).split(' '); |
---|
| 232 | |
---|
| 233 | return !!test_props( props, callback ); |
---|
| 234 | } |
---|
| 235 | |
---|
| 236 | |
---|
| 237 | /** |
---|
| 238 | * Tests |
---|
| 239 | * ----- |
---|
| 240 | */ |
---|
| 241 | |
---|
| 242 | tests['flexbox'] = function() { |
---|
| 243 | /** |
---|
| 244 | * set_prefixed_value_css sets the property of a specified element |
---|
| 245 | * adding vendor prefixes to the VALUE of the property. |
---|
| 246 | * @param {Element} element |
---|
| 247 | * @param {string} property The property name. This will not be prefixed. |
---|
| 248 | * @param {string} value The value of the property. This WILL be prefixed. |
---|
| 249 | * @param {string=} extra Additional CSS to append unmodified to the end of |
---|
| 250 | * the CSS string. |
---|
| 251 | */ |
---|
| 252 | function set_prefixed_value_css(element, property, value, extra) { |
---|
| 253 | property += ':'; |
---|
| 254 | element.style.cssText = (property + prefixes.join(value + ';' + property)).slice(0, -property.length) + (extra || ''); |
---|
| 255 | } |
---|
| 256 | |
---|
| 257 | /** |
---|
| 258 | * set_prefixed_property_css sets the property of a specified element |
---|
| 259 | * adding vendor prefixes to the NAME of the property. |
---|
| 260 | * @param {Element} element |
---|
| 261 | * @param {string} property The property name. This WILL be prefixed. |
---|
| 262 | * @param {string} value The value of the property. This will not be prefixed. |
---|
| 263 | * @param {string=} extra Additional CSS to append unmodified to the end of |
---|
| 264 | * the CSS string. |
---|
| 265 | */ |
---|
| 266 | function set_prefixed_property_css(element, property, value, extra) { |
---|
| 267 | element.style.cssText = prefixes.join(property + ':' + value + ';') + (extra || ''); |
---|
| 268 | } |
---|
| 269 | |
---|
| 270 | var c = document.createElement('div'), |
---|
| 271 | elem = document.createElement('div'); |
---|
| 272 | |
---|
| 273 | set_prefixed_value_css(c, 'display', 'box', 'width:42px;padding:0;'); |
---|
| 274 | set_prefixed_property_css(elem, 'box-flex', '1', 'width:10px;'); |
---|
| 275 | |
---|
| 276 | c.appendChild(elem); |
---|
| 277 | docElement.appendChild(c); |
---|
| 278 | |
---|
| 279 | var ret = elem.offsetWidth === 42; |
---|
| 280 | |
---|
| 281 | c.removeChild(elem); |
---|
| 282 | docElement.removeChild(c); |
---|
| 283 | |
---|
| 284 | return ret; |
---|
| 285 | }; |
---|
| 286 | |
---|
| 287 | // On the S60 and BB Storm, getContext exists, but always returns undefined |
---|
| 288 | // http://github.com/Modernizr/Modernizr/issues/issue/97/ |
---|
| 289 | |
---|
| 290 | tests['canvas'] = function() { |
---|
| 291 | var elem = document.createElement( 'canvas' ); |
---|
| 292 | return !!(elem.getContext && elem.getContext('2d')); |
---|
| 293 | }; |
---|
| 294 | |
---|
| 295 | tests['canvastext'] = function() { |
---|
| 296 | return !!(ret['canvas'] && is(document.createElement( 'canvas' ).getContext('2d').fillText, 'function')); |
---|
| 297 | }; |
---|
| 298 | |
---|
| 299 | // This WebGL test false positives in FF depending on graphics hardware. But really it's quite impossible to know |
---|
| 300 | // wether webgl will succeed until after you create the context. You might have hardware that can support |
---|
| 301 | // a 100x100 webgl canvas, but will not support a 1000x1000 webgl canvas. So this feature inference is weak, |
---|
| 302 | // but intentionally so. |
---|
| 303 | tests['webgl'] = function(){ |
---|
| 304 | return !!window.WebGLRenderingContext; |
---|
| 305 | }; |
---|
| 306 | |
---|
| 307 | /* |
---|
| 308 | * The Modernizr.touch test only indicates if the browser supports |
---|
| 309 | * touch events, which does not necessarily reflect a touchscreen |
---|
| 310 | * device, as evidenced by tablets running Windows 7 or, alas, |
---|
| 311 | * the Palm Pre / WebOS (touch) phones. |
---|
| 312 | * |
---|
| 313 | * Additionally, Chrome (desktop) used to lie about its support on this, |
---|
| 314 | * but that has since been rectified: http://crbug.com/36415 |
---|
| 315 | * |
---|
| 316 | * We also test for Firefox 4 Multitouch Support. |
---|
| 317 | * |
---|
| 318 | * For more info, see: http://modernizr.github.com/Modernizr/touch.html |
---|
| 319 | */ |
---|
| 320 | |
---|
| 321 | tests['touch'] = function() { |
---|
| 322 | |
---|
| 323 | return ('ontouchstart' in window) || testMediaQuery('@media ('+prefixes.join('touch-enabled),(')+'modernizr)'); |
---|
| 324 | |
---|
| 325 | }; |
---|
| 326 | |
---|
| 327 | |
---|
| 328 | /** |
---|
| 329 | * geolocation tests for the new Geolocation API specification. |
---|
| 330 | * This test is a standards compliant-only test; for more complete |
---|
| 331 | * testing, including a Google Gears fallback, please see: |
---|
| 332 | * http://code.google.com/p/geo-location-javascript/ |
---|
| 333 | * or view a fallback solution using google's geo API: |
---|
| 334 | * http://gist.github.com/366184 |
---|
| 335 | */ |
---|
| 336 | tests['geolocation'] = function() { |
---|
| 337 | return !!navigator.geolocation; |
---|
| 338 | }; |
---|
| 339 | |
---|
| 340 | // Per 1.6: |
---|
| 341 | // This used to be Modernizr.crosswindowmessaging but the longer |
---|
| 342 | // name has been deprecated in favor of a shorter and property-matching one. |
---|
| 343 | // The old API is still available in 1.6, but as of 2.0 will throw a warning, |
---|
| 344 | // and in the first release thereafter disappear entirely. |
---|
| 345 | tests['postmessage'] = function() { |
---|
| 346 | return !!window.postMessage; |
---|
| 347 | }; |
---|
| 348 | |
---|
| 349 | // Web SQL database detection is tricky: |
---|
| 350 | |
---|
| 351 | // In chrome incognito mode, openDatabase is truthy, but using it will |
---|
| 352 | // throw an exception: http://crbug.com/42380 |
---|
| 353 | // We can create a dummy database, but there is no way to delete it afterwards. |
---|
| 354 | |
---|
| 355 | // Meanwhile, Safari users can get prompted on any database creation. |
---|
| 356 | // If they do, any page with Modernizr will give them a prompt: |
---|
| 357 | // http://github.com/Modernizr/Modernizr/issues/closed#issue/113 |
---|
| 358 | |
---|
| 359 | // We have chosen to allow the Chrome incognito false positive, so that Modernizr |
---|
| 360 | // doesn't litter the web with these test databases. As a developer, you'll have |
---|
| 361 | // to account for this gotcha yourself. |
---|
| 362 | tests['websqldatabase'] = function() { |
---|
| 363 | var result = !!window.openDatabase; |
---|
| 364 | /* if (result){ |
---|
| 365 | try { |
---|
| 366 | result = !!openDatabase( mod + "testdb", "1.0", mod + "testdb", 2e4); |
---|
| 367 | } catch(e) { |
---|
| 368 | } |
---|
| 369 | } */ |
---|
| 370 | return result; |
---|
| 371 | }; |
---|
| 372 | |
---|
| 373 | // Vendors have inconsistent prefixing with the experimental Indexed DB: |
---|
| 374 | // - Firefox is shipping indexedDB in FF4 as moz_indexedDB |
---|
| 375 | // - Webkit's implementation is accessible through webkitIndexedDB |
---|
| 376 | // We test both styles. |
---|
| 377 | tests['indexedDB'] = function(){ |
---|
| 378 | for (var i = -1, len = domPrefixes.length; ++i < len; ){ |
---|
| 379 | var prefix = domPrefixes[i].toLowerCase(); |
---|
| 380 | if (window[prefix + '_indexedDB'] || window[prefix + 'IndexedDB']){ |
---|
| 381 | return true; |
---|
| 382 | } |
---|
| 383 | } |
---|
| 384 | return false; |
---|
| 385 | }; |
---|
| 386 | |
---|
| 387 | // documentMode logic from YUI to filter out IE8 Compat Mode |
---|
| 388 | // which false positives. |
---|
| 389 | tests['hashchange'] = function() { |
---|
| 390 | return isEventSupported('hashchange', window) && ( document.documentMode === undefined || document.documentMode > 7 ); |
---|
| 391 | }; |
---|
| 392 | |
---|
| 393 | // Per 1.6: |
---|
| 394 | // This used to be Modernizr.historymanagement but the longer |
---|
| 395 | // name has been deprecated in favor of a shorter and property-matching one. |
---|
| 396 | // The old API is still available in 1.6, but as of 2.0 will throw a warning, |
---|
| 397 | // and in the first release thereafter disappear entirely. |
---|
| 398 | tests['history'] = function() { |
---|
| 399 | return !!(window.history && history.pushState); |
---|
| 400 | }; |
---|
| 401 | |
---|
| 402 | tests['draganddrop'] = function() { |
---|
| 403 | return isEventSupported('dragstart') && isEventSupported('drop'); |
---|
| 404 | }; |
---|
| 405 | |
---|
| 406 | tests['websockets'] = function(){ |
---|
| 407 | return ('WebSocket' in window); |
---|
| 408 | }; |
---|
| 409 | |
---|
| 410 | |
---|
| 411 | // http://css-tricks.com/rgba-browser-support/ |
---|
| 412 | tests['rgba'] = function() { |
---|
| 413 | // Set an rgba() color and check the returned value |
---|
| 414 | |
---|
| 415 | set_css( 'background-color:rgba(150,255,150,.5)' ); |
---|
| 416 | |
---|
| 417 | return contains( m_style.backgroundColor, 'rgba' ); |
---|
| 418 | }; |
---|
| 419 | |
---|
| 420 | tests['hsla'] = function() { |
---|
| 421 | // Same as rgba(), in fact, browsers re-map hsla() to rgba() internally, |
---|
| 422 | // except IE9 who retains it as hsla |
---|
| 423 | |
---|
| 424 | set_css('background-color:hsla(120,40%,100%,.5)' ); |
---|
| 425 | |
---|
| 426 | return contains( m_style.backgroundColor, 'rgba' ) || contains( m_style.backgroundColor, 'hsla' ); |
---|
| 427 | }; |
---|
| 428 | |
---|
| 429 | tests['multiplebgs'] = function() { |
---|
| 430 | // Setting multiple images AND a color on the background shorthand property |
---|
| 431 | // and then querying the style.background property value for the number of |
---|
| 432 | // occurrences of "url(" is a reliable method for detecting ACTUAL support for this! |
---|
| 433 | |
---|
| 434 | set_css( 'background:url(//:),url(//:),red url(//:)' ); |
---|
| 435 | |
---|
| 436 | // If the UA supports multiple backgrounds, there should be three occurrences |
---|
| 437 | // of the string "url(" in the return value for elem_style.background |
---|
| 438 | |
---|
| 439 | return new RegExp("(url\\s*\\(.*?){3}").test(m_style.background); |
---|
| 440 | }; |
---|
| 441 | |
---|
| 442 | |
---|
| 443 | // In testing support for a given CSS property, it's legit to test: |
---|
| 444 | // `elem.style[styleName] !== undefined` |
---|
| 445 | // If the property is supported it will return an empty string, |
---|
| 446 | // if unsupported it will return undefined. |
---|
| 447 | |
---|
| 448 | // We'll take advantage of this quick test and skip setting a style |
---|
| 449 | // on our modernizr element, but instead just testing undefined vs |
---|
| 450 | // empty string. |
---|
| 451 | |
---|
| 452 | |
---|
| 453 | tests['backgroundsize'] = function() { |
---|
| 454 | return test_props_all( 'backgroundSize' ); |
---|
| 455 | }; |
---|
| 456 | |
---|
| 457 | tests['borderimage'] = function() { |
---|
| 458 | return test_props_all( 'borderImage' ); |
---|
| 459 | }; |
---|
| 460 | |
---|
| 461 | |
---|
| 462 | // Super comprehensive table about all the unique implementations of |
---|
| 463 | // border-radius: http://muddledramblings.com/table-of-css3-border-radius-compliance |
---|
| 464 | |
---|
| 465 | tests['borderradius'] = function() { |
---|
| 466 | return test_props_all( 'borderRadius', '', function( prop ) { |
---|
| 467 | return contains( prop, 'orderRadius' ); |
---|
| 468 | }); |
---|
| 469 | }; |
---|
| 470 | |
---|
| 471 | // WebOS unfortunately false positives on this test. |
---|
| 472 | tests['boxshadow'] = function() { |
---|
| 473 | return test_props_all( 'boxShadow' ); |
---|
| 474 | }; |
---|
| 475 | |
---|
| 476 | // FF3.0 will false positive on this test |
---|
| 477 | tests['textshadow'] = function(){ |
---|
| 478 | return document.createElement('div').style.textShadow === ''; |
---|
| 479 | }; |
---|
| 480 | |
---|
| 481 | |
---|
| 482 | tests['opacity'] = function() { |
---|
| 483 | // Browsers that actually have CSS Opacity implemented have done so |
---|
| 484 | // according to spec, which means their return values are within the |
---|
| 485 | // range of [0.0,1.0] - including the leading zero. |
---|
| 486 | |
---|
| 487 | set_css_all( 'opacity:.55' ); |
---|
| 488 | |
---|
| 489 | // The non-literal . in this regex is intentional: |
---|
| 490 | // German Chrome returns this value as 0,55 |
---|
| 491 | // https://github.com/Modernizr/Modernizr/issues/#issue/59/comment/516632 |
---|
| 492 | return /^0.55$/.test(m_style.opacity); |
---|
| 493 | }; |
---|
| 494 | |
---|
| 495 | |
---|
| 496 | tests['cssanimations'] = function() { |
---|
| 497 | return test_props_all( 'animationName' ); |
---|
| 498 | }; |
---|
| 499 | |
---|
| 500 | |
---|
| 501 | tests['csscolumns'] = function() { |
---|
| 502 | return test_props_all( 'columnCount' ); |
---|
| 503 | }; |
---|
| 504 | |
---|
| 505 | |
---|
| 506 | tests['cssgradients'] = function() { |
---|
| 507 | /** |
---|
| 508 | * For CSS Gradients syntax, please see: |
---|
| 509 | * http://webkit.org/blog/175/introducing-css-gradients/ |
---|
| 510 | * https://developer.mozilla.org/en/CSS/-moz-linear-gradient |
---|
| 511 | * https://developer.mozilla.org/en/CSS/-moz-radial-gradient |
---|
| 512 | * http://dev.w3.org/csswg/css3-images/#gradients- |
---|
| 513 | */ |
---|
| 514 | |
---|
| 515 | var str1 = 'background-image:', |
---|
| 516 | str2 = 'gradient(linear,left top,right bottom,from(#9f9),to(white));', |
---|
| 517 | str3 = 'linear-gradient(left top,#9f9, white);'; |
---|
| 518 | |
---|
| 519 | set_css( |
---|
| 520 | (str1 + prefixes.join(str2 + str1) + prefixes.join(str3 + str1)).slice(0,-str1.length) |
---|
| 521 | ); |
---|
| 522 | |
---|
| 523 | return contains( m_style.backgroundImage, 'gradient' ); |
---|
| 524 | }; |
---|
| 525 | |
---|
| 526 | |
---|
| 527 | tests['cssreflections'] = function() { |
---|
| 528 | return test_props_all( 'boxReflect' ); |
---|
| 529 | }; |
---|
| 530 | |
---|
| 531 | |
---|
| 532 | tests['csstransforms'] = function() { |
---|
| 533 | return !!test_props([ 'transformProperty', 'WebkitTransform', 'MozTransform', 'OTransform', 'msTransform' ]); |
---|
| 534 | }; |
---|
| 535 | |
---|
| 536 | |
---|
| 537 | tests['csstransforms3d'] = function() { |
---|
| 538 | |
---|
| 539 | var ret = !!test_props([ 'perspectiveProperty', 'WebkitPerspective', 'MozPerspective', 'OPerspective', 'msPerspective' ]); |
---|
| 540 | |
---|
| 541 | // Webkitâs 3D transforms are passed off to the browser's own graphics renderer. |
---|
| 542 | // It works fine in Safari on Leopard and Snow Leopard, but not in Chrome in |
---|
| 543 | // some conditions. As a result, Webkit typically recognizes the syntax but |
---|
| 544 | // will sometimes throw a false positive, thus we must do a more thorough check: |
---|
| 545 | if (ret && 'webkitPerspective' in docElement.style){ |
---|
| 546 | |
---|
| 547 | // Webkit allows this media query to succeed only if the feature is enabled. |
---|
| 548 | // `@media (transform-3d),(-o-transform-3d),(-moz-transform-3d),(-ms-transform-3d),(-webkit-transform-3d),(modernizr){ ... }` |
---|
| 549 | ret = testMediaQuery('@media ('+prefixes.join('transform-3d),(')+'modernizr)'); |
---|
| 550 | } |
---|
| 551 | return ret; |
---|
| 552 | }; |
---|
| 553 | |
---|
| 554 | |
---|
| 555 | tests['csstransitions'] = function() { |
---|
| 556 | return test_props_all( 'transitionProperty' ); |
---|
| 557 | }; |
---|
| 558 | |
---|
| 559 | |
---|
| 560 | // @font-face detection routine by Diego Perini |
---|
| 561 | // http://javascript.nwbox.com/CSSSupport/ |
---|
| 562 | tests['fontface'] = function(){ |
---|
| 563 | |
---|
| 564 | var |
---|
| 565 | sheet, bool, |
---|
| 566 | head = docHead || docElement, |
---|
| 567 | style = document.createElement("style"), |
---|
| 568 | impl = document.implementation || { hasFeature: function() { return false; } }; |
---|
| 569 | |
---|
| 570 | style.type = 'text/css'; |
---|
| 571 | head.insertBefore(style, head.firstChild); |
---|
| 572 | sheet = style.sheet || style.styleSheet; |
---|
| 573 | |
---|
| 574 | var supportAtRule = impl.hasFeature('CSS2', '') ? |
---|
| 575 | function(rule) { |
---|
| 576 | if (!(sheet && rule)) return false; |
---|
| 577 | var result = false; |
---|
| 578 | try { |
---|
| 579 | sheet.insertRule(rule, 0); |
---|
| 580 | result = (/src/i).test(sheet.cssRules[0].cssText); |
---|
| 581 | sheet.deleteRule(sheet.cssRules.length - 1); |
---|
| 582 | } catch(e) { } |
---|
| 583 | return result; |
---|
| 584 | } : |
---|
| 585 | function(rule) { |
---|
| 586 | if (!(sheet && rule)) return false; |
---|
| 587 | sheet.cssText = rule; |
---|
| 588 | |
---|
| 589 | return sheet.cssText.length !== 0 && (/src/i).test(sheet.cssText) && |
---|
| 590 | sheet.cssText |
---|
| 591 | .replace(/\r+|\n+/g, '') |
---|
| 592 | .indexOf(rule.split(' ')[0]) === 0; |
---|
| 593 | }; |
---|
| 594 | |
---|
| 595 | bool = supportAtRule('@font-face { font-family: "font"; src: url(data:,); }'); |
---|
| 596 | head.removeChild(style); |
---|
| 597 | return bool; |
---|
| 598 | }; |
---|
| 599 | |
---|
| 600 | |
---|
| 601 | // These tests evaluate support of the video/audio elements, as well as |
---|
| 602 | // testing what types of content they support. |
---|
| 603 | // |
---|
| 604 | // We're using the Boolean constructor here, so that we can extend the value |
---|
| 605 | // e.g. Modernizr.video // true |
---|
| 606 | // Modernizr.video.ogg // 'probably' |
---|
| 607 | // |
---|
| 608 | // Codec values from : http://github.com/NielsLeenheer/html5test/blob/9106a8/index.html#L845 |
---|
| 609 | // thx to NielsLeenheer and zcorpan |
---|
| 610 | |
---|
| 611 | // Note: in FF 3.5.1 and 3.5.0, "no" was a return value instead of empty string. |
---|
| 612 | // Modernizr does not normalize for that. |
---|
| 613 | |
---|
| 614 | tests['video'] = function() { |
---|
| 615 | var elem = document.createElement('video'), |
---|
| 616 | bool = !!elem.canPlayType; |
---|
| 617 | |
---|
| 618 | if (bool){ |
---|
| 619 | bool = new Boolean(bool); |
---|
| 620 | bool.ogg = elem.canPlayType('video/ogg; codecs="theora"'); |
---|
| 621 | |
---|
| 622 | // Workaround required for IE9, which doesn't report video support without audio codec specified. |
---|
| 623 | // bug 599718 @ msft connect |
---|
| 624 | var h264 = 'video/mp4; codecs="avc1.42E01E'; |
---|
| 625 | bool.h264 = elem.canPlayType(h264 + '"') || elem.canPlayType(h264 + ', mp4a.40.2"'); |
---|
| 626 | |
---|
| 627 | bool.webm = elem.canPlayType('video/webm; codecs="vp8, vorbis"'); |
---|
| 628 | } |
---|
| 629 | return bool; |
---|
| 630 | }; |
---|
| 631 | |
---|
| 632 | tests['audio'] = function() { |
---|
| 633 | var elem = document.createElement('audio'), |
---|
| 634 | bool = !!elem.canPlayType; |
---|
| 635 | |
---|
| 636 | if (bool){ |
---|
| 637 | bool = new Boolean(bool); |
---|
| 638 | bool.ogg = elem.canPlayType('audio/ogg; codecs="vorbis"'); |
---|
| 639 | bool.mp3 = elem.canPlayType('audio/mpeg;'); |
---|
| 640 | |
---|
| 641 | // Mimetypes accepted: |
---|
| 642 | // https://developer.mozilla.org/En/Media_formats_supported_by_the_audio_and_video_elements |
---|
| 643 | // http://bit.ly/iphoneoscodecs |
---|
| 644 | bool.wav = elem.canPlayType('audio/wav; codecs="1"'); |
---|
| 645 | bool.m4a = elem.canPlayType('audio/x-m4a;') || elem.canPlayType('audio/aac;'); |
---|
| 646 | } |
---|
| 647 | return bool; |
---|
| 648 | }; |
---|
| 649 | |
---|
| 650 | |
---|
| 651 | // Firefox has made these tests rather unfun. |
---|
| 652 | |
---|
| 653 | // In FF4, if disabled, window.localStorage should === null. |
---|
| 654 | |
---|
| 655 | // Normally, we could not test that directly and need to do a |
---|
| 656 | // `('localStorage' in window) && ` test first because otherwise Firefox will |
---|
| 657 | // throw http://bugzil.la/365772 if cookies are disabled |
---|
| 658 | |
---|
| 659 | // However, in Firefox 4 betas, if dom.storage.enabled == false, just mentioning |
---|
| 660 | // the property will throw an exception. http://bugzil.la/599479 |
---|
| 661 | // This looks to be fixed for FF4 Final. |
---|
| 662 | |
---|
| 663 | // Because we are forced to try/catch this, we'll go aggressive. |
---|
| 664 | |
---|
| 665 | // FWIW: IE8 Compat mode supports these features completely: |
---|
| 666 | // http://www.quirksmode.org/dom/html5.html |
---|
| 667 | // But IE8 doesn't support either with local files |
---|
| 668 | |
---|
| 669 | tests['localstorage'] = function() { |
---|
| 670 | try { |
---|
| 671 | return !!localStorage.getItem; |
---|
| 672 | } catch(e) { |
---|
| 673 | return false; |
---|
| 674 | } |
---|
| 675 | }; |
---|
| 676 | |
---|
| 677 | tests['sessionstorage'] = function() { |
---|
| 678 | try { |
---|
| 679 | return !!sessionStorage.getItem; |
---|
| 680 | } catch(e){ |
---|
| 681 | return false; |
---|
| 682 | } |
---|
| 683 | }; |
---|
| 684 | |
---|
| 685 | |
---|
| 686 | tests['webWorkers'] = function () { |
---|
| 687 | return !!window.Worker; |
---|
| 688 | }; |
---|
| 689 | |
---|
| 690 | |
---|
| 691 | tests['applicationcache'] = function() { |
---|
| 692 | return !!window.applicationCache; |
---|
| 693 | }; |
---|
| 694 | |
---|
| 695 | |
---|
| 696 | // Thanks to Erik Dahlstrom |
---|
| 697 | tests['svg'] = function(){ |
---|
| 698 | return !!document.createElementNS && !!document.createElementNS(ns.svg, "svg").createSVGRect; |
---|
| 699 | }; |
---|
| 700 | |
---|
| 701 | tests['inlinesvg'] = function() { |
---|
| 702 | var div = document.createElement('div'); |
---|
| 703 | div.innerHTML = '<svg/>'; |
---|
| 704 | return (div.firstChild && div.firstChild.namespaceURI) == ns.svg; |
---|
| 705 | }; |
---|
| 706 | |
---|
| 707 | // Thanks to F1lt3r and lucideer |
---|
| 708 | // http://github.com/Modernizr/Modernizr/issues#issue/35 |
---|
| 709 | tests['smil'] = function(){ |
---|
| 710 | return !!document.createElementNS && /SVG/.test(tostring.call(document.createElementNS(ns.svg,'animate'))); |
---|
| 711 | }; |
---|
| 712 | |
---|
| 713 | tests['svgclippaths'] = function(){ |
---|
| 714 | // Possibly returns a false positive in Safari 3.2? |
---|
| 715 | return !!document.createElementNS && /SVG/.test(tostring.call(document.createElementNS(ns.svg,'clipPath'))); |
---|
| 716 | }; |
---|
| 717 | |
---|
| 718 | |
---|
| 719 | // input features and input types go directly onto the ret object, bypassing the tests loop. |
---|
| 720 | // Hold this guy to execute in a moment. |
---|
| 721 | function webforms(){ |
---|
| 722 | |
---|
| 723 | // Run through HTML5's new input attributes to see if the UA understands any. |
---|
| 724 | // We're using f which is the <input> element created early on |
---|
| 725 | // Mike Taylr has created a comprehensive resource for testing these attributes |
---|
| 726 | // when applied to all input types: |
---|
| 727 | // http://miketaylr.com/code/input-type-attr.html |
---|
| 728 | // spec: http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary |
---|
| 729 | ret['input'] = (function(props) { |
---|
| 730 | for (var i = 0, len = props.length; i<len; i++) { |
---|
| 731 | attrs[ props[i] ] = !!(props[i] in inputElem); |
---|
| 732 | } |
---|
| 733 | return attrs; |
---|
| 734 | })('autocomplete autofocus list placeholder max min multiple pattern required step'.split(' ')); |
---|
| 735 | |
---|
| 736 | // Run through HTML5's new input types to see if the UA understands any. |
---|
| 737 | // This is put behind the tests runloop because it doesn't return a |
---|
| 738 | // true/false like all the other tests; instead, it returns an object |
---|
| 739 | // containing each input type with its corresponding true/false value |
---|
| 740 | |
---|
| 741 | // Big thanks to @miketaylr for the html5 forms expertise. http://miketaylr.com/ |
---|
| 742 | ret['inputtypes'] = (function(props) { |
---|
| 743 | |
---|
| 744 | for (var i = 0, bool, inputElemType, defaultView, len=props.length; i < len; i++) { |
---|
| 745 | |
---|
| 746 | inputElem.setAttribute('type', inputElemType = props[i]); |
---|
| 747 | bool = inputElem.type !== 'text'; |
---|
| 748 | |
---|
| 749 | // We first check to see if the type we give it sticks.. |
---|
| 750 | // If the type does, we feed it a textual value, which shouldn't be valid. |
---|
| 751 | // If the value doesn't stick, we know there's input sanitization which infers a custom UI |
---|
| 752 | if (bool){ |
---|
| 753 | |
---|
| 754 | inputElem.value = smile; |
---|
| 755 | inputElem.style.cssText = 'position:absolute;visibility:hidden;'; |
---|
| 756 | |
---|
| 757 | if (/^range$/.test(inputElemType) && inputElem.style.WebkitAppearance !== undefined){ |
---|
| 758 | |
---|
| 759 | docElement.appendChild(inputElem); |
---|
| 760 | defaultView = document.defaultView; |
---|
| 761 | |
---|
| 762 | // Safari 2-4 allows the smiley as a value, despite making a slider |
---|
| 763 | bool = defaultView.getComputedStyle && |
---|
| 764 | defaultView.getComputedStyle(inputElem, null).WebkitAppearance !== 'textfield' && |
---|
| 765 | // Mobile android web browser has false positive, so must |
---|
| 766 | // check the height to see if the widget is actually there. |
---|
| 767 | (inputElem.offsetHeight !== 0); |
---|
| 768 | |
---|
| 769 | docElement.removeChild(inputElem); |
---|
| 770 | |
---|
| 771 | } else if (/^(search|tel)$/.test(inputElemType)){ |
---|
| 772 | // Spec doesnt define any special parsing or detectable UI |
---|
| 773 | // behaviors so we pass these through as true |
---|
| 774 | |
---|
| 775 | // Interestingly, opera fails the earlier test, so it doesn't |
---|
| 776 | // even make it here. |
---|
| 777 | |
---|
| 778 | } else if (/^(url|email)$/.test(inputElemType)) { |
---|
| 779 | // Real url and email support comes with prebaked validation. |
---|
| 780 | bool = inputElem.checkValidity && inputElem.checkValidity() === false; |
---|
| 781 | |
---|
| 782 | } else if (/^color$/.test(inputElemType)) { |
---|
| 783 | // chuck into DOM and force reflow for Opera bug in 11.00 |
---|
| 784 | // github.com/Modernizr/Modernizr/issues#issue/159 |
---|
| 785 | docElement.appendChild(inputElem); |
---|
| 786 | docElement.offsetWidth; |
---|
| 787 | bool = inputElem.value != smile; |
---|
| 788 | docElement.removeChild(inputElem); |
---|
| 789 | |
---|
| 790 | } else { |
---|
| 791 | // If the upgraded input compontent rejects the :) text, we got a winner |
---|
| 792 | bool = inputElem.value != smile; |
---|
| 793 | } |
---|
| 794 | } |
---|
| 795 | |
---|
| 796 | inputs[ props[i] ] = !!bool; |
---|
| 797 | } |
---|
| 798 | return inputs; |
---|
| 799 | })('search tel url email datetime date month week time datetime-local number range color'.split(' ')); |
---|
| 800 | |
---|
| 801 | } |
---|
| 802 | |
---|
| 803 | |
---|
| 804 | |
---|
| 805 | // End of test definitions |
---|
| 806 | // ----------------------- |
---|
| 807 | |
---|
| 808 | |
---|
| 809 | |
---|
| 810 | // Run through all tests and detect their support in the current UA. |
---|
| 811 | // todo: hypothetically we could be doing an array of tests and use a basic loop here. |
---|
| 812 | for ( var feature in tests ) { |
---|
| 813 | if ( hasOwnProperty( tests, feature ) ) { |
---|
| 814 | // run the test, throw the return value into the Modernizr, |
---|
| 815 | // then based on that boolean, define an appropriate className |
---|
| 816 | // and push it into an array of classes we'll join later. |
---|
| 817 | featurename = feature.toLowerCase(); |
---|
| 818 | ret[ featurename ] = tests[ feature ](); |
---|
| 819 | |
---|
| 820 | classes.push( ( ret[ featurename ] ? '' : 'no-' ) + featurename ); |
---|
| 821 | } |
---|
| 822 | } |
---|
| 823 | |
---|
| 824 | // input tests need to run. |
---|
| 825 | if (!ret.input) webforms(); |
---|
| 826 | |
---|
| 827 | |
---|
| 828 | |
---|
| 829 | // Per 1.6: deprecated API is still accesible for now: |
---|
| 830 | ret.crosswindowmessaging = ret.postmessage; |
---|
| 831 | ret.historymanagement = ret.history; |
---|
| 832 | |
---|
| 833 | |
---|
| 834 | |
---|
| 835 | /** |
---|
| 836 | * Addtest allows the user to define their own feature tests |
---|
| 837 | * the result will be added onto the Modernizr object, |
---|
| 838 | * as well as an appropriate className set on the html element |
---|
| 839 | * |
---|
| 840 | * @param feature - String naming the feature |
---|
| 841 | * @param test - Function returning true if feature is supported, false if not |
---|
| 842 | */ |
---|
| 843 | ret.addTest = function (feature, test) { |
---|
| 844 | feature = feature.toLowerCase(); |
---|
| 845 | |
---|
| 846 | if (ret[ feature ]) { |
---|
| 847 | return; // quit if you're trying to overwrite an existing test |
---|
| 848 | } |
---|
| 849 | test = !!(test()); |
---|
| 850 | docElement.className += ' ' + (test ? '' : 'no-') + feature; |
---|
| 851 | ret[ feature ] = test; |
---|
| 852 | return ret; // allow chaining. |
---|
| 853 | }; |
---|
| 854 | |
---|
| 855 | /** |
---|
| 856 | * Reset m.style.cssText to nothing to reduce memory footprint. |
---|
| 857 | */ |
---|
| 858 | set_css( '' ); |
---|
| 859 | modElem = inputElem = null; |
---|
| 860 | |
---|
| 861 | //>>BEGIN IEPP |
---|
| 862 | // Enable HTML 5 elements for styling in IE. |
---|
| 863 | // fyi: jscript version does not reflect trident version |
---|
| 864 | // therefore ie9 in ie7 mode will still have a jScript v.9 |
---|
| 865 | if ( enableHTML5 && window.attachEvent && (function(){ var elem = document.createElement("div"); |
---|
| 866 | elem.innerHTML = "<elem></elem>"; |
---|
| 867 | return elem.childNodes.length !== 1; })()) { |
---|
| 868 | // iepp v1.6.2 by @jon_neal : code.google.com/p/ie-print-protector |
---|
| 869 | (function(win, doc) { |
---|
| 870 | var elems = 'abbr|article|aside|audio|canvas|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video', |
---|
| 871 | elemsArr = elems.split('|'), |
---|
| 872 | elemsArrLen = elemsArr.length, |
---|
| 873 | elemRegExp = new RegExp('(^|\\s)('+elems+')', 'gi'), |
---|
| 874 | tagRegExp = new RegExp('<(\/*)('+elems+')', 'gi'), |
---|
| 875 | ruleRegExp = new RegExp('(^|[^\\n]*?\\s)('+elems+')([^\\n]*)({[\\n\\w\\W]*?})', 'gi'), |
---|
| 876 | docFrag = doc.createDocumentFragment(), |
---|
| 877 | html = doc.documentElement, |
---|
| 878 | head = html.firstChild, |
---|
| 879 | bodyElem = doc.createElement('body'), |
---|
| 880 | styleElem = doc.createElement('style'), |
---|
| 881 | body; |
---|
| 882 | function shim(doc) { |
---|
| 883 | var a = -1; |
---|
| 884 | while (++a < elemsArrLen) |
---|
| 885 | // Use createElement so IE allows HTML5-named elements in a document |
---|
| 886 | doc.createElement(elemsArr[a]); |
---|
| 887 | } |
---|
| 888 | function getCSS(styleSheetList, mediaType) { |
---|
| 889 | var a = -1, |
---|
| 890 | len = styleSheetList.length, |
---|
| 891 | styleSheet, |
---|
| 892 | cssTextArr = []; |
---|
| 893 | while (++a < len) { |
---|
| 894 | styleSheet = styleSheetList[a]; |
---|
| 895 | // Get css from all non-screen stylesheets and their imports |
---|
| 896 | if ((mediaType = styleSheet.media || mediaType) != 'screen') cssTextArr.push(getCSS(styleSheet.imports, mediaType), styleSheet.cssText); |
---|
| 897 | } |
---|
| 898 | return cssTextArr.join(''); |
---|
| 899 | } |
---|
| 900 | // Shim the document and iepp fragment |
---|
| 901 | shim(doc); |
---|
| 902 | shim(docFrag); |
---|
| 903 | // Add iepp custom print style element |
---|
| 904 | head.insertBefore(styleElem, head.firstChild); |
---|
| 905 | styleElem.media = 'print'; |
---|
| 906 | win.attachEvent( |
---|
| 907 | 'onbeforeprint', |
---|
| 908 | function() { |
---|
| 909 | var a = -1, |
---|
| 910 | cssText = getCSS(doc.styleSheets, 'all'), |
---|
| 911 | cssTextArr = [], |
---|
| 912 | rule; |
---|
| 913 | body = body || doc.body; |
---|
| 914 | // Get only rules which reference HTML5 elements by name |
---|
| 915 | while ((rule = ruleRegExp.exec(cssText)) != null) |
---|
| 916 | // Replace all html5 element references with iepp substitute classnames |
---|
| 917 | cssTextArr.push((rule[1]+rule[2]+rule[3]).replace(elemRegExp, '$1.iepp_$2')+rule[4]); |
---|
| 918 | // Write iepp custom print CSS |
---|
| 919 | styleElem.styleSheet.cssText = cssTextArr.join('\n'); |
---|
| 920 | while (++a < elemsArrLen) { |
---|
| 921 | var nodeList = doc.getElementsByTagName(elemsArr[a]), |
---|
| 922 | nodeListLen = nodeList.length, |
---|
| 923 | b = -1; |
---|
| 924 | while (++b < nodeListLen) |
---|
| 925 | if (nodeList[b].className.indexOf('iepp_') < 0) |
---|
| 926 | // Append iepp substitute classnames to all html5 elements |
---|
| 927 | nodeList[b].className += ' iepp_'+elemsArr[a]; |
---|
| 928 | } |
---|
| 929 | docFrag.appendChild(body); |
---|
| 930 | html.appendChild(bodyElem); |
---|
| 931 | // Write iepp substitute print-safe document |
---|
| 932 | bodyElem.className = body.className; |
---|
| 933 | // Replace HTML5 elements with <font> which is print-safe and shouldn't conflict since it isn't part of html5 |
---|
| 934 | bodyElem.innerHTML = body.innerHTML.replace(tagRegExp, '<$1font'); |
---|
| 935 | } |
---|
| 936 | ); |
---|
| 937 | win.attachEvent( |
---|
| 938 | 'onafterprint', |
---|
| 939 | function() { |
---|
| 940 | // Undo everything done in onbeforeprint |
---|
| 941 | bodyElem.innerHTML = ''; |
---|
| 942 | html.removeChild(bodyElem); |
---|
| 943 | html.appendChild(body); |
---|
| 944 | styleElem.styleSheet.cssText = ''; |
---|
| 945 | } |
---|
| 946 | ); |
---|
| 947 | })(window, document); |
---|
| 948 | } |
---|
| 949 | //>>END IEPP |
---|
| 950 | |
---|
| 951 | // Assign private properties to the return object with prefix |
---|
| 952 | ret._enableHTML5 = enableHTML5; |
---|
| 953 | ret._version = version; |
---|
| 954 | |
---|
| 955 | // Remove "no-js" class from <html> element, if it exists: |
---|
| 956 | docElement.className = docElement.className.replace(/\bno-js\b/,'') |
---|
| 957 | + ' js ' |
---|
| 958 | |
---|
| 959 | // Add the new classes to the <html> element. |
---|
| 960 | + classes.join( ' ' ); |
---|
| 961 | |
---|
| 962 | return ret; |
---|
| 963 | |
---|
| 964 | })(this,this.document); |
---|