custom-bootstrap-vue
Version:
Custom version of bootstrap-vue created for providing specific theme to a particular project
156 lines (133 loc) • 4.62 kB
JavaScript
import { isTag } from './dom'
import { isArray, isNull, isPlainObject, isString, isUndefined } from './inspect'
import { keys } from './object'
import { toString } from './string'
const ANCHOR_TAG = 'a'
// Precompile RegExp
const commaRE = /%2C/g
const encodeReserveRE = /[!'()*]/g
const plusRE = /\+/g
const queryStartRE = /^(\?|#|&)/
// Method to replace reserved chars
const encodeReserveReplacer = c => '%' + c.charCodeAt(0).toString(16)
// Fixed encodeURIComponent which is more conformant to RFC3986:
// - escapes [!'()*]
// - preserve commas
const encode = str =>
encodeURIComponent(toString(str))
.replace(encodeReserveRE, encodeReserveReplacer)
.replace(commaRE, ',')
const decode = decodeURIComponent
// Stringifies an object of query parameters
// See: https://github.com/vuejs/vue-router/blob/dev/src/util/query.js
export const stringifyQueryObj = obj => {
if (!isPlainObject(obj)) {
return ''
}
const query = keys(obj)
.map(key => {
const val = obj[key]
if (isUndefined(val)) {
return ''
} else if (isNull(val)) {
return encode(key)
} else if (isArray(val)) {
return val
.reduce((results, val2) => {
if (isNull(val2)) {
results.push(encode(key))
} else if (!isUndefined(val2)) {
// Faster than string interpolation
results.push(encode(key) + '=' + encode(val2))
}
return results
}, [])
.join('&')
}
// Faster than string interpolation
return encode(key) + '=' + encode(val)
})
/* must check for length, as we only want to filter empty strings, not things that look falsey! */
.filter(x => x.length > 0)
.join('&')
return query ? `?${query}` : ''
}
export const parseQuery = query => {
const parsed = {}
query = toString(query)
.trim()
.replace(queryStartRE, '')
if (!query) {
return parsed
}
query.split('&').forEach(param => {
const parts = param.replace(plusRE, ' ').split('=')
const key = decode(parts.shift())
const val = parts.length > 0 ? decode(parts.join('=')) : null
if (isUndefined(parsed[key])) {
parsed[key] = val
} else if (isArray(parsed[key])) {
parsed[key].push(val)
} else {
parsed[key] = [parsed[key], val]
}
})
return parsed
}
export const isLink = props => !!(props.href || props.to)
export const isRouterLink = tag => !isTag(tag, ANCHOR_TAG)
export const computeTag = ({ to, disabled, routerComponentName } = {}, thisOrParent) => {
const hasRouter = thisOrParent.$router
if (!hasRouter || (hasRouter && disabled) || (hasRouter && !to)) {
return ANCHOR_TAG
}
// TODO:
// Check registered components for existence of user supplied router link component name
// We would need to check PascalCase, kebab-case, and camelCase versions of name:
// const name = routerComponentName
// const names = [name, PascalCase(name), KebabCase(name), CamelCase(name)]
// exists = names.some(name => !!thisOrParent.$options.components[name])
// And may want to cache the result for performance or we just let the render fail
// if the component is not registered
return routerComponentName || (thisOrParent.$nuxt ? 'nuxt-link' : 'router-link')
}
export const computeRel = ({ target, rel } = {}) => {
if (target === '_blank' && isNull(rel)) {
return 'noopener'
}
return rel || null
}
export const computeHref = (
{ href, to } = {},
tag = ANCHOR_TAG,
fallback = '#',
toFallback = '/'
) => {
// We've already checked the $router in computeTag(), so isRouterLink() indicates a live router.
// When deferring to Vue Router's router-link, don't use the href attribute at all.
// We return null, and then remove href from the attributes passed to router-link
if (isRouterLink(tag)) {
return null
}
// Return `href` when explicitly provided
if (href) {
return href
}
// Reconstruct `href` when `to` used, but no router
if (to) {
// Fallback to `to` prop (if `to` is a string)
if (isString(to)) {
return to || toFallback
}
// Fallback to `to.path + to.query + to.hash` prop (if `to` is an object)
if (isPlainObject(to) && (to.path || to.query || to.hash)) {
const path = toString(to.path)
const query = stringifyQueryObj(to.query)
let hash = toString(to.hash)
hash = !hash || hash.charAt(0) === '#' ? hash : `#${hash}`
return `${path}${query}${hash}` || toFallback
}
}
// If nothing is provided return the fallback
return fallback
}