Skip to content

Commit

Permalink
Merge pull request #112 from DDMAL/empty-file
Browse files Browse the repository at this point in the history
feat: support new empty file
  • Loading branch information
kunfang98927 authored Jul 12, 2024
2 parents 2d2001a + 94f1665 commit 3945969
Show file tree
Hide file tree
Showing 6 changed files with 190 additions and 1 deletion.
7 changes: 7 additions & 0 deletions assets/img/empty-file.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions deployment/server/dashboard.html
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@
src="./Cress-gh/assets/img/new-folder.svg"
title="folder"
/>
<img
id="add-file-button"
class="action-bar-item-container active"
src="./Cress-gh/assets/img/empty-file.svg"
title="file"
/>
<img
id="upload-new-doc-button"
class="action-bar-item-container active"
Expand Down
4 changes: 4 additions & 0 deletions src/Dashboard/ContextMenuContent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ export const defaultOptions = `<div id="cm-upload-doc-btn" class="context-menu-i
<div id="cm-new-folder-btn" class="context-menu-item-wrapper">
<div class="context-menu-item">New folder</div>
<img class="context-menu-item-icon" src="${__ASSET_PREFIX__}assets/img/new-folder.svg">
</div>
<div id="cm-new-file-btn" class="context-menu-item-wrapper">
<div class="context-menu-item">New Empty File</div>
<img class="context-menu-item-icon" src="${__ASSET_PREFIX__}assets/img/empty-file.svg">
</div>`;

// If a single file is selected
Expand Down
153 changes: 152 additions & 1 deletion src/Dashboard/Dashboard.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { IEntry, IFile, IFolder, FileSystemTools } from './FileSystem';
import { deleteDocument, updateDocName } from './Storage';
import { deleteDocument, updateDocName, addDocument } from './Storage';
import { FileSystemManager } from './FileSystem';
import { ShiftSelectionManager, dashboardState } from './DashboardTools';
import { InitUploadArea } from './UploadArea';
import * as contextMenuContent from './ContextMenuContent';
import { ModalWindow, ModalWindowView } from '../utils/ModalWindow';
import { v4 as uuidv4 } from 'uuid';

