jquery-ui/ui/widgets/resizable.js

1276 lines
31 KiB
JavaScript
Raw Normal View History

/*!
* jQuery UI Resizable @VERSION
* https://jqueryui.com
2008-06-04 02:34:33 +00:00
*
* Copyright OpenJS Foundation and other contributors
2012-08-09 14:13:24 +00:00
* Released under the MIT license.
* https://jquery.org/license
2008-06-04 02:34:33 +00:00
*/
//>>label: Resizable
//>>group: Interactions
//>>description: Enables resize functionality for any element.
//>>docs: https://api.jqueryui.com/resizable/
//>>demos: https://jqueryui.com/resizable/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/resizable.css
//>>css.theme: ../../themes/base/theme.css
2015-08-24 12:58:35 +00:00
( function( factory ) {
"use strict";
if ( typeof define === "function" && define.amd ) {
// AMD. Register as an anonymous module.
2015-08-24 12:58:35 +00:00
define( [
"jquery",
"./mouse",
"../disable-selection",
"../plugin",
"../version",
"../widget"
], factory );
} else {
// Browser globals
factory( jQuery );
}
} )( function( $ ) {
"use strict";
2008-06-04 02:34:33 +00:00
2015-08-24 12:58:35 +00:00
$.widget( "ui.resizable", $.ui.mouse, {
version: "@VERSION",
widgetEventPrefix: "resize",
options: {
alsoResize: false,
animate: false,
animateDuration: "slow",
animateEasing: "swing",
aspectRatio: false,
autoHide: false,
classes: {
"ui-resizable-se": "ui-icon ui-icon-gripsmall-diagonal-se"
},
containment: false,
ghost: false,
grid: false,
handles: "e,s,se",
helper: false,
maxHeight: null,
maxWidth: null,
minHeight: 10,
minWidth: 10,
2015-08-24 12:58:35 +00:00
// See #7960
zIndex: 90,
// Callbacks
resize: null,
start: null,
stop: null
},
_num: function( value ) {
2015-09-17 13:51:44 +00:00
return parseFloat( value ) || 0;
},
_isNumber: function( value ) {
2015-09-17 13:51:44 +00:00
return !isNaN( parseFloat( value ) );
},
_hasScroll: function( el, a ) {
var scroll,
has = false,
overflow = $( el ).css( "overflow" );
if ( overflow === "hidden" ) {
return false;
}
if ( overflow === "scroll" ) {
return true;
}
scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop";
if ( el[ scroll ] > 0 ) {
return true;
}
// TODO: determine which cases actually cause this to happen
// if the element doesn't have the scroll set, see if it's possible to
// set the scroll
try {
el[ scroll ] = 1;
has = ( el[ scroll ] > 0 );
el[ scroll ] = 0;
} catch ( e ) {
// `el` might be a string, then setting `scroll` will throw
// an error in strict mode; ignore it.
}
return has;
},
_create: function() {
var margins,
o = this.options,
that = this;
this._addClass( "ui-resizable" );
2009-01-24 01:36:22 +00:00
2015-08-24 12:58:35 +00:00
$.extend( this, {
_aspectRatio: !!( o.aspectRatio ),
aspectRatio: o.aspectRatio,
originalElement: this.element,
_proportionallyResizeElements: [],
_helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null
2015-08-24 12:58:35 +00:00
} );
// Wrap the element if it cannot hold child nodes
2015-08-24 12:58:35 +00:00
if ( this.element[ 0 ].nodeName.match( /^(canvas|textarea|input|select|button|img)$/i ) ) {
this.element.wrap(
$( "<div class='ui-wrapper'></div>" ).css( {
overflow: "hidden",
2015-08-24 12:58:35 +00:00
position: this.element.css( "position" ),
width: this.element.outerWidth(),
height: this.element.outerHeight(),
2015-08-24 12:58:35 +00:00
top: this.element.css( "top" ),
left: this.element.css( "left" )
} )
2008-06-04 02:34:33 +00:00
);
this.element = this.element.parent().data(
"ui-resizable", this.element.resizable( "instance" )
);
this.elementIsWrapper = true;
margins = {
2015-08-24 12:58:35 +00:00
marginTop: this.originalElement.css( "marginTop" ),
marginRight: this.originalElement.css( "marginRight" ),
marginBottom: this.originalElement.css( "marginBottom" ),
marginLeft: this.originalElement.css( "marginLeft" )
};
this.element.css( margins );
2015-08-24 12:58:35 +00:00
// Support: Safari
// Prevent Safari textarea resize
2015-08-24 12:58:35 +00:00
this.originalResizeStyle = this.originalElement.css( "resize" );
this.originalElement.css( "resize", "none" );
2015-08-24 12:58:35 +00:00
this._proportionallyResizeElements.push( this.originalElement.css( {
2014-08-11 13:51:45 +00:00
position: "static",
zoom: 1,
display: "block"
2015-08-24 12:58:35 +00:00
} ) );
2008-06-04 02:34:33 +00:00
this._proportionallyResize();
}
this._setupHandles();
if ( o.autoHide ) {
$( this.element )
.on( "mouseenter", function() {
if ( o.disabled ) {
return;
}
that._removeClass( "ui-resizable-autohide" );
that._handles.show();
} )
.on( "mouseleave", function() {
if ( o.disabled ) {
return;
}
if ( !that.resizing ) {
that._addClass( "ui-resizable-autohide" );
that._handles.hide();
}
} );
}
this._mouseInit();
},
_destroy: function() {
this._mouseDestroy();
this._addedHandles.remove();
var wrapper,
_destroy = function( exp ) {
$( exp )
.removeData( "resizable" )
.removeData( "ui-resizable" )
.off( ".resizable" );
};
// TODO: Unwrap at same DOM position
if ( this.elementIsWrapper ) {
_destroy( this.element );
wrapper = 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 );
wrapper.remove();
}
this.originalElement.css( "resize", this.originalResizeStyle );
_destroy( this.originalElement );
return this;
},
_setOption: function( key, value ) {
this._super( key, value );
switch ( key ) {
case "handles":
this._removeHandles();
this._setupHandles();
break;
case "aspectRatio":
this._aspectRatio = !!value;
break;
default:
break;
}
},
_setupHandles: function() {
var o = this.options, handle, i, n, hname, axis, that = this;
2014-08-11 13:51:45 +00:00
this.handles = o.handles ||
2015-08-24 12:58:35 +00:00
( !$( ".ui-resizable-handle", this.element ).length ?
2014-08-11 13:51:45 +00:00
"e,s,se" : {
n: ".ui-resizable-n",
e: ".ui-resizable-e",
s: ".ui-resizable-s",
w: ".ui-resizable-w",
se: ".ui-resizable-se",
sw: ".ui-resizable-sw",
ne: ".ui-resizable-ne",
nw: ".ui-resizable-nw"
} );
this._handles = $();
this._addedHandles = $();
if ( this.handles.constructor === String ) {
2015-08-24 12:58:35 +00:00
if ( this.handles === "all" ) {
this.handles = "n,e,s,w,se,sw,ne,nw";
}
2015-08-24 12:58:35 +00:00
n = this.handles.split( "," );
this.handles = {};
2015-08-24 12:58:35 +00:00
for ( i = 0; i < n.length; i++ ) {
2009-01-24 01:36:22 +00:00
handle = String.prototype.trim.call( n[ i ] );
2014-08-11 13:51:45 +00:00
hname = "ui-resizable-" + handle;
2015-08-24 12:58:35 +00:00
axis = $( "<div>" );
this._addClass( axis, "ui-resizable-handle " + hname );
2009-01-24 01:36:22 +00:00
2015-08-24 12:58:35 +00:00
axis.css( { zIndex: o.zIndex } );
2009-01-06 09:07:15 +00:00
2015-08-24 12:58:35 +00:00
this.handles[ handle ] = ".ui-resizable-" + handle;
if ( !this.element.children( this.handles[ handle ] ).length ) {
this.element.append( axis );
this._addedHandles = this._addedHandles.add( axis );
}
2008-06-04 02:34:33 +00:00
}
2008-06-04 02:34:33 +00:00
}
2015-08-24 12:58:35 +00:00
this._renderAxis = function( target ) {
2009-01-24 01:36:22 +00:00
var i, axis, padPos, padWrapper;
2008-06-04 02:34:33 +00:00
target = target || this.element;
2015-08-24 12:58:35 +00:00
for ( i in this.handles ) {
2009-01-24 01:36:22 +00:00
2015-08-24 12:58:35 +00:00
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 ] );
2015-08-24 12:58:35 +00:00
this._on( this.handles[ i ], { "mousedown": that._mouseDown } );
}
if ( this.elementIsWrapper &&
this.originalElement[ 0 ]
.nodeName
.match( /^(textarea|input|select|button)$/i ) ) {
2015-08-24 12:58:35 +00:00
axis = $( this.handles[ i ], this.element );
padWrapper = /sw|ne|nw|se|n|s/.test( i ) ?
axis.outerHeight() :
axis.outerWidth();
padPos = [ "padding",
2015-08-24 12:58:35 +00:00
/ne|nw|n/.test( i ) ? "Top" :
/se|sw|s/.test( i ) ? "Bottom" :
/^e$/.test( i ) ? "Right" : "Left" ].join( "" );
2015-08-24 12:58:35 +00:00
target.css( padPos, padWrapper );
2008-06-04 02:34:33 +00:00
this._proportionallyResize();
}
2009-01-24 01:36:22 +00:00
this._handles = this._handles.add( this.handles[ i ] );
2008-06-04 02:34:33 +00:00
}
};
// TODO: make renderAxis a prototype function
2015-08-24 12:58:35 +00:00
this._renderAxis( this.element );
2009-01-24 01:36:22 +00:00
this._handles = this._handles.add( this.element.find( ".ui-resizable-handle" ) );
this._handles.disableSelection();
this._handles.on( "mouseover", function() {
2015-08-24 12:58:35 +00:00
if ( !that.resizing ) {
if ( this.className ) {
axis = this.className.match( /ui-resizable-(se|sw|ne|nw|n|e|s|w)/i );
}
2015-08-24 12:58:35 +00:00
that.axis = axis && axis[ 1 ] ? axis[ 1 ] : "se";
2008-06-04 02:34:33 +00:00
}
2015-08-24 12:58:35 +00:00
} );
2015-08-24 12:58:35 +00:00
if ( o.autoHide ) {
this._handles.hide();
this._addClass( "ui-resizable-autohide" );
2008-06-04 02:34:33 +00:00
}
},
_removeHandles: function() {
this._addedHandles.remove();
2008-06-04 02:34:33 +00:00
},
2015-08-24 12:58:35 +00:00
_mouseCapture: function( event ) {
var i, handle,
capture = false;
2015-08-24 12:58:35 +00:00
for ( i in this.handles ) {
handle = $( this.handles[ i ] )[ 0 ];
if ( handle === event.target || $.contains( handle, event.target ) ) {
capture = true;
}
2008-06-04 02:34:33 +00:00
}
return !this.options.disabled && capture;
},
2015-08-24 12:58:35 +00:00
_mouseStart: function( event ) {
var curleft, curtop, cursor, calculatedSize,
o = this.options,
el = this.element;
2009-01-24 01:36:22 +00:00
this.resizing = true;
2008-06-04 02:34:33 +00:00
this._renderProxy();
2015-08-24 12:58:35 +00:00
curleft = this._num( this.helper.css( "left" ) );
curtop = this._num( this.helper.css( "top" ) );
2015-08-24 12:58:35 +00:00
if ( o.containment ) {
curleft += $( o.containment ).scrollLeft() || 0;
curtop += $( o.containment ).scrollTop() || 0;
2008-07-08 17:39:07 +00:00
}
2008-06-04 02:34:33 +00:00
this.offset = this.helper.offset();
this.position = { left: curleft, top: curtop };
2014-08-11 13:51:45 +00:00
if ( !this._helper ) {
calculatedSize = this._calculateAdjustedElementDimensions( el );
}
2014-08-11 13:51:45 +00:00
this.size = this._helper ? {
width: this.helper.width(),
height: this.helper.height()
} : {
width: calculatedSize.width,
height: calculatedSize.height
2014-08-11 13:51:45 +00:00
};
this.originalSize = this._helper ? {
width: el.outerWidth(),
height: el.outerHeight()
} : {
width: calculatedSize.width,
height: calculatedSize.height
2014-08-11 13:51:45 +00:00
};
this.sizeDiff = {
width: el.outerWidth() - el.width(),
height: el.outerHeight() - el.height()
};
2008-06-04 02:34:33 +00:00
this.originalPosition = { left: curleft, top: curtop };
this.originalMousePosition = { left: event.pageX, top: event.pageY };
2015-08-24 12:58:35 +00:00
this.aspectRatio = ( typeof o.aspectRatio === "number" ) ?
2014-08-11 13:51:45 +00:00
o.aspectRatio :
2015-08-24 12:58:35 +00:00
( ( this.originalSize.width / this.originalSize.height ) || 1 );
2015-08-24 12:58:35 +00:00
cursor = $( ".ui-resizable-" + this.axis ).css( "cursor" );
$( "body" ).css( "cursor", cursor === "auto" ? this.axis + "-resize" : cursor );
this._addClass( "ui-resizable-resizing" );
2015-08-24 12:58:35 +00:00
this._propagate( "start", event );
2008-06-04 02:34:33 +00:00
return true;
},
2015-08-24 12:58:35 +00:00
_mouseDrag: function( event ) {
var data, props,
smp = this.originalMousePosition,
a = this.axis,
2015-08-24 12:58:35 +00:00
dx = ( event.pageX - smp.left ) || 0,
dy = ( event.pageY - smp.top ) || 0,
trigger = this._change[ a ];
this._updatePrevProperties();
2015-08-24 12:58:35 +00:00
if ( !trigger ) {
return false;
}
2015-08-24 12:58:35 +00:00
data = trigger.apply( this, [ event, dx, dy ] );
2015-08-24 12:58:35 +00:00
this._updateVirtualBoundaries( event.shiftKey );
if ( this._aspectRatio || event.shiftKey ) {
data = this._updateRatio( data, event );
}
2015-08-24 12:58:35 +00:00
data = this._respectSize( data, event );
2015-08-24 12:58:35 +00:00
this._updateCache( data );
2015-08-24 12:58:35 +00:00
this._propagate( "resize", event );
props = this._applyChanges();
if ( !this._helper && this._proportionallyResizeElements.length ) {
2008-06-04 02:34:33 +00:00
this._proportionallyResize();
}
if ( !$.isEmptyObject( props ) ) {
this._updatePrevProperties();
this._trigger( "resize", event, this.ui() );
this._applyChanges();
}
2008-06-04 02:34:33 +00:00
return false;
},
2015-08-24 12:58:35 +00:00
_mouseStop: function( event ) {
this.resizing = false;
var pr, ista, soffseth, soffsetw, s, left, top,
o = this.options, that = this;
2015-08-24 12:58:35 +00:00
if ( this._helper ) {
pr = this._proportionallyResizeElements;
2015-08-24 12:58:35 +00:00
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;
2014-08-11 13:51:45 +00:00
s = {
2015-08-24 12:58:35 +00:00
width: ( that.helper.width() - soffsetw ),
height: ( that.helper.height() - soffseth )
2014-08-11 13:51:45 +00:00
};
2015-09-17 13:51:44 +00:00
left = ( parseFloat( that.element.css( "left" ) ) +
2015-08-24 12:58:35 +00:00
( that.position.left - that.originalPosition.left ) ) || null;
2015-09-17 13:51:44 +00:00
top = ( parseFloat( that.element.css( "top" ) ) +
2015-08-24 12:58:35 +00:00
( that.position.top - that.originalPosition.top ) ) || null;
2015-08-24 12:58:35 +00:00
if ( !o.animate ) {
this.element.css( $.extend( s, { top: top, left: left } ) );
}
2015-08-24 12:58:35 +00:00
that.helper.height( that.size.height );
that.helper.width( that.size.width );
2015-08-24 12:58:35 +00:00
if ( this._helper && !o.animate ) {
this._proportionallyResize();
}
2008-06-04 02:34:33 +00:00
}
2015-08-24 12:58:35 +00:00
$( "body" ).css( "cursor", "auto" );
this._removeClass( "ui-resizable-resizing" );
2015-08-24 12:58:35 +00:00
this._propagate( "stop", event );
2015-08-24 12:58:35 +00:00
if ( this._helper ) {
this.helper.remove();
}
2008-06-04 02:34:33 +00:00
return false;
2009-01-24 01:36:22 +00:00
2008-06-04 02:34:33 +00:00
},
_updatePrevProperties: function() {
this.prevPosition = {
top: this.position.top,
left: this.position.left
};
this.prevSize = {
width: this.size.width,
height: this.size.height
};
},
_applyChanges: function() {
var props = {};
if ( this.position.top !== this.prevPosition.top ) {
props.top = this.position.top + "px";
}
if ( this.position.left !== this.prevPosition.left ) {
props.left = this.position.left + "px";
}
this.helper.css( props );
if ( this.size.width !== this.prevSize.width ) {
props.width = this.size.width + "px";
this.helper.width( props.width );
}
if ( this.size.height !== this.prevSize.height ) {
props.height = this.size.height + "px";
this.helper.height( props.height );
}
return props;
},
2015-08-24 12:58:35 +00:00
_updateVirtualBoundaries: function( forceAspectRatio ) {
var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b,
o = this.options;
b = {
2015-08-24 12:58:35 +00:00
minWidth: this._isNumber( o.minWidth ) ? o.minWidth : 0,
maxWidth: this._isNumber( o.maxWidth ) ? o.maxWidth : Infinity,
minHeight: this._isNumber( o.minHeight ) ? o.minHeight : 0,
maxHeight: this._isNumber( o.maxHeight ) ? o.maxHeight : Infinity
};
2015-08-24 12:58:35 +00:00
if ( this._aspectRatio || forceAspectRatio ) {
pMinWidth = b.minHeight * this.aspectRatio;
pMinHeight = b.minWidth / this.aspectRatio;
pMaxWidth = b.maxHeight * this.aspectRatio;
pMaxHeight = b.maxWidth / this.aspectRatio;
2015-08-24 12:58:35 +00:00
if ( pMinWidth > b.minWidth ) {
b.minWidth = pMinWidth;
}
2015-08-24 12:58:35 +00:00
if ( pMinHeight > b.minHeight ) {
b.minHeight = pMinHeight;
}
2015-08-24 12:58:35 +00:00
if ( pMaxWidth < b.maxWidth ) {
b.maxWidth = pMaxWidth;
}
2015-08-24 12:58:35 +00:00
if ( pMaxHeight < b.maxHeight ) {
b.maxHeight = pMaxHeight;
}
}
this._vBoundaries = b;
},
2015-08-24 12:58:35 +00:00
_updateCache: function( data ) {
2008-06-04 02:34:33 +00:00
this.offset = this.helper.offset();
2015-08-24 12:58:35 +00:00
if ( this._isNumber( data.left ) ) {
this.position.left = data.left;
}
2015-08-24 12:58:35 +00:00
if ( this._isNumber( data.top ) ) {
this.position.top = data.top;
}
2015-08-24 12:58:35 +00:00
if ( this._isNumber( data.height ) ) {
this.size.height = data.height;
}
2015-08-24 12:58:35 +00:00
if ( this._isNumber( data.width ) ) {
this.size.width = data.width;
}
2008-06-04 02:34:33 +00:00
},
_updateRatio: function( data ) {
var cpos = this.position,
csize = this.size,
a = this.axis;
2015-08-24 12:58:35 +00:00
if ( this._isNumber( data.height ) ) {
data.width = ( data.height * this.aspectRatio );
} else if ( this._isNumber( data.width ) ) {
data.height = ( data.width / this.aspectRatio );
}
2015-08-24 12:58:35 +00:00
if ( a === "sw" ) {
data.left = cpos.left + ( csize.width - data.width );
2008-06-04 02:34:33 +00:00
data.top = null;
}
2015-08-24 12:58:35 +00:00
if ( a === "nw" ) {
data.top = cpos.top + ( csize.height - data.height );
data.left = cpos.left + ( csize.width - data.width );
2008-06-04 02:34:33 +00:00
}
2008-06-04 02:34:33 +00:00
return data;
},
_respectSize: function( data ) {
var o = this._vBoundaries,
a = this.axis,
2015-08-24 12:58:35 +00:00
ismaxw = this._isNumber( data.width ) && o.maxWidth && ( o.maxWidth < data.width ),
ismaxh = this._isNumber( data.height ) && o.maxHeight && ( o.maxHeight < data.height ),
isminw = this._isNumber( data.width ) && o.minWidth && ( o.minWidth > data.width ),
isminh = this._isNumber( data.height ) && o.minHeight && ( o.minHeight > data.height ),
dw = this.originalPosition.left + this.originalSize.width,
dh = this.originalPosition.top + this.originalSize.height,
2015-08-24 12:58:35 +00:00
cw = /sw|nw|w/.test( a ), ch = /nw|ne|n/.test( a );
if ( isminw ) {
data.width = o.minWidth;
}
2015-08-24 12:58:35 +00:00
if ( isminh ) {
data.height = o.minHeight;
}
2015-08-24 12:58:35 +00:00
if ( ismaxw ) {
data.width = o.maxWidth;
}
2015-08-24 12:58:35 +00:00
if ( ismaxh ) {
data.height = o.maxHeight;
}
2015-08-24 12:58:35 +00:00
if ( isminw && cw ) {
data.left = dw - o.minWidth;
}
2015-08-24 12:58:35 +00:00
if ( ismaxw && cw ) {
data.left = dw - o.maxWidth;
}
2015-08-24 12:58:35 +00:00
if ( isminh && ch ) {
data.top = dh - o.minHeight;
}
2015-08-24 12:58:35 +00:00
if ( ismaxh && ch ) {
data.top = dh - o.maxHeight;
}
// Fixing jump error on top/left - bug #2330
2015-08-24 12:58:35 +00:00
if ( !data.width && !data.height && !data.left && data.top ) {
data.top = null;
2015-08-24 12:58:35 +00:00
} else if ( !data.width && !data.height && !data.top && data.left ) {
data.left = null;
}
2008-06-04 02:34:33 +00:00
return data;
},
_getPaddingPlusBorderDimensions: function( element ) {
var i = 0,
widths = [],
borders = [
element.css( "borderTopWidth" ),
element.css( "borderRightWidth" ),
element.css( "borderBottomWidth" ),
element.css( "borderLeftWidth" )
],
paddings = [
element.css( "paddingTop" ),
element.css( "paddingRight" ),
element.css( "paddingBottom" ),
element.css( "paddingLeft" )
];
for ( ; i < 4; i++ ) {
2015-09-17 13:51:44 +00:00
widths[ i ] = ( parseFloat( borders[ i ] ) || 0 );
widths[ i ] += ( parseFloat( paddings[ i ] ) || 0 );
}
return {
height: widths[ 0 ] + widths[ 2 ],
width: widths[ 1 ] + widths[ 3 ]
};
},
_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;
},
2008-06-04 02:34:33 +00:00
_proportionallyResize: function() {
2009-01-24 01:36:22 +00:00
2015-08-24 12:58:35 +00:00
if ( !this._proportionallyResizeElements.length ) {
return;
}
var prel,
i = 0,
element = this.helper || this.element;
2009-01-24 01:36:22 +00:00
2015-08-24 12:58:35 +00:00
for ( ; i < this._proportionallyResizeElements.length; i++ ) {
2009-01-24 01:36:22 +00:00
2015-08-24 12:58:35 +00:00
prel = this._proportionallyResizeElements[ i ];
2009-01-24 01:36:22 +00:00
// TODO: Seems like a bug to cache this.outerDimensions
// considering that we are in a loop.
2015-08-24 12:58:35 +00:00
if ( !this.outerDimensions ) {
this.outerDimensions = this._getPaddingPlusBorderDimensions( prel );
}
2009-01-24 01:36:22 +00:00
2015-08-24 12:58:35 +00:00
prel.css( {
height: ( element.height() - this.outerDimensions.height ) || 0,
width: ( element.width() - this.outerDimensions.width ) || 0
} );
2009-01-24 01:36:22 +00:00
}
2009-01-16 05:57:34 +00:00
2008-06-04 02:34:33 +00:00
},
2008-06-04 02:34:33 +00:00
_renderProxy: function() {
2009-01-24 01:36:22 +00:00
2008-06-04 02:34:33 +00:00
var el = this.element, o = this.options;
this.elementOffset = el.offset();
2015-08-24 12:58:35 +00:00
if ( this._helper ) {
2009-01-24 01:36:22 +00:00
this.helper = this.helper || $( "<div></div>" ).css( { overflow: "hidden" } );
this._addClass( this.helper, this._helper );
2015-08-24 12:58:35 +00:00
this.helper.css( {
width: this.element.outerWidth(),
height: this.element.outerHeight(),
position: "absolute",
2014-08-11 13:51:45 +00:00
left: this.elementOffset.left + "px",
top: this.elementOffset.top + "px",
zIndex: ++o.zIndex //TODO: Don't modify option
2015-08-24 12:58:35 +00:00
} );
this.helper
2015-08-24 12:58:35 +00:00
.appendTo( "body" )
.disableSelection();
2008-06-04 02:34:33 +00:00
} else {
this.helper = this.element;
2008-06-04 02:34:33 +00:00
}
2009-01-24 01:36:22 +00:00
2008-06-04 02:34:33 +00:00
},
2008-06-04 02:34:33 +00:00
_change: {
2015-08-24 12:58:35 +00:00
e: function( event, dx ) {
2008-06-04 02:34:33 +00:00
return { width: this.originalSize.width + dx };
},
2015-08-24 12:58:35 +00:00
w: function( event, dx ) {
var cs = this.originalSize, sp = this.originalPosition;
2008-06-04 02:34:33 +00:00
return { left: sp.left + dx, width: cs.width - dx };
},
2015-08-24 12:58:35 +00:00
n: function( event, dx, dy ) {
var cs = this.originalSize, sp = this.originalPosition;
2008-06-04 02:34:33 +00:00
return { top: sp.top + dy, height: cs.height - dy };
},
2015-08-24 12:58:35 +00:00
s: function( event, dx, dy ) {
2008-06-04 02:34:33 +00:00
return { height: this.originalSize.height + dy };
},
2015-08-24 12:58:35 +00:00
se: function( event, dx, dy ) {
return $.extend( this._change.s.apply( this, arguments ),
this._change.e.apply( this, [ event, dx, dy ] ) );
2008-06-04 02:34:33 +00:00
},
2015-08-24 12:58:35 +00:00
sw: function( event, dx, dy ) {
return $.extend( this._change.s.apply( this, arguments ),
this._change.w.apply( this, [ event, dx, dy ] ) );
2008-06-04 02:34:33 +00:00
},
2015-08-24 12:58:35 +00:00
ne: function( event, dx, dy ) {
return $.extend( this._change.n.apply( this, arguments ),
this._change.e.apply( this, [ event, dx, dy ] ) );
2008-06-04 02:34:33 +00:00
},
2015-08-24 12:58:35 +00:00
nw: function( event, dx, dy ) {
return $.extend( this._change.n.apply( this, arguments ),
this._change.w.apply( this, [ event, dx, dy ] ) );
2008-06-04 02:34:33 +00:00
}
},
2015-08-24 12:58:35 +00:00
_propagate: function( n, event ) {
$.ui.plugin.call( this, n, [ event, this.ui() ] );
if ( n !== "resize" ) {
this._trigger( n, event, this.ui() );
}
},
plugins: {},
ui: function() {
return {
originalElement: this.originalElement,
element: this.element,
helper: this.helper,
position: this.position,
size: this.size,
originalSize: this.originalSize,
originalPosition: this.originalPosition
};
2008-06-04 02:34:33 +00:00
}
2015-08-24 12:58:35 +00:00
} );
2008-06-04 02:34:33 +00:00
/*
* Resizable Extensions
*/
2015-08-24 12:58:35 +00:00
$.ui.plugin.add( "resizable", "animate", {
stop: function( event ) {
2015-08-24 12:58:35 +00:00
var that = $( this ).resizable( "instance" ),
o = that.options,
pr = that._proportionallyResizeElements,
2015-08-24 12:58:35 +00:00
ista = pr.length && ( /textarea/i ).test( pr[ 0 ].nodeName ),
soffseth = ista && that._hasScroll( pr[ 0 ], "left" ) ? 0 : that.sizeDiff.height,
soffsetw = ista ? 0 : that.sizeDiff.width,
style = {
width: ( that.size.width - soffsetw ),
height: ( that.size.height - soffseth )
},
2015-09-17 13:51:44 +00:00
left = ( parseFloat( that.element.css( "left" ) ) +
2015-08-24 12:58:35 +00:00
( that.position.left - that.originalPosition.left ) ) || null,
2015-09-17 13:51:44 +00:00
top = ( parseFloat( that.element.css( "top" ) ) +
2015-08-24 12:58:35 +00:00
( that.position.top - that.originalPosition.top ) ) || null;
that.element.animate(
2015-08-24 12:58:35 +00:00
$.extend( style, top && left ? { top: top, left: left } : {} ), {
duration: o.animateDuration,
easing: o.animateEasing,
step: function() {
var data = {
2015-09-17 13:51:44 +00:00
width: parseFloat( that.element.css( "width" ) ),
height: parseFloat( that.element.css( "height" ) ),
top: parseFloat( that.element.css( "top" ) ),
left: parseFloat( that.element.css( "left" ) )
};
2015-08-24 12:58:35 +00:00
if ( pr && pr.length ) {
$( pr[ 0 ] ).css( { width: data.width, height: data.height } );
}
// Propagating resize, and updating values for each animation step
2015-08-24 12:58:35 +00:00
that._updateCache( data );
that._propagate( "resize", event );
}
}
);
}
2015-08-24 12:58:35 +00:00
} );
$.ui.plugin.add( "resizable", "containment", {
start: function() {
var element, p, co, ch, cw, width, height,
that = $( this ).resizable( "instance" ),
o = that.options,
el = that.element,
oc = o.containment,
ce = ( oc instanceof $ ) ?
oc.get( 0 ) :
( /parent/.test( oc ) ) ? el.parent().get( 0 ) : oc;
if ( !ce ) {
return;
}
that.containerElement = $( ce );
if ( /document/.test( oc ) || oc === document ) {
that.containerOffset = {
left: 0,
top: 0
};
that.containerPosition = {
left: 0,
top: 0
};
that.parentData = {
element: $( document ),
left: 0,
top: 0,
width: $( document ).width(),
height: $( document ).height() || document.body.parentNode.scrollHeight
2008-06-04 02:34:33 +00:00
};
} else {
element = $( ce );
p = [];
2015-08-24 12:58:35 +00:00
$( [ "Top", "Right", "Left", "Bottom" ] ).each( function( i, name ) {
p[ i ] = that._num( element.css( "padding" + name ) );
2015-08-24 12:58:35 +00:00
} );
2009-01-28 21:48:51 +00:00
that.containerOffset = element.offset();
that.containerPosition = element.position();
that.containerSize = {
height: ( element.innerHeight() - p[ 3 ] ),
width: ( element.innerWidth() - p[ 1 ] )
};
co = that.containerOffset;
ch = that.containerSize.height;
cw = that.containerSize.width;
width = ( that._hasScroll( ce, "left" ) ? ce.scrollWidth : cw );
height = ( that._hasScroll( ce ) ? ce.scrollHeight : ch );
that.parentData = {
element: ce,
left: co.left,
top: co.top,
width: width,
height: height
2008-06-04 02:34:33 +00:00
};
}
},
resize: function( event ) {
var woset, hoset, isParent, isOffsetRelative,
that = $( this ).resizable( "instance" ),
o = that.options,
co = that.containerOffset,
cp = that.position,
pRatio = that._aspectRatio || event.shiftKey,
cop = {
top: 0,
left: 0
},
ce = that.containerElement,
continueResize = true;
if ( ce[ 0 ] !== document && ( /static/ ).test( ce.css( "position" ) ) ) {
cop = co;
}
if ( cp.left < ( that._helper ? co.left : 0 ) ) {
2014-08-11 13:51:45 +00:00
that.size.width = that.size.width +
( that._helper ?
( that.position.left - co.left ) :
( that.position.left - cop.left ) );
if ( pRatio ) {
that.size.height = that.size.width / that.aspectRatio;
continueResize = false;
}
that.position.left = o.helper ? co.left : 0;
2008-06-04 02:34:33 +00:00
}
if ( cp.top < ( that._helper ? co.top : 0 ) ) {
2014-08-11 13:51:45 +00:00
that.size.height = that.size.height +
( that._helper ?
( that.position.top - co.top ) :
that.position.top );
if ( pRatio ) {
that.size.width = that.size.height * that.aspectRatio;
continueResize = false;
}
that.position.top = that._helper ? co.top : 0;
2008-06-04 02:34:33 +00:00
}
isParent = that.containerElement.get( 0 ) === that.element.parent().get( 0 );
isOffsetRelative = /relative|absolute/.test( that.containerElement.css( "position" ) );
if ( isParent && isOffsetRelative ) {
that.offset.left = that.parentData.left + that.position.left;
that.offset.top = that.parentData.top + that.position.top;
} else {
that.offset.left = that.element.offset().left;
that.offset.top = that.element.offset().top;
}
2014-08-11 13:51:45 +00:00
woset = Math.abs( that.sizeDiff.width +
2015-08-24 12:58:35 +00:00
( that._helper ?
2014-08-11 13:51:45 +00:00
that.offset.left - cop.left :
2015-08-24 12:58:35 +00:00
( that.offset.left - co.left ) ) );
2014-08-11 13:51:45 +00:00
hoset = Math.abs( that.sizeDiff.height +
2015-08-24 12:58:35 +00:00
( that._helper ?
2014-08-11 13:51:45 +00:00
that.offset.top - cop.top :
2015-08-24 12:58:35 +00:00
( that.offset.top - co.top ) ) );
if ( woset + that.size.width >= that.parentData.width ) {
that.size.width = that.parentData.width - woset;
if ( pRatio ) {
that.size.height = that.size.width / that.aspectRatio;
continueResize = false;
}
2008-06-04 02:34:33 +00:00
}
if ( hoset + that.size.height >= that.parentData.height ) {
that.size.height = that.parentData.height - hoset;
if ( pRatio ) {
that.size.width = that.size.height * that.aspectRatio;
continueResize = false;
}
2008-06-04 02:34:33 +00:00
}
2015-01-28 03:07:32 +00:00
if ( !continueResize ) {
that.position.left = that.prevPosition.left;
that.position.top = that.prevPosition.top;
that.size.width = that.prevSize.width;
that.size.height = that.prevSize.height;
}
},
2014-08-11 13:51:45 +00:00
stop: function() {
var that = $( this ).resizable( "instance" ),
o = that.options,
co = that.containerOffset,
cop = that.containerPosition,
ce = that.containerElement,
helper = $( that.helper ),
ho = helper.offset(),
w = helper.outerWidth() - that.sizeDiff.width,
h = helper.outerHeight() - that.sizeDiff.height;
if ( that._helper && !o.animate && ( /relative/ ).test( ce.css( "position" ) ) ) {
2015-08-24 12:58:35 +00:00
$( this ).css( {
left: ho.left - cop.left - co.left,
width: w,
height: h
2015-08-24 12:58:35 +00:00
} );
}
if ( that._helper && !o.animate && ( /static/ ).test( ce.css( "position" ) ) ) {
2015-08-24 12:58:35 +00:00
$( this ).css( {
left: ho.left - cop.left - co.left,
width: w,
height: h
2015-08-24 12:58:35 +00:00
} );
}
2008-06-04 02:34:33 +00:00
}
2015-08-24 12:58:35 +00:00
} );
2008-06-04 02:34:33 +00:00
2015-08-24 12:58:35 +00:00
$.ui.plugin.add( "resizable", "alsoResize", {
2014-08-11 13:51:45 +00:00
start: function() {
2015-08-24 12:58:35 +00:00
var that = $( this ).resizable( "instance" ),
o = that.options;
2015-08-24 12:58:35 +00:00
$( o.alsoResize ).each( function() {
var el = $( this ),
elSize = that._calculateAdjustedElementDimensions( el );
2015-08-24 12:58:35 +00:00
el.data( "ui-resizable-alsoresize", {
width: elSize.width, height: elSize.height,
2015-09-17 13:51:44 +00:00
left: parseFloat( el.css( "left" ) ), top: parseFloat( el.css( "top" ) )
2015-08-24 12:58:35 +00:00
} );
} );
},
2015-08-24 12:58:35 +00:00
resize: function( event, ui ) {
var that = $( this ).resizable( "instance" ),
o = that.options,
os = that.originalSize,
op = that.originalPosition,
delta = {
2015-08-24 12:58:35 +00:00
height: ( that.size.height - os.height ) || 0,
width: ( that.size.width - os.width ) || 0,
top: ( that.position.top - op.top ) || 0,
left: ( that.position.left - op.left ) || 0
};
2015-08-24 12:58:35 +00:00
$( o.alsoResize ).each( function() {
var el = $( this ), start = $( this ).data( "ui-resizable-alsoresize" ), style = {},
css = el.parents( ui.originalElement[ 0 ] ).length ?
[ "width", "height" ] :
[ "width", "height", "top", "left" ];
2015-08-24 12:58:35 +00:00
$.each( css, function( i, prop ) {
var sum = ( start[ prop ] || 0 ) + ( delta[ prop ] || 0 );
if ( sum && sum >= 0 ) {
style[ prop ] = sum || null;
}
2015-08-24 12:58:35 +00:00
} );
2015-08-24 12:58:35 +00:00
el.css( style );
} );
},
2014-08-11 13:51:45 +00:00
stop: function() {
$( this ).removeData( "ui-resizable-alsoresize" );
}
2015-08-24 12:58:35 +00:00
} );
2015-08-24 12:58:35 +00:00
$.ui.plugin.add( "resizable", "ghost", {
start: function() {
2009-01-24 01:36:22 +00:00
2015-08-24 12:58:35 +00:00
var that = $( this ).resizable( "instance" ), cs = that.size;
that.ghost = that.originalElement.clone();
2015-08-24 12:58:35 +00:00
that.ghost.css( {
opacity: 0.25,
display: "block",
position: "relative",
height: cs.height,
width: cs.width,
margin: 0,
left: 0,
top: 0
2015-08-24 12:58:35 +00:00
} );
that._addClass( that.ghost, "ui-resizable-ghost" );
// DEPRECATED
// TODO: remove after 1.12
if ( $.uiBackCompat === true && typeof that.options.ghost === "string" ) {
// Ghost option
that.ghost.addClass( this.options.ghost );
}
2015-08-24 12:58:35 +00:00
that.ghost.appendTo( that.helper );
2008-06-04 02:34:33 +00:00
},
2014-08-11 13:51:45 +00:00
resize: function() {
2015-08-24 12:58:35 +00:00
var that = $( this ).resizable( "instance" );
if ( that.ghost ) {
that.ghost.css( {
2014-08-11 13:51:45 +00:00
position: "relative",
height: that.size.height,
width: that.size.width
2015-08-24 12:58:35 +00:00
} );
}
2008-06-04 02:34:33 +00:00
},
stop: function() {
2015-08-24 12:58:35 +00:00
var that = $( this ).resizable( "instance" );
if ( that.ghost && that.helper ) {
that.helper.get( 0 ).removeChild( that.ghost.get( 0 ) );
}
2008-06-04 02:34:33 +00:00
}
2015-08-24 12:58:35 +00:00
} );
2008-06-04 02:34:33 +00:00
2015-08-24 12:58:35 +00:00
$.ui.plugin.add( "resizable", "grid", {
resize: function() {
var outerDimensions,
2015-08-24 12:58:35 +00:00
that = $( this ).resizable( "instance" ),
o = that.options,
cs = that.size,
os = that.originalSize,
op = that.originalPosition,
a = that.axis,
2014-08-11 13:51:45 +00:00
grid = typeof o.grid === "number" ? [ o.grid, o.grid ] : o.grid,
2015-08-24 12:58:35 +00:00
gridX = ( grid[ 0 ] || 1 ),
gridY = ( grid[ 1 ] || 1 ),
ox = Math.round( ( cs.width - os.width ) / gridX ) * gridX,
oy = Math.round( ( cs.height - os.height ) / gridY ) * gridY,
newWidth = os.width + ox,
newHeight = os.height + oy,
2015-08-24 12:58:35 +00:00
isMaxWidth = o.maxWidth && ( o.maxWidth < newWidth ),
isMaxHeight = o.maxHeight && ( o.maxHeight < newHeight ),
isMinWidth = o.minWidth && ( o.minWidth > newWidth ),
isMinHeight = o.minHeight && ( o.minHeight > newHeight );
o.grid = grid;
2015-08-24 12:58:35 +00:00
if ( isMinWidth ) {
newWidth += gridX;
}
2015-08-24 12:58:35 +00:00
if ( isMinHeight ) {
newHeight += gridY;
}
2015-08-24 12:58:35 +00:00
if ( isMaxWidth ) {
newWidth -= gridX;
}
2015-08-24 12:58:35 +00:00
if ( isMaxHeight ) {
newHeight -= gridY;
}
2015-08-24 12:58:35 +00:00
if ( /^(se|s|e)$/.test( a ) ) {
that.size.width = newWidth;
that.size.height = newHeight;
2015-08-24 12:58:35 +00:00
} else if ( /^(ne)$/.test( a ) ) {
that.size.width = newWidth;
that.size.height = newHeight;
that.position.top = op.top - oy;
2015-08-24 12:58:35 +00:00
} else if ( /^(sw)$/.test( a ) ) {
that.size.width = newWidth;
that.size.height = newHeight;
that.position.left = op.left - ox;
} else {
2015-08-24 12:58:35 +00:00
if ( newHeight - gridY <= 0 || newWidth - gridX <= 0 ) {
outerDimensions = that._getPaddingPlusBorderDimensions( this );
}
if ( newHeight - gridY > 0 ) {
that.size.height = newHeight;
that.position.top = op.top - oy;
} else {
newHeight = gridY - outerDimensions.height;
that.size.height = newHeight;
that.position.top = op.top + os.height - newHeight;
}
if ( newWidth - gridX > 0 ) {
that.size.width = newWidth;
that.position.left = op.left - ox;
} else {
newWidth = gridX - outerDimensions.width;
that.size.width = newWidth;
that.position.left = op.left + os.width - newWidth;
}
2008-06-04 02:34:33 +00:00
}
}
2015-08-24 12:58:35 +00:00
} );
2008-06-04 02:34:33 +00:00
return $.ui.resizable;
} );