ng-zorro-antd
Version:
An enterprise-class UI components based on Ant Design and Angular
538 lines (531 loc) • 15.6 kB
JavaScript
import { Platform, PlatformModule } from '@angular/cdk/platform';
import { EventEmitter, Component, ViewEncapsulation, ChangeDetectionStrategy, Inject, ChangeDetectorRef, ViewChild, Input, Output, TemplateRef, ElementRef, Renderer2, ContentChild, NgModule } from '@angular/core';
import { __decorate, __metadata } from 'tslib';
import { DOCUMENT, CommonModule } from '@angular/common';
import { fromEvent } from 'rxjs';
import { throttleTime, distinctUntilChanged } from 'rxjs/operators';
import { toNumber, NzConfigService, NzScrollService, InputBoolean, WithConfig, InputNumber, SCROLL_SERVICE_PROVIDER } from 'ng-zorro-antd/core';
import { NzAffixModule } from 'ng-zorro-antd/affix';
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @record
*/
function Section() { }
if (false) {
/** @type {?} */
Section.prototype.comp;
/** @type {?} */
Section.prototype.top;
}
/** @type {?} */
const sharpMatcherRegx = /#([^#]+)$/;
class NzAnchorComponent {
/**
* @param {?} nzConfigService
* @param {?} scrollSrv
* @param {?} doc
* @param {?} cdr
* @param {?} platform
*/
constructor(nzConfigService, scrollSrv, doc, cdr, platform) {
this.nzConfigService = nzConfigService;
this.scrollSrv = scrollSrv;
this.doc = doc;
this.cdr = cdr;
this.platform = platform;
this.nzAffix = true;
this.nzClick = new EventEmitter();
this.nzScroll = new EventEmitter();
this.visible = false;
this.wrapperStyle = { 'max-height': '100vh' };
this.links = [];
this.animating = false;
this.target = null;
this.scroll$ = null;
this.destroyed = false;
}
/**
* @param {?} value
* @return {?}
*/
set nzOffsetTop(value) {
this._offsetTop = toNumber(value, 0);
this.wrapperStyle = {
'max-height': `calc(100vh - ${this._offsetTop}px)`
};
}
/**
* @return {?}
*/
get nzOffsetTop() {
return this._offsetTop;
}
/**
* @param {?} el
* @return {?}
*/
set nzTarget(el) {
this.target = typeof el === 'string' ? this.doc.querySelector(el) : el;
this.registerScrollEvent();
}
/**
* @param {?} link
* @return {?}
*/
registerLink(link) {
this.links.push(link);
}
/**
* @param {?} link
* @return {?}
*/
unregisterLink(link) {
this.links.splice(this.links.indexOf(link), 1);
}
/**
* @private
* @return {?}
*/
getTarget() {
return this.target || window;
}
/**
* @return {?}
*/
ngAfterViewInit() {
this.registerScrollEvent();
}
/**
* @return {?}
*/
ngOnDestroy() {
this.destroyed = true;
this.removeListen();
}
/**
* @private
* @return {?}
*/
registerScrollEvent() {
if (!this.platform.isBrowser) {
return;
}
this.removeListen();
this.scroll$ = fromEvent(this.getTarget(), 'scroll')
.pipe(throttleTime(50), distinctUntilChanged())
.subscribe((/**
* @return {?}
*/
() => this.handleScroll()));
// Browser would maintain the scrolling position when refreshing.
// So we have to delay calculation in avoid of getting a incorrect result.
setTimeout((/**
* @return {?}
*/
() => this.handleScroll()));
}
/**
* @private
* @return {?}
*/
removeListen() {
if (this.scroll$) {
this.scroll$.unsubscribe();
}
}
/**
* @private
* @param {?} element
* @return {?}
*/
getOffsetTop(element) {
if (!element || !element.getClientRects().length) {
return 0;
}
/** @type {?} */
const rect = element.getBoundingClientRect();
if (rect.width || rect.height) {
if (this.getTarget() === window) {
return rect.top - (/** @type {?} */ ((/** @type {?} */ (element.ownerDocument)).documentElement)).clientTop;
}
return rect.top - ((/** @type {?} */ (this.getTarget()))).getBoundingClientRect().top;
}
return rect.top;
}
/**
* @return {?}
*/
handleScroll() {
if (typeof document === 'undefined' || this.destroyed || this.animating) {
return;
}
/** @type {?} */
const sections = [];
/** @type {?} */
const scope = (this.nzOffsetTop || 0) + this.nzBounds;
this.links.forEach((/**
* @param {?} comp
* @return {?}
*/
comp => {
/** @type {?} */
const sharpLinkMatch = sharpMatcherRegx.exec(comp.nzHref.toString());
if (!sharpLinkMatch) {
return;
}
/** @type {?} */
const target = this.doc.getElementById(sharpLinkMatch[1]);
if (target) {
/** @type {?} */
const top = this.getOffsetTop(target);
if (top < scope) {
sections.push({
top,
comp
});
}
}
}));
this.visible = !!sections.length;
if (!this.visible) {
this.clearActive();
this.cdr.detectChanges();
}
else {
/** @type {?} */
const maxSection = sections.reduce((/**
* @param {?} prev
* @param {?} curr
* @return {?}
*/
(prev, curr) => (curr.top > prev.top ? curr : prev)));
this.handleActive(maxSection.comp);
}
}
/**
* @private
* @return {?}
*/
clearActive() {
this.links.forEach((/**
* @param {?} i
* @return {?}
*/
i => {
i.active = false;
i.markForCheck();
}));
}
/**
* @private
* @param {?} comp
* @return {?}
*/
handleActive(comp) {
this.clearActive();
comp.active = true;
comp.markForCheck();
/** @type {?} */
const linkNode = (/** @type {?} */ (((/** @type {?} */ (comp.elementRef.nativeElement))).querySelector('.ant-anchor-link-title')));
this.ink.nativeElement.style.top = `${linkNode.offsetTop + linkNode.clientHeight / 2 - 4.5}px`;
this.visible = true;
this.cdr.detectChanges();
this.nzScroll.emit(comp);
}
/**
* @param {?} linkComp
* @return {?}
*/
handleScrollTo(linkComp) {
/** @type {?} */
const el = this.doc.querySelector(linkComp.nzHref);
if (!el) {
return;
}
this.animating = true;
/** @type {?} */
const containerScrollTop = this.scrollSrv.getScroll(this.getTarget());
/** @type {?} */
const elOffsetTop = this.getOffsetTop(el);
/** @type {?} */
const targetScrollTop = containerScrollTop + elOffsetTop - (this.nzOffsetTop || 0);
this.scrollSrv.scrollTo(this.getTarget(), targetScrollTop, undefined, (/**
* @return {?}
*/
() => {
this.animating = false;
this.handleActive(linkComp);
}));
this.nzClick.emit(linkComp.nzHref);
}
}
NzAnchorComponent.decorators = [
{ type: Component, args: [{
selector: 'nz-anchor',
exportAs: 'nzAnchor',
preserveWhitespaces: false,
template: "<nz-affix *ngIf=\"nzAffix;else content\" [nzOffsetTop]=\"nzOffsetTop\">\n <ng-template [ngTemplateOutlet]=\"content\"></ng-template>\n</nz-affix>\n<ng-template #content>\n <div class=\"ant-anchor-wrapper\" [ngStyle]=\"wrapperStyle\">\n <div class=\"ant-anchor\" [ngClass]=\"{'fixed': !nzAffix && !nzShowInkInFixed}\">\n <div class=\"ant-anchor-ink\">\n <div class=\"ant-anchor-ink-ball\" [class.visible]=\"visible\" #ink></div>\n </div>\n <ng-content></ng-content>\n </div>\n </div>\n</ng-template>",
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
}] }
];
/** @nocollapse */
NzAnchorComponent.ctorParameters = () => [
{ type: NzConfigService },
{ type: NzScrollService },
{ type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] },
{ type: ChangeDetectorRef },
{ type: Platform }
];
NzAnchorComponent.propDecorators = {
ink: [{ type: ViewChild, args: ['ink', { static: false },] }],
nzAffix: [{ type: Input }],
nzShowInkInFixed: [{ type: Input }],
nzBounds: [{ type: Input }],
nzOffsetTop: [{ type: Input }],
nzTarget: [{ type: Input }],
nzClick: [{ type: Output }],
nzScroll: [{ type: Output }]
};
__decorate([
InputBoolean(),
__metadata("design:type", Object)
], NzAnchorComponent.prototype, "nzAffix", void 0);
__decorate([
WithConfig(false), InputBoolean(),
__metadata("design:type", Boolean)
], NzAnchorComponent.prototype, "nzShowInkInFixed", void 0);
__decorate([
WithConfig(5), InputNumber(),
__metadata("design:type", Number)
], NzAnchorComponent.prototype, "nzBounds", void 0);
__decorate([
WithConfig(),
__metadata("design:type", Number),
__metadata("design:paramtypes", [Number])
], NzAnchorComponent.prototype, "nzOffsetTop", null);
if (false) {
/**
* @type {?}
* @private
*/
NzAnchorComponent.prototype.ink;
/** @type {?} */
NzAnchorComponent.prototype.nzAffix;
/** @type {?} */
NzAnchorComponent.prototype.nzShowInkInFixed;
/** @type {?} */
NzAnchorComponent.prototype.nzBounds;
/**
* @type {?}
* @private
*/
NzAnchorComponent.prototype._offsetTop;
/** @type {?} */
NzAnchorComponent.prototype.nzClick;
/** @type {?} */
NzAnchorComponent.prototype.nzScroll;
/** @type {?} */
NzAnchorComponent.prototype.visible;
/** @type {?} */
NzAnchorComponent.prototype.wrapperStyle;
/**
* @type {?}
* @private
*/
NzAnchorComponent.prototype.links;
/**
* @type {?}
* @private
*/
NzAnchorComponent.prototype.animating;
/**
* @type {?}
* @private
*/
NzAnchorComponent.prototype.target;
/**
* @type {?}
* @private
*/
NzAnchorComponent.prototype.scroll$;
/**
* @type {?}
* @private
*/
NzAnchorComponent.prototype.destroyed;
/** @type {?} */
NzAnchorComponent.prototype.nzConfigService;
/**
* @type {?}
* @private
*/
NzAnchorComponent.prototype.scrollSrv;
/**
* @type {?}
* @private
*/
NzAnchorComponent.prototype.doc;
/**
* @type {?}
* @private
*/
NzAnchorComponent.prototype.cdr;
/**
* @type {?}
* @private
*/
NzAnchorComponent.prototype.platform;
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class NzAnchorLinkComponent {
/**
* @param {?} elementRef
* @param {?} anchorComp
* @param {?} cdr
* @param {?} platform
* @param {?} renderer
*/
constructor(elementRef, anchorComp, cdr, platform, renderer) {
this.elementRef = elementRef;
this.anchorComp = anchorComp;
this.cdr = cdr;
this.platform = platform;
this.nzHref = '#';
this.titleStr = '';
this.active = false;
renderer.addClass(elementRef.nativeElement, 'ant-anchor-link');
}
/**
* @param {?} value
* @return {?}
*/
set nzTitle(value) {
if (value instanceof TemplateRef) {
this.titleStr = null;
this.titleTpl = value;
}
else {
this.titleStr = value;
}
}
/**
* @return {?}
*/
ngOnInit() {
this.anchorComp.registerLink(this);
}
/**
* @param {?} e
* @return {?}
*/
goToClick(e) {
e.preventDefault();
e.stopPropagation();
if (this.platform.isBrowser) {
this.anchorComp.handleScrollTo(this);
}
}
/**
* @return {?}
*/
markForCheck() {
this.cdr.markForCheck();
}
/**
* @return {?}
*/
ngOnDestroy() {
this.anchorComp.unregisterLink(this);
}
}
NzAnchorLinkComponent.decorators = [
{ type: Component, args: [{
selector: 'nz-link',
exportAs: 'nzLink',
preserveWhitespaces: false,
template: "<a (click)=\"goToClick($event)\" href=\"{{nzHref}}\" class=\"ant-anchor-link-title\" title=\"{{titleStr}}\">\n <span *ngIf=\"titleStr; else (titleTpl || nzTemplate)\">{{ titleStr }}</span>\n</a>\n<ng-content></ng-content>",
host: {
'[class.ant-anchor-link-active]': 'active'
},
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
styles: [`
nz-link {
display: block;
}
`]
}] }
];
/** @nocollapse */
NzAnchorLinkComponent.ctorParameters = () => [
{ type: ElementRef },
{ type: NzAnchorComponent },
{ type: ChangeDetectorRef },
{ type: Platform },
{ type: Renderer2 }
];
NzAnchorLinkComponent.propDecorators = {
nzHref: [{ type: Input }],
nzTitle: [{ type: Input }],
nzTemplate: [{ type: ContentChild, args: ['nzTemplate', { static: false },] }]
};
if (false) {
/** @type {?} */
NzAnchorLinkComponent.prototype.nzHref;
/** @type {?} */
NzAnchorLinkComponent.prototype.titleStr;
/** @type {?} */
NzAnchorLinkComponent.prototype.titleTpl;
/** @type {?} */
NzAnchorLinkComponent.prototype.active;
/** @type {?} */
NzAnchorLinkComponent.prototype.nzTemplate;
/** @type {?} */
NzAnchorLinkComponent.prototype.elementRef;
/**
* @type {?}
* @private
*/
NzAnchorLinkComponent.prototype.anchorComp;
/**
* @type {?}
* @private
*/
NzAnchorLinkComponent.prototype.cdr;
/**
* @type {?}
* @private
*/
NzAnchorLinkComponent.prototype.platform;
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class NzAnchorModule {
}
NzAnchorModule.decorators = [
{ type: NgModule, args: [{
declarations: [NzAnchorComponent, NzAnchorLinkComponent],
exports: [NzAnchorComponent, NzAnchorLinkComponent],
imports: [CommonModule, NzAffixModule, PlatformModule],
providers: [SCROLL_SERVICE_PROVIDER]
},] }
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
export { NzAnchorComponent, NzAnchorLinkComponent, NzAnchorModule };
//# sourceMappingURL=ng-zorro-antd-anchor.js.map