From 3c9677860f9739c1c6ef971719deee60b1d61a2f Mon Sep 17 00:00:00 2001 From: Arne Hartherz Date: Fri, 20 Mar 2020 12:05:45 +0100 Subject: [PATCH] Fix a bug where an element with automatic `height` and specified `max-height` caused subsequent elements to be clamped incorrectly. Resolves #2 --- CHANGELOG.md | 31 +++++++++++++++++++++++ Gemfile.lock | 2 +- dist/superclamp.js | 57 +++++++++++++++++++++++++++++++++++++++--- dist/superclamp.min.js | 4 +-- package.json | 2 +- src/superclamp.coffee | 44 ++++++++++++++++++++++++++++++-- test/index.html | 16 ++++++++++++ 7 files changed, 146 insertions(+), 10 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..5a0ab98 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,31 @@ +# Changelog +All notable changes to this project will be documented in this file. + +## 0.2.3 +* Fix [a bug](https://github.com/makandra/superclamp/issues/2) where an element with automatic `height` and specified `max-height` caused subsequent elements to be clamped incorrectly. + +## 0.2.2 +* Fix the size calculation in IE for elements using rem + +## 0.2.0 +* Remove jQuery dependency + +## 0.1.5 +* Preserve non-breaking spaces when clamping + +## 0.1.4 +* Calling `reclampAll` with an event argument now reclamps the document + +## 0.1.3 +* Consider `max-height`/`max-width` and improve calculation of fillable area +* support clamping properly after a font change + +## 0.1.2 +* Trigger the `superclamp:done` event when an element was clamped + +## 0.1.1 +* `reclampAll()` accepts a container element +* `clamp()`returns a jQuery collection + +## 0.1.0 +* Initial release diff --git a/Gemfile.lock b/Gemfile.lock index 0cc7ac6..2993813 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -56,4 +56,4 @@ DEPENDENCIES uglifier BUNDLED WITH - 1.10.6 + 2.1.4 diff --git a/dist/superclamp.js b/dist/superclamp.js index bc53550..0a1e6a3 100644 --- a/dist/superclamp.js +++ b/dist/superclamp.js @@ -1,11 +1,11 @@ /*! - * Superclamp 0.2.2 + * Superclamp 0.2.3 * https://github.com/makandra/superclamp */ (function() { - var CSS, DEBUG, DIMENSIONS_KEY, DISTANCE_KEY, DONE_EVENT_NAME, FRAGMENT_NODES_KEY, FRAGMENT_VALUES_KEY, INSTANCE_KEY, LOG, READY_ATTRIBUTE_NAME, Superclamp, UPDATE_EVENT_NAME, debug, drainPhaseQueue, drainQueue, getContents, getDimensions, getFragmentData, getFragments, getInnerPosition, getPosition, getStoredDimensions, hideAll, initializeTextNode, jobQueues, log, queue, setFragments, showAll, storeDimensions, style, triggerEvent, + var CSS, DEBUG, DIMENSIONS_KEY, DISTANCE_KEY, DONE_EVENT_NAME, FRAGMENT_NODES_KEY, FRAGMENT_VALUES_KEY, INSTANCE_KEY, LOG, READY_ATTRIBUTE_NAME, STASHED_HEIGHT, STASHED_WIDTH, Superclamp, UPDATE_EVENT_NAME, debug, drainPhaseQueue, drainQueue, getContents, getDimensions, getFragmentData, getFragments, getInnerPosition, getPosition, getStoredDimensions, hideAll, initializeTextNode, jobQueues, log, queue, setFragments, showAll, storeDimensions, style, triggerEvent, bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, slice = [].slice; @@ -29,6 +29,10 @@ FRAGMENT_VALUES_KEY = 'superclamp:fragmentValues'; + STASHED_HEIGHT = 'superclamp:stashedHeight'; + + STASHED_WIDTH = 'superclamp:stashedWidth'; + CSS = ".clamp-ellipsis.is-not-required {\n visibility: hidden !important;\n}\n.clamp-hidden {\n display: none !important;\n}"; Superclamp = (function() { @@ -75,6 +79,10 @@ this._storeDistance = bind(this._storeDistance, this); this._updateElementAt = bind(this._updateElementAt, this); this._updateEllipsisSize = bind(this._updateEllipsisSize, this); + this._unsetTemporaryStyle = bind(this._unsetTemporaryStyle, this); + this._setTemporaryStyle = bind(this._setTemporaryStyle, this); + this._unsetTemporaryDimensions = bind(this._unsetTemporaryDimensions, this); + this._setTemporaryDimensions = bind(this._setTemporaryDimensions, this); debug('initialize', this.element); spaceNode = document.createTextNode(' '); this.ellipsis = document.createElement('span'); @@ -90,17 +98,57 @@ Superclamp.prototype.clamp = function() { queue('query', (function(_this) { return function() { + _this._setTemporaryDimensions(); _this._updateEllipsisSize(); _this._updateElementAt(); if (_this._unchanged()) { - return debug('unchanged', _this.element); + debug('unchanged', _this.element); + _this._unsetTemporaryDimensions(); } else { - return _this._clampThis(); + _this._clampThis(); } }; })(this)); }; + Superclamp.prototype._setTemporaryDimensions = function() { + var computedStyle, height, maxHeight, maxWidth, width; + computedStyle = window.getComputedStyle(this.element); + maxHeight = parseInt(computedStyle.maxHeight); + maxWidth = parseInt(computedStyle.maxWidth); + height = parseInt(computedStyle.height); + width = parseInt(computedStyle.width); + if (maxHeight && height < maxHeight) { + this._setTemporaryStyle('height', height + "px"); + } + if (maxWidth && width < maxWidth) { + this._setTemporaryStyle('width', width + "px"); + } + }; + + Superclamp.prototype._unsetTemporaryDimensions = function() { + this._unsetTemporaryStyle('height'); + this._unsetTemporaryStyle('width'); + }; + + Superclamp.prototype._setTemporaryStyle = function(styleName, value) { + var stashedPropertyName; + stashedPropertyName = "superclamp:stashedStyle:" + styleName; + if (!this.element.hasOwnProperty(stashedPropertyName)) { + this.element[stashedPropertyName] = this.element.style[styleName]; + } + this.element.style[styleName] = value; + }; + + Superclamp.prototype._unsetTemporaryStyle = function(styleName) { + var stashedPropertyName; + stashedPropertyName = "superclamp:stashedStyle:" + styleName; + if (this.element.hasOwnProperty(stashedPropertyName)) { + this.element.style[styleName] = this.element[stashedPropertyName]; + delete this.element[stashedPropertyName]; + } + }; + Superclamp.prototype._updateEllipsisSize = function() { return storeDimensions(this.ellipsis); }; @@ -120,6 +168,7 @@ log('_clampThis', this.element); return this._clampNode(this.element, (function(_this) { return function(allFit) { + _this._restoreFixedDimensions(); _this._storeDistance(); return queue('layout', function() { if (allFit) { diff --git a/dist/superclamp.min.js b/dist/superclamp.min.js index 6a392a5..95fdd61 100644 --- a/dist/superclamp.min.js +++ b/dist/superclamp.min.js @@ -1,5 +1,5 @@ /*! - * Superclamp 0.2.2 + * Superclamp 0.2.3 * https://github.com/makandra/superclamp */ -(function(){var t,e,n,i,o,r,s,l,u,a,p,c,d,h,m,f,g,y,_,v,b,A,E,T,w,x,N,L,F,I,B,R,S=function(t,e){return function(){return t.apply(e,arguments)}},q=[].slice;u=!1,e=!1,o="superclamp:done",c="superclamp:update",l="superclamp:instance",a="superclamp-ready",n="superclamp:dimensions",i="superclamp:distanceToBottomRight",r="superclamp:fragmentNodes",s="superclamp:fragmentValues",t=".clamp-ellipsis.is-not-required {\n visibility: hidden !important;\n}\n.clamp-hidden {\n display: none !important;\n}",p=function(){function t(t){var e;this.element=t,this._clampNode=S(this._clampNode,this),this._checkFit=S(this._checkFit,this),this._unchanged=S(this._unchanged,this),this._distanceToBottomRight=S(this._distanceToBottomRight,this),this._getEllipsisAt=S(this._getEllipsisAt,this),this._clampThis=S(this._clampThis,this),this._storeDistance=S(this._storeDistance,this),this._updateElementAt=S(this._updateElementAt,this),this._updateEllipsisSize=S(this._updateEllipsisSize,this),d("initialize",this.element),e=document.createTextNode(" "),this.ellipsis=document.createElement("span"),this.ellipsis.classList.add("clamp-ellipsis"),this.ellipsis.innerText="\u2026",this.element.appendChild(e),this.element.appendChild(this.ellipsis),this.element[l]=this,this.element.setAttribute(a,!0)}return t.register=function(t){var e,n,i;for(d(".register",t),e=0,n=t.length;n>e;e++)i=t[e],this.clamp(i);m()},t.clamp=function(e){var n;d(".clamp",e),n=e[l]||new t(e),n.clamp()},t.reclampAll=function(e){var n,i,o,r;for((null==e||null!=e.currentTarget)&&(e=document),r=e.querySelectorAll("["+a+"]"),i=0,o=r.length;o>i;i++)n=r[i],t.clamp(n);return m(),e},t.prototype.clamp=function(){N("query",function(t){return function(){return t._updateEllipsisSize(),t._updateElementAt(),t._unchanged()?d("unchanged",t.element):t._clampThis()}}(this))},t.prototype._updateEllipsisSize=function(){return I(this.ellipsis)},t.prototype._updateElementAt=function(){return this.elementAt=v(this.element)},t.prototype._storeDistance=function(){var t;return t=this._distanceToBottomRight(),d("storing distance",t),this.ellipsis[i]=t},t.prototype._clampThis=function(){return x("_clampThis",this.element),this._clampNode(this.element,function(t){return function(e){return t._storeDistance(),N("layout",function(){return e?t.ellipsis.classList.add("is-not-required"):t.ellipsis.classList.remove("is-not-required"),R(t.element,o)})}}(this))},t.prototype._getEllipsisAt=function(){return b(this.ellipsis)},t.prototype._distanceToBottomRight=function(){var t;return t=this._getEllipsisAt(),[this.elementAt.right-t.right,this.elementAt.bottom-t.bottom]},t.prototype._unchanged=function(){var t,e,n,o,r,s;return s=this.ellipsis[i],null!=s?(t=s[0],n=s[1],r=this._distanceToBottomRight(),e=r[0],o=r[1],d("_unchanged: %o == %o && %o == %o",t,e,n,o),t===e&&n===o):!1},t.prototype._checkFit=function(t){return N("query",function(e){return function(){var n,i;return i=e._getEllipsisAt(),n=i.bottom<=e.elementAt.bottom&&i.right<=e.elementAt.right,d("checkFit: %o (bottom: %o <= %o, right: %o <= %o)",n,i.bottom,e.elementAt.bottom,i.right,e.elementAt.right),t(n)}}(this))},t.prototype._clampNode=function(t,e,n){var i,o;return null==n&&(n=!0),i=function(n){return function(r,s,l){return N("query",function(){var u,a,p;return d("findBestFit #contents: %o, nodeName: %o, prefix: %o",r,t.nodeName,s),0===r.length?e(l):1===r.length?o?(t.nodeValue=s+r[0],n._checkFit(function(n){return N("layout",function(i){return function(){return n?e(l):(t.nodeValue=s.replace(RegExp(" $"),""),e(!1))}}(this))})):n._clampNode(r[0],e,l):(a=Math.floor(r.length/2),u=r.slice(0,a),p=r.slice(a),d("findBestFit head: %o, tail: %o",u,p),o?t.nodeValue=s+u.join(" "):(F(u),E(p)),n._checkFit(function(e){return N("layout",function(n){return function(){return e?(d("fits"),o?i(p,t.nodeValue+" ",l):i(p,"",l)):(d("wont fit"),i(u,s,!1))}}(this))}))})}}(this),o="#text"===t.nodeName,N("layout",function(e){return function(){var r;return o?(T(t),i(_(t),"",n)):"#comment"!==t.nodeName?(F([t]),r=f(t),t===e.element&&(r=Array.prototype.slice.call(r,0,-2)),i(r,"",n)):void 0}}(this))},t}(),w={layout:[],query:[]},N=function(t,e){w[t].push(e)},h=function(t){var e,n;if(n=w[t],0===n.length)return!0;for(d("draining",t);e=n.shift();)e();return!1},m=function(){for(var t,e;!t||!e;)t=h("layout"),e=h("query")},d=function(){var t,n;return t=1<=arguments.length?q.call(arguments,0):[],e&&null!=(n=window.console)&&"function"==typeof n.debug?n.debug.apply(n,t):void 0},x=function(){var t,e;return t=1<=arguments.length?q.call(arguments,0):[],u&&null!=(e=window.console)&&"function"==typeof e.log?e.log.apply(e,t):void 0},I=function(t){t[n]=g(t),d("storeDimensions",t[n])},g=function(t){var e,n,i;return e=window.getComputedStyle(t),n=t.offsetHeight-parseFloat(e.paddingTop)-parseFloat(e.paddingBottom),i=t.offsetWidth-parseFloat(e.paddingLeft)-parseFloat(e.paddingRight),d("getDimensions",[n,i]),[i,n]},A=function(t){return t[n]},b=function(t){var e,n,i,o;return i=A(t)||g(t),o=i[0],e=i[1],n={top:t.offsetTop,left:t.offsetLeft},null==n.bottom&&(n.bottom=n.top+e),null==n.right&&(n.right=n.left+o),d("getPosition of %o: %o",t,n),n},v=function(t){var e,n,i,o,r,s,l,u,a,p;return s=!!t.currentStyle,i=window.getComputedStyle(t),e="border-box"===i.boxSizing,a=t.offsetTop,l=t.offsetLeft,o=parseInt(i.maxHeight)||parseInt(i.height),p=parseInt(i.maxWidth)||parseInt(i.width),e&&(u={top:parseInt(i.paddingTop)||0,left:parseInt(i.paddingLeft)||0,right:parseInt(i.paddingRight)||0,bottom:parseInt(i.paddingBottom)||0},n={top:parseInt(i.borderTopWidth)||0,left:parseInt(i.borderLeftWidth)||0,right:parseInt(i.borderRightWidth)||0,bottom:parseInt(i.borderBottomWidth)||0},s||(a+=u.top+n.top,l+=u.left+n.left,p-=u.left+u.right+n.left+n.right,o-=u.top+u.bottom+n.top+n.bottom)),r={top:a,left:l,right:l+p,bottom:a+o,width:p,height:o}},y=function(t){var e,n,i,o;return i=t.parentNode,n=i[r]||[],o=i[s]||[],e=Array.prototype.indexOf.call(n,t),[n,o,e,i]},L=function(t,e){var n,i,o,l,u;l=y(t),i=l[0],u=l[1],n=l[2],o=l[3],0>n&&(n=i.length),i[n]=t,u[n]=e,o[r]=i,o[s]=u},_=function(t){var e,n,i,o,r;return o=y(t),n=o[0],r=o[1],e=o[2],i=o[3],r[e]},T=function(t){null==_(t)&&L(t,t.nodeValue.split(/[ \t\r\n]+/))},f=function(t){return Array.prototype.slice.call(t.childNodes)},E=function(t){var e,n,i;for(d("hideAll",t),e=0,n=t.length;n>e;e++)i=t[e],"#text"===i.nodeName?(T(i),i.nodeValue=""):i.classList.add("clamp-hidden")},F=function(t){var e,n,i;for(d("showAll",t),e=0,n=t.length;n>e;e++)i=t[e],"#text"===i.nodeName?(T(i),i.nodeValue=_(i).join(" ")):(i.classList.remove("clamp-hidden"),F(f(i)))},R=function(t,e){var n;return"function"==typeof Event?n=new Event("submit"):(n=document.createEvent("Event"),n.initEvent(e,!0,!0)),t.dispatchEvent(n)},B=document.createElement("style"),B.type="text/css",B.appendChild(document.createTextNode(t)),document.head.appendChild(B),"undefined"!=typeof jQuery&&(jQuery.fn.clamp=function(){return p.register(this.get()),this}),document.addEventListener("DOMContentLoaded",function(){return document.addEventListener(c,p.reclampAll)}),"object"==typeof module&&module&&"object"==typeof module.exports?module.exports=p:window.Superclamp=p}).call(this); \ No newline at end of file +(function(){var t,e,n,i,o,r,s,l,a,p,u,h,c,m,d,f,g,y,_,v,T,b,A,E,w,S,x,D,I,N,F,L,B,R,q=function(t,e){return function(){return t.apply(e,arguments)}},C=[].slice;a=!1,e=!1,o="superclamp:done",m="superclamp:update",l="superclamp:instance",p="superclamp-ready",n="superclamp:dimensions",i="superclamp:distanceToBottomRight",r="superclamp:fragmentNodes",s="superclamp:fragmentValues",u="superclamp:stashedHeight",h="superclamp:stashedWidth",t=".clamp-ellipsis.is-not-required {\n visibility: hidden !important;\n}\n.clamp-hidden {\n display: none !important;\n}",c=function(){function t(t){var e;this.element=t,this._clampNode=q(this._clampNode,this),this._checkFit=q(this._checkFit,this),this._unchanged=q(this._unchanged,this),this._distanceToBottomRight=q(this._distanceToBottomRight,this),this._getEllipsisAt=q(this._getEllipsisAt,this),this._clampThis=q(this._clampThis,this),this._storeDistance=q(this._storeDistance,this),this._updateElementAt=q(this._updateElementAt,this),this._updateEllipsisSize=q(this._updateEllipsisSize,this),this._unsetTemporaryStyle=q(this._unsetTemporaryStyle,this),this._setTemporaryStyle=q(this._setTemporaryStyle,this),this._unsetTemporaryDimensions=q(this._unsetTemporaryDimensions,this),this._setTemporaryDimensions=q(this._setTemporaryDimensions,this),d("initialize",this.element),e=document.createTextNode(" "),this.ellipsis=document.createElement("span"),this.ellipsis.classList.add("clamp-ellipsis"),this.ellipsis.innerText="\u2026",this.element.appendChild(e),this.element.appendChild(this.ellipsis),this.element[l]=this,this.element.setAttribute(p,!0)}return t.register=function(t){var e,n,i;for(d(".register",t),e=0,n=t.length;n>e;e++)i=t[e],this.clamp(i);g()},t.clamp=function(e){var n;d(".clamp",e),n=e[l]||new t(e),n.clamp()},t.reclampAll=function(e){var n,i,o,r;for((null==e||null!=e.currentTarget)&&(e=document),r=e.querySelectorAll("["+p+"]"),i=0,o=r.length;o>i;i++)n=r[i],t.clamp(n);return g(),e},t.prototype.clamp=function(){I("query",function(t){return function(){t._setTemporaryDimensions(),t._updateEllipsisSize(),t._updateElementAt(),t._unchanged()?(d("unchanged",t.element),t._unsetTemporaryDimensions()):t._clampThis()}}(this))},t.prototype._setTemporaryDimensions=function(){var t,e,n,i,o;t=window.getComputedStyle(this.element),n=parseInt(t.maxHeight),i=parseInt(t.maxWidth),e=parseInt(t.height),o=parseInt(t.width),n&&n>e&&this._setTemporaryStyle("height",e+"px"),i&&i>o&&this._setTemporaryStyle("width",o+"px")},t.prototype._unsetTemporaryDimensions=function(){this._unsetTemporaryStyle("height"),this._unsetTemporaryStyle("width")},t.prototype._setTemporaryStyle=function(t,e){var n;n="superclamp:stashedStyle:"+t,this.element.hasOwnProperty(n)||(this.element[n]=this.element.style[t]),this.element.style[t]=e},t.prototype._unsetTemporaryStyle=function(t){var e;e="superclamp:stashedStyle:"+t,this.element.hasOwnProperty(e)&&(this.element.style[t]=this.element[e],delete this.element[e])},t.prototype._updateEllipsisSize=function(){return L(this.ellipsis)},t.prototype._updateElementAt=function(){return this.elementAt=b(this.element)},t.prototype._storeDistance=function(){var t;return t=this._distanceToBottomRight(),d("storing distance",t),this.ellipsis[i]=t},t.prototype._clampThis=function(){return D("_clampThis",this.element),this._clampNode(this.element,function(t){return function(e){return t._restoreFixedDimensions(),t._storeDistance(),I("layout",function(){return e?t.ellipsis.classList.add("is-not-required"):t.ellipsis.classList.remove("is-not-required"),R(t.element,o)})}}(this))},t.prototype._getEllipsisAt=function(){return A(this.ellipsis)},t.prototype._distanceToBottomRight=function(){var t;return t=this._getEllipsisAt(),[this.elementAt.right-t.right,this.elementAt.bottom-t.bottom]},t.prototype._unchanged=function(){var t,e,n,o,r,s;return s=this.ellipsis[i],null!=s?(t=s[0],n=s[1],r=this._distanceToBottomRight(),e=r[0],o=r[1],d("_unchanged: %o == %o && %o == %o",t,e,n,o),t===e&&n===o):!1},t.prototype._checkFit=function(t){return I("query",function(e){return function(){var n,i;return i=e._getEllipsisAt(),n=i.bottom<=e.elementAt.bottom&&i.right<=e.elementAt.right,d("checkFit: %o (bottom: %o <= %o, right: %o <= %o)",n,i.bottom,e.elementAt.bottom,i.right,e.elementAt.right),t(n)}}(this))},t.prototype._clampNode=function(t,e,n){var i,o;return null==n&&(n=!0),i=function(n){return function(r,s,l){return I("query",function(){var a,p,u;return d("findBestFit #contents: %o, nodeName: %o, prefix: %o",r,t.nodeName,s),0===r.length?e(l):1===r.length?o?(t.nodeValue=s+r[0],n._checkFit(function(n){return I("layout",function(i){return function(){return n?e(l):(t.nodeValue=s.replace(RegExp(" $"),""),e(!1))}}(this))})):n._clampNode(r[0],e,l):(p=Math.floor(r.length/2),a=r.slice(0,p),u=r.slice(p),d("findBestFit head: %o, tail: %o",a,u),o?t.nodeValue=s+a.join(" "):(F(a),w(u)),n._checkFit(function(e){return I("layout",function(n){return function(){return e?(d("fits"),o?i(u,t.nodeValue+" ",l):i(u,"",l)):(d("wont fit"),i(a,s,!1))}}(this))}))})}}(this),o="#text"===t.nodeName,I("layout",function(e){return function(){var r;return o?(S(t),i(T(t),"",n)):"#comment"!==t.nodeName?(F([t]),r=y(t),t===e.element&&(r=Array.prototype.slice.call(r,0,-2)),i(r,"",n)):void 0}}(this))},t}(),x={layout:[],query:[]},I=function(t,e){x[t].push(e)},f=function(t){var e,n;if(n=x[t],0===n.length)return!0;for(d("draining",t);e=n.shift();)e();return!1},g=function(){for(var t,e;!t||!e;)t=f("layout"),e=f("query")},d=function(){var t,n;return t=1<=arguments.length?C.call(arguments,0):[],e&&null!=(n=window.console)&&"function"==typeof n.debug?n.debug.apply(n,t):void 0},D=function(){var t,e;return t=1<=arguments.length?C.call(arguments,0):[],a&&null!=(e=window.console)&&"function"==typeof e.log?e.log.apply(e,t):void 0},L=function(t){t[n]=_(t),d("storeDimensions",t[n])},_=function(t){var e,n,i;return e=window.getComputedStyle(t),n=t.offsetHeight-parseFloat(e.paddingTop)-parseFloat(e.paddingBottom),i=t.offsetWidth-parseFloat(e.paddingLeft)-parseFloat(e.paddingRight),d("getDimensions",[n,i]),[i,n]},E=function(t){return t[n]},A=function(t){var e,n,i,o;return i=E(t)||_(t),o=i[0],e=i[1],n={top:t.offsetTop,left:t.offsetLeft},null==n.bottom&&(n.bottom=n.top+e),null==n.right&&(n.right=n.left+o),d("getPosition of %o: %o",t,n),n},b=function(t){var e,n,i,o,r,s,l,a,p,u;return s=!!t.currentStyle,i=window.getComputedStyle(t),e="border-box"===i.boxSizing,p=t.offsetTop,l=t.offsetLeft,o=parseInt(i.maxHeight)||parseInt(i.height),u=parseInt(i.maxWidth)||parseInt(i.width),e&&(a={top:parseInt(i.paddingTop)||0,left:parseInt(i.paddingLeft)||0,right:parseInt(i.paddingRight)||0,bottom:parseInt(i.paddingBottom)||0},n={top:parseInt(i.borderTopWidth)||0,left:parseInt(i.borderLeftWidth)||0,right:parseInt(i.borderRightWidth)||0,bottom:parseInt(i.borderBottomWidth)||0},s||(p+=a.top+n.top,l+=a.left+n.left,u-=a.left+a.right+n.left+n.right,o-=a.top+a.bottom+n.top+n.bottom)),r={top:p,left:l,right:l+u,bottom:p+o,width:u,height:o}},v=function(t){var e,n,i,o;return i=t.parentNode,n=i[r]||[],o=i[s]||[],e=Array.prototype.indexOf.call(n,t),[n,o,e,i]},N=function(t,e){var n,i,o,l,a;l=v(t),i=l[0],a=l[1],n=l[2],o=l[3],0>n&&(n=i.length),i[n]=t,a[n]=e,o[r]=i,o[s]=a},T=function(t){var e,n,i,o,r;return o=v(t),n=o[0],r=o[1],e=o[2],i=o[3],r[e]},S=function(t){null==T(t)&&N(t,t.nodeValue.split(/[ \t\r\n]+/))},y=function(t){return Array.prototype.slice.call(t.childNodes)},w=function(t){var e,n,i;for(d("hideAll",t),e=0,n=t.length;n>e;e++)i=t[e],"#text"===i.nodeName?(S(i),i.nodeValue=""):i.classList.add("clamp-hidden")},F=function(t){var e,n,i;for(d("showAll",t),e=0,n=t.length;n>e;e++)i=t[e],"#text"===i.nodeName?(S(i),i.nodeValue=T(i).join(" ")):(i.classList.remove("clamp-hidden"),F(y(i)))},R=function(t,e){var n;return"function"==typeof Event?n=new Event("submit"):(n=document.createEvent("Event"),n.initEvent(e,!0,!0)),t.dispatchEvent(n)},B=document.createElement("style"),B.type="text/css",B.appendChild(document.createTextNode(t)),document.head.appendChild(B),"undefined"!=typeof jQuery&&(jQuery.fn.clamp=function(){return c.register(this.get()),this}),document.addEventListener("DOMContentLoaded",function(){return document.addEventListener(m,c.reclampAll)}),"object"==typeof module&&module&&"object"==typeof module.exports?module.exports=c:window.Superclamp=c}).call(this); \ No newline at end of file diff --git a/package.json b/package.json index 6cf2bf9..8bb34dd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "superclamp", - "version": "0.2.2", + "version": "0.2.3", "description": "Cross-browser ellipsis for multi-line texts, optimized for performance. No dependencies.", "main": "dist/superclamp.js", "files": [ diff --git a/src/superclamp.coffee b/src/superclamp.coffee index 512c8e3..6f5b580 100644 --- a/src/superclamp.coffee +++ b/src/superclamp.coffee @@ -1,5 +1,5 @@ ###! - * Superclamp 0.2.2 + * Superclamp 0.2.3 * https://github.com/makandra/superclamp ### @@ -16,6 +16,8 @@ DIMENSIONS_KEY = 'superclamp:dimensions' DISTANCE_KEY = 'superclamp:distanceToBottomRight' FRAGMENT_NODES_KEY = 'superclamp:fragmentNodes' FRAGMENT_VALUES_KEY = 'superclamp:fragmentValues' +STASHED_HEIGHT = 'superclamp:stashedHeight' +STASHED_WIDTH = 'superclamp:stashedWidth' CSS = """ .clamp-ellipsis.is-not-required { @@ -34,6 +36,7 @@ class Superclamp debug '.register', nodeList for node in nodeList @clamp(node) + drainQueue() return @@ -77,14 +80,50 @@ class Superclamp # font face/size may have changed. Its dimensions are required to # properly calculate if our contents have changed. # We also need to update our element position to compare against. + @_setTemporaryDimensions() @_updateEllipsisSize() @_updateElementAt() if @_unchanged() - debug 'unchanged', @element # no need to (re)clamp + debug 'unchanged', @element + @_unsetTemporaryDimensions() else @_clampThis() + return + return + + _setTemporaryDimensions: => + computedStyle = window.getComputedStyle(@element) + + maxHeight = parseInt(computedStyle.maxHeight) + maxWidth = parseInt(computedStyle.maxWidth) + height = parseInt(computedStyle.height) + width = parseInt(computedStyle.width) + + if maxHeight && height < maxHeight + @_setTemporaryStyle('height', "#{height}px") + if maxWidth && width < maxWidth + @_setTemporaryStyle('width', "#{width}px") + return + + _unsetTemporaryDimensions: => + @_unsetTemporaryStyle('height') + @_unsetTemporaryStyle('width') + return + + _setTemporaryStyle: (styleName, value) => + stashedPropertyName = "superclamp:stashedStyle:#{styleName}" + unless @element.hasOwnProperty(stashedPropertyName) + @element[stashedPropertyName] = @element.style[styleName] + @element.style[styleName] = value + return + + _unsetTemporaryStyle: (styleName) => + stashedPropertyName = "superclamp:stashedStyle:#{styleName}" + if @element.hasOwnProperty(stashedPropertyName) + @element.style[styleName] = @element[stashedPropertyName] + delete @element[stashedPropertyName] return _updateEllipsisSize: => @@ -101,6 +140,7 @@ class Superclamp _clampThis: => log '_clampThis', @element @_clampNode @element, (allFit) => + @_restoreFixedDimensions() @_storeDistance() queue 'layout', => if (allFit) diff --git a/test/index.html b/test/index.html index 4ea37f7..7bb1720 100644 --- a/test/index.html +++ b/test/index.html @@ -14,6 +14,13 @@ height: 200px; max-width: 800px; padding: 5px 25px 10px 80px; + line-height: 18px; + } + .clamp-me.-max-height { + /*width: 400px;*/ + overflow: hidden; + height: unset; + max-height: 100px; } @@ -105,6 +112,15 @@

