]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - jssource/src_files/include/javascript/yui3/build/resize/resize-constrain.js
Release 6.5.0
[Github/sugarcrm.git] / jssource / src_files / include / javascript / yui3 / build / resize / resize-constrain.js
1 /*
2 Copyright (c) 2010, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.com/yui/license.html
5 version: 3.3.0
6 build: 3167
7 */
8 YUI.add('resize-constrain', function(Y) {
9
10 var Lang = Y.Lang,
11         isBoolean = Lang.isBoolean,
12         isNumber = Lang.isNumber,
13         isString = Lang.isString,
14         capitalize = Y.Resize.capitalize,
15
16         isNode = function(v) {
17                 return (v instanceof Y.Node);
18         },
19
20         toNumber = function(num) {
21                 return parseFloat(num) || 0;
22         },
23
24         BORDER_BOTTOM_WIDTH = 'borderBottomWidth',
25         BORDER_LEFT_WIDTH = 'borderLeftWidth',
26         BORDER_RIGHT_WIDTH = 'borderRightWidth',
27         BORDER_TOP_WIDTH = 'borderTopWidth',
28         BORDER = 'border',
29         BOTTOM = 'bottom',
30         CON = 'con',
31         CONSTRAIN = 'constrain',
32         HOST = 'host',
33         LEFT = 'left',
34         MAX_HEIGHT = 'maxHeight',
35         MAX_WIDTH = 'maxWidth',
36         MIN_HEIGHT = 'minHeight',
37         MIN_WIDTH = 'minWidth',
38         NODE = 'node',
39         OFFSET_HEIGHT = 'offsetHeight',
40         OFFSET_WIDTH = 'offsetWidth',
41         PRESEVE_RATIO = 'preserveRatio',
42         REGION = 'region',
43         RESIZE_CONTRAINED = 'resizeConstrained',
44         RIGHT = 'right',
45         TICK_X = 'tickX',
46         TICK_Y = 'tickY',
47         TOP = 'top',
48         WIDTH = 'width',
49         VIEW = 'view',
50         VIEWPORT_REGION = 'viewportRegion';
51
52 function ResizeConstrained() {
53         ResizeConstrained.superclass.constructor.apply(this, arguments);
54 }
55
56 Y.mix(ResizeConstrained, {
57         NAME: RESIZE_CONTRAINED,
58
59         NS: CON,
60
61         ATTRS: {
62         /**
63         * Will attempt to constrain the resize node to the boundaries. Arguments:<br>
64         * 'view': Contrain to Viewport<br>
65         * '#selector_string': Constrain to this node<br>
66         * '{Region Object}': An Object Literal containing a valid region (top, right, bottom, left) of page positions
67         *
68         * @attribute constrain
69         * @type {String/Object/Node}
70         */
71                 constrain: {
72                         setter: function(v) {
73                                 if (v && (isNode(v) || isString(v) || v.nodeType)) {
74                                         v = Y.one(v);
75                                 }
76
77                                 return v;
78                         }
79                 },
80
81         /**
82          * The minimum height of the element
83          *
84          * @attribute minHeight
85          * @default 15
86          * @type Number
87          */
88                 minHeight: {
89                         value: 15,
90                         validator: isNumber
91                 },
92
93         /**
94          * The minimum width of the element
95          *
96          * @attribute minWidth
97          * @default 15
98          * @type Number
99          */
100                 minWidth: {
101                         value: 15,
102                         validator: isNumber
103                 },
104
105         /**
106          * The maximum height of the element
107          *
108          * @attribute maxHeight
109          * @default Infinity
110          * @type Number
111          */
112                 maxHeight: {
113                         value: Infinity,
114                         validator: isNumber
115                 },
116
117         /**
118          * The maximum width of the element
119          *
120          * @attribute maxWidth
121          * @default Infinity
122          * @type Number
123          */
124                 maxWidth: {
125                         value: Infinity,
126                         validator: isNumber
127                 },
128
129                 /**
130          * Maintain the element's ratio when resizing.
131          *
132          * @attribute preserveRatio
133          * @default false
134          * @type boolean
135          */
136                 preserveRatio: {
137                         value: false,
138                         validator: isBoolean
139                 },
140
141                 /**
142          * The number of x ticks to span the resize to.
143          *
144          * @attribute tickX
145          * @default false
146          * @type Number | false
147          */
148                 tickX: {
149                         value: false
150                 },
151
152         /**
153          * The number of y ticks to span the resize to.
154          *
155          * @attribute tickY
156          * @default false
157          * @type Number | false
158          */
159                 tickY: {
160                         value: false
161                 }
162         }
163 });
164
165 Y.extend(ResizeConstrained, Y.Plugin.Base, {
166         /**
167          * Stores the <code>constrain</code>
168          * surrounding information retrieved from
169          * <a href="Resize.html#method__getBoxSurroundingInfo">_getBoxSurroundingInfo</a>.
170          *
171          * @property constrainSurrounding
172          * @type Object
173          * @default null
174          */
175         constrainSurrounding: null,
176
177         initializer: function() {
178                 var instance = this,
179                         host = instance.get(HOST);
180
181                 host.delegate.dd.plug(
182                         Y.Plugin.DDConstrained,
183                         {
184                                 tickX: instance.get(TICK_X),
185                                 tickY: instance.get(TICK_Y)
186                         }
187                 );
188
189                 host.after('resize:align', Y.bind(instance._handleResizeAlignEvent, instance));
190                 host.on('resize:start', Y.bind(instance._handleResizeStartEvent, instance));
191         },
192
193         /**
194      * Helper method to update the current values on
195      * <a href="Resize.html#property_info">info</a> to respect the
196      * constrain node.
197          *
198          * @method _checkConstrain
199          * @param {String} axis 'top' or 'left'
200          * @param {String} axisConstrain 'bottom' or 'right'
201          * @param {String} offset 'offsetHeight' or 'offsetWidth'
202          * @protected
203          */
204         _checkConstrain: function(axis, axisConstrain, offset) {
205                 var instance = this,
206                         point1,
207                         point1Constrain,
208                         point2,
209                         point2Constrain,
210                         host = instance.get(HOST),
211                         info = host.info,
212                         constrainBorders = instance.constrainSurrounding.border,
213                         region = instance._getConstrainRegion();
214
215                 if (region) {
216                         point1 = info[axis] + info[offset];
217                         point1Constrain = region[axisConstrain] - toNumber(constrainBorders[capitalize(BORDER, axisConstrain, WIDTH)]);
218
219                         if (point1 >= point1Constrain) {
220                                 info[offset] -= (point1 - point1Constrain);
221                         }
222
223                         point2 = info[axis];
224                         point2Constrain = region[axis] + toNumber(constrainBorders[capitalize(BORDER, axis, WIDTH)]);
225
226                         if (point2 <= point2Constrain) {
227                                 info[axis] += (point2Constrain - point2);
228                                 info[offset] -= (point2Constrain - point2);
229                         }
230                 }
231         },
232
233     /**
234      * Update the current values on <a href="Resize.html#property_info">info</a>
235      * to respect the maxHeight and minHeight.
236      *
237      * @method _checkHeight
238      * @protected
239      */
240         _checkHeight: function() {
241                 var instance = this,
242                         host = instance.get(HOST),
243                         info = host.info,
244                         maxHeight = (instance.get(MAX_HEIGHT) + host.totalVSurrounding),
245                         minHeight = (instance.get(MIN_HEIGHT) + host.totalVSurrounding);
246
247                 instance._checkConstrain(TOP, BOTTOM, OFFSET_HEIGHT);
248
249                 if (info.offsetHeight > maxHeight) {
250                         host._checkSize(OFFSET_HEIGHT, maxHeight);
251                 }
252
253                 if (info.offsetHeight < minHeight) {
254                         host._checkSize(OFFSET_HEIGHT, minHeight);
255                 }
256         },
257
258     /**
259      * Update the current values on <a href="Resize.html#property_info">info</a>
260      * calculating the correct ratio for the other values.
261      *
262      * @method _checkRatio
263      * @protected
264      */
265         _checkRatio: function() {
266                 var instance = this,
267                         host = instance.get(HOST),
268                         info = host.info,
269                         originalInfo = host.originalInfo,
270                         oWidth = originalInfo.offsetWidth,
271                         oHeight = originalInfo.offsetHeight,
272                         oTop = originalInfo.top,
273                         oLeft = originalInfo.left,
274                         oBottom = originalInfo.bottom,
275                         oRight = originalInfo.right,
276                         // wRatio/hRatio functions keep the ratio information always synced with the current info information
277                         // RETURN: percentage how much width/height has changed from the original width/height
278                         wRatio = function() {
279                                 return (info.offsetWidth/oWidth);
280                         },
281                         hRatio = function() {
282                                 return (info.offsetHeight/oHeight);
283                         },
284                         isClosestToHeight = host.changeHeightHandles,
285                         bottomDiff,
286                         constrainBorders,
287                         constrainRegion,
288                         leftDiff,
289                         rightDiff,
290                         topDiff;
291
292                 // check whether the resizable node is closest to height or not
293                 if (instance.get(CONSTRAIN) && host.changeHeightHandles && host.changeWidthHandles) {
294                         constrainRegion = instance._getConstrainRegion();
295                         constrainBorders = instance.constrainSurrounding.border;
296                         bottomDiff = (constrainRegion.bottom - toNumber(constrainBorders[BORDER_BOTTOM_WIDTH])) - oBottom;
297                         leftDiff = oLeft - (constrainRegion.left + toNumber(constrainBorders[BORDER_LEFT_WIDTH]));
298                         rightDiff = (constrainRegion.right - toNumber(constrainBorders[BORDER_RIGHT_WIDTH])) - oRight;
299                         topDiff = oTop - (constrainRegion.top + toNumber(constrainBorders[BORDER_TOP_WIDTH]));
300
301                         if (host.changeLeftHandles && host.changeTopHandles) {
302                                 isClosestToHeight = (topDiff < leftDiff);
303                         }
304                         else if (host.changeLeftHandles) {
305                                 isClosestToHeight = (bottomDiff < leftDiff);
306                         }
307                         else if (host.changeTopHandles) {
308                                 isClosestToHeight = (topDiff < rightDiff);
309                         }
310                         else {
311                                 isClosestToHeight = (bottomDiff < rightDiff);
312                         }
313                 }
314
315                 // when the height of the resizable element touch the border of the constrain first
316                 // force the offsetWidth to be calculated based on the height ratio
317                 if (isClosestToHeight) {
318                         info.offsetWidth = oWidth*hRatio();
319                         instance._checkWidth();
320                         info.offsetHeight = oHeight*wRatio();
321                 }
322                 else {
323                         info.offsetHeight = oHeight*wRatio();
324                         instance._checkHeight();
325                         info.offsetWidth = oWidth*hRatio();
326                 }
327
328                 // fixing the top on handles which are able to change top
329                 // the idea here is change the top based on how much the height has changed instead of follow the dy
330                 if (host.changeTopHandles) {
331                         info.top = oTop + (oHeight - info.offsetHeight);
332                 }
333
334                 // fixing the left on handles which are able to change left
335                 // the idea here is change the left based on how much the width has changed instead of follow the dx
336                 if (host.changeLeftHandles) {
337                         info.left = oLeft + (oWidth - info.offsetWidth);
338                 }
339
340                 // rounding values to avoid pixel jumpings
341                 Y.each(info, function(value, key) {
342                         if (isNumber(value)) {
343                                 info[key] = Math.round(value);
344                         }
345                 });
346         },
347
348         /**
349          * Check whether the resizable node is inside the constrain region.
350          *
351          * @method _checkRegion
352          * @protected
353          * @return {boolean}
354          */
355         _checkRegion: function() {
356                 var instance = this,
357                         host = instance.get(HOST),
358                         region = instance._getConstrainRegion();
359
360                 return Y.DOM.inRegion(null, region, true, host.info);
361         },
362
363     /**
364      * Update the current values on <a href="Resize.html#property_info">info</a>
365      * to respect the maxWidth and minWidth.
366      *
367      * @method _checkWidth
368      * @protected
369      */
370         _checkWidth: function() {
371                 var instance = this,
372                         host = instance.get(HOST),
373                         info = host.info,
374                         maxWidth = (instance.get(MAX_WIDTH) + host.totalHSurrounding),
375                         minWidth = (instance.get(MIN_WIDTH) + host.totalHSurrounding);
376
377                 instance._checkConstrain(LEFT, RIGHT, OFFSET_WIDTH);
378
379                 if (info.offsetWidth < minWidth) {
380                         host._checkSize(OFFSET_WIDTH, minWidth);
381                 }
382
383                 if (info.offsetWidth > maxWidth) {
384                         host._checkSize(OFFSET_WIDTH, maxWidth);
385                 }
386         },
387
388         /**
389          * Get the constrain region based on the <code>constrain</code>
390      * attribute.
391          *
392          * @method _getConstrainRegion
393          * @protected
394          * @return {Object Region}
395          */
396         _getConstrainRegion: function() {
397                 var instance = this,
398                         host = instance.get(HOST),
399                         node = host.get(NODE),
400                         constrain = instance.get(CONSTRAIN),
401                         region = null;
402
403                 if (constrain) {
404                         if (constrain == VIEW) {
405                                 region = node.get(VIEWPORT_REGION);
406                         }
407                         else if (isNode(constrain)) {
408                                 region = constrain.get(REGION);
409                         }
410                         else {
411                                 region = constrain;
412                         }
413                 }
414
415                 return region;
416         },
417
418         _handleResizeAlignEvent: function(event) {
419                 var instance = this,
420                         host = instance.get(HOST);
421
422                 // check the max/min height and locking top when these values are reach
423                 instance._checkHeight();
424
425                 // check the max/min width and locking left when these values are reach
426                 instance._checkWidth();
427
428                 // calculating the ratio, for proportionally resizing
429                 if (instance.get(PRESEVE_RATIO)) {
430                         instance._checkRatio();
431                 }
432
433                 if (instance.get(CONSTRAIN) && !instance._checkRegion()) {
434                         host.info = host.lastInfo;
435                 }
436         },
437
438         _handleResizeStartEvent: function(event) {
439                 var instance = this,
440                         constrain = instance.get(CONSTRAIN),
441                         host = instance.get(HOST);
442
443                 instance.constrainSurrounding = host._getBoxSurroundingInfo(constrain);
444         }
445 });
446
447 Y.namespace('Plugin');
448 Y.Plugin.ResizeConstrained = ResizeConstrained;
449
450
451 }, '3.3.0' ,{requires:['resize-base', 'plugin'], skinnable:false});