jekyll-cloudinary-fork 1.9.1

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
+ 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: []