cloudinary 1.11.1 → 1.12.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.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +6 -1
  3. data/.travis.yml +12 -6
  4. data/CHANGELOG.md +30 -0
  5. data/cloudinary.gemspec +2 -0
  6. data/lib/active_storage/blob_key.rb +20 -0
  7. data/lib/active_storage/service/cloudinary_service.rb +181 -0
  8. data/lib/cloudinary.rb +9 -4
  9. data/lib/cloudinary/api.rb +17 -4
  10. data/lib/cloudinary/auth_token.rb +6 -4
  11. data/lib/cloudinary/uploader.rb +4 -4
  12. data/lib/cloudinary/utils.rb +62 -29
  13. data/lib/cloudinary/version.rb +1 -1
  14. data/spec/active_storage/Gemfile +12 -0
  15. data/spec/active_storage/application_system_test_case.rb +5 -0
  16. data/spec/active_storage/database/create_users_migration.rb +9 -0
  17. data/spec/active_storage/database/setup.rb +7 -0
  18. data/spec/active_storage/dummy/Rakefile +5 -0
  19. data/spec/active_storage/dummy/app/assets/config/manifest.js +3 -0
  20. data/spec/active_storage/dummy/app/assets/javascripts/application.js +13 -0
  21. data/spec/active_storage/dummy/app/assets/stylesheets/application.css +15 -0
  22. data/spec/active_storage/dummy/app/controllers/application_controller.rb +5 -0
  23. data/spec/active_storage/dummy/app/helpers/application_helper.rb +4 -0
  24. data/spec/active_storage/dummy/app/jobs/application_job.rb +4 -0
  25. data/spec/active_storage/dummy/app/models/application_record.rb +5 -0
  26. data/spec/active_storage/dummy/app/views/layouts/application.html.erb +14 -0
  27. data/spec/active_storage/dummy/bin/bundle +5 -0
  28. data/spec/active_storage/dummy/bin/rails +6 -0
  29. data/spec/active_storage/dummy/bin/rake +6 -0
  30. data/spec/active_storage/dummy/bin/yarn +11 -0
  31. data/spec/active_storage/dummy/config.ru +7 -0
  32. data/spec/active_storage/dummy/config/application.rb +22 -0
  33. data/spec/active_storage/dummy/config/boot.rb +7 -0
  34. data/spec/active_storage/dummy/config/database.yml +25 -0
  35. data/spec/active_storage/dummy/config/environment.rb +7 -0
  36. data/spec/active_storage/dummy/config/environments/development.rb +52 -0
  37. data/spec/active_storage/dummy/config/environments/production.rb +83 -0
  38. data/spec/active_storage/dummy/config/environments/test.rb +38 -0
  39. data/spec/active_storage/dummy/config/initializers/application_controller_renderer.rb +7 -0
  40. data/spec/active_storage/dummy/config/initializers/assets.rb +16 -0
  41. data/spec/active_storage/dummy/config/initializers/backtrace_silencers.rb +8 -0
  42. data/spec/active_storage/dummy/config/initializers/cookies_serializer.rb +7 -0
  43. data/spec/active_storage/dummy/config/initializers/filter_parameter_logging.rb +6 -0
  44. data/spec/active_storage/dummy/config/initializers/inflections.rb +17 -0
  45. data/spec/active_storage/dummy/config/initializers/mime_types.rb +5 -0
  46. data/spec/active_storage/dummy/config/initializers/wrap_parameters.rb +16 -0
  47. data/spec/active_storage/dummy/config/routes.rb +4 -0
  48. data/spec/active_storage/dummy/config/secrets.yml +32 -0
  49. data/spec/active_storage/dummy/config/spring.rb +8 -0
  50. data/spec/active_storage/dummy/config/storage.yml +3 -0
  51. data/spec/active_storage/dummy/config/webpacker.yml +72 -0
  52. data/spec/active_storage/dummy/package.json +5 -0
  53. data/spec/active_storage/dummy/public/404.html +67 -0
  54. data/spec/active_storage/dummy/public/422.html +67 -0
  55. data/spec/active_storage/dummy/public/500.html +66 -0
  56. data/spec/active_storage/dummy/public/apple-touch-icon-precomposed.png +0 -0
  57. data/spec/active_storage/dummy/public/apple-touch-icon.png +0 -0
  58. data/spec/active_storage/dummy/public/favicon.ico +0 -0
  59. data/spec/active_storage/fixtures/files/colors.bmp +0 -0
  60. data/spec/active_storage/fixtures/files/empty_file.txt +0 -0
  61. data/spec/active_storage/fixtures/files/favicon.ico +0 -0
  62. data/spec/active_storage/fixtures/files/icon.psd +0 -0
  63. data/spec/active_storage/fixtures/files/icon.svg +13 -0
  64. data/spec/active_storage/fixtures/files/image.gif +0 -0
  65. data/spec/active_storage/fixtures/files/racecar.jpg +0 -0
  66. data/spec/active_storage/fixtures/files/racecar.tif +0 -0
  67. data/spec/active_storage/fixtures/files/racecar_rotated.jpg +0 -0
  68. data/spec/active_storage/fixtures/files/report.pdf +0 -0
  69. data/spec/active_storage/fixtures/files/rotated_video.mp4 +0 -0
  70. data/spec/active_storage/fixtures/files/video.mp4 +0 -0
  71. data/spec/active_storage/fixtures/files/video_with_rectangular_samples.mp4 +0 -0
  72. data/spec/active_storage/fixtures/files/video_with_undefined_display_aspect_ratio.mp4 +0 -0
  73. data/spec/active_storage/fixtures/files/video_without_video_stream.mp4 +0 -0
  74. data/spec/active_storage/service/cloudinary_service_spec.rb +92 -0
  75. data/spec/active_storage/service/configurations.yml +4 -0
  76. data/spec/active_storage/test_helper.rb +43 -0
  77. data/spec/api_spec.rb +68 -12
  78. data/spec/archive_spec.rb +17 -1
  79. data/spec/cloudinary_helper_spec.rb +2 -0
  80. data/spec/cloudinary_spec.rb +30 -6
  81. data/spec/movie.mp4 +0 -0
  82. data/spec/spec_helper.rb +9 -2
  83. data/spec/uploader_spec.rb +20 -3
  84. data/spec/utils_methods_spec.rb +29 -2
  85. data/spec/utils_spec.rb +93 -11
  86. data/vendor/assets/javascripts/cloudinary/jquery.cloudinary.js +31 -1
  87. data/vendor/assets/javascripts/cloudinary/jquery.fileupload.js +24 -4
  88. data/vendor/assets/javascripts/cloudinary/jquery.ui.widget.js +741 -561
  89. data/vendor/assets/javascripts/cloudinary/load-image.all.min.js +1 -1
  90. metadata +161 -3
