Merge branch 'bw-enable-commonmark' into 'master'
enable CommonMark as the default See merge request gitlab-org/gitlab-ce!19331
This commit is contained in:
commit
1a2ce3cc9d
14 changed files with 207 additions and 98 deletions
|
@ -119,7 +119,7 @@ const gfmRules = {
|
||||||
return el.outerHTML;
|
return el.outerHTML;
|
||||||
},
|
},
|
||||||
'dl'(el, text) {
|
'dl'(el, text) {
|
||||||
let lines = text.trim().split('\n');
|
let lines = text.replace(/\n\n/g, '\n').trim().split('\n');
|
||||||
// Add two spaces to the front of subsequent list items lines,
|
// Add two spaces to the front of subsequent list items lines,
|
||||||
// or leave the line entirely blank.
|
// or leave the line entirely blank.
|
||||||
lines = lines.map((l) => {
|
lines = lines.map((l) => {
|
||||||
|
@ -129,9 +129,13 @@ const gfmRules = {
|
||||||
return ` ${line}`;
|
return ` ${line}`;
|
||||||
});
|
});
|
||||||
|
|
||||||
return `<dl>\n${lines.join('\n')}\n</dl>`;
|
return `<dl>\n${lines.join('\n')}\n</dl>\n`;
|
||||||
},
|
},
|
||||||
'sub, dt, dd, kbd, q, samp, var, ruby, rt, rp, abbr, summary, details'(el, text) {
|
'dt, dd, summary, details'(el, text) {
|
||||||
|
const tag = el.nodeName.toLowerCase();
|
||||||
|
return `<${tag}>${text}</${tag}>\n`;
|
||||||
|
},
|
||||||
|
'sup, sub, kbd, q, samp, var, ruby, rt, rp, abbr'(el, text) {
|
||||||
const tag = el.nodeName.toLowerCase();
|
const tag = el.nodeName.toLowerCase();
|
||||||
return `<${tag}>${text}</${tag}>`;
|
return `<${tag}>${text}</${tag}>`;
|
||||||
},
|
},
|
||||||
|
@ -215,22 +219,22 @@ const gfmRules = {
|
||||||
return text.replace(/^- /mg, '1. ');
|
return text.replace(/^- /mg, '1. ');
|
||||||
},
|
},
|
||||||
'h1'(el, text) {
|
'h1'(el, text) {
|
||||||
return `# ${text.trim()}`;
|
return `# ${text.trim()}\n`;
|
||||||
},
|
},
|
||||||
'h2'(el, text) {
|
'h2'(el, text) {
|
||||||
return `## ${text.trim()}`;
|
return `## ${text.trim()}\n`;
|
||||||
},
|
},
|
||||||
'h3'(el, text) {
|
'h3'(el, text) {
|
||||||
return `### ${text.trim()}`;
|
return `### ${text.trim()}\n`;
|
||||||
},
|
},
|
||||||
'h4'(el, text) {
|
'h4'(el, text) {
|
||||||
return `#### ${text.trim()}`;
|
return `#### ${text.trim()}\n`;
|
||||||
},
|
},
|
||||||
'h5'(el, text) {
|
'h5'(el, text) {
|
||||||
return `##### ${text.trim()}`;
|
return `##### ${text.trim()}\n`;
|
||||||
},
|
},
|
||||||
'h6'(el, text) {
|
'h6'(el, text) {
|
||||||
return `###### ${text.trim()}`;
|
return `###### ${text.trim()}\n`;
|
||||||
},
|
},
|
||||||
'strong'(el, text) {
|
'strong'(el, text) {
|
||||||
return `**${text}**`;
|
return `**${text}**`;
|
||||||
|
@ -241,11 +245,13 @@ const gfmRules = {
|
||||||
'del'(el, text) {
|
'del'(el, text) {
|
||||||
return `~~${text}~~`;
|
return `~~${text}~~`;
|
||||||
},
|
},
|
||||||
'sup'(el, text) {
|
|
||||||
return `^${text}`;
|
|
||||||
},
|
|
||||||
'hr'(el) {
|
'hr'(el) {
|
||||||
return '-----';
|
// extra leading \n is to ensure that there is a blank line between
|
||||||
|
// a list followed by an hr, otherwise this breaks old redcarpet rendering
|
||||||
|
return '\n-----\n';
|
||||||
|
},
|
||||||
|
'p'(el, text) {
|
||||||
|
return `${text.trim()}\n`;
|
||||||
},
|
},
|
||||||
'table'(el) {
|
'table'(el) {
|
||||||
const theadEl = el.querySelector('thead');
|
const theadEl = el.querySelector('thead');
|
||||||
|
@ -263,7 +269,9 @@ const gfmRules = {
|
||||||
|
|
||||||
let before = '';
|
let before = '';
|
||||||
let after = '';
|
let after = '';
|
||||||
switch (cell.style.textAlign) {
|
const alignment = cell.align || cell.style.textAlign;
|
||||||
|
|
||||||
|
switch (alignment) {
|
||||||
case 'center':
|
case 'center':
|
||||||
before = ':';
|
before = ':';
|
||||||
after = ':';
|
after = ':';
|
||||||
|
|
|
@ -114,7 +114,7 @@ module CacheMarkdownField
|
||||||
end
|
end
|
||||||
|
|
||||||
def latest_cached_markdown_version
|
def latest_cached_markdown_version
|
||||||
return CacheMarkdownField::CACHE_REDCARPET_VERSION unless cached_markdown_version
|
return CacheMarkdownField::CACHE_COMMONMARK_VERSION unless cached_markdown_version
|
||||||
|
|
||||||
if cached_markdown_version < CacheMarkdownField::CACHE_COMMONMARK_VERSION_START
|
if cached_markdown_version < CacheMarkdownField::CACHE_COMMONMARK_VERSION_START
|
||||||
CacheMarkdownField::CACHE_REDCARPET_VERSION
|
CacheMarkdownField::CACHE_REDCARPET_VERSION
|
||||||
|
|
5
changelogs/unreleased/bw-enable-commonmark.yml
Normal file
5
changelogs/unreleased/bw-enable-commonmark.yml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Use CommonMark syntax and rendering for new Markdown content
|
||||||
|
merge_request: 19331
|
||||||
|
author:
|
||||||
|
type: added
|
|
@ -3,13 +3,15 @@
|
||||||
## GitLab Flavored Markdown (GFM)
|
## GitLab Flavored Markdown (GFM)
|
||||||
|
|
||||||
> **Note:**
|
> **Note:**
|
||||||
Not all of the GitLab-specific extensions to Markdown that are described in
|
> Not all of the GitLab-specific extensions to Markdown that are described in
|
||||||
this document currently work on our documentation website.
|
> this document currently work on our documentation website.
|
||||||
>
|
>
|
||||||
For the best result, we encourage you to check this document out as rendered
|
> For the best result, we encourage you to check this document out as rendered
|
||||||
by GitLab: [markdown.md]
|
by GitLab: [markdown.md]
|
||||||
|
|
||||||
_GitLab uses the [Redcarpet Ruby library][redcarpet] for Markdown processing._
|
_GitLab uses (as of 11.1) the [CommonMark Ruby Library][commonmarker] for Markdown processing of all new issues, merge requests, comments, and other Markdown content in the GitLab system. Previous content and Markdown files `.md` in the repositories are still processed using the [Redcarpet Ruby library][redcarpet]._
|
||||||
|
|
||||||
|
_Where there are significant differences, we will try to call them out in this document._
|
||||||
|
|
||||||
GitLab uses "GitLab Flavored Markdown" (GFM). It extends the standard Markdown in a few significant ways to add some useful functionality. It was inspired by [GitHub Flavored Markdown](https://help.github.com/articles/basic-writing-and-formatting-syntax/).
|
GitLab uses "GitLab Flavored Markdown" (GFM). It extends the standard Markdown in a few significant ways to add some useful functionality. It was inspired by [GitHub Flavored Markdown](https://help.github.com/articles/basic-writing-and-formatting-syntax/).
|
||||||
|
|
||||||
|
@ -21,7 +23,7 @@ You can use GFM in the following areas:
|
||||||
- milestones
|
- milestones
|
||||||
- snippets (the snippet must be named with a `.md` extension)
|
- snippets (the snippet must be named with a `.md` extension)
|
||||||
- wiki pages
|
- wiki pages
|
||||||
- markdown documents inside the repository
|
- markdown documents inside the repository (currently only rendered by Redcarpet)
|
||||||
|
|
||||||
You can also use other rich text files in GitLab. You might have to install a
|
You can also use other rich text files in GitLab. You might have to install a
|
||||||
dependency to do so. Please see the [github-markup gem readme](https://github.com/gitlabhq/markup#markups) for more information.
|
dependency to do so. Please see the [github-markup gem readme](https://github.com/gitlabhq/markup#markups) for more information.
|
||||||
|
@ -500,6 +502,7 @@ For example:
|
||||||
# This header has Unicode in it: 한글
|
# This header has Unicode in it: 한글
|
||||||
## This header has spaces in it
|
## This header has spaces in it
|
||||||
### This header has spaces in it
|
### This header has spaces in it
|
||||||
|
## This header has 3.5 in it (and parentheses)
|
||||||
```
|
```
|
||||||
|
|
||||||
Would generate the following link IDs:
|
Would generate the following link IDs:
|
||||||
|
@ -509,6 +512,7 @@ Would generate the following link IDs:
|
||||||
1. `this-header-has-unicode-in-it-한글`
|
1. `this-header-has-unicode-in-it-한글`
|
||||||
1. `this-header-has-spaces-in-it`
|
1. `this-header-has-spaces-in-it`
|
||||||
1. `this-header-has-spaces-in-it-1`
|
1. `this-header-has-spaces-in-it-1`
|
||||||
|
1. `this-header-has-3-5-in-it-and-parentheses`
|
||||||
|
|
||||||
Note that the Emoji processing happens before the header IDs are generated, so the Emoji is converted to an image which then gets removed from the ID.
|
Note that the Emoji processing happens before the header IDs are generated, so the Emoji is converted to an image which then gets removed from the ID.
|
||||||
|
|
||||||
|
@ -543,9 +547,9 @@ Examples:
|
||||||
```no-highlight
|
```no-highlight
|
||||||
1. First ordered list item
|
1. First ordered list item
|
||||||
2. Another item
|
2. Another item
|
||||||
* Unordered sub-list.
|
* Unordered sub-list.
|
||||||
1. Actual numbers don't matter, just that it's a number
|
1. Actual numbers don't matter, just that it's a number
|
||||||
1. Ordered sub-list
|
1. Ordered sub-list
|
||||||
4. And another item.
|
4. And another item.
|
||||||
|
|
||||||
* Unordered list can use asterisks
|
* Unordered list can use asterisks
|
||||||
|
@ -557,9 +561,9 @@ Become:
|
||||||
|
|
||||||
1. First ordered list item
|
1. First ordered list item
|
||||||
2. Another item
|
2. Another item
|
||||||
* Unordered sub-list.
|
* Unordered sub-list.
|
||||||
1. Actual numbers don't matter, just that it's a number
|
1. Actual numbers don't matter, just that it's a number
|
||||||
1. Ordered sub-list
|
1. Ordered sub-list
|
||||||
4. And another item.
|
4. And another item.
|
||||||
|
|
||||||
* Unordered list can use asterisks
|
* Unordered list can use asterisks
|
||||||
|
@ -567,26 +571,7 @@ Become:
|
||||||
+ Or pluses
|
+ Or pluses
|
||||||
|
|
||||||
If a list item contains multiple paragraphs,
|
If a list item contains multiple paragraphs,
|
||||||
each subsequent paragraph should be indented with four spaces.
|
each subsequent paragraph should be indented to the same level as the start of the list item text (_Redcarpet: paragraph should be indented with four spaces._)
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```no-highlight
|
|
||||||
1. First ordered list item
|
|
||||||
|
|
||||||
Second paragraph of first item.
|
|
||||||
2. Another item
|
|
||||||
```
|
|
||||||
|
|
||||||
Becomes:
|
|
||||||
|
|
||||||
1. First ordered list item
|
|
||||||
|
|
||||||
Second paragraph of first item.
|
|
||||||
2. Another item
|
|
||||||
|
|
||||||
If the second paragraph isn't indented with four spaces,
|
|
||||||
the second list item will be incorrectly labeled as `1`.
|
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
@ -594,6 +579,28 @@ Example:
|
||||||
1. First ordered list item
|
1. First ordered list item
|
||||||
|
|
||||||
Second paragraph of first item.
|
Second paragraph of first item.
|
||||||
|
|
||||||
|
2. Another item
|
||||||
|
```
|
||||||
|
|
||||||
|
Becomes:
|
||||||
|
|
||||||
|
1. First ordered list item
|
||||||
|
|
||||||
|
Paragraph of first item.
|
||||||
|
|
||||||
|
2. Another item
|
||||||
|
|
||||||
|
If the paragraph of the first item is not indented with the proper number of spaces,
|
||||||
|
the paragraph will appear outside the list, instead of properly indented under the list item.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```no-highlight
|
||||||
|
1. First ordered list item
|
||||||
|
|
||||||
|
Paragraph of first item.
|
||||||
|
|
||||||
2. Another item
|
2. Another item
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -601,7 +608,8 @@ Becomes:
|
||||||
|
|
||||||
1. First ordered list item
|
1. First ordered list item
|
||||||
|
|
||||||
Second paragraph of first item.
|
Paragraph of first item.
|
||||||
|
|
||||||
2. Another item
|
2. Another item
|
||||||
|
|
||||||
### Links
|
### Links
|
||||||
|
@ -719,20 +727,24 @@ Content can be collapsed using HTML's [`<details>`](https://developer.mozilla.or
|
||||||
<p>
|
<p>
|
||||||
<details>
|
<details>
|
||||||
<summary>Click me to collapse/fold.</summary>
|
<summary>Click me to collapse/fold.</summary>
|
||||||
These details will remain hidden until expanded.
|
|
||||||
|
These details <em>will</em> remain <strong>hidden</strong> until expanded.
|
||||||
|
|
||||||
<pre><code>PASTE LOGS HERE</code></pre>
|
<pre><code>PASTE LOGS HERE</code></pre>
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
**Note:** Unfortunately Markdown is not supported inside these tags, as described by the [markdown specification](https://daringfireball.net/projects/markdown/syntax#html). You can work around this by using HTML, for example you can use `<pre><code>` tags instead of [code fences](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/user/markdown.md#code-and-syntax-highlighting).
|
**Note:** Markdown inside these tags is supported, as long as you have a blank link after the `</summary>` tag and before the `</details>` tag, as shown in the example. _Redcarpet does not support Markdown inside these tags. You can work around this by using HTML, for example you can use `<pre><code>` tags instead of [code fences](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/user/markdown.md#code-and-syntax-highlighting)._
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<details>
|
<details>
|
||||||
<summary>Click me to collapse/fold.</summary>
|
<summary>Click me to collapse/fold.</summary>
|
||||||
These details will remain hidden until expanded.
|
|
||||||
|
|
||||||
<pre><code>PASTE LOGS HERE</code></pre>
|
These details _will_ remain **hidden** until expanded.
|
||||||
|
|
||||||
|
PASTE LOGS HERE
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -774,7 +786,7 @@ Underscores
|
||||||
|
|
||||||
### Line Breaks
|
### Line Breaks
|
||||||
|
|
||||||
My basic recommendation for learning how line breaks work is to experiment and discover -- hit <Enter> once (i.e., insert one newline), then hit it twice (i.e., insert two newlines), see what happens. You'll soon learn to get what you want. "Markdown Toggle" is your friend.
|
A good way to learn how line breaks work is to experiment and discover -- hit <kbd>Enter</kbd> once (i.e., insert one newline), then hit it twice (i.e., insert two newlines), see what happens. You'll soon learn to get what you want. The "Preview" tab is your friend.
|
||||||
|
|
||||||
Here are some things to try out:
|
Here are some things to try out:
|
||||||
|
|
||||||
|
@ -810,7 +822,7 @@ spaces.
|
||||||
|
|
||||||
### Tables
|
### Tables
|
||||||
|
|
||||||
Tables aren't part of the core Markdown spec, but they are part of GFM and Markdown Here supports them.
|
Tables aren't part of the core Markdown spec, but they are part of GFM.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
@ -828,9 +840,7 @@ Becomes:
|
||||||
| cell 1 | cell 2 |
|
| cell 1 | cell 2 |
|
||||||
| cell 3 | cell 4 |
|
| cell 3 | cell 4 |
|
||||||
|
|
||||||
**Note**
|
**Note:** The row of dashes between the table header and body must have at least three dashes in each column.
|
||||||
|
|
||||||
The row of dashes between the table header and body must have at least three dashes in each column.
|
|
||||||
|
|
||||||
By including colons in the header row, you can align the text within that column.
|
By including colons in the header row, you can align the text within that column.
|
||||||
|
|
||||||
|
@ -863,6 +873,18 @@ Becomes:
|
||||||
|
|
||||||
You can add footnotes to your text as follows.[^2]
|
You can add footnotes to your text as follows.[^2]
|
||||||
|
|
||||||
|
### Superscripts / Subscripts
|
||||||
|
|
||||||
|
CommonMark and GFM currently do not support the superscript syntax ( `x^2` ) that Redcarpet does. You can use the standard HTML syntax for superscripts and subscripts.
|
||||||
|
|
||||||
|
```
|
||||||
|
The formula for water is H<sub>2</sub>O
|
||||||
|
while the equation for the theory of relativity is E = mc<sup>2</sup>.
|
||||||
|
```
|
||||||
|
|
||||||
|
The formula for water is H<sub>2</sub>O while the equation for the theory of relativity is E = mc<sup>2</sup>.
|
||||||
|
|
||||||
|
|
||||||
## Wiki-specific Markdown
|
## Wiki-specific Markdown
|
||||||
|
|
||||||
The following examples show how links inside wikis behave.
|
The following examples show how links inside wikis behave.
|
||||||
|
@ -954,3 +976,4 @@ A link starting with a `/` is relative to the wiki root.
|
||||||
[katex]: https://github.com/Khan/KaTeX "KaTeX website"
|
[katex]: https://github.com/Khan/KaTeX "KaTeX website"
|
||||||
[katex-subset]: https://github.com/Khan/KaTeX/wiki/Function-Support-in-KaTeX "Macros supported by KaTeX"
|
[katex-subset]: https://github.com/Khan/KaTeX/wiki/Function-Support-in-KaTeX "Macros supported by KaTeX"
|
||||||
[asciidoctor-manual]: http://asciidoctor.org/docs/user-manual/#activating-stem-support "Asciidoctor user manual"
|
[asciidoctor-manual]: http://asciidoctor.org/docs/user-manual/#activating-stem-support "Asciidoctor user manual"
|
||||||
|
[commonmarker]: https://github.com/gjtorikian/commonmarker
|
||||||
|
|
|
@ -10,9 +10,7 @@ module API
|
||||||
detail "This feature was introduced in GitLab 11.0."
|
detail "This feature was introduced in GitLab 11.0."
|
||||||
end
|
end
|
||||||
post do
|
post do
|
||||||
# Explicitly set CommonMark as markdown engine to use.
|
context = { only_path: false }
|
||||||
# Remove this set when https://gitlab.com/gitlab-org/gitlab-ce/issues/43011 is done.
|
|
||||||
context = { markdown_engine: :common_mark, only_path: false }
|
|
||||||
|
|
||||||
if params[:project]
|
if params[:project]
|
||||||
project = Project.find_by_full_path(params[:project])
|
project = Project.find_by_full_path(params[:project])
|
||||||
|
|
|
@ -14,7 +14,7 @@ module Banzai
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
DEFAULT_ENGINE = :redcarpet
|
DEFAULT_ENGINE = :common_mark
|
||||||
|
|
||||||
def engine(engine_from_context)
|
def engine(engine_from_context)
|
||||||
engine_from_context ||= DEFAULT_ENGINE
|
engine_from_context ||= DEFAULT_ENGINE
|
||||||
|
|
|
@ -502,6 +502,13 @@ describe 'Copy as GFM', :js do
|
||||||
1. Numbered lists
|
1. Numbered lists
|
||||||
GFM
|
GFM
|
||||||
|
|
||||||
|
# list item followed by an HR
|
||||||
|
<<-GFM.strip_heredoc,
|
||||||
|
- list item
|
||||||
|
|
||||||
|
-----
|
||||||
|
GFM
|
||||||
|
|
||||||
'# Heading',
|
'# Heading',
|
||||||
'## Heading',
|
'## Heading',
|
||||||
'### Heading',
|
'### Heading',
|
||||||
|
@ -515,8 +522,6 @@ describe 'Copy as GFM', :js do
|
||||||
|
|
||||||
'~~Strikethrough~~',
|
'~~Strikethrough~~',
|
||||||
|
|
||||||
'2^2',
|
|
||||||
|
|
||||||
'-----',
|
'-----',
|
||||||
|
|
||||||
# table
|
# table
|
||||||
|
|
|
@ -44,7 +44,7 @@ describe 'GitLab Markdown', :aggregate_failures do
|
||||||
|
|
||||||
# Shared behavior that all pipelines should exhibit
|
# Shared behavior that all pipelines should exhibit
|
||||||
shared_examples 'all pipelines' do
|
shared_examples 'all pipelines' do
|
||||||
it 'includes Redcarpet extensions' do
|
it 'includes extensions' do
|
||||||
aggregate_failures 'does not parse emphasis inside of words' do
|
aggregate_failures 'does not parse emphasis inside of words' do
|
||||||
expect(doc.to_html).not_to match('foo<em>bar</em>baz')
|
expect(doc.to_html).not_to match('foo<em>bar</em>baz')
|
||||||
end
|
end
|
||||||
|
@ -72,10 +72,6 @@ describe 'GitLab Markdown', :aggregate_failures do
|
||||||
aggregate_failures 'parses strikethroughs' do
|
aggregate_failures 'parses strikethroughs' do
|
||||||
expect(doc).to have_selector(%{del:contains("and this text doesn't")})
|
expect(doc).to have_selector(%{del:contains("and this text doesn't")})
|
||||||
end
|
end
|
||||||
|
|
||||||
aggregate_failures 'parses superscript' do
|
|
||||||
expect(doc).to have_selector('sup', count: 2)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'includes SanitizationFilter' do
|
it 'includes SanitizationFilter' do
|
||||||
|
@ -123,16 +119,24 @@ describe 'GitLab Markdown', :aggregate_failures do
|
||||||
expect(doc).to have_selector('details summary:contains("collapsible")')
|
expect(doc).to have_selector('details summary:contains("collapsible")')
|
||||||
end
|
end
|
||||||
|
|
||||||
aggregate_failures 'permits style attribute in th elements' do
|
aggregate_failures 'permits align attribute in th elements' do
|
||||||
expect(doc.at_css('th:contains("Header")')['style']).to eq 'text-align: center'
|
expect(doc.at_css('th:contains("Header")')['align']).to eq 'center'
|
||||||
expect(doc.at_css('th:contains("Row")')['style']).to eq 'text-align: right'
|
expect(doc.at_css('th:contains("Row")')['align']).to eq 'right'
|
||||||
expect(doc.at_css('th:contains("Example")')['style']).to eq 'text-align: left'
|
expect(doc.at_css('th:contains("Example")')['align']).to eq 'left'
|
||||||
end
|
end
|
||||||
|
|
||||||
aggregate_failures 'permits style attribute in td elements' do
|
aggregate_failures 'permits align attribute in td elements' do
|
||||||
expect(doc.at_css('td:contains("Foo")')['style']).to eq 'text-align: center'
|
expect(doc.at_css('td:contains("Foo")')['align']).to eq 'center'
|
||||||
expect(doc.at_css('td:contains("Bar")')['style']).to eq 'text-align: right'
|
expect(doc.at_css('td:contains("Bar")')['align']).to eq 'right'
|
||||||
expect(doc.at_css('td:contains("Baz")')['style']).to eq 'text-align: left'
|
expect(doc.at_css('td:contains("Baz")')['align']).to eq 'left'
|
||||||
|
end
|
||||||
|
|
||||||
|
aggregate_failures 'permits superscript elements' do
|
||||||
|
expect(doc).to have_selector('sup', count: 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
aggregate_failures 'permits subscript elements' do
|
||||||
|
expect(doc).to have_selector('sub', count: 3)
|
||||||
end
|
end
|
||||||
|
|
||||||
aggregate_failures 'removes `rel` attribute from links' do
|
aggregate_failures 'removes `rel` attribute from links' do
|
||||||
|
@ -320,6 +324,31 @@ describe 'GitLab Markdown', :aggregate_failures do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'Redcarpet documents' do
|
||||||
|
before do
|
||||||
|
allow_any_instance_of(Banzai::Filter::MarkdownFilter).to receive(:engine).and_return('Redcarpet')
|
||||||
|
@html = markdown(@feat.raw_markdown)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'processes certain elements differently' do
|
||||||
|
aggregate_failures 'parses superscript' do
|
||||||
|
expect(doc).to have_selector('sup', count: 3)
|
||||||
|
end
|
||||||
|
|
||||||
|
aggregate_failures 'permits style attribute in th elements' do
|
||||||
|
expect(doc.at_css('th:contains("Header")')['style']).to eq 'text-align: center'
|
||||||
|
expect(doc.at_css('th:contains("Row")')['style']).to eq 'text-align: right'
|
||||||
|
expect(doc.at_css('th:contains("Example")')['style']).to eq 'text-align: left'
|
||||||
|
end
|
||||||
|
|
||||||
|
aggregate_failures 'permits style attribute in td elements' do
|
||||||
|
expect(doc.at_css('td:contains("Foo")')['style']).to eq 'text-align: center'
|
||||||
|
expect(doc.at_css('td:contains("Bar")')['style']).to eq 'text-align: right'
|
||||||
|
expect(doc.at_css('td:contains("Baz")')['style']).to eq 'text-align: left'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Fake a `current_user` helper
|
# Fake a `current_user` helper
|
||||||
def current_user
|
def current_user
|
||||||
@feat.user
|
@feat.user
|
||||||
|
|
|
@ -36,7 +36,7 @@ feature 'Task Lists' do
|
||||||
MARKDOWN
|
MARKDOWN
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:nested_tasks_markdown) do
|
let(:nested_tasks_markdown_redcarpet) do
|
||||||
<<-EOT.strip_heredoc
|
<<-EOT.strip_heredoc
|
||||||
- [ ] Task a
|
- [ ] Task a
|
||||||
- [x] Task a.1
|
- [x] Task a.1
|
||||||
|
@ -49,6 +49,19 @@ feature 'Task Lists' do
|
||||||
EOT
|
EOT
|
||||||
end
|
end
|
||||||
|
|
||||||
|
let(:nested_tasks_markdown) do
|
||||||
|
<<-EOT.strip_heredoc
|
||||||
|
- [ ] Task a
|
||||||
|
- [x] Task a.1
|
||||||
|
- [ ] Task a.2
|
||||||
|
- [ ] Task b
|
||||||
|
|
||||||
|
1. [ ] Task 1
|
||||||
|
1. [ ] Task 1.1
|
||||||
|
1. [x] Task 1.2
|
||||||
|
EOT
|
||||||
|
end
|
||||||
|
|
||||||
before do
|
before do
|
||||||
Warden.test_mode!
|
Warden.test_mode!
|
||||||
|
|
||||||
|
@ -141,13 +154,11 @@ feature 'Task Lists' do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'nested tasks', :js do
|
shared_examples 'shared nested tasks' do
|
||||||
let(:issue) { create(:issue, description: nested_tasks_markdown, author: user, project: project) }
|
|
||||||
|
|
||||||
before do
|
before do
|
||||||
|
allow(Banzai::Filter::MarkdownFilter).to receive(:engine).and_return('Redcarpet')
|
||||||
visit_issue(project, issue)
|
visit_issue(project, issue)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'renders' do
|
it 'renders' do
|
||||||
expect(page).to have_selector('ul.task-list', count: 2)
|
expect(page).to have_selector('ul.task-list', count: 2)
|
||||||
expect(page).to have_selector('li.task-list-item', count: 7)
|
expect(page).to have_selector('li.task-list-item', count: 7)
|
||||||
|
@ -171,6 +182,30 @@ feature 'Task Lists' do
|
||||||
expect(page).to have_content('marked the task Task 1.1 as complete')
|
expect(page).to have_content('marked the task Task 1.1 as complete')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'nested tasks', :js do
|
||||||
|
context 'with Redcarpet' do
|
||||||
|
let(:issue) { create(:issue, description: nested_tasks_markdown_redcarpet, author: user, project: project) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow_any_instance_of(Banzai::Filter::MarkdownFilter).to receive(:engine).and_return('Redcarpet')
|
||||||
|
visit_issue(project, issue)
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'shared nested tasks'
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with CommonMark' do
|
||||||
|
let(:issue) { create(:issue, description: nested_tasks_markdown, author: user, project: project) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow_any_instance_of(Banzai::Filter::MarkdownFilter).to receive(:engine).and_return('CommonMark')
|
||||||
|
visit_issue(project, issue)
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'shared nested tasks'
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'for Notes' do
|
describe 'for Notes' do
|
||||||
|
|
10
spec/fixtures/markdown.md.erb
vendored
10
spec/fixtures/markdown.md.erb
vendored
|
@ -43,8 +43,14 @@ This text says this, ~~and this text doesn't~~.
|
||||||
|
|
||||||
### Superscript
|
### Superscript
|
||||||
|
|
||||||
This is my 1^(st) time using superscript in Markdown. Now this is my
|
This is my 1<sup>(st)</sup> time using superscript in Markdown. Now this is my
|
||||||
2^(nd).
|
2<sup>(nd)</sup>.
|
||||||
|
|
||||||
|
Redcarpet supports this superscript syntax ( x^2 ).
|
||||||
|
|
||||||
|
### Subscript
|
||||||
|
|
||||||
|
This (C<sub>6</sub>H<sub>12</sub>O<sub>6</sub>) is an example of subscripts in Markdown.
|
||||||
|
|
||||||
### Next step
|
### Next step
|
||||||
|
|
||||||
|
|
|
@ -298,7 +298,7 @@ describe MarkupHelper do
|
||||||
|
|
||||||
it 'preserves code color scheme' do
|
it 'preserves code color scheme' do
|
||||||
object = create_object("```ruby\ndef test\n 'hello world'\nend\n```")
|
object = create_object("```ruby\ndef test\n 'hello world'\nend\n```")
|
||||||
expected = "\n<pre class=\"code highlight js-syntax-highlight ruby\">" \
|
expected = "<pre class=\"code highlight js-syntax-highlight ruby\">" \
|
||||||
"<code><span class=\"line\"><span class=\"k\">def</span> <span class=\"nf\">test</span>...</span>\n" \
|
"<code><span class=\"line\"><span class=\"k\">def</span> <span class=\"nf\">test</span>...</span>\n" \
|
||||||
"</code></pre>"
|
"</code></pre>"
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,7 @@ describe('ShortcutsIssuable', function () {
|
||||||
});
|
});
|
||||||
describe('with a multi-line selection', () => {
|
describe('with a multi-line selection', () => {
|
||||||
it('quotes the selected lines as a group', () => {
|
it('quotes the selected lines as a group', () => {
|
||||||
stubSelection('<p>Selected line one.</p>\n\n<p>Selected line two.</p>\n\n<p>Selected line three.</p>');
|
stubSelection('<p>Selected line one.</p>\n<p>Selected line two.</p>\n<p>Selected line three.</p>');
|
||||||
this.shortcut.replyWithSelectedText(true);
|
this.shortcut.replyWithSelectedText(true);
|
||||||
expect($(this.selector).val()).toBe('> Selected line one.\n>\n> Selected line two.\n>\n> Selected line three.\n\n');
|
expect($(this.selector).val()).toBe('> Selected line one.\n>\n> Selected line two.\n>\n> Selected line three.\n\n');
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,13 +7,13 @@ describe Banzai::Filter::MarkdownFilter do
|
||||||
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```")
|
||||||
|
|
||||||
expect(result).to start_with("\n<pre><code lang=\"html\">")
|
expect(result).to start_with("<pre><code lang=\"html\">")
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not add language to lang attribute when not specified' do
|
it 'does not add language to lang attribute when not specified' do
|
||||||
result = filter("```\nsome code\n```")
|
result = filter("```\nsome code\n```")
|
||||||
|
|
||||||
expect(result).to start_with("\n<pre><code>")
|
expect(result).to start_with("<pre><code>")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -156,7 +156,7 @@ describe CacheMarkdownField do
|
||||||
end
|
end
|
||||||
|
|
||||||
it { expect(thing.foo_html).to eq(updated_html) }
|
it { expect(thing.foo_html).to eq(updated_html) }
|
||||||
it { expect(thing.cached_markdown_version).to eq(CacheMarkdownField::CACHE_REDCARPET_VERSION) }
|
it { expect(thing.cached_markdown_version).to eq(CacheMarkdownField::CACHE_COMMONMARK_VERSION) }
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#cached_html_up_to_date?' do
|
describe '#cached_html_up_to_date?' do
|
||||||
|
@ -234,7 +234,7 @@ describe CacheMarkdownField do
|
||||||
|
|
||||||
it 'returns default version when version is nil' do
|
it 'returns default version when version is nil' do
|
||||||
thing.cached_markdown_version = nil
|
thing.cached_markdown_version = nil
|
||||||
is_expected.to eq(CacheMarkdownField::CACHE_REDCARPET_VERSION)
|
is_expected.to eq(CacheMarkdownField::CACHE_COMMONMARK_VERSION)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -261,7 +261,7 @@ describe CacheMarkdownField do
|
||||||
thing.cached_markdown_version = nil
|
thing.cached_markdown_version = nil
|
||||||
thing.refresh_markdown_cache
|
thing.refresh_markdown_cache
|
||||||
|
|
||||||
expect(thing.cached_markdown_version).to eq(CacheMarkdownField::CACHE_REDCARPET_VERSION)
|
expect(thing.cached_markdown_version).to eq(CacheMarkdownField::CACHE_COMMONMARK_VERSION)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -346,7 +346,7 @@ describe CacheMarkdownField do
|
||||||
|
|
||||||
expect(thing.foo_html).to eq(updated_html)
|
expect(thing.foo_html).to eq(updated_html)
|
||||||
expect(thing.baz_html).to eq(updated_html)
|
expect(thing.baz_html).to eq(updated_html)
|
||||||
expect(thing.cached_markdown_version).to eq(CacheMarkdownField::CACHE_REDCARPET_VERSION)
|
expect(thing.cached_markdown_version).to eq(CacheMarkdownField::CACHE_COMMONMARK_VERSION)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -366,7 +366,7 @@ describe CacheMarkdownField do
|
||||||
|
|
||||||
expect(thing.foo_html).to eq(updated_html)
|
expect(thing.foo_html).to eq(updated_html)
|
||||||
expect(thing.baz_html).to eq(updated_html)
|
expect(thing.baz_html).to eq(updated_html)
|
||||||
expect(thing.cached_markdown_version).to eq(CacheMarkdownField::CACHE_REDCARPET_VERSION)
|
expect(thing.cached_markdown_version).to eq(CacheMarkdownField::CACHE_COMMONMARK_VERSION)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue