ngx-multi-line-ellipsis
Version:
Angular directive for multi-line ellipsis
143 lines • 7.9 kB
JavaScript
import { Directive, ElementRef, Input, Renderer2 } from '@angular/core';
var NgxMultiLineEllipsisDirective = /** @class */ (function () {
function NgxMultiLineEllipsisDirective(el, renderer) {
this.el = el;
this.renderer = renderer;
}
NgxMultiLineEllipsisDirective.prototype.ngAfterViewInit = function () {
// Get element font size
var elementFontSize = parseInt(this.getCssproperty(this.el.nativeElement, 'font-size')
.split('px')[0], 10);
// Get element font family
var elementFontFamily = this.getCssproperty(this.el.nativeElement, 'font-family')
.split(',')[0];
// Get element width
var originalElementWidth = this.el.nativeElement.clientWidth;
// Remove the element from DOM
this.renderer.setStyle(this.el.nativeElement, 'display', 'none');
// Create a canvas element so it'd be possiable to measure expected width
var canvas = this.renderer.createElement('canvas');
var canvasContext = canvas.getContext('2d');
// Set the current font size and family for more accurate width
canvasContext.font = elementFontSize + "px " + elementFontFamily;
// Get element original text (will be replaced in future code lines)
var elementOriginalText = this.el.nativeElement.innerHTML.trim();
// Init final top element text
var topElementTextLines = '';
// Init final ellipsis text variable
var ellipsisTextLine = '';
// A flag veriable to indicate if current words num as reached
// the required lines num (minus one)
var hasReachedLimit = false;
var finishLoop = false;
// A veriable that holds current width (top element)
var currentTopElemetWidth = 0;
// A veriable that holds last text that has only complete words in it
// to aviod white spaces breaks
var completeWordsText = '';
// An array of letters (more accurate measurement by canvas method)
var allLetters = elementOriginalText.split('');
// Run on original text string
for (var i = 0; i < elementOriginalText.length && !finishLoop; i++) {
// Checks if current width is smaller than
// the max width for line times the lines to display minus one
if (currentTopElemetWidth < (originalElementWidth * (this.lines - 1)) &&
!hasReachedLimit) {
// Save the current text as previos text
var previosText = topElementTextLines;
// If the current char is 'Space' then it saves the current text
// as it has only complete words
if (elementOriginalText.charAt(i) &&
elementOriginalText.charAt(i) === ' ') {
completeWordsText = topElementTextLines;
}
// Add current char to current text
topElementTextLines =
topElementTextLines + elementOriginalText.charAt(i);
// Get the new current element width
currentTopElemetWidth += canvasContext.measureText(allLetters[i]).width;
if (elementOriginalText.charAt(i) &&
elementOriginalText.charAt(i) === '\n') {
currentTopElemetWidth -= canvasContext.measureText(allLetters[i]).width;
}
// Checks if current width is bigger or equal to
// the max width for line times the lines to display minus one
if (currentTopElemetWidth >= (originalElementWidth * (this.lines - 1))) {
// If the current char is 'Space' it gets
// the previos text as the final text
if (elementOriginalText.charAt(i) &&
elementOriginalText.charAt(i) === ' ') {
// Set previos text as the current element final text
topElementTextLines = previosText;
// Set the ellipsis text line with it's first char
ellipsisTextLine = elementOriginalText.charAt(i);
// Else if the current char is NOT 'Space' means there's a broken word
}
else {
// Set the complete words text string as the element final text
topElementTextLines = completeWordsText;
// Get the previos text (to get the last word taht we didn't included)
var previosTextSplitBySpaces = previosText.split(' ');
var previosLetter = previosTextSplitBySpaces[previosTextSplitBySpaces.length - 1] +
elementOriginalText.charAt(i);
ellipsisTextLine = previosLetter;
}
// Set flag to true so now it'll start to fill ellipsis element
hasReachedLimit = true;
// Set the ellipsis text line with it's first word and current char
}
// Finish to fill the top element
}
else {
// If Next char is 'Space' then saves the current string
// as complete words string
if (elementOriginalText.charAt(i + 1) &&
elementOriginalText.charAt(i + 1) === ' ') {
completeWordsText = topElementTextLines;
}
// Add current char to ellipsis text
ellipsisTextLine = ellipsisTextLine + elementOriginalText.charAt(i);
// Get the new current element width
currentTopElemetWidth += canvasContext.measureText(allLetters[i]).width;
if ((originalElementWidth * this.lines) - currentTopElemetWidth < -100) {
finishLoop = true;
}
}
}
// Create the top element to append
var topTextDiv = this.renderer.createElement('div');
var topText = this.renderer.createText(topElementTextLines.trim());
this.renderer.appendChild(topTextDiv, topText);
// Create the ellipsis elemet to append
var ellipsisDiv = this.renderer.createElement('div');
var ellipsisText = this.renderer.createText(ellipsisTextLine.trim());
this.renderer.setStyle(ellipsisDiv, 'overflow', 'hidden');
this.renderer.setStyle(ellipsisDiv, 'white-space', 'nowrap');
this.renderer.setStyle(ellipsisDiv, 'text-overflow', 'ellipsis');
this.renderer.appendChild(ellipsisDiv, ellipsisText);
// Append both elements to the original element
this.el.nativeElement.innerHTML = '';
this.renderer.appendChild(this.el.nativeElement, topTextDiv);
this.renderer.appendChild(this.el.nativeElement, ellipsisDiv);
this.renderer.setStyle(this.el.nativeElement, 'display', 'block');
};
NgxMultiLineEllipsisDirective.prototype.getCssproperty = function (element, property) {
return getComputedStyle(element, null).getPropertyValue(property);
};
NgxMultiLineEllipsisDirective.decorators = [
{ type: Directive, args: [{
selector: '[ngxEllipsis]'
},] },
];
/** @nocollapse */
NgxMultiLineEllipsisDirective.ctorParameters = function () { return [
{ type: ElementRef, },
{ type: Renderer2, },
]; };
NgxMultiLineEllipsisDirective.propDecorators = {
"lines": [{ type: Input },],
};
return NgxMultiLineEllipsisDirective;
}());
export { NgxMultiLineEllipsisDirective };
//# sourceMappingURL=ngx-multi-line-ellipsis.directive.js.map