3
Copyright 2012 Yahoo! Inc. All rights reserved.
4
Licensed under the BSD License.
5
http://yuilibrary.com/license/
7
YUI.add('resize-constrain', function(Y) {
10
isBoolean = Lang.isBoolean,
11
isNumber = Lang.isNumber,
12
isString = Lang.isString,
13
capitalize = Y.Resize.capitalize,
15
isNode = function(v) {
16
return (v instanceof Y.Node);
19
toNumber = function(num) {
20
return parseFloat(num) || 0;
23
BORDER_BOTTOM_WIDTH = 'borderBottomWidth',
24
BORDER_LEFT_WIDTH = 'borderLeftWidth',
25
BORDER_RIGHT_WIDTH = 'borderRightWidth',
26
BORDER_TOP_WIDTH = 'borderTopWidth',
30
CONSTRAIN = 'constrain',
33
MAX_HEIGHT = 'maxHeight',
34
MAX_WIDTH = 'maxWidth',
35
MIN_HEIGHT = 'minHeight',
36
MIN_WIDTH = 'minWidth',
38
OFFSET_HEIGHT = 'offsetHeight',
39
OFFSET_WIDTH = 'offsetWidth',
40
PRESEVE_RATIO = 'preserveRatio',
42
RESIZE_CONTRAINED = 'resizeConstrained',
49
VIEWPORT_REGION = 'viewportRegion';
52
A Resize plugin that will attempt to constrain the resize node to the boundaries.
54
@submodule resize-contrain
55
@class ResizeConstrained
56
@param config {Object} Object literal specifying widget configuration properties.
62
function ResizeConstrained() {
63
ResizeConstrained.superclass.constructor.apply(this, arguments);
66
Y.mix(ResizeConstrained, {
67
NAME: RESIZE_CONTRAINED,
73
* Will attempt to constrain the resize node to the boundaries. Arguments:<br>
74
* 'view': Contrain to Viewport<br>
75
* '#selector_string': Constrain to this node<br>
76
* '{Region Object}': An Object Literal containing a valid region (top, right, bottom, left) of page positions
78
* @attribute constrain
79
* @type {String|Object|Node}
83
if (v && (isNode(v) || isString(v) || v.nodeType)) {
92
* The minimum height of the element
94
* @attribute minHeight
104
* The minimum width of the element
106
* @attribute minWidth
116
* The maximum height of the element
118
* @attribute maxHeight
128
* The maximum width of the element
130
* @attribute maxWidth
140
* Maintain the element's ratio when resizing.
142
* @attribute preserveRatio
152
* The number of x ticks to span the resize to.
156
* @type Number | false
163
* The number of y ticks to span the resize to.
167
* @type Number | false
175
Y.extend(ResizeConstrained, Y.Plugin.Base, {
177
* Stores the <code>constrain</code>
178
* surrounding information retrieved from
179
* <a href="Resize.html#method__getBoxSurroundingInfo">_getBoxSurroundingInfo</a>.
181
* @property constrainSurrounding
185
constrainSurrounding: null,
187
initializer: function() {
189
host = instance.get(HOST);
191
host.delegate.dd.plug(
192
Y.Plugin.DDConstrained,
194
tickX: instance.get(TICK_X),
195
tickY: instance.get(TICK_Y)
199
host.after('resize:align', Y.bind(instance._handleResizeAlignEvent, instance));
200
host.on('resize:start', Y.bind(instance._handleResizeStartEvent, instance));
204
* Helper method to update the current values on
205
* <a href="Resize.html#property_info">info</a> to respect the
208
* @method _checkConstrain
209
* @param {String} axis 'top' or 'left'
210
* @param {String} axisConstrain 'bottom' or 'right'
211
* @param {String} offset 'offsetHeight' or 'offsetWidth'
214
_checkConstrain: function(axis, axisConstrain, offset) {
220
host = instance.get(HOST),
222
constrainBorders = instance.constrainSurrounding.border,
223
region = instance._getConstrainRegion();
226
point1 = info[axis] + info[offset];
227
point1Constrain = region[axisConstrain] - toNumber(constrainBorders[capitalize(BORDER, axisConstrain, WIDTH)]);
229
if (point1 >= point1Constrain) {
230
info[offset] -= (point1 - point1Constrain);
234
point2Constrain = region[axis] + toNumber(constrainBorders[capitalize(BORDER, axis, WIDTH)]);
236
if (point2 <= point2Constrain) {
237
info[axis] += (point2Constrain - point2);
238
info[offset] -= (point2Constrain - point2);
244
* Update the current values on <a href="Resize.html#property_info">info</a>
245
* to respect the maxHeight and minHeight.
247
* @method _checkHeight
250
_checkHeight: function() {
252
host = instance.get(HOST),
254
maxHeight = (instance.get(MAX_HEIGHT) + host.totalVSurrounding),
255
minHeight = (instance.get(MIN_HEIGHT) + host.totalVSurrounding);
257
instance._checkConstrain(TOP, BOTTOM, OFFSET_HEIGHT);
259
if (info.offsetHeight > maxHeight) {
260
host._checkSize(OFFSET_HEIGHT, maxHeight);
263
if (info.offsetHeight < minHeight) {
264
host._checkSize(OFFSET_HEIGHT, minHeight);
269
* Update the current values on <a href="Resize.html#property_info">info</a>
270
* calculating the correct ratio for the other values.
272
* @method _checkRatio
275
_checkRatio: function() {
277
host = instance.get(HOST),
279
originalInfo = host.originalInfo,
280
oWidth = originalInfo.offsetWidth,
281
oHeight = originalInfo.offsetHeight,
282
oTop = originalInfo.top,
283
oLeft = originalInfo.left,
284
oBottom = originalInfo.bottom,
285
oRight = originalInfo.right,
286
// wRatio/hRatio functions keep the ratio information always synced with the current info information
287
// RETURN: percentage how much width/height has changed from the original width/height
288
wRatio = function() {
289
return (info.offsetWidth/oWidth);
291
hRatio = function() {
292
return (info.offsetHeight/oHeight);
294
isClosestToHeight = host.changeHeightHandles,
302
// check whether the resizable node is closest to height or not
303
if (instance.get(CONSTRAIN) && host.changeHeightHandles && host.changeWidthHandles) {
304
constrainRegion = instance._getConstrainRegion();
305
constrainBorders = instance.constrainSurrounding.border;
306
bottomDiff = (constrainRegion.bottom - toNumber(constrainBorders[BORDER_BOTTOM_WIDTH])) - oBottom;
307
leftDiff = oLeft - (constrainRegion.left + toNumber(constrainBorders[BORDER_LEFT_WIDTH]));
308
rightDiff = (constrainRegion.right - toNumber(constrainBorders[BORDER_RIGHT_WIDTH])) - oRight;
309
topDiff = oTop - (constrainRegion.top + toNumber(constrainBorders[BORDER_TOP_WIDTH]));
311
if (host.changeLeftHandles && host.changeTopHandles) {
312
isClosestToHeight = (topDiff < leftDiff);
314
else if (host.changeLeftHandles) {
315
isClosestToHeight = (bottomDiff < leftDiff);
317
else if (host.changeTopHandles) {
318
isClosestToHeight = (topDiff < rightDiff);
321
isClosestToHeight = (bottomDiff < rightDiff);
325
// when the height of the resizable element touch the border of the constrain first
326
// force the offsetWidth to be calculated based on the height ratio
327
if (isClosestToHeight) {
328
info.offsetWidth = oWidth*hRatio();
329
instance._checkWidth();
330
info.offsetHeight = oHeight*wRatio();
333
info.offsetHeight = oHeight*wRatio();
334
instance._checkHeight();
335
info.offsetWidth = oWidth*hRatio();
338
// fixing the top on handles which are able to change top
339
// the idea here is change the top based on how much the height has changed instead of follow the dy
340
if (host.changeTopHandles) {
341
info.top = oTop + (oHeight - info.offsetHeight);
344
// fixing the left on handles which are able to change left
345
// the idea here is change the left based on how much the width has changed instead of follow the dx
346
if (host.changeLeftHandles) {
347
info.left = oLeft + (oWidth - info.offsetWidth);
350
// rounding values to avoid pixel jumpings
351
Y.each(info, function(value, key) {
352
if (isNumber(value)) {
353
info[key] = Math.round(value);
359
* Check whether the resizable node is inside the constrain region.
361
* @method _checkRegion
365
_checkRegion: function() {
367
host = instance.get(HOST),
368
region = instance._getConstrainRegion();
370
return Y.DOM.inRegion(null, region, true, host.info);
374
* Update the current values on <a href="Resize.html#property_info">info</a>
375
* to respect the maxWidth and minWidth.
377
* @method _checkWidth
380
_checkWidth: function() {
382
host = instance.get(HOST),
384
maxWidth = (instance.get(MAX_WIDTH) + host.totalHSurrounding),
385
minWidth = (instance.get(MIN_WIDTH) + host.totalHSurrounding);
387
instance._checkConstrain(LEFT, RIGHT, OFFSET_WIDTH);
389
if (info.offsetWidth < minWidth) {
390
host._checkSize(OFFSET_WIDTH, minWidth);
393
if (info.offsetWidth > maxWidth) {
394
host._checkSize(OFFSET_WIDTH, maxWidth);
399
* Get the constrain region based on the <code>constrain</code>
402
* @method _getConstrainRegion
404
* @return {Object Region}
406
_getConstrainRegion: function() {
408
host = instance.get(HOST),
409
node = host.get(NODE),
410
constrain = instance.get(CONSTRAIN),
414
if (constrain == VIEW) {
415
region = node.get(VIEWPORT_REGION);
417
else if (isNode(constrain)) {
418
region = constrain.get(REGION);
428
_handleResizeAlignEvent: function(event) {
430
host = instance.get(HOST);
432
// check the max/min height and locking top when these values are reach
433
instance._checkHeight();
435
// check the max/min width and locking left when these values are reach
436
instance._checkWidth();
438
// calculating the ratio, for proportionally resizing
439
if (instance.get(PRESEVE_RATIO)) {
440
instance._checkRatio();
443
if (instance.get(CONSTRAIN) && !instance._checkRegion()) {
444
host.info = host.lastInfo;
448
_handleResizeStartEvent: function(event) {
450
constrain = instance.get(CONSTRAIN),
451
host = instance.get(HOST);
453
instance.constrainSurrounding = host._getBoxSurroundingInfo(constrain);
457
Y.namespace('Plugin');
458
Y.Plugin.ResizeConstrained = ResizeConstrained;
461
}, '3.5.1' ,{requires:['resize-base', 'plugin'], skinnable:false});