Compare commits

...

66 Commits

Author SHA1 Message Date
Travis McLane
ddcaf58a90 runtime.Store => wails.Store 2020-09-04 13:02:11 -05:00
Lea Anthony
f851b89350 v1.7.2-pre5 2020-09-04 20:23:26 +10:00
Lea Anthony
7f72189231 updates 2020-09-04 20:20:21 +10:00
Lea Anthony
ef79dd95cf Merge branch 'sync-store' into develop 2020-09-04 20:19:20 +10:00
Lea Anthony
d49b146eaa Add mutex to store 2020-09-04 20:08:31 +10:00
Lea Anthony
8c051e004d Release v1.7.2-pre4 2020-09-03 20:13:55 +10:00
Lea Anthony
c02b9ac032 Update contributors 2020-09-03 20:12:57 +10:00
Dmitry
35f839ae65 Support Ctlos Linux 2020-09-03 20:11:39 +10:00
Lea Anthony
8a6c44963d Upgrade packages for js runtime 2020-09-02 08:51:21 +10:00
Lea Anthony
d31c5522e9 fix: revert location of wails config 2020-09-02 07:07:12 +10:00
Lea Anthony
6e5b2ce871 Update Contributors 2020-09-01 20:44:50 +10:00
Tim Kipp
c2c9c331cd refactor: attempt to refactor spacing issues detected by houndci 2020-09-01 20:43:20 +10:00
Tim Kipp
9d5280d4d6 feat(templates): updated react template to latest CRA implementation 2020-09-01 20:43:20 +10:00
Lea Anthony
0474f15c05 Simplify Store type conversions 2020-09-01 20:36:18 +10:00
Lea Anthony
ba0af0c16d Lint fix! 2020-08-31 21:17:04 +10:00
Lea Anthony
c9f1247284 Updated to use specialised update fuctions 2020-08-31 21:10:32 +10:00
Lea Anthony
baa661532d Now using reflection
Update() can now take specialised functions
2020-08-31 21:10:20 +10:00
Lea Anthony
43a5f410d9 Major updates
Automatic type conversion
Support struct data
Custom error handler
2020-08-31 20:00:39 +10:00
Lea Anthony
0ab6a93e0c Update runtime defs
Use runtime.Store instead of wails.Store
2020-08-30 16:07:53 +10:00
Lea Anthony
485df87560 Update vanilla template 2020-08-30 15:49:37 +10:00
Lea Anthony
176c447e87 Update to latest assets 2020-08-30 15:49:29 +10:00
Lea Anthony
aa9cb5e58e Add store to js runtime 2020-08-30 15:49:12 +10:00
Lea Anthony
9a7be38462 Update WailsInit checker 2020-08-30 15:47:32 +10:00
Lea Anthony
678c2194db Add Sync Store 2020-08-30 15:46:50 +10:00
Lea Anthony
9f9c9e27de Move runtime out to package 2020-08-30 15:46:31 +10:00
Lea Anthony
01a1288364 Merge branch 'develop' of github.com:wailsapp/wails into develop 2020-08-23 09:50:58 +10:00
Lea Anthony
5cd34e07b9 Release v1.7.2-pre3 2020-08-23 09:50:16 +10:00
Lea Anthony
2290f36939 Allow customising of info.plist 2020-08-23 09:49:54 +10:00
Lea Anthony
670986df5b Lintastic update 2020-08-21 23:44:22 +10:00
Lea Anthony
086cd02cd4 Lint fix 2020-08-21 23:44:22 +10:00
Lea Anthony
d8c8dd57fa Add artem to Contributors 2020-08-21 23:44:22 +10:00
Lea Anthony
2d158d449a Use double encoding for notify data 2020-08-21 23:44:22 +10:00
Lea Anthony
04577c242b Updated contributors 2020-08-04 05:06:50 +10:00
Zámbó Levente
ac0d4493d3 fix(bridge): fixed long message emit issue #469 2020-08-04 05:06:43 +10:00
Lea Anthony
b123156331 v1.7.2-pre2 2020-07-27 21:13:46 +10:00
Lea Anthony
23468ce7c7 Don't clean up windows files 2020-07-27 21:10:32 +10:00
Lea Anthony
7b6bb5e259 Update Contributors 2020-07-16 19:41:41 +10:00
konez2k
77bd34d601 refactor: use proper user config directory
replace os.UserHomeDir with os.UserConfigDir which manages properly the config folder based on platform.
2020-07-13 20:00:59 +10:00
konez2k
d750077a90 Update minimum go version to 1.13 2020-07-13 20:00:59 +10:00
konez2k
71df64087b refactor homedir to stdlib os.UserHomeDir (go1.12)
- remove mitchellh/go-homedir dependency
2020-07-13 20:00:59 +10:00
Lea Anthony
5565f8ba94 v1.7.1 2020-07-03 20:05:01 +10:00
Lea Anthony
3bc91f20c5 Fix contributors 2020-07-03 13:54:02 +10:00
Lea Anthony
0a15cbaa1d v1.7.0-pre2 2020-07-03 13:52:51 +10:00
Lea Anthony
c650671265 fix: vanilla template for windows 2020-07-03 13:48:27 +10:00
Lea Anthony
7106c338df fix: windows icon name 2020-07-03 06:05:47 +10:00
Lea Anthony
be2cef4a63 free filter memory 2020-06-29 06:41:24 +10:00
Lea Anthony
ee93f3c1e6 v1.7.0-pre1 2020-06-22 20:14:10 +10:00
Lea Anthony
b9ffe53732 Add ldflags option to build 2020-06-22 20:13:15 +10:00
Lea Anthony
bbc16fe03a Lint fixes 2020-06-19 09:38:01 +10:00
Lea Anthony
bdfc3ca631 Release v1.6.0 2020-06-19 09:26:19 +10:00
Lea Anthony
490d66cf77 Update Contributors 2020-06-19 09:11:34 +10:00
Lea Anthony
bce686d779 lint fixes 2020-06-19 08:52:44 +10:00
Lea Anthony
c0b0ef0200 Initial implementation of vanilla template 2020-06-19 08:52:44 +10:00
Florian
8e869baed7 fix: trim whitespaces from filters 2020-06-18 20:25:40 +10:00
Florian Didron
7522428d5c feat: add dialog filter for Cocoa 2020-06-18 20:25:40 +10:00
Florian Didron
bc570999e8 feat: file dialog filters for win32 2020-06-18 20:25:40 +10:00
Florian
393a4fceb2 feat: adds file filtering to gtk select/save dialogs 2020-06-16 18:57:25 +10:00
Lea Anthony
da20bcc8d2 v1.6.0-pre6 2020-06-06 14:42:59 +10:00
Lea Anthony
b091baa16f fix: Project options getting overwritten 2020-06-06 14:42:59 +10:00
Lea Anthony
ecaaafa9d9 v1.6.0-pre5 2020-05-27 12:49:14 +10:00
Lea Anthony
0009da9585 fix: ignore case of linux distro id 2020-05-27 12:48:28 +10:00
Lea Anthony
6235e83677 v1.6.0-pre4 2020-05-27 10:38:40 +10:00
Lea Anthony
9f93e7d979 fix default libs identifier for solus 2020-05-27 10:35:42 +10:00
Lea Anthony
949bc40317 Fix package detection for solus 2020-05-27 10:35:42 +10:00
Lea Anthony
81777f29d8 update package names 2020-05-27 10:35:42 +10:00
Lea Anthony
5d35dd3105 Initial support for solus 2020-05-27 10:35:42 +10:00
63 changed files with 4465 additions and 4169 deletions

View File

@@ -13,10 +13,10 @@ jobs:
os: [ubuntu-latest, windows-latest, macOS-latest] os: [ubuntu-latest, windows-latest, macOS-latest]
steps: steps:
- name: Set up Go 1.12 - name: Set up Go 1.13
uses: actions/setup-go@v1 uses: actions/setup-go@v1
with: with:
go-version: 1.12 go-version: 1.13
id: go id: go
- name: Check out code into the Go module directory - name: Check out code into the Go module directory
@@ -27,6 +27,6 @@ jobs:
go get -v -d ./... go get -v -d ./...
- name: Build - name: Build
run: go build -v ./cmd/wails run: go build -v ./cmd/wails
- name: Test - name: Test
run: ./wails version run: ./wails version

View File

@@ -13,10 +13,10 @@ jobs:
os: [ubuntu-latest, windows-latest, macOS-latest] os: [ubuntu-latest, windows-latest, macOS-latest]
steps: steps:
- name: Set up Go 1.12 - name: Set up Go 1.13
uses: actions/setup-go@v1 uses: actions/setup-go@v1
with: with:
go-version: 1.12 go-version: 1.13
id: go id: go
- name: Check out code into the Go module directory - name: Check out code into the Go module directory
@@ -27,6 +27,6 @@ jobs:
go get -v -d ./... go get -v -d ./...
- name: Build - name: Build
run: go build -v ./cmd/wails run: go build -v ./cmd/wails
- name: Test - name: Test
run: ./wails version run: ./wails version

View File

@@ -4,7 +4,7 @@ on:
branches: branches:
- master - master
tags: tags:
- '!**pre**' - '!**pre**'
jobs: jobs:
build: build:
@@ -15,10 +15,10 @@ jobs:
os: [ubuntu-latest, windows-latest, macOS-latest] os: [ubuntu-latest, windows-latest, macOS-latest]
steps: steps:
- name: Set up Go 1.12 - name: Set up Go 1.13
uses: actions/setup-go@v1 uses: actions/setup-go@v1
with: with:
go-version: 1.12 go-version: 1.13
id: go id: go
- name: Check out code into the Go module directory - name: Check out code into the Go module directory
@@ -29,6 +29,6 @@ jobs:
go get -v -d ./... go get -v -d ./...
- name: Build - name: Build
run: go build -v ./cmd/wails run: go build -v ./cmd/wails
- name: Test - name: Test
run: ./wails version run: ./wails version

View File

