UNPKG

ngx-line-truncation

Version:

Ngx Line Truncation is line truncation implementation for Angular that truncate text by user defined line number.

196 lines (190 loc) 7.89 kB
import * as i0 from '@angular/core'; import { EventEmitter, Directive, Input, Output, HostListener, NgModule } from '@angular/core'; import { getContentHeight, getLineHeight, truncate } from 'line-truncation'; import { BehaviorSubject, Subject } from 'rxjs'; import { skip, debounceTime } from 'rxjs/operators'; class LineTruncationDirective { constructor(elementRef, renderer) { this.elementRef = elementRef; this.renderer = renderer; this.lines = 1; this.options = { ellipsis: "\u2026" }; this.watchChanges = false; this.hasTruncated = new EventEmitter(); this.MAX_TRIES = 10; this.observerFlag = true; this._disabled$ = new BehaviorSubject(false); this.element = this.elementRef.nativeElement; this.windowResize$ = new Subject(); } set disabled(val) { this._disabled$.next(val); } handleClick(event) { this.windowResize$.next(event); } /** * Hide the original text content until we've finished the truncation */ ngOnInit() { this._disabled$.pipe(skip(1)).subscribe(disable => { // If there is elementClone, then recover if (!!this.elementClone) { this.putbackElement(); } if (disable) { // shut down listener, observer this.disconnectMutationObserver(); this.disconnectWindowLisener(); } else { // re-register this.truncationInit(); // re-execute truncation this.truncateWhenNecessary(this.element); } }); // first emit handling if (!this._disabled$.getValue()) { this.truncationInit(); } } ngAfterViewInit() { this.truncateWhenNecessary(this.element); } truncateWhenNecessary(element, tries = 1, maxTries = this.MAX_TRIES) { if (this._disabled$.getValue()) { return; } // backup original element before truncation this.elementClone = element.cloneNode(true); if (tries > maxTries) { return; } // Allows buffer period for DOM to be ready setTimeout(() => { // Recursively call the truncate itself if Client Height is not ready if (element.clientHeight > 0) { const contentHeight = getContentHeight(element); const lineHeight = getLineHeight(element); const targetHeight = this.lines * lineHeight; if (contentHeight > targetHeight) { try { truncate(element, this.lines, this.options.ellipsis, this.handler.bind(this)); } catch (e) { this.handler(true); } } else { // when there is no need, simply show the element, emit false and unsubscribe from MutationObserver if `watchChanges` prop was falsy this.handler(false); } } }, 100); } handler(e) { this.isTruncated = e; this.hasTruncated.emit(this.isTruncated); if (!this.watchChanges) { this.observerFlag = false; this.disconnectMutationObserver(); } this.renderer.removeStyle(this.element, "visibility"); } truncationInit() { this.renderer.setStyle(this.element, "visibility", "hidden"); this.initWindowResizeListener(this.element); this.initMutationObserver(this.element); } putbackElement() { // grab old child nodes const childNodes = Array.from(this.elementClone.childNodes); // clean element while (this.element.firstChild) { this.element.removeChild(this.element.firstChild); } // push child node to element shell childNodes.forEach(node => { this.element.appendChild(node); }); this.elementClone = null; } initWindowResizeListener(element) { this.windowListener = this.windowResize$ .pipe(debounceTime(500)) .subscribe(() => { this.renderer.setStyle(element, "visibility", "hidden"); this.putbackElement(); this.truncateWhenNecessary(element); }); } initMutationObserver(element) { this.mutationObserver = new MutationObserver(() => { if (this.observerFlag) { this.truncateWhenNecessary(element); } }); this.mutationObserver.observe(element, { childList: true }); } disconnectMutationObserver() { if (this.mutationObserver) { this.mutationObserver.disconnect(); } } disconnectWindowLisener() { if (this.windowListener) { this.windowListener.unsubscribe(); } } ngOnDestroy() { this._disabled$.complete(); this.disconnectMutationObserver(); this.disconnectWindowLisener(); } } LineTruncationDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0", ngImport: i0, type: LineTruncationDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive }); LineTruncationDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.0.0", type: LineTruncationDirective, selector: "[line-truncation]", inputs: { lines: ["line-truncation", "lines"], options: "options", disabled: "disabled", watchChanges: "watchChanges" }, outputs: { hasTruncated: "hasTruncated" }, host: { listeners: { "window:resize": "handleClick($event)" } }, exportAs: ["lineTruncation"], ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0", ngImport: i0, type: LineTruncationDirective, decorators: [{ type: Directive, args: [{ selector: "[line-truncation]", exportAs: "lineTruncation" }] }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.Renderer2 }]; }, propDecorators: { lines: [{ type: Input, args: ["line-truncation"] }], options: [{ type: Input }], disabled: [{ type: Input }], watchChanges: [{ type: Input }], hasTruncated: [{ type: Output }], handleClick: [{ type: HostListener, args: ["window:resize", ["$event"]] }] } }); class LineTruncationLibModule { } LineTruncationLibModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0", ngImport: i0, type: LineTruncationLibModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); LineTruncationLibModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.0.0", ngImport: i0, type: LineTruncationLibModule, declarations: [LineTruncationDirective], exports: [LineTruncationDirective] }); LineTruncationLibModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.0.0", ngImport: i0, type: LineTruncationLibModule }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0", ngImport: i0, type: LineTruncationLibModule, decorators: [{ type: NgModule, args: [{ declarations: [LineTruncationDirective], exports: [LineTruncationDirective], }] }] }); /* * Public API Surface of line-truncation-lib */ /** * Generated bundle index. Do not edit. */ export { LineTruncationDirective, LineTruncationLibModule }; //# sourceMappingURL=ngx-line-truncation.mjs.map