Class: Jekyll::Spaceship::MathjaxProcessor

Inherits:
Processor
  • Object
show all
Defined in:
lib/jekyll-spaceship/processors/mathjax-processor.rb

Constant Summary

Constants inherited from Processor

Processor::DEFAULT_PRIORITY, Processor::PRIORITY_MAP

Instance Attribute Summary

Attributes inherited from Processor

#config, #exclusions, #handled, #logger, #page, #priority, #registers

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Processor

class_name, #converter, #dispatch, escape_html, exclude, #exclusion_regexs, #ext, fetch_img_data, #filename, #get_exclusion, handle_bang_link, #initialize, #initialize_exclusions, #initialize_priority, #initialize_register, make_img_tag, #name, #next?, #on_handle_html_block, #on_handled, #output_ext, #post_exclude, #pre_exclude, priority, register

Constructor Details

This class inherits a constructor from Jekyll::Spaceship::Processor

Class Method Details

.configObject



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/jekyll-spaceship/processors/mathjax-processor.rb', line 7

def self.config
  {
    'src' => [
      'https://polyfill.io/v3/polyfill.min.js?features=es6',
      'https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js',
    ],
    'config' => {
      'tex' => {
        'inlineMath' => [['$','$'], ['\\(','\\)']],
        'displayMath' => [['$$','$$'], ['\\[','\\]']]
      },
      'svg': { 'fontCache': 'global' }
    },
    'optimize' => {
      'enabled' => true,
      'include' => [],
      'exclude' => []
    }
  }
end

Instance Method Details

#get_math_patternsObject



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/jekyll-spaceship/processors/mathjax-processor.rb', line 87

def get_math_patterns()
  patterns = []
  math_patterns = []
  ['tex', 'tex2jax'].each do |t|
    ['inlineMath', 'displayMath'].each do |m|
      r = config.dig('config', t, m)
      r&.each do |i|
        btag = Regexp.escape(i[0])
        etag = Regexp.escape(i[1])
        patterns <<= /((?<!\\\\)#{btag}([\s\S]*?)(?<!\\\\)#{etag})/
      end
    end
  end
  config['optimize']['include'].each do |pattern|
    patterns <<= /(#{pattern})/
  end
  {
    'include' => patterns,
    'exclude' => config['optimize']['exclude']
  }
end

#has_mathjax_expression?(doc) ⇒ Boolean

Returns:

  • (Boolean)


79
80
81
82
83
84
85
# File 'lib/jekyll-spaceship/processors/mathjax-processor.rb', line 79

def has_mathjax_expression?(doc)
  return true unless config['optimize']['enabled'] == true
  scan_mathjax_expression(doc) do
    return true
  end
  false
end

#on_handle_html(content) ⇒ Object



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/jekyll-spaceship/processors/mathjax-processor.rb', line 56

def on_handle_html(content)
  # use nokogiri to parse html
  doc = Nokogiri::HTML(content)

  head = doc.at('head')
  return content if head.nil?
  return content if not self.has_mathjax_expression? doc

  self.handled = true

  # add mathjax config
  cfg = config['config'].to_json
  head.add_child("<script>MathJax=#{cfg}</script>")

  # add mathjax dependencies
  config['src'] = [config['src']] if config['src'].is_a? String
  config['src'].each do |src|
    head.add_child("<script src=\"#{src}\"></script>")
  end

  doc.to_html
end

#on_handle_markdown(content) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/jekyll-spaceship/processors/mathjax-processor.rb', line 32

def on_handle_markdown(content)
  # pre-handle mathjax expressions in markdown
  patterns = get_math_patterns()
  patterns['include'].each do |pattern|
    content.scan(pattern) do |result|
      expr = result[0]
      body = result[1]
      next if body.size.zero?
      is_excluded = false
      patterns['exclude'].each do |pe|
        break is_excluded = true if expr.match(/#{pe}/)
      end
      next if is_excluded
      escaped_expr = expr
        .gsub(/(?<!^)\\(?!\S$)/, '\\\\\\\\')
        .gsub(/(?<!\\)\$\$/, '\\\$\\\$')
        .gsub(/\\\\(?=\s)/, '\\\\\\\\\\')
        .gsub(/\\ /, '\\\\\\ ')
      content = content.gsub(expr, escaped_expr)
    end
  end
  content
end

#process?Boolean

Returns:

  • (Boolean)


28
29
30
# File 'lib/jekyll-spaceship/processors/mathjax-processor.rb', line 28

def process?
  return true if Type.html?(output_ext) or Type.markdown?(output_ext)
end

#scan_mathjax_expression(doc, &block) ⇒ Object



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/jekyll-spaceship/processors/mathjax-processor.rb', line 109

def scan_mathjax_expression(doc, &block)
  patterns = get_math_patterns()
  doc = doc.clone

  # remove code, pre, figure nodes
  doc.css('body code, body pre, body figure').each do |node|
    node.remove
  end

  # remove scripting mathjax expression
  doc.css('body script').each do |node|
    next if node['type']&.match(/math\/tex/)
    node.remove
  end

  # scan mathjax expressions
  doc.css('body *').each do |node|
    # filter invalid nodes
    next if node.children.size == 0
    invalid = false
    node.children.each do |child|
      unless [
          'text', 'br', 'span',
          'img', 'svg', 'a'
      ].include? child.name
        break invalid = true
      end
    end
    next if invalid

    patterns['include'].each do |pattern|
      # check normal mathjax expression
      node.content.scan(pattern) do |result|
        expr = result[0]
        body = result[1]
        next if body.size.zero?
        is_excluded = false
        patterns['exclude'].each do |pe|
          break is_excluded = true if expr.match(/#{pe}/)
        end
        next if is_excluded
        block.call(node, expr)
      end
    end
  end
end