mirror of https://github.com/anoshenko/rui.git
Added DownloadFile... functions
This commit is contained in:
parent
79fb34f29f
commit
a98d97ea8d
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue