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