Compare commits

...

38 Commits

Author SHA1 Message Date
Lea Anthony
a2ac8af882 chore: Bump to version v0.16.5-pre 2019-07-01 18:10:26 +10:00
Lea Anthony
52afbd3f15 fix: revert back to my-app 2019-07-01 09:01:07 +10:00
Lea Anthony
ce35ee5ca8 Merge branch 'bh90210-118-angular-support' into develop 2019-07-01 08:58:37 +10:00
Lea Anthony
74c64c6420 chore: misc updates for template 2019-07-01 08:57:42 +10:00
Lea Anthony
678328b7aa Merge branch '118-angular-support' of git://github.com/bh90210/wails into bh90210-118-angular-support 2019-06-30 18:11:35 +10:00
Lea Anthony
345c8bc094 fix: linting fixes 2019-06-30 17:16:38 +10:00
Lea Anthony
44386490c8 chore: add default case to bridge switch 2019-06-29 23:03:46 +10:00
bh90210
87158a342a feat: angular template 2019-06-29 15:45:48 +03:00
Lea Anthony
0b43fae32a docs: updated contributors 2019-06-29 21:43:19 +10:00
Lea Anthony
89f7a95167 Merge pull request #141 from wailsapp/138-Template-dependency-checker
feat: initial support for template dependencies
2019-06-27 19:56:57 +10:00
Lea Anthony
c5be3e5634 feat: initial support for template dependencies 2019-06-27 09:05:46 +10:00
Lea Anthony
7156740f6c fix: typo 2019-06-27 08:46:01 +10:00
Lea Anthony
2d29b626c7 chore: version bump 2019-06-26 19:50:22 +10:00
Lea Anthony
698145be1e Merge pull request #140 from wailsapp/139-go.mod-should-reflect-current-wails-version
feat: set wails version in go.mod
2019-06-26 19:48:35 +10:00
Lea Anthony
a9188cbfdd feat: set wails version in go.mod 2019-06-26 19:46:51 +10:00
Lea Anthony
d07cca0278 chore: version bump 2019-06-25 18:49:18 +10:00
Lea Anthony
60d1dc51ad Merge pull request #137 from wailsapp/135-Add-Debian-support
135 add debian support
2019-06-25 18:48:24 +10:00
Lea Anthony
105073e412 fix: add Debian support across tooling 2019-06-25 18:32:25 +10:00
Lea Anthony
9d1f1fff47 feat: debian support 2019-06-25 18:29:57 +10:00
Lea Anthony
08050ec35e Merge pull request #134 from wailsapp/133-Unsupported-Platform-Requests
133 unsupported platform requests
2019-06-25 08:18:06 +10:00
Lea Anthony
bd9751d888 feat: Support distribution support requests 2019-06-25 08:13:20 +10:00
Lea Anthony
7d171b0907 feat: initial support for platform requests 2019-06-24 09:11:06 +10:00
Lea Anthony
5b8f311465 Merge pull request #130 from wailsapp/123-Unify-Runtime-APIs
fix: linting
2019-06-22 08:47:25 +10:00
Lea Anthony
801465ac51 fix: linting 2019-06-22 08:45:46 +10:00
Lea Anthony
a84e2ae9b3 Merge pull request #129 from wailsapp/123-Unify-Runtime-APIs
feat: unify runtime API signatures
2019-06-22 08:43:23 +10:00
Lea Anthony
9496d1d47f Merge pull request #126 from bh90210/121-react-template-build-error
fix(react template): reverting bugfix + code clean-up
2019-06-22 08:39:16 +10:00
Lea Anthony
36e575e0a2 feat: unify runtime API signatures 2019-06-22 08:36:11 +10:00
ktc
70ccb8942b fix(react template): reverting bugfix + code clean-up 2019-06-19 20:09:23 +03:00
Lea Anthony
d3cd3d43bd chore: version bump 2019-06-19 21:04:27 +10:00
Lea Anthony
9116f0d06c Merge pull request #124 from wailsapp/116-Add-browser-methods-to-runtime
116 add browser methods to runtime
2019-06-19 21:01:53 +10:00
Lea Anthony
2c91e26add docs: guardrails badge 2019-06-19 21:01:00 +10:00
Lea Anthony
f1647443dc chore: add .jshintrc file to indicate es6 2019-06-19 20:54:36 +10:00
Lea Anthony
b6b6ce2d4a fix: linting fix 2019-06-19 20:53:04 +10:00
Lea Anthony
abcc869537 feat: added OpenFile 2019-06-19 20:49:39 +10:00
Lea Anthony
3e02e1676a Merge pull request #122 from bh90210/121-react-template-build-error
fix(react template): build bugfix
2019-06-19 08:31:57 +10:00
Lea Anthony
5c8a4de446 fix: version 2019-06-19 08:29:15 +10:00
Lea Anthony
7cabef946e feat: initial support for browser.openURL for f/e 2019-06-19 08:28:31 +10:00
ktc
f2519e5af2 fix(react template): build bugfix 2019-06-18 13:57:45 +03:00
65 changed files with 1437 additions and 305 deletions

29
.eslintrc.js Normal file
View File

@@ -0,0 +1,29 @@
module.exports = {
"env": {
"browser": true,
"es6": true
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": 2016,
"sourceType": "module",
},
"rules": {
"indent": [
"error",
"tab"
],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"error",
"single"
],
"semi": [
"error",
"always"
]
}
};

3
.jshintrc Normal file
View File

@@ -0,0 +1,3 @@
{
"esversion": 6
}

View File

@@ -1,3 +1,4 @@
{ {
"go.formatTool": "goimports" "go.formatTool": "goimports",
"eslint.alwaysShowStatus": true
} }

View File

