jekyll-link-decorator 1.5.1 → 1.5.2
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 +83 -43
- 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: 85919ec3882d487b1545ce0508fde30b74c0fd59e35f2823a8da4b4659437004
|
|
4
|
+
data.tar.gz: b558d2dbd36f937a5f03a670a519439d14f54625d948123977ed38ec67076af4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5a1011beabc1ebf913123b8aff0c38c747afd70c2ee572e16aa35c0d5cebd9ae9226d92ee47fda28dd7a6ac5a6ddd77956d29906faee86b62a1bfc08977cd98e
|
|
7
|
+
data.tar.gz: 6498a39d46641219f4939b9c3becf8b5693441c9b69ed0726d1c49cb7bfff0635df4817b13e1fe6c66befd6e5ca5bda64f500abdd681a443199bb28cbbe52408
|
|
@@ -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-*`, or `link-opacity-*` 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,10 +58,10 @@
|
|
|
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
|
|
@@ -92,14 +92,47 @@ 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
100
|
'link-underline-opacity-0 link-underline-opacity-100-hover'
|
|
102
101
|
DEFAULT_ALERT_LINK_CLASSES = 'alert-link'
|
|
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 families (link-{color},
|
|
115
|
+
# link-underline-{color}) stay generic (\S+) since Bootstrap themes can
|
|
116
|
+
# 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
|
+
].freeze
|
|
103
136
|
DEFAULT_EXTERNAL_LINK_ICON = true
|
|
104
137
|
DEFAULT_EXTERNAL_LINK_ICON_EXCLUDED_TAGS = [].freeze
|
|
105
138
|
DEFAULT_HEADING_ANCHOR = false
|
|
@@ -177,9 +210,8 @@ module Jekyll
|
|
|
177
210
|
link['target'] = '_blank'
|
|
178
211
|
end
|
|
179
212
|
|
|
180
|
-
# Add
|
|
181
|
-
#
|
|
182
|
-
# Preserves any existing rel attribute values
|
|
213
|
+
# Add rel="noopener noreferrer" to target="_blank" links, preserving
|
|
214
|
+
# any existing rel attribute values
|
|
183
215
|
def add_external_target_protection(link)
|
|
184
216
|
target = link['target'].to_s
|
|
185
217
|
|
|
@@ -256,12 +288,20 @@ module Jekyll
|
|
|
256
288
|
doc.css('a:not(.btn)').each do |link|
|
|
257
289
|
next if link.ancestors('p.alert, blockquote.alert').any?
|
|
258
290
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
291
|
+
add_classes(link, classes_to_add_for(link, default_classes))
|
|
292
|
+
end
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
# Drops any default class belonging to a family the link already customizes,
|
|
296
|
+
# so the author's explicit class wins instead of losing silently to a
|
|
297
|
+
# same-specificity Bootstrap !important rule declared later in the sheet.
|
|
298
|
+
# See LINK_CLASS_FAMILIES for how each family's pattern is matched.
|
|
299
|
+
def classes_to_add_for(link, default_classes)
|
|
300
|
+
link_classes = link['class'].to_s.split
|
|
301
|
+
LINK_CLASS_FAMILIES.reduce(default_classes) do |classes, family|
|
|
302
|
+
next classes unless link_classes.any? { |token| token.match?(family[:pattern]) }
|
|
303
|
+
|
|
304
|
+
classes.split.grep_v(family[:pattern]).join(' ')
|
|
265
305
|
end
|
|
266
306
|
end
|
|
267
307
|
|
|
@@ -347,7 +387,7 @@ module Jekyll
|
|
|
347
387
|
|
|
348
388
|
private :add_heading_anchors, :resolve_heading_id, :slugify
|
|
349
389
|
|
|
350
|
-
# Add external-link icon to cross-domain
|
|
390
|
+
# Add external-link icon to cross-domain links
|
|
351
391
|
def add_external_icon(link, site_domain, config, doc)
|
|
352
392
|
external_link_icon = config.fetch('external_link_icon', DEFAULT_EXTERNAL_LINK_ICON)
|
|
353
393
|
|