more file manager progress
This commit is contained in:
@@ -1,16 +1,39 @@
|
|||||||
function FileManager(windowElement) {
|
function FileManager(windowElement) {
|
||||||
this.window = windowElement;
|
this.window = windowElement;
|
||||||
this.navBar = this.window.querySelector("#nav_bar");
|
this.navBar = this.window.querySelector("#nav_bar");
|
||||||
this.btnMenu = this.navBar.querySelector("#btn_menu");
|
this.btnMenu = this.navBar.querySelector("#btn_menu");
|
||||||
this.btnBack = this.navBar.querySelector("#btn_back");
|
this.btnBack = this.navBar.querySelector("#btn_back");
|
||||||
this.btnUp = this.navBar.querySelector("#btn_up");
|
this.btnUp = this.navBar.querySelector("#btn_up");
|
||||||
this.btnForward = this.navBar.querySelector("#btn_forward");
|
this.btnForward = this.navBar.querySelector("#btn_forward");
|
||||||
this.btnHome = this.navBar.querySelector("#btn_home");
|
this.btnHome = this.navBar.querySelector("#btn_home");
|
||||||
this.breadcrumbs = this.navBar.querySelector("#breadcrumbs");
|
this.breadcrumbs = this.navBar.querySelector("#breadcrumbs");
|
||||||
this.btnReload = this.navBar.querySelector("#btn_reload");
|
this.btnReload = this.navBar.querySelector("#btn_reload");
|
||||||
this.inputSearch = this.navBar.querySelector("#input_search");
|
this.inputSearch = this.navBar.querySelector("#input_search");
|
||||||
this.directoryArea = this.window.querySelector("#directory_area");
|
this.directorySorters = this.window.querySelector("#directory_sorters");
|
||||||
this.directoryFooter = this.window.querySelector("#directory_footer");
|
this.directoryArea = this.window.querySelector("#directory_area");
|
||||||
|
this.directoryFooter = this.window.querySelector("#directory_footer");
|
||||||
|
|
||||||
|
// Sorters
|
||||||
|
this.currentSortField = "";
|
||||||
|
this.currentSortAscending = true;
|
||||||
|
|
||||||
|
this.btnSortName = document.createElement("div");
|
||||||
|
this.btnSortName.innerText = "Name";
|
||||||
|
this.btnSortName.addEventListener("click", () => { this.sortBy("name"); });
|
||||||
|
this.directorySorters.appendChild(this.btnSortName);
|
||||||
|
|
||||||
|
this.btnSortType = document.createElement("div");
|
||||||
|
this.btnSortType.innerText = "Type";
|
||||||
|
this.btnSortType.addEventListener("click", () => { this.sortBy("type"); });
|
||||||
|
this.directorySorters.appendChild(this.btnSortType);
|
||||||
|
|
||||||
|
this.btnSortSize = document.createElement("div");
|
||||||
|
this.btnSortSize.innerText = "Size";
|
||||||
|
this.btnSortSize.addEventListener("click", () => { this.sortBy("size"); });
|
||||||
|
this.directorySorters.appendChild(this.btnSortSize);
|
||||||
|
|
||||||
|
// Buttons
|
||||||
|
this.btnReload.addEventListener("click", () => { this.getUserFiles(); })
|
||||||
|
|
||||||
this.dirContainer = document.createElement("div");
|
this.dirContainer = document.createElement("div");
|
||||||
this.directoryArea.appendChild(this.dirContainer);
|
this.directoryArea.appendChild(this.dirContainer);
|
||||||
@@ -22,12 +45,27 @@ function FileManager(windowElement) {
|
|||||||
this.renderVisibleFiles(this.visibleFiles, false);
|
this.renderVisibleFiles(this.visibleFiles, false);
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// type: {icon, name, href, type, size}
|
||||||
this.allFiles = [];
|
this.allFiles = [];
|
||||||
this.visibleFiles = [];
|
this.visibleFiles = [];
|
||||||
|
|
||||||
this.lastScrollTop = 0;
|
this.lastScrollTop = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FileManager.prototype.setSpinner = function() {
|
||||||
|
this.window.appendChild(document.getElementById("tpl_spinner").content.cloneNode(true));
|
||||||
|
}
|
||||||
|
FileManager.prototype.delSpinner = function() {
|
||||||
|
for (let i in this.window.children) {
|
||||||
|
if (
|
||||||
|
typeof(this.window.children[i].classList) === "object" &&
|
||||||
|
this.window.children[i].classList.contains("spinner")
|
||||||
|
) {
|
||||||
|
this.window.children[i].remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FileManager.prototype.search = function(term) {
|
FileManager.prototype.search = function(term) {
|
||||||
if (term === "") {
|
if (term === "") {
|
||||||
this.visibleFiles = this.allFiles;
|
this.visibleFiles = this.allFiles;
|
||||||
@@ -51,28 +89,36 @@ FileManager.prototype.getDirectory = function(path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FileManager.prototype.getUserFiles = function() {
|
FileManager.prototype.getUserFiles = function() {
|
||||||
|
this.setSpinner();
|
||||||
|
|
||||||
let getAll = (page) => {
|
let getAll = (page) => {
|
||||||
fetch(apiEndpoint+"/user/files?page="+page+"&limit=10000").then(resp => {
|
fetch(apiEndpoint+"/user/files?page="+page+"&limit=10000").then(resp => {
|
||||||
if (!resp.ok) {Promise.reject("yo");}
|
if (!resp.ok) {Promise.reject("yo");}
|
||||||
return resp.json();
|
return resp.json();
|
||||||
}).then(resp => {
|
}).then(resp => {
|
||||||
if (page === 0) {
|
for (let i in resp.files) {
|
||||||
this.allFiles = resp.files;
|
this.allFiles.push({
|
||||||
} else {
|
icon: apiEndpoint+"/file/"+resp.files[i].id+"/thumbnail?width=32&height=32",
|
||||||
this.allFiles = this.allFiles.concat(resp.files);
|
name: resp.files[i].name,
|
||||||
|
href: "/u/"+resp.files[i].id,
|
||||||
|
type: resp.files[i].mime_type,
|
||||||
|
size: resp.files[i].size
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
this.allFiles.sort((a, b) => {
|
|
||||||
return a.name.localeCompare(b.name);
|
|
||||||
});
|
|
||||||
this.visibleFiles = this.allFiles;
|
this.visibleFiles = this.allFiles;
|
||||||
|
this.currentSortField = "";
|
||||||
this.renderVisibleFiles(this.visibleFiles, true);
|
this.sortBy("name");
|
||||||
|
|
||||||
if (resp.files.length === 10000) {
|
if (resp.files.length === 10000) {
|
||||||
getAll(page+1);
|
getAll(page+1);
|
||||||
|
} else {
|
||||||
|
// Less than 10000 results means we're done loading, we can
|
||||||
|
// remove the loading spinner
|
||||||
|
this.delSpinner();
|
||||||
}
|
}
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
|
this.delSpinner();
|
||||||
console.log("Req failed:" + err);
|
console.log("Req failed:" + err);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -80,9 +126,77 @@ FileManager.prototype.getUserFiles = function() {
|
|||||||
getAll(0);
|
getAll(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FileManager.prototype.getUserLists = function() {
|
||||||
|
this.setSpinner();
|
||||||
|
|
||||||
|
let getAll = (page) => {
|
||||||
|
fetch(apiEndpoint+"/user/lists?page="+page+"&limit=10000").then(resp => {
|
||||||
|
if (!resp.ok) {Promise.reject("yo");}
|
||||||
|
return resp.json();
|
||||||
|
}).then(resp => {
|
||||||
|
for (let i in resp.lists) {
|
||||||
|
this.allFiles.push({
|
||||||
|
icon: apiEndpoint+"/list/"+resp.lists[i].id+"/thumbnail?width=32&height=32",
|
||||||
|
name: resp.lists[i].title,
|
||||||
|
href: "/l/"+resp.lists[i].id,
|
||||||
|
type: "list",
|
||||||
|
size: 0
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
this.visibleFiles = this.allFiles;
|
||||||
|
this.currentSortField = "";
|
||||||
|
this.sortBy("name");
|
||||||
|
|
||||||
|
if (resp.lists.length === 10000) {
|
||||||
|
getAll(page+1);
|
||||||
|
} else {
|
||||||
|
// Less than 10000 results means we're done loading, we can
|
||||||
|
// remove the loading spinner
|
||||||
|
this.delSpinner();
|
||||||
|
}
|
||||||
|
}).catch((err) => {
|
||||||
|
this.delSpinner();
|
||||||
|
console.log("Req failed:" + err);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
getAll(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
FileManager.prototype.sortBy = function(field) {
|
||||||
|
if (this.currentSortField !== field) {
|
||||||
|
this.currentSortAscending = true;
|
||||||
|
this.currentSortField = field;
|
||||||
|
} else if (this.currentSortField === field) {
|
||||||
|
this.currentSortAscending = !this.currentSortAscending;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.visibleFiles.sort((a, b) => {
|
||||||
|
if (this.currentSortAscending) {
|
||||||
|
return a[field].localeCompare(b[field]);
|
||||||
|
} else {
|
||||||
|
return b[field].localeCompare(a[field]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.renderVisibleFiles(this.visibleFiles, true);
|
||||||
|
}
|
||||||
|
|
||||||
FileManager.prototype.renderVisibleFiles = function(files, freshStart) {
|
FileManager.prototype.renderVisibleFiles = function(files, freshStart) {
|
||||||
|
let scrollDown = this.lastScrollTop <= this.directoryArea.scrollTop;
|
||||||
|
this.lastScrollTop = this.directoryArea.scrollTop;
|
||||||
|
|
||||||
|
let fileMargin = 4;
|
||||||
|
let fileHeight = 32 + fileMargin;
|
||||||
|
let totalHeight = (files.length * fileHeight);
|
||||||
|
let viewportHeight = this.directoryArea.clientHeight;
|
||||||
|
|
||||||
if (freshStart) {
|
if (freshStart) {
|
||||||
this.dirContainer.innerHTML = "";
|
this.dirContainer.innerHTML = "";
|
||||||
|
this.dirContainer.style.height = totalHeight+"px";
|
||||||
|
this.dirContainer.scrollTop = 0;
|
||||||
|
this.lastScrollTop = 0;
|
||||||
|
scrollDown = true;
|
||||||
|
|
||||||
let totalSize = 0;
|
let totalSize = 0;
|
||||||
for (let i in files) {
|
for (let i in files) {
|
||||||
@@ -95,25 +209,15 @@ FileManager.prototype.renderVisibleFiles = function(files, freshStart) {
|
|||||||
+formatDataVolume(totalSize, 4);
|
+formatDataVolume(totalSize, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
let scrollDown = this.lastScrollTop <= this.directoryArea.scrollTop;
|
let paddingTop = this.lastScrollTop - this.lastScrollTop%fileHeight;
|
||||||
this.lastScrollTop = this.directoryArea.scrollTop;
|
let start = Math.floor(paddingTop/fileHeight) - 5;
|
||||||
|
if (start < 0) { start = 0; }
|
||||||
|
|
||||||
let fileHeight = 32;
|
let end = Math.ceil((paddingTop+viewportHeight)/fileHeight) + 5;
|
||||||
let totalHeight = (files.length * fileHeight)+38;
|
|
||||||
let viewportHeight = this.directoryArea.clientHeight;
|
|
||||||
let paddingTop = this.lastScrollTop - this.lastScrollTop%fileHeight;
|
|
||||||
if (paddingTop < 0) { paddingTop = 0;}
|
|
||||||
let paddingBottom = totalHeight - paddingTop - viewportHeight - this.lastScrollTop%fileHeight;
|
|
||||||
if (paddingBottom < 0) {paddingBottom = 0;}
|
|
||||||
|
|
||||||
// Pad the items out which we're not going to show
|
|
||||||
this.dirContainer.style.marginTop = paddingTop+"px";
|
|
||||||
this.dirContainer.style.marginBottom = paddingBottom+"px";
|
|
||||||
|
|
||||||
let start = Math.floor(paddingTop/fileHeight);
|
|
||||||
let end = Math.ceil((paddingTop+viewportHeight)/fileHeight);
|
|
||||||
if (end > files.length) { end = files.length-1; }
|
if (end > files.length) { end = files.length-1; }
|
||||||
|
|
||||||
|
this.dirContainer.style.paddingTop = (start*fileHeight)+"px";
|
||||||
|
|
||||||
// First remove the elements which are out of bounds
|
// First remove the elements which are out of bounds
|
||||||
let firstEl;
|
let firstEl;
|
||||||
let firstIdx = -1;
|
let firstIdx = -1;
|
||||||
@@ -142,13 +246,13 @@ FileManager.prototype.renderVisibleFiles = function(files, freshStart) {
|
|||||||
let makeButton = (i, file) => {
|
let makeButton = (i, file) => {
|
||||||
let el = document.createElement("a");
|
let el = document.createElement("a");
|
||||||
el.classList = "node";
|
el.classList = "node";
|
||||||
el.href = "/u/"+file.id;
|
el.href = file.href;
|
||||||
el.target = "_blank";
|
el.target = "_blank";
|
||||||
el.title = file.name;
|
el.title = file.name;
|
||||||
el.setAttribute("fileindex", i);
|
el.setAttribute("fileindex", i);
|
||||||
|
|
||||||
let thumb = document.createElement("img");
|
let thumb = document.createElement("img");
|
||||||
thumb.src = apiEndpoint+"/file/"+file.id+"/thumbnail?width=32&height=32";
|
thumb.src = file.icon;
|
||||||
|
|
||||||
let label = document.createElement("span");
|
let label = document.createElement("span");
|
||||||
label.innerText = file.name;
|
label.innerText = file.name;
|
||||||
|
@@ -9,18 +9,31 @@
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#button_toggle_navigation {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.file_manager {
|
.file_manager {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
background-color: var(--layer_1_color);
|
background-color: var(--layer_1_color);
|
||||||
box-shadow: #000000 8px 8px 50px 5px;
|
box-shadow: #000000 8px 8px 50px 5px;
|
||||||
left:2%;
|
left:3%;
|
||||||
top:2%;
|
top:3%;
|
||||||
right:2%;
|
right:3%;
|
||||||
bottom:2%;
|
bottom:3%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
@media (max-width: 800px) {
|
||||||
|
.file_manager {
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.file_manager > .nav_bar {
|
.file_manager > .nav_bar {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -30,11 +43,28 @@
|
|||||||
.file_manager > .nav_bar > .breadcrumbs {
|
.file_manager > .nav_bar > .breadcrumbs {
|
||||||
flex-grow: .8;
|
flex-grow: .8;
|
||||||
flex-shrink: 1;
|
flex-shrink: 1;
|
||||||
|
min-width: 0;
|
||||||
}
|
}
|
||||||
.file_manager > .nav_bar > .input_search {
|
.file_manager > .nav_bar > .input_search {
|
||||||
flex-grow: .2;
|
flex-grow: .2;
|
||||||
flex-shrink: 1;
|
flex-shrink: 1;
|
||||||
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.file_manager > .directory_sorters {
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.file_manager > .directory_sorters > div {
|
||||||
|
flex-shrink: 0;
|
||||||
|
flex-grow: 1;
|
||||||
|
display: inline-block;
|
||||||
|
margin: 4px 12px;
|
||||||
|
border-bottom: 1px solid var(--input_color);
|
||||||
|
}
|
||||||
|
|
||||||
.file_manager > .directory_area {
|
.file_manager > .directory_area {
|
||||||
flex-shrink: 1;
|
flex-shrink: 1;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
@@ -45,6 +75,9 @@
|
|||||||
text-align: left;
|
text-align: left;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
.file_manager > .directory_area > div {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
.file_manager > .status_bar {
|
.file_manager > .status_bar {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
@@ -52,9 +85,10 @@
|
|||||||
|
|
||||||
.node {
|
.node {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 24px;
|
height: 32px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
margin: 8px;
|
border-radius: 4px;
|
||||||
|
margin: 6px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
display: block;
|
display: block;
|
||||||
color: var(--text_color);
|
color: var(--text_color);
|
||||||
@@ -69,13 +103,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.spinner {
|
.spinner {
|
||||||
position: relative;
|
position: absolute;
|
||||||
display: block;
|
display: block;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
transform: translateY(-50%);
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
width: 100px;
|
width: 100px;
|
||||||
height: 100px;
|
height: 100px;
|
||||||
}
|
}
|
||||||
@@ -90,7 +125,7 @@
|
|||||||
<div id="page_body" class="page_body">
|
<div id="page_body" class="page_body">
|
||||||
<div id="file_manager" class="file_manager">
|
<div id="file_manager" class="file_manager">
|
||||||
<div id="nav_bar" class="nav_bar highlight_light">
|
<div id="nav_bar" class="nav_bar highlight_light">
|
||||||
<button id="btn_menu">☰</button>
|
<button id="btn_menu" onclick="toggleMenu();">☰</button>
|
||||||
<div class="spacer"></div>
|
<div class="spacer"></div>
|
||||||
<button id="btn_back" >⇐</button id="btn_forward">
|
<button id="btn_back" >⇐</button id="btn_forward">
|
||||||
<button id="btn_up" >⇑</button id="btn_forward">
|
<button id="btn_up" >⇑</button id="btn_forward">
|
||||||
@@ -104,6 +139,7 @@
|
|||||||
<div class="spacer"></div>
|
<div class="spacer"></div>
|
||||||
<button id="btn_reload">↻</button>
|
<button id="btn_reload">↻</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="directory_sorters" class="directory_sorters"></div>
|
||||||
<div id="directory_area" class="directory_area"></div>
|
<div id="directory_area" class="directory_area"></div>
|
||||||
<div id="directory_footer" class="status_bar highlight_light"></div>
|
<div id="directory_footer" class="status_bar highlight_light"></div>
|
||||||
</div>
|
</div>
|
||||||
@@ -115,8 +151,9 @@
|
|||||||
{{template `util.js`}}
|
{{template `util.js`}}
|
||||||
{{template `FileManager.js`}}
|
{{template `FileManager.js`}}
|
||||||
|
|
||||||
|
let fm = null;
|
||||||
window.addEventListener("load", () => {
|
window.addEventListener("load", () => {
|
||||||
let fm = new FileManager(document.getElementById("file_manager"));
|
fm = new FileManager(document.getElementById("file_manager"));
|
||||||
fm.getUserFiles();
|
fm.getUserFiles();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
Reference in New Issue
Block a user