1/*! 2 * viewport-units-buggyfill v0.3.1 3 * @web: https://github.com/rodneyrehm/viewport-units-buggyfill/ 4 * @author: Rodney Rehm - http://rodneyrehm.de/en/ 5 */ 6(function (root, factory) { 7 'use strict'; 8 if (typeof define === 'function' && define.amd) { 9 // AMD. Register as an anonymous module. 10 define([], factory); 11 } else if (typeof exports === 'object') { 12 // Node. Does not work with strict CommonJS, but 13 // only CommonJS-like enviroments that support module.exports, 14 // like Node. 15 module.exports = factory(); 16 } else { 17 // Browser globals (root is window) 18 root.viewportUnitsBuggyfill = factory(); 19 } 20}(this, function () { 21 'use strict'; 22 /*global document, window, location, XMLHttpRequest, XDomainRequest*/ 23 24 var initialized = false; 25 var viewportUnitExpression = /([0-9.-]+)(vh|vw|vmin|vmax)/g; 26 var forEach = [].forEach; 27 var join = [].join; 28 var dimensions; 29 var declarations; 30 var styleNode; 31 var is_safari_or_uiwebview = /(iPhone|iPod|iPad).+AppleWebKit/i.test(window.navigator.userAgent); 32 33 function initialize(force) { 34 if (initialized || (!force && !is_safari_or_uiwebview)) { 35 // this buggyfill only applies to mobile safari 36 return; 37 } 38 39 initialized = true; 40 styleNode = document.createElement('style'); 41 styleNode.id = 'patched-viewport'; 42 document.head.appendChild(styleNode); 43 44 // Issue #6: Cross Origin Stylesheets are not accessible through CSSOM, 45 // therefore download and inject them as <style> to circumvent SOP. 46 importCrossOriginLinks(function() { 47 //window.addEventListener('orientationchange', updateStyles, true); 48 // doing a full refresh rather than updateStyles because an orientationchange 49 // could activate different stylesheets 50 window.addEventListener('orientationchange', refresh, true); 51 refresh(); 52 }); 53 } 54 55 function updateStyles() { 56 styleNode.textContent = getReplacedViewportUnits(); 57 } 58 59 function refresh() { 60 if (!initialized) { 61 return; 62 } 63 findProperties(); 64 updateStyles(); 65 } 66 67 function findProperties() { 68 declarations = []; 69 forEach.call(document.styleSheets, function(sheet) { 70 if (sheet.ownerNode.id === 'patched-viewport' || !sheet.cssRules) { 71 // skip entire sheet because no rules ara present or it's the target-element of the buggyfill 72 return; 73 } 74 if (sheet.media.mediaText && !window.matchMedia(sheet.media.mediaText).matches) { 75 // skip entire sheet because media attribute doesn't match 76 return; 77 } 78 forEach.call(sheet.cssRules, findDeclarations); 79 }); 80 return declarations; 81 } 82 83 function findDeclarations(rule) { 84 if (rule.type === 7) { 85 var value = rule.cssText; 86 viewportUnitExpression.lastIndex = 0; 87 if (viewportUnitExpression.test(value)) { 88 declarations.push([rule, null, value]); 89 } 90 return; 91 } 92 93 if (!rule.style) { 94 if (!rule.cssRules) { 95 return; 96 } 97 98 forEach.call(rule.cssRules, function(_rule) { 99 findDeclarations(_rule); 100 }); 101 102 return; 103 } 104 105 forEach.call(rule.style, function(name) { 106 var value = rule.style.getPropertyValue(name); 107 viewportUnitExpression.lastIndex = 0; 108 if (viewportUnitExpression.test(value)) { 109 declarations.push([rule, name, value]); 110 } 111 }); 112 } 113 114 function getReplacedViewportUnits() { 115 dimensions = getViewport(); 116 117 var css = []; 118 var buffer = []; 119 var open; 120 var close; 121 122 declarations.forEach(function(item) { 123 var _item = overwriteDeclaration.apply(null, item); 124 var _open = _item.selector.length ? (_item.selector.join(' {\n') + ' {\n') : ''; 125 var _close = new Array(_item.selector.length + 1).join('\n}'); 126 127 if (!_open || _open !== open) { 128 if (buffer.length) { 129 css.push(open + buffer.join('\n') + close); 130 buffer.length = 0; 131 } 132 133 if (_open) { 134 open = _open; 135 close = _close; 136 buffer.push(_item.content); 137 } else { 138 css.push(_item.content); 139 open = null; 140 close = null; 141 } 142 143 return; 144 } 145 146 if (_open && !open) { 147 open = _open; 148 close = _close; 149 } 150 151 buffer.push(_item.content); 152 }); 153 154 if (buffer.length) { 155 css.push(open + buffer.join('\n') + close); 156 } 157 158 return css.join('\n\n'); 159 } 160 161 function overwriteDeclaration(rule, name, value) { 162 var _value = value.replace(viewportUnitExpression, replaceValues); 163 var _selectors = []; 164 if (name) { 165 _selectors.push(rule.selectorText); 166 _value = name + ': ' + _value + ';'; 167 } 168 169 var _rule = rule.parentRule; 170 while (_rule) { 171 _selectors.unshift('@media ' + join.call(_rule.media, ', ')); 172 _rule = _rule.parentRule; 173 } 174 175 return { 176 selector: _selectors, 177 content: _value 178 }; 179 } 180 181 function replaceValues(match, number, unit) { 182 var _base = dimensions[unit]; 183 var _number = parseFloat(number) / 100; 184 return (_number * _base) + 'px'; 185 } 186 187 function getViewport() { 188 var vh = window.innerHeight; 189 var vw = window.innerWidth; 190 return { 191 vh: vh, 192 vw: vw, 193 vmax: Math.max(vw, vh), 194 vmin: Math.min(vw, vh) 195 }; 196 } 197 198 function importCrossOriginLinks(next) { 199 var _waiting = 0; 200 var decrease = function() { 201 _waiting--; 202 if (!_waiting) { 203 next(); 204 } 205 }; 206
207 forEach.call(document.styleSheets, function(sheet) { 208 if (!sheet.href || origin(sheet.href) === origin(location.href) ) { 209 // skip <style> and <link> from same origin 210 return; 211 } 212 _waiting++; 213 convertLinkToStyle(sheet.ownerNode, decrease); 214 }); 215 216 if (!_waiting) { 217 next(); 218 } 219 } 220 221 function origin(url) { 222 return url.slice(0, url.indexOf('/', url.indexOf('://') + 3)); 223 } 224 225 function convertLinkToStyle(link, next) { 226 getCors(link.href, function() { 227 var style = document.createElement('style'); 228 style.media = link.media; 229 style.setAttribute('data-href', link.href); 230 style.textContent = this.responseText; 231 link.parentNode.replaceChild(style, link); 232 next(); 233 }, next); 234 } 235 236 function getCors(url, success, error) { 237 var xhr = new XMLHttpRequest(); 238 if ('withCredentials' in xhr) { 239 // XHR for Chrome/Firefox/Opera/Safari. 240 xhr.open('GET', url, true); 241 } else if (typeof XDomainRequest !== 'undefined') { 242 // XDomainRequest for IE. 243 xhr = new XDomainRequest(); 244 xhr.open('GET', url); 245 } else { 246 throw new Error('cross-domain XHR not supported'); 247 } 248 249 xhr.onload = success; 250 xhr.onerror = error; 251 xhr.send(); 252 return xhr; 253 } 254 255 return { 256 version: '0.3.1', 257 findProperties: findProperties, 258 getCss: getReplacedViewportUnits, 259 init: initialize, 260 refresh: refresh 261 }; 262}));
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.