jekyll-picture-tag-latest 1.3.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.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.ruby-version +1 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +24 -0
  6. data/Rakefile +1 -0
  7. data/bin/console +14 -0
  8. data/bin/setup +7 -0
  9. data/examples/_config.yml +4 -0
  10. data/examples/_data/picture.yml +85 -0
  11. data/examples/post.md +18 -0
  12. data/jekyll-picture-tag-latest.gemspec +40 -0
  13. data/lib/jekyll-picture-tag.rb +67 -0
  14. data/lib/jekyll-picture-tag/defaults/global.yml +11 -0
  15. data/lib/jekyll-picture-tag/defaults/presets.yml +7 -0
  16. data/lib/jekyll-picture-tag/generated_image.rb +68 -0
  17. data/lib/jekyll-picture-tag/instructions.rb +105 -0
  18. data/lib/jekyll-picture-tag/instructions/configuration.rb +117 -0
  19. data/lib/jekyll-picture-tag/instructions/html_attributes.rb +59 -0
  20. data/lib/jekyll-picture-tag/instructions/preset.rb +61 -0
  21. data/lib/jekyll-picture-tag/instructions/tag_parser.rb +48 -0
  22. data/lib/jekyll-picture-tag/output_formats.rb +9 -0
  23. data/lib/jekyll-picture-tag/output_formats/auto.rb +15 -0
  24. data/lib/jekyll-picture-tag/output_formats/basics.rb +105 -0
  25. data/lib/jekyll-picture-tag/output_formats/data_attributes.rb +44 -0
  26. data/lib/jekyll-picture-tag/output_formats/data_auto.rb +14 -0
  27. data/lib/jekyll-picture-tag/output_formats/data_img.rb +8 -0
  28. data/lib/jekyll-picture-tag/output_formats/data_picture.rb +8 -0
  29. data/lib/jekyll-picture-tag/output_formats/direct_url.rb +13 -0
  30. data/lib/jekyll-picture-tag/output_formats/img.rb +24 -0
  31. data/lib/jekyll-picture-tag/output_formats/picture.rb +66 -0
  32. data/lib/jekyll-picture-tag/source_image.rb +62 -0
  33. data/lib/jekyll-picture-tag/srcsets.rb +3 -0
  34. data/lib/jekyll-picture-tag/srcsets/basics.rb +78 -0
  35. data/lib/jekyll-picture-tag/srcsets/pixel_ratio.rb +32 -0
  36. data/lib/jekyll-picture-tag/srcsets/width.rb +45 -0
  37. data/lib/jekyll-picture-tag/utils.rb +67 -0
  38. data/lib/jekyll-picture-tag/version.rb +3 -0
  39. data/migration.md +178 -0
  40. data/readme.md +823 -0
  41. metadata +205 -0
