diff --git a/src/Explorer/Notebook/NotebookClientV2.ts b/src/Explorer/Notebook/NotebookClientV2.ts index 138384b6f..cae1bd6d5 100644 --- a/src/Explorer/Notebook/NotebookClientV2.ts +++ b/src/Explorer/Notebook/NotebookClientV2.ts @@ -1,16 +1,14 @@ // Manages all the redux logic for the notebook nteract code // TODO: Merge with NotebookClient? -import { NotebookWorkspaceConnectionInfo } from "../../Contracts/DataModels"; -import * as Constants from "../../Common/Constants"; -import { CdbAppState, makeCdbRecord } from "./NotebookComponent/types"; - // Vendor modules import { actions, AppState, - createHostRef, + ContentRecord, createHostRef, createKernelspecsRef, - makeAppRecord, + HostRecord, + HostRef, + IContentProvider, KernelspecsRef, makeAppRecord, makeCommsRecord, makeContentsRecord, makeEditorsRecord, @@ -18,24 +16,22 @@ import { makeHostsRecord, makeJupyterHostRecord, makeStateRecord, - makeTransformsRecord, - ContentRecord, - HostRecord, - HostRef, - KernelspecsRef, - IContentProvider, + makeTransformsRecord } from "@nteract/core"; +import { configOption, createConfigCollection, defineConfigOption } from "@nteract/mythic-configuration"; import { Media } from "@nteract/outputs"; import TransformVDOM from "@nteract/transform-vdom"; import * as Immutable from "immutable"; -import { Store, AnyAction, MiddlewareAPI, Middleware, Dispatch } from "redux"; - -import configureStore from "./NotebookComponent/store"; - import { Notification } from "react-notification-system"; -import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor"; +import { AnyAction, Dispatch, Middleware, MiddlewareAPI, Store } from "redux"; +import * as Constants from "../../Common/Constants"; +import { NotebookWorkspaceConnectionInfo } from "../../Contracts/DataModels"; import { Action } from "../../Shared/Telemetry/TelemetryConstants"; -import { configOption, createConfigCollection, defineConfigOption } from "@nteract/mythic-configuration"; +import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor"; +import configureStore from "./NotebookComponent/store"; +import { CdbAppState, makeCdbRecord } from "./NotebookComponent/types"; +import IFrameHTML from "./NotebookRenderer/outputs/IFrameHTML"; +import IFrameJavaScript from "./NotebookRenderer/outputs/IFrameJavaScript"; export type KernelSpecsDisplay = { name: string; displayName: string }; @@ -168,8 +164,8 @@ export class NotebookClientV2 { "application/vnd.vega.v5+json": NullTransform, "application/vdom.v1+json": TransformVDOM, "application/json": Media.Json, - "application/javascript": Media.JavaScript, - "text/html": Media.HTML, + "application/javascript": IFrameJavaScript, + "text/html": IFrameHTML, "text/markdown": Media.Markdown, "text/latex": Media.LaTeX, "image/svg+xml": Media.SVG, diff --git a/src/Explorer/Notebook/NotebookRenderer/outputs/IFrameHTML.tsx b/src/Explorer/Notebook/NotebookRenderer/outputs/IFrameHTML.tsx new file mode 100644 index 000000000..62eabc9db --- /dev/null +++ b/src/Explorer/Notebook/NotebookRenderer/outputs/IFrameHTML.tsx @@ -0,0 +1,63 @@ +import * as React from "react"; +import styled from "styled-components"; + +interface Props { + /** + * The HTML string that will be rendered. + */ + data: string; + /** + * The media type associated with the HTML + * string. This defaults to text/html. + */ + mediaType: "text/html"; +} + +const StyledIFrame = styled.iframe` + width: 100%; + border-style: unset; +`; + +export class IFrameHTML extends React.PureComponent { + static defaultProps = { + data: "", + mediaType: "text/html" + }; + + frame?: HTMLIFrameElement; + + appendChildDOM(): void { + if (!this.frame) { + return; + } + + this.frame.contentDocument.open(); + this.frame.contentDocument.write(this.props.data); + this.frame.contentDocument.close(); + } + + componentDidMount(): void { + this.appendChildDOM(); + } + + componentDidUpdate(): void { + this.appendChildDOM(); + } + + render() { + return ( + this.frame = frame} + allow="accelerometer; autoplay; camera; gyroscope; magnetometer; microphone; xr-spatial-tracking" + sandbox="allow-downloads allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-popups-to-escape-sandbox" + onLoad={() => this.onFrameLoaded()} /> + ); + } + + onFrameLoaded() { + this.frame.height = (this.frame.contentDocument.body.scrollHeight + 4) + "px"; + this.frame.contentDocument.body.style.margin = "0px"; + } +} + +export default IFrameHTML; \ No newline at end of file diff --git a/src/Explorer/Notebook/NotebookRenderer/outputs/IFrameJavaScript.tsx b/src/Explorer/Notebook/NotebookRenderer/outputs/IFrameJavaScript.tsx new file mode 100644 index 000000000..8e6732473 --- /dev/null +++ b/src/Explorer/Notebook/NotebookRenderer/outputs/IFrameJavaScript.tsx @@ -0,0 +1,28 @@ +import React from "react"; +import IFrameHTML from "./IFrameHTML"; + +interface Props { + /** + * The JavaScript code that we would like to execute. + */ + data: string; + /** + * The media type associated with our component. + */ + mediaType: "text/javascript"; +} + +export class IFrameJavaScript extends React.PureComponent { + static defaultProps = { + data: "", + mediaType: "application/javascript" + }; + + render() { + return ( + ${this.props.data}`} /> + ); + } +} + +export default IFrameJavaScript; \ No newline at end of file