actiontext 7.1.5.2 → 8.1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +43 -132
  3. data/app/assets/javascripts/actiontext.esm.js +114 -14
  4. data/app/assets/javascripts/actiontext.js +120 -17
  5. data/app/helpers/action_text/content_helper.rb +2 -0
  6. data/app/helpers/action_text/tag_helper.rb +63 -37
  7. data/app/javascript/actiontext/attachment_upload.js +78 -12
  8. data/app/javascript/actiontext/index.js +10 -1
  9. data/app/models/action_text/encrypted_rich_text.rb +2 -2
  10. data/app/models/action_text/record.rb +2 -0
  11. data/app/models/action_text/rich_text.rb +62 -27
  12. data/db/migrate/20180528164100_create_action_text_tables.rb +1 -1
  13. data/lib/action_text/attachable.rb +35 -33
  14. data/lib/action_text/attachables/content_attachment.rb +2 -0
  15. data/lib/action_text/attachables/missing_attachable.rb +2 -0
  16. data/lib/action_text/attachables/remote_image.rb +2 -0
  17. data/lib/action_text/attachment.rb +27 -25
  18. data/lib/action_text/attachment_gallery.rb +2 -0
  19. data/lib/action_text/attachments/caching.rb +2 -0
  20. data/lib/action_text/attachments/minification.rb +2 -0
  21. data/lib/action_text/attachments/trix_conversion.rb +2 -0
  22. data/lib/action_text/attribute.rb +61 -27
  23. data/lib/action_text/content.rb +49 -28
  24. data/lib/action_text/deprecator.rb +2 -0
  25. data/lib/action_text/encryption.rb +2 -0
  26. data/lib/action_text/engine.rb +7 -2
  27. data/lib/action_text/fixture_set.rb +35 -35
  28. data/lib/action_text/fragment.rb +4 -0
  29. data/lib/action_text/gem_version.rb +6 -4
  30. data/lib/action_text/html_conversion.rb +2 -0
  31. data/lib/action_text/plain_text_conversion.rb +65 -28
  32. data/lib/action_text/rendering.rb +2 -1
  33. data/lib/action_text/serialization.rb +2 -0
  34. data/lib/action_text/system_test_helper.rb +52 -33
  35. data/lib/action_text/trix_attachment.rb +2 -0
  36. data/lib/action_text/version.rb +3 -1
  37. data/lib/generators/action_text/install/install_generator.rb +4 -21
  38. data/lib/generators/action_text/install/templates/actiontext.css +414 -5
  39. data/lib/rails/generators/test_unit/install_generator.rb +2 -0
  40. data/package.json +3 -2
  41. metadata +28 -16
  42. data/app/assets/javascripts/trix.js +0 -13720
  43. data/app/assets/stylesheets/trix.css +0 -412
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7cb8576fb6dc6ee3f8b1cfff7f3e3973f6eb3fa34e1784c5c912418233b49a54
4
- data.tar.gz: 47519302480a37ee21c2841674238431d08aec65e7d4d7b459be4805c1631dfa
3
+ metadata.gz: 51fa37e47fded8fa624f616edfdfd65929148c6d9a1dae13a5aa9a0a87ff28e0
4
+ data.tar.gz: 549e8a060b6a447f72d3d5f69fe317bfbeb88627788284133bb8dff358ccd0d6
5
5
  SHA512:
6
- metadata.gz: 7948ef6965b909773870f725b10732634619221c9cffaeefb7fb6881cf77c44ea2746d7b93f152c6a786c24b328b3f409248ed8193d66e593728b3f5976e16a5
7
- data.tar.gz: cc70c65ce97bc493dd9e9cce61fd4fb3026cd4f31c4b5aabeacd01b86858a75df5e2217bf29dbedc983d4b9921692f8736df015ea345954d44f7b61c7b91331d
6
+ metadata.gz: 4eba1482b7e133fcc07242342de6c8890331a081226a2e7cf157baaa8df29f8c333956be2fbffcbe93ce19662ffcf6e625d5fb9c84ce1c1d964a3625a68d308e
7
+ data.tar.gz: d22679beecbaf10140153d3d84a6714d0e341a8bca28dba143949a901fbd5a67fffabf701df97f0766f3cb53c7bd518515dd4e7a97009df13a6e4452be577f37
data/CHANGELOG.md CHANGED
@@ -1,167 +1,78 @@
1
- ## Rails 7.1.5.2 (August 13, 2025) ##
1
+ ## Rails 8.1.2.1 (March 23, 2026) ##
2
2
 
