From 54a08d33fa10f26522a99ad3dde8f12b4599b58e Mon Sep 17 00:00:00 2001 From: cipchk Date: Thu, 18 Jan 2024 20:02:46 +0800 Subject: [PATCH] chore: add loading etc.. components --- angular.json | 4 +-- packages/abc/down-file/down-file.directive.ts | 13 ++++---- .../global-footer-item.component.ts | 16 ++++++---- .../global-footer/global-footer.component.ts | 30 +++++++++---------- packages/abc/hotkey/hotkey.directive.ts | 16 +++++----- packages/abc/loading/loading.component.ts | 2 +- packages/abc/loading/loading.service.ts | 16 +++++----- packages/abc/lodop/lodop.service.ts | 9 +++--- packages/abc/media/media.component.ts | 27 ++++++++--------- .../abc/notice-icon/notice-icon.component.ts | 26 +++++++--------- packages/abc/observers/observer-size.ts | 15 +++++----- .../abc/onboarding/onboarding.component.ts | 19 +++++------- packages/abc/onboarding/onboarding.service.ts | 27 ++++++++--------- 13 files changed, 101 insertions(+), 119 deletions(-) diff --git a/angular.json b/angular.json index 10aa310e66..c9b93f9ef3 100644 --- a/angular.json +++ b/angular.json @@ -154,8 +154,8 @@ "codeCoverageExclude": ["schematics/**", "packages/testing/**"], "include": [ "./test.ts", - // "**/st.spec.ts" - "**/*.spec.ts" + "**/down-file.spec.ts" + // "**/*.spec.ts" ] } } diff --git a/packages/abc/down-file/down-file.directive.ts b/packages/abc/down-file/down-file.directive.ts index e62d669997..ac7c4371dd 100644 --- a/packages/abc/down-file/down-file.directive.ts +++ b/packages/abc/down-file/down-file.directive.ts @@ -7,11 +7,6 @@ import { saveAs } from 'file-saver'; import { _HttpClient } from '@delon/theme'; import type { NzSafeAny } from 'ng-zorro-antd/core/types'; -let isFileSaverSupported = false; -try { - isFileSaverSupported = !!new Blob(); -} catch {} - @Directive({ selector: '[down-file]', exportAs: 'downFile', @@ -45,9 +40,13 @@ export class DownFileDirective { }); return arr.reduce((_o, item) => item, {}); } + private isFileSaverSupported = false; constructor() { - if (!isFileSaverSupported) { + try { + this.isFileSaverSupported = !!new Blob(); + } catch {} + if (!this.isFileSaverSupported) { this.el.classList.add(`down-file__not-support`); } } @@ -59,7 +58,7 @@ export class DownFileDirective { } async _click(ev: MouseEvent): Promise { - if (!isFileSaverSupported || (typeof this.pre === 'function' && !(await this.pre(ev)))) { + if (!this.isFileSaverSupported || (typeof this.pre === 'function' && !(await this.pre(ev)))) { ev.stopPropagation(); ev.preventDefault(); return; diff --git a/packages/abc/global-footer/global-footer-item.component.ts b/packages/abc/global-footer/global-footer-item.component.ts index 63eddb5662..f7e86b072c 100644 --- a/packages/abc/global-footer/global-footer-item.component.ts +++ b/packages/abc/global-footer/global-footer-item.component.ts @@ -1,6 +1,12 @@ -import { ChangeDetectionStrategy, Component, Input, TemplateRef, ViewChild, ViewEncapsulation } from '@angular/core'; - -import { BooleanInput, InputBoolean } from '@delon/util/decorator'; +import { + ChangeDetectionStrategy, + Component, + Input, + TemplateRef, + ViewChild, + ViewEncapsulation, + booleanAttribute +} from '@angular/core'; @Component({ selector: 'global-footer-item', @@ -12,10 +18,8 @@ import { BooleanInput, InputBoolean } from '@delon/util/decorator'; standalone: true }) export class GlobalFooterItemComponent { - static ngAcceptInputType_blankTarget: BooleanInput; - @ViewChild('host', { static: true }) host!: TemplateRef; @Input() href?: string; - @Input() @InputBoolean() blankTarget?: boolean; + @Input({ transform: booleanAttribute }) blankTarget?: boolean; } diff --git a/packages/abc/global-footer/global-footer.component.ts b/packages/abc/global-footer/global-footer.component.ts index 6231a6a083..57ea3ffa2b 100644 --- a/packages/abc/global-footer/global-footer.component.ts +++ b/packages/abc/global-footer/global-footer.component.ts @@ -5,19 +5,18 @@ import { ChangeDetectorRef, Component, ContentChildren, - Inject, + DestroyRef, Input, OnInit, - Optional, QueryList, - ViewEncapsulation + ViewEncapsulation, + inject } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { DomSanitizer } from '@angular/platform-browser'; import { Router } from '@angular/router'; import { WINDOW } from '@delon/util/token'; -import type { NzSafeAny } from 'ng-zorro-antd/core/types'; import { GlobalFooterItemComponent } from './global-footer-item.component'; import { GlobalFooterLink } from './global-footer.types'; @@ -37,10 +36,17 @@ import { GlobalFooterLink } from './global-footer.types'; imports: [NgTemplateOutlet] }) export class GlobalFooterComponent implements OnInit { - private dir$ = this.directionality.change?.pipe(takeUntilDestroyed()); + private readonly router = inject(Router); + private readonly win = inject(WINDOW); + private readonly dom = inject(DomSanitizer); + private readonly directionality = inject(Directionality, { optional: true }); + private readonly cdr = inject(ChangeDetectorRef); + private readonly destroy$ = inject(DestroyRef); + + private dir$ = this.directionality?.change?.pipe(takeUntilDestroyed()); private _links: GlobalFooterLink[] = []; - dir: Direction = 'ltr'; + dir?: Direction = 'ltr'; @Input() set links(val: GlobalFooterLink[]) { @@ -53,14 +59,6 @@ export class GlobalFooterComponent implements OnInit { @ContentChildren(GlobalFooterItemComponent) readonly items!: QueryList; - constructor( - private router: Router, - @Inject(WINDOW) private win: NzSafeAny, - private dom: DomSanitizer, - @Optional() private directionality: Directionality, - private cdr: ChangeDetectorRef - ) {} - to(item: GlobalFooterLink | GlobalFooterItemComponent): void { if (!item.href) { return; @@ -77,8 +75,8 @@ export class GlobalFooterComponent implements OnInit { } ngOnInit(): void { - this.dir = this.directionality.value; - this.dir$.subscribe((direction: Direction) => { + this.dir = this.directionality?.value; + this.dir$?.pipe(takeUntilDestroyed(this.destroy$)).subscribe((direction: Direction) => { this.dir = direction; this.cdr.detectChanges(); }); diff --git a/packages/abc/hotkey/hotkey.directive.ts b/packages/abc/hotkey/hotkey.directive.ts index 914f4d78d4..487a0c686c 100644 --- a/packages/abc/hotkey/hotkey.directive.ts +++ b/packages/abc/hotkey/hotkey.directive.ts @@ -1,10 +1,14 @@ import { Platform } from '@angular/cdk/platform'; -import { Directive, ElementRef, Input, NgZone, OnDestroy } from '@angular/core'; +import { Directive, ElementRef, Input, NgZone, OnDestroy, inject } from '@angular/core'; import { install, uninstall } from '@github/hotkey'; @Directive({ selector: '[hotkey]', standalone: true }) export class HotkeyDirective implements OnDestroy { + private readonly el: HTMLElement = inject(ElementRef).nativeElement; + private readonly ngZone = inject(NgZone); + private readonly platform = inject(Platform); + /** * Specify [hotkey format](https://github.com/github/hotkey#hotkey-string-format) * @@ -14,18 +18,12 @@ export class HotkeyDirective implements OnDestroy { set hotkey(key: string) { if (!this.platform.isBrowser) return; - this.ngZone.runOutsideAngular(() => install(this.el.nativeElement, key)); + this.ngZone.runOutsideAngular(() => install(this.el, key)); } - constructor( - private el: ElementRef, - private ngZone: NgZone, - private platform: Platform - ) {} - ngOnDestroy(): void { if (!this.platform.isBrowser) return; - this.ngZone.runOutsideAngular(() => uninstall(this.el.nativeElement)); + this.ngZone.runOutsideAngular(() => uninstall(this.el)); } } diff --git a/packages/abc/loading/loading.component.ts b/packages/abc/loading/loading.component.ts index 5412213f5f..c8f9bc81cb 100644 --- a/packages/abc/loading/loading.component.ts +++ b/packages/abc/loading/loading.component.ts @@ -22,7 +22,7 @@ import { LoadingCustom, LoadingIcon, LoadingShowOptions } from './loading.types' }) export class LoadingDefaultComponent { options!: LoadingShowOptions; - dir: Direction = 'ltr'; + dir?: Direction = 'ltr'; get icon(): LoadingIcon { return this.options.icon!; diff --git a/packages/abc/loading/loading.service.ts b/packages/abc/loading/loading.service.ts index 3299b03732..fecb846096 100644 --- a/packages/abc/loading/loading.service.ts +++ b/packages/abc/loading/loading.service.ts @@ -1,7 +1,7 @@ import { Directionality } from '@angular/cdk/bidi'; import { Overlay, OverlayRef } from '@angular/cdk/overlay'; import { ComponentPortal } from '@angular/cdk/portal'; -import { ComponentRef, Injectable, OnDestroy, Optional } from '@angular/core'; +import { ComponentRef, Injectable, OnDestroy, inject } from '@angular/core'; import { Subject, Subscription, timer, debounce } from 'rxjs'; import { AlainConfigService, AlainLoadingConfig } from '@delon/util/config'; @@ -11,6 +11,10 @@ import { LoadingShowOptions } from './loading.types'; @Injectable({ providedIn: 'root' }) export class LoadingService implements OnDestroy { + private readonly overlay = inject(Overlay); + private readonly configSrv = inject(AlainConfigService); + private readonly directionality = inject(Directionality, { optional: true }); + private _overlayRef?: OverlayRef; private compRef: ComponentRef | null = null; private opt: LoadingShowOptions | null = null; @@ -22,12 +26,8 @@ export class LoadingService implements OnDestroy { return this.compRef != null ? this.compRef.instance : null; } - constructor( - private overlay: Overlay, - private configSrv: AlainConfigService, - @Optional() private directionality: Directionality - ) { - this.cog = configSrv.merge('loading', { + constructor() { + this.cog = this.configSrv.merge('loading', { type: 'spin', text: '加载中...', icon: { @@ -55,7 +55,7 @@ export class LoadingService implements OnDestroy { backdropClass: 'loading-backdrop' }); this.compRef = this._overlayRef.attach(new ComponentPortal(LoadingDefaultComponent)); - const dir = this.configSrv.get('loading')!.direction || this.directionality.value; + const dir = this.configSrv.get('loading')!.direction || this.directionality?.value; if (this.instance != null) { this.instance!!.options = this.opt; this.instance!!.dir = dir; diff --git a/packages/abc/lodop/lodop.service.ts b/packages/abc/lodop/lodop.service.ts index d82bddc3ea..e482dc9e5b 100644 --- a/packages/abc/lodop/lodop.service.ts +++ b/packages/abc/lodop/lodop.service.ts @@ -1,4 +1,4 @@ -import { Injectable, OnDestroy } from '@angular/core'; +import { Injectable, OnDestroy, inject } from '@angular/core'; import { Observable, of, Subject } from 'rxjs'; import { AlainConfigService, AlainLodopConfig } from '@delon/util/config'; @@ -9,6 +9,8 @@ import { Lodop, LodopPrintResult, LodopResult } from './lodop.types'; @Injectable({ providedIn: 'root' }) export class LodopService implements OnDestroy { + private readonly scriptSrv = inject(LazyService); + private defaultConfig: AlainLodopConfig; private _cog!: AlainLodopConfig; private pending = false; @@ -17,10 +19,7 @@ export class LodopService implements OnDestroy { private _events = new Subject(); private printBuffer: NzSafeAny[] = []; - constructor( - private scriptSrv: LazyService, - configSrv: AlainConfigService - ) { + constructor(configSrv: AlainConfigService) { this.defaultConfig = configSrv.merge('lodop', { url: '//localhost:8443/CLodopfuncs.js', name: 'CLODOP', diff --git a/packages/abc/media/media.component.ts b/packages/abc/media/media.component.ts index fc6b7d0311..c196d5141a 100644 --- a/packages/abc/media/media.component.ts +++ b/packages/abc/media/media.component.ts @@ -14,14 +14,15 @@ import { Renderer2, SimpleChange, ViewEncapsulation, - inject + inject, + numberAttribute } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { timer, take } from 'rxjs'; import type Plyr from 'plyr'; -import { InputNumber, NumberInput, ZoneOutside } from '@delon/util/decorator'; +import { ZoneOutside } from '@delon/util/decorator'; import type { NzSafeAny } from 'ng-zorro-antd/core/types'; import { MediaService } from './media.service'; @@ -41,30 +42,26 @@ export type MediaType = 'html5' | 'youtube' | 'video' | 'audio'; standalone: true }) export class MediaComponent implements OnChanges, AfterViewInit, OnDestroy { - static ngAcceptInputType_delay: NumberInput; + private readonly destroy$ = inject(DestroyRef); + private readonly el: HTMLElement = inject(ElementRef).nativeElement; + private readonly renderer = inject(Renderer2); + private readonly ngZone = inject(NgZone); + private readonly srv = inject(MediaService); + private readonly platform = inject(Platform); private _p?: Plyr | null; private videoEl?: HTMLElement; - private destroy$ = inject(DestroyRef); @Input() type: MediaType = 'video'; @Input() source?: string | Plyr.SourceInfo; @Input() options?: Plyr.Options; - @Input() @InputNumber() delay = 0; + @Input({ transform: numberAttribute }) delay = 0; @Output() readonly ready = new EventEmitter(); get player(): Plyr | undefined | null { return this._p; } - constructor( - private el: ElementRef, - private renderer: Renderer2, - private srv: MediaService, - private ngZone: NgZone, - private platform: Platform - ) {} - @ZoneOutside() private initDelay(): void { timer(this.delay) @@ -95,11 +92,11 @@ export class MediaComponent implements OnChanges, AfterViewInit, OnDestroy { private ensureElement(): void { const { type } = this; - let el = this.el.nativeElement.querySelector(type) as HTMLElement; + let el = this.el.querySelector(type) as HTMLElement; if (!el) { el = this.renderer.createElement(type); (el as HTMLVideoElement).controls = true; - this.el.nativeElement.appendChild(el); + this.el.appendChild(el); } this.videoEl = el; } diff --git a/packages/abc/notice-icon/notice-icon.component.ts b/packages/abc/notice-icon/notice-icon.component.ts index 99252a53a6..834377f822 100644 --- a/packages/abc/notice-icon/notice-icon.component.ts +++ b/packages/abc/notice-icon/notice-icon.component.ts @@ -9,12 +9,14 @@ import { OnDestroy, OnInit, Output, - ViewEncapsulation + ViewEncapsulation, + booleanAttribute, + inject, + numberAttribute } from '@angular/core'; import { Subscription } from 'rxjs'; import { DelonLocaleService, LocaleData } from '@delon/theme'; -import { BooleanInput, InputBoolean, InputNumber, NumberInput } from '@delon/util/decorator'; import { NzBadgeComponent } from 'ng-zorro-antd/badge'; import type { NgClassType } from 'ng-zorro-antd/core/types'; import { NzDropDownDirective, NzDropdownMenuComponent } from 'ng-zorro-antd/dropdown'; @@ -48,21 +50,18 @@ import { NoticeIconSelect, NoticeItem } from './notice-icon.types'; ] }) export class NoticeIconComponent implements OnInit, OnChanges, OnDestroy { - static ngAcceptInputType_count: NumberInput; - static ngAcceptInputType_loading: BooleanInput; - static ngAcceptInputType_popoverVisible: BooleanInput; - static ngAcceptInputType_centered: BooleanInput; - + private readonly i18n = inject(DelonLocaleService); + private readonly cdr = inject(ChangeDetectorRef); private i18n$!: Subscription; locale: LocaleData = {}; @Input() data: NoticeItem[] = []; - @Input() @InputNumber() count?: number; - @Input() @InputBoolean() loading = false; - @Input() @InputBoolean() popoverVisible = false; + @Input({ transform: numberAttribute }) count?: number; + @Input({ transform: booleanAttribute }) loading = false; + @Input({ transform: booleanAttribute }) popoverVisible = false; @Input() btnClass?: NgClassType; @Input() btnIconClass?: NgClassType; - @Input() @InputBoolean() centered = false; + @Input({ transform: booleanAttribute }) centered = false; @Output() readonly select = new EventEmitter(); @Output() readonly clear = new EventEmitter(); @Output() readonly popoverVisibleChange = new EventEmitter(); @@ -71,11 +70,6 @@ export class NoticeIconComponent implements OnInit, OnChanges, OnDestroy { return `header-dropdown notice-icon${!this.centered ? ' notice-icon__tab-left' : ''}`; } - constructor( - private i18n: DelonLocaleService, - private cdr: ChangeDetectorRef - ) {} - onVisibleChange(result: boolean): void { this.popoverVisibleChange.emit(result); } diff --git a/packages/abc/observers/observer-size.ts b/packages/abc/observers/observer-size.ts index 3d81d96a9f..54d1ae43f2 100644 --- a/packages/abc/observers/observer-size.ts +++ b/packages/abc/observers/observer-size.ts @@ -7,7 +7,8 @@ import { NgModule, NgZone, OnDestroy, - Output + Output, + inject } from '@angular/core'; import { Observable, Observer, Subject, Subscription } from 'rxjs'; @@ -84,15 +85,13 @@ export class SizeObserver implements OnDestroy { standalone: true }) export class ObserverSize implements AfterViewInit, OnDestroy { + private readonly _obs = inject(SizeObserver); + private readonly el: HTMLElement = inject(ElementRef).nativeElement; + private readonly ngZone = inject(NgZone); + private _sub$: Subscription | null = null; @Output('observeSize') readonly event = new EventEmitter(); - constructor( - private _obs: SizeObserver, - private el: ElementRef, - private ngZone: NgZone - ) {} - ngAfterViewInit(): void { if (!this._sub$) { this._sub(); @@ -101,7 +100,7 @@ export class ObserverSize implements AfterViewInit, OnDestroy { private _sub(): void { this._unsub(); - const stream = this._obs.observe(this.el.nativeElement); + const stream = this._obs.observe(this.el); this.ngZone.runOutsideAngular(() => { this._sub$ = stream.subscribe(this.event); }); diff --git a/packages/abc/onboarding/onboarding.component.ts b/packages/abc/onboarding/onboarding.component.ts index 60b4425535..da678b59e9 100644 --- a/packages/abc/onboarding/onboarding.component.ts +++ b/packages/abc/onboarding/onboarding.component.ts @@ -8,11 +8,10 @@ import { Component, ElementRef, EventEmitter, - Inject, OnDestroy, - Optional, ViewChild, - ViewEncapsulation + ViewEncapsulation, + inject } from '@angular/core'; import { NzButtonComponent } from 'ng-zorro-antd/button'; @@ -48,6 +47,11 @@ interface OnboardingLightData { imports: [NzPopoverDirective, NzStringTemplateOutletDirective, NzButtonComponent, NzNoAnimationDirective] }) export class OnboardingComponent implements OnDestroy, AfterViewInit { + private readonly el: HTMLElement = inject(ElementRef).nativeElement; + private readonly platform = inject(Platform); + private readonly cdr = inject(ChangeDetectorRef); + private readonly doc = inject(DOCUMENT); + private time: NzSafeAny; private prevSelectorEl?: HTMLElement; config!: OnboardingConfig; @@ -75,13 +79,6 @@ export class OnboardingComponent implements OnDestroy, AfterViewInit { return this._getDoc().defaultView || window; } - constructor( - private el: ElementRef, - @Optional() @Inject(DOCUMENT) private doc: NzSafeAny, - private platform: Platform, - private cdr: ChangeDetectorRef - ) {} - private getLightData(): OnboardingLightData | null { const doc = this._getDoc(); const win = this._getWin(); @@ -143,7 +140,7 @@ export class OnboardingComponent implements OnDestroy, AfterViewInit { return; } - const lightStyle = (this.el.nativeElement.querySelector('.onboarding__light') as HTMLElement).style; + const lightStyle = (this.el.querySelector('.onboarding__light') as HTMLElement).style; lightStyle.top = `${pos.top}px`; lightStyle.left = `${pos.left}px`; lightStyle.width = `${pos.width}px`; diff --git a/packages/abc/onboarding/onboarding.service.ts b/packages/abc/onboarding/onboarding.service.ts index 2c3bfb00f1..83193cb7a4 100644 --- a/packages/abc/onboarding/onboarding.service.ts +++ b/packages/abc/onboarding/onboarding.service.ts @@ -4,11 +4,10 @@ import { ApplicationRef, ComponentRef, EmbeddedViewRef, - Inject, Injectable, OnDestroy, - Optional, - createComponent + createComponent, + inject } from '@angular/core'; import { Router } from '@angular/router'; import { of, pipe, Subscription, delay, switchMap } from 'rxjs'; @@ -18,11 +17,19 @@ import { AlainConfigService } from '@delon/util/config'; import type { NzSafeAny } from 'ng-zorro-antd/core/types'; import { OnboardingComponent } from './onboarding.component'; -import { ONBOARDING_STORE_TOKEN, OnBoardingKeyStore } from './onboarding.storage'; +import { ONBOARDING_STORE_TOKEN } from './onboarding.storage'; import { OnboardingConfig, OnboardingItem, OnboardingOpType } from './onboarding.types'; @Injectable({ providedIn: 'root' }) export class OnboardingService implements OnDestroy { + private readonly i18n = inject(DelonLocaleService); + private readonly appRef = inject(ApplicationRef); + private readonly router = inject(Router); + private readonly doc = inject(DOCUMENT); + private readonly configSrv = inject(AlainConfigService); + private readonly keyStoreSrv = inject(ONBOARDING_STORE_TOKEN); + private readonly directionality = inject(Directionality, { optional: true }); + private compRef!: ComponentRef; private op$!: Subscription; private config?: OnboardingConfig; @@ -44,16 +51,6 @@ export class OnboardingService implements OnDestroy { return this._running; } - constructor( - private i18n: DelonLocaleService, - private appRef: ApplicationRef, - private router: Router, - @Inject(DOCUMENT) private doc: NzSafeAny, - private configSrv: AlainConfigService, - @Inject(ONBOARDING_STORE_TOKEN) private keyStoreSrv: OnBoardingKeyStore, - @Optional() private directionality: Directionality - ) {} - private attach(): void { const compRef = createComponent(OnboardingComponent, { environmentInjector: this.appRef.injector @@ -119,7 +116,7 @@ export class OnboardingService implements OnDestroy { ...this.i18n.getData('onboarding'), ...items[this.active] } as OnboardingItem; - const dir = this.configSrv.get('onboarding')!.direction || this.directionality.value; + const dir = this.configSrv.get('onboarding')!.direction || this.directionality?.value; Object.assign(this.compRef.instance, { item, config: this.config, active: this.active, max: items.length, dir }); const pipes = [ switchMap(() => (item.url ? this.router.navigateByUrl(item.url) : of(true))),