Binary file
@@ -1,8 +1,11 @@
1
+ SUFFIX = ENV['TRAVIS_JOB_ID'] || rand(999999999).to_s
2
+
1
3
  require 'rspec'
2
4
  require 'rexml/parsers/ultralightparser'
3
5
  require 'nokogiri'
4
6
  require 'rspec/version'
5
7
  require 'rest_client'
8
+ require 'active_storage/test_helper' if RUBY_VERSION >= '2.2.2'
6
9
  require 'cloudinary'
7
10
 
8
11
  Cloudinary.config.enhance_image_tag = true
@@ -10,11 +13,15 @@ Cloudinary.config.enhance_image_tag = true
10
13
  DUMMY_CLOUD = "test123"
11
14
  TEST_IMAGE_URL = "http://cloudinary.com/images/old_logo.png"
12
15
  TEST_IMG = "spec/logo.png"
16
+ TEST_VIDEO = "spec/movie.mp4"
17
+ TEST_RAW = "spec/docx.docx"
13
18
  TEST_IMG_W = 241
14
19
  TEST_IMG_H = 51
15
- SUFFIX = ENV['TRAVIS_JOB_ID'] || rand(999999999).to_s
16
20
  TEST_TAG = 'cloudinary_gem_test'
17
21
  TIMESTAMP_TAG = "#{TEST_TAG}_#{SUFFIX}_#{RUBY_VERSION}_#{ defined? Rails::version ? Rails::version : 'no_rails'}"
22
+ UNIQUE_TEST_FOLDER = "#{TEST_TAG}_#{SUFFIX}_folder"
23
+ NEXT_CURSOR = "db27cfb02b3f69cb39049969c23ca430c6d33d5a3a7c3ad1d870c54e1a54ee0faa5acdd9f6d288666986001711759d10"
24
+ GENERIC_FOLDER_NAME = "some_folder"
18
25
 
19
26
  # Auth token
20
27
  KEY = "00112233FF99"
@@ -263,4 +270,4 @@ module Cloudinary
263
270
  end
264
271
 
265
272
  private_class_method :arrays_match?, :hashes_match?
266
- end
273
+ end
@@ -49,6 +49,24 @@ describe Cloudinary::Uploader do
49
49
  end
50
50
  end
51
51
 
52
+ it "should support the cinemagraph_analysis parameter for upload" do
53
+ expected = {
54
+ [:payload, :cinemagraph_analysis] => 1,
55
+ [:method] => :post
56
+ }
57
+ expect(RestClient::Request).to receive(:execute).with(deep_hash_value(expected))
58
+ Cloudinary::Uploader.upload(Pathname.new(TEST_IMG), :cinemagraph_analysis => true, :tags => [TEST_TAG, TIMESTAMP_TAG])
59
+ end
60
+
61
+ it "should support the cinemagraph_analysis parameter for explicit" do
62
+ expected = {
63
+ [:payload, :cinemagraph_analysis] => 1,
64
+ [:method] => :post
65
+ }
66
+ expect(RestClient::Request).to receive(:execute).with(deep_hash_value(expected))
67
+ Cloudinary::Uploader.explicit('sample', :type => "upload", :cinemagraph_analysis => true, :tags => [TEST_TAG, TIMESTAMP_TAG])
68
+ end
69
+
52
70
  describe '.rename' do
53
71
  before(:all) do
54
72
  @result = Cloudinary::Uploader.upload(TEST_IMG, :tags => [TEST_TAG, TIMESTAMP_TAG])
@@ -105,7 +123,7 @@ describe Cloudinary::Uploader do
105
123
  expect(RestClient::Request).to receive(:execute).with(deep_hash_value( [:payload, :public_id] => "sample", [:payload, :eager] => "c_scale,w_2.0"))
106
124
  result = Cloudinary::Uploader.explicit("sample", :type=>"upload", :eager=>[{:crop=>"scale", :width=>"2.0"}])
107
125
  end
108
-
126
+
109
127
  it "should support eager" do
110
128
  result = Cloudinary::Uploader.upload(TEST_IMG, :eager =>[{ :crop =>"scale", :width =>"2.0"}], :tags => [TEST_TAG, TIMESTAMP_TAG])
111
129
  expect(result["eager"].length).to be(1)
@@ -286,7 +304,7 @@ describe Cloudinary::Uploader do
286
304
  end
287
305
 
288
306
  it "should support requesting raw conversion" do
289
- expect{Cloudinary::Uploader.upload("spec/docx.docx", {:resource_type => :raw, :raw_convert => :illegal, :tags => [TEST_TAG, TIMESTAMP_TAG]})}.to raise_error(CloudinaryException, /Illegal value|not a valid|is invalid/)
307
+ expect{Cloudinary::Uploader.upload(TEST_RAW, {:resource_type => :raw, :raw_convert => :illegal, :tags => [TEST_TAG, TIMESTAMP_TAG]})}.to raise_error(CloudinaryException, /Illegal value|not a valid|is invalid/)
290
308
  end
