Skip to content

Commit

Permalink
Resizable: Fix content shrink on resize
Browse files Browse the repository at this point in the history
Make resizable elements not shrink on resize when they have scrollbars
and "box-sizing: content-box".

Fixes: gh-2277
Closes gh-2281
  • Loading branch information
Daniel-Garmig committed Sep 9, 2024
1 parent d564731 commit c934995
Show file tree
Hide file tree
Showing 3 changed files with 191 additions and 17 deletions.
68 changes: 68 additions & 0 deletions tests/unit/resizable/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)" );
}

} );
62 changes: 55 additions & 7 deletions tests/unit/resizable/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -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" );
Expand All @@ -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" );
}

} );
78 changes: 68 additions & 10 deletions ui/widgets/resizable.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand All @@ -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 = {
Expand Down Expand Up @@ -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 ) {
Expand Down Expand Up @@ -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" ) )
} );
} );
Expand Down

0 comments on commit c934995

Please sign in to comment.