frontPanel/src/create/createQuestion.tsx

524 lines
22 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React from 'react';
import { useField, Form, FormikProps, Formik } from 'formik';
import {
Select, Textarea, VStack, Checkbox, Button, HStack,
} from '@chakra-ui/react'
import 'suneditor/dist/css/suneditor.min.css'; // Import Sun Editor's CSS File
import Settings from "./settings";
import WorkSpace from "./workSpace";
import Header from "./header";
import { saveCondition, getCondition } from "./lsBacking";
import type {ElementsOfObject} from "./questionTypes"
//Значения, собираемые для отправки на бэк
interface Values {
title: string;
children: string;
description: string;
}
const types = [
{desc:"текст", value:"text"},
{desc:"селект", value:"select"},
{desc:"чекбокс", value:"checkbox"},
{desc:"файл", value:"file"},
{desc:"кнопка", value:"button"},
{desc: "описание", value: "description"},
{desc:"ничего", value:"none"},
]
export const TextField = (props: any) => {
const [field, meta, helpers] = useField(props);
return (
<>
<Textarea resize="none" width="80%" {...field} {...props} />
{meta.touched && meta.error ? (
<div className="error">{meta.error}</div>
) : null}
</>
);
};
//Для первого ознакомления рекомендую свернуть все функции и почитать их названия и описания
//Заранее берётся поле children нужного родителя. Функция сама отделит все id от родительской части
//Вернёт число для текущего слоя вложенности (в случае чего надо будет ручками присоединить к строке родителя)
const getFreeNumber = (array:Array<ElementsOfObject>):number => {
// Для первого элемента в списке
if (array.length === 0) {
return(0)
} else {
//Для всех последующих элементов
//Создаём массив, состоящий из id всех существующих модалок
let indexes:any = []
//И берём только последние числа от строк, превращая их в числа
for (let i = 0; i < array.length; i++) {
//Строка состоит из чисел, разделённых пробелом.
//Делим строку на массив чисел
let stringArr = array[i].id.split(" ")
//Берём последний элемент массива
stringArr = stringArr.slice(-1)
indexes.push(Number(stringArr[0]))
}
//Сортируем в порядке возрастания
indexes.sort(function compare(a:any, b:any):any {
if (a < b) { return -1;}
if (a > b) { return 1;}
return 0;
}
)
let max = indexes[indexes.length - 1]
//Создаём массив - маску от 0 до самого высокого значения id
let mask:any = []
for (let i = 0; i <= max; i++) {
mask.push(i)
}
//Ищем разницу между существующими id окон и маской. Список пропущенных значений есть список доступных имён.
let difference = indexes
.filter((num:any):any => !mask.includes(num))
.concat(mask.filter((num:any):any => !indexes.includes(num)));
// difference - массив нехватающих в списке номеров.
// Если все окна у нас по порядку, без пропусков - нужно добавить новый номер
if (difference.length === 0) {
return(max + 1)
} else {
//Иначе добавить нехватающий
return(difference[0])
}
}
}
//Прохождение по полю children в поисках нужного id
const getIndexById = (id:string, array:Array<ElementsOfObject>):number => {
let index
for (let i = 0; i <= array.length; i++) {
if (array[i] !== undefined) {
if (array[i].id === id) {
index = i
break
}
}
}
if (typeof index === "number") {
return index
} else {
console.log("Я не нашёл нужный индекс, вывел 0")
return 0
}
}
//Извлечение информации из id для поиска пути к ребёнку.
const getObjectFromId = (id:string, array:any):any => {
//Делим строку на массив чисел
let IDs = id.split(" ")
// o o o o o <--
// \ / \ / | Проходимся по каждому слою. Значит номер итерации укажет на количество элементов,
// o o o <-- кторые нужно добавить к строке currentIteration для получения id родителя на этом уровне вложенности.
// \ / / (наверное, проще её создавать с нуля, зная сколько нужно будет элементов)
// o <--
const getNewIdString = (index:number) => {
let id = ""
for (let i = 0; i < index ;i++) {
id = id + " " + IDs[i]
}
return id.slice(1) //убираем пробел в начале
}
//Счётчик вложенности
let nestingCounter = 0
//В пересчётах в каждом слое вложенности сюда сохраняется найденный объект
let bufferObject
//Считаем до какого уровня вложенности нам вообще искать ребёнка
let stopIndex = IDs.length
const searchId = (array:any) => {
if (nestingCounter === stopIndex) {
//Мы достигли нужного уровня вложенности
return
} else {
nestingCounter = nestingCounter + 1
//Создаём строку id текущей вложенности, танцуя от знания порядкового номера этой вложенности
let calcId = getNewIdString(nestingCounter)
return (
//Здесь можно в заранее созданную переменную оповещать нашли ли мы нужный id. И обработать ошибку если нет
array.forEach((element:any) => {
if (element.id === calcId) {
//Записываем найденный объект и ищем на следующем уровне
bufferObject = element
searchId(element.children)
}
})
)
}
}
searchId(array)
return bufferObject
//Есть два варианта поиска:
//Рекурсивно пройтись по хранилищу тупо ожидая наткнуться на нужного ребёнка
//Проходиться по каждому слою вложенности, создавая id текущего слоя. Находить объект и повторять
//Навскидку второй вариант для ветвистых деревьев быстрее и позволит показать на каком уровне вложенности потанцевально может оборваться поиск...
//при (не дай боже) неверной записи фокусного id
}
export default () => {
//Id - строится на основании всех id родителя + свободное число от 0 до +бесконечности.
//Разделение айдишников в строке посредством пробела
const [stockroom, setStockroom] = React.useState<any>([
{id: "0", type: 7, children: [
{
id: "0 0", type: 7, children: [
// {id: "0 0 0", children: [], type: 4}
]
},
{
id: "0 1", type: 7, children: [
{
id: "0 1 0", children: [
{id: "0 1 0 0", children: [], type: 4},
{id: "0 1 0 1", children: [], type: 4}
], type: 7
}
]
},
{id: "0 2", type: 4, children: []}
]}
])
const [focus, setFocus] = React.useState<string | undefined>() //Хранит путь объекта (id)
// const [focus, setFocus] = React.useState<string | undefined>("1 0 1") //Хранит путь объекта
const setNewFocus = (value:string, multiFocus:boolean) => {
//Фокусы ставятся или удаляются от клика по уже созданным элементам.
if (multiFocus) {
//Клик ЛКМ + shift - мультивыбор
} else {
//Клик ЛКМ - единичный выбор.
setFocus(value)
}
}
//Функция пересоздаёт дерево с проверкой каждого объекта.
// Если объект в фокусе - создаётся новый объект и в него высыпаются старые поля, затем новые поля
const createNewTreeFields = (value:any, tree = stockroom) => {
return (
tree.map((node: any) => {
if (node.id === focus) {
let obj = {
...node,
...value,
}
return (obj)
} else if (node.children.length !== 0) {
return {
...node,
children: createNewTreeFields(value, node.children)
}
} else {
return node
}
})
)
}
//Создание дерева с обновлённым объектом
const createNewTreeObject = (value:any, tree = stockroom) => {
return (
tree.map((node: any) => {
if (node.id === value.id) {
return value
} else if (node.children.length !== 0) {
return {
...node,
children: createNewTreeObject(value, node.children)
}
} else {
return node
}
})
)
}
// Изменение типа очищает все поля
const typeHC = (type:any): void => {
if (focus !== undefined) {
setStockroom(createNewTreeFields({type:type}))
}
}
const colorHC = (color:any) => {
if (focus !== undefined) {
setStockroom(createNewTreeFields({color:color}))
}
}
const createObject = (obj:any, type:number = 4) => {
if (focus !== undefined) {
//Если фокусный элемент - контейнер, добавление происходит внутрь него
//Если фокусный элемент - не контейнер, добавление происходит после объекта с фокусом
const focusedObj = getObjectFromId(focus, stockroom)
if (focusedObj.type === 7) {
//Кладём внутрь фокусного объекта
//Находим свободный ид и прикрепляем его к родительскому id
let newId:any = getFreeNumber(focusedObj.children)
newId = focusedObj.id + " " + newId
//Создаём новый объект
const newObj = {
id: newId,
type: type,
children: []
}
focusedObj.children.push(newObj)
//Создаём дерево с обновлённым родителем
const newTree = createNewTreeObject(focusedObj)
setStockroom(newTree)
} else {
//Кладём рядом с фокусным объектом
//Находим родителя
//Отфигачиваем последний id
let parentId:any = focus.split(" ")
parentId.pop()
parentId = parentId.join(' ')
const parentObj = getObjectFromId(parentId, stockroom)
//Находим свободный ид и прикрепляем его к родительскому id
let newId:any = getFreeNumber(parentObj.children)
newId = parentId + " " + newId
//Создаём новый объект
const newObj = {
id: newId,
type: type,
children: []
}
//Создаём новый массив для поля-children-родителя и присваиваем этот массив
let newChildrenArr = []
for (let i = 0; parentObj.children.length > i ; i++) {
let node = parentObj.children[i]
if (node.id === focus) {
newChildrenArr.push(node)
newChildrenArr.push(newObj)
} else {
newChildrenArr.push(node)
}
}
parentObj.children = newChildrenArr
//Создаём дерево с обновлённым родителем
const newTree = createNewTreeObject(parentObj)
setStockroom(newTree)
}
}
}
const deleteObject = () => {
if (focus !== undefined) {
//Если просто запретить вкладывать объект при создании дерева - будет массив со значением undefined
//Поэтому скажем родителю, что его массив опустел
const focusedObj = getObjectFromId(focus, stockroom)
//Отфигачиваем последний id
let parentId:any = focus.split(" ")
parentId.pop()
parentId = parentId.join(' ')
const parentObj = getObjectFromId(parentId, stockroom)
//Создаём новый массив для поля-children-родителя, не включая в него фокусный объект
let newChildrenArr = []
for (let i = 0; parentObj.children.length > i ; i++) {
let node = parentObj.children[i]
if (node.id !== focus) {
newChildrenArr.push(node)
}
}
parentObj.children = newChildrenArr
let newTree = createNewTreeObject(parentObj)
console.log(stockroom)
console.log(newTree)
setStockroom(newTree)
}
}
// const changeFocus = (id: number): void => {
// //Не менять фокус если снова выбрано то же окно
// if (focus !== id) {
// //Хранилище с отменённым фокусом у объектов (по задумке у одного элемента)
// let newArr = stockroom.map((e:ElementsOfObject) => {
// e.isFocus = false
// return e
// })
//
// //Получаем индексы фокусированных объектов. Новый и, если есть, старый
// let index = getIndexById(id, stockroom)
//
// //Устанавливаем новый фокус и пересоздаём массив
// setFocus(id)
// saveCondition("focus", id)
//
// newArr[index].isFocus = true
// setStockroom([...newArr])
// }
// }
// const changeBgColor = (color: string): void => {
// if (focus !== undefined) {
// let index = getIndexById(focus, stockroom)
//
// let newArr = stockroom
// newArr[index].color = color
// setStockroom([...newArr])
// saveCondition("stockroom", newArr)
// }
// }
// const changeText = (text: string): void => {
// if (focus !== undefined) {
// let index = getIndexById(focus, stockroom)
// let newArr = stockroom
// newArr[index].text = text
// setStockroom([...newArr])
// saveCondition("stockroom", newArr)
// }
// }
//
// const createObject = (obj:ElementsOfObject) => {
//
// //Получаем и присваиваем первый свободный айдишник (по возрастанию)
// const free = getFreeNumber(stockroom)
// obj.id = free
//
// //Хранилище с отменённым фокусом у объектов (по задумке у одного элемента)
// let newArr = stockroom.map((e:ElementsOfObject) => {
// e.isFocus = false
// return e
// })
//
// //Мы должны вставить новый объект следующим после того, на котором фокус. Это достигается позиционированием в массив
// if (focus === undefined){ //фокуса нет - добавляем в конец массива
// newArr.push(obj)
// setStockroom([...newArr])
// saveCondition("stockroom", newArr)
// //Говорим стейту с фокусом, что фокус изменился
// setFocus(newArr.length - 1)
// } else { //фокус есть - добавляем после объекта с фокусом
//
//
//
// let index = getIndexById(focus, stockroom)
// let current = stockroom[index]
// //Объект в фокусе - контейнер. Новый объект создаётся с указанием, что контейнер - родитель
// if (current.type === 7) {
// obj.parent = current.id
// }
//
// newArr.splice(index + 1, 0, obj)
//
// //Говорим стейту с фокусом, что фокус изменился
// setFocus(index + 1)
// setStockroom([...newArr])
// saveCondition("stockroom", newArr)
// }
// }
// const deleteObject = (id: number): void => {
// let index = getIndexById(id, stockroom)
// //Проверка, что объект с таким id существует
// if (stockroom[index] !== undefined) {
// //Если удалён был фокусный объект - фокус теперь неизвестен
// if (stockroom[index].isFocus) {
// setFocus(undefined)
// }
//
// let newArr:any = []
// //Если удалённый объект был хранилищем (контейнером, или селектом), мы не вложим в новый массив его и его потомков
// if (stockroom[index].type === 1 || stockroom[index].type === 7) {
// stockroom.forEach((e:any, i:number) => {
// if (e.id !== id) {
// if (e.parent !== id) {
// newArr.push(e)
// } else {
// if (e.isFocus) {
// setFocus(undefined)
// }
// }
// }
// })
// } else {
// newArr = stockroom
// newArr.splice(index, 1)
// }
// setStockroom([...newArr])
// saveCondition("stockroom", newArr)
// }
// }
return(
<>
<Header/>
<HStack
justifyContent="space-between"
alignItems="normal"
>
<VStack
minWidth="200px"
bgColor="lightgray"
height="98vh"
padding="10px"
>
</VStack>
<VStack>
<WorkSpace
stockroom={stockroom}
setNewFocus={setNewFocus}
focus={focus}
/>
</VStack>
<VStack
minWidth="250px"
bgColor="lightgray"
height="98vh"
padding="10px"
overflow="auto"
>
<Settings
types={types}
stockroom={stockroom}
typeHC={typeHC}
focus={focus}
changeFocus={stockroom}
changeBgColor={colorHC}
changeText={stockroom}
getIndexById={getIndexById}
createObject={createObject}
deleteObject={deleteObject}
/>
<Button onClick={() => {
console.log(stockroom)
}}>info</Button>
</VStack>
</HStack>
</>
)
}