jekyll_picture_tag 1.6.0 → 1.7.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/.rubocop.yml +2 -0
- data/.travis.yml +11 -0
- data/Gemfile +2 -2
- data/Rakefile +28 -0
- data/contributing.md +67 -0
- data/docs/examples/_config.yml +10 -0
- data/{examples → docs/examples}/_data/picture.yml +39 -19
- data/docs/examples/post.md +46 -0
- data/docs/global_configuration.md +115 -0
- data/docs/installation.md +30 -0
- data/docs/migration.md +178 -0
- data/docs/notes.md +85 -0
- data/docs/presets.md +407 -0
- data/docs/readme.md +23 -0
- data/docs/usage.md +131 -0
- data/jekyll-picture-tag.gemspec +3 -12
- data/jekyll_picture_tag.gemspec +8 -3
- data/lib/jekyll-picture-tag.rb +5 -3
- data/lib/jekyll_picture_tag.rb +45 -42
- data/lib/jekyll_picture_tag/defaults/global.yml +0 -3
- data/lib/jekyll_picture_tag/defaults/presets.yml +1 -0
- data/lib/jekyll_picture_tag/generated_image.rb +60 -39
- data/lib/jekyll_picture_tag/img_uri.rb +55 -0
- data/lib/jekyll_picture_tag/instructions.rb +1 -102
- data/lib/jekyll_picture_tag/instructions/configuration.rb +30 -74
- data/lib/jekyll_picture_tag/instructions/html_attributes.rb +18 -27
- data/lib/jekyll_picture_tag/instructions/preset.rb +14 -3
- data/lib/jekyll_picture_tag/instructions/set.rb +61 -0
- data/lib/jekyll_picture_tag/instructions/tag_parser.rb +80 -23
- data/lib/jekyll_picture_tag/output_formats.rb +1 -1
- data/lib/jekyll_picture_tag/output_formats/{basics.rb → basic.rb} +24 -19
- data/lib/jekyll_picture_tag/output_formats/data_attributes.rb +2 -2
- data/lib/jekyll_picture_tag/output_formats/direct_url.rb +1 -3
- data/lib/jekyll_picture_tag/output_formats/img.rb +4 -4
- data/lib/jekyll_picture_tag/output_formats/naked_srcset.rb +5 -4
- data/lib/jekyll_picture_tag/output_formats/picture.rb +6 -16
- data/lib/jekyll_picture_tag/output_formats/readme.md +8 -15
- data/lib/jekyll_picture_tag/router.rb +98 -0
- data/lib/jekyll_picture_tag/source_image.rb +15 -23
- data/lib/jekyll_picture_tag/srcsets.rb +1 -1
- data/lib/jekyll_picture_tag/srcsets/{basics.rb → basic.rb} +22 -13
- data/lib/jekyll_picture_tag/srcsets/pixel_ratio.rb +6 -11
- data/lib/jekyll_picture_tag/srcsets/width.rb +3 -11
- data/lib/jekyll_picture_tag/utils.rb +32 -49
- data/lib/jekyll_picture_tag/version.rb +1 -1
- data/readme.md +70 -70
- metadata +97 -16
- data/bin/console +0 -14
- data/bin/setup +0 -7
- data/examples/_config.yml +0 -4
- data/examples/post.md +0 -18
@@ -1,47 +1,104 @@
|
|
1
1
|
module PictureTag
|
2
2
|
module Instructions
|
3
|
-
# This
|
4
|
-
#
|
3
|
+
# This tag takes the arguments handed to the liquid tag, and extracts the
|
4
|
+
# preset name (if present), source image name(s), and associated media
|
5
|
+
# queries (if present). The leftovers (html attributes) are handed off to
|
6
|
+
# its respective class.
|
5
7
|
class TagParser
|
6
|
-
attr_reader :preset_name, :
|
8
|
+
attr_reader :preset_name, :source_names, :media_presets
|
7
9
|
def initialize(raw_params)
|
8
|
-
|
10
|
+
build_params PictureTag::Utils.liquid_lookup(raw_params)
|
9
11
|
|
10
12
|
@preset_name = grab_preset_name
|
11
13
|
|
12
|
-
#
|
13
|
-
#
|
14
|
-
|
15
|
-
|
14
|
+
# The first param specified will be our base image, so it has no
|
15
|
+
# associated media query.
|
16
|
+
@media_presets = []
|
17
|
+
@source_names = [] << strip_quotes(@params.shift)
|
16
18
|
|
17
|
-
#
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
end
|
22
|
-
|
23
|
-
@source_images = build_sources(source_image_names)
|
19
|
+
# Detect and store arguments of the format 'media_query: img.jpg' as
|
20
|
+
# keys and values.
|
21
|
+
add_media_source while @params.first =~ /[\w\-]+:$/
|
22
|
+
end
|
24
23
|
|
25
|
-
|
26
|
-
@
|
24
|
+
def leftovers
|
25
|
+
@params
|
27
26
|
end
|
28
27
|
|
29
28
|
private
|
30
29
|
|
30
|
+
def add_media_source
|
31
|
+
@media_presets << @params.shift.delete_suffix(':')
|
32
|
+
@source_names << strip_quotes(@params.shift)
|
33
|
+
end
|
34
|
+
|
31
35
|
# First param is the preset name, unless it's a filename.
|
32
36
|
def grab_preset_name
|
33
|
-
if @params.first
|
37
|
+
if @params.first.include? '.'
|
34
38
|
'default'
|
35
39
|
else
|
36
40
|
@params.shift
|
37
41
|
end
|
38
42
|
end
|
39
43
|
|
40
|
-
#
|
41
|
-
#
|
42
|
-
#
|
43
|
-
|
44
|
-
|
44
|
+
# Originally separating arguments was just handled by splitting the raw
|
45
|
+
# params on spaces. To handle quotes and backslash escaping, we have to
|
46
|
+
# parse the string by characters to break it up correctly. I'm sure
|
47
|
+
# there's a library to do this, but it's not that much code honestly. If
|
48
|
+
# this starts getting big, we'll pull in a new dependency.
|
49
|
+
def build_params(raw_params)
|
50
|
+
@params = []
|
51
|
+
@word = ''
|
52
|
+
@in_quotes = false
|
53
|
+
@escaped = false
|
54
|
+
|
55
|
+
raw_params.each_char { |c| handle_char(c) }
|
56
|
+
|
57
|
+
add_word # We have to explicitly add the last one.
|
58
|
+
end
|
59
|
+
|
60
|
+
def handle_char(char)
|
61
|
+
# last character was a backslash:
|
62
|
+
if @escaped
|
63
|
+
close_escape char
|
64
|
+
|
65
|
+
# char is a backslash or a quote:
|
66
|
+
elsif char.match(/["\\]/)
|
67
|
+
handle_special char
|
68
|
+
|
69
|
+
# Character isn't whitespace, or it's inside double quotes:
|
70
|
+
elsif @in_quotes || char.match(/\S/)
|
71
|
+
@word << char
|
72
|
+
|
73
|
+
# Character is whitespace outside of double quotes:
|
74
|
+
else
|
75
|
+
add_word
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def handle_special(char)
|
80
|
+
if char == '\\'
|
81
|
+
@escaped = true
|
82
|
+
elsif char == '"'
|
83
|
+
@in_quotes = !@in_quotes
|
84
|
+
@word << char
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def add_word
|
89
|
+
return if @word.empty?
|
90
|
+
|
91
|
+
@params << @word
|
92
|
+
@word = ''
|
93
|
+
end
|
94
|
+
|
95
|
+
def close_escape(char)
|
96
|
+
@word << char
|
97
|
+
@escaped = false
|
98
|
+
end
|
99
|
+
|
100
|
+
def strip_quotes(name)
|
101
|
+
name.delete_prefix('"').delete_suffix('"')
|
45
102
|
end
|
46
103
|
end
|
47
104
|
end
|
@@ -3,7 +3,7 @@ module PictureTag
|
|
3
3
|
# own option.
|
4
4
|
module OutputFormats
|
5
5
|
# Generic functions common to all output formats.
|
6
|
-
|
6
|
+
class Basic
|
7
7
|
include ObjectiveElements
|
8
8
|
|
9
9
|
# Used for both the fallback image, and for the complete markup.
|
@@ -16,7 +16,7 @@ module PictureTag
|
|
16
16
|
|
17
17
|
fallback = build_fallback_image
|
18
18
|
|
19
|
-
add_src(img, fallback.
|
19
|
+
add_src(img, fallback.uri)
|
20
20
|
|
21
21
|
add_alt(img, attributes['alt'])
|
22
22
|
|
@@ -40,26 +40,17 @@ module PictureTag
|
|
40
40
|
end
|
41
41
|
|
42
42
|
# Media is the media query associated with the desired source image.
|
43
|
-
def build_srcset(
|
43
|
+
def build_srcset(source_image, format)
|
44
44
|
if PictureTag.preset['pixel_ratios']
|
45
|
-
|
45
|
+
Srcsets::PixelRatio.new(source_image, format)
|
46
46
|
else
|
47
|
-
|
47
|
+
Srcsets::Width.new(source_image, format)
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
|
-
def build_pixel_ratio_srcset(media, format)
|
52
|
-
Srcsets::PixelRatio.new(media: media, format: format)
|
53
|
-
end
|
54
|
-
|
55
|
-
def build_width_srcset(media, format)
|
56
|
-
Srcsets::Width.new(media: media, format: format)
|
57
|
-
end
|
58
|
-
|
59
51
|
# Extracting these functions to their own methods for easy overriding.
|
60
|
-
|
61
|
-
|
62
|
-
element.src = PictureTag.build_url name
|
52
|
+
def add_src(element, uri)
|
53
|
+
element.src = uri
|
63
54
|
end
|
64
55
|
|
65
56
|
def add_srcset(element, srcset)
|
@@ -81,9 +72,9 @@ module PictureTag
|
|
81
72
|
# File, not HTML
|
82
73
|
def build_fallback_image
|
83
74
|
GeneratedImage.new(
|
84
|
-
source_file: PictureTag.source_images
|
75
|
+
source_file: PictureTag.source_images.first,
|
85
76
|
format: PictureTag.fallback_format,
|
86
|
-
width:
|
77
|
+
width: checked_fallback_width
|
87
78
|
)
|
88
79
|
end
|
89
80
|
|
@@ -93,7 +84,7 @@ module PictureTag
|
|
93
84
|
# Kramdown is super picky about the {::nomarkdown} extension-- we have to
|
94
85
|
# strip line breaks or nothing works.
|
95
86
|
def nomarkdown_wrapper(content)
|
96
|
-
"{::nomarkdown}#{content.delete("\n")}{:/nomarkdown}"
|
87
|
+
"{::nomarkdown}#{content.delete("\n").gsub(/> </, '><')}{:/nomarkdown}"
|
97
88
|
end
|
98
89
|
|
99
90
|
def anchor_tag(content)
|
@@ -103,6 +94,20 @@ module PictureTag
|
|
103
94
|
|
104
95
|
content.add_parent anchor
|
105
96
|
end
|
97
|
+
|
98
|
+
def checked_fallback_width
|
99
|
+
source = PictureTag.source_images.first
|
100
|
+
target = PictureTag.fallback_width
|
101
|
+
|
102
|
+
if target > source.width
|
103
|
+
Utils.warning "#{source.shortname} is smaller than the " \
|
104
|
+
"requested fallback width of #{target}px. Using #{source.width}" \
|
105
|
+
' px instead.'
|
106
|
+
source.width
|
107
|
+
else
|
108
|
+
target
|
109
|
+
end
|
110
|
+
end
|
106
111
|
end
|
107
112
|
end
|
108
113
|
end
|
@@ -2,9 +2,7 @@ module PictureTag
|
|
2
2
|
module OutputFormats
|
3
3
|
# Represents a bare url you can use in another context, such as a direct
|
4
4
|
# link, but keep the resizing functionality
|
5
|
-
class DirectUrl
|
6
|
-
include PictureTag::OutputFormats::Basics
|
7
|
-
|
5
|
+
class DirectUrl < Basic
|
8
6
|
def to_s
|
9
7
|
build_base_img.src
|
10
8
|
end
|
@@ -2,11 +2,11 @@ module PictureTag
|
|
2
2
|
module OutputFormats
|
3
3
|
# Represents a bare <img> tag with a srcset attribute.
|
4
4
|
# Used when <picture> is unnecessary.
|
5
|
-
class Img
|
6
|
-
include PictureTag::OutputFormats::Basics
|
7
|
-
|
5
|
+
class Img < Basic
|
8
6
|
def srcset
|
9
|
-
build_srcset(
|
7
|
+
@srcset ||= build_srcset(
|
8
|
+
PictureTag.source_images.first, PictureTag.formats.first
|
9
|
+
)
|
10
10
|
end
|
11
11
|
|
12
12
|
def base_markup
|
@@ -1,11 +1,12 @@
|
|
1
1
|
module PictureTag
|
2
2
|
module OutputFormats
|
3
3
|
# Returns only a srcset attribute, for more custom or complicated markup.
|
4
|
-
class NakedSrcset
|
5
|
-
include Basics
|
6
|
-
|
4
|
+
class NakedSrcset < Basic
|
7
5
|
def to_s
|
8
|
-
|
6
|
+
image = PictureTag.source_images.first
|
7
|
+
format = PictureTag.formats.first
|
8
|
+
|
9
|
+
build_srcset(image, format).to_s
|
9
10
|
end
|
10
11
|
end
|
11
12
|
end
|
@@ -2,25 +2,15 @@ module PictureTag
|
|
2
2
|
module OutputFormats
|
3
3
|
# Represents a <picture> tag, enclosing at least 2 <source> tags and an
|
4
4
|
# <img> tag.
|
5
|
-
class Picture
|
6
|
-
include Basics
|
7
|
-
|
5
|
+
class Picture < Basic
|
8
6
|
def srcsets
|
7
|
+
formats = PictureTag.formats
|
8
|
+
# Source images are provided in reverse order and must be flipped:
|
9
|
+
images = PictureTag.source_images.reverse
|
9
10
|
sets = []
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
# provided in the order they must be returned, source images are
|
14
|
-
# provided in the reverse (least to most preferable) and must be
|
15
|
-
# flipped. We'll use an intermediate value to accomplish this.
|
16
|
-
format_set = []
|
17
|
-
|
18
|
-
# Source images are defined in the tag params, and associated with
|
19
|
-
# media queries. The base (first provided) image has a key of nil.
|
20
|
-
PictureTag.source_images.each_key do |media|
|
21
|
-
format_set << build_srcset(media, format)
|
22
|
-
end
|
23
|
-
sets.concat format_set.reverse
|
12
|
+
formats.each do |format|
|
13
|
+
images.each { |image| sets << build_srcset(image, format) }
|
24
14
|
end
|
25
15
|
|
26
16
|
sets
|
@@ -1,16 +1,9 @@
|
|
1
1
|
# Writing Output Formats
|
2
2
|
|
3
|
-
|
4
3
|
## Naming and Instantiating
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
instantiated.
|
9
|
-
|
10
|
-
Example:
|
11
|
-
|
12
|
-
In `_data/picture.yml`: `markup: example_format` will cause the plugin to use
|
13
|
-
an instance of `ExampleFormat` (with no arguments.)
|
5
|
+
In the relevant `_data/picture.yml` preset, `markup: example_format` will cause
|
6
|
+
the plugin to use an instance of `ExampleFormat` (with no arguments.)
|
14
7
|
|
15
8
|
You'll need to add an appropriate `require_relative` statement to
|
16
9
|
`../output_formats.rb`
|
@@ -24,13 +17,13 @@ it this way because information flow was getting arduous; I was passing a lot
|
|
24
17
|
of information to classes which only needed it to pass on to classes they
|
25
18
|
instantiate.
|
26
19
|
|
27
|
-
`PictureTag.source_images` returns
|
28
|
-
liquid tag.
|
29
|
-
|
30
|
-
|
31
|
-
media queries named in `_data/picture.yml`.
|
20
|
+
`PictureTag.source_images` returns an array of the source images provided in
|
21
|
+
the liquid tag. The first one is the base image, the rest that follow are
|
22
|
+
associated with media queries. Check out `source_image.rb` to see what they
|
23
|
+
offer.
|
32
24
|
|
33
|
-
There's a lot of information available, dig around in `../
|
25
|
+
There's a lot of information available, dig around in `../router.rb`.
|
26
|
+
Output formats should only consume this information, never modify it.
|
34
27
|
|
35
28
|
## Producing output
|
36
29
|
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module PictureTag
|
2
|
+
# The rest of the application doesn't care where the instruction logic
|
3
|
+
# resides. The following module 'routes' method calls to the right place, so
|
4
|
+
# the rest of the application can just call 'PictureTag.(some method)'
|
5
|
+
|
6
|
+
# At first I thought I'd do some sweet dynamic metaprogramming here, but it
|
7
|
+
# ended up complicated and clever, rather than convenient and understandable.
|
8
|
+
# This way is not strictly DRY, but it's straightforward and readable. If it
|
9
|
+
# gets big, I'll refactor.
|
10
|
+
module Router
|
11
|
+
attr_accessor :instructions, :context
|
12
|
+
# Context forwarding
|
13
|
+
|
14
|
+
# Global site data
|
15
|
+
def site
|
16
|
+
@context.registers[:site]
|
17
|
+
end
|
18
|
+
|
19
|
+
# Page which tag is called from
|
20
|
+
def page
|
21
|
+
@context.registers[:page]
|
22
|
+
end
|
23
|
+
|
24
|
+
# Instructions forwarding
|
25
|
+
|
26
|
+
def config
|
27
|
+
@instructions.config
|
28
|
+
end
|
29
|
+
|
30
|
+
def preset
|
31
|
+
@instructions.preset
|
32
|
+
end
|
33
|
+
|
34
|
+
def media_presets
|
35
|
+
@instructions.media_presets
|
36
|
+
end
|
37
|
+
|
38
|
+
def html_attributes
|
39
|
+
@instructions.html_attributes
|
40
|
+
end
|
41
|
+
|
42
|
+
def output_class
|
43
|
+
@instructions.output_class
|
44
|
+
end
|
45
|
+
|
46
|
+
def source_images
|
47
|
+
@instructions.source_images
|
48
|
+
end
|
49
|
+
|
50
|
+
# Config Forwarding
|
51
|
+
|
52
|
+
def source_dir
|
53
|
+
config.source_dir
|
54
|
+
end
|
55
|
+
|
56
|
+
def dest_dir
|
57
|
+
config.dest_dir
|
58
|
+
end
|
59
|
+
|
60
|
+
def continue_on_missing?
|
61
|
+
config.continue_on_missing?
|
62
|
+
end
|
63
|
+
|
64
|
+
def cdn?
|
65
|
+
config.cdn?
|
66
|
+
end
|
67
|
+
|
68
|
+
def pconfig
|
69
|
+
config.pconfig
|
70
|
+
end
|
71
|
+
|
72
|
+
# Preset forwarding
|
73
|
+
|
74
|
+
def widths(media)
|
75
|
+
preset.widths(media)
|
76
|
+
end
|
77
|
+
|
78
|
+
def formats
|
79
|
+
preset.formats
|
80
|
+
end
|
81
|
+
|
82
|
+
def fallback_format
|
83
|
+
preset.fallback_format
|
84
|
+
end
|
85
|
+
|
86
|
+
def fallback_width
|
87
|
+
preset.fallback_width
|
88
|
+
end
|
89
|
+
|
90
|
+
def nomarkdown?
|
91
|
+
preset.nomarkdown?
|
92
|
+
end
|
93
|
+
|
94
|
+
def quality(format)
|
95
|
+
preset.quality(format)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|