lexxy 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/assets/javascript/lexxy.js +3376 -2945
- data/app/assets/javascript/lexxy.js.br +0 -0
- data/app/assets/javascript/lexxy.js.gz +0 -0
- data/app/assets/javascript/lexxy.js.map +1 -1
- data/app/assets/javascript/lexxy.min.js +3 -3
- data/app/assets/javascript/lexxy.min.js.br +0 -0
- data/app/assets/javascript/lexxy.min.js.gz +0 -0
- data/app/assets/stylesheets/lexxy-content.css +133 -107
- data/app/assets/stylesheets/lexxy-editor.css +14 -1
- data/app/assets/stylesheets/lexxy-variables.css +1 -0
- data/config/ci.rb +4 -1
- data/lib/active_storage/blob_with_preview_url.rb +27 -6
- data/lib/lexxy/engine.rb +31 -25
- data/lib/lexxy/rich_text_area_tag.rb +2 -1
- data/lib/lexxy/version.rb +1 -1
- metadata +17 -3
|
Binary file
|
|
Binary file
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
:where(.lexxy-content) {
|
|
7
7
|
color: var(--lexxy-color-ink);
|
|
8
|
+
font-size: var(--lexxy-text-size);
|
|
8
9
|
|
|
9
10
|
h1, h2, h3, h4, h5, h6 {
|
|
10
11
|
display: block;
|
|
@@ -18,12 +19,12 @@
|
|
|
18
19
|
}
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
h1 { font-size:
|
|
22
|
-
h2 { font-size: 1.
|
|
23
|
-
h3 { font-size: 1.
|
|
24
|
-
h4 { font-size:
|
|
25
|
-
h5 { font-size: 0.
|
|
26
|
-
h6 { font-size: 0.
|
|
22
|
+
h1 { font-size: 2em; }
|
|
23
|
+
h2 { font-size: 1.5em; }
|
|
24
|
+
h3 { font-size: 1.25em; }
|
|
25
|
+
h4 { font-size: 1em; }
|
|
26
|
+
h5 { font-size: 0.875em; }
|
|
27
|
+
h6 { font-size: 0.75em; }
|
|
27
28
|
|
|
28
29
|
p,
|
|
29
30
|
ul,
|
|
@@ -31,8 +32,8 @@
|
|
|
31
32
|
dl,
|
|
32
33
|
blockquote,
|
|
33
34
|
figure,
|
|
34
|
-
.attachment,
|
|
35
|
-
.attachment-gallery {
|
|
35
|
+
:where(.attachment),
|
|
36
|
+
:where(.attachment-gallery) {
|
|
36
37
|
margin-block: 0 var(--lexxy-content-margin);
|
|
37
38
|
position: relative;
|
|
38
39
|
|
|
@@ -45,28 +46,28 @@
|
|
|
45
46
|
}
|
|
46
47
|
}
|
|
47
48
|
|
|
48
|
-
.lexxy-content__italic {
|
|
49
|
+
:where(.lexxy-content__italic) {
|
|
49
50
|
font-style: italic;
|
|
50
51
|
}
|
|
51
52
|
|
|
52
|
-
.lexxy-content__bold {
|
|
53
|
+
:where(.lexxy-content__bold) {
|
|
53
54
|
font-weight: bold;
|
|
54
55
|
}
|
|
55
56
|
|
|
56
|
-
.lexxy-content__strikethrough {
|
|
57
|
+
:where(.lexxy-content__strikethrough) {
|
|
57
58
|
text-decoration: line-through;
|
|
58
59
|
}
|
|
59
60
|
|
|
60
|
-
.lexxy-content__underline {
|
|
61
|
+
:where(.lexxy-content__underline) {
|
|
61
62
|
text-decoration: underline;
|
|
62
63
|
}
|
|
63
64
|
|
|
64
|
-
.lexxy-content__strikethrough.lexxy-content__underline {
|
|
65
|
+
:where(.lexxy-content__strikethrough.lexxy-content__underline) {
|
|
65
66
|
text-decoration: line-through underline;
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
mark,
|
|
69
|
-
.lexxy-content__highlight {
|
|
70
|
+
:where(.lexxy-content__highlight) {
|
|
70
71
|
background-color: transparent;
|
|
71
72
|
color: inherit;
|
|
72
73
|
}
|
|
@@ -77,6 +78,12 @@
|
|
|
77
78
|
margin: var(--lexxy-content-margin) 0;
|
|
78
79
|
padding: 0.5lh 2ch;
|
|
79
80
|
|
|
81
|
+
em,
|
|
82
|
+
i,
|
|
83
|
+
:where(.lexxy-content__italic) {
|
|
84
|
+
font-style: normal;
|
|
85
|
+
}
|
|
86
|
+
|
|
80
87
|
p:last-child {
|
|
81
88
|
margin-block-end: 0;
|
|
82
89
|
}
|
|
@@ -131,7 +138,7 @@
|
|
|
131
138
|
}
|
|
132
139
|
}
|
|
133
140
|
|
|
134
|
-
ol, ul:not(.lexxy-prompt-menu) {
|
|
141
|
+
ol, ul:not(:where(.lexxy-prompt-menu)) {
|
|
135
142
|
margin-inline-start: calc(var(--lexxy-content-margin) * 1.5);
|
|
136
143
|
padding: 0;
|
|
137
144
|
}
|
|
@@ -144,7 +151,7 @@
|
|
|
144
151
|
list-style-type: decimal;
|
|
145
152
|
}
|
|
146
153
|
|
|
147
|
-
li.lexxy-nested-listitem {
|
|
154
|
+
li:where(.lexxy-nested-listitem) {
|
|
148
155
|
list-style-type: none;
|
|
149
156
|
|
|
150
157
|
ol, ul {
|
|
@@ -168,6 +175,7 @@
|
|
|
168
175
|
}
|
|
169
176
|
}
|
|
170
177
|
|
|
178
|
+
/* Kept at class specificity so it still outweighs the element margin rules above. */
|
|
171
179
|
*:has(+ .horizontal-divider) {
|
|
172
180
|
margin-block-end: 0;
|
|
173
181
|
}
|
|
@@ -177,77 +185,77 @@
|
|
|
177
185
|
}
|
|
178
186
|
|
|
179
187
|
/* Keywords and attributes */
|
|
180
|
-
.code-token__attr,
|
|
181
|
-
.token.attr-name,
|
|
182
|
-
.token.atrule,
|
|
183
|
-
.token.attr,
|
|
184
|
-
.token.keyword {
|
|
188
|
+
:where(.code-token__attr),
|
|
189
|
+
:where(.token.attr-name),
|
|
190
|
+
:where(.token.atrule),
|
|
191
|
+
:where(.token.attr),
|
|
192
|
+
:where(.token.keyword) {
|
|
185
193
|
color: var(--lexxy-color-code-token-att);
|
|
186
194
|
}
|
|
187
195
|
|
|
188
196
|
/* Constants, booleans, numbers, properties, tags */
|
|
189
|
-
.code-token__property,
|
|
190
|
-
.token.boolean,
|
|
191
|
-
.token.constant,
|
|
192
|
-
.token.number,
|
|
193
|
-
.token.property,
|
|
194
|
-
.token.symbol,
|
|
195
|
-
.token.tag {
|
|
197
|
+
:where(.code-token__property),
|
|
198
|
+
:where(.token.boolean),
|
|
199
|
+
:where(.token.constant),
|
|
200
|
+
:where(.token.number),
|
|
201
|
+
:where(.token.property),
|
|
202
|
+
:where(.token.symbol),
|
|
203
|
+
:where(.token.tag) {
|
|
196
204
|
color: var(--lexxy-color-code-token-property);
|
|
197
205
|
}
|
|
198
206
|
|
|
199
207
|
/* Strings, selectors, and built-in constructs */
|
|
200
|
-
.code-token__selector,
|
|
201
|
-
.token.attr-value,
|
|
202
|
-
.token.builtin,
|
|
203
|
-
.token.char,
|
|
204
|
-
.token.inserted,
|
|
205
|
-
.token.line,
|
|
206
|
-
.token.selector,
|
|
207
|
-
.token.string {
|
|
208
|
+
:where(.code-token__selector),
|
|
209
|
+
:where(.token.attr-value),
|
|
210
|
+
:where(.token.builtin),
|
|
211
|
+
:where(.token.char),
|
|
212
|
+
:where(.token.inserted),
|
|
213
|
+
:where(.token.line),
|
|
214
|
+
:where(.token.selector),
|
|
215
|
+
:where(.token.string) {
|
|
208
216
|
color: var(--lexxy-color-code-token-selector);
|
|
209
217
|
}
|
|
210
218
|
|
|
211
219
|
/* Comments and meta information */
|
|
212
|
-
.code-token__comment,
|
|
213
|
-
.token.cdata,
|
|
214
|
-
.token.comment,
|
|
215
|
-
.token.doctype,
|
|
216
|
-
.token.prolog {
|
|
220
|
+
:where(.code-token__comment),
|
|
221
|
+
:where(.token.cdata),
|
|
222
|
+
:where(.token.comment),
|
|
223
|
+
:where(.token.doctype),
|
|
224
|
+
:where(.token.prolog) {
|
|
217
225
|
color: var(--lexxy-color-code-token-comment);
|
|
218
226
|
font-style: italic;
|
|
219
227
|
}
|
|
220
228
|
|
|
221
229
|
/* Operators and symbolic entities */
|
|
222
|
-
.code-token__operator,
|
|
223
|
-
.token.deleted,
|
|
224
|
-
.token.entity,
|
|
225
|
-
.token.operator,
|
|
226
|
-
.token.url,
|
|
227
|
-
code[data-language="diff"] .code-token__operator + .code-token__selector {
|
|
230
|
+
:where(.code-token__operator),
|
|
231
|
+
:where(.token.deleted),
|
|
232
|
+
:where(.token.entity),
|
|
233
|
+
:where(.token.operator),
|
|
234
|
+
:where(.token.url),
|
|
235
|
+
code[data-language="diff"] :where(.code-token__operator) + :where(.code-token__selector) {
|
|
228
236
|
color: var(--lexxy-color-code-token-operator);
|
|
229
237
|
}
|
|
230
238
|
|
|
231
239
|
/* Functions and class names */
|
|
232
|
-
.code-token__function,
|
|
233
|
-
.token.class,
|
|
234
|
-
.token.class-name,
|
|
235
|
-
.token.function {
|
|
240
|
+
:where(.code-token__function),
|
|
241
|
+
:where(.token.class),
|
|
242
|
+
:where(.token.class-name),
|
|
243
|
+
:where(.token.function) {
|
|
236
244
|
color: var(--lexxy-color-code-token-function);
|
|
237
245
|
}
|
|
238
246
|
|
|
239
247
|
/* Variables, regex, namespaces, important */
|
|
240
|
-
.code-token__variable,
|
|
241
|
-
.token.important,
|
|
242
|
-
.token.namespace,
|
|
243
|
-
.token.regex,
|
|
244
|
-
.token.variable {
|
|
248
|
+
:where(.code-token__variable),
|
|
249
|
+
:where(.token.important),
|
|
250
|
+
:where(.token.namespace),
|
|
251
|
+
:where(.token.regex),
|
|
252
|
+
:where(.token.variable) {
|
|
245
253
|
color: var(--lexxy-color-code-token-variable);
|
|
246
254
|
}
|
|
247
255
|
|
|
248
256
|
/* Punctuation */
|
|
249
|
-
.code-token__punctuation,
|
|
250
|
-
.token.punctuation {
|
|
257
|
+
:where(.code-token__punctuation),
|
|
258
|
+
:where(.token.punctuation) {
|
|
251
259
|
color: var(--lexxy-color-code-token-punctuation);
|
|
252
260
|
}
|
|
253
261
|
|
|
@@ -277,7 +285,7 @@
|
|
|
277
285
|
margin-block-end: 0;
|
|
278
286
|
}
|
|
279
287
|
|
|
280
|
-
|
|
288
|
+
&:where(.lexxy-content__table-cell--header) {
|
|
281
289
|
background-color: var(--lexxy-color-table-header-bg);
|
|
282
290
|
font-weight: bold;
|
|
283
291
|
}
|
|
@@ -297,11 +305,11 @@
|
|
|
297
305
|
/* Attachments
|
|
298
306
|
/* ------------------------------------------------------------------------ */
|
|
299
307
|
|
|
300
|
-
p:has(.attachment) {
|
|
308
|
+
p:has(:where(.attachment)) {
|
|
301
309
|
text-align: center;
|
|
302
310
|
}
|
|
303
311
|
|
|
304
|
-
.attachment {
|
|
312
|
+
:where(.attachment) {
|
|
305
313
|
--lexxy-attachment-gap: 0.75ch;
|
|
306
314
|
|
|
307
315
|
block-size: auto;
|
|
@@ -317,14 +325,19 @@
|
|
|
317
325
|
text-align: center;
|
|
318
326
|
}
|
|
319
327
|
|
|
320
|
-
.
|
|
328
|
+
/* Element weight, so a bare `figure { margin: 0 }` reset loaded before Lexxy doesn't uncenter attachments. */
|
|
329
|
+
figure:where(.attachment) {
|
|
330
|
+
margin-inline: auto;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
:where(.attachment__caption) {
|
|
321
334
|
color: var(--lexxy-color-text-subtle);
|
|
322
335
|
display: block;
|
|
323
336
|
font-size: var(--lexxy-text-small);
|
|
324
337
|
padding: 1ch;
|
|
325
338
|
}
|
|
326
339
|
|
|
327
|
-
.attachment__icon {
|
|
340
|
+
:where(.attachment__icon) {
|
|
328
341
|
aspect-ratio: 4/5;
|
|
329
342
|
background-color: color-mix(var(--lexxy-attachment-icon-color), transparent 90%);
|
|
330
343
|
block-size: 3lh;
|
|
@@ -343,7 +356,12 @@
|
|
|
343
356
|
white-space: nowrap;
|
|
344
357
|
}
|
|
345
358
|
|
|
346
|
-
.
|
|
359
|
+
/* Kept at class specificity so it still outweighs the `a:has(img)` rule above. */
|
|
360
|
+
.attachment--preview > a {
|
|
361
|
+
display: block;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
:where(.attachment--preview) {
|
|
347
365
|
img, video {
|
|
348
366
|
border-radius: var(--lexxy-radius);
|
|
349
367
|
block-size: auto;
|
|
@@ -357,16 +375,12 @@
|
|
|
357
375
|
}
|
|
358
376
|
}
|
|
359
377
|
|
|
360
|
-
|
|
361
|
-
display: block;
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
.attachment__caption {
|
|
378
|
+
:where(.attachment__caption) {
|
|
365
379
|
padding-block-end: 0.5ch;
|
|
366
380
|
}
|
|
367
381
|
}
|
|
368
382
|
|
|
369
|
-
.attachment--file {
|
|
383
|
+
:where(.attachment--file) {
|
|
370
384
|
--lexxy-attachment-icon-color: var(--lexxy-color-text-subtle);
|
|
371
385
|
|
|
372
386
|
align-items: center;
|
|
@@ -374,59 +388,59 @@
|
|
|
374
388
|
flex-wrap: wrap;
|
|
375
389
|
inline-size: auto;
|
|
376
390
|
|
|
377
|
-
.attachment__caption {
|
|
391
|
+
:where(.attachment__caption) {
|
|
378
392
|
display: grid;
|
|
379
393
|
flex: 1;
|
|
380
394
|
text-align: start;
|
|
381
395
|
}
|
|
382
396
|
|
|
383
|
-
.attachment__name {
|
|
397
|
+
:where(.attachment__name) {
|
|
384
398
|
color: var(--lexxy-color-ink);
|
|
385
399
|
font-weight: bold;
|
|
386
400
|
}
|
|
387
401
|
}
|
|
388
402
|
|
|
389
|
-
.attachment--psd,
|
|
390
|
-
.attachment--key,
|
|
391
|
-
.attachment--sketch,
|
|
392
|
-
.attachment--ai,
|
|
393
|
-
.attachment--eps,
|
|
394
|
-
.attachment--indd,
|
|
395
|
-
.attachment--svg,
|
|
396
|
-
.attachment--ppt,
|
|
397
|
-
.attachment--pptx {
|
|
403
|
+
:where(.attachment--psd),
|
|
404
|
+
:where(.attachment--key),
|
|
405
|
+
:where(.attachment--sketch),
|
|
406
|
+
:where(.attachment--ai),
|
|
407
|
+
:where(.attachment--eps),
|
|
408
|
+
:where(.attachment--indd),
|
|
409
|
+
:where(.attachment--svg),
|
|
410
|
+
:where(.attachment--ppt),
|
|
411
|
+
:where(.attachment--pptx) {
|
|
398
412
|
--lexxy-attachment-icon-color: var(--lexxy-color-red);
|
|
399
413
|
}
|
|
400
414
|
|
|
401
|
-
.attachment--css,
|
|
402
|
-
.attachment--php,
|
|
403
|
-
.attachment--json,
|
|
404
|
-
.attachment--htm,
|
|
405
|
-
.attachment--html,
|
|
406
|
-
.attachment--rb,
|
|
407
|
-
.attachment--erb,
|
|
408
|
-
.attachment--ts,
|
|
409
|
-
.attachment--js {
|
|
415
|
+
:where(.attachment--css),
|
|
416
|
+
:where(.attachment--php),
|
|
417
|
+
:where(.attachment--json),
|
|
418
|
+
:where(.attachment--htm),
|
|
419
|
+
:where(.attachment--html),
|
|
420
|
+
:where(.attachment--rb),
|
|
421
|
+
:where(.attachment--erb),
|
|
422
|
+
:where(.attachment--ts),
|
|
423
|
+
:where(.attachment--js) {
|
|
410
424
|
--lexxy-attachment-icon-color: var(--lexxy-color-purple);
|
|
411
425
|
}
|
|
412
426
|
|
|
413
|
-
.attachment--txt,
|
|
414
|
-
.attachment--pages,
|
|
415
|
-
.attachment--rtf,
|
|
416
|
-
.attachment--md,
|
|
417
|
-
.attachment--doc,
|
|
418
|
-
.attachment--docx {
|
|
427
|
+
:where(.attachment--txt),
|
|
428
|
+
:where(.attachment--pages),
|
|
429
|
+
:where(.attachment--rtf),
|
|
430
|
+
:where(.attachment--md),
|
|
431
|
+
:where(.attachment--doc),
|
|
432
|
+
:where(.attachment--docx) {
|
|
419
433
|
--lexxy-attachment-icon-color: var(--lexxy-color-blue);
|
|
420
434
|
}
|
|
421
435
|
|
|
422
|
-
.attachment--csv,
|
|
423
|
-
.attachment--numbers,
|
|
424
|
-
.attachment--xls,
|
|
425
|
-
.attachment--xlsx {
|
|
436
|
+
:where(.attachment--csv),
|
|
437
|
+
:where(.attachment--numbers),
|
|
438
|
+
:where(.attachment--xls),
|
|
439
|
+
:where(.attachment--xlsx) {
|
|
426
440
|
--lexxy-attachment-icon-color: var(--lexxy-color-green);
|
|
427
441
|
}
|
|
428
442
|
|
|
429
|
-
.attachment--error {
|
|
443
|
+
:where(.attachment--error) {
|
|
430
444
|
padding-block: 2ch;
|
|
431
445
|
}
|
|
432
446
|
|
|
@@ -434,25 +448,25 @@
|
|
|
434
448
|
/* Image galleries */
|
|
435
449
|
/* ------------------------------------------------------------------------ */
|
|
436
450
|
|
|
437
|
-
.attachment-gallery {
|
|
451
|
+
:where(.attachment-gallery) {
|
|
438
452
|
display: block;
|
|
439
453
|
text-align: center;
|
|
440
454
|
|
|
441
|
-
.attachment {
|
|
455
|
+
:where(.attachment) {
|
|
442
456
|
display: inline-flex;
|
|
443
457
|
flex-direction: column;
|
|
444
458
|
gap: 0;
|
|
445
459
|
inline-size: calc(33.333% - 0.8ch);
|
|
446
460
|
vertical-align: top;
|
|
447
461
|
|
|
448
|
-
.attachment__caption {
|
|
462
|
+
:where(.attachment__caption) {
|
|
449
463
|
padding-block-end: 1ch;
|
|
450
464
|
}
|
|
451
465
|
}
|
|
452
466
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
.attachment {
|
|
467
|
+
&:where(.attachment-gallery--2),
|
|
468
|
+
&:where(.attachment-gallery--4) {
|
|
469
|
+
:where(.attachment) {
|
|
456
470
|
inline-size: calc(50% - 0.8ch);
|
|
457
471
|
}
|
|
458
472
|
}
|
|
@@ -478,6 +492,17 @@
|
|
|
478
492
|
position: relative;
|
|
479
493
|
white-space: normal;
|
|
480
494
|
|
|
495
|
+
/* Gecko drops the whole selection when a drag crosses a contenteditable="false"
|
|
496
|
+
island unless it is selectable as a single unit. Editor-only: the rendered
|
|
497
|
+
view has no contenteditable and must keep normal text selection. */
|
|
498
|
+
lexxy-editor & {
|
|
499
|
+
-webkit-user-select: all;
|
|
500
|
+
|
|
501
|
+
@supports (user-select: all) {
|
|
502
|
+
user-select: all;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
481
506
|
img {
|
|
482
507
|
block-size: var(--lexxy-attachment-image-size);
|
|
483
508
|
border-radius: 50%;
|
|
@@ -489,6 +514,7 @@
|
|
|
489
514
|
/* Horizontal divider */
|
|
490
515
|
/* ------------------------------------------------------------------------ */
|
|
491
516
|
|
|
517
|
+
/* Kept at class specificity: the editor renders the divider as a figure, and this must outweigh the figure margin rule above. */
|
|
492
518
|
.horizontal-divider {
|
|
493
519
|
margin: 0;
|
|
494
520
|
margin-block-end: .5em;
|
|
@@ -457,6 +457,14 @@
|
|
|
457
457
|
display: none;
|
|
458
458
|
}
|
|
459
459
|
|
|
460
|
+
&[data-tables="false"] button[name="table"] {
|
|
461
|
+
display: none;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
&[data-code-blocks="false"][data-inline-code="false"] button[name="code"] {
|
|
465
|
+
display: none;
|
|
466
|
+
}
|
|
467
|
+
|
|
460
468
|
&[data-upload="file"] button[name="image"] {
|
|
461
469
|
display: none;
|
|
462
470
|
}
|
|
@@ -681,7 +689,7 @@
|
|
|
681
689
|
gap: var(--lexxy-toolbar-spacing);
|
|
682
690
|
}
|
|
683
691
|
|
|
684
|
-
input
|
|
692
|
+
input {
|
|
685
693
|
background-color: var(--lexxy-color-canvas);
|
|
686
694
|
border: 1px solid var(--lexxy-color-ink-lighter);
|
|
687
695
|
border-radius: var(--lexxy-radius);
|
|
@@ -1105,6 +1113,11 @@
|
|
|
1105
1113
|
overflow: auto;
|
|
1106
1114
|
padding: var(--lexxy-prompt-padding);
|
|
1107
1115
|
position: absolute;
|
|
1116
|
+
scroll-padding-block: calc(var(--lexxy-prompt-avatar-size) + var(--lexxy-prompt-padding) * 3);
|
|
1117
|
+
/* eslint-disable-next-line css/use-baseline */
|
|
1118
|
+
scrollbar-color: var(--lexxy-color-ink-light) transparent;
|
|
1119
|
+
/* eslint-disable-next-line css/use-baseline */
|
|
1120
|
+
scrollbar-width: thin;
|
|
1108
1121
|
visibility: hidden;
|
|
1109
1122
|
z-index: var(--lexxy-z-popup);
|
|
1110
1123
|
|
data/config/ci.rb
CHANGED
|
@@ -10,7 +10,10 @@ CI.run do
|
|
|
10
10
|
step "Tests: Rails (prepare)", "env RAILS_ENV=test bin/rails db:test:prepare"
|
|
11
11
|
step "Tests: Rails (run)", "env RAILS_ENV=test bin/rails test:all -d"
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
# --with-deps installs the browser's system libraries with apt-get, so it fails on
|
|
14
|
+
# Linux distributions without it, like Arch. Skip it there.
|
|
15
|
+
apt_less_linux = RUBY_PLATFORM.include?("linux") && !system("command -v apt-get > /dev/null")
|
|
16
|
+
step "Tests: Playwright (install)", "npx playwright install #{"--with-deps " unless apt_less_linux}chromium"
|
|
14
17
|
step "Tests: Playwright (run)", "yarn test:browser:chromium"
|
|
15
18
|
|
|
16
19
|
unless success?
|
|
@@ -3,16 +3,37 @@ module ActiveStorage
|
|
|
3
3
|
PREVIEW_SIZE = [ 1024, 768 ]
|
|
4
4
|
|
|
5
5
|
def as_json(options = nil)
|
|
6
|
-
json = super
|
|
6
|
+
json = super
|
|
7
|
+
options ||= {}
|
|
7
8
|
|
|
8
|
-
if previewable?
|
|
9
|
-
json[
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
)
|
|
9
|
+
if previewable? && ActiveStorage::Current.url_options
|
|
10
|
+
attributes = (root = preview_json_root(options)) ? json[root] : json
|
|
11
|
+
attributes["previewable"] = true if serializes_preview_field?("previewable", options)
|
|
12
|
+
attributes["url"] = preview_url_path if serializes_preview_field?("url", options)
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
json
|
|
16
16
|
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
def preview_json_root(options)
|
|
20
|
+
root = options.key?(:root) ? options[:root] : include_root_in_json
|
|
21
|
+
root == true ? model_name.element : root
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Mirrors Active Model: only takes precedence over except.
|
|
25
|
+
def serializes_preview_field?(field, options)
|
|
26
|
+
if only = options[:only]
|
|
27
|
+
Array(only).map(&:to_s).include?(field)
|
|
28
|
+
else
|
|
29
|
+
Array(options[:except]).map(&:to_s).exclude?(field)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def preview_url_path
|
|
34
|
+
Rails.application.routes.url_helpers.rails_representation_path(
|
|
35
|
+
preview(resize_to_limit: PREVIEW_SIZE), ActiveStorage::Current.url_options.merge(only_path: true)
|
|
36
|
+
)
|
|
37
|
+
end
|
|
17
38
|
end
|
|
18
39
|
end
|
data/lib/lexxy/engine.rb
CHANGED
|
@@ -7,13 +7,38 @@ module Lexxy
|
|
|
7
7
|
isolate_namespace Lexxy
|
|
8
8
|
|
|
9
9
|
config.lexxy = ActiveSupport::OrderedOptions.new
|
|
10
|
+
config.lexxy.override_action_text_defaults = true
|
|
11
|
+
|
|
12
|
+
# Rails versions that include Lexxy register it as an editor and allow its markup in
|
|
13
|
+
# Action Text content themselves, so sanitizer lists are left to the application there.
|
|
14
|
+
# This runs before Lexxy registers itself as an editor.
|
|
15
|
+
initializer "lexxy.sanitization", before: "lexxy.action_text_editor" do |app|
|
|
16
|
+
next if app.config.action_text.editors&.key?(:lexxy)
|
|
17
|
+
|
|
18
|
+
ActiveSupport.on_load(:action_text_content) do
|
|
19
|
+
default_allowed_tags = Class.new.include(ActionText::ContentHelper).new.sanitizer_allowed_tags
|
|
20
|
+
ActionText::ContentHelper.allowed_tags = default_allowed_tags + %w[ s u video audio source embed table tbody tr th td ]
|
|
21
|
+
|
|
22
|
+
default_allowed_attributes = Class.new.include(ActionText::ContentHelper).new.sanitizer_allowed_attributes
|
|
23
|
+
ActionText::ContentHelper.allowed_attributes = default_allowed_attributes + %w[ controls poster data-language style value start ]
|
|
24
|
+
|
|
25
|
+
Loofah::HTML5::SafeList::ALLOWED_CSS_FUNCTIONS << "var"
|
|
26
|
+
end
|
|
27
|
+
end
|
|
10
28
|
|
|
11
29
|
if Lexxy.supports_editor_adapter?
|
|
12
30
|
require_relative "../action_text/editor/lexxy_editor"
|
|
13
31
|
|
|
14
32
|
initializer "lexxy.action_text_editor", before: "action_text.editors" do |app|
|
|
15
|
-
app.config.action_text
|
|
16
|
-
|
|
33
|
+
action_text = app.config.action_text
|
|
34
|
+
|
|
35
|
+
# Rails versions that include Lexxy register it themselves and choose the
|
|
36
|
+
# default editor with config.load_defaults. When Lexxy is already registered,
|
|
37
|
+
# config.action_text.editor is left to the application.
|
|
38
|
+
unless action_text.editors.key?(:lexxy)
|
|
39
|
+
action_text.editors[:lexxy] = {}
|
|
40
|
+
action_text.editor = :lexxy if app.config.lexxy.override_action_text_defaults
|
|
41
|
+
end
|
|
17
42
|
end
|
|
18
43
|
else
|
|
19
44
|
# Rails 8.0/8.1 fallback: monkey-patch Action Text helpers
|
|
@@ -22,12 +47,12 @@ module Lexxy
|
|
|
22
47
|
require_relative "form_builder"
|
|
23
48
|
require_relative "action_text_tag"
|
|
24
49
|
|
|
25
|
-
config.lexxy.override_action_text_defaults = true
|
|
26
|
-
|
|
27
50
|
initializer "lexxy.initialize" do |app|
|
|
28
51
|
app.config.to_prepare do
|
|
29
|
-
|
|
30
|
-
|
|
52
|
+
# This runs again on every reload, and on recent Rubies prepending a module into a
|
|
53
|
+
# module again adds another copy to the classes that include it.
|
|
54
|
+
ActionText::TagHelper.prepend(Lexxy::TagHelper) unless ActionText::TagHelper.include?(Lexxy::TagHelper)
|
|
55
|
+
ActionView::Helpers::FormHelper.prepend(Lexxy::FormHelper) unless ActionView::Helpers::FormHelper.include?(Lexxy::FormHelper)
|
|
31
56
|
ActionView::Helpers::FormBuilder.prepend(Lexxy::FormBuilder)
|
|
32
57
|
ActionView::Helpers::Tags::ActionText.prepend(Lexxy::ActionTextTag)
|
|
33
58
|
|
|
@@ -42,25 +67,6 @@ module Lexxy
|
|
|
42
67
|
end
|
|
43
68
|
end
|
|
44
69
|
|
|
45
|
-
initializer "lexxy.assets" do |app|
|
|
46
|
-
if Rails.application.config.respond_to?(:assets)
|
|
47
|
-
app.config.assets.paths << root.join("app/assets/stylesheets")
|
|
48
|
-
app.config.assets.paths << root.join("app/javascript")
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
initializer "lexxy.sanitization" do |app|
|
|
53
|
-
ActiveSupport.on_load(:action_text_content) do
|
|
54
|
-
default_allowed_tags = Class.new.include(ActionText::ContentHelper).new.sanitizer_allowed_tags
|
|
55
|
-
ActionText::ContentHelper.allowed_tags = default_allowed_tags + %w[ video audio source embed table tbody tr th td ]
|
|
56
|
-
|
|
57
|
-
default_allowed_attributes = Class.new.include(ActionText::ContentHelper).new.sanitizer_allowed_attributes
|
|
58
|
-
ActionText::ContentHelper.allowed_attributes = default_allowed_attributes + %w[ controls poster data-language style value start ]
|
|
59
|
-
|
|
60
|
-
Loofah::HTML5::SafeList::ALLOWED_CSS_FUNCTIONS << "var"
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
|
|
64
70
|
initializer "lexxy.blob_with_preview" do |app|
|
|
65
71
|
ActiveSupport.on_load(:active_storage_blob) do
|
|
66
72
|
prepend ActiveStorage::BlobWithPreviewUrl
|
|
@@ -25,7 +25,7 @@ module Lexxy
|
|
|
25
25
|
# Temporary: we need to *adaptarize* action text
|
|
26
26
|
def render_custom_attachments_in(value)
|
|
27
27
|
if value.respond_to?(:body)
|
|
28
|
-
if html = value.
|
|
28
|
+
if html = value.body&.to_html.presence
|
|
29
29
|
self.prefix_partial_path_with_controller_namespace = false if respond_to?(:prefix_partial_path_with_controller_namespace=)
|
|
30
30
|
ActionText::Fragment.wrap(html).replace(ActionText::Attachment.tag_name) do |node|
|
|
31
31
|
if node["url"].blank?
|
|
@@ -33,6 +33,7 @@ module Lexxy
|
|
|
33
33
|
node["content"] = render_action_text_attachment(attachment).to_json
|
|
34
34
|
node["content-type"] ||= attachment.content_type
|
|
35
35
|
end
|
|
36
|
+
|
|
36
37
|
node
|
|
37
38
|
end
|
|
38
39
|
end
|
data/lib/lexxy/version.rb
CHANGED