From e501969807ed0127a8099e3ae711071f31a3b81d Mon Sep 17 00:00:00 2001 From: Ian Wijma Date: Sat, 6 Jan 2024 19:30:09 +1100 Subject: [PATCH] Add sort and query functions to file list Added sort functionality and query methods to the file list, enabling users to sort file entries by name, size or modification date. The sorting can be in ascending or descending order. Also, updated element.js for element retrieval and added 'getElementsOrThrow' and 'getElements' methods. --- src-tauri/src/main.rs | 62 +++++++++++++++++++++++++++++++++++++++++ src/index.html | 12 ++++++-- src/libs/element.js | 4 +-- src/libs/template.js | 16 ++++++++++- src/parts/files.js | 6 ++-- src/parts/files/list.js | 29 +++++++++++++++++-- 6 files changed, 118 insertions(+), 11 deletions(-) diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index e1af30a..39ca8cb 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -1,8 +1,10 @@ // Prevents additional console window on Windows in release, DO NOT REMOVE!! #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] +use std::cmp::Ordering; use std::time::{UNIX_EPOCH}; use std::os::unix::fs::PermissionsExt; +use std::string::ToString; // Learn more about Tauri commands at https://tauri.app/v1/guides/features/command #[tauri::command] @@ -25,10 +27,29 @@ struct EntryMetaData { accessed: u64, } +enum EntryMetaDataFieldValues { + Str(String), + Int(u64), + Bool(bool), +} + +impl EntryMetaData { + pub fn get_field(&self, field: &str) -> Option { + match field { + "name" => Some(EntryMetaDataFieldValues::Str(self.name.clone())), + "size" => Some(EntryMetaDataFieldValues::Int(self.size)), + "modified" => Some(EntryMetaDataFieldValues::Int(self.modified)), + _ => None + } + } +} + #[tauri::command] fn get_files( _window: tauri::Window, directory: &str, + sort: &str, + order: &str, ) -> Vec { use std::fs; use std::path::Path; @@ -91,6 +112,47 @@ fn get_files( }); } + if sort != "" && order != "" { + let order_asc = order != "desc"; + data.sort_by(|a, b| { + if let Some(field_a) = a.get_field(sort) { + if let Some(field_b) = b.get_field(sort) { + return match field_a { + EntryMetaDataFieldValues::Str(a_string) => { + match field_b { + EntryMetaDataFieldValues::Str(b_string) => match order_asc { + true => a_string.cmp(&b_string), + false => b_string.cmp(&a_string) + }, + _ => Ordering::Equal + } + } + EntryMetaDataFieldValues::Int(a_int) => { + match field_b { + EntryMetaDataFieldValues::Int(b_int) => match order_asc { + true => a_int.cmp(&b_int), + false => b_int.cmp(&a_int) + }, + _ => Ordering::Equal + } + } + EntryMetaDataFieldValues::Bool(a_bool) => { + match field_b { + EntryMetaDataFieldValues::Bool(b_bool) => match order_asc { + true => a_bool.cmp(&b_bool), + false => b_bool.cmp(&a_bool) + }, + _ => Ordering::Equal + } + } + } + } + } + + return Ordering::Equal; + }); + } + return data; } diff --git a/src/index.html b/src/index.html index db84665..ac42af9 100644 --- a/src/index.html +++ b/src/index.html @@ -57,9 +57,15 @@ - - - + + + diff --git a/src/libs/element.js b/src/libs/element.js index 14d596b..7572c04 100644 --- a/src/libs/element.js +++ b/src/libs/element.js @@ -25,7 +25,7 @@ export const getElementOrThrow = (source, selector) => { const element = getElement(source, selector); if (!element) { - throw new Error(`Element ${selector} not found in ${source}`); + throw new Error(`Element ${selector} not found in ${source.innerHTML}`); } return element; @@ -40,7 +40,7 @@ export const getElementsOrThrow = (source, selector) => { const elements = getElements(source, selector); if (elements.length <= 0) { - throw new Error(`No elements found with ${selector} in ${source}`); + throw new Error(`No elements found with ${selector} in ${source.innerHTML}`); } return elements diff --git a/src/libs/template.js b/src/libs/template.js index 9734558..a3633b8 100644 --- a/src/libs/template.js +++ b/src/libs/template.js @@ -1,4 +1,4 @@ -import {getElementOrThrow, getOneElementOrThrow} from "./element.js"; +import {getElementOrThrow, getElements, getElementsOrThrow, getOneElementOrThrow} from "./element.js"; /** * @typedef {Object} Template @@ -22,10 +22,24 @@ export const getTemplate = (name) => { */ const el = (selector) => getElementOrThrow(element, `[data-el=${selector}]`); + /** + * @param {string} selector + * @returns {HTMLElement[]} + */ + const els = (selector) => getElementsOrThrow(element, `[data-el=${selector}]`); + + /** + * @param {string} selector + * @returns {HTMLElement[]} + */ + const query = (selector) => getElements(element, selector); + const render = () => element; return { el, + els, + query, render } } \ No newline at end of file diff --git a/src/parts/files.js b/src/parts/files.js index bcf4412..b8d83c1 100644 --- a/src/parts/files.js +++ b/src/parts/files.js @@ -56,10 +56,12 @@ export const renderFiles = async () => { /** * @param {string} directory + * @param {string} sort + * @param {string} order * @returns {Promise} */ -export const getEntries = async (directory) => { - return await tauriInvoke('get_files', { directory }); +export const getEntries = async (directory, sort = '', order = 'asc') => { + return await tauriInvoke('get_files', { directory, sort, order }); } /** diff --git a/src/parts/files/list.js b/src/parts/files/list.js index 9b99478..b04b0fc 100644 --- a/src/parts/files/list.js +++ b/src/parts/files/list.js @@ -6,9 +6,9 @@ import {sep} from "../../libs/path.js"; export const renderListFiles = () => { const fileEl = getOneElementOrThrow(document, '[data-ui=files]'); - const containerTemplate = getTemplate('files-list'); - const body = containerTemplate.el('body'); + let sort = ''; + let order = ''; /** * @callback ValueFormat @@ -31,8 +31,11 @@ export const renderListFiles = () => { } const renderList = async () => { + let containerTemplate = getTemplate('files-list'); + const body = containerTemplate.el('body'); + const currentDirectory = getCurrentDir(); - const entries = await getEntries(currentDirectory); + const entries = await getEntries(currentDirectory, sort, order); for (const entry of entries) { const itemTemplate = getTemplate('files-list-item'); @@ -75,6 +78,26 @@ export const renderListFiles = () => { body.appendChild(itemTemplate.render()); } + const sortEls = containerTemplate.els('sort'); + const handleSort = (sortEl) => { + sort = sortEl.dataset.sort; + + sortEls.forEach(sortEl => sortEl.dataset.order = ''); + + switch (order) { + case '': sortEl.dataset.order = 'asc'; break; + case 'asc': sortEl.dataset.order = 'desc'; break; + case 'desc': sortEl.dataset.order = ''; break; + default: sortEl.dataset.order = ''; break; + } + + order = sortEl.dataset.order; + + console.log({sort, order}); + renderList() + }; + sortEls.forEach(sortEl => sortEl.addEventListener('click', () => handleSort(sortEl))); + fileEl.innerHTML = ''; fileEl.appendChild(containerTemplate.render()); }
NameSizeModified + Name + + Size + + Modified +