Commit 334f5665 authored by Vitaly Slobodin's avatar Vitaly Slobodin

Merge branch 'dmishunov/highlighter-without-jquery' into 'master'

Removed dependency on $ from the highlighter

See merge request gitlab-org/gitlab!67771
parents 7b88f1be 21e12916
...@@ -11,7 +11,7 @@ import renderMetrics from './render_metrics'; ...@@ -11,7 +11,7 @@ import renderMetrics from './render_metrics';
// Delegates to syntax highlight and render math & mermaid diagrams. // Delegates to syntax highlight and render math & mermaid diagrams.
// //
$.fn.renderGFM = function renderGFM() { $.fn.renderGFM = function renderGFM() {
syntaxHighlight(this.find('.js-syntax-highlight')); syntaxHighlight(this.find('.js-syntax-highlight').get());
renderMath(this.find('.js-render-math')); renderMath(this.find('.js-render-math'));
renderMermaid(this.find('.js-render-mermaid')); renderMermaid(this.find('.js-render-mermaid'));
highlightCurrentUser(this.find('.gfm-project_member').get()); highlightCurrentUser(this.find('.gfm-project_member').get());
......
/* eslint-disable consistent-return */ /* eslint-disable consistent-return */
import $ from 'jquery';
// Syntax Highlighter // Syntax Highlighter
// //
// Applies a syntax highlighting color scheme CSS class to any element with the // Applies a syntax highlighting color scheme CSS class to any element with the
...@@ -12,14 +10,30 @@ import $ from 'jquery'; ...@@ -12,14 +10,30 @@ import $ from 'jquery';
// <div class="js-syntax-highlight"></div> // <div class="js-syntax-highlight"></div>
// //
export default function syntaxHighlight(el) { export default function syntaxHighlight($els = null) {
if ($(el).hasClass('js-syntax-highlight')) { if (!$els) return;
const els = $els.get ? $els.get() : $els;
const handler = (el) => {
if (el.classList.contains('js-syntax-highlight')) {
// Given the element itself, apply highlighting // Given the element itself, apply highlighting
return $(el).addClass(gon.user_color_scheme); return el.classList.add(gon.user_color_scheme);
} }
// Given a parent element, recurse to any of its applicable children // Given a parent element, recurse to any of its applicable children
const $children = $(el).find('.js-syntax-highlight'); const children = el.querySelectorAll('.js-syntax-highlight');
if ($children.length) { if (children.length) {
return syntaxHighlight($children); return syntaxHighlight(children);
}
};
// In order to account for NodeList returned by document.querySelectorAll,
// we should rather check whether the els object is iterable
// instead of relying on Array.isArray()
const isIterable = typeof els[Symbol.iterator] === 'function';
if (isIterable) {
els.forEach((el) => handler(el));
} else {
handler(els);
} }
} }
...@@ -10,6 +10,14 @@ describe('Syntax Highlighter', () => { ...@@ -10,6 +10,14 @@ describe('Syntax Highlighter', () => {
} }
return (window.gon.user_color_scheme = value); return (window.gon.user_color_scheme = value);
}; };
// We have to bind `document.querySelectorAll` to `document` to not mess up the fn's context
describe.each`
desc | fn
${'jquery'} | ${$}
${'vanilla all'} | ${document.querySelectorAll.bind(document)}
${'vanilla single'} | ${document.querySelector.bind(document)}
`('highlight using $desc syntax', ({ fn }) => {
describe('on a js-syntax-highlight element', () => { describe('on a js-syntax-highlight element', () => {
beforeEach(() => { beforeEach(() => {
setFixtures('<div class="js-syntax-highlight"></div>'); setFixtures('<div class="js-syntax-highlight"></div>');
...@@ -17,9 +25,9 @@ describe('Syntax Highlighter', () => { ...@@ -17,9 +25,9 @@ describe('Syntax Highlighter', () => {
it('applies syntax highlighting', () => { it('applies syntax highlighting', () => {
stubUserColorScheme('monokai'); stubUserColorScheme('monokai');
syntaxHighlight($('.js-syntax-highlight')); syntaxHighlight(fn('.js-syntax-highlight'));
expect($('.js-syntax-highlight')).toHaveClass('monokai'); expect(fn('.js-syntax-highlight')).toHaveClass('monokai');
}); });
}); });
...@@ -32,17 +40,20 @@ describe('Syntax Highlighter', () => { ...@@ -32,17 +40,20 @@ describe('Syntax Highlighter', () => {
it('applies highlighting to all applicable children', () => { it('applies highlighting to all applicable children', () => {
stubUserColorScheme('monokai'); stubUserColorScheme('monokai');
syntaxHighlight($('.parent')); syntaxHighlight(fn('.parent'));
expect(fn('.parent')).not.toHaveClass('monokai');
expect(fn('.foo')).not.toHaveClass('monokai');
expect($('.parent, .foo')).not.toHaveClass('monokai'); expect(document.querySelectorAll('.monokai').length).toBe(2);
expect($('.monokai').length).toBe(2);
}); });
it('prevents an infinite loop when no matches exist', () => { it('prevents an infinite loop when no matches exist', () => {
setFixtures('<div></div>'); setFixtures('<div></div>');
const highlight = () => syntaxHighlight($('div')); const highlight = () => syntaxHighlight(fn('div'));
expect(highlight).not.toThrow(); expect(highlight).not.toThrow();
}); });
}); });
});
}); });
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment