: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* jQuery UI Draggable 1.13.3
* Copyright OpenJS Foundation and other contributors
* Released under the MIT license.
* https://jquery.org/license
//>>description: Enables dragging functionality for any element.
//>>docs: https://api.jqueryui.com/draggable/
//>>demos: https://jqueryui.com/draggable/
//>>css.structure: ../../themes/base/draggable.css
if ( typeof define === "function" && define.amd ) {
// AMD. Register as an anonymous module.
"../safe-active-element",
$.widget( "ui.draggable", $.ui.mouse, {
widgetEventPrefix: "drag",
connectToSortable: false,
if ( this.options.helper === "original" ) {
this._setPositionRelative();
if ( this.options.addClasses ) {
this._addClass( "ui-draggable" );
this._setHandleClassName();
_setOption: function( key, value ) {
this._super( key, value );
if ( key === "handle" ) {
this._removeHandleClassName();
this._setHandleClassName();
if ( ( this.helper || this.element ).is( ".ui-draggable-dragging" ) ) {
this.destroyOnClear = true;
this._removeHandleClassName();
_mouseCapture: function( event ) {
// Among others, prevent a drag on a resizable-handle
if ( this.helper || o.disabled ||
$( event.target ).closest( ".ui-resizable-handle" ).length > 0 ) {
//Quit if we're not on a valid handle
this.handle = this._getHandle( event );
this._blurActiveElement( event );
this._blockFrames( o.iframeFix === true ? "iframe" : o.iframeFix );
_blockFrames: function( selector ) {
this.iframeBlocks = this.document.find( selector ).map( function() {
.css( "position", "absolute" )
.appendTo( iframe.parent() )
.outerWidth( iframe.outerWidth() )
.outerHeight( iframe.outerHeight() )
.offset( iframe.offset() )[ 0 ];
_unblockFrames: function() {
if ( this.iframeBlocks ) {
this.iframeBlocks.remove();
delete this.iframeBlocks;
_blurActiveElement: function( event ) {
var activeElement = $.ui.safeActiveElement( this.document[ 0 ] ),
target = $( event.target );
// Don't blur if the event occurred on an element that is within
// the currently focused element
if ( target.closest( activeElement ).length ) {
// Blur any element that currently has focus, see #4261
$.ui.safeBlur( activeElement );
_mouseStart: function( event ) {
//Create and append the visible helper
this.helper = this._createHelper( event );
this._addClass( this.helper, "ui-draggable-dragging" );
this._cacheHelperProportions();
//If ddmanager is used for droppables, set the global draggable
$.ui.ddmanager.current = this;
* - Position generation -
* This block generates everything position related - it's the core of draggables.
//Cache the margins of the original element
//Store the helper's css position
this.cssPosition = this.helper.css( "position" );
this.scrollParent = this.helper.scrollParent( true );
this.offsetParent = this.helper.offsetParent();
this.hasFixedAncestor = this.helper.parents().filter( function() {
return $( this ).css( "position" ) === "fixed";
//The element's absolute position on the page minus margins
this.positionAbs = this.element.offset();
this._refreshOffsets( event );
//Generate the original position
this.originalPosition = this.position = this._generatePosition( event, false );
this.originalPageX = event.pageX;
this.originalPageY = event.pageY;
//Adjust the mouse offset relative to the helper if "cursorAt" is supplied
this._adjustOffsetFromHelper( o.cursorAt );
//Set a containment if given in the options
//Trigger event + callbacks
if ( this._trigger( "start", event ) === false ) {
//Recache the helper size
this._cacheHelperProportions();
//Prepare the droppable offsets
if ( $.ui.ddmanager && !o.dropBehaviour ) {
$.ui.ddmanager.prepareOffsets( this, event );
// Execute the drag once - this causes the helper not to be visible before getting its
this._mouseDrag( event, true );
// If the ddmanager is used for droppables, inform the manager that dragging has started
$.ui.ddmanager.dragStart( this, event );
_refreshOffsets: function( event ) {
top: this.positionAbs.top - this.margins.top,
left: this.positionAbs.left - this.margins.left,
parent: this._getParentOffset(),
relative: this._getRelativeOffset()
left: event.pageX - this.offset.left,
top: event.pageY - this.offset.top
_mouseDrag: function( event, noPropagation ) {
// reset any necessary cached properties (see #5009)
if ( this.hasFixedAncestor ) {
this.offset.parent = this._getParentOffset();
//Compute the helpers position
this.position = this._generatePosition( event, true );
this.positionAbs = this._convertPositionTo( "absolute" );
//Call plugins and callbacks and use the resulting position if something is returned
if ( this._trigger( "drag", event, ui ) === false ) {
this._mouseUp( new $.Event( "mouseup", event ) );
this.position = ui.position;
this.helper[ 0 ].style.left = this.position.left + "px";
this.helper[ 0 ].style.top = this.position.top + "px";
$.ui.ddmanager.drag( this, event );
_mouseStop: function( event ) {
//If we are using droppables, inform the manager about the drop
if ( $.ui.ddmanager && !this.options.dropBehaviour ) {
dropped = $.ui.ddmanager.drop( this, event );
//if a drop comes from outside (a sortable)
if ( ( this.options.revert === "invalid" && !dropped ) ||
( this.options.revert === "valid" && dropped ) ||
this.options.revert === true || ( typeof this.options.revert === "function" &&
this.options.revert.call( this.element, dropped ) )
$( this.helper ).animate(
parseInt( this.options.revertDuration, 10 ),
if ( that._trigger( "stop", event ) !== false ) {
if ( this._trigger( "stop", event ) !== false ) {
_mouseUp: function( event ) {
// If the ddmanager is used for droppables, inform the manager that dragging has stopped
$.ui.ddmanager.dragStop( this, event );
// Only need to focus if the event occurred on the draggable itself, see #10527
if ( this.handleElement.is( event.target ) ) {
// The interaction is over; whether or not the click resulted in a drag,
this.element.trigger( "focus" );
return $.ui.mouse.prototype._mouseUp.call( this, event );
if ( this.helper.is( ".ui-draggable-dragging" ) ) {
this._mouseUp( new $.Event( "mouseup", { target: this.element[ 0 ] } ) );
_getHandle: function( event ) {
return this.options.handle ?
!!$( event.target ).closest( this.element.find( this.options.handle ) ).length :
_setHandleClassName: function() {
this.handleElement = this.options.handle ?
this.element.find( this.options.handle ) : this.element;
this._addClass( this.handleElement, "ui-draggable-handle" );
_removeHandleClassName: function() {
this._removeClass( this.handleElement, "ui-draggable-handle" );
_createHelper: function( event ) {
helperIsFunction = typeof o.helper === "function",
helper = helperIsFunction ?
$( o.helper.apply( this.element[ 0 ], [ event ] ) ) :
this.element.clone().removeAttr( "id" ) :
if ( !helper.parents( "body" ).length ) {
helper.appendTo( ( o.appendTo === "parent" ?
this.element[ 0 ].parentNode :
// https://bugs.jqueryui.com/ticket/9446
// a helper function can return the original element
// which wouldn't have been set to relative in _create
if ( helperIsFunction && helper[ 0 ] === this.element[ 0 ] ) {
this._setPositionRelative();
if ( helper[ 0 ] !== this.element[ 0 ] &&
!( /(fixed|absolute)/ ).test( helper.css( "position" ) ) ) {
helper.css( "position", "absolute" );
_setPositionRelative: function() {
if ( !( /^(?:r|a|f)/ ).test( this.element.css( "position" ) ) ) {
this.element[ 0 ].style.position = "relative";
_adjustOffsetFromHelper: function( obj ) {
if ( typeof obj === "string" ) {
if ( Array.isArray( obj ) ) {
obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 };
this.offset.click.left = obj.left + this.margins.left;
this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
this.offset.click.top = obj.top + this.margins.top;
this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
_isRootNode: function( element ) {
return ( /(html|body)/i ).test( element.tagName ) || element === this.document[ 0 ];
_getParentOffset: function() {
//Get the offsetParent and cache its position
var po = this.offsetParent.offset(),
document = this.document[ 0 ];
// This is a special case where we need to modify a offset calculated on start, since the
// 1. The position of the helper is absolute, so it's position is calculated based on the
// next positioned parent
// 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't
// the document, which means that the scroll is included in the initial calculation of the
// offset of the parent, and never recalculated upon drag
if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== document &&
$.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) {
po.left += this.scrollParent.scrollLeft();
po.top += this.scrollParent.scrollTop();
if ( this._isRootNode( this.offsetParent[ 0 ] ) ) {
po = { top: 0, left: 0 };
top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ),
left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 )
_getRelativeOffset: function() {
if ( this.cssPosition !== "relative" ) {
return { top: 0, left: 0 };
var p = this.element.position(),
scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) +
( !scrollIsRootNode ? this.scrollParent.scrollTop() : 0 ),
left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) +
( !scrollIsRootNode ? this.scrollParent.scrollLeft() : 0 )
_cacheMargins: function() {
left: ( parseInt( this.element.css( "marginLeft" ), 10 ) || 0 ),
top: ( parseInt( this.element.css( "marginTop" ), 10 ) || 0 ),
right: ( parseInt( this.element.css( "marginRight" ), 10 ) || 0 ),
bottom: ( parseInt( this.element.css( "marginBottom" ), 10 ) || 0 )
_cacheHelperProportions: function() {
this.helperProportions = {
width: this.helper.outerWidth(),
height: this.helper.outerHeight()
_setContainment: function() {