jekyll-spaceship 0.8.6 → 0.9.3

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: 5f3d45fd1335dcec7d9c05900219920869adaa418fd72b29b3fde3fcdfafc14d
4
- data.tar.gz: 2e1fc457586b11bfa8d9fc215ba6c870a3f09ea85a78872d72a8692eeb12abcf
3
+ metadata.gz: 993252decbad6e7d20ed20245f3ba7c7858eb5845402b06605a8b05d6268225f
4
+ data.tar.gz: 45012fc8ca11671a98d36b1e1c6dfbfef67cc1c12f01f265ed507760e96f40fd
5
5
  SHA512:
6
- metadata.gz: 5c2b6900e10b029dbedad643eeb19c4d7a8332003e0bf8079af7c792bef622bc04ff550194e82d1dde365fd54fcd3f4f3997e25c357fac149db1f7eaca6cb414
7
- data.tar.gz: 9a3b141d78a7d22aceea2e7ca8545c44a070303e4241db7f56adc301917d34bc91ff6dfb5e09df7dbf8a1739cb6c2f4a1c36c5f73fbc1a9884667350789c9bba
6
+ metadata.gz: 139508a04521719d9160e2a0cff09a75600dffc5cae80c9dd75ec047495be87a1a7b786b859d5e335df9226d35617aa9e6470a4905fb497799f2c0c9981d6da2
7
+ data.tar.gz: 00b615b28c36a335749d5b3dcd7a60e55b8639b2d86ae8e027243985c939e75333fd4c882ed84999f3de07b43ff07c632db62f88f3641dc4634c744f91a2b279
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:
@@ -571,17 +578,17 @@ Here are some examples for span IALs:
571
578
  Here is an example for custom table cell with IAL:
572
579
 
573
580
  ```markdown
574
- {:color-style: style="background: black;" }
575
- {:color-style: style="color: white;" }
576
- {:font-style: style="font-weight: 800;" }
581
+ {:color-style: style="background: black;"}
582
+ {:color-style: style="color: white;"}
583
+ {:text-style: style="font-weight: 800; text-decoration: underline;"}
577
584
 
578
585
  |: Here's an Inline Attribute Lists example :||||
579
- | ------- | ------------------------- | -------------------- | ----------- |
586
+ | ------- | ------------------ | -------------------- | ------------------ |
580
587
  |: :|: <div style="color: red;"> &lt; Normal HTML Block > </div> :|||
581
588
  | ^^ | Red {: .cls style="background: orange" } |||
582
589
  | ^^ IALs | Green {: #id style="background: green; color: white" } |||
583
590
  | ^^ | Blue {: style="background: blue; color: white" } |||
584
- | ^^ | Black {: color-style font-weight} |||
591
+ | ^^ | Black {: color-style text-style } |||
585
592
  ```
586
593
 
587
594
  Code above would be parsed as:
@@ -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
  ]
@@ -69,7 +69,7 @@ module Jekyll::Spaceship
69
69
  end
70
70
 
71
71
  def self.ext(page)
72
- ext = page.path.match(/\.\S+$/)
72
+ ext = page.path.match(/\.[^.]+$/)
73
73
  ext.to_s.rstrip
74
74
  end
75
75
 
