feat(plugins) default plugin class and initial plugins: interact, timing and utils base

This commit is contained in:
Benjamin Wegener
2024-01-11 23:25:33 +00:00
parent 159e53137a
commit 46edfb00bd
4 changed files with 238 additions and 0 deletions

View File

@@ -0,0 +1,11 @@
export default class CetraPlugin {
constructor() {}
register(name, id) {
console.log('register method not implemented', this.constructor.name);
}
initComponent(el) {
console.log('there is no init method for this element', el);
}
}

88
lib/plugins/Interact.js Normal file
View File

@@ -0,0 +1,88 @@
import CetraPlugin from './CetraPlugin';
import Registry from '../core/Registry';
import Logger from '../core/Logger';
export default class Interact extends CetraPlugin {
static #actions = [
'on',
'off',
'click',
'dblclick',
'mousedown',
'mouseup',
'keydown',
'keyup',
];
#cetraIdentifier;
#pluginName = 'interact';
constructor(cetraId) {
super(cetraId);
this.#cetraIdentifier = cetraId;
}
register(cetraId) {
this.#cetraIdentifier = cetraId;
const cetra = Registry.getParent(this.#cetraIdentifier);
if (!cetra)
throw new Error(
`no cetra instance found: ${this.#cetraIdentifier}`
);
cetra.registerCommands(Interact.#actions, this.#pluginName);
return this;
}
#actionSelectors(action = null) {
const cetra = Registry.getParent(this.#cetraIdentifier);
if (!cetra)
throw new Error(
`no cetra instance found: ${this.#cetraIdentifier}`
);
return (action ? [action] : Interact.#actions)
.map((action) =>
[
`[data-${cetra.getOption('selector')}-${action}]`,
`[${cetra.getOption('selector')}-${action}]`,
]
.map(
(v) =>
`${v}:not([data-${cetra.getOption('selector')}-id])`
)
.join(',')
)
.join(',');
}
initComponent(comp, compData) {
const els = comp.querySelectorAll(this.#actionSelectors());
for (const el of els) {
this.#initElement(el, compData.get('id'));
}
}
#initElement(el, componentId) {
const cetra = Registry.getParent(this.#cetraIdentifier);
if (!cetra) {
throw new TypeError(
`no cetra instance found: ${this.#cetraIdentifier}`
);
}
let [action, method, varName] = (
el.getAttribute(`data-${cetra.getOption('selector')}-on`) ||
el.getAttribute(`${cetra.getOption('selector')}-on`) ||
''
).split(':');
// adding an eventlistener to the element and triggering a method on the cetra object which is the executioner of the action
el.addEventListener(action, (e) => {
// exec is the action performer it checks
// if there is a command named like the action
// and if so it gives the action to the appropriate
// component
cetra.exec(method, varName, componentId, e);
});
}
}

113
lib/plugins/Timing.js Normal file
View File

@@ -0,0 +1,113 @@
import CetraPlugin from './CetraPlugin';
export default class Timing extends CetraPlugin {
static timers = new Map();
static animationFrameId;
static previousTimestamp;
#pluginName = 'timing';
#uniqueId;
constructor() {
super();
this.#uniqueId = Symbol('timer');
}
/**
* Clears all active timers.
*
* @static
* @memberof Cetra
* @returns {void}
*/
static #clearAllTimers() {
Cetra.timers.clear();
cancelAnimationFrame(Cetra.animationFrameId);
Cetra.animationFrameId = null;
}
/**
* gets called each tick the animationframe runs
* @memberof Cetra
* @static
* @method
* @param {Number} timestamp - the current timestamp of the animationframe
*/
static #update(timestamp) {
const elapsed = timestamp - Cetra.previousTimestamp;
Cetra.previousTimestamp = timestamp;
Cetra.timers.forEach((timer, timerId) => {
timer.timing -= elapsed;
if (timer.timing <= 0) {
timer.callback(elapsed / 1_000);
if (timer.loop) {
timer.timing = timer.interval;
} else {
Cetra.timers.delete(timerId);
}
}
});
if (Cetra.timers.size > 0) {
Cetra.animationFrameId = requestAnimationFrame(Cetra.update);
} else {
Cetra.animationFrameId = null;
}
}
register() {
Cetra.#clearAllTimers();
}
initComponent(el) {
// <div data-ctra-timer="name:delay:loops"></div>
}
/**
* Starts a timer with the specified callback function, interval, and loop flag.
*
* @static
* @memberof Cetra
* @param {Function} callback - The callback function to be executed on each timer tick.
* @param {number} interval - The interval (in milliseconds) between each timer tick.
* @param {boolean} [loop=false] - A flag indicating whether the timer should loop indefinitely.
* @returns {Symbol} The unique timer identifier.
*/
static startTimer(callback, interval, loop = false) {
const timerId = Symbol('timer');
Cetra.timers.set(timerId, {
callback,
interval,
loop,
timing: interval,
startTime: performance.now(),
});
if (!Cetra.animationFrameId) {
Cetra.previousTimestamp = performance.now();
Cetra.animationFrameId = requestAnimationFrame(Cetra.#update);
}
return timerId;
}
/**
* Clears the timer with the specified identifier.
*
* @static
* @memberof Cetra
* @param {Symbol} timerId - The unique identifier of the timer to be cleared.
* @returns {void}
*/
static clearTimer(timerId) {
Cetra.timers.delete(timerId);
if (Cetra.timers.size === 0) {
cancelAnimationFrame(Cetra.animationFrameId);
Cetra.animationFrameId = null;
}
}
}

26
lib/plugins/Utils.js Normal file
View File

@@ -0,0 +1,26 @@
import CetraPlugin from './CetraPlugin';
import Registry from '../core/Registry';
import Logger from '../core/Logger';
export default class Utils extends CetraPlugin {
#cetraIdentifier;
#pluginName = 'utils';
constructor(cetraId) {
super(cetraId);
this.#cetraIdentifier = cetraId;
}
register(cetraId) {}
initComponent(component) {}
increment(val, options = { amount: 1 }) {
console.log('increment', val, options);
const { amount } = options;
return val + amount;
}
increase(val, options = { amount: 1 }) {
return this.increment(val, options);
}
}