cloudinary 1.11.1 → 1.12.0

Sign up to get free protection for your applications and to get access to all the features.
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
  }