KarrLab/datanator_frontend

View on GitHub
src/utils/utils.js

Summary

Maintainability
D
3 days
Test Coverage
A
92%
import React from "react";

function matchAll(string, regex) {
  const matches = [];
  string.replace(regex, function () {
    const match = Array.prototype.slice.call(arguments, 0, -2);
    match.input = arguments[arguments.length - 1];
    match.index = arguments[arguments.length - 2];
    matches.push(match);
  });
  return matches;
}

function formatScientificNotation(
  value,
  sciMagUpThresh = 1,
  sciMagDownThresh = 1,
  sciDecimals = 1,
  fixedDeminals = 1,
  minFixedDecimals = 0,
  html = true
) {
  if (value == null || isNaN(value) || value === undefined) return null;

  const absValue = Math.abs(value);
  const sign = Math.sign(value);
  const exp = Math.floor(Math.log10(absValue));

  if (
    absValue !== 0 &&
    (absValue > Math.pow(10, sciMagUpThresh) ||
      absValue < Math.pow(10, -sciMagDownThresh))
  ) {
    const sciVal = ((sign * absValue) / Math.pow(10, exp)).toFixed(sciDecimals);
    if (html) {
      return (
        <span className="sci-notation">
          {sciVal}&thinsp;&times;&thinsp;10<sup>{exp}</sup>
        </span>
      );
    } else {
      return sciVal + " × 10^" + exp;
    }
  } else if (absValue > 1 || absValue === 0) {
    return value.toFixed(fixedDeminals);
  } else {
    const decimals = Math.max(minFixedDecimals, fixedDeminals - exp);
    return value.toFixed(decimals);
  }
}

function formatChemicalFormula(formula) {
  if (!formula) {
    return null;
  }

  const regex = /([A-Z][a-z]?)([0-9]*)/g;
  const formattedFormula = [];
  for (const match of matchAll(formula, regex)) {
    if (parseFloat(match[2]) === 0) {
      continue;
    }

    if (parseFloat(match[2]) === 1) {
      match[2] = "";
    }

    formattedFormula.push(
      <span key={match[1]}>
        {match[1]}
        {match[2] && <sub>{match[2]}</sub>}
      </span>
    );
  }
  return formattedFormula;
}

function dictOfArraysToArrayOfDicts(dictOfArrays) {
  const arrayOfDicts = [];
  for (const key in dictOfArrays) {
    if (Array.isArray(dictOfArrays[key])) {
      for (let iEl = 0; iEl < dictOfArrays[key].length; iEl++) {
        if (iEl > arrayOfDicts.length - 1) {
          arrayOfDicts.push({});
        }
        arrayOfDicts[iEl][key] = dictOfArrays[key][iEl];
      }
    } else {
      const iEl = 0;
      if (iEl > arrayOfDicts.length - 1) {
        arrayOfDicts.push({});
      }
      arrayOfDicts[iEl][key] = dictOfArrays[key];
    }
  }

  return arrayOfDicts;
}

function upperCaseFirstLetter(string) {
  return (
    string.substring(0, 1).toUpperCase() + string.substring(1, string.length)
  );
}

function scrollTo(el, offsetTop = -52) {
  window.scrollTo({ behavior: "smooth", top: el.offsetTop + offsetTop });
}

function strCompare(a, b, caseInsensitive = true) {
  if (caseInsensitive) {
    a = a.toLowerCase();
    b = b.toLowerCase();
  }

  if (a < b) {
    return -1;
  }

  if (a > b) {
    return 1;
  }

  return 0;
}

function removeDuplicates(array, keyFunc = null) {
  const uniqueKeyVals = {};

  for (const el of array) {
    let key;
    if (keyFunc == null) {
      key = el;
    } else {
      key = keyFunc(el);
    }

    if (!(key in uniqueKeyVals)) {
      uniqueKeyVals[key] = el;
    }
  }

  return Object.values(uniqueKeyVals);
}

