Skip to content

Commit 87688ac

Browse files
committed
make it so cached iframe uses immortal dom node
- this is just partly done, and still has the old code - but it seems dramatically better than before and fixes the subtle bug of state loss on frame change, and also is better at resizing to the content
1 parent 4f426f8 commit 87688ac

File tree

2 files changed

+42
-9
lines changed

2 files changed

+42
-9
lines changed

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

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,17 @@ import useCounter from "@cocalc/frontend/app-framework/counter-hook";
1515
import { get_blob_url } from "../server-urls";
1616
import CachedIFrame from "./cached-iframe";
1717
import { useIFrameContext } from "@cocalc/frontend/jupyter/cell-list";
18+
import HTML from "./mime-types/html";
1819

1920
// This impact loading the iframe data from the backend project (via the sha1 hash).
2021
// Doing retries is useful, e.g., since the project might not be running.
2122
const MAX_ATTEMPTS = 10;
2223
const MAX_WAIT = 5000;
2324
const BACKOFF = 1.3;
2425

26+
const HEIGHT = "70vh";
27+
const WIDTH = "max(800px,70vw)";
28+
2529
interface Props {
2630
sha1: string;
2731
project_id: string;
@@ -31,12 +35,18 @@ interface Props {
3135
export default function IFrame(props: Props) {
3236
// we only use cached iframe if the iframecontext is setup, e.g., it is in Jupyter notebooks, but not in whiteboards.
3337
const iframeContext = useIFrameContext();
34-
return iframeContext.iframeDivRef == null || props.cacheId == null ? (
35-
<NonCachedIFrame {...props} />
36-
) : (
38+
if (iframeContext.iframeDivRef == null || props.cacheId == null) {
39+
return <NonCachedIFrame {...props} />;
40+
} else {
41+
const src = get_blob_url(props.project_id, "html", props.sha1);
42+
return (
43+
<HTML
44+
value={`<iframe src="${src}" style="border:0;height:${HEIGHT};width:${WIDTH}"/>`}
45+
/>
46+
);
3747
// @ts-ignore
38-
<CachedIFrame {...props} />
39-
);
48+
return <CachedIFrame {...props} />;
49+
}
4050
}
4151

4252
function NonCachedIFrame({ sha1, project_id }: Props) {

src/packages/frontend/jupyter/output-messages/immortal-dom-node.tsx

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ const immortals: { [globalKey: string]: any } = {};
1919

2020
const Z_INDEX = 1;
2121

22+
const SCROLL_COUNT = 10;
23+
2224
// make it really standout:
2325
// const PADDING = 5;
2426
// const STYLE = {
@@ -47,7 +49,8 @@ export default function ImmortalDomNode({
4749
if (divRef.current == null) {
4850
return;
4951
}
50-
const elt = getElt()[0];
52+
const jElt = getElt();
53+
const elt = jElt[0];
5154
const eltRect = elt.getBoundingClientRect();
5255
const divRect = divRef.current.getBoundingClientRect();
5356

@@ -82,19 +85,39 @@ export default function ImmortalDomNode({
8285
console.log({ parentRect, eltRect });
8386
// Calculate the overlap area
8487
const top = Math.max(0, parentRect.top - eltRect.top);
85-
const right = Math.min(eltRect.width, parentRect.right - eltRect.left);
88+
// leave 30px on right so to not block scrollbar
89+
const right = Math.min(
90+
eltRect.width,
91+
parentRect.right - 30 - eltRect.left,
92+
);
8693
const bottom = Math.min(eltRect.height, parentRect.bottom - eltRect.top);
8794
const left = Math.max(0, parentRect.left - eltRect.left);
8895

8996
// Apply clip-path to elt to make it visible only inside of parentRect:
9097
elt.style.clipPath = `polygon(${left}px ${top}px, ${right}px ${top}px, ${right}px ${bottom}px, ${left}px ${bottom}px)`;
98+
99+
// if its an iframe resize it
100+
if (html.toLowerCase().startsWith("<iframe")) {
101+
const iframe = jElt.find("iframe");
102+
if (iframe.length > 0) {
103+
var iframeBody = iframe.contents().find("body");
104+
if (iframeBody.length > 0) {
105+
// Get dimensions of the iframe's body
106+
//const width = iframeBody.outerWidth();
107+
const height = iframeBody.outerHeight();
108+
//iframe[0].style.width = `${width}px`;
109+
iframe[0].style.height = `${height}px`;
110+
iframeBody[0].style["overflow-y"] = "hidden";
111+
}
112+
}
113+
}
91114
}
92115
}, []);
93116

94117
const getElt = () => {
95118
if (immortals[globalKey] == null) {
96119
const elt = (immortals[globalKey] = $(
97-
`<div id="${globalKey}" style="border:0;position:absolute;z-index:${zIndex}"/>${html}</div>`,
120+
`<div id="${globalKey}" style="border:0;position:absolute;overflow-y:hidden;z-index:${zIndex}"/>${html}</div>`,
98121
));
99122
$("body").append(elt);
100123
return elt;
@@ -135,7 +158,7 @@ export default function ImmortalDomNode({
135158
// in order to make it so the iframe doesn't appear
136159
// to just get "dragged along" nearly as much, as
137160
// onScroll is throttled.
138-
count = Math.min(100, count + 100);
161+
count = Math.min(SCROLL_COUNT, SCROLL_COUNT + 100);
139162
while (count > 0) {
140163
position();
141164
await new Promise(requestAnimationFrame);

0 commit comments

Comments
 (0)