ArenMg/src/main/webapp/assets/js/utils.js
2021-04-16 11:34:24 +03:00

259 lines
8.4 KiB
JavaScript

function decycle(obj, stack = [ ]) {
if (!obj || typeof obj !== 'object')
return obj;
if (stack.includes(obj))
return null;
let s = stack.concat([obj]);
return Array.isArray(obj) ? obj.map(x => decycle(x, s))
: Object.assign(new obj.constructor(), Object.fromEntries(
Object.entries(obj)
.map(([k, v]) => [k, decycle(v, s)])));
}
function vueLoader(file) {
return httpVueLoader('assets/js/' + file + '.vue');
}
/***** Useful function on prototypes *****/
Array.prototype.remove = function (obj) {
let index = this.indexOf(obj);
if (index !== -1) {
this.splice(index, 1);
return true;
} else {
return false;
}
};
Array.prototype.compare = function (obj) {
if (this === obj) {
return 0;
}
let len = Math.max(this.length, obj.length);
for (let i = 0; i < len; i++) {
if (this[i] === undefined || obj[i] !== undefined && this[i] < obj[i]) {
return -1;
} else if (obj[i] === undefined || this[i] !== undefined && this[i] > obj[i]) {
return 1;
}
}
return 0;
}
if (!Array.prototype.includes) {
Array.prototype.includes = function (obj) {
return this.indexOf(obj) !== -1;
}
}
if (!String.prototype.includes) {
String.prototype.includes = function (obj) {
return this.indexOf(obj) !== -1;
}
}
Node.prototype.getChildPathTo = function (el) {
if (el === this) {
return "";
}
let sibIndex = -1;
let len = el.parentNode.childNodes.length;
let sib;
while (sibIndex < len && sib !== el) {
sibIndex++;
sib = el.parentNode.childNodes[sibIndex];
}
if (el.parentNode === this) {
return sibIndex;
} else {
return this.getChildPathTo(el.parentNode) + "/" + sibIndex;
}
};
Node.prototype.childPathSelector = function (path) {
if (path.constructor !== String) {
path = path + "";
}
let arrayPath = path.split("/");
var result = this;
let len = arrayPath.length;
for (let i = 0; i < len; i++) {
if (result.childNodes.length > arrayPath[i]) {
result = result.childNodes[arrayPath[i]];
} else {
console.warn("Warning : impossible to find child number " + arrayPath[i] + ". The return child may be wrong.", this, result);
}
}
return result;
};
Node.prototype.forEachNode = function (callback, origin = this, end = false, index = []) {
if (end && this === origin) {
return null;
}
if (!end && callback) {
callback(this, [...index], origin);
}
if (!end && this.firstChild !== null) {
index.push(0);
this.firstChild.forEachNode(callback, origin, false, index);
} else if (this.nextSibling !== null) {
index[index.length - 1]++;
this.nextSibling.forEachNode(callback, origin, false, index);
} else {
index.pop();
this.parentNode.forEachNode(callback, origin, true, index);
}
}
/***** Selection handling *****/
function compareRange(type, r1, r2) {
let pos1, pos2;
switch (type) {
case Range.START_TO_START:
pos1 = (r1.startContainer + "/" + r1.startOffset).split("/").map(v => v * 1);
pos2 = (r2.startContainer + "/" + r2.startOffset).split("/").map(v => v * 1);
break;
case Range.START_TO_END:
pos1 = (r1.startContainer + "/" + r1.startOffset).split("/").map(v => v * 1);
pos2 = (r2.endContainer + "/" + r2.endOffset).split("/").map(v => v * 1);
break;
case Range.END_TO_START:
pos1 = (r1.endContainer + "/" + r1.endOffset).split("/").map(v => v * 1);
pos2 = (r2.startContainer + "/" + r2.startOffset).split("/").map(v => v * 1);
break;
case Range.END_TO_END:
pos1 = (r1.endContainer + "/" + r1.endOffset).split("/").map(v => v * 1);
pos2 = (r2.endContainer + "/" + r2.endOffset).split("/").map(v => v * 1);
break;
default:
throw "Invalid first parameter. Use Range.START_TO_START, Range.START_TO_END, Range.END_TO_START or Range.END_TO_END.";
}
return pos1.compare(pos2);
}
Range.prototype.setPathStart = function (container, startContainer, startOffset) {
this.setStart(startContainer ? container.childPathSelector(startContainer) : container.firstChild, startOffset);
}
Range.prototype.setPathEnd = function (container, endContainer, endOffset) {
this.setEnd(endContainer ? container.childPathSelector(endContainer) : container.firstChild, endOffset);
}
Range.prototype.getHtml = function () {
let div = document.createElement('div');
div.appendChild(this.cloneContents());
return div.innerHTML;
}
Range.prototype.affineToWord = function () {
let regExp = new RegExp('[A-Za-zÀ-ÖØ-öø-ÿ\'\.\n\t]');
while (this.startOffset > 0 && regExp.test(this.toString().charAt(0))) {
this.setStart(this.startContainer, this.startOffset - 1);
}
if (this.startOffset !== 0) {
this.setStart(this.startContainer, this.startOffset + 1);
}
while (this.endOffset < this.endContainer.length && regExp.test(this.toString().slice(-1))) {
this.setEnd(this.endContainer, this.endOffset + 1);
}
if (!regExp.test(this.toString().slice(-1)) && this.endOffset !== 0) {
this.setEnd(this.endContainer, this.endOffset - 1);
}
}
function clearSelection() {
if (window.getSelection) {
window.getSelection().removeAllRanges();
} else if (document.selection) {
document.selection.empty();
}
}
/***** Smooth Scroll *****/
var scrollProcess = [];
Math.easeOutExpo = function (time, origin, delta, duration) {
return delta * (-Math.pow(2, -10 * time / duration) + 1) + origin;
};
function clearAllSmoothScroll(container) {
let index = scrollProcess.findIndex((s) => s.container === container);
if (index !== -1) {
let len = scrollProcess[index].intervals.length;
for (var i = 0; i < len; i++) {
clearInterval(scrollProcess[index].intervals[i]);
}
scrollProcess.splice(index, 1);
}
}
function smoothScroll(container, scrollGoal, callback, duration = 0.5) {
clearAllSmoothScroll(container);
let scrollDir = container.scrollTop < scrollGoal ? 1 : -1;
let timeInt = 5;
let time = 0;
let origin = container.scrollTop;
let delta = scrollGoal - container.scrollTop;
duration = duration * (1000 / timeInt);
let index = scrollProcess.findIndex((s) => s.container === container);
if (index === -1) {
scrollProcess.push({
container,
intervals: []
});
index = scrollProcess.length - 1;
}
scrollProcess[index].intervals.push(setInterval(() => {
if (time === duration
|| scrollDir === 1 && (
container.scrollTop === container.scrollTopMax
|| container.scrollTop >= scrollGoal - 1)
|| scrollDir === -1 && (
container.scrollTop === 0
|| container.scrollTop <= scrollGoal + 1)
) {
clearAllSmoothScroll(container);
if (callback) {
callback();
}
} else {
container.scrollTop = Math.easeOutExpo(time, origin, delta, duration);
time++;
}
}, timeInt));
}
function scrollCenter(container, element, callback, duration = 0.5) {
let elemRect = element.getBoundingClientRect();
let containerRect = container.getBoundingClientRect();
let scrollGoal = elemRect.top + (container.scrollTop - containerRect.top);
smoothScroll(container, scrollGoal - (containerRect.height / 4), callback, duration);
}
function inScrollView(container, element) {
let elemRect = element.getBoundingClientRect();
let containerRect = container.getBoundingClientRect();
let scrollTop = elemRect.top + (container.scrollTop - containerRect.top);
let scrollBottom = elemRect.top + (container.scrollTop - containerRect.top - containerRect.height) + elemRect.height;
return (container.scrollTop < scrollTop && container.scrollTop > scrollBottom);
}
/***** Color function *****/
const HSL = {
fromString(color) {
let match = /hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/g.exec(color);
return {h: match[1], s: match[2], l: match[3] / 100};
},
toString(hsl) {
return "hsl(" + hsl.h + ", " + hsl.s * 100 + "%, " + hsl.l * 100 + "%)";
}
}