jekyll_picture_tag 1.2.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 +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