cloudinary 1.1.7 → 1.2.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8c21572d5ca0363eb07c0a226e92498d90d9f2b9
4
- data.tar.gz: ab8a7a05057dbf409296897576f69745d9516a8a
3
+ metadata.gz: 9b2454e65f38986500bbd665f0b795bc828c778e
4
+ data.tar.gz: ad45733ff5323991533c2c731539b39dfed1156c
5
5
  SHA512:
6
- metadata.gz: d609e1b2f396d259645df469f7ec94769f31bae9e49571b77530aa73521bbece7dcdff545309db03f8486ff4c566a68179b26f3d3473a7db444554fd1cdddcca
7
- data.tar.gz: 3496b66de2e36abdde1e9b28e30c392807f784295ed4de76f4f0e87e5362fb9be2202e625cd6ffe85c6e8b4c8d01a70127c6c29ff5a4c6b278e8c0999be7412c
6
+ metadata.gz: f0896c0b1aadf9c847c2fd057c9ff8f8d268198b342e6287e9edc595a6459247df5bee21040d581d3f603f24e43cad165dca7be34801d87bf3d1420e1e5584b6
7
+ data.tar.gz: c7170f8a53f59af81e4a7e7ff757f002ab095d409c5c81c93310f5b1632e72fe5f0dd3a3bafb1f1e0a6986184e8b6c8443b0d94a82f600f82400fa4c0e46bc60
@@ -1,4 +1,19 @@
1
1
 
2
+ 1.2.0 / 2016-06-22
3
+ ==================
4
+
5
+ New functionality and features
6
+ ------------------------------
7
+
8
+ * New configuration parameter `:client_hints`
9
+ * Enhanced auto `width` values
10
+ * Enhanced `quality` values
11
+
12
+ Other Changes
13
+ -------------
14
+
15
+ * Remove coffee and map files. Fixes #203
16
+
2
17
  1.1.7 / 2016-06-06
3
18
  ==================
4
19
 
data/Rakefile CHANGED
@@ -16,8 +16,7 @@ namespace :cloudinary do
16
16
  task :fetch_assets do
17
17
  index_files = %w[jquery.ui.widget.js jquery.iframe-transport.js jquery.fileupload.js jquery.cloudinary.js]
18
18
  processing_files = %w[canvas-to-blob.min.js load-image.all.min.js jquery.fileupload-process.js jquery.fileupload-image.js jquery.fileupload-validate.js]
19
- other_files = %w[jquery.cloudinary.coffee jquery.cloudinary.js.map]
20
- files = index_files + processing_files + other_files
19
+ files = index_files + processing_files
21
20
 
22
21
  release = JSON(RestClient.get("https://api.github.com/repos/cloudinary/cloudinary_js/releases/latest"))
23
22
 
@@ -46,9 +46,11 @@ module CloudinaryHelper
46
46
  source = cloudinary_url_internal(source, tag_options)
47
47
 
48
48
  responsive_placeholder = Cloudinary::Utils.config_option_consume(tag_options, :responsive_placeholder)
49
+ client_hints = Cloudinary::Utils.config_option_consume(tag_options, :client_hints)
50
+
49
51
  hidpi = tag_options.delete(:hidpi)
50
52
  responsive = tag_options.delete(:responsive)
51
- if hidpi || responsive
53
+ if !client_hints && (hidpi || responsive)
52
54
  tag_options["data-src"] = source
53
55
  source = nil
54
56
  extra_class = responsive ? "cld-responsive" : "cld-hidpi"
@@ -184,6 +186,9 @@ module CloudinaryHelper
184
186
  content_tag("script", "$.cloudinary.config(#{params.to_json});".html_safe, :type=>"text/javascript")
185
187
  end
186
188
 
189
+ def cl_client_hints_meta_tag
190
+ tag "meta", "http-equiv" => "Accept-CH", :content => "DPR, Viewport-Width, Width"
191
+ end
187
192
  def cloudinary_url(source, options = {})
188
193
  cloudinary_url_internal(source, options.clone)
189
194
  end
