drapcode-builder
Version:
Drapcode Builder Library
251 lines (215 loc) • 5.53 kB
JavaScript
import { keys, isUndefined, isElement, isArray } from 'underscore';
const elProt = window.Element.prototype;
const matches =
elProt.matches ||
elProt.webkitMatchesSelector ||
elProt.mozMatchesSelector ||
elProt.msMatchesSelector;
/**
* Import styles asynchronously
* @param {String|Array<String>} styles
*/
const appendStyles = (styles, opts = {}) => {
const stls = isArray(styles) ? [...styles] : [styles];
if (stls.length) {
const href = stls.shift();
if (
href &&
(!opts.unique || !document.querySelector(`link[href="${href}"]`))
) {
const { head } = document;
const link = document.createElement('link');
link.href = href;
link.rel = 'stylesheet';
if (opts.prepand) {
head.insertBefore(link, head.firstChild);
} else {
head.appendChild(link);
}
}
appendStyles(stls);
}
};
/**
* Returns shallow diff between 2 objects
* @param {Object} objOrig
* @param {Objec} objNew
* @return {Object}
* @example
* var a = {foo: 'bar', baz: 1, faz: 'sop'};
* var b = {foo: 'bar', baz: 2, bar: ''};
* shallowDiff(a, b);
* // -> {baz: 2, faz: null, bar: ''};
*/
const shallowDiff = (objOrig, objNew) => {
const result = {};
const keysNew = keys(objNew);
for (let prop in objOrig) {
if (objOrig.hasOwnProperty(prop)) {
const origValue = objOrig[prop];
const newValue = objNew[prop];
if (keysNew.indexOf(prop) >= 0) {
if (origValue !== newValue) {
result[prop] = newValue;
}
} else {
result[prop] = null;
}
}
}
for (let prop in objNew) {
if (objNew.hasOwnProperty(prop)) {
if (isUndefined(objOrig[prop])) {
result[prop] = objNew[prop];
}
}
}
return result;
};
const on = (el, ev, fn) => {
ev = ev.split(/\s+/);
el = el instanceof Array ? el : [el];
for (let i = 0; i < ev.length; ++i) {
el.forEach(elem => elem.addEventListener(ev[i], fn));
}
};
const off = (el, ev, fn) => {
ev = ev.split(/\s+/);
el = el instanceof Array ? el : [el];
for (let i = 0; i < ev.length; ++i) {
el.forEach(elem => elem.removeEventListener(ev[i], fn));
}
};
const getUnitFromValue = value => {
return value.replace(parseFloat(value), '');
};
const upFirst = value => value[0].toUpperCase() + value.toLowerCase().slice(1);
const camelCase = value => {
const values = value.split('-').filter(String);
return values[0].toLowerCase() + values.slice(1).map(upFirst);
};
const normalizeFloat = (value, step = 1, valueDef = 0) => {
let stepDecimals = 0;
if (isNaN(value)) return valueDef;
value = parseFloat(value);
if (Math.floor(value) !== value) {
const side = step.toString().split('.')[1];
stepDecimals = side ? side.length : 0;
}
return stepDecimals ? parseFloat(value.toFixed(stepDecimals)) : value;
};
const hasDnd = em => {
return (
'draggable' in document.createElement('i') &&
(em ? em.get('Config').nativeDnD : 1)
);
};
/**
* Ensure to fetch the element from the input argument
* @param {HTMLElement|Component} el Component or HTML element
* @return {HTMLElement}
*/
const getElement = el => {
if (isElement(el) || isTextNode(el)) {
return el;
} else if (el && el.getEl) {
return el.getEl();
}
};
/**
* Check if element is a text node
* @param {HTMLElement} el
* @return {Boolean}
*/
const isTextNode = el => el && el.nodeType === 3;
/**
* Check if element is a comment node
* @param {HTMLElement} el
* @return {Boolean}
*/
export const isCommentNode = el => el && el.nodeType === 8;
/**
* Check if element is a comment node
* @param {HTMLElement} el
* @return {Boolean}
*/
export const isTaggableNode = el => el && !isTextNode(el) && !isCommentNode(el);
/**
* Ensure to fetch the model from the input argument
* @param {HTMLElement|Component} el Component or HTML element
* @return {Component}
*/
const getModel = (el, $) => {
let model = el;
isElement(el) && (model = $(el).data('model'));
return model;
};
const getElRect = el => {
const def = {
top: 0,
left: 0,
width: 0,
height: 0
};
if (!el) return def;
let rectText;
if (isTextNode(el)) {
const range = document.createRange();
range.selectNode(el);
rectText = range.getBoundingClientRect();
range.detach();
}
return (
rectText || (el.getBoundingClientRect ? el.getBoundingClientRect() : def)
);
};
/**
* Get cross-device pointer event
* @param {Event} ev
* @return {Event}
*/
const getPointerEvent = ev =>
ev.touches && ev.touches[0] ? ev.touches[0] : ev;
/**
* Get cross-browser keycode
* @param {Event} ev
* @return {Number}
*/
const getKeyCode = ev => ev.which || ev.keyCode;
const getKeyChar = ev => String.fromCharCode(getKeyCode(ev));
const isEscKey = ev => getKeyCode(ev) === 27;
const isObject = val =>
val !== null && !Array.isArray(val) && typeof val === 'object';
const capitalize = str => str && str.charAt(0).toUpperCase() + str.substring(1);
const isComponent = obj => obj && obj.toHTML;
const isRule = obj => obj && obj.toCSS;
const getViewEl = el => el.__gjsv;
const setViewEl = (el, view) => {
el.__gjsv = view;
};
export {
on,
off,
hasDnd,
upFirst,
matches,
getModel,
getElRect,
camelCase,
isTextNode,
getKeyCode,
getKeyChar,
isEscKey,
getElement,
shallowDiff,
normalizeFloat,
getPointerEvent,
getUnitFromValue,
capitalize,
getViewEl,
setViewEl,
appendStyles,
isObject,
isComponent,
isRule
};