diff --git a/README.md b/README.md index 2bd89b8..342a015 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,7 @@ Truncate.js currently depends on jQuery. There are two ways to use Truncate.js: // Initialize and truncate. $('#truncate_me').truncate({ - lines: 2, - lineHeight: 20 + lines: 2 }); // Update the HTML and truncate. @@ -27,8 +26,7 @@ Truncate.js currently depends on jQuery. There are two ways to use Truncate.js: // Initialize and truncate. var truncated = new Truncate(document.getElementById('#truncate_me'), { - lines: 2, - lineHeight: 20 + lines: 2 }); // Update the HTML and truncate. @@ -54,6 +52,7 @@ Truncate.js currently depends on jQuery. There are two ways to use Truncate.js: - `showMore`: HTML to insert at the truncation point. Useful for a "Show More" button. _default: ""_ - `showLess`: HTML to insert when .expand() is called. Useful for a "Show Less" button. _default: ""_ - `position`: Position of the truncation. Possible values: `start`, `middle`, `end`. _default: "end"_ +- `maxHeight`: Truncate the content to fit in the specified height (in px). ---- diff --git a/dist/truncate.js b/dist/truncate.js index cd03393..51a49be 100644 --- a/dist/truncate.js +++ b/dist/truncate.js @@ -2,6 +2,17 @@ var BLOCK_TAGS = ['table', 'thead', 'tbody', 'tfoot', 'tr', 'col', 'colgroup', 'object', 'embed', 'param', 'ol', 'ul', 'dl', 'blockquote', 'select', 'optgroup', 'option', 'textarea', 'script', 'style']; + /* Trim function. + * Trim only end of string whitespaces + * + * text - String to trim + * + * Returns text without end whitespaces + */ + function trimRight(text) { + return text.replace(/\s*$/,""); + } + function setText(element, text) { if (element.innerText) { element.innerText = text; @@ -81,7 +92,7 @@ while (low <= high) { mid = low + ((high - low) >> 1); // Integer division - chunk = options.ellipsis + $.trim(original.substr(mid - 1, original.length)); + chunk = options.ellipsis + trimRight(original.substr(mid - 1, original.length)); setText(element, chunk); if ($rootNode.height() > options.maxHeight) { @@ -117,7 +128,7 @@ while (low <= high) { mid = low + ((high - low) >> 1); // Integer division - chunk = $.trim(original.substr(0, mid + 1)) + options.ellipsis; + chunk = trimRight(original.substr(0, mid + 1)) + options.ellipsis; setText(element, chunk); if ($rootNode.height() > options.maxHeight) { @@ -152,7 +163,7 @@ while (low <= high) { mid = low + ((high - low) >> 1); // Integer division - chunk = $.trim(original.substr(0, mid)) + options.ellipsis + original.substr(len - mid, len - mid); + chunk = trimRight(original.substr(0, mid)) + options.ellipsis + original.substr(len - mid, len - mid); setText(element, chunk); if ($rootNode.height() > options.maxHeight) { @@ -425,13 +436,19 @@ margin: 0, padding: 0, width: 'auto', - height: 'auto' + height: 'auto', + 'word-wrap': 'break-word' }); this.isTruncated = false; // Check if already meets height requirement if ($wrap.height() > this.options.maxHeight) { this.isTruncated = truncateNestedNode($wrap, $wrap, this.$clipNode, this.options); + + if(this.isExplicitlyCollapsed) { + this.isCollapsed = true; + wasExpanded = false; + } } else { this.isCollapsed = false; } @@ -454,12 +471,20 @@ * Returns nothing. */ expand: function () { + var includeShowLess = true; + + if(this.isExplicitlyCollapsed) { + this.isExplicitlyCollapsed = false; + includeShowLess = false; + } + if (!this.isCollapsed) { return; } this.isCollapsed = false; - this.element.innerHTML = this.isTruncated ? this.original + this.options.showLess : this.original; + + this.element.innerHTML = this.isTruncated ? this.original + (includeShowLess ? this.options.showLess : "") : this.original; }, /* Public: Collapses the element to the truncated state. @@ -470,6 +495,8 @@ * Returns nothing. */ collapse: function (retruncate) { + this.isExplicitlyCollapsed = true; + if (this.isCollapsed) { return; } diff --git a/dist/truncate.min.js b/dist/truncate.min.js index 770867a..59ee8a1 100644 --- a/dist/truncate.min.js +++ b/dist/truncate.min.js @@ -1 +1 @@ -!function(t,e,i){function n(t,e){if(t.innerText)t.innerText=e;else if(t.nodeValue)t.nodeValue=e;else{if(!t.textContent)return!1;t.textContent=e}}function s(t,e,i,s){var o,h=t.parent();t.remove();var r=i?i.length:0;if(h.contents().length>r)return o=h.contents().eq(-1-r),a(o,e,i,s);var l=h.prev();return o=l.contents().eq(-1),o.length?(n(o[0],o.text()+s.ellipsis),h.remove(),i.length&&l.append(i),!0):!1}function o(t,i,o,h){for(var r,a,l=t[0],p=t.text(),u="",d=0,c=p.length;c>=d;)r=d+(c-d>>1),a=h.ellipsis+e.trim(p.substr(r-1,p.length)),n(l,a),i.height()>h.maxHeight?d=r+1:(c=r-1,u=u.length>a.length?u:a);return u.length>0?(n(l,u),!0):s(t,i,o,h)}function h(t,i,o,h){for(var r,a,l=t[0],p=t.text(),u="",d=0,c=p.length;c>=d;)r=d+(c-d>>1),a=e.trim(p.substr(0,r+1))+h.ellipsis,n(l,a),i.height()>h.maxHeight?c=r-1:(d=r+1,u=u.length>a.length?u:a);return u.length>0?(n(l,u),!0):s(t,i,o,h)}function r(t,i,o,h){for(var r,a,l=t[0],p=t.text(),u="",d=0,c=p.length,g=c>>1;g>=d;)r=d+(g-d>>1),a=e.trim(p.substr(0,r))+h.ellipsis+p.substr(c-r,c-r),n(l,a),i.height()>h.maxHeight?g=r-1:(d=r+1,u=u.length>a.length?u:a);return u.length>0?(n(l,u),!0):s(t,i,o,h)}function a(t,e,i,n){return"end"===n.position?h(t,e,i,n):"start"===n.position?o(t,e,i,n):r(t,e,i,n)}function l(t,i,n,s){var o,h,r=t[0],l=t.contents(),p=l.length,d=p-1,g=!1;for(t.empty();d>=0&&!g;d--)o=l.eq(d),h=o[0],8!==h.nodeType&&(r.insertBefore(h,r.firstChild),n.length&&(e.inArray(r.tagName.toLowerCase(),c)>=0?t.after(n):t.append(n)),i.height()>s.maxHeight&&(g=3===h.nodeType?a(o,i,n,s):u(o,i,n,s)),!g&&n.length&&n.remove());return g}function p(t,i,n,s){var o,h,r=t[0],l=t.contents(),p=0,d=l.length,g=!1;for(t.empty();d>p&&!g;p++)o=l.eq(p),h=o[0],8!==h.nodeType&&(r.appendChild(h),n.length&&(e.inArray(r.tagName.toLowerCase(),c)>=0?t.after(n):t.append(n)),i.height()>s.maxHeight&&(g=3===h.nodeType?a(o,i,n,s):u(o,i,n,s)),!g&&n.length&&n.remove());return g}function u(t,e,i,n){return"end"===n.position?p(t,e,i,n):"start"===n.position?l(t,e,i,n):p(t,e,i,n)}function d(t,n){if(this.element=t,this.$element=e(t),this._name="truncate",this._defaults={lines:1,ellipsis:"…",showMore:"",showLess:"",position:"end",lineHeight:"auto"},this.options=e.extend({},this._defaults,n),"auto"===this.options.lineHeight){var s=this.$element.css("line-height"),o=18;"normal"!==s&&(o=parseInt(s,10)),this.options.lineHeight=o}this.options.maxHeight===i&&(this.options.maxHeight=parseInt(this.options.lines,10)*parseInt(this.options.lineHeight,10)),"start"!==this.options.position&&"middle"!==this.options.position&&"end"!==this.options.position&&(this.options.position="end"),this.$clipNode=e(e.parseHTML(this.options.showMore),this.$element),this.original=this.cached=t.innerHTML,this.isTruncated=!1,this.isCollapsed=!0,this.update()}var c=["table","thead","tbody","tfoot","tr","col","colgroup","object","embed","param","ol","ul","dl","blockquote","select","optgroup","option","textarea","script","style"];d.prototype={update:function(t){var e=!this.isCollapsed;"undefined"!=typeof t?this.original=this.element.innerHTML=t:this.isCollapsed&&this.element.innerHTML===this.cached&&(this.element.innerHTML=this.original);var i=this.$element.wrapInner("
").children();i.css({border:"none",margin:0,padding:0,width:"auto",height:"auto"}),this.isTruncated=!1,i.height()>this.options.maxHeight?this.isTruncated=u(i,i,this.$clipNode,this.options):this.isCollapsed=!1,i.replaceWith(i.contents()),this.cached=this.element.innerHTML,e&&(this.element.innerHTML=this.original)},expand:function(){this.isCollapsed&&(this.isCollapsed=!1,this.element.innerHTML=this.isTruncated?this.original+this.options.showLess:this.original)},collapse:function(t){this.isCollapsed||(this.isCollapsed=!0,t=t||!1,t?this.update():this.element.innerHTML=this.cached)}},e.fn.truncate=function(t){var i=e.makeArray(arguments).slice(1);return this.each(function(){var n=e.data(this,"jquery-truncate");n?"function"==typeof n[t]&&n[t].apply(n,i):e.data(this,"jquery-truncate",new d(this,t))})},t.Truncate=d}(this,jQuery); \ No newline at end of file +!function(t,e,i){function n(t){return t.replace(/\s*$/,"")}function s(t,e){if(t.innerText)t.innerText=e;else if(t.nodeValue)t.nodeValue=e;else{if(!t.textContent)return!1;t.textContent=e}}function o(t,e,i,n){var o,h=t.parent();t.remove();var r=i?i.length:0;if(h.contents().length>r)return o=h.contents().eq(-1-r),a(o,e,i,n);var l=h.prev();return o=l.contents().eq(-1),o.length?(s(o[0],o.text()+n.ellipsis),h.remove(),i.length&&l.append(i),!0):!1}function h(t,e,i,h){for(var r,l,a=t[0],p=t.text(),d="",u=0,c=p.length;c>=u;)r=u+(c-u>>1),l=h.ellipsis+n(p.substr(r-1,p.length)),s(a,l),e.height()>h.maxHeight?u=r+1:(c=r-1,d=d.length>l.length?d:l);return d.length>0?(s(a,d),!0):o(t,e,i,h)}function r(t,e,i,h){for(var r,l,a=t[0],p=t.text(),d="",u=0,c=p.length;c>=u;)r=u+(c-u>>1),l=n(p.substr(0,r+1))+h.ellipsis,s(a,l),e.height()>h.maxHeight?c=r-1:(u=r+1,d=d.length>l.length?d:l);return d.length>0?(s(a,d),!0):o(t,e,i,h)}function l(t,e,i,h){for(var r,l,a=t[0],p=t.text(),d="",u=0,c=p.length,g=c>>1;g>=u;)r=u+(g-u>>1),l=n(p.substr(0,r))+h.ellipsis+p.substr(c-r,c-r),s(a,l),e.height()>h.maxHeight?g=r-1:(u=r+1,d=d.length>l.length?d:l);return d.length>0?(s(a,d),!0):o(t,e,i,h)}function a(t,e,i,n){return"end"===n.position?r(t,e,i,n):"start"===n.position?h(t,e,i,n):l(t,e,i,n)}function p(t,i,n,s){var o,h,r=t[0],l=t.contents(),p=l.length,d=p-1,c=!1;for(t.empty();d>=0&&!c;d--)o=l.eq(d),h=o[0],8!==h.nodeType&&(r.insertBefore(h,r.firstChild),n.length&&(e.inArray(r.tagName.toLowerCase(),g)>=0?t.after(n):t.append(n)),i.height()>s.maxHeight&&(c=3===h.nodeType?a(o,i,n,s):u(o,i,n,s)),!c&&n.length&&n.remove());return c}function d(t,i,n,s){var o,h,r=t[0],l=t.contents(),p=0,d=l.length,c=!1;for(t.empty();d>p&&!c;p++)o=l.eq(p),h=o[0],8!==h.nodeType&&(r.appendChild(h),n.length&&(e.inArray(r.tagName.toLowerCase(),g)>=0?t.after(n):t.append(n)),i.height()>s.maxHeight&&(c=3===h.nodeType?a(o,i,n,s):u(o,i,n,s)),!c&&n.length&&n.remove());return c}function u(t,e,i,n){return"end"===n.position?d(t,e,i,n):"start"===n.position?p(t,e,i,n):d(t,e,i,n)}function c(t,n){if(this.element=t,this.$element=e(t),this._name="truncate",this._defaults={lines:1,ellipsis:"…",showMore:"",showLess:"",position:"end",lineHeight:"auto"},this.options=e.extend({},this._defaults,n),"auto"===this.options.lineHeight){var s=this.$element.css("line-height"),o=18;"normal"!==s&&(o=parseInt(s,10)),this.options.lineHeight=o}this.options.maxHeight===i&&(this.options.maxHeight=parseInt(this.options.lines,10)*parseInt(this.options.lineHeight,10)),"start"!==this.options.position&&"middle"!==this.options.position&&"end"!==this.options.position&&(this.options.position="end"),this.$clipNode=e(e.parseHTML(this.options.showMore),this.$element),this.original=this.cached=t.innerHTML,this.isTruncated=!1,this.isCollapsed=!0,this.update()}var g=["table","thead","tbody","tfoot","tr","col","colgroup","object","embed","param","ol","ul","dl","blockquote","select","optgroup","option","textarea","script","style"];c.prototype={update:function(t){var e=!this.isCollapsed;"undefined"!=typeof t?this.original=this.element.innerHTML=t:this.isCollapsed&&this.element.innerHTML===this.cached&&(this.element.innerHTML=this.original);var i=this.$element.wrapInner("").children();i.css({border:"none",margin:0,padding:0,width:"auto",height:"auto","word-wrap":"break-word"}),this.isTruncated=!1,i.height()>this.options.maxHeight?(this.isTruncated=u(i,i,this.$clipNode,this.options),this.isExplicitlyCollapsed&&(this.isCollapsed=!0,e=!1)):this.isCollapsed=!1,i.replaceWith(i.contents()),this.cached=this.element.innerHTML,e&&(this.element.innerHTML=this.original)},expand:function(){var t=!0;this.isExplicitlyCollapsed&&(this.isExplicitlyCollapsed=!1,t=!1),this.isCollapsed&&(this.isCollapsed=!1,this.element.innerHTML=this.isTruncated?this.original+(t?this.options.showLess:""):this.original)},collapse:function(t){this.isExplicitlyCollapsed=!0,this.isCollapsed||(this.isCollapsed=!0,t=t||!1,t?this.update():this.element.innerHTML=this.cached)}},e.fn.truncate=function(t){var i=e.makeArray(arguments).slice(1);return this.each(function(){var n=e.data(this,"jquery-truncate");n?"function"==typeof n[t]&&n[t].apply(n,i):e.data(this,"jquery-truncate",new c(this,t))})},t.Truncate=c}(this,jQuery); \ No newline at end of file diff --git a/package.json b/package.json index ad18741..da11f52 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "truncate.js", - "version": "1.1.1", + "version": "1.1.2", "description": "Fast, intelligent Javascript text truncation", "author": "Jeff Chan", "contributors": [{ diff --git a/test/.jshintrc b/test/.jshintrc new file mode 100644 index 0000000..c705d33 --- /dev/null +++ b/test/.jshintrc @@ -0,0 +1,39 @@ +{ + "globals": { + "jQuery": false, + "$": false, + "describe": false, + "it": false, + "beforeEach": false, + "assert": false, + "afterEach": false + }, + "node": false, + "browser": true, + "boss": true, + "camelcase": false, + "curly": true, + "debug": false, + "devel": false, + "eqeqeq": true, + "evil": true, + "expr": true, + "forin": true, + "immed": true, + "indent": 2, + "laxbreak": false, + "latedef": true, + "newcap": true, + "noarg": true, + "noempty": false, + "nonew": false, + "nomen": false, + "onevar": false, + "plusplus": false, + "sub": true, + "strict": false, + "trailing": true, + "white": true, + "undef": true, + "unused": true +} diff --git a/test/chrome/truncate-test.js b/test/chrome/truncate-test.js index 61755fb..1335294 100644 --- a/test/chrome/truncate-test.js +++ b/test/chrome/truncate-test.js @@ -48,6 +48,24 @@ describe('truncate.js', function () { assert.equal(this.$fixture.html(), "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer to…"); }); + it('truncate correctly word with no space', function () { + this.$fixture.html('E83F2E36E5EB4A0CBE92758E5C20BB8A'); + this.$fixture.css('width', '60px'); + + this.run({lines: 1}, false); + + assert.equal(this.$fixture.html(), "E83F2…"); + }); + + it('truncate correctly white space', function () { + this.$fixture.html('Some text with some link and some more text.'); + this.$fixture.css('width', '250px'); + + this.run({lines: 1}, false); + + assert.equal(this.$fixture.html(), "Some text with some link and some…"); + }); + it('truncate correctly when container has no margin or padding', function () { this.run({lines: 5}); @@ -256,6 +274,20 @@ describe('truncate.js', function () { this.$fixture.truncate('expand'); assert.equal(this.$fixture.html(), "