2016-02-11 15:39:20 +01:00
|
|
|
/**
|
2016-02-15 11:38:06 +01:00
|
|
|
* Copyright (c) Mohammad Naghavi <mohamnag@gmail.com>
|
|
|
|
*
|
|
|
|
* Licenced as stated by LICENSE file under root of this code.
|
|
|
|
*
|
|
|
|
* * NOTICE:
|
|
|
|
* If your nginx config varies from the default config
|
|
|
|
* provided in this code, you probably need to change
|
2022-02-07 16:55:50 +01:00
|
|
|
* value of filesBaseUrl here too.
|
2016-02-15 11:38:06 +01:00
|
|
|
*
|
2016-02-11 15:39:20 +01:00
|
|
|
* Created by mohamnag on 11/02/16.
|
|
|
|
*/
|
|
|
|
|
2022-02-07 16:55:50 +01:00
|
|
|
$(document).ready(function () {
|
2016-02-11 15:39:20 +01:00
|
|
|
|
2022-02-07 16:55:50 +01:00
|
|
|
function applyTheme() {
|
|
|
|
var theme = $('input[name=theme]:checked').val()
|
2016-02-11 15:39:20 +01:00
|
|
|
|
2022-02-07 16:55:50 +01:00
|
|
|
console.log(`setting theme to '${theme}'`)
|
2016-02-11 15:39:20 +01:00
|
|
|
|
2022-02-07 16:55:50 +01:00
|
|
|
$('body')
|
|
|
|
.removeClass()
|
|
|
|
.addClass(theme)
|
2016-02-11 15:39:20 +01:00
|
|
|
|
2022-02-07 16:55:50 +01:00
|
|
|
localStorage.setItem("theme", theme)
|
|
|
|
}
|
2016-02-11 15:39:20 +01:00
|
|
|
|
|
|
|
function renderFileElement(directory, fileName, fileType, fileSize, fileDate) {
|
|
|
|
|
|
|
|
var fileItemElement = fileItemElementTemplate.clone();
|
|
|
|
|
|
|
|
fileItemElement.addClass(fileType);
|
|
|
|
fileItemElement.find(".file-name").text(fileName);
|
|
|
|
|
|
|
|
if (fileDate) {
|
|
|
|
fileItemElement.find(".file-date").text(moment(fileDate).fromNow());
|
|
|
|
}
|
|
|
|
|
2016-02-11 18:42:41 +01:00
|
|
|
if (fileType === "parent") {
|
|
|
|
// navigate to parent dir
|
|
|
|
fileItemElement.find(".file-link").click(function () {
|
|
|
|
navigateTo(directory);
|
|
|
|
});
|
2016-02-11 15:39:20 +01:00
|
|
|
|
2016-02-11 18:42:41 +01:00
|
|
|
} else if (fileType === "directory") {
|
|
|
|
// navigate to sub dir
|
|
|
|
fileItemElement.find(".file-link").click(function () {
|
|
|
|
navigateTo(directory + fileName + "/");
|
|
|
|
});
|
2016-02-11 15:39:20 +01:00
|
|
|
|
|
|
|
} else if (fileType === "other") {
|
|
|
|
// nginx returns symlinks as type other,
|
|
|
|
// lets try to follow the links
|
|
|
|
fileItemElement.find(".file-link").click(function () {
|
|
|
|
navigateTo(directory + fileName + "/");
|
|
|
|
});
|
|
|
|
|
|
|
|
} else {
|
|
|
|
// just file dl
|
|
|
|
fileItemElement.find(".file-link")
|
2016-02-11 18:10:05 +01:00
|
|
|
.attr("href", filesBaseUrl + directory + fileName)
|
2016-02-11 15:39:20 +01:00
|
|
|
.attr("target", "_blank");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fileSize) {
|
|
|
|
fileItemElement.find(".file-size").text(fileSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
return fileItemElement;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getParentDir(path) {
|
|
|
|
|
|
|
|
if (path.length <= 1) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
var lastSlashPos = path.lastIndexOf("/", path.length - 2);
|
|
|
|
var parentDir = lastSlashPos >= 0 ? path.substr(0, lastSlashPos + 1) : null;
|
|
|
|
|
|
|
|
return parentDir;
|
|
|
|
}
|
|
|
|
|
2024-03-27 15:39:24 +01:00
|
|
|
function getREADMEmdFile(filesData, path) {
|
|
|
|
|
|
|
|
if (path === "") {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
var readmeFile = filesData.find(function (fileData) {
|
|
|
|
return fileData.name === "README.md" && fileData.type === "file";
|
|
|
|
});
|
|
|
|
|
|
|
|
return readmeFile ? path + "README.md" : null;
|
|
|
|
}
|
|
|
|
|
2016-02-11 17:37:40 +01:00
|
|
|
function renderFileList(filesData, path) {
|
|
|
|
|
|
|
|
var sortBy = $('input[name=sort]:checked').val();
|
|
|
|
if (sortBy === "date") {
|
|
|
|
console.log("sort by date");
|
|
|
|
|
|
|
|
filesData.sort(function (fileA, fileB) {
|
|
|
|
return fileB.mtime.getTime() - fileA.mtime.getTime();
|
|
|
|
});
|
|
|
|
|
|
|
|
} else if (sortBy === "name") {
|
|
|
|
console.log("sort by name");
|
|
|
|
|
2024-03-25 20:37:43 +01:00
|
|
|
var collator = new Intl.Collator([], {numeric: true});
|
2016-02-11 17:37:40 +01:00
|
|
|
filesData.sort(function (fileA, fileB) {
|
2024-03-25 20:37:43 +01:00
|
|
|
return collator.compare(fileA.name.toLowerCase(), fileB.name.toLowerCase());
|
2024-03-27 14:32:57 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
filesData.sort(function (fileA, fileB) {
|
|
|
|
return collator.compare(fileA.type.toLowerCase(), fileB.type.toLowerCase());
|
2016-02-11 17:37:40 +01:00
|
|
|
});
|
2016-02-11 19:12:08 +01:00
|
|
|
|
|
|
|
} else if (sortBy === "size") {
|
|
|
|
console.log("sort by size");
|
|
|
|
|
|
|
|
filesData.sort(function (fileA, fileB) {
|
|
|
|
var sizeA = fileA.rawSize ? fileA.rawSize : Number.MIN_VALUE;
|
|
|
|
var sizeB = fileB.rawSize ? fileB.rawSize : Number.MIN_VALUE;
|
|
|
|
return sizeA - sizeB;
|
|
|
|
});
|
2016-02-11 17:37:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
fileListElement.empty();
|
|
|
|
|
2024-03-27 14:32:57 +01:00
|
|
|
var directories = [];
|
|
|
|
var files = [];
|
|
|
|
filesData.forEach(function (fileData) {
|
|
|
|
if (fileData.type === "folder") {
|
|
|
|
directories.push(fileData);
|
|
|
|
} else {
|
|
|
|
files.push(fileData);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2016-02-11 17:37:40 +01:00
|
|
|
var parentDir = getParentDir(path);
|
|
|
|
|
|
|
|
if (parentDir) {
|
|
|
|
fileListElement.append(renderFileElement(
|
|
|
|
parentDir,
|
|
|
|
"..",
|
2016-02-11 18:42:41 +01:00
|
|
|
"parent"
|
2016-02-11 17:37:40 +01:00
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2024-03-27 14:32:57 +01:00
|
|
|
directories.forEach(function (fileData) {
|
|
|
|
fileListElement.append(renderFileElement(
|
|
|
|
path,
|
|
|
|
fileData.name,
|
|
|
|
fileData.type,
|
|
|
|
fileData.size,
|
|
|
|
fileData.mtime
|
|
|
|
));
|
|
|
|
});
|
|
|
|
|
|
|
|
files.forEach(function (fileData) {
|
2016-02-11 17:37:40 +01:00
|
|
|
fileListElement.append(renderFileElement(
|
|
|
|
path,
|
|
|
|
fileData.name,
|
|
|
|
fileData.type,
|
|
|
|
fileData.size,
|
|
|
|
fileData.mtime
|
|
|
|
));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-02-11 15:39:20 +01:00
|
|
|
function navigateTo(path) {
|
|
|
|
console.log("navigateTo", path);
|
2016-02-11 18:10:05 +01:00
|
|
|
isNavigating = true;
|
2016-02-11 15:39:20 +01:00
|
|
|
|
|
|
|
$.ajax({
|
|
|
|
url: filesBaseUrl + path,
|
2016-02-11 19:12:08 +01:00
|
|
|
|
|
|
|
dataType: "json",
|
|
|
|
|
2016-02-11 15:39:20 +01:00
|
|
|
success: function (filesData) {
|
|
|
|
|
2016-02-11 19:12:08 +01:00
|
|
|
// fix sizes and dates
|
2016-02-11 15:59:19 +01:00
|
|
|
filesData.map(function (fileData) {
|
2016-02-11 18:42:41 +01:00
|
|
|
fileData.mtime = new Date(fileData.mtime);
|
2016-02-11 19:12:08 +01:00
|
|
|
|
2016-02-11 22:17:30 +01:00
|
|
|
if (fileData.hasOwnProperty("size")) {
|
2016-02-11 19:12:08 +01:00
|
|
|
fileData.rawSize = fileData.size;
|
|
|
|
fileData.size = fileSize(fileData.size);
|
|
|
|
}
|
2016-02-11 18:42:41 +01:00
|
|
|
|
|
|
|
return fileData;
|
2016-02-11 15:59:19 +01:00
|
|
|
});
|
|
|
|
|
2016-02-11 17:37:40 +01:00
|
|
|
renderFileList(filesData, path);
|
2016-02-11 15:39:20 +01:00
|
|
|
|
2016-02-11 17:37:40 +01:00
|
|
|
$('input[name=sort]')
|
|
|
|
.unbind("change")
|
|
|
|
.on("change", function () {
|
|
|
|
renderFileList(filesData, path);
|
|
|
|
});
|
2016-02-11 18:10:05 +01:00
|
|
|
|
2016-02-11 19:12:08 +01:00
|
|
|
console.log("replaceState", path);
|
|
|
|
history.replaceState(null, path, '#' + path);
|
|
|
|
|
2024-03-27 15:39:24 +01:00
|
|
|
if (path) {
|
2024-11-28 10:45:50 +01:00
|
|
|
var zeroMdElement = document.querySelector("zero-md");
|
|
|
|
if (zeroMdElement) {
|
|
|
|
document.querySelector("body > div.container").removeChild(zeroMdElement);
|
|
|
|
}
|
|
|
|
|
2024-03-27 15:39:24 +01:00
|
|
|
var readmePath = getREADMEmdFile(filesData, path);
|
|
|
|
if (readmePath) {
|
2024-11-28 10:45:50 +01:00
|
|
|
zeroMdElement = document.createElement("zero-md");
|
2024-03-27 15:39:24 +01:00
|
|
|
zeroMdElement.setAttribute("src", filesBaseUrl + readmePath);
|
|
|
|
document.querySelector("body > div.container").appendChild(zeroMdElement);
|
|
|
|
}
|
|
|
|
}
|
2016-02-11 19:12:08 +01:00
|
|
|
|
|
|
|
isNavigating = false;
|
|
|
|
},
|
|
|
|
|
|
|
|
error: function (jqxhr, textStatus, errorThrown) {
|
|
|
|
console.log(jqxhr, textStatus, errorThrown);
|
|
|
|
|
|
|
|
if(textStatus === "timeout") {
|
|
|
|
alert("Request to server timed out, retry later!");
|
|
|
|
|
|
|
|
} else if(textStatus === "abort") {
|
|
|
|
alert("Connection to server has been aborted, retry later!");
|
|
|
|
|
|
|
|
} else if(textStatus === "parsererror") {
|
|
|
|
alert("Invalid response from server!");
|
|
|
|
|
|
|
|
} else if(jqxhr.status === 404) {
|
|
|
|
alert("Server cant find this file/directory!");
|
2016-02-11 18:10:05 +01:00
|
|
|
|
|
|
|
} else {
|
2016-02-11 19:12:08 +01:00
|
|
|
// also if(textStatus === "error")
|
|
|
|
alert("Something went wrong in communication to server, retry later!");
|
2016-02-11 18:10:05 +01:00
|
|
|
}
|
|
|
|
|
2016-02-11 19:12:08 +01:00
|
|
|
history.back();
|
2016-02-11 15:39:20 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-02-11 18:42:41 +01:00
|
|
|
function fileSize(bytes) {
|
|
|
|
var exp = Math.log(bytes) / Math.log(1024) | 0;
|
|
|
|
var value = bytes / Math.pow(1024, exp);
|
|
|
|
|
|
|
|
if (exp == 0) {
|
|
|
|
return value.toFixed(0) + ' bytes';
|
|
|
|
|
|
|
|
} else {
|
|
|
|
var result = value.toFixed(2);
|
2024-03-27 13:46:26 +01:00
|
|
|
return result + ' ' + 'KMGTPEZY'[exp - 1] + 'iB';
|
2016-02-11 18:42:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2016-02-11 18:10:05 +01:00
|
|
|
function navigateToUrlLocation() {
|
|
|
|
var requestedPath = window.location.hash;
|
|
|
|
var startPath = requestedPath ? requestedPath.substr(1) : "/";
|
|
|
|
navigateTo(startPath);
|
|
|
|
}
|
|
|
|
|
2022-02-07 16:55:50 +01:00
|
|
|
var filesBaseUrl = "/files";
|
|
|
|
var isNavigating = false;
|
|
|
|
var fileListElement = $("#file-list");
|
|
|
|
var fileItemElementTemplate = fileListElement.find("li").detach();
|
|
|
|
|
|
|
|
// setup theme switching
|
|
|
|
$('input[name=theme]').on("change", applyTheme);
|
|
|
|
|
|
|
|
// apply current theme
|
|
|
|
var theme = localStorage.getItem("theme")
|
|
|
|
console.log(`theme '${theme}' loaded`)
|
|
|
|
$(`input[name=theme][value='${theme}']`).prop('checked', true)
|
|
|
|
applyTheme()
|
|
|
|
|
2016-02-11 19:12:08 +01:00
|
|
|
window.onpopstate = function () {
|
|
|
|
if (!isNavigating) {
|
|
|
|
navigateToUrlLocation();
|
|
|
|
}
|
|
|
|
};
|
2016-02-11 15:39:20 +01:00
|
|
|
|
2016-02-11 18:10:05 +01:00
|
|
|
navigateToUrlLocation();
|
2024-03-25 20:37:43 +01:00
|
|
|
});
|