actiontext 7.0.8 → 7.1.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actiontext might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +40 -123
- data/MIT-LICENSE +1 -1
- data/README.md +2 -2
- data/app/assets/javascripts/actiontext.js +781 -766
- data/app/assets/javascripts/trix.js +12971 -5170
- data/app/assets/stylesheets/trix.css +64 -29
- data/app/helpers/action_text/content_helper.rb +17 -4
- data/app/helpers/action_text/tag_helper.rb +9 -1
- data/app/models/action_text/encrypted_rich_text.rb +2 -0
- data/app/models/action_text/rich_text.rb +29 -1
- data/app/views/action_text/attachables/_content_attachment.html.erb +3 -0
- data/lib/action_text/attachable.rb +69 -5
- data/lib/action_text/attachables/content_attachment.rb +20 -18
- data/lib/action_text/attachables/missing_attachable.rb +17 -3
- data/lib/action_text/attachment.rb +43 -2
- data/lib/action_text/attribute.rb +10 -5
- data/lib/action_text/content.rb +43 -2
- data/lib/action_text/deprecator.rb +7 -0
- data/lib/action_text/engine.rb +14 -8
- data/lib/action_text/fixture_set.rb +2 -0
- data/lib/action_text/fragment.rb +4 -3
- data/lib/action_text/gem_version.rb +3 -3
- data/lib/action_text/html_conversion.rb +1 -1
- data/lib/action_text/rendering.rb +5 -2
- data/lib/action_text/trix_attachment.rb +2 -2
- data/lib/action_text/version.rb +1 -1
- data/lib/action_text.rb +19 -0
- data/lib/generators/action_text/install/install_generator.rb +20 -3
- data/lib/generators/action_text/install/templates/actiontext.css +0 -4
- data/package.json +6 -6
- metadata +15 -13
@@ -1,8 +1,3 @@
|
|
1
|
-
@charset "UTF-8";
|
2
|
-
/*
|
3
|
-
Trix 1.3.1
|
4
|
-
Copyright © 2020 Basecamp, LLC
|
5
|
-
http://trix-editor.org/*/
|
6
1
|
trix-editor {
|
7
2
|
border: 1px solid #bbb;
|
8
3
|
border-radius: 3px;
|
@@ -10,13 +5,16 @@ trix-editor {
|
|
10
5
|
padding: 0.4em 0.6em;
|
11
6
|
min-height: 5em;
|
12
7
|
outline: none; }
|
8
|
+
|
13
9
|
trix-toolbar * {
|
14
10
|
box-sizing: border-box; }
|
11
|
+
|
15
12
|
trix-toolbar .trix-button-row {
|
16
13
|
display: flex;
|
17
14
|
flex-wrap: nowrap;
|
18
15
|
justify-content: space-between;
|
19
16
|
overflow-x: auto; }
|
17
|
+
|
20
18
|
trix-toolbar .trix-button-group {
|
21
19
|
display: flex;
|
22
20
|
margin-bottom: 10px;
|
@@ -26,14 +24,16 @@ trix-toolbar .trix-button-group {
|
|
26
24
|
border-radius: 3px; }
|
27
25
|
trix-toolbar .trix-button-group:not(:first-child) {
|
28
26
|
margin-left: 1.5vw; }
|
29
|
-
@media (max-
|
27
|
+
@media (max-width: 768px) {
|
30
28
|
trix-toolbar .trix-button-group:not(:first-child) {
|
31
29
|
margin-left: 0; } }
|
30
|
+
|
32
31
|
trix-toolbar .trix-button-group-spacer {
|
33
32
|
flex-grow: 1; }
|
34
|
-
@media (max-
|
33
|
+
@media (max-width: 768px) {
|
35
34
|
trix-toolbar .trix-button-group-spacer {
|
36
35
|
display: none; } }
|
36
|
+
|
37
37
|
trix-toolbar .trix-button {
|
38
38
|
position: relative;
|
39
39
|
float: left;
|
@@ -57,17 +57,18 @@ trix-toolbar .trix-button {
|
|
57
57
|
cursor: pointer; }
|
58
58
|
trix-toolbar .trix-button:disabled {
|
59
59
|
color: rgba(0, 0, 0, 0.125); }
|
60
|
-
@media (max-
|
60
|
+
@media (max-width: 768px) {
|
61
61
|
trix-toolbar .trix-button {
|
62
62
|
letter-spacing: -0.01em;
|
63
63
|
padding: 0 0.3em; } }
|
64
|
+
|
64
65
|
trix-toolbar .trix-button--icon {
|
65
66
|
font-size: inherit;
|
66
67
|
width: 2.6em;
|
67
68
|
height: 1.6em;
|
68
69
|
max-width: calc(0.8em + 4vw);
|
69
70
|
text-indent: -9999px; }
|
70
|
-
@media (max-
|
71
|
+
@media (max-width: 768px) {
|
71
72
|
trix-toolbar .trix-button--icon {
|
72
73
|
height: 2em;
|
73
74
|
max-width: calc(0.8em + 3.5vw); } }
|
@@ -83,7 +84,7 @@ trix-toolbar .trix-button--icon {
|
|
83
84
|
background-position: center;
|
84
85
|
background-repeat: no-repeat;
|
85
86
|
background-size: contain; }
|
86
|
-
@media (max-
|
87
|
+
@media (max-width: 768px) {
|
87
88
|
trix-toolbar .trix-button--icon::before {
|
88
89
|
right: 6%;
|
89
90
|
left: 6%; } }
|
@@ -91,38 +92,54 @@ trix-toolbar .trix-button--icon {
|
|
91
92
|
opacity: 1; }
|
92
93
|
trix-toolbar .trix-button--icon:disabled::before {
|
93
94
|
opacity: 0.125; }
|
95
|
+
|
94
96
|
trix-toolbar .trix-button--icon-attach::before {
|
95
|
-
background-image: url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%
|
97
|
+
background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M10.5%2018V7.5c0-2.25%203-2.25%203%200V18c0%204.125-6%204.125-6%200V7.5c0-6.375%209-6.375%209%200V18%22%20stroke%3D%22%23000%22%20stroke-width%3D%222%22%20stroke-miterlimit%3D%2210%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%2F%3E%3C%2Fsvg%3E");
|
96
98
|
top: 8%;
|
97
99
|
bottom: 4%; }
|
100
|
+
|
98
101
|
trix-toolbar .trix-button--icon-bold::before {
|
99
|
-
background-image: url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%
|
102
|
+
background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M6.522%2019.242a.5.5%200%200%201-.5-.5V5.35a.5.5%200%200%201%20.5-.5h5.783c1.347%200%202.46.345%203.24.982.783.64%201.216%201.562%201.216%202.683%200%201.13-.587%202.129-1.476%202.71a.35.35%200%200%200%20.049.613c1.259.56%202.101%201.742%202.101%203.22%200%201.282-.483%202.334-1.363%203.063-.876.726-2.132%201.12-3.66%201.12h-5.89ZM9.27%207.347v3.362h1.97c.766%200%201.347-.17%201.733-.464.38-.291.587-.716.587-1.27%200-.53-.183-.928-.513-1.198-.334-.273-.838-.43-1.505-.43H9.27Zm0%205.606v3.791h2.389c.832%200%201.448-.177%201.853-.497.399-.315.614-.786.614-1.423%200-.62-.22-1.077-.63-1.385-.418-.313-1.053-.486-1.905-.486H9.27Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }
|
103
|
+
|
100
104
|
trix-toolbar .trix-button--icon-italic::before {
|
101
|
-
background-image: url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%
|
105
|
+
background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M9%205h6.5v2h-2.23l-2.31%2010H13v2H6v-2h2.461l2.306-10H9V5Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }
|
106
|
+
|
102
107
|
trix-toolbar .trix-button--icon-link::before {
|
103
|
-
background-image: url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%
|
108
|
+
background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M18.948%205.258a4.337%204.337%200%200%200-6.108%200L11.217%206.87a.993.993%200%200%200%200%201.41c.392.39%201.027.39%201.418%200l1.623-1.613a2.323%202.323%200%200%201%203.271%200%202.29%202.29%200%200%201%200%203.251l-2.393%202.38a3.021%203.021%200%200%201-4.255%200l-.05-.049a1.007%201.007%200%200%200-1.418%200%20.993.993%200%200%200%200%201.41l.05.049a5.036%205.036%200%200%200%207.091%200l2.394-2.38a4.275%204.275%200%200%200%200-6.072Zm-13.683%2013.6a4.337%204.337%200%200%200%206.108%200l1.262-1.255a.993.993%200%200%200%200-1.41%201.007%201.007%200%200%200-1.418%200L9.954%2017.45a2.323%202.323%200%200%201-3.27%200%202.29%202.29%200%200%201%200-3.251l2.344-2.331a2.579%202.579%200%200%201%203.631%200c.392.39%201.027.39%201.419%200a.993.993%200%200%200%200-1.41%204.593%204.593%200%200%200-6.468%200l-2.345%202.33a4.275%204.275%200%200%200%200%206.072Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }
|
109
|
+
|
104
110
|
trix-toolbar .trix-button--icon-strike::before {
|
105
|
-
background-image: url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%
|
111
|
+
background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M6%2014.986c.088%202.647%202.246%204.258%205.635%204.258%203.496%200%205.713-1.728%205.713-4.463%200-.275-.02-.536-.062-.781h-3.461c.398.293.573.654.573%201.123%200%201.035-1.074%201.787-2.646%201.787-1.563%200-2.773-.762-2.91-1.924H6ZM6.432%2010h3.763c-.632-.314-.914-.715-.914-1.273%200-1.045.977-1.739%202.432-1.739%201.475%200%202.52.723%202.617%201.914h2.764c-.05-2.548-2.11-4.238-5.39-4.238-3.145%200-5.392%201.719-5.392%204.316%200%20.363.04.703.12%201.02ZM4%2011a1%201%200%201%200%200%202h15a1%201%200%201%200%200-2H4Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }
|
112
|
+
|
106
113
|
trix-toolbar .trix-button--icon-quote::before {
|
107
|
-
background-image: url(data:image/svg+xml,%3Csvg%
|
114
|
+
background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M4.581%208.471c.44-.5%201.056-.834%201.758-.995C8.074%207.17%209.201%207.822%2010%208.752c1.354%201.578%201.33%203.555.394%205.277-.941%201.731-2.788%203.163-4.988%203.56a.622.622%200%200%201-.653-.317c-.113-.205-.121-.49.16-.764.294-.286.567-.566.791-.835.222-.266.413-.54.524-.815.113-.28.156-.597.026-.908-.128-.303-.39-.524-.72-.69a3.02%203.02%200%200%201-1.674-2.7c0-.905.283-1.59.72-2.088Zm9.419%200c.44-.5%201.055-.834%201.758-.995%201.734-.306%202.862.346%203.66%201.276%201.355%201.578%201.33%203.555.395%205.277-.941%201.731-2.789%203.163-4.988%203.56a.622.622%200%200%201-.653-.317c-.113-.205-.122-.49.16-.764.294-.286.567-.566.791-.835.222-.266.412-.54.523-.815.114-.28.157-.597.026-.908-.127-.303-.39-.524-.72-.69a3.02%203.02%200%200%201-1.672-2.701c0-.905.283-1.59.72-2.088Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }
|
115
|
+
|
108
116
|
trix-toolbar .trix-button--icon-heading-1::before {
|
109
|
-
background-image: url(data:image/svg+xml,%3Csvg%
|
117
|
+
background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M21.5%207.5v-3h-12v3H14v13h3v-13h4.5ZM9%2013.5h3.5v-3h-10v3H6v7h3v-7Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }
|
118
|
+
|
110
119
|
trix-toolbar .trix-button--icon-code::before {
|
111
|
-
background-image: url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%
|
120
|
+
background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M3.293%2011.293a1%201%200%200%200%200%201.414l4%204a1%201%200%201%200%201.414-1.414L5.414%2012l3.293-3.293a1%201%200%200%200-1.414-1.414l-4%204Zm13.414%205.414%204-4a1%201%200%200%200%200-1.414l-4-4a1%201%200%201%200-1.414%201.414L18.586%2012l-3.293%203.293a1%201%200%200%200%201.414%201.414Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }
|
121
|
+
|
112
122
|
trix-toolbar .trix-button--icon-bullet-list::before {
|
113
|
-
background-image: url(data:image/svg+xml,%3Csvg%
|
123
|
+
background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M5%207.5a1.5%201.5%200%201%200%200-3%201.5%201.5%200%200%200%200%203ZM8%206a1%201%200%200%201%201-1h11a1%201%200%201%201%200%202H9a1%201%200%200%201-1-1Zm1%205a1%201%200%201%200%200%202h11a1%201%200%201%200%200-2H9Zm0%206a1%201%200%201%200%200%202h11a1%201%200%201%200%200-2H9Zm-2.5-5a1.5%201.5%200%201%201-3%200%201.5%201.5%200%200%201%203%200ZM5%2019.5a1.5%201.5%200%201%200%200-3%201.5%201.5%200%200%200%200%203Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }
|
124
|
+
|
114
125
|
trix-toolbar .trix-button--icon-number-list::before {
|
115
|
-
background-image: url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%
|
126
|
+
background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M3%204h2v4H4V5H3V4Zm5%202a1%201%200%200%201%201-1h11a1%201%200%201%201%200%202H9a1%201%200%200%201-1-1Zm1%205a1%201%200%201%200%200%202h11a1%201%200%201%200%200-2H9Zm0%206a1%201%200%201%200%200%202h11a1%201%200%201%200%200-2H9Zm-3.5-7H6v1l-1.5%202H6v1H3v-1l1.667-2H3v-1h2.5ZM3%2017v-1h3v4H3v-1h2v-.5H4v-1h1V17H3Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }
|
127
|
+
|
116
128
|
trix-toolbar .trix-button--icon-undo::before {
|
117
|
-
background-image: url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%
|
129
|
+
background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M3%2014a1%201%200%200%200%201%201h6a1%201%200%201%200%200-2H6.257c2.247-2.764%205.151-3.668%207.579-3.264%202.589.432%204.739%202.356%205.174%205.405a1%201%200%200%200%201.98-.283c-.564-3.95-3.415-6.526-6.825-7.095C11.084%207.25%207.63%208.377%205%2011.39V8a1%201%200%200%200-2%200v6Zm2-1Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }
|
130
|
+
|
118
131
|
trix-toolbar .trix-button--icon-redo::before {
|
119
|
-
background-image: url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%
|
132
|
+
background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M21%2014a1%201%200%200%201-1%201h-6a1%201%200%201%201%200-2h3.743c-2.247-2.764-5.151-3.668-7.579-3.264-2.589.432-4.739%202.356-5.174%205.405a1%201%200%200%201-1.98-.283c.564-3.95%203.415-6.526%206.826-7.095%203.08-.513%206.534.614%209.164%203.626V8a1%201%200%201%201%202%200v6Zm-2-1Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }
|
133
|
+
|
120
134
|
trix-toolbar .trix-button--icon-decrease-nesting-level::before {
|
121
|
-
background-image: url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%
|
135
|
+
background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M5%206a1%201%200%200%201%201-1h12a1%201%200%201%201%200%202H6a1%201%200%200%201-1-1Zm4%205a1%201%200%201%200%200%202h9a1%201%200%201%200%200-2H9Zm-3%206a1%201%200%201%200%200%202h12a1%201%200%201%200%200-2H6Zm-3.707-5.707a1%201%200%200%200%200%201.414l2%202a1%201%200%201%200%201.414-1.414L4.414%2012l1.293-1.293a1%201%200%200%200-1.414-1.414l-2%202Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }
|
136
|
+
|
122
137
|
trix-toolbar .trix-button--icon-increase-nesting-level::before {
|
123
|
-
background-image: url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%
|
138
|
+
background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M5%206a1%201%200%200%201%201-1h12a1%201%200%201%201%200%202H6a1%201%200%200%201-1-1Zm4%205a1%201%200%201%200%200%202h9a1%201%200%201%200%200-2H9Zm-3%206a1%201%200%201%200%200%202h12a1%201%200%201%200%200-2H6Zm-2.293-2.293%202-2a1%201%200%200%200%200-1.414l-2-2a1%201%200%201%200-1.414%201.414L3.586%2012l-1.293%201.293a1%201%200%201%200%201.414%201.414Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }
|
139
|
+
|
124
140
|
trix-toolbar .trix-dialogs {
|
125
141
|
position: relative; }
|
142
|
+
|
126
143
|
trix-toolbar .trix-dialog {
|
127
144
|
position: absolute;
|
128
145
|
top: 0;
|
@@ -135,6 +152,7 @@ trix-toolbar .trix-dialog {
|
|
135
152
|
border-top: 2px solid #888;
|
136
153
|
border-radius: 5px;
|
137
154
|
z-index: 5; }
|
155
|
+
|
138
156
|
trix-toolbar .trix-input--dialog {
|
139
157
|
font-size: inherit;
|
140
158
|
font-weight: normal;
|
@@ -149,12 +167,15 @@ trix-toolbar .trix-input--dialog {
|
|
149
167
|
-moz-appearance: none; }
|
150
168
|
trix-toolbar .trix-input--dialog.validate:invalid {
|
151
169
|
box-shadow: #F00 0px 0px 1.5px 1px; }
|
170
|
+
|
152
171
|
trix-toolbar .trix-button--dialog {
|
153
172
|
font-size: inherit;
|
154
173
|
padding: 0.5em;
|
155
174
|
border-bottom: none; }
|
175
|
+
|
156
176
|
trix-toolbar .trix-dialog--link {
|
157
177
|
max-width: 600px; }
|
178
|
+
|
158
179
|
trix-toolbar .trix-dialog__link-fields {
|
159
180
|
display: flex;
|
160
181
|
align-items: baseline; }
|
@@ -163,6 +184,7 @@ trix-toolbar .trix-dialog__link-fields {
|
|
163
184
|
trix-toolbar .trix-dialog__link-fields .trix-button-group {
|
164
185
|
flex: 0 0 content;
|
165
186
|
margin: 0; }
|
187
|
+
|
166
188
|
trix-editor [data-trix-mutable]:not(.attachment__caption-editor) {
|
167
189
|
-webkit-user-select: none;
|
168
190
|
-moz-user-select: none;
|
@@ -172,26 +194,32 @@ trix-editor [data-trix-mutable]:not(.attachment__caption-editor) {
|
|
172
194
|
trix-editor [data-trix-mutable]::-moz-selection,
|
173
195
|
trix-editor [data-trix-cursor-target]::-moz-selection, trix-editor [data-trix-mutable] ::-moz-selection {
|
174
196
|
background: none; }
|
197
|
+
|
175
198
|
trix-editor [data-trix-mutable]::selection,
|
176
199
|
trix-editor [data-trix-cursor-target]::selection, trix-editor [data-trix-mutable] ::selection {
|
177
200
|
background: none; }
|
178
201
|
|
179
|
-
trix-editor [data-trix-mutable]
|
202
|
+
trix-editor .attachment__caption-editor:focus[data-trix-mutable]::-moz-selection {
|
180
203
|
background: highlight; }
|
181
|
-
|
204
|
+
|
205
|
+
trix-editor .attachment__caption-editor:focus[data-trix-mutable]::selection {
|
182
206
|
background: highlight; }
|
183
207
|
|
184
208
|
trix-editor [data-trix-mutable].attachment.attachment--file {
|
185
209
|
box-shadow: 0 0 0 2px highlight;
|
186
210
|
border-color: transparent; }
|
211
|
+
|
187
212
|
trix-editor [data-trix-mutable].attachment img {
|
188
213
|
box-shadow: 0 0 0 2px highlight; }
|
214
|
+
|
189
215
|
trix-editor .attachment {
|
190
216
|
position: relative; }
|
191
217
|
trix-editor .attachment:hover {
|
192
218
|
cursor: default; }
|
219
|
+
|
193
220
|
trix-editor .attachment--preview .attachment__caption:hover {
|
194
221
|
cursor: text; }
|
222
|
+
|
195
223
|
trix-editor .attachment__progress {
|
196
224
|
position: absolute;
|
197
225
|
z-index: 1;
|
@@ -203,6 +231,7 @@ trix-editor .attachment__progress {
|
|
203
231
|
transition: opacity 200ms ease-in; }
|
204
232
|
trix-editor .attachment__progress[value="100"] {
|
205
233
|
opacity: 0; }
|
234
|
+
|
206
235
|
trix-editor .attachment__caption-editor {
|
207
236
|
display: inline-block;
|
208
237
|
width: 100%;
|
@@ -218,6 +247,7 @@ trix-editor .attachment__caption-editor {
|
|
218
247
|
outline: none;
|
219
248
|
-webkit-appearance: none;
|
220
249
|
-moz-appearance: none; }
|
250
|
+
|
221
251
|
trix-editor .attachment__toolbar {
|
222
252
|
position: absolute;
|
223
253
|
z-index: 1;
|
@@ -225,8 +255,10 @@ trix-editor .attachment__toolbar {
|
|
225
255
|
left: 0;
|
226
256
|
width: 100%;
|
227
257
|
text-align: center; }
|
258
|
+
|
228
259
|
trix-editor .trix-button-group {
|
229
260
|
display: inline-flex; }
|
261
|
+
|
230
262
|
trix-editor .trix-button {
|
231
263
|
position: relative;
|
232
264
|
float: left;
|
@@ -245,6 +277,7 @@ trix-editor .trix-button {
|
|
245
277
|
background: #cbeefa; }
|
246
278
|
trix-editor .trix-button:not(:disabled) {
|
247
279
|
cursor: pointer; }
|
280
|
+
|
248
281
|
trix-editor .trix-button--remove {
|
249
282
|
text-indent: -9999px;
|
250
283
|
display: inline-block;
|
@@ -266,7 +299,7 @@ trix-editor .trix-button--remove {
|
|
266
299
|
left: 0;
|
267
300
|
opacity: 0.7;
|
268
301
|
content: "";
|
269
|
-
background-image: url(data:image/svg+xml,%3Csvg%20height%3D%2224%22%20width%3D%2224%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M19%206.
|
302
|
+
background-image: url("data:image/svg+xml,%3Csvg%20height%3D%2224%22%20width%3D%2224%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M19%206.41%2017.59%205%2012%2010.59%206.41%205%205%206.41%2010.59%2012%205%2017.59%206.41%2019%2012%2013.41%2017.59%2019%2019%2017.59%2013.41%2012z%22%2F%3E%3Cpath%20d%3D%22M0%200h24v24H0z%22%20fill%3D%22none%22%2F%3E%3C%2Fsvg%3E");
|
270
303
|
background-position: center;
|
271
304
|
background-repeat: no-repeat;
|
272
305
|
background-size: 90%; }
|
@@ -274,8 +307,10 @@ trix-editor .trix-button--remove {
|
|
274
307
|
border-color: #333; }
|
275
308
|
trix-editor .trix-button--remove:hover::before {
|
276
309
|
opacity: 1; }
|
310
|
+
|
277
311
|
trix-editor .attachment__metadata-container {
|
278
312
|
position: relative; }
|
313
|
+
|
279
314
|
trix-editor .attachment__metadata {
|
280
315
|
position: absolute;
|
281
316
|
left: 50%;
|
@@ -297,7 +332,7 @@ trix-editor .attachment__metadata {
|
|
297
332
|
trix-editor .attachment__metadata .attachment__size {
|
298
333
|
margin-left: 0.2em;
|
299
334
|
white-space: nowrap; }
|
300
|
-
|
335
|
+
|
301
336
|
.trix-content {
|
302
337
|
line-height: 1.5; }
|
303
338
|
.trix-content * {
|
@@ -347,7 +382,7 @@ trix-editor .attachment__metadata {
|
|
347
382
|
.trix-content .attachment__caption {
|
348
383
|
text-align: center; }
|
349
384
|
.trix-content .attachment__caption .attachment__name + .attachment__size::before {
|
350
|
-
content: '
|
385
|
+
content: ' \2022 '; }
|
351
386
|
.trix-content .attachment--preview {
|
352
387
|
width: 100%;
|
353
388
|
text-align: center; }
|
@@ -4,9 +4,9 @@ require "rails-html-sanitizer"
|
|
4
4
|
|
5
5
|
module ActionText
|
6
6
|
module ContentHelper
|
7
|
-
mattr_accessor(:sanitizer
|
8
|
-
mattr_accessor(:allowed_tags)
|
9
|
-
mattr_accessor(:allowed_attributes)
|
7
|
+
mattr_accessor(:sanitizer, default: Rails::HTML4::Sanitizer.safe_list_sanitizer.new)
|
8
|
+
mattr_accessor(:allowed_tags)
|
9
|
+
mattr_accessor(:allowed_attributes)
|
10
10
|
mattr_accessor(:scrubber)
|
11
11
|
|
12
12
|
def render_action_text_content(content)
|
@@ -15,7 +15,12 @@ module ActionText
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def sanitize_action_text_content(content)
|
18
|
-
sanitizer.sanitize(
|
18
|
+
sanitizer.sanitize(
|
19
|
+
content.to_html,
|
20
|
+
tags: sanitizer_allowed_tags,
|
21
|
+
attributes: sanitizer_allowed_attributes,
|
22
|
+
scrubber: scrubber,
|
23
|
+
).html_safe
|
19
24
|
end
|
20
25
|
|
21
26
|
def render_action_text_attachments(content)
|
@@ -48,5 +53,13 @@ module ActionText
|
|
48
53
|
|
49
54
|
render(**options).chomp
|
50
55
|
end
|
56
|
+
|
57
|
+
def sanitizer_allowed_tags
|
58
|
+
allowed_tags || (sanitizer.class.allowed_tags + [ ActionText::Attachment.tag_name, "figure", "figcaption" ])
|
59
|
+
end
|
60
|
+
|
61
|
+
def sanitizer_allowed_attributes
|
62
|
+
allowed_attributes || (sanitizer.class.allowed_attributes + ActionText::Attachment::ATTRIBUTES)
|
63
|
+
end
|
51
64
|
end
|
52
65
|
end
|
@@ -50,7 +50,8 @@ module ActionView::Helpers
|
|
50
50
|
options = @options.stringify_keys
|
51
51
|
add_default_name_and_id(options)
|
52
52
|
options["input"] ||= dom_id(object, [options["id"], :trix_input].compact.join("_")) if object
|
53
|
-
@template_object.rich_text_area_tag(options.delete("name"), options.fetch("value") { value }, options.except("value"))
|
53
|
+
html_tag = @template_object.rich_text_area_tag(options.delete("name"), options.fetch("value") { value }, options.except("value"))
|
54
|
+
error_wrapping(html_tag)
|
54
55
|
end
|
55
56
|
end
|
56
57
|
|
@@ -82,6 +83,13 @@ module ActionView::Helpers
|
|
82
83
|
end
|
83
84
|
|
84
85
|
class FormBuilder
|
86
|
+
# Wraps ActionView::Helpers::FormHelper#rich_text_area for form builders:
|
87
|
+
#
|
88
|
+
# <%= form_with model: @message do |f| %>
|
89
|
+
# <%= f.rich_text_area :content %>
|
90
|
+
# <% end %>
|
91
|
+
#
|
92
|
+
# Please refer to the documentation of the base helper for details.
|
85
93
|
def rich_text_area(method, options = {})
|
86
94
|
@template.rich_text_area(@object_name, method, objectify_options(options))
|
87
95
|
end
|
@@ -1,14 +1,26 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActionText
|
4
|
+
# = Action Text \RichText
|
5
|
+
#
|
4
6
|
# The RichText record holds the content produced by the Trix editor in a serialized +body+ attribute.
|
5
7
|
# It also holds all the references to the embedded files, which are stored using Active Storage.
|
6
8
|
# This record is then associated with the Active Record model the application desires to have
|
7
9
|
# rich text content using the +has_rich_text+ class method.
|
10
|
+
#
|
11
|
+
# class Message < ActiveRecord::Base
|
12
|
+
# has_rich_text :content
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# message = Message.create!(content: "<h1>Funny times!</h1>")
|
16
|
+
# message.content #=> #<ActionText::RichText....
|
17
|
+
# message.content.to_s # => "<h1>Funny times!</h1>"
|
18
|
+
# message.content.to_plain_text # => "Funny times!"
|
19
|
+
#
|
8
20
|
class RichText < Record
|
9
21
|
self.table_name = "action_text_rich_texts"
|
10
22
|
|
11
|
-
serialize :body, ActionText::Content
|
23
|
+
serialize :body, coder: ActionText::Content
|
12
24
|
delegate :to_s, :nil?, to: :body
|
13
25
|
|
14
26
|
belongs_to :record, polymorphic: true, touch: true
|
@@ -18,10 +30,26 @@ module ActionText
|
|
18
30
|
self.embeds = body.attachables.grep(ActiveStorage::Blob).uniq if body.present?
|
19
31
|
end
|
20
32
|
|
33
|
+
# Returns the +body+ attribute as plain text with all HTML tags removed.
|
34
|
+
#
|
35
|
+
# message = Message.create!(content: "<h1>Funny times!</h1>")
|
36
|
+
# message.content.to_plain_text # => "Funny times!"
|
21
37
|
def to_plain_text
|
22
38
|
body&.to_plain_text.to_s
|
23
39
|
end
|
24
40
|
|
41
|
+
# Returns the +body+ attribute in a format that makes it editable in the Trix
|
42
|
+
# editor. Previews of attachments are rendered inline.
|
43
|
+
#
|
44
|
+
# content = "<h1>Funny Times!</h1><figure data-trix-attachment='{\"sgid\":\"..."\}'></figure>"
|
45
|
+
# message = Message.create!(content: content)
|
46
|
+
# message.content.to_trix_html # =>
|
47
|
+
# # <div class="trix-content">
|
48
|
+
# # <h1>Funny times!</h1>
|
49
|
+
# # <figure data-trix-attachment='{\"sgid\":\"..."\}'>
|
50
|
+
# # <img src="http://example.org/rails/active_storage/.../funny.jpg">
|
51
|
+
# # </figure>
|
52
|
+
# # </div>
|
25
53
|
def to_trix_html
|
26
54
|
body&.to_trix_html
|
27
55
|
end
|
@@ -1,12 +1,31 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActionText
|
4
|
+
# = Action Text \Attachable
|
5
|
+
#
|
6
|
+
# Include this module to make a record attachable to an ActionText::Content.
|
7
|
+
#
|
8
|
+
# class Person < ApplicationRecord
|
9
|
+
# include ActionText::Attachable
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
# person = Person.create! name: "Javan"
|
13
|
+
# html = %Q(<action-text-attachment sgid="#{person.attachable_sgid}"></action-text-attachment>)
|
14
|
+
# content = ActionText::Content.new(html)
|
15
|
+
# content.attachables # => [person]
|
4
16
|
module Attachable
|
5
17
|
extend ActiveSupport::Concern
|
6
18
|
|
7
19
|
LOCATOR_NAME = "attachable"
|
8
20
|
|
9
21
|
class << self
|
22
|
+
# Extracts the +ActionText::Attachable+ from the attachment HTML node:
|
23
|
+
#
|
24
|
+
# person = Person.create! name: "Javan"
|
25
|
+
# html = %Q(<action-text-attachment sgid="#{person.attachable_sgid}"></action-text-attachment>)
|
26
|
+
# fragment = ActionText::Fragment.wrap(html)
|
27
|
+
# attachment_node = fragment.find_all(ActionText::Attachment.tag_name).first
|
28
|
+
# ActionText::Attachable.from_node(attachment_node) # => person
|
10
29
|
def from_node(node)
|
11
30
|
if attachable = attachable_from_sgid(node["sgid"])
|
12
31
|
attachable
|
@@ -15,7 +34,7 @@ module ActionText
|
|
15
34
|
elsif attachable = ActionText::Attachables::RemoteImage.from_node(node)
|
16
35
|
attachable
|
17
36
|
else
|
18
|
-
ActionText::Attachables::MissingAttachable
|
37
|
+
ActionText::Attachables::MissingAttachable.new(node["sgid"])
|
19
38
|
end
|
20
39
|
end
|
21
40
|
|
@@ -37,8 +56,24 @@ module ActionText
|
|
37
56
|
def from_attachable_sgid(sgid)
|
38
57
|
ActionText::Attachable.from_attachable_sgid(sgid, only: self)
|
39
58
|
end
|
59
|
+
|
60
|
+
# Returns the path to the partial that is used for rendering missing attachables.
|
61
|
+
# Defaults to "action_text/attachables/missing_attachable".
|
62
|
+
#
|
63
|
+
# Override to render a different partial:
|
64
|
+
#
|
65
|
+
# class User < ApplicationRecord
|
66
|
+
# def self.to_missing_attachable_partial_path
|
67
|
+
# "users/missing_attachable"
|
68
|
+
# end
|
69
|
+
# end
|
70
|
+
def to_missing_attachable_partial_path
|
71
|
+
ActionText::Attachables::MissingAttachable::DEFAULT_PARTIAL_PATH
|
72
|
+
end
|
40
73
|
end
|
41
74
|
|
75
|
+
# Returns the Signed Global ID for the attachable. The purpose of the ID is
|
76
|
+
# set to 'attachable' so it can't be reused for other purposes.
|
42
77
|
def attachable_sgid
|
43
78
|
to_sgid(expires_in: nil, for: LOCATOR_NAME).to_s
|
44
79
|
end
|
@@ -63,14 +98,30 @@ module ActionText
|
|
63
98
|
false
|
64
99
|
end
|
65
100
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
101
|
+
# Returns the path to the partial that is used for rendering the attachable
|
102
|
+
# in Trix. Defaults to +to_partial_path+.
|
103
|
+
#
|
104
|
+
# Override to render a different partial:
|
105
|
+
#
|
106
|
+
# class User < ApplicationRecord
|
107
|
+
# def to_trix_content_attachment_partial_path
|
108
|
+
# "users/trix_content_attachment"
|
109
|
+
# end
|
110
|
+
# end
|
70
111
|
def to_trix_content_attachment_partial_path
|
71
112
|
to_partial_path
|
72
113
|
end
|
73
114
|
|
115
|
+
# Returns the path to the partial that is used for rendering the attachable.
|
116
|
+
# Defaults to +to_partial_path+.
|
117
|
+
#
|
118
|
+
# Override to render a different partial:
|
119
|
+
#
|
120
|
+
# class User < ApplicationRecord
|
121
|
+
# def to_attachable_partial_path
|
122
|
+
# "users/attachable"
|
123
|
+
# end
|
124
|
+
# end
|
74
125
|
def to_attachable_partial_path
|
75
126
|
to_partial_path
|
76
127
|
end
|
@@ -86,5 +137,18 @@ module ActionText
|
|
86
137
|
attrs[:height] = attachable_metadata[:height]
|
87
138
|
end.compact
|
88
139
|
end
|
140
|
+
|
141
|
+
private
|
142
|
+
def attribute_names_for_serialization
|
143
|
+
super + ["attachable_sgid"]
|
144
|
+
end
|
145
|
+
|
146
|
+
def read_attribute_for_serialization(key)
|
147
|
+
if key == "attachable_sgid"
|
148
|
+
persisted? ? super : nil
|
149
|
+
else
|
150
|
+
super
|
151
|
+
end
|
152
|
+
end
|
89
153
|
end
|
90
154
|
end
|
@@ -2,37 +2,39 @@
|
|
2
2
|
|
3
3
|
module ActionText
|
4
4
|
module Attachables
|
5
|
-
class ContentAttachment
|
5
|
+
class ContentAttachment # :nodoc:
|
6
6
|
include ActiveModel::Model
|
7
7
|
|
8
8
|
def self.from_node(node)
|
9
|
-
|
10
|
-
|
11
|
-
attachment = new(name: matches[1])
|
12
|
-
attachment if attachment.valid?
|
13
|
-
end
|
14
|
-
end
|
9
|
+
attachment = new(content_type: node["content-type"], content: node["content"])
|
10
|
+
attachment if attachment.valid?
|
15
11
|
end
|
16
12
|
|
17
|
-
attr_accessor :
|
18
|
-
|
13
|
+
attr_accessor :content_type, :content
|
14
|
+
|
15
|
+
validates_format_of :content_type, with: /html/
|
16
|
+
validates_presence_of :content
|
19
17
|
|
20
18
|
def attachable_plain_text_representation(caption)
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
19
|
+
content_instance.fragment.source
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_html
|
23
|
+
@to_html ||= content_instance.render(content_instance)
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_s
|
27
|
+
to_html
|
27
28
|
end
|
28
29
|
|
29
30
|
def to_partial_path
|
30
31
|
"action_text/attachables/content_attachment"
|
31
32
|
end
|
32
33
|
|
33
|
-
|
34
|
-
|
35
|
-
|
34
|
+
private
|
35
|
+
def content_instance
|
36
|
+
@content_instance ||= ActionText::Content.new(content)
|
37
|
+
end
|
36
38
|
end
|
37
39
|
end
|
38
40
|
end
|
@@ -2,11 +2,25 @@
|
|
2
2
|
|
3
3
|
module ActionText
|
4
4
|
module Attachables
|
5
|
-
|
5
|
+
class MissingAttachable
|
6
6
|
extend ActiveModel::Naming
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
DEFAULT_PARTIAL_PATH = "action_text/attachables/missing_attachable"
|
9
|
+
|
10
|
+
def initialize(sgid)
|
11
|
+
@sgid = SignedGlobalID.parse(sgid, for: ActionText::Attachable::LOCATOR_NAME)
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_partial_path
|
15
|
+
if model
|
16
|
+
model.to_missing_attachable_partial_path
|
17
|
+
else
|
18
|
+
DEFAULT_PARTIAL_PATH
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def model
|
23
|
+
@sgid&.model_name.to_s.safe_constantize
|
10
24
|
end
|
11
25
|
end
|
12
26
|
end
|