forked from mbk-lab/rui_orig
2
0
Fork 0

Added DownloadFile... functions

This commit is contained in:
anoshenko 2021-11-07 09:43:13 +03:00
parent 79fb34f29f
commit a98d97ea8d
4 changed files with 94 additions and 3 deletions

View File

@ -1327,3 +1327,12 @@ function mediaSetVolume(elementId, volume) {
element.volume = volume element.volume = volume
} }
} }
function startDowndload(url, filename) {
var element = document.getElementById("ruiDownloader");
if (element) {
element.href = url;
element.setAttribute("download", filename);
element.click();
}
}

View File

@ -1,15 +1,19 @@
package rui package rui
import ( import (
"bytes"
_ "embed" _ "embed"
"fmt" "fmt"
"io" "io"
"log" "log"
"math/rand" "math/rand"
"net/http" "net/http"
"os"
"os/exec" "os/exec"
"path/filepath"
"runtime" "runtime"
"strconv" "strconv"
"time"
) )
//go:embed app_scripts.js //go:embed app_scripts.js
@ -67,6 +71,7 @@ func (app *application) getStartPage() string {
<body> <body>
<div class="ruiRoot" id="ruiRootView"></div> <div class="ruiRoot" id="ruiRootView"></div>
<div class="ruiPopupLayer" id="ruiPopupLayer" style="visibility: hidden;" onclick="clickOutsidePopup(event)"></div> <div class="ruiPopupLayer" id="ruiPopupLayer" style="visibility: hidden;" onclick="clickOutsidePopup(event)"></div>
<a id="ruiDownloader" download style="display: none;"></a>
</body> </body>
</html>`) </html>`)
@ -129,7 +134,8 @@ func (app *application) ServeHTTP(w http.ResponseWriter, req *http.Request) {
filename = filename[:size-1] filename = filename[:size-1]
} }
if !serveResourceFile(filename, w, req) { if !serveResourceFile(filename, w, req) &&
!serveDownloadFile(filename, w, req) {
w.WriteHeader(http.StatusNotFound) w.WriteHeader(http.StatusNotFound)
} }
} }
@ -295,3 +301,62 @@ func OpenBrowser(url string) bool {
return err != nil return err != nil
} }
type downloadFile struct {
filename string
path string
data []byte
}
var currentDownloadId = int(rand.Int31())
var downloadFiles = map[string]downloadFile{}
func (session *sessionData) startDownload(file downloadFile) {
currentDownloadId++
id := strconv.Itoa(currentDownloadId)
downloadFiles[id] = file
session.runScript(fmt.Sprintf(`startDowndload("%s", "%s")`, id, file.filename))
}
func serveDownloadFile(id string, w http.ResponseWriter, r *http.Request) bool {
if file, ok := downloadFiles[id]; ok {
delete(downloadFiles, id)
if file.data != nil {
http.ServeContent(w, r, file.filename, time.Now(), bytes.NewReader(file.data))
return true
} else if _, err := os.Stat(file.path); err == nil {
http.ServeFile(w, r, file.path)
return true
}
}
return false
}
// DownloadFile starts downloading the file on the client side.
func (session *sessionData) DownloadFile(path string) {
if _, err := os.Stat(path); err != nil {
ErrorLog(err.Error())
return
}
_, filename := filepath.Split(path)
session.startDownload(downloadFile{
filename: filename,
path: path,
data: nil,
})
}
// DownloadFileData starts downloading the file on the client side. Arguments specify the name of the downloaded file and its contents
func (session *sessionData) DownloadFileData(filename string, data []byte) {
if data == nil {
ErrorLog("Invalid download data. Must be not nil.")
return
}
session.startDownload(downloadFile{
filename: filename,
path: "",
data: data,
})
}

View File

@ -6,18 +6,24 @@ import (
const filePickerDemoText = ` const filePickerDemoText = `
GridLayout { GridLayout {
width = 100%, height = 100%, cell-height = "auto, 1fr", width = 100%, height = 100%, cell-height = "auto, 1fr", cell-width = "1fr, auto",
content = [ content = [
FilePicker { FilePicker {
id = filePicker, accept = "txt, html" id = filePicker, accept = "txt, html"
}, },
Button {
id = fileDownload, row = 0, column = 1, content = "Download file", disabled = true,
}
EditView { EditView {
id = selectedFileData, row = 1, type = multiline, read-only = true, wrap = true, id = selectedFileData, row = 1, column = 0:1, type = multiline, read-only = true, wrap = true,
} }
] ]
} }
` `
var downloadedFile []byte = nil
var downloadedFilename = ""
func createFilePickerDemo(session rui.Session) rui.View { func createFilePickerDemo(session rui.Session) rui.View {
view := rui.CreateViewFromText(session, filePickerDemoText) view := rui.CreateViewFromText(session, filePickerDemoText)
if view == nil { if view == nil {
@ -28,12 +34,20 @@ func createFilePickerDemo(session rui.Session) rui.View {
if len(files) > 0 { if len(files) > 0 {
picker.LoadFile(files[0], func(file rui.FileInfo, data []byte) { picker.LoadFile(files[0], func(file rui.FileInfo, data []byte) {
if data != nil { if data != nil {
downloadedFile = data
downloadedFilename = files[0].Name
rui.Set(view, "selectedFileData", rui.Text, string(data)) rui.Set(view, "selectedFileData", rui.Text, string(data))
rui.Set(view, "fileDownload", rui.Disabled, false)
} else { } else {
rui.Set(view, "selectedFileData", rui.Text, rui.LastError()) rui.Set(view, "selectedFileData", rui.Text, rui.LastError())
} }
}) })
} }
}) })
rui.Set(view, "fileDownload", rui.ClickEvent, func() {
view.Session().DownloadFileData(downloadedFilename, downloadedFile)
})
return view return view
} }

View File

@ -53,6 +53,9 @@ type Session interface {
// a description of the error is written to the log // a description of the error is written to the log
Set(viewID, tag string, value interface{}) bool Set(viewID, tag string, value interface{}) bool
DownloadFile(path string)
DownloadFileData(filename string, data []byte)
registerAnimation(props []AnimatedProperty) string registerAnimation(props []AnimatedProperty) string
resolveConstants(value string) (string, bool) resolveConstants(value string) (string, bool)