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