function downloadData(data, filename, mimeType) {
  const anchor = document.createElement("a");

  anchor.download = filename;

  const blob = new Blob([data], { type: mimeType });
  const url = URL.createObjectURL(blob);
  anchor.href = url;

  const clickHandler = () => {
    setTimeout(() => {
      URL.revokeObjectURL(url);
      anchor.removeEventListener("click", clickHandler);
    }, 150);
  };
  anchor.addEventListener("click", clickHandler, false);

  anchor.click();
}

function parseHistoryLocationPathname(history) {
  const pathRegex = /^(\/(.*?)(\/(.*?)(\/(.*?))?)?)?\/?$/;
  const match = history.location.pathname.match(pathRegex);
  let route = null;
  let query = null;
  let organism = null;
  if (match) {
    route = match[2];
    query = match[4] ? decodeURIComponent(match[4].trim()) || null : null;
    organism = match[6] ? decodeURIComponent(match[6].trim()) || null : null;
  }
  if (typeof organism === "string" && organism.toLowerCase() === "null") {
    organism = null;
  }
  return {
    route: route,
    query: query,
    organism: organism,
  };
}

function getNumProperties(obj) {
  let size = 0;
  for (const key in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
      size++;
    }
  }
  return size;
}

function castToArray(obj) {
  if (Array.isArray(obj)) {
    return obj;
  } else {
    if (obj == null || obj === undefined) {
      return [];
    } else {
      return [obj];
    }
  }
}

function numberWithCommas(x) {
  return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}

function isEmpty(element) {
  if (element instanceof Array) {
    if (element.length === 0) {
      return true;
    }
  } else {
    if (Object.keys(element).length === 0) {
      return true;
    }
  }
  return false;
}

function naturalSort(a, b) {
  return a.localeCompare(b, navigator.languages[0] || navigator.language, {
    caseFirst: "lower",
    numeric: true,
    ignorePunctuation: false,
  });
}

function isOrthoDbId(id) {
  return id.match(/^\d/i) != null;
}

function isUniProtId(id) {
  return (
    id.match(
      /^([A-N,R-Z][0-9]([A-Z][A-Z, 0-9][A-Z, 0-9][0-9]){1,2})|([O,P,Q][0-9][A-Z, 0-9][A-Z, 0-9][A-Z, 0-9][0-9])(\.\d+)?$/
    ) != null
  );
}

function replaceNanWithNull(value) {
  if (Number.isNaN(value)) {
    return null;
  }

  if (
    value != null &&
    value !== undefined &&
    (Array.isArray(value) || value.constructor === Object)
  ) {
    const toReplace = [value];
    while (toReplace.length) {
      const val = toReplace.pop();

      if (Array.isArray(val)) {
        for (let i = 0; i < val.length; i++) {
          const v = val[i];
          if (Number.isNaN(v)) {
            val[i] = null;
          } else if (
            v != null &&
            v !== undefined &&
            (Array.isArray(v) || v.constructor === Object)
          ) {
            toReplace.push(v);
          }
        }
      } else if (Object.keys(val).length) {
        for (const key in val) {
          const v = val[key];
          if (Number.isNaN(v)) {
            val[key] = null;
          } else if (
            v != null &&
            v !== undefined &&
            (Array.isArray(v) || v.constructor === Object)
          ) {
            toReplace.push(v);
          }
        }
      }
    }
  }

  return value;
}

const httpRequestLog = [];

const isiOS =
  [
    "iPad Simulator",
    "iPhone Simulator",
    "iPod Simulator",
    "iPad",
    "iPhone",
    "iPod",
  ].includes(navigator.platform) ||
  // iPad on iOS 13 detection
  (navigator.userAgent.includes("Mac") && "ontouchend" in document);

export {
  formatScientificNotation,
  formatChemicalFormula,
  dictOfArraysToArrayOfDicts,
  upperCaseFirstLetter,
  scrollTo,
  strCompare,
  removeDuplicates,
  downloadData,
  parseHistoryLocationPathname,
  getNumProperties,
  castToArray,
  numberWithCommas,
  isEmpty,
  naturalSort,
  isOrthoDbId,
  isUniProtId,
  replaceNanWithNull,
  httpRequestLog,
  isiOS,
};