Commit 750af9fd authored by Brett Walker's avatar Brett Walker Committed by Sean McGivern

Use proper markdown rendering for previews

parent 9790fe58
...@@ -108,6 +108,11 @@ ...@@ -108,6 +108,11 @@
type: String, type: String,
required: true, required: true,
}, },
markdownVersion: {
type: Number,
required: false,
default: 0,
},
projectPath: { projectPath: {
type: String, type: String,
required: true, required: true,
...@@ -282,6 +287,7 @@ ...@@ -282,6 +287,7 @@
:issuable-templates="issuableTemplates" :issuable-templates="issuableTemplates"
:markdown-docs-path="markdownDocsPath" :markdown-docs-path="markdownDocsPath"
:markdown-preview-path="markdownPreviewPath" :markdown-preview-path="markdownPreviewPath"
:markdown-version="markdownVersion"
:project-path="projectPath" :project-path="projectPath"
:project-namespace="projectNamespace" :project-namespace="projectNamespace"
:show-delete-button="showDeleteButton" :show-delete-button="showDeleteButton"
......
...@@ -20,6 +20,11 @@ ...@@ -20,6 +20,11 @@
type: String, type: String,
required: true, required: true,
}, },
markdownVersion: {
type: Number,
required: false,
default: 0,
},
canAttachFile: { canAttachFile: {
type: Boolean, type: Boolean,
required: false, required: false,
...@@ -47,6 +52,7 @@ ...@@ -47,6 +52,7 @@
<markdown-field <markdown-field
:markdown-preview-path="markdownPreviewPath" :markdown-preview-path="markdownPreviewPath"
:markdown-docs-path="markdownDocsPath" :markdown-docs-path="markdownDocsPath"
:markdown-version="markdownVersion"
:can-attach-file="canAttachFile" :can-attach-file="canAttachFile"
:enable-autocomplete="enableAutocomplete" :enable-autocomplete="enableAutocomplete"
> >
......
...@@ -35,6 +35,11 @@ ...@@ -35,6 +35,11 @@
type: String, type: String,
required: true, required: true,
}, },
markdownVersion: {
type: Number,
required: false,
default: 0,
},
projectPath: { projectPath: {
type: String, type: String,
required: true, required: true,
...@@ -97,6 +102,7 @@ ...@@ -97,6 +102,7 @@
:form-state="formState" :form-state="formState"
:markdown-preview-path="markdownPreviewPath" :markdown-preview-path="markdownPreviewPath"
:markdown-docs-path="markdownDocsPath" :markdown-docs-path="markdownDocsPath"
:markdown-version="markdownVersion"
:can-attach-file="canAttachFile" :can-attach-file="canAttachFile"
:enable-autocomplete="enableAutocomplete" :enable-autocomplete="enableAutocomplete"
/> />
......
...@@ -1251,13 +1251,15 @@ export default class Notes { ...@@ -1251,13 +1251,15 @@ export default class Notes {
var postUrl = $originalContentEl.data('postUrl'); var postUrl = $originalContentEl.data('postUrl');
var targetId = $originalContentEl.data('targetId'); var targetId = $originalContentEl.data('targetId');
var targetType = $originalContentEl.data('targetType'); var targetType = $originalContentEl.data('targetType');
var markdownVersion = $originalContentEl.data('markdownVersion');
this.glForm = new GLForm($editForm.find('form'), this.enableGFM); this.glForm = new GLForm($editForm.find('form'), this.enableGFM);
$editForm $editForm
.find('form') .find('form')
.attr('action', `${postUrl}?html=true`) .attr('action', `${postUrl}?html=true`)
.attr('data-remote', 'true'); .attr('data-remote', 'true')
.attr('data-markdown-version', markdownVersion);
$editForm.find('.js-form-target-id').val(targetId); $editForm.find('.js-form-target-id').val(targetId);
$editForm.find('.js-form-target-type').val(targetType); $editForm.find('.js-form-target-type').val(targetType);
$editForm $editForm
......
...@@ -34,6 +34,11 @@ export default { ...@@ -34,6 +34,11 @@ export default {
type: String, type: String,
required: true, required: true,
}, },
markdownVersion: {
type: Number,
required: false,
default: 0,
},
}, },
data() { data() {
return { return {
...@@ -344,6 +349,7 @@ Please check your network connection and try again.`; ...@@ -344,6 +349,7 @@ Please check your network connection and try again.`;
:markdown-preview-path="markdownPreviewPath" :markdown-preview-path="markdownPreviewPath"
:markdown-docs-path="markdownDocsPath" :markdown-docs-path="markdownDocsPath"
:quick-actions-docs-path="quickActionsDocsPath" :quick-actions-docs-path="quickActionsDocsPath"
:markdown-version="markdownVersion"
:add-spacing-classes="false"> :add-spacing-classes="false">
<textarea <textarea
id="note-body" id="note-body"
......
...@@ -92,6 +92,7 @@ export default { ...@@ -92,6 +92,7 @@ export default {
:is-editing="isEditing" :is-editing="isEditing"
:note-body="noteBody" :note-body="noteBody"
:note-id="note.id" :note-id="note.id"
:markdown-version="note.cached_markdown_version"
@handleFormUpdate="handleFormUpdate" @handleFormUpdate="handleFormUpdate"
@cancelForm="formCancelHandler" @cancelForm="formCancelHandler"
/> />
......
...@@ -24,6 +24,11 @@ export default { ...@@ -24,6 +24,11 @@ export default {
required: false, required: false,
default: 0, default: 0,
}, },
markdownVersion: {
type: Number,
required: false,
default: 0,
},
saveButtonTitle: { saveButtonTitle: {
type: String, type: String,
required: false, required: false,
...@@ -156,6 +161,7 @@ export default { ...@@ -156,6 +161,7 @@ export default {
<markdown-field <markdown-field
:markdown-preview-path="markdownPreviewPath" :markdown-preview-path="markdownPreviewPath"
:markdown-docs-path="markdownDocsPath" :markdown-docs-path="markdownDocsPath"
:markdown-version="markdownVersion"
:quick-actions-docs-path="quickActionsDocsPath" :quick-actions-docs-path="quickActionsDocsPath"
:add-spacing-classes="false"> :add-spacing-classes="false">
<textarea <textarea
......
...@@ -43,6 +43,11 @@ export default { ...@@ -43,6 +43,11 @@ export default {
required: false, required: false,
default: true, default: true,
}, },
markdownVersion: {
type: Number,
required: false,
default: 0,
},
}, },
data() { data() {
return { return {
...@@ -192,6 +197,7 @@ export default { ...@@ -192,6 +197,7 @@ export default {
<comment-form <comment-form
:noteable-type="noteableType" :noteable-type="noteableType"
:markdown-version="markdownVersion"
/> />
</div> </div>
</template> </template>
...@@ -15,6 +15,7 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -15,6 +15,7 @@ document.addEventListener('DOMContentLoaded', () => {
const notesDataset = document.getElementById('js-vue-notes').dataset; const notesDataset = document.getElementById('js-vue-notes').dataset;
const parsedUserData = JSON.parse(notesDataset.currentUserData); const parsedUserData = JSON.parse(notesDataset.currentUserData);
const noteableData = JSON.parse(notesDataset.noteableData); const noteableData = JSON.parse(notesDataset.noteableData);
const { markdownVersion } = notesDataset;
let currentUserData = {}; let currentUserData = {};
noteableData.noteableType = notesDataset.noteableType; noteableData.noteableType = notesDataset.noteableType;
...@@ -33,6 +34,7 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -33,6 +34,7 @@ document.addEventListener('DOMContentLoaded', () => {
return { return {
noteableData, noteableData,
currentUserData, currentUserData,
markdownVersion,
notesData: JSON.parse(notesDataset.notesData), notesData: JSON.parse(notesDataset.notesData),
}; };
}, },
...@@ -42,6 +44,7 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -42,6 +44,7 @@ document.addEventListener('DOMContentLoaded', () => {
noteableData: this.noteableData, noteableData: this.noteableData,
notesData: this.notesData, notesData: this.notesData,
userData: this.currentUserData, userData: this.currentUserData,
markdownVersion: this.markdownVersion,
}, },
}); });
}, },
......
...@@ -28,12 +28,16 @@ MarkdownPreview.prototype.ajaxCache = {}; ...@@ -28,12 +28,16 @@ MarkdownPreview.prototype.ajaxCache = {};
MarkdownPreview.prototype.showPreview = function ($form) { MarkdownPreview.prototype.showPreview = function ($form) {
var mdText; var mdText;
var markdownVersion;
var url;
var preview = $form.find('.js-md-preview'); var preview = $form.find('.js-md-preview');
var url = preview.data('url');
if (preview.hasClass('md-preview-loading')) { if (preview.hasClass('md-preview-loading')) {
return; return;
} }
mdText = $form.find('textarea.markdown-area').val(); mdText = $form.find('textarea.markdown-area').val();
markdownVersion = $form.attr('data-markdown-version');
url = this.versionedPreviewPath(preview.data('url'), markdownVersion);
if (mdText.trim().length === 0) { if (mdText.trim().length === 0) {
preview.text(this.emptyMessage); preview.text(this.emptyMessage);
...@@ -59,6 +63,14 @@ MarkdownPreview.prototype.showPreview = function ($form) { ...@@ -59,6 +63,14 @@ MarkdownPreview.prototype.showPreview = function ($form) {
} }
}; };
MarkdownPreview.prototype.versionedPreviewPath = function (markdownPreviewPath, markdownVersion) {
if (typeof markdownVersion === 'undefined') {
return markdownPreviewPath;
}
return `${markdownPreviewPath}${markdownPreviewPath.indexOf('?') === -1 ? '?' : '&'}markdown_version=${markdownVersion}`;
};
MarkdownPreview.prototype.fetchMarkdownPreview = function (text, url, success) { MarkdownPreview.prototype.fetchMarkdownPreview = function (text, url, success) {
if (!url) { if (!url) {
return; return;
......
<script> <script>
import $ from 'jquery'; import $ from 'jquery';
import { s__ } from '~/locale';
import Flash from '../../../flash'; import Flash from '../../../flash';
import GLForm from '../../../gl_form'; import GLForm from '../../../gl_form';
import markdownHeader from './header.vue'; import markdownHeader from './header.vue';
...@@ -22,6 +23,11 @@ ...@@ -22,6 +23,11 @@
type: String, type: String,
required: true, required: true,
}, },
markdownVersion: {
type: Number,
required: false,
default: 0,
},
addSpacingClasses: { addSpacingClasses: {
type: Boolean, type: Boolean,
required: false, required: false,
...@@ -92,10 +98,11 @@ ...@@ -92,10 +98,11 @@
if (text) { if (text) {
this.markdownPreviewLoading = true; this.markdownPreviewLoading = true;
this.$http.post(this.markdownPreviewPath, { text }) this.$http
.post(this.versionedPreviewPath(), { text })
.then(resp => resp.json()) .then(resp => resp.json())
.then(data => this.renderMarkdown(data)) .then(data => this.renderMarkdown(data))
.catch(() => new Flash('Error loading markdown preview')); .catch(() => new Flash(s__('Error loading markdown preview')));
} else { } else {
this.renderMarkdown(); this.renderMarkdown();
} }
...@@ -119,6 +126,13 @@ ...@@ -119,6 +126,13 @@
$(this.$refs['markdown-preview']).renderGFM(); $(this.$refs['markdown-preview']).renderGFM();
}); });
}, },
versionedPreviewPath() {
const { markdownPreviewPath, markdownVersion } = this;
return `${markdownPreviewPath}${
markdownPreviewPath.indexOf('?') === -1 ? '?' : '&'
}markdown_version=${markdownVersion}`;
},
}, },
}; };
</script> </script>
......
...@@ -14,6 +14,8 @@ module PreviewMarkdown ...@@ -14,6 +14,8 @@ module PreviewMarkdown
else {} else {}
end end
markdown_params[:markdown_engine] = result[:markdown_engine]
render json: { render json: {
body: view_context.markdown(result[:text], markdown_params), body: view_context.markdown(result[:text], markdown_params),
references: { references: {
......
...@@ -249,6 +249,7 @@ module IssuablesHelper ...@@ -249,6 +249,7 @@ module IssuablesHelper
issuableRef: issuable.to_reference, issuableRef: issuable.to_reference,
markdownPreviewPath: preview_markdown_path(parent), markdownPreviewPath: preview_markdown_path(parent),
markdownDocsPath: help_page_path('user/markdown'), markdownDocsPath: help_page_path('user/markdown'),
markdownVersion: issuable.cached_markdown_version,
issuableTemplates: issuable_templates(issuable), issuableTemplates: issuable_templates(issuable),
initialTitleHtml: markdown_field(issuable, :title), initialTitleHtml: markdown_field(issuable, :title),
initialTitleText: issuable.title, initialTitleText: issuable.title,
......
...@@ -107,6 +107,7 @@ module MarkupHelper ...@@ -107,6 +107,7 @@ module MarkupHelper
def markup(file_name, text, context = {}) def markup(file_name, text, context = {})
context[:project] ||= @project context[:project] ||= @project
context[:markdown_engine] ||= :redcarpet
html = context.delete(:rendered) || markup_unsafe(file_name, text, context) html = context.delete(:rendered) || markup_unsafe(file_name, text, context)
prepare_for_rendering(html, context) prepare_for_rendering(html, context)
end end
...@@ -120,7 +121,8 @@ module MarkupHelper ...@@ -120,7 +121,8 @@ module MarkupHelper
project: @project, project: @project,
project_wiki: @project_wiki, project_wiki: @project_wiki,
page_slug: wiki_page.slug, page_slug: wiki_page.slug,
issuable_state_filter_enabled: true issuable_state_filter_enabled: true,
markdown_engine: :redcarpet
} }
html = html =
......
...@@ -169,6 +169,7 @@ module NotesHelper ...@@ -169,6 +169,7 @@ module NotesHelper
registerPath: new_session_path(:user, redirect_to_referer: 'yes', anchor: 'register-pane'), registerPath: new_session_path(:user, redirect_to_referer: 'yes', anchor: 'register-pane'),
newSessionPath: new_session_path(:user, redirect_to_referer: 'yes'), newSessionPath: new_session_path(:user, redirect_to_referer: 'yes'),
markdownDocsPath: help_page_path('user/markdown'), markdownDocsPath: help_page_path('user/markdown'),
markdownVersion: issuable.cached_markdown_version,
quickActionsDocsPath: help_page_path('user/project/quick_actions'), quickActionsDocsPath: help_page_path('user/project/quick_actions'),
closePath: close_issuable_path(issuable), closePath: close_issuable_path(issuable),
reopenPath: reopen_issuable_path(issuable), reopenPath: reopen_issuable_path(issuable),
......
...@@ -40,6 +40,18 @@ module CacheMarkdownField ...@@ -40,6 +40,18 @@ module CacheMarkdownField
end end
end end
class MarkdownEngine
def self.from_version(version = nil)
return :common_mark if version.nil? || version == 0
if version < CacheMarkdownField::CACHE_COMMONMARK_VERSION_START
:redcarpet
else
:common_mark
end
end
end
def skip_project_check? def skip_project_check?
false false
end end
...@@ -57,7 +69,7 @@ module CacheMarkdownField ...@@ -57,7 +69,7 @@ module CacheMarkdownField
# Banzai is less strict about authors, so don't always have an author key # Banzai is less strict about authors, so don't always have an author key
context[:author] = self.author if self.respond_to?(:author) context[:author] = self.author if self.respond_to?(:author)
context[:markdown_engine] = markdown_engine context[:markdown_engine] = MarkdownEngine.from_version(latest_cached_markdown_version)
context context
end end
...@@ -123,14 +135,6 @@ module CacheMarkdownField ...@@ -123,14 +135,6 @@ module CacheMarkdownField
end end
end end
def markdown_engine
if latest_cached_markdown_version < CacheMarkdownField::CACHE_COMMONMARK_VERSION_START
:redcarpet
else
:common_mark
end
end
included do included do
cattr_reader :cached_markdown_fields do cattr_reader :cached_markdown_fields do
FieldData.new FieldData.new
......
...@@ -564,7 +564,7 @@ class Repository ...@@ -564,7 +564,7 @@ class Repository
end end
def rendered_readme def rendered_readme
MarkupHelper.markup_unsafe(readme.name, readme.data, project: project) if readme MarkupHelper.markup_unsafe(readme.name, readme.data, project: project, markdown_engine: :redcarpet) if readme
end end
cache_method :rendered_readme cache_method :rendered_readme
......
...@@ -62,6 +62,8 @@ class NoteEntity < API::Entities::Note ...@@ -62,6 +62,8 @@ class NoteEntity < API::Entities::Note
expose :attachment, using: NoteAttachmentEntity, if: -> (note, _) { note.attachment? } expose :attachment, using: NoteAttachmentEntity, if: -> (note, _) { note.attachment? }
expose :cached_markdown_version
private private
def current_user def current_user
......
...@@ -6,7 +6,8 @@ class PreviewMarkdownService < BaseService ...@@ -6,7 +6,8 @@ class PreviewMarkdownService < BaseService
success( success(
text: text, text: text,
users: users, users: users,
commands: commands.join(' ') commands: commands.join(' '),
markdown_engine: markdown_engine
) )
end end
...@@ -42,4 +43,8 @@ class PreviewMarkdownService < BaseService ...@@ -42,4 +43,8 @@ class PreviewMarkdownService < BaseService
def commands_target_id def commands_target_id
params[:quick_actions_target_id] params[:quick_actions_target_id]
end end
def markdown_engine
CacheMarkdownField::MarkdownEngine.from_version(params[:markdown_version].to_i)
end
end end
= form_for [@project.namespace.becomes(Namespace), @project, @issue], html: { class: 'issue-form common-note-form js-quick-submit js-requires-input' } do |f| = form_for [@project.namespace.becomes(Namespace), @project, @issue],
html: { class: 'issue-form common-note-form js-quick-submit js-requires-input' },
data: { markdown_version: @issue.cached_markdown_version } do |f|
= render 'shared/issuable/form', f: f, issuable: @issue = render 'shared/issuable/form', f: f, issuable: @issue
= form_for [@project.namespace.becomes(Namespace), @project, @merge_request], html: { class: 'merge-request-form common-note-form js-requires-input js-quick-submit' } do |f| = form_for [@project.namespace.becomes(Namespace), @project, @merge_request],
html: { class: 'merge-request-form common-note-form js-requires-input js-quick-submit' },
data: { markdown_version: @merge_request.cached_markdown_version } do |f|
= render 'shared/issuable/form', f: f, issuable: @merge_request = render 'shared/issuable/form', f: f, issuable: @merge_request
= form_for [@project.namespace.becomes(Namespace), @project, @milestone], html: {class: 'milestone-form common-note-form js-quick-submit js-requires-input'} do |f| = form_for [@project.namespace.becomes(Namespace), @project, @milestone],
html: {class: 'milestone-form common-note-form js-quick-submit js-requires-input'},
data: { markdown_version: @milestone.cached_markdown_version } do |f|
= form_errors(@milestone) = form_errors(@milestone)
.row .row
.col-md-6 .col-md-6
......
...@@ -11,7 +11,9 @@ ...@@ -11,7 +11,9 @@
%strong= @tag.name %strong= @tag.name
= form_for(@release, method: :put, url: project_tag_release_path(@project, @tag.name), html: { class: 'common-note-form release-form js-quick-submit' }) do |f| = form_for(@release, method: :put, url: project_tag_release_path(@project, @tag.name),
html: { class: 'common-note-form release-form js-quick-submit' },
data: { markdown_version: @release.cached_markdown_version }) do |f|
= render layout: 'projects/md_preview', locals: { url: preview_markdown_path(@project), referenced_users: true } do = render layout: 'projects/md_preview', locals: { url: preview_markdown_path(@project), referenced_users: true } do
= render 'projects/zen', f: f, attr: :description, classes: 'note-textarea', placeholder: "Write your release notes or drag files here…" = render 'projects/zen', f: f, attr: :description, classes: 'note-textarea', placeholder: "Write your release notes or drag files here…"
= render 'shared/notes/hints' = render 'shared/notes/hints'
......
- commit_message = @page.persisted? ? s_("WikiPageEdit|Update %{page_title}") : s_("WikiPageCreate|Create %{page_title}") - commit_message = @page.persisted? ? s_("WikiPageEdit|Update %{page_title}") : s_("WikiPageCreate|Create %{page_title}")
- commit_message = commit_message % { page_title: @page.title } - commit_message = commit_message % { page_title: @page.title }
= form_for [@project.namespace.becomes(Namespace), @project, @page], method: @page.persisted? ? :put : :post, html: { class: 'wiki-form common-note-form prepend-top-default js-quick-submit' } do |f| = form_for [@project.namespace.becomes(Namespace), @project, @page], method: @page.persisted? ? :put : :post,
html: { class: 'wiki-form common-note-form prepend-top-default js-quick-submit' },
data: { markdown_version: CacheMarkdownField::CACHE_REDCARPET_VERSION } do |f|
= form_errors(@page) = form_errors(@page)
- if @page.persisted? - if @page.persisted?
......
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
.note-text.md .note-text.md
= markdown_field(note, :note) = markdown_field(note, :note)
= edited_time_ago_with_tooltip(note, placement: 'bottom', html_class: 'note_edited_ago') = edited_time_ago_with_tooltip(note, placement: 'bottom', html_class: 'note_edited_ago')
.original-note-content.hidden{ data: { post_url: note_url(note), target_id: note.noteable.id, target_type: note.noteable.class.name.underscore } } .original-note-content.hidden{ data: { post_url: note_url(note), target_id: note.noteable.id, target_type: note.noteable.class.name.underscore, markdown_version: note.cached_markdown_version } }
#{note.note} #{note.note}
- if note_editable - if note_editable
= render 'shared/notes/edit', note: note = render 'shared/notes/edit', note: note
......
...@@ -2,7 +2,9 @@ ...@@ -2,7 +2,9 @@
= page_specific_javascript_tag('lib/ace.js') = page_specific_javascript_tag('lib/ace.js')
.snippet-form-holder .snippet-form-holder
= form_for @snippet, url: url, html: { class: "snippet-form js-requires-input js-quick-submit common-note-form" } do |f| = form_for @snippet, url: url,
html: { class: "snippet-form js-requires-input js-quick-submit common-note-form" },
data: { markdown_version: @snippet.cached_markdown_version } do |f|
= form_errors(@snippet) = form_errors(@snippet)
.form-group.row .form-group.row
......
...@@ -9,6 +9,7 @@ describe 'Projects > Wiki > User previews markdown changes', :js do ...@@ -9,6 +9,7 @@ describe 'Projects > Wiki > User previews markdown changes', :js do
[relative link 1](../relative) [relative link 1](../relative)
[relative link 2](./relative) [relative link 2](./relative)
[relative link 3](./e/f/relative) [relative link 3](./e/f/relative)
[spaced link](title with spaces)
HEREDOC HEREDOC
end end
...@@ -42,6 +43,7 @@ describe 'Projects > Wiki > User previews markdown changes', :js do ...@@ -42,6 +43,7 @@ describe 'Projects > Wiki > User previews markdown changes', :js do
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/relative\">relative link 1</a>") expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/relative\">relative link 1</a>")
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/c/relative\">relative link 2</a>") expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/c/relative\">relative link 2</a>")
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/c/e/f/relative\">relative link 3</a>") expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/c/e/f/relative\">relative link 3</a>")
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/title%20with%20spaces\">spaced link</a>")
end end
end end
...@@ -64,6 +66,7 @@ describe 'Projects > Wiki > User previews markdown changes', :js do ...@@ -64,6 +66,7 @@ describe 'Projects > Wiki > User previews markdown changes', :js do
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/relative\">relative link 1</a>") expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/relative\">relative link 1</a>")
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>") expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>")
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>") expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>")
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/title%20with%20spaces\">spaced link</a>")
end end
end end
...@@ -86,6 +89,7 @@ describe 'Projects > Wiki > User previews markdown changes', :js do ...@@ -86,6 +89,7 @@ describe 'Projects > Wiki > User previews markdown changes', :js do
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/relative\">relative link 1</a>") expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/relative\">relative link 1</a>")
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>") expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>")
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>") expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>")
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/title%20with%20spaces\">spaced link</a>")
end end
end end
end end
...@@ -119,6 +123,7 @@ describe 'Projects > Wiki > User previews markdown changes', :js do ...@@ -119,6 +123,7 @@ describe 'Projects > Wiki > User previews markdown changes', :js do
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/relative\">relative link 1</a>") expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/relative\">relative link 1</a>")
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/c/relative\">relative link 2</a>") expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/c/relative\">relative link 2</a>")
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/c/e/f/relative\">relative link 3</a>") expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/c/e/f/relative\">relative link 3</a>")
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/title%20with%20spaces\">spaced link</a>")
end end
end end
...@@ -136,6 +141,7 @@ describe 'Projects > Wiki > User previews markdown changes', :js do ...@@ -136,6 +141,7 @@ describe 'Projects > Wiki > User previews markdown changes', :js do
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/relative\">relative link 1</a>") expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/relative\">relative link 1</a>")
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>") expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>")
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>") expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>")
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/title%20with%20spaces\">spaced link</a>")
end end
end end
...@@ -153,6 +159,7 @@ describe 'Projects > Wiki > User previews markdown changes', :js do ...@@ -153,6 +159,7 @@ describe 'Projects > Wiki > User previews markdown changes', :js do
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/relative\">relative link 1</a>") expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/relative\">relative link 1</a>")
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>") expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>")
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>") expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>")
expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/title%20with%20spaces\">spaced link</a>")
end end
end end
end end
......
...@@ -68,6 +68,26 @@ describe 'Snippet', :js do ...@@ -68,6 +68,26 @@ describe 'Snippet', :js do
end end
end end
context 'with cached Redcarpet html' do
let(:snippet) { create(:personal_snippet, :public, file_name: file_name, content: content, cached_markdown_version: CacheMarkdownField::CACHE_REDCARPET_VERSION) }
let(:file_name) { 'test.md' }
let(:content) { "1. one\n - sublist\n" }
it 'renders correctly' do
expect(page).to have_xpath("//ol//li//ul")
end
end
context 'with cached CommonMark html' do
let(:snippet) { create(:personal_snippet, :public, file_name: file_name, content: content, cached_markdown_version: CacheMarkdownField::CACHE_COMMONMARK_VERSION) }
let(:file_name) { 'test.md' }
let(:content) { "1. one\n - sublist\n" }
it 'renders correctly' do
expect(page).not_to have_xpath("//ol//li//ul")
end
end
context 'switching to the simple viewer' do context 'switching to the simple viewer' do
before do before do
find('.js-blob-viewer-switch-btn[data-viewer=simple]').click find('.js-blob-viewer-switch-btn[data-viewer=simple]').click
......
...@@ -184,6 +184,7 @@ describe IssuablesHelper do ...@@ -184,6 +184,7 @@ describe IssuablesHelper do
issuableRef: "##{issue.iid}", issuableRef: "##{issue.iid}",
markdownPreviewPath: "/#{@project.full_path}/preview_markdown", markdownPreviewPath: "/#{@project.full_path}/preview_markdown",
markdownDocsPath: '/help/user/markdown', markdownDocsPath: '/help/user/markdown',
markdownVersion: 11,
issuableTemplates: [], issuableTemplates: [],
projectPath: @project.path, projectPath: @project.path,
projectNamespace: @project.namespace.path, projectNamespace: @project.namespace.path,
......
...@@ -205,7 +205,9 @@ describe MarkupHelper do ...@@ -205,7 +205,9 @@ describe MarkupHelper do
it "uses Wiki pipeline for markdown files" do it "uses Wiki pipeline for markdown files" do
allow(@wiki).to receive(:format).and_return(:markdown) allow(@wiki).to receive(:format).and_return(:markdown)
expect(helper).to receive(:markdown_unsafe).with('wiki content', pipeline: :wiki, project: project, project_wiki: @wiki, page_slug: "nested/page", issuable_state_filter_enabled: true) expect(helper).to receive(:markdown_unsafe).with('wiki content',
pipeline: :wiki, project: project, project_wiki: @wiki, page_slug: "nested/page",
issuable_state_filter_enabled: true, markdown_engine: :redcarpet)
helper.render_wiki_content(@wiki) helper.render_wiki_content(@wiki)
end end
...@@ -236,19 +238,32 @@ describe MarkupHelper do ...@@ -236,19 +238,32 @@ describe MarkupHelper do
expect(helper.markup('foo.rst', content).encoding.name).to eq('UTF-8') expect(helper.markup('foo.rst', content).encoding.name).to eq('UTF-8')
end end
it "delegates to #markdown_unsafe when file name corresponds to Markdown" do it 'delegates to #markdown_unsafe when file name corresponds to Markdown' do
expect(helper).to receive(:gitlab_markdown?).with('foo.md').and_return(true) expect(helper).to receive(:gitlab_markdown?).with('foo.md').and_return(true)
expect(helper).to receive(:markdown_unsafe).and_return('NOEL') expect(helper).to receive(:markdown_unsafe).and_return('NOEL')
expect(helper.markup('foo.md', content)).to eq('NOEL') expect(helper.markup('foo.md', content)).to eq('NOEL')
end end
it "delegates to #asciidoc_unsafe when file name corresponds to AsciiDoc" do it 'delegates to #asciidoc_unsafe when file name corresponds to AsciiDoc' do
expect(helper).to receive(:asciidoc?).with('foo.adoc').and_return(true) expect(helper).to receive(:asciidoc?).with('foo.adoc').and_return(true)
expect(helper).to receive(:asciidoc_unsafe).and_return('NOEL') expect(helper).to receive(:asciidoc_unsafe).and_return('NOEL')
expect(helper.markup('foo.adoc', content)).to eq('NOEL') expect(helper.markup('foo.adoc', content)).to eq('NOEL')
end end
it 'uses passed in rendered content' do
expect(helper).not_to receive(:gitlab_markdown?)
expect(helper).not_to receive(:markdown_unsafe)
expect(helper.markup('foo.md', content, rendered: '<p>NOEL</p>')).to eq('<p>NOEL</p>')
end
it 'defaults to Redcarpet' do
expect(helper).to receive(:markdown_unsafe).with(content, hash_including(markdown_engine: :redcarpet)).and_return('NOEL')
expect(helper.markup('foo.md', content)).to eq('NOEL')
end
end end
describe '#first_line_in_markdown' do describe '#first_line_in_markdown' do
......
...@@ -165,6 +165,7 @@ export const note = { ...@@ -165,6 +165,7 @@ export const note = {
report_abuse_path: report_abuse_path:
'/abuse_reports/new?ref_url=http%3A%2F%2Flocalhost%3A3000%2Fgitlab-org%2Fgitlab-ce%2Fissues%2F7%23note_546&user_id=1', '/abuse_reports/new?ref_url=http%3A%2F%2Flocalhost%3A3000%2Fgitlab-org%2Fgitlab-ce%2Fissues%2F7%23note_546&user_id=1',
path: '/gitlab-org/gitlab-ce/notes/546', path: '/gitlab-org/gitlab-ce/notes/546',
cached_markdown_version: 11,
}; };
export const discussionMock = { export const discussionMock = {
......
...@@ -3,7 +3,32 @@ require 'spec_helper' ...@@ -3,7 +3,32 @@ require 'spec_helper'
describe Banzai::Filter::MarkdownFilter do describe Banzai::Filter::MarkdownFilter do
include FilterSpecHelper include FilterSpecHelper
context 'code block' do describe 'markdown engine from context' do
it 'defaults to CommonMark' do
expect_any_instance_of(Banzai::Filter::MarkdownEngines::CommonMark).to receive(:render).and_return('test')
filter('test')
end
it 'uses Redcarpet' do
expect_any_instance_of(Banzai::Filter::MarkdownEngines::Redcarpet).to receive(:render).and_return('test')
filter('test', { markdown_engine: :redcarpet })
end
it 'uses CommonMark' do
expect_any_instance_of(Banzai::Filter::MarkdownEngines::CommonMark).to receive(:render).and_return('test')
filter('test', { markdown_engine: :common_mark })
end
end
describe 'code block' do
context 'using CommonMark' do
before do
stub_const('Banzai::Filter::MarkdownFilter::DEFAULT_ENGINE', :common_mark)
end
it 'adds language to lang attribute when specified' do it 'adds language to lang attribute when specified' do
result = filter("```html\nsome code\n```") result = filter("```html\nsome code\n```")
...@@ -16,4 +41,23 @@ describe Banzai::Filter::MarkdownFilter do ...@@ -16,4 +41,23 @@ describe Banzai::Filter::MarkdownFilter do
expect(result).to start_with("<pre><code>") expect(result).to start_with("<pre><code>")
end end
end end
context 'using Redcarpet' do
before do
stub_const('Banzai::Filter::MarkdownFilter::DEFAULT_ENGINE', :redcarpet)
end
it 'adds language to lang attribute when specified' do
result = filter("```html\nsome code\n```")
expect(result).to start_with("\n<pre><code lang=\"html\">")
end
it 'does not add language to lang attribute when not specified' do
result = filter("```\nsome code\n```")
expect(result).to start_with("\n<pre><code>")
end
end
end
end end
...@@ -370,4 +370,20 @@ describe CacheMarkdownField do ...@@ -370,4 +370,20 @@ describe CacheMarkdownField do
end end
end end
end end
describe CacheMarkdownField::MarkdownEngine do
subject { lambda { |version| CacheMarkdownField::MarkdownEngine.from_version(version) } }
it 'returns :common_mark as a default' do
expect(subject.call(nil)).to eq :common_mark
end
it 'returns :common_mark' do
expect(subject.call(CacheMarkdownField::CACHE_COMMONMARK_VERSION)).to eq :common_mark
end
it 'returns :redcarpet' do
expect(subject.call(CacheMarkdownField::CACHE_REDCARPET_VERSION)).to eq :redcarpet
end
end
end end
...@@ -64,4 +64,16 @@ describe PreviewMarkdownService do ...@@ -64,4 +64,16 @@ describe PreviewMarkdownService do
expect(result[:commands]).to eq 'Sets time estimate to 2y.' expect(result[:commands]).to eq 'Sets time estimate to 2y.'
end end
end end
it 'sets correct markdown engine' do
service = described_class.new(project, user, { markdown_version: CacheMarkdownField::CACHE_REDCARPET_VERSION })
result = service.execute
expect(result[:markdown_engine]).to eq :redcarpet
service = described_class.new(project, user, { markdown_version: CacheMarkdownField::CACHE_COMMONMARK_VERSION })
result = service.execute
expect(result[:markdown_engine]).to eq :common_mark
end
end end
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