diff --git a/src/angular-ellipsis.js b/src/angular-ellipsis.js index 1c5eb12..b7fd512 100644 --- a/src/angular-ellipsis.js +++ b/src/angular-ellipsis.js @@ -130,26 +130,15 @@ angular.module('dibari.angular-ellipsis', []) //Set data-overflow on element for targeting element.attr('data-overflowed', 'true'); - // Set complete text and remove one word at a time, until there is no overflow - for (; i < bindArrayStartingLength; i++) { - var current = bindArray.pop(); - - //if the last string still overflowed, then truncate the last string - if (bindArray.length === 0) { - bindArray[0] = current.substring(0, Math.min(current.length, 5)); - } - - if (isHtml) { - element.html(bindArray.join(ellipsisSeparator) + appendString); - } else { - element.text(bindArray.join(ellipsisSeparator)).html(element.html() + appendString); - } - - if ((scope.useParent ? element.parent()[0] : element[0]).scrollHeight < initialMaxHeight || isOverflowed(element, scope.useParent) === false) { - attributes.isTruncated = true; - break; - } - } + const leastUpperBound = calculateLeastUpperBound(element, bindArray, ellipsisSeparator, appendString, isHtml, scope, initialMaxHeight); + + if (isHtml) { + element.html(bindArray.slice(0, leastUpperBound).join(ellipsisSeparator) + appendString); + } else { + element.text(bindArray.slice(0, leastUpperBound).join(ellipsisSeparator)).html(element.html() + appendString); + } + + attributes.isTruncated = true; // If append string was passed and append click function included if (ellipsisSymbol != appendString && typeof(scope.ellipsisAppendClick) !== 'undefined' && scope.ellipsisAppendClick !== '') { @@ -186,6 +175,40 @@ angular.module('dibari.angular-ellipsis', []) return thisElement[0].scrollHeight > thisElement[0].clientHeight; } + function doesItFit(guess, element, bindArray, ellipsisSeparator, appendString, isHtml, scope, initialMaxHeight){ + if (isHtml) { + element.html(bindArray.slice(0, guess).join(ellipsisSeparator) + appendString); + } else { + element.text(bindArray.slice(0, guess).join(ellipsisSeparator)).html(element.html() + appendString); + } + + return ((scope.useParent ? element.parent()[0] : element[0]).scrollHeight < initialMaxHeight || isOverflowed(element, scope.useParent) === false); + } + + function calculateLeastUpperBound(element, bindArray, ellipsisSeparator, appendString, isHtml, scope, initialMaxHeight){ + var upperBound = bindArray.length; + var lowerBound = 0; + + if(doesItFit(upperBound, element, bindArray, ellipsisSeparator, appendString, isHtml, scope, initialMaxHeight)){ + lowerBound = upperBound; + } else { + while(true){ + currentGuess = Math.floor((upperBound + lowerBound) / 2); + if(doesItFit(currentGuess, element, bindArray, ellipsisSeparator, appendString, isHtml, scope, initialMaxHeight)){ + lowerBound = currentGuess; + } else { + upperBound = currentGuess; + } + + if((upperBound - lowerBound) <= 1){ + break; + } + } + } + + return lowerBound; + } + /** * Watchers */ diff --git a/src/angular-ellipsis.min.js b/src/angular-ellipsis.min.js index e0d1fcb..0d78950 100644 --- a/src/angular-ellipsis.min.js +++ b/src/angular-ellipsis.min.js @@ -1 +1 @@ -angular.module("dibari.angular-ellipsis",[]).directive("ellipsis",["$timeout","$window","$sce",function(a,b,c){var d=function(b){var c=null,d=[];this.remove=function(b){-1!==d.indexOf(b)&&(d.splice(d.indexOf(b),1),0===d.length&&(a.cancel(c),c=null))},this.add=function(e){-1===d.indexOf(e)&&d.push(e),c||(c=a(function(){var a=d.slice();c=null,d.length=0,a.forEach(function(a){a()})},b))}},e=new d(0),f=new d(75);return{restrict:"A",scope:{ngBind:"=",ngBindHtml:"=",ellipsisAppend:"@",ellipsisAppendClick:"&",ellipsisSymbol:"@",ellipsisSeparator:"@",useParent:"@",ellipsisSeparatorReg:"="},compile:function(a,d,g){return function(a,d,g){function h(a){var b=0;return angular.forEach(a.parent().children(),function(c){c!=a[0]&&(b+=c.clientHeight)}),a.parent()[0].clientHeight-b}function i(){var b=a.ngBind||a.ngBindHtml,e=!1;if(c.isEnabled()&&angular.isObject(b)&&c.getTrustedHtml(b)&&(e=!0,b=c.getTrustedHtml(b)),b){var f=!a.ngBind&&!!a.ngBindHtml,i=0,k="undefined"!=typeof g.ellipsisSymbol?g.ellipsisSymbol:"…",l="undefined"!=typeof a.ellipsisSeparator?g.ellipsisSeparator:" ",m="undefined"!=typeof a.ellipsisSeparatorReg?a.ellipsisSeparatorReg:!1,n="undefined"!=typeof a.ellipsisAppend&&""!==a.ellipsisAppend?k+""+a.ellipsisAppend+"":k,o=m?b.match(m):b.split(l);if(g.isTruncated=!1,f?d.html(b):d.text(b),j(d,a.useParent)){var p=o.length,q=a.useParent?h(d):d[0].clientHeight;for(f?d.html(b+n):d.text(b).html(d.html()+n),d.attr("data-overflowed","true");p>i;i++)if(o.pop(),f?d.html(o.join(l)+n):d.text(o.join(l)).html(d.html()+n),(a.useParent?d.parent()[0]:d[0]).scrollHeighta[0].clientHeight}function k(){(g.lastWindowResizeWidth!=window.innerWidth||g.lastWindowResizeHeight!=window.innerHeight)&&i(),g.lastWindowResizeWidth=window.innerWidth,g.lastWindowResizeHeight=window.innerHeight}function l(){f.add(k)}g.lastWindowResizeTime=0,g.lastWindowResizeWidth=0,g.lastWindowResizeHeight=0,g.lastWindowTimeoutEvent=null,g.isTruncated=!1,a.$watch("ngBind",function(){e.add(i)}),a.$watch("ngBindHtml",function(){e.add(i)}),a.$watch("ellipsisAppend",function(){i()});var m=angular.element(b);m.bind("resize",l),a.$on("$destroy",function(){m.unbind("resize",l),e.remove(i),f.remove(k)})}}}}]); \ No newline at end of file +angular.module("dibari.angular-ellipsis",[]).directive("ellipsis",["$timeout","$window","$sce",function(a,b,c){var d=function(b){var c=null,d=[];this.remove=function(b){d.indexOf(b)!==-1&&(d.splice(d.indexOf(b),1),0===d.length&&(a.cancel(c),c=null))},this.add=function(e){d.indexOf(e)===-1&&d.push(e),c||(c=a(function(){var a=d.slice();c=null,d.length=0,a.forEach(function(a){a()})},b))}},e=new d(0),f=new d(75);return{restrict:"A",scope:{ngShow:"=",ngBind:"=",ngBindHtml:"=",ellipsisAppend:"@",ellipsisAppendClick:"&",ellipsisSymbol:"@",ellipsisSeparator:"@",useParent:"@",ellipsisSeparatorReg:"=",ellipsisFallbackFontSize:"@"},compile:function(a,d,g){return function(a,d,g){function h(a){return"undefined"!=typeof a}function i(a){var b=0;return angular.forEach(a.parent().children(),function(c){c!=a[0]&&(b+=c.clientHeight)}),a.parent()[0].clientHeight-b}function j(){var b=a.ngBind||a.ngBindHtml,e=!1;if(c.isEnabled()&&angular.isObject(b)&&c.getTrustedHtml(b)&&(e=!0,b=c.getTrustedHtml(b)),b){var f=!a.ngBind&&!!a.ngBindHtml,l="undefined"!=typeof g.ellipsisSymbol?g.ellipsisSymbol:"…",n="undefined"!=typeof a.ellipsisSeparator?g.ellipsisSeparator:" ",o="undefined"!=typeof a.ellipsisSeparatorReg&&a.ellipsisSeparatorReg,p="undefined"!=typeof a.ellipsisAppend&&""!==a.ellipsisAppend?l+""+a.ellipsisAppend+"":l,q=o?b.match(o):b.split(n);if(g.isTruncated=!1,f?d.html(b):d.text(b),h(g.ellipsisFallbackFontSize)&&k(d)&&d.css("font-size",g.ellipsisFallbackFontSize),k(d,a.useParent)){var s=(q.length,a.useParent?i(d):d[0].clientHeight);f?d.html(b+p):d.text(b).html(d.html()+p),d.attr("data-overflowed","true");const t=m(d,q,n,p,f,a,s);f?d.html(q.slice(0,t).join(n)+p):d.text(q.slice(0,t).join(n)).html(d.html()+p),g.isTruncated=!0,l!=p&&"undefined"!=typeof a.ellipsisAppendClick&&""!==a.ellipsisAppendClick&&d.find("span.angular-ellipsis-append").bind("click",function(b){a.$apply(function(){a.ellipsisAppendClick.call(a,{event:b})})}),!e&&c.isEnabled()&&c.trustAsHtml(b)}else d.attr("data-overflowed","false")}}function k(a,b){return a=b?a.parent():a,a[0].scrollHeight>a[0].clientHeight}function l(a,b,c,d,e,f,g,h){return f?b.html(c.slice(0,a).join(d)+e):b.text(c.slice(0,a).join(d)).html(b.html()+e),(g.useParent?b.parent()[0]:b[0]).scrollHeight