actiontext 7.1.3 → 7.2.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +37 -73
  3. data/app/assets/javascripts/trix.js +92 -30
  4. data/app/assets/stylesheets/trix.css +3 -1
  5. data/app/helpers/action_text/content_helper.rb +11 -0
  6. data/app/helpers/action_text/tag_helper.rb +38 -28
  7. data/app/models/action_text/encrypted_rich_text.rb +2 -2
  8. data/app/models/action_text/record.rb +2 -0
  9. data/app/models/action_text/rich_text.rb +58 -26
  10. data/db/migrate/20180528164100_create_action_text_tables.rb +1 -1
  11. data/lib/action_text/attachable.rb +35 -33
  12. data/lib/action_text/attachables/content_attachment.rb +2 -0
  13. data/lib/action_text/attachables/missing_attachable.rb +2 -0
  14. data/lib/action_text/attachables/remote_image.rb +2 -0
  15. data/lib/action_text/attachment.rb +27 -25
  16. data/lib/action_text/attachment_gallery.rb +2 -0
  17. data/lib/action_text/attachments/caching.rb +2 -0
  18. data/lib/action_text/attachments/minification.rb +2 -0
  19. data/lib/action_text/attachments/trix_conversion.rb +2 -0
  20. data/lib/action_text/attribute.rb +36 -22
  21. data/lib/action_text/content.rb +51 -27
  22. data/lib/action_text/deprecator.rb +2 -0
  23. data/lib/action_text/encryption.rb +2 -0
  24. data/lib/action_text/engine.rb +2 -0
  25. data/lib/action_text/fixture_set.rb +34 -34
  26. data/lib/action_text/fragment.rb +4 -0
  27. data/lib/action_text/gem_version.rb +6 -4
  28. data/lib/action_text/html_conversion.rb +2 -0
  29. data/lib/action_text/plain_text_conversion.rb +8 -1
  30. data/lib/action_text/rendering.rb +2 -0
  31. data/lib/action_text/serialization.rb +2 -0
  32. data/lib/action_text/system_test_helper.rb +20 -17
  33. data/lib/action_text/trix_attachment.rb +2 -0
  34. data/lib/action_text/version.rb +3 -1
  35. data/lib/action_text.rb +1 -1
  36. data/lib/generators/action_text/install/install_generator.rb +10 -3
  37. data/lib/rails/generators/test_unit/install_generator.rb +2 -0
  38. data/package.json +2 -2
  39. metadata +18 -18
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4313fb0db4c57a41976e0dd0d8311235e32fcd966c49c4d5da1fc76ccf3a3c19
4
- data.tar.gz: 1c6f538ca06525f027cee23bfb76b301ae6ca8c5737035eac7756ac420ff82a3
3
+ metadata.gz: dff22ea29340985c645f24023a493f071bb20b46bf7219adce5116af1cb2ce09
4
+ data.tar.gz: e8d8db93776bf73f40814736dc238d5643b62434b85ddcffe1c0d9d096d1c940
5
5
  SHA512:
6
- metadata.gz: 6c9da506c6f8c7516ae80bab515e709abb29f1730ff7c8ff6e4b5d8bb14d44cd10c168e674951a48e6aeffcf8b36b6877a6e7e14a8bdeae7fdf246e560c0ea30
7
- data.tar.gz: 8c30ed4e1f0df31e2296e973536f4a30712e280e4dee146d9b5eade3945c37e52078c7685db22f5e943b8c2d38a090ea61d76619392fdddb075fcde29e1cc567
6
+ metadata.gz: 3e6e30b5e160f1f7a3475653fd2cafca61e1ddf94320a5937cb8afe2d58feaca027885a37260f2fe96840433428a4b77f8a69435481d24eec27c3b0e9e82e407
7
+ data.tar.gz: 827a4e32168d54371c23143c469674421217b6411bedb180e7c639e643b500f44236afbf47996a82d7f5b09559838c032aaa1c296b4444265a979b15b7fcb7be
data/CHANGELOG.md CHANGED
@@ -1,102 +1,66 @@
1
- ## Rails 7.1.3 (January 16, 2024) ##
1
+ ## Rails 7.2.1.1 (October 15, 2024) ##
2
2
 
3
- * No changes.
3
+ * Avoid backtracing in plain_text_for_blockquote_node
4
4
 