const documentsContainer: HTMLDivElement = document.querySelector(
'#fs-content-container',
Expand All @@ -25,6 +26,8 @@ const uploadDocumentsButton: HTMLButtonElement = document.querySelector(
);
const newFolderButton: HTMLButtonElement =
document.querySelector('#add-folder-button');
const newFileButton: HTMLButtonElement =
document.querySelector('#add-file-button');

const shiftSelection = new ShiftSelectionManager();
const fsm = FileSystemManager();
Expand All @@ -49,6 +52,7 @@ openButton?.addEventListener('click', openDocsHandler);
removeButton?.addEventListener('click', removeDocsHandler);
uploadDocumentsButton?.addEventListener('click', openUploadAreaHandler);
newFolderButton?.addEventListener('click', openNewFolderWindow);
newFileButton?.addEventListener('click', openNewFileWindow);

// Sorting algorithms
// const sortByAlphanumerical = (a: IEntry, b: IEntry) => a.name.localeCompare(b.name);
Expand Down Expand Up @@ -517,6 +521,7 @@ function updateActionBarButtons() {
) {
uploadDocumentsButton.classList.remove('active');
newFolderButton.classList.remove('active');
newFileButton.classList.remove('active');
removeButton.classList.remove('active');
if (state.getSelectedEntries().length) {
openButton.classList.add('active');
Expand All @@ -528,6 +533,7 @@ function updateActionBarButtons() {
else if (state.isInTrash()) {
uploadDocumentsButton.classList.remove('active');
newFolderButton.classList.remove('active');
newFileButton.classList.remove('active');
removeButton.classList.remove('active');
openButton.classList.remove('active');
}
Expand All @@ -537,20 +543,23 @@ function updateActionBarButtons() {
removeButton.classList.remove('active');
uploadDocumentsButton.classList.remove('active');
newFolderButton.classList.remove('active');
newFileButton.classList.remove('active');
}
// selecting entries
else if (state.getSelectedEntries().length) {
openButton.classList.add('active');
removeButton.classList.add('active');
uploadDocumentsButton.classList.remove('active');
newFolderButton.classList.remove('active');
newFileButton.classList.remove('active');
}
// nothing selected, not in ./Samples or ./Trash
else {
openButton.classList.remove('active');
removeButton.classList.remove('active');
uploadDocumentsButton.classList.add('active');
newFolderButton.classList.add('active');
newFileButton.classList.add('active');
}
}

Expand Down Expand Up @@ -723,6 +732,48 @@ function handleAddFolder(folderName: string) {
}
}

/**
* Add new File to current folder and refresh dashboard
*/
function handleAddFile(fileName: string, rowNum: number) {
// create new file element
const newFileTile = document.createElement('div');
newFileTile.classList.add('document-entry');
newFileTile.classList.add('file-entry');
newFileTile.setAttribute('id', 'new-file');

const newFileId = uuidv4();

// add new empty json file to db
const headers = ['image', 'name', 'classification', 'mei'];
const data = Array(rowNum).fill({});
data.forEach((row) => {
headers.forEach((header) => {
row[header] = '';
});
});
const jsonBlob = new Blob([JSON.stringify([headers, ...data], null, 2)], {
type: 'application/json',
});
addDocument(newFileId, fileName, jsonBlob);

// create new file object to dashboard
const datetime = new Date().toLocaleString();
const fileEntry = FileSystemTools.createFile(fileName, newFileId);
const docEntry = FileSystemTools.addMetadata(fileEntry, {
created_on: datetime,
});
const succeeded = FileSystemTools.addEntry(docEntry, state.getParentFolder());
if (succeeded) {
newFileTile.setAttribute('id', fileName);
updateDashboard();
return true;
} else {
newFileTile.remove();
return false;
}
}

/**
* Renames current selection of document on dashboard, updating the database for files
*
Expand Down Expand Up @@ -977,6 +1028,80 @@ function openNewFolderWindow() {
});
}

/**
* Opens New Empty File menu modal window that prompts for a name.
* On clicking the Create button, closes modal window and creates a new empty file.
*/
function openNewFileWindow() {
if (!newFileButton.classList.contains('active')) return;

// generate modal window
const modalWindow = new ModalWindow();
modalWindow.setModalWindowView(ModalWindowView.NEW_FILE);
modalWindow.openModalWindow();

const inputContainer = document.getElementById(
'dashboard_input_container',
) as HTMLDivElement;
const cancelButton = document.getElementById(
'cancel_dashboard',
) as HTMLButtonElement;
const confirmButton = document.getElementById(
'confirm_dashboard',
) as HTMLButtonElement;

// Create input field for file name
const fileNameInput = document.createElement('input');
fileNameInput.id = 'dashboard_input';
fileNameInput.type = 'text';
fileNameInput.placeholder = 'Untitled File';
fileNameInput.value = 'Untitled File';
// label for file name
const fileNameLabel = document.createElement('label');
fileNameLabel.htmlFor = 'dashboard_input';
fileNameLabel.innerText = 'File Name:';
inputContainer.appendChild(fileNameLabel);
inputContainer.appendChild(fileNameInput);

fileNameInput.select();
fileNameInput.focus();

// Create input field for number of rows
const rowNumInput = document.createElement('input');
rowNumInput.id = 'dashboard_input';
rowNumInput.type = 'number';
rowNumInput.min = '1';
rowNumInput.max = '100';
rowNumInput.value = '10';
// label for number of rows
const rowNumLabel = document.createElement('label');
rowNumLabel.htmlFor = 'dashboard_input';
rowNumLabel.innerText = 'Number of Rows:';
inputContainer.appendChild(rowNumLabel);
inputContainer.appendChild(rowNumInput);

cancelButton.addEventListener('click', () => modalWindow.hideModalWindow());
confirmButton.addEventListener('click', () =>
confirmNewFileAction(
modalWindow,
fileNameInput.value,
parseInt(rowNumInput.value),
),
);

inputContainer.addEventListener('keydown', (event) => {
if (event.key === 'Escape') {
modalWindow.hideModalWindow();
} else if (event.key === 'Enter') {
confirmNewFileAction(
modalWindow,
fileNameInput.value,
parseInt(rowNumInput.value),
);
}
});
}

function confirmNewFolderAction(modalWindow: ModalWindow, folderName: string) {
if (!nameExists(folderName)) {
modalWindow.hideModalWindow();
Expand All @@ -987,6 +1112,20 @@ function confirmNewFolderAction(modalWindow: ModalWindow, folderName: string) {
}
}

function confirmNewFileAction(
modalWindow: ModalWindow,
fileName: string,
rowNum: number,
) {
if (!nameExists(fileName)) {
modalWindow.hideModalWindow();
handleAddFile(fileName, rowNum);
} else {
window.alert('The file name already exists in the current folder!');
openNewFileWindow();
}
}

/**
* Opens Rename menu modal window that prompts for a new name.
*/
Expand Down Expand Up @@ -1261,6 +1400,7 @@ function showContextMenu(view: string, clientX: number, clientY: number) {
const moveBtn = document.getElementById('cm-move-btn');
const updateDocBtn = document.getElementById('cm-upload-doc-btn');
const newFolderBtn = document.getElementById('cm-new-folder-btn');
const newFileBtn = document.getElementById('cm-new-file-btn');

if (deleteBtn) {
deleteBtn.classList.add('disabled');
Expand All @@ -1277,6 +1417,9 @@ function showContextMenu(view: string, clientX: number, clientY: number) {
if (newFolderBtn) {
newFolderBtn.classList.add('disabled');
}
if (newFileBtn) {
newFileBtn.classList.add('disabled');
}
}

// get the position of the user's mouse
Expand Down Expand Up @@ -1478,6 +1621,14 @@ function setContextMenuItemsEventListeners(view: string) {
contextMenu.classList.add('hidden');
openNewFolderWindow();
});

// "New file" menu item
document
.querySelector(`.${btnClassname}#cm-new-file-btn`)
.addEventListener('click', (_e) => {
contextMenu.classList.add('hidden');
openNewFileWindow();
});
}
}

Expand Down
11 changes: 11 additions & 0 deletions src/Dashboard/DashboardContent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,17 @@ export const newFolderHTML = `
</div>
`;

export const newFileHTML = `
<div id="rename_container">
<div id="dashboard_input_container">
</div>
<div id="rename_buttons_container">
<button id="cancel_dashboard">Cancel</button>
<button id="confirm_dashboard">Create</button>
</div>
</div>
`;

export const renameHTML = `
<div id="rename_container">
<div id="dashboard_input_container">
Expand Down
10 changes: 10 additions & 0 deletions src/utils/ModalWindow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { ModalWindowInterface } from '../Interfaces';
import { hotkeysModal } from '../Contents';
import {
newFolderHTML,
newFileHTML,
renameHTML,
uploadAreaHTML,
} from '../Dashboard/DashboardContent';
Expand All @@ -17,6 +18,7 @@ export enum ModalWindowView {
MOVE_TO,
NEW_FOLDER,
RENAME,
NEW_FILE,
}

enum ModalWindowState {
Expand Down Expand Up @@ -110,6 +112,8 @@ export class ModalWindow implements ModalWindowInterface {
// break;
case ModalWindowView.NEW_FOLDER:

case ModalWindowView.NEW_FILE:

case ModalWindowView.RENAME:

default:
Expand All @@ -132,6 +136,7 @@ export class ModalWindow implements ModalWindowInterface {
case ModalWindowView.DOCUMENT_UPLOAD:
case ModalWindowView.MOVE_TO:
case ModalWindowView.NEW_FOLDER:
case ModalWindowView.NEW_FILE:
case ModalWindowView.RENAME:
document.getElementById(
'cress-modal-window-content-container',
Expand Down Expand Up @@ -191,6 +196,11 @@ export class ModalWindow implements ModalWindowInterface {
container.innerHTML = newFolderHTML;
break;

case ModalWindowView.NEW_FILE:
title.innerText = 'NEW FILE';
container.innerHTML = newFileHTML;
break;

case ModalWindowView.RENAME:
title.innerText = 'RENAME';
container.innerHTML = renameHTML;
Expand Down

0 comments on commit 3945969

Please sign in to comment.