291
309
 
292
310
  it "should support requesting categorization" do
@@ -380,7 +398,6 @@ describe Cloudinary::Uploader do
380
398
 
381
399
 
382
400
  describe 'explicit' do
383
-
384
401
  context ":invalidate" do
385
402
  it 'should pass the invalidate value to the server' do
386
403
  expect(RestClient::Request).to receive(:execute).with(deep_hash_value( [:payload, :invalidate] => 1))
@@ -1,7 +1,6 @@
1
1
  require 'rspec'
2
2
  require 'spec_helper'
3
3
  require 'cloudinary'
4
-
5
4
  include Cloudinary
6
5
 
7
6
  describe Utils do
@@ -51,4 +50,32 @@ describe Utils do
51
50
  expect(result).to include('foobar')
52
51
  end
53
52
  end
54
- end
53
+ describe 'is_remote_url' do
54
+ it 'should identify remote URLs correctly' do
55
+ [
56
+ "ftp://ftp.cloudinary.com/images/old_logo.png",
57
+ "http://cloudinary.com/images/old_logo.png",
58
+ "https://cloudinary.com/images/old_logo.png",
59
+ "s3://s3-us-west-2.amazonaws.com/cloudinary/images/old_logo.png",
60
+ "gs://cloudinary/images/old_logo.png",
61
+ "data:image/gif;charset=utf8;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7",
62
+ "data:image/gif;param1=value1;param2=value2;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
63
+ ].each do |url|
64
+ expect(Cloudinary::Utils.is_remote?(url)).to eq(true), url
65
+ end
66
+ end
67
+ end
68
+ describe "resource_type per format" do
69
+ it "should return the correct resource_type per format" do
70
+ format_to_resource_type = {
71
+ "jpg" => "image",
72
+ "mp4" => "video",
73
+ "txt" => "raw",
74
+ "mp3" => "video",
75
+ }
76
+ format_to_resource_type.each do |format, resource_type|
77
+ expect(Cloudinary::Utils.resource_type_for_format(format)).to eq(resource_type)
78
+ end
79
+ end
80
+ end
81
+ end
@@ -319,40 +319,48 @@ describe Cloudinary::Utils do
319
319
  end
320
320
 
321
321
  describe ":transformation" do
322
- it "should support named tranformation" do
322
+ it "should support named transformation" do
323
323
  expect(["test", { :transformation => "blip" }])
324
324
  .to produce_url("#{upload_path}/t_blip/test")
325
325
  .and empty_options
326
326
  end
327
327
 
328
- it "should support array of named tranformations" do
328
+ it "should support array of named transformation" do
329
329
  expect(["test", { :transformation => ["blip", "blop"] }])
330
330
  .to produce_url("#{upload_path}/t_blip.blop/test")
331
331
  .and empty_options
332
332
  end
333
333
 
334
- it "should support base tranformation" do
334
+ it "should support base transformation" do
335
335
  expect(["test", { :transformation => { :x => 100, :y => 100, :crop => :fill }, :crop => :crop, :width => 100 }])
336
336
  .to produce_url("#{upload_path}/c_fill,x_100,y_100/c_crop,w_100/test")
337
337
  .and mutate_options_to({ :width => 100 })
338
338
  end
339
339
 
340
- it "should support array of base tranformations" do
340
+ it "should support array of base transformation" do
341
341
  expect(["test", { :transformation => [{ :x => 100, :y => 100, :width => 200, :crop => :fill }, { :radius => 10 }], :crop => :crop, :width => 100 }])
342
342
  .to produce_url("#{upload_path}/c_fill,w_200,x_100,y_100/r_10/c_crop,w_100/test")
343
343
  .and mutate_options_to({ :width => 100 })
344
344
  end
345
345
 
