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