* jQuery UI Resizable 1.12.1
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
//>>description: Enables resize functionality for any element.
//>>docs: http://api.jqueryui.com/resizable/
//>>demos: http://jqueryui.com/resizable/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/resizable.css
//>>css.theme: ../../themes/base/theme.css
if ( typeof define === "function" && define.amd ) {
// AMD. Register as an anonymous module.
$.widget( "ui.resizable", $.ui.mouse, {
widgetEventPrefix: "resize",
"ui-resizable-se": "ui-icon ui-icon-gripsmall-diagonal-se"
_num: function( value ) {
return parseFloat( value ) || 0;
_isNumber: function( value ) {
return !isNaN( parseFloat( value ) );
_hasScroll: function( el, a ) {
if ( $( el ).css( "overflow" ) === "hidden" ) {
var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
if ( el[ scroll ] > 0 ) {
// TODO: determine which cases actually cause this to happen
// if the element doesn't have the scroll set, see if it's possible to
has = ( el[ scroll ] > 0 );
this._addClass( "ui-resizable" );
_aspectRatio: !!( o.aspectRatio ),
aspectRatio: o.aspectRatio,
originalElement: this.element,
_proportionallyResizeElements: [],
_helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null
// Wrap the element if it cannot hold child nodes
if ( this.element[ 0 ].nodeName.match( /^(canvas|textarea|input|select|button|img)$/i ) ) {
$( "<div class='ui-wrapper' style='overflow: hidden;'></div>" ).css( {
position: this.element.css( "position" ),
width: this.element.outerWidth(),
height: this.element.outerHeight(),
top: this.element.css( "top" ),
left: this.element.css( "left" )
this.element = this.element.parent().data(
"ui-resizable", this.element.resizable( "instance" )
this.elementIsWrapper = true;
marginTop: this.originalElement.css( "marginTop" ),
marginRight: this.originalElement.css( "marginRight" ),
marginBottom: this.originalElement.css( "marginBottom" ),
marginLeft: this.originalElement.css( "marginLeft" )
this.element.css( margins );
this.originalElement.css( "margin", 0 );
// Prevent Safari textarea resize
this.originalResizeStyle = this.originalElement.css( "resize" );
this.originalElement.css( "resize", "none" );
this._proportionallyResizeElements.push( this.originalElement.css( {
// avoid IE jump (hard set the margin)
this.originalElement.css( margins );
this._proportionallyResize();
.on( "mouseenter", function() {
that._removeClass( "ui-resizable-autohide" );
.on( "mouseleave", function() {
that._addClass( "ui-resizable-autohide" );
_destroy = function( exp ) {
.removeData( "resizable" )
.removeData( "ui-resizable" )
.find( ".ui-resizable-handle" )
// TODO: Unwrap at same DOM position
if ( this.elementIsWrapper ) {
_destroy( this.element );
this.originalElement.css( {
position: wrapper.css( "position" ),
width: wrapper.outerWidth(),
height: wrapper.outerHeight(),
top: wrapper.css( "top" ),
left: wrapper.css( "left" )
} ).insertAfter( wrapper );
this.originalElement.css( "resize", this.originalResizeStyle );
_destroy( this.originalElement );
_setOption: function( key, value ) {
this._super( key, value );
_setupHandles: function() {
var o = this.options, handle, i, n, hname, axis, that = this;
this.handles = o.handles ||
( !$( ".ui-resizable-handle", this.element ).length ?
if ( this.handles.constructor === String ) {
if ( this.handles === "all" ) {
this.handles = "n,e,s,w,se,sw,ne,nw";
n = this.handles.split( "," );
for ( i = 0; i < n.length; i++ ) {
handle = $.trim( n[ i ] );
hname = "ui-resizable-" + handle;
this._addClass( axis, "ui-resizable-handle " + hname );
axis.css( { zIndex: o.zIndex } );
this.handles[ handle ] = ".ui-resizable-" + handle;
this.element.append( axis );
this._renderAxis = function( target ) {
var i, axis, padPos, padWrapper;
target = target || this.element;
for ( i in this.handles ) {
if ( this.handles[ i ].constructor === String ) {
this.handles[ i ] = this.element.children( this.handles[ i ] ).first().show();
} else if ( this.handles[ i ].jquery || this.handles[ i ].nodeType ) {
this.handles[ i ] = $( this.handles[ i ] );
this._on( this.handles[ i ], { "mousedown": that._mouseDown } );
if ( this.elementIsWrapper &&
this.originalElement[ 0 ]
.match( /^(textarea|input|select|button)$/i ) ) {
axis = $( this.handles[ i ], this.element );
padWrapper = /sw|ne|nw|se|n|s/.test( i ) ?
/ne|nw|n/.test( i ) ? "Top" :
/se|sw|s/.test( i ) ? "Bottom" :
/^e$/.test( i ) ? "Right" : "Left" ].join( "" );
target.css( padPos, padWrapper );
this._proportionallyResize();
this._handles = this._handles.add( this.handles[ i ] );
// TODO: make renderAxis a prototype function
this._renderAxis( this.element );
this._handles = this._handles.add( this.element.find( ".ui-resizable-handle" ) );
this._handles.disableSelection();
this._handles.on( "mouseover", function() {
axis = this.className.match( /ui-resizable-(se|sw|ne|nw|n|e|s|w)/i );
that.axis = axis && axis[ 1 ] ? axis[ 1 ] : "se";
this._addClass( "ui-resizable-autohide" );
_removeHandles: function() {
_mouseCapture: function( event ) {
for ( i in this.handles ) {
handle = $( this.handles[ i ] )[ 0 ];
if ( handle === event.target || $.contains( handle, event.target ) ) {
return !this.options.disabled && capture;
_mouseStart: function( event ) {
var curleft, curtop, cursor,
curleft = this._num( this.helper.css( "left" ) );
curtop = this._num( this.helper.css( "top" ) );
curleft += $( o.containment ).scrollLeft() || 0;
curtop += $( o.containment ).scrollTop() || 0;
this.offset = this.helper.offset();
this.position = { left: curleft, top: curtop };
this.size = this._helper ? {
width: this.helper.width(),
height: this.helper.height()
this.originalSize = this._helper ? {
width: el.outerWidth() - el.width(),
height: el.outerHeight() - el.height()
this.originalPosition = { left: curleft, top: curtop };
this.originalMousePosition = { left: event.pageX, top: event.pageY };
this.aspectRatio = ( typeof o.aspectRatio === "number" ) ?
( ( this.originalSize.width / this.originalSize.height ) || 1 );
cursor = $( ".ui-resizable-" + this.axis ).css( "cursor" );
$( "body" ).css( "cursor", cursor === "auto" ? this.axis + "-resize" : cursor );
this._addClass( "ui-resizable-resizing" );
this._propagate( "start", event );
_mouseDrag: function( event ) {
smp = this.originalMousePosition,
dx = ( event.pageX - smp.left ) || 0,
dy = ( event.pageY - smp.top ) || 0,
trigger = this._change[ a ];
this._updatePrevProperties();
data = trigger.apply( this, [ event, dx, dy ] );
this._updateVirtualBoundaries( event.shiftKey );
if ( this._aspectRatio || event.shiftKey ) {
data = this._updateRatio( data, event );
data = this._respectSize( data, event );
this._updateCache( data );
this._propagate( "resize", event );
props = this._applyChanges();
if ( !this._helper && this._proportionallyResizeElements.length ) {
this._proportionallyResize();
if ( !$.isEmptyObject( props ) ) {
this._updatePrevProperties();
this._trigger( "resize", event, this.ui() );
_mouseStop: function( event ) {
var pr, ista, soffseth, soffsetw, s, left, top,
o = this.options, that = this;
pr = this._proportionallyResizeElements;
ista = pr.length && ( /textarea/i ).test( pr[ 0 ].nodeName );
soffseth = ista && this._hasScroll( pr[ 0 ], "left" ) ? 0 : that.sizeDiff.height;
soffsetw = ista ? 0 : that.sizeDiff.width;
width: ( that.helper.width() - soffsetw ),
height: ( that.helper.height() - soffseth )
left = ( parseFloat( that.element.css( "left" ) ) +
( that.position.left - that.originalPosition.left ) ) || null;
top = ( parseFloat( that.element.css( "top" ) ) +
( that.position.top - that.originalPosition.top ) ) || null;
this.element.css( $.extend( s, { top: top, left: left } ) );
that.helper.height( that.size.height );
that.helper.width( that.size.width );
if ( this._helper && !o.animate ) {
this._proportionallyResize();
$( "body" ).css( "cursor", "auto" );
this._removeClass( "ui-resizable-resizing" );
this._propagate( "stop", event );
_updatePrevProperties: function() {