PageSourceSearch

https://green.in/js/viewport-units-buggyfill.js

js green.in collected 2026-10-09 00:20:10 UTC 6,897 bytes, 262 lines download raw bytes

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.