From 1feba9f4a94034d1f55e7e4bf280dcaa41068cb0 Mon Sep 17 00:00:00 2001 From: Kevin Ball Date: Wed, 24 May 2017 21:55:33 -0700 Subject: [PATCH] First work towards positioning tooltips in the same way we're doing dropdowns --- js/foundation.tooltip.js | 140 ++++++++++++++------------------------- 1 file changed, 48 insertions(+), 92 deletions(-) diff --git a/js/foundation.tooltip.js b/js/foundation.tooltip.js index 3cb6d6d43..7bd38c392 100644 --- a/js/foundation.tooltip.js +++ b/js/foundation.tooltip.js @@ -2,10 +2,9 @@ import $ from 'jquery'; -import { Box } from './foundation.util.box'; import { GetYoDigits } from './foundation.util.core'; import { MediaQuery } from './foundation.util.mediaQuery'; -import { Plugin } from './foundation.plugin'; +import { Positionable } from './foundation.positionable'; // import "foundation.util.triggers"; @@ -17,7 +16,7 @@ import { Plugin } from './foundation.plugin'; * @requires foundation.util.triggers */ -class Tooltip extends Plugin { +class Tooltip extends Positionable { /** * Creates a new instance of a Tooltip. * @class @@ -41,7 +40,6 @@ class Tooltip extends Plugin { _init() { var elemId = this.$element.attr('aria-describedby') || GetYoDigits(6, 'tooltip'); - this.options.positionClass = this.options.positionClass || this._getPositionClass(this.$element); this.options.tipText = this.options.tipText || this.$element.attr('title'); this.template = this.options.template ? $(this.options.template) : this._buildTemplate(elemId); @@ -63,25 +61,20 @@ class Tooltip extends Plugin { 'data-resize': elemId }).addClass(this.options.triggerClass); - //helper variables to track movement on collisions - this.usedPositions = []; - this.counter = 4; - this.classChanged = false; - + super._init(); this._events(); } - /** - * Grabs the current positioning class, if present, and returns the value or an empty string. - * @private - */ - _getPositionClass(element) { - if (!element) { return ''; } - // var position = element.attr('class').match(/top|left|right/g); - var position = element[0].className.match(/\b(top|left|right)\b/g); - position = position ? position[0] : ''; - return position; - }; + _getDefaultPosition() { + // handle legacy classnames + var position = this.$element[0].className.match(/\b(top|left|right|bottom)\b/g); + return position ? position[0] : 'top'; + } + + _getDefaultAlignment() { + return 'center'; + } + /** * builds the tooltip element, adds attributes, and returns the template. * @private @@ -98,74 +91,13 @@ class Tooltip extends Plugin { return $template; } - /** - * Function that gets called if a collision event is detected. - * @param {String} position - positioning class to try - * @private - */ - _reposition(position) { - this.usedPositions.push(position ? position : 'bottom'); - - //default, try switching to opposite side - if (!position && (this.usedPositions.indexOf('top') < 0)) { - this.template.addClass('top'); - } else if (position === 'top' && (this.usedPositions.indexOf('bottom') < 0)) { - this.template.removeClass(position); - } else if (position === 'left' && (this.usedPositions.indexOf('right') < 0)) { - this.template.removeClass(position) - .addClass('right'); - } else if (position === 'right' && (this.usedPositions.indexOf('left') < 0)) { - this.template.removeClass(position) - .addClass('left'); - } - - //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.template.addClass('left'); - } else if (position === 'top' && (this.usedPositions.indexOf('bottom') > -1) && (this.usedPositions.indexOf('left') < 0)) { - this.template.removeClass(position) - .addClass('left'); - } else if (position === 'left' && (this.usedPositions.indexOf('right') > -1) && (this.usedPositions.indexOf('bottom') < 0)) { - this.template.removeClass(position); - } else if (position === 'right' && (this.usedPositions.indexOf('left') > -1) && (this.usedPositions.indexOf('bottom') < 0)) { - this.template.removeClass(position); - } - //if nothing cleared, set to bottom - else { - this.template.removeClass(position); - } - this.classChanged = true; - this.counter--; - } - /** * sets the position class of an element and recursively calls itself until there are no more possible positions to attempt, or the tooltip element is no longer colliding. * if the tooltip is larger than the screen width, default to full width - any user selected margin * @private */ _setPosition() { - var position = this._getPositionClass(this.template), - $tipDims = Box.GetDimensions(this.template), - $anchorDims = Box.GetDimensions(this.$element), - direction = (position === 'left' ? 'left' : ((position === 'right') ? 'left' : 'top')), - param = (direction === 'top') ? 'height' : 'width', - offset = (param === 'height') ? this.options.vOffset : this.options.hOffset, - _this = this; - - if (($tipDims.width >= $tipDims.windowDims.width) || (!this.counter && !Box.ImNotTouchingYou(this.template))) { - this.template.offset(Box.GetOffsets(this.template, this.$element, 'center bottom', this.options.vOffset, this.options.hOffset, true)).css({ - 'width': $anchorDims.windowDims.width - (this.options.hOffset * 2), - 'height': 'auto' - }); - return false; - } - - this.template.offset(Box.GetOffsets(this.template, this.$element,'center ' + (position || 'bottom'), this.options.vOffset, this.options.hOffset)); - - while(!Box.ImNotTouchingYou(this.template) && this.counter) { - this._reposition(position); - this._setPosition(); - } + super._setPosition(this.$element, this.template); } /** @@ -183,6 +115,7 @@ class Tooltip extends Plugin { var _this = this; this.template.css('visibility', 'hidden').show(); this._setPosition(); + this.template.removeClass('top bottom left right').addClass(this.position) /** * Fires to close all other open tooltips on the page @@ -221,15 +154,6 @@ class Tooltip extends Plugin { }).fadeOut(this.options.fadeOutDuration, function() { _this.isActive = false; _this.isClick = false; - if (_this.classChanged) { - _this.template - .removeClass(_this._getPositionClass(_this.template)) - .addClass(_this.options.positionClass); - - _this.usedPositions = []; - _this.counter = 4; - _this.classChanged = false; - } }); /** * fires when the tooltip is hidden @@ -432,12 +356,44 @@ Tooltip.defaults = { */ clickOpen: true, /** - * Additional positioning classes, set by the JS + * DEPRECATED Additional positioning classes, set by the JS * @option * @type {string} * @default '' */ positionClass: '', + /** + * Position of tooltip. Can be left, right, bottom, top, or auto. + * @option + * @type {string} + * @default 'auto' + */ + position: 'auto', + /** + * Alignment of tooltip 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, tooltip 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 overlap of only the bottom of the container. This is the most common + * behavior for dropdowns, allowing the dropdown to extend the bottom of the + * screen but not otherwise influence or break out of the container. + * Less common for tooltips. + * @option + * @type {boolean} + * @default false + */ + allowBottomOverlap: false, /** * Distance, in pixels, the template should push away from the anchor on the Y axis. * @option -- 2.47.2