jekyll-spaceship 0.8.7 → 0.9.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c04f1aada8ea0a1dde37b51418f843e1d163e1dd7230cf602a0f7caf5d787b19
4
- data.tar.gz: 263b035717beeedaad26f42c896a2265b3be4e9bf977b2883e23d8b678f280db
3
+ metadata.gz: cbba69bcf95b309c36da702cce9670212f7a32985e2522f13b06fdc0058e0b60
4
+ data.tar.gz: 679ee30cad6abfe6c6fb271e3816bff2e16f931b94492d0e0223f4dba11263f4
5
5
  SHA512:
6
- metadata.gz: 566854587a4dea0b991d755467dd402cc39a86235636c9e95c1fbd042ae6ee7bc28bd26ffd99b0d12a8e56ffcff469193bab5008d319e8408949382dec162bdb
7
- data.tar.gz: c79139b158834943705be273a533beef706d028fcbff9f339f08aba027ec85a872c73a522679ab2b69d09c82f6c7bd8f8f551f33bfd369040b510b3db36859c5
6
+ metadata.gz: 207137e6fedec9521c2cde3a3215cf7f1ccbc81f6ce0385c385a1c48d31a1ba7d03b3c532e0cbde80ce2f8d33e79a770d299d64cc436acddfc03ed651a2e9fc4
7
+ data.tar.gz: 1c78e2e73e99f7c3e007e3cbcea683b1d4a4db5771737530865be9262d42adf5617e6d7b9cb9931b4947937fdc64d927bf38967121b2dc98d1107d5bec01cace
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --format progress
3
+ --require spec_helper
@@ -1,13 +1,13 @@
1
1
  language: ruby
2
2
  cache: bundler
3
3
  rvm:
4
- - 2.7
5
- - 2.3
4
+ - 2.7
5
+ - 2.3
6
6
  env:
7
7
  global:
8
- - NOKOGIRI_USE_SYSTEM_LIBRARIES=true
8
+ - NOKOGIRI_USE_SYSTEM_LIBRARIES=true
9
9
  matrix:
10
- - JEKYLL_VERSION="~> 3.8"
10
+ - JEKYLL_VERSION="~> 3.8"
11
11
  matrix:
12
12
  include:
13
13
  - rvm: 2.7
@@ -15,8 +15,8 @@ matrix:
15
15
  - rvm: 2.7
16
16
  env: JEKYLL_VERSION=">= 4.0.0"
17
17
  before_install:
18
- - gem update --system
19
- - gem install bundler
18
+ - gem update --system
19
+ - gem install bundler
20
20
  before_script: bundle update
21
21
  script: script/cibuild
22
22
  notifications:
