luci-base: ui.js FileUpload: option to enable Download button
authorSergey Ponomarev <stokito@gmail.com>
Thu, 21 Sep 2023 19:48:54 +0000 (22:48 +0300)
committerSergey Ponomarev <stokito@gmail.com>
Tue, 9 Apr 2024 07:43:35 +0000 (10:43 +0300)
Allow downloading from a file browser.
The Download button is located near to Delete.
It's shown only for files: folders or /dev/ devices can't be downloaded.
The downloading is made via fs.read_direct() which internally calls cgi-download.

Signed-off-by: Sergey Ponomarev <stokito@gmail.com>
modules/luci-base/htdocs/luci-static/resources/form.js
modules/luci-base/htdocs/luci-static/resources/ui.js

index dbe1382ad406d1fb13c8aa31e6d8a92607cd74ae..df594a3a34068730a7ad9759c7477de33838312a 100644 (file)
@@ -4547,6 +4547,7 @@ var CBIFileUpload = CBIValue.extend(/** @lends LuCI.form.FileUpload.prototype */
                this.show_hidden = false;
                this.enable_upload = true;
                this.enable_remove = true;
+               this.enable_download = false;
                this.root_directory = '/etc/luci-uploads';
        },
 
@@ -4603,6 +4604,14 @@ var CBIFileUpload = CBIValue.extend(/** @lends LuCI.form.FileUpload.prototype */
         * @default true
         */
 
+       /**
+        * Toggle download file functionality.
+        *
+        * @name LuCI.form.FileUpload.prototype#enable_download
+        * @type boolean
+        * @default false
+        */
+
        /**
         * Specify the root directory for file browsing.
         *
@@ -4628,6 +4637,7 @@ var CBIFileUpload = CBIValue.extend(/** @lends LuCI.form.FileUpload.prototype */
                        show_hidden: this.show_hidden,
                        enable_upload: this.enable_upload,
                        enable_remove: this.enable_remove,
+                       enable_download: this.enable_download,
                        root_directory: this.root_directory,
                        disabled: (this.readonly != null) ? this.readonly : this.map.readonly
                });
index 1b14c60c649e004a8b00e54089490815f1767df5..8d41962ac9e81b75dbf6b92059b1820e8e887dc2 100644 (file)
@@ -2636,6 +2636,9 @@ var UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */ {
         * remotely depends on the ACL setup for the current session. This option
         * merely controls whether the file remove controls are rendered or not.
         *
+        * @property {boolean} [enable_download=false]
+        * Specifies whether the widget allows the user to download files.
+        *
         * @property {string} [root_directory=/etc/luci-uploads]
         * Specifies the remote directory the upload and file browsing actions take
         * place in. Browsing to directories outside the root directory is
@@ -2650,6 +2653,7 @@ var UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */ {
                        show_hidden: false,
                        enable_upload: true,
                        enable_remove: true,
+                       enable_download: false,
                        root_directory: '/etc/luci-uploads'
                }, options);
        },
@@ -2931,6 +2935,10 @@ var UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */ {
                                                'class': 'btn',
                                                'click': UI.prototype.createHandlerFn(this, 'handleReset')
                                        }, [ _('Deselect') ]) : '',
+                                       this.options.enable_download && list[i].type == 'file' ? E('button', {
+                                               'class': 'btn',
+                                               'click': UI.prototype.createHandlerFn(this, 'handleDownload', entrypath, list[i])
+                                       }, [ _('Download') ]) : '',
                                        this.options.enable_remove ? E('button', {
                                                'class': 'btn cbi-button-negative',
                                                'click': UI.prototype.createHandlerFn(this, 'handleDelete', entrypath, list[i])
@@ -2994,6 +3002,22 @@ var UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */ {
                this.handleCancel(ev);
        },
 
+       /** @private */
+       handleDownload: function(path, fileStat, ev) {
+               fs.read_direct(path, 'blob').then(function (blob) {
+                       var url = window.URL.createObjectURL(blob);
+                       var a = document.createElement('a');
+                       a.style.display = 'none';
+                       a.href = url;
+                       a.download = fileStat.name;
+                       document.body.appendChild(a);
+                       a.click();
+                       window.URL.revokeObjectURL(url);
+               }).catch(function(err) {
+                       alert(_('Download failed: %s').format(err.message));
+               });
+       },
+
        /** @private */
        handleSelect: function(path, fileStat, ev) {
                var browser = dom.parent(ev.target, '.cbi-filebrowser'),