Files
phabricator/webroot/rsrc/js/core/Hovercard.js

173 lines
4.0 KiB
JavaScript
Raw Normal View History

/**
* @requires javelin-install
* javelin-dom
* javelin-vector
* javelin-request
* javelin-uri
* @provides phui-hovercard
* @javelin
*/
JX.install('Hovercard', {
statics : {
_node : null,
_activeRoot : null,
_visiblePHID : null,
_alignment: null,
fetchUrl : '/search/hovercard/',
/**
* Hovercard storage. {"PHID-XXXX-YYYY":"<...>", ...}
*/
_cards : {},
getAnchor : function() {
return this._activeRoot;
},
getCard : function() {
var self = JX.Hovercard;
return self._node;
},
getAlignment: function() {
var self = JX.Hovercard;
return self._alignment;
},
show : function(root, phid) {
var self = JX.Hovercard;
if (root === this._activeRoot) {
return;
}
self.hide();
self._visiblePHID = phid;
self._activeRoot = root;
if (!(phid in self._cards)) {
self._load([phid]);
} else {
self._drawCard(phid);
}
},
_drawCard : function(phid) {
var self = JX.Hovercard;
// card is loading...
if (self._cards[phid] === true) {
return;
}
// Not the current requested card
if (phid != self._visiblePHID) {
return;
}
// Not loaded
if (!(phid in self._cards)) {
return;
}
var root = self._activeRoot;
var node = JX.$N('div',
{ className: 'jx-hovercard-container' },
JX.$H(self._cards[phid]));
self._node = node;
// Append the card to the document, but offscreen, so we can measure it.
node.style.left = '-10000px';
document.body.appendChild(node);
// Retrieve size from child (wrapper), since node gives wrong dimensions?
var child = node.firstChild;
var p = JX.$V(root);
var d = JX.Vector.getDim(root);
var n = JX.Vector.getDim(child);
var v = JX.Vector.getViewport();
var s = JX.Vector.getScroll();
// Move the tip so it's nicely aligned.
Fix the attempt of graceful alignment for Hovercards Summary: Refs T1048; Fixes T2902 - (Probably) fixes @vrana's issue. I managed to repro it on Ubuntu FF (though on Windows with 1.0GHz/512MB it's really worse...). This revises the approach to the graceful degradation for `too-far-to-the-screen-edge-edge-case`. I noticed that `x` could become very negative, up to about ~`-170px`. This is due to the //"already-on-the-left-side"// nature of object tags. `50 - 200 - 20` = `negative`. Adding `100px` (node.dimension.x / 4) to that won't really help, as the hovercard would still be offscreen. Instead, display them left-aligned with the object tags on the left edge per default, and offer centerization in center cases. This is also better for Pholio, Phriction, which have a way lower min-x than Maniphest, Differential. I also disabled placing the hovercard below the tag in case there's not enough space on the north side. The hovercard would not display 99.99% of the times after being hidden (and it retains the flickering behaviour). Another reason is also our current hide-behaviour, which only assumes north-side alignment. Adding south-side didn't really work (I'm bad with JS), so I didn't bother with it. Disabling this is //acceptable//, since it only really affects Pholio, Phriction. And nobody places object tags in the first line, anyway. Except for my test pages, of course :/ Btw, this also removes the weird jaggy horizontal shifts for object of various lengths (e.g. `{D4356}`, `{rP32ofhw0842obw}` etc.). I think that's only good. Test Plan: Hovered in Pholio, Phriction in Chrome, FF. Did not touch left screen border. Hovered in Maniphest, Differential. Tags farther to the left were aligned left, tags more in the center were pretty centered. Reviewers: epriestley, vrana Reviewed By: epriestley CC: aran, Korvin Maniphest Tasks: T1048, T2902 Differential Revision: https://secure.phabricator.com/D5612
2013-04-07 18:10:43 -07:00
var margin = 20;
// Try to align the card directly above the link, with left borders
// touching.
var x = p.x;
// If this would push us off the right side of the viewport, push things
// back to the left.
if ((x + n.x + margin) > (s.x + v.x)) {
x = (s.x + v.x) - n.x - margin;
}
// Try to put the card above the link.
var y = p.y - n.y - margin;
self._alignment = 'north';
// If the card is near the top of the window, show it beneath the
// link we're hovering over instead.
if ((y - margin) < s.y) {
y = p.y + d.y + margin;
self._alignment = 'south';
}
node.style.left = x + 'px';
node.style.top = y + 'px';
},
hide : function() {
var self = JX.Hovercard;
self._visiblePHID = null;
self._activeRoot = null;
if (self._node) {
JX.DOM.remove(self._node);
self._node = null;
}
},
/**
* Pass it an array of phids to load them into storage
*
* @param list phids
*/
_load : function(phids) {
var self = JX.Hovercard;
var uri = JX.$U(self.fetchUrl);
var send = false;
for (var ii = 0; ii < phids.length; ii++) {
var phid = phids[ii];
if (phid in self._cards) {
continue;
}
self._cards[phid] = true; // means "loading"
uri.setQueryParam('phids['+ii+']', phids[ii]);
send = true;
}
if (!send) {
// already loaded / loading everything!
return;
}
new JX.Request(uri, function(r) {
for (var phid in r.cards) {
self._cards[phid] = r.cards[phid];
// Don't draw if the user is faster than the browser
// Only draw if the user is still requesting the original card
if (self.getCard() && phid != self._visiblePHID) {
continue;
}
self._drawCard(phid);
}
}).send();
}
}
});