346
- it "should support array of tranformations" do
346
+ it "should support array of transformation" do
347
347
  result = Cloudinary::Utils.generate_transformation_string([{ :x => 100, :y => 100, :width => 200, :crop => :fill }, { :radius => 10 }])
348
348
  expect(result).to eq("c_fill,w_200,x_100,y_100/r_10")
349
349
  end
350
350
 
351
- it "should not include empty tranformations" do
351
+ it "should not include empty transformation" do
352
352
  expect(["test", { :transformation => [{}, { :x => 100, :y => 100, :crop => :fill }, {}] }])
353
353
  .to produce_url("#{upload_path}/c_fill,x_100,y_100/test")
354
354
  .and empty_options
355
355
  end
356
+
357
+ describe "should support and translate arithmetic operators" do
358
+ it "should support * / + - ^" do
359
+ t = [{:width => 'initial_width * 2 / 3 ^ 2', :height => 'initial_height + 2 - 3', :crop => 'scale'}]
360
+ expected_trans = "c_scale,h_ih_add_2_sub_3,w_iw_mul_2_div_3_pow_2"
361
+ expect(Cloudinary::Utils.cloudinary_url('sample', :transformation => t)).to eq("#{upload_path}/#{expected_trans}/sample")
362
+ end
363
+ end
356
364
  end
357
365
 
358
366
 
@@ -428,6 +436,34 @@ describe Cloudinary::Utils do
428
436
  .and empty_options
429
437
  end
430
438
 
439
+ it "should process the radius correctly when given valid values" do
440
+ valid_radius_test_values = [
441
+ [10, 'r_10'],
442
+ ['10', 'r_10'],
443
+ ['$v', 'r_$v'],
444
+ [[10, 20, 30], 'r_10:20:30'],
445
+ [[10, 20, '$v'], 'r_10:20:$v'],
446
+ [[10, 20, '$v', 40], 'r_10:20:$v:40'],
447
+ [['10:20'], 'r_10:20'],
448
+ [['10:20:$v:40'], 'r_10:20:$v:40']
449
+ ]
450
+ valid_radius_test_values.each do |options, expected|
451
+ expect(["test", { :transformation => { :radius => options } }])
452
+ .to produce_url("#{root_path}/image/upload/#{expected}/test") .and empty_options
453
+ end
454
+ end
455
+
456
+ it "should throw an error when the radius is given invalid values" do
457
+ invalid_radius_test_values = [
458
+ [],
459
+ [10,20,30,40,50]
460
+ ]
461
+ invalid_radius_test_values.each do |options|
462
+ expect{Cloudinary::Utils.cloudinary_url("test", {:transformation => {:radius => options}})}
463
+ .to raise_error(CloudinaryException)
464
+ end
465
+ end
466
+
431
467
  it "should support format for fetch urls" do
432
468
  expect(["http://cloudinary.com/images/logo.png", { :format => "jpg", :type => :fetch }])
433
469
  .to produce_url("#{root_path}/image/fetch/f_jpg/http://cloudinary.com/images/logo.png")
@@ -578,6 +614,8 @@ describe Cloudinary::Utils do
578
614
  ["text parameter", { :public_id => "test_text", :text => text_layer }, "text:test_text:#{text_encoded}"],
579
615
  ["text with font family and size parameters", { :text => text_layer, :font_family => "Arial", :font_size => "18" }, "text:Arial_18:#{text_encoded}"],
580
616
  ["text with text style parameter", { :text => text_layer, :font_family => "Arial", :font_size => "18", :font_weight => "bold", :font_style => "italic", :letter_spacing => 4, :line_spacing => 2 }, "text:Arial_18_bold_italic_letter_spacing_4_line_spacing_2:#{text_encoded}"],
