Skip to content

Commit

Permalink
chore: enable better sharing of TDs with lz-string
Browse files Browse the repository at this point in the history
  • Loading branch information
spf00 committed Mar 10, 2023
1 parent ff3712d commit c702a47
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 78 deletions.
77 changes: 58 additions & 19 deletions src/components/App/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<GlobalState>
<main className="h-full w-screen flex flex-col">
<AppHeader></AppHeader>
<div className="flex-grow splitter flex flex-row w-full height-adjust">
<div className="w-7/12" id="second"><TDViewer /></div>
<div id="separator"></div>
<div className="w-5/12" id="first"><JSONEditorComponent /></div>
</div>
<AppFooter></AppFooter>
<div id="modal-root"></div>
</main>
<App />
</GlobalState>
);
}

// 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 (
<main className="h-full w-screen flex flex-col">
<AppHeader></AppHeader>
<div className="flex-grow splitter flex flex-row w-full height-adjust">
<div className="w-7/12" id="second"><TDViewer /></div>
<div id="separator"></div>
<div className="w-5/12" id="first"><JSONEditorComponent /></div>
</div>
<AppFooter></AppFooter>
<div id="modal-root"></div>
</main>
);
}


/**
*
Expand Down Expand Up @@ -84,4 +123,4 @@ const dragElement = (element, direction) => {
element.onmousedown = onMouseDown;
}

export default App;
export default GlobalStateWrapper;
19 changes: 0 additions & 19 deletions src/components/App/AppHeader/AppHeader.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down
9 changes: 5 additions & 4 deletions src/components/Dialogs/ConvertTmDialog.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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"]) {
Expand Down Expand Up @@ -138,7 +139,7 @@ const createHtmlInputs = (td) => {
htmlActions = createAffordanceHtml("actions", actions);
htmlEvents = createAffordanceHtml("events", events);

} catch (ignored) {}
} catch (ignored) { }

const divider = (
<h2 key="modalDividerText" className="text-gray-400 pb-2 pt-4">
Expand All @@ -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")
Expand Down Expand Up @@ -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");
}
57 changes: 21 additions & 36 deletions src/components/Dialogs/ShareDialog.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -35,21 +30,32 @@ 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 = <input
type="text"
name="share-td-field"
id="share-td-field"
className="border-gray-600 bg-gray-600 w-full p-2 sm:text-sm border-2 text-white rounded-md focus:outline-none focus:border-blue-500"
defaultValue={compressedTdLink}
/>

if (display) {
return ReactDOM.createPortal(
<DialogTemplate
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."}
/>,
Expand All @@ -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 (<input
type="text"
name="share-td-field"
id="share-td-field"
className="border-gray-600 bg-gray-600 w-full p-2 sm:text-sm border-2 text-white rounded-md focus:outline-none focus:border-blue-500"
defaultValue={createPermalink(td)}
/>);
};

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!");
},
Expand Down

0 comments on commit c702a47

Please sign in to comment.