From 34cb374202d73f24a368d16e4e64e42e01d258d9 Mon Sep 17 00:00:00 2001 From: MickaelK Date: Fri, 10 May 2024 01:31:20 +1000 Subject: [PATCH] chore (rewrite): filesystem elements --- .../components/decorator_shell_filemanager.js | 2 +- public/assets/components/loader.js | 4 +- .../pages/filespage/ctrl_filesystem.css | 2 +- .../assets/pages/filespage/ctrl_filesystem.js | 19 +-- .../assets/pages/filespage/ctrl_submenu.css | 2 +- public/assets/pages/filespage/ctrl_submenu.js | 43 ++--- public/assets/pages/filespage/helper.js | 153 +++++++++--------- public/assets/pages/filespage/thing.js | 8 +- 8 files changed, 127 insertions(+), 106 deletions(-) diff --git a/public/assets/components/decorator_shell_filemanager.js b/public/assets/components/decorator_shell_filemanager.js index bd65f972..2799ae39 100644 --- a/public/assets/components/decorator_shell_filemanager.js +++ b/public/assets/components/decorator_shell_filemanager.js @@ -21,7 +21,7 @@ export default function(ctrl) { render($page); // feature1: setup the breadcrumb path - qs($page, `[is="component-breadcrumb"]`).setAttribute("path", urlToPath(location.pathname)); + qs($page, `[is="component-breadcrumb"]`).setAttribute("path", urlToPath(location.pathname + location.hash)); // feature2: setup the childrens const $main = qs($page, `[data-bind="filemanager-children"]`); diff --git a/public/assets/components/loader.js b/public/assets/components/loader.js index ef595e0e..f4fe0a27 100644 --- a/public/assets/components/loader.js +++ b/public/assets/components/loader.js @@ -45,7 +45,7 @@ class Loader extends window.HTMLElement { customElements.define("component-loader", Loader); export function createLoader($parent, opts = {}) { - const { wait = 500 } = opts; + const { wait = 250 } = opts; const cancel = effect(new rxjs.Observable((observer) => { const $icon = createElement(`
@@ -61,7 +61,7 @@ export function createLoader($parent, opts = {}) { `); const id = window.setTimeout(() => { $parent.replaceChildren($icon); - animate($icon, { time: 1000, keyframes: opacityIn() }); + animate($icon, { time: 750, keyframes: opacityIn() }); }, wait); return () => { clearTimeout(id); diff --git a/public/assets/pages/filespage/ctrl_filesystem.css b/public/assets/pages/filespage/ctrl_filesystem.css index e34bd92c..1a2cf9b5 100644 --- a/public/assets/pages/filespage/ctrl_filesystem.css +++ b/public/assets/pages/filespage/ctrl_filesystem.css @@ -1,5 +1,5 @@ [is="component_filesystem"] .component_filesystem { - padding-top: 5px; + padding-top: 3px; } [is="component_filesystem"] .empty { text-align: center; diff --git a/public/assets/pages/filespage/ctrl_filesystem.js b/public/assets/pages/filespage/ctrl_filesystem.js index 4a929ea0..4636d460 100644 --- a/public/assets/pages/filespage/ctrl_filesystem.js +++ b/public/assets/pages/filespage/ctrl_filesystem.js @@ -49,15 +49,15 @@ export default async function(render) { if (!!state.search) { const removeLoader = createLoader($header); return search(state.search_q).pipe(rxjs.map((files) => ({ - ...rest, files, ...state, + ...rest, files, ...state, read_only: true, })), removeLoader); } - return rxjs.of({ ...rest, files, ...state }); + return rxjs.of({ ...rest, files, ...state, read_only: false }); }))), rxjs.mergeMap(({ show_hidden, files, ...rest }) => { if (show_hidden === false) files = files.filter(({ name }) => name[0] !== "."); console.log(rest); - files = sort(files, rest.sort); + files = sort(files, rest.sort, rest.order); return rxjs.of({ ...rest, files }) }), removeLoader, @@ -69,7 +69,7 @@ export default async function(render) { return rxjs.of({...rest, files }); }), rxjs.mergeMap((obj) => refreshOnResize$.pipe(rxjs.mapTo(obj))), - rxjs.mergeMap(({ files, path, view }) => { // STEP1: setup the list of files + rxjs.mergeMap(({ files, path, view, read_only }) => { // STEP1: setup the list of files $list.closest(".scroll-y").scrollTop = 0; let FILE_HEIGHT, COLUMN_PER_ROW; switch(view) { @@ -99,7 +99,7 @@ export default async function(render) { $fs.appendChild(createThing({ ...file, ...createLink(file, path), - view, + view, read_only, n: i, })); } @@ -129,9 +129,10 @@ export default async function(render) { $listAfter.style.height = `${height - size}px`; }; setHeight(0); - // const top = ($node) => $node.getBoundingClientRect().top; + const top = ($node) => $node.getBoundingClientRect().top; return rxjs.of({ files, + read_only, path, view, currentState: 0, @@ -140,11 +141,11 @@ export default async function(render) { FILE_HEIGHT, BLOCK_SIZE, COLUMN_PER_ROW, - MARGIN: 35, // TODO: top($list) - top($list.closest(".scroll-y")); + MARGIN: top($list) - top($list.closest(".scroll-y")), }); }), rxjs.mergeMap(({ - files, path, view, + files, path, view, read_only, BLOCK_SIZE, COLUMN_PER_ROW, FILE_HEIGHT, MARGIN, currentState, @@ -207,7 +208,7 @@ export default async function(render) { type: "hidden", })); else $fs.appendChild(createThing({ - ...file, + ...file, read_only, ...createLink(file, path), view, n: i, diff --git a/public/assets/pages/filespage/ctrl_submenu.css b/public/assets/pages/filespage/ctrl_submenu.css index 725fa716..65901562 100644 --- a/public/assets/pages/filespage/ctrl_submenu.css +++ b/public/assets/pages/filespage/ctrl_submenu.css @@ -4,7 +4,7 @@ position: sticky; top: 0; z-index: 3; - padding: 5px 0; + padding: 4px 0; backdrop-filter: blur(20px) saturate(2); transition: 0.2s ease box-shadow; } diff --git a/public/assets/pages/filespage/ctrl_submenu.js b/public/assets/pages/filespage/ctrl_submenu.js index c5d916b5..09f33a24 100644 --- a/public/assets/pages/filespage/ctrl_submenu.js +++ b/public/assets/pages/filespage/ctrl_submenu.js @@ -16,7 +16,7 @@ import componentDelete from "./modal_delete.js"; import { getSelection$, clearSelection } from "./state_selection.js"; import { getAction$, setAction } from "./state_event.js"; -import { setState } from "./state_filesystem.js"; +import { setState, getState$ } from "./state_filesystem.js"; const modalOpt = { withButtonsRight: "OK", @@ -38,7 +38,7 @@ export default async function(render) { componentRight(createRender(qs($page, ".action.right"))); effect(rxjs.fromEvent($scroll, "scroll", { passive: true }).pipe( - rxjs.map((e) => e.target.scrollTop > 30), + rxjs.map((e) => e.target.scrollTop > 12), rxjs.distinctUntilChanged(), rxjs.startWith(false), rxjs.tap((scrolling) => scrolling @@ -157,20 +157,20 @@ function componentRight(render) { sort
- +
`))), rxjs.mergeMap(($page) => rxjs.merge( @@ -208,18 +208,23 @@ function componentRight(render) { } const $lis = qsa($page, `.dropdown_container li`); return onClick($lis).pipe( - rxjs.tap(($el) => { + rxjs.first(), + rxjs.mergeMap(($el) => getState$().pipe(rxjs.first(), rxjs.map((state) => ({ + order: state.order, + $el, + })))), + rxjs.tap(({ $el, order }) => { setState( "sort", $el.getAttribute("data-target"), - "order", !!$el.querySelector("img") ? "asc" : "des", + "order", order === "asc" ? "des" : "asc", ); [...$lis].map(($li) => { const $img = $li.querySelector("img"); if ($img) $img.remove(); }); $el.appendChild(createElement(`check`)); + $sort.classList.remove("active"); }), - rxjs.tap(() => $sort.classList.remove("active")), ); }), ), diff --git a/public/assets/pages/filespage/helper.js b/public/assets/pages/filespage/helper.js index cc2af8b5..dba852f9 100644 --- a/public/assets/pages/filespage/helper.js +++ b/public/assets/pages/filespage/helper.js @@ -1,85 +1,94 @@ import { extname } from "../../lib/path.js"; -export function sort(files, type) { - if (type === "name") { - return sortByName(files); - } else if (type === "date") { - return sortByDate(files); - } else { - return sortByType(files); +export function sort(files, type, order) { + switch(type) { + case "name": return sortByName(files, order); + case "date": return sortByDate(files, order); + default: return sortByType(files, order); } -}; +} + +function sortByType(files, order) { + let tmp; + return files.sort(function(fileA, fileB) { + tmp = _moveLoadingDownward(fileA, fileB); + if (tmp !== 0) return tmp; + + tmp = _moveFolderUpward(fileA, fileB); + if (tmp !== 0) return tmp; + + tmp = _moveHiddenFilesDownward(fileA, fileB); + if (tmp !== 0) return tmp; + + const faname = fileA.name.toLowerCase(); + const fbname = fileB.name.toLowerCase(); + + const aExt = extname(faname); + const bExt = extname(fbname); + + if (aExt === bExt) return sortString(faname, fbname, order); + return sortString(aExt, bExt, order); + }); +} + +function sortByName(files, order) { + let tmp; + return files.sort(function(fileA, fileB) { + tmp = _moveLoadingDownward(fileA, fileB); + if (tmp !== 0) return tmp; + + tmp = _moveFolderUpward(fileA, fileB); + if (tmp !== 0) return tmp; + + tmp = _moveHiddenFilesDownward(fileA, fileB); + if (tmp !== 0) return tmp; + + return sortString(fileA.name.toLowerCase(), fileB.name.toLowerCase(), order); + }); +} + +function sortByDate(files, order) { + return files.sort(function(fileA, fileB) { + if (fileB.time === fileA.time) { + return sortString(fileA.name, fileB.name, order); + } + return sortNumber(fileA.time, fileB.time, order); + }); +} + +function sortString(a, b, order) { + if (order === "asc") return a > b ? +1 : -1; + return a < b ? +1 : -1; +} + +function sortNumber(a, b, order) { + if (order === "asc") return b - a; + return a - b; +} function _moveLoadingDownward(fileA, fileB) { - if (fileA.icon === "loading" && fileB.icon !== "loading") { - return +1; - } else if (fileA.icon !== "loading" && fileB.icon === "loading") { - return -1; - } + const aIsLoading = fileA.icon === "loading"; + const bIsLoading = fileB.icon === "loading"; + + if (aIsLoading && !bIsLoading) return +1; + else if (!aIsLoading && bIsLoading) return -1; return 0; } + function _moveFolderUpward(fileA, fileB) { - if (["directory", "link"].indexOf(fileA.type) === -1 && - ["directory", "link"].indexOf(fileB.type) !== -1) { - return +1; - } else if (["directory", "link"].indexOf(fileA.type) !== -1 && - ["directory", "link"].indexOf(fileB.type) === -1) { - return -1; - } + const aIsDirectory = ["directory", "link"].indexOf(fileA.type) !== -1; + const bIsDirectory = ["directory", "link"].indexOf(fileB.type) !== -1; + + if (!aIsDirectory && bIsDirectory) return +1; + else if (aIsDirectory && !bIsDirectory) return -1; return 0; } + function _moveHiddenFilesDownward(fileA, fileB) { - if (fileA.name[0] === "." && fileB.name[0] !== ".") return +1; - else if (fileA.name[0] !== "." && fileB.name[0] === ".") return -1; + const aIsHidden = fileA.name[0] === "."; + const bIsHidden = fileB.name[0] === "."; + + if (aIsHidden && !bIsHidden) return +1; + if (!aIsHidden && bIsHidden) return -1; return 0; } -function sortByType(files) { - return files.sort((fileA, fileB) => { - let tmp = _moveLoadingDownward(fileA, fileB); - if (tmp !== 0) return tmp; - - tmp = _moveFolderUpward(fileA, fileB); - if (tmp !== 0) return tmp; - - tmp = _moveHiddenFilesDownward(fileA, fileB); - if (tmp !== 0) return tmp; - - const aExt = extname(fileA.name.toLowerCase()); - const bExt = extname(fileB.name.toLowerCase()); - - if (fileA.name.toLowerCase() === fileB.name.toLowerCase()) { - return fileA.name > fileB.name ? +1 : -1; - } else { - if (aExt !== bExt) return aExt > bExt ? +1 : -1; - else return fileA.name.toLowerCase() > fileB.name.toLowerCase() ? +1 : -1; - } - }); -} -function sortByName(files) { - return files.sort((fileA, fileB) => { - let tmp = _moveLoadingDownward(fileA, fileB); - if (tmp !== 0) return tmp; - - tmp = _moveFolderUpward(fileA, fileB); - if (tmp !== 0) return tmp; - - tmp = _moveHiddenFilesDownward(fileA, fileB); - if (tmp !== 0) return tmp; - - if (fileA.name.toLowerCase() === fileB.name.toLowerCase()) { - return fileA.name > fileB.name ? +1 : -1; - } - return fileA.name.toLowerCase() > fileB.name.toLowerCase() ? +1 : -1; - }); -} -function sortByDate(files) { - return files.sort((fileA, fileB) => { - const tmp = _moveLoadingDownward(fileA, fileB); - if (tmp !== 0) return tmp; - - if (fileB.time === fileA.time) { - return fileA.name > fileB.name ? +1 : -1; - } - return fileB.time - fileA.time; - }); -} diff --git a/public/assets/pages/filespage/thing.js b/public/assets/pages/filespage/thing.js index 2d6b6e8d..f30779aa 100644 --- a/public/assets/pages/filespage/thing.js +++ b/public/assets/pages/filespage/thing.js @@ -46,6 +46,7 @@ export function createThing({ // permissions = {} view = "", n = 0, + read_only = false, }) { const $thing = $tmpl.cloneNode(true); assert.type($thing, window.HTMLElement); @@ -60,7 +61,12 @@ export function createThing({ $thing.classList.add("view-" + view); $time.textContent = formatTime(new Date(time)); sideEffectSelection($thing, isSelected(n)); - if (type === "hidden") $thing.classList.add("hidden"); + + if (read_only === true) return $thing; + else if (type === "hidden") { + $thing.classList.add("hidden"); + return $thing; + } $thing.querySelector(".component_checkbox").onclick = function(e) { e.preventDefault();