diff --git a/client/pages/viewerpage.js b/client/pages/viewerpage.js index b06c7781..fcf784b9 100644 --- a/client/pages/viewerpage.js +++ b/client/pages/viewerpage.js @@ -1,4 +1,5 @@ -import React from "react"; +import React, { useReducer, useEffect } from "react"; +import { useHistory } from "react-router-dom"; import Path from "path"; import "./viewerpage.scss"; @@ -39,175 +40,155 @@ const Appframe = (props) => ( ); -export class ViewerPageComponent extends React.Component { - constructor(props) { - super(props); - this.state = { - path: props.match.url.replace("/view", "").replace(/%23/g, "#") + (location.hash || ""), - url: null, - filename: Path.basename(props.match.url.replace("/view", "")) || "untitled.dat", - opener: null, - content: null, - needSaving: false, - isSaving: false, - loading: true, - application_arguments: null, - }; - this.props.subscribe("file.select", this.onPathUpdate.bind(this)); - } - UNSAFE_componentWillReceiveProps(props) { - this.setState({ - path: props.match.url.replace("/view", "").replace(/%23/g, "#") + (location.hash || ""), - filename: Path.basename(props.match.url.replace("/view", "")) || "untitled.dat", - }, () => this.componentDidMount()); - } +export function ViewerPageComponent({ error, subscribe, unsubscribe, match, location }) { + const history = useHistory(); + const currentUrl = history.location.pathname; - componentDidMount() { - const metadata = () => { - return new Promise((done, err) => { - const [app_opener, app_args] = opener(this.state.path); - Files.url(this.state.path).then((url) => { - this.setState({ - url: url, - opener: app_opener, - application_arguments: app_args, - }, () => done(app_opener)); - }).catch((error) => { - this.props.error(error); - err(error); - }); - }); - }; - const data_fetch = (app) => { - if (app === "editor" || app === "form") { - return Promise.all([ - Files.cat(this.state.path), - Files.options(this.state.path), - ]).then((d) => { - const [content, options] = d; - this.setState({ - content: content, - loading: false, - acl: options["allow"], - }); - }).catch((err) => { - if (err && err.code === "BINARY_FILE") { - this.setState({ opener: "download", loading: false }); - } else { - this.props.error(err); - } - }); - } - this.setState({ loading: false }); - }; - return metadata().then(data_fetch); - } + const [state, setState] = useReducer((s, a) => { + return { ...s, ...a }; + }, { + url: null, + opener: null, + content: null, + needSaving: false, + isSaving: false, + loading: false, + application_arguments: null, + }); + const path = currentUrl.replace("/view", "").replace(/%23/g, "#") + (location.hash || ""); + const filename = Path.basename(currentUrl.replace("/view", "")) || "untitled.dat"; - componentWillUnmount() { - this.props.unsubscribe("file.select"); - } - - save(file) { - this.setState({ isSaving: true }); - return Files.save(this.state.path, file) - .then(() => { - this.setState({ isSaving: false, needSaving: false }); - return Promise.resolve(); - }) - .then(() => { - return new Promise((done, err) => { + const save = (file) => { + return Files.save(path, file) + .then(() => setState({ isSaving: false, needSaving: false })) + .then(() => (new Promise((done, err) => { const reader = new FileReader(); reader.onload = () => { - this.setState({ content: reader.result }); + setState({ content: reader.result }); done(); }; reader.onerror = (e) => { - err({ message: "Internal error 500" }); + err(new Error("Internal error 500")); }; reader.readAsText(file); - }); - }) + }))) .catch((err) => { if (err && err.code === "CANCELLED") return; - this.setState({ isSaving: false }); + setState({ isSaving: false }); notify.send(err, "error"); - return Promise.reject(err); }); } - onPathUpdate(path) { - this.props.history.push("/files"+path); - } + const needSaving = (bool) => { + setState({ needSaving: bool }); + }; - needSaving(bool) { - return new Promise((done) => { - this.setState({ needSaving: bool }, done); - }); - } + useEffect(() => { + const metadata = () => { + const [app_opener, app_args] = opener(path); + setState({ loading: true, isSaving: true, needSaving: false, url: null, opener: null, application_arguments: null }); + return Files.url(path).then((url) => { + setState({ + url: url, + opener: app_opener, + application_arguments: app_args, + }); + return app_opener; + }).catch((_err) => error(_err)); + }; - render() { - return ( -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - + const data_fetch = (app) => { + if (app !== "editor" && app !== "form") { + setState({ loading: false }); + return null; + } + return Promise.all([ + Files.cat(path), + Files.options(path), + ]).then((d) => { + const [content, options] = d; + setState({ + content: content, + loading: false, + acl: options["allow"], + }); + }).catch((err) => { + if (err.code !== "BINARY_FILE") { + error(err); + return; + } + setState({ + loading: false, + opener: "download", + }); + }); + }; + + metadata().then(data_fetch); + return history.listen(() => {}) + }, [path]); + + return ( +
+ +
+ + + + + + - - + + -
+ + + + + + + + + + + + + + + + + + +
- ); - } +
+ ); } export const ViewerPage = ErrorPage(LoggedInOnly(EventReceiver(ViewerPageComponent))); diff --git a/client/pages/viewerpage/audioplayer.js b/client/pages/viewerpage/audioplayer.js index 340f85b0..a956a499 100644 --- a/client/pages/viewerpage/audioplayer.js +++ b/client/pages/viewerpage/audioplayer.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect, useLayoutEffect } from "react"; +import React, { useState, useEffect, useRef } from "react"; import WaveSurfer from "wavesurfer.js"; import { MenuBar } from "./menubar"; @@ -7,12 +7,12 @@ import "./audioplayer.scss"; export function AudioPlayer({ filename, data }) { const [isPlaying, setIsPlaying] = useState(false); - const [isLoading, setIsLoading] = useState(true); - const [wavesurfer, setWavesurfer] = useState(null); + const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); + const wavesurfer = useRef(null); - useLayoutEffect(() => { - const _ws = WaveSurfer.create({ + useEffect(() => { + wavesurfer.current = WaveSurfer.create({ container: "#waveform", waveColor: "#323639", progressColor: "#6f6f6f", @@ -21,24 +21,22 @@ export function AudioPlayer({ filename, data }) { height: 250, barWidth: 1, }); - - _ws.on("ready", () => { + wavesurfer.current.load(data); + wavesurfer.current.on("ready", () => { setIsLoading(false); }); - _ws.on("error", (err) => { + wavesurfer.current.on("error", (err) => { setIsLoading(false); setError(err) }); - _ws.load(data); - setWavesurfer(_ws); - return () => _ws.destroy(); + return () => wavesurfer.current.destroy(); }, []); useEffect(() => { - if(wavesurfer === null) return; + if(wavesurfer.current === null) return; window.addEventListener("keypress", onKeyPressHandler); return () => window.removeEventListener("keypress", onKeyPressHandler); - }, [wavesurfer, isPlaying]) + }, [isPlaying]) const onKeyPressHandler = (e) => { if(e.code !== "Space") { @@ -50,14 +48,14 @@ export function AudioPlayer({ filename, data }) { const onPlay = (e) => { e.preventDefault(); e.stopPropagation(); - wavesurfer.play(); + wavesurfer.current.play(); setIsPlaying(true); } const onPause = (e) => { e.preventDefault(); e.stopPropagation(); - wavesurfer.pause(); + wavesurfer.current.pause(); setIsPlaying(false); } @@ -72,8 +70,9 @@ export function AudioPlayer({ filename, data }) { -
+
diff --git a/client/pages/viewerpage/pager.js b/client/pages/viewerpage/pager.js index 71cc0608..92b9b9be 100644 --- a/client/pages/viewerpage/pager.js +++ b/client/pages/viewerpage/pager.js @@ -55,7 +55,7 @@ class PagerComponent extends React.Component { ) ? this.calculateNextPageNumber(n) : this.calculatePrevPageNumber(n); Files.url(this.state.files[preload_index].path) .then((url) => this.props.emit("media::preload", url)) - .then(() => this.props.history.push(url)) + .then(() => setTimeout(() => this.props.history.push(url), 0)) .catch(() => {}); } }