Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/jupyter/util/iframe.ts
1447 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
/*
7
Efficient backend processing of iframe srcdoc and general text/html messages.
8
9
MOTIVATION: Sage 3d graphics.
10
*/
11
12
import { decode } from "he";
13
14
// use iframe for anything at all large (reduce strain on )
15
const MAX_HTML_SIZE = 10000;
16
17
// We use iframes to render html in a number of cases:
18
// - if it starts with iframe
19
// - if it has a whole page doctype
20
// - if it has a <script> tag anywhere -- since those are ignored by safe HTML
21
// rendering; using an iframe is the only way. This e.g., makes mpld3 work uses -- <script>! https://github.com/sagemathinc/cocalc/issues/1934
22
// and altair -- https://github.com/sagemathinc/cocalc/issues/4468 -- uses <script type="text/javascript"/>
23
// - do NOT just render all html in an iframe, e.g., this would break bokeh, since one output creates the target elt,
24
// and a different output uses javascript to render it, and this doesn't work with an iframe, of course.
25
export function shouldUseIframe(content: string): boolean {
26
if (!content) {
27
return false;
28
}
29
content = content.toLowerCase();
30
if (
31
content.includes("https://bokeh.org") &&
32
content.includes("bk-notebook-logo")
33
) {
34
// Do NOT use an iframe for bokeh no matter what, since this won't work properly.
35
// Hopefully the above heuristic is sufficiently robust to detect but not overdetect.
36
return false;
37
}
38
if (content.includes("<!doctype html>") || content.includes("<html>")) {
39
// plotly wraps its output in <html>, which strongly suggests it wants to
40
// be in an iframe. It's not valid to put <html> as a child of a div, so really
41
// the only valid way to render an <html> string is as an iframe.
42
return true;
43
}
44
if (content.length >= MAX_HTML_SIZE) {
45
// it'll just break anyways if we don't use an iframe -- if we do, there is hope.
46
return true;
47
}
48
return content.startsWith("<iframe");
49
}
50
51
export function processIframeContent(content: string): string {
52
const decodedContent = decode(content);
53
const contentLower = decodedContent.toLowerCase();
54
const i = contentLower.indexOf("<html>");
55
const j = contentLower.lastIndexOf("</html>");
56
// trim content to the part inside the html tags – keep it otherwise
57
// this is necessary for wrapping inline html code like for
58
// https://github.com/sagemathinc/cocalc/issues/4468
59
let src = "";
60
if (i != -1 && j != -1) {
61
src = decodedContent.slice(i, j + "</html>".length);
62
} else {
63
src = `<html>${decodedContent}</html>`;
64
}
65
return src;
66
}
67
68