jekyll_picture_tag 1.2.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 +7 -0
- data/.gitignore +11 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +24 -0
- data/Rakefile +1 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/examples/_config.yml +4 -0
- data/examples/_data/picture.yml +85 -0
- data/examples/post.md +18 -0
- data/jekyll_picture_tag.gemspec +39 -0
- data/lib/jekyll_picture_tag.rb +67 -0
- data/lib/jekyll_picture_tag/defaults/global.yml +10 -0
- data/lib/jekyll_picture_tag/defaults/presets.yml +7 -0
- data/lib/jekyll_picture_tag/generated_image.rb +66 -0
- data/lib/jekyll_picture_tag/instructions.rb +105 -0
- data/lib/jekyll_picture_tag/instructions/configuration.rb +82 -0
- data/lib/jekyll_picture_tag/instructions/html_attributes.rb +59 -0
- data/lib/jekyll_picture_tag/instructions/preset.rb +61 -0
- data/lib/jekyll_picture_tag/instructions/tag_parser.rb +48 -0
- data/lib/jekyll_picture_tag/output_formats.rb +9 -0
- data/lib/jekyll_picture_tag/output_formats/auto.rb +15 -0
- data/lib/jekyll_picture_tag/output_formats/basics.rb +105 -0
- data/lib/jekyll_picture_tag/output_formats/data_attributes.rb +44 -0
- data/lib/jekyll_picture_tag/output_formats/data_auto.rb +14 -0
- data/lib/jekyll_picture_tag/output_formats/data_img.rb +8 -0
- data/lib/jekyll_picture_tag/output_formats/data_picture.rb +8 -0
- data/lib/jekyll_picture_tag/output_formats/direct_url.rb +13 -0
- data/lib/jekyll_picture_tag/output_formats/img.rb +24 -0
- data/lib/jekyll_picture_tag/output_formats/picture.rb +66 -0
- data/lib/jekyll_picture_tag/source_image.rb +62 -0
- data/lib/jekyll_picture_tag/srcsets.rb +3 -0
- data/lib/jekyll_picture_tag/srcsets/basics.rb +88 -0
- data/lib/jekyll_picture_tag/srcsets/pixel_ratio.rb +32 -0
- data/lib/jekyll_picture_tag/srcsets/width.rb +45 -0
- data/lib/jekyll_picture_tag/utils.rb +67 -0
- data/lib/jekyll_picture_tag/version.rb +3 -0
- data/migration.md +178 -0
- data/readme.md +787 -0
- metadata +191 -0
@@ -0,0 +1,82 @@
|
|
1
|
+
module PictureTag
|
2
|
+
module Instructions
|
3
|
+
# Global config (big picture). loads jekyll data/config files, and the j-p-t
|
4
|
+
# defaults from included yml files.
|
5
|
+
class Configuration
|
6
|
+
def initialize
|
7
|
+
@content = build_config
|
8
|
+
end
|
9
|
+
|
10
|
+
def [](key)
|
11
|
+
@content[key]
|
12
|
+
end
|
13
|
+
|
14
|
+
# Site.source is the master jekyll source directory
|
15
|
+
# Source dir is the jekyll-picture-tag source directory.
|
16
|
+
def source_dir
|
17
|
+
File.join PictureTag.site.source, self['picture']['source']
|
18
|
+
end
|
19
|
+
|
20
|
+
# site.dest is the master jekyll destination directory
|
21
|
+
# source_dest is the jekyll-picture-tag destination directory. (generated
|
22
|
+
# file location setting.)
|
23
|
+
def dest_dir
|
24
|
+
File.join PictureTag.site.dest, self['picture']['output']
|
25
|
+
end
|
26
|
+
|
27
|
+
# Takes our config into account. Generated images, not source
|
28
|
+
def build_url(filename)
|
29
|
+
File.join url_prefix, self['picture']['output'], filename
|
30
|
+
end
|
31
|
+
|
32
|
+
# For linking source images
|
33
|
+
def build_source_url(filename)
|
34
|
+
File.join url_prefix, self['picture']['source'], filename
|
35
|
+
end
|
36
|
+
|
37
|
+
def nomarkdown?
|
38
|
+
Utils.markdown_page? && self['picture']['nomarkdown']
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def build_config
|
44
|
+
YAML.safe_load(
|
45
|
+
# Jekyll Picture Tag Default settings
|
46
|
+
File.read(
|
47
|
+
File.join(ROOT_PATH, 'jekyll_picture_tag/defaults/global.yml')
|
48
|
+
)
|
49
|
+
).merge(
|
50
|
+
# _config.yml defined settings
|
51
|
+
PictureTag.site.config
|
52
|
+
) do |_key, jpt_default, site_value|
|
53
|
+
setting_merge(jpt_default, site_value)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def setting_merge(jpt_default, site_value)
|
58
|
+
if site_value.nil?
|
59
|
+
# Jekyll baseurl is nil if not configured, which breaks things.
|
60
|
+
# jpt_default is an empty string, which doesn't.
|
61
|
+
jpt_default
|
62
|
+
elsif site_value.is_a? Hash
|
63
|
+
# We'll merge hashes one level deep. If we need true deep merging,
|
64
|
+
# we'll import a gem or do something recursive.
|
65
|
+
jpt_default.merge site_value
|
66
|
+
else
|
67
|
+
site_value
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# https://example.com/my-base-path/assets/generated-images/image.jpg
|
72
|
+
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
73
|
+
# | site url | site path | j-p-t dest dir |
|
74
|
+
def url_prefix
|
75
|
+
File.join(
|
76
|
+
self['picture']['relative_url'] ? '' : PictureTag.config['url'],
|
77
|
+
PictureTag.config['baseurl'],
|
78
|
+
)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module PictureTag
|
2
|
+
module Instructions
|
3
|
+
# Handles HTML attributes, sourced from configuration and the liquid tag,
|
4
|
+
# sent to various elements.
|
5
|
+
# Stored as a hash, with string keys.
|
6
|
+
class HTMLAttributeSet
|
7
|
+
# Initialize with leftovers passed into the liquid tag
|
8
|
+
def initialize(params)
|
9
|
+
@content = load_preset
|
10
|
+
|
11
|
+
parse_params(params) if params
|
12
|
+
handle_url
|
13
|
+
end
|
14
|
+
|
15
|
+
def [](key)
|
16
|
+
@content[key]
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def load_preset
|
22
|
+
PictureTag.preset['attributes'] || {}
|
23
|
+
end
|
24
|
+
|
25
|
+
# Syntax this function processes:
|
26
|
+
# class="old way" --picture class="new way" --alt Here's my alt text
|
27
|
+
def parse_params(params)
|
28
|
+
params_array = params.split(/\s+--/).map(&:strip)
|
29
|
+
|
30
|
+
# This allows the old tag syntax to work.
|
31
|
+
@content['implicit'] = params_array.shift unless params.strip =~ /^--/
|
32
|
+
|
33
|
+
# Split function above doesn't take the dashes off the first param.
|
34
|
+
params_array.first.delete_prefix! '--' if params_array.any?
|
35
|
+
|
36
|
+
params_array.each do |param|
|
37
|
+
# Splits on spaces, the first word will be our key.
|
38
|
+
a = param.split
|
39
|
+
|
40
|
+
# Supplied tag arguments will overwrite (not append) configured values
|
41
|
+
@content[a.shift] = a.join(' ')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
# Handles anchor tag destination. Can come from 2 places in 2 formats:
|
45
|
+
# Can come from defaults, preset, or tag
|
46
|
+
# Default is false. Preset can specify either true or false
|
47
|
+
# Tag params can be a URL
|
48
|
+
|
49
|
+
# picture test.jpg --url http://example.com
|
50
|
+
def handle_url
|
51
|
+
return unless PictureTag.preset['link_source'] && !self['link']
|
52
|
+
|
53
|
+
@content['link'] = PictureTag.build_source_url(
|
54
|
+
Utils.biggest_source.shortname
|
55
|
+
)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module PictureTag
|
2
|
+
module Instructions
|
3
|
+
# Handles the specific tag image set to construct.
|
4
|
+
class Preset
|
5
|
+
attr_reader :name
|
6
|
+
def initialize
|
7
|
+
@name = PictureTag.preset_name
|
8
|
+
@content = build_preset
|
9
|
+
end
|
10
|
+
|
11
|
+
def [](key)
|
12
|
+
@content[key]
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns the set of widths to use for a given media query.
|
16
|
+
def widths(media)
|
17
|
+
width_hash = self['media_widths'] || {}
|
18
|
+
width_hash.default = self['widths']
|
19
|
+
width_hash[media]
|
20
|
+
end
|
21
|
+
|
22
|
+
def fallback_format
|
23
|
+
PictureTag::Utils.process_format(@content['fallback_format'], nil)
|
24
|
+
end
|
25
|
+
|
26
|
+
def fallback_width
|
27
|
+
@content['fallback_width']
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def build_preset
|
33
|
+
# The _data/picture.yml file is optional.
|
34
|
+
picture_data_file = grab_data_file
|
35
|
+
|
36
|
+
default_preset.merge picture_data_file
|
37
|
+
end
|
38
|
+
|
39
|
+
def default_preset
|
40
|
+
YAML.safe_load File.read(
|
41
|
+
File.join(ROOT_PATH, 'jekyll_picture_tag/defaults/presets.yml')
|
42
|
+
)
|
43
|
+
end
|
44
|
+
|
45
|
+
def grab_data_file
|
46
|
+
PictureTag.site
|
47
|
+
.data
|
48
|
+
.dig('picture', 'markup_presets', @name) || no_preset
|
49
|
+
end
|
50
|
+
|
51
|
+
def no_preset
|
52
|
+
Utils.warning(
|
53
|
+
" Preset \"#{@name}\" not found in _data/picture.yml under "\
|
54
|
+
'markup_presets key. Using default values.'
|
55
|
+
)
|
56
|
+
|
57
|
+
{}
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module PictureTag
|
2
|
+
module Instructions
|
3
|
+
# This class takes the string given to the jekyll tag, and extracts useful
|
4
|
+
# information from it.
|
5
|
+
class TagParser
|
6
|
+
attr_reader :preset_name, :source_images, :html_attributes_raw
|
7
|
+
def initialize(raw_params)
|
8
|
+
@params = PictureTag::Utils.liquid_lookup(raw_params).split
|
9
|
+
|
10
|
+
@preset_name = grab_preset_name
|
11
|
+
|
12
|
+
# source_image keys are media queries, values are source images. The
|
13
|
+
# first param specified will be our base image, so it has no associated
|
14
|
+
# media query. Yes, nil can be a hash key.
|
15
|
+
source_image_names = { nil => @params.shift }
|
16
|
+
|
17
|
+
# Store source keys which fit a pattern in a hash.
|
18
|
+
while @params.first =~ /[\w\-]+:/
|
19
|
+
media_query = @params.shift[0..-2]
|
20
|
+
source_image_names[media_query] = @params.shift
|
21
|
+
end
|
22
|
+
|
23
|
+
@source_images = build_sources(source_image_names)
|
24
|
+
|
25
|
+
# Anything left will be html attributes
|
26
|
+
@html_attributes_raw = @params.join(' ')
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
# First param is the preset name, unless it's a filename.
|
32
|
+
def grab_preset_name
|
33
|
+
if @params.first =~ %r{[\w./]+\.\w+}
|
34
|
+
'default'
|
35
|
+
else
|
36
|
+
@params.shift
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Takes filenames relative to JPT source directory. SourceImage instances
|
41
|
+
# persist within a tag, allowing us to only perform some expensive File
|
42
|
+
# operations once.
|
43
|
+
def build_sources(names)
|
44
|
+
names.transform_values { |n| PictureTag::SourceImage.new n }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require_relative 'output_formats/basics'
|
2
|
+
require_relative 'output_formats/data_attributes'
|
3
|
+
require_relative 'output_formats/auto'
|
4
|
+
require_relative 'output_formats/img'
|
5
|
+
require_relative 'output_formats/picture'
|
6
|
+
require_relative 'output_formats/data_auto'
|
7
|
+
require_relative 'output_formats/data_picture'
|
8
|
+
require_relative 'output_formats/data_img'
|
9
|
+
require_relative 'output_formats/direct_url'
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module PictureTag
|
2
|
+
module OutputFormats
|
3
|
+
# This is an odd class, which never returns itself. It selects the most
|
4
|
+
# appropriate format, and returns an instance of that class.
|
5
|
+
class Auto
|
6
|
+
def self.new
|
7
|
+
if PictureTag::Utils.count_srcsets > 1
|
8
|
+
Picture.new
|
9
|
+
else
|
10
|
+
Img.new
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module PictureTag
|
2
|
+
# Contains all possible HTML output format options. Auto is considered its
|
3
|
+
# own option.
|
4
|
+
module OutputFormats
|
5
|
+
# Generic functions common to all output formats.
|
6
|
+
module Basics
|
7
|
+
include ObjectiveElements
|
8
|
+
|
9
|
+
# Used for both the fallback image, and for the complete markup.
|
10
|
+
def build_base_img
|
11
|
+
img = SingleTag.new 'img'
|
12
|
+
attributes = PictureTag.html_attributes
|
13
|
+
|
14
|
+
img.attributes << attributes['img']
|
15
|
+
img.attributes << attributes['implicit']
|
16
|
+
|
17
|
+
fallback = build_fallback_image
|
18
|
+
|
19
|
+
add_src(img, fallback.name)
|
20
|
+
|
21
|
+
add_alt(img, attributes['alt'])
|
22
|
+
|
23
|
+
img
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_s
|
27
|
+
wrap(base_markup).to_s
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
# Handles various wrappers around basic markup
|
33
|
+
def wrap(markup)
|
34
|
+
markup = anchor_tag(markup) if PictureTag.html_attributes['link']
|
35
|
+
markup = nomarkdown_wrapper(markup.to_s) if PictureTag.nomarkdown?
|
36
|
+
|
37
|
+
markup
|
38
|
+
end
|
39
|
+
|
40
|
+
def build_srcset(media, format)
|
41
|
+
if PictureTag.preset['pixel_ratios']
|
42
|
+
build_pixel_ratio_srcset(media, format)
|
43
|
+
else
|
44
|
+
build_width_srcset(media, format)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def build_pixel_ratio_srcset(media, format)
|
49
|
+
Srcsets::PixelRatio.new(media: media, format: format)
|
50
|
+
end
|
51
|
+
|
52
|
+
def build_width_srcset(media, format)
|
53
|
+
Srcsets::Width.new(media: media, format: format)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Extracting these functions to their own methods for easy overriding.
|
57
|
+
# They are destructive.
|
58
|
+
def add_src(element, name)
|
59
|
+
element.src = PictureTag.build_url name
|
60
|
+
end
|
61
|
+
|
62
|
+
def add_srcset(element, srcset)
|
63
|
+
element.srcset = srcset.to_s
|
64
|
+
end
|
65
|
+
|
66
|
+
def add_sizes(element, srcset)
|
67
|
+
element.sizes = srcset.sizes if srcset.sizes
|
68
|
+
end
|
69
|
+
|
70
|
+
def add_alt(element, alt)
|
71
|
+
element.alt = alt if alt
|
72
|
+
end
|
73
|
+
|
74
|
+
def add_media(element, srcset)
|
75
|
+
element.media = srcset.media_attribute if srcset.media
|
76
|
+
end
|
77
|
+
|
78
|
+
# File, not HTML
|
79
|
+
def build_fallback_image
|
80
|
+
GeneratedImage.new(
|
81
|
+
source_file: PictureTag.source_images[nil],
|
82
|
+
format: PictureTag.fallback_format,
|
83
|
+
width: PictureTag.fallback_width
|
84
|
+
)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Stops kramdown from molesting our output
|
88
|
+
# Must be given a string.
|
89
|
+
#
|
90
|
+
# Kramdown is super picky about the {::nomarkdown} extension-- we have to
|
91
|
+
# strip line breaks or nothing works.
|
92
|
+
def nomarkdown_wrapper(content)
|
93
|
+
"{::nomarkdown}#{content.delete("\n")}{:/nomarkdown}"
|
94
|
+
end
|
95
|
+
|
96
|
+
def anchor_tag(content)
|
97
|
+
anchor = DoubleTag.new 'a'
|
98
|
+
anchor.attributes << PictureTag.html_attributes['a']
|
99
|
+
anchor.href = PictureTag.html_attributes['link']
|
100
|
+
|
101
|
+
content.add_parent anchor
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module PictureTag
|
2
|
+
module OutputFormats
|
3
|
+
# This is not an output format, it's a module for use in others. It allows
|
4
|
+
# us to create JavaScript Library friendly markup, for things like LazyLoad
|
5
|
+
module DataAttributes
|
6
|
+
def base_markup
|
7
|
+
build_noscript(super)
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def add_src(element, name)
|
13
|
+
element.attributes << { 'data-src' => PictureTag.build_url(name) }
|
14
|
+
end
|
15
|
+
|
16
|
+
def add_srcset(element, srcset)
|
17
|
+
element.attributes << { 'data-srcset' => srcset.to_s }
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_sizes(element, srcset)
|
21
|
+
element.attributes << { 'data-sizes' => srcset.sizes } if srcset.sizes
|
22
|
+
end
|
23
|
+
|
24
|
+
def build_noscript(base_content)
|
25
|
+
return base_content unless PictureTag.preset['noscript']
|
26
|
+
|
27
|
+
noscript = DoubleTag.new(
|
28
|
+
'noscript',
|
29
|
+
content: Img.new.build_base_img,
|
30
|
+
|
31
|
+
# Markdown fix requires removal of line breaks:
|
32
|
+
oneline: PictureTag.nomarkdown?
|
33
|
+
).to_s
|
34
|
+
|
35
|
+
ShelfTag.new(
|
36
|
+
content: [base_content, noscript],
|
37
|
+
|
38
|
+
# Markdown fix requires removal of line breaks:
|
39
|
+
oneline: PictureTag.nomarkdown?
|
40
|
+
)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module PictureTag
|
2
|
+
module OutputFormats
|
3
|
+
# Similar to Auto, but sets data-src (and so on) instead of src
|
4
|
+
class DataAuto < Auto
|
5
|
+
def self.new
|
6
|
+
if PictureTag::Utils.count_srcsets > 1
|
7
|
+
DataPicture.new
|
8
|
+
else
|
9
|
+
DataImg.new
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|