Changeset View
Changeset View
Standalone View
Standalone View
webroot/rsrc/js/application/differential/behavior-populate.js
/** | /** | ||||
* @provides javelin-behavior-differential-populate | * @provides javelin-behavior-differential-populate | ||||
* @requires javelin-behavior | * @requires javelin-behavior | ||||
* javelin-workflow | |||||
* javelin-util | |||||
* javelin-dom | * javelin-dom | ||||
* javelin-stratcom | * javelin-stratcom | ||||
* javelin-behavior-device | |||||
* javelin-vector | |||||
* javelin-router | |||||
* phabricator-tooltip | * phabricator-tooltip | ||||
* changeset-view-manager | |||||
*/ | */ | ||||
JX.behavior('differential-populate', function(config) { | JX.behavior('differential-populate', function(config) { | ||||
function onresponse(target_id, response) { | for (var ii = 0; ii < config.changesetViewIDs.length; ii++) { | ||||
// As we populate the diff, we try to hold the document scroll position | var id = config.changesetViewIDs[ii]; | ||||
// steady, so that, e.g., users who want to leave a comment on a diff with a | var view = JX.ChangesetViewManager.getForNode(JX.$(id)); | ||||
// large number of changes don't constantly have the text area scrolled off | if (view.shouldAutoload()) { | ||||
// the bottom of the screen until the entire diff loads. | view.setStabilize(true).load(); | ||||
// | |||||
// There are two three major cases here: | |||||
// | |||||
// - If we're near the top of the document, never scroll. | |||||
// - If we're near the bottom of the document, always scroll. | |||||
// - Otherwise, scroll if the changes were above the midline of the | |||||
// viewport. | |||||
var target = JX.$(target_id); | |||||
var old_pos = JX.Vector.getScroll(); | |||||
var old_view = JX.Vector.getViewport(); | |||||
var old_dim = JX.Vector.getDocument(); | |||||
// Number of pixels away from the top or bottom of the document which | |||||
// count as "nearby". | |||||
var sticky = 480; | |||||
var near_top = (old_pos.y <= sticky); | |||||
var near_bot = ((old_pos.y + old_view.y) >= (old_dim.y - sticky)); | |||||
var target_pos = JX.Vector.getPos(target); | |||||
var target_dim = JX.Vector.getDim(target); | |||||
var target_mid = (target_pos.y + (target_dim.y / 2)); | |||||
var view_mid = (old_pos.y + (old_view.y / 2)); | |||||
var above_mid = (target_mid < view_mid); | |||||
JX.DOM.replace(target, JX.$H(response.changeset)); | |||||
if (!near_top) { | |||||
if (near_bot || above_mid) { | |||||
// Figure out how much taller the document got. | |||||
var delta = (JX.Vector.getDocument().y - old_dim.y); | |||||
window.scrollTo(old_pos.x, old_pos.y + delta); | |||||
} | } | ||||
} | } | ||||
if (response.coverage) { | |||||
for (var k in response.coverage) { | |||||
try { | |||||
JX.DOM.replace(JX.$(k), JX.$H(response.coverage[k])); | |||||
} catch (ignored) { | |||||
// Not terribly important. | |||||
} | |||||
} | |||||
} | |||||
} | |||||
// NOTE: If you load the page at one device resolution and then resize to | |||||
// a different one we don't re-render the diffs, because it's a complicated | |||||
// mess and you could lose inline comments, cursor positions, etc. | |||||
var renderer = (JX.Device.getDevice() == 'desktop') ? '2up' : '1up'; | |||||
// TODO: Once 1up works better, figure out when to show it. | |||||
renderer = '2up'; | |||||
var get_key = function(id) { | |||||
return 'differential-populate.' + id; | |||||
}; | |||||
var load = function(id, data) { | |||||
var routable = new JX.Workflow(config.uri, data) | |||||
.setHandler(JX.bind(null, onresponse, id)) | |||||
.getRoutable(); | |||||
routable | |||||
.setPriority(500) | |||||
.setType('content') | |||||
.setKey(get_key(id)); | |||||
JX.Router.getInstance().queue(routable); | |||||
return routable; | |||||
}; | |||||
for (var k in config.registry) { | |||||
var data = { | |||||
ref : config.registry[k], | |||||
whitespace: config.whitespace, | |||||
renderer: renderer | |||||
}; | |||||
load(k, data); | |||||
} | |||||
var highlighted = null; | |||||
var highlight_class = null; | |||||
JX.Stratcom.listen( | JX.Stratcom.listen( | ||||
'click', | 'click', | ||||
'differential-load', | 'differential-load', | ||||
function(e) { | function(e) { | ||||
var meta = e.getNodeData('differential-load'); | var meta = e.getNodeData('differential-load'); | ||||
var diff; | var changeset = JX.$(meta.id); | ||||
try { | var view = JX.ChangesetViewManager.getForNode(changeset); | ||||
diff = JX.$(meta.id); | |||||
} catch (ex) { | |||||
// Already loaded. | |||||
} | |||||
if (diff) { | |||||
JX.DOM.setContent( | |||||
diff, | |||||
JX.$H('<div class="differential-loading">Loading...</div>')); | |||||
// When a user explicitly clicks "Load" (or clicks a link in the table | |||||
// of contents) prioritize this request if it already exists. If it | |||||
// doesn't, make a new high-priority request. | |||||
var key = get_key(meta.id); | |||||
var routable = JX.Router.getInstance().getRoutableByKey(key); | |||||
if (!routable) { | |||||
var data = { | |||||
ref : meta.ref, | |||||
whitespace : config.whitespace | |||||
}; | |||||
routable = load(meta.id, data); | |||||
} | |||||
view.load(); | |||||
var routable = view.getRoutable(); | |||||
if (routable) { | |||||
routable.setPriority(2000); | routable.setPriority(2000); | ||||
} | } | ||||
if (meta.kill) { | if (meta.kill) { | ||||
e.kill(); | e.kill(); | ||||
} | } | ||||
}); | }); | ||||
var highlighted = null; | |||||
var highlight_class = null; | |||||
JX.Stratcom.listen( | JX.Stratcom.listen( | ||||
['mouseover', 'mouseout'], | ['mouseover', 'mouseout'], | ||||
['differential-changeset', 'tag:td'], | ['differential-changeset', 'tag:td'], | ||||
function(e) { | function(e) { | ||||
var t = e.getTarget(); | var t = e.getTarget(); | ||||
// NOTE: Using className is not best practice, but the diff UI is perf | // NOTE: Using className is not best practice, but the diff UI is perf | ||||
// sensitive. | // sensitive. | ||||
Show All 40 Lines | function(e) { | ||||
highlighted = t[sibling]; | highlighted = t[sibling]; | ||||
JX.DOM.alterClass(highlighted, highlight_class, true); | JX.DOM.alterClass(highlighted, highlight_class, true); | ||||
} | } | ||||
} | } | ||||
}); | }); | ||||
}); | }); |