mirror of
https://github.com/taigrr/wails.git
synced 2026-04-04 14:12:40 -07:00
Compare commits
7 Commits
v2.0.0-alp
...
feature/v2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
29715b2d57 | ||
|
|
d8ad250608 | ||
|
|
eac8880f6d | ||
|
|
f47100e71c | ||
|
|
9a81a57d13 | ||
|
|
354429bc28 | ||
|
|
99d4d9490c |
@@ -1,6 +1,7 @@
|
||||
package dev
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
@@ -10,14 +11,18 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/wailsapp/wails/v2/pkg/commands/build"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/process"
|
||||
|
||||
"github.com/wzshiming/ctc"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/fs"
|
||||
|
||||
"github.com/fsnotify/fsnotify"
|
||||
|
||||
"github.com/leaanthony/clir"
|
||||
"github.com/wailsapp/wails/v2/internal/fs"
|
||||
"github.com/wailsapp/wails/v2/internal/process"
|
||||
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
||||
"github.com/wailsapp/wails/v2/pkg/commands/build"
|
||||
)
|
||||
|
||||
// AddSubcommand adds the `dev` command for the Wails application
|
||||
@@ -44,212 +49,262 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||
app.PrintBanner()
|
||||
|
||||
// TODO: Check you are in a project directory
|
||||
|
||||
watcher, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer watcher.Close()
|
||||
|
||||
var debugBinaryProcess *process.Process = nil
|
||||
var buildFrontend bool = false
|
||||
var extensionsThatTriggerARebuild = strings.Split(extensions, ",")
|
||||
|
||||
// Setup signal handler
|
||||
quitChannel := make(chan os.Signal, 1)
|
||||
signal.Notify(quitChannel, os.Interrupt, os.Kill, syscall.SIGTERM)
|
||||
|
||||
debounceQuit := make(chan bool, 1)
|
||||
|
||||
// Do initial build
|
||||
logger.Println("Building application for development...")
|
||||
debugBinaryProcess, err = restartApp(logger, "dev", ldflags, compilerCommand, debugBinaryProcess)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
go debounce(100*time.Millisecond, watcher.Events, debounceQuit, func(event fsnotify.Event) {
|
||||
// logger.Println("event: %+v", event)
|
||||
|
||||
// Check for new directories
|
||||
if event.Op&fsnotify.Create == fsnotify.Create {
|
||||
// If this is a folder, add it to our watch list
|
||||
if fs.DirExists(event.Name) {
|
||||
if !strings.Contains(event.Name, "node_modules") {
|
||||
err := watcher.Add(event.Name)
|
||||
if err != nil {
|
||||
logger.Fatal("%s", err.Error())
|
||||
}
|
||||
logger.Println("Watching directory: %s", event.Name)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Check for file writes
|
||||
if event.Op&fsnotify.Write == fsnotify.Write {
|
||||
|
||||
logger.Println("modified file: %s", event.Name)
|
||||
var rebuild bool = false
|
||||
|
||||
// Iterate all file patterns
|
||||
for _, pattern := range extensionsThatTriggerARebuild {
|
||||
rebuild = strings.HasSuffix(event.Name, pattern)
|
||||
if err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
}
|
||||
if rebuild {
|
||||
// Only build frontend when the file isn't a Go file
|
||||
buildFrontend = !strings.HasSuffix(event.Name, "go")
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !rebuild {
|
||||
logger.Println("Filename change: %s did not match extension list (%s)", event.Name, extensions)
|
||||
return
|
||||
}
|
||||
|
||||
logger.Println("Partial build triggered: %s updated", event.Name)
|
||||
|
||||
// Do a rebuild
|
||||
|
||||
// Try and build the app
|
||||
newBinaryProcess, err := restartApp(logger, "dev", ldflags, compilerCommand, debugBinaryProcess)
|
||||
if err != nil {
|
||||
fmt.Printf("Error during build: %s", err.Error())
|
||||
return
|
||||
}
|
||||
// If we have a new process, save it
|
||||
if newBinaryProcess != nil {
|
||||
debugBinaryProcess = newBinaryProcess
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
// Get project dir
|
||||
dir, err := os.Getwd()
|
||||
reloader, err := NewReloader(logger, extensionsThatTriggerARebuild, ldflags, compilerCommand)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get all subdirectories
|
||||
dirs, err := fs.GetSubdirectories(dir)
|
||||
// Start
|
||||
err = reloader.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
println("ERRRRRRRRRR: %+v", err)
|
||||
}
|
||||
|
||||
// Setup a watcher for non-node_modules directories
|
||||
dirs.Each(func(dir string) {
|
||||
if strings.Contains(dir, "node_modules") {
|
||||
return
|
||||
}
|
||||
logger.Println("Watching directory: %s", dir)
|
||||
err = watcher.Add(dir)
|
||||
if err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
}
|
||||
})
|
||||
logger.Println("\nDevelopment mode exited")
|
||||
|
||||
// Wait until we get a quit signal
|
||||
quit := false
|
||||
for quit == false {
|
||||
select {
|
||||
case <-quitChannel:
|
||||
println("Caught quit")
|
||||
// Notify debouncer to quit
|
||||
debounceQuit <- true
|
||||
quit = true
|
||||
}
|
||||
}
|
||||
|
||||
// Kill the current program if running
|
||||
if debugBinaryProcess != nil {
|
||||
err := debugBinaryProcess.Kill()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
logger.Println("Development mode exited")
|
||||
|
||||
return nil
|
||||
return err
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Credit: https://drailing.net/2018/01/debounce-function-for-golang/
|
||||
func debounce(interval time.Duration, input chan fsnotify.Event, quitChannel chan bool, cb func(arg fsnotify.Event)) {
|
||||
var item fsnotify.Event
|
||||
timer := time.NewTimer(interval)
|
||||
exit:
|
||||
type Reloader struct {
|
||||
|
||||
// Main context
|
||||
ctx context.Context
|
||||
|
||||
// Signal context
|
||||
signalContext context.Context
|
||||
|
||||
// notify
|
||||
watcher *fsnotify.Watcher
|
||||
|
||||
// Logger
|
||||
logger *clilogger.CLILogger
|
||||
|
||||
// Extensions to listen for
|
||||
extensionsThatTriggerARebuild []string
|
||||
|
||||
// The binary we are running
|
||||
binary *process.Process
|
||||
|
||||
// options
|
||||
ldflags string
|
||||
compiler string
|
||||
}
|
||||
|
||||
func NewReloader(logger *clilogger.CLILogger, extensionsThatTriggerARebuild []string, ldFlags string, compiler string) (*Reloader, error) {
|
||||
var result Reloader
|
||||
|
||||
// Create context
|
||||
result.ctx = context.Background()
|
||||
|
||||
// Signal context (we don't need cancel)
|
||||
signalContext, _ := signal.NotifyContext(result.ctx, os.Interrupt, os.Kill, syscall.SIGTERM)
|
||||
result.signalContext = signalContext
|
||||
|
||||
// Create watcher
|
||||
watcher, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.watcher = watcher
|
||||
|
||||
// Logger
|
||||
result.logger = logger
|
||||
|
||||
// Extensions
|
||||
result.extensionsThatTriggerARebuild = extensionsThatTriggerARebuild
|
||||
|
||||
// Options
|
||||
result.ldflags = ldFlags
|
||||
result.compiler = compiler
|
||||
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func (r *Reloader) Start() error {
|
||||
|
||||
err := r.rebuildBinary()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get project dir
|
||||
dir, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get all subdirectories
|
||||
dirs, err := fs.GetSubdirectories(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Setup a watcher for non-node_modules directories
|
||||
r.logger.Println("Watching (sub)directories: %s", dir)
|
||||
|
||||
dirs.Each(func(dir string) {
|
||||
if strings.Contains(dir, "node_modules") {
|
||||
return
|
||||
}
|
||||
err = r.watcher.Add(dir)
|
||||
if err != nil {
|
||||
r.logger.Fatal(err.Error())
|
||||
}
|
||||
})
|
||||
|
||||
// Main loop
|
||||
for {
|
||||
select {
|
||||
case item = <-input:
|
||||
timer.Reset(interval)
|
||||
case <-timer.C:
|
||||
if item.Name != "" {
|
||||
cb(item)
|
||||
case <-r.signalContext.Done():
|
||||
if r.binary != nil {
|
||||
println("Binary is not nil - kill")
|
||||
return r.binary.Kill()
|
||||
}
|
||||
return nil
|
||||
case event := <-r.watcher.Events:
|
||||
err := r.processWatcherEvent(event)
|
||||
if err != nil {
|
||||
println("error from processWatcherEvent. Calling cancel()")
|
||||
println("Calling kill")
|
||||
return r.binary.Kill()
|
||||
}
|
||||
case <-quitChannel:
|
||||
break exit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func restartApp(logger *clilogger.CLILogger, outputType string, ldflags string, compilerCommand string, debugBinaryProcess *process.Process) (*process.Process, error) {
|
||||
func (r *Reloader) processWatcherEvent(event fsnotify.Event) error {
|
||||
|
||||
appBinary, err := buildApp(logger, outputType, ldflags, compilerCommand)
|
||||
println()
|
||||
if err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
return nil, errors.Wrap(err, "Build Failed:")
|
||||
// Check for new directories
|
||||
if event.Op&fsnotify.Create == fsnotify.Create {
|
||||
// If this is a folder, add it to our watch list
|
||||
if fs.DirExists(event.Name) {
|
||||
if !strings.Contains(event.Name, "node_modules") {
|
||||
err := r.watcher.Add(event.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.logger.Println("Watching directory: %s", event.Name)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
logger.Println("Build new binary: %s", appBinary)
|
||||
|
||||
// Kill existing binary if need be
|
||||
if debugBinaryProcess != nil {
|
||||
killError := debugBinaryProcess.Kill()
|
||||
// Check for file writes
|
||||
if event.Op&fsnotify.Write == fsnotify.Write {
|
||||
|
||||
if killError != nil {
|
||||
logger.Fatal("Unable to kill debug binary (PID: %d)!", debugBinaryProcess.PID())
|
||||
var rebuild bool
|
||||
|
||||
// Iterate all file patterns
|
||||
for _, pattern := range r.extensionsThatTriggerARebuild {
|
||||
if strings.HasSuffix(event.Name, pattern) {
|
||||
rebuild = true
|
||||
}
|
||||
}
|
||||
|
||||
debugBinaryProcess = nil
|
||||
if !rebuild {
|
||||
return nil
|
||||
}
|
||||
|
||||
r.logger.Println("\n%s[Build triggered] %s %s", ctc.ForegroundGreen|ctc.ForegroundBright, event.Name, ctc.Reset)
|
||||
|
||||
return r.rebuildBinary()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Reloader) rebuildBinary() error {
|
||||
|
||||
// rebuild binary
|
||||
binary, err := r.buildApp()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: Generate `backend.js`
|
||||
// Kill current binary if running
|
||||
if r.binary != nil {
|
||||
err = r.binary.Kill()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Start up new binary
|
||||
newProcess := process.NewProcess(logger, appBinary)
|
||||
newProcess := process.NewProcess(r.ctx, r.logger, binary)
|
||||
err = newProcess.Start()
|
||||
if err != nil {
|
||||
// Remove binary
|
||||
deleteError := fs.DeleteFile(appBinary)
|
||||
if deleteError != nil {
|
||||
logger.Fatal("Unable to delete app binary: " + appBinary)
|
||||
}
|
||||
logger.Fatal("Unable to start application: %s", err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
return newProcess, nil
|
||||
// Ensure process runs correctly
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildApp(logger *clilogger.CLILogger, outputType string, ldflags string, compilerCommand string) (string, error) {
|
||||
//func restartApp(logger *clilogger.CLILogger, outputType string, ldflags string, compilerCommand string, debugBinaryProcess *process.Process) (*process.Process, error) {
|
||||
//
|
||||
// appBinary, err := buildApp(logger, outputType, ldflags, compilerCommand)
|
||||
// println()
|
||||
// if err != nil {
|
||||
// logger.Fatal(err.Error())
|
||||
// return nil, errors.Wrap(err, "Build Failed:")
|
||||
// }
|
||||
// logger.Println("Build new binary: %s", appBinary)
|
||||
//
|
||||
// // Kill existing binary if need be
|
||||
// if debugBinaryProcess != nil {
|
||||
// killError := debugBinaryProcess.Kill()
|
||||
//
|
||||
// if killError != nil {
|
||||
// logger.Fatal("Unable to kill debug binary (PID: %d)!", debugBinaryProcess.PID())
|
||||
// }
|
||||
//
|
||||
// debugBinaryProcess = nil
|
||||
// }
|
||||
//
|
||||
// // TODO: Generate `backend.js`
|
||||
//
|
||||
// // Start up new binary
|
||||
// newProcess := process.NewProcess(logger, appBinary)
|
||||
// err = newProcess.Start()
|
||||
// if err != nil {
|
||||
// // Remove binary
|
||||
// deleteError := fs.DeleteFile(appBinary)
|
||||
// if deleteError != nil {
|
||||
// logger.Fatal("Unable to delete app binary: " + appBinary)
|
||||
// }
|
||||
// logger.Fatal("Unable to start application: %s", err.Error())
|
||||
// }
|
||||
//
|
||||
// // Check if port is open
|
||||
// timeout := time.Second
|
||||
// conn, err := net.DialTimeout("tcp", net.JoinHostPort("host", port), timeout)
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
// newProcess.Running
|
||||
// return newProcess, nil
|
||||
//}
|
||||
|
||||
// buildapp attempts to compile the application
|
||||
// It returns the path to the new binary or an error
|
||||
func (r *Reloader) buildApp() (string, error) {
|
||||
|
||||
// Create random output file
|
||||
outputFile := fmt.Sprintf("debug-%d", time.Now().Unix())
|
||||
|
||||
// Create BuildOptions
|
||||
buildOptions := &build.Options{
|
||||
Logger: logger,
|
||||
OutputType: outputType,
|
||||
Logger: r.logger,
|
||||
OutputType: "dev",
|
||||
Mode: build.Debug,
|
||||
Pack: false,
|
||||
Platform: runtime.GOOS,
|
||||
LDFlags: ldflags,
|
||||
Compiler: compilerCommand,
|
||||
LDFlags: r.ldflags,
|
||||
Compiler: r.compiler,
|
||||
OutputFile: outputFile,
|
||||
IgnoreFrontend: true,
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/wzshiming/ctc"
|
||||
|
||||
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/update"
|
||||
|
||||
"github.com/leaanthony/clir"
|
||||
@@ -19,12 +22,30 @@ func fatal(message string) {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func col(colour ctc.Color, text string) string {
|
||||
return fmt.Sprintf("%s%s%s", colour, text, ctc.Reset)
|
||||
}
|
||||
|
||||
func Yellow(str string) string {
|
||||
return col(ctc.ForegroundBrightYellow, str)
|
||||
}
|
||||
|
||||
func Red(str string) string {
|
||||
return col(ctc.ForegroundBrightRed, str)
|
||||
}
|
||||
|
||||
func banner(cli *clir.Cli) string {
|
||||
return fmt.Sprintf("%s %s - Go/HTML Application Framework", Yellow("Wails"), Red(version))
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
var err error
|
||||
|
||||
app := clir.NewCli("Wails", "Go/HTML Application Framework", version)
|
||||
|
||||
app.SetBannerFunction(banner)
|
||||
|
||||
build.AddBuildSubcommand(app, os.Stdout)
|
||||
err = initialise.AddSubcommand(app, os.Stdout)
|
||||
if err != nil {
|
||||
|
||||
@@ -20,6 +20,7 @@ require (
|
||||
github.com/tdewolff/minify v2.3.6+incompatible
|
||||
github.com/tdewolff/parse v2.3.4+incompatible // indirect
|
||||
github.com/tdewolff/test v1.0.6 // indirect
|
||||
github.com/wzshiming/ctc v1.2.3 // indirect
|
||||
github.com/xyproto/xpm v1.2.1
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a
|
||||
|
||||
@@ -78,6 +78,10 @@ github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
github.com/wzshiming/ctc v1.2.3 h1:q+hW3IQNsjIlOFBTGZZZeIXTElFM4grF4spW/errh/c=
|
||||
github.com/wzshiming/ctc v1.2.3/go.mod h1:2tVAtIY7SUyraSk0JxvwmONNPFL4ARavPuEsg5+KA28=
|
||||
github.com/wzshiming/winseq v0.0.0-20200112104235-db357dc107ae h1:tpXvBXC3hpQBDCc9OojJZCQMVRAbT3TTdUMP8WguXkY=
|
||||
github.com/wzshiming/winseq v0.0.0-20200112104235-db357dc107ae/go.mod h1:VTAq37rkGeV+WOybvZwjXiJOicICdpLCN8ifpISjK20=
|
||||
github.com/xyproto/xpm v1.2.1 h1:trdvGjjWBsOOKzBBUPT6JvaIQM3acJEEYfbxN7M96wg=
|
||||
github.com/xyproto/xpm v1.2.1/go.mod h1:cMnesLsD0PBXLgjDfTDEaKr8XyTFsnP1QycSqRw7BiY=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
@@ -97,6 +101,7 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/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-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c h1:UIcGWL6/wpCfyGuJnRFJRurA+yj8RrW7Q6x2YMCXt6c=
|
||||
|
||||
@@ -4,8 +4,9 @@ package app
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"github.com/wailsapp/wails/v2/pkg/logger"
|
||||
"strings"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/logger"
|
||||
)
|
||||
|
||||
// Init initialises the application for a debug environment
|
||||
|
||||
@@ -212,7 +212,7 @@ func (a *App) Run() error {
|
||||
// Generate backend.js
|
||||
a.bindings.GenerateBackendJS()
|
||||
|
||||
err = a.bridge.Run(dispatcher, bindingDump, a.debug)
|
||||
err = a.bridge.Run(dispatcher, a.menuManager, bindingDump, a.debug)
|
||||
a.logger.Trace("Bridge.Run() exited")
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -53,13 +53,33 @@ func (b *Bindings) GenerateBackendJS() {
|
||||
const backend = {`)
|
||||
output.WriteString("\n")
|
||||
|
||||
for packageName, packages := range store {
|
||||
var sortedPackageNames slicer.StringSlicer
|
||||
for packageName := range store {
|
||||
sortedPackageNames.Add(packageName)
|
||||
}
|
||||
sortedPackageNames.Sort()
|
||||
for _, packageName := range sortedPackageNames.AsSlice() {
|
||||
packages := store[packageName]
|
||||
output.WriteString(fmt.Sprintf(" \"%s\": {", packageName))
|
||||
output.WriteString("\n")
|
||||
for structName, structs := range packages {
|
||||
var sortedStructNames slicer.StringSlicer
|
||||
for structName := range packages {
|
||||
sortedStructNames.Add(structName)
|
||||
}
|
||||
sortedStructNames.Sort()
|
||||
for _, structName := range sortedStructNames.AsSlice() {
|
||||
structs := packages[structName]
|
||||
output.WriteString(fmt.Sprintf(" \"%s\": {", structName))
|
||||
output.WriteString("\n")
|
||||
for methodName, methodDetails := range structs {
|
||||
|
||||
var sortedMethodNames slicer.StringSlicer
|
||||
for methodName := range structs {
|
||||
sortedMethodNames.Add(methodName)
|
||||
}
|
||||
sortedMethodNames.Sort()
|
||||
|
||||
for _, methodName := range sortedMethodNames.AsSlice() {
|
||||
methodDetails := structs[methodName]
|
||||
output.WriteString(" /**\n")
|
||||
output.WriteString(" * " + methodName + "\n")
|
||||
var args slicer.StringSlicer
|
||||
|
||||
@@ -6,6 +6,8 @@ import (
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/menumanager"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/messagedispatcher"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
@@ -25,6 +27,12 @@ type Bridge struct {
|
||||
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
|
||||
// Dialog client
|
||||
dialog *messagedispatcher.DispatchClient
|
||||
|
||||
// Menus
|
||||
menumanager *menumanager.Manager
|
||||
}
|
||||
|
||||
func NewBridge(myLogger *logger.Logger) *Bridge {
|
||||
@@ -44,13 +52,19 @@ func NewBridge(myLogger *logger.Logger) *Bridge {
|
||||
return result
|
||||
}
|
||||
|
||||
func (b *Bridge) Run(dispatcher *messagedispatcher.Dispatcher, bindings string, debug bool) error {
|
||||
func (b *Bridge) Run(dispatcher *messagedispatcher.Dispatcher, menumanager *menumanager.Manager, bindings string, debug bool) error {
|
||||
|
||||
// Ensure we cancel the context when we shutdown
|
||||
defer b.cancel()
|
||||
|
||||
b.bindings = bindings
|
||||
b.dispatcher = dispatcher
|
||||
b.menumanager = menumanager
|
||||
|
||||
// Setup dialog handler
|
||||
dialogClient := NewDialogClient(b.myLogger)
|
||||
b.dialog = dispatcher.RegisterClient(dialogClient)
|
||||
dialogClient.dispatcher = b.dialog
|
||||
|
||||
b.myLogger.Info("Bridge mode started.")
|
||||
|
||||
@@ -80,7 +94,7 @@ func (b *Bridge) wsBridgeHandler(w http.ResponseWriter, r *http.Request) {
|
||||
func (b *Bridge) startSession(conn *websocket.Conn) {
|
||||
|
||||
// Create a new session for this connection
|
||||
s := newSession(conn, b.bindings, b.dispatcher, b.myLogger, b.ctx)
|
||||
s := newSession(conn, b.menumanager, b.bindings, b.dispatcher, b.myLogger, b.ctx)
|
||||
|
||||
// Setup the close handler
|
||||
conn.SetCloseHandler(func(int, string) error {
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/leaanthony/slicer"
|
||||
"github.com/wailsapp/wails/v2/pkg/options/dialog"
|
||||
"golang.org/x/sync/semaphore"
|
||||
)
|
||||
|
||||
type BridgeClient struct {
|
||||
session *session
|
||||
dialogSemaphore *semaphore.Weighted
|
||||
session *session
|
||||
|
||||
// Tray menu cache to send to reconnecting clients
|
||||
messageCache chan string
|
||||
}
|
||||
|
||||
func NewBridgeClient() *BridgeClient {
|
||||
return &BridgeClient{
|
||||
messageCache: make(chan string, 100),
|
||||
}
|
||||
}
|
||||
|
||||
func (b BridgeClient) Quit() {
|
||||
@@ -31,44 +32,15 @@ func (b BridgeClient) CallResult(message string) {
|
||||
}
|
||||
|
||||
func (b BridgeClient) OpenDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
|
||||
b.session.log.Info("OpenDialog unsupported in Bridge mode")
|
||||
// Handled by dialog_client
|
||||
}
|
||||
|
||||
func (b BridgeClient) SaveDialog(dialogOptions *dialog.SaveDialog, callbackID string) {
|
||||
b.session.log.Info("SaveDialog unsupported in Bridge mode")
|
||||
// Handled by dialog_client
|
||||
}
|
||||
|
||||
func (b BridgeClient) MessageDialog(dialogOptions *dialog.MessageDialog, callbackID string) {
|
||||
|
||||
osa, err := exec.LookPath("osascript")
|
||||
if err != nil {
|
||||
b.session.log.Info("MessageDialog unavailable (osascript not found)")
|
||||
return
|
||||
}
|
||||
|
||||
var btns slicer.StringSlicer
|
||||
defaultButton := ""
|
||||
for index, btn := range dialogOptions.Buttons {
|
||||
btns.Add(strconv.Quote(btn))
|
||||
if btn == dialogOptions.DefaultButton {
|
||||
defaultButton = fmt.Sprintf("default button %d", index+1)
|
||||
}
|
||||
}
|
||||
buttons := "{" + btns.Join(",") + "}"
|
||||
script := fmt.Sprintf("display dialog \"%s\" buttons %s %s with title \"%s\"", dialogOptions.Message, buttons, defaultButton, dialogOptions.Title)
|
||||
|
||||
b.session.log.Info("OSASCRIPT: %s", script)
|
||||
go func() {
|
||||
out, err := exec.Command(osa, "-e", script).Output()
|
||||
if err != nil {
|
||||
b.session.log.Error(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
b.session.log.Info(string(out))
|
||||
buttonPressed := strings.TrimSpace(strings.TrimPrefix(string(out), "button returned:"))
|
||||
b.session.client.DispatchMessage("DM" + callbackID + "|" + buttonPressed)
|
||||
}()
|
||||
// Handled by dialog_client
|
||||
}
|
||||
|
||||
func (b BridgeClient) WindowSetTitle(title string) {
|
||||
@@ -144,7 +116,7 @@ func (b BridgeClient) SetTrayMenu(trayMenuJSON string) {
|
||||
}
|
||||
|
||||
func (b BridgeClient) UpdateTrayMenuLabel(trayMenuJSON string) {
|
||||
b.session.sendMessage("TS" + trayMenuJSON)
|
||||
b.session.sendMessage("TU" + trayMenuJSON)
|
||||
}
|
||||
|
||||
func (b BridgeClient) UpdateContextMenu(contextMenuJSON string) {
|
||||
|
||||
141
v2/internal/bridge/dialog_client.go
Normal file
141
v2/internal/bridge/dialog_client.go
Normal file
@@ -0,0 +1,141 @@
|
||||
package bridge
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/messagedispatcher"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
|
||||
"github.com/leaanthony/slicer"
|
||||
"github.com/wailsapp/wails/v2/pkg/options/dialog"
|
||||
)
|
||||
|
||||
type DialogClient struct {
|
||||
dispatcher *messagedispatcher.DispatchClient
|
||||
log *logger.Logger
|
||||
}
|
||||
|
||||
func NewDialogClient(log *logger.Logger) *DialogClient {
|
||||
return &DialogClient{
|
||||
log: log,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DialogClient) Quit() {
|
||||
}
|
||||
|
||||
func (d *DialogClient) NotifyEvent(message string) {
|
||||
}
|
||||
|
||||
func (d *DialogClient) CallResult(message string) {
|
||||
}
|
||||
|
||||
func (d *DialogClient) OpenDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
|
||||
}
|
||||
|
||||
func (d *DialogClient) SaveDialog(dialogOptions *dialog.SaveDialog, callbackID string) {
|
||||
}
|
||||
|
||||
func (d *DialogClient) MessageDialog(dialogOptions *dialog.MessageDialog, callbackID string) {
|
||||
|
||||
osa, err := exec.LookPath("osascript")
|
||||
if err != nil {
|
||||
d.log.Info("MessageDialog unavailable (osascript not found)")
|
||||
return
|
||||
}
|
||||
|
||||
var btns slicer.StringSlicer
|
||||
defaultButton := ""
|
||||
cancelButton := ""
|
||||
for index, btn := range dialogOptions.Buttons {
|
||||
btns.Add(strconv.Quote(btn))
|
||||
if btn == dialogOptions.DefaultButton {
|
||||
defaultButton = fmt.Sprintf("default button %d", index+1)
|
||||
}
|
||||
if btn == dialogOptions.CancelButton {
|
||||
cancelButton = fmt.Sprintf("cancel button %d", index+1)
|
||||
}
|
||||
}
|
||||
buttons := "{" + btns.Join(",") + "}"
|
||||
script := fmt.Sprintf("display dialog \"%s\" buttons %s %s %s with title \"%s\"", dialogOptions.Message, buttons, defaultButton, cancelButton, dialogOptions.Title)
|
||||
go func() {
|
||||
out, err := exec.Command(osa, "-e", script).Output()
|
||||
if err != nil {
|
||||
// Assume user has pressed cancel button
|
||||
if dialogOptions.CancelButton != "" {
|
||||
d.dispatcher.DispatchMessage("DM" + callbackID + "|" + dialogOptions.CancelButton)
|
||||
return
|
||||
}
|
||||
d.log.Error("Dialog had bad exit code. If this was a Cancel button, add 'CancelButton' to the dialog.MessageDialog struct. Error: %s", err.Error())
|
||||
d.dispatcher.DispatchMessage("DM" + callbackID + "|error - check logs")
|
||||
return
|
||||
}
|
||||
|
||||
buttonPressed := strings.TrimSpace(strings.TrimPrefix(string(out), "button returned:"))
|
||||
d.dispatcher.DispatchMessage("DM" + callbackID + "|" + buttonPressed)
|
||||
}()
|
||||
}
|
||||
|
||||
func (d *DialogClient) WindowSetTitle(title string) {
|
||||
}
|
||||
|
||||
func (d *DialogClient) WindowShow() {
|
||||
}
|
||||
|
||||
func (d *DialogClient) WindowHide() {
|
||||
}
|
||||
|
||||
func (d *DialogClient) WindowCenter() {
|
||||
}
|
||||
|
||||
func (d *DialogClient) WindowMaximise() {
|
||||
}
|
||||
|
||||
func (d *DialogClient) WindowUnmaximise() {
|
||||
}
|
||||
|
||||
func (d *DialogClient) WindowMinimise() {
|
||||
}
|
||||
|
||||
func (d *DialogClient) WindowUnminimise() {
|
||||
}
|
||||
|
||||
func (d *DialogClient) WindowPosition(x int, y int) {
|
||||
}
|
||||
|
||||
func (d *DialogClient) WindowSize(width int, height int) {
|
||||
}
|
||||
|
||||
func (d *DialogClient) WindowSetMinSize(width int, height int) {
|
||||
}
|
||||
|
||||
func (d *DialogClient) WindowSetMaxSize(width int, height int) {
|
||||
}
|
||||
|
||||
func (d *DialogClient) WindowFullscreen() {
|
||||
}
|
||||
|
||||
func (d *DialogClient) WindowUnFullscreen() {
|
||||
}
|
||||
|
||||
func (d *DialogClient) WindowSetColour(colour int) {
|
||||
}
|
||||
|
||||
func (d *DialogClient) DarkModeEnabled(callbackID string) {
|
||||
}
|
||||
|
||||
func (d *DialogClient) SetApplicationMenu(menuJSON string) {
|
||||
}
|
||||
|
||||
func (d *DialogClient) SetTrayMenu(trayMenuJSON string) {
|
||||
}
|
||||
|
||||
func (d *DialogClient) UpdateTrayMenuLabel(trayMenuJSON string) {
|
||||
}
|
||||
|
||||
func (d *DialogClient) UpdateContextMenu(contextMenuJSON string) {
|
||||
}
|
||||
@@ -7,6 +7,8 @@ import (
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/menumanager"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/messagedispatcher"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
@@ -35,16 +37,20 @@ type session struct {
|
||||
|
||||
// client
|
||||
client *messagedispatcher.DispatchClient
|
||||
|
||||
// Menus
|
||||
menumanager *menumanager.Manager
|
||||
}
|
||||
|
||||
func newSession(conn *websocket.Conn, bindings string, dispatcher *messagedispatcher.Dispatcher, logger *logger.Logger, ctx context.Context) *session {
|
||||
func newSession(conn *websocket.Conn, menumanager *menumanager.Manager, bindings string, dispatcher *messagedispatcher.Dispatcher, logger *logger.Logger, ctx context.Context) *session {
|
||||
result := &session{
|
||||
conn: conn,
|
||||
bindings: bindings,
|
||||
log: logger,
|
||||
shutdown: make(chan bool),
|
||||
writeChan: make(chan []byte, 100),
|
||||
ctx: ctx,
|
||||
conn: conn,
|
||||
bindings: bindings,
|
||||
log: logger,
|
||||
shutdown: make(chan bool),
|
||||
writeChan: make(chan []byte, 100),
|
||||
ctx: ctx,
|
||||
menumanager: menumanager,
|
||||
}
|
||||
|
||||
result.client = dispatcher.RegisterClient(newBridgeClient(result))
|
||||
@@ -88,6 +94,16 @@ func (s *session) start(firstSession bool) {
|
||||
|
||||
s.sendMessage("b" + bootstrapMessage)
|
||||
|
||||
// Send menus
|
||||
traymenus, err := s.menumanager.GetTrayMenus()
|
||||
if err != nil {
|
||||
s.log.Error(err.Error())
|
||||
}
|
||||
|
||||
for _, trayMenu := range traymenus {
|
||||
s.sendMessage("TS" + trayMenu)
|
||||
}
|
||||
|
||||
for {
|
||||
messageType, buffer, err := s.conn.ReadMessage()
|
||||
if messageType == -1 {
|
||||
|
||||
@@ -575,7 +575,7 @@ id processCheckboxMenuItem(Menu *menu, id parentmenu, const char *title, const c
|
||||
return item;
|
||||
}
|
||||
|
||||
id processTextMenuItem(Menu *menu, id parentMenu, const char *title, const char *menuid, bool disabled, const char *acceleratorkey, const char **modifiers, const char* tooltip, const char* image, const char* fontName, int fontSize, const char* RGBA) {
|
||||
id processTextMenuItem(Menu *menu, id parentMenu, const char *title, const char *menuid, bool disabled, const char *acceleratorkey, const char **modifiers, const char* tooltip, const char* image, const char* fontName, int fontSize, const char* RGBA, bool templateImage) {
|
||||
id item = ALLOC("NSMenuItem");
|
||||
|
||||
// Create a MenuItemCallbackData
|
||||
@@ -598,6 +598,9 @@ id processTextMenuItem(Menu *menu, id parentMenu, const char *title, const char
|
||||
id imageData = msg(data, s("initWithBase64EncodedString:options:"), str(image), 0);
|
||||
id nsimage = ALLOC("NSImage");
|
||||
msg(nsimage, s("initWithData:"), imageData);
|
||||
if( templateImage ) {
|
||||
msg(nsimage, s("template"), YES);
|
||||
}
|
||||
msg(item, s("setImage:"), nsimage);
|
||||
}
|
||||
|
||||
@@ -740,6 +743,9 @@ void processMenuItem(Menu *menu, id parentMenu, JsonNode *item) {
|
||||
const char *image = getJSONString(item, "Image");
|
||||
const char *fontName = getJSONString(item, "FontName");
|
||||
const char *RGBA = getJSONString(item, "RGBA");
|
||||
bool templateImage = false;
|
||||
getJSONBool(item, "MacTemplateImage", &templateImage);
|
||||
|
||||
int fontSize = 12;
|
||||
getJSONInt(item, "FontSize", &fontSize);
|
||||
|
||||
@@ -775,7 +781,7 @@ void processMenuItem(Menu *menu, id parentMenu, JsonNode *item) {
|
||||
if( type != NULL ) {
|
||||
|
||||
if( STREQ(type->string_, "Text")) {
|
||||
processTextMenuItem(menu, parentMenu, label, menuid, disabled, acceleratorkey, modifiers, tooltip, image, fontName, fontSize, RGBA);
|
||||
processTextMenuItem(menu, parentMenu, label, menuid, disabled, acceleratorkey, modifiers, tooltip, image, fontName, fontSize, RGBA, templateImage);
|
||||
}
|
||||
else if ( STREQ(type->string_, "Separator")) {
|
||||
addSeparator(parentMenu);
|
||||
|
||||
@@ -105,7 +105,7 @@ id processRadioMenuItem(Menu *menu, id parentmenu, const char *title, const char
|
||||
|
||||
id processCheckboxMenuItem(Menu *menu, id parentmenu, const char *title, const char *menuid, bool disabled, bool checked, const char *key);
|
||||
|
||||
id processTextMenuItem(Menu *menu, id parentMenu, const char *title, const char *menuid, bool disabled, const char *acceleratorkey, const char **modifiers, const char* tooltip, const char* image, const char* fontName, int fontSize, const char* RGBA);
|
||||
id processTextMenuItem(Menu *menu, id parentMenu, const char *title, const char *menuid, bool disabled, const char *acceleratorkey, const char **modifiers, const char* tooltip, const char* image, const char* fontName, int fontSize, const char* RGBA, bool templateImage);
|
||||
void processMenuItem(Menu *menu, id parentMenu, JsonNode *item);
|
||||
void processMenuData(Menu *menu, JsonNode *menuData);
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package menumanager
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
"github.com/wailsapp/wails/v2/pkg/menu/keys"
|
||||
)
|
||||
@@ -34,7 +35,8 @@ type ProcessedMenuItem struct {
|
||||
FontName string `json:",omitempty"`
|
||||
|
||||
// Image - base64 image data
|
||||
Image string `json:",omitempty"`
|
||||
Image string `json:",omitempty"`
|
||||
MacTemplateImage bool `json:", omitempty"`
|
||||
|
||||
// Tooltip
|
||||
Tooltip string `json:",omitempty"`
|
||||
@@ -44,20 +46,21 @@ func NewProcessedMenuItem(menuItemMap *MenuItemMap, menuItem *menu.MenuItem) *Pr
|
||||
|
||||
ID := menuItemMap.menuItemToIDMap[menuItem]
|
||||
result := &ProcessedMenuItem{
|
||||
ID: ID,
|
||||
Label: menuItem.Label,
|
||||
Role: menuItem.Role,
|
||||
Accelerator: menuItem.Accelerator,
|
||||
Type: menuItem.Type,
|
||||
Disabled: menuItem.Disabled,
|
||||
Hidden: menuItem.Hidden,
|
||||
Checked: menuItem.Checked,
|
||||
SubMenu: nil,
|
||||
RGBA: menuItem.RGBA,
|
||||
FontSize: menuItem.FontSize,
|
||||
FontName: menuItem.FontName,
|
||||
Image: menuItem.Image,
|
||||
Tooltip: menuItem.Tooltip,
|
||||
ID: ID,
|
||||
Label: menuItem.Label,
|
||||
Role: menuItem.Role,
|
||||
Accelerator: menuItem.Accelerator,
|
||||
Type: menuItem.Type,
|
||||
Disabled: menuItem.Disabled,
|
||||
Hidden: menuItem.Hidden,
|
||||
Checked: menuItem.Checked,
|
||||
SubMenu: nil,
|
||||
RGBA: menuItem.RGBA,
|
||||
FontSize: menuItem.FontSize,
|
||||
FontName: menuItem.FontName,
|
||||
Image: menuItem.Image,
|
||||
MacTemplateImage: menuItem.MacTemplateImage,
|
||||
Tooltip: menuItem.Tooltip,
|
||||
}
|
||||
|
||||
if menuItem.SubMenu != nil {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package process
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
@@ -9,18 +10,16 @@ import (
|
||||
|
||||
// Process defines a process that can be executed
|
||||
type Process struct {
|
||||
logger *clilogger.CLILogger
|
||||
cmd *exec.Cmd
|
||||
exitChannel chan bool
|
||||
Running bool
|
||||
logger *clilogger.CLILogger
|
||||
cmd *exec.Cmd
|
||||
running bool
|
||||
}
|
||||
|
||||
// NewProcess creates a new process struct
|
||||
func NewProcess(logger *clilogger.CLILogger, cmd string, args ...string) *Process {
|
||||
func NewProcess(ctx context.Context, logger *clilogger.CLILogger, cmd string, args ...string) *Process {
|
||||
result := &Process{
|
||||
logger: logger,
|
||||
cmd: exec.Command(cmd, args...),
|
||||
exitChannel: make(chan bool, 1),
|
||||
logger: logger,
|
||||
cmd: exec.CommandContext(ctx, cmd, args...),
|
||||
}
|
||||
result.cmd.Stdout = os.Stdout
|
||||
result.cmd.Stderr = os.Stderr
|
||||
@@ -35,30 +34,30 @@ func (p *Process) Start() error {
|
||||
return err
|
||||
}
|
||||
|
||||
p.Running = true
|
||||
p.running = true
|
||||
|
||||
go func(cmd *exec.Cmd, running *bool, logger *clilogger.CLILogger, exitChannel chan bool) {
|
||||
logger.Println("Starting process (PID: %d)", cmd.Process.Pid)
|
||||
cmd.Wait()
|
||||
logger.Println("Exiting process (PID: %d)", cmd.Process.Pid)
|
||||
*running = false
|
||||
exitChannel <- true
|
||||
}(p.cmd, &p.Running, p.logger, p.exitChannel)
|
||||
go func(p *Process) {
|
||||
p.logger.Println("Starting process (PID: %d)", p.cmd.Process.Pid)
|
||||
err := p.cmd.Wait()
|
||||
if err != nil {
|
||||
p.running = false
|
||||
p.logger.Println("Process failed to run: %s", err.Error())
|
||||
return
|
||||
}
|
||||
p.logger.Println("Exiting process (PID: %d)", p.cmd.Process.Pid)
|
||||
}(p)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Kill the process
|
||||
func (p *Process) Kill() error {
|
||||
if !p.Running {
|
||||
return nil
|
||||
if p.running {
|
||||
println("Calling kill")
|
||||
p.running = false
|
||||
return p.cmd.Process.Kill()
|
||||
}
|
||||
err := p.cmd.Process.Kill()
|
||||
|
||||
// Wait for command to exit properly
|
||||
<-p.exitChannel
|
||||
|
||||
return err
|
||||
return nil
|
||||
}
|
||||
|
||||
// PID returns the process PID
|
||||
|
||||
@@ -34,6 +34,9 @@
|
||||
function component_subscribe(component, store, callback) {
|
||||
component.$$.on_destroy.push(subscribe(store, callback));
|
||||
}
|
||||
function action_destroyer(action_result) {
|
||||
return action_result && is_function(action_result.destroy) ? action_result.destroy : noop;
|
||||
}
|
||||
|
||||
const is_client = typeof window !== 'undefined';
|
||||
let now = is_client
|
||||
@@ -91,9 +94,16 @@
|
||||
function text(data) {
|
||||
return document.createTextNode(data);
|
||||
}
|
||||
function space() {
|
||||
return text(' ');
|
||||
}
|
||||
function empty() {
|
||||
return text('');
|
||||
}
|
||||
function listen(node, event, handler, options) {
|
||||
node.addEventListener(event, handler, options);
|
||||
return () => node.removeEventListener(event, handler, options);
|
||||
}
|
||||
function attr(node, attribute, value) {
|
||||
if (value == null)
|
||||
node.removeAttribute(attribute);
|
||||
@@ -179,6 +189,14 @@
|
||||
function set_current_component(component) {
|
||||
current_component = component;
|
||||
}
|
||||
function get_current_component() {
|
||||
if (!current_component)
|
||||
throw new Error('Function called outside component initialization');
|
||||
return current_component;
|
||||
}
|
||||
function onMount(fn) {
|
||||
get_current_component().$$.on_mount.push(fn);
|
||||
}
|
||||
|
||||
const dirty_components = [];
|
||||
const binding_callbacks = [];
|
||||
@@ -400,6 +418,12 @@
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const globals = (typeof window !== 'undefined'
|
||||
? window
|
||||
: typeof globalThis !== 'undefined'
|
||||
? globalThis
|
||||
: global);
|
||||
function create_component(block) {
|
||||
block && block.c();
|
||||
}
|
||||
@@ -576,6 +600,15 @@
|
||||
return { set, update, subscribe };
|
||||
}
|
||||
|
||||
function log(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'
|
||||
);
|
||||
}
|
||||
|
||||
/** Overlay */
|
||||
const overlayVisible = writable(false);
|
||||
|
||||
@@ -604,6 +637,19 @@
|
||||
return current;
|
||||
});
|
||||
}
|
||||
function updateTrayLabel(tray) {
|
||||
trays.update((current) => {
|
||||
// Remove existing if it exists, else add
|
||||
const index = current.findIndex(item => item.ID === tray.ID);
|
||||
if ( index === -1 ) {
|
||||
return log("ERROR: Attempted to update tray index ", tray.ID)
|
||||
}
|
||||
current[index].Label = tray.Label;
|
||||
return current;
|
||||
});
|
||||
}
|
||||
|
||||
let selectedMenu = writable(null);
|
||||
|
||||
function fade(node, { delay = 0, duration = 400, easing = identity } = {}) {
|
||||
const o = +getComputedStyle(node).opacity;
|
||||
@@ -729,91 +775,557 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* TrayMenu.svelte generated by Svelte v3.32.2 */
|
||||
/* Menu.svelte generated by Svelte v3.32.2 */
|
||||
|
||||
function add_css$1() {
|
||||
var style = element("style");
|
||||
style.id = "svelte-1vq8f40-style";
|
||||
style.textContent = ".tray-menu.svelte-1vq8f40{padding-left:0.5rem;padding-right:0.5rem;overflow:visible;font-size:14px}";
|
||||
append(document.head, style);
|
||||
}
|
||||
|
||||
function create_fragment$1(ctx) {
|
||||
let span1;
|
||||
let span0;
|
||||
let t_value = /*tray*/ ctx[0].Label + "";
|
||||
let t;
|
||||
|
||||
return {
|
||||
c() {
|
||||
span1 = element("span");
|
||||
span0 = element("span");
|
||||
t = text(t_value);
|
||||
attr(span0, "class", "label");
|
||||
attr(span1, "class", "tray-menu svelte-1vq8f40");
|
||||
},
|
||||
m(target, anchor) {
|
||||
insert(target, span1, anchor);
|
||||
append(span1, span0);
|
||||
append(span0, t);
|
||||
},
|
||||
p(ctx, [dirty]) {
|
||||
if (dirty & /*tray*/ 1 && t_value !== (t_value = /*tray*/ ctx[0].Label + "")) set_data(t, t_value);
|
||||
},
|
||||
i: noop,
|
||||
o: noop,
|
||||
d(detaching) {
|
||||
if (detaching) detach(span1);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function instance$1($$self, $$props, $$invalidate) {
|
||||
let { tray } = $$props;
|
||||
|
||||
$$self.$$set = $$props => {
|
||||
if ("tray" in $$props) $$invalidate(0, tray = $$props.tray);
|
||||
};
|
||||
|
||||
return [tray];
|
||||
}
|
||||
|
||||
class TrayMenu extends SvelteComponent {
|
||||
constructor(options) {
|
||||
super();
|
||||
if (!document.getElementById("svelte-1vq8f40-style")) add_css$1();
|
||||
init(this, options, instance$1, create_fragment$1, safe_not_equal, { tray: 0 });
|
||||
}
|
||||
}
|
||||
|
||||
/* Menubar.svelte generated by Svelte v3.32.2 */
|
||||
|
||||
function add_css$2() {
|
||||
var style = element("style");
|
||||
style.id = "svelte-iy5wor-style";
|
||||
style.textContent = ".tray-menus.svelte-iy5wor{display:flex;flex-direction:row;justify-content:flex-end}.wails-menubar.svelte-iy5wor{position:relative;display:block;top:0;height:2rem;width:100%;border-bottom:1px solid #b3b3b3;box-shadow:antiquewhite;box-shadow:0px 0px 10px 0px #33333360}";
|
||||
style.id = "svelte-1ucacnf-style";
|
||||
style.textContent = ".menu.svelte-1ucacnf.svelte-1ucacnf{padding:5px;background-color:#0008;color:#EEF;border-radius:5px;margin-top:5px;position:absolute;backdrop-filter:blur(3px) saturate(160%) contrast(45%) brightness(140%);border:1px solid rgb(88,88,88);box-shadow:0 0 1px rgb(146,146,148) inset}.menuitem.svelte-1ucacnf.svelte-1ucacnf{display:flex;align-items:center;padding:1px 5px}.menuitem.svelte-1ucacnf.svelte-1ucacnf:hover{display:flex;align-items:center;background-color:rgb(57,131,223);padding:1px 5px;border-radius:5px}.menuitem.svelte-1ucacnf img.svelte-1ucacnf{padding-right:5px}.separator.svelte-1ucacnf.svelte-1ucacnf{padding-top:5px;width:100%;padding-bottom:5px}.separator.svelte-1ucacnf.svelte-1ucacnf:hover{background-color:#0000}";
|
||||
append(document.head, style);
|
||||
}
|
||||
|
||||
function get_each_context(ctx, list, i) {
|
||||
const child_ctx = ctx.slice();
|
||||
child_ctx[2] = list[i];
|
||||
child_ctx[3] = list[i];
|
||||
return child_ctx;
|
||||
}
|
||||
|
||||
// (11:0) {#if $menuVisible }
|
||||
// (14:0) {#if visible}
|
||||
function create_if_block$1(ctx) {
|
||||
let div;
|
||||
let span;
|
||||
let div_transition;
|
||||
let current;
|
||||
let each_value = /*$trays*/ ctx[1];
|
||||
let if_block = /*menu*/ ctx[0].Menu && create_if_block_1(ctx);
|
||||
|
||||
return {
|
||||
c() {
|
||||
div = element("div");
|
||||
if (if_block) if_block.c();
|
||||
attr(div, "class", "menu svelte-1ucacnf");
|
||||
},
|
||||
m(target, anchor) {
|
||||
insert(target, div, anchor);
|
||||
if (if_block) if_block.m(div, null);
|
||||
},
|
||||
p(ctx, dirty) {
|
||||
if (/*menu*/ ctx[0].Menu) {
|
||||
if (if_block) {
|
||||
if_block.p(ctx, dirty);
|
||||
} else {
|
||||
if_block = create_if_block_1(ctx);
|
||||
if_block.c();
|
||||
if_block.m(div, null);
|
||||
}
|
||||
} else if (if_block) {
|
||||
if_block.d(1);
|
||||
if_block = null;
|
||||
}
|
||||
},
|
||||
d(detaching) {
|
||||
if (detaching) detach(div);
|
||||
if (if_block) if_block.d();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// (16:4) {#if menu.Menu }
|
||||
function create_if_block_1(ctx) {
|
||||
let each_1_anchor;
|
||||
let each_value = /*menu*/ ctx[0].Menu.Items;
|
||||
let each_blocks = [];
|
||||
|
||||
for (let i = 0; i < each_value.length; i += 1) {
|
||||
each_blocks[i] = create_each_block(get_each_context(ctx, each_value, i));
|
||||
}
|
||||
|
||||
return {
|
||||
c() {
|
||||
for (let i = 0; i < each_blocks.length; i += 1) {
|
||||
each_blocks[i].c();
|
||||
}
|
||||
|
||||
each_1_anchor = empty();
|
||||
},
|
||||
m(target, anchor) {
|
||||
for (let i = 0; i < each_blocks.length; i += 1) {
|
||||
each_blocks[i].m(target, anchor);
|
||||
}
|
||||
|
||||
insert(target, each_1_anchor, anchor);
|
||||
},
|
||||
p(ctx, dirty) {
|
||||
if (dirty & /*click, menu*/ 1) {
|
||||
each_value = /*menu*/ ctx[0].Menu.Items;
|
||||
let i;
|
||||
|
||||
for (i = 0; i < each_value.length; i += 1) {
|
||||
const child_ctx = get_each_context(ctx, each_value, i);
|
||||
|
||||
if (each_blocks[i]) {
|
||||
each_blocks[i].p(child_ctx, dirty);
|
||||
} else {
|
||||
each_blocks[i] = create_each_block(child_ctx);
|
||||
each_blocks[i].c();
|
||||
each_blocks[i].m(each_1_anchor.parentNode, each_1_anchor);
|
||||
}
|
||||
}
|
||||
|
||||
for (; i < each_blocks.length; i += 1) {
|
||||
each_blocks[i].d(1);
|
||||
}
|
||||
|
||||
each_blocks.length = each_value.length;
|
||||
}
|
||||
},
|
||||
d(detaching) {
|
||||
destroy_each(each_blocks, detaching);
|
||||
if (detaching) detach(each_1_anchor);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// (25:52)
|
||||
function create_if_block_4(ctx) {
|
||||
let div;
|
||||
|
||||
return {
|
||||
c() {
|
||||
div = element("div");
|
||||
div.innerHTML = `<hr/>`;
|
||||
attr(div, "class", "separator svelte-1ucacnf");
|
||||
},
|
||||
m(target, anchor) {
|
||||
insert(target, div, anchor);
|
||||
},
|
||||
p: noop,
|
||||
d(detaching) {
|
||||
if (detaching) detach(div);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// (18:12) {#if menuItem.Type === "Text" }
|
||||
function create_if_block_2(ctx) {
|
||||
let div1;
|
||||
let t0;
|
||||
let div0;
|
||||
let t1_value = /*menuItem*/ ctx[3].Label + "";
|
||||
let t1;
|
||||
let t2;
|
||||
let mounted;
|
||||
let dispose;
|
||||
let if_block = /*menuItem*/ ctx[3].Image && create_if_block_3(ctx);
|
||||
|
||||
function click_handler() {
|
||||
return /*click_handler*/ ctx[2](/*menuItem*/ ctx[3]);
|
||||
}
|
||||
|
||||
return {
|
||||
c() {
|
||||
div1 = element("div");
|
||||
if (if_block) if_block.c();
|
||||
t0 = space();
|
||||
div0 = element("div");
|
||||
t1 = text(t1_value);
|
||||
t2 = space();
|
||||
attr(div0, "class", "menulabel");
|
||||
attr(div1, "class", "menuitem svelte-1ucacnf");
|
||||
},
|
||||
m(target, anchor) {
|
||||
insert(target, div1, anchor);
|
||||
if (if_block) if_block.m(div1, null);
|
||||
append(div1, t0);
|
||||
append(div1, div0);
|
||||
append(div0, t1);
|
||||
append(div1, t2);
|
||||
|
||||
if (!mounted) {
|
||||
dispose = listen(div1, "click", click_handler);
|
||||
mounted = true;
|
||||
}
|
||||
},
|
||||
p(new_ctx, dirty) {
|
||||
ctx = new_ctx;
|
||||
|
||||
if (/*menuItem*/ ctx[3].Image) {
|
||||
if (if_block) {
|
||||
if_block.p(ctx, dirty);
|
||||
} else {
|
||||
if_block = create_if_block_3(ctx);
|
||||
if_block.c();
|
||||
if_block.m(div1, t0);
|
||||
}
|
||||
} else if (if_block) {
|
||||
if_block.d(1);
|
||||
if_block = null;
|
||||
}
|
||||
|
||||
if (dirty & /*menu*/ 1 && t1_value !== (t1_value = /*menuItem*/ ctx[3].Label + "")) set_data(t1, t1_value);
|
||||
},
|
||||
d(detaching) {
|
||||
if (detaching) detach(div1);
|
||||
if (if_block) if_block.d();
|
||||
mounted = false;
|
||||
dispose();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// (20:12) {#if menuItem.Image }
|
||||
function create_if_block_3(ctx) {
|
||||
let div;
|
||||
let img;
|
||||
let img_src_value;
|
||||
|
||||
return {
|
||||
c() {
|
||||
div = element("div");
|
||||
img = element("img");
|
||||
attr(img, "alt", "");
|
||||
if (img.src !== (img_src_value = "data:image/png;base64," + /*menuItem*/ ctx[3].Image)) attr(img, "src", img_src_value);
|
||||
attr(img, "class", "svelte-1ucacnf");
|
||||
},
|
||||
m(target, anchor) {
|
||||
insert(target, div, anchor);
|
||||
append(div, img);
|
||||
},
|
||||
p(ctx, dirty) {
|
||||
if (dirty & /*menu*/ 1 && img.src !== (img_src_value = "data:image/png;base64," + /*menuItem*/ ctx[3].Image)) {
|
||||
attr(img, "src", img_src_value);
|
||||
}
|
||||
},
|
||||
d(detaching) {
|
||||
if (detaching) detach(div);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// (17:8) {#each menu.Menu.Items as menuItem}
|
||||
function create_each_block(ctx) {
|
||||
let if_block_anchor;
|
||||
|
||||
function select_block_type(ctx, dirty) {
|
||||
if (/*menuItem*/ ctx[3].Type === "Text") return create_if_block_2;
|
||||
if (/*menuItem*/ ctx[3].Type === "Separator") return create_if_block_4;
|
||||
}
|
||||
|
||||
let current_block_type = select_block_type(ctx);
|
||||
let if_block = current_block_type && current_block_type(ctx);
|
||||
|
||||
return {
|
||||
c() {
|
||||
if (if_block) if_block.c();
|
||||
if_block_anchor = empty();
|
||||
},
|
||||
m(target, anchor) {
|
||||
if (if_block) if_block.m(target, anchor);
|
||||
insert(target, if_block_anchor, anchor);
|
||||
},
|
||||
p(ctx, dirty) {
|
||||
if (current_block_type === (current_block_type = select_block_type(ctx)) && if_block) {
|
||||
if_block.p(ctx, dirty);
|
||||
} else {
|
||||
if (if_block) if_block.d(1);
|
||||
if_block = current_block_type && current_block_type(ctx);
|
||||
|
||||
if (if_block) {
|
||||
if_block.c();
|
||||
if_block.m(if_block_anchor.parentNode, if_block_anchor);
|
||||
}
|
||||
}
|
||||
},
|
||||
d(detaching) {
|
||||
if (if_block) {
|
||||
if_block.d(detaching);
|
||||
}
|
||||
|
||||
if (detaching) detach(if_block_anchor);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function create_fragment$1(ctx) {
|
||||
let if_block_anchor;
|
||||
let if_block = /*visible*/ ctx[1] && create_if_block$1(ctx);
|
||||
|
||||
return {
|
||||
c() {
|
||||
if (if_block) if_block.c();
|
||||
if_block_anchor = empty();
|
||||
},
|
||||
m(target, anchor) {
|
||||
if (if_block) if_block.m(target, anchor);
|
||||
insert(target, if_block_anchor, anchor);
|
||||
},
|
||||
p(ctx, [dirty]) {
|
||||
if (/*visible*/ ctx[1]) {
|
||||
if (if_block) {
|
||||
if_block.p(ctx, dirty);
|
||||
} else {
|
||||
if_block = create_if_block$1(ctx);
|
||||
if_block.c();
|
||||
if_block.m(if_block_anchor.parentNode, if_block_anchor);
|
||||
}
|
||||
} else if (if_block) {
|
||||
if_block.d(1);
|
||||
if_block = null;
|
||||
}
|
||||
},
|
||||
i: noop,
|
||||
o: noop,
|
||||
d(detaching) {
|
||||
if (if_block) if_block.d(detaching);
|
||||
if (detaching) detach(if_block_anchor);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function click(id) {
|
||||
console.log("MenuItem", id, "pressed");
|
||||
}
|
||||
|
||||
function instance$1($$self, $$props, $$invalidate) {
|
||||
let { menu } = $$props;
|
||||
console.log({ menu });
|
||||
let { visible = false } = $$props;
|
||||
const click_handler = menuItem => click(menuItem.ID);
|
||||
|
||||
$$self.$$set = $$props => {
|
||||
if ("menu" in $$props) $$invalidate(0, menu = $$props.menu);
|
||||
if ("visible" in $$props) $$invalidate(1, visible = $$props.visible);
|
||||
};
|
||||
|
||||
return [menu, visible, click_handler];
|
||||
}
|
||||
|
||||
class Menu extends SvelteComponent {
|
||||
constructor(options) {
|
||||
super();
|
||||
if (!document.getElementById("svelte-1ucacnf-style")) add_css$1();
|
||||
init(this, options, instance$1, create_fragment$1, safe_not_equal, { menu: 0, visible: 1 });
|
||||
}
|
||||
}
|
||||
|
||||
/* TrayMenu.svelte generated by Svelte v3.32.2 */
|
||||
|
||||
const { document: document_1 } = globals;
|
||||
|
||||
function add_css$2() {
|
||||
var style = element("style");
|
||||
style.id = "svelte-esze1k-style";
|
||||
style.textContent = ".tray-menu.svelte-esze1k{padding-left:0.5rem;padding-right:0.5rem;overflow:visible;font-size:14px}.label.svelte-esze1k{text-align:right;padding-right:10px}";
|
||||
append(document_1.head, style);
|
||||
}
|
||||
|
||||
// (48:4) {#if tray.ProcessedMenu }
|
||||
function create_if_block$2(ctx) {
|
||||
let menu;
|
||||
let current;
|
||||
|
||||
menu = new Menu({
|
||||
props: {
|
||||
menu: /*tray*/ ctx[0].ProcessedMenu,
|
||||
visible: /*visible*/ ctx[1]
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
c() {
|
||||
create_component(menu.$$.fragment);
|
||||
},
|
||||
m(target, anchor) {
|
||||
mount_component(menu, target, anchor);
|
||||
current = true;
|
||||
},
|
||||
p(ctx, dirty) {
|
||||
const menu_changes = {};
|
||||
if (dirty & /*tray*/ 1) menu_changes.menu = /*tray*/ ctx[0].ProcessedMenu;
|
||||
if (dirty & /*visible*/ 2) menu_changes.visible = /*visible*/ ctx[1];
|
||||
menu.$set(menu_changes);
|
||||
},
|
||||
i(local) {
|
||||
if (current) return;
|
||||
transition_in(menu.$$.fragment, local);
|
||||
current = true;
|
||||
},
|
||||
o(local) {
|
||||
transition_out(menu.$$.fragment, local);
|
||||
current = false;
|
||||
},
|
||||
d(detaching) {
|
||||
destroy_component(menu, detaching);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function create_fragment$2(ctx) {
|
||||
let span1;
|
||||
let span0;
|
||||
let t0_value = /*tray*/ ctx[0].Label + "";
|
||||
let t0;
|
||||
let t1;
|
||||
let current;
|
||||
let mounted;
|
||||
let dispose;
|
||||
let if_block = /*tray*/ ctx[0].ProcessedMenu && create_if_block$2(ctx);
|
||||
|
||||
return {
|
||||
c() {
|
||||
span1 = element("span");
|
||||
span0 = element("span");
|
||||
t0 = text(t0_value);
|
||||
t1 = space();
|
||||
if (if_block) if_block.c();
|
||||
attr(span0, "class", "label svelte-esze1k");
|
||||
attr(span1, "class", "tray-menu svelte-esze1k");
|
||||
},
|
||||
m(target, anchor) {
|
||||
insert(target, span1, anchor);
|
||||
append(span1, span0);
|
||||
append(span0, t0);
|
||||
append(span1, t1);
|
||||
if (if_block) if_block.m(span1, null);
|
||||
current = true;
|
||||
|
||||
if (!mounted) {
|
||||
dispose = [
|
||||
listen(span0, "click", /*trayClicked*/ ctx[3]),
|
||||
action_destroyer(clickOutside.call(null, span1)),
|
||||
listen(span1, "click_outside", /*closeMenu*/ ctx[2])
|
||||
];
|
||||
|
||||
mounted = true;
|
||||
}
|
||||
},
|
||||
p(ctx, [dirty]) {
|
||||
if ((!current || dirty & /*tray*/ 1) && t0_value !== (t0_value = /*tray*/ ctx[0].Label + "")) set_data(t0, t0_value);
|
||||
|
||||
if (/*tray*/ ctx[0].ProcessedMenu) {
|
||||
if (if_block) {
|
||||
if_block.p(ctx, dirty);
|
||||
|
||||
if (dirty & /*tray*/ 1) {
|
||||
transition_in(if_block, 1);
|
||||
}
|
||||
} else {
|
||||
if_block = create_if_block$2(ctx);
|
||||
if_block.c();
|
||||
transition_in(if_block, 1);
|
||||
if_block.m(span1, null);
|
||||
}
|
||||
} else if (if_block) {
|
||||
group_outros();
|
||||
|
||||
transition_out(if_block, 1, 1, () => {
|
||||
if_block = null;
|
||||
});
|
||||
|
||||
check_outros();
|
||||
}
|
||||
},
|
||||
i(local) {
|
||||
if (current) return;
|
||||
transition_in(if_block);
|
||||
current = true;
|
||||
},
|
||||
o(local) {
|
||||
transition_out(if_block);
|
||||
current = false;
|
||||
},
|
||||
d(detaching) {
|
||||
if (detaching) detach(span1);
|
||||
if (if_block) if_block.d();
|
||||
mounted = false;
|
||||
run_all(dispose);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function clickOutside(node) {
|
||||
const handleClick = event => {
|
||||
if (node && !node.contains(event.target) && !event.defaultPrevented) {
|
||||
console.log("click outside of node");
|
||||
node.dispatchEvent(new CustomEvent("click_outside", node));
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener("click", handleClick, true);
|
||||
|
||||
return {
|
||||
destroy() {
|
||||
document.removeEventListener("click", handleClick, true);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function instance$2($$self, $$props, $$invalidate) {
|
||||
let visible;
|
||||
let $selectedMenu;
|
||||
component_subscribe($$self, selectedMenu, $$value => $$invalidate(4, $selectedMenu = $$value));
|
||||
let { tray = null } = $$props;
|
||||
|
||||
function closeMenu() {
|
||||
selectedMenu.set(null);
|
||||
}
|
||||
|
||||
function trayClicked() {
|
||||
if ($selectedMenu !== tray) {
|
||||
selectedMenu.set(tray);
|
||||
} else {
|
||||
selectedMenu.set(null);
|
||||
}
|
||||
}
|
||||
|
||||
$$self.$$set = $$props => {
|
||||
if ("tray" in $$props) $$invalidate(0, tray = $$props.tray);
|
||||
};
|
||||
|
||||
$$self.$$.update = () => {
|
||||
if ($$self.$$.dirty & /*$selectedMenu, tray*/ 17) {
|
||||
$$invalidate(1, visible = $selectedMenu === tray);
|
||||
}
|
||||
};
|
||||
|
||||
return [tray, visible, closeMenu, trayClicked, $selectedMenu];
|
||||
}
|
||||
|
||||
class TrayMenu extends SvelteComponent {
|
||||
constructor(options) {
|
||||
super();
|
||||
if (!document_1.getElementById("svelte-esze1k-style")) add_css$2();
|
||||
init(this, options, instance$2, create_fragment$2, safe_not_equal, { tray: 0 });
|
||||
}
|
||||
}
|
||||
|
||||
/* Menubar.svelte generated by Svelte v3.32.2 */
|
||||
|
||||
function add_css$3() {
|
||||
var style = element("style");
|
||||
style.id = "svelte-1i0zb4n-style";
|
||||
style.textContent = ".tray-menus.svelte-1i0zb4n{display:flex;flex-direction:row;justify-content:flex-end}.wails-menubar.svelte-1i0zb4n{position:relative;display:block;top:0;height:2rem;width:100%;border-bottom:1px solid #b3b3b3;box-shadow:0 0 10px 0 #33333360}.time.svelte-1i0zb4n{padding-left:0.5rem;padding-right:1.5rem;overflow:visible;font-size:14px}";
|
||||
append(document.head, style);
|
||||
}
|
||||
|
||||
function get_each_context$1(ctx, list, i) {
|
||||
const child_ctx = ctx.slice();
|
||||
child_ctx[8] = list[i];
|
||||
return child_ctx;
|
||||
}
|
||||
|
||||
// (29:0) {#if $menuVisible }
|
||||
function create_if_block$3(ctx) {
|
||||
let div;
|
||||
let span1;
|
||||
let t0;
|
||||
let span0;
|
||||
let t1;
|
||||
let div_transition;
|
||||
let current;
|
||||
let each_value = /*$trays*/ ctx[2];
|
||||
let each_blocks = [];
|
||||
|
||||
for (let i = 0; i < each_value.length; i += 1) {
|
||||
each_blocks[i] = create_each_block$1(get_each_context$1(ctx, each_value, i));
|
||||
}
|
||||
|
||||
const out = i => transition_out(each_blocks[i], 1, 1, () => {
|
||||
each_blocks[i] = null;
|
||||
});
|
||||
@@ -821,41 +1333,48 @@
|
||||
return {
|
||||
c() {
|
||||
div = element("div");
|
||||
span = element("span");
|
||||
span1 = element("span");
|
||||
|
||||
for (let i = 0; i < each_blocks.length; i += 1) {
|
||||
each_blocks[i].c();
|
||||
}
|
||||
|
||||
attr(span, "class", "tray-menus svelte-iy5wor");
|
||||
attr(div, "class", "wails-menubar svelte-iy5wor");
|
||||
t0 = space();
|
||||
span0 = element("span");
|
||||
t1 = text(/*dateTimeString*/ ctx[0]);
|
||||
attr(span0, "class", "time svelte-1i0zb4n");
|
||||
attr(span1, "class", "tray-menus svelte-1i0zb4n");
|
||||
attr(div, "class", "wails-menubar svelte-1i0zb4n");
|
||||
},
|
||||
m(target, anchor) {
|
||||
insert(target, div, anchor);
|
||||
append(div, span);
|
||||
append(div, span1);
|
||||
|
||||
for (let i = 0; i < each_blocks.length; i += 1) {
|
||||
each_blocks[i].m(span, null);
|
||||
each_blocks[i].m(span1, null);
|
||||
}
|
||||
|
||||
append(span1, t0);
|
||||
append(span1, span0);
|
||||
append(span0, t1);
|
||||
current = true;
|
||||
},
|
||||
p(ctx, dirty) {
|
||||
if (dirty & /*$trays*/ 2) {
|
||||
each_value = /*$trays*/ ctx[1];
|
||||
if (dirty & /*$trays*/ 4) {
|
||||
each_value = /*$trays*/ ctx[2];
|
||||
let i;
|
||||
|
||||
for (i = 0; i < each_value.length; i += 1) {
|
||||
const child_ctx = get_each_context(ctx, each_value, i);
|
||||
const child_ctx = get_each_context$1(ctx, each_value, i);
|
||||
|
||||
if (each_blocks[i]) {
|
||||
each_blocks[i].p(child_ctx, dirty);
|
||||
transition_in(each_blocks[i], 1);
|
||||
} else {
|
||||
each_blocks[i] = create_each_block(child_ctx);
|
||||
each_blocks[i] = create_each_block$1(child_ctx);
|
||||
each_blocks[i].c();
|
||||
transition_in(each_blocks[i], 1);
|
||||
each_blocks[i].m(span, null);
|
||||
each_blocks[i].m(span1, t0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -867,6 +1386,8 @@
|
||||
|
||||
check_outros();
|
||||
}
|
||||
|
||||
if (!current || dirty & /*dateTimeString*/ 1) set_data(t1, /*dateTimeString*/ ctx[0]);
|
||||
},
|
||||
i(local) {
|
||||
if (current) return;
|
||||
@@ -901,11 +1422,11 @@
|
||||
};
|
||||
}
|
||||
|
||||
// (14:4) {#each $trays as tray}
|
||||
function create_each_block(ctx) {
|
||||
// (32:4) {#each $trays as tray}
|
||||
function create_each_block$1(ctx) {
|
||||
let traymenu;
|
||||
let current;
|
||||
traymenu = new TrayMenu({ props: { tray: /*tray*/ ctx[2] } });
|
||||
traymenu = new TrayMenu({ props: { tray: /*tray*/ ctx[8] } });
|
||||
|
||||
return {
|
||||
c() {
|
||||
@@ -917,7 +1438,7 @@
|
||||
},
|
||||
p(ctx, dirty) {
|
||||
const traymenu_changes = {};
|
||||
if (dirty & /*$trays*/ 2) traymenu_changes.tray = /*tray*/ ctx[2];
|
||||
if (dirty & /*$trays*/ 4) traymenu_changes.tray = /*tray*/ ctx[8];
|
||||
traymenu.$set(traymenu_changes);
|
||||
},
|
||||
i(local) {
|
||||
@@ -935,10 +1456,10 @@
|
||||
};
|
||||
}
|
||||
|
||||
function create_fragment$2(ctx) {
|
||||
function create_fragment$3(ctx) {
|
||||
let if_block_anchor;
|
||||
let current;
|
||||
let if_block = /*$menuVisible*/ ctx[0] && create_if_block$1(ctx);
|
||||
let if_block = /*$menuVisible*/ ctx[1] && create_if_block$3(ctx);
|
||||
|
||||
return {
|
||||
c() {
|
||||
@@ -951,15 +1472,15 @@
|
||||
current = true;
|
||||
},
|
||||
p(ctx, [dirty]) {
|
||||
if (/*$menuVisible*/ ctx[0]) {
|
||||
if (/*$menuVisible*/ ctx[1]) {
|
||||
if (if_block) {
|
||||
if_block.p(ctx, dirty);
|
||||
|
||||
if (dirty & /*$menuVisible*/ 1) {
|
||||
if (dirty & /*$menuVisible*/ 2) {
|
||||
transition_in(if_block, 1);
|
||||
}
|
||||
} else {
|
||||
if_block = create_if_block$1(ctx);
|
||||
if_block = create_if_block$3(ctx);
|
||||
if_block.c();
|
||||
transition_in(if_block, 1);
|
||||
if_block.m(if_block_anchor.parentNode, if_block_anchor);
|
||||
@@ -990,19 +1511,65 @@
|
||||
};
|
||||
}
|
||||
|
||||
function instance$2($$self, $$props, $$invalidate) {
|
||||
function instance$3($$self, $$props, $$invalidate) {
|
||||
let day;
|
||||
let dom;
|
||||
let mon;
|
||||
let currentTime;
|
||||
let dateTimeString;
|
||||
let $menuVisible;
|
||||
let $trays;
|
||||
component_subscribe($$self, menuVisible, $$value => $$invalidate(0, $menuVisible = $$value));
|
||||
component_subscribe($$self, trays, $$value => $$invalidate(1, $trays = $$value));
|
||||
return [$menuVisible, $trays];
|
||||
component_subscribe($$self, menuVisible, $$value => $$invalidate(1, $menuVisible = $$value));
|
||||
component_subscribe($$self, trays, $$value => $$invalidate(2, $trays = $$value));
|
||||
let time = new Date();
|
||||
|
||||
onMount(() => {
|
||||
const interval = setInterval(
|
||||
() => {
|
||||
$$invalidate(3, time = new Date());
|
||||
},
|
||||
1000
|
||||
);
|
||||
|
||||
return () => {
|
||||
clearInterval(interval);
|
||||
};
|
||||
});
|
||||
|
||||
$$self.$$.update = () => {
|
||||
if ($$self.$$.dirty & /*time*/ 8) {
|
||||
$$invalidate(4, day = time.toLocaleString("default", { weekday: "short" }));
|
||||
}
|
||||
|
||||
if ($$self.$$.dirty & /*time*/ 8) {
|
||||
$$invalidate(5, dom = time.getDate());
|
||||
}
|
||||
|
||||
if ($$self.$$.dirty & /*time*/ 8) {
|
||||
$$invalidate(6, mon = time.toLocaleString("default", { month: "short" }));
|
||||
}
|
||||
|
||||
if ($$self.$$.dirty & /*time*/ 8) {
|
||||
$$invalidate(7, currentTime = time.toLocaleString("en-US", {
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
hour12: true
|
||||
}).toLowerCase());
|
||||
}
|
||||
|
||||
if ($$self.$$.dirty & /*day, dom, mon, currentTime*/ 240) {
|
||||
$$invalidate(0, dateTimeString = `${day} ${dom} ${mon} ${currentTime}`);
|
||||
}
|
||||
};
|
||||
|
||||
return [dateTimeString, $menuVisible, $trays, time, day, dom, mon, currentTime];
|
||||
}
|
||||
|
||||
class Menubar extends SvelteComponent {
|
||||
constructor(options) {
|
||||
super();
|
||||
if (!document.getElementById("svelte-iy5wor-style")) add_css$2();
|
||||
init(this, options, instance$2, create_fragment$2, safe_not_equal, {});
|
||||
if (!document.getElementById("svelte-1i0zb4n-style")) add_css$3();
|
||||
init(this, options, instance$3, create_fragment$3, safe_not_equal, {});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1020,15 +1587,6 @@
|
||||
let callback = null;
|
||||
let connectTimer;
|
||||
|
||||
function log(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'
|
||||
);
|
||||
}
|
||||
|
||||
function StartWebsocket(userCallback) {
|
||||
|
||||
callback = userCallback;
|
||||
@@ -1160,6 +1718,12 @@
|
||||
let tray = JSON.parse(trayJSON);
|
||||
setTray(tray);
|
||||
break
|
||||
case 'U':
|
||||
// Update label
|
||||
const updateTrayLabelJSON = trayMessage.slice(1);
|
||||
let trayLabelData = JSON.parse(updateTrayLabelJSON);
|
||||
updateTrayLabel(trayLabelData);
|
||||
break
|
||||
default:
|
||||
log('Unknown tray message: ' + message.data);
|
||||
}
|
||||
|
||||
@@ -2,17 +2,73 @@
|
||||
|
||||
export let menu;
|
||||
|
||||
console.log({menu})
|
||||
|
||||
export let visible = false;
|
||||
|
||||
function click(id) {
|
||||
console.log("MenuItem", id, "pressed")
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if visible}
|
||||
<div class="menu">
|
||||
{#each menu.Menu.Items as menuItem}
|
||||
{#if menuItem.Image.length > 0}
|
||||
<img alt="" src="data:image/png;base64,{menuItem.Image}"/>
|
||||
{/if}
|
||||
<span class="menuitem">{menuItem.Label}</span>
|
||||
{/each}
|
||||
{#if menu.Menu }
|
||||
{#each menu.Menu.Items as menuItem}
|
||||
{#if menuItem.Type === "Text" }
|
||||
<div class="menuitem" on:click={() => click(menuItem.ID)}>
|
||||
{#if menuItem.Image }
|
||||
<div><img alt="" src="data:image/png;base64,{menuItem.Image}"/></div>
|
||||
{/if}
|
||||
<div class="menulabel">{menuItem.Label}</div>
|
||||
</div>
|
||||
{:else if menuItem.Type === "Separator"}
|
||||
<div class="separator"><hr/></div>
|
||||
{/if}
|
||||
{/each}
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
|
||||
.menu {
|
||||
padding: 5px;
|
||||
background-color: #0008;
|
||||
color: #EEF;
|
||||
border-radius: 5px;
|
||||
margin-top: 5px;
|
||||
position: absolute;
|
||||
backdrop-filter: blur(3px) saturate(160%) contrast(45%) brightness(140%);
|
||||
border: 1px solid rgb(88,88,88);
|
||||
box-shadow: 0 0 1px rgb(146,146,148) inset;
|
||||
}
|
||||
|
||||
.menuitem {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 1px 5px;
|
||||
}
|
||||
|
||||
.menuitem:hover {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: rgb(57,131,223);
|
||||
padding: 1px 5px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.menuitem img {
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.separator {
|
||||
padding-top: 5px;
|
||||
width: 100%;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
.separator:hover {
|
||||
background-color: #0000;
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -5,6 +5,24 @@
|
||||
|
||||
import {trays} from './store'
|
||||
import TrayMenu from "./TrayMenu.svelte";
|
||||
import {onMount} from "svelte";
|
||||
|
||||
let time = new Date();
|
||||
$: day = time.toLocaleString("default", { weekday: "short" })
|
||||
$: dom = time.getDate()
|
||||
$: mon = time.toLocaleString("default", { month: "short" })
|
||||
$: currentTime = time.toLocaleString('en-US', { hour: 'numeric', minute: 'numeric', hour12: true }).toLowerCase()
|
||||
$: dateTimeString = `${day} ${dom} ${mon} ${currentTime}`
|
||||
|
||||
onMount(() => {
|
||||
const interval = setInterval(() => {
|
||||
time = new Date();
|
||||
}, 1000);
|
||||
|
||||
return () => {
|
||||
clearInterval(interval);
|
||||
};
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
@@ -12,8 +30,9 @@
|
||||
<div class="wails-menubar" transition:fade>
|
||||
<span class="tray-menus">
|
||||
{#each $trays as tray}
|
||||
<TrayMenu {tray}></TrayMenu>
|
||||
<TrayMenu {tray}/>
|
||||
{/each}
|
||||
<span class="time">{dateTimeString}</span>
|
||||
</span>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -31,7 +50,12 @@
|
||||
height: 2rem;
|
||||
width: 100%;
|
||||
border-bottom: 1px solid #b3b3b3;
|
||||
box-shadow: antiquewhite;
|
||||
box-shadow: 0px 0px 10px 0px #33333360;
|
||||
box-shadow: 0 0 10px 0 #33333360;
|
||||
}
|
||||
.time {
|
||||
padding-left: 0.5rem;
|
||||
padding-right: 1.5rem;
|
||||
overflow: visible;
|
||||
font-size: 14px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,13 +1,53 @@
|
||||
<script>
|
||||
import Menu from "./Menu.svelte";
|
||||
import { selectedMenu } from "./store";
|
||||
|
||||
export let tray;
|
||||
export let tray = null;
|
||||
|
||||
$: visible = $selectedMenu === tray;
|
||||
|
||||
function closeMenu() {
|
||||
selectedMenu.set(null);
|
||||
}
|
||||
|
||||
function trayClicked() {
|
||||
if ( $selectedMenu !== tray ) {
|
||||
selectedMenu.set(tray);
|
||||
} else {
|
||||
selectedMenu.set(null);
|
||||
}
|
||||
}
|
||||
// Source: https://svelte.dev/repl/0ace7a508bd843b798ae599940a91783?version=3.16.7
|
||||
/** Dispatch event on click outside of node */
|
||||
function clickOutside(node) {
|
||||
|
||||
const handleClick = event => {
|
||||
if (node && !node.contains(event.target) && !event.defaultPrevented) {
|
||||
console.log("click outside of node")
|
||||
node.dispatchEvent(
|
||||
new CustomEvent('click_outside', node)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('click', handleClick, true);
|
||||
|
||||
return {
|
||||
destroy() {
|
||||
document.removeEventListener('click', handleClick, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<span class="tray-menu">
|
||||
<span class="label">{tray.Label}</span>
|
||||
<!-- <Menu menu="{tray.ProcessedMenu}"/>-->
|
||||
<span class="tray-menu" use:clickOutside on:click_outside={closeMenu}>
|
||||
<!--{#if tray.Image && tray.Image.length > 0}-->
|
||||
<!-- <img alt="" src="data:image/png;base64,{tray.Image}"/>-->
|
||||
<!--{/if}-->
|
||||
<span class="label" on:click={trayClicked}>{tray.Label}</span>
|
||||
{#if tray.ProcessedMenu }
|
||||
<Menu menu="{tray.ProcessedMenu}" visible="{visible}"/>
|
||||
{/if}
|
||||
</span>
|
||||
|
||||
<style>
|
||||
@@ -18,4 +58,9 @@
|
||||
overflow: visible;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.label {
|
||||
text-align: right;
|
||||
padding-right: 10px;
|
||||
}
|
||||
</style>
|
||||
9
v2/internal/runtime/js/runtime/src/log.js
Normal file
9
v2/internal/runtime/js/runtime/src/log.js
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
export function log(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'
|
||||
);
|
||||
}
|
||||
205
v2/internal/runtime/js/runtime/src/package-lock.json
generated
205
v2/internal/runtime/js/runtime/src/package-lock.json
generated
@@ -4,6 +4,32 @@
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": {
|
||||
"version": "7.12.13",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz",
|
||||
"integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/highlight": "^7.12.13"
|
||||
}
|
||||
},
|
||||
"@babel/helper-validator-identifier": {
|
||||
"version": "7.12.11",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz",
|
||||
"integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==",
|
||||
"dev": true
|
||||
},
|
||||
"@babel/highlight": {
|
||||
"version": "7.12.13",
|
||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.12.13.tgz",
|
||||
"integrity": "sha512-kocDQvIbgMKlWxXe9fof3TQ+gkIPOUSEYhJjqUjvKMez3krV7vbzYCDq39Oj11UAVK7JqPVGQPlgE85dPNlQww==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/helper-validator-identifier": "^7.12.11",
|
||||
"chalk": "^2.0.0",
|
||||
"js-tokens": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"@rollup/plugin-commonjs": {
|
||||
"version": "17.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-17.1.0.tgz",
|
||||
@@ -73,6 +99,15 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||
@@ -89,12 +124,50 @@
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"buffer-from": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
|
||||
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
|
||||
"dev": true
|
||||
},
|
||||
"builtin-modules": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz",
|
||||
"integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==",
|
||||
"dev": true
|
||||
},
|
||||
"chalk": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"supports-color": "^5.3.0"
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
|
||||
"dev": true
|
||||
},
|
||||
"commander": {
|
||||
"version": "2.20.3",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
||||
"dev": true
|
||||
},
|
||||
"commondir": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
|
||||
@@ -113,6 +186,12 @@
|
||||
"integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==",
|
||||
"dev": true
|
||||
},
|
||||
"escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
|
||||
"dev": true
|
||||
},
|
||||
"estree-walker": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz",
|
||||
@@ -161,6 +240,12 @@
|
||||
"function-bind": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
|
||||
"dev": true
|
||||
},
|
||||
"inflight": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||
@@ -201,6 +286,40 @@
|
||||
"@types/estree": "*"
|
||||
}
|
||||
},
|
||||
"jest-worker": {
|
||||
"version": "26.6.2",
|
||||
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz",
|
||||
"integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*",
|
||||
"merge-stream": "^2.0.0",
|
||||
"supports-color": "^7.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||
"dev": true
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^4.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
||||
"dev": true
|
||||
},
|
||||
"magic-string": {
|
||||
"version": "0.25.7",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz",
|
||||
@@ -210,6 +329,12 @@
|
||||
"sourcemap-codec": "^1.4.4"
|
||||
}
|
||||
},
|
||||
"merge-stream": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
|
||||
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
|
||||
"dev": true
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||
@@ -246,6 +371,15 @@
|
||||
"integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
|
||||
"dev": true
|
||||
},
|
||||
"randombytes": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safe-buffer": "^5.1.0"
|
||||
}
|
||||
},
|
||||
"require-relative": {
|
||||
"version": "0.8.7",
|
||||
"resolved": "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz",
|
||||
@@ -281,6 +415,18 @@
|
||||
"rollup-pluginutils": "^2.8.2"
|
||||
}
|
||||
},
|
||||
"rollup-plugin-terser": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz",
|
||||
"integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.10.4",
|
||||
"jest-worker": "^26.2.1",
|
||||
"serialize-javascript": "^4.0.0",
|
||||
"terser": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"rollup-pluginutils": {
|
||||
"version": "2.8.2",
|
||||
"resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz",
|
||||
@@ -298,18 +444,77 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||
"dev": true
|
||||
},
|
||||
"serialize-javascript": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz",
|
||||
"integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"randombytes": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.7.3",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
|
||||
"integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
|
||||
"dev": true
|
||||
},
|
||||
"source-map-support": {
|
||||
"version": "0.5.19",
|
||||
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
|
||||
"integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"buffer-from": "^1.0.0",
|
||||
"source-map": "^0.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"sourcemap-codec": {
|
||||
"version": "1.4.8",
|
||||
"resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
|
||||
"integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
|
||||
"dev": true
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"svelte": {
|
||||
"version": "3.32.2",
|
||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.32.2.tgz",
|
||||
"integrity": "sha512-Zxh1MQQl/+vnToKbU1Per+PoMN8Jb2MeKJcGxiOsCGR677hXw7jkMfbnNXq33+dxIzV/HfA4xtoSPJrqeB0VUg==",
|
||||
"dev": true
|
||||
},
|
||||
"terser": {
|
||||
"version": "5.5.1",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.5.1.tgz",
|
||||
"integrity": "sha512-6VGWZNVP2KTUcltUQJ25TtNjx/XgdDsBDKGt8nN0MpydU36LmbPPcMBd2kmtZNNGVVDLg44k7GKeHHj+4zPIBQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"commander": "^2.20.0",
|
||||
"source-map": "~0.7.2",
|
||||
"source-map-support": "~0.5.19"
|
||||
}
|
||||
},
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"build": "npx rollup -c"
|
||||
"build": "npx rollup -c",
|
||||
"watch": "npx rollup -c -w"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
@@ -14,6 +15,7 @@
|
||||
"@rollup/plugin-node-resolve": "^11.1.1",
|
||||
"rollup": "^2.38.5",
|
||||
"rollup-plugin-svelte": "^7.1.0",
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
"svelte": "^3.32.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import resolve from '@rollup/plugin-node-resolve';
|
||||
// import commonjs from '@rollup/plugin-commonjs';
|
||||
import svelte from 'rollup-plugin-svelte';
|
||||
import { terser } from "rollup-plugin-terser";
|
||||
|
||||
export default [
|
||||
// browser-friendly UMD build
|
||||
@@ -28,6 +29,7 @@ export default [
|
||||
}),
|
||||
resolve({browser: true}), // so Rollup can find `ms`
|
||||
// commonjs() // so Rollup can convert `ms` to an ES module
|
||||
// terser(),
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
|
||||
import { writable } from 'svelte/store';
|
||||
import {log} from "./log";
|
||||
|
||||
/** Overlay */
|
||||
export const overlayVisible = writable(false);
|
||||
@@ -36,4 +37,16 @@ export function setTray(tray) {
|
||||
return current;
|
||||
})
|
||||
}
|
||||
export function updateTrayLabel(tray) {
|
||||
trays.update((current) => {
|
||||
// Remove existing if it exists, else add
|
||||
const index = current.findIndex(item => item.ID === tray.ID);
|
||||
if ( index === -1 ) {
|
||||
return log("ERROR: Attempted to update tray index ", tray.ID, "but it doesn't exist")
|
||||
}
|
||||
current[index].Label = tray.Label;
|
||||
return current;
|
||||
})
|
||||
}
|
||||
|
||||
export let selectedMenu = writable(null);
|
||||
@@ -10,21 +10,13 @@ The lightweight framework for web-like apps
|
||||
/* jshint esversion: 6 */
|
||||
|
||||
|
||||
import {setTray, hideOverlay, showOverlay} from "./store";
|
||||
import {setTray, hideOverlay, showOverlay, updateTrayLabel} from "./store";
|
||||
import {log} from "./log";
|
||||
|
||||
let websocket = null;
|
||||
let callback = null;
|
||||
let connectTimer;
|
||||
|
||||
function log(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'
|
||||
);
|
||||
}
|
||||
|
||||
export function StartWebsocket(userCallback) {
|
||||
|
||||
callback = userCallback;
|
||||
@@ -156,6 +148,12 @@ function handleMessage(message) {
|
||||
let tray = JSON.parse(trayJSON)
|
||||
setTray(tray)
|
||||
break
|
||||
case 'U':
|
||||
// Update label
|
||||
const updateTrayLabelJSON = trayMessage.slice(1);
|
||||
let trayLabelData = JSON.parse(updateTrayLabelJSON)
|
||||
updateTrayLabel(trayLabelData)
|
||||
break
|
||||
default:
|
||||
log('Unknown tray message: ' + message.data);
|
||||
}
|
||||
|
||||
@@ -80,4 +80,5 @@ func (m *Manager) Start() {
|
||||
m.logger.Trace("Shutdown")
|
||||
m.wg.Done()
|
||||
}()
|
||||
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package menu
|
||||
|
||||
import (
|
||||
"github.com/wailsapp/wails/v2/pkg/menu/keys"
|
||||
"sync"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/menu/keys"
|
||||
)
|
||||
|
||||
// MenuItem represents a menuitem contained in a menu
|
||||
@@ -38,6 +39,9 @@ type MenuItem struct {
|
||||
// Image - base64 image data
|
||||
Image string
|
||||
|
||||
// MacTemplateImage indicates that on a mac, this image is a template image
|
||||
MacTemplateImage bool
|
||||
|
||||
// Tooltip
|
||||
Tooltip string
|
||||
|
||||
|
||||
Reference in New Issue
Block a user