jekyll-spaceship 0.9.4 → 0.9.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cbba69bcf95b309c36da702cce9670212f7a32985e2522f13b06fdc0058e0b60
4
- data.tar.gz: 679ee30cad6abfe6c6fb271e3816bff2e16f931b94492d0e0223f4dba11263f4
3
+ metadata.gz: 51f0576137305906368ec086aba6c9c11d45799d10dc8a22abd5598a4026251a
4
+ data.tar.gz: 1a52f85350f6d2b3e128b637ec040108d993534ec554296cdd2b998e26551aec
5
5
  SHA512:
6
- metadata.gz: 207137e6fedec9521c2cde3a3215cf7f1ccbc81f6ce0385c385a1c48d31a1ba7d03b3c532e0cbde80ce2f8d33e79a770d299d64cc436acddfc03ed651a2e9fc4
7
- data.tar.gz: 1c78e2e73e99f7c3e007e3cbcea683b1d4a4db5771737530865be9262d42adf5617e6d7b9cb9931b4947937fdc64d927bf38967121b2dc98d1107d5bec01cace
6
+ metadata.gz: 1445456d3974c347367ae35c8b8b2ceec320f523931620d3ad4f19f3982ddefff2f9426f9f47318b6e548da9c0b25b0b370733a472250065579c27296785ce49
7
+ data.tar.gz: f78d6fd69910ea7350b77a6d0c8702214d097e8813032fb4254fa53f4521805c5f2b74c3f1ea8c763cb305b145929d6e12810653952ef57c4c32765048ccaffe
data/.github/FUNDING.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  # These are supported funding model platforms
2
2
 
3
- github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
3
+ github: jeffreytse # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4
4
  patreon: jeffreytse
5
5
  open_collective: # Replace with a single Open Collective username
6
6
  ko_fi: jeffreytse
data/README.md CHANGED
@@ -177,8 +177,15 @@ jekyll-spaceship:
177
177
  inlineMath:
178
178
  - ['$','$']
179
179
  - ['\(','\)']
180
+ displayMath:
181
+ - ['$$','$$']
182
+ - ['\[','\]']
180
183
  svg:
181
184
  fontCache: 'global'
185
+ optimize: # optimization on building stage to check and add mathjax scripts
186
+ enabled: true # value `false` for adding to all pages
187
+ include: [] # include patterns for math expressions checking (regexp)
188
+ exclude: [] # exclude patterns for math expressions checking (regexp)
182
189
  plantuml-processor:
183
190
  mode: default # mode value 'pre-fetch' for fetching image at building stage
184
191
  css:
@@ -434,7 +441,7 @@ Code above would be parsed as:
434
441
  #### Cell Alignment
435
442
 
436
443
  Markdown table syntax use colons ":" for forcing column alignment.
437
- Therefore, here we also use it for foring cell alignment.
444
+ Therefore, here we also use it for forcing cell alignment.
438
445
 
439
446
  Table cell can be set alignment separately.
440
447
 
@@ -31,6 +31,16 @@ module Jekyll::Spaceship
31
31
  first.merge(second.to_h, &merger)
32
32
  end
33
33
 
34
+ def self.deep_dig(obj, key)
35
+ if obj.respond_to?(:key?) && obj.key?(key)
36
+ obj[key]
37
+ elsif obj.respond_to?(:each)
38
+ result = nil
39
+ obj.find { |*a| result = self.deep_dig(a.last, key) }
40
+ result
41
+ end
42
+ end
43
+
34
44
  def self.store(section, default)
35
45
  return @@store[section] if default.nil?
36
46
  @@store[section] = deep_merge(default, @@store[section])
@@ -25,7 +25,11 @@ module Jekyll::Spaceship
25
25
  attr_accessor :handled
26
26
 
27
27
  def name
28
- self.class.name.split('::').last
28
+ self.class.class_name
29
+ end
30
+
31
+ def self.class_name
32
+ self.name.split('::').last
29
33
  end
30
34
 
31
35
  def filename
@@ -212,6 +216,7 @@ module Jekyll::Spaceship
212
216
  'body' => content_body
213
217
  }
214
218
  rescue StandardError => msg
219
+ logger = Logger.new(self.class_name)
215
220
  logger.log msg
216
221
  end
217
222
  end