@@ -15,7 +15,6 @@ Wails is what it is because of the time and effort given by these great people.
* [admin_3.exe](https://github.com/bh90210) * [admin_3.exe](https://github.com/bh90210)
* [iceleo-com](https://github.com/iceleo-com) * [iceleo-com](https://github.com/iceleo-com)
* [fallendusk](https://github.com/fallendusk) * [fallendusk](https://github.com/fallendusk)
* [Florian Didran](https://github.com/fdidron)
* [Nikolai Zimmermann](https://github.com/Chronophylos) * [Nikolai Zimmermann](https://github.com/Chronophylos)
* [Toyam Cox](https://github.com/Vaelatern) * [Toyam Cox](https://github.com/Vaelatern)
* [Robin Eklind](https://github.com/mewmew) * [Robin Eklind](https://github.com/mewmew)
@@ -28,3 +27,9 @@ Wails is what it is because of the time and effort given by these great people.
* [Konez2k](https://github.com/konez2k) * [Konez2k](https://github.com/konez2k)
* [msms](https://github.com/sayuthisobri) * [msms](https://github.com/sayuthisobri)
* [dedo1911](https://github.com/dedo1911) * [dedo1911](https://github.com/dedo1911)
* [Florian Didron](https://github.com/fdidron)
* [Christopher Murphy](https://github.com/Splode)
* [Zámbó, Levente](https://github.com/Lyimmi)
* [artem](https://github.com/Unix4ever)
* [Tim Kipp](https://github.com/timkippdev)
* [Dmitry Gomzyakov](https://github.com/kyoto44)

View File

@@ -36,7 +36,7 @@ The official docs can be found at [https://wails.app](https://wails.app).
Wails uses cgo to bind to the native rendering engines so a number of platform dependent libraries are needed as well as an installation of Go. The basic requirements are: Wails uses cgo to bind to the native rendering engines so a number of platform dependent libraries are needed as well as an installation of Go. The basic requirements are:
- Go 1.12 - Go 1.13
- npm - npm
### MacOS ### MacOS
@@ -57,7 +57,7 @@ _Ubuntu: 16.04, 18.04, 19.04_
_Also succesfully tested on: Zorin 15, Parrot 4.7, Linuxmint 19, Elementary 5, Kali, Neon_, Pop!_OS _Also succesfully tested on: Zorin 15, Parrot 4.7, Linuxmint 19, Elementary 5, Kali, Neon_, Pop!_OS
#### Arch Linux / ArchLabs #### Arch Linux / ArchLabs / Ctlos Linux
`sudo pacman -S webkit2gtk gtk3` `sudo pacman -S webkit2gtk gtk3`

13
app.go
View File

@@ -13,6 +13,7 @@ import (
"github.com/wailsapp/wails/lib/ipc" "github.com/wailsapp/wails/lib/ipc"
"github.com/wailsapp/wails/lib/logger" "github.com/wailsapp/wails/lib/logger"
"github.com/wailsapp/wails/lib/renderer" "github.com/wailsapp/wails/lib/renderer"
wailsruntime "github.com/wailsapp/wails/runtime"
) )
// -------------------------------- Compile time Flags ------------------------------ // -------------------------------- Compile time Flags ------------------------------
@@ -20,6 +21,16 @@ import (
// BuildMode indicates what mode we are in // BuildMode indicates what mode we are in
var BuildMode = cmd.BuildModeProd var BuildMode = cmd.BuildModeProd
// Runtime is the Go Runtime struct
type Runtime = wailsruntime.Runtime
// Store is a state store used for syncing with
// the front end
type Store = wailsruntime.Store
// CustomLogger is a specialised logger
type CustomLogger = logger.CustomLogger
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
// App defines the main application struct // App defines the main application struct
@@ -125,7 +136,7 @@ func (a *App) start() error {
a.ipc.Start(a.eventManager, a.bindingManager) a.ipc.Start(a.eventManager, a.bindingManager)
// Create the runtime // Create the runtime
a.runtime = NewRuntime(a.eventManager, a.renderer) a.runtime = wailsruntime.NewRuntime(a.eventManager, a.renderer)
// Start binding manager and give it our renderer // Start binding manager and give it our renderer
err = a.bindingManager.Start(a.renderer, a.runtime) err = a.bindingManager.Start(a.renderer, a.runtime)

File diff suppressed because one or more lines are too long

View File

@@ -293,9 +293,11 @@ func BuildApplication(binaryName string, forceRebuild bool, buildMode string, pa
fmt.Println(err) fmt.Println(err)
} }
} }
if projectOptions.Platform == "windows" { // Removed by popular demand
helper.CleanWindows(projectOptions) // TODO: Potentially add a flag to cleanup
} // if projectOptions.Platform == "windows" {
// helper.CleanWindows(projectOptions)
// }
}() }()
if projectOptions.CrossCompile { if projectOptions.CrossCompile {
@@ -561,6 +563,11 @@ func ldFlags(po *ProjectOptions, buildMode string) string {
ldflags += "-X github.com/wailsapp/wails.BuildMode=" + buildMode ldflags += "-X github.com/wailsapp/wails.BuildMode=" + buildMode
// Add additional ldflags passed in via the `ldflags` cli flag
if len(po.LdFlags) > 0 {
ldflags += " " + po.LdFlags
}
// If we wish to generate typescript // If we wish to generate typescript
if po.typescriptDefsFilename != "" { if po.typescriptDefsFilename != "" {
cwd, err := os.Getwd() cwd, err := os.Getwd()

View File

@@ -61,6 +61,10 @@ const (
ArchLabs ArchLabs
// PopOS distribution // PopOS distribution
PopOS PopOS
// Solus distribution
Solus
// Ctlos Linux distribution
Ctlos
) )
// DistroInfo contains all the information relating to a linux distribution // DistroInfo contains all the information relating to a linux distribution
@@ -109,7 +113,7 @@ func parseOsRelease(osRelease string) *DistroInfo {
} }
switch splitLine[0] { switch splitLine[0] {
case "ID": case "ID":
osID = strings.Trim(splitLine[1], "\"") osID = strings.ToLower(strings.Trim(splitLine[1], "\""))
case "NAME": case "NAME":
osNAME = strings.Trim(splitLine[1], "\"") osNAME = strings.Trim(splitLine[1], "\"")
case "VERSION_ID": case "VERSION_ID":
@@ -118,7 +122,7 @@ func parseOsRelease(osRelease string) *DistroInfo {
} }
// Check distro name against list of distros // Check distro name against list of distros
switch strings.ToLower(osID) { switch osID {
case "fedora": case "fedora":
result.Distribution = Fedora result.Distribution = Fedora
case "centos": case "centos":
@@ -127,6 +131,8 @@ func parseOsRelease(osRelease string) *DistroInfo {
result.Distribution = Arch result.Distribution = Arch
case "archlabs": case "archlabs":
result.Distribution = ArchLabs result.Distribution = ArchLabs
case "ctlos":
result.Distribution = Ctlos
case "debian": case "debian":
result.Distribution = Debian result.Distribution = Debian
case "ubuntu": case "ubuntu":
@@ -163,6 +169,8 @@ func parseOsRelease(osRelease string) *DistroInfo {
result.Distribution = Leap result.Distribution = Leap
case "pop": case "pop":
result.Distribution = PopOS result.Distribution = PopOS
case "solus":
result.Distribution = Solus
default: default:
result.Distribution = Unknown result.Distribution = Unknown
} }
@@ -199,6 +207,17 @@ func DpkgInstalled(packageName string) (bool, error) {
return exitCode == 0, nil return exitCode == 0, nil
} }
// EOpkgInstalled uses dpkg to see if a package is installed
func EOpkgInstalled(packageName string) (bool, error) {
program := NewProgramHelper()
eopkg := program.FindProgram("eopkg")
if eopkg == nil {
return false, fmt.Errorf("cannot check dependencies: eopkg not found")
}
stdout, _, _, _ := eopkg.Run("info", packageName)
return strings.HasPrefix(stdout, "Installed"), nil
}
// PacmanInstalled uses pacman to see if a package is installed. // PacmanInstalled uses pacman to see if a package is installed.
func PacmanInstalled(packageName string) (bool, error) { func PacmanInstalled(packageName string) (bool, error) {
program := NewProgramHelper() program := NewProgramHelper()

View File

@@ -193,7 +193,16 @@ distributions:
name: ArchLabs name: ArchLabs
gccversioncommand: *gccdumpversion gccversioncommand: *gccdumpversion
programs: *archdefaultprograms programs: *archdefaultprograms
libraries: *archdefaultlibraries libraries: *archdefaultlibraries
ctlos:
id: ctlos
releases:
default:
version: default
name: Ctlos Linux
gccversioncommand: *gccdumpversion
programs: *archdefaultprograms
libraries: *archdefaultlibraries
manjaro: manjaro:
id: manjaro id: manjaro
releases: releases:
@@ -241,6 +250,25 @@ distributions:
gccversioncommand: *gccdumpfullversion gccversioncommand: *gccdumpfullversion
programs: *debiandefaultprograms programs: *debiandefaultprograms
libraries: *debiandefaultlibraries libraries: *debiandefaultlibraries
solus:
id: solus
releases:
default:
version: default
name: Solus
gccversioncommand: *gccdumpfullversion
programs: &solusdefaultprograms
- name: gcc
help: Please install with `sudo eopkg it -c system.devel` and try again
- name: pkg-config
help: Please install with `sudo eopkg it -c system.devel` and try again
- name: npm
help: Please install with `sudo eopkg it nodejs` and try again
libraries: &solusdefaultlibraries
- name: libgtk-3-devel
help: Please install with `sudo eopkg it libgtk-3-devel` and try again
- name: libwebkit-gtk-devel
help: Please install with `sudo eopkg it libwebkit-gtk-devel` and try again
opensuse-tumbleweed: opensuse-tumbleweed:
id: opensuse-tumbleweed id: opensuse-tumbleweed

View File

@@ -212,6 +212,8 @@ func (b *PackageHelper) packageOSX(po *ProjectOptions) error {
packageID := strings.Join([]string{"wails", name, version}, ".") packageID := strings.Join([]string{"wails", name, version}, ".")
plistData := newPlistData(name, exe, packageID, version, author) plistData := newPlistData(name, exe, packageID, version, author)
appname := po.Name + ".app" appname := po.Name + ".app"
plistFilename := path.Join(build, appname, "Contents", "Info.plist")
customPlist := path.Join(b.fs.Cwd(), "info.plist")
// Check binary exists // Check binary exists
source := path.Join(build, exe) source := path.Join(build, exe)
@@ -230,28 +232,48 @@ func (b *PackageHelper) packageOSX(po *ProjectOptions) error {
// Remove the existing package // Remove the existing package
os.RemoveAll(appname) os.RemoveAll(appname)
// Create directories
exeDir := path.Join(build, appname, "/Contents/MacOS") exeDir := path.Join(build, appname, "/Contents/MacOS")
b.fs.MkDirs(exeDir, 0755) b.fs.MkDirs(exeDir, 0755)
resourceDir := path.Join(build, appname, "/Contents/Resources") resourceDir := path.Join(build, appname, "/Contents/Resources")
b.fs.MkDirs(resourceDir, 0755) b.fs.MkDirs(resourceDir, 0755)
tmpl := template.New("infoPlist")
plistFile := filepath.Join(b.getPackageFileBaseDir(), "info.plist")
infoPlist, err := ioutil.ReadFile(plistFile)
if err != nil {
return err
}
tmpl.Parse(string(infoPlist))
// Write the template to a buffer // Do we have a custom plist in the project directory?
var tpl bytes.Buffer if !fs.FileExists(customPlist) {
err = tmpl.Execute(&tpl, plistData)
if err != nil { // No - create a new plist from our defaults
return err tmpl := template.New("infoPlist")
} plistFile := filepath.Join(b.getPackageFileBaseDir(), "info.plist")
filename := path.Join(build, appname, "Contents", "Info.plist") infoPlist, err := ioutil.ReadFile(plistFile)
err = ioutil.WriteFile(filename, tpl.Bytes(), 0644) if err != nil {
if err != nil { return err
return err }
tmpl.Parse(string(infoPlist))
// Write the template to a buffer
var tpl bytes.Buffer
err = tmpl.Execute(&tpl, plistData)
if err != nil {
return err
}
// Save to the package
err = ioutil.WriteFile(plistFilename, tpl.Bytes(), 0644)
if err != nil {
return err
}
// Also write to project directory for customisation
err = ioutil.WriteFile(customPlist, tpl.Bytes(), 0644)
if err != nil {
return err
}
} else {
// Yes - we have a plist. Copy it to the package verbatim
err = fs.CopyFile(customPlist, plistFilename)
if err != nil {
return err
}
} }
// Copy executable // Copy executable
@@ -293,7 +315,7 @@ func (b *PackageHelper) PackageWindows(po *ProjectOptions, cleanUp bool) error {
} }
// Generate icon from PNG // Generate icon from PNG
err = generateWindowsIcon(icon, po.BinaryName+".ico") err = generateWindowsIcon(icon, basename+".ico")
if err != nil { if err != nil {
return err return err
} }

View File

@@ -161,6 +161,7 @@ type ProjectOptions struct {
CrossCompile bool CrossCompile bool
Platform string Platform string
Architecture string Architecture string
LdFlags string
} }
// Defaults sets the default project template // Defaults sets the default project template

View File

@@ -5,12 +5,11 @@ import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"log" "log"
"os"
"path/filepath" "path/filepath"
"runtime" "runtime"
"strconv" "strconv"
"time" "time"
homedir "github.com/mitchellh/go-homedir"
) )
// SystemHelper - Defines everything related to the system // SystemHelper - Defines everything related to the system
@@ -38,10 +37,11 @@ func NewSystemHelper() *SystemHelper {
// setSystemDirs calculates the system directories it is interested in // setSystemDirs calculates the system directories it is interested in
func (s *SystemHelper) setSystemDirs() { func (s *SystemHelper) setSystemDirs() {
var err error var err error
s.homeDir, err = homedir.Dir() s.homeDir, err = os.UserHomeDir()
if err != nil { if err != nil {
log.Fatal("Cannot find home directory! Please file a bug report!") log.Fatal("Cannot find home directory! Please file a bug report!")
} }
// TODO: A better config system // TODO: A better config system
s.wailsSystemDir = filepath.Join(s.homeDir, ".wails") s.wailsSystemDir = filepath.Join(s.homeDir, ".wails")
s.wailsSystemConfig = filepath.Join(s.wailsSystemDir, s.configFilename) s.wailsSystemConfig = filepath.Join(s.wailsSystemDir, s.configFilename)
@@ -132,7 +132,7 @@ func (s *SystemHelper) setup() error {
} }
const introText = ` const introText = `
Wails is a lightweight framework for creating web-like desktop apps in Go. Wails is a lightweight framework for creating web-like desktop apps in Go.
I'll need to ask you a few questions so I can fill in your project templates and then I will try and see if you have the correct dependencies installed. If you don't have the right tools installed, I'll try and suggest how to install them. I'll need to ask you a few questions so I can fill in your project templates and then I will try and see if you have the correct dependencies installed. If you don't have the right tools installed, I'll try and suggest how to install them.
` `
@@ -276,7 +276,7 @@ func CheckDependencies(logger *Logger) (bool, error) {
switch distroInfo.Distribution { switch distroInfo.Distribution {
case Ubuntu, Debian, Zorin, Parrot, Linuxmint, Elementary, Kali, Neon, Deepin, Raspbian, PopOS: case Ubuntu, Debian, Zorin, Parrot, Linuxmint, Elementary, Kali, Neon, Deepin, Raspbian, PopOS:
libraryChecker = DpkgInstalled libraryChecker = DpkgInstalled
case Arch, ArcoLinux, ArchLabs, Manjaro, ManjaroARM: case Arch, ArcoLinux, ArchLabs, Ctlos, Manjaro, ManjaroARM:
libraryChecker = PacmanInstalled libraryChecker = PacmanInstalled
case CentOS, Fedora, Tumbleweed, Leap: case CentOS, Fedora, Tumbleweed, Leap:
libraryChecker = RpmInstalled libraryChecker = RpmInstalled
@@ -284,6 +284,8 @@ func CheckDependencies(logger *Logger) (bool, error) {
libraryChecker = EqueryInstalled libraryChecker = EqueryInstalled
case VoidLinux: case VoidLinux:
libraryChecker = XbpsInstalled libraryChecker = XbpsInstalled
case Solus:
libraryChecker = EOpkgInstalled
default: default:
return false, RequestSupportForDistribution(distroInfo) return false, RequestSupportForDistribution(distroInfo)
} }

View File

@@ -5,8 +5,8 @@
"private": true, "private": true,
"dependencies": { "dependencies": {
"core-js": "^3.6.4", "core-js": "^3.6.4",
"react": "^16.13.0", "react": "^16.13.1",
"react-dom": "^16.13.0", "react-dom": "^16.13.1",
"wails-react-scripts": "3.0.1-2", "wails-react-scripts": "3.0.1-2",
"react-modal": "3.11.2", "react-modal": "3.11.2",
"@wailsapp/runtime": "^1.0.10" "@wailsapp/runtime": "^1.0.10"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -1,10 +1,13 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head>
<head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" /> <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" /> <meta name="theme-color" content="#000000" />
<meta name="description" content="Web site created using create-react-app" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!-- <!--
manifest.json provides metadata used when your web app is installed on a manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
@@ -20,8 +23,9 @@
Learn how to configure a non-root public URL by running `npm run build`. Learn how to configure a non-root public URL by running `npm run build`.
--> -->
<title>React App</title> <title>React App</title>
</head> </head>
<body>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>
<div id="app"></div> <div id="app"></div>
<!-- <!--
@@ -34,5 +38,6 @@
To begin the development, run `npm start` or `yarn start`. To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`. To create a production bundle, use `npm run build` or `yarn build`.
--> -->
</body> </body>
</html>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

View File

@@ -6,6 +6,16 @@
"src": "favicon.ico", "src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16", "sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon" "type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
} }
], ],
"start_url": ".", "start_url": ".",

View File

@@ -0,0 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

View File

@@ -3,11 +3,16 @@
} }
.App-logo { .App-logo {
animation: App-logo-spin infinite 20s linear;
height: 40vmin; height: 40vmin;
pointer-events: none; pointer-events: none;
} }
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header { .App-header {
background-color: #282c34; background-color: #282c34;
min-height: 100vh; min-height: 100vh;

View File

@@ -1,48 +1,35 @@
import React from 'react'; import React, { useState } from 'react';
import Modal from 'react-modal'; import Modal from 'react-modal';
class HelloWorld extends React.Component { function HelloWorld() {
constructor(props, context) { const [showModal, setShowModal] = useState(false);
super(); const [result, setResult] = useState(null);
this.state = {
showModal: false
};
this.handleOpenModal = this.handleOpenModal.bind(this); const handleOpenModal = () => {
this.handleCloseModal = this.handleCloseModal.bind(this); setShowModal(true);
}
handleOpenModal () { window.backend.basic().then((result) => setResult(result));
this.setState({ showModal: true }); };
window.backend.basic().then(result => const handleCloseModal = () => {
this.setState({ setShowModal(false);
result };
})
);
}
handleCloseModal () { return (
this.setState({ showModal: false }); <div className="App">
} <button onClick={() => handleOpenModal()} type="button">
Hello
render() { </button>
const { result } = this.state; <Modal
return ( appElement={document.getElementById("app")}
<div className="App"> isOpen={showModal}
<button onClick={this.handleOpenModal} type="button"> contentLabel="Minimal Modal Example"
Hello >
</button> <p>{result}</p>
<Modal <button onClick={() => handleCloseModal()}>Close Modal</button>
isOpen={this.state.showModal} </Modal>
contentLabel="Minimal Modal Example" </div>
> );
<p>{result}</p>
<button onClick={this.handleCloseModal}>Close Modal</button>
</Modal>
</div>
);
}
} }
export default HelloWorld; export default HelloWorld;

View File

@@ -3,9 +3,20 @@ import ReactDOM from 'react-dom';
import 'core-js/stable'; import 'core-js/stable';
import './index.css'; import './index.css';
import App from './App'; import App from './App';
import * as serviceWorker from './serviceWorker';
import * as Wails from '@wailsapp/runtime'; import * as Wails from '@wailsapp/runtime';
Wails.Init(() => { Wails.Init(() => {
ReactDOM.render(<App />, document.getElementById('app')); ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById("app")
);
}); });
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

View File

@@ -1,8 +1,8 @@
{ {
"name": "React JS", "name": "React JS",
"version": "1.0.0", "version": "1.0.0",
"shortdescription": "Create React App v3 template", "shortdescription": "Create React App v4 template",
"description": "Create React App v3 standar tooling", "description": "Create React App v4 standard tooling",
"install": "npm install", "install": "npm install",
"build": "npm run build", "build": "npm run build",
"author": "bh90210 <ktc@pm.me>", "author": "bh90210 <ktc@pm.me>",

View File

@@ -0,0 +1,5 @@
# README
This is an experimental template for vanilla HTML/JS/CSS.
The webpack rules may need to be adjusted to correctly embed all assets. Babel may also need to be setup correctly.

View File

@@ -0,0 +1,46 @@
package main
import (
"math/rand"
"github.com/wailsapp/wails"
)
// Counter is what we use for counting
type Counter struct {
r *wails.Runtime
store *wails.Store
}
// WailsInit is called when the component is being initialised
func (c *Counter) WailsInit(runtime *wails.Runtime) error {
c.r = runtime
c.store = runtime.Store.New("Counter", 0)
return nil
}
// RandomValue sets the counter to a random value
func (c *Counter) RandomValue() {
c.store.Set(rand.Intn(1000))
}
// Increment will increment the counter
func (c *Counter) Increment() {
increment := func(data int) int {
return data + 1
}
// Update the store using the increment function
c.store.Update(increment)
}
// Decrement will decrement the counter
func (c *Counter) Decrement() {
decrement := func(data int) int {
return data - 1
}
// Update the store using the decrement function
c.store.Update(decrement)
}

View File

@@ -0,0 +1,42 @@
{
"name": "vanilla",
"author": "Lea<l>",
"private": true,
"scripts": {
"serve": "webpack-dev-server",
"build": "npx webpack"
},
"dependencies": {
"core-js": "^3.6.4",
"regenerator-runtime": "^0.13.3",
"@wailsapp/runtime": "^1.0.10"
},
"devDependencies": {
"babel-eslint": "^10.1.0",
"copy-webpack-plugin": "^6.0.2",
"eslint": "^6.8.0",
"eventsource-polyfill": "^0.9.6",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.11",
"webpack-dev-server": "^3.11.0",
"webpack-hot-middleware": "^2.25.0"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"eslint:recommended"
],
"rules": {},
"parserOptions": {
"parser": "babel-eslint"
}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
]
}

View File

@@ -0,0 +1,9 @@
<html>
<head>
<link rel="stylesheet" type="text/css" href="main.css">
</head>
<body>
<div id="app"></div>
<script src="main.js"></script>
</body>
</html>

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,47 @@
import 'core-js/stable';
const runtime = require('@wailsapp/runtime');
// Main entry point
function start() {
var mystore = wails.Store.New('Counter');
// Ensure the default app div is 100% wide/high
var app = document.getElementById('app');
app.style.width = '100%';
app.style.height = '100%';
// Inject html
app.innerHTML = `
<div class='logo'></div>
<div class='container'>
<button onClick='window.backend.Counter.Increment()'>
Increment Counter
</button>
<button onClick='window.backend.Counter.Decrement()'>
Decrement Counter
</button>
</div>
<div class='result'>Counter: <span id='counter'></span></div>
<div class='container'>
<input id='newCounter' type="number" value="0"/>
<button id='setvalue'>Set Counter Value</button>
<button onclick='window.backend.Counter.RandomValue()'>Set to Random Value</button>
</div>
`;
// Connect counter value button to Go method
document.getElementById('setvalue').onclick = function() {
let newValue = parseInt(document.getElementById('newCounter').value,10);
mystore.set(newValue);
};
mystore.subscribe( (state) => {
document.getElementById('counter').innerText = state;
});
mystore.set(0);
};
// We provide our entrypoint as a callback for runtime.Init
runtime.Init(start);

View File

@@ -0,0 +1,56 @@
const path = require('path');
const CopyWebpackPlugin = require('copy-webpack-plugin');
let imageSizeLimit = 9007199254740991; // Number.MAX_SAFE_INTEGER
let sourceDir = path.resolve(__dirname, 'src');
let buildDir = path.resolve(__dirname, 'build');
module.exports = {
entry: {
index: path.resolve(sourceDir, 'main.js')
},
output: {
path: buildDir,
filename: 'main.js'
},
optimization: {
splitChunks: false
},
devServer: {
disableHostCheck: true,
contentBase: path.join(__dirname, 'src'),
compress: true,
open: true,
port: 8090
},
mode: 'production',
module: {
rules: [
{
test: /\.(png|gif|jpg|woff2?|eot|ttf|otf|svg)(\?.*)?$/i,
use: [
{
loader: 'url-loader',
options: {
limit: imageSizeLimit
}
}
],
}
]
},
plugins: [
new CopyWebpackPlugin({
patterns: [
{
from: path.resolve(sourceDir, 'main.css'),
to: path.resolve(buildDir, 'main.css')
},
{
from: path.resolve(sourceDir, 'index.html'),
to: path.resolve(buildDir, 'index.html')
},
]
})
]
};

View File

@@ -0,0 +1,5 @@
module {{.BinaryName}}
require (
github.com/wailsapp/wails {{.WailsVersion}}
)

View File

@@ -0,0 +1,23 @@
package main
import (
"github.com/leaanthony/mewn"
"github.com/wailsapp/wails"
)
func main() {
js := mewn.String("./frontend/build/main.js")
css := mewn.String("./frontend/build/main.css")
app := wails.CreateApp(&wails.AppConfig{
Width: 1024,
Height: 768,
Title: "{{.Name}}",
JS: js,
CSS: css,
Colour: "#131313",
})
app.Bind(&Counter{})
app.Run()
}

View File

@@ -0,0 +1,12 @@
{
"name": "Vanilla",
"shortdescription": "A Vanilla HTML/JS template",
"description": "A basic template using plain html/js and bundled using Webpack 4",
"author": "Lea Anthony<lea.anthony@gmail.com>",
"created": "2020-06-14",
"frontenddir": "frontend",
"install": "npm install",
"build": "npm run build",
"serve": "npm run serve",
"bridge": "src"
}

View File

@@ -1,4 +1,4 @@
package cmd package cmd
// Version - Wails version // Version - Wails version
const Version = "v1.6.0-pre3" const Version = "v1.7.2-pre5"

View File

@@ -29,6 +29,7 @@ func init() {
var typescriptFilename = "" var typescriptFilename = ""
var verbose = false var verbose = false
var platform = "" var platform = ""
var ldflags = ""
buildSpinner := spinner.NewSpinner() buildSpinner := spinner.NewSpinner()
buildSpinner.SetSpinSpeed(50) buildSpinner.SetSpinSpeed(50)
@@ -40,7 +41,8 @@ func init() {
BoolFlag("f", "Force rebuild of application components", &forceRebuild). BoolFlag("f", "Force rebuild of application components", &forceRebuild).
BoolFlag("d", "Build in Debug mode", &debugMode). BoolFlag("d", "Build in Debug mode", &debugMode).
BoolFlag("verbose", "Verbose output", &verbose). BoolFlag("verbose", "Verbose output", &verbose).
StringFlag("t", "Generate Typescript definitions to given file (at runtime)", &typescriptFilename) StringFlag("t", "Generate Typescript definitions to given file (at runtime)", &typescriptFilename).
StringFlag("ldflags", "Extra options for -ldflags", &ldflags)
var b strings.Builder var b strings.Builder
for _, plat := range getSupportedPlatforms() { for _, plat := range getSupportedPlatforms() {
@@ -84,7 +86,7 @@ func init() {
} }
} }
if !supported { if !supported {
return fmt.Errorf("Unsupported platform '%s' specified.\nPlease run `wails build -h` to see the supported platform/architecture options.", platform) return fmt.Errorf("unsupported platform '%s' specified.\nPlease run `wails build -h` to see the supported platform/architecture options", platform)
} }
projectOptions.CrossCompile = true projectOptions.CrossCompile = true
@@ -93,6 +95,9 @@ func init() {
projectOptions.Architecture = plat[1] projectOptions.Architecture = plat[1]
} }
// Add ldflags
projectOptions.LdFlags = ldflags
// Validate config // Validate config
// Check if we have a frontend // Check if we have a frontend
err = cmd.ValidateFrontendConfig(projectOptions) err = cmd.ValidateFrontendConfig(projectOptions)

View File

@@ -35,8 +35,6 @@ func init() {
// Project options // Project options
projectOptions := &cmd.ProjectOptions{} projectOptions := &cmd.ProjectOptions{}
projectOptions.Verbose = verbose
projectOptions.Platform = runtime.GOOS
// Check we are in project directory // Check we are in project directory
// Check project.json loads correctly // Check project.json loads correctly
@@ -46,6 +44,10 @@ func init() {
return err return err
} }
// Set project options
projectOptions.Verbose = verbose
projectOptions.Platform = runtime.GOOS
// Save project directory // Save project directory
projectDir := fs.Cwd() projectDir := fs.Cwd()

View File

@@ -3,9 +3,9 @@ package main
import ( import (
"fmt" "fmt"
"log" "log"
"os"
"github.com/leaanthony/spinner" "github.com/leaanthony/spinner"
"github.com/mitchellh/go-homedir"
"github.com/wailsapp/wails/cmd" "github.com/wailsapp/wails/cmd"
) )
@@ -146,7 +146,7 @@ func updateToVersion(targetVersion *cmd.SemanticVersion, force bool) error {
updateSpinner.Start("Installing Wails " + desiredVersion) updateSpinner.Start("Installing Wails " + desiredVersion)
// Run command in non module directory // Run command in non module directory
homeDir, err := homedir.Dir() homeDir, err := os.UserHomeDir()
if err != nil { if err != nil {
log.Fatal("Cannot find home directory! Please file a bug report!") log.Fatal("Cannot find home directory! Please file a bug report!")
} }

8
go.mod
View File

@@ -14,20 +14,18 @@ require (
github.com/leaanthony/spinner v0.5.3 github.com/leaanthony/spinner v0.5.3
github.com/mattn/go-colorable v0.1.1 // indirect github.com/mattn/go-colorable v0.1.1 // indirect
github.com/mattn/go-isatty v0.0.7 // indirect github.com/mattn/go-isatty v0.0.7 // indirect
github.com/mitchellh/go-homedir v1.1.0
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4 github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4
github.com/pkg/errors v0.8.1 // indirect github.com/pkg/errors v0.8.1 // indirect
github.com/sirupsen/logrus v1.4.1 github.com/sirupsen/logrus v1.4.1
github.com/stretchr/testify v1.3.0 // indirect github.com/stretchr/testify v1.3.0 // indirect
github.com/syossan27/tebata v0.0.0-20180602121909-b283fe4bc5ba github.com/syossan27/tebata v0.0.0-20180602121909-b283fe4bc5ba
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 // indirect
golang.org/x/image v0.0.0-20200430140353-33d19683fad8 golang.org/x/image v0.0.0-20200430140353-33d19683fad8
golang.org/x/net v0.0.0-20190509222800-a4d6f7feada5 // indirect golang.org/x/net v0.0.0-20200625001655-4c5254603344 // indirect
golang.org/x/sys v0.0.0-20190509141414-a5b02f93d862 golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd
golang.org/x/text v0.3.0 golang.org/x/text v0.3.0
gopkg.in/AlecAivazis/survey.v1 v1.8.4 gopkg.in/AlecAivazis/survey.v1 v1.8.4
gopkg.in/yaml.v3 v3.0.0-20190709130402-674ba3eaed22 gopkg.in/yaml.v3 v3.0.0-20190709130402-674ba3eaed22
) )
go 1.12 go 1.13

14
go.sum
View File

@@ -46,8 +46,6 @@ github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4 h1:49lOXmGaUpV9Fz3gd7TFZY106KVlPVa5jcYD1gaQf98= github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4 h1:49lOXmGaUpV9Fz3gd7TFZY106KVlPVa5jcYD1gaQf98=
@@ -68,21 +66,21 @@ github.com/syossan27/tebata v0.0.0-20180602121909-b283fe4bc5ba h1:2DHfQOxcpWdGf5
github.com/syossan27/tebata v0.0.0-20180602121909-b283fe4bc5ba/go.mod h1:iLnlXG2Pakcii2CU0cbY07DRCSvpWNa7nFxtevhOChk= github.com/syossan27/tebata v0.0.0-20180602121909-b283fe4bc5ba/go.mod h1:iLnlXG2Pakcii2CU0cbY07DRCSvpWNa7nFxtevhOChk=
golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 h1:iMGN4xG0cnqj3t+zOM8wUB0BiPKHEwSxEZCvzcbZuvk= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/image v0.0.0-20200430140353-33d19683fad8 h1:6WW6V3x1P/jokJBpRQYUJnMHRP6isStQwCozxnU7XQw= golang.org/x/image v0.0.0-20200430140353-33d19683fad8 h1:6WW6V3x1P/jokJBpRQYUJnMHRP6isStQwCozxnU7XQw=
golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190509222800-a4d6f7feada5 h1:6M3SDHlHHDCx2PcQw3S4KsR170vGqDhJDOmpVd4Hjak= golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4=
golang.org/x/net v0.0.0-20190509222800-a4d6f7feada5/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/sys v0.0.0-20180606202747-9527bec2660b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180606202747-9527bec2660b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190509141414-a5b02f93d862 h1:rM0ROo5vb9AdYJi1110yjWGMej9ITfKddS89P3Fkhug= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
golang.org/x/sys v0.0.0-20190509141414-a5b02f93d862/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/AlecAivazis/survey.v1 v1.8.4 h1:10xXXN3wgIhPheb5NI58zFgZv32Ana7P3Tl4shW+0Qc= gopkg.in/AlecAivazis/survey.v1 v1.8.4 h1:10xXXN3wgIhPheb5NI58zFgZv32Ana7P3Tl4shW+0Qc=

View File

@@ -196,7 +196,7 @@ func (b *boundMethod) processWailsInit() error {
// It must be *wails.Runtime // It must be *wails.Runtime
inputName := b.inputs[0].String() inputName := b.inputs[0].String()
b.log.Debugf("WailsInit input type: %s", inputName) b.log.Debugf("WailsInit input type: %s", inputName)
if inputName != "*wails.Runtime" { if inputName != "*runtime.Runtime" {
return fmt.Errorf("Invalid WailsInit() definition. Expected input to be wails.Runtime, but got %s", inputName) return fmt.Errorf("Invalid WailsInit() definition. Expected input to be wails.Runtime, but got %s", inputName)
} }
@@ -219,7 +219,7 @@ func (b *boundMethod) processWailsInit() error {
} }
func (b *boundMethod) processWailsShutdown() error { func (b *boundMethod) processWailsShutdown() error {
// We must have only 1 input, it must be *wails.Runtime // We must not have any inputs
if len(b.inputs) != 0 { if len(b.inputs) != 0 {
return fmt.Errorf("Invalid WailsShutdown() definition. Expected 0 inputs, but got %d", len(b.inputs)) return fmt.Errorf("Invalid WailsShutdown() definition. Expected 0 inputs, but got %d", len(b.inputs))
} }

View File

@@ -17,9 +17,9 @@ type Renderer interface {
NotifyEvent(eventData *messages.EventData) error NotifyEvent(eventData *messages.EventData) error
// Dialog Runtime // Dialog Runtime
SelectFile() string SelectFile(title string, filter string) string
SelectDirectory() string SelectDirectory() string
SelectSaveFile() string SelectSaveFile(title string, filter string) string
// Window Runtime // Window Runtime
SetColour(string) error SetColour(string) error

View File

@@ -114,7 +114,7 @@ func (h *Bridge) NewBinding(methodName string) error {
// SelectFile is unsupported for Bridge but required // SelectFile is unsupported for Bridge but required
// for the Renderer interface // for the Renderer interface
func (h *Bridge) SelectFile() string { func (h *Bridge) SelectFile(title string, filter string) string {
h.log.Warn("SelectFile() unsupported in bridge mode") h.log.Warn("SelectFile() unsupported in bridge mode")
return "" return ""
} }
@@ -128,7 +128,7 @@ func (h *Bridge) SelectDirectory() string {
// SelectSaveFile is unsupported for Bridge but required // SelectSaveFile is unsupported for Bridge but required
// for the Renderer interface // for the Renderer interface
func (h *Bridge) SelectSaveFile() string { func (h *Bridge) SelectSaveFile(title string, filter string) string {
h.log.Warn("SelectSaveFile() unsupported in bridge mode") h.log.Warn("SelectSaveFile() unsupported in bridge mode")
return "" return ""
} }
@@ -152,12 +152,19 @@ func (h *Bridge) NotifyEvent(event *messages.EventData) error {
// Marshall the data // Marshall the data
data, err = json.Marshal(event.Data) data, err = json.Marshal(event.Data)
if err != nil { if err != nil {
h.log.Errorf("Cannot unmarshall JSON data in event: %s ", err.Error()) h.log.Errorf("Cannot marshal JSON data in event: %s ", err.Error())
return err return err
} }
} }
message := fmt.Sprintf("window.wails._.Notify('%s','%s')", event.Name, data) // Double encode data to ensure everything is escaped correctly.
data, err = json.Marshal(string(data))
if err != nil {
h.log.Errorf("Cannot marshal JSON data in event: %s ", err.Error())
return err
}
message := "window.wails._.Notify('" + event.Name + "'," + string(data) + ")"
dead := []*session{} dead := []*session{}
for _, session := range h.sessions { for _, session := range h.sessions {
err := session.evalJS(message, notifyMessage) err := session.evalJS(message, notifyMessage)

View File

@@ -0,0 +1,9 @@
package renderer
// Autogenerated by Mewn - Do not alter
import "github.com/leaanthony/mewn"
func init() {
mewn.AddAsset(".", "../../runtime/assets/wails.js", "1f8b08000000000000ff94587f6f1b37d2fe2a2be27d5532a6b752ae875e56dd06a9eba23e38761127d73f744241ed8e24262b52478eac0812bffb61f6b76cb9770704b1440ec9e13ccfcc3cd460b135196a6bb8118747e5224c0f61d20c46c09d38e805c7a99b0907b87526a2cf317cdd58877e424b6c4a43e941274e16c9602cebc9e410c2a45e646851a68a82db66adb4b2fb0c42dab84807a36e2c40bc4e8d84384b51429ca79dab12a51307882d7d14c7e3fdfc336418e7b0d0067e7376030ef7a5d901cc760d4ecd0b480623b9044c5c104142ecd2fed5d9d654ab73364871bf01bb881ef6ebb92d86c3ea6f8cf6019d36cb8f6a391cbe74e2735b797854c51612f6dee6db025810f2a5c5ec8f3fc0d766cdb2c1a872174fae5f82321ee270c84d0adc0821ff36c4062133d10bfe1dcd325b1ec5d2e64e6638a47f717752b788b07469ed5ce6402170b32d0a41db41ecb87bc97527590e0bb52d903d8d78750b13847c5d3ae4cbb874413662611d2f69146913190171ce9db4b2bd2e8a434b229c8578ae4d5efa25ad100dbf1cc5c8a4cfd9fce4b66f5b8b6ed7b8f63d2467265b06935f2899621285443ace3e81a436ac43b471162d5d325e297fbf334db0aa2ca005b4c726654c0287d8a72311f8f484e340bcf41051cc326413c20085ac3db9311a99e4cf7dfe1a84a8c13c84490d5c1556f633ccb7cbb3ab8a205aab1bb3b0678d7ccfe877e50c4179ce6ed1b3bb76cebab35679cfea1785aa386bb56bae639bebd86a9595ec7e03e6d387dbb3ebf6cdeeb5dd2f9ad2ea8ce1bc39403707e86aa196ec0e7667d75c356b543a9d75f5326b70abc34ff8274612e473957db9f93901b951fbc2aa3cc13039a9be7ac177dae47617ef942efcdce97c096f9f0fc53b987b9b7d018c3d502a88a43682af08cea822d6e6d17ea1b220555c8059e2eac7519b67988e26f8433331c18b0ba1a638e34604fef787fbbbb84a51bdd873274468efb6ad589e7156d8259387021ea1488c5c83f76a0909869e714137da7296577c33bd295f4fe99264fd99453db36b98d59fcceb49a8e8d49fdad5538b8a434604bae7463e9ef4b265834d93dadba218a4301cd61f8e470ee9484803bbe83767d7da03ef9077d256a8ea496e0f3a3517ec925d6cb808bb952e803f4ef5ac2a943f8e44450c0ff851afc16e91f719647999119c5da9a288d046ecc25cb008f51af2c86e318e3ec0bfb6e031baf93989d88516220809624247a407acb6fc5599bc80444907546e122b1d785b3c42e2c204dd9e7022da3179a082a9cdf24ead898bb942953cc1996a9116215398ad28969935de161097b12662843e115627e56ec959c5ce985d9455adb5dbd356b5d58ab39f9cdd7970719bb37d08e72fdb56796b44d8a435cf33b7dfa0ed97720ab84909b94fdae05f5ebf734eedf9b86d0f270be325e0076572bbfe073527e2e374343b57fddf8c46df8fdfbc79fdd7efbeff6ef4e6cdf8d57b85abd8956bb908650158b75d2032bce4d7e059a71e701369e351998c7a1e0a812b67771139fc71bf819610c6588c08b6484559a1bc8f948f54d46cc844e0b8d25e1a2181187b3996f43dbeaa0bcc49036cf45aac369b625fb54c23e4e5789012ed47699a72b84cc72204797d922af74daa5c4fcd2ca5ff8ec7e9acee29e4f4babce98466e2cdd6afb8eb61f9d075df273c9bce625fe80c6a8f945b6ed760d08b6a988fa962a707d3632a8649c6193c824126a1caecbb1367bfd071c4f826af6117fdd28481913dbb30420e461dbf2bcbc138744e5f5560913948975254299b07fdfa5ba356a3f53b0d45da478499361ab52ab4879c35dd6a3a6be85762e4b7739f393d8713906c153f234285a4879ed24371801465df87f89a42e1e3ebb546aa94baf089df9b2cf1681d24db4dae10f2f97ee1ac4130794259f9040610a4b617d65dab6cd5ab4d461c0c0741c95e3953ed764e5571101347ce96b5e39c83f7e6cfdc23b236de9d3a507166a39c2f1b18a4e63ff92a84c4e1b0891e2924fadc41fbb94d68feb991b7ca7bbd34c7637fbfae418ea94136e4ec37ca8a1f693b37c5d9a459e648bf82f8afe41f482748bbd3bb09e86d155abd29eae428f3bccb9050c7b80e5c7a388d7adaff723c76b39d7dc9ca9bf47007bb9faa8e903c07763a8b336b3285dcc47e5310c76226ca8f6d7e9eee4c59828dca18b72ac3a5a389fba199b81c4fdc453aae4ea9de8b65767de156885eded6a9c51a27ac644d86a9e851153a8f3eab474579b4c148e760502f34b898093181a99d51139fda597a0865859cda59a8941dc61bbbe1a23e55ffe9a9fa7f3b55cfd227ad882456ef0dddd0a62d7f25073a6c276d2b3512a885b64f8e4e429c2421a6861e0fcb33b35dd90f1202174136bde139da1393e690d91c3e7db8b9b2eb8d35600878079b4265c0bffda7bff876291913ddd07474f9465d2e6687d781a6feffff8614042abf789ab975b56d6a6aca6e4c154ab28a36ca7bc849fd34da3889daf8635c6b4ac9e2e87d2d2f23265a6a8a4955890b0e955eab10acdb834b316e76d5b9b4e96343b746c2a5ac094af44d7baa93ec9b1273074bed11f2c160c09a934e1591ee9f4ac2a900e51aad67e3138926640e052044e485c46a87b736ae741baf07444223a580e31853e71341de59d48b7df24c4e50dbedca15940dbaeea0425689570ed585ab9f79344e7e68ea4e94b982a0d37de8b0075dce4f6123c7220f06093953ba174765c18fa8694769d96b836d0509d7623884a67e383916a1d41410827c97e70f654a3db96175a9dc66657ad4bf445c1740df38abb2908909c4085f3135b2b59cdb7c4fd5134c7eb5d2454eecc0e1f0a1ec513786e27df5f070a6eabd7816ee0b200e5022be43747abe45e08cea3a938cceff36f39e09897169fbb002c0b7fd2f71e6fdc7d2cf044f7c7b7226d9dcd9bcfa2da79b5c81ca8fc7f6eb12b076ceffb4ffa84a4dcf191931d2b0e2e484ead61a93af14ea9bdfae6e89d606dc4904542b4082bc4d0fb776993859ebefc4caaa9b27877bf304a5fbfa378c7bf37e5ba0de1490dc4b5225c983fc1594c339a85364bb773149d1c91df1a057b7ca24ba3108ee5115e54f1654bd1c3da3dad1fe3b8a646610a50fefb22fc6ee0ac897903c79520fe8989edcce5b99adba45d1d6d06713ad1ac77b75c148f60dd538da8853941e4a29a3e51fc94d4f867ead2489089f4f9ef1f25634add89a32d54f7fc70459be2c4f14d4ad5dc6754f7af5ead5abe84a6d972b8c3e99555951f2aaf04434c7847c6969573849febe64f5e9c32d59e0cb16b7da407467c90a5eb6bab2c5766d6a3bf7b25d1902b2b122c88746221656e5a49cc34c4cfe1d0000ffff6a61b37f93160000")
}

File diff suppressed because one or more lines are too long

View File

@@ -245,7 +245,7 @@ func (w *WebView) NewBinding(methodName string) error {
} }
// SelectFile opens a dialog that allows the user to select a file // SelectFile opens a dialog that allows the user to select a file
func (w *WebView) SelectFile() string { func (w *WebView) SelectFile(title string, filter string) string {
var result string var result string
// We need to run this on the main thread, however Dispatch is // We need to run this on the main thread, however Dispatch is
@@ -255,7 +255,7 @@ func (w *WebView) SelectFile() string {
wg.Add(1) wg.Add(1)
go func() { go func() {
w.window.Dispatch(func() { w.window.Dispatch(func() {
result = w.window.Dialog(wv.DialogTypeOpen, 0, "Select File", "") result = w.window.Dialog(wv.DialogTypeOpen, 0, title, "", filter)
wg.Done() wg.Done()
}) })
}() }()
@@ -273,7 +273,7 @@ func (w *WebView) SelectDirectory() string {
wg.Add(1) wg.Add(1)
go func() { go func() {
w.window.Dispatch(func() { w.window.Dispatch(func() {
result = w.window.Dialog(wv.DialogTypeOpen, wv.DialogFlagDirectory, "Select Directory", "") result = w.window.Dialog(wv.DialogTypeOpen, wv.DialogFlagDirectory, "Select Directory", "", "")
wg.Done() wg.Done()
}) })
}() }()
@@ -282,7 +282,7 @@ func (w *WebView) SelectDirectory() string {
} }
// SelectSaveFile opens a dialog that allows the user to select a file to save // SelectSaveFile opens a dialog that allows the user to select a file to save
func (w *WebView) SelectSaveFile() string { func (w *WebView) SelectSaveFile(title string, filter string) string {
var result string var result string
// We need to run this on the main thread, however Dispatch is // We need to run this on the main thread, however Dispatch is
// non-blocking so we launch this in a goroutine and wait for // non-blocking so we launch this in a goroutine and wait for
@@ -291,7 +291,7 @@ func (w *WebView) SelectSaveFile() string {
wg.Add(1) wg.Add(1)
go func() { go func() {
w.window.Dispatch(func() { w.window.Dispatch(func() {
result = w.window.Dialog(wv.DialogTypeSave, 0, "Save file", "") result = w.window.Dialog(wv.DialogTypeSave, 0, title, "", filter)
wg.Done() wg.Done()
}) })
}() }()
@@ -329,7 +329,14 @@ func (w *WebView) NotifyEvent(event *messages.EventData) error {
} }
} }
message := fmt.Sprintf("wails._.Notify('%s','%s')", event.Name, data) // Double encode data to ensure everything is escaped correctly.
data, err = json.Marshal(string(data))
if err != nil {
w.log.Errorf("Cannot marshal JSON data in event: %s ", err.Error())
return err
}
message := "window.wails._.Notify('" + event.Name + "'," + string(data) + ")"
return w.evalJS(message) return w.evalJS(message)
} }

View File

@@ -74,9 +74,9 @@ static inline void CgoWebViewSetColor(void *w, uint8_t r, uint8_t g, uint8_t b,
} }
static inline void CgoDialog(void *w, int dlgtype, int flags, static inline void CgoDialog(void *w, int dlgtype, int flags,
char *title, char *arg, char *res, size_t ressz) { char *title, char *arg, char *res, size_t ressz, char *filter) {
webview_dialog(w, dlgtype, flags, webview_dialog(w, dlgtype, flags,
(const char*)title, (const char*) arg, res, ressz); (const char*)title, (const char*) arg, res, ressz, filter);
} }
static inline int CgoWebViewEval(void *w, char *js) { static inline int CgoWebViewEval(void *w, char *js) {
@@ -186,7 +186,7 @@ type WebView interface {
// Dialog() opens a system dialog of the given type and title. String // Dialog() opens a system dialog of the given type and title. String
// argument can be provided for certain dialogs, such as alert boxes. For // argument can be provided for certain dialogs, such as alert boxes. For
// alert boxes argument is a message inside the dialog box. // alert boxes argument is a message inside the dialog box.
Dialog(dlgType DialogType, flags int, title string, arg string) string Dialog(dlgType DialogType, flags int, title string, arg string, filter string) string
// Terminate() breaks the main UI loop. This method must be called from the main thread // Terminate() breaks the main UI loop. This method must be called from the main thread
// only. See Dispatch() for more details. // only. See Dispatch() for more details.
Terminate() Terminate()
@@ -311,7 +311,7 @@ func (w *webview) SetFullscreen(fullscreen bool) {
C.CgoWebViewSetFullscreen(w.w, C.int(boolToInt(fullscreen))) C.CgoWebViewSetFullscreen(w.w, C.int(boolToInt(fullscreen)))
} }
func (w *webview) Dialog(dlgType DialogType, flags int, title string, arg string) string { func (w *webview) Dialog(dlgType DialogType, flags int, title string, arg string, filter string) string {
const maxPath = 4096 const maxPath = 4096
titlePtr := C.CString(title) titlePtr := C.CString(title)
defer C.free(unsafe.Pointer(titlePtr)) defer C.free(unsafe.Pointer(titlePtr))
@@ -319,8 +319,10 @@ func (w *webview) Dialog(dlgType DialogType, flags int, title string, arg string
defer C.free(unsafe.Pointer(argPtr)) defer C.free(unsafe.Pointer(argPtr))
resultPtr := (*C.char)(C.calloc((C.size_t)(unsafe.Sizeof((*C.char)(nil))), (C.size_t)(maxPath))) resultPtr := (*C.char)(C.calloc((C.size_t)(unsafe.Sizeof((*C.char)(nil))), (C.size_t)(maxPath)))
defer C.free(unsafe.Pointer(resultPtr)) defer C.free(unsafe.Pointer(resultPtr))
filterPtr := C.CString(filter)
defer C.free(unsafe.Pointer(filterPtr))
C.CgoDialog(w.w, C.int(dlgType), C.int(flags), titlePtr, C.CgoDialog(w.w, C.int(dlgType), C.int(flags), titlePtr,
argPtr, resultPtr, C.size_t(maxPath)) argPtr, resultPtr, C.size_t(maxPath), filterPtr)
return C.GoString(resultPtr) return C.GoString(resultPtr)
} }

View File

@@ -174,7 +174,7 @@ struct webview_priv
WEBVIEW_API void webview_dialog(struct webview *w, WEBVIEW_API void webview_dialog(struct webview *w,
enum webview_dialog_type dlgtype, int flags, enum webview_dialog_type dlgtype, int flags,
const char *title, const char *arg, const char *title, const char *arg,
char *result, size_t resultsz); char *result, size_t resultsz, char *filter);
WEBVIEW_API void webview_dispatch(struct webview *w, webview_dispatch_fn fn, WEBVIEW_API void webview_dispatch(struct webview *w, webview_dispatch_fn fn,
void *arg); void *arg);
WEBVIEW_API void webview_terminate(struct webview *w); WEBVIEW_API void webview_terminate(struct webview *w);
@@ -418,7 +418,7 @@ struct webview_priv
WEBVIEW_API void webview_dialog(struct webview *w, WEBVIEW_API void webview_dialog(struct webview *w,
enum webview_dialog_type dlgtype, int flags, enum webview_dialog_type dlgtype, int flags,
const char *title, const char *arg, const char *title, const char *arg,
char *result, size_t resultsz) char *result, size_t resultsz, char *filter)
{ {
GtkWidget *dlg; GtkWidget *dlg;
if (result != NULL) if (result != NULL)
@@ -438,6 +438,17 @@ struct webview_priv
"_Cancel", GTK_RESPONSE_CANCEL, "_Cancel", GTK_RESPONSE_CANCEL,
(dlgtype == WEBVIEW_DIALOG_TYPE_OPEN ? "_Open" : "_Save"), (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN ? "_Open" : "_Save"),
GTK_RESPONSE_ACCEPT, NULL); GTK_RESPONSE_ACCEPT, NULL);
if (filter[0] != '\0') {
GtkFileFilter *file_filter = gtk_file_filter_new();
gchar **filters = g_strsplit(filter, ",", -1);
gint i;
for(i = 0; filters && filters[i]; i++) {
gtk_file_filter_add_pattern(file_filter, filters[i]);
}
gtk_file_filter_set_name(file_filter, filter);
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dlg), file_filter);
g_strfreev(filters);
}
gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(dlg), FALSE); gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(dlg), FALSE);
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dlg), FALSE); gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dlg), FALSE);
gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(dlg), TRUE); gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(dlg), TRUE);
@@ -1782,7 +1793,7 @@ struct webview_priv
WEBVIEW_API void webview_dialog(struct webview *w, WEBVIEW_API void webview_dialog(struct webview *w,
enum webview_dialog_type dlgtype, int flags, enum webview_dialog_type dlgtype, int flags,
const char *title, const char *arg, const char *title, const char *arg,
char *result, size_t resultsz) char *result, size_t resultsz, char *filter)
{ {
if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN || if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN ||
dlgtype == WEBVIEW_DIALOG_TYPE_SAVE) dlgtype == WEBVIEW_DIALOG_TYPE_SAVE)
@@ -1822,6 +1833,32 @@ struct webview_priv
FOS_NOTESTFILECREATE | FOS_NODEREFERENCELINKS | FOS_NOTESTFILECREATE | FOS_NODEREFERENCELINKS |
FOS_FORCESHOWHIDDEN | FOS_DEFAULTNOMINIMODE; FOS_FORCESHOWHIDDEN | FOS_DEFAULTNOMINIMODE;
} }
if (filter[0] != '\0')
{
int count;
int i=0;
char* token;
char* filter_dup = strdup(filter);
for (count=1; filter[count]; filter[count]==',' ? count++ : *filter++);
COMDLG_FILTERSPEC rgSpec[count];
char* filters[count];
token = strtok(filter_dup, ",");
while(token != NULL)
{
filters[i] = token;
token = strtok(NULL, ",");
i++;
}
for (int i=0; i < count; i++) {
wchar_t *wFilter = (wchar_t *)malloc(4096);
MultiByteToWideChar(CP_ACP, 0, filters[i], -1, wFilter, 4096);
rgSpec[i].pszName = wFilter;
rgSpec[i].pszSpec = wFilter;
}
if (dlg->lpVtbl->SetFileTypes(dlg, count, rgSpec) != S_OK) {
goto error_dlg;
}
}
if (dlg->lpVtbl->GetOptions(dlg, &opts) != S_OK) if (dlg->lpVtbl->GetOptions(dlg, &opts) != S_OK)
{ {
goto error_dlg; goto error_dlg;
@@ -1940,7 +1977,7 @@ struct webview_priv
(struct webview *)objc_getAssociatedObject(self, "webview"); (struct webview *)objc_getAssociatedObject(self, "webview");
webview_dialog(w, WEBVIEW_DIALOG_TYPE_OPEN, WEBVIEW_DIALOG_FLAG_FILE, "", "", webview_dialog(w, WEBVIEW_DIALOG_TYPE_OPEN, WEBVIEW_DIALOG_FLAG_FILE, "", "",
filename, 255); filename, 255, "");
filename[255] = '\0'; filename[255] = '\0';
if (strlen(filename) > 0) if (strlen(filename) > 0)
{ {
@@ -2203,12 +2240,16 @@ struct webview_priv
WEBVIEW_API void webview_dialog(struct webview *w, WEBVIEW_API void webview_dialog(struct webview *w,
enum webview_dialog_type dlgtype, int flags, enum webview_dialog_type dlgtype, int flags,
const char *title, const char *arg, const char *title, const char *arg,
char *result, size_t resultsz) char *result, size_t resultsz, char *filter)
{ {
if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN || if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN ||
dlgtype == WEBVIEW_DIALOG_TYPE_SAVE) dlgtype == WEBVIEW_DIALOG_TYPE_SAVE)
{ {
NSSavePanel *panel; NSSavePanel *panel;
NSString *filter_str = [NSString stringWithUTF8String:filter];
filter_str = [filter_str stringByReplacingOccurrencesOfString:@"*."
withString:@""];
NSArray *fileTypes = [filter_str componentsSeparatedByString:@","];
if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN) if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN)
{ {
NSOpenPanel *openPanel = [NSOpenPanel openPanel]; NSOpenPanel *openPanel = [NSOpenPanel openPanel];
@@ -2221,6 +2262,10 @@ struct webview_priv
{ {
[openPanel setCanChooseFiles:YES]; [openPanel setCanChooseFiles:YES];
[openPanel setCanChooseDirectories:NO]; [openPanel setCanChooseDirectories:NO];
if(filter[0] != NULL)
{
[openPanel setAllowedFileTypes:fileTypes];
}
} }
[openPanel setResolvesAliases:NO]; [openPanel setResolvesAliases:NO];
[openPanel setAllowsMultipleSelection:NO]; [openPanel setAllowsMultipleSelection:NO];
@@ -2234,6 +2279,10 @@ struct webview_priv
[panel setShowsHiddenFiles:YES]; [panel setShowsHiddenFiles:YES];
[panel setExtensionHidden:NO]; [panel setExtensionHidden:NO];
[panel setCanSelectHiddenExtension:NO]; [panel setCanSelectHiddenExtension:NO];
if(filter[0] != NULL)
{
[panel setAllowedFileTypes:fileTypes];
}
[panel setTreatsFilePackagesAsDirectories:YES]; [panel setTreatsFilePackagesAsDirectories:YES];
[panel beginSheetModalForWindow:w->priv.window [panel beginSheetModalForWindow:w->priv.window
completionHandler:^(NSInteger result) { completionHandler:^(NSInteger result) {

View File

@@ -1,32 +0,0 @@
package wails
import (
"github.com/wailsapp/wails/lib/interfaces"
"github.com/wailsapp/wails/lib/logger"
"github.com/wailsapp/wails/runtime"
)
// CustomLogger type alias
type CustomLogger = logger.CustomLogger
// Runtime is the Wails Runtime Interface, given to a user who has defined the WailsInit method
type Runtime struct {
Events *runtime.Events
Log *runtime.Log
Dialog *runtime.Dialog
Window *runtime.Window
Browser *runtime.Browser
FileSystem *runtime.FileSystem
}
// NewRuntime creates a new Runtime struct
func NewRuntime(eventManager interfaces.EventManager, renderer interfaces.Renderer) *Runtime {
return &Runtime{
Events: runtime.NewEvents(eventManager),
Log: runtime.NewLog(),
Dialog: runtime.NewDialog(renderer),
Window: runtime.NewWindow(renderer),
Browser: runtime.NewBrowser(),
FileSystem: runtime.NewFileSystem(),
}
}

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,7 @@
package runtime package runtime
import "github.com/wailsapp/wails/lib/interfaces" import "github.com/wailsapp/wails/lib/interfaces"
import "strings"
// Dialog exposes an interface to native dialogs // Dialog exposes an interface to native dialogs
type Dialog struct { type Dialog struct {
@@ -15,8 +16,16 @@ func NewDialog(renderer interfaces.Renderer) *Dialog {
} }
// SelectFile prompts the user to select a file // SelectFile prompts the user to select a file
func (r *Dialog) SelectFile() string { func (r *Dialog) SelectFile(params ...string) string {
return r.renderer.SelectFile() title := "Select File"
filter := ""
if len(params) > 0 {
title = params[0]
}
if len(params) > 1 {
filter = strings.Replace(params[1], " ", "", -1)
}
return r.renderer.SelectFile(title, filter)
} }
// SelectDirectory prompts the user to select a directory // SelectDirectory prompts the user to select a directory
@@ -25,6 +34,14 @@ func (r *Dialog) SelectDirectory() string {
} }
// SelectSaveFile prompts the user to select a file for saving // SelectSaveFile prompts the user to select a file for saving
func (r *Dialog) SelectSaveFile() string { func (r *Dialog) SelectSaveFile(params ...string) string {
return r.renderer.SelectSaveFile() title := "Select Save"
filter := ""
if len(params) > 0 {
title = params[0]
}
if len(params) > 1 {
filter = strings.Replace(params[1], " ", "", -1)
}
return r.renderer.SelectSaveFile(title, filter)
} }

View File

@@ -1,9 +1,9 @@
package runtime package runtime
import homedir "github.com/mitchellh/go-homedir" import "os"
// FileSystem exposes file system utilities to the runtime // FileSystem exposes file system utilities to the runtime
type FileSystem struct {} type FileSystem struct{}
// NewFileSystem creates a new FileSystem struct // NewFileSystem creates a new FileSystem struct
func NewFileSystem() *FileSystem { func NewFileSystem() *FileSystem {
@@ -12,5 +12,5 @@ func NewFileSystem() *FileSystem {
// HomeDir returns the user's home directory // HomeDir returns the user's home directory
func (r *FileSystem) HomeDir() (string, error) { func (r *FileSystem) HomeDir() (string, error) {
return homedir.Dir() return os.UserHomeDir()
} }

View File

@@ -15,6 +15,7 @@ import { NewBinding } from './bindings';
import { Callback } from './calls'; import { Callback } from './calls';
import { AddScript, InjectCSS } from './utils'; import { AddScript, InjectCSS } from './utils';
import { AddIPCListener } from './ipc'; import { AddIPCListener } from './ipc';
import * as Store from './store';
// Initialise global if not already // Initialise global if not already
window.wails = window.wails || {}; window.wails = window.wails || {};
@@ -42,6 +43,7 @@ var runtime = {
Heartbeat, Heartbeat,
Acknowledge, Acknowledge,
}, },
Store,
_: internal, _: internal,
}; };

82
runtime/js/core/store.js Normal file
View File

@@ -0,0 +1,82 @@
/*
_ __ _ __
| | / /___ _(_) /____
| | /| / / __ `/ / / ___/
| |/ |/ / /_/ / / (__ )
|__/|__/\__,_/_/_/____/
The lightweight framework for web-like apps
(c) Lea Anthony 2019-present
*/
/* jshint esversion: 6 */
/**
* Creates a new sync store with the given name and optional default value
*
* @export
* @param {string} name
* @param {*} optionalDefault
*/
export function New(name, optionalDefault) {
var data;
// Check we are initialised
if( !window.wails) {
throw Error('Wails is not initialised');
}
// Store for the callbacks
let callbacks = [];
// Subscribe to updates by providing a callback
this.subscribe = (callback) => {
callbacks.push(callback);
};
// sets the store data to the provided `newdata` value
this.set = (newdata) => {
data = newdata;
// Emit a notification to back end
window.wails.Events.Emit('wails:sync:store:updatedbyfrontend:'+name, JSON.stringify(data));
// Notify callbacks
callbacks.forEach( function(callback) {
callback(data);
});
};
// update mutates the value in the store by calling the
// provided method with the current value. The value returned
// by the updater function will be set as the new store value
this.update = (updater) => {
var newValue = updater(data);
this.set(newValue);
};
// Setup event callback
window.wails.Events.On('wails:sync:store:updatedbybackend:'+name, function(result) {
// Parse data
result = JSON.parse(result);
// Todo: Potential preprocessing?
// Save data
data = result;
// Notify callbacks
callbacks.forEach( function(callback) {
callback(data);
});
});
// Set to the optional default if set
if( optionalDefault ) {
this.set(optionalDefault);
}
return this;
}

File diff suppressed because it is too large Load Diff

View File

@@ -29,15 +29,15 @@
}, },
"homepage": "https://github.com/wailsapp/runtime#readme", "homepage": "https://github.com/wailsapp/runtime#readme",
"devDependencies": { "devDependencies": {
"@babel/cli": "^7.5.0", "@babel/cli": "^7.11.5",
"@babel/core": "^7.5.4", "@babel/core": "^7.11.5",
"@babel/plugin-transform-object-assign": "^7.2.0", "@babel/plugin-transform-object-assign": "^7.10.4",
"@babel/preset-env": "^7.5.4", "@babel/preset-env": "^7.11.5",
"babel-loader": "^8.0.6", "babel-loader": "^8.1.0",
"babel-preset-minify": "^0.5.0", "babel-preset-minify": "^0.5.1",
"core-js": "^3.1.4", "core-js": "^3.6.5",
"eslint": "^6.5.1", "eslint": "^7.8.1",
"webpack": "^4.35.3", "webpack": "^4.44.1",
"webpack-cli": "^3.3.5" "webpack-cli": "^3.3.12"
} }
} }

View File

@@ -13,10 +13,12 @@ const Log = require('./log');
const Browser = require('./browser'); const Browser = require('./browser');
const Events = require('./events'); const Events = require('./events');
const Init = require('./init'); const Init = require('./init');
const Store = require('./store');
module.exports = { module.exports = {
Log: Log, Log: Log,
Browser: Browser, Browser: Browser,
Events: Events, Events: Events,
Init: Init Init: Init,
Store: Store,
}; };

492
runtime/js/runtime/package-lock.json generated Normal file
View File

@@ -0,0 +1,492 @@
{
"name": "@wailsapp/runtime",
"version": "1.1.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
"dev": true
},
"camelcase": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
"integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=",
"dev": true
},
"cliui": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
"integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=",
"dev": true,
"requires": {
"string-width": "^1.0.1",
"strip-ansi": "^3.0.1",
"wrap-ansi": "^2.0.0"
}
},
"code-point-at": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
"dev": true
},
"decamelize": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
"dev": true
},
"dts-dom": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/dts-dom/-/dts-dom-3.6.0.tgz",
"integrity": "sha512-on5jxTgt+A6r0Zyyz6ZRHXaAO7J1VPnOd6+AmvI1vH440AlAZZNc5rUHzgPuTjGlrVr1rOWQYNl7ZJK6rDohbw==",
"dev": true
},
"dts-gen": {
"version": "0.5.8",
"resolved": "https://registry.npmjs.org/dts-gen/-/dts-gen-0.5.8.tgz",
"integrity": "sha512-kIAV6dlHaF7r5J+tIuOC1BJls2P72YM0cyWQUR88zcJEpX2ccRZe+HmXLfkkvfPwjvSO3FEqUiyC8On/grx5qw==",
"dev": true,
"requires": {
"dts-dom": "^3.6.0",
"parse-git-config": "^1.1.1",
"typescript": "^3.5.1",
"yargs": "^4.8.1"
}
},
"error-ex": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
"integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
"dev": true,
"requires": {
"is-arrayish": "^0.2.1"
}
},
"extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
"dev": true,
"requires": {
"is-extendable": "^0.1.0"
}
},
"find-up": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
"integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
"dev": true,
"requires": {
"path-exists": "^2.0.0",
"pinkie-promise": "^2.0.0"
}
},
"fs-exists-sync": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz",
"integrity": "sha1-mC1ok6+RjnLQjeyehnP/K1qNat0=",
"dev": true
},
"get-caller-file": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
"integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==",
"dev": true
},
"git-config-path": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/git-config-path/-/git-config-path-1.0.1.tgz",
"integrity": "sha1-bTP37WPbDQ4RgTFQO6s6ykfVRmQ=",
"dev": true,
"requires": {
"extend-shallow": "^2.0.1",
"fs-exists-sync": "^0.1.0",
"homedir-polyfill": "^1.0.0"
}
},
"graceful-fs": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
"integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
"dev": true
},
"homedir-polyfill": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",
"integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==",
"dev": true,
"requires": {
"parse-passwd": "^1.0.0"
}
},
"hosted-git-info": {
"version": "2.8.8",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz",
"integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==",
"dev": true
},
"ini": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
"dev": true
},
"invert-kv": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
"integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=",
"dev": true
},
"is-arrayish": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
"integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
"dev": true
},
"is-extendable": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
"integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
"dev": true
},
"is-fullwidth-code-point": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
"dev": true,
"requires": {
"number-is-nan": "^1.0.0"
}
},
"is-utf8": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
"integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
"dev": true
},
"lcid": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
"integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=",
"dev": true,
"requires": {
"invert-kv": "^1.0.0"
}
},
"load-json-file": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
"integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
"dev": true,
"requires": {
"graceful-fs": "^4.1.2",
"parse-json": "^2.2.0",
"pify": "^2.0.0",
"pinkie-promise": "^2.0.0",
"strip-bom": "^2.0.0"
}
},
"lodash.assign": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz",
"integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=",
"dev": true
},
"normalize-package-data": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
"integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
"dev": true,
"requires": {
"hosted-git-info": "^2.1.4",
"resolve": "^1.10.0",
"semver": "2 || 3 || 4 || 5",
"validate-npm-package-license": "^3.0.1"
}
},
"number-is-nan": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
"dev": true
},
"os-locale": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
"integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
"dev": true,
"requires": {
"lcid": "^1.0.0"
}
},
"parse-git-config": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/parse-git-config/-/parse-git-config-1.1.1.tgz",
"integrity": "sha1-06mYQxcTL1c5hxK7pDjhKVkN34w=",
"dev": true,
"requires": {
"extend-shallow": "^2.0.1",
"fs-exists-sync": "^0.1.0",
"git-config-path": "^1.0.1",
"ini": "^1.3.4"
}
},
"parse-json": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
"integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
"dev": true,
"requires": {
"error-ex": "^1.2.0"
}
},
"parse-passwd": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz",
"integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=",
"dev": true
},
"path-exists": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
"integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
"dev": true,
"requires": {
"pinkie-promise": "^2.0.0"
}
},
"path-parse": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
"dev": true
},
"path-type": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
"integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
"dev": true,
"requires": {
"graceful-fs": "^4.1.2",
"pify": "^2.0.0",
"pinkie-promise": "^2.0.0"
}
},
"pify": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
"dev": true
},
"pinkie": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
"integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
"dev": true
},
"pinkie-promise": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
"integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
"dev": true,
"requires": {
"pinkie": "^2.0.0"
}
},
"read-pkg": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
"integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
"dev": true,
"requires": {
"load-json-file": "^1.0.0",
"normalize-package-data": "^2.3.2",
"path-type": "^1.0.0"
}
},
"read-pkg-up": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
"integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
"dev": true,
"requires": {
"find-up": "^1.0.0",
"read-pkg": "^1.0.0"
}
},
"require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
"dev": true
},
"require-main-filename": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
"integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=",
"dev": true
},
"resolve": {
"version": "1.17.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz",
"integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==",
"dev": true,
"requires": {
"path-parse": "^1.0.6"
}
},
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"dev": true
},
"set-blocking": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
"dev": true
},
"spdx-correct": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz",
"integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==",
"dev": true,
"requires": {
"spdx-expression-parse": "^3.0.0",
"spdx-license-ids": "^3.0.0"
}
},
"spdx-exceptions": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
"integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==",
"dev": true
},
"spdx-expression-parse": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
"integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
"dev": true,
"requires": {
"spdx-exceptions": "^2.1.0",
"spdx-license-ids": "^3.0.0"
}
},
"spdx-license-ids": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz",
"integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==",
"dev": true
},
"string-width": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
"dev": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
"strip-ansi": "^3.0.0"
}
},
"strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"dev": true,
"requires": {
"ansi-regex": "^2.0.0"
}
},
"strip-bom": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
"integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
"dev": true,
"requires": {
"is-utf8": "^0.2.0"
}
},
"typescript": {
"version": "3.9.7",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz",
"integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==",
"dev": true
},
"validate-npm-package-license": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
"integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
"dev": true,
"requires": {
"spdx-correct": "^3.0.0",
"spdx-expression-parse": "^3.0.0"
}
},
"which-module": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz",
"integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=",
"dev": true
},
"window-size": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz",
"integrity": "sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU=",
"dev": true
},
"wrap-ansi": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
"integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
"dev": true,
"requires": {
"string-width": "^1.0.1",
"strip-ansi": "^3.0.1"
}
},
"y18n": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
"integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=",
"dev": true
},
"yargs": {
"version": "4.8.1",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz",
"integrity": "sha1-wMQpJMpKqmsObaFznfshZDn53cA=",
"dev": true,
"requires": {
"cliui": "^3.2.0",
"decamelize": "^1.1.1",
"get-caller-file": "^1.0.1",
"lodash.assign": "^4.0.3",
"os-locale": "^1.4.0",
"read-pkg-up": "^1.0.1",
"require-directory": "^2.1.1",
"require-main-filename": "^1.0.1",
"set-blocking": "^2.0.0",
"string-width": "^1.0.1",
"which-module": "^1.0.0",
"window-size": "^0.2.0",
"y18n": "^3.2.1",
"yargs-parser": "^2.4.1"
}
},
"yargs-parser": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz",
"integrity": "sha1-hVaN488VD/SfpRgl8DqMiA3cxcQ=",
"dev": true,
"requires": {
"camelcase": "^3.0.0",
"lodash.assign": "^4.0.6"
}
}
}
}