3
3
  * No changes.
4
4
 
5
5
 
6
- ## Rails 7.1.5.1 (December 10, 2024) ##
7
-
8
- * Update vendored trix version to 2.1.10
9
-
10
- *John Hawthorn*
11
-
12
-
13
- ## Rails 7.1.5 (October 30, 2024) ##
14
-
15
- * No changes.
16
-
17
-
18
- ## Rails 7.1.4.2 (October 23, 2024) ##
19
-
20
- * No changes.
21
-
22
-
23
- ## Rails 7.1.4.1 (October 15, 2024) ##
24
-
25
- * Avoid backtracing in plain_text_for_blockquote_node
26
-
27
- [CVE-2024-47888]
28
-
29
- *John Hawthorn*
30
-
31
- ## Rails 7.1.4 (August 22, 2024) ##
32
-
33
- * Strip `content` attribute if the key is present but the value is empty
34
-
35
- *Jeremy Green*
36
-
37
- * Only sanitize `content` attribute when present in attachments.
38
-
39
- *Petrik de Heus*
40
-
41
-
42
- ## Rails 7.1.3.4 (June 04, 2024) ##
43
-
44
- * Sanitize ActionText HTML ContentAttachment in Trix edit view
45
- [CVE-2024-32464]
46
-
47
- *Aaron Patterson*
48
-
49
- ## Rails 7.1.3.3 (May 16, 2024) ##
50
-
51
- * Upgrade Trix to 2.1.1 to fix [CVE-2024-34341](https://github.com/basecamp/trix/security/advisories/GHSA-qjqp-xr96-cj99).
52
-
53
- *Rafael Mendonça França*
54
-
55
-
56
- ## Rails 7.1.3.2 (February 21, 2024) ##
6
+ ## Rails 8.1.2 (January 08, 2026) ##
57
7
 
58
8
  * No changes.
59
9
 
60
10
 
61
- ## Rails 7.1.3.1 (February 21, 2024) ##
11
+ ## Rails 8.1.1 (October 28, 2025) ##
62
12
 
63
13
  * No changes.
64
14
 
65
15
 
66
- ## Rails 7.1.3 (January 16, 2024) ##
67
-
68
- * No changes.
69
-
16
+ ## Rails 8.1.0 (October 22, 2025) ##
70
17
 
71
- ## Rails 7.1.2 (November 10, 2023) ##
18
+ * De-couple `@rails/actiontext/attachment_upload.js` from `Trix.Attachment`
72
19
 
73
- * Compile ESM package that can be used directly in the browser as `actiontext.esm.js`.
74
-
75
- *Matias Grunberg*
76
-
77
- * Fix using actiontext.js with Sprockets.
78
-
79
- *Matias Grunberg*
80
-
81
- * Upgrade Trix to 2.0.7.
82
-
83
- *Hartley McGuire*
84
-
85
- * Fix using Trix with Sprockets.
86
-
87
- *Hartley McGuire*
88
-
89
-
90
- ## Rails 7.1.1 (October 11, 2023) ##
91
-
92
- * No changes.
20
+ Implement `@rails/actiontext/index.js` with a `direct-upload:progress` event
21
+ listeners and `Promise` resolution.
93
22
 
23
+ *Sean Doyle*
94
24
 
95
- ## Rails 7.1.0 (October 05, 2023) ##
25
+ * Capture block content for form helper methods
96
26
 
97
- * No changes.
27
+ ```erb
28
+ <%= rich_textarea_tag :content, nil do %>
29
+ <h1>hello world</h1>
30
+ <% end %>
31
+ <!-- <input type="hidden" name="content" id="trix_input_1" value="&lt;h1&gt;hello world&lt;/h1&gt;"/><trix-editor … -->
98
32
 
33
+ <%= rich_textarea :message, :content, input: "trix_input_1" do %>
34
+ <h1>hello world</h1>
35
+ <% end %>
36
+ <!-- <input type="hidden" name="message[content]" id="trix_input_1" value="&lt;h1&gt;hello world&lt;/h1&gt;"/><trix-editor … -->
99
37
 
100
- ## Rails 7.1.0.rc2 (October 01, 2023) ##
38
+ <%= form_with model: Message.new do |form| %>
39
+ <%= form.rich_textarea :content do %>
40
+ <h1>hello world</h1>
41
+ <% end %>
42
+ <% end %>
43
+ <!-- <form action="/messages" accept-charset="UTF-8" method="post"><input type="hidden" name="message[content]" id="message_content_trix_input_message" value="&lt;h1&gt;hello world&lt;/h1&gt;"/><trix-editor … -->
44
+ ```
101
45
 
102
- * No changes.
46
+ *Sean Doyle*
103
47
 
48
+ * Generalize `:rich_text_area` Capybara selector
104
49
 
105
- ## Rails 7.1.0.rc1 (September 27, 2023) ##
50
+ Prepare for more Action Text-capable WYSIWYG editors by making
51
+ `:rich_text_area` rely on the presence of `[role="textbox"]` and
52
+ `[contenteditable]` HTML attributes rather than a `<trix-editor>` element.
106
53
 
107
- * No changes.
54
+ *Sean Doyle*
108
55
 
56
+ * Forward `fill_in_rich_text_area` options to Capybara
109
57
 
110
- ## Rails 7.1.0.beta1 (September 13, 2023) ##
58
+ ```ruby
59
+ fill_in_rich_textarea "Rich text editor", id: "trix_editor_1", with: "Hello world!"
60
+ ```
111
61
 
112
- * Use `Rails::HTML5::SafeListSanitizer` by default in the Rails 7.1 configuration if it is
113
- supported.
62
+ *Sean Doyle*
114
63
 
115
- Action Text's sanitizer can be configured by setting
116
- `config.action_text.sanitizer_vendor`. Supported values are `Rails::HTML4::Sanitizer` or
117
- `Rails::HTML5::Sanitizer`.
64
+ * Attachment upload progress accounts for server processing time.
118
65
 
119
- The Rails 7.1 configuration will set this to `Rails::HTML5::Sanitizer` when it is supported, and
120
- fall back to `Rails::HTML4::Sanitizer`. Previous configurations default to
121
- `Rails::HTML4::Sanitizer`.
66
+ *Jeremy Daer*
122
67
 
123
- As a result of this change, the defaults for `ActionText::ContentHelper.allowed_tags` and
124
- `.allowed_attributes` are applied at runtime, so the value of these attributes is now 'nil'
125
- unless set by the application. You may call `sanitizer_allowed_tags` or
126
- `sanitizer_allowed_attributes` to inspect the tags and attributes being allowed by the
127
- sanitizer.
68
+ * The Trix dependency is now satisfied by a gem, `action_text-trix`, rather than vendored
69
+ files. This allows applications to bump Trix versions independently of Rails
70
+ releases. Effectively this also upgrades Trix to `>= 2.1.15`.
128
71
 
129
72
  *Mike Dalessio*
130
73
 
131
- * Attachables now can override default attachment missing template.
132
-
133
- When rendering Action Text attachments where the underlying attachable model has
134
- been removed, a fallback template is used. You now can override this template on
135
- a per-model basis. For example, you could render a placeholder image for a file
136
- attachment or the text "Deleted User" for a User attachment.
137
-
138
- *Matt Swanson*, *Joel Drapper*
139
-
140
- * Update bundled Trix version from `1.3.1` to `2.0.4`.
141
-
142
- *Sarah Ridge*, *Sean Doyle*
143
-
144
- * Apply `field_error_proc` to `rich_text_area` form fields.
145
-
146
- *Kaíque Kandy Koga*
147
-
148
- * Action Text attachment URLs rendered in a background job (a la Turbo
149
- Streams) now use `Rails.application.default_url_options` and
150
- `Rails.application.config.force_ssl` instead of `http://example.org`.
151
-
152
- *Jonathan Hefner*
153
-
154
- * Support `strict_loading:` option for `has_rich_text` declaration
74
+ * Change `ActionText::RichText#embeds` assignment from `before_save` to `before_validation`
155
75
 
156
76
  *Sean Doyle*
157
77
 
158
- * Update ContentAttachment so that it can encapsulate arbitrary HTML content in a document.
159
-
160
- *Jamis Buck*
161
-
162
- * Fix an issue that caused the content layout to render multiple times when a
163
- rich_text field was updated.
164
-
165
- *Jacob Herrington*
166
-
167
- Please check [7-0-stable](https://github.com/rails/rails/blob/7-0-stable/actiontext/CHANGELOG.md) for previous changes.
78
+ Please check [8-0-stable](https://github.com/rails/rails/blob/8-0-stable/actiontext/CHANGELOG.md) for previous changes.
@@ -672,7 +672,7 @@ class DirectUploadController {
672
672
  }));
673
673
  }
