Changeset View
Changeset View
Standalone View
Standalone View
webroot/rsrc/js/application/repository/repository-crossreference.js
/** | /** | ||||
* @provides javelin-behavior-repository-crossreference | * @provides javelin-behavior-repository-crossreference | ||||
* @requires javelin-behavior | * @requires javelin-behavior | ||||
* javelin-dom | * javelin-dom | ||||
* javelin-stratcom | * javelin-stratcom | ||||
* javelin-uri | * javelin-uri | ||||
*/ | */ | ||||
JX.behavior('repository-crossreference', function(config, statics) { | JX.behavior('repository-crossreference', function(config, statics) { | ||||
var highlighted; | var highlighted; | ||||
var linked = []; | var linked = []; | ||||
var isMac = navigator.platform.indexOf('Mac') > -1; | function isMacOS() { | ||||
var signalKey = isMac ? 91 /*COMMAND*/ : 17 /*CTRL*/; | return (navigator.platform.indexOf('Mac') > -1); | ||||
function isSignalkey(event) { | } | ||||
return isMac ? | |||||
event.getRawEvent().metaKey : | function isHighlightModifierKey(e) { | ||||
event.getRawEvent().ctrlKey; | var signal_key; | ||||
if (isMacOS()) { | |||||
// On macOS, use the "Command" key. | |||||
signal_key = 91; | |||||
} else { | |||||
// On other platforms, use the "Control" key. | |||||
signal_key = 17; | |||||
} | |||||
return (e.getRawEvent().keyCode === signal_key); | |||||
} | |||||
function hasHighlightModifierKey(e) { | |||||
if (isMacOS()) { | |||||
return e.getRawEvent().metaKey; | |||||
} else { | |||||
return e.getRawEvent().ctrlKey; | |||||
} | |||||
} | } | ||||
var classHighlight = 'crossreference-item'; | var classHighlight = 'crossreference-item'; | ||||
var classMouseCursor = 'crossreference-cursor'; | var classMouseCursor = 'crossreference-cursor'; | ||||
// TODO maybe move the dictionary part of this list to the server? | // TODO maybe move the dictionary part of this list to the server? | ||||
var class_map = { | var class_map = { | ||||
nc : 'class', | nc : 'class', | ||||
Show All 10 Lines | JX.DOM.listen( | ||||
element, | element, | ||||
['mouseover', 'mouseout', 'click'], | ['mouseover', 'mouseout', 'click'], | ||||
'tag:span', | 'tag:span', | ||||
function(e) { | function(e) { | ||||
if (e.getType() === 'mouseout') { | if (e.getType() === 'mouseout') { | ||||
unhighlight(); | unhighlight(); | ||||
return; | return; | ||||
} | } | ||||
if (!isSignalkey(e)) { | if (!hasHighlightModifierKey(e)) { | ||||
return; | return; | ||||
} | } | ||||
var target = e.getTarget(); | var target = e.getTarget(); | ||||
try { | try { | ||||
// If we're in an inline comment, don't link symbols. | // If we're in an inline comment, don't link symbols. | ||||
if (JX.DOM.findAbove(target, 'div', 'differential-inline-comment')) { | if (JX.DOM.findAbove(target, 'div', 'differential-inline-comment')) { | ||||
Show All 16 Lines | JX.DOM.listen( | ||||
(target.className in class_map)) { | (target.className in class_map)) { | ||||
highlighted = target; | highlighted = target; | ||||
JX.DOM.alterClass(highlighted, classHighlight, true); | JX.DOM.alterClass(highlighted, classHighlight, true); | ||||
break; | break; | ||||
} | } | ||||
target = target.parentNode; | target = target.parentNode; | ||||
} | } | ||||
} else if (e.getType() === 'click') { | } else if (e.getType() === 'click') { | ||||
openSearch(target, lang); | openSearch(target, {lang: lang}); | ||||
} | } | ||||
}); | }); | ||||
} | } | ||||
function unhighlight() { | function unhighlight() { | ||||
highlighted && JX.DOM.alterClass(highlighted, classHighlight, false); | highlighted && JX.DOM.alterClass(highlighted, classHighlight, false); | ||||
highlighted = null; | highlighted = null; | ||||
} | } | ||||
function openSearch(target, lang) { | function openSearch(target, context) { | ||||
var symbol = target.textContent || target.innerText; | var symbol = target.textContent || target.innerText; | ||||
var query = { | |||||
lang : lang, | context = context || {}; | ||||
repositories : config.repositories.join(','), | context.lang = context.lang || null; | ||||
jump : true | context.repositories = | ||||
}; | context.repositories || | ||||
(config && config.repositories) || | |||||
[]; | |||||
var query = JX.copy({}, context); | |||||
if (query.repositories.length) { | |||||
query.repositories = query.repositories.join(','); | |||||
} else { | |||||
delete query.repositories; | |||||
} | |||||
query.jump = true; | |||||
var c = target.className; | var c = target.className; | ||||
c = c.replace(classHighlight, '').trim(); | c = c.replace(classHighlight, '').trim(); | ||||
if (class_map[c]) { | if (class_map[c]) { | ||||
query.type = class_map[c]; | query.type = class_map[c]; | ||||
} | } | ||||
if (target.hasAttribute('data-symbol-context')) { | if (target.hasAttribute('data-symbol-context')) { | ||||
query.context = target.getAttribute('data-symbol-context'); | query.context = target.getAttribute('data-symbol-context'); | ||||
} | } | ||||
if (target.hasAttribute('data-symbol-name')) { | if (target.hasAttribute('data-symbol-name')) { | ||||
symbol = target.getAttribute('data-symbol-name'); | symbol = target.getAttribute('data-symbol-name'); | ||||
} | } | ||||
var line = getLineNumber(target); | var line = getLineNumber(target); | ||||
if (line !== null) { | if (line !== null) { | ||||
query.line = line; | query.line = line; | ||||
} | } | ||||
if (!query.hasOwnProperty('path')) { | |||||
var path = getPath(target); | var path = getPath(target); | ||||
if (path !== null) { | if (path !== null) { | ||||
query.path = path; | query.path = path; | ||||
} | } | ||||
} | |||||
var char = getChar(target); | var char = getChar(target); | ||||
if (char !== null) { | if (char !== null) { | ||||
query.char = char; | query.char = char; | ||||
} | } | ||||
var uri = JX.$U('/diffusion/symbol/' + symbol + '/'); | var uri = JX.$U('/diffusion/symbol/' + symbol + '/'); | ||||
uri.addQueryParams(query); | uri.addQueryParams(query); | ||||
window.open(uri); | |||||
window.open(uri.toString()); | |||||
} | } | ||||
function linkAll() { | function linkAll() { | ||||
var blocks = JX.DOM.scry(document.body, 'div', 'remarkup-code-block'); | var blocks = JX.DOM.scry(document.body, 'div', 'remarkup-code-block'); | ||||
for (var i = 0; i < blocks.length; ++i) { | for (var i = 0; i < blocks.length; ++i) { | ||||
if (blocks[i].hasAttribute('data-code-lang')) { | if (blocks[i].hasAttribute('data-code-lang')) { | ||||
var lang = blocks[i].getAttribute('data-code-lang'); | var lang = blocks[i].getAttribute('data-code-lang'); | ||||
link(blocks[i], lang); | link(blocks[i], lang); | ||||
▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | function getPath(target) { | ||||
var changeset; | var changeset; | ||||
try { | try { | ||||
changeset = JX.DOM.findAbove(target, 'div', 'differential-changeset'); | changeset = JX.DOM.findAbove(target, 'div', 'differential-changeset'); | ||||
return JX.Stratcom.getData(changeset).path; | return JX.Stratcom.getData(changeset).path; | ||||
} catch (ex) { | } catch (ex) { | ||||
// Ignore. | // Ignore. | ||||
} | } | ||||
// This method works in Diffusion, when viewing the content of a file at | |||||
// a particular commit. | |||||
var file; | |||||
try { | |||||
file = JX.DOM.findAbove(target, 'div', 'diffusion-file-content-view'); | |||||
return JX.Stratcom.getData(file).path; | |||||
} catch (ex) { | |||||
// Ignore. | |||||
} | |||||
return null; | return null; | ||||
} | } | ||||
function getChar(target) { | function getChar(target) { | ||||
var cell = JX.DOM.findAbove(target, 'td'); | var cell = JX.DOM.findAbove(target, 'td'); | ||||
if (!cell) { | if (!cell) { | ||||
return null; | return null; | ||||
} | } | ||||
Show All 13 Lines | for (var ii = 0; ii < cell.childNodes.length; ii++) { | ||||
content = content.replace(/\u200B/g, ''); | content = content.replace(/\u200B/g, ''); | ||||
char += content.length; | char += content.length; | ||||
} | } | ||||
return null; | return null; | ||||
} | } | ||||
if (config.container) { | |||||
link(JX.$(config.container), config.lang); | |||||
} else if (config.section) { | |||||
linkAll(JX.$(config.section)); | |||||
} | |||||
JX.Stratcom.listen( | JX.Stratcom.listen( | ||||
'differential-preview-update', | 'differential-preview-update', | ||||
null, | null, | ||||
function(e) { | function(e) { | ||||
linkAll(e.getData().container); | linkAll(e.getData().container); | ||||
}); | }); | ||||
JX.Stratcom.listen( | JX.Stratcom.listen( | ||||
['keydown', 'keyup'], | ['keydown', 'keyup'], | ||||
null, | null, | ||||
function(e) { | function(e) { | ||||
if (e.getRawEvent().keyCode !== signalKey) { | if (!isHighlightModifierKey(e)) { | ||||
return; | return; | ||||
} | } | ||||
setCursorMode(e.getType() === 'keydown'); | setCursorMode(e.getType() === 'keydown'); | ||||
if (!statics.active) { | if (!statics.active) { | ||||
unhighlight(); | unhighlight(); | ||||
} | } | ||||
}); | }); | ||||
JX.Stratcom.listen( | JX.Stratcom.listen( | ||||
'blur', | 'blur', | ||||
null, | null, | ||||
function(e) { | function(e) { | ||||
if (e.getTarget()) { | if (e.getTarget()) { | ||||
return; | return; | ||||
} | } | ||||
unhighlight(); | unhighlight(); | ||||
setCursorMode(false); | setCursorMode(false); | ||||
}); | }); | ||||
function setCursorMode(active) { | function setCursorMode(active) { | ||||
statics.active = active; | statics.active = active; | ||||
linked.forEach(function(element) { | linked.forEach(function(element) { | ||||
JX.DOM.alterClass(element, classMouseCursor, statics.active); | JX.DOM.alterClass(element, classMouseCursor, statics.active); | ||||
}); | }); | ||||
} | } | ||||
if (config && config.container) { | |||||
link(JX.$(config.container), config.lang); | |||||
} | |||||
JX.Stratcom.listen( | |||||
['mouseover', 'mouseout', 'click'], | |||||
['has-symbols', 'tag:span'], | |||||
function(e) { | |||||
var type = e.getType(); | |||||
if (type === 'mouseout') { | |||||
unhighlight(); | |||||
return; | |||||
} | |||||
if (!hasHighlightModifierKey(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 only part of the symbol was edited, the symbol name itself will | |||||
// have another "<span />" inside of it which highlights only the | |||||
// edited part. Skip over it. | |||||
if (JX.DOM.isNode(target, 'span') && (target.className === 'bright')) { | |||||
target = target.parentNode; | |||||
} | |||||
if (type === 'click') { | |||||
openSearch(target, e.getNodeData('has-symbols').symbols); | |||||
e.kill(); | |||||
return; | |||||
} | |||||
if (e.getType() === 'mouseover') { | |||||
while (target && target !== document.body) { | |||||
if (!JX.DOM.isNode(target, 'span')) { | |||||
target = target.parentNode; | |||||
continue; | |||||
} | |||||
if (!class_map.hasOwnProperty(target.className)) { | |||||
target = target.parentNode; | |||||
continue; | |||||
} | |||||
highlighted = target; | |||||
JX.DOM.alterClass(highlighted, classHighlight, true); | |||||
break; | |||||
} | |||||
} | |||||
}); | |||||
}); | }); |