View File

@@ -1,6 +1,6 @@
{ {
"name": "@wailsapp/runtime", "name": "@wailsapp/runtime",
"version": "1.0.11", "version": "1.1.0",
"description": "Wails Javascript runtime library", "description": "Wails Javascript runtime library",
"main": "main.js", "main": "main.js",
"types": "runtime.d.ts", "types": "runtime.d.ts",
@@ -25,4 +25,4 @@
"devDependencies": { "devDependencies": {
"dts-gen": "^0.5.8" "dts-gen": "^0.5.8"
} }
} }

View File

@@ -21,6 +21,9 @@ declare const wailsapp__runtime: {
Info(message: string): void; Info(message: string): void;
Warning(message: string): void; Warning(message: string): void;
}; };
Store: {
New(name: string, optionalDefault?: any): any;
};
}; };

View File

@@ -0,0 +1,27 @@
/*
_ __ _ __
| | / /___ _(_) /____
| | /| / / __ `/ / / ___/
| |/ |/ / /_/ / / (__ )
|__/|__/\__,_/_/_/____/
The lightweight framework for web-like apps
(c) Lea Anthony 2019-present
*/
/* jshint esversion: 6 */
/**
* Create a new Store with the given name and optional default value
*
* @export
* @param {string} name
* @param {*} optionalDefault
*/
function New(name, optionalDefault) {
return window.wails.Store.New(name, optionalDefault);
}
module.exports = {
New: New,
};

