From 8e5753c8d387ea129422a6c388a25c55010d9c25 Mon Sep 17 00:00:00 2001 From: 1ilit Date: Tue, 19 Sep 2023 15:50:32 +0300 Subject: [PATCH] copy paste cut --- src/components/control_panel.jsx | 76 ++++++++++++++++++++++++++-- src/schemas/index.js | 85 +++++++++++++++++++++++++++++++- 2 files changed, 156 insertions(+), 5 deletions(-) diff --git a/src/components/control_panel.jsx b/src/components/control_panel.jsx index b6b1e87..09933f4 100644 --- a/src/components/control_panel.jsx +++ b/src/components/control_panel.jsx @@ -52,6 +52,8 @@ import CodeMirror from "@uiw/react-codemirror"; import { json } from "@codemirror/lang-json"; import jsPDF from "jspdf"; import { useHotkeys } from "react-hotkeys-hook"; +import { Validator } from "jsonschema"; +import { areaSchema, noteSchema, tableSchema } from "../schemas"; export default function ControlPanel(props) { const MODAL = { @@ -525,6 +527,70 @@ export default function ControlPanel(props) { break; } }; + const copy = () => { + switch (selectedElement.element) { + case ObjectType.TABLE: + navigator.clipboard + .writeText(JSON.stringify({ ...tables[selectedElement.id] })) + .catch((e) => { + Toast.error("Could not copy"); + }); + break; + case ObjectType.NOTE: + navigator.clipboard + .writeText(JSON.stringify({ ...notes[selectedElement.id] })) + .catch((e) => { + Toast.error("Could not copy"); + }); + break; + case ObjectType.AREA: + navigator.clipboard + .writeText(JSON.stringify({ ...areas[selectedElement.id] })) + .catch((e) => { + Toast.error("Could not copy"); + }); + break; + default: + break; + } + }; + const paste = () => { + navigator.clipboard.readText().then((text) => { + let obj = null; + try { + obj = JSON.parse(text); + } catch (error) { + return; + } + const v = new Validator(); + if (v.validate(obj, tableSchema).valid) { + addTable(true, { + ...obj, + x: obj.x + 20, + y: obj.y + 20, + id: tables.length, + }); + } else if (v.validate(obj, areaSchema).valid) { + addArea(true, { + ...obj, + x: obj.x + 20, + y: obj.y + 20, + id: areas.length, + }); + } else if (v.validate(obj, noteSchema)) { + addNote(true, { + ...obj, + x: obj.x + 20, + y: obj.y + 20, + id: notes.length, + }); + } + }); + }; + const cut = () => { + copy(); + del(); + }; const menu = { File: { @@ -698,15 +764,15 @@ export default function ControlPanel(props) { shortcut: "Ctrl+E", }, Cut: { - function: () => {}, + function: cut, shortcut: "Ctrl+X", }, Copy: { - function: () => {}, + function: copy, shortcut: "Ctrl+C", }, Paste: { - function: () => {}, + function: paste, shortcut: "Ctrl+V", }, Duplicate: { @@ -809,6 +875,9 @@ export default function ControlPanel(props) { useHotkeys("ctrl+y, meta+y", redo, { preventDefault: true }); useHotkeys("ctrl+e, meta+e", edit, { preventDefault: true }); useHotkeys("ctrl+d, meta+d", duplicate, { preventDefault: true }); + useHotkeys("ctrl+c, meta+c", copy, { preventDefault: true }); + useHotkeys("ctrl+v, meta+v", paste, { preventDefault: true }); + useHotkeys("ctrl+x, meta+x", cut, { preventDefault: true }); useHotkeys("delete", del, { preventDefault: true }); useHotkeys("ctrl+shift+g, meta+shift+g", viewGrid, { preventDefault: true }); useHotkeys("ctrl+up, meta+up", zoomIn, { preventDefault: true }); @@ -1021,7 +1090,6 @@ export default function ControlPanel(props) { if (!f) { return; } - const reader = new FileReader(); reader.onload = function (event) { let jsonObject = null; diff --git a/src/schemas/index.js b/src/schemas/index.js index 73d139c..2d0c117 100644 --- a/src/schemas/index.js +++ b/src/schemas/index.js @@ -1,3 +1,86 @@ +const tableSchema = { + type: "object", + properties: { + id: { type: "integer" }, + name: { type: "string" }, + x: { type: "number" }, + y: { type: "number" }, + fields: { + type: "array", + items: { + type: "object", + properties: { + name: { type: "string" }, + type: { type: "string" }, + default: { type: "string" }, + check: { type: "string" }, + primary: { type: "boolean" }, + unique: { type: "boolean" }, + notNull: { type: "boolean" }, + increment: { type: "boolean" }, + comment: { type: "string" }, + }, + required: [ + "name", + "type", + "default", + "check", + "primary", + "unique", + "notNull", + "increment", + "comment", + ], + }, + }, + comment: { type: "string" }, + indices: { + type: "array", + items: { + type: "object", + properties: { + name: { type: "string" }, + fields: { + type: "array", + items: { type: "string" }, + }, + }, + required: ["name", "fields"], + }, + }, + color: { type: "string", pattern: "^#[0-9a-fA-F]{6}$" }, + }, + required: ["id", "name", "x", "y", "fields", "comment", "indices", "color"], +}; + +const areaSchema = { + type: "object", + properties: { + id: { type: "integer" }, + name: { type: "string" }, + x: { type: "number" }, + y: { type: "number" }, + width: { type: "number" }, + height: { type: "number" }, + color: { type: "string", pattern: "^#[0-9a-fA-F]{6}$" }, + }, + required: ["id", "name", "x", "y", "width", "height", "color"], +}; + +const noteSchema = { + type: "object", + properties: { + id: { type: "integer" }, + x: { type: "number" }, + y: { type: "number" }, + title: { type: "string" }, + content: { type: "string" }, + color: { type: "string", pattern: "^#[0-9a-fA-F]{6}$" }, + height: { type: "number" }, + }, + required: ["id", "x", "y", "title", "content", "color", "height"], +}; + const jsonSchema = { type: "object", properties: { @@ -152,4 +235,4 @@ const ddbSchema = { }, }; -export { jsonSchema, ddbSchema }; +export { jsonSchema, ddbSchema, tableSchema, noteSchema, areaSchema };