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