jekyll-link-decorator 1.5.1 → 1.6.0
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/lib/jekyll-link-decorator/version.rb +1 -1
- data/lib/jekyll-link-decorator.rb +92 -47
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4d91801b17b914f5fd1b053dabb0ca88e6d814c80dd0a58b929272ddaf636224
|
|
4
|
+
data.tar.gz: 22127cd8018119d37a82855bed5f73476783f46610b763c4eb31a5095689cdac
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 22225853f9368b78e14d32a8c44d945acc6c526a225992603d51317892c2c5ae9f958bf6f4882352441087a00d3f442071142f38f7953f2189bb4c1fe9a0daa1
|
|
7
|
+
data.tar.gz: f83df55c641942409368e632ef79763a669d06d558fe02b2911a4198361d6c81f936360213ce9858c48d32ebd64f465abdca96d42e7bcadc6c6a0613c0cbf002
|
|
@@ -1,54 +1,54 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# This Jekyll plugin, `link_decorator`,
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
# box or is a regular link. It explicitly avoids modifying elements that are
|
|
8
|
-
# designated as buttons by having the `.btn` class.
|
|
3
|
+
# This Jekyll plugin, `link_decorator`, enhances `<a>` tags in Markdown content
|
|
4
|
+
# with Bootstrap CSS classes and external-link icons. It applies different
|
|
5
|
+
# classes depending on whether a link sits inside a Bootstrap alert box or
|
|
6
|
+
# stands alone, and skips elements with the `.btn` class.
|
|
9
7
|
#
|
|
10
8
|
# === External Link Icon Support ===
|
|
11
9
|
#
|
|
12
10
|
# For links pointing to external domains (different from site.url), the plugin
|
|
13
|
-
#
|
|
14
|
-
#
|
|
11
|
+
# adds a Font Awesome external-link icon (fa-solid fa-external-link) at the
|
|
12
|
+
# end of the link text.
|
|
15
13
|
#
|
|
16
14
|
# === External Link Detection & Target Management ===
|
|
17
15
|
#
|
|
18
|
-
# The plugin
|
|
16
|
+
# The plugin detects external links and manages their behavior:
|
|
19
17
|
# - Relative URLs (starting with /, ../) and same-domain absolute URLs open in the same window
|
|
20
|
-
# - Absolute URLs pointing to different domains (http:// or https://)
|
|
21
|
-
# - Links with target="_blank"
|
|
22
|
-
#
|
|
18
|
+
# - Absolute URLs pointing to different domains (http:// or https://) get target="_blank"
|
|
19
|
+
# - Links with target="_blank" receive rel="noopener noreferrer" protection against
|
|
20
|
+
# security vulnerabilities (window.opener access, referrer leakage)
|
|
23
21
|
#
|
|
24
22
|
# === Configuration ===
|
|
25
23
|
#
|
|
26
|
-
#
|
|
27
|
-
# `
|
|
24
|
+
# Customize the plugin's classes by adding `with_link_decorator` and
|
|
25
|
+
# `with_link_decorator_data` to your `_config.yml`.
|
|
28
26
|
#
|
|
29
27
|
# * `with_link_decorator`: Boolean (default: true) that controls whether the plugin runs.
|
|
30
28
|
# Set to false to disable automatic link styling and icon insertion.
|
|
31
29
|
#
|
|
32
30
|
# * `with_link_decorator_data`: A dictionary containing optional configuration keys:
|
|
33
|
-
# - `default_link_classes`:
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
#
|
|
37
|
-
#
|
|
38
|
-
#
|
|
31
|
+
# - `default_link_classes`: Classes applied to links outside an .alert.
|
|
32
|
+
# Example: `default_link_classes: "text-decoration-none"`
|
|
33
|
+
# If a link already carries its own `link-{color}`, `link-underline-*`,
|
|
34
|
+
# `link-offset-*`, `link-underline-opacity-*`, `link-opacity-*`, or `focus-ring(-{color})?` class,
|
|
35
|
+
# the plugin skips the matching default token automatically — see LINK_CLASS_FAMILIES.
|
|
36
|
+
# - `alert_link_classes`: Classes applied to links inside an .alert box.
|
|
37
|
+
# Example: `alert_link_classes: "text-decoration-underline"`
|
|
38
|
+
# - `external_link_icon`: Boolean (default: true) — show the icon on cross-domain
|
|
39
|
+
# external links. Set to false to disable.
|
|
39
40
|
# - `external_link_icon_excluded_tags`: List of HTML child tag names (default: []) whose presence
|
|
40
41
|
# inside an anchor suppresses the external-link icon. Security attributes
|
|
41
|
-
# (target="_blank", rel="noopener noreferrer")
|
|
42
|
+
# (target="_blank", rel="noopener noreferrer") still apply.
|
|
42
43
|
# Example: `external_link_icon_excluded_tags: ["img", "svg"]`
|
|
43
44
|
#
|
|
44
45
|
# === Heading Anchor Support ===
|
|
45
46
|
#
|
|
46
|
-
# The plugin can inject a permalink icon inside each heading (h1–h6)
|
|
47
|
-
#
|
|
48
|
-
#
|
|
47
|
+
# The plugin can inject a permalink icon inside each heading (h1–h6) so every
|
|
48
|
+
# section gets a shareable URL. Configure it via two top-level keys (separate
|
|
49
|
+
# from `with_link_decorator_data`):
|
|
49
50
|
#
|
|
50
|
-
# * `with_heading_anchor`: Boolean (default: false)
|
|
51
|
-
# are injected. Set to true to enable.
|
|
51
|
+
# * `with_heading_anchor`: Boolean (default: false) — set to true to inject heading anchors.
|
|
52
52
|
#
|
|
53
53
|
# * `with_heading_anchor_data`: A dictionary containing optional configuration keys:
|
|
54
54
|
# - `icon`: CSS classes applied to the anchor's glyph element (default:
|
|
@@ -58,16 +58,16 @@
|
|
|
58
58
|
# want an icon-font glyph instead.
|
|
59
59
|
# - `icon_size`: Optional size modifier class appended after the icon classes.
|
|
60
60
|
#
|
|
61
|
-
#
|
|
62
|
-
#
|
|
61
|
+
# Without configuration, the plugin uses its default classes and enables
|
|
62
|
+
# external-link icons.
|
|
63
63
|
#
|
|
64
|
-
#
|
|
64
|
+
# Example `_config.yml`:
|
|
65
65
|
#
|
|
66
66
|
# ```yaml
|
|
67
67
|
# with_link_decorator: true
|
|
68
68
|
# with_link_decorator_data:
|
|
69
|
-
# default_link_classes: "link link-offset-3 link-offset-3-hover link-underline-primary link-underline-opacity-0 link-underline-opacity-100-hover"
|
|
70
|
-
# alert_link_classes: "alert-link"
|
|
69
|
+
# default_link_classes: "link link-offset-3 link-offset-3-hover link-underline-primary link-underline-opacity-0 link-underline-opacity-100-hover focus-ring"
|
|
70
|
+
# alert_link_classes: "alert-link focus-ring"
|
|
71
71
|
# external_link_icon: true
|
|
72
72
|
# external_link_icon_excluded_tags:
|
|
73
73
|
# - img
|
|
@@ -92,14 +92,52 @@ EXISTING_ICON_SELECTORS = [
|
|
|
92
92
|
|
|
93
93
|
module Jekyll
|
|
94
94
|
module Converters
|
|
95
|
-
#
|
|
96
|
-
#
|
|
97
|
-
#
|
|
98
|
-
# It also adds external-link icons for cross-domain external links.
|
|
95
|
+
# Applies CSS classes to <a> tags based on context (e.g., inside an alert
|
|
96
|
+
# box) via Nokogiri CSS selectors, excluding buttons. Also adds
|
|
97
|
+
# external-link icons for cross-domain links.
|
|
99
98
|
class LinkDecorator < Jekyll::Converters::Markdown
|
|
100
99
|
DEFAULT_LINK_CLASSES = 'link link-offset-3 link-offset-3-hover link-underline-primary ' \
|
|
101
|
-
'link-underline-opacity-0 link-underline-opacity-100-hover'
|
|
102
|
-
DEFAULT_ALERT_LINK_CLASSES = 'alert-link'
|
|
100
|
+
'link-underline-opacity-0 link-underline-opacity-100-hover focus-ring'
|
|
101
|
+
DEFAULT_ALERT_LINK_CLASSES = 'alert-link focus-ring'
|
|
102
|
+
|
|
103
|
+
# Bootstrap 5 link-utility "families" whose defaults must not silently
|
|
104
|
+
# override an author's own explicit class from the same family — see
|
|
105
|
+
# classes_to_add_for.
|
|
106
|
+
#
|
|
107
|
+
# Each entry carries a single `pattern:` regex, anchored \A...\z and
|
|
108
|
+
# matched per class token (not against the whole class string), so a
|
|
109
|
+
# compound name like "social-link-danger" or "sidebar-link-offset-2" is
|
|
110
|
+
# never mistaken for an override.
|
|
111
|
+
#
|
|
112
|
+
# Enumerated families (offset, both opacity families) lock to Bootstrap's
|
|
113
|
+
# fixed value set, so an out-of-range value like "link-opacity-42" isn't
|
|
114
|
+
# recognized as an override either. Color and focus-ring families
|
|
115
|
+
# (link-{color}, link-underline-{color}, focus-ring(-{color})?) stay
|
|
116
|
+
# generic (\S+) since Bootstrap themes can define arbitrary custom color names.
|
|
117
|
+
LINK_CLASS_FAMILIES = [
|
|
118
|
+
{ # link-{color}, e.g. link-primary, link-body-emphasis (bare colored-link class;
|
|
119
|
+
# excludes link-underline-*, link-offset-*, and link-opacity-* families)
|
|
120
|
+
pattern: /\Alink-(?!underline\b|offset-|opacity-)\S+\z/
|
|
121
|
+
},
|
|
122
|
+
{ # link-underline-{color}, e.g. link-underline-success (excludes -opacity-*)
|
|
123
|
+
pattern: /\Alink-underline-(?!opacity)\S+\z/
|
|
124
|
+
},
|
|
125
|
+
{ # link-offset-{1,2,3}, each with an optional -hover variant
|
|
126
|
+
pattern: /\Alink-offset-[123](-hover)?\z/
|
|
127
|
+
},
|
|
128
|
+
{ # link-underline-opacity-{0,10,25,50,75,100}, each with an optional -hover variant
|
|
129
|
+
pattern: /\Alink-underline-opacity-(?:0|10|25|50|75|100)(-hover)?\z/
|
|
130
|
+
},
|
|
131
|
+
{ # link-opacity-{10,25,50,75,100}, each with an optional -hover variant
|
|
132
|
+
# (controls link-text opacity, distinct from link-underline-opacity-*)
|
|
133
|
+
pattern: /\Alink-opacity-(?:10|25|50|75|100)(-hover)?\z/
|
|
134
|
+
},
|
|
135
|
+
{ # focus-ring and focus-ring-{color}, e.g. focus-ring-primary, focus-ring-success
|
|
136
|
+
# Bootstrap 5.3 focus-ring has no hover, offset, or opacity variants — only bare
|
|
137
|
+
# and color forms; color stays generic (\S+) for custom theme colors
|
|
138
|
+
pattern: /\Afocus-ring(-\S+)?\z/
|
|
139
|
+
}
|
|
140
|
+
].freeze
|
|
103
141
|
DEFAULT_EXTERNAL_LINK_ICON = true
|
|
104
142
|
DEFAULT_EXTERNAL_LINK_ICON_EXCLUDED_TAGS = [].freeze
|
|
105
143
|
DEFAULT_HEADING_ANCHOR = false
|
|
@@ -177,9 +215,8 @@ module Jekyll
|
|
|
177
215
|
link['target'] = '_blank'
|
|
178
216
|
end
|
|
179
217
|
|
|
180
|
-
# Add
|
|
181
|
-
#
|
|
182
|
-
# Preserves any existing rel attribute values
|
|
218
|
+
# Add rel="noopener noreferrer" to target="_blank" links, preserving
|
|
219
|
+
# any existing rel attribute values
|
|
183
220
|
def add_external_target_protection(link)
|
|
184
221
|
target = link['target'].to_s
|
|
185
222
|
|
|
@@ -256,12 +293,20 @@ module Jekyll
|
|
|
256
293
|
doc.css('a:not(.btn)').each do |link|
|
|
257
294
|
next if link.ancestors('p.alert, blockquote.alert').any?
|
|
258
295
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
296
|
+
add_classes(link, classes_to_add_for(link, default_classes))
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
# Drops any default class belonging to a family the link already customizes,
|
|
301
|
+
# so the author's explicit class wins instead of losing silently to a
|
|
302
|
+
# same-specificity Bootstrap !important rule declared later in the sheet.
|
|
303
|
+
# See LINK_CLASS_FAMILIES for how each family's pattern is matched.
|
|
304
|
+
def classes_to_add_for(link, default_classes)
|
|
305
|
+
link_classes = link['class'].to_s.split
|
|
306
|
+
LINK_CLASS_FAMILIES.reduce(default_classes) do |classes, family|
|
|
307
|
+
next classes unless link_classes.any? { |token| token.match?(family[:pattern]) }
|
|
308
|
+
|
|
309
|
+
classes.split.grep_v(family[:pattern]).join(' ')
|
|
265
310
|
end
|
|
266
311
|
end
|
|
267
312
|
|
|
@@ -347,7 +392,7 @@ module Jekyll
|
|
|
347
392
|
|
|
348
393
|
private :add_heading_anchors, :resolve_heading_id, :slugify
|
|
349
394
|
|
|
350
|
-
# Add external-link icon to cross-domain
|
|
395
|
+
# Add external-link icon to cross-domain links
|
|
351
396
|
def add_external_icon(link, site_domain, config, doc)
|
|
352
397
|
external_link_icon = config.fetch('external_link_icon', DEFAULT_EXTERNAL_LINK_ICON)
|
|
353
398
|
|