@@ -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
@@ -0,0 +1,8 @@
1
+ module PictureTag
2
+ module OutputFormats
3
+ # img with data-src and such instead of src
4
+ class DataImg < Img
5
+ include DataAttributes
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module PictureTag
2
+ module OutputFormats
3
+ # picture tag with data-srcsets and such instead of src.
4
+ class DataPicture < Picture
5
+ include DataAttributes
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,13 @@
1
+ module PictureTag
2
+ module OutputFormats
3
+ # Represents a bare url you can use in another context, such as a direct
4
+ # link, but keep the resizing functionality
5
+ class DirectUrl
6
+ include PictureTag::OutputFormats::Basics
7
+
8
+ def to_s
9
+ build_base_img.src
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,24 @@
1
+ module PictureTag
2
+ module OutputFormats
3
+ # Represents a bare <img> tag with a srcset attribute.
4
+ # Used when <picture> is unnecessary.
5
+ class Img
6
+ include PictureTag::OutputFormats::Basics
7
+
8
+ def srcset
9
+ build_srcset(nil, PictureTag.preset['formats'].first)
10
+ end
11
+
12
+ def base_markup
13
+ img = build_base_img
14
+
15
+ add_srcset(img, srcset)
16
+ add_sizes(img, srcset)
17
+
18
+ img.attributes << PictureTag.html_attributes['parent']
19
+
20
+ img
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,66 @@
1
+ module PictureTag
2
+ module OutputFormats
3
+ # Represents a <picture> tag, enclosing at least 2 <source> tags and an
4
+ # <img> tag.
5
+ class Picture
6
+ include Basics
7
+
8
+ def srcsets
9
+ sets = []
10
+
11
+ PictureTag.preset['formats'].each do |format|
12
+ # We have 2 dimensions here: formats, and source images. Formats are
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
24
+ end
25
+
26
+ sets
27
+ end
28
+
29
+ def build_sources
30
+ srcsets.collect { |s| build_source(s) }
31
+ end
32
+
33
+ def build_source(srcset)
34
+ source = SingleTag.new(
35
+ 'source',
36
+ attributes: PictureTag.html_attributes['source']
37
+ )
38
+
39
+ # Sizes will be the same for all sources. There's some redundant markup
40
+ # here, but I don't think it's worth the effort to prevent.
41
+ add_sizes(source, srcset)
42
+ add_media(source, srcset)
43
+ add_srcset(source, srcset)
44
+
45
+ source.type = srcset.mime_type
46
+
47
+ source
48
+ end
49
+
50
+ def base_markup
51
+ picture = DoubleTag.new(
52
+ 'picture',
53
+ attributes: PictureTag.html_attributes['picture'],
54
+ content: build_sources << build_base_img,
55
+
56
+ # Markdown fix requires removal of line breaks:
57
+ oneline: PictureTag.nomarkdown?
58
+ )
59
+
60
+ picture.attributes << PictureTag.html_attributes['parent']
61
+
62
+ picture
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,62 @@
1
+ module PictureTag
2
+ # Handles a given source image file and its properties. Provides a speed
3
+ # advantage by storing expensive file reads and writes in instance variables,
4
+ # to be reused by many different source images.
5
+ class SourceImage
6
+ attr_reader :name, :shortname
7
+
8
+ def initialize(relative_filename)
9
+ @shortname = relative_filename
10
+ @name = grab_file relative_filename
11
+ end
12
+
13
+ def size
14
+ @size ||= build_size
15
+ end
16
+
17
+ def width
18
+ size[:width]
19
+ end
20
+
21
+ def aspect_ratio
22
+ @aspect_ratio ||= size[:width].to_f / size[:height].to_f
23
+ end
24
+
25
+ def digest
26
+ @digest ||= Digest::MD5.hexdigest(File.read(@name))[0..5]
27
+ end
28
+
29
+ # Includes path relative to default sorce folder, and the original filename.
30
+ def base_name
31
+ @shortname.delete_suffix File.extname(@shortname)
32
+ end
33
+
34
+ # File exention
35
+ def ext
36
+ # [1..-1] will strip the leading period.
37
+ @ext ||= File.extname(@name)[1..-1].downcase
38
+ end
39
+
40
+ private
41
+
42
+ def build_size
43
+ width, height = FastImage.size(@name)
44
+
45
+ {
46
+ width: width,
47
+ height: height
48
+ }
49
+ end
50
+
51
+ # Turn a relative filename into an absolute one, and make sure it exists.
52
+ def grab_file(source_file)
53
+ source_name = File.join(PictureTag.config.source_dir, source_file)
54
+
55
+ unless File.exist? source_name
56
+ raise "Jekyll Picture Tag could not find #{source_name}."
57
+ end
58
+
59
+ source_name
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,3 @@
1
+ require_relative 'srcsets/basics'
2
+ require_relative 'srcsets/pixel_ratio'
3
+ require_relative 'srcsets/width'
@@ -0,0 +1,78 @@
1
+ module PictureTag
2
+ # Handles srcset generation, which also handles file generation.
3
+ module Srcsets
4
+ # Basic functionality for a srcset, which also handles file generation.
5
+ # Classes including this module must implement the to_a method, which
6
+ # accomplishes the following:
7
+ # - Return an array of srcset entries.
8
+ # - Call generate_file for each entry, giving it the desired width in
9
+ # pixels.
10
+ module Basics
11
+ require 'fastimage'
12
+ require 'mime-types'
13
+ attr_reader :media, :source_image
14
+
15
+ def initialize(media:, format:)
16
+ @media = media # Associated Media Query, can be nil
17
+
18
+ # Output format:
19
+ @format = Utils.process_format(format, media)
20
+
21
+ @source_image = PictureTag.source_images[@media]
22
+ end
23
+
24
+ def to_s
25
+ to_a.join(', ')
26
+ end
27
+
28
+ # Allows us to add a type attribute to whichever element contains this
29
+ # srcset.
30
+ def mime_type
31
+ MIME::Types.type_for(@format).first.to_s
32
+ end
33
+
34
+ # Some srcsets have them, for those that don't return nil.
35
+ def sizes
36
+ nil
37
+ end
38
+
39
+ # Check our source image size vs requested sizes
40
+ def check_widths(targets)
41
+ if targets.any? { |t| t > @source_image.width }
42
+ handle_small_source(targets, @source_image.width)
43
+ else
44
+ targets
45
+ end
46
+ end
47
+
48
+ # Generates an HTML attribute
49
+ def media_attribute
50
+ "(#{PictureTag.media_presets[@media]})"
51
+ end
52
+
53
+ private
54
+
55
+ def handle_small_source(targets, image_width)
56
+ PictureTag::Utils.warning(
57
+ " #{@source_image.shortname} is #{image_width}px wide, smaller than" \
58
+ " at least one size in the set #{targets}. Will not enlarge."
59
+ )
60
+
61
+ small_targets = targets.dup.delete_if { |t| t >= image_width }
62
+
63
+ small_targets.push image_width
64
+
65
+ small_targets
66
+ end
67
+
68
+ def generate_file(width)
69
+ GeneratedImage.new(
70
+ source_file: @source_image,
71
+ width: width,
72
+ format: @format
73
+ )
74
+ end
75
+
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,32 @@
1
+ module PictureTag
2
+ module Srcsets
3
+ # Creates a srcset in the "(filename) (pixel_ratio)x" format.
4
+ # Example: "img.jpg 1x, img2.jpg 1.5x, img3.jpg 2x"
5
+ class PixelRatio
6
+ include Basics
7
+
8
+ def to_a
9
+ widths.collect { |w| build_srcset_entry(w) }
10
+ end
11
+
12
+ private
13
+
14
+ def widths
15
+ target = PictureTag.preset['pixel_ratios'].collect do |p|
16
+ p * PictureTag.preset['base_width']
17
+ end
18
+
19
+ check_widths target
20
+ end
21
+
22
+ def build_srcset_entry(width)
23
+ # We have to recalculate the pixel ratio after verifying our source
24
+ # image is large enough.
25
+ pixel_ratio = (width.to_f / PictureTag.preset['base_width']).round(2)
26
+ file = generate_file(width)
27
+
28
+ "#{PictureTag.build_url(file.name)} #{pixel_ratio}x"
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,45 @@
1
+ module PictureTag
2
+ module Srcsets
3
+ # Creates a srcset in the "(filename) (width)w, (...)" format.
4
+ # Example: "img.jpg 400w, img2.jpg 600w, img3.jpg 800w"
5
+ class Width
6
+ include Basics
7
+
8
+ def to_a
9
+ widths.collect { |w| build_srcset_entry(w) }
10
+ end
11
+
12
+ # Sizes html attribute. Since it's intimately related to srcset, we
13
+ # generate it at the same time.
14
+ def sizes
15
+ preset_sizes = PictureTag.preset['sizes'] || {}
16
+ preset_size = PictureTag.preset['size']
17
+ size_set = []
18
+
19
+ preset_sizes.each_pair do |media, size|
20
+ size_set << build_size_entry(media, size)
21
+ end
22
+
23
+ size_set << preset_size if preset_size
24
+
25
+ size_set.any? ? size_set.join(', ') : nil
26
+ end
27
+
28
+ private
29
+
30
+ def widths
31
+ check_widths PictureTag.widths(@media)
32
+ end
33
+
34
+ def build_srcset_entry(width)
35
+ file = generate_file(width)
36
+
37
+ "#{PictureTag.build_url(file.name)} #{file.width}w"
38
+ end
39
+
40
+ def build_size_entry(media, size)
41
+ "(#{PictureTag.media_presets[media]}) #{size}"
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,67 @@
1
+ module PictureTag
2
+ # This is a little module to hold logic that doesn't fit other places. If it
3
+ # starts getting big, refactor.
4
+ module Utils
5
+ # Configure Jekyll to keep our generated files
6
+ def self.keep_files
7
+ dest_dir = PictureTag.config['picture']['output']
8
+
9
+ # Chop a slash off the end, if it's there. Doesn't work otherwise.
10
+ dest_dir = dest_dir[0..-2] if dest_dir =~ %r{/\z}
11
+
12
+ return if PictureTag.site.config['keep_files'].include?(dest_dir)
13
+
14
+ PictureTag.site.config['keep_files'] << dest_dir
15
+ end
16
+
17
+ # Print a warning to the console
18
+ def self.warning(message)
19
+ return if PictureTag.config['picture']['suppress_warnings']
20
+
21
+ warn 'Jekyll Picture Tag Warning: '.yellow + message
22
+ end
23
+
24
+ # Parse a liquid template; allows liquid variables to be included as tag
25
+ # params.
26
+ def self.liquid_lookup(params)
27
+ Liquid::Template.parse(params).render(PictureTag.context)
28
+
29
+ # This gsub allows people to include template code for javascript
30
+ # libraries such as handlebar.js. It adds complication and I'm not sure
31
+ # it has much value now, so I'm commenting it out. If someone has a use
32
+ # case for it we can add it back in.
33
+ # .gsub(/\\\{\\\{|\\\{\\%/, '\{\{' => '{{', '\{\%' => '{%')
34
+ end
35
+
36
+ # Allows us to use 'original' as a format name.
37
+ def self.process_format(format, media)
38
+ if format.casecmp('original').zero?
39
+ PictureTag.source_images[media].ext
40
+ else
41
+ format.downcase
42
+ end
43
+ end
44
+
45
+ # Used for auto markup configuration and such
46
+ def self.count_srcsets
47
+ formats = PictureTag.preset['formats'].length
48
+ source_images = PictureTag.source_images.length
49
+
50
+ formats * source_images
51
+ end
52
+
53
+ # Returns whether or not the current page is a markdown file.
54
+ def self.markdown_page?
55
+ page_name = PictureTag.page['name']
56
+ page_ext = PictureTag.page['ext']
57
+ ext = page_ext ? page_ext : File.extname(page_name)
58
+
59
+ ext.casecmp('.md').zero? || ext.casecmp('.markdown').zero?
60
+ end
61
+
62
+ # Returns the widest source image
63
+ def self.biggest_source
64
+ PictureTag.source_images.values.max_by(&:width)
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,3 @@
1
+ module PictureTag
2
+ VERSION = '1.3.0'.freeze
3
+ end