All files / app/assets/javascripts/code_navigation/utils index.js

96.29% Statements 26/27
90% Branches 9/10
100% Functions 6/6
100% Lines 23/23

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43    2x   2x   3x 2x   2x 9x 9x     9x   9x 9x   9x 4x     8x   4x     9x 13x 4x 4x     9x 8x 8x 8x 8x        
import { wrapNodes, isTextNode } from './dom_utils';
 
export const cachedData = new Map();
 
const wrappedLines = new WeakSet();
 
export const getCurrentHoverElement = () => cachedData.get('current');
export const setCurrentHoverElement = (el) => cachedData.set('current', el);
 
export const addInteractionClass = ({ path, d, wrapTextNodes }) => {
  const lineNumber = d.start_line + 1;
  const lines = document
    .querySelector(`[data-path="${path}"]`)
    .querySelectorAll(`.blob-content #LC${lineNumber}, .line_content:not(.old) #LC${lineNumber}`);
  Iif (!lines?.length) return;
 
  lines.forEach((line) => {
    let charCount = 0;
 
    if (wrapTextNodes) {
      line.childNodes.forEach((elm) => {
        // Highlight.js does not wrap all text nodes by default
        // We need all text nodes to be wrapped in order to append code nav attributes
        elm.replaceWith(...wrapNodes(elm.textContent, elm.classList, elm.dataset));
      });
      wrappedLines.add(line);
    }
 
    const el = [...line.childNodes].find(({ textContent }) => {
      if (charCount === d.start_char) return true;
      charCount += textContent.length;
      return false;
    });
 
    if (el && !isTextNode(el)) {
      el.dataset.charIndex = d.start_char;
      el.dataset.lineIndex = d.start_line;
      el.classList.add('cursor-pointer', 'code-navigation', 'js-code-navigation');
      el.closest('.line').classList.add('code-navigation-line');
    }
  });
};