jekyll-spaceship 0.8.4 → 0.9.1

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: 25f6fbade2f14b20f7a5144628801f0caa203ee2246eb84611e5effc2c2264b6
4
- data.tar.gz: f6ec1d64569913303f51ce4c01c4cd1a57fc1a47da4b01f35721c0737a78d007
3
+ metadata.gz: 989c96c9ba4f7b3d1ec891d43022360ab1bea0a4de2956e8a94c24c927df6ca1
4
+ data.tar.gz: 3aa37c0d529d883e2cef637556d65f65d31e9a5c8ee304ca2a2ee01de11ac527
5
5
  SHA512:
6
- metadata.gz: 4b93d15db0794dc3c70960ad6e5471d5bcd3f90ddb0abb16473b471657483ec9cc9f968bfb237729f3cfe7f546a203fb3924c48a06e68429379bfbd66d343f40
7
- data.tar.gz: ff4bb5fe973f5aaec4aa2eef63bfbd29c1ba8aabad20b9ef316414c088abb3c64387263beb3930d3d0110a7c6e996bf392ff2065a44f19ecf193fd15a9af046e
6
+ metadata.gz: a7bbab4048b639e86cf01e88132c4b9de13acf9651667bcefc15eaaae6c57a3663b69498ebf6172037268ecb63a456a8cf53c751036717f471a8e060a7b5a14b
7
+ data.tar.gz: 56aab57a999fd3604f1b95475662478c8520ab703a9ae2405f863072c92c012cb1dec094814d17d6e1696ce2d3eea7fb0987e78a77a6c7a8465b95db61826702
data/README.md CHANGED
@@ -101,16 +101,20 @@ Spaceship is a minimalistic, powerful and extremely customizable [Jekyll](https:
101
101
  - [1.3 Headerless](#headerless)
102
102
  - [1.4 Cell Alignment](#cell-alignment)
103
103
  - [1.5 Cell Markdown](#cell-markdown)
104
+ - [1.6 Cell Inline Attributes](#cell-inline-attributes)
104
105
  - [2. MathJax Usage](#2-mathjax-usage)
105
106
  - [2.1 Performance Optimization](#21-performance-optimization)
106
107
  - [2.2 How to use?](#22-how-to-use)
107
108
  - [3. PlantUML Usage](#3-plantuml-usage)
108
109
  - [4. Mermaid Usage](#4-mermaid-usage)
109
- - [5. Video Usage](#5-video-usage)
110
+ - [5. Media Usage](#5-media-usage)
110
111
  - [5.1 Youtube Usage](#youtube-usage)
111
112
  - [5.2 Vimeo Usage](#vimeo-usage)
112
113
  - [5.3 DailyMotion Usage](#dailymotion-usage)
113
- - [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)
114
118
  - [6. Hybrid HTML with Markdown](#6-hybrid-html-with-markdown)
115
119
  - [7. Markdown Polyfill](#7-markdown-polyfill)
116
120
  - [7.1 Escape Ordered List](#71-escape-ordered-list)
@@ -161,16 +165,20 @@ jekyll-spaceship:
161
165
  - plantuml-processor
162
166
  - mermaid-processor
163
167
  - polyfill-processor
164
- - video-processor
168
+ - media-processor
165
169
  - emoji-processor
166
170
  - element-processor
167
171
  mathjax-processor:
168
- 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
169
175
  config:
170
- tex2jax:
176
+ tex:
171
177
  inlineMath:
172
178
  - ['$','$']
173
179
  - ['\(','\)']
180
+ svg:
181
+ fontCache: 'global'
174
182
  plantuml-processor:
175
183
  mode: default # mode value 'pre-fetch' for fetching image at building stage
176
184
  css:
@@ -189,14 +197,14 @@ jekyll-spaceship:
189
197
  config:
190
198
  theme: default
191
199
  src: https://mermaid.ink/svg/
192
- video-processor:
200
+ media-processor:
193
201
  default:
194
- id: 'video-{id}'
195
- class: 'video'
202
+ id: 'media-{id}'
203
+ class: 'media'
196
204
  width: '100%'
197
205
  height: 350
198
- border: 0
199
- style: 'max-width: 600px'
206
+ frameborder: 0
207
+ style: 'max-width: 600px; outline: none;'
200
208
  allow: 'encrypted-media; picture-in-picture'
201
209
  emoji-processor:
202
210
  css:
@@ -534,6 +542,61 @@ Rowspan is 4
534
542
  </tbody>
535
543
  </table>
536
544
 
545
+ #### Cell Inline Attributes
546
+
547
+ This feature is very useful for custom cell such as using inline style. (e.g., background, color, font)
548
+ The idea and syntax comes from the [Maruku](http://maruku.rubyforge.org/) package.
549
+
550
+ [](https://kramdown.gettalong.org/syntax.html#block-ials)
551
+
552
+ Following are some examples of attributes definitions (ALDs) and afterwards comes the syntax explanation:
553
+
554
+ ```markdown
555
+ {:ref-name: #id .cls1 .cls2}
556
+ {:second: ref-name #id-of-other title="hallo you"}
557
+ {:other: ref-name second}
558
+ ```
559
+
560
+ An ALD line has the following structure:
561
+
562
+ - a left brace, optionally preceded by up to three spaces,
563
+ - followed by a colon, the id and another colon,
564
+ - followed by attribute definitions (allowed characters are backslash-escaped closing braces or any character except a not escaped closing brace),
565
+ - followed by a closing brace and optional spaces until the end of the line.
566
+
567
+ If there is more than one ALD with the same reference name, the attribute definitions of all the ALDs are processed like they are defined in one ALD.
568
+
569
+ An inline attribute list (IAL) is used to attach attributes to another element.
570
+ Here are some examples for span IALs:
571
+
572
+ ```markdown
573
+ {: #id .cls1 .cls2} <!-- #id <=> id="id", .cls1 .cls2 <=> class="cls1 cls2" -->
574
+ {: ref-name title="hallo you"}
575
+ {: ref-name class='.cls3' .cls4}
576
+ ```
577
+
578
+ Here is an example for custom table cell with IAL:
579
+
580
+ ```markdown
581
+ {:color-style: style="background: black;"}
582
+ {:color-style: style="color: white;"}
583
+ {:text-style: style="font-weight: 800; text-decoration: underline;"}
584
+
585
+ |: Here's an Inline Attribute Lists example :||||
586
+ | ------- | ------------------ | -------------------- | ------------------ |
587
+ |: :|: <div style="color: red;"> &lt; Normal HTML Block > </div> :|||
588
+ | ^^ | Red {: .cls style="background: orange" } |||
589
+ | ^^ IALs | Green {: #id style="background: green; color: white" } |||
590
+ | ^^ | Blue {: style="background: blue; color: white" } |||
591
+ | ^^ | Black {: color-style text-style } |||
592
+ ```
593
+
594
+ Code above would be parsed as:
595
+
596
+ <img width="580px" src="https://user-images.githubusercontent.com/9413601/88461592-738afb00-ced7-11ea-9aac-3179023742b0.png" alt="IALs">
597
+
598
+ Additionally, [here](https://kramdown.gettalong.org/syntax.html#block-ials) you can learn more details about IALs.
599
+
537
600
  ### 2. MathJax Usage
538
601
 
539
602
  [MathJax](http://www.mathjax.org/) is an open-source JavaScript display engine for LaTeX, MathML, and AsciiMath notation that works in all modern browsers.
@@ -645,25 +708,31 @@ Code above would be parsed as:
645
708
 
646
709
  ![Mermaid Diagram](https://user-images.githubusercontent.com/9413601/85282355-2e317300-b4be-11ea-9c30-8f9d61540d14.png)
647
710
 
648
- ### 5. Video Usage
711
+ ### 5. Media Usage
649
712
 
650
- 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?**"
651
714
 
652
- 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.
653
719
 
654
- **For now, these video links parsing are provided:**
720
+ **For now, these media links parsing are provided:**
655
721
 
656
722
  - Youtube
657
723
  - Vimeo
658
724
  - DailyMotion
659
- - 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 ... )
660
729
 
661
- 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:
662
731
 
663
732
  Inline-style:
664
733
 
665
734
  ```markdown
666
- ![]({video-link})
735
+ ![]({media-link})
667
736
  ```
668
737
 
669
738
  Reference-style:
@@ -671,10 +740,10 @@ Reference-style:
671
740
  ```markdown
672
741
  ![][{reference}]
673
742
 
674
- [{reference}]: {video-link}
743
+ [{reference}]: {media-link}
675
744
  ```
676
745
 
677
- 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
678
747
  the link as below:
679
748
 
680
749
  ```markdown
@@ -707,6 +776,22 @@ the link as below:
707
776
  ![](https://dai.ly/x7tgcev?width=100%&height=400)
708
777
  ```
709
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
+
710
795
  #### General Video Usage
711
796
 
712
797
  ```markdown
@@ -717,6 +802,15 @@ the link as below:
717
802
  ![](//techslides.com/demos/sample-videos/small.mp4?width=400)
718
803
  ```
719
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">
720
814
 
721
815
  ### 6. Hybrid HTML with Markdown
722
816
 
@@ -890,7 +984,7 @@ jekyll-spaceship:
890
984
  css:
891
985
  - a: # Replce all `a` tags
892
986
  props: #
893
- loading: lazy # Replace `lading` value to `lazy`
987
+ loading: lazy # Replace `loading` value to `lazy`
894
988
  ```
895
989
 
896
990
  In case you want to prevent loading some images/iframes lazily, add
@@ -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
 
@@ -121,7 +121,7 @@ module Jekyll::Spaceship
121
121
  else
122
122
  if Type.html? output_ext
123
123
  method = 'on_handle_html'
124
- elsif css? output_ext
124
+ elsif Type.css? output_ext
125
125
  method = 'on_handle_css'
126
126
  end
127
127
  if self.respond_to? method
@@ -160,7 +160,7 @@ 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
165
  next if regex.nil?
166
166
  content.scan(regex) do |match_data|
@@ -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
@@ -5,6 +5,9 @@ require "nokogiri"
5
5
 
6
6
  module Jekyll::Spaceship
7
7
  class TableProcessor < Processor
8
+ ATTR_LIST_PATTERN = /((?<!\\)\{:(?:([A-Za-z]\S*):)?(.*?)(?<!\\)\})/
9
+ ATTR_LIST_REFS = {}
10
+
8
11
  def on_handle_markdown(content)
9
12
  # pre-handle reference-style links
10
13
  references = {}
@@ -16,7 +19,9 @@ module Jekyll::Spaceship
16
19
  if references.size > 0
17
20
  content.scan(/[^\n]*(?<!\\)\|[^\n]*/) do |result|
18
21
  references.each do |key, val|
19
- replace = result.gsub(/\[([^\n]*)\]\s*\[#{key}\]/, "[\1](#{val})")
22
+ replace = result.gsub(
23
+ /\[([^\n\]]*?)\]\s*\[#{key}\]/,
24
+ "[\1](#{val})")
20
25
  next if result == replace
21
26
  content = content.gsub(result, replace)
22
27
  end
@@ -42,6 +47,19 @@ module Jekyll::Spaceship
42
47
  next if result == replace
43
48
  content = content.gsub(result, replace)
44
49
  end
50
+
51
+ # pre-handle attribute list (AL)
52
+ ATTR_LIST_REFS.clear()
53
+ content.scan(ATTR_LIST_PATTERN) do |result|
54
+ ref = result[1]
55
+ list = result[2]
56
+ next if ref.nil?
57
+ if ATTR_LIST_REFS.has_key? ref
58
+ ATTR_LIST_REFS[ref] += list
59
+ else
60
+ ATTR_LIST_REFS[ref] = list
61
+ end
62
+ end
45
63
  content
46
64
  end
47
65
 
@@ -69,6 +87,7 @@ module Jekyll::Spaceship
69
87
  handle_multi_rows(data)
70
88
  handle_text_align(data)
71
89
  handle_rowspan(data)
90
+ handle_attr_list(data)
72
91
  end
73
92
  end
74
93
  rows.each do |row|
@@ -161,7 +180,7 @@ module Jekyll::Spaceship
161
180
  if scope.table.multi_row_cells != cells and scope.table.multi_row_start
162
181
  for i in 0...scope.table.multi_row_cells.count do
163
182
  multi_row_cell = scope.table.multi_row_cells[i]
164
- multi_row_cell.inner_html += "<br>#{cells[i].inner_html}"
183
+ multi_row_cell.inner_html += "\n<br>\n#{cells[i].inner_html}"
165
184
  end
166
185
  row.remove
167
186
  end
@@ -186,7 +205,7 @@ module Jekyll::Spaceship
186
205
  span_cell = scope.table.span_row_cells[scope.row.col_index]
187
206
  if span_cell and cell.content.match(/^\s*\^{2}/)
188
207
  cell.content = cell.content.gsub(/^\s*\^{2}/, '')
189
- span_cell.inner_html += "<br>#{cell.inner_html}"
208
+ span_cell.inner_html += "\n<br>\n#{cell.inner_html}"
190
209
  rowspan = span_cell.get_attribute('rowspan') || 1
191
210
  rowspan = rowspan.to_i + 1
192
211
  span_cell.set_attribute('rowspan', "#{rowspan}")
@@ -235,6 +254,52 @@ module Jekyll::Spaceship
235
254
  cell.set_attribute('style', style)
236
255
  end
237
256
 
257
+ # Examples:
258
+ # {:ref-name: .cls1 title="hello" }
259
+ # {: #id ref-name data="world" }
260
+ # {: #id title="hello" }
261
+ # {: .cls style="color: #333" }
262
+ def handle_attr_list(data)
263
+ cell = data.cell
264
+ content = cell.inner_html
265
+ # inline attribute list(IAL) handler
266
+ ial_handler = ->(list) do
267
+ list.scan(/(\S+)=("|')(.*?)\2|(\S+)/) do |attr|
268
+ key = attr[0]
269
+ val = attr[2]
270
+ single = attr[3]
271
+ if !key.nil?
272
+ val = (cell.get_attribute(key) || '') + val
273
+ cell.set_attribute(key, val)
274
+ elsif !single.nil?
275
+ if single.start_with? '#'
276
+ key = 'id'
277
+ val = single[1..-1]
278
+ elsif single.start_with? '.'
279
+ key = 'class'
280
+ val = cell.get_attribute(key) || ''
281
+ val += (val.size.zero? ? '' : ' ') + single[1..-1]
282
+ elsif ATTR_LIST_REFS.has_key? single
283
+ ial_handler.call ATTR_LIST_REFS[single]
284
+ end
285
+ unless key.nil?
286
+ cell.set_attribute(key, val)
287
+ end
288
+ end
289
+ end
290
+ end
291
+ # handle attribute list
292
+ content.scan(ATTR_LIST_PATTERN) do |result|
293
+ ref = result[1]
294
+ list = result[2]
295
+ # handle inline attribute list
296
+ ial_handler.call list if ref.nil?
297
+ # remove attr_list
298
+ content = content.sub(result[0], '')
299
+ end
300
+ cell.inner_html = content
301
+ end
302
+
238
303
  def handle_format(data)
239
304
  cell = data.cell
240
305
  cvter = self.converter('markdown')
@@ -242,6 +307,8 @@ module Jekyll::Spaceship
242
307
  content = cell.inner_html
243
308
  .gsub(/(?<!\\)\|/, '\\|')
244
309
  .gsub(/^\s+|\s+$/, '')
310
+ .gsub(/&lt;/, '<')
311
+ .gsub(/&gt;/, '>')
245
312
  content = cvter.convert(content)
246
313
  content = Nokogiri::HTML.fragment(content)
247
314
  if content.children.first&.name == 'p'
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Jekyll
4
4
  module Spaceship
5
- VERSION = "0.8.4"
5
+ VERSION = "0.9.1"
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.4
4
+ version: 0.9.1
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-16 00:00:00.000000000 Z
11
+ date: 2020-08-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jekyll
@@ -140,11 +140,11 @@ files:
140
140
  - lib/jekyll-spaceship/processors/element-processor.rb
141
141
  - lib/jekyll-spaceship/processors/emoji-processor.rb
142
142
  - lib/jekyll-spaceship/processors/mathjax-processor.rb
143
+ - lib/jekyll-spaceship/processors/media-processor.rb
143
144
  - lib/jekyll-spaceship/processors/mermaid-processor.rb
144
145
  - lib/jekyll-spaceship/processors/plantuml-processor.rb
145
146
  - lib/jekyll-spaceship/processors/polyfill-processor.rb
146
147
  - lib/jekyll-spaceship/processors/table-processor.rb
147
- - lib/jekyll-spaceship/processors/video-processor.rb
148
148
  - lib/jekyll-spaceship/utils/.keep
149
149
  - lib/jekyll-spaceship/version.rb
150
150
  - logos/jekyll-spaceship-logo.png
@@ -169,10 +169,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
169
169
  - !ruby/object:Gem::Version
170
170
  version: '0'
171
171
  requirements: []
172
- rubyforge_project:
173
- rubygems_version: 2.7.7
172
+ rubygems_version: 3.0.8
174
173
  signing_key:
175
174
  specification_version: 4
176
175
  summary: A Jekyll plugin to provide powerful supports for table, mathjax, plantuml,
177
- mermaid, emoji, video, youtube, vimeo, dailymotion, etc.
176
+ mermaid, emoji, video, audio, youtube, vimeo, dailymotion, spotify, soundcloud,
177
+ etc.
178
178
  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