Dashboard sipadu mbip
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

widget-position-align-debug.js 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660
  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-align', function(Y) {
  9. /**
  10. Provides extended/advanced XY positioning support for Widgets, through an
  11. extension.
  12. It builds on top of the `widget-position` module, to provide alignment and
  13. centering support. Future releases aim to add constrained and fixed positioning
  14. support.
  15. @module widget-position-align
  16. **/
  17. var Lang = Y.Lang,
  18. ALIGN = 'align',
  19. ALIGN_ON = 'alignOn',
  20. VISIBLE = 'visible',
  21. BOUNDING_BOX = 'boundingBox',
  22. OFFSET_WIDTH = 'offsetWidth',
  23. OFFSET_HEIGHT = 'offsetHeight',
  24. REGION = 'region',
  25. VIEWPORT_REGION = 'viewportRegion';
  26. /**
  27. Widget extension, which can be used to add extended XY positioning support to
  28. the base Widget class, through the `Base.create` method.
  29. **Note:** This extension requires that the `WidgetPosition` extension be added
  30. to the Widget (before `WidgetPositionAlign`, if part of the same extension list
  31. passed to `Base.build`).
  32. @class WidgetPositionAlign
  33. @param {Object} config User configuration object.
  34. @constructor
  35. **/
  36. function PositionAlign (config) {
  37. if ( ! this._posNode) {
  38. Y.error('WidgetPosition needs to be added to the Widget, ' +
  39. 'before WidgetPositionAlign is added');
  40. }
  41. Y.after(this._bindUIPosAlign, this, 'bindUI');
  42. Y.after(this._syncUIPosAlign, this, 'syncUI');
  43. }
  44. PositionAlign.ATTRS = {
  45. /**
  46. The alignment configuration for this widget.
  47. The `align` attribute is used to align a reference point on the widget, with
  48. the reference point on another `Node`, or the viewport. The object which
  49. `align` expects has the following properties:
  50. * __`node`__: The `Node` to which the widget is to be aligned. If set to
  51. `null`, or not provided, the widget is aligned to the viewport.
  52. * __`points`__: A two element Array, defining the two points on the widget
  53. and `Node`/viewport which are to be aligned. The first element is the
  54. point on the widget, and the second element is the point on the
  55. `Node`/viewport. Supported alignment points are defined as static
  56. properties on `WidgetPositionAlign`.
  57. @example Aligns the top-right corner of the widget with the top-left corner
  58. of the viewport:
  59. myWidget.set('align', {
  60. points: [Y.WidgetPositionAlign.TR, Y.WidgetPositionAlign.TL]
  61. });
  62. @attribute align
  63. @type Object
  64. @default null
  65. **/
  66. align: {
  67. value: null
  68. },
  69. /**
  70. A convenience Attribute, which can be used as a shortcut for the `align`
  71. Attribute.
  72. If set to `true`, the widget is centered in the viewport. If set to a `Node`
  73. reference or valid selector String, the widget will be centered within the
  74. `Node`. If set to `false`, no center positioning is applied.
  75. @attribute centered
  76. @type Boolean|Node
  77. @default false
  78. **/
  79. centered: {
  80. setter : '_setAlignCenter',
  81. lazyAdd:false,
  82. value :false
  83. },
  84. /**
  85. An Array of Objects corresponding to the `Node`s and events that will cause
  86. the alignment of this widget to be synced to the DOM.
  87. The `alignOn` Attribute is expected to be an Array of Objects with the
  88. following properties:
  89. * __`eventName`__: The String event name to listen for.
  90. * __`node`__: The optional `Node` that will fire the event, it can be a
  91. `Node` reference or a selector String. This will default to the widget's
  92. `boundingBox`.
  93. @example Sync this widget's alignment on window resize:
  94. myWidget.set('alignOn', [
  95. {
  96. node : Y.one('win'),
  97. eventName: 'resize'
  98. }
  99. ]);
  100. @attribute alignOn
  101. @type Array
  102. @default []
  103. **/
  104. alignOn: {
  105. value : [],
  106. validator: Y.Lang.isArray
  107. }
  108. };
  109. /**
  110. Constant used to specify the top-left corner for alignment
  111. @property TL
  112. @type String
  113. @value 'tl'
  114. @static
  115. **/
  116. PositionAlign.TL = 'tl';
  117. /**
  118. Constant used to specify the top-right corner for alignment
  119. @property TR
  120. @type String
  121. @value 'tr'
  122. @static
  123. **/
  124. PositionAlign.TR = 'tr';
  125. /**
  126. Constant used to specify the bottom-left corner for alignment
  127. @property BL
  128. @type String
  129. @value 'bl'
  130. @static
  131. **/
  132. PositionAlign.BL = 'bl';
  133. /**
  134. Constant used to specify the bottom-right corner for alignment
  135. @property BR
  136. @type String
  137. @value 'br'
  138. @static
  139. **/
  140. PositionAlign.BR = 'br';
  141. /**
  142. Constant used to specify the top edge-center point for alignment
  143. @property TC
  144. @type String
  145. @value 'tc'
  146. @static
  147. **/
  148. PositionAlign.TC = 'tc';
  149. /**
  150. Constant used to specify the right edge, center point for alignment
  151. @property RC
  152. @type String
  153. @value 'rc'
  154. @static
  155. **/
  156. PositionAlign.RC = 'rc';
  157. /**
  158. Constant used to specify the bottom edge, center point for alignment
  159. @property BC
  160. @type String
  161. @value 'bc'
  162. @static
  163. **/
  164. PositionAlign.BC = 'bc';
  165. /**
  166. Constant used to specify the left edge, center point for alignment
  167. @property LC
  168. @type String
  169. @value 'lc'
  170. @static
  171. **/
  172. PositionAlign.LC = 'lc';
  173. /**
  174. Constant used to specify the center of widget/node/viewport for alignment
  175. @property CC
  176. @type String
  177. @value 'cc'
  178. @static
  179. */
  180. PositionAlign.CC = 'cc';
  181. PositionAlign.prototype = {
  182. // -- Protected Properties -------------------------------------------------
  183. /**
  184. Holds the alignment-syncing event handles.
  185. @property _posAlignUIHandles
  186. @type Array
  187. @default null
  188. @protected
  189. **/
  190. _posAlignUIHandles: null,
  191. // -- Lifecycle Methods ----------------------------------------------------
  192. destructor: function () {
  193. this._detachPosAlignUIHandles();
  194. },
  195. /**
  196. Bind event listeners responsible for updating the UI state in response to
  197. the widget's position-align related state changes.
  198. This method is invoked after `bindUI` has been invoked for the `Widget`
  199. class using the AOP infrastructure.
  200. @method _bindUIPosAlign
  201. @protected
  202. **/
  203. _bindUIPosAlign: function () {
  204. this.after('alignChange', this._afterAlignChange);
  205. this.after('alignOnChange', this._afterAlignOnChange);
  206. this.after('visibleChange', this._syncUIPosAlign);
  207. },
  208. /**
  209. Synchronizes the current `align` Attribute value to the DOM.
  210. This method is invoked after `syncUI` has been invoked for the `Widget`
  211. class using the AOP infrastructure.
  212. @method _syncUIPosAlign
  213. @protected
  214. **/
  215. _syncUIPosAlign: function () {
  216. var align = this.get(ALIGN);
  217. this._uiSetVisiblePosAlign(this.get(VISIBLE));
  218. if (align) {
  219. this._uiSetAlign(align.node, align.points);
  220. }
  221. },
  222. // -- Public Methods -------------------------------------------------------
  223. /**
  224. Aligns this widget to the provided `Node` (or viewport) using the provided
  225. points. This method can be invoked with no arguments which will cause the
  226. widget's current `align` Attribute value to be synced to the DOM.
  227. @example Aligning to the top-left corner of the `<body>`:
  228. myWidget.align('body',
  229. [Y.WidgetPositionAlign.TL, Y.WidgetPositionAlign.TR]);
  230. @method align
  231. @param {Node|String|null} [node] A reference (or selector String) for the
  232. `Node` which with the widget is to be aligned. If null is passed in, the
  233. widget will be aligned with the viewport.
  234. @param {Array[2]} [points] A two item array specifying the points on the
  235. widget and `Node`/viewport which will to be aligned. The first entry is
  236. the point on the widget, and the second entry is the point on the
  237. `Node`/viewport. Valid point references are defined as static constants on
  238. the `WidgetPositionAlign` extension.
  239. @chainable
  240. **/
  241. align: function (node, points) {
  242. if (arguments.length) {
  243. // Set the `align` Attribute.
  244. this.set(ALIGN, {
  245. node : node,
  246. points: points
  247. });
  248. } else {
  249. // Sync the current `align` Attribute value to the DOM.
  250. this._syncUIPosAlign();
  251. }
  252. return this;
  253. },
  254. /**
  255. Centers the widget in the viewport, or if a `Node` is passed in, it will
  256. be centered to that `Node`.
  257. @method centered
  258. @param {Node|String} [node] A `Node` reference or selector String defining
  259. the `Node` which the widget should be centered. If a `Node` is not passed
  260. in, then the widget will be centered to the viewport.
  261. @chainable
  262. **/
  263. centered: function (node) {
  264. return this.align(node, [PositionAlign.CC, PositionAlign.CC]);
  265. },
  266. // -- Protected Methods ----------------------------------------------------
  267. /**
  268. Default setter for `center` Attribute changes. Sets up the appropriate
  269. value, and passes it through the to the align attribute.
  270. @method _setAlignCenter
  271. @param {Boolean|Node} val The Attribute value being set.
  272. @return {Boolean|Node} the value passed in.
  273. @protected
  274. **/
  275. _setAlignCenter: function (val) {
  276. if (val) {
  277. this.set(ALIGN, {
  278. node : val === true ? null : val,
  279. points: [PositionAlign.CC, PositionAlign.CC]
  280. });
  281. }
  282. return val;
  283. },
  284. /**
  285. Updates the UI to reflect the `align` value passed in.
  286. **Note:** See the `align` Attribute documentation, for the Object structure
  287. expected.
  288. @method _uiSetAlign
  289. @param {Node|String|null} [node] The node to align to, or null to indicate
  290. the viewport.
  291. @param {Array} points The alignment points.
  292. @protected
  293. **/
  294. _uiSetAlign: function (node, points) {
  295. if ( ! Lang.isArray(points) || points.length !== 2) {
  296. Y.error('align: Invalid Points Arguments');
  297. return;
  298. }
  299. var nodeRegion = this._getRegion(node),
  300. widgetPoint, nodePoint, xy;
  301. if ( ! nodeRegion) {
  302. // No-op, nothing to align to.
  303. return;
  304. }
  305. widgetPoint = points[0];
  306. nodePoint = points[1];
  307. // TODO: Optimize KWeight - Would lookup table help?
  308. switch (nodePoint) {
  309. case PositionAlign.TL:
  310. xy = [nodeRegion.left, nodeRegion.top];
  311. break;
  312. case PositionAlign.TR:
  313. xy = [nodeRegion.right, nodeRegion.top];
  314. break;
  315. case PositionAlign.BL:
  316. xy = [nodeRegion.left, nodeRegion.bottom];
  317. break;
  318. case PositionAlign.BR:
  319. xy = [nodeRegion.right, nodeRegion.bottom];
  320. break;
  321. case PositionAlign.TC:
  322. xy = [
  323. nodeRegion.left + Math.floor(nodeRegion.width / 2),
  324. nodeRegion.top
  325. ];
  326. break;
  327. case PositionAlign.BC:
  328. xy = [
  329. nodeRegion.left + Math.floor(nodeRegion.width / 2),
  330. nodeRegion.bottom
  331. ];
  332. break;
  333. case PositionAlign.LC:
  334. xy = [
  335. nodeRegion.left,
  336. nodeRegion.top + Math.floor(nodeRegion.height / 2)
  337. ];
  338. break;
  339. case PositionAlign.RC:
  340. xy = [
  341. nodeRegion.right,
  342. nodeRegion.top + Math.floor(nodeRegion.height / 2)
  343. ];
  344. break;
  345. case PositionAlign.CC:
  346. xy = [
  347. nodeRegion.left + Math.floor(nodeRegion.width / 2),
  348. nodeRegion.top + Math.floor(nodeRegion.height / 2)
  349. ];
  350. break;
  351. default:
  352. Y.log('align: Invalid Points Arguments', 'info',
  353. 'widget-position-align');
  354. break;
  355. }
  356. if (xy) {
  357. this._doAlign(widgetPoint, xy[0], xy[1]);
  358. }
  359. },
  360. /**
  361. Attaches or detaches alignment-syncing event handlers based on the widget's
  362. `visible` Attribute state.
  363. @method _uiSetVisiblePosAlign
  364. @param {Boolean} visible The current value of the widget's `visible`
  365. Attribute.
  366. @protected
  367. **/
  368. _uiSetVisiblePosAlign: function (visible) {
  369. if (visible) {
  370. this._attachPosAlignUIHandles();
  371. } else {
  372. this._detachPosAlignUIHandles();
  373. }
  374. },
  375. /**
  376. Attaches the alignment-syncing event handlers.
  377. @method _attachPosAlignUIHandles
  378. @protected
  379. **/
  380. _attachPosAlignUIHandles: function () {
  381. if (this._posAlignUIHandles) {
  382. // No-op if we have already setup the event handlers.
  383. return;
  384. }
  385. var bb = this.get(BOUNDING_BOX),
  386. syncAlign = Y.bind(this._syncUIPosAlign, this),
  387. handles = [];
  388. Y.Array.each(this.get(ALIGN_ON), function (o) {
  389. var event = o.eventName,
  390. node = Y.one(o.node) || bb;
  391. if (event) {
  392. handles.push(node.on(event, syncAlign));
  393. }
  394. });
  395. this._posAlignUIHandles = handles;
  396. },
  397. /**
  398. Detaches the alignment-syncing event handlers.
  399. @method _detachPosAlignUIHandles
  400. @protected
  401. **/
  402. _detachPosAlignUIHandles: function () {
  403. var handles = this._posAlignUIHandles;
  404. if (handles) {
  405. new Y.EventHandle(handles).detach();
  406. this._posAlignUIHandles = null;
  407. }
  408. },
  409. // -- Private Methods ------------------------------------------------------
  410. /**
  411. Helper method, used to align the given point on the widget, with the XY page
  412. coordinates provided.
  413. @method _doAlign
  414. @param {String} widgetPoint Supported point constant
  415. (e.g. WidgetPositionAlign.TL)
  416. @param {Number} x X page coordinate to align to.
  417. @param {Number} y Y page coordinate to align to.
  418. @private
  419. **/
  420. _doAlign: function (widgetPoint, x, y) {
  421. var widgetNode = this._posNode,
  422. xy;
  423. switch (widgetPoint) {
  424. case PositionAlign.TL:
  425. xy = [x, y];
  426. break;
  427. case PositionAlign.TR:
  428. xy = [
  429. x - widgetNode.get(OFFSET_WIDTH),
  430. y
  431. ];
  432. break;
  433. case PositionAlign.BL:
  434. xy = [
  435. x,
  436. y - widgetNode.get(OFFSET_HEIGHT)
  437. ];
  438. break;
  439. case PositionAlign.BR:
  440. xy = [
  441. x - widgetNode.get(OFFSET_WIDTH),
  442. y - widgetNode.get(OFFSET_HEIGHT)
  443. ];
  444. break;
  445. case PositionAlign.TC:
  446. xy = [
  447. x - (widgetNode.get(OFFSET_WIDTH) / 2),
  448. y
  449. ];
  450. break;
  451. case PositionAlign.BC:
  452. xy = [
  453. x - (widgetNode.get(OFFSET_WIDTH) / 2),
  454. y - widgetNode.get(OFFSET_HEIGHT)
  455. ];
  456. break;
  457. case PositionAlign.LC:
  458. xy = [
  459. x,
  460. y - (widgetNode.get(OFFSET_HEIGHT) / 2)
  461. ];
  462. break;
  463. case PositionAlign.RC:
  464. xy = [
  465. x - widgetNode.get(OFFSET_WIDTH),
  466. y - (widgetNode.get(OFFSET_HEIGHT) / 2)
  467. ];
  468. break;
  469. case PositionAlign.CC:
  470. xy = [
  471. x - (widgetNode.get(OFFSET_WIDTH) / 2),
  472. y - (widgetNode.get(OFFSET_HEIGHT) / 2)
  473. ];
  474. break;
  475. default:
  476. Y.log('align: Invalid Points Argument', 'info',
  477. 'widget-position-align');
  478. break;
  479. }
  480. if (xy) {
  481. this.move(xy);
  482. }
  483. },
  484. /**
  485. Returns the region of the passed-in `Node`, or the viewport region if
  486. calling with passing in a `Node`.
  487. @method _getRegion
  488. @param {Node} [node] The node to get the region of.
  489. @return {Object} The node's region.
  490. @private
  491. **/
  492. _getRegion: function (node) {
  493. var nodeRegion;
  494. if ( ! node) {
  495. nodeRegion = this._posNode.get(VIEWPORT_REGION);
  496. } else {
  497. node = Y.Node.one(node);
  498. if (node) {
  499. nodeRegion = node.get(REGION);
  500. }
  501. }
  502. return nodeRegion;
  503. },
  504. // -- Protected Event Handlers ---------------------------------------------
  505. /**
  506. Handles `alignChange` events by updating the UI in response to `align`
  507. Attribute changes.
  508. @method _afterAlignChange
  509. @param {EventFacade} e
  510. @protected
  511. **/
  512. _afterAlignChange: function (e) {
  513. var align = e.newVal;
  514. if (align) {
  515. this._uiSetAlign(align.node, align.points);
  516. }
  517. },
  518. /**
  519. Handles `alignOnChange` events by updating the alignment-syncing event
  520. handlers.
  521. @method _afterAlignOnChange
  522. @param {EventFacade} e
  523. @protected
  524. **/
  525. _afterAlignOnChange: function(e) {
  526. this._detachPosAlignUIHandles();
  527. if (this.get(VISIBLE)) {
  528. this._attachPosAlignUIHandles();
  529. }
  530. }
  531. };
  532. Y.WidgetPositionAlign = PositionAlign;
  533. }, '3.4.0' ,{requires:['widget-position']});