617
+ ["text with antialiasing and font hinting", { :text => "Hello World, Nice to meet you?", :font_family => "Arial", :font_size => "18", :font_antialiasing => "best", :font_hinting => "medium"}, "text:Arial_18_antialias_best_hinting_medium:Hello%20World%252C%20Nice%20to%20meet%20you%3F"],
618
+ ["text with text style parameter (explicit)", "text:Arial_18_antialias_best_hinting_medium:Hello%20World%252C%20Nice%20to%20meet%20you%3F", "text:Arial_18_antialias_best_hinting_medium:Hello%20World%252C%20Nice%20to%20meet%20you%3F"],
581
619
  ["subtitles", { :resource_type => "subtitles", :public_id => "subtitles.srt" }, "subtitles:subtitles.srt"],
582
620
  ["subtitles with font family and size", { :resource_type => "subtitles", :public_id => "subtitles.srt", :font_family => "Arial", :font_size => "40" }, "subtitles:Arial_40:subtitles.srt"],
583
621
  ["image of type fetch", { :public_id => "http://res.cloudinary.com/demo/image/upload/ci", :type => "fetch" }, "fetch:aHR0cDovL3Jlcy5jbG91ZGluYXJ5LmNvbS9kZW1vL2ltYWdlL3VwbG9hZC9jaQ=="]
@@ -732,6 +770,51 @@ describe Cloudinary::Utils do
732
770
  .and empty_options
733
771
  end
734
772
 
773
+ it "should default force_version to True if no value is given" do
774
+ expect(["folder/test", {}])
775
+ .to produce_url("#{upload_path}/v1/folder/test")
776
+ .and empty_options
777
+ end
778
+
779
+ it "should exclude the version if resource is stored in a folder and force_version is False" do
780
+ expect(["folder/test", {:force_version => false}])
781
+ .to produce_url("#{upload_path}/folder/test")
782
+ .and empty_options
783
+ end
784
+
785
+ it "should include the version if given explicitly regardless of force_verison (without folder)" do
786
+ expect(["test", {:force_version => false, :version => 12345}])
787
+ .to produce_url("#{upload_path}/v12345/test")
788
+ .and empty_options
789
+ end
790
+
791
+ it "should include the version if given explicitly regardless of force_verison (with folder)" do
792
+ expect(["folder/test", {:force_version => false, :version => 12345}])
793
+ .to produce_url("#{upload_path}/v12345/folder/test")
794
+ .and empty_options
795
+ end
796
+
797
+ it "should use the force_version option if set in the global config" do
798
+ Cloudinary.config(:force_version => false)
799
+ expect(["folder/test", {}])
800
+ .to produce_url("#{upload_path}/folder/test")
801
+ .and empty_options
802
+ end
803
+
804
+ it "should ignore the global force_version config if version is set explicitly in the options" do
805
+ Cloudinary.config(:force_version => false)
806
+ expect(["folder/test", {:version => 12345}])
807
+ .to produce_url("#{upload_path}/v12345/folder/test")
808
+ .and empty_options
809
+ end
810
+
811
+ it "should override global config option if force_version is given within options" do
812
+ Cloudinary.config(:force_version => false)
813
+ expect(["folder/test", {:force_version => true}])
814
+ .to produce_url("#{upload_path}/v1/folder/test")
815
+ .and empty_options
816
+ end
817
+
735
818
  it "should allow to shorted image/upload urls" do
736
819
  expect(["test", { :shorten => true }])
737
820
  .to produce_url("#{root_path}/iu/test")
@@ -875,11 +958,9 @@ describe Cloudinary::Utils do
875
958
  :effect =>"grayscale"])
876
959
  .to produce_url("#{upload_path}/#{all_operators}/sample")
877
960
  end
878
-
879
961
  end
880
- end
881
962
 
882
- describe "variables" do
963
+ describe "variables" do
883
964
  it "array should define a set of variables" do
