3
Copyright 2012 Yahoo! Inc. All rights reserved.
4
Licensed under the BSD License.
5
http://yuilibrary.com/license/
7
YUI.add('widget-position-align', function(Y) {
10
Provides extended/advanced XY positioning support for Widgets, through an
13
It builds on top of the `widget-position` module, to provide alignment and
14
centering support. Future releases aim to add constrained and fixed positioning
17
@module widget-position-align
25
BOUNDING_BOX = 'boundingBox',
27
OFFSET_WIDTH = 'offsetWidth',
28
OFFSET_HEIGHT = 'offsetHeight',
30
VIEWPORT_REGION = 'viewportRegion';
33
Widget extension, which can be used to add extended XY positioning support to
34
the base Widget class, through the `Base.create` method.
36
**Note:** This extension requires that the `WidgetPosition` extension be added
37
to the Widget (before `WidgetPositionAlign`, if part of the same extension list
38
passed to `Base.build`).
40
@class WidgetPositionAlign
41
@param {Object} config User configuration object.
44
function PositionAlign (config) {
45
if ( ! this._posNode) {
46
Y.error('WidgetPosition needs to be added to the Widget, ' +
47
'before WidgetPositionAlign is added');
50
Y.after(this._bindUIPosAlign, this, 'bindUI');
51
Y.after(this._syncUIPosAlign, this, 'syncUI');
54
PositionAlign.ATTRS = {
57
The alignment configuration for this widget.
59
The `align` attribute is used to align a reference point on the widget, with
60
the reference point on another `Node`, or the viewport. The object which
61
`align` expects has the following properties:
63
* __`node`__: The `Node` to which the widget is to be aligned. If set to
64
`null`, or not provided, the widget is aligned to the viewport.
66
* __`points`__: A two element Array, defining the two points on the widget
67
and `Node`/viewport which are to be aligned. The first element is the
68
point on the widget, and the second element is the point on the
69
`Node`/viewport. Supported alignment points are defined as static
70
properties on `WidgetPositionAlign`.
72
@example Aligns the top-right corner of the widget with the top-left corner
75
myWidget.set('align', {
76
points: [Y.WidgetPositionAlign.TR, Y.WidgetPositionAlign.TL]
88
A convenience Attribute, which can be used as a shortcut for the `align`
91
If set to `true`, the widget is centered in the viewport. If set to a `Node`
92
reference or valid selector String, the widget will be centered within the
93
`Node`. If set to `false`, no center positioning is applied.
100
setter : '_setAlignCenter',
106
An Array of Objects corresponding to the `Node`s and events that will cause
107
the alignment of this widget to be synced to the DOM.
109
The `alignOn` Attribute is expected to be an Array of Objects with the
110
following properties:
112
* __`eventName`__: The String event name to listen for.
114
* __`node`__: The optional `Node` that will fire the event, it can be a
115
`Node` reference or a selector String. This will default to the widget's
118
@example Sync this widget's alignment on window resize:
120
myWidget.set('alignOn', [
133
validator: Y.Lang.isArray
138
Constant used to specify the top-left corner for alignment
145
PositionAlign.TL = 'tl';
148
Constant used to specify the top-right corner for alignment
155
PositionAlign.TR = 'tr';
158
Constant used to specify the bottom-left corner for alignment
165
PositionAlign.BL = 'bl';
168
Constant used to specify the bottom-right corner for alignment
175
PositionAlign.BR = 'br';
178
Constant used to specify the top edge-center point for alignment
185
PositionAlign.TC = 'tc';
188
Constant used to specify the right edge, center point for alignment
195
PositionAlign.RC = 'rc';
198
Constant used to specify the bottom edge, center point for alignment
205
PositionAlign.BC = 'bc';
208
Constant used to specify the left edge, center point for alignment
215
PositionAlign.LC = 'lc';
218
Constant used to specify the center of widget/node/viewport for alignment
225
PositionAlign.CC = 'cc';
227
PositionAlign.prototype = {
228
// -- Protected Properties -------------------------------------------------
231
Holds the alignment-syncing event handles.
233
@property _posAlignUIHandles
238
_posAlignUIHandles: null,
240
// -- Lifecycle Methods ----------------------------------------------------
242
destructor: function () {
243
this._detachPosAlignUIHandles();
247
Bind event listeners responsible for updating the UI state in response to
248
the widget's position-align related state changes.
250
This method is invoked after `bindUI` has been invoked for the `Widget`
251
class using the AOP infrastructure.
253
@method _bindUIPosAlign
256
_bindUIPosAlign: function () {
257
this.after('alignChange', this._afterAlignChange);
258
this.after('alignOnChange', this._afterAlignOnChange);
259
this.after('visibleChange', this._syncUIPosAlign);
263
Synchronizes the current `align` Attribute value to the DOM.
265
This method is invoked after `syncUI` has been invoked for the `Widget`
266
class using the AOP infrastructure.
268
@method _syncUIPosAlign
271
_syncUIPosAlign: function () {
272
var align = this.get(ALIGN);
274
this._uiSetVisiblePosAlign(this.get(VISIBLE));
277
this._uiSetAlign(align.node, align.points);
281
// -- Public Methods -------------------------------------------------------
284
Aligns this widget to the provided `Node` (or viewport) using the provided
285
points. This method can be invoked with no arguments which will cause the
286
widget's current `align` Attribute value to be synced to the DOM.
288
@example Aligning to the top-left corner of the `<body>`:
290
myWidget.align('body',
291
[Y.WidgetPositionAlign.TL, Y.WidgetPositionAlign.TR]);
294
@param {Node|String|null} [node] A reference (or selector String) for the
295
`Node` which with the widget is to be aligned. If null is passed in, the
296
widget will be aligned with the viewport.
297
@param {Array[2]} [points] A two item array specifying the points on the
298
widget and `Node`/viewport which will to be aligned. The first entry is
299
the point on the widget, and the second entry is the point on the
300
`Node`/viewport. Valid point references are defined as static constants on
301
the `WidgetPositionAlign` extension.
304
align: function (node, points) {
305
if (arguments.length) {
306
// Set the `align` Attribute.
312
// Sync the current `align` Attribute value to the DOM.
313
this._syncUIPosAlign();
320
Centers the widget in the viewport, or if a `Node` is passed in, it will
321
be centered to that `Node`.
324
@param {Node|String} [node] A `Node` reference or selector String defining
325
the `Node` which the widget should be centered. If a `Node` is not passed
326
in, then the widget will be centered to the viewport.
329
centered: function (node) {
330
return this.align(node, [PositionAlign.CC, PositionAlign.CC]);
333
// -- Protected Methods ----------------------------------------------------
336
Default setter for `center` Attribute changes. Sets up the appropriate
337
value, and passes it through the to the align attribute.
339
@method _setAlignCenter
340
@param {Boolean|Node} val The Attribute value being set.
341
@return {Boolean|Node} the value passed in.
344
_setAlignCenter: function (val) {
347
node : val === true ? null : val,
348
points: [PositionAlign.CC, PositionAlign.CC]
356
Updates the UI to reflect the `align` value passed in.
358
**Note:** See the `align` Attribute documentation, for the Object structure
362
@param {Node|String|null} [node] The node to align to, or null to indicate
364
@param {Array} points The alignment points.
367
_uiSetAlign: function (node, points) {
368
if ( ! Lang.isArray(points) || points.length !== 2) {
369
Y.error('align: Invalid Points Arguments');
373
var nodeRegion = this._getRegion(node),
374
widgetPoint, nodePoint, xy;
377
// No-op, nothing to align to.
381
widgetPoint = points[0];
382
nodePoint = points[1];
384
// TODO: Optimize KWeight - Would lookup table help?
386
case PositionAlign.TL:
387
xy = [nodeRegion.left, nodeRegion.top];
390
case PositionAlign.TR:
391
xy = [nodeRegion.right, nodeRegion.top];
394
case PositionAlign.BL:
395
xy = [nodeRegion.left, nodeRegion.bottom];
398
case PositionAlign.BR:
399
xy = [nodeRegion.right, nodeRegion.bottom];
402
case PositionAlign.TC:
404
nodeRegion.left + Math.floor(nodeRegion.width / 2),
409
case PositionAlign.BC:
411
nodeRegion.left + Math.floor(nodeRegion.width / 2),
416
case PositionAlign.LC:
419
nodeRegion.top + Math.floor(nodeRegion.height / 2)
423
case PositionAlign.RC:
426
nodeRegion.top + Math.floor(nodeRegion.height / 2)
430
case PositionAlign.CC:
432
nodeRegion.left + Math.floor(nodeRegion.width / 2),
433
nodeRegion.top + Math.floor(nodeRegion.height / 2)
443
this._doAlign(widgetPoint, xy[0], xy[1]);
448
Attaches or detaches alignment-syncing event handlers based on the widget's
449
`visible` Attribute state.
451
@method _uiSetVisiblePosAlign
452
@param {Boolean} visible The current value of the widget's `visible`
456
_uiSetVisiblePosAlign: function (visible) {
458
this._attachPosAlignUIHandles();
460
this._detachPosAlignUIHandles();
465
Attaches the alignment-syncing event handlers.
467
@method _attachPosAlignUIHandles
470
_attachPosAlignUIHandles: function () {
471
if (this._posAlignUIHandles) {
472
// No-op if we have already setup the event handlers.
476
var bb = this.get(BOUNDING_BOX),
477
syncAlign = Y.bind(this._syncUIPosAlign, this),
480
Y.Array.each(this.get(ALIGN_ON), function (o) {
481
var event = o.eventName,
482
node = Y.one(o.node) || bb;
485
handles.push(node.on(event, syncAlign));
489
this._posAlignUIHandles = handles;
493
Detaches the alignment-syncing event handlers.
495
@method _detachPosAlignUIHandles
498
_detachPosAlignUIHandles: function () {
499
var handles = this._posAlignUIHandles;
501
new Y.EventHandle(handles).detach();
502
this._posAlignUIHandles = null;
506
// -- Private Methods ------------------------------------------------------
509
Helper method, used to align the given point on the widget, with the XY page
510
coordinates provided.
513
@param {String} widgetPoint Supported point constant
514
(e.g. WidgetPositionAlign.TL)
515
@param {Number} x X page coordinate to align to.
516
@param {Number} y Y page coordinate to align to.
519
_doAlign: function (widgetPoint, x, y) {
520
var widgetNode = this._posNode,
523
switch (widgetPoint) {
524
case PositionAlign.TL:
528
case PositionAlign.TR:
530
x - widgetNode.get(OFFSET_WIDTH),
535
case PositionAlign.BL:
538
y - widgetNode.get(OFFSET_HEIGHT)
542
case PositionAlign.BR:
544
x - widgetNode.get(OFFSET_WIDTH),
545
y - widgetNode.get(OFFSET_HEIGHT)
549
case PositionAlign.TC:
551
x - (widgetNode.get(OFFSET_WIDTH) / 2),
556
case PositionAlign.BC:
558
x - (widgetNode.get(OFFSET_WIDTH) / 2),
559
y - widgetNode.get(OFFSET_HEIGHT)
563
case PositionAlign.LC:
566
y - (widgetNode.get(OFFSET_HEIGHT) / 2)
570
case PositionAlign.RC:
572
x - widgetNode.get(OFFSET_WIDTH),
573
y - (widgetNode.get(OFFSET_HEIGHT) / 2)
577
case PositionAlign.CC:
579
x - (widgetNode.get(OFFSET_WIDTH) / 2),
580
y - (widgetNode.get(OFFSET_HEIGHT) / 2)
595
Returns the region of the passed-in `Node`, or the viewport region if
596
calling with passing in a `Node`.
599
@param {Node} [node] The node to get the region of.
600
@return {Object} The node's region.
603
_getRegion: function (node) {
607
nodeRegion = this._posNode.get(VIEWPORT_REGION);
609
node = Y.Node.one(node);
611
nodeRegion = node.get(REGION);
618
// -- Protected Event Handlers ---------------------------------------------
621
Handles `alignChange` events by updating the UI in response to `align`
624
@method _afterAlignChange
625
@param {EventFacade} e
628
_afterAlignChange: function (e) {
629
var align = e.newVal;
631
this._uiSetAlign(align.node, align.points);
636
Handles `alignOnChange` events by updating the alignment-syncing event
639
@method _afterAlignOnChange
640
@param {EventFacade} e
643
_afterAlignOnChange: function(e) {
644
this._detachPosAlignUIHandles();
646
if (this.get(VISIBLE)) {
647
this._attachPosAlignUIHandles();
652
Y.WidgetPositionAlign = PositionAlign;
655
}, '3.5.1' ,{requires:['widget-position']});