luci-base: ui: fix path handling in UIFileUpload
authorPaul Donald <newtwen+github@gmail.com>
Thu, 20 Mar 2025 16:20:08 +0000 (17:20 +0100)
committerPaul Donald <newtwen+github@gmail.com>
Thu, 20 Mar 2025 16:21:33 +0000 (17:21 +0100)
Browsing the root path was problematic and the breadcrumb links behaved
inconsistently, requiring a page reload to recover.

canonicalizePath(), splitPath() and renderListing() now handle any path
location properly, including root: '/', and clicks at any breadcrumb
correctly navigate.

Signed-off-by: Paul Donald <newtwen+github@gmail.com>
modules/luci-base/htdocs/luci-static/resources/ui.js

index 83f28b320f3fd5d2314d0d7d737ebcf5de84d14f..f0ea264bd4434bb09e59c21d5fd08c6abd87dda1 100644 (file)
@@ -2877,10 +2877,10 @@ const UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */
 
        /** @private */
        canonicalizePath(path) {
-               return path.replace(/\/{2,}/, '/')
-                       .replace(/\/\.(\/|$)/g, '/')
-                       .replace(/[^\/]+\/\.\.(\/|$)/g, '/')
-                       .replace(/\/$/, '');
+       return path.replace(/\/{2,}/g, '/')                // Collapse multiple slashes
+                               .replace(/\/\.(\/|$)/g, '/')           // Remove `/.`
+                               .replace(/[^\/]+\/\.\.(\/|$)/g, '/')   // Resolve `/..`
+                               .replace(/\/$/g, (m, o, s) => s.length > 1 ? '' : '/'); // Remove trailing `/` only if not root
        },
 
        /** @private */
@@ -2891,10 +2891,7 @@ const UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */
                if (cpath.length <= croot.length)
                        return [ croot ];
 
-               if (cpath.charAt(croot.length) != '/')
-                       return [ croot ];
-
-               const parts = cpath.substring(croot.length + 1).split(/\//);
+               const parts = cpath.substring(croot.length).split(/\//);
 
                parts.unshift(croot);
 
@@ -3079,13 +3076,13 @@ const UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */
                let cur = '';
 
                for (let i = 0; i < dirs.length; i++) {
-                       cur = cur ? `${cur}/${dirs[i]}` : dirs[i];
+                       cur += dirs[i];
                        dom.append(breadcrumb, [
                                i ? ' ยป ' : '',
                                E('a', {
                                        'href': '#',
                                        'click': UI.prototype.createHandlerFn(this, 'handleSelect', cur ?? '/', null)
-                               }, dirs[i] != '' ? '%h'.format(dirs[i]) : E('em', '(root)')),
+                               }, dirs[i] !== '/' ? '%h'.format(dirs[i]) : E('em', '(root)')),
                        ]);
                }