Dashboard sipadu mbip
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

widget-position-constrain-debug.js 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. /*
  2. Copyright (c) 2010, Yahoo! Inc. All rights reserved.
  3. Code licensed under the BSD License:
  4. http://developer.yahoo.com/yui/license.html
  5. version: 3.4.0
  6. build: nightly
  7. */
  8. YUI.add('widget-position-constrain', function(Y) {
  9. /**
  10. * Provides constrained xy positioning support for Widgets, through an extension.
  11. *
  12. * It builds on top of the widget-position module, to provide constrained positioning support.
  13. *
  14. * @module widget-position-constrain
  15. */
  16. var CONSTRAIN = "constrain",
  17. CONSTRAIN_XYCHANGE = "constrain|xyChange",
  18. CONSTRAIN_CHANGE = "constrainChange",
  19. PREVENT_OVERLAP = "preventOverlap",
  20. ALIGN = "align",
  21. EMPTY_STR = "",
  22. BINDUI = "bindUI",
  23. XY = "xy",
  24. X_COORD = "x",
  25. Y_COORD = "y",
  26. Node = Y.Node,
  27. VIEWPORT_REGION = "viewportRegion",
  28. REGION = "region",
  29. PREVENT_OVERLAP_MAP;
  30. /**
  31. * A widget extension, which can be used to add constrained xy positioning support to the base Widget class,
  32. * through the <a href="Base.html#method_build">Base.build</a> method. This extension requires that
  33. * the WidgetPosition extension be added to the Widget (before WidgetPositionConstrain, if part of the same
  34. * extension list passed to Base.build).
  35. *
  36. * @class WidgetPositionConstrain
  37. * @param {Object} User configuration object
  38. */
  39. function PositionConstrain(config) {
  40. if (!this._posNode) {
  41. Y.error("WidgetPosition needs to be added to the Widget, before WidgetPositionConstrain is added");
  42. }
  43. Y.after(this._bindUIPosConstrained, this, BINDUI);
  44. }
  45. /**
  46. * Static property used to define the default attribute
  47. * configuration introduced by WidgetPositionConstrain.
  48. *
  49. * @property ATTRS
  50. * @type Object
  51. * @static
  52. */
  53. PositionConstrain.ATTRS = {
  54. /**
  55. * @attribute constrain
  56. * @type boolean | Node
  57. * @default null
  58. * @description The node to constrain the widget's bounding box to, when setting xy. Can also be
  59. * set to true, to constrain to the viewport.
  60. */
  61. constrain : {
  62. value: null,
  63. setter: "_setConstrain"
  64. },
  65. /**
  66. * @attribute preventOverlap
  67. * @type boolean
  68. * @description If set to true, and WidgetPositionAlign is also added to the Widget,
  69. * constrained positioning will attempt to prevent the widget's bounding box from overlapping
  70. * the element to which it has been aligned, by flipping the orientation of the alignment
  71. * for corner based alignments
  72. */
  73. preventOverlap : {
  74. value:false
  75. }
  76. };
  77. /**
  78. * @property _PREVENT_OVERLAP
  79. * @static
  80. * @protected
  81. * @type Object
  82. * @description The set of positions for which to prevent
  83. * overlap.
  84. */
  85. PREVENT_OVERLAP_MAP = PositionConstrain._PREVENT_OVERLAP = {
  86. x: {
  87. "tltr": 1,
  88. "blbr": 1,
  89. "brbl": 1,
  90. "trtl": 1
  91. },
  92. y : {
  93. "trbr": 1,
  94. "tlbl": 1,
  95. "bltl": 1,
  96. "brtr": 1
  97. }
  98. };
  99. PositionConstrain.prototype = {
  100. /**
  101. * Calculates the constrained positions for the XY positions provided, using
  102. * the provided node argument is passed in. If no node value is passed in, the value of
  103. * the "constrain" attribute is used.
  104. *
  105. * @method getConstrainedXY
  106. * @param {Array} xy The xy values to constrain
  107. * @param {Node | boolean} node Optional. The node to constrain to, or true for the viewport
  108. * @return {Array} The constrained xy values
  109. */
  110. getConstrainedXY : function(xy, node) {
  111. node = node || this.get(CONSTRAIN);
  112. var constrainingRegion = this._getRegion((node === true) ? null : node),
  113. nodeRegion = this._posNode.get(REGION);
  114. return [
  115. this._constrain(xy[0], X_COORD, nodeRegion, constrainingRegion),
  116. this._constrain(xy[1], Y_COORD, nodeRegion, constrainingRegion)
  117. ];
  118. },
  119. /**
  120. * Constrains the widget's bounding box to a node (or the viewport). If xy or node are not
  121. * passed in, the current position and the value of "constrain" will be used respectively.
  122. *
  123. * The widget's position will be changed to the constrained position.
  124. *
  125. * @method constrain
  126. * @param {Array} xy Optional. The xy values to constrain
  127. * @param {Node | boolean} node Optional. The node to constrain to, or true for the viewport
  128. */
  129. constrain : function(xy, node) {
  130. var currentXY,
  131. constrainedXY,
  132. constraint = node || this.get(CONSTRAIN);
  133. if (constraint) {
  134. currentXY = xy || this.get(XY);
  135. constrainedXY = this.getConstrainedXY(currentXY, constraint);
  136. if (constrainedXY[0] !== currentXY[0] || constrainedXY[1] !== currentXY[1]) {
  137. this.set(XY, constrainedXY, { constrained:true });
  138. }
  139. }
  140. },
  141. /**
  142. * The setter implementation for the "constrain" attribute.
  143. *
  144. * @method _setConstrain
  145. * @protected
  146. * @param {Node | boolean} val The attribute value
  147. */
  148. _setConstrain : function(val) {
  149. return (val === true) ? val : Node.one(val);
  150. },
  151. /**
  152. * The method which performs the actual constrain calculations for a given axis ("x" or "y") based
  153. * on the regions provided.
  154. *
  155. * @method _constrain
  156. * @protected
  157. *
  158. * @param {Number} val The value to constrain
  159. * @param {String} axis The axis to use for constrainment
  160. * @param {Region} nodeRegion The region of the node to constrain
  161. * @param {Region} constrainingRegion The region of the node (or viewport) to constrain to
  162. *
  163. * @return {Number} The constrained value
  164. */
  165. _constrain: function(val, axis, nodeRegion, constrainingRegion) {
  166. if (constrainingRegion) {
  167. if (this.get(PREVENT_OVERLAP)) {
  168. val = this._preventOverlap(val, axis, nodeRegion, constrainingRegion);
  169. }
  170. var x = (axis == X_COORD),
  171. regionSize = (x) ? constrainingRegion.width : constrainingRegion.height,
  172. nodeSize = (x) ? nodeRegion.width : nodeRegion.height,
  173. minConstraint = (x) ? constrainingRegion.left : constrainingRegion.top,
  174. maxConstraint = (x) ? constrainingRegion.right - nodeSize : constrainingRegion.bottom - nodeSize;
  175. if (val < minConstraint || val > maxConstraint) {
  176. if (nodeSize < regionSize) {
  177. if (val < minConstraint) {
  178. val = minConstraint;
  179. } else if (val > maxConstraint) {
  180. val = maxConstraint;
  181. }
  182. } else {
  183. val = minConstraint;
  184. }
  185. }
  186. }
  187. return val;
  188. },
  189. /**
  190. * The method which performs the preventOverlap calculations for a given axis ("x" or "y") based
  191. * on the value and regions provided.
  192. *
  193. * @method _preventOverlap
  194. * @protected
  195. *
  196. * @param {Number} val The value being constrain
  197. * @param {String} axis The axis to being constrained
  198. * @param {Region} nodeRegion The region of the node being constrained
  199. * @param {Region} constrainingRegion The region of the node (or viewport) we need to constrain to
  200. *
  201. * @return {Number} The constrained value
  202. */
  203. _preventOverlap : function(val, axis, nodeRegion, constrainingRegion) {
  204. var align = this.get(ALIGN),
  205. x = (axis === X_COORD),
  206. nodeSize,
  207. alignRegion,
  208. nearEdge,
  209. farEdge,
  210. spaceOnNearSide,
  211. spaceOnFarSide;
  212. if (align && align.points && PREVENT_OVERLAP_MAP[axis][align.points.join(EMPTY_STR)]) {
  213. alignRegion = this._getRegion(align.node);
  214. if (alignRegion) {
  215. nodeSize = (x) ? nodeRegion.width : nodeRegion.height;
  216. nearEdge = (x) ? alignRegion.left : alignRegion.top;
  217. farEdge = (x) ? alignRegion.right : alignRegion.bottom;
  218. spaceOnNearSide = (x) ? alignRegion.left - constrainingRegion.left : alignRegion.top - constrainingRegion.top;
  219. spaceOnFarSide = (x) ? constrainingRegion.right - alignRegion.right : constrainingRegion.bottom - alignRegion.bottom;
  220. }
  221. if (val > nearEdge) {
  222. if (spaceOnFarSide < nodeSize && spaceOnNearSide > nodeSize) {
  223. val = nearEdge - nodeSize;
  224. }
  225. } else {
  226. if (spaceOnNearSide < nodeSize && spaceOnFarSide > nodeSize) {
  227. val = farEdge;
  228. }
  229. }
  230. }
  231. return val;
  232. },
  233. /**
  234. * Binds event listeners responsible for updating the UI state in response to
  235. * Widget constrained positioning related state changes.
  236. * <p>
  237. * This method is invoked after bindUI is invoked for the Widget class
  238. * using YUI's aop infrastructure.
  239. * </p>
  240. *
  241. * @method _bindUIPosConstrained
  242. * @protected
  243. */
  244. _bindUIPosConstrained : function() {
  245. this.after(CONSTRAIN_CHANGE, this._afterConstrainChange);
  246. this._enableConstraints(this.get(CONSTRAIN));
  247. },
  248. /**
  249. * After change listener for the "constrain" attribute, responsible
  250. * for updating the UI, in response to attribute changes.
  251. *
  252. * @method _afterConstrainChange
  253. * @protected
  254. * @param {EventFacade} e The event facade
  255. */
  256. _afterConstrainChange : function(e) {
  257. this._enableConstraints(e.newVal);
  258. },
  259. /**
  260. * Updates the UI if enabling constraints, and sets up the xyChange event listeners
  261. * to constrain whenever the widget is moved. Disabling constraints removes the listeners.
  262. *
  263. * @method enable or disable constraints listeners
  264. * @private
  265. * @param {boolean} enable Enable or disable constraints
  266. */
  267. _enableConstraints : function(enable) {
  268. if (enable) {
  269. this.constrain();
  270. this._cxyHandle = this._cxyHandle || this.on(CONSTRAIN_XYCHANGE, this._constrainOnXYChange);
  271. } else if (this._cxyHandle) {
  272. this._cxyHandle.detach();
  273. this._cxyHandle = null;
  274. }
  275. },
  276. /**
  277. * The on change listener for the "xy" attribute. Modifies the event facade's
  278. * newVal property with the constrained XY value.
  279. *
  280. * @method _constrainOnXYChange
  281. * @protected
  282. * @param {EventFacade} e The event facade for the attribute change
  283. */
  284. _constrainOnXYChange : function(e) {
  285. if (!e.constrained) {
  286. e.newVal = this.getConstrainedXY(e.newVal);
  287. }
  288. },
  289. /**
  290. * Utility method to normalize region retrieval from a node instance,
  291. * or the viewport, if no node is provided.
  292. *
  293. * @method _getRegion
  294. * @private
  295. * @param {Node} node Optional.
  296. */
  297. _getRegion : function(node) {
  298. var region;
  299. if (!node) {
  300. region = this._posNode.get(VIEWPORT_REGION);
  301. } else {
  302. node = Node.one(node);
  303. if (node) {
  304. region = node.get(REGION);
  305. }
  306. }
  307. return region;
  308. }
  309. };
  310. Y.WidgetPositionConstrain = PositionConstrain;
  311. }, '3.4.0' ,{requires:['widget-position']});