Compare commits

...

121 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
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
152 changed files with 6524 additions and 2122 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,52 +79,69 @@ 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>
<a href="https://github.com/codydbentley" style="width:65px">
<img src="https://github.com/codydbentley.png?size=65" width="65"/>
<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>
## Installation

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

@@ -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,152 +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
}
}
userTags := []string{}
for _, tag := range strings.Split(tags, " ") {
thisTag := strings.TrimSpace(tag)
if thisTag != "" {
userTags = append(userTags, thisTag)
}
}
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,
UserTags: userTags,
}
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
}
@@ -204,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 {
@@ -346,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
@@ -368,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
@@ -376,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)
@@ -391,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

@@ -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

@@ -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,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.4"

View File

@@ -21,7 +21,7 @@ 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/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
@@ -41,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

@@ -115,8 +115,8 @@ github.com/leaanthony/go-ansi-parser v1.0.1 h1:97v6c5kYppVsbScf4r/VZdXyQ21KQIfeQ
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-20210928094513-a94a08b538bd h1:6m4zZ/esiByaDbzgdvDxjsOaIDgtuG1q2cyhjAi6uAg=
github.com/leaanthony/go-webview2 v0.0.0-20210928094513-a94a08b538bd/go.mod h1:lS5ds4bruPk9d7lzdF/OH31Z0YCerI6MmHNFGsWoUnM=
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=
@@ -257,8 +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-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

