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.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -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.gemspec +39 -0
  13. data/lib/jekyll_picture_tag.rb +67 -0
  14. data/lib/jekyll_picture_tag/defaults/global.yml +10 -0
  15. data/lib/jekyll_picture_tag/defaults/presets.yml +7 -0
  16. data/lib/jekyll_picture_tag/generated_image.rb +66 -0
  17. data/lib/jekyll_picture_tag/instructions.rb +105 -0
  18. data/lib/jekyll_picture_tag/instructions/configuration.rb +82 -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 +88 -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 +787 -0
  41. 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