Summary: Ref T13047. In some reasonable cases, knowing the path and line number where a symbol appears is useful in ranking or filtering the set of matching symbols. Giving symbol sources more information can't hurt, and it's generally free for us to include this context since we just need to grab it out of the document and pass it along. We can't always get this data (for example, if a user types `s idx` into global search, we have no clue) but this is similar to other types of context which are only available sometimes (like which repository a symbol appears in). Test Plan: Command-clicked some symbols in 1-up (unified) and 2-up (side-by-side) diff views with symbol indexes configured. Got accurate path and line information in the URI I was redirected to. Reviewers: amckinley Reviewed By: amckinley Maniphest Tasks: T13047 Differential Revision: https://secure.phabricator.com/D18936
222 lines
5.3 KiB
JavaScript
222 lines
5.3 KiB
JavaScript
/**
|
|
* @provides javelin-behavior-repository-crossreference
|
|
* @requires javelin-behavior
|
|
* javelin-dom
|
|
* javelin-stratcom
|
|
* javelin-uri
|
|
*/
|
|
|
|
JX.behavior('repository-crossreference', function(config, statics) {
|
|
|
|
var highlighted;
|
|
var linked = [];
|
|
|
|
var isMac = navigator.platform.indexOf('Mac') > -1;
|
|
var signalKey = isMac ? 91 /*COMMAND*/ : 17 /*CTRL*/;
|
|
function isSignalkey(event) {
|
|
return isMac ?
|
|
event.getRawEvent().metaKey :
|
|
event.getRawEvent().ctrlKey;
|
|
}
|
|
|
|
var classHighlight = 'crossreference-item';
|
|
var classMouseCursor = 'crossreference-cursor';
|
|
|
|
// TODO maybe move the dictionary part of this list to the server?
|
|
var class_map = {
|
|
nc : 'class',
|
|
nf : 'function',
|
|
na : null,
|
|
nb : 'builtin',
|
|
n : null,
|
|
};
|
|
|
|
function link(element, lang) {
|
|
JX.DOM.alterClass(element, 'repository-crossreference', true);
|
|
linked.push(element);
|
|
JX.DOM.listen(
|
|
element,
|
|
['mouseover', 'mouseout', 'click'],
|
|
'tag:span',
|
|
function(e) {
|
|
if (e.getType() === 'mouseout') {
|
|
unhighlight();
|
|
return;
|
|
}
|
|
if (!isSignalkey(e)) {
|
|
return;
|
|
}
|
|
|
|
var target = e.getTarget();
|
|
|
|
try {
|
|
// If we're in an inline comment, don't link symbols.
|
|
if (JX.DOM.findAbove(target, 'div', 'differential-inline-comment')) {
|
|
return;
|
|
}
|
|
} catch (ex) {
|
|
// Continue if we're not inside an inline comment.
|
|
}
|
|
|
|
if (e.getType() === 'mouseover') {
|
|
while (target !== document.body) {
|
|
if (JX.DOM.isNode(target, 'span') &&
|
|
(target.className in class_map)) {
|
|
highlighted = target;
|
|
JX.DOM.alterClass(highlighted, classHighlight, true);
|
|
break;
|
|
}
|
|
target = target.parentNode;
|
|
}
|
|
} else if (e.getType() === 'click') {
|
|
openSearch(target, lang);
|
|
}
|
|
});
|
|
}
|
|
function unhighlight() {
|
|
highlighted && JX.DOM.alterClass(highlighted, classHighlight, false);
|
|
highlighted = null;
|
|
}
|
|
|
|
function openSearch(target, lang) {
|
|
var symbol = target.textContent || target.innerText;
|
|
var query = {
|
|
lang : lang,
|
|
repositories : config.repositories.join(','),
|
|
jump : true
|
|
};
|
|
var c = target.className;
|
|
c = c.replace(classHighlight, '').trim();
|
|
if (class_map[c]) {
|
|
query.type = class_map[c];
|
|
}
|
|
if (target.hasAttribute('data-symbol-context')) {
|
|
query.context = target.getAttribute('data-symbol-context');
|
|
}
|
|
if (target.hasAttribute('data-symbol-name')) {
|
|
symbol = target.getAttribute('data-symbol-name');
|
|
}
|
|
|
|
var line = getLineNumber(target);
|
|
if (line !== null) {
|
|
query.line = line;
|
|
}
|
|
|
|
var path = getPath(target);
|
|
if (path !== null) {
|
|
query.path = path;
|
|
}
|
|
|
|
var uri = JX.$U('/diffusion/symbol/' + symbol + '/');
|
|
uri.addQueryParams(query);
|
|
window.open(uri);
|
|
}
|
|
|
|
function linkAll() {
|
|
var blocks = JX.DOM.scry(document.body, 'div', 'remarkup-code-block');
|
|
for (var i = 0; i < blocks.length; ++i) {
|
|
if (blocks[i].hasAttribute('data-code-lang')) {
|
|
var lang = blocks[i].getAttribute('data-code-lang');
|
|
link(blocks[i], lang);
|
|
}
|
|
}
|
|
}
|
|
|
|
function getLineNumber(target) {
|
|
|
|
// Figure out the line number by finding the most recent "<th />" in this
|
|
// row with a number in it. We may need to skip over one "<th />" if the
|
|
// diff is being displayed in unified mode.
|
|
|
|
var cell = JX.DOM.findAbove(target, 'td');
|
|
if (!cell) {
|
|
return null;
|
|
}
|
|
|
|
var row = JX.DOM.findAbove(target, 'tr');
|
|
if (!row) {
|
|
return null;
|
|
}
|
|
|
|
var ii;
|
|
|
|
var cell_list = [];
|
|
for (ii = 0; ii < row.childNodes.length; ii++) {
|
|
cell_list.push(row.childNodes[ii]);
|
|
}
|
|
cell_list.reverse();
|
|
|
|
var found = false;
|
|
for (ii = 0; ii < cell_list.length; ii++) {
|
|
if (cell_list[ii] === cell) {
|
|
found = true;
|
|
}
|
|
|
|
if (found && JX.DOM.isType(cell_list[ii], 'th')) {
|
|
var int_value = parseInt(cell_list[ii].textContent, 10);
|
|
if (int_value) {
|
|
return int_value;
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
function getPath(target) {
|
|
var changeset = JX.DOM.findAbove(target, 'div', 'differential-changeset');
|
|
|
|
if (!changeset) {
|
|
return null;
|
|
}
|
|
|
|
return JX.Stratcom.getData(changeset).path;
|
|
}
|
|
|
|
if (config.container) {
|
|
link(JX.$(config.container), config.lang);
|
|
} else if (config.section) {
|
|
linkAll(JX.$(config.section));
|
|
}
|
|
|
|
JX.Stratcom.listen(
|
|
'differential-preview-update',
|
|
null,
|
|
function(e) {
|
|
linkAll(e.getData().container);
|
|
});
|
|
|
|
|
|
JX.Stratcom.listen(
|
|
['keydown', 'keyup'],
|
|
null,
|
|
function(e) {
|
|
if (e.getRawEvent().keyCode !== signalKey) {
|
|
return;
|
|
}
|
|
setCursorMode(e.getType() === 'keydown');
|
|
|
|
if (!statics.active) {
|
|
unhighlight();
|
|
}
|
|
});
|
|
|
|
JX.Stratcom.listen(
|
|
'blur',
|
|
null,
|
|
function(e) {
|
|
if (e.getTarget()) {
|
|
return;
|
|
}
|
|
unhighlight();
|
|
setCursorMode(false);
|
|
});
|
|
|
|
function setCursorMode(active) {
|
|
statics.active = active;
|
|
linked.forEach(function(element) {
|
|
JX.DOM.alterClass(element, classMouseCursor, statics.active);
|
|
});
|
|
}
|
|
});
|