]> git.ipfire.org Git - thirdparty/foundation/foundation-sites.git/commitdiff
Create explicit positioning method for Box and move dropdown positioning to be EXPLICIT
authorKevin Ball <kmball11@gmail.com>
Sat, 20 May 2017 04:32:34 +0000 (21:32 -0700)
committerKevin Ball <kmball11@gmail.com>
Sat, 20 May 2017 04:32:34 +0000 (21:32 -0700)
js/foundation.dropdown.js
js/foundation.util.box.js
test/visual/dropdown/explicit-positioning.html [new file with mode: 0644]
test/visual/dropdown/offsets.html
test/visual/dropdown/overflow.html [new file with mode: 0644]

index db63ba200e8d682bcb2c6cd9f1a5c6e47c9332df..5b078b1e0eb3bd31ad4261729fc0816bbe2c7a72 100644 (file)
@@ -3,7 +3,7 @@
 import $ from 'jquery';
 import { Keyboard } from './foundation.util.keyboard';
 import { Box } from './foundation.util.box';
-import { GetYoDigits } from './foundation.util.core';
+import { GetYoDigits, rtl as Rtl } from './foundation.util.core';
 import { Plugin } from './foundation.plugin';
 
   // import "foundation.util.triggers.js";
@@ -18,6 +18,17 @@ import { Plugin } from './foundation.plugin';
  * @requires foundation.util.triggers
  */
 
