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.
219 lines (193 loc) • 6.91 kB
JavaScript
import { from as arrayFrom } from './array';
// Determine if an element is an HTML Element
export var isElement = function isElement(el) {
return el && el.nodeType === Node.ELEMENT_NODE;
};
// Determine if an HTML element is visible - Faster than CSS check
export var isVisible = function isVisible(el) {
return isElement(el) && document.body.contains(el) && el.getBoundingClientRect().height > 0 && el.getBoundingClientRect().width > 0;
};
// Determine if an element is disabled
export var isDisabled = function isDisabled(el) {
return !isElement(el) || el.disabled || el.classList.contains('disabled') || Boolean(el.getAttribute('disabled'));
};
// Cause/wait-for an element to reflow it's content (adjusting it's height/width)
export var reflow = function reflow(el) {
// requsting an elements offsetHight will trigger a reflow of the element content
return isElement(el) && el.offsetHeight;
};
// Select all elements matching selector. Returns [] if none found
export var selectAll = function selectAll(selector, root) {
if (!isElement(root)) {
root = document;
}
return arrayFrom(root.querySelectorAll(selector));
};
// Select a single element, returns null if not found
export var select = function select(selector, root) {
if (!isElement(root)) {
root = document;
}
return root.querySelector(selector) || null;
};
// Determine if an element matches a selector
export var matches = function matches(el, selector) {
if (!isElement(el)) {
return false;
}
// https://developer.mozilla.org/en-US/docs/Web/API/Element/matches#Polyfill
// Prefer native implementations over polyfill function
var proto = Element.prototype;
var Matches = proto.matches || proto.matchesSelector || proto.mozMatchesSelector || proto.msMatchesSelector || proto.oMatchesSelector || proto.webkitMatchesSelector ||
/* istanbul ignore next */
function (sel) {
var element = this;
var m = selectAll(sel, element.document || element.ownerDocument);
var i = m.length;
// eslint-disable-next-line no-empty
while (--i >= 0 && m.item(i) !== element) {}
return i > -1;
};
return Matches.call(el, selector);
};
// Finds closest element matching selector. Returns null if not found
export var closest = function closest(selector, root) {
if (!isElement(root)) {
return null;
}
// https://developer.mozilla.org/en-US/docs/Web/API/Element/closest
// Since we dont support IE < 10, we can use the "Matches" version of the polyfill for speed
// Prefer native implementation over polyfill function
var Closest = Element.prototype.closest ||
/* istanbul ignore next */
function (sel) {
var element = this;
if (!document.documentElement.contains(element)) {
return null;
}
do {
// Use our "patched" matches function
if (matches(element, sel)) {
return element;
}
element = element.parentElement;
} while (element !== null);
return null;
};
var el = Closest.call(root, selector);
// Emulate jQuery closest and return null if match is the passed in element (root)
return el === root ? null : el;
};
// Get an element given an ID
export var getById = function getById(id) {
return document.getElementById(/^#/.test(id) ? id.slice(1) : id) || null;
};
// Add a class to an element
export var addClass = function addClass(el, className) {
if (className && isElement(el)) {
el.classList.add(className);
}
};
// Remove a class from an element
export var removeClass = function removeClass(el, className) {
if (className && isElement(el)) {
el.classList.remove(className);
}
};
// Test if an element has a class
export var hasClass = function hasClass(el, className) {
if (className && isElement(el)) {
return el.classList.contains(className);
}
return false;
};
// Set an attribute on an element
export var setAttr = function setAttr(el, attr, value) {
if (attr && isElement(el)) {
el.setAttribute(attr, value);
}
};
// Remove an attribute from an element
export var removeAttr = function removeAttr(el, attr) {
if (attr && isElement(el)) {
el.removeAttribute(attr);
}
};
// Get an attribute value from an element (returns null if not found)
export var getAttr = function getAttr(el, attr) {
if (attr && isElement(el)) {
return el.getAttribute(attr);
}
return null;
};
// Determine if an attribute exists on an element (returns true or false, or null if element not found)
export var hasAttr = function hasAttr(el, attr) {
if (attr && isElement(el)) {
return el.hasAttribute(attr);
}
return null;
};
// Return the Bounding Client Rec of an element. Retruns null if not an element
export var getBCR = function getBCR(el) {
return isElement(el) ? el.getBoundingClientRect() : null;
};
// Get computed style object for an element
export var getCS = function getCS(el) {
return isElement(el) ? window.getComputedStyle(el) : {};
};
// Return an element's offset wrt document element
// https://j11y.io/jquery/#v=git&fn=jQuery.fn.offset
export var offset = function offset(el) {
if (isElement(el)) {
if (!el.getClientRects().length) {
return { top: 0, left: 0 };
}
var bcr = getBCR(el);
var win = el.ownerDocument.defaultView;
return {
top: bcr.top + win.pageYOffset,
left: bcr.left + win.pageXOffset
};
}
};
// Return an element's offset wrt to it's offsetParent
// https://j11y.io/jquery/#v=git&fn=jQuery.fn.position
export var position = function position(el) {
if (!isElement(el)) {
return;
}
var parentOffset = { top: 0, left: 0 };
var offsetSelf = void 0;
var offsetParent = void 0;
if (getCS(el).position === 'fixed') {
offsetSelf = getBCR(el);
} else {
offsetSelf = offset(el);
var doc = el.ownerDocument;
offsetParent = el.offsetParent || doc.documentElement;
while (offsetParent && (offsetParent === doc.body || offsetParent === doc.documentElement) && getCS(offsetParent).position === 'static') {
offsetParent = offsetParent.parentNode;
}
if (offsetParent && offsetParent !== el && offsetParent.nodeType === Node.ELEMENT_NODE) {
parentOffset = offset(offsetParent);
parentOffset.top += parseFloat(getCS(offsetParent).borderTopWidth);
parentOffset.left += parseFloat(getCS(offsetParent).borderLeftWidth);
}
}
return {
top: offsetSelf.top - parentOffset.top - parseFloat(getCS(el).marginTop),
left: offsetSelf.left - parentOffset.left - parseFloat(getCS(el).marginLeft)
};
};
// Attach an event listener to an element
export var eventOn = function eventOn(el, evtName, handler) {
if (el && el.addEventListener) {
el.addEventListener(evtName, handler);
}
};
// Remove an event listener from an element
export var eventOff = function eventOff(el, evtName, handler) {
if (el && el.removeEventListener) {
el.removeEventListener(evtName, handler);
}
};