Render math in Asciidoc and Markdown with KaTeX using code blocks
This commit is contained in:
parent
e3f5c4c5f6
commit
2d170a20dc
21 changed files with 358 additions and 166 deletions
|
@ -57,7 +57,7 @@
|
|||
content: this.editor.getValue()
|
||||
}, function(response) {
|
||||
currentPane.empty().append(response);
|
||||
return currentPane.syntaxHighlight();
|
||||
return currentPane.renderGFM();
|
||||
});
|
||||
} else {
|
||||
this.$toggleButton.show();
|
||||
|
|
|
@ -305,7 +305,7 @@
|
|||
}
|
||||
row = form.closest("tr");
|
||||
note_html = $(note.html);
|
||||
note_html.syntaxHighlight();
|
||||
note_html.renderGFM();
|
||||
// is this the first note of discussion?
|
||||
discussionContainer = $(".notes[data-discussion-id='" + note.discussion_id + "']");
|
||||
if ((note.original_discussion_id != null) && discussionContainer.length === 0) {
|
||||
|
@ -322,7 +322,7 @@
|
|||
discussionContainer.append(note_html);
|
||||
// Init discussion on 'Discussion' page if it is merge request page
|
||||
if ($('body').attr('data-page').indexOf('projects:merge_request') === 0) {
|
||||
$('ul.main-notes-list').append(note.discussion_html).syntaxHighlight();
|
||||
$('ul.main-notes-list').append(note.discussion_html).renderGFM();
|
||||
}
|
||||
} else {
|
||||
// append new note to all matching discussions
|
||||
|
@ -463,7 +463,7 @@
|
|||
// Convert returned HTML to a jQuery object so we can modify it further
|
||||
$html = $(note.html);
|
||||
gl.utils.localTimeAgo($('.js-timeago', $html));
|
||||
$html.syntaxHighlight();
|
||||
$html.renderGFM();
|
||||
$html.find('.js-task-list-container').taskList('enable');
|
||||
// Find the note's `li` element by ID and replace it with the updated HTML
|
||||
$note_li = $('.note-row-' + note.id);
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
return this.renderMarkdown(mdText, (function(_this) {
|
||||
return function(response) {
|
||||
preview.html(response.body);
|
||||
preview.syntaxHighlight();
|
||||
preview.renderGFM();
|
||||
return _this.renderReferencedUsers(response.references.users, form);
|
||||
};
|
||||
})(this));
|
||||
|
|
16
app/assets/javascripts/render_gfm.js
Normal file
16
app/assets/javascripts/render_gfm.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, consistent-return, no-var, no-undef, no-else-return, prefer-arrow-callback, padded-blocks, max-len */
|
||||
// Render Gitlab flavoured Markdown
|
||||
//
|
||||
// Delegates to syntax highlight and render math
|
||||
//
|
||||
(function() {
|
||||
$.fn.renderGFM = function() {
|
||||
this.find('.js-syntax-highlight').syntaxHighlight();
|
||||
this.find('.js-render-math').renderMath();
|
||||
};
|
||||
|
||||
$(document).on('ready page:load', function() {
|
||||
return $('body').renderGFM();
|
||||
});
|
||||
|
||||
}).call(this);
|
55
app/assets/javascripts/render_math.js
Normal file
55
app/assets/javascripts/render_math.js
Normal file
|
@ -0,0 +1,55 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, consistent-return, no-var, no-undef, no-else-return, prefer-arrow-callback, padded-blocks, max-len */
|
||||
// Renders math using KaTeX in any element with the
|
||||
// `js-render-math` class
|
||||
//
|
||||
// ### Example Markup
|
||||
//
|
||||
// <code class="js-render-math"></div>
|
||||
//
|
||||
(function() {
|
||||
// Only load once
|
||||
var katexLoaded = false;
|
||||
|
||||
// Loop over all math elements and render math
|
||||
var renderWithKaTeX = function (elements) {
|
||||
elements.each(function () {
|
||||
var mathNode = $('<span></span>');
|
||||
var $this = $(this);
|
||||
|
||||
var display = $this.attr('data-math-style') === 'display';
|
||||
try {
|
||||
katex.render($this.text(), mathNode.get(0), { displayMode: display });
|
||||
mathNode.insertAfter($this);
|
||||
$this.remove();
|
||||
} catch (err) {
|
||||
// What can we do??
|
||||
console.log(err.message);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$.fn.renderMath = function() {
|
||||
var $this = this;
|
||||
if ($this.length === 0) return;
|
||||
|
||||
if (katexLoaded) renderWithKaTeX($this);
|
||||
else {
|
||||
// Request CSS file so it is in the cache
|
||||
$.get(gon.katex_css_url, function() {
|
||||
var css = $('<link>',
|
||||
{ rel: 'stylesheet',
|
||||
type: 'text/css',
|
||||
href: gon.katex_css_url,
|
||||
});
|
||||
css.appendTo('head');
|
||||
|
||||
// Load KaTeX js
|
||||
$.getScript(gon.katex_js_url, function() {
|
||||
katexLoaded = true;
|
||||
renderWithKaTeX($this); // Run KaTeX
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
}).call(this);
|
28
app/assets/javascripts/syntax_highlight.js
Normal file
28
app/assets/javascripts/syntax_highlight.js
Normal file
|
@ -0,0 +1,28 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, consistent-return, no-var, no-undef, no-else-return, prefer-arrow-callback, padded-blocks, max-len */
|
||||
// Syntax Highlighter
|
||||
//
|
||||
// Applies a syntax highlighting color scheme CSS class to any element with the
|
||||
// `js-syntax-highlight` class
|
||||
//
|
||||
// ### Example Markup
|
||||
//
|
||||
// <div class="js-syntax-highlight"></div>
|
||||
//
|
||||
(function() {
|
||||
|
||||
$.fn.syntaxHighlight = function() {
|
||||
var $children;
|
||||
|
||||
if ($(this).hasClass('js-syntax-highlight')) {
|
||||
// Given the element itself, apply highlighting
|
||||
return $(this).addClass(gon.user_color_scheme);
|
||||
} else {
|
||||
// Given a parent element, recurse to any of its applicable children
|
||||
$children = $(this).find('.js-syntax-highlight');
|
||||
if ($children.length) {
|
||||
return $children.syntaxHighlight();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}).call(this);
|
|
@ -1,79 +0,0 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, consistent-return, no-var, no-undef, no-else-return, prefer-arrow-callback, padded-blocks, max-len */
|
||||
// Syntax Highlighter
|
||||
//
|
||||
// Applies a syntax highlighting color scheme CSS class to any element with the
|
||||
// `js-syntax-highlight` class
|
||||
//
|
||||
// ### Example Markup
|
||||
//
|
||||
// <div class="js-syntax-highlight"></div>
|
||||
//
|
||||
(function() {
|
||||
// CSS and JS for KaTeX
|
||||
CSS_PATH = "<%= asset_path('katex.css') %>";
|
||||
JS_PATH = "<%= asset_path('katex.js') %>";
|
||||
|
||||
// Only load once
|
||||
var katexLoaded = false;
|
||||
|
||||
// Loop over all math elements and render math
|
||||
var renderWithKaTeX = function (elements) {
|
||||
elements.each(function () {
|
||||
if (!!$(this).attr('rendered')) return;
|
||||
|
||||
$(this).attr('rendered', true);
|
||||
$(this).hide();
|
||||
var mathNode = $( "<math>Test</math>" );
|
||||
mathNode.insertAfter($(this));
|
||||
|
||||
var display = $(this).hasClass('highlight');
|
||||
katex.render($(this).text(), mathNode.get(0), { displayMode: display })
|
||||
})
|
||||
};
|
||||
var handleMath = function () {
|
||||
var mathElements = $('.code.math');
|
||||
|
||||
if (mathElements.length == 0) return;
|
||||
|
||||
if (katexLoaded) renderWithKaTeX(mathElements);
|
||||
else {
|
||||
// Request CSS file so it is in the cache
|
||||
$.get(CSS_PATH, function(){
|
||||
var css = $('<link>',
|
||||
{rel:'stylesheet',
|
||||
type:'text/css',
|
||||
href: CSS_PATH
|
||||
});
|
||||
css.appendTo('head');
|
||||
|
||||
// Load KaTeX js
|
||||
$.getScript(JS_PATH, function() {
|
||||
katexLoaded = true;
|
||||
renderWithKaTeX(mathElements); // Run KaTeX
|
||||
})
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$.fn.syntaxHighlight = function() {
|
||||
var $children;
|
||||
|
||||
handleMath();
|
||||
|
||||
if ($(this).hasClass('js-syntax-highlight')) {
|
||||
// Given the element itself, apply highlighting
|
||||
return $(this).addClass(gon.user_color_scheme);
|
||||
} else {
|
||||
// Given a parent element, recurse to any of its applicable children
|
||||
$children = $(this).find('.js-syntax-highlight');
|
||||
if ($children.length) {
|
||||
return $children.syntaxHighlight();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$(document).on('ready page:load', function() {
|
||||
return $('.js-syntax-highlight').syntaxHighlight();
|
||||
});
|
||||
|
||||
}).call(this);
|
4
changelogs/unreleased/8003-katex-math.yml
Normal file
4
changelogs/unreleased/8003-katex-math.yml
Normal file
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
title: Added support for math rendering, using KaTeX, in Markdown and asciidoc
|
||||
merge_request: 8003
|
||||
author: Munken
|
|
@ -84,6 +84,8 @@ module Gitlab
|
|||
config.assets.precompile << "print.css"
|
||||
config.assets.precompile << "notify.css"
|
||||
config.assets.precompile << "mailers/*.css"
|
||||
config.assets.precompile << "katex.css"
|
||||
config.assets.precompile << "katex.js"
|
||||
config.assets.precompile << "graphs/graphs_bundle.js"
|
||||
config.assets.precompile << "users/users_bundle.js"
|
||||
config.assets.precompile << "network/network_bundle.js"
|
||||
|
|
2
config/initializers/math_lexer.rb
Normal file
2
config/initializers/math_lexer.rb
Normal file
|
@ -0,0 +1,2 @@
|
|||
# Touch the lexers so it is registered with Rouge
|
||||
Rouge::Lexers::Math
|
|
@ -319,6 +319,40 @@ Here's a sample video:
|
|||
|
||||
![Sample Video](img/markdown_video.mp4)
|
||||
|
||||
### Math
|
||||
|
||||
> If this is not rendered correctly, see
|
||||
https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/user/markdown.md#math
|
||||
|
||||
It is possible to have math written with the LaTeX syntax rendered using [KaTeX][katex].
|
||||
|
||||
Math written inside ```$``$``` will be rendered inline with the text.
|
||||
|
||||
Math written inside triple back quotes, with the language declared as `math`, will be rendered on a separate line.
|
||||
|
||||
Example:
|
||||
|
||||
This math is inline $`a^2+b^2=c^2`$.
|
||||
|
||||
This is on a separate line
|
||||
```math
|
||||
a^2+b^2=c^2
|
||||
```
|
||||
|
||||
Becomes:
|
||||
|
||||
This math is inline $`a^2+b^2=c^2`$.
|
||||
|
||||
This is on a separate line
|
||||
```math
|
||||
a^2+b^2=c^2
|
||||
```
|
||||
|
||||
_Be advised that KaTeX only supports a [subset][katex-subset] of LaTeX._
|
||||
|
||||
>**Note:**
|
||||
This also works for the asciidoctor `:stem: latexmath`. For details see the [asciidoctor user manual][asciidoctor-manual].
|
||||
|
||||
## Standard Markdown
|
||||
|
||||
### Headers
|
||||
|
@ -764,3 +798,6 @@ A link starting with a `/` is relative to the wiki root.
|
|||
[markdown.md]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/user/markdown.md
|
||||
[rouge]: http://rouge.jneen.net/ "Rouge website"
|
||||
[redcarpet]: https://github.com/vmg/redcarpet "Redcarpet 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"
|
||||
[asciidoctor-manual]: http://asciidoctor.org/docs/user-manual/#activating-stem-support "Asciidoctor user manual"
|
|
@ -1,27 +0,0 @@
|
|||
require 'uri'
|
||||
|
||||
module Banzai
|
||||
module Filter
|
||||
# HTML filter that adds class="code math" and removes the dolar sign in $`2+2`$.
|
||||
#
|
||||
class InlineMathFilter < HTML::Pipeline::Filter
|
||||
def call
|
||||
doc.xpath("descendant-or-self::text()[substring(., string-length(.)) = '$']"\
|
||||
"/following-sibling::*[name() = 'code']"\
|
||||
"/following-sibling::text()[starts-with(.,'$')]").each do |el|
|
||||
closing = el
|
||||
code = el.previous
|
||||
code[:class] = 'code math'
|
||||
opening = code.previous
|
||||
|
||||
closing.content = closing.content[1..-1]
|
||||
opening.content = opening.content[0..-2]
|
||||
|
||||
closing
|
||||
end
|
||||
|
||||
doc
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
51
lib/banzai/filter/math_filter.rb
Normal file
51
lib/banzai/filter/math_filter.rb
Normal file
|
@ -0,0 +1,51 @@
|
|||
require 'uri'
|
||||
|
||||
module Banzai
|
||||
module Filter
|
||||
# HTML filter that adds class="code math" and removes the dollar sign in $`2+2`$.
|
||||
#
|
||||
class MathFilter < HTML::Pipeline::Filter
|
||||
# This picks out <code>...</code>.
|
||||
INLINE_MATH = 'descendant-or-self::code'.freeze
|
||||
|
||||
# Pick out a code block which is declared math
|
||||
DISPLAY_MATH = "descendant-or-self::pre[contains(@class, 'math') and contains(@class, 'code')]".freeze
|
||||
|
||||
# Attribute indicating inline or display math.
|
||||
STYLE_ATTRIBUTE = 'data-math-style'.freeze
|
||||
|
||||
# Class used for tagging elements that should be rendered
|
||||
TAG_CLASS = 'js-render-math'.freeze
|
||||
|
||||
INLINE_CLASSES = "code math #{TAG_CLASS}".freeze
|
||||
|
||||
DOLLAR_SIGN = '$'.freeze
|
||||
|
||||
def call
|
||||
doc.xpath(INLINE_MATH).each do |code|
|
||||
closing = code.next
|
||||
opening = code.previous
|
||||
|
||||
# We need a sibling before and after.
|
||||
# They should end and start with $ respectively.
|
||||
if closing && opening &&
|
||||
closing.content.first == DOLLAR_SIGN &&
|
||||
opening.content.last == DOLLAR_SIGN
|
||||
|
||||
code[:class] = INLINE_CLASSES
|
||||
code[STYLE_ATTRIBUTE] = 'inline'
|
||||
closing.content = closing.content[1..-1]
|
||||
opening.content = opening.content[0..-2]
|
||||
end
|
||||
end
|
||||
|
||||
doc.xpath(DISPLAY_MATH).each do |el|
|
||||
el[STYLE_ATTRIBUTE] = 'display'
|
||||
el[:class] += " #{TAG_CLASS}"
|
||||
end
|
||||
|
||||
doc
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -48,9 +48,6 @@ module Banzai
|
|||
end
|
||||
|
||||
def lexer_for(language)
|
||||
if language == 'math'
|
||||
return Rouge::Lexers::Math.new
|
||||
end
|
||||
(Rouge::Lexer.find(language) || Rouge::Lexers::PlainText).new
|
||||
end
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ module Banzai
|
|||
Filter::SyntaxHighlightFilter,
|
||||
Filter::SanitizationFilter,
|
||||
|
||||
Filter::InlineMathFilter,
|
||||
Filter::MathFilter,
|
||||
Filter::UploadLinkFilter,
|
||||
Filter::VideoLinkFilter,
|
||||
Filter::ImageLinkFilter,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
require 'asciidoctor'
|
||||
require 'asciidoctor/converter/html5'
|
||||
|
||||
module Gitlab
|
||||
# Parser/renderer for the AsciiDoc format that uses Asciidoctor and filters
|
||||
|
@ -23,7 +24,7 @@ module Gitlab
|
|||
def self.render(input, context, asciidoc_opts = {})
|
||||
asciidoc_opts.reverse_merge!(
|
||||
safe: :secure,
|
||||
backend: :html5,
|
||||
backend: :gitlab_html5,
|
||||
attributes: []
|
||||
)
|
||||
asciidoc_opts[:attributes].unshift(*DEFAULT_ADOC_ATTRS)
|
||||
|
@ -36,3 +37,31 @@ module Gitlab
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
module Gitlab
|
||||
module Asciidoc
|
||||
class Html5Converter < Asciidoctor::Converter::Html5Converter
|
||||
extend Asciidoctor::Converter::Config
|
||||
|
||||
register_for 'gitlab_html5'
|
||||
|
||||
def stem(node)
|
||||
return super unless node.style.to_sym == :latexmath
|
||||
|
||||
%(<pre#{id_attribute(node)} class="code math js-render-math #{node.role}" data-math-style="display"><code>#{node.content}</code></pre>)
|
||||
end
|
||||
|
||||
def inline_quoted(node)
|
||||
return super unless node.type.to_sym == :latexmath
|
||||
|
||||
%(<code#{id_attribute(node)} class="code math js-render-math #{node.role}" data-math-style="inline">#{node.text}</code>)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def id_attribute(node)
|
||||
node.id ? %( id="#{node.id}") : nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -8,6 +8,8 @@ module Gitlab
|
|||
gon.shortcuts_path = help_page_path('shortcuts')
|
||||
gon.user_color_scheme = Gitlab::ColorSchemes.for_user(current_user).css_class
|
||||
gon.award_menu_url = emojis_path
|
||||
gon.katex_css_url = ActionController::Base.helpers.asset_path('katex.css')
|
||||
gon.katex_js_url = ActionController::Base.helpers.asset_path('katex.js')
|
||||
|
||||
if current_user
|
||||
gon.current_user_id = current_user.id
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
module Rouge
|
||||
module Lexers
|
||||
class Math < Lexer
|
||||
title "Plain Text"
|
||||
title "A passthrough lexer used for LaTeX input"
|
||||
desc "A boring lexer that doesn't highlight anything"
|
||||
|
||||
tag 'math'
|
||||
mimetypes 'text/plain'
|
||||
|
||||
default_options :token => 'Text'
|
||||
default_options token: 'Text'
|
||||
|
||||
def token
|
||||
@token ||= Token[option :token]
|
||||
|
@ -18,4 +18,4 @@ module Rouge
|
|||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Banzai::Filter::InlineMathFilter, lib: true do
|
||||
include FilterSpecHelper
|
||||
|
||||
it 'leaves regular inline code unchanged' do
|
||||
input = "<code>2+2</code>"
|
||||
doc = filter(input)
|
||||
expect(doc.to_s).to eq input
|
||||
end
|
||||
|
||||
it 'removes surrounding dollar signs and adds class' do
|
||||
doc = filter("$<code>2+2</code>$")
|
||||
expect(doc.to_s).to eq '<code class="code math">2+2</code>'
|
||||
end
|
||||
|
||||
it 'only removes surrounding dollar signs' do
|
||||
doc = filter("test $<code>2+2</code>$ test")
|
||||
expect(doc.to_s).to eq 'test <code class="code math">2+2</code> test'
|
||||
end
|
||||
|
||||
it 'only removes surrounding single dollar sign' do
|
||||
doc = filter("test $$<code>2+2</code>$$ test")
|
||||
expect(doc.to_s).to eq 'test $<code class="code math">2+2</code>$ test'
|
||||
end
|
||||
|
||||
it 'ignores cases with missing dolar sign at the end' do
|
||||
input = "test $<code>2+2</code> test"
|
||||
doc = filter(input)
|
||||
expect(doc.to_s).to eq input
|
||||
end
|
||||
|
||||
it 'ignores cases with missing dolar sign at the beginning' do
|
||||
input = "test <code>2+2</code>$ test"
|
||||
doc = filter(input)
|
||||
expect(doc.to_s).to eq input
|
||||
end
|
||||
|
||||
it 'ignores dollar signs if it is not adjacent' do
|
||||
input = '<p>We check strictly $<code>2+2</code> and <code>2+2</code>$ </p>'
|
||||
doc = filter(input)
|
||||
expect(doc.to_s).to eq input
|
||||
end
|
||||
|
||||
end
|
120
spec/lib/banzai/filter/math_filter_spec.rb
Normal file
120
spec/lib/banzai/filter/math_filter_spec.rb
Normal file
|
@ -0,0 +1,120 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Banzai::Filter::MathFilter, lib: true do
|
||||
include FilterSpecHelper
|
||||
|
||||
it 'leaves regular inline code unchanged' do
|
||||
input = "<code>2+2</code>"
|
||||
doc = filter(input)
|
||||
|
||||
expect(doc.to_s).to eq input
|
||||
end
|
||||
|
||||
it 'removes surrounding dollar signs and adds class code, math and js-render-math' do
|
||||
doc = filter("$<code>2+2</code>$")
|
||||
|
||||
expect(doc.to_s).to eq '<code class="code math js-render-math" data-math-style="inline">2+2</code>'
|
||||
end
|
||||
|
||||
it 'only removes surrounding dollar signs' do
|
||||
doc = filter("test $<code>2+2</code>$ test")
|
||||
before = doc.xpath('descendant-or-self::text()[1]').first
|
||||
after = doc.xpath('descendant-or-self::text()[3]').first
|
||||
|
||||
expect(before.to_s).to eq 'test '
|
||||
expect(after.to_s).to eq ' test'
|
||||
end
|
||||
|
||||
it 'only removes surrounding single dollar sign' do
|
||||
doc = filter("test $$<code>2+2</code>$$ test")
|
||||
before = doc.xpath('descendant-or-self::text()[1]').first
|
||||
after = doc.xpath('descendant-or-self::text()[3]').first
|
||||
|
||||
expect(before.to_s).to eq 'test $'
|
||||
expect(after.to_s).to eq '$ test'
|
||||
end
|
||||
|
||||
it 'adds data-math-style inline attribute to inline math' do
|
||||
doc = filter('$<code>2+2</code>$')
|
||||
code = doc.xpath('descendant-or-self::code').first
|
||||
|
||||
expect(code['data-math-style']).to eq 'inline'
|
||||
end
|
||||
|
||||
it 'adds class code and math to inline math' do
|
||||
doc = filter('$<code>2+2</code>$')
|
||||
code = doc.xpath('descendant-or-self::code').first
|
||||
|
||||
expect(code[:class]).to include("code")
|
||||
expect(code[:class]).to include("math")
|
||||
end
|
||||
|
||||
it 'adds js-render-math class to inline math' do
|
||||
doc = filter('$<code>2+2</code>$')
|
||||
code = doc.xpath('descendant-or-self::code').first
|
||||
|
||||
expect(code[:class]).to include("js-render-math")
|
||||
end
|
||||
|
||||
# Cases with faulty syntax. Should be a no-op
|
||||
|
||||
it 'ignores cases with missing dolar sign at the end' do
|
||||
input = "test $<code>2+2</code> test"
|
||||
doc = filter(input)
|
||||
|
||||
expect(doc.to_s).to eq input
|
||||
end
|
||||
|
||||
it 'ignores cases with missing dolar sign at the beginning' do
|
||||
input = "test <code>2+2</code>$ test"
|
||||
doc = filter(input)
|
||||
|
||||
expect(doc.to_s).to eq input
|
||||
end
|
||||
|
||||
it 'ignores dollar signs if it is not adjacent' do
|
||||
input = '<p>We check strictly $<code>2+2</code> and <code>2+2</code>$ </p>'
|
||||
doc = filter(input)
|
||||
|
||||
expect(doc.to_s).to eq input
|
||||
end
|
||||
|
||||
# Display math
|
||||
|
||||
it 'adds data-math-style display attribute to display math' do
|
||||
doc = filter('<pre class="code highlight js-syntax-highlight math" v-pre="true"><code>2+2</code></pre>')
|
||||
pre = doc.xpath('descendant-or-self::pre').first
|
||||
|
||||
expect(pre['data-math-style']).to eq 'display'
|
||||
end
|
||||
|
||||
it 'adds js-render-math class to display math' do
|
||||
doc = filter('<pre class="code highlight js-syntax-highlight math" v-pre="true"><code>2+2</code></pre>')
|
||||
pre = doc.xpath('descendant-or-self::pre').first
|
||||
|
||||
expect(pre[:class]).to include("js-render-math")
|
||||
end
|
||||
|
||||
it 'ignores code blocks that are not math' do
|
||||
input = '<pre class="code highlight js-syntax-highlight plaintext" v-pre="true"><code>2+2</code></pre>'
|
||||
doc = filter(input)
|
||||
|
||||
expect(doc.to_s).to eq input
|
||||
end
|
||||
|
||||
it 'requires the pre to contain both code and math' do
|
||||
input = '<pre class="highlight js-syntax-highlight plaintext math" v-pre="true"><code>2+2</code></pre>'
|
||||
doc = filter(input)
|
||||
|
||||
expect(doc.to_s).to eq input
|
||||
end
|
||||
|
||||
it 'dollar signs around to display math' do
|
||||
doc = filter('$<pre class="code highlight js-syntax-highlight math" v-pre="true"><code>2+2</code></pre>$')
|
||||
before = doc.xpath('descendant-or-self::text()[1]').first
|
||||
after = doc.xpath('descendant-or-self::text()[3]').first
|
||||
|
||||
expect(before.to_s).to eq '$'
|
||||
expect(after.to_s).to eq '$'
|
||||
end
|
||||
end
|
|
@ -11,7 +11,7 @@ module Gitlab
|
|||
it "converts the input using Asciidoctor and default options" do
|
||||
expected_asciidoc_opts = {
|
||||
safe: :secure,
|
||||
backend: :html5,
|
||||
backend: :gitlab_html5,
|
||||
attributes: described_class::DEFAULT_ADOC_ATTRS
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,7 @@ module Gitlab
|
|||
it "merges the options with default ones" do
|
||||
expected_asciidoc_opts = {
|
||||
safe: :safe,
|
||||
backend: :html5,
|
||||
backend: :gitlab_html5,
|
||||
attributes: described_class::DEFAULT_ADOC_ATTRS + ['foo']
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue