feature/fe-folder

This commit is contained in:
Khaiyb949 2024-06-24 13:31:06 +07:00
parent aafaab0cb1
commit 11418bc4c6
9 changed files with 1565 additions and 420 deletions

View File

@ -0,0 +1,373 @@
import { Component, OnInit, Renderer2, ElementRef } from '@angular/core';
import { FoldersService } from 'src/app/services/rest/folders.service';
import { Document, Folders, Results } from 'src/app/data/folders';
@Component({
selector: 'app-view-all-folder',
templateUrl: './viewall-forder.component.html',
styleUrls: ['./viewall-forder.component.scss']
})
export class ViewallForderComponent implements OnInit {
folders: Folders[] = [];
documents: Document[] = [];
results: Results[] = [];
selectedFolderId: number | null = null;
constructor(private foldersService: FoldersService, private renderer: Renderer2, private elementRef: ElementRef) {}
ngOnInit(): void {
this.foldersService.getFoldersAndDocuments().subscribe({
next: (data: any) => {
this.folders = data.folders;
this.documents = data.documents;
this.initializeFolders();
this.initializeDocuments();
this.addEventListeners();
},
error: error => {
console.error('Error fetching data:', error);
}
});
this.foldersService.getResults().subscribe({
next: (data: any) => {
this.results = data.results.filter(result => result.parent_folder !== null);
this.initializeFolders();
},
error: error => {
console.error('Error fetching results:', error);
}
});
}
initializeFolders(): void {
const foldersContainer = this.elementRef.nativeElement.querySelector('#folders-container');
if (foldersContainer) {
const allFolders = [...this.folders, ...this.results];
foldersContainer.innerHTML = '';
const folderMap = new Map<number, Folders[]>();
allFolders.forEach(folder => {
const parentId = folder.parent_folder ?? null;
if (!folderMap.has(parentId)) {
folderMap.set(parentId, []);
}
folderMap.get(parentId)?.push(folder);
});
const createFolders = (parentId: number | null, parentDiv: HTMLElement | null): void => {
const children = folderMap.get(parentId) || [];
children.forEach(folder => {
const folderHTML = this.createFolderHTML(folder);
if (parentDiv) {
this.renderer.appendChild(parentDiv, folderHTML);
} else {
this.renderer.appendChild(foldersContainer, folderHTML);
}
createFolders(folder.id, folderHTML.querySelector('.children-container') as HTMLElement);
});
};
createFolders(null, null);
}
}
initializeDocuments(): void {
const documentsContainer = this.elementRef.nativeElement.querySelector('#documents-container');
if (documentsContainer) {
documentsContainer.innerHTML = '';
const addedDocumentFilenames = new Set<string>();
this.documents.forEach(doc => {
const folder = this.findFolderById(doc.folder_id);
if (!addedDocumentFilenames.has(doc.filename)) {
if (folder && folder.id > 0) {
const folderDiv = this.findFolderDiv(folder.id);
if (folderDiv) {
const documentsContainerInFolder = folderDiv.querySelector('.documents-container') as HTMLElement;
if (documentsContainerInFolder && !documentsContainerInFolder.querySelector(`.document[data-document-id="${doc.id}"]`)) {
const documentHTML = this.createDocumentHTML(doc);
this.renderer.appendChild(documentsContainerInFolder, documentHTML);
addedDocumentFilenames.add(doc.filename);
}
}
} else {
if (!documentsContainer.querySelector(`.document[data-document-id="${doc.id}"]`)) {
const documentHTML = this.createDocumentHTML(doc);
this.renderer.appendChild(documentsContainer, documentHTML);
addedDocumentFilenames.add(doc.filename);
}
}
}
});
}
}
addEventListeners(): void {
// Handling double click for elements with class .folder-cha
const folderChaElements = this.elementRef.nativeElement.querySelectorAll('.folder-cha');
folderChaElements.forEach(item => {
this.renderer.listen(item, 'dblclick', (event: Event) => {
const target = event.currentTarget as HTMLElement;
const folderElement = target.closest('.folder') as HTMLElement;
const folderId = Number(folderElement?.dataset.folderId);
this.confirmDisplayFolderContents(folderId);
});
});
// Remove all 'click' event listeners on 'tr' elements
const folderRows = this.elementRef.nativeElement.querySelectorAll('tr[data-folder-id]');
folderRows.forEach(row => {
// Completely remove 'click' event listener
row.removeEventListener('click', this.handleRowClick);
// Use 'dblclick' instead of 'click'
this.renderer.listen(row, 'dblclick', (event: Event) => {
const target = event.currentTarget as HTMLTableRowElement;
const folderId = Number(target.dataset.folderId);
this.confirmDisplayFolderContents(folderId);
});
});
// Resizing folderLeft section (unchanged from original)
const folderLeft = this.elementRef.nativeElement.querySelector('#folderLeft');
if (folderLeft) {
const resizeHandle = folderLeft.querySelector('.resize-handle') as HTMLElement;
if (resizeHandle) {
let startX: number;
let startWidth: number;
const resizeWidth = (event: MouseEvent) => {
const newWidth = startWidth + (event.clientX - startX);
folderLeft.style.width = `${newWidth}px`; // Corrected template literal usage
const folderRight = this.elementRef.nativeElement.querySelector('.folder-right') as HTMLElement;
if (folderRight) {
folderRight.style.width = `calc(100% - ${newWidth}px)`; // Corrected template literal usage
}
};
const stopResize = () => {
document.removeEventListener('mousemove', resizeWidth);
document.removeEventListener('mouseup', stopResize);
};
this.renderer.listen(resizeHandle, 'mousedown', (event: MouseEvent) => {
startX = event.clientX;
startWidth = parseInt(window.getComputedStyle(folderLeft).width, 10);
document.addEventListener('mousemove', resizeWidth);
document.addEventListener('mouseup', stopResize);
});
}
}
}
// Example function for handling 'click' on rows (if necessary)
handleRowClick(event: Event) {
const target = event.currentTarget as HTMLTableRowElement;
const folderId = Number(target.dataset.folderId);
// Handle click action here if needed
}
confirmDisplayFolderContents(folderId: number): void {
this.displayFolderContents(folderId);
}
displayFolderContents(folderId: number, parentRow: HTMLTableRowElement | null = null): void {
const tableBody = this.elementRef.nativeElement.querySelector('.folder-contents tbody');
if (tableBody) {
const rowsToRemove = parentRow
? tableBody.querySelectorAll(`.child-of-folder-${folderId}`)
: tableBody.querySelectorAll('tr');
rowsToRemove.forEach(row => row.remove());
const childFolders = this.folders.filter(folder => folder.parent_folder === folderId);
const childResults = this.results.filter(result => result.parent_folder === folderId);
const allChildFolders = [...childFolders, ...childResults];
allChildFolders.forEach(folder => {
const row = this.createFolderRowHTML(folder, folderId);
if (parentRow) {
parentRow.insertAdjacentElement('afterend', row);
} else {
tableBody.appendChild(row);
}
});
const childDocuments = this.documents.filter(doc => doc.folder_id === folderId);
childDocuments.forEach(doc => {
const row = this.createDocumentRowHTML(doc, folderId);
if (parentRow) {
parentRow.insertAdjacentElement('afterend', row);
} else {
tableBody.appendChild(row);
}
});
this.addRowEventListeners();
}
}
createFolderRowHTML(folder: Folders, parentId: number): HTMLElement {
const row = document.createElement('tr');
row.classList.add(`child-of-folder-${parentId}`);
row.dataset.folderId = folder.id.toString();
const nameCell = document.createElement('td');
const folderIcon = document.createElement('i');
folderIcon.classList.add('fa-solid', 'fa-folder');
const folderName = document.createElement('p');
folderName.textContent = folder.name;
nameCell.appendChild(folderIcon);
nameCell.appendChild(folderName);
const dateCell = document.createElement('td');
dateCell.textContent = '11/10/2002'; // Placeholder date
const typeCell = document.createElement('td');
typeCell.textContent = 'File Folder';
const sizeCell = document.createElement('td');
sizeCell.textContent = '2 KB'; // Placeholder size
row.appendChild(nameCell);
row.appendChild(dateCell);
row.appendChild(typeCell);
row.appendChild(sizeCell);
return row;
}
createDocumentRowHTML(doc: Document, parentId: number): HTMLElement {
const row = document.createElement('tr');
row.classList.add(`child-of-folder-${parentId}`);
row.dataset.documentId = doc.id.toString();
const nameCell = document.createElement('td');
const fileIcon = document.createElement('i');
fileIcon.classList.add('fa-solid', 'fa-file');
const fileName = document.createElement('p');
fileName.textContent = doc.filename;
nameCell.appendChild(fileIcon);
nameCell.appendChild(fileName);
const dateCell = document.createElement('td');
dateCell.textContent = '11/10/2002'; // Placeholder date
const typeCell = document.createElement('td');
typeCell.textContent = 'txt'; // Placeholder type
const sizeCell = document.createElement('td');
sizeCell.textContent = '2 KB'; // Placeholder size
row.appendChild(nameCell);
row.appendChild(dateCell);
row.appendChild(typeCell);
row.appendChild(sizeCell);
return row;
}
createFolderHTML(folder: Folders): HTMLElement {
const folderDiv = document.createElement('div');
folderDiv.classList.add('folder');
folderDiv.dataset.folderId = folder.id.toString();
const folderIcon = document.createElement('i');
folderIcon.classList.add('fa', 'fa-solid', 'fa-chevron-right');
const folderIconFolder = document.createElement('i');
folderIconFolder.classList.add('fa', 'fa-solid', 'fa-folder');
const folderName = document.createElement('p');
folderName.textContent = folder.name;
const folderHeader = document.createElement('div');
folderHeader.classList.add('folder-cha');
folderHeader.appendChild(folderIcon);
folderHeader.appendChild(folderIconFolder);
folderHeader.appendChild(folderName);
folderDiv.appendChild(folderHeader);
const childrenContainer = document.createElement('div');
childrenContainer.classList.add('children-container');
childrenContainer.style.display = 'none';
folderDiv.appendChild(childrenContainer);
// Variable to store the logged folder id
let loggedFolderId: number | null = null;
this.renderer.listen(folderHeader, 'click', () => {
// Check and log folder id when clicking on folderHeader
const clickedFolderId = folder.id;
if (clickedFolderId !== loggedFolderId) {
if (loggedFolderId !== null) {
console.log(`Removed log for folder ${loggedFolderId}`);
}
console.log(`Clicked folder ${clickedFolderId}`);
loggedFolderId = clickedFolderId;
}
// Display contents of the folder in the tbody
this.displayFolderContents(clickedFolderId);
});
this.renderer.listen(folderIcon, 'click', (event: Event) => {
// Prevent folderHeader click event when clicking on folderIcon
event.stopPropagation();
// Toggle display of childrenContainer
if (childrenContainer.style.display === 'none') {
childrenContainer.style.display = 'block';
folderIcon.style.transform = 'rotate(90deg)';
folderIconFolder.classList.replace('fa-folder', 'fa-folder-open');
} else {
childrenContainer.style.display = 'none';
folderIcon.style.transform = '';
folderIconFolder.classList.replace('fa-folder-open', 'fa-folder');
}
});
return folderDiv;
}
createDocumentHTML(doc: Document): HTMLElement {
const documentDiv = document.createElement('div');
documentDiv.classList.add('document');
documentDiv.dataset.documentId = doc.id.toString();
const documentName = document.createElement('p');
documentName.textContent = doc.filename;
const documentContainer = document.createElement('div');
documentContainer.classList.add('document-container');
documentContainer.appendChild(documentName);
documentDiv.appendChild(documentContainer);
return documentDiv;
}
findFolderById(folderId: number): Folders | undefined {
return this.folders.find(folder => folder.id === folderId);
}
findFolderDiv(folderId: number): HTMLElement | null {
const foldersContainer = document.getElementById('folders-container');
return foldersContainer?.querySelector(`.folder[data-folder-id="${folderId}"]`) as HTMLElement | null;
}
addRowEventListeners(): void {
const folderRows = this.elementRef.nativeElement.querySelectorAll('tr[data-folder-id]');
folderRows.forEach(row => {
this.renderer.listen(row, 'dblclick', (event: Event) => {
const target = event.currentTarget as HTMLTableRowElement;
const folderId = Number(target.dataset.folderId);
this.confirmDisplayFolderContents(folderId);
});
});
}
}

View File

@ -1,8 +1,19 @@
<div class="folder-container">
<div class="sub-folder-container">
<div class="folder-container" id="folderLeft">
<div style="display: none;" class="sub-folder-container">
<form action="">
<input type="text">
<button>UpLoad File</button>
</form>
</div>
<div class="folder-left" id="folderLeft">
<div id="contextMenu" class="addfolder">
<ul>
<li id="am"><a >New file...</a></li>
<li><a >New folder...</a></li>
<li style="border: 1px solid black;"><a >Rename...</a></li>
<li style="border: 1px solid black;"><a >Delete...</a></li>
</ul>
</div>
<div class="folder-left" id="sss">
<div class="folder-left-1">
<div class="folder-left-search">
<button class="search"><i class="fa-solid fa-magnifying-glass"></i></button>
@ -16,16 +27,36 @@
</div>
<div class="resize-handle"></div>
</div>
<div class="folder-right">
<div class="folder-right" id="sss">
<div class="folder-search">
<div class="folder-right-tim"></div>
<div class="folder-right-tim">
<div class="logo-folder">
<i class="fa-solid fa-folder"></i> <i class="fa-solid fa-chevron-right"></i>
</div>
<div class="ten-folder">
<p>Folder 1</p>
<i class="fa-solid fa-chevron-right"></i>
</div>
<div class="ten-folder">
<p>Folder 2</p>
<i class="fa-solid fa-chevron-right"></i>
</div>
<div class="ten-folder">
<p>Folder 3</p>
<i class="fa-solid fa-chevron-right"></i>
</div>
<div class="ten-folder">
<p>Folder 4</p>
<i class="fa-solid fa-chevron-right"></i>
</div>
</div>
<div class="folder-right-search">
<button> <i class="fa-solid fa-magnifying-glass"></i> </button>
<input type="text">
</div>
</div>
<div class="folder-right-conten">
<table>
<table class="folder-contents">
<thead>
<tr>
<td>Name</td>
@ -35,32 +66,7 @@
</tr>
</thead>
<tbody>
<tr>
<td>
<i class="fa-solid fa-folder"></i>
<p>Folder 1</p>
</td>
<td>11/10/2002</td>
<td>
<p>File Folder</p>
</td>
<td>
<p>2 KB</p>
</td>
</tr>
<tr>
<td>
<i class="fa-solid fa-file"></i>
<p>Document</p>
</td>
<td>11/10/2002</td>
<td>
<p>txt</p>
</td>
<td>
<p>2 KB</p>
</td>
</tr>
</tbody>
</table>
</div>

View File

@ -3,12 +3,13 @@ body {
height: 100%;
overflow: hidden;
}
.folder-container {
width: 100%;
height: 100%;
display: flex;
}
.folder-container .folder-left {
.folder-left {
width: 30%;
position: relative;
min-width: 100px;
@ -20,7 +21,7 @@ body {
align-items: center;
flex-direction: column;
overflow: hidden;
}
.resize-handle {
background-color: #f0f0f0;
cursor: ew-resize;
@ -29,11 +30,7 @@ body {
position: absolute;
right: 0;
}
.folder-container .folder-right {
width: 70%;
height: 100vh;
overflow-y: auto;
}
.folder-left-1 {
width: 100%;
height: 30px;
@ -41,6 +38,7 @@ body {
align-items: center;
justify-content: center;
}
.folder-left-search {
width: 85%;
height: 100%;
@ -49,21 +47,24 @@ body {
justify-content: center;
margin-top: 10px;
box-shadow: 0 0 3px 0 gold;
}
.folder-left-search .serch {
.serch {
width: 90%;
height: 100%;
border-left: none;
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
}
.folder-left-search .serch:focus {
&:focus {
outline: none;
}
.serch:focus + .folder-left-search {
&:focus + .folder-left-search {
border: 5px solid gold;
}
.folder-left-search .search {
}
.search {
width: 10%;
height: 100%;
cursor: pointer;
@ -71,17 +72,17 @@ body {
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
}
}
.folder {
width: 95%;
height: auto;
}
#folders-container {
margin-top: 20px;
}
.documents {
width: 95%;
height: auto;
}
.folder-cha {
width: 100%;
height: auto;
@ -89,70 +90,80 @@ body {
cursor: pointer;
margin-top: 2%;
text-align: left;
}
.folder-cha P{
p {
color: #f0f0f0;
}
.folder-cha .fa-solid{
.fa-solid {
color: gold;
padding: 0 5px;
}
.folder-cha .fa-chevron-right{
.fa{
color: gold;
padding: 0 5px;
}
.fa-chevron-right {
color: #f0f0f0;
}
.folder-cha .fa-folder{
.fa-folder {
color: goldenrod;
}
}
.folder-con {
width: 100%;
height: auto;
display: flex;
cursor: pointer;
text-align: left;
}
.folder-con P{
p {
color: #f0f0f0;
}
.foder{
width: 100%;
height: auto;
position: relative;
text-align: left;
}
.folder-con .fa-solid{
.fa-solid {
color: gold;
padding: 0 5px;
}
.folder-con .fa-chevron-right{
.fa-chevron-right {
color: #f0f0f0;
}
.folder-con .fa-folder{
.fa-folder {
color: goldenrod;
}
}
#folders-container {
margin-left: -10%;
}
.docoment {
width: 100%;
display: flex;
align-items: center;
text-align: left;
}
.docomenta,
.document-container {
margin-left: 7%;
}
p {
color: aliceblue;
}
.folder {
position: relative;
overflow: hidden;
padding-left: 20px;
}
.folder .ke {
.ke {
background: #f0f0f0;
width: 1px;
height: 180%;
@ -163,20 +174,28 @@ p{
display: none;
transform: translateY(-15%);
}
}
}
.folder-right {
width: 70%;
height: 100vh;
overflow-y: auto;
.folder-search {
width: 100%;
height: 50px;
display: flex;
align-items: center;
}
.folder-right-tim {
width: 60%;
height: 40px;
background: rgba(128, 128, 128, 0.534);
border-radius: 5px;
margin-left: 10px;
}
.folder-right-search {
width: 30%;
height: 40px;
@ -184,70 +203,83 @@ p{
border-radius: 5px;
margin-left: 50px;
display: flex;
}
.folder-right-search button{
button {
cursor: pointer;
padding: 11px 15px;
border-right: none;
}
.folder-right-search input{
input {
border-left: none;
width: 100%;
}
}
}
.folder-right-conten {
width: 100%;
height: 100%;
}
table {
width: 100%;
border-collapse: collapse;
margin: 20px 0;
background-color: #fff;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
table td{
td {
color: black;
}
table thead {
thead {
background-color: #007bff25;
color: #fff;
}
table thead tr {
tr {
border-bottom: 1px solid #dee2e6;
}
table thead td {
td {
padding: 12px 15px;
text-align: left;
font-weight: bold;
border-left: ăp;
}
}
table tbody tr {
tbody {
tr {
border-bottom: 1px solid #dee2e6;
}
table tbody tr:nth-of-type(even) {
&:nth-of-type(even) {
background-color: #f2f2f2;
}
table tbody tr:hover {
&:hover {
background-color: #f1f1f1;
}
table tbody td {
td {
padding: 12px 15px;
text-align: left;
}
tbody td p{
p {
color: black;
}
table tbody td i {
i {
margin-right: 8px;
}
table tbody td p {
p {
display: inline;
margin: 0;
}
}
}
}
}
}
}

View File

@ -1,92 +1,213 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, Renderer2, ElementRef } from '@angular/core';
import { FoldersService } from 'src/app/services/rest/folders.service';
import { Document, Folders } from 'src/app/data/folders';
import { Document, Folders, Results } from 'src/app/data/folders';
@Component({
selector: 'app-view-all-folder',
templateUrl: './viewall-forder.component.html',
styleUrls: ['./viewall-forder.component.scss']
})
export class ViewAllFolderComponent implements OnInit {
export class ViewallForderComponent implements OnInit {
folders: Folders[] = [];
documents: Document[] = [];
results: Results[] = [];
selectedFolderId: number | null = null;
constructor(private foldersService: FoldersService) {}
constructor(private foldersService: FoldersService, private renderer: Renderer2, private elementRef: ElementRef) {}
ngOnInit(): void {
this.foldersService.getFoldersAndDocuments().subscribe({
next: data => {
next: (data: any) => {
this.folders = data.folders;
this.documents = data.documents;
this.initializeFolders();
this.initializeDocuments();
this.addEventListeners();
this.setupEventListeners();
},
error: error => {
console.error('Error fetching data:', error);
// Xử lý lỗi theo yêu cầu của bạn
}
});
this.foldersService.getResults().subscribe({
next: (data: any) => {
this.results = data.results.filter(result => result.parent_folder !== null);
this.initializeFolders();
},
error: error => {
console.error('Error fetching results:', error);
}
});
}
setupEventListeners(): void {
document.addEventListener("DOMContentLoaded", () => {
const folderLeft = document.getElementById('folderLeft');
const folderright = document.getElementById('folderrightt');
const folderContainer = document.querySelector('.folder-container');
const zoom = document.getElementById("zoomImg");
const contextMenu = document.getElementById("contextMenu");
const toggleButton = document.getElementById("toggleButton");
const amButton = document.getElementById("am");
const subFolderContainer = document.querySelector('.sub-folder-container') as HTMLElement;
let eventsEnabled = false;
amButton.addEventListener("click", () => {
subFolderContainer.style.display = "block";
contextMenu.style.display = "none";
const inputInSubFolder = subFolderContainer.querySelector('input[type="text"]') as HTMLElement;
if (inputInSubFolder) {
inputInSubFolder.focus();
}
const allInputs = document.querySelectorAll('input');
allInputs.forEach((input) => {
if (input !== inputInSubFolder) {
input.blur();
}
});
});
document.getElementById('sss').addEventListener('click', () => {
const contextMenu1 = document.querySelector('.sub-folder-container') as HTMLElement;
if (contextMenu1) {
contextMenu1.style.display = 'none';
}
});
folderLeft.addEventListener('click', () => {
hideContextMenu();
});
folderLeft.addEventListener('contextmenu', (event) => {
event.preventDefault();
showContextMenu(event.clientX, event.clientY);
});
document.addEventListener('mousedown', (event) => {
const targetElement = event.target as HTMLElement;
const clickedInsideContextMenu = contextMenu.contains(targetElement);
const clickedInsideFolderContainer = folderContainer.contains(targetElement);
const clickedInsideAddFolder = targetElement.classList.contains('addfolder') || targetElement.closest('.addfolder');
const clickedInsideAm = targetElement.id === 'am' || targetElement.closest('#am');
if (!clickedInsideContextMenu && !clickedInsideAddFolder && !clickedInsideAm) {
hideContextMenu();
}
if (clickedInsideAm) {
event.preventDefault();
}
});
toggleButton.addEventListener("click", () => {
toggleEvents();
});
function showContextMenu(x: number, y: number) {
if (contextMenu) {
contextMenu.style.display = "block";
contextMenu.style.left = x + "px";
contextMenu.style.top = y + "px";
}
}
function hideContextMenu() {
if (contextMenu) {
contextMenu.style.display = "none";
}
}
function toggleEvents() {
eventsEnabled = !eventsEnabled;
if (eventsEnabled) {
if (zoom) {
zoom.addEventListener("contextmenu", handleContextMenu);
}
} else {
if (zoom) {
zoom.removeEventListener("contextmenu", handleContextMenu);
}
}
}
function handleContextMenu(e: MouseEvent) {
e.preventDefault();
showContextMenu(e.clientX, e.clientY);
}
if (zoom) {
zoom.onmouseup = () => {
if (eventsEnabled) {
hideContextMenu();
}
};
zoom.onmousemove = (e: MouseEvent) => {
// Additional handling if needed
};
}
});
}
initializeFolders(): void {
const foldersContainer = document.getElementById('folders-container');
const foldersContainer = this.elementRef.nativeElement.querySelector('#folders-container');
if (foldersContainer) {
const allFolders = [...this.folders, ...this.results];
foldersContainer.innerHTML = '';
const createFolders = (parentId: number | null, parentDiv: HTMLElement | null) => {
this.folders.forEach(folder => {
if (folder.parent_folder_id === parentId) {
const folderHTML = this.createFolderHTML(folder, parentDiv);
createFolders(folder.id, folderHTML.querySelector('.children-container') as HTMLElement);
const folderMap = new Map<number, Folders[]>();
allFolders.forEach(folder => {
const parentId = folder.parent_folder ?? null;
if (!folderMap.has(parentId)) {
folderMap.set(parentId, []);
}
folderMap.get(parentId)?.push(folder);
});
const createFolders = (parentId: number | null, parentDiv: HTMLElement | null): void => {
const children = folderMap.get(parentId) || [];
children.forEach(folder => {
const folderHTML = this.createFolderHTML(folder);
if (parentDiv) {
this.renderer.appendChild(parentDiv, folderHTML);
} else {
this.renderer.appendChild(foldersContainer, folderHTML);
}
createFolders(folder.id, folderHTML.querySelector('.children-container') as HTMLElement);
});
};
this.folders.forEach(folder => {
if (folder.parent_folder_id === null) {
const folderHTML = this.createFolderHTML(folder);
foldersContainer.appendChild(folderHTML);
this.documents.forEach(doc => {
if (doc.folder_id === folder.id) {
const documentHTML = this.createDocumentHTML(doc);
folderHTML.querySelector('.children-container')?.appendChild(documentHTML);
}
});
createFolders(folder.id, folderHTML.querySelector('.children-container') as HTMLElement);
}
});
createFolders(null, null);
}
}
initializeDocuments(): void {
const documentsContainer = document.getElementById('documents-container');
const foldersContainer = document.getElementById('folders-container');
if (documentsContainer && foldersContainer) {
const documentsContainer = this.elementRef.nativeElement.querySelector('#documents-container');
if (documentsContainer) {
documentsContainer.innerHTML = '';
const addedDocumentFilenames = new Set<string>();
this.documents.forEach(doc => {
if (!addedDocumentFilenames.has(doc.filename)) {
const folder = this.findFolderById(doc.folder_id);
if (folder && folder.id === 71) {
if (!addedDocumentFilenames.has(doc.filename)) {
if (folder && folder.id > 0) {
const folderDiv = this.findFolderDiv(folder.id);
if (folderDiv) {
const documentsContainerInFolder = folderDiv.querySelector('.documents-container');
if (documentsContainerInFolder) {
if (!documentsContainerInFolder.querySelector(`.document[data-document-id="${doc.id}"]`)) {
const documentsContainerInFolder = folderDiv.querySelector('.documents-container') as HTMLElement;
if (documentsContainerInFolder && !documentsContainerInFolder.querySelector(`.document[data-document-id="${doc.id}"]`)) {
const documentHTML = this.createDocumentHTML(doc);
documentsContainerInFolder.appendChild(documentHTML);
this.renderer.appendChild(documentsContainerInFolder, documentHTML);
addedDocumentFilenames.add(doc.filename);
}
}
}
} else {
if (!documentsContainer.querySelector(`.document[data-document-id="${doc.id}"]`)) {
const documentHTML = this.createDocumentHTML(doc);
documentsContainer.appendChild(documentHTML);
this.renderer.appendChild(documentsContainer, documentHTML);
addedDocumentFilenames.add(doc.filename);
}
}
@ -95,24 +216,182 @@ export class ViewAllFolderComponent implements OnInit {
}
}
createFolderHTML(folder: Folders, parentDiv: HTMLElement | null = null): HTMLElement {
addEventListeners(): void {
// Handling double click for elements with class .folder-cha
const folderChaElements = this.elementRef.nativeElement.querySelectorAll('.folder-cha');
folderChaElements.forEach(item => {
this.renderer.listen(item, 'dblclick', (event: Event) => {
const target = event.currentTarget as HTMLElement;
const folderElement = target.closest('.folder') as HTMLElement;
const folderId = Number(folderElement?.dataset.folderId);
this.confirmDisplayFolderContents(folderId);
});
});
// Remove all 'click' event listeners on 'tr' elements
const folderRows = this.elementRef.nativeElement.querySelectorAll('tr[data-folder-id]');
folderRows.forEach(row => {
// Completely remove 'click' event listener
row.removeEventListener('click', this.handleRowClick);
// Use 'dblclick' instead of 'click'
this.renderer.listen(row, 'dblclick', (event: Event) => {
const target = event.currentTarget as HTMLTableRowElement;
const folderId = Number(target.dataset.folderId);
this.confirmDisplayFolderContents(folderId);
});
});
// Resizing folderLeft section (unchanged from original)
const folderLeft = this.elementRef.nativeElement.querySelector('#folderLeft');
if (folderLeft) {
const resizeHandle = folderLeft.querySelector('.resize-handle') as HTMLElement;
if (resizeHandle) {
let startX: number;
let startWidth: number;
const resizeWidth = (event: MouseEvent) => {
const newWidth = startWidth + (event.clientX - startX);
folderLeft.style.width = `${newWidth}px`; // Corrected template literal usage
const folderRight = this.elementRef.nativeElement.querySelector('.folder-right') as HTMLElement;
if (folderRight) {
folderRight.style.width = `calc(100% - ${newWidth}px)`; // Corrected template literal usage
}
};
const stopResize = () => {
document.removeEventListener('mousemove', resizeWidth);
document.removeEventListener('mouseup', stopResize);
};
this.renderer.listen(resizeHandle, 'mousedown', (event: MouseEvent) => {
startX = event.clientX;
startWidth = parseInt(window.getComputedStyle(folderLeft).width, 10);
document.addEventListener('mousemove', resizeWidth);
document.addEventListener('mouseup', stopResize);
});
}
}
}
// Example function for handling 'click' on rows (if necessary)
handleRowClick(event: Event) {
const target = event.currentTarget as HTMLTableRowElement;
const folderId = Number(target.dataset.folderId);
// Handle click action here if needed
}
confirmDisplayFolderContents(folderId: number): void {
this.displayFolderContents(folderId);
}
displayFolderContents(folderId: number, parentRow: HTMLTableRowElement | null = null): void {
const tableBody = this.elementRef.nativeElement.querySelector('.folder-contents tbody');
if (tableBody) {
const rowsToRemove = parentRow
? tableBody.querySelectorAll(`.child-of-folder-${folderId}`)
: tableBody.querySelectorAll('tr');
rowsToRemove.forEach(row => row.remove());
const childFolders = this.folders.filter(folder => folder.parent_folder === folderId);
const childResults = this.results.filter(result => result.parent_folder === folderId);
const allChildFolders = [...childFolders, ...childResults];
allChildFolders.forEach(folder => {
const row = this.createFolderRowHTML(folder, folderId);
if (parentRow) {
parentRow.insertAdjacentElement('afterend', row);
} else {
tableBody.appendChild(row);
}
});
const childDocuments = this.documents.filter(doc => doc.folder_id === folderId);
childDocuments.forEach(doc => {
const row = this.createDocumentRowHTML(doc, folderId);
if (parentRow) {
parentRow.insertAdjacentElement('afterend', row);
} else {
tableBody.appendChild(row);
}
});
this.addRowEventListeners();
}
}
createFolderRowHTML(folder: Folders, parentId: number): HTMLElement {
const row = document.createElement('tr');
row.classList.add(`child-of-folder-${parentId}`);
row.dataset.folderId = folder.id.toString();
const nameCell = document.createElement('td');
const folderIcon = document.createElement('i');
folderIcon.classList.add('fa-solid', 'fa-folder');
const folderName = document.createElement('p');
folderName.textContent = folder.name;
nameCell.appendChild(folderIcon);
nameCell.appendChild(folderName);
const dateCell = document.createElement('td');
dateCell.textContent = '11/10/2002'; // Placeholder date
const typeCell = document.createElement('td');
typeCell.textContent = 'File Folder';
const sizeCell = document.createElement('td');
sizeCell.textContent = '2 KB'; // Placeholder size
row.appendChild(nameCell);
row.appendChild(dateCell);
row.appendChild(typeCell);
row.appendChild(sizeCell);
return row;
}
createDocumentRowHTML(doc: Document, parentId: number): HTMLElement {
const row = document.createElement('tr');
row.classList.add(`child-of-folder-${parentId}`);
row.dataset.documentId = doc.id.toString();
const nameCell = document.createElement('td');
const fileIcon = document.createElement('i');
fileIcon.classList.add('fa-solid', 'fa-file');
const fileName = document.createElement('p');
fileName.textContent = doc.filename;
nameCell.appendChild(fileIcon);
nameCell.appendChild(fileName);
const dateCell = document.createElement('td');
dateCell.textContent = '11/10/2002'; // Placeholder date
const typeCell = document.createElement('td');
typeCell.textContent = 'txt'; // Placeholder type
const sizeCell = document.createElement('td');
sizeCell.textContent = '2 KB'; // Placeholder size
row.appendChild(nameCell);
row.appendChild(dateCell);
row.appendChild(typeCell);
row.appendChild(sizeCell);
return row;
}
createFolderHTML(folder: Folders): HTMLElement {
const folderDiv = document.createElement('div');
folderDiv.classList.add('folder');
folderDiv.dataset.folderId = folder.id.toString();
if (this.hasParentFolder(folder.id)) {
const keDiv = document.createElement('div');
keDiv.classList.add('ke');
folderDiv.appendChild(keDiv);
}
if (parentDiv) {
parentDiv.appendChild(folderDiv);
folderDiv.style.marginLeft = '0px';
}
const folderIcon = document.createElement('i');
folderIcon.classList.add('fa', 'fa-solid', 'fa-chevron-right');
const folderIconFolder = document.createElement('i');
folderIconFolder.classList.add('fa', 'fa-solid', 'fa-folder');
@ -132,9 +411,50 @@ export class ViewAllFolderComponent implements OnInit {
childrenContainer.style.display = 'none';
folderDiv.appendChild(childrenContainer);
// Function to log folder chain recursively
const logFolderChainRecursive = (currentFolder: Folders, chain: string[] = []) => {
chain.unshift(currentFolder.id.toString()); // Prepend current folder id to the chain
if (currentFolder.parent_folder) {
const parentFolder = this.findFolderById(currentFolder.parent_folder);
if (parentFolder) {
logFolderChainRecursive(parentFolder, chain); // Recursive call to log parent folder
}
} else {
console.log(`Clicked folder ${chain.join(' > ')}`); // Log the chain when reached the root folder
}
};
this.renderer.listen(folderHeader, 'click', () => {
logFolderChainRecursive(folder); // Start logging from the clicked folder
this.displayFolderContents(folder.id);
});
this.renderer.listen(folderIcon, 'click', (event: Event) => {
event.stopPropagation();
if (childrenContainer.style.display === 'none') {
childrenContainer.style.display = 'block';
folderIcon.style.transform = 'rotate(90deg)';
folderIconFolder.classList.replace('fa-folder', 'fa-folder-open');
} else {
childrenContainer.style.display = 'none';
folderIcon.style.transform = '';
folderIconFolder.classList.replace('fa-folder-open', 'fa-folder');
}
});
// Recursively create HTML for child folders
const childFolders = this.folders.filter(f => f.parent_folder === folder.id);
childFolders.forEach(childFolder => {
const childFolderHTML = this.createFolderHTML(childFolder);
childrenContainer.appendChild(childFolderHTML);
});
return folderDiv;
}
createDocumentHTML(doc: Document): HTMLElement {
const documentDiv = document.createElement('div');
documentDiv.classList.add('document');
@ -151,80 +471,23 @@ export class ViewAllFolderComponent implements OnInit {
return documentDiv;
}
hasParentFolder(folderId: number): boolean {
return this.folders.some(folder => folder.parent_folder_id === folderId);
}
findFolderById(folderId: number | null): Folders | undefined {
findFolderById(folderId: number): Folders | undefined {
return this.folders.find(folder => folder.id === folderId);
}
findFolderDiv(folderId: number): HTMLElement | null {
const foldersContainer = document.getElementById('folders-container');
return foldersContainer?.querySelector(`.folder[data-folder-id="${folderId}"]`) as HTMLElement;
return foldersContainer?.querySelector(`.folder[data-folder-id="${folderId}"]`) as HTMLElement | null;
}
addEventListeners(): void {
document.addEventListener('DOMContentLoaded', () => {
const folderLeft = document.getElementById('folderLeft');
if (folderLeft) {
const resizeHandle = folderLeft.querySelector('.resize-handle') as HTMLElement | null;
if (resizeHandle) {
let startX: number, startWidth: number;
resizeHandle.addEventListener('mousedown', (event: MouseEvent) => {
startX = event.clientX;
startWidth = parseInt(document.defaultView.getComputedStyle(folderLeft).width, 10);
document.addEventListener('mousemove', resizeWidth);
document.addEventListener('mouseup', stopResize);
});
const resizeWidth = (event: MouseEvent) => {
const newWidth = startWidth + (event.clientX - startX);
folderLeft.style.width = newWidth + 'px';
const folderRight = document.querySelector('.folder-right') as HTMLElement | null;
if (folderRight) {
folderRight.style.width = `calc(100% - ${newWidth}px)`;
}
};
const stopResize = () => {
document.removeEventListener('mousemove', resizeWidth);
document.removeEventListener('mouseup', stopResize);
};
}
}
// Handle folder open/close toggle
const folderCha = document.querySelectorAll('.folder-cha');
if (folderCha.length > 0) {
folderCha.forEach(item => {
let isOpen = false; // Track whether folder is open or closed
const folderIcon = item.querySelector('.fa-folder');
const chevronIcon = item.querySelector('.fa-chevron-right') as HTMLElement;
const folder = item.closest('.folder');
const ke = folder.querySelector('.ke');
item.addEventListener('click', () => {
if (isOpen) {
const ke = folder.querySelector('.ke') as HTMLElement;
ke.style.display = 'none'; // Hide .ke when closing the folder
folderIcon.classList.remove('fa-folder-open' ) ;
folderIcon.classList.add('fa-folder');
chevronIcon.style.transform = ''; // Reset chevron rotation
} else {
const ke = folder.querySelector('.ke') as HTMLElement;
ke.style.display = 'block'; // Show .ke when opening the folder
folderIcon.classList.remove('fa-folder');
folderIcon.classList.add('fa-folder-open');
chevronIcon.style.transform = 'rotate(90deg)'; // Rotate chevron
}
isOpen = !isOpen; // Toggle isOpen state
addRowEventListeners(): void {
const folderRows = this.elementRef.nativeElement.querySelectorAll('tr[data-folder-id]');
folderRows.forEach(row => {
this.renderer.listen(row, 'dblclick', (event: Event) => {
const target = event.currentTarget as HTMLTableRowElement;
const folderId = Number(target.dataset.folderId);
this.confirmDisplayFolderContents(folderId);
});
});
}
});
}
}

View File

@ -10,7 +10,17 @@ export interface Folders extends MatchingModel {
match: string;
matching_algorithm: number;
is_insensitive: boolean;
parent_folder_id: number | null;
parent_folder: number | null;
path: string;
}
export interface Results{
id: number;
owner_id: number;
name: string;
match: string;
matching_algorithm: number;
is_insensitive: boolean;
parent_folder: number | null;
path: string;
}

View File

@ -2,7 +2,7 @@ import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { AbstractNameFilterService } from './abstract-name-filter-service';
import { Folders, Document } from 'src/app/data/folders';
import { Folders, Document,Results } from 'src/app/data/folders';
import { environment } from 'src/environments/environment';
@Injectable({
@ -11,6 +11,10 @@ import { environment } from 'src/environments/environment';
export class FoldersService extends AbstractNameFilterService<Folders> {
constructor(http: HttpClient) {
super(http, 'folders');
}
getResults(): Observable<{results: Results[]}> {
return this.http.get<{results: Results[]}>(`${environment.apiBaseUrl}folders/`);
}
getFoldersAndDocuments(): Observable<{ folders: Folders[], documents: Document[] }> {

View File

@ -0,0 +1,339 @@
body {
overflow: hidden;
}
.folder-container {
width: 100%;
height: 100%;
display: flex;
z-index: 10000 !important;
}
.folder-container .folder-left {
width: 30%;
position: relative;
min-width: 100px;
height: 100vh;
overflow-x: auto;
overflow-y: auto;
background: rgba(37, 36, 36, 0.845);
display: flex;
align-items: center;
flex-direction: column;
overflow: hidden;
}
.resize-handle {
background-color: #f0f0f0;
cursor: ew-resize;
width: 2px;
height: 100%;
position: absolute;
right: 0;
}
.folder-container .folder-right {
width: 70%;
height: 100%;
overflow-y: auto;
}
.folder-left-1 {
width: 100%;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
}
.folder-left-search {
width: 85%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
margin-top: 10px;
box-shadow: 0 0 3px 0 gold;
}
.folder-left-search .serch {
width: 90%;
height: 100%;
border-left: none;
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
}
.folder-left-search .serch:focus {
outline: none;
}
.serch:focus + .folder-left-search {
border: 5px solid gold;
}
.folder-left-search .search {
width: 10%;
height: 100%;
cursor: pointer;
border-right: none;
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
}
.folder{
width: 95%;
height: auto;
}
#folders-container{
margin-top: 20px;
}
.documents {
width: 95%;
height: auto;
}
.folder-cha{
width: 100%;
height: auto;
display: flex;
align-items: center;
cursor: pointer;
text-align: left;
}
.folder-cha P{
color: #f0f0f0;
text-align: center;
position: relative;
margin-bottom: 0;
}
.folder-cha .fa-solid{
color: gold;
padding: 0 5px;
}
.folder-cha .fa-chevron-right{
color: #f0f0f0;
}
.folder-cha .fa-folder{
color: goldenrod;
}
.folder-con{
width: 100%;
height: auto;
display: flex;
cursor: pointer;
text-align: left;
}
.folder-con P{
color: #f0f0f0;
}
.foder{
width: 100%;
height: auto;
position: relative;
text-align: left;
}
.folder-con .fa-solid{
color: gold;
padding: 0 5px;
}
.folder-con .fa-chevron-right{
color: #f0f0f0;
}
.folder-con .fa-folder{
color: goldenrod;
}
#folders-container{
margin-left: -10%;
}
.docoment{
width: 100%;
display: flex;
align-items: center;
text-align: left;
}
.docomenta,
.document-container{
margin-left: 7%;
}
p{
color: aliceblue;
}
.folder {
position: relative;
overflow: hidden;
padding-left: 20px;
}
.folder .ke {
background: #f0f0f0;
width: 1px;
height: 180%;
z-index: 10000;
position: absolute;
left: 8.5%;
top: 60%;
display: none;
transform: translateY(-15%);
}
.folder-search{
width: 100%;
height: 50px;
display: flex;
align-items: center;
}
.folder-right-tim{
width: 60%;
height: 40px;
background: rgba(128, 128, 128, 0.534);
border-radius: 5px;
margin-left: 10px;
}
.folder-right-search{
width: 30%;
height: 40px;
background: rgba(128, 128, 128, 0.449);
border-radius: 5px;
margin-left: 50px;
display: flex;
}
.folder-right-search button{
cursor: pointer;
padding: 11px 15px;
border-right: none;
}
.folder-right-search input{
border-left: none;
width: 100%;
}
.folder-right-conten{
width: 100%;
height: 100%;
}
table {
width: 100%;
border-collapse: collapse;
margin: 20px 0;
background-color: #fff;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
table td{
color: black;
border-left: 1px solid gray;
border-right: 1px solid gray;
}
table thead {
background-color: #007bff25;
color: #fff;
}
table thead tr {
border-bottom: 1px solid #dee2e6;
}
table thead td {
padding: 12px 15px;
text-align: left;
font-weight: bold;
}
table tbody tr {
border-bottom: 1px solid #dee2e6;
}
table tbody tr:nth-of-type(even) {
background-color: #f2f2f2;
}
table tbody tr:hover {
background-color: #f1f1f1;
}
table tbody td {
padding: 12px 15px;
text-align: left;
border: none;
}
table tbody tr td .fa-folder{
color: gold;
}
table tbody tr td .fa-file{
color: rgb(79, 58, 16);
}
tbody td p{
color: black;
}
table tbody td i {
margin-right: 8px;
}
table tbody td p {
display: inline;
margin: 0;
}
.folder-cha:hover{
background: rgb(87, 87, 205);
}
.folder-right-tim {
display: flex;
align-items: center;
}
.logo-folder,
.ten-folder{
display: flex;
align-items: center;
}
.folder-right-tim .fa-folder{
color: gold;
margin-left: 2%;
}
.folder-right-tim .fa-chevron-right{
padding: 0 3px;
color: gray;
}
.logo-folder{
margin-left: 2%;
}
.ten-folder p{
color: black;
}
.sub-folder-container{
width: 40%;
height: 50px;
background: darkcyan;
position: fixed;
z-index: 10000;
top: 0;
left: 30%;
}
.sub-folder-container form{
display: flex;
flex-direction: column;
}
.sub-folder-container form input{
height: 40px;
padding: 0 10px;
border: none;
border: 2px solid salmon;
}
.sub-folder-container form input:focus {
border-color: dodgerblue;
outline: none;
}
.addfolder{
position: absolute;
background: grey;
width: 200px;
height: auto;
z-index: 10000;
border: 1px solid black;
}
#contextMenu{
display: none;
}
.addfolder ul li{
padding: 5px 5px;
list-style-type: none;
cursor: pointer;
}
.addfolder ul li a{
text-decoration: none;
}
.addfolder ul li:hover{
background: burlywood;
}
.folder-right{
background-color: #fff;
}

View File

@ -0,0 +1,117 @@
document.addEventListener("DOMContentLoaded", function() {
var folderLeft = document.getElementById('folderLeft');
var folderright = document.getElementById('folderrightt');
var folderContainer = document.querySelector('.folder-container');
var zoom = document.getElementById("zoomImg");
var contextMenu = document.getElementById("contextMenu");
var toggleButton = document.getElementById("toggleButton");
var eventsEnabled = false;
var amButton = document.getElementById("am");
var subFolderContainer = document.querySelector('.sub-folder-container');
amButton.addEventListener("click", function() {
subFolderContainer.style.display = "block";
contextMenu.style.display = "none";
var inputInSubFolder = subFolderContainer.querySelector('input[type="text"]');
if (inputInSubFolder) {
inputInSubFolder.focus();
}
var allInputs = document.querySelectorAll('input');
allInputs.forEach(function(input) {
if (input !== inputInSubFolder) {
input.blur();
}
});
});
document.getElementById('sss').addEventListener('click', function() {
var contextMenu1 = document.querySelector('.sub-folder-container');
contextMenu1.style.display = 'none';
});
folderLeft.addEventListener('click', function() {
hideContextMenu();
});
folderLeft.addEventListener('contextmenu', function(event) {
event.preventDefault();
showContextMenu(event.clientX, event.clientY);
});
folderright.addEventListener('contextmenu', function(event) {
event.preventDefault();
showContextMenu(event.clientX, event.clientY);
});
document.addEventListener('mousedown', function(event) {
var targetElement = event.target;
var clickedInsideContextMenu = contextMenu.contains(targetElement);
var clickedInsideFolderContainer = folderContainer.contains(targetElement);
var clickedInsideAddFolder = targetElement.classList.contains('addfolder') || targetElement.closest('.addfolder');
var clickedInsideAm = targetElement.id === 'am' || targetElement.closest('#am');
if (!clickedInsideContextMenu && !clickedInsideAddFolder && !clickedInsideAm) {
hideContextMenu();
}
if (clickedInsideAm) {
event.preventDefault();
}
});
toggleButton.addEventListener("click", function() {
toggleEvents();
});
function showContextMenu(x, y) {
contextMenu.style.display = "block";
contextMenu.style.left = x + "px";
contextMenu.style.top = y + "px";
}
function hideContextMenu() {
contextMenu.style.display = "none";
}
function toggleEvents() {
eventsEnabled = !eventsEnabled;
if (eventsEnabled) {
zoom.addEventListener("contextmenu", handleContextMenu);
} else {
zoom.removeEventListener("contextmenu", handleContextMenu);
}
}
function handleContextMenu(e) {
e.preventDefault();
showContextMenu(e.clientX, e.clientY);
}
zoom.onmouseup = function () {
if (eventsEnabled) {
hideContextMenu();
}
};
zoom.onmousemove = function (e) {
};
});

View File

@ -9,6 +9,7 @@
<meta name="theme-color" content="#17541f" />
<link rel="manifest" href="manifest.webmanifest">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css">
<link rel="stylesheet" href="./assets/css-folder/style.css">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="apple-touch-icon" href="apple-touch-icon.png">
</head>