Skip to content

Instantly share code, notes, and snippets.

@bonniss
Last active October 24, 2020 10:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bonniss/f9e6af9032f820398148aaaadd17457b to your computer and use it in GitHub Desktop.
Save bonniss/f9e6af9032f820398148aaaadd17457b to your computer and use it in GitHub Desktop.
Useful snippets in Javascript for up and running project. @link: https://github.com/bootstrap-vue/bootstrap-vue/tree/dev/src/utils
// @link: https://github.com/bootstrap-vue/bootstrap-vue/blob/dev/src/utils/array.js
const from = (...args) => Array.from(...args)
const isArray = val => Array.isArray(val)
const arrayIncludes = (array, value) => array.indexOf(value) !== -1
const concat = (...args) => Array.prototype.concat.apply([], args)
export const createAndFillArray = (size, value) => Array(size).fill(value)
/**
* Utilities to get information about the current environment
*/
// --- Constants ---
export const hasWindowSupport = typeof window !== 'undefined'
export const hasDocumentSupport = typeof document !== 'undefined'
export const hasNavigatorSupport = typeof navigator !== 'undefined'
export const hasPromiseSupport = typeof Promise !== 'undefined'
/* istanbul ignore next: JSDOM always returns false */
export const hasMutationObserverSupport =
typeof MutationObserver !== 'undefined' ||
typeof WebKitMutationObserver !== 'undefined' ||
typeof MozMutationObserver !== 'undefined'
export const isBrowser = hasWindowSupport && hasDocumentSupport && hasNavigatorSupport
// Browser type sniffing
export const userAgent = isBrowser ? window.navigator.userAgent.toLowerCase() : ''
export const isJSDOM = userAgent.indexOf('jsdom') > 0
export const isIE = /msie|trident/.test(userAgent)
// Determine if the browser supports the option passive for events
export const hasPassiveEventSupport = (() => {
let passiveEventSupported = false
if (isBrowser) {
try {
const options = {
get passive() {
// This function will be called when the browser
// attempts to access the passive property.
/* istanbul ignore next: will never be called in JSDOM */
passiveEventSupported = true
}
}
window.addEventListener('test', options, options)
window.removeEventListener('test', options, options)
} catch (err) {
/* istanbul ignore next: will never be called in JSDOM */
passiveEventSupported = false
}
}
return passiveEventSupported
})()
export const hasTouchSupport =
isBrowser && ('ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0)
export const hasPointerEventSupport =
isBrowser && Boolean(window.PointerEvent || window.MSPointerEvent)
/* istanbul ignore next: JSDOM only checks for 'IntersectionObserver' */
export const hasIntersectionObserverSupport =
isBrowser &&
'IntersectionObserver' in window &&
'IntersectionObserverEntry' in window &&
// Edge 15 and UC Browser lack support for `isIntersecting`
// but we an use intersectionRatio > 0 instead
// 'isIntersecting' in window.IntersectionObserverEntry.prototype &&
'intersectionRatio' in window.IntersectionObserverEntry.prototype
// --- Getters ---
export const getEnv = (key, fallback = null) => {
const env = typeof process !== 'undefined' && process ? process.env || {} : {}
if (!key) {
/* istanbul ignore next */
return env
}
return env[key] || fallback
}
import identity from './identity'
import { isArray, isNull, isObject, isUndefinedOrNull } from './inspect'
const RX_ARRAY_NOTATION = /\[(\d+)]/g
/**
* Get property defined by dot/array notation in string, returns undefined if not found
*
* @link https://gist.github.com/jeneg/9767afdcca45601ea44930ea03e0febf#gistcomment-1935901
*
* @param {Object} obj
* @param {string|Array} path
* @return {*}
*/
export const getRaw = (obj, path, defaultValue = undefined) => {
// Handle array of path values
path = isArray(path) ? path.join('.') : path
// If no path or no object passed
if (!path || !isObject(obj)) {
return defaultValue
}
// Handle edge case where user has dot(s) in top-level item field key
// See https://github.com/bootstrap-vue/bootstrap-vue/issues/2762
// Switched to `in` operator vs `hasOwnProperty` to handle obj.prototype getters
// https://github.com/bootstrap-vue/bootstrap-vue/issues/3463
if (path in obj) {
return obj[path]
}
// Handle string array notation (numeric indices only)
path = String(path).replace(RX_ARRAY_NOTATION, '.$1')
const steps = path.split('.').filter(identity)
// Handle case where someone passes a string of only dots
if (steps.length === 0) {
return defaultValue
}
// Traverse path in object to find result
// Switched to `in` operator vs `hasOwnProperty` to handle obj.prototype getters
// https://github.com/bootstrap-vue/bootstrap-vue/issues/3463
return steps.every(step => isObject(obj) && step in obj && !isUndefinedOrNull((obj = obj[step])))
? obj
: isNull(obj)
? null
: defaultValue
}
/**
* Get property defined by dot/array notation in string.
*
* @link https://gist.github.com/jeneg/9767afdcca45601ea44930ea03e0febf#gistcomment-1935901
*
* @param {Object} obj
* @param {string|Array} path
* @param {*} defaultValue (optional)
* @return {*}
*/
export const get = (obj, path, defaultValue = null) => {
const val = getRaw(obj, path)
return isUndefinedOrNull(val) ? defaultValue : val
}
export default get
/* @link: https://github.com/bootstrap-vue/bootstrap-vue/blob/dev/src/utils/html.js */
const RX_HTML_TAGS = /(<([^>]+)>)/gi
// Removes anything that looks like an HTML tag from the supplied string
export const stripTags = (text = '') => String(text).replace(RX_HTML_TAGS, '')
/* https://github.com/bootstrap-vue/bootstrap-vue/blob/dev/src/utils/math.js */
export const mathMin = Math.min
export const mathMax = Math.max
export const mathAbs = Math.abs
export const mathCeil = Math.ceil
export const mathFloor = Math.floor
export const mathPow = Math.pow
export const mathRound = Math.round
const noop = () => {}
export default noop
/* @link: https://github.com/bootstrap-vue/bootstrap-vue/blob/dev/src/utils/number.js */
// Converts a value (string, number, etc) to an integer number
// Assumes radix base 10
export const toInteger = (value, defaultValue = NaN) => {
const integer = parseInt(value, 10)
return isNaN(integer) ? defaultValue : integer
}
// Converts a value (string, number, etc) to a number
export const toFloat = (value, defaultValue = NaN) => {
const float = parseFloat(value)
return isNaN(float) ? defaultValue : float
}
// Converts a value (string, number, etc) to a string
// representation with `precision` digits after the decimal
// Returns the string 'NaN' if the value cannot be converted
export const toFixed = (val, precision) => toFloat(val).toFixed(toInteger(precision, 0))
// @link: https://github.com/bootstrap-vue/bootstrap-vue/blob/dev/src/utils/object.js
const isObject = obj => obj !== null && typeof obj === 'object'
const isPlainObject = obj => Object.prototype.toString.call(obj) === '[object Object]'
const keys = obj => Object.keys(obj)
const toString = obj => Object.prototype.toString.call(obj)
/**
* Return a shallow copy of object with the specified properties only
* @link https://gist.github.com/bisubus/2da8af7e801ffd813fab7ac221aa7afc
*/
export const pick = (obj, props) =>
keys(obj)
.filter(key => props.indexOf(key) !== -1)
.reduce((result, key) => ({ ...result, [key]: obj[key] }), {})
/**
* Return a shallow copy of object with the specified properties omitted
* @link https://gist.github.com/bisubus/2da8af7e801ffd813fab7ac221aa7afc
*/
export const omit = (obj, props) =>
keys(obj)
.filter(key => props.indexOf(key) === -1)
.reduce((result, key) => ({ ...result, [key]: obj[key] }), {})
/**
* Shallow copy an object. If the passed in object
* is null or undefined, returns an empty object
*/
export const clone = obj => ({ ...obj })
const RX_URL = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/;
/*
* Consistent and stable sort function across JavaScript platforms
*
* Inconsistent sorts can cause SSR problems between client and server
* such as in <b-table> if sortBy is applied to the data on server side render.
* Chrome and V8 native sorts are inconsistent/unstable
*
* This function uses native sort with fallback to index compare when the a and b
* compare returns 0
*
* Algorithm based on:
* https://stackoverflow.com/questions/1427608/fast-stable-sorting-algorithm-implementation-in-javascript/45422645#45422645
*
* @param {array} array to sort
* @param {function} sort compare function
* @return {array}
*/
const stableSort = (array, compareFn) => {
// Using `.bind(compareFn)` on the wrapped anonymous function improves
// performance by avoiding the function call setup. We don't use an arrow
// function here as it binds `this` to the `stableSort` context rather than
// the `compareFn` context, which wouldn't give us the performance increase.
return array
.map((a, index) => [index, a])
.sort(
function(a, b) {
return this(a[1], b[1]) || a[0] - b[0]
}.bind(compareFn)
)
.map(e => e[1])
}
/* @link: https://github.com/bootstrap-vue/bootstrap-vue/blob/dev/src/utils/string.js */
// String utilities
import { isArray, isPlainObject, isString, isUndefinedOrNull } from './inspect'
// --- Constants ---
const RX_TRIM_LEFT = /^\s+/
const RX_TRIM_RIGHT = /\s+$/
const RX_REGEXP_REPLACE = /[-/\\^$*+?.()|[\]{}]/g
const RX_UN_KEBAB = /-(\w)/g
const RX_HYPHENATE = /\B([A-Z])/g
// --- Utilities ---
// Converts PascalCase or camelCase to kebab-case
export const kebabCase = str => {
return str.replace(RX_HYPHENATE, '-$1').toLowerCase()
}
// Converts a kebab-case or camelCase string to PascalCase
export const pascalCase = str => {
str = kebabCase(str).replace(RX_UN_KEBAB, (_, c) => (c ? c.toUpperCase() : ''))
return str.charAt(0).toUpperCase() + str.slice(1)
}
// Lowercases the first letter of a string and returns a new string
export const lowerFirst = str => {
str = isString(str) ? str.trim() : String(str)
return str.charAt(0).toLowerCase() + str.slice(1)
}
// Uppercases the first letter of a string and returns a new string
export const upperFirst = str => {
str = isString(str) ? str.trim() : String(str)
return str.charAt(0).toUpperCase() + str.slice(1)
}
// Escape characters to be used in building a regular expression
export const escapeRegExp = str => str.replace(RX_REGEXP_REPLACE, '\\$&')
// Convert a value to a string that can be rendered
// `undefined`/`null` will be converted to `''`
// Plain objects and arrays will be JSON stringified
export const toString = (val, spaces = 2) => {
return isUndefinedOrNull(val)
? ''
: isArray(val) || (isPlainObject(val) && val.toString === Object.prototype.toString)
? JSON.stringify(val, null, spaces)
: String(val)
}
// Remove leading white space from a string
export const trimLeft = str => toString(str).replace(RX_TRIM_LEFT, '')
// Remove Trailing white space from a string
export const trimRight = str => toString(str).replace(RX_TRIM_RIGHT, '')
// Remove leading and trailing white space from a string
export const trim = str => toString(str).trim()
// Lower case a string
export const lowerCase = str => toString(str).toLowerCase()
// Upper case a string
export const upperCase = str => toString(str).toUpperCase()
/* @link: https://github.com/bootstrap-vue/bootstrap-vue/blob/dev/src/utils/inspect.js */
import { isArray } from './array'
import { isObject, isPlainObject } from './object'
import { File } from './safe-types'
// --- Convenience inspection utilities ---
export const toType = val => typeof val
export const toRawType = val => Object.prototype.toString.call(val).slice(8, -1)
export const toRawTypeLC = val => toRawType(val).toLowerCase()
export const isUndefined = val => val === undefined
export const isNull = val => val === null
export const isEmptyString = val => val === ''
export const isUndefinedOrNull = val => isUndefined(val) || isNull(val)
export const isUndefinedOrNullOrEmpty = val => isUndefinedOrNull(val) || isEmptyString(val)
export const isFunction = val => toType(val) === 'function'
export const isBoolean = val => toType(val) === 'boolean'
export const isString = val => toType(val) === 'string'
export const isNumber = val => toType(val) === 'number'
export const isPrimitive = val => isBoolean(val) || isString(val) || isNumber(val)
export const isDate = val => val instanceof Date
export const isEvent = val => val instanceof Event
export const isFile = val => val instanceof File
export const isRegExp = val => toRawType(val) === 'RegExp'
export const isPromise = val =>
!isUndefinedOrNull(val) && isFunction(val.then) && isFunction(val.catch)
// Extra convenience named re-exports
export { isArray, isObject, isPlainObject }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment