Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/frontend/editors/slate/elements/html/editable.tsx
1698 views
1
/*
2
* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.
3
* License: MS-RSL – see LICENSE.md for details
4
*/
5
6
import { useState } from "react";
7
import { register } from "../register";
8
import { useFocused, useSelected, useSlate } from "../hooks";
9
import { ensure_ends_in_two_newline, FOCUSED_COLOR } from "../../util";
10
import { SlateCodeMirror } from "../codemirror";
11
import { useSetElement } from "../set-element";
12
import HTML from "@cocalc/frontend/components/html-ssr";
13
14
function isBR(s: string): boolean {
15
const x = s.toLowerCase().replace(/\s/g, "");
16
return x == "<br>" || x == "<br/>";
17
}
18
19
const Element = ({ attributes, children, element }) => {
20
const focused = useFocused();
21
const selected = useSelected();
22
const border =
23
focused && selected
24
? `1px solid ${FOCUSED_COLOR}`
25
: `1px solid transparent`;
26
const html = ((element.html as string) ?? "").trim();
27
28
// this feels ugly in practice, and we have the source so not doing it.
29
const is_comment = false;
30
// const is_comment = html.startsWith("<!--") && html.endsWith("-->");
31
32
// mode for editing the raw html
33
const [editMode, setEditMode] = useState<boolean>(false);
34
const editor = useSlate();
35
36
const setElement = useSetElement(editor, element);
37
38
function renderEditMode() {
39
if (!editMode) return;
40
return (
41
<div style={{ boxShadow: "8px 8px 4px #888" }}>
42
<SlateCodeMirror
43
value={html}
44
onChange={(html) => {
45
setElement({ html });
46
}}
47
onBlur={() => setEditMode(false)}
48
info="html"
49
options={{
50
lineWrapping: true,
51
autofocus: true,
52
autoCloseTags: true,
53
smartIndent: true,
54
}}
55
isInline={element["type"] == "html_inline"}
56
/>
57
</div>
58
);
59
}
60
61
if (element.type == "html_inline") {
62
return (
63
<span {...attributes}>
64
{renderEditMode()}
65
<code
66
style={{ color: is_comment ? "#a50" : "#aaa", border }}
67
onClick={() => {
68
setEditMode(true);
69
}}
70
>
71
{html}
72
</code>
73
{isBR(html) && <br />}
74
{children}
75
</span>
76
);
77
} else {
78
if (is_comment) {
79
return (
80
<div {...attributes}>
81
<div style={{ color: "#a50" }}>{html}</div>
82
{children}
83
</div>
84
);
85
}
86
return (
87
<div {...attributes}>
88
<div
89
style={{ border }}
90
contentEditable={false}
91
onDoubleClick={() => {
92
setEditMode(true);
93
}}
94
>
95
<HTML value={html} />
96
{renderEditMode()}
97
</div>
98
{children}
99
</div>
100
);
101
}
102
};
103
104
register({
105
slateType: "html_inline",
106
Element,
107
fromSlate: ({ node }) => node.html as string,
108
});
109
110
register({
111
slateType: "html_block",
112
Element,
113
fromSlate: ({ node }) => ensure_ends_in_two_newline(node.html as string),
114
});
115
116