884
965
  options = {
885
966
  :if => "face_count > 2",
@@ -909,7 +990,7 @@ describe Cloudinary::Utils do
909
990
  end
910
991
  end
911
992
 
912
- describe "context" do
993
+ describe "context" do
913
994
  it 'should escape pipe and backslash characters' do
914
995
  context = {"caption" => "different = caption", "alt2" => "alt|alternative"}
915
996
  result = Cloudinary::Utils.encode_context(context)
@@ -925,7 +1006,7 @@ describe Cloudinary::Utils do
925
1006
  end
926
1007
  end
927
1008
 
928
- describe "customFunction" do
1009
+ describe "customFunction" do
929
1010
  custom_function_wasm = {
930
1011
  :function_type => 'wasm',
931
1012
  :source => 'blur.wasm'
@@ -967,4 +1048,5 @@ describe Cloudinary::Utils do
967
1048
  end
968
1049
 
969
1050
  end
1051
+ end
970
1052
  end
@@ -802,7 +802,7 @@ var slice = [].slice,
802
802
  function TextLayer(options) {
803
803
  var keys;
804
804
  TextLayer.__super__.constructor.call(this, options);
805
- keys = ["resourceType", "resourceType", "fontFamily", "fontSize", "fontWeight", "fontStyle", "textDecoration", "textAlign", "stroke", "letterSpacing", "lineSpacing", "text"];
805
+ keys = ["resourceType", "resourceType", "fontFamily", "fontSize", "fontWeight", "fontStyle", "textDecoration", "textAlign", "stroke", "letterSpacing", "lineSpacing", "fontHinting", "fontAntialiasing", "text"];
806
806
  if (options != null) {
807
807
  keys.forEach((function(_this) {
808
808
  return function(key) {
@@ -871,6 +871,16 @@ var slice = [].slice,
871
871
  return this;
872
872
  };
873
873
 
874
+ TextLayer.prototype.fontAntialiasing = function(fontAntialiasing){
875
+ this.options.fontAntialiasing = fontAntialiasing;
876
+ return this;
877
+ };
878
+
879
+ TextLayer.prototype.fontHinting = function(fontHinting ){
880
+ this.options.fontHinting = fontHinting ;
881
+ return this;
882
+ };
883
+
874
884
  TextLayer.prototype.text = function(text) {
875
885
  this.options.text = text;
876
886
  return this;
@@ -932,6 +942,12 @@ var slice = [].slice,
932
942
  if (!(Util.isEmpty(this.options.lineSpacing) && !Util.isNumberLike(this.options.lineSpacing))) {
933
943
  components.push("line_spacing_" + this.options.lineSpacing);
934
944
  }
945
+ if (this.options.fontAntialiasing !== "none") {
946
+ components.push("antialias_"+this.options.fontAntialiasing);
947
+ }
948
+ if (this.options.fontHinting !== "none") {
949
+ components.push("hinting_"+this.options.fontHinting);
950
+ }
935
951
  if (!Util.isEmpty(Util.compact(components))) {
936
952
  if (Util.isEmpty(this.options.fontFamily)) {
937
953
  throw "Must supply fontFamily. " + components;
@@ -2780,6 +2796,20 @@ var slice = [].slice,
2780
2796
  return this.param(value, "gravity", "g");
2781
2797
  };
2782
2798
 
2799
+ Transformation.prototype.fps = function(value) {
2800
+ return this.param(value, "fps", "fps", (function(_this) {
2801
+ return function(fps) {
2802
+ if (Util.isString(fps)) {
2803
+ return fps;
2804
+ } else if (Util.isArray(fps)) {
2805
+ return fps.join("-");
2806
+ } else {
2807
+ return fps;
2808
+ }
2809
+ };
2810
+ })(this));
2811
+ };
2812
+
2783
2813
  Transformation.prototype.height = function(value) {
2784
2814
  return this.param(value, "height", "h", (function(_this) {
2785
2815
  return function() {
@@ -43,7 +43,7 @@
43
43
  '|(Kindle/(1\\.0|2\\.[05]|3\\.0))'
44
44
  ).test(window.navigator.userAgent) ||
45
45
  // Feature detection for all other devices:
46
- $('<input type="file">').prop('disabled'));
46
+ $('<input type="file"/>').prop('disabled'));
47
47
 
48
48
  // The FileReader API is not actually used, but works as feature detection,
49
49
  // as some Safari versions (5?) support XHR file uploads via the FormData API,
@@ -261,6 +261,9 @@
261
261
  // Callback for dragover events of the dropZone(s):
262
262
  // dragover: function (e) {}, // .bind('fileuploaddragover', func);
263
263
 
264
+ // Callback before the start of each chunk upload request (before form data initialization):
265
+ // chunkbeforesend: function (e, data) {}, // .bind('fileuploadchunkbeforesend', func);
266
+
264
267
  // Callback for the start of each chunk upload request:
265
268
  // chunksend: function (e, data) {}, // .bind('fileuploadchunksend', func);
266
269
 
@@ -434,6 +437,13 @@
434
437
  }
435
438
  },
436
439
 
440
+ _deinitProgressListener: function (options) {
441
+ var xhr = options.xhr ? options.xhr() : $.ajaxSettings.xhr();
442
+ if (xhr.upload) {
443
+ $(xhr.upload).unbind('progress');
444
+ }
445
+ },
446
+
437
447
  _isInstanceOf: function (type, obj) {
438
448
  // Cross-frame instanceof check
439
449
  return Object.prototype.toString.call(obj) === '[object ' + type + ']';
@@ -453,7 +463,7 @@
453
463
  }
454
464
  if (!multipart || options.blob || !this._isInstanceOf('File', file)) {
455
465
  options.headers['Content-Disposition'] = 'attachment; filename="' +
456
- encodeURI(file.name) + '"';
466
+ encodeURI(file.uploadName || file.name) + '"';
457
467
  }
458
468
  if (!multipart) {
459
469
  options.contentType = file.type || 'application/octet-stream';
@@ -489,7 +499,11 @@
489
499
  });
490
500
  }
491
501
  if (options.blob) {
492
- formData.append(paramName, options.blob, file.name);
502
+ formData.append(
503
+ paramName,
504
+ options.blob,
505
+ file.uploadName || file.name
506
+ );
493
507
  } else {
494
508
  $.each(options.files, function (index, file) {
495
509
  // This check allows the tests to run with
@@ -762,6 +776,8 @@
762
776
  // Expose the chunk bytes position range:
763
777
  o.contentRange = 'bytes ' + ub + '-' +
764
778
  (ub + o.chunkSize - 1) + '/' + fs;
779
+ // Trigger chunkbeforesend to allow form data to be updated for this chunk
780
+ that._trigger('chunkbeforesend', null, o);
765
781
  // Process the upload data (the blob and potential form data):
766
782
  that._initXHRData(o);
767
783
  // Add progress listeners for this chunk upload:
@@ -808,6 +824,9 @@
808
824
  o.context,
809
825
  [jqXHR, textStatus, errorThrown]
810
826
  );
827
+ })
828
+ .always(function () {
829
+ that._deinitProgressListener(o);
811
830
  });
812
831
  };
813
832
  this._enhancePromise(promise);
@@ -909,6 +928,7 @@
909
928
  }).fail(function (jqXHR, textStatus, errorThrown) {
910
929
  that._onFail(jqXHR, textStatus, errorThrown, options);
911
930
  }).always(function (jqXHRorResult, textStatus, jqXHRorError) {
931
+ that._deinitProgressListener(options);
912
932
  that._onAlways(
913
933
  jqXHRorResult,
914
934
  textStatus,
@@ -1126,7 +1146,7 @@
1126
1146
  dirReader = entry.createReader();
1127
1147
  readEntries();
1128
1148
  } else {
1129
- // Return an empy list for file system items
1149
+ // Return an empty list for file system items
1130
1150
  // other than files or directories:
1131
1151
  dfd.resolve([]);
1132
1152
  }