UNPKG

@v4fire/client

Version:

V4Fire client core library

259 lines (207 loc) • 5.43 kB
/*! * V4Fire Client Core * https://github.com/V4Fire/Client * * Released under the MIT license * https://github.com/V4Fire/Client/blob/master/LICENSE */ /** * [[include:super/i-block/modules/activation/README.md]] * @packageDocumentation */ import symbolGenerator from 'core/symbol'; import { unwrap } from 'core/object/watch'; import { runHook, callMethodFromComponent } from 'core/component'; import type iBlock from 'super/i-block/i-block'; import { statuses } from 'super/i-block/const'; import { suspendRgxp, readyStatuses, inactiveStatuses, asyncNames, nonMuteAsyncLinkNames } from 'super/i-block/modules/activation/const'; export * from 'super/i-block/modules/activation/const'; export const $$ = symbolGenerator(); /** * Activates the component. * The deactivated component won't load data from providers on initializing. * * Basically, you don't need to think about a component activation, * because it's automatically synchronized with `keep-alive` or the special input property. * * @param component * @param [force] - if true, then the component will be forced to activate, even if it is already activated */ export function activate(component: iBlock, force?: boolean): void { const { unsafe, unsafe: {r, lfc, state, rootEmitter} } = component; const isBeforeCreate = lfc.isBeforeCreate(), canActivate = !unsafe.isActivated || force; if (canActivate) { if (isBeforeCreate) { state.initFromRouter(); } if (state.needRouterSync) { void lfc.execCbAfterComponentCreated(() => { rootEmitter.on('onTransition', handler, { label: $$.activate }); async function handler(route: typeof r.route, type: string): Promise<void> { try { if (type === 'hard') { const actualRoute = unwrap(r.route) ?? r.route; if (route !== actualRoute) { await unsafe.promisifyOnce('setRoute', { label: $$.activateAfterTransition }); } else { await unsafe.nextTick({ label: $$.activateAfterHardChange }); } } if (!inactiveStatuses[unsafe.componentStatus]) { state.initFromRouter(); } } catch (err) { stderr(err); } } }); } } if (isBeforeCreate) { return; } if (canActivate) { onActivated(component, true); runHook('activated', component).then(() => { callMethodFromComponent(component, 'activated'); }).catch(stderr); } const children = unsafe.$children; if (children != null) { for (let i = 0; i < children.length; i++) { children[i].unsafe.activate(true); } } } /** * Deactivates the component. * The deactivated component won't load data from providers on initializing. * * Basically, you don't need to think about a component activation, * because it's automatically synchronized with keep-alive or the special input property. * * @param component */ export function deactivate(component: iBlock): void { const {unsafe} = component; if (unsafe.lfc.isBeforeCreate()) { return; } if (unsafe.isActivated) { onDeactivated(component); runHook('deactivated', component).then(() => { callMethodFromComponent(component, 'deactivated'); }).catch(stderr); } const children = unsafe.$children; if (children != null) { for (let i = 0; i < children.length; i++) { children[i].unsafe.deactivate(); } } } /** * Hook handler: the component has been activated * * @param component * @param [force] - if true, then the component will be forced to activate, even if it is already activated */ export function onActivated(component: iBlock, force?: boolean): void { const {unsafe} = component; const cantActivate = unsafe.isActivated || !force && !unsafe.activatedProp && !unsafe.isReadyOnce; if (cantActivate) { return; } const async = [ unsafe.$async, unsafe.async ]; for (let i = 0; i < async.length; i++) { const $a = async[i]; $a.unmuteAll().unsuspendAll(); } if (unsafe.isReadyOnce && !readyStatuses[unsafe.componentStatus]) { unsafe.componentStatus = 'beforeReady'; } const needInitLoadOrReload = !unsafe.isReadyOnce && force || unsafe.reloadOnActivation; if (needInitLoadOrReload) { const group = {group: 'requestSync:get'}; for (let i = 0; i < async.length; i++) { const $a = async[i]; $a.clearAll(group).setImmediate(load, group); } } if (unsafe.isReadyOnce) { unsafe.componentStatus = 'ready'; } unsafe.state.initFromRouter(); unsafe.isActivated = true; function load(): void { const res = unsafe.isReadyOnce ? unsafe.reload() : unsafe.initLoad(); if (Object.isPromise(res)) { res.catch(stderr); } } } /** * Hook handler: the component has been deactivated * @param component */ export function onDeactivated(component: iBlock): void { const {unsafe} = component; const async = [ unsafe.$async, unsafe.async ]; for (let i = 0; i < async.length; i++) { const $a = async[i]; for (let keys = Object.keys(asyncNames), i = 0; i < keys.length; i++) { const key = keys[i]; if (nonMuteAsyncLinkNames[key]) { continue; } const fn = $a[`mute-${asyncNames[key]}`.camelize(false)]; if (Object.isFunction(fn)) { fn.call($a); } } $a.unmuteAll({group: suspendRgxp}).suspendAll(); } if (statuses[component.componentStatus] >= 2) { component.componentStatus = 'inactive'; } component.isActivated = false; }