Path: blob/master/webroot/rsrc/js/application/repository/repository-crossreference.js
12242 views
/**1* @provides javelin-behavior-repository-crossreference2* @requires javelin-behavior3* javelin-dom4* javelin-stratcom5* javelin-uri6*/78JX.behavior('repository-crossreference', function(config, statics) {910var highlighted;11var linked = [];1213function isMacOS() {14return (navigator.platform.indexOf('Mac') > -1);15}1617function isHighlightModifierKey(e) {18var signal_key;19if (isMacOS()) {20// On macOS, use the "Command" key.21signal_key = 91;22} else {23// On other platforms, use the "Control" key.24signal_key = 17;25}2627return (e.getRawEvent().keyCode === signal_key);28}2930function hasHighlightModifierKey(e) {31if (isMacOS()) {32return e.getRawEvent().metaKey;33} else {34return e.getRawEvent().ctrlKey;35}36}3738var classHighlight = 'crossreference-item';39var classMouseCursor = 'crossreference-cursor';4041// TODO maybe move the dictionary part of this list to the server?42var class_map = {43nc : 'class',44nf : 'function',45na : null,46nb : 'builtin',47n : null48};4950function link(element, lang) {51JX.DOM.alterClass(element, 'repository-crossreference', true);52linked.push(element);53JX.DOM.listen(54element,55['mouseover', 'mouseout', 'click'],56'tag:span',57function(e) {58if (e.getType() === 'mouseout') {59unhighlight();60return;61}62if (!hasHighlightModifierKey(e)) {63return;64}6566var target = e.getTarget();6768if (!canLinkNode(target)) {69return;70}7172// If only part of the symbol was edited, the symbol name itself will73// have another "<span />" inside of it which highlights only the74// edited part. Skip over it.75if (JX.DOM.isNode(target, 'span') && (target.className === 'bright')) {76target = target.parentNode;77}7879if (e.getType() === 'mouseover') {80while (target && target !== document.body) {81if (JX.DOM.isNode(target, 'span') &&82(target.className in class_map)) {83highlighted = target;84JX.DOM.alterClass(highlighted, classHighlight, true);85break;86}87target = target.parentNode;88}89} else if (e.getType() === 'click') {90openSearch(target, {lang: lang});91}92});93}9495function canLinkNode(node) {96try {97// If we're in an inline comment, don't link symbols.98if (JX.DOM.findAbove(node, 'div', 'differential-inline-comment')) {99return false;100}101} catch (ex) {102// Continue if we're not inside an inline comment.103}104105// See T13644. Don't open symbols if we're inside a changeset header.106try {107if (JX.DOM.findAbove(node, 'h1')) {108return false;109}110} catch (ex) {111// Continue if not inside a header.112}113114return true;115}116117function unhighlight() {118highlighted && JX.DOM.alterClass(highlighted, classHighlight, false);119highlighted = null;120}121122function openSearch(target, context) {123var symbol = target.textContent || target.innerText;124125context = context || {};126context.lang = context.lang || null;127context.repositories =128context.repositories ||129(config && config.repositories) ||130[];131132var query = JX.copy({}, context);133if (query.repositories.length) {134query.repositories = query.repositories.join(',');135} else {136delete query.repositories;137}138query.jump = true;139140var c = target.className;141c = c.replace(classHighlight, '').trim();142143if (class_map[c]) {144query.type = class_map[c];145}146147if (target.hasAttribute('data-symbol-context')) {148query.context = target.getAttribute('data-symbol-context');149}150151if (target.hasAttribute('data-symbol-name')) {152symbol = target.getAttribute('data-symbol-name');153}154155var line = getLineNumber(target);156if (line !== null) {157query.line = line;158}159160if (!query.hasOwnProperty('path')) {161var path = getPath(target);162if (path !== null) {163query.path = path;164}165}166167var char = getChar(target);168if (char !== null) {169query.char = char;170}171172var uri_symbol = symbol;173174// In some cases, lexers may include whitespace in symbol tags. Trim it,175// since symbols with semantic whitespace aren't supported.176uri_symbol = uri_symbol.trim();177178// See T13437. Symbols like "#define" need to be encoded.179// See T13644. Symbols like "a/b" must be double-encoded to survive180// one layer of decoding by the webserver.181uri_symbol = encodeURIComponent(uri_symbol);182uri_symbol = encodeURIComponent(uri_symbol);183184var uri = JX.$U('/diffusion/symbol/' + uri_symbol + '/');185uri.addQueryParams(query);186187window.open(uri.toString());188}189190function linkAll() {191var blocks = JX.DOM.scry(document.body, 'div', 'remarkup-code-block');192for (var i = 0; i < blocks.length; ++i) {193if (blocks[i].hasAttribute('data-code-lang')) {194var lang = blocks[i].getAttribute('data-code-lang');195link(blocks[i], lang);196}197}198}199200function getLineNumber(target) {201202// Figure out the line number by finding the most recent "<th />" in this203// row with a number in it. We may need to skip over one "<th />" if the204// diff is being displayed in unified mode.205206var cell = JX.DOM.findAbove(target, 'td');207if (!cell) {208return null;209}210211var row = JX.DOM.findAbove(target, 'tr');212if (!row) {213return null;214}215216var ii;217218var cell_list = [];219for (ii = 0; ii < row.childNodes.length; ii++) {220cell_list.push(row.childNodes[ii]);221}222cell_list.reverse();223224var found = false;225for (ii = 0; ii < cell_list.length; ii++) {226if (cell_list[ii] === cell) {227found = true;228}229230if (found && JX.DOM.isType(cell_list[ii], 'th')) {231var int_value = parseInt(cell_list[ii].textContent, 10);232if (int_value) {233return int_value;234}235}236}237238return null;239}240241function getPath(target) {242// This method works in Differential, when browsing a changeset.243var changeset;244try {245changeset = JX.DOM.findAbove(target, 'div', 'differential-changeset');246return JX.Stratcom.getData(changeset).symbolPath || null;247} catch (ex) {248// Ignore.249}250251return null;252}253254function getChar(target) {255var cell = JX.DOM.findAbove(target, 'td');256if (!cell) {257return null;258}259260var char = 1;261for (var ii = 0; ii < cell.childNodes.length; ii++) {262var node = cell.childNodes[ii];263264if (node === target) {265return char;266}267268var content = '' + node.textContent;269char += content.length;270}271272return null;273}274275JX.Stratcom.listen(276'differential-preview-update',277null,278function(e) {279linkAll(e.getData().container);280});281282283JX.Stratcom.listen(284['keydown', 'keyup'],285null,286function(e) {287if (!isHighlightModifierKey(e)) {288return;289}290291setCursorMode(e.getType() === 'keydown');292293if (!statics.active) {294unhighlight();295}296});297298JX.Stratcom.listen(299'blur',300null,301function(e) {302if (e.getTarget()) {303return;304}305unhighlight();306setCursorMode(false);307});308309function setCursorMode(active) {310statics.active = active;311linked.forEach(function(element) {312JX.DOM.alterClass(element, classMouseCursor, statics.active);313});314}315316317if (config && config.container) {318link(JX.$(config.container), config.lang);319}320321JX.Stratcom.listen(322['mouseover', 'mouseout', 'click'],323['has-symbols', 'tag:span'],324function(e) {325var type = e.getType();326327if (type === 'mouseout') {328unhighlight();329return;330}331332if (!hasHighlightModifierKey(e)) {333return;334}335336var target = e.getTarget();337338if (!canLinkNode(target)) {339return;340}341342// If only part of the symbol was edited, the symbol name itself will343// have another "<span />" inside of it which highlights only the344// edited part. Skip over it.345if (JX.DOM.isNode(target, 'span') && (target.className === 'bright')) {346target = target.parentNode;347}348349if (type === 'click') {350openSearch(target, e.getNodeData('has-symbols').symbols);351e.kill();352return;353}354355if (e.getType() === 'mouseover') {356while (target && target !== document.body) {357if (!JX.DOM.isNode(target, 'span')) {358target = target.parentNode;359continue;360}361362if (!class_map.hasOwnProperty(target.className)) {363target = target.parentNode;364continue;365}366367highlighted = target;368JX.DOM.alterClass(highlighted, classHighlight, true);369break;370}371}372});373374});375376377