jekyll-link-attributes 1.0.1 → 2.0.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/.gitignore +1 -1
- data/.ruby-version +1 -1
- data/Gemfile +9 -9
- data/Gemfile.lock +98 -98
- data/LICENSE +24 -24
- data/README.md +102 -64
- data/Rakefile +3 -3
- data/jekyll-link-attributes.gemspec +33 -33
- data/lib/jekyll-link-attributes/hooks.rb +18 -18
- data/lib/jekyll-link-attributes/version.rb +7 -7
- data/lib/jekyll-link-attributes.rb +134 -56
- metadata +5 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d791371caa0d64c3b9f0be8b0166c0dee989a8ba462e58c07ccef19625652fae
|
|
4
|
+
data.tar.gz: 56525b68f3c8ffb2568792b64b1e0e7c271d82cb742d77eaba772db3f7cd5112
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0de1970490f37a7cce17f43303b234957aaf23f9f6fa10514d2e04da2a2c654d4d6b2aa4c9f0099ae1a555701da14f5724c72606c9f2ac610dd3b50a9dbf3bb7
|
|
7
|
+
data.tar.gz: 10bdda6fbaa8ef263b9a3648391fef15031ef507e36307632fceb011037f38c201b131dc718ce8dd6abd8154afec57cdfbd8febb4bd6290c37ea617d6227f050
|
data/.gitignore
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
.idea
|
|
1
|
+
.idea
|
|
2
2
|
jekyll-link-attributes-*.gem
|
data/.ruby-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.1.0
|
|
1
|
+
3.1.0
|
data/Gemfile
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
source 'https://rubygems.org'
|
|
4
|
-
|
|
5
|
-
gemspec
|
|
6
|
-
|
|
7
|
-
group :test do
|
|
8
|
-
gem 'rspec'
|
|
9
|
-
end
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
source 'https://rubygems.org'
|
|
4
|
+
|
|
5
|
+
gemspec
|
|
6
|
+
|
|
7
|
+
group :test do
|
|
8
|
+
gem 'rspec'
|
|
9
|
+
end
|
data/Gemfile.lock
CHANGED
|
@@ -1,98 +1,98 @@
|
|
|
1
|
-
PATH
|
|
2
|
-
remote: .
|
|
3
|
-
specs:
|
|
4
|
-
jekyll-link-attributes (
|
|
5
|
-
|
|
6
|
-
GEM
|
|
7
|
-
remote: https://rubygems.org/
|
|
8
|
-
specs:
|
|
9
|
-
addressable (2.8.1)
|
|
10
|
-
public_suffix (>= 2.0.2, < 6.0)
|
|
11
|
-
colorator (1.1.0)
|
|
12
|
-
concurrent-ruby (1.1.10)
|
|
13
|
-
diff-lcs (1.5.0)
|
|
14
|
-
em-websocket (0.5.3)
|
|
15
|
-
eventmachine (>= 0.12.9)
|
|
16
|
-
http_parser.rb (~> 0)
|
|
17
|
-
eventmachine (1.2.7)
|
|
18
|
-
ffi (1.15.5)
|
|
19
|
-
forwardable-extended (2.6.0)
|
|
20
|
-
http_parser.rb (0.8.0)
|
|
21
|
-
i18n (1.12.0)
|
|
22
|
-
concurrent-ruby (~> 1.0)
|
|
23
|
-
jekyll (4.2.2)
|
|
24
|
-
addressable (~> 2.4)
|
|
25
|
-
colorator (~> 1.0)
|
|
26
|
-
em-websocket (~> 0.5)
|
|
27
|
-
i18n (~> 1.0)
|
|
28
|
-
jekyll-sass-converter (~> 2.0)
|
|
29
|
-
jekyll-watch (~> 2.0)
|
|
30
|
-
kramdown (~> 2.3)
|
|
31
|
-
kramdown-parser-gfm (~> 1.0)
|
|
32
|
-
liquid (~> 4.0)
|
|
33
|
-
mercenary (~> 0.4.0)
|
|
34
|
-
pathutil (~> 0.9)
|
|
35
|
-
rouge (~> 3.0)
|
|
36
|
-
safe_yaml (~> 1.0)
|
|
37
|
-
terminal-table (~> 2.0)
|
|
38
|
-
jekyll-sass-converter (2.2.0)
|
|
39
|
-
sassc (> 2.0.1, < 3.0)
|
|
40
|
-
jekyll-watch (2.2.1)
|
|
41
|
-
listen (~> 3.0)
|
|
42
|
-
kramdown (2.4.0)
|
|
43
|
-
rexml
|
|
44
|
-
kramdown-parser-gfm (1.1.0)
|
|
45
|
-
kramdown (~> 2.0)
|
|
46
|
-
liquid (4.0.3)
|
|
47
|
-
listen (3.7.1)
|
|
48
|
-
rb-fsevent (~> 0.10, >= 0.10.3)
|
|
49
|
-
rb-inotify (~> 0.9, >= 0.9.10)
|
|
50
|
-
mercenary (0.4.0)
|
|
51
|
-
nokogiri (1.13.8-x86_64-darwin)
|
|
52
|
-
racc (~> 1.4)
|
|
53
|
-
nokogiri (1.13.8-x86_64-linux)
|
|
54
|
-
racc (~> 1.4)
|
|
55
|
-
pathutil (0.16.2)
|
|
56
|
-
forwardable-extended (~> 2.6)
|
|
57
|
-
public_suffix (5.0.0)
|
|
58
|
-
racc (1.6.0)
|
|
59
|
-
rake (10.5.0)
|
|
60
|
-
rb-fsevent (0.11.2)
|
|
61
|
-
rb-inotify (0.10.1)
|
|
62
|
-
ffi (~> 1.0)
|
|
63
|
-
rexml (3.2.5)
|
|
64
|
-
rouge (3.30.0)
|
|
65
|
-
rspec (3.11.0)
|
|
66
|
-
rspec-core (~> 3.11.0)
|
|
67
|
-
rspec-expectations (~> 3.11.0)
|
|
68
|
-
rspec-mocks (~> 3.11.0)
|
|
69
|
-
rspec-core (3.11.0)
|
|
70
|
-
rspec-support (~> 3.11.0)
|
|
71
|
-
rspec-expectations (3.11.0)
|
|
72
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
|
73
|
-
rspec-support (~> 3.11.0)
|
|
74
|
-
rspec-mocks (3.11.1)
|
|
75
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
|
76
|
-
rspec-support (~> 3.11.0)
|
|
77
|
-
rspec-support (3.11.0)
|
|
78
|
-
safe_yaml (1.0.5)
|
|
79
|
-
sassc (2.4.0)
|
|
80
|
-
ffi (~> 1.9)
|
|
81
|
-
terminal-table (2.0.0)
|
|
82
|
-
unicode-display_width (~> 1.1, >= 1.1.1)
|
|
83
|
-
unicode-display_width (1.8.0)
|
|
84
|
-
|
|
85
|
-
PLATFORMS
|
|
86
|
-
x86_64-darwin-20
|
|
87
|
-
x86_64-linux
|
|
88
|
-
|
|
89
|
-
DEPENDENCIES
|
|
90
|
-
bundler (>= 2.0.0)
|
|
91
|
-
jekyll (>= 4.0.0)
|
|
92
|
-
jekyll-link-attributes!
|
|
93
|
-
nokogiri (>= 1.0.0)
|
|
94
|
-
rake (>= 10.0.0)
|
|
95
|
-
rspec
|
|
96
|
-
|
|
97
|
-
BUNDLED WITH
|
|
98
|
-
2.3.21
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
jekyll-link-attributes (2.0.1)
|
|
5
|
+
|
|
6
|
+
GEM
|
|
7
|
+
remote: https://rubygems.org/
|
|
8
|
+
specs:
|
|
9
|
+
addressable (2.8.1)
|
|
10
|
+
public_suffix (>= 2.0.2, < 6.0)
|
|
11
|
+
colorator (1.1.0)
|
|
12
|
+
concurrent-ruby (1.1.10)
|
|
13
|
+
diff-lcs (1.5.0)
|
|
14
|
+
em-websocket (0.5.3)
|
|
15
|
+
eventmachine (>= 0.12.9)
|
|
16
|
+
http_parser.rb (~> 0)
|
|
17
|
+
eventmachine (1.2.7)
|
|
18
|
+
ffi (1.15.5)
|
|
19
|
+
forwardable-extended (2.6.0)
|
|
20
|
+
http_parser.rb (0.8.0)
|
|
21
|
+
i18n (1.12.0)
|
|
22
|
+
concurrent-ruby (~> 1.0)
|
|
23
|
+
jekyll (4.2.2)
|
|
24
|
+
addressable (~> 2.4)
|
|
25
|
+
colorator (~> 1.0)
|
|
26
|
+
em-websocket (~> 0.5)
|
|
27
|
+
i18n (~> 1.0)
|
|
28
|
+
jekyll-sass-converter (~> 2.0)
|
|
29
|
+
jekyll-watch (~> 2.0)
|
|
30
|
+
kramdown (~> 2.3)
|
|
31
|
+
kramdown-parser-gfm (~> 1.0)
|
|
32
|
+
liquid (~> 4.0)
|
|
33
|
+
mercenary (~> 0.4.0)
|
|
34
|
+
pathutil (~> 0.9)
|
|
35
|
+
rouge (~> 3.0)
|
|
36
|
+
safe_yaml (~> 1.0)
|
|
37
|
+
terminal-table (~> 2.0)
|
|
38
|
+
jekyll-sass-converter (2.2.0)
|
|
39
|
+
sassc (> 2.0.1, < 3.0)
|
|
40
|
+
jekyll-watch (2.2.1)
|
|
41
|
+
listen (~> 3.0)
|
|
42
|
+
kramdown (2.4.0)
|
|
43
|
+
rexml
|
|
44
|
+
kramdown-parser-gfm (1.1.0)
|
|
45
|
+
kramdown (~> 2.0)
|
|
46
|
+
liquid (4.0.3)
|
|
47
|
+
listen (3.7.1)
|
|
48
|
+
rb-fsevent (~> 0.10, >= 0.10.3)
|
|
49
|
+
rb-inotify (~> 0.9, >= 0.9.10)
|
|
50
|
+
mercenary (0.4.0)
|
|
51
|
+
nokogiri (1.13.8-x86_64-darwin)
|
|
52
|
+
racc (~> 1.4)
|
|
53
|
+
nokogiri (1.13.8-x86_64-linux)
|
|
54
|
+
racc (~> 1.4)
|
|
55
|
+
pathutil (0.16.2)
|
|
56
|
+
forwardable-extended (~> 2.6)
|
|
57
|
+
public_suffix (5.0.0)
|
|
58
|
+
racc (1.6.0)
|
|
59
|
+
rake (10.5.0)
|
|
60
|
+
rb-fsevent (0.11.2)
|
|
61
|
+
rb-inotify (0.10.1)
|
|
62
|
+
ffi (~> 1.0)
|
|
63
|
+
rexml (3.2.5)
|
|
64
|
+
rouge (3.30.0)
|
|
65
|
+
rspec (3.11.0)
|
|
66
|
+
rspec-core (~> 3.11.0)
|
|
67
|
+
rspec-expectations (~> 3.11.0)
|
|
68
|
+
rspec-mocks (~> 3.11.0)
|
|
69
|
+
rspec-core (3.11.0)
|
|
70
|
+
rspec-support (~> 3.11.0)
|
|
71
|
+
rspec-expectations (3.11.0)
|
|
72
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
73
|
+
rspec-support (~> 3.11.0)
|
|
74
|
+
rspec-mocks (3.11.1)
|
|
75
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
76
|
+
rspec-support (~> 3.11.0)
|
|
77
|
+
rspec-support (3.11.0)
|
|
78
|
+
safe_yaml (1.0.5)
|
|
79
|
+
sassc (2.4.0)
|
|
80
|
+
ffi (~> 1.9)
|
|
81
|
+
terminal-table (2.0.0)
|
|
82
|
+
unicode-display_width (~> 1.1, >= 1.1.1)
|
|
83
|
+
unicode-display_width (1.8.0)
|
|
84
|
+
|
|
85
|
+
PLATFORMS
|
|
86
|
+
x86_64-darwin-20
|
|
87
|
+
x86_64-linux
|
|
88
|
+
|
|
89
|
+
DEPENDENCIES
|
|
90
|
+
bundler (>= 2.0.0)
|
|
91
|
+
jekyll (>= 4.0.0)
|
|
92
|
+
jekyll-link-attributes!
|
|
93
|
+
nokogiri (>= 1.0.0)
|
|
94
|
+
rake (>= 10.0.0)
|
|
95
|
+
rspec
|
|
96
|
+
|
|
97
|
+
BUNDLED WITH
|
|
98
|
+
2.3.21
|
data/LICENSE
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
Copyright 2022 Twin Sun, LLC
|
|
2
|
-
|
|
3
|
-
Redistribution and use in source and binary forms, with or without modification,
|
|
4
|
-
are permitted provided that the following conditions are met:
|
|
5
|
-
|
|
6
|
-
* Redistributions of source code must retain the above copyright
|
|
7
|
-
notice, this list of conditions and the following disclaimer.
|
|
8
|
-
* Redistributions in binary form must reproduce the above
|
|
9
|
-
copyright notice, this list of conditions and the following
|
|
10
|
-
disclaimer in the documentation and/or other materials provided
|
|
11
|
-
with the distribution.
|
|
12
|
-
* Neither the name of Twin Sun, LLC nor the names of its
|
|
13
|
-
contributors may be used to endorse or promote products derived
|
|
14
|
-
from this software without specific prior written permission.
|
|
15
|
-
|
|
16
|
-
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
17
|
-
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
18
|
-
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
19
|
-
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
20
|
-
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
21
|
-
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
22
|
-
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
23
|
-
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
24
|
-
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
1
|
+
Copyright 2022 Twin Sun, LLC
|
|
2
|
+
|
|
3
|
+
Redistribution and use in source and binary forms, with or without modification,
|
|
4
|
+
are permitted provided that the following conditions are met:
|
|
5
|
+
|
|
6
|
+
* Redistributions of source code must retain the above copyright
|
|
7
|
+
notice, this list of conditions and the following disclaimer.
|
|
8
|
+
* Redistributions in binary form must reproduce the above
|
|
9
|
+
copyright notice, this list of conditions and the following
|
|
10
|
+
disclaimer in the documentation and/or other materials provided
|
|
11
|
+
with the distribution.
|
|
12
|
+
* Neither the name of Twin Sun, LLC nor the names of its
|
|
13
|
+
contributors may be used to endorse or promote products derived
|
|
14
|
+
from this software without specific prior written permission.
|
|
15
|
+
|
|
16
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
17
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
18
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
19
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
20
|
+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
21
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
22
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
23
|
+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
24
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
25
25
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
CHANGED
|
@@ -1,64 +1,102 @@
|
|
|
1
|
-
# Jekyll Link Attributes
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
## Setup
|
|
7
|
-
|
|
8
|
-
1. Add the gem to your `Gemfile`:
|
|
9
|
-
```ruby
|
|
10
|
-
gem 'jekyll-link-attributes'
|
|
11
|
-
```
|
|
12
|
-
2. Run `bundle install` to install the gem
|
|
13
|
-
3. Add the following to your `_config.yml`:
|
|
14
|
-
```yaml
|
|
15
|
-
plugins:
|
|
16
|
-
- jekyll-link-attributes
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
##
|
|
20
|
-
|
|
21
|
-
###
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
```yaml
|
|
26
|
-
external_links:
|
|
27
|
-
enabled: true
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
1
|
+
# Jekyll Link Attributes
|
|
2
|
+
|
|
3
|
+
A Jekyll plugin for managing external link behavior: `rel` attributes, `target` attributes, and UTM tracking parameters.
|
|
4
|
+
Each concern is independently configurable with its own value and exclude list.
|
|
5
|
+
|
|
6
|
+
## Setup
|
|
7
|
+
|
|
8
|
+
1. Add the gem to your `Gemfile`:
|
|
9
|
+
```ruby
|
|
10
|
+
gem 'jekyll-link-attributes'
|
|
11
|
+
```
|
|
12
|
+
2. Run `bundle install` to install the gem
|
|
13
|
+
3. Add the following to your `_config.yml`:
|
|
14
|
+
```yaml
|
|
15
|
+
plugins:
|
|
16
|
+
- jekyll-link-attributes
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Configuration
|
|
20
|
+
|
|
21
|
+
### Recommended (v2+)
|
|
22
|
+
|
|
23
|
+
Each attribute type is its own section with a `value` and optional `exclude` list:
|
|
24
|
+
|
|
25
|
+
```yaml
|
|
26
|
+
external_links:
|
|
27
|
+
enabled: true
|
|
28
|
+
|
|
29
|
+
rel:
|
|
30
|
+
value: external nofollow noopener
|
|
31
|
+
exclude:
|
|
32
|
+
- https://myotherapp.com(/?|/.*)?
|
|
33
|
+
|
|
34
|
+
target:
|
|
35
|
+
value: _blank
|
|
36
|
+
exclude:
|
|
37
|
+
- https://myotherapp.com(/?|/.*)?
|
|
38
|
+
|
|
39
|
+
utm:
|
|
40
|
+
enabled: true
|
|
41
|
+
source: mysite.com
|
|
42
|
+
medium: website
|
|
43
|
+
exclude:
|
|
44
|
+
- https://github.com(/?|/.*)?
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Legacy (v1, still supported)
|
|
48
|
+
|
|
49
|
+
The original flat configuration style continues to work. The top-level `rel`, `target`, and `exclude` keys are used as fallbacks when the new-style section config is not present:
|
|
50
|
+
|
|
51
|
+
```yaml
|
|
52
|
+
external_links:
|
|
53
|
+
enabled: true
|
|
54
|
+
rel: external nofollow noopener
|
|
55
|
+
target: _blank
|
|
56
|
+
exclude:
|
|
57
|
+
- https://example.com(/?|/.*)?
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Resolution order
|
|
61
|
+
|
|
62
|
+
| Setting | Resolved from | Fallback |
|
|
63
|
+
| ------- | ------------- | -------- |
|
|
64
|
+
| rel value | `external_links.rel.value` | `external_links.rel` (string) or `external nofollow noopener` |
|
|
65
|
+
| rel excludes | `external_links.rel.exclude` | `external_links.exclude` |
|
|
66
|
+
| target value | `external_links.target.value` | `external_links.target` (string) or `_blank` |
|
|
67
|
+
| target excludes | `external_links.target.exclude` | `external_links.exclude` |
|
|
68
|
+
| utm excludes | `external_links.utm.exclude` | *(none, defaults to empty)* |
|
|
69
|
+
|
|
70
|
+
### UTM tracking parameters
|
|
71
|
+
|
|
72
|
+
When `external_links.utm.enabled` is `true`, UTM query parameters are automatically appended to external links:
|
|
73
|
+
|
|
74
|
+
| Param | Value | Source |
|
|
75
|
+
| -------------- | -------------------- | ---------------------------------------------------------------- |
|
|
76
|
+
| `utm_source` | Configured `source` | Falls back to the site `url` with the protocol stripped. |
|
|
77
|
+
| `utm_medium` | Configured `medium` | Falls back to `website`. |
|
|
78
|
+
| `utm_campaign` | Auto-derived | `blog` for post/blog layouts, otherwise the first URL path segment (e.g., `about`), or `homepage` for the root page. |
|
|
79
|
+
| `utm_content` | Auto-derived | The page slug (e.g., `my-great-post` or `index`). |
|
|
80
|
+
|
|
81
|
+
Existing query parameters on links are preserved. UTM parameters already present on a link will not be overwritten.
|
|
82
|
+
|
|
83
|
+
### Skipping individual links
|
|
84
|
+
|
|
85
|
+
The `rel` or `target` attributes will not be modified for links that already have those existing attributes.
|
|
86
|
+
This allows you to skip individual links without having to modify the plugin's configuration.
|
|
87
|
+
|
|
88
|
+
```html
|
|
89
|
+
<a href="https://example.com" rel="nofollow">Example</a> <!-- rel will not be modified, but target will be added. -->
|
|
90
|
+
<a href="https://example.com" target="_self">Example</a> <!-- target will not be modified, but rel will be added. -->
|
|
91
|
+
<a href="https://example.com" rel="nofollow" target="_self">Example</a> <!-- Neither rel nor target will be modified. -->
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Contributing
|
|
95
|
+
|
|
96
|
+
Pull requests are welcome!
|
|
97
|
+
If you wish to change existing behavior, please open an issue to discuss the change before investing time in a PR.
|
|
98
|
+
RSpec tests are encouraged for any new features.
|
|
99
|
+
|
|
100
|
+
## Supported by Twin Sun
|
|
101
|
+
|
|
102
|
+
This project is maintained by [Twin Sun](https://twinsunsolutions.com/), a custom mobile and web app development agency in Nashville, TN.
|
data/Rakefile
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'bundler/gem_tasks'
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'bundler/gem_tasks'
|
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
lib = File.expand_path('../lib', __FILE__)
|
|
2
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
3
|
-
require 'jekyll-link-attributes/version'
|
|
4
|
-
|
|
5
|
-
Gem::Specification.new do |spec|
|
|
6
|
-
spec.name = 'jekyll-link-attributes'
|
|
7
|
-
spec.version = Jekyll::LinkAttributes::VERSION
|
|
8
|
-
spec.authors = ['twinsunllc']
|
|
9
|
-
spec.email = ['contact@twinsunsolutions.com']
|
|
10
|
-
|
|
11
|
-
spec.summary = 'This plugin adds `rel` and `target` attributes to all external links in your Jekyll site.'
|
|
12
|
-
spec.description = spec.summary
|
|
13
|
-
spec.homepage = 'https://github.com/twinsunllc/jekyll-link-attributes'
|
|
14
|
-
spec.license = 'BSD 3-Clause'
|
|
15
|
-
|
|
16
|
-
# Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
|
|
17
|
-
# delete this section to allow pushing this gem to any host.
|
|
18
|
-
if spec.respond_to?(:metadata)
|
|
19
|
-
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
|
20
|
-
else
|
|
21
|
-
raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.'
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
25
|
-
spec.bindir = 'exe'
|
|
26
|
-
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
27
|
-
spec.require_paths = ['lib']
|
|
28
|
-
|
|
29
|
-
spec.add_development_dependency 'bundler', '>= 2.0.0'
|
|
30
|
-
spec.add_development_dependency 'jekyll', '>= 4.0.0'
|
|
31
|
-
spec.add_development_dependency 'nokogiri', '>= 1.0.0'
|
|
32
|
-
spec.add_development_dependency 'rake', '>= 10.0.0'
|
|
33
|
-
end
|
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
3
|
+
require 'jekyll-link-attributes/version'
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = 'jekyll-link-attributes'
|
|
7
|
+
spec.version = Jekyll::LinkAttributes::VERSION
|
|
8
|
+
spec.authors = ['twinsunllc']
|
|
9
|
+
spec.email = ['contact@twinsunsolutions.com']
|
|
10
|
+
|
|
11
|
+
spec.summary = 'This plugin adds `rel` and `target` attributes to all external links in your Jekyll site.'
|
|
12
|
+
spec.description = spec.summary
|
|
13
|
+
spec.homepage = 'https://github.com/twinsunllc/jekyll-link-attributes'
|
|
14
|
+
spec.license = 'BSD 3-Clause'
|
|
15
|
+
|
|
16
|
+
# Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
|
|
17
|
+
# delete this section to allow pushing this gem to any host.
|
|
18
|
+
if spec.respond_to?(:metadata)
|
|
19
|
+
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
|
20
|
+
else
|
|
21
|
+
raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.'
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
25
|
+
spec.bindir = 'exe'
|
|
26
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
27
|
+
spec.require_paths = ['lib']
|
|
28
|
+
|
|
29
|
+
spec.add_development_dependency 'bundler', '>= 2.0.0'
|
|
30
|
+
spec.add_development_dependency 'jekyll', '>= 4.0.0'
|
|
31
|
+
spec.add_development_dependency 'nokogiri', '>= 1.0.0'
|
|
32
|
+
spec.add_development_dependency 'rake', '>= 10.0.0'
|
|
33
|
+
end
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'jekyll/hooks'
|
|
4
|
-
require 'jekyll-link-attributes'
|
|
5
|
-
|
|
6
|
-
Jekyll::Hooks.register :documents, :post_render do |document|
|
|
7
|
-
Jekyll::LinkAttributes.post_render_html(document)
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
Jekyll::Hooks.register :pages, :post_render do |page|
|
|
11
|
-
next unless page.output_ext.eql?('.html')
|
|
12
|
-
|
|
13
|
-
Jekyll::LinkAttributes.post_render_html(page)
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
Jekyll::Hooks.register :posts, :post_render do |post|
|
|
17
|
-
Jekyll::LinkAttributes.post_render_html(post)
|
|
18
|
-
end
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'jekyll/hooks'
|
|
4
|
+
require 'jekyll-link-attributes'
|
|
5
|
+
|
|
6
|
+
Jekyll::Hooks.register :documents, :post_render do |document|
|
|
7
|
+
Jekyll::LinkAttributes.post_render_html(document)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
Jekyll::Hooks.register :pages, :post_render do |page|
|
|
11
|
+
next unless page.output_ext.eql?('.html')
|
|
12
|
+
|
|
13
|
+
Jekyll::LinkAttributes.post_render_html(page)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
Jekyll::Hooks.register :posts, :post_render do |post|
|
|
17
|
+
Jekyll::LinkAttributes.post_render_html(post)
|
|
18
|
+
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Jekyll
|
|
4
|
-
class LinkAttributes
|
|
5
|
-
VERSION = '
|
|
6
|
-
end
|
|
7
|
-
end
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Jekyll
|
|
4
|
+
class LinkAttributes
|
|
5
|
+
VERSION = '2.0.1'
|
|
6
|
+
end
|
|
7
|
+
end
|
|
@@ -1,56 +1,134 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'jekyll-link-attributes/hooks'
|
|
4
|
-
require 'jekyll-link-attributes/version'
|
|
5
|
-
require 'nokogiri'
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
#
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'jekyll-link-attributes/hooks'
|
|
4
|
+
require 'jekyll-link-attributes/version'
|
|
5
|
+
require 'nokogiri'
|
|
6
|
+
require 'uri'
|
|
7
|
+
|
|
8
|
+
module Jekyll
|
|
9
|
+
|
|
10
|
+
# Adjusts external links in HTML documents.
|
|
11
|
+
class LinkAttributes
|
|
12
|
+
|
|
13
|
+
# Perform post_render processing on the specified document/page/post
|
|
14
|
+
# @param [Object] article a Jekyll document, page, or post
|
|
15
|
+
def self.post_render_html(article)
|
|
16
|
+
config = article.site.config
|
|
17
|
+
return unless external_links_enabled?(config: config)
|
|
18
|
+
|
|
19
|
+
ext_config = config['external_links'] || {}
|
|
20
|
+
utm_params = build_utm_params(ext_config: ext_config, site_config: config, article: article)
|
|
21
|
+
|
|
22
|
+
output = Nokogiri::HTML(article.output)
|
|
23
|
+
output.css('a').each do |a|
|
|
24
|
+
next unless external_link?(config: config, url: a['href'])
|
|
25
|
+
|
|
26
|
+
original_href = a['href']
|
|
27
|
+
|
|
28
|
+
# UTM: applied to all external links with its own exclude list
|
|
29
|
+
if utm_params && !excluded?(ext_config: ext_config, section: 'utm', url: original_href)
|
|
30
|
+
a['href'] = append_utm_params(url: a['href'], utm_params: utm_params)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# rel: new-style section config falls back to legacy top-level keys
|
|
34
|
+
unless a['rel']
|
|
35
|
+
rel_value = resolve_value(ext_config: ext_config, section: 'rel', legacy_key: 'rel',
|
|
36
|
+
default: 'external nofollow noopener')
|
|
37
|
+
unless excluded?(ext_config: ext_config, section: 'rel', url: original_href)
|
|
38
|
+
a['rel'] = rel_value
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# target: new-style section config falls back to legacy top-level keys
|
|
43
|
+
unless a['target']
|
|
44
|
+
target_value = resolve_value(ext_config: ext_config, section: 'target', legacy_key: 'target',
|
|
45
|
+
default: '_blank')
|
|
46
|
+
unless excluded?(ext_config: ext_config, section: 'target', url: original_href)
|
|
47
|
+
a['target'] = target_value
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
article.output = output.to_s
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
# Resolve value for a section, falling back to legacy top-level key.
|
|
58
|
+
# New style: external_links.rel.value / external_links.target.value
|
|
59
|
+
# Legacy: external_links.rel / external_links.target (string value)
|
|
60
|
+
def self.resolve_value(ext_config:, section:, legacy_key:, default:)
|
|
61
|
+
section_config = ext_config[section]
|
|
62
|
+
if section_config.is_a?(Hash)
|
|
63
|
+
section_config['value'] || default
|
|
64
|
+
else
|
|
65
|
+
section_config || default
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Check if a URL is excluded for a given section.
|
|
70
|
+
# New style: external_links.<section>.exclude
|
|
71
|
+
# Legacy fallback (rel/target only): external_links.exclude
|
|
72
|
+
def self.excluded?(ext_config:, section:, url:)
|
|
73
|
+
section_config = ext_config[section]
|
|
74
|
+
excludes = if section_config.is_a?(Hash)
|
|
75
|
+
section_config['exclude'] || []
|
|
76
|
+
elsif section == 'utm'
|
|
77
|
+
[]
|
|
78
|
+
else
|
|
79
|
+
ext_config['exclude'] || []
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
excludes.any? { |pattern| Regexp.new("^#{pattern}$").match?(url) }
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def self.external_link?(config:, url:)
|
|
86
|
+
site_url = config['url']
|
|
87
|
+
!(url =~ %r{^https?://}).nil? && (site_url.nil? || !url.start_with?(site_url))
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def self.external_links_enabled?(config:)
|
|
91
|
+
enabled = config.dig('external_links', 'enabled')
|
|
92
|
+
enabled.nil? || enabled
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def self.utm_enabled?(ext_config:)
|
|
96
|
+
ext_config.dig('utm', 'enabled') == true
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def self.build_utm_params(ext_config:, site_config:, article:)
|
|
100
|
+
return nil unless utm_enabled?(ext_config: ext_config)
|
|
101
|
+
|
|
102
|
+
utm_config = ext_config['utm'] || {}
|
|
103
|
+
source = utm_config['source'] || site_config['url']&.sub(%r{\Ahttps?://}, '') || 'website'
|
|
104
|
+
medium = utm_config['medium'] || 'website'
|
|
105
|
+
|
|
106
|
+
campaign = case article.data['layout']
|
|
107
|
+
when 'post', 'blog' then 'blog'
|
|
108
|
+
else
|
|
109
|
+
path = article.url.to_s.gsub(%r{\A/|/\z}, '')
|
|
110
|
+
path.empty? ? 'homepage' : path.split('/').first
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
content = article.data['slug'] || File.basename(article.url.to_s.chomp('/'))
|
|
114
|
+
content = 'index' if content.empty?
|
|
115
|
+
|
|
116
|
+
{
|
|
117
|
+
'utm_source' => source,
|
|
118
|
+
'utm_medium' => medium,
|
|
119
|
+
'utm_campaign' => campaign,
|
|
120
|
+
'utm_content' => content,
|
|
121
|
+
}
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def self.append_utm_params(url:, utm_params:)
|
|
125
|
+
uri = URI.parse(url)
|
|
126
|
+
existing = URI.decode_www_form(uri.query || '').to_h
|
|
127
|
+
utm_params.each { |k, v| existing[k] = v unless existing.key?(k) }
|
|
128
|
+
uri.query = URI.encode_www_form(existing)
|
|
129
|
+
uri.to_s
|
|
130
|
+
rescue URI::InvalidURIError
|
|
131
|
+
url
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: jekyll-link-attributes
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 2.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- twinsunllc
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-03-24 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -90,7 +90,7 @@ licenses:
|
|
|
90
90
|
- BSD 3-Clause
|
|
91
91
|
metadata:
|
|
92
92
|
allowed_push_host: https://rubygems.org
|
|
93
|
-
post_install_message:
|
|
93
|
+
post_install_message:
|
|
94
94
|
rdoc_options: []
|
|
95
95
|
require_paths:
|
|
96
96
|
- lib
|
|
@@ -106,7 +106,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
106
106
|
version: '0'
|
|
107
107
|
requirements: []
|
|
108
108
|
rubygems_version: 3.3.3
|
|
109
|
-
signing_key:
|
|
109
|
+
signing_key:
|
|
110
110
|
specification_version: 4
|
|
111
111
|
summary: This plugin adds `rel` and `target` attributes to all external links in your
|
|
112
112
|
Jekyll site.
|