]*)>\s*!
+ OPENING_BODY_TAG_REGEX = %r!]*)>\s*!.freeze
class << self
# Public: Processes the content and updated the external links
@@ -117,13 +117,9 @@ def configure_adding_additional_css_classes
# Private: Handles the default rel attribute values
def add_default_rel_attributes?
- if should_not_include_noopener?
- @should_add_noopener = false
- end
+ @should_add_noopener = false if should_not_include_noopener?
- if should_not_include_noreferrer?
- @should_add_noreferrrer = false
- end
+ @should_add_noreferrrer = false if should_not_include_noreferrer?
end
# Private: Sets any extra rel attribute values
@@ -142,7 +138,7 @@ def add_css_classes_if_required(link)
if @should_add_css_classes
existing_classes = get_existing_css_classes(link)
existing_classes = " " + existing_classes unless existing_classes.to_s.empty?
- link["class"] = @css_classes_to_add + existing_classes
+ link["class"] = @css_classes_to_add + existing_classes
end
end
@@ -158,27 +154,30 @@ def add_target_blank_attribute(link)
# link = Nokogiri node.
def add_rel_attributes(link)
rel = ""
- if @should_add_noopener
- rel = "noopener"
- end
+ rel = add_noopener_to_rel(rel)
if @should_add_noreferrrer
- unless rel.empty?
- rel += " "
- end
+ rel += " " unless rel.empty?
rel += "noreferrer"
end
if @should_add_extra_rel_attribute_values
- unless rel.empty?
- rel += " "
- end
+ rel += " " unless rel.empty?
rel += @extra_rel_attribute_values
end
- unless rel.empty?
- link["rel"] = rel
+ link["rel"] = rel unless rel.empty?
+ end
+
+ # Private: Adds noopener attribute.
+ #
+ # rel = string
+ def add_noopener_to_rel(rel)
+ if @should_add_noopener
+ rel += " " unless rel.empty?
+ rel += "noopener"
end
+ rel
end
# Private: Checks if the link is a mailto url.
@@ -193,7 +192,7 @@ def not_mailto_link?(link)
#
# link - a url.
def external?(link)
- if link =~ URI.regexp(%w(http https))
+ if link&.match?(URI.regexp(%w(http https)))
URI.parse(link).host != URI.parse(@site_url).host
end
end
@@ -332,6 +331,6 @@ def class_config
end
# Hooks into Jekyll's post_render event.
-Jekyll::Hooks.register %i[pages documents], :post_render do |doc|
+Jekyll::Hooks.register [:pages, :documents], :post_render do |doc|
Jekyll::TargetBlank.process(doc) if Jekyll::TargetBlank.document_processable?(doc)
end
diff --git a/lib/jekyll-target-blank/version.rb b/lib/jekyll-target-blank/version.rb
index 7407b3f..f137b4a 100644
--- a/lib/jekyll-target-blank/version.rb
+++ b/lib/jekyll-target-blank/version.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
module JekyllTargetBlank
- VERSION = "1.2.0"
+ VERSION = "2.0.0"
end
diff --git a/spec/jekyll-target_spec.rb b/spec/jekyll-target_spec.rb
index 30906f8..06987e0 100644
--- a/spec/jekyll-target_spec.rb
+++ b/spec/jekyll-target_spec.rb
@@ -6,53 +6,51 @@
let(:config_overrides) { {} }
let(:config_overrides) do
{
- "url" => "https://keith-mifsud.me",
- "collections" => { "docs" => { "output" => "true" } },
+ 'url' => 'https://keith-mifsud.me',
+ 'collections' => { 'docs' => { 'output' => 'true' } }
}
end
let(:configs) do
Jekyll.configuration(config_overrides.merge(
- {
- "skip_config_files" => false,
- "collections" => { "docs" => { "output" => true } },
- "source" => unit_fixtures_dir,
- "destination" => unit_fixtures_dir("_site"),
- }
- ))
+ 'skip_config_files' => false,
+ 'collections' => { 'docs' => { 'output' => true } },
+ 'source' => unit_fixtures_dir,
+ 'destination' => unit_fixtures_dir('_site')
+ ))
end
let(:target_blank) { described_class }
let(:site) { Jekyll::Site.new(configs) }
let(:posts) { site.posts.docs.sort.reverse }
# get some fixtures
- let(:post_with_external_markdown_link) { find_by_title(posts, "Post with external markdown link") }
+ let(:post_with_external_markdown_link) { find_by_title(posts, 'Post with external markdown link') }
- let(:post_with_multiple_external_markdown_links) { find_by_title(posts, "Post with multiple external markdown links") }
+ let(:post_with_multiple_external_markdown_links) { find_by_title(posts, 'Post with multiple external markdown links') }
- let(:post_with_relative_markdown_link) { find_by_title(posts, "Post with relative markdown link") }
+ let(:post_with_relative_markdown_link) { find_by_title(posts, 'Post with relative markdown link') }
- let(:post_with_absolute_internal_markdown_link) { find_by_title(posts, "Post with absolute internal markdown link") }
+ let(:post_with_absolute_internal_markdown_link) { find_by_title(posts, 'Post with absolute internal markdown link') }
- let(:post_with_html_anchor_tag) { find_by_title(posts, "Post with html anchor tag") }
+ let(:post_with_html_anchor_tag) { find_by_title(posts, 'Post with html anchor tag') }
- let(:post_with_plain_text_link) { find_by_title(posts, "Post with plain text link") }
+ let(:post_with_plain_text_link) { find_by_title(posts, 'Post with plain text link') }
- let(:document_with_a_processable_link) { find_by_title(site.collections["docs"].docs, "Document with a processable link") }
+ let(:document_with_a_processable_link) { find_by_title(site.collections['docs'].docs, 'Document with a processable link') }
- let(:text_file) { find_by_title(site.collections["docs"].docs, "Text file") }
+ let(:text_file) { find_by_title(site.collections['docs'].docs, 'Text file') }
- let(:post_with_code_block) { find_by_title(posts, "Post with code block") }
- let(:document_with_liquid_tag) { find_by_title(site.collections["docs"].docs, "Document with liquid tag") }
+ let(:post_with_code_block) { find_by_title(posts, 'Post with code block') }
+ let(:document_with_liquid_tag) { find_by_title(site.collections['docs'].docs, 'Document with liquid tag') }
- let(:document_with_include) { find_by_title(site.collections["docs"].docs, "Document with include") }
+ let(:document_with_include) { find_by_title(site.collections['docs'].docs, 'Document with include') }
- let(:post_with_mailto_link) { find_by_title(posts, "Post with mailto link") }
+ let(:post_with_mailto_link) { find_by_title(posts, 'Post with mailto link') }
- let(:post_with_external_html_link_and_random_css_classes) { find_by_title(posts, "Post with external html link and random css classes") }
+ let(:post_with_external_html_link_and_random_css_classes) { find_by_title(posts, 'Post with external html link and random css classes') }
- let(:post_with_html_link_containing_the_specified_css_class) { find_by_title(posts, "Post with html link containing the specified css class") }
+ let(:post_with_html_link_containing_the_specified_css_class) { find_by_title(posts, 'Post with html link containing the specified css class') }
- let(:post_with_external_link_containing_the_specified_css_class_and_other_css_classes) { find_by_title(posts, "Post with external link containing the specified css class and other css classes") }
+ let(:post_with_external_link_containing_the_specified_css_class_and_other_css_classes) { find_by_title(posts, 'Post with external link containing the specified css class and other css classes') }
# define common wrappers.
def para(content)
@@ -66,50 +64,50 @@ def para(content)
site.render
end
- context "Without entries in config file" do
+ context 'Without entries in config file' do
let(:config_overrides) do
- { "target-blank" => { "add_css_classes" => false } }
+ { 'target-blank' => { 'add_css_classes' => false } }
end
- it "should add target attribute to external markdown link" do
+ it 'should add target attribute to external markdown link' do
expect(post_with_external_markdown_link.output).to include(para('Link to Google.'))
end
- it "should add target attribute to multiple external markdown links" do
+ it 'should add target attribute to multiple external markdown links' do
expect(post_with_multiple_external_markdown_links.output).to include('
This post contains three links. The first link is to Google, the second link is, well, to my website and since GitHub is so awesome, why not link to them too?
')
end
- it "should not add target attribute to relative markdown link" do
+ it 'should not add target attribute to relative markdown link' do
expect(post_with_relative_markdown_link.output).to include(para('Link to contact page.'))
expect(post_with_relative_markdown_link.output).to_not include(para('Link to contact page'))
end
- it "should not add target attribute to absolute internal link" do
+ it 'should not add target attribute to absolute internal link' do
expect(post_with_absolute_internal_markdown_link.output).to include('
')
end
- it "should correctly handle existing html anchor tag" do
+ it 'should correctly handle existing html anchor tag' do
expect(post_with_html_anchor_tag.output).to include('
')
end
- it "should not interfere with plain text link" do
- expect(post_with_plain_text_link.output).to include("
This is a plain text link to https://google.com.
")
+ it 'should not interfere with plain text link' do
+ expect(post_with_plain_text_link.output).to include('
This is a plain text link to https://google.com.
')
end
- it "should process external links in collections" do
+ it 'should process external links in collections' do
expect(document_with_a_processable_link.output).to include('
')
end
- it "should not process links in non html files" do
- expect(text_file.output).to eq("Valid [link](https://google.com).")
+ it 'should not process links in non html files' do
+ expect(text_file.output).to eq('Valid [link](https://google.com).')
end
- it "should not process link in code block but process link outside of block" do
+ it 'should not process link in code block but process link outside of block' do
expect(post_with_code_block.output).to include('\'https://google.com\'')
expect(post_with_code_block.output).not_to include('https://google.com')
@@ -117,307 +115,307 @@ def para(content)
expect(post_with_code_block.output).to include('
')
end
- it "should not break layouts" do
+ it 'should not break layouts' do
expect(site.pages.first.output).to include('')
expect(site.pages.first.output).to include('')
end
- it "should not interfere with liquid tags" do
+ it 'should not interfere with liquid tags' do
expect(document_with_liquid_tag.output).to include('
')
end
- it "should not interfere with includes" do
- expect(document_with_include.output).to include("
This is a document with an include: This is an include.
")
+ it 'should not interfere with includes' do
+ expect(document_with_include.output).to include('
This is a document with an include: This is an include.
')
end
- it "should not break layout content" do
- expect(site.pages.first.output).to include("
Layout content started.
")
+ it 'should not break layout content' do
+ expect(site.pages.first.output).to include('
Layout content started.
')
- expect(site.pages.first.output).to include("
Layout content ended.
")
+ expect(site.pages.first.output).to include('
Layout content ended.
')
end
- it "should not duplicate post content" do
+ it 'should not duplicate post content' do
expect(post_with_external_markdown_link.output).to eq(post_with_layout_result)
end
- it "should ignore mailto links" do
+ it 'should ignore mailto links' do
expect(post_with_mailto_link.output).to include(para('This is a mailto link.'))
end
end
- context "With a specified css class name" do
- let(:target_blank_css_class) { "ext-link" }
+ context 'With a specified css class name' do
+ let(:target_blank_css_class) { 'ext-link' }
let(:config_overrides) do
{
- "target-blank" => {
- "css_class" => target_blank_css_class,
- "add_css_classes" => false,
- },
+ 'target-blank' => {
+ 'css_class' => target_blank_css_class,
+ 'add_css_classes' => false
+ }
}
end
- it "should not add target attribute to external markdown link that does not have the specified css class" do
+ it 'should not add target attribute to external markdown link that does not have the specified css class' do
expect(post_with_external_markdown_link.output).to_not include(para('Link to Google.'))
end
- it "should not add target attribute to external markdown link that does not have the specified css class even if it does have other css classes" do
+ it 'should not add target attribute to external markdown link that does not have the specified css class even if it does have other css classes' do
expect(post_with_external_html_link_and_random_css_classes.output).to include(para('Link.'))
expect(post_with_external_html_link_and_random_css_classes.output).to_not include('target="_blank" rel="noopener noreferrer"')
end
- it "should add target attribute to an external link containing the specified css class" do
+ it 'should add target attribute to an external link containing the specified css class' do
expect(post_with_html_link_containing_the_specified_css_class.output).to include(para('Link with the css class specified in config.'))
end
- it "should add target attribute to an external link containing the specified css class even when other css classes are specified" do
+ it 'should add target attribute to an external link containing the specified css class even when other css classes are specified' do
expect(post_with_external_link_containing_the_specified_css_class_and_other_css_classes.output).to include(para('This is a link containing the specified css class and two other random css classes.'))
end
end
- context "Adds a CSS classes to the links" do
- let(:target_blank_add_css_class) { "some-class" }
+ context 'Adds a CSS classes to the links' do
+ let(:target_blank_add_css_class) { 'some-class' }
let(:config_overrides) do
- { "target-blank" => { "add_css_classes" => target_blank_add_css_class } }
+ { 'target-blank' => { 'add_css_classes' => target_blank_add_css_class } }
end
- it "should add the CSS class specified in config" do
+ it 'should add the CSS class specified in config' do
expect(post_with_external_markdown_link.output).to include(para('Link to Google.'))
end
- it "should add the CSS class specified in config even when the link already has a CSS class specified" do
+ it 'should add the CSS class specified in config even when the link already has a CSS class specified' do
expect(post_with_html_link_containing_the_specified_css_class.output).to include(para('Link with the css class specified in config.'))
end
- it "should add the CSS class specified in config even when the link has more than CSS classes already included" do
+ it 'should add the CSS class specified in config even when the link has more than CSS classes already included' do
expect(post_with_external_link_containing_the_specified_css_class_and_other_css_classes.output).to include(para('This is a link containing the specified css class and two other random css classes.'))
end
end
- context "When more than one CSS classes are specified in config" do
- it "should add the CSS classes specified in config" do
+ context 'When more than one CSS classes are specified in config' do
+ it 'should add the CSS classes specified in config' do
expect(post_with_external_markdown_link.output).to include(para('Link to Google.'))
end
- it "should add the CSS classes specified in config even when the link already has a CSS class included" do
+ it 'should add the CSS classes specified in config even when the link already has a CSS class included' do
expect(post_with_html_link_containing_the_specified_css_class.output).to include(para('Link with the css class specified in config.'))
end
- it "should add the CSS classes specified in config even when the link already has more than one CSS classes included" do
+ it 'should add the CSS classes specified in config even when the link already has more than one CSS classes included' do
expect(post_with_external_link_containing_the_specified_css_class_and_other_css_classes.output).to include(para('This is a link containing the specified css class and two other random css classes.'))
end
end
- context "When noopener is set to false in config" do
+ context 'When noopener is set to false in config' do
let(:noopener) { false }
let(:config_overrides) do
{
- "target-blank" => {
- "add_css_classes" => false,
- "noopener" => noopener,
- },
+ 'target-blank' => {
+ 'add_css_classes' => false,
+ 'noopener' => noopener
+ }
}
end
- it "should not add noopener value to the rel attribute" do
+ it 'should not add noopener value to the rel attribute' do
expect(post_with_external_markdown_link.output).to_not include(para('Link to Google.'))
end
- it "should still add noreferrer value to the rel attribute" do
+ it 'should still add noreferrer value to the rel attribute' do
expect(post_with_external_markdown_link.output).to include(para('Link to Google.'))
end
end
- context "When noreferrer is set to false in config" do
+ context 'When noreferrer is set to false in config' do
let(:noreferrer) { false }
let(:config_overrides) do
{
- "target-blank" => {
- "add_css_classes" => false,
- "noreferrer" => noreferrer,
- },
+ 'target-blank' => {
+ 'add_css_classes' => false,
+ 'noreferrer' => noreferrer
+ }
}
end
- it "should not add noreferrer value to the rel attribute" do
+ it 'should not add noreferrer value to the rel attribute' do
expect(post_with_external_markdown_link.output).to_not include(para('Link to Google.'))
end
- it "should still add noopener value to the rel attribute" do
+ it 'should still add noopener value to the rel attribute' do
expect(post_with_external_markdown_link.output).to include(para('Link to Google.'))
end
end
- context "When both noopener and noreferrer values are set to false in config" do
+ context 'When both noopener and noreferrer values are set to false in config' do
let(:noopener) { false }
let(:noreferrer) { false }
let(:config_overrides) do
{
- "target-blank" => {
- "add_css_classes" => false,
- "noopener" => noopener,
- "noreferrer" => noreferrer,
- },
+ 'target-blank' => {
+ 'add_css_classes' => false,
+ 'noopener' => noopener,
+ 'noreferrer' => noreferrer
+ }
}
end
- it "should not include the rel attribute values" do
+ it 'should not include the rel attribute values' do
expect(post_with_external_markdown_link.output).to_not include(para('Link to Google.'))
end
- it "should not include the rel attribute noopener value" do
+ it 'should not include the rel attribute noopener value' do
expect(post_with_external_markdown_link.output).to_not include(para('Link to Google.'))
end
- it "should not include the rel attribute noreferrer value" do
+ it 'should not include the rel attribute noreferrer value' do
expect(post_with_external_markdown_link.output).to_not include(para('Link to Google.'))
end
- it "should not include any rel attributes" do
+ it 'should not include any rel attributes' do
expect(post_with_external_markdown_link.output).to include(para('Link to Google.'))
end
end
- context "When one additional rel attribute is added in config" do
- let(:rel_attribute) { "nofollow" }
+ context 'When one additional rel attribute is added in config' do
+ let(:rel_attribute) { 'nofollow' }
let(:config_overrides) do
{
- "target-blank" => {
- "add_css_classes" => false,
- "rel" => rel_attribute,
- },
+ 'target-blank' => {
+ 'add_css_classes' => false,
+ 'rel' => rel_attribute
+ }
}
end
- it "should add the extra rel attribute together with the default ones" do
+ it 'should add the extra rel attribute together with the default ones' do
expect(post_with_external_markdown_link.output).to include(para('Link to Google.'))
end
end
- context "When more than one additional rel attributes are added in config" do
- let(:rel_attribute) { "nofollow tag" }
+ context 'When more than one additional rel attributes are added in config' do
+ let(:rel_attribute) { 'nofollow tag' }
let(:config_overrides) do
{
- "target-blank" => {
- "add_css_classes" => false,
- "rel" => rel_attribute,
- },
+ 'target-blank' => {
+ 'add_css_classes' => false,
+ 'rel' => rel_attribute
+ }
}
end
- it "should add the extra rel attributes together with the default ones" do
+ it 'should add the extra rel attributes together with the default ones' do
expect(post_with_external_markdown_link.output).to include(para('Link to Google.'))
end
end
- context "When one extra rel attribute value are set in config and noopener is set to false" do
- let(:rel_attribute) { "nofollow" }
+ context 'When one extra rel attribute value are set in config and noopener is set to false' do
+ let(:rel_attribute) { 'nofollow' }
let(:noopener) { false }
let(:config_overrides) do
{
- "target-blank" => {
- "add_css_classes" => false,
- "noopener" => noopener,
- "rel" => rel_attribute,
- },
+ 'target-blank' => {
+ 'add_css_classes' => false,
+ 'noopener' => noopener,
+ 'rel' => rel_attribute
+ }
}
end
- it "should the extra rel attribute value and not add the default noopener value" do
+ it 'should the extra rel attribute value and not add the default noopener value' do
expect(post_with_external_markdown_link.output).to include(para('Link to Google.'))
end
end
- context "When more than one extra rel attribute values are set in config and noopener is set to false" do
- let(:rel_attribute) { "nofollow tag" }
+ context 'When more than one extra rel attribute values are set in config and noopener is set to false' do
+ let(:rel_attribute) { 'nofollow tag' }
let(:noopener) { false }
let(:config_overrides) do
{
- "target-blank" => {
- "add_css_classes" => false,
- "noopener" => noopener,
- "rel" => rel_attribute,
- },
+ 'target-blank' => {
+ 'add_css_classes' => false,
+ 'noopener' => noopener,
+ 'rel' => rel_attribute
+ }
}
end
- it "should the extra rel attribute values and not add the default noopener value" do
+ it 'should the extra rel attribute values and not add the default noopener value' do
expect(post_with_external_markdown_link.output).to include(para('Link to Google.'))
end
end
- context "When one extra rel attributes is set in config and both noopener and noreferer are set to false" do
- let(:rel_attribute) { "nofollow" }
+ context 'When one extra rel attributes is set in config and both noopener and noreferer are set to false' do
+ let(:rel_attribute) { 'nofollow' }
let(:noopener) { false }
let(:noreferrer) { false }
let(:config_overrides) do
{
- "target-blank" => {
- "add_css_classes" => false,
- "noopener" => noopener,
- "noreferrer" => noreferrer,
- "rel" => rel_attribute,
- },
+ 'target-blank' => {
+ 'add_css_classes' => false,
+ 'noopener' => noopener,
+ 'noreferrer' => noreferrer,
+ 'rel' => rel_attribute
+ }
}
end
- it "should add the extra rel attribute value and no default ones" do
+ it 'should add the extra rel attribute value and no default ones' do
expect(post_with_external_markdown_link.output).to include(para('Link to Google.'))
end
end
- context "When more than one extra rel attribute values are set in config and both noopener and noreferer are set to false" do
- let(:rel_attribute) { "nofollow tag" }
+ context 'When more than one extra rel attribute values are set in config and both noopener and noreferer are set to false' do
+ let(:rel_attribute) { 'nofollow tag' }
let(:noopener) { false }
let(:noreferrer) { false }
let(:config_overrides) do
{
- "target-blank" => {
- "add_css_classes" => false,
- "noopener" => noopener,
- "noreferrer" => noreferrer,
- "rel" => rel_attribute,
- },
+ 'target-blank' => {
+ 'add_css_classes' => false,
+ 'noopener' => noopener,
+ 'noreferrer' => noreferrer,
+ 'rel' => rel_attribute
+ }
}
end
- it "should add the extra rel attribute values and no default ones" do
+ it 'should add the extra rel attribute values and no default ones' do
expect(post_with_external_markdown_link.output).to include(para('Link to Google.'))
end
end
- context "When noopener is set to false in config but added to the rel config property" do
- let(:rel_attribute) { "noopener" }
+ context 'When noopener is set to false in config but added to the rel config property' do
+ let(:rel_attribute) { 'noopener' }
let(:noopener) { false }
let(:config_overrides) do
{
- "target-blank" => {
- "add_css_classes" => false,
- "noopener" => noopener,
- "rel" => rel_attribute,
- },
+ 'target-blank' => {
+ 'add_css_classes' => false,
+ 'noopener' => noopener,
+ 'rel' => rel_attribute
+ }
}
end
- it "should still include the noopener rel attribute value" do
+ it 'should still include the noopener rel attribute value' do
expect(post_with_external_markdown_link.output).to include(para('Link to Google.'))
end
end
- context "When noopener is set to false in config but added t0 the rel config property alongside one more extra rel attribute value." do
- let(:rel_attribute) { "noopener nofollow" }
+ context 'When noopener is set to false in config but added t0 the rel config property alongside one more extra rel attribute value.' do
+ let(:rel_attribute) { 'noopener nofollow' }
let(:noopener) { false }
let(:config_overrides) do
{
- "target-blank" => {
- "add_css_classes" => false,
- "noopener" => noopener,
- "rel" => rel_attribute,
- },
+ 'target-blank' => {
+ 'add_css_classes' => false,
+ 'noopener' => noopener,
+ 'rel' => rel_attribute
+ }
}
end
- it "should still include the noopener rel attribute value along the extra one" do
+ it 'should still include the noopener rel attribute value along the extra one' do
expect(post_with_external_markdown_link.output).to include(para('Link to Google.'))
end
end
@@ -425,22 +423,22 @@ def para(content)
private
def post_with_layout_result
- <<-RESULT
-
-
-
-
- Post with external markdown link
-
-
-
-
-