This repository has been archived on 2025-03-10. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
cetra/lib/core/Cetra.js

158 lines
3.8 KiB
JavaScript
Raw Normal View History

2023-11-19 16:32:20 +00:00
import Emitter from './Emitter';
import Logger from './Logger';
class Cetra extends Emitter {
// class static globals
static #instances = new Map();
static #uidIndex = new Set();
static #defaultSettings = new Map([
['selector', 'ctra'],
['root', document.body],
]);
2023-11-19 16:32:20 +00:00
#identifier;
#root;
2023-11-19 16:32:20 +00:00
#internals = new Map([
['settings', new Map()],
]);
/**
* Constructs a new instance of the Cetra framework.
* @class
* @classdesc The Cetra framework provides a reactive approach to DOM manipulation and component management.
* @param {Map} settings - A map object containing the framework settings.
*/
constructor(options = new Map()) {
super();
this.#identifier = this.uid();
if (!(options instanceof Map) && typeof options == 'object') {
options = new Map(Object.entries(options));
}
for (const key of Cetra.#defaultSettings.keys()) {
let value = options.get(key);
if (typeof value == 'undefined') {
value = Cetra.#defaultSettings.get(key);
}
this.#internals.get('settings').set(key, value);
}
for (const [key, cb] of options) {
if (!key.startsWith('on') || typeof cb != 'function') continue;
this.on(key, cb);
}
2023-11-19 16:32:20 +00:00
this.#init();
}
/**
* Retrieves an instance of Cetra by its ID.
* @param {string} id - The ID of the Cetra instance to retrieve.
* @returns {Cetra} The Cetra instance with the specified ID.
*/
static getInstance(id) {
return Cetra.#instances.get(id);
}
/**
* Initializes the Cetra framework by setting up the mutation observer and processing existing components.
* @memberof Cetra
* @instance
* @method
*/
#init() {
this.#root =
this.#internals.get('settings').get('root') ||
document.querySelector(this.#internals.get('settings').get('root'));
if (typeof this.#root == 'string') {
this.#root = document.querySelector(this.#root);
if (!this.#root) {
Logger.error('No root found, defaulting to body');
this.#root = document.body;
}
}
this.#registerDefaults();
this.#root.setAttribute(
`data-${this.#internals.get('settings').get('selector')}-id`,
this.#identifier
);
Cetra.#instances.set(this.#identifier, this);
this.emit('onAfterInit', this);
2023-11-19 16:32:20 +00:00
}
/**
* Registers default properties, transformer or anything related to the functionality
* @returns {void}
*/
#registerDefaults() {
}
/**
* checks if the given url is valid
* @param {String} url the url to check
* @returns {Boolean} true if the url is valid, false otherwise
*/
#isUrl(url) {
if (typeof url != 'string') return false;
try {
// if there is no error this should be a valid url
const urlObj = new URL(url, window.location.href);
return this.#internals.get('settings').get('enforceSecureUrls')
? urlObj.protocol === 'https:'
: true;
} catch (err) {
// any error is a bad url
return false;
}
}
/**
* Generates a (internally)unique identifier.
* @param {number} [numGroups=1] - The number of groups to generate.
* @param {number} [groupLength=6] - The length of each group.
* @memberof Cetra
* @method
* @returns {string} The unique identifier.
*/
uid(numGroups = 1, groupLength = 6) {
const usedIds = new Set(Cetra.#uidIndex.values());
let uid = undefined;
while (!uid || usedIds.has(uid)) {
uid = Array.from(Array(numGroups), () =>
Math.random()
.toString(36)
.substring(2, groupLength + 2)
).join('');
}
Cetra.#uidIndex.add(uid);
return uid;
}
/**
* Retrieves the value of the specified option from the framework's settings.
* @memberof Cetra
* @instance
* @method
* @param {string} option - The name of the option to retrieve.
* @returns {*} The value of the specified option.
*/
getOption(key) {
if (typeof key != 'string')
throw new Error('given key is not a string!');
return this.#internals
.get('settings')
.get(key.toString().toLowerCase());
}
}
export default Cetra;