jekyll-plugin-cloudinary 1.2

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6e547561350adf47a94f2f97d017cd3de3e92c453d31dc60890f9bba047993af
4
+ data.tar.gz: a414adbdccefbf0ad76dcbdd2ab77f4aaaf46792f1769b92ef67ced139e24e5c
5
+ SHA512:
6
+ metadata.gz: 7858c1a3e4a6aa41204a053a822c97183a2818657ae5272376cfdeca01b9054fa6c18fef80aa483e6cc2321fe0c7966f3547b58d3b7135ffb2bb615784e96cea
7
+ data.tar.gz: '08b547e5b2be54a64f3464f002b74ed334398fb343f19c66995f885a220bddc71578e15e9367f6ccbfcf93b4834d1495b201962ada2f1e1006dce6545b09338d'
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "https://rubygems.org"
2
+ 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,416 @@
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
+ ```liquid
16
+ {% cloudinary cloudflare.png alt="Un schéma montrant l'apport de Cloudflare" caption="Un schéma montrant l'apport de Cloudflare" loading="lazy" %}
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
+ - [`only_prod` (default: `false`)](#only_prod-default-false)
29
+ - [`verbose` (default: `false`)](#verbose-default-false)
30
+ - [`origin_url`](#origin_url)
31
+ - [Optional (but highly recommended) presets](#optional-but-highly-recommended-presets)
32
+ - [Default preset](#default-preset)
33
+ - [Additional presets](#additional-presets)
34
+ - [Detailed preset settings](#detailed-preset-settings)
35
+ - [`figure` (default: `auto`)](#figure-default-auto)
36
+ - [`min_width` (default: `320`)](#min_width-default-320)
37
+ - [`max_width` (default: `1200`)](#max_width-default-1200)
38
+ - [`fallback_max_width` (defaut: `1200`)](#fallback_max_width-defaut-1200)
39
+ - [`steps` (default: `5`)](#steps-default-5)
40
+ - [`sizes` (default: `"100vw"`)](#sizes-default-100vw)
41
+ - [`attributes` (default: none)](#attributes-default-none)
42
+ - [Liquid tag attributes](#liquid-tag-attributes)
43
+ - [Recommended attributes](#recommended-attributes)
44
+ - [Loading attribute](#loading-attribute)
45
+ - [Other interesting attributes](#other-interesting-attributes)
46
+ - [Live example](#live-example)
47
+ - [Contributing](#contributing)
48
+ - [Do you use the plugin on a live site?](#do-you-use-the-plugin-on-a-live-site)
49
+
50
+ <!-- END doctoc generated TOC please keep comment here to allow auto update -->
51
+
52
+ ## Installation
53
+
54
+ [Sign up **for free** on Cloudinary!](https://nho.io/cloudinary-signup) The free account should be enough for most blogs.
55
+
56
+ Add `gem 'jekyll-cloudinary'` to the `jekyll_plugin` group in your `Gemfile`:
57
+
58
+ ```ruby
59
+ source 'https://rubygems.org'
60
+
61
+ gem 'jekyll'
62
+
63
+ group :jekyll_plugins do
64
+ gem 'jekyll-cloudinary'
65
+ end
66
+ ```
67
+
68
+ Then run `bundle` to install the gem.
69
+
70
+ ## Configuration
71
+
72
+ ### Mandatory settings
73
+
74
+ Add `cloudinary` to your `_config.yml` and your Cloudinary "Cloud name" (find it in your [Cloudinary dashboard](https://cloudinary.com/console)):
75
+
76
+ ```yaml
77
+ cloudinary:
78
+ cloud_name: <put here your Cloudinary "Cloud name">
79
+ ```
80
+
81
+ ### Optional global settings
82
+
83
+ You can now define some global settings
84
+
85
+ ```yaml
86
+ cloudinary:
87
+
88
+ only_prod: true
89
+ verbose: true
90
+ origin_url: https://another-domain.com
91
+ ```
92
+
93
+ #### `only_prod` (default: `false`)
94
+
95
+ When set to `true`, this setting implies that responsive image HTML and Cloudinary URLs are generated only if the environnement is `production`.
96
+
97
+ For example:
98
+
99
+ - if you run `JEKYLL_ENV=production bundle exec jekyll build`, you'll get the code to deploy, with `srcset` and Cloudinary URLs.
100
+ - if you run `JEKYLL_ENV=development bundle exec jekyll serve`, you'll get code for local development, with standard `<img src="…">` code and local URLs.
101
+
102
+ [`JEKYLL_ENV=development` is the default value](https://jekyllrb.com/docs/configuration/#specifying-a-jekyll-environment-at-build-time).
103
+
104
+ If you don't set `only_prod` or set it to `false`, responsive image HTML and Cloudinary URLs are always generated, whatever the environment. jekyll-cloudinary had only this behavior before version 1.11.0.
105
+
106
+ #### `verbose` (default: `false`)
107
+
108
+ When set to `true`, this setting will show messages in the console when something goes wrong, such as:
109
+
110
+ ```
111
+ [Cloudinary] Couldn't find this image to check its width: /path/to/jekyll/_site/assets/img.jpg
112
+ ```
113
+
114
+ or
115
+
116
+ ```
117
+ [Cloudinary] Natural width of source image 'img.jpg' (720px) in _posts/2016-06-09-post.md not enough for creating 1600px version
118
+ ```
119
+
120
+ #### `origin_url`
121
+
122
+ When `origin_url` is set, jekyll-cloudinary will use this URL rather than `site.url` as origin of the source images.
123
+
124
+ This allows you to store your source image on a different domain than your website.
125
+
126
+ ### Optional (but highly recommended) presets
127
+
128
+ You can now define the presets you need for your posts' images, starting with the default one:
129
+
130
+ #### Default preset
131
+
132
+ 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.
133
+
134
+ ```yaml
135
+ cloudinary:
136
+
137
+ presets:
138
+ default:
139
+ min_width: 320
140
+ max_width: 1600
141
+ fallback_max_width: 800
142
+ steps: 5
143
+ sizes: "(min-width: 50rem) 50rem, 90vw"
144
+ ```
145
+
146
+ 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.
147
+
148
+ With this preset, you only have to write this in your Markdown post:
149
+
150
+ <!-- {% raw %} -->
151
+ ```liquid
152
+ {% cloudinary /assets/img.jpg alt="beautiful!" %}
153
+ ```
154
+ <!-- {% endraw %} -->
155
+
156
+ To get this HTML:
157
+
158
+ ```html
159
+ <img
160
+ src="http://res.cloudinary.com/<cloud_name>/image/fetch/c_limit,w_800,q_auto,f_auto/https://<your-domain>/assets/img.jpg"
161
+ srcset="
162
+ http://res.cloudinary.com/<cloud_name>/image/fetch/c_limit,w_320,q_auto,f_auto/https://<your-domain>/assets/img.jpg 320w,
163
+ http://res.cloudinary.com/<cloud_name>/image/fetch/c_limit,w_640,q_auto,f_auto/https://<your-domain>/assets/img.jpg 640w
164
+ http://res.cloudinary.com/<cloud_name>/image/fetch/c_limit,w_960,q_auto,f_auto/https://<your-domain>/assets/img.jpg 960w
165
+ http://res.cloudinary.com/<cloud_name>/image/fetch/c_limit,w_1280,q_auto,f_auto/https://<your-domain>/assets/img.jpg 1280w
166
+ http://res.cloudinary.com/<cloud_name>/image/fetch/c_limit,w_1600,q_auto,f_auto/https://<your-domain>/assets/img.jpg 1600w
167
+ "
168
+ sizes="(min-width: 50rem) 50rem, 90vw"
169
+ alt="beautiful!"
170
+ width="480"
171
+ height="320"
172
+ />
173
+ ```
174
+
175
+ There is a true default `default` preset, but you're strongly encouraged to override it with your own default preset.
176
+
177
+ #### Additional presets
178
+
179
+ You can add other presets if you need several image sizes in your posts.
180
+
181
+ Here is an example for images that take only one third of the post width:
182
+
183
+ ```yaml
184
+ cloudinary:
185
+
186
+ presets:
187
+
188
+ onethird:
189
+ min_width: 110
190
+ max_width: 535
191
+ fallback_max_width: 300
192
+ steps: 3
193
+ sizes: "(min-width: 50rem) 17rem, 30vw"
194
+ attributes:
195
+ class: "one3rd"
196
+ loading: "lazy"
197
+ ```
198
+
199
+ To use this additional preset, you will have to write this in your Markdown post:
200
+
201
+ <!-- {% raw %} -->
202
+ ```liquid
203
+ {% cloudinary onethird /assets/img.jpg %}
204
+ ```
205
+ <!-- {% endraw %} -->
206
+
207
+ The generated element will also get a `class="one3rd"` that can be useful for example with this CSS:
208
+
209
+ ```css
210
+ .one3rd {
211
+ max-width: 33%;
212
+ float: right;
213
+ margin: 0 0 1em 1em;
214
+ }
215
+ ```
216
+
217
+ ### Detailed preset settings
218
+
219
+ #### `figure` (default: `auto`)
220
+
221
+ This setting lets you decide what to do when there is a `caption` attribute in the Cloudinary Liquid tag.
222
+
223
+ The value can be:
224
+
225
+ - `auto` (default): will generate a `<figure>` and `<figcaption>` only if there's a caption
226
+ - `never`: will always generate a `<img>`, losing the caption
227
+ - `always`: will always generate a `<figure>` and `<figcaption>`, even if there's no `caption` attribute
228
+
229
+ If a `<figure>` is generated and there are attributes (in the preset or the Liquid tag), they are added to the `<img>` if they are `alt`, `title` or `loading`, or to the `<figure>`.
230
+
231
+ #### `min_width` (default: `320`)
232
+
233
+ #### `max_width` (default: `1200`)
234
+
235
+ #### `fallback_max_width` (defaut: `1200`)
236
+
237
+ #### `steps` (default: `5`)
238
+
239
+ #### `sizes` (default: `"100vw"`)
240
+
241
+ #### `attributes` (default: none)
242
+
243
+ You can define attributes that will be added to all images using this preset. Attributes are added without transformation to the generated element.
244
+
245
+ You should obviously not add to preset attributes that should have different values for each image, such as `alt`, `caption`, `title`, etc.
246
+
247
+ You can set a `class`, `aria-*` attributes for enhanced accessibility, or even `data-*` attributes you would like to use later with CSS or JavaScript.
248
+
249
+ ## Liquid tag attributes
250
+
251
+ You can add attributes to the liquid tag, after the image path:
252
+
253
+ <!-- {% raw %} -->
254
+ ```liquid
255
+ {% cloudinary onethird /assets/selfie.jpg alt="My selfie" loading="eager" %}
256
+ ```
257
+ <!-- {% endraw %} -->
258
+
259
+ Just like the ones from the preset settings, inline attributes are added without transformation to the generated element.
260
+
261
+ ### Recommended attributes
262
+
263
+ You should obviously define the `alt` attribute, mandatory for accessibility.
264
+
265
+ If you want the image to be inside a `figure` element, you probably also want to add a `caption` attribute. This is the only one that can act differently than other attributes, depending on [the `figure` setting](#figure-default-auto).
266
+
267
+ You can also set a `title` attribute, but there are really few use cases for it on images.
268
+
269
+ `alt`, `caption` and `title` attributes can contain Markdown.
270
+
271
+ ### Loading attribute
272
+
273
+ The `loading` attribute allows you to tell the browser how you want it to load this image.
274
+
275
+ From [this article written by Addy Osmani](https://addyosmani.com/blog/lazy-loading/):
276
+
277
+ > The loading attribute allows a browser to defer loading offscreen images and iframes until users scroll near them. loading supports three values:
278
+ > - `lazy`: is a good candidate for lazy loading.
279
+ > - `eager`: is not a good candidate for lazy loading. Load right away.
280
+ > - `auto`: browser will determine whether or not to lazily load.
281
+ >
282
+ > Not specifying the attribute at all will have the same impact as setting loading=auto.
283
+
284
+ ### Other interesting attributes
285
+
286
+ You can also use attributes to add a `class`, `aria-*` attributes for enhanced accessibility, or even `data-*` attributes you would like to use later with CSS or JavaScript.
287
+
288
+ ## Live example
289
+
290
+ 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).
291
+
292
+ 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).
293
+
294
+ The content is in french, yes, but look only at the images if you don't understand.
295
+
296
+ You'll find here:
297
+
298
+ - 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)
299
+ - 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
300
+
301
+ These image types need different settings to deal with different sizes and position:
302
+
303
+ - screenshot always use the full content width, if they're wide enough
304
+ - 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
305
+
306
+ This is how I use the Cloudinary Liquid tag for the Cloudinary logo and prices table screenshot:
307
+
308
+ <!-- {% raw %} -->
309
+ ```liquid
310
+ {% cloudinary logo /assets/logos/cloudinary.png alt="Logo de Cloudinary" %}
311
+ {% cloudinary cloudinary-pricing.png alt="Les tarifs de Cloudinary" caption="Les tarifs de Cloudinary, dont l'offre gratuite déjà généreuse" %}
312
+ ```
313
+ <!-- {% endraw %} -->
314
+
315
+ The only difference is that I explicitly use the `logo` preset for the logo. The other image uses the `default` preset.
316
+
317
+ Here is the necessary configuration for this:
318
+
319
+ ```yaml
320
+ cloudinary:
321
+ cloud_name: …
322
+ verbose: false
323
+ presets:
324
+ default:
325
+ min_width: 320
326
+ max_width: 1600
327
+ fallback_max_width: 800
328
+ steps: 5
329
+ sizes: '(min-width: 50rem) 50rem, 90vw'
330
+ figure: always
331
+ logo:
332
+ min_width: 80
333
+ max_width: 400
334
+ fallback_max_width: 200
335
+ steps: 3
336
+ sizes: '(min-width: 50rem) 13rem, (min-width: 40rem) 25vw, 45vw'
337
+ figure: never
338
+ attributes:
339
+ class: logo
340
+ ```
341
+
342
+ It generates these HTML fragments (pretty printed here), for the logo:
343
+
344
+ ```html
345
+ <img
346
+ src="https://res.cloudinary.com/nho/image/fetch/c_limit,w_200,q_auto,f_auto/https://nicolas-hoizey.com/assets/logos/cloudinary.png"
347
+ srcset="
348
+ https://res.cloudinary.com/nho/image/fetch/c_limit,w_80,q_auto,f_auto/https://nicolas-hoizey.com/assets/logos/cloudinary.png 80w,
349
+ https://res.cloudinary.com/nho/image/fetch/c_limit,w_240,q_auto,f_auto/https://nicolas-hoizey.com/assets/logos/cloudinary.png 240w,
350
+ https://res.cloudinary.com/nho/image/fetch/c_limit,w_400,q_auto,f_auto/https://nicolas-hoizey.com/assets/logos/cloudinary.png 400w"
351
+ sizes="
352
+ (min-width: 50rem) 13rem,
353
+ (min-width: 40rem) 25vw,
354
+ 45vw"
355
+ class="logo"
356
+ alt="Logo de Cloudinary"
357
+ width="480"
358
+ height="350"
359
+ />
360
+ ```
361
+
362
+ And for the screenshot:
363
+
364
+ ```html
365
+ <figure>
366
+ <img
367
+ 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"
368
+ srcset="
369
+ 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,
370
+ 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,
371
+ 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,
372
+ 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"
373
+ sizes="(min-width: 50rem) 50rem, 90vw"
374
+ alt="Les tarifs de Cloudinary"
375
+ width="1208"
376
+ height="561"
377
+ />
378
+ <figcaption>Les tarifs de Cloudinary, dont l'offre gratuite déjà généreuse</figcaption>
379
+ </figure>
380
+ ```
381
+
382
+ 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.
383
+
384
+ And here are the relevant parts of the accompanying CSS (in Sass form):
385
+
386
+ ```sass
387
+ article {
388
+ figure, img {
389
+ margin: 2em auto;
390
+ display: block;
391
+ max-width: 100%;
392
+ height: auto;
393
+ }
394
+ }
395
+
396
+ .logo {
397
+ display: block;
398
+ margin: 1em auto;
399
+ max-width: 50%;
400
+ height: auto;
401
+
402
+ @media (min-width: 40em) {
403
+ max-width: 25%;
404
+ float: right;
405
+ margin: 0 0 1em 1em;
406
+ }
407
+ }
408
+ ```
409
+
410
+ ## Contributing
411
+
412
+ Thanks for your interest in contributing! There are many ways to contribute to this project. [Get started here](https://github.com/nhoizey/jekyll-cloudinary/blob/master/CONTRIBUTING.md).
413
+
414
+ ## Do you use the plugin on a live site?
415
+
416
+ 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,91 @@
1
+ # Releases
2
+
3
+ ## [v1.13.0](https://github.com/nhoizey/jekyll-cloudinary/releases/tag/v1.13.0)
4
+
5
+ Add cross-origin support to prevent opaque responses in Service Workers.
6
+
7
+ See https://cloudfour.com/thinks/when-7-kb-equals-7-mb/
8
+
9
+ ## [v1.12.4](https://github.com/nhoizey/jekyll-cloudinary/releases/tag/v1.12.4)
10
+
11
+ Improving gem summary and description to help people find it. There was no mention of "plugin" in it… 🤔
12
+
13
+ ## [v1.12.3](https://github.com/nhoizey/jekyll-cloudinary/releases/tag/v1.12.3)
14
+
15
+ Strings are now immutable by default, be careful. ([ca68ba7](https://github.com/nhoizey/jekyll-cloudinary/commit/ca68ba7743b69983836b993761d1004494197795))
16
+
17
+ ## [v1.12.2](https://github.com/nhoizey/jekyll-cloudinary/releases/tag/v1.12.2)
18
+
19
+ Match jekyll's coding style thanks to [@DirtyF](https://github.com/DirtyF) with a little help from [Rubocop](http://rubocop.readthedocs.io/).
20
+
21
+ ## [v1.12.1](https://github.com/nhoizey/jekyll-cloudinary/releases/tag/v1.12.1)
22
+
23
+ Break early if there is no `cloud_name` in `_config.yml`.
24
+
25
+ ## [v1.12.0](https://github.com/nhoizey/jekyll-cloudinary/releases/tag/v1.12.0)
26
+
27
+ Thanks to [@suprafly](https://github.com/suprafly)'s [Pull Request](https://github.com/nhoizey/jekyll-cloudinary/pull/29), you can now host your source images on an origin domain different from your website domain.
28
+
29
+ ## [v1.11.0](https://github.com/nhoizey/jekyll-cloudinary/releases/tag/v1.11.0)
30
+
31
+ Thanks to [Pascal Brokmeier](https://github.com/pascalwhoop)'s [Pull Request](https://github.com/nhoizey/jekyll-cloudinary/pull/34), you can now have responsive images HTML and Cloudinary URLs generated only when you build for production.
32
+
33
+ Just make sure to:
34
+
35
+ - set the new option `only_prod` to `true`
36
+ - and set the environment to `production` before building: `JEKYLL_ENV=production bundle exec jekyll build`
37
+
38
+ ## [v1.10.0](https://github.com/nhoizey/jekyll-cloudinary/releases/tag/v1.10.0)
39
+
40
+ Fixes an issue caused by Jekyll 3.8.1 introducing a change to content's path, adding an `/#excerpt` at the end in case of an excerpt.
41
+
42
+ See https://github.com/nhoizey/jekyll-cloudinary/commit/5372e37e4d31bf1934d90665692b9e14f2ac2147
43
+
44
+ ## [v1.9.1](https://github.com/nhoizey/jekyll-cloudinary/releases/tag/v1.9.1)
45
+
46
+ Better warning message when the local source image is missing.
47
+
48
+ ## [v1.9.0](https://github.com/nhoizey/jekyll-cloudinary/releases/tag/v1.9.0)
49
+
50
+ Get the dimensions of the picture from the source path instead of the destination one ([#19](https://github.com/nhoizey/jekyll-cloudinary/issues/19))
51
+
52
+ ## [v1.8.1](https://github.com/nhoizey/jekyll-cloudinary/releases/tag/v1.8.1)
53
+
54
+ Fixes an issue with local images.
55
+
56
+ ## v1.8.0
57
+
58
+ Image size detection now uses FastImage instead of RMagick to remove imagemagick dependency, thanks to [@aarongustafson](https://github.com/aarongustafson) ([#25](https://github.com/nhoizey/jekyll-cloudinary/issues/25))
59
+
60
+ ## v1.7.0
61
+
62
+ It is now possible to use all effects and transformations from the Cloudinary API, thanks to [@aarongustafson](https://github.com/aarongustafson) ([#24](https://github.com/nhoizey/jekyll-cloudinary/issues/24))
63
+
64
+ ## v1.4.0
65
+
66
+ Now supports sites with baseurl ([#10](https://github.com/nhoizey/jekyll-cloudinary/issues/10))
67
+
68
+ ## v1.3.1
69
+
70
+ Restores natural width if some computed ones are missing.
71
+
72
+ ## v1.3.0
73
+
74
+ Restores `width` and `height` attributes.
75
+
76
+ ## v1.2.17
77
+
78
+ Fixes a little typo with huge impact…
79
+
80
+ ## v1.2.16
81
+
82
+ Code improvements thanks to Rubocop, initialized by [@DirtyF](https://github.com/DirtyF)
83
+
84
+ ## v1.2.15
85
+
86
+ Fixed bugs:
87
+ - Don’t add `<img>` `height` & `width` attributes ([#7](https://github.com/nhoizey/jekyll-cloudinary/issues/7))
88
+ - Dont’t wrap `alt` text in `<p>` ([#8](https://github.com/nhoizey/jekyll-cloudinary/issues/8))
89
+ - `require 'rmagick'` tripped me up ([#11](https://github.com/nhoizey/jekyll-cloudinary/issues/11))
90
+
91
+ Thanks [@eeeps](https://github.com/eeeps) for catching these issues!
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ task :default => :spec
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "jekyll/cloudinary"
@@ -0,0 +1,320 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jekyll
4
+ module Cloudinary
5
+
6
+ class CloudinaryTag < Liquid::Tag
7
+ require "fastimage"
8
+
9
+ def initialize(tag_name, markup, tokens)
10
+ @markup = markup
11
+ super
12
+ end
13
+
14
+ def render(context)
15
+ # Default settings
16
+ settings_defaults = {
17
+ "cloud_name" => "",
18
+ "only_prod" => false,
19
+ "verbose" => false,
20
+ }
21
+ preset_defaults = {
22
+ "min_width" => 320,
23
+ "max_width" => 1200,
24
+ "fallback_max_width" => 1200,
25
+ "steps" => 5,
26
+ "sizes" => "100vw",
27
+ "figure" => "auto",
28
+ "attributes" => {},
29
+ "width_height" => true,
30
+ # Cloudinary transformations
31
+ "height" => false,
32
+ "crop" => "limit",
33
+ "aspect_ratio" => false,
34
+ "gravity" => false,
35
+ "zoom" => false,
36
+ "x" => false,
37
+ "y" => false,
38
+ "format" => false,
39
+ "fetch_format" => "auto",
40
+ "quality" => "auto",
41
+ "radius" => false,
42
+ "angle" => false,
43
+ "effect" => false,
44
+ "opacity" => false,
45
+ "border" => false,
46
+ "background" => false,
47
+ "overlay" => false,
48
+ "underlay" => false,
49
+ "default_image" => false,
50
+ "delay" => false,
51
+ "color" => false,
52
+ "color_space" => false,
53
+ "dpr" => "auto",
54
+ "page" => false,
55
+ "density" => false,
56
+ "flags" => false,
57
+ "transformation" => false,
58
+ }
59
+
60
+ # TODO: Add validation for this parameters
61
+ transformation_options = {
62
+ "height" => "h",
63
+ "crop" => "c", # can include add-on: imagga_scale
64
+ "aspect_ratio" => "ar",
65
+ "gravity" => "g",
66
+ "zoom" => "z",
67
+ "x" => "x",
68
+ "y" => "y",
69
+ "fetch_format" => "f",
70
+ "quality" => "q", # can include add-on: jpegmini
71
+ "radius" => "r",
72
+ "angle" => "a",
73
+ "effect" => "e", # can include add-on: viesus_correct
74
+ "opacity" => "o",
75
+ "border" => "bo",
76
+ "background" => "b",
77
+ "overlay" => "l",
78
+ "underlay" => "u",
79
+ "default_image" => "d",
80
+ "delay" => "dl",
81
+ "color" => "co",
82
+ "color_space" => "cs",
83
+ "dpr" => "dpr",
84
+ "page" => "pg",
85
+ "density" => "dn",
86
+ "flags" => "fl",
87
+ "transformation" => "t",
88
+ }
89
+
90
+ # Settings
91
+ site = context.registers[:site]
92
+ site_url = site.config["url"] || ""
93
+ site_baseurl = site.config["baseurl"] || ""
94
+ if site.config["cloudinary"].nil?
95
+ Jekyll.logger.abort_with("[Cloudinary]", "You must set your cloud_name in _config.yml")
96
+ end
97
+ settings = settings_defaults.merge(site.config["cloudinary"])
98
+ if settings["cloud_name"] == ""
99
+ Jekyll.logger.abort_with("[Cloudinary]", "You must set your cloud_name in _config.yml")
100
+ end
101
+ url = settings["origin_url"] || (site_url + site_baseurl)
102
+
103
+ # Get Markdown converter
104
+ markdown_converter = site.find_converter_instance(::Jekyll::Converters::Markdown)
105
+
106
+ preset_user_defaults = {}
107
+ if settings["presets"]
108
+ if settings["presets"]["default"]
109
+ preset_user_defaults = settings["presets"]["default"]
110
+ end
111
+ end
112
+
113
+ preset = preset_defaults.merge(preset_user_defaults)
114
+
115
+ # Render any liquid variables in tag arguments and unescape template code
116
+ rendered_markup = Liquid::Template
117
+ .parse(@markup)
118
+ .render(context)
119
+ .gsub(%r!\\\{\\\{|\\\{\\%!, '\{\{' => "{{", '\{\%' => "{%")
120
+
121
+ # Extract tag segments
122
+ markup =
123
+ %r!^(?:(?<preset>[^\s.:\/]+)\s+)?(?<image_src>[^\s]+\.[a-zA-Z0-9]{3,4})\s*(?<html_attr>[\s\S]+)?$!
124
+ .match(rendered_markup)
125
+
126
+ unless markup
127
+ Jekyll.logger.abort_with("[Cloudinary]", "Can't read this tag: #{@markup}")
128
+ end
129
+
130
+ # Dynamic image type
131
+ type = "upload"
132
+ # TODO: URL2PNG requires signed URLs... need to investigate more
133
+ # if /^url2png\:/.match(image_src)
134
+ # type = "url2png"
135
+ # image_src.gsub! "url2png:", ""
136
+ # end
137
+ # More TODO: GK changed from fetch
138
+
139
+ image_src = markup[:image_src]
140
+
141
+ if markup[:preset]
142
+ if settings["presets"][markup[:preset]]
143
+ preset = preset.merge(settings["presets"][markup[:preset]])
144
+ elsif settings["verbose"]
145
+ Jekyll.logger.warn(
146
+ "[Cloudinary]",
147
+ "'#{markup[:preset]}' preset for the Cloudinary plugin doesn't exist, \
148
+ using the default one"
149
+ )
150
+ end
151
+ end
152
+
153
+ attributes = preset["attributes"]
154
+
155
+ # Deep copy preset for single instance manipulation
156
+ instance = Marshal.load(Marshal.dump(preset))
157
+
158
+ # Process attributes
159
+ html_attr = if markup[:html_attr]
160
+ Hash[ *markup[:html_attr].scan(%r!(?<attr>[^\s="]+)(?:="(?<value>[^"]+)")?\s?!).flatten ]
161
+ else
162
+ {}
163
+ end
164
+
165
+ if instance["attr"]
166
+ html_attr = instance.delete("attr").merge(html_attr)
167
+ end
168
+
169
+ # Classes from the tag should complete, not replace, the ones from the preset
170
+ if html_attr["class"] && attributes["class"]
171
+ html_attr["class"] << " #{attributes["class"]}"
172
+ end
173
+ html_attr = attributes.merge(html_attr)
174
+
175
+ # SPECIAL
176
+
177
+ # Deal with "special transformation"
178
+ if html_attr["transform"]
179
+ trnsfm = html_attr["transform"]
180
+ Jekyll.logger.warn("There is a transformatio @" + image_src + " ->" + trnsfm)
181
+ html_attr.delete("transform")
182
+ end
183
+
184
+ # Deal with the "caption" attribute as a true <figcaption>
185
+ if html_attr["caption"]
186
+ caption = markdown_converter.convert(html_attr["caption"])
187
+ html_attr.delete("caption")
188
+ end
189
+
190
+ # alt and title attributes should go only to the <img> even when there is a caption
191
+ img_attr = "".dup
192
+ if html_attr["alt"]
193
+ img_attr << " alt=\"#{html_attr["alt"]}\""
194
+ html_attr.delete("alt")
195
+ end
196
+ if html_attr["title"]
197
+ img_attr << " title=\"#{html_attr["title"]}\""
198
+ html_attr.delete("title")
199
+ end
200
+ if html_attr["loading"]
201
+ img_attr << " loading=\"#{html_attr["loading"]}\""
202
+ html_attr.delete("loading")
203
+ end
204
+
205
+ attr_string = html_attr.map { |a, v| "#{a}=\"#{v}\"" }.join(" ")
206
+
207
+ # Figure out the Cloudinary transformations
208
+ transformations = []
209
+ transformations_string = ""
210
+ transformation_options.each do |key, shortcode|
211
+ if preset[key]
212
+ transformations << "#{shortcode}_#{preset[key]}"
213
+ end
214
+ end
215
+ unless transformations.empty?
216
+ transformations_string = transformations.compact.reject(&:empty?).join(",") + ","
217
+ end
218
+
219
+ # Build source image URL
220
+ is_image_remote = true #%r!^https?!.match(image_src)
221
+ if is_image_remote
222
+ # It's remote
223
+ image_dest_path = image_src
224
+ #image_dest_url = image_src
225
+ if trnsfm.nil?
226
+ image_dest_url = "https://res.cloudinary.com/#{settings["cloud_name"]}/image/#{type}/q_auto:best/#{image_src}"
227
+ else
228
+ image_dest_url = "https://res.cloudinary.com/#{settings["cloud_name"]}/image/#{type}/#{trnsfm}/#{image_src}"
229
+ end
230
+
231
+
232
+ if ENV["JEKYLL_ENV"] != "production"
233
+ natural_width, natural_height = nil
234
+ else
235
+ natural_width, natural_height = FastImage.size(image_dest_url)
236
+ end
237
+ if natural_width.nil?
238
+ if ENV["JEKYLL_ENV"] == "production"
239
+ Jekyll.logger.warn("remote url doesn't exists " + image_dest_url)
240
+ end
241
+ return "<img src=\"#{image_dest_url}\" />"
242
+ end
243
+ width_height = "width=\"#{natural_width}\" height=\"#{natural_height}\""
244
+ if trnsfm.nil?
245
+ fallback_url = "https://res.cloudinary.com/#{settings["cloud_name"]}/image/#{type}/#{transformations_string}w_#{preset["fallback_max_width"]}/#{image_src}"
246
+ else
247
+ fallback_url = "https://res.cloudinary.com/#{settings["cloud_name"]}/image/#{type}/#{trnsfm}/#{image_src}"
248
+ end
249
+ end
250
+
251
+ ## Don't generate responsive image HTML and Cloudinary URLs for local development
252
+ #if settings["only_prod"] && ENV["JEKYLL_ENV"] != "production"
253
+ # return "<img src=\"#{image_dest_url}\" #{attr_string} #{img_attr} #{width_height} crossorigin=\"anonymous\" />"
254
+ #end
255
+
256
+ srcset = []
257
+ steps = preset["steps"].to_i
258
+ min_width = preset["min_width"].to_i
259
+ max_width = preset["max_width"].to_i
260
+ step_width = (max_width - min_width) / (steps - 1)
261
+ sizes = preset["sizes"]
262
+
263
+ if natural_width < min_width
264
+ if settings["verbose"]
265
+ Jekyll.logger.warn(
266
+ "[Cloudinary]",
267
+ "Width of source image '#{File.basename(image_src)}' (#{natural_width}px) \
268
+ in #{context["page"]["path"]} not enough for ANY srcset version"
269
+ )
270
+ end
271
+ if trnsfm.nil?
272
+ srcset << "https://res.cloudinary.com/#{settings["cloud_name"]}/image/#{type}/#{transformations_string}w_#{natural_width}/#{image_src} #{natural_width}w"
273
+ else
274
+ srcset << "https://res.cloudinary.com/#{settings["cloud_name"]}/image/#{type}/#{trnsfm}/#{image_src} #{natural_width}w"
275
+ end
276
+ else
277
+ missed_sizes = []
278
+ (1..steps).each do |factor|
279
+ width = min_width + (factor - 1) * step_width
280
+ if width <= natural_width
281
+ if trnsfm.nil?
282
+ srcset << "https://res.cloudinary.com/#{settings["cloud_name"]}/image/#{type}/#{transformations_string}w_#{width}/#{image_src} #{width}w"
283
+ else
284
+ srcset << "https://res.cloudinary.com/#{settings["cloud_name"]}/image/#{type}/#{trnsfm}/#{image_src} #{width}w"
285
+ end
286
+ else
287
+ missed_sizes.push(width)
288
+ end
289
+ end
290
+ unless missed_sizes.empty?
291
+ if trnsfm.nil?
292
+ srcset << "https://res.cloudinary.com/#{settings["cloud_name"]}/image/#{type}/#{transformations_string}w_#{natural_width}/#{image_src} #{natural_width}w"
293
+ else
294
+ srcset << "https://res.cloudinary.com/#{settings["cloud_name"]}/image/#{type}/#{trnsfm}/#{image_src} #{natural_width}w"
295
+ end
296
+ if settings["verbose"]
297
+ Jekyll.logger.warn(
298
+ "[Cloudinary]",
299
+ "Width of source image '#{File.basename(image_src)}' (#{natural_width}px) \
300
+ in #{context["page"]["path"]} not enough for #{missed_sizes.join("px, ")}px \
301
+ version#{missed_sizes.length > 1 ? "s" : ""}"
302
+ )
303
+ end
304
+ end
305
+ end
306
+ srcset_string = srcset.join(",\n")
307
+
308
+ # preset['figure'] can be 'never', 'auto' or 'always'
309
+ if (caption || preset["figure"] == "always") && preset["figure"] != "never"
310
+ "\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"
311
+ else
312
+ "<img src=\"#{fallback_url}\" srcset=\"#{srcset_string}\" sizes=\"#{sizes}\" #{attr_string} #{img_attr} #{width_height} crossorigin=\"anonymous\" />"
313
+ end
314
+ end
315
+ end
316
+
317
+ end
318
+ end
319
+
320
+ Liquid::Template.register_tag("cloudinary", Jekyll::Cloudinary::CloudinaryTag)
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jekyll
4
+ module Cloudinary
5
+ VERSION = "1.14.3"
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jekyll-plugin-cloudinary
3
+ version: !ruby/object:Gem::Version
4
+ version: '1.2'
5
+ platform: ruby
6
+ authors:
7
+ - "@glueckkanja"
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-09-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: fastimage
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: jekyll
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '3.6'
34
+ - - "<"
35
+ - !ruby/object:Gem::Version
36
+ version: '5'
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: '3.6'
44
+ - - "<"
45
+ - !ruby/object:Gem::Version
46
+ version: '5'
47
+ - !ruby/object:Gem::Dependency
48
+ name: bundler
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '1.16'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '1.16'
61
+ - !ruby/object:Gem::Dependency
62
+ name: rake
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '12.0'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '12.0'
75
+ - !ruby/object:Gem::Dependency
76
+ name: rubocop
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: 0.74.0
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: 0.74.0
89
+ description:
90
+ email:
91
+ - info@glueckkanja.com
92
+ executables: []
93
+ extensions: []
94
+ extra_rdoc_files: []
95
+ files:
96
+ - Gemfile
97
+ - LICENSE
98
+ - README.md
99
+ - RELEASES.md
100
+ - Rakefile
101
+ - lib/jekyll-plugin-cloudinary.rb
102
+ - lib/jekyll/cloudinary.rb
103
+ - lib/jekyll/cloudinary/version.rb
104
+ homepage: https://glueckkanja.com
105
+ licenses:
106
+ - MIT
107
+ metadata: {}
108
+ post_install_message:
109
+ rdoc_options: []
110
+ require_paths:
111
+ - lib
112
+ required_ruby_version: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ required_rubygems_version: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ requirements: []
123
+ rubygems_version: 3.0.3
124
+ signing_key:
125
+ specification_version: 4
126
+ summary: GK Jekyll Cloudinary Tag (derived from nhoizey)
127
+ test_files: []