2019-11-03 18:45:16 +01:00
|
|
|
/**
|
|
|
|
* @param {number} min
|
|
|
|
* @param {number} max
|
|
|
|
* @returns {number}
|
|
|
|
*/
|
2019-02-22 23:04:55 +01:00
|
|
|
export const getRandomNumber = (min, max) =>
|
|
|
|
Math.floor(Math.random() * (max - min) + min);
|
2018-05-28 17:22:22 +02:00
|
|
|
|
2019-11-03 18:45:16 +01:00
|
|
|
/**
|
|
|
|
* @param {number} length
|
|
|
|
* @returns {string}
|
|
|
|
*/
|
2019-10-31 18:49:27 +01:00
|
|
|
export const generateChars = length =>
|
|
|
|
Array.from({ length }, () => getRandomNumber(0, 36).toString(36)).join('');
|
2017-06-02 22:34:07 +02:00
|
|
|
|
2019-11-03 18:45:16 +01:00
|
|
|
/**
|
|
|
|
* @param {HTMLInputElement | HTMLSelectElement} element
|
|
|
|
* @param {string} prefix
|
|
|
|
* @returns {string}
|
|
|
|
*/
|
2019-02-22 23:04:55 +01:00
|
|
|
export const generateId = (element, prefix) => {
|
2018-05-28 16:50:16 +02:00
|
|
|
let id =
|
|
|
|
element.id ||
|
|
|
|
(element.name && `${element.name}-${generateChars(2)}`) ||
|
|
|
|
generateChars(4);
|
2017-06-02 22:34:07 +02:00
|
|
|
id = id.replace(/(:|\.|\[|\]|,)/g, '');
|
2018-05-28 18:56:36 +02:00
|
|
|
id = `${prefix}-${id}`;
|
2017-06-02 22:34:07 +02:00
|
|
|
|
|
|
|
return id;
|
|
|
|
};
|
|
|
|
|
2019-11-03 18:45:16 +01:00
|
|
|
/**
|
|
|
|
* @param {any} obj
|
|
|
|
* @returns {string}
|
|
|
|
*/
|
2019-02-22 23:04:55 +01:00
|
|
|
export const getType = obj => Object.prototype.toString.call(obj).slice(8, -1);
|
2016-04-04 22:44:32 +02:00
|
|
|
|
2019-11-03 18:45:16 +01:00
|
|
|
/**
|
|
|
|
* @param {string} type
|
|
|
|
* @param {any} obj
|
|
|
|
* @returns {boolean}
|
|
|
|
*/
|
2019-02-22 23:04:55 +01:00
|
|
|
export const isType = (type, obj) =>
|
|
|
|
obj !== undefined && obj !== null && getType(obj) === type;
|
2016-04-04 22:44:32 +02:00
|
|
|
|
2019-11-03 18:45:16 +01:00
|
|
|
/**
|
|
|
|
* @param {HTMLElement} element
|
|
|
|
* @param {HTMLElement} [wrapper={HTMLDivElement}]
|
|
|
|
* @returns {HTMLElement}
|
|
|
|
*/
|
2019-02-22 23:04:55 +01:00
|
|
|
export const wrap = (element, wrapper = document.createElement('div')) => {
|
2016-09-05 23:04:15 +02:00
|
|
|
if (element.nextSibling) {
|
|
|
|
element.parentNode.insertBefore(wrapper, element.nextSibling);
|
|
|
|
} else {
|
|
|
|
element.parentNode.appendChild(wrapper);
|
|
|
|
}
|
2019-10-29 19:26:11 +01:00
|
|
|
|
2016-09-05 23:04:15 +02:00
|
|
|
return wrapper.appendChild(element);
|
2016-03-16 21:24:11 +01:00
|
|
|
};
|
|
|
|
|
2019-10-28 21:26:19 +01:00
|
|
|
/**
|
|
|
|
* @param {HTMLElement} el
|
|
|
|
* @param {string} attr
|
|
|
|
*/
|
|
|
|
export const findAncestorByAttrName = (el, attr) => el.closest(`[${attr}]`);
|
2017-03-12 14:17:46 +01:00
|
|
|
|
2019-11-03 18:45:16 +01:00
|
|
|
/**
|
|
|
|
* @param {Element} startEl
|
|
|
|
* @param {string} selector
|
|
|
|
* @param {1 | -1} direction
|
|
|
|
* @returns {Element | undefined}
|
|
|
|
*/
|
|
|
|
export const getAdjacentEl = (startEl, selector, direction = 1) => {
|
|
|
|
if (!(startEl instanceof Element) || typeof selector !== 'string') {
|
|
|
|
return undefined;
|
|
|
|
}
|
2016-05-02 14:22:53 +02:00
|
|
|
|
2019-11-03 18:45:16 +01:00
|
|
|
const prop = `${direction > 0 ? 'next' : 'previous'}ElementSibling`;
|
2016-05-02 14:22:53 +02:00
|
|
|
|
2019-11-03 18:45:16 +01:00
|
|
|
let sibling = startEl[prop];
|
|
|
|
while (sibling) {
|
|
|
|
if (sibling.matches(selector)) {
|
|
|
|
return sibling;
|
2019-10-31 18:49:27 +01:00
|
|
|
}
|
2019-11-03 18:45:16 +01:00
|
|
|
sibling = sibling[prop];
|
|
|
|
}
|
2016-08-14 23:14:37 +02:00
|
|
|
|
2019-11-03 18:45:16 +01:00
|
|
|
return sibling;
|
|
|
|
};
|
2016-05-02 14:22:53 +02:00
|
|
|
|
2019-11-03 18:45:16 +01:00
|
|
|
/**
|
|
|
|
* @param {HTMLElement} element
|
|
|
|
* @param {HTMLElement} parent
|
|
|
|
* @param {-1 | 1} direction
|
|
|
|
* @returns {boolean}
|
|
|
|
*/
|
|
|
|
export const isScrolledIntoView = (element, parent, direction = 1) => {
|
|
|
|
if (!element) {
|
|
|
|
return false;
|
2019-02-22 23:04:55 +01:00
|
|
|
}
|
2016-05-02 22:39:33 +02:00
|
|
|
|
2016-09-05 23:04:15 +02:00
|
|
|
let isVisible;
|
2016-05-02 22:39:33 +02:00
|
|
|
|
2016-09-05 23:04:15 +02:00
|
|
|
if (direction > 0) {
|
|
|
|
// In view from bottom
|
2018-05-28 16:50:16 +02:00
|
|
|
isVisible =
|
2019-11-03 18:45:16 +01:00
|
|
|
parent.scrollTop + parent.offsetHeight >=
|
|
|
|
element.offsetTop + element.offsetHeight;
|
2016-09-05 23:04:15 +02:00
|
|
|
} else {
|
|
|
|
// In view from top
|
2019-11-03 18:45:16 +01:00
|
|
|
isVisible = element.offsetTop >= parent.scrollTop;
|
2016-09-05 23:04:15 +02:00
|
|
|
}
|
2016-08-14 23:14:37 +02:00
|
|
|
|
2016-09-05 23:04:15 +02:00
|
|
|
return isVisible;
|
2016-08-14 23:14:37 +02:00
|
|
|
};
|
2016-05-02 16:29:05 +02:00
|
|
|
|
2019-11-03 18:45:16 +01:00
|
|
|
/**
|
|
|
|
* @param {any} value
|
|
|
|
* @returns {any}
|
|
|
|
*/
|
2019-02-22 23:04:55 +01:00
|
|
|
export const sanitise = value => {
|
2019-10-29 22:19:56 +01:00
|
|
|
if (typeof value !== 'string') {
|
2019-02-22 23:04:55 +01:00
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
return value
|
2018-05-28 16:50:16 +02:00
|
|
|
.replace(/&/g, '&')
|
2018-03-23 16:51:50 +01:00
|
|
|
.replace(/>/g, '&rt;')
|
|
|
|
.replace(/</g, '<')
|
|
|
|
.replace(/"/g, '"');
|
2019-02-22 23:04:55 +01:00
|
|
|
};
|
2016-03-16 21:24:11 +01:00
|
|
|
|
2019-11-03 18:45:16 +01:00
|
|
|
/**
|
|
|
|
* @returns {function}
|
|
|
|
*/
|
2019-02-22 23:04:55 +01:00
|
|
|
export const strToEl = (() => {
|
2017-08-16 10:47:22 +02:00
|
|
|
const tmpEl = document.createElement('div');
|
2019-10-29 19:26:11 +01:00
|
|
|
|
2019-02-22 23:04:55 +01:00
|
|
|
return str => {
|
2017-08-16 10:47:22 +02:00
|
|
|
const cleanedInput = str.trim();
|
2017-06-27 13:42:01 +02:00
|
|
|
tmpEl.innerHTML = cleanedInput;
|
2019-02-22 23:04:55 +01:00
|
|
|
const firldChild = tmpEl.children[0];
|
2016-09-05 23:04:15 +02:00
|
|
|
|
|
|
|
while (tmpEl.firstChild) {
|
|
|
|
tmpEl.removeChild(tmpEl.firstChild);
|
|
|
|
}
|
2016-04-04 00:07:10 +02:00
|
|
|
|
2019-02-22 23:04:55 +01:00
|
|
|
return firldChild;
|
2016-09-05 23:04:15 +02:00
|
|
|
};
|
2018-05-28 16:50:16 +02:00
|
|
|
})();
|
2016-04-07 20:44:16 +02:00
|
|
|
|
2019-11-03 14:18:16 +01:00
|
|
|
/**
|
|
|
|
* @param {{ label?: string, value: string }} a
|
|
|
|
* @param {{ label?: string, value: string }} b
|
|
|
|
* @returns {number}
|
|
|
|
*/
|
|
|
|
export const sortByAlpha = (
|
|
|
|
{ value, label = value },
|
|
|
|
{ value: value2, label: label2 = value2 },
|
|
|
|
) =>
|
|
|
|
label.localeCompare(label2, [], {
|
|
|
|
sensitivity: 'base',
|
|
|
|
ignorePunctuation: true,
|
|
|
|
numeric: true,
|
|
|
|
});
|
2016-08-03 15:23:23 +02:00
|
|
|
|
2019-11-03 14:18:16 +01:00
|
|
|
/**
|
2019-11-03 18:45:16 +01:00
|
|
|
* @param {{ score: number }} a
|
|
|
|
* @param {{ score: number }} b
|
2019-11-03 14:18:16 +01:00
|
|
|
*/
|
2017-08-16 10:47:22 +02:00
|
|
|
export const sortByScore = (a, b) => a.score - b.score;
|
2017-01-01 16:32:09 +01:00
|
|
|
|
2019-11-03 18:45:16 +01:00
|
|
|
/**
|
|
|
|
* @param {HTMLElement} element
|
|
|
|
* @param {string} type
|
|
|
|
* @param {object} customArgs
|
|
|
|
*/
|
2017-10-18 10:08:27 +02:00
|
|
|
export const dispatchEvent = (element, type, customArgs = null) => {
|
2017-12-20 13:38:16 +01:00
|
|
|
const event = new CustomEvent(type, {
|
2017-01-01 16:32:09 +01:00
|
|
|
detail: customArgs,
|
|
|
|
bubbles: true,
|
2017-08-16 10:47:22 +02:00
|
|
|
cancelable: true,
|
2017-01-01 16:32:09 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
return element.dispatchEvent(event);
|
|
|
|
};
|
2017-08-10 12:57:17 +02:00
|
|
|
|
2019-11-03 18:45:16 +01:00
|
|
|
/**
|
|
|
|
* @param {string} userAgent
|
|
|
|
* @returns {boolean}
|
|
|
|
*/
|
2019-10-29 22:19:56 +01:00
|
|
|
export const isIE11 = userAgent =>
|
|
|
|
!!(userAgent.match(/Trident/) && userAgent.match(/rv[ :]11/));
|
2018-05-27 18:22:58 +02:00
|
|
|
|
2019-11-03 18:45:16 +01:00
|
|
|
/**
|
|
|
|
* @param {array} array
|
|
|
|
* @param {any} value
|
|
|
|
* @param {string} [key="value"]
|
|
|
|
* @returns {boolean}
|
|
|
|
*/
|
2018-05-28 18:56:36 +02:00
|
|
|
export const existsInArray = (array, value, key = 'value') =>
|
2018-05-28 17:22:22 +02:00
|
|
|
array.some(item => {
|
2019-10-29 22:19:56 +01:00
|
|
|
if (typeof value === 'string') {
|
2018-05-28 18:56:36 +02:00
|
|
|
return item[key] === value.trim();
|
2018-05-27 18:22:58 +02:00
|
|
|
}
|
|
|
|
|
2018-05-28 18:56:36 +02:00
|
|
|
return item[key] === value;
|
2018-05-28 16:50:16 +02:00
|
|
|
});
|
2018-05-28 17:22:22 +02:00
|
|
|
|
2019-11-03 18:45:16 +01:00
|
|
|
/**
|
|
|
|
* @param {any} obj
|
|
|
|
* @returns {any}
|
|
|
|
*/
|
2018-05-28 17:22:22 +02:00
|
|
|
export const cloneObject = obj => JSON.parse(JSON.stringify(obj));
|
2018-10-09 14:16:58 +02:00
|
|
|
|
2019-11-03 18:45:16 +01:00
|
|
|
/**
|
|
|
|
* Returns an array of keys present on the first but missing on the second object
|
|
|
|
* @param {object} a
|
|
|
|
* @param {object} b
|
|
|
|
* @returns {string[]}
|
|
|
|
*/
|
2019-02-12 19:35:46 +01:00
|
|
|
export const diff = (a, b) => {
|
2018-10-09 14:16:58 +02:00
|
|
|
const aKeys = Object.keys(a).sort();
|
|
|
|
const bKeys = Object.keys(b).sort();
|
2019-02-12 19:35:46 +01:00
|
|
|
|
2019-02-22 23:04:55 +01:00
|
|
|
return aKeys.filter(i => bKeys.indexOf(i) < 0);
|
|
|
|
};
|