From c702a475df77450ebfaf18440d110999cb3bbd97 Mon Sep 17 00:00:00 2001 From: Stefan Pfahler Date: Fri, 10 Mar 2023 13:15:16 +0100 Subject: [PATCH] chore: enable better sharing of TDs with lz-string --- src/components/App/App.jsx | 77 ++++++++++++++++------ src/components/App/AppHeader/AppHeader.jsx | 19 ------ src/components/Dialogs/ConvertTmDialog.jsx | 9 +-- src/components/Dialogs/ShareDialog.jsx | 57 ++++++---------- 4 files changed, 84 insertions(+), 78 deletions(-) diff --git a/src/components/App/App.jsx b/src/components/App/App.jsx index 8a57a2a..b3e892c 100644 --- a/src/components/App/App.jsx +++ b/src/components/App/App.jsx @@ -10,34 +10,73 @@ * * SPDX-License-Identifier: EPL-2.0 OR W3C-20150513 ********************************************************************************/ -import React, { useEffect } from 'react'; -import './App.css'; -import TDViewer from '../TDViewer/TDViewer' +import React, { useContext, useEffect, useState } from 'react'; +import ediTDorContext from "../../context/ediTDorContext"; +import GlobalState from '../../context/GlobalState'; +import { decompress } from "../../external/TdPlayground"; import JSONEditorComponent from "../Editor/Editor"; -import AppHeader from './AppHeader/AppHeader'; +import TDViewer from '../TDViewer/TDViewer'; +import './App.css'; import AppFooter from './AppFooter'; -import GlobalState from '../../context/GlobalState'; +import AppHeader from './AppHeader/AppHeader'; -import '../../assets/main.css' +import '../../assets/main.css'; -const App = (props) => { - useEffect(() => { dragElement(document.getElementById("separator"), "H"); }, [props]) +const GlobalStateWrapper = (props) => { return ( -
- -
-
-
-
-
- - -
+
); } +// The useEffect hook for checking the URI was called twice somehow. +// This variable prevents the callback from being executed twice. +let checkedUrl = false; +const App = (props) => { + const context = useContext(ediTDorContext); + + useEffect(() => { dragElement(document.getElementById("separator"), "H"); }, [props]) + + useEffect(() => { + if (checkedUrl || window.location.search.indexOf("td") <= -1) { + return; + } + checkedUrl = true; + + const url = new URL(window.location.href); + const compressedTd = url.searchParams.get("td"); + if (compressedTd == null) return; + + const decompressedTd = decompress(compressedTd); + if (decompressedTd == null || decompressedTd === "") { + alert("The TD found in the URLs path couldn't be reconstructed."); + return; + }; + + try { + const parsedTD = JSON.parse(decompressedTd); + context.updateOfflineTD(JSON.stringify(parsedTD, null, 2)); + } catch (error) { + context.updateOfflineTD(decompressedTd); + alert("The TD found in the URLs path couldn't be parsed, the displayed JSON may contain errors."); + } + }, []); + + return ( +
+ +
+
+
+
+
+ + +
+ ); +} + /** * @@ -84,4 +123,4 @@ const dragElement = (element, direction) => { element.onmousedown = onMouseDown; } -export default App; \ No newline at end of file +export default GlobalStateWrapper; \ No newline at end of file diff --git a/src/components/App/AppHeader/AppHeader.jsx b/src/components/App/AppHeader/AppHeader.jsx index 3c95325..fa87d90 100644 --- a/src/components/App/AppHeader/AppHeader.jsx +++ b/src/components/App/AppHeader/AppHeader.jsx @@ -239,25 +239,6 @@ export default function AppHeader() { return await window.chooseFileSystemEntries(opts); }; - - useEffect(() => { - if (window.location.search.indexOf("td") > -1) { - const url = new URL(window.location.href); - const td = url.searchParams.get("td"); - try { - const parsedTD = JSON.parse(td); - if (parsedTD["@type"] === "tm:ThingModel") { - context.updateIsThingModel(true) - } - context.updateOfflineTD(JSON.stringify(parsedTD, null, 2)); - } catch (error) { - alert('Sorry, we were unable to parse the TD given in the URL') - } - } - //because the GET Param should be only loaded once, the next line was added - // eslint-disable-next-line - }, []); - useEffect(() => { const shortcutHandler = (e) => { if ( diff --git a/src/components/Dialogs/ConvertTmDialog.jsx b/src/components/Dialogs/ConvertTmDialog.jsx index 8491baa..d1842e2 100644 --- a/src/components/Dialogs/ConvertTmDialog.jsx +++ b/src/components/Dialogs/ConvertTmDialog.jsx @@ -14,6 +14,7 @@ import React, { forwardRef, useContext, useEffect, useImperativeHandle } from 'r import ReactDOM from "react-dom"; import ediTDorContext from "../../context/ediTDorContext"; import { DialogTemplate } from "./DialogTemplate"; +import { compress } from "../../external/TdPlayground" export const ConvertTmDialog = forwardRef((props, ref) => { const context = useContext(ediTDorContext); @@ -99,7 +100,7 @@ const createHtmlInputs = (td) => { const properties = Object.keys(parsed["properties"] ? parsed["properties"] : {}); const actions = Object.keys(parsed["actions"] ? parsed["actions"] : {}); const events = Object.keys(parsed["events"] ? parsed["events"] : {}); - const requiredFields = {"properties": [], "actions": [], "events": []}; + const requiredFields = { "properties": [], "actions": [], "events": [] }; // Parse the required interaction affordances if (parsed["tm:required"]) { @@ -138,7 +139,7 @@ const createHtmlInputs = (td) => { htmlActions = createAffordanceHtml("actions", actions); htmlEvents = createAffordanceHtml("events", events); - } catch (ignored) {} + } catch (ignored) { } const divider = (

@@ -162,7 +163,7 @@ const convertTmToTd = (td, htmlInputs) => { // Process the ticked affordances and save them in respective arrays for (const item of htmlInputs) { if (item.props.className.indexOf("form-checkbox") > -1 && - document.getElementById(item.props.children[0].props.id).checked) { + document.getElementById(item.props.children[0].props.id).checked) { if (item.props.children[0].props["data-interaction"] === "properties") properties.push(item["key"].split("/")[1]); else if (item.props.children[0].props["data-interaction"] === "actions") @@ -227,6 +228,6 @@ const convertTmToTd = (td, htmlInputs) => { delete parse["@type"]; delete parse["tm:required"]; - let permalink = `${window.location.origin+window.location.pathname}?td=${encodeURIComponent(JSON.stringify(parse))}`; + let permalink = `${window.location.origin + window.location.pathname}?td=${compress(JSON.stringify(parse))}`; window.open(permalink, "_blank"); } diff --git a/src/components/Dialogs/ShareDialog.jsx b/src/components/Dialogs/ShareDialog.jsx index 272d8fe..323eec4 100644 --- a/src/components/Dialogs/ShareDialog.jsx +++ b/src/components/Dialogs/ShareDialog.jsx @@ -14,17 +14,12 @@ import React, { forwardRef, useContext, useEffect, useImperativeHandle } from 'r import ReactDOM from "react-dom"; import ediTDorContext from "../../context/ediTDorContext"; import { DialogTemplate } from "./DialogTemplate"; +import { compress } from "../../external/TdPlayground" export const ShareDialog = forwardRef((props, ref) => { const context = useContext(ediTDorContext); - const [display, setDisplay] = React.useState(() => { return false }); - - useEffect(() => { - if (display === true) { - copyLinkToClipboard(createPermalink(context.offlineTD)); - focusPermalinkField() - } - }, [display, context]); + const [display, setDisplay] = React.useState(false); + const [compressedTdLink, setCompressedTdLink] = React.useState(""); useImperativeHandle(ref, () => { return { @@ -35,13 +30,24 @@ export const ShareDialog = forwardRef((props, ref) => { const open = () => { setDisplay(true) - }; - const close = () => { - setDisplay(false); + const tmpCompressedTd = compress(context.offlineTD); + const tmpCompressedTdLink = `${window.location.origin + window.location.pathname}?td=${tmpCompressedTd}`; + setCompressedTdLink(tmpCompressedTdLink); + copyLinkToClipboard(tmpCompressedTdLink); + + focusPermalinkField(); }; - const urlField = createPermalinkField(context.offlineTD); + const close = () => { setDisplay(false); }; + + let child = if (display) { return ReactDOM.createPortal( @@ -49,7 +55,7 @@ export const ShareDialog = forwardRef((props, ref) => { onCancel={close} cancelText={"Close"} hasSubmit={false} - children={urlField} + children={child} title={"Share This TD"} description={"A link to this TD was copied to your clipboard."} />, @@ -59,30 +65,9 @@ export const ShareDialog = forwardRef((props, ref) => { return null; }); -const createPermalink = (td) => { - let parsedTD = {}; - try { - parsedTD = JSON.parse(td); - } catch (_) { } - - return `${window.location.origin+window.location.pathname}?td=${encodeURIComponent( - JSON.stringify(parsedTD) - )}`; -} - -const createPermalinkField = (td) => { - return (); -}; - -const copyLinkToClipboard = (link) => { +const copyLinkToClipboard = (compressedTdLink) => { if (document.hasFocus()) { - navigator.clipboard.writeText(link).then( + navigator.clipboard.writeText(compressedTdLink).then( function () { console.log("Async: Copied TD link to clipboard!"); },