bd-core
Version:
a JavaScript library for building browser-hosted user interfaces
332 lines (303 loc) • 9.44 kB
JavaScript
import {adviseGlobal} from './global.js';
let window = 0;
let document = 0;
adviseGlobal(global => {
window = global;
document = window.document;
});
function getAttributeValueFromEvent(e, attributeName, stopNode) {
let node = e.target;
while (node && node !== stopNode) {
if (node.getAttributeNode(attributeName)) {
return node.getAttribute(attributeName);
}
node = node.parentNode;
}
return undefined;
}
function setAttr(node, name, value) {
if (arguments.length === 2) {
// name is a hash
Object.keys(name).forEach(n => setAttr(node, n, name[n]));
} else if (name === 'style') {
setStyle(node, value);
} else if (name === 'innerHTML' || (name in node && node instanceof HTMLElement)) {
node[name] = value;
} else {
node.setAttribute(name, value);
}
}
function getAttr(node, name) {
if (name in node && node instanceof HTMLElement) {
return node[name];
} else {
return node.getAttribute(name);
}
}
let lastComputedStyleNode = 0;
let lastComputedStyle = 0;
function getComputedStyle(node) {
if (lastComputedStyleNode !== node) {
lastComputedStyle = window.getComputedStyle((lastComputedStyleNode = node));
}
return lastComputedStyle;
}
function getStyle(node, property) {
if (lastComputedStyleNode !== node) {
lastComputedStyle = window.getComputedStyle((lastComputedStyleNode = node));
}
const result = lastComputedStyle[property];
return (typeof result === 'string' && /px$/.test(result)) ? parseFloat(result) : result;
}
function getStyles(node, ...styleNames) {
if (lastComputedStyleNode !== node) {
lastComputedStyle = window.getComputedStyle((lastComputedStyleNode = node));
}
let styles = [];
styleNames.forEach(styleName => {
if (Array.isArray(styleName)) {
styles = styles.concat(styleName);
} else if (typeof styleName === 'string') {
styles.push(styleName);
} else {
// styleName is a hash
Object.keys(styleName).forEach(p => styles.push(p));
}
});
const result = {};
styles.forEach(property => {
const value = lastComputedStyle[property];
result[property] = (typeof value === 'string' && /px$/.test(value)) ? parseFloat(value) : value;
});
return result;
}
function setStyle(node, property, value) {
if (arguments.length === 2) {
if (typeof property === 'string') {
node.style = property;
} else {
// property is a hash
Object.keys(property).forEach(p => {
node.style[p] = property[p];
});
}
} else {
node.style[property] = value;
}
}
function getPosit(node) {
const result = node.getBoundingClientRect();
result.t = result.top;
result.b = result.bottom;
result.l = result.left;
result.r = result.right;
result.h = result.height;
result.w = result.width;
return result;
}
function positStyle(v) {
return v === false ? '' : `${v}px`;
}
function setPosit(node, posit) {
// eslint-disable-next-line guard-for-in,no-restricted-syntax
Object.keys(posit).forEach(p => {
switch (p) {
case 't':
node.style.top = positStyle(posit.t);
break;
case 'b':
node.style.bottom = positStyle(posit.b);
break;
case 'l':
node.style.left = positStyle(posit.l);
break;
case 'r':
node.style.right = positStyle(posit.r);
break;
case 'h':
node.style.height = positStyle(posit.h);
break;
case 'w':
node.style.width = positStyle(posit.w);
break;
case 'maxH':
node.style.maxHeight = positStyle(posit.maxH);
break;
case 'maxW':
node.style.maxWidth = positStyle(posit.maxW);
break;
case 'minH':
node.style.minHeight = positStyle(posit.minH);
break;
case 'minW':
node.style.minWidth = positStyle(posit.minW);
break;
case 'z':
node.style.zIndex = posit.z === false ? '' : posit.z;
break;
default:
// ignore...this allows clients to stuff other properties into posit for other reasons
}
});
}
function insertBefore(node, refNode) {
refNode.parentNode.insertBefore(node, refNode);
}
function insertAfter(node, refNode) {
const parent = refNode.parentNode;
if (parent.lastChild === refNode) {
parent.appendChild(node);
} else {
parent.insertBefore(node, refNode.nextSibling);
}
}
function insert(node, refNode, position) {
if (position === undefined || position === 'last') {
// short circuit the common case
refNode.appendChild(node);
} else {
switch (position) {
case 'before':
insertBefore(node, refNode);
break;
case 'after':
insertAfter(node, refNode);
break;
case 'replace':
refNode.parentNode.replaceChild(node, refNode);
return (refNode);
case 'only': {
const result = [];
while (refNode.firstChild) {
result.push(refNode.removeChild(refNode.firstChild));
}
refNode.appendChild(node);
return result;
}
case 'first':
if (refNode.firstChild) {
insertBefore(node, refNode.firstChild);
} else {
refNode.appendChild(node);
}
break;
default:
if (typeof position === 'number') {
const children = refNode.childNodes;
if (!children.length || children.length <= position) {
refNode.appendChild(node);
} else {
insertBefore(node, children[position < 0 ? Math.max(0, children.length + position) : position]);
}
} else {
throw new Error('illegal position');
}
}
}
return 0;
}
function create(tag, props) {
const result = Array.isArray(tag) ? document.createElementNS(`${tag[0]}`, tag[1]) : document.createElement(tag);
if (props) {
Reflect.ownKeys(props).forEach(p => setAttr(result, p, props[p]));
}
return result;
}
const DATA_BD_HIDE_SAVED_VALUE = 'data-bd-hide-saved-value';
function hide(...nodes) {
nodes.forEach(node => {
if (node) {
if (!node.hasAttribute(DATA_BD_HIDE_SAVED_VALUE)) {
node.setAttribute(DATA_BD_HIDE_SAVED_VALUE, node.style.display);
node.style.display = 'none';
}// else, ignore, multiple calls to hide
}
});
}
function show(...nodes) {
nodes.forEach(node => {
if (node) {
let displayValue = '';
if (node.hasAttribute(DATA_BD_HIDE_SAVED_VALUE)) {
displayValue = node.getAttribute(DATA_BD_HIDE_SAVED_VALUE);
node.removeAttribute(DATA_BD_HIDE_SAVED_VALUE);
}
node.style.display = displayValue;
}
});
}
function getMaxZIndex(parent) {
const children = parent.childNodes;
const end = children.length;
let node,
cs,
max = 0,
i = 0;
while (i < end) {
node = children[i++];
cs = node && node.nodeType === 1 && getComputedStyle(node);
max = Math.max(max, (cs && cs.zIndex && Number(cs.zIndex)) || 0);
}
return max;
}
function destroyDomChildren(node) {
let childNode;
while ((childNode = node.lastChild)) {
node.removeChild(childNode);
}
}
function destroyDomNode(node) {
node && node.parentNode && node.parentNode.removeChild(node);
}
function connect(target, type, listener, useCapture) {
let destroyed = false;
useCapture = !!useCapture;
target.addEventListener(type, listener, useCapture);
return {
destroy() {
if (!destroyed) {
destroyed = true;
target.removeEventListener(type, listener, useCapture);
}
}
};
}
function stopEvent(event) {
if (event && event.preventDefault) {
event.preventDefault();
event.stopPropagation();
}
}
function animate(node, className, onComplete) {
const h = connect(node, 'animationend', e => {
if (e.animationName === className) {
h.destroy();
node.classList.remove(className);
if (onComplete) {
onComplete.destroy ? onComplete.destroy() : onComplete();
}
}
});
node.classList.add(className);
}
export {
getAttributeValueFromEvent,
setAttr,
getAttr,
getComputedStyle,
getStyle,
getStyles,
setStyle,
setPosit,
create,
insert,
hide,
show,
getPosit,
getMaxZIndex,
destroyDomChildren,
destroyDomNode,
connect,
animate,
stopEvent
};