-
Notifications
You must be signed in to change notification settings - Fork 217
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
jupyter windowing: first proof of concept (not done!) showing how to …
…maintain iframe state in the context of full on windowing! Yes, this does work.
- Loading branch information
1 parent
3994609
commit 5defdf1
Showing
8 changed files
with
192 additions
and
48 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
102 changes: 102 additions & 0 deletions
102
src/packages/frontend/jupyter/output-messages/cached-iframe.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
/* | ||
It is completely impossible in modern times to move an iframe in the DOM without loosing state, | ||
as explained here: | ||
https://stackoverflow.com/questions/8318264/how-to-move-an-iframe-in-the-dom-without-losing-its-state | ||
Thus, obviously, we need to hide/show the iframe at a particular place, and move it to | ||
match a placeholder div. That's the only possible way to make this work generically. | ||
TODO: | ||
- [ ] tracking vertical position | ||
- [ ] measure and resize to match content size. | ||
- [ ] garbage collect; if you keep changing and evaluating a cell (say), then the iframes just pile up. | ||
Need to go through and get rid of any that are no longer valid. Hard to know how to do that from | ||
here, since unmounting isn't relevant. | ||
*/ | ||
|
||
import { useCallback, useEffect, useMemo, useRef } from "react"; | ||
import { get_blob_url } from "../server-urls"; | ||
import { useIFrameContext } from "@cocalc/frontend/jupyter/cell-list"; | ||
import { delay } from "awaiting"; | ||
import useIsMountedRef from "@cocalc/frontend/app-framework/is-mounted-hook"; | ||
|
||
const HEIGHT = "400px"; | ||
|
||
interface Props { | ||
sha1: string; | ||
project_id: string; | ||
cacheId: string; | ||
} | ||
|
||
export default function CachedIFrame({ cacheId, sha1, project_id }: Props) { | ||
const divRef = useRef<any>(null); | ||
const eltRef = useRef<any>(null); | ||
const iframeContext = useIFrameContext(); | ||
const isMountedRef = useIsMountedRef(); | ||
const key = useMemo(() => { | ||
return `${cacheId}-${sha1}`; | ||
}, [cacheId, sha1]); | ||
|
||
const position = useCallback(() => { | ||
// make it so eltRef.current is exactly positioned on top of divRef.current using CSS | ||
if (eltRef.current == null || divRef.current == null) return; | ||
const eltRect = eltRef.current.getBoundingClientRect(); | ||
const divRect = divRef.current.getBoundingClientRect(); | ||
let deltaTop = divRect.top - eltRect.top; | ||
if (deltaTop) { | ||
if (eltRef.current.style.top) { | ||
deltaTop += parseFloat(eltRef.current.style.top.slice(0, -2)); | ||
} | ||
eltRef.current.style.top = `${deltaTop}px`; | ||
} | ||
let deltaLeft = divRect.left - eltRect.left; | ||
if (deltaLeft) { | ||
if (eltRef.current.style.left) { | ||
deltaLeft += parseFloat(eltRef.current.style.left.slice(0, -2)); | ||
} | ||
eltRef.current.style.left = `${deltaLeft}px`; | ||
} | ||
}, []); | ||
window.x = position; | ||
|
||
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) 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"/>` | ||
); | ||
holder.append(elt); | ||
} | ||
eltRef.current = elt[0]; | ||
if (iframeContext.iframeOnScrolls != null) { | ||
iframeContext.iframeOnScrolls[key] = position; | ||
} | ||
elt.show(); | ||
position(); | ||
})(); | ||
|
||
return () => { | ||
delete iframeContext.iframeOnScrolls?.[key]; | ||
$(eltRef.current).hide(); | ||
}; | ||
}, [key]); | ||
|
||
return <div ref={divRef} style={{ height: HEIGHT, width: "100%" }}></div>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
6 changes: 3 additions & 3 deletions
6
src/packages/frontend/jupyter/output-messages/mime-types/iframe.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,9 @@ | ||
import register from "./register"; | ||
import { IFrame } from "../iframe"; | ||
import IFrame from "../iframe"; | ||
|
||
register("iframe", 7, ({ project_id, value }) => { | ||
register("iframe", 7, ({ id, project_id, value }) => { | ||
if (value == null || project_id == null) { | ||
return <pre>iframe must specify project_id and sha1</pre>; | ||
} | ||
return <IFrame sha1={value} project_id={project_id} />; | ||
return <IFrame cacheId={id} sha1={value} project_id={project_id} />; | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters