Skip to content

Commit

Permalink
iframe: add ability to reload so can deal with problems that will occ…
Browse files Browse the repository at this point in the history
…ur sometimes
  • Loading branch information
williamstein committed Apr 24, 2022
1 parent 80e18bd commit a8b207f
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 57 deletions.
136 changes: 80 additions & 56 deletions src/packages/frontend/jupyter/output-messages/cached-iframe.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ split the Jupyter frame, then the iframes of course get reset. That was a probl
i.e., it's not special to using windowing.
*/

import { Button } from "antd";
import { Icon } from "@cocalc/frontend/components/icon";
import { useCallback, useEffect, useMemo, useRef } from "react";
import { get_blob_url } from "../server-urls";
import { useIFrameContext } from "@cocalc/frontend/jupyter/cell-list";
Expand Down Expand Up @@ -66,73 +68,95 @@ export default function CachedIFrame({ cacheId, sha1, project_id }: Props) {
const divRect = divRef.current.getBoundingClientRect();
eltRef.current.style.width = `${divRect.width}px`;
// Set the height to match the contents:
const height = Math.max(400, $(eltRef.current).contents().height() ?? 0);
eltRef.current.style.height = `${height}px`;
divRef.current.style.height = `${height}px`;
try {
const height = Math.max(400, $(eltRef.current).contents().height() ?? 0);
eltRef.current.style.height = `${height}px`;
divRef.current.style.height = `${height}px`;
} catch (_) {
// height computation can throw. That's fine.
}
}, []);

const showIframe = useCallback(async () => {
if (divRef.current == null) return;
let holder = $(iframeContext.iframeDivRef?.current);
if (holder.length == 0) {
// when first mounting, we have to wait until next loop until the holder is rendered.
await delay(0);
if (!isMountedRef.current) return;
holder = $(iframeContext.iframeDivRef?.current);
}
if (holder.length == 0) {
console.log(`WARNING: iframe sha1=${sha1} failed to get holder!`);
return;
}
let elt = holder.find(`#${key}`);
if (elt.length == 0) {
elt = $(
`<iframe id="${key}" src="${get_blob_url(
project_id,
"html",
sha1
)}" style="border:0;overflow:hidden;width:100%;height:${HEIGHT};position:absolute;left:130px"/>`
);
holder.append(elt);
}
eltRef.current = elt[0];
if (iframeContext.iframeOnScrolls != null) {
let count = 0;
iframeContext.iframeOnScrolls[key] = async () => {
// We run position a lot whenever there is a scroll
// in order to make it so the iframe doesn't appear
// to just get "dragged along" nearly as much, as
// onScroll is throttled.
count = Math.min(100, count + 100);
while (count > 0) {
position();
await new Promise(requestAnimationFrame);
count -= 1;
}
// throw in a size update when we're done.
updateSize();
};
}
elt.show();
position();
updateSize();
// really should wait until the iframe is loaded... though calling position/updateSize randomly
// isn't harmful, and will happen on scrolling.
await delay(500);
position();
updateSize();
}, [key]);

const reloadIframe = useCallback(async () => {
let holder = $(iframeContext.iframeDivRef?.current);
if (holder.length > 0) {
holder.find(`#${key}`).remove();
}
await showIframe();
}, [key]);

useEffect(() => {
updateSize();
}, [resize]);

useEffect(() => {
if (divRef.current == null) return;
(async () => {
let holder = $(iframeContext.iframeDivRef?.current);
if (holder.length == 0) {
// when first mounting, we have to wait until next loop until the holder is rendered.
await delay(0);
if (!isMountedRef.current) return;
holder = $(iframeContext.iframeDivRef?.current);
}
if (holder.length == 0) {
console.log(`WARNING: iframe sha1=${sha1} failed to get holder!`);
return;
}
let elt = holder.find(`#${key}`);
if (elt.length == 0) {
elt = $(
`<iframe id="${key}" src="${get_blob_url(
project_id,
"html",
sha1
)}" style="border:0;overflow:hidden;width:100%;height:${HEIGHT};position:absolute;left:130px"/>`
);
holder.append(elt);
}
eltRef.current = elt[0];
if (iframeContext.iframeOnScrolls != null) {
let count = 0;
iframeContext.iframeOnScrolls[key] = async () => {
// We run position a lot whenever there is a scroll
// in order to make it so the iframe doesn't appear
// to just get "dragged along" nearly as much, as
// onScroll is throttled.
count = Math.min(100, count + 100);
while (count > 0) {
position();
await new Promise(requestAnimationFrame);
count -= 1;
}
// throw in a size update when we're done.
updateSize();
};
}
elt.show();
position();
updateSize();
// really should wait until the iframe is loaded... though calling position/updateSize randomly
// isn't harmful, and will happen on scrolling.
await delay(500);
position();
updateSize();
})();

showIframe();
return () => {
delete iframeContext.iframeOnScrolls?.[key];
$(eltRef.current).hide();
};
}, [key]);

return <div ref={divRef} style={{ height: HEIGHT, width: "100%" }}></div>;
return (
<div ref={divRef} style={{ height: HEIGHT, width: "100%" }}>
<Button
style={{ float: "right", zIndex: 1, marginTop: "5px" }}
onClick={reloadIframe}
>
<Icon name="reload" />
</Button>
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*/

import { Button } from "react-bootstrap";
import { Icon } from "../../components/icon";
import { Icon } from "@cocalc/frontend/components/icon";
import React from "react";
import { Map } from "immutable";
import { JupyterActions } from "../actions";
Expand Down

0 comments on commit a8b207f

Please sign in to comment.