~bac/juju-gui/trunkcopy

« back to all changes in this revision

Viewing changes to lib/yui/build/resize-constrain/resize-constrain.js

  • Committer: kapil.foss at gmail
  • Date: 2012-07-13 18:45:59 UTC
  • Revision ID: kapil.foss@gmail.com-20120713184559-2xl7be17egsrz0c9
reshape

Show diffs side-by-side

added added

removed removed

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