Commit 78a8c6e8 authored by Jose Ivan Vargas's avatar Jose Ivan Vargas

Merge branch '232567-templater' into 'master'

Resolve "Custom renderers cleanup - erb"

Closes #232567

See merge request gitlab-org/gitlab!38694
parents 2353e28f 08a78828
...@@ -8,6 +8,7 @@ import { EDITOR_TYPES } from '~/vue_shared/components/rich_content_editor/consta ...@@ -8,6 +8,7 @@ import { EDITOR_TYPES } from '~/vue_shared/components/rich_content_editor/consta
import { DEFAULT_IMAGE_UPLOAD_PATH } from '../constants'; import { DEFAULT_IMAGE_UPLOAD_PATH } from '../constants';
import imageRepository from '../image_repository'; import imageRepository from '../image_repository';
import formatter from '../services/formatter'; import formatter from '../services/formatter';
import templater from '../services/templater';
export default { export default {
components: { components: {
...@@ -44,7 +45,7 @@ export default { ...@@ -44,7 +45,7 @@ export default {
data() { data() {
return { return {
saveable: false, saveable: false,
parsedSource: parseSourceFile(this.content), parsedSource: parseSourceFile(this.preProcess(true, this.content)),
editorMode: EDITOR_TYPES.wysiwyg, editorMode: EDITOR_TYPES.wysiwyg,
isModified: false, isModified: false,
}; };
...@@ -59,22 +60,30 @@ export default { ...@@ -59,22 +60,30 @@ export default {
}, },
}, },
methods: { methods: {
preProcess(isWrap, value) {
const formattedContent = formatter(value);
const templatedContent = isWrap
? templater.wrap(formattedContent)
: templater.unwrap(formattedContent);
return templatedContent;
},
onInputChange(newVal) { onInputChange(newVal) {
this.parsedSource.sync(newVal, this.isWysiwygMode); this.parsedSource.sync(newVal, this.isWysiwygMode);
this.isModified = this.parsedSource.isModified(); this.isModified = this.parsedSource.isModified();
}, },
onModeChange(mode) { onModeChange(mode) {
this.editorMode = mode; this.editorMode = mode;
const formattedContent = formatter(this.editableContent);
this.$refs.editor.resetInitialValue(formattedContent); const preProcessedContent = this.preProcess(this.isWysiwygMode, this.editableContent);
this.$refs.editor.resetInitialValue(preProcessedContent);
}, },
onUploadImage({ file, imageUrl }) { onUploadImage({ file, imageUrl }) {
this.$options.imageRepository.add(file, imageUrl); this.$options.imageRepository.add(file, imageUrl);
}, },
onSubmit() { onSubmit() {
const formattedContent = formatter(this.parsedSource.content()); const preProcessedContent = this.preProcess(false, this.parsedSource.content());
this.$emit('submit', { this.$emit('submit', {
content: formattedContent, content: preProcessedContent,
images: this.$options.imageRepository.getAll(), images: this.$options.imageRepository.getAll(),
}); });
}, },
......
const marker = 'sse';
const ticks = '```';
const prefix = `${ticks} ${marker}\n`; // Space intentional due to https://github.com/nhn/tui.editor/blob/6bcec75c69028570d93d973aa7533090257eaae0/libs/to-mark/src/renderer.gfm.js#L26
const postfix = `\n${ticks}`;
const code = '.| |\\t|\\n(?!\\n)';
const templatedRegex = new RegExp(`(^${prefix}(${code})+${postfix}$)`, 'gm');
const embeddedRubyRegex = new RegExp(`(^<%(${code})+%>$)`, 'gm');
const unwrap = source => {
let text = source;
const matches = text.match(templatedRegex);
if (matches) {
matches.forEach(match => {
const initial = match.replace(prefix, '').replace(postfix, '');
text = text.replace(match, initial);
});
}
return text;
};
const wrap = source => {
let text = unwrap(source);
const matches = text.match(embeddedRubyRegex);
if (matches) {
matches.forEach(match => {
text = text.replace(match, `${prefix}${match}${postfix}`);
});
}
return text;
};
export default { wrap, unwrap };
...@@ -3,7 +3,6 @@ import renderKramdownList from './renderers/render_kramdown_list'; ...@@ -3,7 +3,6 @@ import renderKramdownList from './renderers/render_kramdown_list';
import renderKramdownText from './renderers/render_kramdown_text'; import renderKramdownText from './renderers/render_kramdown_text';
import renderIdentifierInstanceText from './renderers/render_identifier_instance_text'; import renderIdentifierInstanceText from './renderers/render_identifier_instance_text';
import renderIdentifierParagraph from './renderers/render_identifier_paragraph'; import renderIdentifierParagraph from './renderers/render_identifier_paragraph';
import renderEmbeddedRubyText from './renderers/render_embedded_ruby_text';
import renderFontAwesomeHtmlInline from './renderers/render_font_awesome_html_inline'; import renderFontAwesomeHtmlInline from './renderers/render_font_awesome_html_inline';
import renderSoftbreak from './renderers/render_softbreak'; import renderSoftbreak from './renderers/render_softbreak';
...@@ -11,7 +10,7 @@ const htmlInlineRenderers = [renderFontAwesomeHtmlInline]; ...@@ -11,7 +10,7 @@ const htmlInlineRenderers = [renderFontAwesomeHtmlInline];
const htmlBlockRenderers = [renderBlockHtml]; const htmlBlockRenderers = [renderBlockHtml];
const listRenderers = [renderKramdownList]; const listRenderers = [renderKramdownList];
const paragraphRenderers = [renderIdentifierParagraph]; const paragraphRenderers = [renderIdentifierParagraph];
const textRenderers = [renderKramdownText, renderEmbeddedRubyText, renderIdentifierInstanceText]; const textRenderers = [renderKramdownText, renderIdentifierInstanceText];
const softbreakRenderers = [renderSoftbreak]; const softbreakRenderers = [renderSoftbreak];
const executeRenderer = (renderers, node, context) => { const executeRenderer = (renderers, node, context) => {
......
---
title: Added pre-processing step to the Static Site Editor so code templates (ERB) are interpreted as code not content
merge_request: 38694
author:
type: added
...@@ -15,11 +15,11 @@ import { ...@@ -15,11 +15,11 @@ import {
returnUrl, returnUrl,
} from '../mock_data'; } from '../mock_data';
jest.mock('~/static_site_editor/services/formatter', () => jest.fn(str => `${str} formatted`)); jest.mock('~/static_site_editor/services/formatter', () => jest.fn(str => `${str} format-pass`));
describe('~/static_site_editor/components/edit_area.vue', () => { describe('~/static_site_editor/components/edit_area.vue', () => {
let wrapper; let wrapper;
const formattedContent = `${content} formatted`; const formattedBody = `${body} format-pass`;
const savingChanges = true; const savingChanges = true;
const newBody = `new ${body}`; const newBody = `new ${body}`;
...@@ -53,9 +53,9 @@ describe('~/static_site_editor/components/edit_area.vue', () => { ...@@ -53,9 +53,9 @@ describe('~/static_site_editor/components/edit_area.vue', () => {
expect(findEditHeader().props('title')).toBe(title); expect(findEditHeader().props('title')).toBe(title);
}); });
it('renders rich content editor', () => { it('renders rich content editor with a format pass', () => {
expect(findRichContentEditor().exists()).toBe(true); expect(findRichContentEditor().exists()).toBe(true);
expect(findRichContentEditor().props('content')).toBe(body); expect(findRichContentEditor().props('content')).toBe(formattedBody);
}); });
it('renders publish toolbar', () => { it('renders publish toolbar', () => {
...@@ -97,7 +97,7 @@ describe('~/static_site_editor/components/edit_area.vue', () => { ...@@ -97,7 +97,7 @@ describe('~/static_site_editor/components/edit_area.vue', () => {
}); });
it('sets publish toolbar as not saveable when content changes are rollback', () => { it('sets publish toolbar as not saveable when content changes are rollback', () => {
findRichContentEditor().vm.$emit('input', body); findRichContentEditor().vm.$emit('input', formattedBody);
return wrapper.vm.$nextTick().then(() => { return wrapper.vm.$nextTick().then(() => {
expect(findPublishToolbar().props('saveable')).toBe(false); expect(findPublishToolbar().props('saveable')).toBe(false);
...@@ -124,8 +124,8 @@ describe('~/static_site_editor/components/edit_area.vue', () => { ...@@ -124,8 +124,8 @@ describe('~/static_site_editor/components/edit_area.vue', () => {
it.each` it.each`
initialMode | targetMode | resetValue initialMode | targetMode | resetValue
${EDITOR_TYPES.wysiwyg} | ${EDITOR_TYPES.markdown} | ${formattedContent} ${EDITOR_TYPES.wysiwyg} | ${EDITOR_TYPES.markdown} | ${`${content} format-pass format-pass`}
${EDITOR_TYPES.markdown} | ${EDITOR_TYPES.wysiwyg} | ${`${body} formatted`} ${EDITOR_TYPES.markdown} | ${EDITOR_TYPES.wysiwyg} | ${`${body} format-pass format-pass`}
`( `(
'sets editorMode from $initialMode to $targetMode', 'sets editorMode from $initialMode to $targetMode',
({ initialMode, targetMode, resetValue }) => { ({ initialMode, targetMode, resetValue }) => {
...@@ -144,7 +144,7 @@ describe('~/static_site_editor/components/edit_area.vue', () => { ...@@ -144,7 +144,7 @@ describe('~/static_site_editor/components/edit_area.vue', () => {
findRichContentEditor().vm.$emit('modeChange', EDITOR_TYPES.markdown); findRichContentEditor().vm.$emit('modeChange', EDITOR_TYPES.markdown);
expect(resetInitialValue).toHaveBeenCalledWith(formattedContent); expect(resetInitialValue).toHaveBeenCalledWith(`${content} format-pass format-pass`);
}); });
}); });
...@@ -152,7 +152,7 @@ describe('~/static_site_editor/components/edit_area.vue', () => { ...@@ -152,7 +152,7 @@ describe('~/static_site_editor/components/edit_area.vue', () => {
it('should format the content', () => { it('should format the content', () => {
findPublishToolbar().vm.$emit('submit', content); findPublishToolbar().vm.$emit('submit', content);
expect(wrapper.emitted('submit')[0][0].content).toBe(formattedContent); expect(wrapper.emitted('submit')[0][0].content).toBe(`${content} format-pass format-pass`);
}); });
}); });
}); });
/* eslint-disable no-useless-escape */
import templater from '~/static_site_editor/services/templater';
describe('templater', () => {
const source = `Some text
<% some erb code %>
Some more text
<% if apptype.maturity && (apptype.maturity != "planned") %>
<% maturity = "This application type is at the \"#{apptype.maturity}\" level of maturity." %>
<% end %>
With even text with indented code above.
`;
const sourceTemplated = `Some text
\`\`\` sse
<% some erb code %>
\`\`\`
Some more text
\`\`\` sse
<% if apptype.maturity && (apptype.maturity != "planned") %>
<% maturity = "This application type is at the \"#{apptype.maturity}\" level of maturity." %>
<% end %>
\`\`\`
With even text with indented code above.
`;
it.each`
fn | initial | target
${'wrap'} | ${source} | ${sourceTemplated}
${'wrap'} | ${sourceTemplated} | ${sourceTemplated}
${'unwrap'} | ${sourceTemplated} | ${source}
${'unwrap'} | ${source} | ${source}
`(
'wraps $initial in a templated sse codeblock if $fn is wrap, unwraps otherwise',
({ fn, initial, target }) => {
expect(templater[fn](initial)).toMatch(target);
},
);
});
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