You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

315 lines
9.1 KiB

import { Component } from '@angular/core';
import { TreeService } from '../Helper/tree.service';
import { getEmail, gotoPage } from '../Helper/Helpers';
import { Router } from '@angular/router';
@Component({
selector: 'app-create-image',
imports: [],
templateUrl: './create-image.component.html',
styleUrl: './create-image.component.css'
})
export class CreateImageComponent {
private root: TreeService = new TreeService("Root", "", true, 1, null);
private allFiles: File[] | null = null;
constructor(private router: Router) {}
// initialize
ngOnInit() : void {
// create the root and refresh the file tree
this.RefreshFileTree();
}
RefreshFileTree() {
const filetree = document.getElementById('FileTree') as HTMLUListElement;
filetree.innerHTML = '';
// create list and add the root
const list = document.createElement('ul');
// go through full tree
const fulllist = this.AddListItem(list, this.root);
filetree.appendChild(fulllist);
this.ClearInputs();
}
// uploading files through dropbox
onFileChange(event: any) {
const files: FileList = event.target.files;
if (files.length > 0) {
if (!this.allFiles) this.allFiles = []; // set the array up if it's null
for (let i=0; i < files.length; i++) {
this.allFiles?.push(files[i]);
// add to tree
if (this.AddFileToTree(files[i], false, "", "")) return;
}
// reset files inside dropbox?
this.RefreshFileTree();
this.ClearInputs();
}
}
// add the file to the tree
AddFileToTree(file: File | null, dir: boolean, filename: string, contents: string) : boolean{
const elements = document.querySelectorAll('.selected-node');
// make sure a parent node is selected
if (elements.length == 0) {
alert('Must select a Directory');
this.ClearInputs();
return true;
}
// make sure all the nodes selected are directories
for (let i=0; i < elements.length; i++) {
let li = elements[i] as HTMLLIElement;
if (li.firstChild?.textContent?.substring(0,4) !== "(D)-") {
alert('Must select a directory');
this.ClearInputs();
return true;
}
}
// loop through all the elements adding the name of the file to the tree
for (let i=0; i < elements.length; i++) {
// get the parent node selected
let li = elements[i] as HTMLLIElement;
let results = this.getNodeNumFromClass(li);
let parentname: string = (results[0]).toString();
let parentnum: number = Number(results[1]);
let node = this.root.getNodeByName(parentname,parentnum);
// if the parent node isnt a directory, dont add it
if (node?.getDir() == false) {
alert('can only add files/folders to directories');
this.ClearInputs();
return true;
}
// make sure the filename isnt taken already
if (!node?.IsNameTaken(filename)) {
// get the number of nodes of this name for nodenum
let nodes: TreeService[] = [];
nodes = this.root.getNodesSameName(filename, nodes);
let nodenum = nodes.length + 1;
// add the node to the tree
if (file == null) { // not using dropbox
let newFile = new TreeService(filename, contents, dir, nodenum, node);
node?.AddChild(newFile);
}
else { // using dropbox
let FileObjName : string = file?.name!;
let newFile = new TreeService(FileObjName, "", false, nodenum, node);
node?.AddChild(newFile);
}
}
else {
alert('That file name is already under this directory');
this.ClearInputs();
return true;
}
}
return false;
}
// get the file stuff through creating a new file
getFile(dir: boolean) {
let nameElement = document.getElementById('filename') as HTMLInputElement;
let filename: string = nameElement.value;
let contentsElement = document.getElementById('filecontents') as HTMLTextAreaElement;
let contents : string = contentsElement.value;
if(this.AddFileToTree(null, dir, filename, contents)) return;
this.RefreshFileTree();
}
// use recursion to go through the tree adding each child
AddListItem(list: HTMLUListElement, node: TreeService) {
// add node to current list
const nodeitem = document.createElement('li');
const spanitem = document.createElement('span');
if (node.getDir()) spanitem.textContent = '(D)-' + node.getName();
else spanitem.textContent = node.getName();
// add the name and nodenum to the class list
spanitem.classList.add(node.getName() + node.getNodeNum());
spanitem.addEventListener('click', function(nodeitem) {
const listitem = nodeitem.target as HTMLLIElement;
listitem?.classList.toggle('selected-node');
});
nodeitem.appendChild(spanitem);
// add to list
list.appendChild(nodeitem);
// if node has children
if (node.getChildren().length > 0) {
let nodechildren = node.getChildren();
const childlist = document.createElement('ul');
for (var i=0; i < nodechildren.length; i++) {
let child = nodechildren[i];
list.appendChild(this.AddListItem(childlist, child));
}
}
// return the whole list
return list;
}
// get nodenum from class list
getNodeNumFromClass(item : HTMLLIElement) {
// get the class list of the selected item
const WholeClassList = item.classList;
const namenum = WholeClassList[0];
// break up the string into the two parts
const index = namenum.search(/\d/);
const name = namenum.substring(0,index);
let num : number = Number(namenum.substring(index));
const results = [name,num];
return results;
}
// delete a file from the tree
DeleteFile() {
const items = document.querySelectorAll('.selected-node');
// go through each item selected and remove it from parent
for (var i=0; i < items.length; i++) {
let li = items[i] as HTMLLIElement;
// get the name and num from class list
let results = this.getNodeNumFromClass(li);
let name : string = results[0].toString();
let num : number = Number(results[1]);
let node = this.root.getNodeByName(name,num);
// if root then delete everything
if (node?.getName() === 'Root') {
this.root.DeleteTheChildren();
this.RefreshFileTree();
return;
}
// remove the correct nodes
const parent = node?.getParent();
const newchildren = parent?.getChildren().filter(child => child.getName() !== node?.getName());
parent?.setChildren(newchildren!);
}
// refresh the tree visual
this.RefreshFileTree();
}
// Create the actual Image
CreateImage() {
const imagename = this.getImageName();
if (imagename === true) return;
this.root.DeleteParentRef();
this.SendTree(imagename);
}
// get the name of the image and add the time to it
getImageName() {
const imgElement = document.getElementById('ImageName') as HTMLInputElement;
const imgname = imgElement.value;
// make sure name is included
if (imgname === undefined || imgname === null || imgname === '') {
alert('Must include a name for the image');
return true;
}
// docker states all image names must be lowercase, so have to check for that
if (/[A-Z]/.test(imgname) === true) {
alert('Image name must be all lowercase');
return true;
}
// get the current time to add to the name so no images have same name
let time = new Date().toLocaleTimeString([], {
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false
});
// get rid of the colons and add the time to the image name
time = time.replace(/:/g,'');
return imgname + time;
}
// send the full tree structure to the server side
async SendTree(imgname : string) {
const data = {
root: this.root, imgname: imgname, email: getEmail()
};
// create a form data to hold both JSON and the files
const formdata = new FormData();
// append each file to the form data with the key files
this.allFiles?.forEach((file : File) => {
formdata.append("files", file, file.name);
console.log(file.name);
});
formdata.append('data', JSON.stringify(data));
// send the post request
const res = await fetch('api/images/AddImage', {
method: 'POST',
body: formdata
});
if (res.ok) {
// go back to modify contest
}
}
// clear the input fields after each addition/error
ClearInputs() {
// contents of file
let contentElement = document.getElementById('filecontents') as HTMLTextAreaElement;
contentElement.value = '';
// name of file
let filenameElement = document.getElementById('filename') as HTMLInputElement;
filenameElement.value = '';
// file input box
let fileinputElement = document.getElementById('FileInput') as HTMLInputElement;
fileinputElement.value = '';
}
// go back to Modify Contest
navtoPageMC() {
gotoPage(this.router, '/modify-contest');
}
}