@@ -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,234 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'uri'
4
+
5
+ module Jekyll::Spaceship
6
+ class MediaProcessor < Processor
7
+ def self.config
8
+ {
9
+ 'default' => {
10
+ 'id' => 'media-{id}',
11
+ 'class' => 'media',
12
+ 'width' => '100%',
13
+ 'height' => 350,
14
+ 'frameborder' => 0,
15
+ 'style' => 'max-width: 600px;outline: none',
16
+ 'allow' => 'encrypted-media; picture-in-picture'
17
+ }
18
+ }
19
+ end
20
+
21
+ def on_handle_markdown(content)
22
+ content = handle_normal_audio(content)
23
+ content = handle_normal_video(content)
24
+ content = handle_youtube(content)
25
+ content = handle_vimeo(content)
26
+ content = handle_dailymotion(content)
27
+ content = handle_spotify(content)
28
+ content = handle_soundcloud(content)
29
+ end
30
+
31
+ # Examples:
32
+ # ![audio](//www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3)
33
+ # ![audio](//www.expample.com/examples/t-rex-roar.mp3?autoplay=true&loop=true)
34
+ def handle_normal_audio(content)
35
+ handle_media(content, {
36
+ media_type: 'audio',
37
+ host: '(https?:)?\\/\\/.*\\/',
38
+ id: '(.+?\\.(mp3|wav|ogg|mid|midi|aac|wma))',
39
+ })
40
+ end
41
+
42
+
43
+ # Examples:
44
+ # ![video](//www.html5rocks.com/en/tutorials/video/basics/devstories.webm)
45
+ # ![video](//techslides.com/demos/sample-videos/small.ogv?allow=autoplay)
46
+ # ![video](//techslides.com/demos/sample-videos/small.mp4?width=400)
47
+ def handle_normal_video(content)
48
+ handle_media(content, {
49
+ media_type: 'iframe',
50
+ host: '(https?:)?\\/\\/.*\\/',
51
+ id: '(.+?\\.(avi|mp4|webm|ogg|ogv|flv|mkv|mov|wmv|3gp|rmvb|asf))'
52
+ })
53
+ end
54
+
55
+ # Examples:
56
+ # ![youtube](https://www.youtube.com/watch?v=XA2WjJbmmoM "title")
57
+ # ![youtube](http://www.youtube.com/embed/w-m_yZCLF5Q)
58
+ # ![youtube](//youtu.be/mEP3YXaSww8?height=100%&width=400)
59
+ def handle_youtube(content)
60
+ handle_media(content, {
61
+ media_type: 'iframe',
62
+ host: '(https?:)?\\/\\/.*youtu.*',
63
+ id: '(?<=\\?v\\=|embed\\/|\\.be\\/)([a-zA-Z0-9\\_\\-]+)',
64
+ base_url: "https://www.youtube.com/embed/"
65
+ })
66
+ end
67
+
68
+ # Examples:
69
+ # ![vimeo](https://vimeo.com/263856289)
70
+ # ![vimeo](https://vimeo.com/263856289?height=100%&width=400)
71
+ def handle_vimeo(content)
72
+ handle_media(content, {
73
+ media_type: 'iframe',
74
+ host: '(https?:)?\\/\\/vimeo\\.com\\/',
75
+ id: '([0-9]+)',
76
+ base_url: "https://player.vimeo.com/video/"
77
+ })
78
+ end
79
+
80
+ # Examples:
81
+ # ![dailymotion](https://www.dailymotion.com/video/x7tgcev)
82
+ # ![dailymotion](https://dai.ly/x7tgcev?height=100%&width=400)
83
+ def handle_dailymotion(content)
84
+ handle_media(content, {
85
+ media_type: 'iframe',
86
+ host: '(https?:)?\\/\\/.*dai.?ly.*',
87
+ id: '(?<=video\\/|\\/)([a-zA-Z0-9\\_\\-]+)',
88
+ base_url: "https://www.dailymotion.com/embed/video/"
89
+ })
90
+ end
91
+
92
+ # Examples:
93
+ # ![spotify](//open.spotify.com/track/4Dg5moVCTqxAb7Wr8Dq2T5)
94
+ # ![spotify](//open.spotify.com/track/37mEkAaqCE7FXMvnlVA8pp?width=400)
95
+ def handle_spotify(content)
96
+ handle_media(content, {
97
+ media_type: 'iframe',
98
+ host: '(https?:)?\\/\\/open\\.spotify\\.com\\/track\\/',
99
+ id: '(?<=track\\/)([a-zA-Z0-9\\_\\-]+)',
100
+ base_url: "https://open.spotify.com/embed/track/",
101
+ height: 80
102
+ })
103
+ end
104
+
105
+ # Examples:
106
+ # ![soundcloud](//soundcloud.com/aviciiofficial/preview-avicii-vs-lenny)
107
+ def handle_soundcloud(content)
108
+ handle_media(content, {
109
+ media_type: 'iframe',
110
+ id_from: 'html',
111
+ host: '(https?:)?\\/\\/soundcloud\\.com\\/.+\\/[^\\?]+',
112
+ id: '(?<=soundcloud:\\/\\/sounds:)([0-9]+)',
113
+ base_url: "https://w.soundcloud.com/player/?url="\
114
+ "https%3A//api.soundcloud.com/tracks/",
115
+ height: 125,
116
+ })
117
+ end
118
+
119
+ def handle_media(content, data)
120
+ host = data[:host]
121
+ return content if content.sub(/#{host}/, '').nil?
122
+
123
+ media_type = data[:media_type]
124
+ base_url = data[:base_url]
125
+ id = data[:id_from] === 'html' ? '()' : data[:id]
126
+ url = "(#{host}#{id}\\S*)"
127
+ title = '("(.*)".*){0,1}'
128
+
129
+ # pre-handle reference-style links
130
+ regex = /(\[(.*)\]:\s*(#{url}\s*#{title}))/
131
+ content.scan regex do |match_data|
132
+ match = match_data[0]
133
+ ref_name = match_data[1]
134
+ ref_value = match_data[2]
135
+ content = content.gsub(match, '')
136
+ .gsub(/\!\[(.*)\]\s*\[#{ref_name}\]/,
137
+ "![\1](#{ref_value})")
138
+ end
139
+
140
+ # handle inline-style links
141
+ regex = /(\!\[(.*)\]\(.*#{url}\s*#{title}\))/
142
+ content.scan regex do |match_data|
143
+ url = match_data[2]
144
+ id = data[:id_from] === 'html' \
145
+ ? get_id_from_html(url, data[:id]) \
146
+ : match_data[4]
147
+ title = match_data[6]
148
+ qs = url.match(/(?<=\?)(\S*?)$/)
149
+ qs = Hash[URI.decode_www_form(qs.to_s)].reject do |k, v|
150
+ next true if v == id or v == ''
151
+ end
152
+
153
+ cfg = self.config['default'].clone
154
+ cfg['id'] = qs['id'] || cfg['id']
155
+ cfg['class'] = qs['class'] || cfg['class']
156
+ cfg['style'] = qs['style'] || cfg['style']
157
+ cfg['id'] = cfg['id'].gsub('{id}', id)
158
+ cfg['class'] = cfg['class'].gsub('{id}', id)
159
+
160
+ cfg['src'] = URI(base_url ? "#{base_url}#{id}" : url).tap do |v|
161
+ v.query = URI.encode_www_form(qs) if qs.size > 0
162
+ end
163
+
164
+ case media_type
165
+ when 'audio'
166
+ cfg['autoplay'] = qs['autoplay'] || data[:autoplay] || cfg['autoplay']
167
+ cfg['loop'] = qs['loop'] || data[:loop] || cfg['loop']
168
+ cfg['style'] += ';display: none;' if qs['hidden']
169
+ content = handle_audio(content, { target: match_data[0], cfg: cfg })
170
+ when 'iframe'
171
+ cfg['title'] = title
172
+ cfg['width'] = qs['width'] || data[:width] || cfg['width']
173
+ cfg['height'] = qs['height'] || data[:height] || cfg['height']
174
+ cfg['frameborder'] = qs['frameborder'] || cfg['frameborder']
175
+ cfg['allow'] ||= cfg['allow']
176
+ content = handle_iframe(content, { target: match_data[0], cfg: cfg })
177
+ end
178
+ self.handled = true
179
+ end
180
+ content
181
+ end
182
+
183
+ def handle_audio(content, data)
184
+ cfg = data[:cfg]
185
+ html = "<audio"\
186
+ " id=\"#{cfg['id']}\""\
187
+ " class=\"#{cfg['class']}\""\
188
+ " #{cfg['autoplay'] ? 'autoplay' : ''}"\
189
+ " #{cfg['loop'] ? 'loop' : ''}"\
190
+ " src=\"#{cfg['src']}\""\
191
+ " style=\"#{cfg['style']}\""\
192
+ " controls>" \
193
+ "<p> Your browser doesn't support HTML5 audio."\
194
+ " Here is a <a href=\"#{cfg['src']}\">link to download the audio</a>"\
195
+ "instead. </p>"\
196
+ "</audio>"
197
+ content.gsub(data[:target], html)
198
+ end
199
+
200
+ def handle_iframe(content, data)
201
+ cfg = data[:cfg]
202
+ html = "<iframe"\
203
+ " id=\"#{cfg['id']}\""\
204
+ " class=\"#{cfg['class']}\""\
205
+ " src=\"#{cfg['src']}\""\
206
+ " title=\"#{cfg['title']}\""\
207
+ " width=\"#{cfg['width']}\""\
208
+ " height=\"#{cfg['height']}\""\
209
+ " style=\"#{cfg['style']}\""\
210
+ " allow=\"#{cfg['allow']}\""\
211
+ " frameborder=\"#{cfg['frameborder']}\""\
212
+ " allowfullscreen>"\
213
+ "</iframe>"
214
+ content.gsub(data[:target], html)
215
+ end
216
+
217
+ def get_id_from_html(url, pattern)
218
+ id = ''
219
+ begin
220
+ url = 'https:' + url if url.start_with? '//'
221
+ res = Net::HTTP.get_response URI(url)
222
+ raise res.body unless res.is_a?(Net::HTTPSuccess)
223
+ res.body.match pattern do |match_data|
224
+ id = match_data[0]
225
+ break
226
+ end
227
+ rescue StandardError => msg
228
+ data = url
229
+ logger.log msg
230
+ end
231
+ id
232
+ end
233
+ end
234
+ 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
@@ -19,7 +19,9 @@ module Jekyll::Spaceship
19
19
  if references.size > 0
20
20
  content.scan(/[^\n]*(?<!\\)\|[^\n]*/) do |result|
21
21
  references.each do |key, val|
22
- replace = result.gsub(/\[([^\n]*)\]\s*\[#{key}\]/, "[\1](#{val})")
22
+ replace = result.gsub(
23
+ /\[([^\n\]]*?)\]\s*\[#{key}\]/,
24
+ "[\1](#{val})")
23
25
  next if result == replace
24
26
  content = content.gsub(result, replace)
25
27
  end
@@ -303,10 +305,12 @@ module Jekyll::Spaceship
303
305
  cvter = self.converter('markdown')
304
306
  return if cvter.nil?
305
307
  content = cell.inner_html
308
+ content = self.pre_exclude(content, [/(\<code.*\>.*\<\/code\>)/])
306
309
  .gsub(/(?<!\\)\|/, '\\|')
307
310
  .gsub(/^\s+|\s+$/, '')
308
311
  .gsub(/&lt;/, '<')
309
312
  .gsub(/&gt;/, '>')
313
+ content = self.post_exclude(content)
310
314
  content = cvter.convert(content)
311
315
  content = Nokogiri::HTML.fragment(content)
312
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.6"
5
+ VERSION = "0.9.3"
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.6
4
+ version: 0.9.3
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-25 00:00:00.000000000 Z
11
+ date: 2020-10-07 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