jekyll-cloudinary-fork 1.9.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e47e23ffa0daacd2fa66d9ab8e03cd9406264d40
4
+ data.tar.gz: a3ab751a78912ffd02ed7fce8d7c7fd165c88137
5
+ SHA512:
6
+ metadata.gz: fb9553b652dc51f3a83194c8fe9caf070ad2eea5d69c2c2291efa1bfbd5081727bba427438ddecff267d5e1a27379f90fba0a1510b6b6939f6777d97b0b07d49
7
+ data.tar.gz: 3c878d7660301bea3b6a5bca5cfba2eb0c21a32c915cd2dae4ea690457a9a054a6c1617a19697e7b2c3f40ebf71dbd9a617ae91dc2adf760655d6952b48709c9
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in jekyll-post-files.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Nicolas Hoizey
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,362 @@
1
+ # Jekyll Cloudinary Liquid tag
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/jekyll-cloudinary.svg)](https://badge.fury.io/rb/jekyll-cloudinary)
4
+ [![Gem Downloads](https://img.shields.io/gem/dt/jekyll-cloudinary.svg?style=flat)](http://rubygems.org/gems/jekyll-cloudinary)
5
+
6
+ `jekyll-cloudinary` is a [Jekyll](http://jekyllrb.com/) plugin adding a [Liquid](http://liquidmarkup.org) tag to ease the use of [Cloudinary](https://nho.io/cloudinary-signup) for responsive images in your Markdown/[Kramdown](http://kramdown.gettalong.org/) posts.
7
+
8
+ It builds the HTML for responsive images in the posts, using the `srcset` and `sizes` attributes for the `<img />` tag (see [the "varying size and density" section of this post](https://jakearchibald.com/2015/anatomy-of-responsive-images/#varying-size-and-density) if this is new for you, and why it's recommended to [not use `<picture>` most of the time](https://cloudfour.com/thinks/dont-use-picture-most-of-the-time/)). URLs in the `srcset` are cloudinary URLs that [fetch on-the-fly](http://cloudinary.com/features#fetch) the post's images and resize them to several sizes.
9
+
10
+ You are in full control of the number of generated images and their sizes, and the `sizes` attribute that helps the browser decide which image to download. See the complete configuration options for details.
11
+
12
+ Here is the general syntax of this Liquid tag:
13
+
14
+ {% raw %}
15
+ ```markdown
16
+ {% cloudinary cloudflare.png alt="Un schéma montrant l'apport de Cloudflare" caption="Un schéma montrant l'apport de Cloudflare" %}
17
+ ```
18
+ {% endraw %}
19
+
20
+ <!-- START doctoc generated TOC please keep comment here to allow auto update -->
21
+ <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
22
+ ## Table of contents
23
+
24
+ - [Installation](#installation)
25
+ - [Configuration](#configuration)
26
+ - [Mandatory settings](#mandatory-settings)
27
+ - [Optional global settings](#optional-global-settings)
28
+ - [`verbose` (default: `false`)](#verbose-default-false)
29
+ - [Optional (but highly recommended) presets](#optional-but-highly-recommended-presets)
30
+ - [Default preset](#default-preset)
31
+ - [Additional presets](#additional-presets)
32
+ - [Detailed preset settings](#detailed-preset-settings)
33
+ - [`figure` (default: `auto`)](#figure-default-auto)
34
+ - [`min_width` (default: `320`)](#min_width-default-320)
35
+ - [`max_width` (default: `1200`)](#max_width-default-1200)
36
+ - [`fallback_max_width` (defaut: `1200`)](#fallback_max_width-defaut-1200)
37
+ - [`steps` (default: `5`)](#steps-default-5)
38
+ - [`sizes` (default: `"100vw"`)](#sizes-default-100vw)
39
+ - [`attributes` (default: none)](#attributes-default-none)
40
+ - [Live example](#live-example)
41
+ - [To do](#to-do)
42
+ - [Do you use the plugin on a live site?](#do-you-use-the-plugin-on-a-live-site)
43
+
44
+ <!-- END doctoc generated TOC please keep comment here to allow auto update -->
45
+
46
+ ## Installation
47
+
48
+ [Sign up **for free** on Cloudinary!](https://nho.io/cloudinary-signup) The free account should be enough for most blogs.
49
+
50
+ Add `gem 'jekyll-cloudinary'` to the `jekyll_plugin` group in your `Gemfile`:
51
+
52
+ ```ruby
53
+ source 'https://rubygems.org'
54
+
55
+ gem 'jekyll'
56
+
57
+ group :jekyll_plugins do
58
+ gem 'jekyll-cloudinary'
59
+ end
60
+ ```
61
+
62
+ Then run `bundle` to install the gem.
63
+
64
+ ## Configuration
65
+
66
+ ### Mandatory settings
67
+
68
+ Add `cloudinary` to your `_config.yml` and your Cloudinary "Cloud name" (find it in your [Cloudinary dashboard](https://cloudinary.com/console)):
69
+
70
+ ```yaml
71
+ cloudinary:
72
+ cloud_name: <put here your Cloudinary "Cloud name">
73
+ ```
74
+
75
+ ### Optional global settings
76
+
77
+ You can now define some global settings
78
+
79
+ ```yaml
80
+ cloudinary:
81
+
82
+ verbose: true
83
+ ```
84
+
85
+ #### `verbose` (default: `false`)
86
+
87
+ When set to `true`, this setting will show messages in the console when something goes wrong, such as:
88
+
89
+ ```
90
+ [Cloudinary] Couldn't find this image to check its width: /path/to/jekyll/_site/assets/img.jpg
91
+ ```
92
+
93
+ or
94
+
95
+ ```
96
+ [Cloudinary] Natural width of source image 'img.jpg' (720px) in _posts/2016-06-09-post.md not enough for creating 1600px version
97
+ ```
98
+
99
+ #### `url`
100
+
101
+ When `url` is set, jekyll-cloudinary will use this url, rather than `site.url` to build image links. This has two key use cases:
102
+
103
+ 1. When your images are stored on different server than where your site is hosted, use the `url` setting to point correctly to them.
104
+
105
+ 2. In development mode, `site.url` is overridden by Jekyll to `localhost:4000`. This has the unfortunate consequence of breaking all
106
+ Cloudinary tagged images on your site, because Cloudinary cannot fetch remotely from your localhost. Jekyll recommends that you run the site in `production` mode as a work around, but this has the consequence of pointing all internal links to your site's domain.
107
+
108
+ Using the `url` setting you can mitigate this by pointing the loudinary images to the url where they exist, while allowing your development site to still function correctly.
109
+
110
+ ### Optional (but highly recommended) presets
111
+
112
+ You can now define the presets you need for your posts' images, starting with the default one:
113
+
114
+ #### Default preset
115
+
116
+ The default preset is the one you don't even have to mention when using the Liquid tag, and that will be used if a preset you use in the tag doesn't exist.
117
+
118
+ ```yaml
119
+ cloudinary:
120
+
121
+ presets:
122
+ default:
123
+ min_width: 320
124
+ max_width: 1600
125
+ fallback_max_width: 800
126
+ steps: 5
127
+ sizes: "(min-width: 50rem) 50rem, 90vw"
128
+ ```
129
+
130
+ This preset will generate five images 320 to 1600 pixels wide in the `srcset` and define `sizes` as `"(min-width: 50rem) 50rem, 90vw"`. The fallback image defined in the `src` will have a width of 800 pixels.
131
+
132
+ With this preset, you only have to write this in your Markdown post:
133
+
134
+ {% raw %}
135
+ ```markdown
136
+ {% cloudinary /assets/img.jpg alt="beautiful!" %}
137
+ ```
138
+ {% endraw %}
139
+
140
+ To get this HTML:
141
+
142
+ ```html
143
+ <img
144
+ src="http://res.cloudinary.com/<cloud_name>/image/fetch/c_limit,w_800,q_auto,f_auto/https://<your-domain>/assets/img.jpg"
145
+ srcset="
146
+ http://res.cloudinary.com/<cloud_name>/image/fetch/c_limit,w_320,q_auto,f_auto/https://<your-domain>/assets/img.jpg 320w,
147
+ http://res.cloudinary.com/<cloud_name>/image/fetch/c_limit,w_640,q_auto,f_auto/https://<your-domain>/assets/img.jpg 640w
148
+ http://res.cloudinary.com/<cloud_name>/image/fetch/c_limit,w_960,q_auto,f_auto/https://<your-domain>/assets/img.jpg 960w
149
+ http://res.cloudinary.com/<cloud_name>/image/fetch/c_limit,w_1280,q_auto,f_auto/https://<your-domain>/assets/img.jpg 1280w
150
+ http://res.cloudinary.com/<cloud_name>/image/fetch/c_limit,w_1600,q_auto,f_auto/https://<your-domain>/assets/img.jpg 1600w
151
+ "
152
+ sizes="(min-width: 50rem) 50rem, 90vw"
153
+ alt="beautiful!"
154
+ width="480"
155
+ height="320"
156
+ />
157
+ ```
158
+
159
+ There is a true default `default` preset, but you're strongly encouraged to override it with your own default preset.
160
+
161
+ #### Additional presets
162
+
163
+ You can add other presets if you need several image sizes in your posts.
164
+
165
+ Here is an example for images that take only one third of the post width:
166
+
167
+ ```yaml
168
+ cloudinary:
169
+
170
+ presets:
171
+
172
+ onethird:
173
+ min_width: 110
174
+ max_width: 535
175
+ fallback_max_width: 300
176
+ steps: 3
177
+ sizes: "(min-width: 50rem) 17rem, 30vw"
178
+ attributes:
179
+ class: "one3rd"
180
+ ```
181
+
182
+ To use this additional preset, you will have to write this in your Markdown post:
183
+
184
+ {% raw %}
185
+ ```markdown
186
+ {% cloudinary onethird /assets/img.jpg %}
187
+ ```
188
+ {% endraw %}
189
+
190
+ The generated element will also get a `class="one3rd"` that can be useful for example with this CSS:
191
+
192
+ ```css
193
+ .one3rd {
194
+ max-width: 33%;
195
+ float: right;
196
+ margin: 0 0 1em 1em;
197
+ }
198
+ ```
199
+
200
+ ### Detailed preset settings
201
+
202
+ #### `figure` (default: `auto`)
203
+
204
+ This setting lets you decide what to do when there is a `caption` attribute in the Cloudinary Liquid tag.
205
+
206
+ The value can be:
207
+
208
+ - `auto` (default): will generate a `<figure>` and `<figcaption>` only if there's a caption
209
+ - `never`: will always generate a `<img>`, losing the caption
210
+ - `always`: will always generate a `<figure>` and `<figcaption>`, even if there's no `caption` attribute
211
+
212
+ If a `<figure>` is generated and there are attributes in the Liquid tag, they are added to the `<img>` if they are `alt` or `title`, or to the `<figure>`.
213
+
214
+ #### `min_width` (default: `320`)
215
+
216
+ #### `max_width` (default: `1200`)
217
+
218
+ #### `fallback_max_width` (defaut: `1200`)
219
+
220
+ #### `steps` (default: `5`)
221
+
222
+ #### `sizes` (default: `"100vw"`)
223
+
224
+ #### `attributes` (default: none)
225
+
226
+ Attributes are added without transformation to the generated element.
227
+
228
+ You can obviously define the `alt` attribute, mandatory for accessibility, but you can also set a `title`, a `class`, `aria-*` attributes for enhanced accessibility, or even `data-*` attributes you would like to use later with CSS or JavaScript.
229
+
230
+ The `caption` attribute is the only one that can act differently, depending on the `figure` setting.
231
+
232
+ `alt`, `title` and `caption` attributes can contain Markdown.
233
+
234
+ ## Live example
235
+
236
+ Go to this post: [https://nicolas-hoizey.com/2016/07/tout-change-rien-ne-change.html](https://nicolas-hoizey.com/2016/07/tout-change-rien-ne-change.html).
237
+
238
+ The source Markdown is here: [https://github.com/nhoizey/nicolas-hoizey.com/blob/master/_posts/2016/07/13-tout-change-rien-ne-change/2016-07-13-tout-change-rien-ne-change.md](https://github.com/nhoizey/nicolas-hoizey.com/blob/master/_posts/2016/07/13-tout-change-rien-ne-change/2016-07-13-tout-change-rien-ne-change.md).
239
+
240
+ The content is in french, yes, but look only at the images if you don't understand.
241
+
242
+ You'll find here:
243
+
244
+ - 2 logos floating on the right of the text (or centered on smaller screens): [Jekyll](http://jekyllrb.com/) and [Cloudinary](https://nho.io/cloudinary-signup)
245
+ - 2 screenshots taking the whole width of the content: the [Cloudinary pricing table](http://cloudinary.com/pricing), and [Dareboost](https://www.dareboost.com/en/home)'s performance monitoring graph
246
+
247
+ These image types need different settings to deal with different sizes and position:
248
+
249
+ - screenshot always use the full content width, if they're wide enough
250
+ - logos are centered and take one half of the content width on small screens, and are floated and take one fourth of the content width on larger screens
251
+
252
+ This is how I use the Cloudinary Liquid tag for the Cloudinary logo and prices table screenshot:
253
+
254
+ {% raw %}
255
+ ```markdown
256
+ {% cloudinary logo /assets/logos/cloudinary.png alt="Logo de Cloudinary" %}
257
+ {% cloudinary cloudinary-pricing.png alt="Les tarifs de Cloudinary" caption="Les tarifs de Cloudinary, dont l'offre gratuite déjà généreuse" %}
258
+ ```
259
+ {% endraw %}
260
+
261
+ The only difference is that I explicitly use the `logo` preset for the logo. The other image uses the `default` preset.
262
+
263
+ Here is the necessary configuration for this:
264
+
265
+ ```yaml
266
+ cloudinary:
267
+ cloud_name: …
268
+ verbose: false
269
+ presets:
270
+ default:
271
+ min_width: 320
272
+ max_width: 1600
273
+ fallback_max_width: 800
274
+ steps: 5
275
+ sizes: '(min-width: 50rem) 50rem, 90vw'
276
+ figure: always
277
+ logo:
278
+ min_width: 80
279
+ max_width: 400
280
+ fallback_max_width: 200
281
+ steps: 3
282
+ sizes: '(min-width: 50rem) 13rem, (min-width: 40rem) 25vw, 45vw'
283
+ figure: never
284
+ attributes:
285
+ class: logo
286
+ ```
287
+
288
+ It generates these HTML fragments (pretty printed here), for the logo:
289
+
290
+ ```html
291
+ <img
292
+ src="https://res.cloudinary.com/nho/image/fetch/c_limit,w_200,q_auto,f_auto/https://nicolas-hoizey.com/assets/logos/cloudinary.png"
293
+ srcset="
294
+ https://res.cloudinary.com/nho/image/fetch/c_limit,w_80,q_auto,f_auto/https://nicolas-hoizey.com/assets/logos/cloudinary.png 80w,
295
+ https://res.cloudinary.com/nho/image/fetch/c_limit,w_240,q_auto,f_auto/https://nicolas-hoizey.com/assets/logos/cloudinary.png 240w,
296
+ https://res.cloudinary.com/nho/image/fetch/c_limit,w_400,q_auto,f_auto/https://nicolas-hoizey.com/assets/logos/cloudinary.png 400w"
297
+ sizes="
298
+ (min-width: 50rem) 13rem,
299
+ (min-width: 40rem) 25vw,
300
+ 45vw"
301
+ class="logo"
302
+ alt="Logo de Cloudinary"
303
+ width="480"
304
+ height="350"
305
+ />
306
+ ```
307
+
308
+ And for the screenshot:
309
+
310
+ ```html
311
+ <figure>
312
+ <img
313
+ src="https://res.cloudinary.com/nho/image/fetch/c_limit,w_800,q_auto,f_auto/https://nicolas-hoizey.com/2016/07/cloudinary-pricing.png"
314
+ srcset="
315
+ https://res.cloudinary.com/nho/image/fetch/c_limit,w_320,q_auto,f_auto/https://nicolas-hoizey.com/2016/07/cloudinary-pricing.png 320w,
316
+ https://res.cloudinary.com/nho/image/fetch/c_limit,w_640,q_auto,f_auto/https://nicolas-hoizey.com/2016/07/cloudinary-pricing.png 640w,
317
+ https://res.cloudinary.com/nho/image/fetch/c_limit,w_960,q_auto,f_auto/https://nicolas-hoizey.com/2016/07/cloudinary-pricing.png 960w,
318
+ https://res.cloudinary.com/nho/image/fetch/c_limit,w_1208,q_auto,f_auto/https://nicolas-hoizey.com/2016/07/cloudinary-pricing.png 1208w"
319
+ sizes="(min-width: 50rem) 50rem, 90vw"
320
+ alt="Les tarifs de Cloudinary"
321
+ width="1208"
322
+ height="561"
323
+ />
324
+ <figcaption>Les tarifs de Cloudinary, dont l'offre gratuite déjà généreuse</figcaption>
325
+ </figure>
326
+ ```
327
+
328
+ There are only 4 version in the `srcset` here because 2 of the 5 expected sizes are larger than the source image, and are replaced by one using the native source image width.
329
+
330
+ And here are the relevant parts of the accompanying CSS (in Sass form):
331
+
332
+ ```sass
333
+ article {
334
+ figure, img {
335
+ margin: 2em auto;
336
+ display: block;
337
+ max-width: 100%;
338
+ height: auto;
339
+ }
340
+ }
341
+
342
+ .logo {
343
+ display: block;
344
+ margin: 1em auto;
345
+ max-width: 50%;
346
+ height: auto;
347
+
348
+ @media (min-width: 40em) {
349
+ max-width: 25%;
350
+ float: right;
351
+ margin: 0 0 1em 1em;
352
+ }
353
+ }
354
+ ```
355
+
356
+ ## To do
357
+
358
+ There are already [a few issues for bugs and things that should be added to the plugin](https://github.com/nhoizey/jekyll-cloudinary/issues), feel free to add your ideas!
359
+
360
+ ## Do you use the plugin on a live site?
361
+
362
+ Add it to [the "Sites" page of the wiki](https://github.com/nhoizey/jekyll-cloudinary/wiki/Sites) and please let me know on Twitter: [@nhoizey](https://twitter.com/nhoizey)
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+ task :default => :spec
@@ -0,0 +1 @@
1
+ require "jekyll/cloudinary"
@@ -0,0 +1,303 @@
1
+ module Jekyll
2
+ module Cloudinary
3
+
4
+ class CloudinaryTag < Liquid::Tag
5
+ require "fastimage"
6
+
7
+ def initialize(tag_name, markup, tokens)
8
+ @markup = markup
9
+ super
10
+ end
11
+
12
+ def render(context)
13
+ # Default settings
14
+ preset_defaults = {
15
+ "min_width" => 320,
16
+ "max_width" => 1200,
17
+ "fallback_max_width" => 1200,
18
+ "steps" => 5,
19
+ "sizes" => "100vw",
20
+ "figure" => "auto",
21
+ "attributes" => {},
22
+ "verbose" => false,
23
+ "width_height" => true,
24
+ # Cloudinary transformations
25
+ "height" => false,
26
+ "crop" => "limit",
27
+ "aspect_ratio" => false,
28
+ "gravity" => false,
29
+ "zoom" => false,
30
+ "x" => false,
31
+ "y" => false,
32
+ "format" => false,
33
+ "fetch_format" => "auto",
34
+ "quality" => "auto",
35
+ "radius" => false,
36
+ "angle" => false,
37
+ "effect" => false,
38
+ "opacity" => false,
39
+ "border" => false,
40
+ "background" => false,
41
+ "overlay" => false,
42
+ "underlay" => false,
43
+ "default_image" => false,
44
+ "delay" => false,
45
+ "color" => false,
46
+ "color_space" => false,
47
+ "dpr" => false,
48
+ "page" => false,
49
+ "density" => false,
50
+ "flags" => false,
51
+ "transformation" => false
52
+ }
53
+
54
+ # TODO: Add validation for this parameters
55
+ transformation_options = {
56
+ "height" => "h",
57
+ "crop" => "c", # can include add-on: imagga_scale
58
+ "aspect_ratio" => "ar",
59
+ "gravity" => "g",
60
+ "zoom" => "z",
61
+ "x" => "x",
62
+ "y" => "y",
63
+ "fetch_format" => "f",
64
+ "quality" => "q", # can include add-on: jpegmini
65
+ "radius" => "r",
66
+ "angle" => "a",
67
+ "effect" => "e", # can include add-on: viesus_correct
68
+ "opacity" => "o",
69
+ "border" => "bo",
70
+ "background" => "b",
71
+ "overlay" => "l",
72
+ "underlay" => "u",
73
+ "default_image" => "d",
74
+ "delay" => "dl",
75
+ "color" => "co",
76
+ "color_space" => "cs",
77
+ "dpr" => "dpr",
78
+ "page" => "pg",
79
+ "density" => "dn",
80
+ "flags" => "fl",
81
+ "transformation" => "t"
82
+ }
83
+
84
+ # Settings
85
+ site = context.registers[:site]
86
+ baseurl = site.config["baseurl"] || ""
87
+ settings = site.config["cloudinary"]
88
+ url = settings["url"] || site.config["url"]
89
+
90
+ # Get Markdown converter
91
+ markdown_converter = site.find_converter_instance(::Jekyll::Converters::Markdown)
92
+
93
+ preset_user_defaults = {}
94
+ if settings["presets"]
95
+ if settings["presets"]["default"]
96
+ preset_user_defaults = settings["presets"]["default"]
97
+ end
98
+ end
99
+
100
+ preset = preset_defaults.merge(preset_user_defaults)
101
+
102
+ # Render any liquid variables in tag arguments and unescape template code
103
+ rendered_markup = Liquid::Template
104
+ .parse(@markup)
105
+ .render(context)
106
+ .gsub(%r!\\\{\\\{|\\\{\\%!, '\{\{' => '{{', '\{\%' => '{%')
107
+
108
+ # Extract tag segments
109
+ markup =
110
+ %r!^(?:(?<preset>[^\s.:\/]+)\s+)?(?<image_src>[^\s]+\.[a-zA-Z0-9]{3,4})\s*(?<html_attr>[\s\S]+)?$!
111
+ .match(rendered_markup)
112
+
113
+ unless markup
114
+ Jekyll.logger.abort_with("[Cloudinary]", "Can't read this tag: #{@markup}")
115
+ end
116
+
117
+ image_src = markup[:image_src]
118
+
119
+ # Dynamic image type
120
+ type = "fetch"
121
+ # TODO: URL2PNG requires signed URLs… need to investigate more
122
+ # if /^url2png\:/.match(image_src)
123
+ # type = "url2png"
124
+ # image_src.gsub! "url2png:", ""
125
+ # end
126
+
127
+ if markup[:preset]
128
+ if settings["presets"][markup[:preset]]
129
+ preset = preset.merge(settings["presets"][markup[:preset]])
130
+ elsif settings["verbose"]
131
+ Jekyll.logger.warn(
132
+ "[Cloudinary]",
133
+ "'#{markup[:preset]}' preset for the Cloudinary plugin doesn't exist, \
134
+ using the default one"
135
+ )
136
+ end
137
+ end
138
+
139
+ attributes = preset["attributes"]
140
+
141
+ # Deep copy preset for single instance manipulation
142
+ instance = Marshal.load(Marshal.dump(preset))
143
+
144
+ # Process attributes
145
+ html_attr = if markup[:html_attr]
146
+ Hash[ *markup[:html_attr].scan(%r!(?<attr>[^\s="]+)(?:="(?<value>[^"]+)")?\s?!).flatten ]
147
+ else
148
+ {}
149
+ end
150
+
151
+ if instance["attr"]
152
+ html_attr = instance.delete("attr").merge(html_attr)
153
+ end
154
+
155
+ # Classes from the tag should complete, not replace, the ones from the preset
156
+ if html_attr["class"] && attributes["class"]
157
+ html_attr["class"] << " #{attributes["class"]}"
158
+ end
159
+ html_attr = attributes.merge(html_attr)
160
+
161
+ # Deal with the "caption" attribute as a true <figcaption>
162
+ if html_attr["caption"]
163
+ caption = markdown_converter.convert(html_attr["caption"])
164
+ html_attr.delete("caption")
165
+ end
166
+
167
+ # alt and title attributes should go only to the <img> even when there is a caption
168
+ img_attr = ""
169
+ if html_attr["alt"]
170
+ img_attr << " alt=\"#{html_attr["alt"]}\""
171
+ html_attr.delete("alt")
172
+ end
173
+ if html_attr["title"]
174
+ img_attr << " title=\"#{html_attr["title"]}\""
175
+ html_attr.delete("title")
176
+ end
177
+
178
+ attr_string = html_attr.map { |a, v| "#{a}=\"#{v}\"" }.join(" ")
179
+
180
+ # Figure out the Cloudinary transformations
181
+ transformations = []
182
+ transformations_string = ""
183
+ transformation_options.each do | key, shortcode |
184
+ if preset[key]
185
+ transformations << "#{shortcode}_#{preset[key]}"
186
+ end
187
+ end
188
+ if transformations.length > 0
189
+ transformations_string = transformations.compact.reject(&:empty?).join(',') + ","
190
+ end
191
+
192
+ # Build source image URL
193
+ is_image_remote = /^https?/.match(image_src)
194
+ if is_image_remote
195
+ # It’s remote
196
+ image_dest_path = image_src
197
+ image_dest_url = image_src
198
+ natural_width, natural_height = FastImage.size(image_dest_url)
199
+ # width_height = "width=\"#{natural_width}\" height=\"#{natural_height}\""
200
+ fallback_url = "https://res.cloudinary.com/#{settings["cloud_name"]}/image/#{type}/#{transformations_string}w_#{preset["fallback_max_width"]}/#{image_dest_url}"
201
+ else
202
+ # It’s a local image
203
+ is_image_src_absolute = %r!^/.*$!.match(image_src)
204
+ if is_image_src_absolute
205
+ image_src_path = File.join(
206
+ site.config["source"],
207
+ image_src
208
+ )
209
+ image_dest_path = File.join(
210
+ site.config["destination"],
211
+ image_src
212
+ )
213
+ image_dest_url = File.join(
214
+ url,
215
+ baseurl,
216
+ image_src
217
+ )
218
+ else
219
+ image_src_path = File.join(
220
+ site.config["source"],
221
+ File.dirname(context["page"]["path"]),
222
+ image_src
223
+ )
224
+ image_dest_path = File.join(
225
+ site.config["destination"],
226
+ File.dirname(context["page"]["url"]),
227
+ image_src
228
+ )
229
+ image_dest_url = File.join(
230
+ url,
231
+ baseurl,
232
+ File.dirname(context["page"]["url"]),
233
+ image_src
234
+ )
235
+ end
236
+ if File.exist?(image_src_path)
237
+ natural_width, natural_height = FastImage.size(image_src_path)
238
+ # width_height = "width=\"#{natural_width}\" height=\"#{natural_height}\""
239
+ fallback_url = "https://res.cloudinary.com/#{settings["cloud_name"]}/image/#{type}/#{transformations_string}w_#{preset["fallback_max_width"]}/#{image_dest_url}"
240
+ else
241
+ natural_width = 100_000
242
+ width_height = ""
243
+ Jekyll.logger.warn(
244
+ "[Cloudinary]",
245
+ "Couldn't find this image to check its width: #{image_src_path}."
246
+ )
247
+ fallback_url = image_dest_url
248
+ end
249
+ end
250
+
251
+ srcset = []
252
+ steps = preset["steps"].to_i
253
+ min_width = preset["min_width"].to_i
254
+ max_width = preset["max_width"].to_i
255
+ step_width = (max_width - min_width) / (steps - 1)
256
+ sizes = preset["sizes"]
257
+
258
+ if natural_width < min_width
259
+ if settings["verbose"]
260
+ Jekyll.logger.warn(
261
+ "[Cloudinary]",
262
+ "Width of source image '#{File.basename(image_src)}' (#{natural_width}px) \
263
+ in #{context["page"]["path"]} not enough for ANY srcset version"
264
+ )
265
+ end
266
+ srcset << "https://res.cloudinary.com/#{settings["cloud_name"]}/image/#{type}/#{transformations_string}w_#{natural_width}/#{image_dest_url} #{natural_width}w"
267
+ else
268
+ missed_sizes = []
269
+ (1..steps).each do |factor|
270
+ width = min_width + (factor - 1) * step_width
271
+ if width <= natural_width
272
+ srcset << "https://res.cloudinary.com/#{settings["cloud_name"]}/image/#{type}/#{transformations_string}w_#{width}/#{image_dest_url} #{width}w"
273
+ else
274
+ missed_sizes.push(width)
275
+ end
276
+ end
277
+ unless missed_sizes.empty?
278
+ srcset << "https://res.cloudinary.com/#{settings["cloud_name"]}/image/#{type}/#{transformations_string}w_#{natural_width}/#{image_dest_url} #{natural_width}w"
279
+ if settings["verbose"]
280
+ Jekyll.logger.warn(
281
+ "[Cloudinary]",
282
+ "Width of source image '#{File.basename(image_src)}' (#{natural_width}px) \
283
+ in #{context["page"]["path"]} not enough for #{missed_sizes.join("px, ")}px \
284
+ version#{missed_sizes.length > 1 ? "s" : ""}"
285
+ )
286
+ end
287
+ end
288
+ end
289
+ srcset_string = srcset.join(",\n")
290
+
291
+ # preset['figure'] can be 'never', 'auto' or 'always'
292
+ if (caption || preset["figure"] == "always") && preset["figure"] != "never"
293
+ "\n<figure #{attr_string}>\n<img src=\"#{fallback_url}\" srcset=\"#{srcset_string}\" sizes=\"#{sizes}\" #{img_attr} #{width_height} />\n<figcaption>#{caption}</figcaption>\n</figure>\n"
294
+ else
295
+ "<img src=\"#{fallback_url}\" srcset=\"#{srcset_string}\" sizes=\"#{sizes}\" #{attr_string} #{img_attr} #{width_height} />"
296
+ end
297
+ end
298
+ end
299
+
300
+ end
301
+ end
302
+
303
+ Liquid::Template.register_tag("cloudinary", Jekyll::Cloudinary::CloudinaryTag)
@@ -0,0 +1,5 @@
1
+ module Jekyll
2
+ module Cloudinary
3
+ VERSION = "1.9.1".freeze
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,133 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jekyll-cloudinary-fork
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.9.1
5
+ platform: ruby
6
+ authors:
7
+ - Chris Lyman (a fork of Nicolas Hoizey's work)
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-12-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: jekyll
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '4.0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '3.0'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '4.0'
33
+ - !ruby/object:Gem::Dependency
34
+ name: fastimage
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '2.0'
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: '3.0'
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: '2.0'
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: '3.0'
53
+ - !ruby/object:Gem::Dependency
54
+ name: bundler
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: '1.12'
60
+ type: :development
61
+ prerelease: false
62
+ version_requirements: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - "~>"
65
+ - !ruby/object:Gem::Version
66
+ version: '1.12'
67
+ - !ruby/object:Gem::Dependency
68
+ name: rake
69
+ requirement: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - "~>"
72
+ - !ruby/object:Gem::Version
73
+ version: '10.0'
74
+ type: :development
75
+ prerelease: false
76
+ version_requirements: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - "~>"
79
+ - !ruby/object:Gem::Version
80
+ version: '10.0'
81
+ - !ruby/object:Gem::Dependency
82
+ name: rubocop
83
+ requirement: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - "~>"
86
+ - !ruby/object:Gem::Version
87
+ version: 0.49.0
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - "~>"
93
+ - !ruby/object:Gem::Version
94
+ version: 0.49.0
95
+ description: " Liquid tag to use Cloudinary for optimized responsive posts images.\n"
96
+ email:
97
+ - ''
98
+ executables: []
99
+ extensions: []
100
+ extra_rdoc_files: []
101
+ files:
102
+ - Gemfile
103
+ - LICENSE
104
+ - README.md
105
+ - Rakefile
106
+ - lib/jekyll-cloudinary-fork.rb
107
+ - lib/jekyll/cloudinary.rb
108
+ - lib/jekyll/cloudinary/version.rb
109
+ homepage: https://github.com/suprafly/jekyll-cloudinary
110
+ licenses:
111
+ - MIT
112
+ metadata: {}
113
+ post_install_message:
114
+ rdoc_options: []
115
+ require_paths:
116
+ - lib
117
+ required_ruby_version: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ required_rubygems_version: !ruby/object:Gem::Requirement
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
127
+ requirements: []
128
+ rubyforge_project:
129
+ rubygems_version: 2.5.1
130
+ signing_key:
131
+ specification_version: 4
132
+ summary: Liquid tag for Jekyll with Cloudinary
133
+ test_files: []