/
githubmirror
/
anime
Обзор
Документация
Войти
/
githubmirror
/
anime
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
4.0.0
src/scope.js
209 строк
5 KB
Julian Garnier
v4.0.0
03 апр 2025, 16:31
03 апр 2025, 16:31
66cfea7
Код
Авторство
О чём код?
/// <reference path='./types.js' /> import { doc, win, } from './consts.js'; import { globals, } from './globals.js'; import { isFnc, mergeObjects, } from './helpers.js'; import { parseTargets, } from './targets.js'; /** * @typedef {Object} ReactRef * @property {HTMLElement|SVGElement} [current] */ /** * @typedef {Object} AngularRef * @property {HTMLElement|SVGElement} [nativeElement] */ /** * @typedef {Object} ScopeParams * @property {DOMTargetSelector|ReactRef|AngularRef} [root] * @property {DefaultsParams} [defaults] * @property {Record<String, String>} [mediaQueries] */ /** * @callback ScopeCleanup * @param {Scope} [scope] */ /** * @callback ScopeConstructor * @param {Scope} [scope] * @return {ScopeCleanup|void} */ /** * @callback ScopeMethod * @param {...*} args * @return {ScopeCleanup|void} */ export class Scope { /** @param {ScopeParams} [parameters] */ constructor(parameters = {}) { if (globals.scope) globals.scope.revertibles.push(this); const rootParam = parameters.root; /** @type {Document|DOMTarget} */ let root = doc; if (rootParam) { root = /** @type {ReactRef} */(rootParam).current || /** @type {AngularRef} */(rootParam).nativeElement || parseTargets(/** @type {DOMTargetSelector} */(rootParam))[0] || doc; } const scopeDefaults = parameters.defaults; const globalDefault = globals.defaults; const mediaQueries = parameters.mediaQueries; /** @type {DefaultsParams} */ this.defaults = scopeDefaults ? mergeObjects(scopeDefaults, globalDefault) : globalDefault; /** @type {Document|DOMTarget} */ this.root = root; /** @type {Array<ScopeConstructor>} */ this.constructors = []; /** @type {Array<Function>} */ this.revertConstructors = []; /** @type {Array<Revertible>} */ this.revertibles = []; /** @type {Record<String, Function>} */ this.methods = {}; /** @type {Record<String, Boolean>} */ this.matches = {}; /** @type {Record<String, MediaQueryList>} */ this.mediaQueryLists = {}; /** @type {Record<String, any>} */ this.data = {}; if (mediaQueries) { for (let mq in mediaQueries) { const _mq = win.matchMedia(mediaQueries[mq]); this.mediaQueryLists[mq] = _mq; _mq.addEventListener('change', this); } } } /** * @callback ScoppedCallback * @param {this} scope * @return {any} * * @param {ScoppedCallback} cb * @return {this} */ execute(cb) { let activeScope = globals.scope; let activeRoot = globals.root; let activeDefaults = globals.defaults; globals.scope = this; globals.root = this.root; globals.defaults = this.defaults; const mqs = this.mediaQueryLists; for (let mq in mqs) this.matches[mq] = mqs[mq].matches; const returned = cb(this); globals.scope = activeScope; globals.root = activeRoot; globals.defaults = activeDefaults; return returned; } /** * @return {this} */ refresh() { this.execute(() => { let i = this.revertibles.length; let y = this.revertConstructors.length; while (i--) this.revertibles[i].revert(); while (y--) this.revertConstructors[y](this); this.revertibles.length = 0; this.revertConstructors.length = 0; this.constructors.forEach( constructor => { const revertConstructor = constructor(this); if (revertConstructor) { this.revertConstructors.push(revertConstructor); } }); }); return this; } /** * @callback contructorCallback * @param {this} self * * @overload * @param {String} a1 * @param {ScopeMethod} a2 * @return {this} * * @overload * @param {contructorCallback} a1 * @return {this} * * @param {String|contructorCallback} a1 * @param {ScopeMethod} [a2] */ add(a1, a2) { if (isFnc(a1)) { const constructor = /** @type {contructorCallback} */(a1); this.constructors.push(constructor); this.execute(() => { const revertConstructor = constructor(this); if (revertConstructor) { this.revertConstructors.push(revertConstructor); } }); } else { this.methods[/** @type {String} */(a1)] = (/** @type {any} */...args) => this.execute(() => a2(...args)); } return this; } /** * @param {Event} e */ handleEvent(e) { switch (e.type) { case 'change': this.refresh(); break; } } revert() { const revertibles = this.revertibles; const revertConstructors = this.revertConstructors; const mqs = this.mediaQueryLists; let i = revertibles.length; let y = revertConstructors.length; while (i--) revertibles[i].revert(); while (y--) revertConstructors[y](this); for (let mq in mqs) mqs[mq].removeEventListener('change', this); revertibles.length = 0; revertConstructors.length = 0; this.constructors.length = 0; this.matches = {}; this.methods = {}; this.mediaQueryLists = {}; this.data = {}; } } /** * @param {ScopeParams} [params] * @return {Scope} */ export const createScope = params => new Scope(params);