mirror of
https://github.com/ArenMg/aren.git
synced 2024-09-29 22:35:54 +00:00
259 lines
No EOL
8.4 KiB
JavaScript
259 lines
No EOL
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 + "%)";
|
|
}
|
|
} |