actiontext 7.2.3.1 → 8.0.5.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4e2dd3aa47c3c3db0ba4862b790ab79ef2366e35202ecc096c8d27fc59d3e465
4
- data.tar.gz: bd0d682105f43d86301bf74e1607c9d581a8d30aacd1ac617e3e5f569422ad8b
3
+ metadata.gz: 522ad853a1ec43764311c8bb244b32d1364fe48323ae98c88e1137e2860cd685
4
+ data.tar.gz: b5194a64a3ce3f62d00cf3d3106df51cb0ad190b0abdf5f3ae9ee70b5eaca169
5
5
  SHA512:
6
- metadata.gz: 6dcfadb7d5d24626166e747610cc5170f0bad153349ba434d3884f3ce3fc84e18433483e68767550d63496d0613ced8306e6005fe305aab983b2b0211c0b74d7
7
- data.tar.gz: 147aad763b5e05de59e136853fbf16deb7d2f7c74f60900fcc46bd9c12850a727ab9847ed766f3165609fb03863765186137b521c48e55db4da334b9d8a8a4af
6
+ metadata.gz: 6b9fad1651151b53319b3428c974a7ce150823de6277124b1a7e3361c3bdde5c13f8332deef1d8597a65db4118d07c738aa7da261c696093e933bcb4763d7236
7
+ data.tar.gz: 76aac467811a5a31ac475ac87c86fbf4f7756d7464579bc51ba364869e6727154699d04554381f681962d7ab6821a6ce39ee2030c06c047e84b8f9d1539b741a
data/CHANGELOG.md CHANGED
@@ -1,100 +1,112 @@
1
- ## Rails 7.2.3.1 (March 23, 2026) ##
1
+ ## Rails 8.0.5.1 (July 29, 2026) ##
2
2
 
3
3
  * No changes.
4
4
 
5
5
 
6
- ## Rails 7.2.3 (October 28, 2025) ##
6
+ ## Rails 8.0.5 (March 24, 2026) ##
7
7
 
8
8
  * No changes.
9
9
 
10
10
 
11
- ## Rails 7.2.2.2 (August 13, 2025) ##
11
+ ## Rails 8.0.4.1 (March 23, 2026) ##
12
12
 
13
13
  * No changes.
14
14
 
15
15
 
16
- ## Rails 7.2.2.1 (December 10, 2024) ##
16
+ ## Rails 8.0.4 (October 28, 2025) ##
17
17
 
18
- * Update vendored trix version to 2.1.10
18
+ * No changes.
19
19
 
20
- *John Hawthorn*
21
20
 
21
+ ## Rails 8.0.3 (September 22, 2025) ##
22
+
23
+ * Add rollup-plugin-terser as a dev dependency.
22
24
 
23
- ## Rails 7.2.2 (October 30, 2024) ##
25
+ *Édouard Chin*
26
+
27
+
28
+ ## Rails 8.0.2.1 (August 13, 2025) ##
24
29
 
25
30
  * No changes.
26
31
 
27
32
 
28
- ## Rails 7.2.1.2 (October 23, 2024) ##
33
+ ## Rails 8.0.2 (March 12, 2025) ##
34
+
35
+ * No changes.
36
+
37
+ ## Rails 8.0.2 (March 12, 2025) ##
29
38
 
30
39
  * No changes.
31
40
 
32
41
 
33
- ## Rails 7.2.1.1 (October 15, 2024) ##
42
+ ## Rails 8.0.1 (December 13, 2024) ##
43
+
44
+ * No changes.
45
+
34
46
 
35
- * Avoid backtracing in plain_text_for_blockquote_node
47
+ ## Rails 8.0.0.1 (December 10, 2024) ##
36
48
 
37
- [CVE-2024-47888]
49
+ * Update vendored trix version to 2.1.10
38
50
 
39
51
  *John Hawthorn*
40
52
 
