2 * jQuery UI Resizable 1.8.16
4 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
5 * Dual licensed under the MIT or GPL Version 2 licenses.
6 * http://jquery.org/license
8 * http://docs.jquery.com/UI/Resizables
15 (function( $, undefined ) {
17 $.widget("ui.resizable", $.ui
.mouse
, {
18 widgetEventPrefix
: "resize",
22 animateDuration
: "slow",
23 animateEasing
: "swing",
39 var self
= this, o
= this.options
;
40 this.element
.addClass("ui-resizable");
43 _aspectRatio
: !!(o
.aspectRatio
),
44 aspectRatio
: o
.aspectRatio
,
45 originalElement
: this.element
,
46 _proportionallyResizeElements
: [],
47 _helper
: o
.helper
|| o
.ghost
|| o
.animate
? o
.helper
|| 'ui-resizable-helper' : null
50 //Wrap the element if it cannot hold child nodes
51 if(this.element
[0].nodeName
.match(/canvas|textarea|input|select|button|img/i)) {
53 //Opera fix for relative positioning
54 if (/relative/.test(this.element
.css('position')) && $.browser
.opera
)
55 this.element
.css({ position
: 'relative', top
: 'auto', left
: 'auto' });
57 //Create a wrapper element and set the wrapper to the new current internal element
59 $('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({
60 position
: this.element
.css('position'),
61 width
: this.element
.outerWidth(),
62 height
: this.element
.outerHeight(),
63 top
: this.element
.css('top'),
64 left
: this.element
.css('left')
68 //Overwrite the original this.element
69 this.element
= this.element
.parent().data(
70 "resizable", this.element
.data('resizable')
73 this.elementIsWrapper
= true;
75 //Move margins to the wrapper
76 this.element
.css({ marginLeft
: this.originalElement
.css("marginLeft"), marginTop
: this.originalElement
.css("marginTop"), marginRight
: this.originalElement
.css("marginRight"), marginBottom
: this.originalElement
.css("marginBottom") });
77 this.originalElement
.css({ marginLeft
: 0, marginTop
: 0, marginRight
: 0, marginBottom
: 0});
79 //Prevent Safari textarea resize
80 this.originalResizeStyle
= this.originalElement
.css('resize');
81 this.originalElement
.css('resize', 'none');
83 //Push the actual element to our proportionallyResize internal array
84 this._proportionallyResizeElements
.push(this.originalElement
.css({ position
: 'static', zoom
: 1, display
: 'block' }));
86 // avoid IE jump (hard set the margin)
87 this.originalElement
.css({ margin
: this.originalElement
.css('margin') });
89 // fix handlers offset
90 this._proportionallyResize();
94 this.handles
= o
.handles
|| (!$('.ui-resizable-handle', this.element
).length
? "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' });
95 if(this.handles
.constructor == String
) {
97 if(this.handles
== 'all') this.handles
= 'n,e,s,w,se,sw,ne,nw';
98 var n
= this.handles
.split(","); this.handles
= {};
100 for(var i
= 0; i
< n
.length
; i
++) {
102 var handle
= $.trim(n
[i
]), hname
= 'ui-resizable-'+handle
;
103 var axis
= $('<div class="ui-resizable-handle ' + hname
+ '"></div>');
105 // increase zIndex of sw, se, ne, nw axis
106 //TODO : this modifies original option
107 if(/sw|se|ne|nw/.test(handle
)) axis
.css({ zIndex
: ++o
.zIndex
});
109 //TODO : What's going on here?
110 if ('se' == handle
) {
111 axis
.addClass('ui-icon ui-icon-gripsmall-diagonal-se');
114 //Insert into internal handles object and append to element
115 this.handles
[handle
] = '.ui-resizable-'+handle
;
116 this.element
.append(axis
);
121 this._renderAxis = function(target
) {
123 target
= target
|| this.element
;
125 for(var i
in this.handles
) {
127 if(this.handles
[i
].constructor == String
)
128 this.handles
[i
] = $(this.handles
[i
], this.element
).show();
130 //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls)
131 if (this.elementIsWrapper
&& this.originalElement
[0].nodeName
.match(/textarea|input|select|button/i)) {
133 var axis
= $(this.handles
[i
], this.element
), padWrapper
= 0;
135 //Checking the correct pad and border
136 padWrapper
= /sw|ne|nw|se|n|s/.test(i
) ? axis
.outerHeight() : axis
.outerWidth();
138 //The padding type i have to apply...
139 var padPos
= [ 'padding',
140 /ne|nw|n/.test(i
) ? 'Top' :
141 /se|sw|s/.test(i
) ? 'Bottom' :
142 /^e$/.test(i
) ? 'Right' : 'Left' ].join("");
144 target
.css(padPos
, padWrapper
);
146 this._proportionallyResize();
150 //TODO: What's that good for? There's not anything to be executed left
151 if(!$(this.handles
[i
]).length
)
157 //TODO: make renderAxis a prototype function
158 this._renderAxis(this.element
);
160 this._handles
= $('.ui-resizable-handle', this.element
)
164 this._handles
.mouseover(function() {
165 if (!self
.resizing
) {
167 var axis
= this.className
.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);
169 self
.axis
= axis
&& axis
[1] ? axis
[1] : 'se';
173 //If we want to auto hide the elements
175 this._handles
.hide();
177 .addClass("ui-resizable-autohide")
179 if (o
.disabled
) return;
180 $(this).removeClass("ui-resizable-autohide");
181 self
._handles
.show();
184 if (o
.disabled
) return;
185 if (!self
.resizing
) {
186 $(this).addClass("ui-resizable-autohide");
187 self
._handles
.hide();
192 //Initialize the mouse interaction
197 destroy: function() {
199 this._mouseDestroy();
201 var _destroy = function(exp
) {
202 $(exp
).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing")
203 .removeData("resizable").unbind(".resizable").find('.ui-resizable-handle').remove();
206 //TODO: Unwrap at same DOM position
207 if (this.elementIsWrapper
) {
208 _destroy(this.element
);
209 var wrapper
= this.element
;
211 this.originalElement
.css({
212 position
: wrapper
.css('position'),
213 width
: wrapper
.outerWidth(),
214 height
: wrapper
.outerHeight(),
215 top
: wrapper
.css('top'),
216 left
: wrapper
.css('left')
221 this.originalElement
.css('resize', this.originalResizeStyle
);
222 _destroy(this.originalElement
);
227 _mouseCapture: function(event
) {
229 for (var i
in this.handles
) {
230 if ($(this.handles
[i
])[0] == event
.target
) {
235 return !this.options
.disabled
&& handle
;
238 _mouseStart: function(event
) {
240 var o
= this.options
, iniPos
= this.element
.position(), el
= this.element
;
242 this.resizing
= true;
243 this.documentScroll
= { top
: $(document
).scrollTop(), left
: $(document
).scrollLeft() };
245 // bugfix for http://dev.jquery.com/ticket/1749
246 if (el
.is('.ui-draggable') || (/absolute/).test(el
.css('position'))) {
247 el
.css({ position
: 'absolute', top
: iniPos
.top
, left
: iniPos
.left
});
250 //Opera fixing relative position
251 if ($.browser
.opera
&& (/relative/).test(el
.css('position')))
252 el
.css({ position
: 'relative', top
: 'auto', left
: 'auto' });
256 var curleft
= num(this.helper
.css('left')), curtop
= num(this.helper
.css('top'));
259 curleft
+= $(o
.containment
).scrollLeft() || 0;
260 curtop
+= $(o
.containment
).scrollTop() || 0;
263 //Store needed variables
264 this.offset
= this.helper
.offset();
265 this.position
= { left
: curleft
, top
: curtop
};
266 this.size
= this._helper
? { width
: el
.outerWidth(), height
: el
.outerHeight() } : { width
: el
.width(), height
: el
.height() };
267 this.originalSize
= this._helper
? { width
: el
.outerWidth(), height
: el
.outerHeight() } : { width
: el
.width(), height
: el
.height() };
268 this.originalPosition
= { left
: curleft
, top
: curtop
};
269 this.sizeDiff
= { width
: el
.outerWidth() - el
.width(), height
: el
.outerHeight() - el
.height() };
270 this.originalMousePosition
= { left
: event
.pageX
, top
: event
.pageY
};
273 this.aspectRatio
= (typeof o
.aspectRatio
== 'number') ? o
.aspectRatio
: ((this.originalSize
.width
/ this.originalSize
.height
) || 1);
275 var cursor
= $('.ui-resizable-' + this.axis
).css('cursor');
276 $('body').css('cursor', cursor
== 'auto' ? this.axis
+ '-resize' : cursor
);
278 el
.addClass("ui-resizable-resizing");
279 this._propagate("start", event
);
283 _mouseDrag: function(event
) {
285 //Increase performance, avoid regex
286 var el
= this.helper
, o
= this.options
, props
= {},
287 self
= this, smp
= this.originalMousePosition
, a
= this.axis
;
289 var dx
= (event
.pageX
-smp
.left
)||0, dy
= (event
.pageY
-smp
.top
)||0;
290 var trigger
= this._change
[a
];
291 if (!trigger
) return false;
293 // Calculate the attrs that will be change
294 var data
= trigger
.apply(this, [event
, dx
, dy
]), ie6
= $.browser
.msie
&& $.browser
.version
< 7, csdif
= this.sizeDiff
;
296 // Put this in the mouseDrag handler since the user can start pressing shift while resizing
297 this._updateVirtualBoundaries(event
.shiftKey
);
298 if (this._aspectRatio
|| event
.shiftKey
)
299 data
= this._updateRatio(data
, event
);
301 data
= this._respectSize(data
, event
);
303 // plugins callbacks need to be called first
304 this._propagate("resize", event
);
307 top
: this.position
.top
+ "px", left
: this.position
.left
+ "px",
308 width
: this.size
.width
+ "px", height
: this.size
.height
+ "px"
311 if (!this._helper
&& this._proportionallyResizeElements
.length
)
312 this._proportionallyResize();
314 this._updateCache(data
);
316 // calling the user callback at the end
317 this._trigger('resize', event
, this.ui());
322 _mouseStop: function(event
) {
324 this.resizing
= false;
325 var o
= this.options
, self
= this;
328 var pr
= this._proportionallyResizeElements
, ista
= pr
.length
&& (/textarea/i).test(pr
[0].nodeName
),
329 soffseth
= ista
&& $.ui
.hasScroll(pr
[0], 'left') /* TODO - jump height */ ? 0 : self
.sizeDiff
.height
,
330 soffsetw
= ista
? 0 : self
.sizeDiff
.width
;
332 var s
= { width
: (self
.helper
.width() - soffsetw
), height
: (self
.helper
.height() - soffseth
) },
333 left
= (parseInt(self
.element
.css('left'), 10) + (self
.position
.left
- self
.originalPosition
.left
)) || null,
334 top
= (parseInt(self
.element
.css('top'), 10) + (self
.position
.top
- self
.originalPosition
.top
)) || null;
337 this.element
.css($.extend(s
, { top
: top
, left
: left
}));
339 self
.helper
.height(self
.size
.height
);
340 self
.helper
.width(self
.size
.width
);
342 if (this._helper
&& !o
.animate
) this._proportionallyResize();
345 $('body').css('cursor', 'auto');
347 this.element
.removeClass("ui-resizable-resizing");
349 this._propagate("stop", event
);
351 if (this._helper
) this.helper
.remove();
356 _updateVirtualBoundaries: function(forceAspectRatio
) {
357 var o
= this.options
, pMinWidth
, pMaxWidth
, pMinHeight
, pMaxHeight
, b
;
360 minWidth
: isNumber(o
.minWidth
) ? o
.minWidth
: 0,
361 maxWidth
: isNumber(o
.maxWidth
) ? o
.maxWidth
: Infinity
,
362 minHeight
: isNumber(o
.minHeight
) ? o
.minHeight
: 0,
363 maxHeight
: isNumber(o
.maxHeight
) ? o
.maxHeight
: Infinity
366 if(this._aspectRatio
|| forceAspectRatio
) {
367 // We want to create an enclosing box whose aspect ration is the requested one
368 // First, compute the "projected" size for each dimension based on the aspect ratio and other dimension
369 pMinWidth
= b
.minHeight
* this.aspectRatio
;
370 pMinHeight
= b
.minWidth
/ this.aspectRatio
;
371 pMaxWidth
= b
.maxHeight
* this.aspectRatio
;
372 pMaxHeight
= b
.maxWidth
/ this.aspectRatio
;
374 if(pMinWidth
> b
.minWidth
) b
.minWidth
= pMinWidth
;
375 if(pMinHeight
> b
.minHeight
) b
.minHeight
= pMinHeight
;
376 if(pMaxWidth
< b
.maxWidth
) b
.maxWidth
= pMaxWidth
;
377 if(pMaxHeight
< b
.maxHeight
) b
.maxHeight
= pMaxHeight
;
379 this._vBoundaries
= b
;
382 _updateCache: function(data
) {
383 var o
= this.options
;
384 this.offset
= this.helper
.offset();
385 if (isNumber(data
.left
)) this.position
.left
= data
.left
;
386 if (isNumber(data
.top
)) this.position
.top
= data
.top
;
387 if (isNumber(data
.height
)) this.size
.height
= data
.height
;
388 if (isNumber(data
.width
)) this.size
.width
= data
.width
;
391 _updateRatio: function(data
, event
) {
393 var o
= this.options
, cpos
= this.position
, csize
= this.size
, a
= this.axis
;
395 if (isNumber(data
.height
)) data
.width
= (data
.height
* this.aspectRatio
);
396 else if (isNumber(data
.width
)) data
.height
= (data
.width
/ this.aspectRatio
);
399 data
.left
= cpos
.left
+ (csize
.width
- data
.width
);
403 data
.top
= cpos
.top
+ (csize
.height
- data
.height
);
404 data
.left
= cpos
.left
+ (csize
.width
- data
.width
);
410 _respectSize: function(data
, event
) {
412 var el
= this.helper
, o
= this._vBoundaries
, pRatio
= this._aspectRatio
|| event
.shiftKey
, a
= this.axis
,
413 ismaxw
= isNumber(data
.width
) && o
.maxWidth
&& (o
.maxWidth
< data
.width
), ismaxh
= isNumber(data
.height
) && o
.maxHeight
&& (o
.maxHeight
< data
.height
),
414 isminw
= isNumber(data
.width
) && o
.minWidth
&& (o
.minWidth
> data
.width
), isminh
= isNumber(data
.height
) && o
.minHeight
&& (o
.minHeight
> data
.height
);
416 if (isminw
) data
.width
= o
.minWidth
;
417 if (isminh
) data
.height
= o
.minHeight
;
418 if (ismaxw
) data
.width
= o
.maxWidth
;
419 if (ismaxh
) data
.height
= o
.maxHeight
;
421 var dw
= this.originalPosition
.left
+ this.originalSize
.width
, dh
= this.position
.top
+ this.size
.height
;
422 var cw
= /sw|nw|w/.test(a
), ch
= /nw|ne|n/.test(a
);
424 if (isminw
&& cw
) data
.left
= dw
- o
.minWidth
;
425 if (ismaxw
&& cw
) data
.left
= dw
- o
.maxWidth
;
426 if (isminh
&& ch
) data
.top
= dh
- o
.minHeight
;
427 if (ismaxh
&& ch
) data
.top
= dh
- o
.maxHeight
;
429 // fixing jump error on top/left - bug #2330
430 var isNotwh
= !data
.width
&& !data
.height
;
431 if (isNotwh
&& !data
.left
&& data
.top
) data
.top
= null;
432 else if (isNotwh
&& !data
.top
&& data
.left
) data
.left
= null;
437 _proportionallyResize: function() {
439 var o
= this.options
;
440 if (!this._proportionallyResizeElements
.length
) return;
441 var element
= this.helper
|| this.element
;
443 for (var i
=0; i
< this._proportionallyResizeElements
.length
; i
++) {
445 var prel
= this._proportionallyResizeElements
[i
];
447 if (!this.borderDif
) {
448 var b
= [prel
.css('borderTopWidth'), prel
.css('borderRightWidth'), prel
.css('borderBottomWidth'), prel
.css('borderLeftWidth')],
449 p
= [prel
.css('paddingTop'), prel
.css('paddingRight'), prel
.css('paddingBottom'), prel
.css('paddingLeft')];
451 this.borderDif
= $.map(b
, function(v
, i
) {
452 var border
= parseInt(v
,10)||0, padding
= parseInt(p
[i
],10)||0;
453 return border
+ padding
;
457 if ($.browser
.msie
&& !(!($(element
).is(':hidden') || $(element
).parents(':hidden').length
)))
461 height
: (element
.height() - this.borderDif
[0] - this.borderDif
[2]) || 0,
462 width
: (element
.width() - this.borderDif
[1] - this.borderDif
[3]) || 0
469 _renderProxy: function() {
471 var el
= this.element
, o
= this.options
;
472 this.elementOffset
= el
.offset();
476 this.helper
= this.helper
|| $('<div style="overflow:hidden;"></div>');
478 // fix ie6 offset TODO: This seems broken
479 var ie6
= $.browser
.msie
&& $.browser
.version
< 7, ie6offset
= (ie6
? 1 : 0),
480 pxyoffset
= ( ie6
? 2 : -1 );
482 this.helper
.addClass(this._helper
).css({
483 width
: this.element
.outerWidth() + pxyoffset
,
484 height
: this.element
.outerHeight() + pxyoffset
,
485 position
: 'absolute',
486 left
: this.elementOffset
.left
- ie6offset
+'px',
487 top
: this.elementOffset
.top
- ie6offset
+'px',
488 zIndex
: ++o
.zIndex
//TODO: Don't modify option
496 this.helper
= this.element
;
502 e: function(event
, dx
, dy
) {
503 return { width
: this.originalSize
.width
+ dx
};
505 w: function(event
, dx
, dy
) {
506 var o
= this.options
, cs
= this.originalSize
, sp
= this.originalPosition
;
507 return { left
: sp
.left
+ dx
, width
: cs
.width
- dx
};
509 n: function(event
, dx
, dy
) {
510 var o
= this.options
, cs
= this.originalSize
, sp
= this.originalPosition
;
511 return { top
: sp
.top
+ dy
, height
: cs
.height
- dy
};
513 s: function(event
, dx
, dy
) {
514 return { height
: this.originalSize
.height
+ dy
};
516 se: function(event
, dx
, dy
) {
517 return $.extend(this._change
.s
.apply(this, arguments
), this._change
.e
.apply(this, [event
, dx
, dy
]));
519 sw: function(event
, dx
, dy
) {
520 return $.extend(this._change
.s
.apply(this, arguments
), this._change
.w
.apply(this, [event
, dx
, dy
]));
522 ne: function(event
, dx
, dy
) {
523 return $.extend(this._change
.n
.apply(this, arguments
), this._change
.e
.apply(this, [event
, dx
, dy
]));
525 nw: function(event
, dx
, dy
) {
526 return $.extend(this._change
.n
.apply(this, arguments
), this._change
.w
.apply(this, [event
, dx
, dy
]));
530 _propagate: function(n
, event
) {
531 $.ui
.plugin
.call(this, n
, [event
, this.ui()]);
532 (n
!= "resize" && this._trigger(n
, event
, this.ui()));
539 originalElement
: this.originalElement
,
540 element
: this.element
,
542 position
: this.position
,
544 originalSize
: this.originalSize
,
545 originalPosition
: this.originalPosition
551 $.extend($.ui
.resizable
, {
556 * Resizable Extensions
559 $.ui
.plugin
.add("resizable", "alsoResize", {
561 start: function (event
, ui
) {
562 var self
= $(this).data("resizable"), o
= self
.options
;
564 var _store = function (exp
) {
565 $(exp
).each(function() {
567 el
.data("resizable-alsoresize", {
568 width
: parseInt(el
.width(), 10), height
: parseInt(el
.height(), 10),
569 left
: parseInt(el
.css('left'), 10), top
: parseInt(el
.css('top'), 10),
570 position
: el
.css('position') // to reset Opera on stop()
575 if (typeof(o
.alsoResize
) == 'object' && !o
.alsoResize
.parentNode
) {
576 if (o
.alsoResize
.length
) { o
.alsoResize
= o
.alsoResize
[0]; _store(o
.alsoResize
); }
577 else { $.each(o
.alsoResize
, function (exp
) { _store(exp
); }); }
579 _store(o
.alsoResize
);
583 resize: function (event
, ui
) {
584 var self
= $(this).data("resizable"), o
= self
.options
, os
= self
.originalSize
, op
= self
.originalPosition
;
587 height
: (self
.size
.height
- os
.height
) || 0, width
: (self
.size
.width
- os
.width
) || 0,
588 top
: (self
.position
.top
- op
.top
) || 0, left
: (self
.position
.left
- op
.left
) || 0
591 _alsoResize = function (exp
, c
) {
592 $(exp
).each(function() {
593 var el
= $(this), start
= $(this).data("resizable-alsoresize"), style
= {},
594 css
= c
&& c
.length
? c
: el
.parents(ui
.originalElement
[0]).length
? ['width', 'height'] : ['width', 'height', 'top', 'left'];
596 $.each(css
, function (i
, prop
) {
597 var sum
= (start
[prop
]||0) + (delta
[prop
]||0);
599 style
[prop
] = sum
|| null;
602 // Opera fixing relative position
603 if ($.browser
.opera
&& /relative/.test(el
.css('position'))) {
604 self
._revertToRelativePosition
= true;
605 el
.css({ position
: 'absolute', top
: 'auto', left
: 'auto' });
612 if (typeof(o
.alsoResize
) == 'object' && !o
.alsoResize
.nodeType
) {
613 $.each(o
.alsoResize
, function (exp
, c
) { _alsoResize(exp
, c
); });
615 _alsoResize(o
.alsoResize
);
619 stop: function (event
, ui
) {
620 var self
= $(this).data("resizable"), o
= self
.options
;
622 var _reset = function (exp
) {
623 $(exp
).each(function() {
625 // reset position for Opera - no need to verify it was changed
626 el
.css({ position
: el
.data("resizable-alsoresize").position
});
630 if (self
._revertToRelativePosition
) {
631 self
._revertToRelativePosition
= false;
632 if (typeof(o
.alsoResize
) == 'object' && !o
.alsoResize
.nodeType
) {
633 $.each(o
.alsoResize
, function (exp
) { _reset(exp
); });
635 _reset(o
.alsoResize
);
639 $(this).removeData("resizable-alsoresize");
643 $.ui
.plugin
.add("resizable", "animate", {
645 stop: function(event
, ui
) {
646 var self
= $(this).data("resizable"), o
= self
.options
;
648 var pr
= self
._proportionallyResizeElements
, ista
= pr
.length
&& (/textarea/i).test(pr
[0].nodeName
),
649 soffseth
= ista
&& $.ui
.hasScroll(pr
[0], 'left') /* TODO - jump height */ ? 0 : self
.sizeDiff
.height
,
650 soffsetw
= ista
? 0 : self
.sizeDiff
.width
;
652 var style
= { width
: (self
.size
.width
- soffsetw
), height
: (self
.size
.height
- soffseth
) },
653 left
= (parseInt(self
.element
.css('left'), 10) + (self
.position
.left
- self
.originalPosition
.left
)) || null,
654 top
= (parseInt(self
.element
.css('top'), 10) + (self
.position
.top
- self
.originalPosition
.top
)) || null;
656 self
.element
.animate(
657 $.extend(style
, top
&& left
? { top
: top
, left
: left
} : {}), {
658 duration
: o
.animateDuration
,
659 easing
: o
.animateEasing
,
663 width
: parseInt(self
.element
.css('width'), 10),
664 height
: parseInt(self
.element
.css('height'), 10),
665 top
: parseInt(self
.element
.css('top'), 10),
666 left
: parseInt(self
.element
.css('left'), 10)
669 if (pr
&& pr
.length
) $(pr
[0]).css({ width
: data
.width
, height
: data
.height
});
671 // propagating resize, and updating values for each animation step
672 self
._updateCache(data
);
673 self
._propagate("resize", event
);
682 $.ui
.plugin
.add("resizable", "containment", {
684 start: function(event
, ui
) {
685 var self
= $(this).data("resizable"), o
= self
.options
, el
= self
.element
;
686 var oc
= o
.containment
, ce
= (oc
instanceof $) ? oc
.get(0) : (/parent/.test(oc
)) ? el
.parent().get(0) : oc
;
689 self
.containerElement
= $(ce
);
691 if (/document/.test(oc
) || oc
== document
) {
692 self
.containerOffset
= { left
: 0, top
: 0 };
693 self
.containerPosition
= { left
: 0, top
: 0 };
696 element
: $(document
), left
: 0, top
: 0,
697 width
: $(document
).width(), height
: $(document
).height() || document
.body
.parentNode
.scrollHeight
701 // i'm a node, so compute top, left, right, bottom
703 var element
= $(ce
), p
= [];
704 $([ "Top", "Right", "Left", "Bottom" ]).each(function(i
, name
) { p
[i
] = num(element
.css("padding" + name
)); });
706 self
.containerOffset
= element
.offset();
707 self
.containerPosition
= element
.position();
708 self
.containerSize
= { height
: (element
.innerHeight() - p
[3]), width
: (element
.innerWidth() - p
[1]) };
710 var co
= self
.containerOffset
, ch
= self
.containerSize
.height
, cw
= self
.containerSize
.width
,
711 width
= ($.ui
.hasScroll(ce
, "left") ? ce
.scrollWidth
: cw
), height
= ($.ui
.hasScroll(ce
) ? ce
.scrollHeight
: ch
);
714 element
: ce
, left
: co
.left
, top
: co
.top
, width
: width
, height
: height
719 resize: function(event
, ui
) {
720 var self
= $(this).data("resizable"), o
= self
.options
,
721 ps
= self
.containerSize
, co
= self
.containerOffset
, cs
= self
.size
, cp
= self
.position
,
722 pRatio
= self
._aspectRatio
|| event
.shiftKey
, cop
= { top
:0, left
:0 }, ce
= self
.containerElement
;
724 if (ce
[0] != document
&& (/static/).test(ce
.css('position'))) cop
= co
;
726 if (cp
.left
< (self
._helper
? co
.left
: 0)) {
727 self
.size
.width
= self
.size
.width
+ (self
._helper
? (self
.position
.left
- co
.left
) : (self
.position
.left
- cop
.left
));
728 if (pRatio
) self
.size
.height
= self
.size
.width
/ o
.aspectRatio
;
729 self
.position
.left
= o
.helper
? co
.left
: 0;
732 if (cp
.top
< (self
._helper
? co
.top
: 0)) {
733 self
.size
.height
= self
.size
.height
+ (self
._helper
? (self
.position
.top
- co
.top
) : self
.position
.top
);
734 if (pRatio
) self
.size
.width
= self
.size
.height
* o
.aspectRatio
;
735 self
.position
.top
= self
._helper
? co
.top
: 0;
738 self
.offset
.left
= self
.parentData
.left
+self
.position
.left
;
739 self
.offset
.top
= self
.parentData
.top
+self
.position
.top
;
741 var woset
= Math
.abs( (self
._helper
? self
.offset
.left
- cop
.left
: (self
.offset
.left
- cop
.left
)) + self
.sizeDiff
.width
),
742 hoset
= Math
.abs( (self
._helper
? self
.offset
.top
- cop
.top
: (self
.offset
.top
- co
.top
)) + self
.sizeDiff
.height
);
744 var isParent
= self
.containerElement
.get(0) == self
.element
.parent().get(0),
745 isOffsetRelative
= /relative|absolute/.test(self
.containerElement
.css('position'));
747 if(isParent
&& isOffsetRelative
) woset
-= self
.parentData
.left
;
749 if (woset
+ self
.size
.width
>= self
.parentData
.width
) {
750 self
.size
.width
= self
.parentData
.width
- woset
;
751 if (pRatio
) self
.size
.height
= self
.size
.width
/ self
.aspectRatio
;
754 if (hoset
+ self
.size
.height
>= self
.parentData
.height
) {
755 self
.size
.height
= self
.parentData
.height
- hoset
;
756 if (pRatio
) self
.size
.width
= self
.size
.height
* self
.aspectRatio
;
760 stop: function(event
, ui
){
761 var self
= $(this).data("resizable"), o
= self
.options
, cp
= self
.position
,
762 co
= self
.containerOffset
, cop
= self
.containerPosition
, ce
= self
.containerElement
;
764 var helper
= $(self
.helper
), ho
= helper
.offset(), w
= helper
.outerWidth() - self
.sizeDiff
.width
, h
= helper
.outerHeight() - self
.sizeDiff
.height
;
766 if (self
._helper
&& !o
.animate
&& (/relative/).test(ce
.css('position')))
767 $(this).css({ left
: ho
.left
- cop
.left
- co
.left
, width
: w
, height
: h
});
769 if (self
._helper
&& !o
.animate
&& (/static/).test(ce
.css('position')))
770 $(this).css({ left
: ho
.left
- cop
.left
- co
.left
, width
: w
, height
: h
});
775 $.ui
.plugin
.add("resizable", "ghost", {
777 start: function(event
, ui
) {
779 var self
= $(this).data("resizable"), o
= self
.options
, cs
= self
.size
;
781 self
.ghost
= self
.originalElement
.clone();
783 .css({ opacity
: .25, display
: 'block', position
: 'relative', height
: cs
.height
, width
: cs
.width
, margin
: 0, left
: 0, top
: 0 })
784 .addClass('ui-resizable-ghost')
785 .addClass(typeof o
.ghost
== 'string' ? o
.ghost
: '');
787 self
.ghost
.appendTo(self
.helper
);
791 resize: function(event
, ui
){
792 var self
= $(this).data("resizable"), o
= self
.options
;
793 if (self
.ghost
) self
.ghost
.css({ position
: 'relative', height
: self
.size
.height
, width
: self
.size
.width
});
796 stop: function(event
, ui
){
797 var self
= $(this).data("resizable"), o
= self
.options
;
798 if (self
.ghost
&& self
.helper
) self
.helper
.get(0).removeChild(self
.ghost
.get(0));
803 $.ui
.plugin
.add("resizable", "grid", {
805 resize: function(event
, ui
) {
806 var self
= $(this).data("resizable"), o
= self
.options
, cs
= self
.size
, os
= self
.originalSize
, op
= self
.originalPosition
, a
= self
.axis
, ratio
= o
._aspectRatio
|| event
.shiftKey
;
807 o
.grid
= typeof o
.grid
== "number" ? [o
.grid
, o
.grid
] : o
.grid
;
808 var ox
= Math
.round((cs
.width
- os
.width
) / (o
.grid
[0]||1)) * (o
.grid
[0]||1), oy
= Math
.round((cs
.height
- os
.height
) / (o
.grid
[1]||1)) * (o
.grid
[1]||1);
810 if (/^(se|s|e)$/.test(a
)) {
811 self
.size
.width
= os
.width
+ ox
;
812 self
.size
.height
= os
.height
+ oy
;
814 else if (/^(ne)$/.test(a
)) {
815 self
.size
.width
= os
.width
+ ox
;
816 self
.size
.height
= os
.height
+ oy
;
817 self
.position
.top
= op
.top
- oy
;
819 else if (/^(sw)$/.test(a
)) {
820 self
.size
.width
= os
.width
+ ox
;
821 self
.size
.height
= os
.height
+ oy
;
822 self
.position
.left
= op
.left
- ox
;
825 self
.size
.width
= os
.width
+ ox
;
826 self
.size
.height
= os
.height
+ oy
;
827 self
.position
.top
= op
.top
- oy
;
828 self
.position
.left
= op
.left
- ox
;
834 var num = function(v
) {
835 return parseInt(v
, 10) || 0;
838 var isNumber = function(value
) {
839 return !isNaN(parseInt(value
, 10));