From e7e6a77f6fe011d9a06bb2bcb72b6d36fc58e26f Mon Sep 17 00:00:00 2001 From: Bao Nguyen Date: Sat, 18 Feb 2023 08:37:47 +0700 Subject: [PATCH] implement sorting for file explorer --- package-lock.json | 22 +++++ package.json | 2 + src/lib/components/xp/Previewable.svelte | 1 + src/lib/components/xp/Viewer2.svelte | 2 +- src/lib/components/xp/Viewer3.svelte | 2 +- src/routes/xp/desktop_folder.svelte | 2 +- src/routes/xp/programs/my_computer/sort.js | 58 ++++++++++++ .../xp/programs/my_computer/viewer.svelte | 89 +++++++++++++------ 8 files changed, 147 insertions(+), 31 deletions(-) create mode 100644 src/routes/xp/programs/my_computer/sort.js diff --git a/package-lock.json b/package-lock.json index fb7d488..1732c78 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,9 @@ "build-url": "^6.0.1", "docx": "^7.7.0", "dragselect": "^2.5.5", + "fast-sort": "^3.2.1", "file-saver": "^2.0.5", + "hash-sum": "^2.0.0", "idb-keyval": "^6.2.0", "is-valid-http-url": "^1.0.3", "jsdom": "^20.0.3", @@ -2225,6 +2227,11 @@ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" }, + "node_modules/fast-sort": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/fast-sort/-/fast-sort-3.2.1.tgz", + "integrity": "sha512-ECGwVH57yCv3C8v+4BQkQf65bNR4nFetxfGRRLYmzFEAK3oZBr7zCakBjOY/AptmmoU3ffMPJLLN1rdKdMHoUA==" + }, "node_modules/fastq": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", @@ -2450,6 +2457,11 @@ "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" }, + "node_modules/hash-sum": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-2.0.0.tgz", + "integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==" + }, "node_modules/html-encoding-sniffer": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", @@ -5952,6 +5964,11 @@ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" }, + "fast-sort": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/fast-sort/-/fast-sort-3.2.1.tgz", + "integrity": "sha512-ECGwVH57yCv3C8v+4BQkQf65bNR4nFetxfGRRLYmzFEAK3oZBr7zCakBjOY/AptmmoU3ffMPJLLN1rdKdMHoUA==" + }, "fastq": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", @@ -6116,6 +6133,11 @@ "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" }, + "hash-sum": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-2.0.0.tgz", + "integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==" + }, "html-encoding-sniffer": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", diff --git a/package.json b/package.json index 0446166..52f9247 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,9 @@ "build-url": "^6.0.1", "docx": "^7.7.0", "dragselect": "^2.5.5", + "fast-sort": "^3.2.1", "file-saver": "^2.0.5", + "hash-sum": "^2.0.0", "idb-keyval": "^6.2.0", "is-valid-http-url": "^1.0.3", "jsdom": "^20.0.3", diff --git a/src/lib/components/xp/Previewable.svelte b/src/lib/components/xp/Previewable.svelte index 8cf26f6..9f4392c 100644 --- a/src/lib/components/xp/Previewable.svelte +++ b/src/lib/components/xp/Previewable.svelte @@ -28,6 +28,7 @@ }; async function load_preview(){ + console.log(preview_url) if(preview_url != null) return; if(fs_id == null) return; let url = await fs.get_url(fs_id); diff --git a/src/lib/components/xp/Viewer2.svelte b/src/lib/components/xp/Viewer2.svelte index 1447035..3a7ff37 100644 --- a/src/lib/components/xp/Viewer2.svelte +++ b/src/lib/components/xp/Viewer2.svelte @@ -158,7 +158,7 @@
- {#each items as item} + {#each items as item (item.id)}
open(item.id)} diff --git a/src/lib/components/xp/Viewer3.svelte b/src/lib/components/xp/Viewer3.svelte index 1d693e4..26eb9c3 100644 --- a/src/lib/components/xp/Viewer3.svelte +++ b/src/lib/components/xp/Viewer3.svelte @@ -128,7 +128,7 @@
- {#each items as item} + {#each items as item (item.id)}
open(item.id)}> diff --git a/src/routes/xp/desktop_folder.svelte b/src/routes/xp/desktop_folder.svelte index 38b7b62..ae4b2aa 100644 --- a/src/routes/xp/desktop_folder.svelte +++ b/src/routes/xp/desktop_folder.svelte @@ -231,7 +231,7 @@
- {#each items as item, index} + {#each items as item, index (item.id)}
open(item.id)} on:contextmenu={(e) => on_rightclick(e, item)} diff --git a/src/routes/xp/programs/my_computer/sort.js b/src/routes/xp/programs/my_computer/sort.js new file mode 100644 index 0000000..8eb63fc --- /dev/null +++ b/src/routes/xp/programs/my_computer/sort.js @@ -0,0 +1,58 @@ +import { sort } from 'fast-sort'; +import { SortOptions, SortOrders } from '../../../../lib/system'; + +let cache = {}; +onmessage = async ({data}) => { + let {type, hash, id, items, sort_option, sort_order} = data; + + if(type != 'sort') return; + if(sort_option == SortOptions.NONE){ + postMessage({id, sorted_items: items, type: 'sorted'}); + return; + } + + if(cache[hash] != null){ + postMessage({id, sorted_items: cache[hash], type: 'sorted'}); + return; + } + + console.log('sorting', hash); + + for(let item of items){ + if(item.type == 'folder'){ + item.size = 0; + } + } + let order_key = sort_order == SortOrders.ASCENDING ? 'asc' : 'desc'; + let option_key = 'name'; + + switch (sort_option) { + case SortOptions.NAME: + option_key = 'name'; + break; + case SortOptions.SIZE: + option_key = 'size'; + break; + case SortOptions.DATE_CREATED: + option_key = 'date_created'; + break; + case SortOptions.DATE_MODIFIED: + option_key = 'date_modified'; + break; + default: + break; + } + + let predicate = {}; + predicate[order_key] = elm => { + if(option_key == 'name'){ + return elm[option_key].toLowerCase(); + } else { + return elm[option_key]; + } + } + + let sorted_items = sort(items).by([predicate]); + + postMessage({id, sorted_items, type: 'sorted'}) +} \ No newline at end of file diff --git a/src/routes/xp/programs/my_computer/viewer.svelte b/src/routes/xp/programs/my_computer/viewer.svelte index 8d4fb02..d104cc9 100644 --- a/src/routes/xp/programs/my_computer/viewer.svelte +++ b/src/routes/xp/programs/my_computer/viewer.svelte @@ -14,6 +14,7 @@ let dispatch = createEventDispatcher(); import DragSelect from 'dragselect'; import Previewable from '../../../../lib/components/xp/Previewable.svelte'; + import hash_sum from 'hash-sum'; export let self; export let my_computer_instance; @@ -27,6 +28,34 @@ .filter(el => el != null) .filter(el => !hidden_items.includes(el.id)); + $: sorted_items = id ? null : null;//reset sorted_items every time id changes + let worker = new Worker(new URL('./sort.js', import.meta.url), {type: 'module'}); + worker.onmessage = ({data}) => { + if(data.type == 'sorted' && data.id == id){ + console.log('update sorted_items', id); + sorted_items = data.sorted_items; + } + } + + let last_sort_tx_hash; + $: { + if(id){ + let hash_object = { + id, + items, + sort_option: $hardDrive[id].sort_option, + sort_order: $hardDrive[id].sort_order + }; + + let hash = hash_sum(hash_object); + console.log({hash}) + if(hash != last_sort_tx_hash){ + last_sort_tx_hash = hash; + worker.postMessage({type: 'sort', hash, ...hash_object}); + } + } + } + $: is_focus = $zIndex == my_computer_instance?.window.z_index; let computer = my_computer.map(el => $hardDrive[el]); @@ -257,34 +286,38 @@ on:drop={on_drop} on:dragover={on_drop_over} bind:this={node_ref}>
- {#each items as item} -
open(item.id)} on:contextmenu={(e) => on_rightclick(e, item)}> - {#if previewable_exts.includes(item.ext)} - - {:else} -
-
- {/if} -

- {item.name} -

- {#if $selectingItems.includes(item.id) && renaming} - - {/if} - -
- {/each} + {#if sorted_items} + {#each sorted_items as item (item.id)} +
open(item.id)} on:contextmenu={(e) => on_rightclick(e, item)}> + {#if previewable_exts.includes(item.ext)} + + {:else} +
+
+ {/if} +

+ {item.name} +

+ {#if $selectingItems.includes(item.id) && renaming} + + {/if} + +
+ {/each} + {:else} +

working on it...

+ {/if}