dees-domtools/ts/domtools.classes.domtools.ts
2021-11-26 15:26:15 +01:00

172 lines
5.3 KiB
TypeScript

import * as plugins from './domtools.plugins';
import { Stringmap } from '@pushrocks/lik/dist_ts/lik.stringmap';
import { FastMap } from '@pushrocks/lik/dist_ts/lik.fastmap';
import { TViewport } from './domtools.breakpoints';
import { Scroller } from './domtools.classes.scroller';
import { WebSetup } from '@pushrocks/websetup';
import { ThemeManager } from './domtools.classes.thememanager';
export interface IDomToolsState {
virtualViewport: TViewport;
}
export class DomTools {
// ======
// STATIC
// ======
/**
* setups domtools
*/
public static async setupDomTools() {
let domToolsInstance: DomTools;
if (!globalThis.deesDomTools) {
globalThis.deesDomTools = new DomTools();
domToolsInstance = globalThis.deesDomTools;
// lets make sure the dom is ready
const readyStateChangedFunc = () => {
if (document.readyState === 'interactive' || document.readyState === 'complete') {
domToolsInstance.elements.headElement = document.querySelector('head');
domToolsInstance.elements.bodyElement = document.querySelector('body');
domToolsInstance.domReady.resolve();
}
};
document.addEventListener('readystatechange', readyStateChangedFunc);
domToolsInstance.domToolsReady.resolve();
} else {
domToolsInstance = globalThis.deesDomTools;
}
await domToolsInstance.domToolsReady.promise;
return domToolsInstance;
}
/**
* if you can, use the static asysnc .setupDomTools() function instead since it is safer to use.
*/
public static getGlobalDomToolsSync(): DomTools {
const globalDomTools: DomTools = globalThis.deesDomTools;
if (!globalDomTools) {
throw new Error('You tried to access domtools synchronously too early');
}
return globalThis.deesDomTools;
}
// ========
// INSTANCE
// ========
// elements
public elements: {
headElement: HTMLElement;
bodyElement: HTMLElement;
} = {
headElement: null,
bodyElement: null,
};
public websetup: WebSetup = new WebSetup({
metaObject: {
title: 'loading...',
},
});
public smartstate = new plugins.smartstate.Smartstate();
public domToolsStatePart = this.smartstate.getStatePart<IDomToolsState>('domtools', {
virtualViewport: 'native',
});
public router = new plugins.smartrouter.SmartRouter({
debug: false,
});
public convenience = {
typedrequest: plugins.typedrequest,
smartdelay: plugins.smartdelay,
};
public deesComms = new plugins.deesComms.DeesComms();
public scroller = new plugins.SweetScroll({
/* some options */
}); // TODO: switch to scroller class
public themeManager = new ThemeManager(this);
/* private actionSetVirtualViewport = this.domToolsStatePart.createAction<TViewport>(
async (statePart, payload) => {
const currentState = statePart.getState();
currentState.virtualViewport = payload;
return currentState;
}
);
public setVirtualViewport(environmentArg: TViewport) {
this.domToolsStatePart.dispatchAction(this.actionSetVirtualViewport, environmentArg);
} */
public domToolsReady = plugins.smartpromise.defer();
public domReady = plugins.smartpromise.defer();
public globalStylesReady = plugins.smartpromise.defer();
constructor() {}
private runOnceTrackerStringMap = new Stringmap();
private runOnceResultMap = new FastMap();
/**
* run a function once and always get the Promise of the first execution
* @param identifierArg the indentifier arg identifies functions. functions with the same identifier are considered equal
* @param funcArg the actual func arg to run
*/
public async runOnce<T>(identifierArg: string, funcArg: () => Promise<T>) {
const runningId = `${identifierArg}+runningCheck`;
if (!this.runOnceTrackerStringMap.checkString(identifierArg)) {
this.runOnceTrackerStringMap.addString(identifierArg);
this.runOnceTrackerStringMap.addString(runningId);
const result = await funcArg();
this.runOnceResultMap.addToMap(identifierArg, result);
this.runOnceTrackerStringMap.removeString(runningId);
}
return await this.runOnceTrackerStringMap.registerUntilTrue(
(stringMap) => {
return !stringMap.includes(runningId);
},
() => {
return this.runOnceResultMap.getByKey(identifierArg);
}
);
}
// setStuff
/**
* allows to set global styles
* @param stylesText the css text you want to set
*/
public async setGlobalStyles(stylesText: string) {
await this.domReady.promise;
const styleElement = document.createElement('style');
styleElement.type = 'text/css';
styleElement.appendChild(document.createTextNode(stylesText));
this.elements.headElement.appendChild(styleElement);
}
/**
* allows setting external css files
* @param cssLinkArg a url to an external stylesheet
*/
public async setExternalCss(cssLinkArg: string) {
const cssTag = document.createElement('link');
cssTag.rel = 'stylesheet';
cssTag.crossOrigin = 'anonymous';
cssTag.href = cssLinkArg;
document.head.append(cssTag);
}
/**
* allows setting of website infos
* @param optionsArg the website info
*/
public async setWebsiteInfo(optionsArg: plugins.websetup.IWebSetupConstructorOptions) {
await this.websetup.setup(optionsArg);
await this.websetup.readyPromise;
}
}