UNPKG

@thisissoon/angular-scrollspy

Version:

A simple lightweight library for Angular which automatically updates links to indicate the currently active section in the viewport

328 lines (319 loc) 9.51 kB
import { Directive, Input, HostBinding, ChangeDetectorRef, Injectable, ContentChildren, Component, NgModule } from '@angular/core'; import { InViewportModule } from '@thisissoon/angular-inviewport'; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * A directive used to add an `active` class to a nav item * when the section is in the viewport * * \@example * ```html * <a snScrollSpyItem for="foo" href="#section1">Section 1</a> * ``` * */ class ScrollSpyItemDirective { /** * Creates an instance of ScrollSpyItemDirective. * \@memberof ScrollSpyItemDirective * @param {?} cdRef */ constructor(cdRef) { this.cdRef = cdRef; /** * True if the nav item is the active item in the `items` list * for `ScrollSpyDirective` instance * * \@memberof ScrollSpyItemDirective */ this.active = false; /** * If true means the section is in the viewport * * \@memberof ScrollSpyItemDirective */ this.inViewport = false; } /** * Id of section that links navigates to * * \@readonly * \@memberof ScrollSpyItemDirective * @return {?} */ get section() { return this.href.replace('#', ''); } /** * Manually trigger change detection * * \@memberof ScrollSpyItemDirective * @return {?} */ detectChanges() { this.cdRef.detectChanges(); } } ScrollSpyItemDirective.decorators = [ { type: Directive, args: [{ selector: '[snScrollSpyItem]', },] } ]; /** @nocollapse */ ScrollSpyItemDirective.ctorParameters = () => [ { type: ChangeDetectorRef } ]; ScrollSpyItemDirective.propDecorators = { active: [{ type: HostBinding, args: ['class.active',] }], for: [{ type: Input }], href: [{ type: Input }] }; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * Service that stores a list of `Spy`'s and the state * of their nav items `inViewport` and `active` state * */ class ScrollSpyService { constructor() { /** * List of `Spy`'s * * \@memberof ScrollSpyService */ this.spys = []; /** * Stores requests to add items to spy when spy hasn't been created * yet. Once spy has been added then request will be made again. * * \@memberof ScrollSpyService */ this.buffer = []; } /** * Add spy to list of `spys` * * \@memberof ScrollSpyService * @param {?} id * @param {?} items * @return {?} */ addSpy(id, items) { this.spys.push({ id, items }); /** @type {?} */ const buffer = this.buffer.filter(i => i.spyId === id); this.buffer = this.buffer.filter(i => i.spyId !== id); buffer.forEach(i => this.setSpySectionStatus(i.sectionId, i.spyId, i.inViewport)); } /** * Remove spy from list of `spys` * * \@memberof ScrollSpyService * @param {?} id * @return {?} */ removeSpy(id) { /** @type {?} */ const i = this.spys.findIndex(s => s.id === id); this.spys.splice(i, 1); } /** * Set the `inViewport` status for a spy item then sets the active * to true for the first item in the list that has `inViewport` * set to true * * \@memberof ScrollSpyService * @param {?} sectionId * @param {?} spyId * @param {?} inViewport * @return {?} */ setSpySectionStatus(sectionId, spyId, inViewport) { /** @type {?} */ const spy = this.spys.find(s => s.id === spyId); if (!spy) { this.buffer.push({ sectionId, spyId, inViewport }); return; } /** @type {?} */ const item = spy.items.find(i => i.section === sectionId); if (!item) { return; } item.inViewport = inViewport; /** @type {?} */ const firstInViewport = spy.items.filter(i => i.inViewport)[0]; spy.items.forEach(i => (i.active = false)); if (firstInViewport) { firstInViewport.active = true; firstInViewport.detectChanges(); } } } ScrollSpyService.decorators = [ { type: Injectable } ]; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * Adds `active` class to navigation links when section is in the viewport. * Used in conjuction with `snScrollItem` directive which should be added * to anchor links in the nav * * \@example * ``` * <ul role="navigation" snScrollSpy id="foo"> * <li><a snScrollSpyItem for="foo" href="#section1">Section 1</a></li> * <li><a snScrollSpyItem for="foo" href="#section2">Section 2</a></li> * <li><a snScrollSpyItem for="foo" href="#section3">Section 3</a></li> * <li><a snScrollSpyItem for="foo" href="#section4">Section 4</a></li> * </ul> * ``` * */ class ScrollSpyDirective { /** * Creates an instance of ScrollSpyDirective. * \@memberof ScrollSpyDirective * @param {?} scrollSpySvc */ constructor(scrollSpySvc) { this.scrollSpySvc = scrollSpySvc; } /** * Adds spy to list of spys in `ScrollSpyService` * * \@memberof ScrollSpyDirective * @return {?} */ ngAfterViewInit() { this.scrollSpySvc.addSpy(this.id, this.items); } /** * Remove spy from list of spys when directive is destroyed * * \@memberof ScrollSpyDirective * @return {?} */ ngOnDestroy() { this.scrollSpySvc.removeSpy(this.id); } } ScrollSpyDirective.decorators = [ { type: Directive, args: [{ selector: '[snScrollSpy]', },] } ]; /** @nocollapse */ ScrollSpyDirective.ctorParameters = () => [ { type: ScrollSpyService } ]; ScrollSpyDirective.propDecorators = { items: [{ type: ContentChildren, args: [ScrollSpyItemDirective,] }], id: [{ type: Input }] }; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * A component to wrap section content within that will update the * `ScrollSpyService` when it's in view * * \@example * ```html * <sn-scroll-spy-section id="section1" for="foo"> * ... * </sn-scroll-spy-section> * ``` */ class ScrollSpySectionComponent { /** * Creates an instance of ScrollSpySectionComponent. * \@memberof ScrollSpySectionComponent * @param {?} scrollSpySvc */ constructor(scrollSpySvc) { this.scrollSpySvc = scrollSpySvc; } /** * Updates `ScrollSpy` section when element enters/leaves viewport * * \@memberof ScrollSpySectionComponent * @param {?} inViewport * @return {?} */ onInViewportChange(inViewport) { this.scrollSpySvc.setSpySectionStatus(this.id, this.for, inViewport); } } ScrollSpySectionComponent.decorators = [ { type: Component, args: [{ selector: 'sn-scroll-spy-section', template: "<div\n class=\"sn-hidden\"\n snInViewport\n (inViewportChange)=\"onInViewportChange($event)\">\n</div>\n<ng-content></ng-content>\n", styles: [":host{display:block;position:relative}.sn-hidden{bottom:0;left:0;opacity:0;position:absolute;right:0;top:0;z-index:-1}"] }] } ]; /** @nocollapse */ ScrollSpySectionComponent.ctorParameters = () => [ { type: ScrollSpyService } ]; ScrollSpySectionComponent.propDecorators = { id: [{ type: Input }], for: [{ type: Input }] }; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** @type {?} */ const directives = [ScrollSpyDirective, ScrollSpyItemDirective]; /** @type {?} */ const components = [ScrollSpySectionComponent]; /** @type {?} */ const providers = [ScrollSpyService]; /** * A simple lightweight library for Angular which automatically * updates links to indicate the currently active section in the viewport * */ class ScrollSpyModule { /** * Specify a static method for root module to ensure providers are * only provided once but allows the module to still be imported * into other modules without reproviding services. * * \@memberof ScrollSpyModule * @return {?} */ static forRoot() { return { ngModule: ScrollSpyModule, providers: [...providers], }; } } ScrollSpyModule.decorators = [ { type: NgModule, args: [{ imports: [InViewportModule], declarations: [...directives, ...components], exports: [...directives, ...components], },] } ]; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ export { ScrollSpyDirective, ScrollSpyItemDirective, ScrollSpySectionComponent, ScrollSpyService, ScrollSpyModule }; //# sourceMappingURL=thisissoon-angular-scrollspy.js.map