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 +4 -4
- data/README.md +114 -20
- data/jekyll-spaceship.gemspec +1 -1
- data/lib/jekyll-spaceship/cores/config.rb +1 -1
- data/lib/jekyll-spaceship/cores/manager.rb +1 -1
- data/lib/jekyll-spaceship/cores/processor.rb +2 -2
- data/lib/jekyll-spaceship/processors/mathjax-processor.rb +15 -4
- data/lib/jekyll-spaceship/processors/media-processor.rb +234 -0
- data/lib/jekyll-spaceship/processors/table-processor.rb +70 -3
- data/lib/jekyll-spaceship/version.rb +1 -1
- metadata +6 -6
- data/lib/jekyll-spaceship/processors/video-processor.rb +0 -139
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 989c96c9ba4f7b3d1ec891d43022360ab1bea0a4de2956e8a94c24c927df6ca1
|
4
|
+
data.tar.gz: 3aa37c0d529d883e2cef637556d65f65d31e9a5c8ee304ca2a2ee01de11ac527
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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
|
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
|
-
-
|
168
|
+
- media-processor
|
165
169
|
- emoji-processor
|
166
170
|
- element-processor
|
167
171
|
mathjax-processor:
|
168
|
-
src:
|
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
|
-
|
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
|
-
|
200
|
+
media-processor:
|
193
201
|
default:
|
194
|
-
id: '
|
195
|
-
class: '
|
202
|
+
id: 'media-{id}'
|
203
|
+
class: 'media'
|
196
204
|
width: '100%'
|
197
205
|
height: 350
|
198
|
-
|
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;"> < 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
|

|
647
710
|
|
648
|
-
### 5.
|
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
|
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
|
720
|
+
**For now, these media links parsing are provided:**
|
655
721
|
|
656
722
|
- Youtube
|
657
723
|
- Vimeo
|
658
724
|
- DailyMotion
|
659
|
-
-
|
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
|
-

|
667
736
|
```
|
668
737
|
|
669
738
|
Reference-style:
|
@@ -671,10 +740,10 @@ Reference-style:
|
|
671
740
|
```markdown
|
672
741
|
![][{reference}]
|
673
742
|
|
674
|
-
[{reference}]: {
|
743
|
+
[{reference}]: {media-link}
|
675
744
|
```
|
676
745
|
|
677
|
-
For configuring
|
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
|

|
708
777
|
```
|
709
778
|
|
779
|
+
#### Spotify Usage
|
780
|
+
|
781
|
+
```markdown
|
782
|
+

|
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
|
+

|
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
|

|
718
803
|
```
|
719
804
|
|
805
|
+
#### General Audio Usage
|
806
|
+
|
807
|
+
```markdown
|
808
|
+

|
809
|
+
|
810
|
+

|
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 `
|
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
|
data/jekyll-spaceship.gemspec
CHANGED
@@ -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
|
|
@@ -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' =>
|
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
|
-
'
|
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
|
-
|
31
|
-
|
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
|
+
# 
|
33
|
+
# 
|
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
|
+
# 
|
45
|
+
# 
|
46
|
+
# 
|
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
|
+
# 
|
57
|
+
# 
|
58
|
+
# 
|
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
|
+
# 
|
70
|
+
# 
|
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
|
+
# 
|
82
|
+
# 
|
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
|
+
# 
|
94
|
+
# 
|
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
|
+
# 
|
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
|
+
"")
|
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(
|
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
|
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
|
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(/</, '<')
|
311
|
+
.gsub(/>/, '>')
|
245
312
|
content = cvter.convert(content)
|
246
313
|
content = Nokogiri::HTML.fragment(content)
|
247
314
|
if content.children.first&.name == 'p'
|
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.
|
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-
|
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
|
-
|
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,
|
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
|
-
# 
|
30
|
-
# 
|
31
|
-
# 
|
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
|
-
# 
|
41
|
-
# 
|
42
|
-
# 
|
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
|
-
# 
|
53
|
-
# 
|
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
|
-
# 
|
64
|
-
# 
|
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
|
-
"")
|
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
|