From 91d0d963595051236b632577bef429fe11f04f07 Mon Sep 17 00:00:00 2001 From: Lea Anthony Date: Sat, 24 Sep 2022 07:52:19 +1000 Subject: [PATCH 01/36] Add issue translator (#1891) --- .github/workflows/issue-translator.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .github/workflows/issue-translator.yml diff --git a/.github/workflows/issue-translator.yml b/.github/workflows/issue-translator.yml new file mode 100644 index 000000000..ad9d56c35 --- /dev/null +++ b/.github/workflows/issue-translator.yml @@ -0,0 +1,15 @@ +name: 'issue-translator' +on: + issue_comment: + types: [ created ] + issues: + types: [ opened ] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: tomsun28/issues-translate-action@v2.6 + with: + IS_MODIFY_TITLE: false + CUSTOM_BOT_NOTE: The issue body's language is not English, translating it automatically... From 211eb52747744667b93ea9e00e1280ccffe73049 Mon Sep 17 00:00:00 2001 From: Misite Bao Date: Sat, 24 Sep 2022 09:50:57 +0800 Subject: [PATCH 02/36] chore: update the label name in the issue template (#1893) --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- .github/ISSUE_TEMPLATE/documentation.yml | 2 +- .github/ISSUE_TEMPLATE/feature_request.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 1c31a1cba..238453d3b 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,7 +1,7 @@ name: Bug Report description: Create a report to help us improve # title: "" -labels: ["bug"] +labels: ["Bug"] body: - type: markdown diff --git a/.github/ISSUE_TEMPLATE/documentation.yml b/.github/ISSUE_TEMPLATE/documentation.yml index 5124ea777..c1259587b 100644 --- a/.github/ISSUE_TEMPLATE/documentation.yml +++ b/.github/ISSUE_TEMPLATE/documentation.yml @@ -1,7 +1,7 @@ name: Documentation description: Report an issue related to documentation. # title: "" -labels: ["documentation"] +labels: ["Documentation"] body: - type: markdown diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index 292a039a2..b346c0bdc 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -1,7 +1,7 @@ name: Feature request description: Suggest an idea for this project # title: "" -labels: ["enhancement"] +labels: ["Enhancement"] body: - type: markdown From 73b9dead5d37684a14a1f6994620460ecb41bb06 Mon Sep 17 00:00:00 2001 From: Arif Ali <51419655+arifali123@users.noreply.github.com> Date: Fri, 23 Sep 2022 22:05:18 -0700 Subject: [PATCH 03/36] obfuscated instead of obfuscate in the docs (#1895) the option in the docs is the wrong flag you have to add a d at the end --- website/versioned_docs/version-v2.0.0/guides/obfuscated.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/versioned_docs/version-v2.0.0/guides/obfuscated.mdx b/website/versioned_docs/version-v2.0.0/guides/obfuscated.mdx index c062d0f46..2e7906c40 100644 --- a/website/versioned_docs/version-v2.0.0/guides/obfuscated.mdx +++ b/website/versioned_docs/version-v2.0.0/guides/obfuscated.mdx @@ -5,13 +5,13 @@ Wails includes support for obfuscating your application using [garble](https://g To produce an obfuscated build, you can use the `-obfuscate` flag with the `wails build` command: ```bash -wails build -obfuscate +wails build -obfuscated ``` To customise the obfuscation settings, you can use the `-garbleargs` flag: ```bash -wails build -obfuscate -garbleargs "-literals -tiny -seed=myrandomseed" +wails build -obfuscated -garbleargs "-literals -tiny -seed=myrandomseed" ``` These settings may be persisted in your [project config](../reference/project-config). From 953e67e7edc89af3f86995f6d03f5ee7e13c5536 Mon Sep 17 00:00:00 2001 From: stffabi Date: Sat, 24 Sep 2022 10:03:16 +0200 Subject: [PATCH 04/36] [assetHandler] Remove redundant log prefix (#1896) --- v2/internal/frontend/assetserver/assethandler.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/v2/internal/frontend/assetserver/assethandler.go b/v2/internal/frontend/assetserver/assethandler.go index f30869c88..254f88e2c 100644 --- a/v2/internal/frontend/assetserver/assethandler.go +++ b/v2/internal/frontend/assetserver/assethandler.go @@ -71,11 +71,11 @@ func (d *assetHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { filename = indexHTML } - d.logDebug("[AssetHandler] Loading file '%s'", filename) + d.logDebug("Loading file '%s'", filename) if err := d.serveFSFile(rw, filename); err != nil { if os.IsNotExist(err) { if handler != nil { - d.logDebug("[AssetHandler] File '%s' not found, serving '%s' by AssetHandler", filename, req.URL) + d.logDebug("File '%s' not found, serving '%s' by AssetHandler", filename, req.URL) handler.ServeHTTP(rw, req) err = nil } else if filename == indexHTML { @@ -87,12 +87,12 @@ func (d *assetHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { } if err != nil { - d.logError("[AssetHandler] Unable to load file '%s': %s", filename, err) + d.logError("Unable to load file '%s': %s", filename, err) http.Error(rw, err.Error(), http.StatusInternalServerError) } } } else if handler != nil { - d.logDebug("[AssetHandler] No GET request, serving '%s' by AssetHandler", req.URL) + d.logDebug("No GET request, serving '%s' by AssetHandler", req.URL) handler.ServeHTTP(rw, req) } else { rw.WriteHeader(http.StatusMethodNotAllowed) From f5549db85da08f3ec217ea7a56f188f326e56f2c Mon Sep 17 00:00:00 2001 From: stffabi Date: Sun, 25 Sep 2022 13:21:41 +0200 Subject: [PATCH 05/36] [dev] Do not generate bindings in the dev app itself (#1899) * [dev] Pass skip bindings to the building process * [dev] Do not generate bindings in the dev app itself This is done outside during `wails dev` bootstrapping and fast regeneration seems to sometime cause locking problems on Windows. --- v2/cmd/wails/internal/commands/dev/dev.go | 3 +- v2/internal/app/app_dev.go | 36 ----------------------- 2 files changed, 2 insertions(+), 37 deletions(-) diff --git a/v2/cmd/wails/internal/commands/dev/dev.go b/v2/cmd/wails/internal/commands/dev/dev.go index 82051d73d..66b8079cb 100644 --- a/v2/cmd/wails/internal/commands/dev/dev.go +++ b/v2/cmd/wails/internal/commands/dev/dev.go @@ -160,6 +160,7 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error { } buildOptions := generateBuildOptions(flags) + buildOptions.SkipBindings = flags.skipBindings buildOptions.Logger = logger userTags, err := buildtags.Parse(flags.tags) @@ -169,7 +170,7 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error { buildOptions.UserTags = userTags - if !flags.skipBindings { + if !buildOptions.SkipBindings { if flags.verbosity == build.VERBOSE { LogGreen("Generating Bindings...") } diff --git a/v2/internal/app/app_dev.go b/v2/internal/app/app_dev.go index 6951e6644..dc15c138c 100644 --- a/v2/internal/app/app_dev.go +++ b/v2/internal/app/app_dev.go @@ -22,7 +22,6 @@ import ( "github.com/wailsapp/wails/v2/internal/fs" "github.com/wailsapp/wails/v2/internal/logger" "github.com/wailsapp/wails/v2/internal/menumanager" - "github.com/wailsapp/wails/v2/internal/project" pkglogger "github.com/wailsapp/wails/v2/pkg/logger" "github.com/wailsapp/wails/v2/pkg/options" ) @@ -193,10 +192,6 @@ func CreateApp(appoptions *options.App) (*App, error) { } appBindings := binding.NewBindings(myLogger, appoptions.Bind, bindingExemptions, false) - err = generateBindings(appBindings) - if err != nil { - return nil, err - } eventHandler := runtime.NewEvents(myLogger) ctx = context.WithValue(ctx, "events", eventHandler) messageDispatcher := dispatcher.NewDispatcher(ctx, myLogger, appBindings, eventHandler) @@ -223,37 +218,6 @@ func CreateApp(appoptions *options.App) (*App, error) { } -func generateBindings(bindings *binding.Bindings) error { - - cwd, err := os.Getwd() - if err != nil { - return err - } - projectConfig, err := project.Load(cwd) - if err != nil { - return err - } - - if projectConfig.WailsJSDir == "" { - projectConfig.WailsJSDir = filepath.Join(cwd, "frontend") - } - - targetDir := filepath.Join(projectConfig.WailsJSDir, "wailsjs", "go") - err = os.RemoveAll(targetDir) - if err != nil { - return err - } - _ = fs.MkDirs(targetDir) - - err = bindings.GenerateGoBindings(targetDir) - if err != nil { - return err - } - - return nil - -} - func tryInferAssetDirFromFS(assets iofs.FS) (string, error) { if _, isEmbedFs := assets.(embed.FS); !isEmbedFs { // We only infer the assetdir for embed.FS assets From 1571b10b84c11b399377b9ca6cfca391da5819f8 Mon Sep 17 00:00:00 2001 From: Lea Anthony Date: Sun, 25 Sep 2022 22:20:01 +1000 Subject: [PATCH 06/36] Quote command arguments if they have a space (#1892) --- v2/pkg/commands/build/base.go | 16 ++++++++++++++- v2/pkg/commands/build/base_test.go | 31 ++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/v2/pkg/commands/build/base.go b/v2/pkg/commands/build/base.go index 3f9aa62e3..71bc11d63 100644 --- a/v2/pkg/commands/build/base.go +++ b/v2/pkg/commands/build/base.go @@ -108,6 +108,20 @@ func (b *BaseBuilder) CleanUp() { }) } +func commandPrettifier(args []string) string { + // If we have a single argument, just return it + if len(args) == 1 { + return args[0] + } + // If an argument contains a space, quote it + for i, arg := range args { + if strings.Contains(arg, " ") { + args[i] = fmt.Sprintf("\"%s\"", arg) + } + } + return strings.Join(args, " ") +} + func (b *BaseBuilder) OutputFilename(options *Options) string { outputFile := options.OutputFile if outputFile == "" { @@ -270,7 +284,7 @@ func (b *BaseBuilder) CompileProject(options *Options) error { cmd := exec.Command(compiler, commands.AsSlice()...) cmd.Stderr = os.Stderr if verbose { - println(" Build command:", compiler, commands.Join(" ")) + println(" Build command:", compiler, commandPrettifier(commands.AsSlice())) cmd.Stdout = os.Stdout } // Set the directory diff --git a/v2/pkg/commands/build/base_test.go b/v2/pkg/commands/build/base_test.go index e1ad53482..e44c077d4 100644 --- a/v2/pkg/commands/build/base_test.go +++ b/v2/pkg/commands/build/base_test.go @@ -35,3 +35,34 @@ func TestUpdateEnv(t *testing.T) { } } + +func Test_commandPrettifier(t *testing.T) { + tests := []struct { + name string + input []string + want string + }{ + { + name: "empty", + input: []string{}, + want: "", + }, + { + name: "one arg", + input: []string{"one"}, + want: "one", + }, + { + name: "args where one has spaces", + input: []string{"one", "two three"}, + want: `one "two three"`, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := commandPrettifier(tt.input); got != tt.want { + t.Errorf("commandPrettifier() = %v, want %v", got, tt.want) + } + }) + } +} From 52845a7ca56cfe10802d39237ecbe11227a3de50 Mon Sep 17 00:00:00 2001 From: Lea Anthony Date: Mon, 26 Sep 2022 17:54:56 +1000 Subject: [PATCH 07/36] chore: Update release workflow --- .github/workflows/release.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5a763d836..abb872de7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,8 +3,6 @@ name: Release on: push: branches: [ release/* ] - pull_request: - branches: [ release/* ] workflow_dispatch: jobs: From 9f8101353095616c48b243841118781ece0955e0 Mon Sep 17 00:00:00 2001 From: Lea Anthony Date: Mon, 26 Sep 2022 18:00:38 +1000 Subject: [PATCH 08/36] chore: Update workflows --- .github/workflows/check_docs.yml | 1 + .github/workflows/generate-sponsor-image.yml | 1 + .github/workflows/issue-translator.yml | 1 + .github/workflows/label-sponsors.yml | 1 + .github/workflows/pr.yml | 1 + .github/workflows/projects.yml | 1 + .github/workflows/release.yml | 2 +- 7 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/check_docs.yml b/.github/workflows/check_docs.yml index 6433f7073..0768f1970 100644 --- a/.github/workflows/check_docs.yml +++ b/.github/workflows/check_docs.yml @@ -6,6 +6,7 @@ on: jobs: docs: name: Website Updated + if: github.repository == 'wailsapp/wails' runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/generate-sponsor-image.yml b/.github/workflows/generate-sponsor-image.yml index 711a7b1bb..e7d71c302 100644 --- a/.github/workflows/generate-sponsor-image.yml +++ b/.github/workflows/generate-sponsor-image.yml @@ -10,6 +10,7 @@ on: jobs: update-sponsors: runs-on: ubuntu-latest + if: github.repository == 'wailsapp/wails' steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/issue-translator.yml b/.github/workflows/issue-translator.yml index ad9d56c35..ed029f49d 100644 --- a/.github/workflows/issue-translator.yml +++ b/.github/workflows/issue-translator.yml @@ -8,6 +8,7 @@ on: jobs: build: runs-on: ubuntu-latest + if: github.repository == 'wailsapp/wails' steps: - uses: tomsun28/issues-translate-action@v2.6 with: diff --git a/.github/workflows/label-sponsors.yml b/.github/workflows/label-sponsors.yml index fdaacb3cc..28bda63b8 100644 --- a/.github/workflows/label-sponsors.yml +++ b/.github/workflows/label-sponsors.yml @@ -7,6 +7,7 @@ on: jobs: build: name: is-sponsor-label + if: github.repository == 'wailsapp/wails' runs-on: ubuntu-latest steps: - uses: JasonEtco/is-sponsor-label-action@v1 diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 94691c804..be913c5a3 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -5,6 +5,7 @@ on: jobs: check_branch_name: runs-on: ubuntu-latest + if: github.repository == 'wailsapp/wails' name: Check branch name steps: - run: | diff --git a/.github/workflows/projects.yml b/.github/workflows/projects.yml index 1217e6230..3b81c64e7 100644 --- a/.github/workflows/projects.yml +++ b/.github/workflows/projects.yml @@ -7,6 +7,7 @@ on: jobs: projectcardautolabel_job: runs-on: ubuntu-latest + if: github.repository == 'wailsapp/wails' steps: - name: Run ProjectCard AutoLabel id: runprojectcardautolabel diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index abb872de7..30dceb206 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -8,6 +8,7 @@ on: jobs: test: name: Run Go Tests + if: github.repository == 'wailsapp/wails' runs-on: ${{ matrix.os }} strategy: matrix: @@ -33,7 +34,6 @@ jobs: test_templates: name: Test Templates needs: test - if: github.repository == 'wailsapp/wails' runs-on: ${{ matrix.os }} strategy: fail-fast: true From 2d61278125329809a852e2f2d7204b91def6971b Mon Sep 17 00:00:00 2001 From: ALMAS Date: Mon, 26 Sep 2022 18:43:28 +0800 Subject: [PATCH 09/36] Update Chinese translation (#1894) Co-authored-by: Lea Anthony --- .../version-v2.0.0/gettingstarted/firstproject.mdx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-v2.0.0/gettingstarted/firstproject.mdx b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-v2.0.0/gettingstarted/firstproject.mdx index 3c22691b7..e789438b0 100644 --- a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-v2.0.0/gettingstarted/firstproject.mdx +++ b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-v2.0.0/gettingstarted/firstproject.mdx @@ -116,10 +116,10 @@ Wails 项目有以下布局: - `/main.go` - 主应用 - `/frontend/` - 前端项目文件 - `/build/` - 项目构建目录 -- `/wails.json` - 应用程序图标 -- `/go.mod` - Mac 特定的项目文件 -- `/go.sum` - Windows 特定的项目文件 -- `/build/windows/` - 项目配置 +- `/build/appicon.png` - 应用程序图标 +- `/build/darwin/` - Mac 特定的项目文件 +- `/build/windows/` - Windows 特定的项目文件 +- `/wails.json` - 项目配置 - `/go.mod` - Go module 文件 - `/go.sum` - Go module 校验文件 From e22cfc18c96781c21ac431bf9296740762f75977 Mon Sep 17 00:00:00 2001 From: Lea Anthony Date: Wed, 28 Sep 2022 08:32:14 +1000 Subject: [PATCH 10/36] Update howdoesitwork.mdx --- website/docs/howdoesitwork.mdx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/website/docs/howdoesitwork.mdx b/website/docs/howdoesitwork.mdx index 717e8e2d2..872e847f3 100644 --- a/website/docs/howdoesitwork.mdx +++ b/website/docs/howdoesitwork.mdx @@ -264,11 +264,12 @@ In the example above, `Greet` only returns a `string` so the Javascript call wil is passed to it. All data types are correctly translated between Go and Javascript. Even structs. If you return a struct from a Go call, -it will be returned to your frontend as a Javascript class. Note: If you wish to use structs, you **must** define -`json` struct tags for your fields! +it will be returned to your frontend as a Javascript class. :::info Note +Struct fields *must* have a valid `json` tag to be included in the generated Typescript. + Anonymous nested structs are not supported at this time. ::: From b2069c871ddb9dc5a530e927e7559e90731cb152 Mon Sep 17 00:00:00 2001 From: Lea Anthony Date: Thu, 29 Sep 2022 18:43:35 +1000 Subject: [PATCH 11/36] Refactor app (#1909) * Application refactor * [windows] refactor out main loop. Create new application struct. Refactor assethandler/assetserver signatures. * Refactor darwin app * Refactor app for linux * Update v2/internal/frontend/assetserver/assethandler.go Co-authored-by: stffabi * Update v2/internal/frontend/assetserver/assethandler.go Co-authored-by: stffabi * Update v2/internal/frontend/assetserver/assetserver.go Co-authored-by: stffabi * Update v2/internal/frontend/assetserver/assetserver.go Co-authored-by: stffabi Co-authored-by: stffabi --- v2/go.mod | 2 +- v2/internal/app/app.go | 41 ++++++++++ v2/internal/app/app_bindings.go | 23 ++---- v2/internal/app/app_darwin.go | 16 ---- v2/internal/app/app_debug.go | 1 - .../{app_not_debug.go => app_debug_not.go} | 1 - v2/internal/app/app_default_darwin.go | 24 ------ ...p_default_linux.go => app_default_unix.go} | 8 +- v2/internal/app/app_default_windows.go | 6 -- v2/internal/app/app_dev.go | 25 +------ v2/internal/app/app_linux.go | 16 ---- ...ot_obfuscated.go => app_obfuscated_not.go} | 0 v2/internal/app/app_preflight_unix.go | 12 +++ ...pp_windows.go => app_preflight_windows.go} | 1 - v2/internal/app/app_production.go | 24 +----- .../frontend/assetserver/assethandler.go | 6 +- .../frontend/assetserver/assetserver.go | 6 +- .../frontend/desktop/darwin/Application.h | 2 + .../frontend/desktop/darwin/Application.m | 8 ++ .../frontend/desktop/darwin/frontend.go | 10 ++- .../frontend/desktop/linux/frontend.go | 10 ++- v2/internal/frontend/desktop/linux/window.go | 2 - .../frontend/desktop/windows/frontend.go | 15 +++- v2/internal/frontend/desktop/windows/theme.go | 2 +- .../frontend/desktop/windows/window.go | 15 ++-- v2/internal/frontend/frontend.go | 4 +- v2/pkg/application/application.go | 75 +++++++++++++++++++ v2/{ => pkg/application}/init.go | 4 +- v2/{ => pkg/application}/init_windows.go | 7 +- v2/pkg/options/options.go | 4 +- v2/wails.go | 33 +------- 31 files changed, 205 insertions(+), 198 deletions(-) create mode 100644 v2/internal/app/app.go delete mode 100644 v2/internal/app/app_darwin.go rename v2/internal/app/{app_not_debug.go => app_debug_not.go} (80%) delete mode 100644 v2/internal/app/app_default_darwin.go rename v2/internal/app/{app_default_linux.go => app_default_unix.go} (60%) delete mode 100644 v2/internal/app/app_linux.go rename v2/internal/app/{app_not_obfuscated.go => app_obfuscated_not.go} (100%) create mode 100644 v2/internal/app/app_preflight_unix.go rename v2/internal/app/{app_windows.go => app_preflight_windows.go} (96%) create mode 100644 v2/pkg/application/application.go rename v2/{ => pkg/application}/init.go (51%) rename v2/{ => pkg/application}/init_windows.go (72%) diff --git a/v2/go.mod b/v2/go.mod index eb538b381..b5533fcb9 100644 --- a/v2/go.mod +++ b/v2/go.mod @@ -1,6 +1,6 @@ module github.com/wailsapp/wails/v2 -go 1.19 +go 1.18 require ( github.com/Masterminds/semver v1.5.0 diff --git a/v2/internal/app/app.go b/v2/internal/app/app.go new file mode 100644 index 000000000..f2821aaba --- /dev/null +++ b/v2/internal/app/app.go @@ -0,0 +1,41 @@ +package app + +import ( + "context" + "github.com/wailsapp/wails/v2/internal/frontend" + "github.com/wailsapp/wails/v2/internal/logger" + "github.com/wailsapp/wails/v2/internal/menumanager" + "github.com/wailsapp/wails/v2/pkg/menu" + "github.com/wailsapp/wails/v2/pkg/options" +) + +// App defines a Wails application structure +type App struct { + frontend frontend.Frontend + logger *logger.Logger + options *options.App + + menuManager *menumanager.Manager + + // Indicates if the app is in debug mode + debug bool + + // OnStartup/OnShutdown + startupCallback func(ctx context.Context) + shutdownCallback func(ctx context.Context) + ctx context.Context +} + +// Shutdown the application +func (a *App) Shutdown() { + if a.frontend != nil { + a.frontend.Quit() + } +} + +// SetApplicationMenu sets the application menu +func (a *App) SetApplicationMenu(menu *menu.Menu) { + if a.frontend != nil { + a.frontend.MenuSetApplicationMenu(menu) + } +} diff --git a/v2/internal/app/app_bindings.go b/v2/internal/app/app_bindings.go index f0e059213..b87f41cd8 100644 --- a/v2/internal/app/app_bindings.go +++ b/v2/internal/app/app_bindings.go @@ -1,5 +1,4 @@ //go:build bindings -// +build bindings package app @@ -16,23 +15,17 @@ import ( "github.com/wailsapp/wails/v2/pkg/options" ) -// App defines a Wails application structure -type App struct { - logger *logger.Logger - appoptions *options.App -} - func (a *App) Run() error { // Create binding exemptions - Ugly hack. There must be a better way bindingExemptions := []interface{}{ - a.appoptions.OnStartup, - a.appoptions.OnShutdown, - a.appoptions.OnDomReady, - a.appoptions.OnBeforeClose, + a.options.OnStartup, + a.options.OnShutdown, + a.options.OnDomReady, + a.options.OnBeforeClose, } - appBindings := binding.NewBindings(a.logger, a.appoptions.Bind, bindingExemptions, IsObfuscated()) + appBindings := binding.NewBindings(a.logger, a.options.Bind, bindingExemptions, IsObfuscated()) err := generateBindings(appBindings) if err != nil { @@ -41,8 +34,6 @@ func (a *App) Run() error { return nil } -func (a *App) Shutdown() {} - // CreateApp creates the app! func CreateApp(appoptions *options.App) (*App, error) { // Set up logger @@ -50,8 +41,8 @@ func CreateApp(appoptions *options.App) (*App, error) { myLogger.SetLogLevel(appoptions.LogLevel) result := &App{ - logger: myLogger, - appoptions: appoptions, + logger: myLogger, + options: appoptions, } return result, nil diff --git a/v2/internal/app/app_darwin.go b/v2/internal/app/app_darwin.go deleted file mode 100644 index 939f724a4..000000000 --- a/v2/internal/app/app_darwin.go +++ /dev/null @@ -1,16 +0,0 @@ -//go:build darwin && !bindings -// +build darwin,!bindings - -package app - -import ( - "github.com/wailsapp/wails/v2/internal/logger" - "github.com/wailsapp/wails/v2/pkg/options" -) - -func PreflightChecks(options *options.App, logger *logger.Logger) error { - - _ = options - - return nil -} diff --git a/v2/internal/app/app_debug.go b/v2/internal/app/app_debug.go index bfcdd13b4..c14bedec1 100644 --- a/v2/internal/app/app_debug.go +++ b/v2/internal/app/app_debug.go @@ -1,5 +1,4 @@ //go:build debug -// +build debug package app diff --git a/v2/internal/app/app_not_debug.go b/v2/internal/app/app_debug_not.go similarity index 80% rename from v2/internal/app/app_not_debug.go rename to v2/internal/app/app_debug_not.go index b20a7c80f..04f841ede 100644 --- a/v2/internal/app/app_not_debug.go +++ b/v2/internal/app/app_debug_not.go @@ -1,5 +1,4 @@ //go:build !debug -// +build !debug package app diff --git a/v2/internal/app/app_default_darwin.go b/v2/internal/app/app_default_darwin.go deleted file mode 100644 index b31a002fd..000000000 --- a/v2/internal/app/app_default_darwin.go +++ /dev/null @@ -1,24 +0,0 @@ -//go:build !dev && !production && !bindings && darwin -// +build !dev,!production,!bindings,darwin - -package app - -import ( - "fmt" - - "github.com/wailsapp/wails/v2/pkg/options" -) - -// App defines a Wails application structure -type App struct{} - -func (a *App) Run() error { - return nil -} - -func (a *App) Shutdown() {} - -// CreateApp creates the app! -func CreateApp(_ *options.App) (*App, error) { - return nil, fmt.Errorf(`Wails applications will not build without the correct build tags.`) -} diff --git a/v2/internal/app/app_default_linux.go b/v2/internal/app/app_default_unix.go similarity index 60% rename from v2/internal/app/app_default_linux.go rename to v2/internal/app/app_default_unix.go index 2a2f1770d..10d801285 100644 --- a/v2/internal/app/app_default_linux.go +++ b/v2/internal/app/app_default_unix.go @@ -1,5 +1,4 @@ -//go:build !dev && !production && !bindings && linux -// +build !dev,!production,!bindings,linux +//go:build !dev && !production && !bindings && (linux || darwin) package app @@ -9,15 +8,10 @@ import ( "github.com/wailsapp/wails/v2/pkg/options" ) -// App defines a Wails application structure -type App struct{} - func (a *App) Run() error { return nil } -func (a *App) Shutdown() {} - // CreateApp creates the app! func CreateApp(_ *options.App) (*App, error) { return nil, fmt.Errorf(`Wails applications will not build without the correct build tags.`) diff --git a/v2/internal/app/app_default_windows.go b/v2/internal/app/app_default_windows.go index a05ef2a53..b1b66a081 100644 --- a/v2/internal/app/app_default_windows.go +++ b/v2/internal/app/app_default_windows.go @@ -1,5 +1,4 @@ //go:build !dev && !production && !bindings && windows -// +build !dev,!production,!bindings,windows package app @@ -10,15 +9,10 @@ import ( "github.com/wailsapp/wails/v2/pkg/options" ) -// App defines a Wails application structure -type App struct{} - func (a *App) Run() error { return nil } -func (a *App) Shutdown() {} - // CreateApp creates the app! func CreateApp(_ *options.App) (*App, error) { result := w32.MessageBox(0, diff --git a/v2/internal/app/app_dev.go b/v2/internal/app/app_dev.go index dc15c138c..ac29a9aa5 100644 --- a/v2/internal/app/app_dev.go +++ b/v2/internal/app/app_dev.go @@ -1,5 +1,4 @@ //go:build dev -// +build dev package app @@ -14,7 +13,6 @@ import ( "path/filepath" "github.com/wailsapp/wails/v2/internal/binding" - "github.com/wailsapp/wails/v2/internal/frontend" "github.com/wailsapp/wails/v2/internal/frontend/desktop" "github.com/wailsapp/wails/v2/internal/frontend/devserver" "github.com/wailsapp/wails/v2/internal/frontend/dispatcher" @@ -26,29 +24,10 @@ import ( "github.com/wailsapp/wails/v2/pkg/options" ) -// App defines a Wails application structure -type App struct { - frontend frontend.Frontend - logger *logger.Logger - options *options.App - - menuManager *menumanager.Manager - - // Indicates if the app is in debug mode - debug bool - - // OnStartup/OnShutdown - startupCallback func(ctx context.Context) - shutdownCallback func(ctx context.Context) - ctx context.Context -} - -func (a *App) Shutdown() { - a.frontend.Quit() -} - func (a *App) Run() error { err := a.frontend.Run(a.ctx) + a.frontend.RunMainLoop() + a.frontend.WindowClose() if a.shutdownCallback != nil { a.shutdownCallback(a.ctx) } diff --git a/v2/internal/app/app_linux.go b/v2/internal/app/app_linux.go deleted file mode 100644 index 154cd38e4..000000000 --- a/v2/internal/app/app_linux.go +++ /dev/null @@ -1,16 +0,0 @@ -//go:build linux && !bindings -// +build linux,!bindings - -package app - -import ( - "github.com/wailsapp/wails/v2/internal/logger" - "github.com/wailsapp/wails/v2/pkg/options" -) - -func PreflightChecks(options *options.App, logger *logger.Logger) error { - - _ = options - - return nil -} diff --git a/v2/internal/app/app_not_obfuscated.go b/v2/internal/app/app_obfuscated_not.go similarity index 100% rename from v2/internal/app/app_not_obfuscated.go rename to v2/internal/app/app_obfuscated_not.go diff --git a/v2/internal/app/app_preflight_unix.go b/v2/internal/app/app_preflight_unix.go new file mode 100644 index 000000000..f554df740 --- /dev/null +++ b/v2/internal/app/app_preflight_unix.go @@ -0,0 +1,12 @@ +//go:build (linux || darwin) && !bindings + +package app + +import ( + "github.com/wailsapp/wails/v2/internal/logger" + "github.com/wailsapp/wails/v2/pkg/options" +) + +func PreflightChecks(_ *options.App, _ *logger.Logger) error { + return nil +} diff --git a/v2/internal/app/app_windows.go b/v2/internal/app/app_preflight_windows.go similarity index 96% rename from v2/internal/app/app_windows.go rename to v2/internal/app/app_preflight_windows.go index affc33736..1b71b8b19 100644 --- a/v2/internal/app/app_windows.go +++ b/v2/internal/app/app_preflight_windows.go @@ -1,5 +1,4 @@ //go:build windows && !bindings -// +build windows,!bindings package app diff --git a/v2/internal/app/app_production.go b/v2/internal/app/app_production.go index cd1bfb933..245d375ce 100644 --- a/v2/internal/app/app_production.go +++ b/v2/internal/app/app_production.go @@ -6,7 +6,6 @@ import ( "context" "github.com/wailsapp/wails/v2/internal/binding" - "github.com/wailsapp/wails/v2/internal/frontend" "github.com/wailsapp/wails/v2/internal/frontend/desktop" "github.com/wailsapp/wails/v2/internal/frontend/dispatcher" "github.com/wailsapp/wails/v2/internal/frontend/runtime" @@ -15,29 +14,10 @@ import ( "github.com/wailsapp/wails/v2/pkg/options" ) -// App defines a Wails application structure -type App struct { - frontend frontend.Frontend - logger *logger.Logger - options *options.App - - menuManager *menumanager.Manager - - // Indicates if the app is in debug mode - debug bool - - // OnStartup/OnShutdown - startupCallback func(ctx context.Context) - shutdownCallback func(ctx context.Context) - ctx context.Context -} - -func (a *App) Shutdown() { - a.frontend.Quit() -} - func (a *App) Run() error { err := a.frontend.Run(a.ctx) + a.frontend.RunMainLoop() + a.frontend.WindowClose() if a.shutdownCallback != nil { a.shutdownCallback(a.ctx) } diff --git a/v2/internal/frontend/assetserver/assethandler.go b/v2/internal/frontend/assetserver/assethandler.go index 254f88e2c..ca73be4d2 100644 --- a/v2/internal/frontend/assetserver/assethandler.go +++ b/v2/internal/frontend/assetserver/assethandler.go @@ -14,7 +14,6 @@ import ( "github.com/wailsapp/wails/v2/internal/fs" "github.com/wailsapp/wails/v2/internal/logger" - "github.com/wailsapp/wails/v2/pkg/options" ) //go:embed defaultindex.html @@ -33,8 +32,7 @@ type assetHandler struct { retryMissingFiles bool } -func NewAssetHandler(ctx context.Context, options *options.App) (http.Handler, error) { - vfs := options.Assets +func NewAssetHandler(ctx context.Context, vfs iofs.FS, assetsHandler http.Handler) (http.Handler, error) { if vfs != nil { if _, err := vfs.Open("."); err != nil { return nil, err @@ -53,7 +51,7 @@ func NewAssetHandler(ctx context.Context, options *options.App) (http.Handler, e result := &assetHandler{ fs: vfs, - handler: options.AssetsHandler, + handler: assetsHandler, } if _logger := ctx.Value("logger"); _logger != nil { diff --git a/v2/internal/frontend/assetserver/assetserver.go b/v2/internal/frontend/assetserver/assetserver.go index fb47f881d..5fff282f2 100644 --- a/v2/internal/frontend/assetserver/assetserver.go +++ b/v2/internal/frontend/assetserver/assetserver.go @@ -4,13 +4,13 @@ import ( "bytes" "context" "fmt" + iofs "io/fs" "net/http" "net/http/httptest" "strconv" "github.com/wailsapp/wails/v2/internal/frontend/runtime" "github.com/wailsapp/wails/v2/internal/logger" - "github.com/wailsapp/wails/v2/pkg/options" "golang.org/x/net/html" ) @@ -31,8 +31,8 @@ type AssetServer struct { appendSpinnerToBody bool } -func NewAssetServer(ctx context.Context, options *options.App, bindingsJSON string) (*AssetServer, error) { - handler, err := NewAssetHandler(ctx, options) +func NewAssetServer(ctx context.Context, vfs iofs.FS, assetsHandler http.Handler, bindingsJSON string) (*AssetServer, error) { + handler, err := NewAssetHandler(ctx, vfs, assetsHandler) if err != nil { return nil, err } diff --git a/v2/internal/frontend/desktop/darwin/Application.h b/v2/internal/frontend/desktop/darwin/Application.h index d19c4ed93..94859f770 100644 --- a/v2/internal/frontend/desktop/darwin/Application.h +++ b/v2/internal/frontend/desktop/darwin/Application.h @@ -67,6 +67,8 @@ void SetAbout(void *inctx, const char* title, const char* description, void* ima void* AppendMenuItem(void* inctx, void* nsmenu, const char* label, const char* shortcutKey, int modifiers, int disabled, int checked, int menuItemID); void AppendSeparator(void* inMenu); void UpdateMenuItem(void* nsmenuitem, int checked); +void RunMainLoop(void); +void ReleaseContext(void *inctx); NSString* safeInit(const char* input); diff --git a/v2/internal/frontend/desktop/darwin/Application.m b/v2/internal/frontend/desktop/darwin/Application.m index 7b8ddcc42..6b413036c 100644 --- a/v2/internal/frontend/desktop/darwin/Application.m +++ b/v2/internal/frontend/desktop/darwin/Application.m @@ -381,6 +381,14 @@ void Run(void *inctx, const char* url) { [_url release]; [app setMainMenu:ctx.applicationMenu]; +} + +void RunMainLoop(void) { + NSApplication *app = [NSApplication sharedApplication]; [app run]; +} + +void ReleaseContext(void *inctx) { + WailsContext *ctx = (__bridge WailsContext*) inctx; [ctx release]; } diff --git a/v2/internal/frontend/desktop/darwin/frontend.go b/v2/internal/frontend/desktop/darwin/frontend.go index 46ce478b8..ea157347e 100644 --- a/v2/internal/frontend/desktop/darwin/frontend.go +++ b/v2/internal/frontend/desktop/darwin/frontend.go @@ -59,6 +59,14 @@ type Frontend struct { dispatcher frontend.Dispatcher } +func (f *Frontend) RunMainLoop() { + C.RunMainLoop() +} + +func (f *Frontend) WindowClose() { + C.ReleaseContext(f.mainWindow.context) +} + func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger.Logger, appBindings *binding.Bindings, dispatcher frontend.Dispatcher) *Frontend { result := &Frontend{ frontendOptions: appoptions, @@ -82,7 +90,7 @@ func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger. } else { appBindings.DB().UpdateObfuscatedCallMap() } - assets, err := assetserver.NewAssetServer(ctx, appoptions, bindings) + assets, err := assetserver.NewAssetServer(ctx, appoptions.Assets, appoptions.AssetsHandler, bindings) if err != nil { log.Fatal(err) } diff --git a/v2/internal/frontend/desktop/linux/frontend.go b/v2/internal/frontend/desktop/linux/frontend.go index 64065a270..dce5b2531 100644 --- a/v2/internal/frontend/desktop/linux/frontend.go +++ b/v2/internal/frontend/desktop/linux/frontend.go @@ -52,6 +52,14 @@ type Frontend struct { dispatcher frontend.Dispatcher } +func (f *Frontend) RunMainLoop() { + C.gtk_main() +} + +func (f *Frontend) WindowClose() { + f.mainWindow.Destroy() +} + func init() { runtime.LockOSThread() } @@ -85,7 +93,7 @@ func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger. } else { appBindings.DB().UpdateObfuscatedCallMap() } - assets, err := assetserver.NewAssetServer(ctx, appoptions, bindings) + assets, err := assetserver.NewAssetServer(ctx, appoptions.Assets, appoptions.AssetsHandler, bindings) if err != nil { log.Fatal(err) } diff --git a/v2/internal/frontend/desktop/linux/window.go b/v2/internal/frontend/desktop/linux/window.go index a3ab6f85d..ef6ecafb6 100644 --- a/v2/internal/frontend/desktop/linux/window.go +++ b/v2/internal/frontend/desktop/linux/window.go @@ -861,8 +861,6 @@ func (w *Window) Run(url string) { w.Maximise() } - C.gtk_main() - w.Destroy() } func (w *Window) SetKeepAbove(top bool) { diff --git a/v2/internal/frontend/desktop/windows/frontend.go b/v2/internal/frontend/desktop/windows/frontend.go index a5d13f4c5..59c3dcbdb 100644 --- a/v2/internal/frontend/desktop/windows/frontend.go +++ b/v2/internal/frontend/desktop/windows/frontend.go @@ -102,7 +102,7 @@ func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger. appBindings.DB().UpdateObfuscatedCallMap() } - assets, err := assetserver.NewAssetServer(ctx, appoptions, bindings) + assets, err := assetserver.NewAssetServer(ctx, appoptions.Assets, appoptions.AssetsHandler, bindings) if err != nil { log.Fatal(err) } @@ -180,11 +180,20 @@ func (f *Frontend) Run(ctx context.Context) error { f.frontendOptions.OnStartup(f.ctx) } }() - mainWindow.Run() - mainWindow.Close() + mainWindow.UpdateTheme() return nil } +func (f *Frontend) WindowClose() { + if f.mainWindow != nil { + f.mainWindow.Close() + } +} + +func (f *Frontend) RunMainLoop() { + _ = winc.RunMainLoop() +} + func (f *Frontend) WindowCenter() { runtime.LockOSThread() defer runtime.UnlockOSThread() diff --git a/v2/internal/frontend/desktop/windows/theme.go b/v2/internal/frontend/desktop/windows/theme.go index 897133026..e22f0c6cd 100644 --- a/v2/internal/frontend/desktop/windows/theme.go +++ b/v2/internal/frontend/desktop/windows/theme.go @@ -5,7 +5,7 @@ import ( "github.com/wailsapp/wails/v2/pkg/options/windows" ) -func (w *Window) updateTheme() { +func (w *Window) UpdateTheme() { // Don't redraw theme if nothing has changed if !w.themeChanged { diff --git a/v2/internal/frontend/desktop/windows/window.go b/v2/internal/frontend/desktop/windows/window.go index 1b511d34f..03c8807ce 100644 --- a/v2/internal/frontend/desktop/windows/window.go +++ b/v2/internal/frontend/desktop/windows/window.go @@ -99,7 +99,7 @@ func NewWindow(parent winc.Controller, appoptions *options.App, versionInfo *ope result.SetMaxSize(appoptions.MaxWidth, appoptions.MaxHeight) } - result.updateTheme() + result.UpdateTheme() if appoptions.Windows != nil { result.OnSuspend = appoptions.Windows.OnSuspend @@ -129,11 +129,6 @@ func NewWindow(parent winc.Controller, appoptions *options.App, versionInfo *ope return result } -func (w *Window) Run() int { - w.updateTheme() - return winc.RunMainLoop() -} - func (w *Window) Fullscreen() { w.Form.SetMaxSize(0, 0) w.Form.SetMinSize(0, 0) @@ -190,7 +185,7 @@ func (w *Window) WndProc(msg uint32, wparam, lparam uintptr) uintptr { settingChanged := w32.UTF16PtrToString((*uint16)(unsafe.Pointer(lparam))) if settingChanged == "ImmersiveColorSet" { w.themeChanged = true - w.updateTheme() + w.UpdateTheme() } return 0 case w32.WM_NCLBUTTONDOWN: @@ -204,10 +199,10 @@ func (w *Window) WndProc(msg uint32, wparam, lparam uintptr) uintptr { w.themeChanged = true if int(wparam) == w32.WA_INACTIVE { w.isActive = false - w.updateTheme() + w.UpdateTheme() } else { w.isActive = true - w.updateTheme() + w.UpdateTheme() //} } @@ -303,6 +298,6 @@ func (w *Window) SetTheme(theme winoptions.Theme) { w.theme = theme w.themeChanged = true w.Invoke(func() { - w.updateTheme() + w.UpdateTheme() }) } diff --git a/v2/internal/frontend/frontend.go b/v2/internal/frontend/frontend.go index 979e3dc3e..93449a9a0 100644 --- a/v2/internal/frontend/frontend.go +++ b/v2/internal/frontend/frontend.go @@ -10,7 +10,7 @@ import ( // FileFilter defines a filter for dialog boxes type FileFilter struct { DisplayName string // Filter information EG: "Image Files (*.jpg, *.png)" - Pattern string // semi-colon separated list of extensions, EG: "*.jpg;*.png" + Pattern string // semicolon separated list of extensions, EG: "*.jpg;*.png" } // OpenDialogOptions contains the options for the OpenDialogOptions runtime method @@ -65,6 +65,7 @@ type MessageDialogOptions struct { type Frontend interface { Run(context.Context) error + RunMainLoop() Hide() Show() Quit() @@ -105,6 +106,7 @@ type Frontend interface { WindowIsMinimised() bool WindowIsNormal() bool WindowIsFullscreen() bool + WindowClose() //Screen ScreenGetAll() ([]Screen, error) diff --git a/v2/pkg/application/application.go b/v2/pkg/application/application.go new file mode 100644 index 000000000..205ef6bfb --- /dev/null +++ b/v2/pkg/application/application.go @@ -0,0 +1,75 @@ +package application + +import ( + "github.com/wailsapp/wails/v2/internal/app" + "github.com/wailsapp/wails/v2/internal/signal" + "github.com/wailsapp/wails/v2/pkg/menu" + "github.com/wailsapp/wails/v2/pkg/options" +) + +// Application is the main Wails application +type Application struct { + application *app.App + options *options.App + + // running flag + running bool +} + +// NewWithOptions creates a new Application with the given options +func NewWithOptions(options *options.App) *Application { + if options == nil { + return New() + } + return &Application{ + options: options, + } +} + +// New creates a new Application with the default options +func New() *Application { + return &Application{ + options: &options.App{}, + } +} + +// SetApplicationMenu sets the application menu +func (a *Application) SetApplicationMenu(appMenu *menu.Menu) { + if a.running { + a.application.SetApplicationMenu(appMenu) + return + } + + a.options.Menu = appMenu +} + +// Run starts the application +func (a *Application) Run() error { + + err := applicationInit() + if err != nil { + return err + } + + application, err := app.CreateApp(a.options) + if err != nil { + return err + } + + a.application = application + + // Control-C handlers + signal.OnShutdown(func() { + a.application.Shutdown() + }) + signal.Start() + + a.running = true + + return a.application.Run() +} + +// Quit will shut down the application +func (a *Application) Quit() { + a.application.Shutdown() +} diff --git a/v2/init.go b/v2/pkg/application/init.go similarity index 51% rename from v2/init.go rename to v2/pkg/application/init.go index d6652f014..0fc48cb05 100644 --- a/v2/init.go +++ b/v2/pkg/application/init.go @@ -1,8 +1,8 @@ //go:build !windows // +build !windows -package wails +package application -func Init() error { +func applicationInit() error { return nil } diff --git a/v2/init_windows.go b/v2/pkg/application/init_windows.go similarity index 72% rename from v2/init_windows.go rename to v2/pkg/application/init_windows.go index 173da0a89..7d2900d3d 100644 --- a/v2/init_windows.go +++ b/v2/pkg/application/init_windows.go @@ -1,12 +1,13 @@ -package wails +//go:build windows + +package application import ( "fmt" "syscall" ) -// Init is called at the start of the application -func Init() error { +func applicationInit() error { status, r, err := syscall.NewLazyDLL("user32.dll").NewProc("SetProcessDPIAware").Call() if status == 0 { return fmt.Errorf("exit status %d: %v %v", status, r, err) diff --git a/v2/pkg/options/options.go b/v2/pkg/options/options.go index 1f0a3532b..25f619b6b 100644 --- a/v2/pkg/options/options.go +++ b/v2/pkg/options/options.go @@ -47,9 +47,7 @@ type App struct { AlwaysOnTop bool // BackgroundColour is the background colour of the window // You can use the options.NewRGB and options.NewRGBA functions to create a new colour - BackgroundColour *RGBA - // RGBA is deprecated. Please use BackgroundColour - RGBA *RGBA + BackgroundColour *RGBA Assets fs.FS AssetsHandler http.Handler Menu *menu.Menu diff --git a/v2/wails.go b/v2/wails.go index dec83b810..54be64ca2 100644 --- a/v2/wails.go +++ b/v2/wails.go @@ -3,40 +3,13 @@ package wails import ( - "github.com/wailsapp/wails/v2/internal/app" _ "github.com/wailsapp/wails/v2/internal/goversion" // Add Compile-Time version check for minimum go version - "github.com/wailsapp/wails/v2/internal/signal" + "github.com/wailsapp/wails/v2/pkg/application" "github.com/wailsapp/wails/v2/pkg/options" ) // Run creates an application based on the given config and executes it func Run(options *options.App) error { - - if options.RGBA != nil { - println("---- WARNING ----") - println("The `RGBA` option has been deprecated. Please use `BackgroundColour`.") - - if options.BackgroundColour == nil { - options.BackgroundColour = options.RGBA - } - } - - // Call an Init method manually - err := Init() - if err != nil { - return err - } - - mainapp, err := app.CreateApp(options) - if err != nil { - return err - } - - signal.OnShutdown(func() { - mainapp.Shutdown() - }) - - signal.Start() - - return mainapp.Run() + mainApp := application.NewWithOptions(options) + return mainApp.Run() } From 941218d1c81b9a2f5e5cd04f065139f89e4f142b Mon Sep 17 00:00:00 2001 From: Lea Anthony Date: Thu, 29 Sep 2022 20:51:41 +1000 Subject: [PATCH 12/36] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9312d7057..82db59040 100644 --- a/README.md +++ b/README.md @@ -115,7 +115,7 @@ This project is supported by these kind people / companies: ## Stargazers over time -[![Stargazers over time](https://starchart.cc/wailsapp/wails.svg)](https://starchart.cc/wailsapp/wails) +[![Star History Chart](https://api.star-history.com/svg?repos=wailsapp/wails&type=Date)](https://star-history.com/#wailsapp/wails&Date) ## Contributors From b1e04772d9ececd4d4380dcb472d52b8fa7b068a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Z=C3=A1mb=C3=B3=2C=20Levente?= Date: Thu, 29 Sep 2022 16:06:11 +0200 Subject: [PATCH 13/36] bugfix/linux framless window drag (#1916) --- v2/internal/frontend/runtime/desktop/main.js | 5 ++ v2/internal/frontend/runtime/ipc_websocket.js | 8 +-- .../frontend/runtime/runtime_dev_desktop.js | 56 ++++--------------- .../frontend/runtime/runtime_prod_desktop.js | 2 +- 4 files changed, 22 insertions(+), 49 deletions(-) diff --git a/v2/internal/frontend/runtime/desktop/main.js b/v2/internal/frontend/runtime/desktop/main.js index 80b819efa..674678314 100644 --- a/v2/internal/frontend/runtime/desktop/main.js +++ b/v2/internal/frontend/runtime/desktop/main.js @@ -122,6 +122,11 @@ function setResize(cursor) { } window.addEventListener('mousemove', function (e) { + let mousePressed = e.buttons !== undefined ? e.buttons : e.which; + if(window.wails.flags.shouldDrag && mousePressed <= 0) { + window.wails.flags.shouldDrag = false; + } + if (window.wails.flags.shouldDrag) { window.WailsInvoke("drag"); return; diff --git a/v2/internal/frontend/runtime/ipc_websocket.js b/v2/internal/frontend/runtime/ipc_websocket.js index 1769739c9..c8ffaaef9 100644 --- a/v2/internal/frontend/runtime/ipc_websocket.js +++ b/v2/internal/frontend/runtime/ipc_websocket.js @@ -1,9 +1,9 @@ (()=>{function O(t){console.log("%c wails dev %c "+t+" ","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 _(){}var D=t=>t;function P(t){return t()}function it(){return Object.create(null)}function b(t){t.forEach(P)}function $(t){return typeof t=="function"}function A(t,e){return t!=t?e==e:t!==e||t&&typeof t=="object"||typeof t=="function"}function ot(t){return Object.keys(t).length===0}function rt(t,...e){if(t==null)return _;let n=t.subscribe(...e);return n.unsubscribe?()=>n.unsubscribe():n}function st(t,e,n){t.$$.on_destroy.push(rt(e,n))}var ct=typeof window!="undefined",Ot=ct?()=>window.performance.now():()=>Date.now(),R=ct?t=>requestAnimationFrame(t):_;var F=new Set;function lt(t){F.forEach(e=>{e.c(t)||(F.delete(e),e.f())}),F.size!==0&&R(lt)}function Dt(t){let e;return F.size===0&&R(lt),{promise:new Promise(n=>{F.add(e={c:t,f:n})}),abort(){F.delete(e)}}}var ut=!1;function At(){ut=!0}function Lt(){ut=!1}function Bt(t,e){t.appendChild(e)}function at(t,e,n){let i=N(t);if(!i.getElementById(e)){let o=B("style");o.id=e,o.textContent=n,ft(i,o)}}function N(t){if(!t)return document;let e=t.getRootNode?t.getRootNode():t.ownerDocument;return e&&e.host?e:t.ownerDocument}function Tt(t){let e=B("style");return ft(N(t),e),e.sheet}function ft(t,e){Bt(t.head||t,e)}function W(t,e,n){t.insertBefore(e,n||null)}function L(t){t.parentNode.removeChild(t)}function B(t){return document.createElement(t)}function Jt(t){return document.createTextNode(t)}function dt(){return Jt("")}function ht(t,e,n){n==null?t.removeAttribute(e):t.getAttribute(e)!==n&&t.setAttribute(e,n)}function zt(t){return Array.from(t.childNodes)}function Ht(t,e,{bubbles:n=!1,cancelable:i=!1}={}){let o=document.createEvent("CustomEvent");return o.initCustomEvent(t,n,i,e),o}var T=new Map,J=0;function Gt(t){let e=5381,n=t.length;for(;n--;)e=(e<<5)-e^t.charCodeAt(n);return e>>>0}function qt(t,e){let n={stylesheet:Tt(e),rules:{}};return T.set(t,n),n}function pt(t,e,n,i,o,c,s,l=0){let a=16.666/i,r=`{ `;for(let g=0;g<=1;g+=a){let v=e+(n-e)*c(g);r+=g*100+`%{${s(v,1-v)}} `}let y=r+`100% {${s(n,1-n)}} -}`,f=`__svelte_${Gt(y)}_${l}`,u=N(t),{stylesheet:h,rules:p}=T.get(u)||qt(u,t);p[f]||(p[f]=!0,h.insertRule(`@keyframes ${f} ${y}`,h.cssRules.length));let w=t.style.animation||"";return t.style.animation=`${w?`${w}, `:""}${f} ${i}ms linear ${o}ms 1 both`,J+=1,f}function Kt(t,e){let n=(t.style.animation||"").split(", "),i=n.filter(e?c=>c.indexOf(e)<0:c=>c.indexOf("__svelte")===-1),o=n.length-i.length;o&&(t.style.animation=i.join(", "),J-=o,J||Pt())}function Pt(){R(()=>{J||(T.forEach(t=>{let{stylesheet:e}=t,n=e.cssRules.length;for(;n--;)e.deleteRule(n);t.rules={}}),T.clear())})}var V;function S(t){V=t}var k=[];var _t=[],z=[],mt=[],Rt=Promise.resolve(),U=!1;function Nt(){U||(U=!0,Rt.then(yt))}function x(t){z.push(t)}var X=new Set,H=0;function yt(){let t=V;do{for(;H{C=null})),C}function Z(t,e,n){t.dispatchEvent(Ht(`${e?"intro":"outro"}${n}`))}var G=new Set,m;function gt(){m={r:0,c:[],p:m}}function bt(){m.r||b(m.c),m=m.p}function I(t,e){t&&t.i&&(G.delete(t),t.i(e))}function Q(t,e,n,i){if(t&&t.o){if(G.has(t))return;G.add(t),m.c.push(()=>{G.delete(t),i&&(n&&t.d(1),i())}),t.o(e)}else i&&i()}var Ut={duration:0};function Y(t,e,n,i){let o=e(t,n),c=i?0:1,s=null,l=null,a=null;function r(){a&&Kt(t,a)}function y(u,h){let p=u.b-c;return h*=Math.abs(p),{a:c,b:u.b,d:p,duration:h,start:u.start,end:u.start+h,group:u.group}}function f(u){let{delay:h=0,duration:p=300,easing:w=D,tick:g=_,css:v}=o||Ut,K={start:Ot()+h,b:u};u||(K.group=m,m.r+=1),s||l?l=K:(v&&(r(),a=pt(t,c,u,p,h,w,v)),u&&g(0,1),s=y(K,p),x(()=>Z(t,u,"start")),Dt(j=>{if(l&&j>l.start&&(s=y(l,p),l=null,Z(t,s.b,"start"),v&&(r(),a=pt(t,c,s.b,s.duration,0,w,o.css))),s){if(j>=s.end)g(c=s.b,1-c),Z(t,s.b,"end"),l||(s.b?r():--s.group.r||b(s.group.c)),s=null;else if(j>=s.start){let jt=j-s.start;c=s.a+s.d*w(jt/s.duration),g(c,1-c)}}return!!(s||l)}))}return{run(u){$(o)?Vt().then(()=>{o=o(),f(u)}):f(u)},end(){r(),s=l=null}}}var le=typeof window!="undefined"?window:typeof globalThis!="undefined"?globalThis:global;var ue=new Set(["allowfullscreen","allowpaymentrequest","async","autofocus","autoplay","checked","controls","default","defer","disabled","formnovalidate","hidden","ismap","loop","multiple","muted","nomodule","novalidate","open","playsinline","readonly","required","reversed","selected"]);function Xt(t,e,n,i){let{fragment:o,on_mount:c,on_destroy:s,after_update:l}=t.$$;o&&o.m(e,n),i||x(()=>{let a=c.map(P).filter($);s?s.push(...a):b(a),t.$$.on_mount=[]}),l.forEach(x)}function wt(t,e){let n=t.$$;n.fragment!==null&&(b(n.on_destroy),n.fragment&&n.fragment.d(e),n.on_destroy=n.fragment=null,n.ctx=[])}function Zt(t,e){t.$$.dirty[0]===-1&&(k.push(t),Nt(),t.$$.dirty.fill(0)),t.$$.dirty[e/31|0]|=1<{let p=h.length?h[0]:u;return r.ctx&&o(r.ctx[f],r.ctx[f]=p)&&(!r.skip_bound&&r.bound[f]&&r.bound[f](p),y&&Zt(t,f)),u}):[],r.update(),y=!0,b(r.before_update),r.fragment=i?i(r.ctx):!1,e.target){if(e.hydrate){At();let f=zt(e.target);r.fragment&&r.fragment.l(f),f.forEach(L)}else r.fragment&&r.fragment.c();e.intro&&I(t.$$.fragment),Xt(t,e.target,e.anchor,e.customElement),Lt(),yt()}S(a)}var Qt;typeof HTMLElement=="function"&&(Qt=class extends HTMLElement{constructor(){super();this.attachShadow({mode:"open"})}connectedCallback(){let{on_mount:t}=this.$$;this.$$.on_disconnect=t.map(P).filter($);for(let e in this.$$.slotted)this.appendChild(this.$$.slotted[e])}attributeChangedCallback(t,e,n){this[t]=n}disconnectedCallback(){b(this.$$.on_disconnect)}$destroy(){wt(this,1),this.$destroy=_}$on(t,e){let n=this.$$.callbacks[t]||(this.$$.callbacks[t]=[]);return n.push(e),()=>{let i=n.indexOf(e);i!==-1&&n.splice(i,1)}}$set(t){this.$$set&&!ot(t)&&(this.$$.skip_bound=!0,this.$$set(t),this.$$.skip_bound=!1)}});var tt=class{$destroy(){wt(this,1),this.$destroy=_}$on(e,n){let i=this.$$.callbacks[e]||(this.$$.callbacks[e]=[]);return i.push(n),()=>{let o=i.indexOf(n);o!==-1&&i.splice(o,1)}}$set(e){this.$$set&&!ot(e)&&(this.$$.skip_bound=!0,this.$$set(e),this.$$.skip_bound=!1)}};var M=[];function Ft(t,e=_){let n,i=new Set;function o(l){if(A(t,l)&&(t=l,n)){let a=!M.length;for(let r of i)r[1](),M.push(r,t);if(a){for(let r=0;r{i.delete(r),i.size===0&&(n(),n=null)}}return{set:o,update:c,subscribe:s}}var q=Ft(!1);function xt(){q.set(!0)}function Mt(){q.set(!1)}function et(t,{delay:e=0,duration:n=400,easing:i=D}={}){let o=+getComputedStyle(t).opacity;return{delay:e,duration:n,easing:i,css:c=>`opacity: ${c*o}`}}function Yt(t){at(t,"svelte-181h7z",`.wails-reconnect-overlay.svelte-181h7z{position:fixed;top:0;left:0;width:100%;height:100%;backdrop-filter:blur(2px) saturate(0%) contrast(50%) brightness(25%);z-index:999999\r - }.wails-reconnect-overlay-content.svelte-181h7z{position:relative;top:50%;transform:translateY(-50%);margin:0;background-image:url(data:image/png;base64,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);background-repeat:no-repeat;background-position:center\r - }.wails-reconnect-overlay-loadingspinner.svelte-181h7z{pointer-events:none;width:2.5em;height:2.5em;border:.4em solid transparent;border-color:#f00 #eee0 #f00 #eee0;border-radius:50%;animation:svelte-181h7z-loadingspin 1s linear infinite;margin:auto;padding:2.5em\r +}`,f=`__svelte_${Gt(y)}_${l}`,u=N(t),{stylesheet:h,rules:p}=T.get(u)||qt(u,t);p[f]||(p[f]=!0,h.insertRule(`@keyframes ${f} ${y}`,h.cssRules.length));let w=t.style.animation||"";return t.style.animation=`${w?`${w}, `:""}${f} ${i}ms linear ${o}ms 1 both`,J+=1,f}function Kt(t,e){let n=(t.style.animation||"").split(", "),i=n.filter(e?c=>c.indexOf(e)<0:c=>c.indexOf("__svelte")===-1),o=n.length-i.length;o&&(t.style.animation=i.join(", "),J-=o,J||Pt())}function Pt(){R(()=>{J||(T.forEach(t=>{let{stylesheet:e}=t,n=e.cssRules.length;for(;n--;)e.deleteRule(n);t.rules={}}),T.clear())})}var V;function S(t){V=t}var k=[];var _t=[],z=[],mt=[],Rt=Promise.resolve(),U=!1;function Nt(){U||(U=!0,Rt.then(yt))}function x(t){z.push(t)}var X=new Set,H=0;function yt(){let t=V;do{for(;H{C=null})),C}function Z(t,e,n){t.dispatchEvent(Ht(`${e?"intro":"outro"}${n}`))}var G=new Set,m;function gt(){m={r:0,c:[],p:m}}function bt(){m.r||b(m.c),m=m.p}function I(t,e){t&&t.i&&(G.delete(t),t.i(e))}function Q(t,e,n,i){if(t&&t.o){if(G.has(t))return;G.add(t),m.c.push(()=>{G.delete(t),i&&(n&&t.d(1),i())}),t.o(e)}else i&&i()}var Ut={duration:0};function Y(t,e,n,i){let o=e(t,n),c=i?0:1,s=null,l=null,a=null;function r(){a&&Kt(t,a)}function y(u,h){let p=u.b-c;return h*=Math.abs(p),{a:c,b:u.b,d:p,duration:h,start:u.start,end:u.start+h,group:u.group}}function f(u){let{delay:h=0,duration:p=300,easing:w=D,tick:g=_,css:v}=o||Ut,K={start:Ot()+h,b:u};u||(K.group=m,m.r+=1),s||l?l=K:(v&&(r(),a=pt(t,c,u,p,h,w,v)),u&&g(0,1),s=y(K,p),x(()=>Z(t,u,"start")),Dt(j=>{if(l&&j>l.start&&(s=y(l,p),l=null,Z(t,s.b,"start"),v&&(r(),a=pt(t,c,s.b,s.duration,0,w,o.css))),s){if(j>=s.end)g(c=s.b,1-c),Z(t,s.b,"end"),l||(s.b?r():--s.group.r||b(s.group.c)),s=null;else if(j>=s.start){let jt=j-s.start;c=s.a+s.d*w(jt/s.duration),g(c,1-c)}}return!!(s||l)}))}return{run(u){$(o)?Vt().then(()=>{o=o(),f(u)}):f(u)},end(){r(),s=l=null}}}var le=typeof window!="undefined"?window:typeof globalThis!="undefined"?globalThis:global;var ue=new Set(["allowfullscreen","allowpaymentrequest","async","autofocus","autoplay","checked","controls","default","defer","disabled","formnovalidate","hidden","ismap","loop","multiple","muted","nomodule","novalidate","open","playsinline","readonly","required","reversed","selected"]);function Xt(t,e,n,i){let{fragment:o,on_mount:c,on_destroy:s,after_update:l}=t.$$;o&&o.m(e,n),i||x(()=>{let a=c.map(P).filter($);s?s.push(...a):b(a),t.$$.on_mount=[]}),l.forEach(x)}function wt(t,e){let n=t.$$;n.fragment!==null&&(b(n.on_destroy),n.fragment&&n.fragment.d(e),n.on_destroy=n.fragment=null,n.ctx=[])}function Zt(t,e){t.$$.dirty[0]===-1&&(k.push(t),Nt(),t.$$.dirty.fill(0)),t.$$.dirty[e/31|0]|=1<{let p=h.length?h[0]:u;return r.ctx&&o(r.ctx[f],r.ctx[f]=p)&&(!r.skip_bound&&r.bound[f]&&r.bound[f](p),y&&Zt(t,f)),u}):[],r.update(),y=!0,b(r.before_update),r.fragment=i?i(r.ctx):!1,e.target){if(e.hydrate){At();let f=zt(e.target);r.fragment&&r.fragment.l(f),f.forEach(L)}else r.fragment&&r.fragment.c();e.intro&&I(t.$$.fragment),Xt(t,e.target,e.anchor,e.customElement),Lt(),yt()}S(a)}var Qt;typeof HTMLElement=="function"&&(Qt=class extends HTMLElement{constructor(){super();this.attachShadow({mode:"open"})}connectedCallback(){let{on_mount:t}=this.$$;this.$$.on_disconnect=t.map(P).filter($);for(let e in this.$$.slotted)this.appendChild(this.$$.slotted[e])}attributeChangedCallback(t,e,n){this[t]=n}disconnectedCallback(){b(this.$$.on_disconnect)}$destroy(){wt(this,1),this.$destroy=_}$on(t,e){let n=this.$$.callbacks[t]||(this.$$.callbacks[t]=[]);return n.push(e),()=>{let i=n.indexOf(e);i!==-1&&n.splice(i,1)}}$set(t){this.$$set&&!ot(t)&&(this.$$.skip_bound=!0,this.$$set(t),this.$$.skip_bound=!1)}});var tt=class{$destroy(){wt(this,1),this.$destroy=_}$on(e,n){let i=this.$$.callbacks[e]||(this.$$.callbacks[e]=[]);return i.push(n),()=>{let o=i.indexOf(n);o!==-1&&i.splice(o,1)}}$set(e){this.$$set&&!ot(e)&&(this.$$.skip_bound=!0,this.$$set(e),this.$$.skip_bound=!1)}};var M=[];function Ft(t,e=_){let n,i=new Set;function o(l){if(A(t,l)&&(t=l,n)){let a=!M.length;for(let r of i)r[1](),M.push(r,t);if(a){for(let r=0;r{i.delete(r),i.size===0&&(n(),n=null)}}return{set:o,update:c,subscribe:s}}var q=Ft(!1);function xt(){q.set(!0)}function Mt(){q.set(!1)}function et(t,{delay:e=0,duration:n=400,easing:i=D}={}){let o=+getComputedStyle(t).opacity;return{delay:e,duration:n,easing:i,css:c=>`opacity: ${c*o}`}}function Yt(t){at(t,"svelte-181h7z",`.wails-reconnect-overlay.svelte-181h7z{position:fixed;top:0;left:0;width:100%;height:100%;backdrop-filter:blur(2px) saturate(0%) contrast(50%) brightness(25%);z-index:999999 + }.wails-reconnect-overlay-content.svelte-181h7z{position:relative;top:50%;transform:translateY(-50%);margin:0;background-image:url(data:image/png;base64,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);background-repeat:no-repeat;background-position:center + }.wails-reconnect-overlay-loadingspinner.svelte-181h7z{pointer-events:none;width:2.5em;height:2.5em;border:.4em solid transparent;border-color:#f00 #eee0 #f00 #eee0;border-radius:50%;animation:svelte-181h7z-loadingspin 1s linear infinite;margin:auto;padding:2.5em }@keyframes svelte-181h7z-loadingspin{100%{transform:rotate(360deg)}}`)}function $t(t){let e,n,i;return{c(){e=B("div"),e.innerHTML='
',ht(e,"class","wails-reconnect-overlay svelte-181h7z")},m(o,c){W(o,e,c),i=!0},i(o){i||(x(()=>{n||(n=Y(e,et,{duration:300},!0)),n.run(1)}),i=!0)},o(o){n||(n=Y(e,et,{duration:300},!1)),n.run(0),i=!1},d(o){o&&L(e),o&&n&&n.end()}}}function te(t){let e,n,i=t[0]&&$t(t);return{c(){i&&i.c(),e=dt()},m(o,c){i&&i.m(o,c),W(o,e,c),n=!0},p(o,[c]){o[0]?i?c&1&&I(i,1):(i=$t(o),i.c(),I(i,1),i.m(e.parentNode,e)):i&&(gt(),Q(i,1,1,()=>{i=null}),bt())},i(o){n||(I(i),n=!0)},o(o){Q(i),n=!1},d(o){i&&i.d(o),o&&L(e)}}}function ee(t,e,n){let i;return st(t,q,o=>n(0,i=o)),[i]}var St=class extends tt{constructor(e){super();vt(this,e,ee,te,A,{},Yt)}},kt=St;var ne={},nt=null,E=[];window.WailsInvoke=t=>{if(!nt){console.log("Queueing: "+t),E.push(t);return}nt(t)};window.addEventListener("DOMContentLoaded",()=>{ne.overlay=new kt({target:document.body,anchor:document.querySelector("#wails-spinner")})});var d=null,Ct;window.onbeforeunload=function(){d&&(d.onclose=function(){},d.close(),d=null)};Et();function ie(){nt=t=>{d.send(t)};for(let t=0;t 0) { @@ -130,23 +127,19 @@ // desktop/calls.js var callbacks = {}; - function cryptoRandom() { var array = new Uint32Array(1); return window.crypto.getRandomValues(array)[0]; } - function basicRandom() { return Math.random() * 9007199254740991; } - var randomFunc; if (window.crypto) { randomFunc = cryptoRandom; } else { randomFunc = basicRandom; } - function Call(name, args, timeout) { if (timeout == null) { timeout = 0; @@ -183,14 +176,14 @@ if (timeout == null) { timeout = 0; } - return new Promise(function (resolve, reject) { + return new Promise(function(resolve, reject) { var callbackID; do { callbackID = id + "-" + randomFunc(); } while (callbacks[callbackID]); var timeoutHandle; if (timeout > 0) { - timeoutHandle = setTimeout(function () { + timeoutHandle = setTimeout(function() { reject(Error("Call to method " + id + " timed out. Request ID: " + callbackID)); }, timeout); } @@ -310,105 +303,80 @@ function WindowSetSystemDefaultTheme() { window.WailsInvoke("WASDT"); } - function WindowSetLightTheme() { window.WailsInvoke("WALT"); } - function WindowSetDarkTheme() { window.WailsInvoke("WADT"); } - function WindowCenter() { window.WailsInvoke("Wc"); } - function WindowSetTitle(title) { window.WailsInvoke("WT" + title); } - function WindowFullscreen() { window.WailsInvoke("WF"); } - function WindowUnfullscreen() { window.WailsInvoke("Wf"); } - function WindowIsFullscreen() { return Call(":wails:WindowIsFullscreen"); } - function WindowSetSize(width, height) { window.WailsInvoke("Ws:" + width + ":" + height); } - function WindowGetSize() { return Call(":wails:WindowGetSize"); } - function WindowSetMaxSize(width, height) { window.WailsInvoke("WZ:" + width + ":" + height); } - function WindowSetMinSize(width, height) { window.WailsInvoke("Wz:" + width + ":" + height); } - function WindowSetAlwaysOnTop(b) { window.WailsInvoke("WATP:" + (b ? "1" : "0")); } - function WindowSetPosition(x, y) { window.WailsInvoke("Wp:" + x + ":" + y); } - function WindowGetPosition() { return Call(":wails:WindowGetPos"); } - function WindowHide() { window.WailsInvoke("WH"); } - function WindowShow() { window.WailsInvoke("WS"); } - function WindowMaximise() { window.WailsInvoke("WM"); } - function WindowToggleMaximise() { window.WailsInvoke("Wt"); } - function WindowUnmaximise() { window.WailsInvoke("WU"); } - function WindowIsMaximised() { return Call(":wails:WindowIsMaximised"); } - function WindowMinimise() { window.WailsInvoke("Wm"); } - function WindowUnminimise() { window.WailsInvoke("Wu"); } - function WindowIsMinimised() { return Call(":wails:WindowIsMinimised"); } - function WindowIsNormal() { return Call(":wails:WindowIsNormal"); } - function WindowSetBackgroundColour(R, G, B, A) { - let rgba = JSON.stringify({r: R || 0, g: G || 0, b: B || 0, a: A || 255}); + let rgba = JSON.stringify({ r: R || 0, g: G || 0, b: B || 0, a: A || 255 }); window.WailsInvoke("Wr:" + rgba); } @@ -417,7 +385,6 @@ __export(screen_exports, { ScreenGetAll: () => ScreenGetAll }); - function ScreenGetAll() { return Call(":wails:ScreenGetAll"); } @@ -427,7 +394,6 @@ __export(browser_exports, { BrowserOpenURL: () => BrowserOpenURL }); - function BrowserOpenURL(url) { window.WailsInvoke("BO:" + url); } @@ -487,10 +453,10 @@ window.addEventListener("mouseup", () => { window.wails.flags.shouldDrag = false; }); - var dragTest = function (e) { + var dragTest = function(e) { return window.getComputedStyle(e.target).getPropertyValue(window.wails.flags.cssDragProperty) === window.wails.flags.cssDragValue; }; - window.wails.setCSSDragProperties = function (property, value) { + window.wails.setCSSDragProperties = function(property, value) { window.wails.flags.cssDragProperty = property; window.wails.flags.cssDragValue = value; }; @@ -509,13 +475,15 @@ window.wails.flags.shouldDrag = true; } }); - function setResize(cursor) { document.body.style.cursor = cursor || window.wails.flags.defaultCursor; window.wails.flags.resizeEdge = cursor; } - - window.addEventListener("mousemove", function (e) { + window.addEventListener("mousemove", function(e) { + let mousePressed = e.buttons !== void 0 ? e.buttons : e.which; + if (window.wails.flags.shouldDrag && mousePressed <= 0) { + window.wails.flags.shouldDrag = false; + } if (window.wails.flags.shouldDrag) { window.WailsInvoke("drag"); return; @@ -552,11 +520,11 @@ else if (rightBorder) setResize("e-resize"); }); - window.addEventListener("contextmenu", function (e) { + window.addEventListener("contextmenu", function(e) { if (window.wails.flags.disableWailsDefaultContextMenu) { e.preventDefault(); } }); window.WailsInvoke("runtime:ready"); })(); -//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiZGVza3RvcC9sb2cuanMiLCAiZGVza3RvcC9ldmVudHMuanMiLCAiZGVza3RvcC9jYWxscy5qcyIsICJkZXNrdG9wL2JpbmRpbmdzLmpzIiwgImRlc2t0b3Avd2luZG93LmpzIiwgImRlc2t0b3Avc2NyZWVuLmpzIiwgImRlc2t0b3AvYnJvd3Nlci5qcyIsICJkZXNrdG9wL21haW4uanMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbIi8qXHJcbiBfICAgICAgIF9fICAgICAgXyBfX1xyXG58IHwgICAgIC8gL19fXyBfKF8pIC9fX19fXHJcbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cclxufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXHJcbnxfXy98X18vXFxfXyxfL18vXy9fX19fL1xyXG5UaGUgZWxlY3Ryb24gYWx0ZXJuYXRpdmUgZm9yIEdvXHJcbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcclxuKi9cclxuXHJcbi8qIGpzaGludCBlc3ZlcnNpb246IDYgKi9cclxuXHJcbi8qKlxyXG4gKiBTZW5kcyBhIGxvZyBtZXNzYWdlIHRvIHRoZSBiYWNrZW5kIHdpdGggdGhlIGdpdmVuIGxldmVsICsgbWVzc2FnZVxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbGV2ZWxcclxuICogQHBhcmFtIHtzdHJpbmd9IG1lc3NhZ2VcclxuICovXHJcbmZ1bmN0aW9uIHNlbmRMb2dNZXNzYWdlKGxldmVsLCBtZXNzYWdlKSB7XHJcblxyXG5cdC8vIExvZyBNZXNzYWdlIGZvcm1hdDpcclxuXHQvLyBsW3R5cGVdW21lc3NhZ2VdXHJcblx0d2luZG93LldhaWxzSW52b2tlKCdMJyArIGxldmVsICsgbWVzc2FnZSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBMb2cgdGhlIGdpdmVuIHRyYWNlIG1lc3NhZ2Ugd2l0aCB0aGUgYmFja2VuZFxyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gTG9nVHJhY2UobWVzc2FnZSkge1xyXG5cdHNlbmRMb2dNZXNzYWdlKCdUJywgbWVzc2FnZSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBMb2cgdGhlIGdpdmVuIG1lc3NhZ2Ugd2l0aCB0aGUgYmFja2VuZFxyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gTG9nUHJpbnQobWVzc2FnZSkge1xyXG5cdHNlbmRMb2dNZXNzYWdlKCdQJywgbWVzc2FnZSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBMb2cgdGhlIGdpdmVuIGRlYnVnIG1lc3NhZ2Ugd2l0aCB0aGUgYmFja2VuZFxyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gTG9nRGVidWcobWVzc2FnZSkge1xyXG5cdHNlbmRMb2dNZXNzYWdlKCdEJywgbWVzc2FnZSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBMb2cgdGhlIGdpdmVuIGluZm8gbWVzc2FnZSB3aXRoIHRoZSBiYWNrZW5kXHJcbiAqXHJcbiAqIEBleHBvcnRcclxuICogQHBhcmFtIHtzdHJpbmd9IG1lc3NhZ2VcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBMb2dJbmZvKG1lc3NhZ2UpIHtcclxuXHRzZW5kTG9nTWVzc2FnZSgnSScsIG1lc3NhZ2UpO1xyXG59XHJcblxyXG4vKipcclxuICogTG9nIHRoZSBnaXZlbiB3YXJuaW5nIG1lc3NhZ2Ugd2l0aCB0aGUgYmFja2VuZFxyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gTG9nV2FybmluZyhtZXNzYWdlKSB7XHJcblx0c2VuZExvZ01lc3NhZ2UoJ1cnLCBtZXNzYWdlKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIExvZyB0aGUgZ2l2ZW4gZXJyb3IgbWVzc2FnZSB3aXRoIHRoZSBiYWNrZW5kXHJcbiAqXHJcbiAqIEBleHBvcnRcclxuICogQHBhcmFtIHtzdHJpbmd9IG1lc3NhZ2VcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBMb2dFcnJvcihtZXNzYWdlKSB7XHJcblx0c2VuZExvZ01lc3NhZ2UoJ0UnLCBtZXNzYWdlKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIExvZyB0aGUgZ2l2ZW4gZmF0YWwgbWVzc2FnZSB3aXRoIHRoZSBiYWNrZW5kXHJcbiAqXHJcbiAqIEBleHBvcnRcclxuICogQHBhcmFtIHtzdHJpbmd9IG1lc3NhZ2VcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBMb2dGYXRhbChtZXNzYWdlKSB7XHJcblx0c2VuZExvZ01lc3NhZ2UoJ0YnLCBtZXNzYWdlKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIExvZyBsZXZlbCB0byB0aGUgZ2l2ZW4gbG9nIGxldmVsXHJcbiAqXHJcbiAqIEBleHBvcnRcclxuICogQHBhcmFtIHtudW1iZXJ9IGxvZ2xldmVsXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gU2V0TG9nTGV2ZWwobG9nbGV2ZWwpIHtcclxuXHRzZW5kTG9nTWVzc2FnZSgnUycsIGxvZ2xldmVsKTtcclxufVxyXG5cclxuLy8gTG9nIGxldmVsc1xyXG5leHBvcnQgY29uc3QgTG9nTGV2ZWwgPSB7XHJcblx0VFJBQ0U6IDEsXHJcblx0REVCVUc6IDIsXHJcblx0SU5GTzogMyxcclxuXHRXQVJOSU5HOiA0LFxyXG5cdEVSUk9SOiA1LFxyXG59O1xyXG4iLCAiLypcclxuIF8gICAgICAgX18gICAgICBfIF9fXHJcbnwgfCAgICAgLyAvX19fIF8oXykgL19fX19cclxufCB8IC98IC8gLyBfXyBgLyAvIC8gX19fL1xyXG58IHwvIHwvIC8gL18vIC8gLyAoX18gIClcclxufF9fL3xfXy9cXF9fLF8vXy9fL19fX18vXHJcblRoZSBlbGVjdHJvbiBhbHRlcm5hdGl2ZSBmb3IgR29cclxuKGMpIExlYSBBbnRob255IDIwMTktcHJlc2VudFxyXG4qL1xyXG4vKiBqc2hpbnQgZXN2ZXJzaW9uOiA2ICovXHJcblxyXG4vLyBEZWZpbmVzIGEgc2luZ2xlIGxpc3RlbmVyIHdpdGggYSBtYXhpbXVtIG51bWJlciBvZiB0aW1lcyB0byBjYWxsYmFja1xyXG5cclxuLyoqXHJcbiAqIFRoZSBMaXN0ZW5lciBjbGFzcyBkZWZpbmVzIGEgbGlzdGVuZXIhIDotKVxyXG4gKlxyXG4gKiBAY2xhc3MgTGlzdGVuZXJcclxuICovXHJcbmNsYXNzIExpc3RlbmVyIHtcclxuICAgIC8qKlxyXG4gICAgICogQ3JlYXRlcyBhbiBpbnN0YW5jZSBvZiBMaXN0ZW5lci5cclxuICAgICAqIEBwYXJhbSB7ZnVuY3Rpb259IGNhbGxiYWNrXHJcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gbWF4Q2FsbGJhY2tzXHJcbiAgICAgKiBAbWVtYmVyb2YgTGlzdGVuZXJcclxuICAgICAqL1xyXG4gICAgY29uc3RydWN0b3IoY2FsbGJhY2ssIG1heENhbGxiYWNrcykge1xyXG4gICAgICAgIC8vIERlZmF1bHQgb2YgLTEgbWVhbnMgaW5maW5pdGVcclxuICAgICAgICBtYXhDYWxsYmFja3MgPSBtYXhDYWxsYmFja3MgfHwgLTE7XHJcbiAgICAgICAgLy8gQ2FsbGJhY2sgaW52b2tlcyB0aGUgY2FsbGJhY2sgd2l0aCB0aGUgZ2l2ZW4gZGF0YVxyXG4gICAgICAgIC8vIFJldHVybnMgdHJ1ZSBpZiB0aGlzIGxpc3RlbmVyIHNob3VsZCBiZSBkZXN0cm95ZWRcclxuICAgICAgICB0aGlzLkNhbGxiYWNrID0gKGRhdGEpID0+IHtcclxuICAgICAgICAgICAgY2FsbGJhY2suYXBwbHkobnVsbCwgZGF0YSk7XHJcbiAgICAgICAgICAgIC8vIElmIG1heENhbGxiYWNrcyBpcyBpbmZpbml0ZSwgcmV0dXJuIGZhbHNlIChkbyBub3QgZGVzdHJveSlcclxuICAgICAgICAgICAgaWYgKG1heENhbGxiYWNrcyA9PT0gLTEpIHtcclxuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAvLyBEZWNyZW1lbnQgbWF4Q2FsbGJhY2tzLiBSZXR1cm4gdHJ1ZSBpZiBub3cgMCwgb3RoZXJ3aXNlIGZhbHNlXHJcbiAgICAgICAgICAgIG1heENhbGxiYWNrcyAtPSAxO1xyXG4gICAgICAgICAgICByZXR1cm4gbWF4Q2FsbGJhY2tzID09PSAwO1xyXG4gICAgICAgIH07XHJcbiAgICB9XHJcbn1cclxuXHJcbmV4cG9ydCBjb25zdCBldmVudExpc3RlbmVycyA9IHt9O1xyXG5cclxuLyoqXHJcbiAqIFJlZ2lzdGVycyBhbiBldmVudCBsaXN0ZW5lciB0aGF0IHdpbGwgYmUgaW52b2tlZCBgbWF4Q2FsbGJhY2tzYCB0aW1lcyBiZWZvcmUgYmVpbmcgZGVzdHJveWVkXHJcbiAqXHJcbiAqIEBleHBvcnRcclxuICogQHBhcmFtIHtzdHJpbmd9IGV2ZW50TmFtZVxyXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBjYWxsYmFja1xyXG4gKiBAcGFyYW0ge251bWJlcn0gbWF4Q2FsbGJhY2tzXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gRXZlbnRzT25NdWx0aXBsZShldmVudE5hbWUsIGNhbGxiYWNrLCBtYXhDYWxsYmFja3MpIHtcclxuICAgIGV2ZW50TGlzdGVuZXJzW2V2ZW50TmFtZV0gPSBldmVudExpc3RlbmVyc1tldmVudE5hbWVdIHx8IFtdO1xyXG4gICAgY29uc3QgdGhpc0xpc3RlbmVyID0gbmV3IExpc3RlbmVyKGNhbGxiYWNrLCBtYXhDYWxsYmFja3MpO1xyXG4gICAgZXZlbnRMaXN0ZW5lcnNbZXZlbnROYW1lXS5wdXNoKHRoaXNMaXN0ZW5lcik7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZWdpc3RlcnMgYW4gZXZlbnQgbGlzdGVuZXIgdGhhdCB3aWxsIGJlIGludm9rZWQgZXZlcnkgdGltZSB0aGUgZXZlbnQgaXMgZW1pdHRlZFxyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBldmVudE5hbWVcclxuICogQHBhcmFtIHtmdW5jdGlvbn0gY2FsbGJhY2tcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBFdmVudHNPbihldmVudE5hbWUsIGNhbGxiYWNrKSB7XHJcbiAgICBFdmVudHNPbk11bHRpcGxlKGV2ZW50TmFtZSwgY2FsbGJhY2ssIC0xKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJlZ2lzdGVycyBhbiBldmVudCBsaXN0ZW5lciB0aGF0IHdpbGwgYmUgaW52b2tlZCBvbmNlIHRoZW4gZGVzdHJveWVkXHJcbiAqXHJcbiAqIEBleHBvcnRcclxuICogQHBhcmFtIHtzdHJpbmd9IGV2ZW50TmFtZVxyXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBjYWxsYmFja1xyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIEV2ZW50c09uY2UoZXZlbnROYW1lLCBjYWxsYmFjaykge1xyXG4gICAgRXZlbnRzT25NdWx0aXBsZShldmVudE5hbWUsIGNhbGxiYWNrLCAxKTtcclxufVxyXG5cclxuZnVuY3Rpb24gbm90aWZ5TGlzdGVuZXJzKGV2ZW50RGF0YSkge1xyXG5cclxuICAgIC8vIEdldCB0aGUgZXZlbnQgbmFtZVxyXG4gICAgbGV0IGV2ZW50TmFtZSA9IGV2ZW50RGF0YS5uYW1lO1xyXG5cclxuICAgIC8vIENoZWNrIGlmIHdlIGhhdmUgYW55IGxpc3RlbmVycyBmb3IgdGhpcyBldmVudFxyXG4gICAgaWYgKGV2ZW50TGlzdGVuZXJzW2V2ZW50TmFtZV0pIHtcclxuXHJcbiAgICAgICAgLy8gS2VlcCBhIGxpc3Qgb2YgbGlzdGVuZXIgaW5kZXhlcyB0byBkZXN0cm95XHJcbiAgICAgICAgY29uc3QgbmV3RXZlbnRMaXN0ZW5lckxpc3QgPSBldmVudExpc3RlbmVyc1tldmVudE5hbWVdLnNsaWNlKCk7XHJcblxyXG4gICAgICAgIC8vIEl0ZXJhdGUgbGlzdGVuZXJzXHJcbiAgICAgICAgZm9yIChsZXQgY291bnQgPSAwOyBjb3VudCA8IGV2ZW50TGlzdGVuZXJzW2V2ZW50TmFtZV0ubGVuZ3RoOyBjb3VudCArPSAxKSB7XHJcblxyXG4gICAgICAgICAgICAvLyBHZXQgbmV4dCBsaXN0ZW5lclxyXG4gICAgICAgICAgICBjb25zdCBsaXN0ZW5lciA9IGV2ZW50TGlzdGVuZXJzW2V2ZW50TmFtZV1bY291bnRdO1xyXG5cclxuICAgICAgICAgICAgbGV0IGRhdGEgPSBldmVudERhdGEuZGF0YTtcclxuXHJcbiAgICAgICAgICAgIC8vIERvIHRoZSBjYWxsYmFja1xyXG4gICAgICAgICAgICBjb25zdCBkZXN0cm95ID0gbGlzdGVuZXIuQ2FsbGJhY2soZGF0YSk7XHJcbiAgICAgICAgICAgIGlmIChkZXN0cm95KSB7XHJcbiAgICAgICAgICAgICAgICAvLyBpZiB0aGUgbGlzdGVuZXIgaW5kaWNhdGVkIHRvIGRlc3Ryb3kgaXRzZWxmLCBhZGQgaXQgdG8gdGhlIGRlc3Ryb3kgbGlzdFxyXG4gICAgICAgICAgICAgICAgbmV3RXZlbnRMaXN0ZW5lckxpc3Quc3BsaWNlKGNvdW50LCAxKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gVXBkYXRlIGNhbGxiYWNrcyB3aXRoIG5ldyBsaXN0IG9mIGxpc3RlbmVyc1xyXG4gICAgICAgIGV2ZW50TGlzdGVuZXJzW2V2ZW50TmFtZV0gPSBuZXdFdmVudExpc3RlbmVyTGlzdDtcclxuICAgIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIE5vdGlmeSBpbmZvcm1zIGZyb250ZW5kIGxpc3RlbmVycyB0aGF0IGFuIGV2ZW50IHdhcyBlbWl0dGVkIHdpdGggdGhlIGdpdmVuIGRhdGFcclxuICpcclxuICogQGV4cG9ydFxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbm90aWZ5TWVzc2FnZSAtIGVuY29kZWQgbm90aWZpY2F0aW9uIG1lc3NhZ2VcclxuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gRXZlbnRzTm90aWZ5KG5vdGlmeU1lc3NhZ2UpIHtcclxuICAgIC8vIFBhcnNlIHRoZSBtZXNzYWdlXHJcbiAgICBsZXQgbWVzc2FnZTtcclxuICAgIHRyeSB7XHJcbiAgICAgICAgbWVzc2FnZSA9IEpTT04ucGFyc2Uobm90aWZ5TWVzc2FnZSk7XHJcbiAgICB9IGNhdGNoIChlKSB7XHJcbiAgICAgICAgY29uc3QgZXJyb3IgPSAnSW52YWxpZCBKU09OIHBhc3NlZCB0byBOb3RpZnk6ICcgKyBub3RpZnlNZXNzYWdlO1xyXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihlcnJvcik7XHJcbiAgICB9XHJcbiAgICBub3RpZnlMaXN0ZW5lcnMobWVzc2FnZSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFbWl0IGFuIGV2ZW50IHdpdGggdGhlIGdpdmVuIG5hbWUgYW5kIGRhdGFcclxuICpcclxuICogQGV4cG9ydFxyXG4gKiBAcGFyYW0ge3N0cmluZ30gZXZlbnROYW1lXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gRXZlbnRzRW1pdChldmVudE5hbWUpIHtcclxuXHJcbiAgICBjb25zdCBwYXlsb2FkID0ge1xyXG4gICAgICAgIG5hbWU6IGV2ZW50TmFtZSxcclxuICAgICAgICBkYXRhOiBbXS5zbGljZS5hcHBseShhcmd1bWVudHMpLnNsaWNlKDEpLFxyXG4gICAgfTtcclxuXHJcbiAgICAvLyBOb3RpZnkgSlMgbGlzdGVuZXJzXHJcbiAgICBub3RpZnlMaXN0ZW5lcnMocGF5bG9hZCk7XHJcblxyXG4gICAgLy8gTm90aWZ5IEdvIGxpc3RlbmVyc1xyXG4gICAgd2luZG93LldhaWxzSW52b2tlKCdFRScgKyBKU09OLnN0cmluZ2lmeShwYXlsb2FkKSk7XHJcbn1cclxuXHJcbmZ1bmN0aW9uIHJlbW92ZUxpc3RlbmVyKGV2ZW50TmFtZSkge1xyXG4gICAgLy8gUmVtb3ZlIGxvY2FsIGxpc3RlbmVyc1xyXG4gICAgZGVsZXRlIGV2ZW50TGlzdGVuZXJzW2V2ZW50TmFtZV07XHJcblxyXG4gICAgLy8gTm90aWZ5IEdvIGxpc3RlbmVyc1xyXG4gICAgd2luZG93LldhaWxzSW52b2tlKCdFWCcgKyBldmVudE5hbWUpO1xyXG59XHJcblxyXG4vKipcclxuICogT2ZmIHVucmVnaXN0ZXJzIGEgbGlzdGVuZXIgcHJldmlvdXNseSByZWdpc3RlcmVkIHdpdGggT24sXHJcbiAqIG9wdGlvbmFsbHkgbXVsdGlwbGUgbGlzdGVuZXJlcyBjYW4gYmUgdW5yZWdpc3RlcmVkIHZpYSBgYWRkaXRpb25hbEV2ZW50TmFtZXNgXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBldmVudE5hbWVcclxuICogQHBhcmFtICB7Li4uc3RyaW5nfSBhZGRpdGlvbmFsRXZlbnROYW1lc1xyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIEV2ZW50c09mZihldmVudE5hbWUsIC4uLmFkZGl0aW9uYWxFdmVudE5hbWVzKSB7XHJcbiAgICByZW1vdmVMaXN0ZW5lcihldmVudE5hbWUpXHJcblxyXG4gICAgaWYgKGFkZGl0aW9uYWxFdmVudE5hbWVzLmxlbmd0aCA+IDApIHtcclxuICAgICAgICBhZGRpdGlvbmFsRXZlbnROYW1lcy5mb3JFYWNoKGV2ZW50TmFtZSA9PiB7XHJcbiAgICAgICAgICAgIHJlbW92ZUxpc3RlbmVyKGV2ZW50TmFtZSlcclxuICAgICAgICB9KVxyXG4gICAgfVxyXG59IiwgIi8qXHJcbiBfICAgICAgIF9fICAgICAgXyBfX1xyXG58IHwgICAgIC8gL19fXyBfKF8pIC9fX19fXHJcbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cclxufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXHJcbnxfXy98X18vXFxfXyxfL18vXy9fX19fL1xyXG5UaGUgZWxlY3Ryb24gYWx0ZXJuYXRpdmUgZm9yIEdvXHJcbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcclxuKi9cclxuLyoganNoaW50IGVzdmVyc2lvbjogNiAqL1xyXG5cclxuZXhwb3J0IGNvbnN0IGNhbGxiYWNrcyA9IHt9O1xyXG5cclxuLyoqXHJcbiAqIFJldHVybnMgYSBudW1iZXIgZnJvbSB0aGUgbmF0aXZlIGJyb3dzZXIgcmFuZG9tIGZ1bmN0aW9uXHJcbiAqXHJcbiAqIEByZXR1cm5zIG51bWJlclxyXG4gKi9cclxuZnVuY3Rpb24gY3J5cHRvUmFuZG9tKCkge1xyXG5cdHZhciBhcnJheSA9IG5ldyBVaW50MzJBcnJheSgxKTtcclxuXHRyZXR1cm4gd2luZG93LmNyeXB0by5nZXRSYW5kb21WYWx1ZXMoYXJyYXkpWzBdO1xyXG59XHJcblxyXG4vKipcclxuICogUmV0dXJucyBhIG51bWJlciB1c2luZyBkYSBvbGQtc2tvb2wgTWF0aC5SYW5kb21cclxuICogSSBsaWtlcyB0byBjYWxsIGl0IExPTFJhbmRvbVxyXG4gKlxyXG4gKiBAcmV0dXJucyBudW1iZXJcclxuICovXHJcbmZ1bmN0aW9uIGJhc2ljUmFuZG9tKCkge1xyXG5cdHJldHVybiBNYXRoLnJhbmRvbSgpICogOTAwNzE5OTI1NDc0MDk5MTtcclxufVxyXG5cclxuLy8gUGljayBhIHJhbmRvbSBudW1iZXIgZnVuY3Rpb24gYmFzZWQgb24gYnJvd3NlciBjYXBhYmlsaXR5XHJcbnZhciByYW5kb21GdW5jO1xyXG5pZiAod2luZG93LmNyeXB0bykge1xyXG5cdHJhbmRvbUZ1bmMgPSBjcnlwdG9SYW5kb207XHJcbn0gZWxzZSB7XHJcblx0cmFuZG9tRnVuYyA9IGJhc2ljUmFuZG9tO1xyXG59XHJcblxyXG5cclxuLyoqXHJcbiAqIENhbGwgc2VuZHMgYSBtZXNzYWdlIHRvIHRoZSBiYWNrZW5kIHRvIGNhbGwgdGhlIGJpbmRpbmcgd2l0aCB0aGVcclxuICogZ2l2ZW4gZGF0YS4gQSBwcm9taXNlIGlzIHJldHVybmVkIGFuZCB3aWxsIGJlIGNvbXBsZXRlZCB3aGVuIHRoZVxyXG4gKiBiYWNrZW5kIHJlc3BvbmRzLiBUaGlzIHdpbGwgYmUgcmVzb2x2ZWQgd2hlbiB0aGUgY2FsbCB3YXMgc3VjY2Vzc2Z1bFxyXG4gKiBvciByZWplY3RlZCBpZiBhbiBlcnJvciBpcyBwYXNzZWQgYmFjay5cclxuICogVGhlcmUgaXMgYSB0aW1lb3V0IG1lY2hhbmlzbS4gSWYgdGhlIGNhbGwgZG9lc24ndCByZXNwb25kIGluIHRoZSBnaXZlblxyXG4gKiB0aW1lIChpbiBtaWxsaXNlY29uZHMpIHRoZW4gdGhlIHByb21pc2UgaXMgcmVqZWN0ZWQuXHJcbiAqXHJcbiAqIEBleHBvcnRcclxuICogQHBhcmFtIHtzdHJpbmd9IG5hbWVcclxuICogQHBhcmFtIHthbnk9fSBhcmdzXHJcbiAqIEBwYXJhbSB7bnVtYmVyPX0gdGltZW91dFxyXG4gKiBAcmV0dXJuc1xyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIENhbGwobmFtZSwgYXJncywgdGltZW91dCkge1xyXG5cclxuXHQvLyBUaW1lb3V0IGluZmluaXRlIGJ5IGRlZmF1bHRcclxuXHRpZiAodGltZW91dCA9PSBudWxsKSB7XHJcblx0XHR0aW1lb3V0ID0gMDtcclxuXHR9XHJcblxyXG5cdC8vIENyZWF0ZSBhIHByb21pc2VcclxuXHRyZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24gKHJlc29sdmUsIHJlamVjdCkge1xyXG5cclxuXHRcdC8vIENyZWF0ZSBhIHVuaXF1ZSBjYWxsYmFja0lEXHJcblx0XHR2YXIgY2FsbGJhY2tJRDtcclxuXHRcdGRvIHtcclxuXHRcdFx0Y2FsbGJhY2tJRCA9IG5hbWUgKyAnLScgKyByYW5kb21GdW5jKCk7XHJcblx0XHR9IHdoaWxlIChjYWxsYmFja3NbY2FsbGJhY2tJRF0pO1xyXG5cclxuXHRcdHZhciB0aW1lb3V0SGFuZGxlO1xyXG5cdFx0Ly8gU2V0IHRpbWVvdXRcclxuXHRcdGlmICh0aW1lb3V0ID4gMCkge1xyXG5cdFx0XHR0aW1lb3V0SGFuZGxlID0gc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XHJcblx0XHRcdFx0cmVqZWN0KEVycm9yKCdDYWxsIHRvICcgKyBuYW1lICsgJyB0aW1lZCBvdXQuIFJlcXVlc3QgSUQ6ICcgKyBjYWxsYmFja0lEKSk7XHJcblx0XHRcdH0sIHRpbWVvdXQpO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8vIFN0b3JlIGNhbGxiYWNrXHJcblx0XHRjYWxsYmFja3NbY2FsbGJhY2tJRF0gPSB7XHJcblx0XHRcdHRpbWVvdXRIYW5kbGU6IHRpbWVvdXRIYW5kbGUsXHJcblx0XHRcdHJlamVjdDogcmVqZWN0LFxyXG5cdFx0XHRyZXNvbHZlOiByZXNvbHZlXHJcblx0XHR9O1xyXG5cclxuXHRcdHRyeSB7XHJcblx0XHRcdGNvbnN0IHBheWxvYWQgPSB7XHJcblx0XHRcdFx0bmFtZSxcclxuXHRcdFx0XHRhcmdzLFxyXG5cdFx0XHRcdGNhbGxiYWNrSUQsXHJcblx0XHRcdH07XHJcblxyXG4gICAgICAgICAgICAvLyBNYWtlIHRoZSBjYWxsXHJcbiAgICAgICAgICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnQycgKyBKU09OLnN0cmluZ2lmeShwYXlsb2FkKSk7XHJcbiAgICAgICAgfSBjYXRjaCAoZSkge1xyXG4gICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmVcclxuICAgICAgICAgICAgY29uc29sZS5lcnJvcihlKTtcclxuICAgICAgICB9XHJcbiAgICB9KTtcclxufVxyXG5cclxud2luZG93Lk9iZnVzY2F0ZWRDYWxsID0gKGlkLCBhcmdzLCB0aW1lb3V0KSA9PiB7XHJcblxyXG4gICAgLy8gVGltZW91dCBpbmZpbml0ZSBieSBkZWZhdWx0XHJcbiAgICBpZiAodGltZW91dCA9PSBudWxsKSB7XHJcbiAgICAgICAgdGltZW91dCA9IDA7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ3JlYXRlIGEgcHJvbWlzZVxyXG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uIChyZXNvbHZlLCByZWplY3QpIHtcclxuXHJcbiAgICAgICAgLy8gQ3JlYXRlIGEgdW5pcXVlIGNhbGxiYWNrSURcclxuICAgICAgICB2YXIgY2FsbGJhY2tJRDtcclxuICAgICAgICBkbyB7XHJcbiAgICAgICAgICAgIGNhbGxiYWNrSUQgPSBpZCArICctJyArIHJhbmRvbUZ1bmMoKTtcclxuICAgICAgICB9IHdoaWxlIChjYWxsYmFja3NbY2FsbGJhY2tJRF0pO1xyXG5cclxuICAgICAgICB2YXIgdGltZW91dEhhbmRsZTtcclxuICAgICAgICAvLyBTZXQgdGltZW91dFxyXG4gICAgICAgIGlmICh0aW1lb3V0ID4gMCkge1xyXG4gICAgICAgICAgICB0aW1lb3V0SGFuZGxlID0gc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgICAgICByZWplY3QoRXJyb3IoJ0NhbGwgdG8gbWV0aG9kICcgKyBpZCArICcgdGltZWQgb3V0LiBSZXF1ZXN0IElEOiAnICsgY2FsbGJhY2tJRCkpO1xyXG4gICAgICAgICAgICB9LCB0aW1lb3V0KTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFN0b3JlIGNhbGxiYWNrXHJcbiAgICAgICAgY2FsbGJhY2tzW2NhbGxiYWNrSURdID0ge1xyXG4gICAgICAgICAgICB0aW1lb3V0SGFuZGxlOiB0aW1lb3V0SGFuZGxlLFxyXG4gICAgICAgICAgICByZWplY3Q6IHJlamVjdCxcclxuICAgICAgICAgICAgcmVzb2x2ZTogcmVzb2x2ZVxyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIGNvbnN0IHBheWxvYWQgPSB7XHJcblx0XHRcdFx0aWQsXHJcblx0XHRcdFx0YXJncyxcclxuXHRcdFx0XHRjYWxsYmFja0lELFxyXG5cdFx0XHR9O1xyXG5cclxuICAgICAgICAgICAgLy8gTWFrZSB0aGUgY2FsbFxyXG4gICAgICAgICAgICB3aW5kb3cuV2FpbHNJbnZva2UoJ2MnICsgSlNPTi5zdHJpbmdpZnkocGF5bG9hZCkpO1xyXG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcclxuICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lXHJcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZSk7XHJcbiAgICAgICAgfVxyXG4gICAgfSk7XHJcbn07XHJcblxyXG5cclxuLyoqXHJcbiAqIENhbGxlZCBieSB0aGUgYmFja2VuZCB0byByZXR1cm4gZGF0YSB0byBhIHByZXZpb3VzbHkgY2FsbGVkXHJcbiAqIGJpbmRpbmcgaW52b2NhdGlvblxyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBpbmNvbWluZ01lc3NhZ2VcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBDYWxsYmFjayhpbmNvbWluZ01lc3NhZ2UpIHtcclxuXHQvLyBQYXJzZSB0aGUgbWVzc2FnZVxyXG5cdGxldCBtZXNzYWdlO1xyXG5cdHRyeSB7XHJcblx0XHRtZXNzYWdlID0gSlNPTi5wYXJzZShpbmNvbWluZ01lc3NhZ2UpO1xyXG5cdH0gY2F0Y2ggKGUpIHtcclxuXHRcdGNvbnN0IGVycm9yID0gYEludmFsaWQgSlNPTiBwYXNzZWQgdG8gY2FsbGJhY2s6ICR7ZS5tZXNzYWdlfS4gTWVzc2FnZTogJHtpbmNvbWluZ01lc3NhZ2V9YDtcclxuXHRcdHJ1bnRpbWUuTG9nRGVidWcoZXJyb3IpO1xyXG5cdFx0dGhyb3cgbmV3IEVycm9yKGVycm9yKTtcclxuXHR9XHJcblx0bGV0IGNhbGxiYWNrSUQgPSBtZXNzYWdlLmNhbGxiYWNraWQ7XHJcblx0bGV0IGNhbGxiYWNrRGF0YSA9IGNhbGxiYWNrc1tjYWxsYmFja0lEXTtcclxuXHRpZiAoIWNhbGxiYWNrRGF0YSkge1xyXG5cdFx0Y29uc3QgZXJyb3IgPSBgQ2FsbGJhY2sgJyR7Y2FsbGJhY2tJRH0nIG5vdCByZWdpc3RlcmVkISEhYDtcclxuXHRcdGNvbnNvbGUuZXJyb3IoZXJyb3IpOyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lXHJcblx0XHR0aHJvdyBuZXcgRXJyb3IoZXJyb3IpO1xyXG5cdH1cclxuXHRjbGVhclRpbWVvdXQoY2FsbGJhY2tEYXRhLnRpbWVvdXRIYW5kbGUpO1xyXG5cclxuXHRkZWxldGUgY2FsbGJhY2tzW2NhbGxiYWNrSURdO1xyXG5cclxuXHRpZiAobWVzc2FnZS5lcnJvcikge1xyXG5cdFx0Y2FsbGJhY2tEYXRhLnJlamVjdChtZXNzYWdlLmVycm9yKTtcclxuXHR9IGVsc2Uge1xyXG5cdFx0Y2FsbGJhY2tEYXRhLnJlc29sdmUobWVzc2FnZS5yZXN1bHQpO1xyXG5cdH1cclxufVxyXG4iLCAiLypcclxuIF8gICAgICAgX18gICAgICBfIF9fICAgIFxyXG58IHwgICAgIC8gL19fXyBfKF8pIC9fX19fXHJcbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cclxufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApIFxyXG58X18vfF9fL1xcX18sXy9fL18vX19fXy8gIFxyXG5UaGUgZWxlY3Ryb24gYWx0ZXJuYXRpdmUgZm9yIEdvXHJcbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcclxuKi9cclxuLyoganNoaW50IGVzdmVyc2lvbjogNiAqL1xyXG5cclxuaW1wb3J0IHtDYWxsfSBmcm9tICcuL2NhbGxzJztcclxuXHJcbi8vIFRoaXMgaXMgd2hlcmUgd2UgYmluZCBnbyBtZXRob2Qgd3JhcHBlcnNcclxud2luZG93LmdvID0ge307XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gU2V0QmluZGluZ3MoYmluZGluZ3NNYXApIHtcclxuXHR0cnkge1xyXG5cdFx0YmluZGluZ3NNYXAgPSBKU09OLnBhcnNlKGJpbmRpbmdzTWFwKTtcclxuXHR9IGNhdGNoIChlKSB7XHJcblx0XHRjb25zb2xlLmVycm9yKGUpO1xyXG5cdH1cclxuXHJcblx0Ly8gSW5pdGlhbGlzZSB0aGUgYmluZGluZ3MgbWFwXHJcblx0d2luZG93LmdvID0gd2luZG93LmdvIHx8IHt9O1xyXG5cclxuXHQvLyBJdGVyYXRlIHBhY2thZ2UgbmFtZXNcclxuXHRPYmplY3Qua2V5cyhiaW5kaW5nc01hcCkuZm9yRWFjaCgocGFja2FnZU5hbWUpID0+IHtcclxuXHJcblx0XHQvLyBDcmVhdGUgaW5uZXIgbWFwIGlmIGl0IGRvZXNuJ3QgZXhpc3RcclxuXHRcdHdpbmRvdy5nb1twYWNrYWdlTmFtZV0gPSB3aW5kb3cuZ29bcGFja2FnZU5hbWVdIHx8IHt9O1xyXG5cclxuXHRcdC8vIEl0ZXJhdGUgc3RydWN0IG5hbWVzXHJcblx0XHRPYmplY3Qua2V5cyhiaW5kaW5nc01hcFtwYWNrYWdlTmFtZV0pLmZvckVhY2goKHN0cnVjdE5hbWUpID0+IHtcclxuXHJcblx0XHRcdC8vIENyZWF0ZSBpbm5lciBtYXAgaWYgaXQgZG9lc24ndCBleGlzdFxyXG5cdFx0XHR3aW5kb3cuZ29bcGFja2FnZU5hbWVdW3N0cnVjdE5hbWVdID0gd2luZG93LmdvW3BhY2thZ2VOYW1lXVtzdHJ1Y3ROYW1lXSB8fCB7fTtcclxuXHJcblx0XHRcdE9iamVjdC5rZXlzKGJpbmRpbmdzTWFwW3BhY2thZ2VOYW1lXVtzdHJ1Y3ROYW1lXSkuZm9yRWFjaCgobWV0aG9kTmFtZSkgPT4ge1xyXG5cclxuXHRcdFx0XHR3aW5kb3cuZ29bcGFja2FnZU5hbWVdW3N0cnVjdE5hbWVdW21ldGhvZE5hbWVdID0gZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdFx0XHRcdC8vIE5vIHRpbWVvdXQgYnkgZGVmYXVsdFxyXG5cdFx0XHRcdFx0bGV0IHRpbWVvdXQgPSAwO1xyXG5cclxuXHRcdFx0XHRcdC8vIEFjdHVhbCBmdW5jdGlvblxyXG5cdFx0XHRcdFx0ZnVuY3Rpb24gZHluYW1pYygpIHtcclxuXHRcdFx0XHRcdFx0Y29uc3QgYXJncyA9IFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzKTtcclxuXHRcdFx0XHRcdFx0cmV0dXJuIENhbGwoW3BhY2thZ2VOYW1lLCBzdHJ1Y3ROYW1lLCBtZXRob2ROYW1lXS5qb2luKCcuJyksIGFyZ3MsIHRpbWVvdXQpO1xyXG5cdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdC8vIEFsbG93IHNldHRpbmcgdGltZW91dCB0byBmdW5jdGlvblxyXG5cdFx0XHRcdFx0ZHluYW1pYy5zZXRUaW1lb3V0ID0gZnVuY3Rpb24gKG5ld1RpbWVvdXQpIHtcclxuXHRcdFx0XHRcdFx0dGltZW91dCA9IG5ld1RpbWVvdXQ7XHJcblx0XHRcdFx0XHR9O1xyXG5cclxuXHRcdFx0XHRcdC8vIEFsbG93IGdldHRpbmcgdGltZW91dCB0byBmdW5jdGlvblxyXG5cdFx0XHRcdFx0ZHluYW1pYy5nZXRUaW1lb3V0ID0gZnVuY3Rpb24gKCkge1xyXG5cdFx0XHRcdFx0XHRyZXR1cm4gdGltZW91dDtcclxuXHRcdFx0XHRcdH07XHJcblxyXG5cdFx0XHRcdFx0cmV0dXJuIGR5bmFtaWM7XHJcblx0XHRcdFx0fSgpO1xyXG5cdFx0XHR9KTtcclxuXHRcdH0pO1xyXG5cdH0pO1xyXG59XHJcbiIsICIvKlxyXG4gX1x0ICAgX19cdCAgXyBfX1xyXG58IHxcdCAvIC9fX18gXyhfKSAvX19fX1xyXG58IHwgL3wgLyAvIF9fIGAvIC8gLyBfX18vXHJcbnwgfC8gfC8gLyAvXy8gLyAvIChfXyAgKVxyXG58X18vfF9fL1xcX18sXy9fL18vX19fXy9cclxuVGhlIGVsZWN0cm9uIGFsdGVybmF0aXZlIGZvciBHb1xyXG4oYykgTGVhIEFudGhvbnkgMjAxOS1wcmVzZW50XHJcbiovXHJcblxyXG4vKiBqc2hpbnQgZXN2ZXJzaW9uOiA5ICovXHJcblxyXG5cclxuaW1wb3J0IHtDYWxsfSBmcm9tIFwiLi9jYWxsc1wiO1xyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd1JlbG9hZCgpIHtcclxuICAgIHdpbmRvdy5sb2NhdGlvbi5yZWxvYWQoKTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd1JlbG9hZEFwcCgpIHtcclxuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnV1InKTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd1NldFN5c3RlbURlZmF1bHRUaGVtZSgpIHtcclxuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnV0FTRFQnKTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd1NldExpZ2h0VGhlbWUoKSB7XHJcbiAgICB3aW5kb3cuV2FpbHNJbnZva2UoJ1dBTFQnKTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd1NldERhcmtUaGVtZSgpIHtcclxuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnV0FEVCcpO1xyXG59XHJcblxyXG4vKipcclxuICogUGxhY2UgdGhlIHdpbmRvdyBpbiB0aGUgY2VudGVyIG9mIHRoZSBzY3JlZW5cclxuICpcclxuICogQGV4cG9ydFxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd0NlbnRlcigpIHtcclxuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnV2MnKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIHdpbmRvdyB0aXRsZVxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdGl0bGVcclxuICogQGV4cG9ydFxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd1NldFRpdGxlKHRpdGxlKSB7XHJcbiAgICB3aW5kb3cuV2FpbHNJbnZva2UoJ1dUJyArIHRpdGxlKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIE1ha2VzIHRoZSB3aW5kb3cgZ28gZnVsbHNjcmVlblxyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gV2luZG93RnVsbHNjcmVlbigpIHtcclxuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnV0YnKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJldmVydHMgdGhlIHdpbmRvdyBmcm9tIGZ1bGxzY3JlZW5cclxuICpcclxuICogQGV4cG9ydFxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd1VuZnVsbHNjcmVlbigpIHtcclxuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnV2YnKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHVybnMgdGhlIHN0YXRlIG9mIHRoZSB3aW5kb3csIGkuZS4gd2hldGhlciB0aGUgd2luZG93IGlzIGluIGZ1bGwgc2NyZWVuIG1vZGUgb3Igbm90LlxyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqIEByZXR1cm4ge1Byb21pc2U8Ym9vbGVhbj59IFRoZSBzdGF0ZSBvZiB0aGUgd2luZG93XHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gV2luZG93SXNGdWxsc2NyZWVuKCkge1xyXG4gICAgcmV0dXJuIENhbGwoXCI6d2FpbHM6V2luZG93SXNGdWxsc2NyZWVuXCIpO1xyXG59XHJcblxyXG4vKipcclxuICogU2V0IHRoZSBTaXplIG9mIHRoZSB3aW5kb3dcclxuICpcclxuICogQGV4cG9ydFxyXG4gKiBAcGFyYW0ge251bWJlcn0gd2lkdGhcclxuICogQHBhcmFtIHtudW1iZXJ9IGhlaWdodFxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd1NldFNpemUod2lkdGgsIGhlaWdodCkge1xyXG4gICAgd2luZG93LldhaWxzSW52b2tlKCdXczonICsgd2lkdGggKyAnOicgKyBoZWlnaHQpO1xyXG59XHJcblxyXG4vKipcclxuICogR2V0IHRoZSBTaXplIG9mIHRoZSB3aW5kb3dcclxuICpcclxuICogQGV4cG9ydFxyXG4gKiBAcmV0dXJuIHtQcm9taXNlPHt3OiBudW1iZXIsIGg6IG51bWJlcn0+fSBUaGUgc2l6ZSBvZiB0aGUgd2luZG93XHJcblxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd0dldFNpemUoKSB7XHJcbiAgICByZXR1cm4gQ2FsbChcIjp3YWlsczpXaW5kb3dHZXRTaXplXCIpO1xyXG59XHJcblxyXG4vKipcclxuICogU2V0IHRoZSBtYXhpbXVtIHNpemUgb2YgdGhlIHdpbmRvd1xyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aFxyXG4gKiBAcGFyYW0ge251bWJlcn0gaGVpZ2h0XHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gV2luZG93U2V0TWF4U2l6ZSh3aWR0aCwgaGVpZ2h0KSB7XHJcbiAgICB3aW5kb3cuV2FpbHNJbnZva2UoJ1daOicgKyB3aWR0aCArICc6JyArIGhlaWdodCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXQgdGhlIG1pbmltdW0gc2l6ZSBvZiB0aGUgd2luZG93XHJcbiAqXHJcbiAqIEBleHBvcnRcclxuICogQHBhcmFtIHtudW1iZXJ9IHdpZHRoXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBoZWlnaHRcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBXaW5kb3dTZXRNaW5TaXplKHdpZHRoLCBoZWlnaHQpIHtcclxuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnV3o6JyArIHdpZHRoICsgJzonICsgaGVpZ2h0KTtcclxufVxyXG5cclxuXHJcblxyXG4vKipcclxuICogU2V0IHRoZSB3aW5kb3cgQWx3YXlzT25Ub3Agb3Igbm90IG9uIHRvcFxyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gV2luZG93U2V0QWx3YXlzT25Ub3AoYikge1xyXG5cclxuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnV0FUUDonICsgKGIgPyAnMScgOiAnMCcpKTtcclxufVxyXG5cclxuXHJcblxyXG5cclxuLyoqXHJcbiAqIFNldCB0aGUgUG9zaXRpb24gb2YgdGhlIHdpbmRvd1xyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB4XHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB5XHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gV2luZG93U2V0UG9zaXRpb24oeCwgeSkge1xyXG4gICAgd2luZG93LldhaWxzSW52b2tlKCdXcDonICsgeCArICc6JyArIHkpO1xyXG59XHJcblxyXG4vKipcclxuICogR2V0IHRoZSBQb3NpdGlvbiBvZiB0aGUgd2luZG93XHJcbiAqXHJcbiAqIEBleHBvcnRcclxuICogQHJldHVybiB7UHJvbWlzZTx7eDogbnVtYmVyLCB5OiBudW1iZXJ9Pn0gVGhlIHBvc2l0aW9uIG9mIHRoZSB3aW5kb3dcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBXaW5kb3dHZXRQb3NpdGlvbigpIHtcclxuICAgIHJldHVybiBDYWxsKFwiOndhaWxzOldpbmRvd0dldFBvc1wiKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEhpZGUgdGhlIFdpbmRvd1xyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gV2luZG93SGlkZSgpIHtcclxuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnV0gnKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNob3cgdGhlIFdpbmRvd1xyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gV2luZG93U2hvdygpIHtcclxuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnV1MnKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIE1heGltaXNlIHRoZSBXaW5kb3dcclxuICpcclxuICogQGV4cG9ydFxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd01heGltaXNlKCkge1xyXG4gICAgd2luZG93LldhaWxzSW52b2tlKCdXTScpO1xyXG59XHJcblxyXG4vKipcclxuICogVG9nZ2xlIHRoZSBNYXhpbWlzZSBvZiB0aGUgV2luZG93XHJcbiAqXHJcbiAqIEBleHBvcnRcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBXaW5kb3dUb2dnbGVNYXhpbWlzZSgpIHtcclxuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnV3QnKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFVubWF4aW1pc2UgdGhlIFdpbmRvd1xyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gV2luZG93VW5tYXhpbWlzZSgpIHtcclxuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnV1UnKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHVybnMgdGhlIHN0YXRlIG9mIHRoZSB3aW5kb3csIGkuZS4gd2hldGhlciB0aGUgd2luZG93IGlzIG1heGltaXNlZCBvciBub3QuXHJcbiAqXHJcbiAqIEBleHBvcnRcclxuICogQHJldHVybiB7UHJvbWlzZTxib29sZWFuPn0gVGhlIHN0YXRlIG9mIHRoZSB3aW5kb3dcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBXaW5kb3dJc01heGltaXNlZCgpIHtcclxuICAgIHJldHVybiBDYWxsKFwiOndhaWxzOldpbmRvd0lzTWF4aW1pc2VkXCIpO1xyXG59XHJcblxyXG4vKipcclxuICogTWluaW1pc2UgdGhlIFdpbmRvd1xyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gV2luZG93TWluaW1pc2UoKSB7XHJcbiAgICB3aW5kb3cuV2FpbHNJbnZva2UoJ1dtJyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBVbm1pbmltaXNlIHRoZSBXaW5kb3dcclxuICpcclxuICogQGV4cG9ydFxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd1VubWluaW1pc2UoKSB7XHJcbiAgICB3aW5kb3cuV2FpbHNJbnZva2UoJ1d1Jyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXR1cm5zIHRoZSBzdGF0ZSBvZiB0aGUgd2luZG93LCBpLmUuIHdoZXRoZXIgdGhlIHdpbmRvdyBpcyBtaW5pbWlzZWQgb3Igbm90LlxyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqIEByZXR1cm4ge1Byb21pc2U8Ym9vbGVhbj59IFRoZSBzdGF0ZSBvZiB0aGUgd2luZG93XHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gV2luZG93SXNNaW5pbWlzZWQoKSB7XHJcbiAgICByZXR1cm4gQ2FsbChcIjp3YWlsczpXaW5kb3dJc01pbmltaXNlZFwiKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHVybnMgdGhlIHN0YXRlIG9mIHRoZSB3aW5kb3csIGkuZS4gd2hldGhlciB0aGUgd2luZG93IGlzIG5vcm1hbCBvciBub3QuXHJcbiAqXHJcbiAqIEBleHBvcnRcclxuICogQHJldHVybiB7UHJvbWlzZTxib29sZWFuPn0gVGhlIHN0YXRlIG9mIHRoZSB3aW5kb3dcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBXaW5kb3dJc05vcm1hbCgpIHtcclxuICAgIHJldHVybiBDYWxsKFwiOndhaWxzOldpbmRvd0lzTm9ybWFsXCIpO1xyXG59XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgYmFja2dyb3VuZCBjb2xvdXIgb2YgdGhlIHdpbmRvd1xyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBSIFJlZFxyXG4gKiBAcGFyYW0ge251bWJlcn0gRyBHcmVlblxyXG4gKiBAcGFyYW0ge251bWJlcn0gQiBCbHVlXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBBIEFscGhhXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gV2luZG93U2V0QmFja2dyb3VuZENvbG91cihSLCBHLCBCLCBBKSB7XHJcbiAgICBsZXQgcmdiYSA9IEpTT04uc3RyaW5naWZ5KHtyOiBSIHx8IDAsIGc6IEcgfHwgMCwgYjogQiB8fCAwLCBhOiBBIHx8IDI1NX0pO1xyXG4gICAgd2luZG93LldhaWxzSW52b2tlKCdXcjonICsgcmdiYSk7XHJcbn1cclxuXHJcbiIsICIvKlxyXG4gX1x0ICAgX19cdCAgXyBfX1xyXG58IHxcdCAvIC9fX18gXyhfKSAvX19fX1xyXG58IHwgL3wgLyAvIF9fIGAvIC8gLyBfX18vXHJcbnwgfC8gfC8gLyAvXy8gLyAvIChfXyAgKVxyXG58X18vfF9fL1xcX18sXy9fL18vX19fXy9cclxuVGhlIGVsZWN0cm9uIGFsdGVybmF0aXZlIGZvciBHb1xyXG4oYykgTGVhIEFudGhvbnkgMjAxOS1wcmVzZW50XHJcbiovXHJcblxyXG4vKiBqc2hpbnQgZXN2ZXJzaW9uOiA5ICovXHJcblxyXG5cclxuaW1wb3J0IHtDYWxsfSBmcm9tIFwiLi9jYWxsc1wiO1xyXG5cclxuXHJcbi8qKlxyXG4gKiBHZXRzIHRoZSBhbGwgc2NyZWVucy4gQ2FsbCB0aGlzIGFuZXcgZWFjaCB0aW1lIHlvdSB3YW50IHRvIHJlZnJlc2ggZGF0YSBmcm9tIHRoZSB1bmRlcmx5aW5nIHdpbmRvd2luZyBzeXN0ZW0uXHJcbiAqIEBleHBvcnRcclxuICogQHR5cGVkZWYge2ltcG9ydCgnLi4vd3JhcHBlci9ydW50aW1lJykuU2NyZWVufSBTY3JlZW5cclxuICogQHJldHVybiB7UHJvbWlzZTx7U2NyZWVuW119Pn0gVGhlIHNjcmVlbnNcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBTY3JlZW5HZXRBbGwoKSB7XHJcbiAgICByZXR1cm4gQ2FsbChcIjp3YWlsczpTY3JlZW5HZXRBbGxcIik7XHJcbn1cclxuIiwgIi8qKlxyXG4gKiBAZGVzY3JpcHRpb246IFVzZSB0aGUgc3lzdGVtIGRlZmF1bHQgYnJvd3NlciB0byBvcGVuIHRoZSB1cmxcclxuICogQHBhcmFtIHtzdHJpbmd9IHVybCBcclxuICogQHJldHVybiB7dm9pZH1cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBCcm93c2VyT3BlblVSTCh1cmwpIHtcclxuICB3aW5kb3cuV2FpbHNJbnZva2UoJ0JPOicgKyB1cmwpO1xyXG59IiwgIi8qXHJcbiBfXHQgICBfX1x0ICBfIF9fXHJcbnwgfFx0IC8gL19fXyBfKF8pIC9fX19fXHJcbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cclxufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApXHJcbnxfXy98X18vXFxfXyxfL18vXy9fX19fL1xyXG5UaGUgZWxlY3Ryb24gYWx0ZXJuYXRpdmUgZm9yIEdvXHJcbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcclxuKi9cclxuLyoganNoaW50IGVzdmVyc2lvbjogOSAqL1xyXG5pbXBvcnQgKiBhcyBMb2cgZnJvbSAnLi9sb2cnO1xyXG5pbXBvcnQge2V2ZW50TGlzdGVuZXJzLCBFdmVudHNFbWl0LCBFdmVudHNOb3RpZnksIEV2ZW50c09mZiwgRXZlbnRzT24sIEV2ZW50c09uY2UsIEV2ZW50c09uTXVsdGlwbGV9IGZyb20gJy4vZXZlbnRzJztcclxuaW1wb3J0IHtDYWxsLCBDYWxsYmFjaywgY2FsbGJhY2tzfSBmcm9tICcuL2NhbGxzJztcclxuaW1wb3J0IHtTZXRCaW5kaW5nc30gZnJvbSBcIi4vYmluZGluZ3NcIjtcclxuaW1wb3J0ICogYXMgV2luZG93IGZyb20gXCIuL3dpbmRvd1wiO1xyXG5pbXBvcnQgKiBhcyBTY3JlZW4gZnJvbSBcIi4vc2NyZWVuXCI7XHJcbmltcG9ydCAqIGFzIEJyb3dzZXIgZnJvbSBcIi4vYnJvd3NlclwiO1xyXG5cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBRdWl0KCkge1xyXG4gICAgd2luZG93LldhaWxzSW52b2tlKCdRJyk7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBTaG93KCkge1xyXG4gICAgd2luZG93LldhaWxzSW52b2tlKCdTJyk7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBIaWRlKCkge1xyXG4gICAgd2luZG93LldhaWxzSW52b2tlKCdIJyk7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBFbnZpcm9ubWVudCgpIHtcclxuICAgIHJldHVybiBDYWxsKFwiOndhaWxzOkVudmlyb25tZW50XCIpO1xyXG59XHJcblxyXG4vLyBUaGUgSlMgcnVudGltZVxyXG53aW5kb3cucnVudGltZSA9IHtcclxuICAgIC4uLkxvZyxcclxuICAgIC4uLldpbmRvdyxcclxuICAgIC4uLkJyb3dzZXIsXHJcbiAgICAuLi5TY3JlZW4sXHJcbiAgICBFdmVudHNPbixcclxuICAgIEV2ZW50c09uY2UsXHJcbiAgICBFdmVudHNPbk11bHRpcGxlLFxyXG4gICAgRXZlbnRzRW1pdCxcclxuICAgIEV2ZW50c09mZixcclxuICAgIEVudmlyb25tZW50LFxyXG4gICAgU2hvdyxcclxuICAgIEhpZGUsXHJcbiAgICBRdWl0XHJcbn07XHJcblxyXG4vLyBJbnRlcm5hbCB3YWlscyBlbmRwb2ludHNcclxud2luZG93LndhaWxzID0ge1xyXG4gICAgQ2FsbGJhY2ssXHJcbiAgICBFdmVudHNOb3RpZnksXHJcbiAgICBTZXRCaW5kaW5ncyxcclxuICAgIGV2ZW50TGlzdGVuZXJzLFxyXG4gICAgY2FsbGJhY2tzLFxyXG4gICAgZmxhZ3M6IHtcclxuICAgICAgICBkaXNhYmxlU2Nyb2xsYmFyRHJhZzogZmFsc2UsXHJcbiAgICAgICAgZGlzYWJsZVdhaWxzRGVmYXVsdENvbnRleHRNZW51OiBmYWxzZSxcclxuICAgICAgICBlbmFibGVSZXNpemU6IGZhbHNlLFxyXG4gICAgICAgIGRlZmF1bHRDdXJzb3I6IG51bGwsXHJcbiAgICAgICAgYm9yZGVyVGhpY2tuZXNzOiA2LFxyXG4gICAgICAgIHNob3VsZERyYWc6IGZhbHNlLFxyXG4gICAgICAgIGNzc0RyYWdQcm9wZXJ0eTogXCItLXdhaWxzLWRyYWdnYWJsZVwiLFxyXG4gICAgICAgIGNzc0RyYWdWYWx1ZTogXCJkcmFnXCIsXHJcbiAgICB9XHJcbn07XHJcblxyXG4vLyBTZXQgdGhlIGJpbmRpbmdzXHJcbmlmICh3aW5kb3cud2FpbHNiaW5kaW5ncykge1xyXG4gICAgd2luZG93LndhaWxzLlNldEJpbmRpbmdzKHdpbmRvdy53YWlsc2JpbmRpbmdzKTtcclxuICAgIGRlbGV0ZSB3aW5kb3cud2FpbHMuU2V0QmluZGluZ3M7XHJcbn1cclxuXHJcbi8vIFRoaXMgaXMgZXZhbHVhdGVkIGF0IGJ1aWxkIHRpbWUgaW4gcGFja2FnZS5qc29uXHJcbi8vIGNvbnN0IGRldiA9IDA7XHJcbi8vIGNvbnN0IHByb2R1Y3Rpb24gPSAxO1xyXG5pZiAoRU5WID09PSAxKSB7XHJcbiAgICBkZWxldGUgd2luZG93LndhaWxzYmluZGluZ3M7XHJcbn1cclxuXHJcbndpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdtb3VzZXVwJywgKCkgPT4ge1xyXG4gICAgd2luZG93LndhaWxzLmZsYWdzLnNob3VsZERyYWcgPSBmYWxzZTtcclxufSk7XHJcblxyXG5sZXQgZHJhZ1Rlc3QgPSBmdW5jdGlvbiAoZSkge1xyXG4gICAgcmV0dXJuIHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlKGUudGFyZ2V0KS5nZXRQcm9wZXJ0eVZhbHVlKHdpbmRvdy53YWlscy5mbGFncy5jc3NEcmFnUHJvcGVydHkpID09PSB3aW5kb3cud2FpbHMuZmxhZ3MuY3NzRHJhZ1ZhbHVlO1xyXG59O1xyXG5cclxud2luZG93LndhaWxzLnNldENTU0RyYWdQcm9wZXJ0aWVzID0gZnVuY3Rpb24gKHByb3BlcnR5LCB2YWx1ZSkge1xyXG4gICAgd2luZG93LndhaWxzLmZsYWdzLmNzc0RyYWdQcm9wZXJ0eSA9IHByb3BlcnR5O1xyXG4gICAgd2luZG93LndhaWxzLmZsYWdzLmNzc0RyYWdWYWx1ZSA9IHZhbHVlO1xyXG59XHJcblxyXG53aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignbW91c2Vkb3duJywgKGUpID0+IHtcclxuXHJcbiAgICAvLyBDaGVjayBmb3IgcmVzaXppbmdcclxuICAgIGlmICh3aW5kb3cud2FpbHMuZmxhZ3MucmVzaXplRWRnZSkge1xyXG4gICAgICAgIHdpbmRvdy5XYWlsc0ludm9rZShcInJlc2l6ZTpcIiArIHdpbmRvdy53YWlscy5mbGFncy5yZXNpemVFZGdlKTtcclxuICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XHJcbiAgICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChkcmFnVGVzdChlKSkge1xyXG4gICAgICAgIGlmICh3aW5kb3cud2FpbHMuZmxhZ3MuZGlzYWJsZVNjcm9sbGJhckRyYWcpIHtcclxuICAgICAgICAgICAgLy8gVGhpcyBjaGVja3MgZm9yIGNsaWNrcyBvbiB0aGUgc2Nyb2xsIGJhclxyXG4gICAgICAgICAgICBpZiAoZS5vZmZzZXRYID4gZS50YXJnZXQuY2xpZW50V2lkdGggfHwgZS5vZmZzZXRZID4gZS50YXJnZXQuY2xpZW50SGVpZ2h0KSB7XHJcbiAgICAgICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICAgd2luZG93LndhaWxzLmZsYWdzLnNob3VsZERyYWcgPSB0cnVlO1xyXG4gICAgfVxyXG5cclxufSk7XHJcblxyXG5mdW5jdGlvbiBzZXRSZXNpemUoY3Vyc29yKSB7XHJcbiAgICBkb2N1bWVudC5ib2R5LnN0eWxlLmN1cnNvciA9IGN1cnNvciB8fCB3aW5kb3cud2FpbHMuZmxhZ3MuZGVmYXVsdEN1cnNvcjtcclxuICAgIHdpbmRvdy53YWlscy5mbGFncy5yZXNpemVFZGdlID0gY3Vyc29yO1xyXG59XHJcblxyXG53aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignbW91c2Vtb3ZlJywgZnVuY3Rpb24gKGUpIHtcclxuICAgIGlmICh3aW5kb3cud2FpbHMuZmxhZ3Muc2hvdWxkRHJhZykge1xyXG4gICAgICAgIHdpbmRvdy5XYWlsc0ludm9rZShcImRyYWdcIik7XHJcbiAgICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG4gICAgaWYgKCF3aW5kb3cud2FpbHMuZmxhZ3MuZW5hYmxlUmVzaXplKSB7XHJcbiAgICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG4gICAgaWYgKHdpbmRvdy53YWlscy5mbGFncy5kZWZhdWx0Q3Vyc29yID09IG51bGwpIHtcclxuICAgICAgICB3aW5kb3cud2FpbHMuZmxhZ3MuZGVmYXVsdEN1cnNvciA9IGRvY3VtZW50LmJvZHkuc3R5bGUuY3Vyc29yO1xyXG4gICAgfVxyXG4gICAgaWYgKHdpbmRvdy5vdXRlcldpZHRoIC0gZS5jbGllbnRYIDwgd2luZG93LndhaWxzLmZsYWdzLmJvcmRlclRoaWNrbmVzcyAmJiB3aW5kb3cub3V0ZXJIZWlnaHQgLSBlLmNsaWVudFkgPCB3aW5kb3cud2FpbHMuZmxhZ3MuYm9yZGVyVGhpY2tuZXNzKSB7XHJcbiAgICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS5jdXJzb3IgPSBcInNlLXJlc2l6ZVwiO1xyXG4gICAgfVxyXG4gICAgbGV0IHJpZ2h0Qm9yZGVyID0gd2luZG93Lm91dGVyV2lkdGggLSBlLmNsaWVudFggPCB3aW5kb3cud2FpbHMuZmxhZ3MuYm9yZGVyVGhpY2tuZXNzO1xyXG4gICAgbGV0IGxlZnRCb3JkZXIgPSBlLmNsaWVudFggPCB3aW5kb3cud2FpbHMuZmxhZ3MuYm9yZGVyVGhpY2tuZXNzO1xyXG4gICAgbGV0IHRvcEJvcmRlciA9IGUuY2xpZW50WSA8IHdpbmRvdy53YWlscy5mbGFncy5ib3JkZXJUaGlja25lc3M7XHJcbiAgICBsZXQgYm90dG9tQm9yZGVyID0gd2luZG93Lm91dGVySGVpZ2h0IC0gZS5jbGllbnRZIDwgd2luZG93LndhaWxzLmZsYWdzLmJvcmRlclRoaWNrbmVzcztcclxuXHJcbiAgICAvLyBJZiB3ZSBhcmVuJ3Qgb24gYW4gZWRnZSwgYnV0IHdlcmUsIHJlc2V0IHRoZSBjdXJzb3IgdG8gZGVmYXVsdFxyXG4gICAgaWYgKCFsZWZ0Qm9yZGVyICYmICFyaWdodEJvcmRlciAmJiAhdG9wQm9yZGVyICYmICFib3R0b21Cb3JkZXIgJiYgd2luZG93LndhaWxzLmZsYWdzLnJlc2l6ZUVkZ2UgIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgIHNldFJlc2l6ZSgpO1xyXG4gICAgfSBlbHNlIGlmIChyaWdodEJvcmRlciAmJiBib3R0b21Cb3JkZXIpIHNldFJlc2l6ZShcInNlLXJlc2l6ZVwiKTtcclxuICAgIGVsc2UgaWYgKGxlZnRCb3JkZXIgJiYgYm90dG9tQm9yZGVyKSBzZXRSZXNpemUoXCJzdy1yZXNpemVcIik7XHJcbiAgICBlbHNlIGlmIChsZWZ0Qm9yZGVyICYmIHRvcEJvcmRlcikgc2V0UmVzaXplKFwibnctcmVzaXplXCIpO1xyXG4gICAgZWxzZSBpZiAodG9wQm9yZGVyICYmIHJpZ2h0Qm9yZGVyKSBzZXRSZXNpemUoXCJuZS1yZXNpemVcIik7XHJcbiAgICBlbHNlIGlmIChsZWZ0Qm9yZGVyKSBzZXRSZXNpemUoXCJ3LXJlc2l6ZVwiKTtcclxuICAgIGVsc2UgaWYgKHRvcEJvcmRlcikgc2V0UmVzaXplKFwibi1yZXNpemVcIik7XHJcbiAgICBlbHNlIGlmIChib3R0b21Cb3JkZXIpIHNldFJlc2l6ZShcInMtcmVzaXplXCIpO1xyXG4gICAgZWxzZSBpZiAocmlnaHRCb3JkZXIpIHNldFJlc2l6ZShcImUtcmVzaXplXCIpO1xyXG5cclxufSk7XHJcblxyXG4vLyBTZXR1cCBjb250ZXh0IG1lbnUgaG9va1xyXG53aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignY29udGV4dG1lbnUnLCBmdW5jdGlvbiAoZSkge1xyXG4gICAgaWYgKHdpbmRvdy53YWlscy5mbGFncy5kaXNhYmxlV2FpbHNEZWZhdWx0Q29udGV4dE1lbnUpIHtcclxuICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XHJcbiAgICB9XHJcbn0pO1xyXG5cclxud2luZG93LldhaWxzSW52b2tlKFwicnVudGltZTpyZWFkeVwiKTsiXSwKICAibWFwcGluZ3MiOiAiOzs7Ozs7OztBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFB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 +//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiZGVza3RvcC9sb2cuanMiLCAiZGVza3RvcC9ldmVudHMuanMiLCAiZGVza3RvcC9jYWxscy5qcyIsICJkZXNrdG9wL2JpbmRpbmdzLmpzIiwgImRlc2t0b3Avd2luZG93LmpzIiwgImRlc2t0b3Avc2NyZWVuLmpzIiwgImRlc2t0b3AvYnJvd3Nlci5qcyIsICJkZXNrdG9wL21haW4uanMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbIi8qXG4gXyAgICAgICBfXyAgICAgIF8gX19cbnwgfCAgICAgLyAvX19fIF8oXykgL19fX19cbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cbnwgfC8gfC8gLyAvXy8gLyAvIChfXyAgKVxufF9fL3xfXy9cXF9fLF8vXy9fL19fX18vXG5UaGUgZWxlY3Ryb24gYWx0ZXJuYXRpdmUgZm9yIEdvXG4oYykgTGVhIEFudGhvbnkgMjAxOS1wcmVzZW50XG4qL1xuXG4vKiBqc2hpbnQgZXN2ZXJzaW9uOiA2ICovXG5cbi8qKlxuICogU2VuZHMgYSBsb2cgbWVzc2FnZSB0byB0aGUgYmFja2VuZCB3aXRoIHRoZSBnaXZlbiBsZXZlbCArIG1lc3NhZ2VcbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gbGV2ZWxcbiAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlXG4gKi9cbmZ1bmN0aW9uIHNlbmRMb2dNZXNzYWdlKGxldmVsLCBtZXNzYWdlKSB7XG5cblx0Ly8gTG9nIE1lc3NhZ2UgZm9ybWF0OlxuXHQvLyBsW3R5cGVdW21lc3NhZ2VdXG5cdHdpbmRvdy5XYWlsc0ludm9rZSgnTCcgKyBsZXZlbCArIG1lc3NhZ2UpO1xufVxuXG4vKipcbiAqIExvZyB0aGUgZ2l2ZW4gdHJhY2UgbWVzc2FnZSB3aXRoIHRoZSBiYWNrZW5kXG4gKlxuICogQGV4cG9ydFxuICogQHBhcmFtIHtzdHJpbmd9IG1lc3NhZ2VcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIExvZ1RyYWNlKG1lc3NhZ2UpIHtcblx0c2VuZExvZ01lc3NhZ2UoJ1QnLCBtZXNzYWdlKTtcbn1cblxuLyoqXG4gKiBMb2cgdGhlIGdpdmVuIG1lc3NhZ2Ugd2l0aCB0aGUgYmFja2VuZFxuICpcbiAqIEBleHBvcnRcbiAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBMb2dQcmludChtZXNzYWdlKSB7XG5cdHNlbmRMb2dNZXNzYWdlKCdQJywgbWVzc2FnZSk7XG59XG5cbi8qKlxuICogTG9nIHRoZSBnaXZlbiBkZWJ1ZyBtZXNzYWdlIHdpdGggdGhlIGJhY2tlbmRcbiAqXG4gKiBAZXhwb3J0XG4gKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZVxuICovXG5leHBvcnQgZnVuY3Rpb24gTG9nRGVidWcobWVzc2FnZSkge1xuXHRzZW5kTG9nTWVzc2FnZSgnRCcsIG1lc3NhZ2UpO1xufVxuXG4vKipcbiAqIExvZyB0aGUgZ2l2ZW4gaW5mbyBtZXNzYWdlIHdpdGggdGhlIGJhY2tlbmRcbiAqXG4gKiBAZXhwb3J0XG4gKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZVxuICovXG5leHBvcnQgZnVuY3Rpb24gTG9nSW5mbyhtZXNzYWdlKSB7XG5cdHNlbmRMb2dNZXNzYWdlKCdJJywgbWVzc2FnZSk7XG59XG5cbi8qKlxuICogTG9nIHRoZSBnaXZlbiB3YXJuaW5nIG1lc3NhZ2Ugd2l0aCB0aGUgYmFja2VuZFxuICpcbiAqIEBleHBvcnRcbiAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBMb2dXYXJuaW5nKG1lc3NhZ2UpIHtcblx0c2VuZExvZ01lc3NhZ2UoJ1cnLCBtZXNzYWdlKTtcbn1cblxuLyoqXG4gKiBMb2cgdGhlIGdpdmVuIGVycm9yIG1lc3NhZ2Ugd2l0aCB0aGUgYmFja2VuZFxuICpcbiAqIEBleHBvcnRcbiAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBMb2dFcnJvcihtZXNzYWdlKSB7XG5cdHNlbmRMb2dNZXNzYWdlKCdFJywgbWVzc2FnZSk7XG59XG5cbi8qKlxuICogTG9nIHRoZSBnaXZlbiBmYXRhbCBtZXNzYWdlIHdpdGggdGhlIGJhY2tlbmRcbiAqXG4gKiBAZXhwb3J0XG4gKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZVxuICovXG5leHBvcnQgZnVuY3Rpb24gTG9nRmF0YWwobWVzc2FnZSkge1xuXHRzZW5kTG9nTWVzc2FnZSgnRicsIG1lc3NhZ2UpO1xufVxuXG4vKipcbiAqIFNldHMgdGhlIExvZyBsZXZlbCB0byB0aGUgZ2l2ZW4gbG9nIGxldmVsXG4gKlxuICogQGV4cG9ydFxuICogQHBhcmFtIHtudW1iZXJ9IGxvZ2xldmVsXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBTZXRMb2dMZXZlbChsb2dsZXZlbCkge1xuXHRzZW5kTG9nTWVzc2FnZSgnUycsIGxvZ2xldmVsKTtcbn1cblxuLy8gTG9nIGxldmVsc1xuZXhwb3J0IGNvbnN0IExvZ0xldmVsID0ge1xuXHRUUkFDRTogMSxcblx0REVCVUc6IDIsXG5cdElORk86IDMsXG5cdFdBUk5JTkc6IDQsXG5cdEVSUk9SOiA1LFxufTtcbiIsICIvKlxuIF8gICAgICAgX18gICAgICBfIF9fXG58IHwgICAgIC8gL19fXyBfKF8pIC9fX19fXG58IHwgL3wgLyAvIF9fIGAvIC8gLyBfX18vXG58IHwvIHwvIC8gL18vIC8gLyAoX18gIClcbnxfXy98X18vXFxfXyxfL18vXy9fX19fL1xuVGhlIGVsZWN0cm9uIGFsdGVybmF0aXZlIGZvciBHb1xuKGMpIExlYSBBbnRob255IDIwMTktcHJlc2VudFxuKi9cbi8qIGpzaGludCBlc3ZlcnNpb246IDYgKi9cblxuLy8gRGVmaW5lcyBhIHNpbmdsZSBsaXN0ZW5lciB3aXRoIGEgbWF4aW11bSBudW1iZXIgb2YgdGltZXMgdG8gY2FsbGJhY2tcblxuLyoqXG4gKiBUaGUgTGlzdGVuZXIgY2xhc3MgZGVmaW5lcyBhIGxpc3RlbmVyISA6LSlcbiAqXG4gKiBAY2xhc3MgTGlzdGVuZXJcbiAqL1xuY2xhc3MgTGlzdGVuZXIge1xuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYW4gaW5zdGFuY2Ugb2YgTGlzdGVuZXIuXG4gICAgICogQHBhcmFtIHtmdW5jdGlvbn0gY2FsbGJhY2tcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gbWF4Q2FsbGJhY2tzXG4gICAgICogQG1lbWJlcm9mIExpc3RlbmVyXG4gICAgICovXG4gICAgY29uc3RydWN0b3IoY2FsbGJhY2ssIG1heENhbGxiYWNrcykge1xuICAgICAgICAvLyBEZWZhdWx0IG9mIC0xIG1lYW5zIGluZmluaXRlXG4gICAgICAgIG1heENhbGxiYWNrcyA9IG1heENhbGxiYWNrcyB8fCAtMTtcbiAgICAgICAgLy8gQ2FsbGJhY2sgaW52b2tlcyB0aGUgY2FsbGJhY2sgd2l0aCB0aGUgZ2l2ZW4gZGF0YVxuICAgICAgICAvLyBSZXR1cm5zIHRydWUgaWYgdGhpcyBsaXN0ZW5lciBzaG91bGQgYmUgZGVzdHJveWVkXG4gICAgICAgIHRoaXMuQ2FsbGJhY2sgPSAoZGF0YSkgPT4ge1xuICAgICAgICAgICAgY2FsbGJhY2suYXBwbHkobnVsbCwgZGF0YSk7XG4gICAgICAgICAgICAvLyBJZiBtYXhDYWxsYmFja3MgaXMgaW5maW5pdGUsIHJldHVybiBmYWxzZSAoZG8gbm90IGRlc3Ryb3kpXG4gICAgICAgICAgICBpZiAobWF4Q2FsbGJhY2tzID09PSAtMSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIERlY3JlbWVudCBtYXhDYWxsYmFja3MuIFJldHVybiB0cnVlIGlmIG5vdyAwLCBvdGhlcndpc2UgZmFsc2VcbiAgICAgICAgICAgIG1heENhbGxiYWNrcyAtPSAxO1xuICAgICAgICAgICAgcmV0dXJuIG1heENhbGxiYWNrcyA9PT0gMDtcbiAgICAgICAgfTtcbiAgICB9XG59XG5cbmV4cG9ydCBjb25zdCBldmVudExpc3RlbmVycyA9IHt9O1xuXG4vKipcbiAqIFJlZ2lzdGVycyBhbiBldmVudCBsaXN0ZW5lciB0aGF0IHdpbGwgYmUgaW52b2tlZCBgbWF4Q2FsbGJhY2tzYCB0aW1lcyBiZWZvcmUgYmVpbmcgZGVzdHJveWVkXG4gKlxuICogQGV4cG9ydFxuICogQHBhcmFtIHtzdHJpbmd9IGV2ZW50TmFtZVxuICogQHBhcmFtIHtmdW5jdGlvbn0gY2FsbGJhY2tcbiAqIEBwYXJhbSB7bnVtYmVyfSBtYXhDYWxsYmFja3NcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIEV2ZW50c09uTXVsdGlwbGUoZXZlbnROYW1lLCBjYWxsYmFjaywgbWF4Q2FsbGJhY2tzKSB7XG4gICAgZXZlbnRMaXN0ZW5lcnNbZXZlbnROYW1lXSA9IGV2ZW50TGlzdGVuZXJzW2V2ZW50TmFtZV0gfHwgW107XG4gICAgY29uc3QgdGhpc0xpc3RlbmVyID0gbmV3IExpc3RlbmVyKGNhbGxiYWNrLCBtYXhDYWxsYmFja3MpO1xuICAgIGV2ZW50TGlzdGVuZXJzW2V2ZW50TmFtZV0ucHVzaCh0aGlzTGlzdGVuZXIpO1xufVxuXG4vKipcbiAqIFJlZ2lzdGVycyBhbiBldmVudCBsaXN0ZW5lciB0aGF0IHdpbGwgYmUgaW52b2tlZCBldmVyeSB0aW1lIHRoZSBldmVudCBpcyBlbWl0dGVkXG4gKlxuICogQGV4cG9ydFxuICogQHBhcmFtIHtzdHJpbmd9IGV2ZW50TmFtZVxuICogQHBhcmFtIHtmdW5jdGlvbn0gY2FsbGJhY2tcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIEV2ZW50c09uKGV2ZW50TmFtZSwgY2FsbGJhY2spIHtcbiAgICBFdmVudHNPbk11bHRpcGxlKGV2ZW50TmFtZSwgY2FsbGJhY2ssIC0xKTtcbn1cblxuLyoqXG4gKiBSZWdpc3RlcnMgYW4gZXZlbnQgbGlzdGVuZXIgdGhhdCB3aWxsIGJlIGludm9rZWQgb25jZSB0aGVuIGRlc3Ryb3llZFxuICpcbiAqIEBleHBvcnRcbiAqIEBwYXJhbSB7c3RyaW5nfSBldmVudE5hbWVcbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGNhbGxiYWNrXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBFdmVudHNPbmNlKGV2ZW50TmFtZSwgY2FsbGJhY2spIHtcbiAgICBFdmVudHNPbk11bHRpcGxlKGV2ZW50TmFtZSwgY2FsbGJhY2ssIDEpO1xufVxuXG5mdW5jdGlvbiBub3RpZnlMaXN0ZW5lcnMoZXZlbnREYXRhKSB7XG5cbiAgICAvLyBHZXQgdGhlIGV2ZW50IG5hbWVcbiAgICBsZXQgZXZlbnROYW1lID0gZXZlbnREYXRhLm5hbWU7XG5cbiAgICAvLyBDaGVjayBpZiB3ZSBoYXZlIGFueSBsaXN0ZW5lcnMgZm9yIHRoaXMgZXZlbnRcbiAgICBpZiAoZXZlbnRMaXN0ZW5lcnNbZXZlbnROYW1lXSkge1xuXG4gICAgICAgIC8vIEtlZXAgYSBsaXN0IG9mIGxpc3RlbmVyIGluZGV4ZXMgdG8gZGVzdHJveVxuICAgICAgICBjb25zdCBuZXdFdmVudExpc3RlbmVyTGlzdCA9IGV2ZW50TGlzdGVuZXJzW2V2ZW50TmFtZV0uc2xpY2UoKTtcblxuICAgICAgICAvLyBJdGVyYXRlIGxpc3RlbmVyc1xuICAgICAgICBmb3IgKGxldCBjb3VudCA9IDA7IGNvdW50IDwgZXZlbnRMaXN0ZW5lcnNbZXZlbnROYW1lXS5sZW5ndGg7IGNvdW50ICs9IDEpIHtcblxuICAgICAgICAgICAgLy8gR2V0IG5leHQgbGlzdGVuZXJcbiAgICAgICAgICAgIGNvbnN0IGxpc3RlbmVyID0gZXZlbnRMaXN0ZW5lcnNbZXZlbnROYW1lXVtjb3VudF07XG5cbiAgICAgICAgICAgIGxldCBkYXRhID0gZXZlbnREYXRhLmRhdGE7XG5cbiAgICAgICAgICAgIC8vIERvIHRoZSBjYWxsYmFja1xuICAgICAgICAgICAgY29uc3QgZGVzdHJveSA9IGxpc3RlbmVyLkNhbGxiYWNrKGRhdGEpO1xuICAgICAgICAgICAgaWYgKGRlc3Ryb3kpIHtcbiAgICAgICAgICAgICAgICAvLyBpZiB0aGUgbGlzdGVuZXIgaW5kaWNhdGVkIHRvIGRlc3Ryb3kgaXRzZWxmLCBhZGQgaXQgdG8gdGhlIGRlc3Ryb3kgbGlzdFxuICAgICAgICAgICAgICAgIG5ld0V2ZW50TGlzdGVuZXJMaXN0LnNwbGljZShjb3VudCwgMSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyBVcGRhdGUgY2FsbGJhY2tzIHdpdGggbmV3IGxpc3Qgb2YgbGlzdGVuZXJzXG4gICAgICAgIGV2ZW50TGlzdGVuZXJzW2V2ZW50TmFtZV0gPSBuZXdFdmVudExpc3RlbmVyTGlzdDtcbiAgICB9XG59XG5cbi8qKlxuICogTm90aWZ5IGluZm9ybXMgZnJvbnRlbmQgbGlzdGVuZXJzIHRoYXQgYW4gZXZlbnQgd2FzIGVtaXR0ZWQgd2l0aCB0aGUgZ2l2ZW4gZGF0YVxuICpcbiAqIEBleHBvcnRcbiAqIEBwYXJhbSB7c3RyaW5nfSBub3RpZnlNZXNzYWdlIC0gZW5jb2RlZCBub3RpZmljYXRpb24gbWVzc2FnZVxuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBFdmVudHNOb3RpZnkobm90aWZ5TWVzc2FnZSkge1xuICAgIC8vIFBhcnNlIHRoZSBtZXNzYWdlXG4gICAgbGV0IG1lc3NhZ2U7XG4gICAgdHJ5IHtcbiAgICAgICAgbWVzc2FnZSA9IEpTT04ucGFyc2Uobm90aWZ5TWVzc2FnZSk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBjb25zdCBlcnJvciA9ICdJbnZhbGlkIEpTT04gcGFzc2VkIHRvIE5vdGlmeTogJyArIG5vdGlmeU1lc3NhZ2U7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihlcnJvcik7XG4gICAgfVxuICAgIG5vdGlmeUxpc3RlbmVycyhtZXNzYWdlKTtcbn1cblxuLyoqXG4gKiBFbWl0IGFuIGV2ZW50IHdpdGggdGhlIGdpdmVuIG5hbWUgYW5kIGRhdGFcbiAqXG4gKiBAZXhwb3J0XG4gKiBAcGFyYW0ge3N0cmluZ30gZXZlbnROYW1lXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBFdmVudHNFbWl0KGV2ZW50TmFtZSkge1xuXG4gICAgY29uc3QgcGF5bG9hZCA9IHtcbiAgICAgICAgbmFtZTogZXZlbnROYW1lLFxuICAgICAgICBkYXRhOiBbXS5zbGljZS5hcHBseShhcmd1bWVudHMpLnNsaWNlKDEpLFxuICAgIH07XG5cbiAgICAvLyBOb3RpZnkgSlMgbGlzdGVuZXJzXG4gICAgbm90aWZ5TGlzdGVuZXJzKHBheWxvYWQpO1xuXG4gICAgLy8gTm90aWZ5IEdvIGxpc3RlbmVyc1xuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnRUUnICsgSlNPTi5zdHJpbmdpZnkocGF5bG9hZCkpO1xufVxuXG5mdW5jdGlvbiByZW1vdmVMaXN0ZW5lcihldmVudE5hbWUpIHtcbiAgICAvLyBSZW1vdmUgbG9jYWwgbGlzdGVuZXJzXG4gICAgZGVsZXRlIGV2ZW50TGlzdGVuZXJzW2V2ZW50TmFtZV07XG5cbiAgICAvLyBOb3RpZnkgR28gbGlzdGVuZXJzXG4gICAgd2luZG93LldhaWxzSW52b2tlKCdFWCcgKyBldmVudE5hbWUpO1xufVxuXG4vKipcbiAqIE9mZiB1bnJlZ2lzdGVycyBhIGxpc3RlbmVyIHByZXZpb3VzbHkgcmVnaXN0ZXJlZCB3aXRoIE9uLFxuICogb3B0aW9uYWxseSBtdWx0aXBsZSBsaXN0ZW5lcmVzIGNhbiBiZSB1bnJlZ2lzdGVyZWQgdmlhIGBhZGRpdGlvbmFsRXZlbnROYW1lc2BcbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gZXZlbnROYW1lXG4gKiBAcGFyYW0gIHsuLi5zdHJpbmd9IGFkZGl0aW9uYWxFdmVudE5hbWVzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBFdmVudHNPZmYoZXZlbnROYW1lLCAuLi5hZGRpdGlvbmFsRXZlbnROYW1lcykge1xuICAgIHJlbW92ZUxpc3RlbmVyKGV2ZW50TmFtZSlcblxuICAgIGlmIChhZGRpdGlvbmFsRXZlbnROYW1lcy5sZW5ndGggPiAwKSB7XG4gICAgICAgIGFkZGl0aW9uYWxFdmVudE5hbWVzLmZvckVhY2goZXZlbnROYW1lID0+IHtcbiAgICAgICAgICAgIHJlbW92ZUxpc3RlbmVyKGV2ZW50TmFtZSlcbiAgICAgICAgfSlcbiAgICB9XG59IiwgIi8qXG4gXyAgICAgICBfXyAgICAgIF8gX19cbnwgfCAgICAgLyAvX19fIF8oXykgL19fX19cbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cbnwgfC8gfC8gLyAvXy8gLyAvIChfXyAgKVxufF9fL3xfXy9cXF9fLF8vXy9fL19fX18vXG5UaGUgZWxlY3Ryb24gYWx0ZXJuYXRpdmUgZm9yIEdvXG4oYykgTGVhIEFudGhvbnkgMjAxOS1wcmVzZW50XG4qL1xuLyoganNoaW50IGVzdmVyc2lvbjogNiAqL1xuXG5leHBvcnQgY29uc3QgY2FsbGJhY2tzID0ge307XG5cbi8qKlxuICogUmV0dXJucyBhIG51bWJlciBmcm9tIHRoZSBuYXRpdmUgYnJvd3NlciByYW5kb20gZnVuY3Rpb25cbiAqXG4gKiBAcmV0dXJucyBudW1iZXJcbiAqL1xuZnVuY3Rpb24gY3J5cHRvUmFuZG9tKCkge1xuXHR2YXIgYXJyYXkgPSBuZXcgVWludDMyQXJyYXkoMSk7XG5cdHJldHVybiB3aW5kb3cuY3J5cHRvLmdldFJhbmRvbVZhbHVlcyhhcnJheSlbMF07XG59XG5cbi8qKlxuICogUmV0dXJucyBhIG51bWJlciB1c2luZyBkYSBvbGQtc2tvb2wgTWF0aC5SYW5kb21cbiAqIEkgbGlrZXMgdG8gY2FsbCBpdCBMT0xSYW5kb21cbiAqXG4gKiBAcmV0dXJucyBudW1iZXJcbiAqL1xuZnVuY3Rpb24gYmFzaWNSYW5kb20oKSB7XG5cdHJldHVybiBNYXRoLnJhbmRvbSgpICogOTAwNzE5OTI1NDc0MDk5MTtcbn1cblxuLy8gUGljayBhIHJhbmRvbSBudW1iZXIgZnVuY3Rpb24gYmFzZWQgb24gYnJvd3NlciBjYXBhYmlsaXR5XG52YXIgcmFuZG9tRnVuYztcbmlmICh3aW5kb3cuY3J5cHRvKSB7XG5cdHJhbmRvbUZ1bmMgPSBjcnlwdG9SYW5kb207XG59IGVsc2Uge1xuXHRyYW5kb21GdW5jID0gYmFzaWNSYW5kb207XG59XG5cblxuLyoqXG4gKiBDYWxsIHNlbmRzIGEgbWVzc2FnZSB0byB0aGUgYmFja2VuZCB0byBjYWxsIHRoZSBiaW5kaW5nIHdpdGggdGhlXG4gKiBnaXZlbiBkYXRhLiBBIHByb21pc2UgaXMgcmV0dXJuZWQgYW5kIHdpbGwgYmUgY29tcGxldGVkIHdoZW4gdGhlXG4gKiBiYWNrZW5kIHJlc3BvbmRzLiBUaGlzIHdpbGwgYmUgcmVzb2x2ZWQgd2hlbiB0aGUgY2FsbCB3YXMgc3VjY2Vzc2Z1bFxuICogb3IgcmVqZWN0ZWQgaWYgYW4gZXJyb3IgaXMgcGFzc2VkIGJhY2suXG4gKiBUaGVyZSBpcyBhIHRpbWVvdXQgbWVjaGFuaXNtLiBJZiB0aGUgY2FsbCBkb2Vzbid0IHJlc3BvbmQgaW4gdGhlIGdpdmVuXG4gKiB0aW1lIChpbiBtaWxsaXNlY29uZHMpIHRoZW4gdGhlIHByb21pc2UgaXMgcmVqZWN0ZWQuXG4gKlxuICogQGV4cG9ydFxuICogQHBhcmFtIHtzdHJpbmd9IG5hbWVcbiAqIEBwYXJhbSB7YW55PX0gYXJnc1xuICogQHBhcmFtIHtudW1iZXI9fSB0aW1lb3V0XG4gKiBAcmV0dXJuc1xuICovXG5leHBvcnQgZnVuY3Rpb24gQ2FsbChuYW1lLCBhcmdzLCB0aW1lb3V0KSB7XG5cblx0Ly8gVGltZW91dCBpbmZpbml0ZSBieSBkZWZhdWx0XG5cdGlmICh0aW1lb3V0ID09IG51bGwpIHtcblx0XHR0aW1lb3V0ID0gMDtcblx0fVxuXG5cdC8vIENyZWF0ZSBhIHByb21pc2Vcblx0cmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uIChyZXNvbHZlLCByZWplY3QpIHtcblxuXHRcdC8vIENyZWF0ZSBhIHVuaXF1ZSBjYWxsYmFja0lEXG5cdFx0dmFyIGNhbGxiYWNrSUQ7XG5cdFx0ZG8ge1xuXHRcdFx0Y2FsbGJhY2tJRCA9IG5hbWUgKyAnLScgKyByYW5kb21GdW5jKCk7XG5cdFx0fSB3aGlsZSAoY2FsbGJhY2tzW2NhbGxiYWNrSURdKTtcblxuXHRcdHZhciB0aW1lb3V0SGFuZGxlO1xuXHRcdC8vIFNldCB0aW1lb3V0XG5cdFx0aWYgKHRpbWVvdXQgPiAwKSB7XG5cdFx0XHR0aW1lb3V0SGFuZGxlID0gc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XG5cdFx0XHRcdHJlamVjdChFcnJvcignQ2FsbCB0byAnICsgbmFtZSArICcgdGltZWQgb3V0LiBSZXF1ZXN0IElEOiAnICsgY2FsbGJhY2tJRCkpO1xuXHRcdFx0fSwgdGltZW91dCk7XG5cdFx0fVxuXG5cdFx0Ly8gU3RvcmUgY2FsbGJhY2tcblx0XHRjYWxsYmFja3NbY2FsbGJhY2tJRF0gPSB7XG5cdFx0XHR0aW1lb3V0SGFuZGxlOiB0aW1lb3V0SGFuZGxlLFxuXHRcdFx0cmVqZWN0OiByZWplY3QsXG5cdFx0XHRyZXNvbHZlOiByZXNvbHZlXG5cdFx0fTtcblxuXHRcdHRyeSB7XG5cdFx0XHRjb25zdCBwYXlsb2FkID0ge1xuXHRcdFx0XHRuYW1lLFxuXHRcdFx0XHRhcmdzLFxuXHRcdFx0XHRjYWxsYmFja0lELFxuXHRcdFx0fTtcblxuICAgICAgICAgICAgLy8gTWFrZSB0aGUgY2FsbFxuICAgICAgICAgICAgd2luZG93LldhaWxzSW52b2tlKCdDJyArIEpTT04uc3RyaW5naWZ5KHBheWxvYWQpKTtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lXG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKGUpO1xuICAgICAgICB9XG4gICAgfSk7XG59XG5cbndpbmRvdy5PYmZ1c2NhdGVkQ2FsbCA9IChpZCwgYXJncywgdGltZW91dCkgPT4ge1xuXG4gICAgLy8gVGltZW91dCBpbmZpbml0ZSBieSBkZWZhdWx0XG4gICAgaWYgKHRpbWVvdXQgPT0gbnVsbCkge1xuICAgICAgICB0aW1lb3V0ID0gMDtcbiAgICB9XG5cbiAgICAvLyBDcmVhdGUgYSBwcm9taXNlXG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uIChyZXNvbHZlLCByZWplY3QpIHtcblxuICAgICAgICAvLyBDcmVhdGUgYSB1bmlxdWUgY2FsbGJhY2tJRFxuICAgICAgICB2YXIgY2FsbGJhY2tJRDtcbiAgICAgICAgZG8ge1xuICAgICAgICAgICAgY2FsbGJhY2tJRCA9IGlkICsgJy0nICsgcmFuZG9tRnVuYygpO1xuICAgICAgICB9IHdoaWxlIChjYWxsYmFja3NbY2FsbGJhY2tJRF0pO1xuXG4gICAgICAgIHZhciB0aW1lb3V0SGFuZGxlO1xuICAgICAgICAvLyBTZXQgdGltZW91dFxuICAgICAgICBpZiAodGltZW91dCA+IDApIHtcbiAgICAgICAgICAgIHRpbWVvdXRIYW5kbGUgPSBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICByZWplY3QoRXJyb3IoJ0NhbGwgdG8gbWV0aG9kICcgKyBpZCArICcgdGltZWQgb3V0LiBSZXF1ZXN0IElEOiAnICsgY2FsbGJhY2tJRCkpO1xuICAgICAgICAgICAgfSwgdGltZW91dCk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBTdG9yZSBjYWxsYmFja1xuICAgICAgICBjYWxsYmFja3NbY2FsbGJhY2tJRF0gPSB7XG4gICAgICAgICAgICB0aW1lb3V0SGFuZGxlOiB0aW1lb3V0SGFuZGxlLFxuICAgICAgICAgICAgcmVqZWN0OiByZWplY3QsXG4gICAgICAgICAgICByZXNvbHZlOiByZXNvbHZlXG4gICAgICAgIH07XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IHBheWxvYWQgPSB7XG5cdFx0XHRcdGlkLFxuXHRcdFx0XHRhcmdzLFxuXHRcdFx0XHRjYWxsYmFja0lELFxuXHRcdFx0fTtcblxuICAgICAgICAgICAgLy8gTWFrZSB0aGUgY2FsbFxuICAgICAgICAgICAgd2luZG93LldhaWxzSW52b2tlKCdjJyArIEpTT04uc3RyaW5naWZ5KHBheWxvYWQpKTtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lXG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKGUpO1xuICAgICAgICB9XG4gICAgfSk7XG59O1xuXG5cbi8qKlxuICogQ2FsbGVkIGJ5IHRoZSBiYWNrZW5kIHRvIHJldHVybiBkYXRhIHRvIGEgcHJldmlvdXNseSBjYWxsZWRcbiAqIGJpbmRpbmcgaW52b2NhdGlvblxuICpcbiAqIEBleHBvcnRcbiAqIEBwYXJhbSB7c3RyaW5nfSBpbmNvbWluZ01lc3NhZ2VcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIENhbGxiYWNrKGluY29taW5nTWVzc2FnZSkge1xuXHQvLyBQYXJzZSB0aGUgbWVzc2FnZVxuXHRsZXQgbWVzc2FnZTtcblx0dHJ5IHtcblx0XHRtZXNzYWdlID0gSlNPTi5wYXJzZShpbmNvbWluZ01lc3NhZ2UpO1xuXHR9IGNhdGNoIChlKSB7XG5cdFx0Y29uc3QgZXJyb3IgPSBgSW52YWxpZCBKU09OIHBhc3NlZCB0byBjYWxsYmFjazogJHtlLm1lc3NhZ2V9LiBNZXNzYWdlOiAke2luY29taW5nTWVzc2FnZX1gO1xuXHRcdHJ1bnRpbWUuTG9nRGVidWcoZXJyb3IpO1xuXHRcdHRocm93IG5ldyBFcnJvcihlcnJvcik7XG5cdH1cblx0bGV0IGNhbGxiYWNrSUQgPSBtZXNzYWdlLmNhbGxiYWNraWQ7XG5cdGxldCBjYWxsYmFja0RhdGEgPSBjYWxsYmFja3NbY2FsbGJhY2tJRF07XG5cdGlmICghY2FsbGJhY2tEYXRhKSB7XG5cdFx0Y29uc3QgZXJyb3IgPSBgQ2FsbGJhY2sgJyR7Y2FsbGJhY2tJRH0nIG5vdCByZWdpc3RlcmVkISEhYDtcblx0XHRjb25zb2xlLmVycm9yKGVycm9yKTsgLy8gZXNsaW50LWRpc2FibGUtbGluZVxuXHRcdHRocm93IG5ldyBFcnJvcihlcnJvcik7XG5cdH1cblx0Y2xlYXJUaW1lb3V0KGNhbGxiYWNrRGF0YS50aW1lb3V0SGFuZGxlKTtcblxuXHRkZWxldGUgY2FsbGJhY2tzW2NhbGxiYWNrSURdO1xuXG5cdGlmIChtZXNzYWdlLmVycm9yKSB7XG5cdFx0Y2FsbGJhY2tEYXRhLnJlamVjdChtZXNzYWdlLmVycm9yKTtcblx0fSBlbHNlIHtcblx0XHRjYWxsYmFja0RhdGEucmVzb2x2ZShtZXNzYWdlLnJlc3VsdCk7XG5cdH1cbn1cbiIsICIvKlxuIF8gICAgICAgX18gICAgICBfIF9fICAgIFxufCB8ICAgICAvIC9fX18gXyhfKSAvX19fX1xufCB8IC98IC8gLyBfXyBgLyAvIC8gX19fL1xufCB8LyB8LyAvIC9fLyAvIC8gKF9fICApIFxufF9fL3xfXy9cXF9fLF8vXy9fL19fX18vICBcblRoZSBlbGVjdHJvbiBhbHRlcm5hdGl2ZSBmb3IgR29cbihjKSBMZWEgQW50aG9ueSAyMDE5LXByZXNlbnRcbiovXG4vKiBqc2hpbnQgZXN2ZXJzaW9uOiA2ICovXG5cbmltcG9ydCB7Q2FsbH0gZnJvbSAnLi9jYWxscyc7XG5cbi8vIFRoaXMgaXMgd2hlcmUgd2UgYmluZCBnbyBtZXRob2Qgd3JhcHBlcnNcbndpbmRvdy5nbyA9IHt9O1xuXG5leHBvcnQgZnVuY3Rpb24gU2V0QmluZGluZ3MoYmluZGluZ3NNYXApIHtcblx0dHJ5IHtcblx0XHRiaW5kaW5nc01hcCA9IEpTT04ucGFyc2UoYmluZGluZ3NNYXApO1xuXHR9IGNhdGNoIChlKSB7XG5cdFx0Y29uc29sZS5lcnJvcihlKTtcblx0fVxuXG5cdC8vIEluaXRpYWxpc2UgdGhlIGJpbmRpbmdzIG1hcFxuXHR3aW5kb3cuZ28gPSB3aW5kb3cuZ28gfHwge307XG5cblx0Ly8gSXRlcmF0ZSBwYWNrYWdlIG5hbWVzXG5cdE9iamVjdC5rZXlzKGJpbmRpbmdzTWFwKS5mb3JFYWNoKChwYWNrYWdlTmFtZSkgPT4ge1xuXG5cdFx0Ly8gQ3JlYXRlIGlubmVyIG1hcCBpZiBpdCBkb2Vzbid0IGV4aXN0XG5cdFx0d2luZG93LmdvW3BhY2thZ2VOYW1lXSA9IHdpbmRvdy5nb1twYWNrYWdlTmFtZV0gfHwge307XG5cblx0XHQvLyBJdGVyYXRlIHN0cnVjdCBuYW1lc1xuXHRcdE9iamVjdC5rZXlzKGJpbmRpbmdzTWFwW3BhY2thZ2VOYW1lXSkuZm9yRWFjaCgoc3RydWN0TmFtZSkgPT4ge1xuXG5cdFx0XHQvLyBDcmVhdGUgaW5uZXIgbWFwIGlmIGl0IGRvZXNuJ3QgZXhpc3Rcblx0XHRcdHdpbmRvdy5nb1twYWNrYWdlTmFtZV1bc3RydWN0TmFtZV0gPSB3aW5kb3cuZ29bcGFja2FnZU5hbWVdW3N0cnVjdE5hbWVdIHx8IHt9O1xuXG5cdFx0XHRPYmplY3Qua2V5cyhiaW5kaW5nc01hcFtwYWNrYWdlTmFtZV1bc3RydWN0TmFtZV0pLmZvckVhY2goKG1ldGhvZE5hbWUpID0+IHtcblxuXHRcdFx0XHR3aW5kb3cuZ29bcGFja2FnZU5hbWVdW3N0cnVjdE5hbWVdW21ldGhvZE5hbWVdID0gZnVuY3Rpb24gKCkge1xuXG5cdFx0XHRcdFx0Ly8gTm8gdGltZW91dCBieSBkZWZhdWx0XG5cdFx0XHRcdFx0bGV0IHRpbWVvdXQgPSAwO1xuXG5cdFx0XHRcdFx0Ly8gQWN0dWFsIGZ1bmN0aW9uXG5cdFx0XHRcdFx0ZnVuY3Rpb24gZHluYW1pYygpIHtcblx0XHRcdFx0XHRcdGNvbnN0IGFyZ3MgPSBbXS5zbGljZS5jYWxsKGFyZ3VtZW50cyk7XG5cdFx0XHRcdFx0XHRyZXR1cm4gQ2FsbChbcGFja2FnZU5hbWUsIHN0cnVjdE5hbWUsIG1ldGhvZE5hbWVdLmpvaW4oJy4nKSwgYXJncywgdGltZW91dCk7XG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0Ly8gQWxsb3cgc2V0dGluZyB0aW1lb3V0IHRvIGZ1bmN0aW9uXG5cdFx0XHRcdFx0ZHluYW1pYy5zZXRUaW1lb3V0ID0gZnVuY3Rpb24gKG5ld1RpbWVvdXQpIHtcblx0XHRcdFx0XHRcdHRpbWVvdXQgPSBuZXdUaW1lb3V0O1xuXHRcdFx0XHRcdH07XG5cblx0XHRcdFx0XHQvLyBBbGxvdyBnZXR0aW5nIHRpbWVvdXQgdG8gZnVuY3Rpb25cblx0XHRcdFx0XHRkeW5hbWljLmdldFRpbWVvdXQgPSBmdW5jdGlvbiAoKSB7XG5cdFx0XHRcdFx0XHRyZXR1cm4gdGltZW91dDtcblx0XHRcdFx0XHR9O1xuXG5cdFx0XHRcdFx0cmV0dXJuIGR5bmFtaWM7XG5cdFx0XHRcdH0oKTtcblx0XHRcdH0pO1xuXHRcdH0pO1xuXHR9KTtcbn1cbiIsICIvKlxuIF9cdCAgIF9fXHQgIF8gX19cbnwgfFx0IC8gL19fXyBfKF8pIC9fX19fXG58IHwgL3wgLyAvIF9fIGAvIC8gLyBfX18vXG58IHwvIHwvIC8gL18vIC8gLyAoX18gIClcbnxfXy98X18vXFxfXyxfL18vXy9fX19fL1xuVGhlIGVsZWN0cm9uIGFsdGVybmF0aXZlIGZvciBHb1xuKGMpIExlYSBBbnRob255IDIwMTktcHJlc2VudFxuKi9cblxuLyoganNoaW50IGVzdmVyc2lvbjogOSAqL1xuXG5cbmltcG9ydCB7Q2FsbH0gZnJvbSBcIi4vY2FsbHNcIjtcblxuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd1JlbG9hZCgpIHtcbiAgICB3aW5kb3cubG9jYXRpb24ucmVsb2FkKCk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBXaW5kb3dSZWxvYWRBcHAoKSB7XG4gICAgd2luZG93LldhaWxzSW52b2tlKCdXUicpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gV2luZG93U2V0U3lzdGVtRGVmYXVsdFRoZW1lKCkge1xuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnV0FTRFQnKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd1NldExpZ2h0VGhlbWUoKSB7XG4gICAgd2luZG93LldhaWxzSW52b2tlKCdXQUxUJyk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBXaW5kb3dTZXREYXJrVGhlbWUoKSB7XG4gICAgd2luZG93LldhaWxzSW52b2tlKCdXQURUJyk7XG59XG5cbi8qKlxuICogUGxhY2UgdGhlIHdpbmRvdyBpbiB0aGUgY2VudGVyIG9mIHRoZSBzY3JlZW5cbiAqXG4gKiBAZXhwb3J0XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBXaW5kb3dDZW50ZXIoKSB7XG4gICAgd2luZG93LldhaWxzSW52b2tlKCdXYycpO1xufVxuXG4vKipcbiAqIFNldHMgdGhlIHdpbmRvdyB0aXRsZVxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSB0aXRsZVxuICogQGV4cG9ydFxuICovXG5leHBvcnQgZnVuY3Rpb24gV2luZG93U2V0VGl0bGUodGl0bGUpIHtcbiAgICB3aW5kb3cuV2FpbHNJbnZva2UoJ1dUJyArIHRpdGxlKTtcbn1cblxuLyoqXG4gKiBNYWtlcyB0aGUgd2luZG93IGdvIGZ1bGxzY3JlZW5cbiAqXG4gKiBAZXhwb3J0XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBXaW5kb3dGdWxsc2NyZWVuKCkge1xuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnV0YnKTtcbn1cblxuLyoqXG4gKiBSZXZlcnRzIHRoZSB3aW5kb3cgZnJvbSBmdWxsc2NyZWVuXG4gKlxuICogQGV4cG9ydFxuICovXG5leHBvcnQgZnVuY3Rpb24gV2luZG93VW5mdWxsc2NyZWVuKCkge1xuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnV2YnKTtcbn1cblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBzdGF0ZSBvZiB0aGUgd2luZG93LCBpLmUuIHdoZXRoZXIgdGhlIHdpbmRvdyBpcyBpbiBmdWxsIHNjcmVlbiBtb2RlIG9yIG5vdC5cbiAqXG4gKiBAZXhwb3J0XG4gKiBAcmV0dXJuIHtQcm9taXNlPGJvb2xlYW4+fSBUaGUgc3RhdGUgb2YgdGhlIHdpbmRvd1xuICovXG5leHBvcnQgZnVuY3Rpb24gV2luZG93SXNGdWxsc2NyZWVuKCkge1xuICAgIHJldHVybiBDYWxsKFwiOndhaWxzOldpbmRvd0lzRnVsbHNjcmVlblwiKTtcbn1cblxuLyoqXG4gKiBTZXQgdGhlIFNpemUgb2YgdGhlIHdpbmRvd1xuICpcbiAqIEBleHBvcnRcbiAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aFxuICogQHBhcmFtIHtudW1iZXJ9IGhlaWdodFxuICovXG5leHBvcnQgZnVuY3Rpb24gV2luZG93U2V0U2l6ZSh3aWR0aCwgaGVpZ2h0KSB7XG4gICAgd2luZG93LldhaWxzSW52b2tlKCdXczonICsgd2lkdGggKyAnOicgKyBoZWlnaHQpO1xufVxuXG4vKipcbiAqIEdldCB0aGUgU2l6ZSBvZiB0aGUgd2luZG93XG4gKlxuICogQGV4cG9ydFxuICogQHJldHVybiB7UHJvbWlzZTx7dzogbnVtYmVyLCBoOiBudW1iZXJ9Pn0gVGhlIHNpemUgb2YgdGhlIHdpbmRvd1xuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBXaW5kb3dHZXRTaXplKCkge1xuICAgIHJldHVybiBDYWxsKFwiOndhaWxzOldpbmRvd0dldFNpemVcIik7XG59XG5cbi8qKlxuICogU2V0IHRoZSBtYXhpbXVtIHNpemUgb2YgdGhlIHdpbmRvd1xuICpcbiAqIEBleHBvcnRcbiAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aFxuICogQHBhcmFtIHtudW1iZXJ9IGhlaWdodFxuICovXG5leHBvcnQgZnVuY3Rpb24gV2luZG93U2V0TWF4U2l6ZSh3aWR0aCwgaGVpZ2h0KSB7XG4gICAgd2luZG93LldhaWxzSW52b2tlKCdXWjonICsgd2lkdGggKyAnOicgKyBoZWlnaHQpO1xufVxuXG4vKipcbiAqIFNldCB0aGUgbWluaW11bSBzaXplIG9mIHRoZSB3aW5kb3dcbiAqXG4gKiBAZXhwb3J0XG4gKiBAcGFyYW0ge251bWJlcn0gd2lkdGhcbiAqIEBwYXJhbSB7bnVtYmVyfSBoZWlnaHRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd1NldE1pblNpemUod2lkdGgsIGhlaWdodCkge1xuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnV3o6JyArIHdpZHRoICsgJzonICsgaGVpZ2h0KTtcbn1cblxuXG5cbi8qKlxuICogU2V0IHRoZSB3aW5kb3cgQWx3YXlzT25Ub3Agb3Igbm90IG9uIHRvcFxuICpcbiAqIEBleHBvcnRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd1NldEFsd2F5c09uVG9wKGIpIHtcblxuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnV0FUUDonICsgKGIgPyAnMScgOiAnMCcpKTtcbn1cblxuXG5cblxuLyoqXG4gKiBTZXQgdGhlIFBvc2l0aW9uIG9mIHRoZSB3aW5kb3dcbiAqXG4gKiBAZXhwb3J0XG4gKiBAcGFyYW0ge251bWJlcn0geFxuICogQHBhcmFtIHtudW1iZXJ9IHlcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd1NldFBvc2l0aW9uKHgsIHkpIHtcbiAgICB3aW5kb3cuV2FpbHNJbnZva2UoJ1dwOicgKyB4ICsgJzonICsgeSk7XG59XG5cbi8qKlxuICogR2V0IHRoZSBQb3NpdGlvbiBvZiB0aGUgd2luZG93XG4gKlxuICogQGV4cG9ydFxuICogQHJldHVybiB7UHJvbWlzZTx7eDogbnVtYmVyLCB5OiBudW1iZXJ9Pn0gVGhlIHBvc2l0aW9uIG9mIHRoZSB3aW5kb3dcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd0dldFBvc2l0aW9uKCkge1xuICAgIHJldHVybiBDYWxsKFwiOndhaWxzOldpbmRvd0dldFBvc1wiKTtcbn1cblxuLyoqXG4gKiBIaWRlIHRoZSBXaW5kb3dcbiAqXG4gKiBAZXhwb3J0XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBXaW5kb3dIaWRlKCkge1xuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnV0gnKTtcbn1cblxuLyoqXG4gKiBTaG93IHRoZSBXaW5kb3dcbiAqXG4gKiBAZXhwb3J0XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBXaW5kb3dTaG93KCkge1xuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnV1MnKTtcbn1cblxuLyoqXG4gKiBNYXhpbWlzZSB0aGUgV2luZG93XG4gKlxuICogQGV4cG9ydFxuICovXG5leHBvcnQgZnVuY3Rpb24gV2luZG93TWF4aW1pc2UoKSB7XG4gICAgd2luZG93LldhaWxzSW52b2tlKCdXTScpO1xufVxuXG4vKipcbiAqIFRvZ2dsZSB0aGUgTWF4aW1pc2Ugb2YgdGhlIFdpbmRvd1xuICpcbiAqIEBleHBvcnRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd1RvZ2dsZU1heGltaXNlKCkge1xuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnV3QnKTtcbn1cblxuLyoqXG4gKiBVbm1heGltaXNlIHRoZSBXaW5kb3dcbiAqXG4gKiBAZXhwb3J0XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBXaW5kb3dVbm1heGltaXNlKCkge1xuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnV1UnKTtcbn1cblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBzdGF0ZSBvZiB0aGUgd2luZG93LCBpLmUuIHdoZXRoZXIgdGhlIHdpbmRvdyBpcyBtYXhpbWlzZWQgb3Igbm90LlxuICpcbiAqIEBleHBvcnRcbiAqIEByZXR1cm4ge1Byb21pc2U8Ym9vbGVhbj59IFRoZSBzdGF0ZSBvZiB0aGUgd2luZG93XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBXaW5kb3dJc01heGltaXNlZCgpIHtcbiAgICByZXR1cm4gQ2FsbChcIjp3YWlsczpXaW5kb3dJc01heGltaXNlZFwiKTtcbn1cblxuLyoqXG4gKiBNaW5pbWlzZSB0aGUgV2luZG93XG4gKlxuICogQGV4cG9ydFxuICovXG5leHBvcnQgZnVuY3Rpb24gV2luZG93TWluaW1pc2UoKSB7XG4gICAgd2luZG93LldhaWxzSW52b2tlKCdXbScpO1xufVxuXG4vKipcbiAqIFVubWluaW1pc2UgdGhlIFdpbmRvd1xuICpcbiAqIEBleHBvcnRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd1VubWluaW1pc2UoKSB7XG4gICAgd2luZG93LldhaWxzSW52b2tlKCdXdScpO1xufVxuXG4vKipcbiAqIFJldHVybnMgdGhlIHN0YXRlIG9mIHRoZSB3aW5kb3csIGkuZS4gd2hldGhlciB0aGUgd2luZG93IGlzIG1pbmltaXNlZCBvciBub3QuXG4gKlxuICogQGV4cG9ydFxuICogQHJldHVybiB7UHJvbWlzZTxib29sZWFuPn0gVGhlIHN0YXRlIG9mIHRoZSB3aW5kb3dcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd0lzTWluaW1pc2VkKCkge1xuICAgIHJldHVybiBDYWxsKFwiOndhaWxzOldpbmRvd0lzTWluaW1pc2VkXCIpO1xufVxuXG4vKipcbiAqIFJldHVybnMgdGhlIHN0YXRlIG9mIHRoZSB3aW5kb3csIGkuZS4gd2hldGhlciB0aGUgd2luZG93IGlzIG5vcm1hbCBvciBub3QuXG4gKlxuICogQGV4cG9ydFxuICogQHJldHVybiB7UHJvbWlzZTxib29sZWFuPn0gVGhlIHN0YXRlIG9mIHRoZSB3aW5kb3dcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFdpbmRvd0lzTm9ybWFsKCkge1xuICAgIHJldHVybiBDYWxsKFwiOndhaWxzOldpbmRvd0lzTm9ybWFsXCIpO1xufVxuXG4vKipcbiAqIFNldHMgdGhlIGJhY2tncm91bmQgY29sb3VyIG9mIHRoZSB3aW5kb3dcbiAqXG4gKiBAZXhwb3J0XG4gKiBAcGFyYW0ge251bWJlcn0gUiBSZWRcbiAqIEBwYXJhbSB7bnVtYmVyfSBHIEdyZWVuXG4gKiBAcGFyYW0ge251bWJlcn0gQiBCbHVlXG4gKiBAcGFyYW0ge251bWJlcn0gQSBBbHBoYVxuICovXG5leHBvcnQgZnVuY3Rpb24gV2luZG93U2V0QmFja2dyb3VuZENvbG91cihSLCBHLCBCLCBBKSB7XG4gICAgbGV0IHJnYmEgPSBKU09OLnN0cmluZ2lmeSh7cjogUiB8fCAwLCBnOiBHIHx8IDAsIGI6IEIgfHwgMCwgYTogQSB8fCAyNTV9KTtcbiAgICB3aW5kb3cuV2FpbHNJbnZva2UoJ1dyOicgKyByZ2JhKTtcbn1cblxuIiwgIi8qXG4gX1x0ICAgX19cdCAgXyBfX1xufCB8XHQgLyAvX19fIF8oXykgL19fX19cbnwgfCAvfCAvIC8gX18gYC8gLyAvIF9fXy9cbnwgfC8gfC8gLyAvXy8gLyAvIChfXyAgKVxufF9fL3xfXy9cXF9fLF8vXy9fL19fX18vXG5UaGUgZWxlY3Ryb24gYWx0ZXJuYXRpdmUgZm9yIEdvXG4oYykgTGVhIEFudGhvbnkgMjAxOS1wcmVzZW50XG4qL1xuXG4vKiBqc2hpbnQgZXN2ZXJzaW9uOiA5ICovXG5cblxuaW1wb3J0IHtDYWxsfSBmcm9tIFwiLi9jYWxsc1wiO1xuXG5cbi8qKlxuICogR2V0cyB0aGUgYWxsIHNjcmVlbnMuIENhbGwgdGhpcyBhbmV3IGVhY2ggdGltZSB5b3Ugd2FudCB0byByZWZyZXNoIGRhdGEgZnJvbSB0aGUgdW5kZXJseWluZyB3aW5kb3dpbmcgc3lzdGVtLlxuICogQGV4cG9ydFxuICogQHR5cGVkZWYge2ltcG9ydCgnLi4vd3JhcHBlci9ydW50aW1lJykuU2NyZWVufSBTY3JlZW5cbiAqIEByZXR1cm4ge1Byb21pc2U8e1NjcmVlbltdfT59IFRoZSBzY3JlZW5zXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBTY3JlZW5HZXRBbGwoKSB7XG4gICAgcmV0dXJuIENhbGwoXCI6d2FpbHM6U2NyZWVuR2V0QWxsXCIpO1xufVxuIiwgIi8qKlxuICogQGRlc2NyaXB0aW9uOiBVc2UgdGhlIHN5c3RlbSBkZWZhdWx0IGJyb3dzZXIgdG8gb3BlbiB0aGUgdXJsXG4gKiBAcGFyYW0ge3N0cmluZ30gdXJsIFxuICogQHJldHVybiB7dm9pZH1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIEJyb3dzZXJPcGVuVVJMKHVybCkge1xuICB3aW5kb3cuV2FpbHNJbnZva2UoJ0JPOicgKyB1cmwpO1xufSIsICIvKlxuIF9cdCAgIF9fXHQgIF8gX19cbnwgfFx0IC8gL19fXyBfKF8pIC9fX19fXG58IHwgL3wgLyAvIF9fIGAvIC8gLyBfX18vXG58IHwvIHwvIC8gL18vIC8gLyAoX18gIClcbnxfXy98X18vXFxfXyxfL18vXy9fX19fL1xuVGhlIGVsZWN0cm9uIGFsdGVybmF0aXZlIGZvciBHb1xuKGMpIExlYSBBbnRob255IDIwMTktcHJlc2VudFxuKi9cbi8qIGpzaGludCBlc3ZlcnNpb246IDkgKi9cbmltcG9ydCAqIGFzIExvZyBmcm9tICcuL2xvZyc7XG5pbXBvcnQge2V2ZW50TGlzdGVuZXJzLCBFdmVudHNFbWl0LCBFdmVudHNOb3RpZnksIEV2ZW50c09mZiwgRXZlbnRzT24sIEV2ZW50c09uY2UsIEV2ZW50c09uTXVsdGlwbGV9IGZyb20gJy4vZXZlbnRzJztcbmltcG9ydCB7Q2FsbCwgQ2FsbGJhY2ssIGNhbGxiYWNrc30gZnJvbSAnLi9jYWxscyc7XG5pbXBvcnQge1NldEJpbmRpbmdzfSBmcm9tIFwiLi9iaW5kaW5nc1wiO1xuaW1wb3J0ICogYXMgV2luZG93IGZyb20gXCIuL3dpbmRvd1wiO1xuaW1wb3J0ICogYXMgU2NyZWVuIGZyb20gXCIuL3NjcmVlblwiO1xuaW1wb3J0ICogYXMgQnJvd3NlciBmcm9tIFwiLi9icm93c2VyXCI7XG5cblxuZXhwb3J0IGZ1bmN0aW9uIFF1aXQoKSB7XG4gICAgd2luZG93LldhaWxzSW52b2tlKCdRJyk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBTaG93KCkge1xuICAgIHdpbmRvdy5XYWlsc0ludm9rZSgnUycpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gSGlkZSgpIHtcbiAgICB3aW5kb3cuV2FpbHNJbnZva2UoJ0gnKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIEVudmlyb25tZW50KCkge1xuICAgIHJldHVybiBDYWxsKFwiOndhaWxzOkVudmlyb25tZW50XCIpO1xufVxuXG4vLyBUaGUgSlMgcnVudGltZVxud2luZG93LnJ1bnRpbWUgPSB7XG4gICAgLi4uTG9nLFxuICAgIC4uLldpbmRvdyxcbiAgICAuLi5Ccm93c2VyLFxuICAgIC4uLlNjcmVlbixcbiAgICBFdmVudHNPbixcbiAgICBFdmVudHNPbmNlLFxuICAgIEV2ZW50c09uTXVsdGlwbGUsXG4gICAgRXZlbnRzRW1pdCxcbiAgICBFdmVudHNPZmYsXG4gICAgRW52aXJvbm1lbnQsXG4gICAgU2hvdyxcbiAgICBIaWRlLFxuICAgIFF1aXRcbn07XG5cbi8vIEludGVybmFsIHdhaWxzIGVuZHBvaW50c1xud2luZG93LndhaWxzID0ge1xuICAgIENhbGxiYWNrLFxuICAgIEV2ZW50c05vdGlmeSxcbiAgICBTZXRCaW5kaW5ncyxcbiAgICBldmVudExpc3RlbmVycyxcbiAgICBjYWxsYmFja3MsXG4gICAgZmxhZ3M6IHtcbiAgICAgICAgZGlzYWJsZVNjcm9sbGJhckRyYWc6IGZhbHNlLFxuICAgICAgICBkaXNhYmxlV2FpbHNEZWZhdWx0Q29udGV4dE1lbnU6IGZhbHNlLFxuICAgICAgICBlbmFibGVSZXNpemU6IGZhbHNlLFxuICAgICAgICBkZWZhdWx0Q3Vyc29yOiBudWxsLFxuICAgICAgICBib3JkZXJUaGlja25lc3M6IDYsXG4gICAgICAgIHNob3VsZERyYWc6IGZhbHNlLFxuICAgICAgICBjc3NEcmFnUHJvcGVydHk6IFwiLS13YWlscy1kcmFnZ2FibGVcIixcbiAgICAgICAgY3NzRHJhZ1ZhbHVlOiBcImRyYWdcIixcbiAgICB9XG59O1xuXG4vLyBTZXQgdGhlIGJpbmRpbmdzXG5pZiAod2luZG93LndhaWxzYmluZGluZ3MpIHtcbiAgICB3aW5kb3cud2FpbHMuU2V0QmluZGluZ3Mod2luZG93LndhaWxzYmluZGluZ3MpO1xuICAgIGRlbGV0ZSB3aW5kb3cud2FpbHMuU2V0QmluZGluZ3M7XG59XG5cbi8vIFRoaXMgaXMgZXZhbHVhdGVkIGF0IGJ1aWxkIHRpbWUgaW4gcGFja2FnZS5qc29uXG4vLyBjb25zdCBkZXYgPSAwO1xuLy8gY29uc3QgcHJvZHVjdGlvbiA9IDE7XG5pZiAoRU5WID09PSAxKSB7XG4gICAgZGVsZXRlIHdpbmRvdy53YWlsc2JpbmRpbmdzO1xufVxuXG53aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignbW91c2V1cCcsICgpID0+IHtcbiAgICB3aW5kb3cud2FpbHMuZmxhZ3Muc2hvdWxkRHJhZyA9IGZhbHNlO1xufSk7XG5cbmxldCBkcmFnVGVzdCA9IGZ1bmN0aW9uIChlKSB7XG4gICAgcmV0dXJuIHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlKGUudGFyZ2V0KS5nZXRQcm9wZXJ0eVZhbHVlKHdpbmRvdy53YWlscy5mbGFncy5jc3NEcmFnUHJvcGVydHkpID09PSB3aW5kb3cud2FpbHMuZmxhZ3MuY3NzRHJhZ1ZhbHVlO1xufTtcblxud2luZG93LndhaWxzLnNldENTU0RyYWdQcm9wZXJ0aWVzID0gZnVuY3Rpb24gKHByb3BlcnR5LCB2YWx1ZSkge1xuICAgIHdpbmRvdy53YWlscy5mbGFncy5jc3NEcmFnUHJvcGVydHkgPSBwcm9wZXJ0eTtcbiAgICB3aW5kb3cud2FpbHMuZmxhZ3MuY3NzRHJhZ1ZhbHVlID0gdmFsdWU7XG59XG5cbndpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdtb3VzZWRvd24nLCAoZSkgPT4ge1xuXG4gICAgLy8gQ2hlY2sgZm9yIHJlc2l6aW5nXG4gICAgaWYgKHdpbmRvdy53YWlscy5mbGFncy5yZXNpemVFZGdlKSB7XG4gICAgICAgIHdpbmRvdy5XYWlsc0ludm9rZShcInJlc2l6ZTpcIiArIHdpbmRvdy53YWlscy5mbGFncy5yZXNpemVFZGdlKTtcbiAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKGRyYWdUZXN0KGUpKSB7XG4gICAgICAgIGlmICh3aW5kb3cud2FpbHMuZmxhZ3MuZGlzYWJsZVNjcm9sbGJhckRyYWcpIHtcbiAgICAgICAgICAgIC8vIFRoaXMgY2hlY2tzIGZvciBjbGlja3Mgb24gdGhlIHNjcm9sbCBiYXJcbiAgICAgICAgICAgIGlmIChlLm9mZnNldFggPiBlLnRhcmdldC5jbGllbnRXaWR0aCB8fCBlLm9mZnNldFkgPiBlLnRhcmdldC5jbGllbnRIZWlnaHQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgd2luZG93LndhaWxzLmZsYWdzLnNob3VsZERyYWcgPSB0cnVlO1xuICAgIH1cblxufSk7XG5cbmZ1bmN0aW9uIHNldFJlc2l6ZShjdXJzb3IpIHtcbiAgICBkb2N1bWVudC5ib2R5LnN0eWxlLmN1cnNvciA9IGN1cnNvciB8fCB3aW5kb3cud2FpbHMuZmxhZ3MuZGVmYXVsdEN1cnNvcjtcbiAgICB3aW5kb3cud2FpbHMuZmxhZ3MucmVzaXplRWRnZSA9IGN1cnNvcjtcbn1cblxud2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ21vdXNlbW92ZScsIGZ1bmN0aW9uIChlKSB7XG4gICAgbGV0IG1vdXNlUHJlc3NlZCA9IGUuYnV0dG9ucyAhPT0gdW5kZWZpbmVkID8gZS5idXR0b25zIDogZS53aGljaDtcbiAgICBpZih3aW5kb3cud2FpbHMuZmxhZ3Muc2hvdWxkRHJhZyAmJiBtb3VzZVByZXNzZWQgPD0gMCkge1xuICAgICAgICB3aW5kb3cud2FpbHMuZmxhZ3Muc2hvdWxkRHJhZyA9IGZhbHNlO1xuICAgIH1cbiAgICBcbiAgICBpZiAod2luZG93LndhaWxzLmZsYWdzLnNob3VsZERyYWcpIHtcbiAgICAgICAgd2luZG93LldhaWxzSW52b2tlKFwiZHJhZ1wiKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBpZiAoIXdpbmRvdy53YWlscy5mbGFncy5lbmFibGVSZXNpemUpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBpZiAod2luZG93LndhaWxzLmZsYWdzLmRlZmF1bHRDdXJzb3IgPT0gbnVsbCkge1xuICAgICAgICB3aW5kb3cud2FpbHMuZmxhZ3MuZGVmYXVsdEN1cnNvciA9IGRvY3VtZW50LmJvZHkuc3R5bGUuY3Vyc29yO1xuICAgIH1cbiAgICBpZiAod2luZG93Lm91dGVyV2lkdGggLSBlLmNsaWVudFggPCB3aW5kb3cud2FpbHMuZmxhZ3MuYm9yZGVyVGhpY2tuZXNzICYmIHdpbmRvdy5vdXRlckhlaWdodCAtIGUuY2xpZW50WSA8IHdpbmRvdy53YWlscy5mbGFncy5ib3JkZXJUaGlja25lc3MpIHtcbiAgICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS5jdXJzb3IgPSBcInNlLXJlc2l6ZVwiO1xuICAgIH1cbiAgICBsZXQgcmlnaHRCb3JkZXIgPSB3aW5kb3cub3V0ZXJXaWR0aCAtIGUuY2xpZW50WCA8IHdpbmRvdy53YWlscy5mbGFncy5ib3JkZXJUaGlja25lc3M7XG4gICAgbGV0IGxlZnRCb3JkZXIgPSBlLmNsaWVudFggPCB3aW5kb3cud2FpbHMuZmxhZ3MuYm9yZGVyVGhpY2tuZXNzO1xuICAgIGxldCB0b3BCb3JkZXIgPSBlLmNsaWVudFkgPCB3aW5kb3cud2FpbHMuZmxhZ3MuYm9yZGVyVGhpY2tuZXNzO1xuICAgIGxldCBib3R0b21Cb3JkZXIgPSB3aW5kb3cub3V0ZXJIZWlnaHQgLSBlLmNsaWVudFkgPCB3aW5kb3cud2FpbHMuZmxhZ3MuYm9yZGVyVGhpY2tuZXNzO1xuXG4gICAgLy8gSWYgd2UgYXJlbid0IG9uIGFuIGVkZ2UsIGJ1dCB3ZXJlLCByZXNldCB0aGUgY3Vyc29yIHRvIGRlZmF1bHRcbiAgICBpZiAoIWxlZnRCb3JkZXIgJiYgIXJpZ2h0Qm9yZGVyICYmICF0b3BCb3JkZXIgJiYgIWJvdHRvbUJvcmRlciAmJiB3aW5kb3cud2FpbHMuZmxhZ3MucmVzaXplRWRnZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHNldFJlc2l6ZSgpO1xuICAgIH0gZWxzZSBpZiAocmlnaHRCb3JkZXIgJiYgYm90dG9tQm9yZGVyKSBzZXRSZXNpemUoXCJzZS1yZXNpemVcIik7XG4gICAgZWxzZSBpZiAobGVmdEJvcmRlciAmJiBib3R0b21Cb3JkZXIpIHNldFJlc2l6ZShcInN3LXJlc2l6ZVwiKTtcbiAgICBlbHNlIGlmIChsZWZ0Qm9yZGVyICYmIHRvcEJvcmRlcikgc2V0UmVzaXplKFwibnctcmVzaXplXCIpO1xuICAgIGVsc2UgaWYgKHRvcEJvcmRlciAmJiByaWdodEJvcmRlcikgc2V0UmVzaXplKFwibmUtcmVzaXplXCIpO1xuICAgIGVsc2UgaWYgKGxlZnRCb3JkZXIpIHNldFJlc2l6ZShcInctcmVzaXplXCIpO1xuICAgIGVsc2UgaWYgKHRvcEJvcmRlcikgc2V0UmVzaXplKFwibi1yZXNpemVcIik7XG4gICAgZWxzZSBpZiAoYm90dG9tQm9yZGVyKSBzZXRSZXNpemUoXCJzLXJlc2l6ZVwiKTtcbiAgICBlbHNlIGlmIChyaWdodEJvcmRlcikgc2V0UmVzaXplKFwiZS1yZXNpemVcIik7XG5cbn0pO1xuXG4vLyBTZXR1cCBjb250ZXh0IG1lbnUgaG9va1xud2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ2NvbnRleHRtZW51JywgZnVuY3Rpb24gKGUpIHtcbiAgICBpZiAod2luZG93LndhaWxzLmZsYWdzLmRpc2FibGVXYWlsc0RlZmF1bHRDb250ZXh0TWVudSkge1xuICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgfVxufSk7XG5cbndpbmRvdy5XYWlsc0ludm9rZShcInJ1bnRpbWU6cmVhZHlcIik7Il0sCiAgIm1hcHBpbmdzIjogIjs7Ozs7Ozs7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FB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QU0sTUFBTSxjQUFjLGdCQUFnQixHQUFHO0FBQ25ELGFBQU8sTUFBTSxNQUFNLGFBQWE7QUFBQSxJQUNwQztBQUVBLFFBQUksT0FBTyxNQUFNLE1BQU0sWUFBWTtBQUMvQixhQUFPLFlBQVksTUFBTTtBQUN6QjtBQUFBLElBQ0o7QUFDQSxRQUFJLENBQUMsT0FBTyxNQUFNLE1BQU0sY0FBYztBQUNsQztBQUFBLElBQ0o7QUFDQSxRQUFJLE9BQU8sTUFBTSxNQUFNLGlCQUFpQixNQUFNO0FBQzFDLGFBQU8sTUFBTSxNQUFNLGdCQUFnQixTQUFTLEtBQUssTUFBTTtBQUFBLElBQzNEO0FBQ0EsUUFBSSxPQUFPLGFBQWEsRUFBRSxVQUFVLE9BQU8sTUFBTSxNQUFNLG1CQUFtQixPQUFPLGNBQWMsRUFBRSxVQUFVLE9BQU8sTUFBTSxNQUFNLGlCQUFpQjtBQUMzSSxlQUFTLEtBQUssTUFBTSxTQUFTO0FBQUEsSUFDakM7QUFDQSxRQUFJLGNBQWMsT0FBTyxhQUFhLEVBQUUsVUFBVSxPQUFPLE1BQU0sTUFBTTtBQUNyRSxRQUFJLGFBQWEsRUFBRSxVQUFVLE9BQU8sTUFBTSxNQUFNO0FBQ2hELFFBQUksWUFBWSxFQUFFLFVBQVUsT0FBTyxNQUFNLE1BQU07QUFDL0MsUUFBSSxlQUFlLE9BQU8sY0FBYyxFQUFFLFVBQVUsT0FBTyxNQUFNLE1BQU07QUFHdkUsUUFBSSxDQUFDLGNBQWMsQ0FBQyxlQUFlLENBQUMsYUFBYSxDQUFDLGdCQUFnQixPQUFPLE1BQU0sTUFBTSxlQUFlLFFBQVc7QUFDM0csZ0JBQVU7QUFBQSxJQUNkLFdBQVcsZUFBZTtBQUFjLGdCQUFVLFdBQVc7QUFBQSxhQUNwRCxjQUFjO0FBQWMsZ0JBQVUsV0FBVztBQUFBLGFBQ2pELGNBQWM7QUFBVyxnQkFBVSxXQUFXO0FBQUEsYUFDOUMsYUFBYTtBQUFhLGdCQUFVLFdBQVc7QUFBQSxhQUMvQztBQUFZLGdCQUFVLFVBQVU7QUFBQSxhQUNoQztBQUFXLGdCQUFVLFVBQVU7QUFBQSxhQUMvQjtBQUFjLGdCQUFVLFVBQVU7QUFBQSxhQUNsQztBQUFhLGdCQUFVLFVBQVU7QUFBQSxFQUU5QyxDQUFDO0FBR0QsU0FBTyxpQkFBaUIsZUFBZSxTQUFVLEdBQUc7QUFDaEQsUUFBSSxPQUFPLE1BQU0sTUFBTSxnQ0FBZ0M7QUFDbkQsUUFBRSxlQUFlO0FBQUEsSUFDckI7QUFBQSxFQUNKLENBQUM7QUFFRCxTQUFPLFlBQVksZUFBZTsiLAogICJuYW1lcyI6IFsiZXZlbnROYW1lIl0KfQo= diff --git a/v2/internal/frontend/runtime/runtime_prod_desktop.js b/v2/internal/frontend/runtime/runtime_prod_desktop.js index daf0ade57..d25191c73 100644 --- a/v2/internal/frontend/runtime/runtime_prod_desktop.js +++ b/v2/internal/frontend/runtime/runtime_prod_desktop.js @@ -1 +1 @@ -(()=>{var O=Object.defineProperty;var u=(e,n)=>{for(var o in n)O(e,o,{get:n[o],enumerable:!0})};var p={};u(p,{LogDebug:()=>R,LogError:()=>H,LogFatal:()=>A,LogInfo:()=>B,LogLevel:()=>J,LogPrint:()=>C,LogTrace:()=>z,LogWarning:()=>P,SetLogLevel:()=>M});function d(e,n){window.WailsInvoke("L"+e+n)}function z(e){d("T",e)}function C(e){d("P",e)}function R(e){d("D",e)}function B(e){d("I",e)}function P(e){d("W",e)}function H(e){d("E",e)}function A(e){d("F",e)}function M(e){d("S",e)}var J={TRACE:1,DEBUG:2,INFO:3,WARNING:4,ERROR:5};var v=class{constructor(n,o){o=o||-1,this.Callback=i=>(n.apply(null,i),o===-1?!1:(o-=1,o===0))}},l={};function W(e,n,o){l[e]=l[e]||[];let i=new v(n,o);l[e].push(i)}function h(e,n){W(e,n,-1)}function S(e,n){W(e,n,1)}function y(e){let n=e.name;if(l[n]){let o=l[n].slice();for(let i=0;i0&&n.forEach(o=>{k(o)})}var f={};function F(){var e=new Uint32Array(1);return window.crypto.getRandomValues(e)[0]}function G(){return Math.random()*9007199254740991}var g;window.crypto?g=F:g=G;function s(e,n,o){return o==null&&(o=0),new Promise(function(i,t){var r;do r=e+"-"+g();while(f[r]);var w;o>0&&(w=setTimeout(function(){t(Error("Call to "+e+" timed out. Request ID: "+r))},o)),f[r]={timeoutHandle:w,reject:t,resolve:i};try{let c={name:e,args:n,callbackID:r};window.WailsInvoke("C"+JSON.stringify(c))}catch(c){console.error(c)}})}window.ObfuscatedCall=(e,n,o)=>(o==null&&(o=0),new Promise(function(i,t){var r;do r=e+"-"+g();while(f[r]);var w;o>0&&(w=setTimeout(function(){t(Error("Call to method "+e+" timed out. Request ID: "+r))},o)),f[r]={timeoutHandle:w,reject:t,resolve:i};try{let c={id:e,args:n,callbackID:r};window.WailsInvoke("c"+JSON.stringify(c))}catch(c){console.error(c)}}));function L(e){let n;try{n=JSON.parse(e)}catch(t){let r=`Invalid JSON passed to callback: ${t.message}. Message: ${e}`;throw runtime.LogDebug(r),new Error(r)}let o=n.callbackid,i=f[o];if(!i){let t=`Callback '${o}' not registered!!!`;throw console.error(t),new Error(t)}clearTimeout(i.timeoutHandle),delete f[o],n.error?i.reject(n.error):i.resolve(n.result)}window.go={};function T(e){try{e=JSON.parse(e)}catch(n){console.error(n)}window.go=window.go||{},Object.keys(e).forEach(n=>{window.go[n]=window.go[n]||{},Object.keys(e[n]).forEach(o=>{window.go[n][o]=window.go[n][o]||{},Object.keys(e[n][o]).forEach(i=>{window.go[n][o][i]=function(){let t=0;function r(){let w=[].slice.call(arguments);return s([n,o,i].join("."),w,t)}return r.setTimeout=function(w){t=w},r.getTimeout=function(){return t},r}()})})})}var x={};u(x,{WindowCenter:()=>N,WindowFullscreen:()=>q,WindowGetPosition:()=>te,WindowGetSize:()=>_,WindowHide:()=>re,WindowIsFullscreen:()=>Z,WindowIsMaximised:()=>de,WindowIsMinimised:()=>ue,WindowIsNormal:()=>We,WindowMaximise:()=>le,WindowMinimise:()=>fe,WindowReload:()=>U,WindowReloadApp:()=>V,WindowSetAlwaysOnTop:()=>oe,WindowSetBackgroundColour:()=>ge,WindowSetDarkTheme:()=>Y,WindowSetLightTheme:()=>X,WindowSetMaxSize:()=>ee,WindowSetMinSize:()=>ne,WindowSetPosition:()=>ie,WindowSetSize:()=>K,WindowSetSystemDefaultTheme:()=>j,WindowSetTitle:()=>$,WindowShow:()=>se,WindowToggleMaximise:()=>we,WindowUnfullscreen:()=>Q,WindowUnmaximise:()=>ae,WindowUnminimise:()=>ce});function U(){window.location.reload()}function V(){window.WailsInvoke("WR")}function j(){window.WailsInvoke("WASDT")}function X(){window.WailsInvoke("WALT")}function Y(){window.WailsInvoke("WADT")}function N(){window.WailsInvoke("Wc")}function $(e){window.WailsInvoke("WT"+e)}function q(){window.WailsInvoke("WF")}function Q(){window.WailsInvoke("Wf")}function Z(){return s(":wails:WindowIsFullscreen")}function K(e,n){window.WailsInvoke("Ws:"+e+":"+n)}function _(){return s(":wails:WindowGetSize")}function ee(e,n){window.WailsInvoke("WZ:"+e+":"+n)}function ne(e,n){window.WailsInvoke("Wz:"+e+":"+n)}function oe(e){window.WailsInvoke("WATP:"+(e?"1":"0"))}function ie(e,n){window.WailsInvoke("Wp:"+e+":"+n)}function te(){return s(":wails:WindowGetPos")}function re(){window.WailsInvoke("WH")}function se(){window.WailsInvoke("WS")}function le(){window.WailsInvoke("WM")}function we(){window.WailsInvoke("Wt")}function ae(){window.WailsInvoke("WU")}function de(){return s(":wails:WindowIsMaximised")}function fe(){window.WailsInvoke("Wm")}function ce(){window.WailsInvoke("Wu")}function ue(){return s(":wails:WindowIsMinimised")}function We(){return s(":wails:WindowIsNormal")}function ge(e,n,o,i){let t=JSON.stringify({r:e||0,g:n||0,b:o||0,a:i||255});window.WailsInvoke("Wr:"+t)}var m={};u(m,{ScreenGetAll:()=>pe});function pe(){return s(":wails:ScreenGetAll")}var I={};u(I,{BrowserOpenURL:()=>ve});function ve(e){window.WailsInvoke("BO:"+e)}function xe(){window.WailsInvoke("Q")}function me(){window.WailsInvoke("S")}function Ie(){window.WailsInvoke("H")}function ke(){return s(":wails:Environment")}window.runtime={...p,...x,...I,...m,EventsOn:h,EventsOnce:S,EventsOnMultiple:W,EventsEmit:b,EventsOff:D,Environment:ke,Show:me,Hide:Ie,Quit:xe};window.wails={Callback:L,EventsNotify:E,SetBindings:T,eventListeners:l,callbacks:f,flags:{disableScrollbarDrag:!1,disableWailsDefaultContextMenu:!1,enableResize:!1,defaultCursor:null,borderThickness:6,shouldDrag:!1,cssDragProperty:"--wails-draggable",cssDragValue:"drag"}};window.wailsbindings&&(window.wails.SetBindings(window.wailsbindings),delete window.wails.SetBindings);delete window.wailsbindings;window.addEventListener("mouseup",()=>{window.wails.flags.shouldDrag=!1});var he=function(e){return window.getComputedStyle(e.target).getPropertyValue(window.wails.flags.cssDragProperty)===window.wails.flags.cssDragValue};window.wails.setCSSDragProperties=function(e,n){window.wails.flags.cssDragProperty=e,window.wails.flags.cssDragValue=n};window.addEventListener("mousedown",e=>{if(window.wails.flags.resizeEdge){window.WailsInvoke("resize:"+window.wails.flags.resizeEdge),e.preventDefault();return}if(he(e)){if(window.wails.flags.disableScrollbarDrag&&(e.offsetX>e.target.clientWidth||e.offsetY>e.target.clientHeight))return;window.wails.flags.shouldDrag=!0}});function a(e){document.body.style.cursor=e||window.wails.flags.defaultCursor,window.wails.flags.resizeEdge=e}window.addEventListener("mousemove",function(e){if(window.wails.flags.shouldDrag){window.WailsInvoke("drag");return}if(!window.wails.flags.enableResize)return;window.wails.flags.defaultCursor==null&&(window.wails.flags.defaultCursor=document.body.style.cursor),window.outerWidth-e.clientX{var O=Object.defineProperty;var u=(e,o)=>{for(var n in o)O(e,n,{get:o[n],enumerable:!0})};var p={};u(p,{LogDebug:()=>R,LogError:()=>H,LogFatal:()=>A,LogInfo:()=>P,LogLevel:()=>J,LogPrint:()=>C,LogTrace:()=>z,LogWarning:()=>B,SetLogLevel:()=>M});function d(e,o){window.WailsInvoke("L"+e+o)}function z(e){d("T",e)}function C(e){d("P",e)}function R(e){d("D",e)}function P(e){d("I",e)}function B(e){d("W",e)}function H(e){d("E",e)}function A(e){d("F",e)}function M(e){d("S",e)}var J={TRACE:1,DEBUG:2,INFO:3,WARNING:4,ERROR:5};var v=class{constructor(o,n){n=n||-1,this.Callback=i=>(o.apply(null,i),n===-1?!1:(n-=1,n===0))}},l={};function g(e,o,n){l[e]=l[e]||[];let i=new v(o,n);l[e].push(i)}function k(e,o){g(e,o,-1)}function S(e,o){g(e,o,1)}function y(e){let o=e.name;if(l[o]){let n=l[o].slice();for(let i=0;i0&&o.forEach(n=>{h(n)})}var f={};function F(){var e=new Uint32Array(1);return window.crypto.getRandomValues(e)[0]}function G(){return Math.random()*9007199254740991}var W;window.crypto?W=F:W=G;function s(e,o,n){return n==null&&(n=0),new Promise(function(i,r){var t;do t=e+"-"+W();while(f[t]);var w;n>0&&(w=setTimeout(function(){r(Error("Call to "+e+" timed out. Request ID: "+t))},n)),f[t]={timeoutHandle:w,reject:r,resolve:i};try{let c={name:e,args:o,callbackID:t};window.WailsInvoke("C"+JSON.stringify(c))}catch(c){console.error(c)}})}window.ObfuscatedCall=(e,o,n)=>(n==null&&(n=0),new Promise(function(i,r){var t;do t=e+"-"+W();while(f[t]);var w;n>0&&(w=setTimeout(function(){r(Error("Call to method "+e+" timed out. Request ID: "+t))},n)),f[t]={timeoutHandle:w,reject:r,resolve:i};try{let c={id:e,args:o,callbackID:t};window.WailsInvoke("c"+JSON.stringify(c))}catch(c){console.error(c)}}));function L(e){let o;try{o=JSON.parse(e)}catch(r){let t=`Invalid JSON passed to callback: ${r.message}. Message: ${e}`;throw runtime.LogDebug(t),new Error(t)}let n=o.callbackid,i=f[n];if(!i){let r=`Callback '${n}' not registered!!!`;throw console.error(r),new Error(r)}clearTimeout(i.timeoutHandle),delete f[n],o.error?i.reject(o.error):i.resolve(o.result)}window.go={};function T(e){try{e=JSON.parse(e)}catch(o){console.error(o)}window.go=window.go||{},Object.keys(e).forEach(o=>{window.go[o]=window.go[o]||{},Object.keys(e[o]).forEach(n=>{window.go[o][n]=window.go[o][n]||{},Object.keys(e[o][n]).forEach(i=>{window.go[o][n][i]=function(){let r=0;function t(){let w=[].slice.call(arguments);return s([o,n,i].join("."),w,r)}return t.setTimeout=function(w){r=w},t.getTimeout=function(){return r},t}()})})})}var x={};u(x,{WindowCenter:()=>N,WindowFullscreen:()=>q,WindowGetPosition:()=>te,WindowGetSize:()=>_,WindowHide:()=>re,WindowIsFullscreen:()=>Z,WindowIsMaximised:()=>de,WindowIsMinimised:()=>ue,WindowIsNormal:()=>ge,WindowMaximise:()=>le,WindowMinimise:()=>fe,WindowReload:()=>U,WindowReloadApp:()=>V,WindowSetAlwaysOnTop:()=>ne,WindowSetBackgroundColour:()=>We,WindowSetDarkTheme:()=>Y,WindowSetLightTheme:()=>X,WindowSetMaxSize:()=>ee,WindowSetMinSize:()=>oe,WindowSetPosition:()=>ie,WindowSetSize:()=>K,WindowSetSystemDefaultTheme:()=>j,WindowSetTitle:()=>$,WindowShow:()=>se,WindowToggleMaximise:()=>we,WindowUnfullscreen:()=>Q,WindowUnmaximise:()=>ae,WindowUnminimise:()=>ce});function U(){window.location.reload()}function V(){window.WailsInvoke("WR")}function j(){window.WailsInvoke("WASDT")}function X(){window.WailsInvoke("WALT")}function Y(){window.WailsInvoke("WADT")}function N(){window.WailsInvoke("Wc")}function $(e){window.WailsInvoke("WT"+e)}function q(){window.WailsInvoke("WF")}function Q(){window.WailsInvoke("Wf")}function Z(){return s(":wails:WindowIsFullscreen")}function K(e,o){window.WailsInvoke("Ws:"+e+":"+o)}function _(){return s(":wails:WindowGetSize")}function ee(e,o){window.WailsInvoke("WZ:"+e+":"+o)}function oe(e,o){window.WailsInvoke("Wz:"+e+":"+o)}function ne(e){window.WailsInvoke("WATP:"+(e?"1":"0"))}function ie(e,o){window.WailsInvoke("Wp:"+e+":"+o)}function te(){return s(":wails:WindowGetPos")}function re(){window.WailsInvoke("WH")}function se(){window.WailsInvoke("WS")}function le(){window.WailsInvoke("WM")}function we(){window.WailsInvoke("Wt")}function ae(){window.WailsInvoke("WU")}function de(){return s(":wails:WindowIsMaximised")}function fe(){window.WailsInvoke("Wm")}function ce(){window.WailsInvoke("Wu")}function ue(){return s(":wails:WindowIsMinimised")}function ge(){return s(":wails:WindowIsNormal")}function We(e,o,n,i){let r=JSON.stringify({r:e||0,g:o||0,b:n||0,a:i||255});window.WailsInvoke("Wr:"+r)}var m={};u(m,{ScreenGetAll:()=>pe});function pe(){return s(":wails:ScreenGetAll")}var I={};u(I,{BrowserOpenURL:()=>ve});function ve(e){window.WailsInvoke("BO:"+e)}function xe(){window.WailsInvoke("Q")}function me(){window.WailsInvoke("S")}function Ie(){window.WailsInvoke("H")}function he(){return s(":wails:Environment")}window.runtime={...p,...x,...I,...m,EventsOn:k,EventsOnce:S,EventsOnMultiple:g,EventsEmit:b,EventsOff:D,Environment:he,Show:me,Hide:Ie,Quit:xe};window.wails={Callback:L,EventsNotify:E,SetBindings:T,eventListeners:l,callbacks:f,flags:{disableScrollbarDrag:!1,disableWailsDefaultContextMenu:!1,enableResize:!1,defaultCursor:null,borderThickness:6,shouldDrag:!1,cssDragProperty:"--wails-draggable",cssDragValue:"drag"}};window.wailsbindings&&(window.wails.SetBindings(window.wailsbindings),delete window.wails.SetBindings);delete window.wailsbindings;window.addEventListener("mouseup",()=>{window.wails.flags.shouldDrag=!1});var ke=function(e){return window.getComputedStyle(e.target).getPropertyValue(window.wails.flags.cssDragProperty)===window.wails.flags.cssDragValue};window.wails.setCSSDragProperties=function(e,o){window.wails.flags.cssDragProperty=e,window.wails.flags.cssDragValue=o};window.addEventListener("mousedown",e=>{if(window.wails.flags.resizeEdge){window.WailsInvoke("resize:"+window.wails.flags.resizeEdge),e.preventDefault();return}if(ke(e)){if(window.wails.flags.disableScrollbarDrag&&(e.offsetX>e.target.clientWidth||e.offsetY>e.target.clientHeight))return;window.wails.flags.shouldDrag=!0}});function a(e){document.body.style.cursor=e||window.wails.flags.defaultCursor,window.wails.flags.resizeEdge=e}window.addEventListener("mousemove",function(e){let o=e.buttons!==void 0?e.buttons:e.which;if(window.wails.flags.shouldDrag&&o<=0&&(window.wails.flags.shouldDrag=!1),window.wails.flags.shouldDrag){window.WailsInvoke("drag");return}if(!window.wails.flags.enableResize)return;window.wails.flags.defaultCursor==null&&(window.wails.flags.defaultCursor=document.body.style.cursor),window.outerWidth-e.clientX Date: Fri, 30 Sep 2022 05:17:34 +0800 Subject: [PATCH 14/36] docs: sync documents (#1907) * fix(website): fix command flag name * feat(website): sync translations --- website/docs/guides/obfuscated.mdx | 4 +- website/i18n/ja/code.json | 8 +- .../current.json | 16 +- .../current/community/showcase/riftshare.mdx | 2 +- .../current/gettingstarted/building.mdx | 8 +- .../current/gettingstarted/development.mdx | 14 +- .../current/gettingstarted/firstproject.mdx | 42 ++-- .../current/gettingstarted/installation.mdx | 38 +-- .../current/guides/frontend.mdx | 2 +- .../current/guides/obfuscated.mdx | 4 +- .../current/guides/routing.mdx | 2 +- .../current/guides/signing.mdx | 33 +-- .../current/guides/troubleshooting.mdx | 4 +- .../current/guides/windows-installer.mdx | 2 +- .../current/howdoesitwork.mdx | 223 +++++++++--------- .../current/introduction.mdx | 70 +++--- .../current/reference/cli.mdx | 12 +- .../current/reference/menus.mdx | 11 +- .../current/reference/options.mdx | 170 ++++++------- .../current/reference/runtime/browser.mdx | 4 +- .../current/reference/runtime/dialog.mdx | 98 ++++---- .../current/reference/runtime/events.mdx | 12 +- .../current/reference/runtime/intro.mdx | 44 ++-- .../current/reference/runtime/log.mdx | 64 ++--- .../current/reference/runtime/menu.mdx | 8 +- .../current/reference/runtime/window.mdx | 82 +++---- .../version-v2.0.0-rc.1.json | 14 +- .../version-v2.0.0.json | 14 +- .../version-v2.0.0/guides/obfuscated.mdx | 4 +- .../changelog.mdx | 17 +- .../docusaurus-plugin-content-pages/coc.mdx | 16 +- .../credits.mdx | 33 +-- .../markdown-page.md | 2 +- .../ja/docusaurus-theme-classic/footer.json | 6 +- .../ja/docusaurus-theme-classic/navbar.json | 6 +- website/i18n/zh-Hans/code.json | 2 +- .../2021-09-27-v2-beta1-release-notes.mdx | 4 +- .../2022-09-22-v2-release-notes.mdx | 2 +- .../current/gettingstarted/development.mdx | 2 +- .../current/gettingstarted/firstproject.mdx | 8 +- .../current/guides/obfuscated.mdx | 4 +- .../current/howdoesitwork.mdx | 4 +- .../current/reference/cli.mdx | 44 ++-- .../current/reference/menus.mdx | 2 +- .../current/reference/runtime/dialog.mdx | 30 ++- .../current/reference/runtime/intro.mdx | 2 +- .../current/tutorials/dogsapi.mdx | 2 +- .../version-v2.0.0/guides/obfuscated.mdx | 4 +- .../changelog.mdx | 39 ++- .../credits.mdx | 1 + .../docusaurus-theme-classic/footer.json | 2 +- .../version-v2.0.0-rc.1/guides/obfuscated.mdx | 4 +- 52 files changed, 650 insertions(+), 595 deletions(-) diff --git a/website/docs/guides/obfuscated.mdx b/website/docs/guides/obfuscated.mdx index c062d0f46..2e7906c40 100644 --- a/website/docs/guides/obfuscated.mdx +++ b/website/docs/guides/obfuscated.mdx @@ -5,13 +5,13 @@ Wails includes support for obfuscating your application using [garble](https://g To produce an obfuscated build, you can use the `-obfuscate` flag with the `wails build` command: ```bash -wails build -obfuscate +wails build -obfuscated ``` To customise the obfuscation settings, you can use the `-garbleargs` flag: ```bash -wails build -obfuscate -garbleargs "-literals -tiny -seed=myrandomseed" +wails build -obfuscated -garbleargs "-literals -tiny -seed=myrandomseed" ``` These settings may be persisted in your [project config](../reference/project-config). diff --git a/website/i18n/ja/code.json b/website/i18n/ja/code.json index 91db7b3fa..9f94ff6aa 100644 --- a/website/i18n/ja/code.json +++ b/website/i18n/ja/code.json @@ -3,7 +3,7 @@ "message": "豊富な機能" }, "homepage.Features.Description1": { - "message": "Build comprehensive cross-platform applications using native UI elements such as menus and dialogs." + "message": "メニューやダイアログといったネイティブUI要素を使用して、クロスプラットフォームアプリを構築しましょう。" }, "homepage.Features.Title2": { "message": "使い慣れた技術" @@ -147,7 +147,7 @@ "description": "The ARIA label and title attribute for expand button of doc sidebar" }, "theme.docs.sidebar.expandButtonAriaLabel": { - "message": "サイドバーを展開", + "message": "サイドバーを開く", "description": "The ARIA label and title attribute for expand button of doc sidebar" }, "theme.docs.paginator.navAriaLabel": { @@ -167,7 +167,7 @@ "description": "The title attribute for collapse button of doc sidebar" }, "theme.docs.sidebar.collapseButtonAriaLabel": { - "message": "サイドバーを折りたたむ", + "message": "サイドバーをたたむ", "description": "The title attribute for collapse button of doc sidebar" }, "theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": { @@ -242,7 +242,7 @@ "description": "The label used by the button on the collapsible TOC component" }, "theme.navbar.mobileLanguageDropdown.label": { - "message": "言語一覧", + "message": "言語", "description": "The label for the mobile language switcher dropdown" }, "theme.SearchBar.seeAll": { diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/current.json b/website/i18n/ja/docusaurus-plugin-content-docs/current.json index a810fd335..b5600edee 100644 --- a/website/i18n/ja/docusaurus-plugin-content-docs/current.json +++ b/website/i18n/ja/docusaurus-plugin-content-docs/current.json @@ -4,35 +4,35 @@ "description": "The label for version current" }, "sidebar.docs.category.Getting Started": { - "message": "Getting Started", + "message": "はじめよう", "description": "The label for category Getting Started in sidebar docs" }, "sidebar.docs.category.Reference": { - "message": "Reference", + "message": "リファレンス", "description": "The label for category Reference in sidebar docs" }, "sidebar.docs.category.Runtime": { - "message": "Runtime", + "message": "ランタイム", "description": "The label for category Runtime in sidebar docs" }, "sidebar.docs.category.Community": { - "message": "Community", + "message": "コミュニティ", "description": "The label for category Community in sidebar docs" }, "sidebar.docs.category.Showcase": { - "message": "Showcase", + "message": "事例紹介", "description": "The label for category Showcase in sidebar docs" }, "sidebar.docs.category.Guides": { - "message": "Guides", + "message": "ガイド", "description": "The label for category Guides in sidebar docs" }, "sidebar.docs.category.Tutorials": { - "message": "Tutorials", + "message": "チュートリアル", "description": "The label for category Tutorials in sidebar docs" }, "sidebar.docs.link.Contributing": { - "message": "Contributing", + "message": "コントリビューション", "description": "The label for link Contributing in sidebar docs, linking to /community-guide#ways-of-contributing" } } diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/current/community/showcase/riftshare.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/current/community/showcase/riftshare.mdx index 9928b4785..c86691f21 100644 --- a/website/i18n/ja/docusaurus-plugin-content-docs/current/community/showcase/riftshare.mdx +++ b/website/i18n/ja/docusaurus-plugin-content-docs/current/community/showcase/riftshare.mdx @@ -9,7 +9,7 @@ Easy, Secure, and Free file sharing for everyone. Learn more at [Riftshare.app](https://riftshare.app) -## Features +## 機能 - Easy secure file sharing between computers both in the local network and through the internet - Supports sending files or directories securely through the [magic wormhole protocol](https://magic-wormhole.readthedocs.io/en/latest/) diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/current/gettingstarted/building.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/current/gettingstarted/building.mdx index a1f69f033..dfab958b4 100644 --- a/website/i18n/ja/docusaurus-plugin-content-docs/current/gettingstarted/building.mdx +++ b/website/i18n/ja/docusaurus-plugin-content-docs/current/gettingstarted/building.mdx @@ -2,11 +2,11 @@ sidebar_position: 6 --- -# Compiling your Project +# プロジェクトのコンパイル -From the project directory, run `wails build`. This will compile your project and save the production-ready binary in the `build/bin` directory. +プロジェクトディレクトリ上で、`wails build`コマンドを実行しましょう。 そうすることで、プロジェクトがコンパイルされ、`build/bin`ディレクトリ内に本番配布用のバイナリが出力されます。 -If you run the binary, you should see the default application: +バイナリを起動すると、デフォルト仕様のアプリを確認することができます: ```mdx-code-block
@@ -19,4 +19,4 @@ If you run the binary, you should see the default application:
``` -For more details on compilation options, please refer to the [CLI Reference](../reference/cli.mdx#build). +コンパイルオプションについて詳しくは、[CLIリファレンス](../reference/cli.mdx#build)をご覧ください。 diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/current/gettingstarted/development.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/current/gettingstarted/development.mdx index a0075ef69..b26c3c546 100644 --- a/website/i18n/ja/docusaurus-plugin-content-docs/current/gettingstarted/development.mdx +++ b/website/i18n/ja/docusaurus-plugin-content-docs/current/gettingstarted/development.mdx @@ -2,15 +2,15 @@ sidebar_position: 5 --- -# Developing your Application +# アプリの開発 -You can run your application in development mode by running `wails dev` from your project directory. This will do the following things: +プロジェクトディレクトリのルート上で`wails dev`コマンドを実行すると、アプリを開発モードで起動することができます。 コマンドを実行すると下記の処理が実行されます: -- Build your application and run it -- Bind your Go code to the frontend so it can be called from Javascript +- アプリをビルドしたのち、起動する +- Goのコードをフロントエンドにバインドし、Javascriptから呼び出せるようにする - Using the power of [Vite](https://vitejs.dev/), will watch for modifications in your Go files and rebuild/re-run on change -- Sets up a [webserver](http://localhost:34115) that will serve your application over a browser. This allows you to use your favourite browser extensions. You can even call your Go code from the console +- ブラウザからアプリを操作できるようにする[Webサーバ](http://localhost:34115)を立ち上げる。 これにより、任意のブラウザ拡張機能を利用できる。 JavascriptのコンソールからGoのコードを呼び出すこともできる -To get started, run `wails dev` in the project directory. More information on this can be found [here](../reference/cli.mdx#dev). +アプリ開発を始めるときは、プロジェクトディレクトリ上で`wails dev`コマンドを実行しましょう。 詳しくは、[こちら](../reference/cli.mdx#dev)をご覧ください。 -Coming soon: Tutorial +近日中にチュートリアルを公開予定です。 diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/current/gettingstarted/firstproject.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/current/gettingstarted/firstproject.mdx index 3428906ef..8ce6453d7 100644 --- a/website/i18n/ja/docusaurus-plugin-content-docs/current/gettingstarted/firstproject.mdx +++ b/website/i18n/ja/docusaurus-plugin-content-docs/current/gettingstarted/firstproject.mdx @@ -2,13 +2,13 @@ sidebar_position: 2 --- -# Creating a Project +# プロジェクトの開始 -## Project Generation +## プロジェクトの生成 -Now that the CLI is installed, you can generate a new project by using the `wails init` command. +CLIのインストールが終わったら、`wails init`コマンドで新しいプロジェクトを生成しましょう。 -Pick your favourite framework: +好きなフレームワークを選択してください: ```mdx-code-block import Tabs from "@theme/Tabs"; @@ -90,13 +90,13 @@ If you would rather use Typescript:

-There are also [community templates](../community/templates.mdx) available that offer different capabilities and frameworks. +様々な機能やフレームワークを提供する[コミュニティテンプレート](../community/templates.mdx)を利用することもできます。 -To see the other options available, you can run `wails init -help`. More details can be found in the [CLI Reference](../reference/cli.mdx#init). +プロジェクト生成時に使用可能なオプションを確認するには、`wails init -help`を実行してください。 詳しくは、[CLIリファレンス](../reference/cli.mdx#init)を参照してください。 -## Project Layout +## プロジェクトのディレクトリ構成 -Wails projects have the following layout: +Wailsのプロジェクトディレクトリの構成は次のとおりです: ``` . @@ -111,20 +111,20 @@ Wails projects have the following layout: └── wails.json ``` -### Project structure rundown +### プロジェクトの構造 -- `/main.go` - The main application -- `/frontend/` - Frontend project files -- `/build/` - Project build directory -- `/build/appicon.png` - The application icon -- `/build/darwin/` - Mac specific project files -- `/build/windows/` - Windows specific project files -- `/wails.json` - The project configuration -- `/go.mod` - Go module file -- `/go.sum` - Go module checksum file +- `/main.go` - アプリのメインコード +- `/frontend/` - フロントエンドのプロジェクトディレクトリ +- `/build/` - ビルドディレクトリ +- `/build/appicon.png` - アプリアイコン +- `/build/darwin/` - Mac固有のプロジェクトディレクトリ +- `/build/windows/` - Windows固有のプロジェクトディレクトリ +- `/wails.json` - プロジェクト構成ファイル +- `/go.mod` - Goモジュール定義ファイル +- `/go.sum` - Goモジュールチェックサムファイル -The `frontend` directory has nothing specific to Wails and can be any frontend project of your choosing. +`frontend`ディレクトリ内は、Wailsで決まったファイル構成等は無く、お好きなフロントエンドプロジェクトを配置することができます。 -The `build` directory is used during the build process. These files may be updated to customise your builds. If files are removed from the build directory, default versions will be regenerated. +`build`ディレクトリは、アプリのビルド時に使用されます。 この中のファイルは、ビルドの挙動をカスタマイズするために、適宜ファイル内容を書き換えることができます。 buildディレクトリ内のファイルを削除すると、デフォルトのファイルが再生成されます。 -The default module name in `go.mod` is "changeme". You should change this to something more appropriate. +`go.mod`のモジュール名は、最初は"changeme"になっています。 このモジュール名は、あなたのプロジェクトに適切な名前に変更しましょう。 diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/current/gettingstarted/installation.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/current/gettingstarted/installation.mdx index 858100bbe..1317c1ec4 100644 --- a/website/i18n/ja/docusaurus-plugin-content-docs/current/gettingstarted/installation.mdx +++ b/website/i18n/ja/docusaurus-plugin-content-docs/current/gettingstarted/installation.mdx @@ -2,18 +2,18 @@ sidebar_position: 1 --- -# Installation +# インストール -## Supported Platforms +## サポートされているプラットフォーム - Windows 10/11 AMD64/ARM64 - MacOS 10.13+ AMD64 - MacOS 11.0+ ARM64 - Linux AMD64/ARM64 -## Dependencies +## 依存関係 -Wails has a number of common dependencies that are required before installation: +Wailsをインストールする前に、下記のものを導入しておく必要があります。 - Go 1.18+ - NPM (Node 15+) @@ -22,20 +22,20 @@ Wails has a number of common dependencies that are required before installation: Download Go from the [Go Downloads Page](https://go.dev/dl/). -Ensure that you follow the official [Go installation instructions](https://go.dev/doc/install). You will also need to ensure that your `PATH` environment variable also includes the path to your `~/go/bin` directory. Restart your terminal and do the following checks: +公式の[Goインストール手順](https://go.dev/doc/install)に従って、Goをインストールしてください。 その際、`PATH`環境変数に`~/go/bin`ディレクトリへのパスが含まれていることも確認してください。 それらが終わったら、ターミナルを再起動し、以下の確認をしてください: -- Check Go is installed correctly: `go version` -- Check "~/go/bin" is in your PATH variable: `echo $PATH | grep go/bin` +- Goが正しくインストールされているかを確認する: `go version` +- "~/go/bin"のディレクトリパスがPATH環境変数に含まれているか確認する: `echo $PATH | grep go/bin` ### NPM -Download NPM from the [Node Downloads Page](https://nodejs.org/en/download/). It is best to use the latest release as that is what we generally test against. +[Nodeダウンロードページ](https://nodejs.org/ja/download/)からNPMをダウンロードしてください。 最新版を利用することをお勧めします。なぜなら、私たちは最新版に対してテストを実施しているためです。 -Run `npm --version` to verify. +`npm --version`を実行して、インストールが完了しているかを確認してください。 -## Platform Specific Dependencies +## プラットフォーム固有の依存関係 -You will also need to install platform specific dependencies: +開発作業を行うプラットフォームによって、必要な依存関係が存在します: ```mdx-code-block import Tabs from "@theme/Tabs"; @@ -62,18 +62,18 @@ import TabItem from "@theme/TabItem"; ``` -## Optional Dependencies +## 任意の依存関係 -- [UPX](https://upx.github.io/) for compressing your applications. +- [UPX](https://upx.github.io/)を導入することで、構築したアプリを圧縮できます。 -## Installing Wails +## Wailsのインストール -Run `go install github.com/wailsapp/wails/v2/cmd/wails@latest` to install the Wails CLI. +`go install github.com/wailsapp/wails/v2/cmd/wails@latest`を実行して、Wails CLIをインストールしてください。 -## System Check +## システムチェック -Running `wails doctor` will check if you have the correct dependencies installed. If not, it will advise on what is missing and help on how to rectify any problems. +`wails doctor`を実行すると、必要な依存関係が正しくインストールされているかを確認することができます。 正しくインストールされていない場合は、その内容をあなたにお知らせして、どうすれば解決できるかを教えてくれます。 -## The `wails` command appears to be missing? +## `wails`コマンドが見つからないのですが? -If your system is reporting that the `wails` command is missing, make sure you have followed the Go installation guide correctly. Normally, it means that the `go/bin` directory in your User's home directory is not in the `PATH` environment variable. You will also normally need to close and reopen any open command prompts so that changes to the environment made by the installer are reflected at the command prompt. +`wails`コマンドが見つからないとシステムに怒られた場合は、Goが、公式のGoインストール手順に従って導入されているかを確認してください。 コマンドが見つからないほとんどの理由は、あなたのホームディレクトリ配下にある`go/bin`ディレクトリのパスが、`PATH`環境変数に含まれていないからです。 また、インストールによって行われた環境変更を反映させるために、もともと開いていたコマンドプロンプト(ターミナル)がある場合はそれらをいったん閉じて、再度開きなおしてください。 diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/current/guides/frontend.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/current/guides/frontend.mdx index 4b192c557..29e442c5e 100644 --- a/website/i18n/ja/docusaurus-plugin-content-docs/current/guides/frontend.mdx +++ b/website/i18n/ja/docusaurus-plugin-content-docs/current/guides/frontend.mdx @@ -39,7 +39,7 @@ To provide more flexibility to developers, there is a meta tag that may be used The options are as follows: -| Value | Description | +| 値 | Description | | ------------------- | ------------------------------------------------ | | noautoinjectruntime | Disable the autoinjection of `/wails/runtime.js` | | noautoinjectipc | Disable the autoinjection of `/wails/ipc.js` | diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/current/guides/obfuscated.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/current/guides/obfuscated.mdx index 049efbb32..d5c6c5a29 100644 --- a/website/i18n/ja/docusaurus-plugin-content-docs/current/guides/obfuscated.mdx +++ b/website/i18n/ja/docusaurus-plugin-content-docs/current/guides/obfuscated.mdx @@ -5,13 +5,13 @@ Wails includes support for obfuscating your application using [garble](https://g To produce an obfuscated build, you can use the `-obfuscate` flag with the `wails build` command: ```bash -wails build -obfuscate +wails build -obfuscated ``` To customise the obfuscation settings, you can use the `-garbleargs` flag: ```bash -wails build -obfuscate -garbleargs "-literals -tiny -seed=myrandomseed" +wails build -obfuscated -garbleargs "-literals -tiny -seed=myrandomseed" ``` These settings may be persisted in your [project config](../reference/project-config). diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/current/guides/routing.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/current/guides/routing.mdx index 5a47814cc..a3444f98e 100644 --- a/website/i18n/ja/docusaurus-plugin-content-docs/current/guides/routing.mdx +++ b/website/i18n/ja/docusaurus-plugin-content-docs/current/guides/routing.mdx @@ -22,7 +22,7 @@ const router = createRouter({ The recommended approach for routing in Angular is [HashLocationStrategy](https://codecraft.tv/courses/angular/routing/routing-strategies#_hashlocationstrategy): ```ts -RouterModule.forRoot(routes, {useHash: true}) +RouterModule.forRoot(routes, { useHash: true }); ``` ## React diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/current/guides/signing.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/current/guides/signing.mdx index 3e56f06c1..5bd36b110 100644 --- a/website/i18n/ja/docusaurus-plugin-content-docs/current/guides/signing.mdx +++ b/website/i18n/ja/docusaurus-plugin-content-docs/current/guides/signing.mdx @@ -16,23 +16,24 @@ on: workflow_dispatch: # This Action only starts when you go to Actions and manually run the workflow. -- name: Get Wails - run: go install github.com/wailsapp/wails/v2/cmd/wails@latest - - name: Build Wails app - run: | - wails build - - name: upload artifacts macOS - if: matrix.platform == 'macos-latest' - uses: actions/upload-artifact@v2 +jobs: + package: + strategy: + matrix: + platform: [windows-latest, macos-latest] + go-version: [1.18] + runs-on: ${{ matrix.platform }} + steps: + - uses: actions/checkout@v2 + - name: Install Go + uses: actions/setup-go@v2 with: - name: wails-binaries-macos - path: build/bin/* - - name: upload artifacts windows - if: matrix.platform == 'windows-latest' - uses: actions/upload-artifact@v2 + go-version: ${{ matrix.go-version }} + - name: setup node + uses: actions/setup-node@v2 with: - name: wails-binaries-windows - path: build/bin/* + node-version: 14 + # You may need to manually build you frontend manually here, unless you have configured frontend build and install commands in wails.json. - name: Get Wails run: go install github.com/wailsapp/wails/v2/cmd/wails@latest - name: Build Wails app @@ -58,7 +59,7 @@ Next we need to give the GitHub workflow access to our signing certificate. This certutil -encode .\my-cert.p12 my-cert-base64.txt ``` -You should now have your .txt file with the base64 encoded certificate. Now you need to make two action secrets on GitHub. Now you need to make two action secrets on GitHub. Navigate to *Settings -> Secrets -> Actions* and create the two following secrets: +You should now have your .txt file with the base64 encoded certificate. It should start with _-----BEGIN CERTIFICATE-----_ and end with _-----END CERTIFICATE-----_. Now you need to make two action secrets on GitHub. Navigate to _Settings -> Secrets -> Actions_ and create the two following secrets: - **WIN_SIGNING_CERT** with the contents of your base64 encoded certificate text. - **WIN_SIGNING_CERT_PASSWORD** with the contents of your certificate password. diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/current/guides/troubleshooting.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/current/guides/troubleshooting.mdx index aa1da16a4..c5d62774b 100644 --- a/website/i18n/ja/docusaurus-plugin-content-docs/current/guides/troubleshooting.mdx +++ b/website/i18n/ja/docusaurus-plugin-content-docs/current/guides/troubleshooting.mdx @@ -2,9 +2,9 @@ An assortment of troubleshooting tips. -## The `wails` command appears to be missing? +## `wails`コマンドが見つからないのですが? -If your system is reporting that the `wails` command is missing, make sure you have followed the Go installation guide correctly. Normally, it means that the `go/bin` directory in your User's home directory is not in the `PATH` environment variable. You will also normally need to close and reopen any open command prompts so that changes to the environment made by the installer are reflected at the command prompt. +`wails`コマンドが見つからないとシステムに怒られた場合は、Goが、公式のGoインストール手順に従って導入されているかを確認してください。 コマンドが見つからないほとんどの理由は、あなたのホームディレクトリ配下にある`go/bin`ディレクトリのパスが、`PATH`環境変数に含まれていないからです。 また、インストールによって行われた環境変更を反映させるために、もともと開いていたコマンドプロンプト(ターミナル)がある場合はそれらをいったん閉じて、再度開きなおしてください。 ## My application is displaying a white/blank screen diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/current/guides/windows-installer.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/current/guides/windows-installer.mdx index b0b6e9e1f..88a1698db 100644 --- a/website/i18n/ja/docusaurus-plugin-content-docs/current/guides/windows-installer.mdx +++ b/website/i18n/ja/docusaurus-plugin-content-docs/current/guides/windows-installer.mdx @@ -24,7 +24,7 @@ If you use the chocolatey package manager, run the following script: choco install nsis ``` -If you install NSIS manually, you need to add the *Bin* folder, which contains `makensis.exe`, in your NSIS installation to your path. [Here](https://www.architectryan.com/2018/03/17/add-to-the-path-on-windows-10/) is a good tutorial on how to add to path on Windows. +If you install NSIS manually, you need to add the _Bin_ folder, which contains `makensis.exe`, in your NSIS installation to your path. [Here](https://www.architectryan.com/2018/03/17/add-to-the-path-on-windows-10/) is a good tutorial on how to add to path on Windows. ### Linux diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/current/howdoesitwork.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/current/howdoesitwork.mdx index a0bde09e6..11fe0ad9f 100644 --- a/website/i18n/ja/docusaurus-plugin-content-docs/current/howdoesitwork.mdx +++ b/website/i18n/ja/docusaurus-plugin-content-docs/current/howdoesitwork.mdx @@ -2,9 +2,9 @@ sidebar_position: 20 --- -# How does it work? +# どうやって動いているの? -A Wails application is a standard Go application, with a webkit frontend. The Go part of the application consists of the application code and a runtime library that provides a number of useful operations, like controlling the application window. The frontend is a webkit window that will display the frontend assets. Also available to the frontend is a Javascript version of the runtime library. Finally, it is possible to bind Go methods to the frontend, and these will appear as Javascript methods that can be called, just as if they were local Javascript methods. +Wailsは、webkitフロントエンドを備えた、何の変哲もないGoアプリです。 アプリ全体のうちGoの部分は、アプリのコードと、ウィンドウ制御などの便利な機能を提供するランタイムライブラリで構成されています。 フロントエンドはwebkitウィンドウであり、フロンドエンドアセットをウィンドウ上に表示します。 フロントエンドからも、Javascriptでランタイムライブラリを呼び出すことができます。 そして最終的に、Goのメソッドはフロントエンドにバインドされ、ローカルのJavascriptメソッドであるかのように、フロントエンドから呼び出すことができます。 ```mdx-code-block
@@ -12,11 +12,11 @@ A Wails application is a standard Go application, with a webkit frontend. The Go
``` -## The Main Application +## アプリのメインコード ### Overview -The main application consists of a single call to `wails.Run()`. It accepts the application configuration which describes the size of the application window, the window title, what assets to use, etc. A basic application might look like this: +アプリは、`wails.Run()`メソッドを1回呼び出すことで、構成することができます。 このメソッドで、アプリのウィンドウサイズやウィンドウタイトル、使用アセットなどを指定することができます。 基本的なアプリを作るコードは次のとおりです: ```go title="main.go" package main @@ -68,45 +68,45 @@ func (b *App) Greet(name string) string { } ``` -### Options rundown +### オプション -This example has the following options set: +上記のコードでは、次のオプションが指定されています: -- `Title` - The text that should appear in the window's title bar -- `Width` & `Height` - The dimensions of the window -- `Assets` - The application's frontend assets -- `OnStartup` - A callback for when the window is created and is about to start loading the frontend assets -- `OnShutdown` - A callback for when the application is about to quit -- `Bind` - A slice of struct instances that we wish to expose to the frontend +- `Title` - ウィンドウのタイトルバーに表示されるテキスト +- `Width` & `Height` - ウィンドウの大きさ +- `Assets` - アプリのフロントエンドアセット +- `OnStartup` - ウィンドウが作成され、フロントエンドの読み込みを開始しようとする時のコールバック +- `OnShutdown` - アプリを終了しようとするときのコールバック +- `Bind` - フロントエンドにバインドさせたい構造体インスタンスのスライス -A full list of application options can be found in the [Options Reference](reference/options). +設定可能なすべてのオプションについては、[オプションのリファレンス](reference/options)をご覧ください。 #### Assets -The `Assets` option is mandatory as you can't have a Wails application without frontend assets. Those assets can be any files you would expect to find in a web application - html, js, css, svg, png, etc. **There is no requirement to generate asset bundles** - plain files will do. When the application starts, it will attempt to load `index.html` from your assets and the frontend will essentially work as a browser from that point on. It is worth noting that there is no requirement on where in the `embed.FS` the files live. It is likely that the embed path uses a nested directory relative to your main application code, such as `frontend/dist`: +Wailsでフロントエンドアセット無しのアプリを作成することはできないため、`Assets`オプションは必須オプションです。 アセットには、一般的なWebアプリケーションでよく見かけるような、html、js、css、svg、pngなどのファイルを含めることができます。**アセットバンドルを生成する必要は一切なく**、そのままのファイルを使用できます。 アプリが起動すると、アセット内の`index.html`が読み込まれます。この時点で、フロントエンドはブラウザとして動作するようになります。 `embed.FS`を使ってアセットファイルが格納されたディレクトリを指定しますが、ディレクトリの場所はどこでも構いません。 embedで指定するパスは、`frontend/dist`のように、アプリのメインコードから相対的に見たディレクトリパスになります: ```go title="main.go" //go:embed all:frontend/dist var assets embed.FS ``` -At startup, Wails will iterate the embedded files looking for the directory containing `index.html`. All other assets will be loaded relative to this directory. +起動時に、Wailsは`index.html`が含まれるディレクトリを再帰的に探します。 他のすべてのアセットは、当該ディレクトリから相対的に読み込まれます。 -As production binaries use the files contained in `embed.FS`, there are no external files required to be shipped with the application. +本番用のバイナリファイルには、`embed.FS`で指定されたアセットファイルが含まれるため、アプリ配布時に、バイナリファイルとは別にアセットファイルを付加させる必要はありません。 -When running in development mode using the `wails dev` command, the assets are loaded off disk, and any changes result in a "live reload". The location of the assets will be inferred from the `embed.FS`. +`wails dev`コマンドを使って開発モードでアプリを起動した場合、アセットはディスクから読み込まれ、アセットファイルが更新されると、自動的にアプリがライブリロードされます。 アセットの場所は、`embed.FS`での指定値から推定されます。 -More details can be found in the [Application Development Guide](guides/application-development.mdx). +詳細は、[アプリ開発ガイド](guides/application-development.mdx)をご覧ください。 -#### Application Lifecycle Callbacks +#### アプリのライフサイクル -Just before the frontend is about to load `index.html`, a callback is made to the function provided in [OnStartup](reference/options.mdx#onstartup). A standard Go context is passed to this method. This context is required when calling the runtime so a standard pattern is to save a reference to in this method. Just before the application shuts down, the [OnShutdown](reference/options.mdx#onshutdown) callback is called in the same way, again with the context. There is also an [OnDomReady](reference/options.mdx#ondomready) callback for when the frontend has completed loading all assets in `index.html` and is equivalent of the [`body onload`](https://www.w3schools.com/jsref/event_onload.asp) event in Javascript. It is also possible to hook into the window close (or application quit) event by setting the option [OnBeforeClose](reference/options.mdx#onbeforeclose). +フロントエンドが`index.html`を読み込もうとする直前に、[OnStartup](reference/options.mdx#onstartup)で指定されたメソッドがコールバックされます。 A standard Go context is passed to this method. このメソッドに引数で渡されるContextは、今後、Wailsのラインタイムを呼び出すときに必要になるため、通常は、このContextへの参照を保持しておいてください。 同様に、アプリがシャットダウンされる直前には、[OnShutdown](reference/options.mdx#onshutdown)で指定されたコールバックが呼び出され、Contextも渡されます。 `index.html`に含まれるすべてのアセットが読み込み終わったときに呼び出される[OnDomReady](reference/options.mdx#ondomready)コールバックもあります。これは、Javascriptの[`body onload`](https://www.w3schools.com/jsref/event_onload.asp)イベントと同等のものです。 また、[OnBeforeClose](reference/options.mdx#onbeforeclose)を指定すると、ウィンドウを閉じる(またはアプリを終了する)イベントにフックさせることもできます。 -#### Method Binding +#### メソッドのバインド -The `Bind` option is one of the most important options in a Wails application. It specifies which struct methods to expose to the frontend. Think of structs like "controllers" in a traditional web application. When the application starts, it examines the struct instances listed in the `Bind` field in the options, determines which methods are public (starts with an uppercase letter) and will generate Javascript versions of those methods that can be called by the frontend code. +`Bind`オプションは、Wailsアプリで最も重要なオプションの1つです。 このオプションでは、フロントエンドに公開する、構造体のメソッドを指定することができます。 構造体は、従来のWebアプリにおける"コントローラ"の立ち位置であるとお考えください。 アプリが起動すると、`Bind`オプションで指定されている構造体を対象に、その中にあるパブリックメソッド(大文字で始まるメソッド名)を探します。そして、フロントエンドのコードからそれらのメソッドを呼び出せるJavascriptが生成されます。 -:::info Note +:::info 備考 Wailsで構造体を正しくバインドするためには、構造体の*インスタンス*をオプションで指定してください。 @@ -114,7 +114,7 @@ Wailsで構造体を正しくバインドするためには、構造体の*イ ::: -In this example, we create a new `App` instance and then add this instance to the `Bind` option in `wails.Run`: +下記のコードでは、新しく`App`インスタンスを作成し、`wails.Run`関数の`Bind`オプションの中で、そのインスタンスを追加しています: ```go {16,24} title="main.go" package main @@ -158,7 +158,7 @@ func (a *App) Greet(name string) string { } ``` -You may bind as many structs as you like. Just make sure you create an instance of it and pass it in `Bind`: +構造体は、好きな数だけバインドできます。 `Bind`には、構造体のインスタンスを渡すようにしてください: ```go {8-10} //... @@ -176,26 +176,26 @@ You may bind as many structs as you like. Just make sure you create an instance ``` -When you run `wails dev` (or `wails generate module`), a frontend module will be generated containing the following: +`wails dev`コマンド(または、`wails generate module`コマンド)を実行すると、以下のものを含むフロントエンドモジュールが生成されます: -- Javascript bindings for all bound methods -- Typescript declarations for all bound methods -- Typescript definitions for all Go structs used as inputs or outputs by the bound methods +- バインドされたすべてのメソッドのJavascript +- バインドされたすべてのメソッドのTypescript宣言 +- バインドされたメソッドの引数または返り値で使用されているGoの構造体のTypescript宣言 -This makes it incredibly simple to call Go code from the frontend, using the same strongly typed datastructures. +これにより、強力な型付けがなされたデータ構造を使用して、フロントエンドから簡単にGoのコードを呼び出すことができます。 -## The Frontend +## フロントエンド ### Overview -The frontend is a collection of files rendered by webkit. It's like a browser and webserver in one. There is virtually[^1] no limit to which frameworks or libraries you can use. The main points of interaction between the frontend and your Go code are: +フロントエンドは、webkitによってレンダリングされるファイル群です。 ブラウザとWebサーバが一体となったような動きをします。 使用できるフレームワークやライブラリの制限はほぼありません[^1]。 フロントエンドとGoコードとの相互のやり取りについて、主なポイントは次のとおりです: -- Calling bound Go methods -- Calling runtime methods +- バインドされたGoメソッドの呼び出し +- ランタイムメソッドの呼び出し -### Calling bound Go methods +### バインドされたGoメソッドの呼び出し -When you run your application with `wails dev`, it will automatically generate Javascript bindings for your structs in a directory called `wailsjs/go` (You can also do this by running `wails generate module`). The generated files mirror the package names in your application. In the example above, we bind `app`, which has one public method `Greet`. This will lead to the generation of the following files: +`wails dev`コマンドでアプリを起動すると、Go構造体のJavascriptバインディングが`wailsjs/go`ディレクトリに自動的に生成されます(`wails generate module`コマンドでも生成可能)。 生成されたファイルには、アプリ内のGoパッケージ名が反映されています。 先の例では、`Greet`というパブリックメソッドを持つ`app`をバインドしていました。 この場合、次のようなファイルが生成されることになります: ```bash wailsjs @@ -205,7 +205,7 @@ wailsjs └─App.js ``` -Here we can see that there is a `main` package that contains the Javascript bindings for the bound `App` struct, as well as the Typescript declaration file for those methods. To call `Greet` from our frontend, we simply import the method and call it like a regular Javascript function: +ご覧のとおり、`main`パッケージ内の`App`構造体Javascriptバインディングが、それらのメソッドのTypescript型定義と並んで生成されていることが分かります。 フロントエンドから`Greet`メソッドを呼び出すには、単純にメソッドをインポートし、通常のJavascript関数と同じように呼び出してください: ```javascript // ... @@ -218,29 +218,31 @@ import {Greet} from '../wailsjs/go/main/App' } ``` -The Typescript declaration file gives you the correct types for the bound methods: +Typescript型定義ファイルは、バインドされたメソッドの正しい型を提供します: ```ts export function Greet(arg1:string):Promise; ``` -The generated methods return a Promise. A successful call will result in the first return value from the Go call to be passed to the `resolve` handler. An unsuccessful call is when a Go method that has an error type as it's second return value, passes an error instance back to the caller. This is passed back via the `reject` handler. In the example above, `Greet` only returns a `string` so the Javascript call will never reject - unless invalid data is passed to it. +生成されたメソッドはPromiseを返すようになっています。 呼び出しが成功すると、Goからの1番目の返り値が`resolve`ハンドラに渡されます。 呼び出しに失敗したとみなされるのは、Goメソッドの2番目の返り値がerror型で、それがerrorインスタンスを返したときです。 これは、`reject`ハンドラを介して返されます。 先の例では、`Greet`メソッドは`string`型の返り値のみであるため、無効なデータが渡されない限り、Javascript側でrejectハンドラが呼ばれることはありません。 -All data types are correctly translated between Go and Javascript. Even structs. If you return a struct from a Go call, it will be returned to your frontend as a Javascript class. Note: If you wish to use structs, you **must** define `json` struct tags for your fields! +すべてのデータ型は、GoとJavascriptの間で正しく解釈されます。 もちろん構造体も正しく解釈されます。 Goから構造体が返された場合、フロントエンドにはJavascriptのクラスとして返されます。 -:::info Note +:::info 備考 +Struct fields *must* have a valid `json` tag to be included in the generated Typescript. + Anonymous nested structs are not supported at this time. ::: -It is possible to send structs back to Go. Any Javascript map/class passed as an argument that is expecting a struct, will be converted to that struct type. To make this process a lot easier, in `dev` mode, a TypeScript module is generated, defining all the struct types used in bound methods. Using this module, it's possible to construct and send native Javascript objects to the Go code. +Goに対して引数として構造体を渡すこともできます。 構造体として取り扱ってほしいJavascriptのマップやクラスを渡すと、構造体に変換されます。 あなたが簡単にこれらのことを把握できるように、`dev`モードでは、バウンドされたGoメソッドで使用されている全構造体の型が定義された、Typescriptモジュールが生成されます。 このモジュールを使用すると、Javascriptネイティブなオブジェクトを構築し、Goコードへ送信することができます。 -There is also support for Go methods that use structs in their signature. All Go structs specified by a bound method (either as parameters or return types) will have Typescript versions auto generated as part of the Go code wrapper module. Using these, it's possible to share the same data model between Go and Javascript. +There is also support for Go methods that use structs in their signature. バインドされたメソッドで、引数または返り値として指定されているすべてのGo構造体は、Goのコードラッパーモジュールの一部として生成されたTypescript定義を持っています。 これらを使用することで、GoとJavascriptの間で、同じデータモデルを共有できます。 -Example: We update our `Greet` method to accept a `Person` instead of a string: +例: `Greet`メソッドを更新して、文字列型の代わりに`Person`型を引数で受け付けてみる: ```go title="main.go" type Person struct { @@ -259,7 +261,7 @@ func (a *App) Greet(p Person) string { } ``` -The `wailsjs/go/main/App.js` file will still have the following code: +`wailsjs/go/main/App.js`ファイルには、次のコードが出力されます: ```js title="App.js" export function Greet(arg1) { @@ -267,98 +269,97 @@ export function Greet(arg1) { } ``` -But the `wailsjs/go/main/App.d.ts` file will be updated with the following code: +しかし、`wailsjs/go/main/App.d.ts`ファイルは次のコードが出力されます: ```ts title="App.d.ts" -import {main} from '../models'; +import { main } from "../models"; -export function Greet(arg1:main.Person):Promise; +export function Greet(arg1: main.Person): Promise; ``` -As we can see, the "main" namespace is imported from a new "models.ts" file. This file contains all the struct definitions used by our bound methods. In this example, this is a `Person` struct. If we look at `models.ts`, we can see how the models are defined: +見ると分かるように、"main"名前空間は、新しく生成された"models.ts"ファイルからインポートされています。 このファイルには、バインドされたメソッドで使用されるすべての構造体の型定義が含まれています。 この例では、`Person`構造体の型定義が含まれています。 `models.ts`を確認すれば、モデルがどのように定義されているかが分かります。 ```ts title="models.ts" export namespace main { + export class Address { + street: string; + postcode: string; - export class Address { - street: string; - postcode: string; - - static createFrom(source: any = {}) { - return new Address(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.street = source["street"]; - this.postcode = source["postcode"]; - } + static createFrom(source: any = {}) { + return new Address(source); } - export class Person { - name: string; - age: number; - address?: Address; - static createFrom(source: any = {}) { - return new Person(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.name = source["name"]; - this.age = source["age"]; - this.address = this.convertValues(source["address"], Address); - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } + constructor(source: any = {}) { + if ("string" === typeof source) source = JSON.parse(source); + this.street = source["street"]; + this.postcode = source["postcode"]; } + } + export class Person { + name: string; + age: number; + address?: Address; + + static createFrom(source: any = {}) { + return new Person(source); + } + + constructor(source: any = {}) { + if ("string" === typeof source) source = JSON.parse(source); + this.name = source["name"]; + this.age = source["age"]; + this.address = this.convertValues(source["address"], Address); + } + + convertValues(a: any, classs: any, asMap: boolean = false): any { + if (!a) { + return a; + } + if (a.slice) { + return (a as any[]).map((elem) => this.convertValues(elem, classs)); + } else if ("object" === typeof a) { + if (asMap) { + for (const key of Object.keys(a)) { + a[key] = new classs(a[key]); + } + return a; + } + return new classs(a); + } + return a; + } + } } ``` -So long as you have TypeScript as part of your frontend build configuration, you can use these models in the following way: +フロントエンドのビルド構成にTypescriptを使用している限り、これらのモデルを次のように使用できます: ```js title="mycode.js" -import {Greet} from '../wailsjs/go/main/App' - import {main} from '../wailsjs/go/models' +import { Greet } from "../wailsjs/go/main/App"; +import { main } from "../wailsjs/go/models"; - function generate() { - let person = new main.Person() - person.name = "Peter" - person.age = 27 - Greet(person).then((result) => { - console.log(result) - }) - } +function generate() { + let person = new main.Person(); + person.name = "Peter"; + person.age = 27; + Greet(person).then((result) => { + console.log(result); + }); +} ``` -The combination of generated bindings and TypeScript models makes for a powerful development environment. +生成されたバインディングとTypescriptモデルの組み合わせによって、強力な開発環境を実現させています。 -More information on Binding can be found in the [Binding Methods](guides/application-development.mdx#binding-methods) section of the [Application Development Guide](guides/application-development.mdx). +バインディングの詳細については、[アプリ開発ガイド](guides/application-development.mdx)の[バインディングメソッド](guides/application-development.mdx#binding-methods)をご覧ください。 -### Calling runtime methods +### ランタイムメソッドの呼び出し -The Javascript runtime is located at `window.runtime` and contains many methods to do various tasks such as emit an event or perform logging operations: +Javascriptランタイムは`window.runtime`に存在し、イベント発行やロギングなど、さまざまなタスクを実行するためのメソッドが含まれています: ```js title="mycode.js" window.runtime.EventsEmit("my-event", 1); ``` -More details about the JS runtime can be found in the [Runtime Reference](reference/runtime/intro). +Javascriptランタイムの詳細については、[ランタイムリファレンス](reference/runtime/intro)をご覧ください。 -[^1]: There is a very small subset of libraries that use features unsupported in WebViews. There are often alternatives and workarounds for such cases. +[^1]: まれに、WebViewでサポートされていない機能を使用するライブラリがあります。 ほとんどの場合、それらは代替手段や回避方法がありますので、それらを検討してください。 diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/current/introduction.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/current/introduction.mdx index 8e38bff21..c003052e8 100644 --- a/website/i18n/ja/docusaurus-plugin-content-docs/current/introduction.mdx +++ b/website/i18n/ja/docusaurus-plugin-content-docs/current/introduction.mdx @@ -2,26 +2,26 @@ sidebar_position: 1 --- -# Introduction +# イントロダクション -Wails is a project that enables you to write desktop apps using Go and web technologies. +Wailsは、Go言語とWeb技術を使用して、デスクトップアプリの構築を可能にするプロジェクトです。 -Consider it a lightweight and fast Electron alternative for Go. You can easily build applications with the flexibility and power of Go, combined with a rich, modern frontend. +"Goの力によって、Electronが軽量かつ高速になったようなもの"、と考えるとよいでしょう。 Goの柔軟性とパワーに、リッチでモダンなフロントエンドを組み合わせたアプリを、簡単に構築することができます。 -### Features +### 機能 -- Native Menus, Dialogs, Theming and Translucency -- Windows, macOS and linux support -- Built in templates for Svelte, React, Preact, Vue, Lit and Vanilla JS -- Easily call Go methods from Javascript -- Automatic Go struct to Typescript model generation -- No CGO or external DLLs required on Windows -- Live development mode using the power of [Vite](https://vitejs.dev/) -- Powerful CLI to easily Create, Build and Package applications -- A rich [runtime library](/docs/reference/runtime/intro) -- Applications built with Wails are Apple & Microsoft Store compliant +- ネイティブなメニュー、ダイアログ、テーマ、透過を使用できます +- Windows、macOS、Linuxをサポートしています +- Svelte、React、Preact、Vue、Lit、Vanilla JS向けのテンプレートを用意しています +- JavascriptからGoのメソッドを簡単に呼び出せます +- Go構造体からTypescriptの型を自動的に生成します +- Windowsでは、CGOや外部DLLを用意する必要はありません +- [Vite](https://vitejs.dev/)の力を利用したライブ開発が可能です +- 簡単にアプリを生成、ビルド、パッケージ化できる強力なCLIを用意しています +- 豊富な[ランタイムライブラリ](/docs/reference/runtime/intro)を用意しています +- Wailsで構築されたアプリケーションは、Apple StoreおよびMicrosoft Storeに準拠しています -This is [varly](https://varly.app) - a desktop application for MacOS & Windows written using Wails. Not only does it look great, it uses native menus and translucency - everything you'd expect from a modern native app. +例えば [varly](https://varly.app) は、Wailsで構築されたMacOS・Windows向けのデスクトップアプリです。 見栄えが良いだけではなく、ネイティブメニューや半透明効果を使用しています。これらは、モダンなネイティブアプリに期待されるものです。 ```mdx-code-block

@@ -34,42 +34,42 @@ This is [varly](https://varly.app) - a desktop application for MacOS & Windows w

``` -### Quick Start Templates +### クイックスタートテンプレート -Wails comes with a number of pre-configured templates that allow you to get your application up and running quickly. There are templates for the following frameworks: Svelte, React, Vue, Preact, Lit and Vanilla. There are both Javascript and Typescript versions for each template. +Wailsには、アプリの開発をすばやく始められるように、多数のテンプレートが用意されています。 Svelte、React、Vue、Preact、LitおよびVanilla用で、それぞれのテンプレートがあります。 各テンプレートには、Javascript版とTypescript版が用意されています。 -### Native Elements +### ネイティブ要素 -Wails uses a purpose built library for handling native elements such as Window, Menus, Dialogs, etc, so you can build good-looking, feature rich desktop applications. +Wailsは、ウィンドウ、メニュー、ダイアログなどのネイティブ要素を処理する専用ライブラリを使用するため、見栄えが良く、リッチな機能を備えたデスクトップアプリを構築できます。 -**It does not embed a browser**, so it is resource efficient. Instead, it uses the native rendering engine for the platform. On Windows, this is the new Microsoft Webview2 library, built on Chromium. +**ブラウザを埋め込まないため**、無駄なリソースを割きません。 ブラウザを埋め込まない代わりに、OSプラットフォームのネイティブなレンダリングエンジンを使用します。 例えばWindowsの場合、Chromium上でビルトされているMicrosoft Webview2ライブラリを使用します。 -### Go & Javascript Interoperability +### GoとJavascriptのやり取り -Wails automatically makes your Go methods available to Javascript, so you can call them by name from your frontend! It even generates Typescript models for the structs used by your Go methods, so you can pass the same data structures between Go and Javascript. +Wailsは自動的に、GoのメソッドをJavascriptから利用できるようにするので、フロントエンドからGoのメソッド名を呼び出すことができます。 It even generates Typescript models for the structs used by your Go methods, so you can pass the same data structures between Go and Javascript. -### Runtime Library +### ランタイムライブラリ -Wails provides a runtime library, for both Go and Javascript, that handles a lot of the things modern applications need, like Eventing, Logging, Dialogs, etc. +WailsはGoとJavascriptの両方にランタイムライブラリを提供し、イベント、ロギング、ダイアログなど、モダンなアプリに必要な多くの機能を使うことができます。 -### Live Development Experience +### ライブ開発 -#### Automatic Rebuilds +#### 自動リビルド -When you run your application in "dev" mode, Wails will build your application as a native desktop application, but will read your assets from disk. It will detect any changes to your Go code and automatically rebuild and relaunch your application. +アプリを"dev"モードで起動すると、Wailsはあなたが書いたコードをネイティブデスクトップアプリとしてビルドしますが、プログラムアセットは常にディスクから読み込む状態になります。 その仕組みにより、アプリ起動中にGoコードが書き換えられると、変更を検出して自動的にアプリがリビルドされ、再起動します。 -#### Automatic Reloads +#### 自動リロード -When changes to your application assets are detected, your running application will "reload", reflecting your changes almost immediately. +フロントエンドアセットの変更が検出された場合、起動中のアプリは自動的にリロードされ、変更がすぐに反映されます。 -#### Develop your application in a Browser +#### ブラウザを使った開発 -If you prefer to debug and develop in a browser then Wails has you covered. The running application also has a webserver that will run your application in any browser that connects to it. It will even refresh when your assets change on disk. +If you prefer to debug and develop in a browser then Wails has you covered. ブラウザでのデバッグや開発も、Wailsにお任せください。 起動中のアプリはWebサーバを兼ねており、お好きなブラウザから接続してアプリを操作することができます。 プログラムアセットが書き換わった時はすぐに更新されます。 -### Production-ready Native Binaries +### 本番用のネイティブバイナリ -When you're ready to do the final build of your application, the CLI will compile it down to a single executable, with all the assets bundled into it. On Windows and MacOS, it is possible to create a native package for distribution. The assets used in packaging (icon, info.plist, manifest file, etc) are part of your project and may be customised, giving you total control over how your applications are built. +アプリを本番用にビルドする準備ができたら、CLIが、アプリを単一の実行可能ファイルへコンパイルし、すべてのアセットをバンドルしてくれます。 WindowsおよびMacOSでは、配布用のネイティブパッケージを作成できます。 パッケージ化に必要なアイコン、info.plist、マニフェストファイルなどは、プロジェクトの一部としてカスタマイズできるため、アプリのビルド方法をフルコントロールできます。 -### Tooling +### ツール -The Wails CLI provides a hassle-free way to generate, build and bundle your applications. It will do the heavy lifting of creating icons, compiling your application with optimal settings and delivering a distributable, production ready binary. Choose from a number of starter templates to get up and running quickly! +Wails CLIを使うことで、簡単にアプリを生成、ビルド、バンドルすることができます。 アイコンの作成、最適なコンパイル構成の設定、本番向けのバイナリ配布など、面倒なことをあなたの代わりに引き受けてくれます。 多数のテンプレートの中から、あなたに合ったものを選んで、すぐに開発を始めましょう! diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/cli.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/cli.mdx index ecb25d43a..b0d0dbb5f 100644 --- a/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/cli.mdx +++ b/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/cli.mdx @@ -23,7 +23,7 @@ The Wails CLI has a number of commands that are used for managing your projects. | -ide | Generate IDE project files | | | -f | Force build application | false | -Example: `wails init -n test -d mytestproject -g -ide vscode -q` +例: `wails init -n test -d mytestproject -g -ide vscode -q` This will generate a a project called "test" in the "mytestproject" directory, initialise git, generate vscode project files and do so silently. @@ -33,7 +33,7 @@ More information on using IDEs with Wails can be found [here](../guides/ides.mdx Remote templates (hosted on GitHub) are supported and can be installed by using the template's project URL. -Example: `wails init -n test -t https://github.com/leaanthony/testtemplate[@v1.0.0]` +例: `wails init -n test -t https://github.com/leaanthony/testtemplate[@v1.0.0]` A list of community maintained templates can be found [here](../community/templates.mdx) @@ -61,7 +61,7 @@ If you are unsure about a template, inspect `package.json` and `wails.json` for | -o filename | Output filename | | | -s | Skip building the frontend | false | | -f | Force build application | false | -| -tags "extra tags" | Build tags to pass to Go compiler. Must be quoted. Space or comma (but not both) separated | | +| -tags "extra tags" | Goコンパイラに渡すビルドタグ。 値は引用符で囲んでください。 また、スペースまたはカンマで区切ってください(両方は使用しないでください)。 | | | -upx | Compress final binary using "upx" | | | -upxflags | Flags to pass to upx | | | -v int | Verbosity level (0 - silent, 1 - default, 2 - verbose) | 1 | @@ -71,8 +71,8 @@ If you are unsure about a template, inspect `package.json` and `wails.json` for | -trimpath | Remove all file system paths from the resulting executable. | false | | -race | Build with Go's race detector | false | | -windowsconsole | Keep the console window for Windows builds | | -| -obfuscate | Obfuscate the application using [garble](https://github.com/burrowers/garble) | false | -| -garbleargs | Arguments to pass to garble | `-literals -tiny -seed=random` | +| -obfuscate | [garble](https://github.com/burrowers/garble)を使用してアプリケーションを難読化する | false | +| -garbleargs | garbleへ渡す引数 | `-literals -tiny -seed=random` | For a detailed description of the `webview2` flag, please refer to the [Windows](../guides/windows.mdx) Guide. @@ -172,7 +172,7 @@ Your system is ready for Wails development! | -reloaddirs | Additional directories to trigger reloads (comma separated) | Value in `wails.json` | | -ldflags "flags" | Additional ldflags to pass to the compiler | | | -tags "extra tags" | Build tags to pass to compiler (quoted and space separated) | | -| -loglevel "loglevel" | Loglevel to use - Trace, Debug, Info, Warning, Error | Debug | +| -loglevel "loglevel" | Loglevel to use - Trace, Debug, Info, Warning, Error | デバッグ | | -noreload | Disable automatic reload when assets change | | | -nogen | Disable generate module | | | -v | Verbosity level (0 - silent, 1 - standard, 2 - verbose) | 1 | diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/menus.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/menus.mdx index a53759904..80ae91834 100644 --- a/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/menus.mdx +++ b/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/menus.mdx @@ -33,18 +33,13 @@ An example of how to create a menu: // ... ``` -```` It is also possible to dynamically update the menu, by updating the menu struct and calling \[MenuUpdateApplicationMenu\](../reference/runtime/menu.mdx#menuupdateapplicationmenu). +Menu構造体を更新し、[MenuUpdateApplicationMenu](../reference/runtime/menu.mdx#menuupdateapplicationmenu)メソッドを呼び出すことで、メニューを動的に更新することも可能です。 The example above uses helper methods, however it's possible to build the menu structs manually. ## Menu -A Menu is a collection of MenuItems: - -```go title="Package: github.com/wailsapp/wails/v2/pkg/menu" -## Menu - -A Menu is a collection of MenuItems: +Menuは、MenuItemのコレクションです。 ```go title="Package: github.com/wailsapp/wails/v2/pkg/menu" type Menu struct { @@ -126,7 +121,7 @@ Keys are any single character on a keyboard with the exception of `+`, which is Wails also supports parsing accelerators using the same syntax as Electron. This is useful for storing accelerators in config files. -Example: +例: ```go title="Package: github.com/wailsapp/wails/v2/pkg/menu/keys" // Defines cmd+o on Mac and ctrl-o on Window/Linux diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/options.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/options.mdx index 87f94aec5..dc21f8d1e 100644 --- a/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/options.mdx +++ b/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/options.mdx @@ -2,7 +2,7 @@ sidebar_position: 3 --- -# Options +# オプション ## Application Options @@ -101,93 +101,93 @@ func main() { The text shown in the window's title bar. -Name: Title
Type: `string` +名前: Title
データ型: `string` ### Width The initial width of the window. -Name: Width
Type: `int`
Default: 1024. +名前: Width
データ型: `int`
デフォルト値: 1024 ### Height The initial height of the window. -Name: Height
Type: `int`
Default: 768 +名前: Height
データ型: `int`
デフォルト値: 768 ### DisableResize By default, the main window is resizable. Setting this to `true` will keep it a fixed size. -Name: DisableResize
Type: `bool` +名前: DisableResize
データ型: `bool` ### Fullscreen Setting this to `true` will make the window fullscreen at startup. -Name: Fullscreen
Type: `bool` +名前: Fullscreen
データ型: `bool` ### Frameless When set to `true`, the window will have no borders or title bar. Also see [Frameless Windows](../guides/frameless.mdx). -Name: Frameless
Type: `bool` +名前: Frameless
データ型: `bool` ### MinWidth This sets the minimum width for the window. If the value given in `Width` is less than this value, the window will be set to `MinWidth` by default. -Name: MinWidth
Type: `int` +名前: MinWidth
データ型: `int` ### MinHeight This sets the minimum height for the window. If the value given in `Height` is less than this value, the window will be set to `MinHeight` by default. -Name: MinHeight
Type: `int` +名前: MinHeight
データ型: `int` ### MaxWidth This sets the maximum width for the window. If the value given in `Width` is more than this value, the window will be set to `MaxWidth` by default. -Name: MaxWidth
Type: `int` +名前: MaxWidth
データ型: `int` ### MaxHeight This sets the maximum height for the window. If the value given in `Height` is more than this value, the window will be set to `MaxHeight` by default. -Name: MaxHeight
Type: `int` +名前: MaxHeight
データ型: `int` ### StartHidden When set to `true`, the application will be hidden until [WindowShow](../reference/runtime/window.mdx#windowshow) is called. -Name: StartHidden
Type: `bool` +名前: StartHidden
データ型: `bool` ### HideWindowOnClose -By default, closing the window will close the application. Setting this to `true` means closing the window will hide the window instead. +By default, closing the window will close the application. この設定を`true`にすると、ウィンドウを閉じる操作をした際に、 -hide the window instead. +ウィンドウが非表示の状態になります。 -Name: HideWindowOnClose
Type: `bool` +名前: HideWindowOnClose
データ型: `bool` ### BackgroundColour -This value is the default background colour of the window. Default: white +This value is the default background colour of the window. 例: options.NewRGBA(255,0,0,128) - 50%透過された赤色 -Name: BackgroundColour
Type: `*options.RGBA`
Default: white +名前: BackgroundColour
データ型: `*options.RGBA`
デフォルト値: white ### AlwaysOnTop Indicates that the window should stay above other windows when losing focus. -Name: AlwaysOnTop
Type: `bool` +名前: AlwaysOnTop
データ型: `bool` ### Assets The frontend assets to be used by the application. Requires an `index.html` file. -Name: Assets
Type: `embed.FS` +名前: Assets
データ型: `embed.FS` ### AssetsHandler @@ -195,7 +195,7 @@ Name: Assets
Type: `embed.FS` The assets handler is a generic `http.Handler` which will be called for any non GET request on the assets server and for GET requests which can not be served from the `assets` because the file is not found. -| Value | Win | Mac | Lin | +| 値 | Win | Mac | Lin | | ----------------------- | --- | --- | --- | | GET | ✅ | ✅ | ✅ | | POST | ✅ | ✅ | ❌ | @@ -214,7 +214,7 @@ NOTE: Linux is currently very limited due to targeting a WebKit2GTK Version < 2. NOTE: When used in combination with a Frontend DevServer there might be limitations, eg. Vite serves the index.html on every path, that does not contain a file extension. -Name: AssetsHandler
Type: `http.Handler` +名前: AssetsHandler
データ型: `http.Handler` ### Menu @@ -223,48 +223,48 @@ The menu to be used by the application. More details about Menus in the [Menu Re :::note -On Mac, if no menu is specified, a default menu will be created. +Macでは、メニューが指定されていない場合、デフォルトメニューが作成されます。 ::: -Name: Menu
Type: `*menu.Menu` +名前: Menu
データ型: `*menu.Menu` ### Logger The logger to be used by the application. More details about logging in the [Log Reference](../reference/runtime/log.mdx). -Name: Logger
Type: `logger.Logger`
Default: Logs to Stdout +名前: Logger
データ型: `logger.Logger`
デフォルト値: 標準出力へのロガー ### LogLevel The default log level. More details about logging in the [Log Reference](../reference/runtime/log.mdx). -Name: LogLevel
Type: `logger.LogLevel`
Default: `Info` in dev mode, `Error` in production mode +名前: LogLevel
データ型: `logger.LogLevel`
デフォルト値: 開発モードの場合は`Info`、本番モードの場合は`Error` ### LogLevelProduction The default log level for production builds. More details about logging in the [Log Reference](../reference/runtime/log.mdx). -Name: LogLevelProduction
Type: `logger.LogLevel`
Default: `Error` +名前: LogLevelProduction
データ型: `logger.LogLevel`
デフォルト値: `Error` ### OnStartup This callback is called after the frontend has been created, but before `index.html` has been loaded. It is given the application context. -Name: OnStartup
Type: `func(ctx context.Context)` +名前: OnStartup
データ型: `func(ctx context.Context)` ### OnDomReady This callback is called after the frontend has loaded `index.html` and its resources. It is given the application context. -Name: OnDomReady
Type: `func(ctx context.Context)` +名前: OnDomReady
データ型: `func(ctx context.Context)` ### OnShutdown This callback is called after the frontend has been destroyed, just before the application terminates. It is given the application context. -Name: OnShutdown
Type: `func(ctx context.Context)` +名前: OnShutdown
データ型: `func(ctx context.Context)` ### OnBeforeClose @@ -287,99 +287,99 @@ func (b *App) beforeClose(ctx context.Context) (prevent bool) { } ``` -Name: OnBeforeClose
Type: `func(ctx context.Context) bool` +名前: OnBeforeClose
データ型: `func(ctx context.Context) bool` ### WindowStartState Defines how the window should present itself at startup. -| Value | Win | Mac | Lin | +| 値 | Win | Mac | Lin | | ---------- | --- | --- | --- | | Fullscreen | ✅ | ✅ | ✅ | | Maximised | ✅ | ✅ | ✅ | | Minimised | ✅ | ❌ | ✅ | -Name: WindowStartState
Type: `options.WindowStartState` +名前: WindowStartState
データ型: `options.WindowStartState` ### CSSDragProperty -Indicates the CSS property to use to identify which elements can be used to drag the window. Default: `--wails-draggable`. +ウィンドウをドラッグできる要素を特定するためのCSSプロパティ名を設定します。 デフォルト値: `--wails-draggable` -Name: CSSDragProperty
Type: `string` +名前: CSSDragProperty
データ型: `string` ### CSSDragValue -Indicates what value the `CSSDragProperty` style should have to drag the window. Default: `drag`. +Indicates what value the `CSSDragProperty` style should have to drag the window. デフォルト値: `drag` -Name: CSSDragValue
Type: `string` +名前: CSSDragValue
データ型: `string` ### Bind A slice of struct instances defining methods that need to be bound to the frontend. -Name: Bind
Type: `[]interface{}` +名前: Bind
データ型: `[]interface{}` ### Windows -This defines [Windows specific options](#windows). +[Windows固有のオプション](#windows)を定義します。 -Name: Windows
Type: `*windows.Options` +名前: Windows
データ型: `*windows.Options` #### WebviewIsTransparent Setting this to `true` will make the webview background transparent when an alpha value of `0` is used. This means that if you use `rgba(0,0,0,0)` for `background-color` in your CSS, the host window will show through. Often combined with [WindowIsTranslucent](#WindowIsTranslucent) to make frosty-looking applications. -Name: WebviewIsTransparent
Type: `bool` +名前: WebviewIsTransparent
データ型: `bool` #### WindowIsTranslucent -Setting this to `true` will make the window background translucent. Often combined with [WebviewIsTransparent](#WebviewIsTransparent). +Setting this to `true` will make the window background translucent. 多くの場合、[WebviewIsTransparent](#WebviewIsTransparent)と組み合わせて使用されます。 -For Windows 11 versions before build 22621, this will use the [BlurBehind](https://learn.microsoft.com/en-us/windows/win32/dwm/blur-ovw) method for translucency, which can be slow. For Windows 11 versions after build 22621, this will enable the newer translucency types that are much faster. By default, the type of translucency used will be determined by Windows. To configure this, use the [BackdropType](#BackdropType) option. +ビルド22621より前のWindows 11の場合、半透明を実現させるために[BlurBehind](https://learn.microsoft.com/ja-jp/windows/win32/dwm/blur-ovw)メソッドを使用するため、処理が遅くなる可能性があります。 ビルド22621以降のWindows 11では、より高速な、新しい半透明タイプが有効になります。 デフォルトで使用される半透明タイプは、Windowsにより決定されます。 このタイプを設定するには、[BackdropType](#BackdropType)オプションを使用してください。 -Name: WindowIsTranslucent
Type: `bool` +名前: WindowIsTranslucent
データ型: `bool` #### BackdropType :::note -Requires Windows 11 build 22621 or later. +この設定を適用するには、Windows 11 ビルド22621以降が必要です。 ::: -Sets the translucency type of the window. This is only applicable if [WindowIsTranslucent](#WindowIsTranslucent) is set to `true`. +ウィンドウの半透明タイプを設定します。 この設定は、[WindowIsTranslucent](#WindowIsTranslucent)が`true`に設定されている場合にのみ適用されます。 -Name: BackdropType
Type `windows.BackdropType` +名前: BackdropType
データ型: `windows.BackdropType` -The value can be one of the following: +値は次のいずれかを指定してください: -| Value | Description | -| ------- | ----------------------------------------------------------------------------------------- | -| Auto | Let Windows decide which backdrop to use | -| None | Do not use translucency | -| Acrylic | Use [Acrylic](https://learn.microsoft.com/en-us/windows/apps/design/style/acrylic) effect | -| Mica | Use [Mica](https://learn.microsoft.com/en-us/windows/apps/design/style/mica) effect | -| Tabbed | Use Tabbed. This is a backdrop that is similar to Mica. | +| 値 | Description | +| ------- | ----------------------------------------------------------------------------------- | +| Auto | Windowsに背景を決定させる | +| None | 半透明にしない | +| Acrylic | [アクリル](https://learn.microsoft.com/ja-jp/windows/apps/design/style/acrylic)の効果を使用する | +| Mica | [マイカ](https://learn.microsoft.com/ja-jp/windows/apps/design/style/mica)の効果を使用する | +| Tabbed | タブを使用する。 これはマイカに似ている背景です。 | #### DisableWindowIcon Setting this to `true` will remove the icon in the top left corner of the title bar. -Name: DisableWindowIcon
Type: `bool` +名前: DisableWindowIcon
データ型: `bool` #### DisableFramelessWindowDecorations Setting this to `true` will remove the window decorations in [Frameless](#Frameless) mode. This means there will be no 'Aero Shadow' and no 'Rounded Corners' shown for the window. Please note that 'Rounded Corners' are only supported on Windows 11. -Name: DisableFramelessWindowDecorations
Type: `bool` +名前: DisableFramelessWindowDecorations
データ型: `bool` #### WebviewUserDataPath This defines the path where the WebView2 stores the user data. If empty `%APPDATA%\[BinaryName.exe]` will be used. -Name: WebviewUserDataPath
Type: `string` +名前: WebviewUserDataPath
データ型: `string` #### WebviewBrowserPath @@ -391,7 +391,7 @@ Important information about distribution of fixed version runtime: - [Known issues for fixed version](https://docs.microsoft.com/en-us/microsoft-edge/webview2/concepts/distribution#known-issues-for-fixed-version) - [The path of fixed version of the WebView2 Runtime should not contain \Edge\Application\.](https://docs.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.1245.22#createcorewebview2environmentwithoptions) -Name: WebviewBrowserPath
Type: `string` +名前: WebviewBrowserPath
データ型: `string` #### Theme @@ -399,29 +399,29 @@ Minimum Windows Version: Windows 10 2004/20H1 This defines the theme that the application should use: -| Value | Description | -| ------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | -| SystemDefault | *Default*. The theme will be based on the system default. If the user changes their theme, the application will update to use the new setting | -| Dark | The application will use a dark theme exclusively | -| Light | The application will use a light theme exclusively | +| 値 | Description | +| ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | +| SystemDefault | _デフォルト値_です。 The theme will be based on the system default. If the user changes their theme, the application will update to use the new setting | +| Dark | The application will use a dark theme exclusively | +| Light | The application will use a light theme exclusively | -Name: Theme
Type: `windows.Theme` +名前: Theme
データ型: `windows.Theme` #### CustomTheme :::note -Minimum Windows Version: Windows 10/11 2009/21H2 Build 22000 +サポートされるWindowsの最小バージョン: Windows 10/11 2009/21H2 ビルド22000 ::: Allows you to specify custom colours for TitleBar, TitleText and Border for both light and dark mode, as well as when the window is active or inactive. -Name: CustomTheme
Type: `windows.CustomTheme` +名前: CustomTheme
データ型: `windows.CustomTheme` -##### CustomTheme type +##### CustomTheme 型 The CustomTheme struct uses `int32` to specify the colour values. These are in the standard(!) Windows format of: `0x00BBGGAA`. A helper function is provided to do RGB conversions into this format: `windows.RGB(r,g,b uint8)`. @@ -469,7 +469,7 @@ Example: A struct of strings used by the webview2 installer if a valid webview2 runtime is not found. -Name: Messages
Type: `*windows.Messages` +名前: Messages
データ型: `*windows.Messages` Customise this for any language you choose to support. @@ -477,31 +477,31 @@ Customise this for any language you choose to support. ResizeDebounceMS is the amount of time to debounce redraws of webview2 when resizing the window. The default value (0) will perform redraws as fast as it can. -Name: ResizeDebounceMS
Type: `uint16` +名前: ResizeDebounceMS
データ型: `uint16` #### OnSuspend -If set, this function will be called when Windows initiates a switch to low power mode (suspend/hibernate) +Windowsがローパワーモード(サスペンド/休止状態) に切り替わると呼び出されるコールバックを設定します。 -Name: OnSuspend
Type: `func()` +名前: OnSuspend
データ型: `func()` #### OnResume -If set, this function will be called when Windows resumes from low power mode (suspend/hibernate) +Windowsがローパワーモード(サスペンド/休止状態) から復帰したときに呼び出されるコールバックを設定します。 -Name: OnResume
Type: `func()` +名前: OnResume
データ型: `func()` ### Mac -This defines [Mac specific options](#mac). +[Mac固有のオプション](#mac)を定義します。 -Name: Mac
Type: `*mac.Options` +名前: Mac
データ定義: `*mac.Options` #### TitleBar The TitleBar struct provides the ability to configure the look and feel of the title bar. -Name: TitleBar
Type: [`*mac.TitleBar`](#titlebar-struct) +名前: TitleBar
データ型: [`*mac.TitleBar`](#titlebar-struct) ##### Titlebar struct @@ -549,13 +549,13 @@ Click [here](https://github.com/lukakerr/NSWindowStyles) for some inspiration on Appearance is used to set the style of your app in accordance with Apple's [NSAppearance](https://developer.apple.com/documentation/appkit/nsappearancename?language=objc) names. -Name: Appearance
Type: [`mac.AppearanceType`](#appearance-type) +名前: Appearance
データ型: [`mac.AppearanceType`](#appearance-type) -##### Appearance type +##### Appearance 型 You can specify the application's [appearance](https://developer.apple.com/documentation/appkit/nsappearance?language=objc). -| Value | Description | +| 値 | Description | | ----------------------------------------------------- | --------------------------------------------------------------- | | DefaultAppearance | DefaultAppearance uses the default system value | | NSAppearanceNameAqua | The standard light system appearance | @@ -578,19 +578,19 @@ Mac: &mac.Options{ Setting this to `true` will make the webview background transparent when an alpha value of `0` is used. This means that if you use `rgba(0,0,0,0)` for `background-color` in your CSS, the host window will show through. Often combined with [WindowIsTranslucent](#WindowIsTranslucent) to make frosty-looking applications. -Name: WebviewIsTransparent
Type: `bool` +名前: WebviewIsTransparent
データ型: `bool` #### WindowIsTranslucent Setting this to `true` will make the window background translucent. Often combined with [WebviewIsTransparent](#WebviewIsTransparent) to make frosty-looking applications. -Name: WindowIsTranslucent
Type: `bool` +名前: WindowIsTranslucent
データ型: `bool` #### About This configuration lets you set the title, message and icon for the "About" menu item in the app menu created by the "AppMenu" role. -Name: About
Type: [`*mac.AboutInfo`](#about-struct) +名前: About
データ型: [`*mac.AboutInfo`](#about-struct) ##### About struct @@ -649,15 +649,15 @@ When clicked, that will open an about message box: ### Linux -This defines [Linux specific options](#linux). +[Linux固有のオプション](#linux)を定義します。 -Name: Linux
Type: `*linux.Options` +名前: Linux
データ型: `*linux.Options` #### Icon Sets up the icon representing the window. This icon is used when the window is minimized (also known as iconified). -Name: Icon
Type: `[]byte` +名前: Icon
データ型: `[]byte` Some window managers or desktop environments may also place it in the window frame, or display it in other contexts. On others, the icon is not used at all, so your mileage may vary. diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/runtime/browser.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/runtime/browser.mdx index c71ec4a3a..39ae7e0a9 100644 --- a/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/runtime/browser.mdx +++ b/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/runtime/browser.mdx @@ -4,10 +4,10 @@ sidebar_position: 7 # Browser -These methods are related to the system browser. +これらは、システムブラウザに関連したメソッドです。 ### BrowserOpenURL -Opens the given URL in the system browser. +指定されたURLをシステムブラウザで開きます。 Go: `BrowserOpenURL(ctx context.Context, url string)`
JS: `BrowserOpenURL(url string)` diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/runtime/dialog.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/runtime/dialog.mdx index d2aa9ab6a..28c91d225 100644 --- a/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/runtime/dialog.mdx +++ b/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/runtime/dialog.mdx @@ -2,59 +2,59 @@ sidebar_position: 5 --- -# Dialog +# ダイアログ -This part of the runtime provides access to native dialogs, such as File Selectors and Message boxes. +ランタイムでは、ファイルセレクターやメッセージボックスといったネイティブダイアログへのアクセスを提供しています。 :::info Javascript -Dialog is currently unsupported in the JS runtime. +現在、Javascriptランタイムではダイアログをサポートしていません。 ::: ### OpenDirectoryDialog -Opens a dialog that prompts the user to select a directory. Can be customised using [OpenDialogOptions](#opendialogoptions). +ユーザにディレクトリの選択を求めるダイアログを開きます。 [OpenDialogOptions](#opendialogoptions)を使用してカスタマイズできます。 Go: `OpenDirectoryDialog(ctx context.Context, dialogOptions OpenDialogOptions) (string, error)` -Returns: Selected directory (blank if the user cancelled) or an error +返り値: 選択されたディレクトリ(キャンセルされた場合は空) またはエラー ### OpenFileDialog -Opens a dialog that prompts the user to select a file. Can be customised using [OpenDialogOptions](#opendialogoptions). +ユーザにファイルの選択を求めるダイアログを開きます。 [OpenDialogOptions](#opendialogoptions)を使用してカスタマイズできます。 Go: `OpenFileDialog(ctx context.Context, dialogOptions OpenDialogOptions) (string, error)` -Returns: Selected file (blank if the user cancelled) or an error +返り値: 選択されたファイル(キャンセルされた場合は空) またはエラー ### OpenMultipleFilesDialog -Opens a dialog that prompts the user to select multiple files. Can be customised using [OpenDialogOptions](#opendialogoptions). +ユーザに複数ファイルの選択を求めるダイアログを開きます。 [OpenDialogOptions](#opendialogoptions)を使用してカスタマイズできます。 Go: `OpenMultipleFilesDialog(ctx context.Context, dialogOptions OpenDialogOptions) ([]string, error)` -Returns: Selected files (nil if the user cancelled) or an error +返り値: 選択された複数ファイル(キャンセルされた場合はnil) またはエラー ### SaveFileDialog -Opens a dialog that prompts the user to select a filename for the purposes of saving. Can be customised using [SaveDialogOptions](#savedialogoptions). +保存の目的でユーザにファイル名を入力選択させるダイアログを開きます。 [SaveDialogOptions](#savedialogoptions)を使用してカスタマイズできます。 Go: `SaveFileDialog(ctx context.Context, dialogOptions SaveDialogOptions) (string, error)` -Returns: The selected file (blank if the user cancelled) or an error +返り値: 入力選択されたファイル(キャンセルされた場合は空) またはエラー ### MessageDialog -Displays a message using a message dialog. Can be customised using [MessageDialogOptions](#messagedialogoptions). +メッセージダイアログを使用してメッセージを表示します。 [MessageDialogOptions](#messagedialogoptions)を使用してカスタマイズできます。 Go: `MessageDialog(ctx context.Context, dialogOptions MessageDialogOptions) (string, error)` -Returns: The text of the selected button or an error +返り値: 選択されたボタンのテキストまたはエラー -## Options +## オプション ### OpenDialogOptions @@ -71,16 +71,16 @@ type OpenDialogOptions struct { } ``` -| Field | Description | Win | Mac | Lin | -| -------------------------- | ---------------------------------------------- | --- | --- | --- | -| DefaultDirectory | The directory the dialog will show when opened | ✅ | ✅ | ✅ | -| DefaultFilename | The default filename | ✅ | ✅ | ✅ | -| Title | Title for the dialog | ✅ | ✅ | ✅ | -| [Filters](#filefilter) | A list of file filters | ✅ | ✅ | ✅ | -| ShowHiddenFiles | Show files hidden by the system | | ✅ | ✅ | -| CanCreateDirectories | Allow user to create directories | | ✅ | | -| ResolvesAliases | If true, returns the file not the alias | | ✅ | | -| TreatPackagesAsDirectories | Allow navigating into packages | | ✅ | | +| Field | Description | Win | Mac | Lin | +| -------------------------- | ------------------------- | --- | --- | --- | +| DefaultDirectory | ダイアログが開かれたときに初期表示するディレクトリ | ✅ | ✅ | ✅ | +| DefaultFilename | デフォルトファイル名 | ✅ | ✅ | ✅ | +| Title | ダイアログのタイトル | ✅ | ✅ | ✅ | +| [Filters](#filefilter) | ファイルフィルタのリスト | ✅ | ✅ | ✅ | +| ShowHiddenFiles | システムの隠しファイルを表示 | | ✅ | ✅ | +| CanCreateDirectories | ユーザによるディレクトリの作成を許可する | | ✅ | | +| ResolvesAliases | エイリアスではなくファイルパスを返す | | ✅ | | +| TreatPackagesAsDirectories | パッケージへのナビゲーションを許可 | | ✅ | | ### SaveDialogOptions @@ -96,15 +96,15 @@ type SaveDialogOptions struct { } ``` -| Field | Description | Win | Mac | Lin | -| -------------------------- | ---------------------------------------------- | --- | --- | --- | -| DefaultDirectory | The directory the dialog will show when opened | ✅ | ✅ | ✅ | -| DefaultFilename | The default filename | ✅ | ✅ | ✅ | -| Title | Title for the dialog | ✅ | ✅ | ✅ | -| [Filters](#filefilter) | A list of file filters | ✅ | ✅ | ✅ | -| ShowHiddenFiles | Show files hidden by the system | | ✅ | ✅ | -| CanCreateDirectories | Allow user to create directories | | ✅ | | -| TreatPackagesAsDirectories | Allow navigating into packages | | ✅ | | +| Field | Description | Win | Mac | Lin | +| -------------------------- | ------------------------- | --- | --- | --- | +| DefaultDirectory | ダイアログが開かれたときに初期表示するディレクトリ | ✅ | ✅ | ✅ | +| DefaultFilename | デフォルトファイル名 | ✅ | ✅ | ✅ | +| Title | ダイアログのタイトル | ✅ | ✅ | ✅ | +| [Filters](#filefilter) | ファイルフィルタのリスト | ✅ | ✅ | ✅ | +| ShowHiddenFiles | システムの隠しファイルを表示 | | ✅ | ✅ | +| CanCreateDirectories | ユーザによるディレクトリの作成を許可する | | ✅ | | +| TreatPackagesAsDirectories | パッケージへのナビゲーションを許可 | | ✅ | | ### MessageDialogOptions @@ -119,18 +119,30 @@ type MessageDialogOptions struct { } ``` -| Field | Description | Win | Mac | Lin | -| ------------- | ------------------------------------------------------------------------- | --- | --- | --- | -| Type | The type of message dialog, eg question, info... | ✅ | ✅ | ✅ | -| Title | Title for the dialog | ✅ | ✅ | ✅ | -| Message | The message to show the user | ✅ | ✅ | ✅ | -| Buttons | A list of button titles | | ✅ | | -| DefaultButton | The button with this text should be treated as default. Bound to `return` | | ✅ | | -| CancelButton | The button with this text should be treated as cancel. Bound to `escape` | | ✅ | | +| Field | Description | Win | Mac | Lin | +| ------------- | ------------------------------------------------- | -------------- | --- | --- | +| Type | メッセージダイアログの種類 (質問、情報など) | ✅ | ✅ | ✅ | +| Title | ダイアログのタイトル | ✅ | ✅ | ✅ | +| Message | ユーザに表示するメッセージ | ✅ | ✅ | ✅ | +| Buttons | ボタンテキストのリスト | | ✅ | | +| DefaultButton | 指定されたテキストのボタンをデフォルトボタンとして扱う。 Bound to `return`. | ✅[*](#windows) | ✅ | | +| CancelButton | 指定されたテキストのボタンをキャンセルボタンとして扱う。 `escape`キーにバインドされます。 | | ✅ | | #### Windows -Windows has standard dialog types in which the buttons are not customisable. The value returned will be one of: "Ok", "Cancel", "Abort", "Retry", "Ignore", "Yes", "No", "Try Again" or "Continue" +Windowsでは、ボタンのカスタマイズができない標準ダイアログタイプがあります。 The value returned will be one of: "Ok", "Cancel", "Abort", "Retry", "Ignore", "Yes", "No", "Try Again" or "Continue". + +For Question dialogs, the default button is "Yes" and the cancel button is "No". This can be changed by setting the `DefaultButton` value to `"No"`. + +Example: +```go + result, err := runtime.MessageDialog(a.ctx, runtime.MessageDialogOptions{ + Type: runtime.QuestionDialog, + Title: "Question", + Message: "Do you want to continue?", + DefaultButton: "No", + }) +``` #### Linux @@ -150,7 +162,7 @@ selection, err := runtime.MessageDialog(b.ctx, runtime.MessageDialogOptions{ }) ``` -the first button is shown as default: +1番目のボタンがデフォルトになります: ```mdx-code-block
diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/runtime/events.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/runtime/events.mdx index 48d27f996..48893b0b7 100644 --- a/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/runtime/events.mdx +++ b/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/runtime/events.mdx @@ -2,13 +2,13 @@ sidebar_position: 2 --- -# Events +# イベント -The Wails runtime provides a unified events system, where events can be emitted or received by either Go or Javascript. Optionally, data may be passed with the events. Listeners will receive the data in the local data types. +Wailsでは、GoまたはJavascriptによって発行および受信できる、一元化されたイベントシステムが用意されています。 必要に応じて、イベント発行時にデータを渡すことも可能です。 イベントリスナーは、そのデータをローカルデータ型で受け取ります。 ### EventsOn -This method sets up a listener for the given event name. When an event of type `eventName` is [emitted](#EventsEmit), the callback is triggered. Any additional data sent with the emitted event will be passed to the callback. +このメソッドは、指定されたイベント名のイベントリスナーを新たに設定します。 `eventName`という名前のイベントが[発行](#EventsEmit)されると、コールバックがトリガーされます。 イベント発行時にデータも付与されていた場合、そのデータはコールバックに渡されます。 Go: `EventsOn(ctx context.Context, eventName string, callback func(optionalData ...interface{}))`
JS: `EventsOn(eventName string, callback function(optionalData?: any))` @@ -20,18 +20,18 @@ Go: `EventsOff(ctx context.Context, eventName string, additionalEventNames ...st ### EventsOnce -This method sets up a listener for the given event name, but will only trigger once. +このメソッドは、指定されたイベント名のイベントリスナーを新たに設定し、一度だけトリガーさせます。 Go: `EventsOnce(ctx context.Context, eventName string, callback func(optionalData ...interface{}))`
JS: `EventsOnce(eventName string, callback function(optionalData?: any))` ### EventsOnMultiple -This method sets up a listener for the given event name, but will only trigger a maximum of `counter` times. +このメソッドは、指定されたイベント名のイベントリスナーを新たに設定し、最大`counter`回だけトリガーします。 Go: `EventsOnMultiple(ctx context.Context, eventName string, callback func(optionalData ...interface{}), counter int)`
JS: `EventsOnMultiple(eventName string, callback function(optionalData?: any), counter int)` ### EventsEmit -This method emits the given event. Optional data may be passed with the event. This will trigger any event listeners. +このメソッドは、指定されたイベントを発行します。 必要に応じて、イベント発行時にデータを渡すこともできます。 このメソッドによって、任意のイベントリスナーをトリガーさせることができます。 Go: `EventsEmit(ctx context.Context, eventName string, optionalData ...interface{})`
JS: `EventsEmit(ctx context, optionalData function(optionalData?: any))` diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/runtime/intro.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/runtime/intro.mdx index 9cbe28096..855981f03 100644 --- a/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/runtime/intro.mdx +++ b/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/runtime/intro.mdx @@ -2,68 +2,68 @@ sidebar_position: 1 --- -# Introduction +# イントロダクション -The runtime is a library that provides utility methods for your application. There is both a Go and Javascript runtime and the aim is to try and keep them at parity where possible. +ランタイムは、アプリケーションにユーティリティメソッドを提供するライブラリです。 GoとJavascriptの両方にランタイムがあり、どちらにもほぼ同じメソッドが提供されています。 ユーティリティメソッドには次のようなものがあります: -- [Window](window.mdx) +- [ウィンドウ](window.mdx) - [Menu](menu.mdx) -- [Dialog](dialog.mdx) -- [Events](events.mdx) +- [ダイアログ](dialog.mdx) +- [イベント](events.mdx) - [Browser](browser.mdx) -- [Log](log.mdx) +- [ログ](log.mdx) -The Go Runtime is available through importing `github.com/wailsapp/wails/v2/pkg/runtime`. All methods in this package take a context as the first parameter. This context should be obtained from the [OnStartup](../options.mdx#onstartup) or [OnDomReady](../options.mdx#ondomready) hooks. +Goのランタイムは、`github.com/wailsapp/wails/v2/pkg/runtime`をインポートすることで利用できます。 このパッケージのすべてのメソッドは、1番目の引数でContextを渡す必要があります。 このContextは、[OnStartup](../options.mdx#onstartup)フック、または[OnDomReady](../options.mdx#ondomready)フックからあらかじめ取得しておいてください。 -:::info Note +:::info 備考 -Whilst the context will be provided to the [OnStartup](../options.mdx#onstartup) method, there's no guarantee the runtime will work in this method as the window is initialising in a different thread. If you wish to call runtime methods at startup, use [OnDomReady](../options.mdx#ondomready). +[OnStartup](../options.mdx#onstartup)で提供されるContextは、ウィンドウが別のスレッドで初期化されているため、ランタイムが機能する保証がありません。 起動時にランタイムメソッドを呼び出したい場合は、[OnDomReady](../options.mdx#ondomready)を使用してください。 ::: -The Javascript library is available to the frontend via the `window.runtime` map. There is a runtime package generated when using `dev` mode that provides Typescript declarations for the runtime. This should be located in the `wailsjs` directory in your frontend directory. +Javascriptのランタイムは、`window.runtime`マップを介してフロントエンド上で利用できます。 `dev`モードでは、Typescript型定義を提供するランタイムパッケージが生成されます。 これらは、フロントエンドディレクトリの`wailsjs`ディレクトリに配置しておく必要があります。 -### Hide +### 非表示 Go: `Hide(ctx context.Context)`
JS: `Hide()` -Hides the application. +アプリケーションを非表示にします。 -:::info Note +:::info 備考 -Macでこのメソッドを使用すると、標準のMacアプリケーションにおけるメニュー項目の`Hide`と同じ方法で、アプリケーションが非表示になります。 This is different to hiding the window, but the application still being in the foreground. For Windows and Linux, this is currently the same as `WindowHide`. +Macでこのメソッドを使用すると、標準のMacアプリケーションにおけるメニュー項目の`Hide`と同じ方法で、アプリケーションが非表示になります。 これはウィンドウの非表示とは異なりますが、アプリケーションはフォアグラウンドに残ったままになります。 WindowsおよびLinuxでは、`WindowHide`メソッドと同等です。 ::: -### Show +### 表示 -Shows the application. +アプリケーションを表示します。 -:::info Note +:::info 備考 -Macでこのメソッドを使用すると、アプリケーションがフォアグラウンドに戻ります。 For Windows and Linux, this is currently the same as `WindowShow`. +Macでこのメソッドを使用すると、アプリケーションがフォアグラウンドに戻ります。 WindowsおよびLinuxでは、`WindowShow`メソッドと同等です。 ::: Go: `Show(ctx context.Context)`
JS: `Show()` -### Quit +### 終了 -Quits the application. +アプリケーションを終了します。 Go: `Quit(ctx context.Context)`
JS: `Quit()` -### Environment +### 環境 -Returns details of the current environment. +現在の環境の詳細情報を取得します。 Go: `Environment(ctx context.Context) EnvironmentInfo`
JS: `Environment(): Promise` diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/runtime/log.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/runtime/log.mdx index e5e6ea7ac..057aa802a 100644 --- a/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/runtime/log.mdx +++ b/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/runtime/log.mdx @@ -2,120 +2,120 @@ sidebar_position: 3 --- -# Log +# ログ -The Wails runtime provides a logging mechanism that may be called from Go or Javascript. Like most loggers, there are a number of log levels: +Wailsでは、GoまたはJavascriptから呼び出すことのできるロギングメカニズムを用意しています。 一般的なロガーと同じように、ログにはいくつかのログレベルがあります: -- Trace -- Debug -- Info -- Warning +- トレース +- デバッグ +- 情報 +- 警告 - Error -- Fatal +- 致命的 -The logger will output any log message at the current, or higher, log level. Example: The `Debug` log level will output all messages except `Trace` messages. +ロガーは、設定されている出力ログレベル以上のログメッセージを出力します。 例えば、出力ログレベルを`Debug`に設定した場合、`Trace`以外のすべてのレベルのメッセージが出力されます。 ### LogPrint -Logs the given message as a raw message. +指定されたメッセージをRawメッセージとしてロギングします。 Go: `LogPrint(ctx context.Context, message string)`
JS: `LogPrint(message: string)` ### LogPrintf -Logs the given message as a raw message. +指定されたメッセージをRawメッセージとしてロギングします。 Go: `LogPrintf(ctx context.Context, format string, args ...interface{})`
### LogTrace -Logs the given message at the `Trace` log level. +指定されたメッセージを`Trace`ログレベルでロギングします。 Go: `LogTrace(ctx context.Context, message string)`
JS: `LogTrace(message: string)` ### LogTracef -Logs the given message at the `Trace` log level. +指定されたメッセージを`Trace`ログレベルでロギングします。 Go: `LogTracef(ctx context.Context, format string, args ...interface{})`
### LogDebug -Logs the given message at the `Debug` log level. +指定されたメッセージを`Debug`ログレベルでロギングします。 Go: `LogDebug(ctx context.Context, message string)`
JS: `LogDebug(message: string)` ### LogDebugf -Logs the given message at the `Debug` log level. +指定されたメッセージを`Debug`ログレベルでロギングします。 Go: `LogDebugf(ctx context.Context, format string, args ...interface{})`
### LogInfo -Logs the given message at the `Info` log level. +指定されたメッセージを`Info`ログレベルでロギングします。 Go: `LogInfo(ctx context.Context, message string)`
JS: `LogInfo(message: string)` ### LogInfof -Logs the given message at the `Info` log level. +指定されたメッセージを`Info`ログレベルでロギングします。 Go: `LogInfof(ctx context.Context, format string, args ...interface{})`
### LogWarning -Logs the given message at the `Warning` log level. +指定されたメッセージを`Warning`ログレベルでロギングします。 Go: `LogWarning(ctx context.Context, message string)`
JS: `LogWarning(message: string)` ### LogWarningf -Logs the given message at the `Warning` log level. +指定されたメッセージを`Warning`ログレベルでロギングします。 Go: `LogWarningf(ctx context.Context, format string, args ...interface{})`
### LogError -Logs the given message at the `Error` log level. +指定されたメッセージを`Error`ログレベルでロギングします。 Go: `LogError(ctx context.Context, message string)`
JS: `LogError(message: string)` ### LogErrorf -Logs the given message at the `Error` log level. +指定されたメッセージを`Error`ログレベルでロギングします。 Go: `LogErrorf(ctx context.Context, format string, args ...interface{})`
### LogFatal -Logs the given message at the `Fatal` log level. +指定されたメッセージを`Fatal`ログレベルでロギングします。 Go: `LogFatal(ctx context.Context, message string)`
JS: `LogFatal(message: string)` ### LogFatalf -Logs the given message at the `Fatal` log level. +指定されたメッセージを`Fatal`ログレベルでロギングします。 Go: `LogFatalf(ctx context.Context, format string, args ...interface{})`
### LogSetLogLevel -Sets the log level. In Javascript, the number relates to the following log levels: +出力ログレベルを設定します。 Javascriptでは、数値が次のログレベルに対応しています: -| Value | Log Level | -| ----- | --------- | -| 1 | Trace | -| 2 | Debug | -| 3 | Info | -| 4 | Warning | -| 5 | Error | +| 値 | ログレベル | +| - | ----- | +| 1 | トレース | +| 2 | デバッグ | +| 3 | 情報 | +| 4 | 警告 | +| 5 | Error | Go: `LogSetLogLevel(ctx context.Context, level logger.LogLevel)`
JS: `LogSetLogLevel(level: number)` -## Using a Custom Logger +## カスタムロガーの使用 -A custom logger may be used by providing it using the [Logger](../options.mdx#logger) application option. The only requirement is that the logger implements the `logger.Logger` interface defined in `github.com/wailsapp/wails/v2/pkg/logger`: +カスタムロガーは、アプリケーションオプションの1つである[Logger](../options.mdx#logger)で指定してあげることで、使用することができます。 カスタムロガーを使用する際の唯一の要件は、`github.com/wailsapp/wails/v2/pkg/logger`で定義されている`logger.Logger`インターフェースを、ロガーに実装することです: ```go title="logger.go" type Logger interface { diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/runtime/menu.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/runtime/menu.mdx index 68feb7a3f..0d2b40a7d 100644 --- a/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/runtime/menu.mdx +++ b/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/runtime/menu.mdx @@ -4,24 +4,24 @@ sidebar_position: 6 # Menu -These methods are related to the application menu. +これらは、アプリケーションメニューに関連したメソッドです。 :::info Javascript -Menu is currently unsupported in the JS runtime. +現在、Javascriptランタイムではメニューをサポートしていません。 ::: ### MenuSetApplicationMenu -Sets the application menu to the given [menu](../menus.mdx). +指定された[menu](../menus.mdx)をアプリケーションメニューとして設定します。 Go: `MenuSetApplicationMenu(ctx context.Context, menu *menu.Menu)` ### MenuUpdateApplicationMenu -Updates the application menu, picking up any changes to the menu passed to `MenuSetApplicationMenu`. +`MenuSetApplicationMenu`に渡されたメニューへの変更を検知し、アプリケーションメニューを更新します。 Go: `MenuUpdateApplicationMenu(ctx context.Context)` diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/runtime/window.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/runtime/window.mdx index 6bc4099cb..090be184a 100644 --- a/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/runtime/window.mdx +++ b/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/runtime/window.mdx @@ -2,199 +2,199 @@ sidebar_position: 4 --- -# Window +# ウィンドウ -These methods give control of the application window. +アプリケーションウィンドウを制御できるメソッド群です。 ### WindowSetTitle -Sets the text in the window title bar. +ウィンドウのタイトルバーにテキストを設定します。 Go: `WindowSetTitle(ctx context.Context, title string)`
JS: `WindowSetTitle(title: string)` ### WindowFullscreen -Makes the window full screen. +ウィンドウをフルスクリーンにします。 Go: `WindowFullscreen(ctx context.Context)`
JS: `WindowFullscreen()` ### WindowUnfullscreen -Restores the previous window dimensions and position prior to full screen. +フルスクリーンにする前のウィンドウサイズおよび位置に戻します。 Go: `WindowUnfullscreen(ctx context.Context)`
JS: `WindowUnfullscreen()` ### WindowIsFullscreen -Returns true if the window is full screen. +ウィンドウがフルスクリーンの場合は、trueを返します。 Go: `WindowIsFullscreen(ctx context.Context) bool`
JS: `WindowIsFullscreen() bool` ### WindowCenter -Centers the window on the monitor the window is currently on. +ウィンドウが現在表示されているモニターの中央に、ウィンドウを配置させます。 Go: `WindowReload(ctx context.Context)`
JS: `WindowReload()` ### WindowReload -Performs a "reload" (Reloads current page). +リロードします。(現在表示されているページをリロード) Go: `WindowReloadApp(ctx context.Context)`
JS: `WindowReloadApp()` ### WindowReloadApp -Reloads the application frontend. +アプリケーションフロントエンドをリロードします。 Go: `WindowSetSystemDefaultTheme(ctx context.Context)`
JS: `WindowSetSystemDefaultTheme()` ### WindowSetSystemDefaultTheme -Windows only. +Windowsのみ使用可能。 Go: `WindowSetDarkTheme(ctx context.Context)`
JS: `WindowSetDarkTheme()` -Sets window theme to system default (dark/light). +ウィンドウのテーマをシステムデフォルト(ダーク/ライト) に設定します。 ### WindowSetLightTheme -Windows only. +Windowsのみ使用可能。 Go: `WindowSetLightTheme(ctx context.Context)`
JS: `WindowSetLightTheme()` -Sets window theme to light. +ウィンドウのテーマをライトに設定します。 ### WindowSetDarkTheme -Windows only. +Windowsのみ使用可能。 Go: `WindowShow(ctx context.Context)`
JS: `WindowShow()` -Sets window theme to dark. +ウィンドウのテーマをダークに設定します。 ### WindowShow -Shows the window, if it is currently hidden. +ウィンドウが非表示になっている場合は、表示させます。 Go: `WindowHide(ctx context.Context)`
JS: `WindowHide()` ### WindowHide -Hides the window, if it is currently visible. +現在表示されているウィンドウを非表示にします。 Go: `WindowSetSize(ctx context.Context, width int, height int)`
JS: `WindowSetSize(size: Size)` ### WindowIsNormal -Returns true if the window not minimised, maximised or fullscreen. +ウィンドウが最小化、最大化、またはフルスクリーンになっていない場合、trueを返します。 Go: `WindowIsNormal(ctx context.Context) bool`
JS: `WindowIsNormal() bool` ### WindowSetSize -Sets the width and height of the window. +ウィンドウの幅と高さを設定します。 Go: `WindowSetMaxSize(ctx context.Context, width int, height int)`
JS: `WindowSetMaxSize(size: Size)` ### WindowGetSize -Gets the width and height of the window. +ウィンドウの幅と高さを取得します。 -Go: `WindowSetMinSize(ctx context.Context, width int, height int)`
JS: `WindowSetMinSize(size: Size)` +Go: `WindowGetSize(ctx context.Context) (width int, height int)`
JS: `WindowGetSize() : Size` ### WindowSetMinSize -Sets the minimum window size. Will resize the window if the window is currently smaller than the given dimensions. +ウィンドウの最小サイズを設定します。 現在のウィンドウサイズが、指定された最小サイズよりも小さい場合、現在のウィンドウサイズは変更されます。 -Setting a size of `0,0` will disable this constraint. +サイズを`0,0`に設定すると、サイズの制約が無効化されます。 Go: `WindowSetAlwaysOnTop(ctx context.Context, b bool)`
JS: `WindowSetAlwaysOnTop(b: Boolen)` ### WindowSetMaxSize -Sets the maximum window size. Will resize the window if the window is currently larger than the given dimensions. +ウィンドウの最大サイズを設定します。 現在のウィンドウサイズが、指定された最大サイズよりも大きい場合、現在のウィンドウサイズは変更されます。 -Setting a size of `0,0` will disable this constraint. +サイズを`0,0`に設定すると、サイズの制約が無効化されます。 Go: `WindowSetPosition(ctx context.Context, x int, y int)`
JS: `WindowSetPosition(position: Position)` ### WindowSetAlwaysOnTop -Sets the window AlwaysOnTop or not on top. +ウィンドウを常に最前面に表示するかを切り替えます。 -Go: `WindowGetPosition(ctx context.Context) (x int, y int)`
JS: `WindowGetPosition() : Position` +Go: `WindowSetAlwaysOnTop(ctx context.Context, b bool)`
JS: `WindowSetAlwaysOnTop(b: Boolen)` ### WindowSetPosition -Sets the window position relative to the monitor the window is currently on. +現在ウィンドウが表示されているモニターに対する、相対的なウィンドウ位置を設定します。 Go: `WindowMaximise(ctx context.Context)`
JS: `WindowMaximise()` ### WindowGetPosition -Gets the window position relative to the monitor the window is currently on. +現在ウィンドウが表示されているモニターに対する、相対的なウィンドウ位置を取得します。 -Go: `WindowUnmaximise(ctx context.Context)`
JS: `WindowUnmaximise()` +Go: `WindowGetPosition(ctx context.Context) (x int, y int)`
JS: `WindowGetPosition() : Position` ### WindowMaximise -Maximises the window to fill the screen. +ウィンドウを最大化します。 Go: `WindowToggleMaximise(ctx context.Context)`
JS: `WindowToggleMaximise()` ### WindowUnmaximise -Restores the window to the dimensions and position prior to maximising. +ウィンドウの最大化を解除し、最大化する前のサイズおよび位置に戻します。 Go: `WindowMinimise(ctx context.Context)`
JS: `WindowMinimise()` ### WindowIsMaximised -Returns true if the window is maximised. +ウィンドウが最大化している場合はtrueを返します。 Go: `WindowIsMaximised(ctx context.Context) bool`
JS: `WindowIsMaximised() bool` ### WindowToggleMaximise -Toggles between Maximised and UnMaximised. +最大化の状態を切り替えます。 Go: `WindowToggleMaximise(ctx context.Context)`
JS: `WindowToggleMaximise()` ### WindowMinimise -Minimises the window. +ウィンドウを最小化します。 Go: `WindowSetBackgroundColour(ctx context.Context, R, G, B, A uint8)`
JS: `WindowSetBackgroundColour(R, G, B, A)` ### WindowUnminimise -Restores the window to the dimensions and position prior to minimising. +ウィンドウの最小化を解除し、最小化する前のサイズおよび位置に戻します。 Go: `WindowUnminimise(ctx context.Context)`
JS: `WindowUnminimise()` ### WindowIsMinimised -Returns true if the window is minimised. +ウィンドウが最小化している場合はtrueを返します。 Go: `WindowIsMinimised(ctx context.Context) bool`
JS: `WindowIsMinimised() bool` ### WindowSetBackgroundColour -Sets the background colour of the window to the given RGBA colour definition. This colour will show through for all transparent pixels. +ウィンドウの背景色をRGBAカラー定義で設定します。 この色は、すべての透過ピクセルに対して表示されます。 -Valid values for R, G, B and A are 0-255. +R、G、B、Aの有効な値の範囲は0~255です。 :::info Windows -On Windows, only alpha values of 0 or 255 are supported. Any value that is not 0 will be considered 255. +Windowsの場合、0または255のアルファ値(A) のみがサポートされています。 0以外の値を指定すると、すべて255とみなされます。 ::: Go: `WindowSetBackgroundColour(ctx context.Context, R, G, B, A uint8)`
JS: `WindowSetBackgroundColour(R, G, B, A)` -## Typescript Object Definitions +## Typescript型定義 ### Position diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/version-v2.0.0-rc.1.json b/website/i18n/ja/docusaurus-plugin-content-docs/version-v2.0.0-rc.1.json index 49cf4687e..79085926e 100644 --- a/website/i18n/ja/docusaurus-plugin-content-docs/version-v2.0.0-rc.1.json +++ b/website/i18n/ja/docusaurus-plugin-content-docs/version-v2.0.0-rc.1.json @@ -4,11 +4,11 @@ "description": "The label for version v2.0.0-rc.1" }, "sidebar.docs.category.Getting Started": { - "message": "Getting Started", + "message": "はじめよう", "description": "The label for category Getting Started in sidebar docs" }, "sidebar.docs.category.Reference": { - "message": "Reference", + "message": "リファレンス", "description": "The label for category Reference in sidebar docs" }, "sidebar.docs.category.Runtime": { @@ -16,23 +16,23 @@ "description": "The label for category Runtime in sidebar docs" }, "sidebar.docs.category.Community": { - "message": "Community", + "message": "コミュニティ", "description": "The label for category Community in sidebar docs" }, "sidebar.docs.category.Showcase": { - "message": "Showcase", + "message": "事例紹介", "description": "The label for category Showcase in sidebar docs" }, "sidebar.docs.category.Guides": { - "message": "Guides", + "message": "ガイド", "description": "The label for category Guides in sidebar docs" }, "sidebar.docs.category.Tutorials": { - "message": "Tutorials", + "message": "チュートリアル", "description": "The label for category Tutorials in sidebar docs" }, "sidebar.docs.link.Contributing": { - "message": "Contributing", + "message": "コントリビューション", "description": "The label for link Contributing in sidebar docs, linking to /community-guide#ways-of-contributing" } } diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/version-v2.0.0.json b/website/i18n/ja/docusaurus-plugin-content-docs/version-v2.0.0.json index 421c838e6..1bb1b5cf6 100644 --- a/website/i18n/ja/docusaurus-plugin-content-docs/version-v2.0.0.json +++ b/website/i18n/ja/docusaurus-plugin-content-docs/version-v2.0.0.json @@ -4,11 +4,11 @@ "description": "The label for version v2.0.0" }, "sidebar.docs.category.Getting Started": { - "message": "Getting Started", + "message": "はじめよう", "description": "The label for category Getting Started in sidebar docs" }, "sidebar.docs.category.Reference": { - "message": "Reference", + "message": "リファレンス", "description": "The label for category Reference in sidebar docs" }, "sidebar.docs.category.Runtime": { @@ -16,23 +16,23 @@ "description": "The label for category Runtime in sidebar docs" }, "sidebar.docs.category.Community": { - "message": "Community", + "message": "コミュニティ", "description": "The label for category Community in sidebar docs" }, "sidebar.docs.category.Showcase": { - "message": "Showcase", + "message": "事例紹介", "description": "The label for category Showcase in sidebar docs" }, "sidebar.docs.category.Guides": { - "message": "Guides", + "message": "ガイド", "description": "The label for category Guides in sidebar docs" }, "sidebar.docs.category.Tutorials": { - "message": "Tutorials", + "message": "チュートリアル", "description": "The label for category Tutorials in sidebar docs" }, "sidebar.docs.link.Contributing": { - "message": "Contributing", + "message": "コントリビューション", "description": "The label for link Contributing in sidebar docs, linking to /community-guide#ways-of-contributing" } } diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/version-v2.0.0/guides/obfuscated.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/version-v2.0.0/guides/obfuscated.mdx index 049efbb32..d5c6c5a29 100644 --- a/website/i18n/ja/docusaurus-plugin-content-docs/version-v2.0.0/guides/obfuscated.mdx +++ b/website/i18n/ja/docusaurus-plugin-content-docs/version-v2.0.0/guides/obfuscated.mdx @@ -5,13 +5,13 @@ Wails includes support for obfuscating your application using [garble](https://g To produce an obfuscated build, you can use the `-obfuscate` flag with the `wails build` command: ```bash -wails build -obfuscate +wails build -obfuscated ``` To customise the obfuscation settings, you can use the `-garbleargs` flag: ```bash -wails build -obfuscate -garbleargs "-literals -tiny -seed=myrandomseed" +wails build -obfuscated -garbleargs "-literals -tiny -seed=myrandomseed" ``` These settings may be persisted in your [project config](../reference/project-config). diff --git a/website/i18n/ja/docusaurus-plugin-content-pages/changelog.mdx b/website/i18n/ja/docusaurus-plugin-content-pages/changelog.mdx index 7b66a474d..06f1579e3 100644 --- a/website/i18n/ja/docusaurus-plugin-content-pages/changelog.mdx +++ b/website/i18n/ja/docusaurus-plugin-content-pages/changelog.mdx @@ -4,7 +4,22 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased +## v2.0.0 - 2022-09-22 + +## Fixed +* Fix buildtags parsing if only one tag is specified by @stffabi in https://github.com/wailsapp/wails/pull/1858 +* Use embed all to include all files in templates by @stffabi in https://github.com/wailsapp/wails/pull/1862 + +## Changed +* Bump minimum required Go version to 1.18 by @stffabi in https://github.com/wailsapp/wails/pull/1854 +* Add check for minimum required Go version by @stffabi in https://github.com/wailsapp/wails/pull/1853 +* chore: update README and workflows by @misitebao in https://github.com/wailsapp/wails/pull/1848 +* Update introduction.mdx by @ParvinEyvazov in https://github.com/wailsapp/wails/pull/1863 +* Releasetest/release workflow by @leaanthony in https://github.com/wailsapp/wails/pull/1869 +* Optimize documentation website by @misitebao in https://github.com/wailsapp/wails/pull/1849 + +## New Contributors +* @ParvinEyvazov made their first contribution in https://github.com/wailsapp/wails/pull/1863 ## v2.0.0-rc.1 - 2022-09-13 diff --git a/website/i18n/ja/docusaurus-plugin-content-pages/coc.mdx b/website/i18n/ja/docusaurus-plugin-content-pages/coc.mdx index 131132831..917c6cfdc 100644 --- a/website/i18n/ja/docusaurus-plugin-content-pages/coc.mdx +++ b/website/i18n/ja/docusaurus-plugin-content-pages/coc.mdx @@ -1,4 +1,4 @@ -# Contributor Covenant Code of Conduct +# コントリビューターの行動規範 ## 私たちの約束 @@ -32,25 +32,25 @@ ## 適用範囲 -This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. +この行動規範は、すべてのコミュニティスペース内で適用され、個人がパブリックスペースでコミュニティを公式に代表している場合にも適用されます。 私たちのコミュニティを代表する例には、公式の電子メールアドレスの使用、公式のソーシャルメディアアカウントを介した投稿、オンラインまたはオフラインのイベントでの指定代理人としての行動などがあります。 ## 執行 -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at coc@wails.io. All complaints will be reviewed and investigated promptly and fairly. +虐待的、嫌がらせ、またはその他の許容できない行動の事例は、執行を担当するコミュニティリーダー coc@wails.io へ報告される場合があります。 すべての苦情は迅速かつ公正にレビューおよび調査されます。 すべてのコミュニティリーダーは、問題の報告者のプライバシーとセキュリティを尊重する義務があります。 ## 執行ガイドライン -Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: +コミュニティリーダーは、この行動規範に違反していると見なした行動への帰結を判断する際に、これらのコミュニティガイドラインに従います。 -### 1. Correction +### 1. 更生 **コミュニティへの影響**: コミュニティで専門家にふさわしくない、または歓迎されないと思われる不適切な言葉の使用やその他の不適切な行動をすること。 **帰結**: コミュニティリーダーからの非公開の書面による警告。 違反の理由を明確にし、行動が不適切だった理由を説明します。 公の謝罪が要求される場合があります。 -### 2. Warning +### 2. 警告 **コミュニティへの影響**: 単一の出来事または一連の動作による違反。 @@ -60,7 +60,7 @@ Community leaders will follow these Community Impact Guidelines in determining t **コミュニティへの影響**: 持続的で不適切な行動を含む、コミュニティ標準の重大な違反。 -**帰結**: 指定された期間のコミュニティとのあらゆる種類の相互関係または公的なコミュニケーションの一時的な禁止。 この期間中、行動規範を実施する人々との一方的な対話を含め、関係する人々との公的または私的な対話は許可されません。 これらの条件に違反すると、永久的に禁止される場合があります。 Violating these terms may lead to a permanent ban. +**帰結**: 指定された期間のコミュニティとのあらゆる種類の相互関係または公的なコミュニケーションの一時的な禁止。 この期間中、行動規範を実施する人々との一方的な対話を含め、関係する人々との公的または私的な対話は許可されません。 これらの条件に違反すると、永久的に禁止される場合があります。 これらの条件に違反すると、永久的に禁止される場合があります。 ### 4. 永久的な禁止 @@ -68,7 +68,7 @@ Community leaders will follow these Community Impact Guidelines in determining t **帰結**: コミュニティ内でのあらゆる種類の公的な相互関係の永久的な禁止。 -## Attribution +## 帰属 この行動規範は、https://www.contributor-covenant.org/version/2/0/code_of_conduct.html で利用可能な [Contributor Covenant](https://www.contributor-covenant.org) バージョン 2.0 を基に作成されています。 diff --git a/website/i18n/ja/docusaurus-plugin-content-pages/credits.mdx b/website/i18n/ja/docusaurus-plugin-content-pages/credits.mdx index 67cd6bfc5..e65b68bc3 100644 --- a/website/i18n/ja/docusaurus-plugin-content-pages/credits.mdx +++ b/website/i18n/ja/docusaurus-plugin-content-pages/credits.mdx @@ -1,15 +1,15 @@ -# Credits +# クレジット -- [Lea Anthony](https://github.com/leaanthony) - Project owner, lead developer -- [Stffabi](https://github.com/stffabi) - Technical lead, developer and maintainer -- [Misite Bao](https://github.com/misitebao) - Documentation wizard, Chinese translation, Windows testing, Bug finder general -- [Travis McLane](https://github.com/tmclane) - Cross-compilation work, MacOS testing -- [Byron Chris](https://github.com/bh90210) - Linux distro wizard, Linux testing +- [Lea Anthony](https://github.com/leaanthony) - プロジェクトオーナー、開発リーダー +- [Stffabi](https://github.com/stffabi) - テクニカルリーダー、開発担当、保守担当 +- [Misite Bao](https://github.com/misitebao) - ドキュメント専門担当、翻訳担当(中国語)、Windowsテスター、不具合収集担当 +- [Travis McLane](https://github.com/tmclane) - クロスコンパイル担当、MacOSテスター +- [Byron Chris](https://github.com/bh90210) - Linuxディストリビューション専門担当、Linuxテスター -## Sponsors +## スポンサー -## Contributors +## コントリビューター @@ -179,6 +179,7 @@
Maicarons J

📖
kiddov

📖 💵 ⚠️ 🤔
Nicolas Coutin

💵 +
Parvin Eyvazov

📖 @@ -187,12 +188,12 @@ -## Special Mentions +## スペシャルサンクス -- [John Chadwick](https://github.com/jchv) - His amazing work on [go-webview2](https://github.com/jchv/go-webview2) and [go-winloader](https://github.com/jchv/go-winloader) have made the Windows version possible. -- [Tad Vizbaras](https://github.com/tadvi) - His winc project was the first step down the path to a pure Go Wails. -- [Mat Ryer](https://github.com/matryer) - For advice, support and bants. -- [Dustin Krysak](https://wiki.ubuntu.com/bashfulrobot) - His support and feedback has been invaluable. -- [Justen Walker](https://github.com/justenwalker/) - For helping wrangle COM issues which got v2 over the line. -- [Wang, Chi](https://github.com/patr0nus/) - The DeskGap project was a huge influence on the direction of Wails v2. -- [Serge Zaitsev](https://github.com/zserge) - Whilst Wails does not use the Webview project, it is still a source of inspiration. +- [John Chadwick](https://github.com/jchv) - 彼の[go-webview2](https://github.com/jchv/go-webview2)および[go-winloader](https://github.com/jchv/go-winloader)というすばらしい成果によって、Windows版を開発できました。 +- [Tad Vizbaras](https://github.com/tadvi) - 彼のwincプロジェクトは、純粋なGo Wails開発の最初のステップでした。 +- [Mat Ryer](https://github.com/matryer) - アドバイス、サポート、営業。 +- [Dustin Krysak](https://wiki.ubuntu.com/bashfulrobot) - 彼は非常に有益なサポートおよびフィードバックをしてくれました。 +- [Justen Walker](https://github.com/justenwalker/) - v2を成功させるために、COM問題を解決してくれました。 +- [Wang, Chi](https://github.com/patr0nus/) - DeskGapプロジェクトは、Wails v2の方向性に大きな影響を与えてくれました。 +- [Serge Zaitsev](https://github.com/zserge) - WailsがWebviewを使用していない間、インスピレーションの源となっていました。 diff --git a/website/i18n/ja/docusaurus-plugin-content-pages/markdown-page.md b/website/i18n/ja/docusaurus-plugin-content-pages/markdown-page.md index 9756c5b66..01a7a772c 100644 --- a/website/i18n/ja/docusaurus-plugin-content-pages/markdown-page.md +++ b/website/i18n/ja/docusaurus-plugin-content-pages/markdown-page.md @@ -4,4 +4,4 @@ title: Markdown page example # Markdown page example -You don't need React to write simple standalone pages. +シンプルな単一ページを作成する場合、Reactは必要ありません。 diff --git a/website/i18n/ja/docusaurus-theme-classic/footer.json b/website/i18n/ja/docusaurus-theme-classic/footer.json index 559ec9a01..22c9a2f88 100644 --- a/website/i18n/ja/docusaurus-theme-classic/footer.json +++ b/website/i18n/ja/docusaurus-theme-classic/footer.json @@ -4,7 +4,7 @@ "description": "The title of the footer links column with title=Docs in the footer" }, "link.title.Community": { - "message": "Community", + "message": "コミュニティ", "description": "The title of the footer links column with title=Community in the footer" }, "link.title.More": { @@ -12,11 +12,11 @@ "description": "The title of the footer links column with title=More in the footer" }, "link.item.label.Introduction": { - "message": "Introduction", + "message": "イントロダクション", "description": "The label of footer link with label=Introduction linking to /docs/introduction" }, "link.item.label.Getting Started": { - "message": "Getting Started", + "message": "はじめよう", "description": "The label of footer link with label=Getting Started linking to /docs/gettingstarted/installation" }, "link.item.label.Changelog": { diff --git a/website/i18n/ja/docusaurus-theme-classic/navbar.json b/website/i18n/ja/docusaurus-theme-classic/navbar.json index 2953b8af1..6f738ece3 100644 --- a/website/i18n/ja/docusaurus-theme-classic/navbar.json +++ b/website/i18n/ja/docusaurus-theme-classic/navbar.json @@ -16,7 +16,7 @@ "description": "Navbar item with label GitHub" }, "item.label.About": { - "message": "About", + "message": "概要", "description": "Navbar item with label About" }, "item.label.FAQ": { @@ -32,11 +32,11 @@ "description": "Navbar item with label Community Guide" }, "item.label.Credits": { - "message": "Credits", + "message": "クレジット", "description": "Navbar item with label Credits" }, "item.label.Code of Conduct": { - "message": "Code of Conduct", + "message": "行動規範", "description": "Navbar item with label Code of Conduct" } } diff --git a/website/i18n/zh-Hans/code.json b/website/i18n/zh-Hans/code.json index ce08c5b09..cc56b491b 100644 --- a/website/i18n/zh-Hans/code.json +++ b/website/i18n/zh-Hans/code.json @@ -242,7 +242,7 @@ "description": "The label used by the button on the collapsible TOC component" }, "theme.navbar.mobileLanguageDropdown.label": { - "message": "语言", + "message": "选择语言", "description": "The label for the mobile language switcher dropdown" }, "theme.SearchBar.seeAll": { diff --git a/website/i18n/zh-Hans/docusaurus-plugin-content-blog/2021-09-27-v2-beta1-release-notes.mdx b/website/i18n/zh-Hans/docusaurus-plugin-content-blog/2021-09-27-v2-beta1-release-notes.mdx index 1eacc3171..e69a6e415 100644 --- a/website/i18n/zh-Hans/docusaurus-plugin-content-blog/2021-09-27-v2-beta1-release-notes.mdx +++ b/website/i18n/zh-Hans/docusaurus-plugin-content-blog/2021-09-27-v2-beta1-release-notes.mdx @@ -65,9 +65,9 @@ Gophers 欢呼吧! 单个二进制文件的构想依然存在!
``` -有很多对原生菜单支持的请求。 Wails 终于帮您搞定了。 应用程序菜单现已可用,并且包括对大多数原生菜单功能的支持。 这包括标准菜单项、复选框、单选组、子菜单和分隔符。 +有很多对原生菜单支持的需求。 Wails 终于帮您搞定了。 应用程序菜单现已可用,并且包括对大多数原生菜单功能的支持。 这包括标准菜单项、复选框、单选组、子菜单和分隔符。 -在 v1 中有大量的请求,要求能够更好地控制窗口本身。 我很高兴地宣布,有专门用于此的新运行时 API。 它功能丰富,支持多显示器配置。 还有一个改进的对话框 API:现在,您可以拥有具有丰富配置的现代原生对话框,以满足您的所有对话框需求。 +在 v1 中有大量的需求,要求能够更好地控制窗口本身。 我很高兴地宣布,有专门用于此的新运行时 API。 它功能丰富,支持多显示器配置。 还有一个改进的对话框 API:现在,您可以拥有具有丰富配置的现代原生对话框,以满足您所有的对话框需求。 现在可以选择随项目生成 IDE 配置。 这意味着如果您在受支持的 IDE 中打开您的项目,它已经被配置为构建和调试您的应用程序。 目前支持 VSCode,但我们希望尽快支持其他 IDE,例如 Goland。 diff --git a/website/i18n/zh-Hans/docusaurus-plugin-content-blog/2022-09-22-v2-release-notes.mdx b/website/i18n/zh-Hans/docusaurus-plugin-content-blog/2022-09-22-v2-release-notes.mdx index 5e897e478..3c0fed7d9 100644 --- a/website/i18n/zh-Hans/docusaurus-plugin-content-blog/2022-09-22-v2-release-notes.mdx +++ b/website/i18n/zh-Hans/docusaurus-plugin-content-blog/2022-09-22-v2-release-notes.mdx @@ -95,4 +95,4 @@ V2 版本是该项目的巨大飞跃,解决了 v1 的许多痛点。 如果您 ‐ Lea -PPS:如果您或您的公司发现 Wails 有用,可以考虑 [赞助该项目](https://github.com/sponsors/leaanthony)。 谢谢! 谢谢! +PPS:如果您或您的公司发现 Wails 有用,可以考虑 [赞助该项目](https://github.com/sponsors/leaanthony)。 谢谢! diff --git a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/gettingstarted/development.mdx b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/gettingstarted/development.mdx index 1343a8a89..e681d5940 100644 --- a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/gettingstarted/development.mdx +++ b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/gettingstarted/development.mdx @@ -9,7 +9,7 @@ sidebar_position: 5 - 构建您的应用程序并运行它 - 将您的 Go 代码绑定到前端,以便可以从 Javascript 调用它 - 使用 [Vite](https://vitejs.dev/) 的强大功能,将监视您的 Go 文件中的修改并在更改时重新构建/重新运行 -- 启动一个 [网络服务器](http://localhost:34115) 通过浏览器为您的应用程序提供服务。 这使您可以使用自己喜欢的浏览器扩展。你甚至可以从控制台调用你的 Go 代码。 您甚至可以从控制台调用 Go 代码。 +- 启动一个 [网络服务器](http://localhost:34115) 通过浏览器为您的应用程序提供服务。 这使您可以使用自己喜欢的浏览器扩展。 你甚至可以从控制台调用你的 Go 代码。 首先,在项目目录中运行 `wails dev`。 可以在 [此处](../reference/cli#开发) 找到有关这方面的更多信息。 diff --git a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/gettingstarted/firstproject.mdx b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/gettingstarted/firstproject.mdx index 3c22691b7..e789438b0 100644 --- a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/gettingstarted/firstproject.mdx +++ b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/gettingstarted/firstproject.mdx @@ -116,10 +116,10 @@ Wails 项目有以下布局: - `/main.go` - 主应用 - `/frontend/` - 前端项目文件 - `/build/` - 项目构建目录 -- `/wails.json` - 应用程序图标 -- `/go.mod` - Mac 特定的项目文件 -- `/go.sum` - Windows 特定的项目文件 -- `/build/windows/` - 项目配置 +- `/build/appicon.png` - 应用程序图标 +- `/build/darwin/` - Mac 特定的项目文件 +- `/build/windows/` - Windows 特定的项目文件 +- `/wails.json` - 项目配置 - `/go.mod` - Go module 文件 - `/go.sum` - Go module 校验文件 diff --git a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/guides/obfuscated.mdx b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/guides/obfuscated.mdx index 5fc20ca15..aa5814f54 100644 --- a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/guides/obfuscated.mdx +++ b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/guides/obfuscated.mdx @@ -5,13 +5,13 @@ Wails 支持使用 [garble](https://github.com/burrowers/garble) 来混淆您的 要生成混淆构建,您可以将 `-obfuscate` 标志与 `wails build` 命令一起使用: ```bash -wails build -obfuscate +wails build -obfuscated ``` 要自定义混淆设置,您可以使用以下 `-garbleargs` 标志: ```bash -wails build -obfuscate -garbleargs "-literals -tiny -seed=myrandomseed" +wails build -obfuscated -garbleargs "-literals -tiny -seed=myrandomseed" ``` 这些设置可能会保留在您的 [项目配置](../reference/project-config) 中。 diff --git a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/howdoesitwork.mdx b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/howdoesitwork.mdx index 1e47ea8bb..87cc5c397 100644 --- a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/howdoesitwork.mdx +++ b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/howdoesitwork.mdx @@ -226,11 +226,13 @@ export function Greet(arg1: string): Promise; 生成的方法返回一个 Promise 成功的调用将导致 Go 调用的第一个返回值被传递给 `resolve` 处理程序。 不成功的调用是当 Go 方法的第二个返回值具有错误类型时,将错误实例传递回调用者。 这通过 `reject` 处理程序传回的。 在上面的示例中,`Greet` 只返回一个 `string`,因此 Javascript 调用永远不会 reject - 除非将无效数据传递给它。 -所有数据类型都在 Go 和 Javascript 之间正确转换。 包括结构体。 如果您从 Go 调用返回一个结构体,它将作为 Javascript 类返回到您的前端。 注意:如果您想使用结构体,您 **必须** 为您的结构体字段定义 `json` 标签! +所有数据类型都在 Go 和 Javascript 之间正确转换。 包括结构体。 如果您从 Go 调用返回一个结构体,它将作为 Javascript 类返回到您的前端。 :::info 注意 +结构体字段 *必须* 具有有效的 `json` 标签,以包含在生成的 TypeScript 中。 + 目前不支持嵌套匿名结构体。 ::: diff --git a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/reference/cli.mdx b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/reference/cli.mdx index 4f483e8fd..60af66588 100644 --- a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/reference/cli.mdx +++ b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/reference/cli.mdx @@ -51,28 +51,28 @@ Wails CLI 有许多用于管理项目的命令。 所有命令都以此方式运 `wails build` 用于将您的项目编译为生产可用的二进制文件。 -| 标志 | 描述 | 默认 | -|:--------------- |:-------------------------------------------------------------------------------------------- |:--------------------------------------------------------------------------------------------------------- | -| -platform | 为指定的 [平台](../reference/cli#平台)(逗号分割)构建,例如: `windows/arm64`。 注意,如果不给出架构,则使用 `runtime.GOARCH`。 | 如果给定环境变量 platform = `GOOS` 否则等于 `runtime.GOOS`。
如果给定环境变量 arch = `GOARCH` 否则等于 `runtime.GOARCH`. | -| -clean | 清理 `build/bin` 目录 | | -| -compiler "编译器" | 使用不同的 go 编译器来构建,例如 go1.15beta1 | go | -| -ldflags "标志" | 传递给编译器的额外 ldflags | | -| -nopackage | 不打包应用程序 | | -| -o 文件名 | 输出文件名 | | -| -s | 跳过前端构建 | false | -| -f | 强制构建应用 | false | -| -tags "额外标签" | 构建标签以传递给 Go 编译器。 必须引用。 空格或逗号(但不能同时使用)分隔 | | -| -upx | 使用 “upx” 压缩最终二进制文件 | | -| -upxflags | 传递给 upx 的标志 | | -| -v int | 详细级别 (0 - silent, 1 - default, 2 - verbose) | 1 | -| -webview2 | WebView2 安装策略:download,embed,browser,error. | download | -| -u | 更新项目的 `go.mod` 以使用与 CLI 相同版本的 Wails | | -| -debug | 在应用程序中保留调试信息。 允许在应用程序窗口中使用 devtools | false | -| -trimpath | 从生成的可执行文件中删除所有文件系统路径。 | false | -| -race | 使用 Go 的竞态检测器构建 | false | -| -windowsconsole | 保留Windows构建控制台窗口 | | -| -obfuscate | 使用 [garble](https://github.com/burrowers/garble) 混淆应用程序 | false | -| -garbleargs | 传递给 garble 的参数 | `-literals -tiny -seed=random` | +| 标志 | 描述 | 默认 | +|:--------------- |:------------------------------------------------------------------------------------------------------------- |:---------------------------------------------------------------------------------------------------------- | +| -platform | 为指定的 [平台](../reference/cli#平台)(逗号分割)构建,例如: `windows/arm64`。 `windows/arm64`。 注意,如果不给出架构,则使用 `runtime.GOARCH`。 | 如果给定环境变量 platform = `GOOS` 否则等于 `runtime.GOOS`。
如果给定环境变量 arch = `GOARCH` 否则等于 `runtime.GOARCH`. | +| -clean | 清理 `build/bin` 目录 | | +| -compiler "编译器" | 使用不同的 go 编译器来构建,例如 go1.15beta1 | go | +| -ldflags "标志" | 传递给编译器的额外 ldflags | | +| -nopackage | 不打包应用程序 | | +| -o 文件名 | 输出文件名 | | +| -s | 跳过前端构建 | false | +| -f | 强制构建应用 | false | +| -tags "额外标签" | 构建标签以传递给 Go 编译器。 必须引用。 空格或逗号(但不能同时使用)分隔 | | +| -upx | 使用 “upx” 压缩最终二进制文件 | | +| -upxflags | 传递给 upx 的标志 | | +| -v int | 详细级别 (0 - silent, 1 - default, 2 - verbose) | 1 | +| -webview2 | WebView2 安装策略:download,embed,browser,error. | download | +| -u | 更新项目的 `go.mod` 以使用与 CLI 相同版本的 Wails | | +| -debug | 在应用程序中保留调试信息。 允许在应用程序窗口中使用 devtools | false | +| -trimpath | 从生成的可执行文件中删除所有文件系统路径。 | false | +| -race | 使用 Go 的竞态检测器构建 | false | +| -windowsconsole | 保留Windows构建控制台窗口 | | +| -obfuscate | 使用 [garble](https://github.com/burrowers/garble) 混淆应用程序 | false | +| -garbleargs | 传递给 garble 的参数 | `-literals -tiny -seed=random` | 有关 `webview2` 标志的详细描述,请参阅 [Windows 系统指南](../guides/windows)。 diff --git a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/reference/menus.mdx b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/reference/menus.mdx index 17233e8c6..d89fe06e0 100644 --- a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/reference/menus.mdx +++ b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/reference/menus.mdx @@ -209,7 +209,7 @@ type CallbackData struct { } ``` -该函数被赋予一个 `CallbackData` 结构,该结构指示哪个菜单项触发了回调。 这在使用可能共享回调的单选菜单组时很有用。这在使用可能共享回调的单选组时很有用。 +该函数被赋予一个 `CallbackData` 结构,该结构指示哪个菜单项触发了回调。 这在使用可能共享回调的单选组时很有用。 ### 角色 diff --git a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/reference/runtime/dialog.mdx b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/reference/runtime/dialog.mdx index e99d6d50d..169a288f2 100644 --- a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/reference/runtime/dialog.mdx +++ b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/reference/runtime/dialog.mdx @@ -119,18 +119,30 @@ type MessageDialogOptions struct { } ``` -| 字段 | 描述 | Win | Mac | Lin | -| ------------- | ------------------------------ | --- | --- | --- | -| 类型 | 消息对话框的类型,例如问题、信息... | ✅ | ✅ | ✅ | -| Title | 对话框的标题 | ✅ | ✅ | ✅ | -| Message | 向用户显示的消息 | ✅ | ✅ | ✅ | -| Buttons | 按钮标题列表 | | ✅ | | -| DefaultButton | 带有此文本的按钮应被视为默认按钮。 绑定到 `return` | | ✅ | | -| CancelButton | 带有此文本的按钮应被视为取消。 绑定到 `escape` | | ✅ | | +| 字段 | 描述 | Win | Mac | Lin | +| ------------- | ------------------------------ | -------------- | --- | --- | +| 类型 | 消息对话框的类型,例如问题、信息... | ✅ | ✅ | ✅ | +| Title | 对话框的标题 | ✅ | ✅ | ✅ | +| Message | 向用户显示的消息 | ✅ | ✅ | ✅ | +| Buttons | 按钮标题列表 | | ✅ | | +| DefaultButton | 带有此文本的按钮应被视为默认按钮。 必定 `return`。 | ✅[*](#windows) | ✅ | | +| CancelButton | 带有此文本的按钮应被视为取消。 必定 `escape` | | ✅ | | #### Windows -Windows 具有标准对话框类型,其中的按钮不可自定义。 返回的值将是以下之一:"Ok"、"Cancel"、"Abort"、"Retry"、"Ignore"、"Yes"、"No"、"Try Again"或"Continue" +Windows 具有标准对话框类型,其中的按钮不可自定义。 返回的值将是以下之一:"Ok"、"Cancel"、"Abort"、"Retry"、"Ignore"、"Yes"、"No"、"Try Again"或"Continue"。 + +对于问题对话框,默认按钮是 “是”,取消按钮是 “否”。 可以通过将 `默认按钮` 值设置为 `"否"` 来改变这一点。 + +示例: +```go + result, err := runtime.MessageDialog(a.ctx, runtime.MessageDialogOptions{ + Type: runtime.QuestionDialog, + Title: "Question", + Message: "Do you want to continue?", + DefaultButton: "No", + }) +``` #### Linux diff --git a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/reference/runtime/intro.mdx b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/reference/runtime/intro.mdx index 444b4195b..c491166b9 100644 --- a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/reference/runtime/intro.mdx +++ b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/reference/runtime/intro.mdx @@ -36,7 +36,7 @@ Go: `Hide(ctx context.Context)`
JS: `Hide()` :::info 注意 -` Hide` 在 Mac 上,这将以与标准 Mac 应用程序中的菜单项相同的方式隐藏应用程序。 这与隐藏窗口不同,但应用程序仍处于前台。 对于 Windows 和 Linux,这与 `WindowHide` 相同。 +`Hide` 在 Mac 上,这将以与标准 Mac 应用程序中的菜单项相同的方式隐藏应用程序。 这与隐藏窗口不同,但应用程序仍处于前台。 对于 Windows 和 Linux,这与 `WindowHide` 相同。 ::: diff --git a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/tutorials/dogsapi.mdx b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/tutorials/dogsapi.mdx index 38f5f7233..110870ac5 100644 --- a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/tutorials/dogsapi.mdx +++ b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/tutorials/dogsapi.mdx @@ -27,7 +27,7 @@ sidebar_position: 20 ### 创建项目 -让我们创建应用程序。 从终端输入:` wails init -n dogs-api -t svelte` +让我们创建应用程序。 从终端输入:`wails init -n dogs-api -t svelte` 注意:如果您想添加 IDE 支持,我们可以选择在此命令的末尾添加 `-ide vscode` 或 `-ide goland`。 diff --git a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-v2.0.0/guides/obfuscated.mdx b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-v2.0.0/guides/obfuscated.mdx index 5fc20ca15..aa5814f54 100644 --- a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-v2.0.0/guides/obfuscated.mdx +++ b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/version-v2.0.0/guides/obfuscated.mdx @@ -5,13 +5,13 @@ Wails 支持使用 [garble](https://github.com/burrowers/garble) 来混淆您的 要生成混淆构建,您可以将 `-obfuscate` 标志与 `wails build` 命令一起使用: ```bash -wails build -obfuscate +wails build -obfuscated ``` 要自定义混淆设置,您可以使用以下 `-garbleargs` 标志: ```bash -wails build -obfuscate -garbleargs "-literals -tiny -seed=myrandomseed" +wails build -obfuscated -garbleargs "-literals -tiny -seed=myrandomseed" ``` 这些设置可能会保留在您的 [项目配置](../reference/project-config) 中。 diff --git a/website/i18n/zh-Hans/docusaurus-plugin-content-pages/changelog.mdx b/website/i18n/zh-Hans/docusaurus-plugin-content-pages/changelog.mdx index 0a9c4aab7..069722375 100644 --- a/website/i18n/zh-Hans/docusaurus-plugin-content-pages/changelog.mdx +++ b/website/i18n/zh-Hans/docusaurus-plugin-content-pages/changelog.mdx @@ -4,13 +4,28 @@ 格式基于 [维护更新日志](https://keepachangelog.com/en/1.0.0/),并且该项目遵循 [语义化版本](https://semver.org/spec/v2.0.0.html)。 -## 即将发布 +## v2.0.0 - 2022-09-22 + +## 修复 +* Fix buildtags parsing if only one tag is specified by @stffabi in https://github.com/wailsapp/wails/pull/1858 +* Use embed all to include all files in templates by @stffabi in https://github.com/wailsapp/wails/pull/1862 + +## 变更 +* Bump minimum required Go version to 1.18 by @stffabi in https://github.com/wailsapp/wails/pull/1854 +* Add check for minimum required Go version by @stffabi in https://github.com/wailsapp/wails/pull/1853 +* chore: update README and workflows by @misitebao in https://github.com/wailsapp/wails/pull/1848 +* Add nixpkgs support to doctor command. by @ianmjones in https://github.com/wailsapp/wails/pull/1551 by @ianmjones in https://github.com/wailsapp/wails/pull/1551 by @ianmjones in https://github.com/wailsapp/wails/pull/1551 +* Releasetest/release workflow by @leaanthony in https://github.com/wailsapp/wails/pull/1869 +* Optimize documentation website by @misitebao in https://github.com/wailsapp/wails/pull/1849 + +## 新贡献者 +* @ParvinEyvazov made their first contribution in https://github.com/wailsapp/wails/pull/1863 ## v2.0.0-rc.1 - 2022-09-13 ### 废弃 -- The `-noGen` flag for the `wails dev` command has been replaced with `-skipbindings`. This is to align with the `wails build` command. +- The `-noGen` flag for the `wails dev` command has been replaced with `-skipbindings`. This is to align with the `wails build` command. This is to align with the `wails build` command. ### 新增 @@ -172,7 +187,7 @@ Experimental: &options.Experimental{ ### 废弃 -- The `Fullscreen` application option is deprecated. Please use [`WindowStartState`](https://wails.io/docs/reference/options#windowstartstate) instead. +- The `Fullscreen` application option is deprecated. The `Fullscreen` application option is deprecated. Please use [`WindowStartState`](https://wails.io/docs/reference/options#windowstartstate) instead. ### 新贡献者 @@ -202,8 +217,8 @@ Experimental: &options.Experimental{ - Fix stack corruption in Windows when using ICoreWebView2HttpHeadersCollectionIterator by @stffabi in https://github.com/wailsapp/wails/pull/1589 - Move WindowGet\* to main thread by @leaanthony in https://github.com/wailsapp/wails/pull/1464 -- Allow -appargs flag to pass flags to binary. by @ianmjones in https://github.com/wailsapp/wails/pull/1534 -- Fix checking for installed apt package in none English session. by @ianmjones in https://github.com/wailsapp/wails/pull/1548 +- Allow -appargs flag to pass flags to binary. by @ianmjones in https://github.com/wailsapp/wails/pull/1534 by @ianmjones in https://github.com/wailsapp/wails/pull/1534 +- Fix checking for installed apt package in none English session. by @ianmjones in https://github.com/wailsapp/wails/pull/1548 by @ianmjones in https://github.com/wailsapp/wails/pull/1548 - Fix OnBeforeClose code for Mac by @leaanthony in https://github.com/wailsapp/wails/pull/1558 - Support Maps in TS conversion by @leaanthony in https://github.com/wailsapp/wails/pull/1435 - Check for line length when scanning for local devserver url by @leaanthony in https://github.com/wailsapp/wails/pull/1566 @@ -333,14 +348,14 @@ Experimental: &options.Experimental{ ### Breaking Changes -- When data was sent to the `EventsOn` callback, it was being sent as a slice of values, instead of optional parameters to the method. `EventsOn` now works as expected, but you will need to update your code if you currently use this. [More information](https://github.com/wailsapp/wails/issues/1324) -- The broken `bindings.js` and `bindings.d.ts` files have been replaced by a new JS/TS code generation system. More details [here](https://wails.io/docs/howdoesitwork#calling-bound-go-methods) +- When data was sent to the `EventsOn` callback, it was being sent as a slice of values, instead of optional parameters to the method. `EventsOn` now works as expected, but you will need to update your code if you currently use this. [More information](https://github.com/wailsapp/wails/issues/1324) `EventsOn` now works as expected, but you will need to update your code if you currently use this. [More information](https://github.com/wailsapp/wails/issues/1324) +- The broken `bindings.js` and `bindings.d.ts` files have been replaced by a new JS/TS code generation system. More details [here](https://wails.io/docs/howdoesitwork#calling-bound-go-methods) More details [here](https://wails.io/docs/howdoesitwork#calling-bound-go-methods) ### 新增 -- **New Templates**: Svelte, React, Vue, Preact, Lit and Vanilla templates, both JS and TS versions. `wails init -l` for more info. -- Default templates now powered by [Vite](https://vitejs.dev). This enables lightning fast reloads when you use `wails dev`! -- Add support for external frontend development servers. See `frontend:dev:serverUrl` in the [project config](https://wails.io/docs/reference/project-config) - [@stffabi](https://github.com/stffabi) +- **New Templates**: Svelte, React, Vue, Preact, Lit and Vanilla templates, both JS and TS versions. `wails init -l` for more info. `wails init -l` for more info. +- Default templates now powered by [Vite](https://vitejs.dev). This enables lightning fast reloads when you use `wails dev`! This enables lightning fast reloads when you use `wails dev`! +- Add support for external frontend development servers. Add support for external frontend development servers. See `frontend:dev:serverUrl` in the [project config](https://wails.io/docs/reference/project-config) - [@stffabi](https://github.com/stffabi) - [Fully configurable dark mode](https://wails.io/docs/reference/options#theme) for Windows. - Hugely improved [WailsJS generation](https://wails.io/docs/howdoesitwork#calling-bound-go-methods) (both Javascript and Typescript) - Wails doctor now reports information about the wails installation - [@stffabi](https://github.com/stffabi) @@ -390,13 +405,13 @@ Experimental: &options.Experimental{ - Ensure binary resources can be served by [@napalu](https://github.com/napalu) in #1240 - Only retry loading assets when loading from disk by [@leaanthony](https://github.com/leaanthony) in #1241 - [v2, windows] Fix maximised start state by [@stffabi](https://github.com/stffabi) in #1243 -- Ensure Linux IsFullScreen uses GDK_WINDOW_STATE_FULLSCREEN bitmask appropriately. by [@ianmjones](https://github.com/ianmjones) in #1245 +- Ensure Linux IsFullScreen uses GDK_WINDOW_STATE_FULLSCREEN bitmask appropriately. by [@ianmjones](https://github.com/ianmjones) in #1245 by [@ianmjones](https://github.com/ianmjones) in #1245 - Fix memory leak in ExecJS for Mac by [@leaanthony](https://github.com/leaanthony) in #1230 - Fix, or at least a workaround, for (#1232) by [@BillBuilt](https://github.com/BillBuilt) in #1247 - [v2] Use os.Args[0] for self starting wails by [@stffabi](https://github.com/stffabi) in #1258 - [v2, windows] Windows switch scheme: https -> http by @stefpap in #1255 - Ensure Focus is regained by Webview2 when tabbing by [@leaanthony](https://github.com/leaanthony) in #1257 -- Try to focus window when Show() is called. by [@leaanthony](https://github.com/leaanthony) in #1212 +- Try to focus window when Show() is called. by [@leaanthony](https://github.com/leaanthony) in #1212 by [@leaanthony](https://github.com/leaanthony) in #1212 - Check system for user installed Linux dependencies by [@leaanthony](https://github.com/leaanthony) in #1180 ### 变更 diff --git a/website/i18n/zh-Hans/docusaurus-plugin-content-pages/credits.mdx b/website/i18n/zh-Hans/docusaurus-plugin-content-pages/credits.mdx index 1b6c85039..40e0d5704 100644 --- a/website/i18n/zh-Hans/docusaurus-plugin-content-pages/credits.mdx +++ b/website/i18n/zh-Hans/docusaurus-plugin-content-pages/credits.mdx @@ -179,6 +179,7 @@
Maicarons J

📖
kiddov

📖 💵 ⚠️ 🤔
Nicolas Coutin

💵 +
Parvin Eyvazov

📖 diff --git a/website/i18n/zh-Hans/docusaurus-theme-classic/footer.json b/website/i18n/zh-Hans/docusaurus-theme-classic/footer.json index c13664373..85b1d8c3d 100644 --- a/website/i18n/zh-Hans/docusaurus-theme-classic/footer.json +++ b/website/i18n/zh-Hans/docusaurus-theme-classic/footer.json @@ -28,7 +28,7 @@ "description": "The label of footer link with label=Github linking to https://github.com/wailsapp/wails" }, "link.item.label.Twitter": { - "message": "Twitter", + "message": "Twitter(推特)", "description": "The label of footer link with label=Twitter linking to https://twitter.com/wailsapp" }, "link.item.label.Slack": { diff --git a/website/versioned_docs/version-v2.0.0-rc.1/guides/obfuscated.mdx b/website/versioned_docs/version-v2.0.0-rc.1/guides/obfuscated.mdx index 7d0e78def..c36a8a554 100644 --- a/website/versioned_docs/version-v2.0.0-rc.1/guides/obfuscated.mdx +++ b/website/versioned_docs/version-v2.0.0-rc.1/guides/obfuscated.mdx @@ -5,12 +5,12 @@ Wails includes support for obfuscating your application using [garble](https://g To produce an obfuscated build, you can use the `-obfuscate` flag with the `wails build` command: ```bash -wails build -obfuscate +wails build -obfuscated ``` To customise the obfuscation settings, you can use the `-garbleargs` flag: ```bash -wails build -obfuscate -garbleargs "-literals -tiny -seed=myrandomseed" +wails build -obfuscated -garbleargs "-literals -tiny -seed=myrandomseed" ``` These settings may be persisted in your [project config](/guides/reference/project-config). From 60a59f12b2a21f9d87edd17d465786717fa5fac6 Mon Sep 17 00:00:00 2001 From: Lea Anthony Date: Fri, 30 Sep 2022 08:15:20 +1000 Subject: [PATCH 15/36] Update build and test workflow --- .github/workflows/{release.yml => build_and_test.yml} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename .github/workflows/{release.yml => build_and_test.yml} (97%) diff --git a/.github/workflows/release.yml b/.github/workflows/build_and_test.yml similarity index 97% rename from .github/workflows/release.yml rename to .github/workflows/build_and_test.yml index 30dceb206..5f070a099 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/build_and_test.yml @@ -1,8 +1,8 @@ -name: Release +name: Build + Test on: push: - branches: [ release/* ] + branches: [ release/*, master ] workflow_dispatch: jobs: From d699e77c334a55bea43a64f97ecbd8c0e1391444 Mon Sep 17 00:00:00 2001 From: Lea Anthony Date: Fri, 30 Sep 2022 08:22:22 +1000 Subject: [PATCH 16/36] Update build and test workflow --- .github/workflows/build_and_test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index 5f070a099..f31d3cec8 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -8,7 +8,7 @@ on: jobs: test: name: Run Go Tests - if: github.repository == 'wailsapp/wails' + if: github.repository == 'wailsapp/wails' && ((github.branch == 'master' || github.branch == 'release/*') || (github.event_name == 'pull_request' && github.event.review.state == 'approved')) runs-on: ${{ matrix.os }} strategy: matrix: From 37954141cca27d6e55c5b5e9e315af788daeca7f Mon Sep 17 00:00:00 2001 From: Lea Anthony Date: Fri, 30 Sep 2022 08:25:03 +1000 Subject: [PATCH 17/36] Update build_and_test.yml --- .github/workflows/build_and_test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index f31d3cec8..3d249927b 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -2,7 +2,7 @@ name: Build + Test on: push: - branches: [ release/*, master ] + branches: "*" workflow_dispatch: jobs: From e7188e877fe0ca19608fb3099397c0cfd2a01b37 Mon Sep 17 00:00:00 2001 From: Lea Anthony Date: Fri, 30 Sep 2022 08:27:22 +1000 Subject: [PATCH 18/36] Update build and test workflow --- .github/workflows/build_and_test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index 3d249927b..5f070a099 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -2,13 +2,13 @@ name: Build + Test on: push: - branches: "*" + branches: [ release/*, master ] workflow_dispatch: jobs: test: name: Run Go Tests - if: github.repository == 'wailsapp/wails' && ((github.branch == 'master' || github.branch == 'release/*') || (github.event_name == 'pull_request' && github.event.review.state == 'approved')) + if: github.repository == 'wailsapp/wails' runs-on: ${{ matrix.os }} strategy: matrix: From c05666af7b6e84344c205830bbabcfe3c8b949f6 Mon Sep 17 00:00:00 2001 From: Lea Anthony Date: Fri, 30 Sep 2022 08:34:32 +1000 Subject: [PATCH 19/36] Fix asset handler on linux --- v2/internal/frontend/devserver/devserver.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v2/internal/frontend/devserver/devserver.go b/v2/internal/frontend/devserver/devserver.go index 87240b4d2..2f0e5066a 100644 --- a/v2/internal/frontend/devserver/devserver.go +++ b/v2/internal/frontend/devserver/devserver.go @@ -83,7 +83,7 @@ func (d *DevWebServer) Run(ctx context.Context) error { }) var err error - assetHandler, err = assetserver.NewAssetHandler(ctx, d.appoptions) + assetHandler, err = assetserver.NewAssetHandler(ctx, d.appoptions.Assets, d.appoptions.AssetsHandler) if err != nil { log.Fatal(err) } From d92e8d43c8035a1659fdbb5a46bc195311b15ae2 Mon Sep 17 00:00:00 2001 From: Richard Guay Date: Fri, 30 Sep 2022 05:40:30 +0700 Subject: [PATCH 20/36] Adding Tutorial link (#1903) Co-authored-by: Lea Anthony --- website/docs/community/links.mdx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/website/docs/community/links.mdx b/website/docs/community/links.mdx index d081cb9b3..23a4b8cf6 100644 --- a/website/docs/community/links.mdx +++ b/website/docs/community/links.mdx @@ -22,3 +22,6 @@ The [definitive list](https://github.com/wailsapp/awesome-wails) of links relate - [Twitter](https://twitter.com/wailsapp) - [Wails Chinese Community QQ Group](https://qm.qq.com/cgi-bin/qm/qr?k=PmIURne5hFGNd7QWzW5qd6FV-INEjNJv&jump_from=webapi) - Group number: 1067173054 + +## Other Tutorials and Articles +- [Building of Bulletin Board](https://blog.customct.com/building-bulletin-board) From 3ed0d69d61875467ea10f222cbd5e693dfb9be41 Mon Sep 17 00:00:00 2001 From: Lea Anthony Date: Fri, 30 Sep 2022 08:41:49 +1000 Subject: [PATCH 21/36] Update generate-sponsor-image.yml --- .github/workflows/generate-sponsor-image.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/generate-sponsor-image.yml b/.github/workflows/generate-sponsor-image.yml index e7d71c302..09c4a55ad 100644 --- a/.github/workflows/generate-sponsor-image.yml +++ b/.github/workflows/generate-sponsor-image.yml @@ -4,8 +4,6 @@ on: workflow_dispatch: schedule: - cron: "0 0 * * *" - push: - branches: [ master ] jobs: update-sponsors: From 13532e00a0a30b3824c57ed9901cd56af86d19e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Z=C3=A1mb=C3=B3=2C=20Levente?= Date: Fri, 30 Sep 2022 00:51:08 +0200 Subject: [PATCH 22/36] add missing resize for framless window on linux (#1918) Co-authored-by: Lea Anthony --- .../frontend/desktop/linux/frontend.go | 43 +++++++++++++++++++ v2/internal/frontend/desktop/linux/window.go | 41 ++++++++++++++++-- 2 files changed, 81 insertions(+), 3 deletions(-) diff --git a/v2/internal/frontend/desktop/linux/frontend.go b/v2/internal/frontend/desktop/linux/frontend.go index dce5b2531..b07fe9866 100644 --- a/v2/internal/frontend/desktop/linux/frontend.go +++ b/v2/internal/frontend/desktop/linux/frontend.go @@ -21,6 +21,7 @@ import ( "os" "runtime" "strconv" + "strings" "text/template" "unsafe" @@ -183,10 +184,16 @@ func (f *Frontend) WindowSetTitle(title string) { } func (f *Frontend) WindowFullscreen() { + if f.frontendOptions.Frameless && f.frontendOptions.DisableResize == false { + f.ExecJS("window.wails.flags.enableResize = false;") + } f.mainWindow.Fullscreen() } func (f *Frontend) WindowUnfullscreen() { + if f.frontendOptions.Frameless && f.frontendOptions.DisableResize == false { + f.ExecJS("window.wails.flags.enableResize = true;") + } f.mainWindow.UnFullscreen() } @@ -289,6 +296,17 @@ func (f *Frontend) Notify(name string, data ...interface{}) { f.mainWindow.ExecJS(`window.wails.EventsNotify('` + template.JSEscapeString(string(payload)) + `');`) } +var edgeMap = map[string]uintptr{ + "n-resize": C.GDK_WINDOW_EDGE_NORTH, + "ne-resize": C.GDK_WINDOW_EDGE_NORTH_EAST, + "e-resize": C.GDK_WINDOW_EDGE_EAST, + "se-resize": C.GDK_WINDOW_EDGE_SOUTH_EAST, + "s-resize": C.GDK_WINDOW_EDGE_SOUTH, + "sw-resize": C.GDK_WINDOW_EDGE_SOUTH_WEST, + "w-resize": C.GDK_WINDOW_EDGE_WEST, + "nw-resize": C.GDK_WINDOW_EDGE_NORTH_WEST, +} + func (f *Frontend) processMessage(message string) { if message == "DomReady" { if f.frontendOptions.OnDomReady != nil { @@ -304,9 +322,29 @@ func (f *Frontend) processMessage(message string) { return } + if strings.HasPrefix(message, "resize:") { + if !f.mainWindow.IsFullScreen() { + sl := strings.Split(message, ":") + if len(sl) != 2 { + f.logger.Info("Unknown message returned from dispatcher: %+v", message) + return + } + edge := edgeMap[sl[1]] + err := f.startResize(edge) + if err != nil { + f.logger.Error(err.Error()) + } + } + return + } + if message == "runtime:ready" { cmd := fmt.Sprintf("window.wails.setCSSDragProperties('%s', '%s');", f.frontendOptions.CSSDragProperty, f.frontendOptions.CSSDragValue) f.ExecJS(cmd) + + if f.frontendOptions.Frameless && f.frontendOptions.DisableResize == false { + f.ExecJS("window.wails.flags.enableResize = true;") + } return } @@ -339,6 +377,11 @@ func (f *Frontend) startDrag() { f.mainWindow.StartDrag() } +func (f *Frontend) startResize(edge uintptr) error { + f.mainWindow.StartResize(edge) + return nil +} + func (f *Frontend) ExecJS(js string) { f.mainWindow.ExecJS(js) } diff --git a/v2/internal/frontend/desktop/linux/window.go b/v2/internal/frontend/desktop/linux/window.go index ef6ecafb6..1f119e526 100644 --- a/v2/internal/frontend/desktop/linux/window.go +++ b/v2/internal/frontend/desktop/linux/window.go @@ -159,11 +159,12 @@ ulong setupInvokeSignal(void* contentManager) { return g_signal_connect((WebKitUserContentManager*)contentManager, "script-message-received::external", G_CALLBACK(sendMessageToBackend), NULL); } -// These are the x,y & time of the last mouse down event +// These are the x,y,time & button of the last mouse down event // It's used for window dragging float xroot = 0.0f; float yroot = 0.0f; int dragTime = -1; +uint mouseButton = 0; bool contextMenuDisabled = false; gboolean buttonPress(GtkWidget *widget, GdkEventButton *event, void* dummy) @@ -173,7 +174,7 @@ gboolean buttonPress(GtkWidget *widget, GdkEventButton *event, void* dummy) dragTime = -1; return FALSE; } - + mouseButton = event->button; if( event->button == 3 && contextMenuDisabled ) { return TRUE; } @@ -256,7 +257,7 @@ static gboolean startDrag(gpointer data) { return G_SOURCE_REMOVE; } - gtk_window_begin_move_drag(options->mainwindow, 1, xroot, yroot, dragTime); + gtk_window_begin_move_drag(options->mainwindow, mouseButton, xroot, yroot, dragTime); free(data); return G_SOURCE_REMOVE; @@ -269,6 +270,36 @@ static void StartDrag(void *webview, GtkWindow* mainwindow) { ExecuteOnMainThread(startDrag, (gpointer)data); } +typedef struct ResizeOptions { + void *webview; + GtkWindow* mainwindow; + GdkWindowEdge edge; +} ResizeOptions; + +static gboolean startResize(gpointer data) { + ResizeOptions* options = (ResizeOptions*)data; + + // Ignore non-toplevel widgets + GtkWidget *window = gtk_widget_get_toplevel(GTK_WIDGET(options->webview)); + if (!GTK_IS_WINDOW(window)) { + free(data); + return G_SOURCE_REMOVE; + } + + gtk_window_begin_resize_drag(options->mainwindow, options->edge, 1, xroot, yroot, dragTime); + free(data); + + return G_SOURCE_REMOVE; +} + +static void StartResize(void *webview, GtkWindow* mainwindow, GdkWindowEdge edge) { + ResizeOptions* data = malloc(sizeof(ResizeOptions)); + data->webview = webview; + data->mainwindow = mainwindow; + data->edge = edge; + ExecuteOnMainThread(startResize, (gpointer)data); +} + typedef struct JSCallback { void* webview; char* script; @@ -895,6 +926,10 @@ func (w *Window) StartDrag() { C.StartDrag(w.webview, w.asGTKWindow()) } +func (w *Window) StartResize(edge uintptr) { + C.StartResize(w.webview, w.asGTKWindow(), C.GdkWindowEdge(edge)) +} + func (w *Window) Quit() { C.gtk_main_quit() } From 32e9cb30bf769685d59667319edeede605b61d70 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Sep 2022 22:00:01 +0200 Subject: [PATCH 23/36] Bump github.com/labstack/echo/v4 from 4.7.2 to 4.9.0 in /v2 (#1924) --- v2/go.mod | 2 +- v2/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/v2/go.mod b/v2/go.mod index b5533fcb9..4ace88a3b 100644 --- a/v2/go.mod +++ b/v2/go.mod @@ -13,7 +13,7 @@ require ( github.com/imdario/mergo v0.3.12 github.com/jackmordaunt/icns v1.0.0 github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e - github.com/labstack/echo/v4 v4.7.2 + github.com/labstack/echo/v4 v4.9.0 github.com/leaanthony/clir v1.0.4 github.com/leaanthony/debme v1.2.1 github.com/leaanthony/go-ansi-parser v1.0.1 diff --git a/v2/go.sum b/v2/go.sum index 028577eb3..3d961b87e 100644 --- a/v2/go.sum +++ b/v2/go.sum @@ -80,8 +80,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/labstack/echo/v4 v4.7.2 h1:Kv2/p8OaQ+M6Ex4eGimg9b9e6icoxA42JSlOR3msKtI= -github.com/labstack/echo/v4 v4.7.2/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks= +github.com/labstack/echo/v4 v4.9.0 h1:wPOF1CE6gvt/kmbMR4dGzWvHMPT+sAEUJOwOTtvITVY= +github.com/labstack/echo/v4 v4.9.0/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks= github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o= github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= github.com/leaanthony/clir v1.0.4 h1:Dov2y9zWJmZr7CjaCe86lKa4b5CSxskGAt2yBkoDyiU= From 26902503788a4a20a930d1a7ad05a2dfa97c7583 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Z=C3=A1mb=C3=B3=2C=20Levente?= Date: Sat, 1 Oct 2022 07:44:38 +0200 Subject: [PATCH 24/36] Add window transparency for linux (#1926) --- v2/internal/frontend/desktop/linux/window.go | 14 ++++++++++++++ v2/pkg/options/linux/linux.go | 3 ++- website/docs/reference/options.mdx | 8 ++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/v2/internal/frontend/desktop/linux/window.go b/v2/internal/frontend/desktop/linux/window.go index 1f119e526..e7033fe94 100644 --- a/v2/internal/frontend/desktop/linux/window.go +++ b/v2/internal/frontend/desktop/linux/window.go @@ -623,6 +623,17 @@ void SetWindowIcon(GtkWindow* window, const guchar* buf, gsize len) { g_object_unref(loader); } +static void SetWindowTransparency(GtkWidget *widget) +{ + GdkScreen *screen = gtk_widget_get_screen(widget); + GdkVisual *visual = gdk_screen_get_rgba_visual(screen); + + if (visual != NULL && gdk_screen_is_composited(screen)) { + gtk_widget_set_app_paintable(widget, true); + gtk_widget_set_visual(widget, visual); + } +} + */ import "C" import ( @@ -714,6 +725,9 @@ func NewWindow(appoptions *options.App, debug bool) *Window { if appoptions.Linux.Icon != nil { result.SetWindowIcon(appoptions.Linux.Icon) } + if appoptions.Linux.WindowIsTranslucent { + C.SetWindowTransparency(gtkWindow) + } } // Menu diff --git a/v2/pkg/options/linux/linux.go b/v2/pkg/options/linux/linux.go index 2e73064a0..b44186b4c 100644 --- a/v2/pkg/options/linux/linux.go +++ b/v2/pkg/options/linux/linux.go @@ -2,5 +2,6 @@ package linux // Options specific to Linux builds type Options struct { - Icon []byte + Icon []byte + WindowIsTranslucent bool } diff --git a/website/docs/reference/options.mdx b/website/docs/reference/options.mdx index 72cc5f358..723a58708 100644 --- a/website/docs/reference/options.mdx +++ b/website/docs/reference/options.mdx @@ -89,6 +89,7 @@ func main() { }, Linux: &linux.Options{ Icon: icon, + WindowIsTranslucent: false, }, }) if err != nil { @@ -748,3 +749,10 @@ On KDE it should work. The icon should be provided in whatever size it was naturally drawn; that is, don’t scale the image before passing it. Scaling is postponed until the last minute, when the desired final size is known, to allow best quality. + +#### WindowIsTranslucent + +Setting this to `true` will make the window background translucent. Some window managers may ignore it, or result in a black window. + +Name: WindowIsTranslucent
+Type: `bool` \ No newline at end of file From de49b1f1255e233a3c9bdf0cf0b34e24c5409569 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Z=C3=A1mb=C3=B3=2C=20Levente?= Date: Sat, 1 Oct 2022 07:45:37 +0200 Subject: [PATCH 25/36] fix gtk_window_begin_resize_drag's mouse button (#1920) Co-authored-by: Lea Anthony --- v2/internal/frontend/desktop/linux/window.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v2/internal/frontend/desktop/linux/window.go b/v2/internal/frontend/desktop/linux/window.go index e7033fe94..f414c0cf8 100644 --- a/v2/internal/frontend/desktop/linux/window.go +++ b/v2/internal/frontend/desktop/linux/window.go @@ -286,7 +286,7 @@ static gboolean startResize(gpointer data) { return G_SOURCE_REMOVE; } - gtk_window_begin_resize_drag(options->mainwindow, options->edge, 1, xroot, yroot, dragTime); + gtk_window_begin_resize_drag(options->mainwindow, options->edge, mouseButton, xroot, yroot, dragTime); free(data); return G_SOURCE_REMOVE; From 40e326a70870eab1e6f67f7da9dd53aef11ebdaa Mon Sep 17 00:00:00 2001 From: JulioDRF Date: Sat, 1 Oct 2022 05:49:51 +0000 Subject: [PATCH 26/36] Fix binding generation special cases (#1902) * Make binding.go easier to test * Fix non-deterministic namespace order for bindings * Add binding tests * Fix nested import structs, non-string map keys, and escape invalid variable names Co-authored-by: Lea Anthony --- v2/internal/binding/binding.go | 33 +++++-- .../binding_test/binding_escapedname_test.go | 32 +++++++ .../binding_test/binding_importedmap_test.go | 94 ++++++++++++++++++ .../binding_importedslice_test.go | 94 ++++++++++++++++++ .../binding_importedstruct_test.go | 95 +++++++++++++++++++ .../binding_test/binding_nestedfield_test.go | 63 ++++++++++++ .../binding_nonstringmapkey_test.go | 32 +++++++ .../binding_test/binding_singlefield_test.go | 32 +++++++ .../binding/binding_test/binding_test.go | 51 ++++++++++ .../binding_test_import.go | 15 +++ .../binding_nestedimport.go | 5 + v2/internal/binding/reflect.go | 5 + v2/internal/typescriptify/typescriptify.go | 73 ++++++++++---- 13 files changed, 600 insertions(+), 24 deletions(-) create mode 100644 v2/internal/binding/binding_test/binding_escapedname_test.go create mode 100644 v2/internal/binding/binding_test/binding_importedmap_test.go create mode 100644 v2/internal/binding/binding_test/binding_importedslice_test.go create mode 100644 v2/internal/binding/binding_test/binding_importedstruct_test.go create mode 100644 v2/internal/binding/binding_test/binding_nestedfield_test.go create mode 100644 v2/internal/binding/binding_test/binding_nonstringmapkey_test.go create mode 100644 v2/internal/binding/binding_test/binding_singlefield_test.go create mode 100644 v2/internal/binding/binding_test/binding_test.go create mode 100644 v2/internal/binding/binding_test/binding_test_import/binding_test_import.go create mode 100644 v2/internal/binding/binding_test/binding_test_import/binding_test_nestedimport/binding_nestedimport.go diff --git a/v2/internal/binding/binding.go b/v2/internal/binding/binding.go index a27d1d038..f972b7179 100755 --- a/v2/internal/binding/binding.go +++ b/v2/internal/binding/binding.go @@ -8,6 +8,7 @@ import ( "path/filepath" "reflect" "runtime" + "sort" "strings" "github.com/wailsapp/wails/v2/internal/typescriptify" @@ -83,7 +84,7 @@ func (b *Bindings) ToJSON() (string, error) { return b.db.ToJSON() } -func (b *Bindings) WriteModels(modelsDir string) error { +func (b *Bindings) GenerateModels() ([]byte, error) { models := map[string]string{} var seen slicer.StringSlicer allStructNames := b.getAllStructNames() @@ -102,15 +103,23 @@ func (b *Bindings) WriteModels(modelsDir string) error { } str, err := w.Convert(nil) if err != nil { - return err + return nil, err } thisPackageCode += str seen.AddSlice(w.GetGeneratedStructs()) models[packageName] = thisPackageCode } + // Sort the package names first to make the output deterministic + sortedPackageNames := make([]string, 0) + for packageName := range models { + sortedPackageNames = append(sortedPackageNames, packageName) + } + sort.Strings(sortedPackageNames) + var modelsData bytes.Buffer - for packageName, modelData := range models { + for _, packageName := range sortedPackageNames { + modelData := models[packageName] if strings.TrimSpace(modelData) == "" { continue } @@ -121,14 +130,22 @@ func (b *Bindings) WriteModels(modelsDir string) error { } modelsData.WriteString("\n}\n\n") } + return modelsData.Bytes(), nil +} +func (b *Bindings) WriteModels(modelsDir string) error { + + modelsData, err := b.GenerateModels() + if err != nil { + return err + } // Don't write if we don't have anything - if len(modelsData.Bytes()) == 0 { + if len(modelsData) == 0 { return nil } filename := filepath.Join(modelsDir, "models.ts") - err := os.WriteFile(filename, modelsData.Bytes(), 0755) + err = os.WriteFile(filename, modelsData, 0755) if err != nil { return err } @@ -147,7 +164,7 @@ func (b *Bindings) AddStructToGenerateTS(packageName string, structName string, // Iterate this struct and add any struct field references structType := reflect.TypeOf(s) - if structType.Kind() == reflect.Ptr { + if hasElements(structType) { structType = structType.Elem() } @@ -169,11 +186,11 @@ func (b *Bindings) AddStructToGenerateTS(packageName string, structName string, s := reflect.Indirect(a).Interface() b.AddStructToGenerateTS(pName, sName, s) } - } else if kind == reflect.Ptr && field.Type.Elem().Kind() == reflect.Struct { + } else if hasElements(field.Type) && field.Type.Elem().Kind() == reflect.Struct { if !field.IsExported() { continue } - fqname := field.Type.String() + fqname := field.Type.Elem().String() sName := strings.Split(fqname, ".")[1] pName := getPackageName(fqname) typ := field.Type.Elem() diff --git a/v2/internal/binding/binding_test/binding_escapedname_test.go b/v2/internal/binding/binding_test/binding_escapedname_test.go new file mode 100644 index 000000000..1bf6ce3ad --- /dev/null +++ b/v2/internal/binding/binding_test/binding_escapedname_test.go @@ -0,0 +1,32 @@ +package binding_test + +type EscapedName struct { + Name string `json:"n.a.m.e"` +} + +func (s EscapedName) Get() EscapedName { + return s +} + +var EscapedNameTest = BindingTest{ + name: "EscapedName", + structs: []interface{}{ + &EscapedName{}, + }, + exemptions: nil, + shouldError: false, + want: ` +export namespace binding_test { + export class EscapedName { + "n.a.m.e": string; + static createFrom(source: any = {}) { + return new EscapedName(source); + } + constructor(source: any = {}) { + if ('string' === typeof source) source = JSON.parse(source); + this["n.a.m.e"] = source["n.a.m.e"]; + } + } +} +`, +} diff --git a/v2/internal/binding/binding_test/binding_importedmap_test.go b/v2/internal/binding/binding_test/binding_importedmap_test.go new file mode 100644 index 000000000..54fb261a8 --- /dev/null +++ b/v2/internal/binding/binding_test/binding_importedmap_test.go @@ -0,0 +1,94 @@ +package binding_test + +import "github.com/wailsapp/wails/v2/internal/binding/binding_test/binding_test_import" + +type ImportedMap struct { + AMapWrapperContainer binding_test_import.AMapWrapper `json:"AMapWrapperContainer"` +} + +func (s ImportedMap) Get() ImportedMap { + return s +} + +var ImportedMapTest = BindingTest{ + name: "ImportedMap", + structs: []interface{}{ + &ImportedMap{}, + }, + exemptions: nil, + shouldError: false, + want: ` +export namespace binding_test { + export class ImportedMap { + AMapWrapperContainer: binding_test_import.AMapWrapper; + static createFrom(source: any = {}) { + return new ImportedMap(source); + } + constructor(source: any = {}) { + if ('string' === typeof source) source = JSON.parse(source); + this.AMapWrapperContainer = this.convertValues(source["AMapWrapperContainer"], binding_test_import.AMapWrapper); + } + convertValues(a: any, classs: any, asMap: boolean = false): any { + if (!a) { + return a; + } + if (a.slice) { + return (a as any[]).map(elem => this.convertValues(elem, classs)); + } else if ("object" === typeof a) { + if (asMap) { + for (const key of Object.keys(a)) { + a[key] = new classs(a[key]); + } + return a; + } + return new classs(a); + } + return a; + } + } +} + +export namespace binding_test_import { + export class AMapWrapper { + AMap: {[key: string]: binding_test_nestedimport.A}; + static createFrom(source: any = {}) { + return new AMapWrapper(source); + } + constructor(source: any = {}) { + if ('string' === typeof source) source = JSON.parse(source); + this.AMap = this.convertValues(source["AMap"], binding_test_nestedimport.A, true); + } + convertValues(a: any, classs: any, asMap: boolean = false): any { + if (!a) { + return a; + } + if (a.slice) { + return (a as any[]).map(elem => this.convertValues(elem, classs)); + } else if ("object" === typeof a) { + if (asMap) { + for (const key of Object.keys(a)) { + a[key] = new classs(a[key]); + } + return a; + } + return new classs(a); + } + return a; + } + } +} + +export namespace binding_test_nestedimport { + export class A { + A: string; + static createFrom(source: any = {}) { + return new A(source); + } + constructor(source: any = {}) { + if ('string' === typeof source) source = JSON.parse(source); + this.A = source["A"]; + } + } +} +`, +} diff --git a/v2/internal/binding/binding_test/binding_importedslice_test.go b/v2/internal/binding/binding_test/binding_importedslice_test.go new file mode 100644 index 000000000..b4a63689c --- /dev/null +++ b/v2/internal/binding/binding_test/binding_importedslice_test.go @@ -0,0 +1,94 @@ +package binding_test + +import "github.com/wailsapp/wails/v2/internal/binding/binding_test/binding_test_import" + +type ImportedSlice struct { + ASliceWrapperContainer binding_test_import.ASliceWrapper `json:"ASliceWrapperContainer"` +} + +func (s ImportedSlice) Get() ImportedSlice { + return s +} + +var ImportedSliceTest = BindingTest{ + name: "ImportedSlice", + structs: []interface{}{ + &ImportedSlice{}, + }, + exemptions: nil, + shouldError: false, + want: ` +export namespace binding_test { + export class ImportedSlice { + ASliceWrapperContainer: binding_test_import.ASliceWrapper; + static createFrom(source: any = {}) { + return new ImportedSlice(source); + } + constructor(source: any = {}) { + if ('string' === typeof source) source = JSON.parse(source); + this.ASliceWrapperContainer = this.convertValues(source["ASliceWrapperContainer"], binding_test_import.ASliceWrapper); + } + convertValues(a: any, classs: any, asMap: boolean = false): any { + if (!a) { + return a; + } + if (a.slice) { + return (a as any[]).map(elem => this.convertValues(elem, classs)); + } else if ("object" === typeof a) { + if (asMap) { + for (const key of Object.keys(a)) { + a[key] = new classs(a[key]); + } + return a; + } + return new classs(a); + } + return a; + } + } +} + +export namespace binding_test_import { + export class ASliceWrapper { + ASlice: binding_test_nestedimport.A[]; + static createFrom(source: any = {}) { + return new ASliceWrapper(source); + } + constructor(source: any = {}) { + if ('string' === typeof source) source = JSON.parse(source); + this.ASlice = this.convertValues(source["ASlice"], binding_test_nestedimport.A); + } + convertValues(a: any, classs: any, asMap: boolean = false): any { + if (!a) { + return a; + } + if (a.slice) { + return (a as any[]).map(elem => this.convertValues(elem, classs)); + } else if ("object" === typeof a) { + if (asMap) { + for (const key of Object.keys(a)) { + a[key] = new classs(a[key]); + } + return a; + } + return new classs(a); + } + return a; + } + } +} + +export namespace binding_test_nestedimport { + export class A { + A: string; + static createFrom(source: any = {}) { + return new A(source); + } + constructor(source: any = {}) { + if ('string' === typeof source) source = JSON.parse(source); + this.A = source["A"]; + } + } +} +`, +} diff --git a/v2/internal/binding/binding_test/binding_importedstruct_test.go b/v2/internal/binding/binding_test/binding_importedstruct_test.go new file mode 100644 index 000000000..1629be9fa --- /dev/null +++ b/v2/internal/binding/binding_test/binding_importedstruct_test.go @@ -0,0 +1,95 @@ +package binding_test + +import "github.com/wailsapp/wails/v2/internal/binding/binding_test/binding_test_import" + +type ImportedStruct struct { + AWrapperContainer binding_test_import.AWrapper `json:"AWrapperContainer"` +} + +func (s ImportedStruct) Get() ImportedStruct { + return s +} + +var ImportedStructTest = BindingTest{ + name: "ImportedStruct", + structs: []interface{}{ + &ImportedStruct{}, + }, + exemptions: nil, + shouldError: false, + want: ` +export namespace binding_test { + export class ImportedStruct { + AWrapperContainer: binding_test_import.AWrapper; + static createFrom(source: any = {}) { + return new ImportedStruct(source); + } + constructor(source: any = {}) { + if ('string' === typeof source) source = JSON.parse(source); + this.AWrapperContainer = this.convertValues(source["AWrapperContainer"], binding_test_import.AWrapper); + } + convertValues(a: any, classs: any, asMap: boolean = false): any { + if (!a) { + return a; + } + + if (a.slice) { + return (a as any[]).map(elem => this.convertValues(elem, classs)); + } else if ("object" === typeof a) { + if (asMap) { + for (const key of Object.keys(a)) { + a[key] = new classs(a[key]); + } + return a; + } + return new classs(a); + } + return a; + } + } +} + +export namespace binding_test_import { + export class AWrapper { + AWrapper: binding_test_nestedimport.A; + static createFrom(source: any = {}) { + return new AWrapper(source); + } + constructor(source: any = {}) { + if ('string' === typeof source) source = JSON.parse(source); + this.AWrapper = this.convertValues(source["AWrapper"], binding_test_nestedimport.A); + } + convertValues(a: any, classs: any, asMap: boolean = false): any { + if (!a) { + return a; + } + if (a.slice) { + return (a as any[]).map(elem => this.convertValues(elem, classs)); + } else if ("object" === typeof a) { + if (asMap) { + for (const key of Object.keys(a)) { + a[key] = new classs(a[key]); + } + return a; + } + return new classs(a); + } + return a; + } + } +} + +export namespace binding_test_nestedimport { + export class A { + A: string; + static createFrom(source: any = {}) { + return new A(source); + } + constructor(source: any = {}) { + if ('string' === typeof source) source = JSON.parse(source); + this.A = source["A"]; + } + } +} +`, +} diff --git a/v2/internal/binding/binding_test/binding_nestedfield_test.go b/v2/internal/binding/binding_test/binding_nestedfield_test.go new file mode 100644 index 000000000..c2e4fcf9f --- /dev/null +++ b/v2/internal/binding/binding_test/binding_nestedfield_test.go @@ -0,0 +1,63 @@ +package binding_test + +type As struct { + B Bs `json:"b"` +} + +type Bs struct { + Name string `json:"name"` +} + +func (a As) Get() As { + return a +} + +var NestedFieldTest = BindingTest{ + name: "NestedField", + structs: []interface{}{ + &As{}, + }, + exemptions: nil, + shouldError: false, + want: ` +export namespace binding_test { + export class Bs { + name: string; + static createFrom(source: any = {}) { + return new Bs(source); + } + constructor(source: any = {}) { + if ('string' === typeof source) source = JSON.parse(source); + this.name = source["name"]; + } + } + export class As { + b: Bs; + static createFrom(source: any = {}) { + return new As(source); + } + constructor(source: any = {}) { + if ('string' === typeof source) source = JSON.parse(source); + this.b = this.convertValues(source["b"], Bs); + } + convertValues(a: any, classs: any, asMap: boolean = false): any { + if (!a) { + return a; + } + if (a.slice) { + return (a as any[]).map(elem => this.convertValues(elem, classs)); + } else if ("object" === typeof a) { + if (asMap) { + for (const key of Object.keys(a)) { + a[key] = new classs(a[key]); + } + return a; + } + return new classs(a); + } + return a; + } + } +} +`, +} diff --git a/v2/internal/binding/binding_test/binding_nonstringmapkey_test.go b/v2/internal/binding/binding_test/binding_nonstringmapkey_test.go new file mode 100644 index 000000000..37a61dd29 --- /dev/null +++ b/v2/internal/binding/binding_test/binding_nonstringmapkey_test.go @@ -0,0 +1,32 @@ +package binding_test + +type NonStringMapKey struct { + NumberMap map[uint]any `json:"numberMap"` +} + +func (s NonStringMapKey) Get() NonStringMapKey { + return s +} + +var NonStringMapKeyTest = BindingTest{ + name: "NonStringMapKey", + structs: []interface{}{ + &NonStringMapKey{}, + }, + exemptions: nil, + shouldError: false, + want: ` +export namespace binding_test { + export class NonStringMapKey { + numberMap: {[key: number]: any}; + static createFrom(source: any = {}) { + return new NonStringMapKey(source); + } + constructor(source: any = {}) { + if ('string' === typeof source) source = JSON.parse(source); + this.numberMap = source["numberMap"]; + } + } +} +`, +} diff --git a/v2/internal/binding/binding_test/binding_singlefield_test.go b/v2/internal/binding/binding_test/binding_singlefield_test.go new file mode 100644 index 000000000..2919ab29e --- /dev/null +++ b/v2/internal/binding/binding_test/binding_singlefield_test.go @@ -0,0 +1,32 @@ +package binding_test + +type SingleField struct { + Name string `json:"name"` +} + +func (s SingleField) Get() SingleField { + return s +} + +var SingleFieldTest = BindingTest{ + name: "SingleField", + structs: []interface{}{ + &SingleField{}, + }, + exemptions: nil, + shouldError: false, + want: ` +export namespace binding_test { + export class SingleField { + name: string; + static createFrom(source: any = {}) { + return new SingleField(source); + } + constructor(source: any = {}) { + if ('string' === typeof source) source = JSON.parse(source); + this.name = source["name"]; + } + } +} +`, +} diff --git a/v2/internal/binding/binding_test/binding_test.go b/v2/internal/binding/binding_test/binding_test.go new file mode 100644 index 000000000..f41507112 --- /dev/null +++ b/v2/internal/binding/binding_test/binding_test.go @@ -0,0 +1,51 @@ +package binding_test + +import ( + "reflect" + "strings" + "testing" + + "github.com/stretchr/testify/require" + "github.com/wailsapp/wails/v2/internal/binding" + "github.com/wailsapp/wails/v2/internal/logger" +) + +type BindingTest struct { + name string + structs []interface{} + exemptions []interface{} + want string + shouldError bool +} + +func TestBindings_GenerateModels(t *testing.T) { + + tests := []BindingTest{ + EscapedNameTest, + ImportedStructTest, + ImportedSliceTest, + ImportedMapTest, + NestedFieldTest, + NonStringMapKeyTest, + SingleFieldTest, + } + + testLogger := &logger.Logger{} + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + b := binding.NewBindings(testLogger, tt.structs, tt.exemptions, false) + for _, s := range tt.structs { + err := b.Add(s) + require.NoError(t, err) + } + got, err := b.GenerateModels() + if (err != nil) != tt.shouldError { + t.Errorf("GenerateModels() error = %v, shouldError %v", err, tt.shouldError) + return + } + if !reflect.DeepEqual(strings.Fields(string(got)), strings.Fields(tt.want)) { + t.Errorf("GenerateModels() got = %v, want %v", string(got), tt.want) + } + }) + } +} diff --git a/v2/internal/binding/binding_test/binding_test_import/binding_test_import.go b/v2/internal/binding/binding_test/binding_test_import/binding_test_import.go new file mode 100644 index 000000000..6b99d43be --- /dev/null +++ b/v2/internal/binding/binding_test/binding_test_import/binding_test_import.go @@ -0,0 +1,15 @@ +package binding_test_import + +import "github.com/wailsapp/wails/v2/internal/binding/binding_test/binding_test_import/binding_test_nestedimport" + +type AWrapper struct { + AWrapper binding_test_nestedimport.A `json:"AWrapper"` +} + +type ASliceWrapper struct { + ASlice []binding_test_nestedimport.A `json:"ASlice"` +} + +type AMapWrapper struct { + AMap map[string]binding_test_nestedimport.A `json:"AMap"` +} diff --git a/v2/internal/binding/binding_test/binding_test_import/binding_test_nestedimport/binding_nestedimport.go b/v2/internal/binding/binding_test/binding_test_import/binding_test_nestedimport/binding_nestedimport.go new file mode 100644 index 000000000..31c70ad3f --- /dev/null +++ b/v2/internal/binding/binding_test/binding_test_import/binding_test_nestedimport/binding_nestedimport.go @@ -0,0 +1,5 @@ +package binding_test_nestedimport + +type A struct { + A string `json:"A"` +} diff --git a/v2/internal/binding/reflect.go b/v2/internal/binding/reflect.go index 6572407f9..deef09ffe 100755 --- a/v2/internal/binding/reflect.go +++ b/v2/internal/binding/reflect.go @@ -165,3 +165,8 @@ func getPackageName(in string) string { result = strings.ReplaceAll(result, "*", "") return result } + +func hasElements(typ reflect.Type) bool { + kind := typ.Kind() + return kind == reflect.Ptr || kind == reflect.Array || kind == reflect.Slice || kind == reflect.Map +} diff --git a/v2/internal/typescriptify/typescriptify.go b/v2/internal/typescriptify/typescriptify.go index 8419801e2..35ee3c100 100644 --- a/v2/internal/typescriptify/typescriptify.go +++ b/v2/internal/typescriptify/typescriptify.go @@ -3,14 +3,16 @@ package typescriptify import ( "bufio" "fmt" - "github.com/leaanthony/slicer" "io/ioutil" "os" "path" "reflect" + "regexp" "strings" "time" + "github.com/leaanthony/slicer" + "github.com/tkrajina/go-reflector/reflector" ) @@ -34,6 +36,7 @@ const ( } return a; }` + jsVariableNameRegex = `^([A-Z]|[a-z]|\$|_)([A-Z]|[a-z]|[0-9]|\$|_)*$` ) // TypeOptions overrides options set by `ts_*` tags. @@ -266,20 +269,34 @@ func (t *typeScriptClassBuilder) AddMapField(fieldName string, field reflect.Str if valueType.Kind() == reflect.Ptr { valueTypeName = valueType.Elem().Name() } + if valueType.Kind() == reflect.Struct && differentNamespaces(t.namespace, valueType) { + valueTypeName = valueType.String() + } strippedFieldName := strings.ReplaceAll(fieldName, "?", "") + isOptional := strings.HasSuffix(fieldName, "?") - keyTypeStr := keyType.Name() - // Key should always be string, no need for this: - // _, isSimple := t.types[keyType.Kind()] - // if !isSimple { - // keyTypeStr = t.prefix + keyType.Name() + t.suffix - // } + keyTypeStr := "" + // Key should always be a JS primitive. JS will read it as a string either way. + if typeStr, isSimple := t.types[keyType.Kind()]; isSimple { + keyTypeStr = typeStr + } else { + keyTypeStr = t.types[reflect.String] + } + var dotField string + if regexp.MustCompile(jsVariableNameRegex).Match([]byte(strippedFieldName)) { + dotField = fmt.Sprintf(".%s", strippedFieldName) + } else { + dotField = fmt.Sprintf(`["%s"]`, strippedFieldName) + if isOptional { + fieldName = fmt.Sprintf(`"%s"?`, strippedFieldName) + } + } t.fields = append(t.fields, fmt.Sprintf("%s%s: {[key: %s]: %s};", t.indent, fieldName, keyTypeStr, valueTypeName)) if valueType.Kind() == reflect.Struct { - t.constructorBody = append(t.constructorBody, fmt.Sprintf("%s%sthis.%s = this.convertValues(source[\"%s\"], %s, true);", t.indent, t.indent, strippedFieldName, strippedFieldName, t.prefix+valueTypeName+t.suffix)) + t.constructorBody = append(t.constructorBody, fmt.Sprintf("%s%sthis%s = this.convertValues(source[\"%s\"], %s, true);", t.indent, t.indent, dotField, strippedFieldName, t.prefix+valueTypeName+t.suffix)) } else { - t.constructorBody = append(t.constructorBody, fmt.Sprintf("%s%sthis.%s = source[\"%s\"];", t.indent, t.indent, strippedFieldName, strippedFieldName)) + t.constructorBody = append(t.constructorBody, fmt.Sprintf("%s%sthis%s = source[\"%s\"];", t.indent, t.indent, dotField, strippedFieldName)) } } @@ -571,11 +588,8 @@ func (t *TypeScriptify) convertType(depth int, typeOf reflect.Type, customCode m return "", nil } t.logf(depth, "Converting type %s", typeOf.String()) - if strings.ContainsRune(typeOf.String(), '.') { - namespace := strings.Split(typeOf.String(), ".")[0] - if namespace != t.Namespace { - return "", nil - } + if differentNamespaces(t.Namespace, typeOf) { + return "", nil } t.alreadyConverted[typeOf.String()] = true @@ -829,17 +843,34 @@ func (t *typeScriptClassBuilder) AddStructField(fieldName string, field reflect. func (t *typeScriptClassBuilder) AddArrayOfStructsField(fieldName string, field reflect.StructField, arrayDepth int) { fieldType := field.Type.Elem().Name() + if differentNamespaces(t.namespace, field.Type.Elem()) { + fieldType = field.Type.Elem().String() + } strippedFieldName := strings.ReplaceAll(fieldName, "?", "") t.addField(fieldName, fmt.Sprint(t.prefix+fieldType+t.suffix, strings.Repeat("[]", arrayDepth)), false) t.addInitializerFieldLine(strippedFieldName, fmt.Sprintf("this.convertValues(source[\"%s\"], %s)", strippedFieldName, t.prefix+fieldType+t.suffix)) } func (t *typeScriptClassBuilder) addInitializerFieldLine(fld, initializer string) { - t.createFromMethodBody = append(t.createFromMethodBody, fmt.Sprint(t.indent, t.indent, "result.", fld, " = ", initializer, ";")) - t.constructorBody = append(t.constructorBody, fmt.Sprint(t.indent, t.indent, "this.", fld, " = ", initializer, ";")) + var dotField string + if regexp.MustCompile(jsVariableNameRegex).Match([]byte(fld)) { + dotField = fmt.Sprintf(".%s", fld) + } else { + dotField = fmt.Sprintf(`["%s"]`, fld) + } + t.createFromMethodBody = append(t.createFromMethodBody, fmt.Sprint(t.indent, t.indent, "result", dotField, " = ", initializer, ";")) + t.constructorBody = append(t.constructorBody, fmt.Sprint(t.indent, t.indent, "this", dotField, " = ", initializer, ";")) } func (t *typeScriptClassBuilder) addField(fld, fldType string, isAnyType bool) { + isOptional := strings.HasSuffix(fld, "?") + strippedFieldName := strings.ReplaceAll(fld, "?", "") + if !regexp.MustCompile(jsVariableNameRegex).Match([]byte(strippedFieldName)) { + fld = fmt.Sprintf(`"%s"`, fld) + if isOptional { + fld += "?" + } + } if isAnyType { t.fields = append(t.fields, fmt.Sprint(t.indent, "// Go type: ", fldType, "\n", t.indent, fld, ": any;")) } else { @@ -860,3 +891,13 @@ func getStructFQN(in string) string { result = strings.ReplaceAll(result, "*", "") return result } + +func differentNamespaces(namespace string, typeOf reflect.Type) bool { + if strings.ContainsRune(typeOf.String(), '.') { + typeNamespace := strings.Split(typeOf.String(), ".")[0] + if namespace != typeNamespace { + return true + } + } + return false +} From 6a3b89d212fb23e47b24e10ea21aa95988d04b90 Mon Sep 17 00:00:00 2001 From: Lea Anthony Date: Sat, 1 Oct 2022 19:03:20 +1000 Subject: [PATCH 27/36] fix: exemption typo --- v2/internal/binding/binding.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v2/internal/binding/binding.go b/v2/internal/binding/binding.go index f972b7179..f50b633b4 100755 --- a/v2/internal/binding/binding.go +++ b/v2/internal/binding/binding.go @@ -36,7 +36,7 @@ func NewBindings(logger *logger.Logger, structPointersToBind []interface{}, exem } for _, exemption := range exemptions { - if exemptions == nil { + if exemption == nil { continue } name := runtime.FuncForPC(reflect.ValueOf(exemption).Pointer()).Name() From ef32ea2575d7ecb07b780387f210ab772d72db07 Mon Sep 17 00:00:00 2001 From: Misite Bao Date: Sun, 2 Oct 2022 18:03:11 +0800 Subject: [PATCH 28/36] fix: remove the `.git` directory in the template (#1929) fixed: https://github.com/wailsapp/wails/issues/1928 --- v2/cmd/wails/internal/commands/initialise/initialise.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/v2/cmd/wails/internal/commands/initialise/initialise.go b/v2/cmd/wails/internal/commands/initialise/initialise.go index f5c56a1cb..0fa131873 100644 --- a/v2/cmd/wails/internal/commands/initialise/initialise.go +++ b/v2/cmd/wails/internal/commands/initialise/initialise.go @@ -189,6 +189,12 @@ func initProject(options *templates.Options, quiet bool, ciMode bool) error { updateReplaceLine(workspace) } + // Remove the `.git`` directory in the template project + err = os.RemoveAll(".git") + if err != nil { + return err + } + if options.InitGit { err = initGit(options) if err != nil { From f3cbd383a32c44b615adb2b5da20abdc12b6665b Mon Sep 17 00:00:00 2001 From: Artur S Date: Sun, 2 Oct 2022 13:38:58 +0200 Subject: [PATCH 29/36] add react-ts-vite-tailwind template (#1930) --- website/docs/community/templates.mdx | 1 + 1 file changed, 1 insertion(+) diff --git a/website/docs/community/templates.mdx b/website/docs/community/templates.mdx index 5b0cddafe..6bc78f647 100644 --- a/website/docs/community/templates.mdx +++ b/website/docs/community/templates.mdx @@ -36,6 +36,7 @@ If you are unsure about a template, inspect `package.json` and `wails.json` for - [wails-react-template](https://github.com/AlienRecall/wails-react-template) - A template using reactjs - [wails-react-template](https://github.com/flin7/wails-react-template) - A minimal template for React that supports live development - [wails-template-nextjs](https://github.com/LGiki/wails-template-nextjs) - A template using Next.js and TypeScript +- [wails-vite-react-ts-tailwind-template](https://github.com/hotafrika/wails-vite-react-ts-tailwind-template) - A template for React + TypeScript + Vite + TailwindCSS ## Svelte From 130f4cc36a72cdf4d39bef67f0a78aca1cf8a6fd Mon Sep 17 00:00:00 2001 From: Misite Bao Date: Tue, 4 Oct 2022 16:22:35 +0800 Subject: [PATCH 30/36] docs: sync documents (#1936) --- .../current/community/links.mdx | 3 + .../current/community/showcase/riftshare.mdx | 2 +- .../current/community/templates.mdx | 5 +- .../current/guides/dynamic-assets.mdx | 4 +- .../current/guides/ides.mdx | 152 ++++++++++-------- .../current/reference/menus.mdx | 2 +- .../current/reference/options.mdx | 7 + .../current/community/links.mdx | 3 + .../current/community/templates.mdx | 1 + .../current/reference/options.mdx | 7 + 10 files changed, 110 insertions(+), 76 deletions(-) diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/current/community/links.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/current/community/links.mdx index 4a3a89e87..3f9ebf2fc 100644 --- a/website/i18n/ja/docusaurus-plugin-content-docs/current/community/links.mdx +++ b/website/i18n/ja/docusaurus-plugin-content-docs/current/community/links.mdx @@ -21,3 +21,6 @@ The [definitive list](https://github.com/wailsapp/awesome-wails) of links relate - [Twitter](https://twitter.com/wailsapp) - [Wails Chinese Community QQ Group](https://qm.qq.com/cgi-bin/qm/qr?k=PmIURne5hFGNd7QWzW5qd6FV-INEjNJv&jump_from=webapi) - Group number: 1067173054 + +## Other Tutorials and Articles +- [Building of Bulletin Board](https://blog.customct.com/building-bulletin-board) diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/current/community/showcase/riftshare.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/current/community/showcase/riftshare.mdx index c86691f21..9928b4785 100644 --- a/website/i18n/ja/docusaurus-plugin-content-docs/current/community/showcase/riftshare.mdx +++ b/website/i18n/ja/docusaurus-plugin-content-docs/current/community/showcase/riftshare.mdx @@ -9,7 +9,7 @@ Easy, Secure, and Free file sharing for everyone. Learn more at [Riftshare.app](https://riftshare.app) -## 機能 +## Features - Easy secure file sharing between computers both in the local network and through the internet - Supports sending files or directories securely through the [magic wormhole protocol](https://magic-wormhole.readthedocs.io/en/latest/) diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/current/community/templates.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/current/community/templates.mdx index 3c24c5d7e..de98ef05f 100644 --- a/website/i18n/ja/docusaurus-plugin-content-docs/current/community/templates.mdx +++ b/website/i18n/ja/docusaurus-plugin-content-docs/current/community/templates.mdx @@ -37,6 +37,7 @@ If you are unsure about a template, inspect `package.json` and `wails.json` for - [wails-react-template](https://github.com/AlienRecall/wails-react-template) - A template using reactjs - [wails-react-template](https://github.com/flin7/wails-react-template) - A minimal template for React that supports live development - [wails-template-nextjs](https://github.com/LGiki/wails-template-nextjs) - A template using Next.js and TypeScript +- [wails-vite-react-ts-tailwind-template](https://github.com/hotafrika/wails-vite-react-ts-tailwind-template) - A template for React + TypeScript + Vite + TailwindCSS ## Svelte @@ -49,6 +50,6 @@ If you are unsure about a template, inspect `package.json` and `wails.json` for - [wails-elm-template](https://github.com/benjamin-thomas/wails-elm-template) - Develop your GUI app with functional programming and a **snappy** hot-reload setup :tada: :rocket: -## Pure JavaScript (Vanilla) +## ピュアJavaScript (バニラ) -- [wails-pure-js-template](https://github.com/KiddoV/wails-pure-js-template) - A template with nothing but just basic JavaScript, HTML, and CSS +- [wails-pure-js-template](https://github.com/KiddoV/wails-pure-js-template) - 基本的なJavaScript、HTML、CSSのみを含むテンプレート diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/current/guides/dynamic-assets.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/current/guides/dynamic-assets.mdx index 40a779381..e4c199594 100644 --- a/website/i18n/ja/docusaurus-plugin-content-docs/current/guides/dynamic-assets.mdx +++ b/website/i18n/ja/docusaurus-plugin-content-docs/current/guides/dynamic-assets.mdx @@ -106,13 +106,13 @@ However, if we request `go.mod`, we will see the following output: This technique can be used to load images directly into the page. If we updated our default vanilla template and replaced the logo image: ```html - + ``` with: ```html - + ``` Then we would see the following: diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/current/guides/ides.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/current/guides/ides.mdx index 5187065ad..7649030a2 100644 --- a/website/i18n/ja/docusaurus-plugin-content-docs/current/guides/ides.mdx +++ b/website/i18n/ja/docusaurus-plugin-content-docs/current/guides/ides.mdx @@ -21,36 +21,44 @@ The 2 files generated are `tasks.json` and `launch.json`. Below are the files ge ```json title="tasks.json" { - "version": "2.0.0", - "tasks": [ - { - "label": "build", - "type": "shell", - "options": { - "cwd": "${workspaceFolder}" - }, - "command": "go", - "args": ["build", "-tags", "dev", "-gcflags", "all=-N -l", "-o", "build/bin/myproject.exe"] - }, - ] + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "type": "shell", + "options": { + "cwd": "${workspaceFolder}" + }, + "command": "go", + "args": [ + "build", + "-tags", + "dev", + "-gcflags", + "all=-N -l", + "-o", + "build/bin/myproject.exe" + ] + } + ] } ``` ```json title="launch.json" { - "version": "0.2.0", - "configurations": [ - { - "name": "Wails: Debug myproject", - "type": "go", - "request": "launch", - "mode": "exec", - "program": "${workspaceFolder}/build/bin/myproject.exe", - "preLaunchTask": "build", - "cwd": "${workspaceFolder}", - "env": {} - }, - ] + "version": "0.2.0", + "configurations": [ + { + "name": "Wails: Debug myproject", + "type": "go", + "request": "launch", + "mode": "exec", + "program": "${workspaceFolder}/build/bin/myproject.exe", + "preLaunchTask": "build", + "cwd": "${workspaceFolder}", + "env": {} + } + ] } ``` @@ -60,51 +68,55 @@ The `tasks.json` file is simple for the default project as there is no `npm inst ```json title="tasks.json" { - "version": "2.0.0", - "tasks": [ - { - "label": "npm install", - "type": "npm", - "script": "install", - "options": { - "cwd": "${workspaceFolder}/frontend" - }, - "presentation": { - "clear": true, - "panel": "shared", - "showReuseMessage": false - }, - "problemMatcher": [] - }, - { - "label": "npm run build", - "type": "npm", - "script": "build", - "options": { - "cwd": "${workspaceFolder}/frontend" - }, - "presentation": { - "clear": true, - "panel": "shared", - "showReuseMessage": false - }, - "problemMatcher": [] - }, - { - "label": "build", - "type": "shell", - "options": { - "cwd": "${workspaceFolder}" - }, - "command": "go", - "args": ["build", "-tags", "dev", "-gcflags", "all=-N -l", "-o", "build/bin/vscode.exe"], - "dependsOn":[ - "npm install", - "npm run build" - ] - - }, - ] + "version": "2.0.0", + "tasks": [ + { + "label": "npm install", + "type": "npm", + "script": "install", + "options": { + "cwd": "${workspaceFolder}/frontend" + }, + "presentation": { + "clear": true, + "panel": "shared", + "showReuseMessage": false + }, + "problemMatcher": [] + }, + { + "label": "npm run build", + "type": "npm", + "script": "build", + "options": { + "cwd": "${workspaceFolder}/frontend" + }, + "presentation": { + "clear": true, + "panel": "shared", + "showReuseMessage": false + }, + "problemMatcher": [] + }, + { + "label": "build", + "type": "shell", + "options": { + "cwd": "${workspaceFolder}" + }, + "command": "go", + "args": [ + "build", + "-tags", + "dev", + "-gcflags", + "all=-N -l", + "-o", + "build/bin/vscode.exe" + ], + "dependsOn": ["npm install", "npm run build"] + } + ] } ``` diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/menus.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/menus.mdx index 80ae91834..18020ddb8 100644 --- a/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/menus.mdx +++ b/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/menus.mdx @@ -223,7 +223,7 @@ Roles are currently supported on Mac only. A menu item may have a role, which is essentially a pre-defined menu item. We currently support the following roles: -| Role | Description | +| ロール | Description | | ------------ | ------------------------------------------------------------------------ | | AppMenuRole | The standard Mac application menu. Can be created using `menu.AppMenu()` | | EditMenuRole | The standard Mac edit menu. Can be created using `menu.EditMenu()` | diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/options.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/options.mdx index dc21f8d1e..4e4db6f2b 100644 --- a/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/options.mdx +++ b/website/i18n/ja/docusaurus-plugin-content-docs/current/reference/options.mdx @@ -88,6 +88,7 @@ func main() { }, Linux: &linux.Options{ Icon: icon, + WindowIsTranslucent: false, }, }) if err != nil { @@ -664,3 +665,9 @@ Some window managers or desktop environments may also place it in the window fra NOTE: Gnome on Wayland at least does not display this icon. To have a application icon there, a `.desktop` file has to be used. On KDE it should work. The icon should be provided in whatever size it was naturally drawn; that is, don’t scale the image before passing it. Scaling is postponed until the last minute, when the desired final size is known, to allow best quality. + +#### WindowIsTranslucent + +Setting this to `true` will make the window background translucent. Some window managers may ignore it, or result in a black window. + +名前: WindowIsTranslucent
データ型: `bool` \ No newline at end of file diff --git a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/community/links.mdx b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/community/links.mdx index b62a6f2ee..efd963510 100644 --- a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/community/links.mdx +++ b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/community/links.mdx @@ -21,3 +21,6 @@ Wails 相关的 [优秀列表](https://github.com/wailsapp/awesome-wails)。 - [Twitter](https://twitter.com/wailsapp) - [Wails 中文社区 QQ 群](https://qm.qq.com/cgi-bin/qm/qr?k=PmIURne5hFGNd7QWzW5qd6FV-INEjNJv&jump_from=webapi) - 群号:1067173054 + +## 其他教程和文章 +- [Building of Bulletin Board](https://blog.customct.com/building-bulletin-board) diff --git a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/community/templates.mdx b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/community/templates.mdx index 133fc48b9..fd69bc4f7 100644 --- a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/community/templates.mdx +++ b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/community/templates.mdx @@ -37,6 +37,7 @@ sidebar_position: 1 - [wails-react-template](https://github.com/AlienRecall/wails-react-template) - 基于 reactjs 的模板 - [wails-react-template](https://github.com/flin7/wails-react-template) - 基于 React 并支持实时开发模式的轻量级模板 - [wails-vite-react-ts](https://github.com/lontten/wails-vite-react-ts) - 基于 Vite + React + TypeScript 的模板 +- [wails-vite-react-ts-tailwind-template](https://github.com/hotafrika/wails-vite-react-ts-tailwind-template) - 一个 React + TypeScript + Vite + TailwindCSS 模板 ## Svelte diff --git a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/reference/options.mdx b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/reference/options.mdx index 861606924..a4e511216 100644 --- a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/reference/options.mdx +++ b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/reference/options.mdx @@ -88,6 +88,7 @@ func main() { }, Linux: &linux.Options{ Icon: icon, + WindowIsTranslucent: false, }, }) if err != nil { @@ -680,3 +681,9 @@ func main() { 注意:Wayland 上的 Gnome 至少不显示此图标。 要在那里有一个应用程序图标,必须使用一个`.desktop`文件。 在 KDE 上它应该可以工作。 图标应该以自然绘制的任何尺寸提供;也就是说,在传递图像之前不要缩放图像。 缩放将延迟到当所需的最终尺寸已知的最后一刻,以获得最佳质量。 + +#### 窗口半透明 + +将此设置为 `true` 将使窗口半透明。 某些窗口管理员可能忽略它,或导致黑窗口。 + +名称:WindowIsTranslucent
类型:`bool` \ No newline at end of file From bd378b2e0f13e0036c4e77d0720bc0d5810b2468 Mon Sep 17 00:00:00 2001 From: JulioDRF Date: Tue, 4 Oct 2022 19:47:37 +0000 Subject: [PATCH 31/36] Fix wails dev (#1931) * Fix wails dev * Pass wg as pointer to both goroutines in DevWebServer.Run * Remove shutdown goroutine --- v2/internal/frontend/devserver/devserver.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/v2/internal/frontend/devserver/devserver.go b/v2/internal/frontend/devserver/devserver.go index 2f0e5066a..0d1d7cc3e 100644 --- a/v2/internal/frontend/devserver/devserver.go +++ b/v2/internal/frontend/devserver/devserver.go @@ -132,22 +132,18 @@ func (d *DevWebServer) Run(ctx context.Context) error { }(d.server, d.logger) d.LogDebug("Serving DevServer at http://%s", devServerAddr) - - defer func() { - err := d.server.Shutdown(context.Background()) - if err != nil { - d.logger.Error(err.Error()) - } - }() } // Launch desktop app err = d.desktopFrontend.Run(ctx) - d.LogDebug("Starting shutdown") return err } +func (d *DevWebServer) RunMainLoop() { + d.desktopFrontend.RunMainLoop() +} + func (d *DevWebServer) Quit() { d.desktopFrontend.Quit() } @@ -186,6 +182,10 @@ func (d *DevWebServer) WindowSetTitle(title string) { d.desktopFrontend.WindowSetTitle(title) } +func (d *DevWebServer) WindowClose() { + d.desktopFrontend.WindowClose() +} + func (d *DevWebServer) WindowShow() { d.desktopFrontend.WindowShow() } From eee67979078f65887e90c5d60084af1c22837960 Mon Sep 17 00:00:00 2001 From: Lea Anthony Date: Wed, 5 Oct 2022 08:44:23 +1100 Subject: [PATCH 32/36] Add WindowExecJS method (#1927) * Add WindowExecJS * [devserver] Embed the base frontend into the DevServer struct * Update docs Co-authored-by: stffabi --- v2/internal/app/app_dev.go | 1 + v2/internal/app/app_production.go | 1 + .../frontend/desktop/darwin/frontend.go | 4 +- .../frontend/desktop/linux/frontend.go | 3 +- .../frontend/desktop/windows/frontend.go | 3 +- v2/internal/frontend/devserver/devserver.go | 174 +----------------- v2/internal/frontend/frontend.go | 1 + v2/pkg/runtime/window.go | 6 + website/docs/reference/runtime/window.mdx | 9 + 9 files changed, 28 insertions(+), 174 deletions(-) diff --git a/v2/internal/app/app_dev.go b/v2/internal/app/app_dev.go index ac29a9aa5..7eb58249e 100644 --- a/v2/internal/app/app_dev.go +++ b/v2/internal/app/app_dev.go @@ -181,6 +181,7 @@ func CreateApp(appoptions *options.App) (*App, error) { eventHandler.AddFrontend(appFrontend) eventHandler.AddFrontend(desktopFrontend) + ctx = context.WithValue(ctx, "frontend", appFrontend) result := &App{ ctx: ctx, frontend: appFrontend, diff --git a/v2/internal/app/app_production.go b/v2/internal/app/app_production.go index 245d375ce..afb67bdb3 100644 --- a/v2/internal/app/app_production.go +++ b/v2/internal/app/app_production.go @@ -84,6 +84,7 @@ func CreateApp(appoptions *options.App) (*App, error) { appFrontend := desktop.NewFrontend(ctx, appoptions, myLogger, appBindings, messageDispatcher) eventHandler.AddFrontend(appFrontend) + ctx = context.WithValue(ctx, "frontend", appFrontend) result := &App{ ctx: ctx, frontend: appFrontend, diff --git a/v2/internal/frontend/desktop/darwin/frontend.go b/v2/internal/frontend/desktop/darwin/frontend.go index ea157347e..ca9975749 100644 --- a/v2/internal/frontend/desktop/darwin/frontend.go +++ b/v2/internal/frontend/desktop/darwin/frontend.go @@ -145,9 +145,7 @@ func (f *Frontend) WindowSetDarkTheme() { } func (f *Frontend) Run(ctx context.Context) error { - - f.ctx = context.WithValue(ctx, "frontend", f) - + f.ctx = ctx var _debug = ctx.Value("debug") if _debug != nil { f.debug = _debug.(bool) diff --git a/v2/internal/frontend/desktop/linux/frontend.go b/v2/internal/frontend/desktop/linux/frontend.go index b07fe9866..6457bc984 100644 --- a/v2/internal/frontend/desktop/linux/frontend.go +++ b/v2/internal/frontend/desktop/linux/frontend.go @@ -142,8 +142,7 @@ func (f *Frontend) WindowSetDarkTheme() { } func (f *Frontend) Run(ctx context.Context) error { - - f.ctx = context.WithValue(ctx, "frontend", f) + f.ctx = ctx go func() { if f.frontendOptions.OnStartup != nil { diff --git a/v2/internal/frontend/desktop/windows/frontend.go b/v2/internal/frontend/desktop/windows/frontend.go index 59c3dcbdb..6e09b369f 100644 --- a/v2/internal/frontend/desktop/windows/frontend.go +++ b/v2/internal/frontend/desktop/windows/frontend.go @@ -128,8 +128,7 @@ func (f *Frontend) WindowSetDarkTheme() { } func (f *Frontend) Run(ctx context.Context) error { - - f.ctx = context.WithValue(ctx, "frontend", f) + f.ctx = ctx mainWindow := NewWindow(nil, f.frontendOptions, f.versionInfo) f.mainWindow = mainWindow diff --git a/v2/internal/frontend/devserver/devserver.go b/v2/internal/frontend/devserver/devserver.go index 0d1d7cc3e..3cfebd587 100644 --- a/v2/internal/frontend/devserver/devserver.go +++ b/v2/internal/frontend/devserver/devserver.go @@ -23,7 +23,6 @@ import ( "github.com/wailsapp/wails/v2/internal/frontend/assetserver" "github.com/wailsapp/wails/v2/internal/logger" "github.com/wailsapp/wails/v2/internal/menumanager" - "github.com/wailsapp/wails/v2/pkg/menu" "github.com/wailsapp/wails/v2/pkg/options" "golang.org/x/net/websocket" ) @@ -43,31 +42,11 @@ type DevWebServer struct { starttime string // Desktop frontend - desktopFrontend frontend.Frontend + frontend.Frontend devServerAddr string } -func (d *DevWebServer) Hide() { - d.desktopFrontend.Hide() -} - -func (d *DevWebServer) Show() { - d.desktopFrontend.Show() -} - -func (d *DevWebServer) WindowSetSystemDefaultTheme() { - d.desktopFrontend.WindowSetSystemDefaultTheme() -} - -func (d *DevWebServer) WindowSetLightTheme() { - d.desktopFrontend.WindowSetLightTheme() -} - -func (d *DevWebServer) WindowSetDarkTheme() { - d.desktopFrontend.WindowSetDarkTheme() -} - func (d *DevWebServer) Run(ctx context.Context) error { d.ctx = ctx @@ -135,159 +114,19 @@ func (d *DevWebServer) Run(ctx context.Context) error { } // Launch desktop app - err = d.desktopFrontend.Run(ctx) + err = d.Frontend.Run(ctx) return err } -func (d *DevWebServer) RunMainLoop() { - d.desktopFrontend.RunMainLoop() -} - -func (d *DevWebServer) Quit() { - d.desktopFrontend.Quit() -} - -func (d *DevWebServer) OpenFileDialog(dialogOptions frontend.OpenDialogOptions) (string, error) { - return d.desktopFrontend.OpenFileDialog(dialogOptions) -} - -func (d *DevWebServer) OpenMultipleFilesDialog(dialogOptions frontend.OpenDialogOptions) ([]string, error) { - return d.OpenMultipleFilesDialog(dialogOptions) -} - -func (d *DevWebServer) OpenDirectoryDialog(dialogOptions frontend.OpenDialogOptions) (string, error) { - return d.OpenDirectoryDialog(dialogOptions) -} - -func (d *DevWebServer) SaveFileDialog(dialogOptions frontend.SaveDialogOptions) (string, error) { - return d.desktopFrontend.SaveFileDialog(dialogOptions) -} - -func (d *DevWebServer) MessageDialog(dialogOptions frontend.MessageDialogOptions) (string, error) { - return d.desktopFrontend.MessageDialog(dialogOptions) -} - func (d *DevWebServer) WindowReload() { d.broadcast("reload") - d.desktopFrontend.WindowReload() + d.Frontend.WindowReload() } func (d *DevWebServer) WindowReloadApp() { d.broadcast("reloadapp") - d.desktopFrontend.WindowReloadApp() -} - -func (d *DevWebServer) WindowSetTitle(title string) { - d.desktopFrontend.WindowSetTitle(title) -} - -func (d *DevWebServer) WindowClose() { - d.desktopFrontend.WindowClose() -} - -func (d *DevWebServer) WindowShow() { - d.desktopFrontend.WindowShow() -} - -func (d *DevWebServer) WindowHide() { - d.desktopFrontend.WindowHide() -} - -func (d *DevWebServer) WindowCenter() { - d.desktopFrontend.WindowCenter() -} - -func (d *DevWebServer) WindowMaximise() { - d.desktopFrontend.WindowMaximise() -} - -func (d *DevWebServer) WindowToggleMaximise() { - d.desktopFrontend.WindowToggleMaximise() -} - -func (d *DevWebServer) WindowUnmaximise() { - d.desktopFrontend.WindowUnmaximise() -} - -func (d *DevWebServer) WindowIsMaximised() bool { - return d.desktopFrontend.WindowIsMaximised() -} - -func (d *DevWebServer) WindowMinimise() { - d.desktopFrontend.WindowMinimise() -} - -func (d *DevWebServer) WindowUnminimise() { - d.desktopFrontend.WindowUnminimise() -} -func (d *DevWebServer) WindowSetAlwaysOnTop(b bool) { - d.desktopFrontend.WindowSetAlwaysOnTop(b) -} - -func (d *DevWebServer) WindowIsMinimised() bool { - return d.desktopFrontend.WindowIsMinimised() -} - -func (d *DevWebServer) WindowSetPosition(x int, y int) { - d.desktopFrontend.WindowSetPosition(x, y) -} - -func (d *DevWebServer) WindowGetPosition() (int, int) { - return d.desktopFrontend.WindowGetPosition() -} - -func (d *DevWebServer) WindowSetSize(width int, height int) { - d.desktopFrontend.WindowSetSize(width, height) -} - -func (d *DevWebServer) WindowGetSize() (int, int) { - return d.desktopFrontend.WindowGetSize() -} - -func (d *DevWebServer) WindowSetMinSize(width int, height int) { - d.desktopFrontend.WindowSetMinSize(width, height) -} - -func (d *DevWebServer) WindowSetMaxSize(width int, height int) { - d.desktopFrontend.WindowSetMaxSize(width, height) -} - -func (d *DevWebServer) WindowFullscreen() { - d.desktopFrontend.WindowFullscreen() -} - -func (d *DevWebServer) WindowUnfullscreen() { - d.desktopFrontend.WindowUnfullscreen() -} - -func (d *DevWebServer) WindowSetBackgroundColour(col *options.RGBA) { - d.desktopFrontend.WindowSetBackgroundColour(col) -} - -func (d *DevWebServer) ScreenGetAll() ([]Screen, error) { - return d.desktopFrontend.ScreenGetAll() -} - -func (d *DevWebServer) WindowIsFullscreen() bool { - return d.desktopFrontend.WindowIsFullscreen() -} - -func (d *DevWebServer) WindowIsNormal() bool { - return d.desktopFrontend.WindowIsNormal() -} - -func (d *DevWebServer) MenuSetApplicationMenu(menu *menu.Menu) { - d.desktopFrontend.MenuSetApplicationMenu(menu) -} - -func (d *DevWebServer) MenuUpdateApplicationMenu() { - d.desktopFrontend.MenuUpdateApplicationMenu() -} - -// BrowserOpenURL uses the system default browser to open the url -func (d *DevWebServer) BrowserOpenURL(url string) { - d.desktopFrontend.BrowserOpenURL(url) + d.Frontend.WindowReloadApp() } func (d *DevWebServer) Notify(name string, data ...interface{}) { @@ -298,6 +137,7 @@ func (d *DevWebServer) handleReload(c echo.Context) error { d.WindowReload() return c.NoContent(http.StatusNoContent) } + func (d *DevWebServer) handleReloadApp(c echo.Context) error { d.WindowReloadApp() return c.NoContent(http.StatusNoContent) @@ -426,13 +266,13 @@ func (d *DevWebServer) notifyExcludingSender(eventMessage []byte, sender *websoc d.logger.Error(err.Error()) return } - d.desktopFrontend.Notify(notifyMessage.Name, notifyMessage.Data...) + d.Frontend.Notify(notifyMessage.Name, notifyMessage.Data...) } func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger.Logger, appBindings *binding.Bindings, dispatcher frontend.Dispatcher, menuManager *menumanager.Manager, desktopFrontend frontend.Frontend) *DevWebServer { result := &DevWebServer{ ctx: ctx, - desktopFrontend: desktopFrontend, + Frontend: desktopFrontend, appoptions: appoptions, logger: myLogger, appBindings: appBindings, diff --git a/v2/internal/frontend/frontend.go b/v2/internal/frontend/frontend.go index 93449a9a0..cbf80346c 100644 --- a/v2/internal/frontend/frontend.go +++ b/v2/internal/frontend/frontend.go @@ -66,6 +66,7 @@ type MessageDialogOptions struct { type Frontend interface { Run(context.Context) error RunMainLoop() + ExecJS(js string) Hide() Show() Quit() diff --git a/v2/pkg/runtime/window.go b/v2/pkg/runtime/window.go index 9f6a040c4..ca28e9d30 100644 --- a/v2/pkg/runtime/window.go +++ b/v2/pkg/runtime/window.go @@ -163,6 +163,12 @@ func WindowIsNormal(ctx context.Context) bool { return appFrontend.WindowIsNormal() } +// WindowExecJS executes the given Js in the window +func WindowExecJS(ctx context.Context, js string) { + appFrontend := getFrontend(ctx) + appFrontend.ExecJS(js) +} + func WindowSetBackgroundColour(ctx context.Context, R, G, B, A uint8) { appFrontend := getFrontend(ctx) col := &options.RGBA{ diff --git a/website/docs/reference/runtime/window.mdx b/website/docs/reference/runtime/window.mdx index bac1f3fbe..eec2a991b 100644 --- a/website/docs/reference/runtime/window.mdx +++ b/website/docs/reference/runtime/window.mdx @@ -41,6 +41,15 @@ Centers the window on the monitor the window is currently on. Go: `WindowCenter(ctx context.Context)`
JS: `WindowCenter()` +### WindowExecJS + +Executes arbitrary JS code in the window. + +This method runs the code in the browser asynchronously and returns immediately. +If the script causes any errors, they will only be available in the browser console. + +Go: `WindowExecJS(ctx context.Context, js string)` + ### WindowReload Performs a "reload" (Reloads current page). From eae90df3230f2cda70563eb36411baad39441970 Mon Sep 17 00:00:00 2001 From: Scott Opell Date: Sun, 9 Oct 2022 05:27:24 -0400 Subject: [PATCH 33/36] fix for dev file watching missing some file updates due to platform oddities (#1946) --- v2/cmd/wails/internal/commands/dev/dev.go | 38 ++++++++++++++++------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/v2/cmd/wails/internal/commands/dev/dev.go b/v2/cmd/wails/internal/commands/dev/dev.go index 66b8079cb..e97c64350 100644 --- a/v2/cmd/wails/internal/commands/dev/dev.go +++ b/v2/cmd/wails/internal/commands/dev/dev.go @@ -574,7 +574,19 @@ func doWatcherLoop(buildOptions *build.Options, debugBinaryProcess *process.Proc case err := <-watcher.Errors: LogDarkYellow(err.Error()) case item := <-watcher.Events: - // Check for file writes + isEligibleFile := func(fileName string) bool { + // Iterate all file patterns + ext := filepath.Ext(fileName) + if ext != "" { + ext = ext[1:] + if _, exists := extensionsThatTriggerARebuild[ext]; exists { + return true + } + } + return false + } + + // Handle write operations if item.Op&fsnotify.Write == fsnotify.Write { // Ignore directories itemName := item.Name @@ -582,15 +594,10 @@ func doWatcherLoop(buildOptions *build.Options, debugBinaryProcess *process.Proc continue } - // Iterate all file patterns - ext := filepath.Ext(itemName) - if ext != "" { - ext = ext[1:] - if _, exists := extensionsThatTriggerARebuild[ext]; exists { - rebuild = true - timer.Reset(interval) - continue - } + if isEligibleFile(itemName) { + rebuild = true + timer.Reset(interval) + continue } for _, reloadDir := range dirsThatTriggerAReload { @@ -606,7 +613,8 @@ func doWatcherLoop(buildOptions *build.Options, debugBinaryProcess *process.Proc timer.Reset(interval) } - // Check for new directories + + // Handle new fs entries that are created if item.Op&fsnotify.Create == fsnotify.Create { // If this is a folder, add it to our watch list if fs.DirExists(item.Name) { @@ -618,6 +626,14 @@ func doWatcherLoop(buildOptions *build.Options, debugBinaryProcess *process.Proc } LogGreen("Added new directory to watcher: %s", item.Name) } + } else if isEligibleFile(item.Name) { + // Handle creation of new file. + // Note: On some platforms an update to a file is represented as + // REMOVE -> CREATE instead of WRITE, so this is not only new files + // but also updates to existing files + rebuild = true + timer.Reset(interval) + continue } } case <-timer.C: From 504531f340e4b97592d4a666b77233f175b99799 Mon Sep 17 00:00:00 2001 From: Alex <20666153+o8x@users.noreply.github.com> Date: Sun, 9 Oct 2022 21:15:36 +0800 Subject: [PATCH 34/36] Update README.zh-Hans.md (#1949) replace the star history chart with star-history.com --- README.zh-Hans.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.zh-Hans.md b/README.zh-Hans.md index dc1cb6246..727bc09d1 100644 --- a/README.zh-Hans.md +++ b/README.zh-Hans.md @@ -111,7 +111,7 @@ ## 星星增长趋势 -[![星星增长趋势](https://starchart.cc/wailsapp/wails.svg)](https://starchart.cc/wailsapp/wails) +[![星星增长趋势](https://api.star-history.com/svg?repos=wailsapp/wails&type=Date)](https://star-history.com/#wailsapp/wails&Date) ## 贡献者 From 2a20049ea771d93f4852f6a7697c649753a877df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Valentin=20Trinqu=C3=A9?= Date: Mon, 10 Oct 2022 14:50:55 +0200 Subject: [PATCH 35/36] fix: Prevent type parsing to interfere with package name in typescript generation (#1942) Before that fix: The method... ```go func (h *Handler) RespondToInteraction(interaction interactor.Interaction) {} ``` ... would generate... ```ts export function RespondToInteraction(arg1:number):Promise; ``` ... because the `interaction` package starts with `int` and anything starting with `int` is interpreted as `number`. --- .../binding_conflicting_package_name_test.go | 64 +++++++++++++++++++ .../binding_test_import/float_package/type.go | 5 ++ .../binding_test_import/int_package/type.go | 5 ++ .../binding_test_import/map_package/type.go | 5 ++ .../binding_test_import/uint_package/type.go | 5 ++ v2/internal/binding/generate.go | 15 +++-- 6 files changed, 94 insertions(+), 5 deletions(-) create mode 100644 v2/internal/binding/binding_test/binding_conflicting_package_name_test.go create mode 100644 v2/internal/binding/binding_test/binding_test_import/float_package/type.go create mode 100644 v2/internal/binding/binding_test/binding_test_import/int_package/type.go create mode 100644 v2/internal/binding/binding_test/binding_test_import/map_package/type.go create mode 100644 v2/internal/binding/binding_test/binding_test_import/uint_package/type.go diff --git a/v2/internal/binding/binding_test/binding_conflicting_package_name_test.go b/v2/internal/binding/binding_test/binding_conflicting_package_name_test.go new file mode 100644 index 000000000..2309d6daf --- /dev/null +++ b/v2/internal/binding/binding_test/binding_conflicting_package_name_test.go @@ -0,0 +1,64 @@ +package binding_test + +import ( + "io/fs" + "os" + "testing" + + "github.com/wailsapp/wails/v2/internal/binding" + "github.com/wailsapp/wails/v2/internal/binding/binding_test/binding_test_import/float_package" + "github.com/wailsapp/wails/v2/internal/binding/binding_test/binding_test_import/int_package" + "github.com/wailsapp/wails/v2/internal/binding/binding_test/binding_test_import/map_package" + "github.com/wailsapp/wails/v2/internal/binding/binding_test/binding_test_import/uint_package" + "github.com/wailsapp/wails/v2/internal/logger" +) + +const expectedBindings = `// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT +import {float_package} from '../models'; +import {int_package} from '../models'; +import {map_package} from '../models'; +import {uint_package} from '../models'; + +export function StartingWithFloat(arg1:float_package.SomeStruct):Promise; + +export function StartingWithInt(arg1:int_package.SomeStruct):Promise; + +export function StartingWithMap(arg1:map_package.SomeStruct):Promise; + +export function StartingWithUint(arg1:uint_package.SomeStruct):Promise; +` + +type HandlerTest struct{} + +func (h *HandlerTest) StartingWithInt(_ int_package.SomeStruct) {} +func (h *HandlerTest) StartingWithFloat(_ float_package.SomeStruct) {} +func (h *HandlerTest) StartingWithUint(_ uint_package.SomeStruct) {} +func (h *HandlerTest) StartingWithMap(_ map_package.SomeStruct) {} + +func TestConflictingPackageName(t *testing.T) { + // given + generationDir := t.TempDir() + + // setup + testLogger := &logger.Logger{} + b := binding.NewBindings(testLogger, []interface{}{&HandlerTest{}}, []interface{}{}, false) + + // then + err := b.GenerateGoBindings(generationDir) + if err != nil { + t.Fatalf("could not generate the Go bindings: %v", err) + } + + // then + rawGeneratedBindings, err := fs.ReadFile(os.DirFS(generationDir), "binding_test/HandlerTest.d.ts") + if err != nil { + t.Fatalf("could not read the generated bindings: %v", err) + } + + // then + generatedBindings := string(rawGeneratedBindings) + if generatedBindings != expectedBindings { + t.Fatalf("the generated bindings does not match the expected ones.\nWanted:\n%s\n\nGot:\n%s", expectedBindings, generatedBindings) + } +} diff --git a/v2/internal/binding/binding_test/binding_test_import/float_package/type.go b/v2/internal/binding/binding_test/binding_test_import/float_package/type.go new file mode 100644 index 000000000..66a20304b --- /dev/null +++ b/v2/internal/binding/binding_test/binding_test_import/float_package/type.go @@ -0,0 +1,5 @@ +package float_package + +type SomeStruct struct { + Name string `json:"string"` +} diff --git a/v2/internal/binding/binding_test/binding_test_import/int_package/type.go b/v2/internal/binding/binding_test/binding_test_import/int_package/type.go new file mode 100644 index 000000000..bff29946a --- /dev/null +++ b/v2/internal/binding/binding_test/binding_test_import/int_package/type.go @@ -0,0 +1,5 @@ +package int_package + +type SomeStruct struct { + Name string `json:"string"` +} diff --git a/v2/internal/binding/binding_test/binding_test_import/map_package/type.go b/v2/internal/binding/binding_test/binding_test_import/map_package/type.go new file mode 100644 index 000000000..34303757c --- /dev/null +++ b/v2/internal/binding/binding_test/binding_test_import/map_package/type.go @@ -0,0 +1,5 @@ +package map_package + +type SomeStruct struct { + Name string `json:"string"` +} diff --git a/v2/internal/binding/binding_test/binding_test_import/uint_package/type.go b/v2/internal/binding/binding_test/binding_test_import/uint_package/type.go new file mode 100644 index 000000000..dd55675f6 --- /dev/null +++ b/v2/internal/binding/binding_test/binding_test_import/uint_package/type.go @@ -0,0 +1,5 @@ +package uint_package + +type SomeStruct struct { + Name string `json:"string"` +} diff --git a/v2/internal/binding/generate.go b/v2/internal/binding/generate.go index 6921ae34d..9793e77f2 100644 --- a/v2/internal/binding/generate.go +++ b/v2/internal/binding/generate.go @@ -120,6 +120,16 @@ func (b *Bindings) GenerateGoBindings(baseDir string) error { } func goTypeToJSDocType(input string, importNamespaces *slicer.StringSlicer) string { + // Verifying this first to ensure we are not converting a type + // coming from a package that has a name matching a golang type, such as: + // - interactor -> int + // - mapper -> map + if strings.ContainsRune(input, '.') { + namespace := getPackageName(input) + importNamespaces.Add(namespace) + return namespace + "." + strings.Split(input, ".")[1] + } + switch true { case input == "interface {}" || input == "interface{}": return "any" @@ -150,11 +160,6 @@ func goTypeToJSDocType(input string, importNamespaces *slicer.StringSlicer) stri arrayType := goTypeToJSDocType(input[2:], importNamespaces) return "Array<" + arrayType + ">" default: - if strings.ContainsRune(input, '.') { - namespace := getPackageName(input) - importNamespaces.Add(namespace) - return namespace + "." + strings.Split(input, ".")[1] - } return "any" } } From c78f59bbc1591345cec0a9a6a5694de7e4c3db4f Mon Sep 17 00:00:00 2001 From: Rob Nice Date: Tue, 11 Oct 2022 04:22:24 -0400 Subject: [PATCH 36/36] Add Elm Tailwind CSS community template (#1939) * add link/description * rename project --- website/docs/community/templates.mdx | 1 + 1 file changed, 1 insertion(+) diff --git a/website/docs/community/templates.mdx b/website/docs/community/templates.mdx index 6bc78f647..500f75ebd 100644 --- a/website/docs/community/templates.mdx +++ b/website/docs/community/templates.mdx @@ -48,6 +48,7 @@ If you are unsure about a template, inspect `package.json` and `wails.json` for ## Elm - [wails-elm-template](https://github.com/benjamin-thomas/wails-elm-template) - Develop your GUI app with functional programming and a **snappy** hot-reload setup :tada: :rocket: +- [wails-template-elm-tailwind](https://github.com/rnice01/wails-template-elm-tailwind) - Combine the powers :muscle: of Elm + Tailwind CSS + Wails! Hot reloading supported. ## Pure JavaScript (Vanilla)