Changeset View
Changeset View
Standalone View
Standalone View
webroot/rsrc/js/core/Hovercard.js
| /** | /** | ||||
| * @requires javelin-install | * @requires javelin-install | ||||
| * javelin-dom | * javelin-dom | ||||
| * javelin-vector | * javelin-vector | ||||
| * javelin-request | * javelin-request | ||||
| * javelin-uri | * javelin-uri | ||||
| * @provides phui-hovercard | * @provides phui-hovercard | ||||
| * @javelin | * @javelin | ||||
| */ | */ | ||||
| JX.install('Hovercard', { | JX.install('Hovercard', { | ||||
| statics : { | properties: { | ||||
| _node : null, | hovercardKey: null, | ||||
| _activeRoot : null, | objectPHID: null, | ||||
| _visiblePHID : null, | isLoading: false, | ||||
| _alignment: null, | isLoaded: false, | ||||
| content: 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() { | members: { | ||||
| var self = JX.Hovercard; | newContentNode: function() { | ||||
| return self._alignment; | return JX.$H(this.getContent()); | ||||
| }, | |||||
| 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. | |||||
| 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(); | |||||
| } | |||||
| } | |||||
| }); | }); | ||||