674
674
  uploadRequestDidProgress(event) {
675
- const progress = event.loaded / event.total * 100;
675
+ const progress = event.loaded / event.total * 90;
676
676
  if (progress) {
677
677
  this.dispatch("progress", {
678
678
  progress: progress
@@ -707,6 +707,42 @@ class DirectUploadController {
707
707
  xhr: xhr
708
708
  });
709
709
  xhr.upload.addEventListener("progress", (event => this.uploadRequestDidProgress(event)));
710
+ xhr.upload.addEventListener("loadend", (() => {
711
+ this.simulateResponseProgress(xhr);
712
+ }));
713
+ }
714
+ simulateResponseProgress(xhr) {
715
+ let progress = 90;
716
+ const startTime = Date.now();
717
+ const updateProgress = () => {
718
+ const elapsed = Date.now() - startTime;
719
+ const estimatedResponseTime = this.estimateResponseTime();
720
+ const responseProgress = Math.min(elapsed / estimatedResponseTime, 1);
721
+ progress = 90 + responseProgress * 9;
722
+ this.dispatch("progress", {
723
+ progress: progress
724
+ });
725
+ if (xhr.readyState !== XMLHttpRequest.DONE && progress < 99) {
726
+ requestAnimationFrame(updateProgress);
727
+ }
728
+ };
729
+ xhr.addEventListener("loadend", (() => {
730
+ this.dispatch("progress", {
731
+ progress: 100
732
+ });
733
+ }));
734
+ requestAnimationFrame(updateProgress);
735
+ }
736
+ estimateResponseTime() {
737
+ const fileSize = this.file.size;
738
+ const MB = 1024 * 1024;
739
+ if (fileSize < MB) {
740
+ return 1e3;
741
+ } else if (fileSize < 10 * MB) {
742
+ return 2e3;
743
+ } else {
744
+ return 3e3 + fileSize / MB * 50;
745
+ }
710
746
  }
711
747
  }
712
748
 
@@ -846,32 +882,92 @@ function autostart() {
846
882
  setTimeout(autostart, 1);
847
883
 
848
884
  class AttachmentUpload {
849
- constructor(attachment, element) {
885
+ constructor(attachment, element, file = attachment.file) {
850
886
  this.attachment = attachment;
851
887
  this.element = element;
852
- this.directUpload = new DirectUpload(attachment.file, this.directUploadUrl, this);
888
+ this.directUpload = new DirectUpload(file, this.directUploadUrl, this);
889
+ this.file = file;
853
890
  }
854
891
  start() {
855
- this.directUpload.create(this.directUploadDidComplete.bind(this));
892
+ return new Promise(((resolve, reject) => {
893
+ this.directUpload.create(((error, attributes) => this.directUploadDidComplete(error, attributes, resolve, reject)));
894
+ this.dispatch("start");
895
+ }));
856
896
  }
857
897
  directUploadWillStoreFileWithXHR(xhr) {
858
898
  xhr.upload.addEventListener("progress", (event => {
859
- const progress = event.loaded / event.total * 100;
860
- this.attachment.setUploadProgress(progress);
899
+ const progress = event.loaded / event.total * 90;
900
+ if (progress) {
901
+ this.dispatch("progress", {
902
+ progress: progress
903
+ });
904
+ }
905
+ }));
906
+ xhr.upload.addEventListener("loadend", (() => {
907
+ this.simulateResponseProgress(xhr);
908
+ }));
909
+ }
910
+ simulateResponseProgress(xhr) {
911
+ let progress = 90;
912
+ const startTime = Date.now();
913
+ const updateProgress = () => {
914
+ const elapsed = Date.now() - startTime;
915
+ const estimatedResponseTime = this.estimateResponseTime();
916
+ const responseProgress = Math.min(elapsed / estimatedResponseTime, 1);
917
+ progress = 90 + responseProgress * 9;
918
+ this.dispatch("progress", {
919
+ progress: progress
920
+ });
921
+ if (xhr.readyState !== XMLHttpRequest.DONE && progress < 99) {
922
+ requestAnimationFrame(updateProgress);
923
+ }
924
+ };
925
+ xhr.addEventListener("loadend", (() => {
926
+ this.dispatch("progress", {
927
+ progress: 100
928
+ });
861
929
  }));
930
+ requestAnimationFrame(updateProgress);
931
+ }
932
+ estimateResponseTime() {
933
+ const fileSize = this.file.size;
934
+ const MB = 1024 * 1024;
935
+ if (fileSize < MB) {
936
+ return 1e3;
937
+ } else if (fileSize < 10 * MB) {
938
+ return 2e3;
939
+ } else {
940
+ return 3e3 + fileSize / MB * 50;
941
+ }
862
942
  }
863
- directUploadDidComplete(error, attributes) {
943
+ directUploadDidComplete(error, attributes, resolve, reject) {
864
944
  if (error) {
865
- throw new Error(`Direct upload failed: ${error}`);
945
+ this.dispatchError(error, reject);
946
+ } else {
947
+ resolve({
948
+ sgid: attributes.attachable_sgid,
949
+ url: this.createBlobUrl(attributes.signed_id, attributes.filename)
950
+ });
951
+ this.dispatch("end");
866
952
  }
867
- this.attachment.setAttributes({
868
- sgid: attributes.attachable_sgid,
869
- url: this.createBlobUrl(attributes.signed_id, attributes.filename)
870
- });
871
953
  }
872
954
  createBlobUrl(signedId, filename) {
873
955
  return this.blobUrlTemplate.replace(":signed_id", signedId).replace(":filename", encodeURIComponent(filename));
874
956
  }
957
+ dispatch(name, detail = {}) {
958
+ detail.attachment = this.attachment;
959
+ return dispatchEvent(this.element, `direct-upload:${name}`, {
960
+ detail: detail
961
+ });
962
+ }
963
+ dispatchError(error, reject) {
964
+ const event = this.dispatch("error", {
965
+ error: error
966
+ });
967
+ if (!event.defaultPrevented) {
968
+ reject(error);
969
+ }
970
+ }
875
971
  get directUploadUrl() {
876
972
  return this.element.dataset.directUploadUrl;
877
973
  }
@@ -883,7 +979,11 @@ class AttachmentUpload {
883
979
  addEventListener("trix-attachment-add", (event => {
884
980
  const {attachment: attachment, target: target} = event;
885
981
  if (attachment.file) {
886
- const upload = new AttachmentUpload(attachment, target);
887
- upload.start();
982
+ const upload = new AttachmentUpload(attachment, target, attachment.file);
983
+ const onProgress = event => attachment.setUploadProgress(event.detail.progress);
984
+ target.addEventListener("direct-upload:progress", onProgress);
985
+ upload.start().then((attributes => attachment.setAttributes(attributes))).catch((error => alert(error))).finally((() => target.removeEventListener("direct-upload:progress", onProgress)));
888
986
  }
889
987
  }));
988
+
989
+ export { AttachmentUpload };
@@ -1,6 +1,7 @@
1
- (function(factory) {
2
- typeof define === "function" && define.amd ? define(factory) : factory();
3
- })((function() {
1
+ (function(global, factory) {
2
+ typeof exports === "object" && typeof module !== "undefined" ? factory(exports) : typeof define === "function" && define.amd ? define([ "exports" ], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self,
3
+ factory(global.ActionText = {}));
4
+ })(this, (function(exports) {
4
5
  "use strict";
5
6
  var sparkMd5 = {
6
7
  exports: {}
@@ -661,7 +662,7 @@
661
662
  }));
662
663
  }
663
664
  uploadRequestDidProgress(event) {
664
- const progress = event.loaded / event.total * 100;
665
+ const progress = event.loaded / event.total * 90;
665
666
  if (progress) {
666
667
  this.dispatch("progress", {
667
668
  progress: progress
@@ -696,6 +697,42 @@
696
697
  xhr: xhr
697
698
  });
698
699
  xhr.upload.addEventListener("progress", (event => this.uploadRequestDidProgress(event)));
700
+ xhr.upload.addEventListener("loadend", (() => {
701
+ this.simulateResponseProgress(xhr);
702
+ }));
703
+ }
704
+ simulateResponseProgress(xhr) {
705
+ let progress = 90;
706
+ const startTime = Date.now();
707
+ const updateProgress = () => {
708
+ const elapsed = Date.now() - startTime;
709
+ const estimatedResponseTime = this.estimateResponseTime();
710
+ const responseProgress = Math.min(elapsed / estimatedResponseTime, 1);
711
+ progress = 90 + responseProgress * 9;
712
+ this.dispatch("progress", {
713
+ progress: progress
714
+ });
715
+ if (xhr.readyState !== XMLHttpRequest.DONE && progress < 99) {
716
+ requestAnimationFrame(updateProgress);
717
+ }
718
+ };
719
+ xhr.addEventListener("loadend", (() => {
720
+ this.dispatch("progress", {
721
+ progress: 100
722
+ });
723
+ }));
724
+ requestAnimationFrame(updateProgress);
725
+ }
726
+ estimateResponseTime() {
727
+ const fileSize = this.file.size;
728
+ const MB = 1024 * 1024;
729
+ if (fileSize < MB) {
730
+ return 1e3;
731
+ } else if (fileSize < 10 * MB) {
732
+ return 2e3;
733
+ } else {
734
+ return 3e3 + fileSize / MB * 50;
735
+ }
699
736
  }
700
737
  }
701
738
  const inputSelector = "input[type=file][data-direct-upload-url]:not([disabled])";
@@ -819,32 +856,92 @@
819
856
  }
820
857
  setTimeout(autostart, 1);
821
858
  class AttachmentUpload {
822
- constructor(attachment, element) {
859
+ constructor(attachment, element, file = attachment.file) {
823
860
  this.attachment = attachment;
824
861
  this.element = element;
825
- this.directUpload = new DirectUpload(attachment.file, this.directUploadUrl, this);
862
+ this.directUpload = new DirectUpload(file, this.directUploadUrl, this);
863
+ this.file = file;
826
864
  }
827
865
  start() {
828
- this.directUpload.create(this.directUploadDidComplete.bind(this));
866
+ return new Promise(((resolve, reject) => {
867
+ this.directUpload.create(((error, attributes) => this.directUploadDidComplete(error, attributes, resolve, reject)));
868
+ this.dispatch("start");
869
+ }));
829
870
  }
830
871
  directUploadWillStoreFileWithXHR(xhr) {
831
872
  xhr.upload.addEventListener("progress", (event => {
832
- const progress = event.loaded / event.total * 100;
833
- this.attachment.setUploadProgress(progress);
873
+ const progress = event.loaded / event.total * 90;
874
+ if (progress) {
875
+ this.dispatch("progress", {
876
+ progress: progress
877
+ });
878
+ }
879
+ }));
880
+ xhr.upload.addEventListener("loadend", (() => {
881
+ this.simulateResponseProgress(xhr);
834
882
  }));
835
883
  }
836
- directUploadDidComplete(error, attributes) {
884
+ simulateResponseProgress(xhr) {
885
+ let progress = 90;
886
+ const startTime = Date.now();
887
+ const updateProgress = () => {
888
+ const elapsed = Date.now() - startTime;
889
+ const estimatedResponseTime = this.estimateResponseTime();
890
+ const responseProgress = Math.min(elapsed / estimatedResponseTime, 1);
891
+ progress = 90 + responseProgress * 9;
892
+ this.dispatch("progress", {
893
+ progress: progress
894
+ });
895
+ if (xhr.readyState !== XMLHttpRequest.DONE && progress < 99) {
896
+ requestAnimationFrame(updateProgress);
897
+ }
898
+ };
899
+ xhr.addEventListener("loadend", (() => {
900
+ this.dispatch("progress", {
901
+ progress: 100
902
+ });
903
+ }));
904
+ requestAnimationFrame(updateProgress);
905
+ }
906
+ estimateResponseTime() {
907
+ const fileSize = this.file.size;
908
+ const MB = 1024 * 1024;
909
+ if (fileSize < MB) {
910
+ return 1e3;
911
+ } else if (fileSize < 10 * MB) {
912
+ return 2e3;
913
+ } else {
914
+ return 3e3 + fileSize / MB * 50;
915
+ }
916
+ }
917
+ directUploadDidComplete(error, attributes, resolve, reject) {
837
918
  if (error) {
838
- throw new Error(`Direct upload failed: ${error}`);
919
+ this.dispatchError(error, reject);
920
+ } else {
921
+ resolve({
922
+ sgid: attributes.attachable_sgid,
923
+ url: this.createBlobUrl(attributes.signed_id, attributes.filename)
924
+ });
925
+ this.dispatch("end");
839
926
  }
840
- this.attachment.setAttributes({
841
- sgid: attributes.attachable_sgid,
842
- url: this.createBlobUrl(attributes.signed_id, attributes.filename)
843
- });
844
927
  }
845
928
  createBlobUrl(signedId, filename) {
846
929
  return this.blobUrlTemplate.replace(":signed_id", signedId).replace(":filename", encodeURIComponent(filename));
847
930
  }
931
+ dispatch(name, detail = {}) {
932
+ detail.attachment = this.attachment;
933
+ return dispatchEvent(this.element, `direct-upload:${name}`, {
934
+ detail: detail
935
+ });
936
+ }
937
+ dispatchError(error, reject) {
938
+ const event = this.dispatch("error", {
939
+ error: error
940
+ });
941
+ if (!event.defaultPrevented) {
942
+ reject(error);
943
+ }
944
+ }
848
945
  get directUploadUrl() {
849
946
  return this.element.dataset.directUploadUrl;
850
947
  }
@@ -855,8 +952,14 @@
855
952
  addEventListener("trix-attachment-add", (event => {
856
953
  const {attachment: attachment, target: target} = event;
857
954
  if (attachment.file) {
858
- const upload = new AttachmentUpload(attachment, target);
859
- upload.start();
955
+ const upload = new AttachmentUpload(attachment, target, attachment.file);
956
+ const onProgress = event => attachment.setUploadProgress(event.detail.progress);
957
+ target.addEventListener("direct-upload:progress", onProgress);
958
+ upload.start().then((attributes => attachment.setAttributes(attributes))).catch((error => alert(error))).finally((() => target.removeEventListener("direct-upload:progress", onProgress)));
860
959
  }
861
960
  }));
961
+ exports.AttachmentUpload = AttachmentUpload;
962
+ Object.defineProperty(exports, "__esModule", {
963
+ value: true
964
+ });
862
965
  }));
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "rails-html-sanitizer"
4
6
 
5
7
  module ActionText