5
+ [CVE-2024-47888]
5
6
 
6
- ## Rails 7.1.2 (November 10, 2023) ##
7
+ ## Rails 7.2.1 (August 22, 2024) ##
7
8
 
8
- * Compile ESM package that can be used directly in the browser as `actiontext.esm.js`.
9
-
10
- *Matias Grunberg*
11
-
12
- * Fix using actiontext.js with Sprockets.
13
-
14
- *Matias Grunberg*
15
-
16
- * Upgrade Trix to 2.0.7.
17
-
18
- *Hartley McGuire*
19
-
20
- * Fix using Trix with Sprockets.
21
-
22
- *Hartley McGuire*
23
-
24
-
25
- ## Rails 7.1.1 (October 11, 2023) ##
26
-
27
- * No changes.
9
+ * Strip `content` attribute if the key is present but the value is empty
28
10
 
11
+ *Jeremy Green*
29
12
 
30
- ## Rails 7.1.0 (October 05, 2023) ##
31
13
 
32
- * No changes.
14
+ ## Rails 7.2.0 (August 09, 2024) ##
15
+ * Only sanitize `content` attribute when present in attachments.
33
16
 
17
+ *Petrik de Heus*
34
18
 
35
- ## Rails 7.1.0.rc2 (October 01, 2023) ##
19
+ * Sanitize ActionText HTML ContentAttachment in Trix edit view
20
+ [CVE-2024-32464]
36
21
 
37
- * No changes.
22
+ *Aaron Patterson*, *Zack Deveau*
38
23
 
24
+ * Use `includes` instead of `eager_load` for `with_all_rich_text`.
39
25
 
40
- ## Rails 7.1.0.rc1 (September 27, 2023) ##
26
+ *Petrik de Heus*
41
27
 
42
- * No changes.
28
+ * Delegate `ActionText::Content#deconstruct` to `Nokogiri::XML::DocumentFragment#elements`.
43
29
 
30
+ ```ruby
31
+ content = ActionText::Content.new <<~HTML
32
+ <h1>Hello, world</h1>
44
33
 
45
- ## Rails 7.1.0.beta1 (September 13, 2023) ##
34
+ <div>The body</div>
35
+ HTML
46
36
 
47
- * Use `Rails::HTML5::SafeListSanitizer` by default in the Rails 7.1 configuration if it is
48
- supported.
37
+ content => [h1, div]
49
38
 
50
- Action Text's sanitizer can be configured by setting
51
- `config.action_text.sanitizer_vendor`. Supported values are `Rails::HTML4::Sanitizer` or
52
- `Rails::HTML5::Sanitizer`.
39
+ assert_pattern { h1 => { content: "Hello, world" } }
40
+ assert_pattern { div => { content: "The body" } }
41
+ ```
53
42
 
54
- The Rails 7.1 configuration will set this to `Rails::HTML5::Sanitizer` when it is supported, and
55
- fall back to `Rails::HTML4::Sanitizer`. Previous configurations default to
56
- `Rails::HTML4::Sanitizer`.
57
-
58
- As a result of this change, the defaults for `ActionText::ContentHelper.allowed_tags` and
59
- `.allowed_attributes` are applied at runtime, so the value of these attributes is now 'nil'
60
- unless set by the application. You may call `sanitizer_allowed_tags` or
61
- `sanitizer_allowed_attributes` to inspect the tags and attributes being allowed by the
62
- sanitizer.
63
-
64
- *Mike Dalessio*
65
-
66
- * Attachables now can override default attachment missing template.
67
-
68
- When rendering Action Text attachments where the underlying attachable model has
69
- been removed, a fallback template is used. You now can override this template on
70
- a per-model basis. For example, you could render a placeholder image for a file
71
- attachment or the text "Deleted User" for a User attachment.
72
-
73
- *Matt Swanson*, *Joel Drapper*
74
-
75
- * Update bundled Trix version from `1.3.1` to `2.0.4`.
76
-
77
- *Sarah Ridge*, *Sean Doyle*
43
+ *Sean Doyle*
78
44
 
79
- * Apply `field_error_proc` to `rich_text_area` form fields.
45
+ * Fix all Action Text database related models to respect
46
+ `ActiveRecord::Base.table_name_prefix` configuration.
80
47
 
