diff options
author | Daniel GarcĂa <93217193+Daniel-Garmig@users.noreply.github.com> | 2024-09-09 23:51:57 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-09-09 23:51:57 +0200 |
commit | c934995efa431efe0b15b6f9a6b614e6b8e88399 (patch) | |
tree | 9a4eed3162984e79521bd0f5369ca5d7e16090e3 | |
parent | d564731f20a5eee6c6e373344a2bd6fc9d047e63 (diff) | |
download | jquery-ui-c934995efa431efe0b15b6f9a6b614e6b8e88399.tar.gz jquery-ui-c934995efa431efe0b15b6f9a6b614e6b8e88399.zip |
Resizable: Fix content shrink on resize
Make resizable elements not shrink on resize when they have scrollbars
and "box-sizing: content-box".
Fixes: gh-2277
Closes gh-2281
-rw-r--r-- | tests/unit/resizable/core.js | 68 | ||||
-rw-r--r-- | tests/unit/resizable/options.js | 62 | ||||
-rw-r--r-- | ui/widgets/resizable.js | 78 |
3 files changed, 191 insertions, 17 deletions
diff --git a/tests/unit/resizable/core.js b/tests/unit/resizable/core.js index b3c61514a..b47f0b645 100644 --- a/tests/unit/resizable/core.js +++ b/tests/unit/resizable/core.js @@ -244,4 +244,72 @@ QUnit.test( "nested resizable", function( assert ) { outer.remove(); } ); +QUnit.test( "Resizable with scrollbars and box-sizing: border-box", function( assert ) { + assert.expect( 4 ); + testResizableWithBoxSizing( assert, { + isBorderBox: true, + applyScaleTransform: false + } ); +} ); + +QUnit.test( "Resizable with scrollbars and box-sizing: content-box", function( assert ) { + assert.expect( 4 ); + testResizableWithBoxSizing( assert, { + isBorderBox: false, + applyScaleTransform: false + } ); +} ); + +QUnit.test( "Resizable with scrollbars, a transform and box-sizing: border-box", function( assert ) { + assert.expect( 4 ); + testResizableWithBoxSizing( assert, { + isBorderBox: true, + applyScaleTransform: true + } ); +} ); + +QUnit.test( "Resizable with scrollbars, a transform and box-sizing: content-box", function( assert ) { + assert.expect( 4 ); + testResizableWithBoxSizing( assert, { + isBorderBox: false, + applyScaleTransform: true + } ); +} ); + +function testResizableWithBoxSizing( assert, options ) { + var widthBefore, heightBefore, + cssBoxSizing = options.isBorderBox ? "border-box" : "content-box", + cssTransform = options.applyScaleTransform ? "scale(1.5)" : "", + elementContent = $( "<div>" ) + .css( { + width: "200px", + height: "200px", + padding: "10px", + border: "5px", + borderStyle: "solid", + margin: "20px" + } ) + .appendTo( "#resizable1" ), + element = $( "#resizable1" ).css( { overflow: "auto", transform: cssTransform } ).resizable(), + handle = ".ui-resizable-se"; + + $( "<style> * { box-sizing: " + cssBoxSizing + "; } </style>" ).appendTo( "#qunit-fixture" ); + + // In some browsers scrollbar may change element size (when "box-sizing: content-box") + widthBefore = element.innerWidth(); + heightBefore = element.innerHeight(); + + // Both scrollbars + testHelper.drag( handle, 10, 10 ); + assert.equal( parseFloat( element.innerWidth() ), widthBefore + 10, "element width (both scrollbars)" ); + assert.equal( parseFloat( element.innerHeight() ), heightBefore + 10, "element height (both scrollbars)" ); + + // Single (vertical) scrollbar. + elementContent.css( "width", "50px" ); + + testHelper.drag( handle, 10, 10 ); + assert.equal( parseFloat( element.innerWidth() ), widthBefore + 20, "element width (only vertical scrollbar)" ); + assert.equal( parseFloat( element.innerHeight() ), heightBefore + 20, "element height (only vertical scrollbar)" ); +} + } ); diff --git a/tests/unit/resizable/options.js b/tests/unit/resizable/options.js index add8d8034..b80c051d5 100644 --- a/tests/unit/resizable/options.js +++ b/tests/unit/resizable/options.js @@ -542,21 +542,22 @@ QUnit.test( "alsoResize + multiple selection", function( assert ) { QUnit.test( "alsoResize with box-sizing: border-box", function( assert ) { assert.expect( 4 ); + $( "<style> * { box-sizing: border-box; } </style>" ).appendTo( "#qunit-fixture" ); + var other = $( "<div>" ) .css( { - width: 50, - height: 50, - padding: 10, - border: 5 + width: "50px", + height: "50px", + padding: "10px", + border: "5px", + borderStyle: "solid" } ) - .appendTo( "body" ), + .appendTo( "#qunit-fixture" ), element = $( "#resizable1" ).resizable( { alsoResize: other } ), handle = ".ui-resizable-se"; - $( "*" ).css( "box-sizing", "border-box" ); - testHelper.drag( handle, 80, 80 ); assert.equal( element.width(), 180, "resizable width" ); @@ -565,4 +566,51 @@ QUnit.test( "alsoResize with box-sizing: border-box", function( assert ) { assert.equal( parseFloat( other.css( "height" ) ), 130, "alsoResize height" ); } ); +QUnit.test( "alsoResize with scrollbars and box-sizing: border-box", function( assert ) { + assert.expect( 4 ); + testAlsoResizeWithBoxSizing( assert, { + isBorderBox: true + } ); +} ); + +QUnit.test( "alsoResize with scrollbars and box-sizing: content-box", function( assert ) { + assert.expect( 4 ); + testAlsoResizeWithBoxSizing( assert, { + isBorderBox: false + } ); +} ); + +function testAlsoResizeWithBoxSizing( assert, options ) { + var widthBefore, heightBefore, + cssBoxSizing = options.isBorderBox ? "border-box" : "content-box", + other = $( "<div>" ) + .css( { + width: "150px", + height: "150px", + padding: "10px", + border: "5px", + borderStyle: "solid", + margin: "20px", + overflow: "scroll" + } ) + .appendTo( "#qunit-fixture" ), + element = $( "#resizable1" ).resizable( { + alsoResize: other + } ), + handle = ".ui-resizable-se"; + + $( "<style> * { box-sizing: " + cssBoxSizing + "; } </style>" ).appendTo( "#qunit-fixture" ); + + // In some browsers scrollbar may change element computed size. + widthBefore = other.innerWidth(); + heightBefore = other.innerHeight(); + + testHelper.drag( handle, 80, 80 ); + + assert.equal( element.width(), 180, "resizable width" ); + assert.equal( parseFloat( other.innerWidth() ), widthBefore + 80, "alsoResize width" ); + assert.equal( element.height(), 180, "resizable height" ); + assert.equal( parseFloat( other.innerHeight() ), heightBefore + 80, "alsoResize height" ); +} + } ); diff --git a/ui/widgets/resizable.js b/ui/widgets/resizable.js index 1698d55e8..6f1e0ebde 100644 --- a/ui/widgets/resizable.js +++ b/ui/widgets/resizable.js @@ -80,12 +80,18 @@ $.widget( "ui.resizable", $.ui.mouse, { _hasScroll: function( el, a ) { - if ( $( el ).css( "overflow" ) === "hidden" ) { + var scroll, + has = false, + overflow = $( el ).css( "overflow" ); + + if ( overflow === "hidden" ) { return false; } + if ( overflow === "scroll" ) { + return true; + } - var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop", - has = false; + scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop"; if ( el[ scroll ] > 0 ) { return true; @@ -362,7 +368,7 @@ $.widget( "ui.resizable", $.ui.mouse, { _mouseStart: function( event ) { - var curleft, curtop, cursor, + var curleft, curtop, cursor, calculatedSize, o = this.options, el = this.element; @@ -381,20 +387,24 @@ $.widget( "ui.resizable", $.ui.mouse, { this.offset = this.helper.offset(); this.position = { left: curleft, top: curtop }; + if ( !this._helper ) { + calculatedSize = this._calculateAdjustedElementDimensions( el ); + } + this.size = this._helper ? { width: this.helper.width(), height: this.helper.height() } : { - width: el.width(), - height: el.height() + width: calculatedSize.width, + height: calculatedSize.height }; this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { - width: el.width(), - height: el.height() + width: calculatedSize.width, + height: calculatedSize.height }; this.sizeDiff = { @@ -690,6 +700,52 @@ $.widget( "ui.resizable", $.ui.mouse, { }; }, + _calculateAdjustedElementDimensions: function( element ) { + var elWidth, elHeight, paddingBorder, + ce = element.get( 0 ); + + if ( element.css( "box-sizing" ) !== "content-box" || + ( !this._hasScroll( ce ) && !this._hasScroll( ce, "left" ) ) ) { + return { + height: parseFloat( element.css( "height" ) ), + width: parseFloat( element.css( "width" ) ) + }; + } + + // Check if CSS inline styles are set and use those (usually from previous resizes) + elWidth = parseFloat( ce.style.width ); + elHeight = parseFloat( ce.style.height ); + + paddingBorder = this._getPaddingPlusBorderDimensions( element ); + elWidth = isNaN( elWidth ) ? + this._getElementTheoreticalSize( element, paddingBorder, "width" ) : + elWidth; + elHeight = isNaN( elHeight ) ? + this._getElementTheoreticalSize( element, paddingBorder, "height" ) : + elHeight; + + return { + height: elHeight, + width: elWidth + }; + }, + + _getElementTheoreticalSize: function( element, extraSize, dimension ) { + + // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border + var size = Math.max( 0, Math.ceil( + element.get( 0 )[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + extraSize[ dimension ] - + 0.5 + + // If offsetWidth/offsetHeight is unknown, then we can't determine theoretical size. + // Use an explicit zero to avoid NaN. + // See https://github.com/jquery/jquery/issues/3964 + ) ) || 0; + + return size; + }, + _proportionallyResize: function() { if ( !this._proportionallyResizeElements.length ) { @@ -1044,9 +1100,11 @@ $.ui.plugin.add( "resizable", "alsoResize", { o = that.options; $( o.alsoResize ).each( function() { - var el = $( this ); + var el = $( this ), + elSize = that._calculateAdjustedElementDimensions( el ); + el.data( "ui-resizable-alsoresize", { - width: parseFloat( el.css( "width" ) ), height: parseFloat( el.css( "height" ) ), + width: elSize.width, height: elSize.height, left: parseFloat( el.css( "left" ) ), top: parseFloat( el.css( "top" ) ) } ); } ); |