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';
// Delegates to syntax highlight and render math & mermaid diagrams.
//
$.fn.renderGFM = function renderGFM() {
syntaxHighlight(this.find('.js-syntax-highlight'));
syntaxHighlight(this.find('.js-syntax-highlight').get());
renderMath(this.find('.js-render-math'));
renderMermaid(this.find('.js-render-mermaid'));
highlightCurrentUser(this.find('.gfm-project_member').get());
......
/* eslint-disable consistent-return */
import $ from 'jquery';
// Syntax Highlighter
//
// Applies a syntax highlighting color scheme CSS class to any element with the
......@@ -12,14 +10,30 @@ import $ from 'jquery';
// <div class="js-syntax-highlight"></div>
//
export default function syntaxHighlight(el) {
if ($(el).hasClass('js-syntax-highlight')) {
// Given the element itself, apply highlighting
return $(el).addClass(gon.user_color_scheme);
}
// Given a parent element, recurse to any of its applicable children
const $children = $(el).find('.js-syntax-highlight');
if ($children.length) {
return syntaxHighlight($children);
export default function syntaxHighlight($els = null) {
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
return el.classList.add(gon.user_color_scheme);
}
// 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', () => {
}
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', () => {
beforeEach(() => {
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>',
);
});
describe('on a parent element', () => {
beforeEach(() => {
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>',
);
});
it('applies highlighting to all applicable children', () => {
stubUserColorScheme('monokai');
syntaxHighlight($('.parent'));
it('applies highlighting to all applicable children', () => {
stubUserColorScheme('monokai');
syntaxHighlight(fn('.parent'));
expect($('.parent, .foo')).not.toHaveClass('monokai');
expect($('.monokai').length).toBe(2);
});
expect(fn('.parent')).not.toHaveClass('monokai');
expect(fn('.foo')).not.toHaveClass('monokai');
expect(document.querySelectorAll('.monokai').length).toBe(2);
});
it('prevents an infinite loop when no matches exist', () => {
setFixtures('<div></div>');
const highlight = () => syntaxHighlight($('div'));
it('prevents an infinite loop when no matches exist', () => {
setFixtures('<div></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