41
- ## Rails 7.2.1 (August 22, 2024) ##
42
53
 
43
- * Strip `content` attribute if the key is present but the value is empty
54
+ ## Rails 8.0.0 (November 07, 2024) ##
44
55
 
45
- *Jeremy Green*
56
+ * No changes.
46
57
 
47
58
 
48
- ## Rails 7.2.0 (August 09, 2024) ##
49
- * Only sanitize `content` attribute when present in attachments.
59
+ ## Rails 8.0.0.rc2 (October 30, 2024) ##
50
60
 
51
- *Petrik de Heus*
61
+ * No changes.
52
62
 
53
- * Sanitize ActionText HTML ContentAttachment in Trix edit view
54
- [CVE-2024-32464]
55
63
 
56
- *Aaron Patterson*, *Zack Deveau*
64
+ ## Rails 8.0.0.rc1 (October 19, 2024) ##
57
65
 
58
- * Use `includes` instead of `eager_load` for `with_all_rich_text`.
66
+ * No changes.
59
67
 
60
- *Petrik de Heus*
61
68
 
62
- * Delegate `ActionText::Content#deconstruct` to `Nokogiri::XML::DocumentFragment#elements`.
69
+ ## Rails 8.0.0.beta1 (September 26, 2024) ##
63
70
 
64
- ```ruby
65
- content = ActionText::Content.new <<~HTML
66
- <h1>Hello, world</h1>
71
+ * Dispatch direct-upload events on attachment uploads
67
72
 
68
- <div>The body</div>
69
- HTML
73
+ When using Action Text's rich textarea, it's possible to attach files to the
74
+ editor. Previously, that action didn't dispatch any events, which made it hard
75
+ to react to the file uploads. For instance, if an upload failed, there was no
76
+ way to notify the user about it, or remove the attachment from the editor.
70
77
 
71
- content => [h1, div]
78
+ This commits adds new events - `direct-upload:start`, `direct-upload:progress`,
79
+ and `direct-upload:end` - similar to how Active Storage's direct uploads work.
72
80
 
73
- assert_pattern { h1 => { content: "Hello, world" } }
74
- assert_pattern { div => { content: "The body" } }
75
- ```
81
+ *Matheus Richard*, *Brad Rees*
76
82
 
77
- *Sean Doyle*
83
+ * Add `store_if_blank` option to `has_rich_text`
78
84
 
79
- * Fix all Action Text database related models to respect
80
- `ActiveRecord::Base.table_name_prefix` configuration.
85
+ Pass `store_if_blank: false` to not create `ActionText::RichText` records when saving with a blank attribute, such as from an optional form parameter.
81
86
 
82
- *Chedli Bourguiba*
87
+ ```ruby
88
+ class Message
89
+ has_rich_text :content, store_if_blank: false
90
+ end
91
+
92
+ Message.create(content: "hi") # creates an ActionText::RichText
93
+ Message.create(content: "") # does not create an ActionText::RichText
94
+ ```
83
95
 
84
- * Compile ESM package that can be used directly in the browser as actiontext.esm.js
96
+ *Alex Ghiculescu*
85
97
 
86
- *Matias Grunberg*
98
+ * Strip `content` attribute if the key is present but the value is empty
87
99
 
88
- * Fix using actiontext.js with Sprockets.
100
+ *Jeremy Green*
89
101
 
90
- *Matias Grunberg*
102
+ * Rename `rich_text_area` methods into `rich_textarea`
91
103
 
92
- * Upgrade Trix to 2.0.7
104
+ Old names are still available as aliases.
93
105
 
94
- *Hartley McGuire*
106
+ *Sean Doyle*
95
107
 
96
- * Fix using Trix with Sprockets.
108
+ * Only sanitize `content` attribute when present in attachments.
97
109
 
98
- *Hartley McGuire*
110
+ *Petrik de Heus*
99
111
 
