- /**
- * The Resize Utility allows you to make an HTML element resizable.
- * @module resize
- * @main resize
- */
-
- var Lang = Y.Lang,
- isArray = Lang.isArray,
- isBoolean = Lang.isBoolean,
- isNumber = Lang.isNumber,
- isString = Lang.isString,
-
- yArray = Y.Array,
- trim = Lang.trim,
- indexOf = yArray.indexOf,
-
- COMMA = ',',
- DOT = '.',
- EMPTY_STR = '',
- HANDLE_SUB = '{handle}',
- SPACE = ' ',
-
- ACTIVE = 'active',
- ACTIVE_HANDLE = 'activeHandle',
- ACTIVE_HANDLE_NODE = 'activeHandleNode',
- ALL = 'all',
- AUTO_HIDE = 'autoHide',
- BORDER = 'border',
- BOTTOM = 'bottom',
- CLASS_NAME = 'className',
- COLOR = 'color',
- DEF_MIN_HEIGHT = 'defMinHeight',
- DEF_MIN_WIDTH = 'defMinWidth',
- HANDLE = 'handle',
- HANDLES = 'handles',
- HANDLES_WRAPPER = 'handlesWrapper',
- HIDDEN = 'hidden',
- INNER = 'inner',
- LEFT = 'left',
- MARGIN = 'margin',
- NODE = 'node',
- NODE_NAME = 'nodeName',
- NONE = 'none',
- OFFSET_HEIGHT = 'offsetHeight',
- OFFSET_WIDTH = 'offsetWidth',
- PADDING = 'padding',
- PARENT_NODE = 'parentNode',
- POSITION = 'position',
- RELATIVE = 'relative',
- RESIZE = 'resize',
- RESIZING = 'resizing',
- RIGHT = 'right',
- STATIC = 'static',
- STYLE = 'style',
- TOP = 'top',
- WIDTH = 'width',
- WRAP = 'wrap',
- WRAPPER = 'wrapper',
- WRAP_TYPES = 'wrapTypes',
-
- EV_MOUSE_UP = 'resize:mouseUp',
- EV_RESIZE = 'resize:resize',
- EV_RESIZE_ALIGN = 'resize:align',
- EV_RESIZE_END = 'resize:end',
- EV_RESIZE_START = 'resize:start',
-
- T = 't',
- TR = 'tr',
- R = 'r',
- BR = 'br',
- B = 'b',
- BL = 'bl',
- L = 'l',
- TL = 'tl',
-
- concat = function() {
- return Array.prototype.slice.call(arguments).join(SPACE);
- },
-
- // round the passed number to get rid of pixel-flickering
- toRoundNumber = function(num) {
- return Math.round(parseFloat(num)) || 0;
- },
-
- getCompStyle = function(node, val) {
- return node.getComputedStyle(val);
- },
-
- handleAttrName = function(handle) {
- return HANDLE + handle.toUpperCase();
- },
-
- isNode = function(v) {
- return (v instanceof Y.Node);
- },
-
- toInitialCap = Y.cached(
- function(str) {
- return str.substring(0, 1).toUpperCase() + str.substring(1);
- }
- ),
-
- capitalize = Y.cached(function() {
- var out = [],
- args = yArray(arguments, 0, true);
-
- yArray.each(args, function(part, i) {
- if (i > 0) {
- part = toInitialCap(part);
- }
- out.push(part);
- });
-
- return out.join(EMPTY_STR);
- }),
-
- getCN = Y.ClassNameManager.getClassName,
-
- CSS_RESIZE = getCN(RESIZE),
- CSS_RESIZE_HANDLE = getCN(RESIZE, HANDLE),
- CSS_RESIZE_HANDLE_ACTIVE = getCN(RESIZE, HANDLE, ACTIVE),
- CSS_RESIZE_HANDLE_INNER = getCN(RESIZE, HANDLE, INNER),
- CSS_RESIZE_HANDLE_INNER_PLACEHOLDER = getCN(RESIZE, HANDLE, INNER, HANDLE_SUB),
- CSS_RESIZE_HANDLE_PLACEHOLDER = getCN(RESIZE, HANDLE, HANDLE_SUB),
- CSS_RESIZE_HIDDEN_HANDLES = getCN(RESIZE, HIDDEN, HANDLES),
- CSS_RESIZE_HANDLES_WRAPPER = getCN(RESIZE, HANDLES, WRAPPER),
- CSS_RESIZE_WRAPPER = getCN(RESIZE, WRAPPER);
-
- /**
- A base class for Resize, providing:
-
- * Basic Lifecycle (initializer, renderUI, bindUI, syncUI, destructor)
- * Applies drag handles to an element to make it resizable
- * Here is the list of valid resize handles:
- `[ 't', 'tr', 'r', 'br', 'b', 'bl', 'l', 'tl' ]`. You can
- read this list as top, top-right, right, bottom-right, bottom,
- bottom-left, left, top-left.
- * The drag handles are inserted into the element and positioned
- absolute. Some elements, such as a textarea or image, don't support
- children. To overcome that, set wrap:true in your config and the
- element willbe wrapped for you automatically.
-
- Quick Example:
-
- var instance = new Y.Resize({
- node: '#resize1',
- preserveRatio: true,
- wrap: true,
- maxHeight: 170,
- maxWidth: 400,
- handles: 't, tr, r, br, b, bl, l, tl'
- });
-
- Check the list of <a href="Resize.html#attrs">Configuration Attributes</a> available for
- Resize.
-
- @class Resize
- @param config {Object} Object literal specifying widget configuration properties.
- @constructor
- @extends Base
- */
-
- function Resize() {
- Resize.superclass.constructor.apply(this, arguments);
- }
-
- Y.mix(Resize, {
- /**
- * Static property provides a string to identify the class.
- *
- * @property NAME
- * @type String
- * @static
- */
- NAME: RESIZE,
-
- /**
- * Static property used to define the default attribute
- * configuration for the Resize.
- *
- * @property ATTRS
- * @type Object
- * @static
- */
- ATTRS: {
- /**
- * Stores the active handle during the resize.
- *
- * @attribute activeHandle
- * @default null
- * @private
- * @type String
- */
- activeHandle: {
- value: null,
- validator: function(v) {
- return Y.Lang.isString(v) || Y.Lang.isNull(v);
- }
- },
-
- /**
- * Stores the active handle element during the resize.
- *
- * @attribute activeHandleNode
- * @default null
- * @private
- * @type Node
- */
- activeHandleNode: {
- value: null,
- validator: isNode
- },
-
- /**
- * False to ensure that the resize handles are always visible, true to
- * display them only when the user mouses over the resizable borders.
- *
- * @attribute autoHide
- * @default false
- * @type boolean
- */
- autoHide: {
- value: false,
- validator: isBoolean
- },
-
- /**
- * The default minimum height of the element. Only used when
- * ResizeConstrained is not plugged.
- *
- * @attribute defMinHeight
- * @default 15
- * @type Number
- */
- defMinHeight: {
- value: 15,
- validator: isNumber
- },
-
- /**
- * The default minimum width of the element. Only used when
- * ResizeConstrained is not plugged.
- *
- * @attribute defMinWidth
- * @default 15
- * @type Number
- */
- defMinWidth: {
- value: 15,
- validator: isNumber
- },
-
- /**
- * The handles to use (any combination of): 't', 'b', 'r', 'l', 'bl',
- * 'br', 'tl', 'tr'. Can use a shortcut of All.
- *
- * @attribute handles
- * @default all
- * @type Array | String
- */
- handles: {
- setter: '_setHandles',
- value: ALL
- },
-
- /**
- * Node to wrap the resize handles.
- *
- * @attribute handlesWrapper
- * @type Node
- */
- handlesWrapper: {
- readOnly: true,
- setter: Y.one,
- valueFn: '_valueHandlesWrapper'
- },
-
- /**
- * The selector or element to resize. Required.
- *
- * @attribute node
- * @type Node
- */
- node: {
- setter: Y.one
- },
-
- /**
- * True when the element is being Resized.
- *
- * @attribute resizing
- * @default false
- * @type boolean
- */
- resizing: {
- value: false,
- validator: isBoolean
- },
-
- /**
- * True to wrap an element with a div if needed (required for textareas
- * and images, defaults to false) in favor of the handles config option.
- * The wrapper element type (default div) could be over-riden passing the
- * <code>wrapper</code> attribute.
- *
- * @attribute wrap
- * @default false
- * @type boolean
- */
- wrap: {
- setter: '_setWrap',
- value: false,
- validator: isBoolean
- },
-
- /**
- * Elements that requires a wrapper by default. Normally are elements
- * which cannot have children elements.
- *
- * @attribute wrapTypes
- * @default /canvas|textarea|input|select|button|img/i
- * @readOnly
- * @type Regex
- */
- wrapTypes: {
- readOnly: true,
- value: /^canvas|textarea|input|select|button|img|iframe|table|embed$/i
- },
-
- /**
- * Element to wrap the <code>wrapTypes</code>. This element will house
- * the handles elements.
- *
- * @attribute wrapper
- * @default div
- * @type String | Node
- * @writeOnce
- */
- wrapper: {
- readOnly: true,
- valueFn: '_valueWrapper',
- writeOnce: true
- }
- },
-
- RULES: {
- b: function(instance, dx, dy) {
- var info = instance.info,
- originalInfo = instance.originalInfo;
-
- info.offsetHeight = originalInfo.offsetHeight + dy;
- },
-
- l: function(instance, dx) {
- var info = instance.info,
- originalInfo = instance.originalInfo;
-
- info.left = originalInfo.left + dx;
- info.offsetWidth = originalInfo.offsetWidth - dx;
- },
-
- r: function(instance, dx) {
- var info = instance.info,
- originalInfo = instance.originalInfo;
-
- info.offsetWidth = originalInfo.offsetWidth + dx;
- },
-
- t: function(instance, dx, dy) {
- var info = instance.info,
- originalInfo = instance.originalInfo;
-
- info.top = originalInfo.top + dy;
- info.offsetHeight = originalInfo.offsetHeight - dy;
- },
-
- tr: function() {
- this.t.apply(this, arguments);
- this.r.apply(this, arguments);
- },
-
- bl: function() {
- this.b.apply(this, arguments);
- this.l.apply(this, arguments);
- },
-
- br: function() {
- this.b.apply(this, arguments);
- this.r.apply(this, arguments);
- },
-
- tl: function() {
- this.t.apply(this, arguments);
- this.l.apply(this, arguments);
- }
- },
-
- capitalize: capitalize
- });
-
- Y.Resize = Y.extend(
- Resize,
- Y.Base,
- {
- /**
- * Array containing all possible resizable handles.
- *
- * @property ALL_HANDLES
- * @type {String}
- */
- ALL_HANDLES: [ T, TR, R, BR, B, BL, L, TL ],
-
- /**
- * Regex which matches with the handles that could change the height of
- * the resizable element.
- *
- * @property REGEX_CHANGE_HEIGHT
- * @type {String}
- */
- REGEX_CHANGE_HEIGHT: /^(t|tr|b|bl|br|tl)$/i,
-
- /**
- * Regex which matches with the handles that could change the left of
- * the resizable element.
- *
- * @property REGEX_CHANGE_LEFT
- * @type {String}
- */
- REGEX_CHANGE_LEFT: /^(tl|l|bl)$/i,
-
- /**
- * Regex which matches with the handles that could change the top of
- * the resizable element.
- *
- * @property REGEX_CHANGE_TOP
- * @type {String}
- */
- REGEX_CHANGE_TOP: /^(tl|t|tr)$/i,
-
- /**
- * Regex which matches with the handles that could change the width of
- * the resizable element.
- *
- * @property REGEX_CHANGE_WIDTH
- * @type {String}
- */
- REGEX_CHANGE_WIDTH: /^(bl|br|l|r|tl|tr)$/i,
-
- /**
- * Template used to create the resize wrapper for the handles.
- *
- * @property HANDLES_WRAP_TEMPLATE
- * @type {String}
- */
- HANDLES_WRAP_TEMPLATE: '<div class="'+CSS_RESIZE_HANDLES_WRAPPER+'"></div>',
-
- /**
- * Template used to create the resize wrapper node when needed.
- *
- * @property WRAP_TEMPLATE
- * @type {String}
- */
- WRAP_TEMPLATE: '<div class="'+CSS_RESIZE_WRAPPER+'"></div>',
-
- /**
- * Template used to create each resize handle.
- *
- * @property HANDLE_TEMPLATE
- * @type {String}
- */
- HANDLE_TEMPLATE: '<div class="'+concat(CSS_RESIZE_HANDLE, CSS_RESIZE_HANDLE_PLACEHOLDER)+'">' +
- '<div class="'+concat(CSS_RESIZE_HANDLE_INNER, CSS_RESIZE_HANDLE_INNER_PLACEHOLDER)+'"> </div>' +
- '</div>',
-
-
- /**
- * Each box has a content area and optional surrounding padding and
- * border areas. This property stores the sum of all horizontal
- * surrounding * information needed to adjust the node height.
- *
- * @property totalHSurrounding
- * @default 0
- * @type number
- */
- totalHSurrounding: 0,
-
- /**
- * Each box has a content area and optional surrounding padding and
- * border areas. This property stores the sum of all vertical
- * surrounding * information needed to adjust the node height.
- *
- * @property totalVSurrounding
- * @default 0
- * @type number
- */
- totalVSurrounding: 0,
-
- /**
- * Stores the <a href="Resize.html#attr_node">node</a>
- * surrounding information retrieved from
- * <a href="Resize.html#method__getBoxSurroundingInfo">_getBoxSurroundingInfo</a>.
- *
- * @property nodeSurrounding
- * @type Object
- * @default null
- */
- nodeSurrounding: null,
-
- /**
- * Stores the <a href="Resize.html#attr_wrapper">wrapper</a>
- * surrounding information retrieved from
- * <a href="Resize.html#method__getBoxSurroundingInfo">_getBoxSurroundingInfo</a>.
- *
- * @property wrapperSurrounding
- * @type Object
- * @default null
- */
- wrapperSurrounding: null,
-
- /**
- * Whether the handle being dragged can change the height.
- *
- * @property changeHeightHandles
- * @default false
- * @type boolean
- */
- changeHeightHandles: false,
-
- /**
- * Whether the handle being dragged can change the left.
- *
- * @property changeLeftHandles
- * @default false
- * @type boolean
- */
- changeLeftHandles: false,
-
- /**
- * Whether the handle being dragged can change the top.
- *
- * @property changeTopHandles
- * @default false
- * @type boolean
- */
- changeTopHandles: false,
-
- /**
- * Whether the handle being dragged can change the width.
- *
- * @property changeWidthHandles
- * @default false
- * @type boolean
- */
- changeWidthHandles: false,
-
- /**
- * Store DD.Delegate reference for the respective Resize instance.
- *
- * @property delegate
- * @default null
- * @type Object
- */
- delegate: null,
-
- /**
- * Stores the current values for the height, width, top and left. You are
- * able to manipulate these values on resize in order to change the resize
- * behavior.
- *
- * @property info
- * @type Object
- * @protected
- */
- info: null,
-
- /**
- * Stores the last values for the height, width, top and left.
- *
- * @property lastInfo
- * @type Object
- * @protected
- */
- lastInfo: null,
-
- /**
- * Stores the original values for the height, width, top and left, stored
- * on resize start.
- *
- * @property originalInfo
- * @type Object
- * @protected
- */
- originalInfo: null,
-
- /**
- * Construction logic executed during Resize instantiation. Lifecycle.
- *
- * @method initializer
- * @protected
- */
- initializer: function() {
- this._eventHandles = [];
-
- this.renderer();
- },
-
- /**
- * Create the DOM structure for the Resize. Lifecycle.
- *
- * @method renderUI
- * @protected
- */
- renderUI: function() {
- var instance = this;
-
- instance._renderHandles();
- },
-
- /**
- * Bind the events on the Resize UI. Lifecycle.
- *
- * @method bindUI
- * @protected
- */
- bindUI: function() {
- var instance = this;
-
- instance._createEvents();
- instance._bindDD();
- instance._bindHandle();
- },
-
- /**
- * Sync the Resize UI.
- *
- * @method syncUI
- * @protected
- */
- syncUI: function() {
- var instance = this;
-
- this.get(NODE).addClass(CSS_RESIZE);
-
- // hide handles if AUTO_HIDE is true
- instance._setHideHandlesUI(
- instance.get(AUTO_HIDE)
- );
- },
-
- /**
- * Destructor lifecycle implementation for the Resize class.
- * Detaches all previously attached listeners and removes the Resize handles.
- *
- * @method destructor
- * @protected
- */
- destructor: function() {
- var instance = this,
- node = instance.get(NODE),
- wrapper = instance.get(WRAPPER),
- pNode = wrapper.get(PARENT_NODE);
-
- Y.each(
- instance._eventHandles,
- function(handle) {
- handle.detach();
- }
- );
-
- instance._eventHandles.length = 0;
-
- // destroy handles dd and remove them from the dom
- instance.eachHandle(function(handleEl) {
- instance.delegate.dd.destroy();
-
- // remove handle
- handleEl.remove(true);
- });
-
- instance.delegate.destroy();
-
- // unwrap node
- if (instance.get(WRAP)) {
- instance._copyStyles(wrapper, node);
-
- if (pNode) {
- pNode.insertBefore(node, wrapper);
- }
-
- wrapper.remove(true);
- }
-
- node.removeClass(CSS_RESIZE);
- node.removeClass(CSS_RESIZE_HIDDEN_HANDLES);
- },
-
- /**
- * Creates DOM (or manipulates DOM for progressive enhancement)
- * This method is invoked by initializer(). It's chained automatically for
- * subclasses if required.
- *
- * @method renderer
- * @protected
- */
- renderer: function() {
- this.renderUI();
- this.bindUI();
- this.syncUI();
- },
-
- /**
- * <p>Loop through each handle which is being used and executes a callback.</p>
- * <p>Example:</p>
- * <pre><code>instance.eachHandle(
- * function(handleName, index) { ... }
- * );</code></pre>
- *
- * @method eachHandle
- * @param {function} fn Callback function to be executed for each handle.
- */
- eachHandle: function(fn) {
- var instance = this;
-
- Y.each(
- instance.get(HANDLES),
- function(handle, i) {
- var handleEl = instance.get(
- handleAttrName(handle)
- );
-
- fn.apply(instance, [handleEl, handle, i]);
- }
- );
- },
-
- /**
- * Bind the handles DragDrop events to the Resize instance.
- *
- * @method _bindDD
- * @private
- */
- _bindDD: function() {
- var instance = this;
-
- instance.delegate = new Y.DD.Delegate(
- {
- bubbleTargets: instance,
- container: instance.get(HANDLES_WRAPPER),
- dragConfig: {
- clickPixelThresh: 0,
- clickTimeThresh: 0,
- useShim: true,
- move: false
- },
- nodes: DOT+CSS_RESIZE_HANDLE,
- target: false
- }
- );
-
- instance._eventHandles.push(
- instance.on('drag:drag', instance._handleResizeEvent),
- instance.on('drag:dropmiss', instance._handleMouseUpEvent),
- instance.on('drag:end', instance._handleResizeEndEvent),
- instance.on('drag:start', instance._handleResizeStartEvent)
- );
- },
-
- /**
- * Bind the events related to the handles (_onHandleMouseEnter, _onHandleMouseLeave).
- *
- * @method _bindHandle
- * @private
- */
- _bindHandle: function() {
- var instance = this,
- wrapper = instance.get(WRAPPER);
-
- instance._eventHandles.push(
- wrapper.on('mouseenter', Y.bind(instance._onWrapperMouseEnter, instance)),
- wrapper.on('mouseleave', Y.bind(instance._onWrapperMouseLeave, instance)),
- wrapper.delegate('mouseenter', Y.bind(instance._onHandleMouseEnter, instance), DOT+CSS_RESIZE_HANDLE),
- wrapper.delegate('mouseleave', Y.bind(instance._onHandleMouseLeave, instance), DOT+CSS_RESIZE_HANDLE)
- );
- },
-
- /**
- * Create the custom events used on the Resize.
- *
- * @method _createEvents
- * @private
- */
- _createEvents: function() {
- var instance = this,
- // create publish function for kweight optimization
- publish = function(name, fn) {
- instance.publish(name, {
- defaultFn: fn,
- queuable: false,
- emitFacade: true,
- bubbles: true,
- prefix: RESIZE
- });
- };
-
- /**
- * Handles the resize start event. Fired when a handle starts to be
- * dragged.
- *
- * @event resize:start
- * @preventable _defResizeStartFn
- * @param {EventFacade} event The resize start event.
- * @bubbles Resize
- */
- publish(EV_RESIZE_START, this._defResizeStartFn);
-
- /**
- * Handles the resize event. Fired on each pixel when the handle is
- * being dragged.
- *
- * @event resize:resize
- * @preventable _defResizeFn
- * @param {EventFacade} event The resize event.
- * @bubbles Resize
- */
- publish(EV_RESIZE, this._defResizeFn);
-
- /**
- * Handles the resize align event.
- *
- * @event resize:align
- * @preventable _defResizeAlignFn
- * @param {EventFacade} event The resize align event.
- * @bubbles Resize
- */
- publish(EV_RESIZE_ALIGN, this._defResizeAlignFn);
-
- /**
- * Handles the resize end event. Fired when a handle stop to be
- * dragged.
- *
- * @event resize:end
- * @preventable _defResizeEndFn
- * @param {EventFacade} event The resize end event.
- * @bubbles Resize
- */
- publish(EV_RESIZE_END, this._defResizeEndFn);
-
- /**
- * Handles the resize mouseUp event. Fired when a mouseUp event happens on a
- * handle.
- *
- * @event resize:mouseUp
- * @preventable _defMouseUpFn
- * @param {EventFacade} event The resize mouseUp event.
- * @bubbles Resize
- */
- publish(EV_MOUSE_UP, this._defMouseUpFn);
- },
-
- /**
- * Responsible for loop each handle element and append to the wrapper.
- *
- * @method _renderHandles
- * @protected
- */
- _renderHandles: function() {
- var instance = this,
- wrapper = instance.get(WRAPPER),
- handlesWrapper = instance.get(HANDLES_WRAPPER);
-
- instance.eachHandle(function(handleEl) {
- handlesWrapper.append(handleEl);
- });
-
- wrapper.append(handlesWrapper);
- },
-
- /**
- * Creates the handle element based on the handle name and initialize the
- * DragDrop on it.
- *
- * @method _buildHandle
- * @param {String} handle Handle name ('t', 'tr', 'b', ...).
- * @protected
- */
- _buildHandle: function(handle) {
- var instance = this;
-
- return Y.Node.create(
- Y.Lang.sub(instance.HANDLE_TEMPLATE, {
- handle: handle
- })
- );
- },
-
- /**
- * Basic resize calculations.
- *
- * @method _calcResize
- * @protected
- */
- _calcResize: function() {
- var instance = this,
- handle = instance.handle,
- info = instance.info,
- originalInfo = instance.originalInfo,
-
- dx = info.actXY[0] - originalInfo.actXY[0],
- dy = info.actXY[1] - originalInfo.actXY[1];
-
- if (handle && Y.Resize.RULES[handle]) {
- Y.Resize.RULES[handle](instance, dx, dy);
- }
- else {
- Y.log('Handle rule not found: ' + handle, 'warn', 'resize');
- }
- },
-
- /**
- * Helper method to update the current size value on
- * <a href="Resize.html#property_info">info</a> to respect the
- * min/max values and fix the top/left calculations.
- *
- * @method _checkSize
- * @param {String} offset 'offsetHeight' or 'offsetWidth'
- * @param {number} size Size to restrict the offset
- * @protected
- */
- _checkSize: function(offset, size) {
- var instance = this,
- info = instance.info,
- originalInfo = instance.originalInfo,
- axis = (offset === OFFSET_HEIGHT) ? TOP : LEFT;
-
- // forcing the offsetHeight/offsetWidth to be the passed size
- info[offset] = size;
-
- // predicting, based on the original information, the last left valid in case of reach the min/max dimension
- // this calculation avoid browser event leaks when user interact very fast
- if (((axis === LEFT) && instance.changeLeftHandles) ||
- ((axis === TOP) && instance.changeTopHandles)) {
-
- info[axis] = originalInfo[axis] + originalInfo[offset] - size;
- }
- },
-
- /**
- * Copy relevant styles of the <a href="Resize.html#attr_node">node</a>
- * to the <a href="Resize.html#attr_wrapper">wrapper</a>.
- *
- * @method _copyStyles
- * @param {Node} node Node from.
- * @param {Node} wrapper Node to.
- * @protected
- */
- _copyStyles: function(node, wrapper) {
- var position = node.getStyle(POSITION).toLowerCase(),
- surrounding = this._getBoxSurroundingInfo(node),
- wrapperStyle;
-
- // resizable wrapper should be positioned
- if (position === STATIC) {
- position = RELATIVE;
- }
-
- wrapperStyle = {
- position: position,
- left: getCompStyle(node, LEFT),
- top: getCompStyle(node, TOP)
- };
-
- Y.mix(wrapperStyle, surrounding.margin);
- Y.mix(wrapperStyle, surrounding.border);
-
- wrapper.setStyles(wrapperStyle);
-
- // remove margin and border from the internal node
- node.setStyles({ border: 0, margin: 0 });
-
- wrapper.sizeTo(
- node.get(OFFSET_WIDTH) + surrounding.totalHBorder,
- node.get(OFFSET_HEIGHT) + surrounding.totalVBorder
- );
- },
-
- // extract handle name from a string
- // using Y.cached to memoize the function for performance
- _extractHandleName: Y.cached(
- function(node) {
- var className = node.get(CLASS_NAME),
-
- match = className.match(
- new RegExp(
- getCN(RESIZE, HANDLE, '(\\w{1,2})\\b')
- )
- );
-
- return match ? match[1] : null;
- }
- ),
-
- /**
- * <p>Generates metadata to the <a href="Resize.html#property_info">info</a>
- * and <a href="Resize.html#property_originalInfo">originalInfo</a></p>
- * <pre><code>bottom, actXY, left, top, offsetHeight, offsetWidth, right</code></pre>
- *
- * @method _getInfo
- * @param {Node} node
- * @param {EventFacade} event
- * @private
- */
- _getInfo: function(node, event) {
- var actXY = [0,0],
- drag = event.dragEvent.target,
- nodeXY = node.getXY(),
- nodeX = nodeXY[0],
- nodeY = nodeXY[1],
- offsetHeight = node.get(OFFSET_HEIGHT),
- offsetWidth = node.get(OFFSET_WIDTH);
-
- if (event) {
- // the xy that the node will be set to. Changing this will alter the position as it's dragged.
- actXY = (drag.actXY.length ? drag.actXY : drag.lastXY);
- }
-
- return {
- actXY: actXY,
- bottom: (nodeY + offsetHeight),
- left: nodeX,
- offsetHeight: offsetHeight,
- offsetWidth: offsetWidth,
- right: (nodeX + offsetWidth),
- top: nodeY
- };
- },
-
- /**
- * Each box has a content area and optional surrounding margin,
- * padding and * border areas. This method get all this information from
- * the passed node. For more reference see
- * <a href="http://www.w3.org/TR/CSS21/box.html#box-dimensions">
- * http://www.w3.org/TR/CSS21/box.html#box-dimensions</a>.
- *
- * @method _getBoxSurroundingInfo
- * @param {Node} node
- * @private
- * @return {Object}
- */
- _getBoxSurroundingInfo: function(node) {
- var info = {
- padding: {},
- margin: {},
- border: {}
- };
-
- if (isNode(node)) {
- Y.each([ TOP, RIGHT, BOTTOM, LEFT ], function(dir) {
- var paddingProperty = capitalize(PADDING, dir),
- marginProperty = capitalize(MARGIN, dir),
- borderWidthProperty = capitalize(BORDER, dir, WIDTH),
- borderColorProperty = capitalize(BORDER, dir, COLOR),
- borderStyleProperty = capitalize(BORDER, dir, STYLE);
-
- info.border[borderColorProperty] = getCompStyle(node, borderColorProperty);
- info.border[borderStyleProperty] = getCompStyle(node, borderStyleProperty);
- info.border[borderWidthProperty] = getCompStyle(node, borderWidthProperty);
- info.margin[marginProperty] = getCompStyle(node, marginProperty);
- info.padding[paddingProperty] = getCompStyle(node, paddingProperty);
- });
- }
-
- info.totalHBorder = (toRoundNumber(info.border.borderLeftWidth) + toRoundNumber(info.border.borderRightWidth));
- info.totalHPadding = (toRoundNumber(info.padding.paddingLeft) + toRoundNumber(info.padding.paddingRight));
- info.totalVBorder = (toRoundNumber(info.border.borderBottomWidth) + toRoundNumber(info.border.borderTopWidth));
- info.totalVPadding = (toRoundNumber(info.padding.paddingBottom) + toRoundNumber(info.padding.paddingTop));
-
- return info;
- },
-
- /**
- * Sync the Resize UI with internal values from
- * <a href="Resize.html#property_info">info</a>.
- *
- * @method _syncUI
- * @protected
- */
- _syncUI: function() {
- var instance = this,
- info = instance.info,
- wrapperSurrounding = instance.wrapperSurrounding,
- wrapper = instance.get(WRAPPER),
- node = instance.get(NODE);
-
- wrapper.sizeTo(info.offsetWidth, info.offsetHeight);
-
- if (instance.changeLeftHandles || instance.changeTopHandles) {
- wrapper.setXY([info.left, info.top]);
- }
-
- // if a wrap node is being used
- if (!wrapper.compareTo(node)) {
- // the original internal node borders were copied to the wrapper on
- // _copyStyles, to compensate that subtract the borders from the internal node
- node.sizeTo(
- info.offsetWidth - wrapperSurrounding.totalHBorder,
- info.offsetHeight - wrapperSurrounding.totalVBorder
- );
- }
-
- // prevent webkit textarea resize
- if (Y.UA.webkit) {
- node.setStyle(RESIZE, NONE);
- }
- },
-
- /**
- * Update <code>instance.changeHeightHandles,
- * instance.changeLeftHandles, instance.changeTopHandles,
- * instance.changeWidthHandles</code> information.
- *
- * @method _updateChangeHandleInfo
- * @private
- */
- _updateChangeHandleInfo: function(handle) {
- var instance = this;
-
- instance.changeHeightHandles = instance.REGEX_CHANGE_HEIGHT.test(handle);
- instance.changeLeftHandles = instance.REGEX_CHANGE_LEFT.test(handle);
- instance.changeTopHandles = instance.REGEX_CHANGE_TOP.test(handle);
- instance.changeWidthHandles = instance.REGEX_CHANGE_WIDTH.test(handle);
- },
-
- /**
- * Update <a href="Resize.html#property_info">info</a> values (bottom, actXY, left, top, offsetHeight, offsetWidth, right).
- *
- * @method _updateInfo
- * @private
- */
- _updateInfo: function(event) {
- var instance = this;
-
- instance.info = instance._getInfo(instance.get(WRAPPER), event);
- },
-
- /**
- * Update properties
- * <a href="Resize.html#property_nodeSurrounding">nodeSurrounding</a>,
- * <a href="Resize.html#property_nodeSurrounding">wrapperSurrounding</a>,
- * <a href="Resize.html#property_nodeSurrounding">totalVSurrounding</a>,
- * <a href="Resize.html#property_nodeSurrounding">totalHSurrounding</a>.
- *
- * @method _updateSurroundingInfo
- * @private
- */
- _updateSurroundingInfo: function() {
- var instance = this,
- node = instance.get(NODE),
- wrapper = instance.get(WRAPPER),
- nodeSurrounding = instance._getBoxSurroundingInfo(node),
- wrapperSurrounding = instance._getBoxSurroundingInfo(wrapper);
-
- instance.nodeSurrounding = nodeSurrounding;
- instance.wrapperSurrounding = wrapperSurrounding;
-
- instance.totalVSurrounding = (nodeSurrounding.totalVPadding + wrapperSurrounding.totalVBorder);
- instance.totalHSurrounding = (nodeSurrounding.totalHPadding + wrapperSurrounding.totalHBorder);
- },
-
- /**
- * Set the active state of the handles.
- *
- * @method _setActiveHandlesUI
- * @param {boolean} val True to activate the handles, false to deactivate.
- * @protected
- */
- _setActiveHandlesUI: function(val) {
- var instance = this,
- activeHandleNode = instance.get(ACTIVE_HANDLE_NODE);
-
- if (activeHandleNode) {
- if (val) {
- // remove CSS_RESIZE_HANDLE_ACTIVE from all handles before addClass on the active
- instance.eachHandle(
- function(handleEl) {
- handleEl.removeClass(CSS_RESIZE_HANDLE_ACTIVE);
- }
- );
-
- activeHandleNode.addClass(CSS_RESIZE_HANDLE_ACTIVE);
- }
- else {
- activeHandleNode.removeClass(CSS_RESIZE_HANDLE_ACTIVE);
- }
- }
- },
-
- /**
- * Setter for the handles attribute
- *
- * @method _setHandles
- * @protected
- * @param {String} val
- */
- _setHandles: function(val) {
- var instance = this,
- handles = [];
-
- // handles attr accepts both array or string
- if (isArray(val)) {
- handles = val;
- }
- else if (isString(val)) {
- // if the handles attr passed in is an ALL string...
- if (val.toLowerCase() === ALL) {
- handles = instance.ALL_HANDLES;
- }
- // otherwise, split the string to extract the handles
- else {
- Y.each(
- val.split(COMMA),
- function(node) {
- var handle = trim(node);
-
- // if its a valid handle, add it to the handles output
- if (indexOf(instance.ALL_HANDLES, handle) > -1) {
- handles.push(handle);
- }
- }
- );
- }
- }
-
- return handles;
- },
-
- /**
- * Set the visibility of the handles.
- *
- * @method _setHideHandlesUI
- * @param {boolean} val True to hide the handles, false to show.
- * @protected
- */
- _setHideHandlesUI: function(val) {
- var instance = this,
- wrapper = instance.get(WRAPPER);
-
- if (!instance.get(RESIZING)) {
- if (val) {
- wrapper.addClass(CSS_RESIZE_HIDDEN_HANDLES);
- }
- else {
- wrapper.removeClass(CSS_RESIZE_HIDDEN_HANDLES);
- }
- }
- },
-
- /**
- * Setter for the wrap attribute
- *
- * @method _setWrap
- * @protected
- * @param {boolean} val
- */
- _setWrap: function(val) {
- var instance = this,
- node = instance.get(NODE),
- nodeName = node.get(NODE_NAME),
- typeRegex = instance.get(WRAP_TYPES);
-
- // if nodeName is listed on WRAP_TYPES force use the wrapper
- if (typeRegex.test(nodeName)) {
- val = true;
- }
-
- return val;
- },
-
- /**
- * Default resize:mouseUp handler
- *
- * @method _defMouseUpFn
- * @param {EventFacade} event The Event object
- * @protected
- */
- _defMouseUpFn: function() {
- var instance = this;
-
- instance.set(RESIZING, false);
- },
-
- /**
- * Default resize:resize handler
- *
- * @method _defResizeFn
- * @param {EventFacade} event The Event object
- * @protected
- */
- _defResizeFn: function(event) {
- var instance = this;
-
- instance._resize(event);
- },
-
- /**
- * Logic method for _defResizeFn. Allow AOP.
- *
- * @method _resize
- * @param {EventFacade} event The Event object
- * @protected
- */
- _resize: function(event) {
- var instance = this;
-
- instance._handleResizeAlignEvent(event.dragEvent);
-
- // _syncUI of the wrapper, not using proxy
- instance._syncUI();
- },
-
- /**
- * Default resize:align handler
- *
- * @method _defResizeAlignFn
- * @param {EventFacade} event The Event object
- * @protected
- */
- _defResizeAlignFn: function(event) {
- var instance = this;
-
- instance._resizeAlign(event);
- },
-
- /**
- * Logic method for _defResizeAlignFn. Allow AOP.
- *
- * @method _resizeAlign
- * @param {EventFacade} event The Event object
- * @protected
- */
- _resizeAlign: function(event) {
- var instance = this,
- info,
- defMinHeight,
- defMinWidth;
-
- instance.lastInfo = instance.info;
-
- // update the instance.info values
- instance._updateInfo(event);
-
- info = instance.info;
-
- // basic resize calculations
- instance._calcResize();
-
- // if Y.Plugin.ResizeConstrained is not plugged, check for min dimension
- if (!instance.con) {
- defMinHeight = (instance.get(DEF_MIN_HEIGHT) + instance.totalVSurrounding);
- defMinWidth = (instance.get(DEF_MIN_WIDTH) + instance.totalHSurrounding);
-
- if (info.offsetHeight <= defMinHeight) {
- instance._checkSize(OFFSET_HEIGHT, defMinHeight);
- }
-
- if (info.offsetWidth <= defMinWidth) {
- instance._checkSize(OFFSET_WIDTH, defMinWidth);
- }
- }
- },
-
- /**
- * Default resize:end handler
- *
- * @method _defResizeEndFn
- * @param {EventFacade} event The Event object
- * @protected
- */
- _defResizeEndFn: function(event) {
- var instance = this;
-
- instance._resizeEnd(event);
- },
-
- /**
- * Logic method for _defResizeEndFn. Allow AOP.
- *
- * @method _resizeEnd
- * @param {EventFacade} event The Event object
- * @protected
- */
- _resizeEnd: function(event) {
- var instance = this,
- drag = event.dragEvent.target;
-
- // reseting actXY from drag when drag end
- drag.actXY = [];
-
- // syncUI when resize end
- instance._syncUI();
-
- instance._setActiveHandlesUI(false);
-
- instance.set(ACTIVE_HANDLE, null);
- instance.set(ACTIVE_HANDLE_NODE, null);
-
- instance.handle = null;
- },
-
- /**
- * Default resize:start handler
- *
- * @method _defResizeStartFn
- * @param {EventFacade} event The Event object
- * @protected
- */
- _defResizeStartFn: function(event) {
- var instance = this;
-
- instance._resizeStart(event);
- },
-
- /**
- * Logic method for _defResizeStartFn. Allow AOP.
- *
- * @method _resizeStart
- * @param {EventFacade} event The Event object
- * @protected
- */
- _resizeStart: function(event) {
- var instance = this,
- wrapper = instance.get(WRAPPER);
-
- instance.handle = instance.get(ACTIVE_HANDLE);
-
- instance.set(RESIZING, true);
-
- instance._updateSurroundingInfo();
-
- // create an originalInfo information for reference
- instance.originalInfo = instance._getInfo(wrapper, event);
-
- instance._updateInfo(event);
- },
-
- /**
- * Fires the resize:mouseUp event.
- *
- * @method _handleMouseUpEvent
- * @param {EventFacade} event resize:mouseUp event facade
- * @protected
- */
- _handleMouseUpEvent: function(event) {
- this.fire(EV_MOUSE_UP, { dragEvent: event, info: this.info });
- },
-
- /**
- * Fires the resize:resize event.
- *
- * @method _handleResizeEvent
- * @param {EventFacade} event resize:resize event facade
- * @protected
- */
- _handleResizeEvent: function(event) {
- this.fire(EV_RESIZE, { dragEvent: event, info: this.info });
- },
-
- /**
- * Fires the resize:align event.
- *
- * @method _handleResizeAlignEvent
- * @param {EventFacade} event resize:resize event facade
- * @protected
- */
- _handleResizeAlignEvent: function(event) {
- this.fire(EV_RESIZE_ALIGN, { dragEvent: event, info: this.info });
- },
-
- /**
- * Fires the resize:end event.
- *
- * @method _handleResizeEndEvent
- * @param {EventFacade} event resize:end event facade
- * @protected
- */
- _handleResizeEndEvent: function(event) {
- this.fire(EV_RESIZE_END, { dragEvent: event, info: this.info });
- },
-
- /**
- * Fires the resize:start event.
- *
- * @method _handleResizeStartEvent
- * @param {EventFacade} event resize:start event facade
- * @protected
- */
- _handleResizeStartEvent: function(event) {
- if (!this.get(ACTIVE_HANDLE)) {
- //This handles the "touch" case
- this._setHandleFromNode(event.target.get('node'));
- }
- this.fire(EV_RESIZE_START, { dragEvent: event, info: this.info });
- },
-
- /**
- * Mouseenter event handler for the <a href="Resize.html#attr_wrapper">wrapper</a>.
- *
- * @method _onWrapperMouseEnter
- * @param {EventFacade} event
- * @protected
- */
- _onWrapperMouseEnter: function() {
- var instance = this;
-
- if (instance.get(AUTO_HIDE)) {
- instance._setHideHandlesUI(false);
- }
- },
-
- /**
- * Mouseleave event handler for the <a href="Resize.html#attr_wrapper">wrapper</a>.
- *
- * @method _onWrapperMouseLeave
- * @param {EventFacade} event
- * @protected
- */
- _onWrapperMouseLeave: function() {
- var instance = this;
-
- if (instance.get(AUTO_HIDE)) {
- instance._setHideHandlesUI(true);
- }
- },
-
- /**
- * Handles setting the activeHandle from a node, used from startDrag (for touch) and mouseenter (for mouse).
- *
- * @method _setHandleFromNode
- * @param {Node} node
- * @protected
- */
- _setHandleFromNode: function(node) {
- var instance = this,
- handle = instance._extractHandleName(node);
-
- if (!instance.get(RESIZING)) {
- instance.set(ACTIVE_HANDLE, handle);
- instance.set(ACTIVE_HANDLE_NODE, node);
-
- instance._setActiveHandlesUI(true);
- instance._updateChangeHandleInfo(handle);
- }
- },
-
- /**
- * Mouseenter event handler for the handles.
- *
- * @method _onHandleMouseEnter
- * @param {EventFacade} event
- * @protected
- */
- _onHandleMouseEnter: function(event) {
- this._setHandleFromNode(event.currentTarget);
- },
-
- /**
- * Mouseout event handler for the handles.
- *
- * @method _onHandleMouseLeave
- * @param {EventFacade} event
- * @protected
- */
- _onHandleMouseLeave: function() {
- var instance = this;
-
- if (!instance.get(RESIZING)) {
- instance._setActiveHandlesUI(false);
- }
- },
-
- /**
- * Default value for the wrapper handles node attribute
- *
- * @method _valueHandlesWrapper
- * @protected
- * @readOnly
- */
- _valueHandlesWrapper: function() {
- return Y.Node.create(this.HANDLES_WRAP_TEMPLATE);
- },
-
- /**
- * Default value for the wrapper attribute
- *
- * @method _valueWrapper
- * @protected
- * @readOnly
- */
- _valueWrapper: function() {
- var instance = this,
- node = instance.get(NODE),
- pNode = node.get(PARENT_NODE),
- // by deafult the wrapper is always the node
- wrapper = node;
-
- // if the node is listed on the wrapTypes or wrap is set to true, create another wrapper
- if (instance.get(WRAP)) {
- wrapper = Y.Node.create(instance.WRAP_TEMPLATE);
-
- if (pNode) {
- pNode.insertBefore(wrapper, node);
- }
-
- wrapper.append(node);
-
- instance._copyStyles(node, wrapper);
-
- // remove positioning of wrapped node, the WRAPPER take care about positioning
- node.setStyles({
- position: STATIC,
- left: 0,
- top: 0
- });
- }
-
- return wrapper;
- }
- }
- );
-
- Y.each(Y.Resize.prototype.ALL_HANDLES, function(handle) {
- // creating ATTRS with the handles elements
- Y.Resize.ATTRS[handleAttrName(handle)] = {
- setter: function() {
- return this._buildHandle(handle);
- },
- value: null,
- writeOnce: true
- };
- });
-
-