@@ -16,31 +16,72 @@ module Jekyll::Spaceship
16
16
  end
17
17
 
18
18
  def on_handle_html(content)
19
- # handle emoji markup
20
- content.scan(/:([\w\d+-]+):/) do |match|
19
+ emoji_filter(content, 'pre code') do |emoji|
20
+ # mark current file has been handled
21
+ self.handled = true
22
+
23
+ # here is the replacement content
24
+ "<img class=\"#{config['css']['class']}\""\
25
+ " title=\":#{emoji.name}:\""\
26
+ " alt=\":#{emoji.name}:\""\
27
+ " raw=\"#{emoji.raw}\""\
28
+ " src=\"#{config['src']}#{emoji.image_filename}\""\
29
+ " style=\"vertical-align: middle; display: inline;"\
30
+ " max-width: 1em; visibility: hidden;\""\
31
+ " onload=\"this.style.visibility='visible'\""\
32
+ " onerror=\"this.replaceWith(this.getAttribute('raw'))\">"\
33
+ "</img>"
34
+ end
35
+ end
36
+
37
+ def emoji_filter(content, selector)
38
+ # use nokogiri to parse html
39
+ doc = Nokogiri::HTML(content)
40
+
41
+ body = doc.at('body')
42
+
43
+ # in case of a page has no the body node, especially when your
44
+ # page's layout field of front matter is nil or unavailable
45
+ return content if body.nil?
46
+
47
+ # filter nodes (pre, code)
48
+ nodes = body.css(selector)
49
+ nodes.each do |node|
50
+ # handle emoji markup
51
+ node.inner_html = node.inner_html.gsub(
52
+ /:([\w\d+-]+?):/, '\:\1\:'
53
+ )
54
+ end
55
+
56
+ # parse the emoji
57
+ content = body.inner_html
58
+ content.scan(/(?<!\\):([\w\d+-]+?)(?<!\\):/) do |match|
59
+ # Skip invalid emoji name
21
60
  emoji = Emoji.find_by_alias match[0]
22
61
  next if emoji.nil?
23
- self.handled = true
24
62
 
25
63
  # escape plus sign
26
64
  emoji_name = emoji.name.gsub('+', '\\\+')
27
- css_class = self.config['css']['class']
65
+
66
+ result = yield emoji
67
+ next if result.nil?
28
68
 
29
69
  content = content.gsub(
30
70
  /(?<!\=")\s*:#{emoji_name}:\s*(?!"\s)/,
31
- "<img class=\"#{css_class}\""\
32
- " title=\":#{emoji.name}:\""\
33
- " alt=\":#{emoji.name}:\""\
34
- " raw=\"#{emoji.raw}\""\
35
- " src=\"#{config['src']}#{emoji.image_filename}\""\
36
- " style=\"vertical-align: middle; display: inline;"\
37
- " max-width: 1em; visibility: hidden;\""\
38
- " onload=\"this.style.visibility='visible'\""\
39
- " onerror=\"this.replaceWith(this.getAttribute('raw'))\">"\
40
- "</img>"
71
+ result)
72
+ end
73
+
74
+ body.inner_html = content
75
+
76
+ # restore nodes (pre, code)
77
+ nodes.each do |node|
78
+ # handle emoji markup
79
+ node.inner_html = node.inner_html.gsub(
80
+ /\\:([\w\d+-]+?)\\:/, ':\1:'
41
81
  )
42
82
  end
43
- content
83
+
84
+ doc.to_html
44
85
  end
45
86
  end
46
87
  end
@@ -11,14 +11,45 @@ module Jekyll::Spaceship
11
11
  'https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js',
12
12
  ],
13
13
  'config' => {
14
- 'tex' => { 'inlineMath' => [['$','$'], ['\\(','\\)']] },
14
+ 'tex' => {
15
+ 'inlineMath' => [['$','$'], ['\\(','\\)']],
16
+ 'displayMath' => [['$$','$$'], ['\\[','\\]']]
17
+ },
15
18
  'svg': { 'fontCache': 'global' }
19
+ },
20
+ 'optimize' => {
21
+ 'enabled' => true,
22
+ 'include' => [],
23
+ 'exclude' => []
16
24
  }
17
25
  }
18
26
  end
19
27
 
20
28
  def process?
21
- return true if Type.html?(output_ext)
29
+ return true if Type.html?(output_ext) or Type.markdown?(output_ext)
30
+ end
31
+
32
+ def on_handle_markdown(content)
33
+ # pre-handle mathjax expressions in markdown
34
+ patterns = get_math_patterns()
35
+ patterns['include'].each do |pattern|
36
+ content.scan(pattern) do |result|
37
+ expr = result[0]
38
+ body = result[1]
39
+ next if body.size.zero?
40
+ is_excluded = false
41
+ patterns['exclude'].each do |pe|
42
+ break is_excluded = true if expr.match(/#{pe}/)
43
+ end
44
+ next if is_excluded
45
+ escaped_expr = expr
46
+ .gsub(/(?<!^)\\(?!\S$)/, '\\\\\\\\')
47
+ .gsub(/(?<!\\)\$\$/, '\\\$\\\$')
48
+ .gsub(/\\ /, '\\\\\\ ')
49
+ content = content.gsub(expr, escaped_expr)
50
+ end
51
+ end
52
+ content
22
53
  end
23
54
 
24
55
  def on_handle_html(content)
@@ -45,22 +76,67 @@ module Jekyll::Spaceship
45
76
  end
46
77
 
47
78
  def has_mathjax_expression?(doc)
48
- doc.css('*').each do |node|
49
- if node.content.match(/(?<!\\)\$.+(?<!\\)\$/)
50
- return true
51
- end
52
- if node.content.match(/(?<!\\)\\\(.+(?<!\\)\\\)/)
53
- return true
79
+ return true unless config['optimize']['enabled'] == true
80
+ scan_mathjax_expression(doc) do
81
+ return true
82
+ end
83
+ false
84
+ end
85
+
86
+ def get_math_patterns()
87
+ patterns = []
88
+ math_patterns = []
89
+ ['tex', 'tex2jax'].each do |t|
90
+ ['inlineMath', 'displayMath'].each do |m|
91
+ r = config.dig('config', t, m)
92
+ r&.each do |i|
93
+ btag = Regexp.escape(i[0])
94
+ etag = Regexp.escape(i[1])
95
+ patterns <<= /((?<!\\\\)#{btag}(.*?)(?<!\\\\)#{etag})/
96
+ end
54
97
  end
55
98
  end
99
+ config['optimize']['include'].each do |pattern|
100
+ patterns <<= /(#{pattern})/
101
+ end
102
+ {
103
+ 'include' => patterns,
104
+ 'exclude' => config['optimize']['exclude']
105
+ }
106
+ end
56
107
 
57
- doc.css('script').each do |node|
58
- type = node['type']
59
- if type and type.match(/math\/tex/)
60
- return true
108
+ def scan_mathjax_expression(doc, &block)
109
+ patterns = get_math_patterns()
110
+ doc = doc.clone
111
+
112
+ # remove code, pre, figure nodes
113
+ doc.css('body code, body pre, body figure').each do |node|
114
+ node.remove
115
+ end
116
+
117
+ # remove scripting mathjax expression
118
+ doc.css('body script').each do |node|
119
+ next if node['type']&.match(/math\/tex/)
120
+ node.remove
121
+ end
122
+
123
+ # scan mathjax expressions
124
+ doc.css('body *').each do |node|
125
+ patterns['include'].each do |pattern|
126
+ # check normal mathjax expression
127
+ node.content.scan(pattern) do |result|
128
+ expr = result[0]
129
+ body = result[1]
130
+ next if body.size.zero?
131
+ is_excluded = false
132
+ patterns['exclude'].each do |pe|
133
+ break is_excluded = true if expr.match(/#{pe}/)
134
+ end
135
+ next if is_excluded
136
+ block.call(node, expr)
137
+ end
61
138
  end
62
139
  end
63
- false
64
140
  end
65
141
  end
66
142
  end
@@ -42,7 +42,7 @@ module Jekyll::Spaceship
42
42
  handle_media(element, {
43
43
  media_type: 'audio',
44
44
  host: '(https?:\\/\\/)?.*\\/',
45
- id: '(.+?\\.(mp3|wav|ogg|mid|midi|aac|wma))',
45
+ id: '(.+?\\.(mp3|wav|ogg|mid|midi|aac|wma))'
46
46
  })
47
47
  end
48
48
 
@@ -53,7 +53,7 @@ module Jekyll::Spaceship
53
53
  # ![video](//techslides.com/demos/sample-videos/small.mp4?width=400)
54
54
  def handle_normal_video(element)
55
55
  handle_media(element, {
56
- media_type: 'iframe',
56
+ media_type: 'video',
57
57
  host: '(https?:\\/\\/)?.*\\/',
58
58
  id: '(.+?\\.(avi|mp4|webm|ogg|ogv|flv|mkv|mov|wmv|3gp|rmvb|asf))'
59
59
  })
@@ -90,8 +90,8 @@ module Jekyll::Spaceship
90
90
  def handle_dailymotion(element)
91
91
  handle_media(element, {
92
92
  media_type: 'iframe',
93
- host: '(https?:)?\\/\\/.*dai.?ly.*',
94
- id: '(?<=video\\/|\\/)([a-zA-Z0-9\\_\\-]+)',
93
+ host: '(https?:)?\\/\\/(?>www\\.)?dai\\.?ly(?>motion\\.com\\/video)?\\/',
94
+ id: '([a-zA-Z0-9\\_\\-]+)',
95
95
  base_url: "https://www.dailymotion.com/embed/video/"
96
96
  })
97
97
  end
@@ -128,7 +128,7 @@ module Jekyll::Spaceship
128
128
  src = element.get_attribute('src')
129
129
  title = element.get_attribute('title')
130
130
  id = data[:id_from] === 'html' ? '()' : data[:id]
131
- match_data = src.match(/#{host}#{id}\S*/)
131
+ match_data = src&.match(/#{host}#{id}\S*/)
132
132
  return if match_data.nil?
133
133
 
134
134
  media_type = data[:media_type]
@@ -158,6 +158,10 @@ module Jekyll::Spaceship
158
158
  cfg['loop'] = qs['loop'] || data[:loop] || cfg['loop']
159
159
  cfg['style'] += ';display: none;' if qs['hidden']
160
160
  handle_audio(element, { cfg: cfg })
161
+ when 'video'
162
+ cfg['autoplay'] = qs['autoplay'] || data[:autoplay] || cfg['autoplay']
163
+ cfg['loop'] = qs['loop'] || data[:loop] || cfg['loop']
164
+ handle_video(element, { cfg: cfg })
161
165
  when 'iframe'
162
166
  cfg['title'] = title
163
167
  cfg['width'] = qs['width'] || data[:width] || cfg['width']
@@ -179,12 +183,32 @@ module Jekyll::Spaceship
179
183
  " src=\"#{cfg['src']}\""\
180
184
  " style=\"#{cfg['style']}\""\
181
185
  " controls>" \
182
- "<p> Your browser doesn't support HTML5 audio."\
186
+ " Your browser doesn't support HTML5 audio."\
183
187
  " Here is a <a href=\"#{cfg['src']}\">link to download the audio</a>"\
184
- "instead. </p>"\
188
+ " instead."\
185
189
  "</audio>"
186
- doc = Nokogiri::XML(html)
187
- element.replace(doc.children.first)
190
+ doc = Nokogiri::HTML(html)
191
+ return if element.parent.nil?
192
+ element.replace(doc.at('body').children.first)
193
+ end
194
+
195
+ def handle_video(element, data)
196
+ cfg = data[:cfg]
197
+ html = "<video"\
198
+ " id=\"#{cfg['id']}\""\
199
+ " class=\"#{cfg['class']}\""\
200
+ " style=\"#{cfg['style']}\""\
201
+ " #{cfg['autoplay'] ? 'autoplay' : ''}"\
202
+ " #{cfg['loop'] ? 'loop' : ''}"\
203
+ " controls>" \
204
+ " <source src=\"#{cfg['src']}\">" \
205
+ " Your browser doesn't support HTML5 video."\
206
+ " Here is a <a href=\"#{cfg['src']}\">link to download the video</a>"\
207
+ " instead."\
208
+ "</video>"
209
+ doc = Nokogiri::HTML(html)
210
+ return if element.parent.nil?
211
+ element.replace(doc.at('body').children.first)
188
212
  end
189
213
 
190
214
  def handle_iframe(element, data)
@@ -201,8 +225,9 @@ module Jekyll::Spaceship
201
225
  " frameborder=\"#{cfg['frameborder']}\""\
202
226
  " allowfullscreen>"\
203
227
  "</iframe>"
204
- doc = Nokogiri::XML(html)
205
- element.replace(doc.children.first)
228
+ doc = Nokogiri::HTML(html)
229
+ return if element.parent.nil?
230
+ element.replace(doc.at('body').children.first)
206
231
  end
207
232
 
208
233
  def get_id_from_html(url, pattern)
@@ -60,6 +60,9 @@ module Jekyll::Spaceship
60
60
  end
61
61
 
62
62
  def handle_mermaid(code)
63
+ # Handle extra empty lines, otherwise it would cause error
64
+ code = code.gsub(/\n\s*\n/, "\n%%-\n")
65
+
63
66
  # encode to UTF-8
64
67
  code = code.encode('UTF-8')
65
68
  url = get_url(code)
@@ -18,13 +18,21 @@ module Jekyll::Spaceship
18
18
  end
19
19
  if references.size > 0
20
20
  content.scan(/[^\n]*(?<!\\)\|[^\n]*/) do |result|
21
+ replace = result
21
22
  references.each do |key, val|
22
- replace = result.gsub(
23
- /\[([^\n\]]*?)\]\s*\[#{key}\]/,
24
- "[\1](#{val})")
25
- next if result == replace
26
- content = content.gsub(result, replace)
23
+ replace = replace.gsub(
24
+ /\[([^\n\]]*?)\]\s*\[#{Regexp.escape(key)}\]/,
25
+ "[\\1](#{val})"
26
+ )
27
27
  end
28
+ references.each do |key, val|
29
+ replace = replace.gsub(
30
+ /\[#{Regexp.escape(key)}\](?!\s*\(.*?\))/,
31
+ "[#{key}](#{val})"
32
+ )
33
+ end
34
+ next if result == replace
35
+ content = content.gsub(result, replace)
28
36
  end
29
37
  end
30
38
 
@@ -43,7 +51,7 @@ module Jekyll::Spaceship
43
51
  .gsub(/((?<!\\)\${1,2})[^\n]*?\1/, '')
44
52
  .match(/(?<!\\)\|/)
45
53
  replace = result.gsub(
46
- /(?<!(?<!\\)\\)(\*|\$|\[|\(|\"|_)/, '\\\\\\\\\1')
54
+ /(?<!(?<!\\)\\)(\*|\$|\[(?!\^)|\(|\"|_)/, '\\\\\\\\\1')
47
55
  next if result == replace
48
56
  content = content.gsub(result, replace)
49
57
  end
@@ -143,10 +151,10 @@ module Jekyll::Spaceship
143
151
  end
144
152
  end
145
153
 
146
- result = cell.content.match(/(\|)+$/)
154
+ result = cell.inner_html.match(/(\|)+$/)
147
155
  return if result.nil?
148
156
 
149
- cell.content = cell.content.gsub(/(\|)+$/, '')
157
+ cell.inner_html = cell.inner_html.gsub(/(\|)+$/, '')
150
158
  result = result[0]
151
159
  colspan = result.scan(/\|/).count
152
160
  scope.row.colspan += colspan
@@ -203,8 +211,8 @@ module Jekyll::Spaceship
203
211
 
204
212
  # handle rowspan
205
213
  span_cell = scope.table.span_row_cells[scope.row.col_index]
206
- if span_cell and cell.content.match(/^\s*\^{2}/)
207
- cell.content = cell.content.gsub(/^\s*\^{2}/, '')
214
+ if span_cell and cell.inner_html.match(/^\s*\^{2}/)
215
+ cell.inner_html = cell.inner_html.gsub(/^\s*\^{2}/, '')
208
216
  span_cell.inner_html += "\n<br>\n#{cell.inner_html}"
209
217
  rowspan = span_cell.get_attribute('rowspan') || 1
210
218
  rowspan = rowspan.to_i + 1
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Jekyll
4
4
  module Spaceship
5
- VERSION = "0.9.4"
5
+ VERSION = "0.9.9"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jekyll-spaceship
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.4
4
+ version: 0.9.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - jeffreytse
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-10-12 00:00:00.000000000 Z
11
+ date: 2021-04-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jekyll