Compare commits

..

1 Commits

Author SHA1 Message Date
Lea Anthony
a17f385749 chore: add debug info 2019-06-16 19:53:18 +10:00
130 changed files with 1151 additions and 10548 deletions

42
.chglog/CHANGELOG.tpl.md Executable file
View File

@@ -0,0 +1,42 @@
{{ if .Versions -}}
<a name="unreleased"></a>
## [Unreleased]
{{ if .Unreleased.CommitGroups -}}
{{ range .Unreleased.CommitGroups -}}
### {{ .Title }}
{{ range .Commits -}}
- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }}
{{ end }}
{{ end -}}
{{ end -}}
{{ end -}}
{{ range .Versions }}
<a name="{{ .Tag.Name }}"></a>
## {{ if .Tag.Previous }}[{{ .Tag.Name }}]{{ else }}{{ .Tag.Name }}{{ end }} - {{ datetime "2006-01-02" .Tag.Date }}
{{ range .CommitGroups -}}
### {{ .Title }}
{{ range .Commits -}}
- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }}
{{ end }}
{{ end -}}
{{- if .NoteGroups -}}
{{ range .NoteGroups -}}
### {{ .Title }}
{{ range .Notes }}
{{ .Body }}
{{ end }}
{{ end -}}
{{ end -}}
{{ end -}}
{{- if .Versions }}
[Unreleased]: {{ .Info.RepositoryURL }}/compare/{{ $latest := index .Versions 0 }}{{ $latest.Tag.Name }}...HEAD
{{ range .Versions -}}
{{ if .Tag.Previous -}}
[{{ .Tag.Name }}]: {{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }}
{{ end -}}
{{ end -}}
{{ end -}}

27
.chglog/config.yml Executable file
View File

@@ -0,0 +1,27 @@
style: github
template: CHANGELOG.tpl.md
info:
title: CHANGELOG
repository_url: https://github.com/wailsapp/wails
options:
commits:
# filters:
# Type:
# - feat
# - fix
# - perf
# - refactor
commit_groups:
# title_maps:
# feat: Features
# fix: Bug Fixes
# perf: Performance Improvements
# refactor: Code Refactoring
header:
pattern: "^(\\w*)\\:\\s(.*)$"
pattern_maps:
- Type
- Subject
notes:
keywords:
- BREAKING CHANGE

View File

@@ -1 +0,0 @@
runtime/js/dist/wails.js

View File

@@ -1,29 +0,0 @@
{
"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"
]
}
}

2
.gitignore vendored
View File

@@ -16,4 +16,4 @@ examples/**/example*
cmd/wails/wails cmd/wails/wails
.DS_Store .DS_Store
tmp tmp
node_modules dist

View File

@@ -1,6 +0,0 @@
jshint:
config_file: .jshintrc
eslint:
enabled: true
config_file: .eslintrc
ignore_file: .eslintignore

View File

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

View File

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

View File

@@ -1,28 +1,19 @@
2019-06-18 **v0.16.0**
* React template FTW! - Thanks [admin_3.exe](https://github.com/bh90210)!
* Updated contributors
* Arch Linux detection without lsb-release
* Removed deprecated methods for dealing with JS/CSS in the backend
2019-05-29 **v0.14.11-pre** <a name="v0.13.0"></a>
* Windows fix for spinner ## [v0.13.0] - 2019-05-12
2019-05-29 **v0.14.10-pre** ### Feat
* Windows fix for Vuetify - revamped 'update' system
- no need for explicit GO111MODULE=on
2019-05-29 **v0.14.9-pre** ### Fix
* Vuetify project template 🎉 - documentation typo fixes
- windows init project
- windows 10 colour
- leave windows assets on -p flag
- show prerequisite errors
2019-05-29 **v0.14.8-pre** ### Docs
* Updated Ubuntu npm install command - updated contributors
- added awesomego logo
2019-05-22 **v0.14.7-pre** - added Redhat distro
* New projects are built automatically when initialised
* Go 1.12 is now a minimum requirement
2019-05-21 **v0.14.6-pre**
* Hotfix for module dependency issue
2019-05-20 **v0.14.5-pre**
* Added developer tooling - New Template Generator
* Documentation fixes - Thanks [admin_3.exe](https://github.com/bh90210)!

View File

@@ -12,5 +12,3 @@ 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)
* [fallendusk](https://github.com/fallendusk)

View File

@@ -10,7 +10,6 @@
<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!
@@ -19,7 +18,6 @@ The traditional method of providing web interfaces to Go programs is via a built
- Use standard Go libraries/frameworks for the backend - Use standard Go libraries/frameworks for the backend
- Use any frontend technology to build your UI - Use any frontend technology to build your UI
- Quickly create Vue, Vuetify or React frontends for your Go programs
- Expose Go methods/functions to the frontend via a single bind command - Expose Go methods/functions to the frontend via a single bind command
- Uses native rendering engines - no embedded browser - Uses native rendering engines - no embedded browser
- Shared events system - Shared events system
@@ -46,7 +44,7 @@ Make sure you have the xcode command line tools installed. This can be done by r
### Linux ### Linux
#### Ubuntu 18.04, Debian 9, Zorin 15 #### Ubuntu 18.04
`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`
@@ -99,7 +97,7 @@ Without the following people, this project would never have existed:
* [Dustin Krysak](https://wiki.ubuntu.com/bashfulrobot) - His support and feedback has been immense. More patience than you can throw a stick at (Not long now Dustin!). * [Dustin Krysak](https://wiki.ubuntu.com/bashfulrobot) - His support and feedback has been immense. More patience than you can throw a stick at (Not long now Dustin!).
* [Serge Zaitsev](https://github.com/zserge) - Creator of [Webview](https://github.com/zserge/webview) which Wails uses for the windowing. * [Serge Zaitsev](https://github.com/zserge) - Creator of [Webview](https://github.com/zserge/webview) which Wails uses for the windowing.
And without [these people](CONTRIBUTORS.md), it wouldn't be what it is today. A huge thank you to each and every one of you! And without [these people](CONTRIBUTORS.md), it wouldn't be what it is today.
Special Mentions: Special Mentions:

51
app.go
View File

@@ -2,13 +2,6 @@ package wails
import ( import (
"github.com/wailsapp/wails/cmd" "github.com/wailsapp/wails/cmd"
"github.com/wailsapp/wails/lib/logger"
"github.com/wailsapp/wails/runtime/go/runtime"
"github.com/wailsapp/wails/lib/renderer"
"github.com/wailsapp/wails/lib/binding"
"github.com/wailsapp/wails/lib/ipc"
"github.com/wailsapp/wails/lib/event"
"github.com/wailsapp/wails/lib/interfaces"
) )
// -------------------------------- Compile time Flags ------------------------------ // -------------------------------- Compile time Flags ------------------------------
@@ -20,15 +13,15 @@ var BuildMode = cmd.BuildModeProd
// App defines the main application struct // App defines the main application struct
type App struct { type App struct {
config *AppConfig // The Application configuration object config *AppConfig // The Application configuration object
cli *cmd.Cli // In debug mode, we have a cli cli *cmd.Cli // In debug mode, we have a cli
renderer interfaces.Renderer // The renderer is what we will render the app to renderer Renderer // The renderer is what we will render the app to
logLevel string // The log level of the app logLevel string // The log level of the app
ipc interfaces.IPCManager // Handles the IPC calls ipc *ipcManager // Handles the IPC calls
log *logger.CustomLogger // Logger log *CustomLogger // Logger
bindingManager interfaces.BindingManager // Handles binding of Go code to renderer bindingManager *bindingManager // Handles binding of Go code to renderer
eventManager interfaces.EventManager // Handles all the events eventManager *eventManager // Handles all the events
runtime interfaces.Runtime // The runtime object for registered structs runtime *Runtime // The runtime object for registered structs
} }
// CreateApp creates the application window with the given configuration // CreateApp creates the application window with the given configuration
@@ -41,14 +34,14 @@ func CreateApp(optionalConfig ...*AppConfig) *App {
result := &App{ result := &App{
logLevel: "info", logLevel: "info",
renderer: renderer.NewWebView(), renderer: &webViewRenderer{},
ipc: ipc.NewManager(), ipc: newIPCManager(),
bindingManager: binding.NewManager(), bindingManager: newBindingManager(),
eventManager: event.NewManager(), eventManager: newEventManager(),
log: logger.NewCustomLogger("App"), log: newCustomLogger("App"),
} }
appconfig, err := newConfig(userConfig) appconfig, err := newAppConfig(userConfig)
if err != nil { if err != nil {
result.log.Fatalf("Cannot use custom HTML: %s", err.Error()) result.log.Fatalf("Cannot use custom HTML: %s", err.Error())
} }
@@ -82,14 +75,14 @@ func (a *App) Run() error {
func (a *App) start() error { func (a *App) start() error {
// Set the log level // Set the log level
logger.SetLogLevel(a.logLevel) setLogLevel(a.logLevel)
// Log starup // Log starup
a.log.Info("Starting") a.log.Info("Starting")
// Check if we are to run in headless mode // Check if we are to run in headless mode
if BuildMode == cmd.BuildModeBridge { if BuildMode == cmd.BuildModeBridge {
a.renderer = &renderer.Headless{} a.renderer = &Headless{}
} }
// Initialise the renderer // Initialise the renderer
@@ -99,16 +92,16 @@ func (a *App) start() error {
} }
// Start event manager and give it our renderer // Start event manager and give it our renderer
a.eventManager.Start(a.renderer) a.eventManager.start(a.renderer)
// Start the IPC Manager and give it the event manager and binding manager // Start the IPC Manager and give it the event manager and binding manager
a.ipc.Start(a.eventManager, a.bindingManager) a.ipc.start(a.eventManager, a.bindingManager)
// Create the runtime // Create the runtime
a.runtime = runtime.NewRuntime(a.eventManager, a.renderer) a.runtime = 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)
if err != nil { if err != nil {
return err return err
} }
@@ -120,5 +113,5 @@ func (a *App) start() error {
// Bind allows the user to bind the given object // Bind allows the user to bind the given object
// with the application // with the application
func (a *App) Bind(object interface{}) { func (a *App) Bind(object interface{}) {
a.bindingManager.Bind(object) a.bindingManager.bind(object)
} }

View File

@@ -1,5 +1,11 @@
package wails package wails
import (
"strings"
"github.com/dchest/htmlmin"
"github.com/leaanthony/mewn"
)
// AppConfig is the configuration structure used when creating a Wails App object // AppConfig is the configuration structure used when creating a Wails App object
type AppConfig struct { type AppConfig struct {
@@ -12,51 +18,7 @@ type AppConfig struct {
Colour string Colour string
Resizable bool Resizable bool
DisableInspector bool DisableInspector bool
} isHTMLFragment bool
// GetWidth returns the desired width
func (a *AppConfig) GetWidth() int {
return a.Width
}
// GetHeight returns the desired height
func (a *AppConfig) GetHeight() int {
return a.Height
}
// GetTitle returns the desired window title
func (a *AppConfig) GetTitle() string {
return a.Title
}
// GetDefaultHTML returns the desired window title
func (a *AppConfig) GetDefaultHTML() string {
return a.defaultHTML
}
// GetResizable returns true if the window should be resizable
func (a *AppConfig) GetResizable() bool {
return a.Resizable
}
// GetDisableInspector returns true if the inspector should be disabled
func (a *AppConfig) GetDisableInspector() bool {
return a.DisableInspector
}
// GetColour returns the colour
func (a *AppConfig) GetColour() string {
return a.Colour
}
// GetCSS returns the user CSS
func (a *AppConfig) GetCSS() string {
return a.CSS
}
// GetJS returns the user Javascript
func (a *AppConfig) GetJS() string {
return a.JS
} }
func (a *AppConfig) merge(in *AppConfig) error { func (a *AppConfig) merge(in *AppConfig) error {
@@ -66,6 +28,32 @@ func (a *AppConfig) merge(in *AppConfig) error {
if in.Title != "" { if in.Title != "" {
a.Title = in.Title a.Title = in.Title
} }
if in.HTML != "" {
minified, err := htmlmin.Minify([]byte(in.HTML), &htmlmin.Options{
MinifyScripts: true,
})
if err != nil {
return err
}
inlineHTML := string(minified)
inlineHTML = strings.Replace(inlineHTML, "'", "\\'", -1)
inlineHTML = strings.Replace(inlineHTML, "\n", " ", -1)
a.HTML = strings.TrimSpace(inlineHTML)
// Deduce whether this is a full html page or a fragment
// The document is determined to be a fragment if an HTML
// tag exists and is located before the first div tag
HTMLTagIndex := strings.Index(a.HTML, "<html")
DivTagIndex := strings.Index(a.HTML, "<div")
if HTMLTagIndex == -1 {
a.isHTMLFragment = true
} else {
if DivTagIndex < HTMLTagIndex {
a.isHTMLFragment = true
}
}
}
if in.Colour != "" { if in.Colour != "" {
a.Colour = in.Colour a.Colour = in.Colour
@@ -88,13 +76,14 @@ func (a *AppConfig) merge(in *AppConfig) error {
} }
// Creates the default configuration // Creates the default configuration
func newConfig(userConfig *AppConfig) (*AppConfig, error) { func newAppConfig(userConfig *AppConfig) (*AppConfig, error) {
result := &AppConfig{ result := &AppConfig{
Width: 800, Width: 800,
Height: 600, Height: 600,
Resizable: true, Resizable: true,
Title: "My Wails App", Title: "My Wails App",
Colour: "#FFF", // White by default Colour: "#FFF", // White by default
HTML: mewn.String("./wailsruntimeassets/default/default.html"),
} }
if userConfig != nil { if userConfig != nil {

View File

@@ -1,4 +1,4 @@
package binding package wails
import ( import (
"bytes" "bytes"
@@ -6,8 +6,6 @@ import (
"fmt" "fmt"
"reflect" "reflect"
"runtime" "runtime"
"github.com/wailsapp/wails/lib/logger"
) )
type boundFunction struct { type boundFunction struct {
@@ -16,7 +14,7 @@ type boundFunction struct {
functionType reflect.Type functionType reflect.Type
inputs []reflect.Type inputs []reflect.Type
returnTypes []reflect.Type returnTypes []reflect.Type
log *logger.CustomLogger log *CustomLogger
hasErrorReturnType bool hasErrorReturnType bool
} }
@@ -32,7 +30,7 @@ func newBoundFunction(object interface{}) (*boundFunction, error) {
fullName: name, fullName: name,
function: objectValue, function: objectValue,
functionType: objectType, functionType: objectType,
log: logger.NewCustomLogger(name), log: newCustomLogger(name),
} }
err := result.processParameters() err := result.processParameters()
@@ -57,7 +55,7 @@ func (b *boundFunction) processParameters() error {
b.inputs[index] = param b.inputs[index] = param
typ := param typ := param
index := index index := index
b.log.DebugFields("Input param", logger.Fields{ b.log.DebugFields("Input param", Fields{
"index": index, "index": index,
"name": name, "name": name,
"kind": kind, "kind": kind,

View File

@@ -1,46 +1,45 @@
package binding package wails
import ( import (
"fmt" "fmt"
"reflect" "reflect"
"unicode" "unicode"
"github.com/wailsapp/wails/lib/logger"
"github.com/wailsapp/wails/lib/messages"
"github.com/wailsapp/wails/lib/interfaces"
) )
// Manager handles method binding /**
type Manager struct {
binding:
Name() // Full name (package+name)
Call(params)
**/
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 *logger.CustomLogger log *CustomLogger
renderer interfaces.Renderer renderer Renderer
runtime interfaces.Runtime // The runtime object to pass to bound structs runtime *Runtime // The runtime object to pass to bound structs
objectsToBind []interface{} objectsToBind []interface{}
bindPackageNames bool // Package name should be considered when binding bindPackageNames bool // Package name should be considered when binding
} }
// NewManager creates a new Manager struct func newBindingManager() *bindingManager {
func NewManager() interfaces.BindingManager { result := &bindingManager{
result := &Manager{ methods: make(map[string]*boundMethod),
methods: make(map[string]*boundMethod), functions: make(map[string]*boundFunction),
functions: make(map[string]*boundFunction), log: newCustomLogger("Bind"),
log: logger.NewCustomLogger("Bind"),
internalMethods: newInternalMethods(),
} }
return result return result
} }
// BindPackageNames sets a flag to indicate package names should be considered when binding // Sets flag to indicate package names should be considered when binding
func (b *Manager) BindPackageNames() { func (b *bindingManager) BindPackageNames() {
b.bindPackageNames = true b.bindPackageNames = true
} }
// Start the binding manager func (b *bindingManager) start(renderer Renderer, runtime *Runtime) error {
func (b *Manager) Start(renderer interfaces.Renderer, runtime interfaces.Runtime) error {
b.log.Info("Starting") b.log.Info("Starting")
b.renderer = renderer b.renderer = renderer
b.runtime = runtime b.runtime = runtime
@@ -53,7 +52,7 @@ func (b *Manager) Start(renderer interfaces.Renderer, runtime interfaces.Runtime
return err return err
} }
func (b *Manager) initialise() error { func (b *bindingManager) initialise() error {
var err error var err error
// var binding *boundMethod // var binding *boundMethod
@@ -91,7 +90,7 @@ func (b *Manager) initialise() error {
} }
// bind the given struct method // bind the given struct method
func (b *Manager) bindMethod(object interface{}) error { func (b *bindingManager) bindMethod(object interface{}) error {
objectType := reflect.TypeOf(object) objectType := reflect.TypeOf(object)
baseName := objectType.String() baseName := objectType.String()
@@ -141,7 +140,7 @@ func (b *Manager) bindMethod(object interface{}) error {
} }
// bind the given function object // bind the given function object
func (b *Manager) bindFunction(object interface{}) error { func (b *bindingManager) bindFunction(object interface{}) error {
newFunction, err := newBoundFunction(object) newFunction, err := newBoundFunction(object)
if err != nil { if err != nil {
@@ -158,18 +157,13 @@ func (b *Manager) bindFunction(object interface{}) error {
return nil return nil
} }
// Bind saves the given object to be bound at start time // Save the given object to be bound at start time
func (b *Manager) Bind(object interface{}) { func (b *bindingManager) bind(object interface{}) {
// Store binding // Store binding
b.objectsToBind = append(b.objectsToBind, object) b.objectsToBind = append(b.objectsToBind, object)
} }
func (b *Manager) processInternalCall(callData *messages.CallData) (interface{}, error) { func (b *bindingManager) processFunctionCall(callData *callData) (interface{}, error) {
// Strip prefix
return b.internalMethods.processCall(callData)
}
func (b *Manager) processFunctionCall(callData *messages.CallData) (interface{}, error) {
// Return values // Return values
var result []reflect.Value var result []reflect.Value
var err error var err error
@@ -198,7 +192,7 @@ func (b *Manager) processFunctionCall(callData *messages.CallData) (interface{},
return result[0].Interface(), nil return result[0].Interface(), nil
} }
func (b *Manager) processMethodCall(callData *messages.CallData) (interface{}, error) { func (b *bindingManager) processMethodCall(callData *callData) (interface{}, error) {
// Return values // Return values
var result []reflect.Value var result []reflect.Value
var err error var err error
@@ -232,8 +226,8 @@ func (b *Manager) processMethodCall(callData *messages.CallData) (interface{}, e
return nil, nil return nil, nil
} }
// ProcessCall processes the given call request // process an incoming call request
func (b *Manager) ProcessCall(callData *messages.CallData) (result interface{}, err error) { func (b *bindingManager) processCall(callData *callData) (result interface{}, err error) {
b.log.Debugf("Wanting to call %s", callData.BindingName) b.log.Debugf("Wanting to call %s", callData.BindingName)
// Determine if this is function call or method call by the number of // Determine if this is function call or method call by the number of
@@ -260,8 +254,6 @@ func (b *Manager) ProcessCall(callData *messages.CallData) (result interface{},
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)
@@ -271,7 +263,7 @@ func (b *Manager) ProcessCall(callData *messages.CallData) (result interface{},
// callWailsInitMethods calls all of the WailsInit methods that were // callWailsInitMethods calls all of the WailsInit methods that were
// registered with the runtime object // registered with the runtime object
func (b *Manager) callWailsInitMethods() error { func (b *bindingManager) callWailsInitMethods() error {
// Create reflect value for runtime object // Create reflect value for runtime object
runtimeValue := reflect.ValueOf(b.runtime) runtimeValue := reflect.ValueOf(b.runtime)
params := []reflect.Value{runtimeValue} params := []reflect.Value{runtimeValue}

View File

@@ -1,12 +1,10 @@
package binding package wails
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"reflect" "reflect"
"github.com/wailsapp/wails/lib/logger"
) )
type boundMethod struct { type boundMethod struct {
@@ -15,7 +13,7 @@ type boundMethod struct {
method reflect.Value method reflect.Value
inputs []reflect.Type inputs []reflect.Type
returnTypes []reflect.Type returnTypes []reflect.Type
log *logger.CustomLogger log *CustomLogger
hasErrorReturnType bool // Indicates if there is an error return type hasErrorReturnType bool // Indicates if there is an error return type
isWailsInit bool isWailsInit bool
} }
@@ -29,7 +27,7 @@ func newBoundMethod(name string, fullName string, method reflect.Value, objectTy
} }
// Setup logger // Setup logger
result.log = logger.NewCustomLogger(result.fullName) result.log = newCustomLogger(result.fullName)
// Check if Parameters are valid // Check if Parameters are valid
err := result.processParameters() err := result.processParameters()
@@ -59,7 +57,7 @@ func (b *boundMethod) processParameters() error {
b.inputs[index] = param b.inputs[index] = param
typ := param typ := param
index := index index := index
b.log.DebugFields("Input param", logger.Fields{ b.log.DebugFields("Input param", Fields{
"index": index, "index": index,
"name": name, "name": name,
"kind": kind, "kind": kind,
@@ -168,10 +166,10 @@ func (b *boundMethod) setInputValue(index int, typ reflect.Type, val interface{}
reflect.Map, reflect.Map,
reflect.Ptr, reflect.Ptr,
reflect.Slice: reflect.Slice:
b.log.Debug("Converting nil to type") logger.Debug("Converting nil to type")
result = reflect.ValueOf(val).Convert(typ) result = reflect.ValueOf(val).Convert(typ)
default: default:
b.log.Debug("Cannot convert nil to type, returning error") logger.Debug("Cannot convert nil to type, returning error")
return reflect.Zero(typ), fmt.Errorf("Unable to use null value for parameter %d of method %s", index+1, b.fullName) return reflect.Zero(typ), fmt.Errorf("Unable to use null value for parameter %d of method %s", index+1, b.fullName)
} }
} else { } else {

File diff suppressed because one or more lines are too long

View File

@@ -271,7 +271,7 @@ func InstallBridge(caller string, projectDir string, projectOptions *ProjectOpti
} }
// Copy bridge to project // Copy bridge to project
bridgeAssets := mewn.Group("../runtime/bridge/") bridgeAssets := mewn.Group("../wailsruntimeassets/bridge/")
bridgeFileData := bridgeAssets.Bytes(bridgeFile) bridgeFileData := bridgeAssets.Bytes(bridgeFile)
bridgeFileTarget := filepath.Join(projectDir, projectOptions.FrontEnd.Dir, projectOptions.FrontEnd.Bridge, "wailsbridge.js") bridgeFileTarget := filepath.Join(projectDir, projectOptions.FrontEnd.Dir, projectOptions.FrontEnd.Bridge, "wailsbridge.js")
err := fs.CreateFile(bridgeFileTarget, bridgeFileData) err := fs.CreateFile(bridgeFileTarget, bridgeFileData)

View File

@@ -3,12 +3,9 @@ package cmd
import ( import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"net/url"
"os" "os"
"runtime" "regexp"
"strings" "strings"
"github.com/pkg/browser"
) )
// LinuxDistribution is of type int // LinuxDistribution is of type int
@@ -23,12 +20,6 @@ const (
Arch Arch
// RedHat linux distribution // RedHat linux distribution
RedHat RedHat
// Debian distribution
Debian
// Gentoo distribution
Gentoo
// Zorin distribution
Zorin
) )
// DistroInfo contains all the information relating to a linux distribution // DistroInfo contains all the information relating to a linux distribution
@@ -38,7 +29,6 @@ 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
@@ -53,7 +43,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
@@ -68,14 +58,8 @@ func GetLinuxDistroInfo() *DistroInfo {
result.Distribution = Ubuntu result.Distribution = Ubuntu
case "Arch", "ManjaroLinux": case "Arch", "ManjaroLinux":
result.Distribution = Arch result.Distribution = Arch
case "Debian": default:
result.Distribution = Debian result.Distribution = Unknown
case "Gentoo":
result.Distribution = Gentoo
case "Zorin":
result.Distribution = Zorin
case "Fedora":
result.Distribution = RedHat
} }
case "Description": case "Description":
result.Description = value result.Description = value
@@ -83,37 +67,21 @@ 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")
// Split into lines // compile a regex to find NAME=distro
lines := strings.Split(string(osRelease), "\n") re := regexp.MustCompile(`^NAME=(.*)\n`)
// Iterate lines // extract the distro name
for _, line := range lines { osName := string(re.FindSubmatch(osRelease)[1])
// Split each line by the equals char // strip quotations
splitLine := strings.SplitN(line, "=", 2) osName = strings.Trim(osName, "\"")
// 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
@@ -121,29 +89,13 @@ 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
case "Gentoo/Linux":
result.Distribution = Gentoo
default: default:
result.Distribution = Unknown result.Distribution = Unknown
result.DistributorID = osName
} }
} }
return result return result
} }
// EqueryInstalled uses equery to see if a package is installed
func EqueryInstalled(packageName string) (bool, error) {
program := NewProgramHelper()
equery := program.FindProgram("equery")
if equery == nil {
return false, fmt.Errorf("cannont check dependencies: equery not found")
}
_, _, exitCode, _ := equery.Run("l", packageName)
return exitCode == 0, nil
}
// DpkgInstalled uses dpkg to see if a package is installed // DpkgInstalled uses dpkg to see if a package is installed
func DpkgInstalled(packageName string) (bool, error) { func DpkgInstalled(packageName string) (bool, error) {
program := NewProgramHelper() program := NewProgramHelper()
@@ -176,45 +128,3 @@ 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,10 +49,11 @@ func getRequiredProgramsLinux() *Prerequisites {
result := &Prerequisites{} result := &Prerequisites{}
distroInfo := GetLinuxDistroInfo() distroInfo := GetLinuxDistroInfo()
switch distroInfo.Distribution { switch distroInfo.Distribution {
case Ubuntu, Debian, Zorin: case Ubuntu:
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"))
@@ -93,12 +94,9 @@ func getRequiredLibrariesLinux() (*Prerequisites, error) {
result := &Prerequisites{} result := &Prerequisites{}
distroInfo := GetLinuxDistroInfo() distroInfo := GetLinuxDistroInfo()
switch distroInfo.Distribution { switch distroInfo.Distribution {
case Ubuntu, Debian, Zorin: case Ubuntu:
result.Add(newPrerequisite("libgtk-3-dev", "Please install with `sudo apt install libgtk-3-dev` and try again")) result.Add(newPrerequisite("libgtk-3-dev", "Please install with `sudo apt install libgtk-3-dev` and try again"))
result.Add(newPrerequisite("libwebkit2gtk-4.0-dev", "Please install with `sudo apt install libwebkit2gtk-4.0-dev` and try again")) result.Add(newPrerequisite("libwebkit2gtk-4.0-dev", "Please install with `sudo apt install libwebkit2gtk-4.0-dev` and try again"))
case Gentoo:
result.Add(newPrerequisite("gtk+:3", "Please install with `sudo emerge gtk+:3` and try again"))
result.Add(newPrerequisite("webkit-gtk", "Please install with `sudo emerge webkit-gtk` and try again"))
case Arch: case Arch:
result.Add(newPrerequisite("gtk3", "Please install with `sudo pacman -S gtk3` and try again")) result.Add(newPrerequisite("gtk3", "Please install with `sudo pacman -S gtk3` and try again"))
result.Add(newPrerequisite("webkit2gtk", "Please install with `sudo pacman -S webkit2gtk` and try again")) result.Add(newPrerequisite("webkit2gtk", "Please install with `sudo pacman -S webkit2gtk` and try again"))

View File

@@ -7,7 +7,6 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"runtime" "runtime"
"sort"
"strings" "strings"
"github.com/leaanthony/slicer" "github.com/leaanthony/slicer"
@@ -144,13 +143,11 @@ 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
@@ -185,13 +182,7 @@ func (po *ProjectOptions) PromptForInputs() error {
po.selectedTemplate = templateDetails[po.Template] po.selectedTemplate = templateDetails[po.Template]
} else { } else {
keys := make([]string, 0) for _, templateDetail := range templateDetails {
for k := range templateDetails {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
templateDetail := templateDetails[k]
templateList.Add(templateDetail) templateList.Add(templateDetail)
options.Add(fmt.Sprintf("%s - %s", templateDetail.Metadata.Name, templateDetail.Metadata.ShortDescription)) options.Add(fmt.Sprintf("%s - %s", templateDetail.Metadata.Name, templateDetail.Metadata.ShortDescription))
} }

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, Zorin, Debian: case Ubuntu:
installed, err := DpkgInstalled(library.Name) installed, err := DpkgInstalled(library.Name)
if err != nil { if err != nil {
return false, err return false, err
@@ -305,19 +305,9 @@ func CheckDependencies(logger *Logger) (bool, error) {
} else { } else {
logger.Green("Library '%s' installed.", library.Name) logger.Green("Library '%s' installed.", library.Name)
} }
case Gentoo:
installed, err := EqueryInstalled(library.Name)
if err != nil {
return false, err
}
if !installed {
errors = true
logger.Error("Library '%s' not found. %s", library.Name, library.Help)
} else {
logger.Green("Library '%s' installed.", library.Name)
}
default: default:
return false, RequestSupportForDistribution(distroInfo, library.Name) fmt.Printf("here 1. DistroInfo = %+v\n", distroInfo)
return false, fmt.Errorf("unable to check libraries on distribution '%s'. Please ensure that the '%s' equivalent is installed", distroInfo.DistributorID, library.Name)
} }
} }
} }

View File

@@ -16,26 +16,18 @@ 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
@@ -160,31 +152,6 @@ 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 {
@@ -193,9 +160,6 @@ 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

@@ -1,13 +0,0 @@
# 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

@@ -1,47 +0,0 @@
# 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

@@ -1,27 +0,0 @@
# 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

@@ -1,121 +0,0 @@
{
"$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

@@ -1,12 +0,0 @@
# 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

@@ -1,32 +0,0 @@
// @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

@@ -1,23 +0,0 @@
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

@@ -1,11 +0,0 @@
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

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

View File

@@ -1,32 +0,0 @@
// 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

@@ -1,50 +0,0 @@
{
"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

@@ -1,13 +0,0 @@
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

@@ -1,14 +0,0 @@
<!--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

@@ -1,35 +0,0 @@
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

@@ -1,19 +0,0 @@
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

@@ -1,20 +0,0 @@
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

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

View File

@@ -1,16 +0,0 @@
// 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.

Before

Width:  |  Height:  |  Size: 5.3 KiB

View File

@@ -1,14 +0,0 @@
<!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

@@ -1,18 +0,0 @@
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

@@ -1,63 +0,0 @@
/**
* 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

@@ -1,24 +0,0 @@
/* 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

@@ -1,20 +0,0 @@
// 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

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

View File

@@ -1,23 +0,0 @@
{
"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

@@ -1,18 +0,0 @@
{
"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

@@ -1,92 +0,0 @@
{
"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

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

View File

@@ -1,27 +0,0 @@
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

@@ -1,20 +0,0 @@
{
"name": "Angular",
"version": "1.0.0",
"shortdescription": "Angular 8 template (Requires node 10.8+)",
"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

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

View File

@@ -26,8 +26,22 @@ 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 { result } = this.state; const { loading, 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,5 +1 @@
module {{.BinaryName}} module {{.BinaryName}}
require (
github.com/wailsapp/wails {{.WailsVersion}}
)

View File

@@ -1,3 +0,0 @@
{
"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,5 +1 @@
module {{.BinaryName}} module {{.BinaryName}}
require (
github.com/wailsapp/wails {{.WailsVersion}}
)

View File

@@ -1,5 +1 @@
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.17.4-pre" const Version = "v0.15.0"

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, cmd.Zorin, cmd.Debian: case cmd.Ubuntu:
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,8 @@ func checkLibraries() (errors bool, err error) {
logger.Green("Library '%s' installed.", library.Name) logger.Green("Library '%s' installed.", library.Name)
} }
default: default:
return false, cmd.RequestSupportForDistribution(distroInfo, library.Name) fmt.Printf("here 2. DistroInfo = %+v\n", distroInfo)
return false, fmt.Errorf("unable to check libraries on distribution '%s'. Please ensure that the '%s' equivalent is installed", distroInfo.DistributorID, library.Name)
} }
} }
} }

View File

@@ -1,34 +1,31 @@
package event package wails
import ( import (
"fmt" "fmt"
"sync" "sync"
"github.com/wailsapp/wails/lib/logger"
"github.com/wailsapp/wails/lib/messages"
"github.com/wailsapp/wails/lib/interfaces"
) )
// Manager handles and processes events // eventManager handles and processes events
type Manager struct { type eventManager struct {
incomingEvents chan *messages.EventData incomingEvents chan *eventData
listeners map[string][]*eventListener listeners map[string][]*eventListener
exit bool exit bool
log *logger.CustomLogger log *CustomLogger
renderer interfaces.Renderer // Messages will be dispatched to the frontend renderer Renderer // Messages will be dispatched to the frontend
} }
// NewManager creates a new event manager with a 100 event buffer // newEventManager creates a new event manager with a 100 event buffer
func NewManager() interfaces.EventManager { func newEventManager() *eventManager {
return &Manager{ return &eventManager{
incomingEvents: make(chan *messages.EventData, 100), incomingEvents: make(chan *eventData, 100),
listeners: make(map[string][]*eventListener), listeners: make(map[string][]*eventListener),
exit: false, exit: false,
log: logger.NewCustomLogger("Events"), log: newCustomLogger("Events"),
} }
} }
// PushEvent places the given event on to the event queue // PushEvent places the given event on to the event queue
func (e *Manager) PushEvent(eventData *messages.EventData) { func (e *eventManager) PushEvent(eventData *eventData) {
e.incomingEvents <- eventData e.incomingEvents <- eventData
} }
@@ -43,7 +40,7 @@ type eventListener struct {
} }
// Creates a new event listener from the given callback function // Creates a new event listener from the given callback function
func (e *Manager) addEventListener(eventName string, callback func(...interface{}), counter int) error { func (e *eventManager) addEventListener(eventName string, callback func(...interface{}), counter int) error {
// Sanity check inputs // Sanity check inputs
if callback == nil { if callback == nil {
@@ -68,19 +65,18 @@ func (e *Manager) addEventListener(eventName string, callback func(...interface{
return nil return nil
} }
// On adds a listener for the given event func (e *eventManager) On(eventName string, callback func(...interface{})) {
func (e *Manager) On(eventName string, callback func(...interface{})) {
// Add a persistent eventListener (counter = 0) // Add a persistent eventListener (counter = 0)
e.addEventListener(eventName, callback, 0) e.addEventListener(eventName, callback, 0)
} }
// Emit broadcasts the given event to the subscribed listeners // Emit broadcasts the given event to the subscribed listeners
func (e *Manager) Emit(eventName string, optionalData ...interface{}) { func (e *eventManager) Emit(eventName string, optionalData ...interface{}) {
e.incomingEvents <- &messages.EventData{Name: eventName, Data: optionalData} e.incomingEvents <- &eventData{Name: eventName, Data: optionalData}
} }
// Start the event manager's queue processing // Starts the event manager's queue processing
func (e *Manager) Start(renderer interfaces.Renderer) { func (e *eventManager) start(renderer Renderer) {
e.log.Info("Starting") e.log.Info("Starting")
@@ -99,7 +95,7 @@ func (e *Manager) Start(renderer interfaces.Renderer) {
// TODO: Listen for application exit // TODO: Listen for application exit
select { select {
case event := <-e.incomingEvents: case event := <-e.incomingEvents:
e.log.DebugFields("Got Event", logger.Fields{ e.log.DebugFields("Got Event", Fields{
"data": event.Data, "data": event.Data,
"name": event.Name, "name": event.Name,
}) })
@@ -147,6 +143,6 @@ func (e *Manager) Start(renderer interfaces.Renderer) {
wg.Wait() wg.Wait()
} }
func (e *Manager) stop() { func (e *eventManager) stop() {
e.exit = true e.exit = true
} }

2
go.mod
View File

@@ -12,7 +12,7 @@ require (
github.com/kennygrant/sanitize v1.2.4 github.com/kennygrant/sanitize v1.2.4
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
github.com/leaanthony/mewn v0.10.7 github.com/leaanthony/mewn v0.10.7
github.com/leaanthony/slicer v1.3.2 github.com/leaanthony/slicer v1.3.1
github.com/leaanthony/spinner v0.5.3 github.com/leaanthony/spinner v0.5.3
github.com/masterminds/semver v1.4.2 github.com/masterminds/semver v1.4.2
github.com/mattn/go-colorable v0.1.1 // indirect github.com/mattn/go-colorable v0.1.1 // indirect

4
go.sum
View File

@@ -33,8 +33,8 @@ github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/leaanthony/mewn v0.10.7 h1:jCcNJyIUOpwj+I5SuATvCugDjHkoo+j6ubEOxxrxmPA= github.com/leaanthony/mewn v0.10.7 h1:jCcNJyIUOpwj+I5SuATvCugDjHkoo+j6ubEOxxrxmPA=
github.com/leaanthony/mewn v0.10.7/go.mod h1:CRkTx8unLiSSilu/Sd7i1LwrdaAL+3eQ3ses99qGMEQ= github.com/leaanthony/mewn v0.10.7/go.mod h1:CRkTx8unLiSSilu/Sd7i1LwrdaAL+3eQ3ses99qGMEQ=
github.com/leaanthony/slicer v1.3.2 h1:kGWWFoyaY5WzwGrUsHXMmGbssuYthP4qYBNlkNpNAB8= github.com/leaanthony/slicer v1.3.1 h1:n2iIV2sxvL/3bpnmVY0vBjXf3yYFWcB6CYLVMrzJxRw=
github.com/leaanthony/slicer v1.3.2/go.mod h1:VMB/HGvr3uR3MRpFWHWAm0w+DHQLzPHYe2pKfpFlQIQ= github.com/leaanthony/slicer v1.3.1/go.mod h1:VMB/HGvr3uR3MRpFWHWAm0w+DHQLzPHYe2pKfpFlQIQ=
github.com/leaanthony/spinner v0.5.3 h1:IMTvgdQCec5QA4qRy0wil4XsRP+QcG1OwLWVK/LPZ5Y= github.com/leaanthony/spinner v0.5.3 h1:IMTvgdQCec5QA4qRy0wil4XsRP+QcG1OwLWVK/LPZ5Y=
github.com/leaanthony/spinner v0.5.3/go.mod h1:oHlrvWicr++CVV7ALWYi+qHk/XNA91D9IJ48IqmpVUo= github.com/leaanthony/spinner v0.5.3/go.mod h1:oHlrvWicr++CVV7ALWYi+qHk/XNA91D9IJ48IqmpVUo=
github.com/leaanthony/synx v0.1.0 h1:R0lmg2w6VMb8XcotOwAe5DLyzwjLrskNkwU7LLWsyL8= github.com/leaanthony/synx v0.1.0 h1:R0lmg2w6VMb8XcotOwAe5DLyzwjLrskNkwU7LLWsyL8=

View File

@@ -1,18 +1,21 @@
package ipc package wails
import ( import (
"fmt" "fmt"
"github.com/wailsapp/wails/lib/messages"
) )
type callData struct {
BindingName string `json:"bindingName"`
Data string `json:"data,omitempty"`
}
func init() { func init() {
messageProcessors["call"] = processCallData messageProcessors["call"] = processCallData
} }
func processCallData(message *ipcMessage) (*ipcMessage, error) { func processCallData(message *ipcMessage) (*ipcMessage, error) {
var payload messages.CallData var payload callData
// Decode binding call data // Decode binding call data
payloadMap := message.Payload.(map[string]interface{}) payloadMap := message.Payload.(map[string]interface{})

View File

@@ -1,11 +1,14 @@
package ipc package wails
import ( import (
"encoding/json" "encoding/json"
"github.com/wailsapp/wails/lib/messages"
) )
type eventData struct {
Name string `json:"name"`
Data interface{} `json:"data"`
}
// Register the message handler // Register the message handler
func init() { func init() {
messageProcessors["event"] = processEventData messageProcessors["event"] = processEventData
@@ -16,7 +19,7 @@ func processEventData(message *ipcMessage) (*ipcMessage, error) {
// TODO: Is it worth double checking this is actually an event message, // TODO: Is it worth double checking this is actually an event message,
// even though that's done by the caller? // even though that's done by the caller?
var payload messages.EventData var payload eventData
// Decode event data // Decode event data
payloadMap := message.Payload.(map[string]interface{}) payloadMap := message.Payload.(map[string]interface{})

View File

@@ -1,6 +1,9 @@
package ipc package wails
import "github.com/wailsapp/wails/lib/messages" type logData struct {
Level string `json:"level"`
Message string `json:"string"`
}
// Register the message handler // Register the message handler
func init() { func init() {
@@ -10,7 +13,7 @@ func init() {
// This processes the given log message // This processes the given log message
func processLogData(message *ipcMessage) (*ipcMessage, error) { func processLogData(message *ipcMessage) (*ipcMessage, error) {
var payload messages.LogData var payload logData
// Decode event data // Decode event data
payloadMap := message.Payload.(map[string]interface{}) payloadMap := message.Payload.(map[string]interface{})

View File

@@ -1,42 +1,35 @@
package ipc package wails
import ( import (
"fmt" "fmt"
"github.com/wailsapp/wails/lib/interfaces"
"github.com/wailsapp/wails/lib/logger"
"github.com/wailsapp/wails/lib/messages"
) )
// Manager manages the IPC subsystem type ipcManager struct {
type Manager struct { renderer Renderer // The renderer
renderer interfaces.Renderer // The renderer
messageQueue chan *ipcMessage messageQueue chan *ipcMessage
// quitChannel chan struct{} // quitChannel chan struct{}
// signals chan os.Signal // signals chan os.Signal
log *logger.CustomLogger log *CustomLogger
eventManager interfaces.EventManager eventManager *eventManager
bindingManager interfaces.BindingManager bindingManager *bindingManager
} }
// NewManager creates a new IPC Manager func newIPCManager() *ipcManager {
func NewManager() interfaces.IPCManager { result := &ipcManager{
result := &Manager{
messageQueue: make(chan *ipcMessage, 100), messageQueue: make(chan *ipcMessage, 100),
// quitChannel: make(chan struct{}), // quitChannel: make(chan struct{}),
// signals: make(chan os.Signal, 1), // signals: make(chan os.Signal, 1),
log: logger.NewCustomLogger("IPC"), log: newCustomLogger("IPC"),
} }
return result return result
} }
// BindRenderer sets the renderer, returns the dispatch function // Sets the renderer, returns the dispatch function
func (i *Manager) BindRenderer(renderer interfaces.Renderer) { func (i *ipcManager) bindRenderer(renderer Renderer) {
i.renderer = renderer i.renderer = renderer
} }
// Start the IPC Manager func (i *ipcManager) start(eventManager *eventManager, bindingManager *bindingManager) {
func (i *Manager) Start(eventManager interfaces.EventManager, bindingManager interfaces.BindingManager) {
// Store manager references // Store manager references
i.eventManager = eventManager i.eventManager = eventManager
@@ -49,36 +42,36 @@ func (i *Manager) Start(eventManager interfaces.EventManager, bindingManager int
for running { for running {
select { select {
case incomingMessage := <-i.messageQueue: case incomingMessage := <-i.messageQueue:
i.log.DebugFields("Processing message", logger.Fields{ i.log.DebugFields("Processing message", Fields{
"1D": &incomingMessage, "1D": &incomingMessage,
}) })
switch incomingMessage.Type { switch incomingMessage.Type {
case "call": case "call":
callData := incomingMessage.Payload.(*messages.CallData) callData := incomingMessage.Payload.(*callData)
i.log.DebugFields("Processing call", logger.Fields{ i.log.DebugFields("Processing call", Fields{
"1D": &incomingMessage, "1D": &incomingMessage,
"bindingName": callData.BindingName, "bindingName": callData.BindingName,
"data": callData.Data, "data": callData.Data,
}) })
go func() { go func() {
result, err := bindingManager.ProcessCall(callData) result, err := bindingManager.processCall(callData)
i.log.DebugFields("processed call", logger.Fields{"result": result, "err": err}) i.log.DebugFields("processed call", Fields{"result": result, "err": err})
if err != nil { if err != nil {
incomingMessage.ReturnError(err.Error()) incomingMessage.ReturnError(err.Error())
} else { } else {
incomingMessage.ReturnSuccess(result) incomingMessage.ReturnSuccess(result)
} }
i.log.DebugFields("Finished processing call", logger.Fields{ i.log.DebugFields("Finished processing call", Fields{
"1D": &incomingMessage, "1D": &incomingMessage,
}) })
}() }()
case "event": case "event":
// Extract event data // Extract event data
eventData := incomingMessage.Payload.(*messages.EventData) eventData := incomingMessage.Payload.(*eventData)
// Log // Log
i.log.DebugFields("Processing event", logger.Fields{ i.log.DebugFields("Processing event", Fields{
"name": eventData.Name, "name": eventData.Name,
"data": eventData.Data, "data": eventData.Data,
}) })
@@ -87,24 +80,24 @@ func (i *Manager) Start(eventManager interfaces.EventManager, bindingManager int
i.eventManager.PushEvent(eventData) i.eventManager.PushEvent(eventData)
// Log // Log
i.log.DebugFields("Finished processing event", logger.Fields{ i.log.DebugFields("Finished processing event", Fields{
"name": eventData.Name, "name": eventData.Name,
}) })
case "log": case "log":
logdata := incomingMessage.Payload.(*messages.LogData) logdata := incomingMessage.Payload.(*logData)
switch logdata.Level { switch logdata.Level {
case "info": case "info":
i.log.Info(logdata.Message) logger.Info(logdata.Message)
case "debug": case "debug":
i.log.Debug(logdata.Message) logger.Debug(logdata.Message)
case "warning": case "warning":
i.log.Warn(logdata.Message) logger.Warning(logdata.Message)
case "error": case "error":
i.log.Error(logdata.Message) logger.Error(logdata.Message)
case "fatal": case "fatal":
i.log.Fatal(logdata.Message) logger.Fatal(logdata.Message)
default: default:
i.log.ErrorFields("Invalid log level sent", logger.Fields{ i.log.ErrorFields("Invalid log level sent", Fields{
"level": logdata.Level, "level": logdata.Level,
"message": logdata.Message, "message": logdata.Message,
}) })
@@ -114,7 +107,7 @@ func (i *Manager) Start(eventManager interfaces.EventManager, bindingManager int
} }
// Log // Log
i.log.DebugFields("Finished processing message", logger.Fields{ i.log.DebugFields("Finished processing message", Fields{
"1D": &incomingMessage, "1D": &incomingMessage,
}) })
// case <-manager.quitChannel: // case <-manager.quitChannel:
@@ -132,7 +125,7 @@ func (i *Manager) Start(eventManager interfaces.EventManager, bindingManager int
// Dispatch receives JSON encoded messages from the renderer. // Dispatch receives JSON encoded messages from the renderer.
// It processes the message to ensure that it is valid and places // It processes the message to ensure that it is valid and places
// the processed message on the message queue // the processed message on the message queue
func (i *Manager) Dispatch(message string) { func (i *ipcManager) Dispatch(message string) {
// Create a new IPC Message // Create a new IPC Message
incomingMessage, err := newIPCMessage(message, i.SendResponse) incomingMessage, err := newIPCMessage(message, i.SendResponse)
@@ -155,7 +148,7 @@ func (i *Manager) Dispatch(message string) {
} }
// SendResponse sends the given response back to the frontend // SendResponse sends the given response back to the frontend
func (i *Manager) SendResponse(response *ipcResponse) error { func (i *ipcManager) SendResponse(response *ipcResponse) error {
// Serialise the Message // Serialise the Message
data, err := response.Serialise() data, err := response.Serialise()

View File

@@ -1,4 +1,4 @@
package ipc package wails
import ( import (
"encoding/json" "encoding/json"

View File

@@ -1,4 +1,4 @@
package ipc package wails
import ( import (
"encoding/hex" "encoding/hex"

View File

@@ -1,71 +0,0 @@
package binding
import (
"fmt"
"strings"
"github.com/wailsapp/wails/lib/logger"
"github.com/wailsapp/wails/lib/messages"
"github.com/wailsapp/wails/runtime/go/runtime"
)
type internalMethods struct {
log *logger.CustomLogger
browser *runtime.Browser
}
func newInternalMethods() *internalMethods {
return &internalMethods{
log: logger.NewCustomLogger("InternalCall"),
browser: runtime.NewBrowser(),
}
}
func (i *internalMethods) processCall(callData *messages.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

@@ -1,14 +0,0 @@
package interfaces
// AppConfig is the application config interface
type AppConfig interface {
GetWidth() int
GetHeight() int
GetTitle() string
GetResizable() bool
GetDefaultHTML() string
GetDisableInspector() bool
GetColour() string
GetCSS() string
GetJS() string
}

View File

@@ -1,10 +0,0 @@
package interfaces
import "github.com/wailsapp/wails/lib/messages"
// BindingManager is the binding manager interface
type BindingManager interface {
Bind(object interface{})
Start(renderer Renderer, runtime Runtime) error
ProcessCall(callData *messages.CallData) (result interface{}, err error)
}

View File

@@ -1,11 +0,0 @@
package interfaces
import "github.com/wailsapp/wails/lib/messages"
// EventManager is the event manager interface
type EventManager interface {
PushEvent(*messages.EventData)
Emit(eventName string, optionalData ...interface{})
On(eventName string, callback func(...interface{}))
Start(Renderer)
}

View File

@@ -1,8 +0,0 @@
package interfaces
// IPCManager is the event manager interface
type IPCManager interface {
BindRenderer(Renderer)
Dispatch(message string)
Start(eventManager EventManager, bindingManager BindingManager)
}

View File

@@ -1,4 +0,0 @@
package interfaces
// Runtime interface
type Runtime interface {}

View File

@@ -1,7 +0,0 @@
package messages
// CallData represents a call to a Go function/method
type CallData struct {
BindingName string `json:"bindingName"`
Data string `json:"data,omitempty"`
}

View File

@@ -1,7 +0,0 @@
package messages
// EventData represents an event sent from the frontend
type EventData struct {
Name string `json:"name"`
Data interface{} `json:"data"`
}

View File

@@ -1,7 +0,0 @@
package messages
// LogData represents a call to log from the frontend
type LogData struct {
Level string `json:"level"`
Message string `json:"string"`
}

File diff suppressed because one or more lines are too long

View File

@@ -1,14 +1,14 @@
package logger package wails
import ( import (
"os" "os"
"strings" "strings"
"github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
// Global logger reference // Global logger reference
var logger = logrus.New() var logger = log.New()
// Fields is used by the customLogger object to output // Fields is used by the customLogger object to output
// fields along with a message // fields along with a message
@@ -17,26 +17,26 @@ type Fields map[string]interface{}
// Default options for the global logger // Default options for the global logger
func init() { func init() {
logger.SetOutput(os.Stdout) logger.SetOutput(os.Stdout)
logger.SetLevel(logrus.DebugLevel) logger.SetLevel(log.DebugLevel)
} }
// SetLogLevel sets the log level to the given level // Sets the log level to the given level
func SetLogLevel(level string) { func setLogLevel(level string) {
switch strings.ToLower(level) { switch strings.ToLower(level) {
case "info": case "info":
logger.SetLevel(logrus.InfoLevel) logger.SetLevel(log.InfoLevel)
case "debug": case "debug":
logger.SetLevel(logrus.DebugLevel) logger.SetLevel(log.DebugLevel)
case "warn": case "warn":
logger.SetLevel(logrus.WarnLevel) logger.SetLevel(log.WarnLevel)
case "error": case "error":
logger.SetLevel(logrus.ErrorLevel) logger.SetLevel(log.ErrorLevel)
case "fatal": case "fatal":
logger.SetLevel(logrus.FatalLevel) logger.SetLevel(log.FatalLevel)
case "panic": case "panic":
logger.SetLevel(logrus.PanicLevel) logger.SetLevel(log.PanicLevel)
default: default:
logger.SetLevel(logrus.DebugLevel) logger.SetLevel(log.DebugLevel)
logger.Warnf("Log level '%s' not recognised. Setting to Debug.", level) logger.Warnf("Log level '%s' not recognised. Setting to Debug.", level)
} }
} }

View File

@@ -1,4 +1,4 @@
package logger package wails
// CustomLogger is a wrapper object to logrus // CustomLogger is a wrapper object to logrus
type CustomLogger struct { type CustomLogger struct {
@@ -6,8 +6,7 @@ type CustomLogger struct {
errorOnly bool errorOnly bool
} }
// NewCustomLogger creates a new custom logger with the given prefix func newCustomLogger(prefix string) *CustomLogger {
func NewCustomLogger(prefix string) *CustomLogger {
return &CustomLogger{ return &CustomLogger{
prefix: "[" + prefix + "] ", prefix: "[" + prefix + "] ",
} }

View File

@@ -1,11 +1,8 @@
package interfaces package wails
import (
"github.com/wailsapp/wails/lib/messages"
)
// Renderer is an interface describing a Wails target to render the app to // Renderer is an interface describing a Wails target to render the app to
type Renderer interface { type Renderer interface {
Initialise(AppConfig, IPCManager, EventManager) error Initialise(*AppConfig, *ipcManager, *eventManager) error
Run() error Run() error
// Binding // Binding
@@ -13,7 +10,7 @@ type Renderer interface {
Callback(data string) error Callback(data string) error
// Events // Events
NotifyEvent(eventData *messages.EventData) error NotifyEvent(eventData *eventData) error
// Dialog Runtime // Dialog Runtime
SelectFile() string SelectFile() string

View File

@@ -1,4 +1,4 @@
package renderer package wails
import ( import (
"encoding/json" "encoding/json"
@@ -10,9 +10,6 @@ import (
"github.com/dchest/htmlmin" "github.com/dchest/htmlmin"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
"github.com/leaanthony/mewn" "github.com/leaanthony/mewn"
"github.com/wailsapp/wails/lib/interfaces"
"github.com/wailsapp/wails/lib/logger"
"github.com/wailsapp/wails/lib/messages"
) )
type messageType int type messageType int
@@ -35,10 +32,10 @@ func (m messageType) toString() string {
// and renders the files over a websocket // and renders the files over a websocket
type Headless struct { type Headless struct {
// Common // Common
log *logger.CustomLogger log *CustomLogger
ipcManager interfaces.IPCManager ipcManager *ipcManager
appConfig interfaces.AppConfig appConfig *AppConfig
eventManager interfaces.EventManager eventManager *eventManager
bindingCache []string bindingCache []string
// Headless specific // Headless specific
@@ -51,12 +48,12 @@ type Headless struct {
} }
// Initialise the Headless Renderer // Initialise the Headless Renderer
func (h *Headless) Initialise(appConfig interfaces.AppConfig, ipcManager interfaces.IPCManager, eventManager interfaces.EventManager) error { func (h *Headless) Initialise(appConfig *AppConfig, ipcManager *ipcManager, eventManager *eventManager) error {
h.ipcManager = ipcManager h.ipcManager = ipcManager
h.appConfig = appConfig h.appConfig = appConfig
h.eventManager = eventManager h.eventManager = eventManager
ipcManager.BindRenderer(h) ipcManager.bindRenderer(h)
h.log = logger.NewCustomLogger("Bridge") h.log = newCustomLogger("Bridge")
return nil return nil
} }
@@ -86,7 +83,7 @@ func (h *Headless) injectCSS(css string) {
minifiedCSS = strings.Replace(minifiedCSS, "\\", "\\\\", -1) minifiedCSS = strings.Replace(minifiedCSS, "\\", "\\\\", -1)
minifiedCSS = strings.Replace(minifiedCSS, "'", "\\'", -1) minifiedCSS = strings.Replace(minifiedCSS, "'", "\\'", -1)
minifiedCSS = strings.Replace(minifiedCSS, "\n", " ", -1) minifiedCSS = strings.Replace(minifiedCSS, "\n", " ", -1)
inject := fmt.Sprintf("wails._.InjectCSS('%s')", minifiedCSS) inject := fmt.Sprintf("wails._.injectCSS('%s')", minifiedCSS)
h.evalJS(inject, cssMessage) h.evalJS(inject, cssMessage)
} }
@@ -120,7 +117,7 @@ func (h *Headless) start(conn *websocket.Conn) {
// set external.invoke // set external.invoke
h.log.Infof("Connected to frontend.") h.log.Infof("Connected to frontend.")
wailsRuntime := mewn.String("../../runtime/js/dist/wails.js") wailsRuntime := mewn.String("./wailsruntimeassets/default/wails.min.js")
h.evalJS(wailsRuntime, wailsRuntimeMessage) h.evalJS(wailsRuntime, wailsRuntimeMessage)
// Inject bindings // Inject bindings
@@ -195,13 +192,13 @@ func (h *Headless) Callback(data string) error {
} }
// NotifyEvent notifies the frontend of an event // NotifyEvent notifies the frontend of an event
func (h *Headless) NotifyEvent(event *messages.EventData) error { func (h *Headless) NotifyEvent(event *eventData) error {
// Look out! Nils about! // Look out! Nils about!
var err error var err error
if event == nil { if event == nil {
err = fmt.Errorf("Sent nil event to renderer.webViewRenderer") err = fmt.Errorf("Sent nil event to renderer.webViewRenderer")
h.log.Error(err.Error()) logger.Error(err)
return err return err
} }
@@ -218,14 +215,14 @@ func (h *Headless) NotifyEvent(event *messages.EventData) error {
} }
} }
message := fmt.Sprintf("window.wails._.Notify('%s','%s')", event.Name, data) message := fmt.Sprintf("window.wails._.notify('%s','%s')", event.Name, data)
return h.evalJS(message, notifyMessage) return h.evalJS(message, notifyMessage)
} }
// SetColour is unsupported for Headless but required // SetColour is unsupported for Headless but required
// for the Renderer interface // for the Renderer interface
func (h *Headless) SetColour(colour string) error { func (h *Headless) SetColour(colour string) error {
h.log.WarnFields("SetColour ignored for headless more", logger.Fields{"col": colour}) h.log.WarnFields("SetColour ignored for headless more", Fields{"col": colour})
return nil return nil
} }
@@ -244,7 +241,7 @@ func (h *Headless) UnFullscreen() {
// SetTitle is currently unsupported for Headless but required // SetTitle is currently unsupported for Headless but required
// for the Renderer interface // for the Renderer interface
func (h *Headless) SetTitle(title string) { func (h *Headless) SetTitle(title string) {
h.log.WarnFields("SetTitle() unsupported in bridge mode", logger.Fields{"title": title}) h.log.WarnFields("SetTitle() unsupported in bridge mode", Fields{"title": title})
} }
// Close is unsupported for Headless but required // Close is unsupported for Headless but required

View File

@@ -1,61 +1,52 @@
package renderer package wails
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"math/rand" "math/rand"
"strings"
"sync" "sync"
"time" "time"
"github.com/go-playground/colors" "github.com/go-playground/colors"
"github.com/leaanthony/mewn" "github.com/leaanthony/mewn"
"github.com/wailsapp/wails/lib/logger"
"github.com/wailsapp/wails/lib/messages"
"github.com/wailsapp/wails/lib/interfaces"
"github.com/wailsapp/webview" "github.com/wailsapp/webview"
) )
// WebView defines the main webview application window // Window defines the main application window
// Default values in [] // Default values in []
type WebView struct { type webViewRenderer struct {
window webview.WebView // The webview object window webview.WebView // The webview object
ipc interfaces.IPCManager ipc *ipcManager
log *logger.CustomLogger log *CustomLogger
config interfaces.AppConfig config *AppConfig
eventManager interfaces.EventManager eventManager *eventManager
bindingCache []string bindingCache []string
} }
// NewWebView returns a new WebView struct
func NewWebView() *WebView {
return &WebView{};
}
// Initialise sets up the WebView // Initialise sets up the WebView
func (w *WebView) Initialise(config interfaces.AppConfig, ipc interfaces.IPCManager, eventManager interfaces.EventManager) error { func (w *webViewRenderer) Initialise(config *AppConfig, ipc *ipcManager, eventManager *eventManager) error {
// Store reference to eventManager // Store reference to eventManager
w.eventManager = eventManager w.eventManager = eventManager
// Set up logger // Set up logger
w.log = logger.NewCustomLogger("WebView") w.log = newCustomLogger("WebView")
// Set up the dispatcher function // Set up the dispatcher function
w.ipc = ipc w.ipc = ipc
ipc.BindRenderer(w) ipc.bindRenderer(w)
// Save the config // Save the config
w.config = config w.config = config
// Create the WebView instance // Create the WebView instance
w.window = webview.NewWebview(webview.Settings{ w.window = webview.NewWebview(webview.Settings{
Width: config.GetWidth(), Width: config.Width,
Height: config.GetHeight(), Height: config.Height,
Title: config.GetTitle(), Title: config.Title,
Resizable: config.GetResizable(), Resizable: config.Resizable,
URL: config.GetDefaultHTML(), URL: config.defaultHTML,
Debug: !config.GetDisableInspector(), Debug: !config.DisableInspector,
ExternalInvokeCallback: func(_ webview.WebView, message string) { ExternalInvokeCallback: func(_ webview.WebView, message string) {
w.ipc.Dispatch(message) w.ipc.Dispatch(message)
}, },
@@ -64,7 +55,7 @@ func (w *WebView) Initialise(config interfaces.AppConfig, ipc interfaces.IPCMana
// SignalManager.OnExit(w.Exit) // SignalManager.OnExit(w.Exit)
// Set colour // Set colour
err := w.SetColour(config.GetColour()) err := w.SetColour(config.Colour)
if err != nil { if err != nil {
return err return err
} }
@@ -73,8 +64,7 @@ func (w *WebView) Initialise(config interfaces.AppConfig, ipc interfaces.IPCMana
return nil return nil
} }
// SetColour sets the window colour func (w *webViewRenderer) SetColour(colour string) error {
func (w *WebView) SetColour(colour string) error {
color, err := colors.Parse(colour) color, err := colors.Parse(colour)
if err != nil { if err != nil {
return err return err
@@ -90,12 +80,12 @@ func (w *WebView) SetColour(colour string) error {
// evalJS evaluates the given js in the WebView // evalJS evaluates the given js in the WebView
// I should rename this to evilJS lol // I should rename this to evilJS lol
func (w *WebView) evalJS(js string) error { func (w *webViewRenderer) evalJS(js string) error {
outputJS := fmt.Sprintf("%.45s", js) outputJS := fmt.Sprintf("%.45s", js)
if len(js) > 45 { if len(js) > 45 {
outputJS += "..." outputJS += "..."
} }
w.log.DebugFields("Eval", logger.Fields{"js": outputJS}) w.log.DebugFields("Eval", Fields{"js": outputJS})
// //
w.window.Dispatch(func() { w.window.Dispatch(func() {
w.window.Eval(js) w.window.Eval(js)
@@ -103,21 +93,12 @@ func (w *WebView) evalJS(js string) error {
return nil return nil
} }
// Escape the Javascripts!
func escapeJS(js string) (string, error) {
result := strings.Replace(js, "\\", "\\\\", -1)
result = strings.Replace(result, "'", "\\'", -1)
result = strings.Replace(result, "\n", "\\n", -1)
return result, nil
}
// evalJSSync evaluates the given js in the WebView synchronously // evalJSSync evaluates the given js in the WebView synchronously
// Do not call this from the main thread or you'll nuke your app because // Do not call this from the main thread or you'll nuke your app because
// you won't get the callback. // you won't get the callback.
func (w *WebView) evalJSSync(js string) error { func (w *webViewRenderer) evalJSSync(js string) error {
minified, err := escapeJS(js) minified, err := escapeJS(js)
if err != nil { if err != nil {
return err return err
} }
@@ -126,7 +107,7 @@ func (w *WebView) evalJSSync(js string) error {
if len(js) > 45 { if len(js) > 45 {
outputJS += "..." outputJS += "..."
} }
w.log.DebugFields("EvalSync", logger.Fields{"js": outputJS}) w.log.DebugFields("EvalSync", Fields{"js": outputJS})
ID := fmt.Sprintf("syncjs:%d:%d", time.Now().Unix(), rand.Intn(9999)) ID := fmt.Sprintf("syncjs:%d:%d", time.Now().Unix(), rand.Intn(9999))
var wg sync.WaitGroup var wg sync.WaitGroup
@@ -141,7 +122,7 @@ func (w *WebView) evalJSSync(js string) error {
wg.Done() wg.Done()
exit = true exit = true
}) })
command := fmt.Sprintf("wails._.AddScript('%s', '%s')", minified, ID) command := fmt.Sprintf("wails._.addScript('%s', '%s')", minified, ID)
w.window.Dispatch(func() { w.window.Dispatch(func() {
w.window.Eval(command) w.window.Eval(command)
}) })
@@ -156,24 +137,24 @@ func (w *WebView) evalJSSync(js string) error {
} }
// injectCSS adds the given CSS to the WebView // injectCSS adds the given CSS to the WebView
func (w *WebView) injectCSS(css string) { func (w *webViewRenderer) injectCSS(css string) {
w.window.Dispatch(func() { w.window.Dispatch(func() {
w.window.InjectCSS(css) w.window.InjectCSS(css)
}) })
} }
// Exit closes the window // Quit the window
func (w *WebView) Exit() { func (w *webViewRenderer) Exit() {
w.window.Exit() w.window.Exit()
} }
// Run the window main loop // Run the window main loop
func (w *WebView) Run() error { func (w *webViewRenderer) Run() error {
w.log.Info("Run()") w.log.Info("Run()")
// Runtime assets // Runtime assets
wailsRuntime := mewn.String("../../runtime/js/dist/wails.js") wailsRuntime := mewn.String("./wailsruntimeassets/default/wails.min.js")
w.evalJS(wailsRuntime) w.evalJS(wailsRuntime)
// Ping the wait channel when the wails runtime is loaded // Ping the wait channel when the wails runtime is loaded
@@ -187,30 +168,38 @@ func (w *WebView) Run() error {
w.evalJSSync(binding) w.evalJSSync(binding)
} }
// // Inject Framework
// if w.frameworkJS != "" {
// w.evalJSSync(w.frameworkJS)
// }
// if w.frameworkCSS != "" {
// w.injectCSS(w.frameworkCSS)
// }
// Inject user CSS // Inject user CSS
if w.config.GetCSS() != "" { if w.config.CSS != "" {
outputCSS := fmt.Sprintf("%.45s", w.config.GetCSS()) outputCSS := fmt.Sprintf("%.45s", w.config.CSS)
if len(outputCSS) > 45 { if len(outputCSS) > 45 {
outputCSS += "..." outputCSS += "..."
} }
w.log.DebugFields("Inject User CSS", logger.Fields{"css": outputCSS}) w.log.DebugFields("Inject User CSS", Fields{"css": outputCSS})
w.injectCSS(w.config.GetCSS()) w.injectCSS(w.config.CSS)
} else { } else {
// Use default wails css // Use default wails css
w.log.Debug("Injecting Default Wails CSS") w.log.Debug("Injecting Default Wails CSS")
defaultCSS := mewn.String("../../runtime/assets/wails.css") defaultCSS := mewn.String("./wailsruntimeassets/default/wails.css")
w.injectCSS(defaultCSS) w.injectCSS(defaultCSS)
} }
// Inject user JS // Inject user JS
if w.config.GetJS() != "" { if w.config.JS != "" {
outputJS := fmt.Sprintf("%.45s", w.config.GetJS()) outputJS := fmt.Sprintf("%.45s", w.config.JS)
if len(outputJS) > 45 { if len(outputJS) > 45 {
outputJS += "..." outputJS += "..."
} }
w.log.DebugFields("Inject User JS", logger.Fields{"js": outputJS}) w.log.DebugFields("Inject User JS", Fields{"js": outputJS})
w.evalJSSync(w.config.GetJS()) w.evalJSSync(w.config.JS)
} }
// Emit that everything is loaded and ready // Emit that everything is loaded and ready
@@ -224,15 +213,14 @@ func (w *WebView) Run() error {
return nil return nil
} }
// NewBinding registers a new binding with the frontend // Binds the given method name with the front end
func (w *WebView) NewBinding(methodName string) error { func (w *webViewRenderer) NewBinding(methodName string) error {
objectCode := fmt.Sprintf("window.wails._.NewBinding('%s');", methodName) objectCode := fmt.Sprintf("window.wails._.newBinding('%s');", methodName)
w.bindingCache = append(w.bindingCache, objectCode) w.bindingCache = append(w.bindingCache, objectCode)
return nil return nil
} }
// SelectFile opens a dialog that allows the user to select a file func (w *webViewRenderer) SelectFile() string {
func (w *WebView) SelectFile() 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
@@ -250,8 +238,7 @@ func (w *WebView) SelectFile() string {
return result return result
} }
// SelectDirectory opens a dialog that allows the user to select a directory func (w *webViewRenderer) SelectDirectory() string {
func (w *WebView) SelectDirectory() 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
@@ -268,8 +255,7 @@ func (w *WebView) SelectDirectory() string {
return result return result
} }
// SelectSaveFile opens a dialog that allows the user to select a file to save func (w *webViewRenderer) SelectSaveFile() string {
func (w *WebView) SelectSaveFile() 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
@@ -287,19 +273,18 @@ func (w *WebView) SelectSaveFile() string {
} }
// Callback sends a callback to the frontend // Callback sends a callback to the frontend
func (w *WebView) Callback(data string) error { func (w *webViewRenderer) Callback(data string) error {
callbackCMD := fmt.Sprintf("window.wails._.Callback('%s');", data) callbackCMD := fmt.Sprintf("window.wails._.callback('%s');", data)
return w.evalJS(callbackCMD) return w.evalJS(callbackCMD)
} }
// NotifyEvent notifies the frontend about a backend runtime event func (w *webViewRenderer) NotifyEvent(event *eventData) error {
func (w *WebView) NotifyEvent(event *messages.EventData) error {
// Look out! Nils about! // Look out! Nils about!
var err error var err error
if event == nil { if event == nil {
err = fmt.Errorf("Sent nil event to renderer.WebView") err = fmt.Errorf("Sent nil event to renderer.webViewRenderer")
w.log.Error(err.Error()) logger.Error(err)
return err return err
} }
@@ -316,13 +301,13 @@ func (w *WebView) NotifyEvent(event *messages.EventData) error {
} }
} }
message := fmt.Sprintf("wails._.Notify('%s','%s')", event.Name, data) message := fmt.Sprintf("wails._.notify('%s','%s')", event.Name, data)
return w.evalJS(message) return w.evalJS(message)
} }
// Fullscreen makes the main window go fullscreen // Window
func (w *WebView) Fullscreen() { func (w *webViewRenderer) Fullscreen() {
if w.config.GetResizable() == false { if w.config.Resizable == false {
w.log.Warn("Cannot call Fullscreen() - App.Resizable = false") w.log.Warn("Cannot call Fullscreen() - App.Resizable = false")
return return
} }
@@ -331,9 +316,8 @@ func (w *WebView) Fullscreen() {
}) })
} }
// UnFullscreen returns the window to the position prior to a fullscreen call func (w *webViewRenderer) UnFullscreen() {
func (w *WebView) UnFullscreen() { if w.config.Resizable == false {
if w.config.GetResizable() == false {
w.log.Warn("Cannot call UnFullscreen() - App.Resizable = false") w.log.Warn("Cannot call UnFullscreen() - App.Resizable = false")
return return
} }
@@ -342,15 +326,13 @@ func (w *WebView) UnFullscreen() {
}) })
} }
// SetTitle sets the window title func (w *webViewRenderer) SetTitle(title string) {
func (w *WebView) SetTitle(title string) {
w.window.Dispatch(func() { w.window.Dispatch(func() {
w.window.SetTitle(title) w.window.SetTitle(title)
}) })
} }
// Close closes the window func (w *webViewRenderer) Close() {
func (w *WebView) Close() {
w.window.Dispatch(func() { w.window.Dispatch(func() {
w.window.Terminate() w.window.Terminate()
}) })

20
runtime.go Normal file
View File

@@ -0,0 +1,20 @@
package wails
// Runtime is the Wails Runtime Interface, given to a user who has defined the WailsInit method
type Runtime struct {
Events *RuntimeEvents
Log *RuntimeLog
Dialog *RuntimeDialog
Window *RuntimeWindow
FileSystem *RuntimeFileSystem
}
func newRuntime(eventManager *eventManager, renderer Renderer) *Runtime {
return &Runtime{
Events: newRuntimeEvents(eventManager),
Log: newRuntimeLog(),
Dialog: newRuntimeDialog(renderer),
Window: newRuntimeWindow(renderer),
FileSystem: newRuntimeFileSystem(),
}
}

View File

@@ -1,216 +0,0 @@
/*
Wails Bridge (c) 2019-present Lea Anthony
This library creates a bridge between your application
and the frontend, allowing you to develop your app using
standard tooling (browser extensions, live reload, etc).
Usage:
```
import Bridge from "./wailsbridge";
Bridge.Start(startApp);
```
The given callback (startApp in the example) will be called
when the bridge has successfully initialised. It passes the
window.wails object back, in case it is not accessible directly.
*/
// Bridge object
window.wailsbridge = {
reconnectOverlay: null,
reconnectTimer: 300,
wsURL: 'ws://localhost:34115/bridge',
connectionState: null,
config: {},
websocket: null,
callback: null,
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>',
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)}}',
log: function (message) {
// eslint-disable-next-line
console.log(
'%c wails bridge %c ' + message + ' ',
'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'
);
}
};
// Adapted from webview - thanks zserge!
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);
}
// Creates a node in the Dom
function createNode(parent, elementType, id, className, content) {
var d = document.createElement(elementType);
if (id) {
d.id = id;
}
if (className) {
d.className = className;
}
if (content) {
d.innerHTML = content;
}
parent.appendChild(d);
return d;
}
// Sets up the overlay
function setupOverlay() {
var body = document.body;
var wailsBridgeNode = createNode(body, 'div', 'wails-bridge');
wailsBridgeNode.innerHTML = window.wailsbridge.overlayHTML;
// Inject the overlay CSS
injectCSS(window.wailsbridge.overlayCSS);
}
// Start the Wails Bridge
function startBridge() {
// Setup the overlay
setupOverlay();
window.wailsbridge.websocket = null;
window.wailsbridge.connectTimer = null;
window.wailsbridge.reconnectOverlay = document.querySelector(
'.wails-reconnect-overlay'
);
window.wailsbridge.connectionState = 'disconnected';
// Shows the overlay
function showReconnectOverlay() {
window.wailsbridge.reconnectOverlay.style.display = 'block';
}
// Hides the overlay
function hideReconnectOverlay() {
window.wailsbridge.reconnectOverlay.style.display = 'none';
}
// Bridge external.invoke
window.external = {
invoke: function (msg) {
window.wailsbridge.websocket.send(msg);
}
};
// Adds a script to the Dom.
// Removes it if second parameter is true.
function addScript(script, remove) {
var s = document.createElement('script');
s.setAttribute('type', 'text/javascript');
s.textContent = script;
document.head.appendChild(s);
// Remove internal messages from the DOM
if (remove) {
s.parentNode.removeChild(s);
}
}
// Handles incoming websocket connections
function handleConnect() {
window.wailsbridge.log('Connected to backend');
hideReconnectOverlay();
clearInterval(window.wailsbridge.connectTimer);
window.wailsbridge.websocket.onclose = handleDisconnect;
window.wailsbridge.websocket.onmessage = handleMessage;
window.wailsbridge.connectionState = 'connected';
}
// Handles websocket disconnects
function handleDisconnect() {
window.wailsbridge.log('Disconnected from backend');
window.wailsbridge.websocket = null;
window.wailsbridge.connectionState = 'disconnected';
showReconnectOverlay();
connect();
}
// Try to connect to the backend every 300ms (default value).
// Change this value in the main wailsbridge object.
function connect() {
window.wailsbridge.connectTimer = setInterval(function () {
if (window.wailsbridge.websocket == null) {
window.wailsbridge.websocket = new WebSocket(window.wailsbridge.wsURL);
window.wailsbridge.websocket.onopen = handleConnect;
window.wailsbridge.websocket.onerror = function (e) {
e.stopImmediatePropagation();
e.stopPropagation();
e.preventDefault();
window.wailsbridge.websocket = null;
return false;
};
}
}, window.wailsbridge.reconnectTimer);
}
function handleMessage(message) {
// As a bridge we ignore js and css injections
switch (message.data[0]) {
// Wails library - inject!
case 'w':
addScript(message.data.slice(1));
// Now wails runtime is loaded, wails for the ready event
// and callback to the main app
window.wails.Events.On('wails:loaded', function () {
window.wailsbridge.log('Wails Ready');
if (window.wailsbridge.callback) {
window.wailsbridge.log('Notifying application');
window.wailsbridge.callback(window.wails);
}
});
window.wailsbridge.log('Loaded Wails Runtime');
break;
// Notifications
case 'n':
addScript(message.data.slice(1), true);
break;
// Binding
case 'b':
var binding = message.data.slice(1);
//log("Binding: " + binding)
window.wails._.NewBinding(binding);
break;
// Call back
case 'c':
var callbackData = message.data.slice(1);
window.wails._.Callback(callbackData);
break;
default:
window.wails.Log.Error('Unknown message type received: ' + message.data[0]);
}
}
// Start by showing the overlay...
showReconnectOverlay();
// ...and attempt to connect
connect();
}
export default {
// The main function
// Passes the main Wails object to the callback if given.
Start: function (callback) {
// Save the callback
window.wailsbridge.callback = callback;
// Start Bridge
startBridge();
}
};

View File

@@ -1,17 +0,0 @@
/*
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

@@ -1,21 +0,0 @@
package runtime
import "github.com/pkg/browser"
// Browser exposes browser methods to the runtime
type Browser struct{}
// NewBrowser creates a new runtime Browser struct
func NewBrowser() *Browser {
return &Browser{}
}
// OpenURL opens the given url in the system's default browser
func (r *Browser) OpenURL(url string) error {
return browser.OpenURL(url)
}
// OpenFile opens the given file in the system's default browser
func (r *Browser) OpenFile(filePath string) error {
return browser.OpenFile(filePath)
}

View File

@@ -1,30 +0,0 @@
package runtime
import "github.com/wailsapp/wails/lib/interfaces"
// Dialog exposes an interface to native dialogs
type Dialog struct {
renderer interfaces.Renderer
}
// newDialog creates a new Dialog struct
func newDialog(renderer interfaces.Renderer) *Dialog {
return &Dialog{
renderer: renderer,
}
}
// SelectFile prompts the user to select a file
func (r *Dialog) SelectFile() string {
return r.renderer.SelectFile()
}
// SelectDirectory prompts the user to select a directory
func (r *Dialog) SelectDirectory() string {
return r.renderer.SelectDirectory()
}
// SelectSaveFile prompts the user to select a file for saving
func (r *Dialog) SelectSaveFile() string {
return r.renderer.SelectSaveFile()
}

View File

@@ -1,24 +0,0 @@
package runtime
import "github.com/wailsapp/wails/lib/interfaces"
// Events exposes the events interface
type Events struct {
eventManager interfaces.EventManager
}
func newEvents(eventManager interfaces.EventManager) *Events {
return &Events{
eventManager: eventManager,
}
}
// On pass through
func (r *Events) On(eventName string, callback func(optionalData ...interface{})) {
r.eventManager.On(eventName, callback)
}
// Emit pass through
func (r *Events) Emit(eventName string, optionalData ...interface{}) {
r.eventManager.Emit(eventName, optionalData...)
}

View File

@@ -1,16 +0,0 @@
package runtime
import homedir "github.com/mitchellh/go-homedir"
// FileSystem exposes file system utilities to the runtime
type FileSystem struct {}
// Creates a new FileSystem struct
func newFileSystem() *FileSystem {
return &FileSystem{}
}
// HomeDir returns the user's home directory
func (r *FileSystem) HomeDir() (string, error) {
return homedir.Dir()
}

View File

@@ -1,16 +0,0 @@
package runtime
import "github.com/wailsapp/wails/lib/logger"
// Log exposes the logging interface to the runtime
type Log struct{}
// newLog creates a new Log struct
func newLog() *Log {
return &Log{}
}
// New creates a new logger
func (r *Log) New(prefix string) *logger.CustomLogger {
return logger.NewCustomLogger(prefix)
}

View File

@@ -1,25 +0,0 @@
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
}
// NewRuntime creates a new Runtime struct
func NewRuntime(eventManager interfaces.EventManager, renderer interfaces.Renderer) *Runtime {
return &Runtime{
Events: newEvents(eventManager),
Log: newLog(),
Dialog: newDialog(renderer),
Window: newWindow(renderer),
Browser: NewBrowser(),
FileSystem: newFileSystem(),
}
}

Some files were not shown because too many files have changed in this diff Show More