@@ -51,10 +51,10 @@ class Cloudinary::Utils
51
51
  angle = build_array(options.delete(:angle)).join(".")
52
52
 
53
53
  no_html_sizes = has_layer || angle.present? || crop.to_s == "fit" || crop.to_s == "limit" || crop.to_s == "lfill"
54
- options.delete(:width) if width && (width.to_f < 1 || no_html_sizes || width == "auto" || responsive_width)
54
+ options.delete(:width) if width && (width.to_f < 1 || no_html_sizes || width.to_s.start_with?("auto") || responsive_width)
55
55
  options.delete(:height) if height && (height.to_f < 1 || no_html_sizes || responsive_width)
56
56
 
57
- width=height=nil if crop.nil? && !has_layer && width != "auto" && !allow_implicit_crop_mode
57
+ width=height=nil if crop.nil? && !has_layer && !width.to_s.start_with?("auto") && !allow_implicit_crop_mode
58
58
 
59
59
  background = options.delete(:background)
60
60
  background = background.sub(/^#/, 'rgb:') if background
@@ -156,7 +156,7 @@ class Cloudinary::Utils
156
156
  transformations << generate_transformation_string(responsive_width_transformation.clone, allow_implicit_crop_mode)
157
157
  end
158
158
 
159
- if width.to_s == "auto" || responsive_width
159
+ if width.to_s.start_with?( "auto") || responsive_width
160
160
  options[:responsive] = true
161
161
  end
162
162
  if dpr.to_s == "auto"
@@ -1,4 +1,4 @@
1
1
  # Copyright Cloudinary
2
2
  module Cloudinary
3
- VERSION = "1.1.7"
3
+ VERSION = "1.2.0"
4
4
  end
@@ -11,6 +11,9 @@ end
11
11
  RSpec.describe CloudinaryHelper do
12
12
  let(:helper) { helper_class.new }
13
13
  let(:options) { {} }
14
+ before :each do
15
+ Cloudinary.config({})
16
+ end
14
17
  context "#cl_image_upload_tag" do
15
18
  let(:options) {{:multiple => true}}
16
19
  before do
@@ -70,5 +73,58 @@ RSpec.describe CloudinaryHelper do
70
73
  expect(test_tag['data-src']).to eq( "http://res.cloudinary.com/test/image/upload/dpr_auto/sample.jpg")
71
74
  end
72
75
  end
76
+
77
+ context ":client_hints" do
78
+ shared_examples "client_hints" do
79
+ it "should not use data-src or set responsive class" do
80
+ expect(test_tag.name).to match( 'img')
81
+ expect(test_tag['class']).to be_nil
82
+ expect(test_tag['data-src']).to be_nil
83
+ expect(test_tag['src']).to eq( "http://res.cloudinary.com/test/image/upload/dpr_auto,w_auto/sample.jpg")
84
+ end
85
+ it "should override :responsive" do
86
+ Cloudinary.config.responsive = true
87
+ expect(test_tag.name).to match( 'img')
88
+ expect(test_tag['class']).to be_nil
89
+ expect(test_tag['data-src']).to be_nil
90
+ expect(test_tag['src']).to eq( "http://res.cloudinary.com/test/image/upload/dpr_auto,w_auto/sample.jpg")
91
+ end
92
+ end
93
+ context "as option" do
94
+ let(:options) { {:dpr => :auto, :cloud_name => "test", :width => "auto", :client_hints => true} }
95
+ include_examples "client_hints"
96
+ end
97
+ context "as global configuration" do
98
+ before do
99
+ Cloudinary.config.client_hints = true
100
+ end
101
+ let(:options) { {:dpr => :auto, :cloud_name => "test", :width => "auto"} }
102
+ include_examples "client_hints"
103
+ end
104
+
105
+ context "false" do
106
+ let(:options) { {:width => :auto, :cloud_name => "test", :client_hints => false} }
107
+ it "should use normal responsive behaviour" do
108
+ expect(test_tag.name).to match( 'img')
109
+ expect(test_tag['class']).to eq( 'cld-responsive')
110
+ expect(test_tag['data-src']).to eq( "http://res.cloudinary.com/test/image/upload/w_auto/sample.jpg")
111
+ end
112
+ end
113
+ context "width" do
114
+ let(:options) { {:dpr => :auto, :cloud_name => "test", :width => "auto:breakpoints", :client_hints => true}}
115
+ it "supports auto width" do
116
+ expect(test_tag['src']).to eq( "http://res.cloudinary.com/test/image/upload/dpr_auto,w_auto:breakpoints/sample.jpg")
117
+ end
118
+ end
119
+ end
120
+ end
121
+
122
+ context "#cl_client_hints_meta_tag" do
123
+ it "should create a meta tag" do
124
+ tag = TestTag.new( helper.cl_client_hints_meta_tag)
125
+ expect(tag.name).to match('meta')
126
+ expect(tag['content']).to eq('DPR, Viewport-Width, Width')
127
+ expect(tag['http-equiv']).to eq('Accept-CH')
128
+ end
73
129
  end
74
130
  end
@@ -207,6 +207,18 @@ describe Cloudinary::Utils do
207
207
  .to produce_url("#{upload_path}/c_crop,h_10,w_10/test")
208
208
  .and mutate_options_to({ :width => "10", :height => "10" })
209
209
  end
210
+ it "should support auto width" do
211
+ expect(["test", { :width => "auto:20", :crop => :fill }])
212
+ .to produce_url("#{upload_path}/c_fill,w_auto:20/test")
213
+ expect(["test", { :width => "auto:20:350", :crop => :fill }])
214
+ .to produce_url("#{upload_path}/c_fill,w_auto:20:350/test")
215
+ expect(["test", { :width => "auto:breakpoints", :crop => :fill }])
216
+ .to produce_url("#{upload_path}/c_fill,w_auto:breakpoints/test")
217
+ expect(["test", { :width => "auto:breakpoints_100_1900_20_15", :crop => :fill }])
218
+ .to produce_url("#{upload_path}/c_fill,w_auto:breakpoints_100_1900_20_15/test")
219
+ expect(["test", { :width => "auto:breakpoints:json", :crop => :fill }])
220
+ .to produce_url("#{upload_path}/c_fill,w_auto:breakpoints:json/test")
221
+ end
210
222
  end
211
223
 
212
224
  it "should use x, y, radius, prefix, gravity and quality from options" do
@@ -214,7 +226,24 @@ describe Cloudinary::Utils do
214
226
  .to produce_url("#{upload_path}/g_center,p_a,q_0.4,r_3,x_1,y_2/test")
215
227
  .and empty_options
216
228
  end
229
+ context ":quality" do
230
+ it "support a percent value" do
231
+ expect(["test", { :x => 1, :y => 2, :radius => 3, :gravity => :center, :quality => 80, :prefix => "a" }])
232
+ .to produce_url("#{upload_path}/g_center,p_a,q_80,r_3,x_1,y_2/test")
233
+
234
+ expect(["test", { :x => 1, :y => 2, :radius => 3, :gravity => :center, :quality => "80:444", :prefix => "a" }])
235
+ .to produce_url("#{upload_path}/g_center,p_a,q_80:444,r_3,x_1,y_2/test")
236
+ end
237
+ it "should support auto value" do
238
+
239
+ expect(["test", { :x => 1, :y => 2, :radius => 3, :gravity => :center, :quality => "auto", :prefix => "a" }])
240
+ .to produce_url("#{upload_path}/g_center,p_a,q_auto,r_3,x_1,y_2/test")
217
241
 
242
+ expect(["test", { :x => 1, :y => 2, :radius => 3, :gravity => :center, :quality => "auto:good", :prefix => "a" }])
243
+ .to produce_url("#{upload_path}/g_center,p_a,q_auto:good,r_3,x_1,y_2/test")
244
+
245
+ end
246
+ end
218
247
  describe ":transformation" do
219
248
  it "should support named tranformation" do
220
249
  expect(["test", { :transformation => "blip" }])
@@ -1,6 +1,6 @@
1
1
 
2
2
  /**
3
- * Cloudinary's JavaScript library - Version 2.0.9
3
+ * Cloudinary's JavaScript library - Version 2.1.0
4
4
  * Copyright Cloudinary
5
5
  * see https://github.com/cloudinary/cloudinary_js
6
6
  *
@@ -1748,16 +1748,18 @@ var extend = function(child, parent) { for (var key in parent) { if (hasProp.cal
1748
1748
  };
1749
1749
 
1750
1750
  Transformation.prototype.dpr = function(value) {
1751
- return this.param(value, "dpr", "dpr", function(dpr) {
1752
- dpr = dpr.toString();
1753
- if (dpr === "auto") {
1754
- return "1.0";
1755
- } else if (dpr != null ? dpr.match(/^\d+$/) : void 0) {
1756
- return dpr + ".0";
1757
- } else {
1758
- return dpr;
1759
- }
1760
- });
1751
+ return this.param(value, "dpr", "dpr", (function(_this) {
1752
+ return function(dpr) {
1753
+ dpr = dpr.toString();
1754
+ if ((dpr === "auto") && _this.getValue("client_hints") !== true) {
1755
+ return "1.0";
1756
+ } else if (dpr != null ? dpr.match(/^\d+$/) : void 0) {
1757
+ return dpr + ".0";
1758
+ } else {
1759
+ return dpr;
1760
+ }
1761
+ };
1762
+ })(this));
1761
1763
  };
1762
1764
 
1763
1765
  Transformation.prototype.effect = function(value) {
@@ -2389,6 +2391,12 @@ var extend = function(child, parent) { for (var key in parent) { if (hasProp.cal
2389
2391
  return element;
2390
2392
  };
2391
2393
 
2394
+ HtmlTag.isResponsive = function(tag, responsiveClass) {
2395
+ var dataSrc;
2396
+ dataSrc = Util.getData(tag, 'src-cache') || Util.getData(tag, 'src');
2397
+ return Util.hasClass(tag, responsiveClass) && /\bw_auto\b/.exec(dataSrc);
2398
+ };
2399
+
2392
2400
  return HtmlTag;
2393
2401
 
2394
2402
  })();
@@ -2837,9 +2845,9 @@ var extend = function(child, parent) { for (var key in parent) { if (hasProp.cal
2837
2845
 
2838
2846
  })(TextLayer);
2839
2847
  Cloudinary = (function() {
2840
- var AKAMAI_SHARED_CDN, CF_SHARED_CDN, DEFAULT_POSTER_OPTIONS, DEFAULT_VIDEO_SOURCE_TYPES, OLD_AKAMAI_SHARED_CDN, SHARED_CDN, VERSION, absolutize, applyBreakpoints, cdnSubdomainNumber, closestAbove, cloudinaryUrlPrefix, defaultBreakpoints, finalizeResourceType, parentWidth;
2848
+ var AKAMAI_SHARED_CDN, CF_SHARED_CDN, DEFAULT_POSTER_OPTIONS, DEFAULT_VIDEO_SOURCE_TYPES, OLD_AKAMAI_SHARED_CDN, SHARED_CDN, VERSION, absolutize, applyBreakpoints, cdnSubdomainNumber, closestAbove, cloudinaryUrlPrefix, defaultBreakpoints, finalizeResourceType, findContainerWidth, maxWidth, updateDpr;
2841
2849
 
2842
- VERSION = "2.0.9";
2850
+ VERSION = "2.1.0";
2843
2851
 
2844
2852
  CF_SHARED_CDN = "d3jpl91pxevbkh.cloudfront.net";
2845
2853
 
@@ -3137,17 +3145,20 @@ var extend = function(child, parent) { for (var key in parent) { if (hasProp.cal
3137
3145
  */
3138
3146
 
3139
3147
  Cloudinary.prototype.image = function(publicId, options) {
3140
- var img;
3148
+ var client_hints, img, ref, ref1;
3141
3149
  if (options == null) {
3142
3150
  options = {};
3143
3151
  }
3144
3152
  img = this.imageTag(publicId, options);
3145
- if (options.src == null) {
3153
+ client_hints = (ref = (ref1 = options.client_hints) != null ? ref1 : this.config('client_hints')) != null ? ref : false;
3154
+ if (!((options.src != null) || client_hints)) {
3146
3155
  img.setAttr("src", '');
3147
3156
  }
3148
3157
  img = img.toDOM();
3149
- Util.setData(img, 'src-cache', this.url(publicId, options));
3150
- this.cloudinary_update(img, options);
3158
+ if (!client_hints) {
3159
+ Util.setData(img, 'src-cache', this.url(publicId, options));
3160
+ this.cloudinary_update(img, options);
3161
+ }
3151
3162
  return img;
3152
3163
  };
3153
3164
 
@@ -3355,11 +3366,11 @@ var extend = function(child, parent) { for (var key in parent) { if (hasProp.cal
3355
3366
  * @ignore
3356
3367
  */
3357
3368
 
3358
- Cloudinary.prototype.calc_breakpoint = function(element, width) {
3369
+ Cloudinary.prototype.calc_breakpoint = function(element, width, steps) {
3359
3370
  var breakpoints, point;
3360
3371
  breakpoints = Util.getData(element, 'breakpoints') || Util.getData(element, 'stoppoints') || this.config('breakpoints') || this.config('stoppoints') || defaultBreakpoints;
3361
3372
  if (Util.isFunction(breakpoints)) {
3362
- return breakpoints(width);
3373
+ return breakpoints(width, steps);
3363
3374
  } else {
3364
3375
  if (Util.isString(breakpoints)) {
3365
3376
  breakpoints = ((function() {
@@ -3414,8 +3425,11 @@ var extend = function(child, parent) { for (var key in parent) { if (hasProp.cal
3414
3425
  return dprString;
3415
3426
  };
3416
3427
 
3417
- defaultBreakpoints = function(width) {
3418
- return 100 * Math.ceil(width / 100);
3428
+ defaultBreakpoints = function(width, steps) {
3429
+ if (steps == null) {
3430
+ steps = 100;
3431
+ }
3432
+ return steps * Math.ceil(width / steps);
3419
3433
  };
3420
3434
 
3421
3435
  closestAbove = function(list, value) {
@@ -3510,17 +3524,17 @@ var extend = function(child, parent) { for (var key in parent) { if (hasProp.cal
3510
3524
  return this;
3511
3525
  };
3512
3526
 
3513
- applyBreakpoints = function(tag, width, options) {
3527
+ applyBreakpoints = function(tag, width, steps, options) {
3514
3528
  var ref, ref1, ref2, responsive_use_breakpoints;
3515
3529
  responsive_use_breakpoints = (ref = (ref1 = (ref2 = options['responsive_use_breakpoints']) != null ? ref2 : options['responsive_use_stoppoints']) != null ? ref1 : this.config('responsive_use_breakpoints')) != null ? ref : this.config('responsive_use_stoppoints');
3516
3530
  if ((!responsive_use_breakpoints) || (responsive_use_breakpoints === 'resize' && !options.resizing)) {
3517
3531
  return width;
3518
3532
  } else {
3519
- return this.calc_breakpoint(tag, width);
3533
+ return this.calc_breakpoint(tag, width, steps);
3520
3534
  }
3521
3535
  };
3522
3536
 
3523
- parentWidth = function(element) {
3537
+ findContainerWidth = function(element) {
3524
3538
  var containerWidth, style;
3525
3539
  containerWidth = 0;
3526
3540
  while (((element = element != null ? element.parentNode : void 0) instanceof Element) && !containerWidth) {
@@ -3532,6 +3546,20 @@ var extend = function(child, parent) { for (var key in parent) { if (hasProp.cal
3532
3546
  return containerWidth;
3533
3547
  };
3534
3548
 
3549
+ updateDpr = function(dataSrc, roundDpr) {
3550
+ return dataSrc.replace(/\bdpr_(1\.0|auto)\b/g, 'dpr_' + this.device_pixel_ratio(roundDpr));
3551
+ };
3552
+
3553
+ maxWidth = function(requiredWidth, tag) {
3554
+ var imageWidth;
3555
+ imageWidth = Util.getData(tag, 'width') || 0;
3556
+ if (requiredWidth > imageWidth) {
3557
+ imageWidth = requiredWidth;
3558
+ Util.setData(tag, 'width', requiredWidth);
3559
+ }
3560
+ return requiredWidth;
3561
+ };
3562
+
3535
3563
 
3536
3564
  /**
3537
3565
  * Update hidpi (dpr_auto) and responsive (w_auto) fields according to the current container size and the device pixel ratio.
@@ -3549,10 +3577,16 @@ var extend = function(child, parent) { for (var key in parent) { if (hasProp.cal
3549
3577
  */
3550
3578
 
3551
3579
  Cloudinary.prototype.cloudinary_update = function(elements, options) {
3552
- var containerWidth, imageWidth, j, len, ref, ref1, ref2, ref3, requestedWidth, responsiveClass, roundDpr, setUrl, src, tag;
3580
+ var client_hints, containerWidth, dataSrc, j, len, match, ref, ref1, ref2, ref3, ref4, ref5, ref6, ref7, requiredWidth, responsive, responsiveClass, roundDpr, setUrl, tag;
3553
3581
  if (options == null) {
3554
3582
  options = {};
3555
3583
  }
3584
+ client_hints = (ref = (ref1 = options.client_hints) != null ? ref1 : this.config('client_hints')) != null ? ref : false;
3585
+ client_hints = client_hints || (typeof document !== "undefined" && document !== null ? document.querySelector('meta[http-equiv="Accept-CH"]') : void 0);
3586
+ if (client_hints) {
3587
+ return;
3588
+ }
3589
+ responsive = (ref2 = (ref3 = options.responsive) != null ? ref3 : this.config('responsive')) != null ? ref2 : false;
3556
3590
  elements = (function() {
3557
3591
  switch (false) {
3558
3592
  case !Util.isArray(elements):
@@ -3565,30 +3599,33 @@ var extend = function(child, parent) { for (var key in parent) { if (hasProp.cal
3565
3599
  return [elements];
3566
3600
  }
3567
3601
  })();
3568
- responsiveClass = (ref = (ref1 = this.responsiveConfig['responsive_class']) != null ? ref1 : options['responsive_class']) != null ? ref : this.config('responsive_class');
3569
- roundDpr = (ref2 = options['round_dpr']) != null ? ref2 : this.config('round_dpr');
3602
+ responsiveClass = (ref4 = (ref5 = this.responsiveConfig['responsive_class']) != null ? ref5 : options['responsive_class']) != null ? ref4 : this.config('responsive_class');
3603
+ roundDpr = (ref6 = options['round_dpr']) != null ? ref6 : this.config('round_dpr');
3570
3604
  for (j = 0, len = elements.length; j < len; j++) {
3571
3605
  tag = elements[j];
3572
- if (!((ref3 = tag.tagName) != null ? ref3.match(/img/i) : void 0)) {
3606
+ if (!((ref7 = tag.tagName) != null ? ref7.match(/img/i) : void 0)) {
3573
3607
  continue;
3574
3608
  }
3575
3609
  setUrl = true;
3576
- if (options.responsive) {
3610
+ if (responsive && !client_hints) {
3577
3611
  Util.addClass(tag, responsiveClass);
3578
3612
  }
3579
- src = Util.getData(tag, 'src-cache') || Util.getData(tag, 'src');
3580
- if (!Util.isEmpty(src)) {
3581
- src = src.replace(/\bdpr_(1\.0|auto)\b/g, 'dpr_' + this.device_pixel_ratio(roundDpr));
3582
- if (Util.hasClass(tag, responsiveClass) && /\bw_auto\b/.exec(src)) {
3583
- containerWidth = parentWidth(tag);
3613
+ dataSrc = Util.getData(tag, 'src-cache') || Util.getData(tag, 'src');
3614
+ if (!Util.isEmpty(dataSrc)) {
3615
+ dataSrc = updateDpr.call(this, dataSrc, roundDpr);
3616
+ if (HtmlTag.isResponsive(tag, responsiveClass)) {
3617
+ containerWidth = findContainerWidth(tag);
3584
3618
  if (containerWidth !== 0) {
3585
- requestedWidth = applyBreakpoints.call(this, tag, containerWidth, options);
3586
- imageWidth = Util.getData(tag, 'width') || 0;
3587
- if (requestedWidth > imageWidth) {
3588
- imageWidth = requestedWidth;
3589
- Util.setData(tag, 'width', requestedWidth);
3619
+ switch (false) {
3620
+ case !/w_auto:breakpoints/.test(dataSrc):
3621
+ requiredWidth = maxWidth(containerWidth, tag);
3622
+ dataSrc = dataSrc.replace(/w_auto:breakpoints([_0-9]*)(:[0-9]+)?/, "w_auto:breakpoints$1:" + requiredWidth);
3623
+ break;
3624
+ case !(match = /w_auto(:(\d+))?/.exec(dataSrc)):
3625
+ requiredWidth = applyBreakpoints.call(this, tag, containerWidth, match[2], options);
3626
+ requiredWidth = maxWidth(requiredWidth, tag);
3627
+ dataSrc = dataSrc.replace(/w_auto[^,\/]*/g, "w_" + requiredWidth);
3590
3628
  }
3591
- src = src.replace(/\bw_auto\b/g, 'w_' + imageWidth);
3592
3629
  Util.removeAttribute(tag, 'width');
3593
3630
  if (!options.responsive_preserve_height) {
3594
3631
  Util.removeAttribute(tag, 'height');
@@ -3598,7 +3635,7 @@ var extend = function(child, parent) { for (var key in parent) { if (hasProp.cal
3598
3635
  }
3599
3636
  }
3600
3637
  if (setUrl) {
3601
- Util.setAttribute(tag, 'src', src);
3638
+ Util.setAttribute(tag, 'src', dataSrc);
3602
3639
  }
3603
3640
  }
3604
3641
  }
@@ -3645,16 +3682,20 @@ var extend = function(child, parent) { for (var key in parent) { if (hasProp.cal
3645
3682
  */
3646
3683
 
3647
3684
  CloudinaryJQuery.prototype.image = function(publicId, options) {
3648
- var img, tag_options, url;
3685
+ var client_hints, img, ref, ref1;
3649
3686
  if (options == null) {
3650
3687
  options = {};
3651
3688
  }
3652
- tag_options = Util.merge({
3653
- src: ''
3654
- }, options);
3655
- img = this.imageTag(publicId, tag_options).toHtml();
3656
- url = this.url(publicId, options);
3657
- return jQuery(img).data('src-cache', url).cloudinary_update(options);
3689
+ img = this.imageTag(publicId, options);
3690
+ client_hints = (ref = (ref1 = options.client_hints) != null ? ref1 : this.config('client_hints')) != null ? ref : false;
3691
+ if (!((options.src != null) || client_hints)) {
3692
+ img.setAttr("src", '');
3693
+ }
3694
+ img = jQuery(img.toHtml());
3695
+ if (!client_hints) {
3696
+ img.data('src-cache', this.url(publicId, options)).cloudinary_update(options);
3697
+ }
3698
+ return img;
3658
3699
  };
3659
3700
 
3660
3701
 
@@ -4022,10 +4063,10 @@ var extend = function(child, parent) { for (var key in parent) { if (hasProp.cal
4022
4063
  TextLayer: TextLayer,
4023
4064
  SubtitlesLayer: SubtitlesLayer,
4024
4065
  Cloudinary: Cloudinary,
4025
- VERSION: "2.0.9",
4066
+ VERSION: "2.1.0",
4026
4067
  CloudinaryJQuery: CloudinaryJQuery
4027
4068
  };
4028
4069
  return cloudinary;
4029
4070
  });
4030
4071
 
4031
- //# sourceMappingURL=jquery.cloudinary.js.map
4072
+