Files
phabricator/webroot/rsrc/js/core/Hovercard.js
Bob Trahan f7c14736c1 Hovercards - don't let them run off the right edge of the viewport anymore
Summary: Fixes T7524.

Test Plan:
- made a task with a comment including another task. resized window so still desktop size and task reference on edge of window. invoked hovercard by bovering over task reference and noted the hovercard was completely visible.
- opened the durable column and made a task reference. invoked hovercard by hovering over task reference and noted the hovercard was completely visible.

Reviewers: epriestley

Reviewed By: epriestley

Subscribers: Korvin, epriestley

Maniphest Tasks: T7524

Differential Revision: https://secure.phabricator.com/D12759
2015-05-07 16:01:10 -07:00

164 lines
4.1 KiB
JavaScript

/**
* @requires javelin-install
* javelin-dom
* javelin-vector
* javelin-request
* javelin-uri
* @provides phabricator-hovercard
* @javelin
*/
JX.install('Hovercard', {
statics : {
_node : null,
_activeRoot : null,
_visiblePHID : null,
fetchUrl : '/search/hovercard/retrieve/',
/**
* Hovercard storage. {"PHID-XXXX-YYYY":"<...>", ...}
*/
_cards : {},
getAnchor : function() {
return this._activeRoot;
},
getCard : function() {
var self = JX.Hovercard;
return self._node;
},
show : function(root, phid) {
var self = JX.Hovercard;
// Already displaying
if (self.getCard() && phid == self._visiblePHID) {
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();
// Move the tip so it's nicely aligned.
// I'm just doing north/south alignment for now
// TODO: Fix southern graceful align
var margin = 20;
// We can't shift left by ~$margin or more here due to Pholio, Phriction
var x = parseInt(p.x, 10) - margin / 2;
var y = parseInt(p.y - n.y, 10) - margin;
// If running off the edge of the viewport, make it margin / 2 away
// from the far right edge of the viewport instead
if ((x + n.x) > (v.x)) {
x = x - parseInt(x + n.x - v.x + margin / 2, 10);
// If more in the center, we can safely center
} else if (x > (n.x / 2) + margin) {
x = parseInt(p.x - (n.x / 2) + d.x, 10);
}
// Temporarily disabled, since it gives weird results (you can only see
// a hovercard once, as soon as it's hidden, it cannot be shown again)
// if (y < n.y) {
// // Place it southern, since northern is not enough space
// y = p.y + d.y + margin;
// }
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();
}
}
});