jekyll-link-decorator 1.5.0 → 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/README.md +1 -1
- data/lib/jekyll-link-decorator/version.rb +1 -1
- data/lib/jekyll-link-decorator.rb +91 -53
- 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
|
data/README.md
CHANGED
|
@@ -1,67 +1,67 @@
|
|
|
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
|
|
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
|
-
# - `icon`:
|
|
55
|
-
#
|
|
56
|
-
#
|
|
57
|
-
#
|
|
58
|
-
#
|
|
59
|
-
#
|
|
54
|
+
# - `icon`: CSS classes applied to the anchor's glyph element (default:
|
|
55
|
+
# "heading-anchor-hash pe-1", which renders a plain "#" via the
|
|
56
|
+
# jekyll-theme-centos-base theme's CSS). Accepts any class list, including
|
|
57
|
+
# Font Awesome icon classes (e.g. "fa-solid fa-hashtag") for sites that
|
|
58
|
+
# want an icon-font glyph instead.
|
|
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
|
|
@@ -75,9 +75,7 @@
|
|
|
75
75
|
#
|
|
76
76
|
# with_heading_anchor: true
|
|
77
77
|
# with_heading_anchor_data:
|
|
78
|
-
# icon: "
|
|
79
|
-
# copy_success_message: "Copied!"
|
|
80
|
-
# reset_delay: 2000
|
|
78
|
+
# icon: "heading-anchor-hash pe-1"
|
|
81
79
|
# ```
|
|
82
80
|
|
|
83
81
|
require 'nokogiri'
|
|
@@ -94,18 +92,51 @@ EXISTING_ICON_SELECTORS = [
|
|
|
94
92
|
|
|
95
93
|
module Jekyll
|
|
96
94
|
module Converters
|
|
97
|
-
#
|
|
98
|
-
#
|
|
99
|
-
#
|
|
100
|
-
# 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.
|
|
101
98
|
class LinkDecorator < Jekyll::Converters::Markdown
|
|
102
99
|
DEFAULT_LINK_CLASSES = 'link link-offset-3 link-offset-3-hover link-underline-primary ' \
|
|
103
100
|
'link-underline-opacity-0 link-underline-opacity-100-hover'
|
|
104
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
|
|
105
136
|
DEFAULT_EXTERNAL_LINK_ICON = true
|
|
106
137
|
DEFAULT_EXTERNAL_LINK_ICON_EXCLUDED_TAGS = [].freeze
|
|
107
138
|
DEFAULT_HEADING_ANCHOR = false
|
|
108
|
-
DEFAULT_HEADING_ANCHOR_ICON = '
|
|
139
|
+
DEFAULT_HEADING_ANCHOR_ICON = 'heading-anchor-hash pe-1'
|
|
109
140
|
|
|
110
141
|
def self.name
|
|
111
142
|
'LinkDecorator'
|
|
@@ -179,9 +210,8 @@ module Jekyll
|
|
|
179
210
|
link['target'] = '_blank'
|
|
180
211
|
end
|
|
181
212
|
|
|
182
|
-
# Add
|
|
183
|
-
#
|
|
184
|
-
# Preserves any existing rel attribute values
|
|
213
|
+
# Add rel="noopener noreferrer" to target="_blank" links, preserving
|
|
214
|
+
# any existing rel attribute values
|
|
185
215
|
def add_external_target_protection(link)
|
|
186
216
|
target = link['target'].to_s
|
|
187
217
|
|
|
@@ -258,12 +288,20 @@ module Jekyll
|
|
|
258
288
|
doc.css('a:not(.btn)').each do |link|
|
|
259
289
|
next if link.ancestors('p.alert, blockquote.alert').any?
|
|
260
290
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
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(' ')
|
|
267
305
|
end
|
|
268
306
|
end
|
|
269
307
|
|
|
@@ -349,7 +387,7 @@ module Jekyll
|
|
|
349
387
|
|
|
350
388
|
private :add_heading_anchors, :resolve_heading_id, :slugify
|
|
351
389
|
|
|
352
|
-
# Add external-link icon to cross-domain
|
|
390
|
+
# Add external-link icon to cross-domain links
|
|
353
391
|
def add_external_icon(link, site_domain, config, doc)
|
|
354
392
|
external_link_icon = config.fetch('external_link_icon', DEFAULT_EXTERNAL_LINK_ICON)
|
|
355
393
|
|