UNPKG

bootstrap-vue

Version:

Quickly integrate Bootstrap 4 components with Vue.js

230 lines (203 loc) 7.13 kB
import { from as arrayFrom } from './array'; // Determine if an element is an HTML Element export const isElement = el => { return el && el.nodeType === Node.ELEMENT_NODE; }; // Determine if an HTML element is visible - Faster than CSS check export const isVisible = el => { return isElement(el) && document.body.contains(el) && el.getBoundingClientRect().height > 0 && el.getBoundingClientRect().width > 0 }; // Determine if an element is disabled export const 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 const 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 const selectAll = (selector, root) => { if (!isElement(root)) { root = document; } return arrayFrom(root.querySelectorAll(selector)); }; // Select a single element, returns null if not found export const select = (selector, root) => { if (!isElement(root)) { root = document; } return root.querySelector(selector) || null; }; // Determine if an element matches a selector export const 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 const proto = Element.prototype; const Matches = proto.matches || proto.matchesSelector || proto.mozMatchesSelector || proto.msMatchesSelector || proto.oMatchesSelector || proto.webkitMatchesSelector || function(sel) { const element = this; const m = selectAll(sel, element.document || element.ownerDocument); let 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 const 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 const Closest = Element.prototype.closest || function(sel) { let 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; }; const 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 const getById = id => { return document.getElementById(/^#/.test(id) ? id.slice(1) : id) || null; }; // Add a class to an element export const addClass = (el, className) => { if (className && isElement(el)) { el.classList.add(className); } }; // Remove a class from an element export const removeClass = (el, className) => { if (className && isElement(el)) { el.classList.remove(className); } }; // Test if an element has a class export const hasClass = (el, className) => { if (className && isElement(el)) { return el.classList.contains(className); } return false; }; // Set an attribute on an element export const setAttr = (el, attr, value) => { if (attr && isElement(el)) { el.setAttribute(attr, value); } }; // Remove an attribute from an element export const removeAttr = (el, attr) => { if (attr && isElement(el)) { el.removeAttribute(attr); } }; // Get an attribute value from an element (returns null if not found) export const 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 const 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 const getBCR = el => { return isElement(el) ? el.getBoundingClientRect() : null; }; // Get computed style object for an element export const 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 const offset = el => { if (isElement(el)) { if (!el.getClientRects().length) { return { top: 0, left: 0 }; } const bcr = getBCR(el); const 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 const position = el => { if (!isElement(el)) { return; } let parentOffset = { top: 0, left: 0 }; let offsetSelf; let offsetParent; if (getCS(el).position === 'fixed') { offsetSelf = getBCR(el); } else { offsetSelf = offset(el); const 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 const eventOn = (el, evtName, handler) => { if (el && el.addEventListener) { el.addEventListener(evtName, handler); } }; // Remove an event listener from an element export const eventOff = (el, evtName, handler) => { if (el && el.removeEventListener) { el.removeEventListener(evtName, handler); } };