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;
// Given the element itself, apply highlighting
return $(el).addClass(gon.user_color_scheme); const els = $els.get ? $els.get() : $els;
} const handler = (el) => {
// Given a parent element, recurse to any of its applicable children if (el.classList.contains('js-syntax-highlight')) {
const $children = $(el).find('.js-syntax-highlight'); // Given the element itself, apply highlighting
if ($children.length) { return el.classList.add(gon.user_color_scheme);
return syntaxHighlight($children); }
// Given a parent element, recurse to any of its applicable children
const children = el.querySelectorAll('.js-syntax-highlight');
if (children.length) {
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,39 +10,50 @@ describe('Syntax Highlighter', () => { ...@@ -10,39 +10,50 @@ describe('Syntax Highlighter', () => {
} }
return (window.gon.user_color_scheme = value); return (window.gon.user_color_scheme = value);
}; };
describe('on a js-syntax-highlight element', () => {
beforeEach(() => {
setFixtures('<div class="js-syntax-highlight"></div>');
});
it('applies syntax highlighting', () => {
stubUserColorScheme('monokai');
syntaxHighlight($('.js-syntax-highlight'));
expect($('.js-syntax-highlight')).toHaveClass('monokai'); // 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', () => {
beforeEach(() => {
setFixtures('<div class="js-syntax-highlight"></div>');
});
it('applies syntax highlighting', () => {
stubUserColorScheme('monokai');
syntaxHighlight(fn('.js-syntax-highlight'));
expect(fn('.js-syntax-highlight')).toHaveClass('monokai');
});
}); });
});
describe('on a parent element', () => { describe('on a parent element', () => {
beforeEach(() => { beforeEach(() => {
setFixtures( setFixtures(
'<div class="parent">\n <div class="js-syntax-highlight"></div>\n <div class="foo"></div>\n <div class="js-syntax-highlight"></div>\n</div>', '<div class="parent">\n <div class="js-syntax-highlight"></div>\n <div class="foo"></div>\n <div class="js-syntax-highlight"></div>\n</div>',
); );
}); });
it('applies highlighting to all applicable children', () => { it('applies highlighting to all applicable children', () => {
stubUserColorScheme('monokai'); stubUserColorScheme('monokai');
syntaxHighlight($('.parent')); syntaxHighlight(fn('.parent'));
expect($('.parent, .foo')).not.toHaveClass('monokai'); expect(fn('.parent')).not.toHaveClass('monokai');
expect($('.monokai').length).toBe(2); expect(fn('.foo')).not.toHaveClass('monokai');
});
expect(document.querySelectorAll('.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