aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel GarcĂ­a <93217193+Daniel-Garmig@users.noreply.github.com>2024-09-09 23:51:57 +0200
committerGitHub <noreply@github.com>2024-09-09 23:51:57 +0200
commitc934995efa431efe0b15b6f9a6b614e6b8e88399 (patch)
tree9a4eed3162984e79521bd0f5369ca5d7e16090e3
parentd564731f20a5eee6c6e373344a2bd6fc9d047e63 (diff)
downloadjquery-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.js68
-rw-r--r--tests/unit/resizable/options.js62
-rw-r--r--ui/widgets/resizable.js78
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" ) )
} );
} );