All files / src/support/compatibility vendors.ts

100% Statements 47/47
100% Branches 18/18
100% Functions 10/10
100% Lines 45/45

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112        206x 12x       12x 12x                     12x 12x           12x 6x   6x 1x     5x 5x   5x 17x 17x               17x 65x         5x                 12x 11x 11x   11x 4x     7x 7x 7x 7x   7x 10x 42x 42x 42x 2x 2x     10x       7x             12x 60x   60x 1x     59x 220x 220x     59x 59x    
import { each } from 'support/utils/array';
import { hasOwnProperty } from 'support/utils/object';
import { createDiv } from 'support/dom/create';
 
const firstLetterToUpper = (str: string): string => str.charAt(0).toUpperCase() + str.slice(1);
const getDummyStyle = (): CSSStyleDeclaration => createDiv().style;
 
// https://developer.mozilla.org/en-US/docs/Glossary/Vendor_Prefix
 
export const cssPrefixes: ReadonlyArray<string> = ['-webkit-', '-moz-', '-o-', '-ms-'];
export const jsPrefixes: ReadonlyArray<string> = [
  'WebKit',
  'Moz',
  'O',
  'MS',
  'webkit',
  'moz',
  'o',
  'ms',
];
 
export const jsCache: { [key: string]: any } = {};
export const cssCache: { [key: string]: string } = {};
 
/**
 * Gets the name of the given CSS property with vendor prefix if it isn't supported without it, or and empty string if unsupported.
 * @param name The name of the CSS property which shall be get.
 */
export const cssProperty = (name: string): string => {
  let result: string | undefined = cssCache[name];
 
  if (hasOwnProperty(cssCache, name)) {
    return result;
  }
 
  const uppercasedName: string = firstLetterToUpper(name);
  const elmStyle: CSSStyleDeclaration = getDummyStyle();
 
  each(cssPrefixes, (prefix: string) => {
    const prefixWithoutDashes: string = prefix.replace(/-/g, '');
    const resultPossibilities: Array<string> = [
      name, // transition
      prefix + name, // -webkit-transition
      prefixWithoutDashes + uppercasedName, // webkitTransition
      firstLetterToUpper(prefixWithoutDashes) + uppercasedName, // WebkitTransition
    ];
 
    // eslint-disable-next-line no-return-assign
    return !(result = resultPossibilities.find(
      (resultPossibility: string) => elmStyle[resultPossibility] !== undefined
    ));
  });
 
  // eslint-disable-next-line no-return-assign
  return (cssCache[name] = result || '');
};
 
/**
 * Get the name of the given CSS property value(s), with vendor prefix if it isn't supported without it, or an empty string if no value is supported.
 * @param property The CSS property to which the CSS property value(s) belong.
 * @param values The value(s) separated by spaces which shall be get.
 * @param suffix A suffix which is added to each value in case the value is a function or something else more advanced.
 */
export const cssPropertyValue = (property: string, values: string, suffix?: string): string => {
  const name = `${property} ${values}`;
  let result: string | undefined = cssCache[name];
 
  if (hasOwnProperty(cssCache, name)) {
    return result;
  }
 
  const dummyStyle: CSSStyleDeclaration = getDummyStyle();
  const possbleValues: Array<string> = values.split(' ');
  const preparedSuffix: string = suffix || '';
  const cssPrefixesWithFirstEmpty = [''].concat(cssPrefixes);
 
  each(possbleValues, (possibleValue: string) => {
    each(cssPrefixesWithFirstEmpty, (prefix: string) => {
      const prop = prefix + possibleValue;
      dummyStyle.cssText = `${property}:${prop}${preparedSuffix}`;
      if (dummyStyle.length) {
        result = prop;
        return false;
      }
    });
    return !result;
  });
 
  // eslint-disable-next-line no-return-assign
  return (cssCache[name] = result || '');
};
 
/**
 * Get the requested JS function, object or constructor with vendor prefix if it isn't supported without or undefined if unsupported.
 * @param name The name of the JS function, object or constructor.
 */
export const jsAPI = <T = any>(name: string): T | undefined => {
  let result: any = jsCache[name] || window[name];
 
  if (hasOwnProperty(jsCache, name)) {
    return result;
  }
 
  each(jsPrefixes, (prefix: string) => {
    result = result || window[prefix + firstLetterToUpper(name)];
    return !result;
  });
 
  jsCache[name] = result;
  return result;
};