Container including nested elements

+

Subsequently clamped items

+
+
This should not be clamped. Lorem ipsum dolor sit amet, consectetur adipiscing elit. elit. Aliquam gravida sem quam
+
This should be clamped: Pellentesque ut fringilla lacus. Donec posuere efficitur odio quis feugiat. Suspendisse non sollicitudin orci. Vestibulum at ornare eros. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aliquam in justo a nisl tristique hendrerit vel sit amet urna. Ut posuere tortor ornare sagittis commodo. Proin placerat leo eu convallis dictum.
+
This should be clamped: Pellentesque ut fringilla lacus. Donec posuere efficitur odio quis feugiat. Suspendisse non sollicitudin orci. Vestibulum at ornare eros. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aliquam in justo a nisl tristique hendrerit vel sit amet urna. Ut posuere tortor ornare sagittis commodo. Proin placerat leo eu convallis dictum.
+
This should be clamped: Pellentesque ut fringilla lacus. Donec posuere efficitur odio quis feugiat. Suspendisse non sollicitudin orci. Vestibulum at ornare eros. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aliquam in justo a nisl tristique hendrerit vel sit amet urna. Ut posuere tortor ornare sagittis commodo. Proin placerat leo eu convallis dictum.
+
This should not be clamped. It is just an element without max-height between other elements that have a given max-height
+
This should be clamped: Pellentesque ut fringilla lacus. Donec posuere efficitur odio quis feugiat. Suspendisse non sollicitudin orci. Vestibulum at ornare eros. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aliquam in justo a nisl tristique hendrerit vel sit amet urna. Ut posuere tortor ornare sagittis commodo. Proin placerat leo eu convallis dictum.
+