81
- *Kaíque Kandy Koga*
48
+ *Chedli Bourguiba*
82
49
 
83
- * Action Text attachment URLs rendered in a background job (a la Turbo
84
- Streams) now use `Rails.application.default_url_options` and
85
- `Rails.application.config.force_ssl` instead of `http://example.org`.
50
+ * Compile ESM package that can be used directly in the browser as actiontext.esm.js
86
51
 
87
- *Jonathan Hefner*
52
+ *Matias Grunberg*
88
53
 
89
- * Support `strict_loading:` option for `has_rich_text` declaration
54
+ * Fix using actiontext.js with Sprockets.
90
55
 
91
- *Sean Doyle*
56
+ *Matias Grunberg*
92
57
 
93
- * Update ContentAttachment so that it can encapsulate arbitrary HTML content in a document.
58
+ * Upgrade Trix to 2.0.7
94
59
 
95
- *Jamis Buck*
60
+ *Hartley McGuire*
96
61
 
97
- * Fix an issue that caused the content layout to render multiple times when a
98
- rich_text field was updated.
62
+ * Fix using Trix with Sprockets.
99
63
 
100
- *Jacob Herrington*
64
+ *Hartley McGuire*
101
65
 
102
- Please check [7-0-stable](https://github.com/rails/rails/blob/7-0-stable/actiontext/CHANGELOG.md) for previous changes.
66
+ Please check [7-1-stable](https://github.com/rails/rails/blob/7-1-stable/actiontext/CHANGELOG.md) for previous changes.
@@ -1,6 +1,6 @@
1
1
  /*
2
- Trix 2.0.7
3
- Copyright © 2023 37signals, LLC
2
+ Trix 2.1.1
3
+ Copyright © 2024 37signals, LLC
4
4
  */
5
5
  (function (global, factory) {
6
6
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
@@ -9,7 +9,7 @@ Copyright © 2023 37signals, LLC
9
9
  })(this, (function () { 'use strict';
10
10
 
11
11
  var name = "trix";
12
- var version = "2.0.7";
12
+ var version = "2.1.1";
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";
@@ -17,6 +17,7 @@ Copyright © 2023 37signals, LLC
17
17
  var files = [
18
18
  "dist/*.css",
19
19
  "dist/*.js",
20
+ "dist/*.map",
20
21
  "src/{inspector,trix}/*.js"
21
22
  ];
22
23
  var repository = {
@@ -130,6 +131,7 @@ Copyright © 2023 37signals, LLC
130
131
  code: {
131
132
  tagName: "pre",
132
133
  terminal: true,
134
+ htmlAttributes: ["language"],
133
135
  text: {
134
136
  plaintext: true
135
137
  }
@@ -1215,7 +1217,7 @@ $\
1215
1217
  no-useless-escape,
1216
1218
  */
1217
1219
  const normalizeSpaces = string => string.replace(new RegExp("".concat(ZERO_WIDTH_SPACE), "g"), "").replace(new RegExp("".concat(NON_BREAKING_SPACE), "g"), " ");
1218
- const normalizeNewlines = string => string.replace(/\r\n/g, "\n");
1220
+ const normalizeNewlines = string => string.replace(/\r\n?/g, "\n");
1219
1221
  const breakableWhitespacePattern = new RegExp("[^\\S".concat(NON_BREAKING_SPACE, "]"));
1220
1222
  const squishBreakableWhitespace = string => string
1221
1223
  // Replace all breakable whitespace characters with a space
@@ -2144,20 +2146,28 @@ $\
2144
2146
  }
2145
2147
  }
2146
2148
  createContainerElement(depth) {
2147
- let attributes, className;
2149
+ const attributes = {};
2150
+ let className;
2148
2151
  const attributeName = this.attributes[depth];
2149
2152
  const {
2150
- tagName
2153
+ tagName,
2154
+ htmlAttributes = []
2151
2155
  } = getBlockConfig(attributeName);
2152
2156
  if (depth === 0 && this.block.isRTL()) {
2153
- attributes = {
2157
+ Object.assign(attributes, {
2154
2158
  dir: "rtl"
2155
- };
2159
+ });
2156
2160
  }
2157
2161
  if (attributeName === "attachmentGallery") {
2158
2162
  const size = this.block.getBlockBreakPosition();
2159
2163
  className = "".concat(css$1.attachmentGallery, " ").concat(css$1.attachmentGallery, "--").concat(size);
2160
2164
  }
2165
+ Object.entries(this.block.htmlAttributes).forEach(_ref => {
2166
+ let [name, value] = _ref;
2167
+ if (htmlAttributes.includes(name)) {
2168
+ attributes[name] = value;
2169
+ }
2170
+ });
2161
2171
  return makeElement({
2162
2172
  tagName,
2163
2173
  className,
@@ -5828,28 +5838,29 @@ $\
5828
5838
  class Block extends TrixObject {
5829
5839
  static fromJSON(blockJSON) {
5830
5840
  const text = Text.fromJSON(blockJSON.text);
5831
- return new this(text, blockJSON.attributes);
5841
+ return new this(text, blockJSON.attributes, blockJSON.htmlAttributes);
5832
5842
  }
5833
- constructor(text, attributes) {
5843
+ constructor(text, attributes, htmlAttributes) {
5834
5844
  super(...arguments);
5835
5845
  this.text = applyBlockBreakToText(text || new Text());
5836
5846
  this.attributes = attributes || [];
5847
+ this.htmlAttributes = htmlAttributes || {};
5837
5848
  }
5838
5849
  isEmpty() {
5839
5850
  return this.text.isBlockBreak();
5840
5851
  }
5841
5852
  isEqualTo(block) {
5842
5853
  if (super.isEqualTo(block)) return true;
5843
- return this.text.isEqualTo(block === null || block === void 0 ? void 0 : block.text) && arraysAreEqual(this.attributes, block === null || block === void 0 ? void 0 : block.attributes);
5854
+ return this.text.isEqualTo(block === null || block === void 0 ? void 0 : block.text) && arraysAreEqual(this.attributes, block === null || block === void 0 ? void 0 : block.attributes) && objectsAreEqual(this.htmlAttributes, block === null || block === void 0 ? void 0 : block.htmlAttributes);
5844
5855
  }
5845
5856
  copyWithText(text) {
5846
- return new Block(text, this.attributes);
5857
+ return new Block(text, this.attributes, this.htmlAttributes);
5847
5858
  }
5848
5859
  copyWithoutText() {
5849
5860
  return this.copyWithText(null);
5850
5861
  }
5851
5862
  copyWithAttributes(attributes) {
5852
- return new Block(this.text, attributes);
5863
+ return new Block(this.text, attributes, this.htmlAttributes);
5853
5864
  }
5854
5865
  copyWithoutAttributes() {
5855
5866
  return this.copyWithAttributes(null);
@@ -5866,6 +5877,12 @@ $\
5866
5877
  const attributes = this.attributes.concat(expandAttribute(attribute));
5867
5878
  return this.copyWithAttributes(attributes);
5868
5879
  }
5880
+ addHTMLAttribute(attribute, value) {
5881
+ const htmlAttributes = Object.assign({}, this.htmlAttributes, {
5882
+ [attribute]: value
5883
+ });
5884
+ return new Block(this.text, this.attributes, htmlAttributes);
5885
+ }
5869
5886
  removeAttribute(attribute) {
5870
5887
  const {
5871
5888
  listAttribute
@@ -5962,7 +5979,8 @@ $\
5962
5979
  toJSON() {
5963
5980
  return {
5964
5981
  text: this.text,
5965
- attributes: this.attributes
5982
+ attributes: this.attributes,
5983
+ htmlAttributes: this.htmlAttributes
5966
5984
  };
5967
5985
  }
5968
5986
 
@@ -6325,6 +6343,11 @@ $\
6325
6343
  const range = this.getRangeOfAttachment(attachment);
6326
6344
  return this.removeAttributeAtRange(attribute, range);
6327
6345
  }
6346
+ setHTMLAttributeAtPosition(position, name, value) {
6347
+ const block = this.getBlockAtPosition(position);
6348
+ const updatedBlock = block.addHTMLAttribute(name, value);
6349
+ return this.replaceBlock(block, updatedBlock);
6350
+ }
6328
6351
  insertBlockBreakAtRange(range) {
6329
6352
  let blocks;
6330
6353
  range = normalizeRange(range);
@@ -6793,9 +6816,9 @@ $\
6793
6816
  return attributes;
6794
6817
  };
6795
6818
 
6796
- const DEFAULT_ALLOWED_ATTRIBUTES = "style href src width height class".split(" ");
6819
+ const DEFAULT_ALLOWED_ATTRIBUTES = "style href src width height language class".split(" ");
6797
6820
  const DEFAULT_FORBIDDEN_PROTOCOLS = "javascript:".split(" ");
6798
- const DEFAULT_FORBIDDEN_ELEMENTS = "script iframe form".split(" ");
6821
+ const DEFAULT_FORBIDDEN_ELEMENTS = "script iframe form noscript".split(" ");
6799
6822
  class HTMLSanitizer extends BasicObject {
6800
6823
  static sanitize(html, options) {
6801
6824
  const sanitizer = new this(html, options);
@@ -6923,15 +6946,21 @@ $\
6923
6946
  };
6924
6947
  const blockForAttributes = function () {
6925
6948
  let attributes = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
6949
+ let htmlAttributes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
6926
6950
  const text = [];
6927
6951
  return {
6928
6952
  text,
6929
- attributes
6953
+ attributes,
6954
+ htmlAttributes
6930
6955
  };
6931
6956
  };
6932
6957
  const parseTrixDataAttribute = (element, name) => {
6933
6958
  try {
6934
- return JSON.parse(element.getAttribute("data-trix-".concat(name)));
6959
+ const data = JSON.parse(element.getAttribute("data-trix-".concat(name)));
6960
+ if (data.contentType === "text/html" && data.content) {
6961
+ data.content = HTMLSanitizer.sanitize(data.content).getHTML();
6962
+ }
6963
+ return data;
6935
6964
  } catch (error) {
6936
6965
  return {};
6937
6966
  }
@@ -7027,8 +7056,9 @@ $\
7027
7056
  } else if (element === this.containerElement || this.isBlockElement(element)) {
7028
7057
  var _this$currentBlock;
7029
7058
  const attributes = this.getBlockAttributes(element);
7059
+ const htmlAttributes = this.getBlockHTMLAttributes(element);
7030
7060
  if (!arraysAreEqual(attributes, (_this$currentBlock = this.currentBlock) === null || _this$currentBlock === void 0 ? void 0 : _this$currentBlock.attributes)) {
7031
- this.currentBlock = this.appendBlockForAttributesWithElement(attributes, element);
7061
+ this.currentBlock = this.appendBlockForAttributesWithElement(attributes, element, htmlAttributes);
7032
7062
  this.currentBlockElement = element;
7033
7063
  }
7034
7064
  }
@@ -7039,9 +7069,10 @@ $\
7039
7069
  if (elementIsBlockElement && !this.isBlockElement(element.firstChild)) {
7040
7070
  if (!this.isInsignificantTextNode(element.firstChild) || !this.isBlockElement(element.firstElementChild)) {
7041
7071
  const attributes = this.getBlockAttributes(element);
7072
+ const htmlAttributes = this.getBlockHTMLAttributes(element);
7042
7073
  if (element.firstChild) {
7043
7074
  if (!(currentBlockContainsElement && arraysAreEqual(attributes, this.currentBlock.attributes))) {
7044
- this.currentBlock = this.appendBlockForAttributesWithElement(attributes, element);
7075
+ this.currentBlock = this.appendBlockForAttributesWithElement(attributes, element, htmlAttributes);
7045
7076
  this.currentBlockElement = element;
7046
7077
  } else {
7047
7078
  return this.appendStringWithAttributes("\n");
@@ -7129,8 +7160,9 @@ $\
7129
7160
  // Document construction
7130
7161
 
7131
7162
  appendBlockForAttributesWithElement(attributes, element) {
7163
+ let htmlAttributes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
7132
7164
  this.blockElements.push(element);
7133
- const block = blockForAttributes(attributes);
7165
+ const block = blockForAttributes(attributes, htmlAttributes);
7134
7166
  this.blocks.push(block);
7135
7167
  return block;
7136
7168
  }
@@ -7235,6 +7267,17 @@ $\
7235
7267
  }
7236
7268
  return attributes$1.reverse();
7237
7269
  }
7270
+ getBlockHTMLAttributes(element) {
7271
+ const attributes$1 = {};
7272
+ const blockConfig = Object.values(attributes).find(settings => settings.tagName === tagName(element));
7273
+ const allowedAttributes = (blockConfig === null || blockConfig === void 0 ? void 0 : blockConfig.htmlAttributes) || [];
7274
+ allowedAttributes.forEach(attribute => {
7275
+ if (element.hasAttribute(attribute)) {
7276
+ attributes$1[attribute] = element.getAttribute(attribute);
7277
+ }
7278
+ });
7279
+ return attributes$1;
7280
+ }
7238
7281
  findBlockElementAncestors(element) {
7239
7282
  const ancestors = [];
7240
7283
  while (element && element !== this.containerElement) {
@@ -7830,6 +7873,15 @@ $\
7830
7873
  return this.notifyDelegateOfCurrentAttributesChange();
7831
7874
  }
7832
7875
  }
7876
+ setHTMLAtributeAtPosition(position, attributeName, value) {
7877
+ var _getBlockConfig;
7878
+ const block = this.document.getBlockAtPosition(position);
7879
+ const allowedHTMLAttributes = (_getBlockConfig = getBlockConfig(block.getLastAttribute())) === null || _getBlockConfig === void 0 ? void 0 : _getBlockConfig.htmlAttributes;
7880
+ if (block && allowedHTMLAttributes !== null && allowedHTMLAttributes !== void 0 && allowedHTMLAttributes.includes(attributeName)) {
7881
+ const newDocument = this.document.setHTMLAttributeAtPosition(position, attributeName, value);
7882
+ this.setDocument(newDocument);
7883
+ }
7884
+ }
7833
7885
  setTextAttribute(attributeName, value) {
7834
7886
  const selectedRange = this.getSelectedRange();
7835
7887
  if (!selectedRange) return;
@@ -7877,10 +7929,10 @@ $\
7877
7929
  return ((_this$getBlock = this.getBlock()) === null || _this$getBlock === void 0 ? void 0 : _this$getBlock.getNestingLevel()) > 0;
7878
7930
  }
7879
7931
  canIncreaseNestingLevel() {
7880
- var _getBlockConfig;
7932
+ var _getBlockConfig2;
7881
7933
  const block = this.getBlock();
7882
7934
  if (!block) return;
7883
- if ((_getBlockConfig = getBlockConfig(block.getLastNestableAttribute())) !== null && _getBlockConfig !== void 0 && _getBlockConfig.listAttribute) {
7935
+ if ((_getBlockConfig2 = getBlockConfig(block.getLastNestableAttribute())) !== null && _getBlockConfig2 !== void 0 && _getBlockConfig2.listAttribute) {
7884
7936
  const previousBlock = this.getPreviousBlock();
7885
7937
  if (previousBlock) {
7886
7938
  return arrayStartsWith(previousBlock.getListItemAttributes(), block.getListItemAttributes());
@@ -8521,6 +8573,11 @@ $\
8521
8573
  return this.composition.removeCurrentAttribute(name);
8522
8574
  }
8523
8575
 
8576
+ // HTML attributes
8577
+ setHTMLAtributeAtPosition(position, name, value) {
8578
+ this.composition.setHTMLAtributeAtPosition(position, name, value);
8579
+ }
8580
+
8524
8581
  // Nesting level
8525
8582
 
8526
8583
  canDecreaseNestingLevel() {
@@ -10941,8 +10998,12 @@ $\
10941
10998
  });
10942
10999
  },
10943
11000
  insertReplacementText() {
10944
- return this.insertString(this.event.dataTransfer.getData("text/plain"), {
10945
- updatePosition: false
11001
+ const replacement = this.event.dataTransfer.getData("text/plain");
11002
+ const domRange = this.event.getTargetRanges()[0];
11003
+ this.withTargetDOMRange(domRange, () => {
11004
+ this.insertString(replacement, {
11005
+ updatePosition: false
11006
+ });
10946
11007
  });
10947
11008
  },
10948
11009
  insertText() {
@@ -11064,7 +11125,7 @@ $\
11064
11125
  return this.toggleDialog(actionName);
11065
11126
  } else {
11066
11127
  var _this$delegate2;
11067
- return (_this$delegate2 = this.delegate) === null || _this$delegate2 === void 0 ? void 0 : _this$delegate2.toolbarDidInvokeAction(actionName);
11128
+ return (_this$delegate2 = this.delegate) === null || _this$delegate2 === void 0 ? void 0 : _this$delegate2.toolbarDidInvokeAction(actionName, element);
11068
11129
  }
11069
11130
  }
11070
11131
  didClickAttributeButton(event, element) {
@@ -11509,8 +11570,8 @@ $\
11509
11570
  });
11510
11571
  }
11511
11572
  }
11512
- toolbarDidInvokeAction(actionName) {
11513
- return this.invokeAction(actionName);
11573
+ toolbarDidInvokeAction(actionName, invokingElement) {
11574
+ return this.invokeAction(actionName, invokingElement);
11514
11575
  }
11515
11576
  toolbarDidToggleAttribute(attributeName) {
11516
11577
  this.recordFormattingUndoEntry(attributeName);
@@ -11579,10 +11640,11 @@ $\
11579
11640
  return !!((_this$actions$actionN = this.actions[actionName]) !== null && _this$actions$actionN !== void 0 && (_this$actions$actionN = _this$actions$actionN.test) !== null && _this$actions$actionN !== void 0 && _this$actions$actionN.call(this));
11580
11641
  }
11581
11642
  }
11582
- invokeAction(actionName) {
11643
+ invokeAction(actionName, invokingElement) {
11583
11644
  if (this.actionIsExternal(actionName)) {
11584
11645
  return this.notifyEditorElement("action-invoke", {
11585
- actionName
11646
+ actionName,
11647
+ invokingElement
11586
11648
  });
11587
11649
  } else {
11588
11650
  var _this$actions$actionN2;
@@ -334,7 +334,9 @@ trix-editor .attachment__metadata {
334
334
  white-space: nowrap; }
335
335
 
336
336
  .trix-content {
337
- line-height: 1.5; }
337
+ line-height: 1.5;
338
+ overflow-wrap: break-word;
339
+ word-break: break-word; }
338
340
  .trix-content * {
339
341
  box-sizing: border-box;
340
342
  margin: 0;
@@ -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
@@ -14,6 +16,15 @@ module ActionText
14
16
  sanitize_action_text_content(render_action_text_attachments(content))
15
17
  end
16
18
 
19
+ def sanitize_content_attachment(content_attachment)
20
+ sanitizer.sanitize(
21
+ content_attachment,
22
+ tags: sanitizer_allowed_tags,
23
+ attributes: sanitizer_allowed_attributes,
24
+ scrubber: scrubber,
25
+ )
26
+ end
27
+
17
28
  def sanitize_action_text_content(content)
18
29
  sanitizer.sanitize(
19
30
  content.to_html,
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "active_support/core_ext/object/try"
4
6
  require "action_view/helpers/tags/placeholderable"
5
7
 
@@ -7,20 +9,24 @@ module ActionText
7
9
  module TagHelper
8
10
  cattr_accessor(:id, instance_accessor: false) { 0 }
9
11
 
10
- # Returns a +trix-editor+ tag that instantiates the Trix JavaScript editor as well as a hidden field
11
- # that Trix will write to on changes, so the content will be sent on form submissions.
12
+ # Returns a `trix-editor` tag that instantiates the Trix JavaScript editor as
13
+ # well as a hidden field that Trix will write to on changes, so the content will
14
+ # be sent on form submissions.
15
+ #
16
+ # #### Options
17
+ # * `:class` - Defaults to "trix-content" so that default styles will be
18
+ # applied. Setting this to a different value will prevent default styles
19
+ # from being applied.
20
+ # * `[:data][:direct_upload_url]` - Defaults to `rails_direct_uploads_url`.
21
+ # * `[:data][:blob_url_template]` - Defaults to
22
+ # `rails_service_blob_url(":signed_id", ":filename")`.
12
23
  #
13
- # ==== Options
14
- # * <tt>:class</tt> - Defaults to "trix-content" so that default styles will be applied.
15
- # Setting this to a different value will prevent default styles from being applied.
16
- # * <tt>[:data][:direct_upload_url]</tt> - Defaults to +rails_direct_uploads_url+.
17
- # * <tt>[:data][:blob_url_template]</tt> - Defaults to <tt>rails_service_blob_url(":signed_id", ":filename")</tt>.
18
24
  #
19
- # ==== Example
25
+ # #### Example
20
26
  #
21
- # rich_text_area_tag "content", message.content
22
- # # <input type="hidden" name="content" id="trix_input_post_1">
23
- # # <trix-editor id="content" input="trix_input_post_1" class="trix-content" ...></trix-editor>
27
+ # rich_text_area_tag "content", message.content
28
+ # # <input type="hidden" name="content" id="trix_input_post_1">
29
+ # # <trix-editor id="content" input="trix_input_post_1" class="trix-content" ...></trix-editor>
24
30
  def rich_text_area_tag(name, value = nil, options = {})
25
31
  options = options.symbolize_keys
26
32
  form = options.delete(:form)
@@ -56,23 +62,27 @@ module ActionView::Helpers
56
62
  end
57
63
 
58
64
  module FormHelper
59
- # Returns a +trix-editor+ tag that instantiates the Trix JavaScript editor as well as a hidden field
60
- # that Trix will write to on changes, so the content will be sent on form submissions.
65
+ # Returns a `trix-editor` tag that instantiates the Trix JavaScript editor as
66
+ # well as a hidden field that Trix will write to on changes, so the content will
67
+ # be sent on form submissions.
68
+ #
69
+ # #### Options
70
+ # * `:class` - Defaults to "trix-content" which ensures default styling is
71
+ # applied.
72
+ # * `:value` - Adds a default value to the HTML input tag.
73
+ # * `[:data][:direct_upload_url]` - Defaults to `rails_direct_uploads_url`.
74
+ # * `[:data][:blob_url_template]` - Defaults to
75
+ # `rails_service_blob_url(":signed_id", ":filename")`.
61
76
  #
62
- # ==== Options
63
- # * <tt>:class</tt> - Defaults to "trix-content" which ensures default styling is applied.
64
- # * <tt>:value</tt> - Adds a default value to the HTML input tag.
65
- # * <tt>[:data][:direct_upload_url]</tt> - Defaults to +rails_direct_uploads_url+.
66
- # * <tt>[:data][:blob_url_template]</tt> - Defaults to <tt>rails_service_blob_url(":signed_id", ":filename")</tt>.
67
77
  #
68
- # ==== Example
69
- # rich_text_area :message, :content
70
- # # <input type="hidden" name="message[content]" id="message_content_trix_input_message_1">
71
- # # <trix-editor id="content" input="message_content_trix_input_message_1" class="trix-content" ...></trix-editor>
78
+ # #### Example
79
+ # rich_text_area :message, :content
80
+ # # <input type="hidden" name="message[content]" id="message_content_trix_input_message_1">
81
+ # # <trix-editor id="content" input="message_content_trix_input_message_1" class="trix-content" ...></trix-editor>
72
82
  #
73
- # rich_text_area :message, :content, value: "<h1>Default message</h1>"
74
- # # <input type="hidden" name="message[content]" id="message_content_trix_input_message_1" value="<h1>Default message</h1>">
75
- # # <trix-editor id="content" input="message_content_trix_input_message_1" class="trix-content" ...></trix-editor>
83
+ # rich_text_area :message, :content, value: "<h1>Default message</h1>"
84
+ # # <input type="hidden" name="message[content]" id="message_content_trix_input_message_1" value="<h1>Default message</h1>">
85
+ # # <trix-editor id="content" input="message_content_trix_input_message_1" class="trix-content" ...></trix-editor>
76
86
  def rich_text_area(object_name, method, options = {})
77
87
  Tags::ActionText.new(object_name, method, self, options).render
78
88
  end
@@ -81,9 +91,9 @@ module ActionView::Helpers
81
91
  class FormBuilder
82
92
  # Wraps ActionView::Helpers::FormHelper#rich_text_area for form builders:
83
93
  #
84
- # <%= form_with model: @message do |f| %>
85
- # <%= f.rich_text_area :content %>
86
- # <% end %>
94
+ # <%= form_with model: @message do |f| %>
95
+ # <%= f.rich_text_area :content %>
96
+ # <% end %>
87
97
  #
88
98
  # Please refer to the documentation of the base helper for details.
89
99
  def rich_text_area(method, options = {})
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionText
4
6
  class EncryptedRichText < RichText
5
- self.table_name = "action_text_rich_texts"
6
-
7
7
  encrypts :body
8
8
  end
9
9
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionText
4
6
  class Record < ActiveRecord::Base # :nodoc:
5
7
  self.abstract_class = true