{"version":3,"file":"ellipsis-angular.mjs","sources":["../../../projects/ellipsis-angular/src/lib/ellipsis-angular.service.ts","../../../projects/ellipsis-angular/src/lib/ellipsis-angular.directive.ts","../../../projects/ellipsis-angular/src/lib/ellipsis-angular.module.ts","../../../projects/ellipsis-angular/src/public-api.ts","../../../projects/ellipsis-angular/src/ellipsis-angular.ts"],"sourcesContent":["import { Injectable } from '@angular/core';\n\n@Injectable({\n  providedIn: 'root',\n})\nexport class EllipsisAngularService {\n  constructor() {}\n}\n","import {\n  AfterViewInit,\n  OnChanges,\n  Directive,\n  ElementRef,\n  HostListener,\n  Input,\n  SecurityContext,\n  SimpleChanges,\n} from '@angular/core';\nimport { DomSanitizer } from '@angular/platform-browser';\n\n@Directive({\n  selector: '[ellipsis-angular]',\n})\nexport class EllipsisAngularDirective implements OnChanges, AfterViewInit {\n  @Input() innerHTML?: string;\n\n  private ellipsisSymbol = '&hellip;';\n  private ellipsisSeparator = ' ';\n  private ellipsisSeparatorReg = new RegExp('[' + this.ellipsisSeparator + ']+', 'gm');\n  private unclosedHTMLTagMatcher = /<[^>]*$/;\n  private lastWindowResizeWidth: number = 0;\n  private lastWindowResizeHeight: number = 0;\n  private resizeObserver!: ResizeObserver;\n\n  constructor(private el: ElementRef, private sanitizer: DomSanitizer) {\n    this.resizeObserver = new ResizeObserver(() => {\n      this.ellipsis();\n    });\n  }\n\n  private trustAsHtml(text: string): string | null {\n    return this.sanitizer.sanitize(SecurityContext.HTML, text);\n  }\n\n  private ellipsis() {\n    setTimeout(() => {\n      const domElement = this.el.nativeElement;\n      let trustedHtml = this.trustAsHtml(this.innerHTML ? this.innerHTML : '');\n\n      if (trustedHtml) {\n        domElement.innerHTML = trustedHtml;\n        // When the text has overflow\n        if (this.isOverflowed()) {\n          const initialMaxHeight = domElement.clientHeight;\n          const initialMaxWidth = domElement.clientWidth;\n          const separatorLocations = [];\n\n          let match;\n          // tslint:disable-next-line:no-conditional-assignment\n          while ((match = this.ellipsisSeparatorReg.exec(trustedHtml)) !== null) {\n            separatorLocations.push(match.index);\n          }\n\n          // We know the text overflows and there are no natural breakpoints so we build a new index\n          // With this index it will search for the best truncate location instead of for the best ellipsisSeparator location\n          if (separatorLocations.length === 0) {\n            let textLength = 5;\n            while (textLength <= trustedHtml.length) {\n              separatorLocations.push(textLength);\n              textLength += 5;\n            }\n            separatorLocations.push(trustedHtml.length);\n          }\n          let lowerBound = 0;\n          let upperBound = separatorLocations.length - 1;\n          let textCutOffIndex, range;\n          // Loop while upper bound and lower bound are not confined to the smallest range yet\n          while (true) {\n            // This is an implementation of a binary search as we try to find the overflow position as quickly as possible\n            range = upperBound - lowerBound;\n            // tslint:disable-next-line:no-bitwise\n            textCutOffIndex = lowerBound + (range >> 1);\n            if (range <= 1) {\n              break;\n            } else {\n              if (\n                this.fastIsOverflowing(\n                  this.getTextUpToIndex(trustedHtml, separatorLocations, textCutOffIndex) + this.ellipsisSymbol,\n                  initialMaxHeight,\n                  initialMaxWidth\n                )\n              ) {\n                // The match was in the lower half, excluding the previous upper part\n                upperBound = textCutOffIndex;\n              } else {\n                // The match was in the upper half, excluding the previous lower part\n                lowerBound = textCutOffIndex;\n              }\n            }\n          }\n          // We finished the search now we set the new text through the correct trustedHtml api\n          domElement.innerHTML =\n            this.getTextUpToIndex(trustedHtml, separatorLocations, textCutOffIndex) + this.ellipsisSymbol;\n\n          //Set data-overflow class on element for css stying\n          domElement.classList.add('ellipsis-angular-overflowed');\n        } else {\n          domElement.classList.remove('ellipsis-angular-overflowed');\n        }\n      } else if (trustedHtml === '') {\n        domElement.innerHTML = '';\n        domElement.classList.remove('ellipsis-angular-overflowed');\n      }\n    });\n  }\n\n  private isOverflowed(): boolean {\n    const elDomNode = this.el.nativeElement;\n    return elDomNode.scrollHeight > elDomNode.clientHeight || elDomNode.scrollWidth > elDomNode.clientWidth;\n  }\n\n  private fastIsOverflowing(text: string, initialMaxHeight: number, initialMaxWidth: number): boolean {\n    const elDomNode = this.el.nativeElement;\n    elDomNode.innerHTML = text;\n    return elDomNode.scrollHeight > initialMaxHeight || elDomNode.scrollWidth > initialMaxWidth;\n  }\n\n  private getTextUpToIndex(htmlText: string, separatorLocations: number[], index: number): string {\n    return htmlText.substring(0, separatorLocations[index]).replace(this.unclosedHTMLTagMatcher, '');\n  }\n\n  @HostListener('window:resize', ['$event'])\n  onResize() {\n    if (this.lastWindowResizeWidth !== window.innerWidth || this.lastWindowResizeHeight !== window.innerHeight) {\n      this.ellipsis();\n    }\n\n    this.lastWindowResizeWidth = window.innerWidth;\n    this.lastWindowResizeHeight = window.innerHeight;\n  }\n\n  ngOnChanges(changes: SimpleChanges) {\n    if ('innerHTML' in changes) {\n      this.ellipsis();\n    }\n  }\n\n  ngAfterViewInit() {\n    if (this.innerHTML === undefined && this.el.nativeElement.innerHTML !== '') {\n      this.innerHTML = this.el.nativeElement.innerHTML;\n      this.ellipsis();\n    }\n    this.resizeObserver.observe(this.el.nativeElement);\n  }\n}\n","import { NgModule } from '@angular/core';\nimport { EllipsisAngularDirective } from './ellipsis-angular.directive';\n\n@NgModule({\n  declarations: [EllipsisAngularDirective],\n  imports: [],\n  exports: [EllipsisAngularDirective],\n})\nexport class EllipsisAngularModule {}\n","/*\n * Public API Surface of ellipsis-angular\n */\n\nexport * from './lib/ellipsis-angular.service';\nexport * from './lib/ellipsis-angular.directive';\nexport * from './lib/ellipsis-angular.module';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}