jekyll_img 0.2.5 → 0.2.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -0
- data/README.md +63 -36
- data/lib/img_builder.rb +62 -62
- data/lib/img_props.rb +5 -10
- data/lib/jekyll_img/version.rb +1 -1
- data/lib/jekyll_img.rb +4 -3
- data/lib/source.rb +98 -0
- data/spec/img_builder_spec.rb +51 -18
- data/spec/img_props_spec.rb +12 -23
- data/spec/jekyll_img_spec.rb +11 -7
- data/spec/source_spec.rb +87 -0
- data/spec/status_persistence.txt +16 -0
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0ec131406e5dce078a0d63a5a821f73b8de66ece127990a8c3fa34a348c9d819
|
4
|
+
data.tar.gz: ed9c9f00d0df3b50ea9409593ccc58fa6aca91d2e8c200a4ece28a8b3fc21aa3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 256b5e033e1f7ab3b08a0e37df0091eb39c67430397da6fb44745cd29e0dbc46fa104efe88b4230ca8d17ecb47014006ae11031895f14cf7031632e702f8cf0d
|
7
|
+
data.tar.gz: 15a4431e31fdef70e180dc0a774f9a9eff410276768d42a7f3b727a72f1b1c30fd87a6242199ddf0898bb1e0fa17aa43ce70cf67b727b3981d85be1aa4ede188
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,18 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## 0.2.7 / 2024-09-11
|
4
|
+
|
5
|
+
* Further tweaking of the generated HTML.
|
6
|
+
|
7
|
+
|
8
|
+
## 0.2.6 / 2024-09-10
|
9
|
+
|
10
|
+
* Optimized the generated HTML.
|
11
|
+
For example, `srcset` elements are now only generated for images that actually exit locally.
|
12
|
+
For remote images, only an `img` element is generated for the specified filetype.
|
13
|
+
The tests can be found in `demo/img_test.html`.
|
14
|
+
|
15
|
+
|
3
16
|
## 0.2.5 / 2024-07-23
|
4
17
|
|
5
18
|
* Depends on jekyll_plugin_support v1.0.2
|
data/README.md
CHANGED
@@ -9,10 +9,6 @@ Muliple image formats are supported for each image.
|
|
9
9
|
The user’s web browser determines the formats which it will accept.
|
10
10
|
The most desirable formats that the web browser supports are prioritized.
|
11
11
|
|
12
|
-
I explain why the `webp` image format is important in
|
13
|
-
[Converting All Images in a Website to `webp` Format](https://mslinn.com/blog/2020/08/15/converting-all-images-to-webp-format.html).
|
14
|
-
That article also provides 2 bash scripts for converting existing images to and from <code>webp</code> format.
|
15
|
-
|
16
12
|
For example, if an image is encloded in `webp`, `png` and `gif` filetypes,
|
17
13
|
and the user’s web browser is relatively recent,
|
18
14
|
then `webp` format will give the fastest transmission and look best.
|
@@ -22,56 +18,87 @@ Really old web browsers would only support the `gif` file type.
|
|
22
18
|
|
23
19
|
Please read the next section for details.
|
24
20
|
|
21
|
+
I explain why the `webp` image format is important in
|
22
|
+
[Converting All Images in a Website to `webp` Format](https://mslinn.com/blog/2020/08/15/converting-all-images-to-webp-format.html).
|
23
|
+
That article also provides 2 bash scripts for converting existing images to and from <code>webp</code> format.
|
24
|
+
|
25
25
|
See [demo/index.html](demo/index.html) for examples.
|
26
26
|
|
27
27
|
|
28
|
+
## External Images
|
29
|
+
|
30
|
+
Images whose `src` attribute starts with `http` are not served from the Jekyll website.
|
31
|
+
The `jekyll_img` plugin generates HTML for external images using an `img` element with a `src`
|
32
|
+
attribute as you might expect.
|
33
|
+
|
34
|
+
|
28
35
|
## Image Fallback
|
29
36
|
|
30
|
-
|
31
|
-
|
37
|
+
For local files (files served from the Jekyll website),
|
38
|
+
the `jekyll_img` plugin generates HTML that falls back to successively less performant
|
39
|
+
formats.
|
40
|
+
This is made possible by using a
|
32
41
|
[`picture`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture) element.
|
33
42
|
|
34
|
-
|
43
|
+
At least one version of every image are required.
|
44
|
+
Supported filetypes are:
|
45
|
+
`svg`, `webp`, `apng`, `png`, `jpg`, `jpeg`, `jfif`, `pjpeg`, `pjp`, `gif`, `tif`, `tiff`, `bmp`, `ico` and `cur`.
|
35
46
|
|
36
|
-
|
37
|
-
|
38
|
-
`
|
39
|
-
and
|
40
|
-
|
41
|
-
For example, these two invocations yield the same result:
|
47
|
+
For example, an image file might have the following verions: `blah.webp`, `blah.png` and `blah.jpg`.
|
48
|
+
Given a tag invocation like `{% img src='blah.webp' %}`,
|
49
|
+
the plugin would generate a `picture` element that contains an `img` sub-element with the given `src` attribute,
|
50
|
+
and a `source` element for each related image (`blah.png` and `blah.jpg`).
|
51
|
+
Conceptually, the generated HTML might look something like this:
|
42
52
|
|
43
53
|
```html
|
44
|
-
|
45
|
-
|
54
|
+
<picture>
|
55
|
+
<source srcset="blah.png" />
|
56
|
+
<source srcset="blah.jpg" />
|
57
|
+
<img src="blah.webp" />
|
58
|
+
</picture>
|
46
59
|
```
|
47
60
|
|
48
|
-
|
49
|
-
|
61
|
+
If no filetype is given for the image, `webp` is assumed.
|
62
|
+
For example, these two invocations yield the same result,
|
63
|
+
if `blah.webp` exists on the Jekyll website:
|
50
64
|
|
51
65
|
```html
|
52
|
-
|
53
|
-
|
54
|
-
<source srcset="blah.webp" type="image/webp" />
|
55
|
-
<source srcset="blah.apng" type="image/apng">
|
56
|
-
<source srcset="blah.png" type="image/png">
|
57
|
-
<source srcset="blah.jpg" type="image/jpeg">
|
58
|
-
<source srcset="blah.jpeg" type="image/jpeg">
|
59
|
-
<source srcset="blah.jfif" type="image/jpeg">
|
60
|
-
<source srcset="blah.pjpeg" type="image/jpeg">
|
61
|
-
<source srcset="blah.pjp" type="image/jpeg">
|
62
|
-
<source srcset="blah.gif" type="image/gif">
|
63
|
-
<source srcset="blah.tif" type="image/tiff">
|
64
|
-
<source srcset="blah.tiff" type="image/tiff">
|
65
|
-
<source srcset="blah.bmp" type="image/bmp">
|
66
|
-
<source srcset="blah.ico" type="image/x-icon">
|
67
|
-
<source srcset="blah.cur" type="image/x-icon">
|
68
|
-
<img src="blah.png" />
|
69
|
-
</picture>
|
66
|
+
{% img src="blah" %}
|
67
|
+
{% img src="blah.webp" %}
|
70
68
|
```
|
71
69
|
|
72
70
|
If both `blah.webp` and `blah.png` were available,
|
73
71
|
the above would fetch and display `blah.webp` if the web browser supported `webp` format,
|
74
72
|
otherwise it would fetch and display `blah.png`.
|
73
|
+
If the browser did not support the `picture` element,
|
74
|
+
the `img src` attribute would be used to specify the image.
|
75
|
+
|
76
|
+
|
77
|
+
### Default and Relative Paths
|
78
|
+
|
79
|
+
Local images whose path does not start with a slash are assumed to be relative to `/assets/images`.
|
80
|
+
Simply specifying the filename of the image will cause it to be fetched from
|
81
|
+
`/assets/images/`.
|
82
|
+
For example, the following all fetch the same image:
|
83
|
+
|
84
|
+
```html
|
85
|
+
{% img src="/assets/images/blah.webp" %}
|
86
|
+
{% img src="blah.webp" %}
|
87
|
+
{% img src="blah" %}
|
88
|
+
```
|
89
|
+
|
90
|
+
To specify an image in a subdirectory of where the page resides,
|
91
|
+
prepend the relative path with a dot (`.`).
|
92
|
+
|
93
|
+
For example, if the current page resides in a [Jekyll collection](https://jekyllrb.com/docs/collections/)
|
94
|
+
with path `/collections/_av_studio/`,
|
95
|
+
and an image resides in the `/collections/_av_studio/images` subdirectory,
|
96
|
+
the following would result in the same image being displayed:
|
97
|
+
|
98
|
+
```html
|
99
|
+
{% img src="/av_studio/images/blah" %}
|
100
|
+
{% img src="./images/blah" %}
|
101
|
+
```
|
75
102
|
|
76
103
|
|
77
104
|
## Supported Filetypes
|
@@ -103,7 +130,7 @@ Run the demo website by typing:
|
|
103
130
|
$ demo/_bin/debug -r
|
104
131
|
```
|
105
132
|
|
106
|
-
... and point your web browser to http://localhost:
|
133
|
+
... and point your web browser to http://localhost:4011
|
107
134
|
|
108
135
|
|
109
136
|
## Usage
|
data/lib/img_builder.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
|
-
# Like RoR's squish method
|
2
1
|
class String
|
2
|
+
def remove_blank_lines
|
3
|
+
strip.gsub(/^\s*$\n/, '')
|
4
|
+
end
|
5
|
+
|
6
|
+
# Like RoR's squish method
|
3
7
|
def squish
|
4
8
|
strip.gsub(/\s+/, ' ')
|
5
9
|
end
|
@@ -7,84 +11,80 @@ end
|
|
7
11
|
|
8
12
|
# Constructs HTML img tag from properties
|
9
13
|
class ImgBuilder
|
14
|
+
attr_reader :source
|
15
|
+
|
10
16
|
def initialize(props)
|
11
17
|
props.compute_dependant_properties
|
12
18
|
@props = props
|
19
|
+
@source = Source.new @props.src
|
13
20
|
end
|
14
21
|
|
15
|
-
def
|
16
|
-
|
17
|
-
|
22
|
+
def generate_figcaption
|
23
|
+
<<~END_CAPTION
|
24
|
+
<figcaption class='imgFigCaption #{@props.attr_size_class}'>
|
25
|
+
#{@props.url ? generate_url_caption : @props.caption}
|
26
|
+
</figcaption>
|
27
|
+
END_CAPTION
|
28
|
+
end
|
29
|
+
|
30
|
+
def generate_img
|
31
|
+
img_classes = @props.classes || 'rounded shadow'
|
32
|
+
<<~END_IMG
|
33
|
+
<img #{@props.attr_alt}
|
34
|
+
class="imgImg #{img_classes.squish}"
|
35
|
+
src="#{@source.src_fallback}"
|
36
|
+
#{@props.attr_style_img}
|
37
|
+
#{@props.attr_title}
|
38
|
+
/>
|
39
|
+
END_IMG
|
40
|
+
end
|
41
|
+
|
42
|
+
# See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture
|
43
|
+
def generate_picture
|
44
|
+
return generate_img if @props.src.start_with? 'http'
|
45
|
+
|
46
|
+
# avif is not well supported yet
|
47
|
+
# <source srcset="#{@props.src_any 'avif'}" type="image/avif">
|
48
|
+
result = <<~END_IMG
|
49
|
+
<picture#{@props.attr_id} class='imgPicture'>
|
50
|
+
#{@source.generate.join("\n ")}
|
51
|
+
#{generate_img}
|
52
|
+
</picture>
|
53
|
+
END_IMG
|
54
|
+
result.strip
|
55
|
+
end
|
56
|
+
|
57
|
+
def generate_url_caption
|
58
|
+
<<~END_URL
|
59
|
+
<a href="#{@props.url}"#{@props.attr_target}#{@props.attr_nofollow}>
|
60
|
+
#{@props.caption}
|
61
|
+
</a>
|
62
|
+
END_URL
|
18
63
|
end
|
19
64
|
|
20
|
-
|
65
|
+
def generate_url_wrapper
|
66
|
+
<<~END_HTML
|
67
|
+
<a href='#{@props.url}'#{@props.attr_target}#{@props.attr_nofollow} class='imgImgUrl'>
|
68
|
+
#{generate_picture}
|
69
|
+
</a>
|
70
|
+
END_HTML
|
71
|
+
end
|
21
72
|
|
22
73
|
def generate_wrapper
|
23
74
|
classes = "imgWrapper #{@props.img_display} #{@props.align} #{@props.attr_size_class} #{@props.wrapper_class}".squish
|
24
|
-
|
75
|
+
<<~END_HTML.remove_blank_lines
|
25
76
|
<div class='#{classes}' style='#{@props.attr_width_style} #{@props.wrapper_style}'>
|
26
77
|
#{"<figure>\n" if @props.caption}
|
27
|
-
#{
|
28
|
-
|
29
|
-
else
|
30
|
-
generate_img
|
31
|
-
end
|
32
|
-
}
|
33
|
-
#{generate_figure_caption}
|
78
|
+
#{@props.url ? generate_url_wrapper : generate_picture}
|
79
|
+
#{generate_figcaption if @props.caption}
|
34
80
|
#{"</figure>\n" if @props.caption}
|
35
81
|
#{@props.attribute if @props.attribution}
|
36
82
|
</div>
|
37
83
|
END_HTML
|
38
|
-
result.strip
|
39
84
|
end
|
40
85
|
|
41
|
-
def
|
42
|
-
|
43
|
-
|
44
|
-
<<~END_CAPTION
|
45
|
-
<figcaption class='imgFigCaption #{@props.attr_size_class}'>
|
46
|
-
#{if @props.url
|
47
|
-
<<~END_URL
|
48
|
-
<a href="#{@props.url}" #{@props.attr_target} #{@props.attr_nofollow}>
|
49
|
-
#{@props.caption}
|
50
|
-
</a>
|
51
|
-
END_URL
|
52
|
-
else
|
53
|
-
@props.caption
|
54
|
-
end
|
55
|
-
}
|
56
|
-
</figcaption>
|
57
|
-
END_CAPTION
|
58
|
-
end
|
59
|
-
|
60
|
-
# See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture
|
61
|
-
def generate_img
|
62
|
-
img_classes = @props.classes || 'rounded shadow'
|
63
|
-
<<~END_IMG
|
64
|
-
<picture#{@props.attr_id} class='imgPicture'>
|
65
|
-
<source srcset="#{@props.src_any 'svg'}" type="image/svg">
|
66
|
-
<!---<source srcset="#{@props.src_any 'avif'}" type="image/avif">-->
|
67
|
-
<source srcset="#{@props.src}" type="image/webp">
|
68
|
-
<source srcset="#{@props.src_any 'apng'}" type="image/apng">
|
69
|
-
<source srcset="#{@props.src_any 'png'}" type="image/png">
|
70
|
-
<source srcset="#{@props.src_any 'jpg'}" type="image/jpeg">
|
71
|
-
<source srcset="#{@props.src_any 'jpeg'}" type="image/jpeg">
|
72
|
-
<source srcset="#{@props.src_any 'jfif'}" type="image/jpeg">
|
73
|
-
<source srcset="#{@props.src_any 'pjpeg'}" type="image/jpeg">
|
74
|
-
<source srcset="#{@props.src_any 'pjp'}" type="image/jpeg">
|
75
|
-
<source srcset="#{@props.src_any 'gif'}" type="image/gif">
|
76
|
-
<source srcset="#{@props.src_any 'tif'}" type="image/tiff">
|
77
|
-
<source srcset="#{@props.src_any 'tiff'}" type="image/tiff">
|
78
|
-
<source srcset="#{@props.src_any 'bmp'}" type="image/bmp">
|
79
|
-
<source srcset="#{@props.src_any 'ico'}" type="image/x-icon">
|
80
|
-
<source srcset="#{@props.src_any 'cur'}" type="image/x-icon">
|
81
|
-
<img #{@props.attr_alt}
|
82
|
-
class="imgImg #{img_classes.squish}"
|
83
|
-
src="#{@props.src_png}"
|
84
|
-
#{@props.attr_style_img}
|
85
|
-
#{@props.attr_title}
|
86
|
-
/>
|
87
|
-
</picture>
|
88
|
-
END_IMG
|
86
|
+
def to_s
|
87
|
+
@props.compute_dependant_properties
|
88
|
+
generate_wrapper
|
89
89
|
end
|
90
90
|
end
|
data/lib/img_props.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
1
3
|
# Properties from user
|
2
4
|
# All methods are idempotent.
|
3
5
|
# attr_ methods can be called after compute_dependant_properties
|
@@ -8,6 +10,7 @@ class ImgProperties
|
|
8
10
|
:url, :wrapper_class, :wrapper_style
|
9
11
|
|
10
12
|
SIZES = %w[eighthsize fullsize halfsize initial quartersize].freeze
|
13
|
+
UNITS = %w[Q ch cm em dvh dvw ex in lh lvh lvw mm pc px pt rem rlh svh svw vb vh vi vmax vmin vw %].freeze
|
11
14
|
|
12
15
|
def attr_alt
|
13
16
|
"alt='#{@alt}'" if @alt
|
@@ -67,13 +70,7 @@ class ImgProperties
|
|
67
70
|
end
|
68
71
|
|
69
72
|
def src_any(filetype)
|
70
|
-
@src.gsub(
|
71
|
-
end
|
72
|
-
|
73
|
-
def src_png
|
74
|
-
raise Jekyll::ImgError, "The 'src' parameter was not specified" if @src.to_s.empty?
|
75
|
-
|
76
|
-
@src.gsub('.webp', '.png')
|
73
|
+
@src.gsub(/\..*?$/, ".#{filetype}")
|
77
74
|
end
|
78
75
|
|
79
76
|
def self.local_path?(src)
|
@@ -84,7 +81,7 @@ class ImgProperties
|
|
84
81
|
private
|
85
82
|
|
86
83
|
def setup_src
|
87
|
-
raise Jekyll::ImgError, "The 'src' parameter was not specified" if @src.nil?
|
84
|
+
raise Jekyll::ImgError, "The 'src' parameter was not specified" if @src.nil? || [true, false].include?(@src)
|
88
85
|
|
89
86
|
raise Jekyll::ImgError, "The 'src' parameter was empty" if @src.empty?
|
90
87
|
|
@@ -101,8 +98,6 @@ class ImgProperties
|
|
101
98
|
# raise Jekyll::ImgError, "#{@src} does not exist" unless File.exist?(src)
|
102
99
|
end
|
103
100
|
|
104
|
-
UNITS = %w[Q ch cm em dvh dvw ex in lh lvh lvw mm pc px pt rem rlh svh svw vb vh vi vmax vmin vw %].freeze
|
105
|
-
|
106
101
|
def size_unit_specified?
|
107
102
|
return false if @size == false || @size.to_s.strip.empty?
|
108
103
|
|
data/lib/jekyll_img/version.rb
CHANGED
data/lib/jekyll_img.rb
CHANGED
@@ -3,17 +3,18 @@ require 'helper/jekyll_plugin_helper'
|
|
3
3
|
require 'pry'
|
4
4
|
require_relative 'img_builder'
|
5
5
|
require_relative 'img_props'
|
6
|
+
require_relative 'source'
|
6
7
|
require_relative 'jekyll_img/version'
|
7
8
|
|
8
9
|
# @author Copyright 2023 Michael Slinn
|
9
10
|
# @license SPDX-License-Identifier: Apache-2.0
|
10
11
|
|
11
12
|
module ImgModule
|
12
|
-
PLUGIN_NAME = 'img'.freeze
|
13
|
+
PLUGIN_NAME = 'img'.freeze unless const_defined?(:PLUGIN_NAME)
|
13
14
|
end
|
14
15
|
|
15
16
|
module Jekyll
|
16
|
-
ImgError = ::JekyllSupport.define_error
|
17
|
+
ImgError = ::JekyllSupport.define_error unless const_defined?(:ImgError)
|
17
18
|
|
18
19
|
# Plugin implementation
|
19
20
|
class Img < ::JekyllSupport::JekyllTag
|
@@ -54,6 +55,6 @@ module Jekyll
|
|
54
55
|
e.html_message
|
55
56
|
end
|
56
57
|
|
57
|
-
::JekyllSupport::JekyllPluginHelper.register(self, ImgModule::PLUGIN_NAME)
|
58
|
+
::JekyllSupport::JekyllPluginHelper.register(self, ImgModule::PLUGIN_NAME) unless $PROGRAM_NAME.end_with?('/rspec')
|
58
59
|
end
|
59
60
|
end
|
data/lib/source.rb
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
class Source
|
2
|
+
RANKS = %w[svg webp apng png jpg jpeg jfif pjpeg pjp gif tif tiff bmp cur ico].freeze
|
3
|
+
RANKS_LENGTH = RANKS.length
|
4
|
+
|
5
|
+
def initialize(path)
|
6
|
+
raise Jekyll::ImgError, "The 'src' parameter was not specified" if path.nil?
|
7
|
+
raise Jekyll::ImgError, "The 'src' parameter was empty" if path.empty?
|
8
|
+
|
9
|
+
path.strip!
|
10
|
+
raise Jekyll::ImgError, "The 'src' parameter only contained whitespace" if path.empty?
|
11
|
+
|
12
|
+
@path = path
|
13
|
+
@absolute_path = @path.start_with?('/')
|
14
|
+
end
|
15
|
+
|
16
|
+
# @return array of source statements for filetypes that exist locally;
|
17
|
+
# return nil if @path points to a remote image
|
18
|
+
def generate
|
19
|
+
return nil if @path.nil? || @path.start_with?('http')
|
20
|
+
|
21
|
+
result = sorted_files.map do |filename|
|
22
|
+
mtype = mimetype filename
|
23
|
+
next unless mtype
|
24
|
+
|
25
|
+
<<~END_HTML
|
26
|
+
<source srcset="#{filename}" type="#{mtype}">
|
27
|
+
END_HTML
|
28
|
+
end
|
29
|
+
result&.compact&.map(&:strip)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Webp is the least desired variant, png is most desired variant.
|
33
|
+
# @return URL of external image, otherwise return specified path unless it is a webp;
|
34
|
+
# in which case return most desired image variant that exists.
|
35
|
+
def src_fallback
|
36
|
+
return @path if @path.start_with? 'http'
|
37
|
+
|
38
|
+
result = @absolute_path ? @path.delete_prefix('.') : @path
|
39
|
+
png = result.gsub(/\.webp$/, '.png')
|
40
|
+
return png if File.exist? png
|
41
|
+
return result unless result.end_with? '.webp' # we know @path will be a webp after this
|
42
|
+
|
43
|
+
files = sorted_files
|
44
|
+
return files[0] if files.count == 1
|
45
|
+
|
46
|
+
files.each do |filename|
|
47
|
+
ext = File.extname filename
|
48
|
+
unless ext == '.webp'
|
49
|
+
return @absolute_path ? filename.delete_prefix('.') : filename
|
50
|
+
end
|
51
|
+
end
|
52
|
+
result
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
# Convert absolute paths (which reference the website root) to relative paths for globbing
|
58
|
+
def globbed_path
|
59
|
+
dir = File.dirname @path
|
60
|
+
dir = ".#{dir}" if dir.start_with?('/')
|
61
|
+
base = File.basename @path, ".*"
|
62
|
+
"#{dir}/#{base}.*"
|
63
|
+
end
|
64
|
+
|
65
|
+
def mimetype(path)
|
66
|
+
case File.extname(path)
|
67
|
+
when '.svg'
|
68
|
+
'image/svg'
|
69
|
+
when '.webp'
|
70
|
+
'image/webp'
|
71
|
+
when '.png'
|
72
|
+
'image/png'
|
73
|
+
when '.apng'
|
74
|
+
'image/apng'
|
75
|
+
when %w[.jpg .jpeg .jfif .pjpeg .pjp]
|
76
|
+
'image/jpeg'
|
77
|
+
when '.gif'
|
78
|
+
'image/gif'
|
79
|
+
when %w[.tif .tiff]
|
80
|
+
'image/tiff'
|
81
|
+
when '.bmp'
|
82
|
+
'image/bmp'
|
83
|
+
when %w[cur ico]
|
84
|
+
'image/x-icon'
|
85
|
+
# else
|
86
|
+
# raise Jekyll::ImgError, "#{path} has an unrecognized filetype."
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def sorted_files
|
91
|
+
sorted = Dir[globbed_path].sort_by do |path|
|
92
|
+
ext = File.extname(path)&.delete_prefix('.')
|
93
|
+
index = RANKS.index(ext)
|
94
|
+
index || RANKS_LENGTH
|
95
|
+
end
|
96
|
+
sorted.map { |x| @absolute_path ? x.delete_prefix('.') : x }
|
97
|
+
end
|
98
|
+
end
|
data/spec/img_builder_spec.rb
CHANGED
@@ -1,36 +1,69 @@
|
|
1
1
|
require 'rspec/match_ignoring_whitespace'
|
2
2
|
require_relative '../lib/img_builder'
|
3
3
|
require_relative '../lib/img_props'
|
4
|
+
require_relative '../lib/source'
|
4
5
|
|
5
6
|
# Test ImgProperties
|
6
7
|
class ImgPropertiesTest
|
7
8
|
RSpec.describe ImgBuilder do
|
9
|
+
Dir.chdir("demo")
|
10
|
+
props = ImgProperties.new
|
11
|
+
props.src = '/assets/images/jekyll.webp'
|
12
|
+
builder = described_class.new(props)
|
13
|
+
|
14
|
+
it 'generates sources' do
|
15
|
+
actual = builder.source.generate
|
16
|
+
desired = [
|
17
|
+
'<source srcset="/assets/images/jekyll.webp" type="image/webp">',
|
18
|
+
'<source srcset="/assets/images/jekyll.png" type="image/png">'
|
19
|
+
]
|
20
|
+
expect(actual).to match_array(desired)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'generates a figcaption' do
|
24
|
+
desired = <<~END_STRING
|
25
|
+
<figcaption class='imgFigCaption '>
|
26
|
+
</figcaption>
|
27
|
+
END_STRING
|
28
|
+
expect(builder.generate_figcaption).to match_ignoring_whitespace(desired)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'generates a picture' do
|
32
|
+
desired = <<~END_DESIRED
|
33
|
+
<picture class='imgPicture'>
|
34
|
+
<source srcset="/assets/images/jekyll.webp" type="image/webp">
|
35
|
+
<source srcset="/assets/images/jekyll.png" type="image/png">
|
36
|
+
<img class="imgImg rounded shadow"
|
37
|
+
src="/assets/images/jekyll.png"
|
38
|
+
style='width: 100%; '
|
39
|
+
/>
|
40
|
+
</picture>
|
41
|
+
END_DESIRED
|
42
|
+
actual = builder.generate_picture
|
43
|
+
expect(actual).to match_ignoring_whitespace(desired)
|
44
|
+
end
|
45
|
+
|
8
46
|
it 'generates a default img' do
|
9
|
-
|
10
|
-
props.src = 'blah.webp'
|
11
|
-
builder = described_class.new(props)
|
12
|
-
picture = <<~END_IMG
|
47
|
+
desired = <<~END_IMG
|
13
48
|
<div class='imgWrapper imgFlex' style=' '>
|
14
49
|
<picture class='imgPicture'>
|
15
|
-
<source srcset="/assets/images/
|
16
|
-
<source srcset="/assets/images/
|
50
|
+
<source srcset="/assets/images/jekyll.webp" type="image/webp">
|
51
|
+
<source srcset="/assets/images/jekyll.png" type="image/png">
|
17
52
|
<img class="imgImg rounded shadow"
|
18
|
-
src="/assets/images/
|
53
|
+
src="/assets/images/jekyll.png"
|
19
54
|
style='width: 100%; '
|
20
55
|
/>
|
21
56
|
</picture>
|
22
57
|
</div>
|
23
58
|
END_IMG
|
24
59
|
|
25
|
-
|
26
|
-
expect(
|
60
|
+
actual = builder.generate_wrapper
|
61
|
+
expect(actual).to match_ignoring_whitespace(desired)
|
27
62
|
end
|
28
63
|
|
29
|
-
it 'generates an img with size and caption' do
|
30
|
-
props = ImgProperties.new
|
64
|
+
it 'generates an img wrapper with size and caption' do
|
31
65
|
props.caption = 'This is a caption'
|
32
66
|
props.size = '123px'
|
33
|
-
props.src = 'blah.webp'
|
34
67
|
builder = described_class.new(props)
|
35
68
|
|
36
69
|
caption = <<~END_CAPTION
|
@@ -39,15 +72,15 @@ class ImgPropertiesTest
|
|
39
72
|
</figcaption>
|
40
73
|
END_CAPTION
|
41
74
|
|
42
|
-
|
75
|
+
desired = <<~END_IMG
|
43
76
|
<div class='imgWrapper imgBlock' style='width: 123px; '>
|
44
77
|
<figure>
|
45
78
|
<picture class='imgPicture'>
|
46
|
-
<source srcset="/assets/images/
|
47
|
-
<source srcset="/assets/images/
|
79
|
+
<source srcset="/assets/images/jekyll.webp" type="image/webp">
|
80
|
+
<source srcset="/assets/images/jekyll.png" type="image/png">
|
48
81
|
<img alt='This is a caption'
|
49
82
|
class="imgImg rounded shadow"
|
50
|
-
src="/assets/images/
|
83
|
+
src="/assets/images/jekyll.png"
|
51
84
|
style='width: 100%; '
|
52
85
|
title='This is a caption'
|
53
86
|
/>
|
@@ -57,8 +90,8 @@ class ImgPropertiesTest
|
|
57
90
|
</div>
|
58
91
|
END_IMG
|
59
92
|
|
60
|
-
|
61
|
-
expect(
|
93
|
+
actual = builder.generate_wrapper
|
94
|
+
expect(actual).to match_ignoring_whitespace(desired)
|
62
95
|
end
|
63
96
|
end
|
64
97
|
end
|
data/spec/img_props_spec.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require_relative '../lib/img_props'
|
2
2
|
|
3
|
-
class
|
3
|
+
class ImgPropertiesTest
|
4
4
|
RSpec.describe ImgProperties do
|
5
5
|
it 'detects relative paths' do
|
6
6
|
expect(described_class.local_path?('abcdef')).to be false
|
@@ -26,15 +26,19 @@ class ImgProperitesTest
|
|
26
26
|
expect(props.attr_target).to eq(" target='_blank'")
|
27
27
|
expect(props.attr_title).to be_nil
|
28
28
|
expect(props.attr_width_style).to be_nil
|
29
|
-
|
30
|
-
props.compute_dependant_properties
|
31
|
-
expect(props.attr_wrapper_align_class).to eq('inline')
|
32
29
|
end
|
33
30
|
|
31
|
+
# it 'defaults to inline alignment' do
|
32
|
+
# props = described_class.new
|
33
|
+
# props.src = 'relative/path.webp'
|
34
|
+
# props.compute_dependant_properties
|
35
|
+
# expect(props.attr_wrapper_align_class).to eq('inline')
|
36
|
+
# end
|
37
|
+
|
34
38
|
it 'raises exception if src was not specified' do
|
35
39
|
props = described_class.new
|
36
|
-
expect { props.
|
37
|
-
expect { props.send(:setup_src) }.to raise_error(
|
40
|
+
expect { props.compute_dependant_properties }.to raise_error(Jekyll::ImgError)
|
41
|
+
expect { props.send(:setup_src) }.to raise_error(Jekyll::ImgError)
|
38
42
|
|
39
43
|
props.src = 'relative/path.webp'
|
40
44
|
props.send(:setup_src)
|
@@ -69,21 +73,18 @@ class ImgProperitesTest
|
|
69
73
|
|
70
74
|
props.size = '100px'
|
71
75
|
expect(props.attr_size_class).to be_nil
|
72
|
-
expect(props.attr_style_img).to eq("style='
|
76
|
+
expect(props.attr_style_img).to eq("style='width: 100%; '")
|
73
77
|
expect(props.attr_width_style).to eq('width: 100px;')
|
74
78
|
|
75
79
|
props.size = '10%'
|
76
80
|
expect(props.attr_size_class).to be_nil
|
77
|
-
expect(props.attr_style_img).to eq("style='max-width: 10%;'")
|
78
81
|
expect(props.attr_width_style).to eq('width: 10%;')
|
82
|
+
expect(props.attr_style_img).to eq("style='width: 100%; '")
|
79
83
|
|
80
84
|
props.size = 'fullsize'
|
81
85
|
expect(props.attr_size_class).to eq('fullsize')
|
82
86
|
expect(props.attr_width_style).to be_nil
|
83
87
|
|
84
|
-
props.style = 'width: 30rem;'
|
85
|
-
expect(props.attr_style_img).to eq("style='width: 30rem;'")
|
86
|
-
|
87
88
|
props.target = 'moon'
|
88
89
|
expect(props.attr_target).to eq(" target='moon'")
|
89
90
|
|
@@ -95,17 +96,5 @@ class ImgProperitesTest
|
|
95
96
|
expect(props.attr_size_class).to be_nil
|
96
97
|
expect(props.attr_width_style).to eq('width: 100px;')
|
97
98
|
end
|
98
|
-
|
99
|
-
it 'generates proper alignment attributes' do
|
100
|
-
props = described_class.new
|
101
|
-
|
102
|
-
props.align = 'inline'
|
103
|
-
props.compute_dependant_properties
|
104
|
-
expect(props.attr_wrapper_align_class).to eq('inline')
|
105
|
-
|
106
|
-
props.align = 'center'
|
107
|
-
props.compute_dependant_properties
|
108
|
-
expect(props.attr_wrapper_align_class).to eq('center')
|
109
|
-
end
|
110
99
|
end
|
111
100
|
end
|
data/spec/jekyll_img_spec.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
require 'jekyll'
|
2
2
|
require 'jekyll_plugin_logger'
|
3
|
+
require 'helper/jekyll_plugin_helper'
|
4
|
+
require 'jekyll_plugin_support'
|
3
5
|
require 'rspec/match_ignoring_whitespace'
|
4
6
|
require_relative '../lib/jekyll_img'
|
5
7
|
|
6
|
-
Registers = Struct.new(:page, :site)
|
8
|
+
Registers = Struct.new(:page, :site) unless defined? :Registers
|
7
9
|
|
8
10
|
# Mock for Collections
|
9
11
|
class Collections
|
@@ -46,14 +48,15 @@ class MyTest
|
|
46
48
|
let(:parse_context) { TestParseContext.new }
|
47
49
|
|
48
50
|
let(:helper) do
|
49
|
-
JekyllPluginHelper.new(
|
51
|
+
::JekyllSupport::JekyllPluginHelper.new(
|
50
52
|
'img',
|
51
53
|
'src="./blah.webp"',
|
52
|
-
logger
|
54
|
+
logger,
|
55
|
+
false
|
53
56
|
)
|
54
57
|
end
|
55
58
|
|
56
|
-
|
59
|
+
xit 'has no cite or url' do
|
57
60
|
helper.reinitialize('src="./blah.webp"')
|
58
61
|
img = described_class.send(
|
59
62
|
:new,
|
@@ -61,10 +64,11 @@ class MyTest
|
|
61
64
|
helper.markup.dup,
|
62
65
|
parse_context
|
63
66
|
)
|
64
|
-
|
65
|
-
|
67
|
+
actual = img.render_impl
|
68
|
+
desired = <<~END_DESIRED
|
66
69
|
<img src="./blah.webp">
|
67
|
-
|
70
|
+
END_DESIRED
|
71
|
+
expect(actual).to match_ignoring_whitespace(desired)
|
68
72
|
end
|
69
73
|
end
|
70
74
|
end
|
data/spec/source_spec.rb
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'rspec/match_ignoring_whitespace'
|
2
|
+
require_relative '../lib/source'
|
3
|
+
|
4
|
+
# Test ImgProperties
|
5
|
+
class ImgPropertiesTest
|
6
|
+
RSpec.describe Source do
|
7
|
+
Dir.chdir("#{__dir__}/../demo")
|
8
|
+
source_absolute = described_class.new('/assets/images/jekyll_240x103.webp')
|
9
|
+
source_relative = described_class.new('./assets/images/jekyll_240x103.webp')
|
10
|
+
|
11
|
+
it 'globs absolute paths' do
|
12
|
+
expect(source_absolute.send(:globbed_path)).to eq("./assets/images/jekyll_240x103.*")
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'globs relative paths' do
|
16
|
+
expect(source_relative.send(:globbed_path)).to eq("./assets/images/jekyll_240x103.*")
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'sorts files with absolute path' do
|
20
|
+
actual = source_absolute.send(:sorted_files)
|
21
|
+
desired = [
|
22
|
+
"/assets/images/jekyll_240x103.webp",
|
23
|
+
"/assets/images/jekyll_240x103.png",
|
24
|
+
"/assets/images/jekyll_240x103.jpg",
|
25
|
+
"/assets/images/jekyll_240x103.gif",
|
26
|
+
"/assets/images/jekyll_240x103.txt"
|
27
|
+
]
|
28
|
+
expect(actual).to eq(desired)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'sorts files with relative path' do
|
32
|
+
actual = source_relative.send(:sorted_files)
|
33
|
+
desired = [
|
34
|
+
"./assets/images/jekyll_240x103.webp",
|
35
|
+
"./assets/images/jekyll_240x103.png",
|
36
|
+
"./assets/images/jekyll_240x103.jpg",
|
37
|
+
"./assets/images/jekyll_240x103.gif",
|
38
|
+
"./assets/images/jekyll_240x103.txt"
|
39
|
+
]
|
40
|
+
expect(actual).to eq(desired)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'generates mimetype for absolute paths' do
|
44
|
+
expect(source_absolute.send(:mimetype, 'blah.png')).to eq('image/png')
|
45
|
+
expect(source_absolute.send(:mimetype, 'blah.svg')).to eq('image/svg')
|
46
|
+
expect(source_absolute.send(:mimetype, 'blah.webp')).to eq('image/webp')
|
47
|
+
expect(source_absolute.send(:mimetype, 'blah.gif')).to eq('image/gif')
|
48
|
+
expect(source_absolute.send(:mimetype, 'blah.blah')).to be_nil
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'generates mimetype for relative paths' do
|
52
|
+
expect(source_relative.send(:mimetype, 'blah.png')).to eq('image/png')
|
53
|
+
expect(source_relative.send(:mimetype, 'blah.svg')).to eq('image/svg')
|
54
|
+
expect(source_relative.send(:mimetype, 'blah.webp')).to eq('image/webp')
|
55
|
+
expect(source_relative.send(:mimetype, 'blah.gif')).to eq('image/gif')
|
56
|
+
expect(source_relative.send(:mimetype, 'blah.blah')).to be_nil
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'generates source fallback for absolute paths' do
|
60
|
+
expect(source_absolute.src_fallback).to eq("/assets/images/jekyll_240x103.png")
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'generates source fallback for relative paths' do
|
64
|
+
expect(source_relative.src_fallback).to eq("./assets/images/jekyll_240x103.png")
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'generates sources for absolute paths' do
|
68
|
+
actual = source_absolute.generate.join("\n")
|
69
|
+
desired = <<~END_DESIRED
|
70
|
+
<source srcset="/assets/images/jekyll_240x103.webp" type="image/webp">
|
71
|
+
<source srcset="/assets/images/jekyll_240x103.png" type="image/png">
|
72
|
+
<source srcset="/assets/images/jekyll_240x103.gif" type="image/gif">
|
73
|
+
END_DESIRED
|
74
|
+
expect(actual).to match_ignoring_whitespace(desired)
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'generates sources for relative paths' do
|
78
|
+
actual = source_relative.generate.join("\n")
|
79
|
+
desired = <<~END_DESIRED
|
80
|
+
<source srcset="./assets/images/jekyll_240x103.webp" type="image/webp">
|
81
|
+
<source srcset="./assets/images/jekyll_240x103.png" type="image/png">
|
82
|
+
<source srcset="./assets/images/jekyll_240x103.gif" type="image/gif">
|
83
|
+
END_DESIRED
|
84
|
+
expect(actual).to match_ignoring_whitespace(desired)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
example_id | status | run_time |
|
2
|
+
------------------------------- | ------ | --------------- |
|
3
|
+
./spec/img_builder_spec.rb[1:1] | failed | 14.37 seconds |
|
4
|
+
./spec/img_builder_spec.rb[1:2] | failed | 0.01498 seconds |
|
5
|
+
./spec/img_builder_spec.rb[1:3] | failed | 0.00093 seconds |
|
6
|
+
./spec/img_props_spec.rb[1:1] | passed | 0.00393 seconds |
|
7
|
+
./spec/img_props_spec.rb[1:2] | passed | 0.00006 seconds |
|
8
|
+
./spec/img_props_spec.rb[1:3] | passed | 0.00673 seconds |
|
9
|
+
./spec/img_props_spec.rb[1:4] | passed | 4.65 seconds |
|
10
|
+
./spec/img_props_spec.rb[1:5] | passed | 0.00009 seconds |
|
11
|
+
./spec/jekyll_img_spec.rb[1:1] | failed | 40.84 seconds |
|
12
|
+
./spec/source_spec.rb[1:1] | passed | 0.00089 seconds |
|
13
|
+
./spec/source_spec.rb[1:2] | passed | 0.0045 seconds |
|
14
|
+
./spec/source_spec.rb[1:3] | passed | 0.00687 seconds |
|
15
|
+
./spec/source_spec.rb[1:4] | passed | 0.00071 seconds |
|
16
|
+
./spec/source_spec.rb[1:5] | passed | 1.72 seconds |
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jekyll_img
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Slinn
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-09-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: jekyll
|
@@ -55,10 +55,13 @@ files:
|
|
55
55
|
- lib/img_props.rb
|
56
56
|
- lib/jekyll_img.rb
|
57
57
|
- lib/jekyll_img/version.rb
|
58
|
+
- lib/source.rb
|
58
59
|
- spec/img_builder_spec.rb
|
59
60
|
- spec/img_props_spec.rb
|
60
61
|
- spec/jekyll_img_spec.rb
|
62
|
+
- spec/source_spec.rb
|
61
63
|
- spec/spec_helper.rb
|
64
|
+
- spec/status_persistence.txt
|
62
65
|
homepage: https://www.mslinn.com/jekyll_plugins/jekyll_img.html
|
63
66
|
licenses:
|
64
67
|
- MIT
|
@@ -94,5 +97,7 @@ test_files:
|
|
94
97
|
- spec/img_builder_spec.rb
|
95
98
|
- spec/img_props_spec.rb
|
96
99
|
- spec/jekyll_img_spec.rb
|
100
|
+
- spec/source_spec.rb
|
97
101
|
- spec/spec_helper.rb
|
102
|
+
- spec/status_persistence.txt
|
98
103
|
...
|