actiontext 7.0.8 → 7.1.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +37 -135
- 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 +4 -4
- 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 +7 -6
- metadata +17 -15
@@ -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
|