summaryrefslogtreecommitdiffstats
path: root/actual.js
blob: 2325de9ac7b7c9cfdbfaed862ed6440d80f36fda (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
!function(root, name, make) {
  if (typeof module != 'undefined' && module.exports) module.exports = make();
  else root[name] = make();
}(this, 'actual', function() {

  /**
   * @param {string} feature range feature name e.g. "width"
   * @param {string=} unit CSS unit for feature e.g. "em"
   * @param {number=} init initial guess
   * @param {number=} step size for iterations
   * @return {number} breakpoint (0 if invalid unit or feature)
   */
  function actual(feature, unit, init, step) {
    var up, gte, lte, curr, mq = actual['mq'];
    unit = typeof unit == 'string' ? unit : '';
    init = 0 < init ? (unit ? +init : init>>0) : 1;
    // Step starts positive. Minimize iterations, unless feat may be "integer" type.
    step = 0 < step ? +step : 0 > step ? -step : 'px' == unit ? 256 : unit ? 32 : 1;
    for (feature += ':', unit += ')', curr = init; step && 0 <= curr; curr+=step) {
      lte = mq('(min-' + feature + curr + unit);
      gte = mq('(max-' + feature + curr + unit);
      // Found: Use the floored value if it makes an exact match. Else return as is.
      if (lte && gte) return mq('(' + feature + (curr>>0) + unit) ? curr>>0 : curr;
      // 1st iteration: Save direction. Flip if down. Break if neither b/c unknown.
      if (null == up) step = (up = !gte) ? lte && step : -step;
      // Later iterations: If skipped, reverse direction and raise precision.
      else if (gte ? up : !up) up = !up, step = -step/2;
    }
    return 0;
  }

  /**
   * @param {string} unit
   * @return {Function}
   */
  function as(unit) {
    return function(feature) {
      return actual(feature, unit);
    };
  }

  var media = 'matchMedia', win = typeof window != 'undefined' && window;
  actual['actual'] = actual;
  actual['as'] = as;
  actual['is'] = actual['mq'] = win[media] || win[media = 'msMatchMedia'] ? function(q) {
    return !!win[media](q).matches;
  } : function() {
    return false;
  };

  return actual;
});