cloudinary 1.9.1 → 1.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -5
- data/.gitignore +1 -0
- data/CHANGELOG.md +32 -0
- data/cloudinary.gemspec +2 -1
- data/lib/cloudinary/api.rb +28 -13
- data/lib/cloudinary/cache.rb +38 -0
- data/lib/cloudinary/cache/breakpoints_cache.rb +31 -0
- data/lib/cloudinary/cache/key_value_cache_adapter.rb +25 -0
- data/lib/cloudinary/cache/rails_cache_adapter.rb +34 -0
- data/lib/cloudinary/cache/storage/rails_cache_storage.rb +5 -0
- data/lib/cloudinary/helper.rb +47 -4
- data/lib/cloudinary/responsive.rb +111 -0
- data/lib/cloudinary/uploader.rb +22 -4
- data/lib/cloudinary/utils.rb +122 -5
- data/lib/cloudinary/version.rb +1 -1
- data/spec/access_control_spec.rb +3 -0
- data/spec/api_spec.rb +19 -13
- data/spec/auth_token_spec.rb +8 -10
- data/spec/cache_spec.rb +109 -0
- data/spec/cloudinary_helper_spec.rb +147 -12
- data/spec/image_spec.rb +107 -0
- data/spec/spec_helper.rb +38 -17
- data/spec/uploader_spec.rb +23 -8
- data/spec/utils_spec.rb +46 -3
- data/spec/video_tag_spec.rb +7 -5
- data/spec/video_url_spec.rb +4 -2
- data/tools/update_version +202 -0
- metadata +83 -30
checksums.yaml
CHANGED
@@ -1,7 +1,17 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
2
|
+
!binary "U0hBMjU2":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
ODI0YWQ0Mjg5NGRkYjkxYjRkZTNkOTZhMTgzNzA5YmMyY2E2ZGVhMmZmN2Fj
|
5
|
+
NDRkYTNkNjI3ZDM5YjEwZDFkYg==
|
6
|
+
data.tar.gz: !binary |-
|
7
|
+
MGMyNDU5NTIxY2Q3M2UyMWM2ZjFmYWVkZjUwNGZmYWFmNmE0MWY0MWY2MTgz
|
8
|
+
ZTgyNzIyMjA0YjU1NjZhMWM3Yg==
|
5
9
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
|
10
|
+
metadata.gz: !binary |-
|
11
|
+
YWViMTg1MzFiOWI1ODkzYWYzNWQxMzUyZWUyMTUyNWIwODRiMDI5NWFjNmYy
|
12
|
+
YjVlNjc3NjUzN2E3ODgzNWRiNTEwZDVlZWFlYWQ2ODg5NTc3ZTcxNzIyOThl
|
13
|
+
YWY3MjlkYzkwNjk0MDY1YjI3ODJjM2RjY2FiMWYyOTMyODU4NzU=
|
14
|
+
data.tar.gz: !binary |-
|
15
|
+
MTQzOWE0OGZjZTg3MmI1YTJiOWQ2NzI1MmE4ZDQ2YWQxN2NhMThmMjMzNjJk
|
16
|
+
ZjUwZjNmYTc4MDA4ODBlM2Y0Y2FjOWNiOTc2NjI1YTg1M2EyOTg1MTNkMjg1
|
17
|
+
NTE2ZmQ2ZGEyMjk2YTE1MDM0NWM3ZGIyZDcxZDFjM2ZlNDJhNTk=
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,36 @@
|
|
1
1
|
|
2
|
+
1.10.0 / 2018-11-08
|
3
|
+
===================
|
4
|
+
|
5
|
+
New functionality and features
|
6
|
+
------------------------------
|
7
|
+
|
8
|
+
* Add the `custom_function` transformation parameter
|
9
|
+
* Add Picture and source tags
|
10
|
+
* Add `srcset` attribute to image tag
|
11
|
+
* Add support for overlays of type fetch
|
12
|
+
* Add breakpoints cache
|
13
|
+
|
14
|
+
Other Changes
|
15
|
+
-------------
|
16
|
+
|
17
|
+
* Add `update_version` script
|
18
|
+
* Fix transformations test
|
19
|
+
* Replace ruby list notation to support older ruby versions
|
20
|
+
* Refactor tests
|
21
|
+
* Replace REXML with Nokogiri
|
22
|
+
* Un-ignore the lib folder
|
23
|
+
* Ignore empty transformations when processing an array of transformations
|
24
|
+
* Restore configuration after each test
|
25
|
+
* Limit Rack version to fix compatibility issues with ruby 1.9.3
|
26
|
+
* Fix context escaping in call_context_api
|
27
|
+
* Fix uploadLarge to use X-Unique-Upload-Id
|
28
|
+
* Add test cases of OCR for upload and URL generation
|
29
|
+
* Add test case of conditional tags
|
30
|
+
* Fix expected result in cname with cdn_subdomain test
|
31
|
+
* Fix raw conversion test
|
32
|
+
* Raise exception when api-secret is missing in signed-url flow
|
33
|
+
|
2
34
|
1.9.1 / 2018-03-06
|
3
35
|
==================
|
4
36
|
|
data/cloudinary.gemspec
CHANGED
@@ -33,10 +33,11 @@ Gem::Specification.new do |s|
|
|
33
33
|
elsif RUBY_VERSION >= "1.9"
|
34
34
|
s.add_dependency "rest-client", '< 2.0'
|
35
35
|
s.add_dependency 'json', '~> 1.8'
|
36
|
-
s.add_development_dependency "actionpack", '<
|
36
|
+
s.add_development_dependency "actionpack", '<5.0'
|
37
37
|
s.add_development_dependency "simplecov"
|
38
38
|
s.add_development_dependency "nokogiri", "<1.7.0"
|
39
39
|
s.add_development_dependency "rubyzip", '<1.2.1'
|
40
|
+
s.add_development_dependency "rack", '<1.6.5'
|
40
41
|
else
|
41
42
|
s.add_dependency "i18n", "<0.7.0"
|
42
43
|
s.add_dependency "rest-client", "<=1.6.8"
|
data/lib/cloudinary/api.rb
CHANGED
@@ -19,9 +19,9 @@ class Cloudinary::Api
|
|
19
19
|
# This sets the instantiated self as the response Hash
|
20
20
|
update Cloudinary::Api.parse_json_response response
|
21
21
|
|
22
|
-
@rate_limit_allowed = response.headers[:x_featureratelimit_limit].to_i
|
23
|
-
@rate_limit_reset_at = Time.parse(response.headers[:x_featureratelimit_reset])
|
24
|
-
@rate_limit_remaining = response.headers[:x_featureratelimit_remaining].to_i
|
22
|
+
@rate_limit_allowed = response.headers[:x_featureratelimit_limit].to_i if response.headers[:x_featureratelimit_limit]
|
23
|
+
@rate_limit_reset_at = Time.parse(response.headers[:x_featureratelimit_reset]) if response.headers[:x_featureratelimit_reset]
|
24
|
+
@rate_limit_remaining = response.headers[:x_featureratelimit_remaining].to_i if response.headers[:x_featureratelimit_remaining]
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
@@ -311,6 +311,18 @@ class Cloudinary::Api
|
|
311
311
|
update_resources_access_mode(access_mode, :public_ids, public_ids, options)
|
312
312
|
end
|
313
313
|
|
314
|
+
def self.get_breakpoints(public_id, options)
|
315
|
+
local_options = options.clone
|
316
|
+
base_transformation = Cloudinary::Utils.generate_transformation_string(local_options)
|
317
|
+
srcset = local_options[:srcset]
|
318
|
+
breakpoints = [:min_width, :max_width, :bytes_step, :max_images].map {|k| srcset[k]}.join('_')
|
319
|
+
|
320
|
+
|
321
|
+
local_options[:transformation] = [base_transformation, width: "auto:breakpoints_#{breakpoints}:json"]
|
322
|
+
json_url = Cloudinary::Utils.cloudinary_url public_id, local_options
|
323
|
+
call_json_api('GET', json_url, {}, 60, {})
|
324
|
+
end
|
325
|
+
|
314
326
|
protected
|
315
327
|
|
316
328
|
def self.call_api(method, uri, params, options)
|
@@ -330,24 +342,27 @@ class Cloudinary::Api
|
|
330
342
|
else
|
331
343
|
payload = params.reject { |k, v| v.nil? || v=="" }
|
332
344
|
end
|
345
|
+
call_json_api(method, api_url, payload, timeout, headers)
|
346
|
+
end
|
347
|
+
|
348
|
+
def self.call_json_api(method, api_url, payload, timeout, headers)
|
333
349
|
RestClient::Request.execute(:method => method, :url => api_url, :payload => payload, :timeout => timeout, :headers => headers) do
|
334
350
|
|response, request, tmpresult|
|
335
351
|
return Response.new(response) if response.code == 200
|
336
352
|
exception_class = case response.code
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
353
|
+
when 400 then BadRequest
|
354
|
+
when 401 then AuthorizationRequired
|
355
|
+
when 403 then NotAllowed
|
356
|
+
when 404 then NotFound
|
357
|
+
when 409 then AlreadyExists
|
358
|
+
when 420 then RateLimited
|
359
|
+
when 500 then GeneralError
|
360
|
+
else raise GeneralError.new("Server returned unexpected status code - #{response.code} - #{response.body}")
|
361
|
+
end
|
346
362
|
json = parse_json_response(response)
|
347
363
|
raise exception_class.new(json["error"]["message"])
|
348
364
|
end
|
349
365
|
end
|
350
|
-
|
351
366
|
def self.parse_json_response(response)
|
352
367
|
return Cloudinary::Utils.json_decode(response.body)
|
353
368
|
rescue => e
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'digest'
|
2
|
+
|
3
|
+
module Cloudinary
|
4
|
+
module Cache
|
5
|
+
|
6
|
+
class << self
|
7
|
+
attr_accessor :storage
|
8
|
+
|
9
|
+
def get(public_id, options)
|
10
|
+
if block_given?
|
11
|
+
storage.read(generate_cache_key(public_id, options)) {yield}
|
12
|
+
else
|
13
|
+
storage.read(generate_cache_key(public_id, options))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def set(public_id, options, value)
|
18
|
+
storage.write(generate_cache_key(public_id, options), value)
|
19
|
+
end
|
20
|
+
|
21
|
+
alias_method :fetch, :get
|
22
|
+
|
23
|
+
def flush_all
|
24
|
+
storage.clear
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def generate_cache_key(public_id, options)
|
30
|
+
type = options[:type] || "upload"
|
31
|
+
resource_type = options[:resource_type] || "image"
|
32
|
+
transformation = Cloudinary::Utils.generate_transformation_string options.clone
|
33
|
+
format = options[:format]
|
34
|
+
Digest::SHA1.hexdigest [public_id, type, resource_type, transformation, format].reject(&:blank?).join('/')
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Cloudinary::Cache
|
2
|
+
class BreakpointsCache
|
3
|
+
attr_accessor :adapter
|
4
|
+
|
5
|
+
def set(public_id, options, value)
|
6
|
+
upload_type, resource_type, transformation, format = options_to_parameters(options)
|
7
|
+
@adapter.set(public_id, upload_type, resource_type, transformation, format, value)
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
def fetch(public_id, options)
|
12
|
+
upload_type, resource_type, transformation, format = options_to_parameters(options)
|
13
|
+
@adapter.set(public_id, upload_type, resource_type, transformation, format, &Proc.new)
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
def get(public_id, options)
|
18
|
+
upload_type, resource_type, transformation, format = options_to_parameters(options)
|
19
|
+
@adapter.get(public_id, upload_type, resource_type, transformation, format)
|
20
|
+
end
|
21
|
+
|
22
|
+
def options_to_parameters(options)
|
23
|
+
options = Cloudinary::Utils.symbolize_keys options
|
24
|
+
transformation = Cloudinary::Utils.generate_transformation_string(options)
|
25
|
+
upload_type = options[:type] || 'upload'
|
26
|
+
resource_type = options[:resource_type] || 'image'
|
27
|
+
format = options[:format] || ""
|
28
|
+
[upload_type, resource_type, transformation, format]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'digest'
|
2
|
+
module Cloudinary::Cache
|
3
|
+
class KeyValueCacheAdapter < CacheAdapter
|
4
|
+
def get(public_id, type, resource_type, transformation, format)
|
5
|
+
key = generate_cache_key(public_id, type, resource_type, transformation, format)
|
6
|
+
@storage.get(key)
|
7
|
+
end
|
8
|
+
|
9
|
+
def set(public_id, type, resource_type, transformation, format, value)
|
10
|
+
key = generate_cache_key(public_id, type, resource_type, transformation, format)
|
11
|
+
@storage.set(key, value)
|
12
|
+
end
|
13
|
+
|
14
|
+
def flush_all()
|
15
|
+
@storage.flush_all()
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def generate_cache_key(public_id, type, resource_type, transformation, format)
|
21
|
+
Digest::SHA1.hexdigest [public_id, type, resource_type, transformation, format].reject(&:blank?)
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Cloudinary::Cache
|
2
|
+
class RailsCacheAdapter < CacheAdapter
|
3
|
+
|
4
|
+
def flush_all
|
5
|
+
end
|
6
|
+
|
7
|
+
def get(public_id, type, resource_type, transformation, format)
|
8
|
+
key = generate_cache_key(public_id, type, resource_type, transformation, format)
|
9
|
+
Rails.cache.read(key)
|
10
|
+
end
|
11
|
+
|
12
|
+
def init
|
13
|
+
unless defined? Rails
|
14
|
+
raise CloudinaryException.new "Rails is required in order to use RailsCacheAdapter"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def set(public_id, type, resource_type, transformation, format, value)
|
19
|
+
key = generate_cache_key(public_id, type, resource_type, transformation, format)
|
20
|
+
Rails.cache.write(key, value)
|
21
|
+
end
|
22
|
+
|
23
|
+
def fetch(public_id, type, resource_type, transformation, format)
|
24
|
+
key = generate_cache_key(public_id, type, resource_type, transformation, format)
|
25
|
+
Rails.cache.fetch(key, &Proc.new)
|
26
|
+
end
|
27
|
+
private
|
28
|
+
|
29
|
+
def generate_cache_key(public_id, type, resource_type, transformation, format)
|
30
|
+
Digest::SHA1.hexdigest [public_id, type, resource_type, transformation, format].reject(&:blank?)
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
data/lib/cloudinary/helper.rb
CHANGED
@@ -1,7 +1,11 @@
|
|
1
1
|
require 'digest/md5'
|
2
2
|
require 'cloudinary/video_helper'
|
3
|
+
require 'cloudinary/responsive'
|
3
4
|
|
4
5
|
module CloudinaryHelper
|
6
|
+
include ActionView::Helpers::CaptureHelper
|
7
|
+
include Responsive
|
8
|
+
|
5
9
|
CL_BLANK = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
6
10
|
|
7
11
|
# Stand-in for Rails image_tag helper that accepts various options for transformations.
|
@@ -37,13 +41,45 @@ module CloudinaryHelper
|
|
37
41
|
|
38
42
|
end
|
39
43
|
|
44
|
+
|
45
|
+
def cl_picture_tag(source, options = {}, sources =[])
|
46
|
+
|
47
|
+
options = options.clone
|
48
|
+
content_tag 'picture' do
|
49
|
+
sources.map do |source_def|
|
50
|
+
source_options = options.clone
|
51
|
+
source_options = Cloudinary::Utils.chain_transformation(source_options, source_def[:transformation])
|
52
|
+
source_options[:media] = source_def
|
53
|
+
cl_source_tag(source, source_options)
|
54
|
+
end.push(cl_image_tag(source, options))
|
55
|
+
.join('')
|
56
|
+
.html_safe
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def cl_source_tag(source, options)
|
61
|
+
srcset_param = options.fetch(:srcset, {}).merge(Cloudinary.config.srcset || {})
|
62
|
+
attributes = options.fetch(:attributes, {}).clone
|
63
|
+
responsive_attributes = generate_image_responsive_attributes(source, attributes, srcset_param, options)
|
64
|
+
attributes = attributes.merge(responsive_attributes)
|
65
|
+
unless attributes.has_key? :srcset
|
66
|
+
attributes[:srcset] = Cloudinary::Utils.cloudinary_url(source, options)
|
67
|
+
end
|
68
|
+
media_attr = generate_media_attribute(options[:media])
|
69
|
+
attributes[:media] = media_attr unless media_attr.empty?
|
70
|
+
tag "source", attributes, true
|
71
|
+
end
|
72
|
+
|
73
|
+
|
40
74
|
def cloudinary_tag(source, options = {})
|
41
75
|
tag_options = options.clone
|
42
76
|
tag_options[:width] = tag_options.delete(:html_width) if tag_options.include?(:html_width)
|
43
77
|
tag_options[:height] = tag_options.delete(:html_height) if tag_options.include?(:html_height)
|
44
78
|
tag_options[:size] = tag_options.delete(:html_size) if tag_options.include?(:html_size)
|
45
79
|
tag_options[:border] = tag_options.delete(:html_border) if tag_options.include?(:html_border)
|
46
|
-
|
80
|
+
srcset_param = Cloudinary::Utils.config_option_consume(tag_options, :srcset, {})
|
81
|
+
src = cloudinary_url_internal(source, tag_options)
|
82
|
+
attributes = tag_options.delete(:attributes) || {}
|
47
83
|
|
48
84
|
responsive_placeholder = Cloudinary::Utils.config_option_consume(tag_options, :responsive_placeholder)
|
49
85
|
client_hints = Cloudinary::Utils.config_option_consume(tag_options, :client_hints)
|
@@ -51,15 +87,21 @@ module CloudinaryHelper
|
|
51
87
|
hidpi = tag_options.delete(:hidpi)
|
52
88
|
responsive = tag_options.delete(:responsive)
|
53
89
|
if !client_hints && (hidpi || responsive)
|
54
|
-
tag_options["data-src"] =
|
55
|
-
|
90
|
+
tag_options["data-src"] = src
|
91
|
+
src = nil
|
56
92
|
extra_class = responsive ? "cld-responsive" : "cld-hidpi"
|
57
93
|
tag_options[:class] = [tag_options[:class], extra_class].compact.join(" ")
|
58
94
|
responsive_placeholder = CL_BLANK if responsive_placeholder == "blank"
|
59
95
|
tag_options[:src] = responsive_placeholder
|
60
96
|
end
|
97
|
+
responsive_attrs = generate_image_responsive_attributes(source, attributes, srcset_param, options)
|
98
|
+
unless responsive_attrs.empty?
|
99
|
+
tag_options.delete(:width)
|
100
|
+
tag_options.delete(:height)
|
101
|
+
tag_options.merge! responsive_attrs
|
102
|
+
end
|
61
103
|
if block_given?
|
62
|
-
yield(
|
104
|
+
yield(src,tag_options)
|
63
105
|
else
|
64
106
|
tag('div', tag_options)
|
65
107
|
end
|
@@ -281,6 +323,7 @@ module CloudinaryHelper
|
|
281
323
|
end
|
282
324
|
|
283
325
|
private
|
326
|
+
|
284
327
|
def cloudinary_url_internal(source, options = {})
|
285
328
|
options[:ssl_detected] = request.ssl? if defined?(request) && request && request.respond_to?(:ssl?)
|
286
329
|
if defined?(CarrierWave::Uploader::Base) && source.is_a?(CarrierWave::Uploader::Base)
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module Responsive
|
2
|
+
# Calculate breakpoints for the given configuration
|
3
|
+
# @private
|
4
|
+
def generate_breakpoints(srcset)
|
5
|
+
return srcset[:breakpoints] if srcset[:breakpoints].is_a? Array
|
6
|
+
min_width, max_width, max_images = [:min_width, :max_width, :max_images].map {|k| srcset[k]}
|
7
|
+
unless [min_width, max_width, max_images].all? {|a| a.is_a? Numeric}
|
8
|
+
throw 'Either (min_width, max_width, max_images) or breakpoints must be provided to the image srcset attribute'
|
9
|
+
end
|
10
|
+
if min_width > max_width
|
11
|
+
throw 'min_width must be less than max_width'
|
12
|
+
end
|
13
|
+
|
14
|
+
if max_images <= 0
|
15
|
+
throw 'max_images must be a positive integer'
|
16
|
+
elsif max_images === 1
|
17
|
+
min_width = max_width
|
18
|
+
end
|
19
|
+
step_size = ((max_width - min_width).to_f / [max_images - 1, 1].max).ceil
|
20
|
+
current = min_width
|
21
|
+
breakpoints = []
|
22
|
+
while current < max_width do
|
23
|
+
breakpoints.push(current)
|
24
|
+
current += step_size
|
25
|
+
end
|
26
|
+
breakpoints.push(max_width)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Generate the srcset and sizes attributes
|
30
|
+
# @private
|
31
|
+
def generate_image_responsive_attributes(public_id, attributes = {}, srcset_data = {}, options = {})
|
32
|
+
# Create both srcset and sizes here to avoid fetching breakpoints twice
|
33
|
+
|
34
|
+
responsive_attributes = {}
|
35
|
+
generate_srcset = !attributes[:srcset]
|
36
|
+
|
37
|
+
if srcset_data.empty?
|
38
|
+
return responsive_attributes
|
39
|
+
elsif srcset_data.is_a? String
|
40
|
+
responsive_attributes[:srcset] = srcset_data
|
41
|
+
return responsive_attributes
|
42
|
+
end
|
43
|
+
|
44
|
+
generate_sizes = !attributes[:sizes] && srcset_data[:sizes]
|
45
|
+
|
46
|
+
if generate_srcset || generate_sizes
|
47
|
+
breakpoints = get_or_generate_breakpoints(public_id, srcset_data, options)
|
48
|
+
|
49
|
+
if generate_srcset
|
50
|
+
transformation = srcset_data[:transformation]
|
51
|
+
srcset_attr = generate_srcset_attribute(public_id, breakpoints, transformation, options)
|
52
|
+
responsive_attributes[:srcset] = srcset_attr unless srcset_attr.empty?
|
53
|
+
end
|
54
|
+
|
55
|
+
if generate_sizes
|
56
|
+
sizes_attr = generate_sizes_attribute(breakpoints)
|
57
|
+
responsive_attributes[:sizes] = sizes_attr unless sizes_attr.empty?
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
responsive_attributes
|
62
|
+
end
|
63
|
+
|
64
|
+
# If cache is enabled, get the breakpoints from the cache. If the values were not found in the cache,
|
65
|
+
# or cache is not enabled, generate the values.
|
66
|
+
# @private
|
67
|
+
def get_or_generate_breakpoints(public_id, srcset, options)
|
68
|
+
if srcset[:use_cache]
|
69
|
+
Cloudinary::Cache.get(public_id, options) || []
|
70
|
+
else
|
71
|
+
generate_breakpoints(srcset)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Generate a resource URL scaled to the given width
|
76
|
+
# @private
|
77
|
+
def generate_scaled_url(public_id, width, transformation={}, options={})
|
78
|
+
config_params = Cloudinary::Utils.extract_config_params(options)
|
79
|
+
transformation ||= options
|
80
|
+
config_params[:raw_transformation] = Cloudinary::Utils.generate_transformation_string(
|
81
|
+
[transformation.clone, {:crop => 'scale', :width => width}].reject(&:blank?))
|
82
|
+
config_params.delete :width
|
83
|
+
config_params.delete :height
|
84
|
+
Cloudinary::Utils.cloudinary_url public_id, config_params
|
85
|
+
end
|
86
|
+
|
87
|
+
# Generate srcset attribute value of the HTML img tag
|
88
|
+
# @private
|
89
|
+
def generate_srcset_attribute(public_id, breakpoints, transformation={}, options={})
|
90
|
+
options = options.clone
|
91
|
+
Cloudinary::Utils.patch_fetch_format(options)
|
92
|
+
breakpoints.map{|width| "#{generate_scaled_url(public_id, width, transformation, options)} #{width}w"}.join(', ').html_safe
|
93
|
+
end
|
94
|
+
|
95
|
+
# Generate media attribute value of the HTML img tag
|
96
|
+
# @private
|
97
|
+
def generate_media_attribute(options)
|
98
|
+
options ||= {}
|
99
|
+
[:min_width, :max_width]
|
100
|
+
.select {|name| options[name]}
|
101
|
+
.map {|name| "(#{name.to_s.tr('_', '-')}: #{options[name]}px)"}
|
102
|
+
.join(' and ').html_safe
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
# Generate the sizes attribute
|
107
|
+
# @private
|
108
|
+
def generate_sizes_attribute(breakpoints)
|
109
|
+
breakpoints.map{|width| "(max-width: #{width}px) #{width}px"}.join(', ')
|
110
|
+
end
|
111
|
+
end
|