29
runtime/runtime.go Normal file
View File

@@ -0,0 +1,29 @@
package runtime
import "github.com/wailsapp/wails/lib/interfaces"
// Runtime is the Wails Runtime Interface, given to a user who has defined the WailsInit method
type Runtime struct {
Events *Events
Log *Log
Dialog *Dialog
Window *Window
Browser *Browser
FileSystem *FileSystem
Store *StoreProvider
}
// NewRuntime creates a new Runtime struct
func NewRuntime(eventManager interfaces.EventManager, renderer interfaces.Renderer) *Runtime {
result := &Runtime{
Events: NewEvents(eventManager),
Log: NewLog(),
Dialog: NewDialog(renderer),
Window: NewWindow(renderer),
Browser: NewBrowser(),
FileSystem: NewFileSystem(),
}
// We need a reference to itself
result.Store = NewStoreProvider(result)
return result
}

248
runtime/store.go Normal file
View File

@@ -0,0 +1,248 @@
// Package runtime contains all the methods and data structures related to the
// runtime library of Wails. This includes both Go and JS runtimes.
package runtime
import (
"bytes"
"encoding/json"
"fmt"
"log"
"reflect"
"sync"
)
// Options defines the optional data that may be used
// when creating a Store
type Options struct {
// The name of the store
Name string
// The runtime to attach the store to
Runtime *Runtime
// Indicates if notifying Go listeners should be notified of updates
// synchronously (on the current thread) or asynchronously using
// goroutines
NotifySynchronously bool
}
// StoreProvider is a struct that creates Stores
type StoreProvider struct {
runtime *Runtime
}
// NewStoreProvider creates new stores using the provided Runtime reference.
func NewStoreProvider(runtime *Runtime) *StoreProvider {
return &StoreProvider{
runtime: runtime,
}
}
// Store is where we keep named data
type Store struct {
name string
data reflect.Value
dataType reflect.Type
eventPrefix string
callbacks []func(interface{})
runtime *Runtime
notifySynchronously bool
// Lock
mux sync.Mutex
// Error handler
errorHandler func(error)
}
// New creates a new store
func (p *StoreProvider) New(name string, defaultValue interface{}) *Store {
dataType := reflect.TypeOf(defaultValue)
result := Store{
name: name,
runtime: p.runtime,
data: reflect.ValueOf(defaultValue),
dataType: dataType,
}
// Setup the sync listener
result.setupListener()
return &result
}
// OnError takes a function that will be called
// whenever an error occurs
func (s *Store) OnError(callback func(error)) {
s.errorHandler = callback
}
// Processes the updates sent by the front end
func (s *Store) processUpdatedData(data string) error {
// Decode incoming data
var rawdata json.RawMessage
d := json.NewDecoder(bytes.NewBufferString(data))
err := d.Decode(&rawdata)
if err != nil {
return err
}
// Create a new instance of our data and unmarshal
// the received value into it
newData := reflect.New(s.dataType).Interface()
err = json.Unmarshal(rawdata, &newData)
if err != nil {
return err
}
// Lock mutex for writing
s.mux.Lock()
// Handle nulls
if newData == nil {
s.data = reflect.Zero(s.dataType)
} else {
// Store the resultant value in the data store
s.data = reflect.ValueOf(newData).Elem()
}
// Unlock mutex
s.mux.Unlock()
return nil
}
// Setup listener for front end changes
func (s *Store) setupListener() {
// Listen for updates from the front end
s.runtime.Events.On("wails:sync:store:updatedbyfrontend:"+s.name, func(data ...interface{}) {
// Process the incoming data
err := s.processUpdatedData(data[0].(string))
if err != nil {
if s.errorHandler != nil {
s.errorHandler(err)
return
}
}
// Notify listeners
s.notify()
})
}
// notify the listeners of the current data state
func (s *Store) notify() {
// Execute callbacks
for _, callback := range s.callbacks {
if s.notifySynchronously {
callback(s.data)
} else {
go callback(s.data)
}
}
}
// Set will update the data held by the store
// and notify listeners of the change
func (s *Store) Set(data interface{}) error {
inType := reflect.TypeOf(data)
if inType != s.dataType {
return fmt.Errorf("invalid data given in Store.Set(). Expected %s, got %s", s.dataType.String(), inType.String())
}
// Save data
s.mux.Lock()
s.data = reflect.ValueOf(data)
s.mux.Unlock()
// Stringify data
newdata, err := json.Marshal(data)
if err != nil {
if s.errorHandler != nil {
return err
}
}
// Emit event to front end
s.runtime.Events.Emit("wails:sync:store:updatedbybackend:"+s.name, string(newdata))
// Notify subscribers
s.notify()
return nil
}
// Subscribe will subscribe to updates to the store by
// providing a callback. Any updates to the store are sent
// to the callback
func (s *Store) Subscribe(callback func(interface{})) {
s.callbacks = append(s.callbacks, callback)
}
// updaterCheck ensures the given function to Update() is
// of the correct signature. Absolutely cannot wait for
// generics to land rather than writing this nonsense.
func (s *Store) updaterCheck(updater interface{}) error {
// Get type
updaterType := reflect.TypeOf(updater)
// Check updater is a function
if updaterType.Kind() != reflect.Func {
return fmt.Errorf("invalid value given to store.Update(). Expected 'func(%s) %s'", s.dataType.String(), s.dataType.String())
}
// Check input param
if updaterType.NumIn() != 1 {
return fmt.Errorf("invalid number of parameters given in updater function. Expected 1")
}
// Check input data type
if updaterType.In(0) != s.dataType {
return fmt.Errorf("invalid type for input parameter given in updater function. Expected %s, got %s", s.dataType.String(), updaterType.In(0))
}
// Check output param
if updaterType.NumOut() != 1 {
return fmt.Errorf("invalid number of return parameters given in updater function. Expected 1")
}
// Check output data type
if updaterType.Out(0) != s.dataType {
return fmt.Errorf("invalid type for return parameter given in updater function. Expected %s, got %s", s.dataType.String(), updaterType.Out(0))
}
return nil
}
// Update takes a function that is passed the current state.
// The result of that function is then set as the new state
// of the store. This will notify listeners of the change
func (s *Store) Update(updater interface{}) {
err := s.updaterCheck(updater)
if err != nil {
log.Fatal(err)
}
// Build args
args := []reflect.Value{s.data}
// Make call
results := reflect.ValueOf(updater).Call(args)
// We will only have 1 result. Set the store to it
s.Set(results[0].Interface())
}