Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/src/packages/jupyter/blobs/iframe.ts
Views: 687
/*1* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.2* License: MS-RSL – see LICENSE.md for details3*/45/*6Efficient backend processing of iframe srcdoc and general text/html messages.78MOTIVATION: Sage 3d graphics.9*/1011import { decode } from "he";12//import { getLogger } from "@cocalc/backend/logger";13//const logger = getLogger("jupyter:blobs:iframe");1415// see https://github.com/sagemathinc/cocalc/issues/432216const MAX_HTML_SIZE = 10 ** 6;1718// We use iframes to render html in a number of cases:19// - if it starts with iframe20// - if it has a whole page doctype21// - if it has a <script> tag anywhere -- since those are ignored by safe HTML22// rendering; using an iframe is the only way. This e.g., makes mpld3 work uses -- <script>! https://github.com/sagemathinc/cocalc/issues/193423// and altair -- https://github.com/sagemathinc/cocalc/issues/4468 -- uses <script type="text/javascript"/>24// - do NOT just render all html in an iframe, e.g., this would break bokeh, since one output creates the target elt,25// and a different output uses javascript to render it, and this doesn't work with an iframe, of course.26export function is_likely_iframe(content: string): boolean {27if (!content) {28return false;29}30content = content.toLowerCase();31if (32content.includes("https://bokeh.org") &&33content.includes("bk-notebook-logo")34) {35// Do NOT use an iframe for bokeh no matter what, since this won't work properly.36// Hopefully the above heuristic is sufficiently robust to detect but not overdetect.37return false;38}39if (content.includes("<!doctype html>") || content.includes("<html>")) {40// plotly wraps its output in <html>, which strongly suggests it wants to41// be in an iframe. It's not valid to put <html> as a child of a div, so really42// the only valid way to render an <html> string is as an iframe.43return true;44}45if (content.length >= MAX_HTML_SIZE) {46// it'll just break anyways if we don't use an iframe -- if we do, there is hope.47return true;48}49return content.startsWith("<iframe");50}5152export function process(53content: string,54saveToBlobStore: (data: string, type: string, ipynb?: string) => string,55): string {56const decodedContent = decode(content);57const contentLower = decodedContent.toLowerCase();58const i = contentLower.indexOf("<html>");59const j = contentLower.lastIndexOf("</html>");60// trim content to the part inside the html tags – keep it otherwise61// this is necessary for wrapping inline html code like for62// https://github.com/sagemathinc/cocalc/issues/446863let src = "";64if (i != -1 && j != -1) {65src = decodedContent.slice(i, j + "</html>".length);66} else {67src = `<html>${decodedContent}</html>`;68}69// logger.debug("process", { content, src });70return saveToBlobStore(src, "text/html", content);71}727374