| Linux in-mum-web1499.main-hosting.eu 5.14.0-503.40.1.el9_5.x86_64 #1 SMP PREEMPT_DYNAMIC Mon May 5 06:06:04 EDT 2025 x86_64 Path : /home/u901718425/domains/portal.urbanpillar.in/public_html/ |
| Current File : /home/u901718425/domains/portal.urbanpillar.in/public_html/drive.js |
$(document).ready(function () {
let drivePath = userInfo.role !== 'master' ? '/uploads/drive' : '/uploads/';
function showToast(message, type = 'success') {
Toastify({
text: message,
duration: 3000,
gravity: "top",
position: "right",
backgroundColor: type === 'success' ? "#4CAF50" : "#F44336",
stopOnFocus: true,
}).showToast();
}
let firstSelectedIndex = null;
let currentPath = '';
let pathHistory = [];
loadFiles();
let filesIcon = {empty: '/img/empty-folder.svg',folder: '/img/folder.svg'};
$('#uploadForm').on('submit', function (e) {
e.preventDefault();
let formData = new FormData(this);
$.ajax({
url: 'api/upload.php',
type: 'POST',
data: formData,
contentType: false,
processData: false,
success: function () {
$('#uploadModal').modal('hide');
$('#uploadForm')[0].reset();
loadFiles();
}
});
});
function preview(file) {
let html = '';
const fileExt = file.name.split('.').pop().toLowerCase();
const fullPath = currentPath ? `${currentPath}/${file.name}` : file.name;
if (file.is_dir) {
// Show folder icon based on empty/full
html = `<img src="${file.is_empty ? filesIcon.empty : filesIcon.folder}" class="w-100 h-auto ratio-1x1" />`;
} else {
// Show preview based on file type
if (['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp'].includes(fileExt)) {
html = `<img src="${drivePath}/${fullPath}" class="w-100 h-auto ratio-1x1" />`;
} else if (fileExt === 'pdf') {
html = `<iframe src="${drivePath}/${fullPath}" class="w-100 ratio-1x1" frameborder="0"></iframe>`;
} else if (fileExt === 'txt') {
html = `<iframe src="${drivePath}/${fullPath}" class="w-100 bg-light text-dark ratio-1x1" frameborder="0"></iframe>`;
} else if (['doc', 'docx'].includes(fileExt)) {
html = `<iframe src="https://docs.google.com/gview?url=${window.location.origin}${drivePath}/${file.name}&embedded=true"
class="w-100 ratio-1x1" frameborder="0"></iframe>`;
} else {
html = `<div class="text-center"><i class="bi bi-file-earmark fs-1 text-secondary"></i></div>`;
}
}
return html;
}
// Load files from a given path
function loadFiles(path = '') {
currentPath = path;
if(currentPath !==""){
$('#back-button').show();
}else {
$('#back-button').hide();
}
$.getJSON('api/list.php', { folder: path }, function (files) {
let html = '';
if (files.length === 0) {
html = '<div class="col-12"><div class="alert alert-warning">No files uploaded.</div></div>';
} else {
$.each(files, function (i, file) {
const fullPath = path ? `${path}/${file.name}` : file.name;
html += `
<div class="col-4 col-md-2">
<div class="card border-0 position-relative" >
<div class="card-body ${file.is_dir ? 'folder' : 'file'}" data-path="${fullPath}">
${preview(file)}
<p class="card-text mb-0 text-center fs-7">${file.name}</p>
</div>
</div>
</div>`;
});
}
$('#file-list').html(html);
});
}
// Initial load
loadFiles();
let selectedPath = '';
let isDir = false;
function showContextMenu(x, y, path = null, isDirectory = false) {
selectedPath = path;
isDir = isDirectory;
let menuHtml = "";
if (path) {
// Right-clicked on file or folder
menuHtml = `
<ul id="custom-context-menu" class="position-absolute list-group shadow" style="top:${y}px;left:${x}px;z-index:9999;min-width:160px;">
<li class="list-group-item list-group-item-action" data-action="view">📄 View</li>
<li class="list-group-item list-group-item-action" data-action="rename">✏️ Rename</li>
${['master'].includes(userInfo.role) && `<li class="list-group-item list-group-item-action" data-action="delete">🗑️ Delete</li>`}
<li class="list-group-item list-group-item-action" data-action="download">⬇️ Download</li>
</ul>
`;
} else {
// Right-clicked on empty space
menuHtml = `
<ul id="custom-context-menu" class="position-absolute list-group shadow" style="top:${y}px;left:${x}px;z-index:9999;min-width:160px;">
<li class="list-group-item list-group-item-action" data-action="create-folder">📁 Create Folder</li>
</ul>
`;
}
$("#custom-context-menu").remove();
$("body").append(menuHtml);
$(document).on("click.contextmenu", function () {
$("#custom-context-menu").remove();
$(document).off("click.contextmenu");
});
}
$(document).on("click", "#back-button", function (e) {
console.log(currentPath);
if(currentPath.includes('/')){
let backParts = currentPath.split("/");
backParts.pop(); // remove last part (current folder)
const previousPath = backParts.join('/');
loadFiles(previousPath, false); // Load without adding to history
}else{
loadFiles('', false);
}
// back = back.splice()
});
function createFolderPrompt() {
const folderName = prompt("Enter new folder name:");
if (!folderName) return;
$.post('api/create_folder.php', {
path: currentPath,
name: folderName || 'New Folder'
}, function (response) {
if (response.status === 'success') {
showToast('Folder created successfully');
loadFiles(currentPath);
} else {
showToast(response.message, 'error');
}
}, 'json');
}
// function debounce(func, delay) {
// let timeout;
// return function (...args) {
// clearTimeout(timeout);
// timeout = setTimeout(() => func.apply(this, args), delay);
// };
// }
// const debouncedLoadFiles = debounce(() => loadFiles(currentPath), 500);
// // Instead of setInterval, use a mutation observer or manual trigger if needed
// // But if you still want interval-style updates, use:
// setInterval(() => {
// debouncedLoadFiles();
// }, 50000);
$(document).on("contextmenu", function (e) {
// Prevent context menu if right-clicked on file or folder
if ($(e.target).closest(".file, .folder, #custom-context-menu").length === 0) {
e.preventDefault();
showContextMenu(e.pageX, e.pageY); // No path, show Create Folder
}
});
function renameItem() {
const newName = prompt('Enter new name:');
if (!newName) return;
$.post('api/rename.php', { path: selectedPath, new_name: newName }, function (res) {
showToast(res.message, 'error');
if (res.success) loadFiles(currentPath);
}, 'json');
}
function deleteItem() {
if (!confirm('Are you sure you want to delete this item?')) return;
$.ajax({
url: 'api/delete.php',
method: 'POST',
data: {
path: selectedPath,
is_dir: isDir
},
success: function (res) {
if (res.success) {
showToast(res.message);
loadFiles(currentPath); // Refresh UI
} else {
showToast(res.message, 'error');
}
},
error: function (xhr, status, error) {
console.error("Delete failed", error);
showToast("An error occurred while deleting the item.", 'error');
}
});
}
function downloadItem() {
if (!selectedPath) return;
const statusEl = document.getElementById('download-status');
statusEl.textContent = 'Preparing download...';
statusEl.style.display = 'block';
fetch(`api/download.php?path=${encodeURIComponent(selectedPath)}`, {
method: 'GET',
credentials: 'include',
})
.then(response => {
if (!response.ok) throw new Error("Download failed");
const disposition = response.headers.get('Content-Disposition');
const filenameMatch = disposition && disposition.match(/filename="(.+)"/);
const filename = filenameMatch ? filenameMatch[1] : 'download.zip';
return response.blob().then(blob => ({ blob, filename }));
})
.then(({ blob, filename }) => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
a.click();
window.URL.revokeObjectURL(url);
document.getElementById('download-status').textContent = 'Download complete!';
setTimeout(() => {
document.getElementById('download-status').style.display = 'none';
}, 3000);
})
.catch(err => {
console.error(err);
statusEl.textContent = 'Download failed!';
setTimeout(() => {
statusEl.style.display = 'none';
}, 3000);
});
}
// Double-click handler
$(document).on('dblclick', '.folder', function () {
const folderPath = $(this).data('path');
loadFiles(folderPath);
});
const dropZone = $('#drop-zone');
// Highlight drop area
dropZone.on('dragover dragenter', function (e) {
e.preventDefault();
e.stopPropagation();
dropZone.addClass('bg-light border-success');
});
dropZone.on('dragleave drop', function (e) {
e.preventDefault();
e.stopPropagation();
dropZone.removeClass('bg-light border-success');
});
// Drop handler
dropZone.on('drop', function (e) {
const items = e.originalEvent.dataTransfer.items;
if (items) {
for (let i = 0; i < items.length; i++) {
const item = items[i].webkitGetAsEntry?.();
if (item) {
traverseFileTree(item);
}
}
}
});
function traverseFileTree(item, path = "") {
if (item.isFile) {
item.file(function (file) {
uploadFile(file, path);
});
} else if (item.isDirectory) {
const dirReader = item.createReader();
dirReader.readEntries(function (entries) {
for (let i = 0; i < entries.length; i++) {
traverseFileTree(entries[i], path + item.name + "/");
}
});
}
}
function uploadFile(file, folderPath = "") {
const formData = new FormData();
formData.append("file", file);
formData.append("path", currentPath + "/" + folderPath); // dynamic folder path
const id = "upload_" + Date.now() + "_" + Math.random().toString(36).substr(2, 5);
showUploadStatus(id, `Uploading: ${folderPath}${file.name}`);
$.ajax({
url: "api/upload.php",
method: "POST",
data: formData,
processData: false,
contentType: false,
success: function (res) {
updateUploadStatus(id, `✅ ${folderPath}${file.name}`);
loadFiles(currentPath); // Refresh UI
},
error: function () {
updateUploadStatus(id, `❌ Failed: ${folderPath}${file.name}`);
}
});
}
function showUploadStatus(id, message) {
const html = `
<div id="${id}" class="alert alert-info shadow-sm py-2 px-3 mb-2">
${message}
</div>
`;
$('#upload-status').append(html);
}
function updateUploadStatus(id, message) {
$(`#${id}`).removeClass('alert-info').addClass('alert-success').html(message);
setTimeout(() => $(`#${id}`).fadeOut(1000, () => $(`#${id}`).remove()), 4000);
}
// let selectedItems = [];
// $(document).on('click', '.card-body', function (e) {
// const path = $(this).data('path');
// // Ctrl+Click selection
// if (e.ctrlKey || e.metaKey) {
// $(this).toggleClass('selected');
// } else {
// $('.card-body').removeClass('selected');
// $(this).addClass('selected');
// }
// updateSelectedItems();
// });
// function updateSelectedItems() {
// selectedItems = [];
// $('.card-body.selected').each(function () {
// selectedItems.push($(this).data('path'));
// });
// }
// $(document).on("contextmenu", ".card-body", function (e) {
// e.preventDefault();
// const $clicked = $(this);
// const filePath = $clicked.data("path");
// const isDirectory = $clicked.hasClass("folder");
// // Clear selection if this wasn't already selected
// if (!$clicked.hasClass('selected')) {
// $('.card-body').removeClass('selected');
// $clicked.addClass('selected');
// }
// updateSelectedItems();
// const x = e.pageX;
// const y = e.pageY;
// let menuHtml = "";
// if (selectedItems.length > 1) {
// // Show multi-select context menu
// menuHtml = `
// <ul id="custom-context-menu" class="position-absolute list-group shadow" style="top:${y}px;left:${x}px;z-index:9999;min-width:160px;">
// <li class="list-group-item list-group-item-action" data-action="download-selected">⬇️ Download Selected</li>
// <li class="list-group-item list-group-item-action" data-action="delete-selected">🗑️ Delete Selected</li>
// </ul>
// `;
// } else if (selectedItems.length === 1) {
// // Single item context menu
// selectedPath = filePath;
// isDir = isDirectory;
// menuHtml = `
// <ul id="custom-context-menu" class="position-absolute list-group shadow" style="top:${y}px;left:${x}px;z-index:9999;min-width:160px;">
// <li class="list-group-item list-group-item-action" data-action="view">📄 View</li>
// <li class="list-group-item list-group-item-action" data-action="rename">✏️ Rename</li>
// <li class="list-group-item list-group-item-action" data-action="delete">🗑️ Delete</li>
// <li class="list-group-item list-group-item-action" data-action="download">⬇️ Download</li>
// </ul>
// `;
// }
// $('#custom-context-menu').remove();
// $('body').append(menuHtml);
// });
// $(document).on("click", ".card-body", function (e) {
// const $clicked = $(this);
// const allItems = $(".card-body");
// if (e.ctrlKey || e.metaKey) {
// // Toggle selection on Ctrl/Cmd click
// $clicked.toggleClass("selected");
// // Update base index only if there's at least one selected
// const selected = allItems.filter(".selected");
// if (selected.length === 1) {
// firstSelectedIndex = allItems.index($clicked);
// }
// } else if (e.shiftKey && firstSelectedIndex !== null) {
// // Shift + click: range selection
// const currentIndex = allItems.index($clicked);
// const start = Math.min(firstSelectedIndex, currentIndex);
// const end = Math.max(firstSelectedIndex, currentIndex);
// allItems.removeClass("selected");
// for (let i = start; i <= end; i++) {
// allItems.eq(i).addClass("selected");
// }
// } else {
// // Regular click
// allItems.removeClass("selected");
// $clicked.addClass("selected");
// firstSelectedIndex = allItems.index($clicked);
// }
// updateSelectedItems();
// });
// // Ctrl+A for select all
// $(document).on('keydown', function (e) {
// if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'a') {
// e.preventDefault();
// $('.card-body').addClass('selected');
// updateSelectedItems();
// }
// });
// // Hide the custom context menu on clicking outside
$(document).on("click", function (e) {
// If the click target is not inside the context menu
if (!$(e.target).closest("#custom-context-menu").length) {
$("#custom-context-menu").remove();
}
});
let selectedItems = [];
$(document).on("click", ".card-body", function (e) {
const $clicked = $(this);
const allItems = $(".card-body");
if (e.ctrlKey || e.metaKey) {
// Toggle selection on Ctrl/Cmd click
$clicked.toggleClass("selected");
const selected = allItems.filter(".selected");
if (selected.length === 1) {
firstSelectedIndex = allItems.index($clicked);
}
} else if (e.shiftKey && firstSelectedIndex !== null) {
// Shift + click: range selection
const currentIndex = allItems.index($clicked);
const start = Math.min(firstSelectedIndex, currentIndex);
const end = Math.max(firstSelectedIndex, currentIndex);
allItems.removeClass("selected");
for (let i = start; i <= end; i++) {
allItems.eq(i).addClass("selected");
}
} else {
// Regular click
allItems.removeClass("selected");
$clicked.addClass("selected");
firstSelectedIndex = allItems.index($clicked);
}
updateSelectedItems();
});
function updateSelectedItems() {
selectedItems = [];
$(".card-body.selected").each(function () {
selectedItems.push($(this).data("path"));
});
}
// Context Menu
$(document).on("contextmenu", ".card-body", function (e) {
e.preventDefault();
const $clicked = $(this);
const filePath = $clicked.data("path");
const isDirectory = $clicked.hasClass("folder");
// If not selected, make it the only selected one
if (!$clicked.hasClass("selected")) {
$(".card-body").removeClass("selected");
$clicked.addClass("selected");
}
updateSelectedItems();
const x = e.pageX;
const y = e.pageY;
let menuHtml = "";
if (selectedItems.length > 1) {
menuHtml = `
<ul id="custom-context-menu" class="position-absolute list-group shadow" style="top:${y}px;left:${x}px;z-index:9999;min-width:160px;">
<li class="list-group-item list-group-item-action" data-action="download-selected">⬇️ Download Selected</li>
<li class="list-group-item list-group-item-action" data-action="delete-selected">🗑️ Delete Selected</li>
</ul>
`;
} else {
selectedPath = filePath;
isDir = isDirectory;
menuHtml = `
<ul id="custom-context-menu" class="position-absolute list-group shadow" style="top:${y}px;left:${x}px;z-index:9999;min-width:160px;">
<li class="list-group-item list-group-item-action" data-action="view">📄 View</li>
<li class="list-group-item list-group-item-action" data-action="rename">✏️ Rename</li>
<li class="list-group-item list-group-item-action" data-action="delete">🗑️ Delete</li>
<li class="list-group-item list-group-item-action" data-action="download">⬇️ Download</li>
</ul>
`;
}
$("#custom-context-menu").remove();
$("body").append(menuHtml);
});
// Ctrl+A
$(document).on("keydown", function (e) {
if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "a") {
e.preventDefault();
$(".card-body").addClass("selected");
updateSelectedItems();
}
});
$(document).on("click", "#custom-context-menu li", function () {
const action = $(this).data("action");
$("#custom-context-menu").remove();
switch (action) {
case "view":
viewFile();
break;
case "rename":
renameItem();
break;
case "delete":
deleteSelectedItems();
break;
case "download":
downloadItem();
break;
case "create-folder":
createFolderPrompt();
break;
case "download-selected":
downloadSelectedItems();
break;
case "delete-selected":
deleteSelectedItems();
break;
}
});
function viewFile() {
if (!selectedPath) return;
// Open the file in a new tab
window.open(`https://portal.urbanpillar.in${drivePath}/${selectedPath}`, "_blank");
}
function downloadSelectedItems() {
if (selectedItems.length === 0) return;
const items = selectedItems.map(path => {
const el = $(`.card-body[data-path="${path}"]`);
return {
path: path,
is_dir: el.hasClass('folder')
};
});
const form = $('<form>', {
method: 'POST',
action: 'api/zip.php',
target: '_blank' // opens download in new tab
});
form.append($('<input>', {
type: 'hidden',
name: 'items',
value: JSON.stringify(items)
}));
$('body').append(form);
form.submit();
form.remove();
}
function deleteSelectedItems() {
if (selectedItems.length === 0) return;
if (!confirm(`Are you sure you want to delete ${selectedItems.length} item(s)?`)) return;
const itemsToDelete = selectedItems.map(path => {
const el = $(`.card-body[data-path="${path}"]`);
return {
path: path,
is_dir: el.hasClass('folder')
};
});
$.ajax({
url: 'api/delete.php',
method: 'POST',
contentType: 'application/json',
data: JSON.stringify({ paths: itemsToDelete }),
success: function (res) {
console.log(res);
loadFiles(currentPath);
},
error: function (err) {
alert('Error deleting files.');
console.error(err);
}
});
}
let isDragging = false;
let startX, startY;
$(document).on('mousedown', function (e) {
// Left mouse button only
if (e.button !== 0) return;
isDragging = true;
startX = e.pageX;
startY = e.pageY;
$('#selection-box').css({
top: startY + 'px',
left: startX + 'px',
width: 0,
height: 0,
display: 'block'
});
});
$(document).on('mousemove', function (e) {
if (!isDragging) return;
const x = Math.min(e.pageX, startX);
const y = Math.min(e.pageY, startY);
const w = Math.abs(e.pageX - startX);
const h = Math.abs(e.pageY - startY);
$('#selection-box').css({
top: y + 'px',
left: x + 'px',
width: w + 'px',
height: h + 'px'
});
$('.card-body').each(function () {
const $el = $(this);
const offset = $el.offset();
const elX = offset.left;
const elY = offset.top;
const elW = $el.outerWidth();
const elH = $el.outerHeight();
const isInside = !(elX > x + w || elX + elW < x || elY > y + h || elY + elH < y);
if (isInside) {
$el.addClass('selected');
} else if (!e.ctrlKey && !e.metaKey) {
$el.removeClass('selected');
}
});
updateSelectedItems();
});
$(document).on('mouseup', function () {
if (isDragging) {
isDragging = false;
$('#selection-box').hide();
}
});
});