data/README.md CHANGED
@@ -107,11 +107,14 @@ Spaceship is a minimalistic, powerful and extremely customizable [Jekyll](https:
107
107
  - [2.2 How to use?](#22-how-to-use)
108
108
  - [3. PlantUML Usage](#3-plantuml-usage)
109
109
  - [4. Mermaid Usage](#4-mermaid-usage)
110
- - [5. Video Usage](#5-video-usage)
110
+ - [5. Media Usage](#5-media-usage)
111
111
  - [5.1 Youtube Usage](#youtube-usage)
112
112
  - [5.2 Vimeo Usage](#vimeo-usage)
113
113
  - [5.3 DailyMotion Usage](#dailymotion-usage)
114
- - [5.4 General Video Usage](#general-video-usage)
114
+ - [5.4 Spotify Usage](#spotify-usage)
115
+ - [5.5 SoundCloud Usage](#soundcloud-usage)
116
+ - [5.6 General Video Usage](#general-video-usage)
117
+ - [5.7 General Audio Usage](#general-audio-usage)
115
118
  - [6. Hybrid HTML with Markdown](#6-hybrid-html-with-markdown)
116
119
  - [7. Markdown Polyfill](#7-markdown-polyfill)
117
120
  - [7.1 Escape Ordered List](#71-escape-ordered-list)
@@ -143,7 +146,7 @@ plugins:
143
146
 
144
147
  **💡 Tip:** Note that GitHub Pages runs in `safe` mode and only allows [a set of whitelisted plugins](https://pages.github.com/versions/). To use the gem in GitHub Pages, you need to build locally or use CI (e.g. [travis](https://travis-ci.org/), [github workflow](https://help.github.com/en/actions/configuring-and-managing-workflows/configuring-a-workflow)) and deploy to your `gh-pages` branch.
145
148
 
146
- ### Additions
149
+ ### Additions for Unlimited GitHub Pages
147
150
 
148
151
  * Here is a GitHub Action named [jekyll-deploy-action](https://github.com/jeffreytse/jekyll-deploy-action) for Jekyll site deployment conveniently. 👍
149
152
  * Here is a [Jekyll site](https://github.com/jeffreytse/jekyll-jeffreytse-blog) using Travis to build and deploy to GitHub Pages for your references.
@@ -162,16 +165,20 @@ jekyll-spaceship:
162
165
  - plantuml-processor
163
166
  - mermaid-processor
164
167
  - polyfill-processor
165
- - video-processor
168
+ - media-processor
166
169
  - emoji-processor
167
170
  - element-processor
168
171
  mathjax-processor:
169
- src: //cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML
172
+ src:
173
+ - https://polyfill.io/v3/polyfill.min.js?features=es6
174
+ - https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js
170
175
  config:
171
- tex2jax:
176
+ tex:
172
177
  inlineMath:
173
178
  - ['$','$']
174
179
  - ['\(','\)']
180
+ svg:
181
+ fontCache: 'global'
175
182
  plantuml-processor:
176
183
  mode: default # mode value 'pre-fetch' for fetching image at building stage
177
184
  css:
@@ -179,7 +186,7 @@ jekyll-spaceship:
179
186
  syntax:
180
187
  code: 'plantuml!'
181
188
  custom: ['@startuml', '@enduml']
182
- src: http://www.plantuml.com/plantuml/png/
189
+ src: http://www.plantuml.com/plantuml/svg/
183
190
  mermaid-processor:
184
191
  mode: default # mode value 'pre-fetch' for fetching image at building stage
185
192
  css:
@@ -190,14 +197,14 @@ jekyll-spaceship:
190
197
  config:
191
198
  theme: default
192
199
  src: https://mermaid.ink/svg/
193
- video-processor:
200
+ media-processor:
194
201
  default:
195
- id: 'video-{id}'
196
- class: 'video'
202
+ id: 'media-{id}'
203
+ class: 'media'
197
204
  width: '100%'
198
205
  height: 350
199
- border: 0
200
- style: 'max-width: 600px'
206
+ frameborder: 0
207
+ style: 'max-width: 600px; outline: none;'
201
208
  allow: 'encrypted-media; picture-in-picture'
202
209
  emoji-processor:
203
210
  css:
@@ -630,7 +637,7 @@ Code above would be parsed as:
630
637
 
631
638
  ### 3. PlantUML Usage
632
639
 
633
- [PlantUML](http://plantuml.sourceforge.net/) is a component that allows to quickly write:
640
+ [PlantUML](https://plantuml.com) is a component that allows to quickly write:
634
641
 
635
642
  - sequence diagram,
636
643
  - use case diagram,
@@ -701,25 +708,31 @@ Code above would be parsed as:
701
708
 
702
709
  ![Mermaid Diagram](https://user-images.githubusercontent.com/9413601/85282355-2e317300-b4be-11ea-9c30-8f9d61540d14.png)
703
710
 
704
- ### 5. Video Usage
711
+ ### 5. Media Usage
705
712
 
706
- How often did you find yourself googling "**How to embed a video in markdown?**"
713
+ How often did you find yourself googling "**How to embed a video/audio in markdown?**"
707
714
 
708
- While its not possible to embed a video in markdown, the best and easiest way is to extract a frame from the video. To add videos to your markdown files easier I developped this tool for you, and it will parse the video link inside the image block automatically.
715
+ While its not possible to embed a video/audio in markdown, the best and easiest
716
+ way is to extract a frame from the video/audio. To add videos/audios to your
717
+ markdown files easier I developped this tool for you, and it will parse the
718
+ video/audio link inside the image block automatically.
709
719
 
710
- **For now, these video links parsing are provided:**
720
+ **For now, these media links parsing are provided:**
711
721
 
712
722
  - Youtube
713
723
  - Vimeo
714
724
  - DailyMotion
715
- - General Video ( mp4 | avi | webm | ogg | ogv | 3gp | flv | mov ... )
725
+ - Spotify
726
+ - SoundCloud
727
+ - General Video ( mp4 | avi | ogg | ogv | webm | 3gp | flv | mov ... )
728
+ - General Audio ( mp3 | wav | ogg | mid | midi | aac | wma ... )
716
729
 
717
- There are two ways to embed a video in your Jekyll blog page:
730
+ There are two ways to embed a video/audio in your Jekyll blog page:
718
731
 
719
732
  Inline-style:
720
733
 
721
734
  ```markdown
722
- ![]({video-link})
735
+ ![]({media-link})
723
736
  ```
724
737
 
725
738
  Reference-style:
@@ -727,10 +740,10 @@ Reference-style:
727
740
  ```markdown
728
741
  ![][{reference}]
729
742
 
730
- [{reference}]: {video-link}
743
+ [{reference}]: {media-link}
731
744
  ```
732
745
 
733
- For configuring video attributes (e.g, width, height), just adding query string to
746
+ For configuring media attributes (e.g, width, height), just adding query string to
734
747
  the link as below:
735
748
 
736
749
  ```markdown
@@ -763,6 +776,22 @@ the link as below:
763
776
  ![](https://dai.ly/x7tgcev?width=100%&height=400)
764
777
  ```
765
778
 
779
+ #### Spotify Usage
780
+
781
+ ```markdown
782
+ ![](http://open.spotify.com/track/4Dg5moVCTqxAb7Wr8Dq2T5)
783
+ ```
784
+
785
+ <image width="600" src="https://user-images.githubusercontent.com/9413601/89762618-5d11b000-db23-11ea-81db-35cc3682b234.png">
786
+
787
+ #### SoundCloud Usage
788
+
789
+ ```markdown
790
+ ![](https://soundcloud.com/aviciiofficial/preview-avicii-vs-lenny)
791
+ ```
792
+
793
+ <image width="600" src="https://user-images.githubusercontent.com/9413601/89762969-1c666680-db24-11ea-97e3-4340f7fac7ac.png">
794
+
766
795
  #### General Video Usage
767
796
 
768
797
  ```markdown
@@ -773,6 +802,15 @@ the link as below:
773
802
  ![](//techslides.com/demos/sample-videos/small.mp4?width=400)
774
803
  ```
775
804
 
805
+ #### General Audio Usage
806
+
807
+ ```markdown
808
+ ![](//www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3)
809
+
810
+ ![](//www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3?autoplay=1&loop=1)
811
+ ```
812
+
813
+ <image width="300" src="https://user-images.githubusercontent.com/9413601/89762143-68181080-db22-11ea-8467-e8b2a8a96ae5.png">
776
814
 
777
815
  ### 6. Hybrid HTML with Markdown
778
816
 
@@ -928,7 +966,7 @@ Automatically adds a `target="_blank" rel="noopener noreferrer"` attribute to al
928
966
  jekyll-spaceship:
929
967
  element-processor:
930
968
  css:
931
- - a: # Replce all `a` tags
969
+ - a: # Replace all `a` tags
932
970
  props:
933
971
  class: ['(^.*$)', '\0 ext-link'] # Add `ext-link` to class by regex pattern
934
972
  target: _blank # Replace `target` value to `_blank`
@@ -944,9 +982,9 @@ Automatically adds `loading="lazy"` to `img` and `iframe` tags to natively load
944
982
  jekyll-spaceship:
945
983
  element-processor:
946
984
  css:
947
- - a: # Replce all `a` tags
985
+ - a: # Replace all `a` tags
948
986
  props: #
949
- loading: lazy # Replace `lading` value to `lazy`
987
+ loading: lazy # Replace `loading` value to `lazy`
950
988
  ```
951
989
 
952
990
  In case you want to prevent loading some images/iframes lazily, add
@@ -959,7 +997,7 @@ See the following examples to prevent lazy loading.
959
997
  jekyll-spaceship:
960
998
  element-processor:
961
999
  css:
962
- - a: # Replce all `a` tags
1000
+ - a: # Replace all `a` tags
963
1001
  props: #
964
1002
  loading: eager # Replace `loading` value to `eager`
965
1003
  ```
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.version = Jekyll::Spaceship::VERSION
10
10
  spec.authors = ["jeffreytse"]
11
11
  spec.email = ["jeffreytse.mail@gmail.com"]
12
- spec.summary = "A Jekyll plugin to provide powerful supports for table, mathjax, plantuml, mermaid, emoji, video, youtube, vimeo, dailymotion, etc."
12
+ spec.summary = "A Jekyll plugin to provide powerful supports for table, mathjax, plantuml, mermaid, emoji, video, audio, youtube, vimeo, dailymotion, spotify, soundcloud, etc."
13
13
  spec.homepage = "https://github.com/jeffreytse/jekyll-spaceship"
14
14
  spec.license = "MIT"
15
15
 
@@ -10,7 +10,7 @@ module Jekyll::Spaceship
10
10
  'plantuml-processor',
11
11
  'mermaid-processor',
12
12
  'polyfill-processor',
13
- 'video-processor',
13
+ 'media-processor',
14
14
  'emoji-processor',
15
15
  'element-processor'
16
16
  ]
@@ -116,7 +116,7 @@ module Jekyll::Spaceship
116
116
  if self.respond_to? method
117
117
  @page.content = self.pre_exclude @page.content
118
118
  @page.content = self.send method, @page.content
119
- @page.content = self.after_exclude @page.content
119
+ @page.content = self.post_exclude @page.content
120
120
  end
121
121
  else
122
122
  if Type.html? output_ext
@@ -151,8 +151,8 @@ module Jekyll::Spaceship
151
151
  logger.log file
152
152
  end
153
153
 
154
- def pre_exclude(content)
155
- @exclusion_store = []
154
+ def exclusion_regexs()
155
+ regexs = []
156
156
  @exclusions.each do |type|
157
157
  regex = nil
158
158
  if type == :code
@@ -160,9 +160,16 @@ module Jekyll::Spaceship
160
160
  elsif type == :math
161
161
  regex = /(((?<!\\)\${1,2})[^\n]*?\1)/
162
162
  elsif type == :liquid_filter
163
- regex = /((?<!\\)\{\{[^\n]*?\}\})/
163
+ regex = /((?<!\\)((\{\{[^\n]*?\}\})|(\{%[^\n]*?%\})))/
164
164
  end
165
- next if regex.nil?
165
+ regexs.push regex unless regex.nil?
166
+ end
167
+ regexs
168
+ end
169
+
170
+ def pre_exclude(content, regexs = self.exclusion_regexs())
171
+ @exclusion_store = []
172
+ regexs.each do |regex|
166
173
  content.scan(regex) do |match_data|
167
174
  match = match_data[0]
168
175
  id = @exclusion_store.size
@@ -173,7 +180,7 @@ module Jekyll::Spaceship
173
180
  content
174
181
  end
175
182
 
176
- def after_exclude(content)
183
+ def post_exclude(content)
177
184
  while @exclusion_store.size > 0
178
185
  match = @exclusion_store.pop
179
186
  id = @exclusion_store.size
@@ -192,5 +199,38 @@ module Jekyll::Spaceship
192
199
  end
193
200
  content
194
201
  end
202
+
203
+ def self.fetch_img_data(url)
204
+ begin
205
+ res = Net::HTTP.get_response URI(url)
206
+ raise res.body unless res.is_a?(Net::HTTPSuccess)
207
+ content_type = res.header['Content-Type']
208
+ raise 'Unknown content type!' if content_type.nil?
209
+ content_body = res.body.force_encoding('UTF-8')
210
+ return {
211
+ 'type' => content_type,
212
+ 'body' => content_body
213
+ }
214
+ rescue StandardError => msg
215
+ logger.log msg
216
+ end
217
+ end
218
+
219
+ def self.make_img_tag(data)
220
+ css_class = data['class']
221
+ type = data['type']
222
+ body = data['body']
223
+ if type == 'url'
224
+ "<img class=\"#{css_class}\" src=\"#{body}\">"
225
+ elsif type.include?('svg')
226
+ body.gsub(/\<\?xml.*?\?>/, '')
227
+ .gsub(/<!--[^\0]*?-->/, '')
228
+ .sub(/<svg /, "<svg class=\"#{css_class}\" ")
229
+ else
230
+ body = Base64.encode64(body)
231
+ body = "data:#{type};base64, #{body}"
232
+ "<img class=\"#{css_class}\" src=\"#{body}\">"
233
+ end
234
+ end
195
235
  end
196
236
  end
@@ -6,9 +6,13 @@ module Jekyll::Spaceship
6
6
  class MathjaxProcessor < Processor
7
7
  def self.config
8
8
  {
9
- 'src' => '//cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML',
9
+ 'src' => [
10
+ 'https://polyfill.io/v3/polyfill.min.js?features=es6',
11
+ 'https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js',
12
+ ],
10
13
  'config' => {
11
- 'tex2jax' => { 'inlineMath' => [['$','$'], ['\\(','\\)']] }
14
+ 'tex' => { 'inlineMath' => [['$','$'], ['\\(','\\)']] },
15
+ 'svg': { 'fontCache': 'global' }
12
16
  }
13
17
  }
14
18
  end
@@ -27,8 +31,15 @@ module Jekyll::Spaceship
27
31
 
28
32
  self.handled = true
29
33
 
30
- cfg = "MathJax.Hub.Config(#{config['config'].to_json});"
31
- head.add_child("<script src=\"#{config['src']}\">#{cfg}</script>")
34
+ # add mathjax config
35
+ cfg = config['config'].to_json
36
+ head.add_child("<script>MathJax=#{cfg}</script>")
37
+
38
+ # add mathjax dependencies
39
+ config['src'] = [config['src']] if config['src'].is_a? String
40
+ config['src'].each do |src|
41
+ head.add_child("<script src=\"#{src}\"></script>")
42
+ end
32
43
 
33
44
  doc.to_html
34
45
  end
@@ -0,0 +1,225 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'uri'
4
+ require "nokogiri"
5
+
6
+ module Jekyll::Spaceship
7
+ class MediaProcessor < Processor
8
+ def self.config
9
+ {
10
+ 'default' => {
11
+ 'id' => 'media-{id}',
12
+ 'class' => 'media',
13
+ 'width' => '100%',
14
+ 'height' => 350,
15
+ 'frameborder' => 0,
16
+ 'style' => 'max-width: 600px;outline: none',
17
+ 'allow' => 'encrypted-media; picture-in-picture'
18
+ }
19
+ }
20
+ end
21
+
22
+ def on_handle_html(content)
23
+ # use nokogiri to parse html content
24
+ doc = Nokogiri::HTML(content)
25
+ # handle each img tag
26
+ doc.css('img').each do |element|
27
+ handle_normal_audio(element)
28
+ handle_normal_video(element)
29
+ handle_youtube(element)
30
+ handle_vimeo(element)
31
+ handle_dailymotion(element)
32
+ handle_spotify(element)
33
+ handle_soundcloud(element)
34
+ end
35
+ doc.to_html
36
+ end
37
+
38
+ # Examples:
39
+ # ![audio](//www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3)
40
+ # ![audio](//www.expample.com/examples/t-rex-roar.mp3?autoplay=true&loop=true)
41
+ def handle_normal_audio(element)
42
+ handle_media(element, {
43
+ media_type: 'audio',
44
+ host: '(https?:\\/\\/)?.*\\/',
45
+ id: '(.+?\\.(mp3|wav|ogg|mid|midi|aac|wma))',
46
+ })
47
+ end
48
+
49
+
50
+ # Examples:
51
+ # ![video](//www.html5rocks.com/en/tutorials/video/basics/devstories.webm)
52
+ # ![video](//techslides.com/demos/sample-videos/small.ogv?allow=autoplay)
53
+ # ![video](//techslides.com/demos/sample-videos/small.mp4?width=400)
54
+ def handle_normal_video(element)
55
+ handle_media(element, {
56
+ media_type: 'iframe',
57
+ host: '(https?:\\/\\/)?.*\\/',
58
+ id: '(.+?\\.(avi|mp4|webm|ogg|ogv|flv|mkv|mov|wmv|3gp|rmvb|asf))'
59
+ })
60
+ end
61
+
62
+ # Examples:
63
+ # ![youtube](https://www.youtube.com/watch?v=XA2WjJbmmoM "title")
64
+ # ![youtube](http://www.youtube.com/embed/w-m_yZCLF5Q)
65
+ # ![youtube](//youtu.be/mEP3YXaSww8?height=100%&width=400)
66
+ def handle_youtube(element)
67
+ handle_media(element, {
68
+ media_type: 'iframe',
69
+ host: '(https?:)?\\/\\/.*youtu.*',
70
+ id: '(?<=\\?v\\=|embed\\/|\\.be\\/)([a-zA-Z0-9\\_\\-]+)',
71
+ base_url: "https://www.youtube.com/embed/"
72
+ })
73
+ end
74
+
75
+ # Examples:
76
+ # ![vimeo](https://vimeo.com/263856289)
77
+ # ![vimeo](https://vimeo.com/263856289?height=100%&width=400)
78
+ def handle_vimeo(element)
79
+ handle_media(element, {
80
+ media_type: 'iframe',
81
+ host: '(https?:)?\\/\\/vimeo\\.com\\/',
82
+ id: '([0-9]+)',
83
+ base_url: "https://player.vimeo.com/video/"
84
+ })
85
+ end
86
+
87
+ # Examples:
88
+ # ![dailymotion](https://www.dailymotion.com/video/x7tgcev)
89
+ # ![dailymotion](https://dai.ly/x7tgcev?height=100%&width=400)
90
+ def handle_dailymotion(element)
91
+ handle_media(element, {
92
+ media_type: 'iframe',
93
+ host: '(https?:)?\\/\\/.*dai.?ly.*',
94
+ id: '(?<=video\\/|\\/)([a-zA-Z0-9\\_\\-]+)',
95
+ base_url: "https://www.dailymotion.com/embed/video/"
96
+ })
97
+ end
98
+
99
+ # Examples:
100
+ # ![spotify](//open.spotify.com/track/4Dg5moVCTqxAb7Wr8Dq2T5)
101
+ # ![spotify](//open.spotify.com/track/37mEkAaqCE7FXMvnlVA8pp?width=400)
102
+ def handle_spotify(element)
103
+ handle_media(element, {
104
+ media_type: 'iframe',
105
+ host: '(https?:)?\\/\\/open\\.spotify\\.com\\/track\\/',
106
+ id: '(?<=track\\/)([a-zA-Z0-9\\_\\-]+)',
107
+ base_url: "https://open.spotify.com/embed/track/",
108
+ height: 80
109
+ })
110
+ end
111
+
112
+ # Examples:
113
+ # ![soundcloud](//soundcloud.com/aviciiofficial/preview-avicii-vs-lenny)
114
+ def handle_soundcloud(element)
115
+ handle_media(element, {
116
+ media_type: 'iframe',
117
+ id_from: 'html',
118
+ host: '(https?:)?\\/\\/soundcloud\\.com\\/.+\\/[^\\?]+',
119
+ id: '(?<=soundcloud:\\/\\/sounds:)([0-9]+)',
120
+ base_url: "https://w.soundcloud.com/player/?url="\
121
+ "https%3A//api.soundcloud.com/tracks/",
122
+ height: 125,
123
+ })
124
+ end
125
+
126
+ def handle_media(element, data)
127
+ host = data[:host]
128
+ src = element.get_attribute('src')
129
+ title = element.get_attribute('title')
130
+ id = data[:id_from] === 'html' ? '()' : data[:id]
131
+ match_data = src.match(/#{host}#{id}\S*/)
132
+ return if match_data.nil?
133
+
134
+ media_type = data[:media_type]
135
+ base_url = data[:base_url]
136
+ id = data[:id_from] === 'html' \
137
+ ? get_id_from_html(src, data[:id]) \
138
+ : match_data[2]
139
+ qs = src.match(/(?<=\?)(\S*?)$/)
140
+ qs = Hash[URI.decode_www_form(qs.to_s)].reject do |k, v|
141
+ next true if v == id or v == ''
142
+ end
143
+
144
+ cfg = self.config['default'].clone
145
+ cfg['id'] = qs['id'] || cfg['id']
146
+ cfg['class'] = qs['class'] || cfg['class']
147
+ cfg['style'] = qs['style'] || cfg['style']
148
+ cfg['id'] = cfg['id'].gsub('{id}', id)
149
+ cfg['class'] = cfg['class'].gsub('{id}', id)
150
+
151
+ cfg['src'] = URI(base_url ? "#{base_url}#{id}" : src).tap do |v|
152
+ v.query = URI.encode_www_form(qs) if qs.size > 0
153
+ end
154
+
155
+ case media_type
156
+ when 'audio'
157
+ cfg['autoplay'] = qs['autoplay'] || data[:autoplay] || cfg['autoplay']
158
+ cfg['loop'] = qs['loop'] || data[:loop] || cfg['loop']
159
+ cfg['style'] += ';display: none;' if qs['hidden']
160
+ handle_audio(element, { cfg: cfg })
161
+ when 'iframe'
162
+ cfg['title'] = title
163
+ cfg['width'] = qs['width'] || data[:width] || cfg['width']
164
+ cfg['height'] = qs['height'] || data[:height] || cfg['height']
165
+ cfg['frameborder'] = qs['frameborder'] || cfg['frameborder']
166
+ cfg['allow'] ||= cfg['allow']
167
+ handle_iframe(element, { cfg: cfg })
168
+ end
169
+ self.handled = true
170
+ end
171
+
172
+ def handle_audio(element, data)
173
+ cfg = data[:cfg]
174
+ html = "<audio"\
175
+ " id=\"#{cfg['id']}\""\
176
+ " class=\"#{cfg['class']}\""\
177
+ " #{cfg['autoplay'] ? 'autoplay' : ''}"\
178
+ " #{cfg['loop'] ? 'loop' : ''}"\
179
+ " src=\"#{cfg['src']}\""\
180
+ " style=\"#{cfg['style']}\""\
181
+ " controls>" \
182
+ "<p> Your browser doesn't support HTML5 audio."\
183
+ " Here is a <a href=\"#{cfg['src']}\">link to download the audio</a>"\
184
+ "instead. </p>"\
185
+ "</audio>"
186
+ doc = Nokogiri::XML(html)
187
+ element.replace(doc.children.first)
188
+ end
189
+
190
+ def handle_iframe(element, data)
191
+ cfg = data[:cfg]
192
+ html = "<iframe"\
193
+ " id=\"#{cfg['id']}\""\
194
+ " class=\"#{cfg['class']}\""\
195
+ " src=\"#{cfg['src']}\""\
196
+ " title=\"#{cfg['title']}\""\
197
+ " width=\"#{cfg['width']}\""\
198
+ " height=\"#{cfg['height']}\""\
199
+ " style=\"#{cfg['style']}\""\
200
+ " allow=\"#{cfg['allow']}\""\
201
+ " frameborder=\"#{cfg['frameborder']}\""\
202
+ " allowfullscreen>"\
203
+ "</iframe>"
204
+ doc = Nokogiri::XML(html)
205
+ element.replace(doc.children.first)
206
+ end
207
+
208
+ def get_id_from_html(url, pattern)
209
+ id = ''
210
+ begin
211
+ url = 'https:' + url if url.start_with? '//'
212
+ res = Net::HTTP.get_response URI(url)
213
+ raise res.body unless res.is_a?(Net::HTTPSuccess)
214
+ res.body.match pattern do |match_data|
215
+ id = match_data[0]
216
+ break
217
+ end
218
+ rescue StandardError => msg
219
+ data = url
220
+ logger.log msg
221
+ end
222
+ id
223
+ end
224
+ end
225
+ end
@@ -62,18 +62,20 @@ module Jekyll::Spaceship
62
62
  def handle_mermaid(code)
63
63
  # encode to UTF-8
64
64
  code = code.encode('UTF-8')
65
-
66
65
  url = get_url(code)
67
66
 
68
67
  # render mode
69
68
  case self.config['mode']
70
69
  when 'pre-fetch'
71
- url = self.get_mermaid_img_data(url)
70
+ data = self.class.fetch_img_data(url)
71
+ end
72
+ if data.nil?
73
+ data = { 'type' => 'url', 'body' => url }
72
74
  end
73
75
 
74
76
  # return img tag
75
- css_class = self.config['css']['class']
76
- "<img class=\"#{css_class}\" src=\"#{url}\">"
77
+ data['class'] = self.config['css']['class']
78
+ self.class.make_img_tag(data)
77
79
  end
78
80
 
79
81
  def get_url(code)
@@ -96,21 +98,5 @@ module Jekyll::Spaceship
96
98
  raise "No supported src ! #{src}"
97
99
  end
98
100
  end
99
-
100
- def get_mermaid_img_data(url)
101
- data = ''
102
- begin
103
- res = Net::HTTP.get_response URI(url)
104
- raise res.body unless res.is_a?(Net::HTTPSuccess)
105
- data = Base64.encode64(res.body)
106
- content_type = res.header['Content-Type']
107
- raise 'Unknown content type!' if content_type.nil?
108
- data = "data:#{content_type};base64, #{data}"
109
- rescue StandardError => msg
110
- data = url
111
- logger.log msg
112
- end
113
- data
114
- end
115
101
  end
116
102
  end
@@ -17,7 +17,7 @@ module Jekyll::Spaceship
17
17
  'css' => {
18
18
  'class' => 'plantuml'
19
19
  },
20
- 'src' => 'http://www.plantuml.com/plantuml/png/'
20
+ 'src' => 'http://www.plantuml.com/plantuml/svg/'
21
21
  }
22
22
  end
23
23
 
@@ -59,18 +59,20 @@ module Jekyll::Spaceship
59
59
  def handle_plantuml(code)
60
60
  # wrap plantuml code
61
61
  code = "@startuml#{code}@enduml".encode('UTF-8')
62
-
63
- url = get_url(code)
62
+ url = self.get_url(code)
64
63
 
65
64
  # render mode
66
65
  case self.config['mode']
67
66
  when 'pre-fetch'
68
- url = self.get_plantuml_img_data(url)
67
+ data = self.class.fetch_img_data(url)
68
+ end
69
+ if data.nil?
70
+ data = { 'type' => 'url', 'body' => url }
69
71
  end
70
72
 
71
73
  # return img tag
72
- css_class = self.config['css']['class']
73
- "<img class=\"#{css_class}\" src=\"#{url}\">"
74
+ data['class'] = self.config['css']['class']
75
+ self.class.make_img_tag(data)
74
76
  end
75
77
 
76
78
  def get_url(code)
@@ -87,21 +89,5 @@ module Jekyll::Spaceship
87
89
  raise "No supported src ! #{src}"
88
90
  end
89
91
  end
90
-
91
- def get_plantuml_img_data(url)
92
- data = ''
93
- begin
94
- res = Net::HTTP.get_response URI(url)
95
- raise res.body unless res.is_a?(Net::HTTPSuccess)
96
- data = Base64.encode64(res.body)
97
- content_type = res.header['Content-Type']
98
- raise 'Unknown content type!' if content_type.nil?
99
- data = "data:#{content_type};base64, #{data}"
100
- rescue StandardError => msg
101
- data = url
102
- logger.log msg
103
- end
104
- data
105
- end
106
92
  end
107
93
  end
@@ -305,10 +305,12 @@ module Jekyll::Spaceship
305
305
  cvter = self.converter('markdown')
306
306
  return if cvter.nil?
307
307
  content = cell.inner_html
308
+ content = self.pre_exclude(content, [/(\<code.*\>.*\<\/code\>)/])
308
309
  .gsub(/(?<!\\)\|/, '\\|')
309
310
  .gsub(/^\s+|\s+$/, '')
310
311
  .gsub(/&lt;/, '<')
311
312
  .gsub(/&gt;/, '>')
313
+ content = self.post_exclude(content)
312
314
  content = cvter.convert(content)
313
315
  content = Nokogiri::HTML.fragment(content)
314
316
  if content.children.first&.name == 'p'
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Jekyll
4
4
  module Spaceship
5
- VERSION = "0.8.7"
5
+ VERSION = "0.9.4"
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.8.7
4
+ version: 0.9.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - jeffreytse
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-07-30 00:00:00.000000000 Z
11
+ date: 2020-10-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jekyll
@@ -124,6 +124,7 @@ files:
124
124
  - ".codeclimate.yml"
125
125
  - ".github/FUNDING.yml"
126
126
  - ".gitignore"
127
+ - ".rspec"
127
128
  - ".travis.yml"
128
129
  - Gemfile
129
130
  - LICENSE.txt
@@ -140,11 +141,11 @@ files:
140
141
  - lib/jekyll-spaceship/processors/element-processor.rb
141
142
  - lib/jekyll-spaceship/processors/emoji-processor.rb
142
143
  - lib/jekyll-spaceship/processors/mathjax-processor.rb
144
+ - lib/jekyll-spaceship/processors/media-processor.rb
143
145
  - lib/jekyll-spaceship/processors/mermaid-processor.rb
144
146
  - lib/jekyll-spaceship/processors/plantuml-processor.rb
145
147
  - lib/jekyll-spaceship/processors/polyfill-processor.rb
146
148
  - lib/jekyll-spaceship/processors/table-processor.rb
147
- - lib/jekyll-spaceship/processors/video-processor.rb
148
149
  - lib/jekyll-spaceship/utils/.keep
149
150
  - lib/jekyll-spaceship/version.rb
150
151
  - logos/jekyll-spaceship-logo.png
@@ -173,5 +174,6 @@ rubygems_version: 3.0.8
173
174
  signing_key:
174
175
  specification_version: 4
175
176
  summary: A Jekyll plugin to provide powerful supports for table, mathjax, plantuml,
176
- mermaid, emoji, video, youtube, vimeo, dailymotion, etc.
177
+ mermaid, emoji, video, audio, youtube, vimeo, dailymotion, spotify, soundcloud,
178
+ etc.
177
179
  test_files: []
@@ -1,139 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'uri'
4
-
5
- module Jekyll::Spaceship
6
- class VideoProcessor < Processor
7
- def self.config
8
- {
9
- 'default' => {
10
- 'id' => 'video-{id}',
11
- 'class' => 'video',
12
- 'width' => '100%',
13
- 'height' => 350,
14
- 'border' => 0,
15
- 'style' => 'max-width: 600px',
16
- 'allow' => 'encrypted-media; picture-in-picture',
17
- }
18
- }
19
- end
20
-
21
- def on_handle_markdown(content)
22
- content = handle_normal_video(content)
23
- content = handle_youtube(content)
24
- content = handle_vimeo(content)
25
- content = handle_dailymotion(content)
26
- end
27
-
28
- # Examples:
29
- # ![video](//www.html5rocks.com/en/tutorials/video/basics/devstories.webm)
30
- # ![video](//techslides.com/demos/sample-videos/small.ogv?allow=autoplay)
31
- # ![video](//techslides.com/demos/sample-videos/small.mp4?width=400)
32
- def handle_normal_video(content)
33
- handle_video(content, {
34
- host: '(https?:)?\\/\\/.*\\/',
35
- id: '(.+?\\.(avi|mp4|webm|ogg|ogv|flv|mkv|mov|wmv|3gp|rmvb|asf))',
36
- })
37
- end
38
-
39
- # Examples:
40
- # ![youtube](https://www.youtube.com/watch?v=XA2WjJbmmoM "title")
41
- # ![youtube](http://www.youtube.com/embed/w-m_yZCLF5Q)
42
- # ![youtube](//youtu.be/mEP3YXaSww8?height=100%&width=400)
43
- def handle_youtube(content)
44
- handle_video(content, {
45
- host: '(https?:)?\\/\\/.*youtu.*',
46
- id: '(?<=\\?v\\=|embed\\/|\\.be\\/)([a-zA-Z0-9\\_\\-]+)',
47
- iframe_url: "https://www.youtube.com/embed/"
48
- })
49
- end
50
-
51
- # Examples:
52
- # ![vimeo](https://vimeo.com/263856289)
53
- # ![vimeo](https://vimeo.com/263856289?height=100%&width=400)
54
- def handle_vimeo(content)
55
- handle_video(content, {
56
- host: '(https?:)?\\/\\/vimeo\\.com\\/',
57
- id: '([0-9]+)',
58
- iframe_url: "https://player.vimeo.com/video/"
59
- })
60
- end
61
-
62
- # Examples:
63
- # ![dailymotion](https://www.dailymotion.com/video/x7tgcev)
64
- # ![dailymotion](https://dai.ly/x7tgcev?height=100%&width=400)
65
- def handle_dailymotion(content)
66
- handle_video(content, {
67
- host: '(https?:)?\\/\\/.*dai.?ly.*',
68
- id: '(?<=video\\/|\\/)([a-zA-Z0-9\\_\\-]+)',
69
- iframe_url: "https://www.dailymotion.com/embed/video/"
70
- })
71
- end
72
-
73
- def handle_video(content, data)
74
- host = data[:host]
75
- return content if content.sub(/#{host}/, '').nil?
76
-
77
- iframe_url = data[:iframe_url]
78
- id = data[:id]
79
- url = "(#{host}#{id}\\S*)"
80
- title = '("(.*)".*){0,1}'
81
-
82
- # pre-handle reference-style links
83
- regex = /(\[(.*)\]:\s*(#{url}\s*#{title}))/
84
- content.scan regex do |match_data|
85
- match = match_data[0]
86
- ref_name = match_data[1]
87
- ref_value = match_data[2]
88
- content = content.gsub(match, '')
89
- .gsub(/\!\[(.*)\]\s*\[#{ref_name}\]/,
90
- "![\1](#{ref_value})")
91
- end
92
-
93
- # handle inline-style links
94
- regex = /(\!\[(.*)\]\(.*#{url}\s*#{title}\))/
95
- content.scan regex do |match_data|
96
- url = match_data[2]
97
- id = match_data[4]
98
- title = match_data[6]
99
- qs = url.match(/(?<=\?)(\S*?)$/)
100
- qs = Hash[URI.decode_www_form(qs.to_s)].reject do |k, v|
101
- next true if v == id or v == ''
102
- end
103
-
104
- default = self.config['default']
105
- css_id = qs['id'] || default['id']
106
- css_class = qs['class'] || default['class']
107
- width = qs['width'] || data[:width] || default['width']
108
- height = qs['height'] || data[:height] || default['height']
109
- frameborder = qs['frameborder'] || default['border']
110
- style = qs['style'] || default['style']
111
- allow = qs['allow'] || default['allow']
112
-
113
- css_id = css_id.gsub('{id}', id)
114
- css_class = css_class.gsub('{id}', id)
115
-
116
- url = URI(iframe_url ? "#{iframe_url}#{id}" : url).tap do |v|
117
- v.query = URI.encode_www_form(qs) if qs.size > 0
118
- end
119
-
120
- html = "<iframe"\
121
- " id=\"#{css_id}\""\
122
- " class=\"#{css_class}\""\
123
- " src=\"#{url}\""\
124
- " title=\"#{title}\""\
125
- " width=\"#{width}\""\
126
- " height=\"#{height}\""\
127
- " style=\"#{style}\""\
128
- " allow=\"#{allow}\""\
129
- " frameborder=\"#{frameborder}\""\
130
- " allowfullscreen>" \
131
- "</iframe>"
132
-
133
- content = content.gsub(match_data[0], html)
134
- self.handled = true
135
- end
136
- content
137
- end
138
- end
139
- end