2025-05-17 11:06:45 +02:00
|
|
|
class Intro {
|
|
|
|
|
constructor(name) {
|
|
|
|
|
this.name = name;
|
2025-05-03 15:12:16 +02:00
|
|
|
}
|
2025-05-17 11:06:45 +02:00
|
|
|
|
|
|
|
|
init() {
|
|
|
|
|
return new Promise((resolve) => {
|
|
|
|
|
console.log('%s Init', this.name);
|
|
|
|
|
|
|
|
|
|
resolve();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class UI {
|
|
|
|
|
constructor() {
|
|
|
|
|
this.introDelay = 6;
|
|
|
|
|
this.hintDelay = 1;
|
|
|
|
|
this.isAgree = false;
|
|
|
|
|
this.steps = {
|
|
|
|
|
agreement: {
|
|
|
|
|
element: document.getElementById('agreement'),
|
|
|
|
|
msgIn: 'Agreement shown.',
|
|
|
|
|
msgOut: 'Agreement accepted.',
|
|
|
|
|
msgNo: 'No agreement today.'
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
this.intro = document.getElementById('intro');
|
|
|
|
|
this.agreement = this.steps.agreement.element;
|
|
|
|
|
this.hint = {
|
|
|
|
|
element: document.getElementById('hint'),
|
|
|
|
|
delay: this.hintDelay * 1000
|
|
|
|
|
};
|
|
|
|
|
this.loader = document.getElementById('loader');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
showIntro() {
|
|
|
|
|
const el = this.intro;
|
|
|
|
|
const dy = this.introDelay * 1000;
|
|
|
|
|
|
|
|
|
|
document.addEventListener('click', hintHandler, false);
|
|
|
|
|
document.addEventListener('keydown', hintHandler, false);
|
|
|
|
|
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
if (el) {
|
|
|
|
|
console.info("Intro begin.");
|
|
|
|
|
|
|
|
|
|
el.classList.replace('op_hide', 'op_show');
|
|
|
|
|
setTimeout(
|
|
|
|
|
() => {
|
|
|
|
|
el.classList.replace('op_show', 'op_hide');
|
|
|
|
|
el.addEventListener('transitionend', () => {
|
|
|
|
|
console.info("Intro fin.");
|
|
|
|
|
|
|
|
|
|
el.classList.add('di_none');
|
|
|
|
|
resolve("Intro fin.");
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
dy
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
reject('No intro available.');
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
showHint() {
|
|
|
|
|
if (typeof this.hint.timeoutId === 'number') {
|
|
|
|
|
this.cancelHint();
|
2025-05-02 19:50:26 +02:00
|
|
|
}
|
|
|
|
|
|
2025-05-17 11:06:45 +02:00
|
|
|
this.hint.element.classList.remove('di_none');
|
2025-05-02 19:50:26 +02:00
|
|
|
|
2025-05-17 11:06:45 +02:00
|
|
|
this.hint.timeoutId = setTimeout(
|
2025-05-02 19:50:26 +02:00
|
|
|
() => {
|
2025-05-17 11:06:45 +02:00
|
|
|
this.dismissHint();
|
2025-05-02 19:50:26 +02:00
|
|
|
},
|
2025-05-17 11:06:45 +02:00
|
|
|
this.hint.delay
|
2025-05-02 19:50:26 +02:00
|
|
|
);
|
|
|
|
|
}
|
2025-05-17 11:06:45 +02:00
|
|
|
|
|
|
|
|
dismissHint() {
|
|
|
|
|
this.hint.element.classList.add('di_none');
|
|
|
|
|
this.hint.timeoutId = undefined;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cancelHint() {
|
|
|
|
|
clearTimeout(this.hint.timeoutId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
showIdle() {
|
|
|
|
|
const el = document.getElementById('idle');
|
|
|
|
|
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
if (el) {
|
|
|
|
|
console.info('Idle.');
|
|
|
|
|
|
|
|
|
|
el.classList.replace('op_hide', 'op_show');
|
|
|
|
|
resolve('Idle.');
|
|
|
|
|
} else {
|
|
|
|
|
reject();
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
init() {
|
|
|
|
|
return new Promise((resolve) => {
|
|
|
|
|
console.log('Init');
|
|
|
|
|
|
|
|
|
|
resolve();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-05-02 19:50:26 +02:00
|
|
|
|
2025-05-02 20:35:58 +02:00
|
|
|
function init() {
|
|
|
|
|
return new Promise((resolve) => {
|
|
|
|
|
console.log('Init');
|
2025-05-03 12:34:23 +02:00
|
|
|
|
2025-05-18 11:20:48 +02:00
|
|
|
// Set all steps to not receive pointer events
|
|
|
|
|
document.querySelectorAll('.step').forEach(element => {
|
|
|
|
|
console.log(element);
|
|
|
|
|
|
|
|
|
|
element.style.pointerEvents = 'none';
|
|
|
|
|
});
|
|
|
|
|
|
2025-05-02 20:35:58 +02:00
|
|
|
resolve();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function showIntro() {
|
|
|
|
|
const el = intro;
|
|
|
|
|
const dy = introDelay * 1000;
|
|
|
|
|
|
2025-05-03 15:12:16 +02:00
|
|
|
document.addEventListener('click', hintHandler, false);
|
|
|
|
|
document.addEventListener('keydown', hintHandler, false);
|
2025-05-03 12:34:23 +02:00
|
|
|
|
2025-05-02 20:35:58 +02:00
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
if (el) {
|
|
|
|
|
console.info("Intro begin.");
|
|
|
|
|
|
2025-05-03 12:34:23 +02:00
|
|
|
el.classList.replace('op_hide', 'op_show');
|
2025-05-02 20:35:58 +02:00
|
|
|
setTimeout(
|
|
|
|
|
() => {
|
|
|
|
|
el.classList.replace('op_show', 'op_hide');
|
|
|
|
|
el.addEventListener('transitionend', () => {
|
|
|
|
|
console.info("Intro fin.");
|
2025-05-03 12:34:23 +02:00
|
|
|
|
2025-05-03 15:12:16 +02:00
|
|
|
el.classList.add('di_none');
|
2025-05-18 12:07:10 +02:00
|
|
|
|
2025-05-02 20:35:58 +02:00
|
|
|
resolve("Intro fin.");
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
dy
|
|
|
|
|
);
|
|
|
|
|
} else {
|
2025-05-18 12:07:10 +02:00
|
|
|
document.removeEventListener('click', hintHandler);
|
|
|
|
|
document.removeEventListener('keydown', hintHandler);
|
|
|
|
|
|
2025-05-02 20:35:58 +02:00
|
|
|
reject('No intro available.');
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function showAgreement() {
|
2025-05-03 15:12:16 +02:00
|
|
|
document.removeEventListener('click', hintHandler);
|
|
|
|
|
document.removeEventListener('keydown', hintHandler);
|
2025-05-02 20:35:58 +02:00
|
|
|
const el = agreement;
|
|
|
|
|
const dy = introDelay * 1000;
|
|
|
|
|
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
if (el) {
|
2025-05-03 15:12:16 +02:00
|
|
|
console.info(steps.agreement.msgIn);
|
2025-05-02 20:35:58 +02:00
|
|
|
|
2025-05-03 12:34:23 +02:00
|
|
|
el.classList.replace('op_hide', 'op_show');
|
2025-05-18 11:20:48 +02:00
|
|
|
el.style.pointerEvents = '';
|
|
|
|
|
|
2025-05-03 15:12:16 +02:00
|
|
|
el.addEventListener('click', agreeHandler);
|
2025-05-18 12:07:10 +02:00
|
|
|
document.addEventListener('keydown', agreeHandler);
|
2025-05-02 20:35:58 +02:00
|
|
|
} else {
|
2025-05-03 15:12:16 +02:00
|
|
|
reject(steps.agreement.msgNo);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function agreeHandler() {
|
|
|
|
|
const el = agreement;
|
|
|
|
|
|
|
|
|
|
isAgree = true;
|
|
|
|
|
|
|
|
|
|
el.classList.replace('op_show', 'op_hide');
|
|
|
|
|
el.addEventListener('transitionend', function endListener() {
|
|
|
|
|
console.info(steps.agreement.msgOut);
|
|
|
|
|
|
|
|
|
|
el.removeEventListener('transitionend', endListener);
|
|
|
|
|
el.removeEventListener('click', agreeHandler);
|
2025-05-18 12:07:10 +02:00
|
|
|
document.removeEventListener('keydown', agreeHandler);
|
2025-05-03 15:12:16 +02:00
|
|
|
el.classList.add('di_none');
|
2025-05-18 12:07:10 +02:00
|
|
|
|
2025-05-03 15:12:16 +02:00
|
|
|
resolve(steps.agreement.msgOut);
|
|
|
|
|
});
|
2025-05-02 20:35:58 +02:00
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-04 22:25:03 +02:00
|
|
|
function showIdle() {
|
|
|
|
|
const el = document.getElementById('idle');
|
|
|
|
|
|
2025-05-18 11:20:48 +02:00
|
|
|
document.addEventListener('mouseleave', idleStart, false);
|
|
|
|
|
document.addEventListener('mouseenter', idleStop, false);
|
|
|
|
|
|
2025-05-04 22:25:03 +02:00
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
if (el) {
|
|
|
|
|
console.info('Idle.');
|
|
|
|
|
|
|
|
|
|
el.classList.replace('op_hide', 'op_show');
|
2025-05-18 11:20:48 +02:00
|
|
|
el.style.pointerEvents = '';
|
|
|
|
|
el.addEventListener('click', idleStart, false);
|
2025-05-18 12:07:10 +02:00
|
|
|
|
2025-05-04 22:25:03 +02:00
|
|
|
resolve('Idle.');
|
|
|
|
|
} else {
|
2025-05-18 11:20:48 +02:00
|
|
|
document.removeEventListener('mouseleave', idleStart);
|
|
|
|
|
document.removeEventListener('mouseenter', idleStop);
|
|
|
|
|
|
2025-05-04 22:25:03 +02:00
|
|
|
reject();
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-03 12:34:23 +02:00
|
|
|
function loadCore() {
|
|
|
|
|
const el = loader;
|
|
|
|
|
const bar = loader.querySelector('#progress');
|
|
|
|
|
const status = loader.querySelector('#status');
|
|
|
|
|
const spinner = loader.querySelector('#spinner');
|
|
|
|
|
const sp = spinner.querySelector('span');
|
|
|
|
|
|
|
|
|
|
let progress = 0;
|
|
|
|
|
|
|
|
|
|
return new Promise((resolve) => {
|
|
|
|
|
console.info("Core loading.");
|
|
|
|
|
|
|
|
|
|
updateProgressBar();
|
|
|
|
|
|
|
|
|
|
function updateProgressBar() {
|
2025-05-03 15:12:16 +02:00
|
|
|
const maxChunk = 33;
|
|
|
|
|
const time = 400;
|
|
|
|
|
let increment = randomIntFrom(1, maxChunk);
|
2025-05-03 12:34:23 +02:00
|
|
|
|
|
|
|
|
progress += increment;
|
|
|
|
|
|
|
|
|
|
if (progress >= 100) progress = 100;
|
|
|
|
|
// console.log(progress);
|
|
|
|
|
|
|
|
|
|
bar.style.width = progress + '%';
|
|
|
|
|
status.textContent = progress + '%';
|
|
|
|
|
|
|
|
|
|
if (progress < 100) {
|
2025-05-03 15:12:16 +02:00
|
|
|
setTimeout(updateProgressBar, time);
|
2025-05-03 12:34:23 +02:00
|
|
|
} else {
|
|
|
|
|
bar.style.width = '100%';
|
|
|
|
|
sp.style.animationPlayState = 'paused';
|
|
|
|
|
spinner.style.color = 'white';
|
|
|
|
|
spinner.style.backgroundColor = 'black';
|
|
|
|
|
el.classList.replace('op_show', 'op_hide');
|
2025-05-03 15:12:16 +02:00
|
|
|
el.addEventListener('transitionend', function endListener() {
|
2025-05-03 12:34:23 +02:00
|
|
|
console.info("Core loaded.");
|
|
|
|
|
|
2025-05-03 15:12:16 +02:00
|
|
|
el.removeEventListener('transitionend', endListener);
|
|
|
|
|
el.classList.add('di_none');
|
2025-05-18 12:07:10 +02:00
|
|
|
|
2025-05-03 12:34:23 +02:00
|
|
|
resolve("Core loaded.");
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Gibt eine Zahl zwischen <min> und <max> aus.
|
|
|
|
|
* Die Werte <min> und <max> sind dabei mit eingeschlossen.
|
|
|
|
|
* Mit <pos> kann der Exponent für eine 10er-Teilung angegeben werden.
|
|
|
|
|
*
|
|
|
|
|
* @param {number} min
|
|
|
|
|
* @param {number} max
|
|
|
|
|
* @param {number} pos
|
|
|
|
|
* @returns {number}
|
|
|
|
|
*/
|
|
|
|
|
function randomIntFrom(min, max, pos = 0) {
|
|
|
|
|
pos = Math.pow(10, pos);
|
|
|
|
|
min = Math.ceil(min);
|
|
|
|
|
max = Math.floor(max);
|
|
|
|
|
|
|
|
|
|
return Math.floor((Math.random() * (max - min + 1) + min) / pos) * pos;
|
2025-05-03 15:12:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Erstellt Kontext für hint-Objekt und ermöglicht das Entfernen des Ereignis.
|
|
|
|
|
*/
|
|
|
|
|
function hintHandler() {
|
|
|
|
|
hint.show();
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-18 11:20:48 +02:00
|
|
|
function idleStart() {
|
|
|
|
|
idle.cycle();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function idleStop() {
|
|
|
|
|
idle.cancel();
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-03 15:12:16 +02:00
|
|
|
/**
|
|
|
|
|
* Blendet einen Schritt aus.
|
|
|
|
|
*
|
|
|
|
|
* @param {*} e
|
|
|
|
|
* @returns
|
|
|
|
|
*/
|
|
|
|
|
function stepHandler(e) {
|
|
|
|
|
const el = e.target;
|
|
|
|
|
const msg = steps[el.id].msgOut;
|
|
|
|
|
|
|
|
|
|
return new Promise(function (resolve) {
|
|
|
|
|
el.classList.replace('op_show', 'op_hide');
|
|
|
|
|
el.addEventListener('transitionend', function endListener() {
|
|
|
|
|
console.info(msg);
|
|
|
|
|
|
|
|
|
|
el.removeEventListener('transitionend', endListener);
|
2025-05-18 12:07:10 +02:00
|
|
|
|
2025-05-03 15:12:16 +02:00
|
|
|
resolve(msg);
|
|
|
|
|
});
|
|
|
|
|
})
|
2025-05-03 12:34:23 +02:00
|
|
|
}
|