Skip to content

Commit ea0c1ce

Browse files
committed
rename immortal dom to stable unsafe html; implemented 'garbage collection' via lru cache
- i don't think I like this and am going to try a ttl cache instead
1 parent dd689f0 commit ea0c1ce

File tree

3 files changed

+46
-16
lines changed

3 files changed

+46
-16
lines changed

src/packages/frontend/jupyter/output-messages/iframe.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,19 +31,25 @@ interface Props {
3131
project_id: string;
3232
cacheId?: string;
3333
index?: number;
34+
trust?: boolean;
3435
}
3536

3637
export default function IFrame(props: Props) {
3738
// we only use cached iframe if the iframecontext is setup, e.g., it is in Jupyter notebooks, but not in whiteboards.
3839
const iframeContext = useIFrameContext();
39-
if (iframeContext.iframeDivRef == null || props.cacheId == null) {
40+
if (
41+
iframeContext.iframeDivRef == null ||
42+
props.cacheId == null ||
43+
!props.trust
44+
) {
4045
return <NonCachedIFrame {...props} />;
4146
} else {
4247
const src = get_blob_url(props.project_id, "html", props.sha1);
4348
return (
4449
<HTML
4550
id={props.cacheId}
4651
index={props.index}
52+
trust={props.trust}
4753
value={`<iframe src="${src}" style="border:0;height:${HEIGHT};width:${WIDTH}"/>`}
4854
/>
4955
);

src/packages/frontend/jupyter/output-messages/mime-types/html.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,24 @@
11
import register from "./register";
2-
//import HTML from "@cocalc/frontend/components/html-ssr";
3-
import ImmortalDomNode from "../immortal-dom-node";
2+
import HTML from "@cocalc/frontend/components/html-ssr";
3+
import StableUnsafeHtml from "../stable-unsafe-html";
44

55
const Html = ({
66
value,
77
id,
88
index,
9+
trust,
910
}: {
1011
value: string;
1112
id?: string;
1213
index?: number;
14+
trust?: boolean;
1315
}) => {
14-
// <HTML value={value} />
15-
console.log("HTML", { id, index });
16+
if (!trust) {
17+
<HTML value={value} />;
18+
}
1619
return (
1720
<div style={{ margin: "5px 0" }}>
18-
<ImmortalDomNode html={value} docId={`${id}-${index}`} />
21+
<StableUnsafeHtml html={value} docId={`${id}-${index}`} />
1922
</div>
2023
);
2124
};

src/packages/frontend/jupyter/output-messages/immortal-dom-node.tsx renamed to src/packages/frontend/jupyter/output-messages/stable-unsafe-html.tsx

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
/*
2-
Create an immortal DOM node. This is a way to render HTML that stays stable
2+
Create stable unsafe HTML DOM node. This is a way to render HTML that stays stable
33
irregardless of it being unmounted/remounted.
4-
This supports virtualization, window splitting, etc., without loss of state.
4+
This supports virtualization, window splitting, etc., without loss of state...
5+
unless there are too many of them, then we delete the oldest.
6+
7+
Unsafe is in the name since there is NO SANITIZATION. Only use this on trusted
8+
documents.
59
*/
610

711
import { useCallback, useEffect, useRef } from "react";
@@ -16,11 +20,24 @@ interface Props {
1620
zIndex?: number;
1721
}
1822

19-
const immortals: { [globalKey: string]: any } = {};
23+
import LRU from "lru-cache";
24+
25+
const CACHE_SIZE = 100;
26+
27+
const immortals = new LRU<string, any>({
28+
max: CACHE_SIZE,
29+
updateAgeOnGet: true,
30+
updateAgeOnHas: true,
31+
dispose: (elt) => {
32+
elt.empty();
33+
elt.remove();
34+
},
35+
});
36+
// const immortals: { [globalKey: string]: any } = {};
2037

2138
const Z_INDEX = 1;
2239

23-
const SCROLL_COUNT = 10;
40+
const SCROLL_COUNT = 25;
2441

2542
// make it really standout:
2643
// const PADDING = 5;
@@ -35,7 +52,7 @@ const SCROLL_COUNT = 10;
3552
const PADDING = 0;
3653
const STYLE = {} as const;
3754

38-
export default function ImmortalDomNode({
55+
export default function StableUnsafeHtml({
3956
docId,
4057
html,
4158
zIndex = Z_INDEX, // todo: support changing?
@@ -117,14 +134,18 @@ export default function ImmortalDomNode({
117134
}, []);
118135

119136
const getElt = () => {
120-
if (immortals[globalKey] == null) {
121-
const elt = (immortals[globalKey] = $(
137+
console.log("size", immortals.size);
138+
if (!immortals.has(globalKey)) {
139+
console.log("cache miss", globalKey);
140+
const elt = $(
122141
`<div id="${globalKey}" style="border:0;position:absolute;overflow-y:hidden;z-index:${zIndex}"/>${html}</div>`,
123-
));
142+
);
143+
immortals.set(globalKey, elt);
124144
$("body").append(elt);
125145
return elt;
126146
} else {
127-
return immortals[globalKey];
147+
console.log("cache hit", globalKey);
148+
return immortals.get(globalKey);
128149
}
129150
};
130151

@@ -161,7 +182,7 @@ export default function ImmortalDomNode({
161182
// in order to make it so the iframe doesn't appear
162183
// to just get "dragged along" nearly as much, as
163184
// onScroll is throttled.
164-
count = Math.min(SCROLL_COUNT, SCROLL_COUNT + 100);
185+
count = SCROLL_COUNT;
165186
while (count > 0) {
166187
position();
167188
await new Promise(requestAnimationFrame);

0 commit comments

Comments
 (0)