diff --git a/res/include/script/file_manager/FileManager.js b/res/include/script/file_manager/FileManager.js index 25b123a..9e733d1 100644 --- a/res/include/script/file_manager/FileManager.js +++ b/res/include/script/file_manager/FileManager.js @@ -1,16 +1,39 @@ function FileManager(windowElement) { - this.window = windowElement; - this.navBar = this.window.querySelector("#nav_bar"); - this.btnMenu = this.navBar.querySelector("#btn_menu"); - this.btnBack = this.navBar.querySelector("#btn_back"); - this.btnUp = this.navBar.querySelector("#btn_up"); - this.btnForward = this.navBar.querySelector("#btn_forward"); - this.btnHome = this.navBar.querySelector("#btn_home"); - this.breadcrumbs = this.navBar.querySelector("#breadcrumbs"); - this.btnReload = this.navBar.querySelector("#btn_reload"); - this.inputSearch = this.navBar.querySelector("#input_search"); - this.directoryArea = this.window.querySelector("#directory_area"); - this.directoryFooter = this.window.querySelector("#directory_footer"); + this.window = windowElement; + this.navBar = this.window.querySelector("#nav_bar"); + this.btnMenu = this.navBar.querySelector("#btn_menu"); + this.btnBack = this.navBar.querySelector("#btn_back"); + this.btnUp = this.navBar.querySelector("#btn_up"); + this.btnForward = this.navBar.querySelector("#btn_forward"); + this.btnHome = this.navBar.querySelector("#btn_home"); + this.breadcrumbs = this.navBar.querySelector("#breadcrumbs"); + this.btnReload = this.navBar.querySelector("#btn_reload"); + this.inputSearch = this.navBar.querySelector("#input_search"); + this.directorySorters = this.window.querySelector("#directory_sorters"); + 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.directoryArea.appendChild(this.dirContainer); @@ -22,12 +45,27 @@ function FileManager(windowElement) { this.renderVisibleFiles(this.visibleFiles, false); }) + // type: {icon, name, href, type, size} this.allFiles = []; this.visibleFiles = []; 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) { if (term === "") { this.visibleFiles = this.allFiles; @@ -51,28 +89,36 @@ FileManager.prototype.getDirectory = function(path) { } FileManager.prototype.getUserFiles = function() { + this.setSpinner(); + let getAll = (page) => { fetch(apiEndpoint+"/user/files?page="+page+"&limit=10000").then(resp => { if (!resp.ok) {Promise.reject("yo");} return resp.json(); }).then(resp => { - if (page === 0) { - this.allFiles = resp.files; - } else { - this.allFiles = this.allFiles.concat(resp.files); + for (let i in resp.files) { + this.allFiles.push({ + icon: apiEndpoint+"/file/"+resp.files[i].id+"/thumbnail?width=32&height=32", + 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.renderVisibleFiles(this.visibleFiles, true); + this.currentSortField = ""; + this.sortBy("name"); if (resp.files.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); }) } @@ -80,9 +126,77 @@ FileManager.prototype.getUserFiles = function() { 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) { + 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) { this.dirContainer.innerHTML = ""; + this.dirContainer.style.height = totalHeight+"px"; + this.dirContainer.scrollTop = 0; + this.lastScrollTop = 0; + scrollDown = true; let totalSize = 0; for (let i in files) { @@ -95,25 +209,15 @@ FileManager.prototype.renderVisibleFiles = function(files, freshStart) { +formatDataVolume(totalSize, 4); } - let scrollDown = this.lastScrollTop <= this.directoryArea.scrollTop; - this.lastScrollTop = this.directoryArea.scrollTop; + let paddingTop = this.lastScrollTop - this.lastScrollTop%fileHeight; + let start = Math.floor(paddingTop/fileHeight) - 5; + if (start < 0) { start = 0; } - let fileHeight = 32; - 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); + let end = Math.ceil((paddingTop+viewportHeight)/fileHeight) + 5; if (end > files.length) { end = files.length-1; } + this.dirContainer.style.paddingTop = (start*fileHeight)+"px"; + // First remove the elements which are out of bounds let firstEl; let firstIdx = -1; @@ -142,13 +246,13 @@ FileManager.prototype.renderVisibleFiles = function(files, freshStart) { let makeButton = (i, file) => { let el = document.createElement("a"); el.classList = "node"; - el.href = "/u/"+file.id; + el.href = file.href; el.target = "_blank"; el.title = file.name; el.setAttribute("fileindex", i); 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"); label.innerText = file.name; diff --git a/res/template/account/file_manager.html b/res/template/account/file_manager.html index 06590d4..1d4a7ad 100644 --- a/res/template/account/file_manager.html +++ b/res/template/account/file_manager.html @@ -9,18 +9,31 @@ padding: 0; } + #button_toggle_navigation { + display: none; + } + .file_manager { position: absolute; padding: 0; background-color: var(--layer_1_color); box-shadow: #000000 8px 8px 50px 5px; - left:2%; - top:2%; - right:2%; - bottom:2%; + left:3%; + top:3%; + right:3%; + bottom:3%; display: flex; flex-direction: column; } + @media (max-width: 800px) { + .file_manager { + left: 0; + top: 0; + right: 0; + bottom: 0; + } + } + .file_manager > .nav_bar { flex-shrink: 0; display: flex; @@ -30,11 +43,28 @@ .file_manager > .nav_bar > .breadcrumbs { flex-grow: .8; flex-shrink: 1; + min-width: 0; } .file_manager > .nav_bar > .input_search { flex-grow: .2; 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 { flex-shrink: 1; flex-grow: 1; @@ -45,6 +75,9 @@ text-align: left; box-sizing: border-box; } + .file_manager > .directory_area > div { + box-sizing: border-box; + } .file_manager > .status_bar { flex-shrink: 0; text-align: left; @@ -52,9 +85,10 @@ .node { position: relative; - height: 24px; + height: 32px; overflow: hidden; - margin: 8px; + border-radius: 4px; + margin: 6px; box-sizing: border-box; display: block; color: var(--text_color); @@ -69,13 +103,14 @@ } .spinner { - position: relative; + position: absolute; display: block; margin: auto; max-width: 100%; max-height: 100%; top: 50%; - transform: translateY(-50%); + left: 50%; + transform: translate(-50%, -50%); width: 100px; height: 100px; } @@ -90,7 +125,7 @@
+
@@ -115,8 +151,9 @@ {{template `util.js`}} {{template `FileManager.js`}} + let fm = null; window.addEventListener("load", () => { - let fm = new FileManager(document.getElementById("file_manager")); + fm = new FileManager(document.getElementById("file_manager")); fm.getUserFiles(); });