mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-13 15:39:31 +08:00
commit
9370030ff3
@ -1,42 +0,0 @@
|
|||||||
{{ 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 -}}
|
|
@ -1,27 +0,0 @@
|
|||||||
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
|
|
1
.eslintignore
Normal file
1
.eslintignore
Normal file
@ -0,0 +1 @@
|
|||||||
|
runtime/assets/default.html
|
30
.eslintrc
Normal file
30
.eslintrc
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"env": {
|
||||||
|
"browser": true,
|
||||||
|
"es6": true,
|
||||||
|
"node": 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
2
.gitignore
vendored
@ -16,4 +16,4 @@ examples/**/example*
|
|||||||
cmd/wails/wails
|
cmd/wails/wails
|
||||||
.DS_Store
|
.DS_Store
|
||||||
tmp
|
tmp
|
||||||
dist
|
node_modules/
|
6
.hound.yml
Normal file
6
.hound.yml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
jshint:
|
||||||
|
config_file: .jshintrc
|
||||||
|
eslint:
|
||||||
|
enabled: true
|
||||||
|
config_file: .eslintrc
|
||||||
|
ignore_file: .eslintignore
|
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@ -1,3 +1,4 @@
|
|||||||
{
|
{
|
||||||
"go.formatTool": "goimports"
|
"go.formatTool": "goimports",
|
||||||
|
"eslint.alwaysShowStatus": true
|
||||||
}
|
}
|
@ -1,3 +1,9 @@
|
|||||||
|
|
||||||
|
2019-07-20 **v0.17.6-pre**
|
||||||
|
* Significant refactor of runtime
|
||||||
|
* Removed wailsbridge file - now a unified approach taken
|
||||||
|
* Fixed React on Windows - Thanks [Florian Didran](https://github.com/fdidron)!
|
||||||
|
|
||||||
2019-06-18 **v0.16.0**
|
2019-06-18 **v0.16.0**
|
||||||
* React template FTW! - Thanks [admin_3.exe](https://github.com/bh90210)!
|
* React template FTW! - Thanks [admin_3.exe](https://github.com/bh90210)!
|
||||||
* Updated contributors
|
* Updated contributors
|
||||||
|
@ -12,3 +12,6 @@ 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)
|
||||||
|
* [Florian Didran](https://github.com/fdidron)
|
||||||
|
@ -46,7 +46,7 @@ Make sure you have the xcode command line tools installed. This can be done by r
|
|||||||
|
|
||||||
### Linux
|
### Linux
|
||||||
|
|
||||||
#### Ubuntu 18.04, Debian 9
|
#### Ubuntu 18.04, Debian 9, Zorin 15
|
||||||
|
|
||||||
`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`
|
||||||
|
|
||||||
|
52
app.go
52
app.go
@ -2,6 +2,12 @@ package wails
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/wailsapp/wails/cmd"
|
"github.com/wailsapp/wails/cmd"
|
||||||
|
"github.com/wailsapp/wails/lib/binding"
|
||||||
|
"github.com/wailsapp/wails/lib/event"
|
||||||
|
"github.com/wailsapp/wails/lib/interfaces"
|
||||||
|
"github.com/wailsapp/wails/lib/ipc"
|
||||||
|
"github.com/wailsapp/wails/lib/logger"
|
||||||
|
"github.com/wailsapp/wails/lib/renderer"
|
||||||
)
|
)
|
||||||
|
|
||||||
// -------------------------------- Compile time Flags ------------------------------
|
// -------------------------------- Compile time Flags ------------------------------
|
||||||
@ -13,15 +19,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 Renderer // The renderer is what we will render the app to
|
renderer interfaces.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 *ipcManager // Handles the IPC calls
|
ipc interfaces.IPCManager // Handles the IPC calls
|
||||||
log *CustomLogger // Logger
|
log *logger.CustomLogger // Logger
|
||||||
bindingManager *bindingManager // Handles binding of Go code to renderer
|
bindingManager interfaces.BindingManager // Handles binding of Go code to renderer
|
||||||
eventManager *eventManager // Handles all the events
|
eventManager interfaces.EventManager // Handles all the events
|
||||||
runtime *Runtime // The runtime object for registered structs
|
runtime interfaces.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
|
||||||
@ -34,14 +40,14 @@ func CreateApp(optionalConfig ...*AppConfig) *App {
|
|||||||
|
|
||||||
result := &App{
|
result := &App{
|
||||||
logLevel: "info",
|
logLevel: "info",
|
||||||
renderer: &webViewRenderer{},
|
renderer: renderer.NewWebView(),
|
||||||
ipc: newIPCManager(),
|
ipc: ipc.NewManager(),
|
||||||
bindingManager: newBindingManager(),
|
bindingManager: binding.NewManager(),
|
||||||
eventManager: newEventManager(),
|
eventManager: event.NewManager(),
|
||||||
log: newCustomLogger("App"),
|
log: logger.NewCustomLogger("App"),
|
||||||
}
|
}
|
||||||
|
|
||||||
appconfig, err := newAppConfig(userConfig)
|
appconfig, err := newConfig(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())
|
||||||
}
|
}
|
||||||
@ -75,14 +81,14 @@ func (a *App) Run() error {
|
|||||||
func (a *App) start() error {
|
func (a *App) start() error {
|
||||||
|
|
||||||
// Set the log level
|
// Set the log level
|
||||||
setLogLevel(a.logLevel)
|
logger.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 bridge mode
|
||||||
if BuildMode == cmd.BuildModeBridge {
|
if BuildMode == cmd.BuildModeBridge {
|
||||||
a.renderer = &Headless{}
|
a.renderer = &renderer.Bridge{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialise the renderer
|
// Initialise the renderer
|
||||||
@ -92,16 +98,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 = 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
|
||||||
}
|
}
|
||||||
@ -113,5 +119,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)
|
||||||
}
|
}
|
||||||
|
@ -1,97 +0,0 @@
|
|||||||
package wails
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/dchest/htmlmin"
|
|
||||||
"github.com/leaanthony/mewn"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AppConfig is the configuration structure used when creating a Wails App object
|
|
||||||
type AppConfig struct {
|
|
||||||
Width, Height int
|
|
||||||
Title string
|
|
||||||
defaultHTML string
|
|
||||||
HTML string
|
|
||||||
JS string
|
|
||||||
CSS string
|
|
||||||
Colour string
|
|
||||||
Resizable bool
|
|
||||||
DisableInspector bool
|
|
||||||
isHTMLFragment bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *AppConfig) merge(in *AppConfig) error {
|
|
||||||
if in.CSS != "" {
|
|
||||||
a.CSS = in.CSS
|
|
||||||
}
|
|
||||||
if 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 != "" {
|
|
||||||
a.Colour = in.Colour
|
|
||||||
}
|
|
||||||
|
|
||||||
if in.JS != "" {
|
|
||||||
a.JS = in.JS
|
|
||||||
}
|
|
||||||
|
|
||||||
if in.Width != 0 {
|
|
||||||
a.Width = in.Width
|
|
||||||
}
|
|
||||||
if in.Height != 0 {
|
|
||||||
a.Height = in.Height
|
|
||||||
}
|
|
||||||
a.Resizable = in.Resizable
|
|
||||||
a.DisableInspector = in.DisableInspector
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creates the default configuration
|
|
||||||
func newAppConfig(userConfig *AppConfig) (*AppConfig, error) {
|
|
||||||
result := &AppConfig{
|
|
||||||
Width: 800,
|
|
||||||
Height: 600,
|
|
||||||
Resizable: true,
|
|
||||||
Title: "My Wails App",
|
|
||||||
Colour: "#FFF", // White by default
|
|
||||||
HTML: mewn.String("./wailsruntimeassets/default/default.html"),
|
|
||||||
}
|
|
||||||
|
|
||||||
if userConfig != nil {
|
|
||||||
err := result.merge(userConfig)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result, nil
|
|
||||||
}
|
|
@ -11,10 +11,9 @@ func (app *App) setupCli() *cmd.Cli {
|
|||||||
result := cmd.NewCli(app.config.Title, "Debug build")
|
result := cmd.NewCli(app.config.Title, "Debug build")
|
||||||
result.Version(cmd.Version)
|
result.Version(cmd.Version)
|
||||||
|
|
||||||
// Setup cli to handle loglevel and headless flags
|
// Setup cli to handle loglevel
|
||||||
result.
|
result.
|
||||||
StringFlag("loglevel", "Sets the log level [debug|info|error|panic|fatal]. Default debug", &app.logLevel).
|
StringFlag("loglevel", "Sets the log level [debug|info|error|panic|fatal]. Default debug", &app.logLevel).
|
||||||
// BoolFlag("headless", "Runs the app in headless mode", &app.headless).
|
|
||||||
Action(app.start)
|
Action(app.start)
|
||||||
|
|
||||||
// Banner
|
// Banner
|
File diff suppressed because one or more lines are too long
@ -9,7 +9,7 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
mewn "github.com/leaanthony/mewn"
|
"github.com/leaanthony/mewn"
|
||||||
"github.com/leaanthony/slicer"
|
"github.com/leaanthony/slicer"
|
||||||
"github.com/leaanthony/spinner"
|
"github.com/leaanthony/spinner"
|
||||||
)
|
)
|
||||||
@ -249,8 +249,8 @@ func InstallFrontendDeps(projectDir string, projectOptions *ProjectOptions, forc
|
|||||||
ioutil.WriteFile(md5sumFile, []byte(packageJSONMD5), 0644)
|
ioutil.WriteFile(md5sumFile, []byte(packageJSONMD5), 0644)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Install the bridge library
|
// Install the runtime
|
||||||
err = InstallBridge(caller, projectDir, projectOptions)
|
err = InstallRuntime(caller, projectDir, projectOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -263,22 +263,29 @@ func InstallFrontendDeps(projectDir string, projectOptions *ProjectOptions, forc
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// InstallBridge installs the relevant bridge javascript library
|
// InstallRuntime installs the correct runtime for the type of build
|
||||||
func InstallBridge(caller string, projectDir string, projectOptions *ProjectOptions) error {
|
func InstallRuntime(caller string, projectDir string, projectOptions *ProjectOptions) error {
|
||||||
bridgeFile := "wailsbridge.prod.js"
|
if caller == "build" {
|
||||||
if caller == "serve" {
|
return InstallProdRuntime(projectDir, projectOptions)
|
||||||
bridgeFile = "wailsbridge.js"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy bridge to project
|
return InstallBridge(projectDir, projectOptions)
|
||||||
bridgeAssets := mewn.Group("../wailsruntimeassets/bridge/")
|
}
|
||||||
bridgeFileData := bridgeAssets.Bytes(bridgeFile)
|
|
||||||
bridgeFileTarget := filepath.Join(projectDir, projectOptions.FrontEnd.Dir, projectOptions.FrontEnd.Bridge, "wailsbridge.js")
|
// InstallBridge installs the relevant bridge javascript library
|
||||||
err := fs.CreateFile(bridgeFileTarget, bridgeFileData)
|
func InstallBridge(projectDir string, projectOptions *ProjectOptions) error {
|
||||||
if err != nil {
|
bridgeFileData := mewn.String("../runtime/assets/bridge.js")
|
||||||
return err
|
bridgeFileTarget := filepath.Join(projectDir, projectOptions.FrontEnd.Dir, "node_modules", "@wailsapp", "runtime", "main.js")
|
||||||
}
|
err := fs.CreateFile(bridgeFileTarget, []byte(bridgeFileData))
|
||||||
return nil
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstallProdRuntime installs the production runtime
|
||||||
|
func InstallProdRuntime(projectDir string, projectOptions *ProjectOptions) error {
|
||||||
|
prodInit := mewn.String("../runtime/js/runtime/init.js")
|
||||||
|
bridgeFileTarget := filepath.Join(projectDir, projectOptions.FrontEnd.Dir, "node_modules", "@wailsapp", "runtime", "main.js")
|
||||||
|
err := fs.CreateFile(bridgeFileTarget, []byte(prodInit))
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServeProject attempts to serve up the current project so that it may be connected to
|
// ServeProject attempts to serve up the current project so that it may be connected to
|
||||||
|
23
cmd/linux.go
23
cmd/linux.go
@ -25,6 +25,10 @@ const (
|
|||||||
RedHat
|
RedHat
|
||||||
// Debian distribution
|
// Debian distribution
|
||||||
Debian
|
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
|
||||||
@ -66,6 +70,12 @@ func GetLinuxDistroInfo() *DistroInfo {
|
|||||||
result.Distribution = Arch
|
result.Distribution = Arch
|
||||||
case "Debian":
|
case "Debian":
|
||||||
result.Distribution = Debian
|
result.Distribution = Debian
|
||||||
|
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
|
||||||
@ -113,6 +123,8 @@ func GetLinuxDistroInfo() *DistroInfo {
|
|||||||
result.Distribution = Arch
|
result.Distribution = Arch
|
||||||
case "Debian GNU/Linux":
|
case "Debian GNU/Linux":
|
||||||
result.Distribution = Debian
|
result.Distribution = Debian
|
||||||
|
case "Gentoo/Linux":
|
||||||
|
result.Distribution = Gentoo
|
||||||
default:
|
default:
|
||||||
result.Distribution = Unknown
|
result.Distribution = Unknown
|
||||||
result.DistributorID = osName
|
result.DistributorID = osName
|
||||||
@ -121,6 +133,17 @@ func GetLinuxDistroInfo() *DistroInfo {
|
|||||||
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()
|
||||||
|
@ -49,7 +49,7 @@ func getRequiredProgramsLinux() *Prerequisites {
|
|||||||
result := &Prerequisites{}
|
result := &Prerequisites{}
|
||||||
distroInfo := GetLinuxDistroInfo()
|
distroInfo := GetLinuxDistroInfo()
|
||||||
switch distroInfo.Distribution {
|
switch distroInfo.Distribution {
|
||||||
case Ubuntu, Debian:
|
case Ubuntu, Debian, Zorin:
|
||||||
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"))
|
||||||
@ -93,9 +93,12 @@ func getRequiredLibrariesLinux() (*Prerequisites, error) {
|
|||||||
result := &Prerequisites{}
|
result := &Prerequisites{}
|
||||||
distroInfo := GetLinuxDistroInfo()
|
distroInfo := GetLinuxDistroInfo()
|
||||||
switch distroInfo.Distribution {
|
switch distroInfo.Distribution {
|
||||||
case Ubuntu:
|
case Ubuntu, Debian, Zorin:
|
||||||
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"))
|
||||||
|
@ -117,14 +117,15 @@ func (p *ProgramHelper) RunCommandArray(args []string, dir ...string) error {
|
|||||||
}
|
}
|
||||||
args = args[1:]
|
args = args[1:]
|
||||||
var stderr string
|
var stderr string
|
||||||
// fmt.Printf("RunCommandArray = %s %+v\n", program, args)
|
var stdout string
|
||||||
if len(dir) > 0 {
|
if len(dir) > 0 {
|
||||||
_, stderr, err = p.shell.RunInDirectory(dir[0], program, args...)
|
stdout, stderr, err = p.shell.RunInDirectory(dir[0], program, args...)
|
||||||
} else {
|
} else {
|
||||||
_, stderr, err = p.shell.Run(program, args...)
|
stdout, stderr, err = p.shell.Run(program, args...)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(stderr)
|
fmt.Println(stderr)
|
||||||
|
fmt.Println(stdout)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/leaanthony/slicer"
|
"github.com/leaanthony/slicer"
|
||||||
@ -184,7 +185,13 @@ func (po *ProjectOptions) PromptForInputs() error {
|
|||||||
po.selectedTemplate = templateDetails[po.Template]
|
po.selectedTemplate = templateDetails[po.Template]
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
for _, templateDetail := range templateDetails {
|
keys := make([]string, 0)
|
||||||
|
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))
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/masterminds/semver"
|
"github.com/Masterminds/semver"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SemanticVersion is a struct containing a semantic version
|
// SemanticVersion is a struct containing a semantic version
|
||||||
|
@ -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, Debian:
|
case Ubuntu, Zorin, Debian:
|
||||||
installed, err := DpkgInstalled(library.Name)
|
installed, err := DpkgInstalled(library.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
@ -305,6 +305,17 @@ 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)
|
return false, RequestSupportForDistribution(distroInfo, library.Name)
|
||||||
}
|
}
|
||||||
|
13
cmd/templates/angular-template/frontend/.editorconfig
Normal file
13
cmd/templates/angular-template/frontend/.editorconfig
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# Editor configuration, see https://editorconfig.org
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
max_line_length = off
|
||||||
|
trim_trailing_whitespace = false
|
47
cmd/templates/angular-template/frontend/.gitignore
vendored
Normal file
47
cmd/templates/angular-template/frontend/.gitignore
vendored
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
# compiled output
|
||||||
|
/dist
|
||||||
|
/tmp
|
||||||
|
/out-tsc
|
||||||
|
# Only exists if Bazel was run
|
||||||
|
/bazel-out
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
|
||||||
|
# profiling files
|
||||||
|
chrome-profiler-events.json
|
||||||
|
speed-measure-plugin.json
|
||||||
|
|
||||||
|
# IDEs and editors
|
||||||
|
/.idea
|
||||||
|
.project
|
||||||
|
.classpath
|
||||||
|
.c9/
|
||||||
|
*.launch
|
||||||
|
.settings/
|
||||||
|
*.sublime-workspace
|
||||||
|
|
||||||
|
# IDE - VSCode
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.history/*
|
||||||
|
|
||||||
|
# misc
|
||||||
|
/.sass-cache
|
||||||
|
/connect.lock
|
||||||
|
/coverage
|
||||||
|
/libpeerconnection.log
|
||||||
|
npm-debug.log
|
||||||
|
yarn-error.log
|
||||||
|
testem.log
|
||||||
|
/typings
|
||||||
|
|
||||||
|
# System Files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
.editorcinfig
|
27
cmd/templates/angular-template/frontend/README.md
Normal file
27
cmd/templates/angular-template/frontend/README.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# MyApp
|
||||||
|
|
||||||
|
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.0.3.
|
||||||
|
|
||||||
|
## Development server
|
||||||
|
|
||||||
|
Run `npx ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
|
||||||
|
|
||||||
|
## Code scaffolding
|
||||||
|
|
||||||
|
Run `npx ng generate component component-name` to generate a new component. You can also use `npx ng generate directive|pipe|service|class|guard|interface|enum|module`.
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
Run `npx ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
|
||||||
|
|
||||||
|
## Running unit tests
|
||||||
|
|
||||||
|
Run `npx ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||||
|
|
||||||
|
## Running end-to-end tests
|
||||||
|
|
||||||
|
Run `npx ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
|
||||||
|
|
||||||
|
## Further help
|
||||||
|
|
||||||
|
To get more help on the Angular CLI use `npx ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
|
121
cmd/templates/angular-template/frontend/angular.json
Normal file
121
cmd/templates/angular-template/frontend/angular.json
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
{
|
||||||
|
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||||
|
"version": 1,
|
||||||
|
"newProjectRoot": "projects",
|
||||||
|
"projects": {
|
||||||
|
"my-app": {
|
||||||
|
"projectType": "application",
|
||||||
|
"schematics": {},
|
||||||
|
"root": "",
|
||||||
|
"sourceRoot": "src",
|
||||||
|
"prefix": "app",
|
||||||
|
"architect": {
|
||||||
|
"build": {
|
||||||
|
"builder": "ngx-build-plus:browser",
|
||||||
|
"options": {
|
||||||
|
"outputPath": "dist/my-app",
|
||||||
|
"index": "src/index.html",
|
||||||
|
"main": "src/main.ts",
|
||||||
|
"polyfills": "src/polyfills.ts",
|
||||||
|
"tsConfig": "tsconfig.app.json",
|
||||||
|
"aot": false,
|
||||||
|
"assets": [
|
||||||
|
"src/favicon.ico",
|
||||||
|
"src/assets"
|
||||||
|
],
|
||||||
|
"styles": [
|
||||||
|
"src/styles.css"
|
||||||
|
],
|
||||||
|
"scripts": []
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"fileReplacements": [
|
||||||
|
{
|
||||||
|
"replace": "src/environments/environment.ts",
|
||||||
|
"with": "src/environments/environment.prod.ts"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"optimization": true,
|
||||||
|
"outputHashing": "all",
|
||||||
|
"sourceMap": false,
|
||||||
|
"extractCss": true,
|
||||||
|
"namedChunks": false,
|
||||||
|
"aot": true,
|
||||||
|
"extractLicenses": true,
|
||||||
|
"vendorChunk": false,
|
||||||
|
"buildOptimizer": true,
|
||||||
|
"budgets": [
|
||||||
|
{
|
||||||
|
"type": "initial",
|
||||||
|
"maximumWarning": "2mb",
|
||||||
|
"maximumError": "5mb"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"serve": {
|
||||||
|
"builder": "ngx-build-plus:dev-server",
|
||||||
|
"options": {
|
||||||
|
"browserTarget": "my-app:build"
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"browserTarget": "my-app:build:production"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"extract-i18n": {
|
||||||
|
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||||
|
"options": {
|
||||||
|
"browserTarget": "my-app:build"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"builder": "ngx-build-plus:karma",
|
||||||
|
"options": {
|
||||||
|
"main": "src/test.ts",
|
||||||
|
"polyfills": "src/polyfills.ts",
|
||||||
|
"tsConfig": "tsconfig.spec.json",
|
||||||
|
"karmaConfig": "karma.conf.js",
|
||||||
|
"assets": [
|
||||||
|
"src/favicon.ico",
|
||||||
|
"src/assets"
|
||||||
|
],
|
||||||
|
"styles": [
|
||||||
|
"src/styles.css"
|
||||||
|
],
|
||||||
|
"scripts": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lint": {
|
||||||
|
"builder": "@angular-devkit/build-angular:tslint",
|
||||||
|
"options": {
|
||||||
|
"tsConfig": [
|
||||||
|
"tsconfig.app.json",
|
||||||
|
"tsconfig.spec.json",
|
||||||
|
"e2e/tsconfig.json"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"**/node_modules/**"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"e2e": {
|
||||||
|
"builder": "@angular-devkit/build-angular:protractor",
|
||||||
|
"options": {
|
||||||
|
"protractorConfig": "e2e/protractor.conf.js",
|
||||||
|
"devServerTarget": "my-app:serve"
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"devServerTarget": "my-app:serve:production"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"defaultProject": "my-app"
|
||||||
|
}
|
12
cmd/templates/angular-template/frontend/browserslist
Normal file
12
cmd/templates/angular-template/frontend/browserslist
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
|
||||||
|
# For additional information regarding the format and rule options, please see:
|
||||||
|
# https://github.com/browserslist/browserslist#queries
|
||||||
|
|
||||||
|
# You can see what browsers were selected by your queries by running:
|
||||||
|
# npx browserslist
|
||||||
|
|
||||||
|
> 0.5%
|
||||||
|
last 2 versions
|
||||||
|
Firefox ESR
|
||||||
|
not dead
|
||||||
|
not IE 9-11 # For IE 9-11 support, remove 'not'.
|
@ -0,0 +1,32 @@
|
|||||||
|
// @ts-check
|
||||||
|
// Protractor configuration file, see link for more information
|
||||||
|
// https://github.com/angular/protractor/blob/master/lib/config.ts
|
||||||
|
|
||||||
|
const { SpecReporter } = require('jasmine-spec-reporter');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type { import("protractor").Config }
|
||||||
|
*/
|
||||||
|
exports.config = {
|
||||||
|
allScriptsTimeout: 11000,
|
||||||
|
specs: [
|
||||||
|
'./src/**/*.e2e-spec.ts'
|
||||||
|
],
|
||||||
|
capabilities: {
|
||||||
|
'browserName': 'chrome'
|
||||||
|
},
|
||||||
|
directConnect: true,
|
||||||
|
baseUrl: 'http://localhost:4200/',
|
||||||
|
framework: 'jasmine',
|
||||||
|
jasmineNodeOpts: {
|
||||||
|
showColors: true,
|
||||||
|
defaultTimeoutInterval: 30000,
|
||||||
|
print: function() {}
|
||||||
|
},
|
||||||
|
onPrepare() {
|
||||||
|
require('ts-node').register({
|
||||||
|
project: require('path').join(__dirname, './tsconfig.json')
|
||||||
|
});
|
||||||
|
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,23 @@
|
|||||||
|
import { AppPage } from './app.po';
|
||||||
|
import { browser, logging } from 'protractor';
|
||||||
|
|
||||||
|
describe('workspace-project App', () => {
|
||||||
|
let page: AppPage;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
page = new AppPage();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display welcome message', () => {
|
||||||
|
page.navigateTo();
|
||||||
|
expect(page.getTitleText()).toEqual('Welcome to my-app!');
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
// Assert that there are no errors emitted from the browser
|
||||||
|
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
|
||||||
|
expect(logs).not.toContain(jasmine.objectContaining({
|
||||||
|
level: logging.Level.SEVERE,
|
||||||
|
} as logging.Entry));
|
||||||
|
});
|
||||||
|
});
|
11
cmd/templates/angular-template/frontend/e2e/src/app.po.ts
Normal file
11
cmd/templates/angular-template/frontend/e2e/src/app.po.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { browser, by, element } from 'protractor';
|
||||||
|
|
||||||
|
export class AppPage {
|
||||||
|
navigateTo() {
|
||||||
|
return browser.get(browser.baseUrl) as Promise<any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
getTitleText() {
|
||||||
|
return element(by.css('app-root h1')).getText() as Promise<string>;
|
||||||
|
}
|
||||||
|
}
|
13
cmd/templates/angular-template/frontend/e2e/tsconfig.json
Normal file
13
cmd/templates/angular-template/frontend/e2e/tsconfig.json
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"extends": "../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../out-tsc/e2e",
|
||||||
|
"module": "commonjs",
|
||||||
|
"target": "es5",
|
||||||
|
"types": [
|
||||||
|
"jasmine",
|
||||||
|
"jasminewd2",
|
||||||
|
"node"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
32
cmd/templates/angular-template/frontend/karma.conf.js
Normal file
32
cmd/templates/angular-template/frontend/karma.conf.js
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// Karma configuration file, see link for more information
|
||||||
|
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||||
|
|
||||||
|
module.exports = function (config) {
|
||||||
|
config.set({
|
||||||
|
basePath: '',
|
||||||
|
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||||
|
plugins: [
|
||||||
|
require('karma-jasmine'),
|
||||||
|
require('karma-chrome-launcher'),
|
||||||
|
require('karma-jasmine-html-reporter'),
|
||||||
|
require('karma-coverage-istanbul-reporter'),
|
||||||
|
require('@angular-devkit/build-angular/plugins/karma')
|
||||||
|
],
|
||||||
|
client: {
|
||||||
|
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||||
|
},
|
||||||
|
coverageIstanbulReporter: {
|
||||||
|
dir: require('path').join(__dirname, './coverage/my-app'),
|
||||||
|
reports: ['html', 'lcovonly', 'text-summary'],
|
||||||
|
fixWebpackSourcePaths: true
|
||||||
|
},
|
||||||
|
reporters: ['progress', 'kjhtml'],
|
||||||
|
port: 9876,
|
||||||
|
colors: true,
|
||||||
|
logLevel: config.LOG_INFO,
|
||||||
|
autoWatch: true,
|
||||||
|
browsers: ['Chrome'],
|
||||||
|
singleRun: false,
|
||||||
|
restartOnFileChange: true
|
||||||
|
});
|
||||||
|
};
|
@ -0,0 +1,51 @@
|
|||||||
|
{
|
||||||
|
"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",
|
||||||
|
"@wailsapp/runtime": "^1.0.0",
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { Routes, RouterModule } from '@angular/router';
|
||||||
|
|
||||||
|
const routes: Routes = [];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [
|
||||||
|
RouterModule.forRoot(routes)
|
||||||
|
],
|
||||||
|
exports: [RouterModule]
|
||||||
|
})
|
||||||
|
|
||||||
|
export class AppRoutingModule { }
|
@ -0,0 +1,14 @@
|
|||||||
|
<!--The content below is only a placeholder and can be replaced.-->
|
||||||
|
<div style="text-align:center">
|
||||||
|
<h1>
|
||||||
|
Welcome to {{ title }}!
|
||||||
|
</h1>
|
||||||
|
<img width="300" alt="Angular Logo"
|
||||||
|
src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg==">
|
||||||
|
|
||||||
|
<br />
|
||||||
|
<button (click)="onClickMe()">Hello</button>
|
||||||
|
<p>{{clickMessage}}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<router-outlet></router-outlet>
|
@ -0,0 +1,35 @@
|
|||||||
|
import { TestBed, async } from '@angular/core/testing';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { AppComponent } from './app.component';
|
||||||
|
|
||||||
|
describe('AppComponent', () => {
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [
|
||||||
|
RouterTestingModule
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
AppComponent
|
||||||
|
],
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should create the app', () => {
|
||||||
|
const fixture = TestBed.createComponent(AppComponent);
|
||||||
|
const app = fixture.debugElement.componentInstance;
|
||||||
|
expect(app).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should have as title 'my-app'`, () => {
|
||||||
|
const fixture = TestBed.createComponent(AppComponent);
|
||||||
|
const app = fixture.debugElement.componentInstance;
|
||||||
|
expect(app.title).toEqual('my-app');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render title in a h1 tag', () => {
|
||||||
|
const fixture = TestBed.createComponent(AppComponent);
|
||||||
|
fixture.detectChanges();
|
||||||
|
const compiled = fixture.debugElement.nativeElement;
|
||||||
|
expect(compiled.querySelector('h1').textContent).toContain('Welcome to my-app!');
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,19 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: '[id="app"]',
|
||||||
|
templateUrl: './app.component.html',
|
||||||
|
styleUrls: ['./app.component.css']
|
||||||
|
})
|
||||||
|
export class AppComponent {
|
||||||
|
title = 'my-app';
|
||||||
|
|
||||||
|
clickMessage = '';
|
||||||
|
|
||||||
|
onClickMe() {
|
||||||
|
// @ts-ignore
|
||||||
|
window.backend.basic().then(result =>
|
||||||
|
this.clickMessage = result
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
|
||||||
|
import { AppRoutingModule } from './app-routing.module';
|
||||||
|
import { AppComponent } from './app.component';
|
||||||
|
|
||||||
|
import { APP_BASE_HREF } from '@angular/common';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
AppComponent
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
BrowserModule,
|
||||||
|
AppRoutingModule
|
||||||
|
],
|
||||||
|
providers: [{provide: APP_BASE_HREF, useValue : '/' }],
|
||||||
|
bootstrap: [AppComponent]
|
||||||
|
})
|
||||||
|
export class AppModule { }
|
@ -0,0 +1,3 @@
|
|||||||
|
export const environment = {
|
||||||
|
production: true
|
||||||
|
};
|
@ -0,0 +1,16 @@
|
|||||||
|
// This file can be replaced during build by using the `fileReplacements` array.
|
||||||
|
// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
|
||||||
|
// The list of file replacements can be found in `angular.json`.
|
||||||
|
|
||||||
|
export const environment = {
|
||||||
|
production: false
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For easier debugging in development mode, you can import the following file
|
||||||
|
* to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
|
||||||
|
*
|
||||||
|
* This import should be commented out in production mode because it will have a negative impact
|
||||||
|
* on performance if an error is thrown.
|
||||||
|
*/
|
||||||
|
// import 'zone.js/dist/zone-error'; // Included with Angular CLI.
|
BIN
cmd/templates/angular-template/frontend/src/favicon.ico
Normal file
BIN
cmd/templates/angular-template/frontend/src/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.3 KiB |
@ -0,0 +1,14 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>my-app</title>
|
||||||
|
<base href="/">
|
||||||
|
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
18
cmd/templates/angular-template/frontend/src/main.ts
Normal file
18
cmd/templates/angular-template/frontend/src/main.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { enableProdMode } from '@angular/core';
|
||||||
|
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||||
|
|
||||||
|
import { AppModule } from './app/app.module';
|
||||||
|
import { environment } from './environments/environment';
|
||||||
|
|
||||||
|
import 'zone.js'
|
||||||
|
|
||||||
|
import Wails from '@wailsapp/runtime';
|
||||||
|
|
||||||
|
if (environment.production) {
|
||||||
|
enableProdMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
Wails.Init(() => {
|
||||||
|
platformBrowserDynamic().bootstrapModule(AppModule)
|
||||||
|
.catch(err => console.error(err));
|
||||||
|
});
|
63
cmd/templates/angular-template/frontend/src/polyfills.ts
Normal file
63
cmd/templates/angular-template/frontend/src/polyfills.ts
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/**
|
||||||
|
* This file includes polyfills needed by Angular and is loaded before the app.
|
||||||
|
* You can add your own extra polyfills to this file.
|
||||||
|
*
|
||||||
|
* This file is divided into 2 sections:
|
||||||
|
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
|
||||||
|
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
|
||||||
|
* file.
|
||||||
|
*
|
||||||
|
* The current setup is for so-called "evergreen" browsers; the last versions of browsers that
|
||||||
|
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
|
||||||
|
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
|
||||||
|
*
|
||||||
|
* Learn more in https://angular.io/guide/browser-support
|
||||||
|
*/
|
||||||
|
|
||||||
|
/***************************************************************************************************
|
||||||
|
* BROWSER POLYFILLS
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
|
||||||
|
// import 'classlist.js'; // Run `npm install --save classlist.js`.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Web Animations `@angular/platform-browser/animations`
|
||||||
|
* Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
|
||||||
|
* Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
|
||||||
|
*/
|
||||||
|
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* By default, zone.js will patch all possible macroTask and DomEvents
|
||||||
|
* user can disable parts of macroTask/DomEvents patch by setting following flags
|
||||||
|
* because those flags need to be set before `zone.js` being loaded, and webpack
|
||||||
|
* will put import in the top of bundle, so user need to create a separate file
|
||||||
|
* in this directory (for example: zone-flags.ts), and put the following flags
|
||||||
|
* into that file, and then add the following code before importing zone.js.
|
||||||
|
* import './zone-flags.ts';
|
||||||
|
*
|
||||||
|
* The flags allowed in zone-flags.ts are listed here.
|
||||||
|
*
|
||||||
|
* The following flags will work for all browsers.
|
||||||
|
*
|
||||||
|
* (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
|
||||||
|
* (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
|
||||||
|
* (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
|
||||||
|
*
|
||||||
|
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
|
||||||
|
* with the following flag, it will bypass `zone.js` patch for IE/Edge
|
||||||
|
*
|
||||||
|
* (window as any).__Zone_enable_cross_context_check = true;
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/***************************************************************************************************
|
||||||
|
* Zone JS is required by default for Angular itself.
|
||||||
|
*/
|
||||||
|
//import 'zone.js/dist/zone'; // Included with Angular CLI.
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************************************
|
||||||
|
* APPLICATION IMPORTS
|
||||||
|
*/
|
24
cmd/templates/angular-template/frontend/src/styles.css
Normal file
24
cmd/templates/angular-template/frontend/src/styles.css
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/* You can add global styles to this file, and also import other style files */
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
|
||||||
|
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
|
||||||
|
sans-serif;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
|
||||||
|
background-color: #282c34;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
color: white
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
color: white
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
background-color: white;
|
||||||
|
color: black;
|
||||||
|
}
|
20
cmd/templates/angular-template/frontend/src/test.ts
Normal file
20
cmd/templates/angular-template/frontend/src/test.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||||
|
|
||||||
|
import 'zone.js/dist/zone-testing';
|
||||||
|
import { getTestBed } from '@angular/core/testing';
|
||||||
|
import {
|
||||||
|
BrowserDynamicTestingModule,
|
||||||
|
platformBrowserDynamicTesting
|
||||||
|
} from '@angular/platform-browser-dynamic/testing';
|
||||||
|
|
||||||
|
declare const require: any;
|
||||||
|
|
||||||
|
// First, initialize the Angular testing environment.
|
||||||
|
getTestBed().initTestEnvironment(
|
||||||
|
BrowserDynamicTestingModule,
|
||||||
|
platformBrowserDynamicTesting()
|
||||||
|
);
|
||||||
|
// Then we find all the tests.
|
||||||
|
const context = require.context('./', true, /\.spec\.ts$/);
|
||||||
|
// And load the modules.
|
||||||
|
context.keys().map(context);
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
14
cmd/templates/angular-template/frontend/tsconfig.app.json
Normal file
14
cmd/templates/angular-template/frontend/tsconfig.app.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./out-tsc/app",
|
||||||
|
"types": []
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src/**/*.ts"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"src/test.ts",
|
||||||
|
"src/**/*.spec.ts"
|
||||||
|
]
|
||||||
|
}
|
23
cmd/templates/angular-template/frontend/tsconfig.json
Normal file
23
cmd/templates/angular-template/frontend/tsconfig.json
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"compileOnSave": false,
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": "./",
|
||||||
|
"outDir": "./dist/out-tsc",
|
||||||
|
"sourceMap": true,
|
||||||
|
"declaration": false,
|
||||||
|
"downlevelIteration": true,
|
||||||
|
"emitDecoratorMetadata": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"importHelpers": true,
|
||||||
|
"target": "es2015",
|
||||||
|
"typeRoots": [
|
||||||
|
"node_modules/@types"
|
||||||
|
],
|
||||||
|
"lib": [
|
||||||
|
"es2018",
|
||||||
|
"dom"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
18
cmd/templates/angular-template/frontend/tsconfig.spec.json
Normal file
18
cmd/templates/angular-template/frontend/tsconfig.spec.json
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./out-tsc/spec",
|
||||||
|
"types": [
|
||||||
|
"jasmine",
|
||||||
|
"node"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"src/test.ts",
|
||||||
|
"src/polyfills.ts"
|
||||||
|
],
|
||||||
|
"include": [
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.d.ts"
|
||||||
|
]
|
||||||
|
}
|
92
cmd/templates/angular-template/frontend/tslint.json
Normal file
92
cmd/templates/angular-template/frontend/tslint.json
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
{
|
||||||
|
"extends": "tslint:recommended",
|
||||||
|
"rules": {
|
||||||
|
"array-type": false,
|
||||||
|
"arrow-parens": false,
|
||||||
|
"deprecation": {
|
||||||
|
"severity": "warn"
|
||||||
|
},
|
||||||
|
"component-class-suffix": true,
|
||||||
|
"contextual-lifecycle": true,
|
||||||
|
"directive-class-suffix": true,
|
||||||
|
"directive-selector": [
|
||||||
|
true,
|
||||||
|
"attribute",
|
||||||
|
"app",
|
||||||
|
"camelCase"
|
||||||
|
],
|
||||||
|
"component-selector": [
|
||||||
|
true,
|
||||||
|
"element",
|
||||||
|
"app",
|
||||||
|
"kebab-case"
|
||||||
|
],
|
||||||
|
"import-blacklist": [
|
||||||
|
true,
|
||||||
|
"rxjs/Rx"
|
||||||
|
],
|
||||||
|
"interface-name": false,
|
||||||
|
"max-classes-per-file": false,
|
||||||
|
"max-line-length": [
|
||||||
|
true,
|
||||||
|
140
|
||||||
|
],
|
||||||
|
"member-access": false,
|
||||||
|
"member-ordering": [
|
||||||
|
true,
|
||||||
|
{
|
||||||
|
"order": [
|
||||||
|
"static-field",
|
||||||
|
"instance-field",
|
||||||
|
"static-method",
|
||||||
|
"instance-method"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"no-consecutive-blank-lines": false,
|
||||||
|
"no-console": [
|
||||||
|
true,
|
||||||
|
"debug",
|
||||||
|
"info",
|
||||||
|
"time",
|
||||||
|
"timeEnd",
|
||||||
|
"trace"
|
||||||
|
],
|
||||||
|
"no-empty": false,
|
||||||
|
"no-inferrable-types": [
|
||||||
|
true,
|
||||||
|
"ignore-params"
|
||||||
|
],
|
||||||
|
"no-non-null-assertion": true,
|
||||||
|
"no-redundant-jsdoc": true,
|
||||||
|
"no-switch-case-fall-through": true,
|
||||||
|
"no-use-before-declare": true,
|
||||||
|
"no-var-requires": false,
|
||||||
|
"object-literal-key-quotes": [
|
||||||
|
true,
|
||||||
|
"as-needed"
|
||||||
|
],
|
||||||
|
"object-literal-sort-keys": false,
|
||||||
|
"ordered-imports": false,
|
||||||
|
"quotemark": [
|
||||||
|
true,
|
||||||
|
"single"
|
||||||
|
],
|
||||||
|
"trailing-comma": false,
|
||||||
|
"no-conflicting-lifecycle": true,
|
||||||
|
"no-host-metadata-property": true,
|
||||||
|
"no-input-rename": true,
|
||||||
|
"no-inputs-metadata-property": true,
|
||||||
|
"no-output-native": true,
|
||||||
|
"no-output-on-prefix": true,
|
||||||
|
"no-output-rename": true,
|
||||||
|
"no-outputs-metadata-property": true,
|
||||||
|
"template-banana-in-box": true,
|
||||||
|
"template-no-negated-async": true,
|
||||||
|
"use-lifecycle-interface": true,
|
||||||
|
"use-pipe-transform-interface": true
|
||||||
|
},
|
||||||
|
"rulesDirectory": [
|
||||||
|
"codelyzer"
|
||||||
|
]
|
||||||
|
}
|
5
cmd/templates/angular-template/go.mod.template
Normal file
5
cmd/templates/angular-template/go.mod.template
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
module {{.BinaryName}}
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/wailsapp/wails {{.WailsVersion}}
|
||||||
|
)
|
27
cmd/templates/angular-template/main.go.template
Normal file
27
cmd/templates/angular-template/main.go.template
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/leaanthony/mewn"
|
||||||
|
"github.com/wailsapp/wails"
|
||||||
|
)
|
||||||
|
|
||||||
|
func basic() string {
|
||||||
|
return "World!"
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
js := mewn.String("./frontend/dist/my-app/main-es2015.js")
|
||||||
|
css := mewn.String("./frontend/dist/my-app/styles.css")
|
||||||
|
|
||||||
|
app := wails.CreateApp(&wails.AppConfig{
|
||||||
|
Width: 1024,
|
||||||
|
Height: 768,
|
||||||
|
Title: "{{.Name}}",
|
||||||
|
JS: js,
|
||||||
|
CSS: css,
|
||||||
|
Colour: "#131313",
|
||||||
|
})
|
||||||
|
app.Bind(basic)
|
||||||
|
app.Run()
|
||||||
|
}
|
20
cmd/templates/angular-template/template.json
Normal file
20
cmd/templates/angular-template/template.json
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"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": ""
|
||||||
|
}
|
@ -4,10 +4,12 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"core-js": "^3.1.4",
|
||||||
"react": "^16.8.6",
|
"react": "^16.8.6",
|
||||||
"react-dom": "^16.8.6",
|
"react-dom": "^16.8.6",
|
||||||
"wails-react-scripts": "3.0.1-2",
|
"wails-react-scripts": "3.0.1-2",
|
||||||
"react-modal": "3.8.1"
|
"react-modal": "3.8.1",
|
||||||
|
"@wailsapp/runtime": "^1.0.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "react-scripts start",
|
"start": "react-scripts start",
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
|
import 'core-js/stable';
|
||||||
import './index.css';
|
import './index.css';
|
||||||
import App from './App';
|
import App from './App';
|
||||||
|
|
||||||
import Bridge from "./wailsbridge";
|
import Wails from '@wailsapp/runtime';
|
||||||
|
|
||||||
Bridge.Start(() => {
|
Wails.Init(() => {
|
||||||
ReactDOM.render(<App />, document.getElementById('app'));
|
ReactDOM.render(<App />, document.getElementById('app'));
|
||||||
});
|
});
|
||||||
|
@ -9,7 +9,8 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"core-js": "^2.6.4",
|
"core-js": "^2.6.4",
|
||||||
"vue": "^2.5.22"
|
"vue": "^2.5.22",
|
||||||
|
"@wailsapp/runtime": "^1.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vue/cli-plugin-babel": "^3.4.0",
|
"@vue/cli-plugin-babel": "^3.4.0",
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import Vue from "vue";
|
import Vue from 'vue';
|
||||||
import App from "./App.vue";
|
import App from './App.vue';
|
||||||
|
|
||||||
Vue.config.productionTip = false;
|
Vue.config.productionTip = false;
|
||||||
Vue.config.devtools = true;
|
Vue.config.devtools = true;
|
||||||
|
|
||||||
import Bridge from "./wailsbridge";
|
import Wails from '@wailsapp/runtime';
|
||||||
|
|
||||||
Bridge.Start(() => {
|
Wails.Init(() => {
|
||||||
new Vue({
|
new Vue({
|
||||||
render: h => h(App)
|
render: h => h(App)
|
||||||
}).$mount("#app");
|
}).$mount('#app');
|
||||||
});
|
});
|
||||||
|
@ -12,7 +12,8 @@
|
|||||||
"core-js": "^2.6.4",
|
"core-js": "^2.6.4",
|
||||||
"material-design-icons-iconfont": "^5.0.1",
|
"material-design-icons-iconfont": "^5.0.1",
|
||||||
"vue": "^2.5.22",
|
"vue": "^2.5.22",
|
||||||
"vuetify": "^1.5.14"
|
"vuetify": "^1.5.14",
|
||||||
|
"@wailsapp/runtime": "^1.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vue/cli-plugin-babel": "^3.4.0",
|
"@vue/cli-plugin-babel": "^3.4.0",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import 'babel-polyfill';
|
import 'babel-polyfill';
|
||||||
import Vue from "vue";
|
import Vue from 'vue';
|
||||||
|
|
||||||
// Setup Vuetify
|
// Setup Vuetify
|
||||||
import Vuetify from 'vuetify';
|
import Vuetify from 'vuetify';
|
||||||
@ -7,15 +7,15 @@ Vue.use(Vuetify);
|
|||||||
import 'vuetify/dist/vuetify.min.css';
|
import 'vuetify/dist/vuetify.min.css';
|
||||||
import 'material-design-icons-iconfont';
|
import 'material-design-icons-iconfont';
|
||||||
|
|
||||||
import App from "./App.vue";
|
import App from './App.vue';
|
||||||
|
|
||||||
Vue.config.productionTip = false;
|
Vue.config.productionTip = false;
|
||||||
Vue.config.devtools = true;
|
Vue.config.devtools = true;
|
||||||
|
|
||||||
import Bridge from "./wailsbridge";
|
import Wails from '@wailsapp/runtime';
|
||||||
|
|
||||||
Bridge.Start(() => {
|
Wails.Init(() => {
|
||||||
new Vue({
|
new Vue({
|
||||||
render: h => h(App)
|
render: h => h(App)
|
||||||
}).$mount("#app");
|
}).$mount('#app');
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
// Version - Wails version
|
// Version - Wails version
|
||||||
const Version = "v0.16.4-pre"
|
const Version = "v0.17.6-pre"
|
||||||
|
@ -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.Debian:
|
case cmd.Ubuntu, cmd.Zorin, cmd.Debian:
|
||||||
installed, err := cmd.DpkgInstalled(library.Name)
|
installed, err := cmd.DpkgInstalled(library.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
|
@ -72,8 +72,17 @@ func init() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure that runtime init.js is the production version
|
||||||
|
err = cmd.InstallProdRuntime(projectDir, projectOptions)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Move to project directory
|
// Move to project directory
|
||||||
err = os.Chdir(projectDir)
|
err = os.Chdir(projectDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -45,7 +45,7 @@ func init() {
|
|||||||
projectDir := fs.Cwd()
|
projectDir := fs.Cwd()
|
||||||
|
|
||||||
// Install the bridge library
|
// Install the bridge library
|
||||||
err = cmd.InstallBridge("serve", projectDir, projectOptions)
|
err = cmd.InstallBridge(projectDir, projectOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
110
config.go
Normal file
110
config.go
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
package wails
|
||||||
|
|
||||||
|
import "github.com/leaanthony/mewn"
|
||||||
|
|
||||||
|
// AppConfig is the configuration structure used when creating a Wails App object
|
||||||
|
type AppConfig struct {
|
||||||
|
Width, Height int
|
||||||
|
Title string
|
||||||
|
defaultHTML string
|
||||||
|
HTML string
|
||||||
|
JS string
|
||||||
|
CSS string
|
||||||
|
Colour string
|
||||||
|
Resizable bool
|
||||||
|
DisableInspector 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 default HTML
|
||||||
|
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 {
|
||||||
|
if in.CSS != "" {
|
||||||
|
a.CSS = in.CSS
|
||||||
|
}
|
||||||
|
if in.Title != "" {
|
||||||
|
a.Title = in.Title
|
||||||
|
}
|
||||||
|
|
||||||
|
if in.Colour != "" {
|
||||||
|
a.Colour = in.Colour
|
||||||
|
}
|
||||||
|
|
||||||
|
if in.JS != "" {
|
||||||
|
a.JS = in.JS
|
||||||
|
}
|
||||||
|
|
||||||
|
if in.Width != 0 {
|
||||||
|
a.Width = in.Width
|
||||||
|
}
|
||||||
|
if in.Height != 0 {
|
||||||
|
a.Height = in.Height
|
||||||
|
}
|
||||||
|
a.Resizable = in.Resizable
|
||||||
|
a.DisableInspector = in.DisableInspector
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates the default configuration
|
||||||
|
func newConfig(userConfig *AppConfig) (*AppConfig, error) {
|
||||||
|
result := &AppConfig{
|
||||||
|
Width: 800,
|
||||||
|
Height: 600,
|
||||||
|
Resizable: true,
|
||||||
|
Title: "My Wails App",
|
||||||
|
Colour: "#FFF", // White by default
|
||||||
|
HTML: mewn.String("./runtime/assets/default.html"),
|
||||||
|
}
|
||||||
|
|
||||||
|
if userConfig != nil {
|
||||||
|
err := result.merge(userConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
5
go.mod
5
go.mod
@ -1,7 +1,7 @@
|
|||||||
module github.com/wailsapp/wails
|
module github.com/wailsapp/wails
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Masterminds/semver v1.4.2 // indirect
|
github.com/Masterminds/semver v1.4.2
|
||||||
github.com/dchest/cssmin v0.0.0-20151210170030-fb8d9b44afdc // indirect
|
github.com/dchest/cssmin v0.0.0-20151210170030-fb8d9b44afdc // indirect
|
||||||
github.com/dchest/htmlmin v0.0.0-20150526090704-e254725e81ac
|
github.com/dchest/htmlmin v0.0.0-20150526090704-e254725e81ac
|
||||||
github.com/dchest/jsmin v0.0.0-20160823214000-faeced883947 // indirect
|
github.com/dchest/jsmin v0.0.0-20160823214000-faeced883947 // indirect
|
||||||
@ -12,9 +12,8 @@ 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.1
|
github.com/leaanthony/slicer v1.3.2
|
||||||
github.com/leaanthony/spinner v0.5.3
|
github.com/leaanthony/spinner v0.5.3
|
||||||
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
|
||||||
github.com/mattn/go-isatty v0.0.7 // indirect
|
github.com/mattn/go-isatty v0.0.7 // indirect
|
||||||
github.com/mitchellh/go-homedir v1.1.0
|
github.com/mitchellh/go-homedir v1.1.0
|
||||||
|
14
go.sum
14
go.sum
@ -25,7 +25,6 @@ github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNU
|
|||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||||
github.com/kennygrant/sanitize v1.2.4 h1:gN25/otpP5vAsO2djbMhF/LQX6R7+O1TB4yv8NzpJ3o=
|
github.com/kennygrant/sanitize v1.2.4 h1:gN25/otpP5vAsO2djbMhF/LQX6R7+O1TB4yv8NzpJ3o=
|
||||||
github.com/kennygrant/sanitize v1.2.4/go.mod h1:LGsjYYtgxbetdg5owWB2mpgUL6e2nfw2eObZ0u0qvak=
|
github.com/kennygrant/sanitize v1.2.4/go.mod h1:LGsjYYtgxbetdg5owWB2mpgUL6e2nfw2eObZ0u0qvak=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
@ -33,22 +32,18 @@ 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.1 h1:n2iIV2sxvL/3bpnmVY0vBjXf3yYFWcB6CYLVMrzJxRw=
|
github.com/leaanthony/slicer v1.3.2 h1:kGWWFoyaY5WzwGrUsHXMmGbssuYthP4qYBNlkNpNAB8=
|
||||||
github.com/leaanthony/slicer v1.3.1/go.mod h1:VMB/HGvr3uR3MRpFWHWAm0w+DHQLzPHYe2pKfpFlQIQ=
|
github.com/leaanthony/slicer v1.3.2/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=
|
||||||
github.com/leaanthony/synx v0.1.0/go.mod h1:Iz7eybeeG8bdq640iR+CwYb8p+9EOsgMWghkSRyZcqs=
|
github.com/leaanthony/synx v0.1.0/go.mod h1:Iz7eybeeG8bdq640iR+CwYb8p+9EOsgMWghkSRyZcqs=
|
||||||
github.com/leaanthony/wincursor v0.1.0 h1:Dsyp68QcF5cCs65AMBmxoYNEm0n8K7mMchG6a8fYxf8=
|
github.com/leaanthony/wincursor v0.1.0 h1:Dsyp68QcF5cCs65AMBmxoYNEm0n8K7mMchG6a8fYxf8=
|
||||||
github.com/leaanthony/wincursor v0.1.0/go.mod h1:7TVwwrzSH/2Y9gLOGH+VhA+bZhoWXBRgbGNTMk+yimE=
|
github.com/leaanthony/wincursor v0.1.0/go.mod h1:7TVwwrzSH/2Y9gLOGH+VhA+bZhoWXBRgbGNTMk+yimE=
|
||||||
github.com/masterminds/semver v1.4.2 h1:BgrAYDjlAebjtOwS7C/1QZoh5WgyXx4b59ydc+Ph8xI=
|
|
||||||
github.com/masterminds/semver v1.4.2/go.mod h1:s7KNT9fnd7edGzwwP7RBX4H0v/CYd5qdOLfkL1V75yg=
|
|
||||||
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
|
|
||||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||||
github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg=
|
github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg=
|
||||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
|
|
||||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc=
|
github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc=
|
||||||
@ -73,11 +68,8 @@ github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
|
|||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/wailsapp/webview v0.2.7 h1:fN5L5H9Oivg9IJPk7uaXQnjqB68Fny11ZWkIaTIZHmk=
|
|
||||||
github.com/wailsapp/webview v0.2.7/go.mod h1:XO9HJbKWokDxUYTWQEBCYg95n/To1v7PxvanDNVf8hY=
|
|
||||||
github.com/zserge/webview v0.0.0-20190123072648-16c93bcaeaeb/go.mod h1:a1CV8KR4Dd1eP2g+mEijGOp+HKczwdKHWyx0aPHKvo4=
|
github.com/zserge/webview v0.0.0-20190123072648-16c93bcaeaeb/go.mod h1:a1CV8KR4Dd1eP2g+mEijGOp+HKczwdKHWyx0aPHKvo4=
|
||||||
golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
|
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 h1:iMGN4xG0cnqj3t+zOM8wUB0BiPKHEwSxEZCvzcbZuvk=
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 h1:iMGN4xG0cnqj3t+zOM8wUB0BiPKHEwSxEZCvzcbZuvk=
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
@ -86,10 +78,8 @@ golang.org/x/net v0.0.0-20190509222800-a4d6f7feada5 h1:6M3SDHlHHDCx2PcQw3S4KsR17
|
|||||||
golang.org/x/net v0.0.0-20190509222800-a4d6f7feada5/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190509222800-a4d6f7feada5/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/sys v0.0.0-20180606202747-9527bec2660b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180606202747-9527bec2660b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb h1:pf3XwC90UUdNPYWZdFjhGBE7DUFuK3Ct1zWmZ65QN30=
|
|
||||||
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
|
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190509141414-a5b02f93d862 h1:rM0ROo5vb9AdYJi1110yjWGMej9ITfKddS89P3Fkhug=
|
golang.org/x/sys v0.0.0-20190509141414-a5b02f93d862 h1:rM0ROo5vb9AdYJi1110yjWGMej9ITfKddS89P3Fkhug=
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package wails
|
package binding
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@ -6,6 +6,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/lib/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
type boundFunction struct {
|
type boundFunction struct {
|
||||||
@ -14,7 +16,7 @@ type boundFunction struct {
|
|||||||
functionType reflect.Type
|
functionType reflect.Type
|
||||||
inputs []reflect.Type
|
inputs []reflect.Type
|
||||||
returnTypes []reflect.Type
|
returnTypes []reflect.Type
|
||||||
log *CustomLogger
|
log *logger.CustomLogger
|
||||||
hasErrorReturnType bool
|
hasErrorReturnType bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,7 +32,7 @@ func newBoundFunction(object interface{}) (*boundFunction, error) {
|
|||||||
fullName: name,
|
fullName: name,
|
||||||
function: objectValue,
|
function: objectValue,
|
||||||
functionType: objectType,
|
functionType: objectType,
|
||||||
log: newCustomLogger(name),
|
log: logger.NewCustomLogger(name),
|
||||||
}
|
}
|
||||||
|
|
||||||
err := result.processParameters()
|
err := result.processParameters()
|
||||||
@ -55,7 +57,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", Fields{
|
b.log.DebugFields("Input param", logger.Fields{
|
||||||
"index": index,
|
"index": index,
|
||||||
"name": name,
|
"name": name,
|
||||||
"kind": kind,
|
"kind": kind,
|
@ -1,27 +1,33 @@
|
|||||||
package wails
|
package binding
|
||||||
|
|
||||||
import "strings"
|
import (
|
||||||
import "fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
type internalMethods struct{
|
"github.com/wailsapp/wails/lib/logger"
|
||||||
log *CustomLogger
|
"github.com/wailsapp/wails/lib/messages"
|
||||||
browser *RuntimeBrowser
|
"github.com/wailsapp/wails/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
type internalMethods struct {
|
||||||
|
log *logger.CustomLogger
|
||||||
|
browser *runtime.Browser
|
||||||
}
|
}
|
||||||
|
|
||||||
func newInternalMethods() *internalMethods {
|
func newInternalMethods() *internalMethods {
|
||||||
return &internalMethods{
|
return &internalMethods{
|
||||||
log: newCustomLogger("InternalCall"),
|
log: logger.NewCustomLogger("InternalCall"),
|
||||||
browser: newRuntimeBrowser(),
|
browser: runtime.NewBrowser(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *internalMethods) processCall(callData *callData) (interface{}, error) {
|
func (i *internalMethods) processCall(callData *messages.CallData) (interface{}, error) {
|
||||||
if !strings.HasPrefix(callData.BindingName, ".wails.") {
|
if !strings.HasPrefix(callData.BindingName, ".wails.") {
|
||||||
return nil, fmt.Errorf("Invalid call signature '%s'", callData.BindingName)
|
return nil, fmt.Errorf("Invalid call signature '%s'", callData.BindingName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Strip prefix
|
// Strip prefix
|
||||||
var splitCall = strings.Split(callData.BindingName,".")[2:]
|
var splitCall = strings.Split(callData.BindingName, ".")[2:]
|
||||||
if len(splitCall) != 2 {
|
if len(splitCall) != 2 {
|
||||||
return nil, fmt.Errorf("Invalid call signature '%s'", callData.BindingName)
|
return nil, fmt.Errorf("Invalid call signature '%s'", callData.BindingName)
|
||||||
}
|
}
|
||||||
@ -37,14 +43,14 @@ func (i *internalMethods) processCall(callData *callData) (interface{}, error) {
|
|||||||
|
|
||||||
func (i *internalMethods) processBrowserCommand(command string, data interface{}) (interface{}, error) {
|
func (i *internalMethods) processBrowserCommand(command string, data interface{}) (interface{}, error) {
|
||||||
switch command {
|
switch command {
|
||||||
case "OpenURL":
|
case "OpenURL":
|
||||||
url := data.(string)
|
url := data.(string)
|
||||||
// Strip string quotes. Credit: https://stackoverflow.com/a/44222648
|
// Strip string quotes. Credit: https://stackoverflow.com/a/44222648
|
||||||
if url[0] == '"' {
|
if url[0] == '"' {
|
||||||
url = url[1:]
|
url = url[1:]
|
||||||
}
|
}
|
||||||
if i := len(url)-1; url[i] == '"' {
|
if i := len(url) - 1; url[i] == '"' {
|
||||||
url = url[:i]
|
url = url[:i]
|
||||||
}
|
}
|
||||||
i.log.Debugf("Calling Browser.OpenURL with '%s'", url)
|
i.log.Debugf("Calling Browser.OpenURL with '%s'", url)
|
||||||
return nil, i.browser.OpenURL(url)
|
return nil, i.browser.OpenURL(url)
|
||||||
@ -54,12 +60,12 @@ func (i *internalMethods) processBrowserCommand(command string, data interface{}
|
|||||||
if filename[0] == '"' {
|
if filename[0] == '"' {
|
||||||
filename = filename[1:]
|
filename = filename[1:]
|
||||||
}
|
}
|
||||||
if i := len(filename)-1; filename[i] == '"' {
|
if i := len(filename) - 1; filename[i] == '"' {
|
||||||
filename = filename[:i]
|
filename = filename[:i]
|
||||||
}
|
}
|
||||||
i.log.Debugf("Calling Browser.OpenFile with '%s'", filename)
|
i.log.Debugf("Calling Browser.OpenFile with '%s'", filename)
|
||||||
return nil, i.browser.OpenFile(filename)
|
return nil, i.browser.OpenFile(filename)
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("Unknown Browser command '%s'", command)
|
return nil, fmt.Errorf("Unknown Browser command '%s'", command)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,47 +1,46 @@
|
|||||||
package wails
|
package binding
|
||||||
|
|
||||||
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
|
internalMethods *internalMethods
|
||||||
initMethods []*boundMethod
|
initMethods []*boundMethod
|
||||||
log *CustomLogger
|
log *logger.CustomLogger
|
||||||
renderer Renderer
|
renderer interfaces.Renderer
|
||||||
runtime *Runtime // The runtime object to pass to bound structs
|
runtime interfaces.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
|
||||||
}
|
}
|
||||||
|
|
||||||
func newBindingManager() *bindingManager {
|
// NewManager creates a new Manager struct
|
||||||
result := &bindingManager{
|
func NewManager() interfaces.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(),
|
internalMethods: newInternalMethods(),
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets flag to indicate package names should be considered when binding
|
// BindPackageNames sets a flag to indicate package names should be considered when binding
|
||||||
func (b *bindingManager) BindPackageNames() {
|
func (b *Manager) BindPackageNames() {
|
||||||
b.bindPackageNames = true
|
b.bindPackageNames = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *bindingManager) start(renderer Renderer, runtime *Runtime) error {
|
// Start the binding manager
|
||||||
|
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
|
||||||
@ -54,7 +53,7 @@ func (b *bindingManager) start(renderer Renderer, runtime *Runtime) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *bindingManager) initialise() error {
|
func (b *Manager) initialise() error {
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
// var binding *boundMethod
|
// var binding *boundMethod
|
||||||
@ -92,7 +91,7 @@ func (b *bindingManager) initialise() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// bind the given struct method
|
// bind the given struct method
|
||||||
func (b *bindingManager) bindMethod(object interface{}) error {
|
func (b *Manager) bindMethod(object interface{}) error {
|
||||||
|
|
||||||
objectType := reflect.TypeOf(object)
|
objectType := reflect.TypeOf(object)
|
||||||
baseName := objectType.String()
|
baseName := objectType.String()
|
||||||
@ -142,7 +141,7 @@ func (b *bindingManager) bindMethod(object interface{}) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// bind the given function object
|
// bind the given function object
|
||||||
func (b *bindingManager) bindFunction(object interface{}) error {
|
func (b *Manager) bindFunction(object interface{}) error {
|
||||||
|
|
||||||
newFunction, err := newBoundFunction(object)
|
newFunction, err := newBoundFunction(object)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -159,18 +158,18 @@ func (b *bindingManager) bindFunction(object interface{}) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save the given object to be bound at start time
|
// Bind saves the given object to be bound at start time
|
||||||
func (b *bindingManager) bind(object interface{}) {
|
func (b *Manager) Bind(object interface{}) {
|
||||||
// Store binding
|
// Store binding
|
||||||
b.objectsToBind = append(b.objectsToBind, object)
|
b.objectsToBind = append(b.objectsToBind, object)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *bindingManager) processInternalCall(callData *callData) (interface{}, error) {
|
func (b *Manager) processInternalCall(callData *messages.CallData) (interface{}, error) {
|
||||||
// Strip prefix
|
// Strip prefix
|
||||||
return b.internalMethods.processCall(callData)
|
return b.internalMethods.processCall(callData)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *bindingManager) processFunctionCall(callData *callData) (interface{}, error) {
|
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
|
||||||
@ -199,7 +198,7 @@ func (b *bindingManager) processFunctionCall(callData *callData) (interface{}, e
|
|||||||
return result[0].Interface(), nil
|
return result[0].Interface(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *bindingManager) processMethodCall(callData *callData) (interface{}, error) {
|
func (b *Manager) processMethodCall(callData *messages.CallData) (interface{}, error) {
|
||||||
// Return values
|
// Return values
|
||||||
var result []reflect.Value
|
var result []reflect.Value
|
||||||
var err error
|
var err error
|
||||||
@ -233,8 +232,8 @@ func (b *bindingManager) processMethodCall(callData *callData) (interface{}, err
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// process an incoming call request
|
// ProcessCall processes the given call request
|
||||||
func (b *bindingManager) processCall(callData *callData) (result interface{}, err error) {
|
func (b *Manager) ProcessCall(callData *messages.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
|
||||||
@ -272,7 +271,7 @@ func (b *bindingManager) processCall(callData *callData) (result interface{}, er
|
|||||||
|
|
||||||
// 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 *bindingManager) callWailsInitMethods() error {
|
func (b *Manager) 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}
|
@ -1,10 +1,12 @@
|
|||||||
package wails
|
package binding
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/lib/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
type boundMethod struct {
|
type boundMethod struct {
|
||||||
@ -13,7 +15,7 @@ type boundMethod struct {
|
|||||||
method reflect.Value
|
method reflect.Value
|
||||||
inputs []reflect.Type
|
inputs []reflect.Type
|
||||||
returnTypes []reflect.Type
|
returnTypes []reflect.Type
|
||||||
log *CustomLogger
|
log *logger.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
|
||||||
}
|
}
|
||||||
@ -27,7 +29,7 @@ func newBoundMethod(name string, fullName string, method reflect.Value, objectTy
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Setup logger
|
// Setup logger
|
||||||
result.log = newCustomLogger(result.fullName)
|
result.log = logger.NewCustomLogger(result.fullName)
|
||||||
|
|
||||||
// Check if Parameters are valid
|
// Check if Parameters are valid
|
||||||
err := result.processParameters()
|
err := result.processParameters()
|
||||||
@ -57,7 +59,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", Fields{
|
b.log.DebugFields("Input param", logger.Fields{
|
||||||
"index": index,
|
"index": index,
|
||||||
"name": name,
|
"name": name,
|
||||||
"kind": kind,
|
"kind": kind,
|
||||||
@ -166,10 +168,10 @@ func (b *boundMethod) setInputValue(index int, typ reflect.Type, val interface{}
|
|||||||
reflect.Map,
|
reflect.Map,
|
||||||
reflect.Ptr,
|
reflect.Ptr,
|
||||||
reflect.Slice:
|
reflect.Slice:
|
||||||
logger.Debug("Converting nil to type")
|
b.log.Debug("Converting nil to type")
|
||||||
result = reflect.ValueOf(val).Convert(typ)
|
result = reflect.ValueOf(val).Convert(typ)
|
||||||
default:
|
default:
|
||||||
logger.Debug("Cannot convert nil to type, returning error")
|
b.log.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 {
|
@ -1,31 +1,34 @@
|
|||||||
package wails
|
package event
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
"github.com/wailsapp/wails/lib/logger"
|
||||||
|
"github.com/wailsapp/wails/lib/messages"
|
||||||
|
"github.com/wailsapp/wails/lib/interfaces"
|
||||||
)
|
)
|
||||||
|
|
||||||
// eventManager handles and processes events
|
// Manager handles and processes events
|
||||||
type eventManager struct {
|
type Manager struct {
|
||||||
incomingEvents chan *eventData
|
incomingEvents chan *messages.EventData
|
||||||
listeners map[string][]*eventListener
|
listeners map[string][]*eventListener
|
||||||
exit bool
|
exit bool
|
||||||
log *CustomLogger
|
log *logger.CustomLogger
|
||||||
renderer Renderer // Messages will be dispatched to the frontend
|
renderer interfaces.Renderer // Messages will be dispatched to the frontend
|
||||||
}
|
}
|
||||||
|
|
||||||
// newEventManager creates a new event manager with a 100 event buffer
|
// NewManager creates a new event manager with a 100 event buffer
|
||||||
func newEventManager() *eventManager {
|
func NewManager() interfaces.EventManager {
|
||||||
return &eventManager{
|
return &Manager{
|
||||||
incomingEvents: make(chan *eventData, 100),
|
incomingEvents: make(chan *messages.EventData, 100),
|
||||||
listeners: make(map[string][]*eventListener),
|
listeners: make(map[string][]*eventListener),
|
||||||
exit: false,
|
exit: false,
|
||||||
log: newCustomLogger("Events"),
|
log: logger.NewCustomLogger("Events"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// PushEvent places the given event on to the event queue
|
// PushEvent places the given event on to the event queue
|
||||||
func (e *eventManager) PushEvent(eventData *eventData) {
|
func (e *Manager) PushEvent(eventData *messages.EventData) {
|
||||||
e.incomingEvents <- eventData
|
e.incomingEvents <- eventData
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,7 +43,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 *eventManager) addEventListener(eventName string, callback func(...interface{}), counter int) error {
|
func (e *Manager) addEventListener(eventName string, callback func(...interface{}), counter int) error {
|
||||||
|
|
||||||
// Sanity check inputs
|
// Sanity check inputs
|
||||||
if callback == nil {
|
if callback == nil {
|
||||||
@ -65,18 +68,19 @@ func (e *eventManager) addEventListener(eventName string, callback func(...inter
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *eventManager) On(eventName string, callback func(...interface{})) {
|
// On adds a listener for the given event
|
||||||
|
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 *eventManager) Emit(eventName string, optionalData ...interface{}) {
|
func (e *Manager) Emit(eventName string, optionalData ...interface{}) {
|
||||||
e.incomingEvents <- &eventData{Name: eventName, Data: optionalData}
|
e.incomingEvents <- &messages.EventData{Name: eventName, Data: optionalData}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Starts the event manager's queue processing
|
// Start the event manager's queue processing
|
||||||
func (e *eventManager) start(renderer Renderer) {
|
func (e *Manager) Start(renderer interfaces.Renderer) {
|
||||||
|
|
||||||
e.log.Info("Starting")
|
e.log.Info("Starting")
|
||||||
|
|
||||||
@ -95,7 +99,7 @@ func (e *eventManager) start(renderer 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", Fields{
|
e.log.DebugFields("Got Event", logger.Fields{
|
||||||
"data": event.Data,
|
"data": event.Data,
|
||||||
"name": event.Name,
|
"name": event.Name,
|
||||||
})
|
})
|
||||||
@ -143,6 +147,6 @@ func (e *eventManager) start(renderer Renderer) {
|
|||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *eventManager) stop() {
|
func (e *Manager) stop() {
|
||||||
e.exit = true
|
e.exit = true
|
||||||
}
|
}
|
14
lib/interfaces/appconfig.go
Normal file
14
lib/interfaces/appconfig.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
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
|
||||||
|
}
|
10
lib/interfaces/bindingmanager.go
Normal file
10
lib/interfaces/bindingmanager.go
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
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)
|
||||||
|
}
|
11
lib/interfaces/eventmanager.go
Normal file
11
lib/interfaces/eventmanager.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
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)
|
||||||
|
}
|
8
lib/interfaces/ipcmanager.go
Normal file
8
lib/interfaces/ipcmanager.go
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package interfaces
|
||||||
|
|
||||||
|
// IPCManager is the event manager interface
|
||||||
|
type IPCManager interface {
|
||||||
|
BindRenderer(Renderer)
|
||||||
|
Dispatch(message string)
|
||||||
|
Start(eventManager EventManager, bindingManager BindingManager)
|
||||||
|
}
|
@ -1,8 +1,11 @@
|
|||||||
package wails
|
package interfaces
|
||||||
|
|
||||||
|
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
|
||||||
@ -10,7 +13,7 @@ type Renderer interface {
|
|||||||
Callback(data string) error
|
Callback(data string) error
|
||||||
|
|
||||||
// Events
|
// Events
|
||||||
NotifyEvent(eventData *eventData) error
|
NotifyEvent(eventData *messages.EventData) error
|
||||||
|
|
||||||
// Dialog Runtime
|
// Dialog Runtime
|
||||||
SelectFile() string
|
SelectFile() string
|
4
lib/interfaces/runtime.go
Normal file
4
lib/interfaces/runtime.go
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
package interfaces
|
||||||
|
|
||||||
|
// Runtime interface
|
||||||
|
type Runtime interface {}
|
@ -1,13 +1,10 @@
|
|||||||
package wails
|
package ipc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
)
|
|
||||||
|
|
||||||
type callData struct {
|
"github.com/wailsapp/wails/lib/messages"
|
||||||
BindingName string `json:"bindingName"`
|
)
|
||||||
Data string `json:"data,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
messageProcessors["call"] = processCallData
|
messageProcessors["call"] = processCallData
|
||||||
@ -15,7 +12,7 @@ func init() {
|
|||||||
|
|
||||||
func processCallData(message *ipcMessage) (*ipcMessage, error) {
|
func processCallData(message *ipcMessage) (*ipcMessage, error) {
|
||||||
|
|
||||||
var payload callData
|
var payload messages.CallData
|
||||||
|
|
||||||
// Decode binding call data
|
// Decode binding call data
|
||||||
payloadMap := message.Payload.(map[string]interface{})
|
payloadMap := message.Payload.(map[string]interface{})
|
@ -1,13 +1,10 @@
|
|||||||
package wails
|
package ipc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
)
|
|
||||||
|
|
||||||
type eventData struct {
|
"github.com/wailsapp/wails/lib/messages"
|
||||||
Name string `json:"name"`
|
)
|
||||||
Data interface{} `json:"data"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register the message handler
|
// Register the message handler
|
||||||
func init() {
|
func init() {
|
||||||
@ -19,7 +16,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 eventData
|
var payload messages.EventData
|
||||||
|
|
||||||
// Decode event data
|
// Decode event data
|
||||||
payloadMap := message.Payload.(map[string]interface{})
|
payloadMap := message.Payload.(map[string]interface{})
|
@ -1,9 +1,6 @@
|
|||||||
package wails
|
package ipc
|
||||||
|
|
||||||
type logData struct {
|
import "github.com/wailsapp/wails/lib/messages"
|
||||||
Level string `json:"level"`
|
|
||||||
Message string `json:"string"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register the message handler
|
// Register the message handler
|
||||||
func init() {
|
func init() {
|
||||||
@ -13,7 +10,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 logData
|
var payload messages.LogData
|
||||||
|
|
||||||
// Decode event data
|
// Decode event data
|
||||||
payloadMap := message.Payload.(map[string]interface{})
|
payloadMap := message.Payload.(map[string]interface{})
|
@ -1,35 +1,42 @@
|
|||||||
package wails
|
package ipc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/lib/interfaces"
|
||||||
|
"github.com/wailsapp/wails/lib/logger"
|
||||||
|
"github.com/wailsapp/wails/lib/messages"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ipcManager struct {
|
// Manager manages the IPC subsystem
|
||||||
renderer Renderer // The renderer
|
type Manager struct {
|
||||||
|
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 *CustomLogger
|
log *logger.CustomLogger
|
||||||
eventManager *eventManager
|
eventManager interfaces.EventManager
|
||||||
bindingManager *bindingManager
|
bindingManager interfaces.BindingManager
|
||||||
}
|
}
|
||||||
|
|
||||||
func newIPCManager() *ipcManager {
|
// NewManager creates a new IPC Manager
|
||||||
result := &ipcManager{
|
func NewManager() interfaces.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: newCustomLogger("IPC"),
|
log: logger.NewCustomLogger("IPC"),
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the renderer, returns the dispatch function
|
// BindRenderer sets the renderer, returns the dispatch function
|
||||||
func (i *ipcManager) bindRenderer(renderer Renderer) {
|
func (i *Manager) BindRenderer(renderer interfaces.Renderer) {
|
||||||
i.renderer = renderer
|
i.renderer = renderer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *ipcManager) start(eventManager *eventManager, bindingManager *bindingManager) {
|
// Start the IPC Manager
|
||||||
|
func (i *Manager) Start(eventManager interfaces.EventManager, bindingManager interfaces.BindingManager) {
|
||||||
|
|
||||||
// Store manager references
|
// Store manager references
|
||||||
i.eventManager = eventManager
|
i.eventManager = eventManager
|
||||||
@ -42,36 +49,36 @@ func (i *ipcManager) start(eventManager *eventManager, bindingManager *bindingMa
|
|||||||
for running {
|
for running {
|
||||||
select {
|
select {
|
||||||
case incomingMessage := <-i.messageQueue:
|
case incomingMessage := <-i.messageQueue:
|
||||||
i.log.DebugFields("Processing message", Fields{
|
i.log.DebugFields("Processing message", logger.Fields{
|
||||||
"1D": &incomingMessage,
|
"1D": &incomingMessage,
|
||||||
})
|
})
|
||||||
switch incomingMessage.Type {
|
switch incomingMessage.Type {
|
||||||
case "call":
|
case "call":
|
||||||
callData := incomingMessage.Payload.(*callData)
|
callData := incomingMessage.Payload.(*messages.CallData)
|
||||||
i.log.DebugFields("Processing call", Fields{
|
i.log.DebugFields("Processing call", logger.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", Fields{"result": result, "err": err})
|
i.log.DebugFields("processed call", logger.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", Fields{
|
i.log.DebugFields("Finished processing call", logger.Fields{
|
||||||
"1D": &incomingMessage,
|
"1D": &incomingMessage,
|
||||||
})
|
})
|
||||||
}()
|
}()
|
||||||
case "event":
|
case "event":
|
||||||
|
|
||||||
// Extract event data
|
// Extract event data
|
||||||
eventData := incomingMessage.Payload.(*eventData)
|
eventData := incomingMessage.Payload.(*messages.EventData)
|
||||||
|
|
||||||
// Log
|
// Log
|
||||||
i.log.DebugFields("Processing event", Fields{
|
i.log.DebugFields("Processing event", logger.Fields{
|
||||||
"name": eventData.Name,
|
"name": eventData.Name,
|
||||||
"data": eventData.Data,
|
"data": eventData.Data,
|
||||||
})
|
})
|
||||||
@ -80,24 +87,24 @@ func (i *ipcManager) start(eventManager *eventManager, bindingManager *bindingMa
|
|||||||
i.eventManager.PushEvent(eventData)
|
i.eventManager.PushEvent(eventData)
|
||||||
|
|
||||||
// Log
|
// Log
|
||||||
i.log.DebugFields("Finished processing event", Fields{
|
i.log.DebugFields("Finished processing event", logger.Fields{
|
||||||
"name": eventData.Name,
|
"name": eventData.Name,
|
||||||
})
|
})
|
||||||
case "log":
|
case "log":
|
||||||
logdata := incomingMessage.Payload.(*logData)
|
logdata := incomingMessage.Payload.(*messages.LogData)
|
||||||
switch logdata.Level {
|
switch logdata.Level {
|
||||||
case "info":
|
case "info":
|
||||||
logger.Info(logdata.Message)
|
logger.GlobalLogger.Info(logdata.Message)
|
||||||
case "debug":
|
case "debug":
|
||||||
logger.Debug(logdata.Message)
|
logger.GlobalLogger.Debug(logdata.Message)
|
||||||
case "warning":
|
case "warning":
|
||||||
logger.Warning(logdata.Message)
|
logger.GlobalLogger.Warn(logdata.Message)
|
||||||
case "error":
|
case "error":
|
||||||
logger.Error(logdata.Message)
|
logger.GlobalLogger.Error(logdata.Message)
|
||||||
case "fatal":
|
case "fatal":
|
||||||
logger.Fatal(logdata.Message)
|
logger.GlobalLogger.Fatal(logdata.Message)
|
||||||
default:
|
default:
|
||||||
i.log.ErrorFields("Invalid log level sent", Fields{
|
logger.ErrorFields("Invalid log level sent", logger.Fields{
|
||||||
"level": logdata.Level,
|
"level": logdata.Level,
|
||||||
"message": logdata.Message,
|
"message": logdata.Message,
|
||||||
})
|
})
|
||||||
@ -107,7 +114,7 @@ func (i *ipcManager) start(eventManager *eventManager, bindingManager *bindingMa
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Log
|
// Log
|
||||||
i.log.DebugFields("Finished processing message", Fields{
|
i.log.DebugFields("Finished processing message", logger.Fields{
|
||||||
"1D": &incomingMessage,
|
"1D": &incomingMessage,
|
||||||
})
|
})
|
||||||
// case <-manager.quitChannel:
|
// case <-manager.quitChannel:
|
||||||
@ -125,7 +132,7 @@ func (i *ipcManager) start(eventManager *eventManager, bindingManager *bindingMa
|
|||||||
// 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 *ipcManager) Dispatch(message string) {
|
func (i *Manager) 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)
|
||||||
@ -148,7 +155,7 @@ func (i *ipcManager) Dispatch(message string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SendResponse sends the given response back to the frontend
|
// SendResponse sends the given response back to the frontend
|
||||||
func (i *ipcManager) SendResponse(response *ipcResponse) error {
|
func (i *Manager) SendResponse(response *ipcResponse) error {
|
||||||
|
|
||||||
// Serialise the Message
|
// Serialise the Message
|
||||||
data, err := response.Serialise()
|
data, err := response.Serialise()
|
@ -1,4 +1,4 @@
|
|||||||
package wails
|
package ipc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
@ -1,4 +1,4 @@
|
|||||||
package wails
|
package ipc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
@ -1,4 +1,4 @@
|
|||||||
package wails
|
package logger
|
||||||
|
|
||||||
// CustomLogger is a wrapper object to logrus
|
// CustomLogger is a wrapper object to logrus
|
||||||
type CustomLogger struct {
|
type CustomLogger struct {
|
||||||
@ -6,7 +6,8 @@ type CustomLogger struct {
|
|||||||
errorOnly bool
|
errorOnly bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func newCustomLogger(prefix string) *CustomLogger {
|
// NewCustomLogger creates a new custom logger with the given prefix
|
||||||
|
func NewCustomLogger(prefix string) *CustomLogger {
|
||||||
return &CustomLogger{
|
return &CustomLogger{
|
||||||
prefix: "[" + prefix + "] ",
|
prefix: "[" + prefix + "] ",
|
||||||
}
|
}
|
||||||
@ -14,90 +15,90 @@ func newCustomLogger(prefix string) *CustomLogger {
|
|||||||
|
|
||||||
// Info level message
|
// Info level message
|
||||||
func (c *CustomLogger) Info(message string) {
|
func (c *CustomLogger) Info(message string) {
|
||||||
logger.Info(c.prefix + message)
|
GlobalLogger.Info(c.prefix + message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Infof - formatted message
|
// Infof - formatted message
|
||||||
func (c *CustomLogger) Infof(message string, args ...interface{}) {
|
func (c *CustomLogger) Infof(message string, args ...interface{}) {
|
||||||
logger.Infof(c.prefix+message, args...)
|
GlobalLogger.Infof(c.prefix+message, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InfoFields - message with fields
|
// InfoFields - message with fields
|
||||||
func (c *CustomLogger) InfoFields(message string, fields Fields) {
|
func (c *CustomLogger) InfoFields(message string, fields Fields) {
|
||||||
logger.WithFields(map[string]interface{}(fields)).Info(c.prefix + message)
|
GlobalLogger.WithFields(map[string]interface{}(fields)).Info(c.prefix + message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debug level message
|
// Debug level message
|
||||||
func (c *CustomLogger) Debug(message string) {
|
func (c *CustomLogger) Debug(message string) {
|
||||||
logger.Debug(c.prefix + message)
|
GlobalLogger.Debug(c.prefix + message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debugf - formatted message
|
// Debugf - formatted message
|
||||||
func (c *CustomLogger) Debugf(message string, args ...interface{}) {
|
func (c *CustomLogger) Debugf(message string, args ...interface{}) {
|
||||||
logger.Debugf(c.prefix+message, args...)
|
GlobalLogger.Debugf(c.prefix+message, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DebugFields - message with fields
|
// DebugFields - message with fields
|
||||||
func (c *CustomLogger) DebugFields(message string, fields Fields) {
|
func (c *CustomLogger) DebugFields(message string, fields Fields) {
|
||||||
logger.WithFields(map[string]interface{}(fields)).Debug(c.prefix + message)
|
GlobalLogger.WithFields(map[string]interface{}(fields)).Debug(c.prefix + message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Warn level message
|
// Warn level message
|
||||||
func (c *CustomLogger) Warn(message string) {
|
func (c *CustomLogger) Warn(message string) {
|
||||||
logger.Warn(c.prefix + message)
|
GlobalLogger.Warn(c.prefix + message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Warnf - formatted message
|
// Warnf - formatted message
|
||||||
func (c *CustomLogger) Warnf(message string, args ...interface{}) {
|
func (c *CustomLogger) Warnf(message string, args ...interface{}) {
|
||||||
logger.Warnf(c.prefix+message, args...)
|
GlobalLogger.Warnf(c.prefix+message, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WarnFields - message with fields
|
// WarnFields - message with fields
|
||||||
func (c *CustomLogger) WarnFields(message string, fields Fields) {
|
func (c *CustomLogger) WarnFields(message string, fields Fields) {
|
||||||
logger.WithFields(map[string]interface{}(fields)).Warn(c.prefix + message)
|
GlobalLogger.WithFields(map[string]interface{}(fields)).Warn(c.prefix + message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error level message
|
// Error level message
|
||||||
func (c *CustomLogger) Error(message string) {
|
func (c *CustomLogger) Error(message string) {
|
||||||
logger.Error(c.prefix + message)
|
GlobalLogger.Error(c.prefix + message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Errorf - formatted message
|
// Errorf - formatted message
|
||||||
func (c *CustomLogger) Errorf(message string, args ...interface{}) {
|
func (c *CustomLogger) Errorf(message string, args ...interface{}) {
|
||||||
logger.Errorf(c.prefix+message, args...)
|
GlobalLogger.Errorf(c.prefix+message, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrorFields - message with fields
|
// ErrorFields - message with fields
|
||||||
func (c *CustomLogger) ErrorFields(message string, fields Fields) {
|
func (c *CustomLogger) ErrorFields(message string, fields Fields) {
|
||||||
logger.WithFields(map[string]interface{}(fields)).Error(c.prefix + message)
|
GlobalLogger.WithFields(map[string]interface{}(fields)).Error(c.prefix + message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fatal level message
|
// Fatal level message
|
||||||
func (c *CustomLogger) Fatal(message string) {
|
func (c *CustomLogger) Fatal(message string) {
|
||||||
logger.Fatal(c.prefix + message)
|
GlobalLogger.Fatal(c.prefix + message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fatalf - formatted message
|
// Fatalf - formatted message
|
||||||
func (c *CustomLogger) Fatalf(message string, args ...interface{}) {
|
func (c *CustomLogger) Fatalf(message string, args ...interface{}) {
|
||||||
logger.Fatalf(c.prefix+message, args...)
|
GlobalLogger.Fatalf(c.prefix+message, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FatalFields - message with fields
|
// FatalFields - message with fields
|
||||||
func (c *CustomLogger) FatalFields(message string, fields Fields) {
|
func (c *CustomLogger) FatalFields(message string, fields Fields) {
|
||||||
logger.WithFields(map[string]interface{}(fields)).Fatal(c.prefix + message)
|
GlobalLogger.WithFields(map[string]interface{}(fields)).Fatal(c.prefix + message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Panic level message
|
// Panic level message
|
||||||
func (c *CustomLogger) Panic(message string) {
|
func (c *CustomLogger) Panic(message string) {
|
||||||
logger.Panic(c.prefix + message)
|
GlobalLogger.Panic(c.prefix + message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Panicf - formatted message
|
// Panicf - formatted message
|
||||||
func (c *CustomLogger) Panicf(message string, args ...interface{}) {
|
func (c *CustomLogger) Panicf(message string, args ...interface{}) {
|
||||||
logger.Panicf(c.prefix+message, args...)
|
GlobalLogger.Panicf(c.prefix+message, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PanicFields - message with fields
|
// PanicFields - message with fields
|
||||||
func (c *CustomLogger) PanicFields(message string, fields Fields) {
|
func (c *CustomLogger) PanicFields(message string, fields Fields) {
|
||||||
logger.WithFields(map[string]interface{}(fields)).Panic(c.prefix + message)
|
GlobalLogger.WithFields(map[string]interface{}(fields)).Panic(c.prefix + message)
|
||||||
}
|
}
|
47
lib/logger/log.go
Normal file
47
lib/logger/log.go
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package logger
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GlobalLogger is the global logger
|
||||||
|
var GlobalLogger = logrus.New()
|
||||||
|
|
||||||
|
// Fields is used by the customLogger object to output
|
||||||
|
// fields along with a message
|
||||||
|
type Fields map[string]interface{}
|
||||||
|
|
||||||
|
// Default options for the global logger
|
||||||
|
func init() {
|
||||||
|
GlobalLogger.SetOutput(os.Stdout)
|
||||||
|
GlobalLogger.SetLevel(logrus.DebugLevel)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrorFields is a helper for logging fields to the global logger
|
||||||
|
func ErrorFields(message string, fields Fields) {
|
||||||
|
GlobalLogger.WithFields(map[string]interface{}(fields)).Error(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLogLevel sets the log level to the given level
|
||||||
|
func SetLogLevel(level string) {
|
||||||
|
switch strings.ToLower(level) {
|
||||||
|
case "info":
|
||||||
|
GlobalLogger.SetLevel(logrus.InfoLevel)
|
||||||
|
case "debug":
|
||||||
|
GlobalLogger.SetLevel(logrus.DebugLevel)
|
||||||
|
case "warn":
|
||||||
|
GlobalLogger.SetLevel(logrus.WarnLevel)
|
||||||
|
case "error":
|
||||||
|
GlobalLogger.SetLevel(logrus.ErrorLevel)
|
||||||
|
case "fatal":
|
||||||
|
GlobalLogger.SetLevel(logrus.FatalLevel)
|
||||||
|
case "panic":
|
||||||
|
GlobalLogger.SetLevel(logrus.PanicLevel)
|
||||||
|
default:
|
||||||
|
GlobalLogger.SetLevel(logrus.DebugLevel)
|
||||||
|
GlobalLogger.Warnf("Log level '%s' not recognised. Setting to Debug.", level)
|
||||||
|
}
|
||||||
|
}
|
7
lib/messages/calldata.go
Normal file
7
lib/messages/calldata.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package messages
|
||||||
|
|
||||||
|
// CallData represents a call to a Go function/method
|
||||||
|
type CallData struct {
|
||||||
|
BindingName string `json:"bindingName"`
|
||||||
|
Data string `json:"data,omitempty"`
|
||||||
|
}
|
7
lib/messages/eventdata.go
Normal file
7
lib/messages/eventdata.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package messages
|
||||||
|
|
||||||
|
// EventData represents an event sent from the frontend
|
||||||
|
type EventData struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Data interface{} `json:"data"`
|
||||||
|
}
|
7
lib/messages/logdata.go
Normal file
7
lib/messages/logdata.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package messages
|
||||||
|
|
||||||
|
// LogData represents a call to log from the frontend
|
||||||
|
type LogData struct {
|
||||||
|
Level string `json:"level"`
|
||||||
|
Message string `json:"string"`
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package wails
|
package renderer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@ -10,6 +10,9 @@ 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
|
||||||
@ -28,17 +31,17 @@ func (m messageType) toString() string {
|
|||||||
return [...]string{"j", "s", "h", "n", "b", "c", "w"}[m]
|
return [...]string{"j", "s", "h", "n", "b", "c", "w"}[m]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Headless is a backend that opens a local web server
|
// Bridge is a backend that opens a local web server
|
||||||
// and renders the files over a websocket
|
// and renders the files over a websocket
|
||||||
type Headless struct {
|
type Bridge struct {
|
||||||
// Common
|
// Common
|
||||||
log *CustomLogger
|
log *logger.CustomLogger
|
||||||
ipcManager *ipcManager
|
ipcManager interfaces.IPCManager
|
||||||
appConfig *AppConfig
|
appConfig interfaces.AppConfig
|
||||||
eventManager *eventManager
|
eventManager interfaces.EventManager
|
||||||
bindingCache []string
|
bindingCache []string
|
||||||
|
|
||||||
// Headless specific
|
// Bridge specific
|
||||||
initialisationJS []string
|
initialisationJS []string
|
||||||
server *http.Server
|
server *http.Server
|
||||||
theConnection *websocket.Conn
|
theConnection *websocket.Conn
|
||||||
@ -47,17 +50,17 @@ type Headless struct {
|
|||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialise the Headless Renderer
|
// Initialise the Bridge Renderer
|
||||||
func (h *Headless) Initialise(appConfig *AppConfig, ipcManager *ipcManager, eventManager *eventManager) error {
|
func (h *Bridge) Initialise(appConfig interfaces.AppConfig, ipcManager interfaces.IPCManager, eventManager interfaces.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 = newCustomLogger("Bridge")
|
h.log = logger.NewCustomLogger("Bridge")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Headless) evalJS(js string, mtype messageType) error {
|
func (h *Bridge) evalJS(js string, mtype messageType) error {
|
||||||
|
|
||||||
message := mtype.toString() + js
|
message := mtype.toString() + js
|
||||||
|
|
||||||
@ -71,7 +74,7 @@ func (h *Headless) evalJS(js string, mtype messageType) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Headless) injectCSS(css string) {
|
func (h *Bridge) injectCSS(css string) {
|
||||||
// Minify css to overcome issues in the browser with carriage returns
|
// Minify css to overcome issues in the browser with carriage returns
|
||||||
minified, err := htmlmin.Minify([]byte(css), &htmlmin.Options{
|
minified, err := htmlmin.Minify([]byte(css), &htmlmin.Options{
|
||||||
MinifyStyles: true,
|
MinifyStyles: true,
|
||||||
@ -83,11 +86,11 @@ 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Headless) wsBridgeHandler(w http.ResponseWriter, r *http.Request) {
|
func (h *Bridge) wsBridgeHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
conn, err := websocket.Upgrade(w, r, w.Header(), 1024, 1024)
|
conn, err := websocket.Upgrade(w, r, w.Header(), 1024, 1024)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "Could not open websocket connection", http.StatusBadRequest)
|
http.Error(w, "Could not open websocket connection", http.StatusBadRequest)
|
||||||
@ -102,7 +105,7 @@ func (h *Headless) wsBridgeHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
go h.start(conn)
|
go h.start(conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Headless) sendMessage(conn *websocket.Conn, msg string) {
|
func (h *Bridge) sendMessage(conn *websocket.Conn, msg string) {
|
||||||
|
|
||||||
h.lock.Lock()
|
h.lock.Lock()
|
||||||
defer h.lock.Unlock()
|
defer h.lock.Unlock()
|
||||||
@ -112,12 +115,12 @@ func (h *Headless) sendMessage(conn *websocket.Conn, msg string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Headless) start(conn *websocket.Conn) {
|
func (h *Bridge) 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("./wailsruntimeassets/default/wails.min.js")
|
wailsRuntime := mewn.String("../../runtime/assets/wails.js")
|
||||||
h.evalJS(wailsRuntime, wailsRuntimeMessage)
|
h.evalJS(wailsRuntime, wailsRuntimeMessage)
|
||||||
|
|
||||||
// Inject bindings
|
// Inject bindings
|
||||||
@ -144,8 +147,8 @@ func (h *Headless) start(conn *websocket.Conn) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the app in headless mode!
|
// Run the app in Bridge mode!
|
||||||
func (h *Headless) Run() error {
|
func (h *Bridge) Run() error {
|
||||||
h.server = &http.Server{Addr: ":34115"}
|
h.server = &http.Server{Addr: ":34115"}
|
||||||
http.HandleFunc("/bridge", h.wsBridgeHandler)
|
http.HandleFunc("/bridge", h.wsBridgeHandler)
|
||||||
|
|
||||||
@ -160,45 +163,45 @@ func (h *Headless) Run() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewBinding creates a new binding with the frontend
|
// NewBinding creates a new binding with the frontend
|
||||||
func (h *Headless) NewBinding(methodName string) error {
|
func (h *Bridge) NewBinding(methodName string) error {
|
||||||
h.bindingCache = append(h.bindingCache, methodName)
|
h.bindingCache = append(h.bindingCache, methodName)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectFile is unsupported for Headless but required
|
// SelectFile is unsupported for Bridge but required
|
||||||
// for the Renderer interface
|
// for the Renderer interface
|
||||||
func (h *Headless) SelectFile() string {
|
func (h *Bridge) SelectFile() string {
|
||||||
h.log.Warn("SelectFile() unsupported in bridge mode")
|
h.log.Warn("SelectFile() unsupported in bridge mode")
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectDirectory is unsupported for Headless but required
|
// SelectDirectory is unsupported for Bridge but required
|
||||||
// for the Renderer interface
|
// for the Renderer interface
|
||||||
func (h *Headless) SelectDirectory() string {
|
func (h *Bridge) SelectDirectory() string {
|
||||||
h.log.Warn("SelectDirectory() unsupported in bridge mode")
|
h.log.Warn("SelectDirectory() unsupported in bridge mode")
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectSaveFile is unsupported for Headless but required
|
// SelectSaveFile is unsupported for Bridge but required
|
||||||
// for the Renderer interface
|
// for the Renderer interface
|
||||||
func (h *Headless) SelectSaveFile() string {
|
func (h *Bridge) SelectSaveFile() string {
|
||||||
h.log.Warn("SelectSaveFile() unsupported in bridge mode")
|
h.log.Warn("SelectSaveFile() unsupported in bridge mode")
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// Callback sends a callback to the frontend
|
// Callback sends a callback to the frontend
|
||||||
func (h *Headless) Callback(data string) error {
|
func (h *Bridge) Callback(data string) error {
|
||||||
return h.evalJS(data, callbackMessage)
|
return h.evalJS(data, callbackMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyEvent notifies the frontend of an event
|
// NotifyEvent notifies the frontend of an event
|
||||||
func (h *Headless) NotifyEvent(event *eventData) error {
|
func (h *Bridge) 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.webViewRenderer")
|
err = fmt.Errorf("Sent nil event to renderer.webViewRenderer")
|
||||||
logger.Error(err)
|
h.log.Error(err.Error())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,37 +218,37 @@ func (h *Headless) NotifyEvent(event *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 Bridge but required
|
||||||
// for the Renderer interface
|
// for the Renderer interface
|
||||||
func (h *Headless) SetColour(colour string) error {
|
func (h *Bridge) SetColour(colour string) error {
|
||||||
h.log.WarnFields("SetColour ignored for headless more", Fields{"col": colour})
|
h.log.WarnFields("SetColour ignored for Bridge more", logger.Fields{"col": colour})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fullscreen is unsupported for Headless but required
|
// Fullscreen is unsupported for Bridge but required
|
||||||
// for the Renderer interface
|
// for the Renderer interface
|
||||||
func (h *Headless) Fullscreen() {
|
func (h *Bridge) Fullscreen() {
|
||||||
h.log.Warn("Fullscreen() unsupported in bridge mode")
|
h.log.Warn("Fullscreen() unsupported in bridge mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnFullscreen is unsupported for Headless but required
|
// UnFullscreen is unsupported for Bridge but required
|
||||||
// for the Renderer interface
|
// for the Renderer interface
|
||||||
func (h *Headless) UnFullscreen() {
|
func (h *Bridge) UnFullscreen() {
|
||||||
h.log.Warn("UnFullscreen() unsupported in bridge mode")
|
h.log.Warn("UnFullscreen() unsupported in bridge mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTitle is currently unsupported for Headless but required
|
// SetTitle is currently unsupported for Bridge but required
|
||||||
// for the Renderer interface
|
// for the Renderer interface
|
||||||
func (h *Headless) SetTitle(title string) {
|
func (h *Bridge) SetTitle(title string) {
|
||||||
h.log.WarnFields("SetTitle() unsupported in bridge mode", Fields{"title": title})
|
h.log.WarnFields("SetTitle() unsupported in bridge mode", logger.Fields{"title": title})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close is unsupported for Headless but required
|
// Close is unsupported for Bridge but required
|
||||||
// for the Renderer interface
|
// for the Renderer interface
|
||||||
func (h *Headless) Close() {
|
func (h *Bridge) Close() {
|
||||||
h.log.Warn("Close() unsupported in bridge mode")
|
h.log.Warn("Close() unsupported in bridge mode")
|
||||||
}
|
}
|
10
lib/renderer/renderer-mewn.go
Normal file
10
lib/renderer/renderer-mewn.go
Normal file
File diff suppressed because one or more lines are too long
@ -1,52 +1,61 @@
|
|||||||
package wails
|
package renderer
|
||||||
|
|
||||||
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/interfaces"
|
||||||
|
"github.com/wailsapp/wails/lib/logger"
|
||||||
|
"github.com/wailsapp/wails/lib/messages"
|
||||||
"github.com/wailsapp/webview"
|
"github.com/wailsapp/webview"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Window defines the main application window
|
// WebView defines the main webview application window
|
||||||
// Default values in []
|
// Default values in []
|
||||||
type webViewRenderer struct {
|
type WebView struct {
|
||||||
window webview.WebView // The webview object
|
window webview.WebView // The webview object
|
||||||
ipc *ipcManager
|
ipc interfaces.IPCManager
|
||||||
log *CustomLogger
|
log *logger.CustomLogger
|
||||||
config *AppConfig
|
config interfaces.AppConfig
|
||||||
eventManager *eventManager
|
eventManager interfaces.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 *webViewRenderer) Initialise(config *AppConfig, ipc *ipcManager, eventManager *eventManager) error {
|
func (w *WebView) Initialise(config interfaces.AppConfig, ipc interfaces.IPCManager, eventManager interfaces.EventManager) error {
|
||||||
|
|
||||||
// Store reference to eventManager
|
// Store reference to eventManager
|
||||||
w.eventManager = eventManager
|
w.eventManager = eventManager
|
||||||
|
|
||||||
// Set up logger
|
// Set up logger
|
||||||
w.log = newCustomLogger("WebView")
|
w.log = logger.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.Width,
|
Width: config.GetWidth(),
|
||||||
Height: config.Height,
|
Height: config.GetHeight(),
|
||||||
Title: config.Title,
|
Title: config.GetTitle(),
|
||||||
Resizable: config.Resizable,
|
Resizable: config.GetResizable(),
|
||||||
URL: config.defaultHTML,
|
URL: config.GetDefaultHTML(),
|
||||||
Debug: !config.DisableInspector,
|
Debug: !config.GetDisableInspector(),
|
||||||
ExternalInvokeCallback: func(_ webview.WebView, message string) {
|
ExternalInvokeCallback: func(_ webview.WebView, message string) {
|
||||||
w.ipc.Dispatch(message)
|
w.ipc.Dispatch(message)
|
||||||
},
|
},
|
||||||
@ -55,7 +64,7 @@ func (w *webViewRenderer) Initialise(config *AppConfig, ipc *ipcManager, eventMa
|
|||||||
// SignalManager.OnExit(w.Exit)
|
// SignalManager.OnExit(w.Exit)
|
||||||
|
|
||||||
// Set colour
|
// Set colour
|
||||||
err := w.SetColour(config.Colour)
|
err := w.SetColour(config.GetColour())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -64,7 +73,8 @@ func (w *webViewRenderer) Initialise(config *AppConfig, ipc *ipcManager, eventMa
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *webViewRenderer) SetColour(colour string) error {
|
// SetColour sets the window colour
|
||||||
|
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
|
||||||
@ -80,12 +90,12 @@ func (w *webViewRenderer) 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 *webViewRenderer) evalJS(js string) error {
|
func (w *WebView) 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", Fields{"js": outputJS})
|
w.log.DebugFields("Eval", logger.Fields{"js": outputJS})
|
||||||
//
|
//
|
||||||
w.window.Dispatch(func() {
|
w.window.Dispatch(func() {
|
||||||
w.window.Eval(js)
|
w.window.Eval(js)
|
||||||
@ -93,12 +103,21 @@ func (w *webViewRenderer) 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 *webViewRenderer) evalJSSync(js string) error {
|
func (w *WebView) evalJSSync(js string) error {
|
||||||
|
|
||||||
minified, err := escapeJS(js)
|
minified, err := escapeJS(js)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -107,7 +126,7 @@ func (w *webViewRenderer) evalJSSync(js string) error {
|
|||||||
if len(js) > 45 {
|
if len(js) > 45 {
|
||||||
outputJS += "..."
|
outputJS += "..."
|
||||||
}
|
}
|
||||||
w.log.DebugFields("EvalSync", Fields{"js": outputJS})
|
w.log.DebugFields("EvalSync", logger.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
|
||||||
@ -122,7 +141,7 @@ func (w *webViewRenderer) 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)
|
||||||
})
|
})
|
||||||
@ -137,26 +156,30 @@ func (w *webViewRenderer) evalJSSync(js string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// injectCSS adds the given CSS to the WebView
|
// injectCSS adds the given CSS to the WebView
|
||||||
func (w *webViewRenderer) injectCSS(css string) {
|
func (w *WebView) injectCSS(css string) {
|
||||||
w.window.Dispatch(func() {
|
w.window.Dispatch(func() {
|
||||||
w.window.InjectCSS(css)
|
w.window.InjectCSS(css)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Quit the window
|
// Exit closes the window
|
||||||
func (w *webViewRenderer) Exit() {
|
func (w *WebView) Exit() {
|
||||||
w.window.Exit()
|
w.window.Exit()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the window main loop
|
// Run the window main loop
|
||||||
func (w *webViewRenderer) Run() error {
|
func (w *WebView) Run() error {
|
||||||
|
|
||||||
w.log.Info("Run()")
|
w.log.Info("Run()")
|
||||||
|
|
||||||
// Runtime assets
|
// Runtime assets
|
||||||
wailsRuntime := mewn.String("./wailsruntimeassets/default/wails.min.js")
|
wailsRuntime := mewn.String("../../runtime/assets/wails.js")
|
||||||
|
w.log.Info("1")
|
||||||
|
|
||||||
w.evalJS(wailsRuntime)
|
w.evalJS(wailsRuntime)
|
||||||
|
|
||||||
|
w.log.Info("2")
|
||||||
|
|
||||||
// Ping the wait channel when the wails runtime is loaded
|
// Ping the wait channel when the wails runtime is loaded
|
||||||
w.eventManager.On("wails:loaded", func(...interface{}) {
|
w.eventManager.On("wails:loaded", func(...interface{}) {
|
||||||
|
|
||||||
@ -168,38 +191,30 @@ func (w *webViewRenderer) 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.CSS != "" {
|
if w.config.GetCSS() != "" {
|
||||||
outputCSS := fmt.Sprintf("%.45s", w.config.CSS)
|
outputCSS := fmt.Sprintf("%.45s", w.config.GetCSS())
|
||||||
if len(outputCSS) > 45 {
|
if len(outputCSS) > 45 {
|
||||||
outputCSS += "..."
|
outputCSS += "..."
|
||||||
}
|
}
|
||||||
w.log.DebugFields("Inject User CSS", Fields{"css": outputCSS})
|
w.log.DebugFields("Inject User CSS", logger.Fields{"css": outputCSS})
|
||||||
w.injectCSS(w.config.CSS)
|
w.injectCSS(w.config.GetCSS())
|
||||||
} 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("./wailsruntimeassets/default/wails.css")
|
defaultCSS := mewn.String("../../runtime/assets/wails.css")
|
||||||
|
|
||||||
w.injectCSS(defaultCSS)
|
w.injectCSS(defaultCSS)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inject user JS
|
// Inject user JS
|
||||||
if w.config.JS != "" {
|
if w.config.GetJS() != "" {
|
||||||
outputJS := fmt.Sprintf("%.45s", w.config.JS)
|
outputJS := fmt.Sprintf("%.45s", w.config.GetJS())
|
||||||
if len(outputJS) > 45 {
|
if len(outputJS) > 45 {
|
||||||
outputJS += "..."
|
outputJS += "..."
|
||||||
}
|
}
|
||||||
w.log.DebugFields("Inject User JS", Fields{"js": outputJS})
|
w.log.DebugFields("Inject User JS", logger.Fields{"js": outputJS})
|
||||||
w.evalJSSync(w.config.JS)
|
w.evalJSSync(w.config.GetJS())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit that everything is loaded and ready
|
// Emit that everything is loaded and ready
|
||||||
@ -213,14 +228,15 @@ func (w *webViewRenderer) Run() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Binds the given method name with the front end
|
// NewBinding registers a new binding with the frontend
|
||||||
func (w *webViewRenderer) NewBinding(methodName string) error {
|
func (w *WebView) 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
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *webViewRenderer) SelectFile() string {
|
// SelectFile opens a dialog that allows the user to select a file
|
||||||
|
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
|
||||||
@ -238,7 +254,8 @@ func (w *webViewRenderer) SelectFile() string {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *webViewRenderer) SelectDirectory() string {
|
// SelectDirectory opens a dialog that allows the user to select a directory
|
||||||
|
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
|
||||||
@ -255,7 +272,8 @@ func (w *webViewRenderer) SelectDirectory() string {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *webViewRenderer) SelectSaveFile() string {
|
// SelectSaveFile opens a dialog that allows the user to select a file to save
|
||||||
|
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
|
||||||
@ -273,18 +291,19 @@ func (w *webViewRenderer) SelectSaveFile() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Callback sends a callback to the frontend
|
// Callback sends a callback to the frontend
|
||||||
func (w *webViewRenderer) Callback(data string) error {
|
func (w *WebView) 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *webViewRenderer) NotifyEvent(event *eventData) error {
|
// NotifyEvent notifies the frontend about a backend runtime event
|
||||||
|
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.webViewRenderer")
|
err = fmt.Errorf("Sent nil event to renderer.WebView")
|
||||||
logger.Error(err)
|
w.log.Error(err.Error())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,13 +320,13 @@ func (w *webViewRenderer) NotifyEvent(event *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)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Window
|
// Fullscreen makes the main window go fullscreen
|
||||||
func (w *webViewRenderer) Fullscreen() {
|
func (w *WebView) Fullscreen() {
|
||||||
if w.config.Resizable == false {
|
if w.config.GetResizable() == false {
|
||||||
w.log.Warn("Cannot call Fullscreen() - App.Resizable = false")
|
w.log.Warn("Cannot call Fullscreen() - App.Resizable = false")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -316,8 +335,9 @@ func (w *webViewRenderer) Fullscreen() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *webViewRenderer) UnFullscreen() {
|
// UnFullscreen returns the window to the position prior to a fullscreen call
|
||||||
if w.config.Resizable == false {
|
func (w *WebView) UnFullscreen() {
|
||||||
|
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
|
||||||
}
|
}
|
||||||
@ -326,13 +346,15 @@ func (w *webViewRenderer) UnFullscreen() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *webViewRenderer) SetTitle(title string) {
|
// SetTitle sets the window title
|
||||||
|
func (w *WebView) SetTitle(title string) {
|
||||||
w.window.Dispatch(func() {
|
w.window.Dispatch(func() {
|
||||||
w.window.SetTitle(title)
|
w.window.SetTitle(title)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *webViewRenderer) Close() {
|
// Close closes the window
|
||||||
|
func (w *WebView) Close() {
|
||||||
w.window.Dispatch(func() {
|
w.window.Dispatch(func() {
|
||||||
w.window.Terminate()
|
w.window.Terminate()
|
||||||
})
|
})
|
42
log.go
42
log.go
@ -1,42 +0,0 @@
|
|||||||
package wails
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Global logger reference
|
|
||||||
var logger = log.New()
|
|
||||||
|
|
||||||
// Fields is used by the customLogger object to output
|
|
||||||
// fields along with a message
|
|
||||||
type Fields map[string]interface{}
|
|
||||||
|
|
||||||
// Default options for the global logger
|
|
||||||
func init() {
|
|
||||||
logger.SetOutput(os.Stdout)
|
|
||||||
logger.SetLevel(log.DebugLevel)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sets the log level to the given level
|
|
||||||
func setLogLevel(level string) {
|
|
||||||
switch strings.ToLower(level) {
|
|
||||||
case "info":
|
|
||||||
logger.SetLevel(log.InfoLevel)
|
|
||||||
case "debug":
|
|
||||||
logger.SetLevel(log.DebugLevel)
|
|
||||||
case "warn":
|
|
||||||
logger.SetLevel(log.WarnLevel)
|
|
||||||
case "error":
|
|
||||||
logger.SetLevel(log.ErrorLevel)
|
|
||||||
case "fatal":
|
|
||||||
logger.SetLevel(log.FatalLevel)
|
|
||||||
case "panic":
|
|
||||||
logger.SetLevel(log.PanicLevel)
|
|
||||||
default:
|
|
||||||
logger.SetLevel(log.DebugLevel)
|
|
||||||
logger.Warnf("Log level '%s' not recognised. Setting to Debug.", level)
|
|
||||||
}
|
|
||||||
}
|
|
36
runtime.go
36
runtime.go
@ -1,22 +1,32 @@
|
|||||||
package wails
|
package wails
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/wailsapp/wails/lib/interfaces"
|
||||||
|
"github.com/wailsapp/wails/lib/logger"
|
||||||
|
"github.com/wailsapp/wails/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CustomLogger type alias
|
||||||
|
type CustomLogger = logger.CustomLogger
|
||||||
|
|
||||||
// Runtime is the Wails Runtime Interface, given to a user who has defined the WailsInit method
|
// Runtime is the Wails Runtime Interface, given to a user who has defined the WailsInit method
|
||||||
type Runtime struct {
|
type Runtime struct {
|
||||||
Events *RuntimeEvents
|
Events *runtime.Events
|
||||||
Log *RuntimeLog
|
Log *runtime.Log
|
||||||
Dialog *RuntimeDialog
|
Dialog *runtime.Dialog
|
||||||
Window *RuntimeWindow
|
Window *runtime.Window
|
||||||
Browser *RuntimeBrowser
|
Browser *runtime.Browser
|
||||||
FileSystem *RuntimeFileSystem
|
FileSystem *runtime.FileSystem
|
||||||
}
|
}
|
||||||
|
|
||||||
func newRuntime(eventManager *eventManager, renderer Renderer) *Runtime {
|
// NewRuntime creates a new Runtime struct
|
||||||
|
func NewRuntime(eventManager interfaces.EventManager, renderer interfaces.Renderer) *Runtime {
|
||||||
return &Runtime{
|
return &Runtime{
|
||||||
Events: newRuntimeEvents(eventManager),
|
Events: runtime.NewEvents(eventManager),
|
||||||
Log: newRuntimeLog(),
|
Log: runtime.NewLog(),
|
||||||
Dialog: newRuntimeDialog(renderer),
|
Dialog: runtime.NewDialog(renderer),
|
||||||
Window: newRuntimeWindow(renderer),
|
Window: runtime.NewWindow(renderer),
|
||||||
Browser: newRuntimeBrowser(),
|
Browser: runtime.NewBrowser(),
|
||||||
FileSystem: newRuntimeFileSystem(),
|
FileSystem: runtime.NewFileSystem(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
217
runtime/assets/bridge.js
Normal file
217
runtime/assets/bridge.js
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
/*
|
||||||
|
_ __ _ __
|
||||||
|
| | / /___ _(_) /____
|
||||||
|
| | /| / / __ `/ / / ___/
|
||||||
|
| |/ |/ / /_/ / / (__ )
|
||||||
|
|__/|__/\__,_/_/_/____/
|
||||||
|
The lightweight framework for web-like apps
|
||||||
|
(c) Lea Anthony 2019-present
|
||||||
|
*/
|
||||||
|
/* jshint esversion: 6 */
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
function start(callback) {
|
||||||
|
|
||||||
|
// Set up the bridge
|
||||||
|
init();
|
||||||
|
|
||||||
|
// Save the callback
|
||||||
|
window.wailsbridge.callback = callback;
|
||||||
|
|
||||||
|
// Start Bridge
|
||||||
|
startBridge();
|
||||||
|
}
|
||||||
|
|
||||||
|
function Init(callback) {
|
||||||
|
start(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { Init };
|
18
runtime/assets/default.html
Normal file
18
runtime/assets/default.html
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script type="text/javascript">function AddScript(js, callbackID) {
|
||||||
|
var script = document.createElement('script');
|
||||||
|
script.text = js;
|
||||||
|
document.body.appendChild(script);
|
||||||
|
}</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
1
runtime/assets/wails.js
Normal file
1
runtime/assets/wails.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
!function(n){var t={};function e(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return n[r].call(o.exports,o,o.exports,e),o.l=!0,o.exports}e.m=n,e.c=t,e.d=function(n,t,r){e.o(n,t)||Object.defineProperty(n,t,{enumerable:!0,get:r})},e.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},e.t=function(n,t){if(1&t&&(n=e(n)),8&t)return n;if(4&t&&"object"==typeof n&&n&&n.__esModule)return n;var r=Object.create(null);if(e.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:n}),2&t&&"string"!=typeof n)for(var o in n)e.d(r,o,function(t){return n[t]}.bind(null,o));return r},e.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return e.d(t,"a",t),t},e.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},e.p="",e(e.s=0)}([function(n,t,e){"use strict";e.r(t);var r={};e.r(r),e.d(r,"Debug",function(){return c}),e.d(r,"Info",function(){return u}),e.d(r,"Warning",function(){return l}),e.d(r,"Error",function(){return f}),e.d(r,"Fatal",function(){return d});var o={};function a(n,t,e){var r={type:n,callbackID:e,payload:t};!function(n){window.external.invoke(n)}(JSON.stringify(r))}function i(n,t){a("log",{level:n,message:t})}function c(n){i("debug",n)}function u(n){i("info",n)}function l(n){i("warning",n)}function f(n){i("error",n)}function d(n){i("fatal",n)}e.r(o),e.d(o,"OpenURL",function(){return y}),e.d(o,"OpenFile",function(){return g});var s,p={};function v(n,t,e){return null!=e&&null!=e||(e=0),new Promise(function(r,o){var i;do{i=n+"-"+s()}while(p[i]);if(e>0)var c=setTimeout(function(){o(Error("Call to "+n+" timed out. Request ID: "+i))},e);p[i]={timeoutHandle:c,reject:o,resolve:r};try{a("call",{bindingName:n,data:JSON.stringify(t)},i)}catch(n){console.error(n)}})}function w(n,t){return v(".wails."+n,t)}function y(n){return w("Browser.OpenURL",n)}function g(n){return w("Browser.OpenFile",n)}s=window.crypto?function(){var n=new Uint32Array(1);return window.crypto.getRandomValues(n)[0]}:function(){return 9007199254740991*Math.random()};var m=function n(t,e){!function(n,t){if(!(n instanceof t))throw new TypeError("Cannot call a class as a function")}(this,n),e=e||-1,this.Callback=function(n){return t.apply(null,n),-1!==e&&0===(e-=1)}},b={};function h(n,t,e){b[n]=b[n]||[];var r=new m(t,e);b[n].push(r)}function O(n){a("event",{name:n,data:JSON.stringify([].slice.apply(arguments).slice(1))})}var S={};function j(n){try{return new Function("var "+n),!0}catch(n){return!1}}function k(){return(k=Object.assign||function(n){for(var t=1;t<arguments.length;t++){var e=arguments[t];for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(n[r]=e[r])}return n}).apply(this,arguments)}window.backend={},e.d(t,"Init",function(){return N}),window.wails=window.wails||{},window.backend={};var E={NewBinding:function(n){var t=[].concat(n.split(".").splice(1)),e=window.backend;if(t.length>1)for(var r=0;r<t.length-1;r+=1){var o=t[r];if(!j(o))return new Error("".concat(o," is not a valid javascript identifier."));e[o]={},e=e[o]}var a=t.pop();if(!j(a))return new Error("".concat(a," is not a valid javascript identifier."));e[a]=function(){var t=0;function e(){var e=[].slice.call(arguments);return v(n,e,t)}return e.setTimeout=function(n){t=n},e.getTimeout=function(){return t},e}()},Callback:function(n){var t;n=decodeURIComponent(n.replace(/\s+/g,"").replace(/[0-9a-f]{2}/g,"%$&"));try{t=JSON.parse(n)}catch(t){var e="Invalid JSON passed to callback: ".concat(t.message,". Message: ").concat(n);throw c(e),new Error(e)}var r=t.callbackid,o=p[r];if(!o){var a="Callback '".concat(r,"' not registed!!!");throw console.error(a),new Error(a)}clearTimeout(o.timeoutHandle),delete p[r],t.error?o.reject(t.error):o.resolve(t.data)},Notify:function(n,t){if(b[n]){for(var e=b[n].slice(),r=0;r<b[n].length;r+=1){var o=b[n][r],a=[];if(t)try{a=JSON.parse(t)}catch(t){f("Invalid JSON data sent to notify. Event name = "+n)}o.Callback(a)&&e.splice(r,1)}b[n]=e}},AddScript:function(n,t){var e=document.createElement("script");e.text=n,document.body.appendChild(e),t&&O(t)},InjectCSS:function(n){var t=document.createElement("style");t.setAttribute("type","text/css"),t.styleSheet?t.styleSheet.cssText=n:t.appendChild(document.createTextNode(n)),(document.head||document.getElementsByTagName("head")[0]).appendChild(t)},Init:N},C={Log:r,Browser:o,Events:{On:function(n,t){h(n,t)},Emit:O,Heartbeat:function(n,t,e){var r=null;S[n]=function(){clearInterval(r),e()},r=setInterval(function(){O(n)},t)},Acknowledge:function(n){if(!S[n])throw new f("Cannot acknowledge unknown heartbeat '".concat(n,"'"));S[n]()}},_:E};function N(n){n()}k(window.wails,C),O("wails:loaded")}]);
|
21
runtime/browser.go
Normal file
21
runtime/browser.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
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)
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user