Version 3.18.1
Show:

File: resize/js/resize-base.js

  1. /**
  2. * The Resize Utility allows you to make an HTML element resizable.
  3. * @module resize
  4. * @main resize
  5. */
  6. var Lang = Y.Lang,
  7. isArray = Lang.isArray,
  8. isBoolean = Lang.isBoolean,
  9. isNumber = Lang.isNumber,
  10. isString = Lang.isString,
  11. yArray = Y.Array,
  12. trim = Lang.trim,
  13. indexOf = yArray.indexOf,
  14. COMMA = ',',
  15. DOT = '.',
  16. EMPTY_STR = '',
  17. HANDLE_SUB = '{handle}',
  18. SPACE = ' ',
  19. ACTIVE = 'active',
  20. ACTIVE_HANDLE = 'activeHandle',
  21. ACTIVE_HANDLE_NODE = 'activeHandleNode',
  22. ALL = 'all',
  23. AUTO_HIDE = 'autoHide',
  24. BORDER = 'border',
  25. BOTTOM = 'bottom',
  26. CLASS_NAME = 'className',
  27. COLOR = 'color',
  28. DEF_MIN_HEIGHT = 'defMinHeight',
  29. DEF_MIN_WIDTH = 'defMinWidth',
  30. HANDLE = 'handle',
  31. HANDLES = 'handles',
  32. HANDLES_WRAPPER = 'handlesWrapper',
  33. HIDDEN = 'hidden',
  34. INNER = 'inner',
  35. LEFT = 'left',
  36. MARGIN = 'margin',
  37. NODE = 'node',
  38. NODE_NAME = 'nodeName',
  39. NONE = 'none',
  40. OFFSET_HEIGHT = 'offsetHeight',
  41. OFFSET_WIDTH = 'offsetWidth',
  42. PADDING = 'padding',
  43. PARENT_NODE = 'parentNode',
  44. POSITION = 'position',
  45. RELATIVE = 'relative',
  46. RESIZE = 'resize',
  47. RESIZING = 'resizing',
  48. RIGHT = 'right',
  49. STATIC = 'static',
  50. STYLE = 'style',
  51. TOP = 'top',
  52. WIDTH = 'width',
  53. WRAP = 'wrap',
  54. WRAPPER = 'wrapper',
  55. WRAP_TYPES = 'wrapTypes',
  56. EV_MOUSE_UP = 'resize:mouseUp',
  57. EV_RESIZE = 'resize:resize',
  58. EV_RESIZE_ALIGN = 'resize:align',
  59. EV_RESIZE_END = 'resize:end',
  60. EV_RESIZE_START = 'resize:start',
  61. T = 't',
  62. TR = 'tr',
  63. R = 'r',
  64. BR = 'br',
  65. B = 'b',
  66. BL = 'bl',
  67. L = 'l',
  68. TL = 'tl',
  69. concat = function() {
  70. return Array.prototype.slice.call(arguments).join(SPACE);
  71. },
  72. // round the passed number to get rid of pixel-flickering
  73. toRoundNumber = function(num) {
  74. return Math.round(parseFloat(num)) || 0;
  75. },
  76. getCompStyle = function(node, val) {
  77. return node.getComputedStyle(val);
  78. },
  79. handleAttrName = function(handle) {
  80. return HANDLE + handle.toUpperCase();
  81. },
  82. isNode = function(v) {
  83. return (v instanceof Y.Node);
  84. },
  85. toInitialCap = Y.cached(
  86. function(str) {
  87. return str.substring(0, 1).toUpperCase() + str.substring(1);
  88. }
  89. ),
  90. capitalize = Y.cached(function() {
  91. var out = [],
  92. args = yArray(arguments, 0, true);
  93. yArray.each(args, function(part, i) {
  94. if (i > 0) {
  95. part = toInitialCap(part);
  96. }
  97. out.push(part);
  98. });
  99. return out.join(EMPTY_STR);
  100. }),
  101. getCN = Y.ClassNameManager.getClassName,
  102. CSS_RESIZE = getCN(RESIZE),
  103. CSS_RESIZE_HANDLE = getCN(RESIZE, HANDLE),
  104. CSS_RESIZE_HANDLE_ACTIVE = getCN(RESIZE, HANDLE, ACTIVE),
  105. CSS_RESIZE_HANDLE_INNER = getCN(RESIZE, HANDLE, INNER),
  106. CSS_RESIZE_HANDLE_INNER_PLACEHOLDER = getCN(RESIZE, HANDLE, INNER, HANDLE_SUB),
  107. CSS_RESIZE_HANDLE_PLACEHOLDER = getCN(RESIZE, HANDLE, HANDLE_SUB),
  108. CSS_RESIZE_HIDDEN_HANDLES = getCN(RESIZE, HIDDEN, HANDLES),
  109. CSS_RESIZE_HANDLES_WRAPPER = getCN(RESIZE, HANDLES, WRAPPER),
  110. CSS_RESIZE_WRAPPER = getCN(RESIZE, WRAPPER);
  111. /**
  112. A base class for Resize, providing:
  113. * Basic Lifecycle (initializer, renderUI, bindUI, syncUI, destructor)
  114. * Applies drag handles to an element to make it resizable
  115. * Here is the list of valid resize handles:
  116. `[ 't', 'tr', 'r', 'br', 'b', 'bl', 'l', 'tl' ]`. You can
  117. read this list as top, top-right, right, bottom-right, bottom,
  118. bottom-left, left, top-left.
  119. * The drag handles are inserted into the element and positioned
  120. absolute. Some elements, such as a textarea or image, don't support
  121. children. To overcome that, set wrap:true in your config and the
  122. element willbe wrapped for you automatically.
  123. Quick Example:
  124. var instance = new Y.Resize({
  125. node: '#resize1',
  126. preserveRatio: true,
  127. wrap: true,
  128. maxHeight: 170,
  129. maxWidth: 400,
  130. handles: 't, tr, r, br, b, bl, l, tl'
  131. });
  132. Check the list of <a href="Resize.html#attrs">Configuration Attributes</a> available for
  133. Resize.
  134. @class Resize
  135. @param config {Object} Object literal specifying widget configuration properties.
  136. @constructor
  137. @extends Base
  138. */
  139. function Resize() {
  140. Resize.superclass.constructor.apply(this, arguments);
  141. }
  142. Y.mix(Resize, {
  143. /**
  144. * Static property provides a string to identify the class.
  145. *
  146. * @property NAME
  147. * @type String
  148. * @static
  149. */
  150. NAME: RESIZE,
  151. /**
  152. * Static property used to define the default attribute
  153. * configuration for the Resize.
  154. *
  155. * @property ATTRS
  156. * @type Object
  157. * @static
  158. */
  159. ATTRS: {
  160. /**
  161. * Stores the active handle during the resize.
  162. *
  163. * @attribute activeHandle
  164. * @default null
  165. * @private
  166. * @type String
  167. */
  168. activeHandle: {
  169. value: null,
  170. validator: function(v) {
  171. return Y.Lang.isString(v) || Y.Lang.isNull(v);
  172. }
  173. },
  174. /**
  175. * Stores the active handle element during the resize.
  176. *
  177. * @attribute activeHandleNode
  178. * @default null
  179. * @private
  180. * @type Node
  181. */
  182. activeHandleNode: {
  183. value: null,
  184. validator: isNode
  185. },
  186. /**
  187. * False to ensure that the resize handles are always visible, true to
  188. * display them only when the user mouses over the resizable borders.
  189. *
  190. * @attribute autoHide
  191. * @default false
  192. * @type boolean
  193. */
  194. autoHide: {
  195. value: false,
  196. validator: isBoolean
  197. },
  198. /**
  199. * The default minimum height of the element. Only used when
  200. * ResizeConstrained is not plugged.
  201. *
  202. * @attribute defMinHeight
  203. * @default 15
  204. * @type Number
  205. */
  206. defMinHeight: {
  207. value: 15,
  208. validator: isNumber
  209. },
  210. /**
  211. * The default minimum width of the element. Only used when
  212. * ResizeConstrained is not plugged.
  213. *
  214. * @attribute defMinWidth
  215. * @default 15
  216. * @type Number
  217. */
  218. defMinWidth: {
  219. value: 15,
  220. validator: isNumber
  221. },
  222. /**
  223. * The handles to use (any combination of): 't', 'b', 'r', 'l', 'bl',
  224. * 'br', 'tl', 'tr'. Can use a shortcut of All.
  225. *
  226. * @attribute handles
  227. * @default all
  228. * @type Array | String
  229. */
  230. handles: {
  231. setter: '_setHandles',
  232. value: ALL
  233. },
  234. /**
  235. * Node to wrap the resize handles.
  236. *
  237. * @attribute handlesWrapper
  238. * @type Node
  239. */
  240. handlesWrapper: {
  241. readOnly: true,
  242. setter: Y.one,
  243. valueFn: '_valueHandlesWrapper'
  244. },
  245. /**
  246. * The selector or element to resize. Required.
  247. *
  248. * @attribute node
  249. * @type Node
  250. */
  251. node: {
  252. setter: Y.one
  253. },
  254. /**
  255. * True when the element is being Resized.
  256. *
  257. * @attribute resizing
  258. * @default false
  259. * @type boolean
  260. */
  261. resizing: {
  262. value: false,
  263. validator: isBoolean
  264. },
  265. /**
  266. * True to wrap an element with a div if needed (required for textareas
  267. * and images, defaults to false) in favor of the handles config option.
  268. * The wrapper element type (default div) could be over-riden passing the
  269. * <code>wrapper</code> attribute.
  270. *
  271. * @attribute wrap
  272. * @default false
  273. * @type boolean
  274. */
  275. wrap: {
  276. setter: '_setWrap',
  277. value: false,
  278. validator: isBoolean
  279. },
  280. /**
  281. * Elements that requires a wrapper by default. Normally are elements
  282. * which cannot have children elements.
  283. *
  284. * @attribute wrapTypes
  285. * @default /canvas|textarea|input|select|button|img/i
  286. * @readOnly
  287. * @type Regex
  288. */
  289. wrapTypes: {
  290. readOnly: true,
  291. value: /^canvas|textarea|input|select|button|img|iframe|table|embed$/i
  292. },
  293. /**
  294. * Element to wrap the <code>wrapTypes</code>. This element will house
  295. * the handles elements.
  296. *
  297. * @attribute wrapper
  298. * @default div
  299. * @type String | Node
  300. * @writeOnce
  301. */
  302. wrapper: {
  303. readOnly: true,
  304. valueFn: '_valueWrapper',
  305. writeOnce: true
  306. }
  307. },
  308. RULES: {
  309. b: function(instance, dx, dy) {
  310. var info = instance.info,
  311. originalInfo = instance.originalInfo;
  312. info.offsetHeight = originalInfo.offsetHeight + dy;
  313. },
  314. l: function(instance, dx) {
  315. var info = instance.info,
  316. originalInfo = instance.originalInfo;
  317. info.left = originalInfo.left + dx;
  318. info.offsetWidth = originalInfo.offsetWidth - dx;
  319. },
  320. r: function(instance, dx) {
  321. var info = instance.info,
  322. originalInfo = instance.originalInfo;
  323. info.offsetWidth = originalInfo.offsetWidth + dx;
  324. },
  325. t: function(instance, dx, dy) {
  326. var info = instance.info,
  327. originalInfo = instance.originalInfo;
  328. info.top = originalInfo.top + dy;
  329. info.offsetHeight = originalInfo.offsetHeight - dy;
  330. },
  331. tr: function() {
  332. this.t.apply(this, arguments);
  333. this.r.apply(this, arguments);
  334. },
  335. bl: function() {
  336. this.b.apply(this, arguments);
  337. this.l.apply(this, arguments);
  338. },
  339. br: function() {
  340. this.b.apply(this, arguments);
  341. this.r.apply(this, arguments);
  342. },
  343. tl: function() {
  344. this.t.apply(this, arguments);
  345. this.l.apply(this, arguments);
  346. }
  347. },
  348. capitalize: capitalize
  349. });
  350. Y.Resize = Y.extend(
  351. Resize,
  352. Y.Base,
  353. {
  354. /**
  355. * Array containing all possible resizable handles.
  356. *
  357. * @property ALL_HANDLES
  358. * @type {String}
  359. */
  360. ALL_HANDLES: [ T, TR, R, BR, B, BL, L, TL ],
  361. /**
  362. * Regex which matches with the handles that could change the height of
  363. * the resizable element.
  364. *
  365. * @property REGEX_CHANGE_HEIGHT
  366. * @type {String}
  367. */
  368. REGEX_CHANGE_HEIGHT: /^(t|tr|b|bl|br|tl)$/i,
  369. /**
  370. * Regex which matches with the handles that could change the left of
  371. * the resizable element.
  372. *
  373. * @property REGEX_CHANGE_LEFT
  374. * @type {String}
  375. */
  376. REGEX_CHANGE_LEFT: /^(tl|l|bl)$/i,
  377. /**
  378. * Regex which matches with the handles that could change the top of
  379. * the resizable element.
  380. *
  381. * @property REGEX_CHANGE_TOP
  382. * @type {String}
  383. */
  384. REGEX_CHANGE_TOP: /^(tl|t|tr)$/i,
  385. /**
  386. * Regex which matches with the handles that could change the width of
  387. * the resizable element.
  388. *
  389. * @property REGEX_CHANGE_WIDTH
  390. * @type {String}
  391. */
  392. REGEX_CHANGE_WIDTH: /^(bl|br|l|r|tl|tr)$/i,
  393. /**
  394. * Template used to create the resize wrapper for the handles.
  395. *
  396. * @property HANDLES_WRAP_TEMPLATE
  397. * @type {String}
  398. */
  399. HANDLES_WRAP_TEMPLATE: '<div class="'+CSS_RESIZE_HANDLES_WRAPPER+'"></div>',
  400. /**
  401. * Template used to create the resize wrapper node when needed.
  402. *
  403. * @property WRAP_TEMPLATE
  404. * @type {String}
  405. */
  406. WRAP_TEMPLATE: '<div class="'+CSS_RESIZE_WRAPPER+'"></div>',
  407. /**
  408. * Template used to create each resize handle.
  409. *
  410. * @property HANDLE_TEMPLATE
  411. * @type {String}
  412. */
  413. HANDLE_TEMPLATE: '<div class="'+concat(CSS_RESIZE_HANDLE, CSS_RESIZE_HANDLE_PLACEHOLDER)+'">' +
  414. '<div class="'+concat(CSS_RESIZE_HANDLE_INNER, CSS_RESIZE_HANDLE_INNER_PLACEHOLDER)+'">&nbsp;</div>' +
  415. '</div>',
  416. /**
  417. * Each box has a content area and optional surrounding padding and
  418. * border areas. This property stores the sum of all horizontal
  419. * surrounding * information needed to adjust the node height.
  420. *
  421. * @property totalHSurrounding
  422. * @default 0
  423. * @type number
  424. */
  425. totalHSurrounding: 0,
  426. /**
  427. * Each box has a content area and optional surrounding padding and
  428. * border areas. This property stores the sum of all vertical
  429. * surrounding * information needed to adjust the node height.
  430. *
  431. * @property totalVSurrounding
  432. * @default 0
  433. * @type number
  434. */
  435. totalVSurrounding: 0,
  436. /**
  437. * Stores the <a href="Resize.html#attr_node">node</a>
  438. * surrounding information retrieved from
  439. * <a href="Resize.html#method__getBoxSurroundingInfo">_getBoxSurroundingInfo</a>.
  440. *
  441. * @property nodeSurrounding
  442. * @type Object
  443. * @default null
  444. */
  445. nodeSurrounding: null,
  446. /**
  447. * Stores the <a href="Resize.html#attr_wrapper">wrapper</a>
  448. * surrounding information retrieved from
  449. * <a href="Resize.html#method__getBoxSurroundingInfo">_getBoxSurroundingInfo</a>.
  450. *
  451. * @property wrapperSurrounding
  452. * @type Object
  453. * @default null
  454. */
  455. wrapperSurrounding: null,
  456. /**
  457. * Whether the handle being dragged can change the height.
  458. *
  459. * @property changeHeightHandles
  460. * @default false
  461. * @type boolean
  462. */
  463. changeHeightHandles: false,
  464. /**
  465. * Whether the handle being dragged can change the left.
  466. *
  467. * @property changeLeftHandles
  468. * @default false
  469. * @type boolean
  470. */
  471. changeLeftHandles: false,
  472. /**
  473. * Whether the handle being dragged can change the top.
  474. *
  475. * @property changeTopHandles
  476. * @default false
  477. * @type boolean
  478. */
  479. changeTopHandles: false,
  480. /**
  481. * Whether the handle being dragged can change the width.
  482. *
  483. * @property changeWidthHandles
  484. * @default false
  485. * @type boolean
  486. */
  487. changeWidthHandles: false,
  488. /**
  489. * Store DD.Delegate reference for the respective Resize instance.
  490. *
  491. * @property delegate
  492. * @default null
  493. * @type Object
  494. */
  495. delegate: null,
  496. /**
  497. * Stores the current values for the height, width, top and left. You are
  498. * able to manipulate these values on resize in order to change the resize
  499. * behavior.
  500. *
  501. * @property info
  502. * @type Object
  503. * @protected
  504. */
  505. info: null,
  506. /**
  507. * Stores the last values for the height, width, top and left.
  508. *
  509. * @property lastInfo
  510. * @type Object
  511. * @protected
  512. */
  513. lastInfo: null,
  514. /**
  515. * Stores the original values for the height, width, top and left, stored
  516. * on resize start.
  517. *
  518. * @property originalInfo
  519. * @type Object
  520. * @protected
  521. */
  522. originalInfo: null,
  523. /**
  524. * Construction logic executed during Resize instantiation. Lifecycle.
  525. *
  526. * @method initializer
  527. * @protected
  528. */
  529. initializer: function() {
  530. this._eventHandles = [];
  531. this.renderer();
  532. },
  533. /**
  534. * Create the DOM structure for the Resize. Lifecycle.
  535. *
  536. * @method renderUI
  537. * @protected
  538. */
  539. renderUI: function() {
  540. var instance = this;
  541. instance._renderHandles();
  542. },
  543. /**
  544. * Bind the events on the Resize UI. Lifecycle.
  545. *
  546. * @method bindUI
  547. * @protected
  548. */
  549. bindUI: function() {
  550. var instance = this;
  551. instance._createEvents();
  552. instance._bindDD();
  553. instance._bindHandle();
  554. },
  555. /**
  556. * Sync the Resize UI.
  557. *
  558. * @method syncUI
  559. * @protected
  560. */
  561. syncUI: function() {
  562. var instance = this;
  563. this.get(NODE).addClass(CSS_RESIZE);
  564. // hide handles if AUTO_HIDE is true
  565. instance._setHideHandlesUI(
  566. instance.get(AUTO_HIDE)
  567. );
  568. },
  569. /**
  570. * Destructor lifecycle implementation for the Resize class.
  571. * Detaches all previously attached listeners and removes the Resize handles.
  572. *
  573. * @method destructor
  574. * @protected
  575. */
  576. destructor: function() {
  577. var instance = this,
  578. node = instance.get(NODE),
  579. wrapper = instance.get(WRAPPER),
  580. pNode = wrapper.get(PARENT_NODE);
  581. Y.each(
  582. instance._eventHandles,
  583. function(handle) {
  584. handle.detach();
  585. }
  586. );
  587. instance._eventHandles.length = 0;
  588. // destroy handles dd and remove them from the dom
  589. instance.eachHandle(function(handleEl) {
  590. instance.delegate.dd.destroy();
  591. // remove handle
  592. handleEl.remove(true);
  593. });
  594. instance.delegate.destroy();
  595. // unwrap node
  596. if (instance.get(WRAP)) {
  597. instance._copyStyles(wrapper, node);
  598. if (pNode) {
  599. pNode.insertBefore(node, wrapper);
  600. }
  601. wrapper.remove(true);
  602. }
  603. node.removeClass(CSS_RESIZE);
  604. node.removeClass(CSS_RESIZE_HIDDEN_HANDLES);
  605. },
  606. /**
  607. * Creates DOM (or manipulates DOM for progressive enhancement)
  608. * This method is invoked by initializer(). It's chained automatically for
  609. * subclasses if required.
  610. *
  611. * @method renderer
  612. * @protected
  613. */
  614. renderer: function() {
  615. this.renderUI();
  616. this.bindUI();
  617. this.syncUI();
  618. },
  619. /**
  620. * <p>Loop through each handle which is being used and executes a callback.</p>
  621. * <p>Example:</p>
  622. * <pre><code>instance.eachHandle(
  623. * function(handleName, index) { ... }
  624. * );</code></pre>
  625. *
  626. * @method eachHandle
  627. * @param {function} fn Callback function to be executed for each handle.
  628. */
  629. eachHandle: function(fn) {
  630. var instance = this;
  631. Y.each(
  632. instance.get(HANDLES),
  633. function(handle, i) {
  634. var handleEl = instance.get(
  635. handleAttrName(handle)
  636. );
  637. fn.apply(instance, [handleEl, handle, i]);
  638. }
  639. );
  640. },
  641. /**
  642. * Bind the handles DragDrop events to the Resize instance.
  643. *
  644. * @method _bindDD
  645. * @private
  646. */
  647. _bindDD: function() {
  648. var instance = this;
  649. instance.delegate = new Y.DD.Delegate(
  650. {
  651. bubbleTargets: instance,
  652. container: instance.get(HANDLES_WRAPPER),
  653. dragConfig: {
  654. clickPixelThresh: 0,
  655. clickTimeThresh: 0,
  656. useShim: true,
  657. move: false
  658. },
  659. nodes: DOT+CSS_RESIZE_HANDLE,
  660. target: false
  661. }
  662. );
  663. instance._eventHandles.push(
  664. instance.on('drag:drag', instance._handleResizeEvent),
  665. instance.on('drag:dropmiss', instance._handleMouseUpEvent),
  666. instance.on('drag:end', instance._handleResizeEndEvent),
  667. instance.on('drag:start', instance._handleResizeStartEvent)
  668. );
  669. },
  670. /**
  671. * Bind the events related to the handles (_onHandleMouseEnter, _onHandleMouseLeave).
  672. *
  673. * @method _bindHandle
  674. * @private
  675. */
  676. _bindHandle: function() {
  677. var instance = this,
  678. wrapper = instance.get(WRAPPER);
  679. instance._eventHandles.push(
  680. wrapper.on('mouseenter', Y.bind(instance._onWrapperMouseEnter, instance)),
  681. wrapper.on('mouseleave', Y.bind(instance._onWrapperMouseLeave, instance)),
  682. wrapper.delegate('mouseenter', Y.bind(instance._onHandleMouseEnter, instance), DOT+CSS_RESIZE_HANDLE),
  683. wrapper.delegate('mouseleave', Y.bind(instance._onHandleMouseLeave, instance), DOT+CSS_RESIZE_HANDLE)
  684. );
  685. },
  686. /**
  687. * Create the custom events used on the Resize.
  688. *
  689. * @method _createEvents
  690. * @private
  691. */
  692. _createEvents: function() {
  693. var instance = this,
  694. // create publish function for kweight optimization
  695. publish = function(name, fn) {
  696. instance.publish(name, {
  697. defaultFn: fn,
  698. queuable: false,
  699. emitFacade: true,
  700. bubbles: true,
  701. prefix: RESIZE
  702. });
  703. };
  704. /**
  705. * Handles the resize start event. Fired when a handle starts to be
  706. * dragged.
  707. *
  708. * @event resize:start
  709. * @preventable _defResizeStartFn
  710. * @param {EventFacade} event The resize start event.
  711. * @bubbles Resize
  712. */
  713. publish(EV_RESIZE_START, this._defResizeStartFn);
  714. /**
  715. * Handles the resize event. Fired on each pixel when the handle is
  716. * being dragged.
  717. *
  718. * @event resize:resize
  719. * @preventable _defResizeFn
  720. * @param {EventFacade} event The resize event.
  721. * @bubbles Resize
  722. */
  723. publish(EV_RESIZE, this._defResizeFn);
  724. /**
  725. * Handles the resize align event.
  726. *
  727. * @event resize:align
  728. * @preventable _defResizeAlignFn
  729. * @param {EventFacade} event The resize align event.
  730. * @bubbles Resize
  731. */
  732. publish(EV_RESIZE_ALIGN, this._defResizeAlignFn);
  733. /**
  734. * Handles the resize end event. Fired when a handle stop to be
  735. * dragged.
  736. *
  737. * @event resize:end
  738. * @preventable _defResizeEndFn
  739. * @param {EventFacade} event The resize end event.
  740. * @bubbles Resize
  741. */
  742. publish(EV_RESIZE_END, this._defResizeEndFn);
  743. /**
  744. * Handles the resize mouseUp event. Fired when a mouseUp event happens on a
  745. * handle.
  746. *
  747. * @event resize:mouseUp
  748. * @preventable _defMouseUpFn
  749. * @param {EventFacade} event The resize mouseUp event.
  750. * @bubbles Resize
  751. */
  752. publish(EV_MOUSE_UP, this._defMouseUpFn);
  753. },
  754. /**
  755. * Responsible for loop each handle element and append to the wrapper.
  756. *
  757. * @method _renderHandles
  758. * @protected
  759. */
  760. _renderHandles: function() {
  761. var instance = this,
  762. wrapper = instance.get(WRAPPER),
  763. handlesWrapper = instance.get(HANDLES_WRAPPER);
  764. instance.eachHandle(function(handleEl) {
  765. handlesWrapper.append(handleEl);
  766. });
  767. wrapper.append(handlesWrapper);
  768. },
  769. /**
  770. * Creates the handle element based on the handle name and initialize the
  771. * DragDrop on it.
  772. *
  773. * @method _buildHandle
  774. * @param {String} handle Handle name ('t', 'tr', 'b', ...).
  775. * @protected
  776. */
  777. _buildHandle: function(handle) {
  778. var instance = this;
  779. return Y.Node.create(
  780. Y.Lang.sub(instance.HANDLE_TEMPLATE, {
  781. handle: handle
  782. })
  783. );
  784. },
  785. /**
  786. * Basic resize calculations.
  787. *
  788. * @method _calcResize
  789. * @protected
  790. */
  791. _calcResize: function() {
  792. var instance = this,
  793. handle = instance.handle,
  794. info = instance.info,
  795. originalInfo = instance.originalInfo,
  796. dx = info.actXY[0] - originalInfo.actXY[0],
  797. dy = info.actXY[1] - originalInfo.actXY[1];
  798. if (handle && Y.Resize.RULES[handle]) {
  799. Y.Resize.RULES[handle](instance, dx, dy);
  800. }
  801. else {
  802. Y.log('Handle rule not found: ' + handle, 'warn', 'resize');
  803. }
  804. },
  805. /**
  806. * Helper method to update the current size value on
  807. * <a href="Resize.html#property_info">info</a> to respect the
  808. * min/max values and fix the top/left calculations.
  809. *
  810. * @method _checkSize
  811. * @param {String} offset 'offsetHeight' or 'offsetWidth'
  812. * @param {number} size Size to restrict the offset
  813. * @protected
  814. */
  815. _checkSize: function(offset, size) {
  816. var instance = this,
  817. info = instance.info,
  818. originalInfo = instance.originalInfo,
  819. axis = (offset === OFFSET_HEIGHT) ? TOP : LEFT;
  820. // forcing the offsetHeight/offsetWidth to be the passed size
  821. info[offset] = size;
  822. // predicting, based on the original information, the last left valid in case of reach the min/max dimension
  823. // this calculation avoid browser event leaks when user interact very fast
  824. if (((axis === LEFT) && instance.changeLeftHandles) ||
  825. ((axis === TOP) && instance.changeTopHandles)) {
  826. info[axis] = originalInfo[axis] + originalInfo[offset] - size;
  827. }
  828. },
  829. /**
  830. * Copy relevant styles of the <a href="Resize.html#attr_node">node</a>
  831. * to the <a href="Resize.html#attr_wrapper">wrapper</a>.
  832. *
  833. * @method _copyStyles
  834. * @param {Node} node Node from.
  835. * @param {Node} wrapper Node to.
  836. * @protected
  837. */
  838. _copyStyles: function(node, wrapper) {
  839. var position = node.getStyle(POSITION).toLowerCase(),
  840. surrounding = this._getBoxSurroundingInfo(node),
  841. wrapperStyle;
  842. // resizable wrapper should be positioned
  843. if (position === STATIC) {
  844. position = RELATIVE;
  845. }
  846. wrapperStyle = {
  847. position: position,
  848. left: getCompStyle(node, LEFT),
  849. top: getCompStyle(node, TOP)
  850. };
  851. Y.mix(wrapperStyle, surrounding.margin);
  852. Y.mix(wrapperStyle, surrounding.border);
  853. wrapper.setStyles(wrapperStyle);
  854. // remove margin and border from the internal node
  855. node.setStyles({ border: 0, margin: 0 });
  856. wrapper.sizeTo(
  857. node.get(OFFSET_WIDTH) + surrounding.totalHBorder,
  858. node.get(OFFSET_HEIGHT) + surrounding.totalVBorder
  859. );
  860. },
  861. // extract handle name from a string
  862. // using Y.cached to memoize the function for performance
  863. _extractHandleName: Y.cached(
  864. function(node) {
  865. var className = node.get(CLASS_NAME),
  866. match = className.match(
  867. new RegExp(
  868. getCN(RESIZE, HANDLE, '(\\w{1,2})\\b')
  869. )
  870. );
  871. return match ? match[1] : null;
  872. }
  873. ),
  874. /**
  875. * <p>Generates metadata to the <a href="Resize.html#property_info">info</a>
  876. * and <a href="Resize.html#property_originalInfo">originalInfo</a></p>
  877. * <pre><code>bottom, actXY, left, top, offsetHeight, offsetWidth, right</code></pre>
  878. *
  879. * @method _getInfo
  880. * @param {Node} node
  881. * @param {EventFacade} event
  882. * @private
  883. */
  884. _getInfo: function(node, event) {
  885. var actXY = [0,0],
  886. drag = event.dragEvent.target,
  887. nodeXY = node.getXY(),
  888. nodeX = nodeXY[0],
  889. nodeY = nodeXY[1],
  890. offsetHeight = node.get(OFFSET_HEIGHT),
  891. offsetWidth = node.get(OFFSET_WIDTH);
  892. if (event) {
  893. // the xy that the node will be set to. Changing this will alter the position as it's dragged.
  894. actXY = (drag.actXY.length ? drag.actXY : drag.lastXY);
  895. }
  896. return {
  897. actXY: actXY,
  898. bottom: (nodeY + offsetHeight),
  899. left: nodeX,
  900. offsetHeight: offsetHeight,
  901. offsetWidth: offsetWidth,
  902. right: (nodeX + offsetWidth),
  903. top: nodeY
  904. };
  905. },
  906. /**
  907. * Each box has a content area and optional surrounding margin,
  908. * padding and * border areas. This method get all this information from
  909. * the passed node. For more reference see
  910. * <a href="http://www.w3.org/TR/CSS21/box.html#box-dimensions">
  911. * http://www.w3.org/TR/CSS21/box.html#box-dimensions</a>.
  912. *
  913. * @method _getBoxSurroundingInfo
  914. * @param {Node} node
  915. * @private
  916. * @return {Object}
  917. */
  918. _getBoxSurroundingInfo: function(node) {
  919. var info = {
  920. padding: {},
  921. margin: {},
  922. border: {}
  923. };
  924. if (isNode(node)) {
  925. Y.each([ TOP, RIGHT, BOTTOM, LEFT ], function(dir) {
  926. var paddingProperty = capitalize(PADDING, dir),
  927. marginProperty = capitalize(MARGIN, dir),
  928. borderWidthProperty = capitalize(BORDER, dir, WIDTH),
  929. borderColorProperty = capitalize(BORDER, dir, COLOR),
  930. borderStyleProperty = capitalize(BORDER, dir, STYLE);
  931. info.border[borderColorProperty] = getCompStyle(node, borderColorProperty);
  932. info.border[borderStyleProperty] = getCompStyle(node, borderStyleProperty);
  933. info.border[borderWidthProperty] = getCompStyle(node, borderWidthProperty);
  934. info.margin[marginProperty] = getCompStyle(node, marginProperty);
  935. info.padding[paddingProperty] = getCompStyle(node, paddingProperty);
  936. });
  937. }
  938. info.totalHBorder = (toRoundNumber(info.border.borderLeftWidth) + toRoundNumber(info.border.borderRightWidth));
  939. info.totalHPadding = (toRoundNumber(info.padding.paddingLeft) + toRoundNumber(info.padding.paddingRight));
  940. info.totalVBorder = (toRoundNumber(info.border.borderBottomWidth) + toRoundNumber(info.border.borderTopWidth));
  941. info.totalVPadding = (toRoundNumber(info.padding.paddingBottom) + toRoundNumber(info.padding.paddingTop));
  942. return info;
  943. },
  944. /**
  945. * Sync the Resize UI with internal values from
  946. * <a href="Resize.html#property_info">info</a>.
  947. *
  948. * @method _syncUI
  949. * @protected
  950. */
  951. _syncUI: function() {
  952. var instance = this,
  953. info = instance.info,
  954. wrapperSurrounding = instance.wrapperSurrounding,
  955. wrapper = instance.get(WRAPPER),
  956. node = instance.get(NODE);
  957. wrapper.sizeTo(info.offsetWidth, info.offsetHeight);
  958. if (instance.changeLeftHandles || instance.changeTopHandles) {
  959. wrapper.setXY([info.left, info.top]);
  960. }
  961. // if a wrap node is being used
  962. if (!wrapper.compareTo(node)) {
  963. // the original internal node borders were copied to the wrapper on
  964. // _copyStyles, to compensate that subtract the borders from the internal node
  965. node.sizeTo(
  966. info.offsetWidth - wrapperSurrounding.totalHBorder,
  967. info.offsetHeight - wrapperSurrounding.totalVBorder
  968. );
  969. }
  970. // prevent webkit textarea resize
  971. if (Y.UA.webkit) {
  972. node.setStyle(RESIZE, NONE);
  973. }
  974. },
  975. /**
  976. * Update <code>instance.changeHeightHandles,
  977. * instance.changeLeftHandles, instance.changeTopHandles,
  978. * instance.changeWidthHandles</code> information.
  979. *
  980. * @method _updateChangeHandleInfo
  981. * @private
  982. */
  983. _updateChangeHandleInfo: function(handle) {
  984. var instance = this;
  985. instance.changeHeightHandles = instance.REGEX_CHANGE_HEIGHT.test(handle);
  986. instance.changeLeftHandles = instance.REGEX_CHANGE_LEFT.test(handle);
  987. instance.changeTopHandles = instance.REGEX_CHANGE_TOP.test(handle);
  988. instance.changeWidthHandles = instance.REGEX_CHANGE_WIDTH.test(handle);
  989. },
  990. /**
  991. * Update <a href="Resize.html#property_info">info</a> values (bottom, actXY, left, top, offsetHeight, offsetWidth, right).
  992. *
  993. * @method _updateInfo
  994. * @private
  995. */
  996. _updateInfo: function(event) {
  997. var instance = this;
  998. instance.info = instance._getInfo(instance.get(WRAPPER), event);
  999. },
  1000. /**
  1001. * Update properties
  1002. * <a href="Resize.html#property_nodeSurrounding">nodeSurrounding</a>,
  1003. * <a href="Resize.html#property_nodeSurrounding">wrapperSurrounding</a>,
  1004. * <a href="Resize.html#property_nodeSurrounding">totalVSurrounding</a>,
  1005. * <a href="Resize.html#property_nodeSurrounding">totalHSurrounding</a>.
  1006. *
  1007. * @method _updateSurroundingInfo
  1008. * @private
  1009. */
  1010. _updateSurroundingInfo: function() {
  1011. var instance = this,
  1012. node = instance.get(NODE),
  1013. wrapper = instance.get(WRAPPER),
  1014. nodeSurrounding = instance._getBoxSurroundingInfo(node),
  1015. wrapperSurrounding = instance._getBoxSurroundingInfo(wrapper);
  1016. instance.nodeSurrounding = nodeSurrounding;
  1017. instance.wrapperSurrounding = wrapperSurrounding;
  1018. instance.totalVSurrounding = (nodeSurrounding.totalVPadding + wrapperSurrounding.totalVBorder);
  1019. instance.totalHSurrounding = (nodeSurrounding.totalHPadding + wrapperSurrounding.totalHBorder);
  1020. },
  1021. /**
  1022. * Set the active state of the handles.
  1023. *
  1024. * @method _setActiveHandlesUI
  1025. * @param {boolean} val True to activate the handles, false to deactivate.
  1026. * @protected
  1027. */
  1028. _setActiveHandlesUI: function(val) {
  1029. var instance = this,
  1030. activeHandleNode = instance.get(ACTIVE_HANDLE_NODE);
  1031. if (activeHandleNode) {
  1032. if (val) {
  1033. // remove CSS_RESIZE_HANDLE_ACTIVE from all handles before addClass on the active
  1034. instance.eachHandle(
  1035. function(handleEl) {
  1036. handleEl.removeClass(CSS_RESIZE_HANDLE_ACTIVE);
  1037. }
  1038. );
  1039. activeHandleNode.addClass(CSS_RESIZE_HANDLE_ACTIVE);
  1040. }
  1041. else {
  1042. activeHandleNode.removeClass(CSS_RESIZE_HANDLE_ACTIVE);
  1043. }
  1044. }
  1045. },
  1046. /**
  1047. * Setter for the handles attribute
  1048. *
  1049. * @method _setHandles
  1050. * @protected
  1051. * @param {String} val
  1052. */
  1053. _setHandles: function(val) {
  1054. var instance = this,
  1055. handles = [];
  1056. // handles attr accepts both array or string
  1057. if (isArray(val)) {
  1058. handles = val;
  1059. }
  1060. else if (isString(val)) {
  1061. // if the handles attr passed in is an ALL string...
  1062. if (val.toLowerCase() === ALL) {
  1063. handles = instance.ALL_HANDLES;
  1064. }
  1065. // otherwise, split the string to extract the handles
  1066. else {
  1067. Y.each(
  1068. val.split(COMMA),
  1069. function(node) {
  1070. var handle = trim(node);
  1071. // if its a valid handle, add it to the handles output
  1072. if (indexOf(instance.ALL_HANDLES, handle) > -1) {
  1073. handles.push(handle);
  1074. }
  1075. }
  1076. );
  1077. }
  1078. }
  1079. return handles;
  1080. },
  1081. /**
  1082. * Set the visibility of the handles.
  1083. *
  1084. * @method _setHideHandlesUI
  1085. * @param {boolean} val True to hide the handles, false to show.
  1086. * @protected
  1087. */
  1088. _setHideHandlesUI: function(val) {
  1089. var instance = this,
  1090. wrapper = instance.get(WRAPPER);
  1091. if (!instance.get(RESIZING)) {
  1092. if (val) {
  1093. wrapper.addClass(CSS_RESIZE_HIDDEN_HANDLES);
  1094. }
  1095. else {
  1096. wrapper.removeClass(CSS_RESIZE_HIDDEN_HANDLES);
  1097. }
  1098. }
  1099. },
  1100. /**
  1101. * Setter for the wrap attribute
  1102. *
  1103. * @method _setWrap
  1104. * @protected
  1105. * @param {boolean} val
  1106. */
  1107. _setWrap: function(val) {
  1108. var instance = this,
  1109. node = instance.get(NODE),
  1110. nodeName = node.get(NODE_NAME),
  1111. typeRegex = instance.get(WRAP_TYPES);
  1112. // if nodeName is listed on WRAP_TYPES force use the wrapper
  1113. if (typeRegex.test(nodeName)) {
  1114. val = true;
  1115. }
  1116. return val;
  1117. },
  1118. /**
  1119. * Default resize:mouseUp handler
  1120. *
  1121. * @method _defMouseUpFn
  1122. * @param {EventFacade} event The Event object
  1123. * @protected
  1124. */
  1125. _defMouseUpFn: function() {
  1126. var instance = this;
  1127. instance.set(RESIZING, false);
  1128. },
  1129. /**
  1130. * Default resize:resize handler
  1131. *
  1132. * @method _defResizeFn
  1133. * @param {EventFacade} event The Event object
  1134. * @protected
  1135. */
  1136. _defResizeFn: function(event) {
  1137. var instance = this;
  1138. instance._resize(event);
  1139. },
  1140. /**
  1141. * Logic method for _defResizeFn. Allow AOP.
  1142. *
  1143. * @method _resize
  1144. * @param {EventFacade} event The Event object
  1145. * @protected
  1146. */
  1147. _resize: function(event) {
  1148. var instance = this;
  1149. instance._handleResizeAlignEvent(event.dragEvent);
  1150. // _syncUI of the wrapper, not using proxy
  1151. instance._syncUI();
  1152. },
  1153. /**
  1154. * Default resize:align handler
  1155. *
  1156. * @method _defResizeAlignFn
  1157. * @param {EventFacade} event The Event object
  1158. * @protected
  1159. */
  1160. _defResizeAlignFn: function(event) {
  1161. var instance = this;
  1162. instance._resizeAlign(event);
  1163. },
  1164. /**
  1165. * Logic method for _defResizeAlignFn. Allow AOP.
  1166. *
  1167. * @method _resizeAlign
  1168. * @param {EventFacade} event The Event object
  1169. * @protected
  1170. */
  1171. _resizeAlign: function(event) {
  1172. var instance = this,
  1173. info,
  1174. defMinHeight,
  1175. defMinWidth;
  1176. instance.lastInfo = instance.info;
  1177. // update the instance.info values
  1178. instance._updateInfo(event);
  1179. info = instance.info;
  1180. // basic resize calculations
  1181. instance._calcResize();
  1182. // if Y.Plugin.ResizeConstrained is not plugged, check for min dimension
  1183. if (!instance.con) {
  1184. defMinHeight = (instance.get(DEF_MIN_HEIGHT) + instance.totalVSurrounding);
  1185. defMinWidth = (instance.get(DEF_MIN_WIDTH) + instance.totalHSurrounding);
  1186. if (info.offsetHeight <= defMinHeight) {
  1187. instance._checkSize(OFFSET_HEIGHT, defMinHeight);
  1188. }
  1189. if (info.offsetWidth <= defMinWidth) {
  1190. instance._checkSize(OFFSET_WIDTH, defMinWidth);
  1191. }
  1192. }
  1193. },
  1194. /**
  1195. * Default resize:end handler
  1196. *
  1197. * @method _defResizeEndFn
  1198. * @param {EventFacade} event The Event object
  1199. * @protected
  1200. */
  1201. _defResizeEndFn: function(event) {
  1202. var instance = this;
  1203. instance._resizeEnd(event);
  1204. },
  1205. /**
  1206. * Logic method for _defResizeEndFn. Allow AOP.
  1207. *
  1208. * @method _resizeEnd
  1209. * @param {EventFacade} event The Event object
  1210. * @protected
  1211. */
  1212. _resizeEnd: function(event) {
  1213. var instance = this,
  1214. drag = event.dragEvent.target;
  1215. // reseting actXY from drag when drag end
  1216. drag.actXY = [];
  1217. // syncUI when resize end
  1218. instance._syncUI();
  1219. instance._setActiveHandlesUI(false);
  1220. instance.set(ACTIVE_HANDLE, null);
  1221. instance.set(ACTIVE_HANDLE_NODE, null);
  1222. instance.handle = null;
  1223. },
  1224. /**
  1225. * Default resize:start handler
  1226. *
  1227. * @method _defResizeStartFn
  1228. * @param {EventFacade} event The Event object
  1229. * @protected
  1230. */
  1231. _defResizeStartFn: function(event) {
  1232. var instance = this;
  1233. instance._resizeStart(event);
  1234. },
  1235. /**
  1236. * Logic method for _defResizeStartFn. Allow AOP.
  1237. *
  1238. * @method _resizeStart
  1239. * @param {EventFacade} event The Event object
  1240. * @protected
  1241. */
  1242. _resizeStart: function(event) {
  1243. var instance = this,
  1244. wrapper = instance.get(WRAPPER);
  1245. instance.handle = instance.get(ACTIVE_HANDLE);
  1246. instance.set(RESIZING, true);
  1247. instance._updateSurroundingInfo();
  1248. // create an originalInfo information for reference
  1249. instance.originalInfo = instance._getInfo(wrapper, event);
  1250. instance._updateInfo(event);
  1251. },
  1252. /**
  1253. * Fires the resize:mouseUp event.
  1254. *
  1255. * @method _handleMouseUpEvent
  1256. * @param {EventFacade} event resize:mouseUp event facade
  1257. * @protected
  1258. */
  1259. _handleMouseUpEvent: function(event) {
  1260. this.fire(EV_MOUSE_UP, { dragEvent: event, info: this.info });
  1261. },
  1262. /**
  1263. * Fires the resize:resize event.
  1264. *
  1265. * @method _handleResizeEvent
  1266. * @param {EventFacade} event resize:resize event facade
  1267. * @protected
  1268. */
  1269. _handleResizeEvent: function(event) {
  1270. this.fire(EV_RESIZE, { dragEvent: event, info: this.info });
  1271. },
  1272. /**
  1273. * Fires the resize:align event.
  1274. *
  1275. * @method _handleResizeAlignEvent
  1276. * @param {EventFacade} event resize:resize event facade
  1277. * @protected
  1278. */
  1279. _handleResizeAlignEvent: function(event) {
  1280. this.fire(EV_RESIZE_ALIGN, { dragEvent: event, info: this.info });
  1281. },
  1282. /**
  1283. * Fires the resize:end event.
  1284. *
  1285. * @method _handleResizeEndEvent
  1286. * @param {EventFacade} event resize:end event facade
  1287. * @protected
  1288. */
  1289. _handleResizeEndEvent: function(event) {
  1290. this.fire(EV_RESIZE_END, { dragEvent: event, info: this.info });
  1291. },
  1292. /**
  1293. * Fires the resize:start event.
  1294. *
  1295. * @method _handleResizeStartEvent
  1296. * @param {EventFacade} event resize:start event facade
  1297. * @protected
  1298. */
  1299. _handleResizeStartEvent: function(event) {
  1300. if (!this.get(ACTIVE_HANDLE)) {
  1301. //This handles the "touch" case
  1302. this._setHandleFromNode(event.target.get('node'));
  1303. }
  1304. this.fire(EV_RESIZE_START, { dragEvent: event, info: this.info });
  1305. },
  1306. /**
  1307. * Mouseenter event handler for the <a href="Resize.html#attr_wrapper">wrapper</a>.
  1308. *
  1309. * @method _onWrapperMouseEnter
  1310. * @param {EventFacade} event
  1311. * @protected
  1312. */
  1313. _onWrapperMouseEnter: function() {
  1314. var instance = this;
  1315. if (instance.get(AUTO_HIDE)) {
  1316. instance._setHideHandlesUI(false);
  1317. }
  1318. },
  1319. /**
  1320. * Mouseleave event handler for the <a href="Resize.html#attr_wrapper">wrapper</a>.
  1321. *
  1322. * @method _onWrapperMouseLeave
  1323. * @param {EventFacade} event
  1324. * @protected
  1325. */
  1326. _onWrapperMouseLeave: function() {
  1327. var instance = this;
  1328. if (instance.get(AUTO_HIDE)) {
  1329. instance._setHideHandlesUI(true);
  1330. }
  1331. },
  1332. /**
  1333. * Handles setting the activeHandle from a node, used from startDrag (for touch) and mouseenter (for mouse).
  1334. *
  1335. * @method _setHandleFromNode
  1336. * @param {Node} node
  1337. * @protected
  1338. */
  1339. _setHandleFromNode: function(node) {
  1340. var instance = this,
  1341. handle = instance._extractHandleName(node);
  1342. if (!instance.get(RESIZING)) {
  1343. instance.set(ACTIVE_HANDLE, handle);
  1344. instance.set(ACTIVE_HANDLE_NODE, node);
  1345. instance._setActiveHandlesUI(true);
  1346. instance._updateChangeHandleInfo(handle);
  1347. }
  1348. },
  1349. /**
  1350. * Mouseenter event handler for the handles.
  1351. *
  1352. * @method _onHandleMouseEnter
  1353. * @param {EventFacade} event
  1354. * @protected
  1355. */
  1356. _onHandleMouseEnter: function(event) {
  1357. this._setHandleFromNode(event.currentTarget);
  1358. },
  1359. /**
  1360. * Mouseout event handler for the handles.
  1361. *
  1362. * @method _onHandleMouseLeave
  1363. * @param {EventFacade} event
  1364. * @protected
  1365. */
  1366. _onHandleMouseLeave: function() {
  1367. var instance = this;
  1368. if (!instance.get(RESIZING)) {
  1369. instance._setActiveHandlesUI(false);
  1370. }
  1371. },
  1372. /**
  1373. * Default value for the wrapper handles node attribute
  1374. *
  1375. * @method _valueHandlesWrapper
  1376. * @protected
  1377. * @readOnly
  1378. */
  1379. _valueHandlesWrapper: function() {
  1380. return Y.Node.create(this.HANDLES_WRAP_TEMPLATE);
  1381. },
  1382. /**
  1383. * Default value for the wrapper attribute
  1384. *
  1385. * @method _valueWrapper
  1386. * @protected
  1387. * @readOnly
  1388. */
  1389. _valueWrapper: function() {
  1390. var instance = this,
  1391. node = instance.get(NODE),
  1392. pNode = node.get(PARENT_NODE),
  1393. // by deafult the wrapper is always the node
  1394. wrapper = node;
  1395. // if the node is listed on the wrapTypes or wrap is set to true, create another wrapper
  1396. if (instance.get(WRAP)) {
  1397. wrapper = Y.Node.create(instance.WRAP_TEMPLATE);
  1398. if (pNode) {
  1399. pNode.insertBefore(wrapper, node);
  1400. }
  1401. wrapper.append(node);
  1402. instance._copyStyles(node, wrapper);
  1403. // remove positioning of wrapped node, the WRAPPER take care about positioning
  1404. node.setStyles({
  1405. position: STATIC,
  1406. left: 0,
  1407. top: 0
  1408. });
  1409. }
  1410. return wrapper;
  1411. }
  1412. }
  1413. );
  1414. Y.each(Y.Resize.prototype.ALL_HANDLES, function(handle) {
  1415. // creating ATTRS with the handles elements
  1416. Y.Resize.ATTRS[handleAttrName(handle)] = {
  1417. setter: function() {
  1418. return this._buildHandle(handle);
  1419. },
  1420. value: null,
  1421. writeOnce: true
  1422. };
  1423. });