1/*! 2 * viewport-units-buggyfill v0.5.4 3 * @web: https://github.com/rodneyrehm/viewport-units-buggyfill/ 4 * @author: Rodney Rehm - http://rodneyrehm.de/en/ 5 */ 6 7 8(function (root, factory) { 9 'use strict'; 10 if (typeof define === 'function' && define.amd) { 11 // AMD. Register as an anonymous module. 12 define([], factory); 13 } else if (typeof exports === 'object') { 14 // Node. Does not work with strict CommonJS, but 15 // only CommonJS-like enviroments that support module.exports, 16 // like Node. 17 module.exports = factory(); 18 } else { 19 // Browser globals (root is window) 20 root.viewportUnitsBuggyfill = factory(); 21 } 22}(this, function () { 23 'use strict'; 24 /*global document, window, navigator, location, XMLHttpRequest, XDomainRequest*/ 25 26 var initialized = false; 27 var options; 28 var userAgent = window.navigator.userAgent; 29 var viewportUnitExpression = /([+-]?[0-9.]+)(vh|vw|vmin|vmax)/g; 30 var forEach = [].forEach; 31 var dimensions; 32 var declarations; 33 var styleNode; 34 var isBuggyIE = /MSIE [0-9]\./i.test(userAgent); 35 var isOldIE = /MSIE [0-8]\./i.test(userAgent); 36 var isOperaMini = userAgent.indexOf('Opera Mini') > -1; 37 38 var isMobileSafari = /(iPhone|iPod|iPad).+AppleWebKit/i.test(userAgent) && (function() { 39 // Regexp for iOS-version tested against the following userAgent strings: 40 // Example WebView UserAgents: 41 // * iOS Chrome on iOS8: "Mozilla/5.0 (iPad; CPU OS 8_1 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) CriOS/39.0.2171.50 Mobile/12B410 Safari/600.1.4" 42 // * iOS Facebook on iOS7: "Mozilla/5.0 (iPhone; CPU iPhone OS 7_1_1 like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Mobile/11D201 [FBAN/FBIOS;FBAV/12.1.0.24.20; FBBV/3214247; FBDV/iPhone6,1;FBMD/iPhone; FBSN/iPhone OS;FBSV/7.1.1; FBSS/2; FBCR/AT&T;FBID/phone;FBLC/en_US;FBOP/5]" 43 // Example Safari UserAgents: 44 // * Safari iOS8: "Mozilla/5.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/600.1.3 (KHTML, like Gecko) Version/8.0 Mobile/12A4345d Safari/600.1.4" 45 // * Safari iOS7: "Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A4449d Safari/9537.53" 46 var iOSversion = userAgent.match(/OS (\d)/); 47 // viewport units work fine in mobile Safari and webView on iOS 8+ 48 return iOSversion && iOSversion.length>1 && parseInt(iOSversion[1]) < 8; 49 })(); 50 51 var isBadStockAndroid = (function() { 52 // Android stock browser test derived from 53 // http://stackoverflow.com/questions/24926221/distinguish-android-chrome-from-stock-browser-stock-browsers-user-agent-contai 54 var isAndroid = userAgent.indexOf(' Android ') > -1; 55 if (!isAndroid) { 56 return false; 57 } 58 59 var isStockAndroid = userAgent.indexOf('Version/') > -1; 60 if (!isStockAndroid) { 61 return false; 62 } 63 64 var versionNumber = parseFloat((userAgent.match('Android ([0-9.]+)') || [])[1]); 65 // anything below 4.4 uses WebKit without *any* viewport support, 66 // 4.4 has issues with viewport units within calc() 67 return versionNumber <= 4.4; 68 })(); 69 70 // added check for IE11, since it *still* doesn't understand vmax!!! 71 if (!isBuggyIE) { 72 isBuggyIE = !!navigator.userAgent.match(/Trident.*rv[ :]*11\./); 73 } 74 function debounce(func, wait) { 75 var timeout; 76 return function() { 77 var context = this; 78 var args = arguments; 79 var callback = function() { 80 func.apply(context, args); 81 }; 82 83 clearTimeout(timeout); 84 timeout = setTimeout(callback, wait); 85 }; 86 } 87 88 // from http://stackoverflow.com/questions/326069/how-to-identify-if-a-webpage-is-being-loaded-inside-an-iframe-or-directly-into-t 89 function inIframe() { 90 try { 91 return window.self !== window.top; 92 } catch (e) { 93 return true; 94 } 95 } 96 97 function initialize(initOptions) { 98 if (initialized) { 99 return; 100 } 101 102 if (initOptions === true) { 103 initOptions = { 104 force: true 105 }; 106 } 107 108 options = initOptions || {}; 109 options.isMobileSafari = isMobileSafari; 110 options.isBadStockAndroid = isBadStockAndroid; 111 112 if (isOldIE || (!options.force && !isMobileSafari && !isBuggyIE && !isBadStockAndroid && !isOperaMini && (!options.hacks || !options.hacks.required(options)))) { 113 // this buggyfill only applies to mobile safari, IE9-10 and the Stock Android Browser. 114 if (window.console && isOldIE) { 115 console.info('viewport-units-buggyfill requires a proper CSSOM and basic viewport unit support, which are not available in IE8 and below'); 116 } 117 118 return { 119 init: function () {} 120 }; 121 } 122 123 options.hacks && options.hacks.initialize(options); 124 125 initialized = true; 126 styleNode = document.createElement('style'); 127 styleNode.id = 'patched-viewport'; 128 document.head.appendChild(styleNode); 129 130 // Issue #6: Cross Origin Stylesheets are not accessible through CSSOM, 131 // therefore download and inject them as <style> to circumvent SOP. 132 importCrossOriginLinks(function() { 133 var _refresh = debounce(refresh, options.refreshDebounceWait || 100); 134 // doing a full refresh rather than updateStyles because an orientationchange 135 // could activate different stylesheets 136 window.addEventListener('orientationchange', _refresh, true); 137 // orientationchange might have happened while in a different window 138 window.addEventListener('pageshow', _refresh, true); 139 140 if (options.force || isBuggyIE || inIframe()) { 141 window.addEventListener('resize', _refresh, true); 142 options._listeningToResize = true; 143 } 144 145 options.hacks && options.hacks.initializeEvents(options, refresh, _refresh); 146 147 refresh(); 148 }); 149 } 150 151 function updateStyles() { 152 styleNode.textContent = getReplacedViewportUnits(); 153 // move to the end in case inline <style>s were added dynamically 154 styleNode.parentNode.appendChild(styleNode); 155 } 156 157 function refresh() { 158 if (!initialized) { 159 return; 160 } 161 162 findProperties(); 163
164 // iOS Safari will report window.innerWidth and .innerHeight as 0 unless a timeout is used here. 165 // TODO: figure out WHY innerWidth === 0 166 setTimeout(function() { 167 updateStyles(); 168 }, 1); 169 } 170 171 function findProperties() { 172 declarations = []; 173 forEach.call(document.styleSheets, function(sheet) { 174 if (sheet.ownerNode.id === 'patched-viewport' || !sheet.cssRules || sheet.ownerNode.getAttribute('data-viewport-units-buggyfill') === 'ignore') { 175 // skip entire sheet because no rules are present, it's supposed to be ignored or it's the target-element of the buggyfill 176 return; 177 } 178 179 if (sheet.media && sheet.media.mediaText && window.matchMedia && !window.matchMedia(sheet.media.mediaText).matches) { 180 // skip entire sheet because media attribute doesn't match 181 return; 182 } 183 184 forEach.call(sheet.cssRules, findDeclarations); 185 }); 186 187 return declarations; 188 } 189 190 function findDeclarations(rule) { 191 if (rule.type === 7) { 192 var value; 193 194 // there may be a case where accessing cssText throws an error. 195 // I could not reproduce this issue, but the worst that can happen 196 // this way is an animation not running properly. 197 // not awesome, but probably better than a script error 198 // see https://github.com/rodneyrehm/viewport-units-buggyfill/issues/21 199 try { 200 value = rule.cssText; 201 } catch(e) { 202 return; 203 } 204 205 viewportUnitExpression.lastIndex = 0; 206 if (viewportUnitExpression.test(value)) { 207 // KeyframesRule does not have a CSS-PropertyName 208 declarations.push([rule, null, value]); 209 options.hacks && options.hacks.findDeclarations(declarations, rule, null, value); 210 } 211 212 return; 213 } 214 215 if (!rule.style) { 216 if (!rule.cssRules) { 217 return; 218 } 219 220 forEach.call(rule.cssRules, function(_rule) { 221 findDeclarations(_rule); 222 }); 223 224 return; 225 } 226 227 forEach.call(rule.style, function(name) { 228 var value = rule.style.getPropertyValue(name); 229 // preserve those !important rules 230 if (rule.style.getPropertyPriority(name)) { 231 value += ' !important'; 232 } 233 234 viewportUnitExpression.lastIndex = 0; 235 if (viewportUnitExpression.test(value)) { 236 declarations.push([rule, name, value]); 237 options.hacks && options.hacks.findDeclarations(declarations, rule, name, value); 238 } 239 }); 240 } 241 242 function getReplacedViewportUnits() { 243 dimensions = getViewport(); 244 245 var css = []; 246 var buffer = []; 247 var open; 248 var close; 249 250 declarations.forEach(function(item) { 251 var _item = overwriteDeclaration.apply(null, item); 252 var _open = _item.selector.length ? (_item.selector.join(' {\n') + ' {\n') : ''; 253 var _close = new Array(_item.selector.length + 1).join('\n}'); 254 255 if (!_open || _open !== open) { 256 if (buffer.length) { 257 css.push(open + buffer.join('\n') + close); 258 buffer.length = 0; 259 } 260 261 if (_open) { 262 open = _open; 263 close = _close; 264 buffer.push(_item.content); 265 } else { 266 css.push(_item.content); 267 open = null; 268 close = null; 269 } 270 271 return; 272 } 273 274 if (_open && !open) { 275 open = _open; 276 close = _close; 277 } 278 279 buffer.push(_item.content); 280 }); 281 282 if (buffer.length) { 283 css.push(open + buffer.join('\n') + close); 284 } 285 286 // Opera Mini messes up on the content hack (it replaces the DOM node's innerHTML with the value). 287 // This fixes it. We test for Opera Mini only since it is the most expensive CSS selector 288 // see https://developer.mozilla.org/en-US/docs/Web/CSS/Universal_selectors 289 if (isOperaMini) { 290 css.push('* { content: normal !important; }'); 291 } 292 293 return css.join('\n\n'); 294 } 295 296 function overwriteDeclaration(rule, name, value) { 297 var _value; 298 var _selectors = []; 299 300 _value = value.replace(viewportUnitExpression, replaceValues); 301 302 if (options.hacks) { 303 _value = options.hacks.overwriteDeclaration(rule, name, _value); 304 } 305 306 if (name) { 307 // skipping KeyframesRule 308 _selectors.push(rule.selectorText); 309 _value = name + ': ' + _value + ';'; 310 } 311 312 var _rule = rule.parentRule; 313 while (_rule) { 314 _selectors.unshift('@media ' + _rule.media.mediaText); 315 _rule = _rule.parentRule; 316 } 317 318 return { 319 selector: _selectors, 320 content: _value 321 }; 322 } 323 324 function replaceValues(match, number, unit) { 325 var _base = dimensions[unit]; 326 var _number = parseFloat(number) / 100; 327 return (_number * _base) + 'px'; 328 } 329 330 function getViewport() { 331 var vh = window.innerHeight; 332 var vw = window.innerWidth; 333 334 return { 335 vh: vh, 336 vw: vw, 337 vmax: Math.max(vw, vh), 338 vmin: Math.min(vw, vh) 339 }; 340 } 341 342 function importCrossOriginLinks(next) { 343 var _waiting = 0; 344 var decrease = function() { 345 _waiting--; 346 if (!_waiting) { 347 next(); 348 } 349 }; 350
351 forEach.call(document.styleSheets, function(sheet) { 352 if (!sheet.href || origin(sheet.href) === origin(location.href) || sheet.ownerNode.getAttribute('data-viewport-units-buggyfill') === 'ignore') { 353 // skip <style> and <link> from same origin or explicitly declared to ignore 354 return; 355 } 356 357 _waiting++; 358 convertLinkToStyle(sheet.ownerNode, decrease); 359 }); 360 361 if (!_waiting) { 362 next(); 363 } 364 } 365 366 function origin(url) { 367 return url.slice(0, url.indexOf('/', url.indexOf('://') + 3)); 368 } 369 370 function convertLinkToStyle(link, next) { 371 getCors(link.href, function() { 372 var style = document.createElement('style'); 373 style.media = link.media; 374 style.setAttribute('data-href', link.href); 375 style.textContent = this.responseText; 376 link.parentNode.replaceChild(style, link); 377 next(); 378 }, next); 379 } 380 381 function getCors(url, success, error) { 382 var xhr = new XMLHttpRequest(); 383 if ('withCredentials' in xhr) { 384 // XHR for Chrome/Firefox/Opera/Safari. 385 xhr.open('GET', url, true); 386 } else if (typeof XDomainRequest !== 'undefined') { 387 // XDomainRequest for IE. 388 xhr = new XDomainRequest(); 389 xhr.open('GET', url); 390 } else { 391 throw new Error('cross-domain XHR not supported'); 392 } 393 394 xhr.onload = success; 395 xhr.onerror = error; 396 xhr.send(); 397 return xhr; 398 } 399 400 return { 401 version: '0.5.4', 402 findProperties: findProperties, 403 getCss: getReplacedViewportUnits, 404 init: initialize, 405 refresh: refresh 406 }; 407 408}));
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.