plugins: HFS.textSortCompare #1018

Massimo Melina committed Jun 15, 2025 at 11:46 UTC c5cd1e36cdc7474a237bcc77d85495362d872386
3 files changed +14 -8
dev-plugins.md
+8 -3
@@ -3,7 +3,7 @@
3 If the information you are searching for is not in this document, [please ask](https://github.com/rejetto/hfs/discussions).
4
5 A plug-in is a folder with a `plugin.js` file in it. To install a plugin you just copy the folder into the `plugins` folder.
6 -You will find `plugins` folder near `config.yaml`, and then in `USER_FOLDER/.hfs` for Linux and MacOS, or near `hfs.exe` on Windows.
6 +You will find `plugins` folder near `config.yaml`, and then in `USER_FOLDER/.hfs` for Linux and macOS, or near `hfs.exe` on Windows.
7
8 Plug-ins can be hot-swapped, and to some extent can be edited without restarting the server.
9
@@ -124,7 +124,7 @@ All the following properties are optional unless otherwise specified.
124 complicated object form to link github, use the string form.
125 Plugins with custom repos are not included in search results, but the update feature will still work.
126 - `changelog: { version: number, message: string }[]` the UI will show only entries with version greater than currently installed.
127 - You can use `md` syntax for the message.
127 + You can use `md` syntax inside the message. (JSON syntax)
128
129 **WARNING:** All the properties above are a bit special and must go in `exports` only (thus, not returned in `init`) and the syntax
130 used must be strictly JSON (thus, no single quotes, only double quotes for strings and objects), and must fit one line.
@@ -441,6 +441,9 @@ In frontend you will have access to the `HFS` object of the global scope, which
441 - `urlParams: object` you'll find each parameter in the URL mapped in this object as string.
442 - `fileShowComponents: { Video, Audio }` exposes standard components used by file-show. Can be useful if you need extend them, inside `fileShow` event.
443 - `isShowSupported(entry: DirEntry): boolean` true if the entry is supported by Show.
444 +- `textSortCompare(a: string, b: string): number` the function HFS will use for text sorting.
445 + Returns a negative if `a` must go before `b`, a positive if `b` must go before `a`, or zero they have same order.
446 + It's exposed for you to use, or to overwrite if you need.
447
448 The following properties are accessible only immediately at top-level; don't call it later in a callback.
449 - `getPluginConfig()` returns object of all config keys that are declared frontend-accessible by this plugin.
@@ -1031,4 +1034,6 @@ If you want to override a text regardless of the language, use the special langu
1034 - 12.5 (v0.57.2)
1035 - changed parameters for events log, error_log, failedLogin, accountRenamed
1036 - HFS.fileShow return value
1034 - - HFS.isShowSupported
\ No newline at end of file
1037 + - HFS.isShowSupported
1038 +- 12.6 (v0.57.6)
1039 + - HFS.textSortCompare
\ No newline at end of file
frontend/src/useFetchList.ts
+5 -4
@@ -8,7 +8,7 @@ import { subscribeKey } from 'valtio/utils'
8 import { useIsMounted } from 'usehooks-ts'
9 import { alertDialog } from './dialog'
10 import {
11 - hfsEvent, LIST, urlParams, xlate, objFromKeys,
11 + hfsEvent, LIST, urlParams, xlate, objFromKeys, getHFS,
12 HTTP_MESSAGES, HTTP_METHOD_NOT_ALLOWED, HTTP_UNAUTHORIZED,
13 } from './misc'
14 import { useLocation, useNavigate } from 'react-router-dom'
@@ -168,7 +168,7 @@ export function reloadList() {
168 state.listReloader = Date.now()
169 }
170
171 -const { compare: localCompare } = new Intl.Collator(navigator.language)
171 +getHFS().textSortCompare = new Intl.Collator(navigator.language).compare // expose it, so that it can be overridden
172
173 function sort(list: DirList) {
174 const { sort_by, folders_first, sort_numerics } = state
@@ -178,18 +178,19 @@ function sort(list: DirList) {
178 const byTime = sort_by === 'time'
179 const byCreation = sort_by === 'creation'
180 const invert = state.invert_order ? -1 : 1
181 + const {textSortCompare} = getHFS()
182 return list.sort((a, b) =>
183 -compareScalar(a.order||0, b.order||0)
184 || hfsEvent('sortCompare', { a, b }).find(Boolean)
185 || folders_first && -compareScalar(a.isFolder, b.isFolder)
186 || invert * (bySize ? compareScalar(a.s||0, b.s||0)
186 - : byExt ? localCompare(a.ext, b.ext)
187 + : byExt ? textSortCompare(a.ext, b.ext)
188 : byTime ? compareScalar(a.m, b.m)
189 : byCreation ? compareScalar(a.c, b.c)
190 : 0
191 )
192 || sort_numerics && (invert * compareNumerics(a.n, b.n))
192 - || invert * localCompare(a.n, b.n) // fallback to name/path
193 + || invert * textSortCompare(a.n, b.n) // fallback to name/path
194 )
195
196 function compareNumerics(a: string, b: string) {
src/const.ts
+1 -1
@@ -9,7 +9,7 @@ import { formatTimestamp } from './cross'
9 import { argv } from './argv'
10 export * from './cross-const'
11
12 -export const API_VERSION = 12.5
12 +export const API_VERSION = 12.6
13 export const COMPATIBLE_API_VERSION = 1 // while changes in the api are not breaking, this number stays the same, otherwise it is made equal to API_VERSION
14
15 // you can add arguments with this file, currently used for the update process on mac/linux