Commit de4645a8 authored by Phil Hughes's avatar Phil Hughes

Merge branch '221083-custom-renderer-font-awesome' into 'master'

Add font awesome custom renderer

Closes #221083

See merge request gitlab-org/gitlab!36361
parents 4529939f 434e1847
......@@ -3,7 +3,9 @@ import renderKramdownList from './renderers/render_kramdown_list';
import renderKramdownText from './renderers/render_kramdown_text';
import renderIdentifierParagraph from './renderers/render_identifier_paragraph';
import renderEmbeddedRubyText from './renderers/render_embedded_ruby_text';
import renderFontAwesomeHtmlInline from './renderers/render_font_awesome_html_inline';
const htmlInlineRenderers = [renderFontAwesomeHtmlInline];
const htmlRenderers = [renderHtml];
const listRenderers = [renderKramdownList];
const paragraphRenderers = [renderIdentifierParagraph];
......@@ -26,7 +28,7 @@ const buildCustomRendererFunctions = (customRenderers, defaults) => {
};
const buildCustomHTMLRenderer = (
customRenderers = { htmlBlock: [], list: [], paragraph: [], text: [] },
customRenderers = { htmlBlock: [], htmlInline: [], list: [], paragraph: [], text: [] },
) => {
const defaults = {
htmlBlock(node, context) {
......@@ -34,6 +36,11 @@ const buildCustomHTMLRenderer = (
return executeRenderer(allHtmlRenderers, node, context);
},
htmlInline(node, context) {
const allHtmlInlineRenderers = [...customRenderers.htmlInline, ...htmlInlineRenderers];
return executeRenderer(allHtmlInlineRenderers, node, context);
},
list(node, context) {
const allListRenderers = [...customRenderers.list, ...listRenderers];
......
......@@ -2,9 +2,14 @@ const buildToken = (type, tagName, props) => {
return { type, tagName, ...props };
};
export const buildUneditableOpenTokens = token => {
const TAG_TYPES = {
block: 'div',
inline: 'span',
};
export const buildUneditableOpenTokens = (token, type = TAG_TYPES.block) => {
return [
buildToken('openTag', 'div', {
buildToken('openTag', type, {
attributes: { contenteditable: false },
classNames: [
'gl-px-4 gl-py-2 gl-opacity-5 gl-bg-gray-100 gl-user-select-none gl-cursor-not-allowed',
......@@ -14,10 +19,17 @@ export const buildUneditableOpenTokens = token => {
];
};
export const buildUneditableCloseToken = () => buildToken('closeTag', 'div');
export const buildUneditableCloseToken = (type = TAG_TYPES.block) => buildToken('closeTag', type);
export const buildUneditableCloseTokens = (token, type = TAG_TYPES.block) => {
return [token, buildUneditableCloseToken(type)];
};
export const buildUneditableCloseTokens = token => {
return [token, buildToken('closeTag', 'div')];
export const buildUneditableInlineTokens = token => {
return [
...buildUneditableOpenTokens(token, TAG_TYPES.inline),
buildUneditableCloseToken(TAG_TYPES.inline),
];
};
export const buildUneditableTokens = token => {
......
import { buildUneditableInlineTokens } from './build_uneditable_token';
const fontAwesomeRegexOpen = /<i class="fa.+>/;
const canRender = ({ literal }) => {
return fontAwesomeRegexOpen.test(literal);
};
const render = (_, { origin }) => buildUneditableInlineTokens(origin());
export default { canRender, render };
---
title: Add a custom HTML renderer to the Static Site Editor for font awesome inline HTML syntax
merge_request: 36361
author:
type: added
......@@ -2,14 +2,17 @@ import {
buildUneditableOpenTokens,
buildUneditableCloseToken,
buildUneditableCloseTokens,
buildUneditableInlineTokens,
buildUneditableTokens,
} from '~/vue_shared/components/rich_content_editor/services/renderers/build_uneditable_token';
import {
originInlineToken,
originToken,
uneditableOpenTokens,
uneditableCloseToken,
uneditableCloseTokens,
uneditableInlineTokens,
uneditableTokens,
} from './mock_data';
......@@ -38,8 +41,17 @@ describe('Build Uneditable Token renderer helper', () => {
});
});
describe('buildUneditableInlineTokens', () => {
it('returns a 3-item array of tokens with the originInlineToken wrapped in the middle of inline tokens', () => {
const result = buildUneditableInlineTokens(originInlineToken);
expect(result).toHaveLength(3);
expect(result).toStrictEqual(uneditableInlineTokens);
});
});
describe('buildUneditableTokens', () => {
it('returns a 3-item array of tokens with the originToken wrapped in the middle', () => {
it('returns a 3-item array of tokens with the originToken wrapped in the middle of block tokens', () => {
const result = buildUneditableTokens(originToken);
expect(result).toHaveLength(3);
......
......@@ -12,20 +12,36 @@ export const normalTextNode = buildMockTextNode('This is just normal text.');
// Token spec helpers
const uneditableOpenToken = {
type: 'openTag',
tagName: 'div',
attributes: { contenteditable: false },
classNames: [
'gl-px-4 gl-py-2 gl-opacity-5 gl-bg-gray-100 gl-user-select-none gl-cursor-not-allowed',
],
const buildUneditableOpenToken = type => {
return {
type: 'openTag',
tagName: type,
attributes: { contenteditable: false },
classNames: [
'gl-px-4 gl-py-2 gl-opacity-5 gl-bg-gray-100 gl-user-select-none gl-cursor-not-allowed',
],
};
};
const buildUneditableCloseToken = type => {
return { type: 'closeTag', tagName: type };
};
export const uneditableCloseToken = { type: 'closeTag', tagName: 'div' };
export const originToken = {
type: 'text',
content: '{:.no_toc .hidden-md .hidden-lg}',
};
export const uneditableOpenTokens = [uneditableOpenToken, originToken];
export const uneditableCloseToken = buildUneditableCloseToken('div');
export const uneditableOpenTokens = [buildUneditableOpenToken('div'), originToken];
export const uneditableCloseTokens = [originToken, uneditableCloseToken];
export const uneditableTokens = [...uneditableOpenTokens, uneditableCloseToken];
export const originInlineToken = {
type: 'text',
content: '<i>Inline</i> content',
};
export const uneditableInlineTokens = [
buildUneditableOpenToken('span'),
originInlineToken,
buildUneditableCloseToken('span'),
];
import renderer from '~/vue_shared/components/rich_content_editor/services/renderers/render_font_awesome_html_inline';
import { buildUneditableInlineTokens } from '~/vue_shared/components/rich_content_editor/services/renderers/build_uneditable_token';
import { normalTextNode } from './mock_data';
const fontAwesomeInlineHtmlNode = {
firstChild: null,
literal: '<i class="far fa-paper-plane" id="biz-tech-icons">',
type: 'html',
};
describe('Render Font Awesome Inline HTML renderer', () => {
describe('canRender', () => {
it('should return true when the argument `literal` has font awesome inline html syntax', () => {
expect(renderer.canRender(fontAwesomeInlineHtmlNode)).toBe(true);
});
it('should return false when the argument `literal` lacks font awesome inline html syntax', () => {
expect(renderer.canRender(normalTextNode)).toBe(false);
});
});
describe('render', () => {
it('should return uneditable inline tokens', () => {
const token = { type: 'text', tagName: null, content: fontAwesomeInlineHtmlNode.literal };
const context = { origin: () => token };
expect(renderer.render(fontAwesomeInlineHtmlNode, context)).toStrictEqual(
buildUneditableInlineTokens(token),
);
});
});
});
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