From 29715b2d57ccc3fd80a936309fcf37dc1066756f Mon Sep 17 00:00:00 2001 From: Lea Anthony Date: Fri, 19 Feb 2021 20:37:02 +1100 Subject: [PATCH] [WIP] --- v2/cmd/wails/internal/commands/dev/dev.go | 383 ++++++++++-------- v2/cmd/wails/main.go | 21 + v2/go.mod | 1 + v2/go.sum | 5 + v2/internal/app/debug.go | 3 +- v2/internal/process/process.go | 47 ++- v2/internal/runtime/js/runtime/bridge.js | 172 ++++++-- .../runtime/js/runtime/src/Menu.svelte | 30 +- .../runtime/js/runtime/src/TrayMenu.svelte | 5 +- v2/internal/signal/signal.go | 1 + 10 files changed, 428 insertions(+), 240 deletions(-) diff --git a/v2/cmd/wails/internal/commands/dev/dev.go b/v2/cmd/wails/internal/commands/dev/dev.go index 3201fdcb..5adf1d71 100644 --- a/v2/cmd/wails/internal/commands/dev/dev.go +++ b/v2/cmd/wails/internal/commands/dev/dev.go @@ -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, } diff --git a/v2/cmd/wails/main.go b/v2/cmd/wails/main.go index 01eee20b..0d157edd 100644 --- a/v2/cmd/wails/main.go +++ b/v2/cmd/wails/main.go @@ -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 { diff --git a/v2/go.mod b/v2/go.mod index a89cbcbe..924321e7 100644 --- a/v2/go.mod +++ b/v2/go.mod @@ -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 diff --git a/v2/go.sum b/v2/go.sum index b8cc83b8..7657a28d 100644 --- a/v2/go.sum +++ b/v2/go.sum @@ -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= diff --git a/v2/internal/app/debug.go b/v2/internal/app/debug.go index 22bc7cdc..7b76b0ed 100644 --- a/v2/internal/app/debug.go +++ b/v2/internal/app/debug.go @@ -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 diff --git a/v2/internal/process/process.go b/v2/internal/process/process.go index 8c1a99bf..afe595cf 100644 --- a/v2/internal/process/process.go +++ b/v2/internal/process/process.go @@ -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 diff --git a/v2/internal/runtime/js/runtime/bridge.js b/v2/internal/runtime/js/runtime/bridge.js index 6efce19b..d09ac7b4 100644 --- a/v2/internal/runtime/js/runtime/bridge.js +++ b/v2/internal/runtime/js/runtime/bridge.js @@ -779,18 +779,18 @@ function add_css$1() { var style = element("style"); - style.id = "svelte-1oysp7o-style"; - style.textContent = ".menu.svelte-1oysp7o.svelte-1oysp7o{padding:3px;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-1oysp7o.svelte-1oysp7o{display:flex;align-items:center;padding:1px 5px}.menuitem.svelte-1oysp7o.svelte-1oysp7o:hover{display:flex;align-items:center;background-color:rgb(57,131,223);padding:1px 5px;border-radius:5px}.menuitem.svelte-1oysp7o img.svelte-1oysp7o{padding-right:5px}"; + 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; } - // (8:0) {#if !hidden} + // (14:0) {#if visible} function create_if_block$1(ctx) { let div; let if_block = /*menu*/ ctx[0].Menu && create_if_block_1(ctx); @@ -799,7 +799,7 @@ c() { div = element("div"); if (if_block) if_block.c(); - attr(div, "class", "menu svelte-1oysp7o"); + attr(div, "class", "menu svelte-1ucacnf"); }, m(target, anchor) { insert(target, div, anchor); @@ -826,7 +826,7 @@ }; } - // (10:4) {#if menu.Menu } + // (16:4) {#if menu.Menu } function create_if_block_1(ctx) { let each_1_anchor; let each_value = /*menu*/ ctx[0].Menu.Items; @@ -852,7 +852,7 @@ insert(target, each_1_anchor, anchor); }, p(ctx, dirty) { - if (dirty & /*menu*/ 1) { + if (dirty & /*click, menu*/ 1) { each_value = /*menu*/ ctx[0].Menu.Items; let i; @@ -882,44 +882,41 @@ }; } - // (13:12) {#if menuItem.Image } - function create_if_block_2(ctx) { + // (25:52) + function create_if_block_4(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[2].Image)) attr(img, "src", img_src_value); - attr(img, "class", "svelte-1oysp7o"); + div.innerHTML = `
`; + attr(div, "class", "separator 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[2].Image)) { - attr(img, "src", img_src_value); - } }, + p: noop, d(detaching) { if (detaching) detach(div); } }; } - // (11:8) {#each menu.Menu.Items as menuItem} - function create_each_block(ctx) { + // (18:12) {#if menuItem.Type === "Text" } + function create_if_block_2(ctx) { let div1; let t0; let div0; - let t1_value = /*menuItem*/ ctx[2].Label + ""; + let t1_value = /*menuItem*/ ctx[3].Label + ""; let t1; let t2; - let if_block = /*menuItem*/ ctx[2].Image && create_if_block_2(ctx); + 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() { @@ -930,7 +927,7 @@ t1 = text(t1_value); t2 = space(); attr(div0, "class", "menulabel"); - attr(div1, "class", "menuitem svelte-1oysp7o"); + attr(div1, "class", "menuitem svelte-1ucacnf"); }, m(target, anchor) { insert(target, div1, anchor); @@ -939,13 +936,20 @@ append(div1, div0); append(div0, t1); append(div1, t2); + + if (!mounted) { + dispose = listen(div1, "click", click_handler); + mounted = true; + } }, - p(ctx, dirty) { - if (/*menuItem*/ ctx[2].Image) { + 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_2(ctx); + if_block = create_if_block_3(ctx); if_block.c(); if_block.m(div1, t0); } @@ -954,18 +958,93 @@ if_block = null; } - if (dirty & /*menu*/ 1 && t1_value !== (t1_value = /*menuItem*/ ctx[2].Label + "")) set_data(t1, t1_value); + 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 = !/*hidden*/ ctx[1] && create_if_block$1(ctx); + let if_block = /*visible*/ ctx[1] && create_if_block$1(ctx); return { c() { @@ -977,7 +1056,7 @@ insert(target, if_block_anchor, anchor); }, p(ctx, [dirty]) { - if (!/*hidden*/ ctx[1]) { + if (/*visible*/ ctx[1]) { if (if_block) { if_block.p(ctx, dirty); } else { @@ -999,23 +1078,29 @@ }; } + function click(id) { + console.log("MenuItem", id, "pressed"); + } + function instance$1($$self, $$props, $$invalidate) { let { menu } = $$props; - let { hidden = true } = $$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 ("hidden" in $$props) $$invalidate(1, hidden = $$props.hidden); + if ("visible" in $$props) $$invalidate(1, visible = $$props.visible); }; - return [menu, hidden]; + return [menu, visible, click_handler]; } class Menu extends SvelteComponent { constructor(options) { super(); - if (!document.getElementById("svelte-1oysp7o-style")) add_css$1(); - init(this, options, instance$1, create_fragment$1, safe_not_equal, { menu: 0, hidden: 1 }); + if (!document.getElementById("svelte-1ucacnf-style")) add_css$1(); + init(this, options, instance$1, create_fragment$1, safe_not_equal, { menu: 0, visible: 1 }); } } @@ -1030,7 +1115,7 @@ append(document_1.head, style); } - // (47:4) {#if tray.ProcessedMenu } + // (48:4) {#if tray.ProcessedMenu } function create_if_block$2(ctx) { let menu; let current; @@ -1038,7 +1123,7 @@ menu = new Menu({ props: { menu: /*tray*/ ctx[0].ProcessedMenu, - hidden: /*hidden*/ ctx[1] + visible: /*visible*/ ctx[1] } }); @@ -1053,7 +1138,7 @@ p(ctx, dirty) { const menu_changes = {}; if (dirty & /*tray*/ 1) menu_changes.menu = /*tray*/ ctx[0].ProcessedMenu; - if (dirty & /*hidden*/ 2) menu_changes.hidden = /*hidden*/ ctx[1]; + if (dirty & /*visible*/ 2) menu_changes.visible = /*visible*/ ctx[1]; menu.$set(menu_changes); }, i(local) { @@ -1157,6 +1242,7 @@ 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)); } }; @@ -1171,7 +1257,7 @@ } function instance$2($$self, $$props, $$invalidate) { - let hidden; + let visible; let $selectedMenu; component_subscribe($$self, selectedMenu, $$value => $$invalidate(4, $selectedMenu = $$value)); let { tray = null } = $$props; @@ -1194,11 +1280,11 @@ $$self.$$.update = () => { if ($$self.$$.dirty & /*$selectedMenu, tray*/ 17) { - $$invalidate(1, hidden = $selectedMenu !== tray); + $$invalidate(1, visible = $selectedMenu === tray); } }; - return [tray, hidden, closeMenu, trayClicked, $selectedMenu]; + return [tray, visible, closeMenu, trayClicked, $selectedMenu]; } class TrayMenu extends SvelteComponent { diff --git a/v2/internal/runtime/js/runtime/src/Menu.svelte b/v2/internal/runtime/js/runtime/src/Menu.svelte index f98894a0..ec5839a0 100644 --- a/v2/internal/runtime/js/runtime/src/Menu.svelte +++ b/v2/internal/runtime/js/runtime/src/Menu.svelte @@ -2,19 +2,29 @@ export let menu; - export let hidden = true; + console.log({menu}) + + export let visible = false; + + function click(id) { + console.log("MenuItem", id, "pressed") + } -{#if !hidden} +{#if visible}