resizable.js 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275
  1. /*!
  2. * jQuery UI Resizable 1.14.1
  3. * https://jqueryui.com
  4. *
  5. * Copyright OpenJS Foundation and other contributors
  6. * Released under the MIT license.
  7. * https://jquery.org/license
  8. */
  9. //>>label: Resizable
  10. //>>group: Interactions
  11. //>>description: Enables resize functionality for any element.
  12. //>>docs: https://api.jqueryui.com/resizable/
  13. //>>demos: https://jqueryui.com/resizable/
  14. //>>css.structure: ../../themes/base/core.css
  15. //>>css.structure: ../../themes/base/resizable.css
  16. //>>css.theme: ../../themes/base/theme.css
  17. ( function( factory ) {
  18. "use strict";
  19. if ( typeof define === "function" && define.amd ) {
  20. // AMD. Register as an anonymous module.
  21. define( [
  22. "jquery",
  23. "./mouse",
  24. "../disable-selection",
  25. "../plugin",
  26. "../version",
  27. "../widget"
  28. ], factory );
  29. } else {
  30. // Browser globals
  31. factory( jQuery );
  32. }
  33. } )( function( $ ) {
  34. "use strict";
  35. $.widget( "ui.resizable", $.ui.mouse, {
  36. version: "1.14.1",
  37. widgetEventPrefix: "resize",
  38. options: {
  39. alsoResize: false,
  40. animate: false,
  41. animateDuration: "slow",
  42. animateEasing: "swing",
  43. aspectRatio: false,
  44. autoHide: false,
  45. classes: {
  46. "ui-resizable-se": "ui-icon ui-icon-gripsmall-diagonal-se"
  47. },
  48. containment: false,
  49. ghost: false,
  50. grid: false,
  51. handles: "e,s,se",
  52. helper: false,
  53. maxHeight: null,
  54. maxWidth: null,
  55. minHeight: 10,
  56. minWidth: 10,
  57. // See #7960
  58. zIndex: 90,
  59. // Callbacks
  60. resize: null,
  61. start: null,
  62. stop: null
  63. },
  64. _num: function( value ) {
  65. return parseFloat( value ) || 0;
  66. },
  67. _isNumber: function( value ) {
  68. return !isNaN( parseFloat( value ) );
  69. },
  70. _hasScroll: function( el, a ) {
  71. var scroll,
  72. has = false,
  73. overflow = $( el ).css( "overflow" );
  74. if ( overflow === "hidden" ) {
  75. return false;
  76. }
  77. if ( overflow === "scroll" ) {
  78. return true;
  79. }
  80. scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop";
  81. if ( el[ scroll ] > 0 ) {
  82. return true;
  83. }
  84. // TODO: determine which cases actually cause this to happen
  85. // if the element doesn't have the scroll set, see if it's possible to
  86. // set the scroll
  87. try {
  88. el[ scroll ] = 1;
  89. has = ( el[ scroll ] > 0 );
  90. el[ scroll ] = 0;
  91. } catch ( e ) {
  92. // `el` might be a string, then setting `scroll` will throw
  93. // an error in strict mode; ignore it.
  94. }
  95. return has;
  96. },
  97. _create: function() {
  98. var margins,
  99. o = this.options,
  100. that = this;
  101. this._addClass( "ui-resizable" );
  102. $.extend( this, {
  103. _aspectRatio: !!( o.aspectRatio ),
  104. aspectRatio: o.aspectRatio,
  105. originalElement: this.element,
  106. _proportionallyResizeElements: [],
  107. _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null
  108. } );
  109. // Wrap the element if it cannot hold child nodes
  110. if ( this.element[ 0 ].nodeName.match( /^(canvas|textarea|input|select|button|img)$/i ) ) {
  111. this.element.wrap(
  112. $( "<div class='ui-wrapper'></div>" ).css( {
  113. overflow: "hidden",
  114. position: this.element.css( "position" ),
  115. width: this.element.outerWidth(),
  116. height: this.element.outerHeight(),
  117. top: this.element.css( "top" ),
  118. left: this.element.css( "left" )
  119. } )
  120. );
  121. this.element = this.element.parent().data(
  122. "ui-resizable", this.element.resizable( "instance" )
  123. );
  124. this.elementIsWrapper = true;
  125. margins = {
  126. marginTop: this.originalElement.css( "marginTop" ),
  127. marginRight: this.originalElement.css( "marginRight" ),
  128. marginBottom: this.originalElement.css( "marginBottom" ),
  129. marginLeft: this.originalElement.css( "marginLeft" )
  130. };
  131. this.element.css( margins );
  132. // Support: Safari
  133. // Prevent Safari textarea resize
  134. this.originalResizeStyle = this.originalElement.css( "resize" );
  135. this.originalElement.css( "resize", "none" );
  136. this._proportionallyResizeElements.push( this.originalElement.css( {
  137. position: "static",
  138. zoom: 1,
  139. display: "block"
  140. } ) );
  141. this._proportionallyResize();
  142. }
  143. this._setupHandles();
  144. if ( o.autoHide ) {
  145. $( this.element )
  146. .on( "mouseenter", function() {
  147. if ( o.disabled ) {
  148. return;
  149. }
  150. that._removeClass( "ui-resizable-autohide" );
  151. that._handles.show();
  152. } )
  153. .on( "mouseleave", function() {
  154. if ( o.disabled ) {
  155. return;
  156. }
  157. if ( !that.resizing ) {
  158. that._addClass( "ui-resizable-autohide" );
  159. that._handles.hide();
  160. }
  161. } );
  162. }
  163. this._mouseInit();
  164. },
  165. _destroy: function() {
  166. this._mouseDestroy();
  167. this._addedHandles.remove();
  168. var wrapper,
  169. _destroy = function( exp ) {
  170. $( exp )
  171. .removeData( "resizable" )
  172. .removeData( "ui-resizable" )
  173. .off( ".resizable" );
  174. };
  175. // TODO: Unwrap at same DOM position
  176. if ( this.elementIsWrapper ) {
  177. _destroy( this.element );
  178. wrapper = this.element;
  179. this.originalElement.css( {
  180. position: wrapper.css( "position" ),
  181. width: wrapper.outerWidth(),
  182. height: wrapper.outerHeight(),
  183. top: wrapper.css( "top" ),
  184. left: wrapper.css( "left" )
  185. } ).insertAfter( wrapper );
  186. wrapper.remove();
  187. }
  188. this.originalElement.css( "resize", this.originalResizeStyle );
  189. _destroy( this.originalElement );
  190. return this;
  191. },
  192. _setOption: function( key, value ) {
  193. this._super( key, value );
  194. switch ( key ) {
  195. case "handles":
  196. this._removeHandles();
  197. this._setupHandles();
  198. break;
  199. case "aspectRatio":
  200. this._aspectRatio = !!value;
  201. break;
  202. default:
  203. break;
  204. }
  205. },
  206. _setupHandles: function() {
  207. var o = this.options, handle, i, n, hname, axis, that = this;
  208. this.handles = o.handles ||
  209. ( !$( ".ui-resizable-handle", this.element ).length ?
  210. "e,s,se" : {
  211. n: ".ui-resizable-n",
  212. e: ".ui-resizable-e",
  213. s: ".ui-resizable-s",
  214. w: ".ui-resizable-w",
  215. se: ".ui-resizable-se",
  216. sw: ".ui-resizable-sw",
  217. ne: ".ui-resizable-ne",
  218. nw: ".ui-resizable-nw"
  219. } );
  220. this._handles = $();
  221. this._addedHandles = $();
  222. if ( this.handles.constructor === String ) {
  223. if ( this.handles === "all" ) {
  224. this.handles = "n,e,s,w,se,sw,ne,nw";
  225. }
  226. n = this.handles.split( "," );
  227. this.handles = {};
  228. for ( i = 0; i < n.length; i++ ) {
  229. handle = String.prototype.trim.call( n[ i ] );
  230. hname = "ui-resizable-" + handle;
  231. axis = $( "<div>" );
  232. this._addClass( axis, "ui-resizable-handle " + hname );
  233. axis.css( { zIndex: o.zIndex } );
  234. this.handles[ handle ] = ".ui-resizable-" + handle;
  235. if ( !this.element.children( this.handles[ handle ] ).length ) {
  236. this.element.append( axis );
  237. this._addedHandles = this._addedHandles.add( axis );
  238. }
  239. }
  240. }
  241. this._renderAxis = function( target ) {
  242. var i, axis, padPos, padWrapper;
  243. target = target || this.element;
  244. for ( i in this.handles ) {
  245. if ( this.handles[ i ].constructor === String ) {
  246. this.handles[ i ] = this.element.children( this.handles[ i ] ).first().show();
  247. } else if ( this.handles[ i ].jquery || this.handles[ i ].nodeType ) {
  248. this.handles[ i ] = $( this.handles[ i ] );
  249. this._on( this.handles[ i ], { "mousedown": that._mouseDown } );
  250. }
  251. if ( this.elementIsWrapper &&
  252. this.originalElement[ 0 ]
  253. .nodeName
  254. .match( /^(textarea|input|select|button)$/i ) ) {
  255. axis = $( this.handles[ i ], this.element );
  256. padWrapper = /sw|ne|nw|se|n|s/.test( i ) ?
  257. axis.outerHeight() :
  258. axis.outerWidth();
  259. padPos = [ "padding",
  260. /ne|nw|n/.test( i ) ? "Top" :
  261. /se|sw|s/.test( i ) ? "Bottom" :
  262. /^e$/.test( i ) ? "Right" : "Left" ].join( "" );
  263. target.css( padPos, padWrapper );
  264. this._proportionallyResize();
  265. }
  266. this._handles = this._handles.add( this.handles[ i ] );
  267. }
  268. };
  269. // TODO: make renderAxis a prototype function
  270. this._renderAxis( this.element );
  271. this._handles = this._handles.add( this.element.find( ".ui-resizable-handle" ) );
  272. this._handles.disableSelection();
  273. this._handles.on( "mouseover", function() {
  274. if ( !that.resizing ) {
  275. if ( this.className ) {
  276. axis = this.className.match( /ui-resizable-(se|sw|ne|nw|n|e|s|w)/i );
  277. }
  278. that.axis = axis && axis[ 1 ] ? axis[ 1 ] : "se";
  279. }
  280. } );
  281. if ( o.autoHide ) {
  282. this._handles.hide();
  283. this._addClass( "ui-resizable-autohide" );
  284. }
  285. },
  286. _removeHandles: function() {
  287. this._addedHandles.remove();
  288. },
  289. _mouseCapture: function( event ) {
  290. var i, handle,
  291. capture = false;
  292. for ( i in this.handles ) {
  293. handle = $( this.handles[ i ] )[ 0 ];
  294. if ( handle === event.target || $.contains( handle, event.target ) ) {
  295. capture = true;
  296. }
  297. }
  298. return !this.options.disabled && capture;
  299. },
  300. _mouseStart: function( event ) {
  301. var curleft, curtop, cursor, calculatedSize,
  302. o = this.options,
  303. el = this.element;
  304. this.resizing = true;
  305. this._renderProxy();
  306. curleft = this._num( this.helper.css( "left" ) );
  307. curtop = this._num( this.helper.css( "top" ) );
  308. if ( o.containment ) {
  309. curleft += $( o.containment ).scrollLeft() || 0;
  310. curtop += $( o.containment ).scrollTop() || 0;
  311. }
  312. this.offset = this.helper.offset();
  313. this.position = { left: curleft, top: curtop };
  314. if ( !this._helper ) {
  315. calculatedSize = this._calculateAdjustedElementDimensions( el );
  316. }
  317. this.size = this._helper ? {
  318. width: this.helper.width(),
  319. height: this.helper.height()
  320. } : {
  321. width: calculatedSize.width,
  322. height: calculatedSize.height
  323. };
  324. this.originalSize = this._helper ? {
  325. width: el.outerWidth(),
  326. height: el.outerHeight()
  327. } : {
  328. width: calculatedSize.width,
  329. height: calculatedSize.height
  330. };
  331. this.sizeDiff = {
  332. width: el.outerWidth() - el.width(),
  333. height: el.outerHeight() - el.height()
  334. };
  335. this.originalPosition = { left: curleft, top: curtop };
  336. this.originalMousePosition = { left: event.pageX, top: event.pageY };
  337. this.aspectRatio = ( typeof o.aspectRatio === "number" ) ?
  338. o.aspectRatio :
  339. ( ( this.originalSize.width / this.originalSize.height ) || 1 );
  340. cursor = $( ".ui-resizable-" + this.axis ).css( "cursor" );
  341. $( "body" ).css( "cursor", cursor === "auto" ? this.axis + "-resize" : cursor );
  342. this._addClass( "ui-resizable-resizing" );
  343. this._propagate( "start", event );
  344. return true;
  345. },
  346. _mouseDrag: function( event ) {
  347. var data, props,
  348. smp = this.originalMousePosition,
  349. a = this.axis,
  350. dx = ( event.pageX - smp.left ) || 0,
  351. dy = ( event.pageY - smp.top ) || 0,
  352. trigger = this._change[ a ];
  353. this._updatePrevProperties();
  354. if ( !trigger ) {
  355. return false;
  356. }
  357. data = trigger.apply( this, [ event, dx, dy ] );
  358. this._updateVirtualBoundaries( event.shiftKey );
  359. if ( this._aspectRatio || event.shiftKey ) {
  360. data = this._updateRatio( data, event );
  361. }
  362. data = this._respectSize( data, event );
  363. this._updateCache( data );
  364. this._propagate( "resize", event );
  365. props = this._applyChanges();
  366. if ( !this._helper && this._proportionallyResizeElements.length ) {
  367. this._proportionallyResize();
  368. }
  369. if ( !$.isEmptyObject( props ) ) {
  370. this._updatePrevProperties();
  371. this._trigger( "resize", event, this.ui() );
  372. this._applyChanges();
  373. }
  374. return false;
  375. },
  376. _mouseStop: function( event ) {
  377. this.resizing = false;
  378. var pr, ista, soffseth, soffsetw, s, left, top,
  379. o = this.options, that = this;
  380. if ( this._helper ) {
  381. pr = this._proportionallyResizeElements;
  382. ista = pr.length && ( /textarea/i ).test( pr[ 0 ].nodeName );
  383. soffseth = ista && this._hasScroll( pr[ 0 ], "left" ) ? 0 : that.sizeDiff.height;
  384. soffsetw = ista ? 0 : that.sizeDiff.width;
  385. s = {
  386. width: ( that.helper.width() - soffsetw ),
  387. height: ( that.helper.height() - soffseth )
  388. };
  389. left = ( parseFloat( that.element.css( "left" ) ) +
  390. ( that.position.left - that.originalPosition.left ) ) || null;
  391. top = ( parseFloat( that.element.css( "top" ) ) +
  392. ( that.position.top - that.originalPosition.top ) ) || null;
  393. if ( !o.animate ) {
  394. this.element.css( $.extend( s, { top: top, left: left } ) );
  395. }
  396. that.helper.height( that.size.height );
  397. that.helper.width( that.size.width );
  398. if ( this._helper && !o.animate ) {
  399. this._proportionallyResize();
  400. }
  401. }
  402. $( "body" ).css( "cursor", "auto" );
  403. this._removeClass( "ui-resizable-resizing" );
  404. this._propagate( "stop", event );
  405. if ( this._helper ) {
  406. this.helper.remove();
  407. }
  408. return false;
  409. },
  410. _updatePrevProperties: function() {
  411. this.prevPosition = {
  412. top: this.position.top,
  413. left: this.position.left
  414. };
  415. this.prevSize = {
  416. width: this.size.width,
  417. height: this.size.height
  418. };
  419. },
  420. _applyChanges: function() {
  421. var props = {};
  422. if ( this.position.top !== this.prevPosition.top ) {
  423. props.top = this.position.top + "px";
  424. }
  425. if ( this.position.left !== this.prevPosition.left ) {
  426. props.left = this.position.left + "px";
  427. }
  428. this.helper.css( props );
  429. if ( this.size.width !== this.prevSize.width ) {
  430. props.width = this.size.width + "px";
  431. this.helper.width( props.width );
  432. }
  433. if ( this.size.height !== this.prevSize.height ) {
  434. props.height = this.size.height + "px";
  435. this.helper.height( props.height );
  436. }
  437. return props;
  438. },
  439. _updateVirtualBoundaries: function( forceAspectRatio ) {
  440. var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b,
  441. o = this.options;
  442. b = {
  443. minWidth: this._isNumber( o.minWidth ) ? o.minWidth : 0,
  444. maxWidth: this._isNumber( o.maxWidth ) ? o.maxWidth : Infinity,
  445. minHeight: this._isNumber( o.minHeight ) ? o.minHeight : 0,
  446. maxHeight: this._isNumber( o.maxHeight ) ? o.maxHeight : Infinity
  447. };
  448. if ( this._aspectRatio || forceAspectRatio ) {
  449. pMinWidth = b.minHeight * this.aspectRatio;
  450. pMinHeight = b.minWidth / this.aspectRatio;
  451. pMaxWidth = b.maxHeight * this.aspectRatio;
  452. pMaxHeight = b.maxWidth / this.aspectRatio;
  453. if ( pMinWidth > b.minWidth ) {
  454. b.minWidth = pMinWidth;
  455. }
  456. if ( pMinHeight > b.minHeight ) {
  457. b.minHeight = pMinHeight;
  458. }
  459. if ( pMaxWidth < b.maxWidth ) {
  460. b.maxWidth = pMaxWidth;
  461. }
  462. if ( pMaxHeight < b.maxHeight ) {
  463. b.maxHeight = pMaxHeight;
  464. }
  465. }
  466. this._vBoundaries = b;
  467. },
  468. _updateCache: function( data ) {
  469. this.offset = this.helper.offset();
  470. if ( this._isNumber( data.left ) ) {
  471. this.position.left = data.left;
  472. }
  473. if ( this._isNumber( data.top ) ) {
  474. this.position.top = data.top;
  475. }
  476. if ( this._isNumber( data.height ) ) {
  477. this.size.height = data.height;
  478. }
  479. if ( this._isNumber( data.width ) ) {
  480. this.size.width = data.width;
  481. }
  482. },
  483. _updateRatio: function( data ) {
  484. var cpos = this.position,
  485. csize = this.size,
  486. a = this.axis;
  487. if ( this._isNumber( data.height ) ) {
  488. data.width = ( data.height * this.aspectRatio );
  489. } else if ( this._isNumber( data.width ) ) {
  490. data.height = ( data.width / this.aspectRatio );
  491. }
  492. if ( a === "sw" ) {
  493. data.left = cpos.left + ( csize.width - data.width );
  494. data.top = null;
  495. }
  496. if ( a === "nw" ) {
  497. data.top = cpos.top + ( csize.height - data.height );
  498. data.left = cpos.left + ( csize.width - data.width );
  499. }
  500. return data;
  501. },
  502. _respectSize: function( data ) {
  503. var o = this._vBoundaries,
  504. a = this.axis,
  505. ismaxw = this._isNumber( data.width ) && o.maxWidth && ( o.maxWidth < data.width ),
  506. ismaxh = this._isNumber( data.height ) && o.maxHeight && ( o.maxHeight < data.height ),
  507. isminw = this._isNumber( data.width ) && o.minWidth && ( o.minWidth > data.width ),
  508. isminh = this._isNumber( data.height ) && o.minHeight && ( o.minHeight > data.height ),
  509. dw = this.originalPosition.left + this.originalSize.width,
  510. dh = this.originalPosition.top + this.originalSize.height,
  511. cw = /sw|nw|w/.test( a ), ch = /nw|ne|n/.test( a );
  512. if ( isminw ) {
  513. data.width = o.minWidth;
  514. }
  515. if ( isminh ) {
  516. data.height = o.minHeight;
  517. }
  518. if ( ismaxw ) {
  519. data.width = o.maxWidth;
  520. }
  521. if ( ismaxh ) {
  522. data.height = o.maxHeight;
  523. }
  524. if ( isminw && cw ) {
  525. data.left = dw - o.minWidth;
  526. }
  527. if ( ismaxw && cw ) {
  528. data.left = dw - o.maxWidth;
  529. }
  530. if ( isminh && ch ) {
  531. data.top = dh - o.minHeight;
  532. }
  533. if ( ismaxh && ch ) {
  534. data.top = dh - o.maxHeight;
  535. }
  536. // Fixing jump error on top/left - bug #2330
  537. if ( !data.width && !data.height && !data.left && data.top ) {
  538. data.top = null;
  539. } else if ( !data.width && !data.height && !data.top && data.left ) {
  540. data.left = null;
  541. }
  542. return data;
  543. },
  544. _getPaddingPlusBorderDimensions: function( element ) {
  545. var i = 0,
  546. widths = [],
  547. borders = [
  548. element.css( "borderTopWidth" ),
  549. element.css( "borderRightWidth" ),
  550. element.css( "borderBottomWidth" ),
  551. element.css( "borderLeftWidth" )
  552. ],
  553. paddings = [
  554. element.css( "paddingTop" ),
  555. element.css( "paddingRight" ),
  556. element.css( "paddingBottom" ),
  557. element.css( "paddingLeft" )
  558. ];
  559. for ( ; i < 4; i++ ) {
  560. widths[ i ] = ( parseFloat( borders[ i ] ) || 0 );
  561. widths[ i ] += ( parseFloat( paddings[ i ] ) || 0 );
  562. }
  563. return {
  564. height: widths[ 0 ] + widths[ 2 ],
  565. width: widths[ 1 ] + widths[ 3 ]
  566. };
  567. },
  568. _calculateAdjustedElementDimensions: function( element ) {
  569. var elWidth, elHeight, paddingBorder,
  570. ce = element.get( 0 );
  571. if ( element.css( "box-sizing" ) !== "content-box" ||
  572. ( !this._hasScroll( ce ) && !this._hasScroll( ce, "left" ) ) ) {
  573. return {
  574. height: parseFloat( element.css( "height" ) ),
  575. width: parseFloat( element.css( "width" ) )
  576. };
  577. }
  578. // Check if CSS inline styles are set and use those (usually from previous resizes)
  579. elWidth = parseFloat( ce.style.width );
  580. elHeight = parseFloat( ce.style.height );
  581. paddingBorder = this._getPaddingPlusBorderDimensions( element );
  582. elWidth = isNaN( elWidth ) ?
  583. this._getElementTheoreticalSize( element, paddingBorder, "width" ) :
  584. elWidth;
  585. elHeight = isNaN( elHeight ) ?
  586. this._getElementTheoreticalSize( element, paddingBorder, "height" ) :
  587. elHeight;
  588. return {
  589. height: elHeight,
  590. width: elWidth
  591. };
  592. },
  593. _getElementTheoreticalSize: function( element, extraSize, dimension ) {
  594. // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border
  595. var size = Math.max( 0, Math.ceil(
  596. element.get( 0 )[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -
  597. extraSize[ dimension ] -
  598. 0.5
  599. // If offsetWidth/offsetHeight is unknown, then we can't determine theoretical size.
  600. // Use an explicit zero to avoid NaN.
  601. // See https://github.com/jquery/jquery/issues/3964
  602. ) ) || 0;
  603. return size;
  604. },
  605. _proportionallyResize: function() {
  606. if ( !this._proportionallyResizeElements.length ) {
  607. return;
  608. }
  609. var prel,
  610. i = 0,
  611. element = this.helper || this.element;
  612. for ( ; i < this._proportionallyResizeElements.length; i++ ) {
  613. prel = this._proportionallyResizeElements[ i ];
  614. // TODO: Seems like a bug to cache this.outerDimensions
  615. // considering that we are in a loop.
  616. if ( !this.outerDimensions ) {
  617. this.outerDimensions = this._getPaddingPlusBorderDimensions( prel );
  618. }
  619. prel.css( {
  620. height: ( element.height() - this.outerDimensions.height ) || 0,
  621. width: ( element.width() - this.outerDimensions.width ) || 0
  622. } );
  623. }
  624. },
  625. _renderProxy: function() {
  626. var el = this.element, o = this.options;
  627. this.elementOffset = el.offset();
  628. if ( this._helper ) {
  629. this.helper = this.helper || $( "<div></div>" ).css( { overflow: "hidden" } );
  630. this._addClass( this.helper, this._helper );
  631. this.helper.css( {
  632. width: this.element.outerWidth(),
  633. height: this.element.outerHeight(),
  634. position: "absolute",
  635. left: this.elementOffset.left + "px",
  636. top: this.elementOffset.top + "px",
  637. zIndex: ++o.zIndex //TODO: Don't modify option
  638. } );
  639. this.helper
  640. .appendTo( "body" )
  641. .disableSelection();
  642. } else {
  643. this.helper = this.element;
  644. }
  645. },
  646. _change: {
  647. e: function( event, dx ) {
  648. return { width: this.originalSize.width + dx };
  649. },
  650. w: function( event, dx ) {
  651. var cs = this.originalSize, sp = this.originalPosition;
  652. return { left: sp.left + dx, width: cs.width - dx };
  653. },
  654. n: function( event, dx, dy ) {
  655. var cs = this.originalSize, sp = this.originalPosition;
  656. return { top: sp.top + dy, height: cs.height - dy };
  657. },
  658. s: function( event, dx, dy ) {
  659. return { height: this.originalSize.height + dy };
  660. },
  661. se: function( event, dx, dy ) {
  662. return $.extend( this._change.s.apply( this, arguments ),
  663. this._change.e.apply( this, [ event, dx, dy ] ) );
  664. },
  665. sw: function( event, dx, dy ) {
  666. return $.extend( this._change.s.apply( this, arguments ),
  667. this._change.w.apply( this, [ event, dx, dy ] ) );
  668. },
  669. ne: function( event, dx, dy ) {
  670. return $.extend( this._change.n.apply( this, arguments ),
  671. this._change.e.apply( this, [ event, dx, dy ] ) );
  672. },
  673. nw: function( event, dx, dy ) {
  674. return $.extend( this._change.n.apply( this, arguments ),
  675. this._change.w.apply( this, [ event, dx, dy ] ) );
  676. }
  677. },
  678. _propagate: function( n, event ) {
  679. $.ui.plugin.call( this, n, [ event, this.ui() ] );
  680. if ( n !== "resize" ) {
  681. this._trigger( n, event, this.ui() );
  682. }
  683. },
  684. plugins: {},
  685. ui: function() {
  686. return {
  687. originalElement: this.originalElement,
  688. element: this.element,
  689. helper: this.helper,
  690. position: this.position,
  691. size: this.size,
  692. originalSize: this.originalSize,
  693. originalPosition: this.originalPosition
  694. };
  695. }
  696. } );
  697. /*
  698. * Resizable Extensions
  699. */
  700. $.ui.plugin.add( "resizable", "animate", {
  701. stop: function( event ) {
  702. var that = $( this ).resizable( "instance" ),
  703. o = that.options,
  704. pr = that._proportionallyResizeElements,
  705. ista = pr.length && ( /textarea/i ).test( pr[ 0 ].nodeName ),
  706. soffseth = ista && that._hasScroll( pr[ 0 ], "left" ) ? 0 : that.sizeDiff.height,
  707. soffsetw = ista ? 0 : that.sizeDiff.width,
  708. style = {
  709. width: ( that.size.width - soffsetw ),
  710. height: ( that.size.height - soffseth )
  711. },
  712. left = ( parseFloat( that.element.css( "left" ) ) +
  713. ( that.position.left - that.originalPosition.left ) ) || null,
  714. top = ( parseFloat( that.element.css( "top" ) ) +
  715. ( that.position.top - that.originalPosition.top ) ) || null;
  716. that.element.animate(
  717. $.extend( style, top && left ? { top: top, left: left } : {} ), {
  718. duration: o.animateDuration,
  719. easing: o.animateEasing,
  720. step: function() {
  721. var data = {
  722. width: parseFloat( that.element.css( "width" ) ),
  723. height: parseFloat( that.element.css( "height" ) ),
  724. top: parseFloat( that.element.css( "top" ) ),
  725. left: parseFloat( that.element.css( "left" ) )
  726. };
  727. if ( pr && pr.length ) {
  728. $( pr[ 0 ] ).css( { width: data.width, height: data.height } );
  729. }
  730. // Propagating resize, and updating values for each animation step
  731. that._updateCache( data );
  732. that._propagate( "resize", event );
  733. }
  734. }
  735. );
  736. }
  737. } );
  738. $.ui.plugin.add( "resizable", "containment", {
  739. start: function() {
  740. var element, p, co, ch, cw, width, height,
  741. that = $( this ).resizable( "instance" ),
  742. o = that.options,
  743. el = that.element,
  744. oc = o.containment,
  745. ce = ( oc instanceof $ ) ?
  746. oc.get( 0 ) :
  747. ( /parent/.test( oc ) ) ? el.parent().get( 0 ) : oc;
  748. if ( !ce ) {
  749. return;
  750. }
  751. that.containerElement = $( ce );
  752. if ( /document/.test( oc ) || oc === document ) {
  753. that.containerOffset = {
  754. left: 0,
  755. top: 0
  756. };
  757. that.containerPosition = {
  758. left: 0,
  759. top: 0
  760. };
  761. that.parentData = {
  762. element: $( document ),
  763. left: 0,
  764. top: 0,
  765. width: $( document ).width(),
  766. height: $( document ).height() || document.body.parentNode.scrollHeight
  767. };
  768. } else {
  769. element = $( ce );
  770. p = [];
  771. $( [ "Top", "Right", "Left", "Bottom" ] ).each( function( i, name ) {
  772. p[ i ] = that._num( element.css( "padding" + name ) );
  773. } );
  774. that.containerOffset = element.offset();
  775. that.containerPosition = element.position();
  776. that.containerSize = {
  777. height: ( element.innerHeight() - p[ 3 ] ),
  778. width: ( element.innerWidth() - p[ 1 ] )
  779. };
  780. co = that.containerOffset;
  781. ch = that.containerSize.height;
  782. cw = that.containerSize.width;
  783. width = ( that._hasScroll( ce, "left" ) ? ce.scrollWidth : cw );
  784. height = ( that._hasScroll( ce ) ? ce.scrollHeight : ch );
  785. that.parentData = {
  786. element: ce,
  787. left: co.left,
  788. top: co.top,
  789. width: width,
  790. height: height
  791. };
  792. }
  793. },
  794. resize: function( event ) {
  795. var woset, hoset, isParent, isOffsetRelative,
  796. that = $( this ).resizable( "instance" ),
  797. o = that.options,
  798. co = that.containerOffset,
  799. cp = that.position,
  800. pRatio = that._aspectRatio || event.shiftKey,
  801. cop = {
  802. top: 0,
  803. left: 0
  804. },
  805. ce = that.containerElement,
  806. continueResize = true;
  807. if ( ce[ 0 ] !== document && ( /static/ ).test( ce.css( "position" ) ) ) {
  808. cop = co;
  809. }
  810. if ( cp.left < ( that._helper ? co.left : 0 ) ) {
  811. that.size.width = that.size.width +
  812. ( that._helper ?
  813. ( that.position.left - co.left ) :
  814. ( that.position.left - cop.left ) );
  815. if ( pRatio ) {
  816. that.size.height = that.size.width / that.aspectRatio;
  817. continueResize = false;
  818. }
  819. that.position.left = o.helper ? co.left : 0;
  820. }
  821. if ( cp.top < ( that._helper ? co.top : 0 ) ) {
  822. that.size.height = that.size.height +
  823. ( that._helper ?
  824. ( that.position.top - co.top ) :
  825. that.position.top );
  826. if ( pRatio ) {
  827. that.size.width = that.size.height * that.aspectRatio;
  828. continueResize = false;
  829. }
  830. that.position.top = that._helper ? co.top : 0;
  831. }
  832. isParent = that.containerElement.get( 0 ) === that.element.parent().get( 0 );
  833. isOffsetRelative = /relative|absolute/.test( that.containerElement.css( "position" ) );
  834. if ( isParent && isOffsetRelative ) {
  835. that.offset.left = that.parentData.left + that.position.left;
  836. that.offset.top = that.parentData.top + that.position.top;
  837. } else {
  838. that.offset.left = that.element.offset().left;
  839. that.offset.top = that.element.offset().top;
  840. }
  841. woset = Math.abs( that.sizeDiff.width +
  842. ( that._helper ?
  843. that.offset.left - cop.left :
  844. ( that.offset.left - co.left ) ) );
  845. hoset = Math.abs( that.sizeDiff.height +
  846. ( that._helper ?
  847. that.offset.top - cop.top :
  848. ( that.offset.top - co.top ) ) );
  849. if ( woset + that.size.width >= that.parentData.width ) {
  850. that.size.width = that.parentData.width - woset;
  851. if ( pRatio ) {
  852. that.size.height = that.size.width / that.aspectRatio;
  853. continueResize = false;
  854. }
  855. }
  856. if ( hoset + that.size.height >= that.parentData.height ) {
  857. that.size.height = that.parentData.height - hoset;
  858. if ( pRatio ) {
  859. that.size.width = that.size.height * that.aspectRatio;
  860. continueResize = false;
  861. }
  862. }
  863. if ( !continueResize ) {
  864. that.position.left = that.prevPosition.left;
  865. that.position.top = that.prevPosition.top;
  866. that.size.width = that.prevSize.width;
  867. that.size.height = that.prevSize.height;
  868. }
  869. },
  870. stop: function() {
  871. var that = $( this ).resizable( "instance" ),
  872. o = that.options,
  873. co = that.containerOffset,
  874. cop = that.containerPosition,
  875. ce = that.containerElement,
  876. helper = $( that.helper ),
  877. ho = helper.offset(),
  878. w = helper.outerWidth() - that.sizeDiff.width,
  879. h = helper.outerHeight() - that.sizeDiff.height;
  880. if ( that._helper && !o.animate && ( /relative/ ).test( ce.css( "position" ) ) ) {
  881. $( this ).css( {
  882. left: ho.left - cop.left - co.left,
  883. width: w,
  884. height: h
  885. } );
  886. }
  887. if ( that._helper && !o.animate && ( /static/ ).test( ce.css( "position" ) ) ) {
  888. $( this ).css( {
  889. left: ho.left - cop.left - co.left,
  890. width: w,
  891. height: h
  892. } );
  893. }
  894. }
  895. } );
  896. $.ui.plugin.add( "resizable", "alsoResize", {
  897. start: function() {
  898. var that = $( this ).resizable( "instance" ),
  899. o = that.options;
  900. $( o.alsoResize ).each( function() {
  901. var el = $( this ),
  902. elSize = that._calculateAdjustedElementDimensions( el );
  903. el.data( "ui-resizable-alsoresize", {
  904. width: elSize.width, height: elSize.height,
  905. left: parseFloat( el.css( "left" ) ), top: parseFloat( el.css( "top" ) )
  906. } );
  907. } );
  908. },
  909. resize: function( event, ui ) {
  910. var that = $( this ).resizable( "instance" ),
  911. o = that.options,
  912. os = that.originalSize,
  913. op = that.originalPosition,
  914. delta = {
  915. height: ( that.size.height - os.height ) || 0,
  916. width: ( that.size.width - os.width ) || 0,
  917. top: ( that.position.top - op.top ) || 0,
  918. left: ( that.position.left - op.left ) || 0
  919. };
  920. $( o.alsoResize ).each( function() {
  921. var el = $( this ), start = $( this ).data( "ui-resizable-alsoresize" ), style = {},
  922. css = el.parents( ui.originalElement[ 0 ] ).length ?
  923. [ "width", "height" ] :
  924. [ "width", "height", "top", "left" ];
  925. $.each( css, function( i, prop ) {
  926. var sum = ( start[ prop ] || 0 ) + ( delta[ prop ] || 0 );
  927. if ( sum && sum >= 0 ) {
  928. style[ prop ] = sum || null;
  929. }
  930. } );
  931. el.css( style );
  932. } );
  933. },
  934. stop: function() {
  935. $( this ).removeData( "ui-resizable-alsoresize" );
  936. }
  937. } );
  938. $.ui.plugin.add( "resizable", "ghost", {
  939. start: function() {
  940. var that = $( this ).resizable( "instance" ), cs = that.size;
  941. that.ghost = that.originalElement.clone();
  942. that.ghost.css( {
  943. opacity: 0.25,
  944. display: "block",
  945. position: "relative",
  946. height: cs.height,
  947. width: cs.width,
  948. margin: 0,
  949. left: 0,
  950. top: 0
  951. } );
  952. that._addClass( that.ghost, "ui-resizable-ghost" );
  953. // DEPRECATED
  954. // TODO: remove after 1.12
  955. if ( $.uiBackCompat === true && typeof that.options.ghost === "string" ) {
  956. // Ghost option
  957. that.ghost.addClass( this.options.ghost );
  958. }
  959. that.ghost.appendTo( that.helper );
  960. },
  961. resize: function() {
  962. var that = $( this ).resizable( "instance" );
  963. if ( that.ghost ) {
  964. that.ghost.css( {
  965. position: "relative",
  966. height: that.size.height,
  967. width: that.size.width
  968. } );
  969. }
  970. },
  971. stop: function() {
  972. var that = $( this ).resizable( "instance" );
  973. if ( that.ghost && that.helper ) {
  974. that.helper.get( 0 ).removeChild( that.ghost.get( 0 ) );
  975. }
  976. }
  977. } );
  978. $.ui.plugin.add( "resizable", "grid", {
  979. resize: function() {
  980. var outerDimensions,
  981. that = $( this ).resizable( "instance" ),
  982. o = that.options,
  983. cs = that.size,
  984. os = that.originalSize,
  985. op = that.originalPosition,
  986. a = that.axis,
  987. grid = typeof o.grid === "number" ? [ o.grid, o.grid ] : o.grid,
  988. gridX = ( grid[ 0 ] || 1 ),
  989. gridY = ( grid[ 1 ] || 1 ),
  990. ox = Math.round( ( cs.width - os.width ) / gridX ) * gridX,
  991. oy = Math.round( ( cs.height - os.height ) / gridY ) * gridY,
  992. newWidth = os.width + ox,
  993. newHeight = os.height + oy,
  994. isMaxWidth = o.maxWidth && ( o.maxWidth < newWidth ),
  995. isMaxHeight = o.maxHeight && ( o.maxHeight < newHeight ),
  996. isMinWidth = o.minWidth && ( o.minWidth > newWidth ),
  997. isMinHeight = o.minHeight && ( o.minHeight > newHeight );
  998. o.grid = grid;
  999. if ( isMinWidth ) {
  1000. newWidth += gridX;
  1001. }
  1002. if ( isMinHeight ) {
  1003. newHeight += gridY;
  1004. }
  1005. if ( isMaxWidth ) {
  1006. newWidth -= gridX;
  1007. }
  1008. if ( isMaxHeight ) {
  1009. newHeight -= gridY;
  1010. }
  1011. if ( /^(se|s|e)$/.test( a ) ) {
  1012. that.size.width = newWidth;
  1013. that.size.height = newHeight;
  1014. } else if ( /^(ne)$/.test( a ) ) {
  1015. that.size.width = newWidth;
  1016. that.size.height = newHeight;
  1017. that.position.top = op.top - oy;
  1018. } else if ( /^(sw)$/.test( a ) ) {
  1019. that.size.width = newWidth;
  1020. that.size.height = newHeight;
  1021. that.position.left = op.left - ox;
  1022. } else {
  1023. if ( newHeight - gridY <= 0 || newWidth - gridX <= 0 ) {
  1024. outerDimensions = that._getPaddingPlusBorderDimensions( this );
  1025. }
  1026. if ( newHeight - gridY > 0 ) {
  1027. that.size.height = newHeight;
  1028. that.position.top = op.top - oy;
  1029. } else {
  1030. newHeight = gridY - outerDimensions.height;
  1031. that.size.height = newHeight;
  1032. that.position.top = op.top + os.height - newHeight;
  1033. }
  1034. if ( newWidth - gridX > 0 ) {
  1035. that.size.width = newWidth;
  1036. that.position.left = op.left - ox;
  1037. } else {
  1038. newWidth = gridX - outerDimensions.width;
  1039. that.size.width = newWidth;
  1040. that.position.left = op.left + os.width - newWidth;
  1041. }
  1042. }
  1043. }
  1044. } );
  1045. return $.ui.resizable;
  1046. } );