@37signals/lexxy 0.9.29 → 0.9.30
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.
- package/dist/lexxy.esm.js +31 -4
- package/package.json +1 -1
package/dist/lexxy.esm.js
CHANGED
|
@@ -15,7 +15,7 @@ import { HistoryExtension } from '@lexical/history';
|
|
|
15
15
|
import { $isCodeNode, CodeHighlightNode, PrismTokenizer, $isCodeHighlightNode, $createCodeNode, $createCodeHighlightNode, CodeNode, registerCodeHighlighting, normalizeCodeLang, CODE_LANGUAGE_FRIENDLY_NAME_MAP } from '@lexical/code';
|
|
16
16
|
import { TRANSFORMERS, registerMarkdownShortcuts } from '@lexical/markdown';
|
|
17
17
|
import { INSERT_TABLE_COMMAND, $getTableCellNodeFromLexicalNode, TableCellNode, TableNode, TableRowNode, setScrollableTablesActive, registerTablePlugin, registerTableSelectionObserver, TableCellHeaderStates, $insertTableRowAtSelection, $insertTableColumnAtSelection, $deleteTableRowAtSelection, $deleteTableColumnAtSelection, $findTableNode, $getTableRowIndexFromTableCellNode, $getTableColumnIndexFromTableCellNode, $findCellNode, $getElementForTableNode } from '@lexical/table';
|
|
18
|
-
import {
|
|
18
|
+
import { Marked } from 'marked';
|
|
19
19
|
import { $insertDataTransferForRichText } from '@lexical/clipboard';
|
|
20
20
|
import 'prismjs';
|
|
21
21
|
import 'prismjs/components/prism-clike';
|
|
@@ -67,6 +67,22 @@ function styleFilterHook(_currentNode, hookEvent) {
|
|
|
67
67
|
|
|
68
68
|
DOMPurify.addHook("uponSanitizeAttribute", styleFilterHook);
|
|
69
69
|
|
|
70
|
+
const FORBIDDEN_STIMULUS_ATTRIBUTES = [ "data-controller", "data-action" ];
|
|
71
|
+
|
|
72
|
+
// Stimulus behavior attributes must never survive sanitization, whatever an
|
|
73
|
+
// extension's allowedElements declares. FORBID_ATTR alone isn't enough: in
|
|
74
|
+
// DOMPurify 3.x the functional ADD_ATTR — which Lexxy builds from the public
|
|
75
|
+
// allowedElements API — is evaluated ahead of FORBID_ATTR, so an extension that
|
|
76
|
+
// listed one of these on a tag would otherwise reinstate it. This hook drops
|
|
77
|
+
// them unconditionally, keeping the class-level prohibition config-independent.
|
|
78
|
+
function stimulusAttributeFilterHook(_currentNode, hookEvent) {
|
|
79
|
+
if (FORBIDDEN_STIMULUS_ATTRIBUTES.includes(hookEvent.attrName)) {
|
|
80
|
+
hookEvent.keepAttr = false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
DOMPurify.addHook("uponSanitizeAttribute", stimulusAttributeFilterHook);
|
|
85
|
+
|
|
70
86
|
DOMPurify.addHook("uponSanitizeElement", (node, data) => {
|
|
71
87
|
if (data.tagName === "strong" || data.tagName === "em") {
|
|
72
88
|
node.removeAttribute("class");
|
|
@@ -90,7 +106,12 @@ function buildConfig(allowedElements ) {
|
|
|
90
106
|
ALLOWED_ATTR: ALLOWED_HTML_ATTRIBUTES,
|
|
91
107
|
ADD_ATTR: (attribute, tag) => tagAttributes[tag]?.includes(attribute),
|
|
92
108
|
ADD_URI_SAFE_ATTR: [ "caption", "filename" ],
|
|
93
|
-
SAFE_FOR_XML: false // So that it does not strip attributes that contains serialized HTML (like content)
|
|
109
|
+
SAFE_FOR_XML: false, // So that it does not strip attributes that contains serialized HTML (like content)
|
|
110
|
+
// Stimulus behavior attributes must never survive sanitization: they let stored content
|
|
111
|
+
// wire up arbitrary controllers/actions in the viewer's session. FORBID_ATTR wins over
|
|
112
|
+
// ALLOWED_ATTR/ADD_ATTR/ALLOW_DATA_ATTR in DOMPurify, so this holds even though other
|
|
113
|
+
// data-* attributes (data-language, data-trix-*, etc.) are otherwise allowed through.
|
|
114
|
+
FORBID_ATTR: [ "data-controller", "data-action" ]
|
|
94
115
|
}
|
|
95
116
|
}
|
|
96
117
|
|
|
@@ -6348,7 +6369,7 @@ class Contents {
|
|
|
6348
6369
|
insertText(text, { tag } = {}) {
|
|
6349
6370
|
this.editor.update(() => {
|
|
6350
6371
|
const paragraph = $createParagraphNode();
|
|
6351
|
-
text.split(
|
|
6372
|
+
text.split(/\r\n|\r|\n/).forEach((line, index) => {
|
|
6352
6373
|
if (index > 0) paragraph.append($createLineBreakNode());
|
|
6353
6374
|
paragraph.append($createTextNode(line));
|
|
6354
6375
|
});
|
|
@@ -6990,6 +7011,12 @@ class Contents {
|
|
|
6990
7011
|
}
|
|
6991
7012
|
}
|
|
6992
7013
|
|
|
7014
|
+
// Markdown reads any line indented by a tab or four spaces as a code block. Pasted
|
|
7015
|
+
// plain text is full of incidental indentation — outlines, notes, logs — and nobody
|
|
7016
|
+
// indents a note meaning "this is code"; they fence it. Keep fences, drop the
|
|
7017
|
+
// indentation rule.
|
|
7018
|
+
const pastedMarkdown = new Marked({ breaks: true }).use({ tokenizer: { code: () => undefined } });
|
|
7019
|
+
|
|
6993
7020
|
class Clipboard {
|
|
6994
7021
|
#listeners = new ListenerBin()
|
|
6995
7022
|
|
|
@@ -7176,7 +7203,7 @@ class Clipboard {
|
|
|
7176
7203
|
}
|
|
7177
7204
|
|
|
7178
7205
|
#pasteMarkdown(text) {
|
|
7179
|
-
const html =
|
|
7206
|
+
const html = pastedMarkdown.parse(text);
|
|
7180
7207
|
const doc = parseHtml(html);
|
|
7181
7208
|
|
|
7182
7209
|
if (this.#isPlainTextWithoutMarkdown(doc)) {
|