diff --git a/resources/celerity/map.php b/resources/celerity/map.php --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -10,7 +10,7 @@ 'conpherence.pkg.css' => '0b64e988', 'conpherence.pkg.js' => '6249a1cf', 'core.pkg.css' => '9c725fa0', - 'core.pkg.js' => 'f998932d', + 'core.pkg.js' => 'a2ead3fe', 'darkconsole.pkg.js' => 'e7393ebb', 'differential.pkg.css' => 'f69afb45', 'differential.pkg.js' => '40b18f35', @@ -489,7 +489,7 @@ 'rsrc/js/core/ShapedRequest.js' => '7cbe244b', 'rsrc/js/core/TextAreaUtils.js' => '320810c8', 'rsrc/js/core/Title.js' => '485aaa6c', - 'rsrc/js/core/ToolTip.js' => '6323f942', + 'rsrc/js/core/ToolTip.js' => 'b5c62c3b', 'rsrc/js/core/behavior-active-nav.js' => 'e379b58e', 'rsrc/js/core/behavior-audio-source.js' => '59b251eb', 'rsrc/js/core/behavior-autofocus.js' => '7319e029', @@ -816,7 +816,7 @@ 'phabricator-standard-page-view' => '894d8a25', 'phabricator-textareautils' => '320810c8', 'phabricator-title' => '485aaa6c', - 'phabricator-tooltip' => '6323f942', + 'phabricator-tooltip' => 'b5c62c3b', 'phabricator-ui-example-css' => '528b19de', 'phabricator-uiexample-javelin-view' => 'd4a14807', 'phabricator-uiexample-reactor-button' => 'd19198c8', @@ -1418,12 +1418,6 @@ 'javelin-install', 'javelin-util', ), - '6323f942' => array( - 'javelin-install', - 'javelin-util', - 'javelin-dom', - 'javelin-vector', - ), '635de1ec' => array( 'javelin-behavior', 'javelin-stratcom', @@ -1903,6 +1897,12 @@ 'javelin-install', 'javelin-dom', ), + 'b5c62c3b' => array( + 'javelin-install', + 'javelin-util', + 'javelin-dom', + 'javelin-vector', + ), 'b5d57730' => array( 'javelin-install', 'javelin-stratcom', diff --git a/webroot/rsrc/js/core/ToolTip.js b/webroot/rsrc/js/core/ToolTip.js --- a/webroot/rsrc/js/core/ToolTip.js +++ b/webroot/rsrc/js/core/ToolTip.js @@ -65,15 +65,48 @@ _getSmartPosition: function (align, root, node) { var self = JX.Tooltip; - var pos = self._proposePosition(align, root, node); - // If toolip is offscreen, try to be clever - if (!JX.Tooltip.isOnScreen(pos, node)) { - align = self._getImprovedOrientation(pos, node); - pos = self._proposePosition(align, root, node); + // Figure out how to position the tooltip on screen. We will try the + // configured aligment first. + var try_alignments = [align]; + + // If the configured alignment does not fit, we'll try the opposite + // alignment. + var opposites = { + N: 'S', + S: 'N', + E: 'W', + W: 'E' + }; + try_alignments.push(opposites[align]); + + // Then we'll try the other alignments, in arbitrary order. + for (var k in opposites) { + try_alignments.push(k); } - self._setAnchor(align); + var use_alignment = null; + var use_pos = null; + for (var ii = 0; ii < try_alignments.length; ii++) { + var try_alignment = try_alignments[ii]; + + var pos = self._proposePosition(try_alignment, root, node); + if (self.isOnScreen(pos, node)) { + use_alignment = try_alignment; + use_pos = pos; + break; + } + } + + // If we don't come up with a good answer, default to the configured + // alignment. + if (use_alignment === null) { + use_alignment = align; + use_pos = self._proposePosition(use_alignment, root, node); + } + + self._setAnchor(use_alignment); + return pos; }, @@ -108,56 +141,24 @@ }, isOnScreen: function (a, node) { - var s = JX.Vector.getScroll(); - var v = JX.Vector.getViewport(); - var max_x = s.x + v.x; - var max_y = s.y + v.y; - + var view = this._getViewBoundaries(); var corners = this._getNodeCornerPositions(a, node); - // Check if any of the corners are offscreen + // Check if any of the corners are offscreen. for (var i = 0; i < corners.length; i++) { var corner = corners[i]; - if (corner.x < s.x || - corner.y < s.y || - corner.x > max_x || - corner.y > max_y) { + if (corner.x < view.w || + corner.y < view.n || + corner.x > view.e || + corner.y > view.s) { return false; } } return true; }, - _getImprovedOrientation: function (a, node) { - // Try to predict the "more correct" orientation - var s = JX.Vector.getScroll(); - var v = JX.Vector.getViewport(); - var max_x = s.x + v.x; - var max_y = s.y + v.y; - - var corners = this._getNodeCornerPositions(a, node); - - for (var i = 0; i < corners.length; i++) { - var corner = corners[i]; - if (corner.y < v.y) { - return 'S'; - } else - if (corner.x < v.x) { - return 'E'; - } else - if (corner.y > max_y) { - return 'N'; - } else - if (corner.x > max_x) { - return 'W'; - } else { - return 'N'; - } - } - }, - _getNodeCornerPositions: function(pos, node) { - // Get positions of all four corners of a node + // Get positions of all four corners of a node. var n = JX.Vector.getDim(node); return [new JX.Vector(pos.x, pos.y), new JX.Vector(pos.x + n.x, pos.y), @@ -165,6 +166,24 @@ new JX.Vector(pos.x + n.x, pos.y + n.y)]; }, + _getViewBoundaries: function() { + var s = JX.Vector.getScroll(); + var v = JX.Vector.getViewport(); + var max_x = s.x + v.x; + var max_y = s.y + v.y; + + // Even if the corner is technically on the screen, don't allow the + // tip to display too close to the edge of the screen. + var margin = 16; + + return { + w: s.x + margin, + e: max_x - margin, + n: s.y + margin, + s: max_y - margin + }; + }, + _setAnchor: function (align) { // Orient the little tail JX.DOM.alterClass(this._node, 'jx-tooltip-align-' + align, true);