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
JavaScript
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