- var Lang = Y.Lang,
- isBoolean = Lang.isBoolean,
- isNumber = Lang.isNumber,
- isString = Lang.isString,
- capitalize = Y.Resize.capitalize,
- isNode = function(v) {
- return (v instanceof Y.Node);
- },
- toNumber = function(num) {
- return parseFloat(num) || 0;
- },
- BORDER_BOTTOM_WIDTH = 'borderBottomWidth',
- BORDER_LEFT_WIDTH = 'borderLeftWidth',
- BORDER_RIGHT_WIDTH = 'borderRightWidth',
- BORDER_TOP_WIDTH = 'borderTopWidth',
- BORDER = 'border',
- BOTTOM = 'bottom',
- CON = 'con',
- CONSTRAIN = 'constrain',
- HOST = 'host',
- LEFT = 'left',
- MAX_HEIGHT = 'maxHeight',
- MAX_WIDTH = 'maxWidth',
- MIN_HEIGHT = 'minHeight',
- MIN_WIDTH = 'minWidth',
- NODE = 'node',
- OFFSET_HEIGHT = 'offsetHeight',
- OFFSET_WIDTH = 'offsetWidth',
- PRESEVE_RATIO = 'preserveRatio',
- REGION = 'region',
- RESIZE_CONTRAINED = 'resizeConstrained',
- RIGHT = 'right',
- TICK_X = 'tickX',
- TICK_Y = 'tickY',
- TOP = 'top',
- WIDTH = 'width',
- VIEW = 'view',
- VIEWPORT_REGION = 'viewportRegion';
- /**
- A Resize plugin that will attempt to constrain the resize node to the boundaries.
- @module resize
- @submodule resize-contrain
- @class ResizeConstrained
- @param config {Object} Object literal specifying widget configuration properties.
- @constructor
- @extends Plugin.Base
- @namespace Plugin
- */
- function ResizeConstrained() {
- ResizeConstrained.superclass.constructor.apply(this, arguments);
- }
- Y.mix(ResizeConstrained, {
- NAME: RESIZE_CONTRAINED,
- NS: CON,
- ATTRS: {
- /**
- * Will attempt to constrain the resize node to the boundaries. Arguments:<br>
- * 'view': Contrain to Viewport<br>
- * '#selector_string': Constrain to this node<br>
- * '{Region Object}': An Object Literal containing a valid region (top, right, bottom, left) of page positions
- *
- * @attribute constrain
- * @type {String|Object|Node}
- */
- constrain: {
- setter: function(v) {
- if (v && (isNode(v) || isString(v) || v.nodeType)) {
- v = Y.one(v);
- }
- return v;
- }
- },
- /**
- * The minimum height of the element
- *
- * @attribute minHeight
- * @default 15
- * @type Number
- */
- minHeight: {
- value: 15,
- validator: isNumber
- },
- /**
- * The minimum width of the element
- *
- * @attribute minWidth
- * @default 15
- * @type Number
- */
- minWidth: {
- value: 15,
- validator: isNumber
- },
- /**
- * The maximum height of the element
- *
- * @attribute maxHeight
- * @default Infinity
- * @type Number
- */
- maxHeight: {
- value: Infinity,
- validator: isNumber
- },
- /**
- * The maximum width of the element
- *
- * @attribute maxWidth
- * @default Infinity
- * @type Number
- */
- maxWidth: {
- value: Infinity,
- validator: isNumber
- },
- /**
- * Maintain the element's ratio when resizing.
- *
- * @attribute preserveRatio
- * @default false
- * @type boolean
- */
- preserveRatio: {
- value: false,
- validator: isBoolean
- },
- /**
- * The number of x ticks to span the resize to.
- *
- * @attribute tickX
- * @default false
- * @type Number | false
- */
- tickX: {
- value: false
- },
- /**
- * The number of y ticks to span the resize to.
- *
- * @attribute tickY
- * @default false
- * @type Number | false
- */
- tickY: {
- value: false
- }
- }
- });
- Y.extend(ResizeConstrained, Y.Plugin.Base, {
- /**
- * Stores the <code>constrain</code>
- * surrounding information retrieved from
- * <a href="Resize.html#method__getBoxSurroundingInfo">_getBoxSurroundingInfo</a>.
- *
- * @property constrainSurrounding
- * @type Object
- * @default null
- */
- constrainSurrounding: null,
- initializer: function() {
- var instance = this,
- host = instance.get(HOST);
- host.delegate.dd.plug(
- Y.Plugin.DDConstrained,
- {
- tickX: instance.get(TICK_X),
- tickY: instance.get(TICK_Y)
- }
- );
- host.after('resize:align', Y.bind(instance._handleResizeAlignEvent, instance));
- host.on('resize:start', Y.bind(instance._handleResizeStartEvent, instance));
- },
- /**
- * Helper method to update the current values on
- * <a href="Resize.html#property_info">info</a> to respect the
- * constrain node.
- *
- * @method _checkConstrain
- * @param {String} axis 'top' or 'left'
- * @param {String} axisConstrain 'bottom' or 'right'
- * @param {String} offset 'offsetHeight' or 'offsetWidth'
- * @protected
- */
- _checkConstrain: function(axis, axisConstrain, offset) {
- var instance = this,
- point1,
- point1Constrain,
- point2,
- point2Constrain,
- host = instance.get(HOST),
- info = host.info,
- constrainBorders = instance.constrainSurrounding.border,
- region = instance._getConstrainRegion();
- if (region) {
- point1 = info[axis] + info[offset];
- point1Constrain = region[axisConstrain] - toNumber(constrainBorders[capitalize(BORDER, axisConstrain, WIDTH)]);
- if (point1 >= point1Constrain) {
- info[offset] -= (point1 - point1Constrain);
- }
- point2 = info[axis];
- point2Constrain = region[axis] + toNumber(constrainBorders[capitalize(BORDER, axis, WIDTH)]);
- if (point2 <= point2Constrain) {
- info[axis] += (point2Constrain - point2);
- info[offset] -= (point2Constrain - point2);
- }
- }
- },
- /**
- * Update the current values on <a href="Resize.html#property_info">info</a>
- * to respect the maxHeight and minHeight.
- *
- * @method _checkHeight
- * @protected
- */
- _checkHeight: function() {
- var instance = this,
- host = instance.get(HOST),
- info = host.info,
- maxHeight = (instance.get(MAX_HEIGHT) + host.totalVSurrounding),
- minHeight = (instance.get(MIN_HEIGHT) + host.totalVSurrounding);
- instance._checkConstrain(TOP, BOTTOM, OFFSET_HEIGHT);
- if (info.offsetHeight > maxHeight) {
- host._checkSize(OFFSET_HEIGHT, maxHeight);
- }
- if (info.offsetHeight < minHeight) {
- host._checkSize(OFFSET_HEIGHT, minHeight);
- }
- },
- /**
- * Update the current values on <a href="Resize.html#property_info">info</a>
- * calculating the correct ratio for the other values.
- *
- * @method _checkRatio
- * @protected
- */
- _checkRatio: function() {
- var instance = this,
- host = instance.get(HOST),
- info = host.info,
- originalInfo = host.originalInfo,
- oWidth = originalInfo.offsetWidth,
- oHeight = originalInfo.offsetHeight,
- oTop = originalInfo.top,
- oLeft = originalInfo.left,
- oBottom = originalInfo.bottom,
- oRight = originalInfo.right,
- // wRatio/hRatio functions keep the ratio information always synced with the current info information
- // RETURN: percentage how much width/height has changed from the original width/height
- wRatio = function() {
- return (info.offsetWidth/oWidth);
- },
- hRatio = function() {
- return (info.offsetHeight/oHeight);
- },
- isClosestToHeight = host.changeHeightHandles,
- bottomDiff,
- constrainBorders,
- constrainRegion,
- leftDiff,
- rightDiff,
- topDiff;
- // check whether the resizable node is closest to height or not
- if (instance.get(CONSTRAIN) && host.changeHeightHandles && host.changeWidthHandles) {
- constrainRegion = instance._getConstrainRegion();
- constrainBorders = instance.constrainSurrounding.border;
- bottomDiff = (constrainRegion.bottom - toNumber(constrainBorders[BORDER_BOTTOM_WIDTH])) - oBottom;
- leftDiff = oLeft - (constrainRegion.left + toNumber(constrainBorders[BORDER_LEFT_WIDTH]));
- rightDiff = (constrainRegion.right - toNumber(constrainBorders[BORDER_RIGHT_WIDTH])) - oRight;
- topDiff = oTop - (constrainRegion.top + toNumber(constrainBorders[BORDER_TOP_WIDTH]));
- if (host.changeLeftHandles && host.changeTopHandles) {
- isClosestToHeight = (topDiff < leftDiff);
- }
- else if (host.changeLeftHandles) {
- isClosestToHeight = (bottomDiff < leftDiff);
- }
- else if (host.changeTopHandles) {
- isClosestToHeight = (topDiff < rightDiff);
- }
- else {
- isClosestToHeight = (bottomDiff < rightDiff);
- }
- }
- // when the height of the resizable element touch the border of the constrain first
- // force the offsetWidth to be calculated based on the height ratio
- if (isClosestToHeight) {
- info.offsetWidth = oWidth*hRatio();
- instance._checkWidth();
- info.offsetHeight = oHeight*wRatio();
- }
- else {
- info.offsetHeight = oHeight*wRatio();
- instance._checkHeight();
- info.offsetWidth = oWidth*hRatio();
- }
- // fixing the top on handles which are able to change top
- // the idea here is change the top based on how much the height has changed instead of follow the dy
- if (host.changeTopHandles) {
- info.top = oTop + (oHeight - info.offsetHeight);
- }
- // fixing the left on handles which are able to change left
- // the idea here is change the left based on how much the width has changed instead of follow the dx
- if (host.changeLeftHandles) {
- info.left = oLeft + (oWidth - info.offsetWidth);
- }
- // rounding values to avoid pixel jumpings
- Y.each(info, function(value, key) {
- if (isNumber(value)) {
- info[key] = Math.round(value);
- }
- });
- },
- /**
- * Check whether the resizable node is inside the constrain region.
- *
- * @method _checkRegion
- * @protected
- * @return {boolean}
- */
- _checkRegion: function() {
- var instance = this,
- host = instance.get(HOST),
- region = instance._getConstrainRegion();
- return Y.DOM.inRegion(null, region, true, host.info);
- },
- /**
- * Update the current values on <a href="Resize.html#property_info">info</a>
- * to respect the maxWidth and minWidth.
- *
- * @method _checkWidth
- * @protected
- */
- _checkWidth: function() {
- var instance = this,
- host = instance.get(HOST),
- info = host.info,
- maxWidth = (instance.get(MAX_WIDTH) + host.totalHSurrounding),
- minWidth = (instance.get(MIN_WIDTH) + host.totalHSurrounding);
- instance._checkConstrain(LEFT, RIGHT, OFFSET_WIDTH);
- if (info.offsetWidth < minWidth) {
- host._checkSize(OFFSET_WIDTH, minWidth);
- }
- if (info.offsetWidth > maxWidth) {
- host._checkSize(OFFSET_WIDTH, maxWidth);
- }
- },
- /**
- * Get the constrain region based on the <code>constrain</code>
- * attribute.
- *
- * @method _getConstrainRegion
- * @protected
- * @return {Object Region}
- */
- _getConstrainRegion: function() {
- var instance = this,
- host = instance.get(HOST),
- node = host.get(NODE),
- constrain = instance.get(CONSTRAIN),
- region = null;
- if (constrain) {
- if (constrain === VIEW) {
- region = node.get(VIEWPORT_REGION);
- }
- else if (isNode(constrain)) {
- region = constrain.get(REGION);
- }
- else {
- region = constrain;
- }
- }
- return region;
- },
- _handleResizeAlignEvent: function() {
- var instance = this,
- host = instance.get(HOST);
- // check the max/min height and locking top when these values are reach
- instance._checkHeight();
- // check the max/min width and locking left when these values are reach
- instance._checkWidth();
- // calculating the ratio, for proportionally resizing
- if (instance.get(PRESEVE_RATIO)) {
- instance._checkRatio();
- }
- if (instance.get(CONSTRAIN) && !instance._checkRegion()) {
- host.info = host.lastInfo;
- }
- },
- _handleResizeStartEvent: function() {
- var instance = this,
- constrain = instance.get(CONSTRAIN),
- host = instance.get(HOST);
- instance.constrainSurrounding = host._getBoxSurroundingInfo(constrain);
- }
- });
- Y.namespace('Plugin');
- Y.Plugin.ResizeConstrained = ResizeConstrained;
-