@@ -16,7 +16,7 @@ import (
//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
@@ -24,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
@@ -90,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

@@ -7,7 +7,9 @@ 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"
)
/*
@@ -49,7 +51,11 @@ func (a *BrowserAssetServer) processIndexHTML() ([]byte, error) {
if err != nil {
return nil, err
}
indexHTML, err = injectHTML(string(indexHTML), `<div id="wails-spinner"></div>`)
htmlNode, err := getHTMLNode(indexHTML)
if err != nil {
return nil, err
}
err = appendSpinnerToBody(htmlNode)
if err != nil {
return nil, err
}
@@ -57,19 +63,27 @@ func (a *BrowserAssetServer) processIndexHTML() ([]byte, error) {
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 {
indexHTML, err = injectHTML(string(indexHTML), `<script src="/wails/runtime.js"></script>`)
err := insertScriptInHead(htmlNode, "/wails/runtime.js")
if err != nil {
return nil, err
}
}
if wailsOptions.disableBindingsInjection == false {
indexHTML, err = injectHTML(string(indexHTML), `<script src="/wails/ipc.js"></script>`)
if err != nil {
return nil, err
}
var buffer bytes.Buffer
err = html.Render(&buffer, htmlNode)
if err != nil {
return nil, err
}
return indexHTML, nil
return buffer.Bytes(), nil
}
func (a *BrowserAssetServer) Load(filename string) ([]byte, string, error) {
@@ -84,6 +98,14 @@ func (a *BrowserAssetServer) Load(filename string) ([]byte, string, error) {
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

View File

@@ -119,14 +119,13 @@ func (a *DesktopAssetServer) processIndexHTML() ([]byte, error) {
log.Fatal(err)
return nil, err
}
fmt.Printf("%+v\n", wailsOptions)
if wailsOptions.disableRuntimeInjection == false {
indexHTML, err = injectHTML(string(indexHTML), `<script src="/wails/runtime.js"></script>`)
if err != nil {
return nil, err
}
}
if wailsOptions.disableBindingsInjection == false {
if wailsOptions.disableIPCInjection == false {
indexHTML, err = injectHTML(string(indexHTML), `<script src="/wails/ipc.js"></script>`)
if err != nil {
return nil, err

View File

@@ -2,6 +2,7 @@ package assetserver
import (
"bytes"
"errors"
"fmt"
"golang.org/x/net/html"
"strings"
@@ -10,14 +11,14 @@ import (
type optionType string
const (
noAutoInject optionType = "noautoinject"
noAutoInjectRuntime optionType = "noautoinjectruntime"
noAutoInjectBindings optionType = "noautoinjectbindings"
noAutoInject optionType = "noautoinject"
noAutoInjectRuntime optionType = "noautoinjectruntime"
noAutoInjectIPC optionType = "noautoinjectipc"
)
type Options struct {
disableRuntimeInjection bool
disableBindingsInjection bool
disableRuntimeInjection bool
disableIPCInjection bool
}
func newOptions(optionString string) *Options {
@@ -28,9 +29,9 @@ func newOptions(optionString string) *Options {
switch optionType(strings.TrimSpace(option)) {
case noAutoInject:
result.disableRuntimeInjection = true
result.disableBindingsInjection = true
case noAutoInjectBindings:
result.disableBindingsInjection = true
result.disableIPCInjection = true
case noAutoInjectIPC:
result.disableIPCInjection = true
case noAutoInjectRuntime:
result.disableRuntimeInjection = true
}
@@ -86,3 +87,77 @@ func extractOptions(htmldata []byte) (*Options, error) {
}
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

@@ -33,8 +33,8 @@ func genMeta(content string) []byte {
func genOptions(runtime bool, bindings bool) *Options {
return &Options{
disableRuntimeInjection: runtime,
disableBindingsInjection: bindings,
disableRuntimeInjection: runtime,
disableIPCInjection: bindings,
}
}
@@ -50,11 +50,11 @@ func Test_extractOptions(t *testing.T) {
{"bad options", genMeta("noauto"), genOptions(false, false), false},
{"realhtml", []byte(realHTML), genOptions(true, true), false},
{"noautoinject", genMeta("noautoinject"), genOptions(true, true), false},
{"noautoinjectbindings", genMeta("noautoinjectbindings"), genOptions(false, 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,noautoinjectbindings"), genOptions(true, true), false},
{"multiple spaces", genMeta(" noautoinjectruntime, noautoinjectbindings "), genOptions(true, true), 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) {

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

@@ -35,7 +35,7 @@ type DevWebServer struct {
dispatcher frontend.Dispatcher
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.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")
// 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()
}()
}
}
@@ -363,7 +388,7 @@ func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger.
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 darwin
//go:build darwin || windows
package runtime
import _ "embed"
//go:embed ipc_darwin.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 +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,8 +0,0 @@
//go:build windows
package runtime
import _ "embed"
//go:embed ipc_windows.js
var DesktopIPC []byte

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",

View File

@@ -1,4 +1,4 @@
//go:build dev
//go:build dev || bindings || (!dev && !production && !bindings)
package runtime

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
(()=>{var g=Object.defineProperty;var h=o=>g(o,"__esModule",{value:!0});var f=(o,n)=>{h(o);for(var e in n)g(o,e,{get:n[e],enumerable:!0})};var W={};f(W,{LogDebug:()=>T,LogError:()=>D,LogFatal:()=>F,LogInfo:()=>C,LogLevel:()=>U,LogPrint:()=>B,LogTrace:()=>R,LogWarning:()=>J,SetLogLevel:()=>G});function l(o,n){window.WailsInvoke("L"+o+n)}function R(o){l("T",o)}function B(o){l("P",o)}function T(o){l("D",o)}function C(o){l("I",o)}function J(o){l("W",o)}function D(o){l("E",o)}function F(o){l("F",o)}function G(o){l("S",o)}var U={TRACE:1,DEBUG:2,INFO:3,WARNING:4,ERROR:5};var E=class{constructor(n,e){e=e||-1,this.Callback=t=>(n.apply(null,t),e===-1?!1:(e-=1,e===0))}},s={};function d(o,n,e){s[o]=s[o]||[];let t=new E(n,e);s[o].push(t)}function I(o,n){d(o,n,-1)}function k(o,n){d(o,n,1)}function m(o){let n=o.name;if(s[n]){let e=s[n].slice();for(let t=0;t<s[n].length;t+=1){let r=s[n][t],i=o.data;r.Callback(i)&&e.splice(t,1)}s[n]=e}}function S(o){let n;try{n=JSON.parse(o)}catch(e){let t="Invalid JSON passed to Notify: "+o;throw new Error(t)}m(n)}function y(o){let n={name:o,data:[].slice.apply(arguments).slice(1)};m(n),window.WailsInvoke("EE"+JSON.stringify(n))}function L(o){s.delete(o),window.WailsInvoke("EX"+o)}var c={};function z(){var o=new Uint32Array(1);return window.crypto.getRandomValues(o)[0]}function A(){return Math.random()*9007199254740991}var p;window.crypto?p=z:p=A;function a(o,n,e){return e==null&&(e=0),new Promise(function(t,r){var i;do i=o+"-"+p();while(c[i]);var w;e>0&&(w=setTimeout(function(){r(Error("Call to "+o+" timed out. Request ID: "+i))},e)),c[i]={timeoutHandle:w,reject:r,resolve:t};try{let u={name:o,args:n,callbackID:i};window.WailsInvoke("C"+JSON.stringify(u))}catch(u){console.error(u)}})}function O(o){var n;try{n=JSON.parse(o)}catch(r){let i=`Invalid JSON passed to callback: ${r.message}. Message: ${o}`;throw wails.LogDebug(i),new Error(i)}var e=n.callbackid,t=c[e];if(!t){let r=`Callback '${e}' not registered!!!`;throw console.error(r),new Error(r)}clearTimeout(t.timeoutHandle),delete c[e],n.error?t.reject(n.error):t.resolve(n.result)}window.go={};function b(o){try{o=JSON.parse(o)}catch(n){console.error(n)}window.go=window.go||{},Object.keys(o).forEach(n=>{window.go[n]=window.go[n]||{},Object.keys(o[n]).forEach(e=>{window.go[n][e]=window.go[n][e]||{},Object.keys(o[n][e]).forEach(t=>{window.go[n][e][t]=function(){let r=0;function i(){let w=[].slice.call(arguments);return a([n,e,t].join("."),w,r)}return i.setTimeout=function(w){r=w},i.getTimeout=function(){return r},i}()})})})}var v={};f(v,{WindowCenter:()=>j,WindowFullscreen:()=>M,WindowGetPosition:()=>Z,WindowGetSize:()=>V,WindowHide:()=>K,WindowMaximise:()=>_,WindowMinimise:()=>no,WindowReload:()=>P,WindowSetMaxSize:()=>q,WindowSetMinSize:()=>N,WindowSetPosition:()=>X,WindowSetRGBA:()=>to,WindowSetSize:()=>Q,WindowSetTitle:()=>H,WindowShow:()=>Y,WindowUnFullscreen:()=>$,WindowUnmaximise:()=>oo,WindowUnminimise:()=>eo});function P(){window.location.reload()}function j(){window.WailsInvoke("Wc")}function H(o){window.WailsInvoke("WT"+o)}function M(){window.WailsInvoke("WF")}function $(){window.WailsInvoke("Wf")}function Q(o,n){window.WailsInvoke("Ws:"+o+":"+n)}function V(){return a(":wails:WindowGetSize")}function q(o,n){window.WailsInvoke("WZ:"+o+":"+n)}function N(o,n){window.WailsInvoke("Wz:"+o+":"+n)}function X(o,n){window.WailsInvoke("Wp:"+o+":"+n)}function Z(){return a(":wails:WindowGetPos")}function K(){window.WailsInvoke("WH")}function Y(){window.WailsInvoke("WS")}function _(){window.WailsInvoke("WM")}function oo(){window.WailsInvoke("WU")}function no(){window.WailsInvoke("Wm")}function eo(){window.WailsInvoke("Wu")}function to(o){let n=JSON.stringify(o);window.WailsInvoke("Wr:"+n)}var x={};f(x,{BrowserOpenURL:()=>io});function io(o){window.WailsInvoke("BO:"+o)}function ro(){window.WailsInvoke("Q")}window.runtime={...W,...v,...x,EventsOn:I,EventsOnce:k,EventsOnMultiple:d,EventsEmit:y,EventsOff:L,Quit:ro};window.wails={Callback:O,EventsNotify:S,SetBindings:b,eventListeners:s,callbacks:c};window.wails.SetBindings(window.wailsbindings);delete window.wails.SetBindings;window.addEventListener("mousedown",o=>{let n=o.target;for(;n!=null&&!n.hasAttribute("data-wails-no-drag");){if(n.hasAttribute("data-wails-drag")){window.WailsInvoke("drag");break}n=n.parentElement}});})();
(()=>{var x=Object.defineProperty;var h=n=>x(n,"__esModule",{value:!0});var u=(n,o)=>{h(n);for(var e in o)x(n,e,{get:o[e],enumerable:!0})};var W={};u(W,{LogDebug:()=>C,LogError:()=>J,LogFatal:()=>F,LogInfo:()=>B,LogLevel:()=>U,LogPrint:()=>R,LogTrace:()=>D,LogWarning:()=>T,SetLogLevel:()=>G});function l(n,o){window.WailsInvoke("L"+n+o)}function D(n){l("T",n)}function R(n){l("P",n)}function C(n){l("D",n)}function B(n){l("I",n)}function T(n){l("W",n)}function J(n){l("E",n)}function F(n){l("F",n)}function G(n){l("S",n)}var U={TRACE:1,DEBUG:2,INFO:3,WARNING:4,ERROR:5};var E=class{constructor(o,e){e=e||-1,this.Callback=t=>(o.apply(null,t),e===-1?!1:(e-=1,e===0))}},s={};function d(n,o,e){s[n]=s[n]||[];let t=new E(o,e);s[n].push(t)}function I(n,o){d(n,o,-1)}function k(n,o){d(n,o,1)}function S(n){let o=n.name;if(s[o]){let e=s[o].slice();for(let t=0;t<s[o].length;t+=1){let r=s[o][t],i=n.data;r.Callback(i)&&e.splice(t,1)}s[o]=e}}function m(n){let o;try{o=JSON.parse(n)}catch(e){let t="Invalid JSON passed to Notify: "+n;throw new Error(t)}S(o)}function b(n){let o={name:n,data:[].slice.apply(arguments).slice(1)};S(o),window.WailsInvoke("EE"+JSON.stringify(o))}function y(n){s.delete(n),window.WailsInvoke("EX"+n)}var a={};function z(){var n=new Uint32Array(1);return window.crypto.getRandomValues(n)[0]}function A(){return Math.random()*9007199254740991}var p;window.crypto?p=z:p=A;function c(n,o,e){return e==null&&(e=0),new Promise(function(t,r){var i;do i=n+"-"+p();while(a[i]);var w;e>0&&(w=setTimeout(function(){r(Error("Call to "+n+" timed out. Request ID: "+i))},e)),a[i]={timeoutHandle:w,reject:r,resolve:t};try{let f={name:n,args:o,callbackID:i};window.WailsInvoke("C"+JSON.stringify(f))}catch(f){console.error(f)}})}function L(n){var o;try{o=JSON.parse(n)}catch(r){let i=`Invalid JSON passed to callback: ${r.message}. Message: ${n}`;throw wails.LogDebug(i),new Error(i)}var e=o.callbackid,t=a[e];if(!t){let r=`Callback '${e}' not registered!!!`;throw console.error(r),new Error(r)}clearTimeout(t.timeoutHandle),delete a[e],o.error?t.reject(o.error):t.resolve(o.result)}window.go={};function O(n){try{n=JSON.parse(n)}catch(o){console.error(o)}window.go=window.go||{},Object.keys(n).forEach(o=>{window.go[o]=window.go[o]||{},Object.keys(n[o]).forEach(e=>{window.go[o][e]=window.go[o][e]||{},Object.keys(n[o][e]).forEach(t=>{window.go[o][e][t]=function(){let r=0;function i(){let w=[].slice.call(arguments);return c([o,e,t].join("."),w,r)}return i.setTimeout=function(w){r=w},i.getTimeout=function(){return r},i}()})})})}var v={};u(v,{WindowCenter:()=>M,WindowFullscreen:()=>j,WindowGetPosition:()=>Y,WindowGetSize:()=>V,WindowHide:()=>Z,WindowMaximise:()=>_,WindowMinimise:()=>on,WindowReload:()=>H,WindowSetMaxSize:()=>X,WindowSetMinSize:()=>q,WindowSetPosition:()=>N,WindowSetRGBA:()=>tn,WindowSetSize:()=>Q,WindowSetTitle:()=>P,WindowShow:()=>K,WindowUnFullscreen:()=>$,WindowUnmaximise:()=>nn,WindowUnminimise:()=>en});function H(){window.location.reload()}function M(){window.WailsInvoke("Wc")}function P(n){window.WailsInvoke("WT"+n)}function j(){window.WailsInvoke("WF")}function $(){window.WailsInvoke("Wf")}function Q(n,o){window.WailsInvoke("Ws:"+n+":"+o)}function V(){return c(":wails:WindowGetSize")}function X(n,o){window.WailsInvoke("WZ:"+n+":"+o)}function q(n,o){window.WailsInvoke("Wz:"+n+":"+o)}function N(n,o){window.WailsInvoke("Wp:"+n+":"+o)}function Y(){return c(":wails:WindowGetPos")}function Z(){window.WailsInvoke("WH")}function K(){window.WailsInvoke("WS")}function _(){window.WailsInvoke("WM")}function nn(){window.WailsInvoke("WU")}function on(){window.WailsInvoke("Wm")}function en(){window.WailsInvoke("Wu")}function tn(n){let o=JSON.stringify(n);window.WailsInvoke("Wr:"+o)}var g={};u(g,{BrowserOpenURL:()=>rn});function rn(n){window.WailsInvoke("BO:"+n)}function sn(){window.WailsInvoke("Q")}window.runtime={...W,...v,...g,EventsOn:I,EventsOnce:k,EventsOnMultiple:d,EventsEmit:b,EventsOff:y,Quit:sn};window.wails={Callback:L,EventsNotify:m,SetBindings:O,eventListeners:s,callbacks:a,flags:{disableScrollbarDrag:!1,disableWailsDefaultContextMenu:!1}};window.wails.SetBindings(window.wailsbindings);delete window.wails.SetBindings;window.addEventListener("mousedown",n=>{let o=n.target;for(;o!=null&&!o.hasAttribute("data-wails-no-drag");){if(o.hasAttribute("data-wails-drag")){if(window.wails.flags.disableScrollbarDrag&&(n.offsetX>n.target.clientWidth||n.offsetY>n.target.clientHeight))break;window.WailsInvoke("drag"),n.preventDefault();break}o=o.parentElement}});window.addEventListener("contextmenu",function(n){window.wails.flags.disableWailsDefaultContextMenu&&n.preventDefault()});})();

View File

@@ -9,9 +9,9 @@ interface Size {
}
interface RGBA {
r,
g,
b,
r: number;
g: number;
b: number;
a: number;
}

View File

@@ -0,0 +1,79 @@
package gomod
import (
"fmt"
"github.com/Masterminds/semver"
"golang.org/x/mod/modfile"
)
func GetWailsVersionFromModFile(goModText []byte) (*semver.Version, error) {
file, err := modfile.Parse("", goModText, nil)
if err != nil {
return nil, err
}
for _, req := range file.Require {
if req.Syntax == nil {
continue
}
tokenPosition := 0
if !req.Syntax.InBlock {
tokenPosition = 1
}
if req.Syntax.Token[tokenPosition] == "github.com/wailsapp/wails/v2" {
version := req.Syntax.Token[tokenPosition+1]
return semver.NewVersion(version)
}
}
return nil, nil
}
func GoModOutOfSync(goModData []byte, currentVersion string) (bool, error) {
gomodversion, err := GetWailsVersionFromModFile(goModData)
if err != nil {
return false, err
}
result, err := semver.NewVersion(currentVersion)
if err != nil || result == nil {
return false, fmt.Errorf("Unable to parse Wails version: %s", currentVersion)
}
return !gomodversion.Equal(result), nil
}
func UpdateGoModVersion(goModText []byte, currentVersion string) ([]byte, error) {
file, err := modfile.Parse("", goModText, nil)
if err != nil {
return nil, err
}
err = file.AddRequire("github.com/wailsapp/wails/v2", currentVersion)
if err != nil {
return nil, err
}
// Replace
if len(file.Replace) == 0 {
return file.Format()
}
for _, req := range file.Replace {
if req.Syntax == nil {
continue
}
tokenPosition := 0
if !req.Syntax.InBlock {
tokenPosition = 1
}
if req.Syntax.Token[tokenPosition] == "github.com/wailsapp/wails/v2" {
version := req.Syntax.Token[tokenPosition+1]
_, err := semver.NewVersion(version)
if err == nil {
req.Syntax.Token[tokenPosition+1] = currentVersion
}
}
}
return file.Format()
}

View File

@@ -0,0 +1,603 @@
package gomod
import (
"github.com/Masterminds/semver"
"github.com/matryer/is"
"reflect"
"testing"
)
const basic string = `module changeme
go 1.17
require github.com/wailsapp/wails/v2 v2.0.0-beta.7
require (
github.com/andybalholm/brotli v1.0.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab // indirect
github.com/gabriel-vasile/mimetype v1.3.1 // indirect
github.com/go-ole/go-ole v1.2.5 // indirect
github.com/gofiber/fiber/v2 v2.17.0 // indirect
github.com/gofiber/websocket/v2 v2.0.8 // indirect
github.com/google/uuid v1.1.2 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
github.com/klauspost/compress v1.12.2 // indirect
github.com/leaanthony/debme v1.2.1 // indirect
github.com/leaanthony/go-ansi-parser v1.0.1 // indirect
github.com/leaanthony/go-common-file-dialog v1.0.3 // indirect
github.com/leaanthony/go-webview2 v0.0.0-20211007092718-65d2f028ef2d // indirect
github.com/leaanthony/gosod v1.0.3 // indirect
github.com/leaanthony/slicer v1.5.0 // indirect
github.com/leaanthony/typescriptify-golang-structs v0.1.7 // indirect
github.com/leaanthony/webview2runtime v1.1.0 // indirect
github.com/leaanthony/winc v0.0.0-20210921073452-54963136bf18 // indirect
github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f // indirect
github.com/tkrajina/go-reflector v0.5.5 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.28.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect
)
//replace github.com/wailsapp/wails/v2 v2.0.0-beta.7 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2
`
func TestGetWailsVersion(t *testing.T) {
tests := []struct {
name string
goModText []byte
want *semver.Version
wantErr bool
}{
{"basic", []byte(basic), semver.MustParse("v2.0.0-beta.7"), false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := GetWailsVersionFromModFile(tt.goModText)
if (err != nil) != tt.wantErr {
t.Errorf("GetWailsVersion() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetWailsVersion() got = %v, want %v", got, tt.want)
}
})
}
}
const basicUpdated string = `module changeme
go 1.17
require github.com/wailsapp/wails/v2 v2.0.0-beta.15
require (
github.com/andybalholm/brotli v1.0.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab // indirect
github.com/gabriel-vasile/mimetype v1.3.1 // indirect
github.com/go-ole/go-ole v1.2.5 // indirect
github.com/gofiber/fiber/v2 v2.17.0 // indirect
github.com/gofiber/websocket/v2 v2.0.8 // indirect
github.com/google/uuid v1.1.2 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
github.com/klauspost/compress v1.12.2 // indirect
github.com/leaanthony/debme v1.2.1 // indirect
github.com/leaanthony/go-ansi-parser v1.0.1 // indirect
github.com/leaanthony/go-common-file-dialog v1.0.3 // indirect
github.com/leaanthony/go-webview2 v0.0.0-20211007092718-65d2f028ef2d // indirect
github.com/leaanthony/gosod v1.0.3 // indirect
github.com/leaanthony/slicer v1.5.0 // indirect
github.com/leaanthony/typescriptify-golang-structs v0.1.7 // indirect
github.com/leaanthony/webview2runtime v1.1.0 // indirect
github.com/leaanthony/winc v0.0.0-20210921073452-54963136bf18 // indirect
github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f // indirect
github.com/tkrajina/go-reflector v0.5.5 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.28.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect
)
//replace github.com/wailsapp/wails/v2 v2.0.0-beta.7 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2
`
const multilineRequire = `module changeme
go 1.17
require (
github.com/wailsapp/wails/v2 v2.0.0-beta.7
)
require (
github.com/andybalholm/brotli v1.0.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab // indirect
github.com/gabriel-vasile/mimetype v1.3.1 // indirect
github.com/go-ole/go-ole v1.2.5 // indirect
github.com/gofiber/fiber/v2 v2.17.0 // indirect
github.com/gofiber/websocket/v2 v2.0.8 // indirect
github.com/google/uuid v1.1.2 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
github.com/klauspost/compress v1.12.2 // indirect
github.com/leaanthony/debme v1.2.1 // indirect
github.com/leaanthony/go-ansi-parser v1.0.1 // indirect
github.com/leaanthony/go-common-file-dialog v1.0.3 // indirect
github.com/leaanthony/go-webview2 v0.0.0-20211007092718-65d2f028ef2d // indirect
github.com/leaanthony/gosod v1.0.3 // indirect
github.com/leaanthony/slicer v1.5.0 // indirect
github.com/leaanthony/typescriptify-golang-structs v0.1.7 // indirect
github.com/leaanthony/webview2runtime v1.1.0 // indirect
github.com/leaanthony/winc v0.0.0-20210921073452-54963136bf18 // indirect
github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f // indirect
github.com/tkrajina/go-reflector v0.5.5 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.28.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect
)
//replace github.com/wailsapp/wails/v2 v2.0.0-beta.7 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2
`
const multilineReplace = `module changeme
go 1.17
require (
github.com/wailsapp/wails/v2 v2.0.0-beta.7
)
require (
github.com/andybalholm/brotli v1.0.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab // indirect
github.com/gabriel-vasile/mimetype v1.3.1 // indirect
github.com/go-ole/go-ole v1.2.5 // indirect
github.com/gofiber/fiber/v2 v2.17.0 // indirect
github.com/gofiber/websocket/v2 v2.0.8 // indirect
github.com/google/uuid v1.1.2 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
github.com/klauspost/compress v1.12.2 // indirect
github.com/leaanthony/debme v1.2.1 // indirect
github.com/leaanthony/go-ansi-parser v1.0.1 // indirect
github.com/leaanthony/go-common-file-dialog v1.0.3 // indirect
github.com/leaanthony/go-webview2 v0.0.0-20211007092718-65d2f028ef2d // indirect
github.com/leaanthony/gosod v1.0.3 // indirect
github.com/leaanthony/slicer v1.5.0 // indirect
github.com/leaanthony/typescriptify-golang-structs v0.1.7 // indirect
github.com/leaanthony/webview2runtime v1.1.0 // indirect
github.com/leaanthony/winc v0.0.0-20210921073452-54963136bf18 // indirect
github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f // indirect
github.com/tkrajina/go-reflector v0.5.5 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.28.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect
)
replace github.com/wailsapp/wails/v2 v2.0.0-beta.7 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2
`
const multilineReplaceNoVersion = `module changeme
go 1.17
require (
github.com/wailsapp/wails/v2 v2.0.0-beta.7
)
require (
github.com/andybalholm/brotli v1.0.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab // indirect
github.com/gabriel-vasile/mimetype v1.3.1 // indirect
github.com/go-ole/go-ole v1.2.5 // indirect
github.com/gofiber/fiber/v2 v2.17.0 // indirect
github.com/gofiber/websocket/v2 v2.0.8 // indirect
github.com/google/uuid v1.1.2 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
github.com/klauspost/compress v1.12.2 // indirect
github.com/leaanthony/debme v1.2.1 // indirect
github.com/leaanthony/go-ansi-parser v1.0.1 // indirect
github.com/leaanthony/go-common-file-dialog v1.0.3 // indirect
github.com/leaanthony/go-webview2 v0.0.0-20211007092718-65d2f028ef2d // indirect
github.com/leaanthony/gosod v1.0.3 // indirect
github.com/leaanthony/slicer v1.5.0 // indirect
github.com/leaanthony/typescriptify-golang-structs v0.1.7 // indirect
github.com/leaanthony/webview2runtime v1.1.0 // indirect
github.com/leaanthony/winc v0.0.0-20210921073452-54963136bf18 // indirect
github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f // indirect
github.com/tkrajina/go-reflector v0.5.5 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.28.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect
)
replace github.com/wailsapp/wails/v2 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2
`
const multilineReplaceNoVersionBlock = `module changeme
go 1.17
require (
github.com/wailsapp/wails/v2 v2.0.0-beta.7
)
require (
github.com/andybalholm/brotli v1.0.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab // indirect
github.com/gabriel-vasile/mimetype v1.3.1 // indirect
github.com/go-ole/go-ole v1.2.5 // indirect
github.com/gofiber/fiber/v2 v2.17.0 // indirect
github.com/gofiber/websocket/v2 v2.0.8 // indirect
github.com/google/uuid v1.1.2 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
github.com/klauspost/compress v1.12.2 // indirect
github.com/leaanthony/debme v1.2.1 // indirect
github.com/leaanthony/go-ansi-parser v1.0.1 // indirect
github.com/leaanthony/go-common-file-dialog v1.0.3 // indirect
github.com/leaanthony/go-webview2 v0.0.0-20211007092718-65d2f028ef2d // indirect
github.com/leaanthony/gosod v1.0.3 // indirect
github.com/leaanthony/slicer v1.5.0 // indirect
github.com/leaanthony/typescriptify-golang-structs v0.1.7 // indirect
github.com/leaanthony/webview2runtime v1.1.0 // indirect
github.com/leaanthony/winc v0.0.0-20210921073452-54963136bf18 // indirect
github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f // indirect
github.com/tkrajina/go-reflector v0.5.5 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.28.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect
)
replace (
github.com/wailsapp/wails/v2 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2
)
`
const multilineReplaceBlock = `module changeme
go 1.17
require (
github.com/wailsapp/wails/v2 v2.0.0-beta.7
)
require (
github.com/andybalholm/brotli v1.0.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab // indirect
github.com/gabriel-vasile/mimetype v1.3.1 // indirect
github.com/go-ole/go-ole v1.2.5 // indirect
github.com/gofiber/fiber/v2 v2.17.0 // indirect
github.com/gofiber/websocket/v2 v2.0.8 // indirect
github.com/google/uuid v1.1.2 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
github.com/klauspost/compress v1.12.2 // indirect
github.com/leaanthony/debme v1.2.1 // indirect
github.com/leaanthony/go-ansi-parser v1.0.1 // indirect
github.com/leaanthony/go-common-file-dialog v1.0.3 // indirect
github.com/leaanthony/go-webview2 v0.0.0-20211007092718-65d2f028ef2d // indirect
github.com/leaanthony/gosod v1.0.3 // indirect
github.com/leaanthony/slicer v1.5.0 // indirect
github.com/leaanthony/typescriptify-golang-structs v0.1.7 // indirect
github.com/leaanthony/webview2runtime v1.1.0 // indirect
github.com/leaanthony/winc v0.0.0-20210921073452-54963136bf18 // indirect
github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f // indirect
github.com/tkrajina/go-reflector v0.5.5 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.28.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect
)
replace (
github.com/wailsapp/wails/v2 v2.0.0-beta.7 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2
)
`
const multilineRequireUpdated = `module changeme
go 1.17
require (
github.com/wailsapp/wails/v2 v2.0.0-beta.15
)
require (
github.com/andybalholm/brotli v1.0.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab // indirect
github.com/gabriel-vasile/mimetype v1.3.1 // indirect
github.com/go-ole/go-ole v1.2.5 // indirect
github.com/gofiber/fiber/v2 v2.17.0 // indirect
github.com/gofiber/websocket/v2 v2.0.8 // indirect
github.com/google/uuid v1.1.2 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
github.com/klauspost/compress v1.12.2 // indirect
github.com/leaanthony/debme v1.2.1 // indirect
github.com/leaanthony/go-ansi-parser v1.0.1 // indirect
github.com/leaanthony/go-common-file-dialog v1.0.3 // indirect
github.com/leaanthony/go-webview2 v0.0.0-20211007092718-65d2f028ef2d // indirect
github.com/leaanthony/gosod v1.0.3 // indirect
github.com/leaanthony/slicer v1.5.0 // indirect
github.com/leaanthony/typescriptify-golang-structs v0.1.7 // indirect
github.com/leaanthony/webview2runtime v1.1.0 // indirect
github.com/leaanthony/winc v0.0.0-20210921073452-54963136bf18 // indirect
github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f // indirect
github.com/tkrajina/go-reflector v0.5.5 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.28.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect
)
//replace github.com/wailsapp/wails/v2 v2.0.0-beta.7 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2
`
func TestUpdateGoModVersion(t *testing.T) {
is2 := is.New(t)
type args struct {
goModText []byte
currentVersion string
}
tests := []struct {
name string
args args
want []byte
wantErr bool
}{
{"basic", args{[]byte(basic), "v2.0.0-beta.15"}, []byte(basicUpdated), false},
{"basicmultiline", args{[]byte(multilineRequire), "v2.0.0-beta.15"}, []byte(multilineRequireUpdated), false},
{"basicmultilinereplace", args{[]byte(multilineReplace), "v2.0.0-beta.15"}, []byte(multilineReplaceUpdated), false},
{"basicmultilinereplaceblock", args{[]byte(multilineReplaceBlock), "v2.0.0-beta.15"}, []byte(multilineReplaceBlockUpdated), false},
{"basicmultilinereplacenoversion", args{[]byte(multilineReplaceNoVersion), "v2.0.0-beta.15"}, []byte(multilineReplaceNoVersionUpdated), false},
{"basicmultilinereplacenoversionblock", args{[]byte(multilineReplaceNoVersionBlock), "v2.0.0-beta.15"}, []byte(multilineReplaceNoVersionBlockUpdated), false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := UpdateGoModVersion(tt.args.goModText, tt.args.currentVersion)
if (err != nil) != tt.wantErr {
t.Errorf("UpdateGoModVersion() error = %v, wantErr %v", err, tt.wantErr)
return
}
is2.Equal(got, tt.want)
})
}
}
func TestGoModOutOfSync(t *testing.T) {
is2 := is.New(t)
type args struct {
goModData []byte
currentVersion string
}
tests := []struct {
name string
args args
want bool
wantErr bool
}{
{"basic", args{[]byte(basic), "v2.0.0-beta.15"}, true, false},
{"basicmultiline", args{[]byte(multilineRequire), "v2.0.0-beta.15"}, true, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := GoModOutOfSync(tt.args.goModData, tt.args.currentVersion)
if (err != nil) != tt.wantErr {
t.Errorf("GoModOutOfSync() error = %v, wantErr %v", err, tt.wantErr)
return
}
is2.Equal(got, tt.want)
})
}
}
const multilineReplaceUpdated = `module changeme
go 1.17
require (
github.com/wailsapp/wails/v2 v2.0.0-beta.15
)
require (
github.com/andybalholm/brotli v1.0.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab // indirect
github.com/gabriel-vasile/mimetype v1.3.1 // indirect
github.com/go-ole/go-ole v1.2.5 // indirect
github.com/gofiber/fiber/v2 v2.17.0 // indirect
github.com/gofiber/websocket/v2 v2.0.8 // indirect
github.com/google/uuid v1.1.2 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
github.com/klauspost/compress v1.12.2 // indirect
github.com/leaanthony/debme v1.2.1 // indirect
github.com/leaanthony/go-ansi-parser v1.0.1 // indirect
github.com/leaanthony/go-common-file-dialog v1.0.3 // indirect
github.com/leaanthony/go-webview2 v0.0.0-20211007092718-65d2f028ef2d // indirect
github.com/leaanthony/gosod v1.0.3 // indirect
github.com/leaanthony/slicer v1.5.0 // indirect
github.com/leaanthony/typescriptify-golang-structs v0.1.7 // indirect
github.com/leaanthony/webview2runtime v1.1.0 // indirect
github.com/leaanthony/winc v0.0.0-20210921073452-54963136bf18 // indirect
github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f // indirect
github.com/tkrajina/go-reflector v0.5.5 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.28.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect
)
replace github.com/wailsapp/wails/v2 v2.0.0-beta.15 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2
`
const multilineReplaceNoVersionUpdated = `module changeme
go 1.17
require (
github.com/wailsapp/wails/v2 v2.0.0-beta.15
)
require (
github.com/andybalholm/brotli v1.0.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab // indirect
github.com/gabriel-vasile/mimetype v1.3.1 // indirect
github.com/go-ole/go-ole v1.2.5 // indirect
github.com/gofiber/fiber/v2 v2.17.0 // indirect
github.com/gofiber/websocket/v2 v2.0.8 // indirect
github.com/google/uuid v1.1.2 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
github.com/klauspost/compress v1.12.2 // indirect
github.com/leaanthony/debme v1.2.1 // indirect
github.com/leaanthony/go-ansi-parser v1.0.1 // indirect
github.com/leaanthony/go-common-file-dialog v1.0.3 // indirect
github.com/leaanthony/go-webview2 v0.0.0-20211007092718-65d2f028ef2d // indirect
github.com/leaanthony/gosod v1.0.3 // indirect
github.com/leaanthony/slicer v1.5.0 // indirect
github.com/leaanthony/typescriptify-golang-structs v0.1.7 // indirect
github.com/leaanthony/webview2runtime v1.1.0 // indirect
github.com/leaanthony/winc v0.0.0-20210921073452-54963136bf18 // indirect
github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f // indirect
github.com/tkrajina/go-reflector v0.5.5 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.28.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect
)
replace github.com/wailsapp/wails/v2 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2
`
const multilineReplaceNoVersionBlockUpdated = `module changeme
go 1.17
require (
github.com/wailsapp/wails/v2 v2.0.0-beta.15
)
require (
github.com/andybalholm/brotli v1.0.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab // indirect
github.com/gabriel-vasile/mimetype v1.3.1 // indirect
github.com/go-ole/go-ole v1.2.5 // indirect
github.com/gofiber/fiber/v2 v2.17.0 // indirect
github.com/gofiber/websocket/v2 v2.0.8 // indirect
github.com/google/uuid v1.1.2 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
github.com/klauspost/compress v1.12.2 // indirect
github.com/leaanthony/debme v1.2.1 // indirect
github.com/leaanthony/go-ansi-parser v1.0.1 // indirect
github.com/leaanthony/go-common-file-dialog v1.0.3 // indirect
github.com/leaanthony/go-webview2 v0.0.0-20211007092718-65d2f028ef2d // indirect
github.com/leaanthony/gosod v1.0.3 // indirect
github.com/leaanthony/slicer v1.5.0 // indirect
github.com/leaanthony/typescriptify-golang-structs v0.1.7 // indirect
github.com/leaanthony/webview2runtime v1.1.0 // indirect
github.com/leaanthony/winc v0.0.0-20210921073452-54963136bf18 // indirect
github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f // indirect
github.com/tkrajina/go-reflector v0.5.5 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.28.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect
)
replace (
github.com/wailsapp/wails/v2 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2
)
`
const multilineReplaceBlockUpdated = `module changeme
go 1.17
require (
github.com/wailsapp/wails/v2 v2.0.0-beta.15
)
require (
github.com/andybalholm/brotli v1.0.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab // indirect
github.com/gabriel-vasile/mimetype v1.3.1 // indirect
github.com/go-ole/go-ole v1.2.5 // indirect
github.com/gofiber/fiber/v2 v2.17.0 // indirect
github.com/gofiber/websocket/v2 v2.0.8 // indirect
github.com/google/uuid v1.1.2 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
github.com/klauspost/compress v1.12.2 // indirect
github.com/leaanthony/debme v1.2.1 // indirect
github.com/leaanthony/go-ansi-parser v1.0.1 // indirect
github.com/leaanthony/go-common-file-dialog v1.0.3 // indirect
github.com/leaanthony/go-webview2 v0.0.0-20211007092718-65d2f028ef2d // indirect
github.com/leaanthony/gosod v1.0.3 // indirect
github.com/leaanthony/slicer v1.5.0 // indirect
github.com/leaanthony/typescriptify-golang-structs v0.1.7 // indirect
github.com/leaanthony/webview2runtime v1.1.0 // indirect
github.com/leaanthony/winc v0.0.0-20210921073452-54963136bf18 // indirect
github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f // indirect
github.com/tkrajina/go-reflector v0.5.5 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.28.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect
)
replace (
github.com/wailsapp/wails/v2 v2.0.0-beta.15 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2
)
`

View File

@@ -69,3 +69,7 @@ func (p *Process) Kill() error {
func (p *Process) PID() int {
return p.cmd.Process.Pid
}
func (p *Process) SetDir(dir string) {
p.cmd.Dir = dir
}

View File

@@ -18,6 +18,7 @@ type Project struct {
BuildCommand string `json:"frontend:build"`
InstallCommand string `json:"frontend:install"`
DevCommand string `json:"frontend:dev"`
// Directory to generate the API Module
WailsJSDir string `json:"wailsjsdir"`
@@ -46,6 +47,12 @@ type Project struct {
// Fully qualified filename
filename string
// The debounce time for hot-reload of the built-in dev server. Default 100
DebounceMS int `json:"debounceMS"`
// The url to use to server assets. Default "https://localhost:34115"
DevServerURL string `json:"devserverurl"`
}
func (p *Project) Save() error {

View File

@@ -4,6 +4,7 @@ import (
"bytes"
"fmt"
"github.com/leaanthony/gosod"
wailsRuntime "github.com/wailsapp/wails/v2/internal/frontend/runtime"
"github.com/wailsapp/wails/v2/internal/frontend/runtime/wrapper"
"io/ioutil"
"os"
@@ -377,7 +378,22 @@ func generateRuntimeWrapper(options *Options) error {
wrapperDir := filepath.Join(options.WailsJSDir, "wailsjs", "runtime")
_ = os.RemoveAll(wrapperDir)
extractor := gosod.New(wrapper.RuntimeWrapper)
return extractor.Extract(wrapperDir, nil)
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
}
return nil
}
// NpmInstall runs "npm install" in the given directory
@@ -504,7 +520,14 @@ func (b *BaseBuilder) BuildFrontend(outputLogger *clilogger.CLILogger) error {
}
// Check if there is a build command
if b.projectData.BuildCommand == "" {
var buildCommand string
switch b.projectData.OutputType {
case "dev":
buildCommand = b.projectData.DevCommand
default:
buildCommand = b.projectData.BuildCommand
}
if buildCommand == "" {
outputLogger.Println("No Build command. Skipping.")
// No - ignore
return nil

View File

@@ -46,11 +46,10 @@ type Options struct {
Verbosity int // Verbosity level (0 - silent, 1 - default, 2 - verbose)
Compress bool // Compress the final binary
CompressFlags string // Flags to pass to UPX
AppleIdentity string
WebView2Strategy string // WebView2 installer strategy
RunDelve bool // Indicates if we should run delve after the build
WailsJSDir string // Directory to generate the wailsjs module
ForceBuild bool // Force
WebView2Strategy string // WebView2 installer strategy
RunDelve bool // Indicates if we should run delve after the build
WailsJSDir string // Directory to generate the wailsjs module
ForceBuild bool // Force
}
// Build the project!

View File

@@ -2,17 +2,16 @@ package build
import (
"bytes"
"fmt"
"github.com/wailsapp/wails/v2/pkg/buildassets"
"image"
"io/ioutil"
"os"
"os/exec"
"path"
"path/filepath"
"strings"
"text/template"
"github.com/wailsapp/wails/v2/pkg/buildassets"
"github.com/jackmordaunt/icns"
"github.com/pkg/errors"
"github.com/wailsapp/wails/v2/internal/fs"
@@ -55,13 +54,7 @@ func packageApplication(options *Options) error {
return err
}
// Sign app if needed
if options.AppleIdentity != "" {
err = signApplication(options)
if err != nil {
return err
}
}
options.CompiledBinary = packedBinaryPath
return nil
}
@@ -186,21 +179,3 @@ func processApplicationIcon(resourceDir string, iconsDir string) (err error) {
}()
return icns.Encode(dest, srcImg)
}
func signApplication(options *Options) error {
bundlename := filepath.Join(options.BuildDirectory, options.ProjectData.Name+".app")
identity := fmt.Sprintf(`"%s"`, options.AppleIdentity)
cmd := exec.Command("codesign", "--sign", identity, "--deep", "--force", "--verbose", "--timestamp", "--options", "runtime", bundlename)
var stdo, stde bytes.Buffer
cmd.Stdout = &stdo
cmd.Stderr = &stde
// Run command
err := cmd.Run()
// Format error if we have one
if err != nil {
return fmt.Errorf("%s\n%s", err, string(stde.Bytes()))
}
return nil
}

View File

@@ -0,0 +1,66 @@
package main
import (
"bytes"
_ "embed"
"encoding/json"
"io/ioutil"
"log"
"net/http"
"os"
"path/filepath"
"text/template"
)
type Rgb struct {
R uint8 `json:"r"`
G uint8 `json:"g"`
B uint8 `json:"b"`
}
type Hsl struct {
H float64 `json:"h"`
S float64 `json:"s"`
L float64 `json:"l"`
}
type InputCol struct {
Colorid uint8 `json:"colorId"`
Hexstring string `json:"hexString"`
Rgb Rgb `json:"rgb"`
Hsl Hsl `json:"hsl"`
Name string `json:"name"`
}
//go:embed gen.tmpl
var Template string
func main() {
var Cols []InputCol
resp, err := http.Get("https://jonasjacek.github.io/colors/data.json")
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
err = json.Unmarshal(data, &Cols)
if err != nil {
log.Fatal(err)
}
t, err := template.New("cols").Parse(Template)
if err != nil {
log.Fatal(err)
}
var buffer bytes.Buffer
err = t.Execute(&buffer, Cols)
if err != nil {
log.Fatal(err)
}
os.WriteFile(filepath.Join("..", "cols.go"), buffer.Bytes(), 0755)
}

View File

@@ -0,0 +1,29 @@
package menu
type Rgb struct {
R uint8 `json:"r"`
G uint8 `json:"g"`
B uint8 `json:"b"`
}
type Hsl struct {
H float64 `json:"h"`
S float64 `json:"s"`
L float64 `json:"l"`
}
type Col struct {
Hex string `json:"hex"`
Rgb Rgb `json:"rgb"`
Hsl Hsl `json:"hsl"`
Name string `json:"name"`
}
var Cols = []*Col{ {{range $col := .}}
{
Hex: "{{.Hexstring}}",
Rgb: Rgb{ {{.Rgb.R}}, {{.Rgb.G}}, {{.Rgb.B}} },
Hsl: Hsl{ {{.Hsl.H}}, {{.Hsl.S}}, {{.Hsl.L}} },
Name: "{{.Name}}",
},{{end}}
}

1559
v2/pkg/menu/cols.go Executable file

File diff suppressed because it is too large Load Diff

256
v2/pkg/menu/styledlabel.go Normal file
View File

@@ -0,0 +1,256 @@
package menu
import (
"fmt"
"strconv"
"strings"
)
type TextStyle int
const (
Bold TextStyle = 1 << 0
Faint TextStyle = 1 << 1
Italic TextStyle = 1 << 2
Blinking TextStyle = 1 << 3
Inversed TextStyle = 1 << 4
Invisible TextStyle = 1 << 5
Underlined TextStyle = 1 << 6
Strikethrough TextStyle = 1 << 7
)
type StyledText struct {
Label string
FgCol *Col
BgCol *Col
Style TextStyle
}
func (s *StyledText) Bold() bool {
return s.Style&Bold == Bold
}
func (s *StyledText) Faint() bool {
return s.Style&Faint == Faint
}
func (s *StyledText) Italic() bool {
return s.Style&Italic == Italic
}
func (s *StyledText) Blinking() bool {
return s.Style&Blinking == Blinking
}
func (s *StyledText) Inversed() bool {
return s.Style&Inversed == Inversed
}
func (s *StyledText) Invisible() bool {
return s.Style&Invisible == Invisible
}
func (s *StyledText) Underlined() bool {
return s.Style&Underlined == Underlined
}
func (s *StyledText) Strikethrough() bool {
return s.Style&Strikethrough == Strikethrough
}
var ansiColorMap = map[string]map[string]*Col{
"Normal": {
"30": Cols[0],
"31": Cols[1],
"32": Cols[2],
"33": Cols[3],
"34": Cols[4],
"35": Cols[5],
"36": Cols[6],
"37": Cols[7],
},
"Bold": {
"30": Cols[8],
"31": Cols[9],
"32": Cols[10],
"33": Cols[11],
"34": Cols[12],
"35": Cols[13],
"36": Cols[14],
"37": Cols[15],
},
"Faint": {
"30": Cols[0],
"31": Cols[1],
"32": Cols[2],
"33": Cols[3],
"34": Cols[4],
"35": Cols[5],
"36": Cols[6],
"37": Cols[7],
},
}
func ParseANSI(input string) ([]*StyledText, error) {
var result []*StyledText
invalid := fmt.Errorf("invalid ansi string")
missingTerminator := fmt.Errorf("missing escape terminator 'm'")
invalidTrueColorSequence := fmt.Errorf("invalid TrueColor sequence")
invalid256ColSequence := fmt.Errorf("invalid 256 colour sequence")
index := 0
var currentStyledText *StyledText = &StyledText{}
if len(input) == 0 {
return nil, invalid
}
for {
// Read all chars to next escape code
esc := strings.Index(input, "\033[")
// If no more esc chars, save what's left and return
if esc == -1 {
text := input[index:]
if len(text) > 0 {
currentStyledText.Label = text
result = append(result, currentStyledText)
}
return result, nil
}
label := input[:esc]
if len(label) > 0 {
currentStyledText.Label = label
result = append(result, currentStyledText)
currentStyledText = &StyledText{
Label: "",
FgCol: currentStyledText.FgCol,
BgCol: currentStyledText.BgCol,
Style: currentStyledText.Style,
}
}
input = input[esc:]
// skip
input = input[2:]
// Read in params
endesc := strings.Index(input, "m")
if endesc == -1 {
return nil, missingTerminator
}
paramText := input[:endesc]
input = input[endesc+1:]
params := strings.Split(paramText, ";")
colourMap := ansiColorMap["Normal"]
skip := 0
for index, param := range params {
if skip > 0 {
skip--
continue
}
switch param {
case "0":
// Reset styles
if len(params) == 1 {
if len(currentStyledText.Label) > 0 {
result = append(result, currentStyledText)
currentStyledText = &StyledText{
Label: "",
FgCol: currentStyledText.FgCol,
BgCol: currentStyledText.BgCol,
Style: currentStyledText.Style,
}
continue
}
}
currentStyledText.Style = 0
currentStyledText.FgCol = nil
currentStyledText.BgCol = nil
case "1":
// Bold
colourMap = ansiColorMap["Bold"]
currentStyledText.Style |= Bold
case "2":
// Dim/Feint
colourMap = ansiColorMap["Faint"]
currentStyledText.Style |= Faint
case "3":
// Italic
currentStyledText.Style |= Italic
case "4":
// Underlined
currentStyledText.Style |= Underlined
case "5":
// Blinking
currentStyledText.Style |= Blinking
case "7":
// Inverse
currentStyledText.Style |= Inversed
case "8":
// Invisible
currentStyledText.Style |= Invisible
case "9":
// Strikethrough
currentStyledText.Style |= Strikethrough
case "30", "31", "32", "33", "34", "35", "36", "37":
currentStyledText.FgCol = colourMap[param]
case "40", "41", "42", "43", "44", "45", "46", "47":
currentStyledText.BgCol = colourMap[param]
case "38", "48":
if len(params)-index < 2 {
return nil, invalid
}
// 256 colours
if params[index+1] == "5" {
skip = 2
colIndexText := params[index+2]
colIndex, err := strconv.Atoi(colIndexText)
if err != nil {
return nil, invalid256ColSequence
}
if colIndex < 0 || colIndex > 255 {
return nil, invalid256ColSequence
}
if param == "38" {
currentStyledText.FgCol = Cols[colIndex]
continue
}
currentStyledText.BgCol = Cols[colIndex]
continue
}
// we must have 4 params left
if len(params)-index < 4 {
return nil, invalidTrueColorSequence
}
if params[index+1] != "2" {
return nil, invalidTrueColorSequence
}
var r, g, b uint8
ri, err := strconv.Atoi(params[index+2])
if err != nil {
return nil, invalidTrueColorSequence
}
gi, err := strconv.Atoi(params[index+3])
if err != nil {
return nil, invalidTrueColorSequence
}
bi, err := strconv.Atoi(params[index+4])
if err != nil {
return nil, invalidTrueColorSequence
}
if bi > 255 || gi > 255 || ri > 255 {
return nil, invalidTrueColorSequence
}
if bi < 0 || gi < 0 || ri < 0 {
return nil, invalidTrueColorSequence
}
r = uint8(ri)
g = uint8(gi)
b = uint8(bi)
skip = 4
colvalue := fmt.Sprintf("#%02x%02x%02x", r, g, b)
if param == "38" {
currentStyledText.FgCol = &Col{Hex: colvalue, Rgb: Rgb{r, g, b}}
continue
}
currentStyledText.BgCol = &Col{Hex: colvalue}
default:
return nil, invalid
}
}
}
return result, nil
}

View File

@@ -0,0 +1,197 @@
package menu
import (
"testing"
"github.com/matryer/is"
)
func TestParseAnsi16SingleColour(t *testing.T) {
is := is.New(t)
tests := []struct {
name string
input string
wantText string
wantColor string
wantErr bool
}{
{"No formatting", "Hello World", "Hello World", "", false},
{"Black", "\u001b[0;30mHello World\033[0m", "Hello World", "Black", false},
{"Red", "\u001b[0;31mHello World\033[0m", "Hello World", "Maroon", false},
{"Green", "\u001b[0;32m\033[0m", "", "Green", false},
{"Yellow", "\u001b[0;33m😀\033[0m", "😀", "Olive", false},
{"Blue", "\u001b[0;34m123\033[0m", "123", "Navy", false},
{"Purple", "\u001b[0;35m👩🏽🔧\u001B[0m", "👩🏽‍🔧", "Purple", false},
{"Cyan", "\033[0;36m😀\033[0m", "😀", "Teal", false},
{"White", "\u001b[0;37m[0;37m\033[0m", "[0;37m", "Silver", false},
{"Black Bold", "\u001b[1;30mHello World\033[0m", "Hello World", "Grey", false},
{"Red Bold", "\u001b[1;31mHello World\033[0m", "Hello World", "Red", false},
{"Green Bold", "\u001b[1;32m\033[0m", "", "Lime", false},
{"Yellow Bold", "\u001b[1;33m😀\033[0m", "😀", "Yellow", false},
{"Blue Bold", "\u001b[1;34m123\033[0m", "123", "Blue", false},
{"Purple Bold", "\u001b[1;35m👩🏽🔧\u001B[0m", "👩🏽‍🔧", "Fuchsia", false},
{"Cyan Bold", "\033[1;36m😀\033[0m", "😀", "Aqua", false},
{"White Bold", "\u001b[1;37m[0;37m\033[0m", "[0;37m", "White", false},
{"Blank", "", "", "", true},
{"Emoji", "😀👩🏽‍🔧", "😀👩🏽‍🔧", "", false},
{"Spaces", " ", " ", "", false},
{"Bad code", "\u001b[1 ", "", "", true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := ParseANSI(tt.input)
is.Equal(err != nil, tt.wantErr)
expectedLength := 1
if tt.wantErr {
expectedLength = 0
}
is.Equal(len(got), expectedLength)
if expectedLength == 1 {
if len(tt.wantColor) > 0 {
is.True(got[0].FgCol != nil)
is.Equal(got[0].FgCol.Name, tt.wantColor)
}
}
})
}
}
func TestParseAnsi16MultiColour(t *testing.T) {
is := is.New(t)
tests := []struct {
name string
input string
want []*StyledText
wantErr bool
}{
{"Black & Red", "\u001B[0;30mHello World\u001B[0m\u001B[0;31mHello World\u001B[0m", []*StyledText{
{Label: "Hello World", FgCol: &Col{Name: "Black"}},
{Label: "Hello World", FgCol: &Col{Name: "Maroon"}},
}, false},
{"Text then Black & Red", "This is great!\u001B[0;30mHello World\u001B[0m\u001B[0;31mHello World\u001B[0m", []*StyledText{
{Label: "This is great!"},
{Label: "Hello World", FgCol: &Col{Name: "Black"}},
{Label: "Hello World", FgCol: &Col{Name: "Maroon"}},
}, false},
{"Text Reset then Black & Red", "This is great!\u001B[0m\u001B[0;30mHello World\u001B[0m\u001B[0;31mHello World\u001B[0m", []*StyledText{
{Label: "This is great!"},
{Label: "Hello World", FgCol: &Col{Name: "Black"}},
{Label: "Hello World", FgCol: &Col{Name: "Maroon"}},
}, false},
{"Black & Red no reset", "\u001B[0;30mHello World\u001B[0;31mHello World", []*StyledText{
{Label: "Hello World", FgCol: &Col{Name: "Black"}},
{Label: "Hello World", FgCol: &Col{Name: "Maroon"}},
}, false},
{"Black,space,Red", "\u001B[0;30mHello World\u001B[0m \u001B[0;31mHello World\u001B[0m", []*StyledText{
{Label: "Hello World", FgCol: &Col{Name: "Black"}},
{Label: " "},
{Label: "Hello World", FgCol: &Col{Name: "Maroon"}},
}, false},
{"Black,Red,Blue,Green underlined", "\033[4;30mBlack\u001B[0m\u001B[4;31mRed\u001B[0m\u001B[4;34mBlue\u001B[0m\u001B[4;32mGreen\u001B[0m", []*StyledText{
{Label: "Black", FgCol: &Col{Name: "Black"}, Style: Underlined},
{Label: "Red", FgCol: &Col{Name: "Maroon"}, Style: Underlined},
{Label: "Blue", FgCol: &Col{Name: "Navy"}, Style: Underlined},
{Label: "Green", FgCol: &Col{Name: "Green"}, Style: Underlined},
}, false},
{"Black,Red,Blue,Green bold", "\033[1;30mBlack\u001B[0m\u001B[1;31mRed\u001B[0m\u001B[1;34mBlue\u001B[0m\u001B[1;32mGreen\u001B[0m", []*StyledText{
{Label: "Black", FgCol: &Col{Name: "Grey"}, Style: Bold},
{Label: "Red", FgCol: &Col{Name: "Red"}, Style: Bold},
{Label: "Blue", FgCol: &Col{Name: "Blue"}, Style: Bold},
{Label: "Green", FgCol: &Col{Name: "Lime"}, Style: Bold},
}, false},
{"Green Feint & Yellow Italic", "\u001B[2;32m👩🏽🔧\u001B[0m\u001B[0;3;33m👩🏽🔧\u001B[0m", []*StyledText{
{Label: "👩🏽‍🔧", FgCol: &Col{Name: "Green"}, Style: Faint},
{Label: "👩🏽‍🔧", FgCol: &Col{Name: "Olive"}, Style: Italic},
}, false},
{"Green Blinking & Yellow Inversed", "\u001B[5;32m👩🏽🔧\u001B[0m\u001B[0;7;33m👩🏽🔧\u001B[0m", []*StyledText{
{Label: "👩🏽‍🔧", FgCol: &Col{Name: "Green"}, Style: Blinking},
{Label: "👩🏽‍🔧", FgCol: &Col{Name: "Olive"}, Style: Inversed},
}, false},
{"Green Invisible & Yellow Invisible & Strikethrough", "\u001B[8;32m👩🏽🔧\u001B[0m\u001B[9;33m👩🏽🔧\u001B[0m", []*StyledText{
{Label: "👩🏽‍🔧", FgCol: &Col{Name: "Green"}, Style: Invisible},
{Label: "👩🏽‍🔧", FgCol: &Col{Name: "Olive"}, Style: Invisible | Strikethrough},
}, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := ParseANSI(tt.input)
is.Equal(err != nil, tt.wantErr)
for index, w := range tt.want {
is.Equal(got[index].Label, w.Label)
if w.FgCol != nil {
is.Equal(got[index].FgCol.Name, w.FgCol.Name)
}
is.Equal(got[index].Style, w.Style)
}
})
}
}
func TestParseAnsi256(t *testing.T) {
is := is.New(t)
tests := []struct {
name string
input string
want []*StyledText
wantErr bool
}{
{"Grey93 & DarkViolet", "\u001B[38;5;255mGrey93\u001B[0m\u001B[38;5;128mDarkViolet\u001B[0m", []*StyledText{
{Label: "Grey93", FgCol: &Col{Name: "Grey93"}},
{Label: "DarkViolet", FgCol: &Col{Name: "DarkViolet"}},
}, false},
{"Grey93 Bold & DarkViolet Italic", "\u001B[0;1;38;5;255mGrey93\u001B[0m\u001B[0;3;38;5;128mDarkViolet\u001B[0m", []*StyledText{
{Label: "Grey93", FgCol: &Col{Name: "Grey93"}, Style: Bold},
{Label: "DarkViolet", FgCol: &Col{Name: "DarkViolet"}, Style: Italic},
}, false},
{"Grey93 Bold & DarkViolet Italic", "\u001B[0;1;38;5;256mGrey93\u001B[0m", nil, true},
{"Grey93 Bold & DarkViolet Italic", "\u001B[0;1;38;5;-1mGrey93\u001B[0m", nil, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := ParseANSI(tt.input)
is.Equal(err != nil, tt.wantErr)
for index, w := range tt.want {
is.Equal(got[index].Label, w.Label)
if w.FgCol != nil {
is.Equal(got[index].FgCol.Name, w.FgCol.Name)
}
is.Equal(got[index].Style, w.Style)
}
})
}
}
func TestParseAnsiTrueColor(t *testing.T) {
is := is.New(t)
tests := []struct {
name string
input string
want []*StyledText
wantErr bool
}{
{"Red", "\u001B[38;2;255;0;0mRed\u001B[0m", []*StyledText{
{Label: "Red", FgCol: &Col{Rgb: Rgb{255, 0, 0}, Hex: "#ff0000"}},
}, false},
{"Red, text, Green", "\u001B[38;2;255;0;0mRed\u001B[0mI am plain text\u001B[38;2;0;255;0mGreen\u001B[0m", []*StyledText{
{Label: "Red", FgCol: &Col{Rgb: Rgb{255, 0, 0}, Hex: "#ff0000"}},
{Label: "I am plain text"},
{Label: "Green", FgCol: &Col{Rgb: Rgb{0, 255, 0}, Hex: "#00ff00"}},
}, false},
{"Bad 1", "\u001B[38;2;256;0;0mRed\u001B[0m", nil, true},
{"Bad 2", "\u001B[38;2;-1;0;0mRed\u001B[0m", nil, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := ParseANSI(tt.input)
is.Equal(err != nil, tt.wantErr)
for index, w := range tt.want {
is.Equal(got[index].Label, w.Label)
if w.FgCol != nil {
is.Equal(got[index].FgCol.Hex, w.FgCol.Hex)
is.Equal(got[index].FgCol.Rgb, w.FgCol.Rgb)
}
is.Equal(got[index].Style, w.Style)
}
})
}
}

View File

@@ -15,5 +15,5 @@ type Options struct {
WebviewIsTransparent bool
WindowIsTranslucent bool
ActivationPolicy ActivationPolicy
URLHandlers map[string]func(string)
//URLHandlers map[string]func(string)
}

View File

@@ -3,9 +3,11 @@ package options
import (
"context"
"embed"
"github.com/wailsapp/wails/v2/pkg/options/windows"
"log"
"github.com/wailsapp/wails/v2/pkg/options/mac"
"github.com/wailsapp/wails/v2/pkg/options/windows"
"github.com/wailsapp/wails/v2/pkg/menu"
"github.com/imdario/mergo"
@@ -26,6 +28,7 @@ type App struct {
MaxHeight int
StartHidden bool
HideWindowOnClose bool
AlwaysOnTop bool
RGBA *RGBA
Assets embed.FS
Menu *menu.Menu
@@ -39,7 +42,7 @@ type App struct {
//ContextMenus []*menu.ContextMenu
//TrayMenus []*menu.TrayMenu
Windows *windows.Options
//Mac *mac.Options
Mac *mac.Options
}
type RGBA struct {

View File

@@ -2,6 +2,7 @@ package runtime
import (
"context"
"github.com/wailsapp/wails/v2/pkg/options"
)
@@ -53,6 +54,11 @@ func WindowSetSize(ctx context.Context, width int, height int) {
appFrontend.WindowSetSize(width, height)
}
func WindowGetSize(ctx context.Context) (int, int) {
appFrontend := getFrontend(ctx)
return appFrontend.WindowGetSize()
}
// WindowSetMinSize sets the minimum size of the window
func WindowSetMinSize(ctx context.Context, width int, height int) {
appFrontend := getFrontend(ctx)
@@ -71,6 +77,11 @@ func WindowSetPosition(ctx context.Context, x int, y int) {
appFrontend.WindowSetPos(x, y)
}
func WindowGetPos(ctx context.Context) (int, int) {
appFrontend := getFrontend(ctx)
return appFrontend.WindowGetPos()
}
// WindowMaximise the window
func WindowMaximise(ctx context.Context) {
appFrontend := getFrontend(ctx)

View File

@@ -1,34 +0,0 @@
name: Deploy mirror | 部署镜像
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build-and-deploy:
name: Automatic deployment | 自动部署
runs-on: ubuntu-latest
if: github.repository == 'misitebao/wails-docs'
steps:
- name: Checkout | 切换到部署分支
uses: actions/checkout@v2
with:
ref: "main"
submodules: true
fetch-depth: 0
- name: Build Site | 构建网站
run: |
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: "build"
# TARGET: "/www/wwwroot/beta.wails.top"

View File

@@ -22,4 +22,9 @@ Example: `wails init -n "Your Project Name" -t https://github.com/misitebao/wail
## Vue
- [wails-template-vue](https://github.com/misitebao/wails-template-vue) - A template using vue and vue-router
- [wails-vite-vue-ts](https://github.com/codydbentley/wails-vite-vue-ts) - Vue 3 TypeScript with Vite (and instructions to add features)
- [wails-vite-vue-the-works](https://github.com/codydbentley/wails-vite-vue-the-works) - Vue 3 TypeScript with Vite, Vuex, Vue Router, Sass, and ESLint + Prettier
## Angular
- [wails-angular-template](https://github.com/TAINCER/wails-angular-template) - Angular with TypeScript, Sass, Hot-Reload, Code-Splitting and i18n

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