Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/next/components/share/file-contents.tsx
1450 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
import Markdown from "@cocalc/frontend/editors/slate/static-markdown";
7
import {
8
isAudio,
9
isCodemirror,
10
isHTML,
11
isImage,
12
isMarkdown,
13
isVideo,
14
} from "@cocalc/frontend/file-extensions";
15
import Slides from "@cocalc/frontend/frame-editors/slides-editor/share";
16
import Whiteboard from "@cocalc/frontend/frame-editors/whiteboard-editor/share/index";
17
import JupyterNotebook from "@cocalc/frontend/jupyter/nbviewer/nbviewer";
18
import { FileContext } from "@cocalc/frontend/lib/file-context";
19
import A from "components/misc/A";
20
import { isIOS, isSafari } from "lib/share/feature";
21
import rawURL from "lib/share/raw-url";
22
import getUrlTransform from "lib/share/url-transform";
23
import { containingPath, getExtension } from "lib/share/util";
24
import useCustomize from "lib/use-customize";
25
import getAnchorTagComponent from "./anchor-tag-component";
26
import CodeMirror from "./codemirror";
27
import SageWorksheet from "./sage-worksheet";
28
29
import type { JSX } from "react";
30
31
interface Props {
32
id: string;
33
content?: string;
34
relativePath: string;
35
path: string;
36
truncated?: boolean;
37
jupyter_api?: boolean;
38
}
39
40
export default function FileContents({
41
id,
42
content,
43
path,
44
relativePath,
45
jupyter_api,
46
}: Props): JSX.Element {
47
const filename = relativePath ? relativePath : path;
48
const ext = getExtension(filename);
49
const raw = rawURL({ id, path, relativePath });
50
const { jupyterApiEnabled } = useCustomize();
51
52
const withFileContext = (x) => {
53
const relPath = containingPath(relativePath);
54
const value = {
55
urlTransform: getUrlTransform({ id, path, relativePath: relPath }),
56
AnchorTagComponent: getAnchorTagComponent({ id, relativePath: relPath }),
57
jupyterApiEnabled: jupyterApiEnabled && jupyter_api,
58
noSanitize: false, // We **MUST** sanitize, since we users could launch XSS attacks, mess up style, etc.,
59
// This will, of course, break things, in which case users will have to open them in their own projects.
60
};
61
return <FileContext.Provider value={value}>{x}</FileContext.Provider>;
62
};
63
64
if (isImage(ext)) {
65
return <img src={raw} style={{ maxWidth: "100%" }} />;
66
} else if (isVideo(ext)) {
67
return (
68
<video
69
controls={true}
70
autoPlay={true}
71
loop={true}
72
style={{ width: "100%", height: "auto" }}
73
src={raw}
74
/>
75
);
76
} else if (isAudio(ext)) {
77
return <audio src={raw} autoPlay={true} controls={true} loop={false} />;
78
} else if (ext === "pdf") {
79
// iOS and iPADOS does not have any way to embed PDF's in pages.
80
// I think pretty much every other web browser does, though
81
// strangely even desktop Safari seems often broken, so we also block that.
82
// Amazingly, nextjs handles this sort of thing fine!
83
return isIOS() || isSafari() ? (
84
<h1 style={{ textAlign: "center", margin: "30px" }}>
85
<A href={raw} external>
86
View this PDF...
87
</A>
88
</h1>
89
) : (
90
<embed
91
style={{ width: "100%", height: "100vh" }}
92
src={raw}
93
type="application/pdf"
94
/>
95
);
96
} else if (content == null) {
97
return (
98
<h1 style={{ textAlign: "center", margin: "30px" }}>
99
<A href={raw} external>
100
Open or Download...
101
</A>{" "}
102
</h1>
103
);
104
} else if (isCodemirror(ext)) {
105
return <CodeMirror content={content} filename={filename} />;
106
} else if (isMarkdown(ext)) {
107
return withFileContext(<Markdown value={content} />);
108
} else if (isHTML(ext)) {
109
// We use a sandboxed iframe since it is much more likely to be
110
// useful to users than our HTML component. Most use of our
111
// HTML component with math rendering, etc., is much better done
112
// via a Markdown file. This makes it easy to show, e.g.,
113
// static k3d plots, which CUP is doing. HTML files tend to
114
// be independent of cocalc anyways.
115
return (
116
<iframe
117
srcDoc={content}
118
style={{ width: "100%", height: "100vh" }}
119
sandbox="allow-scripts"
120
/>
121
);
122
// return withFileContext(
123
// <HTML value={content} style={{ width: "100%", height: "100vh" }} />
124
// );
125
} else if (ext == "sagews") {
126
return withFileContext(<SageWorksheet content={content} />);
127
} else if (ext == "ipynb") {
128
return withFileContext(<JupyterNotebook content={content} />);
129
} else if (ext == "board") {
130
return withFileContext(<Whiteboard content={content} />);
131
} else if (ext == "slides") {
132
return withFileContext(<Slides content={content} />);
133
}
134
return <pre>{content}</pre>;
135
}
136
137