jekyll-picture-tag-latest 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
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