+const POSITIONS = ['left', 'right', 'top', 'bottom'];
+const VERTICAL_ALIGNMENTS = ['top', 'bottom', 'center'];
+const HORIZONTAL_ALIGNMENTS = ['left', 'right', 'center'];
+
+const ALIGNMENTS = {
+  'left': VERTICAL_ALIGNMENTS,
+  'right': VERTICAL_ALIGNMENTS,
+  'top': HORIZONTAL_ALIGNMENTS,
+  'bottom': HORIZONTAL_ALIGNMENTS
+}
+
 class Dropdown extends Plugin {
   /**
    * Creates a new instance of a dropdown.
@@ -61,9 +72,9 @@ class Dropdown extends Plugin {
     }else{
       this.$parent = null;
     }
-    this.options.positionClass = this.getPositionClass();
-    this.counter = 4;
-    this.usedPositions = [];
+    this._setupPositionAndAlignment();
+
+    this.triedPositions = {};
     this.$element.attr({
       'aria-hidden': 'true',
       'data-yeti-box': $id,
@@ -73,6 +84,18 @@ class Dropdown extends Plugin {
     this._events();
   }
 
+  _setupPositionAndAlignment() {
+    if(this.options.position === 'left' || this.options.position === 'right') {
+      this.isHorizontallyPositioned = true;
+    }
+    if(this.options.position === 'top' || this.options.position === 'bottom') {
+      this.isVerticallyPositioned = true;
+    }
+
+    this.position  = this.options.position === 'auto' ? this._getDefaultPosition() : this.options.position;
+    this.alignment = this.options.alignment === 'auto' ? this._getDefaultAlignment() : this.options.alignment;
+  }
+
   /**
    * Helper function to determine current orientation of dropdown pane.
    * @function
@@ -88,86 +111,97 @@ class Dropdown extends Plugin {
     return position;
   }
 
+  _getDefaultPosition() {
+    // handle legacy classnames
+    var position = this.$element[0].className.match(/(top|left|right|bottom)/g);
+    if(position) {
+      return position[0];
+    } else {
+      return 'bottom'
+    }
+  }
+
+  _getDefaultAlignment() {
+    // handle legacy float appraoch
+    var horizontalPosition = /float-(\S+)/.exec(this.$anchor[0].className);
+    if(horizontalPosition) {
+      return horizontalPosition[1];
+    }
+
+    switch(this.position) {
+      case 'bottom':
+      case 'top':
+        return Rtl() ? 'left' : 'right';
+      case 'left':
+      case 'right':
+        return 'bottom';
+    }
+  }
+
   /**
-   * Adjusts the dropdown panes orientation by adding/removing positioning classes.
+   * Adjusts the dropdown pane possible positions by iterating through alignments
+   * and positions. NOTE: Only used if position is auto, otherwise only alignments
+   * will be tried within the specified position.
    * @function
    * @private
-   * @param {String} position - position class to remove.
    */
-  _reposition(position) {
-    this.usedPositions.push(position ? position : 'bottom');
-    //default, try switching to opposite side
-    if(!position && (this.usedPositions.indexOf('top') < 0)){
-      this.$element.addClass('top');
-    }else if(position === 'top' && (this.usedPositions.indexOf('bottom') < 0)){
-      this.$element.removeClass(position);
-    }else if(position === 'left' && (this.usedPositions.indexOf('right') < 0)){
-      this.$element.removeClass(position)
-          .addClass('right');
-    }else if(position === 'right' && (this.usedPositions.indexOf('left') < 0)){
-      this.$element.removeClass(position)
-          .addClass('left');
-    }
+  _reposition() {
+  }
+
 
-    //if default change didn't work, try bottom or left first
-    else if(!position && (this.usedPositions.indexOf('top') > -1) && (this.usedPositions.indexOf('left') < 0)){
-      this.$element.addClass('left');
-    }else if(position === 'top' && (this.usedPositions.indexOf('bottom') > -1) && (this.usedPositions.indexOf('left') < 0)){
-      this.$element.removeClass(position)
-          .addClass('left');
-    }else if(position === 'left' && (this.usedPositions.indexOf('right') > -1) && (this.usedPositions.indexOf('bottom') < 0)){
-      this.$element.removeClass(position);
-    }else if(position === 'right' && (this.usedPositions.indexOf('left') > -1) && (this.usedPositions.indexOf('bottom') < 0)){
-      this.$element.removeClass(position);
+  /**
+   * Adjusts the dropdown pane possible positions by iterating through alignments
+   * on the current position.
+   * @function
+   * @private
+   */
+  _realign() {
+    this._addTriedPosition(this.position, this.alignment)
+    var alignments = ALIGNMENTS[this.position]
+    var currentIdx = alignments.indexOf(this.alignment);
+    if(currentIdx === alignments.length - 1) {
+      this.alignment = alignments[0];
+    } else {
+      this.alignment = alignments[currentIdx + 1];
     }
-    //if nothing cleared, set to bottom
-    else{
-      this.$element.removeClass(position);
+  }
+
+  _addTriedPosition(position, alignment) {
+    this.triedPositions[position] = this.triedPositions[position] || []
+    this.triedPositions[position].push(alignment);
+  }
+
+  _positionsExhausted() {
+    if(this.options.position === 'auto') {
+    } else {
+      return this.triedPositions[this.position] && this.triedPositions[this.position].length == ALIGNMENTS[this.position].length;
     }
-    this.classChanged = true;
-    this.counter--;
   }
 
   /**
-   * Sets the position and orientation of the dropdown pane, checks for collisions.
+   * Sets the position and orientation of the dropdown pane, checks for collisions if allow-overlap is not true.
    * Recursively calls itself if a collision is detected, with a new position class.
    * @function
    * @private
    */
   _setPosition() {
     if(this.$anchor.attr('aria-expanded') === 'false'){ return false; }
-    var position = this.getPositionClass(),
-        $eleDims = Box.GetDimensions(this.$element),
-        $anchorDims = Box.GetDimensions(this.$anchor),
-        _this = this,
-        direction = (position === 'left' ? 'left' : ((position === 'right') ? 'left' : 'top')),
-        param = (direction === 'top') ? 'height' : 'width',
-        offset = (param === 'height') ? this.options.vOffset : this.options.hOffset;
-
-    if(($eleDims.width >= $eleDims.windowDims.width) || (!this.counter && !Box.ImNotTouchingYou(this.$element, this.$parent))){
-      var newWidth = $eleDims.windowDims.width,
-          parentHOffset = 0;
-      if(this.$parent){
-        var $parentDims = Box.GetDimensions(this.$parent),
-            parentHOffset = $parentDims.offset.left;
-        if ($parentDims.width < newWidth){
-          newWidth = $parentDims.width;
-        }
-      }
+    var $eleDims = Box.GetDimensions(this.$element),
+        $anchorDims = Box.GetDimensions(this.$anchor);
 
-      this.$element.offset(Box.GetOffsets(this.$element, this.$anchor, 'center bottom', this.options.vOffset, this.options.hOffset + parentHOffset, true)).css({
-        'width': newWidth - (this.options.hOffset * 2),
-        'height': 'auto'
-      });
-      this.classChanged = true;
-      return false;
-    }
 
-    this.$element.offset(Box.GetOffsets(this.$element, this.$anchor, position, this.options.vOffset, this.options.hOffset));
+    this.$element.offset(Box.GetExplicitOffsets(this.$element, this.$anchor, this.position, this.alignment, this.options.vOffset, this.options.hOffset));
 
-    while(!Box.ImNotTouchingYou(this.$element, this.$parent, true) && this.counter){
-      this._reposition(position);
-      this._setPosition();
+    if(!this.options.allowOverlap) {
+      while(!Box.ImNotTouchingYou(this.$element, this.$parent, this.isVerticallyPositioned, this.isHorizontallyPositioned) && !this._positionsExhausted()){
+        if(this.options.position === 'auto') {
+          this._reposition();
+        } else {
+          console.log('realigning');
+          this._realign();
+        }
+        this._setPosition();
+      }
     }
   }
 
@@ -393,16 +427,16 @@ Dropdown.defaults = {
    * Number of pixels between the dropdown pane and the triggering element on open.
    * @option
    * @type {number}
-   * @default 1
+   * @default 0
    */
-  vOffset: 1,
+  vOffset: 0,
   /**
    * Number of pixels between the dropdown pane and the triggering element on open.
    * @option
    * @type {number}
-   * @default 1
+   * @default 0
    */
-  hOffset: 1,
+  hOffset: 0,
   /**
    * Class applied to adjust open position. JS will test and fill this in.
    * @option
@@ -410,6 +444,28 @@ Dropdown.defaults = {
    * @default ''
    */
   positionClass: '',
+
+  /**
+   * Position of dropdown. Can be left, right, bottom, top, or auto.
+   * @option
+   * @type {string}
+   * @default 'auto'
+   */
+  position: 'auto',
+  /**
+   * Alignment of dropdown relative to anchor. Can be left, right, bottom, top, center, or auto.
+   * @option
+   * @type {string}
+   * @default 'auto'
+   */
+  alignment: 'auto',
+  /**
+   * Allow overlap of container/window. If false, dropdown will first try to position as defined by data-position and data-alignment, but reposition if it would cause an overflow.
+   * @option
+   * @type {boolean}
+   * @default false
+   */
+  allowOverlap: false,
   /**
    * Allow the plugin to trap focus to the dropdown pane if opened with keyboard commands.
    * @option
index ca13f8c9cfc50f3290357c3e029a2ceb24aa0af0..a5c6d082fb4d540a3621079458a27b415e83cb59 100644 (file)
@@ -6,7 +6,8 @@ import { rtl as Rtl } from "./foundation.util.core";
 var Box = {
   ImNotTouchingYou: ImNotTouchingYou,
   GetDimensions: GetDimensions,
-  GetOffsets: GetOffsets
+  GetOffsets: GetOffsets,
+  GetExplicitOffsets: GetExplicitOffsets
 }
 
 /**
@@ -99,7 +100,9 @@ function GetDimensions(elem, test){
 
 /**
  * Returns an object of top and left integer pixel values for dynamically rendered elements,
- * such as: Tooltip, Reveal, and Dropdown
+ * such as: Tooltip, Reveal, and Dropdown. Maintained for backwards compatibility, and where
+ * you don't know alignment, but generally from
+ * 6.4 forward you should use GetExplicitOffsets, as GetOffsets conflates position and alignment.
  * @function
  * @param {jQuery} element - jQuery object for the element being positioned.
  * @param {jQuery} anchor - jQuery object for the element's anchor point.
@@ -110,58 +113,34 @@ function GetDimensions(elem, test){
  * TODO alter/rewrite to work with `em` values as well/instead of pixels
  */
 function GetOffsets(element, anchor, position, vOffset, hOffset, isOverflow) {
-  var $eleDims = GetDimensions(element),
-      $anchorDims = anchor ? GetDimensions(anchor) : null;
-
   switch (position) {
     case 'top':
-      return {
-        left: (Rtl() ? $anchorDims.offset.left - $eleDims.width + $anchorDims.width - hOffset: $anchorDims.offset.left + hOffset),
-        top: $anchorDims.offset.top - ($eleDims.height + vOffset)
-      }
-      break;
-    case 'left':
-      return {
-        left: $anchorDims.offset.left - ($eleDims.width + hOffset),
-        top: $anchorDims.offset.top + vOffset
-      }
-      break;
-    case 'right':
-      return {
-        left: $anchorDims.offset.left + $anchorDims.width + hOffset,
-        top: $anchorDims.offset.top + vOffset
-      }
-      break;
+      return Rtl() ?
+        GetExplicitOffsets(element, anchor, 'top', 'left', vOffset, hOffset, isOverflow) :
+        GetExplicitOffsets(element, anchor, 'top', 'right', vOffset, hOffset, isOverflow);
+    case 'bottom':
+      return Rtl() ?
+        GetExplicitOffsets(element, anchor, 'bottom', 'left', vOffset, hOffset, isOverflow) :
+        GetExplicitOffsets(element, anchor, 'bottom', 'right', vOffset, hOffset, isOverflow);
     case 'center top':
-      return {
-        left: ($anchorDims.offset.left + ($anchorDims.width / 2)) - ($eleDims.width / 2) + hOffset,
-        top: $anchorDims.offset.top - ($eleDims.height + vOffset)
-      }
-      break;
+      return GetExplicitOffsets(element, anchor, 'top', 'center', vOffset, hOffset, isOverflow);
     case 'center bottom':
-      return {
-        left: isOverflow ? hOffset : (($anchorDims.offset.left + ($anchorDims.width / 2)) - ($eleDims.width / 2)) + hOffset,
-        top: $anchorDims.offset.top + $anchorDims.height + vOffset
-      }
-      break;
+      return GetExplicitOffsets(element, anchor, 'bottom', 'center', vOffset, hOffset, isOverflow);
     case 'center left':
-      return {
-        left: $anchorDims.offset.left - ($eleDims.width + hOffset),
-        top: ($anchorDims.offset.top + vOffset + ($anchorDims.height / 2)) - ($eleDims.height / 2)
-      }
-      break;
+      return GetExplicitOffsets(element, anchor, 'left', 'center', vOffset, hOffset, isOverflow);
     case 'center right':
-      return {
-        left: $anchorDims.offset.left + $anchorDims.width + hOffset + 1,
-        top: ($anchorDims.offset.top + ($anchorDims.height / 2)) - ($eleDims.height / 2) + vOffset
-      }
-      break;
+      return GetExplicitOffsets(element, anchor, 'right', 'center', vOffset, hOffset, isOverflow);
+    case 'left bottom':
+      return GetExplicitOffsets(element, anchor, 'bottom', 'left', vOffset, hOffset, isOverflow);
+    case 'right bottom':
+      return GetExplicitOffsets(element, anchor, 'bottom', 'right', vOffset, hOffset, isOverflow);
+    // Backwards compatibility... this along with the reveal and reveal full
+    // classes are the only ones that didn't reference anchor
     case 'center':
       return {
         left: ($eleDims.windowDims.offset.left + ($eleDims.windowDims.width / 2)) - ($eleDims.width / 2) + hOffset,
         top: ($eleDims.windowDims.offset.top + ($eleDims.windowDims.height / 2)) - ($eleDims.height / 2 + vOffset)
       }
-      break;
     case 'reveal':
       return {
         left: ($eleDims.windowDims.width - $eleDims.width) / 2 + hOffset,
@@ -173,24 +152,72 @@ function GetOffsets(element, anchor, position, vOffset, hOffset, isOverflow) {
         top: $eleDims.windowDims.offset.top
       }
       break;
-    case 'left bottom':
-      return {
-        left: $anchorDims.offset.left - hOffset,
-        top: $anchorDims.offset.top + $anchorDims.height + vOffset
-      };
-      break;
-    case 'right bottom':
-      return {
-        left: $anchorDims.offset.left + $anchorDims.width + hOffset - $eleDims.width,
-        top: $anchorDims.offset.top + $anchorDims.height + vOffset
-      };
-      break;
     default:
       return {
         left: (Rtl() ? $anchorDims.offset.left - $eleDims.width + $anchorDims.width - hOffset: $anchorDims.offset.left + hOffset),
         top: $anchorDims.offset.top + $anchorDims.height + vOffset
       }
+
+  }
+
+}
+
+function GetExplicitOffsets(element, anchor, position, alignment, vOffset, hOffset, isOverflow) {
+  var $eleDims = GetDimensions(element),
+      $anchorDims = anchor ? GetDimensions(anchor) : null;
+
+      var topVal, leftVal;
+
+  // set position related attribute
+
+  switch (position) {
+    case 'top':
+      topVal = $anchorDims.offset.top - ($eleDims.height + vOffset);
+      break;
+    case 'bottom':
+      topVal = $anchorDims.offset.top + $anchorDims.height + vOffset;
+      break;
+    case 'left':
+      leftVal = $anchorDims.offset.left - ($eleDims.width + hOffset);
+      break;
+    case 'right':
+      leftVal = $anchorDims.offset.left + $anchorDims.width + hOffset;
+      break;
+  }
+
+
+  // set alignment related attribute
+  switch (position) {
+    case 'top':
+    case 'bottom':
+      switch (alignment) {
+        case 'left':
+          leftVal = $anchorDims.offset.left + hOffset;
+          break;
+        case 'right':
+          leftVal = $anchorDims.offset.left - $eleDims.width + $anchorDims.width - hOffset;
+          break;
+        case 'center':
+          leftVal = isOverflow ? hOffset : (($anchorDims.offset.left + ($anchorDims.width / 2)) - ($eleDims.width / 2)) + hOffset;
+          break;
+      }
+      break;
+    case 'right':
+    case 'left':
+      switch (alignment) {
+        case 'bottom':
+          topVal = $anchorDims.offset.top - vOffset + $anchorDims.height - $eleDims.height;
+          break;
+        case 'top':
+          topVal = $anchorDims.offset.top + vOffset
+          break;
+        case 'center':
+          topVal = ($anchorDims.offset.top + vOffset + ($anchorDims.height / 2)) - ($eleDims.height / 2)
+          break;
+      }
+      break;
   }
+  return {top: topVal, left: leftVal};
 }
 
 export {Box};
diff --git a/test/visual/dropdown/explicit-positioning.html b/test/visual/dropdown/explicit-positioning.html
new file mode 100644 (file)
index 0000000..935ca24
--- /dev/null
@@ -0,0 +1,127 @@
+<!doctype html>
+<!--[if IE 9]><html class="lt-ie10" lang="en" > <![endif]-->
+<html class="no-js" lang="en" dir="ltr">
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <title>Foundation for Sites Testing</title>
+    <link href="../assets/css/foundation.css" rel="stylesheet" />
+  </head>
+  <body>
+    <div class="row column">
+      <h1>Dropdown: Explicit Positioning Content - no offsets</h1>
+
+      <p>These dropdowns test various positioning and alignments. Valid
+         positions are left/right/top/bottom.  Valid alignments are
+         left/right/top/bottom/center. Left align means left sides should line up.
+         Right align means right sides should line up. Center align means centers should line up.
+      </p>
+
+      <h4>Top and Bottom positioned</h4>
+      <div class="row small-up-1 medium-up-3">
+        <div class="column">
+          <p>Bottom Left</p>
+          <button class="button" type="button" data-toggle="example-dropdown-bottom-left">Toggle Dropdown</button>
+          <div class="dropdown-pane" data-position="bottom" data-alignment="left" id="example-dropdown-bottom-left" data-dropdown data-auto-focus="true">
+            <p>This dropdown has position bottom and alignment left should align with its top left corner at the bottom left of the button</p>
+          </div>
+        </div>
+
+        <div class="column">
+          <p>Bottom Center</p>
+          <button class="button" type="button" data-toggle="example-dropdown-bottom-center">Toggle Dropdown</button>
+          <div class="dropdown-pane" data-position="bottom" data-alignment="center" id="example-dropdown-bottom-center" data-dropdown data-auto-focus="true">
+            <p>This dropdown has position bottom and alignment center should align below the button with its center aligned with the center of the button</p>
+          </div>
+        </div>
+
+        <div class="column">
+          <p>Bottom Right</p>
+          <button class="button" type="button" data-toggle="example-dropdown-bottom-right">Toggle Dropdown</button>
+          <div class="dropdown-pane" data-position="bottom" data-alignment="right" id="example-dropdown-bottom-right" data-dropdown data-auto-focus="true">
+            <p>This dropdown has position bottom and alignment right should align with its top right corner at the bottom right of the button</p>
+          </div>
+        </div>
+
+        <div class="column">
+          <p>Top Left</p>
+          <button class="button" type="button" data-toggle="example-dropdown-top-left">Toggle Dropdown</button>
+          <div class="dropdown-pane" data-position="top" data-alignment="left" id="example-dropdown-top-left" data-dropdown data-auto-focus="true">
+            <p>This dropdown has position top and alignment left should align with its bottom left corner at the top left of the button</p>
+          </div>
+        </div>
+
+        <div class="column">
+          <p>Top Center</p>
+          <button class="button" type="button" data-toggle="example-dropdown-top-center">Toggle Dropdown</button>
+          <div class="dropdown-pane" data-position="top" data-alignment="center" id="example-dropdown-top-center" data-dropdown data-auto-focus="true">
+            <p>This dropdown has position top and alignment center should align above with its center aligned with the center of the button</p>
+          </div>
+        </div>
+
+        <div class="column">
+          <p>Top Right</p>
+          <button class="button" type="button" data-toggle="example-dropdown-top-right">Toggle Dropdown</button>
+          <div class="dropdown-pane" data-position="top" data-alignment="right" id="example-dropdown-top-right" data-dropdown data-auto-focus="true">
+            <p>This dropdown has position top and alignment right should align with its bottom right corner at the top right of the button</p>
+          </div>
+        </div>
+      </div>
+
+
+      <h4>Left and Right Positioned</h4>
+      <div class="row small-up-1 medium-up-2">
+        <div class="column">
+          <p>Right Top</p>
+          <button class="button" type="button" data-toggle="example-dropdown-right-top">Toggle Dropdown</button>
+          <div class="dropdown-pane" data-position="right" data-alignment="top" id="example-dropdown-right-top" data-dropdown data-auto-focus="true">
+            <p>This dropdown has position right and alignment top should align with its top left corner at the top right of the button</p>
+          </div>
+        </div>
+        <div class="column">
+          <p>Left Top</p>
+          <button class="button" type="button" data-toggle="example-dropdown-left-top">Toggle Dropdown</button>
+          <div class="dropdown-pane" data-position="left" data-alignment="top" id="example-dropdown-left-top" data-dropdown data-auto-focus="true">
+            <p>This dropdown has position left and alignment top should align with its top right corner at the top left of the button</p>
+          </div>
+        </div>
+
+        <div class="column">
+          <p>Right Center</p>
+          <button class="button" type="button" data-toggle="example-dropdown-right-center">Toggle Dropdown</button>
+          <div class="dropdown-pane" data-position="right" data-alignment="center" id="example-dropdown-right-center" data-dropdown data-auto-focus="true">
+            <p>This dropdown has position right and alignment center should align to the right of the button with the center of the dropdown vertically aligned with the center of the button</p>
+          </div>
+        </div>
+        <div class="column">
+          <p>Left Center</p>
+          <button class="button" type="button" data-toggle="example-dropdown-left-center">Toggle Dropdown</button>
+          <div class="dropdown-pane" data-position="left" data-alignment="center" id="example-dropdown-left-center" data-dropdown data-auto-focus="true">
+            <p>This dropdown has position left and alignment center should align to the left of the button with the center of the dropdown vertically aligned with the center of the button</p>
+          </div>
+        </div>
+
+        <div class="column">
+          <p>Right Bottom</p>
+          <button class="button" type="button" data-toggle="example-dropdown-right-bottom">Toggle Dropdown</button>
+          <div class="dropdown-pane" data-position="right" data-alignment="bottom" id="example-dropdown-right-bottom" data-dropdown data-auto-focus="true">
+            <p>This dropdown has position right and alignment bottom should align with its bottom left corner at the bottom right of the button</p>
+          </div>
+        </div>
+        <div class="column">
+          <p>Left Bottom</p>
+          <button class="button" type="button" data-toggle="example-dropdown-left-bottom">Toggle Dropdown</button>
+          <div class="dropdown-pane" data-position="left" data-alignment="bottom" id="example-dropdown-left-bottom" data-dropdown data-auto-focus="true">
+            <p>This dropdown has position left and alignment bottom should align with its bottom right corner at the bottom left of the button</p>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <script src="../assets/js/vendor.js"></script>
+    <script src="../assets/js/foundation.js"></script>
+    <script>
+      $(document).foundation();
+    </script>
+  </body>
+</html>
index 5f847019d66bd2b19f1d0e92f6cbb2932fe7d18b..25ec2a8e0814759765d4212c6b70823f0307ea2f 100644 (file)
   </head>
   <body>
     <div class="row column">
-      <h1>Dropdown: Positioning Content</h1>
+      <h1>Dropdown: Explicit Positioning Content - with offsets</h1>
 
-      <p>These dropdowns test various positioning and position offsets</p>
+      <p>These dropdowns test various positioning and alignments WITH OFFSETS. 
+         Valid positions are left/right/top/bottom.  Valid alignments are
+         left/right/top/bottom/center. Left align means left sides should line up.
+         Right align means right sides should line up. Center align means centers should line up.
+         Positive Offsets should always be applied in a direction to create
+         space between the anchor and the dropdown.
+      </p>
 
-      <p>This dropdown should be offset by 10 down and 30 to the right</p>
-      <button class="button" type="button" data-toggle="example-dropdown">Toggle Dropdown</button>
-      <div class="dropdown-pane" id="example-dropdown" data-dropdown data-v-offset="10" data-h-offset="30" data-auto-focus="true">
-        <p>This dropdown should be offset by 10 down and 30 to the right</p>
-      </div>
-      <p>This dropdown has position left and alignment center, and should go off the screen left because it has allow-overlap true</p>
-      <button class="button" type="button" data-toggle="example-dropdown2">Toggle Dropdown</button>
-      <div class="dropdown-pane" data-position="left" data-alignment="center" data-allow-overlap="true" data-id="example-dropdown2" data-dropdown data-auto-focus="true">
-        <p>This dropdown should go off the screen left because it is 100% explicitly positioned.</p>
-      </div>
-      <p>This dropdown has position left and should go left if there is room and otherwise below</p>
-      <button class="button" type="button" data-toggle="example-dropdown3">Toggle Dropdown</button>
-      <div class="dropdown-pane" data-position="left" id="example-dropdown3" data-dropdown data-auto-focus="true">
-        <p>This dropdown should go left if there is room and otherwise below</p>
-      </div>
-      <p>This dropdown has position bottom and alignment left should align with its top right corner at the bottom right of the button</p>
-      <button class="button" type="button" data-toggle="example-dropdown4">Toggle Dropdown</button>
-      <div class="dropdown-pane" data-position="bottom" data-alignment="left" id="example-dropdown4" data-dropdown data-auto-focus="true">
-        <p>This dropdown has position bottom and alignment left should align with its top right corner at the bottom right of the button</p>
+      <h4>Top and Bottom positioned</h4>
+      <div class="row small-up-1 medium-up-3">
+        <div class="column">
+          <p>Bottom Left</p>
+          <button class="button" type="button" data-toggle="example-dropdown-bottom-left">Toggle Dropdown</button>
+          <div class="dropdown-pane" data-h-offset="50" data-v-offset="50" data-position="bottom" data-alignment="left" id="example-dropdown-bottom-left" data-dropdown data-auto-focus="true">
+            <p>This offset should push right and down.</p>
+          </div>
+        </div>
+
+        <div class="column">
+          <p>Bottom Center</p>
+          <button class="button" type="button" data-toggle="example-dropdown-bottom-center">Toggle Dropdown</button>
+          <div class="dropdown-pane" data-h-offset="50" data-v-offset="50" data-position="bottom" data-alignment="center" id="example-dropdown-bottom-center" data-dropdown data-auto-focus="true">
+            <p>This offset should push right and down.</p>
+          </div>
+        </div>
+
+        <div class="column">
+          <p>Bottom Right</p>
+          <button class="button" type="button" data-toggle="example-dropdown-bottom-right">Toggle Dropdown</button>
+          <div class="dropdown-pane" data-h-offset="50" data-v-offset="50" data-position="bottom" data-alignment="right" id="example-dropdown-bottom-right" data-dropdown data-auto-focus="true">
+            <p>This offset should push left and down.</p>
+          </div>
+        </div>
+
+        <div class="column">
+          <p>Top Left</p>
+          <button class="button" type="button" data-toggle="example-dropdown-top-left">Toggle Dropdown</button>
+          <div class="dropdown-pane" data-h-offset="50" data-v-offset="50" data-position="top" data-alignment="left" id="example-dropdown-top-left" data-dropdown data-auto-focus="true">
+            <p>This offset should push right and up.</p>
+          </div>
+        </div>
+
+        <div class="column">
+          <p>Top Center</p>
+          <button class="button" type="button" data-toggle="example-dropdown-top-center">Toggle Dropdown</button>
+          <div class="dropdown-pane" data-h-offset="50" data-v-offset="50" data-position="top" data-alignment="center" id="example-dropdown-top-center" data-dropdown data-auto-focus="true">
+            <p>This offset should push right and up.</p>
+          </div>
+        </div>
+
+        <div class="column">
+          <p>Top Right</p>
+          <button class="button" type="button" data-toggle="example-dropdown-top-right">Toggle Dropdown</button>
+          <div class="dropdown-pane" data-h-offset="50" data-v-offset="50" data-position="top" data-alignment="right" id="example-dropdown-top-right" data-dropdown data-auto-focus="true">
+            <p>This offset should push left and up.</p>
+          </div>
+        </div>
       </div>
-      <p>This dropdown has position left and alignment top should align with its bottom right corner at the bottom left corner of the butotn</p>
-      <button class="button" type="button" data-toggle="example-dropdown5">Toggle Dropdown</button>
-      <div class="dropdown-pane" data-position="left" data-alignment="top" id="example-dropdown5" data-dropdown data-auto-focus="true">
-        <p>This dropdown has position left and alignment top should align with its bottom right corner at the bottom left corner of the butotn</p>
+
+
+      <h4>Left and Right Positioned</h4>
+      <div class="row small-up-1 medium-up-2">
+        <div class="column">
+          <p>Right Top</p>
+          <button class="button" type="button" data-toggle="example-dropdown-right-top">Toggle Dropdown</button>
+          <div class="dropdown-pane" data-h-offset="50" data-v-offset="50" data-position="right" data-alignment="top" id="example-dropdown-right-top" data-dropdown data-auto-focus="true">
+            <p>This offset should push right and down.</p>
+          </div>
+        </div>
+        <div class="column">
+          <p>Left Top</p>
+          <button class="button" type="button" data-toggle="example-dropdown-left-top">Toggle Dropdown</button>
+          <div class="dropdown-pane" data-h-offset="50" data-v-offset="50" data-position="left" data-alignment="top" id="example-dropdown-left-top" data-dropdown data-auto-focus="true">
+            <p>This offset should push left and down.</p>
+          </div>
+        </div>
+
+        <div class="column">
+          <p>Right Center</p>
+          <button class="button" type="button" data-toggle="example-dropdown-right-center">Toggle Dropdown</button>
+          <div class="dropdown-pane" data-h-offset="50" data-v-offset="50" data-position="right" data-alignment="center" id="example-dropdown-right-center" data-dropdown data-auto-focus="true">
+            <p>This offset should push right and down.</p>
+          </div>
+        </div>
+        <div class="column">
+          <p>Left Center</p>
+          <button class="button" type="button" data-toggle="example-dropdown-left-center">Toggle Dropdown</button>
+          <div class="dropdown-pane" data-h-offset="50" data-v-offset="50" data-position="left" data-alignment="center" id="example-dropdown-left-center" data-dropdown data-auto-focus="true">
+            <p>This offset should push left and down.</p>
+          </div>
+        </div>
+
+        <div class="column">
+          <p>Right Bottom</p>
+          <button class="button" type="button" data-toggle="example-dropdown-right-bottom">Toggle Dropdown</button>
+          <div class="dropdown-pane" data-h-offset="50" data-v-offset="50" data-position="right" data-alignment="bottom" id="example-dropdown-right-bottom" data-dropdown data-auto-focus="true">
+            <p>This offset should push right and up.</p>
+          </div>
+        </div>
+        <div class="column">
+          <p>Left Bottom</p>
+          <button class="button" type="button" data-toggle="example-dropdown-left-bottom">Toggle Dropdown</button>
+          <div class="dropdown-pane" data-h-offset="50" data-v-offset="50" data-position="left" data-alignment="bottom" id="example-dropdown-left-bottom" data-dropdown data-auto-focus="true">
+            <p>This offset should push left and up.</p>
+          </div>
+        </div>
       </div>
     </div>
 
diff --git a/test/visual/dropdown/overflow.html b/test/visual/dropdown/overflow.html
new file mode 100644 (file)
index 0000000..ba26f45
--- /dev/null
@@ -0,0 +1,92 @@
+<!doctype html>
+<!--[if IE 9]><html class="lt-ie10" lang="en" > <![endif]-->
+<html class="no-js" lang="en" dir="ltr">
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <title>Foundation for Sites Testing</title>
+    <link href="../assets/css/foundation.css" rel="stylesheet" />
+  </head>
+  <body>
+    <div class="row column">
+      <h1>Dropdown: Overflow Handling</h1>
+
+      <p>These dropdowns test various overflow situations.</p>
+
+      <h4>Right and Left Overflow</h4>
+      <div class="row small-up-1 medium-up-2" style="background-color:#ddd;">
+        <div class="column">
+          <p>Bottom Right Default Behavior (no overflow)</p>
+          <button class="button" type="button" data-toggle="example-dropdown-bottom-right">Toggle Dropdown</button>
+          <div class="dropdown-pane" data-parent-class="row" data-position="bottom" data-alignment="right" id="example-dropdown-bottom-right" data-dropdown data-auto-focus="true">
+            <p>This dropdown should be on the bottom aligned with the left, all inside the container</p>
+          </div>
+        </div>
+        <div class="column">
+          <p>Bottom Left Default Behavior (no overflow)</p>
+          <button class="button float-right" type="button" data-toggle="example-dropdown-bottom-left">Toggle Dropdown</button>
+          <div class="dropdown-pane" data-parent-class="row" data-position="bottom" data-alignment="left" id="example-dropdown-bottom-left" data-dropdown data-auto-focus="true">
+            <p>This dropdown should be on the bottom aligned with the right, all inside the container</p>
+          </div>
+        </div>
+
+        <div class="column">
+          <p>Bottom Right Overflow Allowed</p>
+          <button class="button" type="button" data-toggle="example-dropdown-bottom-right-overflow">Toggle Dropdown</button>
+          <div class="dropdown-pane" data-allow-overlap="true" data-parent-class="row" data-position="bottom" data-alignment="right" id="example-dropdown-bottom-right-overflow" data-dropdown data-auto-focus="true">
+            <p>This dropdown should be on the bottom aligned with the right, breaking out of the container</p>
+          </div>
+        </div>
+
+        <div class="column">
+          <p>Bottom Left Overflow Allowed</p>
+          <button class="button float-right" type="button" data-toggle="example-dropdown-bottom-left-overflow">Toggle Dropdown</button>
+          <div class="dropdown-pane" data-allow-overlap="true" data-parent-class="row" data-position="bottom" data-alignment="left" id="example-dropdown-bottom-left-overflow" data-dropdown data-auto-focus="true">
+            <p>This dropdown should be on the bottom aligned with the left, breaking out of the container</p>
+          </div>
+        </div>
+      </div>
+
+      <h4>Bottom and Top Overflow</h4>
+      <div class="row small-up-2" style="background-color:#ddd;">
+        <div class="column">
+          <p>Right Bottom Default Behavior (no overflow)</p>
+          <button class="button" type="button" data-toggle="example-dropdown-right-bottom">Toggle Dropdown</button>
+          <div class="dropdown-pane" data-parent-class="row" data-position="right" data-alignment="bottom" id="example-dropdown-right-bottom" data-dropdown data-auto-focus="true">
+            <p>This dropdown should be on the right aligned with the top of the button after realigning</p>
+          </div>
+        </div>
+        <div class="column">
+          <p>Left Bottom Default Behavior (no overflow)</p>
+          <button class="button float-right" type="button" data-toggle="example-dropdown-left-bottom">Toggle Dropdown</button>
+          <div class="dropdown-pane" data-parent-class="row" data-position="left" data-alignment="bottom" id="example-dropdown-left-bottom" data-dropdown data-auto-focus="true">
+            <p>This dropdown should be on the left aligned with the top of the button after realigning</p>
+          </div>
+        </div>
+
+        <div class="column">
+          <p>Right Top Default Behavior (no overflow)</p>
+          <button class="button" type="button" data-toggle="example-dropdown-right-top">Toggle Dropdown</button>
+          <div class="dropdown-pane" data-parent-class="row" data-position="right" data-alignment="top" id="example-dropdown-right-top" data-dropdown data-auto-focus="true">
+            <p>This dropdown should be on the right aligned with the bottom of the button after realigning</p>
+          </div>
+        </div>
+
+        <div class="column">
+          <p>Left Top Default Behavior (no overflow)</p>
+          <button class="button float-right" type="button" data-toggle="example-dropdown-left-top">Toggle Dropdown</button>
+          <div class="dropdown-pane" data-parent-class="row" data-position="left" data-alignment="top" id="example-dropdown-left-top" data-dropdown data-auto-focus="true">
+            <p>This dropdown should be on the left aligned with the bottom of the button after realigning</p>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <script src="../assets/js/vendor.js"></script>
+    <script src="../assets/js/foundation.js"></script>
+    <script>
+      $(document).foundation();
+    </script>
+  </body>
+</html>
+