100
- Please check [7-1-stable](https://github.com/rails/rails/blob/7-1-stable/actiontext/CHANGELOG.md) for previous changes.
112
+ Please check [7-2-stable](https://github.com/rails/rails/blob/7-2-stable/actiontext/CHANGELOG.md) for previous changes.
@@ -853,25 +853,47 @@ class AttachmentUpload {
853
853
  }
854
854
  start() {
855
855
  this.directUpload.create(this.directUploadDidComplete.bind(this));
856
+ this.dispatch("start");
856
857
  }
857
858
  directUploadWillStoreFileWithXHR(xhr) {
858
859
  xhr.upload.addEventListener("progress", (event => {
859
860
  const progress = event.loaded / event.total * 100;
860
861
  this.attachment.setUploadProgress(progress);
862
+ if (progress) {
863
+ this.dispatch("progress", {
864
+ progress: progress
865
+ });
866
+ }
861
867
  }));
862
868
  }
863
869
  directUploadDidComplete(error, attributes) {
864
870
  if (error) {
865
- throw new Error(`Direct upload failed: ${error}`);
871
+ this.dispatchError(error);
872
+ } else {
873
+ this.attachment.setAttributes({
874
+ sgid: attributes.attachable_sgid,
875
+ url: this.createBlobUrl(attributes.signed_id, attributes.filename)
876
+ });
877
+ this.dispatch("end");
866
878
  }
867
- this.attachment.setAttributes({
868
- sgid: attributes.attachable_sgid,
869
- url: this.createBlobUrl(attributes.signed_id, attributes.filename)
870
- });
871
879
  }
872
880
  createBlobUrl(signedId, filename) {
873
881
  return this.blobUrlTemplate.replace(":signed_id", signedId).replace(":filename", encodeURIComponent(filename));
874
882
  }
883
+ dispatch(name, detail = {}) {
884
+ detail.attachment = this.attachment;
885
+ return dispatchEvent(this.element, `direct-upload:${name}`, {
886
+ detail: detail
887
+ });
888
+ }
889
+ dispatchError(error) {
890
+ const event = this.dispatch("error", {
891
+ error: error
892
+ });
893
+ if (!event.defaultPrevented) {
894
+ alert(error);
895
+ }
896
+ }
875
897
  get directUploadUrl() {
876
898
  return this.element.dataset.directUploadUrl;
877
899
  }
@@ -826,25 +826,47 @@
826
826
  }
827
827
  start() {
828
828
  this.directUpload.create(this.directUploadDidComplete.bind(this));
829
+ this.dispatch("start");
829
830
  }
830
831
  directUploadWillStoreFileWithXHR(xhr) {
831
832
  xhr.upload.addEventListener("progress", (event => {
832
833
  const progress = event.loaded / event.total * 100;
833
834
  this.attachment.setUploadProgress(progress);
835
+ if (progress) {
836
+ this.dispatch("progress", {
837
+ progress: progress
838
+ });
839
+ }
834
840
  }));
835
841
  }
836
842
  directUploadDidComplete(error, attributes) {
837
843
  if (error) {
838
- throw new Error(`Direct upload failed: ${error}`);
844
+ this.dispatchError(error);
845
+ } else {
846
+ this.attachment.setAttributes({
847
+ sgid: attributes.attachable_sgid,
848
+ url: this.createBlobUrl(attributes.signed_id, attributes.filename)
849
+ });
850
+ this.dispatch("end");
839
851
  }
840
- this.attachment.setAttributes({
841
- sgid: attributes.attachable_sgid,
842
- url: this.createBlobUrl(attributes.signed_id, attributes.filename)
843
- });
844
852
  }
845
853
  createBlobUrl(signedId, filename) {
846
854
  return this.blobUrlTemplate.replace(":signed_id", signedId).replace(":filename", encodeURIComponent(filename));
847
855
  }
856
+ dispatch(name, detail = {}) {
857
+ detail.attachment = this.attachment;
858
+ return dispatchEvent(this.element, `direct-upload:${name}`, {
859
+ detail: detail
860
+ });
861
+ }
862
+ dispatchError(error) {
863
+ const event = this.dispatch("error", {
864
+ error: error
865
+ });
866
+ if (!event.defaultPrevented) {
867
+ alert(error);
868
+ }
869
+ }
848
870
  get directUploadUrl() {
849
871
  return this.element.dataset.directUploadUrl;
850
872
  }
@@ -1,5 +1,5 @@
1
1
  /*
2
- Trix 2.1.10
2
+ Trix 2.1.12
3
3
  Copyright © 2024 37signals, LLC
4
4
  */
5
5
  (function (global, factory) {
@@ -9,7 +9,7 @@ Copyright © 2024 37signals, LLC
9
9
  })(this, (function () { 'use strict';
10
10
 
11
11
  var name = "trix";
12
- var version = "2.1.10";
12
+ var version = "2.1.12";
13
13
  var description = "A rich text editor for everyday writing";
14
14
  var main = "dist/trix.umd.min.js";
15
15
  var module = "dist/trix.esm.min.js";
@@ -44,6 +44,7 @@ Copyright © 2024 37signals, LLC
44
44
  "@rollup/plugin-node-resolve": "^13.3.0",
45
45
  "@web/dev-server": "^0.1.34",
46
46
  "babel-eslint": "^10.1.0",
47
+ chokidar: "^4.0.2",
47
48
  concurrently: "^7.4.0",
48
49
  eslint: "^7.32.0",
49
50
  esm: "^3.2.25",
@@ -51,12 +52,12 @@ Copyright © 2024 37signals, LLC
51
52
  "karma-chrome-launcher": "3.2.0",
52
53
  "karma-qunit": "^4.1.2",
53
54
  "karma-sauce-launcher": "^4.3.6",
54
- "node-sass": "^7.0.1",
55
55
  qunit: "2.19.1",
56
56
  rangy: "^1.3.0",
57
57
  rollup: "^2.56.3",
58
58
  "rollup-plugin-includepaths": "^0.2.4",
59
59
  "rollup-plugin-terser": "^7.0.2",
60
+ sass: "^1.83.0",
60
61
  svgo: "^2.8.0",
61
62
  webdriverio: "^7.19.5"
62
63
  };
@@ -64,7 +65,7 @@ Copyright © 2024 37signals, LLC
64
65
  webdriverio: "^7.19.5"
65
66
  };
66
67
  var scripts = {
67
- "build-css": "node-sass --functions=./assets/trix/stylesheets/functions assets/trix.scss dist/trix.css",
68
+ "build-css": "bin/sass-build assets/trix.scss dist/trix.css",
68
69
  "build-js": "rollup -c",
69
70
  "build-assets": "cp -f assets/*.html dist/",
70
71
  build: "yarn run build-js && yarn run build-css && yarn run build-assets",
@@ -209,6 +210,12 @@ Copyright © 2024 37signals, LLC
209
210
  attachmentGallery: "attachment-gallery"
210
211
  };
211
212
 
213
+ var dompurify = {
214
+ ADD_ATTR: ["language"],
215
+ SAFE_FOR_XML: false,
216
+ RETURN_DOM: true
217
+ };
218
+
212
219
  var lang$1 = {
213
220
  attachFiles: "Attach Files",
214
221
  bold: "Bold",
@@ -631,7 +638,7 @@ Copyright © 2024 37signals, LLC
631
638
 
632
639
  var toolbar = {
633
640
  getDefaultHTML() {
634
- return "<div class=\"trix-button-row\">\n <span class=\"trix-button-group trix-button-group--text-tools\" data-trix-button-group=\"text-tools\">\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-bold\" data-trix-attribute=\"bold\" data-trix-key=\"b\" title=\"".concat(lang$1.bold, "\" tabindex=\"-1\">").concat(lang$1.bold, "</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-italic\" data-trix-attribute=\"italic\" data-trix-key=\"i\" title=\"").concat(lang$1.italic, "\" tabindex=\"-1\">").concat(lang$1.italic, "</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-strike\" data-trix-attribute=\"strike\" title=\"").concat(lang$1.strike, "\" tabindex=\"-1\">").concat(lang$1.strike, "</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-link\" data-trix-attribute=\"href\" data-trix-action=\"link\" data-trix-key=\"k\" title=\"").concat(lang$1.link, "\" tabindex=\"-1\">").concat(lang$1.link, "</button>\n </span>\n\n <span class=\"trix-button-group trix-button-group--block-tools\" data-trix-button-group=\"block-tools\">\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-heading-1\" data-trix-attribute=\"heading1\" title=\"").concat(lang$1.heading1, "\" tabindex=\"-1\">").concat(lang$1.heading1, "</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-quote\" data-trix-attribute=\"quote\" title=\"").concat(lang$1.quote, "\" tabindex=\"-1\">").concat(lang$1.quote, "</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-code\" data-trix-attribute=\"code\" title=\"").concat(lang$1.code, "\" tabindex=\"-1\">").concat(lang$1.code, "</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-bullet-list\" data-trix-attribute=\"bullet\" title=\"").concat(lang$1.bullets, "\" tabindex=\"-1\">").concat(lang$1.bullets, "</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-number-list\" data-trix-attribute=\"number\" title=\"").concat(lang$1.numbers, "\" tabindex=\"-1\">").concat(lang$1.numbers, "</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-decrease-nesting-level\" data-trix-action=\"decreaseNestingLevel\" title=\"").concat(lang$1.outdent, "\" tabindex=\"-1\">").concat(lang$1.outdent, "</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-increase-nesting-level\" data-trix-action=\"increaseNestingLevel\" title=\"").concat(lang$1.indent, "\" tabindex=\"-1\">").concat(lang$1.indent, "</button>\n </span>\n\n <span class=\"trix-button-group trix-button-group--file-tools\" data-trix-button-group=\"file-tools\">\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-attach\" data-trix-action=\"attachFiles\" title=\"").concat(lang$1.attachFiles, "\" tabindex=\"-1\">").concat(lang$1.attachFiles, "</button>\n </span>\n\n <span class=\"trix-button-group-spacer\"></span>\n\n <span class=\"trix-button-group trix-button-group--history-tools\" data-trix-button-group=\"history-tools\">\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-undo\" data-trix-action=\"undo\" data-trix-key=\"z\" title=\"").concat(lang$1.undo, "\" tabindex=\"-1\">").concat(lang$1.undo, "</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-redo\" data-trix-action=\"redo\" data-trix-key=\"shift+z\" title=\"").concat(lang$1.redo, "\" tabindex=\"-1\">").concat(lang$1.redo, "</button>\n </span>\n </div>\n\n <div class=\"trix-dialogs\" data-trix-dialogs>\n <div class=\"trix-dialog trix-dialog--link\" data-trix-dialog=\"href\" data-trix-dialog-attribute=\"href\">\n <div class=\"trix-dialog__link-fields\">\n <input type=\"url\" name=\"href\" class=\"trix-input trix-input--dialog\" placeholder=\"").concat(lang$1.urlPlaceholder, "\" aria-label=\"").concat(lang$1.url, "\" required data-trix-input>\n <div class=\"trix-button-group\">\n <input type=\"button\" class=\"trix-button trix-button--dialog\" value=\"").concat(lang$1.link, "\" data-trix-method=\"setAttribute\">\n <input type=\"button\" class=\"trix-button trix-button--dialog\" value=\"").concat(lang$1.unlink, "\" data-trix-method=\"removeAttribute\">\n </div>\n </div>\n </div>\n </div>");
641
+ return "<div class=\"trix-button-row\">\n <span class=\"trix-button-group trix-button-group--text-tools\" data-trix-button-group=\"text-tools\">\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-bold\" data-trix-attribute=\"bold\" data-trix-key=\"b\" title=\"".concat(lang$1.bold, "\" tabindex=\"-1\">").concat(lang$1.bold, "</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-italic\" data-trix-attribute=\"italic\" data-trix-key=\"i\" title=\"").concat(lang$1.italic, "\" tabindex=\"-1\">").concat(lang$1.italic, "</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-strike\" data-trix-attribute=\"strike\" title=\"").concat(lang$1.strike, "\" tabindex=\"-1\">").concat(lang$1.strike, "</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-link\" data-trix-attribute=\"href\" data-trix-action=\"link\" data-trix-key=\"k\" title=\"").concat(lang$1.link, "\" tabindex=\"-1\">").concat(lang$1.link, "</button>\n </span>\n\n <span class=\"trix-button-group trix-button-group--block-tools\" data-trix-button-group=\"block-tools\">\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-heading-1\" data-trix-attribute=\"heading1\" title=\"").concat(lang$1.heading1, "\" tabindex=\"-1\">").concat(lang$1.heading1, "</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-quote\" data-trix-attribute=\"quote\" title=\"").concat(lang$1.quote, "\" tabindex=\"-1\">").concat(lang$1.quote, "</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-code\" data-trix-attribute=\"code\" title=\"").concat(lang$1.code, "\" tabindex=\"-1\">").concat(lang$1.code, "</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-bullet-list\" data-trix-attribute=\"bullet\" title=\"").concat(lang$1.bullets, "\" tabindex=\"-1\">").concat(lang$1.bullets, "</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-number-list\" data-trix-attribute=\"number\" title=\"").concat(lang$1.numbers, "\" tabindex=\"-1\">").concat(lang$1.numbers, "</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-decrease-nesting-level\" data-trix-action=\"decreaseNestingLevel\" title=\"").concat(lang$1.outdent, "\" tabindex=\"-1\">").concat(lang$1.outdent, "</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-increase-nesting-level\" data-trix-action=\"increaseNestingLevel\" title=\"").concat(lang$1.indent, "\" tabindex=\"-1\">").concat(lang$1.indent, "</button>\n </span>\n\n <span class=\"trix-button-group trix-button-group--file-tools\" data-trix-button-group=\"file-tools\">\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-attach\" data-trix-action=\"attachFiles\" title=\"").concat(lang$1.attachFiles, "\" tabindex=\"-1\">").concat(lang$1.attachFiles, "</button>\n </span>\n\n <span class=\"trix-button-group-spacer\"></span>\n\n <span class=\"trix-button-group trix-button-group--history-tools\" data-trix-button-group=\"history-tools\">\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-undo\" data-trix-action=\"undo\" data-trix-key=\"z\" title=\"").concat(lang$1.undo, "\" tabindex=\"-1\">").concat(lang$1.undo, "</button>\n <button type=\"button\" class=\"trix-button trix-button--icon trix-button--icon-redo\" data-trix-action=\"redo\" data-trix-key=\"shift+z\" title=\"").concat(lang$1.redo, "\" tabindex=\"-1\">").concat(lang$1.redo, "</button>\n </span>\n </div>\n\n <div class=\"trix-dialogs\" data-trix-dialogs>\n <div class=\"trix-dialog trix-dialog--link\" data-trix-dialog=\"href\" data-trix-dialog-attribute=\"href\">\n <div class=\"trix-dialog__link-fields\">\n <input type=\"url\" name=\"href\" class=\"trix-input trix-input--dialog\" placeholder=\"").concat(lang$1.urlPlaceholder, "\" aria-label=\"").concat(lang$1.url, "\" data-trix-validate-href required data-trix-input>\n <div class=\"trix-button-group\">\n <input type=\"button\" class=\"trix-button trix-button--dialog\" value=\"").concat(lang$1.link, "\" data-trix-method=\"setAttribute\">\n <input type=\"button\" class=\"trix-button trix-button--dialog\" value=\"").concat(lang$1.unlink, "\" data-trix-method=\"removeAttribute\">\n </div>\n </div>\n </div>\n </div>");
635
642
  }
636
643
  };
637
644
 
@@ -645,6 +652,7 @@ Copyright © 2024 37signals, LLC
645
652
  blockAttributes: attributes,
646
653
  browser: browser$1,
647
654
  css: css$3,
655
+ dompurify: dompurify,
648
656
  fileSize: file_size_formatting,
649
657
  input: input,
650
658
  keyNames: key_names,
@@ -3064,6 +3072,12 @@ $\
3064
3072
  }
3065
3073
  var purify = createDOMPurify();
3066
3074
 
3075
+ purify.addHook("uponSanitizeAttribute", function (node, data) {
3076
+ const allowedAttributePattern = /^data-trix-/;
3077
+ if (allowedAttributePattern.test(data.attrName)) {
3078
+ data.forceKeepAttr = true;
3079
+ }
3080
+ });
3067
3081
  const DEFAULT_ALLOWED_ATTRIBUTES = "style href src width height language class".split(" ");
3068
3082
  const DEFAULT_FORBIDDEN_PROTOCOLS = "javascript:".split(" ");
3069
3083
  const DEFAULT_FORBIDDEN_ELEMENTS = "script iframe form noscript".split(" ");
@@ -3093,10 +3107,9 @@ $\
3093
3107
  sanitize() {
3094
3108
  this.sanitizeElements();
3095
3109
  this.normalizeListElementNesting();
3096
- return purify.sanitize(this.body, {
3097
- ADD_ATTR: ["language"],
3098
- RETURN_DOM: true
3099
- });
3110
+ purify.setConfig(dompurify);
3111
+ this.body = purify.sanitize(this.body);
3112
+ return this.body;
3100
3113
  }
3101
3114
  getHTML() {
3102
3115
  return this.body.innerHTML;
@@ -12626,16 +12639,26 @@ $\
12626
12639
  return (_this$delegate6 = this.delegate) === null || _this$delegate6 === void 0 ? void 0 : _this$delegate6.toolbarDidShowDialog(dialogName);
12627
12640
  }
12628
12641
  setAttribute(dialogElement) {
12642
+ var _this$delegate7;
12629
12643
  const attributeName = getAttributeName(dialogElement);
12630
12644
  const input = getInputForDialog(dialogElement, attributeName);
12631
- if (input.willValidate && !input.checkValidity()) {
12632
- input.setAttribute("data-trix-validate", "");
12633
- input.classList.add("trix-validate");
12634
- return input.focus();
12645
+ if (input.willValidate) {
12646
+ input.setCustomValidity("");
12647
+ if (!input.checkValidity() || !this.isSafeAttribute(input)) {
12648
+ input.setCustomValidity("Invalid value");
12649
+ input.setAttribute("data-trix-validate", "");
12650
+ input.classList.add("trix-validate");
12651
+ return input.focus();
12652
+ }
12653
+ }
12654
+ (_this$delegate7 = this.delegate) === null || _this$delegate7 === void 0 || _this$delegate7.toolbarDidUpdateAttribute(attributeName, input.value);
12655
+ return this.hideDialog();
12656
+ }
12657
+ isSafeAttribute(input) {
12658
+ if (input.hasAttribute("data-trix-validate-href")) {
12659
+ return purify.isValidAttribute("a", "href", input.value);
12635
12660
  } else {
12636
- var _this$delegate7;
12637
- (_this$delegate7 = this.delegate) === null || _this$delegate7 === void 0 || _this$delegate7.toolbarDidUpdateAttribute(attributeName, input.value);
12638
- return this.hideDialog();
12661
+ return true;
12639
12662
  }
12640
12663
  }
12641
12664
  removeAttribute(dialogElement) {