@v4fire/client
Version:
V4Fire client core library
209 lines (174 loc) • 4.91 kB
text/typescript
/*!
* V4Fire Client Core
* https://github.com/V4Fire/Client
*
* Released under the MIT license
* https://github.com/V4Fire/Client/blob/master/LICENSE
*/
/**
* [[include:super/i-page/README.md]]
* @packageDocumentation
*/
import symbolGenerator from 'core/symbol';
import iVisible from 'traits/i-visible/i-visible';
import iData, { component, prop, system, computed, watch, hook, ModsDecl } from 'super/i-data/i-data';
import type { TitleValue, StageTitles, ScrollOptions, DescriptionValue } from 'super/i-page/interface';
export * from 'super/i-data/i-data';
export * from 'super/i-page/interface';
export const
$$ = symbolGenerator();
/**
* Superclass for all page components
*/
({inheritMods: false})
export default abstract class iPage extends iData implements iVisible {
override readonly reloadOnActivation: boolean = true;
override readonly syncRouterStoreOnInit: boolean = true;
/** @see [[iVisible.prototype.hideIfOffline]] */
(Boolean)
readonly hideIfOffline: boolean = false;
/**
* An initial page title.
* Basically this title is set via `document.title`.
*/
({type: [String, Function]})
readonly pageTitleProp: TitleValue = '';
/**
* An initial page title.
* Basically this title is set via `document.title`.
*/
({type: [String, Function]})
readonly pageDescriptionProp: DescriptionValue = '';
/**
* A dictionary of page titles (basically these titles are set via `document.title`).
* The dictionary values are tied to the `stage` values.
*
* A key with the name `[[DEFAULT]]` is used by default. If a key value is defined as a function,
* it will be invoked (the result will be used as a title).
*/
({type: Object, required: false})
readonly stagePageTitles?: StageTitles<this>;
/**
* Current page title
*
* @see [[iPage.pageTitleProp]]
* @see [[iPage.stagePageTitles]]
*/
({cache: false})
get pageTitle(): string {
return this.r.PageMetaData.title;
}
/**
* Sets a new page title.
* Basically this title is set via `document.title`.
*/
set pageTitle(value: string) {
if (this.isActivated) {
this.r.PageMetaData.title = value;
}
}
/**
* A wrapped version of the `scrollTo` method.
* The calling cancels all previous tasks.
*
* @see [[iPage.scrollTo]]
*/
({cache: true})
get scrollToProxy(): this['scrollTo'] {
return (...args) => {
this.async.setImmediate(() => this.scrollTo(...args), {
label: $$.scrollTo
});
};
}
static override readonly mods: ModsDecl = {
...iVisible.mods
};
/**
* Page title store
*/
((o) => o.sync.link((v) => Object.isFunction(v) ? v(o) : v))
protected pageTitleStore!: string;
/**
* Page description store
*/
((o) => o.sync.link((v) => Object.isFunction(v) ? v(o) : v))
protected pageDescriptionStore!: string;
/**
* Scrolls a page by the specified options
* @param opts
*/
scrollTo(opts: ScrollOptions): void;
/**
* Scrolls a page to the specified coordinates
*
* @param x
* @param y
*/
scrollTo(x?: number, y?: number): void;
scrollTo(p?: ScrollOptions | number, y?: number): void {
this.async.cancelProxy({label: $$.scrollTo});
const scroll = (opts: ScrollToOptions) => {
try {
globalThis.scrollTo(opts);
} catch {
globalThis.scrollTo(opts.left == null ? pageXOffset : opts.left, opts.top == null ? pageYOffset : opts.top);
}
};
if (Object.isPlainObject(p)) {
scroll({left: p.x, top: p.y, ...Object.reject(p, ['x', 'y'])});
} else {
scroll({left: p, top: y});
}
}
override activate(force?: boolean): void {
this.setRootMod('active', true);
super.activate(force);
}
override deactivate(): void {
this.setRootMod('active', false);
super.deactivate();
}
/**
* Synchronization for the `stagePageTitles` field
*/
('!:onStageChange')
protected syncStageTitles(): CanUndef<string> {
const
stageTitles = this.stagePageTitles;
if (stageTitles == null) {
return;
}
if (this.stage != null) {
let
v = stageTitles[this.stage];
if (v == null) {
v = stageTitles['[[DEFAULT]]'];
}
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (v != null) {
return this.r.PageMetaData.title = Object.isFunction(v) ? v(this) : v;
}
}
}
/**
* Initializes a custom page title
*/
(['created', 'activated'])
protected initPageMetaData(): void {
if (this.syncStageTitles() == null && Object.isTruly(this.pageTitleStore)) {
this.r.PageMetaData.title = this.pageTitleStore;
}
if (Object.isTruly(this.pageDescriptionStore)) {
this.r.PageMetaData.description = this.pageDescriptionStore;
}
}
protected override initModEvents(): void {
super.initModEvents();
iVisible.initModEvents(this);
}
protected override beforeDestroy(): void {
this.removeRootMod('active');
super.beforeDestroy();
}
}