bootstrap-vue
Version:
BootstrapVue provides one of the most comprehensive implementations of Bootstrap 4 components and grid system for Vue.js and with extensive and automated WAI-ARIA accessibility markup.
229 lines (201 loc) • 6.38 kB
JavaScript
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
import { assign, keys } from '../../utils/object';
import { arrayIncludes, concat } from '../../utils/array';
import { mergeData } from 'vue-functional-data-merge';
/**
* The Link component is used in many other BV components.
* As such, sharing its props makes supporting all its features easier.
* However, some components need to modify the defaults for their own purpose.
* Prefer sharing a fresh copy of the props to ensure mutations
* do not affect other component references to the props.
*
* https://github.com/vuejs/vue-router/blob/dev/src/components/link.js
* @return {{}}
*/
export function propsFactory() {
return {
href: {
type: String,
default: null
},
rel: {
type: String,
default: null
},
target: {
type: String,
default: '_self'
},
active: {
type: Boolean,
default: false
},
activeClass: {
type: String,
default: 'active'
},
append: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
},
event: {
type: [String, Array],
default: 'click'
},
exact: {
type: Boolean,
default: false
},
exactActiveClass: {
type: String,
default: 'active'
},
replace: {
type: Boolean,
default: false
},
routerTag: {
type: String,
default: 'a'
},
to: {
type: [String, Object],
default: null
}
};
}
export var props = propsFactory();
export function pickLinkProps(propsToPick) {
var freshLinkProps = propsFactory();
// Normalize everything to array.
propsToPick = concat(propsToPick);
return keys(freshLinkProps).reduce(function (memo, prop) {
if (arrayIncludes(propsToPick, prop)) {
memo[prop] = freshLinkProps[prop];
}
return memo;
}, {});
}
export function omitLinkProps(propsToOmit) {
var freshLinkProps = propsFactory();
// Normalize everything to array.
propsToOmit = concat(propsToOmit);
return keys(props).reduce(function (memo, prop) {
if (!arrayIncludes(propsToOmit, prop)) {
memo[prop] = freshLinkProps[prop];
}
return memo;
}, {});
}
export var computed = {
linkProps: function linkProps() {
var linkProps = {};
var propKeys = keys(props);
for (var i = 0; i < propKeys.length; i++) {
var prop = propKeys[i];
// Computed Vue getters are bound to the instance.
linkProps[prop] = this[prop];
}
return linkProps;
}
};
function computeTag(props, parent) {
return Boolean(parent.$router) && props.to && !props.disabled ? 'router-link' : 'a';
}
function computeHref(_ref, tag) {
var disabled = _ref.disabled,
href = _ref.href,
to = _ref.to;
// We've already checked the parent.$router in computeTag,
// so router-link means live router.
// When deferring to Vue Router's router-link,
// don't use the href attr at all.
// Must return undefined for router-link to populate href.
if (tag === 'router-link') return void 0;
// If href 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 (typeof to === 'string') return to;
// Fallback to `to.path` prop (if `to` is an object)
if ((typeof to === 'undefined' ? 'undefined' : _typeof(to)) === 'object' && typeof to.path === 'string') return to.path;
}
// If nothing is provided use '#'
return '#';
}
function computeRel(_ref2) {
var target = _ref2.target,
rel = _ref2.rel;
if (target === '_blank' && rel === null) {
return 'noopener';
}
return rel || null;
}
function clickHandlerFactory(_ref3) {
var disabled = _ref3.disabled,
tag = _ref3.tag,
href = _ref3.href,
suppliedHandler = _ref3.suppliedHandler,
parent = _ref3.parent;
var isRouterLink = tag === 'router-link';
return function onClick(e) {
if (disabled && e instanceof Event) {
// Stop event from bubbling up.
e.stopPropagation();
// Kill the event loop attached to this specific EventTarget.
e.stopImmediatePropagation();
} else {
parent.$root.$emit('clicked::link', e);
if (isRouterLink && e.target.__vue__) {
e.target.__vue__.$emit('click', e);
}
if (typeof suppliedHandler === 'function') {
suppliedHandler.apply(undefined, arguments);
}
}
if (!isRouterLink && href === '#' || disabled) {
// Stop scroll-to-top behavior or navigation.
e.preventDefault();
}
};
}
export default {
functional: true,
props: propsFactory(),
render: function render(h, _ref4) {
var props = _ref4.props,
data = _ref4.data,
parent = _ref4.parent,
children = _ref4.children;
var tag = computeTag(props, parent);
var rel = computeRel(props);
var href = computeHref(props, tag);
var eventType = tag === 'router-link' ? 'nativeOn' : 'on';
var suppliedHandler = (data[eventType] || {}).click;
var handlers = { click: clickHandlerFactory({ tag: tag, href: href, disabled: props.disabled, suppliedHandler: suppliedHandler, parent: parent }) };
var componentData = mergeData(data, {
class: [props.active ? props.exact ? props.exactActiveClass : props.activeClass : null, { disabled: props.disabled }],
attrs: {
rel: rel,
href: href,
target: props.target,
tabindex: props.disabled ? '-1' : data.attrs ? data.attrs.tabindex : null,
'aria-disabled': tag === 'a' && props.disabled ? 'true' : null
},
props: assign(props, { tag: props.routerTag })
});
// If href prop exists on router-link (even undefined or null) it fails working on SSR
if (!componentData.attrs.href) {
delete componentData.attrs.href;
}
// We want to overwrite any click handler since our callback
// will invoke the supplied handler if !props.disabled
componentData[eventType] = assign(componentData[eventType] || {}, handlers);
return h(tag, componentData, children);
}
};