Compare commits

...

144 Commits

Author SHA1 Message Date
Lea Anthony
f9e559f069 Merge branch 'master' into develop 2021-10-26 19:35:18 +11:00
Lea Anthony
9a4c603001 [v1] Update logrus to v1.8.1 2021-10-26 19:32:53 +11:00
Lea Anthony
98a95e99a5 [mac] Fixes #879 2021-10-26 19:28:15 +11:00
Lea Anthony
d19c982eed v2.0.0-beta.15 2021-10-26 19:21:41 +11:00
Lea Anthony
a963836e75 [v2] fix: check process exists before killing 2021-10-26 19:20:39 +11:00
Lea Anthony
00e9eb4b0b [v2] fix: run frontend:dev when using wails dev 2021-10-26 19:20:09 +11:00
Lea Anthony
262b6281e1 Update sponsors. Cheers DonTomato! 2021-10-26 19:05:07 +11:00
Lea Anthony
f66c70f0be Merge pull request #893 from Wakeful-Cloud/master
Fixed WindowGetSize
2021-10-25 19:20:47 +11:00
Wakeful-Cloud
717d373668 Fixed WindowGetSize 2021-10-24 18:00:47 -06:00
Lea Anthony
d29fa94aa4 Merge pull request #891 from Wakeful-Cloud/master
Fix TypeScript runtime declaration
2021-10-24 19:11:11 +11:00
Wakeful-Cloud
01dd0cd0b2 Fix TypeScript runtime declaration 2021-10-24 04:05:47 +00:00
Lea Anthony
126cc78d1a [v2] add overscroll-behavior 2021-10-24 09:03:05 +11:00
Lea Anthony
5703d465fc [v2] v2.0.0-beta.14 2021-10-23 08:52:02 +11:00
Lea Anthony
0c2963cf53 [windows] Add webview2 permissions 2021-10-23 07:17:58 +11:00
Lea Anthony
b61fd16936 [windows] Disable swipe navigation 2021-10-23 05:50:39 +11:00
Lea Anthony
3a8ba96cb3 [windows] Update webview2 to 91.0.992.28 2021-10-23 05:50:39 +11:00
Lea Anthony
3b1d74cf84 Merge pull request #886 from TAINCER/patch-1
Added Angular template to Community templates list
2021-10-22 17:11:50 +11:00
Lea Anthony
2e0a6f95a0 [website] Update dialog docs 2021-10-22 16:59:44 +11:00
Timm Ortloff
8470bfb26b Added Angular template to Community templates list 2021-10-22 06:47:03 +02:00
Lea Anthony
bea0c1446a [mac] dialog support 2021-10-22 08:42:36 +11:00
Lea Anthony
35ebbdfa12 [v2] Fix typo in templates 2021-10-22 08:42:35 +11:00
Lea Anthony
bb25b3f42f Update events.mdx 2021-10-20 20:31:58 +11:00
Lea Anthony
4a11f9bb20 Update sponsors 2021-10-20 17:40:57 +11:00
Lea Anthony
c1a20d0509 [mac] Fix SetRGBA and disabling context menus in prod build 2021-10-19 20:08:43 +11:00
Lea Anthony
32c3721b1b [mac] Fix webviewistransparent and debug flag 2021-10-19 20:07:36 +11:00
Lea Anthony
913cc56adf [v2] Add flag to remove default context menu 2021-10-19 20:06:18 +11:00
Lea Anthony
38f37e817b [mac] Get asset server hooked up, window drag, Window runtime. 2021-10-18 22:02:23 +11:00
Lea Anthony
4e68f92083 [v2] Add WindowGetPos & WindowGetSize 2021-10-18 21:42:02 +11:00
Lea Anthony
3edbda313e [mac] add SetRGBA and basic hooks for asset serving 2021-10-17 21:50:15 +11:00
Lea Anthony
04cde94c96 [windows] add build tags to browser runtime 2021-10-17 21:50:15 +11:00
Lea Anthony
1faa962cf5 Update README.md 2021-10-16 15:47:02 +11:00
Lea Anthony
94a74520be Update logo 2021-10-16 15:45:59 +11:00
Lea Anthony
27dd40fd29 Update logos 2021-10-16 08:57:28 +11:00
Lea Anthony
616ecabb41 [mac] migrated colour code 2021-10-14 20:38:11 +11:00
Lea Anthony
15cd325034 [mac] experimental 2021-10-14 20:35:45 +11:00
Lea Anthony
450eb2e7ae [mac] message passing, quit 2021-10-14 20:34:47 +11:00
Lea Anthony
84622b829c [website] Fix build 2021-10-14 17:55:01 +11:00
Lea Anthony
a1323ce5e9 [mac] experimental 2021-10-13 22:01:35 +11:00
Lea Anthony
49629f6dc6 [mac] Fix build tags 2021-10-13 21:16:07 +11:00
Lea Anthony
231848cb9e [mac] Don't create .app in dev 2021-10-13 21:16:06 +11:00
Lea Anthony
a51d8bb47d [v2] Move "AlwaysOnTop" option 2021-10-13 08:05:31 +11:00
Lea Anthony
e0e4c0ae11 [v2] Add "AlwaysOnTop" option 2021-10-13 08:02:35 +11:00
Lea Anthony
d47b3734af [v2] v2.0.0-beta.13 2021-10-12 20:47:03 +11:00
Lea Anthony
26d248a4b6 [v2] Add flag to disable scrollbar drag 2021-10-12 20:45:53 +11:00
Lea Anthony
6413a6fb4d Update Sponsors 2021-10-12 20:35:38 +11:00
Lea Anthony
5e36f4fc7f [v2] Remove chromium message on shutdown 2021-10-12 08:58:33 +11:00
Lea Anthony
b47c278c95 Merge pull request #868 from stankovic98/add-artix-linux
add artix linux distro
2021-10-12 08:54:16 +11:00
Lea Anthony
81a9619fd7 [v2] v2.0.0-beta.12 2021-10-12 06:53:35 +11:00
Lea Anthony
ce103af77b [v2] Update 'replace' line in go.mod 2021-10-12 06:51:22 +11:00
Lea Anthony
2649c3d17d [v2] Fix bindings.js 2021-10-12 06:34:01 +11:00
Lea Anthony
a35cc035b0 Merge pull request #867 from marktohark/master
add locker for websocket.WriteMessage
2021-10-12 06:21:53 +11:00
Antonio
a94a720a68 add artix linux distro 2021-10-11 17:16:24 +02:00
unknown
995fe38ee4 add locker for websocket.WriteMessage 2021-10-11 21:10:55 +08:00
Lea Anthony
7fd311f7a6 Merge pull request #865 from marktohark/master
add \r\n for awaitIPC callback
2021-10-11 22:50:47 +11:00
unknown
356774e3f7 use backtick with return 2021-10-11 19:41:45 +08:00
unknown
5d8653be83 add \r\n for awaitIPC callback 2021-10-11 16:41:11 +08:00
Lea Anthony
8b5bcdfeff [v2] v2.0.0-beta.11 2021-10-11 19:24:04 +11:00
Lea Anthony
f6655d019f [v2] Better errors 2021-10-11 19:23:31 +11:00
Lea Anthony
8f31183fa8 [v2] Fix client timeouts 2021-10-11 19:23:31 +11:00
Lea Anthony
64528b4f02 Merge pull request #863 from marcus-crane/master
Correct help text for enabling Debug log level
2021-10-11 17:56:25 +11:00
Marcus Crane
7945853294 Correct help text for enabling Debug log level
All in forms of documentation, the correct name for the second most verbose log level is "Debug" but under `wails dev --help`, it's called Dev

