1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2025-01-14 16:51:08 +01:00

Hovercard front-end code & stuff

Summary:
Refs T1048; Depends on D5557, D5558

They hover right above your eyes. Try it out at home :D (in that case, don't forget to checkout D5557 and D5558)

Worth a lot of improvement. But it's great for now after a little bit of styling.

Scrape load (search current document for all hovercards and pre-load them) and lazy load (e.g. previewing comments which is not covered by scrape load) implemented.

Added some seemingly useful graceful situations. Too much to the left, too much to the top.

Test Plan:
Tested on Ubuntu, Chrome and FF. No Windows yet, since I have it live at no place. Works pretty fine, at least it will appear.

Could test left graceful fallback. Don't know what happens if you place it too far to the top. I expect either good results or placement about the center of the screen in case of glitches.

For now, they'll disappear right away once the mouse leaves the object tag. Intended is when leaving both tag and hovercard.

Reviewers: epriestley, chad, btrahan

CC: aran, Korvin

Maniphest Tasks: T1048

Differential Revision: https://secure.phabricator.com/D5563

Conflicts:

	src/__celerity_resource_map__.php
This commit is contained in:
Anh Nhan Nguyen 2013-04-05 08:31:35 -07:00 committed by epriestley
parent a8418990d0
commit 635bd1ef07
5 changed files with 250 additions and 2 deletions

View file

@ -1903,6 +1903,19 @@ celerity_register_resource_map(array(
),
'disk' => '/rsrc/js/application/uiexample/gesture-example.js',
),
'javelin-behavior-phabricator-hovercards' =>
array(
'uri' => '/res/8366e963/rsrc/js/application/core/behavior-hovercard.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-behavior',
1 => 'javelin-behavior-device',
2 => 'javelin-stratcom',
3 => 'phabricator-hovercard',
),
'disk' => '/rsrc/js/application/core/behavior-hovercard.js',
),
'javelin-behavior-phabricator-keyboard-pager' =>
array(
'uri' => '/res/56d64eff/rsrc/js/application/core/behavior-keyboard-pager.js',
@ -3027,9 +3040,24 @@ celerity_register_resource_map(array(
),
'disk' => '/rsrc/css/layout/phabricator-header-view.css',
),
'phabricator-hovercard' =>
array(
'uri' => '/res/1db6db48/rsrc/js/application/core/Hovercard.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-install',
1 => 'javelin-util',
2 => 'javelin-dom',
3 => 'javelin-vector',
4 => 'javelin-request',
5 => 'phabricator-busy',
),
'disk' => '/rsrc/js/application/core/Hovercard.js',
),
'phabricator-hovercard-view-css' =>
array(
'uri' => '/res/68d69a87/rsrc/css/layout/phabricator-hovercard-view.css',
'uri' => '/res/ed56200c/rsrc/css/layout/phabricator-hovercard-view.css',
'type' => 'css',
'requires' =>
array(

View file

@ -130,6 +130,7 @@ final class PhabricatorTagView extends AphrontView {
}
if ($this->phid) {
Javelin::initBehavior('phabricator-hovercards');
return javelin_tag(
'a',

View file

@ -2,10 +2,13 @@
* @provides phabricator-hovercard-view-css
*/
.jx-hovercard-container {
position: absolute;
}
.phabricator-hovercard-wrapper {
border-radius: 4px;
width: 400px;
margin: auto;
padding: 4px;
background-color: #cccccc;
}

View file

@ -0,0 +1,124 @@
/**
* @requires javelin-install
* javelin-util
* javelin-dom
* javelin-vector
* javelin-request
* phabricator-busy
* @provides phabricator-hovercard
* @javelin
*/
JX.install('Hovercard', {
statics : {
_node : null,
_activeRoot : null,
_didScrape : false,
fetchUrl : '/search/hovercard/retrieve/',
/**
* Hovercard storage. {"PHID-XXXX-YYYY":"<...>", ...}
*/
cards : {},
show : function(root, phid) {
// Hovercards are all loaded by now, but when somebody previews a comment
// for example it may not be loaded yet.
if (!JX.Hovercard.cards[phid]) {
JX.Hovercard.load([phid]);
}
var node = JX.$N('div',
{ className: 'jx-hovercard-container' },
JX.Hovercard.cards[phid]);
JX.Hovercard.hide();
this._node = node;
this._activeRoot = root;
// 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);
// Move the tip so it's nicely aligned.
// I'm just doing north alignment for now
// TODO: Gracefully align to the side in edge cases
// I know, hardcoded paddings...
var x = parseInt(p.x - ((n.x - d.x) / 2)) + 20;
var y = parseInt(p.y - n.y) - 20;
// Why use 4? Shouldn't it be just 2?
if (x < (n.x / 4)) {
x += (n.x / 4);
}
if (y < n.y) {
// Place it at the bottom
y += n.y + d.y + 50;
}
node.style.left = x + 'px';
node.style.top = y + 'px';
},
hide : function() {
if (this._node) {
JX.DOM.remove(this._node);
this._node = null;
}
if (this._activeRoot) {
this._activeRoot = null;
}
},
/**
* Pass it an array of phids to load them into storage
*
* @param list phids
*/
load : function(phids) {
var uri = JX.$U(JX.Hovercard.fetchUrl);
for (var ii = 0; ii < phids.length; ii++) {
uri.setQueryParam("phids["+ii+"]", phids[ii]);
}
new JX.Request(uri, function(r) {
for (var phid in r.cards) {
JX.Hovercard.cards[phid] = JX.$H(r.cards[phid]);
}
}).send();
},
// For later probably
// Currently unused
scrapeAndLoad: function() {
if (!JX.Hovercard._didScrape) {
// I assume links only for now
var cards = JX.DOM.scry(document, 'a', 'hovercard');
var phids = [];
var data;
for (var i = 0; i < cards.length; i++) {
data = JX.Stratcom.getData(cards[i]);
phids.push(data.hoverPHID);
}
JX.Hovercard.load(phids);
JX.Hovercard._didScrape = true;
}
}
}
});

View file

@ -0,0 +1,92 @@
/**
* @provides javelin-behavior-phabricator-hovercards
* @requires javelin-behavior
* javelin-behavior-device
* javelin-stratcom
* phabricator-hovercard
* @javelin
*/
JX.behavior('phabricator-hovercards', function(config) {
// First find all hovercard-able object on page and load them in a batch
JX.Hovercard.scrapeAndLoad();
// Event stuff
JX.Stratcom.listen(
['mouseover'],
'hovercard',
function (e) {
if (e.getType() == 'mouseout') {
JX.Hovercard.hide();
return;
}
if (JX.Device.getDevice() != 'desktop') {
return;
}
var data = e.getNodeData('hovercard');
JX.Hovercard.show(
e.getNode('hovercard'),
data.hoverPHID);
});
JX.Stratcom.listen(
['mousemove'],
null,
function (e) {
if (JX.Device.getDevice() != 'desktop') {
return;
}
if (!JX.Hovercard._node) {
return;
}
var root = JX.Hovercard._activeRoot;
var node = JX.Hovercard._node.firstChild;
var mouse = JX.$V(e);
var node_pos = JX.$V(node);
var node_dim = JX.Vector.getDim(node);
var root_pos = JX.$V(root);
var root_dim = JX.Vector.getDim(root);
var margin = 20;
// Cursor is above the node.
if (mouse.y < node_pos.y - margin) {
JX.Hovercard.hide();
}
// Cursor is below the root.
if (mouse.y > root_pos.y + root_dim.y + margin) {
JX.Hovercard.hide();
}
// Cursor is too far to the left.
if (mouse.x < Math.min(root_pos.x, node_pos.x) - margin) {
JX.Hovercard.hide();
}
// Cursor is too far to the right.
if (mouse.x >
Math.max(root_pos.x + root_dim.x, node_pos.x + node_dim.x) + margin) {
JX.Hovercard.hide();
}
});
// When we leave the page, hide any visible hovercards. If we don't do this,
// clicking a link with a hovercard and then hitting "back" will give you a
// phantom tooltip.
JX.Stratcom.listen(
'unload',
null,
function(e) {
JX.Hovercard.hide();
});
});