@@ -12,3 +12,4 @@ Wails is what it is because of the time and effort given by these great people.
* [intelwalk](https://github.com/intelwalk) * [intelwalk](https://github.com/intelwalk)
* [Mark Stenglein](https://github.com/ocelotsloth) * [Mark Stenglein](https://github.com/ocelotsloth)
* [admin_3.exe](https://github.com/bh90210) * [admin_3.exe](https://github.com/bh90210)
* [iceleo-com](https://github.com/iceleo-com)

View File

@@ -10,6 +10,7 @@
<a href="https://github.com/wailsapp/wails/issues"><img src="https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat" alt="CodeFactor" /></a> <a href="https://github.com/wailsapp/wails/issues"><img src="https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat" alt="CodeFactor" /></a>
<a href="https://houndci.com"><img src="https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg"/></a> <a href="https://houndci.com"><img src="https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg"/></a>
<a href="https://github.com/avelino/awesome-go" rel="nofollow"><img src="https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg" alt="Awesome"></a> <a href="https://github.com/avelino/awesome-go" rel="nofollow"><img src="https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg" alt="Awesome"></a>
<a href="https://dashboard.guardrails.io/default/gh/wailsapp/wails"><img src="https://badges.guardrails.io/wailsapp/wails.svg?token=53657bc22ec360d7673c894fdd70568e918ec581d10d84427ed4de5fe1eeff1a"></a>
</p> </p>
The traditional method of providing web interfaces to Go programs is via a built-in web server. Wails offers a different approach: it provides the ability to wrap both Go code and a web frontend into a single binary. Tools are provided to make this easy for you by handling project creation, compilation and bundling. All you have to do is get creative! The traditional method of providing web interfaces to Go programs is via a built-in web server. Wails offers a different approach: it provides the ability to wrap both Go code and a web frontend into a single binary. Tools are provided to make this easy for you by handling project creation, compilation and bundling. All you have to do is get creative!
@@ -45,7 +46,7 @@ Make sure you have the xcode command line tools installed. This can be done by r
### Linux ### Linux
#### Ubuntu 18.04 #### Ubuntu 18.04, Debian 9
`sudo apt install pkg-config build-essential libgtk-3-dev libwebkit2gtk-4.0-dev` `sudo apt install pkg-config build-essential libgtk-3-dev libwebkit2gtk-4.0-dev`

65
binding_internal.go Normal file
View File

@@ -0,0 +1,65 @@
package wails
import "strings"
import "fmt"
type internalMethods struct{
log *CustomLogger
browser *RuntimeBrowser
}
func newInternalMethods() *internalMethods {
return &internalMethods{
log: newCustomLogger("InternalCall"),
browser: newRuntimeBrowser(),
}
}
func (i *internalMethods) processCall(callData *callData) (interface{}, error) {
if !strings.HasPrefix(callData.BindingName, ".wails.") {
return nil, fmt.Errorf("Invalid call signature '%s'", callData.BindingName)
}
// Strip prefix
var splitCall = strings.Split(callData.BindingName,".")[2:]
if len(splitCall) != 2 {
return nil, fmt.Errorf("Invalid call signature '%s'", callData.BindingName)
}
group := splitCall[0]
switch group {
case "Browser":
return i.processBrowserCommand(splitCall[1], callData.Data)
default:
return nil, fmt.Errorf("Unknown internal command group '%s'", group)
}
}
func (i *internalMethods) processBrowserCommand(command string, data interface{}) (interface{}, error) {
switch command {
case "OpenURL":
url := data.(string)
// Strip string quotes. Credit: https://stackoverflow.com/a/44222648
if url[0] == '"' {
url = url[1:]
}
if i := len(url)-1; url[i] == '"' {
url = url[:i]
}
i.log.Debugf("Calling Browser.OpenURL with '%s'", url)
return nil, i.browser.OpenURL(url)
case "OpenFile":
filename := data.(string)
// Strip string quotes. Credit: https://stackoverflow.com/a/44222648
if filename[0] == '"' {
filename = filename[1:]
}
if i := len(filename)-1; filename[i] == '"' {
filename = filename[:i]
}
i.log.Debugf("Calling Browser.OpenFile with '%s'", filename)
return nil, i.browser.OpenFile(filename)
default:
return nil, fmt.Errorf("Unknown Browser command '%s'", command)
}
}

View File

@@ -17,6 +17,7 @@ binding:
type bindingManager struct { type bindingManager struct {
methods map[string]*boundMethod methods map[string]*boundMethod
functions map[string]*boundFunction functions map[string]*boundFunction
internalMethods *internalMethods
initMethods []*boundMethod initMethods []*boundMethod
log *CustomLogger log *CustomLogger
renderer Renderer renderer Renderer
@@ -27,9 +28,10 @@ type bindingManager struct {
func newBindingManager() *bindingManager { func newBindingManager() *bindingManager {
result := &bindingManager{ result := &bindingManager{
methods: make(map[string]*boundMethod), methods: make(map[string]*boundMethod),
functions: make(map[string]*boundFunction), functions: make(map[string]*boundFunction),
log: newCustomLogger("Bind"), log: newCustomLogger("Bind"),
internalMethods: newInternalMethods(),
} }
return result return result
} }
@@ -163,6 +165,11 @@ func (b *bindingManager) bind(object interface{}) {
b.objectsToBind = append(b.objectsToBind, object) b.objectsToBind = append(b.objectsToBind, object)
} }
func (b *bindingManager) processInternalCall(callData *callData) (interface{}, error) {
// Strip prefix
return b.internalMethods.processCall(callData)
}
func (b *bindingManager) processFunctionCall(callData *callData) (interface{}, error) { func (b *bindingManager) processFunctionCall(callData *callData) (interface{}, error) {
// Return values // Return values
var result []reflect.Value var result []reflect.Value
@@ -254,6 +261,8 @@ func (b *bindingManager) processCall(callData *callData) (result interface{}, er
result, err = b.processFunctionCall(callData) result, err = b.processFunctionCall(callData)
case 2: case 2:
result, err = b.processMethodCall(callData) result, err = b.processMethodCall(callData)
case 3:
result, err = b.processInternalCall(callData)
default: default:
result = nil result = nil
err = fmt.Errorf("Invalid binding name '%s'", callData.BindingName) err = fmt.Errorf("Invalid binding name '%s'", callData.BindingName)

10
cmd/cmd-mewn.go Normal file

File diff suppressed because one or more lines are too long

View File

@@ -3,9 +3,12 @@ package cmd
import ( import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"net/url"
"os" "os"
"regexp" "runtime"
"strings" "strings"
"github.com/pkg/browser"
) )
// LinuxDistribution is of type int // LinuxDistribution is of type int
@@ -20,6 +23,8 @@ const (
Arch Arch
// RedHat linux distribution // RedHat linux distribution
RedHat RedHat
// Debian distribution
Debian
) )
// DistroInfo contains all the information relating to a linux distribution // DistroInfo contains all the information relating to a linux distribution
@@ -29,6 +34,7 @@ type DistroInfo struct {
Release string Release string
Codename string Codename string
DistributorID string DistributorID string
DiscoveredBy string
} }
// GetLinuxDistroInfo returns information about the running linux distribution // GetLinuxDistroInfo returns information about the running linux distribution
@@ -43,7 +49,7 @@ func GetLinuxDistroInfo() *DistroInfo {
if err != nil { if err != nil {
return result return result
} }
result.DiscoveredBy = "lsb"
for _, line := range strings.Split(stdout, "\n") { for _, line := range strings.Split(stdout, "\n") {
if strings.Contains(line, ":") { if strings.Contains(line, ":") {
// Iterate lines a // Iterate lines a
@@ -58,6 +64,8 @@ func GetLinuxDistroInfo() *DistroInfo {
result.Distribution = Ubuntu result.Distribution = Ubuntu
case "Arch", "ManjaroLinux": case "Arch", "ManjaroLinux":
result.Distribution = Arch result.Distribution = Arch
case "Debian":
result.Distribution = Debian
} }
case "Description": case "Description":
result.Description = value result.Description = value
@@ -65,21 +73,37 @@ func GetLinuxDistroInfo() *DistroInfo {
result.Release = value result.Release = value
case "Codename": case "Codename":
result.Codename = value result.Codename = value
} }
} }
} }
// check if /etc/os-release exists // check if /etc/os-release exists
} else if _, err := os.Stat("/etc/os-release"); !os.IsNotExist(err) { } else if _, err := os.Stat("/etc/os-release"); !os.IsNotExist(err) {
// Default value
osName := "Unknown"
version := ""
// read /etc/os-release // read /etc/os-release
osRelease, _ := ioutil.ReadFile("/etc/os-release") osRelease, _ := ioutil.ReadFile("/etc/os-release")
// compile a regex to find NAME=distro // Split into lines
re := regexp.MustCompile(`^NAME=(.*)\n`) lines := strings.Split(string(osRelease), "\n")
// extract the distro name // Iterate lines
osName := string(re.FindSubmatch(osRelease)[1]) for _, line := range lines {
// strip quotations // Split each line by the equals char
osName = strings.Trim(osName, "\"") splitLine := strings.SplitN(line, "=", 2)
// Check we have
if len(splitLine) != 2 {
continue
}
switch splitLine[0] {
case "NAME":
osName = strings.Trim(splitLine[1], "\"")
case "VERSION_ID":
version = strings.Trim(splitLine[1], "\"")
}
}
// Check distro name against list of distros // Check distro name against list of distros
result.Release = version
result.DiscoveredBy = "os-release"
switch osName { switch osName {
case "Fedora": case "Fedora":
result.Distribution = RedHat result.Distribution = RedHat
@@ -87,6 +111,11 @@ func GetLinuxDistroInfo() *DistroInfo {
result.Distribution = RedHat result.Distribution = RedHat
case "Arch Linux": case "Arch Linux":
result.Distribution = Arch result.Distribution = Arch
case "Debian GNU/Linux":
result.Distribution = Debian
default:
result.Distribution = Unknown
result.DistributorID = osName
} }
} }
return result return result
@@ -124,3 +153,45 @@ func RpmInstalled(packageName string) (bool, error) {
_, _, exitCode, _ := rpm.Run("--query", packageName) _, _, exitCode, _ := rpm.Run("--query", packageName)
return exitCode == 0, nil return exitCode == 0, nil
} }
// RequestSupportForDistribution promts the user to submit a request to support their
// currently unsupported distribution
func RequestSupportForDistribution(distroInfo *DistroInfo, libraryName string) error {
var logger = NewLogger()
defaultError := fmt.Errorf("unable to check libraries on distribution '%s'. Please ensure that the '%s' equivalent is installed", distroInfo.DistributorID, libraryName)
logger.Yellow("Distribution '%s' is not currently supported, but we would love to!", distroInfo.DistributorID)
q := fmt.Sprintf("Would you like to submit a request to support distribution '%s'?", distroInfo.DistributorID)
result := Prompt(q, "yes")
if strings.ToLower(result) != "yes" {
return defaultError
}
title := fmt.Sprintf("Support Distribution '%s'", distroInfo.DistributorID)
var str strings.Builder
gomodule, exists := os.LookupEnv("GO111MODULE")
if !exists {
gomodule = "(Not Set)"
}
str.WriteString("\n| Name | Value |\n| ----- | ----- |\n")
str.WriteString(fmt.Sprintf("| Wails Version | %s |\n", Version))
str.WriteString(fmt.Sprintf("| Go Version | %s |\n", runtime.Version()))
str.WriteString(fmt.Sprintf("| Platform | %s |\n", runtime.GOOS))
str.WriteString(fmt.Sprintf("| Arch | %s |\n", runtime.GOARCH))
str.WriteString(fmt.Sprintf("| GO111MODULE | %s |\n", gomodule))
str.WriteString(fmt.Sprintf("| Distribution ID | %s |\n", distroInfo.DistributorID))
str.WriteString(fmt.Sprintf("| Distribution Version | %s |\n", distroInfo.Release))
str.WriteString(fmt.Sprintf("| Discovered by | %s |\n", distroInfo.DiscoveredBy))
body := fmt.Sprintf("**Description**\nDistribution '%s' is currently unsupported.\n\n**Further Information**\n\n%s\n\n*Please add any extra information here, EG: libraries that are needed to make the distribution work, or commands to install them*", distroInfo.DistributorID, str.String())
fullURL := "https://github.com/wailsapp/wails/issues/new?"
params := "title=" + title + "&body=" + body
fmt.Println("Opening browser to file request.")
browser.OpenURL(fullURL + url.PathEscape(params))
return nil
}

View File

@@ -49,11 +49,10 @@ func getRequiredProgramsLinux() *Prerequisites {
result := &Prerequisites{} result := &Prerequisites{}
distroInfo := GetLinuxDistroInfo() distroInfo := GetLinuxDistroInfo()
switch distroInfo.Distribution { switch distroInfo.Distribution {
case Ubuntu: case Ubuntu, Debian:
result.Add(newPrerequisite("gcc", "Please install with `sudo apt install build-essentials` and try again")) result.Add(newPrerequisite("gcc", "Please install with `sudo apt install build-essentials` and try again"))
result.Add(newPrerequisite("pkg-config", "Please install with `sudo apt install pkg-config` and try again")) result.Add(newPrerequisite("pkg-config", "Please install with `sudo apt install pkg-config` and try again"))
result.Add(newPrerequisite("npm", "Please install with `sudo snap install node --channel=12/stable --classic` and try again")) result.Add(newPrerequisite("npm", "Please install with `sudo snap install node --channel=12/stable --classic` and try again"))
default: default:
result.Add(newPrerequisite("gcc", "Please install with your system package manager and try again")) result.Add(newPrerequisite("gcc", "Please install with your system package manager and try again"))
result.Add(newPrerequisite("pkg-config", "Please install with your system package manager and try again")) result.Add(newPrerequisite("pkg-config", "Please install with your system package manager and try again"))

View File

@@ -143,11 +143,13 @@ type ProjectOptions struct {
log *Logger log *Logger
templates *TemplateHelper templates *TemplateHelper
selectedTemplate *TemplateDetails selectedTemplate *TemplateDetails
WailsVersion string
} }
// Defaults sets the default project template // Defaults sets the default project template
func (po *ProjectOptions) Defaults() { func (po *ProjectOptions) Defaults() {
po.Template = "vuebasic" po.Template = "vuebasic"
po.WailsVersion = Version
} }
// PromptForInputs asks the user to input project details // PromptForInputs asks the user to input project details

View File

@@ -272,7 +272,7 @@ func CheckDependencies(logger *Logger) (bool, error) {
distroInfo := GetLinuxDistroInfo() distroInfo := GetLinuxDistroInfo()
for _, library := range *requiredLibraries { for _, library := range *requiredLibraries {
switch distroInfo.Distribution { switch distroInfo.Distribution {
case Ubuntu: case Ubuntu, Debian:
installed, err := DpkgInstalled(library.Name) installed, err := DpkgInstalled(library.Name)
if err != nil { if err != nil {
return false, err return false, err
@@ -295,7 +295,6 @@ func CheckDependencies(logger *Logger) (bool, error) {
logger.Green("Library '%s' installed.", library.Name) logger.Green("Library '%s' installed.", library.Name)
} }
case RedHat: case RedHat:
installed, err := RpmInstalled(library.Name) installed, err := RpmInstalled(library.Name)
if err != nil { if err != nil {
return false, err return false, err
@@ -307,7 +306,7 @@ func CheckDependencies(logger *Logger) (bool, error) {
logger.Green("Library '%s' installed.", library.Name) logger.Green("Library '%s' installed.", library.Name)
} }
default: default:
return false, fmt.Errorf("unable to check libraries on distribution '%s'. Please ensure that the '%s' equivalent is installed", distroInfo.DistributorID, library.Name) return false, RequestSupportForDistribution(distroInfo, library.Name)
} }
} }
} }

View File

@@ -16,18 +16,26 @@ import (
// TemplateMetadata holds all the metadata for a Wails template // TemplateMetadata holds all the metadata for a Wails template
type TemplateMetadata struct { type TemplateMetadata struct {
Name string `json:"name"` Name string `json:"name"`
Version string `json:"version"` Version string `json:"version"`
ShortDescription string `json:"shortdescription"` ShortDescription string `json:"shortdescription"`
Description string `json:"description"` Description string `json:"description"`
Install string `json:"install"` Install string `json:"install"`
Build string `json:"build"` Build string `json:"build"`
Author string `json:"author"` Author string `json:"author"`
Created string `json:"created"` Created string `json:"created"`
FrontendDir string `json:"frontenddir"` FrontendDir string `json:"frontenddir"`
Serve string `json:"serve"` Serve string `json:"serve"`
Bridge string `json:"bridge"` Bridge string `json:"bridge"`
WailsDir string `json:"wailsdir"` WailsDir string `json:"wailsdir"`
TemplateDependencies []*TemplateDependency `json:"dependencies,omitempty"`
}
// TemplateDependency defines a binary dependency for the template
// EG: ng for angular
type TemplateDependency struct {
Bin string `json:"bin"`
Help string `json:"help"`
} }
// TemplateDetails holds information about a specific template // TemplateDetails holds information about a specific template
@@ -152,6 +160,31 @@ func (t *TemplateHelper) GetTemplateFilenames(template *TemplateDetails) (*slice
// project path given // project path given
func (t *TemplateHelper) InstallTemplate(projectPath string, projectOptions *ProjectOptions) error { func (t *TemplateHelper) InstallTemplate(projectPath string, projectOptions *ProjectOptions) error {
// Check dependencies before installing
dependencies := projectOptions.selectedTemplate.Metadata.TemplateDependencies
if dependencies != nil {
programHelper := NewProgramHelper()
logger := NewLogger()
errors := []string{}
for _, dep := range dependencies {
program := programHelper.FindProgram(dep.Bin)
if program == nil {
errors = append(errors, dep.Help)
}
}
if len(errors) > 0 {
mainError := "template dependencies not installed"
if len(errors) == 1 {
mainError = errors[0]
} else {
for _, error := range errors {
logger.Red(error)
}
}
return fmt.Errorf(mainError)
}
}
// Get template files // Get template files
templateFilenames, err := t.GetTemplateFilenames(projectOptions.selectedTemplate) templateFilenames, err := t.GetTemplateFilenames(projectOptions.selectedTemplate)
if err != nil { if err != nil {
@@ -160,6 +193,9 @@ func (t *TemplateHelper) InstallTemplate(projectPath string, projectOptions *Pro
templatePath := projectOptions.selectedTemplate.Path templatePath := projectOptions.selectedTemplate.Path
// Save the version
projectOptions.WailsVersion = Version
templateJSONFilename := filepath.Join(templatePath, t.metadataFilename) templateJSONFilename := filepath.Join(templatePath, t.metadataFilename)
templateFiles := templateFilenames.Filter(func(filename string) bool { templateFiles := templateFilenames.Filter(func(filename string) bool {

View File

@@ -0,0 +1,13 @@
# Editor configuration, see https://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
max_line_length = off
trim_trailing_whitespace = false

View File

@@ -0,0 +1,47 @@
# See http://help.github.com/ignore-files/ for more about ignoring files.
# compiled output
/dist
/tmp
/out-tsc
# Only exists if Bazel was run
/bazel-out
# dependencies
/node_modules
# profiling files
chrome-profiler-events.json
speed-measure-plugin.json
# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*
# misc
/.sass-cache
/connect.lock
/coverage
/libpeerconnection.log
npm-debug.log
yarn-error.log
testem.log
/typings
# System Files
.DS_Store
Thumbs.db
.editorcinfig

View File

@@ -0,0 +1,27 @@
# MyApp
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.0.3.
## Development server
Run `npx ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
## Code scaffolding
Run `npx ng generate component component-name` to generate a new component. You can also use `npx ng generate directive|pipe|service|class|guard|interface|enum|module`.
## Build
Run `npx ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
## Running unit tests
Run `npx ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
## Running end-to-end tests
Run `npx ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
## Further help
To get more help on the Angular CLI use `npx ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).

View File

@@ -0,0 +1,121 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"my-app": {
"projectType": "application",
"schematics": {},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "ngx-build-plus:browser",
"options": {
"outputPath": "dist/my-app",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"aot": false,
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.css"
],
"scripts": []
},
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
}
]
}
}
},
"serve": {
"builder": "ngx-build-plus:dev-server",
"options": {
"browserTarget": "my-app:build"
},
"configurations": {
"production": {
"browserTarget": "my-app:build:production"
}
}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "my-app:build"
}
},
"test": {
"builder": "ngx-build-plus:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.css"
],
"scripts": []
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"tsconfig.app.json",
"tsconfig.spec.json",
"e2e/tsconfig.json"
],
"exclude": [
"**/node_modules/**"
]
}
},
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "my-app:serve"
},
"configurations": {
"production": {
"devServerTarget": "my-app:serve:production"
}
}
}
}
}
},
"defaultProject": "my-app"
}

View File

@@ -0,0 +1,12 @@
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries
# You can see what browsers were selected by your queries by running:
# npx browserslist
> 0.5%
last 2 versions
Firefox ESR
not dead
not IE 9-11 # For IE 9-11 support, remove 'not'.

View File

@@ -0,0 +1,32 @@
// @ts-check
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts
const { SpecReporter } = require('jasmine-spec-reporter');
/**
* @type { import("protractor").Config }
*/
exports.config = {
allScriptsTimeout: 11000,
specs: [
'./src/**/*.e2e-spec.ts'
],
capabilities: {
'browserName': 'chrome'
},
directConnect: true,
baseUrl: 'http://localhost:4200/',
framework: 'jasmine',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {}
},
onPrepare() {
require('ts-node').register({
project: require('path').join(__dirname, './tsconfig.json')
});
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
}
};

View File

@@ -0,0 +1,23 @@
import { AppPage } from './app.po';
import { browser, logging } from 'protractor';
describe('workspace-project App', () => {
let page: AppPage;
beforeEach(() => {
page = new AppPage();
});
it('should display welcome message', () => {
page.navigateTo();
expect(page.getTitleText()).toEqual('Welcome to my-app!');
});
afterEach(async () => {
// Assert that there are no errors emitted from the browser
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
expect(logs).not.toContain(jasmine.objectContaining({
level: logging.Level.SEVERE,
} as logging.Entry));
});
});

View File

@@ -0,0 +1,11 @@
import { browser, by, element } from 'protractor';
export class AppPage {
navigateTo() {
return browser.get(browser.baseUrl) as Promise<any>;
}
getTitleText() {
return element(by.css('app-root h1')).getText() as Promise<string>;
}
}

View File

@@ -0,0 +1,13 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/e2e",
"module": "commonjs",
"target": "es5",
"types": [
"jasmine",
"jasminewd2",
"node"
]
}
}

View File

@@ -0,0 +1,32 @@
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular-devkit/build-angular'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'),
require('@angular-devkit/build-angular/plugins/karma')
],
client: {
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
coverageIstanbulReporter: {
dir: require('path').join(__dirname, './coverage/my-app'),
reports: ['html', 'lcovonly', 'text-summary'],
fixWebpackSourcePaths: true
},
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false,
restartOnFileChange: true
});
};

View File

@@ -0,0 +1,50 @@
{
"name": "my-app",
"version": "0.0.0",
"scripts": {
"ng": "npx ng",
"start": "npx ng serve --poll=2000",
"build": "npx ng build --single-bundle true --output-hashing none --prod --bundle-styles false",
"test": "npx ng test",
"lint": "npx ng lint",
"e2e": "npx ng e2e"
},
"private": true,
"dependencies": {
"@angular/animations": "^8.0.2",
"@angular/cdk": "^8.0.1",
"@angular/common": "~8.0.1",
"@angular/compiler": "~8.0.1",
"@angular/core": "~8.0.1",
"@angular/forms": "~8.0.1",
"@angular/material": "^8.0.1",
"@angular/platform-browser": "~8.0.1",
"@angular/platform-browser-dynamic": "~8.0.1",
"@angular/router": "~8.0.1",
"ngx-build-plus": "^8.0.3",
"rxjs": "~6.4.0",
"tslib": "^1.9.0",
"zone.js": "~0.9.1"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.800.0",
"@angular/cli": "~8.0.3",
"@angular/compiler-cli": "~8.0.1",
"@angular/language-service": "~8.0.1",
"@types/node": "~8.9.4",
"@types/jasmine": "~3.3.8",
"@types/jasminewd2": "~2.0.3",
"codelyzer": "^5.0.0",
"jasmine-core": "~3.4.0",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~4.1.0",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage-istanbul-reporter": "~2.0.1",
"karma-jasmine": "~2.0.1",
"karma-jasmine-html-reporter": "^1.4.0",
"protractor": "~5.4.0",
"ts-node": "~7.0.0",
"tslint": "~5.15.0",
"typescript": "~3.4.3"
}
}

View File

@@ -0,0 +1,13 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
const routes: Routes = [];
@NgModule({
imports: [
RouterModule.forRoot(routes)
],
exports: [RouterModule]
})
export class AppRoutingModule { }

View File

@@ -0,0 +1,14 @@
<!--The content below is only a placeholder and can be replaced.-->
<div style="text-align:center">
<h1>
Welcome to {{ title }}!
</h1>
<img width="300" alt="Angular Logo"
src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg==">
<br />
<button (click)="onClickMe()">Hello</button>
<p>{{clickMessage}}</p>
</div>
<router-outlet></router-outlet>

View File

@@ -0,0 +1,35 @@
import { TestBed, async } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule
],
declarations: [
AppComponent
],
}).compileComponents();
}));
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
});
it(`should have as title 'my-app'`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app.title).toEqual('my-app');
});
it('should render title in a h1 tag', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.debugElement.nativeElement;
expect(compiled.querySelector('h1').textContent).toContain('Welcome to my-app!');
});
});

View File

@@ -0,0 +1,19 @@
import { Component } from '@angular/core';
@Component({
selector: '[id="app"]',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'my-app';
clickMessage = '';
onClickMe() {
// @ts-ignore
window.backend.basic().then(result =>
this.clickMessage = result
);
}
}

View File

@@ -0,0 +1,20 @@
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { APP_BASE_HREF } from '@angular/common';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule
],
providers: [{provide: APP_BASE_HREF, useValue : '/' }],
bootstrap: [AppComponent]
})
export class AppModule { }

View File

@@ -0,0 +1,3 @@
export const environment = {
production: true
};

View File

@@ -0,0 +1,16 @@
// This file can be replaced during build by using the `fileReplacements` array.
// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
// The list of file replacements can be found in `angular.json`.
export const environment = {
production: false
};
/*
* For easier debugging in development mode, you can import the following file
* to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
*
* This import should be commented out in production mode because it will have a negative impact
* on performance if an error is thrown.
*/
// import 'zone.js/dist/zone-error'; // Included with Angular CLI.

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@@ -0,0 +1,14 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>my-app</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<div id="app"></div>
</body>
</html>

View File

@@ -0,0 +1,18 @@
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
import 'zone.js'
import Bridge from './wailsbridge';
if (environment.production) {
enableProdMode();
}
Bridge.Start(() => {
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
});

View File

@@ -0,0 +1,63 @@
/**
* This file includes polyfills needed by Angular and is loaded before the app.
* You can add your own extra polyfills to this file.
*
* This file is divided into 2 sections:
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
* file.
*
* The current setup is for so-called "evergreen" browsers; the last versions of browsers that
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
*
* Learn more in https://angular.io/guide/browser-support
*/
/***************************************************************************************************
* BROWSER POLYFILLS
*/
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
// import 'classlist.js'; // Run `npm install --save classlist.js`.
/**
* Web Animations `@angular/platform-browser/animations`
* Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
* Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
*/
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
/**
* By default, zone.js will patch all possible macroTask and DomEvents
* user can disable parts of macroTask/DomEvents patch by setting following flags
* because those flags need to be set before `zone.js` being loaded, and webpack
* will put import in the top of bundle, so user need to create a separate file
* in this directory (for example: zone-flags.ts), and put the following flags
* into that file, and then add the following code before importing zone.js.
* import './zone-flags.ts';
*
* The flags allowed in zone-flags.ts are listed here.
*
* The following flags will work for all browsers.
*
* (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
* (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
* (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
*
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
* with the following flag, it will bypass `zone.js` patch for IE/Edge
*
* (window as any).__Zone_enable_cross_context_check = true;
*
*/
/***************************************************************************************************
* Zone JS is required by default for Angular itself.
*/
//import 'zone.js/dist/zone'; // Included with Angular CLI.
/***************************************************************************************************
* APPLICATION IMPORTS
*/

View File

@@ -0,0 +1,24 @@
/* You can add global styles to this file, and also import other style files */
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background-color: #282c34;
}
p {
color: white
}
h1 {
color: white
}
button {
background-color: white;
color: black;
}

View File

@@ -0,0 +1,20 @@
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js/dist/zone-testing';
import { getTestBed } from '@angular/core/testing';
import {
BrowserDynamicTestingModule,
platformBrowserDynamicTesting
} from '@angular/platform-browser-dynamic/testing';
declare const require: any;
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);
// Then we find all the tests.
const context = require.context('./', true, /\.spec\.ts$/);
// And load the modules.
context.keys().map(context);

View File

@@ -0,0 +1,17 @@
/*
Wails Bridge (c) 2019-present Lea Anthony
This prod version is to get around having to rewrite your code
for production. When doing a release build, this file will be used
instead of the full version.
*/
export default {
// The main function
// Passes the main Wails object to the callback if given.
Start: function(callback) {
if (callback) {
window.wails.events.on("wails:ready", callback);
}
}
};

View File

@@ -0,0 +1,14 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/app",
"types": []
},
"include": [
"src/**/*.ts"
],
"exclude": [
"src/test.ts",
"src/**/*.spec.ts"
]
}

View File

@@ -0,0 +1,23 @@
{
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist/out-tsc",
"sourceMap": true,
"declaration": false,
"downlevelIteration": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"module": "esnext",
"moduleResolution": "node",
"importHelpers": true,
"target": "es2015",
"typeRoots": [
"node_modules/@types"
],
"lib": [
"es2018",
"dom"
]
}
}

View File

@@ -0,0 +1,18 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/spec",
"types": [
"jasmine",
"node"
]
},
"files": [
"src/test.ts",
"src/polyfills.ts"
],
"include": [
"src/**/*.spec.ts",
"src/**/*.d.ts"
]
}

View File

@@ -0,0 +1,92 @@
{
"extends": "tslint:recommended",
"rules": {
"array-type": false,
"arrow-parens": false,
"deprecation": {
"severity": "warn"
},
"component-class-suffix": true,
"contextual-lifecycle": true,
"directive-class-suffix": true,
"directive-selector": [
true,
"attribute",
"app",
"camelCase"
],
"component-selector": [
true,
"element",
"app",
"kebab-case"
],
"import-blacklist": [
true,
"rxjs/Rx"
],
"interface-name": false,
"max-classes-per-file": false,
"max-line-length": [
true,
140
],
"member-access": false,
"member-ordering": [
true,
{
"order": [
"static-field",
"instance-field",
"static-method",
"instance-method"
]
}
],
"no-consecutive-blank-lines": false,
"no-console": [
true,
"debug",
"info",
"time",
"timeEnd",
"trace"
],
"no-empty": false,
"no-inferrable-types": [
true,
"ignore-params"
],
"no-non-null-assertion": true,
"no-redundant-jsdoc": true,
"no-switch-case-fall-through": true,
"no-use-before-declare": true,
"no-var-requires": false,
"object-literal-key-quotes": [
true,
"as-needed"
],
"object-literal-sort-keys": false,
"ordered-imports": false,
"quotemark": [
true,
"single"
],
"trailing-comma": false,
"no-conflicting-lifecycle": true,
"no-host-metadata-property": true,
"no-input-rename": true,
"no-inputs-metadata-property": true,
"no-output-native": true,
"no-output-on-prefix": true,
"no-output-rename": true,
"no-outputs-metadata-property": true,
"template-banana-in-box": true,
"template-no-negated-async": true,
"use-lifecycle-interface": true,
"use-pipe-transform-interface": true
},
"rulesDirectory": [
"codelyzer"
]
}

View File

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

View File

@@ -0,0 +1,27 @@
package main
import (
"github.com/leaanthony/mewn"
"github.com/wailsapp/wails"
)
func basic() string {
return "World!"
}
func main() {
js := mewn.String("./frontend/dist/my-app/main-es2015.js")
css := mewn.String("./frontend/dist/my-app/styles.css")
app := wails.CreateApp(&wails.AppConfig{
Width: 1024,
Height: 768,
Title: "{{.Name}}",
JS: js,
CSS: css,
Colour: "#131313",
})
app.Bind(basic)
app.Run()
}

View File

@@ -0,0 +1,20 @@
{
"name": "Angular",
"version": "1.0.0",
"shortdescription": "Angular 8 template",
"description": "Angular projects w/ @angular/cli - Note: in order to reach the cli use npx like this: npx ng",
"dependencies": [
{
"bin": "npx",
"help": "This template requires 'npx'. Please install with 'npm install -g npx'"
}
],
"install": "npm install",
"build": "npx ng build --single-bundle true --output-hashing none --prod --bundle-styles false",
"author": "bh90210 <ktc@pm.me>",
"created": "2019-06-15 18:23:48.666414555 +0300 EEST m=+223.934866008",
"frontenddir": "frontend",
"serve": "npx ng serve --poll=2000",
"bridge": "src",
"wailsdir": ""
}

View File

@@ -0,0 +1,3 @@
{
"esversion": 6
}

View File

@@ -26,22 +26,8 @@ class HelloWorld extends React.Component {
this.setState({ showModal: false }); this.setState({ showModal: false });
} }
startAsync() {
this.setState({
loading: true
});
window.backend.basic().then(result =>
this.setState({
loading: false,
result
})
);
}
render() { render() {
const { loading, result } = this.state; const { result } = this.state;
return ( return (
<div className="App"> <div className="App">
<button onClick={this.handleOpenModal} type="button"> <button onClick={this.handleOpenModal} type="button">

View File

@@ -9,9 +9,9 @@
export default { export default {
// The main function // The main function
// Passes the main Wails object to the callback if given. // Passes the main Wails object to the callback if given.
Start: function(callback) { Start: function (callback) {
if (callback) { if (callback) {
window.wails.events.on("wails:ready", callback); window.wails.Events.On("wails:ready", callback);
} }
} }
}; };

View File

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

View File

@@ -0,0 +1,3 @@
{
"esversion": 6
}

View File

@@ -9,9 +9,9 @@
export default { export default {
// The main function // The main function
// Passes the main Wails object to the callback if given. // Passes the main Wails object to the callback if given.
Start: function(callback) { Start: function (callback) {
if (callback) { if (callback) {
window.wails.events.on("wails:ready", callback); window.wails.Events.On("wails:ready", callback);
} }
} }
}; };

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
package cmd package cmd
// Version - Wails version // Version - Wails version
const Version = "v0.16.0" const Version = "v0.16.5-pre"

View File

@@ -96,7 +96,7 @@ func checkLibraries() (errors bool, err error) {
distroInfo := cmd.GetLinuxDistroInfo() distroInfo := cmd.GetLinuxDistroInfo()
for _, library := range *requiredLibraries { for _, library := range *requiredLibraries {
switch distroInfo.Distribution { switch distroInfo.Distribution {
case cmd.Ubuntu: case cmd.Ubuntu, cmd.Debian:
installed, err := cmd.DpkgInstalled(library.Name) installed, err := cmd.DpkgInstalled(library.Name)
if err != nil { if err != nil {
return false, err return false, err
@@ -108,7 +108,7 @@ func checkLibraries() (errors bool, err error) {
logger.Green("Library '%s' installed.", library.Name) logger.Green("Library '%s' installed.", library.Name)
} }
default: default:
return false, fmt.Errorf("unable to check libraries on distribution '%s'. Please ensure that the '%s' equivalent is installed", distroInfo.DistributorID, library.Name) return false, cmd.RequestSupportForDistribution(distroInfo, library.Name)
} }
} }
} }

View File

@@ -6,6 +6,7 @@ type Runtime struct {
Log *RuntimeLog Log *RuntimeLog
Dialog *RuntimeDialog Dialog *RuntimeDialog
Window *RuntimeWindow Window *RuntimeWindow
Browser *RuntimeBrowser
FileSystem *RuntimeFileSystem FileSystem *RuntimeFileSystem
} }
@@ -15,6 +16,7 @@ func newRuntime(eventManager *eventManager, renderer Renderer) *Runtime {
Log: newRuntimeLog(), Log: newRuntimeLog(),
Dialog: newRuntimeDialog(renderer), Dialog: newRuntimeDialog(renderer),
Window: newRuntimeWindow(renderer), Window: newRuntimeWindow(renderer),
Browser: newRuntimeBrowser(),
FileSystem: newRuntimeFileSystem(), FileSystem: newRuntimeFileSystem(),
} }
} }

25
runtime_browser.go Normal file
View File

@@ -0,0 +1,25 @@
package wails
import "github.com/pkg/browser"
// GlobalRuntimeBrowser is the global instance of the RuntimeBrowser object
// Why? Because we need to use it in both the runtime and from the frontend
var GlobalRuntimeBrowser = newRuntimeBrowser()
// RuntimeBrowser exposes browser methods to the runtime
type RuntimeBrowser struct {
}
func newRuntimeBrowser() *RuntimeBrowser {
return &RuntimeBrowser{}
}
// OpenURL opens the given url in the system's default browser
func (r *RuntimeBrowser) OpenURL(url string) error {
return browser.OpenURL(url)
}
// OpenFile opens the given file in the system's default browser
func (r *RuntimeBrowser) OpenFile(filePath string) error {
return browser.OpenFile(filePath)
}

File diff suppressed because one or more lines are too long

View File

@@ -18,197 +18,199 @@
// Bridge object // Bridge object
window.wailsbridge = { window.wailsbridge = {
reconnectOverlay: null, reconnectOverlay: null,
reconnectTimer: 300, reconnectTimer: 300,
wsURL: "ws://localhost:34115/bridge", wsURL: 'ws://localhost:34115/bridge',
connectionState: null, connectionState: null,
config: {}, config: {},
websocket: null, websocket: null,
callback: null, callback: null,
overlayHTML: overlayHTML:
'<div class="wails-reconnect-overlay"><div class="wails-reconnect-overlay-content"><div class="wails-reconnect-overlay-title">Wails Bridge</div><br><div class="wails-reconnect-overlay-loadingspinner"></div><br><div id="wails-reconnect-overlay-message">Waiting for backend</div></div></div>', '<div class="wails-reconnect-overlay"><div class="wails-reconnect-overlay-content"><div class="wails-reconnect-overlay-title">Wails Bridge</div><br><div class="wails-reconnect-overlay-loadingspinner"></div><br><div id="wails-reconnect-overlay-message">Waiting for backend</div></div></div>',
overlayCSS: overlayCSS:
".wails-reconnect-overlay{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,.6);font-family:sans-serif;display:none;z-index:999999}.wails-reconnect-overlay-content{padding:20px 30px;text-align:center;width:20em;position:relative;height:14em;border-radius:1em;margin:5% auto 0;background-color:#fff;box-shadow:1px 1px 20px 3px;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC8AAAAuCAMAAACPpbA7AAAAqFBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQAAAAAAAAEBAQAAAAAAAAAAAAEBAQEBAQDAwMBAQEAAAABAQEAAAAAAAAAAAABAQEAAAAAAAACAgICAgIBAQEAAAAAAAAAAAAAAAAAAAAAAAABAQEAAAACAgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBQWKCj6oAAAAN3RSTlMALiIqDhkGBAswJjP0GxP6NR4W9/ztjRDMhWU50G9g5eHXvbZ9XEI9xZTcqZl2aldKo55QwoCvZUgzhAAAAs9JREFUSMeNleeWqjAUhU0BCaH3Itiw9zKT93+zG02QK1hm/5HF+jzZJ6fQe6cyXE+jg9X7o9wxuylIIf4Tv2V3+bOrEXnf8dwQ/KQIGDN2/S+4OmVCVXL/ScBnfibxURqIByP/hONE8r8T+bDMlQ98KSl7Y8hzjpS8v1qtDh8u5f8KQpGpfnPPhqG8JeogN37Hq9eaN2xRhIwAaGnvws8F1ShxqK5ob2twYi1FAMD4rXsYtnC/JEiRbl4cUrCWhnMCLRFemXezXbb59QK4WASOsm6n2W1+4CBT2JmtzQ6fsrbGubR/NFbd2g5Y179+5w/GEHaKsHjYCet7CgrXU3txarNC7YxOVJtIj4/ERzMdZfzc31hp+8cD6eGILgarZY9uZ12hAs03vfBD9C171gS5Omz7OcvxALQIn4u8RRBBBcsi9WW2woO9ipLgfzpYlggg3ZRdROUC8KT7QLqq3W9KB5BbdFVg4929kdwp6+qaZnMCCNBdj+NyN1W885Ry/AL3D4AQbsVV4noCiM/C83kyYq80XlDAYQtralOiDzoRAHlotWl8q2tjvYlOgcg1A8jEApZa+C06TBdAz2Qv0wu11I/zZOyJQ6EwGez2P2b8PIQr1hwwnAZsAxwA4UAYOyXUxM/xp6tHAn4GUmPGM9R28oVxgC0e/zQJJI6DyhyZ1r7uzRQhpcW7x7vTaWSzKSG6aep77kroTEl3U81uSVaUTtgEINfC8epx+Q4F9SpplHG84Ek6m4RAq9/TLkOBrxyeuddZhHvGIp1XXfFy3Z3vtwNblKGiDn+J+92vwwABHghj7HnzlS1H5kB49AZvdGCFgiBPq69qfXPr3y++yilF0ON4R8eR7spAsLpZ95NqAW5tab1c4vkZm6aleajchMwYTdILQQTwE2OV411ZM9WztDjPql12caBi6gDpUKmDd4U1XNdQxZ4LIXQ5/Tr4P7I9tYcFrDK3AAAAAElFTkSuQmCC);background-repeat:no-repeat;background-position:center}.wails-reconnect-overlay-title{font-size:2em}.wails-reconnect-overlay-message{font-size:1.3em}.wails-reconnect-overlay-loadingspinner{pointer-events:none;width:2.5em;height:2.5em;border:.4em solid transparent;border-color:#3E67EC #eee #eee;border-radius:50%;animation:loadingspin 1s linear infinite;margin:auto;padding:2.5em}@keyframes loadingspin{100%{transform:rotate(360deg)}}", '.wails-reconnect-overlay{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,.6);font-family:sans-serif;display:none;z-index:999999}.wails-reconnect-overlay-content{padding:20px 30px;text-align:center;width:20em;position:relative;height:14em;border-radius:1em;margin:5% auto 0;background-color:#fff;box-shadow:1px 1px 20px 3px;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC8AAAAuCAMAAACPpbA7AAAAqFBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQAAAAAAAAEBAQAAAAAAAAAAAAEBAQEBAQDAwMBAQEAAAABAQEAAAAAAAAAAAABAQEAAAAAAAACAgICAgIBAQEAAAAAAAAAAAAAAAAAAAAAAAABAQEAAAACAgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBQWKCj6oAAAAN3RSTlMALiIqDhkGBAswJjP0GxP6NR4W9/ztjRDMhWU50G9g5eHXvbZ9XEI9xZTcqZl2aldKo55QwoCvZUgzhAAAAs9JREFUSMeNleeWqjAUhU0BCaH3Itiw9zKT93+zG02QK1hm/5HF+jzZJ6fQe6cyXE+jg9X7o9wxuylIIf4Tv2V3+bOrEXnf8dwQ/KQIGDN2/S+4OmVCVXL/ScBnfibxURqIByP/hONE8r8T+bDMlQ98KSl7Y8hzjpS8v1qtDh8u5f8KQpGpfnPPhqG8JeogN37Hq9eaN2xRhIwAaGnvws8F1ShxqK5ob2twYi1FAMD4rXsYtnC/JEiRbl4cUrCWhnMCLRFemXezXbb59QK4WASOsm6n2W1+4CBT2JmtzQ6fsrbGubR/NFbd2g5Y179+5w/GEHaKsHjYCet7CgrXU3txarNC7YxOVJtIj4/ERzMdZfzc31hp+8cD6eGILgarZY9uZ12hAs03vfBD9C171gS5Omz7OcvxALQIn4u8RRBBBcsi9WW2woO9ipLgfzpYlggg3ZRdROUC8KT7QLqq3W9KB5BbdFVg4929kdwp6+qaZnMCCNBdj+NyN1W885Ry/AL3D4AQbsVV4noCiM/C83kyYq80XlDAYQtralOiDzoRAHlotWl8q2tjvYlOgcg1A8jEApZa+C06TBdAz2Qv0wu11I/zZOyJQ6EwGez2P2b8PIQr1hwwnAZsAxwA4UAYOyXUxM/xp6tHAn4GUmPGM9R28oVxgC0e/zQJJI6DyhyZ1r7uzRQhpcW7x7vTaWSzKSG6aep77kroTEl3U81uSVaUTtgEINfC8epx+Q4F9SpplHG84Ek6m4RAq9/TLkOBrxyeuddZhHvGIp1XXfFy3Z3vtwNblKGiDn+J+92vwwABHghj7HnzlS1H5kB49AZvdGCFgiBPq69qfXPr3y++yilF0ON4R8eR7spAsLpZ95NqAW5tab1c4vkZm6aleajchMwYTdILQQTwE2OV411ZM9WztDjPql12caBi6gDpUKmDd4U1XNdQxZ4LIXQ5/Tr4P7I9tYcFrDK3AAAAAElFTkSuQmCC);background-repeat:no-repeat;background-position:center}.wails-reconnect-overlay-title{font-size:2em}.wails-reconnect-overlay-message{font-size:1.3em}.wails-reconnect-overlay-loadingspinner{pointer-events:none;width:2.5em;height:2.5em;border:.4em solid transparent;border-color:#3E67EC #eee #eee;border-radius:50%;animation:loadingspin 1s linear infinite;margin:auto;padding:2.5em}@keyframes loadingspin{100%{transform:rotate(360deg)}}',
log: function (message) { log: function (message) {
// eslint-disable-next-line // eslint-disable-next-line
console.log( console.log(
"%c wails bridge %c " + message + " ", '%c wails bridge %c ' + message + ' ',
"background: #aa0000; color: #fff; border-radius: 3px 0px 0px 3px; padding: 1px; font-size: 0.7rem", 'background: #aa0000; color: #fff; border-radius: 3px 0px 0px 3px; padding: 1px; font-size: 0.7rem',
"background: #009900; color: #fff; border-radius: 0px 3px 3px 0px; padding: 1px; font-size: 0.7rem" 'background: #009900; color: #fff; border-radius: 0px 3px 3px 0px; padding: 1px; font-size: 0.7rem'
); );
} }
}; };
// Adapted from webview - thanks zserge! // Adapted from webview - thanks zserge!
function injectCSS(css) { function injectCSS(css) {
var elem = document.createElement("style"); var elem = document.createElement('style');
elem.setAttribute("type", "text/css"); elem.setAttribute('type', 'text/css');
if (elem.styleSheet) { if (elem.styleSheet) {
elem.styleSheet.cssText = css; elem.styleSheet.cssText = css;
} else { } else {
elem.appendChild(document.createTextNode(css)); elem.appendChild(document.createTextNode(css));
} }
var head = document.head || document.getElementsByTagName("head")[0]; var head = document.head || document.getElementsByTagName('head')[0];
head.appendChild(elem); head.appendChild(elem);
} }
// Creates a node in the Dom // Creates a node in the Dom
function createNode(parent, elementType, id, className, content) { function createNode(parent, elementType, id, className, content) {
var d = document.createElement(elementType); var d = document.createElement(elementType);
if (id) { if (id) {
d.id = id; d.id = id;
} }
if (className) { if (className) {
d.className = className; d.className = className;
} }
if (content) { if (content) {
d.innerHTML = content; d.innerHTML = content;
} }
parent.appendChild(d); parent.appendChild(d);
return d; return d;
} }
// Sets up the overlay // Sets up the overlay
function setupOverlay() { function setupOverlay() {
var body = document.body; var body = document.body;
var wailsBridgeNode = createNode(body, "div", "wails-bridge"); var wailsBridgeNode = createNode(body, 'div', 'wails-bridge');
wailsBridgeNode.innerHTML = window.wailsbridge.overlayHTML; wailsBridgeNode.innerHTML = window.wailsbridge.overlayHTML;
// Inject the overlay CSS // Inject the overlay CSS
injectCSS(window.wailsbridge.overlayCSS); injectCSS(window.wailsbridge.overlayCSS);
} }
// Start the Wails Bridge // Start the Wails Bridge
function startBridge() { function startBridge() {
// Setup the overlay // Setup the overlay
setupOverlay(); setupOverlay();
window.wailsbridge.websocket = null; window.wailsbridge.websocket = null;
window.wailsbridge.connectTimer = null; window.wailsbridge.connectTimer = null;
window.wailsbridge.reconnectOverlay = document.querySelector( window.wailsbridge.reconnectOverlay = document.querySelector(
".wails-reconnect-overlay" '.wails-reconnect-overlay'
); );
window.wailsbridge.connectionState = "disconnected"; window.wailsbridge.connectionState = 'disconnected';
// Shows the overlay // Shows the overlay
function showReconnectOverlay() { function showReconnectOverlay() {
window.wailsbridge.reconnectOverlay.style.display = "block"; window.wailsbridge.reconnectOverlay.style.display = 'block';
} }
// Hides the overlay // Hides the overlay
function hideReconnectOverlay() { function hideReconnectOverlay() {
window.wailsbridge.reconnectOverlay.style.display = "none"; window.wailsbridge.reconnectOverlay.style.display = 'none';
} }
// Bridge external.invoke // Bridge external.invoke
window.external = { window.external = {
invoke: function (msg) { invoke: function (msg) {
window.wailsbridge.websocket.send(msg); window.wailsbridge.websocket.send(msg);
} }
}; };
// Adds a script to the Dom. // Adds a script to the Dom.
// Removes it if second parameter is true. // Removes it if second parameter is true.
function addScript(script, remove) { function addScript(script, remove) {
var s = document.createElement("script"); var s = document.createElement('script');
s.setAttribute('type', 'text/javascript'); s.setAttribute('type', 'text/javascript');
s.textContent = script; s.textContent = script;
document.head.appendChild(s); document.head.appendChild(s);
// Remove internal messages from the DOM // Remove internal messages from the DOM
if (remove) { if (remove) {
s.parentNode.removeChild(s); s.parentNode.removeChild(s);
} }
} }
// Handles incoming websocket connections // Handles incoming websocket connections
function handleConnect() { function handleConnect() {
window.wailsbridge.log("Connected to backend"); window.wailsbridge.log('Connected to backend');
hideReconnectOverlay(); hideReconnectOverlay();
clearInterval(window.wailsbridge.connectTimer); clearInterval(window.wailsbridge.connectTimer);
window.wailsbridge.websocket.onclose = handleDisconnect; window.wailsbridge.websocket.onclose = handleDisconnect;
window.wailsbridge.websocket.onmessage = handleMessage; window.wailsbridge.websocket.onmessage = handleMessage;
window.wailsbridge.connectionState = "connected"; window.wailsbridge.connectionState = 'connected';
} }
// Handles websocket disconnects // Handles websocket disconnects
function handleDisconnect() { function handleDisconnect() {
window.wailsbridge.log("Disconnected from backend"); window.wailsbridge.log('Disconnected from backend');
window.wailsbridge.websocket = null; window.wailsbridge.websocket = null;
window.wailsbridge.connectionState = "disconnected"; window.wailsbridge.connectionState = 'disconnected';
showReconnectOverlay(); showReconnectOverlay();
connect(); connect();
} }
// Try to connect to the backend every 300ms (default value). // Try to connect to the backend every 300ms (default value).
// Change this value in the main wailsbridge object. // Change this value in the main wailsbridge object.
function connect() { function connect() {
window.wailsbridge.connectTimer = setInterval(function () { window.wailsbridge.connectTimer = setInterval(function () {
if (window.wailsbridge.websocket == null) { if (window.wailsbridge.websocket == null) {
window.wailsbridge.websocket = new WebSocket(window.wailsbridge.wsURL); window.wailsbridge.websocket = new WebSocket(window.wailsbridge.wsURL);
window.wailsbridge.websocket.onopen = handleConnect; window.wailsbridge.websocket.onopen = handleConnect;
window.wailsbridge.websocket.onerror = function (e) { window.wailsbridge.websocket.onerror = function (e) {
e.stopImmediatePropagation(); e.stopImmediatePropagation();
e.stopPropagation(); e.stopPropagation();
e.preventDefault(); e.preventDefault();
window.wailsbridge.websocket = null; window.wailsbridge.websocket = null;
return false; return false;
}; };
} }
}, window.wailsbridge.reconnectTimer); }, window.wailsbridge.reconnectTimer);
} }
function handleMessage(message) { function handleMessage(message) {
// As a bridge we ignore js and css injections // As a bridge we ignore js and css injections
switch (message.data[0]) { switch (message.data[0]) {
// Wails library - inject! // Wails library - inject!
case "w": case 'w':
addScript(message.data.slice(1)); addScript(message.data.slice(1));
// Now wails runtime is loaded, wails for the ready event // Now wails runtime is loaded, wails for the ready event
// and callback to the main app // and callback to the main app
window.wails.events.on("wails:loaded", function () { window.wails.Events.On('wails:loaded', function () {
window.wailsbridge.log("Wails Ready"); window.wailsbridge.log('Wails Ready');
if (window.wailsbridge.callback) { if (window.wailsbridge.callback) {
window.wailsbridge.log("Notifying application"); window.wailsbridge.log('Notifying application');
window.wailsbridge.callback(window.wails); window.wailsbridge.callback(window.wails);
} }
}); });
window.wailsbridge.log("Loaded Wails Runtime"); window.wailsbridge.log('Loaded Wails Runtime');
break; break;
// Notifications // Notifications
case "n": case 'n':
addScript(message.data.slice(1), true); addScript(message.data.slice(1), true);
break; break;
// Binding // Binding
case "b": case 'b':
var binding = message.data.slice(1); var binding = message.data.slice(1);
//log("Binding: " + binding) //log("Binding: " + binding)
window.wails._.newBinding(binding); window.wails._.newBinding(binding);
break; break;
// Call back // Call back
case "c": case 'c':
var callbackData = message.data.slice(1); var callbackData = message.data.slice(1);
window.wails._.callback(callbackData); window.wails._.callback(callbackData);
break; break;
} default:
} window.wails.Log.Error('Unknown message type received: ' + message.data[0]);
}
}
// Start by showing the overlay... // Start by showing the overlay...
showReconnectOverlay(); showReconnectOverlay();
// ...and attempt to connect // ...and attempt to connect
connect(); connect();
} }
export default { export default {
// The main function // The main function
// Passes the main Wails object to the callback if given. // Passes the main Wails object to the callback if given.
Start: function (callback) { Start: function (callback) {
// Save the callback // Save the callback
window.wailsbridge.callback = callback; window.wailsbridge.callback = callback;
// Start Bridge // Start Bridge
startBridge(); startBridge();
} }
}; };

View File

@@ -7,11 +7,11 @@
*/ */
export default { export default {
// The main function // The main function
// Passes the main Wails object to the callback if given. // Passes the main Wails object to the callback if given.
Start: function(callback) { Start: function (callback) {
if (callback) { if (callback) {
window.wails.events.on("wails:ready", callback); window.wails.Events.On('wails:ready', callback);
} }
} }
}; };

View File

@@ -1,40 +0,0 @@
(function(){window.wails=window.wails||{};window.backend={};function cryptoRandom(){var array=new Uint32Array(1);return window.crypto.getRandomValues(array)[0]}function basicRandom(){return Math.random()*9007199254740991}var randomFunc;if(window.crypto){randomFunc=cryptoRandom}else{randomFunc=basicRandom}function isValidIdentifier(name){try{new Function("var "+name);return true}catch(e){return false}}function addScript(js,callbackID){var script=document.createElement("script");script.text=js;document.body.appendChild(script);window.wails.events.emit(callbackID)}function injectCSS(css){var elem=document.createElement('style');elem.setAttribute('type','text/css');if(elem.styleSheet){elem.styleSheet.cssText=css}else{elem.appendChild(document.createTextNode(css))}var head=document.head||document.getElementsByTagName('head')[0];head.appendChild(elem)}var bindingsBasePath=window.backend;function addBindingPath(pathSections){var currentPath=bindingsBasePath;for(var sectionIndex in pathSections){var section=pathSections[sectionIndex];if(!isValidIdentifier(section)){var errMessage=section+" is not a valid javascript identifier.";var err=new Error(errMessage);return[null,err]}if(!currentPath[section]){currentPath[section]={}}currentPath=currentPath[section]}return[currentPath,null]}function newBinding(bindingName){var bindingSections=bindingName.split('.').splice(1);var callName=bindingSections.pop();var pathToBinding;var err;var bs=addBindingPath(bindingSections);var pathToBinding=bs[0];var err=bs[1];if(err!=null){return err}pathToBinding[callName]=function(){var timeout=0;function dynamic(){var args=[].slice.call(arguments);return call(bindingName,args,timeout)}dynamic.setTimeout=function(newTimeout){timeout=newTimeout};dynamic.getTimeout=function(){return timeout};return dynamic}()}var callbacks={};function call(bindingName,data,timeout){if(timeout==null||timeout==undefined){timeout=0}return new Promise(function(resolve,reject){var callbackID;do{callbackID=bindingName+"-"+randomFunc()}while(callbacks[callbackID]);if(timeout>0){var timeoutHandle=setTimeout(function(){reject(Error("Call to "+bindingName+" timed out. Request ID: "+callbackID))},timeout)}callbacks[callbackID]={timeoutHandle:timeoutHandle,reject:reject,resolve:resolve};try{var payloaddata=JSON.stringify(data);message={type:"call",callbackid:callbackID,payload:{bindingName:bindingName,data:payloaddata}};var payload=JSON.stringify(message);external.invoke(payload)}catch(e){console.error(e)}})}function callback(incomingMessage){var message;try{message=JSON.parse(incomingMessage)}catch(e){wails.log.debug("Invalid JSON passed to callback: "+e.message);wails.log.debug("Message: "+incomingMessage);return}callbackID=message.callbackid;callbackData=callbacks[callbackID];if(!callbackData){console.error("Callback '"+callbackID+"' not registed!!!");return}clearTimeout(callbackData.timeoutHandle);delete callbacks[callbackID];if(message.error){return callbackData.reject(message.error)}return callbackData.resolve(message.data)}var eventListeners={};function on(eventName,callback){eventListeners[eventName]=eventListeners[eventName]||[];eventListeners[eventName].push(callback)}function notify(eventName,data){if(eventListeners[eventName]){eventListeners[eventName].forEach(function(element){var parsedData=[];if(data){try{parsedData=JSON.parse(data)}catch(e){wails.log.error("Invalid JSON data sent to notify. Event name = "+eventName)}}element.apply(null,parsedData)})}}function emit(eventName){var data=JSON.stringify([].slice.apply(arguments).slice(1));message={type:"event",payload:{name:eventName,data:data}};external.invoke(JSON.stringify(message))}window.wails.events={emit:emit,on:on};function sendLogMessage(level,message){message={type:"log",payload:{level:level,message:message}};external.invoke(JSON.stringify(message))}function logDebug(message){sendLogMessage("debug",message)}function logInfo(message){sendLogMessage("info",message)}function logWarning(message){sendLogMessage("warning",message)}function logError(message){sendLogMessage("error",message)}function logFatal(message){sendLogMessage("fatal",message)}window.wails.log={debug:logDebug,info:logInfo,warning:logWarning,error:logError,fatal:logFatal};window.wails._={newBinding:newBinding,callback:callback,notify:notify,sendLogMessage:sendLogMessage,callbacks:callbacks,injectCSS:injectCSS,addScript:addScript};window.wails.events.emit("wails:loaded");})();
(function(){window.wails=window.wails||{};window.backend={};function cryptoRandom(){var array=new Uint32Array(1);return window.crypto.getRandomValues(array)[0]}
function basicRandom(){return Math.random()*9007199254740991}
var randomFunc;if(window.crypto){randomFunc=cryptoRandom}else{randomFunc=basicRandom}
function isValidIdentifier(name){try{new Function("var "+name);return!0}catch(e){return!1}}
function addScript(js,callbackID){var script=document.createElement("script");script.text=js;document.body.appendChild(script);window.wails.events.emit(callbackID)}
function injectCSS(css){var elem=document.createElement('style');elem.setAttribute('type','text/css');if(elem.styleSheet){elem.styleSheet.cssText=css}else{elem.appendChild(document.createTextNode(css))}
var head=document.head||document.getElementsByTagName('head')[0];head.appendChild(elem)}
var bindingsBasePath=window.backend;function addBindingPath(pathSections){var currentPath=bindingsBasePath;for(var sectionIndex in pathSections){var section=pathSections[sectionIndex];if(!isValidIdentifier(section)){var errMessage=section+" is not a valid javascript identifier.";var err=new Error(errMessage);return[null,err]}
if(!currentPath[section]){currentPath[section]={}}
currentPath=currentPath[section]}
return[currentPath,null]}
function newBinding(bindingName){var bindingSections=bindingName.split('.').splice(1);var callName=bindingSections.pop();var pathToBinding;var err;var bs=addBindingPath(bindingSections);var pathToBinding=bs[0];var err=bs[1];if(err!=null){return err}
pathToBinding[callName]=function(){var timeout=0;function dynamic(){var args=[].slice.call(arguments);return call(bindingName,args,timeout)}
dynamic.setTimeout=function(newTimeout){timeout=newTimeout}
dynamic.getTimeout=function(){return timeout}
return dynamic}()}
var callbacks={};function call(bindingName,data,timeout){if(timeout==null||timeout==undefined){timeout=0}
return new Promise(function(resolve,reject){var callbackID;do{callbackID=bindingName+"-"+randomFunc()}while(callbacks[callbackID]);if(timeout>0){var timeoutHandle=setTimeout(function(){reject(Error("Call to "+bindingName+" timed out. Request ID: "+callbackID))},timeout)}
callbacks[callbackID]={timeoutHandle:timeoutHandle,reject:reject,resolve:resolve}
try{var payloaddata=JSON.stringify(data);message={type:"call",callbackid:callbackID,payload:{bindingName:bindingName,data:payloaddata,}}
var payload=JSON.stringify(message);external.invoke(payload)}catch(e){console.error(e)}})}
function callback(incomingMessage){incomingMessage=decodeURIComponent(incomingMessage.replace(/\s+/g,'').replace(/[0-9a-f]{2}/g,'%$&'));var message;try{message=JSON.parse(incomingMessage)}catch(e){wails.log.debug("Invalid JSON passed to callback: "+e.message);wails.log.debug("Message: "+incomingMessage);return}
callbackID=message.callbackid;callbackData=callbacks[callbackID];if(!callbackData){console.error("Callback '"+callbackID+"' not registed!!!");return}
clearTimeout(callbackData.timeoutHandle);delete callbacks[callbackID];if(message.error){return callbackData.reject(message.error)}
return callbackData.resolve(message.data)}
var eventListeners={};function on(eventName,callback){eventListeners[eventName]=eventListeners[eventName]||[];eventListeners[eventName].push(callback)}
function notify(eventName,data){if(eventListeners[eventName]){eventListeners[eventName].forEach(function(element){var parsedData=[];if(data){try{parsedData=JSON.parse(data)}catch(e){wails.log.error("Invalid JSON data sent to notify. Event name = "+eventName)}}
element.apply(null,parsedData)})}}
function emit(eventName){var data=JSON.stringify([].slice.apply(arguments).slice(1));message={type:"event",payload:{name:eventName,data:data,}}
external.invoke(JSON.stringify(message))}
window.wails.events={emit:emit,on:on};function sendLogMessage(level,message){message={type:"log",payload:{level:level,message:message,}}
external.invoke(JSON.stringify(message))}
function logDebug(message){sendLogMessage("debug",message)}
function logInfo(message){sendLogMessage("info",message)}
function logWarning(message){sendLogMessage("warning",message)}
function logError(message){sendLogMessage("error",message)}
function logFatal(message){sendLogMessage("fatal",message)}
window.wails.log={debug:logDebug,info:logInfo,warning:logWarning,error:logError,fatal:logFatal,};window.wails._={newBinding:newBinding,callback:callback,notify:notify,sendLogMessage:sendLogMessage,callbacks:callbacks,injectCSS:injectCSS,addScript:addScript,}
window.wails.events.emit("wails:loaded")})()

View File

@@ -1 +1 @@
!function(){var e;function n(e){try{return new Function("var "+e),!0}catch(e){return!1}}window.wails=window.wails||{},window.backend={},e=window.crypto?function(){var e=new Uint32Array(1);return window.crypto.getRandomValues(e)[0]}:function(){return 9007199254740991*Math.random()};var a=window.backend;var t={};var i={};function r(e,n){n={type:"log",payload:{level:e,message:n}},external.invoke(JSON.stringify(n))}window.wails.events={emit:function(e){var n=JSON.stringify([].slice.apply(arguments).slice(1));message={type:"event",payload:{name:e,data:n}},external.invoke(JSON.stringify(message))},on:function(e,n){i[e]=i[e]||[],i[e].push(n)}},window.wails.log={debug:function(e){r("debug",e)},info:function(e){r("info",e)},warning:function(e){r("warning",e)},error:function(e){r("error",e)},fatal:function(e){r("fatal",e)}},window.wails._={newBinding:function(i){var r,l=i.split(".").splice(1),o=l.pop(),c=function(e){var t=a;for(var i in e){var r=e[i];if(!n(r))return[null,new Error(r+" is not a valid javascript identifier.")];t[r]||(t[r]={}),t=t[r]}return[t,null]}(l),s=c[0];if(null!=(r=c[1]))return r;s[o]=function(){var n=0;function a(){var a=[].slice.call(arguments);return function(n,a,i){return null!=i&&null!=i||(i=0),new Promise(function(r,l){var o;do{o=n+"-"+e()}while(t[o]);if(i>0)var c=setTimeout(function(){l(Error("Call to "+n+" timed out. Request ID: "+o))},i);t[o]={timeoutHandle:c,reject:l,resolve:r};try{var s=JSON.stringify(a);message={type:"call",callbackid:o,payload:{bindingName:n,data:s}};var u=JSON.stringify(message);external.invoke(u)}catch(e){console.error(e)}})}(i,a,n)}return a.setTimeout=function(e){n=e},a.getTimeout=function(){return n},a}()},callback:function(e){var n;e=decodeURIComponent(e.replace(/\s+/g,"").replace(/[0-9a-f]{2}/g,"%$&"));try{n=JSON.parse(e)}catch(n){return wails.log.debug("Invalid JSON passed to callback: "+n.message),void wails.log.debug("Message: "+e)}if(callbackID=n.callbackid,callbackData=t[callbackID],callbackData)return clearTimeout(callbackData.timeoutHandle),delete t[callbackID],n.error?callbackData.reject(n.error):callbackData.resolve(n.data);console.error("Callback '"+callbackID+"' not registed!!!")},notify:function(e,n){i[e]&&i[e].forEach(function(a){var t=[];if(n)try{t=JSON.parse(n)}catch(n){wails.log.error("Invalid JSON data sent to notify. Event name = "+e)}a.apply(null,t)})},sendLogMessage:r,callbacks:t,injectCSS:function(e){var n=document.createElement("style");n.setAttribute("type","text/css"),n.styleSheet?n.styleSheet.cssText=e:n.appendChild(document.createTextNode(e)),(document.head||document.getElementsByTagName("head")[0]).appendChild(n)},addScript:function(e,n){var a=document.createElement("script");a.text=e,document.body.appendChild(a),window.wails.events.emit(n)}},window.wails.events.emit("wails:loaded")}(); !function(){var e;function n(e){try{return new Function("var "+e),!0}catch(e){return!1}}window.wails=window.wails||{},window.backend={},e=window.crypto?function(){var e=new Uint32Array(1);return window.crypto.getRandomValues(e)[0]}:function(){return 9007199254740991*Math.random()};var t=window.backend;var r={};function i(n,t,i){return null!=i&&null!=i||(i=0),new Promise(function(a,o){var l;do{l=n+"-"+e()}while(r[l]);if(i>0)var c=setTimeout(function(){o(Error("Call to "+n+" timed out. Request ID: "+l))},i);r[l]={timeoutHandle:c,reject:o,resolve:a};try{var s=JSON.stringify(t),u={type:"call",callbackid:l,payload:{bindingName:n,data:s}},d=JSON.stringify(u);external.invoke(d)}catch(e){console.error(e)}})}function a(e,n){return i(".wails."+e,n)}var o={};function l(e,n){o[e]=o[e]||[],o[e].push(n)}function c(e){var n={type:"event",payload:{name:e,data:JSON.stringify([].slice.apply(arguments).slice(1))}};external.invoke(JSON.stringify(n))}function s(e,n){var t=n[0].toUpperCase()+n.substring(1);return function(r,i){return console.warn("Method events."+n+" has been deprecated. Please use Events."+t),e(r,i)}}function u(e,n){n={type:"log",payload:{level:e,message:n}},external.invoke(JSON.stringify(n))}function d(e,n){var t=n[0].toUpperCase()+n.substring(1);return function(r){return console.warn("Method Log."+n+" has been deprecated. Please use Log."+t),e(r)}}function w(e){u("debug",e)}function f(e){u("info",e)}function p(e){u("warning",e)}function v(e){u("error",e)}function g(e){u("fatal",e)}window.wails.events={emit:s(c,"emit"),on:s(l,"on")},window.wails.Events={Emit:c,On:l},window.wails.Browser={OpenURL:function(e){return a("Browser.OpenURL",e)},OpenFile:function(e){return a("Browser.OpenFile",e)}},window.wails.log={debug:d(w,"debug"),info:d(f,"info"),warning:d(p,"warning"),error:d(v,"error"),fatal:d(g,"fatal")},window.wails.Log={Debug:w,Info:f,Warning:p,Error:v,Fatal:g},window.wails._={newBinding:function(e){var r=e.split(".").splice(1),a=r.pop(),o=function(e){var r=t;for(var i in e){var a=e[i];if(!n(a))return[null,new Error(a+" is not a valid javascript identifier.")];r[a]||(r[a]={}),r=r[a]}return[r,null]}(r),l=o[0],c=o[1];if(null!=c)return c;l[a]=function(){var n=0;function t(){var t=[].slice.call(arguments);return i(e,t,n)}return t.setTimeout=function(e){n=e},t.getTimeout=function(){return n},t}()},callback:function(e){var n;e=decodeURIComponent(e.replace(/\s+/g,"").replace(/[0-9a-f]{2}/g,"%$&"));try{n=JSON.parse(e)}catch(n){return window.wails.Log.Debug("Invalid JSON passed to callback: "+n.message),void window.wails.Log.Debug("Message: "+e)}var t=n.callbackid,i=r[t];if(i)return clearTimeout(i.timeoutHandle),delete r[t],n.error?i.reject(n.error):i.resolve(n.data);console.error("Callback '"+t+"' not registed!!!")},notify:function(e,n){o[e]&&o[e].forEach(function(t){var r=[];if(n)try{r=JSON.parse(n)}catch(n){window.wails.Log.Error("Invalid JSON data sent to notify. Event name = "+e)}t.apply(null,r)})},sendLogMessage:u,callbacks:r,injectCSS:function(e){var n=document.createElement("style");n.setAttribute("type","text/css"),n.styleSheet?n.styleSheet.cssText=e:n.appendChild(document.createTextNode(e)),(document.head||document.getElementsByTagName("head")[0]).appendChild(n)},addScript:function(e,n){var t=document.createElement("script");t.text=e,document.body.appendChild(t),window.wails.Events.Emit(n)}},window.wails.Events.Emit("wails:loaded")}();

View File

@@ -31,7 +31,7 @@
function isValidIdentifier(name) { function isValidIdentifier(name) {
// Don't xss yourself :-) // Don't xss yourself :-)
try { try {
new Function("var " + name); new Function('var ' + name);
return true; return true;
} catch (e) { } catch (e) {
return false; return false;
@@ -40,10 +40,10 @@
// -------------- JS ---------------- // -------------- JS ----------------
function addScript(js, callbackID) { function addScript(js, callbackID) {
var script = document.createElement("script"); var script = document.createElement('script');
script.text = js; script.text = js;
document.body.appendChild(script); document.body.appendChild(script);
window.wails.events.emit(callbackID); window.wails.Events.Emit(callbackID);
} }
// -------------- CSS --------------- // -------------- CSS ---------------
@@ -75,7 +75,7 @@
// Is section a valid javascript identifier? // Is section a valid javascript identifier?
if (!isValidIdentifier(section)) { if (!isValidIdentifier(section)) {
var errMessage = section + " is not a valid javascript identifier."; var errMessage = section + ' is not a valid javascript identifier.';
var err = new Error(errMessage); var err = new Error(errMessage);
return [null, err]; return [null, err];
} }
@@ -98,9 +98,6 @@
// Get the actual function/method call name // Get the actual function/method call name
var callName = bindingSections.pop(); var callName = bindingSections.pop();
var pathToBinding;
var err;
// Add path to binding // Add path to binding
var bs = addBindingPath(bindingSections); var bs = addBindingPath(bindingSections);
var pathToBinding = bs[0]; var pathToBinding = bs[0];
@@ -126,12 +123,12 @@
// Allow setting timeout to function // Allow setting timeout to function
dynamic.setTimeout = function (newTimeout) { dynamic.setTimeout = function (newTimeout) {
timeout = newTimeout; timeout = newTimeout;
} };
// Allow getting timeout to function // Allow getting timeout to function
dynamic.getTimeout = function () { dynamic.getTimeout = function () {
return timeout; return timeout;
} };
return dynamic; return dynamic;
}(); }();
@@ -163,13 +160,13 @@
// Create a unique callbackID // Create a unique callbackID
var callbackID; var callbackID;
do { do {
callbackID = bindingName + "-" + randomFunc(); callbackID = bindingName + '-' + randomFunc();
} while (callbacks[callbackID]); } while (callbacks[callbackID]);
// Set timeout // Set timeout
if (timeout > 0) { if (timeout > 0) {
var timeoutHandle = setTimeout(function () { var timeoutHandle = setTimeout(function () {
reject(Error("Call to " + bindingName + " timed out. Request ID: " + callbackID)); reject(Error('Call to ' + bindingName + ' timed out. Request ID: ' + callbackID));
}, timeout); }, timeout);
} }
@@ -178,26 +175,32 @@
timeoutHandle: timeoutHandle, timeoutHandle: timeoutHandle,
reject: reject, reject: reject,
resolve: resolve resolve: resolve
} };
try { try {
var payloaddata = JSON.stringify(data); var payloaddata = JSON.stringify(data);
// Create the message // Create the message
message = { var message = {
type: "call", type: 'call',
callbackid: callbackID, callbackid: callbackID,
payload: { payload: {
bindingName: bindingName, bindingName: bindingName,
data: payloaddata, data: payloaddata,
} }
} };
// Make the call // Make the call
var payload = JSON.stringify(message); var payload = JSON.stringify(message);
external.invoke(payload); external.invoke(payload);
} catch (e) { } catch (e) {
// eslint-disable-next-line
console.error(e); console.error(e);
} }
}) });
}
// systemCall is used to call wails methods from the frontend
function systemCall(method, data) {
return call('.wails.' + method, data);
} }
// Called by the backend to return data to a previously called // Called by the backend to return data to a previously called
@@ -212,15 +215,16 @@
try { try {
message = JSON.parse(incomingMessage); message = JSON.parse(incomingMessage);
} catch (e) { } catch (e) {
wails.log.debug("Invalid JSON passed to callback: " + e.message); window.wails.Log.Debug('Invalid JSON passed to callback: ' + e.message);
wails.log.debug("Message: " + incomingMessage); window.wails.Log.Debug('Message: ' + incomingMessage);
return; return;
} }
callbackID = message.callbackid; var callbackID = message.callbackid;
callbackData = callbacks[callbackID]; var callbackData = callbacks[callbackID];
if (!callbackData) { if (!callbackData) {
console.error("Callback '" + callbackID + "' not registed!!!"); // eslint-disable-next-line
return console.error('Callback \'' + callbackID + '\' not registed!!!');
return;
} }
clearTimeout(callbackData.timeoutHandle); clearTimeout(callbackData.timeoutHandle);
delete callbacks[callbackID]; delete callbacks[callbackID];
@@ -254,7 +258,7 @@
try { try {
parsedData = JSON.parse(data); parsedData = JSON.parse(data);
} catch (e) { } catch (e) {
wails.log.error("Invalid JSON data sent to notify. Event name = " + eventName) window.wails.Log.Error('Invalid JSON data sent to notify. Event name = ' + eventName);
} }
} }
element.apply(null, parsedData); element.apply(null, parsedData);
@@ -269,22 +273,57 @@
var data = JSON.stringify([].slice.apply(arguments).slice(1)); var data = JSON.stringify([].slice.apply(arguments).slice(1));
// Notify backend // Notify backend
message = { var message = {
type: "event", type: 'event',
payload: { payload: {
name: eventName, name: eventName,
data: data, data: data,
} }
} };
external.invoke(JSON.stringify(message)); external.invoke(JSON.stringify(message));
} }
function deprecatedEventsFunction(fn, oldName) {
var newName = oldName[0].toUpperCase() + oldName.substring(1);
return function (eventName, eventData) {
// eslint-disable-next-line
console.warn('Method events.' + oldName + ' has been deprecated. Please use Events.' + newName);
return fn(eventName, eventData);
};
}
// Deprecated Events calls
window.wails.events = {
emit: deprecatedEventsFunction(emit, 'emit'),
on: deprecatedEventsFunction(on, 'on'),
};
// Events calls // Events calls
window.wails.events = { emit: emit, on: on }; window.wails.Events = {
Emit: emit,
On: on
};
/************************************************************/ /************************************************************/
/************************* Browser **************************/
function OpenURL(url) {
return systemCall('Browser.OpenURL', url);
}
function OpenFile(filename) {
return systemCall('Browser.OpenFile', filename);
}
window.wails.Browser = {
OpenURL,
OpenFile,
};
/************************* Logging **************************/ /************************* Logging **************************/
// Sends a log message to the backend with the given // Sends a log message to the backend with the given
@@ -293,39 +332,57 @@
// Log Message // Log Message
message = { message = {
type: "log", type: 'log',
payload: { payload: {
level: level, level: level,
message: message, message: message,
} }
} };
external.invoke(JSON.stringify(message)); external.invoke(JSON.stringify(message));
} }
function deprecatedLogFunction(fn, oldName) {
var newName = oldName[0].toUpperCase() + oldName.substring(1);
return function (message) {
// eslint-disable-next-line
console.warn('Method Log.' + oldName + ' has been deprecated. Please use Log.' + newName);
return fn(message);
};
}
function logDebug(message) { function logDebug(message) {
sendLogMessage("debug", message); sendLogMessage('debug', message);
} }
function logInfo(message) { function logInfo(message) {
sendLogMessage("info", message); sendLogMessage('info', message);
} }
function logWarning(message) { function logWarning(message) {
sendLogMessage("warning", message); sendLogMessage('warning', message);
} }
function logError(message) { function logError(message) {
sendLogMessage("error", message); sendLogMessage('error', message);
} }
function logFatal(message) { function logFatal(message) {
sendLogMessage("fatal", message); sendLogMessage('fatal', message);
} }
window.wails.log = { window.wails.log = {
debug: logDebug, debug: deprecatedLogFunction(logDebug, 'debug'),
info: logInfo, info: deprecatedLogFunction(logInfo, 'info'),
warning: logWarning, warning: deprecatedLogFunction(logWarning, 'warning'),
error: logError, error: deprecatedLogFunction(logError, 'error'),
fatal: logFatal, fatal: deprecatedLogFunction(logFatal, 'fatal'),
}; };
window.wails.Log = {
Debug: logDebug,
Info: logInfo,
Warning: logWarning,
Error: logError,
Fatal: logFatal,
};
/************************** Exports *************************/ /************************** Exports *************************/
window.wails._ = { window.wails._ = {
@@ -336,12 +393,12 @@
callbacks: callbacks, callbacks: callbacks,
injectCSS: injectCSS, injectCSS: injectCSS,
addScript: addScript, addScript: addScript,
} };
/************************************************************/ /************************************************************/
// Notify backend that the runtime has finished loading // Notify backend that the runtime has finished loading
window.wails.events.emit("wails:loaded"); window.wails.Events.Emit('wails:loaded');
})() })();