Trying to use it throws an error as well so correcting the name to be Debug
2021-10-11 13:31:28 +13:00
Lea Anthony
b0df3f5c39 [v2] v2.0.0-beta.10 2021-10-10 15:46:04 +11:00
Lea Anthony
7caf6af91d [v2] Fix websocket ipc timing bug. Use proper HTML parsing for injection. 2021-10-10 15:43:01 +11:00
Lea Anthony
dd7c6a3d58 [v2] v2.0.0-beta.9 2021-10-10 11:20:20 +11:00
Lea Anthony
cfbeb1efd1 [v2] Fix parsing multiline require in go.mod 2021-10-10 11:18:52 +11:00
Lea Anthony
3022b0bf3f [mac] Fix binary path in dev 2021-10-09 17:43:34 +11:00
Lea Anthony
3723c41d15 [mac] Fix binary path in build. Remove apple identity 2021-10-09 17:39:51 +11:00
Lea Anthony
2729081f2c [v2] v2.0.0-beta.8 2021-10-09 07:57:23 +11:00
Lea Anthony
cad1317fc8 [v2] Tags passthrough for wails generate module 2021-10-09 07:56:19 +11:00
Lea Anthony
1368c20029 [website] v2.0.0-beta.7 2021-10-09 00:06:39 +11:00
Lea Anthony
0acfdd1516 [website] v2.0.0-beta.6 2021-10-09 00:03:35 +11:00
Lea Anthony
212a20626a [website] Update go webview 2021-10-09 00:02:53 +11:00
Lea Anthony
722ecc969b [website] Update docs to v2.0.0-beta.5 2021-10-08 20:27:10 +11:00
Lea Anthony
078145c030 [v2] v2.0.0-beta.5 2021-10-08 19:54:48 +11:00
Lea Anthony
3765c8fb57 [v2] Auto update wails version in projects in dev mode 2021-10-08 19:53:46 +11:00
Lea Anthony
10ac38c650 [v2] update go build url 2021-10-08 19:51:51 +11:00
Lea Anthony
a16e41f813 [v2] Tidy up frontend 2021-10-07 21:04:33 +11:00
Lea Anthony
1bd3deb39f Merge pull request #859 from marktohark/master
PutAreBrowserAcceleratorKeysEnabled => false
2021-10-07 21:02:27 +11:00
unknown
be5f7ceb0e uncomment PostMessage 2021-10-07 17:34:06 +08:00
Lea Anthony
6943b657c9 [v2] Fix error messages in dev mode 2021-10-07 18:56:53 +11:00
unknown
a148c67df0 don't hook any AcceleratorKey in callback 2021-10-07 14:35:14 +08:00
unknown
69297667c1 PutAreBrowserAcceleratorKeysEnabled => false 2021-10-07 14:28:52 +08:00
Lea Anthony
1ae9469e90 [v2] Fix bindings build tags 2021-10-06 20:36:31 +11:00
Lea Anthony
d597d8e1c9 [v2] Fix bindings build tags 2021-10-06 20:36:15 +11:00
Lea Anthony
d32152ed84 [website] Add sponsor 2021-10-06 20:36:15 +11:00
Lea Anthony
d28a7e8987 [v2] Run go mod tidy first to ensure deps are up to date 2021-10-06 20:36:15 +11:00
Lea Anthony
ef362a746a Merge pull request #849 from marktohark/filter-execjs-json
add template.JSEscapeString to ensure ExecJs normal execution
2021-10-06 20:13:19 +11:00
Lea Anthony
c16c95673e Merge pull request #855 from wailsapp/dependabot/go_modules/github.com/gorilla/websocket-1.4.1
Bump github.com/gorilla/websocket from 1.4.0 to 1.4.1
2021-10-06 07:19:52 +11:00
dependabot[bot]
d426fc46b5 Bump github.com/gorilla/websocket from 1.4.0 to 1.4.1
Bumps [github.com/gorilla/websocket](https://github.com/gorilla/websocket) from 1.4.0 to 1.4.1.
- [Release notes](https://github.com/gorilla/websocket/releases)
- [Commits](https://github.com/gorilla/websocket/compare/v1.4.0...v1.4.1)

---
updated-dependencies:
- dependency-name: github.com/gorilla/websocket
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-05 18:12:23 +00:00
Lea Anthony
0efeed4d7f Merge pull request #852 from misitebao/synchronize-chinese-documents
feat(website): synchronize chinese documents
2021-10-06 05:10:38 +11:00
misitebao
a11a75fa12 feat(website): correct and optimize documents 2021-10-05 22:26:34 +08:00
misitebao
2d551cd019 feat(website): synchronize showcase 2021-10-05 22:26:34 +08:00
misitebao
37259b8adb feat(website): synchronize chinese documents 2021-10-05 22:26:33 +08:00
misitebao
d5cfcc80f7 config(website): update dependency configuration file 2021-10-05 22:26:33 +08:00
misitebao
25564b7211 ci: add scripts for automatic deployment of mirrored websites 2021-10-05 22:26:32 +08:00
Lea Anthony
661b24cfa2 Update Sponsors 2021-10-05 23:34:04 +11:00
Lea Anthony
75f703465a [v2] Generate module command. Updated wails dev 2021-10-05 22:27:12 +11:00
unknown
9949420639 add template.JSEscapeString to ensure ExecJs normal execution 2021-10-05 09:45:36 +08:00
Lea Anthony
9e347bf71f [v2] Generate ipcdev.js and runtimedev.js 2021-10-04 19:58:46 +11:00
Lea Anthony
829fd8616b [v2] Make ipc.js cross-platform 2021-10-04 19:42:22 +11:00
Lea Anthony
ae980d48fd [v2] Fix connection delay for websockets 2021-10-04 17:10:46 +11:00
Lea Anthony
ba9e64f53a Merge pull request #848 from codydbentley/refactor-dev-command
Refactored `wails dev` command:
2021-10-04 17:10:26 +11:00
Lea Anthony
b15d98b555 [v2] Rename noautoinjectbindings -> noautoinjectipc 2021-10-04 16:53:27 +11:00
Cody Bentley
bdda454f69 Refactored wails dev command:
- added `devFlags` data structure for managing flags
- created `defaultDevFlags()` for generating default `devFlags` struct
- created `loadAndMergeProjectConfig()` to consolidate wails.json interaction
- re-arranged some variable creation and logic to put related pieces together
- consolidated `frontend:dev` handling to `runFrontendDevCommand()`
- added `generateBuildOptions()` for readability
- removed unused `passthruArgs` slice
- consolidated `restartApp()` call signature, removed unused `firstRun` argument
- fixed browser open option still using hard-coded default value, switched to recently added const `defaultDevServerURL`
- removed unnecessary `projectDir` variable (it's identical to `cwd` variable)
- consolidated watcher init to `initialiseWatcher()` which returns a deferable closer
- moved the main watch loop to `doWatcherLoop()`
- moved new deBounce flag handling to `loadAndMergeProjectConfig()`
2021-10-03 23:01:42 -06:00
Lea Anthony
a59d01ddb9 [v2] Fix killing dev command on Windows 2021-10-03 22:19:40 +11:00
Lea Anthony
27f8df2b31 [v2] Support "frontend:dev" command 2021-10-03 21:29:59 +11:00
Lea Anthony
1b28f69236 [v2] Fix -devserverurl flag 2021-10-03 16:44:37 +11:00
Lea Anthony
7572b64bec [v2] Add -devserverurl flag 2021-10-03 15:07:10 +11:00
Lea Anthony
f6b83b0933 [v2] New -debounce flag to configure debounce time of dev server 2021-10-03 14:04:05 +11:00
Lea Anthony
a51ab25e2c Merge pull request #845 from codydbentley/add-new-templates
Added two new Vue3 TS templates to website
2021-10-03 13:33:57 +11:00
Lea Anthony
aeaaccb942 Merge pull request #846 from codydbentley/fix-template-generator
Fixed base NEXTSTEPS and README in v2 template generator
2021-10-03 12:36:20 +11:00
Cody Bentley
4bf3eb303b Fixed base NEXTSTEPS and README in v2 template generator 2021-10-02 17:29:43 -06:00
Cody Bentley
b5437ed1b5 Added two new Vue3 TS templates to website 2021-10-02 17:27:07 -06:00
Lea Anthony
e2e752dd06 [v2] Fix timing bug 2021-10-02 19:55:49 +10:00
Lea Anthony
9dc2caecf0 [website] Rename heading 2021-10-02 14:27:06 +10:00
Lea Anthony
b0da974a7d [v2] v2.0.0-beta.4 2021-10-02 14:16:40 +10:00
Lea Anthony
b4dc8c252a [v2] update now uses go install 2021-10-02 14:14:07 +10:00
Lea Anthony
afb1d12c3b [v2] Add meta tag to control script injection behaviour 2021-10-02 14:04:59 +10:00
Lea Anthony
7a0cb428f2 Merge pull request #840 from codydbentley/fix-missing-comma-in-bindings
Fixed missing comma that breaks bindings with more than one package
2021-09-30 19:28:56 +10:00
Cody Bentley
e6a89790e3 Fixed missing comma that would break bindings when more than one package exists 2021-09-29 22:04:28 -06:00
Lea Anthony
daede02c16 Merge pull request #776 from wailsapp/dependabot/npm_and_yarn/runtime/js/runtime/path-parse-1.0.7
Bump path-parse from 1.0.6 to 1.0.7 in /runtime/js/runtime
2021-09-30 08:40:10 +10:00
Lea Anthony
417895f40b Merge pull request #826 from wailsapp/dependabot/npm_and_yarn/website/prismjs-1.25.0
Bump prismjs from 1.24.1 to 1.25.0 in /website
2021-09-30 08:39:41 +10:00
Lea Anthony
6bc26aa669 [v2] Add .gitignore to templates 2021-09-30 08:20:32 +10:00
Lea Anthony
a641deb388 [v2] Devserver listen to localhost 2021-09-30 08:00:50 +10:00
Lea Anthony
e013ce14a1 [v2] fix tags in dev mode 2021-09-30 07:11:49 +10:00
Lea Anthony
9930ee10da Revert "Corrected obsolete 'text/javascript' mime to 'application/javascript'"
This reverts commit 23c1ebfac9.
2021-09-30 07:07:13 +10:00
Lea Anthony
de6c57771e [website] update sponsors 2021-09-30 07:01:30 +10:00
Lea Anthony
c8359b0743 [v2] sync go.sum 2021-09-30 07:01:12 +10:00
Lea Anthony
12b7cf09e6 [v2] Support Goland IDE 2021-09-30 07:00:46 +10:00
Lea Anthony
28af34f978 [website] update installation instructions to v2.0.0-beta.3 2021-09-29 20:39:58 +10:00
Lea Anthony
49b1acc147 [v2] v2.0.0-beta.3 2021-09-29 20:24:56 +10:00
Lea Anthony
0ee3015c7d [website] update IDE flag 2021-09-29 20:19:14 +10:00
Lea Anthony
4aa1464b48 [v2] fix module version in templates. Refactor ide flag 2021-09-29 20:15:26 +10:00
Lea Anthony
7b52995c86 Merge pull request #833 from codydbentley/add-js-to-mimecache
Added JS case to mimecache
2021-09-29 18:06:47 +10:00
Cody Bentley
23c1ebfac9 Corrected obsolete 'text/javascript' mime to 'application/javascript' 2021-09-29 01:06:28 -06:00
Cody Bentley
3de31613a1 Added JS case to mimecache 2021-09-29 00:50:49 -06:00
dependabot[bot]
7311868636 Bump prismjs from 1.24.1 to 1.25.0 in /website
Bumps [prismjs](https://github.com/PrismJS/prism) from 1.24.1 to 1.25.0.
- [Release notes](https://github.com/PrismJS/prism/releases)
- [Changelog](https://github.com/PrismJS/prism/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PrismJS/prism/compare/v1.24.1...v1.25.0)

---
updated-dependencies:
- dependency-name: prismjs
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-27 09:37:34 +00:00
Lea Anthony
3caa0f1438 v1.16.7 2021-09-03 19:15:37 +10:00
Florian Didron
b8ef90cb41 fix: prevent hidden files to show on gtk host when opening a file dialog 2021-09-03 19:12:47 +10:00
Lea Anthony
9efc648e3d Merge pull request #789 from diogox/develop
Add NixOS support
2021-09-03 18:55:53 +10:00
Diogo Xavier
baa96f47d8 Add NixOS support 2021-08-30 19:15:10 +01:00
Lea Anthony
184ce763c1 v1.16.6 2021-08-14 19:02:16 +10:00
Lea Anthony
229ee95f91 Don't build project by default. Added -build flag to wails init to mimic old behaviour 2021-08-14 19:00:35 +10:00
dependabot[bot]
ed4b74f01b Bump path-parse from 1.0.6 to 1.0.7 in /runtime/js/runtime
Bumps [path-parse](https://github.com/jbgutierrez/path-parse) from 1.0.6 to 1.0.7.
- [Release notes](https://github.com/jbgutierrez/path-parse/releases)
- [Commits](https://github.com/jbgutierrez/path-parse/commits/v1.0.7)

---
updated-dependencies:
- dependency-name: path-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-12 21:19:10 +00:00
175 changed files with 7204 additions and 2262 deletions

View File

@@ -0,0 +1,35 @@
name: Deploy mirror | 部署镜像
on:
push:
branches: [master]
# pull_request:
# branches: [ main ]
jobs:
build-and-deploy:
name: Automatic deployment | 自动部署
runs-on: ubuntu-latest
if: github.repository == 'misitebao/wails'
steps:
- name: Checkout | 切换到部署分支
uses: actions/checkout@v2
with:
ref: "master"
submodules: true
fetch-depth: 0
- name: Build Site | 构建网站
run: |
cd website &&
npm install && npm run build
- name: Deploy to Server | 部署到服务器
uses: hengkx/ssh-deploy@v1.0.1
with:
HOST: ${{ secrets.DEPLOY_HOST }}
USERNAME: ${{ secrets.DEPLOY_HOST_USER }}
PASSWORD: ${{ secrets.DEPLOY_HOST_PASSWORD }}
SOURCE: "website/build"
TARGET: "/www/wwwroot/wails.top"

View File

@@ -1,5 +1,5 @@
<p align="center" style="text-align: center">
<img src="logo_cropped.png" width="40%"><br/>
<img src="logo.png" width="55%"><br/>
</p>
<p align="center">
Build desktop applications using Go & Web Technologies.<br/><br/>
@@ -79,45 +79,67 @@ This project is supported by these kind people / companies:
<a href="https://github.com/snider" style="width:100px;">
<img src="https://github.com/snider.png?size=100" width="100"/>
</a>
<a href="https://github.com/codydbentley" style="width:100px">
<img src="https://github.com/codydbentley.png?size=100" width="100"/>
</a>
<br/>
<br/>
<a href="https://github.com/matryer" style="width:100px">
<img src="https://github.com/matryer.png" width="100"/>
</a>
<a href="https://www.jetbrains.com?from=Wails" style="width:100px">
<img src="jetbrains-grayscale.png" width="100"/>
<img src="/img/jetbrains-grayscale.png" width="100"/>
</a>
<a href="https://github.com/tc-hib" style="width:55px;border-radius: 50%">
<img src="https://github.com/tc-hib.png?size=55" width="55" style="border-radius: 50%"/>
<a href="https://github.com/tc-hib" style="width:55px">
<img src="https://github.com/tc-hib.png?size=55" width="55"/>
</a>
<a href="https://github.com/picatz" style="width:50px;border-radius: 50%">
<img src="https://github.com/picatz.png?size=50" width="50" style="border-radius: 50%"/>
<a href="https://github.com/picatz" style="width:50px">
<img src="https://github.com/picatz.png?size=50" width="50"/>
</a>
<a href="https://github.com/tylertravisty" style="width:50px;border-radius: 50%">
<img src="https://github.com/tylertravisty.png?size=50" width="50" style="border-radius: 50%"/>
<a href="https://github.com/tylertravisty" style="width:50px">
<img src="https://github.com/tylertravisty.png?size=50" width="50"/>
</a>
<a href="https://github.com/akhudek" style="width:50px;border-radius: 50%">
<img src="https://github.com/akhudek.png?size=50" width="50" style="border-radius: 50%"/>
<a href="https://github.com/akhudek" style="width:50px">
<img src="https://github.com/akhudek.png?size=50" width="50"/>
</a>
<a href="https://github.com/trea" style="width:50px;border-radius: 50%">
<img src="https://github.com/trea.png?size=50" width="50" style="border-radius: 50%"/>
<a href="https://github.com/trea" style="width:50px">
<img src="https://github.com/trea.png?size=50" width="50"/>
</a>
<a href="https://github.com/LanguageAgnostic" style="width:55px;border-radius: 50%">
<img src="https://github.com/LanguageAgnostic.png?size=55" width="55" style="border-radius: 50%"/>
<a href="https://github.com/LanguageAgnostic" style="width:55px">
<img src="https://github.com/LanguageAgnostic.png?size=55" width="55"/>
</a>
<a href="https://github.com/fcjr" style="width:55px;border-radius: 50%">
<img src="https://github.com/fcjr.png?size=55" width="55" style="border-radius: 50%"/>
<a href="https://github.com/fcjr" style="width:55px">
<img src="https://github.com/fcjr.png?size=55" width="55"/>
</a>
<a href="https://github.com/nickarellano" style="width:60px;border-radius: 50%">
<img src="https://github.com/nickarellano.png?size=60" width="60" style="border-radius: 50%"/>
<a href="https://github.com/nickarellano" style="width:60px">
<img src="https://github.com/nickarellano.png?size=60" width="60"/>
</a>
<a href="https://github.com/bglw" style="width:65px;border-radius: 50%">
<img src="https://github.com/bglw.png?size=65" width="65" style="border-radius: 50%"/>
<a href="https://github.com/bglw" style="width:65px">
<img src="https://github.com/bglw.png?size=65" width="65"/>
</a>
<a href="https://github.com/jugglingjsons" style="width:50px;border-radius: 50%">
<img src="https://github.com/jugglingjsons.png?size=50" width="50" style="border-radius: 50%"/>
<a href="https://github.com/jugglingjsons" style="width:50px">
<img src="https://github.com/jugglingjsons.png?size=50" width="50"/>
</a>
<a href="https://github.com/marcus-crane" style="width:50px;border-radius: 50%">
<img src="https://github.com/marcus-crane.png?size=50" width="50" style="border-radius: 50%"/>
<a href="https://github.com/marcus-crane" style="width:65px">
<img src="https://github.com/marcus-crane.png?size=65" width="65"/>
</a>
<a href="https://github.com/bbergshaven" style="width:45px">
<img src="https://github.com/bbergshaven.png?size=45" width="45"/>
</a>
<a href="https://github.com/Gilgames000" style="width:45px">
<img src="https://github.com/Gilgames000.png?size=45" width="45"/>
</a>
<a href="https://github.com/ilgityildirim" style="width:50px">
<img src="https://github.com/ilgityildirim.png?size=50" width="50"/>
</a>
<a href="https://github.com/ondoki" style="width:65px">
<img src="https://github.com/ondoki.png?size=65" width="65"/>
</a>
<a href="https://github.com/questrail" style="width:50px">
<img src="https://github.com/questrail.png?size=50" width="50"/>
</a>
<a href="https://github.com/DonTomato" style="width:45px">
<img src="https://github.com/DonTomato.png?size=45" width="45"/>
</a>
<span id="nav-5"></span>

View File

@@ -1,5 +1,5 @@
<p align="center" style="text-align: center">
<img src="logo_cropped.png" width="40%"><br/>
<img src="logo.png" width="40%"><br/>
</p>
<p align="center">
使用 Go 和 Web 技术构建桌面应用程序。<br/><br/>
@@ -73,47 +73,74 @@
这个项目由以下这些人或者公司支持:
<a href="https://github.com/sponsors/leaanthony" style="width:100px;">
<img src="sponsors/bronze%20sponsor.png" width="100"/>
</a>
<a href="https://github.com/snider" style="width:100px;">
<img src="https://github.com/snider.png?size=100" width="100"/>
</a>
<a href="https://github.com/codydbentley" style="width:100px">
<img src="https://github.com/codydbentley.png?size=100" width="100"/>
</a>
<br/>
<br/>
<a href="https://github.com/matryer" style="width:100px">
<img src="https://github.com/matryer.png" width="100"/>
</a>
<a href="https://www.jetbrains.com?from=Wails" style="width:100px">
<img src="jetbrains-grayscale.png" width="100"/>
<img src="/img/jetbrains-grayscale.png" width="100"/>
</a>
<a href="https://github.com/tc-hib" style="width:55px;border-radius: 50%">
<img src="https://github.com/tc-hib.png?size=55" width="55" style="border-radius: 50%"/>
<a href="https://github.com/tc-hib" style="width:55px">
<img src="https://github.com/tc-hib.png?size=55" width="55"/>
</a>
<a href="https://github.com/picatz" style="width:50px;border-radius: 50%">
<img src="https://github.com/picatz.png?size=50" width="50" style="border-radius: 50%"/>
<a href="https://github.com/picatz" style="width:50px">
<img src="https://github.com/picatz.png?size=50" width="50"/>
</a>
<a href="https://github.com/tylertravisty" style="width:50px;border-radius: 50%">
<img src="https://github.com/tylertravisty.png?size=50" width="50" style="border-radius: 50%"/>
<a href="https://github.com/tylertravisty" style="width:50px">
<img src="https://github.com/tylertravisty.png?size=50" width="50"/>
</a>
<a href="https://github.com/akhudek" style="width:50px;border-radius: 50%">
<img src="https://github.com/akhudek.png?size=50" width="50" style="border-radius: 50%"/>
<a href="https://github.com/akhudek" style="width:50px">
<img src="https://github.com/akhudek.png?size=50" width="50"/>
</a>
<a href="https://github.com/trea" style="width:50px;border-radius: 50%">
<img src="https://github.com/trea.png?size=50" width="50" style="border-radius: 50%"/>
<a href="https://github.com/trea" style="width:50px">
<img src="https://github.com/trea.png?size=50" width="50"/>
</a>
<a href="https://github.com/LanguageAgnostic" style="width:55px;border-radius: 50%">
<img src="https://github.com/LanguageAgnostic.png?size=55" width="55" style="border-radius: 50%"/>
<a href="https://github.com/LanguageAgnostic" style="width:55px">
<img src="https://github.com/LanguageAgnostic.png?size=55" width="55"/>
</a>
<a href="https://github.com/snider" style="width:60px;border-radius: 50%">
<img src="https://github.com/snider.png?size=60" width="60" style="border-radius: 50%"/>
<a href="https://github.com/fcjr" style="width:55px">
<img src="https://github.com/fcjr.png?size=55" width="55"/>
</a>
<a href="https://github.com/fcjr" style="width:55px;border-radius: 50%">
<img src="https://github.com/fcjr.png?size=55" width="55" style="border-radius: 50%"/>
<a href="https://github.com/nickarellano" style="width:60px">
<img src="https://github.com/nickarellano.png?size=60" width="60"/>
</a>
<a href="https://github.com/nickarellano" style="width:60px;border-radius: 50%">
<img src="https://github.com/nickarellano.png?size=60" width="60" style="border-radius: 50%"/>
<a href="https://github.com/bglw" style="width:65px">
<img src="https://github.com/bglw.png?size=65" width="65"/>
</a>
<a href="https://github.com/bglw" style="width:65px;border-radius: 50%">
<img src="https://github.com/bglw.png?size=65" width="65" style="border-radius: 50%"/>
<a href="https://github.com/jugglingjsons" style="width:50px">
<img src="https://github.com/jugglingjsons.png?size=50" width="50"/>
</a>
<a href="https://github.com/jugglingjsons" style="width:50px;border-radius: 50%">
<img src="https://github.com/jugglingjsons.png?size=50" width="50" style="border-radius: 50%"/>
<a href="https://github.com/marcus-crane" style="width:65px">
<img src="https://github.com/marcus-crane.png?size=65" width="65"/>
</a>
<a href="https://github.com/marcus-crane" style="width:50px;border-radius: 50%">
<img src="https://github.com/marcus-crane.png?size=50" width="50" style="border-radius: 50%"/>
<a href="https://github.com/bbergshaven" style="width:45px">
<img src="https://github.com/bbergshaven.png?size=45" width="45"/>
</a>
<a href="https://github.com/Gilgames000" style="width:45px">
<img src="https://github.com/Gilgames000.png?size=45" width="45"/>
</a>
<a href="https://github.com/ilgityildirim" style="width:50px">
<img src="https://github.com/ilgityildirim.png?size=50" width="50"/>
</a>
<a href="https://github.com/ondoki" style="width:65px">
<img src="https://github.com/ondoki.png?size=65" width="65"/>
</a>
<a href="https://github.com/questrail" style="width:50px">
<img src="https://github.com/questrail.png?size=50" width="50"/>
</a>
<a href="https://github.com/DonTomato" style="width:45px">
<img src="https://github.com/DonTomato.png?size=45" width="45"/>
</a>
<span id="nav-5"></span>

View File

@@ -71,6 +71,11 @@ const (
Crux
// RHEL distribution
RHEL
// NixOS distribution
NixOS
// Artix linux distribution
ArtixLinux
)
// DistroInfo contains all the information relating to a linux distribution
@@ -183,6 +188,10 @@ func parseOsRelease(osRelease string) *DistroInfo {
result.Distribution = EndeavourOS
case "crux":
result.Distribution = Crux
case "nixos":
result.Distribution = NixOS
case "artix":
result.Distribution = ArtixLinux
default:
result.Distribution = Unknown
}
@@ -274,6 +283,18 @@ func PrtGetInstalled(packageName string) (bool, error) {
return exitCode == 0, nil
}
// NixEnvInstalled uses nix-env to see if a package is installed
func NixEnvInstalled(packageName string) (bool, error) {
program := NewProgramHelper()
nixEnv := program.FindProgram("nix-env")
if nixEnv == nil {
return false, fmt.Errorf("cannot check dependencies: nix-env not found")
}
packageName = strings.ReplaceAll(packageName, "+", `\+`)
_, _, exitCode, _ := nixEnv.Run("-q", packageName)
return exitCode == 0, nil
}
// RequestSupportForDistribution promts the user to submit a request to support their
// currently unsupported distribution
func RequestSupportForDistribution(distroInfo *DistroInfo) error {

View File

@@ -213,6 +213,15 @@ distributions:
gccversioncommand: *gccdumpversion
programs: *archdefaultprograms
libraries: *archdefaultlibraries
artix:
id: artix
releases:
default:
version: default
name: Artix Linux
gccversioncommand: *gccdumpversion
programs: *archdefaultprograms
libraries: *archdefaultlibraries
ctlos:
id: ctlos
releases:
@@ -345,3 +354,22 @@ distributions:
help: Please install with `sudo prt-get depinst gtk3` and try again
- name: webkitgtk
help: Please install with `sudo prt-get depinst webkitgtk` and try again
nixos:
id: nixos
releases:
default:
version: default
name: NixOS
gccversioncommand: *gccdumpversion
programs:
- name: gcc
help: Please install with `nix-env -iA nixos.gcc`
- name: pkg-config
help: Please install with `nix-env -iA nixos.pkg-config`
- name: npm
help: Please install with `nix-env -iA nixos.nodejs`
libraries:
- name: gtk+3
help: Please install with `nix-env -iA nixos.gtk3`
- name: webkitgtk
help: Please install with `nix-env -iA nixos.nodePackages.webkitgtk`

View File

@@ -281,7 +281,7 @@ func CheckDependencies(logger *Logger) (bool, error) {
switch distroInfo.Distribution {
case Ubuntu, Debian, Zorin, Parrot, Linuxmint, Elementary, Kali, Neon, Deepin, Raspbian, PopOS:
libraryChecker = DpkgInstalled
case Arch, ArcoLinux, ArchLabs, Ctlos, Manjaro, ManjaroARM, EndeavourOS:
case Arch, ArcoLinux, ArchLabs, Ctlos, Manjaro, ManjaroARM, EndeavourOS, ArtixLinux:
libraryChecker = PacmanInstalled
case CentOS, Fedora, Tumbleweed, Leap, RHEL:
libraryChecker = RpmInstalled
@@ -293,6 +293,8 @@ func CheckDependencies(logger *Logger) (bool, error) {
libraryChecker = EOpkgInstalled
case Crux:
libraryChecker = PrtGetInstalled
case NixOS:
libraryChecker = NixEnvInstalled
default:
return false, RequestSupportForDistribution(distroInfo)
}

View File

@@ -1,4 +1,4 @@
package cmd
// Version - Wails version
const Version = "v1.16.5"
const Version = "v1.16.7"

View File

@@ -15,6 +15,7 @@ func init() {
projectOptions := projectHelper.NewProjectOptions()
commandDescription := `Generates a new Wails project using the given flags.
Any flags that are required and not given will be prompted for.`
build := false
initCommand := app.Command("init", "Initialises a new Wails project").
LongDescription(commandDescription).
@@ -23,7 +24,8 @@ Any flags that are required and not given will be prompted for.`
StringFlag("template", "Template name", &projectOptions.Template).
StringFlag("name", "Project name", &projectOptions.Name).
StringFlag("description", "Project description", &projectOptions.Description).
StringFlag("output", "Output binary name", &projectOptions.BinaryName)
StringFlag("output", "Output binary name", &projectOptions.BinaryName).
BoolFlag("build", "Build project after generating", &build)
initCommand.Action(func() error {
@@ -64,6 +66,10 @@ Any flags that are required and not given will be prompted for.`
return err
}
genSpinner.Success()
if !build {
logger.Yellow("Project '%s' initialised. Run `wails build` to build it.", projectOptions.Name)
return nil
}
// Build the project
cwd, _ := os.Getwd()

7
go.mod
View File

@@ -5,7 +5,7 @@ require (
github.com/abadojack/whatlanggo v1.0.1
github.com/fatih/color v1.7.0
github.com/go-playground/colors v1.2.0
github.com/gorilla/websocket v1.4.0
github.com/gorilla/websocket v1.4.1
github.com/jackmordaunt/icns v1.0.0
github.com/kennygrant/sanitize v1.2.4
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
@@ -16,12 +16,13 @@ require (
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4
github.com/pkg/errors v0.8.1 // indirect
github.com/sirupsen/logrus v1.4.1
github.com/sirupsen/logrus v1.8.1
github.com/stretchr/objx v0.1.1 // indirect
github.com/stretchr/testify v1.3.0 // indirect
github.com/syossan27/tebata v0.0.0-20180602121909-b283fe4bc5ba
golang.org/x/image v0.0.0-20200430140353-33d19683fad8
golang.org/x/net v0.0.0-20200625001655-4c5254603344 // indirect
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359
golang.org/x/text v0.3.0
gopkg.in/AlecAivazis/survey.v1 v1.8.4
gopkg.in/yaml.v3 v3.0.0-20190709130402-674ba3eaed22

9
go.sum
View File

@@ -11,8 +11,8 @@ github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/go-playground/colors v1.2.0 h1:0EdjTXKrr2g1L/LQTYtIqabeHpZuGZz1U4osS1T8+5M=
github.com/go-playground/colors v1.2.0/go.mod h1:miw1R2JIE19cclPxsXqNdzLZsk4DP4iF+m88bRc7kfM=
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174 h1:WlZsjVhE8Af9IcZDGgJGQpNflI3+MJSBhsgT5PCtzBQ=
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A=
github.com/jackmordaunt/icns v1.0.0 h1:RYSxplerf/l/DUd09AHtITwckkv/mqjVv4DjYdPmAMQ=
@@ -54,6 +54,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
@@ -76,9 +78,12 @@ golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c h1:UIcGWL6/wpCfyGuJnRFJRurA+yj8RrW7Q6x2YMCXt6c=
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359 h1:2B5p2L5IfGiD7+b9BOoRMC6DgObAVZV+Fsp050NqXik=
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/AlecAivazis/survey.v1 v1.8.4 h1:10xXXN3wgIhPheb5NI58zFgZv32Ana7P3Tl4shW+0Qc=

View File

@@ -54,7 +54,7 @@ extern "C"
int ready;
int js_busy;
int should_exit;
int min_width;
int min_height;
int max_width;
@@ -179,7 +179,7 @@ struct webview_priv
WEBVIEW_API int webview_inject_css(struct webview *w, const char *css);
WEBVIEW_API void webview_set_title(struct webview *w, const char *title);
WEBVIEW_API void webview_focus(struct webview *w);
WEBVIEW_API void webview_minsize(struct webview *w, int width, int height);
WEBVIEW_API void webview_minsize(struct webview *w, int width, int height);
WEBVIEW_API void webview_maxsize(struct webview *w, int width, int height);
WEBVIEW_API void webview_set_fullscreen(struct webview *w, int fullscreen);
WEBVIEW_API void webview_set_color(struct webview *w, uint8_t r, uint8_t g,
@@ -342,12 +342,12 @@ struct webview_priv
w->priv.should_exit = 0;
w->priv.queue = g_async_queue_new();
w->priv.window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
w->priv.min_width = -1;
w->priv.min_height = -1;
w->priv.max_width = -1;
w->priv.max_height = -1;
gtk_window_set_title(GTK_WINDOW(w->priv.window), w->title);
if (w->resizable)
@@ -421,13 +421,13 @@ struct webview_priv
}
WEBVIEW_API void webview_minsize(struct webview *w, int width, int height) {
w->priv.min_width = width;
w->priv.min_height = height;
GdkGeometry hints;
GdkWindowHints usedHints = (GdkWindowHints) GDK_HINT_MIN_SIZE;
hints.min_width = w->priv.min_width;
hints.min_height = w->priv.min_height;
if (w->priv.max_width != -1) {
@@ -435,18 +435,18 @@ struct webview_priv
hints.max_height = w->priv.max_height;
usedHints = (GdkWindowHints)(GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE);
}
gtk_window_set_geometry_hints(GTK_WINDOW(w->priv.window), w->priv.window, &hints, usedHints);
}
WEBVIEW_API void webview_maxsize(struct webview *w, int width, int height) {
w->priv.max_width = width;
w->priv.max_height = height;
GdkGeometry hints;
GdkWindowHints usedHints = (GdkWindowHints) GDK_HINT_MAX_SIZE;
if (w->priv.min_width != -1) {
hints.min_width = w->priv.min_width;
hints.min_height = w->priv.min_height;
@@ -454,7 +454,7 @@ struct webview_priv
}
hints.max_width = w->priv.max_width;
hints.max_height = w->priv.max_height;
gtk_window_set_geometry_hints(GTK_WINDOW(w->priv.window), w->priv.window, &hints, usedHints);
}
@@ -514,7 +514,6 @@ struct webview_priv
}
gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(dlg), FALSE);
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dlg), FALSE);
gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(dlg), TRUE);
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dlg), TRUE);
gtk_file_chooser_set_create_folders(GTK_FILE_CHOOSER(dlg), TRUE);
gint response = gtk_dialog_run(GTK_DIALOG(dlg));
@@ -1398,12 +1397,12 @@ struct webview_priv
case WM_GETMINMAXINFO:
{
if (w != NULL) {
// get pixel density
// get pixel density
HDC hDC = GetDC(NULL);
double DPIScaleX = GetDeviceCaps(hDC, 88)/96.0;
double DPIScaleY = GetDeviceCaps(hDC, 90)/96.0;
ReleaseDC(NULL, hDC);
RECT rcClient, rcWind;
POINT ptDiff;
GetClientRect(hwnd, &rcClient);
@@ -1413,7 +1412,7 @@ struct webview_priv
int heightExtra = (rcWind.bottom - rcWind.top) - rcClient.bottom;
LPMINMAXINFO lpMMI = (LPMINMAXINFO)lParam;
if (w->priv.min_width != -1) {
lpMMI->ptMinTrackSize.x = w->priv.min_width * DPIScaleX + widthExtra;
lpMMI->ptMinTrackSize.y = w->priv.min_height * DPIScaleY + heightExtra;
@@ -1423,7 +1422,7 @@ struct webview_priv
lpMMI->ptMaxTrackSize.y = w->priv.max_height * DPIScaleY + heightExtra;
}
}
return 0;
}
case WM_DESTROY:
@@ -2328,14 +2327,14 @@ struct webview_priv
{
[w->priv.window makeKeyWindow];
}
WEBVIEW_API void webview_minsize(struct webview *w, int width, int height) {
NSSize size;
size.width = width;
size.height = height;
[w->priv.window setMinSize:size];
}
WEBVIEW_API void webview_maxsize(struct webview *w, int width, int height) {
NSSize size;
size.width = width;
@@ -2346,7 +2345,7 @@ struct webview_priv
[button performSelectorOnMainThread:@selector(setEnabled:) withObject:NO
waitUntilDone:NO];
}
WEBVIEW_API void webview_set_fullscreen(struct webview *w, int fullscreen)
{
int b = ((([w->priv.window styleMask] & NSWindowStyleMaskFullScreen) ==
@@ -2503,4 +2502,4 @@ struct webview_priv
}
#endif
#endif /* WEBVIEW_H */
#endif /* WEBVIEW_H */

BIN
logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

View File

@@ -260,9 +260,9 @@
}
},
"path-parse": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true
},
"path-type": {

View File

@@ -117,12 +117,20 @@ func AddBuildSubcommand(app *clir.Cli, w io.Writer) {
}
// Tags
experimental := false
userTags := []string{}
for _, tag := range strings.Split(tags, " ") {
thisTag := strings.TrimSpace(tag)
if thisTag != "" {
userTags = append(userTags, thisTag)
}
if thisTag == "exp" {
experimental = true
}
}
if runtime.GOOS == "darwin" && !experimental {
return fmt.Errorf("MacOS version coming soon!")
}
// Webview2 installer strategy (download by default)

View File

@@ -1,18 +1,24 @@
package dev
import (
"context"
"fmt"
"io"
"log"
"net/http"
"os"
"os/exec"
"os/signal"
"path/filepath"
"runtime"
"strconv"
"strings"
"sync"
"syscall"
"time"
"github.com/wailsapp/wails/v2/cmd/wails/internal"
"github.com/wailsapp/wails/v2/internal/gomod"
"github.com/leaanthony/slicer"
"github.com/wailsapp/wails/v2/internal/project"
@@ -27,6 +33,8 @@ import (
"github.com/wailsapp/wails/v2/pkg/commands/build"
)
const defaultDevServerURL = "http://localhost:34115"
func LogGreen(message string, args ...interface{}) {
text := fmt.Sprintf(message, args...)
println(colour.Green(text))
@@ -50,143 +58,115 @@ func sliceToMap(input []string) map[string]struct{} {
return result
}
type devFlags struct {
ldflags string
compilerCommand string
assetDir string
extensions string
openBrowser bool
noReload bool
wailsjsdir string
tags string
verbosity int
loglevel string
forceBuild bool
debounceMS int
devServerURL string
}
// AddSubcommand adds the `dev` command for the Wails application
func AddSubcommand(app *clir.Cli, w io.Writer) error {
command := app.NewSubCommand("dev", "Development mode")
// Passthrough ldflags
ldflags := ""
command.StringFlag("ldflags", "optional ldflags", &ldflags)
// compiler command
compilerCommand := "go"
command.StringFlag("compiler", "Use a different go compiler to build, eg go1.15beta1", &compilerCommand)
assetDir := ""
command.StringFlag("assetdir", "Serve assets from the given directory", &assetDir)
// extensions to trigger rebuilds of application
extensions := "go"
command.StringFlag("e", "Extensions to trigger rebuilds (comma separated) eg go", &extensions)
openBrowser := false
command.BoolFlag("browser", "Open application in browser", &openBrowser)
noreload := false
command.BoolFlag("noreload", "Disable reload on asset change", &noreload)
wailsjsdir := ""
command.StringFlag("wailsjsdir", "Directory to generate the Wails JS modules", &wailsjsdir)
// tags to pass to `go`
tags := ""
command.StringFlag("tags", "tags to pass to Go compiler (quoted and space separated)", &tags)
// Verbosity
verbosity := 1
command.IntFlag("v", "Verbosity level (0 - silent, 1 - standard, 2 - verbose)", &verbosity)
loglevel := ""
command.StringFlag("loglevel", "Loglevel to use - Trace, Dev, Info, Warning, Error", &loglevel)
forceBuild := false
command.BoolFlag("f", "Force build application", &forceBuild)
flags := defaultDevFlags()
command.StringFlag("ldflags", "optional ldflags", &flags.ldflags)
command.StringFlag("compiler", "Use a different go compiler to build, eg go1.15beta1", &flags.compilerCommand)
command.StringFlag("assetdir", "Serve assets from the given directory", &flags.assetDir)
command.StringFlag("e", "Extensions to trigger rebuilds (comma separated) eg go", &flags.extensions)
command.BoolFlag("browser", "Open application in browser", &flags.openBrowser)
command.BoolFlag("noreload", "Disable reload on asset change", &flags.noReload)
command.StringFlag("wailsjsdir", "Directory to generate the Wails JS modules", &flags.wailsjsdir)
command.StringFlag("tags", "tags to pass to Go compiler (quoted and space separated)", &flags.tags)
command.IntFlag("v", "Verbosity level (0 - silent, 1 - standard, 2 - verbose)", &flags.verbosity)
command.StringFlag("loglevel", "Loglevel to use - Trace, Debug, Info, Warning, Error", &flags.loglevel)
command.BoolFlag("f", "Force build application", &flags.forceBuild)
command.IntFlag("debounce", "The amount of time to wait to trigger a reload on change", &flags.debounceMS)
command.StringFlag("devserverurl", "The url of the dev server to use", &flags.devServerURL)
command.Action(func() error {
// Create logger
logger := clilogger.New(w)
app.PrintBanner()
experimental := false
userTags := []string{}
for _, tag := range strings.Split(flags.tags, " ") {
thisTag := strings.TrimSpace(tag)
if thisTag != "" {
userTags = append(userTags, thisTag)
}
if thisTag == "exp" {
experimental = true
}
}
if runtime.GOOS == "darwin" && !experimental {
return fmt.Errorf("MacOS version coming soon!")
}
cwd, err := os.Getwd()
if err != nil {
return err
}
projectConfig, err := project.Load(cwd)
projectConfig, err := loadAndMergeProjectConfig(cwd, &flags)
if err != nil {
return err
}
if projectConfig.AssetDirectory == "" && assetDir == "" {
return fmt.Errorf("No asset directory provided. Please use -assetdir to indicate which directory contains your built assets.")
}
if assetDir == "" && projectConfig.AssetDirectory != "" {
assetDir = projectConfig.AssetDirectory
}
if assetDir != projectConfig.AssetDirectory {
projectConfig.AssetDirectory = filepath.ToSlash(assetDir)
err := projectConfig.Save()
if err != nil {
return err
}
}
assetDir, err := filepath.Abs(assetDir)
// Update go.mod to use current wails version
err = syncGoModVersion(cwd)
if err != nil {
return err
}
if wailsjsdir == "" && projectConfig.WailsJSDir != "" {
wailsjsdir = projectConfig.WailsJSDir
}
if wailsjsdir == "" {
wailsjsdir = "./frontend"
}
if wailsjsdir != projectConfig.WailsJSDir {
projectConfig.WailsJSDir = filepath.ToSlash(wailsjsdir)
err := projectConfig.Save()
if err != nil {
return err
}
}
buildOptions := &build.Options{
Logger: logger,
OutputType: "dev",
Mode: build.Dev,
Arch: runtime.GOARCH,
Pack: true,
Platform: runtime.GOOS,
LDFlags: ldflags,
Compiler: compilerCommand,
ForceBuild: forceBuild,
IgnoreFrontend: false,
Verbosity: verbosity,
WailsJSDir: wailsjsdir,
}
watcher, err := fsnotify.NewWatcher()
// Run go mod tidy to ensure we're up to date
err = runCommand(cwd, false, "go", "mod", "tidy")
if err != nil {
return err
}
defer func(watcher *fsnotify.Watcher) {
err := watcher.Close()
if err != nil {
log.Fatal(err)
}
}(watcher)
if flags.tags != "" {
err = runCommand(cwd, true, "wails", "generate", "module", "-tags", flags.tags)
} else {
err = runCommand(cwd, true, "wails", "generate", "module")
}
if err != nil {
return err
}
// frontend:dev server command
if projectConfig.DevCommand != "" {
var devCommandWaitGroup sync.WaitGroup
closer := runFrontendDevCommand(cwd, projectConfig.DevCommand, &devCommandWaitGroup)
defer closer(&devCommandWaitGroup)
}
buildOptions := generateBuildOptions(flags)
buildOptions.Logger = logger
buildOptions.UserTags = internal.ParseUserTags(flags.tags)
var debugBinaryProcess *process.Process = nil
var extensionsThatTriggerARebuild = sliceToMap(strings.Split(extensions, ","))
// Setup signal handler
quitChannel := make(chan os.Signal, 1)
signal.Notify(quitChannel, os.Interrupt, os.Kill, syscall.SIGTERM)
exitCodeChannel := make(chan int, 1)
var passthruArgs []string
//if len(os.Args) > 2 {
// passthruArgs = os.Args[2:]
//}
// Do initial build
logger.Println("Building application for development...")
newProcess, appBinary, err := restartApp(logger, buildOptions, debugBinaryProcess, loglevel, passthruArgs, assetDir, false, exitCodeChannel)
newProcess, appBinary, err := restartApp(buildOptions, debugBinaryProcess, flags, exitCodeChannel)
if err != nil {
return err
}
@@ -195,129 +175,32 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
}
// open browser
if openBrowser {
err = browser.OpenURL("http://localhost:34115")
if flags.openBrowser {
url := defaultDevServerURL
if flags.devServerURL != "" {
url = flags.devServerURL
}
err = browser.OpenURL(url)
if err != nil {
return err
}
}
if err != nil {
return err
}
var newBinaryProcess *process.Process
// Get project dir
projectDir, err := os.Getwd()
if err != nil {
return err
}
// Get all subdirectories
dirs, err := fs.GetSubdirectories(projectDir)
if err != nil {
return err
}
LogGreen("Watching (sub)/directory: %s", projectDir)
// Setup a watcher for non-node_modules directories
dirs.Each(func(dir string) {
if strings.Contains(dir, "node_modules") {
return
}
// Ignore build directory
if strings.HasPrefix(dir, filepath.Join(projectDir, "build")) {
return
}
// Ignore dot directories
if strings.HasPrefix(dir, ".") {
return
}
err = watcher.Add(dir)
// create the project files watcher
watcher, err := initialiseWatcher(cwd, logger.Fatal)
defer func(watcher *fsnotify.Watcher) {
err := watcher.Close()
if err != nil {
logger.Fatal(err.Error())
}
})
}(watcher)
// Main Loop
quit := false
// Use 100ms debounce
interval := 100 * time.Millisecond
timer := time.NewTimer(interval)
rebuild := false
reload := false
for quit == false {
//reload := false
select {
case exitCode := <-exitCodeChannel:
if exitCode == 0 {
quit = true
}
case item := <-watcher.Events:
// Check for file writes
if item.Op&fsnotify.Write == fsnotify.Write {
// Ignore directories
if fs.DirExists(item.Name) {
continue
}
LogGreen("Watching (sub)/directory: %s", cwd)
LogGreen("Using Dev Server URL: %s", flags.devServerURL)
LogGreen("Using reload debounce setting of %d milliseconds", flags.debounceMS)
// Iterate all file patterns
ext := filepath.Ext(item.Name)
if ext != "" {
ext = ext[1:]
if _, exists := extensionsThatTriggerARebuild[ext]; exists {
rebuild = true
continue
}
}
if strings.HasPrefix(item.Name, assetDir) {
reload = true
}
timer.Reset(interval)
}
// Check for new directories
if item.Op&fsnotify.Create == fsnotify.Create {
// If this is a folder, add it to our watch list
if fs.DirExists(item.Name) {
//node_modules is BANNED!
if !strings.Contains(item.Name, "node_modules") {
err := watcher.Add(item.Name)
if err != nil {
logger.Fatal("%s", err.Error())
}
LogGreen("Added new directory to watcher: %s", item.Name)
}
}
}
case <-timer.C:
if rebuild {
rebuild = false
LogGreen("[Rebuild triggered] files updated")
// Try and build the app
newBinaryProcess, _, err = restartApp(logger, buildOptions, debugBinaryProcess, loglevel, passthruArgs, assetDir, false, exitCodeChannel)
if err != nil {
LogRed("Error during build: %s", err.Error())
continue
}
// If we have a new process, save it
if newBinaryProcess != nil {
debugBinaryProcess = newBinaryProcess
}
}
if reload {
reload = false
_, err = http.Get("http://localhost:34115/wails/reload")
if err != nil {
LogRed("Error during refresh: %s", err.Error())
}
}
case <-quitChannel:
LogGreen("\nCaught quit")
quit = true
}
}
// Watch for changes and trigger restartApp()
doWatcherLoop(buildOptions, debugBinaryProcess, flags, watcher, exitCodeChannel, quitChannel)
// Kill the current program if running
if debugBinaryProcess != nil {
@@ -337,18 +220,233 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
return nil
})
return nil
}
func restartApp(logger *clilogger.CLILogger, buildOptions *build.Options, debugBinaryProcess *process.Process, loglevel string, passthruArgs []string, assetDir string, firstRun bool, exitCodeChannel chan int) (*process.Process, string, error) {
func syncGoModVersion(cwd string) error {
gomodFilename := filepath.Join(cwd, "go.mod")
gomodData, err := os.ReadFile(gomodFilename)
if err != nil {
return err
}
outOfSync, err := gomod.GoModOutOfSync(gomodData, internal.Version)
if err != nil {
return err
}
if !outOfSync {
return nil
}
LogGreen("Updating go.mod to use Wails '%s'", internal.Version)
newGoData, err := gomod.UpdateGoModVersion(gomodData, internal.Version)
if err != nil {
return err
}
return os.WriteFile(gomodFilename, newGoData, 0755)
}
func runCommand(dir string, exitOnError bool, command string, args ...string) error {
LogGreen("Executing: " + command + " " + strings.Join(args, " "))
cmd := exec.Command(command, args...)
cmd.Dir = dir
output, err := cmd.CombinedOutput()
if err != nil {
println(string(output))
if exitOnError {
os.Exit(1)
}
return err
}
return nil
}
// defaultDevFlags generates devFlags with default options
func defaultDevFlags() devFlags {
return devFlags{
devServerURL: defaultDevServerURL,
compilerCommand: "go",
verbosity: 1,
extensions: "go",
debounceMS: 100,
}
}
// generateBuildOptions creates a build.Options using the flags
func generateBuildOptions(flags devFlags) *build.Options {
result := &build.Options{
OutputType: "dev",
Mode: build.Dev,
Arch: runtime.GOARCH,
Pack: false,
Platform: runtime.GOOS,
LDFlags: flags.ldflags,
Compiler: flags.compilerCommand,
ForceBuild: flags.forceBuild,
IgnoreFrontend: false,
Verbosity: flags.verbosity,
WailsJSDir: flags.wailsjsdir,
}
switch runtime.GOOS {
case "darwin":
result.Pack = false
}
return result
}
// loadAndMergeProjectConfig reconciles flags passed to the CLI with project config settings and updates
// the project config if necessary
func loadAndMergeProjectConfig(cwd string, flags *devFlags) (*project.Project, error) {
projectConfig, err := project.Load(cwd)
if err != nil {
return nil, err
}
var shouldSaveConfig bool
if projectConfig.AssetDirectory == "" && flags.assetDir == "" {
return nil, fmt.Errorf("No asset directory provided. Please use -assetdir to indicate which directory contains your built assets.")
}
if flags.assetDir == "" && projectConfig.AssetDirectory != "" {
flags.assetDir = projectConfig.AssetDirectory
}
if flags.assetDir != projectConfig.AssetDirectory {
projectConfig.AssetDirectory = filepath.ToSlash(flags.assetDir)
}
flags.assetDir, err = filepath.Abs(flags.assetDir)
if err != nil {
return nil, err
}
if flags.devServerURL == defaultDevServerURL && projectConfig.DevServerURL != defaultDevServerURL && projectConfig.DevServerURL != "" {
flags.devServerURL = projectConfig.DevServerURL
}
if flags.devServerURL != projectConfig.DevServerURL {
projectConfig.DevServerURL = flags.devServerURL
shouldSaveConfig = true
}
if flags.wailsjsdir == "" && projectConfig.WailsJSDir != "" {
flags.wailsjsdir = projectConfig.WailsJSDir
}
if flags.wailsjsdir == "" {
flags.wailsjsdir = "./frontend"
}
if flags.wailsjsdir != projectConfig.WailsJSDir {
projectConfig.WailsJSDir = filepath.ToSlash(flags.wailsjsdir)
shouldSaveConfig = true
}
if flags.debounceMS == 100 && projectConfig.DebounceMS != 100 {
if projectConfig.DebounceMS == 0 {
projectConfig.DebounceMS = 100
}
flags.debounceMS = projectConfig.DebounceMS
}
if flags.debounceMS != projectConfig.DebounceMS {
projectConfig.DebounceMS = flags.debounceMS
shouldSaveConfig = true
}
if shouldSaveConfig {
err = projectConfig.Save()
if err != nil {
return nil, err
}
}
return projectConfig, nil
}
// runFrontendDevCommand will run the `frontend:dev` command if it was given, ex- `npm run dev`
func runFrontendDevCommand(cwd string, devCommand string, wg *sync.WaitGroup) func(group *sync.WaitGroup) {
LogGreen("Running frontend dev command: '%s'", devCommand)
ctx, cancel := context.WithCancel(context.Background())
dir := filepath.Join(cwd, "frontend")
cmdSlice := strings.Split(devCommand, " ")
wg.Add(1)
cmd := exec.CommandContext(ctx, cmdSlice[0], cmdSlice[1:]...)
cmd.Stderr = os.Stderr
cmd.Stdout = os.Stdout
cmd.Dir = dir
go func(ctx context.Context, devCommand string, cwd string, wg *sync.WaitGroup) {
err := cmd.Run()
if err != nil {
if err.Error() != "exit status 1" {
LogRed("Error from '%s': %s", devCommand, err.Error())
}
}
LogGreen("Dev command exited!")
wg.Done()
}(ctx, devCommand, cwd, wg)
return func(wg *sync.WaitGroup) {
if runtime.GOOS == "windows" {
// Credit: https://stackoverflow.com/a/44551450
// For whatever reason, killing an npm script on windows just doesn't exit properly with cancel
if cmd != nil && cmd.Process != nil {
kill := exec.Command("TASKKILL", "/T", "/F", "/PID", strconv.Itoa(cmd.Process.Pid))
kill.Stderr = os.Stderr
kill.Stdout = os.Stdout
err := kill.Run()
if err != nil {
if err.Error() != "exit status 1" {
LogRed("Error from '%s': %s", devCommand, err.Error())
}
}
}
} else {
cancel()
}
wg.Wait()
}
}
// initialiseWatcher creates the project directory watcher that will trigger recompile
func initialiseWatcher(cwd string, logFatal func(string, ...interface{})) (*fsnotify.Watcher, error) {
watcher, err := fsnotify.NewWatcher()
if err != nil {
return nil, err
}
// Get all subdirectories
dirs, err := fs.GetSubdirectories(cwd)
if err != nil {
return nil, err
}
// Setup a watcher for non-node_modules directories
dirs.Each(func(dir string) {
if strings.Contains(dir, "node_modules") {
return
}
// Ignore build directory
if strings.HasPrefix(dir, filepath.Join(cwd, "build")) {
return
}
// Ignore dot directories
if strings.HasPrefix(dir, ".") {
return
}
err = watcher.Add(dir)
if err != nil {
logFatal(err.Error())
}
})
return watcher, nil
}
// restartApp does the actual rebuilding of the application when files change
func restartApp(buildOptions *build.Options, debugBinaryProcess *process.Process, flags devFlags, exitCodeChannel chan int) (*process.Process, string, error) {
appBinary, err := build.Build(buildOptions)
println()
if err != nil {
if firstRun {
return nil, "", err
}
LogRed("Build error - continuing to run current version")
LogDarkYellow(err.Error())
return nil, "", nil
@@ -359,7 +457,7 @@ func restartApp(logger *clilogger.CLILogger, buildOptions *build.Options, debugB
killError := debugBinaryProcess.Kill()
if killError != nil {
logger.Fatal("Unable to kill debug binary (PID: %d)!", debugBinaryProcess.PID())
buildOptions.Logger.Fatal("Unable to kill debug binary (PID: %d)!", debugBinaryProcess.PID())
}
debugBinaryProcess = nil
@@ -367,13 +465,12 @@ func restartApp(logger *clilogger.CLILogger, buildOptions *build.Options, debugB
// Start up new binary with correct args
args := slicer.StringSlicer{}
args.Add("-loglevel", loglevel)
if assetDir != "" {
args.Add("-assetdir", assetDir)
args.Add("-loglevel", flags.loglevel)
if flags.assetDir != "" {
args.Add("-assetdir", flags.assetDir)
}
if len(passthruArgs) > 0 {
args.AddSlice(passthruArgs)
if flags.devServerURL != "" {
args.Add("-devserverurl", flags.devServerURL)
}
newProcess := process.NewProcess(appBinary, args.AsSlice()...)
err = newProcess.Start(exitCodeChannel)
@@ -382,11 +479,98 @@ func restartApp(logger *clilogger.CLILogger, buildOptions *build.Options, debugB
if fs.FileExists(appBinary) {
deleteError := fs.DeleteFile(appBinary)
if deleteError != nil {
logger.Fatal("Unable to delete app binary: " + appBinary)
buildOptions.Logger.Fatal("Unable to delete app binary: " + appBinary)
}
}
logger.Fatal("Unable to start application: %s", err.Error())
buildOptions.Logger.Fatal("Unable to start application: %s", err.Error())
}
return newProcess, appBinary, nil
}
// doWatcherLoop is the main watch loop that runs while dev is active
func doWatcherLoop(buildOptions *build.Options, debugBinaryProcess *process.Process, flags devFlags, watcher *fsnotify.Watcher, exitCodeChannel chan int, quitChannel chan os.Signal) {
// Main Loop
var (
err error
newBinaryProcess *process.Process
)
var extensionsThatTriggerARebuild = sliceToMap(strings.Split(flags.extensions, ","))
quit := false
interval := time.Duration(flags.debounceMS) * time.Millisecond
timer := time.NewTimer(interval)
rebuild := false
reload := false
for quit == false {
//reload := false
select {
case exitCode := <-exitCodeChannel:
if exitCode == 0 {
quit = true
}
case item := <-watcher.Events:
// Check for file writes
if item.Op&fsnotify.Write == fsnotify.Write {
// Ignore directories
if fs.DirExists(item.Name) {
continue
}
// Iterate all file patterns
ext := filepath.Ext(item.Name)
if ext != "" {
ext = ext[1:]
if _, exists := extensionsThatTriggerARebuild[ext]; exists {
rebuild = true
timer.Reset(interval)
continue
}
}
if strings.HasPrefix(item.Name, flags.assetDir) {
reload = true
}
timer.Reset(interval)
}
// Check for new directories
if item.Op&fsnotify.Create == fsnotify.Create {
// If this is a folder, add it to our watch list
if fs.DirExists(item.Name) {
//node_modules is BANNED!
if !strings.Contains(item.Name, "node_modules") {
err := watcher.Add(item.Name)
if err != nil {
buildOptions.Logger.Fatal("%s", err.Error())
}
LogGreen("Added new directory to watcher: %s", item.Name)
}
}
}
case <-timer.C:
if rebuild {
rebuild = false
LogGreen("[Rebuild triggered] files updated")
// Try and build the app
newBinaryProcess, _, err = restartApp(buildOptions, debugBinaryProcess, flags, exitCodeChannel)
if err != nil {
LogRed("Error during build: %s", err.Error())
continue
}
// If we have a new process, save it
if newBinaryProcess != nil {
debugBinaryProcess = newBinaryProcess
}
}
if reload {
reload = false
_, err = http.Get("http://localhost:34115/wails/reload")
if err != nil {
LogRed("Error during refresh: %s", err.Error())
}
}
case <-quitChannel:
LogGreen("\nCaught quit")
quit = true
}
}
}

View File

@@ -6,8 +6,6 @@ import (
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/generate/template"
"github.com/leaanthony/clir"
"github.com/wailsapp/wails/v2/pkg/clilogger"
"github.com/wailsapp/wails/v2/pkg/parser"
)
// AddSubcommand adds the `generate` command for the Wails application
@@ -15,34 +13,11 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
command := app.NewSubCommand("generate", "Code Generation Tools")
//AddModuleCommand(app, command, w)
err := AddModuleCommand(app, command, w)
if err != nil {
return err
}
template.AddSubCommand(app, command, w)
return nil
}
func logPackage(pkg *parser.Package, logger *clilogger.CLILogger) {
logger.Println("Processed Go package '" + pkg.Gopackage.Name + "' as '" + pkg.Name + "'")
for _, strct := range pkg.Structs() {
logger.Println("")
logger.Println(" Processed struct '" + strct.Name + "'")
if strct.IsBound {
for _, method := range strct.Methods {
logger.Println(" Bound method '" + method.Name + "'")
}
}
if strct.IsUsedAsData {
for _, field := range strct.Fields {
if !field.Ignored {
logger.Print(" Processed ")
if field.IsOptional {
logger.Print("optional ")
}
logger.Println("field '" + field.Name + "' as '" + field.JSName() + "'")
}
}
}
}
logger.Println("")
}

View File

@@ -1,58 +1,58 @@
package generate
import (
"io"
"time"
"fmt"
"github.com/leaanthony/clir"
"github.com/wailsapp/wails/v2/pkg/clilogger"
"github.com/wailsapp/wails/v2/pkg/parser"
"github.com/wailsapp/wails/v2/cmd/wails/internal"
"github.com/wailsapp/wails/v2/internal/shell"
"io"
"os"
"path/filepath"
"runtime"
"strings"
)
func AddModuleCommand(app *clir.Cli, parent *clir.Command, w io.Writer) {
// AddModuleCommand adds the `module` subcommand for the `generate` command
func AddModuleCommand(app *clir.Cli, parent *clir.Command, w io.Writer) error {
// Backend API
backendAPI := parent.NewSubCommand("module", "Generates a JS module for the frontend to interface with the backend")
command := parent.NewSubCommand("module", "Generate wailsjs modules")
var tags string
command.StringFlag("tags", "tags to pass to Go compiler (quoted and space separated)", &tags)
// Quiet Init
quiet := false
backendAPI.BoolFlag("q", "Suppress output to console", &quiet)
command.Action(func() error {
backendAPI.Action(func() error {
filename := "wailsbindings"
if runtime.GOOS == "windows" {
filename += ".exe"
}
// go build -tags bindings -o bindings.exe
tempDir := os.TempDir()
filename = filepath.Join(tempDir, filename)
// Create logger
logger := clilogger.New(w)
logger.Mute(quiet)
app.PrintBanner()
logger.Print("Generating Javascript module for Go code...")
// Start Time
start := time.Now()
p, err := parser.GenerateWailsFrontendPackage()
cwd, err := os.Getwd()
if err != nil {
return err
}
logger.Println("done.")
logger.Println("")
elapsed := time.Since(start)
packages := p.Packages
// Print report
for _, pkg := range p.Packages {
if pkg.ShouldGenerate() {
logPackage(pkg, logger)
}
tagList := internal.ParseUserTags(tags)
tagList = append(tagList, "bindings")
stdout, stderr, err := shell.RunCommand(cwd, "go", "build", "-tags", strings.Join(tagList, ","), "-o", filename)
if err != nil {
return fmt.Errorf("%s\n%s\n%s", stdout, stderr, err)
}
logger.Println("%d packages parsed in %s.", len(packages), elapsed)
stdout, stderr, err = shell.RunCommand(cwd, filename)
if err != nil {
return fmt.Errorf("%s\n%s\n%s", stdout, stderr, err)
}
err = os.Remove(filename)
if err != nil {
return err
}
return nil
})
return nil
}

View File

@@ -21,7 +21,7 @@ The next steps to complete the template are:
You can test your template by running this command:
`wails init -name test -t {{.TemplateDir}}`
`wails init -n test -t {{.TemplateDir}}`
### Checklist

View File

@@ -12,5 +12,5 @@ To generate a platform native package, add the `-package` flag.
## Live Development
To run in live development mode, run `wails dev` in the project directory. In another terminal, go into the `frontend`
directory and run `npm run dev`. The frontend dev server will run on http://localhost:5000. Connect to this
directory and run `npm run dev`. The frontend dev server will run on http://localhost:34115. Connect to this
in your browser and connect to your application.

View File

@@ -2,7 +2,7 @@ module changeme
go 1.17
require github.com/wailsapp/wails/v2 v2.0.0-beta.1
require github.com/wailsapp/wails/v2 {{.WailsVersion}}
require (
github.com/andybalholm/brotli v1.0.2 // indirect
@@ -35,4 +35,4 @@ golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf // indirect
)
// replace github.com/wailsapp/wails/v2 v2.0.0-beta.1 => {{.WailsDirectory}}
// replace github.com/wailsapp/wails/v2 {{.WailsVersion}} => {{.WailsDirectory}}

View File

@@ -81,16 +81,18 @@ func AddSubCommand(app *clir.Cli, parent *clir.Command, w io.Writer) {
}
type templateData struct {
Name string
Description string
TemplateDir string
Name string
Description string
TemplateDir string
WailsVersion string
}
println("Extracting base template files...")
err = g.Extract(templateDir, &templateData{
Name: name,
TemplateDir: templateDir,
Name: name,
TemplateDir: templateDir,
WailsVersion: app.Version(),
})
if err != nil {
return err

View File

@@ -2,7 +2,12 @@ package initialise
import (
"fmt"
"github.com/flytam/filenamify"
"github.com/leaanthony/slicer"
"io"
"os"
"os/exec"
"path/filepath"
"strings"
"time"
@@ -46,8 +51,8 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
}
// VSCode project files
vscode := false
command.BoolFlag("vscode", "Generate VSCode project files", &vscode)
ide := ""
command.StringFlag("ide", "Generate IDE project files", &ide)
// List templates
list := false
@@ -75,6 +80,15 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
return nil
}
// Validate IDE option
supportedIDEs := slicer.String([]string{"vscode", "goland"})
ide = strings.ToLower(ide)
if ide != "" {
if !supportedIDEs.Contains(ide) {
return fmt.Errorf("ide '%s' not supported. Valid values: %s", ide, supportedIDEs.Join(" "))
}
}
if !quiet {
app.PrintBanner()
}
@@ -83,27 +97,47 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
logger.Println(task)
logger.Println(strings.Repeat("-", len(task)))
projectFilename, err := filenamify.Filenamify(projectName, filenamify.Options{
Replacement: "_",
MaxLength: 255,
})
if err != nil {
return err
}
goBinary, err := exec.LookPath("go")
if err != nil {
return fmt.Errorf("unable to find Go compiler. Please download and install Go: https://golang.org/dl/")
}
// Get base path and convert to forward slashes
goPath := filepath.ToSlash(filepath.Dir(goBinary))
// Trim bin directory
goSDKPath := strings.TrimSuffix(goPath, "/bin")
// Create Template Options
options := &templates.Options{
ProjectName: projectName,
TargetDir: projectDirectory,
TemplateName: templateName,
Logger: logger,
GenerateVSCode: vscode,
InitGit: initGit,
ProjectName: projectName,
TargetDir: projectDirectory,
TemplateName: templateName,
Logger: logger,
IDE: ide,
InitGit: initGit,
ProjectNameFilename: projectFilename,
WailsVersion: app.Version(),
GoSDKPath: goSDKPath,
}
// Try to discover author details from git config
findAuthorDetails(options)
return initProject(options)
return initProject(options, quiet)
})
return nil
}
// initProject is our main init command
func initProject(options *templates.Options) error {
func initProject(options *templates.Options, quiet bool) error {
// Start Time
start := time.Now()
@@ -120,6 +154,19 @@ func initProject(options *templates.Options) error {
return err
}
// Run `go mod tidy` to ensure `go.sum` is up to date
cmd := exec.Command("go", "mod", "tidy")
cmd.Dir = options.TargetDir
cmd.Stderr = os.Stderr
if !quiet {
println("")
cmd.Stdout = os.Stdout
}
err = cmd.Run()
if err != nil {
return err
}
if options.InitGit {
err = initGit(options)
if err != nil {
@@ -127,6 +174,10 @@ func initProject(options *templates.Options) error {
}
}
if quiet {
return nil
}
// Output stats
elapsed := time.Since(start)
options.Logger.Println("")
@@ -135,9 +186,14 @@ func initProject(options *templates.Options) error {
options.Logger.Println("Project Template: " + options.TemplateName)
options.Logger.Println("Template Support: " + template.HelpURL)
if options.GenerateVSCode {
// IDE message
switch options.IDE {
case "vscode":
options.Logger.Println("VSCode config files generated.")
case "goland":
options.Logger.Println("Goland config files generated.")
}
if options.InitGit {
options.Logger.Println("Git repository initialised.")
}

View File

@@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/{{.ProjectNameFilename}}.iml"
filepath="$PROJECT_DIR$/.idea/{{.ProjectNameFilename}}.iml"/>
</modules>
</component>
</project>

View File

@@ -0,0 +1 @@
{{.ProjectName}}

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="Go" enabled="true" />
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git"/>
</component>
</project>

View File

@@ -0,0 +1,95 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AutoImportSettings">
<option name="autoReloadType" value="ALL"/>
</component>
<component name="GOROOT" url="file://{{.GoSDKPath}}"/>
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$"/>
</component>
<component name="GoLibraries">
<option name="indexEntireGoPath" value="false"/>
</component>
<component name="ProjectId" id="wails-{{.ProjectName}}"/>
<component name="ProjectLevelVcsManager" settingsEditedManually="true"/>
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true"/>
<option name="showLibraryContents" value="true"/>
</component>
<component name="PropertiesComponent">
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true"/>
<property name="RunOnceActivity.ShowReadmeOnStart" value="true"/>
<property name="WebServerToolWindowFactoryState" value="false"/>
<property name="com.intellij.ide.scratch.LRUPopupBuilder$1/New Scratch File" value="TEXT"/>
<property name="go.formatter.settings.were.checked" value="true"/>
<property name="go.import.settings.migrated" value="true"/>
<property name="go.modules.go.list.on.any.changes.was.set" value="true"/>
<property name="go.sdk.automatically.set" value="true"/>
<property name="go.tried.to.enable.integration.vgo.integrator" value="true"/>
<property name="last_opened_file_path" value="$PROJECT_DIR$"/>
<property name="settings.editor.selected.configurable"
value="reference.settingsdialog.IDE.editor.colors.Console Font"/>
</component>
<component name="RunManager" selected="Go Build.{{.ProjectName}} (dev)">>
<configuration name="{{.ProjectName}} (dev)" type="GoApplicationRunConfiguration" factoryName="Go Application">
<module name="{{.ProjectName}}"/>
<working_directory value="$PROJECT_DIR$"/>
<go_parameters value="-gcflags &quot;all=-N -l&quot; -tags dev -o {{.PathToDesktopBinary}}"/>
<useCustomBuildTags value="true"/>
<parameters value="-assetdir {{.AssetDir}}"/>
<envs>
<env name="CGO_ENABLED" value="&quot;{{.CGOEnabled}}&quot;"/>
</envs>
<kind value="DIRECTORY"/>
<directory value="$PROJECT_DIR$"/>
<filePath value="$PROJECT_DIR$"/>
<method v="2">
</method>
</configuration>
<configuration name="{{.ProjectName}} (production)" type="GoApplicationRunConfiguration"
factoryName="Go Application">
<module name="{{.ProjectName}}"/>
<working_directory value="$PROJECT_DIR$"/>
<go_parameters
value="-ldflags &quot;-w -s{{.WindowsFlags}}&quot; -tags desktop,production -o {{.PathToDesktopBinary}}"/>
<useCustomBuildTags value="true"/>
<envs>
<env name="CGO_ENABLED" value="&quot;{{.CGOEnabled}}&quot;"/>
</envs>
<kind value="DIRECTORY"/>
<directory value="$PROJECT_DIR$"/>
<filePath value="$PROJECT_DIR$"/>
<method v="2">
</method>
</configuration>
<list>
<item itemvalue="Go Build.{{.ProjectName}} (dev)"/>
<item itemvalue="Go Remote.Local"/>
</list>
</component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0"
DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true"/>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="3"/>
</component>
<component name="Vcs.Log.Tabs.Properties">
<option name="TAB_STATES">
<map>
<entry key="MAIN">
<value>
<State/>
</value>
</entry>
</map>
</option>
<option name="oldMeFiltersMigrated" value="true"/>
</component>
<component name="VgoProject">
<integration-enabled>true</integration-enabled>
</component>
<component name="XDebuggerManager">
<breakpoint-manager>
</breakpoint-manager>
</component>
</project>

View File

@@ -42,6 +42,11 @@ type Data struct {
AuthorEmail string
AuthorNameAndEmail string
WailsDirectory string
GoSDKPath string
AssetDir string
WindowsFlags string
CGOEnabled string
OutputFile string
}
// Options for installing a template
@@ -51,13 +56,19 @@ type Options struct {
BinaryName string
TargetDir string
Logger *clilogger.CLILogger
GenerateVSCode bool
PathToDesktopBinary string
PathToServerBinary string
InitGit bool
AuthorName string
AuthorEmail string
AssetDir string
IDE string
ProjectNameFilename string // The project name but as a valid filename
WailsVersion string
GoSDKPath string
WindowsFlags string
CGOEnabled string
OutputFile string
}
// Template holds data relating to a template
@@ -241,6 +252,7 @@ func Install(options *Options) (bool, *Template, error) {
BinaryName := filepath.Base(options.TargetDir)
NPMProjectName := strings.ToLower(strings.ReplaceAll(BinaryName, " ", ""))
localWailsDirectory := fs.RelativePath("../../../../../..")
templateData := &Data{
ProjectName: options.ProjectName,
BinaryName: filepath.Base(options.TargetDir),
@@ -248,6 +260,9 @@ func Install(options *Options) (bool, *Template, error) {
WailsDirectory: localWailsDirectory,
AuthorEmail: options.AuthorEmail,
AuthorName: options.AuthorName,
WailsVersion: options.WailsVersion,
GoSDKPath: options.GoSDKPath,
AssetDir: options.AssetDir,
}
// Create a formatted name and email combo.
@@ -259,6 +274,10 @@ func Install(options *Options) (bool, *Template, error) {
}
templateData.AuthorNameAndEmail = strings.TrimSpace(templateData.AuthorNameAndEmail)
installer.RenameFiles(map[string]string{
"gitignore.txt": ".gitignore",
})
// Extract the template
err = installer.Extract(options.TargetDir, templateData)
if err != nil {
@@ -317,17 +336,58 @@ func OutputList(logger *clilogger.CLILogger) error {
func generateIDEFiles(options *Options) error {
if options.GenerateVSCode {
switch options.IDE {
case "vscode":
return generateVSCodeFiles(options)
case "goland":
return generateGolandFiles(options)
}
return nil
}
type ideOptions struct {
name string
targetDir string
options *Options
renameFiles map[string]string
ignoredFiles []string
}
func generateGolandFiles(options *Options) error {
ideoptions := ideOptions{
name: "goland",
targetDir: filepath.Join(options.TargetDir, ".idea"),
options: options,
renameFiles: map[string]string{
"projectname.iml": options.ProjectNameFilename + ".iml",
"gitignore.txt": ".gitignore",
"name": ".name",
},
}
if !options.InitGit {
ideoptions.ignoredFiles = []string{"vcs.xml"}
}
err := installIDEFiles(ideoptions)
if err != nil {
return errors.Wrap(err, "generating Goland IDE files")
}
return nil
}
func generateVSCodeFiles(options *Options) error {
ideoptions := ideOptions{
name: "vscode",
targetDir: filepath.Join(options.TargetDir, ".vscode"),
options: options,
}
return installIDEFiles(ideoptions)
targetDir := filepath.Join(options.TargetDir, ".vscode")
source, err := debme.FS(ides, "ides/vscode")
}
func installIDEFiles(o ideOptions) error {
source, err := debme.FS(ides, "ides/"+o.name)
if err != nil {
return err
}
@@ -335,14 +395,22 @@ func generateVSCodeFiles(options *Options) error {
// Use gosod to install the template
installer := gosod.New(source)
binaryName := filepath.Base(options.TargetDir)
if o.renameFiles != nil {
installer.RenameFiles(o.renameFiles)
}
for _, ignoreFile := range o.ignoredFiles {
installer.IgnoreFile(ignoreFile)
}
binaryName := filepath.Base(o.options.TargetDir)
if runtime.GOOS == "windows" {
// yay windows
binaryName += ".exe"
}
// Parse wails.json for assetdir
wailsJSONBytes, err := os.ReadFile(filepath.Join(options.TargetDir, "wails.json"))
wailsJSONBytes, err := os.ReadFile(filepath.Join(o.options.TargetDir, "wails.json"))
if err != nil {
return err
}
@@ -356,10 +424,16 @@ func generateVSCodeFiles(options *Options) error {
return fmt.Errorf("Unable to find 'assetdir' in 'wails.json' ")
}
options.AssetDir = assetDir.(string)
options.PathToDesktopBinary = filepath.ToSlash(filepath.Join("build", "bin", binaryName))
o.options.AssetDir = assetDir.(string)
o.options.PathToDesktopBinary = filepath.ToSlash(filepath.Join("build", "bin", binaryName))
err = installer.Extract(targetDir, options)
o.options.WindowsFlags = ""
o.options.CGOEnabled = "1"
if runtime.GOOS == "windows" {
o.options.WindowsFlags = " -H windowsgui"
o.options.CGOEnabled = "0"
}
err = installer.Extract(o.targetDir, o.options)
if err != nil {
return err
}

View File

@@ -22,7 +22,7 @@ func (b *App) startup(ctx context.Context) {
}
// domReady is called after the front-end dom has been loaded
func (b App) domReady(ctx context.Context) {
func (b *App) domReady(ctx context.Context) {
// Add your action here
}

View File

@@ -13,6 +13,7 @@ body {
margin: 0;
width: 100%;
height: 100%;
overscroll-behavior: none;
}
@font-face {

View File

@@ -0,0 +1,9 @@
# Wails bin directory
build/bin
# IDEs
.idea
.vscode
# The black hole that is...
node_modules

View File

@@ -2,7 +2,7 @@ module changeme
go 1.17
require github.com/wailsapp/wails/v2 v2.0.0-beta.1
require github.com/wailsapp/wails/v2 {{.WailsVersion}}
require (
github.com/andybalholm/brotli v1.0.2 // indirect
@@ -35,4 +35,4 @@ golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf // indirect
)
// replace github.com/wailsapp/wails/v2 v2.0.0-beta.1 => {{.WailsDirectory}}
// replace github.com/wailsapp/wails/v2 {{.WailsVersion}} => {{.WailsDirectory}}

View File

@@ -15,6 +15,7 @@ github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab h1:9e2joQGp642w
github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab/go.mod h1:smsv/h4PBEBaU0XDTY5UwJTpZv69fQ0FfcLJr21mA6Y=
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/flytam/filenamify v1.0.0/go.mod h1:Dzf9kVycwcsBlr2ATg6uxjqiFgKGH+5SKFuhdeP5zu8=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/gabriel-vasile/mimetype v1.3.1 h1:qevA6c2MtE1RorlScnixeG0VA1H4xrXyhyX3oWBynNQ=
github.com/gabriel-vasile/mimetype v1.3.1/go.mod h1:fA8fi6KUiG7MgQQ+mEWotXoEOvmxRtOJlERCzSmRvr8=
@@ -58,8 +59,9 @@ github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/jackmordaunt/icns v1.0.0/go.mod h1:7TTQVEuGzVVfOPPlLNHJIkzA6CoV7aH1Dv9dW351oOo=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5 h1:pdFFlHXY9tZXmJz+tRSm1DzYEH4ebha7cffmm607bMU=
github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck=
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
@@ -75,16 +77,15 @@ 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/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leaanthony/clir v1.0.4/go.mod h1:k/RBkdkFl18xkkACMCLt09bhiZnrGORoxmomeMvDpE0=
github.com/leaanthony/debme v1.1.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA=
github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc=
github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA=
github.com/leaanthony/go-ansi-parser v1.0.1 h1:97v6c5kYppVsbScf4r/VZdXyQ21KQIfeQOk2DgKxGG4=
github.com/leaanthony/go-ansi-parser v1.0.1/go.mod h1:7arTzgVI47srICYhvgUV4CGd063sGEeoSlych5yeSPM=
github.com/leaanthony/go-common-file-dialog v1.0.3 h1:O0uGjKnWtdEADGrkg+TyAAbZylykMwwx/MNEXn9fp+Y=
github.com/leaanthony/go-common-file-dialog v1.0.3/go.mod h1:TGhEc9eSJgRsupZ+iH1ZgAOnEo9zp05cRH2j08RPrF0=
github.com/leaanthony/go-webview2 v0.0.0-20210914103035-f00aa774a934 h1:nK/JTPyJi5QRqYjVZjXgtN4/dhg2qtngoLxLDVn429k=
github.com/leaanthony/go-webview2 v0.0.0-20210914103035-f00aa774a934/go.mod h1:lS5ds4bruPk9d7lzdF/OH31Z0YCerI6MmHNFGsWoUnM=
github.com/leaanthony/gosod v1.0.2/go.mod h1:W8RyeSFBXu7RpIxPGEJfW4moSyGGEjlJMLV25wEbAdU=
github.com/leaanthony/go-webview2 v0.0.0-20210928094513-a94a08b538bd h1:6m4zZ/esiByaDbzgdvDxjsOaIDgtuG1q2cyhjAi6uAg=
github.com/leaanthony/go-webview2 v0.0.0-20210928094513-a94a08b538bd/go.mod h1:lS5ds4bruPk9d7lzdF/OH31Z0YCerI6MmHNFGsWoUnM=
github.com/leaanthony/gosod v1.0.3/go.mod h1:BJ2J+oHsQIyIQpnLPjnqFGTMnOZXDbvWtRCSG7jGxs4=
github.com/leaanthony/idgen v1.0.0/go.mod h1:4nBZnt8ml/f/ic/EVQuLxuj817RccT2fyrUaZFxrcVA=
github.com/leaanthony/slicer v1.5.0 h1:aHYTN8xbCCLxJmkNKiLB6tgcMARl4eWmH9/F+S/0HtY=
github.com/leaanthony/slicer v1.5.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY=
@@ -146,6 +147,8 @@ github.com/valyala/fasthttp v1.28.0/go.mod h1:cmWIqlu99AO/RKcp1HWaViTqc57FswJOfY
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
github.com/wailsapp/wails/v2 v2.0.0-beta.3 h1:8vhBbnjpYDF6cCUwKadon7J/98UjcP1nrnptUl70Tfg=
github.com/wailsapp/wails/v2 v2.0.0-beta.3/go.mod h1:aku28riyHF2G5jmx/qtxjLWi7VwpTjhhX/HVLCptWFA=
github.com/wzshiming/ctc v1.2.3/go.mod h1:2tVAtIY7SUyraSk0JxvwmONNPFL4ARavPuEsg5+KA28=
github.com/wzshiming/winseq v0.0.0-20200112104235-db357dc107ae/go.mod h1:VTAq37rkGeV+WOybvZwjXiJOicICdpLCN8ifpISjK20=
github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0=
@@ -193,8 +196,8 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210611083646-a4fc73990273/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf h1:2ucpDCmfkl8Bd/FsLtiD653Wf96cW37s+iGx93zsu4k=
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 h1:foEbQz/B0Oz6YIqu/69kfXPYeFQAuuMYFkjaqXzl5Wo=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
@@ -222,4 +225,4 @@ gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=

View File

@@ -22,7 +22,7 @@ func (b *App) startup(ctx context.Context) {
}
// domReady is called after the front-end dom has been loaded
func (b App) domReady(ctx context.Context) {
func (b *App) domReady(ctx context.Context) {
// Add your action here
}

View File

@@ -8,8 +8,9 @@ body {
margin: 0;
color: white;
font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
"Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
sans-serif;
"Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
sans-serif;
overscroll-behavior: none;
}
@font-face {

View File

@@ -0,0 +1,9 @@
# Wails bin directory
build/bin
# IDEs
.idea
.vscode
# The black hole that is...
node_modules

View File

@@ -2,7 +2,7 @@ module changeme
go 1.17
require github.com/wailsapp/wails/v2 v2.0.0-beta.1
require github.com/wailsapp/wails/v2 {{.WailsVersion}}
require (
github.com/andybalholm/brotli v1.0.2 // indirect
@@ -35,4 +35,4 @@ golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf // indirect
)
// replace github.com/wailsapp/wails/v2 v2.0.0-beta.1 => {{.WailsDirectory}}
// replace github.com/wailsapp/wails/v2 {{.WailsVersion}} => {{.WailsDirectory}}

View File

@@ -15,6 +15,7 @@ github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab h1:9e2joQGp642w
github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab/go.mod h1:smsv/h4PBEBaU0XDTY5UwJTpZv69fQ0FfcLJr21mA6Y=
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/flytam/filenamify v1.0.0/go.mod h1:Dzf9kVycwcsBlr2ATg6uxjqiFgKGH+5SKFuhdeP5zu8=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/gabriel-vasile/mimetype v1.3.1 h1:qevA6c2MtE1RorlScnixeG0VA1H4xrXyhyX3oWBynNQ=
github.com/gabriel-vasile/mimetype v1.3.1/go.mod h1:fA8fi6KUiG7MgQQ+mEWotXoEOvmxRtOJlERCzSmRvr8=
@@ -58,8 +59,9 @@ github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/jackmordaunt/icns v1.0.0/go.mod h1:7TTQVEuGzVVfOPPlLNHJIkzA6CoV7aH1Dv9dW351oOo=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5 h1:pdFFlHXY9tZXmJz+tRSm1DzYEH4ebha7cffmm607bMU=
github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck=
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
@@ -75,16 +77,15 @@ 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/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leaanthony/clir v1.0.4/go.mod h1:k/RBkdkFl18xkkACMCLt09bhiZnrGORoxmomeMvDpE0=
github.com/leaanthony/debme v1.1.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA=
github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc=
github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA=
github.com/leaanthony/go-ansi-parser v1.0.1 h1:97v6c5kYppVsbScf4r/VZdXyQ21KQIfeQOk2DgKxGG4=
github.com/leaanthony/go-ansi-parser v1.0.1/go.mod h1:7arTzgVI47srICYhvgUV4CGd063sGEeoSlych5yeSPM=
github.com/leaanthony/go-common-file-dialog v1.0.3 h1:O0uGjKnWtdEADGrkg+TyAAbZylykMwwx/MNEXn9fp+Y=
github.com/leaanthony/go-common-file-dialog v1.0.3/go.mod h1:TGhEc9eSJgRsupZ+iH1ZgAOnEo9zp05cRH2j08RPrF0=
github.com/leaanthony/go-webview2 v0.0.0-20210914103035-f00aa774a934 h1:nK/JTPyJi5QRqYjVZjXgtN4/dhg2qtngoLxLDVn429k=
github.com/leaanthony/go-webview2 v0.0.0-20210914103035-f00aa774a934/go.mod h1:lS5ds4bruPk9d7lzdF/OH31Z0YCerI6MmHNFGsWoUnM=
github.com/leaanthony/gosod v1.0.2/go.mod h1:W8RyeSFBXu7RpIxPGEJfW4moSyGGEjlJMLV25wEbAdU=
github.com/leaanthony/go-webview2 v0.0.0-20210928094513-a94a08b538bd h1:6m4zZ/esiByaDbzgdvDxjsOaIDgtuG1q2cyhjAi6uAg=
github.com/leaanthony/go-webview2 v0.0.0-20210928094513-a94a08b538bd/go.mod h1:lS5ds4bruPk9d7lzdF/OH31Z0YCerI6MmHNFGsWoUnM=
github.com/leaanthony/gosod v1.0.3/go.mod h1:BJ2J+oHsQIyIQpnLPjnqFGTMnOZXDbvWtRCSG7jGxs4=
github.com/leaanthony/idgen v1.0.0/go.mod h1:4nBZnt8ml/f/ic/EVQuLxuj817RccT2fyrUaZFxrcVA=
github.com/leaanthony/slicer v1.5.0 h1:aHYTN8xbCCLxJmkNKiLB6tgcMARl4eWmH9/F+S/0HtY=
github.com/leaanthony/slicer v1.5.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY=
@@ -146,6 +147,8 @@ github.com/valyala/fasthttp v1.28.0/go.mod h1:cmWIqlu99AO/RKcp1HWaViTqc57FswJOfY
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
github.com/wailsapp/wails/v2 v2.0.0-beta.3 h1:8vhBbnjpYDF6cCUwKadon7J/98UjcP1nrnptUl70Tfg=
github.com/wailsapp/wails/v2 v2.0.0-beta.3/go.mod h1:aku28riyHF2G5jmx/qtxjLWi7VwpTjhhX/HVLCptWFA=
github.com/wzshiming/ctc v1.2.3/go.mod h1:2tVAtIY7SUyraSk0JxvwmONNPFL4ARavPuEsg5+KA28=
github.com/wzshiming/winseq v0.0.0-20200112104235-db357dc107ae/go.mod h1:VTAq37rkGeV+WOybvZwjXiJOicICdpLCN8ifpISjK20=
github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0=
@@ -193,8 +196,8 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210611083646-a4fc73990273/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf h1:2ucpDCmfkl8Bd/FsLtiD653Wf96cW37s+iGx93zsu4k=
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 h1:foEbQz/B0Oz6YIqu/69kfXPYeFQAuuMYFkjaqXzl5Wo=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=

View File

@@ -86,7 +86,7 @@ func updateToVersion(logger *clilogger.CLILogger, targetVersion *github.Semantic
// Early exit
if targetVersionString == currentVersion {
logger.Println("Looks like you're up to date!")
logger.Println("\nLooks like you're up to date!")
return nil
}
@@ -151,14 +151,16 @@ func updateToVersion(logger *clilogger.CLILogger, targetVersion *github.Semantic
log.Fatal("Cannot find home directory! Please file a bug report!")
}
sout, serr, err := shell.RunCommand(homeDir, "go", "get", "github.com/wailsapp/wails/v2/cmd/wails@"+desiredVersion)
sout, serr, err := shell.RunCommand(homeDir, "go", "install", "github.com/wailsapp/wails/v2/cmd/wails@"+desiredVersion)
if err != nil {
logger.Println("Failed.")
logger.Println(sout + `\n` + serr)
return err
}
fmt.Println()
logger.Println("\n")
logger.Println("Wails CLI updated to " + desiredVersion)
logger.Println("Make sure you update your project go.mod file to use " + desiredVersion + ":")
logger.Println(" require github.com/wailsapp/wails/v2 " + desiredVersion)
return nil
}

View File

@@ -0,0 +1,15 @@
package internal
import "strings"
// ParseUserTags takes the string form of tags and converts to a slice of strings
func ParseUserTags(tagString string) []string {
userTags := make([]string, 0)
for _, tag := range strings.Split(tagString, " ") {
thisTag := strings.TrimSpace(tag)
if thisTag != "" {
userTags = append(userTags, thisTag)
}
}
return userTags
}

View File

@@ -0,0 +1,3 @@
package internal
var Version = "v2.0.0-beta.15"

View File

@@ -2,6 +2,7 @@ package main
import (
"fmt"
"github.com/wailsapp/wails/v2/cmd/wails/internal"
"os"
"github.com/wailsapp/wails/v2/internal/colour"
@@ -24,7 +25,7 @@ func fatal(message string) {
func banner(_ *clir.Cli) string {
return fmt.Sprintf("%s %s\n",
colour.Yellow("Wails CLI"),
colour.DarkRed(version))
colour.DarkRed(internal.Version))
}
func printFooter() {
@@ -35,7 +36,7 @@ func main() {
var err error
app := clir.NewCli("Wails", "Go/HTML Appkit", version)
app := clir.NewCli("Wails", "Go/HTML Appkit", internal.Version)
app.SetBannerFunction(banner)
defer printFooter()
@@ -61,14 +62,14 @@ func main() {
fatal(err.Error())
}
err = update.AddSubcommand(app, os.Stdout, version)
err = update.AddSubcommand(app, os.Stdout, internal.Version)
if err != nil {
fatal(err.Error())
}
command := app.NewSubCommand("version", "The Wails CLI version")
command.Action(func() error {
println(version)
println(internal.Version)
return nil
})

View File

@@ -1,3 +0,0 @@
package main
var version = "v2.0.0-beta.2"

View File

@@ -5,6 +5,7 @@ go 1.17
require (
github.com/Masterminds/semver v1.5.0
github.com/fatih/structtag v1.2.0
github.com/flytam/filenamify v1.0.0
github.com/fsnotify/fsnotify v1.4.9
github.com/gabriel-vasile/mimetype v1.3.1
github.com/go-git/go-billy/v5 v5.2.0 // indirect
@@ -20,8 +21,8 @@ require (
github.com/leaanthony/debme v1.2.1
github.com/leaanthony/go-ansi-parser v1.0.1
github.com/leaanthony/go-common-file-dialog v1.0.3
github.com/leaanthony/go-webview2 v0.0.0-20210928094513-a94a08b538bd
github.com/leaanthony/gosod v1.0.2
github.com/leaanthony/go-webview2 v0.0.0-20211022194343-1e4c8d4226f3
github.com/leaanthony/gosod v1.0.3
github.com/leaanthony/idgen v1.0.0
github.com/leaanthony/slicer v1.5.0
github.com/leaanthony/typescriptify-golang-structs v0.1.7
@@ -40,9 +41,9 @@ require (
github.com/wzshiming/ctc v1.2.3
github.com/xyproto/xpm v1.2.1
github.com/ztrue/tracerr v0.3.0
golang.org/x/mod v0.4.1 // indirect
golang.org/x/mod v0.4.1
golang.org/x/net v0.0.0-20210510120150-4163338589ed
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6
golang.org/x/sys v0.0.0-20211020174200-9d6173849985
golang.org/x/tools v0.1.0
nhooyr.io/websocket v1.8.6
)

View File

@@ -22,6 +22,8 @@ github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab/go.mod h1:smsv/
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/flytam/filenamify v1.0.0 h1:ewx6BY2dj7U6h2zGPJmt33q/BjkSf/YsY/woQvnUNIs=
github.com/flytam/filenamify v1.0.0/go.mod h1:Dzf9kVycwcsBlr2ATg6uxjqiFgKGH+5SKFuhdeP5zu8=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/gabriel-vasile/mimetype v1.3.1 h1:qevA6c2MtE1RorlScnixeG0VA1H4xrXyhyX3oWBynNQ=
@@ -84,7 +86,6 @@ github.com/jackmordaunt/icns v1.0.0 h1:RYSxplerf/l/DUd09AHtITwckkv/mqjVv4DjYdPmA
github.com/jackmordaunt/icns v1.0.0/go.mod h1:7TTQVEuGzVVfOPPlLNHJIkzA6CoV7aH1Dv9dW351oOo=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5 h1:pdFFlHXY9tZXmJz+tRSm1DzYEH4ebha7cffmm607bMU=
github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck=
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
@@ -108,19 +109,16 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leaanthony/clir v1.0.4 h1:Dov2y9zWJmZr7CjaCe86lKa4b5CSxskGAt2yBkoDyiU=
github.com/leaanthony/clir v1.0.4/go.mod h1:k/RBkdkFl18xkkACMCLt09bhiZnrGORoxmomeMvDpE0=
github.com/leaanthony/debme v1.1.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA=
github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc=
github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA=
github.com/leaanthony/go-ansi-parser v1.0.1 h1:97v6c5kYppVsbScf4r/VZdXyQ21KQIfeQOk2DgKxGG4=
github.com/leaanthony/go-ansi-parser v1.0.1/go.mod h1:7arTzgVI47srICYhvgUV4CGd063sGEeoSlych5yeSPM=
github.com/leaanthony/go-common-file-dialog v1.0.3 h1:O0uGjKnWtdEADGrkg+TyAAbZylykMwwx/MNEXn9fp+Y=
github.com/leaanthony/go-common-file-dialog v1.0.3/go.mod h1:TGhEc9eSJgRsupZ+iH1ZgAOnEo9zp05cRH2j08RPrF0=
github.com/leaanthony/go-webview2 v0.0.0-20210914103035-f00aa774a934 h1:nK/JTPyJi5QRqYjVZjXgtN4/dhg2qtngoLxLDVn429k=
github.com/leaanthony/go-webview2 v0.0.0-20210914103035-f00aa774a934/go.mod h1:lS5ds4bruPk9d7lzdF/OH31Z0YCerI6MmHNFGsWoUnM=
github.com/leaanthony/go-webview2 v0.0.0-20210928094513-a94a08b538bd h1:6m4zZ/esiByaDbzgdvDxjsOaIDgtuG1q2cyhjAi6uAg=
github.com/leaanthony/go-webview2 v0.0.0-20210928094513-a94a08b538bd/go.mod h1:lS5ds4bruPk9d7lzdF/OH31Z0YCerI6MmHNFGsWoUnM=
github.com/leaanthony/gosod v1.0.2 h1:LtjqaIoHuoXiQXbzMPq0isjNfltSyHKhWeiU/JbmP0w=
github.com/leaanthony/gosod v1.0.2/go.mod h1:W8RyeSFBXu7RpIxPGEJfW4moSyGGEjlJMLV25wEbAdU=
github.com/leaanthony/go-webview2 v0.0.0-20211022194343-1e4c8d4226f3 h1:qhgrg3MhFRAIvtaqoqI+SrT+0wDYpxDMp9e3cvcxMpI=
github.com/leaanthony/go-webview2 v0.0.0-20211022194343-1e4c8d4226f3/go.mod h1:lS5ds4bruPk9d7lzdF/OH31Z0YCerI6MmHNFGsWoUnM=
github.com/leaanthony/gosod v1.0.3 h1:Fnt+/B6NjQOVuCWOKYRREZnjGyvg+mEhd1nkkA04aTQ=
github.com/leaanthony/gosod v1.0.3/go.mod h1:BJ2J+oHsQIyIQpnLPjnqFGTMnOZXDbvWtRCSG7jGxs4=
github.com/leaanthony/idgen v1.0.0 h1:IZreR+JGEzFV4yeVuBZA25gM0keUoFy+RDUldncQ+Jw=
github.com/leaanthony/idgen v1.0.0/go.mod h1:4nBZnt8ml/f/ic/EVQuLxuj817RccT2fyrUaZFxrcVA=
github.com/leaanthony/slicer v1.5.0 h1:aHYTN8xbCCLxJmkNKiLB6tgcMARl4eWmH9/F+S/0HtY=
@@ -259,10 +257,8 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210611083646-a4fc73990273/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf h1:2ucpDCmfkl8Bd/FsLtiD653Wf96cW37s+iGx93zsu4k=
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 h1:foEbQz/B0Oz6YIqu/69kfXPYeFQAuuMYFkjaqXzl5Wo=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211020174200-9d6173849985 h1:LOlKVhfDyahgmqa97awczplwkjzNaELFg3zRIJ13RYo=
golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

View File

@@ -0,0 +1,105 @@
//go:build bindings
// +build bindings
package appng
import (
"github.com/leaanthony/gosod"
"github.com/wailsapp/wails/v2/internal/binding"
wailsRuntime "github.com/wailsapp/wails/v2/internal/frontend/runtime"
"github.com/wailsapp/wails/v2/internal/frontend/runtime/wrapper"
"github.com/wailsapp/wails/v2/internal/fs"
"github.com/wailsapp/wails/v2/internal/logger"
"github.com/wailsapp/wails/v2/internal/project"
"github.com/wailsapp/wails/v2/pkg/options"
"os"
"path/filepath"
)
// 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}
appBindings := binding.NewBindings(a.logger, a.appoptions.Bind, bindingExemptions)
err := generateBindings(appBindings)
if err != nil {
return err
}
return nil
}
// CreateApp creates the app!
func CreateApp(appoptions *options.App) (*App, error) {
// Set up logger
myLogger := logger.New(appoptions.Logger)
myLogger.SetLogLevel(appoptions.LogLevel)
result := &App{
logger: myLogger,
appoptions: appoptions,
}
return result, nil
}
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
}
wrapperDir := filepath.Join(projectConfig.WailsJSDir, "wailsjs", "runtime")
_ = os.RemoveAll(wrapperDir)
extractor := gosod.New(wrapper.RuntimeWrapper)
err = extractor.Extract(wrapperDir, nil)
if err != nil {
return err
}
//ipcdev.js
err = os.WriteFile(filepath.Join(wrapperDir, "ipcdev.js"), wailsRuntime.DesktopIPC, 0755)
if err != nil {
return err
}
//runtimedev.js
err = os.WriteFile(filepath.Join(wrapperDir, "runtimedev.js"), wailsRuntime.RuntimeDesktopJS, 0755)
if err != nil {
return err
}
targetDir := filepath.Join(projectConfig.WailsJSDir, "wailsjs", "go")
err = os.RemoveAll(targetDir)
if err != nil {
return err
}
_ = fs.MkDirs(targetDir)
modelsFile := filepath.Join(targetDir, "models.ts")
err = bindings.WriteTS(modelsFile)
if err != nil {
return err
}
// Write backend method wrappers
bindingsFilename := filepath.Join(targetDir, "bindings.js")
err = bindings.GenerateBackendJS(bindingsFilename, true)
if err != nil {
return err
}
return nil
}

View File

@@ -1,4 +1,4 @@
//go:build darwin
//go:build darwin && !bindings
package appng

View File

@@ -1,4 +1,4 @@
//go:build !dev && !production && darwin
//go:build !dev && !production && !bindings && darwin
package appng

View File

@@ -1,4 +1,4 @@
//go:build !dev && !production && windows
//go:build !dev && !production && !bindings && windows
package appng
@@ -24,7 +24,7 @@ Please use "wails build" or press "OK" to open the documentation on how to use "
"Error",
w32.MB_ICONERROR|w32.MB_OKCANCEL)
if result == 1 {
exec.Command("rundll32", "url.dll,FileProtocolHandler", "https://wails.io").Start()
exec.Command("rundll32", "url.dll,FileProtocolHandler", "https://wails.io/docs/guides/manual-builds").Start()
}
return nil, nil
}

View File

@@ -61,11 +61,16 @@ func CreateApp(appoptions *options.App) (*App, error) {
// Check for CLI Flags
assetdir := flag.String("assetdir", "", "Directory to serve assets")
devServerURL := flag.String("devserverurl", "", "URL of development server")
loglevel := flag.String("loglevel", "debug", "Loglevel to use - Trace, Debug, Info, Warning, Error")
flag.Parse()
if devServerURL != nil && *devServerURL != "" {
ctx = context.WithValue(ctx, "devserverurl", *devServerURL)
}
if assetdir != nil && *assetdir != "" {
ctx = context.WithValue(ctx, "assetdir", *assetdir)
}
if loglevel != nil && *loglevel != "" {
level, err := pkglogger.StringToLogLevel(*loglevel)
if err != nil {
@@ -157,7 +162,7 @@ func generateBindings(bindings *binding.Bindings) error {
// Write backend method wrappers
bindingsFilename := filepath.Join(targetDir, "bindings.js")
err = bindings.GenerateBackendJS(bindingsFilename)
err = bindings.GenerateBackendJS(bindingsFilename, false)
if err != nil {
return err
}

View File

@@ -1,4 +1,4 @@
//go:build windows
//go:build windows && !bindings
package appng

View File

@@ -4,18 +4,19 @@ import (
"bytes"
_ "embed"
"fmt"
"github.com/wailsapp/wails/v2/internal/fs"
"os"
"path/filepath"
"strings"
"github.com/wailsapp/wails/v2/internal/fs"
"github.com/leaanthony/slicer"
)
//go:embed assets/package.json
var packageJSON []byte
func (b *Bindings) GenerateBackendJS(targetfile string) error {
func (b *Bindings) GenerateBackendJS(targetfile string, isDevBindings bool) error {
store := b.db.store
var output bytes.Buffer
@@ -23,8 +24,18 @@ func (b *Bindings) GenerateBackendJS(targetfile string) error {
output.WriteString(`// @ts-check
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
`)
const go = {`)
if isDevBindings {
json, err := b.ToJSON()
if err != nil {
return err
}
output.WriteString("window.wailsbindings = " + json + ";")
output.WriteString("\n")
}
output.WriteString(`const go = {`)
output.WriteString("\n")
var sortedPackageNames slicer.StringSlicer
@@ -89,12 +100,10 @@ const go = {`)
})
output.WriteString(fmt.Sprintf(" }"))
output.WriteString("\n")
output.WriteString(" },\n")
})
output.WriteString(fmt.Sprintf(" }\n"))
output.WriteString("\n")
output.WriteString(" },\n\n")
})
output.WriteString(`};

View File

@@ -1252,7 +1252,7 @@ void createDelegate(struct Application *app) {
app->delegate = delegate;
msg_id(app->application, s("setDelegate:"), delegate);
msg_id(app->application, s("setDelegate:"), delegate);
}
bool windowShouldClose(id self, SEL cmd, id sender) {

View File

@@ -1 +1 @@
The version of WebView2 used: 1.0.864.35
The version of WebView2 SDK used: 1.0.992.28

View File

@@ -7,7 +7,7 @@ set sdk_version=%1
set native_dir="%~dp0\microsoft.web.webview2.%sdk_version%\build\native"
copy "%native_dir%\include\*.h" .. >NUL
copy "%native_dir%\x64\WebView2Loader.dll" "..\x64" >NUL
@rd /S /Q "microsoft.web.webview2.%sdk_version%"
@REM @rd /S /Q "microsoft.web.webview2.%sdk_version%"
del /s version.txt >nul 2>&1
echo The version of WebView2 SDK used: %sdk_version% > sdkversion.txt
echo SDK updated to %sdk_version%

View File

@@ -5,7 +5,7 @@ import (
"github.com/leaanthony/webview2runtime"
)
const MinimumRuntimeVersion string = "91.0.864.48"
const MinimumRuntimeVersion string = "91.0.992.28"
type installationStatus int

View File

@@ -0,0 +1,115 @@
//go:build dev
// +build dev
package assetserver
import (
"bytes"
"github.com/wailsapp/wails/v2/internal/frontend/runtime"
"github.com/wailsapp/wails/v2/pkg/options"
"golang.org/x/net/html"
"path/filepath"
"strings"
)
/*
The assetserver for dev serves assets from disk.
It injects a websocket based IPC script into `index.html`.
*/
import (
"os"
)
type BrowserAssetServer struct {
runtimeJS []byte
assetdir string
appOptions *options.App
}
func NewBrowserAssetServer(assetdir string, bindingsJSON string, appOptions *options.App) (*BrowserAssetServer, error) {
result := &BrowserAssetServer{
assetdir: assetdir,
appOptions: appOptions,
}
var buffer bytes.Buffer
buffer.WriteString(`window.wailsbindings='` + bindingsJSON + `';` + "\n")
buffer.Write(runtime.RuntimeDesktopJS)
result.runtimeJS = buffer.Bytes()
return result, nil
}
func (a *BrowserAssetServer) loadFileFromDisk(filename string) ([]byte, error) {
return os.ReadFile(filepath.Join(a.assetdir, filename))
}
func (a *BrowserAssetServer) processIndexHTML() ([]byte, error) {
indexHTML, err := a.loadFileFromDisk("index.html")
if err != nil {
return nil, err
}
htmlNode, err := getHTMLNode(indexHTML)
if err != nil {
return nil, err
}
err = appendSpinnerToBody(htmlNode)
if err != nil {
return nil, err
}
wailsOptions, err := extractOptions(indexHTML)
if err != nil {
return nil, err
}
if wailsOptions.disableIPCInjection == false {
err := insertScriptInHead(htmlNode, "/wails/ipc.js")
if err != nil {
return nil, err
}
}
if wailsOptions.disableRuntimeInjection == false {
err := insertScriptInHead(htmlNode, "/wails/runtime.js")
if err != nil {
return nil, err
}
}
var buffer bytes.Buffer
err = html.Render(&buffer, htmlNode)
if err != nil {
return nil, err
}
return buffer.Bytes(), nil
}
func (a *BrowserAssetServer) Load(filename string) ([]byte, string, error) {
var content []byte
var err error
switch filename {
case "/":
content, err = a.processIndexHTML()
case "/wails/runtime.js":
content = a.runtimeJS
case "/wails/ipc.js":
content = runtime.WebsocketIPC
default:
content, err = a.loadFileFromDisk(filename)
if strings.HasSuffix(filename, ".js") {
var buffer bytes.Buffer
buffer.WriteString("window.awaitIPC('" + filename + "', ()=>{")
buffer.Write(content)
buffer.WriteString(`
});`)
content = buffer.Bytes()
}
}
if err != nil {
return nil, "", err
}
mimeType := GetMimetype(filename, content)
return content, mimeType, nil
}

View File

@@ -10,13 +10,13 @@ import (
"github.com/wailsapp/wails/v2/internal/frontend/runtime"
"github.com/wailsapp/wails/v2/internal/logger"
"io/fs"
"log"
"path/filepath"
"strings"
)
type DesktopAssetServer struct {
assets debme.Debme
indexFile []byte
runtimeJS []byte
assetdir string
logger *logger.Logger
@@ -106,27 +106,41 @@ func (a *DesktopAssetServer) init(assets embed.FS) error {
if err != nil {
return err
}
indexHTML, err := a.assets.ReadFile("index.html")
if err != nil {
return err
}
a.indexFile, err = injectHTML(string(indexHTML), `<script src="/wails/runtime.js"></script>`)
if err != nil {
return err
}
a.indexFile, err = injectHTML(string(a.indexFile), `<script src="/wails/ipc.js"></script>`)
if err != nil {
return err
}
return nil
}
func (a *DesktopAssetServer) processIndexHTML() ([]byte, error) {
indexHTML, err := a.ReadFile("index.html")
if err != nil {
return nil, err
}
wailsOptions, err := extractOptions(indexHTML)
if err != nil {
log.Fatal(err)
return nil, err
}
if wailsOptions.disableRuntimeInjection == false {
indexHTML, err = injectHTML(string(indexHTML), `<script src="/wails/runtime.js"></script>`)
if err != nil {
return nil, err
}
}
if wailsOptions.disableIPCInjection == false {
indexHTML, err = injectHTML(string(indexHTML), `<script src="/wails/ipc.js"></script>`)
if err != nil {
return nil, err
}
}
return indexHTML, nil
}
func (a *DesktopAssetServer) Load(filename string) ([]byte, string, error) {
var content []byte
var err error
switch filename {
case "/":
content = a.indexFile
content, err = a.processIndexHTML()
case "/wails/runtime.js":
content = a.runtimeJS
case "/wails/ipc.js":

View File

@@ -1,93 +0,0 @@
//go:build dev
// +build dev
package assetserver
import (
"bytes"
"github.com/wailsapp/wails/v2/internal/frontend/runtime"
"github.com/wailsapp/wails/v2/pkg/options"
"path/filepath"
)
/*
The assetserver for dev serves assets from disk.
It injects a websocket based IPC script into `index.html`.
*/
import (
"os"
)
type AssetServer struct {
indexFile []byte
runtimeJS []byte
assetdir string
appOptions *options.App
}
func NewAssetServer(assetdir string, bindingsJSON string, appOptions *options.App) (*AssetServer, error) {
result := &AssetServer{
assetdir: assetdir,
appOptions: appOptions,
}
err := result.init()
if err != nil {
return nil, err
}
var buffer bytes.Buffer
buffer.WriteString(`window.wailsbindings='` + bindingsJSON + `';` + "\n")
buffer.Write(runtime.RuntimeDesktopJS)
result.runtimeJS = buffer.Bytes()
err = result.init()
return result, err
}
func (a *AssetServer) loadFileFromDisk(filename string) ([]byte, error) {
return os.ReadFile(filepath.Join(a.assetdir, filename))
}
func (a *AssetServer) init() error {
var err error
a.indexFile, err = a.loadFileFromDisk("index.html")
if err != nil {
return err
}
a.indexFile, err = injectHTML(string(a.indexFile), `<div id="wails-spinner"></div>`)
if err != nil {
return err
}
a.indexFile, err = injectHTML(string(a.indexFile), `<script src="/wails/ipc.js"></script>`)
if err != nil {
return err
}
a.indexFile, err = injectHTML(string(a.indexFile), `<script src="/wails/runtime.js"></script>`)
if err != nil {
return err
}
return nil
}
func (a *AssetServer) Load(filename string) ([]byte, string, error) {
var content []byte
var err error
switch filename {
case "/":
content = a.indexFile
case "/wails/runtime.js":
content = a.runtimeJS
case "/wails/ipc.js":
content = runtime.WebsocketIPC
default:
content, err = a.loadFileFromDisk(filename)
}
if err != nil {
return nil, "", err
}
mimeType := GetMimetype(filename, content)
return content, mimeType, nil
}

View File

@@ -2,20 +2,162 @@ package assetserver
import (
"bytes"
"errors"
"fmt"
"golang.org/x/net/html"
"strings"
)
type optionType string
const (
noAutoInject optionType = "noautoinject"
noAutoInjectRuntime optionType = "noautoinjectruntime"
noAutoInjectIPC optionType = "noautoinjectipc"
)
type Options struct {
disableRuntimeInjection bool
disableIPCInjection bool
}
func newOptions(optionString string) *Options {
var result = &Options{}
optionString = strings.ToLower(optionString)
options := strings.Split(optionString, ",")
for _, option := range options {
switch optionType(strings.TrimSpace(option)) {
case noAutoInject:
result.disableRuntimeInjection = true
result.disableIPCInjection = true
case noAutoInjectIPC:
result.disableIPCInjection = true
case noAutoInjectRuntime:
result.disableRuntimeInjection = true
}
}
return result
}
func injectHTML(input string, html string) ([]byte, error) {
splits := strings.Split(input, "</body>")
splits := strings.Split(input, "</head>")
if len(splits) != 2 {
return nil, fmt.Errorf("unable to locate a </body> tag in your html")
return nil, fmt.Errorf("unable to locate a </head> tag in your html")
}
var result bytes.Buffer
result.WriteString(splits[0])
result.WriteString(html)
result.WriteString("</body>")
result.WriteString("</head>")
result.WriteString(splits[1])
return result.Bytes(), nil
}
func extractOptions(htmldata []byte) (*Options, error) {
doc, err := html.Parse(bytes.NewReader(htmldata))
if err != nil {
return nil, err
}
var extractor func(*html.Node) *Options
extractor = func(node *html.Node) *Options {
if node.Type == html.ElementNode && node.Data == "meta" {
isWailsOptionsTag := false
wailsOptions := ""
for _, attr := range node.Attr {
if isWailsOptionsTag && attr.Key == "content" {
wailsOptions = attr.Val
}
if attr.Val == "wails-options" {
isWailsOptionsTag = true
}
}
return newOptions(wailsOptions)
}
for child := node.FirstChild; child != nil; child = child.NextSibling {
result := extractor(child)
if result != nil {
return result
}
}
return nil
}
result := extractor(doc)
if result == nil {
result = &Options{}
}
return result, nil
}
func createScriptNode(scriptName string) *html.Node {
return &html.Node{
Type: html.ElementNode,
Data: "script",
Attr: []html.Attribute{
{
Key: "src",
Val: scriptName,
},
},
}
}
func createDivNode(id string) *html.Node {
return &html.Node{
Type: html.ElementNode,
Data: "div",
Attr: []html.Attribute{
{
Namespace: "",
Key: "id",
Val: id,
},
},
}
}
func insertScriptInHead(htmlNode *html.Node, scriptName string) error {
headNode := findFirstTag(htmlNode, "head")
if headNode == nil {
return errors.New("cannot find head in HTML")
}
scriptNode := createScriptNode(scriptName)
if headNode.FirstChild != nil {
headNode.InsertBefore(scriptNode, headNode.FirstChild)
} else {
headNode.AppendChild(scriptNode)
}
return nil
}
func appendSpinnerToBody(htmlNode *html.Node) error {
bodyNode := findFirstTag(htmlNode, "body")
if bodyNode == nil {
return errors.New("cannot find body in HTML")
}
scriptNode := createDivNode("wails-spinner")
bodyNode.AppendChild(scriptNode)
return nil
}
func getHTMLNode(htmldata []byte) (*html.Node, error) {
return html.Parse(bytes.NewReader(htmldata))
}
func findFirstTag(htmlnode *html.Node, tagName string) *html.Node {
var extractor func(*html.Node) *html.Node
var result *html.Node
extractor = func(node *html.Node) *html.Node {
if node.Type == html.ElementNode && node.Data == tagName {
return node
}
for child := node.FirstChild; child != nil; child = child.NextSibling {
result := extractor(child)
if result != nil {
return result
}
}
return nil
}
result = extractor(htmlnode)
return result
}

View File

@@ -0,0 +1,70 @@
package assetserver
import (
"reflect"
"testing"
)
const realHTML = `<html>
<head>
<title>test3</title>
<meta name="wails-options" content="noautoinject">
<link rel="stylesheet" href="/main.css">
</head>
<body data-wails-drag>
<div class="logo"></div>
<div class="result" id="result">Please enter your name below <20></div>
<div class="input-box" id="input" data-wails-no-drag>
<input class="input" id="name" type="text" autocomplete="off">
<button class="btn" onclick="greet()">Greet</button>
</div>
<script src="/main.js"></script>
</body>
</html>
`
func genMeta(content string) []byte {
return []byte("<html><head><meta name=\"wails-options\" content=\"" + content + "\"></head><body></body></html>")
}
func genOptions(runtime bool, bindings bool) *Options {
return &Options{
disableRuntimeInjection: runtime,
disableIPCInjection: bindings,
}
}
func Test_extractOptions(t *testing.T) {
tests := []struct {
name string
htmldata []byte
want *Options
wantError bool
}{
{"empty", []byte(""), &Options{}, false},
{"bad data", []byte("<"), &Options{}, false},
{"bad options", genMeta("noauto"), genOptions(false, false), false},
{"realhtml", []byte(realHTML), genOptions(true, true), false},
{"noautoinject", genMeta("noautoinject"), genOptions(true, true), false},
{"noautoinjectipc", genMeta("noautoinjectipc"), genOptions(false, true), false},
{"noautoinjectruntime", genMeta("noautoinjectruntime"), genOptions(true, false), false},
{"spaces", genMeta(" noautoinjectruntime "), genOptions(true, false), false},
{"multiple", genMeta("noautoinjectruntime,noautoinjectipc"), genOptions(true, true), false},
{"multiple spaces", genMeta(" noautoinjectruntime, noautoinjectipc "), genOptions(true, true), false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := extractOptions(tt.htmldata)
if !tt.wantError && err != nil {
t.Errorf("did not want error but got it")
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("extractOptions() = %v, want %v", got, tt.want)
}
})
}
}

View File

@@ -5,8 +5,9 @@ import (
"path/filepath"
"strings"
"sync"
"github.com/gabriel-vasile/mimetype"
)
import "github.com/gabriel-vasile/mimetype"
var (
cache = map[string]string{}
@@ -33,6 +34,10 @@ func GetMimetype(filename string, data []byte) string {
result = strings.Replace(result, "text/plain", "text/css", 1)
}
if filepath.Ext(filename) == ".js" && strings.HasPrefix(result, "text/plain") {
result = strings.Replace(result, "text/plain", "text/javascript", 1)
}
if result == "" {
result = "application/octet-stream"
}

View File

@@ -14,6 +14,7 @@ func TestGetMimetype(t *testing.T) {
}{
// TODO: Add test cases.
{"css", args{"test.css", []byte("body{margin:0;padding:0;background-color:#d579b2}#app{font-family:Avenir,Helvetica,Arial,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-align:center;color:#2c3e50;background-color:#ededed}#nav{padding:30px}#nav a{font-weight:700;color:#2c\n3e50}#nav a.router-link-exact-active{color:#42b983}.hello[data-v-4e26ad49]{margin:10px 0}")}, "text/css; charset=utf-8"},
{"js", args{"test.js", []byte("let foo = 'bar'; console.log(foo);")}, "text/javascript; charset=utf-8"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

View File

@@ -0,0 +1,20 @@
//
// AppDelegate.h
// test
//
// Created by Lea Anthony on 10/10/21.
//
#ifndef AppDelegate_h
#define AppDelegate_h
#import <Cocoa/Cocoa.h>
@interface AppDelegate : NSResponder <NSTouchBarProvider>
@property bool alwaysOnTop;
@property (retain) NSWindow* mainWindow;
@end
#endif /* AppDelegate_h */

View File

@@ -0,0 +1,53 @@
//
// AppDelegate.m
// test
//
// Created by Lea Anthony on 10/10/21.
//
#import <Foundation/Foundation.h>
#import <Cocoa/Cocoa.h>
#import "AppDelegate.h"
@implementation AppDelegate
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender {
return NO;
}
- (void)applicationWillFinishLaunching:(NSNotification *)aNotification {
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
[self.mainWindow makeKeyAndOrderFront:self];
if (self.alwaysOnTop) {
[self.mainWindow setLevel:NSStatusWindowLevel];
}
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
[NSApp activateIgnoringOtherApps:YES];
}
//
//- (void) CreateMenu {
// [NSApplication sharedApplication];
// menubar = [[NSMenu new] autorelease];
// id appMenuItem = [[NSMenuItem new] autorelease];
// [menubar addItem:appMenuItem];
// [NSApp setMainMenu:menubar];
// id appMenu = [[NSMenu new] autorelease];
// id appName = [[NSProcessInfo processInfo] processName];
// id quitTitle = [@"Quit " stringByAppendingString:appName];
// id quitMenuItem = [[[NSMenuItem alloc] initWithTitle:quitTitle
// action:@selector(terminate:) keyEquivalent:@"q"]
// autorelease];
// [appMenu addItem:quitMenuItem];
// [appMenuItem setSubmenu:appMenu];
//}
//
//- (void) dealloc {
// [super dealloc];
// window = nil;
// menubar = nil;
//}
@synthesize touchBar;
@end

View File

@@ -0,0 +1,44 @@
//
// Application.h
// test
//
// Created by Lea Anthony on 10/10/21.
//
#ifndef Application_h
#define Application_h
#import <Foundation/Foundation.h>
#import <Cocoa/Cocoa.h>
#import "WailsContext.h"
WailsContext* Create(const char* title, int width, int height, int frameless, int resizable, int fullscreen, int fullSizeContent, int hideTitleBar, int titlebarAppearsTransparent, int hideTitle, int useToolbar, int hideToolbarSeparator, int webviewIsTransparent, int alwaysOnTop, int hideWindowOnClose, const char *appearance, int windowIsTranslucent, int debug);
void Run(void*);
void SetTitle(void* ctx, const char *title);
void Center(void* ctx);
void SetSize(void* ctx, int width, int height);
void SetMinSize(void* ctx, int width, int height);
void SetMaxSize(void* ctx, int width, int height);
void SetPosition(void* ctx, int x, int y);
void Fullscreen(void* ctx);
void UnFullscreen(void* ctx);
void Minimise(void* ctx);
void UnMinimise(void* ctx);
void Maximise(void* ctx);
void UnMaximise(void* ctx);
void Hide(void* ctx);
void Show(void* ctx);
void SetRGBA(void* ctx, int r, int g, int b, int a);
void ExecJS(void* ctx, const char*);
void Quit(void*);
const char* GetSize(void *ctx);
const char* GetPos(void *ctx);
void ProcessURLResponse(void *inctx, const char *url, const char *contentType, const char *data, int datalength);
void MessageDialog(void *inctx, const char* dialogType, const char* title, const char* message, const char* button1, const char* button2, const char* button3, const char* button4, const char* defaultButton, const char* cancelButton);
void OpenFileDialog(void *inctx, const char* title, const char* defaultFilename, const char* defaultDirectory, int allowDirectories, int allowFiles, int canCreateDirectories, int treatPackagesAsDirectories, int resolveAliases, int showHiddenFiles, int allowMultipleSelection, const char* filters);
void SaveFileDialog(void *inctx, const char* title, const char* defaultFilename, const char* defaultDirectory, int canCreateDirectories, int treatPackagesAsDirectories, int showHiddenFiles, const char* filters);
#endif /* Application_h */

View File

@@ -0,0 +1,214 @@
//
// Application.m
//
// Created by Lea Anthony on 10/10/21.
//
#import <Foundation/Foundation.h>
#import <Cocoa/Cocoa.h>
#import "WailsContext.h"
#import "Application.h"
#import "AppDelegate.h"
WailsContext* Create(const char* title, int width, int height, int frameless, int resizable, int fullscreen, int fullSizeContent, int hideTitleBar, int titlebarAppearsTransparent, int hideTitle, int useToolbar, int hideToolbarSeparator, int webviewIsTransparent, int alwaysOnTop, int hideWindowOnClose, const char *appearance, int windowIsTranslucent, int debug) {
WailsContext *result = [WailsContext new];
result.debug = debug;
[result CreateWindow:width :height :frameless :resizable :fullscreen :fullSizeContent :hideTitleBar :titlebarAppearsTransparent :hideTitle :useToolbar :hideToolbarSeparator :webviewIsTransparent :hideWindowOnClose :appearance :windowIsTranslucent];
[result SetTitle:title];
[result Center];
result.alwaysOnTop = alwaysOnTop;
result.hideOnClose = hideWindowOnClose;
return result;
}
void ProcessURLResponse(void *inctx, const char *url, const char *contentType, const char* data, int datalength) {
WailsContext *ctx = (__bridge WailsContext*) inctx;
NSString *nsurl = [[NSString alloc] initWithUTF8String:url];
NSString *nsContentType = [[NSString alloc] initWithUTF8String:contentType];
NSData *nsdata = [NSData dataWithBytes:data length:datalength];
[ctx processURLResponse:nsurl :nsContentType :nsdata];
}
void ExecJS(void* inctx, const char *script) {
WailsContext *ctx = (__bridge WailsContext*) inctx;
ON_MAIN_THREAD(
[ctx ExecJS:script];
);
}
void SetTitle(void* inctx, const char *title) {
WailsContext *ctx = (__bridge WailsContext*) inctx;
ON_MAIN_THREAD(
[ctx SetTitle:title];
);
}
void SetRGBA(void *inctx, int r, int g, int b, int a) {
WailsContext *ctx = (__bridge WailsContext*) inctx;
ON_MAIN_THREAD(
[ctx SetRGBA:r :g :b :a];
);
}
void SetSize(void* inctx, int width, int height) {
WailsContext *ctx = (__bridge WailsContext*) inctx;
ON_MAIN_THREAD(
[ctx SetSize:width :height];
);
}
void SetMinSize(void* inctx, int width, int height) {
WailsContext *ctx = (__bridge WailsContext*) inctx;
ON_MAIN_THREAD(
[ctx SetMinSize:width :height];
);
}
void SetMaxSize(void* inctx, int width, int height) {
WailsContext *ctx = (__bridge WailsContext*) inctx;
ON_MAIN_THREAD(
[ctx SetMaxSize:width :height];
);
}
void SetPosition(void* inctx, int x, int y) {
WailsContext *ctx = (__bridge WailsContext*) inctx;
ON_MAIN_THREAD(
[ctx SetSize:x :y];
);
}
void Center(void* inctx) {
WailsContext *ctx = (__bridge WailsContext*) inctx;
ON_MAIN_THREAD(
[ctx Center];
);
}
void Fullscreen(void* inctx) {
WailsContext *ctx = (__bridge WailsContext*) inctx;
ON_MAIN_THREAD(
[ctx Fullscreen];
);
}
void UnFullscreen(void* inctx) {
WailsContext *ctx = (__bridge WailsContext*) inctx;
ON_MAIN_THREAD(
[ctx UnFullscreen];
);
}
void Minimise(void* inctx) {
WailsContext *ctx = (__bridge WailsContext*) inctx;
ON_MAIN_THREAD(
[ctx Minimise];
);
}
void UnMinimise(void* inctx) {
WailsContext *ctx = (__bridge WailsContext*) inctx;
ON_MAIN_THREAD(
[ctx UnMinimise];
);
}
void Maximise(void* inctx) {
WailsContext *ctx = (__bridge WailsContext*) inctx;
ON_MAIN_THREAD(
[ctx Maximise];
);
}
const char* GetSize(void *inctx) {
WailsContext *ctx = (__bridge WailsContext*) inctx;
NSRect frame = [ctx.mainWindow frame];
NSString *result = [NSString stringWithFormat:@"%d,%d", (int)frame.size.width, (int)frame.size.height];
return [result UTF8String];
}
const char* GetPos(void *inctx) {
WailsContext *ctx = (__bridge WailsContext*) inctx;
NSScreen* screen = [ctx getCurrentScreen];
NSRect windowFrame = [ctx.mainWindow frame];
NSRect screenFrame = [screen visibleFrame];
int x = windowFrame.origin.x - screenFrame.origin.x;
int y = windowFrame.origin.y - screenFrame.origin.y;
y = screenFrame.size.height - y - windowFrame.size.height;
NSString *result = [NSString stringWithFormat:@"%d,%d",x,y];
return [result UTF8String];
}
void UnMaximise(void* inctx) {
WailsContext *ctx = (__bridge WailsContext*) inctx;
ON_MAIN_THREAD(
[ctx UnMaximise];
);
}
void Quit(void *inctx) {
WailsContext *ctx = (__bridge WailsContext*) inctx;
[NSApp stop:ctx];
}
void Hide(void *inctx) {
WailsContext *ctx = (__bridge WailsContext*) inctx;
ON_MAIN_THREAD(
[ctx Hide];
);
}
void Show(void *inctx) {
WailsContext *ctx = (__bridge WailsContext*) inctx;
ON_MAIN_THREAD(
[ctx Show];
);
}
void MessageDialog(void *inctx, const char* dialogType, const char* title, const char* message, const char* button1, const char* button2, const char* button3, const char* button4, const char* defaultButton, const char* cancelButton) {
WailsContext *ctx = (__bridge WailsContext*) inctx;
ON_MAIN_THREAD(
[ctx MessageDialog:dialogType :title :message :button1 :button2 :button3 :button4 :defaultButton :cancelButton];
)
}
void OpenFileDialog(void *inctx, const char* title, const char* defaultFilename, const char* defaultDirectory, int allowDirectories, int allowFiles, int canCreateDirectories, int treatPackagesAsDirectories, int resolveAliases, int showHiddenFiles, int allowMultipleSelection, const char* filters) {
WailsContext *ctx = (__bridge WailsContext*) inctx;
ON_MAIN_THREAD(
[ctx OpenFileDialog:title :defaultFilename :defaultDirectory :allowDirectories :allowFiles :canCreateDirectories :treatPackagesAsDirectories :resolveAliases :showHiddenFiles :allowMultipleSelection :filters];
)
}
void SaveFileDialog(void *inctx, const char* title, const char* defaultFilename, const char* defaultDirectory, int canCreateDirectories, int treatPackagesAsDirectories, int showHiddenFiles, const char* filters) {
WailsContext *ctx = (__bridge WailsContext*) inctx;
ON_MAIN_THREAD(
[ctx SaveFileDialog:title :defaultFilename :defaultDirectory :canCreateDirectories :treatPackagesAsDirectories :showHiddenFiles :filters];
)
}
void Run(void *inctx) {
WailsContext *ctx = (__bridge WailsContext*) inctx;
[NSApplication sharedApplication];
AppDelegate* delegate = [AppDelegate new];
[NSApp setDelegate:(id)delegate];
ctx.appdelegate = delegate;
delegate.mainWindow = ctx.mainWindow;
delegate.alwaysOnTop = ctx.alwaysOnTop;
[ctx loadRequest:@"wails://wails/"];
[NSApp run];
[ctx release];
NSLog(@"Here");
}

View File

@@ -0,0 +1,18 @@
//
// WailsAlert.h
// test
//
// Created by Lea Anthony on 20/10/21.
//
#ifndef WailsAlert_h
#define WailsAlert_h
#import <Cocoa/Cocoa.h>
@interface WailsAlert : NSAlert
- (void)addButton:(const char*)text :(const char*)defaultButton :(const char*)cancelButton;
@end
#endif /* WailsAlert_h */

View File

@@ -0,0 +1,30 @@
//
// WailsAlert.m
// test
//
// Created by Lea Anthony on 20/10/21.
//
#import <Foundation/Foundation.h>
#import "WailsAlert.h"
@implementation WailsAlert
- (void)addButton:(const char*)text :(const char*)defaultButton :(const char*)cancelButton {
if( text == nil ) {
return;
}
NSButton *button = [self addButtonWithTitle:[NSString stringWithUTF8String:text]];
if( defaultButton != nil && strcmp(text, defaultButton) == 0) {
[button setKeyEquivalent:@"\r"];
} else if( cancelButton != nil && strcmp(text, cancelButton) == 0) {
[button setKeyEquivalent:@"\033"];
} else {
[button setKeyEquivalent:@""];
}
}
@end

View File

@@ -0,0 +1,74 @@
//
// WailsContext.h
// test
//
// Created by Lea Anthony on 10/10/21.
//
#ifndef WailsContext_h
#define WailsContext_h
#import <Cocoa/Cocoa.h>
#import <WebKit/WebKit.h>
#define ON_MAIN_THREAD(str) dispatch_async(dispatch_get_main_queue(), ^{ str; });
@interface WailsWindow : NSWindow
- (BOOL)canBecomeKeyWindow;
@end
@interface WailsContext : NSObject <WKURLSchemeHandler,WKScriptMessageHandler>
@property (retain) WailsWindow* mainWindow;
@property (retain) WKWebView* webview;
@property (nonatomic, assign) id appdelegate;
@property bool hideOnClose;
@property bool shuttingDown;
@property NSSize maxSize;
@property NSSize minSize;
@property (retain) NSEvent* mouseEvent;
@property bool alwaysOnTop;
@property bool maximised;
@property bool debug;
@property (retain) WKUserContentController* userContentController;
@property (retain) NSMutableDictionary *urlRequests;
- (void) CreateWindow:(int)width :(int)height :(bool)frameless :(bool)resizable :(bool)fullscreen :(bool)fullSizeContent :(bool)hideTitleBar :(bool)titlebarAppearsTransparent :(bool)hideTitle :(bool)useToolbar :(bool)hideToolbarSeparator :(bool)webviewIsTransparent :(bool)hideWindowOnClose :(const char *)appearance :(bool)windowIsTranslucent;
- (void) SetSize:(int)width :(int)height;
- (void) SetPosition:(int)x :(int) y;
- (void) SetMinSize:(int)minWidth :(int)minHeight;
- (void) SetMaxSize:(int)maxWidth :(int)maxHeight;
- (void) SetTitle:(const char*)title;
- (void) Center;
- (void) Fullscreen;
- (void) UnFullscreen;
- (void) Minimise;
- (void) UnMinimise;
- (void) Maximise;
- (void) UnMaximise;
- (void) SetRGBA:(int)r :(int)g :(int)b :(int)a;
- (void) HideMouse;
- (void) ShowMouse;
- (void) Hide;
- (void) Show;
-(void) MessageDialog :(const char*)dialogType :(const char*)title :(const char*)message :(const char*)button1 :(const char*)button2 :(const char*)button3 :(const char*)button4 :(const char*)defaultButton :(const char*)cancelButton;
-(void) OpenFileDialog :(const char*)title :(const char*)defaultFilename :(const char*)defaultDirectory :(bool)allowDirectories :(bool)allowFiles :(bool)canCreateDirectories :(bool)treatPackagesAsDirectories :(bool)resolveAliases :(bool)showHiddenFiles :(bool)allowMultipleSelection :(const char*)filters;
-(void) SaveFileDialog :(const char*)title :(const char*)defaultFilename :(const char*)defaultDirectory :(bool)canCreateDirectories :(bool)treatPackagesAsDirectories :(bool)showHiddenFiles :(const char*)filters;
- (void) loadRequest:(NSString*)url;
- (void) processURLResponse:(NSString *)url :(NSString *)contentType :(NSData*)data;
- (void) ExecJS:(const char*)script;
- (NSScreen*) getCurrentScreen;
@end
#endif /* WailsContext_h */

View File

@@ -0,0 +1,527 @@
//
// WailsContext.m
// test
//
// Created by Lea Anthony on 10/10/21.
//
#import <Foundation/Foundation.h>
#import <WebKit/WebKit.h>
#import "WailsContext.h"
#import "WailsAlert.h"
#import "WindowDelegate.h"
#import "message.h"
@implementation WailsWindow
- (BOOL)canBecomeKeyWindow
{
return YES;
}
@end
@implementation WailsContext
- (void) SetSize:(int)width :(int)height {
if (self.shuttingDown) return;
NSRect frame = [self.mainWindow frame];
frame.origin.y += frame.size.height - height;
frame.size.width = width;
frame.size.height = height;
[self.mainWindow setFrame:frame display:TRUE animate:FALSE];
}
- (void) SetPosition:(int)x :(int)y {
if (self.shuttingDown) return;
NSScreen* screen = [self getCurrentScreen];
NSRect windowFrame = [self.mainWindow frame];
NSRect screenFrame = [screen visibleFrame];
windowFrame.origin.x += screenFrame.origin.x + (float)x;
windowFrame.origin.y += (screenFrame.origin.y + screenFrame.size.height) - windowFrame.size.height - (float)y;
[self.mainWindow setFrame:windowFrame display:TRUE animate:FALSE];
}
- (void) SetMinSize:(int)minWidth :(int)minHeight {
if (self.shuttingDown) return;
NSSize size = { minWidth, minHeight };
self.minSize = size;
[self.mainWindow setMinSize:size];
[self adjustWindowSize];
}
- (void) SetMaxSize:(int)maxWidth :(int)maxHeight {
if (self.shuttingDown) return;
NSSize size = { FLT_MAX, FLT_MAX };
size.width = maxWidth > 0 ? maxWidth : FLT_MAX;
size.height = maxHeight > 0 ? maxHeight : FLT_MAX;
self.maxSize = size;
[self.mainWindow setMinSize:size];
[self adjustWindowSize];
}
- (void) adjustWindowSize {
if (self.shuttingDown) return;
NSRect currentFrame = [self.mainWindow frame];
if ( currentFrame.size.width > self.maxSize.width ) currentFrame.size.width = self.maxSize.width;
if ( currentFrame.size.width < self.minSize.width ) currentFrame.size.width = self.minSize.width;
if ( currentFrame.size.height > self.maxSize.height ) currentFrame.size.height = self.maxSize.height;
if ( currentFrame.size.height < self.minSize.height ) currentFrame.size.height = self.minSize.height;
[self.mainWindow setFrame:currentFrame display:TRUE animate:FALSE];
}
- (void) dealloc {
[super dealloc];
[self.appdelegate release];
[self.mainWindow release];
[self.mouseEvent release];
[self.userContentController release];
[self.urlRequests release];
}
- (NSScreen*) getCurrentScreen {
NSScreen* screen = [self.mainWindow screen];
if( screen == NULL ) {
screen = [NSScreen mainScreen];
}
return screen;
}
- (void) SetTitle:(const char *)title {
NSString *_title = [NSString stringWithUTF8String:title];
[self.mainWindow setTitle:_title];
}
- (void) Center {
[self.mainWindow center];
}
- (void) CreateWindow:(int)width :(int)height :(bool)frameless :(bool)resizable :(bool)fullscreen :(bool)fullSizeContent :(bool)hideTitleBar :(bool)titlebarAppearsTransparent :(bool)hideTitle :(bool)useToolbar :(bool)hideToolbarSeparator :(bool)webviewIsTransparent :(bool)hideWindowOnClose :(const char *)appearance :(bool)windowIsTranslucent {
self.urlRequests = [NSMutableDictionary new];
NSWindowStyleMask styleMask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable;
if (frameless) {
styleMask = NSWindowStyleMaskBorderless;
} else {
if (resizable) {
styleMask |= NSWindowStyleMaskResizable;
}
}
if (fullscreen) {
styleMask |= NSWindowStyleMaskFullScreen;
}
if( fullSizeContent || frameless || titlebarAppearsTransparent ) {
styleMask |= NSWindowStyleMaskFullSizeContentView;
}
self.mainWindow = [[[WailsWindow alloc] initWithContentRect:NSMakeRect(0, 0, width, height)
styleMask:styleMask backing:NSBackingStoreBuffered defer:NO]
autorelease];
if (frameless) {
return;
}
if (useToolbar) {
NSLog(@"Using Toolbar");
id toolbar = [[NSToolbar alloc] initWithIdentifier:@"wails.toolbar"];
[toolbar autorelease];
[toolbar setShowsBaselineSeparator:!hideToolbarSeparator];
[self.mainWindow setToolbar:toolbar];
}
[self.mainWindow setTitleVisibility:hideTitle];
[self.mainWindow setTitlebarAppearsTransparent:titlebarAppearsTransparent];
[self.mainWindow canBecomeKeyWindow];
id contentView = [self.mainWindow contentView];
if (windowIsTranslucent) {
NSVisualEffectView *effectView = [NSVisualEffectView alloc];
NSRect bounds = [contentView bounds];
[effectView initWithFrame:bounds];
[effectView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
[effectView setBlendingMode:NSVisualEffectBlendingModeBehindWindow];
[effectView setState:NSVisualEffectStateActive];
[contentView addSubview:effectView positioned:NSWindowBelow relativeTo:nil];
}
if (appearance != nil) {
NSString *name = [NSString stringWithUTF8String:appearance];
NSAppearance *nsAppearance = [NSAppearance appearanceNamed:name];
[self.mainWindow setAppearance:nsAppearance];
}
// Set up min/max
NSSize maxSize = { FLT_MAX, FLT_MAX };
self.maxSize = maxSize;
NSSize minSize = { 0, 0 };
self.minSize = minSize;
[self adjustWindowSize];
WindowDelegate *windowDelegate = [WindowDelegate new];
windowDelegate.hideOnClose = hideWindowOnClose;
[self.mainWindow setDelegate:windowDelegate];
// Webview stuff here!
WKWebViewConfiguration *config = [WKWebViewConfiguration new];
config.suppressesIncrementalRendering = true;
[config setURLSchemeHandler:self forURLScheme:@"wails"];
[config.preferences setValue:[NSNumber numberWithBool:true] forKey:@"developerExtrasEnabled"];
WKUserContentController* userContentController = [WKUserContentController new];
[userContentController addScriptMessageHandler:self name:@"external"];
config.userContentController = userContentController;
self.userContentController = userContentController;
if (self.debug) {
[config.preferences setValue:@YES forKey:@"developerExtrasEnabled"];
} else {
// Disable default context menus
WKUserScript *initScript = [WKUserScript new];
[initScript initWithSource:@"window.wails.flags.disableWailsDefaultContextMenu = true;"
injectionTime:WKUserScriptInjectionTimeAtDocumentEnd
forMainFrameOnly:false];
[userContentController addUserScript:initScript];
}
self.webview = [WKWebView alloc];
CGRect init = { 0,0,0,0 };
[self.webview initWithFrame:init configuration:config];
[contentView addSubview:self.webview];
[self.webview setAutoresizingMask: NSViewWidthSizable|NSViewHeightSizable];
CGRect contentViewBounds = [contentView bounds];
[self.webview setFrame:contentViewBounds];
if (webviewIsTransparent) {
[self.webview setValue:[NSNumber numberWithBool:!webviewIsTransparent] forKey:@"drawsBackground"];
}
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setBool:FALSE forKey:@"NSAutomaticQuoteSubstitutionEnabled"];
// Mouse monitors
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskLeftMouseDown handler:^NSEvent * _Nullable(NSEvent * _Nonnull event) {
id window = [event window];
if (window == self.mainWindow) {
self.mouseEvent = event;
}
return event;
}];
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskLeftMouseUp handler:^NSEvent * _Nullable(NSEvent * _Nonnull event) {
id window = [event window];
if (window == self.mainWindow) {
self.mouseEvent = nil;
[self ShowMouse];
}
return event;
}];
}
- (void) loadRequest :(NSString*)url {
NSURL *wkUrl = [NSURL URLWithString:url];
NSURLRequest *wkRequest = [NSURLRequest requestWithURL:wkUrl];
[self.webview loadRequest:wkRequest];
}
- (void) SetRGBA:(int)r :(int)g :(int)b :(int)a {
float red = r/255;
float green = g/255;
float blue = b/255;
float alpha = a/255;
id colour = [NSColor colorWithCalibratedRed:red green:green blue:blue alpha:alpha ];
[self.mainWindow setBackgroundColor:colour];
}
- (void) HideMouse {
[NSCursor hide];
}
- (void) ShowMouse {
[NSCursor unhide];
}
- (bool) isFullScreen {
long mask = [self.mainWindow styleMask];
return (mask & NSWindowStyleMaskFullScreen) == NSWindowStyleMaskFullScreen;
}
// Fullscreen sets the main window to be fullscreen
- (void) Fullscreen {
if( ! [self isFullScreen] ) {
[self.mainWindow toggleFullScreen:nil];
}
}
// UnFullscreen resets the main window after a fullscreen
- (void) UnFullscreen {
if( [self isFullScreen] ) {
[self.mainWindow toggleFullScreen:nil];
}
}
- (void) Minimise {
[self.mainWindow miniaturize:nil];
}
- (void) UnMinimise {
[self.mainWindow deminiaturize:nil];
}
- (void) Hide {
[self.mainWindow orderOut:nil];
}
- (void) Show {
[self.mainWindow makeKeyAndOrderFront:nil];
[NSApp activateIgnoringOtherApps:YES];
}
- (void) Maximise {
if (! self.maximised) {
[self.mainWindow zoom:nil];
}
}
- (void) UnMaximise {
if (self.maximised) {
[self.mainWindow zoom:nil];
}
}
- (void) ExecJS:(const char*)script {
NSString *nsscript = [NSString stringWithUTF8String:script];
[self.webview evaluateJavaScript:nsscript completionHandler:nil];
}
- (void) processURLResponse:(NSString *)url :(NSString *)contentType :(NSData *)data {
id<WKURLSchemeTask> urlSchemeTask = self.urlRequests[url];
NSURL *nsurl = [NSURL URLWithString:url];
NSHTTPURLResponse *response = [NSHTTPURLResponse new];
NSMutableDictionary *headerFields = [NSMutableDictionary new];
headerFields[@"content-type"] = contentType;
[response initWithURL:nsurl statusCode:200 HTTPVersion:@"HTTP/1.1" headerFields:headerFields];
[urlSchemeTask didReceiveResponse:response];
[urlSchemeTask didReceiveData:data];
[urlSchemeTask didFinish];
[self.urlRequests removeObjectForKey:url];
}
- (void)webView:(nonnull WKWebView *)webView startURLSchemeTask:(nonnull id<WKURLSchemeTask>)urlSchemeTask {
// Do something
self.urlRequests[urlSchemeTask.request.URL.absoluteString] = urlSchemeTask;
processURLRequest(self, [urlSchemeTask.request.URL.absoluteString UTF8String]);
}
- (void)webView:(nonnull WKWebView *)webView stopURLSchemeTask:(nonnull id<WKURLSchemeTask>)urlSchemeTask {
}
- (void)userContentController:(nonnull WKUserContentController *)userContentController didReceiveScriptMessage:(nonnull WKScriptMessage *)message {
NSString *m = message.body;
// Check for drag
if ( [m isEqualToString:@"drag"] ) {
if( ! [self isFullScreen] ) {
if( self.mouseEvent != nil ) {
[self HideMouse];
ON_MAIN_THREAD(
[self.mainWindow performWindowDragWithEvent:self.mouseEvent];
);
}
return;
}
}
const char *_m = [m UTF8String];
processMessage(_m);
}
/***** Dialogs ******/
-(void) MessageDialog :(const char*)dialogType :(const char*)title :(const char*)message :(const char*)button1 :(const char*)button2 :(const char*)button3 :(const char*)button4 :(const char*)defaultButton :(const char*)cancelButton {
WailsAlert *alert = [WailsAlert new];
int style = NSAlertStyleInformational;
if (dialogType != nil ) {
if( strcmp(dialogType, "warning") == 0 ) {
style = NSAlertStyleWarning;
}
if( strcmp(dialogType, "error") == 0) {
style = NSAlertStyleCritical;
}
}
[alert setAlertStyle:style];
if( strlen(title) > 0 ) {
[alert setMessageText:[NSString stringWithUTF8String:title]];
}
if( strlen(message) > 0 ) {
[alert setInformativeText:[NSString stringWithUTF8String:message]];
}
[alert addButton:button1 :defaultButton :cancelButton];
[alert addButton:button2 :defaultButton :cancelButton];
[alert addButton:button3 :defaultButton :cancelButton];
[alert addButton:button4 :defaultButton :cancelButton];
long response = [alert runModal];
int result;
if( response == NSAlertFirstButtonReturn ) {
result = 0;
}
else if( response == NSAlertSecondButtonReturn ) {
result = 1;
}
else if( response == NSAlertThirdButtonReturn ) {
result = 2;
} else {
result = 3;
}
processMessageDialogResponse(result);
}
-(void) OpenFileDialog :(const char*)title :(const char*)defaultFilename :(const char*)defaultDirectory :(bool)allowDirectories :(bool)allowFiles :(bool)canCreateDirectories :(bool)treatPackagesAsDirectories :(bool)resolveAliases :(bool)showHiddenFiles :(bool)allowMultipleSelection :(const char*)filters {
// Create the dialog
NSOpenPanel *dialog = [NSOpenPanel openPanel];
// Valid but appears to do nothing.... :/
if( strlen(title) > 0 ) {
[dialog setTitle:[NSString stringWithUTF8String:title]];
}
// Filters - semicolon delimited list of file extensions
if( allowFiles ) {
if( filters != nil && strlen(filters) > 0) {
NSString *filterString = [[NSString stringWithUTF8String:filters] stringByReplacingOccurrencesOfString:@"*." withString:@""];
filterString = [filterString stringByReplacingOccurrencesOfString:@" " withString:@""];
NSArray *filterList = [filterString componentsSeparatedByString:@";"];
[dialog setAllowedFileTypes:filterList];
} else {
[dialog setAllowsOtherFileTypes:true];
}
// Default Filename
if( defaultFilename != NULL && strlen(defaultFilename) > 0 ) {
[dialog setNameFieldStringValue:[NSString stringWithUTF8String:defaultFilename]];
}
[dialog setAllowsMultipleSelection: allowMultipleSelection];
[dialog setShowsHiddenFiles: showHiddenFiles];
}
// Default Directory
if( defaultDirectory != NULL && strlen(defaultDirectory) > 0 ) {
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithUTF8String:defaultDirectory]];
[dialog setDirectoryURL:url];
}
// Setup Options
[dialog setCanChooseFiles: allowFiles];
[dialog setCanChooseDirectories: allowDirectories];
[dialog setCanCreateDirectories: canCreateDirectories];
[dialog setResolvesAliases: resolveAliases];
[dialog setTreatsFilePackagesAsDirectories: treatPackagesAsDirectories];
// Setup callback handler
[dialog beginSheetModalForWindow:self.mainWindow completionHandler:^(NSModalResponse returnCode) {
NSMutableArray *arr = [NSMutableArray new];
for (NSURL *url in [dialog URLs]) {
[arr addObject:[url path]];
}
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:arr options:0 error:nil];
NSString *nsjson = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
processOpenFileDialogResponse([nsjson UTF8String]);
}];
[dialog runModal];
}
-(void) SaveFileDialog :(const char*)title :(const char*)defaultFilename :(const char*)defaultDirectory :(bool)canCreateDirectories :(bool)treatPackagesAsDirectories :(bool)showHiddenFiles :(const char*)filters; {
// Create the dialog
NSSavePanel *dialog = [NSOpenPanel savePanel];
// Valid but appears to do nothing.... :/
if( strlen(title) > 0 ) {
[dialog setTitle:[NSString stringWithUTF8String:title]];
}
// Filters - semicolon delimited list of file extensions
if( filters != nil && strlen(filters) > 0) {
NSString *filterString = [[NSString stringWithUTF8String:filters] stringByReplacingOccurrencesOfString:@"*." withString:@""];
filterString = [filterString stringByReplacingOccurrencesOfString:@" " withString:@""];
NSArray *filterList = [filterString componentsSeparatedByString:@";"];
[dialog setAllowedFileTypes:filterList];
} else {
[dialog setAllowsOtherFileTypes:true];
}
// Default Filename
if( defaultFilename != NULL && strlen(defaultFilename) > 0 ) {
[dialog setNameFieldStringValue:[NSString stringWithUTF8String:defaultFilename]];
}
// Default Directory
if( defaultDirectory != NULL && strlen(defaultDirectory) > 0 ) {
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithUTF8String:defaultDirectory]];
[dialog setDirectoryURL:url];
}
// Setup Options
[dialog setCanCreateDirectories: canCreateDirectories];
[dialog setTreatsFilePackagesAsDirectories: treatPackagesAsDirectories];
[dialog setShowsHiddenFiles: showHiddenFiles];
// Setup callback handler
[dialog beginSheetModalForWindow:self.mainWindow completionHandler:^(NSModalResponse returnCode) {
NSURL *url = [dialog URL];
processSaveFileDialogResponse([url.path UTF8String]);
}];
[dialog runModal];
}
@end

View File

@@ -0,0 +1,18 @@
//
// WindowDelegate.h
// test
//
// Created by Lea Anthony on 10/10/21.
//
#ifndef WindowDelegate_h
#define WindowDelegate_h
@interface WindowDelegate : NSObject <NSWindowDelegate>
@property bool hideOnClose;
@end
#endif /* WindowDelegate_h */

View File

@@ -0,0 +1,23 @@
//
// WindowDelegate.m
// test
//
// Created by Lea Anthony on 10/10/21.
//
#import <Foundation/Foundation.h>
#import <Cocoa/Cocoa.h>
#import "WindowDelegate.h"
#import "message.h"
@implementation WindowDelegate
- (BOOL)windowShouldClose:(NSWindow *)sender {
[sender orderOut:nil];
if( self.hideOnClose == false ) {
processMessage("Q");
}
return !self.hideOnClose;
}
@end

View File

@@ -1,4 +1,5 @@
//go:build darwin
// +build darwin
package darwin

View File

@@ -0,0 +1,32 @@
package darwin
/*
#include <stdlib.h>
*/
import "C"
import "unsafe"
// Calloc handles alloc/dealloc of C data
type Calloc struct {
pool []unsafe.Pointer
}
// NewCalloc creates a new allocator
func NewCalloc() Calloc {
return Calloc{}
}
// String creates a new C string and retains a reference to it
func (c Calloc) String(in string) *C.char {
result := C.CString(in)
c.pool = append(c.pool, unsafe.Pointer(result))
return result
}
// Free frees all allocated C memory
func (c Calloc) Free() {
for _, str := range c.pool {
C.free(str)
}
c.pool = []unsafe.Pointer{}
}

View File

@@ -1,32 +1,185 @@
//go:build darwin
// +build darwin
package darwin
/*
#cgo CFLAGS: -x objective-c
#cgo LDFLAGS: -framework Foundation -framework Cocoa -framework WebKit
#import <Foundation/Foundation.h>
#import "Application.h"
#import "WailsContext.h"
*/
import "C"
import (
"encoding/json"
"fmt"
"strings"
"sync"
"github.com/leaanthony/slicer"
"github.com/wailsapp/wails/v2/internal/frontend"
)
// Obj-C dialog methods send the response to this channel
var messageDialogResponse = make(chan int)
var openFileDialogResponse = make(chan string)
var saveFileDialogResponse = make(chan string)
var dialogLock sync.Mutex
// OpenDirectoryDialog prompts the user to select a directory
func (f *Frontend) OpenDirectoryDialog(options frontend.OpenDialogOptions) (string, error) {
return "", nil
results, err := f.openDialog(&options, false, false, true)
if err != nil {
return "", err
}
var selected string
if len(results) > 0 {
selected = results[0]
}
return selected, nil
}
func (f *Frontend) openDialog(options *frontend.OpenDialogOptions, multiple bool, allowfiles bool, allowdirectories bool) ([]string, error) {
dialogLock.Lock()
defer dialogLock.Unlock()
c := NewCalloc()
defer c.Free()
title := c.String(options.Title)
defaultFilename := c.String(options.DefaultFilename)
defaultDirectory := c.String(options.DefaultDirectory)
allowDirectories := bool2Cint(allowdirectories)
allowFiles := bool2Cint(allowfiles)
canCreateDirectories := bool2Cint(options.CanCreateDirectories)
treatPackagesAsDirectories := bool2Cint(options.TreatPackagesAsDirectories)
resolveAliases := bool2Cint(options.ResolvesAliases)
showHiddenFiles := bool2Cint(options.ShowHiddenFiles)
allowMultipleFileSelection := bool2Cint(multiple)
var filterStrings slicer.StringSlicer
if options.Filters != nil {
for _, filter := range options.Filters {
thesePatterns := strings.Split(filter.Pattern, ";")
for _, pattern := range thesePatterns {
pattern = strings.TrimSpace(pattern)
if pattern != "" {
filterStrings.Add(pattern)
}
}
}
filterStrings.Deduplicate()
}
filters := filterStrings.Join(";")
C.OpenFileDialog(f.mainWindow.context, title, defaultFilename, defaultDirectory, allowDirectories, allowFiles, canCreateDirectories, treatPackagesAsDirectories, resolveAliases, showHiddenFiles, allowMultipleFileSelection, c.String(filters))
var result = <-openFileDialogResponse
var parsedResults []string
err := json.Unmarshal([]byte(result), &parsedResults)
return parsedResults, err
}
// OpenFileDialog prompts the user to select a file
func (f *Frontend) OpenFileDialog(options frontend.OpenDialogOptions) (string, error) {
return "", nil
results, err := f.openDialog(&options, false, options.AllowFiles, options.AllowDirectories)
if err != nil {
return "", err
}
var selected string
if len(results) > 0 {
selected = results[0]
}
return selected, nil
}
// OpenMultipleFilesDialog prompts the user to select a file
func (f *Frontend) OpenMultipleFilesDialog(dialogOptions frontend.OpenDialogOptions) ([]string, error) {
return []string{}, nil
func (f *Frontend) OpenMultipleFilesDialog(options frontend.OpenDialogOptions) ([]string, error) {
return f.openDialog(&options, true, options.AllowFiles, options.AllowDirectories)
}
// SaveFileDialog prompts the user to select a file
func (f *Frontend) SaveFileDialog(dialogOptions frontend.SaveDialogOptions) (string, error) {
return "", nil
func (f *Frontend) SaveFileDialog(options frontend.SaveDialogOptions) (string, error) {
dialogLock.Lock()
defer dialogLock.Unlock()
c := NewCalloc()
defer c.Free()
title := c.String(options.Title)
defaultFilename := c.String(options.DefaultFilename)
defaultDirectory := c.String(options.DefaultDirectory)
canCreateDirectories := bool2Cint(options.CanCreateDirectories)
treatPackagesAsDirectories := bool2Cint(options.TreatPackagesAsDirectories)
showHiddenFiles := bool2Cint(options.ShowHiddenFiles)
var filterStrings slicer.StringSlicer
if options.Filters != nil {
for _, filter := range options.Filters {
thesePatterns := strings.Split(filter.Pattern, ";")
for _, pattern := range thesePatterns {
pattern = strings.TrimSpace(pattern)
if pattern != "" {
filterStrings.Add(pattern)
}
}
}
filterStrings.Deduplicate()
}
filters := filterStrings.Join(";")
C.SaveFileDialog(f.mainWindow.context, title, defaultFilename, defaultDirectory, canCreateDirectories, treatPackagesAsDirectories, showHiddenFiles, c.String(filters))
var result = <-saveFileDialogResponse
return result, nil
}
// MessageDialog show a message dialog to the user
func (f *Frontend) MessageDialog(options frontend.MessageDialogOptions) (string, error) {
return "", nil
dialogLock.Lock()
defer dialogLock.Unlock()
c := NewCalloc()
defer c.Free()
dialogType := c.String(string(options.Type))
title := c.String(options.Title)
message := c.String(options.Message)
defaultButton := c.String(options.DefaultButton)
cancelButton := c.String(options.CancelButton)
const MaxButtons = 4
var buttons [MaxButtons]*C.char
for index, buttonText := range options.Buttons {
if index == MaxButtons {
return "", fmt.Errorf("max %d buttons supported (%d given)", MaxButtons, len(options.Buttons))
}
buttons[index] = c.String(buttonText)
}
C.MessageDialog(f.mainWindow.context, dialogType, title, message, buttons[0], buttons[1], buttons[2], buttons[3], defaultButton, cancelButton)
var result = <-messageDialogResponse
selectedC := buttons[result]
var selected string
if selectedC != nil {
selected = options.Buttons[result]
}
return selected, nil
}
//export processMessageDialogResponse
func processMessageDialogResponse(selection int) {
messageDialogResponse <- selection
}
//export processOpenFileDialogResponse
func processOpenFileDialogResponse(cselection *C.char) {
selection := C.GoString(cselection)
openFileDialogResponse <- selection
}
//export processSaveFileDialogResponse
func processSaveFileDialogResponse(cselection *C.char) {
selection := C.GoString(cselection)
saveFileDialogResponse <- selection
}

View File

@@ -1,12 +1,26 @@
//go:build darwin
// +build darwin
package darwin
/*
#cgo CFLAGS: -x objective-c
#cgo LDFLAGS: -framework Foundation -framework Cocoa -framework WebKit
#import <Foundation/Foundation.h>
#import "Application.h"
#import "WailsContext.h"
#include <stdlib.h>
*/
import "C"
import (
"context"
"encoding/json"
"html/template"
"log"
"runtime"
"strconv"
"strings"
"unsafe"
"github.com/wailsapp/wails/v2/internal/binding"
"github.com/wailsapp/wails/v2/internal/frontend"
@@ -15,6 +29,14 @@ import (
"github.com/wailsapp/wails/v2/pkg/options"
)
type request struct {
url *C.char
ctx unsafe.Pointer
}
var messageBuffer = make(chan string, 100)
var requestBuffer = make(chan *request, 100)
type Frontend struct {
// Context
@@ -28,7 +50,7 @@ type Frontend struct {
assets *assetserver.DesktopAssetServer
// main window handle
//mainWindow *Window
mainWindow *Window
minWidth, minHeight, maxWidth, maxHeight int
bindings *binding.Bindings
dispatcher frontend.Dispatcher
@@ -68,9 +90,23 @@ func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger.
}
result.assets = assets
go result.startMessageProcessor()
go result.startRequestProcessor()
return result
}
func (f *Frontend) startMessageProcessor() {
for message := range messageBuffer {
f.processMessage(message)
}
}
func (f *Frontend) startRequestProcessor() {
for request := range requestBuffer {
f.processRequest(request)
}
}
func (f *Frontend) WindowReload() {
f.ExecJS("runtime.WindowReload();")
}
@@ -79,222 +115,101 @@ func (f *Frontend) Run(ctx context.Context) error {
f.ctx = context.WithValue(ctx, "frontend", f)
//mainWindow := NewWindow(nil, f.frontendOptions)
//f.mainWindow = mainWindow
//
//var _debug = ctx.Value("debug")
//if _debug != nil {
// f.debug = _debug.(bool)
//}
//
//f.WindowCenter()
//f.setupChromium()
//
//mainWindow.OnSize().Bind(func(arg *winc.Event) {
// f.chromium.Resize()
//})
//
//mainWindow.OnClose().Bind(func(arg *winc.Event) {
// if f.frontendOptions.HideWindowOnClose {
// f.WindowHide()
// } else {
// f.Quit()
// }
//})
//
//// TODO: Move this into a callback from frontend
//go func() {
// if f.frontendOptions.OnStartup != nil {
// f.frontendOptions.OnStartup(f.ctx)
// }
//}()
//
//mainWindow.Run()
var _debug = ctx.Value("debug")
if _debug != nil {
f.debug = _debug.(bool)
}
mainWindow := NewWindow(f.frontendOptions, f.debug)
f.mainWindow = mainWindow
f.mainWindow.Center()
go func() {
if f.frontendOptions.OnStartup != nil {
f.frontendOptions.OnStartup(f.ctx)
}
}()
mainWindow.Run()
return nil
}
func (f *Frontend) WindowCenter() {
runtime.LockOSThread()
//f.mainWindow.Center()
f.mainWindow.Center()
}
func (f *Frontend) WindowSetPos(x, y int) {
runtime.LockOSThread()
//f.mainWindow.SetPos(x, y)
f.mainWindow.SetPos(x, y)
}
func (f *Frontend) WindowGetPos() (int, int) {
runtime.LockOSThread()
//return f.mainWindow.Pos()
return 0, 0
return f.mainWindow.Pos()
}
func (f *Frontend) WindowSetSize(width, height int) {
runtime.LockOSThread()
//f.mainWindow.SetSize(width, height)
f.mainWindow.SetSize(width, height)
}
func (f *Frontend) WindowGetSize() (int, int) {
runtime.LockOSThread()
//return f.mainWindow.Size()
return 0, 0
return f.mainWindow.Size()
}
func (f *Frontend) WindowSetTitle(title string) {
runtime.LockOSThread()
//f.mainWindow.SetText(title)
f.mainWindow.SetTitle(title)
}
func (f *Frontend) WindowFullscreen() {
runtime.LockOSThread()
//f.mainWindow.SetMaxSize(0, 0)
//f.mainWindow.SetMinSize(0, 0)
//f.mainWindow.Fullscreen()
f.mainWindow.SetMaxSize(0, 0)
f.mainWindow.SetMinSize(0, 0)
f.mainWindow.Fullscreen()
}
func (f *Frontend) WindowUnFullscreen() {
runtime.LockOSThread()
//f.mainWindow.UnFullscreen()
//f.mainWindow.SetMaxSize(f.maxWidth, f.maxHeight)
//f.mainWindow.SetMinSize(f.minWidth, f.minHeight)
f.mainWindow.UnFullscreen()
f.mainWindow.SetMaxSize(f.maxWidth, f.maxHeight)
f.mainWindow.SetMinSize(f.minWidth, f.minHeight)
}
func (f *Frontend) WindowShow() {
runtime.LockOSThread()
//f.mainWindow.Show()
f.mainWindow.Show()
}
func (f *Frontend) WindowHide() {
runtime.LockOSThread()
//f.mainWindow.Hide()
f.mainWindow.Hide()
}
func (f *Frontend) WindowMaximise() {
runtime.LockOSThread()
//f.mainWindow.Maximise()
f.mainWindow.Maximise()
}
func (f *Frontend) WindowUnmaximise() {
runtime.LockOSThread()
//f.mainWindow.Restore()
f.mainWindow.UnMaximise()
}
func (f *Frontend) WindowMinimise() {
runtime.LockOSThread()
//f.mainWindow.Minimise()
f.mainWindow.Minimise()
}
func (f *Frontend) WindowUnminimise() {
runtime.LockOSThread()
//f.mainWindow.Restore()
f.mainWindow.UnMinimise()
}
func (f *Frontend) WindowSetMinSize(width int, height int) {
runtime.LockOSThread()
f.minWidth = width
f.minHeight = height
//f.mainWindow.SetMinSize(width, height)
f.mainWindow.SetMinSize(width, height)
}
func (f *Frontend) WindowSetMaxSize(width int, height int) {
runtime.LockOSThread()
f.maxWidth = width
f.maxHeight = height
//f.mainWindow.SetMaxSize(width, height)
f.mainWindow.SetMaxSize(width, height)
}
func (f *Frontend) WindowSetRGBA(col *options.RGBA) {
runtime.LockOSThread()
if col == nil {
return
}
/*
//f.mainWindow.Dispatch(func() {
controller := f.chromium.GetController()
controller2 := controller.GetICoreWebView2Controller2()
backgroundCol := edge.COREWEBVIEW2_COLOR{
A: col.A,
R: col.R,
G: col.G,
B: col.B,
}
// Webview2 only has 0 and 255 as valid values.
if backgroundCol.A > 0 && backgroundCol.A < 255 {
backgroundCol.A = 255
}
if f.frontendOptions.Windows != nil && f.frontendOptions.Windows.WebviewIsTransparent {
backgroundCol.A = 0
}
err := controller2.PutDefaultBackgroundColor(backgroundCol)
if err != nil {
log.Fatal(err)
}
})
*/
f.mainWindow.SetRGBA(col.R, col.G, col.B, col.A)
}
func (f *Frontend) Quit() {
//winc.Exit()
f.mainWindow.Quit()
}
/*
const (
ctrlZ int = 90
ctrlX = 88
ctrlC = 67
ctrlV = 86
)
func (f *Frontend) setupChromium() {
chromium := edge.NewChromium()
f.chromium = chromium
chromium.MessageCallback = f.processMessage
chromium.WebResourceRequestedCallback = f.processRequest
chromium.NavigationCompletedCallback = f.navigationCompleted
acceleratorsWebviewShouldProcess := slicer.Int([]int{ctrlV, ctrlC, ctrlX, ctrlZ})
chromium.AcceleratorKeyCallback = func(vkey uint) bool {
// We want webview to handle ctrl-C, ctrl-Z, ctrl-v, ctrl-x
if acceleratorsWebviewShouldProcess.Contains(int(vkey)) {
return false
}
// Post keypress
//w32.PostMessage(f.mainWindow.Handle(), w32.WM_KEYDOWN, uintptr(vkey), 0)
return true
}
chromium.Embed(f.mainWindow.Handle())
chromium.Resize()
settings, err := chromium.GetSettings()
if err != nil {
log.Fatal(err)
}
err = settings.PutAreDefaultContextMenusEnabled(f.debug)
if err != nil {
log.Fatal(err)
}
err = settings.PutAreDevToolsEnabled(f.debug)
if err != nil {
log.Fatal(err)
}
err = settings.PutIsZoomControlEnabled(false)
if err != nil {
log.Fatal(err)
}
err = settings.PutIsStatusBarEnabled(false)
if err != nil {
log.Fatal(err)
}
err = settings.PutIsStatusBarEnabled(false)
if err != nil {
log.Fatal(err)
}
// Set background colour
f.WindowSetRGBA(f.frontendOptions.RGBA)
chromium.AddWebResourceRequestedFilter("*", edge.COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL)
chromium.Navigate("file://wails/")
}
*/
type EventNotify struct {
Name string `json:"name"`
Data []interface{} `json:"data"`
@@ -310,42 +225,9 @@ func (f *Frontend) Notify(name string, data ...interface{}) {
f.logger.Error(err.Error())
return
}
f.ExecJS(`window.wails.EventsNotify('` + string(payload) + `');`)
f.ExecJS(`window.wails.EventsNotify('` + template.JSEscapeString(string(payload)) + `');`)
}
//func (f *Frontend) processRequest(req *edge.ICoreWebView2WebResourceRequest, args *edge.ICoreWebView2WebResourceRequestedEventArgs) {
// //Get the request
// uri, _ := req.GetUri()
//
// // Translate URI
// uri = strings.TrimPrefix(uri, "file://wails")
// if !strings.HasPrefix(uri, "/") {
// return
// }
//
// // Load file from asset store
// content, mimeType, err := f.assets.Load(uri)
// if err != nil {
// return
// }
//
// env := f.chromium.Environment()
// headers := "Content-Type: " + mimeType
// if f.servingFromDisk {
// headers += "\nPragma: no-cache"
// }
// response, err := env.CreateWebResourceResponse(content, 200, "OK", headers)
// if err != nil {
// return
// }
// // Send response back
// err = args.PutResponse(response)
// if err != nil {
// return
// }
// return
//}
func (f *Frontend) processMessage(message string) {
if message == "drag" {
err := f.startDrag()
@@ -374,9 +256,7 @@ func (f *Frontend) processMessage(message string) {
}
func (f *Frontend) Callback(message string) {
//f.mainWindow.Dispatch(func() {
// f.chromium.Eval(`window.wails.Callback(` + strconv.Quote(message) + `);`)
//})
f.ExecJS(`window.wails.Callback(` + strconv.Quote(message) + `);`)
}
func (f *Frontend) startDrag() error {
@@ -388,30 +268,39 @@ func (f *Frontend) startDrag() error {
}
func (f *Frontend) ExecJS(js string) {
//f.mainWindow.Dispatch(func() {
// f.chromium.Eval(js)
//})
f.mainWindow.ExecJS(js)
}
//func (f *Frontend) navigationCompleted(sender *edge.ICoreWebView2, args *edge.ICoreWebView2NavigationCompletedEventArgs) {
// if f.frontendOptions.OnDomReady != nil {
// go f.frontendOptions.OnDomReady(f.ctx)
// }
//
// // If you want to start hidden, return
// if f.frontendOptions.StartHidden {
// return
// }
//
// // Hack to make it visible: https://github.com/MicrosoftEdge/WebView2Feedback/issues/1077#issuecomment-825375026
// err := f.chromium.Hide()
// if err != nil {
// log.Fatal(err)
// }
// err = f.chromium.Show()
// if err != nil {
// log.Fatal(err)
// }
// f.mainWindow.Show()
//
//}
func (f *Frontend) processRequest(r *request) {
url := C.GoString(r.url)
url = strings.TrimPrefix(url, "wails://wails")
if !strings.HasPrefix(url, "/") {
return
}
_contents, _mimetype, err := f.assets.Load(url)
if err != nil {
f.logger.Error(err.Error())
//TODO: Handle errors
return
}
data := C.CString(string(_contents))
defer C.free(unsafe.Pointer(data))
mimetype := C.CString(_mimetype)
defer C.free(unsafe.Pointer(mimetype))
C.ProcessURLResponse(r.ctx, r.url, mimetype, data, C.int(len(_contents)))
}
//export processMessage
func processMessage(message *C.char) {
goMessage := C.GoString(message)
messageBuffer <- goMessage
}
//export processURLRequest
func processURLRequest(ctx unsafe.Pointer, url *C.char) {
requestBuffer <- &request{
url: url,
ctx: ctx,
}
}

View File

@@ -0,0 +1,56 @@
//go:build ignore
// main.m
// test
//
// Created by Lea Anthony on 10/10/21.
//
// ****** This file is used for testing purposes only ******
#import <Foundation/Foundation.h>
#import "Application.h"
void processMessage(const char*t) {
NSLog(@"processMessage called");
}
void processMessageDialogResponse(int t) {
NSLog(@"processMessage called");
}
void processOpenFileDialogResponse(const char *t) {
NSLog(@"processMessage called %s", t);
}
void processURLRequest(void *ctx, const char* url) {
NSLog(@"processURLRequest called");
const char myByteArray[] = { 0x3c,0x68,0x31,0x3e,0x48,0x65,0x6c,0x6c,0x6f,0x20,0x57,0x6f,0x72,0x6c,0x64,0x21,0x3c,0x2f,0x68,0x31,0x3e };
ProcessURLResponse(ctx, url, "text/html", myByteArray, 21);
}
int main(int argc, const char * argv[]) {
// insert code here...
int frameless = 0;
int resizable = 1;
int fullscreen = 0;
int fullSizeContent = 1;
int hideTitleBar = 0;
int titlebarAppearsTransparent = 1;
int hideTitle = 0;
int useToolbar = 1;
int hideToolbarSeparator = 1;
int webviewIsTransparent = 0;
int alwaysOnTop = 1;
int hideWindowOnClose = 0;
const char* appearance = "NSAppearanceNameDarkAqua";
int windowIsTranslucent = 1;
int debug = 1;
WailsContext *result = Create("OI OI!",400,400, frameless, resizable, fullscreen, fullSizeContent, hideTitleBar, titlebarAppearsTransparent, hideTitle, useToolbar, hideToolbarSeparator, webviewIsTransparent, alwaysOnTop, hideWindowOnClose, appearance, windowIsTranslucent, debug);
SetRGBA(result, 255, 0, 0, 255);
Run((void*)CFBridgingRetain(result));
return 0;
}

View File

@@ -1,4 +1,5 @@
//go:build darwin
// +build darwin
package darwin

View File

@@ -0,0 +1,28 @@
//
// message.h
// test
//
// Created by Lea Anthony on 14/10/21.
//
#ifndef export_h
#define export_h
#ifdef __cplusplus
extern "C"
{
#endif
void processMessage(const char *);
void processURLRequest(void*, const char *);
void processMessageDialogResponse(int);
void processOpenFileDialogResponse(const char*);
void processSaveFileDialogResponse(const char*);
#ifdef __cplusplus
}
#endif
#endif /* export_h */

View File

@@ -0,0 +1,187 @@
package darwin
/*
#cgo CFLAGS: -x objective-c
#cgo LDFLAGS: -framework Foundation -framework Cocoa -framework WebKit
#import <Foundation/Foundation.h>
#import "Application.h"
#import "WailsContext.h"
#include <stdlib.h>
*/
import "C"
import (
"log"
"runtime"
"strconv"
"strings"
"unsafe"
"github.com/wailsapp/wails/v2/pkg/options"
)
func init() {
runtime.LockOSThread()
}
type Window struct {
context unsafe.Pointer
}
func bool2Cint(value bool) C.int {
if value {
return C.int(1)
}
return C.int(0)
}
func NewWindow(frontendOptions *options.App, debugMode bool) *Window {
c := NewCalloc()
defer c.Free()
frameless := bool2Cint(frontendOptions.Frameless)
resizable := bool2Cint(!frontendOptions.DisableResize)
fullscreen := bool2Cint(frontendOptions.Fullscreen)
alwaysOnTop := bool2Cint(frontendOptions.AlwaysOnTop)
hideWindowOnClose := bool2Cint(frontendOptions.HideWindowOnClose)
debug := bool2Cint(debugMode)
alpha := C.int(frontendOptions.RGBA.A)
red := C.int(frontendOptions.RGBA.R)
green := C.int(frontendOptions.RGBA.G)
blue := C.int(frontendOptions.RGBA.B)
var fullSizeContent, hideTitleBar, hideTitle, useToolbar, webviewIsTransparent C.int
var titlebarAppearsTransparent, hideToolbarSeparator, windowIsTranslucent C.int
var appearance, title *C.char
width := C.int(frontendOptions.Width)
height := C.int(frontendOptions.Height)
title = c.String(frontendOptions.Title)
if frontendOptions.Mac != nil {
mac := frontendOptions.Mac
if mac.TitleBar != nil {
fullSizeContent = bool2Cint(mac.TitleBar.FullSizeContent)
hideTitleBar = bool2Cint(mac.TitleBar.HideTitleBar)
hideTitle = bool2Cint(mac.TitleBar.HideTitle)
useToolbar = bool2Cint(mac.TitleBar.UseToolbar)
titlebarAppearsTransparent = bool2Cint(mac.TitleBar.TitlebarAppearsTransparent)
hideToolbarSeparator = bool2Cint(mac.TitleBar.HideToolbarSeparator)
}
windowIsTranslucent = bool2Cint(mac.WindowIsTranslucent)
webviewIsTransparent = bool2Cint(mac.WebviewIsTransparent)
appearance = c.String(string(mac.Appearance))
}
var context *C.WailsContext = C.Create(title, width, height, frameless, resizable, fullscreen, fullSizeContent, hideTitleBar, titlebarAppearsTransparent, hideTitle, useToolbar, hideToolbarSeparator, webviewIsTransparent, alwaysOnTop, hideWindowOnClose, appearance, windowIsTranslucent, debug)
C.SetRGBA(unsafe.Pointer(context), red, green, blue, alpha)
return &Window{
context: unsafe.Pointer(context),
}
}
func (w *Window) Center() {
C.Center(w.context)
}
func (w *Window) Run() {
C.Run(w.context)
println("I exited!")
}
func (w *Window) Quit() {
C.Quit(w.context)
}
func (w *Window) SetRGBA(r uint8, g uint8, b uint8, a uint8) {
C.SetRGBA(w.context, C.int(r), C.int(g), C.int(b), C.int(a))
}
func (w *Window) ExecJS(js string) {
_js := C.CString(js)
C.ExecJS(w.context, _js)
C.free(unsafe.Pointer(_js))
}
func (w *Window) SetPos(x int, y int) {
C.SetPosition(w.context, C.int(x), C.int(y))
}
func (w *Window) SetSize(width int, height int) {
C.SetSize(w.context, C.int(width), C.int(height))
}
func (w *Window) SetTitle(title string) {
t := C.CString(title)
C.SetTitle(w.context, t)
C.free(unsafe.Pointer(t))
}
func (w *Window) Maximise() {
C.Maximise(w.context)
}
func (w *Window) UnMaximise() {
C.UnMaximise(w.context)
}
func (w *Window) Minimise() {
C.Minimise(w.context)
}
func (w *Window) UnMinimise() {
C.UnMinimise(w.context)
}
func (w *Window) SetMinSize(width int, height int) {
C.SetMinSize(w.context, C.int(width), C.int(height))
}
func (w *Window) SetMaxSize(width int, height int) {
C.SetMaxSize(w.context, C.int(width), C.int(height))
}
func (w *Window) Fullscreen() {
C.Fullscreen(w.context)
}
func (w *Window) UnFullscreen() {
C.UnFullscreen(w.context)
}
func (w *Window) Show() {
C.Show(w.context)
}
func (w *Window) Hide() {
C.Hide(w.context)
}
func parseIntDuo(temp string) (int, int) {
split := strings.Split(temp, ",")
x, err := strconv.Atoi(split[0])
if err != nil {
log.Fatal(err)
}
y, err := strconv.Atoi(split[1])
if err != nil {
log.Fatal(err)
}
return x, y
}
func (w *Window) Pos() (int, int) {
var _result *C.char = C.GetPos(w.context)
temp := C.GoString(_result)
return parseIntDuo(temp)
}
func (w *Window) Size() (int, int) {
var _result *C.char = C.GetSize(w.context)
temp := C.GoString(_result)
return parseIntDuo(temp)
}

View File

@@ -1,3 +1,6 @@
//go:build windows
// +build windows
package windows
import (

View File

@@ -11,8 +11,7 @@ import (
"runtime"
"strconv"
"strings"
"github.com/leaanthony/slicer"
"text/template"
"github.com/leaanthony/go-webview2/pkg/edge"
"github.com/leaanthony/winc"
@@ -35,7 +34,8 @@ type Frontend struct {
debug bool
// Assets
assets *assetserver.DesktopAssetServer
assets *assetserver.DesktopAssetServer
startURL string
// main window handle
mainWindow *Window
@@ -57,21 +57,33 @@ func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger.
minWidth: appoptions.MinWidth,
maxHeight: appoptions.MaxHeight,
maxWidth: appoptions.MaxWidth,
}
// Check if we have been given a directory to serve assets from.
// If so, this means we are in dev mode and are serving assets off disk.
// We indicate this through the `servingFromDisk` flag to ensure requests
// aren't cached by WebView2 in dev mode
_assetdir := ctx.Value("assetdir")
if _assetdir != nil {
result.servingFromDisk = true
startURL: "file://wails/",
}
bindingsJSON, err := appBindings.ToJSON()
if err != nil {
log.Fatal(err)
}
_devServerURL := ctx.Value("devserverurl")
if _devServerURL != nil {
devServerURL := _devServerURL.(string)
if len(devServerURL) > 0 && devServerURL != "http://localhost:34115" {
result.startURL = devServerURL
return result
}
}
// Check if we have been given a directory to serve assets from.
// If so, this means we are in dev mode and are serving assets off disk.
// We indicate this through the `servingFromDisk` flag to ensure requests
// aren't cached by WebView2 in dev mode
_assetdir := ctx.Value("assetdir")
if _assetdir != nil {
result.servingFromDisk = true
}
assets, err := assetserver.NewDesktopAssetServer(ctx, appoptions.Assets, bindingsJSON)
if err != nil {
log.Fatal(err)
@@ -123,6 +135,7 @@ func (f *Frontend) Run(ctx context.Context) error {
}
mainWindow.Run()
mainWindow.Close()
return nil
}
@@ -245,35 +258,15 @@ func (f *Frontend) Quit() {
winc.Exit()
}
const (
ctrlZ int = 90
ctrlX = 88
ctrlC = 67
ctrlV = 86
ctrlA = 65
arrowUp = 38
arrowDown = 40
arrowRight = 39
arrowLeft = 37
keyDel = 46
)
func (f *Frontend) setupChromium() {
chromium := edge.NewChromium()
f.chromium = chromium
chromium.MessageCallback = f.processMessage
chromium.WebResourceRequestedCallback = f.processRequest
chromium.NavigationCompletedCallback = f.navigationCompleted
acceleratorsWebviewShouldProcess := slicer.Int([]int{ctrlV, ctrlC, ctrlX, ctrlZ, ctrlA, arrowLeft, arrowRight, arrowUp, arrowDown, keyDel})
chromium.AcceleratorKeyCallback = func(vkey uint) bool {
// We want webview to handle ctrl-C, ctrl-Z, ctrl-v, ctrl-x
if acceleratorsWebviewShouldProcess.Contains(int(vkey)) {
return false
}
// Post keypress
w32.PostMessage(f.mainWindow.Handle(), w32.WM_KEYDOWN, uintptr(vkey), 0)
return true
return false
}
chromium.Embed(f.mainWindow.Handle())
chromium.Resize()
@@ -297,7 +290,11 @@ func (f *Frontend) setupChromium() {
if err != nil {
log.Fatal(err)
}
err = settings.PutIsStatusBarEnabled(false)
err = settings.PutAreBrowserAcceleratorKeysEnabled(false)
if err != nil {
log.Fatal(err)
}
err = settings.PutIsSwipeNavigationEnabled(false)
if err != nil {
log.Fatal(err)
}
@@ -305,8 +302,9 @@ func (f *Frontend) setupChromium() {
// Set background colour
f.WindowSetRGBA(f.frontendOptions.RGBA)
chromium.SetGlobalPermission(edge.CoreWebView2PermissionStateAllow)
chromium.AddWebResourceRequestedFilter("*", edge.COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL)
chromium.Navigate("file://wails/")
chromium.Navigate(f.startURL)
}
type EventNotify struct {
@@ -324,7 +322,7 @@ func (f *Frontend) Notify(name string, data ...interface{}) {
f.logger.Error(err.Error())
return
}
f.ExecJS(`window.wails.EventsNotify('` + string(payload) + `');`)
f.ExecJS(`window.wails.EventsNotify('` + template.JSEscapeString(string(payload)) + `');`)
}
func (f *Frontend) processRequest(req *edge.ICoreWebView2WebResourceRequest, args *edge.ICoreWebView2WebResourceRequestedEventArgs) {

View File

@@ -30,6 +30,9 @@ func NewWindow(parent winc.Controller, options *options.App) *Window {
exStyle |= w32.WS_EX_NOREDIRECTIONBITMAP
}
}
if options.AlwaysOnTop {
exStyle |= w32.WS_EX_TOPMOST
}
var dwStyle = w32.WS_OVERLAPPEDWINDOW
if options.Frameless {

View File

@@ -33,9 +33,9 @@ type DevWebServer struct {
logger *logger.Logger
appBindings *binding.Bindings
dispatcher frontend.Dispatcher
assetServer *assetserver.AssetServer
assetServer *assetserver.BrowserAssetServer
socketMutex sync.Mutex
websocketClients map[*websocket.Conn]struct{}
websocketClients map[*websocket.Conn]*sync.Mutex
menuManager *menumanager.Manager
starttime string
@@ -58,6 +58,7 @@ func (d *DevWebServer) Run(ctx context.Context) error {
d.server.Get("/wails/ipc", websocket.New(func(c *websocket.Conn) {
d.newWebsocketSession(c)
locker := d.websocketClients[c]
// websocket.Conn bindings https://pkg.go.dev/github.com/fasthttp/websocket?tab=doc#pkg-index
var (
mt int
@@ -85,55 +86,65 @@ func (d *DevWebServer) Run(ctx context.Context) error {
d.logger.Error(err.Error())
}
if result != "" {
locker.Lock()
if err = c.WriteMessage(mt, []byte(result)); err != nil {
locker.Unlock()
break
}
locker.Unlock()
}
}
}))
_assetdir := ctx.Value("assetdir")
if _assetdir == nil {
return fmt.Errorf("no assetdir provided")
_devServerURL := ctx.Value("devserverurl")
if _devServerURL == "http://localhost:34115" {
// Setup internal dev server
_assetdir := ctx.Value("assetdir")
if _assetdir == nil {
return fmt.Errorf("no assetdir provided")
}
if _assetdir != nil {
assetdir := _assetdir.(string)
bindingsJSON, err := d.appBindings.ToJSON()
if err != nil {
log.Fatal(err)
}
d.assetServer, err = assetserver.NewBrowserAssetServer(assetdir, bindingsJSON, d.appoptions)
if err != nil {
log.Fatal(err)
}
absdir, err := filepath.Abs(assetdir)
if err != nil {
return err
}
d.LogDebug("Serving assets from: %s", absdir)
}
d.server.Get("*", d.loadAsset)
// Start server
go func(server *fiber.App, log *logger.Logger) {
err := server.Listen("localhost:34115")
if err != nil {
log.Error(err.Error())
}
d.LogDebug("Shutdown completed")
}(d.server, d.logger)
d.LogDebug("Serving application at http://localhost:34115")
defer func() {
err := d.server.Shutdown()
if err != nil {
d.logger.Error(err.Error())
}
}()
}
if _assetdir != nil {
assetdir := _assetdir.(string)
bindingsJSON, err := d.appBindings.ToJSON()
if err != nil {
log.Fatal(err)
}
d.assetServer, err = assetserver.NewAssetServer(assetdir, bindingsJSON, d.appoptions)
if err != nil {
log.Fatal(err)
}
absdir, err := filepath.Abs(assetdir)
if err != nil {
return err
}
d.LogDebug("Serving assets from: %s", absdir)
}
d.server.Get("*", d.loadAsset)
// Start server
go func(server *fiber.App, log *logger.Logger) {
err := server.Listen(":34115")
if err != nil {
log.Error(err.Error())
}
d.LogDebug("Shutdown completed")
}(d.server, d.logger)
d.LogDebug("Serving application at http://localhost:34115")
// Launch desktop app
err := d.desktopFrontend.Run(ctx)
d.LogDebug("Starting shutdown")
err2 := d.server.Shutdown()
if err2 != nil {
d.logger.Error(err.Error())
}
return err
}
@@ -286,7 +297,7 @@ func (d *DevWebServer) newWebsocketSession(c *websocket.Conn) {
d.LogDebug(fmt.Sprintf("Websocket client %p disconnected", c))
return nil
})
d.websocketClients[c] = struct{}{}
d.websocketClients[c] = &sync.Mutex{}
d.LogDebug(fmt.Sprintf("Websocket client %p connected", c))
}
@@ -298,12 +309,21 @@ type EventNotify struct {
func (d *DevWebServer) broadcast(message string) {
d.socketMutex.Lock()
defer d.socketMutex.Unlock()
for client := range d.websocketClients {
err := client.WriteMessage(websocket.TextMessage, []byte(message))
if err != nil {
d.logger.Error(err.Error())
return
}
for client, locker := range d.websocketClients {
go func() {
if client == nil {
d.logger.Error("Lost connection to websocket server")
return
}
locker.Lock()
err := client.WriteMessage(websocket.TextMessage, []byte(message))
if err != nil {
locker.Unlock()
d.logger.Error(err.Error())
return
}
locker.Unlock()
}()
}
}
@@ -324,15 +344,20 @@ func (d *DevWebServer) notify(name string, data ...interface{}) {
func (d *DevWebServer) broadcastExcludingSender(message string, sender *websocket.Conn) {
d.socketMutex.Lock()
defer d.socketMutex.Unlock()
for client := range d.websocketClients {
if client == sender {
continue
}
err := client.WriteMessage(websocket.TextMessage, []byte(message))
if err != nil {
d.logger.Error(err.Error())
return
}
for client, locker := range d.websocketClients {
go func() {
if client == sender {
return
}
locker.Lock()
err := client.WriteMessage(websocket.TextMessage, []byte(message))
if err != nil {
locker.Unlock()
d.logger.Error(err.Error())
return
}
locker.Unlock()
}()
}
}
@@ -358,11 +383,12 @@ func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger.
appBindings: appBindings,
dispatcher: dispatcher,
server: fiber.New(fiber.Config{
ReadTimeout: time.Second * 5,
DisableStartupMessage: true,
}),
menuManager: menuManager,
websocketClients: make(map[*websocket.Conn]struct{}),
websocketClients: make(map[*websocket.Conn]*sync.Mutex),
}
return result
}

View File

@@ -2,8 +2,9 @@ package dispatcher
import (
"fmt"
"github.com/wailsapp/wails/v2/internal/frontend"
"strings"
"github.com/wailsapp/wails/v2/internal/frontend"
)
const systemCallPrefix = ":wails:"
@@ -29,7 +30,7 @@ func (d *Dispatcher) processSystemCall(payload callMessage, sender frontend.Fron
return &position{x, y}, nil
case "WindowGetSize":
w, h := sender.WindowGetSize()
return &position{w, h}, nil
return &size{w, h}, nil
default:
return nil, fmt.Errorf("unknown systemcall message: %s", payload.Name)
}

View File

@@ -10,25 +10,30 @@ The electron alternative for Go
/* jshint esversion: 6 */
/**
* SendMessage sends the given message to the backend
* WailsInvoke sends the given message to the backend
*
* @param {string} message
*/
// const windows = 0;
// const macos = 1;
// const linux = 2;
(function () {
// Credit: https://stackoverflow.com/a/2631521
let _deeptest = function (s) {
var obj = window[s.shift()];
while (obj && s.length) obj = obj[s.shift()];
return obj;
};
let windows = _deeptest(["chrome", "webview", "postMessage"]);
let mac = _deeptest(["webkit", "messageHandlers", "external", "postMessage"]);
window.WailsInvoke = function (message) {
// Call Platform specific invoke method
if (PLATFORM === 0) {
window.chrome.webview.postMessage(message);
} else if (PLATFORM === 1) {
window.webkit.messageHandlers.external.postMessage(message);
} else if (PLATFORM === 2) {
console.error("Unsupported Platform");
} else {
if (!windows && !mac) {
console.error("Unsupported Platform");
return;
}
};
if (windows) {
window.WailsInvoke = (message) => window.chrome.webview.postMessage(message);
}
if (mac) {
window.WailsInvoke = (message) => window.webkit.messageHandlers.external.postMessage(message);
}
})();

View File

@@ -39,7 +39,11 @@ window.wails = {
EventsNotify,
SetBindings,
eventListeners,
callbacks
callbacks,
flags: {
disableScrollbarDrag: false,
disableWailsDefaultContextMenu: false,
}
};
// Set the bindings
@@ -61,9 +65,23 @@ window.addEventListener('mousedown', (e) => {
if (currentElement.hasAttribute('data-wails-no-drag')) {
break;
} else if (currentElement.hasAttribute('data-wails-drag')) {
if (window.wails.flags.disableScrollbarDrag) {
// This checks for clicks on the scroll bar
if (e.offsetX > e.target.clientWidth || e.offsetY > e.target.clientHeight) {
break;
}
}
window.WailsInvoke("drag");
e.preventDefault();
break;
}
currentElement = currentElement.parentElement;
}
});
// Setup context menu hook
window.addEventListener('contextmenu', function (e) {
if (window.wails.flags.disableWailsDefaultContextMenu) {
e.preventDefault();
}
});

View File

@@ -1,50 +1,15 @@
/* jshint esversion: 8 */
const esbuild = require("esbuild");
const sveltePlugin = require("esbuild-svelte");
let sveltePlugin = {
name: 'svelte',
setup(build) {
let svelte = require('svelte/compiler');
let path = require('path');
let fs = require('fs');
build.onLoad({filter: /\.svelte$/}, async (args) => {
// This converts a message in Svelte's format to esbuild's format
let convertMessage = ({message, start, end}) => {
let location;
if (start && end) {
let lineText = source.split(/\r\n|\r|\n/g)[start.line - 1];
let lineEnd = start.line === end.line ? end.column : lineText.length;
location = {
file: filename,
line: start.line,
column: start.column,
length: lineEnd - start.column,
lineText,
};
}
return {text: message, location};
};
// Load the file from the file system
let source = await fs.promises.readFile(args.path, 'utf8');
let filename = path.relative(process.cwd(), args.path);
// Convert Svelte syntax to JavaScript
try {
let {js, warnings} = svelte.compile(source, {filename});
let contents = js.code + `//# sourceMappingURL=` + js.map.toUrl();
return {contents, warnings: warnings.map(convertMessage)};
} catch (e) {
return {errors: [convertMessage(e)]};
}
});
}
};
require('esbuild').build({
minify: true,
entryPoints: ['main.js'],
bundle: true,
outfile: '../ipc_websocket.js',
plugins: [sveltePlugin],
}).catch(() => process.exit(1));
esbuild
.build({
entryPoints: ["main.js"],
bundle: true,
minify: true,
outfile: "../ipc_websocket.js",
plugins: [sveltePlugin({compileOptions: {css: true}})],
logLevel: "info",
sourcemap: "inline",
})
.catch(() => process.exit(1));

View File

@@ -14,11 +14,21 @@ import Overlay from "./Overlay.svelte";
import {hideOverlay, showOverlay} from "./store";
let components = {};
window.ipcCallbacks = [];
window.ipcCallbackNames = [];
// Sets up the overlay
components.overlay = new Overlay({
target: document.body,
anchor: document.querySelector('#wails-spinner'),
window.awaitIPC = (name, callback) => {
if (!window.ipcCallbacks) return callback;
log("Queuing '" + name + "' for execution once ipc ready.");
window.ipcCallbackNames.push(name);
window.ipcCallbacks.push(callback);
};
window.addEventListener('DOMContentLoaded', () => {
components.overlay = new Overlay({
target: document.body,
anchor: document.querySelector('#wails-spinner'),
});
});
let websocket = null;
@@ -40,6 +50,12 @@ function setupIPCBridge() {
window.WailsInvoke = (message) => {
websocket.send(message);
};
for (let i = 0; i < window.ipcCallbacks.length; i++) {
log("Executing JS: " + window.ipcCallbackNames[i]);
window.ipcCallbacks[i]();
}
delete window.ipcCallbacks;
delete window.ipcCallbackNames;
}
// Handles incoming websocket connections
@@ -60,21 +76,24 @@ function handleDisconnect() {
connect();
}
// Try to connect to the backend every 1s (default value).
function _connect() {
if (websocket == null) {
websocket = new WebSocket('ws://' + window.location.hostname + ':34115/wails/ipc');
websocket.onopen = handleConnect;
websocket.onerror = function (e) {
e.stopImmediatePropagation();
e.stopPropagation();
e.preventDefault();
websocket = null;
return false;
};
}
}
// Try to connect to the backend every .5s
function connect() {
connectTimer = setInterval(function () {
if (websocket == null) {
websocket = new WebSocket('ws://' + window.location.hostname + ':34115/wails/ipc');
websocket.onopen = handleConnect;
websocket.onerror = function (e) {
e.stopImmediatePropagation();
e.stopPropagation();
e.preventDefault();
websocket = null;
return false;
};
}
}, 250);
_connect();
connectTimer = setInterval(_connect, 500);
}
function handleMessage(message) {

View File

@@ -1,871 +1,8 @@
{
"name": "dev",
"version": "2.0.0",
"lockfileVersion": 2,
"lockfileVersion": 1,
"requires": true,
"packages": {
"": {
"version": "2.0.0",
"license": "ISC",
"devDependencies": {
"esbuild": "^0.12.17",
"npm-run-all": "^4.1.5",
"svelte": "^3.42.2"
}
},
"node_modules/ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
"dependencies": {
"color-convert": "^1.9.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true
},
"node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/call-bind": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
"integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
"dev": true,
"dependencies": {
"function-bind": "^1.1.1",
"get-intrinsic": "^1.0.2"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"dependencies": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"dev": true,
"dependencies": {
"color-name": "1.1.3"
}
},
"node_modules/color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
"dev": true
},
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"dev": true
},
"node_modules/cross-spawn": {
"version": "6.0.5",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
"integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
"dev": true,
"dependencies": {
"nice-try": "^1.0.4",
"path-key": "^2.0.1",
"semver": "^5.5.0",
"shebang-command": "^1.2.0",
"which": "^1.2.9"
},
"engines": {
"node": ">=4.8"
}
},
"node_modules/define-properties": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
"integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
"dev": true,
"dependencies": {
"object-keys": "^1.0.12"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/error-ex": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
"integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
"dev": true,
"dependencies": {
"is-arrayish": "^0.2.1"
}
},
"node_modules/es-abstract": {
"version": "1.18.5",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.5.tgz",
"integrity": "sha512-DDggyJLoS91CkJjgauM5c0yZMjiD1uK3KcaCeAmffGwZ+ODWzOkPN4QwRbsK5DOFf06fywmyLci3ZD8jLGhVYA==",
"dev": true,
"dependencies": {
"call-bind": "^1.0.2",
"es-to-primitive": "^1.2.1",
"function-bind": "^1.1.1",
"get-intrinsic": "^1.1.1",
"has": "^1.0.3",
"has-symbols": "^1.0.2",
"internal-slot": "^1.0.3",
"is-callable": "^1.2.3",
"is-negative-zero": "^2.0.1",
"is-regex": "^1.1.3",
"is-string": "^1.0.6",
"object-inspect": "^1.11.0",
"object-keys": "^1.1.1",
"object.assign": "^4.1.2",
"string.prototype.trimend": "^1.0.4",
"string.prototype.trimstart": "^1.0.4",
"unbox-primitive": "^1.0.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/es-to-primitive": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
"integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
"dev": true,
"dependencies": {
"is-callable": "^1.1.4",
"is-date-object": "^1.0.1",
"is-symbol": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/esbuild": {
"version": "0.12.21",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.12.21.tgz",
"integrity": "sha512-7hyXbU3g94aREufI/5nls7Xcc+RGQeZWZApm6hoBaFvt2BPtpT4TjFMQ9Tb1jU8XyBGz00ShmiyflCogphMHFQ==",
"dev": true,
"hasInstallScript": true,
"bin": {
"esbuild": "bin/esbuild"
}
},
"node_modules/escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true,
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
"dev": true
},
"node_modules/get-intrinsic": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
"integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
"dev": true,
"dependencies": {
"function-bind": "^1.1.1",
"has": "^1.0.3",
"has-symbols": "^1.0.1"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/graceful-fs": {
"version": "4.2.8",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz",
"integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==",
"dev": true
},
"node_modules/has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
"dev": true,
"dependencies": {
"function-bind": "^1.1.1"
},
"engines": {
"node": ">= 0.4.0"
}
},
"node_modules/has-bigints": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz",
"integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==",
"dev": true,
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
"dev": true,
"engines": {
"node": ">=4"
}
},
"node_modules/has-symbols": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
"integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==",
"dev": true,
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-tostringtag": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
"integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
"dev": true,
"dependencies": {
"has-symbols": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/hosted-git-info": {
"version": "2.8.9",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
"integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
"dev": true
},
"node_modules/internal-slot": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz",
"integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==",
"dev": true,
"dependencies": {
"get-intrinsic": "^1.1.0",
"has": "^1.0.3",
"side-channel": "^1.0.4"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/is-arrayish": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
"integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
"dev": true
},
"node_modules/is-bigint": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
"integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==",
"dev": true,
"dependencies": {
"has-bigints": "^1.0.1"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-boolean-object": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
"integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==",
"dev": true,
"dependencies": {
"call-bind": "^1.0.2",
"has-tostringtag": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-callable": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz",
"integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==",
"dev": true,
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-core-module": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.6.0.tgz",
"integrity": "sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ==",
"dev": true,
"dependencies": {
"has": "^1.0.3"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-date-object": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
"integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
"dev": true,
"dependencies": {
"has-tostringtag": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-negative-zero": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz",
"integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==",
"dev": true,
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-number-object": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz",
"integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==",
"dev": true,
"dependencies": {
"has-tostringtag": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-regex": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
"integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
"dev": true,
"dependencies": {
"call-bind": "^1.0.2",
"has-tostringtag": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-string": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
"integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
"dev": true,
"dependencies": {
"has-tostringtag": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-symbol": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
"integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==",
"dev": true,
"dependencies": {
"has-symbols": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
"dev": true
},
"node_modules/json-parse-better-errors": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
"integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
"dev": true
},
"node_modules/load-json-file": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
"integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=",
"dev": true,
"dependencies": {
"graceful-fs": "^4.1.2",
"parse-json": "^4.0.0",
"pify": "^3.0.0",
"strip-bom": "^3.0.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/memorystream": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz",
"integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=",
"dev": true,
"engines": {
"node": ">= 0.10.0"
}
},
"node_modules/minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/nice-try": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
"dev": true
},
"node_modules/normalize-package-data": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
"integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
"dev": true,
"dependencies": {
"hosted-git-info": "^2.1.4",
"resolve": "^1.10.0",
"semver": "2 || 3 || 4 || 5",
"validate-npm-package-license": "^3.0.1"
}
},
"node_modules/npm-run-all": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz",
"integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==",
"dev": true,
"dependencies": {
"ansi-styles": "^3.2.1",
"chalk": "^2.4.1",
"cross-spawn": "^6.0.5",
"memorystream": "^0.3.1",
"minimatch": "^3.0.4",
"pidtree": "^0.3.0",
"read-pkg": "^3.0.0",
"shell-quote": "^1.6.1",
"string.prototype.padend": "^3.0.0"
},
"bin": {
"npm-run-all": "bin/npm-run-all/index.js",
"run-p": "bin/run-p/index.js",
"run-s": "bin/run-s/index.js"
},
"engines": {
"node": ">= 4"
}
},
"node_modules/object-inspect": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz",
"integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==",
"dev": true,
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/object-keys": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
"dev": true,
"engines": {
"node": ">= 0.4"
}
},
"node_modules/object.assign": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz",
"integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==",
"dev": true,
"dependencies": {
"call-bind": "^1.0.0",
"define-properties": "^1.1.3",
"has-symbols": "^1.0.1",
"object-keys": "^1.1.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/parse-json": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
"integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
"dev": true,
"dependencies": {
"error-ex": "^1.3.1",
"json-parse-better-errors": "^1.0.1"
},
"engines": {
"node": ">=4"
}
},
"node_modules/path-key": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
"integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
"dev": true,
"engines": {
"node": ">=4"
}
},
"node_modules/path-parse": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true
},
"node_modules/path-type": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
"integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
"dev": true,
"dependencies": {
"pify": "^3.0.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/pidtree": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz",
"integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==",
"dev": true,
"bin": {
"pidtree": "bin/pidtree.js"
},
"engines": {
"node": ">=0.10"
}
},
"node_modules/pify": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
"dev": true,
"engines": {
"node": ">=4"
}
},
"node_modules/read-pkg": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
"integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=",
"dev": true,
"dependencies": {
"load-json-file": "^4.0.0",
"normalize-package-data": "^2.3.2",
"path-type": "^3.0.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/resolve": {
"version": "1.20.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
"integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==",
"dev": true,
"dependencies": {
"is-core-module": "^2.2.0",
"path-parse": "^1.0.6"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"dev": true,
"bin": {
"semver": "bin/semver"
}
},
"node_modules/shebang-command": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
"integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
"dev": true,
"dependencies": {
"shebang-regex": "^1.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/shebang-regex": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
"integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/shell-quote": {
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz",
"integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==",
"dev": true
},
"node_modules/side-channel": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
"integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
"dev": true,
"dependencies": {
"call-bind": "^1.0.0",
"get-intrinsic": "^1.0.2",
"object-inspect": "^1.9.0"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/spdx-correct": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz",
"integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==",
"dev": true,
"dependencies": {
"spdx-expression-parse": "^3.0.0",
"spdx-license-ids": "^3.0.0"
}
},
"node_modules/spdx-exceptions": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
"integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==",
"dev": true
},
"node_modules/spdx-expression-parse": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
"integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
"dev": true,
"dependencies": {
"spdx-exceptions": "^2.1.0",
"spdx-license-ids": "^3.0.0"
}
},
"node_modules/spdx-license-ids": {
"version": "3.0.10",
"resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.10.tgz",
"integrity": "sha512-oie3/+gKf7QtpitB0LYLETe+k8SifzsX4KixvpOsbI6S0kRiRQ5MKOio8eMSAKQ17N06+wdEOXRiId+zOxo0hA==",
"dev": true
},
"node_modules/string.prototype.padend": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.2.tgz",
"integrity": "sha512-/AQFLdYvePENU3W5rgurfWSMU6n+Ww8n/3cUt7E+vPBB/D7YDG8x+qjoFs4M/alR2bW7Qg6xMjVwWUOvuQ0XpQ==",
"dev": true,
"dependencies": {
"call-bind": "^1.0.2",
"define-properties": "^1.1.3",
"es-abstract": "^1.18.0-next.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/string.prototype.trimend": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz",
"integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==",
"dev": true,
"dependencies": {
"call-bind": "^1.0.2",
"define-properties": "^1.1.3"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/string.prototype.trimstart": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz",
"integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==",
"dev": true,
"dependencies": {
"call-bind": "^1.0.2",
"define-properties": "^1.1.3"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/strip-bom": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
"integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
"dev": true,
"engines": {
"node": ">=4"
}
},
"node_modules/supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"dependencies": {
"has-flag": "^3.0.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/svelte": {
"version": "3.42.2",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.42.2.tgz",
"integrity": "sha512-FOyNYKXb8wdE0Ot+Ctt2/OyDLsNBP8+V6PUE9ag6ZKeLslIou0LnMu1fhtWUA+HjzKTbAM1yj+4PFLtg/3pMJA==",
"dev": true,
"engines": {
"node": ">= 8"
}
},
"node_modules/unbox-primitive": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz",
"integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==",
"dev": true,
"dependencies": {
"function-bind": "^1.1.1",
"has-bigints": "^1.0.1",
"has-symbols": "^1.0.2",
"which-boxed-primitive": "^1.0.2"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/validate-npm-package-license": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
"integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
"dev": true,
"dependencies": {
"spdx-correct": "^3.0.0",
"spdx-expression-parse": "^3.0.0"
}
},
"node_modules/which": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
"integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
"dev": true,
"dependencies": {
"isexe": "^2.0.0"
},
"bin": {
"which": "bin/which"
}
},
"node_modules/which-boxed-primitive": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
"integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==",
"dev": true,
"dependencies": {
"is-bigint": "^1.0.1",
"is-boolean-object": "^1.1.0",
"is-number-object": "^1.0.4",
"is-string": "^1.0.5",
"is-symbol": "^1.0.3"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
}
},
"dependencies": {
"ansi-styles": {
"version": "3.2.1",
@@ -1007,6 +144,23 @@
"integrity": "sha512-7hyXbU3g94aREufI/5nls7Xcc+RGQeZWZApm6hoBaFvt2BPtpT4TjFMQ9Tb1jU8XyBGz00ShmiyflCogphMHFQ==",
"dev": true
},
"esbuild-svelte": {
"version": "0.5.6",
"resolved": "https://registry.npmjs.org/esbuild-svelte/-/esbuild-svelte-0.5.6.tgz",
"integrity": "sha512-Bz8nU45FrT6sP/Tf3M2rQUuBGxnDSNSPZNIoYwSNt5H+wjSyo/t+zm94tgnOZsR6GgpDMbNQgo4jGbK0NLvEfw==",
"dev": true,
"requires": {
"svelte": "^3.42.6"
},
"dependencies": {
"svelte": {
"version": "3.43.1",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.43.1.tgz",
"integrity": "sha512-nvPIaKx4HLzYlSdquISZpgG1Kqr2VAWQjZOt3Iwm3UhbqmA0LnSx4k1YpRMEhjQYW3ZCqQoK8Egto9tv4YewMA==",
"dev": true
}
}
},
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",

View File

@@ -12,6 +12,7 @@
"devDependencies": {
"esbuild": "^0.12.17",
"npm-run-all": "^4.1.5",
"svelte": "^3.42.2"
"svelte": "^3.42.2",
"esbuild-svelte": "^0.5.6"
}
}

View File

@@ -1,8 +1,8 @@
//go:build windows
//go:build darwin || windows
package runtime
import _ "embed"
//go:embed ipc_windows.js
//go:embed ipc.js
var DesktopIPC []byte

View File

@@ -0,0 +1 @@
(()=>{(function(){let o=function(e){for(var s=window[e.shift()];s&&e.length;)s=s[e.shift()];return s},t=o(["chrome","webview","postMessage"]),n=o(["webkit","messageHandlers","external","postMessage"]);if(!t&&!n){console.error("Unsupported Platform");return}t&&(window.WailsInvoke=e=>window.chrome.webview.postMessage(e)),n&&(window.WailsInvoke=e=>window.webkit.messageHandlers.external.postMessage(e))})();})();

View File

@@ -1,8 +0,0 @@
//go:build darwin
package runtime
import _ "embed"
//go:embed ipc_darwin.js
var DesktopIPC []byte

View File

@@ -1 +0,0 @@
(()=>{window.WailsInvoke=function(e){window.webkit.messageHandlers.external.postMessage(e)};})();

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
(()=>{window.WailsInvoke=function(e){window.chrome.webview.postMessage(e)};})();

View File

@@ -5,8 +5,7 @@
"main": "index.js",
"scripts": {
"build": "run-p build:*",
"build:ipc-windows": "esbuild desktop/ipc.js --bundle --minify --outfile=ipc_windows.js --define:PLATFORM=0",
"build:ipc-darwin": "esbuild desktop/ipc.js --bundle --minify --outfile=ipc_darwin.js --define:PLATFORM=1",
"build:ipc-desktop": "esbuild desktop/ipc.js --bundle --minify --outfile=ipc.js",
"build:ipc-dev": "cd dev && npm run build",
"build:runtime-desktop-prod": "esbuild desktop/main.js --bundle --minify --outfile=runtime_prod_desktop.js --define:ENV=1",
"build:runtime-desktop-dev": "esbuild desktop/main.js --bundle --sourcemap=inline --outfile=runtime_dev_desktop.js --define:ENV=0",

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