diff --git a/resources/celerity/map.php b/resources/celerity/map.php --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -7,14 +7,14 @@ return array( 'names' => array( - 'core.pkg.css' => '1a07e64e', - 'core.pkg.js' => 'c5b39816', + 'core.pkg.css' => '232fd038', + 'core.pkg.js' => '417722ff', 'darkconsole.pkg.js' => 'ca8671ce', 'differential.pkg.css' => '12c11318', 'differential.pkg.js' => '11a5b750', 'diffusion.pkg.css' => '3783278d', 'diffusion.pkg.js' => '5b4010f4', - 'javelin.pkg.js' => '74a8353b', + 'javelin.pkg.js' => '0452e69d', 'maniphest.pkg.css' => 'f1887d71', 'maniphest.pkg.js' => '2fe8af22', 'rsrc/css/aphront/aphront-bars.css' => '231ac33c', @@ -113,7 +113,7 @@ 'rsrc/css/core/core.css' => 'da26ddb2', 'rsrc/css/core/remarkup.css' => '0923dbd6', 'rsrc/css/core/syntax.css' => '3c18c1cb', - 'rsrc/css/core/z-index.css' => '0fd29d49', + 'rsrc/css/core/z-index.css' => 'edd5911b', 'rsrc/css/diviner/diviner-shared.css' => '38813222', 'rsrc/css/font/font-source-sans-pro.css' => '225851dd', 'rsrc/css/layout/phabricator-action-header-view.css' => 'c14dfc57', @@ -199,7 +199,7 @@ 'rsrc/externals/javelin/ext/view/__tests__/ViewInterpreter.js' => '7a94d6a5', 'rsrc/externals/javelin/ext/view/__tests__/ViewRenderer.js' => '5426001c', 'rsrc/externals/javelin/lib/Cookie.js' => '6b3dcf44', - 'rsrc/externals/javelin/lib/DOM.js' => '5054855f', + 'rsrc/externals/javelin/lib/DOM.js' => '32a4d380', 'rsrc/externals/javelin/lib/History.js' => 'c60f4327', 'rsrc/externals/javelin/lib/JSON.js' => '08e56a4e', 'rsrc/externals/javelin/lib/Mask.js' => 'b9f26029', @@ -440,7 +440,7 @@ 'rsrc/js/core/Prefab.js' => '0326e5d0', 'rsrc/js/core/ShapedRequest.js' => 'dfa181a4', 'rsrc/js/core/TextAreaUtils.js' => 'b3ec3cfc', - 'rsrc/js/core/ToolTip.js' => '0a81ea29', + 'rsrc/js/core/ToolTip.js' => '3915d490', 'rsrc/js/core/behavior-active-nav.js' => 'c81bc98f', 'rsrc/js/core/behavior-audio-source.js' => '59b251eb', 'rsrc/js/core/behavior-autofocus.js' => '7319e029', @@ -630,7 +630,7 @@ 'javelin-behavior-workflow' => 'fee00761', 'javelin-color' => '7e41274a', 'javelin-cookie' => '6b3dcf44', - 'javelin-dom' => '5054855f', + 'javelin-dom' => '32a4d380', 'javelin-dynval' => 'f6555212', 'javelin-event' => '79473b62', 'javelin-fx' => '54b612ba', @@ -716,7 +716,7 @@ 'phabricator-source-code-view-css' => '62a99814', 'phabricator-standard-page-view' => '517cdfb1', 'phabricator-textareautils' => 'b3ec3cfc', - 'phabricator-tooltip' => '0a81ea29', + 'phabricator-tooltip' => '3915d490', 'phabricator-transaction-view-css' => 'ce491938', 'phabricator-ui-example-css' => '4741b891', 'phabricator-uiexample-javelin-view' => 'd4a14807', @@ -729,7 +729,7 @@ 'phabricator-uiexample-reactor-select' => '189e4fe3', 'phabricator-uiexample-reactor-sendclass' => 'bf97561d', 'phabricator-uiexample-reactor-sendproperties' => '551add57', - 'phabricator-zindex-css' => '0fd29d49', + 'phabricator-zindex-css' => 'edd5911b', 'phame-css' => '450826e1', 'pholio-css' => '2fa97dbe', 'pholio-edit-css' => 'b9e59b6d', @@ -864,13 +864,6 @@ array( 0 => 'javelin-install', ), - '0a81ea29' => - array( - 0 => 'javelin-install', - 1 => 'javelin-util', - 2 => 'javelin-dom', - 3 => 'javelin-vector', - ), '0c33c1a0' => array( 0 => 'javelin-view', @@ -1035,6 +1028,14 @@ 3 => 'javelin-stratcom', 4 => 'javelin-request', ), + '32a4d380' => + array( + 0 => 'javelin-magical-init', + 1 => 'javelin-install', + 2 => 'javelin-util', + 3 => 'javelin-vector', + 4 => 'javelin-stratcom', + ), '356de121' => array( 0 => 'javelin-util', @@ -1049,6 +1050,13 @@ 3 => 'javelin-dom', 4 => 'phabricator-draggable-list', ), + '3915d490' => + array( + 0 => 'javelin-install', + 1 => 'javelin-util', + 2 => 'javelin-dom', + 3 => 'javelin-vector', + ), '3aa45ad9' => array( 0 => 'javelin-behavior', @@ -1119,14 +1127,6 @@ 2 => 'javelin-dom', 3 => 'javelin-util', ), - '5054855f' => - array( - 0 => 'javelin-magical-init', - 1 => 'javelin-install', - 2 => 'javelin-util', - 3 => 'javelin-vector', - 4 => 'javelin-stratcom', - ), '52a92793' => array( 0 => 'javelin-util', diff --git a/webroot/rsrc/css/core/z-index.css b/webroot/rsrc/css/core/z-index.css --- a/webroot/rsrc/css/core/z-index.css +++ b/webroot/rsrc/css/core/z-index.css @@ -125,10 +125,6 @@ z-index: 16; } -.jx-tooltip-container { - z-index: 18; -} - .pholio-device-lightbox { z-index: 20; } @@ -144,3 +140,7 @@ .remarkup-control-fullscreen-mode { z-index: 50; } + +.jx-tooltip-container { + z-index: 51; +} diff --git a/webroot/rsrc/externals/javelin/lib/DOM.js b/webroot/rsrc/externals/javelin/lib/DOM.js --- a/webroot/rsrc/externals/javelin/lib/DOM.js +++ b/webroot/rsrc/externals/javelin/lib/DOM.js @@ -543,7 +543,7 @@ }, -/* -( Serializing Froms )-------------------------------------------------- */ +/* -( Serializing Forms )-------------------------------------------------- */ /** 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 @@ -31,7 +31,7 @@ var node = JX.$N( 'div', - { className: 'jx-tooltip-container jx-tooltip-align-' + align }, + { className: 'jx-tooltip-container' }, [ JX.$N('div', { className: 'jx-tooltip' }, content), JX.$N('div', { className: 'jx-tooltip-anchor' }) @@ -46,30 +46,115 @@ node.style.left = '-10000px'; document.body.appendChild(node); + // Jump through some hoops trying to auto-position the tooltip + var pos = this._getSmartPosition(align, root, node); + pos.setPos(node); + }, + + _getSmartPosition: function (align, root, node) { + var pos = JX.Tooltip._proposePosition(align, root, node); + + // If toolip is offscreen, try to be clever + if (!JX.Tooltip.isOnScreen(pos, node)) { + align = JX.Tooltip._getImprovedOrientation(pos, node); + pos = JX.Tooltip._proposePosition(align, root, node); + } + + JX.Tooltip._setAnchor(align); + return pos; + }, + + _proposePosition: function (align, root, node) { var p = JX.$V(root); var d = JX.Vector.getDim(root); var n = JX.Vector.getDim(node); + var l = 0; + var t = 0; - // Move the tip so it's nicely aligned. - + // Caculate the tip so it's nicely aligned. switch (align) { case 'N': - node.style.left = parseInt(p.x - ((n.x - d.x) / 2), 10) + 'px'; - node.style.top = parseInt(p.y - n.y, 10) + 'px'; + l = parseInt(p.x - ((n.x - d.x) / 2), 10); + t = parseInt(p.y - n.y, 10); break; case 'E': - node.style.left = parseInt(p.x + d.x, 10) + 'px'; - node.style.top = parseInt(p.y - ((n.y - d.y) / 2), 10) + 'px'; + l = parseInt(p.x + d.x, 10); + t = parseInt(p.y - ((n.y - d.y) / 2), 10); break; case 'S': - node.style.left = parseInt(p.x - ((n.x - d.x) / 2), 10) + 'px'; - node.style.top = parseInt(p.y + d.y + 5, 10) + 'px'; + l = parseInt(p.x - ((n.x - d.x) / 2), 10); + t = parseInt(p.y + d.y + 5, 10); break; case 'W': - node.style.left = parseInt(p.x - n.x - 5, 10) + 'px'; - node.style.top = parseInt(p.y - ((n.y - d.y) / 2), 10) + 'px'; + l = parseInt(p.x - n.x - 5, 10); + t = parseInt(p.y - ((n.y - d.y) / 2), 10); break; } + + return new JX.Vector(l, t); + }, + + 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 corners = this._getNodeCornerPositions(a, node); + + // 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) { + 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 + var n = JX.Vector.getDim(node); + return [new JX.Vector(pos.x, pos.y), + new JX.Vector(pos.x + n.x, pos.y), + new JX.Vector(pos.x, pos.y + n.y), + new JX.Vector(pos.x + n.x, pos.y + n.y)]; + }, + + _setAnchor: function (align) { + // Orient the little tail + JX.DOM.alterClass(this._node, 'jx-tooltip-align-' + align, true); }, hide : function() {